-
Notifications
You must be signed in to change notification settings - Fork 24
/
permuted.go
147 lines (139 loc) · 4.25 KB
/
permuted.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
// Copyright (c) 2019, The Emergent Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package patgen
import (
"errors"
"fmt"
"log"
"math"
"cogentcore.org/core/math32"
"cogentcore.org/lab/base/randx"
"cogentcore.org/lab/stats/metric"
"cogentcore.org/lab/tensor"
)
// PermutedBinary sets the given tensor to contain nOn onVal values and the
// remainder are offVal values, using a permuted order of tensor elements (i.e.,
// randomly shuffled or permuted).
func PermutedBinary(tsr tensor.Tensor, nOn int, onVal, offVal float64) {
ln := tsr.Len()
if ln == 0 {
return
}
pord := RandSource.Perm(ln)
for i := 0; i < ln; i++ {
if i < nOn {
tsr.SetFloat1D(onVal, pord[i])
} else {
tsr.SetFloat1D(offVal, pord[i])
}
}
}
// PermutedBinaryRows treats the tensor as a column of rows as in a table.Table
// and sets each row to contain nOn onVal values and the remainder are offVal values,
// using a permuted order of tensor elements (i.e., randomly shuffled or permuted).
func PermutedBinaryRows(tsr tensor.Tensor, nOn int, onVal, offVal float64) {
rows, cells := tsr.Shape().RowCellSize()
if rows == 0 || cells == 0 {
return
}
pord := RandSource.Perm(cells)
for rw := 0; rw < rows; rw++ {
stidx := rw * cells
for i := 0; i < cells; i++ {
if i < nOn {
tsr.SetFloat1D(onVal, stidx+pord[i])
} else {
tsr.SetFloat1D(offVal, stidx+pord[i])
}
}
randx.PermuteInts(pord, RandSource)
}
}
// MinDiffPrintIters set this to true to see the iteration stats for
// PermutedBinaryMinDiff -- for large, long-running cases.
var MinDiffPrintIters = false
// PermutedBinaryMinDiff treats the tensor as a column of rows as in a table.Table
// and sets each row to contain nOn onVal values and the remainder are offVal values,
// using a permuted order of tensor elements (i.e., randomly shuffled or permuted).
// This version ensures that all patterns have at least a given minimum distance from each other,
// expressed using minDiff = number of bits that must be different (can't be > nOn).
// If the mindiff constraint cannot be met within a reasonable number of iterations,
// then an error is returned.
func PermutedBinaryMinDiff(tsr *tensor.Float32, nOn int, onVal, offVal float32, minDiff int) error {
rows, cells := tsr.Shape().RowCellSize()
if rows == 0 || cells == 0 {
return errors.New("empty tensor")
}
pord := RandSource.Perm(cells)
iters := 100
nunder := make([]int, rows) // per row
fails := 0
for itr := 0; itr < iters; itr++ {
for rw := 0; rw < rows; rw++ {
if itr > 0 && nunder[rw] == 0 {
continue
}
stidx := rw * cells
for i := 0; i < cells; i++ {
if i < nOn {
tsr.Values[stidx+pord[i]] = onVal
} else {
tsr.Values[stidx+pord[i]] = offVal
}
}
randx.PermuteInts(pord, RandSource)
}
for i := range nunder {
nunder[i] = 0
}
nbad := 0
mxnun := 0
for r1 := 0; r1 < rows; r1++ {
r1v := tsr.SubSpace(r1).(*tensor.Float32)
for r2 := r1 + 1; r2 < rows; r2++ {
r2v := tsr.SubSpace(r2).(*tensor.Float32)
dst := metric.Hamming(r1v, r2v).Float1D(0)
df := int(math.Round(float64(.5 * dst)))
if df < minDiff {
nunder[r1]++
mxnun = max(nunder[r1])
nunder[r2]++
mxnun = max(nunder[r2])
nbad++
}
}
}
if nbad == 0 {
break
}
fails++
if MinDiffPrintIters {
fmt.Printf("PermutedBinaryMinDiff: Itr: %d NBad: %d MaxN: %d\n", itr, nbad, mxnun)
}
}
if fails == iters {
err := fmt.Errorf("PermutedBinaryMinDiff: minimum difference of: %d was not met: %d times, rows: %d", minDiff, fails, rows)
log.Println(err)
return err
}
return nil
}
// RowVsPrevDist32 returns the minimum and maximum distance between the given row
// in tensor and all previous rows. Row must be >= 1 and < total rows.
// (outer-most dimension is row, as in columns of table.Table).
func RowVsPrevDist32(tsr *tensor.Float32, row int, fun metric.MetricFunc) (min, max float32) {
if row < 1 {
return
}
min = float32(math.MaxFloat32)
max = float32(-math.MaxFloat32)
lrow := tsr.SubSpace(row).(*tensor.Float32)
for i := 0; i <= row-1; i++ {
crow := tsr.SubSpace(i).(*tensor.Float32)
dst := float32(fun(lrow, crow).Float1D(0))
min = math32.Min(min, dst)
max = math32.Max(max, dst)
}
return
}