-
Notifications
You must be signed in to change notification settings - Fork 25
/
fixed.go
199 lines (164 loc) · 5.7 KB
/
fixed.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
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
// 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 env
import (
"fmt"
"log"
"math/rand"
"github.com/emer/emergent/v2/erand"
"github.com/emer/etable/v2/etable"
"github.com/emer/etable/v2/etensor"
)
// FixedTable is a basic Env that manages patterns from an etable.Table, with
// either sequential or permuted random ordering, and uses standard Trial / Epoch
// TimeScale counters to record progress and iterations through the table.
// It also records the outer loop of Run as provided by the model.
// It uses an IndexView indexed view of the Table, so a single shared table
// can be used across different environments, with each having its own unique view.
type FixedTable struct {
// name of this environment
Nm string
// description of this environment
Dsc string
// this is an indexed view of the table with the set of patterns to output -- the indexes are used for the *sequential* view so you can easily sort / split / filter the patterns to be presented using this view -- we then add the random permuted Order on top of those if !sequential
Table *etable.IndexView
// present items from the table in sequential order (i.e., according to the indexed view on the Table)? otherwise permuted random order
Sequential bool
// permuted order of items to present if not sequential -- updated every time through the list
Order []int
// current run of model as provided during Init
Run Ctr `view:"inline"`
// number of times through entire set of patterns
Epoch Ctr `view:"inline"`
// current ordinal item in Table -- if Sequential then = row number in table, otherwise is index in Order list that then gives row number in Table
Trial Ctr `view:"inline"`
// if Table has a Name column, this is the contents of that
TrialName CurPrvString
// if Table has a Group column, this is contents of that
GroupName CurPrvString
// name of the Name column -- defaults to 'Name'
NameCol string
// name of the Group column -- defaults to 'Group'
GroupCol string
}
func (ft *FixedTable) Name() string { return ft.Nm }
func (ft *FixedTable) Desc() string { return ft.Dsc }
func (ft *FixedTable) Validate() error {
if ft.Table == nil || ft.Table.Table == nil {
return fmt.Errorf("env.FixedTable: %v has no Table set", ft.Nm)
}
if ft.Table.Table.NumCols() == 0 {
return fmt.Errorf("env.FixedTable: %v Table has no columns -- Outputs will be invalid", ft.Nm)
}
return nil
}
func (ft *FixedTable) Init(run int) {
if ft.NameCol == "" {
ft.NameCol = "Name"
}
if ft.GroupCol == "" {
ft.GroupCol = "Group"
}
ft.Run.Scale = Run
ft.Epoch.Scale = Epoch
ft.Trial.Scale = Trial
ft.Run.Init()
ft.Epoch.Init()
ft.Trial.Init()
ft.Run.Cur = run
ft.NewOrder()
ft.Trial.Cur = -1 // init state -- key so that first Step() = 0
}
// Config configures the environment to use given table IndexView and
// evaluation mode (e.g., etime.Train.String()). If mode is Train
// then a Run counter is added, otherwise just Epoch and Trial.
// NameCol and GroupCol are initialized to "Name" and "Group"
// so set these to something else after this if needed.
func (ft *FixedTable) Config(tbl *etable.IndexView) {
ft.Table = tbl
ft.Init(0)
}
// NewOrder sets a new random Order based on number of rows in the table.
func (ft *FixedTable) NewOrder() {
np := ft.Table.Len()
ft.Order = rand.Perm(np) // always start with new one so random order is identical
// and always maintain Order so random number usage is same regardless, and if
// user switches between Sequential and random at any point, it all works..
ft.Trial.Max = np
}
// PermuteOrder permutes the existing order table to get a new random sequence of inputs
// just calls: erand.PermuteInts(ft.Order)
func (ft *FixedTable) PermuteOrder() {
erand.PermuteInts(ft.Order)
}
// Row returns the current row number in table, based on Sequential / perumuted Order and
// already de-referenced through the IndexView's indexes to get the actual row in the table.
func (ft *FixedTable) Row() int {
if ft.Sequential {
return ft.Table.Indexes[ft.Trial.Cur]
}
return ft.Table.Indexes[ft.Order[ft.Trial.Cur]]
}
func (ft *FixedTable) SetTrialName() {
if nms := ft.Table.Table.ColByName(ft.NameCol); nms != nil {
rw := ft.Row()
if rw >= 0 && rw < nms.Len() {
ft.TrialName.Set(nms.StringValue1D(rw))
}
}
}
func (ft *FixedTable) SetGroupName() {
if nms := ft.Table.Table.ColByName(ft.GroupCol); nms != nil {
rw := ft.Row()
if rw >= 0 && rw < nms.Len() {
ft.GroupName.Set(nms.StringValue1D(rw))
}
}
}
func (ft *FixedTable) Step() bool {
ft.Epoch.Same() // good idea to just reset all non-inner-most counters at start
if ft.Trial.Incr() { // if true, hit max, reset to 0
ft.PermuteOrder()
ft.Epoch.Incr()
}
ft.SetTrialName()
ft.SetGroupName()
return true
}
func (ft *FixedTable) Counter(scale TimeScales) (cur, prv int, chg bool) {
switch scale {
case Run:
return ft.Run.Query()
case Epoch:
return ft.Epoch.Query()
case Trial:
return ft.Trial.Query()
}
return -1, -1, false
}
func (ft *FixedTable) State(element string) etensor.Tensor {
et, err := ft.Table.Table.CellTensorTry(element, ft.Row())
if err != nil {
log.Println(err)
}
return et
}
func (ft *FixedTable) Action(element string, input etensor.Tensor) {
// nop
}
// Compile-time check that implements Env interface
var _ Env = (*FixedTable)(nil)
/////////////////////////////////////////////////////
// EnvDesc -- optional but implemented here
func (ft *FixedTable) Counters() []TimeScales {
return []TimeScales{Run, Epoch, Trial}
}
func (ft *FixedTable) States() Elements {
els := Elements{}
els.FromSchema(ft.Table.Table.Schema())
return els
}
func (ft *FixedTable) Actions() Elements {
return nil
}