-
Notifications
You must be signed in to change notification settings - Fork 27
/
Copy pathmpifixed.go
163 lines (135 loc) · 4.74 KB
/
mpifixed.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
// Copyright (c) 2020, 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"
"cogentcore.org/lab/base/randx"
"cogentcore.org/lab/table"
"cogentcore.org/lab/tensor"
"cogentcore.org/lab/tensor/tensormpi"
)
// MPIFixedTable is an MPI-enabled version of the [FixedTable], which is
// a basic Env that manages patterns from a [table.Table[, with
// either sequential or permuted random ordering, and a Trial counter to
// record iterations through the table.
// Use [table.NewView] to provide a unique indexed view of a shared table.
// The MPI version distributes trials across MPI procs, in the Order list.
// It is ESSENTIAL that the number of trials (rows) in Table is
// evenly divisible by number of MPI procs!
// If all nodes start with the same seed, it should remain synchronized.
type MPIFixedTable struct {
// name of this environment
Name string
// Table has 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.
// This adds the random permuted Order on top of those if !sequential.
Table *table.Table
// 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 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 Counter `display:"inline"`
// if Table has a Name column, this is the contents of that
TrialName CurPrevString
// if Table has a Group column, this is contents of that
GroupName CurPrevString
// name of the Name column -- defaults to 'Name'
NameCol string
// name of the Group column -- defaults to 'Group'
GroupCol string
// for MPI, trial we start each epoch on, as index into Order
TrialSt int
// for MPI, trial number we end each epoch before (i.e., when ctr gets to Ed, restarts)
TrialEd int
}
func (ft *MPIFixedTable) Validate() error {
if ft.Table == nil {
return fmt.Errorf("MPIFixedTable: %v has no Table set", ft.Name)
}
if ft.Table.NumColumns() == 0 {
return fmt.Errorf("MPIFixedTable: %v Table has no columns -- Outputs will be invalid", ft.Name)
}
return nil
}
func (ft *MPIFixedTable) Label() string { return ft.Name }
func (ft *MPIFixedTable) String() string {
s := ft.TrialName.Cur
if ft.GroupName.Cur != "" {
s = ft.GroupName.Cur + "_" + s
}
return s
}
func (ft *MPIFixedTable) Init(run int) {
if ft.NameCol == "" {
ft.NameCol = "Name"
}
if ft.GroupCol == "" {
ft.GroupCol = "Group"
}
ft.Trial.Init()
ft.NewOrder()
ft.Trial.Cur = ft.TrialSt - 1 // init state -- key so that first Step() = ft.TrialSt
}
// NewOrder sets a new random Order based on number of rows in the table.
func (ft *MPIFixedTable) NewOrder() {
np := ft.Table.NumRows()
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.TrialSt, ft.TrialEd, _ = tensormpi.AllocN(np)
ft.Trial.Max = ft.TrialEd
}
// PermuteOrder permutes the existing order table to get a new random sequence of inputs
// just calls: randx.PermuteInts(ft.Order)
func (ft *MPIFixedTable) PermuteOrder() {
randx.PermuteInts(ft.Order)
}
// Row returns the current row number in table, based on Sequential / perumuted Order.
func (ft *MPIFixedTable) Row() int {
if ft.Sequential {
return ft.Trial.Cur
}
return ft.Order[ft.Trial.Cur]
}
func (ft *MPIFixedTable) SetTrialName() {
if nms := ft.Table.Column(ft.NameCol); nms != nil {
rw := ft.Row()
if rw >= 0 && rw < nms.Len() {
ft.TrialName.Set(nms.StringRow(rw, 0))
}
}
}
func (ft *MPIFixedTable) SetGroupName() {
if nms := ft.Table.Column(ft.GroupCol); nms != nil {
rw := ft.Row()
if rw >= 0 && rw < nms.Len() {
ft.GroupName.Set(nms.StringRow(rw, 0))
}
}
}
func (ft *MPIFixedTable) Step() bool {
if ft.Trial.Incr() { // if true, hit max, reset to 0
ft.Trial.Cur = ft.TrialSt // key to reset always to start
ft.PermuteOrder()
}
ft.SetTrialName()
ft.SetGroupName()
return true
}
func (ft *MPIFixedTable) State(element string) tensor.Values {
et := ft.Table.Column(element).RowTensor(ft.Row())
if et == nil {
log.Println("MPIFixedTable.State -- could not find element:", element)
}
return et
}
func (ft *MPIFixedTable) Action(element string, input tensor.Values) {
// nop
}
// Compile-time check that implements Env interface
var _ Env = (*MPIFixedTable)(nil)