From 283d532b80672b717ae7795dd94e59fe28382fe3 Mon Sep 17 00:00:00 2001 From: "Randall C. O'Reilly" Date: Fri, 15 Dec 2023 14:42:39 -0800 Subject: [PATCH] major update to all enums and type info using gti; plots updated; python moved to emerpy --- .goki/config.toml | 75 + axon/act.go | 2 +- axon/act_prjn.go | 21 +- axon/axon.go | 2 + axon/basic_test.go | 6 +- axon/context.go | 4 +- axon/damodtypes_string.go | 57 - axon/enumgen.go | 2478 ++++++++++++++++++++++++++ axon/globals.go | 19 +- axon/globalvars_string.go | 149 -- axon/gplayertypes_string.go | 57 - axon/gpu.go | 2 +- axon/gtigen.go | 1900 ++++++++++++++++++++ axon/hebbprjn.go | 2 +- axon/inhib.go | 2 +- axon/layer.go | 29 +- axon/layerbase.go | 2 +- axon/layertypes.go | 15 +- axon/layertypes_string.go | 111 -- axon/learn.go | 2 +- axon/network.go | 6 +- axon/networkbase.go | 4 +- axon/neuromod.go | 17 +- axon/neuron.go | 149 +- axon/neuronavgvars_string.go | 63 - axon/neuronflags_string.go | 58 - axon/neuronidxs_string.go | 55 - axon/neuronvars_string.go | 209 --- axon/pcore_layers.go | 18 +- axon/pool.go | 2 +- axon/prjn.go | 10 +- axon/prjn_compute.go | 8 +- axon/prjngtypes_string.go | 59 - axon/prjntypes.go | 13 +- axon/prjntypes_string.go | 71 - axon/pvlv_layers.go | 6 +- axon/rand.go | 2 +- axon/shaders/Makefile | 2 +- axon/shaders/gpu_applyext.spv | Bin 24704 -> 24932 bytes axon/shaders/gpu_cycle.spv | Bin 91520 -> 92556 bytes axon/shaders/gpu_cycleinc.spv | Bin 4992 -> 4992 bytes axon/shaders/gpu_cyclepost.spv | Bin 131940 -> 132612 bytes axon/shaders/gpu_dwt.spv | Bin 89852 -> 90104 bytes axon/shaders/gpu_laygi.spv | Bin 30444 -> 30516 bytes axon/shaders/gpu_minuspool.spv | Bin 28572 -> 28644 bytes axon/shaders/gpu_newstate_neuron.spv | Bin 34780 -> 34852 bytes axon/shaders/gpu_newstate_pool.spv | Bin 34556 -> 34628 bytes axon/shaders/gpu_plusneuron.spv | Bin 33224 -> 33752 bytes axon/shaders/gpu_poolgi.spv | Bin 31120 -> 31192 bytes axon/shaders/gpu_postspike.spv | Bin 43248 -> 43248 bytes axon/shaders/gpu_sendspike.spv | Bin 51100 -> 51100 bytes axon/shaders/gpu_synca.spv | Bin 56404 -> 57232 bytes axon/synapse.go | 132 +- axon/synapsecavars_string.go | 63 - axon/synapseidxs_string.go | 55 - axon/synapsevars_string.go | 59 - axon/threads.go | 5 +- axon/threads_test.go | 3 +- axon/valencetypes_string.go | 53 - chans/ak_plot/ak_plot.go | 130 +- chans/ak_plot/gtigen.go | 41 + chans/chans.go | 2 + chans/gabab_plot/gabab_plot.go | 149 +- chans/gabab_plot/gtigen.go | 51 + chans/gtigen.go | 237 +++ chans/kna.go | 2 +- chans/mahp_plot/gtigen.go | 40 + chans/mahp_plot/mahp_plot.go | 130 +- chans/nmda_plot/gtigen.go | 44 + chans/nmda_plot/nmda_plot.go | 131 +- chans/sahp_plot/gtigen.go | 38 + chans/sahp_plot/sahp_plot.go | 132 +- chans/skca_plot/gtigen.go | 38 + chans/skca_plot/skca_plot.go | 130 +- chans/vgcc_plot/gtigen.go | 40 + chans/vgcc_plot/vgcc_plot.go | 130 +- fsfffb/fsfffb.go | 2 +- fsfffb/inhib.go | 2 +- kinase/enumgen.go | 131 ++ kinase/gtigen.go | 65 + kinase/params.go | 6 +- kinase/plot/synca_plot.go | 22 +- kinase/rules.go | 13 +- kinase/rules_string.go | 42 - nxx1/gtigen.go | 34 + nxx1/nxx1.go | 2 + python/LICENSE | 29 - python/MANIFEST.in | 2 - python/Makefile | 50 - python/README.md | 43 - python/go.mod | 30 - python/go.sum | 367 ---- python/gotopy/README.md | 45 - python/gotopy/leabra-to.py | 371 ---- python/gotopy/requirements.txt | 1 - python/pyside/etor.py | 121 -- python/pyside/pyet.py | 383 ---- python/pyside/pygiv.py | 410 ----- python/pyside/pyparams.py | 36 - python/requirements.txt | 7 - python/setup.py | 22 - 101 files changed, 5721 insertions(+), 4037 deletions(-) create mode 100644 .goki/config.toml delete mode 100644 axon/damodtypes_string.go create mode 100644 axon/enumgen.go delete mode 100644 axon/globalvars_string.go delete mode 100644 axon/gplayertypes_string.go create mode 100644 axon/gtigen.go delete mode 100644 axon/layertypes_string.go delete mode 100644 axon/neuronavgvars_string.go delete mode 100644 axon/neuronflags_string.go delete mode 100644 axon/neuronidxs_string.go delete mode 100644 axon/neuronvars_string.go delete mode 100644 axon/prjngtypes_string.go delete mode 100644 axon/prjntypes_string.go delete mode 100644 axon/synapsecavars_string.go delete mode 100644 axon/synapseidxs_string.go delete mode 100644 axon/synapsevars_string.go delete mode 100644 axon/valencetypes_string.go create mode 100644 chans/ak_plot/gtigen.go create mode 100644 chans/gabab_plot/gtigen.go create mode 100644 chans/gtigen.go create mode 100644 chans/mahp_plot/gtigen.go create mode 100644 chans/nmda_plot/gtigen.go create mode 100644 chans/sahp_plot/gtigen.go create mode 100644 chans/skca_plot/gtigen.go create mode 100644 chans/vgcc_plot/gtigen.go create mode 100644 kinase/enumgen.go create mode 100644 kinase/gtigen.go delete mode 100644 kinase/rules_string.go create mode 100644 nxx1/gtigen.go delete mode 100644 python/LICENSE delete mode 100644 python/MANIFEST.in delete mode 100644 python/Makefile delete mode 100644 python/README.md delete mode 100644 python/go.mod delete mode 100644 python/go.sum delete mode 100644 python/gotopy/README.md delete mode 100755 python/gotopy/leabra-to.py delete mode 100644 python/gotopy/requirements.txt delete mode 100644 python/pyside/etor.py delete mode 100644 python/pyside/pyet.py delete mode 100644 python/pyside/pygiv.py delete mode 100644 python/pyside/pyparams.py delete mode 100644 python/requirements.txt delete mode 100644 python/setup.py diff --git a/.goki/config.toml b/.goki/config.toml new file mode 100644 index 000000000..9b45ba3ca --- /dev/null +++ b/.goki/config.toml @@ -0,0 +1,75 @@ +Name = "axon" +Desc = "" +Version = "v2.0.0-dev0.0.1" +Type = "Library" + +[Build] + Package = "." + Output = "" + ID = "com.org.todo.axon" + Debug = false + Rebuild = false + Install = false + PrintOnly = false + Print = false + Trimpath = false + Work = false + IOSVersion = "13.0" + AndroidMinSDK = 23 + AndroidTargetSDK = 29 + +[Web] + Port = "8080" + RandomVersion = false + Gzip = false + BackgroundColor = "#2d2c2c" + ThemeColor = "#2d2c2c" + LoadingLabel = "" + Lang = "en" + Title = "" + Description = "" + Author = "" + Image = "" + AutoUpdateInterval = "10s" + WasmContentLengthHeader = "" + ServiceWorkerTemplate = "" + +[Setup] + [Setup.Platform] + OS = "" + Arch = "" + +[Log] + Target = "android" + Keep = false + All = "F" + +[Release] + VersionFile = "axon/version.go" + Package = "axon" + +[Generate] + Dir = "." + Output = "gokigen.go" + [Generate.Enumgen] + Dir = "." + Output = "enumgen.go" + Transform = "" + TrimPrefix = "" + AddPrefix = "" + LineComment = true + AcceptLower = true + Text = true + JSON = false + YAML = false + SQL = false + GQL = false + [Generate.Gtigen] + Dir = "." + Output = "gtigen.go" + AddTypes = false + AddMethods = false + AddFuncs = false + Instance = false + TypeVar = false + Setters = false diff --git a/axon/act.go b/axon/act.go index 2f1228f7a..7844cdfb0 100644 --- a/axon/act.go +++ b/axon/act.go @@ -7,8 +7,8 @@ package axon import ( "github.com/emer/axon/chans" "github.com/emer/emergent/v2/erand" - "github.com/goki/gosl/slbool" "goki.dev/etable/v2/minmax" + "goki.dev/gosl/v2/slbool" "goki.dev/mat32/v2" ) diff --git a/axon/act_prjn.go b/axon/act_prjn.go index f7872ce7a..236e1ebc5 100644 --- a/axon/act_prjn.go +++ b/axon/act_prjn.go @@ -8,24 +8,15 @@ import ( "log" "github.com/emer/emergent/v2/erand" - "github.com/goki/gosl/slbool" - "github.com/goki/ki/ints" - "github.com/goki/ki/kit" + "goki.dev/gosl/v2/slbool" "goki.dev/mat32/v2" ) -//go:generate stringer -type=PrjnGTypes - -var KiT_PrjnGTypes = kit.Enums.AddEnum(PrjnGTypesN, kit.NotBitFlag, nil) - -func (ev PrjnGTypes) MarshalJSON() ([]byte, error) { return kit.EnumMarshalJSON(ev) } -func (ev *PrjnGTypes) UnmarshalJSON(b []byte) error { return kit.EnumUnmarshalJSON(ev, b) } - //gosl: start act_prjn // PrjnGTypes represents the conductance (G) effects of a given projection, // including excitatory, inhibitory, and modulatory. -type PrjnGTypes int32 +type PrjnGTypes int32 //enums:enum // The projection conductance types const ( @@ -49,8 +40,6 @@ const ( // Context projections are for inputs to CT layers, which update // only at the end of the plus phase, and send to CtxtGe. ContextG - - PrjnGTypesN ) ////////////////////////////////////////////////////////////////////////////////////// @@ -251,16 +240,16 @@ func (ws *PrjnScaleParams) SLayActScale(savg, snu, ncon float32) float32 { } semExtra := 2 slayActN := int(mat32.Round(savg * snu)) // sending layer actual # active - slayActN = ints.MaxInt(slayActN, 1) + slayActN = max(slayActN, 1) var sc float32 if ncon == snu { sc = 1 / float32(slayActN) } else { maxActN := int(mat32.Min(ncon, float32(slayActN))) // max number we could get avgActN := int(mat32.Round(savg * ncon)) // recv average actual # active if uniform - avgActN = ints.MaxInt(avgActN, 1) + avgActN = max(avgActN, 1) expActN := avgActN + semExtra // expected - expActN = ints.MinInt(expActN, maxActN) + expActN = min(expActN, maxActN) sc = 1 / float32(expActN) } return sc diff --git a/axon/axon.go b/axon/axon.go index e811b35da..da5795926 100644 --- a/axon/axon.go +++ b/axon/axon.go @@ -4,6 +4,8 @@ package axon +//go:generate goki generate -add-types + import ( "github.com/emer/emergent/v2/emer" ) diff --git a/axon/basic_test.go b/axon/basic_test.go index caa2a7495..682cec384 100644 --- a/axon/basic_test.go +++ b/axon/basic_test.go @@ -21,8 +21,8 @@ import ( "github.com/emer/emergent/v2/etime" "github.com/emer/emergent/v2/params" "github.com/emer/emergent/v2/prjn" - "github.com/goki/ki/kit" "goki.dev/etable/v2/etensor" + "goki.dev/laser" "goki.dev/mat32/v2" "golang.org/x/exp/maps" ) @@ -260,7 +260,7 @@ func TestSpikeProp(t *testing.T) { // StructVals adds field vals to given vals map func StructVals(obj any, vals map[string]float32, key string) { - v := kit.NonPtrValue(reflect.ValueOf(obj)) + v := laser.NonPtrValue(reflect.ValueOf(obj)) typ := v.Type() for i := 0; i < v.NumField(); i++ { ft := typ.Field(i) @@ -269,7 +269,7 @@ func StructVals(obj any, vals map[string]float32, key string) { } fv := v.Field(i) kk := key + fmt.Sprintf("\t%s", ft.Name) - vals[kk], _ = kit.ToFloat32(fv.Interface()) + vals[kk], _ = laser.ToFloat32(fv.Interface()) } } diff --git a/axon/context.go b/axon/context.go index 4f5239e68..224400cad 100644 --- a/axon/context.go +++ b/axon/context.go @@ -8,9 +8,9 @@ import ( "math" "github.com/emer/emergent/v2/etime" - "github.com/goki/gosl/slbool" - "github.com/goki/gosl/slrand" "goki.dev/glop/num" + "goki.dev/gosl/v2/slbool" + "goki.dev/gosl/v2/slrand" ) var ( diff --git a/axon/damodtypes_string.go b/axon/damodtypes_string.go deleted file mode 100644 index 81604a5e5..000000000 --- a/axon/damodtypes_string.go +++ /dev/null @@ -1,57 +0,0 @@ -// Code generated by "stringer -type=DAModTypes"; DO NOT EDIT. - -package axon - -import ( - "errors" - "strconv" -) - -var _ = errors.New("dummy error") - -func _() { - // An "invalid array index" compiler error signifies that the constant values have changed. - // Re-run the stringer command to generate them again. - var x [1]struct{} - _ = x[NoDAMod-0] - _ = x[D1Mod-1] - _ = x[D2Mod-2] - _ = x[D1AbsMod-3] - _ = x[DAModTypesN-4] -} - -const _DAModTypes_name = "NoDAModD1ModD2ModD1AbsModDAModTypesN" - -var _DAModTypes_index = [...]uint8{0, 7, 12, 17, 25, 36} - -func (i DAModTypes) String() string { - if i < 0 || i >= DAModTypes(len(_DAModTypes_index)-1) { - return "DAModTypes(" + strconv.FormatInt(int64(i), 10) + ")" - } - return _DAModTypes_name[_DAModTypes_index[i]:_DAModTypes_index[i+1]] -} - -func (i *DAModTypes) FromString(s string) error { - for j := 0; j < len(_DAModTypes_index)-1; j++ { - if s == _DAModTypes_name[_DAModTypes_index[j]:_DAModTypes_index[j+1]] { - *i = DAModTypes(j) - return nil - } - } - return errors.New("String: " + s + " is not a valid option for type: DAModTypes") -} - -var _DAModTypes_descMap = map[DAModTypes]string{ - 0: `NoDAMod means there is no effect of dopamine on neural activity`, - 1: `D1Mod is for neurons that primarily express dopamine D1 receptors, which are excitatory from DA bursts, inhibitory from dips. Cortical neurons can generally use this type, while subcortical populations are more diverse in having both D1 and D2 subtypes.`, - 2: `D2Mod is for neurons that primarily express dopamine D2 receptors, which are excitatory from DA dips, inhibitory from bursts.`, - 3: `D1AbsMod is like D1Mod, except the absolute value of DA is used instead of the signed value. There are a subset of DA neurons that send increased DA for both negative and positive outcomes, targeting frontal neurons.`, - 4: ``, -} - -func (i DAModTypes) Desc() string { - if str, ok := _DAModTypes_descMap[i]; ok { - return str - } - return "DAModTypes(" + strconv.FormatInt(int64(i), 10) + ")" -} diff --git a/axon/enumgen.go b/axon/enumgen.go new file mode 100644 index 000000000..d441cf0cb --- /dev/null +++ b/axon/enumgen.go @@ -0,0 +1,2478 @@ +// Code generated by "goki generate -add-types"; DO NOT EDIT. + +package axon + +import ( + "errors" + "log" + "strconv" + "strings" + + "goki.dev/enums" +) + +var _PrjnGTypesValues = []PrjnGTypes{0, 1, 2, 3, 4} + +// PrjnGTypesN is the highest valid value +// for type PrjnGTypes, plus one. +const PrjnGTypesN PrjnGTypes = 5 + +// An "invalid array index" compiler error signifies that the constant values have changed. +// Re-run the enumgen command to generate them again. +func _PrjnGTypesNoOp() { + var x [1]struct{} + _ = x[ExcitatoryG-(0)] + _ = x[InhibitoryG-(1)] + _ = x[ModulatoryG-(2)] + _ = x[MaintG-(3)] + _ = x[ContextG-(4)] +} + +var _PrjnGTypesNameToValueMap = map[string]PrjnGTypes{ + `ExcitatoryG`: 0, + `excitatoryg`: 0, + `InhibitoryG`: 1, + `inhibitoryg`: 1, + `ModulatoryG`: 2, + `modulatoryg`: 2, + `MaintG`: 3, + `maintg`: 3, + `ContextG`: 4, + `contextg`: 4, +} + +var _PrjnGTypesDescMap = map[PrjnGTypes]string{ + 0: `Excitatory projections drive Ge conductance on receiving neurons, which send to GiRaw and GiSyn neuron variables.`, + 1: `Inhibitory projections drive Gi inhibitory conductance, which send to GiRaw and GiSyn neuron variables.`, + 2: `Modulatory projections have a multiplicative effect on other inputs, which send to GModRaw and GModSyn neuron variables.`, + 3: `Maintenance projections drive unique set of NMDA channels that support strong active maintenance abilities. Send to GMaintRaw and GMaintSyn neuron variables.`, + 4: `Context projections are for inputs to CT layers, which update only at the end of the plus phase, and send to CtxtGe.`, +} + +var _PrjnGTypesMap = map[PrjnGTypes]string{ + 0: `ExcitatoryG`, + 1: `InhibitoryG`, + 2: `ModulatoryG`, + 3: `MaintG`, + 4: `ContextG`, +} + +// String returns the string representation +// of this PrjnGTypes value. +func (i PrjnGTypes) String() string { + if str, ok := _PrjnGTypesMap[i]; ok { + return str + } + return strconv.FormatInt(int64(i), 10) +} + +// SetString sets the PrjnGTypes value from its +// string representation, and returns an +// error if the string is invalid. +func (i *PrjnGTypes) SetString(s string) error { + if val, ok := _PrjnGTypesNameToValueMap[s]; ok { + *i = val + return nil + } + if val, ok := _PrjnGTypesNameToValueMap[strings.ToLower(s)]; ok { + *i = val + return nil + } + return errors.New(s + " is not a valid value for type PrjnGTypes") +} + +// Int64 returns the PrjnGTypes value as an int64. +func (i PrjnGTypes) Int64() int64 { + return int64(i) +} + +// SetInt64 sets the PrjnGTypes value from an int64. +func (i *PrjnGTypes) SetInt64(in int64) { + *i = PrjnGTypes(in) +} + +// Desc returns the description of the PrjnGTypes value. +func (i PrjnGTypes) Desc() string { + if str, ok := _PrjnGTypesDescMap[i]; ok { + return str + } + return i.String() +} + +// PrjnGTypesValues returns all possible values +// for the type PrjnGTypes. +func PrjnGTypesValues() []PrjnGTypes { + return _PrjnGTypesValues +} + +// Values returns all possible values +// for the type PrjnGTypes. +func (i PrjnGTypes) Values() []enums.Enum { + res := make([]enums.Enum, len(_PrjnGTypesValues)) + for i, d := range _PrjnGTypesValues { + res[i] = d + } + return res +} + +// IsValid returns whether the value is a +// valid option for type PrjnGTypes. +func (i PrjnGTypes) IsValid() bool { + _, ok := _PrjnGTypesMap[i] + return ok +} + +// MarshalText implements the [encoding.TextMarshaler] interface. +func (i PrjnGTypes) MarshalText() ([]byte, error) { + return []byte(i.String()), nil +} + +// UnmarshalText implements the [encoding.TextUnmarshaler] interface. +func (i *PrjnGTypes) UnmarshalText(text []byte) error { + if err := i.SetString(string(text)); err != nil { + log.Println(err) + } + return nil +} + +var _GlobalVarsValues = []GlobalVars{0, 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} + +// GlobalVarsN is the highest valid value +// for type GlobalVars, plus one. +const GlobalVarsN GlobalVars = 50 + +// An "invalid array index" compiler error signifies that the constant values have changed. +// Re-run the enumgen command to generate them again. +func _GlobalVarsNoOp() { + var x [1]struct{} + _ = x[GvRew-(0)] + _ = x[GvHasRew-(1)] + _ = x[GvRewPred-(2)] + _ = x[GvPrevPred-(3)] + _ = x[GvHadRew-(4)] + _ = x[GvDA-(5)] + _ = x[GvACh-(6)] + _ = x[GvNE-(7)] + _ = x[GvSer-(8)] + _ = x[GvAChRaw-(9)] + _ = x[GvNotMaint-(10)] + _ = x[GvVSMatrixJustGated-(11)] + _ = x[GvVSMatrixHasGated-(12)] + _ = x[GvCuriosityPoolGated-(13)] + _ = x[GvTime-(14)] + _ = x[GvEffort-(15)] + _ = x[GvUrgencyRaw-(16)] + _ = x[GvUrgency-(17)] + _ = x[GvHasPosUS-(18)] + _ = x[GvHadPosUS-(19)] + _ = x[GvNegUSOutcome-(20)] + _ = x[GvHadNegUSOutcome-(21)] + _ = x[GvPVposSum-(22)] + _ = x[GvPVpos-(23)] + _ = x[GvPVnegSum-(24)] + _ = x[GvPVneg-(25)] + _ = x[GvPVposEst-(26)] + _ = x[GvPVposEstSum-(27)] + _ = x[GvPVposEstDisc-(28)] + _ = x[GvGiveUpDiff-(29)] + _ = x[GvGiveUpProb-(30)] + _ = x[GvGiveUp-(31)] + _ = x[GvGaveUp-(32)] + _ = x[GvVSPatchPos-(33)] + _ = x[GvVSPatchPosPrev-(34)] + _ = x[GvVSPatchPosSum-(35)] + _ = x[GvLHbDip-(36)] + _ = x[GvLHbBurst-(37)] + _ = x[GvLHbPVDA-(38)] + _ = x[GvCeMpos-(39)] + _ = x[GvCeMneg-(40)] + _ = x[GvVtaDA-(41)] + _ = x[GvUSneg-(42)] + _ = x[GvUSnegRaw-(43)] + _ = x[GvDrives-(44)] + _ = x[GvUSpos-(45)] + _ = x[GvVSPatch-(46)] + _ = x[GvVSPatchPrev-(47)] + _ = x[GvOFCposUSPTMaint-(48)] + _ = x[GvVSMatrixPoolGated-(49)] +} + +var _GlobalVarsNameToValueMap = map[string]GlobalVars{ + `GvRew`: 0, + `gvrew`: 0, + `GvHasRew`: 1, + `gvhasrew`: 1, + `GvRewPred`: 2, + `gvrewpred`: 2, + `GvPrevPred`: 3, + `gvprevpred`: 3, + `GvHadRew`: 4, + `gvhadrew`: 4, + `GvDA`: 5, + `gvda`: 5, + `GvACh`: 6, + `gvach`: 6, + `GvNE`: 7, + `gvne`: 7, + `GvSer`: 8, + `gvser`: 8, + `GvAChRaw`: 9, + `gvachraw`: 9, + `GvNotMaint`: 10, + `gvnotmaint`: 10, + `GvVSMatrixJustGated`: 11, + `gvvsmatrixjustgated`: 11, + `GvVSMatrixHasGated`: 12, + `gvvsmatrixhasgated`: 12, + `GvCuriosityPoolGated`: 13, + `gvcuriositypoolgated`: 13, + `GvTime`: 14, + `gvtime`: 14, + `GvEffort`: 15, + `gveffort`: 15, + `GvUrgencyRaw`: 16, + `gvurgencyraw`: 16, + `GvUrgency`: 17, + `gvurgency`: 17, + `GvHasPosUS`: 18, + `gvhasposus`: 18, + `GvHadPosUS`: 19, + `gvhadposus`: 19, + `GvNegUSOutcome`: 20, + `gvnegusoutcome`: 20, + `GvHadNegUSOutcome`: 21, + `gvhadnegusoutcome`: 21, + `GvPVposSum`: 22, + `gvpvpossum`: 22, + `GvPVpos`: 23, + `gvpvpos`: 23, + `GvPVnegSum`: 24, + `gvpvnegsum`: 24, + `GvPVneg`: 25, + `gvpvneg`: 25, + `GvPVposEst`: 26, + `gvpvposest`: 26, + `GvPVposEstSum`: 27, + `gvpvposestsum`: 27, + `GvPVposEstDisc`: 28, + `gvpvposestdisc`: 28, + `GvGiveUpDiff`: 29, + `gvgiveupdiff`: 29, + `GvGiveUpProb`: 30, + `gvgiveupprob`: 30, + `GvGiveUp`: 31, + `gvgiveup`: 31, + `GvGaveUp`: 32, + `gvgaveup`: 32, + `GvVSPatchPos`: 33, + `gvvspatchpos`: 33, + `GvVSPatchPosPrev`: 34, + `gvvspatchposprev`: 34, + `GvVSPatchPosSum`: 35, + `gvvspatchpossum`: 35, + `GvLHbDip`: 36, + `gvlhbdip`: 36, + `GvLHbBurst`: 37, + `gvlhbburst`: 37, + `GvLHbPVDA`: 38, + `gvlhbpvda`: 38, + `GvCeMpos`: 39, + `gvcempos`: 39, + `GvCeMneg`: 40, + `gvcemneg`: 40, + `GvVtaDA`: 41, + `gvvtada`: 41, + `GvUSneg`: 42, + `gvusneg`: 42, + `GvUSnegRaw`: 43, + `gvusnegraw`: 43, + `GvDrives`: 44, + `gvdrives`: 44, + `GvUSpos`: 45, + `gvuspos`: 45, + `GvVSPatch`: 46, + `gvvspatch`: 46, + `GvVSPatchPrev`: 47, + `gvvspatchprev`: 47, + `GvOFCposUSPTMaint`: 48, + `gvofcposusptmaint`: 48, + `GvVSMatrixPoolGated`: 49, + `gvvsmatrixpoolgated`: 49, +} + +var _GlobalVarsDescMap = map[GlobalVars]string{ + 0: `Rew is reward value -- this is set here in the Context struct, and the RL Rew layer grabs it from there -- must also set HasRew flag when rew is set -- otherwise is ignored.`, + 1: `HasRew must be set to true when a reward is present -- otherwise Rew is ignored. Also set when PVLV BOA model gives up. This drives ACh release in the PVLV model.`, + 2: `RewPred is reward prediction -- computed by a special reward prediction layer`, + 3: `PrevPred is previous time step reward prediction -- e.g., for TDPredLayer`, + 4: `HadRew is HasRew state from the previous trial -- copied from HasRew in NewState -- used for updating Effort, Urgency at start of new trial`, + 5: `DA is dopamine -- represents reward prediction error, signaled as phasic increases or decreases in activity relative to a tonic baseline, which is represented by a value of 0. Released by the VTA -- ventral tegmental area, or SNc -- substantia nigra pars compacta.`, + 6: `ACh is acetylcholine -- activated by salient events, particularly at the onset of a reward / punishment outcome (US), or onset of a conditioned stimulus (CS). Driven by BLA -> PPtg that detects changes in BLA activity, via LDTLayer type`, + 7: `NE is norepinepherine -- not yet in use`, + 8: `Ser is serotonin -- not yet in use`, + 9: `AChRaw is raw ACh value used in updating global ACh value by LDTLayer`, + 10: `NotMaint is activity of the PTNotMaintLayer -- drives top-down inhibition of LDT layer / ACh activity.`, + 11: `VSMatrixJustGated is VSMatrix just gated (to engage goal maintenance in PFC areas), set at end of plus phase -- this excludes any gating happening at time of US`, + 12: `VSMatrixHasGated is VSMatrix has gated since the last time HasRew was set (US outcome received or expected one failed to be received`, + 13: `CuriosityPoolGated is true if VSMatrixJustGated and the first pool representing the curiosity / novelty drive gated -- this can change the giving up Effort.Max parameter.`, + 14: `Time is raw time counter, incrementing upward during goal engaged window. This is also copied directly into NegUS[0] which tracks time, but we maintain a separate effort value to make it clearer.`, + 15: `Effort is raw effort counter -- incrementing upward for each effort step during goal engaged window. This is also copied directly into NegUS[1] which tracks effort, but we maintain a separate effort value to make it clearer.`, + 16: `UrgencyRaw is raw effort for urgency -- incrementing upward from effort increments per step when _not_ goal engaged`, + 17: `Urgency is the overall urgency activity level (normalized 0-1), computed from logistic function of GvUrgencyRaw`, + 18: `HasPosUS indicates has positive US on this trial -- drives goal accomplishment logic and gating.`, + 19: `HadPosUS is state from the previous trial (copied from HasPosUS in NewState).`, + 20: `NegUSOutcome indicates that a strong negative US stimulus was experienced, driving phasic ACh, VSMatrix gating to reset current goal engaged plan (if any), and phasic dopamine based on the outcome.`, + 21: `HadNegUSOutcome is state from the previous trial (copied from NegUSOutcome in NewState)`, + 22: `PVposSum is total weighted positive valence primary value = sum of Weight * USpos * Drive`, + 23: `PVpos is normalized positive valence primary value = (1 - 1/(1+PVposGain * PVposSum))`, + 24: `PVnegSum is total weighted negative valence primary value = sum of Weight * USneg`, + 25: `PVpos is normalized negative valence primary value = (1 - 1/(1+PVnegGain * PVnegSum))`, + 26: `PVposEst is the estimated PVpos value based on OFCposUSPT and VSMatrix gating`, + 27: `PVposEstSum is the sum that goes into computing estimated PVpos value based on OFCposUSPT and VSMatrix gating`, + 28: `PVposEstDisc is the discounted version of PVposEst, subtracting VSPatchPosSum, which represents the accumulated expectation of PVpos to this point.`, + 29: `GiveUpDiff is the difference: PVposEstDisc - PVneg representing the expected positive outcome up to this point. When this turns negative, the chance of giving up goes up proportionally, as a logistic function of this difference.`, + 30: `GiveUpProb is the probability from the logistic function of GiveUpDiff`, + 31: `GiveUp is true if a reset was triggered probabilistically based on GiveUpProb`, + 32: `GaveUp is copy of GiveUp from previous trial`, + 33: `VSPatchPos is net shunting input from VSPatch (PosD1, named PVi in original PVLV) computed as the Max of US-specific VSPatch saved values. This is also stored as GvRewPred.`, + 34: `VSPatchPosPrev is the previous-trial version of VSPatchPos -- for adjusting the VSPatchThr threshold`, + 35: `VSPatchPosSum is the sum of VSPatchPos over goal engaged trials, representing the integrated prediction that the US is going to occur`, + 36: `computed LHb activity level that drives dipping / pausing of DA firing, when VSPatch pos prediction > actual PV reward drive or PVneg > PVpos`, + 37: `LHbBurst is computed LHb activity level that drives bursts of DA firing, when actual PV reward drive > VSPatch pos prediction`, + 38: `LHbPVDA is GvLHbBurst - GvLHbDip -- the LHb contribution to DA, reflecting PV and VSPatch (PVi), but not the CS (LV) contributions`, + 39: `CeMpos is positive valence central nucleus of the amygdala (CeM) LV (learned value) activity, reflecting |BLAPosAcqD1 - BLAPosExtD2|_+ positively rectified. CeM sets Raw directly. Note that a positive US onset even with no active Drive will be reflected here, enabling learning about unexpected outcomes`, + 40: `CeMneg is negative valence central nucleus of the amygdala (CeM) LV (learned value) activity, reflecting |BLANegAcqD2 - BLANegExtD1|_+ positively rectified. CeM sets Raw directly`, + 41: `VtaDA is overall dopamine value reflecting all of the different inputs`, + 42: `USneg are negative valence US outcomes -- normalized version of raw, NNegUSs of them`, + 43: `USnegRaw are raw, linearly incremented negative valence US outcomes, this value is also integrated together with all US vals for PVneg`, + 44: `Drives is current drive state -- updated with optional homeostatic exponential return to baseline values`, + 45: `USpos is current positive-valence drive-satisfying input(s) (unconditioned stimuli = US)`, + 46: `VSPatch is current reward predicting VSPatch (PosD1) values`, + 47: `VSPatch is previous reward predicting VSPatch (PosD1) values`, + 48: `OFCposUSPTMaint is activity level of given OFCposUSPT maintenance pool used in anticipating potential USpos outcome value`, + 49: `VSMatrixPoolGated indicates whether given VSMatrix pool gated this is reset after last goal accomplished -- records gating since then.`, +} + +var _GlobalVarsMap = map[GlobalVars]string{ + 0: `GvRew`, + 1: `GvHasRew`, + 2: `GvRewPred`, + 3: `GvPrevPred`, + 4: `GvHadRew`, + 5: `GvDA`, + 6: `GvACh`, + 7: `GvNE`, + 8: `GvSer`, + 9: `GvAChRaw`, + 10: `GvNotMaint`, + 11: `GvVSMatrixJustGated`, + 12: `GvVSMatrixHasGated`, + 13: `GvCuriosityPoolGated`, + 14: `GvTime`, + 15: `GvEffort`, + 16: `GvUrgencyRaw`, + 17: `GvUrgency`, + 18: `GvHasPosUS`, + 19: `GvHadPosUS`, + 20: `GvNegUSOutcome`, + 21: `GvHadNegUSOutcome`, + 22: `GvPVposSum`, + 23: `GvPVpos`, + 24: `GvPVnegSum`, + 25: `GvPVneg`, + 26: `GvPVposEst`, + 27: `GvPVposEstSum`, + 28: `GvPVposEstDisc`, + 29: `GvGiveUpDiff`, + 30: `GvGiveUpProb`, + 31: `GvGiveUp`, + 32: `GvGaveUp`, + 33: `GvVSPatchPos`, + 34: `GvVSPatchPosPrev`, + 35: `GvVSPatchPosSum`, + 36: `GvLHbDip`, + 37: `GvLHbBurst`, + 38: `GvLHbPVDA`, + 39: `GvCeMpos`, + 40: `GvCeMneg`, + 41: `GvVtaDA`, + 42: `GvUSneg`, + 43: `GvUSnegRaw`, + 44: `GvDrives`, + 45: `GvUSpos`, + 46: `GvVSPatch`, + 47: `GvVSPatchPrev`, + 48: `GvOFCposUSPTMaint`, + 49: `GvVSMatrixPoolGated`, +} + +// String returns the string representation +// of this GlobalVars value. +func (i GlobalVars) String() string { + if str, ok := _GlobalVarsMap[i]; ok { + return str + } + return strconv.FormatInt(int64(i), 10) +} + +// SetString sets the GlobalVars value from its +// string representation, and returns an +// error if the string is invalid. +func (i *GlobalVars) SetString(s string) error { + if val, ok := _GlobalVarsNameToValueMap[s]; ok { + *i = val + return nil + } + if val, ok := _GlobalVarsNameToValueMap[strings.ToLower(s)]; ok { + *i = val + return nil + } + return errors.New(s + " is not a valid value for type GlobalVars") +} + +// Int64 returns the GlobalVars value as an int64. +func (i GlobalVars) Int64() int64 { + return int64(i) +} + +// SetInt64 sets the GlobalVars value from an int64. +func (i *GlobalVars) SetInt64(in int64) { + *i = GlobalVars(in) +} + +// Desc returns the description of the GlobalVars value. +func (i GlobalVars) Desc() string { + if str, ok := _GlobalVarsDescMap[i]; ok { + return str + } + return i.String() +} + +// GlobalVarsValues returns all possible values +// for the type GlobalVars. +func GlobalVarsValues() []GlobalVars { + return _GlobalVarsValues +} + +// Values returns all possible values +// for the type GlobalVars. +func (i GlobalVars) Values() []enums.Enum { + res := make([]enums.Enum, len(_GlobalVarsValues)) + for i, d := range _GlobalVarsValues { + res[i] = d + } + return res +} + +// IsValid returns whether the value is a +// valid option for type GlobalVars. +func (i GlobalVars) IsValid() bool { + _, ok := _GlobalVarsMap[i] + return ok +} + +// MarshalText implements the [encoding.TextMarshaler] interface. +func (i GlobalVars) MarshalText() ([]byte, error) { + return []byte(i.String()), nil +} + +// UnmarshalText implements the [encoding.TextUnmarshaler] interface. +func (i *GlobalVars) UnmarshalText(text []byte) error { + if err := i.SetString(string(text)); err != nil { + log.Println(err) + } + return nil +} + +var _LayerTypesValues = []LayerTypes{0, 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} + +// LayerTypesN is the highest valid value +// for type LayerTypes, plus one. +const LayerTypesN LayerTypes = 31 + +// An "invalid array index" compiler error signifies that the constant values have changed. +// Re-run the enumgen command to generate them again. +func _LayerTypesNoOp() { + var x [1]struct{} + _ = x[SuperLayer-(0)] + _ = x[InputLayer-(1)] + _ = x[TargetLayer-(2)] + _ = x[CompareLayer-(3)] + _ = x[CTLayer-(4)] + _ = x[PulvinarLayer-(5)] + _ = x[TRNLayer-(6)] + _ = x[PTMaintLayer-(7)] + _ = x[PTPredLayer-(8)] + _ = x[PTNotMaintLayer-(9)] + _ = x[MatrixLayer-(10)] + _ = x[STNLayer-(11)] + _ = x[GPLayer-(12)] + _ = x[BGThalLayer-(13)] + _ = x[VSGatedLayer-(14)] + _ = x[BLALayer-(15)] + _ = x[CeMLayer-(16)] + _ = x[VSPatchLayer-(17)] + _ = x[LHbLayer-(18)] + _ = x[DrivesLayer-(19)] + _ = x[UrgencyLayer-(20)] + _ = x[USLayer-(21)] + _ = x[PVLayer-(22)] + _ = x[LDTLayer-(23)] + _ = x[VTALayer-(24)] + _ = x[RewLayer-(25)] + _ = x[RWPredLayer-(26)] + _ = x[RWDaLayer-(27)] + _ = x[TDPredLayer-(28)] + _ = x[TDIntegLayer-(29)] + _ = x[TDDaLayer-(30)] +} + +var _LayerTypesNameToValueMap = map[string]LayerTypes{ + `SuperLayer`: 0, + `superlayer`: 0, + `InputLayer`: 1, + `inputlayer`: 1, + `TargetLayer`: 2, + `targetlayer`: 2, + `CompareLayer`: 3, + `comparelayer`: 3, + `CTLayer`: 4, + `ctlayer`: 4, + `PulvinarLayer`: 5, + `pulvinarlayer`: 5, + `TRNLayer`: 6, + `trnlayer`: 6, + `PTMaintLayer`: 7, + `ptmaintlayer`: 7, + `PTPredLayer`: 8, + `ptpredlayer`: 8, + `PTNotMaintLayer`: 9, + `ptnotmaintlayer`: 9, + `MatrixLayer`: 10, + `matrixlayer`: 10, + `STNLayer`: 11, + `stnlayer`: 11, + `GPLayer`: 12, + `gplayer`: 12, + `BGThalLayer`: 13, + `bgthallayer`: 13, + `VSGatedLayer`: 14, + `vsgatedlayer`: 14, + `BLALayer`: 15, + `blalayer`: 15, + `CeMLayer`: 16, + `cemlayer`: 16, + `VSPatchLayer`: 17, + `vspatchlayer`: 17, + `LHbLayer`: 18, + `lhblayer`: 18, + `DrivesLayer`: 19, + `driveslayer`: 19, + `UrgencyLayer`: 20, + `urgencylayer`: 20, + `USLayer`: 21, + `uslayer`: 21, + `PVLayer`: 22, + `pvlayer`: 22, + `LDTLayer`: 23, + `ldtlayer`: 23, + `VTALayer`: 24, + `vtalayer`: 24, + `RewLayer`: 25, + `rewlayer`: 25, + `RWPredLayer`: 26, + `rwpredlayer`: 26, + `RWDaLayer`: 27, + `rwdalayer`: 27, + `TDPredLayer`: 28, + `tdpredlayer`: 28, + `TDIntegLayer`: 29, + `tdinteglayer`: 29, + `TDDaLayer`: 30, + `tddalayer`: 30, +} + +var _LayerTypesDescMap = map[LayerTypes]string{ + 0: `Super is a superficial cortical layer (lamina 2-3-4) which does not receive direct input or targets. In more generic models, it should be used as a Hidden layer, and maps onto the Hidden type in emer.LayerType.`, + 1: `Input is a layer that receives direct external input in its Ext inputs. Biologically, it can be a primary sensory layer, or a thalamic layer.`, + 2: `Target is a layer that receives direct external target inputs used for driving plus-phase learning. Simple target layers are generally not used in more biological models, which instead use predictive learning via Pulvinar or related mechanisms.`, + 3: `Compare is a layer that receives external comparison inputs, which drive statistics but do NOT drive activation or learning directly. It is rarely used in axon.`, + 4: `CT are layer 6 corticothalamic projecting neurons, which drive "top down" predictions in Pulvinar layers. They maintain information over time via stronger NMDA channels and use maintained prior state information to generate predictions about current states forming on Super layers that then drive PT (5IB) bursting activity, which are the plus-phase drivers of Pulvinar activity.`, + 5: `Pulvinar are thalamic relay cell neurons in the higher-order Pulvinar nucleus of the thalamus, and functionally isomorphic neurons in the MD thalamus, and potentially other areas. These cells alternately reflect predictions driven by CT projections, and actual outcomes driven by 5IB Burst activity from corresponding PT or Super layer neurons that provide strong driving inputs.`, + 6: `TRNLayer is thalamic reticular nucleus layer for inhibitory competition within the thalamus.`, + 7: `PTMaintLayer implements the subset of pyramidal tract (PT) layer 5 intrinsic bursting (5IB) deep neurons that exhibit robust, stable maintenance of activity over the duration of a goal engaged window, modulated by basal ganglia (BG) disinhibitory gating, supported by strong MaintNMDA channels and recurrent excitation. The lateral PTSelfMaint projection uses MaintG to drive GMaintRaw input that feeds into the stronger, longer MaintNMDA channels, and the ThalToPT ModulatoryG projection from BGThalamus multiplicatively modulates the strength of other inputs, such that only at the time of BG gating are these strong enough to drive sustained active maintenance. Use Act.Dend.ModGain to parameterize.`, + 8: `PTPredLayer implements the subset of pyramidal tract (PT) layer 5 intrinsic bursting (5IB) deep neurons that combine modulatory input from PTMaintLayer sustained maintenance and CTLayer dynamic predictive learning that helps to predict state changes during the period of active goal maintenance. This layer provides the primary input to VSPatch US-timing prediction layers, and other layers that require predictive dynamic`, + 9: `PTNotMaintLayer implements a tonically active layer that is inhibited by the PTMaintLayer, thereby providing an active representation of the *absence* of maintained PT activity, which is useful for driving appropriate actions (e.g., exploration) when not in goal-engaged mode.`, + 10: `MatrixLayer represents the matrisome medium spiny neurons (MSNs) that are the main Go / NoGo gating units in BG. These are strongly modulated by phasic dopamine: D1 = Go, D2 = NoGo.`, + 11: `STNLayer represents subthalamic nucleus neurons, with two subtypes: STNp are more strongly driven and get over bursting threshold, driving strong, rapid activation of the KCa channels, causing a long pause in firing, which creates a window during which GPe dynamics resolve Go vs. No balance. STNs are more weakly driven and thus more slowly activate KCa, resulting in a longer period of activation, during which the GPi is inhibited to prevent premature gating based only MtxGo inhibition -- gating only occurs when GPeIn signal has had a chance to integrate its MtxNo inputs.`, + 12: `GPLayer represents a globus pallidus layer in the BG, including: GPeOut, GPeIn, GPeTA (arkypallidal), and GPi. Typically just a single unit per Pool representing a given stripe.`, + 13: `BGThalLayer represents a BG gated thalamic layer, which receives BG gating in the form of an inhibitory projection from GPi. Located mainly in the Ventral thalamus: VA / VM / VL, and also parts of MD mediodorsal thalamus.`, + 14: `VSGated represents explicit coding of VS gating status: JustGated and HasGated (since last US or failed predicted US), For visualization and / or motor action signaling.`, + 15: `BLALayer represents a basolateral amygdala layer which learns to associate arbitrary stimuli (CSs) with behaviorally salient outcomes (USs)`, + 16: `CeMLayer represents a central nucleus of the amygdala layer.`, + 17: `VSPatchLayer represents a ventral striatum patch layer, which learns to represent the expected amount of dopamine reward and projects both directly with shunting inhibition to the VTA and indirectly via the LHb / RMTg to cancel phasic dopamine firing to expected rewards (i.e., reward prediction error).`, + 18: `LHbLayer represents the lateral habenula, which drives dipping in the VTA. It tracks the Global LHb values for visualization purposes -- updated by VTALayer.`, + 19: `DrivesLayer represents the Drives in PVLV framework. It tracks the Global Drives values for visualization and predictive learning purposes.`, + 20: `UrgencyLayer represents the Urgency factor in PVLV framework. It tracks the Global Urgency.Urge value for visualization and predictive learning purposes.`, + 21: `USLayer represents a US unconditioned stimulus layer (USpos or USneg). It tracks the Global USpos or USneg, for visualization and predictive learning purposes. Actual US inputs are set in PVLV.`, + 22: `PVLayer represents a PV primary value layer (PVpos or PVneg) representing the total primary value as a function of US inputs, drives, and effort. It tracks the Global VTA.PVpos, PVneg values for visualization and predictive learning purposes.`, + 23: `LDTLayer represents the laterodorsal tegmentum layer, which is the primary limbic ACh (acetylcholine) driver to other ACh: BG cholinergic interneurons (CIN) and nucleus basalis ACh areas. The phasic ACh release signals reward salient inputs from CS, US and US omssion, and it drives widespread disinhibition of BG gating and VTA DA firing. It receives excitation from superior colliculus which computes a temporal derivative (stimulus specific adaptation, SSA) of sensory inputs, and inhibitory input from OFC, ACC driving suppression of distracting inputs during goal-engaged states.`, + 24: `VTALayer represents the ventral tegmental area, which releases dopamine. It computes final DA value from PVLV-computed LHb PVDA (primary value DA), updated at start of each trial from updated US, Effort, etc state, and cycle-by-cycle LV learned value state reflecting CS inputs, in the Amygdala (CeM). Its activity reflects this DA level, which is effectively broadcast vial Global state values to all layers.`, + 25: `RewLayer represents positive or negative reward values across 2 units, showing spiking rates for each, and Act always represents signed value.`, + 26: `RWPredLayer computes reward prediction for a simple Rescorla-Wagner learning dynamic (i.e., PV learning in the PVLV framework). Activity is computed as linear function of excitatory conductance (which can be negative -- there are no constraints). Use with RWPrjn which does simple delta-rule learning on minus-plus.`, + 27: `RWDaLayer computes a dopamine (DA) signal based on a simple Rescorla-Wagner learning dynamic (i.e., PV learning in the PVLV framework). It computes difference between r(t) and RWPred values. r(t) is accessed directly from a Rew layer -- if no external input then no DA is computed -- critical for effective use of RW only for PV cases. RWPred prediction is also accessed directly from Rew layer to avoid any issues.`, + 28: `TDPredLayer is the temporal differences reward prediction layer. It represents estimated value V(t) in the minus phase, and computes estimated V(t+1) based on its learned weights in plus phase, using the TDPredPrjn projection type for DA modulated learning.`, + 29: `TDIntegLayer is the temporal differences reward integration layer. It represents estimated value V(t) from prior time step in the minus phase, and estimated discount * V(t+1) + r(t) in the plus phase. It gets Rew, PrevPred from Context.NeuroMod, and Special LayerVals from TDPredLayer.`, + 30: `TDDaLayer computes a dopamine (DA) signal as the temporal difference (TD) between the TDIntegLayer activations in the minus and plus phase. These are retrieved from Special LayerVals.`, +} + +var _LayerTypesMap = map[LayerTypes]string{ + 0: `SuperLayer`, + 1: `InputLayer`, + 2: `TargetLayer`, + 3: `CompareLayer`, + 4: `CTLayer`, + 5: `PulvinarLayer`, + 6: `TRNLayer`, + 7: `PTMaintLayer`, + 8: `PTPredLayer`, + 9: `PTNotMaintLayer`, + 10: `MatrixLayer`, + 11: `STNLayer`, + 12: `GPLayer`, + 13: `BGThalLayer`, + 14: `VSGatedLayer`, + 15: `BLALayer`, + 16: `CeMLayer`, + 17: `VSPatchLayer`, + 18: `LHbLayer`, + 19: `DrivesLayer`, + 20: `UrgencyLayer`, + 21: `USLayer`, + 22: `PVLayer`, + 23: `LDTLayer`, + 24: `VTALayer`, + 25: `RewLayer`, + 26: `RWPredLayer`, + 27: `RWDaLayer`, + 28: `TDPredLayer`, + 29: `TDIntegLayer`, + 30: `TDDaLayer`, +} + +// String returns the string representation +// of this LayerTypes value. +func (i LayerTypes) String() string { + if str, ok := _LayerTypesMap[i]; ok { + return str + } + return strconv.FormatInt(int64(i), 10) +} + +// SetString sets the LayerTypes value from its +// string representation, and returns an +// error if the string is invalid. +func (i *LayerTypes) SetString(s string) error { + if val, ok := _LayerTypesNameToValueMap[s]; ok { + *i = val + return nil + } + if val, ok := _LayerTypesNameToValueMap[strings.ToLower(s)]; ok { + *i = val + return nil + } + return errors.New(s + " is not a valid value for type LayerTypes") +} + +// Int64 returns the LayerTypes value as an int64. +func (i LayerTypes) Int64() int64 { + return int64(i) +} + +// SetInt64 sets the LayerTypes value from an int64. +func (i *LayerTypes) SetInt64(in int64) { + *i = LayerTypes(in) +} + +// Desc returns the description of the LayerTypes value. +func (i LayerTypes) Desc() string { + if str, ok := _LayerTypesDescMap[i]; ok { + return str + } + return i.String() +} + +// LayerTypesValues returns all possible values +// for the type LayerTypes. +func LayerTypesValues() []LayerTypes { + return _LayerTypesValues +} + +// Values returns all possible values +// for the type LayerTypes. +func (i LayerTypes) Values() []enums.Enum { + res := make([]enums.Enum, len(_LayerTypesValues)) + for i, d := range _LayerTypesValues { + res[i] = d + } + return res +} + +// IsValid returns whether the value is a +// valid option for type LayerTypes. +func (i LayerTypes) IsValid() bool { + _, ok := _LayerTypesMap[i] + return ok +} + +// MarshalText implements the [encoding.TextMarshaler] interface. +func (i LayerTypes) MarshalText() ([]byte, error) { + return []byte(i.String()), nil +} + +// UnmarshalText implements the [encoding.TextUnmarshaler] interface. +func (i *LayerTypes) UnmarshalText(text []byte) error { + if err := i.SetString(string(text)); err != nil { + log.Println(err) + } + return nil +} + +var _DAModTypesValues = []DAModTypes{0, 1, 2, 3} + +// DAModTypesN is the highest valid value +// for type DAModTypes, plus one. +const DAModTypesN DAModTypes = 4 + +// An "invalid array index" compiler error signifies that the constant values have changed. +// Re-run the enumgen command to generate them again. +func _DAModTypesNoOp() { + var x [1]struct{} + _ = x[NoDAMod-(0)] + _ = x[D1Mod-(1)] + _ = x[D2Mod-(2)] + _ = x[D1AbsMod-(3)] +} + +var _DAModTypesNameToValueMap = map[string]DAModTypes{ + `NoDAMod`: 0, + `nodamod`: 0, + `D1Mod`: 1, + `d1mod`: 1, + `D2Mod`: 2, + `d2mod`: 2, + `D1AbsMod`: 3, + `d1absmod`: 3, +} + +var _DAModTypesDescMap = map[DAModTypes]string{ + 0: `NoDAMod means there is no effect of dopamine on neural activity`, + 1: `D1Mod is for neurons that primarily express dopamine D1 receptors, which are excitatory from DA bursts, inhibitory from dips. Cortical neurons can generally use this type, while subcortical populations are more diverse in having both D1 and D2 subtypes.`, + 2: `D2Mod is for neurons that primarily express dopamine D2 receptors, which are excitatory from DA dips, inhibitory from bursts.`, + 3: `D1AbsMod is like D1Mod, except the absolute value of DA is used instead of the signed value. There are a subset of DA neurons that send increased DA for both negative and positive outcomes, targeting frontal neurons.`, +} + +var _DAModTypesMap = map[DAModTypes]string{ + 0: `NoDAMod`, + 1: `D1Mod`, + 2: `D2Mod`, + 3: `D1AbsMod`, +} + +// String returns the string representation +// of this DAModTypes value. +func (i DAModTypes) String() string { + if str, ok := _DAModTypesMap[i]; ok { + return str + } + return strconv.FormatInt(int64(i), 10) +} + +// SetString sets the DAModTypes value from its +// string representation, and returns an +// error if the string is invalid. +func (i *DAModTypes) SetString(s string) error { + if val, ok := _DAModTypesNameToValueMap[s]; ok { + *i = val + return nil + } + if val, ok := _DAModTypesNameToValueMap[strings.ToLower(s)]; ok { + *i = val + return nil + } + return errors.New(s + " is not a valid value for type DAModTypes") +} + +// Int64 returns the DAModTypes value as an int64. +func (i DAModTypes) Int64() int64 { + return int64(i) +} + +// SetInt64 sets the DAModTypes value from an int64. +func (i *DAModTypes) SetInt64(in int64) { + *i = DAModTypes(in) +} + +// Desc returns the description of the DAModTypes value. +func (i DAModTypes) Desc() string { + if str, ok := _DAModTypesDescMap[i]; ok { + return str + } + return i.String() +} + +// DAModTypesValues returns all possible values +// for the type DAModTypes. +func DAModTypesValues() []DAModTypes { + return _DAModTypesValues +} + +// Values returns all possible values +// for the type DAModTypes. +func (i DAModTypes) Values() []enums.Enum { + res := make([]enums.Enum, len(_DAModTypesValues)) + for i, d := range _DAModTypesValues { + res[i] = d + } + return res +} + +// IsValid returns whether the value is a +// valid option for type DAModTypes. +func (i DAModTypes) IsValid() bool { + _, ok := _DAModTypesMap[i] + return ok +} + +// MarshalText implements the [encoding.TextMarshaler] interface. +func (i DAModTypes) MarshalText() ([]byte, error) { + return []byte(i.String()), nil +} + +// UnmarshalText implements the [encoding.TextUnmarshaler] interface. +func (i *DAModTypes) UnmarshalText(text []byte) error { + if err := i.SetString(string(text)); err != nil { + log.Println(err) + } + return nil +} + +var _ValenceTypesValues = []ValenceTypes{0, 1} + +// ValenceTypesN is the highest valid value +// for type ValenceTypes, plus one. +const ValenceTypesN ValenceTypes = 2 + +// An "invalid array index" compiler error signifies that the constant values have changed. +// Re-run the enumgen command to generate them again. +func _ValenceTypesNoOp() { + var x [1]struct{} + _ = x[Positive-(0)] + _ = x[Negative-(1)] +} + +var _ValenceTypesNameToValueMap = map[string]ValenceTypes{ + `Positive`: 0, + `positive`: 0, + `Negative`: 1, + `negative`: 1, +} + +var _ValenceTypesDescMap = map[ValenceTypes]string{ + 0: `Positive valence codes for outcomes aligned with drives / goals.`, + 1: `Negative valence codes for harmful or aversive outcomes.`, +} + +var _ValenceTypesMap = map[ValenceTypes]string{ + 0: `Positive`, + 1: `Negative`, +} + +// String returns the string representation +// of this ValenceTypes value. +func (i ValenceTypes) String() string { + if str, ok := _ValenceTypesMap[i]; ok { + return str + } + return strconv.FormatInt(int64(i), 10) +} + +// SetString sets the ValenceTypes value from its +// string representation, and returns an +// error if the string is invalid. +func (i *ValenceTypes) SetString(s string) error { + if val, ok := _ValenceTypesNameToValueMap[s]; ok { + *i = val + return nil + } + if val, ok := _ValenceTypesNameToValueMap[strings.ToLower(s)]; ok { + *i = val + return nil + } + return errors.New(s + " is not a valid value for type ValenceTypes") +} + +// Int64 returns the ValenceTypes value as an int64. +func (i ValenceTypes) Int64() int64 { + return int64(i) +} + +// SetInt64 sets the ValenceTypes value from an int64. +func (i *ValenceTypes) SetInt64(in int64) { + *i = ValenceTypes(in) +} + +// Desc returns the description of the ValenceTypes value. +func (i ValenceTypes) Desc() string { + if str, ok := _ValenceTypesDescMap[i]; ok { + return str + } + return i.String() +} + +// ValenceTypesValues returns all possible values +// for the type ValenceTypes. +func ValenceTypesValues() []ValenceTypes { + return _ValenceTypesValues +} + +// Values returns all possible values +// for the type ValenceTypes. +func (i ValenceTypes) Values() []enums.Enum { + res := make([]enums.Enum, len(_ValenceTypesValues)) + for i, d := range _ValenceTypesValues { + res[i] = d + } + return res +} + +// IsValid returns whether the value is a +// valid option for type ValenceTypes. +func (i ValenceTypes) IsValid() bool { + _, ok := _ValenceTypesMap[i] + return ok +} + +// MarshalText implements the [encoding.TextMarshaler] interface. +func (i ValenceTypes) MarshalText() ([]byte, error) { + return []byte(i.String()), nil +} + +// UnmarshalText implements the [encoding.TextUnmarshaler] interface. +func (i *ValenceTypes) UnmarshalText(text []byte) error { + if err := i.SetString(string(text)); err != nil { + log.Println(err) + } + return nil +} + +var _NeuronFlagsValues = []NeuronFlags{1, 2, 4, 8} + +// NeuronFlagsN is the highest valid value +// for type NeuronFlags, plus one. +const NeuronFlagsN NeuronFlags = 9 + +// An "invalid array index" compiler error signifies that the constant values have changed. +// Re-run the enumgen command to generate them again. +func _NeuronFlagsNoOp() { + var x [1]struct{} + _ = x[NeuronOff-(1)] + _ = x[NeuronHasExt-(2)] + _ = x[NeuronHasTarg-(4)] + _ = x[NeuronHasCmpr-(8)] +} + +var _NeuronFlagsNameToValueMap = map[string]NeuronFlags{ + `NeuronOff`: 1, + `neuronoff`: 1, + `NeuronHasExt`: 2, + `neuronhasext`: 2, + `NeuronHasTarg`: 4, + `neuronhastarg`: 4, + `NeuronHasCmpr`: 8, + `neuronhascmpr`: 8, +} + +var _NeuronFlagsDescMap = map[NeuronFlags]string{ + 1: `NeuronOff flag indicates that this neuron has been turned off (i.e., lesioned)`, + 2: `NeuronHasExt means the neuron has external input in its Ext field`, + 4: `NeuronHasTarg means the neuron has external target input in its Target field`, + 8: `NeuronHasCmpr means the neuron has external comparison input in its Target field -- used for computing comparison statistics but does not drive neural activity ever`, +} + +var _NeuronFlagsMap = map[NeuronFlags]string{ + 1: `NeuronOff`, + 2: `NeuronHasExt`, + 4: `NeuronHasTarg`, + 8: `NeuronHasCmpr`, +} + +// String returns the string representation +// of this NeuronFlags value. +func (i NeuronFlags) String() string { + if str, ok := _NeuronFlagsMap[i]; ok { + return str + } + return strconv.FormatInt(int64(i), 10) +} + +// SetString sets the NeuronFlags value from its +// string representation, and returns an +// error if the string is invalid. +func (i *NeuronFlags) SetString(s string) error { + if val, ok := _NeuronFlagsNameToValueMap[s]; ok { + *i = val + return nil + } + if val, ok := _NeuronFlagsNameToValueMap[strings.ToLower(s)]; ok { + *i = val + return nil + } + return errors.New(s + " is not a valid value for type NeuronFlags") +} + +// Int64 returns the NeuronFlags value as an int64. +func (i NeuronFlags) Int64() int64 { + return int64(i) +} + +// SetInt64 sets the NeuronFlags value from an int64. +func (i *NeuronFlags) SetInt64(in int64) { + *i = NeuronFlags(in) +} + +// Desc returns the description of the NeuronFlags value. +func (i NeuronFlags) Desc() string { + if str, ok := _NeuronFlagsDescMap[i]; ok { + return str + } + return i.String() +} + +// NeuronFlagsValues returns all possible values +// for the type NeuronFlags. +func NeuronFlagsValues() []NeuronFlags { + return _NeuronFlagsValues +} + +// Values returns all possible values +// for the type NeuronFlags. +func (i NeuronFlags) Values() []enums.Enum { + res := make([]enums.Enum, len(_NeuronFlagsValues)) + for i, d := range _NeuronFlagsValues { + res[i] = d + } + return res +} + +// IsValid returns whether the value is a +// valid option for type NeuronFlags. +func (i NeuronFlags) IsValid() bool { + _, ok := _NeuronFlagsMap[i] + return ok +} + +// MarshalText implements the [encoding.TextMarshaler] interface. +func (i NeuronFlags) MarshalText() ([]byte, error) { + return []byte(i.String()), nil +} + +// UnmarshalText implements the [encoding.TextUnmarshaler] interface. +func (i *NeuronFlags) UnmarshalText(text []byte) error { + if err := i.SetString(string(text)); err != nil { + log.Println(err) + } + return nil +} + +var _NeuronVarsValues = []NeuronVars{0, 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} + +// NeuronVarsN is the highest valid value +// for type NeuronVars, plus one. +const NeuronVarsN NeuronVars = 80 + +// An "invalid array index" compiler error signifies that the constant values have changed. +// Re-run the enumgen command to generate them again. +func _NeuronVarsNoOp() { + var x [1]struct{} + _ = x[Spike-(0)] + _ = x[Spiked-(1)] + _ = x[Act-(2)] + _ = x[ActInt-(3)] + _ = x[ActM-(4)] + _ = x[ActP-(5)] + _ = x[Ext-(6)] + _ = x[Target-(7)] + _ = x[Ge-(8)] + _ = x[Gi-(9)] + _ = x[Gk-(10)] + _ = x[Inet-(11)] + _ = x[Vm-(12)] + _ = x[VmDend-(13)] + _ = x[ISI-(14)] + _ = x[ISIAvg-(15)] + _ = x[CaSpkP-(16)] + _ = x[CaSpkD-(17)] + _ = x[CaSyn-(18)] + _ = x[CaSpkM-(19)] + _ = x[CaSpkPM-(20)] + _ = x[CaLrn-(21)] + _ = x[NrnCaM-(22)] + _ = x[NrnCaP-(23)] + _ = x[NrnCaD-(24)] + _ = x[CaDiff-(25)] + _ = x[Attn-(26)] + _ = x[RLRate-(27)] + _ = x[SpkMaxCa-(28)] + _ = x[SpkMax-(29)] + _ = x[SpkPrv-(30)] + _ = x[SpkSt1-(31)] + _ = x[SpkSt2-(32)] + _ = x[GeNoiseP-(33)] + _ = x[GeNoise-(34)] + _ = x[GiNoiseP-(35)] + _ = x[GiNoise-(36)] + _ = x[GeExt-(37)] + _ = x[GeRaw-(38)] + _ = x[GeSyn-(39)] + _ = x[GiRaw-(40)] + _ = x[GiSyn-(41)] + _ = x[GeInt-(42)] + _ = x[GeIntNorm-(43)] + _ = x[GiInt-(44)] + _ = x[GModRaw-(45)] + _ = x[GModSyn-(46)] + _ = x[GMaintRaw-(47)] + _ = x[GMaintSyn-(48)] + _ = x[SSGi-(49)] + _ = x[SSGiDend-(50)] + _ = x[Gak-(51)] + _ = x[MahpN-(52)] + _ = x[SahpCa-(53)] + _ = x[SahpN-(54)] + _ = x[GknaMed-(55)] + _ = x[GknaSlow-(56)] + _ = x[GnmdaSyn-(57)] + _ = x[Gnmda-(58)] + _ = x[GnmdaMaint-(59)] + _ = x[GnmdaLrn-(60)] + _ = x[NmdaCa-(61)] + _ = x[GgabaB-(62)] + _ = x[GABAB-(63)] + _ = x[GABABx-(64)] + _ = x[Gvgcc-(65)] + _ = x[VgccM-(66)] + _ = x[VgccH-(67)] + _ = x[VgccCa-(68)] + _ = x[VgccCaInt-(69)] + _ = x[SKCaIn-(70)] + _ = x[SKCaR-(71)] + _ = x[SKCaM-(72)] + _ = x[Gsk-(73)] + _ = x[Burst-(74)] + _ = x[BurstPrv-(75)] + _ = x[CtxtGe-(76)] + _ = x[CtxtGeRaw-(77)] + _ = x[CtxtGeOrig-(78)] + _ = x[NrnFlags-(79)] +} + +var _NeuronVarsNameToValueMap = map[string]NeuronVars{ + `Spike`: 0, + `spike`: 0, + `Spiked`: 1, + `spiked`: 1, + `Act`: 2, + `act`: 2, + `ActInt`: 3, + `actint`: 3, + `ActM`: 4, + `actm`: 4, + `ActP`: 5, + `actp`: 5, + `Ext`: 6, + `ext`: 6, + `Target`: 7, + `target`: 7, + `Ge`: 8, + `ge`: 8, + `Gi`: 9, + `gi`: 9, + `Gk`: 10, + `gk`: 10, + `Inet`: 11, + `inet`: 11, + `Vm`: 12, + `vm`: 12, + `VmDend`: 13, + `vmdend`: 13, + `ISI`: 14, + `isi`: 14, + `ISIAvg`: 15, + `isiavg`: 15, + `CaSpkP`: 16, + `caspkp`: 16, + `CaSpkD`: 17, + `caspkd`: 17, + `CaSyn`: 18, + `casyn`: 18, + `CaSpkM`: 19, + `caspkm`: 19, + `CaSpkPM`: 20, + `caspkpm`: 20, + `CaLrn`: 21, + `calrn`: 21, + `NrnCaM`: 22, + `nrncam`: 22, + `NrnCaP`: 23, + `nrncap`: 23, + `NrnCaD`: 24, + `nrncad`: 24, + `CaDiff`: 25, + `cadiff`: 25, + `Attn`: 26, + `attn`: 26, + `RLRate`: 27, + `rlrate`: 27, + `SpkMaxCa`: 28, + `spkmaxca`: 28, + `SpkMax`: 29, + `spkmax`: 29, + `SpkPrv`: 30, + `spkprv`: 30, + `SpkSt1`: 31, + `spkst1`: 31, + `SpkSt2`: 32, + `spkst2`: 32, + `GeNoiseP`: 33, + `genoisep`: 33, + `GeNoise`: 34, + `genoise`: 34, + `GiNoiseP`: 35, + `ginoisep`: 35, + `GiNoise`: 36, + `ginoise`: 36, + `GeExt`: 37, + `geext`: 37, + `GeRaw`: 38, + `geraw`: 38, + `GeSyn`: 39, + `gesyn`: 39, + `GiRaw`: 40, + `giraw`: 40, + `GiSyn`: 41, + `gisyn`: 41, + `GeInt`: 42, + `geint`: 42, + `GeIntNorm`: 43, + `geintnorm`: 43, + `GiInt`: 44, + `giint`: 44, + `GModRaw`: 45, + `gmodraw`: 45, + `GModSyn`: 46, + `gmodsyn`: 46, + `GMaintRaw`: 47, + `gmaintraw`: 47, + `GMaintSyn`: 48, + `gmaintsyn`: 48, + `SSGi`: 49, + `ssgi`: 49, + `SSGiDend`: 50, + `ssgidend`: 50, + `Gak`: 51, + `gak`: 51, + `MahpN`: 52, + `mahpn`: 52, + `SahpCa`: 53, + `sahpca`: 53, + `SahpN`: 54, + `sahpn`: 54, + `GknaMed`: 55, + `gknamed`: 55, + `GknaSlow`: 56, + `gknaslow`: 56, + `GnmdaSyn`: 57, + `gnmdasyn`: 57, + `Gnmda`: 58, + `gnmda`: 58, + `GnmdaMaint`: 59, + `gnmdamaint`: 59, + `GnmdaLrn`: 60, + `gnmdalrn`: 60, + `NmdaCa`: 61, + `nmdaca`: 61, + `GgabaB`: 62, + `ggabab`: 62, + `GABAB`: 63, + `gabab`: 63, + `GABABx`: 64, + `gababx`: 64, + `Gvgcc`: 65, + `gvgcc`: 65, + `VgccM`: 66, + `vgccm`: 66, + `VgccH`: 67, + `vgcch`: 67, + `VgccCa`: 68, + `vgccca`: 68, + `VgccCaInt`: 69, + `vgcccaint`: 69, + `SKCaIn`: 70, + `skcain`: 70, + `SKCaR`: 71, + `skcar`: 71, + `SKCaM`: 72, + `skcam`: 72, + `Gsk`: 73, + `gsk`: 73, + `Burst`: 74, + `burst`: 74, + `BurstPrv`: 75, + `burstprv`: 75, + `CtxtGe`: 76, + `ctxtge`: 76, + `CtxtGeRaw`: 77, + `ctxtgeraw`: 77, + `CtxtGeOrig`: 78, + `ctxtgeorig`: 78, + `NrnFlags`: 79, + `nrnflags`: 79, +} + +var _NeuronVarsDescMap = map[NeuronVars]string{ + 0: `Spike is whether neuron has spiked or not on this cycle (0 or 1)`, + 1: `Spiked is 1 if neuron has spiked within the last 10 cycles (msecs), corresponding to a nominal max spiking rate of 100 Hz, 0 otherwise -- useful for visualization and computing activity levels in terms of average spiked levels.`, + 2: `Act is rate-coded activation value reflecting instantaneous estimated rate of spiking, based on 1 / ISIAvg. This drives feedback inhibition in the FFFB function (todo: this will change when better inhibition is implemented), and is integrated over time for ActInt which is then used for performance statistics and layer average activations, etc. Should not be used for learning or other computations.`, + 3: `ActInt is integrated running-average activation value computed from Act with time constant Act.Dt.IntTau, to produce a longer-term integrated value reflecting the overall activation state across the ThetaCycle time scale, as the overall response of network to current input state -- this is copied to ActM and ActP at the ends of the minus and plus phases, respectively, and used in computing performance-level statistics (which are typically based on ActM). Should not be used for learning or other computations.`, + 4: `ActM is ActInt activation state at end of third quarter, representing the posterior-cortical minus phase activation -- used for statistics and monitoring network performance. Should not be used for learning or other computations.`, + 5: `ActP is ActInt activation state at end of fourth quarter, representing the posterior-cortical plus_phase activation -- used for statistics and monitoring network performance. Should not be used for learning or other computations.`, + 6: `Ext is external input: drives activation of unit from outside influences (e.g., sensory input)`, + 7: `Target is the target value: drives learning to produce this activation value`, + 8: `Ge is total excitatory conductance, including all forms of excitation (e.g., NMDA) -- does *not* include Gbar.E`, + 9: `Gi is total inhibitory synaptic conductance -- the net inhibitory input to the neuron -- does *not* include Gbar.I`, + 10: `Gk is total potassium conductance, typically reflecting sodium-gated potassium currents involved in adaptation effects -- does *not* include Gbar.K`, + 11: `Inet is net current produced by all channels -- drives update of Vm`, + 12: `Vm is membrane potential -- integrates Inet current over time`, + 13: `VmDend is dendritic membrane potential -- has a slower time constant, is not subject to the VmR reset after spiking`, + 14: `ISI is current inter-spike-interval -- counts up since last spike. Starts at -1 when initialized.`, + 15: `ISIAvg is average inter-spike-interval -- average time interval between spikes, integrated with ISITau rate constant (relatively fast) to capture something close to an instantaneous spiking rate. Starts at -1 when initialized, and goes to -2 after first spike, and is only valid after the second spike post-initialization.`, + 16: `CaSpkP is continuous cascaded integration of CaSpkM at PTau time constant (typically 40), representing neuron-level purely spiking version of plus, LTP direction of weight change and capturing the function of CaMKII in the Kinase learning rule. Used for specialized learning and computational functions, statistics, instead of Act.`, + 17: `CaSpkD is continuous cascaded integration CaSpkP at DTau time constant (typically 40), representing neuron-level purely spiking version of minus, LTD direction of weight change and capturing the function of DAPK1 in the Kinase learning rule. Used for specialized learning and computational functions, statistics, instead of Act.`, + 18: `CaSyn is spike-driven calcium trace for synapse-level Ca-driven learning: exponential integration of SpikeG * Spike at SynTau time constant (typically 30). Synapses integrate send.CaSyn * recv.CaSyn across M, P, D time integrals for the synaptic trace driving credit assignment in learning. Time constant reflects binding time of Glu to NMDA and Ca buffering postsynaptically, and determines time window where pre * post spiking must overlap to drive learning.`, + 19: `CaSpkM is spike-driven calcium trace used as a neuron-level proxy for synpatic credit assignment factor based on continuous time-integrated spiking: exponential integration of SpikeG * Spike at MTau time constant (typically 5). Simulates a calmodulin (CaM) like signal at the most abstract level.`, + 20: `CaSpkPM is minus-phase snapshot of the CaSpkP value -- similar to ActM but using a more directly spike-integrated value.`, + 21: `CaLrn is recv neuron calcium signal used to drive temporal error difference component of standard learning rule, combining NMDA (NmdaCa) and spiking-driven VGCC (VgccCaInt) calcium sources (vs. CaSpk* which only reflects spiking component). This is integrated into CaM, CaP, CaD, and temporal derivative is CaP - CaD (CaMKII - DAPK1). This approximates the backprop error derivative on net input, but VGCC component adds a proportion of recv activation delta as well -- a balance of both works best. The synaptic-level trace multiplier provides the credit assignment factor, reflecting coincident activity and potentially integrated over longer multi-trial timescales.`, + 22: `NrnCaM is integrated CaLrn at MTau timescale (typically 5), simulating a calmodulin (CaM) like signal, which then drives CaP, CaD for delta signal driving error-driven learning.`, + 23: `NrnCaP is cascaded integration of CaM at PTau time constant (typically 40), representing the plus, LTP direction of weight change and capturing the function of CaMKII in the Kinase learning rule.`, + 24: `NrnCaD is cascaded integratoin of CaP at DTau time constant (typically 40), representing the minus, LTD direction of weight change and capturing the function of DAPK1 in the Kinase learning rule.`, + 25: `CaDiff is difference between CaP - CaD -- this is the error signal that drives error-driven learning.`, + 26: `Attn is Attentional modulation factor, which can be set by special layers such as the TRC -- multiplies Ge`, + 27: `RLRate is recv-unit based learning rate multiplier, reflecting the sigmoid derivative computed from the CaSpkD of recv unit, and the normalized difference CaSpkP - CaSpkD / MAX(CaSpkP - CaSpkD).`, + 28: `SpkMaxCa is Ca integrated like CaSpkP but only starting at MaxCycStart cycle, to prevent inclusion of carryover spiking from prior theta cycle trial -- the PTau time constant otherwise results in significant carryover. This is the input to SpkMax`, + 29: `SpkMax is maximum CaSpkP across one theta cycle time window (max of SpkMaxCa) -- used for specialized algorithms that have more phasic behavior within a single trial, e.g., BG Matrix layer gating. Also useful for visualization of peak activity of neurons.`, + 30: `SpkPrv is final CaSpkD activation state at end of previous theta cycle. used for specialized learning mechanisms that operate on delayed sending activations.`, + 31: `SpkSt1 is the activation state at specific time point within current state processing window (e.g., 50 msec for beta cycle within standard theta cycle), as saved by SpkSt1() function. Used for example in hippocampus for CA3, CA1 learning`, + 32: `SpkSt2 is the activation state at specific time point within current state processing window (e.g., 100 msec for beta cycle within standard theta cycle), as saved by SpkSt2() function. Used for example in hippocampus for CA3, CA1 learning`, + 33: `GeNoiseP is accumulating poisson probability factor for driving excitatory noise spiking -- multiply times uniform random deviate at each time step, until it gets below the target threshold based on lambda.`, + 34: `GeNoise is integrated noise excitatory conductance, added into Ge`, + 35: `GiNoiseP is accumulating poisson probability factor for driving inhibitory noise spiking -- multiply times uniform random deviate at each time step, until it gets below the target threshold based on lambda.`, + 36: `GiNoise is integrated noise inhibotyr conductance, added into Gi`, + 37: `GeExt is extra excitatory conductance added to Ge -- from Ext input, GeCtxt etc`, + 38: `GeRaw is raw excitatory conductance (net input) received from senders = current raw spiking drive`, + 39: `GeSyn is time-integrated total excitatory synaptic conductance, with an instantaneous rise time from each spike (in GeRaw) and exponential decay with Dt.GeTau, aggregated over projections -- does *not* include Gbar.E`, + 40: `GiRaw is raw inhibitory conductance (net input) received from senders = current raw spiking drive`, + 41: `GiSyn is time-integrated total inhibitory synaptic conductance, with an instantaneous rise time from each spike (in GiRaw) and exponential decay with Dt.GiTau, aggregated over projections -- does *not* include Gbar.I. This is added with computed FFFB inhibition to get the full inhibition in Gi`, + 42: `GeInt is integrated running-average activation value computed from Ge with time constant Act.Dt.IntTau, to produce a longer-term integrated value reflecting the overall Ge level across the ThetaCycle time scale (Ge itself fluctuates considerably) -- useful for stats to set strength of connections etc to get neurons into right range of overall excitatory drive`, + 43: `GeIntNorm is normalized GeInt value (divided by the layer maximum) -- this is used for learning in layers that require learning on subthreshold activity`, + 44: `GiInt is integrated running-average activation value computed from GiSyn with time constant Act.Dt.IntTau, to produce a longer-term integrated value reflecting the overall synaptic Gi level across the ThetaCycle time scale (Gi itself fluctuates considerably) -- useful for stats to set strength of connections etc to get neurons into right range of overall inhibitory drive`, + 45: `GModRaw is raw modulatory conductance, received from GType = ModulatoryG projections`, + 46: `GModSyn is syn integrated modulatory conductance, received from GType = ModulatoryG projections`, + 47: `GMaintRaw is raw maintenance conductance, received from GType = MaintG projections`, + 48: `GMaintSyn is syn integrated maintenance conductance, integrated using MaintNMDA params.`, + 49: `SSGi is SST+ somatostatin positive slow spiking inhibition`, + 50: `SSGiDend is amount of SST+ somatostatin positive slow spiking inhibition applied to dendritic Vm (VmDend)`, + 51: `Gak is conductance of A-type K potassium channels`, + 52: `MahpN is accumulating voltage-gated gating value for the medium time scale AHP`, + 53: `SahpCa is slowly accumulating calcium value that drives the slow AHP`, + 54: `SahpN is sAHP gating value`, + 55: `GknaMed is conductance of sodium-gated potassium channel (KNa) medium dynamics (Slick) -- produces accommodation / adaptation of firing`, + 56: `GknaSlow is conductance of sodium-gated potassium channel (KNa) slow dynamics (Slack) -- produces accommodation / adaptation of firing`, + 57: `GnmdaSyn is integrated NMDA recv synaptic current -- adds GeRaw and decays with time constant`, + 58: `Gnmda is net postsynaptic (recv) NMDA conductance, after Mg V-gating and Gbar -- added directly to Ge as it has the same reversal potential`, + 59: `GnmdaMaint is net postsynaptic maintenance NMDA conductance, computed from GMaintSyn and GMaintRaw, after Mg V-gating and Gbar -- added directly to Ge as it has the same reversal potential`, + 60: `GnmdaLrn is learning version of integrated NMDA recv synaptic current -- adds GeRaw and decays with time constant -- drives NmdaCa that then drives CaM for learning`, + 61: `NmdaCa is NMDA calcium computed from GnmdaLrn, drives learning via CaM`, + 62: `GgabaB is net GABA-B conductance, after Vm gating and Gbar + Gbase -- applies to Gk, not Gi, for GIRK, with .1 reversal potential.`, + 63: `GABAB is GABA-B / GIRK activation -- time-integrated value with rise and decay time constants`, + 64: `GABABx is GABA-B / GIRK internal drive variable -- gets the raw activation and decays`, + 65: `Gvgcc is conductance (via Ca) for VGCC voltage gated calcium channels`, + 66: `VgccM is activation gate of VGCC channels`, + 67: `VgccH inactivation gate of VGCC channels`, + 68: `VgccCa is instantaneous VGCC calcium flux -- can be driven by spiking or directly from Gvgcc`, + 69: `VgccCaInt time-integrated VGCC calcium flux -- this is actually what drives learning`, + 70: `SKCaIn is intracellular calcium store level, available to be released with spiking as SKCaR, which can bind to SKCa receptors and drive K current. replenishment is a function of spiking activity being below a threshold`, + 71: `SKCaR released amount of intracellular calcium, from SKCaIn, as a function of spiking events. this can bind to SKCa channels and drive K currents.`, + 72: `SKCaM is Calcium-gated potassium channel gating factor, driven by SKCaR via a Hill equation as in chans.SKPCaParams.`, + 73: `Gsk is Calcium-gated potassium channel conductance as a function of Gbar * SKCaM.`, + 74: `Burst is 5IB bursting activation value, computed by thresholding regular CaSpkP value in Super superficial layers`, + 75: `BurstPrv is previous Burst bursting activation from prior time step -- used for context-based learning`, + 76: `CtxtGe is context (temporally delayed) excitatory conductance, driven by deep bursting at end of the plus phase, for CT layers.`, + 77: `CtxtGeRaw is raw update of context (temporally delayed) excitatory conductance, driven by deep bursting at end of the plus phase, for CT layers.`, + 78: `CtxtGeOrig is original CtxtGe value prior to any decay factor -- updates at end of plus phase.`, + 79: `NrnFlags are bit flags for binary state variables, which are converted to / from uint32. These need to be in Vars because they can be differential per data (for ext inputs) and are writable (indexes are read only).`, +} + +var _NeuronVarsMap = map[NeuronVars]string{ + 0: `Spike`, + 1: `Spiked`, + 2: `Act`, + 3: `ActInt`, + 4: `ActM`, + 5: `ActP`, + 6: `Ext`, + 7: `Target`, + 8: `Ge`, + 9: `Gi`, + 10: `Gk`, + 11: `Inet`, + 12: `Vm`, + 13: `VmDend`, + 14: `ISI`, + 15: `ISIAvg`, + 16: `CaSpkP`, + 17: `CaSpkD`, + 18: `CaSyn`, + 19: `CaSpkM`, + 20: `CaSpkPM`, + 21: `CaLrn`, + 22: `NrnCaM`, + 23: `NrnCaP`, + 24: `NrnCaD`, + 25: `CaDiff`, + 26: `Attn`, + 27: `RLRate`, + 28: `SpkMaxCa`, + 29: `SpkMax`, + 30: `SpkPrv`, + 31: `SpkSt1`, + 32: `SpkSt2`, + 33: `GeNoiseP`, + 34: `GeNoise`, + 35: `GiNoiseP`, + 36: `GiNoise`, + 37: `GeExt`, + 38: `GeRaw`, + 39: `GeSyn`, + 40: `GiRaw`, + 41: `GiSyn`, + 42: `GeInt`, + 43: `GeIntNorm`, + 44: `GiInt`, + 45: `GModRaw`, + 46: `GModSyn`, + 47: `GMaintRaw`, + 48: `GMaintSyn`, + 49: `SSGi`, + 50: `SSGiDend`, + 51: `Gak`, + 52: `MahpN`, + 53: `SahpCa`, + 54: `SahpN`, + 55: `GknaMed`, + 56: `GknaSlow`, + 57: `GnmdaSyn`, + 58: `Gnmda`, + 59: `GnmdaMaint`, + 60: `GnmdaLrn`, + 61: `NmdaCa`, + 62: `GgabaB`, + 63: `GABAB`, + 64: `GABABx`, + 65: `Gvgcc`, + 66: `VgccM`, + 67: `VgccH`, + 68: `VgccCa`, + 69: `VgccCaInt`, + 70: `SKCaIn`, + 71: `SKCaR`, + 72: `SKCaM`, + 73: `Gsk`, + 74: `Burst`, + 75: `BurstPrv`, + 76: `CtxtGe`, + 77: `CtxtGeRaw`, + 78: `CtxtGeOrig`, + 79: `NrnFlags`, +} + +// String returns the string representation +// of this NeuronVars value. +func (i NeuronVars) String() string { + if str, ok := _NeuronVarsMap[i]; ok { + return str + } + return strconv.FormatInt(int64(i), 10) +} + +// SetString sets the NeuronVars value from its +// string representation, and returns an +// error if the string is invalid. +func (i *NeuronVars) SetString(s string) error { + if val, ok := _NeuronVarsNameToValueMap[s]; ok { + *i = val + return nil + } + if val, ok := _NeuronVarsNameToValueMap[strings.ToLower(s)]; ok { + *i = val + return nil + } + return errors.New(s + " is not a valid value for type NeuronVars") +} + +// Int64 returns the NeuronVars value as an int64. +func (i NeuronVars) Int64() int64 { + return int64(i) +} + +// SetInt64 sets the NeuronVars value from an int64. +func (i *NeuronVars) SetInt64(in int64) { + *i = NeuronVars(in) +} + +// Desc returns the description of the NeuronVars value. +func (i NeuronVars) Desc() string { + if str, ok := _NeuronVarsDescMap[i]; ok { + return str + } + return i.String() +} + +// NeuronVarsValues returns all possible values +// for the type NeuronVars. +func NeuronVarsValues() []NeuronVars { + return _NeuronVarsValues +} + +// Values returns all possible values +// for the type NeuronVars. +func (i NeuronVars) Values() []enums.Enum { + res := make([]enums.Enum, len(_NeuronVarsValues)) + for i, d := range _NeuronVarsValues { + res[i] = d + } + return res +} + +// IsValid returns whether the value is a +// valid option for type NeuronVars. +func (i NeuronVars) IsValid() bool { + _, ok := _NeuronVarsMap[i] + return ok +} + +// MarshalText implements the [encoding.TextMarshaler] interface. +func (i NeuronVars) MarshalText() ([]byte, error) { + return []byte(i.String()), nil +} + +// UnmarshalText implements the [encoding.TextUnmarshaler] interface. +func (i *NeuronVars) UnmarshalText(text []byte) error { + if err := i.SetString(string(text)); err != nil { + log.Println(err) + } + return nil +} + +var _NeuronAvgVarsValues = []NeuronAvgVars{0, 1, 2, 3, 4, 5, 6} + +// NeuronAvgVarsN is the highest valid value +// for type NeuronAvgVars, plus one. +const NeuronAvgVarsN NeuronAvgVars = 7 + +// An "invalid array index" compiler error signifies that the constant values have changed. +// Re-run the enumgen command to generate them again. +func _NeuronAvgVarsNoOp() { + var x [1]struct{} + _ = x[ActAvg-(0)] + _ = x[AvgPct-(1)] + _ = x[TrgAvg-(2)] + _ = x[DTrgAvg-(3)] + _ = x[AvgDif-(4)] + _ = x[GeBase-(5)] + _ = x[GiBase-(6)] +} + +var _NeuronAvgVarsNameToValueMap = map[string]NeuronAvgVars{ + `ActAvg`: 0, + `actavg`: 0, + `AvgPct`: 1, + `avgpct`: 1, + `TrgAvg`: 2, + `trgavg`: 2, + `DTrgAvg`: 3, + `dtrgavg`: 3, + `AvgDif`: 4, + `avgdif`: 4, + `GeBase`: 5, + `gebase`: 5, + `GiBase`: 6, + `gibase`: 6, +} + +var _NeuronAvgVarsDescMap = map[NeuronAvgVars]string{ + 0: `ActAvg is average activation (of minus phase activation state) over long time intervals (time constant = Dt.LongAvgTau) -- useful for finding hog units and seeing overall distribution of activation`, + 1: `AvgPct is ActAvg as a proportion of overall layer activation -- this is used for synaptic scaling to match TrgAvg activation -- updated at SlowInterval intervals`, + 2: `TrgAvg is neuron's target average activation as a proportion of overall layer activation, assigned during weight initialization, driving synaptic scaling relative to AvgPct`, + 3: `DTrgAvg is change in neuron's target average activation as a result of unit-wise error gradient -- acts like a bias weight. MPI needs to share these across processors.`, + 4: `AvgDif is AvgPct - TrgAvg -- i.e., the error in overall activity level relative to set point for this neuron, which drives synaptic scaling -- updated at SlowInterval intervals`, + 5: `GeBase is baseline level of Ge, added to GeRaw, for intrinsic excitability`, + 6: `GiBase is baseline level of Gi, added to GiRaw, for intrinsic excitability`, +} + +var _NeuronAvgVarsMap = map[NeuronAvgVars]string{ + 0: `ActAvg`, + 1: `AvgPct`, + 2: `TrgAvg`, + 3: `DTrgAvg`, + 4: `AvgDif`, + 5: `GeBase`, + 6: `GiBase`, +} + +// String returns the string representation +// of this NeuronAvgVars value. +func (i NeuronAvgVars) String() string { + if str, ok := _NeuronAvgVarsMap[i]; ok { + return str + } + return strconv.FormatInt(int64(i), 10) +} + +// SetString sets the NeuronAvgVars value from its +// string representation, and returns an +// error if the string is invalid. +func (i *NeuronAvgVars) SetString(s string) error { + if val, ok := _NeuronAvgVarsNameToValueMap[s]; ok { + *i = val + return nil + } + if val, ok := _NeuronAvgVarsNameToValueMap[strings.ToLower(s)]; ok { + *i = val + return nil + } + return errors.New(s + " is not a valid value for type NeuronAvgVars") +} + +// Int64 returns the NeuronAvgVars value as an int64. +func (i NeuronAvgVars) Int64() int64 { + return int64(i) +} + +// SetInt64 sets the NeuronAvgVars value from an int64. +func (i *NeuronAvgVars) SetInt64(in int64) { + *i = NeuronAvgVars(in) +} + +// Desc returns the description of the NeuronAvgVars value. +func (i NeuronAvgVars) Desc() string { + if str, ok := _NeuronAvgVarsDescMap[i]; ok { + return str + } + return i.String() +} + +// NeuronAvgVarsValues returns all possible values +// for the type NeuronAvgVars. +func NeuronAvgVarsValues() []NeuronAvgVars { + return _NeuronAvgVarsValues +} + +// Values returns all possible values +// for the type NeuronAvgVars. +func (i NeuronAvgVars) Values() []enums.Enum { + res := make([]enums.Enum, len(_NeuronAvgVarsValues)) + for i, d := range _NeuronAvgVarsValues { + res[i] = d + } + return res +} + +// IsValid returns whether the value is a +// valid option for type NeuronAvgVars. +func (i NeuronAvgVars) IsValid() bool { + _, ok := _NeuronAvgVarsMap[i] + return ok +} + +// MarshalText implements the [encoding.TextMarshaler] interface. +func (i NeuronAvgVars) MarshalText() ([]byte, error) { + return []byte(i.String()), nil +} + +// UnmarshalText implements the [encoding.TextUnmarshaler] interface. +func (i *NeuronAvgVars) UnmarshalText(text []byte) error { + if err := i.SetString(string(text)); err != nil { + log.Println(err) + } + return nil +} + +var _NeuronIdxsValues = []NeuronIdxs{0, 1, 2} + +// NeuronIdxsN is the highest valid value +// for type NeuronIdxs, plus one. +const NeuronIdxsN NeuronIdxs = 3 + +// An "invalid array index" compiler error signifies that the constant values have changed. +// Re-run the enumgen command to generate them again. +func _NeuronIdxsNoOp() { + var x [1]struct{} + _ = x[NrnNeurIdx-(0)] + _ = x[NrnLayIdx-(1)] + _ = x[NrnSubPool-(2)] +} + +var _NeuronIdxsNameToValueMap = map[string]NeuronIdxs{ + `NrnNeurIdx`: 0, + `nrnneuridx`: 0, + `NrnLayIdx`: 1, + `nrnlayidx`: 1, + `NrnSubPool`: 2, + `nrnsubpool`: 2, +} + +var _NeuronIdxsDescMap = map[NeuronIdxs]string{ + 0: `NrnNeurIdx is the index of this neuron within its owning layer`, + 1: `NrnLayIdx is the index of the layer that this neuron belongs to, needed for neuron-level parallel code.`, + 2: `NrnSubPool is the index of the sub-level inhibitory pool for this neuron (only for 4D shapes, the pool (unit-group / hypercolumn) structure level). Indicies start at 1 -- 0 is layer-level pool (is 0 if no sub-pools).`, +} + +var _NeuronIdxsMap = map[NeuronIdxs]string{ + 0: `NrnNeurIdx`, + 1: `NrnLayIdx`, + 2: `NrnSubPool`, +} + +// String returns the string representation +// of this NeuronIdxs value. +func (i NeuronIdxs) String() string { + if str, ok := _NeuronIdxsMap[i]; ok { + return str + } + return strconv.FormatInt(int64(i), 10) +} + +// SetString sets the NeuronIdxs value from its +// string representation, and returns an +// error if the string is invalid. +func (i *NeuronIdxs) SetString(s string) error { + if val, ok := _NeuronIdxsNameToValueMap[s]; ok { + *i = val + return nil + } + if val, ok := _NeuronIdxsNameToValueMap[strings.ToLower(s)]; ok { + *i = val + return nil + } + return errors.New(s + " is not a valid value for type NeuronIdxs") +} + +// Int64 returns the NeuronIdxs value as an int64. +func (i NeuronIdxs) Int64() int64 { + return int64(i) +} + +// SetInt64 sets the NeuronIdxs value from an int64. +func (i *NeuronIdxs) SetInt64(in int64) { + *i = NeuronIdxs(in) +} + +// Desc returns the description of the NeuronIdxs value. +func (i NeuronIdxs) Desc() string { + if str, ok := _NeuronIdxsDescMap[i]; ok { + return str + } + return i.String() +} + +// NeuronIdxsValues returns all possible values +// for the type NeuronIdxs. +func NeuronIdxsValues() []NeuronIdxs { + return _NeuronIdxsValues +} + +// Values returns all possible values +// for the type NeuronIdxs. +func (i NeuronIdxs) Values() []enums.Enum { + res := make([]enums.Enum, len(_NeuronIdxsValues)) + for i, d := range _NeuronIdxsValues { + res[i] = d + } + return res +} + +// IsValid returns whether the value is a +// valid option for type NeuronIdxs. +func (i NeuronIdxs) IsValid() bool { + _, ok := _NeuronIdxsMap[i] + return ok +} + +// MarshalText implements the [encoding.TextMarshaler] interface. +func (i NeuronIdxs) MarshalText() ([]byte, error) { + return []byte(i.String()), nil +} + +// UnmarshalText implements the [encoding.TextUnmarshaler] interface. +func (i *NeuronIdxs) UnmarshalText(text []byte) error { + if err := i.SetString(string(text)); err != nil { + log.Println(err) + } + return nil +} + +var _GPLayerTypesValues = []GPLayerTypes{0, 1, 2, 3} + +// GPLayerTypesN is the highest valid value +// for type GPLayerTypes, plus one. +const GPLayerTypesN GPLayerTypes = 4 + +// An "invalid array index" compiler error signifies that the constant values have changed. +// Re-run the enumgen command to generate them again. +func _GPLayerTypesNoOp() { + var x [1]struct{} + _ = x[GPeOut-(0)] + _ = x[GPeIn-(1)] + _ = x[GPeTA-(2)] + _ = x[GPi-(3)] +} + +var _GPLayerTypesNameToValueMap = map[string]GPLayerTypes{ + `GPeOut`: 0, + `gpeout`: 0, + `GPeIn`: 1, + `gpein`: 1, + `GPeTA`: 2, + `gpeta`: 2, + `GPi`: 3, + `gpi`: 3, +} + +var _GPLayerTypesDescMap = map[GPLayerTypes]string{ + 0: `GPeOut is Outer layer of GPe neurons, receiving inhibition from MtxGo`, + 1: `GPeIn is Inner layer of GPe neurons, receiving inhibition from GPeOut and MtxNo`, + 2: `GPeTA is arkypallidal layer of GPe neurons, receiving inhibition from GPeIn and projecting inhibition to Mtx`, + 3: `GPi is the inner globus pallidus, functionally equivalent to SNr, receiving from MtxGo and GPeIn, and sending inhibition to VThal`, +} + +var _GPLayerTypesMap = map[GPLayerTypes]string{ + 0: `GPeOut`, + 1: `GPeIn`, + 2: `GPeTA`, + 3: `GPi`, +} + +// String returns the string representation +// of this GPLayerTypes value. +func (i GPLayerTypes) String() string { + if str, ok := _GPLayerTypesMap[i]; ok { + return str + } + return strconv.FormatInt(int64(i), 10) +} + +// SetString sets the GPLayerTypes value from its +// string representation, and returns an +// error if the string is invalid. +func (i *GPLayerTypes) SetString(s string) error { + if val, ok := _GPLayerTypesNameToValueMap[s]; ok { + *i = val + return nil + } + if val, ok := _GPLayerTypesNameToValueMap[strings.ToLower(s)]; ok { + *i = val + return nil + } + return errors.New(s + " is not a valid value for type GPLayerTypes") +} + +// Int64 returns the GPLayerTypes value as an int64. +func (i GPLayerTypes) Int64() int64 { + return int64(i) +} + +// SetInt64 sets the GPLayerTypes value from an int64. +func (i *GPLayerTypes) SetInt64(in int64) { + *i = GPLayerTypes(in) +} + +// Desc returns the description of the GPLayerTypes value. +func (i GPLayerTypes) Desc() string { + if str, ok := _GPLayerTypesDescMap[i]; ok { + return str + } + return i.String() +} + +// GPLayerTypesValues returns all possible values +// for the type GPLayerTypes. +func GPLayerTypesValues() []GPLayerTypes { + return _GPLayerTypesValues +} + +// Values returns all possible values +// for the type GPLayerTypes. +func (i GPLayerTypes) Values() []enums.Enum { + res := make([]enums.Enum, len(_GPLayerTypesValues)) + for i, d := range _GPLayerTypesValues { + res[i] = d + } + return res +} + +// IsValid returns whether the value is a +// valid option for type GPLayerTypes. +func (i GPLayerTypes) IsValid() bool { + _, ok := _GPLayerTypesMap[i] + return ok +} + +// MarshalText implements the [encoding.TextMarshaler] interface. +func (i GPLayerTypes) MarshalText() ([]byte, error) { + return []byte(i.String()), nil +} + +// UnmarshalText implements the [encoding.TextUnmarshaler] interface. +func (i *GPLayerTypes) UnmarshalText(text []byte) error { + if err := i.SetString(string(text)); err != nil { + log.Println(err) + } + return nil +} + +var _PrjnTypesValues = []PrjnTypes{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10} + +// PrjnTypesN is the highest valid value +// for type PrjnTypes, plus one. +const PrjnTypesN PrjnTypes = 11 + +// An "invalid array index" compiler error signifies that the constant values have changed. +// Re-run the enumgen command to generate them again. +func _PrjnTypesNoOp() { + var x [1]struct{} + _ = x[ForwardPrjn-(0)] + _ = x[BackPrjn-(1)] + _ = x[LateralPrjn-(2)] + _ = x[InhibPrjn-(3)] + _ = x[CTCtxtPrjn-(4)] + _ = x[RWPrjn-(5)] + _ = x[TDPredPrjn-(6)] + _ = x[BLAPrjn-(7)] + _ = x[HipPrjn-(8)] + _ = x[VSPatchPrjn-(9)] + _ = x[MatrixPrjn-(10)] +} + +var _PrjnTypesNameToValueMap = map[string]PrjnTypes{ + `ForwardPrjn`: 0, + `forwardprjn`: 0, + `BackPrjn`: 1, + `backprjn`: 1, + `LateralPrjn`: 2, + `lateralprjn`: 2, + `InhibPrjn`: 3, + `inhibprjn`: 3, + `CTCtxtPrjn`: 4, + `ctctxtprjn`: 4, + `RWPrjn`: 5, + `rwprjn`: 5, + `TDPredPrjn`: 6, + `tdpredprjn`: 6, + `BLAPrjn`: 7, + `blaprjn`: 7, + `HipPrjn`: 8, + `hipprjn`: 8, + `VSPatchPrjn`: 9, + `vspatchprjn`: 9, + `MatrixPrjn`: 10, + `matrixprjn`: 10, +} + +var _PrjnTypesDescMap = map[PrjnTypes]string{ + 0: `Forward is a feedforward, bottom-up projection from sensory inputs to higher layers`, + 1: `Back is a feedback, top-down projection from higher layers back to lower layers`, + 2: `Lateral is a lateral projection within the same layer / area`, + 3: `Inhib is an inhibitory projection that drives inhibitory synaptic conductances instead of the default excitatory ones.`, + 4: `CTCtxt are projections from Superficial layers to CT layers that send Burst activations drive updating of CtxtGe excitatory conductance, at end of plus (51B Bursting) phase. Biologically, this projection comes from the PT layer 5IB neurons, but it is simpler to use the Super neurons directly, and PT are optional for most network types. These projections also use a special learning rule that takes into account the temporal delays in the activation states. Can also add self context from CT for deeper temporal context.`, + 5: `RWPrjn does dopamine-modulated learning for reward prediction: Da * Send.CaSpkP (integrated current spiking activity). Uses RLPredPrjn parameters. Use in RWPredLayer typically to generate reward predictions. If the Da sign is positive, the first recv unit learns fully; for negative, second one learns fully. Lower lrate applies for opposite cases. Weights are positive-only.`, + 6: `TDPredPrjn does dopamine-modulated learning for reward prediction: DWt = Da * Send.SpkPrv (activity on *previous* timestep) Uses RLPredPrjn parameters. Use in TDPredLayer typically to generate reward predictions. If the Da sign is positive, the first recv unit learns fully; for negative, second one learns fully. Lower lrate applies for opposite cases. Weights are positive-only.`, + 7: `BLAPrjn implements the PVLV BLA learning rule: dW = ACh * X_t-1 * (Y_t - Y_t-1) The recv delta is across trials, where the US should activate on trial boundary, to enable sufficient time for gating through to OFC, so BLA initially learns based on US present - US absent. It can also learn based on CS onset if there is a prior CS that predicts that.`, + 8: ``, + 9: `VSPatchPrjn implements the VSPatch learning rule: dW = ACh * DA * X * Y where DA is D1 vs. D2 modulated DA level, X = sending activity factor, Y = receiving activity factor, and ACh provides overall modulation.`, + 10: `MatrixPrjn supports trace-based learning, where an initial trace of synaptic co-activity is formed, and then modulated by subsequent phasic dopamine & ACh when an outcome occurs. This bridges the temporal gap between gating activity and subsequent outcomes, and is based biologically on synaptic tags. Trace is reset at time of reward based on ACh level (from CINs in biology).`, +} + +var _PrjnTypesMap = map[PrjnTypes]string{ + 0: `ForwardPrjn`, + 1: `BackPrjn`, + 2: `LateralPrjn`, + 3: `InhibPrjn`, + 4: `CTCtxtPrjn`, + 5: `RWPrjn`, + 6: `TDPredPrjn`, + 7: `BLAPrjn`, + 8: `HipPrjn`, + 9: `VSPatchPrjn`, + 10: `MatrixPrjn`, +} + +// String returns the string representation +// of this PrjnTypes value. +func (i PrjnTypes) String() string { + if str, ok := _PrjnTypesMap[i]; ok { + return str + } + return strconv.FormatInt(int64(i), 10) +} + +// SetString sets the PrjnTypes value from its +// string representation, and returns an +// error if the string is invalid. +func (i *PrjnTypes) SetString(s string) error { + if val, ok := _PrjnTypesNameToValueMap[s]; ok { + *i = val + return nil + } + if val, ok := _PrjnTypesNameToValueMap[strings.ToLower(s)]; ok { + *i = val + return nil + } + return errors.New(s + " is not a valid value for type PrjnTypes") +} + +// Int64 returns the PrjnTypes value as an int64. +func (i PrjnTypes) Int64() int64 { + return int64(i) +} + +// SetInt64 sets the PrjnTypes value from an int64. +func (i *PrjnTypes) SetInt64(in int64) { + *i = PrjnTypes(in) +} + +// Desc returns the description of the PrjnTypes value. +func (i PrjnTypes) Desc() string { + if str, ok := _PrjnTypesDescMap[i]; ok { + return str + } + return i.String() +} + +// PrjnTypesValues returns all possible values +// for the type PrjnTypes. +func PrjnTypesValues() []PrjnTypes { + return _PrjnTypesValues +} + +// Values returns all possible values +// for the type PrjnTypes. +func (i PrjnTypes) Values() []enums.Enum { + res := make([]enums.Enum, len(_PrjnTypesValues)) + for i, d := range _PrjnTypesValues { + res[i] = d + } + return res +} + +// IsValid returns whether the value is a +// valid option for type PrjnTypes. +func (i PrjnTypes) IsValid() bool { + _, ok := _PrjnTypesMap[i] + return ok +} + +// MarshalText implements the [encoding.TextMarshaler] interface. +func (i PrjnTypes) MarshalText() ([]byte, error) { + return []byte(i.String()), nil +} + +// UnmarshalText implements the [encoding.TextUnmarshaler] interface. +func (i *PrjnTypes) UnmarshalText(text []byte) error { + if err := i.SetString(string(text)); err != nil { + log.Println(err) + } + return nil +} + +var _SynapseVarsValues = []SynapseVars{0, 1, 2, 3, 4} + +// SynapseVarsN is the highest valid value +// for type SynapseVars, plus one. +const SynapseVarsN SynapseVars = 5 + +// An "invalid array index" compiler error signifies that the constant values have changed. +// Re-run the enumgen command to generate them again. +func _SynapseVarsNoOp() { + var x [1]struct{} + _ = x[Wt-(0)] + _ = x[LWt-(1)] + _ = x[SWt-(2)] + _ = x[DWt-(3)] + _ = x[DSWt-(4)] +} + +var _SynapseVarsNameToValueMap = map[string]SynapseVars{ + `Wt`: 0, + `wt`: 0, + `LWt`: 1, + `lwt`: 1, + `SWt`: 2, + `swt`: 2, + `DWt`: 3, + `dwt`: 3, + `DSWt`: 4, + `dswt`: 4, +} + +var _SynapseVarsDescMap = map[SynapseVars]string{ + 0: `Wt is effective synaptic weight value, determining how much conductance one spike drives on the receiving neuron, representing the actual number of effective AMPA receptors in the synapse. Wt = SWt * WtSig(LWt), where WtSig produces values between 0-2 based on LWt, centered on 1.`, + 1: `LWt is rapidly learning, linear weight value -- learns according to the lrate specified in the connection spec. Biologically, this represents the internal biochemical processes that drive the trafficking of AMPA receptors in the synaptic density. Initially all LWt are .5, which gives 1 from WtSig function.`, + 2: `SWt is slowly adapting structural weight value, which acts as a multiplicative scaling factor on synaptic efficacy: biologically represents the physical size and efficacy of the dendritic spine. SWt values adapt in an outer loop along with synaptic scaling, with constraints to prevent runaway positive feedback loops and maintain variance and further capacity to learn. Initial variance is all in SWt, with LWt set to .5, and scaling absorbs some of LWt into SWt.`, + 3: `DWt is delta (change in) synaptic weight, from learning -- updates LWt which then updates Wt.`, + 4: `DSWt is change in SWt slow synaptic weight -- accumulates DWt`, +} + +var _SynapseVarsMap = map[SynapseVars]string{ + 0: `Wt`, + 1: `LWt`, + 2: `SWt`, + 3: `DWt`, + 4: `DSWt`, +} + +// String returns the string representation +// of this SynapseVars value. +func (i SynapseVars) String() string { + if str, ok := _SynapseVarsMap[i]; ok { + return str + } + return strconv.FormatInt(int64(i), 10) +} + +// SetString sets the SynapseVars value from its +// string representation, and returns an +// error if the string is invalid. +func (i *SynapseVars) SetString(s string) error { + if val, ok := _SynapseVarsNameToValueMap[s]; ok { + *i = val + return nil + } + if val, ok := _SynapseVarsNameToValueMap[strings.ToLower(s)]; ok { + *i = val + return nil + } + return errors.New(s + " is not a valid value for type SynapseVars") +} + +// Int64 returns the SynapseVars value as an int64. +func (i SynapseVars) Int64() int64 { + return int64(i) +} + +// SetInt64 sets the SynapseVars value from an int64. +func (i *SynapseVars) SetInt64(in int64) { + *i = SynapseVars(in) +} + +// Desc returns the description of the SynapseVars value. +func (i SynapseVars) Desc() string { + if str, ok := _SynapseVarsDescMap[i]; ok { + return str + } + return i.String() +} + +// SynapseVarsValues returns all possible values +// for the type SynapseVars. +func SynapseVarsValues() []SynapseVars { + return _SynapseVarsValues +} + +// Values returns all possible values +// for the type SynapseVars. +func (i SynapseVars) Values() []enums.Enum { + res := make([]enums.Enum, len(_SynapseVarsValues)) + for i, d := range _SynapseVarsValues { + res[i] = d + } + return res +} + +// IsValid returns whether the value is a +// valid option for type SynapseVars. +func (i SynapseVars) IsValid() bool { + _, ok := _SynapseVarsMap[i] + return ok +} + +// MarshalText implements the [encoding.TextMarshaler] interface. +func (i SynapseVars) MarshalText() ([]byte, error) { + return []byte(i.String()), nil +} + +// UnmarshalText implements the [encoding.TextUnmarshaler] interface. +func (i *SynapseVars) UnmarshalText(text []byte) error { + if err := i.SetString(string(text)); err != nil { + log.Println(err) + } + return nil +} + +var _SynapseCaVarsValues = []SynapseCaVars{0, 1, 2, 3, 4, 5, 6} + +// SynapseCaVarsN is the highest valid value +// for type SynapseCaVars, plus one. +const SynapseCaVarsN SynapseCaVars = 7 + +// An "invalid array index" compiler error signifies that the constant values have changed. +// Re-run the enumgen command to generate them again. +func _SynapseCaVarsNoOp() { + var x [1]struct{} + _ = x[CaM-(0)] + _ = x[CaP-(1)] + _ = x[CaD-(2)] + _ = x[CaUpT-(3)] + _ = x[Tr-(4)] + _ = x[DTr-(5)] + _ = x[DiDWt-(6)] +} + +var _SynapseCaVarsNameToValueMap = map[string]SynapseCaVars{ + `CaM`: 0, + `cam`: 0, + `CaP`: 1, + `cap`: 1, + `CaD`: 2, + `cad`: 2, + `CaUpT`: 3, + `caupt`: 3, + `Tr`: 4, + `tr`: 4, + `DTr`: 5, + `dtr`: 5, + `DiDWt`: 6, + `didwt`: 6, +} + +var _SynapseCaVarsDescMap = map[SynapseCaVars]string{ + 0: `CaM is first stage running average (mean) Ca calcium level (like CaM = calmodulin), feeds into CaP`, + 1: `CaP is shorter timescale integrated CaM value, representing the plus, LTP direction of weight change and capturing the function of CaMKII in the Kinase learning rule`, + 2: `CaD is longer timescale integrated CaP value, representing the minus, LTD direction of weight change and capturing the function of DAPK1 in the Kinase learning rule`, + 3: `CaUpT is time in CyclesTotal of last updating of Ca values at the synapse level, for optimized synaptic-level Ca integration -- converted to / from uint32`, + 4: `Tr is trace of synaptic activity over time -- used for credit assignment in learning. In MatrixPrjn this is a tag that is then updated later when US occurs.`, + 5: `DTr is delta (change in) Tr trace of synaptic activity over time`, + 6: `DiDWt is delta weight for each data parallel index (Di) -- this is directly computed from the Ca values (in cortical version) and then aggregated into the overall DWt (which may be further integrated across MPI nodes), which then drives changes in Wt values`, +} + +var _SynapseCaVarsMap = map[SynapseCaVars]string{ + 0: `CaM`, + 1: `CaP`, + 2: `CaD`, + 3: `CaUpT`, + 4: `Tr`, + 5: `DTr`, + 6: `DiDWt`, +} + +// String returns the string representation +// of this SynapseCaVars value. +func (i SynapseCaVars) String() string { + if str, ok := _SynapseCaVarsMap[i]; ok { + return str + } + return strconv.FormatInt(int64(i), 10) +} + +// SetString sets the SynapseCaVars value from its +// string representation, and returns an +// error if the string is invalid. +func (i *SynapseCaVars) SetString(s string) error { + if val, ok := _SynapseCaVarsNameToValueMap[s]; ok { + *i = val + return nil + } + if val, ok := _SynapseCaVarsNameToValueMap[strings.ToLower(s)]; ok { + *i = val + return nil + } + return errors.New(s + " is not a valid value for type SynapseCaVars") +} + +// Int64 returns the SynapseCaVars value as an int64. +func (i SynapseCaVars) Int64() int64 { + return int64(i) +} + +// SetInt64 sets the SynapseCaVars value from an int64. +func (i *SynapseCaVars) SetInt64(in int64) { + *i = SynapseCaVars(in) +} + +// Desc returns the description of the SynapseCaVars value. +func (i SynapseCaVars) Desc() string { + if str, ok := _SynapseCaVarsDescMap[i]; ok { + return str + } + return i.String() +} + +// SynapseCaVarsValues returns all possible values +// for the type SynapseCaVars. +func SynapseCaVarsValues() []SynapseCaVars { + return _SynapseCaVarsValues +} + +// Values returns all possible values +// for the type SynapseCaVars. +func (i SynapseCaVars) Values() []enums.Enum { + res := make([]enums.Enum, len(_SynapseCaVarsValues)) + for i, d := range _SynapseCaVarsValues { + res[i] = d + } + return res +} + +// IsValid returns whether the value is a +// valid option for type SynapseCaVars. +func (i SynapseCaVars) IsValid() bool { + _, ok := _SynapseCaVarsMap[i] + return ok +} + +// MarshalText implements the [encoding.TextMarshaler] interface. +func (i SynapseCaVars) MarshalText() ([]byte, error) { + return []byte(i.String()), nil +} + +// UnmarshalText implements the [encoding.TextUnmarshaler] interface. +func (i *SynapseCaVars) UnmarshalText(text []byte) error { + if err := i.SetString(string(text)); err != nil { + log.Println(err) + } + return nil +} + +var _SynapseIdxsValues = []SynapseIdxs{0, 1, 2} + +// SynapseIdxsN is the highest valid value +// for type SynapseIdxs, plus one. +const SynapseIdxsN SynapseIdxs = 3 + +// An "invalid array index" compiler error signifies that the constant values have changed. +// Re-run the enumgen command to generate them again. +func _SynapseIdxsNoOp() { + var x [1]struct{} + _ = x[SynRecvIdx-(0)] + _ = x[SynSendIdx-(1)] + _ = x[SynPrjnIdx-(2)] +} + +var _SynapseIdxsNameToValueMap = map[string]SynapseIdxs{ + `SynRecvIdx`: 0, + `synrecvidx`: 0, + `SynSendIdx`: 1, + `synsendidx`: 1, + `SynPrjnIdx`: 2, + `synprjnidx`: 2, +} + +var _SynapseIdxsDescMap = map[SynapseIdxs]string{ + 0: `SynRecvIdx is receiving neuron index in network's global list of neurons`, + 1: `SynSendIdx is sending neuron index in network's global list of neurons`, + 2: `SynPrjnIdx is projection index in global list of projections organized as [Layers][RecvPrjns]`, +} + +var _SynapseIdxsMap = map[SynapseIdxs]string{ + 0: `SynRecvIdx`, + 1: `SynSendIdx`, + 2: `SynPrjnIdx`, +} + +// String returns the string representation +// of this SynapseIdxs value. +func (i SynapseIdxs) String() string { + if str, ok := _SynapseIdxsMap[i]; ok { + return str + } + return strconv.FormatInt(int64(i), 10) +} + +// SetString sets the SynapseIdxs value from its +// string representation, and returns an +// error if the string is invalid. +func (i *SynapseIdxs) SetString(s string) error { + if val, ok := _SynapseIdxsNameToValueMap[s]; ok { + *i = val + return nil + } + if val, ok := _SynapseIdxsNameToValueMap[strings.ToLower(s)]; ok { + *i = val + return nil + } + return errors.New(s + " is not a valid value for type SynapseIdxs") +} + +// Int64 returns the SynapseIdxs value as an int64. +func (i SynapseIdxs) Int64() int64 { + return int64(i) +} + +// SetInt64 sets the SynapseIdxs value from an int64. +func (i *SynapseIdxs) SetInt64(in int64) { + *i = SynapseIdxs(in) +} + +// Desc returns the description of the SynapseIdxs value. +func (i SynapseIdxs) Desc() string { + if str, ok := _SynapseIdxsDescMap[i]; ok { + return str + } + return i.String() +} + +// SynapseIdxsValues returns all possible values +// for the type SynapseIdxs. +func SynapseIdxsValues() []SynapseIdxs { + return _SynapseIdxsValues +} + +// Values returns all possible values +// for the type SynapseIdxs. +func (i SynapseIdxs) Values() []enums.Enum { + res := make([]enums.Enum, len(_SynapseIdxsValues)) + for i, d := range _SynapseIdxsValues { + res[i] = d + } + return res +} + +// IsValid returns whether the value is a +// valid option for type SynapseIdxs. +func (i SynapseIdxs) IsValid() bool { + _, ok := _SynapseIdxsMap[i] + return ok +} + +// MarshalText implements the [encoding.TextMarshaler] interface. +func (i SynapseIdxs) MarshalText() ([]byte, error) { + return []byte(i.String()), nil +} + +// UnmarshalText implements the [encoding.TextUnmarshaler] interface. +func (i *SynapseIdxs) UnmarshalText(text []byte) error { + if err := i.SetString(string(text)); err != nil { + log.Println(err) + } + return nil +} diff --git a/axon/globals.go b/axon/globals.go index 8e0bc05e3..50b38984b 100644 --- a/axon/globals.go +++ b/axon/globals.go @@ -4,20 +4,11 @@ package axon -import "github.com/goki/ki/kit" - -//go:generate stringer -type=GlobalVars - -var KiT_GlobalVars = kit.Enums.AddEnum(GlobalVarsN, kit.NotBitFlag, nil) - -func (ev GlobalVars) MarshalJSON() ([]byte, error) { return kit.EnumMarshalJSON(ev) } -func (ev *GlobalVars) UnmarshalJSON(b []byte) error { return kit.EnumUnmarshalJSON(ev, b) } - //gosl: start globals // GlobalVars are network-wide variables, such as neuromodulators, reward, drives, etc // including the state for the PVLV phasic dopamine model. -type GlobalVars int32 +type GlobalVars int32 //enums:enum const ( ///////////////////////////////////////// @@ -229,7 +220,13 @@ const ( // this is reset after last goal accomplished -- records gating since then. GvVSMatrixPoolGated - GlobalVarsN + // IMPORTANT: if GvVSMatrixPoolGated is not the last, need to update gosl defn below ) //gosl: end globals + +//gosl: hlsl globals +/* +static const GlobalVars GlobalVarsN = GvVSMatrixPoolGated + 1; +*/ +//gosl: end globals diff --git a/axon/globalvars_string.go b/axon/globalvars_string.go deleted file mode 100644 index b059e107d..000000000 --- a/axon/globalvars_string.go +++ /dev/null @@ -1,149 +0,0 @@ -// Code generated by "stringer -type=GlobalVars"; DO NOT EDIT. - -package axon - -import ( - "errors" - "strconv" -) - -var _ = errors.New("dummy error") - -func _() { - // An "invalid array index" compiler error signifies that the constant values have changed. - // Re-run the stringer command to generate them again. - var x [1]struct{} - _ = x[GvRew-0] - _ = x[GvHasRew-1] - _ = x[GvRewPred-2] - _ = x[GvPrevPred-3] - _ = x[GvHadRew-4] - _ = x[GvDA-5] - _ = x[GvACh-6] - _ = x[GvNE-7] - _ = x[GvSer-8] - _ = x[GvAChRaw-9] - _ = x[GvNotMaint-10] - _ = x[GvVSMatrixJustGated-11] - _ = x[GvVSMatrixHasGated-12] - _ = x[GvCuriosityPoolGated-13] - _ = x[GvTime-14] - _ = x[GvEffort-15] - _ = x[GvUrgencyRaw-16] - _ = x[GvUrgency-17] - _ = x[GvHasPosUS-18] - _ = x[GvHadPosUS-19] - _ = x[GvNegUSOutcome-20] - _ = x[GvHadNegUSOutcome-21] - _ = x[GvPVposSum-22] - _ = x[GvPVpos-23] - _ = x[GvPVnegSum-24] - _ = x[GvPVneg-25] - _ = x[GvPVposEst-26] - _ = x[GvPVposEstSum-27] - _ = x[GvPVposEstDisc-28] - _ = x[GvGiveUpDiff-29] - _ = x[GvGiveUpProb-30] - _ = x[GvGiveUp-31] - _ = x[GvGaveUp-32] - _ = x[GvVSPatchPos-33] - _ = x[GvVSPatchPosPrev-34] - _ = x[GvVSPatchPosSum-35] - _ = x[GvLHbDip-36] - _ = x[GvLHbBurst-37] - _ = x[GvLHbPVDA-38] - _ = x[GvCeMpos-39] - _ = x[GvCeMneg-40] - _ = x[GvVtaDA-41] - _ = x[GvUSneg-42] - _ = x[GvUSnegRaw-43] - _ = x[GvDrives-44] - _ = x[GvUSpos-45] - _ = x[GvVSPatch-46] - _ = x[GvVSPatchPrev-47] - _ = x[GvOFCposUSPTMaint-48] - _ = x[GvVSMatrixPoolGated-49] - _ = x[GlobalVarsN-50] -} - -const _GlobalVars_name = "GvRewGvHasRewGvRewPredGvPrevPredGvHadRewGvDAGvAChGvNEGvSerGvAChRawGvNotMaintGvVSMatrixJustGatedGvVSMatrixHasGatedGvCuriosityPoolGatedGvTimeGvEffortGvUrgencyRawGvUrgencyGvHasPosUSGvHadPosUSGvNegUSOutcomeGvHadNegUSOutcomeGvPVposSumGvPVposGvPVnegSumGvPVnegGvPVposEstGvPVposEstSumGvPVposEstDiscGvGiveUpDiffGvGiveUpProbGvGiveUpGvGaveUpGvVSPatchPosGvVSPatchPosPrevGvVSPatchPosSumGvLHbDipGvLHbBurstGvLHbPVDAGvCeMposGvCeMnegGvVtaDAGvUSnegGvUSnegRawGvDrivesGvUSposGvVSPatchGvVSPatchPrevGvOFCposUSPTMaintGvVSMatrixPoolGatedGlobalVarsN" - -var _GlobalVars_index = [...]uint16{0, 5, 13, 22, 32, 40, 44, 49, 53, 58, 66, 76, 95, 113, 133, 139, 147, 159, 168, 178, 188, 202, 219, 229, 236, 246, 253, 263, 276, 290, 302, 314, 322, 330, 342, 358, 373, 381, 391, 400, 408, 416, 423, 430, 440, 448, 455, 464, 477, 494, 513, 524} - -func (i GlobalVars) String() string { - if i < 0 || i >= GlobalVars(len(_GlobalVars_index)-1) { - return "GlobalVars(" + strconv.FormatInt(int64(i), 10) + ")" - } - return _GlobalVars_name[_GlobalVars_index[i]:_GlobalVars_index[i+1]] -} - -func (i *GlobalVars) FromString(s string) error { - for j := 0; j < len(_GlobalVars_index)-1; j++ { - if s == _GlobalVars_name[_GlobalVars_index[j]:_GlobalVars_index[j+1]] { - *i = GlobalVars(j) - return nil - } - } - return errors.New("String: " + s + " is not a valid option for type: GlobalVars") -} - -var _GlobalVars_descMap = map[GlobalVars]string{ - 0: `Rew is reward value -- this is set here in the Context struct, and the RL Rew layer grabs it from there -- must also set HasRew flag when rew is set -- otherwise is ignored.`, - 1: `HasRew must be set to true when a reward is present -- otherwise Rew is ignored. Also set when PVLV BOA model gives up. This drives ACh release in the PVLV model.`, - 2: `RewPred is reward prediction -- computed by a special reward prediction layer`, - 3: `PrevPred is previous time step reward prediction -- e.g., for TDPredLayer`, - 4: `HadRew is HasRew state from the previous trial -- copied from HasRew in NewState -- used for updating Effort, Urgency at start of new trial`, - 5: `DA is dopamine -- represents reward prediction error, signaled as phasic increases or decreases in activity relative to a tonic baseline, which is represented by a value of 0. Released by the VTA -- ventral tegmental area, or SNc -- substantia nigra pars compacta.`, - 6: `ACh is acetylcholine -- activated by salient events, particularly at the onset of a reward / punishment outcome (US), or onset of a conditioned stimulus (CS). Driven by BLA -> PPtg that detects changes in BLA activity, via LDTLayer type`, - 7: `NE is norepinepherine -- not yet in use`, - 8: `Ser is serotonin -- not yet in use`, - 9: `AChRaw is raw ACh value used in updating global ACh value by LDTLayer`, - 10: `NotMaint is activity of the PTNotMaintLayer -- drives top-down inhibition of LDT layer / ACh activity.`, - 11: `VSMatrixJustGated is VSMatrix just gated (to engage goal maintenance in PFC areas), set at end of plus phase -- this excludes any gating happening at time of US`, - 12: `VSMatrixHasGated is VSMatrix has gated since the last time HasRew was set (US outcome received or expected one failed to be received`, - 13: `CuriosityPoolGated is true if VSMatrixJustGated and the first pool representing the curiosity / novelty drive gated -- this can change the giving up Effort.Max parameter.`, - 14: `Time is raw time counter, incrementing upward during goal engaged window. This is also copied directly into NegUS[0] which tracks time, but we maintain a separate effort value to make it clearer.`, - 15: `Effort is raw effort counter -- incrementing upward for each effort step during goal engaged window. This is also copied directly into NegUS[1] which tracks effort, but we maintain a separate effort value to make it clearer.`, - 16: `UrgencyRaw is raw effort for urgency -- incrementing upward from effort increments per step when _not_ goal engaged`, - 17: `Urgency is the overall urgency activity level (normalized 0-1), computed from logistic function of GvUrgencyRaw`, - 18: `HasPosUS indicates has positive US on this trial -- drives goal accomplishment logic and gating.`, - 19: `HadPosUS is state from the previous trial (copied from HasPosUS in NewState).`, - 20: `NegUSOutcome indicates that a strong negative US stimulus was experienced, driving phasic ACh, VSMatrix gating to reset current goal engaged plan (if any), and phasic dopamine based on the outcome.`, - 21: `HadNegUSOutcome is state from the previous trial (copied from NegUSOutcome in NewState)`, - 22: `PVposSum is total weighted positive valence primary value = sum of Weight * USpos * Drive`, - 23: `PVpos is normalized positive valence primary value = (1 - 1/(1+PVposGain * PVposSum))`, - 24: `PVnegSum is total weighted negative valence primary value = sum of Weight * USneg`, - 25: `PVpos is normalized negative valence primary value = (1 - 1/(1+PVnegGain * PVnegSum))`, - 26: `PVposEst is the estimated PVpos value based on OFCposUSPT and VSMatrix gating`, - 27: `PVposEstSum is the sum that goes into computing estimated PVpos value based on OFCposUSPT and VSMatrix gating`, - 28: `PVposEstDisc is the discounted version of PVposEst, subtracting VSPatchPosSum, which represents the accumulated expectation of PVpos to this point.`, - 29: `GiveUpDiff is the difference: PVposEstDisc - PVneg representing the expected positive outcome up to this point. When this turns negative, the chance of giving up goes up proportionally, as a logistic function of this difference.`, - 30: `GiveUpProb is the probability from the logistic function of GiveUpDiff`, - 31: `GiveUp is true if a reset was triggered probabilistically based on GiveUpProb`, - 32: `GaveUp is copy of GiveUp from previous trial`, - 33: `VSPatchPos is net shunting input from VSPatch (PosD1, named PVi in original PVLV) computed as the Max of US-specific VSPatch saved values. This is also stored as GvRewPred.`, - 34: `VSPatchPosPrev is the previous-trial version of VSPatchPos -- for adjusting the VSPatchThr threshold`, - 35: `VSPatchPosSum is the sum of VSPatchPos over goal engaged trials, representing the integrated prediction that the US is going to occur`, - 36: `computed LHb activity level that drives dipping / pausing of DA firing, when VSPatch pos prediction > actual PV reward drive or PVneg > PVpos`, - 37: `LHbBurst is computed LHb activity level that drives bursts of DA firing, when actual PV reward drive > VSPatch pos prediction`, - 38: `LHbPVDA is GvLHbBurst - GvLHbDip -- the LHb contribution to DA, reflecting PV and VSPatch (PVi), but not the CS (LV) contributions`, - 39: `CeMpos is positive valence central nucleus of the amygdala (CeM) LV (learned value) activity, reflecting |BLAPosAcqD1 - BLAPosExtD2|_+ positively rectified. CeM sets Raw directly. Note that a positive US onset even with no active Drive will be reflected here, enabling learning about unexpected outcomes`, - 40: `CeMneg is negative valence central nucleus of the amygdala (CeM) LV (learned value) activity, reflecting |BLANegAcqD2 - BLANegExtD1|_+ positively rectified. CeM sets Raw directly`, - 41: `VtaDA is overall dopamine value reflecting all of the different inputs`, - 42: `USneg are negative valence US outcomes -- normalized version of raw, NNegUSs of them`, - 43: `USnegRaw are raw, linearly incremented negative valence US outcomes, this value is also integrated together with all US vals for PVneg`, - 44: `Drives is current drive state -- updated with optional homeostatic exponential return to baseline values`, - 45: `USpos is current positive-valence drive-satisfying input(s) (unconditioned stimuli = US)`, - 46: `VSPatch is current reward predicting VSPatch (PosD1) values`, - 47: `VSPatch is previous reward predicting VSPatch (PosD1) values`, - 48: `OFCposUSPTMaint is activity level of given OFCposUSPT maintenance pool used in anticipating potential USpos outcome value`, - 49: `VSMatrixPoolGated indicates whether given VSMatrix pool gated this is reset after last goal accomplished -- records gating since then.`, - 50: ``, -} - -func (i GlobalVars) Desc() string { - if str, ok := _GlobalVars_descMap[i]; ok { - return str - } - return "GlobalVars(" + strconv.FormatInt(int64(i), 10) + ")" -} diff --git a/axon/gplayertypes_string.go b/axon/gplayertypes_string.go deleted file mode 100644 index d713eacd4..000000000 --- a/axon/gplayertypes_string.go +++ /dev/null @@ -1,57 +0,0 @@ -// Code generated by "stringer -type=GPLayerTypes"; DO NOT EDIT. - -package axon - -import ( - "errors" - "strconv" -) - -var _ = errors.New("dummy error") - -func _() { - // An "invalid array index" compiler error signifies that the constant values have changed. - // Re-run the stringer command to generate them again. - var x [1]struct{} - _ = x[GPeOut-0] - _ = x[GPeIn-1] - _ = x[GPeTA-2] - _ = x[GPi-3] - _ = x[GPLayerTypesN-4] -} - -const _GPLayerTypes_name = "GPeOutGPeInGPeTAGPiGPLayerTypesN" - -var _GPLayerTypes_index = [...]uint8{0, 6, 11, 16, 19, 32} - -func (i GPLayerTypes) String() string { - if i < 0 || i >= GPLayerTypes(len(_GPLayerTypes_index)-1) { - return "GPLayerTypes(" + strconv.FormatInt(int64(i), 10) + ")" - } - return _GPLayerTypes_name[_GPLayerTypes_index[i]:_GPLayerTypes_index[i+1]] -} - -func (i *GPLayerTypes) FromString(s string) error { - for j := 0; j < len(_GPLayerTypes_index)-1; j++ { - if s == _GPLayerTypes_name[_GPLayerTypes_index[j]:_GPLayerTypes_index[j+1]] { - *i = GPLayerTypes(j) - return nil - } - } - return errors.New("String: " + s + " is not a valid option for type: GPLayerTypes") -} - -var _GPLayerTypes_descMap = map[GPLayerTypes]string{ - 0: `GPeOut is Outer layer of GPe neurons, receiving inhibition from MtxGo`, - 1: `GPeIn is Inner layer of GPe neurons, receiving inhibition from GPeOut and MtxNo`, - 2: `GPeTA is arkypallidal layer of GPe neurons, receiving inhibition from GPeIn and projecting inhibition to Mtx`, - 3: `GPi is the inner globus pallidus, functionally equivalent to SNr, receiving from MtxGo and GPeIn, and sending inhibition to VThal`, - 4: ``, -} - -func (i GPLayerTypes) Desc() string { - if str, ok := _GPLayerTypes_descMap[i]; ok { - return str - } - return "GPLayerTypes(" + strconv.FormatInt(int64(i), 10) + ")" -} diff --git a/axon/gpu.go b/axon/gpu.go index a9fa6e7a6..69f5d632f 100644 --- a/axon/gpu.go +++ b/axon/gpu.go @@ -19,7 +19,7 @@ import ( //go:embed shaders/*.spv var content embed.FS -//go:generate gosl -exclude=Update,UpdateParams,Defaults,AllParams github.com/goki/mat32/fastexp.go github.com/emer/etable/minmax ../chans/chans.go ../chans ../kinase ../fsfffb/inhib.go ../fsfffb github.com/emer/emergent/etime github.com/emer/emergent/ringidx rand.go avgmax.go neuromod.go globals.go context.go neuron.go synapse.go pool.go layervals.go act.go act_prjn.go inhib.go learn.go layertypes.go layerparams.go deep_layers.go rl_layers.go pvlv_layers.go pcore_layers.go prjntypes.go prjnparams.go deep_prjns.go rl_prjns.go pvlv_prjns.go pcore_prjns.go hip_prjns.go gpu_hlsl +//go:generate gosl -exclude=Update,UpdateParams,Defaults,AllParams goki.dev/mat32/v2/fastexp.go goki.dev/etable/v2/minmax ../chans/chans.go ../chans ../kinase ../fsfffb/inhib.go ../fsfffb github.com/emer/emergent/v2/etime github.com/emer/emergent/v2/ringidx rand.go avgmax.go neuromod.go globals.go context.go neuron.go synapse.go pool.go layervals.go act.go act_prjn.go inhib.go learn.go layertypes.go layerparams.go deep_layers.go rl_layers.go pvlv_layers.go pcore_layers.go prjntypes.go prjnparams.go deep_prjns.go rl_prjns.go pvlv_prjns.go pcore_prjns.go hip_prjns.go gpu_hlsl // Full vars code -- each gpu_*.hlsl uses a subset diff --git a/axon/gtigen.go b/axon/gtigen.go new file mode 100644 index 000000000..41a994c14 --- /dev/null +++ b/axon/gtigen.go @@ -0,0 +1,1900 @@ +// Code generated by "goki generate -add-types"; DO NOT EDIT. + +package axon + +import ( + "goki.dev/gti" + "goki.dev/ordmap" +) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.SpikeParams", + ShortName: "axon.SpikeParams", + IDName: "spike-params", + Doc: "SpikeParams contains spiking activation function params.\nImplements a basic thresholded Vm model, and optionally\nthe AdEx adaptive exponential function (adapt is KNaAdapt)", + Directives: gti.Directives{ + >i.Directive{Tool: "gosl", Directive: "hlsl", Args: []string{"act"}}, + >i.Directive{Tool: "gosl", Directive: "end", Args: []string{"act"}}, + >i.Directive{Tool: "gosl", Directive: "start", Args: []string{"act"}}, + }, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"Thr", >i.Field{Name: "Thr", Type: "float32", LocalType: "float32", Doc: "threshold value Theta (Q) for firing output activation (.5 is more accurate value based on AdEx biological parameters and normalization", Directives: gti.Directives{}, Tag: "def:\"0.5\""}}, + {"VmR", >i.Field{Name: "VmR", Type: "float32", LocalType: "float32", Doc: "post-spiking membrane potential to reset to, produces refractory effect if lower than VmInit -- 0.3 is apropriate biologically-based value for AdEx (Brette & Gurstner, 2005) parameters. See also RTau", Directives: gti.Directives{}, Tag: "def:\"0.3\""}}, + {"Tr", >i.Field{Name: "Tr", Type: "int32", LocalType: "int32", Doc: "post-spiking explicit refractory period, in cycles -- prevents Vm updating for this number of cycles post firing -- Vm is reduced in exponential steps over this period according to RTau, being fixed at Tr to VmR exactly", Directives: gti.Directives{}, Tag: "min:\"1\" def:\"3\""}}, + {"RTau", >i.Field{Name: "RTau", Type: "float32", LocalType: "float32", Doc: "time constant for decaying Vm down to VmR -- at end of Tr it is set to VmR exactly -- this provides a more realistic shape of the post-spiking Vm which is only relevant for more realistic channels that key off of Vm -- does not otherwise affect standard computation", Directives: gti.Directives{}, Tag: "def:\"1.6667\""}}, + {"Exp", >i.Field{Name: "Exp", Type: "goki.dev/gosl/v2/slbool.Bool", LocalType: "slbool.Bool", Doc: "if true, turn on exponential excitatory current that drives Vm rapidly upward for spiking as it gets past its nominal firing threshold (Thr) -- nicely captures the Hodgkin Huxley dynamics of Na and K channels -- uses Brette & Gurstner 2005 AdEx formulation", Directives: gti.Directives{}, Tag: "def:\"true\""}}, + {"ExpSlope", >i.Field{Name: "ExpSlope", Type: "float32", LocalType: "float32", Doc: "slope in Vm (2 mV = .02 in normalized units) for extra exponential excitatory current that drives Vm rapidly upward for spiking as it gets past its nominal firing threshold (Thr) -- nicely captures the Hodgkin Huxley dynamics of Na and K channels -- uses Brette & Gurstner 2005 AdEx formulation", Directives: gti.Directives{}, Tag: "viewif:\"Exp\" def:\"0.02\""}}, + {"ExpThr", >i.Field{Name: "ExpThr", Type: "float32", LocalType: "float32", Doc: "membrane potential threshold for actually triggering a spike when using the exponential mechanism", Directives: gti.Directives{}, Tag: "viewif:\"Exp\" def:\"0.9\""}}, + {"MaxHz", >i.Field{Name: "MaxHz", Type: "float32", LocalType: "float32", Doc: "for translating spiking interval (rate) into rate-code activation equivalent, what is the maximum firing rate associated with a maximum activation value of 1", Directives: gti.Directives{}, Tag: "def:\"180\" min:\"1\""}}, + {"ISITau", >i.Field{Name: "ISITau", Type: "float32", LocalType: "float32", Doc: "constant for integrating the spiking interval in estimating spiking rate", Directives: gti.Directives{}, Tag: "def:\"5\" min:\"1\""}}, + {"ISIDt", >i.Field{Name: "ISIDt", Type: "float32", LocalType: "float32", Doc: "rate = 1 / tau", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + {"RDt", >i.Field{Name: "RDt", Type: "float32", LocalType: "float32", Doc: "rate = 1 / tau", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + {"pad", >i.Field{Name: "pad", Type: "int32", LocalType: "int32", Doc: "", Directives: gti.Directives{}, Tag: ""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.DendParams", + ShortName: "axon.DendParams", + IDName: "dend-params", + Doc: "DendParams are the parameters for updating dendrite-specific dynamics", + Directives: gti.Directives{}, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"GbarExp", >i.Field{Name: "GbarExp", Type: "float32", LocalType: "float32", Doc: "dendrite-specific strength multiplier of the exponential spiking drive on Vm -- e.g., .5 makes it half as strong as at the soma (which uses Gbar.L as a strength multiplier per the AdEx standard model)", Directives: gti.Directives{}, Tag: "def:\"0.2,0.5\""}}, + {"GbarR", >i.Field{Name: "GbarR", Type: "float32", LocalType: "float32", Doc: "dendrite-specific conductance of Kdr delayed rectifier currents, used to reset membrane potential for dendrite -- applied for Tr msec", Directives: gti.Directives{}, Tag: "def:\"3,6\""}}, + {"SSGi", >i.Field{Name: "SSGi", Type: "float32", LocalType: "float32", Doc: "SST+ somatostatin positive slow spiking inhibition level specifically affecting dendritic Vm (VmDend) -- this is important for countering a positive feedback loop from NMDA getting stronger over the course of learning -- also typically requires SubMean = 1 for TrgAvgAct and learning to fully counter this feedback loop.", Directives: gti.Directives{}, Tag: "def:\"0,2\""}}, + {"HasMod", >i.Field{Name: "HasMod", Type: "goki.dev/gosl/v2/slbool.Bool", LocalType: "slbool.Bool", Doc: "set automatically based on whether this layer has any recv projections that have a GType conductance type of Modulatory -- if so, then multiply GeSyn etc by GModSyn", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + {"ModGain", >i.Field{Name: "ModGain", Type: "float32", LocalType: "float32", Doc: "multiplicative gain factor on the total modulatory input -- this can also be controlled by the PrjnScale.Abs factor on ModulatoryG inputs, but it is convenient to be able to control on the layer as well.", Directives: gti.Directives{}, Tag: ""}}, + {"ModBase", >i.Field{Name: "ModBase", Type: "float32", LocalType: "float32", Doc: "baseline modulatory level for modulatory effects -- net modulation is ModBase + ModGain * GModSyn", Directives: gti.Directives{}, Tag: ""}}, + {"pad", >i.Field{Name: "pad", Type: "int32", LocalType: "int32", Doc: "", Directives: gti.Directives{}, Tag: ""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.ActInitParams", + ShortName: "axon.ActInitParams", + IDName: "act-init-params", + Doc: "ActInitParams are initial values for key network state variables.\nInitialized in InitActs called by InitWts, and provides target values for DecayState.", + Directives: gti.Directives{}, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"Vm", >i.Field{Name: "Vm", Type: "float32", LocalType: "float32", Doc: "initial membrane potential -- see Erev.L for the resting potential (typically .3)", Directives: gti.Directives{}, Tag: "def:\"0.3\""}}, + {"Act", >i.Field{Name: "Act", Type: "float32", LocalType: "float32", Doc: "initial activation value -- typically 0", Directives: gti.Directives{}, Tag: "def:\"0\""}}, + {"GeBase", >i.Field{Name: "GeBase", Type: "float32", LocalType: "float32", Doc: "baseline level of excitatory conductance (net input) -- Ge is initialized to this value, and it is added in as a constant background level of excitatory input -- captures all the other inputs not represented in the model, and intrinsic excitability, etc", Directives: gti.Directives{}, Tag: "def:\"0\""}}, + {"GiBase", >i.Field{Name: "GiBase", Type: "float32", LocalType: "float32", Doc: "baseline level of inhibitory conductance (net input) -- Gi is initialized to this value, and it is added in as a constant background level of inhibitory input -- captures all the other inputs not represented in the model", Directives: gti.Directives{}, Tag: "def:\"0\""}}, + {"GeVar", >i.Field{Name: "GeVar", Type: "float32", LocalType: "float32", Doc: "variance (sigma) of gaussian distribution around baseline Ge values, per unit, to establish variability in intrinsic excitability. value never goes < 0", Directives: gti.Directives{}, Tag: "def:\"0\""}}, + {"GiVar", >i.Field{Name: "GiVar", Type: "float32", LocalType: "float32", Doc: "variance (sigma) of gaussian distribution around baseline Gi values, per unit, to establish variability in intrinsic excitability. value never goes < 0", Directives: gti.Directives{}, Tag: "def:\"0\""}}, + {"pad", >i.Field{Name: "pad", Type: "int32", LocalType: "int32", Doc: "", Directives: gti.Directives{}, Tag: ""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.DecayParams", + ShortName: "axon.DecayParams", + IDName: "decay-params", + Doc: "DecayParams control the decay of activation state in the DecayState function\ncalled in NewState when a new state is to be processed.", + Directives: gti.Directives{ + >i.Directive{Tool: "gosl", Directive: "start", Args: []string{"act"}}, + }, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"Act", >i.Field{Name: "Act", Type: "float32", LocalType: "float32", Doc: "proportion to decay most activation state variables toward initial values at start of every ThetaCycle (except those controlled separately below) -- if 1 it is effectively equivalent to full clear, resetting other derived values. ISI is reset every AlphaCycle to get a fresh sample of activations (doesn't affect direct computation -- only readout).", Directives: gti.Directives{}, Tag: "def:\"0,0.2,0.5,1\" max:\"1\" min:\"0\""}}, + {"Glong", >i.Field{Name: "Glong", Type: "float32", LocalType: "float32", Doc: "proportion to decay long-lasting conductances, NMDA and GABA, and also the dendritic membrane potential -- when using random stimulus order, it is important to decay this significantly to allow a fresh start -- but set Act to 0 to enable ongoing activity to keep neurons in their sensitive regime.", Directives: gti.Directives{}, Tag: "def:\"0,0.6\" max:\"1\" min:\"0\""}}, + {"AHP", >i.Field{Name: "AHP", Type: "float32", LocalType: "float32", Doc: "decay of afterhyperpolarization currents, including mAHP, sAHP, and KNa -- has a separate decay because often useful to have this not decay at all even if decay is on.", Directives: gti.Directives{}, Tag: "def:\"0\" max:\"1\" min:\"0\""}}, + {"LearnCa", >i.Field{Name: "LearnCa", Type: "float32", LocalType: "float32", Doc: "decay of Ca variables driven by spiking activity used in learning: CaSpk* and Ca* variables. These are typically not decayed but may need to be in some situations.", Directives: gti.Directives{}, Tag: "def:\"0\" max:\"1\" min:\"0\""}}, + {"OnRew", >i.Field{Name: "OnRew", Type: "goki.dev/gosl/v2/slbool.Bool", LocalType: "slbool.Bool", Doc: "decay layer at end of ThetaCycle when there is a global reward -- true by default for PTPred, PTMaint and PFC Super layers", Directives: gti.Directives{}, Tag: ""}}, + {"pad", >i.Field{Name: "pad", Type: "float32", LocalType: "float32", Doc: "", Directives: gti.Directives{}, Tag: ""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.DtParams", + ShortName: "axon.DtParams", + IDName: "dt-params", + Doc: "DtParams are time and rate constants for temporal derivatives in Axon (Vm, G)", + Directives: gti.Directives{}, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"Integ", >i.Field{Name: "Integ", Type: "float32", LocalType: "float32", Doc: "overall rate constant for numerical integration, for all equations at the unit level -- all time constants are specified in millisecond units, with one cycle = 1 msec -- if you instead want to make one cycle = 2 msec, you can do this globally by setting this integ value to 2 (etc). However, stability issues will likely arise if you go too high. For improved numerical stability, you may even need to reduce this value to 0.5 or possibly even lower (typically however this is not necessary). MUST also coordinate this with network.time_inc variable to ensure that global network.time reflects simulated time accurately", Directives: gti.Directives{}, Tag: "def:\"1,0.5\" min:\"0\""}}, + {"VmTau", >i.Field{Name: "VmTau", Type: "float32", LocalType: "float32", Doc: "membrane potential time constant in cycles, which should be milliseconds typically (tau is roughly how long it takes for value to change significantly -- 1.4x the half-life) -- reflects the capacitance of the neuron in principle -- biological default for AdEx spiking model C = 281 pF = 2.81 normalized", Directives: gti.Directives{}, Tag: "def:\"2.81\" min:\"1\""}}, + {"VmDendTau", >i.Field{Name: "VmDendTau", Type: "float32", LocalType: "float32", Doc: "dendritic membrane potential time constant in cycles, which should be milliseconds typically (tau is roughly how long it takes for value to change significantly -- 1.4x the half-life) -- reflects the capacitance of the neuron in principle -- biological default for AdEx spiking model C = 281 pF = 2.81 normalized", Directives: gti.Directives{}, Tag: "def:\"5\" min:\"1\""}}, + {"VmSteps", >i.Field{Name: "VmSteps", Type: "int32", LocalType: "int32", Doc: "number of integration steps to take in computing new Vm value -- this is the one computation that can be most numerically unstable so taking multiple steps with proportionally smaller dt is beneficial", Directives: gti.Directives{}, Tag: "def:\"2\" min:\"1\""}}, + {"GeTau", >i.Field{Name: "GeTau", Type: "float32", LocalType: "float32", Doc: "time constant for decay of excitatory AMPA receptor conductance.", Directives: gti.Directives{}, Tag: "def:\"5\" min:\"1\""}}, + {"GiTau", >i.Field{Name: "GiTau", Type: "float32", LocalType: "float32", Doc: "time constant for decay of inhibitory GABAa receptor conductance.", Directives: gti.Directives{}, Tag: "def:\"7\" min:\"1\""}}, + {"IntTau", >i.Field{Name: "IntTau", Type: "float32", LocalType: "float32", Doc: "time constant for integrating values over timescale of an individual input state (e.g., roughly 200 msec -- theta cycle), used in computing ActInt, GeInt from Ge, and GiInt from GiSyn -- this is used for scoring performance, not for learning, in cycles, which should be milliseconds typically (tau is roughly how long it takes for value to change significantly -- 1.4x the half-life),", Directives: gti.Directives{}, Tag: "def:\"40\" min:\"1\""}}, + {"LongAvgTau", >i.Field{Name: "LongAvgTau", Type: "float32", LocalType: "float32", Doc: "time constant for integrating slower long-time-scale averages, such as nrn.ActAvg, Pool.ActsMAvg, ActsPAvg -- computed in NewState when a new input state is present (i.e., not msec but in units of a theta cycle) (tau is roughly how long it takes for value to change significantly) -- set lower for smaller models", Directives: gti.Directives{}, Tag: "def:\"20\" min:\"1\""}}, + {"MaxCycStart", >i.Field{Name: "MaxCycStart", Type: "int32", LocalType: "int32", Doc: "cycle to start updating the SpkMaxCa, SpkMax values within a theta cycle -- early cycles often reflect prior state", Directives: gti.Directives{}, Tag: "def:\"10\" min:\"0\""}}, + {"VmDt", >i.Field{Name: "VmDt", Type: "float32", LocalType: "float32", Doc: "nominal rate = Integ / tau", Directives: gti.Directives{}, Tag: "view:\"-\" json:\"-\" xml:\"-\""}}, + {"VmDendDt", >i.Field{Name: "VmDendDt", Type: "float32", LocalType: "float32", Doc: "nominal rate = Integ / tau", Directives: gti.Directives{}, Tag: "view:\"-\" json:\"-\" xml:\"-\""}}, + {"DtStep", >i.Field{Name: "DtStep", Type: "float32", LocalType: "float32", Doc: "1 / VmSteps", Directives: gti.Directives{}, Tag: "view:\"-\" json:\"-\" xml:\"-\""}}, + {"GeDt", >i.Field{Name: "GeDt", Type: "float32", LocalType: "float32", Doc: "rate = Integ / tau", Directives: gti.Directives{}, Tag: "view:\"-\" json:\"-\" xml:\"-\""}}, + {"GiDt", >i.Field{Name: "GiDt", Type: "float32", LocalType: "float32", Doc: "rate = Integ / tau", Directives: gti.Directives{}, Tag: "view:\"-\" json:\"-\" xml:\"-\""}}, + {"IntDt", >i.Field{Name: "IntDt", Type: "float32", LocalType: "float32", Doc: "rate = Integ / tau", Directives: gti.Directives{}, Tag: "view:\"-\" json:\"-\" xml:\"-\""}}, + {"LongAvgDt", >i.Field{Name: "LongAvgDt", Type: "float32", LocalType: "float32", Doc: "rate = 1 / tau", Directives: gti.Directives{}, Tag: "view:\"-\" json:\"-\" xml:\"-\""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.SpikeNoiseParams", + ShortName: "axon.SpikeNoiseParams", + IDName: "spike-noise-params", + Doc: "SpikeNoiseParams parameterizes background spiking activity impinging on the neuron,\nsimulated using a poisson spiking process.", + Directives: gti.Directives{}, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"On", >i.Field{Name: "On", Type: "goki.dev/gosl/v2/slbool.Bool", LocalType: "slbool.Bool", Doc: "add noise simulating background spiking levels", Directives: gti.Directives{}, Tag: ""}}, + {"GeHz", >i.Field{Name: "GeHz", Type: "float32", LocalType: "float32", Doc: "mean frequency of excitatory spikes -- typically 50Hz but multiple inputs increase rate -- poisson lambda parameter, also the variance", Directives: gti.Directives{}, Tag: "viewif:\"On\" def:\"100\""}}, + {"Ge", >i.Field{Name: "Ge", Type: "float32", LocalType: "float32", Doc: "excitatory conductance per spike -- .001 has minimal impact, .01 can be strong, and .15 is needed to influence timing of clamped inputs", Directives: gti.Directives{}, Tag: "viewif:\"On\" min:\"0\""}}, + {"GiHz", >i.Field{Name: "GiHz", Type: "float32", LocalType: "float32", Doc: "mean frequency of inhibitory spikes -- typically 100Hz fast spiking but multiple inputs increase rate -- poisson lambda parameter, also the variance", Directives: gti.Directives{}, Tag: "viewif:\"On\" def:\"200\""}}, + {"Gi", >i.Field{Name: "Gi", Type: "float32", LocalType: "float32", Doc: "excitatory conductance per spike -- .001 has minimal impact, .01 can be strong, and .15 is needed to influence timing of clamped inputs", Directives: gti.Directives{}, Tag: "viewif:\"On\" min:\"0\""}}, + {"GeExpInt", >i.Field{Name: "GeExpInt", Type: "float32", LocalType: "float32", Doc: "Exp(-Interval) which is the threshold for GeNoiseP as it is updated", Directives: gti.Directives{}, Tag: "view:\"-\" json:\"-\" xml:\"-\""}}, + {"GiExpInt", >i.Field{Name: "GiExpInt", Type: "float32", LocalType: "float32", Doc: "Exp(-Interval) which is the threshold for GiNoiseP as it is updated", Directives: gti.Directives{}, Tag: "view:\"-\" json:\"-\" xml:\"-\""}}, + {"pad", >i.Field{Name: "pad", Type: "int32", LocalType: "int32", Doc: "", Directives: gti.Directives{}, Tag: ""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.ClampParams", + ShortName: "axon.ClampParams", + IDName: "clamp-params", + Doc: "ClampParams specify how external inputs drive excitatory conductances\n(like a current clamp) -- either adds or overwrites existing conductances.\nNoise is added in either case.", + Directives: gti.Directives{}, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"IsInput", >i.Field{Name: "IsInput", Type: "goki.dev/gosl/v2/slbool.Bool", LocalType: "slbool.Bool", Doc: "is this a clamped input layer? set automatically based on layer type at initialization", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + {"IsTarget", >i.Field{Name: "IsTarget", Type: "goki.dev/gosl/v2/slbool.Bool", LocalType: "slbool.Bool", Doc: "is this a target layer? set automatically based on layer type at initialization", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + {"Ge", >i.Field{Name: "Ge", Type: "float32", LocalType: "float32", Doc: "amount of Ge driven for clamping -- generally use 0.8 for Target layers, 1.5 for Input layers", Directives: gti.Directives{}, Tag: "def:\"0.8,1.5\""}}, + {"Add", >i.Field{Name: "Add", Type: "goki.dev/gosl/v2/slbool.Bool", LocalType: "slbool.Bool", Doc: "", Directives: gti.Directives{}, Tag: "def:\"false\" view:\"add external conductance on top of any existing -- generally this is not a good idea for target layers (creates a main effect that learning can never match), but may be ok for input layers\""}}, + {"ErrThr", >i.Field{Name: "ErrThr", Type: "float32", LocalType: "float32", Doc: "threshold on neuron Act activity to count as active for computing error relative to target in PctErr method", Directives: gti.Directives{}, Tag: "def:\"0.5\""}}, + {"pad", >i.Field{Name: "pad", Type: "float32", LocalType: "float32", Doc: "", Directives: gti.Directives{}, Tag: ""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.AttnParams", + ShortName: "axon.AttnParams", + IDName: "attn-params", + Doc: "AttnParams determine how the Attn modulates Ge", + Directives: gti.Directives{}, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"On", >i.Field{Name: "On", Type: "goki.dev/gosl/v2/slbool.Bool", LocalType: "slbool.Bool", Doc: "is attentional modulation active?", Directives: gti.Directives{}, Tag: ""}}, + {"Min", >i.Field{Name: "Min", Type: "float32", LocalType: "float32", Doc: "minimum act multiplier if attention is 0", Directives: gti.Directives{}, Tag: "viewif:\"On\""}}, + {"RTThr", >i.Field{Name: "RTThr", Type: "float32", LocalType: "float32", Doc: "threshold on CaSpkP for determining the reaction time for the Layer -- starts after MaxCycStart to ensure that prior trial activity has had a chance to dissipate.", Directives: gti.Directives{}, Tag: ""}}, + {"pad", >i.Field{Name: "pad", Type: "int32", LocalType: "int32", Doc: "", Directives: gti.Directives{}, Tag: ""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.PopCodeParams", + ShortName: "axon.PopCodeParams", + IDName: "pop-code-params", + Doc: "PopCodeParams provides an encoding of scalar value using population code,\nwhere a single continuous (scalar) value is encoded as a gaussian bump\nacross a population of neurons (1 dimensional).\nIt can also modulate rate code and number of neurons active according to the value.\nThis is for layers that represent values as in the PVLV system (from Context.PVLV).\nBoth normalized activation values (1 max) and Ge conductance values can be generated.", + Directives: gti.Directives{}, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"On", >i.Field{Name: "On", Type: "goki.dev/gosl/v2/slbool.Bool", LocalType: "slbool.Bool", Doc: "use popcode encoding of variable(s) that this layer represents", Directives: gti.Directives{}, Tag: ""}}, + {"Ge", >i.Field{Name: "Ge", Type: "float32", LocalType: "float32", Doc: "Ge multiplier for driving excitatory conductance based on PopCode -- multiplies normalized activation values", Directives: gti.Directives{}, Tag: "viewif:\"On\" def:\"0.1\""}}, + {"Min", >i.Field{Name: "Min", Type: "float32", LocalType: "float32", Doc: "minimum value representable -- for GaussBump, typically include extra to allow mean with activity on either side to represent the lowest value you want to encode", Directives: gti.Directives{}, Tag: "viewif:\"On\" def:\"-0.1\""}}, + {"Max", >i.Field{Name: "Max", Type: "float32", LocalType: "float32", Doc: "maximum value representable -- for GaussBump, typically include extra to allow mean with activity on either side to represent the lowest value you want to encode", Directives: gti.Directives{}, Tag: "viewif:\"On\" def:\"1.1\""}}, + {"MinAct", >i.Field{Name: "MinAct", Type: "float32", LocalType: "float32", Doc: "activation multiplier for values at Min end of range, where values at Max end have an activation of 1 -- if this is < 1, then there is a rate code proportional to the value in addition to the popcode pattern -- see also MinSigma, MaxSigma", Directives: gti.Directives{}, Tag: "viewif:\"On\" def:\"1,0.5\""}}, + {"MinSigma", >i.Field{Name: "MinSigma", Type: "float32", LocalType: "float32", Doc: "sigma parameter of a gaussian specifying the tuning width of the coarse-coded units, in normalized 0-1 range -- for Min value -- if MinSigma < MaxSigma then more units are activated for Max values vs. Min values, proportionally", Directives: gti.Directives{}, Tag: "viewif:\"On\" def:\"0.1,0.08\""}}, + {"MaxSigma", >i.Field{Name: "MaxSigma", Type: "float32", LocalType: "float32", Doc: "sigma parameter of a gaussian specifying the tuning width of the coarse-coded units, in normalized 0-1 range -- for Min value -- if MinSigma < MaxSigma then more units are activated for Max values vs. Min values, proportionally", Directives: gti.Directives{}, Tag: "viewif:\"On\" def:\"0.1,0.12\""}}, + {"Clip", >i.Field{Name: "Clip", Type: "goki.dev/gosl/v2/slbool.Bool", LocalType: "slbool.Bool", Doc: "ensure that encoded and decoded value remains within specified range", Directives: gti.Directives{}, Tag: "viewif:\"On\""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.ActParams", + ShortName: "axon.ActParams", + IDName: "act-params", + Doc: "axon.ActParams contains all the activation computation params and functions\nfor basic Axon, at the neuron level .\nThis is included in axon.Layer to drive the computation.", + Directives: gti.Directives{}, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"Spikes", >i.Field{Name: "Spikes", Type: "github.com/emer/axon/axon.SpikeParams", LocalType: "SpikeParams", Doc: "Spiking function parameters", Directives: gti.Directives{}, Tag: "view:\"inline\""}}, + {"Dend", >i.Field{Name: "Dend", Type: "github.com/emer/axon/axon.DendParams", LocalType: "DendParams", Doc: "dendrite-specific parameters", Directives: gti.Directives{}, Tag: "view:\"inline\""}}, + {"Init", >i.Field{Name: "Init", Type: "github.com/emer/axon/axon.ActInitParams", LocalType: "ActInitParams", Doc: "initial values for key network state variables -- initialized in InitActs called by InitWts, and provides target values for DecayState", Directives: gti.Directives{}, Tag: "view:\"inline\""}}, + {"Decay", >i.Field{Name: "Decay", Type: "github.com/emer/axon/axon.DecayParams", LocalType: "DecayParams", Doc: "amount to decay between AlphaCycles, simulating passage of time and effects of saccades etc, especially important for environments with random temporal structure (e.g., most standard neural net training corpora)", Directives: gti.Directives{}, Tag: "view:\"inline\""}}, + {"Dt", >i.Field{Name: "Dt", Type: "github.com/emer/axon/axon.DtParams", LocalType: "DtParams", Doc: "time and rate constants for temporal derivatives / updating of activation state", Directives: gti.Directives{}, Tag: "view:\"inline\""}}, + {"Gbar", >i.Field{Name: "Gbar", Type: "github.com/emer/axon/chans.Chans", LocalType: "chans.Chans", Doc: "maximal conductances levels for channels", Directives: gti.Directives{}, Tag: "view:\"inline\""}}, + {"Erev", >i.Field{Name: "Erev", Type: "github.com/emer/axon/chans.Chans", LocalType: "chans.Chans", Doc: "reversal potentials for each channel", Directives: gti.Directives{}, Tag: "view:\"inline\""}}, + {"Clamp", >i.Field{Name: "Clamp", Type: "github.com/emer/axon/axon.ClampParams", LocalType: "ClampParams", Doc: "how external inputs drive neural activations", Directives: gti.Directives{}, Tag: "view:\"inline\""}}, + {"Noise", >i.Field{Name: "Noise", Type: "github.com/emer/axon/axon.SpikeNoiseParams", LocalType: "SpikeNoiseParams", Doc: "how, where, when, and how much noise to add", Directives: gti.Directives{}, Tag: "view:\"inline\""}}, + {"VmRange", >i.Field{Name: "VmRange", Type: "goki.dev/etable/v2/minmax.F32", LocalType: "minmax.F32", Doc: "range for Vm membrane potential -- -- important to keep just at extreme range of reversal potentials to prevent numerical instability", Directives: gti.Directives{}, Tag: "view:\"inline\""}}, + {"Mahp", >i.Field{Name: "Mahp", Type: "github.com/emer/axon/chans.MahpParams", LocalType: "chans.MahpParams", Doc: "M-type medium time-scale afterhyperpolarization mAHP current -- this is the primary form of adaptation on the time scale of multiple sequences of spikes", Directives: gti.Directives{}, Tag: "view:\"inline\""}}, + {"Sahp", >i.Field{Name: "Sahp", Type: "github.com/emer/axon/chans.SahpParams", LocalType: "chans.SahpParams", Doc: "slow time-scale afterhyperpolarization sAHP current -- integrates CaSpkD at theta cycle intervals and produces a hard cutoff on sustained activity for any neuron", Directives: gti.Directives{}, Tag: "view:\"inline\""}}, + {"KNa", >i.Field{Name: "KNa", Type: "github.com/emer/axon/chans.KNaMedSlow", LocalType: "chans.KNaMedSlow", Doc: "sodium-gated potassium channel adaptation parameters -- activates a leak-like current as a function of neural activity (firing = Na influx) at two different time-scales (Slick = medium, Slack = slow)", Directives: gti.Directives{}, Tag: "view:\"inline\""}}, + {"NMDA", >i.Field{Name: "NMDA", Type: "github.com/emer/axon/chans.NMDAParams", LocalType: "chans.NMDAParams", Doc: "NMDA channel parameters used in computing Gnmda conductance for bistability, and postsynaptic calcium flux used in learning. Note that Learn.Snmda has distinct parameters used in computing sending NMDA parameters used in learning.", Directives: gti.Directives{}, Tag: "view:\"inline\""}}, + {"MaintNMDA", >i.Field{Name: "MaintNMDA", Type: "github.com/emer/axon/chans.NMDAParams", LocalType: "chans.NMDAParams", Doc: "NMDA channel parameters used in computing Gnmda conductance for bistability, and postsynaptic calcium flux used in learning. Note that Learn.Snmda has distinct parameters used in computing sending NMDA parameters used in learning.", Directives: gti.Directives{}, Tag: "view:\"inline\""}}, + {"GabaB", >i.Field{Name: "GabaB", Type: "github.com/emer/axon/chans.GABABParams", LocalType: "chans.GABABParams", Doc: "GABA-B / GIRK channel parameters", Directives: gti.Directives{}, Tag: "view:\"inline\""}}, + {"VGCC", >i.Field{Name: "VGCC", Type: "github.com/emer/axon/chans.VGCCParams", LocalType: "chans.VGCCParams", Doc: "voltage gated calcium channels -- provide a key additional source of Ca for learning and positive-feedback loop upstate for active neurons", Directives: gti.Directives{}, Tag: "view:\"inline\""}}, + {"AK", >i.Field{Name: "AK", Type: "github.com/emer/axon/chans.AKsParams", LocalType: "chans.AKsParams", Doc: "A-type potassium (K) channel that is particularly important for limiting the runaway excitation from VGCC channels", Directives: gti.Directives{}, Tag: "view:\"inline\""}}, + {"SKCa", >i.Field{Name: "SKCa", Type: "github.com/emer/axon/chans.SKCaParams", LocalType: "chans.SKCaParams", Doc: "small-conductance calcium-activated potassium channel produces the pausing function as a consequence of rapid bursting.", Directives: gti.Directives{}, Tag: "view:\"inline\""}}, + {"AttnMod", >i.Field{Name: "AttnMod", Type: "github.com/emer/axon/axon.AttnParams", LocalType: "AttnParams", Doc: "Attentional modulation parameters: how Attn modulates Ge", Directives: gti.Directives{}, Tag: "view:\"inline\""}}, + {"PopCode", >i.Field{Name: "PopCode", Type: "github.com/emer/axon/axon.PopCodeParams", LocalType: "PopCodeParams", Doc: "provides encoding population codes, used to represent a single continuous (scalar) value, across a population of units / neurons (1 dimensional)", Directives: gti.Directives{}, Tag: "view:\"inline\""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.PrjnGTypes", + ShortName: "axon.PrjnGTypes", + IDName: "prjn-g-types", + Doc: "PrjnGTypes represents the conductance (G) effects of a given projection,\nincluding excitatory, inhibitory, and modulatory.", + Directives: gti.Directives{ + >i.Directive{Tool: "gosl", Directive: "start", Args: []string{"act_prjn"}}, + >i.Directive{Tool: "enums", Directive: "enum", Args: []string{}}, + }, + + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.SynComParams", + ShortName: "axon.SynComParams", + IDName: "syn-com-params", + Doc: "SynComParams are synaptic communication parameters:\nused in the Prjn parameters. Includes delay and\nprobability of failure, and Inhib for inhibitory connections,\nand modulatory projections that have multiplicative-like effects.", + Directives: gti.Directives{}, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"GType", >i.Field{Name: "GType", Type: "github.com/emer/axon/axon.PrjnGTypes", LocalType: "PrjnGTypes", Doc: "type of conductance (G) communicated by this projection", Directives: gti.Directives{}, Tag: ""}}, + {"Delay", >i.Field{Name: "Delay", Type: "uint32", LocalType: "uint32", Doc: "additional synaptic delay in msec for inputs arriving at this projection. Must be <= MaxDelay which is set during network building based on MaxDelay of any existing Prjn in the network. Delay = 0 means a spike reaches receivers in the next Cycle, which is the minimum time (1 msec). Biologically, subtract 1 from biological synaptic delay values to set corresponding Delay value.", Directives: gti.Directives{}, Tag: "min:\"0\" def:\"2\""}}, + {"MaxDelay", >i.Field{Name: "MaxDelay", Type: "uint32", LocalType: "uint32", Doc: "maximum value of Delay -- based on MaxDelay values when the BuildGBuf function was called when the network was built -- cannot set it longer than this, except by calling BuildGBuf on network after changing MaxDelay to a larger value in any projection in the network.", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + {"PFail", >i.Field{Name: "PFail", Type: "float32", LocalType: "float32", Doc: "probability of synaptic transmission failure -- if > 0, then weights are turned off at random as a function of PFail (times 1-SWt if PFailSwt)", Directives: gti.Directives{}, Tag: ""}}, + {"PFailSWt", >i.Field{Name: "PFailSWt", Type: "goki.dev/gosl/v2/slbool.Bool", LocalType: "slbool.Bool", Doc: "if true, then probability of failure is inversely proportional to SWt structural / slow weight value (i.e., multiply PFail * (1-SWt)))", Directives: gti.Directives{}, Tag: ""}}, + {"DelLen", >i.Field{Name: "DelLen", Type: "uint32", LocalType: "uint32", Doc: "delay length = actual length of the GBuf buffer per neuron = Delay+1 -- just for speed", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + {"pad", >i.Field{Name: "pad", Type: "float32", LocalType: "float32", Doc: "", Directives: gti.Directives{}, Tag: ""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.PrjnScaleParams", + ShortName: "axon.PrjnScaleParams", + IDName: "prjn-scale-params", + Doc: "PrjnScaleParams are projection scaling parameters: modulates overall strength of projection,\nusing both absolute and relative factors.", + Directives: gti.Directives{ + >i.Directive{Tool: "gosl", Directive: "start", Args: []string{"act_prjn"}}, + }, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"Rel", >i.Field{Name: "Rel", Type: "float32", LocalType: "float32", Doc: "relative scaling that shifts balance between different projections -- this is subject to normalization across all other projections into receiving neuron, and determines the GScale.Target for adapting scaling", Directives: gti.Directives{}, Tag: "min:\"0\""}}, + {"Abs", >i.Field{Name: "Abs", Type: "float32", LocalType: "float32", Doc: "absolute multiplier adjustment factor for the prjn scaling -- can be used to adjust for idiosyncrasies not accommodated by the standard scaling based on initial target activation level and relative scaling factors -- any adaptation operates by directly adjusting scaling factor from the initially computed value", Directives: gti.Directives{}, Tag: "def:\"1\" min:\"0\""}}, + {"pad", >i.Field{Name: "pad", Type: "float32", LocalType: "float32", Doc: "", Directives: gti.Directives{}, Tag: ""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.AvgMaxI32", + ShortName: "axon.AvgMaxI32", + IDName: "avg-max-i-32", + Doc: "AvgMaxI32 holds average and max statistics for float32,\nand values used for computing them incrementally,\nusing a fixed precision int32 based float representation\nthat can be used with GPU-based atomic add and max functions.\nThis ONLY works for positive values with averages around 1, and\nthe N must be set IN ADVANCE to the correct number of items.\nOnce Calc() is called, the incremental values are reset\nvia Init() so it is always ready for updating without a separate\nInit() pass.", + Directives: gti.Directives{ + >i.Directive{Tool: "gosl", Directive: "start", Args: []string{"avgmaxi"}}, + }, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"Avg", >i.Field{Name: "Avg", Type: "float32", LocalType: "float32", Doc: "Average, from Calc when last computed as Sum / N", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + {"Max", >i.Field{Name: "Max", Type: "float32", LocalType: "float32", Doc: "Maximum value, copied from CurMax in Calc", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + {"Sum", >i.Field{Name: "Sum", Type: "int32", LocalType: "int32", Doc: "sum for computing average -- incremented in UpdateVal, reset in Calc", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + {"CurMax", >i.Field{Name: "CurMax", Type: "int32", LocalType: "int32", Doc: "current maximum value, updated via UpdateVal, reset in Calc", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + {"N", >i.Field{Name: "N", Type: "int32", LocalType: "int32", Doc: "number of items in the sum -- this must be set in advance to a known value and it is used in computing the float <-> int conversion factor to maximize precision.", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + {"pad", >i.Field{Name: "pad", Type: "int32", LocalType: "int32", Doc: "", Directives: gti.Directives{}, Tag: ""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.AxonNetwork", + ShortName: "axon.AxonNetwork", + IDName: "axon-network", + Doc: "AxonNetwork defines the essential algorithmic API for Axon, at the network level.\nThese are the methods that the user calls in their Sim code:\n* NewState\n* Cycle\n* NewPhase\n* DWt\n* WtFmDwt\nBecause we don't want to have to force the user to use the interface cast in calling\nthese methods, we provide Impl versions here that are the implementations\nwhich the user-facing method calls through the interface cast.\nSpecialized algorithms should thus only change the Impl version, which is what\nis exposed here in this interface.\n\nThere is now a strong constraint that all Cycle level computation takes place\nin one pass at the Layer level, which greatly improves threading efficiency.\n\nAll of the structural API is in emer.Network, which this interface also inherits for\nconvenience.", + Directives: gti.Directives{}, + + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.AxonLayer", + ShortName: "axon.AxonLayer", + IDName: "axon-layer", + Doc: "AxonLayer defines the essential algorithmic API for Axon, at the layer level.\nThese are the methods that the axon.Network calls on its layers at each step\nof processing. Other Layer types can selectively re-implement (override) these methods\nto modify the computation, while inheriting the basic behavior for non-overridden methods.\n\nAll of the structural API is in emer.Layer, which this interface also inherits for\nconvenience.", + Directives: gti.Directives{}, + + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.AxonPrjn", + ShortName: "axon.AxonPrjn", + IDName: "axon-prjn", + Doc: "AxonPrjn defines the essential algorithmic API for Axon, at the projection level.\nThese are the methods that the axon.Layer calls on its prjns at each step\nof processing. Other Prjn types can selectively re-implement (override) these methods\nto modify the computation, while inheriting the basic behavior for non-overridden methods.\n\nAll of the structural API is in emer.Prjn, which this interface also inherits for\nconvenience.", + Directives: gti.Directives{}, + + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.AxonPrjns", + ShortName: "axon.AxonPrjns", + IDName: "axon-prjns", + Doc: "", + Directives: gti.Directives{}, + + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.NetIdxs", + ShortName: "axon.NetIdxs", + IDName: "net-idxs", + Doc: "NetIdxs are indexes and sizes for processing network", + Directives: gti.Directives{ + >i.Directive{Tool: "gosl", Directive: "end", Args: []string{"context"}}, + >i.Directive{Tool: "gosl", Directive: "hlsl", Args: []string{"context"}}, + >i.Directive{Tool: "gosl", Directive: "end", Args: []string{"context"}}, + >i.Directive{Tool: "gosl", Directive: "start", Args: []string{"context"}}, + }, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"NData", >i.Field{Name: "NData", Type: "uint32", LocalType: "uint32", Doc: "number of data parallel items to process currently", Directives: gti.Directives{}, Tag: "min:\"1\""}}, + {"NetIdx", >i.Field{Name: "NetIdx", Type: "uint32", LocalType: "uint32", Doc: "network index in global Networks list of networks -- needed for GPU shader kernel compatible network variable access functions (e.g., NrnV, SynV etc) in CPU mode", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + {"MaxData", >i.Field{Name: "MaxData", Type: "uint32", LocalType: "uint32", Doc: "maximum amount of data parallel", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + {"NLayers", >i.Field{Name: "NLayers", Type: "uint32", LocalType: "uint32", Doc: "number of layers in the network", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + {"NNeurons", >i.Field{Name: "NNeurons", Type: "uint32", LocalType: "uint32", Doc: "total number of neurons", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + {"NPools", >i.Field{Name: "NPools", Type: "uint32", LocalType: "uint32", Doc: "total number of pools excluding * MaxData factor", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + {"NSyns", >i.Field{Name: "NSyns", Type: "uint32", LocalType: "uint32", Doc: "total number of synapses", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + {"GPUMaxBuffFloats", >i.Field{Name: "GPUMaxBuffFloats", Type: "uint32", LocalType: "uint32", Doc: "maximum size in float32 (4 bytes) of a GPU buffer -- needed for GPU access", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + {"GPUSynCaBanks", >i.Field{Name: "GPUSynCaBanks", Type: "uint32", LocalType: "uint32", Doc: "total number of SynCa banks of GPUMaxBufferBytes arrays in GPU", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + {"PVLVNPosUSs", >i.Field{Name: "PVLVNPosUSs", Type: "uint32", LocalType: "uint32", Doc: "total number of PVLV Drives / positive USs", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + {"PVLVNNegUSs", >i.Field{Name: "PVLVNNegUSs", Type: "uint32", LocalType: "uint32", Doc: "total number of PVLV Negative USs", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + {"GvUSnegOff", >i.Field{Name: "GvUSnegOff", Type: "uint32", LocalType: "uint32", Doc: "offset into GlobalVars for USneg values", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + {"GvUSnegStride", >i.Field{Name: "GvUSnegStride", Type: "uint32", LocalType: "uint32", Doc: "stride into GlobalVars for USneg values", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + {"GvUSposOff", >i.Field{Name: "GvUSposOff", Type: "uint32", LocalType: "uint32", Doc: "offset into GlobalVars for USpos, Drive, VSPatch values values", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + {"GvUSposStride", >i.Field{Name: "GvUSposStride", Type: "uint32", LocalType: "uint32", Doc: "stride into GlobalVars for USpos, Drive, VSPatch values", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + {"pad", >i.Field{Name: "pad", Type: "uint32", LocalType: "uint32", Doc: "", Directives: gti.Directives{}, Tag: ""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.Context", + ShortName: "axon.Context", + IDName: "context", + Doc: "Context contains all of the global context state info\nthat is shared across every step of the computation.\nIt is passed around to all relevant computational functions,\nand is updated on the CPU and synced to the GPU after every cycle.\nIt is the *only* mechanism for communication from CPU to GPU.\nIt contains timing, Testing vs. Training mode, random number context,\nglobal neuromodulation, etc.", + Directives: gti.Directives{}, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"Mode", >i.Field{Name: "Mode", Type: "github.com/emer/emergent/v2/etime.Modes", LocalType: "etime.Modes", Doc: "current evaluation mode, e.g., Train, Test, etc", Directives: gti.Directives{}, Tag: ""}}, + {"Testing", >i.Field{Name: "Testing", Type: "goki.dev/gosl/v2/slbool.Bool", LocalType: "slbool.Bool", Doc: "if true, the model is being run in a testing mode, so no weight changes or other associated computations are needed. this flag should only affect learning-related behavior. Is automatically updated based on Mode != Train", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + {"Phase", >i.Field{Name: "Phase", Type: "int32", LocalType: "int32", Doc: "phase counter: typicaly 0-1 for minus-plus but can be more phases for other algorithms", Directives: gti.Directives{}, Tag: ""}}, + {"PlusPhase", >i.Field{Name: "PlusPhase", Type: "goki.dev/gosl/v2/slbool.Bool", LocalType: "slbool.Bool", Doc: "true if this is the plus phase, when the outcome / bursting is occurring, driving positive learning -- else minus phase", Directives: gti.Directives{}, Tag: ""}}, + {"PhaseCycle", >i.Field{Name: "PhaseCycle", Type: "int32", LocalType: "int32", Doc: "cycle within current phase -- minus or plus", Directives: gti.Directives{}, Tag: ""}}, + {"Cycle", >i.Field{Name: "Cycle", Type: "int32", LocalType: "int32", Doc: "cycle counter: number of iterations of activation updating (settling) on the current state -- this counts time sequentially until reset with NewState", Directives: gti.Directives{}, Tag: ""}}, + {"ThetaCycles", >i.Field{Name: "ThetaCycles", Type: "int32", LocalType: "int32", Doc: "length of the theta cycle in terms of 1 msec Cycles -- some network update steps depend on doing something at the end of the theta cycle (e.g., CTCtxtPrjn).", Directives: gti.Directives{}, Tag: "def:\"200\""}}, + {"CyclesTotal", >i.Field{Name: "CyclesTotal", Type: "int32", LocalType: "int32", Doc: "total cycle count -- increments continuously from whenever it was last reset -- typically this is number of milliseconds in simulation time -- is int32 and not uint32 b/c used with Synapse CaUpT which needs to have a -1 case for expired update time", Directives: gti.Directives{}, Tag: ""}}, + {"Time", >i.Field{Name: "Time", Type: "float32", LocalType: "float32", Doc: "accumulated amount of time the network has been running, in simulation-time (not real world time), in seconds", Directives: gti.Directives{}, Tag: ""}}, + {"TrialsTotal", >i.Field{Name: "TrialsTotal", Type: "int32", LocalType: "int32", Doc: "total trial count -- increments continuously in NewState call *only in Train mode* from whenever it was last reset -- can be used for synchronizing weight updates across nodes", Directives: gti.Directives{}, Tag: ""}}, + {"TimePerCycle", >i.Field{Name: "TimePerCycle", Type: "float32", LocalType: "float32", Doc: "amount of time to increment per cycle", Directives: gti.Directives{}, Tag: "def:\"0.001\""}}, + {"SlowInterval", >i.Field{Name: "SlowInterval", Type: "int32", LocalType: "int32", Doc: "how frequently to perform slow adaptive processes such as synaptic scaling, inhibition adaptation, associated in the brain with sleep, in the SlowAdapt method. This should be long enough for meaningful changes to accumulate -- 100 is default but could easily be longer in larger models. Because SlowCtr is incremented by NData, high NData cases (e.g. 16) likely need to increase this value -- e.g., 400 seems to produce overall consistent results in various models.", Directives: gti.Directives{}, Tag: "def:\"100\""}}, + {"SlowCtr", >i.Field{Name: "SlowCtr", Type: "int32", LocalType: "int32", Doc: "counter for how long it has been since last SlowAdapt step. Note that this is incremented by NData to maintain consistency across different values of this parameter.", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + {"SynCaCtr", >i.Field{Name: "SynCaCtr", Type: "float32", LocalType: "float32", Doc: "synaptic calcium counter, which drives the CaUpT synaptic value to optimize updating of this computationally expensive factor. It is incremented by 1 for each cycle, and reset at the SlowInterval, at which point the synaptic calcium values are all reset.", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + {"pad", >i.Field{Name: "pad", Type: "float32", LocalType: "float32", Doc: "", Directives: gti.Directives{}, Tag: ""}}, + {"NetIdxs", >i.Field{Name: "NetIdxs", Type: "github.com/emer/axon/axon.NetIdxs", LocalType: "NetIdxs", Doc: "indexes and sizes of current network", Directives: gti.Directives{}, Tag: "view:\"inline\""}}, + {"NeuronVars", >i.Field{Name: "NeuronVars", Type: "github.com/emer/axon/axon.NeuronVarStrides", LocalType: "NeuronVarStrides", Doc: "stride offsets for accessing neuron variables", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + {"NeuronAvgVars", >i.Field{Name: "NeuronAvgVars", Type: "github.com/emer/axon/axon.NeuronAvgVarStrides", LocalType: "NeuronAvgVarStrides", Doc: "stride offsets for accessing neuron average variables", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + {"NeuronIdxs", >i.Field{Name: "NeuronIdxs", Type: "github.com/emer/axon/axon.NeuronIdxStrides", LocalType: "NeuronIdxStrides", Doc: "stride offsets for accessing neuron indexes", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + {"SynapseVars", >i.Field{Name: "SynapseVars", Type: "github.com/emer/axon/axon.SynapseVarStrides", LocalType: "SynapseVarStrides", Doc: "stride offsets for accessing synapse variables", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + {"SynapseCaVars", >i.Field{Name: "SynapseCaVars", Type: "github.com/emer/axon/axon.SynapseCaStrides", LocalType: "SynapseCaStrides", Doc: "stride offsets for accessing synapse Ca variables", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + {"SynapseIdxs", >i.Field{Name: "SynapseIdxs", Type: "github.com/emer/axon/axon.SynapseIdxStrides", LocalType: "SynapseIdxStrides", Doc: "stride offsets for accessing synapse indexes", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + {"RandCtr", >i.Field{Name: "RandCtr", Type: "goki.dev/gosl/v2/slrand.Counter", LocalType: "slrand.Counter", Doc: "random counter -- incremented by maximum number of possible random numbers generated per cycle, regardless of how many are actually used -- this is shared across all layers so must encompass all possible param settings.", Directives: gti.Directives{}, Tag: ""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.BurstParams", + ShortName: "axon.BurstParams", + IDName: "burst-params", + Doc: "BurstParams determine how the 5IB Burst activation is computed from\nCaSpkP integrated spiking values in Super layers -- thresholded.", + Directives: gti.Directives{ + >i.Directive{Tool: "gosl", Directive: "start", Args: []string{"deep_layers"}}, + }, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"ThrRel", >i.Field{Name: "ThrRel", Type: "float32", LocalType: "float32", Doc: "Relative component of threshold on superficial activation value, below which it does not drive Burst (and above which, Burst = CaSpkP). This is the distance between the average and maximum activation values within layer (e.g., 0 = average, 1 = max). Overall effective threshold is MAX of relative and absolute thresholds.", Directives: gti.Directives{}, Tag: "max:\"1\" def:\"0.1\""}}, + {"ThrAbs", >i.Field{Name: "ThrAbs", Type: "float32", LocalType: "float32", Doc: "Absolute component of threshold on superficial activation value, below which it does not drive Burst (and above which, Burst = CaSpkP). Overall effective threshold is MAX of relative and absolute thresholds.", Directives: gti.Directives{}, Tag: "min:\"0\" max:\"1\" def:\"0.1\""}}, + {"pad", >i.Field{Name: "pad", Type: "float32", LocalType: "float32", Doc: "", Directives: gti.Directives{}, Tag: ""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.CTParams", + ShortName: "axon.CTParams", + IDName: "ct-params", + Doc: "CTParams control the CT corticothalamic neuron special behavior", + Directives: gti.Directives{}, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"GeGain", >i.Field{Name: "GeGain", Type: "float32", LocalType: "float32", Doc: "gain factor for context excitatory input, which is constant as compared to the spiking input from other projections, so it must be downscaled accordingly. This can make a difference and may need to be scaled up or down.", Directives: gti.Directives{}, Tag: "def:\"0.05,0.1,1,2\""}}, + {"DecayTau", >i.Field{Name: "DecayTau", Type: "float32", LocalType: "float32", Doc: "decay time constant for context Ge input -- if > 0, decays over time so intrinsic circuit dynamics have to take over. For single-step copy-based cases, set to 0, while longer-time-scale dynamics should use 50", Directives: gti.Directives{}, Tag: "def:\"0,50\""}}, + {"DecayDt", >i.Field{Name: "DecayDt", Type: "float32", LocalType: "float32", Doc: "1 / tau", Directives: gti.Directives{}, Tag: "view:\"-\" json:\"-\" xml:\"-\""}}, + {"pad", >i.Field{Name: "pad", Type: "float32", LocalType: "float32", Doc: "", Directives: gti.Directives{}, Tag: ""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.PulvParams", + ShortName: "axon.PulvParams", + IDName: "pulv-params", + Doc: "PulvParams provides parameters for how the plus-phase (outcome)\nstate of Pulvinar thalamic relay cell neurons is computed from\nthe corresponding driver neuron Burst activation (or CaSpkP if not Super)", + Directives: gti.Directives{}, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"DriveScale", >i.Field{Name: "DriveScale", Type: "float32", LocalType: "float32", Doc: "multiplier on driver input strength, multiplies CaSpkP from driver layer to produce Ge excitatory input to Pulv unit.", Directives: gti.Directives{}, Tag: "def:\"0.1\" min:\"0.0\""}}, + {"FullDriveAct", >i.Field{Name: "FullDriveAct", Type: "float32", LocalType: "float32", Doc: "Level of Max driver layer CaSpkP at which the drivers fully drive the burst phase activation. If there is weaker driver input, then (Max/FullDriveAct) proportion of the non-driver inputs remain and this critically prevents the network from learning to turn activation off, which is difficult and severely degrades learning.", Directives: gti.Directives{}, Tag: "def:\"0.6\" min:\"0.01\""}}, + {"DriveLayIdx", >i.Field{Name: "DriveLayIdx", Type: "int32", LocalType: "int32", Doc: "index of layer that generates the driving activity into this one -- set via SetBuildConfig(DriveLayName) setting", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + {"pad", >i.Field{Name: "pad", Type: "float32", LocalType: "float32", Doc: "", Directives: gti.Directives{}, Tag: ""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.GlobalVars", + ShortName: "axon.GlobalVars", + IDName: "global-vars", + Doc: "GlobalVars are network-wide variables, such as neuromodulators, reward, drives, etc\nincluding the state for the PVLV phasic dopamine model.", + Directives: gti.Directives{ + >i.Directive{Tool: "gosl", Directive: "start", Args: []string{"globals"}}, + >i.Directive{Tool: "enums", Directive: "enum", Args: []string{}}, + }, + + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.PushOff", + ShortName: "axon.PushOff", + IDName: "push-off", + Doc: "PushOff has push constants for setting offset into compute shader", + Directives: gti.Directives{}, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"Off", >i.Field{Name: "Off", Type: "uint32", LocalType: "uint32", Doc: "offset", Directives: gti.Directives{}, Tag: ""}}, + {"pad", >i.Field{Name: "pad", Type: "uint32", LocalType: "uint32", Doc: "", Directives: gti.Directives{}, Tag: ""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.GPU", + ShortName: "axon.GPU", + IDName: "gpu", + Doc: "GPU manages all of the GPU-based computation for a given Network.\nLives within the network.", + Directives: gti.Directives{}, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"On", >i.Field{Name: "On", Type: "bool", LocalType: "bool", Doc: "if true, actually use the GPU", Directives: gti.Directives{}, Tag: ""}}, + {"RecFunTimes", >i.Field{Name: "RecFunTimes", Type: "bool", LocalType: "bool", Doc: "", Directives: gti.Directives{}, Tag: "desc:\"if true, slower separate shader pipeline runs are used, with a CPU-sync Wait at the end, to enable timing information about each individual shader to be collected using the network FunTimer system. otherwise, only aggregate information is available about the entire Cycle call."}}, + {"CycleByCycle", >i.Field{Name: "CycleByCycle", Type: "bool", LocalType: "bool", Doc: "if true, process each cycle one at a time. Otherwise, 10 cycles at a time are processed in one batch.", Directives: gti.Directives{}, Tag: ""}}, + {"Net", >i.Field{Name: "Net", Type: "*github.com/emer/axon/axon.Network", LocalType: "*Network", Doc: "the network we operate on -- we live under this net", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + {"Ctx", >i.Field{Name: "Ctx", Type: "*github.com/emer/axon/axon.Context", LocalType: "*Context", Doc: "the context we use", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + {"Sys", >i.Field{Name: "Sys", Type: "*github.com/goki/vgpu/vgpu.System", LocalType: "*vgpu.System", Doc: "the vgpu compute system", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + {"Params", >i.Field{Name: "Params", Type: "*github.com/goki/vgpu/vgpu.VarSet", LocalType: "*vgpu.VarSet", Doc: "VarSet = 0: the uniform LayerParams", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + {"Idxs", >i.Field{Name: "Idxs", Type: "*github.com/goki/vgpu/vgpu.VarSet", LocalType: "*vgpu.VarSet", Doc: "VarSet = 1: the storage indexes and PrjnParams", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + {"Structs", >i.Field{Name: "Structs", Type: "*github.com/goki/vgpu/vgpu.VarSet", LocalType: "*vgpu.VarSet", Doc: "VarSet = 2: the Storage buffer for RW state structs and neuron floats", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + {"Syns", >i.Field{Name: "Syns", Type: "*github.com/goki/vgpu/vgpu.VarSet", LocalType: "*vgpu.VarSet", Doc: "Varset = 3: the Storage buffer for synapses", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + {"SynCas", >i.Field{Name: "SynCas", Type: "*github.com/goki/vgpu/vgpu.VarSet", LocalType: "*vgpu.VarSet", Doc: "Varset = 4: the Storage buffer for SynCa banks", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + {"Semaphores", >i.Field{Name: "Semaphores", Type: "map[string]github.com/goki/vulkan.Semaphore", LocalType: "map[string]vk.Semaphore", Doc: "for sequencing commands", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + {"NThreads", >i.Field{Name: "NThreads", Type: "int", LocalType: "int", Doc: "number of warp threads -- typically 64 -- must update all hlsl files if changed!", Directives: gti.Directives{}, Tag: "view:\"-\" inactive:\"-\" def:\"64\""}}, + {"MaxBufferBytes", >i.Field{Name: "MaxBufferBytes", Type: "uint32", LocalType: "uint32", Doc: "maximum number of bytes per individual storage buffer element, from GPUProps.Limits.MaxStorageBufferRange", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + {"SynapseCas0", >i.Field{Name: "SynapseCas0", Type: "[]float32", LocalType: "[]float32", Doc: "bank of floats for GPU access", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + {"SynapseCas1", >i.Field{Name: "SynapseCas1", Type: "[]float32", LocalType: "[]float32", Doc: "bank of floats for GPU access", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + {"SynapseCas2", >i.Field{Name: "SynapseCas2", Type: "[]float32", LocalType: "[]float32", Doc: "bank of floats for GPU access", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + {"SynapseCas3", >i.Field{Name: "SynapseCas3", Type: "[]float32", LocalType: "[]float32", Doc: "bank of floats for GPU access", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + {"SynapseCas4", >i.Field{Name: "SynapseCas4", Type: "[]float32", LocalType: "[]float32", Doc: "bank of floats for GPU access", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + {"SynapseCas5", >i.Field{Name: "SynapseCas5", Type: "[]float32", LocalType: "[]float32", Doc: "bank of floats for GPU access", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + {"SynapseCas6", >i.Field{Name: "SynapseCas6", Type: "[]float32", LocalType: "[]float32", Doc: "bank of floats for GPU access", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + {"SynapseCas7", >i.Field{Name: "SynapseCas7", Type: "[]float32", LocalType: "[]float32", Doc: "bank of floats for GPU access", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + {"DidBind", >i.Field{Name: "DidBind", Type: "map[string]bool", LocalType: "map[string]bool", Doc: "tracks var binding", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.HipConfig", + ShortName: "axon.HipConfig", + IDName: "hip-config", + Doc: "HipConfig have the hippocampus size and connectivity parameters", + Directives: gti.Directives{}, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"EC2Size", >i.Field{Name: "EC2Size", Type: "github.com/emer/emergent/v2/evec.Vec2i", LocalType: "evec.Vec2i", Doc: "size of EC2", Directives: gti.Directives{}, Tag: "nest:\"+\""}}, + {"EC3NPool", >i.Field{Name: "EC3NPool", Type: "github.com/emer/emergent/v2/evec.Vec2i", LocalType: "evec.Vec2i", Doc: "number of EC3 pools (outer dimension)", Directives: gti.Directives{}, Tag: "nest:\"+\""}}, + {"EC3NNrn", >i.Field{Name: "EC3NNrn", Type: "github.com/emer/emergent/v2/evec.Vec2i", LocalType: "evec.Vec2i", Doc: "number of neurons in one EC3 pool", Directives: gti.Directives{}, Tag: "nest:\"+\""}}, + {"CA1NNrn", >i.Field{Name: "CA1NNrn", Type: "github.com/emer/emergent/v2/evec.Vec2i", LocalType: "evec.Vec2i", Doc: "number of neurons in one CA1 pool", Directives: gti.Directives{}, Tag: "nest:\"+\""}}, + {"CA3Size", >i.Field{Name: "CA3Size", Type: "github.com/emer/emergent/v2/evec.Vec2i", LocalType: "evec.Vec2i", Doc: "size of CA3", Directives: gti.Directives{}, Tag: "nest:\"+\""}}, + {"DGRatio", >i.Field{Name: "DGRatio", Type: "float32", LocalType: "float32", Doc: "size of DG / CA3", Directives: gti.Directives{}, Tag: "def:\"2.236\""}}, + {"EC3ToEC2PCon", >i.Field{Name: "EC3ToEC2PCon", Type: "float32", LocalType: "float32", Doc: "percent connectivity from EC3 to EC2", Directives: gti.Directives{}, Tag: "def:\"0.1\""}}, + {"EC2ToDGPCon", >i.Field{Name: "EC2ToDGPCon", Type: "float32", LocalType: "float32", Doc: "percent connectivity from EC2 to DG", Directives: gti.Directives{}, Tag: "def:\"0.25\""}}, + {"EC2ToCA3PCon", >i.Field{Name: "EC2ToCA3PCon", Type: "float32", LocalType: "float32", Doc: "percent connectivity from EC2 to CA3", Directives: gti.Directives{}, Tag: "def:\"0.25\""}}, + {"CA3ToCA1PCon", >i.Field{Name: "CA3ToCA1PCon", Type: "float32", LocalType: "float32", Doc: "percent connectivity from CA3 to CA1", Directives: gti.Directives{}, Tag: "def:\"0.25\""}}, + {"DGToCA3PCon", >i.Field{Name: "DGToCA3PCon", Type: "float32", LocalType: "float32", Doc: "percent connectivity into CA3 from DG", Directives: gti.Directives{}, Tag: "def:\"0.02\""}}, + {"EC2LatRadius", >i.Field{Name: "EC2LatRadius", Type: "int", LocalType: "int", Doc: "lateral radius of connectivity in EC2", Directives: gti.Directives{}, Tag: ""}}, + {"EC2LatSigma", >i.Field{Name: "EC2LatSigma", Type: "float32", LocalType: "float32", Doc: "lateral gaussian sigma in EC2 for how quickly weights fall off with distance", Directives: gti.Directives{}, Tag: ""}}, + {"MossyDelta", >i.Field{Name: "MossyDelta", Type: "float32", LocalType: "float32", Doc: "proportion of full mossy fiber strength (PrjnScale.Rel) for CA3 EDL in training, applied at the start of a trial to reduce DG -> CA3 strength. 1 = fully reduce strength, .5 = 50% reduction, etc", Directives: gti.Directives{}, Tag: "def:\"1\""}}, + {"MossyDeltaTest", >i.Field{Name: "MossyDeltaTest", Type: "float32", LocalType: "float32", Doc: "proportion of full mossy fiber strength (PrjnScale.Rel) for CA3 EDL in testing, applied during 2nd-3rd quarters to reduce DG -> CA3 strength. 1 = fully reduce strength, .5 = 50% reduction, etc", Directives: gti.Directives{}, Tag: "def:\"0.75\""}}, + {"ThetaLow", >i.Field{Name: "ThetaLow", Type: "float32", LocalType: "float32", Doc: "low theta modulation value for temporal difference EDL -- sets PrjnScale.Rel on CA1 <-> EC prjns consistent with Theta phase model", Directives: gti.Directives{}, Tag: "def:\"0.9\""}}, + {"ThetaHigh", >i.Field{Name: "ThetaHigh", Type: "float32", LocalType: "float32", Doc: "high theta modulation value for temporal difference EDL -- sets PrjnScale.Rel on CA1 <-> EC prjns consistent with Theta phase model", Directives: gti.Directives{}, Tag: "def:\"1\""}}, + {"EC5Clamp", >i.Field{Name: "EC5Clamp", Type: "bool", LocalType: "bool", Doc: "flag for clamping the EC5 from EC5ClampSrc", Directives: gti.Directives{}, Tag: "def:\"true\""}}, + {"EC5ClampSrc", >i.Field{Name: "EC5ClampSrc", Type: "string", LocalType: "string", Doc: "source layer for EC5 clamping activations in the plus phase -- biologically it is EC3 but can use an Input layer if available", Directives: gti.Directives{}, Tag: "def:\"EC3\""}}, + {"EC5ClampTest", >i.Field{Name: "EC5ClampTest", Type: "bool", LocalType: "bool", Doc: "clamp the EC5 from EC5ClampSrc during testing as well as training -- this will overwrite any target values that might be used in stats (e.g., in the basic hip example), so it must be turned off there", Directives: gti.Directives{}, Tag: "def:\"true\""}}, + {"EC5ClampThr", >i.Field{Name: "EC5ClampThr", Type: "float32", LocalType: "float32", Doc: "threshold for binarizing EC5 clamp values -- any value above this is clamped to 1, else 0 -- helps produce a cleaner learning signal. Set to 0 to not perform any binarization.", Directives: gti.Directives{}, Tag: "def:\"0.1\""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.HipPrjnParams", + ShortName: "axon.HipPrjnParams", + IDName: "hip-prjn-params", + Doc: "HipPrjnParams define behavior of hippocampus prjns, which have special learning rules", + Directives: gti.Directives{ + >i.Directive{Tool: "gosl", Directive: "start", Args: []string{"hip_prjns"}}, + }, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"Hebb", >i.Field{Name: "Hebb", Type: "float32", LocalType: "float32", Doc: "Hebbian learning proportion", Directives: gti.Directives{}, Tag: "def:\"0\""}}, + {"Err", >i.Field{Name: "Err", Type: "float32", LocalType: "float32", Doc: "EDL proportion", Directives: gti.Directives{}, Tag: "def:\"1\""}}, + {"SAvgCor", >i.Field{Name: "SAvgCor", Type: "float32", LocalType: "float32", Doc: "proportion of correction to apply to sending average activation for hebbian learning component (0=none, 1=all, .5=half, etc)", Directives: gti.Directives{}, Tag: "def:\"0.4:0.8\" min:\"0\" max:\"1\""}}, + {"SAvgThr", >i.Field{Name: "SAvgThr", Type: "float32", LocalType: "float32", Doc: "threshold of sending average activation below which learning does not occur (prevents learning when there is no input)", Directives: gti.Directives{}, Tag: "def:\"0.01\" min:\"0\""}}, + {"SNominal", >i.Field{Name: "SNominal", Type: "float32", LocalType: "float32", Doc: "sending layer Nominal (need to manually set it to be the same as the sending layer)", Directives: gti.Directives{}, Tag: "def:\"0.1\" min:\"0\""}}, + {"pad", >i.Field{Name: "pad", Type: "float32", LocalType: "float32", Doc: "", Directives: gti.Directives{}, Tag: ""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.ActAvgParams", + ShortName: "axon.ActAvgParams", + IDName: "act-avg-params", + Doc: "ActAvgParams represents the nominal average activity levels in the layer\nand parameters for adapting the computed Gi inhibition levels to maintain\naverage activity within a target range.", + Directives: gti.Directives{ + >i.Directive{Tool: "gosl", Directive: "hlsl", Args: []string{"inhib"}}, + >i.Directive{Tool: "gosl", Directive: "end", Args: []string{"inhib"}}, + >i.Directive{Tool: "gosl", Directive: "start", Args: []string{"inhib"}}, + }, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"Nominal", >i.Field{Name: "Nominal", Type: "float32", LocalType: "float32", Doc: "nominal estimated average activity level in the layer, which is used in computing the scaling factor on sending projections from this layer. In general it should roughly match the layer ActAvg.ActMAvg value, which can be logged using the axon.LogAddDiagnosticItems function. If layers receiving from this layer are not getting enough Ge excitation, then this Nominal level can be lowered to increase projection strength (fewer active neurons means each one contributes more, so scaling factor goes as the inverse of activity level), or vice-versa if Ge is too high. It is also the basis for the target activity level used for the AdaptGi option -- see the Offset which is added to this value.", Directives: gti.Directives{}, Tag: "min:\"0\" step:\"0.01\""}}, + {"AdaptGi", >i.Field{Name: "AdaptGi", Type: "goki.dev/gosl/v2/slbool.Bool", LocalType: "slbool.Bool", Doc: "enable adapting of layer inhibition Gi multiplier factor (stored in layer GiMult value) to maintain a Target layer level of ActAvg.ActMAvg. This generally works well and improves the long-term stability of the models. It is not enabled by default because it depends on having established a reasonable Nominal + Offset target activity level.", Directives: gti.Directives{}, Tag: ""}}, + {"Offset", >i.Field{Name: "Offset", Type: "float32", LocalType: "float32", Doc: "offset to add to Nominal for the target average activity that drives adaptation of Gi for this layer. Typically the Nominal level is good, but sometimes Nominal must be adjusted up or down to achieve desired Ge scaling, so this Offset can compensate accordingly.", Directives: gti.Directives{}, Tag: "def:\"0\" min:\"0\" step:\"0.01\" viewif:\"AdaptGi\""}}, + {"HiTol", >i.Field{Name: "HiTol", Type: "float32", LocalType: "float32", Doc: "tolerance for higher than Target target average activation as a proportion of that target value (0 = exactly the target, 0.2 = 20% higher than target) -- only once activations move outside this tolerance are inhibitory values adapted.", Directives: gti.Directives{}, Tag: "def:\"0\" viewif:\"AdaptGi\""}}, + {"LoTol", >i.Field{Name: "LoTol", Type: "float32", LocalType: "float32", Doc: "tolerance for lower than Target target average activation as a proportion of that target value (0 = exactly the target, 0.5 = 50% lower than target) -- only once activations move outside this tolerance are inhibitory values adapted.", Directives: gti.Directives{}, Tag: "def:\"0.8\" viewif:\"AdaptGi\""}}, + {"AdaptRate", >i.Field{Name: "AdaptRate", Type: "float32", LocalType: "float32", Doc: "rate of Gi adaptation as function of AdaptRate * (Target - ActMAvg) / Target -- occurs at spaced intervals determined by Network.SlowInterval value -- slower values such as 0.01 may be needed for large networks and sparse layers.", Directives: gti.Directives{}, Tag: "def:\"0.1\" viewif:\"AdaptGi\""}}, + {"pad", >i.Field{Name: "pad", Type: "float32", LocalType: "float32", Doc: "", Directives: gti.Directives{}, Tag: ""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.TopoInhibParams", + ShortName: "axon.TopoInhibParams", + IDName: "topo-inhib-params", + Doc: "TopoInhibParams provides for topographic gaussian inhibition integrating over neighborhood.\nTODO: not currently being used", + Directives: gti.Directives{}, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"On", >i.Field{Name: "On", Type: "goki.dev/gosl/v2/slbool.Bool", LocalType: "slbool.Bool", Doc: "use topographic inhibition", Directives: gti.Directives{}, Tag: ""}}, + {"Width", >i.Field{Name: "Width", Type: "int32", LocalType: "int32", Doc: "half-width of topographic inhibition within layer", Directives: gti.Directives{}, Tag: "viewif:\"On\""}}, + {"Sigma", >i.Field{Name: "Sigma", Type: "float32", LocalType: "float32", Doc: "normalized gaussian sigma as proportion of Width, for gaussian weighting", Directives: gti.Directives{}, Tag: "viewif:\"On\""}}, + {"Wrap", >i.Field{Name: "Wrap", Type: "goki.dev/gosl/v2/slbool.Bool", LocalType: "slbool.Bool", Doc: "half-width of topographic inhibition within layer", Directives: gti.Directives{}, Tag: "viewif:\"On\""}}, + {"Gi", >i.Field{Name: "Gi", Type: "float32", LocalType: "float32", Doc: "overall inhibition multiplier for topographic inhibition (generally <= 1)", Directives: gti.Directives{}, Tag: "viewif:\"On\""}}, + {"FF", >i.Field{Name: "FF", Type: "float32", LocalType: "float32", Doc: "overall inhibitory contribution from feedforward inhibition -- multiplies average Ge from pools or Ge from neurons", Directives: gti.Directives{}, Tag: "viewif:\"On\""}}, + {"FB", >i.Field{Name: "FB", Type: "float32", LocalType: "float32", Doc: "overall inhibitory contribution from feedback inhibition -- multiplies average activation from pools or Act from neurons", Directives: gti.Directives{}, Tag: "viewif:\"On\""}}, + {"FF0", >i.Field{Name: "FF0", Type: "float32", LocalType: "float32", Doc: "feedforward zero point for Ge per neuron (summed Ge is compared to N * FF0) -- below this level, no FF inhibition is computed, above this it is FF * (Sum Ge - N * FF0)", Directives: gti.Directives{}, Tag: "viewif:\"On\""}}, + {"WidthWt", >i.Field{Name: "WidthWt", Type: "float32", LocalType: "float32", Doc: "weight value at width -- to assess the value of Sigma", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + {"pad", >i.Field{Name: "pad", Type: "float32", LocalType: "float32", Doc: "", Directives: gti.Directives{}, Tag: ""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.InhibParams", + ShortName: "axon.InhibParams", + IDName: "inhib-params", + Doc: "axon.InhibParams contains all the inhibition computation params and functions for basic Axon\nThis is included in axon.Layer to support computation.\nThis also includes other misc layer-level params such as expected average activation in the layer\nwhich is used for Ge rescaling and potentially for adapting inhibition over time", + Directives: gti.Directives{}, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"ActAvg", >i.Field{Name: "ActAvg", Type: "github.com/emer/axon/axon.ActAvgParams", LocalType: "ActAvgParams", Doc: "layer-level and pool-level average activation initial values and updating / adaptation thereof -- initial values help determine initial scaling factors.", Directives: gti.Directives{}, Tag: "view:\"inline\""}}, + {"Layer", >i.Field{Name: "Layer", Type: "github.com/emer/axon/fsfffb.GiParams", LocalType: "fsfffb.GiParams", Doc: "inhibition across the entire layer -- inputs generally use Gi = 0.8 or 0.9, 1.3 or higher for sparse layers. If the layer has sub-pools (4D shape) then this is effectively between-pool inhibition.", Directives: gti.Directives{}, Tag: "view:\"inline\""}}, + {"Pool", >i.Field{Name: "Pool", Type: "github.com/emer/axon/fsfffb.GiParams", LocalType: "fsfffb.GiParams", Doc: "inhibition within sub-pools of units, for layers with 4D shape -- almost always need this if the layer has pools.", Directives: gti.Directives{}, Tag: "view:\"inline\""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.Layer", + ShortName: "axon.Layer", + IDName: "layer", + Doc: "axon.Layer implements the basic Axon spiking activation function,\nand manages learning in the projections.", + Directives: gti.Directives{}, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"Params", >i.Field{Name: "Params", Type: "*github.com/emer/axon/axon.LayerParams", LocalType: "*LayerParams", Doc: "all layer-level parameters -- these must remain constant once configured", Directives: gti.Directives{}, Tag: ""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"LayerBase", >i.Field{Name: "LayerBase", Type: "github.com/emer/axon/axon.LayerBase", LocalType: "LayerBase", Doc: "", Directives: gti.Directives{}, Tag: ""}}, + }), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.LayerBase", + ShortName: "axon.LayerBase", + IDName: "layer-base", + Doc: "LayerBase manages the structural elements of the layer, which are common\nto any Layer type.\nThe Base does not have algorithm-specific methods and parameters, so it can be easily\nreused for different algorithms, and cleanly separates the algorithm-specific code.\nAny dependency on the algorithm-level Layer can be captured in the AxonLayer interface,\naccessed via the AxonLay field.", + Directives: gti.Directives{}, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"AxonLay", >i.Field{Name: "AxonLay", Type: "github.com/emer/axon/axon.AxonLayer", LocalType: "AxonLayer", Doc: "we need a pointer to ourselves as an AxonLayer (which subsumes emer.Layer), which can always be used to extract the true underlying type of object when layer is embedded in other structs -- function receivers do not have this ability so this is necessary.", Directives: gti.Directives{}, Tag: "copy:\"-\" json:\"-\" xml:\"-\" view:\"-\""}}, + {"Network", >i.Field{Name: "Network", Type: "*github.com/emer/axon/axon.Network", LocalType: "*Network", Doc: "our parent network, in case we need to use it to find other layers etc -- set when added by network", Directives: gti.Directives{}, Tag: "copy:\"-\" json:\"-\" xml:\"-\" view:\"-\""}}, + {"Nm", >i.Field{Name: "Nm", Type: "string", LocalType: "string", Doc: "Name of the layer -- this must be unique within the network, which has a map for quick lookup and layers are typically accessed directly by name", Directives: gti.Directives{}, Tag: ""}}, + {"Cls", >i.Field{Name: "Cls", Type: "string", LocalType: "string", Doc: "Class is for applying parameter styles, can be space separated multple tags", Directives: gti.Directives{}, Tag: ""}}, + {"Off", >i.Field{Name: "Off", Type: "bool", LocalType: "bool", Doc: "inactivate this layer -- allows for easy experimentation", Directives: gti.Directives{}, Tag: ""}}, + {"Shp", >i.Field{Name: "Shp", Type: "goki.dev/etable/v2/etensor.Shape", LocalType: "etensor.Shape", Doc: "shape of the layer -- can be 2D for basic layers and 4D for layers with sub-groups (hypercolumns) -- order is outer-to-inner (row major) so Y then X for 2D and for 4D: Y-X unit pools then Y-X neurons within pools", Directives: gti.Directives{}, Tag: ""}}, + {"Typ", >i.Field{Name: "Typ", Type: "github.com/emer/axon/axon.LayerTypes", LocalType: "LayerTypes", Doc: "type of layer -- Hidden, Input, Target, Compare, or extended type in specialized algorithms -- matches against .Class parameter styles (e.g., .Hidden etc)", Directives: gti.Directives{}, Tag: ""}}, + {"Rel", >i.Field{Name: "Rel", Type: "github.com/emer/emergent/v2/relpos.Rel", LocalType: "relpos.Rel", Doc: "Spatial relationship to other layer, determines positioning", Directives: gti.Directives{}, Tag: "tableview:\"-\" view:\"inline\""}}, + {"Ps", >i.Field{Name: "Ps", Type: "goki.dev/mat32/v2.Vec3", LocalType: "mat32.Vec3", Doc: "position of lower-left-hand corner of layer in 3D space, computed from Rel. Layers are in X-Y width - height planes, stacked vertically in Z axis.", Directives: gti.Directives{}, Tag: "tableview:\"-\""}}, + {"Idx", >i.Field{Name: "Idx", Type: "int", LocalType: "int", Doc: "a 0..n-1 index of the position of the layer within list of layers in the network. For Axon networks, it only has significance in determining who gets which weights for enforcing initial weight symmetry -- higher layers get weights from lower layers.", Directives: gti.Directives{}, Tag: "view:\"-\" inactive:\"-\""}}, + {"NNeurons", >i.Field{Name: "NNeurons", Type: "uint32", LocalType: "uint32", Doc: "number of neurons in the layer", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + {"NeurStIdx", >i.Field{Name: "NeurStIdx", Type: "uint32", LocalType: "uint32", Doc: "starting index of neurons for this layer within the global Network list", Directives: gti.Directives{}, Tag: "view:\"-\" inactive:\"-\""}}, + {"NPools", >i.Field{Name: "NPools", Type: "uint32", LocalType: "uint32", Doc: "number of pools based on layer shape -- at least 1 for layer pool + 4D subpools", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + {"MaxData", >i.Field{Name: "MaxData", Type: "uint32", LocalType: "uint32", Doc: "maximum amount of input data that can be processed in parallel in one pass of the network. Neuron, Pool, Vals storage is allocated to hold this amount.", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + {"RepIxs", >i.Field{Name: "RepIxs", Type: "[]int", LocalType: "[]int", Doc: "indexes of representative units in the layer, for computationally expensive stats or displays -- also set RepShp", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + {"RepShp", >i.Field{Name: "RepShp", Type: "goki.dev/etable/v2/etensor.Shape", LocalType: "etensor.Shape", Doc: "shape of representative units in the layer -- if RepIxs is empty or .Shp is nil, use overall layer shape", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + {"RcvPrjns", >i.Field{Name: "RcvPrjns", Type: "github.com/emer/axon/axon.AxonPrjns", LocalType: "AxonPrjns", Doc: "list of receiving projections into this layer from other layers", Directives: gti.Directives{}, Tag: ""}}, + {"SndPrjns", >i.Field{Name: "SndPrjns", Type: "github.com/emer/axon/axon.AxonPrjns", LocalType: "AxonPrjns", Doc: "list of sending projections from this layer to other layers", Directives: gti.Directives{}, Tag: ""}}, + {"Vals", >i.Field{Name: "Vals", Type: "[]github.com/emer/axon/axon.LayerVals", LocalType: "[]LayerVals", Doc: "layer-level state values that are updated during computation -- one for each data parallel -- is a sub-slice of network full set", Directives: gti.Directives{}, Tag: ""}}, + {"Pools", >i.Field{Name: "Pools", Type: "[]github.com/emer/axon/axon.Pool", LocalType: "[]Pool", Doc: "computes FS-FFFB inhibition and other pooled, aggregate state variables -- has at least 1 for entire layer (lpl = layer pool), and one for each sub-pool if shape supports that (4D) * 1 per data parallel (inner loop). This is a sub-slice from overall Network Pools slice. You must iterate over index and use pointer to modify values.", Directives: gti.Directives{}, Tag: ""}}, + {"Exts", >i.Field{Name: "Exts", Type: "[]float32", LocalType: "[]float32", Doc: "external input values for this layer, allocated from network global Exts slice", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + {"BuildConfig", >i.Field{Name: "BuildConfig", Type: "map[string]string", LocalType: "map[string]string", Doc: "configuration data set when the network is configured, that is used during the network Build() process via PostBuild method, after all the structure of the network has been fully constructed. In particular, the Params is nil until Build, so setting anything specific in there (e.g., an index to another layer) must be done as a second pass. Note that Params are all applied after Build and can set user-modifiable params, so this is for more special algorithm structural parameters set during ConfigNet() methods.,", Directives: gti.Directives{}, Tag: "tableview:\"-\""}}, + {"DefParams", >i.Field{Name: "DefParams", Type: "github.com/emer/emergent/v2/params.Params", LocalType: "params.Params", Doc: "default parameters that are applied prior to user-set parameters -- these are useful for specific layer functionality in specialized brain areas (e.g., PVLV, BG etc) not associated with a layer type, which otherwise is used to hard-code initial default parameters -- typically just set to a literal map.", Directives: gti.Directives{}, Tag: "tableview:\"-\""}}, + {"ParamsHistory", >i.Field{Name: "ParamsHistory", Type: "github.com/emer/emergent/v2/params.HistoryImpl", LocalType: "params.HistoryImpl", Doc: "provides a history of parameters applied to the layer", Directives: gti.Directives{}, Tag: "tableview:\"-\""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.LayerIdxs", + ShortName: "axon.LayerIdxs", + IDName: "layer-idxs", + Doc: "LayerIdxs contains index access into network global arrays for GPU.", + Directives: gti.Directives{ + >i.Directive{Tool: "gosl", Directive: "hlsl", Args: []string{"layerparams"}}, + >i.Directive{Tool: "gosl", Directive: "end", Args: []string{"layerparams"}}, + >i.Directive{Tool: "gosl", Directive: "start", Args: []string{"layerparams"}}, + }, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"LayIdx", >i.Field{Name: "LayIdx", Type: "uint32", LocalType: "uint32", Doc: "layer index", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + {"MaxData", >i.Field{Name: "MaxData", Type: "uint32", LocalType: "uint32", Doc: "maximum number of data parallel elements", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + {"PoolSt", >i.Field{Name: "PoolSt", Type: "uint32", LocalType: "uint32", Doc: "start of pools for this layer -- first one is always the layer-wide pool", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + {"NeurSt", >i.Field{Name: "NeurSt", Type: "uint32", LocalType: "uint32", Doc: "start of neurons for this layer in global array (same as Layer.NeurStIdx)", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + {"NeurN", >i.Field{Name: "NeurN", Type: "uint32", LocalType: "uint32", Doc: "number of neurons in layer", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + {"RecvSt", >i.Field{Name: "RecvSt", Type: "uint32", LocalType: "uint32", Doc: "start index into RecvPrjns global array", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + {"RecvN", >i.Field{Name: "RecvN", Type: "uint32", LocalType: "uint32", Doc: "number of recv projections", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + {"SendSt", >i.Field{Name: "SendSt", Type: "uint32", LocalType: "uint32", Doc: "start index into RecvPrjns global array", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + {"SendN", >i.Field{Name: "SendN", Type: "uint32", LocalType: "uint32", Doc: "number of recv projections", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + {"ExtsSt", >i.Field{Name: "ExtsSt", Type: "uint32", LocalType: "uint32", Doc: "starting index in network global Exts list of external input for this layer -- only for Input / Target / Compare layer types", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + {"ShpPlY", >i.Field{Name: "ShpPlY", Type: "int32", LocalType: "int32", Doc: "layer shape Pools Y dimension -- 1 for 2D", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + {"ShpPlX", >i.Field{Name: "ShpPlX", Type: "int32", LocalType: "int32", Doc: "layer shape Pools X dimension -- 1 for 2D", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + {"ShpUnY", >i.Field{Name: "ShpUnY", Type: "int32", LocalType: "int32", Doc: "layer shape Units Y dimension", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + {"ShpUnX", >i.Field{Name: "ShpUnX", Type: "int32", LocalType: "int32", Doc: "layer shape Units X dimension", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + {"pad", >i.Field{Name: "pad", Type: "uint32", LocalType: "uint32", Doc: "", Directives: gti.Directives{}, Tag: ""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.LayerInhibIdxs", + ShortName: "axon.LayerInhibIdxs", + IDName: "layer-inhib-idxs", + Doc: "LayerInhibIdxs contains indexes of layers for between-layer inhibition", + Directives: gti.Directives{}, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"Idx1", >i.Field{Name: "Idx1", Type: "int32", LocalType: "int32", Doc: "idx of Layer to get layer-level inhibition from -- set during Build from BuildConfig LayInhib1Name if present -- -1 if not used", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + {"Idx2", >i.Field{Name: "Idx2", Type: "int32", LocalType: "int32", Doc: "idx of Layer to get layer-level inhibition from -- set during Build from BuildConfig LayInhib2Name if present -- -1 if not used", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + {"Idx3", >i.Field{Name: "Idx3", Type: "int32", LocalType: "int32", Doc: "idx of Layer to get layer-level inhibition from -- set during Build from BuildConfig LayInhib3Name if present -- -1 if not used", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + {"Idx4", >i.Field{Name: "Idx4", Type: "int32", LocalType: "int32", Doc: "idx of Layer to geta layer-level inhibition from -- set during Build from BuildConfig LayInhib4Name if present -- -1 if not used", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.LayerParams", + ShortName: "axon.LayerParams", + IDName: "layer-params", + Doc: "LayerParams contains all of the layer parameters.\nThese values must remain constant over the course of computation.\nOn the GPU, they are loaded into a uniform.", + Directives: gti.Directives{}, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"LayType", >i.Field{Name: "LayType", Type: "github.com/emer/axon/axon.LayerTypes", LocalType: "LayerTypes", Doc: "functional type of layer -- determines functional code path for specialized layer types, and is synchronized with the Layer.Typ value", Directives: gti.Directives{}, Tag: ""}}, + {"pad", >i.Field{Name: "pad", Type: "int32", LocalType: "int32", Doc: "", Directives: gti.Directives{}, Tag: ""}}, + {"Acts", >i.Field{Name: "Acts", Type: "github.com/emer/axon/axon.ActParams", LocalType: "ActParams", Doc: "Activation parameters and methods for computing activations", Directives: gti.Directives{}, Tag: "view:\"add-fields\""}}, + {"Inhib", >i.Field{Name: "Inhib", Type: "github.com/emer/axon/axon.InhibParams", LocalType: "InhibParams", Doc: "Inhibition parameters and methods for computing layer-level inhibition", Directives: gti.Directives{}, Tag: "view:\"add-fields\""}}, + {"LayInhib", >i.Field{Name: "LayInhib", Type: "github.com/emer/axon/axon.LayerInhibIdxs", LocalType: "LayerInhibIdxs", Doc: "indexes of layers that contribute between-layer inhibition to this layer -- set these indexes via BuildConfig LayInhibXName (X = 1, 2...)", Directives: gti.Directives{}, Tag: "view:\"inline\""}}, + {"Learn", >i.Field{Name: "Learn", Type: "github.com/emer/axon/axon.LearnNeurParams", LocalType: "LearnNeurParams", Doc: "Learning parameters and methods that operate at the neuron level", Directives: gti.Directives{}, Tag: "view:\"add-fields\""}}, + {"Bursts", >i.Field{Name: "Bursts", Type: "github.com/emer/axon/axon.BurstParams", LocalType: "BurstParams", Doc: "BurstParams determine how the 5IB Burst activation is computed from CaSpkP integrated spiking values in Super layers -- thresholded.", Directives: gti.Directives{}, Tag: "viewif:\"LayType=SuperLayer\" view:\"inline\""}}, + {"CT", >i.Field{Name: "CT", Type: "github.com/emer/axon/axon.CTParams", LocalType: "CTParams", Doc: "] params for the CT corticothalamic layer and PTPred layer that generates predictions over the Pulvinar using context -- uses the CtxtGe excitatory input plus stronger NMDA channels to maintain context trace", Directives: gti.Directives{}, Tag: "viewif:\"LayType=[CTLayer,PTPredLayer,PTNotMaintLayer,BLALayer]\" view:\"inline\""}}, + {"Pulv", >i.Field{Name: "Pulv", Type: "github.com/emer/axon/axon.PulvParams", LocalType: "PulvParams", Doc: "provides parameters for how the plus-phase (outcome) state of Pulvinar thalamic relay cell neurons is computed from the corresponding driver neuron Burst activation (or CaSpkP if not Super)", Directives: gti.Directives{}, Tag: "viewif:\"LayType=PulvinarLayer\" view:\"inline\""}}, + {"Matrix", >i.Field{Name: "Matrix", Type: "github.com/emer/axon/axon.MatrixParams", LocalType: "MatrixParams", Doc: "parameters for BG Striatum Matrix MSN layers, which are the main Go / NoGo gating units in BG.", Directives: gti.Directives{}, Tag: "viewif:\"LayType=MatrixLayer\" view:\"inline\""}}, + {"GP", >i.Field{Name: "GP", Type: "github.com/emer/axon/axon.GPParams", LocalType: "GPParams", Doc: "type of GP Layer.", Directives: gti.Directives{}, Tag: "viewif:\"LayType=GPLayer\" view:\"inline\""}}, + {"VSPatch", >i.Field{Name: "VSPatch", Type: "github.com/emer/axon/axon.VSPatchParams", LocalType: "VSPatchParams", Doc: "parameters for VSPatch learning", Directives: gti.Directives{}, Tag: "viewif:\"LayType=VSPatchLayer\" view:\"inline\""}}, + {"LDT", >i.Field{Name: "LDT", Type: "github.com/emer/axon/axon.LDTParams", LocalType: "LDTParams", Doc: "parameterizes laterodorsal tegmentum ACh salience neuromodulatory signal, driven by superior colliculus stimulus novelty, US input / absence, and OFC / ACC inhibition", Directives: gti.Directives{}, Tag: "viewif:\"LayType=LDTLayer\" view:\"inline\""}}, + {"VTA", >i.Field{Name: "VTA", Type: "github.com/emer/axon/axon.VTAParams", LocalType: "VTAParams", Doc: "parameterizes computing overall VTA DA based on LHb PVDA (primary value -- at US time, computed at start of each trial and stored in LHbPVDA global value) and Amygdala (CeM) CS / learned value (LV) activations, which update every cycle.", Directives: gti.Directives{}, Tag: "viewif:\"LayType=VTALayer\" view:\"inline\""}}, + {"RWPred", >i.Field{Name: "RWPred", Type: "github.com/emer/axon/axon.RWPredParams", LocalType: "RWPredParams", Doc: "parameterizes reward prediction for a simple Rescorla-Wagner learning dynamic (i.e., PV learning in the PVLV framework).", Directives: gti.Directives{}, Tag: "viewif:\"LayType=RWPredLayer\" view:\"inline\""}}, + {"RWDa", >i.Field{Name: "RWDa", Type: "github.com/emer/axon/axon.RWDaParams", LocalType: "RWDaParams", Doc: "parameterizes reward prediction dopamine for a simple Rescorla-Wagner learning dynamic (i.e., PV learning in the PVLV framework).", Directives: gti.Directives{}, Tag: "viewif:\"LayType=RWDaLayer\" view:\"inline\""}}, + {"TDInteg", >i.Field{Name: "TDInteg", Type: "github.com/emer/axon/axon.TDIntegParams", LocalType: "TDIntegParams", Doc: "parameterizes TD reward integration layer", Directives: gti.Directives{}, Tag: "viewif:\"LayType=TDIntegLayer\" view:\"inline\""}}, + {"TDDa", >i.Field{Name: "TDDa", Type: "github.com/emer/axon/axon.TDDaParams", LocalType: "TDDaParams", Doc: "parameterizes dopamine (DA) signal as the temporal difference (TD) between the TDIntegLayer activations in the minus and plus phase.", Directives: gti.Directives{}, Tag: "viewif:\"LayType=TDDaLayer\" view:\"inline\""}}, + {"Idxs", >i.Field{Name: "Idxs", Type: "github.com/emer/axon/axon.LayerIdxs", LocalType: "LayerIdxs", Doc: "recv and send projection array access info", Directives: gti.Directives{}, Tag: ""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.LayerTypes", + ShortName: "axon.LayerTypes", + IDName: "layer-types", + Doc: "LayerTypes is an axon-specific layer type enum,\nthat encompasses all the different algorithm types supported.\nClass parameter styles automatically key off of these types.\nThe first entries must be kept synchronized with the emer.LayerType,\nalthough we replace Hidden -> Super.", + Directives: gti.Directives{ + >i.Directive{Tool: "gosl", Directive: "start", Args: []string{"layertypes"}}, + >i.Directive{Tool: "enums", Directive: "enum", Args: []string{}}, + }, + + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.ActAvgVals", + ShortName: "axon.ActAvgVals", + IDName: "act-avg-vals", + Doc: "ActAvgVals are long-running-average activation levels stored in the LayerVals,\nfor monitoring and adapting inhibition and possibly scaling parameters.\nAll of these integrate over NData within a network, so are the same across them.", + Directives: gti.Directives{ + >i.Directive{Tool: "gosl", Directive: "start", Args: []string{"layervals"}}, + }, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"ActMAvg", >i.Field{Name: "ActMAvg", Type: "float32", LocalType: "float32", Doc: "running-average minus-phase activity integrated at Dt.LongAvgTau -- used for adapting inhibition relative to target level", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + {"ActPAvg", >i.Field{Name: "ActPAvg", Type: "float32", LocalType: "float32", Doc: "running-average plus-phase activity integrated at Dt.LongAvgTau", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + {"AvgMaxGeM", >i.Field{Name: "AvgMaxGeM", Type: "float32", LocalType: "float32", Doc: "running-average max of minus-phase Ge value across the layer integrated at Dt.LongAvgTau", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + {"AvgMaxGiM", >i.Field{Name: "AvgMaxGiM", Type: "float32", LocalType: "float32", Doc: "running-average max of minus-phase Gi value across the layer integrated at Dt.LongAvgTau", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + {"GiMult", >i.Field{Name: "GiMult", Type: "float32", LocalType: "float32", Doc: "multiplier on inhibition -- adapted to maintain target activity level", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + {"AdaptThr", >i.Field{Name: "AdaptThr", Type: "float32", LocalType: "float32", Doc: "adaptive threshold -- only used for specialized layers, e.g., VSPatch", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + {"pad", >i.Field{Name: "pad", Type: "float32", LocalType: "float32", Doc: "", Directives: gti.Directives{}, Tag: ""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.CorSimStats", + ShortName: "axon.CorSimStats", + IDName: "cor-sim-stats", + Doc: "CorSimStats holds correlation similarity (centered cosine aka normalized dot product)\nstatistics at the layer level", + Directives: gti.Directives{}, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"Cor", >i.Field{Name: "Cor", Type: "float32", LocalType: "float32", Doc: "correlation (centered cosine aka normalized dot product) activation difference between ActP and ActM on this alpha-cycle for this layer -- computed by CorSimFmActs called by PlusPhase", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + {"Avg", >i.Field{Name: "Avg", Type: "float32", LocalType: "float32", Doc: "running average of correlation similarity between ActP and ActM -- computed with CorSim.Tau time constant in PlusPhase", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + {"Var", >i.Field{Name: "Var", Type: "float32", LocalType: "float32", Doc: "running variance of correlation similarity between ActP and ActM -- computed with CorSim.Tau time constant in PlusPhase", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + {"pad", >i.Field{Name: "pad", Type: "float32", LocalType: "float32", Doc: "", Directives: gti.Directives{}, Tag: ""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.LaySpecialVals", + ShortName: "axon.LaySpecialVals", + IDName: "lay-special-vals", + Doc: "LaySpecialVals holds special values used to communicate to other layers\nbased on neural values, used for special algorithms such as RL where\nsome of the computation is done algorithmically.", + Directives: gti.Directives{}, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"V1", >i.Field{Name: "V1", Type: "float32", LocalType: "float32", Doc: "one value", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + {"V2", >i.Field{Name: "V2", Type: "float32", LocalType: "float32", Doc: "one value", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + {"V3", >i.Field{Name: "V3", Type: "float32", LocalType: "float32", Doc: "one value", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + {"V4", >i.Field{Name: "V4", Type: "float32", LocalType: "float32", Doc: "one value", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.LayerVals", + ShortName: "axon.LayerVals", + IDName: "layer-vals", + Doc: "LayerVals holds extra layer state that is updated per layer.\nIt is sync'd down from the GPU to the CPU after every Cycle.", + Directives: gti.Directives{}, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"LayIdx", >i.Field{Name: "LayIdx", Type: "uint32", LocalType: "uint32", Doc: "layer index for these vals", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + {"DataIdx", >i.Field{Name: "DataIdx", Type: "uint32", LocalType: "uint32", Doc: "data index for these vals", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + {"RT", >i.Field{Name: "RT", Type: "float32", LocalType: "float32", Doc: "reaction time for this layer in cycles, which is -1 until the Max CaSpkP level (after MaxCycStart) exceeds the Act.Attn.RTThr threshold", Directives: gti.Directives{}, Tag: "inactive:\"-\""}}, + {"pad", >i.Field{Name: "pad", Type: "uint32", LocalType: "uint32", Doc: "", Directives: gti.Directives{}, Tag: ""}}, + {"ActAvg", >i.Field{Name: "ActAvg", Type: "github.com/emer/axon/axon.ActAvgVals", LocalType: "ActAvgVals", Doc: "running-average activation levels used for adaptive inhibition, and other adapting values", Directives: gti.Directives{}, Tag: "view:\"inline\""}}, + {"CorSim", >i.Field{Name: "CorSim", Type: "github.com/emer/axon/axon.CorSimStats", LocalType: "CorSimStats", Doc: "correlation (centered cosine aka normalized dot product) similarity between ActM, ActP states", Directives: gti.Directives{}, Tag: ""}}, + {"Special", >i.Field{Name: "Special", Type: "github.com/emer/axon/axon.LaySpecialVals", LocalType: "LaySpecialVals", Doc: "special values used to communicate to other layers based on neural values computed on the GPU -- special cross-layer computations happen CPU-side and are sent back into the network via Context on the next cycle -- used for special algorithms such as RL / DA etc", Directives: gti.Directives{}, Tag: "view:\"inline\""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.CaLrnParams", + ShortName: "axon.CaLrnParams", + IDName: "ca-lrn-params", + Doc: "CaLrnParams parameterizes the neuron-level calcium signals driving learning:\nCaLrn = NMDA + VGCC Ca sources, where VGCC can be simulated from spiking or\nuse the more complex and dynamic VGCC channel directly.\nCaLrn is then integrated in a cascading manner at multiple time scales:\nCaM (as in calmodulin), CaP (ltP, CaMKII, plus phase), CaD (ltD, DAPK1, minus phase).", + Directives: gti.Directives{ + >i.Directive{Tool: "gosl", Directive: "hlsl", Args: []string{"learn_neur"}}, + >i.Directive{Tool: "gosl", Directive: "end", Args: []string{"learn_neur"}}, + >i.Directive{Tool: "gosl", Directive: "start", Args: []string{"learn_neur"}}, + }, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"Norm", >i.Field{Name: "Norm", Type: "float32", LocalType: "float32", Doc: "denomenator used for normalizing CaLrn, so the max is roughly 1 - 1.5 or so, which works best in terms of previous standard learning rules, and overall learning performance", Directives: gti.Directives{}, Tag: "def:\"80\""}}, + {"SpkVGCC", >i.Field{Name: "SpkVGCC", Type: "goki.dev/gosl/v2/slbool.Bool", LocalType: "slbool.Bool", Doc: "use spikes to generate VGCC instead of actual VGCC current -- see SpkVGCCa for calcium contribution from each spike", Directives: gti.Directives{}, Tag: "def:\"true\""}}, + {"SpkVgccCa", >i.Field{Name: "SpkVgccCa", Type: "float32", LocalType: "float32", Doc: "multiplier on spike for computing Ca contribution to CaLrn in SpkVGCC mode", Directives: gti.Directives{}, Tag: "def:\"35\""}}, + {"VgccTau", >i.Field{Name: "VgccTau", Type: "float32", LocalType: "float32", Doc: "time constant of decay for VgccCa calcium -- it is highly transient around spikes, so decay and diffusion factors are more important than for long-lasting NMDA factor. VgccCa is integrated separately int VgccCaInt prior to adding into NMDA Ca in CaLrn", Directives: gti.Directives{}, Tag: "def:\"10\""}}, + {"Dt", >i.Field{Name: "Dt", Type: "github.com/emer/axon/kinase.CaDtParams", LocalType: "kinase.CaDtParams", Doc: "time constants for integrating CaLrn across M, P and D cascading levels", Directives: gti.Directives{}, Tag: "view:\"inline\""}}, + {"UpdtThr", >i.Field{Name: "UpdtThr", Type: "float32", LocalType: "float32", Doc: "Threshold on CaSpkP CaSpkD value for updating synapse-level Ca values (SynCa) -- this is purely a performance optimization that excludes random infrequent spikes -- 0.05 works well on larger networks but not smaller, which require the .01 default.", Directives: gti.Directives{}, Tag: "def:\"0.01,0.02,0.5\""}}, + {"VgccDt", >i.Field{Name: "VgccDt", Type: "float32", LocalType: "float32", Doc: "rate = 1 / tau", Directives: gti.Directives{}, Tag: "view:\"-\" json:\"-\" xml:\"-\" inactive:\"+\""}}, + {"NormInv", >i.Field{Name: "NormInv", Type: "float32", LocalType: "float32", Doc: "= 1 / Norm", Directives: gti.Directives{}, Tag: "view:\"-\" json:\"-\" xml:\"-\" inactive:\"+\""}}, + {"pad", >i.Field{Name: "pad", Type: "int32", LocalType: "int32", Doc: "", Directives: gti.Directives{}, Tag: ""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.CaSpkParams", + ShortName: "axon.CaSpkParams", + IDName: "ca-spk-params", + Doc: "CaSpkParams parameterizes the neuron-level spike-driven calcium\nsignals, starting with CaSyn that is integrated at the neuron level\nand drives synapse-level, pre * post Ca integration, which provides the Tr\ntrace that multiplies error signals, and drives learning directly for Target layers.\nCaSpk* values are integrated separately at the Neuron level and used for UpdtThr\nand RLRate as a proxy for the activation (spiking) based learning signal.", + Directives: gti.Directives{}, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"SpikeG", >i.Field{Name: "SpikeG", Type: "float32", LocalType: "float32", Doc: "gain multiplier on spike for computing CaSpk: increasing this directly affects the magnitude of the trace values, learning rate in Target layers, and other factors that depend on CaSpk values: RLRate, UpdtThr. Prjn.KinaseCa.SpikeG provides an additional gain factor specific to the synapse-level trace factors, without affecting neuron-level CaSpk values. Larger networks require higher gain factors at the neuron level -- 12, vs 8 for smaller.", Directives: gti.Directives{}, Tag: "def:\"8,12\""}}, + {"SynTau", >i.Field{Name: "SynTau", Type: "float32", LocalType: "float32", Doc: "time constant for integrating spike-driven calcium trace at sender and recv neurons, CaSyn, which then drives synapse-level integration of the joint pre * post synapse-level activity, in cycles (msec). Note: if this param is changed, then there will be a change in effective learning rate that can be compensated for by multiplying PrjnParams.Learn.KinaseCa.SpikeG by sqrt(30 / sqrt(SynTau)", Directives: gti.Directives{}, Tag: "def:\"30\" min:\"1\""}}, + {"SynDt", >i.Field{Name: "SynDt", Type: "float32", LocalType: "float32", Doc: "rate = 1 / tau", Directives: gti.Directives{}, Tag: "view:\"-\" json:\"-\" xml:\"-\" inactive:\"+\""}}, + {"pad", >i.Field{Name: "pad", Type: "int32", LocalType: "int32", Doc: "", Directives: gti.Directives{}, Tag: ""}}, + {"Dt", >i.Field{Name: "Dt", Type: "github.com/emer/axon/kinase.CaDtParams", LocalType: "kinase.CaDtParams", Doc: "time constants for integrating CaSpk across M, P and D cascading levels -- these are typically the same as in CaLrn and Prjn level for synaptic integration, except for the M factor.", Directives: gti.Directives{}, Tag: "view:\"inline\""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.TrgAvgActParams", + ShortName: "axon.TrgAvgActParams", + IDName: "trg-avg-act-params", + Doc: "TrgAvgActParams govern the target and actual long-term average activity in neurons.\nTarget value is adapted by neuron-wise error and difference in actual vs. target.\ndrives synaptic scaling at a slow timescale (Network.SlowInterval).", + Directives: gti.Directives{}, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"On", >i.Field{Name: "On", Type: "goki.dev/gosl/v2/slbool.Bool", LocalType: "slbool.Bool", Doc: "whether to use target average activity mechanism to scale synaptic weights", Directives: gti.Directives{}, Tag: ""}}, + {"GiBaseInit", >i.Field{Name: "GiBaseInit", Type: "float32", LocalType: "float32", Doc: "if this is > 0, then each neuron's GiBase is initialized as this proportion of TrgRange.Max - TrgAvg -- gives neurons differences in intrinsic inhibition / leak as a starting bias", Directives: gti.Directives{}, Tag: ""}}, + {"ErrLRate", >i.Field{Name: "ErrLRate", Type: "float32", LocalType: "float32", Doc: "learning rate for adjustments to Trg value based on unit-level error signal. Population TrgAvg values are renormalized to fixed overall average in TrgRange. Generally, deviating from the default doesn't make much difference.", Directives: gti.Directives{}, Tag: "viewif:\"On\" def:\"0.02\""}}, + {"SynScaleRate", >i.Field{Name: "SynScaleRate", Type: "float32", LocalType: "float32", Doc: "rate parameter for how much to scale synaptic weights in proportion to the AvgDif between target and actual proportion activity -- this determines the effective strength of the constraint, and larger models may need more than the weaker default value.", Directives: gti.Directives{}, Tag: "viewif:\"On\" def:\"0.005,0.0002\""}}, + {"SubMean", >i.Field{Name: "SubMean", Type: "float32", LocalType: "float32", Doc: "amount of mean trg change to subtract -- 1 = full zero sum. 1 works best in general -- but in some cases it may be better to start with 0 and then increase using network SetSubMean method at a later point.", Directives: gti.Directives{}, Tag: "viewif:\"On\" def:\"0,1\""}}, + {"Permute", >i.Field{Name: "Permute", Type: "goki.dev/gosl/v2/slbool.Bool", LocalType: "slbool.Bool", Doc: "permute the order of TrgAvg values within layer -- otherwise they are just assigned in order from highest to lowest for easy visualization -- generally must be true if any topographic weights are being used", Directives: gti.Directives{}, Tag: "viewif:\"On\" def:\"true\""}}, + {"Pool", >i.Field{Name: "Pool", Type: "goki.dev/gosl/v2/slbool.Bool", LocalType: "slbool.Bool", Doc: "use pool-level target values if pool-level inhibition and 4D pooled layers are present -- if pool sizes are relatively small, then may not be useful to distribute targets just within pool", Directives: gti.Directives{}, Tag: "viewif:\"On\""}}, + {"pad", >i.Field{Name: "pad", Type: "int32", LocalType: "int32", Doc: "", Directives: gti.Directives{}, Tag: ""}}, + {"TrgRange", >i.Field{Name: "TrgRange", Type: "goki.dev/etable/v2/minmax.F32", LocalType: "minmax.F32", Doc: "range of target normalized average activations -- individual neurons are assigned values within this range to TrgAvg, and clamped within this range.", Directives: gti.Directives{}, Tag: "viewif:\"On\" def:\"{'Min':0.5,'Max':2}\""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.RLRateParams", + ShortName: "axon.RLRateParams", + IDName: "rl-rate-params", + Doc: "RLRateParams are recv neuron learning rate modulation parameters.\nHas two factors: the derivative of the sigmoid based on CaSpkD\nactivity levels, and based on the phase-wise differences in activity (Diff).", + Directives: gti.Directives{}, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"On", >i.Field{Name: "On", Type: "goki.dev/gosl/v2/slbool.Bool", LocalType: "slbool.Bool", Doc: "use learning rate modulation", Directives: gti.Directives{}, Tag: "def:\"true\""}}, + {"SigmoidMin", >i.Field{Name: "SigmoidMin", Type: "float32", LocalType: "float32", Doc: "minimum learning rate multiplier for sigmoidal act (1-act) factor -- prevents lrate from going too low for extreme values. Set to 1 to disable Sigmoid derivative factor, which is default for Target layers.", Directives: gti.Directives{}, Tag: "viewif:\"On\" def:\"0.05,1\""}}, + {"Diff", >i.Field{Name: "Diff", Type: "goki.dev/gosl/v2/slbool.Bool", LocalType: "slbool.Bool", Doc: "modulate learning rate as a function of plus - minus differences", Directives: gti.Directives{}, Tag: "viewif:\"On\""}}, + {"SpkThr", >i.Field{Name: "SpkThr", Type: "float32", LocalType: "float32", Doc: "threshold on Max(CaSpkP, CaSpkD) below which Min lrate applies -- must be > 0 to prevent div by zero", Directives: gti.Directives{}, Tag: "viewif:\"On&&Diff\" def:\"0.1\""}}, + {"DiffThr", >i.Field{Name: "DiffThr", Type: "float32", LocalType: "float32", Doc: "threshold on recv neuron error delta, i.e., |CaSpkP - CaSpkD| below which lrate is at Min value", Directives: gti.Directives{}, Tag: "viewif:\"On&&Diff\" def:\"0.02\""}}, + {"Min", >i.Field{Name: "Min", Type: "float32", LocalType: "float32", Doc: "for Diff component, minimum learning rate value when below ActDiffThr", Directives: gti.Directives{}, Tag: "viewif:\"On&&Diff\" def:\"0.001\""}}, + {"pad", >i.Field{Name: "pad", Type: "int32", LocalType: "int32", Doc: "", Directives: gti.Directives{}, Tag: ""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.LearnNeurParams", + ShortName: "axon.LearnNeurParams", + IDName: "learn-neur-params", + Doc: "axon.LearnNeurParams manages learning-related parameters at the neuron-level.\nThis is mainly the running average activations that drive learning", + Directives: gti.Directives{}, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"CaLearn", >i.Field{Name: "CaLearn", Type: "github.com/emer/axon/axon.CaLrnParams", LocalType: "CaLrnParams", Doc: "parameterizes the neuron-level calcium signals driving learning: CaLrn = NMDA + VGCC Ca sources, where VGCC can be simulated from spiking or use the more complex and dynamic VGCC channel directly. CaLrn is then integrated in a cascading manner at multiple time scales: CaM (as in calmodulin), CaP (ltP, CaMKII, plus phase), CaD (ltD, DAPK1, minus phase).", Directives: gti.Directives{}, Tag: "view:\"inline\""}}, + {"CaSpk", >i.Field{Name: "CaSpk", Type: "github.com/emer/axon/axon.CaSpkParams", LocalType: "CaSpkParams", Doc: "parameterizes the neuron-level spike-driven calcium signals, starting with CaSyn that is integrated at the neuron level, and drives synapse-level, pre * post Ca integration, which provides the Tr trace that multiplies error signals, and drives learning directly for Target layers. CaSpk* values are integrated separately at the Neuron level and used for UpdtThr and RLRate as a proxy for the activation (spiking) based learning signal.", Directives: gti.Directives{}, Tag: "view:\"inline\""}}, + {"LrnNMDA", >i.Field{Name: "LrnNMDA", Type: "github.com/emer/axon/chans.NMDAParams", LocalType: "chans.NMDAParams", Doc: "NMDA channel parameters used for learning, vs. the ones driving activation -- allows exploration of learning parameters independent of their effects on active maintenance contributions of NMDA, and may be supported by different receptor subtypes", Directives: gti.Directives{}, Tag: "view:\"inline\""}}, + {"TrgAvgAct", >i.Field{Name: "TrgAvgAct", Type: "github.com/emer/axon/axon.TrgAvgActParams", LocalType: "TrgAvgActParams", Doc: "synaptic scaling parameters for regulating overall average activity compared to neuron's own target level", Directives: gti.Directives{}, Tag: "view:\"inline\""}}, + {"RLRate", >i.Field{Name: "RLRate", Type: "github.com/emer/axon/axon.RLRateParams", LocalType: "RLRateParams", Doc: "recv neuron learning rate modulation params -- an additional error-based modulation of learning for receiver side: RLRate = |CaSpkP - CaSpkD| / Max(CaSpkP, CaSpkD)", Directives: gti.Directives{}, Tag: "view:\"inline\""}}, + {"NeuroMod", >i.Field{Name: "NeuroMod", Type: "github.com/emer/axon/axon.NeuroModParams", LocalType: "NeuroModParams", Doc: "neuromodulation effects on learning rate and activity, as a function of layer-level DA and ACh values, which are updated from global Context values, and computed from reinforcement learning algorithms", Directives: gti.Directives{}, Tag: "view:\"inline\""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.SWtInitParams", + ShortName: "axon.SWtInitParams", + IDName: "s-wt-init-params", + Doc: "SWtInitParams for initial SWt values", + Directives: gti.Directives{}, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"SPct", >i.Field{Name: "SPct", Type: "float32", LocalType: "float32", Doc: "how much of the initial random weights are captured in the SWt values -- rest goes into the LWt values. 1 gives the strongest initial biasing effect, for larger models that need more structural support. 0.5 should work for most models where stronger constraints are not needed.", Directives: gti.Directives{}, Tag: "min:\"0\" max:\"1\" def:\"0,1,0.5\""}}, + {"Mean", >i.Field{Name: "Mean", Type: "float32", LocalType: "float32", Doc: "target mean weight values across receiving neuron's projection -- the mean SWt values are constrained to remain at this value. some projections may benefit from lower mean of .4", Directives: gti.Directives{}, Tag: "def:\"0.5,0.4\""}}, + {"Var", >i.Field{Name: "Var", Type: "float32", LocalType: "float32", Doc: "initial variance in weight values, prior to constraints.", Directives: gti.Directives{}, Tag: "def:\"0.25\""}}, + {"Sym", >i.Field{Name: "Sym", Type: "goki.dev/gosl/v2/slbool.Bool", LocalType: "slbool.Bool", Doc: "symmetrize the initial weight values with those in reciprocal projection -- typically true for bidirectional excitatory connections", Directives: gti.Directives{}, Tag: "def:\"true\""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.SWtAdaptParams", + ShortName: "axon.SWtAdaptParams", + IDName: "s-wt-adapt-params", + Doc: "SWtAdaptParams manages adaptation of SWt values", + Directives: gti.Directives{}, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"On", >i.Field{Name: "On", Type: "goki.dev/gosl/v2/slbool.Bool", LocalType: "slbool.Bool", Doc: "if true, adaptation is active -- if false, SWt values are not updated, in which case it is generally good to have Init.SPct=0 too.", Directives: gti.Directives{}, Tag: ""}}, + {"LRate", >i.Field{Name: "LRate", Type: "float32", LocalType: "float32", Doc: "learning rate multiplier on the accumulated DWt values (which already have fast LRate applied) to incorporate into SWt during slow outer loop updating -- lower values impose stronger constraints, for larger networks that need more structural support, e.g., 0.001 is better after 1,000 epochs in large models. 0.1 is fine for smaller models.", Directives: gti.Directives{}, Tag: "viewif:\"On\" def:\"0.1,0.01,0.001,0.0002\""}}, + {"SubMean", >i.Field{Name: "SubMean", Type: "float32", LocalType: "float32", Doc: "amount of mean to subtract from SWt delta when updating -- generally best to set to 1", Directives: gti.Directives{}, Tag: "viewif:\"On\" def:\"1\""}}, + {"SigGain", >i.Field{Name: "SigGain", Type: "float32", LocalType: "float32", Doc: "gain of sigmoidal constrast enhancement function used to transform learned, linear LWt values into Wt values", Directives: gti.Directives{}, Tag: "viewif:\"On\" def:\"6\""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.SWtParams", + ShortName: "axon.SWtParams", + IDName: "s-wt-params", + Doc: "SWtParams manages structural, slowly adapting weight values (SWt),\nin terms of initialization and updating over course of learning.\nSWts impose initial and slowly adapting constraints on neuron connectivity\nto encourage differentiation of neuron representations and overall good behavior\nin terms of not hogging the representational space.\nThe TrgAvg activity constraint is not enforced through SWt -- it needs to be\nmore dynamic and supported by the regular learned weights.", + Directives: gti.Directives{ + >i.Directive{Tool: "gosl", Directive: "start", Args: []string{"learn"}}, + }, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"Init", >i.Field{Name: "Init", Type: "github.com/emer/axon/axon.SWtInitParams", LocalType: "SWtInitParams", Doc: "initialization of SWt values", Directives: gti.Directives{}, Tag: "view:\"inline\""}}, + {"Adapt", >i.Field{Name: "Adapt", Type: "github.com/emer/axon/axon.SWtAdaptParams", LocalType: "SWtAdaptParams", Doc: "adaptation of SWt values in response to LWt learning", Directives: gti.Directives{}, Tag: "view:\"inline\""}}, + {"Limit", >i.Field{Name: "Limit", Type: "goki.dev/etable/v2/minmax.F32", LocalType: "minmax.F32", Doc: "range limits for SWt values", Directives: gti.Directives{}, Tag: "def:\"{'Min':0.2,'Max':0.8}\" view:\"inline\""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.LRateParams", + ShortName: "axon.LRateParams", + IDName: "l-rate-params", + Doc: "LRateParams manages learning rate parameters", + Directives: gti.Directives{ + >i.Directive{Tool: "gosl", Directive: "start", Args: []string{"learn"}}, + }, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"Base", >i.Field{Name: "Base", Type: "float32", LocalType: "float32", Doc: "base learning rate for this projection -- can be modulated by other factors below -- for larger networks, use slower rates such as 0.04, smaller networks can use faster 0.2.", Directives: gti.Directives{}, Tag: "def:\"0.04,0.1,0.2\""}}, + {"Sched", >i.Field{Name: "Sched", Type: "float32", LocalType: "float32", Doc: "scheduled learning rate multiplier, simulating reduction in plasticity over aging", Directives: gti.Directives{}, Tag: ""}}, + {"Mod", >i.Field{Name: "Mod", Type: "float32", LocalType: "float32", Doc: "dynamic learning rate modulation due to neuromodulatory or other such factors", Directives: gti.Directives{}, Tag: ""}}, + {"Eff", >i.Field{Name: "Eff", Type: "float32", LocalType: "float32", Doc: "effective actual learning rate multiplier used in computing DWt: Eff = eMod * Sched * Base", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.TraceParams", + ShortName: "axon.TraceParams", + IDName: "trace-params", + Doc: "TraceParams manages learning rate parameters", + Directives: gti.Directives{}, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"Tau", >i.Field{Name: "Tau", Type: "float32", LocalType: "float32", Doc: "time constant for integrating trace over theta cycle timescales -- governs the decay rate of syanptic trace", Directives: gti.Directives{}, Tag: "def:\"1,2,4\""}}, + {"SubMean", >i.Field{Name: "SubMean", Type: "float32", LocalType: "float32", Doc: "amount of the mean dWt to subtract, producing a zero-sum effect -- 1.0 = full zero-sum dWt -- only on non-zero DWts. typically set to 0 for standard trace learning projections, although some require it for stability over the long haul. can use SetSubMean to set to 1 after significant early learning has occurred with 0. Some special prjn types (e.g., Hebb) benefit from SubMean = 1 always", Directives: gti.Directives{}, Tag: "def:\"0,1\""}}, + {"LearnThr", >i.Field{Name: "LearnThr", Type: "float32", LocalType: "float32", Doc: "threshold for learning, depending on different algorithms -- in Matrix and VSPatch it applies to normalized GeIntNorm value -- setting this relatively high encourages sparser representations", Directives: gti.Directives{}, Tag: ""}}, + {"Dt", >i.Field{Name: "Dt", Type: "float32", LocalType: "float32", Doc: "rate = 1 / tau", Directives: gti.Directives{}, Tag: "view:\"-\" json:\"-\" xml:\"-\" inactive:\"+\""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.LRateMod", + ShortName: "axon.LRateMod", + IDName: "l-rate-mod", + Doc: "LRateMod implements global learning rate modulation, based on a performance-based\nfactor, for example error. Increasing levels of the factor = higher learning rate.\nThis can be added to a Sim and called prior to DWt() to dynamically change lrate\nbased on overall network performance.", + Directives: gti.Directives{}, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"On", >i.Field{Name: "On", Type: "goki.dev/gosl/v2/slbool.Bool", LocalType: "slbool.Bool", Doc: "toggle use of this modulation factor", Directives: gti.Directives{}, Tag: ""}}, + {"Base", >i.Field{Name: "Base", Type: "float32", LocalType: "float32", Doc: "baseline learning rate -- what you get for correct cases", Directives: gti.Directives{}, Tag: "viewif:\"On\" min:\"0\" max:\"1\""}}, + {"pad", >i.Field{Name: "pad", Type: "int32", LocalType: "int32", Doc: "", Directives: gti.Directives{}, Tag: ""}}, + {"Range", >i.Field{Name: "Range", Type: "goki.dev/etable/v2/minmax.F32", LocalType: "minmax.F32", Doc: "defines the range over which modulation occurs for the modulator factor -- Min and below get the Base level of learning rate modulation, Max and above get a modulation of 1", Directives: gti.Directives{}, Tag: "viewif:\"On\""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.LearnSynParams", + ShortName: "axon.LearnSynParams", + IDName: "learn-syn-params", + Doc: "LearnSynParams manages learning-related parameters at the synapse-level.", + Directives: gti.Directives{ + >i.Directive{Tool: "gosl", Directive: "start", Args: []string{"learn"}}, + }, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"Learn", >i.Field{Name: "Learn", Type: "goki.dev/gosl/v2/slbool.Bool", LocalType: "slbool.Bool", Doc: "enable learning for this projection", Directives: gti.Directives{}, Tag: ""}}, + {"pad", >i.Field{Name: "pad", Type: "int32", LocalType: "int32", Doc: "", Directives: gti.Directives{}, Tag: ""}}, + {"LRate", >i.Field{Name: "LRate", Type: "github.com/emer/axon/axon.LRateParams", LocalType: "LRateParams", Doc: "learning rate parameters, supporting two levels of modulation on top of base learning rate.", Directives: gti.Directives{}, Tag: "viewif:\"Learn\""}}, + {"Trace", >i.Field{Name: "Trace", Type: "github.com/emer/axon/axon.TraceParams", LocalType: "TraceParams", Doc: "trace-based learning parameters", Directives: gti.Directives{}, Tag: "viewif:\"Learn\""}}, + {"KinaseCa", >i.Field{Name: "KinaseCa", Type: "github.com/emer/axon/kinase.CaParams", LocalType: "kinase.CaParams", Doc: "kinase calcium Ca integration parameters", Directives: gti.Directives{}, Tag: "viewif:\"Learn\" view:\"inline\""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.Network", + ShortName: "axon.Network", + IDName: "network", + Doc: "axon.Network implements the Axon spiking model,\nbuilding on the algorithm-independent NetworkBase that manages\nall the infrastructure.", + Directives: gti.Directives{}, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"NetworkBase", >i.Field{Name: "NetworkBase", Type: "github.com/emer/axon/axon.NetworkBase", LocalType: "NetworkBase", Doc: "", Directives: gti.Directives{}, Tag: ""}}, + }), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.NetworkBase", + ShortName: "axon.NetworkBase", + IDName: "network-base", + Doc: "NetworkBase manages the basic structural components of a network (layers).\nThe main Network then can just have the algorithm-specific code.", + Directives: gti.Directives{}, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"EmerNet", >i.Field{Name: "EmerNet", Type: "github.com/emer/emergent/v2/emer.Network", LocalType: "emer.Network", Doc: "we need a pointer to ourselves as an emer.Network, which can always be used to extract the true underlying type of object when network is embedded in other structs -- function receivers do not have this ability so this is necessary.", Directives: gti.Directives{}, Tag: "copy:\"-\" json:\"-\" xml:\"-\" view:\"-\""}}, + {"Nm", >i.Field{Name: "Nm", Type: "string", LocalType: "string", Doc: "overall name of network -- helps discriminate if there are multiple", Directives: gti.Directives{}, Tag: ""}}, + {"WtsFile", >i.Field{Name: "WtsFile", Type: "string", LocalType: "string", Doc: "filename of last weights file loaded or saved", Directives: gti.Directives{}, Tag: ""}}, + {"PVLV", >i.Field{Name: "PVLV", Type: "github.com/emer/axon/axon.PVLV", LocalType: "PVLV", Doc: "PVLV system for phasic dopamine signaling, including internal drives, US outcomes. Core LHb (lateral habenula) and VTA (ventral tegmental area) dopamine are computed in equations using inputs from specialized network layers (LDTLayer driven by BLA, CeM layers, VSPatchLayer). Renders USLayer, PVLayer, DrivesLayer representations based on state updated here.", Directives: gti.Directives{}, Tag: ""}}, + {"LayMap", >i.Field{Name: "LayMap", Type: "map[string]*github.com/emer/axon/axon.Layer", LocalType: "map[string]*Layer", Doc: "map of name to layers -- layer names must be unique", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + {"LayClassMap", >i.Field{Name: "LayClassMap", Type: "map[string][]string", LocalType: "map[string][]string", Doc: "map of layer classes -- made during Build", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + {"MinPos", >i.Field{Name: "MinPos", Type: "goki.dev/mat32/v2.Vec3", LocalType: "mat32.Vec3", Doc: "minimum display position in network", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + {"MaxPos", >i.Field{Name: "MaxPos", Type: "goki.dev/mat32/v2.Vec3", LocalType: "mat32.Vec3", Doc: "maximum display position in network", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + {"MetaData", >i.Field{Name: "MetaData", Type: "map[string]string", LocalType: "map[string]string", Doc: "optional metadata that is saved in network weights files -- e.g., can indicate number of epochs that were trained, or any other information about this network that would be useful to save", Directives: gti.Directives{}, Tag: ""}}, + {"UseGPUOrder", >i.Field{Name: "UseGPUOrder", Type: "bool", LocalType: "bool", Doc: "if true, the neuron and synapse variables will be organized into a gpu-optimized memory order, otherwise cpu-optimized. This must be set before network Build() is called.", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + {"NetIdx", >i.Field{Name: "NetIdx", Type: "uint32", LocalType: "uint32", Doc: "network index in global Networks list of networks -- needed for GPU shader kernel compatible network variable access functions (e.g., NrnV, SynV etc) in CPU mode", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + {"MaxDelay", >i.Field{Name: "MaxDelay", Type: "uint32", LocalType: "uint32", Doc: "maximum synaptic delay across any projection in the network -- used for sizing the GBuf accumulation buffer.", Directives: gti.Directives{}, Tag: "inactive:\"+\" view:\"-\""}}, + {"MaxData", >i.Field{Name: "MaxData", Type: "uint32", LocalType: "uint32", Doc: "maximum number of data inputs that can be processed in parallel in one pass of the network. Neuron storage is allocated to hold this amount during Build process, and this value reflects that.", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + {"NNeurons", >i.Field{Name: "NNeurons", Type: "uint32", LocalType: "uint32", Doc: "total number of neurons", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + {"NSyns", >i.Field{Name: "NSyns", Type: "uint32", LocalType: "uint32", Doc: "total number of synapses", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + {"Globals", >i.Field{Name: "Globals", Type: "[]float32", LocalType: "[]float32", Doc: "storage for global vars", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + {"Layers", >i.Field{Name: "Layers", Type: "[]*github.com/emer/axon/axon.Layer", LocalType: "[]*Layer", Doc: "array of layers", Directives: gti.Directives{}, Tag: ""}}, + {"LayParams", >i.Field{Name: "LayParams", Type: "[]github.com/emer/axon/axon.LayerParams", LocalType: "[]LayerParams", Doc: "array of layer parameters, in 1-to-1 correspondence with Layers", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + {"LayVals", >i.Field{Name: "LayVals", Type: "[]github.com/emer/axon/axon.LayerVals", LocalType: "[]LayerVals", Doc: "array of layer values, with extra per data", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + {"Pools", >i.Field{Name: "Pools", Type: "[]github.com/emer/axon/axon.Pool", LocalType: "[]Pool", Doc: "array of inhibitory pools for all layers.", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + {"Neurons", >i.Field{Name: "Neurons", Type: "[]float32", LocalType: "[]float32", Doc: "entire network's allocation of neuron variables, accessed via NrnV function with flexible striding", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + {"NeuronAvgs", >i.Field{Name: "NeuronAvgs", Type: "[]float32", LocalType: "[]float32", Doc: "] entire network's allocation of neuron average avariables, accessed via NrnAvgV function with flexible striding", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + {"NeuronIxs", >i.Field{Name: "NeuronIxs", Type: "[]uint32", LocalType: "[]uint32", Doc: "entire network's allocation of neuron index variables, accessed via NrnI function with flexible striding", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + {"Prjns", >i.Field{Name: "Prjns", Type: "[]*github.com/emer/axon/axon.Prjn", LocalType: "[]*Prjn", Doc: "pointers to all projections in the network, sender-based", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + {"PrjnParams", >i.Field{Name: "PrjnParams", Type: "[]github.com/emer/axon/axon.PrjnParams", LocalType: "[]PrjnParams", Doc: "array of projection parameters, in 1-to-1 correspondence with Prjns, sender-based", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + {"SynapseIxs", >i.Field{Name: "SynapseIxs", Type: "[]uint32", LocalType: "[]uint32", Doc: "entire network's allocation of synapse idx vars, organized sender-based, with flexible striding, accessed via SynI function", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + {"Synapses", >i.Field{Name: "Synapses", Type: "[]float32", LocalType: "[]float32", Doc: "entire network's allocation of synapses, organized sender-based, with flexible striding, accessed via SynV function", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + {"SynapseCas", >i.Field{Name: "SynapseCas", Type: "[]float32", LocalType: "[]float32", Doc: "entire network's allocation of synapse Ca vars, organized sender-based, with flexible striding, accessed via SynCaV function", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + {"PrjnSendCon", >i.Field{Name: "PrjnSendCon", Type: "[]github.com/emer/axon/axon.StartN", LocalType: "[]StartN", Doc: "starting offset and N cons for each sending neuron, for indexing into the Syns synapses, which are organized sender-based.", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + {"PrjnRecvCon", >i.Field{Name: "PrjnRecvCon", Type: "[]github.com/emer/axon/axon.StartN", LocalType: "[]StartN", Doc: "starting offset and N cons for each recv neuron, for indexing into the RecvSynIdx array of indexes into the Syns synapses, which are organized sender-based.", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + {"PrjnGBuf", >i.Field{Name: "PrjnGBuf", Type: "[]int32", LocalType: "[]int32", Doc: "conductance buffer for accumulating spikes -- subslices are allocated to each projection -- uses int-encoded float values for faster GPU atomic integration", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + {"PrjnGSyns", >i.Field{Name: "PrjnGSyns", Type: "[]float32", LocalType: "[]float32", Doc: "synaptic conductance integrated over time per projection per recv neurons -- spikes come in via PrjnBuf -- subslices are allocated to each projection", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + {"RecvPrjnIdxs", >i.Field{Name: "RecvPrjnIdxs", Type: "[]uint32", LocalType: "[]uint32", Doc: "indexes into Prjns (organized by SendPrjn) organized by recv projections -- needed for iterating through recv prjns efficiently on GPU.", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + {"RecvSynIdxs", >i.Field{Name: "RecvSynIdxs", Type: "[]uint32", LocalType: "[]uint32", Doc: "indexes into Synapses for each recv neuron, organized into blocks according to PrjnRecvCon, for receiver-based access.", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + {"Exts", >i.Field{Name: "Exts", Type: "[]float32", LocalType: "[]float32", Doc: "external input values for all Input / Target / Compare layers in the network -- the ApplyExt methods write to this per layer, and it is then actually applied in one consistent method.", Directives: gti.Directives{}, Tag: ""}}, + {"Ctx", >i.Field{Name: "Ctx", Type: "github.com/emer/axon/axon.Context", LocalType: "Context", Doc: "context used only for accessing neurons for display -- NetIdxs.NData in here is copied from active context in NewState", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + {"Rand", >i.Field{Name: "Rand", Type: "github.com/emer/emergent/v2/erand.SysRand", LocalType: "erand.SysRand", Doc: "random number generator for the network -- all random calls must use this -- set seed here for weight initialization values", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + {"RndSeed", >i.Field{Name: "RndSeed", Type: "int64", LocalType: "int64", Doc: "random seed to be set at the start of configuring the network and initializing the weights -- set this to get a different set of weights", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + {"NThreads", >i.Field{Name: "NThreads", Type: "int", LocalType: "int", Doc: "number of threads to use for parallel processing", Directives: gti.Directives{}, Tag: ""}}, + {"GPU", >i.Field{Name: "GPU", Type: "github.com/emer/axon/axon.GPU", LocalType: "GPU", Doc: "GPU implementation", Directives: gti.Directives{}, Tag: "view:\"inline\""}}, + {"RecFunTimes", >i.Field{Name: "RecFunTimes", Type: "bool", LocalType: "bool", Doc: "record function timer information", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + {"FunTimes", >i.Field{Name: "FunTimes", Type: "map[string]*github.com/emer/emergent/v2/timer.Time", LocalType: "map[string]*timer.Time", Doc: "timers for each major function (step of processing)", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.DAModTypes", + ShortName: "axon.DAModTypes", + IDName: "da-mod-types", + Doc: "DAModTypes are types of dopamine modulation of neural activity.", + Directives: gti.Directives{ + >i.Directive{Tool: "gosl", Directive: "start", Args: []string{"neuromod"}}, + >i.Directive{Tool: "enums", Directive: "enum", Args: []string{}}, + }, + + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.ValenceTypes", + ShortName: "axon.ValenceTypes", + IDName: "valence-types", + Doc: "ValenceTypes are types of valence coding: positive or negative.", + Directives: gti.Directives{ + >i.Directive{Tool: "enums", Directive: "enum", Args: []string{}}, + }, + + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.NeuroModParams", + ShortName: "axon.NeuroModParams", + IDName: "neuro-mod-params", + Doc: "NeuroModParams specifies the effects of neuromodulators on neural\nactivity and learning rate. These can apply to any neuron type,\nand are applied in the core cycle update equations.", + Directives: gti.Directives{}, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"DAMod", >i.Field{Name: "DAMod", Type: "github.com/emer/axon/axon.DAModTypes", LocalType: "DAModTypes", Doc: "dopamine receptor-based effects of dopamine modulation on excitatory and inhibitory conductances: D1 is excitatory, D2 is inhibitory as a function of increasing dopamine", Directives: gti.Directives{}, Tag: ""}}, + {"Valence", >i.Field{Name: "Valence", Type: "github.com/emer/axon/axon.ValenceTypes", LocalType: "ValenceTypes", Doc: "valence coding of this layer -- may affect specific layer types but does not directly affect neuromodulators currently", Directives: gti.Directives{}, Tag: ""}}, + {"DAModGain", >i.Field{Name: "DAModGain", Type: "float32", LocalType: "float32", Doc: "multiplicative factor on overall DA modulation specified by DAMod -- resulting overall gain factor is: 1 + DAModGain * DA, where DA is appropriate DA-driven factor", Directives: gti.Directives{}, Tag: "viewif:\"DAMod!=NoDAMod\""}}, + {"DALRateSign", >i.Field{Name: "DALRateSign", Type: "goki.dev/gosl/v2/slbool.Bool", LocalType: "slbool.Bool", Doc: "modulate the sign of the learning rate factor according to the DA sign, taking into account the DAMod sign reversal for D2Mod, also using BurstGain and DipGain to modulate DA value -- otherwise, only the magnitude of the learning rate is modulated as a function of raw DA magnitude according to DALRateMod (without additional gain factors)", Directives: gti.Directives{}, Tag: ""}}, + {"DALRateMod", >i.Field{Name: "DALRateMod", Type: "float32", LocalType: "float32", Doc: "if not using DALRateSign, this is the proportion of maximum learning rate that Abs(DA) magnitude can modulate -- e.g., if 0.2, then DA = 0 = 80% of std learning rate, 1 = 100%", Directives: gti.Directives{}, Tag: "min:\"0\" max:\"1\" viewif:\"!DALRateSign\""}}, + {"AChLRateMod", >i.Field{Name: "AChLRateMod", Type: "float32", LocalType: "float32", Doc: "proportion of maximum learning rate that ACh can modulate -- e.g., if 0.2, then ACh = 0 = 80% of std learning rate, 1 = 100%", Directives: gti.Directives{}, Tag: "min:\"0\" max:\"1\""}}, + {"AChDisInhib", >i.Field{Name: "AChDisInhib", Type: "float32", LocalType: "float32", Doc: "amount of extra Gi inhibition added in proportion to 1 - ACh level -- makes ACh disinhibitory", Directives: gti.Directives{}, Tag: "min:\"0\" def:\"0,5\""}}, + {"BurstGain", >i.Field{Name: "BurstGain", Type: "float32", LocalType: "float32", Doc: "multiplicative gain factor applied to positive dopamine signals -- this operates on the raw dopamine signal prior to any effect of D2 receptors in reversing its sign!", Directives: gti.Directives{}, Tag: "min:\"0\" def:\"1\""}}, + {"DipGain", >i.Field{Name: "DipGain", Type: "float32", LocalType: "float32", Doc: "multiplicative gain factor applied to negative dopamine signals -- this operates on the raw dopamine signal prior to any effect of D2 receptors in reversing its sign! should be small for acq, but roughly equal to burst for ext", Directives: gti.Directives{}, Tag: "min:\"0\" def:\"1\""}}, + {"pad", >i.Field{Name: "pad", Type: "float32", LocalType: "float32", Doc: "", Directives: gti.Directives{}, Tag: ""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.NeuronFlags", + ShortName: "axon.NeuronFlags", + IDName: "neuron-flags", + Doc: "NeuronFlags are bit-flags encoding relevant binary state for neurons", + Directives: gti.Directives{ + >i.Directive{Tool: "gosl", Directive: "start", Args: []string{"neuron"}}, + >i.Directive{Tool: "enums", Directive: "enum", Args: []string{}}, + }, + + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.NeuronVars", + ShortName: "axon.NeuronVars", + IDName: "neuron-vars", + Doc: "NeuronVars are the neuron variables representing current active state,\nspecific to each input data state.\nSee NeuronAvgVars for vars shared across data.", + Directives: gti.Directives{ + >i.Directive{Tool: "enums", Directive: "enum", Args: []string{}}, + }, + + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.NeuronAvgVars", + ShortName: "axon.NeuronAvgVars", + IDName: "neuron-avg-vars", + Doc: "NeuronAvgVars are mostly neuron variables involved in longer-term average activity\nwhich is aggregated over time and not specific to each input data state,\nalong with any other state that is not input data specific.", + Directives: gti.Directives{ + >i.Directive{Tool: "enums", Directive: "enum", Args: []string{}}, + }, + + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.NeuronIdxs", + ShortName: "axon.NeuronIdxs", + IDName: "neuron-idxs", + Doc: "NeuronIdxs are the neuron indexes and other uint32 values.\nThere is only one of these per neuron -- not data parallel.\nnote: Flags are encoded in Vars because they are data parallel and\nwritable, whereas indexes are read-only.", + Directives: gti.Directives{ + >i.Directive{Tool: "enums", Directive: "enum", Args: []string{}}, + }, + + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.NeuronVarStrides", + ShortName: "axon.NeuronVarStrides", + IDName: "neuron-var-strides", + Doc: "NeuronVarStrides encodes the stride offsets for neuron variable access\ninto network float32 array. Data is always the inner-most variable.", + Directives: gti.Directives{ + >i.Directive{Tool: "gosl", Directive: "end", Args: []string{"neuron"}}, + >i.Directive{Tool: "gosl", Directive: "hlsl", Args: []string{"neuron"}}, + >i.Directive{Tool: "gosl", Directive: "end", Args: []string{"neuron"}}, + >i.Directive{Tool: "gosl", Directive: "start", Args: []string{"neuron"}}, + }, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"Neuron", >i.Field{Name: "Neuron", Type: "uint32", LocalType: "uint32", Doc: "neuron level", Directives: gti.Directives{}, Tag: ""}}, + {"Var", >i.Field{Name: "Var", Type: "uint32", LocalType: "uint32", Doc: "variable level", Directives: gti.Directives{}, Tag: ""}}, + {"pad", >i.Field{Name: "pad", Type: "uint32", LocalType: "uint32", Doc: "", Directives: gti.Directives{}, Tag: ""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.NeuronAvgVarStrides", + ShortName: "axon.NeuronAvgVarStrides", + IDName: "neuron-avg-var-strides", + Doc: "NeuronAvgVarStrides encodes the stride offsets for neuron variable access\ninto network float32 array. Data is always the inner-most variable.", + Directives: gti.Directives{}, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"Neuron", >i.Field{Name: "Neuron", Type: "uint32", LocalType: "uint32", Doc: "neuron level", Directives: gti.Directives{}, Tag: ""}}, + {"Var", >i.Field{Name: "Var", Type: "uint32", LocalType: "uint32", Doc: "variable level", Directives: gti.Directives{}, Tag: ""}}, + {"pad", >i.Field{Name: "pad", Type: "uint32", LocalType: "uint32", Doc: "", Directives: gti.Directives{}, Tag: ""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.NeuronIdxStrides", + ShortName: "axon.NeuronIdxStrides", + IDName: "neuron-idx-strides", + Doc: "NeuronIdxStrides encodes the stride offsets for neuron index access\ninto network uint32 array.", + Directives: gti.Directives{}, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"Neuron", >i.Field{Name: "Neuron", Type: "uint32", LocalType: "uint32", Doc: "neuron level", Directives: gti.Directives{}, Tag: ""}}, + {"Index", >i.Field{Name: "Index", Type: "uint32", LocalType: "uint32", Doc: "index value level", Directives: gti.Directives{}, Tag: ""}}, + {"pad", >i.Field{Name: "pad", Type: "uint32", LocalType: "uint32", Doc: "", Directives: gti.Directives{}, Tag: ""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.MatrixParams", + ShortName: "axon.MatrixParams", + IDName: "matrix-params", + Doc: "MatrixParams has parameters for BG Striatum Matrix MSN layers\nThese are the main Go / NoGo gating units in BG.\nDA, ACh learning rate modulation is pre-computed on the recv neuron\nRLRate variable via NeuroMod. Also uses Pool.Gated for InvertNoGate,\nupdated in PlusPhase prior to DWt call.\nMust set Learn.NeuroMod.DAMod = D1Mod or D2Mod via SetBuildConfig(\"DAMod\").", + Directives: gti.Directives{ + >i.Directive{Tool: "gosl", Directive: "start", Args: []string{"pcore_layers"}}, + }, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"GateThr", >i.Field{Name: "GateThr", Type: "float32", LocalType: "float32", Doc: "threshold on layer Avg SpkMax for Matrix Go and VThal layers to count as having gated", Directives: gti.Directives{}, Tag: "def:\"0.05\""}}, + {"IsVS", >i.Field{Name: "IsVS", Type: "goki.dev/gosl/v2/slbool.Bool", LocalType: "slbool.Bool", Doc: "is this a ventral striatum (VS) matrix layer? if true, the gating status of this layer is recorded in the Global state, and used for updating effort and other factors.", Directives: gti.Directives{}, Tag: ""}}, + {"OtherMatrixIdx", >i.Field{Name: "OtherMatrixIdx", Type: "int32", LocalType: "int32", Doc: "index of other matrix (Go if we are NoGo and vice-versa). Set during Build from BuildConfig OtherMatrixName", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + {"ThalLay1Idx", >i.Field{Name: "ThalLay1Idx", Type: "int32", LocalType: "int32", Doc: "index of thalamus layer that we gate. needed to get gating information. Set during Build from BuildConfig ThalLay1Name if present -- -1 if not used", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + {"ThalLay2Idx", >i.Field{Name: "ThalLay2Idx", Type: "int32", LocalType: "int32", Doc: "index of thalamus layer that we gate. needed to get gating information. Set during Build from BuildConfig ThalLay2Name if present -- -1 if not used", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + {"ThalLay3Idx", >i.Field{Name: "ThalLay3Idx", Type: "int32", LocalType: "int32", Doc: "index of thalamus layer that we gate. needed to get gating information. Set during Build from BuildConfig ThalLay3Name if present -- -1 if not used", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + {"ThalLay4Idx", >i.Field{Name: "ThalLay4Idx", Type: "int32", LocalType: "int32", Doc: "index of thalamus layer that we gate. needed to get gating information. Set during Build from BuildConfig ThalLay4Name if present -- -1 if not used", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + {"ThalLay5Idx", >i.Field{Name: "ThalLay5Idx", Type: "int32", LocalType: "int32", Doc: "index of thalamus layer that we gate. needed to get gating information. Set during Build from BuildConfig ThalLay5Name if present -- -1 if not used", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + {"ThalLay6Idx", >i.Field{Name: "ThalLay6Idx", Type: "int32", LocalType: "int32", Doc: "index of thalamus layer that we gate. needed to get gating information. Set during Build from BuildConfig ThalLay6Name if present -- -1 if not used", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + {"pad", >i.Field{Name: "pad", Type: "int32", LocalType: "int32", Doc: "", Directives: gti.Directives{}, Tag: ""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.GPLayerTypes", + ShortName: "axon.GPLayerTypes", + IDName: "gp-layer-types", + Doc: "GPLayerTypes is a GPLayer axon-specific layer type enum.", + Directives: gti.Directives{ + >i.Directive{Tool: "enums", Directive: "enum", Args: []string{}}, + }, + + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.GPParams", + ShortName: "axon.GPParams", + IDName: "gp-params", + Doc: "GPLayer represents a globus pallidus layer, including:\nGPeOut, GPeIn, GPeTA (arkypallidal), and GPi (see GPType for type).\nTypically just a single unit per Pool representing a given stripe.", + Directives: gti.Directives{}, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"GPType", >i.Field{Name: "GPType", Type: "github.com/emer/axon/axon.GPLayerTypes", LocalType: "GPLayerTypes", Doc: "type of GP Layer -- must set during config using SetBuildConfig of GPType.", Directives: gti.Directives{}, Tag: "viewif:\"LayType=GPLayer\" view:\"inline\""}}, + {"pad", >i.Field{Name: "pad", Type: "uint32", LocalType: "uint32", Doc: "", Directives: gti.Directives{}, Tag: ""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.MatrixPrjnParams", + ShortName: "axon.MatrixPrjnParams", + IDName: "matrix-prjn-params", + Doc: "MatrixPrjnParams for trace-based learning in the MatrixPrjn.\nA trace of synaptic co-activity is formed, and then modulated by dopamine\nwhenever it occurs. This bridges the temporal gap between gating activity\nand subsequent activity, and is based biologically on synaptic tags.\nTrace is applied to DWt and reset at the time of reward.", + Directives: gti.Directives{ + >i.Directive{Tool: "gosl", Directive: "start", Args: []string{"pcore_prjns"}}, + }, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"NoGateLRate", >i.Field{Name: "NoGateLRate", Type: "float32", LocalType: "float32", Doc: "learning rate for when ACh was elevated but no gating took place, in proportion to the level of ACh that indicates the salience of the event. A low level of this learning prevents the highly maladaptive situation where the BG is not gating and thus no learning can occur.", Directives: gti.Directives{}, Tag: "def:\"1\""}}, + {"pad", >i.Field{Name: "pad", Type: "float32", LocalType: "float32", Doc: "", Directives: gti.Directives{}, Tag: ""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.AvgMaxPhases", + ShortName: "axon.AvgMaxPhases", + IDName: "avg-max-phases", + Doc: "AvgMaxPhases contains the average and maximum values over a Pool of neurons,\nat different time scales within a standard ThetaCycle of updating.\nIt is much more efficient on the GPU to just grab everything in one pass at\nthe cycle level, and then take snapshots from there.\nAll of the cycle level values are updated at the *start* of the cycle\nbased on values from the prior cycle -- thus are 1 cycle behind in general.", + Directives: gti.Directives{ + >i.Directive{Tool: "gosl", Directive: "hlsl", Args: []string{"pool"}}, + >i.Directive{Tool: "gosl", Directive: "end", Args: []string{"pool"}}, + >i.Directive{Tool: "gosl", Directive: "start", Args: []string{"pool"}}, + }, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"Cycle", >i.Field{Name: "Cycle", Type: "github.com/emer/axon/axon.AvgMaxI32", LocalType: "AvgMaxI32", Doc: "updated every cycle -- this is the source of all subsequent time scales", Directives: gti.Directives{}, Tag: "view:\"inline\""}}, + {"Minus", >i.Field{Name: "Minus", Type: "github.com/emer/axon/axon.AvgMaxI32", LocalType: "AvgMaxI32", Doc: "at the end of the minus phase", Directives: gti.Directives{}, Tag: "view:\"inline\""}}, + {"Plus", >i.Field{Name: "Plus", Type: "github.com/emer/axon/axon.AvgMaxI32", LocalType: "AvgMaxI32", Doc: "at the end of the plus phase", Directives: gti.Directives{}, Tag: "view:\"inline\""}}, + {"Prev", >i.Field{Name: "Prev", Type: "github.com/emer/axon/axon.AvgMaxI32", LocalType: "AvgMaxI32", Doc: "at the end of the previous plus phase", Directives: gti.Directives{}, Tag: "view:\"inline\""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.PoolAvgMax", + ShortName: "axon.PoolAvgMax", + IDName: "pool-avg-max", + Doc: "PoolAvgMax contains the average and maximum values over a Pool of neurons\nfor different variables of interest, at Cycle, Minus and Plus phase timescales.\nAll of the cycle level values are updated at the *start* of the cycle\nbased on values from the prior cycle -- thus are 1 cycle behind in general.", + Directives: gti.Directives{}, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"CaSpkP", >i.Field{Name: "CaSpkP", Type: "github.com/emer/axon/axon.AvgMaxPhases", LocalType: "AvgMaxPhases", Doc: "avg and maximum CaSpkP (continuously updated at roughly 40 msec integration window timescale, ends up capturing potentiation, plus-phase signal) -- this is the primary variable to use for tracking overall pool activity", Directives: gti.Directives{}, Tag: "inactive:\"+\" view:\"inline\""}}, + {"CaSpkD", >i.Field{Name: "CaSpkD", Type: "github.com/emer/axon/axon.AvgMaxPhases", LocalType: "AvgMaxPhases", Doc: "avg and maximum CaSpkD longer-term depression / DAPK1 signal in layer", Directives: gti.Directives{}, Tag: "inactive:\"+\" view:\"inline\""}}, + {"SpkMax", >i.Field{Name: "SpkMax", Type: "github.com/emer/axon/axon.AvgMaxPhases", LocalType: "AvgMaxPhases", Doc: "avg and maximum SpkMax value (based on CaSpkP) -- reflects peak activity at any point across the cycle", Directives: gti.Directives{}, Tag: "inactive:\"+\" view:\"inline\""}}, + {"Act", >i.Field{Name: "Act", Type: "github.com/emer/axon/axon.AvgMaxPhases", LocalType: "AvgMaxPhases", Doc: "avg and maximum Act firing rate value", Directives: gti.Directives{}, Tag: "inactive:\"+\" view:\"inline\""}}, + {"GeInt", >i.Field{Name: "GeInt", Type: "github.com/emer/axon/axon.AvgMaxPhases", LocalType: "AvgMaxPhases", Doc: "avg and maximum GeInt integrated running-average excitatory conductance value", Directives: gti.Directives{}, Tag: "inactive:\"+\" view:\"inline\""}}, + {"GiInt", >i.Field{Name: "GiInt", Type: "github.com/emer/axon/axon.AvgMaxPhases", LocalType: "AvgMaxPhases", Doc: "avg and maximum GiInt integrated running-average inhibitory conductance value", Directives: gti.Directives{}, Tag: "inactive:\"+\" view:\"inline\""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.Pool", + ShortName: "axon.Pool", + IDName: "pool", + Doc: "Pool contains computed values for FS-FFFB inhibition,\nand various other state values for layers\nand pools (unit groups) that can be subject to inhibition", + Directives: gti.Directives{ + >i.Directive{Tool: "gosl", Directive: "end", Args: []string{"pool"}}, + >i.Directive{Tool: "gosl", Directive: "hlsl", Args: []string{"pool"}}, + >i.Directive{Tool: "gosl", Directive: "end", Args: []string{"pool"}}, + >i.Directive{Tool: "gosl", Directive: "start", Args: []string{"pool"}}, + }, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"StIdx", >i.Field{Name: "StIdx", Type: "uint32", LocalType: "uint32", Doc: "starting and ending (exlusive) layer-wise indexes for the list of neurons in this pool", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + {"LayIdx", >i.Field{Name: "LayIdx", Type: "uint32", LocalType: "uint32", Doc: "layer index in global layer list", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + {"DataIdx", >i.Field{Name: "DataIdx", Type: "uint32", LocalType: "uint32", Doc: "data parallel index (innermost index per layer)", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + {"PoolIdx", >i.Field{Name: "PoolIdx", Type: "uint32", LocalType: "uint32", Doc: "pool index in global pool list:", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + {"IsLayPool", >i.Field{Name: "IsLayPool", Type: "goki.dev/gosl/v2/slbool.Bool", LocalType: "slbool.Bool", Doc: "is this a layer-wide pool? if not, it represents a sub-pool of units within a 4D layer", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + {"Gated", >i.Field{Name: "Gated", Type: "goki.dev/gosl/v2/slbool.Bool", LocalType: "slbool.Bool", Doc: "for special types where relevant (e.g., MatrixLayer, BGThalLayer), indicates if the pool was gated", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + {"pad", >i.Field{Name: "pad", Type: "uint32", LocalType: "uint32", Doc: "", Directives: gti.Directives{}, Tag: ""}}, + {"Inhib", >i.Field{Name: "Inhib", Type: "github.com/emer/axon/fsfffb.Inhib", LocalType: "fsfffb.Inhib", Doc: "fast-slow FFFB inhibition values", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + {"AvgMax", >i.Field{Name: "AvgMax", Type: "github.com/emer/axon/axon.PoolAvgMax", LocalType: "PoolAvgMax", Doc: "average and max values for relevant variables in this pool, at different time scales", Directives: gti.Directives{}, Tag: ""}}, + {"AvgDif", >i.Field{Name: "AvgDif", Type: "github.com/emer/axon/axon.AvgMaxI32", LocalType: "AvgMaxI32", Doc: "absolute value of AvgDif differences from actual neuron ActPct relative to TrgAvg", Directives: gti.Directives{}, Tag: "inactive:\"+\" view:\"inline\""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.Prjn", + ShortName: "axon.Prjn", + IDName: "prjn", + Doc: "axon.Prjn is a basic Axon projection with synaptic learning parameters", + Directives: gti.Directives{}, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"Params", >i.Field{Name: "Params", Type: "*github.com/emer/axon/axon.PrjnParams", LocalType: "*PrjnParams", Doc: "all prjn-level parameters -- these must remain constant once configured", Directives: gti.Directives{}, Tag: ""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"PrjnBase", >i.Field{Name: "PrjnBase", Type: "github.com/emer/axon/axon.PrjnBase", LocalType: "PrjnBase", Doc: "", Directives: gti.Directives{}, Tag: ""}}, + }), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.PrjnBase", + ShortName: "axon.PrjnBase", + IDName: "prjn-base", + Doc: "PrjnBase contains the basic structural information for specifying a projection of synaptic\nconnections between two layers, and maintaining all the synaptic connection-level data.\nThe same struct token is added to the Recv and Send layer prjn lists, and it manages everything\nabout the connectivity, and methods on the Prjn handle all the relevant computation.\nThe Base does not have algorithm-specific methods and parameters, so it can be easily\nreused for different algorithms, and cleanly separates the algorithm-specific code.\nAny dependency on the algorithm-level Prjn can be captured in the AxonPrjn interface,\naccessed via the AxonPrj field.", + Directives: gti.Directives{}, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"AxonPrj", >i.Field{Name: "AxonPrj", Type: "github.com/emer/axon/axon.AxonPrjn", LocalType: "AxonPrjn", Doc: "we need a pointer to ourselves as an AxonPrjn, which can always be used to extract the true underlying type of object when prjn is embedded in other structs -- function receivers do not have this ability so this is necessary.", Directives: gti.Directives{}, Tag: "copy:\"-\" json:\"-\" xml:\"-\" view:\"-\""}}, + {"Off", >i.Field{Name: "Off", Type: "bool", LocalType: "bool", Doc: "inactivate this projection -- allows for easy experimentation", Directives: gti.Directives{}, Tag: ""}}, + {"Cls", >i.Field{Name: "Cls", Type: "string", LocalType: "string", Doc: "Class is for applying parameter styles, can be space separated multple tags", Directives: gti.Directives{}, Tag: ""}}, + {"Notes", >i.Field{Name: "Notes", Type: "string", LocalType: "string", Doc: "can record notes about this projection here", Directives: gti.Directives{}, Tag: ""}}, + {"Send", >i.Field{Name: "Send", Type: "*github.com/emer/axon/axon.Layer", LocalType: "*Layer", Doc: "sending layer for this projection", Directives: gti.Directives{}, Tag: ""}}, + {"Recv", >i.Field{Name: "Recv", Type: "*github.com/emer/axon/axon.Layer", LocalType: "*Layer", Doc: "receiving layer for this projection", Directives: gti.Directives{}, Tag: ""}}, + {"Pat", >i.Field{Name: "Pat", Type: "github.com/emer/emergent/v2/prjn.Pattern", LocalType: "prjn.Pattern", Doc: "pattern of connectivity", Directives: gti.Directives{}, Tag: "tableview:\"-\""}}, + {"Typ", >i.Field{Name: "Typ", Type: "github.com/emer/axon/axon.PrjnTypes", LocalType: "PrjnTypes", Doc: "type of projection -- Forward, Back, Lateral, or extended type in specialized algorithms -- matches against .Cls parameter styles (e.g., .Back etc)", Directives: gti.Directives{}, Tag: ""}}, + {"DefParams", >i.Field{Name: "DefParams", Type: "github.com/emer/emergent/v2/params.Params", LocalType: "params.Params", Doc: "default parameters that are applied prior to user-set parameters -- these are useful for specific functionality in specialized brain areas (e.g., PVLV, BG etc) not associated with a prjn type, which otherwise is used to hard-code initial default parameters -- typically just set to a literal map.", Directives: gti.Directives{}, Tag: "tableview:\"-\""}}, + {"ParamsHistory", >i.Field{Name: "ParamsHistory", Type: "github.com/emer/emergent/v2/params.HistoryImpl", LocalType: "params.HistoryImpl", Doc: "provides a history of parameters applied to the layer", Directives: gti.Directives{}, Tag: "tableview:\"-\""}}, + {"RecvConNAvgMax", >i.Field{Name: "RecvConNAvgMax", Type: "goki.dev/etable/v2/minmax.AvgMax32", LocalType: "minmax.AvgMax32", Doc: "average and maximum number of recv connections in the receiving layer", Directives: gti.Directives{}, Tag: "tableview:\"-\" inactive:\"+\" view:\"inline\""}}, + {"SendConNAvgMax", >i.Field{Name: "SendConNAvgMax", Type: "goki.dev/etable/v2/minmax.AvgMax32", LocalType: "minmax.AvgMax32", Doc: "average and maximum number of sending connections in the sending layer", Directives: gti.Directives{}, Tag: "tableview:\"-\" inactive:\"+\" view:\"inline\""}}, + {"SynStIdx", >i.Field{Name: "SynStIdx", Type: "uint32", LocalType: "uint32", Doc: "start index into global Synapse array:", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + {"NSyns", >i.Field{Name: "NSyns", Type: "uint32", LocalType: "uint32", Doc: "number of synapses in this projection", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + {"RecvCon", >i.Field{Name: "RecvCon", Type: "[]github.com/emer/axon/axon.StartN", LocalType: "[]StartN", Doc: "starting offset and N cons for each recv neuron, for indexing into the RecvSynIdx array of indexes into the Syns synapses, which are organized sender-based. This is locally-managed during build process, but also copied to network global PrjnRecvCons slice for GPU usage.", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + {"RecvSynIdx", >i.Field{Name: "RecvSynIdx", Type: "[]uint32", LocalType: "[]uint32", Doc: "index into Syns synaptic state for each sending unit and connection within that, for the sending projection which does not own the synapses, and instead indexes into recv-ordered list", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + {"RecvConIdx", >i.Field{Name: "RecvConIdx", Type: "[]uint32", LocalType: "[]uint32", Doc: "for each recv synapse, this is index of *sending* neuron It is generally preferable to use the Synapse SendIdx where needed, instead of this slice, because then the memory access will be close by other values on the synapse.", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + {"SendCon", >i.Field{Name: "SendCon", Type: "[]github.com/emer/axon/axon.StartN", LocalType: "[]StartN", Doc: "starting offset and N cons for each sending neuron, for indexing into the Syns synapses, which are organized sender-based. This is locally-managed during build process, but also copied to network global PrjnSendCons slice for GPU usage.", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + {"SendConIdx", >i.Field{Name: "SendConIdx", Type: "[]uint32", LocalType: "[]uint32", Doc: "index of other neuron that receives the sender's synaptic input, ordered by the sending layer's order of units as the outer loop, and SendCon.N receiving units within that. It is generally preferable to use the Synapse RecvIdx where needed, instead of this slice, because then the memory access will be close by other values on the synapse.", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + {"GBuf", >i.Field{Name: "GBuf", Type: "[]int32", LocalType: "[]int32", Doc: "Ge or Gi conductance ring buffer for each neuron, accessed through Params.Com.ReadIdx, WriteIdx -- scale * weight is added with Com delay offset -- a subslice from network PrjnGBuf. Uses int-encoded float values for faster GPU atomic integration", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + {"GSyns", >i.Field{Name: "GSyns", Type: "[]float32", LocalType: "[]float32", Doc: "projection-level synaptic conductance values, integrated by prjn before being integrated at the neuron level, which enables the neuron to perform non-linear integration as needed -- a subslice from network PrjnGSyn.", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.StartN", + ShortName: "axon.StartN", + IDName: "start-n", + Doc: "StartN holds a starting offset index and a number of items\narranged from Start to Start+N (exclusive).\nThis is not 16 byte padded and only for use on CPU side.", + Directives: gti.Directives{ + >i.Directive{Tool: "gosl", Directive: "hlsl", Args: []string{"prjnparams"}}, + >i.Directive{Tool: "gosl", Directive: "end", Args: []string{"prjnparams"}}, + >i.Directive{Tool: "gosl", Directive: "start", Args: []string{"prjnparams"}}, + }, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"Start", >i.Field{Name: "Start", Type: "uint32", LocalType: "uint32", Doc: "starting offset", Directives: gti.Directives{}, Tag: ""}}, + {"N", >i.Field{Name: "N", Type: "uint32", LocalType: "uint32", Doc: "number of items --", Directives: gti.Directives{}, Tag: ""}}, + {"pad", >i.Field{Name: "pad", Type: "uint32", LocalType: "uint32", Doc: "", Directives: gti.Directives{}, Tag: ""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.PrjnIdxs", + ShortName: "axon.PrjnIdxs", + IDName: "prjn-idxs", + Doc: "PrjnIdxs contains prjn-level index information into global memory arrays", + Directives: gti.Directives{}, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"PrjnIdx", >i.Field{Name: "PrjnIdx", Type: "uint32", LocalType: "uint32", Doc: "", Directives: gti.Directives{}, Tag: ""}}, + {"RecvLay", >i.Field{Name: "RecvLay", Type: "uint32", LocalType: "uint32", Doc: "", Directives: gti.Directives{}, Tag: ""}}, + {"RecvNeurSt", >i.Field{Name: "RecvNeurSt", Type: "uint32", LocalType: "uint32", Doc: "", Directives: gti.Directives{}, Tag: ""}}, + {"RecvNeurN", >i.Field{Name: "RecvNeurN", Type: "uint32", LocalType: "uint32", Doc: "", Directives: gti.Directives{}, Tag: ""}}, + {"SendLay", >i.Field{Name: "SendLay", Type: "uint32", LocalType: "uint32", Doc: "", Directives: gti.Directives{}, Tag: ""}}, + {"SendNeurSt", >i.Field{Name: "SendNeurSt", Type: "uint32", LocalType: "uint32", Doc: "", Directives: gti.Directives{}, Tag: ""}}, + {"SendNeurN", >i.Field{Name: "SendNeurN", Type: "uint32", LocalType: "uint32", Doc: "", Directives: gti.Directives{}, Tag: ""}}, + {"SynapseSt", >i.Field{Name: "SynapseSt", Type: "uint32", LocalType: "uint32", Doc: "", Directives: gti.Directives{}, Tag: ""}}, + {"SendConSt", >i.Field{Name: "SendConSt", Type: "uint32", LocalType: "uint32", Doc: "", Directives: gti.Directives{}, Tag: ""}}, + {"RecvConSt", >i.Field{Name: "RecvConSt", Type: "uint32", LocalType: "uint32", Doc: "", Directives: gti.Directives{}, Tag: ""}}, + {"RecvSynSt", >i.Field{Name: "RecvSynSt", Type: "uint32", LocalType: "uint32", Doc: "", Directives: gti.Directives{}, Tag: ""}}, + {"GBufSt", >i.Field{Name: "GBufSt", Type: "uint32", LocalType: "uint32", Doc: "", Directives: gti.Directives{}, Tag: ""}}, + {"GSynSt", >i.Field{Name: "GSynSt", Type: "uint32", LocalType: "uint32", Doc: "", Directives: gti.Directives{}, Tag: ""}}, + {"pad", >i.Field{Name: "pad", Type: "uint32", LocalType: "uint32", Doc: "", Directives: gti.Directives{}, Tag: ""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.GScaleVals", + ShortName: "axon.GScaleVals", + IDName: "g-scale-vals", + Doc: "GScaleVals holds the conductance scaling values.\nThese are computed once at start and remain constant thereafter,\nand therefore belong on Params and not on PrjnVals.", + Directives: gti.Directives{}, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"Scale", >i.Field{Name: "Scale", Type: "float32", LocalType: "float32", Doc: "scaling factor for integrating synaptic input conductances (G's), originally computed as a function of sending layer activity and number of connections, and typically adapted from there -- see Prjn.PrjnScale adapt params", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + {"Rel", >i.Field{Name: "Rel", Type: "float32", LocalType: "float32", Doc: "normalized relative proportion of total receiving conductance for this projection: PrjnScale.Rel / sum(PrjnScale.Rel across relevant prjns)", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + {"pad", >i.Field{Name: "pad", Type: "float32", LocalType: "float32", Doc: "", Directives: gti.Directives{}, Tag: ""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.PrjnParams", + ShortName: "axon.PrjnParams", + IDName: "prjn-params", + Doc: "PrjnParams contains all of the prjn parameters.\nThese values must remain constant over the course of computation.\nOn the GPU, they are loaded into a uniform.", + Directives: gti.Directives{}, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"PrjnType", >i.Field{Name: "PrjnType", Type: "github.com/emer/axon/axon.PrjnTypes", LocalType: "PrjnTypes", Doc: "functional type of prjn -- determines functional code path for specialized layer types, and is synchronized with the Prjn.Typ value", Directives: gti.Directives{}, Tag: ""}}, + {"pad", >i.Field{Name: "pad", Type: "int32", LocalType: "int32", Doc: "", Directives: gti.Directives{}, Tag: ""}}, + {"Idxs", >i.Field{Name: "Idxs", Type: "github.com/emer/axon/axon.PrjnIdxs", LocalType: "PrjnIdxs", Doc: "recv and send neuron-level projection index array access info", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + {"Com", >i.Field{Name: "Com", Type: "github.com/emer/axon/axon.SynComParams", LocalType: "SynComParams", Doc: "synaptic communication parameters: delay, probability of failure", Directives: gti.Directives{}, Tag: "view:\"inline\""}}, + {"PrjnScale", >i.Field{Name: "PrjnScale", Type: "github.com/emer/axon/axon.PrjnScaleParams", LocalType: "PrjnScaleParams", Doc: "projection scaling parameters for computing GScale: modulates overall strength of projection, using both absolute and relative factors, with adaptation option to maintain target max conductances", Directives: gti.Directives{}, Tag: "view:\"inline\""}}, + {"SWts", >i.Field{Name: "SWts", Type: "github.com/emer/axon/axon.SWtParams", LocalType: "SWtParams", Doc: "slowly adapting, structural weight value parameters, which control initial weight values and slower outer-loop adjustments", Directives: gti.Directives{}, Tag: "view:\"add-fields\""}}, + {"Learn", >i.Field{Name: "Learn", Type: "github.com/emer/axon/axon.LearnSynParams", LocalType: "LearnSynParams", Doc: "synaptic-level learning parameters for learning in the fast LWt values.", Directives: gti.Directives{}, Tag: "view:\"add-fields\""}}, + {"GScale", >i.Field{Name: "GScale", Type: "github.com/emer/axon/axon.GScaleVals", LocalType: "GScaleVals", Doc: "conductance scaling values", Directives: gti.Directives{}, Tag: "view:\"inline\""}}, + {"RLPred", >i.Field{Name: "RLPred", Type: "github.com/emer/axon/axon.RLPredPrjnParams", LocalType: "RLPredPrjnParams", Doc: "] Params for RWPrjn and TDPredPrjn for doing dopamine-modulated learning for reward prediction: Da * Send activity. Use in RWPredLayer or TDPredLayer typically to generate reward predictions. If the Da sign is positive, the first recv unit learns fully; for negative, second one learns fully. Lower lrate applies for opposite cases. Weights are positive-only.", Directives: gti.Directives{}, Tag: "viewif:\"PrjnType=[RWPrjn,TDPredPrjn]\" view:\"inline\""}}, + {"Matrix", >i.Field{Name: "Matrix", Type: "github.com/emer/axon/axon.MatrixPrjnParams", LocalType: "MatrixPrjnParams", Doc: "for trace-based learning in the MatrixPrjn. A trace of synaptic co-activity is formed, and then modulated by dopamine whenever it occurs. This bridges the temporal gap between gating activity and subsequent activity, and is based biologically on synaptic tags. Trace is reset at time of reward based on ACh level from CINs.", Directives: gti.Directives{}, Tag: "viewif:\"PrjnType=MatrixPrjn\" view:\"inline\""}}, + {"BLA", >i.Field{Name: "BLA", Type: "github.com/emer/axon/axon.BLAPrjnParams", LocalType: "BLAPrjnParams", Doc: "Basolateral Amygdala projection parameters.", Directives: gti.Directives{}, Tag: "viewif:\"PrjnType=BLAPrjn\" view:\"inline\""}}, + {"Hip", >i.Field{Name: "Hip", Type: "github.com/emer/axon/axon.HipPrjnParams", LocalType: "HipPrjnParams", Doc: "Hip bench parameters.", Directives: gti.Directives{}, Tag: "viewif:\"PrjnType=HipPrjn\" view:\"inline\""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.PrjnTypes", + ShortName: "axon.PrjnTypes", + IDName: "prjn-types", + Doc: "PrjnTypes is an axon-specific prjn type enum,\nthat encompasses all the different algorithm types supported.\nClass parameter styles automatically key off of these types.\nThe first entries must be kept synchronized with the emer.PrjnType.", + Directives: gti.Directives{ + >i.Directive{Tool: "gosl", Directive: "start", Args: []string{"prjntypes"}}, + >i.Directive{Tool: "enums", Directive: "enum", Args: []string{}}, + }, + + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.DriveParams", + ShortName: "axon.DriveParams", + IDName: "drive-params", + Doc: "DriveParams manages the drive parameters for computing and updating drive state.\nMost of the params are for optional case where drives are automatically\nupdated based on US consumption (which satisfies drives) and time passing\n(which increases drives).", + Directives: gti.Directives{}, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"DriveMin", >i.Field{Name: "DriveMin", Type: "float32", LocalType: "float32", Doc: "minimum effective drive value -- this is an automatic baseline ensuring that a positive US results in at least some minimal level of reward. Unlike Base values, this is not reflected in the activity of the drive values -- applies at the time of reward calculation as a minimum baseline.", Directives: gti.Directives{}, Tag: ""}}, + {"Base", >i.Field{Name: "Base", Type: "[]float32", LocalType: "[]float32", Doc: "baseline levels for each drive -- what they naturally trend toward in the absence of any input. Set inactive drives to 0 baseline, active ones typically elevated baseline (0-1 range).", Directives: gti.Directives{}, Tag: ""}}, + {"Tau", >i.Field{Name: "Tau", Type: "[]float32", LocalType: "[]float32", Doc: "time constants in ThetaCycle (trial) units for natural update toward Base values -- 0 values means no natural update.", Directives: gti.Directives{}, Tag: ""}}, + {"Satisfaction", >i.Field{Name: "Satisfaction", Type: "[]float32", LocalType: "[]float32", Doc: "decrement in drive value when US is consumed, thus partially satisfying the drive -- positive values are subtracted from current Drive value.", Directives: gti.Directives{}, Tag: ""}}, + {"Dt", >i.Field{Name: "Dt", Type: "[]float32", LocalType: "[]float32", Doc: "1/Tau", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.UrgencyParams", + ShortName: "axon.UrgencyParams", + IDName: "urgency-params", + Doc: "UrgencyParams has urgency (increasing pressure to do something)\nand parameters for updating it.\nRaw urgency integrates effort when _not_ goal engaged\nwhile effort (negative US 0) integrates when a goal _is_ engaged.", + Directives: gti.Directives{}, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"U50", >i.Field{Name: "U50", Type: "float32", LocalType: "float32", Doc: "value of raw urgency where the urgency activation level is 50%", Directives: gti.Directives{}, Tag: ""}}, + {"Power", >i.Field{Name: "Power", Type: "int32", LocalType: "int32", Doc: "exponent on the urge factor -- valid numbers are 1,2,4,6", Directives: gti.Directives{}, Tag: "def:\"4\""}}, + {"Thr", >i.Field{Name: "Thr", Type: "float32", LocalType: "float32", Doc: "threshold for urge -- cuts off small baseline values", Directives: gti.Directives{}, Tag: "def:\"0.2\""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.USParams", + ShortName: "axon.USParams", + IDName: "us-params", + Doc: "USParams control how positive and negative USs are\nweighted and integrated to compute an overall PV primary value.", + Directives: gti.Directives{}, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"NegUSOutcomeThr", >i.Field{Name: "NegUSOutcomeThr", Type: "float32", LocalType: "float32", Doc: "threshold for a negative US increment, _after_ multiplying by the USnegGains factor for that US (to allow for normalized input magnitudes that may translate into different magnitude of effects), to drive a phasic ACh response and associated VSMatrix gating and dopamine firing -- i.e., a full negative US outcome event (global NegUSOutcome flag is set)", Directives: gti.Directives{}, Tag: "def:\"0.5\""}}, + {"PVposGain", >i.Field{Name: "PVposGain", Type: "float32", LocalType: "float32", Doc: "gain factor applied to sum of weighted, drive-scaled positive USs to compute PVpos primary value summary -- multiplied prior to 1/(1+x) normalization. Use this to adjust the overall scaling of PVpos reward within 0-1 normalized range (see also PVnegGain). Each USpos is assumed to be in 0-1 range, default 1.", Directives: gti.Directives{}, Tag: "def:\"2\""}}, + {"PVnegGain", >i.Field{Name: "PVnegGain", Type: "float32", LocalType: "float32", Doc: "gain factor applied to sum of weighted negative USs to compute PVneg primary value summary -- multiplied prior to 1/(1+x) normalization. Use this to adjust overall scaling of PVneg within 0-1 normalized range (see also PVposGain).", Directives: gti.Directives{}, Tag: "def:\"1\""}}, + {"USnegGains", >i.Field{Name: "USnegGains", Type: "[]float32", LocalType: "[]float32", Doc: "gain factor for each individual negative US, multiplied prior to 1/(1+x) normalization of each term for activating the OFCnegUS pools. These gains are _not_ applied in computing summary PVneg value (see PVnegWts), and generally must be larger than the weights to leverage the dynamic range within each US pool.", Directives: gti.Directives{}, Tag: ""}}, + {"PVposWts", >i.Field{Name: "PVposWts", Type: "[]float32", LocalType: "[]float32", Doc: "weight factor applied to each separate positive US on the way to computing the overall PVpos summary value, to control the weighting of each US relative to the others. Each pos US is also multiplied by its dynamic Drive factor as well. Use PVposGain to control the overall scaling of the PVpos value.", Directives: gti.Directives{}, Tag: ""}}, + {"PVnegWts", >i.Field{Name: "PVnegWts", Type: "[]float32", LocalType: "[]float32", Doc: "weight factor applied to each separate negative US on the way to computing the overall PVneg summary value, to control the weighting of each US relative to the others. The first pool is Time, second is Effort, and these are typically weighted lower (.02) than salient simulation-specific USs (1).", Directives: gti.Directives{}, Tag: ""}}, + {"USposEst", >i.Field{Name: "USposEst", Type: "[]float32", LocalType: "[]float32", Doc: "computed estimated US values, based on OFCposUSPT and VSMatrix gating, in PVposEst", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.LHbParams", + ShortName: "axon.LHbParams", + IDName: "l-hb-params", + Doc: "LHbParams has values for computing LHb & RMTg which drives dips / pauses in DA firing.\nLHb handles all US-related (PV = primary value) processing.\nPositive net LHb activity drives dips / pauses in VTA DA activity,\ne.g., when predicted pos > actual or actual neg > predicted.\nNegative net LHb activity drives bursts in VTA DA activity,\ne.g., when actual pos > predicted (redundant with LV / Amygdala)\nor \"relief\" burst when actual neg < predicted.", + Directives: gti.Directives{}, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"NegThr", >i.Field{Name: "NegThr", Type: "float32", LocalType: "float32", Doc: "threshold factor that multiplies integrated pvNeg value to establish a threshold for whether the integrated pvPos value is good enough to drive overall net positive reward", Directives: gti.Directives{}, Tag: "def:\"1\""}}, + {"BurstGain", >i.Field{Name: "BurstGain", Type: "float32", LocalType: "float32", Doc: "gain multiplier on PVpos for purposes of generating bursts (not for discounting negative dips) -- 4 renormalizes for typical ~.5 values (.5 * .5 = .25)", Directives: gti.Directives{}, Tag: "def:\"1\""}}, + {"DipGain", >i.Field{Name: "DipGain", Type: "float32", LocalType: "float32", Doc: "gain multiplier on PVneg for purposes of generating dips (not for discounting positive bursts) -- 4 renormalizes for typical ~.5 values (.5 * .5 = .25)", Directives: gti.Directives{}, Tag: "def:\"1\""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.GiveUpParams", + ShortName: "axon.GiveUpParams", + IDName: "give-up-params", + Doc: "GiveUpParams are parameters for computing when to give up", + Directives: gti.Directives{}, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"NegThr", >i.Field{Name: "NegThr", Type: "float32", LocalType: "float32", Doc: "threshold factor that multiplies integrated pvNeg value to establish a threshold for whether the integrated pvPos value is good enough to drive overall net positive reward", Directives: gti.Directives{}, Tag: "def:\"1\""}}, + {"Gain", >i.Field{Name: "Gain", Type: "float32", LocalType: "float32", Doc: "multiplier on pos - neg for logistic probability function -- higher gain values produce more binary give up behavior and lower values produce more graded stochastic behavior around the threshold", Directives: gti.Directives{}, Tag: "def:\"10\""}}, + {"MinPVposEst", >i.Field{Name: "MinPVposEst", Type: "float32", LocalType: "float32", Doc: "minimum estimated PVpos value -- deals with any errors in the estimation process to make sure that erroneous GiveUp doesn't happen.", Directives: gti.Directives{}, Tag: ""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.PVLV", + ShortName: "axon.PVLV", + IDName: "pvlv", + Doc: "PVLV represents the core brainstem-level (hypothalamus) bodily drives\nand resulting dopamine from US (unconditioned stimulus) inputs,\nas computed by the PVLV model of primary value (PV)\nand learned value (LV), describing the functions of the Amygala,\nVentral Striatum, VTA and associated midbrain nuclei (LDT, LHb, RMTg).\nCore LHb (lateral habenula) and VTA (ventral tegmental area) dopamine\nare computed in equations using inputs from specialized network layers\n(LDTLayer driven by BLA, CeM layers, VSPatchLayer).\nThe Drives, Effort, US and resulting LHb PV dopamine computation all happens at the\nat the start of each trial (NewState, Step). The LV / CS dopamine is computed\ncycle-by-cycle by the VTA layer using parameters set by the VTA layer.\nRenders USLayer, PVLayer, DrivesLayer representations based on state updated here.", + Directives: gti.Directives{}, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"NPosUSs", >i.Field{Name: "NPosUSs", Type: "uint32", LocalType: "uint32", Doc: "number of possible positive US states and corresponding drives -- the first is always reserved for novelty / curiosity. Must be set programmatically via SetNUSs method, which allocates corresponding parameters.", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + {"NNegUSs", >i.Field{Name: "NNegUSs", Type: "uint32", LocalType: "uint32", Doc: "number of possible negative US states -- is reserved for accumulated time, the accumulated effort cost. Must be set programmatically via SetNUSs method, which allocates corresponding parameters.", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + {"Drive", >i.Field{Name: "Drive", Type: "github.com/emer/axon/axon.DriveParams", LocalType: "DriveParams", Doc: "parameters and state for built-in drives that form the core motivations of agent, controlled by lateral hypothalamus and associated body state monitoring such as glucose levels and thirst.", Directives: gti.Directives{}, Tag: ""}}, + {"Urgency", >i.Field{Name: "Urgency", Type: "github.com/emer/axon/axon.UrgencyParams", LocalType: "UrgencyParams", Doc: "urgency (increasing pressure to do something) and parameters for updating it. Raw urgency is incremented by same units as effort, but is only reset with a positive US.", Directives: gti.Directives{}, Tag: "view:\"inline\""}}, + {"USs", >i.Field{Name: "USs", Type: "github.com/emer/axon/axon.USParams", LocalType: "USParams", Doc: "controls how positive and negative USs are weighted and integrated to compute an overall PV primary value.", Directives: gti.Directives{}, Tag: ""}}, + {"LHb", >i.Field{Name: "LHb", Type: "github.com/emer/axon/axon.LHbParams", LocalType: "LHbParams", Doc: "lateral habenula (LHb) parameters and state, which drives dipping / pausing in dopamine when the predicted positive outcome > actual, or actual negative outcome > predicted. Can also drive bursting for the converse, and via matrix phasic firing", Directives: gti.Directives{}, Tag: "view:\"inline\""}}, + {"GiveUp", >i.Field{Name: "GiveUp", Type: "github.com/emer/axon/axon.GiveUpParams", LocalType: "GiveUpParams", Doc: "parameters for giving up based on PV pos - neg difference", Directives: gti.Directives{}, Tag: ""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.LDTParams", + ShortName: "axon.LDTParams", + IDName: "ldt-params", + Doc: "LDTParams compute reward salience as ACh global neuromodulatory signal\nas a function of the MAX activation of its inputs.", + Directives: gti.Directives{ + >i.Directive{Tool: "gosl", Directive: "start", Args: []string{"pvlv_layers"}}, + }, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"SrcThr", >i.Field{Name: "SrcThr", Type: "float32", LocalType: "float32", Doc: "threshold per input source, on absolute value (magnitude), to count as a significant reward event, which then drives maximal ACh -- set to 0 to disable this nonlinear behavior", Directives: gti.Directives{}, Tag: "def:\"0.05\""}}, + {"Rew", >i.Field{Name: "Rew", Type: "goki.dev/gosl/v2/slbool.Bool", LocalType: "slbool.Bool", Doc: "use the global Context.NeuroMod.HasRew flag -- if there is some kind of external reward being given, then ACh goes to 1, else 0 for this component", Directives: gti.Directives{}, Tag: "def:\"true\""}}, + {"MaintInhib", >i.Field{Name: "MaintInhib", Type: "float32", LocalType: "float32", Doc: "extent to which active maintenance (via Context.NeuroMod.NotMaint PTNotMaintLayer activity) inhibits ACh signals -- when goal engaged, distractability is lower.", Directives: gti.Directives{}, Tag: "def:\"2\""}}, + {"NotMaintMax", >i.Field{Name: "NotMaintMax", Type: "float32", LocalType: "float32", Doc: "maximum NeuroMod.NotMaint activity for computing Maint as 1-NotMaint -- when NotMaint is >= NotMaintMax, then Maint = 0.", Directives: gti.Directives{}, Tag: "def:\"0.4\""}}, + {"SrcLay1Idx", >i.Field{Name: "SrcLay1Idx", Type: "int32", LocalType: "int32", Doc: "idx of Layer to get max activity from -- set during Build from BuildConfig SrcLay1Name if present -- -1 if not used", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + {"SrcLay2Idx", >i.Field{Name: "SrcLay2Idx", Type: "int32", LocalType: "int32", Doc: "idx of Layer to get max activity from -- set during Build from BuildConfig SrcLay2Name if present -- -1 if not used", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + {"SrcLay3Idx", >i.Field{Name: "SrcLay3Idx", Type: "int32", LocalType: "int32", Doc: "idx of Layer to get max activity from -- set during Build from BuildConfig SrcLay3Name if present -- -1 if not used", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + {"SrcLay4Idx", >i.Field{Name: "SrcLay4Idx", Type: "int32", LocalType: "int32", Doc: "idx of Layer to get max activity from -- set during Build from BuildConfig SrcLay4Name if present -- -1 if not used", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.VSPatchParams", + ShortName: "axon.VSPatchParams", + IDName: "vs-patch-params", + Doc: "VSPatchParams parameters for VSPatch learning", + Directives: gti.Directives{}, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"Gain", >i.Field{Name: "Gain", Type: "float32", LocalType: "float32", Doc: "multiplier applied after Thr threshold", Directives: gti.Directives{}, Tag: "def:\"3\""}}, + {"ThrInit", >i.Field{Name: "ThrInit", Type: "float32", LocalType: "float32", Doc: "initial value for overall threshold, which adapts over time -- stored in LayerVals.ActAvgVals.AdaptThr", Directives: gti.Directives{}, Tag: "def:\"0.15\""}}, + {"ThrLRate", >i.Field{Name: "ThrLRate", Type: "float32", LocalType: "float32", Doc: "learning rate for the threshold -- moves in proportion to same predictive error signal that drives synaptic learning", Directives: gti.Directives{}, Tag: "def:\"0,0.002\""}}, + {"ThrNonRew", >i.Field{Name: "ThrNonRew", Type: "float32", LocalType: "float32", Doc: "extra gain factor for non-reward trials, which is the most critical", Directives: gti.Directives{}, Tag: "def:\"10\""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.VTAParams", + ShortName: "axon.VTAParams", + IDName: "vta-params", + Doc: "VTAParams are for computing overall VTA DA based on LHb PVDA\n(primary value -- at US time, computed at start of each trial\nand stored in LHbPVDA global value)\nand Amygdala (CeM) CS / learned value (LV) activations, which update\nevery cycle.", + Directives: gti.Directives{}, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"CeMGain", >i.Field{Name: "CeMGain", Type: "float32", LocalType: "float32", Doc: "gain on CeM activity difference (CeMPos - CeMNeg) for generating LV CS-driven dopamine values", Directives: gti.Directives{}, Tag: "def:\"0.75\""}}, + {"LHbGain", >i.Field{Name: "LHbGain", Type: "float32", LocalType: "float32", Doc: "gain on computed LHb DA (Burst - Dip) -- for controlling DA levels", Directives: gti.Directives{}, Tag: "def:\"1.25\""}}, + {"pad", >i.Field{Name: "pad", Type: "float32", LocalType: "float32", Doc: "", Directives: gti.Directives{}, Tag: ""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.BLAPrjnParams", + ShortName: "axon.BLAPrjnParams", + IDName: "bla-prjn-params", + Doc: "BLAPrjnParams has parameters for basolateral amygdala learning.\nLearning is driven by the Tr trace as function of ACh * Send Act\nrecorded prior to US, and at US, recv unit delta: CaSpkP - SpkPrv\ntimes normalized GeIntNorm for recv unit credit assignment.\nThe Learn.Trace.Tau time constant determines trace updating over trials\nwhen ACh is above threshold -- this determines strength of second-order\nconditioning -- default of 1 means none, but can be increased as needed.", + Directives: gti.Directives{ + >i.Directive{Tool: "gosl", Directive: "start", Args: []string{"pvlv_prjns"}}, + }, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"NegDeltaLRate", >i.Field{Name: "NegDeltaLRate", Type: "float32", LocalType: "float32", Doc: "use 0.01 for acquisition (don't unlearn) and 1 for extinction -- negative delta learning rate multiplier", Directives: gti.Directives{}, Tag: "def:\"0.01,1\""}}, + {"AChThr", >i.Field{Name: "AChThr", Type: "float32", LocalType: "float32", Doc: "threshold on this layer's ACh level for trace learning updates", Directives: gti.Directives{}, Tag: "def:\"0.1\""}}, + {"USTrace", >i.Field{Name: "USTrace", Type: "float32", LocalType: "float32", Doc: "proportion of US time stimulus activity to use for the trace component of", Directives: gti.Directives{}, Tag: "def:\"0,0.5\""}}, + {"pad", >i.Field{Name: "pad", Type: "float32", LocalType: "float32", Doc: "", Directives: gti.Directives{}, Tag: ""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.RandFunIdx", + ShortName: "axon.RandFunIdx", + IDName: "rand-fun-idx", + Doc: "", + Directives: gti.Directives{ + >i.Directive{Tool: "gosl", Directive: "hlsl", Args: []string{"axonrand"}}, + >i.Directive{Tool: "gosl", Directive: "end", Args: []string{"axonrand"}}, + >i.Directive{Tool: "gosl", Directive: "start", Args: []string{"axonrand"}}, + }, + + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.RWPredParams", + ShortName: "axon.RWPredParams", + IDName: "rw-pred-params", + Doc: "RWPredParams parameterizes reward prediction for a simple Rescorla-Wagner\nlearning dynamic (i.e., PV learning in the PVLV framework).", + Directives: gti.Directives{ + >i.Directive{Tool: "gosl", Directive: "start", Args: []string{"rl_layers"}}, + }, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"PredRange", >i.Field{Name: "PredRange", Type: "goki.dev/etable/v2/minmax.F32", LocalType: "minmax.F32", Doc: "default 0.1..0.99 range of predictions that can be represented -- having a truncated range preserves some sensitivity in dopamine at the extremes of good or poor performance", Directives: gti.Directives{}, Tag: ""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.RWDaParams", + ShortName: "axon.RWDaParams", + IDName: "rw-da-params", + Doc: "RWDaParams computes a dopamine (DA) signal using simple Rescorla-Wagner\nlearning dynamic (i.e., PV learning in the PVLV framework).", + Directives: gti.Directives{}, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"TonicGe", >i.Field{Name: "TonicGe", Type: "float32", LocalType: "float32", Doc: "tonic baseline Ge level for DA = 0 -- +/- are between 0 and 2*TonicGe -- just for spiking display of computed DA value", Directives: gti.Directives{}, Tag: ""}}, + {"RWPredLayIdx", >i.Field{Name: "RWPredLayIdx", Type: "int32", LocalType: "int32", Doc: "idx of RWPredLayer to get reward prediction from -- set during Build from BuildConfig RWPredLayName", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + {"pad", >i.Field{Name: "pad", Type: "uint32", LocalType: "uint32", Doc: "", Directives: gti.Directives{}, Tag: ""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.TDIntegParams", + ShortName: "axon.TDIntegParams", + IDName: "td-integ-params", + Doc: "TDIntegParams are params for reward integrator layer", + Directives: gti.Directives{}, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"Discount", >i.Field{Name: "Discount", Type: "float32", LocalType: "float32", Doc: "discount factor -- how much to discount the future prediction from TDPred", Directives: gti.Directives{}, Tag: ""}}, + {"PredGain", >i.Field{Name: "PredGain", Type: "float32", LocalType: "float32", Doc: "gain factor on TD rew pred activations", Directives: gti.Directives{}, Tag: ""}}, + {"TDPredLayIdx", >i.Field{Name: "TDPredLayIdx", Type: "int32", LocalType: "int32", Doc: "idx of TDPredLayer to get reward prediction from -- set during Build from BuildConfig TDPredLayName", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + {"pad", >i.Field{Name: "pad", Type: "uint32", LocalType: "uint32", Doc: "", Directives: gti.Directives{}, Tag: ""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.TDDaParams", + ShortName: "axon.TDDaParams", + IDName: "td-da-params", + Doc: "TDDaParams are params for dopamine (DA) signal as the temporal difference (TD)\nbetween the TDIntegLayer activations in the minus and plus phase.", + Directives: gti.Directives{}, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"TonicGe", >i.Field{Name: "TonicGe", Type: "float32", LocalType: "float32", Doc: "tonic baseline Ge level for DA = 0 -- +/- are between 0 and 2*TonicGe -- just for spiking display of computed DA value", Directives: gti.Directives{}, Tag: ""}}, + {"TDIntegLayIdx", >i.Field{Name: "TDIntegLayIdx", Type: "int32", LocalType: "int32", Doc: "idx of TDIntegLayer to get reward prediction from -- set during Build from BuildConfig TDIntegLayName", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + {"pad", >i.Field{Name: "pad", Type: "uint32", LocalType: "uint32", Doc: "", Directives: gti.Directives{}, Tag: ""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.RLPredPrjnParams", + ShortName: "axon.RLPredPrjnParams", + IDName: "rl-pred-prjn-params", + Doc: "RLPredPrjnParams does dopamine-modulated learning for reward prediction: Da * Send.Act\nUsed by RWPrjn and TDPredPrjn within corresponding RWPredLayer or TDPredLayer\nto generate reward predictions based on its incoming weights, using linear activation\nfunction. Has no weight bounds or limits on sign etc.", + Directives: gti.Directives{ + >i.Directive{Tool: "gosl", Directive: "start", Args: []string{"rl_prjns"}}, + }, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"OppSignLRate", >i.Field{Name: "OppSignLRate", Type: "float32", LocalType: "float32", Doc: "how much to learn on opposite DA sign coding neuron (0..1)", Directives: gti.Directives{}, Tag: ""}}, + {"DaTol", >i.Field{Name: "DaTol", Type: "float32", LocalType: "float32", Doc: "tolerance on DA -- if below this abs value, then DA goes to zero and there is no learning -- prevents prediction from exactly learning to cancel out reward value, retaining a residual valence of signal", Directives: gti.Directives{}, Tag: ""}}, + {"pad", >i.Field{Name: "pad", Type: "float32", LocalType: "float32", Doc: "", Directives: gti.Directives{}, Tag: ""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.SynapseVars", + ShortName: "axon.SynapseVars", + IDName: "synapse-vars", + Doc: "SynapseVars are the neuron variables representing current synaptic state,\nspecifically weights.", + Directives: gti.Directives{ + >i.Directive{Tool: "gosl", Directive: "start", Args: []string{"synapse"}}, + >i.Directive{Tool: "enums", Directive: "enum", Args: []string{}}, + }, + + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.SynapseCaVars", + ShortName: "axon.SynapseCaVars", + IDName: "synapse-ca-vars", + Doc: "SynapseCaVars are synapse variables for calcium involved in learning,\nwhich are data parallel input specific.", + Directives: gti.Directives{ + >i.Directive{Tool: "enums", Directive: "enum", Args: []string{}}, + }, + + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.SynapseIdxs", + ShortName: "axon.SynapseIdxs", + IDName: "synapse-idxs", + Doc: "SynapseIdxs are the neuron indexes and other uint32 values (flags, etc).\nThere is only one of these per neuron -- not data parallel.", + Directives: gti.Directives{ + >i.Directive{Tool: "enums", Directive: "enum", Args: []string{}}, + }, + + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.SynapseVarStrides", + ShortName: "axon.SynapseVarStrides", + IDName: "synapse-var-strides", + Doc: "SynapseVarStrides encodes the stride offsets for synapse variable access\ninto network float32 array.", + Directives: gti.Directives{ + >i.Directive{Tool: "gosl", Directive: "end", Args: []string{"synapse"}}, + >i.Directive{Tool: "gosl", Directive: "hlsl", Args: []string{"synapse"}}, + >i.Directive{Tool: "gosl", Directive: "end", Args: []string{"synapse"}}, + >i.Directive{Tool: "gosl", Directive: "start", Args: []string{"synapse"}}, + }, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"Synapse", >i.Field{Name: "Synapse", Type: "uint32", LocalType: "uint32", Doc: "synapse level", Directives: gti.Directives{}, Tag: ""}}, + {"Var", >i.Field{Name: "Var", Type: "uint32", LocalType: "uint32", Doc: "variable level", Directives: gti.Directives{}, Tag: ""}}, + {"pad", >i.Field{Name: "pad", Type: "uint32", LocalType: "uint32", Doc: "", Directives: gti.Directives{}, Tag: ""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.SynapseCaStrides", + ShortName: "axon.SynapseCaStrides", + IDName: "synapse-ca-strides", + Doc: "SynapseCaStrides encodes the stride offsets for synapse variable access\ninto network float32 array. Data is always the inner-most variable.", + Directives: gti.Directives{}, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"Synapse", >i.Field{Name: "Synapse", Type: "uint64", LocalType: "uint64", Doc: "synapse level", Directives: gti.Directives{}, Tag: ""}}, + {"Var", >i.Field{Name: "Var", Type: "uint64", LocalType: "uint64", Doc: "variable level", Directives: gti.Directives{}, Tag: ""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/axon.SynapseIdxStrides", + ShortName: "axon.SynapseIdxStrides", + IDName: "synapse-idx-strides", + Doc: "SynapseIdxStrides encodes the stride offsets for synapse index access\ninto network uint32 array.", + Directives: gti.Directives{}, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"Synapse", >i.Field{Name: "Synapse", Type: "uint32", LocalType: "uint32", Doc: "synapse level", Directives: gti.Directives{}, Tag: ""}}, + {"Index", >i.Field{Name: "Index", Type: "uint32", LocalType: "uint32", Doc: "index value level", Directives: gti.Directives{}, Tag: ""}}, + {"pad", >i.Field{Name: "pad", Type: "uint32", LocalType: "uint32", Doc: "", Directives: gti.Directives{}, Tag: ""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) diff --git a/axon/hebbprjn.go b/axon/hebbprjn.go index c966121d5..f3a588fc1 100644 --- a/axon/hebbprjn.go +++ b/axon/hebbprjn.go @@ -8,7 +8,7 @@ package axon todo: for GPU, must have this in base case -import "github.com/goki/gosl/slbool" +import "goki.dev/gosl/v2/slbool" // HebbPrjn is a simple hebbian learning projection, using the CPCA Hebbian rule. // Note: when used with inhibitory projections, requires Learn.Trace.SubMean = 1 diff --git a/axon/inhib.go b/axon/inhib.go index 4364298ff..5697671aa 100644 --- a/axon/inhib.go +++ b/axon/inhib.go @@ -6,7 +6,7 @@ package axon import ( "github.com/emer/axon/fsfffb" - "github.com/goki/gosl/slbool" + "goki.dev/gosl/v2/slbool" "goki.dev/mat32/v2" ) diff --git a/axon/layer.go b/axon/layer.go index 0e43aa24b..9f05a3dfa 100644 --- a/axon/layer.go +++ b/axon/layer.go @@ -11,9 +11,6 @@ import ( "strings" "github.com/emer/emergent/v2/erand" - "github.com/goki/ki/ints" - "github.com/goki/ki/ki" - "github.com/goki/ki/kit" "goki.dev/etable/v2/etensor" ) @@ -30,8 +27,6 @@ type Layer struct { Params *LayerParams } -var KiT_Layer = kit.Types.AddType(&Layer{}, LayerProps) - // Object returns the object with parameters to be set by emer.Params func (ly *Layer) Object() any { return ly.Params @@ -507,8 +502,8 @@ func (ly *Layer) ApplyExtFlags() (clearMask, setMask NeuronFlags, toTarg bool) { // ApplyExt2D applies 2D tensor external input func (ly *Layer) ApplyExt2D(ctx *Context, di uint32, ext etensor.Tensor) { clearMask, setMask, toTarg := ly.ApplyExtFlags() - ymx := ints.MinInt(ext.Dim(0), ly.Shp.Dim(0)) - xmx := ints.MinInt(ext.Dim(1), ly.Shp.Dim(1)) + ymx := min(ext.Dim(0), ly.Shp.Dim(0)) + xmx := min(ext.Dim(1), ly.Shp.Dim(1)) for y := 0; y < ymx; y++ { for x := 0; x < xmx; x++ { idx := []int{y, x} @@ -524,8 +519,8 @@ func (ly *Layer) ApplyExt2Dto4D(ctx *Context, di uint32, ext etensor.Tensor) { clearMask, setMask, toTarg := ly.ApplyExtFlags() lNy, lNx, _, _ := etensor.Prjn2DShape(&ly.Shp, false) - ymx := ints.MinInt(ext.Dim(0), lNy) - xmx := ints.MinInt(ext.Dim(1), lNx) + ymx := min(ext.Dim(0), lNy) + xmx := min(ext.Dim(1), lNx) for y := 0; y < ymx; y++ { for x := 0; x < xmx; x++ { idx := []int{y, x} @@ -539,10 +534,10 @@ func (ly *Layer) ApplyExt2Dto4D(ctx *Context, di uint32, ext etensor.Tensor) { // ApplyExt4D applies 4D tensor external input func (ly *Layer) ApplyExt4D(ctx *Context, di uint32, ext etensor.Tensor) { clearMask, setMask, toTarg := ly.ApplyExtFlags() - ypmx := ints.MinInt(ext.Dim(0), ly.Shp.Dim(0)) - xpmx := ints.MinInt(ext.Dim(1), ly.Shp.Dim(1)) - ynmx := ints.MinInt(ext.Dim(2), ly.Shp.Dim(2)) - xnmx := ints.MinInt(ext.Dim(3), ly.Shp.Dim(3)) + ypmx := min(ext.Dim(0), ly.Shp.Dim(0)) + xpmx := min(ext.Dim(1), ly.Shp.Dim(1)) + ynmx := min(ext.Dim(2), ly.Shp.Dim(2)) + xnmx := min(ext.Dim(3), ly.Shp.Dim(3)) for yp := 0; yp < ypmx; yp++ { for xp := 0; xp < xpmx; xp++ { for yn := 0; yn < ynmx; yn++ { @@ -562,7 +557,7 @@ func (ly *Layer) ApplyExt4D(ctx *Context, di uint32, ext etensor.Tensor) { // otherwise it goes in Ext func (ly *Layer) ApplyExt1DTsr(ctx *Context, di uint32, ext etensor.Tensor) { clearMask, setMask, toTarg := ly.ApplyExtFlags() - mx := uint32(ints.MinInt(ext.Len(), int(ly.NNeurons))) + mx := uint32(min(ext.Len(), int(ly.NNeurons))) for lni := uint32(0); lni < mx; lni++ { val := float32(ext.FloatVal1D(int(lni))) ly.ApplyExtVal(ctx, lni, di, val, clearMask, setMask, toTarg) @@ -574,7 +569,7 @@ func (ly *Layer) ApplyExt1DTsr(ctx *Context, di uint32, ext etensor.Tensor) { // otherwise it goes in Ext func (ly *Layer) ApplyExt1D(ctx *Context, di uint32, ext []float64) { clearMask, setMask, toTarg := ly.ApplyExtFlags() - mx := uint32(ints.MinInt(len(ext), int(ly.NNeurons))) + mx := uint32(min(len(ext), int(ly.NNeurons))) for lni := uint32(0); lni < mx; lni++ { val := float32(ext[lni]) ly.ApplyExtVal(ctx, lni, di, val, clearMask, setMask, toTarg) @@ -586,7 +581,7 @@ func (ly *Layer) ApplyExt1D(ctx *Context, di uint32, ext []float64) { // otherwise it goes in Ext func (ly *Layer) ApplyExt1D32(ctx *Context, di uint32, ext []float32) { clearMask, setMask, toTarg := ly.ApplyExtFlags() - mx := uint32(ints.MinInt(len(ext), int(ly.NNeurons))) + mx := uint32(min(len(ext), int(ly.NNeurons))) for lni := uint32(0); lni < mx; lni++ { val := ext[lni] ly.ApplyExtVal(ctx, lni, di, val, clearMask, setMask, toTarg) @@ -895,6 +890,7 @@ func (ly *Layer) LesionNeurons(prop float32) int { ////////////////////////////////////////////////////////////////////////////////////// // Layer props for gui +/* var LayerProps = ki.Props{ "EnumType:Typ": KiT_LayerTypes, // uses our LayerTypes for GUI "ToolBar": ki.PropSlice{ @@ -926,3 +922,4 @@ var LayerProps = ki.Props{ }}, }, } +*/ diff --git a/axon/layerbase.go b/axon/layerbase.go index d08e0119c..0322dc4c6 100644 --- a/axon/layerbase.go +++ b/axon/layerbase.go @@ -16,9 +16,9 @@ import ( "github.com/emer/emergent/v2/params" "github.com/emer/emergent/v2/relpos" "github.com/emer/emergent/v2/weights" - "github.com/goki/ki/indent" "goki.dev/etable/v2/etensor" "goki.dev/gi/v2/giv" + "goki.dev/glop/indent" "goki.dev/mat32/v2" ) diff --git a/axon/layertypes.go b/axon/layertypes.go index 22a0bc5c7..ad716a806 100644 --- a/axon/layertypes.go +++ b/axon/layertypes.go @@ -4,10 +4,6 @@ package axon -import ( - "github.com/goki/ki/kit" -) - //gosl: start layertypes // LayerTypes is an axon-specific layer type enum, @@ -15,7 +11,7 @@ import ( // Class parameter styles automatically key off of these types. // The first entries must be kept synchronized with the emer.LayerType, // although we replace Hidden -> Super. -type LayerTypes int32 +type LayerTypes int32 //enums:enum // note: we need to add the Layer extension to avoid naming // conflicts between layer, projection and other things. @@ -236,8 +232,6 @@ const ( // between the TDIntegLayer activations in the minus and plus phase. // These are retrieved from Special LayerVals. TDDaLayer - - LayerTypesN ) // IsExtLayerType returns true if the layer type deals with external input: @@ -259,10 +253,3 @@ func (lt LayerTypes) IsExt() bool { } return false } - -//go:generate stringer -type=LayerTypes - -var KiT_LayerTypes = kit.Enums.AddEnum(LayerTypesN, kit.NotBitFlag, nil) - -func (ev LayerTypes) MarshalJSON() ([]byte, error) { return kit.EnumMarshalJSON(ev) } -func (ev *LayerTypes) UnmarshalJSON(b []byte) error { return kit.EnumUnmarshalJSON(ev, b) } diff --git a/axon/layertypes_string.go b/axon/layertypes_string.go deleted file mode 100644 index 6d88fb397..000000000 --- a/axon/layertypes_string.go +++ /dev/null @@ -1,111 +0,0 @@ -// Code generated by "stringer -type=LayerTypes"; DO NOT EDIT. - -package axon - -import ( - "errors" - "strconv" -) - -var _ = errors.New("dummy error") - -func _() { - // An "invalid array index" compiler error signifies that the constant values have changed. - // Re-run the stringer command to generate them again. - var x [1]struct{} - _ = x[SuperLayer-0] - _ = x[InputLayer-1] - _ = x[TargetLayer-2] - _ = x[CompareLayer-3] - _ = x[CTLayer-4] - _ = x[PulvinarLayer-5] - _ = x[TRNLayer-6] - _ = x[PTMaintLayer-7] - _ = x[PTPredLayer-8] - _ = x[PTNotMaintLayer-9] - _ = x[MatrixLayer-10] - _ = x[STNLayer-11] - _ = x[GPLayer-12] - _ = x[BGThalLayer-13] - _ = x[VSGatedLayer-14] - _ = x[BLALayer-15] - _ = x[CeMLayer-16] - _ = x[VSPatchLayer-17] - _ = x[LHbLayer-18] - _ = x[DrivesLayer-19] - _ = x[UrgencyLayer-20] - _ = x[USLayer-21] - _ = x[PVLayer-22] - _ = x[LDTLayer-23] - _ = x[VTALayer-24] - _ = x[RewLayer-25] - _ = x[RWPredLayer-26] - _ = x[RWDaLayer-27] - _ = x[TDPredLayer-28] - _ = x[TDIntegLayer-29] - _ = x[TDDaLayer-30] - _ = x[LayerTypesN-31] -} - -const _LayerTypes_name = "SuperLayerInputLayerTargetLayerCompareLayerCTLayerPulvinarLayerTRNLayerPTMaintLayerPTPredLayerPTNotMaintLayerMatrixLayerSTNLayerGPLayerBGThalLayerVSGatedLayerBLALayerCeMLayerVSPatchLayerLHbLayerDrivesLayerUrgencyLayerUSLayerPVLayerLDTLayerVTALayerRewLayerRWPredLayerRWDaLayerTDPredLayerTDIntegLayerTDDaLayerLayerTypesN" - -var _LayerTypes_index = [...]uint16{0, 10, 20, 31, 43, 50, 63, 71, 83, 94, 109, 120, 128, 135, 146, 158, 166, 174, 186, 194, 205, 217, 224, 231, 239, 247, 255, 266, 275, 286, 298, 307, 318} - -func (i LayerTypes) String() string { - if i < 0 || i >= LayerTypes(len(_LayerTypes_index)-1) { - return "LayerTypes(" + strconv.FormatInt(int64(i), 10) + ")" - } - return _LayerTypes_name[_LayerTypes_index[i]:_LayerTypes_index[i+1]] -} - -func (i *LayerTypes) FromString(s string) error { - for j := 0; j < len(_LayerTypes_index)-1; j++ { - if s == _LayerTypes_name[_LayerTypes_index[j]:_LayerTypes_index[j+1]] { - *i = LayerTypes(j) - return nil - } - } - return errors.New("String: " + s + " is not a valid option for type: LayerTypes") -} - -var _LayerTypes_descMap = map[LayerTypes]string{ - 0: `Super is a superficial cortical layer (lamina 2-3-4) which does not receive direct input or targets. In more generic models, it should be used as a Hidden layer, and maps onto the Hidden type in emer.LayerType.`, - 1: `Input is a layer that receives direct external input in its Ext inputs. Biologically, it can be a primary sensory layer, or a thalamic layer.`, - 2: `Target is a layer that receives direct external target inputs used for driving plus-phase learning. Simple target layers are generally not used in more biological models, which instead use predictive learning via Pulvinar or related mechanisms.`, - 3: `Compare is a layer that receives external comparison inputs, which drive statistics but do NOT drive activation or learning directly. It is rarely used in axon.`, - 4: `CT are layer 6 corticothalamic projecting neurons, which drive "top down" predictions in Pulvinar layers. They maintain information over time via stronger NMDA channels and use maintained prior state information to generate predictions about current states forming on Super layers that then drive PT (5IB) bursting activity, which are the plus-phase drivers of Pulvinar activity.`, - 5: `Pulvinar are thalamic relay cell neurons in the higher-order Pulvinar nucleus of the thalamus, and functionally isomorphic neurons in the MD thalamus, and potentially other areas. These cells alternately reflect predictions driven by CT projections, and actual outcomes driven by 5IB Burst activity from corresponding PT or Super layer neurons that provide strong driving inputs.`, - 6: `TRNLayer is thalamic reticular nucleus layer for inhibitory competition within the thalamus.`, - 7: `PTMaintLayer implements the subset of pyramidal tract (PT) layer 5 intrinsic bursting (5IB) deep neurons that exhibit robust, stable maintenance of activity over the duration of a goal engaged window, modulated by basal ganglia (BG) disinhibitory gating, supported by strong MaintNMDA channels and recurrent excitation. The lateral PTSelfMaint projection uses MaintG to drive GMaintRaw input that feeds into the stronger, longer MaintNMDA channels, and the ThalToPT ModulatoryG projection from BGThalamus multiplicatively modulates the strength of other inputs, such that only at the time of BG gating are these strong enough to drive sustained active maintenance. Use Act.Dend.ModGain to parameterize.`, - 8: `PTPredLayer implements the subset of pyramidal tract (PT) layer 5 intrinsic bursting (5IB) deep neurons that combine modulatory input from PTMaintLayer sustained maintenance and CTLayer dynamic predictive learning that helps to predict state changes during the period of active goal maintenance. This layer provides the primary input to VSPatch US-timing prediction layers, and other layers that require predictive dynamic`, - 9: `PTNotMaintLayer implements a tonically active layer that is inhibited by the PTMaintLayer, thereby providing an active representation of the *absence* of maintained PT activity, which is useful for driving appropriate actions (e.g., exploration) when not in goal-engaged mode.`, - 10: `MatrixLayer represents the matrisome medium spiny neurons (MSNs) that are the main Go / NoGo gating units in BG. These are strongly modulated by phasic dopamine: D1 = Go, D2 = NoGo.`, - 11: `STNLayer represents subthalamic nucleus neurons, with two subtypes: STNp are more strongly driven and get over bursting threshold, driving strong, rapid activation of the KCa channels, causing a long pause in firing, which creates a window during which GPe dynamics resolve Go vs. No balance. STNs are more weakly driven and thus more slowly activate KCa, resulting in a longer period of activation, during which the GPi is inhibited to prevent premature gating based only MtxGo inhibition -- gating only occurs when GPeIn signal has had a chance to integrate its MtxNo inputs.`, - 12: `GPLayer represents a globus pallidus layer in the BG, including: GPeOut, GPeIn, GPeTA (arkypallidal), and GPi. Typically just a single unit per Pool representing a given stripe.`, - 13: `BGThalLayer represents a BG gated thalamic layer, which receives BG gating in the form of an inhibitory projection from GPi. Located mainly in the Ventral thalamus: VA / VM / VL, and also parts of MD mediodorsal thalamus.`, - 14: `VSGated represents explicit coding of VS gating status: JustGated and HasGated (since last US or failed predicted US), For visualization and / or motor action signaling.`, - 15: `BLALayer represents a basolateral amygdala layer which learns to associate arbitrary stimuli (CSs) with behaviorally salient outcomes (USs)`, - 16: `CeMLayer represents a central nucleus of the amygdala layer.`, - 17: `VSPatchLayer represents a ventral striatum patch layer, which learns to represent the expected amount of dopamine reward and projects both directly with shunting inhibition to the VTA and indirectly via the LHb / RMTg to cancel phasic dopamine firing to expected rewards (i.e., reward prediction error).`, - 18: `LHbLayer represents the lateral habenula, which drives dipping in the VTA. It tracks the Global LHb values for visualization purposes -- updated by VTALayer.`, - 19: `DrivesLayer represents the Drives in PVLV framework. It tracks the Global Drives values for visualization and predictive learning purposes.`, - 20: `UrgencyLayer represents the Urgency factor in PVLV framework. It tracks the Global Urgency.Urge value for visualization and predictive learning purposes.`, - 21: `USLayer represents a US unconditioned stimulus layer (USpos or USneg). It tracks the Global USpos or USneg, for visualization and predictive learning purposes. Actual US inputs are set in PVLV.`, - 22: `PVLayer represents a PV primary value layer (PVpos or PVneg) representing the total primary value as a function of US inputs, drives, and effort. It tracks the Global VTA.PVpos, PVneg values for visualization and predictive learning purposes.`, - 23: `LDTLayer represents the laterodorsal tegmentum layer, which is the primary limbic ACh (acetylcholine) driver to other ACh: BG cholinergic interneurons (CIN) and nucleus basalis ACh areas. The phasic ACh release signals reward salient inputs from CS, US and US omssion, and it drives widespread disinhibition of BG gating and VTA DA firing. It receives excitation from superior colliculus which computes a temporal derivative (stimulus specific adaptation, SSA) of sensory inputs, and inhibitory input from OFC, ACC driving suppression of distracting inputs during goal-engaged states.`, - 24: `VTALayer represents the ventral tegmental area, which releases dopamine. It computes final DA value from PVLV-computed LHb PVDA (primary value DA), updated at start of each trial from updated US, Effort, etc state, and cycle-by-cycle LV learned value state reflecting CS inputs, in the Amygdala (CeM). Its activity reflects this DA level, which is effectively broadcast vial Global state values to all layers.`, - 25: `RewLayer represents positive or negative reward values across 2 units, showing spiking rates for each, and Act always represents signed value.`, - 26: `RWPredLayer computes reward prediction for a simple Rescorla-Wagner learning dynamic (i.e., PV learning in the PVLV framework). Activity is computed as linear function of excitatory conductance (which can be negative -- there are no constraints). Use with RWPrjn which does simple delta-rule learning on minus-plus.`, - 27: `RWDaLayer computes a dopamine (DA) signal based on a simple Rescorla-Wagner learning dynamic (i.e., PV learning in the PVLV framework). It computes difference between r(t) and RWPred values. r(t) is accessed directly from a Rew layer -- if no external input then no DA is computed -- critical for effective use of RW only for PV cases. RWPred prediction is also accessed directly from Rew layer to avoid any issues.`, - 28: `TDPredLayer is the temporal differences reward prediction layer. It represents estimated value V(t) in the minus phase, and computes estimated V(t+1) based on its learned weights in plus phase, using the TDPredPrjn projection type for DA modulated learning.`, - 29: `TDIntegLayer is the temporal differences reward integration layer. It represents estimated value V(t) from prior time step in the minus phase, and estimated discount * V(t+1) + r(t) in the plus phase. It gets Rew, PrevPred from Context.NeuroMod, and Special LayerVals from TDPredLayer.`, - 30: `TDDaLayer computes a dopamine (DA) signal as the temporal difference (TD) between the TDIntegLayer activations in the minus and plus phase. These are retrieved from Special LayerVals.`, - 31: ``, -} - -func (i LayerTypes) Desc() string { - if str, ok := _LayerTypes_descMap[i]; ok { - return str - } - return "LayerTypes(" + strconv.FormatInt(int64(i), 10) + ")" -} diff --git a/axon/learn.go b/axon/learn.go index a434ef299..848ac922b 100644 --- a/axon/learn.go +++ b/axon/learn.go @@ -8,8 +8,8 @@ import ( "github.com/emer/axon/chans" "github.com/emer/axon/kinase" "github.com/emer/emergent/v2/erand" - "github.com/goki/gosl/slbool" "goki.dev/etable/v2/minmax" + "goki.dev/gosl/v2/slbool" "goki.dev/mat32/v2" ) diff --git a/axon/network.go b/axon/network.go index 74253f8dc..82d74ca8a 100644 --- a/axon/network.go +++ b/axon/network.go @@ -11,8 +11,6 @@ import ( "github.com/c2h5oh/datasize" "github.com/emer/emergent/v2/emer" "github.com/emer/emergent/v2/prjn" - "github.com/goki/ki/ki" - "github.com/goki/ki/kit" "goki.dev/etable/v2/etensor" ) @@ -23,8 +21,6 @@ type Network struct { NetworkBase } -var KiT_Network = kit.Types.AddType(&Network{}, NetworkProps) - // InitName MUST be called to initialize the network's pointer to itself as an emer.Network // which enables the proper interface methods to be called. Also sets the name, // and initializes NetIdx in global list of Network @@ -695,6 +691,7 @@ func (nt *Network) SizeReport(detail bool) string { ////////////////////////////////////////////////////////////////////////////////////// // Network props for gui +/* var NetworkProps = ki.Props{ "ToolBar": ki.PropSlice{ {"SaveWtsJSON", ki.Props{ @@ -774,3 +771,4 @@ var NetworkProps = ki.Props{ }}, }, } +*/ diff --git a/axon/networkbase.go b/axon/networkbase.go index c021f120f..178ad2b9c 100644 --- a/axon/networkbase.go +++ b/axon/networkbase.go @@ -29,9 +29,9 @@ import ( "github.com/emer/emergent/v2/relpos" "github.com/emer/emergent/v2/timer" "github.com/emer/emergent/v2/weights" - "github.com/goki/ki/indent" - "github.com/goki/kigen/dedupe" "goki.dev/gi/v2/gi" + "goki.dev/glop/dedupe" + "goki.dev/glop/indent" "goki.dev/mat32/v2" ) diff --git a/axon/neuromod.go b/axon/neuromod.go index 3a39f66b2..66f1e7207 100644 --- a/axon/neuromod.go +++ b/axon/neuromod.go @@ -5,21 +5,14 @@ package axon import ( - "github.com/goki/gosl/slbool" - "github.com/goki/ki/kit" + "goki.dev/gosl/v2/slbool" "goki.dev/mat32/v2" ) -//go:generate stringer -type=DAModTypes -//go:generate stringer -type=ValenceTypes - -var KiT_DAModTypes = kit.Enums.AddEnum(DAModTypesN, kit.NotBitFlag, nil) -var KiT_ValenceTypes = kit.Enums.AddEnum(ValenceTypesN, kit.NotBitFlag, nil) - //gosl: start neuromod // DAModTypes are types of dopamine modulation of neural activity. -type DAModTypes int32 +type DAModTypes int32 //enums:enum const ( // NoDAMod means there is no effect of dopamine on neural activity @@ -40,12 +33,10 @@ const ( // There are a subset of DA neurons that send increased DA for // both negative and positive outcomes, targeting frontal neurons. D1AbsMod - - DAModTypesN ) // ValenceTypes are types of valence coding: positive or negative. -type ValenceTypes int32 +type ValenceTypes int32 //enums:enum const ( // Positive valence codes for outcomes aligned with drives / goals. @@ -53,8 +44,6 @@ const ( // Negative valence codes for harmful or aversive outcomes. Negative - - ValenceTypesN ) // NeuroModParams specifies the effects of neuromodulators on neural diff --git a/axon/neuron.go b/axon/neuron.go index 523e2f7ae..a9f789014 100644 --- a/axon/neuron.go +++ b/axon/neuron.go @@ -8,33 +8,12 @@ import ( "fmt" "github.com/emer/emergent/v2/netview" - "github.com/goki/ki/kit" ) -//go:generate stringer -type=NeuronFlags -//go:generate stringer -type=NeuronVars -//go:generate stringer -type=NeuronAvgVars -//go:generate stringer -type=NeuronIdxs - -var KiT_NeuronVars = kit.Enums.AddEnum(NeuronVarsN, kit.NotBitFlag, nil) - -func (ev NeuronVars) MarshalJSON() ([]byte, error) { return kit.EnumMarshalJSON(ev) } -func (ev *NeuronVars) UnmarshalJSON(b []byte) error { return kit.EnumUnmarshalJSON(ev, b) } - -var KiT_NeuronAvgVars = kit.Enums.AddEnum(NeuronAvgVarsN, kit.NotBitFlag, nil) - -func (ev NeuronAvgVars) MarshalJSON() ([]byte, error) { return kit.EnumMarshalJSON(ev) } -func (ev *NeuronAvgVars) UnmarshalJSON(b []byte) error { return kit.EnumUnmarshalJSON(ev, b) } - -var KiT_NeuronIdxs = kit.Enums.AddEnum(NeuronIdxsN, kit.NotBitFlag, nil) - -func (ev NeuronIdxs) MarshalJSON() ([]byte, error) { return kit.EnumMarshalJSON(ev) } -func (ev *NeuronIdxs) UnmarshalJSON(b []byte) error { return kit.EnumUnmarshalJSON(ev, b) } - //gosl: start neuron // NeuronFlags are bit-flags encoding relevant binary state for neurons -type NeuronFlags int32 +type NeuronFlags int32 //enums:enum // The neuron flags const ( @@ -55,7 +34,7 @@ const ( // NeuronVars are the neuron variables representing current active state, // specific to each input data state. // See NeuronAvgVars for vars shared across data. -type NeuronVars int32 +type NeuronVars int32 //enums:enum const ( ///////////////////////////////////////// @@ -339,9 +318,76 @@ const ( // and are writable (indexes are read only). NrnFlags - NeuronVarsN + // IMPORTANT: if NrnFlags is not the last, need to update gosl defn below ) +// NeuronAvgVars are mostly neuron variables involved in longer-term average activity +// which is aggregated over time and not specific to each input data state, +// along with any other state that is not input data specific. +type NeuronAvgVars int32 //enums:enum + +const ( + // ActAvg is average activation (of minus phase activation state) over long time intervals (time constant = Dt.LongAvgTau) -- useful for finding hog units and seeing overall distribution of activation + ActAvg NeuronAvgVars = iota + + // AvgPct is ActAvg as a proportion of overall layer activation -- this is used for synaptic scaling to match TrgAvg activation -- updated at SlowInterval intervals + AvgPct + + // TrgAvg is neuron's target average activation as a proportion of overall layer activation, assigned during weight initialization, driving synaptic scaling relative to AvgPct + TrgAvg + + // DTrgAvg is change in neuron's target average activation as a result of unit-wise error gradient -- acts like a bias weight. MPI needs to share these across processors. + DTrgAvg + + // AvgDif is AvgPct - TrgAvg -- i.e., the error in overall activity level relative to set point for this neuron, which drives synaptic scaling -- updated at SlowInterval intervals + AvgDif + + // GeBase is baseline level of Ge, added to GeRaw, for intrinsic excitability + GeBase + + // GiBase is baseline level of Gi, added to GiRaw, for intrinsic excitability + GiBase + + // IMPORTANT: if GiBase is not the last, need to update gosl defn below +) + +// NeuronIdxs are the neuron indexes and other uint32 values. +// There is only one of these per neuron -- not data parallel. +// note: Flags are encoded in Vars because they are data parallel and +// writable, whereas indexes are read-only. +type NeuronIdxs int32 //enums:enum + +const ( + // NrnNeurIdx is the index of this neuron within its owning layer + NrnNeurIdx NeuronIdxs = iota + + // NrnLayIdx is the index of the layer that this neuron belongs to, + // needed for neuron-level parallel code. + NrnLayIdx + + // NrnSubPool is the index of the sub-level inhibitory pool for this neuron + // (only for 4D shapes, the pool (unit-group / hypercolumn) structure level). + // Indicies start at 1 -- 0 is layer-level pool (is 0 if no sub-pools). + NrnSubPool + + // IMPORTANT: if NrnSubPool is not the last, need to update gosl defn below +) + +//gosl: end neuron + +//gosl: hlsl neuron +/* +static const NeuronVars NeuronVarsN = NrnFlags + 1; +static const NeuronAvgVars NeuronAvgVarsN = GiBase + 1; +static const NeuronIdxs NeuronIdxsN = NrnSubPool + 1; +*/ +//gosl: end neuron + +//gosl: start neuron + +//////////////////////////////////////////////// +// Strides + // NeuronVarStrides encodes the stride offsets for neuron variable access // into network float32 array. Data is always the inner-most variable. type NeuronVarStrides struct { @@ -377,36 +423,6 @@ func (ns *NeuronVarStrides) SetVarOuter(nneur, ndata int) { //////////////////////////////////////////////// // NeuronAvgVars -// NeuronAvgVars are mostly neuron variables involved in longer-term average activity -// which is aggregated over time and not specific to each input data state, -// along with any other state that is not input data specific. -type NeuronAvgVars int32 - -const ( - // ActAvg is average activation (of minus phase activation state) over long time intervals (time constant = Dt.LongAvgTau) -- useful for finding hog units and seeing overall distribution of activation - ActAvg NeuronAvgVars = iota - - // AvgPct is ActAvg as a proportion of overall layer activation -- this is used for synaptic scaling to match TrgAvg activation -- updated at SlowInterval intervals - AvgPct - - // TrgAvg is neuron's target average activation as a proportion of overall layer activation, assigned during weight initialization, driving synaptic scaling relative to AvgPct - TrgAvg - - // DTrgAvg is change in neuron's target average activation as a result of unit-wise error gradient -- acts like a bias weight. MPI needs to share these across processors. - DTrgAvg - - // AvgDif is AvgPct - TrgAvg -- i.e., the error in overall activity level relative to set point for this neuron, which drives synaptic scaling -- updated at SlowInterval intervals - AvgDif - - // GeBase is baseline level of Ge, added to GeRaw, for intrinsic excitability - GeBase - - // GiBase is baseline level of Gi, added to GiRaw, for intrinsic excitability - GiBase - - NeuronAvgVarsN -) - // NeuronAvgVarStrides encodes the stride offsets for neuron variable access // into network float32 array. Data is always the inner-most variable. type NeuronAvgVarStrides struct { @@ -442,28 +458,6 @@ func (ns *NeuronAvgVarStrides) SetVarOuter(nneur int) { //////////////////////////////////////////////// // Idxs -// NeuronIdxs are the neuron indexes and other uint32 values. -// There is only one of these per neuron -- not data parallel. -// note: Flags are encoded in Vars because they are data parallel and -// writable, whereas indexes are read-only. -type NeuronIdxs int32 - -const ( - // NrnNeurIdx is the index of this neuron within its owning layer - NrnNeurIdx NeuronIdxs = iota - - // NrnLayIdx is the index of the layer that this neuron belongs to, - // needed for neuron-level parallel code. - NrnLayIdx - - // NrnSubPool is the index of the sub-level inhibitory pool for this neuron - // (only for 4D shapes, the pool (unit-group / hypercolumn) structure level). - // Indicies start at 1 -- 0 is layer-level pool (is 0 if no sub-pools). - NrnSubPool - - NeuronIdxsN -) - // NeuronIdxStrides encodes the stride offsets for neuron index access // into network uint32 array. type NeuronIdxStrides struct { @@ -500,6 +494,9 @@ func (ns *NeuronIdxStrides) SetIdxOuter(nneur int) { //gosl: end neuron +//////////////////////////////////////////////// +// Props + // NeuronVarProps has all of the display properties for neuron variables, including desc tooltips var NeuronVarProps = map[string]string{ ///////////////////////////////////////// diff --git a/axon/neuronavgvars_string.go b/axon/neuronavgvars_string.go deleted file mode 100644 index d50bbb399..000000000 --- a/axon/neuronavgvars_string.go +++ /dev/null @@ -1,63 +0,0 @@ -// Code generated by "stringer -type=NeuronAvgVars"; DO NOT EDIT. - -package axon - -import ( - "errors" - "strconv" -) - -var _ = errors.New("dummy error") - -func _() { - // An "invalid array index" compiler error signifies that the constant values have changed. - // Re-run the stringer command to generate them again. - var x [1]struct{} - _ = x[ActAvg-0] - _ = x[AvgPct-1] - _ = x[TrgAvg-2] - _ = x[DTrgAvg-3] - _ = x[AvgDif-4] - _ = x[GeBase-5] - _ = x[GiBase-6] - _ = x[NeuronAvgVarsN-7] -} - -const _NeuronAvgVars_name = "ActAvgAvgPctTrgAvgDTrgAvgAvgDifGeBaseGiBaseNeuronAvgVarsN" - -var _NeuronAvgVars_index = [...]uint8{0, 6, 12, 18, 25, 31, 37, 43, 57} - -func (i NeuronAvgVars) String() string { - if i < 0 || i >= NeuronAvgVars(len(_NeuronAvgVars_index)-1) { - return "NeuronAvgVars(" + strconv.FormatInt(int64(i), 10) + ")" - } - return _NeuronAvgVars_name[_NeuronAvgVars_index[i]:_NeuronAvgVars_index[i+1]] -} - -func (i *NeuronAvgVars) FromString(s string) error { - for j := 0; j < len(_NeuronAvgVars_index)-1; j++ { - if s == _NeuronAvgVars_name[_NeuronAvgVars_index[j]:_NeuronAvgVars_index[j+1]] { - *i = NeuronAvgVars(j) - return nil - } - } - return errors.New("String: " + s + " is not a valid option for type: NeuronAvgVars") -} - -var _NeuronAvgVars_descMap = map[NeuronAvgVars]string{ - 0: `ActAvg is average activation (of minus phase activation state) over long time intervals (time constant = Dt.LongAvgTau) -- useful for finding hog units and seeing overall distribution of activation`, - 1: `AvgPct is ActAvg as a proportion of overall layer activation -- this is used for synaptic scaling to match TrgAvg activation -- updated at SlowInterval intervals`, - 2: `TrgAvg is neuron's target average activation as a proportion of overall layer activation, assigned during weight initialization, driving synaptic scaling relative to AvgPct`, - 3: `DTrgAvg is change in neuron's target average activation as a result of unit-wise error gradient -- acts like a bias weight. MPI needs to share these across processors.`, - 4: `AvgDif is AvgPct - TrgAvg -- i.e., the error in overall activity level relative to set point for this neuron, which drives synaptic scaling -- updated at SlowInterval intervals`, - 5: `GeBase is baseline level of Ge, added to GeRaw, for intrinsic excitability`, - 6: `GiBase is baseline level of Gi, added to GiRaw, for intrinsic excitability`, - 7: ``, -} - -func (i NeuronAvgVars) Desc() string { - if str, ok := _NeuronAvgVars_descMap[i]; ok { - return str - } - return "NeuronAvgVars(" + strconv.FormatInt(int64(i), 10) + ")" -} diff --git a/axon/neuronflags_string.go b/axon/neuronflags_string.go deleted file mode 100644 index 4437e3a04..000000000 --- a/axon/neuronflags_string.go +++ /dev/null @@ -1,58 +0,0 @@ -// Code generated by "stringer -type=NeuronFlags"; DO NOT EDIT. - -package axon - -import ( - "errors" - "strconv" -) - -var _ = errors.New("dummy error") - -func _() { - // An "invalid array index" compiler error signifies that the constant values have changed. - // Re-run the stringer command to generate them again. - var x [1]struct{} - _ = x[NeuronOff-1] - _ = x[NeuronHasExt-2] - _ = x[NeuronHasTarg-4] - _ = x[NeuronHasCmpr-8] -} - -const ( - _NeuronFlags_name_0 = "NeuronOffNeuronHasExt" - _NeuronFlags_name_1 = "NeuronHasTarg" - _NeuronFlags_name_2 = "NeuronHasCmpr" -) - -var ( - _NeuronFlags_index_0 = [...]uint8{0, 9, 21} -) - -func (i NeuronFlags) String() string { - switch { - case 1 <= i && i <= 2: - i -= 1 - return _NeuronFlags_name_0[_NeuronFlags_index_0[i]:_NeuronFlags_index_0[i+1]] - case i == 4: - return _NeuronFlags_name_1 - case i == 8: - return _NeuronFlags_name_2 - default: - return "NeuronFlags(" + strconv.FormatInt(int64(i), 10) + ")" - } -} - -var _NeuronFlags_descMap = map[NeuronFlags]string{ - 1: `NeuronOff flag indicates that this neuron has been turned off (i.e., lesioned)`, - 2: `NeuronHasExt means the neuron has external input in its Ext field`, - 4: `NeuronHasTarg means the neuron has external target input in its Target field`, - 8: `NeuronHasCmpr means the neuron has external comparison input in its Target field -- used for computing comparison statistics but does not drive neural activity ever`, -} - -func (i NeuronFlags) Desc() string { - if str, ok := _NeuronFlags_descMap[i]; ok { - return str - } - return "NeuronFlags(" + strconv.FormatInt(int64(i), 10) + ")" -} diff --git a/axon/neuronidxs_string.go b/axon/neuronidxs_string.go deleted file mode 100644 index d0bf3358b..000000000 --- a/axon/neuronidxs_string.go +++ /dev/null @@ -1,55 +0,0 @@ -// Code generated by "stringer -type=NeuronIdxs"; DO NOT EDIT. - -package axon - -import ( - "errors" - "strconv" -) - -var _ = errors.New("dummy error") - -func _() { - // An "invalid array index" compiler error signifies that the constant values have changed. - // Re-run the stringer command to generate them again. - var x [1]struct{} - _ = x[NrnNeurIdx-0] - _ = x[NrnLayIdx-1] - _ = x[NrnSubPool-2] - _ = x[NeuronIdxsN-3] -} - -const _NeuronIdxs_name = "NrnNeurIdxNrnLayIdxNrnSubPoolNeuronIdxsN" - -var _NeuronIdxs_index = [...]uint8{0, 10, 19, 29, 40} - -func (i NeuronIdxs) String() string { - if i < 0 || i >= NeuronIdxs(len(_NeuronIdxs_index)-1) { - return "NeuronIdxs(" + strconv.FormatInt(int64(i), 10) + ")" - } - return _NeuronIdxs_name[_NeuronIdxs_index[i]:_NeuronIdxs_index[i+1]] -} - -func (i *NeuronIdxs) FromString(s string) error { - for j := 0; j < len(_NeuronIdxs_index)-1; j++ { - if s == _NeuronIdxs_name[_NeuronIdxs_index[j]:_NeuronIdxs_index[j+1]] { - *i = NeuronIdxs(j) - return nil - } - } - return errors.New("String: " + s + " is not a valid option for type: NeuronIdxs") -} - -var _NeuronIdxs_descMap = map[NeuronIdxs]string{ - 0: `NrnNeurIdx is the index of this neuron within its owning layer`, - 1: `NrnLayIdx is the index of the layer that this neuron belongs to, needed for neuron-level parallel code.`, - 2: `NrnSubPool is the index of the sub-level inhibitory pool for this neuron (only for 4D shapes, the pool (unit-group / hypercolumn) structure level). Indicies start at 1 -- 0 is layer-level pool (is 0 if no sub-pools).`, - 3: ``, -} - -func (i NeuronIdxs) Desc() string { - if str, ok := _NeuronIdxs_descMap[i]; ok { - return str - } - return "NeuronIdxs(" + strconv.FormatInt(int64(i), 10) + ")" -} diff --git a/axon/neuronvars_string.go b/axon/neuronvars_string.go deleted file mode 100644 index 2fa0d8ee5..000000000 --- a/axon/neuronvars_string.go +++ /dev/null @@ -1,209 +0,0 @@ -// Code generated by "stringer -type=NeuronVars"; DO NOT EDIT. - -package axon - -import ( - "errors" - "strconv" -) - -var _ = errors.New("dummy error") - -func _() { - // An "invalid array index" compiler error signifies that the constant values have changed. - // Re-run the stringer command to generate them again. - var x [1]struct{} - _ = x[Spike-0] - _ = x[Spiked-1] - _ = x[Act-2] - _ = x[ActInt-3] - _ = x[ActM-4] - _ = x[ActP-5] - _ = x[Ext-6] - _ = x[Target-7] - _ = x[Ge-8] - _ = x[Gi-9] - _ = x[Gk-10] - _ = x[Inet-11] - _ = x[Vm-12] - _ = x[VmDend-13] - _ = x[ISI-14] - _ = x[ISIAvg-15] - _ = x[CaSpkP-16] - _ = x[CaSpkD-17] - _ = x[CaSyn-18] - _ = x[CaSpkM-19] - _ = x[CaSpkPM-20] - _ = x[CaLrn-21] - _ = x[NrnCaM-22] - _ = x[NrnCaP-23] - _ = x[NrnCaD-24] - _ = x[CaDiff-25] - _ = x[Attn-26] - _ = x[RLRate-27] - _ = x[SpkMaxCa-28] - _ = x[SpkMax-29] - _ = x[SpkPrv-30] - _ = x[SpkSt1-31] - _ = x[SpkSt2-32] - _ = x[GeNoiseP-33] - _ = x[GeNoise-34] - _ = x[GiNoiseP-35] - _ = x[GiNoise-36] - _ = x[GeExt-37] - _ = x[GeRaw-38] - _ = x[GeSyn-39] - _ = x[GiRaw-40] - _ = x[GiSyn-41] - _ = x[GeInt-42] - _ = x[GeIntNorm-43] - _ = x[GiInt-44] - _ = x[GModRaw-45] - _ = x[GModSyn-46] - _ = x[GMaintRaw-47] - _ = x[GMaintSyn-48] - _ = x[SSGi-49] - _ = x[SSGiDend-50] - _ = x[Gak-51] - _ = x[MahpN-52] - _ = x[SahpCa-53] - _ = x[SahpN-54] - _ = x[GknaMed-55] - _ = x[GknaSlow-56] - _ = x[GnmdaSyn-57] - _ = x[Gnmda-58] - _ = x[GnmdaMaint-59] - _ = x[GnmdaLrn-60] - _ = x[NmdaCa-61] - _ = x[GgabaB-62] - _ = x[GABAB-63] - _ = x[GABABx-64] - _ = x[Gvgcc-65] - _ = x[VgccM-66] - _ = x[VgccH-67] - _ = x[VgccCa-68] - _ = x[VgccCaInt-69] - _ = x[SKCaIn-70] - _ = x[SKCaR-71] - _ = x[SKCaM-72] - _ = x[Gsk-73] - _ = x[Burst-74] - _ = x[BurstPrv-75] - _ = x[CtxtGe-76] - _ = x[CtxtGeRaw-77] - _ = x[CtxtGeOrig-78] - _ = x[NrnFlags-79] - _ = x[NeuronVarsN-80] -} - -const _NeuronVars_name = "SpikeSpikedActActIntActMActPExtTargetGeGiGkInetVmVmDendISIISIAvgCaSpkPCaSpkDCaSynCaSpkMCaSpkPMCaLrnNrnCaMNrnCaPNrnCaDCaDiffAttnRLRateSpkMaxCaSpkMaxSpkPrvSpkSt1SpkSt2GeNoisePGeNoiseGiNoisePGiNoiseGeExtGeRawGeSynGiRawGiSynGeIntGeIntNormGiIntGModRawGModSynGMaintRawGMaintSynSSGiSSGiDendGakMahpNSahpCaSahpNGknaMedGknaSlowGnmdaSynGnmdaGnmdaMaintGnmdaLrnNmdaCaGgabaBGABABGABABxGvgccVgccMVgccHVgccCaVgccCaIntSKCaInSKCaRSKCaMGskBurstBurstPrvCtxtGeCtxtGeRawCtxtGeOrigNrnFlagsNeuronVarsN" - -var _NeuronVars_index = [...]uint16{0, 5, 11, 14, 20, 24, 28, 31, 37, 39, 41, 43, 47, 49, 55, 58, 64, 70, 76, 81, 87, 94, 99, 105, 111, 117, 123, 127, 133, 141, 147, 153, 159, 165, 173, 180, 188, 195, 200, 205, 210, 215, 220, 225, 234, 239, 246, 253, 262, 271, 275, 283, 286, 291, 297, 302, 309, 317, 325, 330, 340, 348, 354, 360, 365, 371, 376, 381, 386, 392, 401, 407, 412, 417, 420, 425, 433, 439, 448, 458, 466, 477} - -func (i NeuronVars) String() string { - if i < 0 || i >= NeuronVars(len(_NeuronVars_index)-1) { - return "NeuronVars(" + strconv.FormatInt(int64(i), 10) + ")" - } - return _NeuronVars_name[_NeuronVars_index[i]:_NeuronVars_index[i+1]] -} - -func (i *NeuronVars) FromString(s string) error { - for j := 0; j < len(_NeuronVars_index)-1; j++ { - if s == _NeuronVars_name[_NeuronVars_index[j]:_NeuronVars_index[j+1]] { - *i = NeuronVars(j) - return nil - } - } - return errors.New("String: " + s + " is not a valid option for type: NeuronVars") -} - -var _NeuronVars_descMap = map[NeuronVars]string{ - 0: `Spike is whether neuron has spiked or not on this cycle (0 or 1)`, - 1: `Spiked is 1 if neuron has spiked within the last 10 cycles (msecs), corresponding to a nominal max spiking rate of 100 Hz, 0 otherwise -- useful for visualization and computing activity levels in terms of average spiked levels.`, - 2: `Act is rate-coded activation value reflecting instantaneous estimated rate of spiking, based on 1 / ISIAvg. This drives feedback inhibition in the FFFB function (todo: this will change when better inhibition is implemented), and is integrated over time for ActInt which is then used for performance statistics and layer average activations, etc. Should not be used for learning or other computations.`, - 3: `ActInt is integrated running-average activation value computed from Act with time constant Act.Dt.IntTau, to produce a longer-term integrated value reflecting the overall activation state across the ThetaCycle time scale, as the overall response of network to current input state -- this is copied to ActM and ActP at the ends of the minus and plus phases, respectively, and used in computing performance-level statistics (which are typically based on ActM). Should not be used for learning or other computations.`, - 4: `ActM is ActInt activation state at end of third quarter, representing the posterior-cortical minus phase activation -- used for statistics and monitoring network performance. Should not be used for learning or other computations.`, - 5: `ActP is ActInt activation state at end of fourth quarter, representing the posterior-cortical plus_phase activation -- used for statistics and monitoring network performance. Should not be used for learning or other computations.`, - 6: `Ext is external input: drives activation of unit from outside influences (e.g., sensory input)`, - 7: `Target is the target value: drives learning to produce this activation value`, - 8: `Ge is total excitatory conductance, including all forms of excitation (e.g., NMDA) -- does *not* include Gbar.E`, - 9: `Gi is total inhibitory synaptic conductance -- the net inhibitory input to the neuron -- does *not* include Gbar.I`, - 10: `Gk is total potassium conductance, typically reflecting sodium-gated potassium currents involved in adaptation effects -- does *not* include Gbar.K`, - 11: `Inet is net current produced by all channels -- drives update of Vm`, - 12: `Vm is membrane potential -- integrates Inet current over time`, - 13: `VmDend is dendritic membrane potential -- has a slower time constant, is not subject to the VmR reset after spiking`, - 14: `ISI is current inter-spike-interval -- counts up since last spike. Starts at -1 when initialized.`, - 15: `ISIAvg is average inter-spike-interval -- average time interval between spikes, integrated with ISITau rate constant (relatively fast) to capture something close to an instantaneous spiking rate. Starts at -1 when initialized, and goes to -2 after first spike, and is only valid after the second spike post-initialization.`, - 16: `CaSpkP is continuous cascaded integration of CaSpkM at PTau time constant (typically 40), representing neuron-level purely spiking version of plus, LTP direction of weight change and capturing the function of CaMKII in the Kinase learning rule. Used for specialized learning and computational functions, statistics, instead of Act.`, - 17: `CaSpkD is continuous cascaded integration CaSpkP at DTau time constant (typically 40), representing neuron-level purely spiking version of minus, LTD direction of weight change and capturing the function of DAPK1 in the Kinase learning rule. Used for specialized learning and computational functions, statistics, instead of Act.`, - 18: `CaSyn is spike-driven calcium trace for synapse-level Ca-driven learning: exponential integration of SpikeG * Spike at SynTau time constant (typically 30). Synapses integrate send.CaSyn * recv.CaSyn across M, P, D time integrals for the synaptic trace driving credit assignment in learning. Time constant reflects binding time of Glu to NMDA and Ca buffering postsynaptically, and determines time window where pre * post spiking must overlap to drive learning.`, - 19: `CaSpkM is spike-driven calcium trace used as a neuron-level proxy for synpatic credit assignment factor based on continuous time-integrated spiking: exponential integration of SpikeG * Spike at MTau time constant (typically 5). Simulates a calmodulin (CaM) like signal at the most abstract level.`, - 20: `CaSpkPM is minus-phase snapshot of the CaSpkP value -- similar to ActM but using a more directly spike-integrated value.`, - 21: `CaLrn is recv neuron calcium signal used to drive temporal error difference component of standard learning rule, combining NMDA (NmdaCa) and spiking-driven VGCC (VgccCaInt) calcium sources (vs. CaSpk* which only reflects spiking component). This is integrated into CaM, CaP, CaD, and temporal derivative is CaP - CaD (CaMKII - DAPK1). This approximates the backprop error derivative on net input, but VGCC component adds a proportion of recv activation delta as well -- a balance of both works best. The synaptic-level trace multiplier provides the credit assignment factor, reflecting coincident activity and potentially integrated over longer multi-trial timescales.`, - 22: `NrnCaM is integrated CaLrn at MTau timescale (typically 5), simulating a calmodulin (CaM) like signal, which then drives CaP, CaD for delta signal driving error-driven learning.`, - 23: `NrnCaP is cascaded integration of CaM at PTau time constant (typically 40), representing the plus, LTP direction of weight change and capturing the function of CaMKII in the Kinase learning rule.`, - 24: `NrnCaD is cascaded integratoin of CaP at DTau time constant (typically 40), representing the minus, LTD direction of weight change and capturing the function of DAPK1 in the Kinase learning rule.`, - 25: `CaDiff is difference between CaP - CaD -- this is the error signal that drives error-driven learning.`, - 26: `Attn is Attentional modulation factor, which can be set by special layers such as the TRC -- multiplies Ge`, - 27: `RLRate is recv-unit based learning rate multiplier, reflecting the sigmoid derivative computed from the CaSpkD of recv unit, and the normalized difference CaSpkP - CaSpkD / MAX(CaSpkP - CaSpkD).`, - 28: `SpkMaxCa is Ca integrated like CaSpkP but only starting at MaxCycStart cycle, to prevent inclusion of carryover spiking from prior theta cycle trial -- the PTau time constant otherwise results in significant carryover. This is the input to SpkMax`, - 29: `SpkMax is maximum CaSpkP across one theta cycle time window (max of SpkMaxCa) -- used for specialized algorithms that have more phasic behavior within a single trial, e.g., BG Matrix layer gating. Also useful for visualization of peak activity of neurons.`, - 30: `SpkPrv is final CaSpkD activation state at end of previous theta cycle. used for specialized learning mechanisms that operate on delayed sending activations.`, - 31: `SpkSt1 is the activation state at specific time point within current state processing window (e.g., 50 msec for beta cycle within standard theta cycle), as saved by SpkSt1() function. Used for example in hippocampus for CA3, CA1 learning`, - 32: `SpkSt2 is the activation state at specific time point within current state processing window (e.g., 100 msec for beta cycle within standard theta cycle), as saved by SpkSt2() function. Used for example in hippocampus for CA3, CA1 learning`, - 33: `GeNoiseP is accumulating poisson probability factor for driving excitatory noise spiking -- multiply times uniform random deviate at each time step, until it gets below the target threshold based on lambda.`, - 34: `GeNoise is integrated noise excitatory conductance, added into Ge`, - 35: `GiNoiseP is accumulating poisson probability factor for driving inhibitory noise spiking -- multiply times uniform random deviate at each time step, until it gets below the target threshold based on lambda.`, - 36: `GiNoise is integrated noise inhibotyr conductance, added into Gi`, - 37: `GeExt is extra excitatory conductance added to Ge -- from Ext input, GeCtxt etc`, - 38: `GeRaw is raw excitatory conductance (net input) received from senders = current raw spiking drive`, - 39: `GeSyn is time-integrated total excitatory synaptic conductance, with an instantaneous rise time from each spike (in GeRaw) and exponential decay with Dt.GeTau, aggregated over projections -- does *not* include Gbar.E`, - 40: `GiRaw is raw inhibitory conductance (net input) received from senders = current raw spiking drive`, - 41: `GiSyn is time-integrated total inhibitory synaptic conductance, with an instantaneous rise time from each spike (in GiRaw) and exponential decay with Dt.GiTau, aggregated over projections -- does *not* include Gbar.I. This is added with computed FFFB inhibition to get the full inhibition in Gi`, - 42: `GeInt is integrated running-average activation value computed from Ge with time constant Act.Dt.IntTau, to produce a longer-term integrated value reflecting the overall Ge level across the ThetaCycle time scale (Ge itself fluctuates considerably) -- useful for stats to set strength of connections etc to get neurons into right range of overall excitatory drive`, - 43: `GeIntNorm is normalized GeInt value (divided by the layer maximum) -- this is used for learning in layers that require learning on subthreshold activity`, - 44: `GiInt is integrated running-average activation value computed from GiSyn with time constant Act.Dt.IntTau, to produce a longer-term integrated value reflecting the overall synaptic Gi level across the ThetaCycle time scale (Gi itself fluctuates considerably) -- useful for stats to set strength of connections etc to get neurons into right range of overall inhibitory drive`, - 45: `GModRaw is raw modulatory conductance, received from GType = ModulatoryG projections`, - 46: `GModSyn is syn integrated modulatory conductance, received from GType = ModulatoryG projections`, - 47: `GMaintRaw is raw maintenance conductance, received from GType = MaintG projections`, - 48: `GMaintSyn is syn integrated maintenance conductance, integrated using MaintNMDA params.`, - 49: `SSGi is SST+ somatostatin positive slow spiking inhibition`, - 50: `SSGiDend is amount of SST+ somatostatin positive slow spiking inhibition applied to dendritic Vm (VmDend)`, - 51: `Gak is conductance of A-type K potassium channels`, - 52: `MahpN is accumulating voltage-gated gating value for the medium time scale AHP`, - 53: `SahpCa is slowly accumulating calcium value that drives the slow AHP`, - 54: `SahpN is sAHP gating value`, - 55: `GknaMed is conductance of sodium-gated potassium channel (KNa) medium dynamics (Slick) -- produces accommodation / adaptation of firing`, - 56: `GknaSlow is conductance of sodium-gated potassium channel (KNa) slow dynamics (Slack) -- produces accommodation / adaptation of firing`, - 57: `GnmdaSyn is integrated NMDA recv synaptic current -- adds GeRaw and decays with time constant`, - 58: `Gnmda is net postsynaptic (recv) NMDA conductance, after Mg V-gating and Gbar -- added directly to Ge as it has the same reversal potential`, - 59: `GnmdaMaint is net postsynaptic maintenance NMDA conductance, computed from GMaintSyn and GMaintRaw, after Mg V-gating and Gbar -- added directly to Ge as it has the same reversal potential`, - 60: `GnmdaLrn is learning version of integrated NMDA recv synaptic current -- adds GeRaw and decays with time constant -- drives NmdaCa that then drives CaM for learning`, - 61: `NmdaCa is NMDA calcium computed from GnmdaLrn, drives learning via CaM`, - 62: `GgabaB is net GABA-B conductance, after Vm gating and Gbar + Gbase -- applies to Gk, not Gi, for GIRK, with .1 reversal potential.`, - 63: `GABAB is GABA-B / GIRK activation -- time-integrated value with rise and decay time constants`, - 64: `GABABx is GABA-B / GIRK internal drive variable -- gets the raw activation and decays`, - 65: `Gvgcc is conductance (via Ca) for VGCC voltage gated calcium channels`, - 66: `VgccM is activation gate of VGCC channels`, - 67: `VgccH inactivation gate of VGCC channels`, - 68: `VgccCa is instantaneous VGCC calcium flux -- can be driven by spiking or directly from Gvgcc`, - 69: `VgccCaInt time-integrated VGCC calcium flux -- this is actually what drives learning`, - 70: `SKCaIn is intracellular calcium store level, available to be released with spiking as SKCaR, which can bind to SKCa receptors and drive K current. replenishment is a function of spiking activity being below a threshold`, - 71: `SKCaR released amount of intracellular calcium, from SKCaIn, as a function of spiking events. this can bind to SKCa channels and drive K currents.`, - 72: `SKCaM is Calcium-gated potassium channel gating factor, driven by SKCaR via a Hill equation as in chans.SKPCaParams.`, - 73: `Gsk is Calcium-gated potassium channel conductance as a function of Gbar * SKCaM.`, - 74: `Burst is 5IB bursting activation value, computed by thresholding regular CaSpkP value in Super superficial layers`, - 75: `BurstPrv is previous Burst bursting activation from prior time step -- used for context-based learning`, - 76: `CtxtGe is context (temporally delayed) excitatory conductance, driven by deep bursting at end of the plus phase, for CT layers.`, - 77: `CtxtGeRaw is raw update of context (temporally delayed) excitatory conductance, driven by deep bursting at end of the plus phase, for CT layers.`, - 78: `CtxtGeOrig is original CtxtGe value prior to any decay factor -- updates at end of plus phase.`, - 79: `NrnFlags are bit flags for binary state variables, which are converted to / from uint32. These need to be in Vars because they can be differential per data (for ext inputs) and are writable (indexes are read only).`, - 80: ``, -} - -func (i NeuronVars) Desc() string { - if str, ok := _NeuronVars_descMap[i]; ok { - return str - } - return "NeuronVars(" + strconv.FormatInt(int64(i), 10) + ")" -} diff --git a/axon/pcore_layers.go b/axon/pcore_layers.go index 56bba03c0..9ab3d3aea 100644 --- a/axon/pcore_layers.go +++ b/axon/pcore_layers.go @@ -8,9 +8,8 @@ import ( "log" "strings" - "github.com/goki/gosl/slbool" - "github.com/goki/ki/kit" "goki.dev/glop/num" + "goki.dev/gosl/v2/slbool" ) //gosl: start pcore_layers @@ -61,7 +60,7 @@ func (mp *MatrixParams) Update() { } // GPLayerTypes is a GPLayer axon-specific layer type enum. -type GPLayerTypes int32 +type GPLayerTypes int32 //enums:enum // The GPLayer types const ( @@ -78,8 +77,6 @@ const ( // GPi is the inner globus pallidus, functionally equivalent to SNr, // receiving from MtxGo and GPeIn, and sending inhibition to VThal GPi - - GPLayerTypesN ) // GPLayer represents a globus pallidus layer, including: @@ -263,7 +260,7 @@ func (ly *Layer) MatrixPostBuild() { dm, err := ly.BuildConfigByName("DAMod") if err == nil { - err = ly.Params.Learn.NeuroMod.DAMod.FromString(dm) + err = ly.Params.Learn.NeuroMod.DAMod.SetString(dm) if err != nil { log.Println(err) } @@ -341,17 +338,10 @@ func (ly *Layer) GPiDefaults() { } } -//go:generate stringer -type=GPLayerTypes - -var KiT_GPLayerTypes = kit.Enums.AddEnum(GPLayerTypesN, kit.NotBitFlag, nil) - -func (ev GPLayerTypes) MarshalJSON() ([]byte, error) { return kit.EnumMarshalJSON(ev) } -func (ev *GPLayerTypes) UnmarshalJSON(b []byte) error { return kit.EnumUnmarshalJSON(ev, b) } - func (ly *Layer) GPPostBuild() { gpnm, err := ly.BuildConfigByName("GPType") if err == nil { - err = ly.Params.GP.GPType.FromString(gpnm) + err = ly.Params.GP.GPType.SetString(gpnm) if err != nil { log.Println(err) } diff --git a/axon/pool.go b/axon/pool.go index 672c2914e..f0dea04ad 100644 --- a/axon/pool.go +++ b/axon/pool.go @@ -6,7 +6,7 @@ package axon import ( "github.com/emer/axon/fsfffb" - "github.com/goki/gosl/slbool" + "goki.dev/gosl/v2/slbool" "goki.dev/mat32/v2" ) diff --git a/axon/prjn.go b/axon/prjn.go index f8e1cd076..c95721ccb 100644 --- a/axon/prjn.go +++ b/axon/prjn.go @@ -11,10 +11,8 @@ import ( "github.com/emer/emergent/v2/erand" "github.com/emer/emergent/v2/weights" - "github.com/goki/ki/indent" - "github.com/goki/ki/ki" - "github.com/goki/ki/kit" "goki.dev/etable/v2/etensor" + "goki.dev/glop/indent" ) // https://github.com/kisvegabor/abbreviations-in-code suggests Buf instead of Buff @@ -31,8 +29,6 @@ type Prjn struct { Params *PrjnParams } -var KiT_Prjn = kit.Types.AddType(&Prjn{}, PrjnProps) - // Object returns the object with parameters to be set by emer.Params func (pj *Prjn) Object() any { return pj.Params @@ -538,7 +534,3 @@ func (pj *Prjn) InitGBuffs() { pj.GSyns[ri] = 0 } } - -var PrjnProps = ki.Props{ - "EnumType:Typ": KiT_PrjnTypes, // uses our PrjnTypes for GUI -} diff --git a/axon/prjn_compute.go b/axon/prjn_compute.go index 6111a686d..ae89030d5 100644 --- a/axon/prjn_compute.go +++ b/axon/prjn_compute.go @@ -188,8 +188,8 @@ func (pj *Prjn) SWtFmWt(ctx *Context) { if rlay.Params.IsTarget() { return } - max := pj.Params.SWts.Limit.Max - min := pj.Params.SWts.Limit.Min + mx := pj.Params.SWts.Limit.Max + mn := pj.Params.SWts.Limit.Min lr := pj.Params.SWts.Adapt.LRate for lni := uint32(0); lni < rlay.NNeurons; lni++ { syIdxs := pj.RecvSynIdxs(lni) @@ -202,9 +202,9 @@ func (pj *Prjn) SWtFmWt(ctx *Context) { syni := pj.SynStIdx + syi swt := SynV(ctx, syni, SWt) if SynV(ctx, syni, DSWt) >= 0 { // softbound for SWt - MulSynV(ctx, syni, DSWt, (max - swt)) + MulSynV(ctx, syni, DSWt, (mx - swt)) } else { - MulSynV(ctx, syni, DSWt, (swt - min)) + MulSynV(ctx, syni, DSWt, (swt - mn)) } avgDWt += SynV(ctx, syni, DSWt) } diff --git a/axon/prjngtypes_string.go b/axon/prjngtypes_string.go deleted file mode 100644 index 48f4977ea..000000000 --- a/axon/prjngtypes_string.go +++ /dev/null @@ -1,59 +0,0 @@ -// Code generated by "stringer -type=PrjnGTypes"; DO NOT EDIT. - -package axon - -import ( - "errors" - "strconv" -) - -var _ = errors.New("dummy error") - -func _() { - // An "invalid array index" compiler error signifies that the constant values have changed. - // Re-run the stringer command to generate them again. - var x [1]struct{} - _ = x[ExcitatoryG-0] - _ = x[InhibitoryG-1] - _ = x[ModulatoryG-2] - _ = x[MaintG-3] - _ = x[ContextG-4] - _ = x[PrjnGTypesN-5] -} - -const _PrjnGTypes_name = "ExcitatoryGInhibitoryGModulatoryGMaintGContextGPrjnGTypesN" - -var _PrjnGTypes_index = [...]uint8{0, 11, 22, 33, 39, 47, 58} - -func (i PrjnGTypes) String() string { - if i < 0 || i >= PrjnGTypes(len(_PrjnGTypes_index)-1) { - return "PrjnGTypes(" + strconv.FormatInt(int64(i), 10) + ")" - } - return _PrjnGTypes_name[_PrjnGTypes_index[i]:_PrjnGTypes_index[i+1]] -} - -func (i *PrjnGTypes) FromString(s string) error { - for j := 0; j < len(_PrjnGTypes_index)-1; j++ { - if s == _PrjnGTypes_name[_PrjnGTypes_index[j]:_PrjnGTypes_index[j+1]] { - *i = PrjnGTypes(j) - return nil - } - } - return errors.New("String: " + s + " is not a valid option for type: PrjnGTypes") -} - -var _PrjnGTypes_descMap = map[PrjnGTypes]string{ - 0: `Excitatory projections drive Ge conductance on receiving neurons, which send to GiRaw and GiSyn neuron variables.`, - 1: `Inhibitory projections drive Gi inhibitory conductance, which send to GiRaw and GiSyn neuron variables.`, - 2: `Modulatory projections have a multiplicative effect on other inputs, which send to GModRaw and GModSyn neuron variables.`, - 3: `Maintenance projections drive unique set of NMDA channels that support strong active maintenance abilities. Send to GMaintRaw and GMaintSyn neuron variables.`, - 4: `Context projections are for inputs to CT layers, which update only at the end of the plus phase, and send to CtxtGe.`, - 5: ``, -} - -func (i PrjnGTypes) Desc() string { - if str, ok := _PrjnGTypes_descMap[i]; ok { - return str - } - return "PrjnGTypes(" + strconv.FormatInt(int64(i), 10) + ")" -} diff --git a/axon/prjntypes.go b/axon/prjntypes.go index 34fbbd03b..e718b17b8 100644 --- a/axon/prjntypes.go +++ b/axon/prjntypes.go @@ -4,15 +4,13 @@ package axon -import "github.com/goki/ki/kit" - //gosl: start prjntypes // PrjnTypes is an axon-specific prjn type enum, // that encompasses all the different algorithm types supported. // Class parameter styles automatically key off of these types. // The first entries must be kept synchronized with the emer.PrjnType. -type PrjnTypes int32 +type PrjnTypes int32 //enums:enum // The projection types const ( @@ -80,15 +78,6 @@ const ( // and subsequent outcomes, and is based biologically on synaptic tags. // Trace is reset at time of reward based on ACh level (from CINs in biology). MatrixPrjn - - PrjnTypesN ) //gosl: end prjntypes - -//go:generate stringer -type=PrjnTypes - -var KiT_PrjnTypes = kit.Enums.AddEnum(PrjnTypesN, kit.NotBitFlag, nil) - -func (ev PrjnTypes) MarshalJSON() ([]byte, error) { return kit.EnumMarshalJSON(ev) } -func (ev *PrjnTypes) UnmarshalJSON(b []byte) error { return kit.EnumUnmarshalJSON(ev, b) } diff --git a/axon/prjntypes_string.go b/axon/prjntypes_string.go deleted file mode 100644 index 46318703c..000000000 --- a/axon/prjntypes_string.go +++ /dev/null @@ -1,71 +0,0 @@ -// Code generated by "stringer -type=PrjnTypes"; DO NOT EDIT. - -package axon - -import ( - "errors" - "strconv" -) - -var _ = errors.New("dummy error") - -func _() { - // An "invalid array index" compiler error signifies that the constant values have changed. - // Re-run the stringer command to generate them again. - var x [1]struct{} - _ = x[ForwardPrjn-0] - _ = x[BackPrjn-1] - _ = x[LateralPrjn-2] - _ = x[InhibPrjn-3] - _ = x[CTCtxtPrjn-4] - _ = x[RWPrjn-5] - _ = x[TDPredPrjn-6] - _ = x[BLAPrjn-7] - _ = x[HipPrjn-8] - _ = x[VSPatchPrjn-9] - _ = x[MatrixPrjn-10] - _ = x[PrjnTypesN-11] -} - -const _PrjnTypes_name = "ForwardPrjnBackPrjnLateralPrjnInhibPrjnCTCtxtPrjnRWPrjnTDPredPrjnBLAPrjnHipPrjnVSPatchPrjnMatrixPrjnPrjnTypesN" - -var _PrjnTypes_index = [...]uint8{0, 11, 19, 30, 39, 49, 55, 65, 72, 79, 90, 100, 110} - -func (i PrjnTypes) String() string { - if i < 0 || i >= PrjnTypes(len(_PrjnTypes_index)-1) { - return "PrjnTypes(" + strconv.FormatInt(int64(i), 10) + ")" - } - return _PrjnTypes_name[_PrjnTypes_index[i]:_PrjnTypes_index[i+1]] -} - -func (i *PrjnTypes) FromString(s string) error { - for j := 0; j < len(_PrjnTypes_index)-1; j++ { - if s == _PrjnTypes_name[_PrjnTypes_index[j]:_PrjnTypes_index[j+1]] { - *i = PrjnTypes(j) - return nil - } - } - return errors.New("String: " + s + " is not a valid option for type: PrjnTypes") -} - -var _PrjnTypes_descMap = map[PrjnTypes]string{ - 0: `Forward is a feedforward, bottom-up projection from sensory inputs to higher layers`, - 1: `Back is a feedback, top-down projection from higher layers back to lower layers`, - 2: `Lateral is a lateral projection within the same layer / area`, - 3: `Inhib is an inhibitory projection that drives inhibitory synaptic conductances instead of the default excitatory ones.`, - 4: `CTCtxt are projections from Superficial layers to CT layers that send Burst activations drive updating of CtxtGe excitatory conductance, at end of plus (51B Bursting) phase. Biologically, this projection comes from the PT layer 5IB neurons, but it is simpler to use the Super neurons directly, and PT are optional for most network types. These projections also use a special learning rule that takes into account the temporal delays in the activation states. Can also add self context from CT for deeper temporal context.`, - 5: `RWPrjn does dopamine-modulated learning for reward prediction: Da * Send.CaSpkP (integrated current spiking activity). Uses RLPredPrjn parameters. Use in RWPredLayer typically to generate reward predictions. If the Da sign is positive, the first recv unit learns fully; for negative, second one learns fully. Lower lrate applies for opposite cases. Weights are positive-only.`, - 6: `TDPredPrjn does dopamine-modulated learning for reward prediction: DWt = Da * Send.SpkPrv (activity on *previous* timestep) Uses RLPredPrjn parameters. Use in TDPredLayer typically to generate reward predictions. If the Da sign is positive, the first recv unit learns fully; for negative, second one learns fully. Lower lrate applies for opposite cases. Weights are positive-only.`, - 7: `BLAPrjn implements the PVLV BLA learning rule: dW = ACh * X_t-1 * (Y_t - Y_t-1) The recv delta is across trials, where the US should activate on trial boundary, to enable sufficient time for gating through to OFC, so BLA initially learns based on US present - US absent. It can also learn based on CS onset if there is a prior CS that predicts that.`, - 8: ``, - 9: `VSPatchPrjn implements the VSPatch learning rule: dW = ACh * DA * X * Y where DA is D1 vs. D2 modulated DA level, X = sending activity factor, Y = receiving activity factor, and ACh provides overall modulation.`, - 10: `MatrixPrjn supports trace-based learning, where an initial trace of synaptic co-activity is formed, and then modulated by subsequent phasic dopamine & ACh when an outcome occurs. This bridges the temporal gap between gating activity and subsequent outcomes, and is based biologically on synaptic tags. Trace is reset at time of reward based on ACh level (from CINs in biology).`, - 11: ``, -} - -func (i PrjnTypes) Desc() string { - if str, ok := _PrjnTypes_descMap[i]; ok { - return str - } - return "PrjnTypes(" + strconv.FormatInt(int64(i), 10) + ")" -} diff --git a/axon/pvlv_layers.go b/axon/pvlv_layers.go index e48d16d2a..5220d14eb 100644 --- a/axon/pvlv_layers.go +++ b/axon/pvlv_layers.go @@ -8,7 +8,7 @@ import ( "log" "strings" - "github.com/goki/gosl/slbool" + "goki.dev/gosl/v2/slbool" "goki.dev/mat32/v2" ) @@ -261,14 +261,14 @@ func (ly *Layer) BLADefaults() { func (ly *Layer) PVLVPostBuild() { dm, err := ly.BuildConfigByName("DAMod") if err == nil { - err = ly.Params.Learn.NeuroMod.DAMod.FromString(dm) + err = ly.Params.Learn.NeuroMod.DAMod.SetString(dm) if err != nil { log.Println(err) } } vl, err := ly.BuildConfigByName("Valence") if err == nil { - err = ly.Params.Learn.NeuroMod.Valence.FromString(vl) + err = ly.Params.Learn.NeuroMod.Valence.SetString(vl) if err != nil { log.Println(err) } diff --git a/axon/rand.go b/axon/rand.go index 21821ed7c..937b1c5b5 100644 --- a/axon/rand.go +++ b/axon/rand.go @@ -1,7 +1,7 @@ package axon import ( - "github.com/goki/gosl/slrand" + "goki.dev/gosl/v2/slrand" ) //gosl: hlsl axonrand diff --git a/axon/shaders/Makefile b/axon/shaders/Makefile index 7fb7ba39d..408124029 100644 --- a/axon/shaders/Makefile +++ b/axon/shaders/Makefile @@ -2,7 +2,7 @@ # The go generate command does this automatically. all: - cd ../; gosl -exclude=Update,UpdateParams,Defaults,AllParams github.com/goki/mat32/fastexp.go github.com/emer/etable/minmax ../chans/chans.go ../chans ../kinase ../fsfffb/inhib.go ../fsfffb github.com/emer/emergent/etime github.com/emer/emergent/ringidx rand.go avgmax.go neuromod.go globals.go context.go neuron.go synapse.go pool.go layervals.go act.go act_prjn.go inhib.go learn.go layertypes.go layerparams.go deep_layers.go rl_layers.go pvlv_layers.go pcore_layers.go prjntypes.go prjnparams.go deep_prjns.go rl_prjns.go pvlv_prjns.go pcore_prjns.go hip_prjns.go gpu_hlsl + cd ../; gosl -exclude=Update,UpdateParams,Defaults,AllParams goki.dev/mat32/v2/fastexp.go goki.dev/etable/v2/minmax ../chans/chans.go ../chans ../kinase ../fsfffb/inhib.go ../fsfffb github.com/emer/emergent/v2/etime github.com/emer/emergent/v2/ringidx rand.go avgmax.go neuromod.go globals.go context.go neuron.go synapse.go pool.go layervals.go act.go act_prjn.go inhib.go learn.go layertypes.go layerparams.go deep_layers.go rl_layers.go pvlv_layers.go pcore_layers.go prjntypes.go prjnparams.go deep_prjns.go rl_prjns.go pvlv_prjns.go pcore_prjns.go hip_prjns.go gpu_hlsl # note: gosl automatically compiles the hlsl files using this command: %.spv : %.hlsl diff --git a/axon/shaders/gpu_applyext.spv b/axon/shaders/gpu_applyext.spv index dcc7577b26637f27989ce8d0f2397dc282eb77df..4e90ee168f4cfae0b8bfb68fc2377d2677b00908 100644 GIT binary patch delta 1158 zcmZvcyG~V66h+s)S0ohB@CC-oKcEp}Y#=Ba6>OxkptdI*3cdguD+&r@@QDhds9X>P zQRL|Z6f1s#_#h;XaXdS@ChlZr%{ABBYwmsag~7Sf{(PyiQa)K9QHqGB_&(7%do8;i z$D*73KDY;dL?s>&UB9WRKLlz&qnz{csLS_Epbdjg@QYgNF&;#H-t!3F1MUL*os~Qv zM~t-fp32g^DQeC;2b}kWsHZW_dkS}+9`;XyG;bPi-8(!Zy1aw>bD-utdGefz$a2$5 zh?=G*V={dK*VKcsAs?X0OSnrDdtL!GP2|qIQ{?Kkx%%JvXCr1wG;q^ZV6z5QqDupN z=0Fu_ARpo-x`^{58@(=QX>0Bbrg5nYGy z3&drht8uz`|F>}WTmkIKVg=&zxE9|5H8;w=zk|)yHF{5U9rAW-YK{P}=aUGlo4!H>2+zB+Z$G?CL;2YRuw8yuw$AfMXU0%-KEwBwd zjJ!3YX$;~g@nmkWXj3b-(f`!!NuU2C{1)iPpo{nks4W#w`MJ>gi1zqoUx2#vGdC-w zfjjWpfxF~t$>1y8FSA$}e1qGgo(%Tj>KZu9y!IJ=PV;KSiTt*ZT)08>_QoUr<+Ol5 DOnA$b delta 909 zcmYk4NlsK@6oqe92^9wA1_&e8fr)WK#RdZ?k%$R#;3kZZfh({W$bk*ZRxETMJ8yk1CXVDe6$d|wq za23oK+H>MXU@iGx5bL`Jl5d$e3m~UhqcARpIA$SA03AtTd-zKp=qrl^C!45aS32y^6`;5H? z=RJz7nip)^L2#T#J-^S7#8t2hYG4mIfw>dtH&-v`_LXye2hkIQa0grm&T$j$WqkY* zY|`Wp@(K7Pnq(L7Y4o_!&#=SO>HPw}0ykrP3C|qtjkpp0*7R7LE!DDAl+*QpBc2Bj zS->~`4%9lu`~E1j2e2NW>?crn0ej8Ue7}gx^Zh1Qqjx-C;17vcvs*0imspc}THqhC WdRoBT)1ANLIh&`SbhXu->^%dQ+M6i= diff --git a/axon/shaders/gpu_cycle.spv b/axon/shaders/gpu_cycle.spv index 59d50de1a4dc721f6a7e236b47c6676c4c3fd774..cac0d7b14e525d9f13a97b0a66516c165f390ab0 100644 GIT binary patch literal 92556 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 Pw`0xvI{r;1R^j>&`qQ^+ literal 91520 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�Ti`Mgk<=f!4V`TD%r968Sm^~tdXSY3R#1RJmB*a}X*#@iY>@zf{Y zHehub^S0oTEo0se&K&BJcYCmW&C!OO9O{!}09ak*9l*Yi=UsnCi|sye@&~~gr{;DHS%>?Ajq7-f={Td? z4{RKDj!#|YzCYM?Q^#=tvOaS89_>J6ZPn!-aS-@0Z1m3@4hHM1F209=^;c(o59R7% zebpVtDQ7*!`TTP@IAhcA2;}&wJCgG#PW`-QTt|b4V5o2UFa+$l)ER3i*ThnH4Ck?& z#`2oy=y72EjFtP~@nDu+<34yIKpXY;#<<2XUX|t3j}ySg)W%rm)7JUv>%6KgAKw$f z`f6hw<7%7wd5!H!V8`V;(a$*Ax-ZP*e#pO3J{hd7>&*I`0`{;+>Q3c6jZ;6b>G$d2 zjX7N_`kevx&`;f&oO1e!vscan>*pRwzt2W?42g9P*uz-r&gDFh(^y{9@AJW}{k{Os z9O@j`gS7rJ1;WDr>wK10Yv~_;^ zI?n-3ysB>-VmwVz!u=nWP6Ybem$R2s87=`RSyk^Z@4K{Ap z%r#&S*NnPrIpy>dJ165R%V!N;2RcZU!mUkRA zzIjr!o4}6IF=%h@?4g^%>W!Ov+=47Gr!MPrG+3R_&8*K`!C9Yv-q%LG?;*Z(*c0*Q zTpeSc(__FsyX$j$EL@(`>h+VeKjN*q+JA8yS99mteH&QYyf54i{(mU2ai~R;T z>aUIS(N2AQp8(5ceounWZkgXxaL!L%=JzyMzRvF%%`n==51zrIgKeKt?dmGuqdziX+IOV)&iIekPu=_3d ztM|Yw5l24tcpv;UvFaZD0M2@-OFcdW%h!5*gq(V)ckFWJ@jjO^c}>2L!B4m3`vlH> z>XPqMuzbz;8FKQe&pbZ|t4oeAz(2L*_!7<>>XPFtuzbz&HF9#OPmXWE>aq{N1+PIZ z)6ega5gYG(>a=%U@&6vIf8K9?0L$rT-PFm&{zvc)d`67?6LR(c8Ce_o^!FF=S`0#6 zYVj-h=ayQGhqD&yQj6cf^0gMfBc~SX9jBamGOj@6n`j&hX;LN8k`ThdS*L;5? zC!hM{_y?>m`|Dq@dF5k6BN{g8$3)2KM_+(G+BgSesgLi(P2bF666Bj&=FlF_IjGAV zI)LTt96BOr4(gMm6Ifm5Fe%u)^0Da*)+Te944gTv3eZOz=b)YX_;vxyWe$^re{GpV zS2*XOE_3JxmalW@j+{BDPmU?T>N1BZ!RD2Z%~W7*GKZ?ikfaU8vXGG3C)jK9R^W@!YCU9qB<^6GHWDoDX z>Sp1bmD78#*Nkg6@ObR%eRXy?$E7agngc9f$2BK%#-%>>=m}Pr9CLwxYsoP;oH^7b z$2?&9nqyw%x|+j%-C=a+o*fm`P^Kb-m0CEo&I`I>J*&4uv}`t68I11Uf1!;aLz$p=Fk@`U+1t2a^|2uIaUR$ w%N|<|Y+iZm-H)q>^;Wk!r=0Z`J8u2;v4_!lRZefbDz|6O`g;AFO7!OZ577`1H~;_u diff --git a/axon/shaders/gpu_cycleinc.spv b/axon/shaders/gpu_cycleinc.spv index 366b28aa7f2d5a00f97bf7c12f9b80c02c4bb5ee..5390ebf8a8c6cce2c4e53a90c16744e292b019a1 100644 GIT binary patch delta 480 zcmZorZ&2TGgU45tfrUYYfq_8*h(SOb$`^%j;e0V5pAjn052VF`m;;F~0c5jJR^<(^ z2bo3*mSbQ8LQFG2;_NuYK`w#XDF!A1n#d1q&WcAe#xspS%{V<|V&8qv&K#0c#-XD&P$yCklA8f&x-v@cU;f&zc?UqN}es32TaS120jj!q$KQII=)f!Gy@LDAB{ UzzWoLQz#fHuPZDMBz=XA0T-eu?f?J) delta 480 zcmZorZ&2TGgU45!frWvefq_8;h}nTy6v!6^(h5Kf0w8%1UkuDc@Wp|AMyNbUzXT9- zOjhL$uLr571j{k70U@RtAaRHbQRP7590>JtaLYjwoCpbs_+&{wZB=yVfmHHfsLbS> z%_usVmERgjI`Rigf^@-xLlekmg7GJ>1*>_A-g7^ysy#+z?(m*T##I~Top8Qu(9xf^f7u6Mt2D+nD$XXQS4qqU4 a1!7P%G%&CNb=?#S2FmLS%L7SYVPgPMWGO5F diff --git a/axon/shaders/gpu_cyclepost.spv b/axon/shaders/gpu_cyclepost.spv index 19ca7871a63679b934ca3861ba9acad1aa2226b0..e41dff1446d8a2269bbadcb71261a9e2ea065c3d 100644 GIT binary patch literal 132612 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 literal 131940 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 bsO#tVF6}dDy$)=(kEKp++kd#y7UBFqQqu?s diff --git a/axon/shaders/gpu_dwt.spv b/axon/shaders/gpu_dwt.spv index 37a2d866ad82b73840fa9453f13d336bdd5f6945..5f8acb5e8d36e8f691f169f4e5d07d1f46610509 100644 GIT binary patch literal 90104 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 literal 89852 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 diff --git a/axon/shaders/gpu_laygi.spv b/axon/shaders/gpu_laygi.spv index 94c1655df052b617aa613ac17ad03280ebc18507..4df40e81d47c05e3ac28f16a933ad20ae6571c8e 100644 GIT binary patch delta 6709 zcma)>37A%8702%kAfP}EV3QIgku4Ht5Qrk^ltdt?FhGWAQy`lmVvCv7Ma`|fzRb+X z%uF#XNlUZU_Oi`3Dofi}wbew;>i4_zp4&U$b9wT6=J5W{IsdcV^S7`W%&j+^f5 z7&)kO($J#lD2ifKv3%#qNxif8Ee02h(GNiUOiuceeznr)gL{!-$*;Z?8QR*|dw18^ zqO(|qc2F^>T36pVf9ah=hMTmK)|3@zjt^}@u~%^jp1vfeTHLyA#hB^;V~j4QYJD`) z>RCQ!NPm@yC!SrNLQE$z7@1IvE@nKM9RG)7$A>m>w9g!9FRP|?95&EV+YfKBy8~;m zABFgtfIf>=n_|8rSlb7pef9wRAZNL4<%Jzqw-V zvg=u8lZXQ`xY)qzVbMMY=Bca`@xGK*JPVF9pN5!6eJ$&pOt;3|OgE?b$y-)MHYTTq zEqYqgZBuoebKp%pH{xUEHYyIWmPU_c&S77keM8GS- z+>}~B6FfZAUj^Pf)6W9$lj*MpkI3}1!6P$$3wRXu>jJLbZz9etNjYPW(Kibe|R=2ChUFA{H^|b%>-3 zQj+t*Cej{BE&#XZScENdTnLtP136Z)UWAxO`?ba3vNB$r96rtK!G0d13GHt{wE0Bh z2U)i!U3(OIBiLpyPR+gvY_r;<**Aj+Hp@(W`bhE?u%zhrtzZ*rr`xL8w}G|W?AuxW z*sS&zqRnQ-d9&JkI6)rncOc%F1@4LCI0Ny7EKEP#�YvfxGBgR5```Y%Zr%z>>#@*?Jgdx-JwN6a-~ zc~y-2e=X9~-4^T-v_0|SBwyDSmWS|qWcXbE@CNK? z&0amO{BSaFO2_FV=-SRFO&{wGh&Erortw(rMCvTyWr!J-V~{!A6FJ64>5qaNVp_Xa zca=Bd(;q$D1lATkd_LvPV)NUd*fEGxZySo6QQDLFAd(g#?uqyF z7DR3|`iW$VMsG#emN)uI^g4Izj#IizEiz*?pUN3v#~Ib*R^ zUj1|Eb#*YgTWi;JP1i2pahNkka*TB< z<`28iE3OaB?I`WZJSdX#1M>}ZxzXr1!P=tHZ-KStjeZ-w&fV%+*IjCn8Ke15&Hy{k zsGc8~JFv@*>fZ%xi|XG4Ys;&DAHA*)_Q32~*EL7>!Stji&ekdL7>yzkXc# zLo8aOi(O!C(Z!Fz+VU=bj9zB}`-I0LR*C~7$Jm(4PrwZ^t((_(m3QLPA3gjOtSx%@ z8CYB1!(HeN`Klh`>E#&fRLmcCpEsMzhT?7v?a7Wyr2N4A9Gl!|^cP@l(daM1+VVz! zg*&1NI(14vHxHd%Zz>+a+a?t^Vyw=K92f%Tu8{<`rn z*m&(*$XCt>{0q@xP#^0fh+7g*_iwPAi_%{<{sWeyJ;v*=aCyU?4_^gNSD!JFzXRQg z6I)h?qq8B{>t?V%10r}3*l9)K!40uq8e{dzk1c*lviorTxExd^3x@~K@fqN04(wiw z{ncU!3H`)xb$g-vYlZ7|OlTFpq2NncBW75N@z)W3!x3$}k0wwho-`V9WPyDOaXj(f z=mSRG>eT?<;SD$Ds_^Sb}}}2*X`^7K~?_$C^M(%!&Q?2-Hl`0Y6K@nEw@u?b*JQ<2LM{l*0U ziC}A#=|yt@_$qkDmwkYV82G6Y=rq8jk>E*S6P%MKFbS;9IG;$Lw%|V*tS$5d!Cohy z*zJ1?I6ZJ#?7-k_%l$LJSL0J5NQ#U7G_W?`$G!}n4)zl-gM-lBXIK4`li!PP>@yH; za>Tc$7siwh=5KdblFS1WB-i`-Qt+*EFnBeq$)_MDu*fr6{a8fKA&54Mh|OoC>e}P{ zJPYiEwh?{%3>r*?3;WVm58;^yIe@`8E(=lQY1V zCQcczw?i?uAHsO`=rbs|GaIN2ihe0AtFC=xCLyZ@md3zid29tW1AJqjETjslV2?}*5;7{44Q z)4%^qQ241va|Npe6Gy^caC^cN;5ik2#z*p{U~Lh*4BQ?YUqZ_|4(9)DAmm>bLz2Fg N0^VKMM`&**@?U*8-E9B> delta 6497 zcmbW5d7M>c8OP56gM%_tIM~gmnIPIBQ%MDJ(3_DBGQhC30MeL%1P()5*uyq8-Y6S&aQz!0rS&?KZj9H zbE4xIn-?J8+sxN?uDYmYZEf}`w{+N_&wnHksd<#?@F_-BHhA^fwzwix~^z~c)3E5Tm(h`$Ov zq2Z^=**FI_h~(Aag9`p@z!MApYr*XW|8?Mwf`1NpGIlg=yQeni$35PM_j<-&TJ#Lg zP12FWxsRO#W}gSaK7?B^6C4L9=00x4&c*yxleTP+&jWif^D*;QVGA%PG3R_t&4qc5 zH-N1pUrqBO7vMA(>4%FV7lPH?ND*(yMVN);w=t32#hAQ{xrEWr1H|Oth{?Gi@%@Z0 zIF&FE6TJy+x0mGIz8P${^0DH#fSa3j^-<%kU^UU~+rZY5k7nNvhEKC@-+|-DZVkK> zle0N-bgM64y=hUGR~OoNK`9BIkpnyD5iamS+zocHh4|`B!uGsqaCw3Rad2b!bCvob;~JtMNJ58uEqsh9N-yP(EgcgOm{@6K`k8hjI?UaYqF z^see{FtX9ox4?4I(zn5K#g@K<->A~RzS1qDGB)A6`zf}r@2Y+eMmFa8K3Fd1`2kq2 zIL{C98}sa0U+I-m=|Zg*3v~tJnEyxMdM4OwurRv@KL#0%K7In0i#~n|mMivgJO0C} z!8v1G12yJG2R{RsmhbQjk)fQ^@Df4h27~$ zeg#o4Ry%b=SM?4U*=Xt4V7X}NH(aT6h~Jo}e`6(;QRzah77KL+BMWWIz6}0^U(W8_VB0dE!Cc8V=#ANs2%f-_F2A125MFW2aH#acfUlm=s zL6f3^y(Qw8z(oW90IP`x{t1?g2L1(>D>iU1escp0m_KX4ph;E!rZ|J~-&j%Xv*F}R z81KvDq21S{_1HptKiK$r`S<(-VDshAp=D?n{*uOx=QP5BPIn|2q@9&N`utOV(jR#-K7&!;zIsP4B ztPPXfmy)RCgswCiamxa`3URD>0)F#u4G_16v7+|C60Jw0)>!TE;kHA4J`XApF0Ty? zccw-smPB8WmoZkHvb{w6!dz>tsO>1xz9`okL)%kd_oGV0D{C#AM_PPzNpw|S%2;vQ zNhR7B=UQV$?ZGA56}i?J+B9p?7guMAcyTT^=6&#QKJSos#yb!fdotK75XXE7xcQh@ zk{|lV5La`4l8*fLUBR)4fe<|wtY{){)_XxyYI&;xdo$bSO(nnL~*e15WKjj6Y0`CIcB z(-R>iO>{*D4;F1{O{2H_{( z4Nu4SoE>k?-wn?IJMq=%uFtvY_!cu}of(XNd|w!QCMIVsv3JP1^k=lBUV@Q3a2TYk zyprTw^5W0Jm-kk0=f46684t&omopYScm&v(4HhSHvU~Y%GWW)_8juGbgl1m1vh!FXBg+#8cmBai+&0@DheU3*VyQ&jwp0F5R(Uxwy1* z!2D#F&RpxMiTvZh=7+x5^T*E;u4A--A}^pq1oh;(V4I2KIv#u~Ir1^V31Bs`qgC*= zXyl{m=YZu$n&A9T#Nj7v!j3JhD2hH8Y|%L9d0;v7Y}A-sO!_>q$9M%6HBN$aL7{m* zSlvmUf1FPrxcRK(?QhJaC^#SN`Gi2`2>!-fwqsT%8isF10f%(aH z<|;pLj!MT{>JgC-Q;_v3P(6U&}m$A@Td G7WRKdzz5}F7%#Dqlz(bN`-P%0=QiXsjOqNuoy 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 VoQLMi9sQ&7g+KRiD#Eq8{vWv6DwhBN diff --git a/axon/shaders/gpu_newstate_pool.spv b/axon/shaders/gpu_newstate_pool.spv index 4ca101ef8fa58eac51930039d6a68c7f938dd903..c295611da9fb88542c656d78ddd9447939960b8f 100644 GIT binary patch delta 4786 zcma)TZ1ux^eo4!pA~Qb9yaulj63aBYL(=Dw505x+j$- zJ~2aG22Y_Rne?=)s83QY*41<_OkTOHW>Zx&ODR!t!N~C!gjSt2PI}@oM6v*V+IyAR z>g{ck<1$RFu~%LkGO}$|$y=-&H6fisTm@7GRVQtdllFC;|G`x!&6D2vqi(b1`-r~i zXXT91%L?fg04(AJ$Rhf~_u9Zd`W)8j4PdpOv8O%VJ>4_+bnLbdXu$4Knu`5Y$gdjx zEVwqwL}$ax8_|Bw9`+Woy$2_!u|3_2gKN(#Oe?OgUEirZSlzLfMq9jVT#v%^;)Zd< zS_RJ0jw<#a-=i?2SUdix^h$Imdp^{G0fo;7 z+Uhei-5O3tp8`KVv#GnA{p$6!1ek_0Fb9~9d~QykfjlUuTlC5B z00CHl+!8vGFh}c1{T%gHv>V}lD9Nq339^{K__+}7w*%Q{>Sjp1d?0Jt^(~MwetmhU zoX8?5b?h~effJw+kVy=>6%rHyw;`9~hhq!;?Z{%LW=Zcrz7^8G9GkD;osh-oTbwjX zOUAo0huz$b?6;jFwBG}1vm@nga64Al9?2IYoBXOQ`4VIkX^#e$BJbG%^SAq0FOh%pv_9a&K5Z)AF! zCEtMV$!$ro7V{=lfOE=ou zGMF_&?h-Tz4THHPwJ=~3pN==n0mi*YUE^!qDrCVUH&FLR{-9tqS@ zlLP)$28@d}6#G_4f4ryLGMn+fk=x;ZzLENNl;rw1QrS0mE!<~ud;RHXQhFD6VjKjy z&>CnsWO3TvL<4uh4V3#>kAnXVjfPD859B!FuZse*{?*VH3aW5a5}ySYQj|(ahYKsm z@32P5s{p!yJ3R|tg{>dlBK6OK7a_ODVj5!;6Zj?#;OFP?X;T1#BA{6V0Sj^g&GCx~ ze2X&tJg`y})DpiKr`HN@lk#kOX|f-Rp>_2Rsb+j#|#jO^dAgqH<5Du`EdxcMH(AhcPP4( z(igT)$lA@*m;V#$z*oEfLlE3g0Uo$&_#|{Y>5Obbd34eR*-k8?D|8qX6YGYo-?7`s z;c)$aPE5bLcGpc+qLU+#?Zn`)9f_5k*MjkQVd#`E4#5+-u#jM3=jNCOAX8OVw2)kIRH}o&}d1n&< delta 4665 zcma);SCAD|5QgV23xWay3$BS3L_`ap&{C@`E%!mI3>Y4);z{w5Ah0VzMVv)30}3N5 zqJkMw6a+I0D3~x|&N=5yGJW6dG&|l}D5t8o|L*?#be}$F=I)xAHGj^i>DHlUzz#`L zNs^>{vj5U<^G6IFoYW>Gu$vG!cAdzd0PdV^8ZmaDo^!FL zAW71)GVJqmJ4t#cHA$My9l2MfW!b|cKkeAlQVLCnsLKA=H9G-Q~fa_ zV?)p`Zp&>sy^;e)0K%RQER z7Ax#$S=PL`QaL|s9AB5V+wOMCRP!CrvF-5nAGZzv@ooMwrFnKrhPDN^`n?(#;6D=a zX}~@KtxvJgiRktkJE_{AHBPv=GA(;{!n(fId~Ii!&o5g#ad73r?EQ(Ox&_bKHD{+x z8eF+3n>uMwdNH1fw*ZS5I_Z4ZZG zPemV8__WUlAKhxFIbj;c$tA*t;9({EBJimt+op$?>=y9pCEKRmKn1a(nMKTv#XETg zxJQzcF~AuU|;&MuLAcj*>k|Y844NW2N{jtbiObFEk4EkV=Z!cLNAGR)0!AZCz>*rdV&2}Rh;M|=x~uZo z@546Um~_cs#bsb$H@U`UA+r(dxW2FHaztKglJD#NNOe+%FOqzhA1HW{^WZjeEM_5d z9zx{B&L0Ms>ZHk4IDA!N=Z}CTMZ%-tQbNx6RSNzJu$-_T13QhlgpY&uInkElZmb0B zU+95)j;kJc9K~G3%M~%TjZQ~DgH$(q4n8O3**{xwhOD$G_ab;X(v@SA8sSp0pkoUlJA>?rmj zcDa~*Io2}IIA4<1>-P~xb+L)~V)2i`a>D+ku%p)Oo!YYa(I?3==lV&7tyi^-Q` zG4qT^vG2gu#m>eTYkv=x6ZQ`$6^7w^>w{J$f{jfbK|KPVhUm!@st~-+{QC;CC+ZQ#+aiS;;#>cflvg@$HCqm+BbbPGHC9&buPr zkeFU~uyHr#^maxY_i=j0dm#E*H_Z(T^=x(IItul|XCV{nklsiX>H{{ugt&!vDdJJc zcs-)u4T$4khF!rnxy192v)c`aqcRx2-NE`T)W|>gUb;QNr=vYj<6by@=V7~%J;4@K z$42^s-H1&zAbTPCMm+z17!n-2JL!*>;N!@QYwLGmaqMJousbm~d;`GxolI~_r;cMFp>v>^~V(aF6@Ur9PJd0I|Y5(k>^fbe>}eOWZZ~0$C>6k@?0ay zbGA?<#l7$xP4Y511$E?j37taZ#HIC;nd9qgjyiID?YGeO)};7Q_+Fc|3T={FdtPCy K|KjQ&iu?;Ca9{-h diff --git a/axon/shaders/gpu_plusneuron.spv b/axon/shaders/gpu_plusneuron.spv index 8d59a1c795d23cf314b1a11b26f24455f463f0c6..162676f38863937b7605b19f36aa534f51b09c3d 100644 GIT binary patch delta 9799 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 delta 9224 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 diff --git a/axon/shaders/gpu_poolgi.spv b/axon/shaders/gpu_poolgi.spv index 1ce9ba9627e00733bd5e20eb5cec37e7d6c838c2..65d3c779ca3cf7df78035a9409efc9779a2044a4 100644 GIT binary patch delta 7399 zcma)=37l4C6^HM@AfkW`U{jGKp;nS*5{Mw^WKCmfo!W}WDVBYsAf`ivg6&?kduA_ta!^;t;Y#_E~(wGGL7 zWsA{{&UzQ)k{y$0-P@<1NegKlGxvhSLK~JHkR6Mss}xgpHtw7|c=TSzpzJuUPevLY zvj_L-sWN=tMfp-xE0*)OYU&GNpc3*p5G_B)=eI1p3T#elwScd&% z#LqDF@r>FO^PR}pydc^q>|^ikT5g%Yxuv^tQYmqElKRWbvJ^H9Pz2~F%K|+5e*!-ct3fwEp_ZnV}!BZ22 z*MPYxm3{%ZU!q?KJ}A*&3qCl}UkC1==of(pB>KhRfz+=GydFFR8AIPLt;^@frG5zQ z4U7|L(XBAf72D0f>lyt#0`|^sK;%1ilFRMfh#2FigInwhUxMWB%M`@G`N(v{A_iTG zNQ!_>;AZ|*Y{7pcSk9$o(ai6We4vw2A|J{h!$wu{^k9eAAAT~ak z@hU`K#JmUG9OH>kW3EQeB^u-%elJoNWHAeMFtZYxFJlHu8`L>Vy*+ritejhJu$5R^(Yb}=tKJn^1er*8^H1+=EM7m z@lA-B8^Q7-<|bp@|8!qn1s{$G+6tB!K{tczX5`}%G26iMBIYCeiSYr-BWOE{#JDOS zZ3^;niaqshxCN2piT04*iWDcB(E~jlF}H{FHbno;jq1raYdXLf5v5QeBL;4vC-b04N)ODB(B(#>KL%@yMt=gdr}72<&5g-f%zGBxl#S+U~N(TUa+>b`Y+I{>R@s=Hm_(KtzEuLW6oF_ zXO}EZ_Dl3CzH#@8q4}?{XpJuJ18a*e?gwj2yZAMFl?Ch!PeZH}2S(2QNUX|lz%?e+FxdM*jlVmNxoV^eT5_(W>@bi_BP>zoiVY%NfiOxl#S^U~N(TA7E{1 z^?#yQ)xjQ^-K*Mi?ebk3b2?M8vlIJsat-57B#obmz7UBw_g^I^dfJ7q&G^-f|3;eQ zIU;#cOs4@+?7c&H-TU7U)9n3wG;b6%Is~ zb6NRINk6b0?Xe99fs=;w;(uFwGu#H921S8`!EQ|i_un_Th@Do(>XRR_1Hi6o#15>9 zogVwI(||Y&=afmEU0{<1_VC3`*_mL^gm(XCI)r?F;?LEmp!PK(P%v(`dvM3+yDsG2I9?`-xg6B| z4>o>7xdO+4wHfDx^l1zJ3&6R?FuV}#U313n-?8B48M}Y-eKuc&Urt>5X& zf&Iio@nUqh*-`)K7N03TJ_-hpK`<61@g2-$G5+JhHg^Nq|B(rf z5vd#O?i1&&p?r=Blc%DxOscxCx<>`BH@|FCHfq& zoM`eaupI4?e=hj{_J4lTq1W(r19z=nzJ)s-yS2i_wqw+wK-2=OA*#(cEHiH1`;M5Bi*p^^A^|K#&vxOOt?& zWkCF-(r377QCb;`JP!0xAHe_s delta 7145 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 RT#~c4uOMyb{j@TH@qhd`6yg8? diff --git a/axon/shaders/gpu_postspike.spv b/axon/shaders/gpu_postspike.spv index c8e6edd626579276652b2ac4f3700e82b8f59f3b..f8ab888e71839dbbce7d2806e5ed42200b05c9c4 100644 GIT binary patch delta 3942 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 XopbK@aUY|t*v`G@{Lb$?_ndRT z?{eSv>cQKq2k#rcAY+tkh|BA8xo&~bpIh6-Vmh`Dwx#`rn3q9@g|ilnwk&VBU}17x z0!6W9tSioSmkPZ!S~V0tJ(N*pEgqdi8u{+QTn?c~ea~Fy@))*_4>+slMTt7DcX4&W zfSmst3%s$e5w80&oB25Th370eX^o6oLS+_BDUCt?$71$#)QFh_JV*Ew|AOcD;bV=? z#krpBa|o^ymb%B=OW8App4Fcjp1pLYm1I-QncBfEQK!6HoDNW9ylP4DT+6G@7C(S7 z$#^A7b47(lr2*Z94`bf4PlCS$9jB5^23f_dNJ&b9%__24 z>O#p}J~K{guAjNHOZ&Ks9d59+$SPJN%iI_}JkH^)l-@F`QqYSAN@u5_Nh@SE>VF?M*FgKY%QZ@S z)5qPjB6%uVv_lRG{ddT3kd@R$%$Fe_Kz@dlac8XxH$K(0iWI9joLBLwW%<%>lnyV)9%Sx90OgZ#>z)y#89?J43W>CiW0`WjTfo^9w4K`){qk-KAECl-} zh-8@OPef1V_@`kE`4hP_4}wKcXF`N^!k^A(ZWa);GY`Wi%%_spB=ZOI2&`-f_b!~f z#y2RH5_|;^ojlIM&=&!tWymMXTv|7c6IcR-&LxMfG6R%mejuCuUif38sb=)lii4HR_Qt0xt2C~Vmb##J22`K`GlRJr1B_`m^{Gl&}{PQ*eaW2 z9|aPV71-}^$KKX2V||ByKQB+*6u+ zMsq)NxV_BH+$^!a)c!9V|GdpJIM*H^^qb#J@*YAeI}?Lh)*@uQS^ckMZXf_=<)Syxz-{O z>X4~f>r!B}7WrhYX#D{`N>%`&y1s|lM@a>+{`Ic}MqKhqgyx35$Z&R}R1*OHEn=*5 z{Qkxd;m_Ye6?k{(3R>WP4dPR$cTxrZCaNIy9j;*NF6vL`E{S*sG|KriC*p-&rTjg7 z1*8XSH9;ho<-6sO|5|%?+Me*)-EYgz&}How-kF-cv~t!yTKW7wUinhlJPh$pE{&YkDssRL?O{{k@D z1M=xOZBqSQAPxQ4FKRaVgng+^{MkCD?bB@X2|Mtf)LjOo2l-MK;z>Oyb+3enP_ynz9fy26&Otflt8|=tC(Z>OXB|BK z;{5#XuUO)eq{e0NdG1%e&djZ9iqVf(?fH{XLKT> ztQH=b0e1Ar1Z?s7Bk9nSI_WN$%j0q$_waa@$B{>gIrV4?uAj4xCem5G@O?VnlDa1G zHRnf!{lQtRpo@Y9x{`UxOT1*HYX%o^8P-Jzp>k;()9uco)cyq03$d@6e?cegIAobi zehd8#{VQ#OvH59q^`tB4HSqW1*VM0gntoN$%v|_>flk%=RNC=${-@Ug MiyH4!i;lbh0e;hqP5=M^ delta 4543 zcmb7H4{Vjy6@MRpD%D}E6$#r)B^9wgDp4f$$?DdbS}Ru4U{y4YAxh8)PEuIudyoF1 z6#9TiDVGO=RQqg;R6uAyUTK9_D7GLmio_ss22;#f#wKRCY^>Wz_B-d??|b((U9vSf z_nz}Rzwg|0&b{C5_jWgq-Q76$(1fLVUe7pBxyR$Fgxmy~1ly1KE(raRpX>lz2|Ebe zvI~|@wk*G0wk$IxjaZIM^`v+nRM9sktG4pz$1|#|6_bldBj3ZAYaz69;+fk$KErnK zQD@b;JYC1FT+vuID(8QV1>RK8&7MawoB6o;*^5`6wI(Jlq4FzcS0^F=$70TN)QAP6 zJV*F5{{=5i;8TsxrFfoAI0RQ|tGv^lrJR{UFC59V7p+=gWjGXbrgm^k)VazXZU?9_ zeznrS#PX|){$FCu2wdlGw7@e4;vAYN^xF*kJ?Kvwb}RJphTR5zf?>BqA8Xiqpl2KQ z`_NOxzMZSy3uB5yQ0>7?PHP{KGzZ1JA2Qvr4?w@$us?);k6|B#KEtpNK~FL4PUyvk z-39$Av8y>P8^+TH;V|@{78ezm+RYZ`f~A-{#>>D%Ho z^iz;^%!*ZIr8%q$ho!DmE#W)ktmcN8yQn(BUEy*g)fHAiO|0=^^zpcu$EF%DN2Y_; z;<7)h$#hXVBAk`FVW8A7L33&oT-pXf%M6s7DQMV0siT6%HA<(9suc99fzn+mXvP{@ zjryP978_`SyIP~PHwo^6HJNkBq8)Nk=zoX&4YHQHi1|9?6Ubj6HQZUN&Wl$yr!LD1 z*d=veT2@d^ub+j6mSPO5dLCo-FREXyn*idJbu&^E$rP=d1+0?C4j#YeF?BuRzV-7a z(W3WSvJF4Fi|$+F&awe&iooIdO9B>tTUlpzHrC3qxNHjFusvEOTwsTuxvm5W1IKw#pAvnx)}F z_E*B66is!qe=tmCSevDcYOpAN6-44^Z+@M#Sqmg7KGv$&Z1M>^zIiUQLqO}icJ<9OCL(z)$yq-+Np=V46SLi+SAOE~jg;J28uRFwU(EefonrgCO=fR&V= zI@d%|E;r?}{{Z|+8L0=hlD}Z9^rsX4A*@1ozhoEPTF$lfz?0NDFnWPepU5ZdJSCOK zfh6StcAsXGPsdh;9Q!1Yq^!XHShL9|?6hrl=u>1H^{IawWqp1d?OIwycI~Ww;&b;2 zU!)NJ+6ZwY5#pZH+zXofmCGGwZvJ+O^^Nxb&h@{xeLm+p1cd%mntOUlv&kp9UfM2| z{T>J%^&vdL9?X|v{}D6!gk7?u9Jvkd$g=$Ql^yfP@HfZ=d}90nN>CN-vQhZ(u6M0U zd*|D?;8Rq!@7{>+0HM161aYpCI$$H~Uki-5vB~v^+CPQAbPrWfxkp#f1@~K!pgO;oDhPE@1=$~P1#|XMfBN@H z#0#KN&R@9^uk5Sl_u*S0Ls+W=BDt*IFPHpx+Oya3*cbP|FFQjYYj^R^G##Xs3l7oB zmk;sE*E(Oq$|YU0^4*})%2}8teq|T!On(>c%=s=pzqW8^YOdGi`fNVGHgO|1pI^;= zNONbq++q7Syk|ZjEy&s2vqv`ZUTe5vh zv*x+1qVC7Q3U_-sj|ITnM?`)`KSMr=e5t#F*$YQuzo6OV6L#&9^}K5@0U1Kj?*L6F9Fgvg8iyylTX;!dgOo0QXomORemq+OldFGy|Y*9 zUIEs~x>xF$kDGz)G1;m=&hJc|-ImrvwE&*-Ob!D1d)^LT*Ai#$#|Nz6GXv#fx< z@MJpO)yqDn+bv^Y7Jue^kFbAs7b_c}VBvvGUh*0*85@|-1zd-96+)I$=@ax;_=oXp>aTd3epS)T bT=;&3PSpif&goqKr`HFI8Xr{4Pka9ZFrAGs diff --git a/axon/shaders/gpu_synca.spv b/axon/shaders/gpu_synca.spv index 7e359038d2f183d17a28a024f193811a860fab21..20e2ce6fb12e4523a2c3d29923f9ed280df448b7 100644 GIT binary patch literal 57232 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 literal 56404 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 diff --git a/axon/synapse.go b/axon/synapse.go index eb9111ace..c9e5b8998 100644 --- a/axon/synapse.go +++ b/axon/synapse.go @@ -6,34 +6,13 @@ package axon import ( "fmt" - - "github.com/goki/ki/kit" ) -//go:generate stringer -type=SynapseVars -//go:generate stringer -type=SynapseCaVars -//go:generate stringer -type=SynapseIdxs - -var KiT_SynapseVars = kit.Enums.AddEnum(SynapseVarsN, kit.NotBitFlag, nil) - -func (ev SynapseVars) MarshalJSON() ([]byte, error) { return kit.EnumMarshalJSON(ev) } -func (ev *SynapseVars) UnmarshalJSON(b []byte) error { return kit.EnumUnmarshalJSON(ev, b) } - -var KiT_SynapseCaVars = kit.Enums.AddEnum(SynapseCaVarsN, kit.NotBitFlag, nil) - -func (ev SynapseCaVars) MarshalJSON() ([]byte, error) { return kit.EnumMarshalJSON(ev) } -func (ev *SynapseCaVars) UnmarshalJSON(b []byte) error { return kit.EnumUnmarshalJSON(ev, b) } - -var KiT_SynapseIdxs = kit.Enums.AddEnum(SynapseIdxsN, kit.NotBitFlag, nil) - -func (ev SynapseIdxs) MarshalJSON() ([]byte, error) { return kit.EnumMarshalJSON(ev) } -func (ev *SynapseIdxs) UnmarshalJSON(b []byte) error { return kit.EnumUnmarshalJSON(ev, b) } - //gosl: start synapse // SynapseVars are the neuron variables representing current synaptic state, // specifically weights. -type SynapseVars int32 +type SynapseVars int32 //enums:enum const ( // Wt is effective synaptic weight value, determining how much conductance one spike drives on the receiving neuron, representing the actual number of effective AMPA receptors in the synapse. Wt = SWt * WtSig(LWt), where WtSig produces values between 0-2 based on LWt, centered on 1. @@ -51,9 +30,70 @@ const ( // DSWt is change in SWt slow synaptic weight -- accumulates DWt DSWt - SynapseVarsN + // IMPORTANT: if DSWt is not the last, need to update gosl defn below +) + +// SynapseCaVars are synapse variables for calcium involved in learning, +// which are data parallel input specific. +type SynapseCaVars int32 //enums:enum + +const ( + // CaM is first stage running average (mean) Ca calcium level (like CaM = calmodulin), feeds into CaP + CaM SynapseCaVars = iota + + // CaP is shorter timescale integrated CaM value, representing the plus, LTP direction of weight change and capturing the function of CaMKII in the Kinase learning rule + CaP + + // CaD is longer timescale integrated CaP value, representing the minus, LTD direction of weight change and capturing the function of DAPK1 in the Kinase learning rule + CaD + + // CaUpT is time in CyclesTotal of last updating of Ca values at the synapse level, for optimized synaptic-level Ca integration -- converted to / from uint32 + CaUpT + + // Tr is trace of synaptic activity over time -- used for credit assignment in learning. In MatrixPrjn this is a tag that is then updated later when US occurs. + Tr + + // DTr is delta (change in) Tr trace of synaptic activity over time + DTr + + // DiDWt is delta weight for each data parallel index (Di) -- this is directly computed from the Ca values (in cortical version) and then aggregated into the overall DWt (which may be further integrated across MPI nodes), which then drives changes in Wt values + DiDWt + + // IMPORTANT: if DiDWt is not the last, need to update gosl defn below +) + +// SynapseIdxs are the neuron indexes and other uint32 values (flags, etc). +// There is only one of these per neuron -- not data parallel. +type SynapseIdxs int32 //enums:enum + +const ( + // SynRecvIdx is receiving neuron index in network's global list of neurons + SynRecvIdx SynapseIdxs = iota + + // SynSendIdx is sending neuron index in network's global list of neurons + SynSendIdx + + // SynPrjnIdx is projection index in global list of projections organized as [Layers][RecvPrjns] + SynPrjnIdx + + // IMPORTANT: if SynPrjnIdx is not the last, need to update gosl defn below ) +//gosl: end synapse + +//gosl: hlsl synapse +/* +static const SynapseVars SynapseVarsN = DSWt + 1; +static const SynapseCaVars SynapseCaVarsN = DiDWt + 1; +static const SynapseIdxs SynapseIdxsN = SynPrjnIdx + 1; +*/ +//gosl: end synapse + +//gosl: start synapse + +//////////////////////////////////////////////// +// Strides + // SynapseVarStrides encodes the stride offsets for synapse variable access // into network float32 array. type SynapseVarStrides struct { @@ -92,35 +132,6 @@ func (ns *SynapseVarStrides) SetVarOuter(nsyn int) { //////////////////////////////////////////////// // SynapseCaVars -// SynapseCaVars are synapse variables for calcium involved in learning, -// which are data parallel input specific. -type SynapseCaVars int32 - -const ( - // CaM is first stage running average (mean) Ca calcium level (like CaM = calmodulin), feeds into CaP - CaM SynapseCaVars = iota - - // CaP is shorter timescale integrated CaM value, representing the plus, LTP direction of weight change and capturing the function of CaMKII in the Kinase learning rule - CaP - - // CaD is longer timescale integrated CaP value, representing the minus, LTD direction of weight change and capturing the function of DAPK1 in the Kinase learning rule - CaD - - // CaUpT is time in CyclesTotal of last updating of Ca values at the synapse level, for optimized synaptic-level Ca integration -- converted to / from uint32 - CaUpT - - // Tr is trace of synaptic activity over time -- used for credit assignment in learning. In MatrixPrjn this is a tag that is then updated later when US occurs. - Tr - - // DTr is delta (change in) Tr trace of synaptic activity over time - DTr - - // DiDWt is delta weight for each data parallel index (Di) -- this is directly computed from the Ca values (in cortical version) and then aggregated into the overall DWt (which may be further integrated across MPI nodes), which then drives changes in Wt values - DiDWt - - SynapseCaVarsN -) - // SynapseCaStrides encodes the stride offsets for synapse variable access // into network float32 array. Data is always the inner-most variable. type SynapseCaStrides struct { @@ -154,23 +165,6 @@ func (ns *SynapseCaStrides) SetVarOuter(nsyn, ndata int) { //////////////////////////////////////////////// // Idxs -// SynapseIdxs are the neuron indexes and other uint32 values (flags, etc). -// There is only one of these per neuron -- not data parallel. -type SynapseIdxs int32 - -const ( - // SynRecvIdx is receiving neuron index in network's global list of neurons - SynRecvIdx SynapseIdxs = iota - - // SynSendIdx is sending neuron index in network's global list of neurons - SynSendIdx - - // SynPrjnIdx is projection index in global list of projections organized as [Layers][RecvPrjns] - SynPrjnIdx - - SynapseIdxsN -) - // SynapseIdxStrides encodes the stride offsets for synapse index access // into network uint32 array. type SynapseIdxStrides struct { diff --git a/axon/synapsecavars_string.go b/axon/synapsecavars_string.go deleted file mode 100644 index 3b7f03289..000000000 --- a/axon/synapsecavars_string.go +++ /dev/null @@ -1,63 +0,0 @@ -// Code generated by "stringer -type=SynapseCaVars"; DO NOT EDIT. - -package axon - -import ( - "errors" - "strconv" -) - -var _ = errors.New("dummy error") - -func _() { - // An "invalid array index" compiler error signifies that the constant values have changed. - // Re-run the stringer command to generate them again. - var x [1]struct{} - _ = x[CaM-0] - _ = x[CaP-1] - _ = x[CaD-2] - _ = x[CaUpT-3] - _ = x[Tr-4] - _ = x[DTr-5] - _ = x[DiDWt-6] - _ = x[SynapseCaVarsN-7] -} - -const _SynapseCaVars_name = "CaMCaPCaDCaUpTTrDTrDiDWtSynapseCaVarsN" - -var _SynapseCaVars_index = [...]uint8{0, 3, 6, 9, 14, 16, 19, 24, 38} - -func (i SynapseCaVars) String() string { - if i < 0 || i >= SynapseCaVars(len(_SynapseCaVars_index)-1) { - return "SynapseCaVars(" + strconv.FormatInt(int64(i), 10) + ")" - } - return _SynapseCaVars_name[_SynapseCaVars_index[i]:_SynapseCaVars_index[i+1]] -} - -func (i *SynapseCaVars) FromString(s string) error { - for j := 0; j < len(_SynapseCaVars_index)-1; j++ { - if s == _SynapseCaVars_name[_SynapseCaVars_index[j]:_SynapseCaVars_index[j+1]] { - *i = SynapseCaVars(j) - return nil - } - } - return errors.New("String: " + s + " is not a valid option for type: SynapseCaVars") -} - -var _SynapseCaVars_descMap = map[SynapseCaVars]string{ - 0: `CaM is first stage running average (mean) Ca calcium level (like CaM = calmodulin), feeds into CaP`, - 1: `CaP is shorter timescale integrated CaM value, representing the plus, LTP direction of weight change and capturing the function of CaMKII in the Kinase learning rule`, - 2: `CaD is longer timescale integrated CaP value, representing the minus, LTD direction of weight change and capturing the function of DAPK1 in the Kinase learning rule`, - 3: `CaUpT is time in CyclesTotal of last updating of Ca values at the synapse level, for optimized synaptic-level Ca integration -- converted to / from uint32`, - 4: `Tr is trace of synaptic activity over time -- used for credit assignment in learning. In MatrixPrjn this is a tag that is then updated later when US occurs.`, - 5: `DTr is delta (change in) Tr trace of synaptic activity over time`, - 6: `DiDWt is delta weight for each data parallel index (Di) -- this is directly computed from the Ca values (in cortical version) and then aggregated into the overall DWt (which may be further integrated across MPI nodes), which then drives changes in Wt values`, - 7: ``, -} - -func (i SynapseCaVars) Desc() string { - if str, ok := _SynapseCaVars_descMap[i]; ok { - return str - } - return "SynapseCaVars(" + strconv.FormatInt(int64(i), 10) + ")" -} diff --git a/axon/synapseidxs_string.go b/axon/synapseidxs_string.go deleted file mode 100644 index 06cb5c2ca..000000000 --- a/axon/synapseidxs_string.go +++ /dev/null @@ -1,55 +0,0 @@ -// Code generated by "stringer -type=SynapseIdxs"; DO NOT EDIT. - -package axon - -import ( - "errors" - "strconv" -) - -var _ = errors.New("dummy error") - -func _() { - // An "invalid array index" compiler error signifies that the constant values have changed. - // Re-run the stringer command to generate them again. - var x [1]struct{} - _ = x[SynRecvIdx-0] - _ = x[SynSendIdx-1] - _ = x[SynPrjnIdx-2] - _ = x[SynapseIdxsN-3] -} - -const _SynapseIdxs_name = "SynRecvIdxSynSendIdxSynPrjnIdxSynapseIdxsN" - -var _SynapseIdxs_index = [...]uint8{0, 10, 20, 30, 42} - -func (i SynapseIdxs) String() string { - if i < 0 || i >= SynapseIdxs(len(_SynapseIdxs_index)-1) { - return "SynapseIdxs(" + strconv.FormatInt(int64(i), 10) + ")" - } - return _SynapseIdxs_name[_SynapseIdxs_index[i]:_SynapseIdxs_index[i+1]] -} - -func (i *SynapseIdxs) FromString(s string) error { - for j := 0; j < len(_SynapseIdxs_index)-1; j++ { - if s == _SynapseIdxs_name[_SynapseIdxs_index[j]:_SynapseIdxs_index[j+1]] { - *i = SynapseIdxs(j) - return nil - } - } - return errors.New("String: " + s + " is not a valid option for type: SynapseIdxs") -} - -var _SynapseIdxs_descMap = map[SynapseIdxs]string{ - 0: `SynRecvIdx is receiving neuron index in network's global list of neurons`, - 1: `SynSendIdx is sending neuron index in network's global list of neurons`, - 2: `SynPrjnIdx is projection index in global list of projections organized as [Layers][RecvPrjns]`, - 3: ``, -} - -func (i SynapseIdxs) Desc() string { - if str, ok := _SynapseIdxs_descMap[i]; ok { - return str - } - return "SynapseIdxs(" + strconv.FormatInt(int64(i), 10) + ")" -} diff --git a/axon/synapsevars_string.go b/axon/synapsevars_string.go deleted file mode 100644 index e97671d9f..000000000 --- a/axon/synapsevars_string.go +++ /dev/null @@ -1,59 +0,0 @@ -// Code generated by "stringer -type=SynapseVars"; DO NOT EDIT. - -package axon - -import ( - "errors" - "strconv" -) - -var _ = errors.New("dummy error") - -func _() { - // An "invalid array index" compiler error signifies that the constant values have changed. - // Re-run the stringer command to generate them again. - var x [1]struct{} - _ = x[Wt-0] - _ = x[LWt-1] - _ = x[SWt-2] - _ = x[DWt-3] - _ = x[DSWt-4] - _ = x[SynapseVarsN-5] -} - -const _SynapseVars_name = "WtLWtSWtDWtDSWtSynapseVarsN" - -var _SynapseVars_index = [...]uint8{0, 2, 5, 8, 11, 15, 27} - -func (i SynapseVars) String() string { - if i < 0 || i >= SynapseVars(len(_SynapseVars_index)-1) { - return "SynapseVars(" + strconv.FormatInt(int64(i), 10) + ")" - } - return _SynapseVars_name[_SynapseVars_index[i]:_SynapseVars_index[i+1]] -} - -func (i *SynapseVars) FromString(s string) error { - for j := 0; j < len(_SynapseVars_index)-1; j++ { - if s == _SynapseVars_name[_SynapseVars_index[j]:_SynapseVars_index[j+1]] { - *i = SynapseVars(j) - return nil - } - } - return errors.New("String: " + s + " is not a valid option for type: SynapseVars") -} - -var _SynapseVars_descMap = map[SynapseVars]string{ - 0: `Wt is effective synaptic weight value, determining how much conductance one spike drives on the receiving neuron, representing the actual number of effective AMPA receptors in the synapse. Wt = SWt * WtSig(LWt), where WtSig produces values between 0-2 based on LWt, centered on 1.`, - 1: `LWt is rapidly learning, linear weight value -- learns according to the lrate specified in the connection spec. Biologically, this represents the internal biochemical processes that drive the trafficking of AMPA receptors in the synaptic density. Initially all LWt are .5, which gives 1 from WtSig function.`, - 2: `SWt is slowly adapting structural weight value, which acts as a multiplicative scaling factor on synaptic efficacy: biologically represents the physical size and efficacy of the dendritic spine. SWt values adapt in an outer loop along with synaptic scaling, with constraints to prevent runaway positive feedback loops and maintain variance and further capacity to learn. Initial variance is all in SWt, with LWt set to .5, and scaling absorbs some of LWt into SWt.`, - 3: `DWt is delta (change in) synaptic weight, from learning -- updates LWt which then updates Wt.`, - 4: `DSWt is change in SWt slow synaptic weight -- accumulates DWt`, - 5: ``, -} - -func (i SynapseVars) Desc() string { - if str, ok := _SynapseVars_descMap[i]; ok { - return str - } - return "SynapseVars(" + strconv.FormatInt(int64(i), 10) + ")" -} diff --git a/axon/threads.go b/axon/threads.go index ffcdceae0..692ee1410 100644 --- a/axon/threads.go +++ b/axon/threads.go @@ -12,8 +12,7 @@ import ( "sync" "github.com/emer/emergent/v2/timer" - "github.com/goki/ki/atomctr" - "github.com/goki/ki/ints" + "goki.dev/glop/atomctr" ) // Maps the given function across the [0, total) range of items, using @@ -81,7 +80,7 @@ func (nt *NetworkBase) SetNThreads(nthr int) { nthr = 1 } } - nt.NThreads = ints.MinInt(maxProcs, nthr) + nt.NThreads = min(maxProcs, nthr) } // PrjnMapSeq applies function of given name to all projections sequentially. diff --git a/axon/threads_test.go b/axon/threads_test.go index e55339326..831f6b5d4 100644 --- a/axon/threads_test.go +++ b/axon/threads_test.go @@ -14,7 +14,6 @@ import ( "github.com/emer/emergent/v2/etime" "github.com/emer/emergent/v2/patgen" "github.com/emer/emergent/v2/prjn" - "github.com/goki/ki/ints" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "goki.dev/etable/v2/etable" @@ -318,7 +317,7 @@ func generateRandomPatterns(nPats int, seed int64) *etable.Table { {Name: "Input", Type: etensor.FLOAT32, CellShape: shape, DimNames: []string{"Y", "X"}}, {Name: "Output", Type: etensor.FLOAT32, CellShape: shape, DimNames: []string{"Y", "X"}}, }, nPats) - numOn := ints.MaxInt((shape[0]*shape[1])/4, 1) // ensure min at least 1 + numOn := max((shape[0]*shape[1])/4, 1) // ensure min at least 1 patgen.PermutedBinaryRows(pats.Cols[1], numOn, 1, 0) patgen.PermutedBinaryRows(pats.Cols[2], numOn, 1, 0) // fmt.Printf("%v\n", pats.Cols[1].(*etensor.Float32).Values) diff --git a/axon/valencetypes_string.go b/axon/valencetypes_string.go deleted file mode 100644 index 8a0dcf6ab..000000000 --- a/axon/valencetypes_string.go +++ /dev/null @@ -1,53 +0,0 @@ -// Code generated by "stringer -type=ValenceTypes"; DO NOT EDIT. - -package axon - -import ( - "errors" - "strconv" -) - -var _ = errors.New("dummy error") - -func _() { - // An "invalid array index" compiler error signifies that the constant values have changed. - // Re-run the stringer command to generate them again. - var x [1]struct{} - _ = x[Positive-0] - _ = x[Negative-1] - _ = x[ValenceTypesN-2] -} - -const _ValenceTypes_name = "PositiveNegativeValenceTypesN" - -var _ValenceTypes_index = [...]uint8{0, 8, 16, 29} - -func (i ValenceTypes) String() string { - if i < 0 || i >= ValenceTypes(len(_ValenceTypes_index)-1) { - return "ValenceTypes(" + strconv.FormatInt(int64(i), 10) + ")" - } - return _ValenceTypes_name[_ValenceTypes_index[i]:_ValenceTypes_index[i+1]] -} - -func (i *ValenceTypes) FromString(s string) error { - for j := 0; j < len(_ValenceTypes_index)-1; j++ { - if s == _ValenceTypes_name[_ValenceTypes_index[j]:_ValenceTypes_index[j+1]] { - *i = ValenceTypes(j) - return nil - } - } - return errors.New("String: " + s + " is not a valid option for type: ValenceTypes") -} - -var _ValenceTypes_descMap = map[ValenceTypes]string{ - 0: `Positive valence codes for outcomes aligned with drives / goals.`, - 1: `Negative valence codes for harmful or aversive outcomes.`, - 2: ``, -} - -func (i ValenceTypes) Desc() string { - if str, ok := _ValenceTypes_descMap[i]; ok { - return str - } - return "ValenceTypes(" + strconv.FormatInt(int64(i), 10) + ")" -} diff --git a/chans/ak_plot/ak_plot.go b/chans/ak_plot/ak_plot.go index 20f47c8c7..63330a8df 100644 --- a/chans/ak_plot/ak_plot.go +++ b/chans/ak_plot/ak_plot.go @@ -5,32 +5,30 @@ // ak_plot plots an equation updating over time in a etable.Table and Plot2D. package main +//go:generate goki generate -add-types + import ( "strconv" "github.com/emer/axon/chans" - "github.com/emer/etable/eplot" - "github.com/emer/etable/etable" - "github.com/emer/etable/etensor" - _ "github.com/emer/etable/etview" // include to get gui views - "github.com/goki/gi/gi" - "github.com/goki/gi/gimain" - "github.com/goki/gi/giv" - "github.com/goki/ki/ki" - "github.com/goki/mat32" + "goki.dev/etable/v2/eplot" + "goki.dev/etable/v2/etable" + "goki.dev/etable/v2/etensor" + _ "goki.dev/etable/v2/etview" // include to get gui views + "goki.dev/gi/v2/gi" + "goki.dev/gi/v2/gimain" + "goki.dev/gi/v2/giv" + "goki.dev/icons" ) -func main() { - TheSim.Config() - gimain.Main(func() { // this starts gui -- requires valid OpenGL display connection (e.g., X11) - guirun() - }) -} +func main() { gimain.Run(app) } -func guirun() { - TheSim.VmRun() - win := TheSim.ConfigGui() - win.StartEventLoop() +func app() { + sim := &Sim{} + sim.Config() + sim.VmRun() + b := sim.ConfigGUI() + b.NewWindow().Run().Wait() } // LogPrec is precision for saving float values in logs @@ -80,17 +78,8 @@ type Sim struct { // the plot TimePlot *eplot.Plot2D `view:"-"` - - // main GUI window - Win *gi.Window `view:"-"` - - // the master toolbar - ToolBar *gi.ToolBar `view:"-"` } -// TheSim is the overall state for this simulation -var TheSim Sim - // Config configures all the elements using the standard functions func (ss *Sim) Config() { ss.AK.Defaults() @@ -117,7 +106,7 @@ func (ss *Sim) Update() { } // VmRun plots the equation as a function of V -func (ss *Sim) VmRun() { +func (ss *Sim) VmRun() { //gti:add ss.Update() dt := ss.Table @@ -153,7 +142,9 @@ func (ss *Sim) VmRun() { dt.SetCellFloat("Ms", vi, float64(ms)) dt.SetCellFloat("Gaks", vi, float64(gs)) } - ss.Plot.Update() + if ss.Plot != nil { + ss.Plot.UpdatePlot() + } } func (ss *Sim) ConfigTable(dt *etable.Table) { @@ -199,7 +190,7 @@ func (ss *Sim) ConfigPlot(plt *eplot.Plot2D, dt *etable.Table) *eplot.Plot2D { ///////////////////////////////////////////////////////////////// // TimeRun runs the equation over time. -func (ss *Sim) TimeRun() { +func (ss *Sim) TimeRun() { //gti:add ss.Update() dt := ss.TimeTable @@ -258,7 +249,9 @@ func (ss *Sim) TimeRun() { } } } - ss.TimePlot.Update() + if ss.TimePlot != nil { + ss.TimePlot.UpdatePlot() + } } func (ss *Sim) ConfigTimeTable(dt *etable.Table) { @@ -302,73 +295,28 @@ func (ss *Sim) ConfigTimePlot(plt *eplot.Plot2D, dt *etable.Table) *eplot.Plot2D return plt } -// ConfigGui configures the GoGi gui interface for this simulation, -func (ss *Sim) ConfigGui() *gi.Window { - width := 1600 - height := 1200 - - // gi.WinEventTrace = true - - gi.SetAppName("ak_plot") - gi.SetAppAbout(`This plots an equation. See emergent on GitHub.

`) - - win := gi.NewMainWindow("ak_plot", "Plotting Equations", width, height) - ss.Win = win +// ConfigGUI configures the GoGi gui interface for this simulation, +func (ss *Sim) ConfigGUI() *gi.Body { + b := gi.NewAppBody("ak_plot").SetTitle("Plotting Equations") - vp := win.WinViewport2D() - updt := vp.UpdateStart() - - mfr := win.SetMainFrame() - - tbar := gi.AddNewToolBar(mfr, "tbar") - tbar.SetStretchMaxWidth() - ss.ToolBar = tbar - - split := gi.AddNewSplitView(mfr, "split") - split.Dim = mat32.X - split.SetStretchMax() - - sv := giv.AddNewStructView(split, "sv") + split := gi.NewSplits(b, "split") + sv := giv.NewStructView(split, "sv") sv.SetStruct(ss) - tv := gi.AddNewTabView(split, "tv") + tv := gi.NewTabs(split, "tv") - plt := tv.AddNewTab(eplot.KiT_Plot2D, "V-G Plot").(*eplot.Plot2D) - ss.Plot = ss.ConfigPlot(plt, ss.Table) + ss.Plot = eplot.NewSubPlot(tv.NewTab("V-G Plot")) + ss.ConfigPlot(ss.Plot, ss.Table) - plt = tv.AddNewTab(eplot.KiT_Plot2D, "TimePlot").(*eplot.Plot2D) - ss.TimePlot = ss.ConfigTimePlot(plt, ss.TimeTable) + ss.TimePlot = eplot.NewSubPlot(tv.NewTab("TimePlot")) + ss.ConfigTimePlot(ss.TimePlot, ss.TimeTable) split.SetSplits(.3, .7) - tbar.AddAction(gi.ActOpts{Label: "V-G Run", Icon: "update", Tooltip: "Run the equations and plot results."}, win.This(), func(recv, send ki.Ki, sig int64, data interface{}) { - ss.VmRun() - vp.SetNeedsFullRender() - }) - - tbar.AddAction(gi.ActOpts{Label: "Time Run", Icon: "update", Tooltip: "Run the equations and plot results."}, win.This(), func(recv, send ki.Ki, sig int64, data interface{}) { - ss.TimeRun() - vp.SetNeedsFullRender() + b.AddAppBar(func(tb *gi.Toolbar) { + giv.NewFuncButton(tb, ss.VmRun).SetIcon(icons.PlayArrow) + giv.NewFuncButton(tb, ss.TimeRun).SetIcon(icons.PlayArrow) }) - tbar.AddAction(gi.ActOpts{Label: "README", Icon: "file-markdown", Tooltip: "Opens your browser on the README file that contains instructions for how to run this model."}, win.This(), - func(recv, send ki.Ki, sig int64, data interface{}) { - gi.OpenURL("https://github.com/emer/axon/blob/master/chans/ak_plot/README.md") - }) - - vp.UpdateEndNoSig(updt) - - // main menu - appnm := gi.AppName() - mmen := win.MainMenu - mmen.ConfigMenus([]string{appnm, "File", "Edit", "Window"}) - - amen := win.MainMenu.ChildByName(appnm, 0).(*gi.Action) - amen.Menu.AddAppMenu(win) - - emen := win.MainMenu.ChildByName("Edit", 1).(*gi.Action) - emen.Menu.AddCopyCutPaste(win) - - win.MainMenuUpdated() - return win + return b } diff --git a/chans/ak_plot/gtigen.go b/chans/ak_plot/gtigen.go new file mode 100644 index 000000000..629f203b3 --- /dev/null +++ b/chans/ak_plot/gtigen.go @@ -0,0 +1,41 @@ +// Code generated by "goki generate -add-types"; DO NOT EDIT. + +package main + +import ( + "goki.dev/gti" + "goki.dev/ordmap" +) + +var _ = gti.AddType(>i.Type{ + Name: "main.Sim", + ShortName: "main.Sim", + IDName: "sim", + Doc: "Sim holds the params, table, etc", + Directives: gti.Directives{}, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"AK", >i.Field{Name: "AK", Type: "github.com/emer/axon/chans.AKParams", LocalType: "chans.AKParams", Doc: "AK function", Directives: gti.Directives{}, Tag: ""}}, + {"AKs", >i.Field{Name: "AKs", Type: "github.com/emer/axon/chans.AKsParams", LocalType: "chans.AKsParams", Doc: "AKs simplified function", Directives: gti.Directives{}, Tag: ""}}, + {"Vstart", >i.Field{Name: "Vstart", Type: "float32", LocalType: "float32", Doc: "starting voltage", Directives: gti.Directives{}, Tag: "def:\"-100\""}}, + {"Vend", >i.Field{Name: "Vend", Type: "float32", LocalType: "float32", Doc: "ending voltage", Directives: gti.Directives{}, Tag: "def:\"100\""}}, + {"Vstep", >i.Field{Name: "Vstep", Type: "float32", LocalType: "float32", Doc: "voltage increment", Directives: gti.Directives{}, Tag: "def:\"1\""}}, + {"TimeSteps", >i.Field{Name: "TimeSteps", Type: "int", LocalType: "int", Doc: "number of time steps", Directives: gti.Directives{}, Tag: ""}}, + {"TimeSpike", >i.Field{Name: "TimeSpike", Type: "bool", LocalType: "bool", Doc: "do spiking instead of voltage ramp", Directives: gti.Directives{}, Tag: ""}}, + {"SpikeFreq", >i.Field{Name: "SpikeFreq", Type: "float32", LocalType: "float32", Doc: "spiking frequency", Directives: gti.Directives{}, Tag: ""}}, + {"TimeVstart", >i.Field{Name: "TimeVstart", Type: "float32", LocalType: "float32", Doc: "time-run starting membrane potential", Directives: gti.Directives{}, Tag: ""}}, + {"TimeVend", >i.Field{Name: "TimeVend", Type: "float32", LocalType: "float32", Doc: "time-run ending membrane potential", Directives: gti.Directives{}, Tag: ""}}, + {"Table", >i.Field{Name: "Table", Type: "*goki.dev/etable/v2/etable.Table", LocalType: "*etable.Table", Doc: "table for plot", Directives: gti.Directives{}, Tag: "view:\"no-inline\""}}, + {"Plot", >i.Field{Name: "Plot", Type: "*goki.dev/etable/v2/eplot.Plot2D", LocalType: "*eplot.Plot2D", Doc: "the plot", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + {"TimeTable", >i.Field{Name: "TimeTable", Type: "*goki.dev/etable/v2/etable.Table", LocalType: "*etable.Table", Doc: "table for plot", Directives: gti.Directives{}, Tag: "view:\"no-inline\""}}, + {"TimePlot", >i.Field{Name: "TimePlot", Type: "*goki.dev/etable/v2/eplot.Plot2D", LocalType: "*eplot.Plot2D", Doc: "the plot", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{ + {"VmRun", >i.Method{Name: "VmRun", Doc: "VmRun plots the equation as a function of V", Directives: gti.Directives{ + >i.Directive{Tool: "gti", Directive: "add", Args: []string{}}, + }, Args: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), Returns: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{})}}, + {"TimeRun", >i.Method{Name: "TimeRun", Doc: "TimeRun runs the equation over time.", Directives: gti.Directives{ + >i.Directive{Tool: "gti", Directive: "add", Args: []string{}}, + }, Args: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), Returns: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{})}}, + }), +}) diff --git a/chans/chans.go b/chans/chans.go index 8e81ade17..f61fed669 100644 --- a/chans/chans.go +++ b/chans/chans.go @@ -10,6 +10,8 @@ Includes excitatory, leak, inhibition, and dynamic potassium channels. */ package chans +//go:generate goki generate -add-types + //gosl: hlsl chans // #include "fastexp.hlsl" //gosl: end chans diff --git a/chans/gabab_plot/gabab_plot.go b/chans/gabab_plot/gabab_plot.go index a9e642aad..0d6bcfebc 100644 --- a/chans/gabab_plot/gabab_plot.go +++ b/chans/gabab_plot/gabab_plot.go @@ -5,34 +5,33 @@ // gabab_plot plots an equation updating over time in a etable.Table and Plot2D. package main +//go:generate goki generate -add-types + import ( "math" "strconv" "github.com/emer/axon/chans" - "github.com/emer/etable/eplot" - "github.com/emer/etable/etable" - "github.com/emer/etable/etensor" - _ "github.com/emer/etable/etview" // include to get gui views - "github.com/goki/gi/gi" - "github.com/goki/gi/gimain" - "github.com/goki/gi/giv" - "github.com/goki/ki/ki" - "github.com/goki/mat32" + "goki.dev/etable/v2/eplot" + "goki.dev/etable/v2/etable" + "goki.dev/etable/v2/etensor" + _ "goki.dev/etable/v2/etview" // include to get gui views + "goki.dev/gi/v2/gi" + "goki.dev/gi/v2/gimain" + "goki.dev/gi/v2/giv" + "goki.dev/icons" + "goki.dev/mat32/v2" ) -func main() { - TheSim.Config() - gimain.Main(func() { // this starts gui -- requires valid OpenGL display connection (e.g., X11) - guirun() - }) -} +func main() { gimain.Run(app) } -func guirun() { - TheSim.VGRun() - TheSim.SGRun() - win := TheSim.ConfigGui() - win.StartEventLoop() +func app() { + sim := &Sim{} + sim.Config() + sim.VGRun() + sim.SGRun() + b := sim.ConfigGUI() + b.NewWindow().Run().Wait() } // LogPrec is precision for saving float values in logs @@ -103,17 +102,8 @@ type Sim struct { // the plot TimePlot *eplot.Plot2D `view:"-"` - - // main GUI window - Win *gi.Window `view:"-"` - - // the master toolbar - ToolBar *gi.ToolBar `view:"-"` } -// TheSim is the overall state for this simulation -var TheSim Sim - // Config configures all the elements using the standard functions func (ss *Sim) Config() { ss.GABAstd.Defaults() @@ -149,7 +139,7 @@ func (ss *Sim) Update() { } // VGRun runs the V-G equation. -func (ss *Sim) VGRun() { +func (ss *Sim) VGRun() { //gti:add ss.Update() dt := ss.VGTable @@ -169,7 +159,9 @@ func (ss *Sim) VGRun() { dt.SetCellFloat("GgabaB_std", vi, float64(gs)) dt.SetCellFloat("GgabaB_bug", vi, float64(gbug)) } - ss.VGPlot.Update() + if ss.VGPlot != nil { + ss.VGPlot.UpdatePlot() + } } func (ss *Sim) ConfigVGTable(dt *etable.Table) { @@ -200,7 +192,7 @@ func (ss *Sim) ConfigVGPlot(plt *eplot.Plot2D, dt *etable.Table) *eplot.Plot2D { ////////////////////////////////////////////////// // SGRun runs the spike-g equation. -func (ss *Sim) SGRun() { +func (ss *Sim) SGRun() { //gti:add ss.Update() dt := ss.SGTable @@ -217,7 +209,9 @@ func (ss *Sim) SGRun() { dt.SetCellFloat("GgabaB_max", si, g) dt.SetCellFloat("GgabaBstd_max", si, float64(gs)) } - ss.SGPlot.Update() + if ss.SGPlot != nil { + ss.SGPlot.UpdatePlot() + } } func (ss *Sim) ConfigSGTable(dt *etable.Table) { @@ -247,7 +241,7 @@ func (ss *Sim) ConfigSGPlot(plt *eplot.Plot2D, dt *etable.Table) *eplot.Plot2D { ////////////////////////////////////////////////// // TimeRun runs the equation. -func (ss *Sim) TimeRun() { +func (ss *Sim) TimeRun() { //gti:add ss.Update() dt := ss.TimeTable @@ -281,7 +275,9 @@ func (ss *Sim) TimeRun() { time += ss.TimeInc } - ss.TimePlot.Update() + if ss.TimePlot != nil { + ss.TimePlot.UpdatePlot() + } } func (ss *Sim) ConfigTimeTable(dt *etable.Table) { @@ -314,81 +310,32 @@ func (ss *Sim) ConfigTimePlot(plt *eplot.Plot2D, dt *etable.Table) *eplot.Plot2D return plt } -// ConfigGui configures the GoGi gui interface for this simulation, -func (ss *Sim) ConfigGui() *gi.Window { - width := 1600 - height := 1200 - - // gi.WinEventTrace = true - - gi.SetAppName("gabab_plot") - gi.SetAppAbout(`This plots an equation. See emergent on GitHub.

`) - - win := gi.NewMainWindow("gababplot", "Plotting Equations", width, height) - ss.Win = win - - vp := win.WinViewport2D() - updt := vp.UpdateStart() +// ConfigGUI configures the GoGi gui interface for this simulation, +func (ss *Sim) ConfigGUI() *gi.Body { + b := gi.NewAppBody("gabab_plot").SetTitle("Plotting Equations") - mfr := win.SetMainFrame() - - tbar := gi.AddNewToolBar(mfr, "tbar") - tbar.SetStretchMaxWidth() - ss.ToolBar = tbar - - split := gi.AddNewSplitView(mfr, "split") - split.Dim = mat32.X - split.SetStretchMax() - - sv := giv.AddNewStructView(split, "sv") + split := gi.NewSplits(b, "split") + sv := giv.NewStructView(split, "sv") sv.SetStruct(ss) - tv := gi.AddNewTabView(split, "tv") + tv := gi.NewTabs(split, "tv") - plt := tv.AddNewTab(eplot.KiT_Plot2D, "VGPlot").(*eplot.Plot2D) - ss.VGPlot = ss.ConfigVGPlot(plt, ss.VGTable) + ss.VGPlot = eplot.NewSubPlot(tv.NewTab("V-G Plot")) + ss.ConfigVGPlot(ss.VGPlot, ss.VGTable) - plt = tv.AddNewTab(eplot.KiT_Plot2D, "SGPlot").(*eplot.Plot2D) - ss.SGPlot = ss.ConfigSGPlot(plt, ss.SGTable) + ss.SGPlot = eplot.NewSubPlot(tv.NewTab("S-G Plot")) + ss.ConfigSGPlot(ss.SGPlot, ss.SGTable) - plt = tv.AddNewTab(eplot.KiT_Plot2D, "TimePlot").(*eplot.Plot2D) - ss.TimePlot = ss.ConfigTimePlot(plt, ss.TimeTable) + ss.TimePlot = eplot.NewSubPlot(tv.NewTab("TimePlot")) + ss.ConfigTimePlot(ss.TimePlot, ss.TimeTable) split.SetSplits(.3, .7) - tbar.AddAction(gi.ActOpts{Label: "Run VG", Icon: "update", Tooltip: "Run the equations and plot results."}, win.This(), func(recv, send ki.Ki, sig int64, data interface{}) { - ss.VGRun() - vp.SetNeedsFullRender() - }) - - tbar.AddAction(gi.ActOpts{Label: "Run SG", Icon: "update", Tooltip: "Run the equations and plot results."}, win.This(), func(recv, send ki.Ki, sig int64, data interface{}) { - ss.SGRun() - vp.SetNeedsFullRender() - }) - - tbar.AddAction(gi.ActOpts{Label: "Run Time", Icon: "update", Tooltip: "Run the equations and plot results."}, win.This(), func(recv, send ki.Ki, sig int64, data interface{}) { - ss.TimeRun() - vp.SetNeedsFullRender() + b.AddAppBar(func(tb *gi.Toolbar) { + giv.NewFuncButton(tb, ss.VGRun).SetIcon(icons.PlayArrow) + giv.NewFuncButton(tb, ss.SGRun).SetIcon(icons.PlayArrow) + giv.NewFuncButton(tb, ss.TimeRun).SetIcon(icons.PlayArrow) }) - tbar.AddAction(gi.ActOpts{Label: "README", Icon: "file-markdown", Tooltip: "Opens your browser on the README file that contains instructions for how to run this model."}, win.This(), - func(recv, send ki.Ki, sig int64, data interface{}) { - gi.OpenURL("https://github.com/emer/axon/blob/master/chans/gabab_plot/README.md") - }) - - vp.UpdateEndNoSig(updt) - - // main menu - appnm := gi.AppName() - mmen := win.MainMenu - mmen.ConfigMenus([]string{appnm, "File", "Edit", "Window"}) - - amen := win.MainMenu.ChildByName(appnm, 0).(*gi.Action) - amen.Menu.AddAppMenu(win) - - emen := win.MainMenu.ChildByName("Edit", 1).(*gi.Action) - emen.Menu.AddCopyCutPaste(win) - - win.MainMenuUpdated() - return win + return b } diff --git a/chans/gabab_plot/gtigen.go b/chans/gabab_plot/gtigen.go new file mode 100644 index 000000000..2b63ff514 --- /dev/null +++ b/chans/gabab_plot/gtigen.go @@ -0,0 +1,51 @@ +// Code generated by "goki generate -add-types"; DO NOT EDIT. + +package main + +import ( + "goki.dev/gti" + "goki.dev/ordmap" +) + +var _ = gti.AddType(>i.Type{ + Name: "main.Sim", + ShortName: "main.Sim", + IDName: "sim", + Doc: "Sim holds the params, table, etc", + Directives: gti.Directives{}, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"GABAstd", >i.Field{Name: "GABAstd", Type: "github.com/emer/axon/chans.GABABParams", LocalType: "chans.GABABParams", Doc: "standard chans version of GABAB", Directives: gti.Directives{}, Tag: ""}}, + {"GABAbv", >i.Field{Name: "GABAbv", Type: "float64", LocalType: "float64", Doc: "multiplier on GABAb as function of voltage", Directives: gti.Directives{}, Tag: "def:\"0.1\""}}, + {"GABAbo", >i.Field{Name: "GABAbo", Type: "float64", LocalType: "float64", Doc: "offset of GABAb function", Directives: gti.Directives{}, Tag: "def:\"10\""}}, + {"GABAberev", >i.Field{Name: "GABAberev", Type: "float64", LocalType: "float64", Doc: "GABAb reversal / driving potential", Directives: gti.Directives{}, Tag: "def:\"-90\""}}, + {"Vstart", >i.Field{Name: "Vstart", Type: "float64", LocalType: "float64", Doc: "starting voltage", Directives: gti.Directives{}, Tag: "def:\"-90\""}}, + {"Vend", >i.Field{Name: "Vend", Type: "float64", LocalType: "float64", Doc: "ending voltage", Directives: gti.Directives{}, Tag: "def:\"0\""}}, + {"Vstep", >i.Field{Name: "Vstep", Type: "float64", LocalType: "float64", Doc: "voltage increment", Directives: gti.Directives{}, Tag: "def:\"1\""}}, + {"Smax", >i.Field{Name: "Smax", Type: "int", LocalType: "int", Doc: "max number of spikes", Directives: gti.Directives{}, Tag: "def:\"15\""}}, + {"RiseTau", >i.Field{Name: "RiseTau", Type: "float64", LocalType: "float64", Doc: "rise time constant", Directives: gti.Directives{}, Tag: ""}}, + {"DecayTau", >i.Field{Name: "DecayTau", Type: "float64", LocalType: "float64", Doc: "decay time constant -- must NOT be same as RiseTau", Directives: gti.Directives{}, Tag: ""}}, + {"GsXInit", >i.Field{Name: "GsXInit", Type: "float64", LocalType: "float64", Doc: "initial value of GsX driving variable at point of synaptic input onset -- decays expoentially from this start", Directives: gti.Directives{}, Tag: ""}}, + {"MaxTime", >i.Field{Name: "MaxTime", Type: "float64", LocalType: "float64", Doc: "time when peak conductance occurs, in TimeInc units", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + {"TauFact", >i.Field{Name: "TauFact", Type: "float64", LocalType: "float64", Doc: "time constant factor used in integration: (Decay / Rise) ^ (Rise / (Decay - Rise))", Directives: gti.Directives{}, Tag: "inactive:\"+\""}}, + {"TimeSteps", >i.Field{Name: "TimeSteps", Type: "int", LocalType: "int", Doc: "total number of time steps to take", Directives: gti.Directives{}, Tag: ""}}, + {"TimeInc", >i.Field{Name: "TimeInc", Type: "float64", LocalType: "float64", Doc: "time increment per step", Directives: gti.Directives{}, Tag: ""}}, + {"VGTable", >i.Field{Name: "VGTable", Type: "*goki.dev/etable/v2/etable.Table", LocalType: "*etable.Table", Doc: "table for plot", Directives: gti.Directives{}, Tag: "view:\"no-inline\""}}, + {"SGTable", >i.Field{Name: "SGTable", Type: "*goki.dev/etable/v2/etable.Table", LocalType: "*etable.Table", Doc: "table for plot", Directives: gti.Directives{}, Tag: "view:\"no-inline\""}}, + {"TimeTable", >i.Field{Name: "TimeTable", Type: "*goki.dev/etable/v2/etable.Table", LocalType: "*etable.Table", Doc: "table for plot", Directives: gti.Directives{}, Tag: "view:\"no-inline\""}}, + {"VGPlot", >i.Field{Name: "VGPlot", Type: "*goki.dev/etable/v2/eplot.Plot2D", LocalType: "*eplot.Plot2D", Doc: "the plot", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + {"SGPlot", >i.Field{Name: "SGPlot", Type: "*goki.dev/etable/v2/eplot.Plot2D", LocalType: "*eplot.Plot2D", Doc: "the plot", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + {"TimePlot", >i.Field{Name: "TimePlot", Type: "*goki.dev/etable/v2/eplot.Plot2D", LocalType: "*eplot.Plot2D", Doc: "the plot", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{ + {"VGRun", >i.Method{Name: "VGRun", Doc: "VGRun runs the V-G equation.", Directives: gti.Directives{ + >i.Directive{Tool: "gti", Directive: "add", Args: []string{}}, + }, Args: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), Returns: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{})}}, + {"SGRun", >i.Method{Name: "SGRun", Doc: "SGRun runs the spike-g equation.", Directives: gti.Directives{ + >i.Directive{Tool: "gti", Directive: "add", Args: []string{}}, + }, Args: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), Returns: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{})}}, + {"TimeRun", >i.Method{Name: "TimeRun", Doc: "TimeRun runs the equation.", Directives: gti.Directives{ + >i.Directive{Tool: "gti", Directive: "add", Args: []string{}}, + }, Args: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), Returns: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{})}}, + }), +}) diff --git a/chans/gtigen.go b/chans/gtigen.go new file mode 100644 index 000000000..069589ed9 --- /dev/null +++ b/chans/gtigen.go @@ -0,0 +1,237 @@ +// Code generated by "goki generate -add-types"; DO NOT EDIT. + +package chans + +import ( + "goki.dev/gti" + "goki.dev/ordmap" +) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/chans.AKParams", + ShortName: "chans.AKParams", + IDName: "ak-params", + Doc: "AKParams control an A-type K channel, which is voltage gated with maximal\nactivation around -37 mV. It has two state variables, M (v-gated opening)\nand H (v-gated closing), which integrate with fast and slow time constants,\nrespectively. H relatively quickly hits an asymptotic level of inactivation\nfor sustained activity patterns.\nIt is particularly important for counteracting the excitatory effects of\nvoltage gated calcium channels which can otherwise drive runaway excitatory currents.\nSee AKsParams for a much simpler version that works fine when full AP-like spikes are\nnot simulated, as in our standard axon models.", + Directives: gti.Directives{}, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"Gbar", >i.Field{Name: "Gbar", Type: "float32", LocalType: "float32", Doc: "strength of AK current", Directives: gti.Directives{}, Tag: "def:\"1,0.1,0.01\""}}, + {"Beta", >i.Field{Name: "Beta", Type: "float32", LocalType: "float32", Doc: "multiplier for the beta term; 0.01446 for distal, 0.02039 for proximal dendrites", Directives: gti.Directives{}, Tag: "viewif:\"Gbar>0\" def:\"0.01446,02039\""}}, + {"Dm", >i.Field{Name: "Dm", Type: "float32", LocalType: "float32", Doc: "Dm factor: 0.5 for distal, 0.25 for proximal", Directives: gti.Directives{}, Tag: "viewif:\"Gbar>0\" def:\"0.5,0.25\""}}, + {"Koff", >i.Field{Name: "Koff", Type: "float32", LocalType: "float32", Doc: "offset for K, 1.8 for distal, 1.5 for proximal", Directives: gti.Directives{}, Tag: "viewif:\"Gbar>0\" def:\"1.8,1.5\""}}, + {"Voff", >i.Field{Name: "Voff", Type: "float32", LocalType: "float32", Doc: "voltage offset for alpha and beta functions: 1 for distal, 11 for proximal", Directives: gti.Directives{}, Tag: "viewif:\"Gbar>0\" def:\"1,11\""}}, + {"Hf", >i.Field{Name: "Hf", Type: "float32", LocalType: "float32", Doc: "h multiplier factor, 0.1133 for distal, 0.1112 for proximal", Directives: gti.Directives{}, Tag: "viewif:\"Gbar>0\" def:\"0.1133,0.1112\""}}, + {"pad", >i.Field{Name: "pad", Type: "float32", LocalType: "float32", Doc: "", Directives: gti.Directives{}, Tag: ""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/chans.AKsParams", + ShortName: "chans.AKsParams", + IDName: "a-ks-params", + Doc: "AKsParams provides a highly simplified stateless A-type K channel\nthat only has the voltage-gated activation (M) dynamic with a cutoff\nthat ends up capturing a close approximation to the much more complex AK function.\nThis is voltage gated with maximal activation around -37 mV.\nIt is particularly important for counteracting the excitatory effects of\nvoltage gated calcium channels which can otherwise drive runaway excitatory currents.", + Directives: gti.Directives{ + >i.Directive{Tool: "gosl", Directive: "start", Args: []string{"chans"}}, + }, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"Gbar", >i.Field{Name: "Gbar", Type: "float32", LocalType: "float32", Doc: "strength of AK current", Directives: gti.Directives{}, Tag: "def:\"2,0.1,0.01\""}}, + {"Hf", >i.Field{Name: "Hf", Type: "float32", LocalType: "float32", Doc: "H factor as a constant multiplier on overall M factor result -- rescales M to level consistent with H being present at full strength", Directives: gti.Directives{}, Tag: "viewif:\"Gbar>0\" def:\"0.076\""}}, + {"Mf", >i.Field{Name: "Mf", Type: "float32", LocalType: "float32", Doc: "multiplier for M -- determines slope of function", Directives: gti.Directives{}, Tag: "viewif:\"Gbar>0\" def:\"0.075\""}}, + {"Voff", >i.Field{Name: "Voff", Type: "float32", LocalType: "float32", Doc: "voltage offset in biological units for M function", Directives: gti.Directives{}, Tag: "viewif:\"Gbar>0\" def:\"2\""}}, + {"Vmax", >i.Field{Name: "Vmax", Type: "float32", LocalType: "float32", Doc: "", Directives: gti.Directives{}, Tag: "viewif:\"Gbar>0\" def:-37\" desc:\"voltage level of maximum channel opening -- stays flat above that\""}}, + {"pad", >i.Field{Name: "pad", Type: "int32", LocalType: "int32", Doc: "", Directives: gti.Directives{}, Tag: ""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/chans.Chans", + ShortName: "chans.Chans", + IDName: "chans", + Doc: "Chans are ion channels used in computing point-neuron activation function", + Directives: gti.Directives{ + >i.Directive{Tool: "go", Directive: "generate", Args: []string{"goki", "generate", "-add-types"}}, + >i.Directive{Tool: "gosl", Directive: "hlsl", Args: []string{"chans"}}, + >i.Directive{Tool: "gosl", Directive: "end", Args: []string{"chans"}}, + >i.Directive{Tool: "gosl", Directive: "start", Args: []string{"chans"}}, + }, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"E", >i.Field{Name: "E", Type: "float32", LocalType: "float32", Doc: "excitatory sodium (Na) AMPA channels activated by synaptic glutamate", Directives: gti.Directives{}, Tag: ""}}, + {"L", >i.Field{Name: "L", Type: "float32", LocalType: "float32", Doc: "constant leak (potassium, K+) channels -- determines resting potential (typically higher than resting potential of K)", Directives: gti.Directives{}, Tag: ""}}, + {"I", >i.Field{Name: "I", Type: "float32", LocalType: "float32", Doc: "inhibitory chloride (Cl-) channels activated by synaptic GABA", Directives: gti.Directives{}, Tag: ""}}, + {"K", >i.Field{Name: "K", Type: "float32", LocalType: "float32", Doc: "gated / active potassium channels -- typically hyperpolarizing relative to leak / rest", Directives: gti.Directives{}, Tag: ""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/chans.GABABParams", + ShortName: "chans.GABABParams", + IDName: "gabab-params", + Doc: "GABABParams control the GABAB dynamics in PFC Maint neurons,\nbased on Brunel & Wang (2001) parameters.", + Directives: gti.Directives{ + >i.Directive{Tool: "gosl", Directive: "start", Args: []string{"chans"}}, + }, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"Gbar", >i.Field{Name: "Gbar", Type: "float32", LocalType: "float32", Doc: "overall strength multiplier of GABA-B current. The 0.015 default is a high value that works well in smaller networks -- larger networks may benefit from lower levels (e.g., 0.012).", Directives: gti.Directives{}, Tag: "def:\"0,0.012,0.015\""}}, + {"RiseTau", >i.Field{Name: "RiseTau", Type: "float32", LocalType: "float32", Doc: "rise time for bi-exponential time dynamics of GABA-B", Directives: gti.Directives{}, Tag: "viewif:\"Gbar>0\" def:\"45\""}}, + {"DecayTau", >i.Field{Name: "DecayTau", Type: "float32", LocalType: "float32", Doc: "decay time for bi-exponential time dynamics of GABA-B", Directives: gti.Directives{}, Tag: "viewif:\"Gbar>0\" def:\"50\""}}, + {"Gbase", >i.Field{Name: "Gbase", Type: "float32", LocalType: "float32", Doc: "baseline level of GABA-B channels open independent of inhibitory input (is added to spiking-produced conductance)", Directives: gti.Directives{}, Tag: "viewif:\"Gbar>0\" def:\"0.2\""}}, + {"GiSpike", >i.Field{Name: "GiSpike", Type: "float32", LocalType: "float32", Doc: "multiplier for converting Gi to equivalent GABA spikes", Directives: gti.Directives{}, Tag: "viewif:\"Gbar>0\" def:\"10\""}}, + {"MaxTime", >i.Field{Name: "MaxTime", Type: "float32", LocalType: "float32", Doc: "time offset when peak conductance occurs, in msec, computed from RiseTau and DecayTau", Directives: gti.Directives{}, Tag: "viewif:\"Gbar>0\" inactive:\"+\""}}, + {"TauFact", >i.Field{Name: "TauFact", Type: "float32", LocalType: "float32", Doc: "time constant factor used in integration: (Decay / Rise) ^ (Rise / (Decay - Rise))", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + {"RiseDt", >i.Field{Name: "RiseDt", Type: "float32", LocalType: "float32", Doc: "1/Tau", Directives: gti.Directives{}, Tag: "view:\"-\" inactive:\"+\""}}, + {"DecayDt", >i.Field{Name: "DecayDt", Type: "float32", LocalType: "float32", Doc: "1/Tau", Directives: gti.Directives{}, Tag: "view:\"-\" inactive:\"+\""}}, + {"pad", >i.Field{Name: "pad", Type: "float32", LocalType: "float32", Doc: "", Directives: gti.Directives{}, Tag: ""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/chans.KNaParams", + ShortName: "chans.KNaParams", + IDName: "k-na-params", + Doc: "KNaParams implements sodium (Na) gated potassium (K) currents\nthat drive adaptation (accommodation) in neural firing.\nAs neurons spike, driving an influx of Na, this activates\nthe K channels, which, like leak channels, pull the membrane\npotential back down toward rest (or even below).", + Directives: gti.Directives{ + >i.Directive{Tool: "gosl", Directive: "start", Args: []string{"chans"}}, + }, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"On", >i.Field{Name: "On", Type: "goki.dev/gosl/v2/slbool.Bool", LocalType: "slbool.Bool", Doc: "if On, use this component of K-Na adaptation", Directives: gti.Directives{}, Tag: ""}}, + {"Rise", >i.Field{Name: "Rise", Type: "float32", LocalType: "float32", Doc: "Rise rate of fast time-scale adaptation as function of Na concentration due to spiking -- directly multiplies -- 1/rise = tau for rise rate", Directives: gti.Directives{}, Tag: "viewif:\"On\""}}, + {"Max", >i.Field{Name: "Max", Type: "float32", LocalType: "float32", Doc: "Maximum potential conductance of fast K channels -- divide nA biological value by 10 for the normalized units here", Directives: gti.Directives{}, Tag: "viewif:\"On\""}}, + {"Tau", >i.Field{Name: "Tau", Type: "float32", LocalType: "float32", Doc: "time constant in cycles for decay of adaptation, which should be milliseconds typically (tau is roughly how long it takes for value to change significantly -- 1.4x the half-life)", Directives: gti.Directives{}, Tag: "viewif:\"On\""}}, + {"Dt", >i.Field{Name: "Dt", Type: "float32", LocalType: "float32", Doc: "1/Tau rate constant", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + {"pad", >i.Field{Name: "pad", Type: "int32", LocalType: "int32", Doc: "", Directives: gti.Directives{}, Tag: ""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/chans.KNaMedSlow", + ShortName: "chans.KNaMedSlow", + IDName: "k-na-med-slow", + Doc: "KNaMedSlow describes sodium-gated potassium channel adaptation mechanism.\nEvidence supports 2 different time constants:\nSlick (medium) and Slack (slow)", + Directives: gti.Directives{}, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"On", >i.Field{Name: "On", Type: "goki.dev/gosl/v2/slbool.Bool", LocalType: "slbool.Bool", Doc: "if On, apply K-Na adaptation", Directives: gti.Directives{}, Tag: ""}}, + {"TrialSlow", >i.Field{Name: "TrialSlow", Type: "goki.dev/gosl/v2/slbool.Bool", LocalType: "slbool.Bool", Doc: "engages an optional version of Slow that discretely turns on at start of new trial (NewState): nrn.GknaSlow += Slow.Max * nrn.SpkPrv -- achieves a strong form of adaptation", Directives: gti.Directives{}, Tag: ""}}, + {"pad", >i.Field{Name: "pad", Type: "int32", LocalType: "int32", Doc: "", Directives: gti.Directives{}, Tag: ""}}, + {"Med", >i.Field{Name: "Med", Type: "github.com/emer/axon/chans.KNaParams", LocalType: "KNaParams", Doc: "medium time-scale adaptation", Directives: gti.Directives{}, Tag: "viewif:\"On\" view:\"inline\""}}, + {"Slow", >i.Field{Name: "Slow", Type: "github.com/emer/axon/chans.KNaParams", LocalType: "KNaParams", Doc: "slow time-scale adaptation", Directives: gti.Directives{}, Tag: "viewif:\"On\" view:\"inline\""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/chans.MahpParams", + ShortName: "chans.MahpParams", + IDName: "mahp-params", + Doc: "MahpParams implements an M-type medium afterhyperpolarizing (mAHP) channel,\nwhere m also stands for muscarinic due to the ACh inactivation of this channel.\nIt has a slow activation and deactivation time constant, and opens at a lowish\nmembrane potential.\nThere is one gating variable n updated over time with a tau that is also voltage dependent.\nThe infinite-time value of n is voltage dependent according to a logistic function\nof the membrane potential, centered at Voff with slope Vslope.", + Directives: gti.Directives{ + >i.Directive{Tool: "gosl", Directive: "start", Args: []string{"chans"}}, + }, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"Gbar", >i.Field{Name: "Gbar", Type: "float32", LocalType: "float32", Doc: "strength of mAHP current", Directives: gti.Directives{}, Tag: ""}}, + {"Voff", >i.Field{Name: "Voff", Type: "float32", LocalType: "float32", Doc: "voltage offset (threshold) in biological units for infinite time N gating function -- where the gate is at 50% strength", Directives: gti.Directives{}, Tag: "viewif:\"Gbar>0\" def:\"-30\""}}, + {"Vslope", >i.Field{Name: "Vslope", Type: "float32", LocalType: "float32", Doc: "slope of the arget (infinite time) gating function", Directives: gti.Directives{}, Tag: "viewif:\"Gbar>0\" def:\"9\""}}, + {"TauMax", >i.Field{Name: "TauMax", Type: "float32", LocalType: "float32", Doc: "maximum slow rate time constant in msec for activation / deactivation. The effective Tau is much slower -- 1/20th in original temp, and 1/60th in standard 37 C temp", Directives: gti.Directives{}, Tag: "viewif:\"Gbar>0\" def:\"1000\""}}, + {"Tadj", >i.Field{Name: "Tadj", Type: "float32", LocalType: "float32", Doc: "temperature adjustment factor: assume temp = 37 C, whereas original units were at 23 C", Directives: gti.Directives{}, Tag: "viewif:\"Gbar>0\" view:\"-\" inactive:\"+\""}}, + {"DtMax", >i.Field{Name: "DtMax", Type: "float32", LocalType: "float32", Doc: "1/Tau", Directives: gti.Directives{}, Tag: "view:\"-\" inactive:\"+\""}}, + {"pad", >i.Field{Name: "pad", Type: "int32", LocalType: "int32", Doc: "", Directives: gti.Directives{}, Tag: ""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/chans.NMDAParams", + ShortName: "chans.NMDAParams", + IDName: "nmda-params", + Doc: "NMDAParams control the NMDA dynamics, based on Jahr & Stevens (1990) equations\nwhich are widely used in models, from Brunel & Wang (2001) to Sanders et al. (2013).\nThe overall conductance is a function of a voltage-dependent postsynaptic factor based\non Mg ion blockage, and presynaptic Glu-based opening, which in a simple model just\nincrements", + Directives: gti.Directives{ + >i.Directive{Tool: "gosl", Directive: "start", Args: []string{"chans"}}, + }, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"Gbar", >i.Field{Name: "Gbar", Type: "float32", LocalType: "float32", Doc: "overall multiplier for strength of NMDA current -- multiplies GnmdaSyn to get net conductance.", Directives: gti.Directives{}, Tag: "def:\"0,0.006,0.007\""}}, + {"Tau", >i.Field{Name: "Tau", Type: "float32", LocalType: "float32", Doc: "decay time constant for NMDA channel activation -- rise time is 2 msec and not worth extra effort for biexponential. 30 fits the Urakubo et al (2008) model with ITau = 100, but 100 works better in practice is small networks so far.", Directives: gti.Directives{}, Tag: "viewif:\"Gbar>0\" def:\"30,50,100,200,300\""}}, + {"ITau", >i.Field{Name: "ITau", Type: "float32", LocalType: "float32", Doc: "decay time constant for NMDA channel inhibition, which captures the Urakubo et al (2008) allosteric dynamics (100 fits their model well) -- set to 1 to eliminate that mechanism.", Directives: gti.Directives{}, Tag: "viewif:\"Gbar>0\" def:\"1,100\""}}, + {"MgC", >i.Field{Name: "MgC", Type: "float32", LocalType: "float32", Doc: "magnesium ion concentration: Brunel & Wang (2001) and Sanders et al (2013) use 1 mM, based on Jahr & Stevens (1990). Urakubo et al (2008) use 1.5 mM. 1.4 with Voff = 5 works best so far in large models, 1.2, Voff = 0 best in smaller nets.", Directives: gti.Directives{}, Tag: "viewif:\"Gbar>0\" def:\"1:1.5\""}}, + {"Voff", >i.Field{Name: "Voff", Type: "float32", LocalType: "float32", Doc: "offset in membrane potential in biological units for voltage-dependent functions. 5 corresponds to the -65 mV rest, -45 threshold of the Urakubo et al (2008) model. 5 was used before in a buggy version of NMDA equation -- 0 is new default.", Directives: gti.Directives{}, Tag: "viewif:\"Gbar>0\" def:\"0\""}}, + {"Dt", >i.Field{Name: "Dt", Type: "float32", LocalType: "float32", Doc: "rate = 1 / tau", Directives: gti.Directives{}, Tag: "view:\"-\" json:\"-\" xml:\"-\""}}, + {"IDt", >i.Field{Name: "IDt", Type: "float32", LocalType: "float32", Doc: "rate = 1 / tau", Directives: gti.Directives{}, Tag: "view:\"-\" json:\"-\" xml:\"-\""}}, + {"MgFact", >i.Field{Name: "MgFact", Type: "float32", LocalType: "float32", Doc: "MgFact = MgC / 3.57", Directives: gti.Directives{}, Tag: "view:\"-\" json:\"-\" xml:\"-\""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/chans.SahpParams", + ShortName: "chans.SahpParams", + IDName: "sahp-params", + Doc: "SahpParams implements a slow afterhyperpolarizing (sAHP) channel,\nIt has a slowly accumulating calcium value, aggregated at the\ntheta cycle level, that then drives the logistic gating function,\nso that it only activates after a significant accumulation.\nAfter which point it decays.\nFor the theta-cycle updating, the normal m-type tau is all within\nthe scope of a single theta cycle, so we just omit the time integration\nof the n gating value, but tau is computed in any case.", + Directives: gti.Directives{ + >i.Directive{Tool: "gosl", Directive: "start", Args: []string{"chans"}}, + }, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"Gbar", >i.Field{Name: "Gbar", Type: "float32", LocalType: "float32", Doc: "strength of sAHP current", Directives: gti.Directives{}, Tag: "def:\"0.05,0.1\""}}, + {"CaTau", >i.Field{Name: "CaTau", Type: "float32", LocalType: "float32", Doc: "time constant for integrating Ca across theta cycles", Directives: gti.Directives{}, Tag: "viewif:\"Gbar>0\" def:\"5,10\""}}, + {"Off", >i.Field{Name: "Off", Type: "float32", LocalType: "float32", Doc: "integrated Ca offset (threshold) for infinite time N gating function -- where the gate is at 50% strength", Directives: gti.Directives{}, Tag: "viewif:\"Gbar>0\" def:\"0.8\""}}, + {"Slope", >i.Field{Name: "Slope", Type: "float32", LocalType: "float32", Doc: "slope of the infinite time logistic gating function", Directives: gti.Directives{}, Tag: "viewif:\"Gbar>0\" def:\"0.02\""}}, + {"TauMax", >i.Field{Name: "TauMax", Type: "float32", LocalType: "float32", Doc: "maximum slow rate time constant in msec for activation / deactivation. The effective Tau is much slower -- 1/20th in original temp, and 1/60th in standard 37 C temp", Directives: gti.Directives{}, Tag: "viewif:\"Gbar>0\" def:\"1\""}}, + {"CaDt", >i.Field{Name: "CaDt", Type: "float32", LocalType: "float32", Doc: "1/Tau", Directives: gti.Directives{}, Tag: "view:\"-\" inactive:\"+\""}}, + {"DtMax", >i.Field{Name: "DtMax", Type: "float32", LocalType: "float32", Doc: "1/Tau", Directives: gti.Directives{}, Tag: "view:\"-\" inactive:\"+\""}}, + {"pad", >i.Field{Name: "pad", Type: "int32", LocalType: "int32", Doc: "", Directives: gti.Directives{}, Tag: ""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/chans.SKCaParams", + ShortName: "chans.SKCaParams", + IDName: "sk-ca-params", + Doc: "SKCaParams describes the small-conductance calcium-activated potassium channel,\nactivated by intracellular stores in a way that drives pauses in firing,\nand can require inactivity to recharge the Ca available for release.\nThese intracellular stores can release quickly, have a slow decay once released,\nand the stores can take a while to rebuild, leading to rapidly triggered,\nlong-lasting pauses that don't recur until stores have rebuilt, which is the\nobserved pattern of firing of STNp pausing neurons.\nCaIn = intracellular stores available for release; CaR = released amount from stores\nCaM = K channel conductance gating factor driven by CaR binding,\ncomputed using the Hill equations described in Fujita et al (2012), Gunay et al (2008)\n(also Muddapu & Chakravarthy, 2021): X^h / (X^h + C50^h) where h ~= 4 (hard coded)", + Directives: gti.Directives{ + >i.Directive{Tool: "gosl", Directive: "start", Args: []string{"chans"}}, + }, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"Gbar", >i.Field{Name: "Gbar", Type: "float32", LocalType: "float32", Doc: "overall strength of sKCa current -- inactive if 0", Directives: gti.Directives{}, Tag: "def:\"0,2,3\""}}, + {"C50", >i.Field{Name: "C50", Type: "float32", LocalType: "float32", Doc: "50% Ca concentration baseline value in Hill equation -- set this to level that activates at reasonable levels of SKCaR", Directives: gti.Directives{}, Tag: "viewif:\"Gbar>0\" def:\"0.4,0.5\""}}, + {"ActTau", >i.Field{Name: "ActTau", Type: "float32", LocalType: "float32", Doc: "K channel gating factor activation time constant -- roughly 5-15 msec in literature", Directives: gti.Directives{}, Tag: "viewif:\"Gbar>0\" def:\"15\""}}, + {"DeTau", >i.Field{Name: "DeTau", Type: "float32", LocalType: "float32", Doc: "K channel gating factor deactivation time constant -- roughly 30-50 msec in literature", Directives: gti.Directives{}, Tag: "viewif:\"Gbar>0\" def:\"30\""}}, + {"KCaR", >i.Field{Name: "KCaR", Type: "float32", LocalType: "float32", Doc: "proportion of CaIn intracellular stores that are released per spike, going into CaR", Directives: gti.Directives{}, Tag: "viewif:\"Gbar>0\" def:\"0.4,0.8\""}}, + {"CaRDecayTau", >i.Field{Name: "CaRDecayTau", Type: "float32", LocalType: "float32", Doc: "SKCaR released calcium decay time constant", Directives: gti.Directives{}, Tag: "viewif:\"Gbar>0\" def:\"150,200\""}}, + {"CaInThr", >i.Field{Name: "CaInThr", Type: "float32", LocalType: "float32", Doc: "level of time-integrated spiking activity (CaSpkD) below which CaIn intracelluar stores are replenished -- a low threshold can be used to require minimal activity to recharge -- set to a high value (e.g., 10) for constant recharge.", Directives: gti.Directives{}, Tag: "viewif:\"Gbar>0\" def:\"0.01\""}}, + {"CaInTau", >i.Field{Name: "CaInTau", Type: "float32", LocalType: "float32", Doc: "time constant in msec for storing CaIn when activity is below CaInThr", Directives: gti.Directives{}, Tag: "viewif:\"Gbar>0\" def:\"50\""}}, + {"ActDt", >i.Field{Name: "ActDt", Type: "float32", LocalType: "float32", Doc: "rate = 1 / tau", Directives: gti.Directives{}, Tag: "view:\"-\" json:\"-\" xml:\"-\""}}, + {"DeDt", >i.Field{Name: "DeDt", Type: "float32", LocalType: "float32", Doc: "rate = 1 / tau", Directives: gti.Directives{}, Tag: "view:\"-\" json:\"-\" xml:\"-\""}}, + {"CaRDecayDt", >i.Field{Name: "CaRDecayDt", Type: "float32", LocalType: "float32", Doc: "rate = 1 / tau", Directives: gti.Directives{}, Tag: "view:\"-\" json:\"-\" xml:\"-\""}}, + {"CaInDt", >i.Field{Name: "CaInDt", Type: "float32", LocalType: "float32", Doc: "rate = 1 / tau", Directives: gti.Directives{}, Tag: "view:\"-\" json:\"-\" xml:\"-\""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/chans.VGCCParams", + ShortName: "chans.VGCCParams", + IDName: "vgcc-params", + Doc: "VGCCParams control the standard L-type Ca channel\nAll functions based on Urakubo et al (2008).\nSource code available at http://kurodalab.bs.s.u-tokyo.ac.jp/info/STDP/Urakubo2008.tar.gz.\nIn particular look at the file MODEL/Poirazi_cell/CaL.g.", + Directives: gti.Directives{ + >i.Directive{Tool: "gosl", Directive: "start", Args: []string{"chans"}}, + }, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"Gbar", >i.Field{Name: "Gbar", Type: "float32", LocalType: "float32", Doc: "strength of VGCC current -- 0.12 value is from Urakubo et al (2008) model -- best fits actual model behavior using axon equations (1.5 nominal in that model), 0.02 works better in practice for not getting stuck in high plateau firing", Directives: gti.Directives{}, Tag: "def:\"0.02,0.12\""}}, + {"Ca", >i.Field{Name: "Ca", Type: "float32", LocalType: "float32", Doc: "calcium from conductance factor -- important for learning contribution of VGCC", Directives: gti.Directives{}, Tag: "viewif:\"Gbar>0\" def:\"25\""}}, + {"pad", >i.Field{Name: "pad", Type: "int32", LocalType: "int32", Doc: "", Directives: gti.Directives{}, Tag: ""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) diff --git a/chans/kna.go b/chans/kna.go index a18858366..0a30615c8 100644 --- a/chans/kna.go +++ b/chans/kna.go @@ -4,7 +4,7 @@ package chans -import "github.com/goki/gosl/slbool" +import "goki.dev/gosl/v2/slbool" //gosl: start chans diff --git a/chans/mahp_plot/gtigen.go b/chans/mahp_plot/gtigen.go new file mode 100644 index 000000000..28d114390 --- /dev/null +++ b/chans/mahp_plot/gtigen.go @@ -0,0 +1,40 @@ +// Code generated by "goki generate -add-types"; DO NOT EDIT. + +package main + +import ( + "goki.dev/gti" + "goki.dev/ordmap" +) + +var _ = gti.AddType(>i.Type{ + Name: "main.Sim", + ShortName: "main.Sim", + IDName: "sim", + Doc: "Sim holds the params, table, etc", + Directives: gti.Directives{}, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"Mahp", >i.Field{Name: "Mahp", Type: "github.com/emer/axon/chans.MahpParams", LocalType: "chans.MahpParams", Doc: "mAHP function", Directives: gti.Directives{}, Tag: "view:\"inline\""}}, + {"Vstart", >i.Field{Name: "Vstart", Type: "float32", LocalType: "float32", Doc: "starting voltage", Directives: gti.Directives{}, Tag: "def:\"-100\""}}, + {"Vend", >i.Field{Name: "Vend", Type: "float32", LocalType: "float32", Doc: "ending voltage", Directives: gti.Directives{}, Tag: "def:\"100\""}}, + {"Vstep", >i.Field{Name: "Vstep", Type: "float32", LocalType: "float32", Doc: "voltage increment", Directives: gti.Directives{}, Tag: "def:\"1\""}}, + {"TimeSteps", >i.Field{Name: "TimeSteps", Type: "int", LocalType: "int", Doc: "number of time steps", Directives: gti.Directives{}, Tag: ""}}, + {"TimeSpike", >i.Field{Name: "TimeSpike", Type: "bool", LocalType: "bool", Doc: "do spiking instead of voltage ramp", Directives: gti.Directives{}, Tag: ""}}, + {"SpikeFreq", >i.Field{Name: "SpikeFreq", Type: "float32", LocalType: "float32", Doc: "spiking frequency", Directives: gti.Directives{}, Tag: ""}}, + {"TimeVstart", >i.Field{Name: "TimeVstart", Type: "float32", LocalType: "float32", Doc: "time-run starting membrane potential", Directives: gti.Directives{}, Tag: ""}}, + {"TimeVend", >i.Field{Name: "TimeVend", Type: "float32", LocalType: "float32", Doc: "time-run ending membrane potential", Directives: gti.Directives{}, Tag: ""}}, + {"Table", >i.Field{Name: "Table", Type: "*goki.dev/etable/v2/etable.Table", LocalType: "*etable.Table", Doc: "table for plot", Directives: gti.Directives{}, Tag: "view:\"no-inline\""}}, + {"Plot", >i.Field{Name: "Plot", Type: "*goki.dev/etable/v2/eplot.Plot2D", LocalType: "*eplot.Plot2D", Doc: "the plot", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + {"TimeTable", >i.Field{Name: "TimeTable", Type: "*goki.dev/etable/v2/etable.Table", LocalType: "*etable.Table", Doc: "table for plot", Directives: gti.Directives{}, Tag: "view:\"no-inline\""}}, + {"TimePlot", >i.Field{Name: "TimePlot", Type: "*goki.dev/etable/v2/eplot.Plot2D", LocalType: "*eplot.Plot2D", Doc: "the plot", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{ + {"VmRun", >i.Method{Name: "VmRun", Doc: "VmRun plots the equation as a function of V", Directives: gti.Directives{ + >i.Directive{Tool: "gti", Directive: "add", Args: []string{}}, + }, Args: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), Returns: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{})}}, + {"TimeRun", >i.Method{Name: "TimeRun", Doc: "TimeRun runs the equation over time.", Directives: gti.Directives{ + >i.Directive{Tool: "gti", Directive: "add", Args: []string{}}, + }, Args: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), Returns: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{})}}, + }), +}) diff --git a/chans/mahp_plot/mahp_plot.go b/chans/mahp_plot/mahp_plot.go index 7c2e69080..85f732a56 100644 --- a/chans/mahp_plot/mahp_plot.go +++ b/chans/mahp_plot/mahp_plot.go @@ -5,32 +5,30 @@ // mahp_plot plots an equation updating over time in a etable.Table and Plot2D. package main +//go:generate goki generate -add-types + import ( "strconv" "github.com/emer/axon/chans" - "github.com/emer/etable/eplot" - "github.com/emer/etable/etable" - "github.com/emer/etable/etensor" - _ "github.com/emer/etable/etview" // include to get gui views - "github.com/goki/gi/gi" - "github.com/goki/gi/gimain" - "github.com/goki/gi/giv" - "github.com/goki/ki/ki" - "github.com/goki/mat32" + "goki.dev/etable/v2/eplot" + "goki.dev/etable/v2/etable" + "goki.dev/etable/v2/etensor" + _ "goki.dev/etable/v2/etview" // include to get gui views + "goki.dev/gi/v2/gi" + "goki.dev/gi/v2/gimain" + "goki.dev/gi/v2/giv" + "goki.dev/icons" ) -func main() { - TheSim.Config() - gimain.Main(func() { // this starts gui -- requires valid OpenGL display connection (e.g., X11) - guirun() - }) -} +func main() { gimain.Run(app) } -func guirun() { - TheSim.VmRun() - win := TheSim.ConfigGui() - win.StartEventLoop() +func app() { + sim := &Sim{} + sim.Config() + sim.VmRun() + b := sim.ConfigGUI() + b.NewWindow().Run().Wait() } // LogPrec is precision for saving float values in logs @@ -77,17 +75,8 @@ type Sim struct { // the plot TimePlot *eplot.Plot2D `view:"-"` - - // main GUI window - Win *gi.Window `view:"-"` - - // the master toolbar - ToolBar *gi.ToolBar `view:"-"` } -// TheSim is the overall state for this simulation -var TheSim Sim - // Config configures all the elements using the standard functions func (ss *Sim) Config() { ss.Mahp.Defaults() @@ -112,7 +101,7 @@ func (ss *Sim) Update() { } // VmRun plots the equation as a function of V -func (ss *Sim) VmRun() { +func (ss *Sim) VmRun() { //gti:add ss.Update() dt := ss.Table @@ -129,7 +118,9 @@ func (ss *Sim) VmRun() { dt.SetCellFloat("Ninf", vi, float64(ninf)) dt.SetCellFloat("Tau", vi, float64(tau)) } - ss.Plot.Update() + if ss.Plot != nil { + ss.Plot.UpdatePlot() + } } func (ss *Sim) ConfigTable(dt *etable.Table) { @@ -159,7 +150,7 @@ func (ss *Sim) ConfigPlot(plt *eplot.Plot2D, dt *etable.Table) *eplot.Plot2D { ///////////////////////////////////////////////////////////////// // TimeRun runs the equation over time. -func (ss *Sim) TimeRun() { +func (ss *Sim) TimeRun() { //gti:add ss.Update() dt := ss.TimeTable @@ -210,7 +201,9 @@ func (ss *Sim) TimeRun() { } n += dn } - ss.TimePlot.Update() + if ss.TimePlot != nil { + ss.TimePlot.UpdatePlot() + } } func (ss *Sim) ConfigTimeTable(dt *etable.Table) { @@ -247,73 +240,28 @@ func (ss *Sim) ConfigTimePlot(plt *eplot.Plot2D, dt *etable.Table) *eplot.Plot2D return plt } -// ConfigGui configures the GoGi gui interface for this simulation, -func (ss *Sim) ConfigGui() *gi.Window { - width := 1600 - height := 1200 - - // gi.WinEventTrace = true - - gi.SetAppName("mahp_plot") - gi.SetAppAbout(`This plots an equation. See emergent on GitHub.

`) - - win := gi.NewMainWindow("mahp_plot", "Plotting Equations", width, height) - ss.Win = win +// ConfigGUI configures the GoGi gui interface for this simulation, +func (ss *Sim) ConfigGUI() *gi.Body { + b := gi.NewAppBody("mahp_plot").SetTitle("Plotting Equations") - vp := win.WinViewport2D() - updt := vp.UpdateStart() - - mfr := win.SetMainFrame() - - tbar := gi.AddNewToolBar(mfr, "tbar") - tbar.SetStretchMaxWidth() - ss.ToolBar = tbar - - split := gi.AddNewSplitView(mfr, "split") - split.Dim = mat32.X - split.SetStretchMax() - - sv := giv.AddNewStructView(split, "sv") + split := gi.NewSplits(b, "split") + sv := giv.NewStructView(split, "sv") sv.SetStruct(ss) - tv := gi.AddNewTabView(split, "tv") + tv := gi.NewTabs(split, "tv") - plt := tv.AddNewTab(eplot.KiT_Plot2D, "V-G Plot").(*eplot.Plot2D) - ss.Plot = ss.ConfigPlot(plt, ss.Table) + ss.Plot = eplot.NewSubPlot(tv.NewTab("V-G Plot")) + ss.ConfigPlot(ss.Plot, ss.Table) - plt = tv.AddNewTab(eplot.KiT_Plot2D, "TimePlot").(*eplot.Plot2D) - ss.TimePlot = ss.ConfigTimePlot(plt, ss.TimeTable) + ss.TimePlot = eplot.NewSubPlot(tv.NewTab("TimePlot")) + ss.ConfigTimePlot(ss.TimePlot, ss.TimeTable) split.SetSplits(.3, .7) - tbar.AddAction(gi.ActOpts{Label: "V-G Run", Icon: "update", Tooltip: "Run the equations and plot results."}, win.This(), func(recv, send ki.Ki, sig int64, data interface{}) { - ss.VmRun() - vp.SetNeedsFullRender() - }) - - tbar.AddAction(gi.ActOpts{Label: "Time Run", Icon: "update", Tooltip: "Run the equations and plot results."}, win.This(), func(recv, send ki.Ki, sig int64, data interface{}) { - ss.TimeRun() - vp.SetNeedsFullRender() + b.AddAppBar(func(tb *gi.Toolbar) { + giv.NewFuncButton(tb, ss.VmRun).SetIcon(icons.PlayArrow) + giv.NewFuncButton(tb, ss.TimeRun).SetIcon(icons.PlayArrow) }) - tbar.AddAction(gi.ActOpts{Label: "README", Icon: "file-markdown", Tooltip: "Opens your browser on the README file that contains instructions for how to run this model."}, win.This(), - func(recv, send ki.Ki, sig int64, data interface{}) { - gi.OpenURL("https://github.com/emer/axon/blob/master/chans/mahp_plot/README.md") - }) - - vp.UpdateEndNoSig(updt) - - // main menu - appnm := gi.AppName() - mmen := win.MainMenu - mmen.ConfigMenus([]string{appnm, "File", "Edit", "Window"}) - - amen := win.MainMenu.ChildByName(appnm, 0).(*gi.Action) - amen.Menu.AddAppMenu(win) - - emen := win.MainMenu.ChildByName("Edit", 1).(*gi.Action) - emen.Menu.AddCopyCutPaste(win) - - win.MainMenuUpdated() - return win + return b } diff --git a/chans/nmda_plot/gtigen.go b/chans/nmda_plot/gtigen.go new file mode 100644 index 000000000..b9a3c82fe --- /dev/null +++ b/chans/nmda_plot/gtigen.go @@ -0,0 +1,44 @@ +// Code generated by "goki generate -add-types"; DO NOT EDIT. + +package main + +import ( + "goki.dev/gti" + "goki.dev/ordmap" +) + +var _ = gti.AddType(>i.Type{ + Name: "main.Sim", + ShortName: "main.Sim", + IDName: "sim", + Doc: "Sim holds the params, table, etc", + Directives: gti.Directives{}, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"NMDAStd", >i.Field{Name: "NMDAStd", Type: "github.com/emer/axon/chans.NMDAParams", LocalType: "chans.NMDAParams", Doc: "standard NMDA implementation in chans", Directives: gti.Directives{}, Tag: ""}}, + {"NMDAv", >i.Field{Name: "NMDAv", Type: "float64", LocalType: "float64", Doc: "multiplier on NMDA as function of voltage", Directives: gti.Directives{}, Tag: "def:\"0.062\""}}, + {"MgC", >i.Field{Name: "MgC", Type: "float64", LocalType: "float64", Doc: "magnesium ion concentration -- somewhere between 1 and 1.5", Directives: gti.Directives{}, Tag: ""}}, + {"NMDAd", >i.Field{Name: "NMDAd", Type: "float64", LocalType: "float64", Doc: "denominator of NMDA function", Directives: gti.Directives{}, Tag: "def:\"3.57\""}}, + {"NMDAerev", >i.Field{Name: "NMDAerev", Type: "float64", LocalType: "float64", Doc: "NMDA reversal / driving potential", Directives: gti.Directives{}, Tag: "def:\"0\""}}, + {"BugVoff", >i.Field{Name: "BugVoff", Type: "float64", LocalType: "float64", Doc: "for old buggy NMDA: voff value to use", Directives: gti.Directives{}, Tag: ""}}, + {"Vstart", >i.Field{Name: "Vstart", Type: "float64", LocalType: "float64", Doc: "starting voltage", Directives: gti.Directives{}, Tag: "def:\"-90\""}}, + {"Vend", >i.Field{Name: "Vend", Type: "float64", LocalType: "float64", Doc: "ending voltage", Directives: gti.Directives{}, Tag: "def:\"10\""}}, + {"Vstep", >i.Field{Name: "Vstep", Type: "float64", LocalType: "float64", Doc: "voltage increment", Directives: gti.Directives{}, Tag: "def:\"1\""}}, + {"Tau", >i.Field{Name: "Tau", Type: "float64", LocalType: "float64", Doc: "decay time constant for NMDA current -- rise time is 2 msec and not worth extra effort for biexponential", Directives: gti.Directives{}, Tag: "def:\"100\""}}, + {"TimeSteps", >i.Field{Name: "TimeSteps", Type: "int", LocalType: "int", Doc: "number of time steps", Directives: gti.Directives{}, Tag: ""}}, + {"TimeV", >i.Field{Name: "TimeV", Type: "float64", LocalType: "float64", Doc: "voltage for TimeRun", Directives: gti.Directives{}, Tag: ""}}, + {"TimeGin", >i.Field{Name: "TimeGin", Type: "float64", LocalType: "float64", Doc: "NMDA Gsyn current input at every time step", Directives: gti.Directives{}, Tag: ""}}, + {"Table", >i.Field{Name: "Table", Type: "*goki.dev/etable/v2/etable.Table", LocalType: "*etable.Table", Doc: "table for plot", Directives: gti.Directives{}, Tag: "view:\"no-inline\""}}, + {"Plot", >i.Field{Name: "Plot", Type: "*goki.dev/etable/v2/eplot.Plot2D", LocalType: "*eplot.Plot2D", Doc: "the plot", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + {"TimeTable", >i.Field{Name: "TimeTable", Type: "*goki.dev/etable/v2/etable.Table", LocalType: "*etable.Table", Doc: "table for plot", Directives: gti.Directives{}, Tag: "view:\"no-inline\""}}, + {"TimePlot", >i.Field{Name: "TimePlot", Type: "*goki.dev/etable/v2/eplot.Plot2D", LocalType: "*eplot.Plot2D", Doc: "the plot", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{ + {"Run", >i.Method{Name: "Run", Doc: "Run runs the equation.", Directives: gti.Directives{ + >i.Directive{Tool: "gti", Directive: "add", Args: []string{}}, + }, Args: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), Returns: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{})}}, + {"TimeRun", >i.Method{Name: "TimeRun", Doc: "TimeRun runs the equation over time.", Directives: gti.Directives{ + >i.Directive{Tool: "gti", Directive: "add", Args: []string{}}, + }, Args: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), Returns: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{})}}, + }), +}) diff --git a/chans/nmda_plot/nmda_plot.go b/chans/nmda_plot/nmda_plot.go index 530139ebc..0b2dbc3ce 100644 --- a/chans/nmda_plot/nmda_plot.go +++ b/chans/nmda_plot/nmda_plot.go @@ -5,33 +5,32 @@ // nmda_plot plots an equation updating over time in a etable.Table and Plot2D. package main +//go:generate goki generate -add-types + import ( "math" "strconv" "github.com/emer/axon/chans" - "github.com/emer/etable/eplot" - "github.com/emer/etable/etable" - "github.com/emer/etable/etensor" - _ "github.com/emer/etable/etview" // include to get gui views - "github.com/goki/gi/gi" - "github.com/goki/gi/gimain" - "github.com/goki/gi/giv" - "github.com/goki/ki/ki" - "github.com/goki/mat32" + "goki.dev/etable/v2/eplot" + "goki.dev/etable/v2/etable" + "goki.dev/etable/v2/etensor" + _ "goki.dev/etable/v2/etview" // include to get gui views + "goki.dev/gi/v2/gi" + "goki.dev/gi/v2/gimain" + "goki.dev/gi/v2/giv" + "goki.dev/icons" + "goki.dev/mat32/v2" ) -func main() { - TheSim.Config() - gimain.Main(func() { // this starts gui - guirun() - }) -} +func main() { gimain.Run(app) } -func guirun() { - TheSim.Run() - win := TheSim.ConfigGui() - win.StartEventLoop() +func app() { + sim := &Sim{} + sim.Config() + sim.Run() + b := sim.ConfigGUI() + b.NewWindow().Run().Wait() } // LogPrec is precision for saving float values in logs @@ -90,17 +89,8 @@ type Sim struct { // the plot TimePlot *eplot.Plot2D `view:"-"` - - // main GUI window - Win *gi.Window `view:"-"` - - // the master toolbar - ToolBar *gi.ToolBar `view:"-"` } -// TheSim is the overall state for this simulation -var TheSim Sim - // Config configures all the elements using the standard functions func (ss *Sim) Config() { ss.NMDAStd.Defaults() @@ -132,7 +122,7 @@ func (ss *Sim) Update() { // https://brian2.readthedocs.io/en/stable/examples/frompapers.Brunel_Wang_2001.html // Run runs the equation. -func (ss *Sim) Run() { +func (ss *Sim) Run() { //gti:add ss.Update() dt := ss.Table @@ -166,7 +156,9 @@ func (ss *Sim) Run() { dt.SetCellFloat("Gnmda_bug", vi, float64(gbug)) dt.SetCellFloat("Ca", vi, float64(ca)) } - ss.Plot.Update() + if ss.Plot != nil { + ss.Plot.UpdatePlot() + } } func (ss *Sim) ConfigTable(dt *etable.Table) { @@ -200,7 +192,7 @@ func (ss *Sim) ConfigPlot(plt *eplot.Plot2D, dt *etable.Table) *eplot.Plot2D { ///////////////////////////////////////////////////////////////// // TimeRun runs the equation over time. -func (ss *Sim) TimeRun() { +func (ss *Sim) TimeRun() { //gti:add ss.Update() dt := ss.TimeTable @@ -222,7 +214,9 @@ func (ss *Sim) TimeRun() { dt.SetCellFloat("Gnmda", ti, g) dt.SetCellFloat("NMDA", ti, nmda) } - ss.TimePlot.Update() + if ss.TimePlot != nil { + ss.TimePlot.UpdatePlot() + } } func (ss *Sim) ConfigTimeTable(dt *etable.Table) { @@ -249,73 +243,28 @@ func (ss *Sim) ConfigTimePlot(plt *eplot.Plot2D, dt *etable.Table) *eplot.Plot2D return plt } -// ConfigGui configures the GoGi gui interface for this simulation, -func (ss *Sim) ConfigGui() *gi.Window { - width := 1600 - height := 1200 - - // gi.WinEventTrace = true - - gi.SetAppName("nmda_plot") - gi.SetAppAbout(`This plots an equation. See emergent on GitHub.

`) - - win := gi.NewMainWindow("nmdaplot", "Plotting Equations", width, height) - ss.Win = win +// ConfigGUI configures the GoGi gui interface for this simulation, +func (ss *Sim) ConfigGUI() *gi.Body { + b := gi.NewAppBody("nmda_plot").SetTitle("Plotting Equations") - vp := win.WinViewport2D() - updt := vp.UpdateStart() - - mfr := win.SetMainFrame() - - tbar := gi.AddNewToolBar(mfr, "tbar") - tbar.SetStretchMaxWidth() - ss.ToolBar = tbar - - split := gi.AddNewSplitView(mfr, "split") - split.Dim = mat32.X - split.SetStretchMax() - - sv := giv.AddNewStructView(split, "sv") + split := gi.NewSplits(b, "split") + sv := giv.NewStructView(split, "sv") sv.SetStruct(ss) - tv := gi.AddNewTabView(split, "tv") + tv := gi.NewTabs(split, "tv") - plt := tv.AddNewTab(eplot.KiT_Plot2D, "V-G Plot").(*eplot.Plot2D) - ss.Plot = ss.ConfigPlot(plt, ss.Table) + ss.Plot = eplot.NewSubPlot(tv.NewTab("V-G Plot")) + ss.ConfigPlot(ss.Plot, ss.Table) - plt = tv.AddNewTab(eplot.KiT_Plot2D, "TimePlot").(*eplot.Plot2D) - ss.TimePlot = ss.ConfigTimePlot(plt, ss.TimeTable) + ss.TimePlot = eplot.NewSubPlot(tv.NewTab("TimePlot")) + ss.ConfigTimePlot(ss.TimePlot, ss.TimeTable) split.SetSplits(.3, .7) - tbar.AddAction(gi.ActOpts{Label: "V-G Run", Icon: "update", Tooltip: "Run the equations and plot results."}, win.This(), func(recv, send ki.Ki, sig int64, data interface{}) { - ss.Run() - vp.SetNeedsFullRender() - }) - - tbar.AddAction(gi.ActOpts{Label: "Time Run", Icon: "update", Tooltip: "Run the equations and plot results."}, win.This(), func(recv, send ki.Ki, sig int64, data interface{}) { - ss.TimeRun() - vp.SetNeedsFullRender() + b.AddAppBar(func(tb *gi.Toolbar) { + giv.NewFuncButton(tb, ss.Run).SetIcon(icons.PlayArrow) + giv.NewFuncButton(tb, ss.TimeRun).SetIcon(icons.PlayArrow) }) - tbar.AddAction(gi.ActOpts{Label: "README", Icon: "file-markdown", Tooltip: "Opens your browser on the README file that contains instructions for how to run this model."}, win.This(), - func(recv, send ki.Ki, sig int64, data interface{}) { - gi.OpenURL("https://github.com/emer/axon/blob/master/chans/nmda_plot/README.md") - }) - - vp.UpdateEndNoSig(updt) - - // main menu - appnm := gi.AppName() - mmen := win.MainMenu - mmen.ConfigMenus([]string{appnm, "File", "Edit", "Window"}) - - amen := win.MainMenu.ChildByName(appnm, 0).(*gi.Action) - amen.Menu.AddAppMenu(win) - - emen := win.MainMenu.ChildByName("Edit", 1).(*gi.Action) - emen.Menu.AddCopyCutPaste(win) - - win.MainMenuUpdated() - return win + return b } diff --git a/chans/sahp_plot/gtigen.go b/chans/sahp_plot/gtigen.go new file mode 100644 index 000000000..1cb35ca70 --- /dev/null +++ b/chans/sahp_plot/gtigen.go @@ -0,0 +1,38 @@ +// Code generated by "goki generate -add-types"; DO NOT EDIT. + +package main + +import ( + "goki.dev/gti" + "goki.dev/ordmap" +) + +var _ = gti.AddType(>i.Type{ + Name: "main.Sim", + ShortName: "main.Sim", + IDName: "sim", + Doc: "Sim holds the params, table, etc", + Directives: gti.Directives{}, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"Sahp", >i.Field{Name: "Sahp", Type: "github.com/emer/axon/chans.SahpParams", LocalType: "chans.SahpParams", Doc: "sAHP function", Directives: gti.Directives{}, Tag: "view:\"inline\""}}, + {"CaStart", >i.Field{Name: "CaStart", Type: "float32", LocalType: "float32", Doc: "starting calcium", Directives: gti.Directives{}, Tag: "def:\"0\""}}, + {"CaEnd", >i.Field{Name: "CaEnd", Type: "float32", LocalType: "float32", Doc: "ending calcium", Directives: gti.Directives{}, Tag: "def:\"1.5\""}}, + {"CaStep", >i.Field{Name: "CaStep", Type: "float32", LocalType: "float32", Doc: "calcium increment", Directives: gti.Directives{}, Tag: "def:\"0.01\""}}, + {"TimeSteps", >i.Field{Name: "TimeSteps", Type: "int", LocalType: "int", Doc: "number of time steps", Directives: gti.Directives{}, Tag: ""}}, + {"TimeCaStart", >i.Field{Name: "TimeCaStart", Type: "float32", LocalType: "float32", Doc: "time-run starting calcium", Directives: gti.Directives{}, Tag: ""}}, + {"TimeCaD", >i.Field{Name: "TimeCaD", Type: "float32", LocalType: "float32", Doc: "time-run CaD value at end of each theta cycle", Directives: gti.Directives{}, Tag: ""}}, + {"Table", >i.Field{Name: "Table", Type: "*goki.dev/etable/v2/etable.Table", LocalType: "*etable.Table", Doc: "table for plot", Directives: gti.Directives{}, Tag: "view:\"no-inline\""}}, + {"Plot", >i.Field{Name: "Plot", Type: "*goki.dev/etable/v2/eplot.Plot2D", LocalType: "*eplot.Plot2D", Doc: "the plot", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + {"TimeTable", >i.Field{Name: "TimeTable", Type: "*goki.dev/etable/v2/etable.Table", LocalType: "*etable.Table", Doc: "table for plot", Directives: gti.Directives{}, Tag: "view:\"no-inline\""}}, + {"TimePlot", >i.Field{Name: "TimePlot", Type: "*goki.dev/etable/v2/eplot.Plot2D", LocalType: "*eplot.Plot2D", Doc: "the plot", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{ + {"CaRun", >i.Method{Name: "CaRun", Doc: "CaRun plots the equation as a function of V", Directives: gti.Directives{ + >i.Directive{Tool: "gti", Directive: "add", Args: []string{}}, + }, Args: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), Returns: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{})}}, + {"TimeRun", >i.Method{Name: "TimeRun", Doc: "TimeRun runs the equation over time.", Directives: gti.Directives{ + >i.Directive{Tool: "gti", Directive: "add", Args: []string{}}, + }, Args: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), Returns: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{})}}, + }), +}) diff --git a/chans/sahp_plot/sahp_plot.go b/chans/sahp_plot/sahp_plot.go index b2cfdd008..5bdd4851b 100644 --- a/chans/sahp_plot/sahp_plot.go +++ b/chans/sahp_plot/sahp_plot.go @@ -2,35 +2,33 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// mahp_plot plots an equation updating over time in a etable.Table and Plot2D. +// sahp_plot plots an equation updating over time in a etable.Table and Plot2D. package main +//go:generate goki generate -add-types + import ( "strconv" "github.com/emer/axon/chans" - "github.com/emer/etable/eplot" - "github.com/emer/etable/etable" - "github.com/emer/etable/etensor" - _ "github.com/emer/etable/etview" // include to get gui views - "github.com/goki/gi/gi" - "github.com/goki/gi/gimain" - "github.com/goki/gi/giv" - "github.com/goki/ki/ki" - "github.com/goki/mat32" + "goki.dev/etable/v2/eplot" + "goki.dev/etable/v2/etable" + "goki.dev/etable/v2/etensor" + _ "goki.dev/etable/v2/etview" // include to get gui views + "goki.dev/gi/v2/gi" + "goki.dev/gi/v2/gimain" + "goki.dev/gi/v2/giv" + "goki.dev/icons" ) -func main() { - TheSim.Config() - gimain.Main(func() { // this starts gui -- requires valid OpenGL display connection (e.g., X11) - guirun() - }) -} +func main() { gimain.Run(app) } -func guirun() { - TheSim.CaRun() - win := TheSim.ConfigGui() - win.StartEventLoop() +func app() { + sim := &Sim{} + sim.Config() + sim.CaRun() + b := sim.ConfigGUI() + b.NewWindow().Run().Wait() } // LogPrec is precision for saving float values in logs @@ -71,17 +69,8 @@ type Sim struct { // the plot TimePlot *eplot.Plot2D `view:"-"` - - // main GUI window - Win *gi.Window `view:"-"` - - // the master toolbar - ToolBar *gi.ToolBar `view:"-"` } -// TheSim is the overall state for this simulation -var TheSim Sim - // Config configures all the elements using the standard functions func (ss *Sim) Config() { ss.Sahp.Defaults() @@ -104,7 +93,7 @@ func (ss *Sim) Update() { } // CaRun plots the equation as a function of V -func (ss *Sim) CaRun() { +func (ss *Sim) CaRun() { //gti:add ss.Update() dt := ss.Table @@ -121,7 +110,9 @@ func (ss *Sim) CaRun() { dt.SetCellFloat("Ninf", vi, float64(ninf)) dt.SetCellFloat("Tau", vi, float64(tau)) } - ss.Plot.Update() + if ss.Plot != nil { + ss.Plot.UpdatePlot() + } } func (ss *Sim) ConfigTable(dt *etable.Table) { @@ -151,7 +142,7 @@ func (ss *Sim) ConfigPlot(plt *eplot.Plot2D, dt *etable.Table) *eplot.Plot2D { ///////////////////////////////////////////////////////////////// // TimeRun runs the equation over time. -func (ss *Sim) TimeRun() { +func (ss *Sim) TimeRun() { //gti:add ss.Update() dt := ss.TimeTable @@ -181,7 +172,9 @@ func (ss *Sim) TimeRun() { ca = mp.CaInt(ca, ss.TimeCaD) n += dn } - ss.TimePlot.Update() + if ss.TimePlot != nil { + ss.TimePlot.UpdatePlot() + } } func (ss *Sim) ConfigTimeTable(dt *etable.Table) { @@ -218,73 +211,28 @@ func (ss *Sim) ConfigTimePlot(plt *eplot.Plot2D, dt *etable.Table) *eplot.Plot2D return plt } -// ConfigGui configures the GoGi gui interface for this simulation, -func (ss *Sim) ConfigGui() *gi.Window { - width := 1600 - height := 1200 - - // gi.WinEventTrace = true - - gi.SetAppName("sahp_plot") - gi.SetAppAbout(`This plots an equation. See emergent on GitHub.

`) - - win := gi.NewMainWindow("sahp_plot", "Plotting Equations", width, height) - ss.Win = win +// ConfigGUI configures the GoGi gui interface for this simulation, +func (ss *Sim) ConfigGUI() *gi.Body { + b := gi.NewAppBody("sahp_plot").SetTitle("Plotting Equations") - vp := win.WinViewport2D() - updt := vp.UpdateStart() - - mfr := win.SetMainFrame() - - tbar := gi.AddNewToolBar(mfr, "tbar") - tbar.SetStretchMaxWidth() - ss.ToolBar = tbar - - split := gi.AddNewSplitView(mfr, "split") - split.Dim = mat32.X - split.SetStretchMax() - - sv := giv.AddNewStructView(split, "sv") + split := gi.NewSplits(b, "split") + sv := giv.NewStructView(split, "sv") sv.SetStruct(ss) - tv := gi.AddNewTabView(split, "tv") + tv := gi.NewTabs(split, "tv") - plt := tv.AddNewTab(eplot.KiT_Plot2D, "Ca-G Plot").(*eplot.Plot2D) - ss.Plot = ss.ConfigPlot(plt, ss.Table) + ss.Plot = eplot.NewSubPlot(tv.NewTab("Ca-G Plot")) + ss.ConfigPlot(ss.Plot, ss.Table) - plt = tv.AddNewTab(eplot.KiT_Plot2D, "TimePlot").(*eplot.Plot2D) - ss.TimePlot = ss.ConfigTimePlot(plt, ss.TimeTable) + ss.TimePlot = eplot.NewSubPlot(tv.NewTab("TimePlot")) + ss.ConfigTimePlot(ss.TimePlot, ss.TimeTable) split.SetSplits(.3, .7) - tbar.AddAction(gi.ActOpts{Label: "Ca-G Run", Icon: "update", Tooltip: "Run the equations and plot results."}, win.This(), func(recv, send ki.Ki, sig int64, data interface{}) { - ss.CaRun() - vp.SetNeedsFullRender() - }) - - tbar.AddAction(gi.ActOpts{Label: "Time Run", Icon: "update", Tooltip: "Run the equations and plot results."}, win.This(), func(recv, send ki.Ki, sig int64, data interface{}) { - ss.TimeRun() - vp.SetNeedsFullRender() + b.AddAppBar(func(tb *gi.Toolbar) { + giv.NewFuncButton(tb, ss.CaRun).SetIcon(icons.PlayArrow) + giv.NewFuncButton(tb, ss.TimeRun).SetIcon(icons.PlayArrow) }) - tbar.AddAction(gi.ActOpts{Label: "README", Icon: "file-markdown", Tooltip: "Opens your browser on the README file that contains instructions for how to run this model."}, win.This(), - func(recv, send ki.Ki, sig int64, data interface{}) { - gi.OpenURL("https://github.com/emer/axon/blob/master/chans/sahp_plot/README.md") - }) - - vp.UpdateEndNoSig(updt) - - // main menu - appnm := gi.AppName() - mmen := win.MainMenu - mmen.ConfigMenus([]string{appnm, "File", "Edit", "Window"}) - - amen := win.MainMenu.ChildByName(appnm, 0).(*gi.Action) - amen.Menu.AddAppMenu(win) - - emen := win.MainMenu.ChildByName("Edit", 1).(*gi.Action) - emen.Menu.AddCopyCutPaste(win) - - win.MainMenuUpdated() - return win + return b } diff --git a/chans/skca_plot/gtigen.go b/chans/skca_plot/gtigen.go new file mode 100644 index 000000000..c043acdb1 --- /dev/null +++ b/chans/skca_plot/gtigen.go @@ -0,0 +1,38 @@ +// Code generated by "goki generate -add-types"; DO NOT EDIT. + +package main + +import ( + "goki.dev/gti" + "goki.dev/ordmap" +) + +var _ = gti.AddType(>i.Type{ + Name: "main.Sim", + ShortName: "main.Sim", + IDName: "sim", + Doc: "Sim holds the params, table, etc", + Directives: gti.Directives{}, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"SKCa", >i.Field{Name: "SKCa", Type: "github.com/emer/axon/chans.SKCaParams", LocalType: "chans.SKCaParams", Doc: "SKCa params", Directives: gti.Directives{}, Tag: ""}}, + {"CaParams", >i.Field{Name: "CaParams", Type: "github.com/emer/axon/kinase.CaParams", LocalType: "kinase.CaParams", Doc: "time constants for integrating Ca from spiking across M, P and D cascading levels", Directives: gti.Directives{}, Tag: ""}}, + {"NoSpikeThr", >i.Field{Name: "NoSpikeThr", Type: "float32", LocalType: "float32", Doc: "threshold of SK M gating factor above which the neuron cannot spike", Directives: gti.Directives{}, Tag: "def:\"0.5\""}}, + {"CaStep", >i.Field{Name: "CaStep", Type: "float32", LocalType: "float32", Doc: "Ca conc increment for M gating func plot", Directives: gti.Directives{}, Tag: "def:\"0.05\""}}, + {"TimeSteps", >i.Field{Name: "TimeSteps", Type: "int", LocalType: "int", Doc: "number of time steps", Directives: gti.Directives{}, Tag: ""}}, + {"TimeSpike", >i.Field{Name: "TimeSpike", Type: "bool", LocalType: "bool", Doc: "do spiking instead of Ca conc ramp", Directives: gti.Directives{}, Tag: ""}}, + {"SpikeFreq", >i.Field{Name: "SpikeFreq", Type: "float32", LocalType: "float32", Doc: "spiking frequency", Directives: gti.Directives{}, Tag: ""}}, + {"Table", >i.Field{Name: "Table", Type: "*goki.dev/etable/v2/etable.Table", LocalType: "*etable.Table", Doc: "table for plot", Directives: gti.Directives{}, Tag: "view:\"no-inline\""}}, + {"Plot", >i.Field{Name: "Plot", Type: "*goki.dev/etable/v2/eplot.Plot2D", LocalType: "*eplot.Plot2D", Doc: "the plot", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + {"TimeTable", >i.Field{Name: "TimeTable", Type: "*goki.dev/etable/v2/etable.Table", LocalType: "*etable.Table", Doc: "table for plot", Directives: gti.Directives{}, Tag: "view:\"no-inline\""}}, + {"TimePlot", >i.Field{Name: "TimePlot", Type: "*goki.dev/etable/v2/eplot.Plot2D", LocalType: "*eplot.Plot2D", Doc: "the plot", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{ + {"CamRun", >i.Method{Name: "CamRun", Doc: "CamRun plots the equation as a function of Ca", Directives: gti.Directives{ + >i.Directive{Tool: "gti", Directive: "add", Args: []string{}}, + }, Args: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), Returns: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{})}}, + {"TimeRun", >i.Method{Name: "TimeRun", Doc: "TimeRun runs the equation over time.", Directives: gti.Directives{ + >i.Directive{Tool: "gti", Directive: "add", Args: []string{}}, + }, Args: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), Returns: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{})}}, + }), +}) diff --git a/chans/skca_plot/skca_plot.go b/chans/skca_plot/skca_plot.go index 61fcd9184..633e8353a 100644 --- a/chans/skca_plot/skca_plot.go +++ b/chans/skca_plot/skca_plot.go @@ -5,33 +5,31 @@ // ska_plot plots an equation updating over time in a etable.Table and Plot2D. package main +//go:generate goki generate -add-types + import ( "strconv" "github.com/emer/axon/chans" "github.com/emer/axon/kinase" - "github.com/emer/etable/eplot" - "github.com/emer/etable/etable" - "github.com/emer/etable/etensor" - _ "github.com/emer/etable/etview" // include to get gui views - "github.com/goki/gi/gi" - "github.com/goki/gi/gimain" - "github.com/goki/gi/giv" - "github.com/goki/ki/ki" - "github.com/goki/mat32" + "goki.dev/etable/v2/eplot" + "goki.dev/etable/v2/etable" + "goki.dev/etable/v2/etensor" + _ "goki.dev/etable/v2/etview" // include to get gui views + "goki.dev/gi/v2/gi" + "goki.dev/gi/v2/gimain" + "goki.dev/gi/v2/giv" + "goki.dev/icons" ) -func main() { - TheSim.Config() - gimain.Main(func() { // this starts gui -- requires valid OpenGL display connection (e.g., X11) - guirun() - }) -} +func main() { gimain.Run(app) } -func guirun() { - TheSim.CamRun() - win := TheSim.ConfigGui() - win.StartEventLoop() +func app() { + sim := &Sim{} + sim.Config() + sim.CamRun() + b := sim.ConfigGUI() + b.NewWindow().Run().Wait() } // LogPrec is precision for saving float values in logs @@ -72,17 +70,8 @@ type Sim struct { // the plot TimePlot *eplot.Plot2D `view:"-"` - - // main GUI window - Win *gi.Window `view:"-"` - - // the master toolbar - ToolBar *gi.ToolBar `view:"-"` } -// TheSim is the overall state for this simulation -var TheSim Sim - // Config configures all the elements using the standard functions func (ss *Sim) Config() { ss.SKCa.Defaults() @@ -105,7 +94,7 @@ func (ss *Sim) Update() { } // CamRun plots the equation as a function of Ca -func (ss *Sim) CamRun() { +func (ss *Sim) CamRun() { //gti:add ss.Update() dt := ss.Table @@ -120,7 +109,9 @@ func (ss *Sim) CamRun() { dt.SetCellFloat("Mhill", vi, float64(mh)) dt.SetCellFloat("Mgw06", vi, float64(mg)) } - ss.Plot.Update() + if ss.Plot != nil { + ss.Plot.UpdatePlot() + } } func (ss *Sim) ConfigTable(dt *etable.Table) { @@ -150,7 +141,7 @@ func (ss *Sim) ConfigPlot(plt *eplot.Plot2D, dt *etable.Table) *eplot.Plot2D { ///////////////////////////////////////////////////////////////// // TimeRun runs the equation over time. -func (ss *Sim) TimeRun() { +func (ss *Sim) TimeRun() { //gti:add ss.Update() dt := ss.TimeTable @@ -190,7 +181,9 @@ func (ss *Sim) TimeRun() { } ss.CaParams.FmSpike(spike, &caM, &caP, &caD) } - ss.TimePlot.Update() + if ss.TimePlot != nil { + ss.TimePlot.UpdatePlot() + } } func (ss *Sim) ConfigTimeTable(dt *etable.Table) { @@ -227,73 +220,28 @@ func (ss *Sim) ConfigTimePlot(plt *eplot.Plot2D, dt *etable.Table) *eplot.Plot2D return plt } -// ConfigGui configures the GoGi gui interface for this simulation, -func (ss *Sim) ConfigGui() *gi.Window { - width := 1600 - height := 1200 - - // gi.WinEventTrace = true - - gi.SetAppName("skca_plot") - gi.SetAppAbout(`This plots an equation. See emergent on GitHub.

`) - - win := gi.NewMainWindow("skca_plot", "Plotting Equations", width, height) - ss.Win = win +// ConfigGUI configures the GoGi gui interface for this simulation, +func (ss *Sim) ConfigGUI() *gi.Body { + b := gi.NewAppBody("skca_plot").SetTitle("Plotting Equations") - vp := win.WinViewport2D() - updt := vp.UpdateStart() - - mfr := win.SetMainFrame() - - tbar := gi.AddNewToolBar(mfr, "tbar") - tbar.SetStretchMaxWidth() - ss.ToolBar = tbar - - split := gi.AddNewSplitView(mfr, "split") - split.Dim = mat32.X - split.SetStretchMax() - - sv := giv.AddNewStructView(split, "sv") + split := gi.NewSplits(b, "split") + sv := giv.NewStructView(split, "sv") sv.SetStruct(ss) - tv := gi.AddNewTabView(split, "tv") + tv := gi.NewTabs(split, "tv") - plt := tv.AddNewTab(eplot.KiT_Plot2D, "Ca-G Plot").(*eplot.Plot2D) - ss.Plot = ss.ConfigPlot(plt, ss.Table) + ss.Plot = eplot.NewSubPlot(tv.NewTab("Ca-G Plot")) + ss.ConfigPlot(ss.Plot, ss.Table) - plt = tv.AddNewTab(eplot.KiT_Plot2D, "TimePlot").(*eplot.Plot2D) - ss.TimePlot = ss.ConfigTimePlot(plt, ss.TimeTable) + ss.TimePlot = eplot.NewSubPlot(tv.NewTab("TimePlot")) + ss.ConfigTimePlot(ss.TimePlot, ss.TimeTable) split.SetSplits(.3, .7) - tbar.AddAction(gi.ActOpts{Label: "Ca-M Run", Icon: "update", Tooltip: "Run the equations and plot results."}, win.This(), func(recv, send ki.Ki, sig int64, data interface{}) { - ss.CamRun() - vp.SetNeedsFullRender() - }) - - tbar.AddAction(gi.ActOpts{Label: "Time Run", Icon: "update", Tooltip: "Run the equations and plot results."}, win.This(), func(recv, send ki.Ki, sig int64, data interface{}) { - ss.TimeRun() - vp.SetNeedsFullRender() + b.AddAppBar(func(tb *gi.Toolbar) { + giv.NewFuncButton(tb, ss.CamRun).SetIcon(icons.PlayArrow) + giv.NewFuncButton(tb, ss.TimeRun).SetIcon(icons.PlayArrow) }) - tbar.AddAction(gi.ActOpts{Label: "README", Icon: "file-markdown", Tooltip: "Opens your browser on the README file that contains instructions for how to run this model."}, win.This(), - func(recv, send ki.Ki, sig int64, data interface{}) { - gi.OpenURL("https://github.com/emer/axon/blob/master/chans/skca_plot/README.md") - }) - - vp.UpdateEndNoSig(updt) - - // main menu - appnm := gi.AppName() - mmen := win.MainMenu - mmen.ConfigMenus([]string{appnm, "File", "Edit", "Window"}) - - amen := win.MainMenu.ChildByName(appnm, 0).(*gi.Action) - amen.Menu.AddAppMenu(win) - - emen := win.MainMenu.ChildByName("Edit", 1).(*gi.Action) - emen.Menu.AddCopyCutPaste(win) - - win.MainMenuUpdated() - return win + return b } diff --git a/chans/vgcc_plot/gtigen.go b/chans/vgcc_plot/gtigen.go new file mode 100644 index 000000000..50a5a92ca --- /dev/null +++ b/chans/vgcc_plot/gtigen.go @@ -0,0 +1,40 @@ +// Code generated by "goki generate -add-types"; DO NOT EDIT. + +package main + +import ( + "goki.dev/gti" + "goki.dev/ordmap" +) + +var _ = gti.AddType(>i.Type{ + Name: "main.Sim", + ShortName: "main.Sim", + IDName: "sim", + Doc: "Sim holds the params, table, etc", + Directives: gti.Directives{}, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"VGCC", >i.Field{Name: "VGCC", Type: "github.com/emer/axon/chans.VGCCParams", LocalType: "chans.VGCCParams", Doc: "VGCC function", Directives: gti.Directives{}, Tag: ""}}, + {"Vstart", >i.Field{Name: "Vstart", Type: "float32", LocalType: "float32", Doc: "starting voltage", Directives: gti.Directives{}, Tag: "def:\"-90\""}}, + {"Vend", >i.Field{Name: "Vend", Type: "float32", LocalType: "float32", Doc: "ending voltage", Directives: gti.Directives{}, Tag: "def:\"0\""}}, + {"Vstep", >i.Field{Name: "Vstep", Type: "float32", LocalType: "float32", Doc: "voltage increment", Directives: gti.Directives{}, Tag: "def:\"1\""}}, + {"TimeSteps", >i.Field{Name: "TimeSteps", Type: "int", LocalType: "int", Doc: "number of time steps", Directives: gti.Directives{}, Tag: ""}}, + {"TimeSpike", >i.Field{Name: "TimeSpike", Type: "bool", LocalType: "bool", Doc: "do spiking instead of voltage ramp", Directives: gti.Directives{}, Tag: ""}}, + {"SpikeFreq", >i.Field{Name: "SpikeFreq", Type: "float32", LocalType: "float32", Doc: "spiking frequency", Directives: gti.Directives{}, Tag: ""}}, + {"TimeVstart", >i.Field{Name: "TimeVstart", Type: "float32", LocalType: "float32", Doc: "time-run starting membrane potential", Directives: gti.Directives{}, Tag: ""}}, + {"TimeVend", >i.Field{Name: "TimeVend", Type: "float32", LocalType: "float32", Doc: "time-run ending membrane potential", Directives: gti.Directives{}, Tag: ""}}, + {"Table", >i.Field{Name: "Table", Type: "*goki.dev/etable/v2/etable.Table", LocalType: "*etable.Table", Doc: "table for plot", Directives: gti.Directives{}, Tag: "view:\"no-inline\""}}, + {"Plot", >i.Field{Name: "Plot", Type: "*goki.dev/etable/v2/eplot.Plot2D", LocalType: "*eplot.Plot2D", Doc: "the plot", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + {"TimeTable", >i.Field{Name: "TimeTable", Type: "*goki.dev/etable/v2/etable.Table", LocalType: "*etable.Table", Doc: "table for plot", Directives: gti.Directives{}, Tag: "view:\"no-inline\""}}, + {"TimePlot", >i.Field{Name: "TimePlot", Type: "*goki.dev/etable/v2/eplot.Plot2D", LocalType: "*eplot.Plot2D", Doc: "the plot", Directives: gti.Directives{}, Tag: "view:\"-\""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{ + {"VmRun", >i.Method{Name: "VmRun", Doc: "VmRun plots the equation as a function of V", Directives: gti.Directives{ + >i.Directive{Tool: "gti", Directive: "add", Args: []string{}}, + }, Args: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), Returns: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{})}}, + {"TimeRun", >i.Method{Name: "TimeRun", Doc: "TimeRun runs the equation over time.", Directives: gti.Directives{ + >i.Directive{Tool: "gti", Directive: "add", Args: []string{}}, + }, Args: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), Returns: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{})}}, + }), +}) diff --git a/chans/vgcc_plot/vgcc_plot.go b/chans/vgcc_plot/vgcc_plot.go index 51cf2ba7b..31e924385 100644 --- a/chans/vgcc_plot/vgcc_plot.go +++ b/chans/vgcc_plot/vgcc_plot.go @@ -5,32 +5,30 @@ // vgcc_plot plots an equation updating over time in a etable.Table and Plot2D. package main +//go:generate goki generate -add-types + import ( "strconv" "github.com/emer/axon/chans" - "github.com/emer/etable/eplot" - "github.com/emer/etable/etable" - "github.com/emer/etable/etensor" - _ "github.com/emer/etable/etview" // include to get gui views - "github.com/goki/gi/gi" - "github.com/goki/gi/gimain" - "github.com/goki/gi/giv" - "github.com/goki/ki/ki" - "github.com/goki/mat32" + "goki.dev/etable/v2/eplot" + "goki.dev/etable/v2/etable" + "goki.dev/etable/v2/etensor" + _ "goki.dev/etable/v2/etview" // include to get gui views + "goki.dev/gi/v2/gi" + "goki.dev/gi/v2/gimain" + "goki.dev/gi/v2/giv" + "goki.dev/icons" ) -func main() { - TheSim.Config() - gimain.Main(func() { // this starts gui -- requires valid OpenGL display connection (e.g., X11) - guirun() - }) -} +func main() { gimain.Run(app) } -func guirun() { - TheSim.VmRun() - win := TheSim.ConfigGui() - win.StartEventLoop() +func app() { + sim := &Sim{} + sim.Config() + sim.VmRun() + b := sim.ConfigGUI() + b.NewWindow().Run().Wait() } // LogPrec is precision for saving float values in logs @@ -77,17 +75,8 @@ type Sim struct { // the plot TimePlot *eplot.Plot2D `view:"-"` - - // main GUI window - Win *gi.Window `view:"-"` - - // the master toolbar - ToolBar *gi.ToolBar `view:"-"` } -// TheSim is the overall state for this simulation -var TheSim Sim - // Config configures all the elements using the standard functions func (ss *Sim) Config() { ss.VGCC.Defaults() @@ -112,7 +101,7 @@ func (ss *Sim) Update() { } // VmRun plots the equation as a function of V -func (ss *Sim) VmRun() { +func (ss *Sim) VmRun() { //gti:add ss.Update() dt := ss.Table @@ -134,7 +123,9 @@ func (ss *Sim) VmRun() { dt.SetCellFloat("dM", vi, float64(dm)) dt.SetCellFloat("dH", vi, float64(dh)) } - ss.Plot.Update() + if ss.Plot != nil { + ss.Plot.UpdatePlot() + } } func (ss *Sim) ConfigTable(dt *etable.Table) { @@ -168,7 +159,7 @@ func (ss *Sim) ConfigPlot(plt *eplot.Plot2D, dt *etable.Table) *eplot.Plot2D { ///////////////////////////////////////////////////////////////// // TimeRun runs the equation over time. -func (ss *Sim) TimeRun() { +func (ss *Sim) TimeRun() { //gti:add ss.Update() dt := ss.TimeTable @@ -212,7 +203,9 @@ func (ss *Sim) TimeRun() { } } } - ss.TimePlot.Update() + if ss.TimePlot != nil { + ss.TimePlot.UpdatePlot() + } } func (ss *Sim) ConfigTimeTable(dt *etable.Table) { @@ -246,73 +239,28 @@ func (ss *Sim) ConfigTimePlot(plt *eplot.Plot2D, dt *etable.Table) *eplot.Plot2D return plt } -// ConfigGui configures the GoGi gui interface for this simulation, -func (ss *Sim) ConfigGui() *gi.Window { - width := 1600 - height := 1200 - - // gi.WinEventTrace = true - - gi.SetAppName("vgcc_plot") - gi.SetAppAbout(`This plots an equation. See emergent on GitHub.

`) - - win := gi.NewMainWindow("vgcc_plot", "Plotting Equations", width, height) - ss.Win = win +// ConfigGUI configures the GoGi gui interface for this simulation, +func (ss *Sim) ConfigGUI() *gi.Body { + b := gi.NewAppBody("vgcc_plot").SetTitle("Plotting Equations") - vp := win.WinViewport2D() - updt := vp.UpdateStart() - - mfr := win.SetMainFrame() - - tbar := gi.AddNewToolBar(mfr, "tbar") - tbar.SetStretchMaxWidth() - ss.ToolBar = tbar - - split := gi.AddNewSplitView(mfr, "split") - split.Dim = mat32.X - split.SetStretchMax() - - sv := giv.AddNewStructView(split, "sv") + split := gi.NewSplits(b, "split") + sv := giv.NewStructView(split, "sv") sv.SetStruct(ss) - tv := gi.AddNewTabView(split, "tv") + tv := gi.NewTabs(split, "tv") - plt := tv.AddNewTab(eplot.KiT_Plot2D, "V-G Plot").(*eplot.Plot2D) - ss.Plot = ss.ConfigPlot(plt, ss.Table) + ss.Plot = eplot.NewSubPlot(tv.NewTab("V-G Plot")) + ss.ConfigPlot(ss.Plot, ss.Table) - plt = tv.AddNewTab(eplot.KiT_Plot2D, "TimePlot").(*eplot.Plot2D) - ss.TimePlot = ss.ConfigTimePlot(plt, ss.TimeTable) + ss.TimePlot = eplot.NewSubPlot(tv.NewTab("TimePlot")) + ss.ConfigTimePlot(ss.TimePlot, ss.TimeTable) split.SetSplits(.3, .7) - tbar.AddAction(gi.ActOpts{Label: "V-G Run", Icon: "update", Tooltip: "Run the equations and plot results."}, win.This(), func(recv, send ki.Ki, sig int64, data interface{}) { - ss.VmRun() - vp.SetNeedsFullRender() - }) - - tbar.AddAction(gi.ActOpts{Label: "Time Run", Icon: "update", Tooltip: "Run the equations and plot results."}, win.This(), func(recv, send ki.Ki, sig int64, data interface{}) { - ss.TimeRun() - vp.SetNeedsFullRender() + b.AddAppBar(func(tb *gi.Toolbar) { + giv.NewFuncButton(tb, ss.VmRun).SetIcon(icons.PlayArrow) + giv.NewFuncButton(tb, ss.TimeRun).SetIcon(icons.PlayArrow) }) - tbar.AddAction(gi.ActOpts{Label: "README", Icon: "file-markdown", Tooltip: "Opens your browser on the README file that contains instructions for how to run this model."}, win.This(), - func(recv, send ki.Ki, sig int64, data interface{}) { - gi.OpenURL("https://github.com/emer/axon/blob/master/chans/vgcc_plot/README.md") - }) - - vp.UpdateEndNoSig(updt) - - // main menu - appnm := gi.AppName() - mmen := win.MainMenu - mmen.ConfigMenus([]string{appnm, "File", "Edit", "Window"}) - - amen := win.MainMenu.ChildByName(appnm, 0).(*gi.Action) - amen.Menu.AddAppMenu(win) - - emen := win.MainMenu.ChildByName("Edit", 1).(*gi.Action) - emen.Menu.AddCopyCutPaste(win) - - win.MainMenuUpdated() - return win + return b } diff --git a/fsfffb/fsfffb.go b/fsfffb/fsfffb.go index 47460a194..2e2f36122 100644 --- a/fsfffb/fsfffb.go +++ b/fsfffb/fsfffb.go @@ -13,7 +13,7 @@ active at any time, where k is typically 10-20 percent of N. */ package fsfffb -import "github.com/goki/gosl/slbool" +import "goki.dev/gosl/v2/slbool" //gosl: start fsfffb diff --git a/fsfffb/inhib.go b/fsfffb/inhib.go index 81eeb394e..f52c05379 100644 --- a/fsfffb/inhib.go +++ b/fsfffb/inhib.go @@ -7,7 +7,7 @@ package fsfffb import ( "log" - "github.com/goki/gosl/slbool" + "goki.dev/gosl/v2/slbool" "goki.dev/mat32/v2" ) diff --git a/kinase/enumgen.go b/kinase/enumgen.go new file mode 100644 index 000000000..4f4eea767 --- /dev/null +++ b/kinase/enumgen.go @@ -0,0 +1,131 @@ +// Code generated by "goki generate -add-types"; DO NOT EDIT. + +package kinase + +import ( + "errors" + "log" + "strconv" + "strings" + + "goki.dev/enums" +) + +var _RulesValues = []Rules{0, 1, 2, 3} + +// RulesN is the highest valid value +// for type Rules, plus one. +const RulesN Rules = 4 + +// An "invalid array index" compiler error signifies that the constant values have changed. +// Re-run the enumgen command to generate them again. +func _RulesNoOp() { + var x [1]struct{} + _ = x[SynSpkCont-(0)] + _ = x[SynNMDACont-(1)] + _ = x[SynSpkTheta-(2)] + _ = x[NeurSpkTheta-(3)] +} + +var _RulesNameToValueMap = map[string]Rules{ + `SynSpkCont`: 0, + `synspkcont`: 0, + `SynNMDACont`: 1, + `synnmdacont`: 1, + `SynSpkTheta`: 2, + `synspktheta`: 2, + `NeurSpkTheta`: 3, + `neurspktheta`: 3, +} + +var _RulesDescMap = map[Rules]string{ + 0: `SynSpkCont implements synaptic-level Ca signals at an abstract level, purely driven by spikes, not NMDA channel Ca, as a product of sender and recv CaSyn values that capture the decaying Ca trace from spiking, qualitatively as in the NMDA dynamics. These spike-driven Ca signals are integrated in a cascaded manner via CaM, then CaP (reflecting CaMKII) and finally CaD (reflecting DAPK1). It uses continuous learning based on temporary DWt (TDWt) values based on the TWindow around spikes, which convert into DWt after a pause in synaptic activity (no arbitrary ThetaCycle boundaries). There is an option to compare with SynSpkTheta by only doing DWt updates at the theta cycle level, in which case the key difference is the use of TDWt, which can remove some variability associated with the arbitrary timing of the end of trials.`, + 1: `SynNMDACont is the same as SynSpkCont with NMDA-driven calcium signals computed according to the very close approximation to the Urakubo et al (2008) allosteric NMDA dynamics, then integrated at P vs. D time scales. This is the most biologically realistic yet computationally tractable verseion of the Kinase learning algorithm.`, + 2: `SynSpkTheta abstracts the SynSpkCont algorithm by only computing the DWt change at the end of the ThetaCycle, instead of continuous updating. This allows an optimized implementation that is roughly 1/3 slower than the fastest NeurSpkTheta version, while still capturing much of the learning dynamics by virtue of synaptic-level integration.`, + 3: `NeurSpkTheta uses neuron-level spike-driven calcium signals integrated at P vs. D time scales -- this is the original Leabra and Axon XCAL / CHL learning rule. It exhibits strong sensitivity to final spikes and thus high levels of variance.`, +} + +var _RulesMap = map[Rules]string{ + 0: `SynSpkCont`, + 1: `SynNMDACont`, + 2: `SynSpkTheta`, + 3: `NeurSpkTheta`, +} + +// String returns the string representation +// of this Rules value. +func (i Rules) String() string { + if str, ok := _RulesMap[i]; ok { + return str + } + return strconv.FormatInt(int64(i), 10) +} + +// SetString sets the Rules value from its +// string representation, and returns an +// error if the string is invalid. +func (i *Rules) SetString(s string) error { + if val, ok := _RulesNameToValueMap[s]; ok { + *i = val + return nil + } + if val, ok := _RulesNameToValueMap[strings.ToLower(s)]; ok { + *i = val + return nil + } + return errors.New(s + " is not a valid value for type Rules") +} + +// Int64 returns the Rules value as an int64. +func (i Rules) Int64() int64 { + return int64(i) +} + +// SetInt64 sets the Rules value from an int64. +func (i *Rules) SetInt64(in int64) { + *i = Rules(in) +} + +// Desc returns the description of the Rules value. +func (i Rules) Desc() string { + if str, ok := _RulesDescMap[i]; ok { + return str + } + return i.String() +} + +// RulesValues returns all possible values +// for the type Rules. +func RulesValues() []Rules { + return _RulesValues +} + +// Values returns all possible values +// for the type Rules. +func (i Rules) Values() []enums.Enum { + res := make([]enums.Enum, len(_RulesValues)) + for i, d := range _RulesValues { + res[i] = d + } + return res +} + +// IsValid returns whether the value is a +// valid option for type Rules. +func (i Rules) IsValid() bool { + _, ok := _RulesMap[i] + return ok +} + +// MarshalText implements the [encoding.TextMarshaler] interface. +func (i Rules) MarshalText() ([]byte, error) { + return []byte(i.String()), nil +} + +// UnmarshalText implements the [encoding.TextUnmarshaler] interface. +func (i *Rules) UnmarshalText(text []byte) error { + if err := i.SetString(string(text)); err != nil { + log.Println(err) + } + return nil +} diff --git a/kinase/gtigen.go b/kinase/gtigen.go new file mode 100644 index 000000000..a008dcbad --- /dev/null +++ b/kinase/gtigen.go @@ -0,0 +1,65 @@ +// Code generated by "goki generate -add-types"; DO NOT EDIT. + +package kinase + +import ( + "goki.dev/gti" + "goki.dev/ordmap" +) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/kinase.CaDtParams", + ShortName: "kinase.CaDtParams", + IDName: "ca-dt-params", + Doc: "CaDtParams has rate constants for integrating Ca calcium\nat different time scales, including final CaP = CaMKII and CaD = DAPK1\ntimescales for LTP potentiation vs. LTD depression factors.", + Directives: gti.Directives{ + >i.Directive{Tool: "gosl", Directive: "start", Args: []string{"kinase"}}, + >i.Directive{Tool: "gti", Directive: "add", Args: []string{}}, + }, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"MTau", >i.Field{Name: "MTau", Type: "float32", LocalType: "float32", Doc: "CaM (calmodulin) time constant in cycles (msec) -- for synaptic-level integration this integrates on top of Ca signal from send->CaSyn * recv->CaSyn, each of which are typically integrated with a 30 msec Tau.", Directives: gti.Directives{}, Tag: "def:\"2,5\" min:\"1\""}}, + {"PTau", >i.Field{Name: "PTau", Type: "float32", LocalType: "float32", Doc: "LTP spike-driven Ca factor (CaP) time constant in cycles (msec), simulating CaMKII in the Kinase framework, with 40 on top of MTau roughly tracking the biophysical rise time. Computationally, CaP represents the plus phase learning signal that reflects the most recent past information.", Directives: gti.Directives{}, Tag: "def:\"39\" min:\"1\""}}, + {"DTau", >i.Field{Name: "DTau", Type: "float32", LocalType: "float32", Doc: "LTD spike-driven Ca factor (CaD) time constant in cycles (msec), simulating DAPK1 in Kinase framework. Computationally, CaD represents the minus phase learning signal that reflects the expectation representation prior to experiencing the outcome (in addition to the outcome). For integration equations, this cannot be identical to PTau.", Directives: gti.Directives{}, Tag: "def:\"41\" min:\"1\""}}, + {"ExpAdj", >i.Field{Name: "ExpAdj", Type: "goki.dev/gosl/v2/slbool.Bool", LocalType: "slbool.Bool", Doc: "if true, adjust dt time constants when using exponential integration equations to compensate for difference between discrete and continuous integration", Directives: gti.Directives{}, Tag: ""}}, + {"MDt", >i.Field{Name: "MDt", Type: "float32", LocalType: "float32", Doc: "rate = 1 / tau", Directives: gti.Directives{}, Tag: "view:\"-\" json:\"-\" xml:\"-\" inactive:\"+\""}}, + {"PDt", >i.Field{Name: "PDt", Type: "float32", LocalType: "float32", Doc: "rate = 1 / tau", Directives: gti.Directives{}, Tag: "view:\"-\" json:\"-\" xml:\"-\" inactive:\"+\""}}, + {"DDt", >i.Field{Name: "DDt", Type: "float32", LocalType: "float32", Doc: "rate = 1 / tau", Directives: gti.Directives{}, Tag: "view:\"-\" json:\"-\" xml:\"-\" inactive:\"+\""}}, + {"M4Dt", >i.Field{Name: "M4Dt", Type: "float32", LocalType: "float32", Doc: "4 * rate = 1 / tau", Directives: gti.Directives{}, Tag: "view:\"-\" json:\"-\" xml:\"-\" inactive:\"+\""}}, + {"P4Dt", >i.Field{Name: "P4Dt", Type: "float32", LocalType: "float32", Doc: "4 * rate = 1 / tau", Directives: gti.Directives{}, Tag: "view:\"-\" json:\"-\" xml:\"-\" inactive:\"+\""}}, + {"D4Dt", >i.Field{Name: "D4Dt", Type: "float32", LocalType: "float32", Doc: "4 * rate = 1 / tau", Directives: gti.Directives{}, Tag: "view:\"-\" json:\"-\" xml:\"-\" inactive:\"+\""}}, + {"pad", >i.Field{Name: "pad", Type: "int32", LocalType: "int32", Doc: "", Directives: gti.Directives{}, Tag: ""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/kinase.CaParams", + ShortName: "kinase.CaParams", + IDName: "ca-params", + Doc: "CaParams has rate constants for integrating spike-driven Ca calcium\nat different time scales, including final CaP = CaMKII and CaD = DAPK1\ntimescales for LTP potentiation vs. LTD depression factors.", + Directives: gti.Directives{ + >i.Directive{Tool: "gti", Directive: "add", Args: []string{}}, + }, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"SpikeG", >i.Field{Name: "SpikeG", Type: "float32", LocalType: "float32", Doc: "spiking gain factor for SynSpk learning rule variants. This alters the overall range of values, keeping them in roughly the unit scale, and affects effective learning rate.", Directives: gti.Directives{}, Tag: "def:\"12\""}}, + {"MaxISI", >i.Field{Name: "MaxISI", Type: "int32", LocalType: "int32", Doc: "maximum ISI for integrating in Opt mode -- above that just set to 0", Directives: gti.Directives{}, Tag: "def:\"100\""}}, + {"pad", >i.Field{Name: "pad", Type: "int32", LocalType: "int32", Doc: "", Directives: gti.Directives{}, Tag: ""}}, + {"Dt", >i.Field{Name: "Dt", Type: "github.com/emer/axon/kinase.CaDtParams", LocalType: "CaDtParams", Doc: "time constants for integrating at M, P, and D cascading levels", Directives: gti.Directives{}, Tag: "view:\"inline\""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/kinase.Rules", + ShortName: "kinase.Rules", + IDName: "rules", + Doc: "Rules are different options for Kinase-based learning rules\nThese are now implemented using separate Prjn types in kinasex", + Directives: gti.Directives{ + >i.Directive{Tool: "go", Directive: "generate", Args: []string{"goki", "generate", "-add-types"}}, + >i.Directive{Tool: "enums", Directive: "enum", Args: []string{}}, + }, + + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) diff --git a/kinase/params.go b/kinase/params.go index 086f81eea..36e5d012a 100644 --- a/kinase/params.go +++ b/kinase/params.go @@ -5,7 +5,7 @@ package kinase import ( - "github.com/goki/gosl/slbool" + "goki.dev/gosl/v2/slbool" "goki.dev/mat32/v2" ) @@ -14,7 +14,7 @@ import ( // CaDtParams has rate constants for integrating Ca calcium // at different time scales, including final CaP = CaMKII and CaD = DAPK1 // timescales for LTP potentiation vs. LTD depression factors. -type CaDtParams struct { +type CaDtParams struct { //gti:add // CaM (calmodulin) time constant in cycles (msec) -- for synaptic-level integration this integrates on top of Ca signal from send->CaSyn * recv->CaSyn, each of which are typically integrated with a 30 msec Tau. MTau float32 `def:"2,5" min:"1"` @@ -107,7 +107,7 @@ func (kp *CaDtParams) CaAtT(ti int32, caM, caP, caD *float32) { // CaParams has rate constants for integrating spike-driven Ca calcium // at different time scales, including final CaP = CaMKII and CaD = DAPK1 // timescales for LTP potentiation vs. LTD depression factors. -type CaParams struct { +type CaParams struct { //gti:add // spiking gain factor for SynSpk learning rule variants. This alters the overall range of values, keeping them in roughly the unit scale, and affects effective learning rate. SpikeG float32 `def:"12"` diff --git a/kinase/plot/synca_plot.go b/kinase/plot/synca_plot.go index 41b8cf235..6b37439b5 100644 --- a/kinase/plot/synca_plot.go +++ b/kinase/plot/synca_plot.go @@ -11,15 +11,15 @@ import ( "github.com/emer/axon/kinase" "github.com/emer/etable/eplot" - "github.com/emer/etable/etable" - "github.com/emer/etable/etensor" - _ "github.com/emer/etable/etview" // include to get gui views - "github.com/goki/gi/gi" - "github.com/goki/gi/gimain" - "github.com/goki/gi/giv" - _ "github.com/goki/gosl/slboolview" // ditto "github.com/goki/ki/ki" - "github.com/goki/mat32" + "goki.dev/etable/v2/etable" + "goki.dev/etable/v2/etensor" + _ "goki.dev/etable/v2/vv2iew" // include to get gui views + "goki.dev/gi/v2/gi" + "goki.dev/gi/v2/gimain" + "goki.dev/gi/v2/giv" + _ "goki.dev/gosl/v2/slboolview" // ditto + "goki.dev/mat32/v2" ) func main() { @@ -30,7 +30,7 @@ func main() { } func guirun() { - win := TheSim.ConfigGui() + win := TheSim.ConfigGUI() win.StartEventLoop() } @@ -256,8 +256,8 @@ func (ss *Sim) ConfigTimePlot(plt *eplot.Plot2D, dt *etable.Table) *eplot.Plot2D return plt } -// ConfigGui configures the GoGi gui interface for this simulation, -func (ss *Sim) ConfigGui() *gi.Window { +// ConfigGUI configures the GoGi gui interface for this simulation, +func (ss *Sim) ConfigGUI() *gi.Window { width := 1600 height := 1200 diff --git a/kinase/rules.go b/kinase/rules.go index ed73b2438..ce2d414b8 100644 --- a/kinase/rules.go +++ b/kinase/rules.go @@ -4,18 +4,11 @@ package kinase -import "github.com/goki/ki/kit" +//go:generate goki generate -add-types // Rules are different options for Kinase-based learning rules // These are now implemented using separate Prjn types in kinasex -type Rules int32 - -//go:generate stringer -type=Rules - -var KiT_Rules = kit.Enums.AddEnum(RulesN, kit.NotBitFlag, nil) - -func (ev Rules) MarshalJSON() ([]byte, error) { return kit.EnumMarshalJSON(ev) } -func (ev *Rules) UnmarshalJSON(b []byte) error { return kit.EnumUnmarshalJSON(ev, b) } +type Rules int32 //enums:enum // The different versions of Kinase learning rules const ( @@ -54,6 +47,4 @@ const ( // It exhibits strong sensitivity to final spikes and thus // high levels of variance. NeurSpkTheta - - RulesN ) diff --git a/kinase/rules_string.go b/kinase/rules_string.go deleted file mode 100644 index 5af5b4d6b..000000000 --- a/kinase/rules_string.go +++ /dev/null @@ -1,42 +0,0 @@ -// Code generated by "stringer -type=Rules"; DO NOT EDIT. - -package kinase - -import ( - "errors" - "strconv" -) - -var _ = errors.New("dummy error") - -func _() { - // An "invalid array index" compiler error signifies that the constant values have changed. - // Re-run the stringer command to generate them again. - var x [1]struct{} - _ = x[SynSpkCont-0] - _ = x[SynNMDACont-1] - _ = x[SynSpkTheta-2] - _ = x[NeurSpkTheta-3] - _ = x[RulesN-4] -} - -const _Rules_name = "SynSpkContSynNMDAContSynSpkThetaNeurSpkThetaRulesN" - -var _Rules_index = [...]uint8{0, 10, 21, 32, 44, 50} - -func (i Rules) String() string { - if i < 0 || i >= Rules(len(_Rules_index)-1) { - return "Rules(" + strconv.FormatInt(int64(i), 10) + ")" - } - return _Rules_name[_Rules_index[i]:_Rules_index[i+1]] -} - -func (i *Rules) FromString(s string) error { - for j := 0; j < len(_Rules_index)-1; j++ { - if s == _Rules_name[_Rules_index[j]:_Rules_index[j+1]] { - *i = Rules(j) - return nil - } - } - return errors.New("String: " + s + " is not a valid option for type: Rules") -} diff --git a/nxx1/gtigen.go b/nxx1/gtigen.go new file mode 100644 index 000000000..318885a8b --- /dev/null +++ b/nxx1/gtigen.go @@ -0,0 +1,34 @@ +// Code generated by "goki generate -add-types"; DO NOT EDIT. + +package nxx1 + +import ( + "goki.dev/gti" + "goki.dev/ordmap" +) + +var _ = gti.AddType(>i.Type{ + Name: "github.com/emer/axon/nxx1.Params", + ShortName: "nxx1.Params", + IDName: "params", + Doc: "Params are the Noisy X/(X+1) rate-coded activation function parameters.\nThis function well-characterizes the neural response function empirically,\nas a saturating sigmoid-like nonlinear response with an initial largely-linear regime.\nThe basic x/(x+1) sigmoid function is convolved with a gaussian noise kernel to produce\na better approximation of the effects of noise on neural firing -- the main effect is\nto create a continuous graded early level of firing even slightly below threshold, softening\nthe otherwise hard transition to firing at threshold.\nA hand-optimized piece-wise function approximation is used to generate the NXX1 function\ninstead of requiring a lookup table of the gaussian convolution. This is much easier\nto use across a range of computational platforms including GPU's, and produces very similar\noverall values. abc.", + Directives: gti.Directives{}, + Fields: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{ + {"Thr", >i.Field{Name: "Thr", Type: "float32", LocalType: "float32", Doc: "threshold value Theta (Q) for firing output activation (.5 is more accurate value based on AdEx biological parameters and normalization", Directives: gti.Directives{}, Tag: "def:\"0.5\""}}, + {"Gain", >i.Field{Name: "Gain", Type: "float32", LocalType: "float32", Doc: "gain (gamma) of the rate-coded activation functions -- 100 is default, 80 works better for larger models, and 20 is closer to the actual spiking behavior of the AdEx model -- use lower values for more graded signals, generally in lower input/sensory layers of the network", Directives: gti.Directives{}, Tag: "def:\"80,100,40,20\" min:\"0\""}}, + {"NVar", >i.Field{Name: "NVar", Type: "float32", LocalType: "float32", Doc: "variance of the Gaussian noise kernel for convolving with XX1 in NOISY_XX1 and NOISY_LINEAR -- determines the level of curvature of the activation function near the threshold -- increase for more graded responding there -- note that this is not actual stochastic noise, just constant convolved gaussian smoothness to the activation function", Directives: gti.Directives{}, Tag: "def:\"0.005,0.01\" min:\"0\""}}, + {"VmActThr", >i.Field{Name: "VmActThr", Type: "float32", LocalType: "float32", Doc: "threshold on activation below which the direct vm - act.thr is used -- this should be low -- once it gets active should use net - g_e_thr ge-linear dynamics (gelin)", Directives: gti.Directives{}, Tag: "def:\"0.01\""}}, + {"SigMult", >i.Field{Name: "SigMult", Type: "float32", LocalType: "float32", Doc: "multiplier on sigmoid used for computing values for net < thr", Directives: gti.Directives{}, Tag: "def:\"0.33\" view:\"-\" json:\"-\" xml:\"-\""}}, + {"SigMultPow", >i.Field{Name: "SigMultPow", Type: "float32", LocalType: "float32", Doc: "power for computing sig_mult_eff as function of gain * nvar", Directives: gti.Directives{}, Tag: "def:\"0.8\" view:\"-\" json:\"-\" xml:\"-\""}}, + {"SigGain", >i.Field{Name: "SigGain", Type: "float32", LocalType: "float32", Doc: "gain multipler on (net - thr) for sigmoid used for computing values for net < thr", Directives: gti.Directives{}, Tag: "def:\"3\" view:\"-\" json:\"-\" xml:\"-\""}}, + {"InterpRange", >i.Field{Name: "InterpRange", Type: "float32", LocalType: "float32", Doc: "interpolation range above zero to use interpolation", Directives: gti.Directives{}, Tag: "def:\"0.01\" view:\"-\" json:\"-\" xml:\"-\""}}, + {"GainCorRange", >i.Field{Name: "GainCorRange", Type: "float32", LocalType: "float32", Doc: "range in units of nvar over which to apply gain correction to compensate for convolution", Directives: gti.Directives{}, Tag: "def:\"10\" view:\"-\" json:\"-\" xml:\"-\""}}, + {"GainCor", >i.Field{Name: "GainCor", Type: "float32", LocalType: "float32", Doc: "gain correction multiplier -- how much to correct gains", Directives: gti.Directives{}, Tag: "def:\"0.1\" view:\"-\" json:\"-\" xml:\"-\""}}, + {"SigGainNVar", >i.Field{Name: "SigGainNVar", Type: "float32", LocalType: "float32", Doc: "sig_gain / nvar", Directives: gti.Directives{}, Tag: "view:\"-\" json:\"-\" xml:\"-\""}}, + {"SigMultEff", >i.Field{Name: "SigMultEff", Type: "float32", LocalType: "float32", Doc: "overall multiplier on sigmoidal component for values below threshold = sig_mult * pow(gain * nvar, sig_mult_pow)", Directives: gti.Directives{}, Tag: "view:\"-\" json:\"-\" xml:\"-\""}}, + {"SigValAt0", >i.Field{Name: "SigValAt0", Type: "float32", LocalType: "float32", Doc: "0.5 * sig_mult_eff -- used for interpolation portion", Directives: gti.Directives{}, Tag: "view:\"-\" json:\"-\" xml:\"-\""}}, + {"InterpVal", >i.Field{Name: "InterpVal", Type: "float32", LocalType: "float32", Doc: "function value at interp_range - sig_val_at_0 -- for interpolation", Directives: gti.Directives{}, Tag: "view:\"-\" json:\"-\" xml:\"-\""}}, + }), + Embeds: ordmap.Make([]ordmap.KeyVal[string, *gti.Field]{}), + Methods: ordmap.Make([]ordmap.KeyVal[string, *gti.Method]{}), +}) diff --git a/nxx1/nxx1.go b/nxx1/nxx1.go index e81844c9a..2e9d6e0ab 100644 --- a/nxx1/nxx1.go +++ b/nxx1/nxx1.go @@ -19,6 +19,8 @@ overall values. */ package nxx1 +//go:generate goki generate -add-types + import ( "goki.dev/mat32/v2" ) diff --git a/python/LICENSE b/python/LICENSE deleted file mode 100644 index abdfa70c2..000000000 --- a/python/LICENSE +++ /dev/null @@ -1,29 +0,0 @@ -BSD 3-Clause License - -Copyright (c) 2018, The emergent Authors -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -* Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/python/MANIFEST.in b/python/MANIFEST.in deleted file mode 100644 index a5ebd87eb..000000000 --- a/python/MANIFEST.in +++ /dev/null @@ -1,2 +0,0 @@ -global-include *.so *.py -global-exclude build.py diff --git a/python/Makefile b/python/Makefile deleted file mode 100644 index 220a44d44..000000000 --- a/python/Makefile +++ /dev/null @@ -1,50 +0,0 @@ -# Makefile for gopy pkg generation of python bindings to emergent -# File is generated by gopy (will not be overwritten though) -# gopy exe -name=leabra -vm=python3 -no-warn -exclude=driver,oswin -main="runtime.LockOSThread(); gimain.Main(func() { GoPyMainRun() })" math/rand github.com/goki/ki/ki github.com/goki/mat32 github.com/goki/gi/units github.com/goki/gi/gi github.com/goki/gi/svg github.com/goki/gi/giv github.com/goki/gi/gi3d github.com/goki/gi/gimain github.com/emer/etable github.com/emer/emergent github.com/emer/leabra/chans github.com/emer/leabra/fffb github.com/emer/leabra/knadapt github.com/emer/leabra/nxx1 github.com/emer/leabra/leabra github.com/emer/leabra/spike github.com/emer/leabra/deep github.com/emer/leabra/hip github.com/emer/leabra/rl github.com/emer/leabra/pbwm github.com/emer/leabra/glong github.com/emer/leabra/pcore github.com/emer/leabra/agate github.com/emer/vision - -PYTHON=python3 -PIP=$(PYTHON) -m pip - -PBGV=`$(PIP) list | grep PyBindGen` - -all: prereq gen - -.PHONY: prereq gen all build install install-pkg install-exe clean - -prereq: - @echo "Installing go prerequisites:" - - go get golang.org/x/tools/cmd/goimports # this installs into ~/go/bin - - go get github.com/go-python/gopy - @echo "Installing python prerequisites -- ignore err if already installed:" - - $(PIP) install -r requirements.txt - @echo - @echo "if this fails, you may see errors like this:" - @echo " Undefined symbols for architecture x86_64:" - @echo " _PyInit__gi, referenced from:..." - @echo - -install: install-pkg install-exe - -# note: it is important that leabra come before deep otherwise deep captures all the common types -# unfortunately this means that all sub-packages need to be explicitly listed. -gen: - gopy exe -name=leabra -vm=python3 -no-warn -exclude=driver,oswin,draw,example,examples,gif,jpeg,png,draw -main="runtime.LockOSThread(); gimain.Main(func() { GoPyMainRun() })" math/rand image github.com/anthonynsimon/bild/transform github.com/goki/ki/ki github.com/goki/ki/kit github.com/goki/mat32 github.com/goki/gi/units github.com/goki/gi/gist github.com/goki/gi/girl github.com/goki/gi/gi github.com/goki/gi/svg github.com/goki/gi/giv github.com/goki/gi/gi3d github.com/goki/gi/gimain github.com/emer/etable github.com/emer/emergent github.com/emer/leabra/chans github.com/emer/leabra/fffb github.com/emer/leabra/knadapt github.com/emer/leabra/nxx1 github.com/emer/leabra/leabra github.com/emer/leabra/spike github.com/emer/leabra/deep github.com/emer/leabra/hip github.com/emer/leabra/rl github.com/emer/leabra/pbwm github.com/emer/leabra/glong github.com/emer/leabra/pcore github.com/emer/leabra/agate github.com/emer/vision github.com/emer/etorch - -build: - $(MAKE) -C leabra build - -install-pkg: - # this does a local install of the package, building the sdist and then directly installing it - # copy pyside/*.py etc to leabra so these libs will be installed along with rest - cp pyside/*.py leabra/ - rm -rf dist build */*.egg-info *.egg-info - $(PYTHON) setup.py sdist - $(PIP) install dist/*.tar.gz - -install-exe: - # install executable into /usr/local/bin - cp leabra/pyleabra /usr/local/bin/ - -clean: - rm -rf leabra dist build */*.egg-info *.egg-info - diff --git a/python/README.md b/python/README.md deleted file mode 100644 index 30f0f3583..000000000 --- a/python/README.md +++ /dev/null @@ -1,43 +0,0 @@ -# Python interface to emergent / Leabra - -**These Python interfaces are currently unused** - -You can run the Go version of *emergent* via Python, using the [gopy](https://github.com/go-python/gopy) tool that automatically creates Python bindings for Go packages. - -See the [GoGi Python README](https://github.com/goki/gi/blob/master/python/README.md) for more details on how the python wrapper works and how to use it for GUI-level functionality. **If you encounter any difficulties with this install, then try doing the install in GoGi first**, and read more about the different install issues there. - -See the `.py` versions of various projects in `examples`, and especially in the [Comp Cog Neuro sims](https://github.com/CompCogNeuro/sims), for many examples of Python versions. - -See [etable pyet](https://github.com/emer/etable/tree/master/examples/pyet) for example code for converting between the Go `etable.Table` and `numpy`, `torch`, and `pandas` table structures. All of the converted projects rely on `etable` because it provides a complete GUI interface for viewing and manipulating the data, but it is easy to convert any of these tables into Python-native formats (and copy back-and-forth). The `pyet` python library (in `pyside` and auto-installed with this package) has the necessary routines. - -# Installation - -First, you have to install the Go version of emergent: [Wiki Install](https://github.com/emer/emergent/wiki/Install). - -Python version 3 (3.6, 3.8 have been well tested) is recommended. - -This assumes that you are using go modules, as discussed in the wiki install page, and *that you are in the `leabra` directory where you installed leabra* (e.g., `git clone https://github.com/emer/leabra` and then `cd leabra`) - -```sh -$ cd python # should be in leabra/python now -- i.e., the dir where this README.md is.. -$ make -$ make install # may need to do: sudo make install -- installs into /usr/local/bin and python site-packages -$ cd ../examples/ra25 -$ ./ra25.py # runs using magic code on first line of file -- alternatively: -$ pyleabra -i ra25.py # pyleabra was installed during make install into /usr/local/bin -``` - -The `pyleabra` executable combines standard python and the full Go emergent and GoGi gui packages -- see the information in the GoGi python readme for more technical information about this. - -# Sharing install - -To make a compiled version available to others, you just need the `dist/leabra-1.1.15.tar.gz` file and the `pyleabra` executable: - -```sh -$ ./pyleabra -m pip install leabra-1.1.15.tar.gz -$ ./pyleabra -m pip install numpy # numpy is needed -$ cp pyleabra /usr/local/bin/ -``` - -These steps might require `sudo` permissions. - diff --git a/python/go.mod b/python/go.mod deleted file mode 100644 index 70d9312d9..000000000 --- a/python/go.mod +++ /dev/null @@ -1,30 +0,0 @@ -module github.com/emer/leabra/python - -go 1.15 - -require ( - github.com/alecthomas/chroma v0.8.2 - github.com/anthonynsimon/bild v0.13.0 - github.com/apache/arrow/go/arrow v0.0.0-20201121231650-0e8be3caa4a6 - github.com/aymerick/douceur v0.2.0 - github.com/emer/emergent v1.1.27 - github.com/emer/etable v1.0.27 - github.com/emer/etorch v1.0.6 - github.com/emer/axon v1.2.17 - github.com/emer/vision v1.1.6 - github.com/go-gl/mathgl v1.0.0 - github.com/go-python/gopy v0.3.4 - github.com/goki/gi v1.2.7 - github.com/goki/ki v1.1.3 - github.com/goki/mat32 v1.0.9 - github.com/goki/pi v1.0.14 - github.com/goki/vci v1.0.0 - github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 - github.com/ianbruene/go-difflib v1.2.0 - github.com/pkg/errors v0.9.1 // indirect - github.com/srwiley/rasterx v0.0.0-20200120212402-85cb7272f5e9 - github.com/srwiley/scanx v0.0.0-20190309010443-e94503791388 - golang.org/x/image v0.0.0-20200927104501-e162460cd6b5 - gonum.org/v1/gonum v0.9.1 - gonum.org/v1/plot v0.9.0 -) diff --git a/python/go.sum b/python/go.sum deleted file mode 100644 index 88a88719e..000000000 --- a/python/go.sum +++ /dev/null @@ -1,367 +0,0 @@ -cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -gioui.org v0.0.0-20200628203458-851255f7a67b/go.mod h1:jiUwifN9cRl/zmco43aAqh0aV+s9GbhG13KcD+gEpkU= -github.com/BurntSushi/freetype-go v0.0.0-20160129220410-b763ddbfe298 h1:1qlsVAQJXZHsaM8b6OLVo6muQUQd4CwkH/D3fnnbHXA= -github.com/BurntSushi/freetype-go v0.0.0-20160129220410-b763ddbfe298/go.mod h1:D+QujdIlUNfa0igpNMk6UIvlb6C252URs4yupRUV4lQ= -github.com/BurntSushi/graphics-go v0.0.0-20160129215708-b43f31a4a966 h1:lTG4HQym5oPKjL7nGs+csTgiDna685ZXjxijkne828g= -github.com/BurntSushi/graphics-go v0.0.0-20160129215708-b43f31a4a966/go.mod h1:Mid70uvE93zn9wgF92A/r5ixgnvX8Lh68fxp9KQBaI0= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/BurntSushi/xgb v0.0.0-20200324125942-20f126ea2843 h1:3iF31c7rp7nGZVDv7YQ+VxOgpipVfPKotLXykjZmwM8= -github.com/BurntSushi/xgb v0.0.0-20200324125942-20f126ea2843/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/BurntSushi/xgb v0.0.0-20201008132610-5f9e7b3c49cd h1:u7K2oMFMd8APDV3fM1j2rO3U/XJf1g1qC3DDTKou8iM= -github.com/BurntSushi/xgb v0.0.0-20201008132610-5f9e7b3c49cd/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/BurntSushi/xgbutil v0.0.0-20190907113008-ad855c713046 h1:O/r2Sj+8QcMF7V5IcmiE2sMFV2q3J47BEirxbXJAdzA= -github.com/BurntSushi/xgbutil v0.0.0-20190907113008-ad855c713046/go.mod h1:uw9h2sd4WWHOPdJ13MQpwK5qYWKYDumDqxWWIknEQ+k= -github.com/Knetic/govaluate v3.0.0+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= -github.com/Masterminds/vcs v1.13.1 h1:NL3G1X7/7xduQtA2sJLpVpfHTNBALVNSjob6KEjPXNQ= -github.com/Masterminds/vcs v1.13.1/go.mod h1:N09YCmOQr6RLxC6UNHzuVwAdodYbbnycGHSmwVJjcKA= -github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af h1:wVe6/Ea46ZMeNkQjjBW6xcqyQA/j5e0D6GytH95g0gQ= -github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= -github.com/ajstarks/svgo v0.0.0-20200725142600-7a3c8b57fecb h1:EVl3FJLQCzSbgBezKo/1A4ADnJ4mtJZ0RvnNzDJ44nY= -github.com/ajstarks/svgo v0.0.0-20200725142600-7a3c8b57fecb/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= -github.com/akutz/sortfold v0.2.1 h1:u9x3FC6oM+6gZKEVNRnmVafJgappwrv9YqpELQCYViI= -github.com/akutz/sortfold v0.2.1/go.mod h1:m1NArmessx+/3z2N8MiiTjq79A3WwZwDDiZ7eeD4jHA= -github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38/go.mod h1:r7bzyVFMNntcxPZXK3/+KdruV1H5KSlyVY0gc+NgInI= -github.com/alecthomas/chroma v0.7.3/go.mod h1:sko8vR34/90zvl5QdcUdvzL3J8NKjAUx9va9jPuFNoM= -github.com/alecthomas/chroma v0.8.0 h1:HS+HE97sgcqjQGu5uVr8jIE55Mmh5UeQ7kckAhHg2pY= -github.com/alecthomas/chroma v0.8.0/go.mod h1:sko8vR34/90zvl5QdcUdvzL3J8NKjAUx9va9jPuFNoM= -github.com/alecthomas/chroma v0.8.2 h1:x3zkuE2lUk/RIekyAJ3XRqSCP4zwWDfcw/YJCuCAACg= -github.com/alecthomas/chroma v0.8.2/go.mod h1:sko8vR34/90zvl5QdcUdvzL3J8NKjAUx9va9jPuFNoM= -github.com/alecthomas/colour v0.0.0-20160524082231-60882d9e2721/go.mod h1:QO9JBoKquHd+jz9nshCh40fOfO+JzsoXy8qTHF68zU0= -github.com/alecthomas/kong v0.2.4/go.mod h1:kQOmtJgV+Lb4aj+I2LEn40cbtawdWJ9Y8QLq+lElKxE= -github.com/alecthomas/repr v0.0.0-20180818092828-117648cd9897/go.mod h1:xTS7Pm1pD1mvyM075QCDSRqH6qRLXylzS24ZTpRiSzQ= -github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= -github.com/anthonynsimon/bild v0.12.0/go.mod h1:tpzzp0aYkAsMi1zmfhimaDyX1xjn2OUc1AJZK/TF0AE= -github.com/anthonynsimon/bild v0.13.0 h1:mN3tMaNds1wBWi1BrJq0ipDBhpkooYfu7ZFSMhXt1C8= -github.com/anthonynsimon/bild v0.13.0/go.mod h1:tpzzp0aYkAsMi1zmfhimaDyX1xjn2OUc1AJZK/TF0AE= -github.com/apache/arrow/go/arrow v0.0.0-20200628183233-0b9720463eec h1:n+QIIV5z1XRDz9+Ul5Za0uof/0n6Xr80PH+5wz2IoEY= -github.com/apache/arrow/go/arrow v0.0.0-20200628183233-0b9720463eec/go.mod h1:QNYViu/X0HXDHw7m3KXzWSVXIbfUvJqBFe6Gj8/pYA0= -github.com/apache/arrow/go/arrow v0.0.0-20201121231650-0e8be3caa4a6 h1:I6DhrNsGbs+MV5BlunXOJ3Q+aSMaM2t0yiYWzfY+ySU= -github.com/apache/arrow/go/arrow v0.0.0-20201121231650-0e8be3caa4a6/go.mod h1:c9sxoIT3YgLxH4UhLOCKaBlEojuMhVYpk4Ntv3opUTQ= -github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= -github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= -github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= -github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= -github.com/c2h5oh/datasize v0.0.0-20200112174442-28bbd4740fee/go.mod h1:S/7n9copUssQ56c7aAgHqftWO4LTf4xY6CGWt8Bc+3M= -github.com/c2h5oh/datasize v0.0.0-20200825124411-48ed595a09d2 h1:t8KYCwSKsOEZBFELI4Pn/phbp38iJ1RRAkDFNin1aak= -github.com/c2h5oh/datasize v0.0.0-20200825124411-48ed595a09d2/go.mod h1:S/7n9copUssQ56c7aAgHqftWO4LTf4xY6CGWt8Bc+3M= -github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/chewxy/math32 v1.0.6 h1:JWZYUNl2rtgVVui6z8JBsDgkOG2DYmfSODyo95yKfx4= -github.com/chewxy/math32 v1.0.6/go.mod h1:dOB2rcuFrCn6UHrze36WSLVPKtzPMRAQvBvUwkSsLqs= -github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= -github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= -github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964 h1:y5HC9v93H5EPKqaS1UYVg1uYah5Xf51mBfIoWehClUQ= -github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964/go.mod h1:Xd9hchkHSWYkEqJwUGisez3G1QY8Ryz0sdWrLPMGjLk= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= -github.com/dlclark/regexp2 v1.2.1 h1:Ff/S0snjr1oZHUNOkvA/gP6KUaMg5vDDl3Qnhjnwgm8= -github.com/dlclark/regexp2 v1.2.1/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= -github.com/dlclark/regexp2 v1.4.0 h1:F1rxgk7p4uKjwIQxBs9oAXe5CqrXlCduYEJvrF4u93E= -github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= -github.com/emer/emergent v1.1.10/go.mod h1:YscDt9Cl7zEl9gNbjHJ5jzoFUyLNHilSfCO9wHJWly4= -github.com/emer/emergent v1.1.11 h1:iJxKpJdF2D1GN7veCmU6TMrmvfCXcJgbfh10wybhi3k= -github.com/emer/emergent v1.1.11/go.mod h1:9Y+EJNcAjPMdiKn/HxsF3QF3Oc0fvvNMFWEpG8M9yrQ= -github.com/emer/emergent v1.1.12/go.mod h1:XkJOn5TpDnC8uY7hVvmyoRRo76VwV6fXXdZGeg5Tgpk= -github.com/emer/emergent v1.1.13 h1:/A+K39oyrhtDklMfNdld5do2fyBKdMPffaBVy752x1g= -github.com/emer/emergent v1.1.13/go.mod h1:VUAhHTyRN7nhaOVAKnYQ8YHr1J7Ha+MhMCQOG+Ttdec= -github.com/emer/empi v1.0.8/go.mod h1:/hKEKGnnOVHn4ePadz6Ik/gnucbDq+KyLrVmTtLu+KI= -github.com/emer/empi v1.0.9/go.mod h1:T+NJAeHlVy9ETmQjaL+9pUV/k1TwOc6rKQ0tPWJrvWs= -github.com/emer/etable v1.0.14/go.mod h1:BKPO7uhj3wbgY3TlBFCqmFGLsozJYydE27dSa3hVi48= -github.com/emer/etable v1.0.16 h1:xv1vNYaOMZQijmhWH0vNXN1uVp0ZZAKXEA+JLHVDpuA= -github.com/emer/etable v1.0.16/go.mod h1:eP3PjPnmQjX4iXF/gRSMgFV8loepGgDbdweRa6t/wo0= -github.com/emer/etable v1.0.17/go.mod h1:eP3PjPnmQjX4iXF/gRSMgFV8loepGgDbdweRa6t/wo0= -github.com/emer/etable v1.0.18 h1:o2DFfVt+ujb8ks5v0LfL5zPfLardf+XrMShnudlBA30= -github.com/emer/etable v1.0.18/go.mod h1:/qOVnq0jL+JWu3HBepfX92ktUMlWiog7a3Uxsmk5Y7Q= -github.com/emer/etorch v1.0.0 h1:9fpoaitYObEGr0Ogp4BBOt1P7e/HlsyUv88azaIw1Tw= -github.com/emer/etorch v1.0.0/go.mod h1:ZG/F0YXe4/gUBcbTWQ9G3nXX99jklsqDJE2GBXKDZSU= -github.com/emer/leabra v1.1.10/go.mod h1:yghPPPY6ExxgBQTe2WTLjwdy3ylKWEMb7xxD1uwVpro= -github.com/emer/leabra v1.1.11 h1:oUrVvyjwTQzEAGcU21lRLVAd5QxrNsFuSn4eBR5kdGc= -github.com/emer/leabra v1.1.11/go.mod h1:hZZ+mueFUs2mYZW10BIzPjyTS73h9qi2zMwTE6HK4xw= -github.com/emer/leabra v1.1.14 h1:kiztdfbQ6KYDuro9xh96aP08VYiie8Y4vQFh26L1DdM= -github.com/emer/leabra v1.1.14/go.mod h1:tlgKKOszSXjuzxOdEQTpxOdkEMmF5coSkVmZF8rKR7g= -github.com/emer/leabra v1.1.15 h1:r7rcgLkT73C5hzZVNdvjpNcHyf9ELfMUrUblzGsAmGQ= -github.com/emer/leabra v1.1.15/go.mod h1:ekWEnoNYCQ88t45GPPQGrT38rfbKgtQvEVTLNvewDTk= -github.com/emer/vision v1.1.4 h1:5fQw3JS6CM6z/DUQ5xG6F7Bkof/5JkC5pBeb1oFEQiU= -github.com/emer/vision v1.1.4/go.mod h1:5Mw0cVXMMnM/7MR0doyQb+ESAKBUEWgxjsyPmyOWl/c= -github.com/emer/vision v1.1.6 h1:R+a5ugzB0o556gxw1S20oKbJOxtyJtx+B6vsN9U87TQ= -github.com/emer/vision v1.1.6/go.mod h1:AuFuhLKVG5YAVA588eM0K68tNzpP5pnDlxcYiVUUXtI= -github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= -github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/fatih/camelcase v1.0.0 h1:hxNvNX/xYBp0ovncs8WyWZrOrpBNub/JfaMvbURyft8= -github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc= -github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= -github.com/fogleman/gg v1.3.0 h1:/7zJX8F6AaYQc57WQCyN9cAIz+4bCJGO9B+dyW29am8= -github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/gabriel-vasile/mimetype v1.1.1 h1:qbN9MPuRf3bstHu9zkI9jDWNfH//9+9kHxr9oRBBBOA= -github.com/gabriel-vasile/mimetype v1.1.1/go.mod h1:6CDPel/o/3/s4+bp6kIbsWATq8pmgOisOPG40CJa6To= -github.com/gabriel-vasile/mimetype v1.1.2 h1:gaPnPcNor5aZSVCJVSGipcpbgMWiAAj9z182ocSGbHU= -github.com/gabriel-vasile/mimetype v1.1.2/go.mod h1:6CDPel/o/3/s4+bp6kIbsWATq8pmgOisOPG40CJa6To= -github.com/go-fonts/dejavu v0.1.0/go.mod h1:4Wt4I4OU2Nq9asgDCteaAaWZOV24E+0/Pwo0gppep4g= -github.com/go-gl/gl v0.0.0-20190320180904-bf2b1f2f34d7 h1:SCYMcCJ89LjRGwEa0tRluNRiMjZHalQZrVrvTbPh+qw= -github.com/go-gl/gl v0.0.0-20190320180904-bf2b1f2f34d7/go.mod h1:482civXOzJJCPzJ4ZOX/pwvXBWSnzD4OKMdH4ClKGbk= -github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1 h1:QbL/5oDUmRBzO9/Z7Seo6zf912W/a6Sr4Eu0G/3Jho0= -github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200420212212-258d9bec320e/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200707082815-5321531c36a2 h1:Ac1OEHHkbAZ6EUnJahF0GKcU0FjPc/V8F1DvjhKngFE= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200707082815-5321531c36a2/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20201108214237-06ea97f0c265 h1:BcbKYUZo/TKPsiSh7LymK3p+TNAJJW3OfGO/21sBbiA= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20201108214237-06ea97f0c265/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-gl/mathgl v0.0.0-20190713194549-592312d8590a h1:yoAEv7yeWqfL/l9A/J5QOndXIJCldv+uuQB1DSNQbS0= -github.com/go-gl/mathgl v0.0.0-20190713194549-592312d8590a/go.mod h1:yhpkQzEiH9yPyxDUGzkmgScbaBVlhC06qodikEM0ZwQ= -github.com/go-gl/mathgl v1.0.0 h1:t9DznWJlXxxjeeKLIdovCOVJQk/GzDEL7h/h+Ro2B68= -github.com/go-gl/mathgl v1.0.0/go.mod h1:yhpkQzEiH9yPyxDUGzkmgScbaBVlhC06qodikEM0ZwQ= -github.com/go-latex/latex v0.0.0-20200518072620-0806b477ea35 h1:uroDDLmuCK5Pz5J/Ef5vCL6F0sJmAtZFTm0/cF027F4= -github.com/go-latex/latex v0.0.0-20200518072620-0806b477ea35/go.mod h1:PNI+CcWytn/2Z/9f1SGOOYn0eILruVyp0v2/iAs8asQ= -github.com/go-python/gopy v0.3.1/go.mod h1:gQ2Itc84itA1AjrVqnMnv7HLkfmNObRXlR1co7CXpbk= -github.com/go-python/gopy v0.3.2-0.20200916100237-6d8fa23dbe8a h1:8nA6hyfrKNHl0EjaoYEl5Yqw8COcHjwAgY/wdkAavqg= -github.com/go-python/gopy v0.3.2-0.20200916100237-6d8fa23dbe8a/go.mod h1:IcdfJ6FULCVq1E11uXTaa4XWORT77SLHZrO4DVTqB78= -github.com/go-python/gopy v0.3.2 h1:nB5nK4JThMkmsev0JADnD7bsK3SFMJWK+8z0kw9a1kg= -github.com/go-python/gopy v0.3.2/go.mod h1:IcdfJ6FULCVq1E11uXTaa4XWORT77SLHZrO4DVTqB78= -github.com/goki/freetype v0.0.0-20181231101311-fa8a33aabaff h1:W71vTCKoxtdXgnm1ECDFkfQnpdqAO00zzGXLA5yaEX8= -github.com/goki/freetype v0.0.0-20181231101311-fa8a33aabaff/go.mod h1:wfqRWLHRBsRgkp5dmbG56SA0DmVtwrF5N3oPdI8t+Aw= -github.com/goki/gi v1.0.14/go.mod h1:Ig7a4paXz+H2k1L9Yd4ZRnVw/BIh2XAhdTiQhKGkK7c= -github.com/goki/gi v1.0.16 h1:O1t6huv/GPHmkZC+peftO+2XG/aijKaljcSb42PCP2s= -github.com/goki/gi v1.0.16/go.mod h1:E1XS7yoU8sD2XtpnI1RznuKzB8lwYYMqo3J/5lt/9vM= -github.com/goki/gi v1.0.17/go.mod h1:E1XS7yoU8sD2XtpnI1RznuKzB8lwYYMqo3J/5lt/9vM= -github.com/goki/gi v1.1.0 h1:boO48CeCdiMtitplfDniCOJB5zj1hJlmJLVgq2ERNc0= -github.com/goki/gi v1.1.0/go.mod h1:ssRCcYuLBqqm2M4kY/Xj5WwZ2D/eaXmdUoXALIIbfDs= -github.com/goki/ki v1.0.0/go.mod h1:X+gmVeAym3JDSbbiA7iF1qkgAlTVWl1JV9sRsGDzxOA= -github.com/goki/ki v1.0.2/go.mod h1:X+gmVeAym3JDSbbiA7iF1qkgAlTVWl1JV9sRsGDzxOA= -github.com/goki/ki v1.0.4 h1:F6W6vEMfI583A4pvyqOlvPXVjzRNzj3EWaGD1vyBbgc= -github.com/goki/ki v1.0.4/go.mod h1:X+gmVeAym3JDSbbiA7iF1qkgAlTVWl1JV9sRsGDzxOA= -github.com/goki/ki v1.0.5 h1:XsCtIyiu/PysmAuRbfY+l+q4Zk1/W7jS3d6GqxO+f9U= -github.com/goki/ki v1.0.5/go.mod h1:X+gmVeAym3JDSbbiA7iF1qkgAlTVWl1JV9sRsGDzxOA= -github.com/goki/mat32 v1.0.2 h1:pWwejsySL7TXcuE+axGVhF6I4U9YBK6RCDyYwgPmucA= -github.com/goki/mat32 v1.0.2/go.mod h1:SCqUsgLhG48i7wu/Kce9OF62abYJnxCX7YL5TOxZ0K4= -github.com/goki/pi v1.0.7 h1:7v3FklAhsu2oVBxVOYQ9od3ynVAfjevKHgekEGNmVLc= -github.com/goki/pi v1.0.7/go.mod h1:V3Jaw+FKB0D5u2UJJA+6EWpd4bBevWN6DaxTFpOy+z8= -github.com/goki/prof v0.0.0-20180502205428-54bc71b5d09b h1:3zU6niF8uvEaNtRBhOkmgbE/Fx7D6xuALotArTpycNc= -github.com/goki/prof v0.0.0-20180502205428-54bc71b5d09b/go.mod h1:pgRizZOb3eUJr+ByZnXnPvt+a0fVOTn0Ujc2TqVZpW4= -github.com/goki/vci v1.0.0 h1:ib0x+rdYF84vX6uNOIQ1dRKFx7fgK7hDcv+cp0CkRhg= -github.com/goki/vci v1.0.0/go.mod h1:uOQl8kDy2Nb7MEY8cyz72ntp2PaTwJkm2GZNKrEKHE0= -github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g= -github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= -github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/gonuts/commander v0.1.0 h1:EcDTiVw9oAVORFjQOEOuHQqcl6OXMyTgELocTq6zJ0I= -github.com/gonuts/commander v0.1.0/go.mod h1:qkb5mSlcWodYgo7vs8ulLnXhfinhZsZcm6+H/z1JjgY= -github.com/gonuts/flag v0.1.0 h1:fqMv/MZ+oNGu0i9gp0/IQ/ZaPIDoAZBOBaJoV7viCWM= -github.com/gonuts/flag v0.1.0/go.mod h1:ZTmTGtrSPejTo/SRNhCqwLTmiAgyBdCkLYhHrAoBdz4= -github.com/google/flatbuffers v1.11.0/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= -github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY= -github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c= -github.com/h2non/filetype v1.1.0 h1:Or/gjocJrJRNK/Cri/TDEKFjAR+cfG6eK65NGYB6gBA= -github.com/h2non/filetype v1.1.0/go.mod h1:319b3zT68BvV+WRj7cwy856M2ehB3HqNOt6sy1HndBY= -github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/ianbruene/go-difflib v1.2.0 h1:iARmgaCq6nW5QptdoFm0PYAyNGix3xw/xRgEwphJSZw= -github.com/ianbruene/go-difflib v1.2.0/go.mod h1:uJbrQ06VPxjRiRIrync+E6VcWFGW2dWqw2gvQp6HQPY= -github.com/iancoleman/strcase v0.0.0-20191112232945-16388991a334/go.mod h1:SK73tn/9oHe+/Y0h39VT4UCxmurVJkR5NA7kMEAOgSE= -github.com/iancoleman/strcase v0.1.1 h1:2I+LRClyCYB7JgZb9U0k75VHUiQe9RfknRqDyUfzp7k= -github.com/iancoleman/strcase v0.1.1/go.mod h1:SK73tn/9oHe+/Y0h39VT4UCxmurVJkR5NA7kMEAOgSE= -github.com/iancoleman/strcase v0.1.2 h1:gnomlvw9tnV3ITTAxzKSgTF+8kFWcU/f+TgttpXGz1U= -github.com/iancoleman/strcase v0.1.2/go.mod h1:SK73tn/9oHe+/Y0h39VT4UCxmurVJkR5NA7kMEAOgSE= -github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a h1:zPPuIq2jAWWPTrGt70eK/BSch+gFAGrNzecsoENgu2o= -github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a/go.mod h1:yL958EeXv8Ylng6IfnvG4oflryUi3vgA3xPs9hmII1s= -github.com/jinzhu/copier v0.0.0-20201025035756-632e723a6687 h1:bWXum+xWafUxxJpcXnystwg5m3iVpPYtrGJFc1rjfLc= -github.com/jinzhu/copier v0.0.0-20201025035756-632e723a6687/go.mod h1:24xnZezI2Yqac9J61UC6/dG/k76ttpq0DdJI3QmUvro= -github.com/jung-kurt/gofpdf v1.0.0/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= -github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5 h1:PJr+ZMXIecYc1Ey2zucXdR73SMBtgjPgwa31099IMv0= -github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= -github.com/jung-kurt/gofpdf v1.16.2 h1:jgbatWHfRlPYiK85qgevsZTHviWXKwB1TTiKdz5PtRc= -github.com/jung-kurt/gofpdf v1.16.2/go.mod h1:1hl7y57EsiPAkLbOwzpzqgx1A30nQCk/YmFV8S2vmK0= -github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= -github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/phpdave11/gofpdi v1.0.7/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= -github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= -github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w= -github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= -github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= -github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= -github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= -github.com/srwiley/oksvg v0.0.0-20200311192757-870daf9aa564/go.mod h1:afMbS0qvv1m5tfENCwnOdZGOF8RGR/FsZ7bvBxQGZG4= -github.com/srwiley/rasterx v0.0.0-20200120212402-85cb7272f5e9 h1:m59mIOBO4kfcNCEzJNy71UkeF4XIx2EVmL9KLwDQdmM= -github.com/srwiley/rasterx v0.0.0-20200120212402-85cb7272f5e9/go.mod h1:mvWM0+15UqyrFKqdRjY6LuAVJR0HOVhJlEgZ5JWtSWU= -github.com/srwiley/scanFT v0.0.0-20190309001647-3267585b8d6d/go.mod h1:Z7vQGQxdJpx5MQ8GkOGiTJL4zq8eSyI86tTUiy9cov0= -github.com/srwiley/scanx v0.0.0-20190309010443-e94503791388 h1:ZdkidVdpLW13BQ9a+/3uerT2ezy9J7KQWH18JCfhDmI= -github.com/srwiley/scanx v0.0.0-20190309010443-e94503791388/go.mod h1:C/WY5lmWfMtPFYYBTd3Lzdn4FTLr+RxlIeiBNye+/os= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.2.0/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= -github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= -github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20191002040644-a1355ae1e2c3/go.mod h1:NOZ3BPKG0ec/BKJQgnvsSFpcKLM5xXVWnvZS97DWHgE= -golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= -golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= -golang.org/x/image v0.0.0-20190321063152-3fc05d484e9f/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= -golang.org/x/image v0.0.0-20190703141733-d6a02ce849c9/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20190910094157-69e4b8554b2a/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20200119044424-58c23975cae1 h1:5h3ngYt7+vXCDZCup/HkCQgW5XwmSvR/nA2JmJ0RErg= -golang.org/x/image v0.0.0-20200119044424-58c23975cae1/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20200618115811-c13761719519/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20200801110659-972c09e46d76 h1:U7GPaoQyQmX+CBRWXKrvRzWTbd+slqeSh8uARsIyhAw= -golang.org/x/image v0.0.0-20200801110659-972c09e46d76/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20200927104501-e162460cd6b5 h1:QelT11PB4FXiDEXucrfNckHoFxwt8USGY1ajP1ZF5lM= -golang.org/x/image v0.0.0-20200927104501-e162460cd6b5/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= -golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= -golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200904194848-62affa334b73 h1:MXfv8rhZWmFeqX3GNZRsd6vOLoaCHjYEX3qkRo3YBUA= -golang.org/x/net v0.0.0-20200904194848-62affa334b73/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201110031124-69a78807bb2b h1:uwuIcX0g4Yl1NC5XAz37xsr2lTtcqevgzYNVt49waME= -golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200413165638-669c56c373c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.4 h1:0YWbFKbhXG/wIiuHDSKpS0Iy7FSA+u45VtBMfQcFTTc= -golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190927191325-030b2cf1153e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20200326194725-b1df9901287c h1:lOHr9KzDy5SxEmffvQO+sLmartg6RfDELX60/tv3qFg= -golang.org/x/tools v0.0.0-20200326194725-b1df9901287c/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= -golang.org/x/tools v0.0.0-20200619210111-0f592d2728bb/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200915201639-f4cefd1cb5ba/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= -golang.org/x/tools v0.0.0-20200917221617-d56e4e40bc9d h1:y39d97JVttj+rkTXITl1nf9Vsk+VoRuNzIDLFldUSB4= -golang.org/x/tools v0.0.0-20200917221617-d56e4e40bc9d/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= -golang.org/x/tools v0.0.0-20201121010211-780cb80bd7fb h1:z5+u0pkAUPUWd3taoTialQ2JAMo4Wo1Z3L25U4ZV9r0= -golang.org/x/tools v0.0.0-20201121010211-780cb80bd7fb/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= -gonum.org/v1/gonum v0.7.0 h1:Hdks0L0hgznZLG9nzXb8vZ0rRvqNvAcgAp84y7Mwkgw= -gonum.org/v1/gonum v0.7.0/go.mod h1:L02bwd0sqlsvRv41G7wGWFCsVNZFv/k1xzGIxeANHGM= -gonum.org/v1/gonum v0.8.1 h1:wGtP3yGpc5mCLOLeTeBdjeui9oZSz5De0eOjMLC/QuQ= -gonum.org/v1/gonum v0.8.1/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0= -gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= -gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc= -gonum.org/v1/plot v0.7.0 h1:Otpxyvra6Ie07ft50OX5BrCfS/BWEMvhsCUHwPEJmLI= -gonum.org/v1/plot v0.7.0/go.mod h1:2wtU6YrrdQAhAF9+MTd5tOQjrov/zF70b1i99Npjvgo= -gonum.org/v1/plot v0.8.1 h1:1oWyfw7tIDDtKb+t+SbR9RFruMmNJlsKiZUolHdys2I= -gonum.org/v1/plot v0.8.1/go.mod h1:3GH8dTfoceRTELDnv+4HNwbvM/eMfdDUGHFG2bo3NeE= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20200911024640-645f7a48b24f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= -google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.32.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc/cmd/protoc-gen-go-grpc v0.0.0-20200910201057-6591123024b3/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= -google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= -google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= -google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= -google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= diff --git a/python/gotopy/README.md b/python/gotopy/README.md deleted file mode 100644 index a19079ecd..000000000 --- a/python/gotopy/README.md +++ /dev/null @@ -1,45 +0,0 @@ -This directory has info and tools for converting Go-based simulation projects to Python. - -# GoToPy - -GoToPy does a first pass conversion of Go syntax to Python syntax: https://github.com/go-python/gotopy - -```sh -$ go get github.com/go-python/gotopy -``` - -This does the install directly, so the gotopy executable should be in your `~/go/bin` directory, which you should add to your `PATH` if not already. Check by typing: `which gotopy` for example. - -To run directly: - -```sh -$ gotopy -gogi mysim.go > mysim.py -``` - -The `-gogi` option is important for enabling extra conversions for the GoGi gui system. - -# leabra-to.py - -This Python program does additional steps specific to Leabra sims to attempt to get the code closer to usable. To prepare, run: - -```sh -$ pip3 install -r requirements.txt -``` - -You can copy this file to an appropriate place on your path, e.g.: - -```sh -$ cp leabra-to.py /usr/local/bin -``` - -and then run it: - -```sh -$ leabra-to.py mysim.go -``` - -which generates a file named `mysim.py` -- important: will overwrite any existing! - -After running, you will need to fix the start and end by copying from an existing project that is similar (use ra25 if nothing else), with the CB callback functions at the top, and the `tbar.AddAction` calls in `ConfigGui` at the end that call these callbacks instead of the inline code. There may be other errors which you can discover by running it -- there is a diminishing returns point on this conversion process so it is not designed to be complete. - - diff --git a/python/gotopy/leabra-to.py b/python/gotopy/leabra-to.py deleted file mode 100755 index 070452666..000000000 --- a/python/gotopy/leabra-to.py +++ /dev/null @@ -1,371 +0,0 @@ -#!/usr/local/bin/python3 - -# 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. - -# use: -# leabra-to.py mysim.go -# -# Generates mysim.py conversion of mysim.go, attempting to - -import os, sys, subprocess - -debug = False - -# these are defined below -inserts = [] -replaces = [] -deletes = [] - -def read_as_string(fnm): - # reads file as string - if not os.path.isfile(fnm): - return "" - with open(fnm, "r") as f: - val = f.read() - return val - -def write_string(fnm, stval): - with open(fnm,"w") as f: - f.write(stval) - -def gotopy(fname): - result = subprocess.run(["gotopy","-gogi", fname], capture_output=True) - if len(result.stderr) > 0: - print(str(result.stderr, "utf-8")) - return str(result.stdout, "utf-8") - -def repls(txt): - txt = txt.replace("leabra.LeabraLayer(", "leabra.Layer(") - txt = txt.replace(".AsLeabra()", "") - txt = txt.replace("(`", "('") - txt = txt.replace("`)", "')") - txt = txt.replace(" = ss.TrainUpdt", " = ss.TrainUpdt.value") - txt = txt.replace(" = ss.TestUpdt", " = ss.TestUpdt.value") - txt = txt.replace(" ss.TrainUpdt >", " ss.TrainUpdt.value >") - txt = txt.replace(" ss.TestUpdt >", " ss.TestUpdt.value >") - return txt - -def inserttxt(txt, ati, ins): - if debug: - print("\n##########\nins:") - print(ins) - for i, v in enumerate(ins): - txt.insert(ati+i, v) - -def repltxt(txt, ati, ftxt, itxt): - if debug: - print("\n##########\nrepl:") - print(ftxt) - print("with:") - print(itxt) - nf = len(ftxt) - ni = len(itxt) - for i, v in enumerate(itxt): - if i < nf: - txt[ati+i] = v - else: - txt.insert(ati+i, v) - if nf > ni: - del txt[ati+ni:ati+nf] - -def diffs(txt): - lns = txt.splitlines() - nln = lns.copy() - ni = 0 - insi = -1 - rpli = -1 - deli = -1 - didone = False - for i, v in enumerate(lns): - for j, ir in enumerate(inserts): - if j <= insi: - continue - ftxt = ir[0] - lnoff = ir[1] - itxt = ir[2] - if ftxt in v: - inserttxt(nln, ni+lnoff, itxt) - ni += len(itxt) - insi = j - break - for j, rp in enumerate(replaces): - if j <= rpli: - continue - ftxt = rp[0] - itxt = rp[1] - if ftxt[0] == v: - repltxt(nln, ni, ftxt, itxt) - ni += len(itxt) - len(ftxt) - rpli = j - break - for j, ft in enumerate(deletes): - if j <= deli: - continue - if ft[0] == v: - if debug: - print("\n##########\ndel:") - print(ft) - del nln[ni:ni+len(ft)] - ni -= len(ft) - deli = j - break - ni += 1 - return '\n'.join(nln) - -def column(txt): - lns = txt.splitlines() - insc = False - start = False - for i, v in enumerate(lns): - if " = etable.Schema(" in v: - insc = True - start = True - continue - if insc and "etensor." in v: - op = v.find('("') - if op < 0: - insc = False - continue - if start: - lns[i] = v[:op] + "[etable.Column" + v[op:] - start = False - else: - lns[i] = v[:op] + "etable.Column" + v[op:] - elif insc: - lns[i-1] = lns[i-1][:-1] + "]" - insc = False - continue - return '\n'.join(lns) - -def main(argv): - if len(argv) < 2 or argv[1] == "help": - print("\n%s converts leabra .go sim file to Python .py file\n" % argv[0]) - print("usage: just takes the input filename") - exit(0) - - fname = argv[1] - outfn = os.path.splitext(fname)[0] + ".py" - raw = gotopy(fname) - txt = diffs(raw) - txt = repls(txt) - txt = column(txt) - write_string(outfn, txt) - -############################################## -### text edits - -# the only constraint is that these must be *in sequential order* -- the index -# is incremented for every match, so it doesn't revisit any matches more than once - -## tuple elements are: find, offset, text - -inserts = [ -("def New(ss):", -1, [ -''' self.vp = 0''', -''' self.SetTags("vp", 'view:"-" desc:"viewport"')''', -'', -''' def InitParams(ss):''', -''' """''', -''' Sets the default set of parameters -- Base is always applied, and others can be optionally''', -''' selected to apply on top of that''', -''' """''', -''' ss.Params.OpenJSON("my.params")''', -]), -("def Config(ss):", 4, [ -''' ss.InitParams()''' -]), -("viewUpdt = ss.TrainUpdt", 0, [ -''' if ss.Win != 0:''', -''' ss.Win.PollEvents() # this is essential for GUI responsiveness while running''', -]), -("def Stopped(ss):", 10, [ -''' ss.UpdateClassView()''' -]), -("vp = win.WinViewport2D()", 1, [ -''' ss.vp = vp''', -]), -] - -replaces = [ -([ -''' err = net.Build()''', -''' if err != 0:''', -''' log.Println(err)''', -''' return''', -],[ -''' net.Build()''' -]), -([ -''' ss.RndSeed = time.Now().UnixNano()''', -],[ -''' ss.RndSeed = int(datetime.now(timezone.utc).timestamp())''', -]), -([ -''' switch viewUpdt:''', -''' if leabra.Cycle:''', -],[ -''' if viewUpdt == leabra.Cycle:''', -]), -([ -''' if leabra.FastSpike:''' -],[ -''' if viewUpdt == leabra.FastSpike:''' -]), -([ -''' if ss.ViewOn:''', -''' switch :''' -],[ -''' if ss.ViewOn:''' -]), -([ -''' epc, _, chg = ss.TrainEnv.Counter(env.Epoch)''', -],[ -''' epc = env.CounterCur(ss.TrainEnv, env.Epoch)''', -''' chg = env.CounterChg(ss.TrainEnv, env.Epoch)''', -]), -([ -''' ss.TrlSSE, ss.TrlAvgSSE = out.MSE(0.5)''', -],[ -''' ss.TrlSSE = out.SSE(0.5) # 0.5 = per-unit tolerance -- right side of .5''', -''' ss.TrlAvgSSE = ss.TrlSSE / len(out.Neurons)''' -]), -([ -''' _, _, chg = ss.TestEnv.Counter(env.Epoch)''' -],[ -''' chg = env.CounterChg(ss.TestEnv, env.Epoch)''' -]), -([ -''' _, _, chg = ss.TestEnv.Counter(env.Epoch)''' -],[ -''' chg = env.CounterChg(ss.TestEnv, env.Epoch)''' -]), -([ -''' err = ss.SetParamsSet("Base", sheet, setMsg)''', -''' if ss.ParamSet != "" and ss.ParamSet != "Base":''', -''' sps = ss.ParamSet.split()''', -''' for ps in sps :''', -''' err = ss.SetParamsSet(ps, sheet, setMsg)''', -''' return err''', -],[ -''' ss.SetParamsSet("Base", sheet, setMsg)''', -''' if ss.ParamSet != "" and ss.ParamSet != "Base":''', -''' sps = ss.ParamSet.split()''', -''' for ps in sps:''', -''' ss.SetParamsSet(ps, sheet, setMsg)''', -]), -([ -''' pset, err = ss.Params.SetByNameTry(setNm)''', -''' if err != 0:''', -''' return err''', -''' if sheet == "" or sheet == "Network":''', -''' netp, ok = pset.Sheets["Network"]''', -''' if ok:''', -''' ss.Net.ApplyParams(netp, setMsg)''', -'', -''' if sheet == "" or sheet == "Sim":''', -''' simp, ok = pset.Sheets["Sim"]''', -''' if ok:''', -''' simp.Apply(ss, setMsg)''', -'', -''' return err''', -],[ -''' pset = ss.Params.SetByNameTry(setNm)''', -''' if sheet == "" or sheet == "Network":''', -''' if "Network" in pset.Sheets:''', -''' netp = pset.SheetByNameTry("Network")''', -''' ss.Net.ApplyParams(netp, setMsg)''', -''' if sheet == "" or sheet == "Sim":''', -''' if "Sim" in pset.Sheets:''', -''' simp= pset.SheetByNameTry("Sim")''', -''' pyparams.ApplyParams(ss, simp, setMsg)''', -]), -([ -''' if ss.ValsTsrs == 0:''', -''' ss.ValsTsrs = make({})''', -''' tsr, ok = ss.ValsTsrs[name]''', -''' if not ok:''', -''' tsr = etensor.Float32()''', -''' ss.ValsTsrs[name] = tsr''', -],[ -''' if name in ss.ValsTsrs:''', -''' return ss.ValsTsrs[name]''', -''' tsr = etensor.Float32()''', -''' ss.ValsTsrs[name] = tsr''', -]), -([ -''' sv = giv.AddNewStructView(split, "sv")''', -''' sv.SetStruct(ss)''' -],[ -''' cv = ss.NewClassView("sv")''', -''' cv.AddFrame(split)''', -''' cv.Config()''' -]), -([ -''' nv = *netview.NetView(tv.AddNewTab(netview.KiT_NetView, "NetView"))''' -],[ -''' nv = netview.NetView()''', -''' tv.AddTab(nv, "NetView")''' -]), -([ -''' plt = *eplot.Plot2D(tv.AddNewTab(eplot.KiT_Plot2D, "TrnEpcPlot"))''' -],[ -''' plt = eplot.Plot2D()''', -''' tv.AddTab(plt, "TrnEpcPlot")''' -]), -([ -''' plt = *eplot.Plot2D(tv.AddNewTab(eplot.KiT_Plot2D, "TstTrlPlot"))''' -],[ -''' plt = eplot.Plot2D()''', -''' tv.AddTab(plt, "TstTrlPlot")''' -]), -([ -''' plt = *eplot.Plot2D(tv.AddNewTab(eplot.KiT_Plot2D, "TstCycPlot"))''' -],[ -''' plt = eplot.Plot2D()''', -''' tv.AddTab(plt, "TstCycPlot")''' -]), -([ -''' plt = *eplot.Plot2D(tv.AddNewTab(eplot.KiT_Plot2D, "TstEpcPlot"))''' -],[ -''' plt = eplot.Plot2D()''', -''' tv.AddTab(plt, "TstEpcPlot")''' -]), -([ -''' plt = *eplot.Plot2D(tv.AddNewTab(eplot.KiT_Plot2D, "RunPlot"))''' -],[ -''' plt = eplot.Plot2D()''', -''' tv.AddTab(plt, "RunPlot")''' -]), -([ -''' plt = *eplot.Plot2D(tv.AddNewTab(eplot.KiT_Plot2D, "TrnEpcPlot"))''' -],[ -''' plt = eplot.Plot2D()''', -''' tv.AddTab(plt, "TrnEpcPlot")''' -]), -([ -''' split.SetSplits(.2, .8)''' -],[ -''' split.SetSplitsList(go.Slice_float32([.2, .8]))''', -''' recv = win.This()''' -]), -] - -deletes = [ -[ -''' # re-config env just in case a different set of patterns was''', -],[ -''' # selected or patterns have been modified etc''', -],[ -''' # ss.Win.PollEvents() // this can be used instead of running in a separate goroutine''', -],[ -''' # update prior weight changes at start, so any DWt values remain visible at end''', -''' # you might want to do this less frequently to achieve a mini-batch update''', -''' # in which case, move it out to the TrainTrial method where the relevant''', -''' # counters are being dealt with.''', -] -] - -main(sys.argv) - diff --git a/python/gotopy/requirements.txt b/python/gotopy/requirements.txt deleted file mode 100644 index 8b1378917..000000000 --- a/python/gotopy/requirements.txt +++ /dev/null @@ -1 +0,0 @@ - diff --git a/python/pyside/etor.py b/python/pyside/etor.py deleted file mode 100644 index dba7f318a..000000000 --- a/python/pyside/etor.py +++ /dev/null @@ -1,121 +0,0 @@ -# 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. - -# etor is python-side library for eTorch, for saving and copying network -# state for visualization. - -# note: from below here should be updated for standalone etorch vs. leabra - -from etorch import go, etorch, gi, netview - -import torch - -class State(object): - """ - State manages saving and copying of network state - """ - def __init__(self, nn): - self.nn = nn # our torch.nn module - self.record = True # set to False to turn off recording - self.rec_wts = False # set to True to turn on recording of prjn-level weight state - self.trace = False # print out dimensions of what is recorded -- useful for initial config - self.wtmap = {} # dict of names for prjn weights - self.net = 0 # network that we save to - - def set_net(self, net): - """ - set_net sets the etorch.Network to display to - """ - self.net = net - - def rec(self, x, var): - """ - rec records current tensor state x to variable named var - """ - if not self.record: - return - if self.trace: - print(var, x.size()) - - sd = self.nn.state_dict() - net = self.net - - nmv = var.split(".") - vnm = nmv[-1] - lnm = ".".join(nmv[:-1]) - ly = etorch.Layer(net.LayerByName(lnm)) - nst = ly.States[vnm] - nst.Values.copy(torch.flatten(x)) - - if not self.rec_wts: - return - - for pi in ly.RcvPrjns: - pj = etorch.Prjn(handle=pi) - pnm = pj.Name() - if not pnm in self.wtmap: - continue - wnm = self.wtmap[pnm] - wts = sd[wnm + ".weight"] - pst = pj.States["Wt"] - pst.Values.copy(torch.flatten(wts)) - bnm = wnm + ".bias" - if bnm in sd: - bst = sd[bnm] - lst = ly.States["Bias"] - lst.Values.copy(torch.flatten(bst)) - -class NetView(object): - """ - NetView opens a separate window with the network view -- for standalone use. - """ - def __init__(self, net): - self.Net = net - self.NetView = 0 - self.Win = 0 - self.vp = 0 - - def open(ss): - """ - open opens the window of this gui - """ - width = 1600 - height = 1200 - - win = gi.NewMainWindow("netview", "eTorch NetView", width, height) - ss.Win = win - - vp = win.WinViewport2D() - ss.vp = vp - updt = vp.UpdateStart() - - mfr = win.SetMainFrame() - - nv = netview.NetView() - mfr.AddChild(nv) - nv.Var = "Act" - nv.SetNet(ss.Net) - ss.NetView = nv - - # main menu - appnm = gi.AppName() - mmen = win.MainMenu - mmen.ConfigMenus(go.Slice_string([appnm, "File", "Edit", "Window"])) - - amen = gi.Action(win.MainMenu.ChildByName(appnm, 0)) - amen.Menu.AddAppMenu(win) - - emen = gi.Action(win.MainMenu.ChildByName("Edit", 1)) - emen.Menu.AddCopyCutPaste(win) - win.MainMenuUpdated() - vp.UpdateEndNoSig(updt) - win.GoStartEventLoop() - - def update(ss): - """ - call update to update display - """ - ss.NetView.Record("") # note: can include any kind of textual state information here to display too - ss.NetView.GoUpdate() - diff --git a/python/pyside/pyet.py b/python/pyside/pyet.py deleted file mode 100644 index 62caad3de..000000000 --- a/python/pyside/pyet.py +++ /dev/null @@ -1,383 +0,0 @@ -# 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. - -# code for converting etensor.Tensor and etable.Table to / from -# various python data formats including numpy, pandas, and pytorch `TensorDataset`, -# which has the same structure as an `etable`, and is used in the -# `pytorch` neural network framework. - -from leabra import go, etable, etensor - -import numpy as np -import pandas as pd -import torch -import torch.utils.data as data_utils - -def etensor_to_numpy(et): - """ - returns a numpy ndarray constructed from the given etensor.Tensor. - data is copied into the numpy ndarray -- it is not a view. - """ - nar = 0 - if et.DataType() == etensor.UINT8: - nar = np.array(etensor.Uint8(et).Values, dtype=np.uint8) - elif et.DataType() == etensor.INT8: - nar = np.array(etensor.Int8(et).Values, dtype=np.int8) - elif et.DataType() == etensor.UINT16: - nar = np.array(etensor.Uint16(et).Values, dtype=np.uint16) - elif et.DataType() == etensor.INT16: - nar = np.array(etensor.Int16(et).Values, dtype=np.int16) - elif et.DataType() == etensor.UINT32: - nar = np.array(etensor.Uint32(et).Values, dtype=np.uint32) - elif et.DataType() == etensor.INT32: - nar = np.array(etensor.Int32(et).Values, dtype=np.int32) - elif et.DataType() == etensor.UINT64: - nar = np.array(etensor.Uint64(et).Values, dtype=np.uint64) - elif et.DataType() == etensor.INT64: - nar = np.array(etensor.Int64(et).Values, dtype=np.int64) - elif et.DataType() == etensor.FLOAT32: - nar = np.array(etensor.Float32(et).Values, dtype=np.float32) - elif et.DataType() == etensor.FLOAT64: - nar = np.array(etensor.Float64(et).Values, dtype=np.float64) - elif et.DataType() == etensor.STRING: - nar = np.array(etensor.String(et).Values) - elif et.DataType() == etensor.INT: - nar = np.array(etensor.Int(et).Values, dtype=np.intc) - elif et.DataType() == etensor.BOOL: - etb = etensor.Bits(et) - sz = etb.Len() - nar = np.zeros(sz, dtype=np.bool_) - for i in range(sz): - nar[i] = etb.Value1D(i) - else: - raise TypeError("tensor with type %s cannot be converted" % (et.DataType().String())) - return 0 - # there does not appear to be a way to set the shape at the same time as initializing - return nar.reshape(et.Shapes()) - - -def numpy_to_etensor(nar): - """ - returns an etensor.Tensor constructed from the given etensor.Tensor - data is copied into the Tensor -- it is not a view. - """ - et = 0 - narf = np.reshape(nar, -1) # flat view - if nar.dtype == np.uint8: - et = etensor.NewUint8(go.Slice_int(list(nar.shape)), go.nil, go.nil) - et.Values.copy(narf) - elif nar.dtype == np.int8: - et = etensor.NewInt8(go.Slice_int(list(nar.shape)), go.nil, go.nil) - et.Values.copy(narf) - elif nar.dtype == np.uint16: - et = etensor.NewUint16(go.Slice_int(list(nar.shape)), go.nil, go.nil) - et.Values.copy(narf) - elif nar.dtype == np.int16: - et = etensor.NewInt16(go.Slice_int(list(nar.shape)), go.nil, go.nil) - et.Values.copy(narf) - elif nar.dtype == np.uint32: - et = etensor.NewUint32(go.Slice_int(list(nar.shape)), go.nil, go.nil) - et.Values.copy(narf) - elif nar.dtype == np.int32: - et = etensor.NewInt32(go.Slice_int(list(nar.shape)), go.nil, go.nil) - et.Values.copy(narf) - elif nar.dtype == np.uint64: - et = etensor.NewUint64(go.Slice_int(list(nar.shape)), go.nil, go.nil) - et.Values.copy(narf) - elif nar.dtype == np.int64: - et = etensor.NewInt64(go.Slice_int(list(nar.shape)), go.nil, go.nil) - et.Values.copy(narf) - elif nar.dtype == np.float32: - et = etensor.NewFloat32(go.Slice_int(list(nar.shape)), go.nil, go.nil) - et.Values.copy(narf) - elif nar.dtype == np.float64: - et = etensor.NewFloat64(go.Slice_int(list(nar.shape)), go.nil, go.nil) - et.Values.copy(narf) - elif nar.dtype.type is np.string_ or nar.dtype.type is np.str_: - et = etensor.NewString(go.Slice_int(list(nar.shape)), go.nil, go.nil) - et.Values.copy(narf) - elif nar.dtype == np.int_ or nar.dtype == np.intc: - et = etensor.NewInt(go.Slice_int(list(nar.shape)), go.nil, go.nil) - et.Values.copy(narf) - elif nar.dtype == np.bool_: - et = etensor.NewBits(go.Slice_int(list(nar.shape)), go.nil, go.nil) - rnar = narf - sz = len(rnar) - for i in range(sz): - et.Set1D(i, rnar[i]) - else: - raise TypeError("numpy ndarray with type %s cannot be converted" % (nar.dtype)) - return 0 - return et - -######################### -# Copying - -def copy_etensor_to_numpy(nar, et): - """ - copies data from etensor.Tensor (et, source) to existing numpy ndarray (nar, dest). - """ - narf = np.reshape(nar, -1) - etv = et - if et.DataType() == etensor.UINT8: - etv = etensor.Uint8(et).Values - elif et.DataType() == etensor.INT8: - etv = etensor.Int8(et).Values - elif et.DataType() == etensor.UINT16: - etv = etensor.Uint16(et).Values - elif et.DataType() == etensor.INT16: - etv = etensor.Int16(et).Values - elif et.DataType() == etensor.UINT32: - etv = etensor.Uint32(et).Values - elif et.DataType() == etensor.INT32: - etv = etensor.Int32(et).Values - elif et.DataType() == etensor.UINT64: - etv = etensor.Uint64(et).Values - elif et.DataType() == etensor.INT64: - etv = etensor.Int64(et).Values - elif et.DataType() == etensor.FLOAT32: - etv = etensor.Float32(et).Values - elif et.DataType() == etensor.FLOAT64: - etv = etensor.Float64(et).Values - elif et.DataType() == etensor.STRING: - etv = etensor.String(et).Values - elif et.DataType() == etensor.INT: - etv = etensor.Int(et).Values - elif et.DataType() == etensor.BOOL: - etb = etensor.Bits(et) - sz = min(etb.Len(), len(narf)) - for i in range(sz): - narf[i] = etb.Value1D(i) - return - else: - raise TypeError("tensor with type %s cannot be copied" % (et.DataType().String())) - return 0 - np.copyto(narf, etv, casting='unsafe') - -def copy_numpy_to_etensor(et, nar): - """ - copies data from numpy ndarray (nar, source) to existing etensor.Tensor (et, dest) - """ - narf = np.reshape(nar, -1) - etv = et - if et.DataType() == etensor.UINT8: - etv = etensor.Uint8(et).Values - elif et.DataType() == etensor.INT8: - etv = etensor.Int8(et).Values - elif et.DataType() == etensor.UINT16: - etv = etensor.Uint16(et).Values - elif et.DataType() == etensor.INT16: - etv = etensor.Int16(et).Values - elif et.DataType() == etensor.UINT32: - etv = etensor.Uint32(et).Values - elif et.DataType() == etensor.INT32: - etv = etensor.Int32(et).Values - elif et.DataType() == etensor.UINT64: - etv = etensor.Uint64(et).Values - elif et.DataType() == etensor.INT64: - etv = etensor.Int64(et).Values - elif et.DataType() == etensor.FLOAT32: - etv = etensor.Float32(et).Values - elif et.DataType() == etensor.FLOAT64: - etv = etensor.Float64(et).Values - elif et.DataType() == etensor.STRING: - etv = etensor.String(et).Values - elif et.DataType() == etensor.INT: - etv = etensor.Int(et).Values - elif et.DataType() == etensor.BOOL: - etb = etensor.Bits(et) - sz = min(etb.Len(), len(narf)) - for i in range(sz): - narf[i] = etb.Value1D(i) - return - else: - raise TypeError("tensor with type %s cannot be copied" % (et.DataType().String())) - return 0 - etv.copy(narf) # go slice copy, not python copy = clone - - -########################################## -# Tables - -class eTable(object): - """ - pyet.eTable is a Python version of the Go etable.Table, with slices of columns - as numpy ndarrays, and corresponding column names, along with a coordinated - dictionary of names to col indexes. This is returned by basic - etable_to_py() function to convert all data from an etable.Table, - and can then be used to convert into other python datatable / frame - structures. - """ - def __init__(self): - self.Cols = [] - self.ColNames = [] - self.Rows = 0 - self.ColNameMap = {} - self.MetaData = {} - - def __str__(dt): - return "Columns: %s\nRows: %d Cols:\n%s\n" % (dt.ColNameMap, dt.Rows, dt.Cols) - - def UpdateColNameMap(dt): - """ - UpdateColNameMap updates the column name map - """ - dt.ColNameMap = {} - for i, nm in enumerate(dt.ColNames): - dt.ColNameMap[nm] = i - - def AddCol(dt, nar, name): - """ - AddCol adds a numpy ndarray as a new column, with given name - """ - dt.Cols.append(nar) - dt.ColNames.append(name) - dt.UpdateColNameMap() - - def ColByName(dt, name): - """ - ColByName returns column of given name, or raises a LookupError if not found - """ - if name in dt.ColNameMap: - return dt.Cols[dt.ColNameMap[name]] - raise LookupError("column named: %s not found" % (name)) - - def MergeCols(dt, st_nm, n): - """ - MergeCols merges n sequential columns into a multidimensional array, starting at given column name - Resulting columns are all stored at st_nm - """ - sti = dt.ColNameMap[st_nm] - cls = dt.Cols[sti:sti+n] - nc = np.column_stack(cls) - dt.Cols[sti] = nc - del dt.Cols[sti+1:sti+n] - del dt.ColNames[sti+1:sti+n] - dt.UpdateColNameMap() - - def ReshapeCol(dt, colnm, shp): - """ - ReshapeCol reshapes column to given shape - """ - ci = dt.ColNameMap[colnm] - dc = dt.Cols[ci] - dt.Cols[ci] = dc.reshape(shp) - -def etable_to_py(et): - """ - returns a pyet.eTable python version of given etable.Table. - The eTable can then be converted into other standard Python formats, - but most of them don't quite capture exactly the same information, so - the eTable can be handy to keep around. - """ - pt = eTable() - pt.Rows = et.Rows - nc = len(et.Cols) - for ci in range(nc): - dc = et.Cols[ci] - cn = et.ColNames[ci] - nar = etensor_to_numpy(dc) - pt.AddCol(nar, cn) - for md in et.MetaData: - pt.MetaData[md[0]] = md[1] - return pt - -def py_to_etable(pt): - """ - returns an etable.Table version of given pyet.eTable. - """ - et = etable.Table() - et.Rows = pt.Rows - nc = len(pt.Cols) - for ci in range(nc): - pc = pt.Cols[ci] - cn = pt.ColNames[ci] - tsr = numpy_to_etensor(pc) - et.AddCol(tsr, cn) - for md in pt.MetaData: - et.SetMetaData(md, pt.MetaData[md]) - return et - -def copy_etable_to_py(pt, et): - """ - copies values in columns of same name from etable.Table to pyet.eTable - """ - nc = len(pt.Cols) - for ci in range(nc): - pc = pt.Cols[ci] - cn = pt.ColNames[ci] - try: - dc = et.ColByNameTry(cn) - copy_etensor_to_numpy(pc, dc) - except: - pass - -def copy_py_to_etable(et, pt): - """ - copies values in columns of same name from pyet.eTable to etable.Table - """ - nc = len(et.Cols) - for ci in range(nc): - dc = et.Cols[ci] - cn = et.ColNames[ci] - try: - pc = pt.ColByName(cn) - copy_numpy_to_etensor(dc, pc) - except: - pass - -def etable_to_torch(et): - """ - returns a torch.utils.data.TensorDataset constructed from the numeric columns - of the given pyet.eTable (string columns are not allowed in TensorDataset) - """ - tsrs = [] - nc = len(et.Cols) - for ci in range(nc): - dc = et.Cols[ci] - cn = et.ColNames[ci] - - if dc.dtype.type is np.string_ or dc.dtype.type is np.str_: - continue - - tsr = torch.from_numpy(dc) - tsrs.append(tsr) - ds = data_utils.TensorDataset(*tsrs) - return ds - -def etable_to_pandas(et, skip_tensors=False): - """ - returns a pandas DataFrame constructed from the columns - of the given pyet.eTable, spreading tensor cells over sequential - 1d columns, if they aren't skipped over. - """ - ed = {} - nc = len(et.Cols) - for ci in range(nc): - dc = et.Cols[ci] - cn = et.ColNames[ci] - if dc.ndim == 1: - ed[cn] = dc - continue - if skip_tensors: - continue - csz = int(dc.size / et.Rows) # cell size - rs = dc.reshape([et.Rows, csz]) - for i in range(csz): - cnn = "%s_%d" % (cn, i) - ed[cnn] = rs[:,i] - df = pd.DataFrame(data=ed) - return df - -def pandas_to_etable(df): - """ - returns a pyet.eTable constructed from given pandas DataFrame - """ - pt = eTable() - pt.Rows = len(df.index) - for cn in df.columns: - dc = df.loc[:, cn].values - pt.AddCol(dc, cn) - return pt - diff --git a/python/pyside/pygiv.py b/python/pyside/pygiv.py deleted file mode 100644 index eef4c5fd3..000000000 --- a/python/pyside/pygiv.py +++ /dev/null @@ -1,410 +0,0 @@ -# Copyright (c) 2019, The GoKi Authors. All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - -from leabra import go, gi, giv, kit, units -from enum import Enum - -class ClassViewObj(object): - """ - ClassViewObj is the base class for Python-defined classes that support a GUI editor (View) - that functions like the StructView in GoGi. It maintains a dict of tags for each field - that determine tooltips and other behavior for the field GUI representation. - """ - def __init__(self): - self.Tags = {} - self.ClassView = 0 - self.ClassViewInline = 0 - self.ClassViewDialog = 0 - - def SetTags(self, field, tags): - self.Tags[field] = tags - - def NewClassView(self, name): - self.ClassView = ClassView(self, name) - return self.ClassView - - def UpdateClassView(self): - if self.ClassView != 0: - self.ClassView.Update() - - def NewClassViewInline(self, name): - self.ClassViewInline = ClassViewInline(self, name) - return self.ClassViewInline - - def UpdateClassViewInline(self): - if self.ClassViewInline != 0: - self.ClassViewInline.Update() - - def OpenViewDialog(self, vp, name, tags): - """ opens a new dialog window for this object, or if one already exists, raises it """ - if self.ClassViewDialog != 0 and self.ClassViewDialog.Win.IsVisible(): - self.ClassViewDialog.Win.Raise() - return - self.ClassViewDialog = ClassViewDialog(vp, self, name, tags, giv.DlgOpts(Title=name)) - return self.ClassViewDialog - -class ClassViewInline(object): - """ - ClassViewInline provides GoGi giv.StructViewInline like inline editor for - python class objects under GoGi. - Due to limitations on calling python callbacks across threads, you must pass a unique - name to the constructor. The object must be a ClassViewObj, with tags using same - syntax as the struct field tags in Go: https://github.com/goki/gi/wiki/Tags - for customizing the view properties (space separated, name:"value") - """ - def __init__(self, obj, name): - """ note: essential to provide a distinctive name for each view """ - self.Class = obj - self.Name = name - classviews[name] = self - self.Lay = 0 - self.Tags = obj.Tags - self.Views = {} # dict of ValueView reps of Go objs - self.Widgets = {} # dict of Widget reps of Python objs - - def FieldTags(self, field): - """ returns the full string of tags for given field, empty string if none """ - if field in self.Tags: - return self.Tags[field] - return "" - - def FieldTagVal(self, field, key): - """ returns the value for given key in tags for given field, empty string if none """ - return giv.StructTagVal(key, self.FieldTags(field)) - - def Config(self): - self.Lay = gi.Layout() - self.Lay.InitName(self.Lay, self.Name) - self.Lay.Lay = gi.LayoutHoriz - self.Lay.SetStretchMaxWidth() - updt = self.Lay.UpdateStart() - flds = self.Class.__dict__ - self.Views = {} - self.Widgets = {} - for nm, val in flds.items(): - tags = self.FieldTags(nm) - if HasTagValue(tags, "view", "-") or nm == "Tags" or nm.startswith("ClassView"): - continue - lbl = gi.Label(self.Lay.AddNewChild(gi.KiT_Label(), "lbl_" + nm)) - lbl.Redrawable = True - lbl.SetProp("horizontal-align", "left") - lbl.SetText(nm) - dsc = self.FieldTagVal(nm, "desc") - if dsc != "": - lbl.Tooltip = dsc - if isinstance(val, go.GoClass): - fnm = self.Name + ":" + nm - if kit.IfaceIsNil(val): - print("Field %s is Nil in ClassView for obj: %s" % (fnm, str(self.Class))) - continue - vv = giv.ToValueView(val, tags) - giv.SetSoloValueIface(vv, val) - vw = self.Lay.AddNewChild(vv.WidgetType(), fnm) - vv.ConfigWidget(vw) - self.Views[nm] = vv - self.Widgets[nm] = vw - # todo: vv.ViewSig.Connect? - else: - vw = PyObjView(val, nm, self.Lay, self.Name, tags) - self.Widgets[nm] = vw - self.Lay.UpdateEnd(updt) - - def Update(self): - updt = self.Lay.UpdateStart() - flds = self.Class.__dict__ - for nm, val in flds.items(): - if nm in self.Views: - vv = self.Views[nm] - giv.SetSoloValueIface(vv, val) # always update in case it might have changed - vv.UpdateWidget() - elif nm in self.Widgets: - vw = self.Widgets[nm] - PyObjUpdtView(val, vw, nm) - self.Lay.UpdateEnd(updt) - -class ClassView(object): - """ - ClassView provides GoGi giv.StructView like editor for python class objects under GoGi. - Due to limitations on calling python callbacks across threads, you must pass a unique - name to the constructor. The object must be a ClassViewObj, with tags using same - syntax as the struct field tags in Go: https://github.com/goki/gi/wiki/Tags - for customizing the view properties (space separated, name:"value") - """ - def __init__(self, obj, name): - """ note: essential to provide a distinctive name for each view """ - self.Class = obj - self.Name = name - classviews[name] = self - self.Frame = 0 - self.Tags = obj.Tags - self.Views = {} # dict of ValueView reps of Go objs - self.Widgets = {} # dict of Widget reps of Python objs - - def AddFrame(self, par): - """ Add a new gi.Frame for the view to given parent gi object """ - self.Frame = gi.Frame(par.AddNewChild(gi.KiT_Frame(), "classview")) - - def FieldTags(self, field): - """ returns the full string of tags for given field, empty string if none """ - if field in self.Tags: - return self.Tags[field] - return "" - - def FieldTagVal(self, field, key): - """ returns the value for given key in tags for given field, empty string if none """ - return giv.StructTagVal(key, self.FieldTags(field)) - - def Config(self): - self.Frame.SetStretchMaxWidth() - self.Frame.SetStretchMaxHeight() - self.Frame.Lay = gi.LayoutGrid - self.Frame.Stripes = gi.RowStripes - self.Frame.SetPropInt("columns", 2) - updt = self.Frame.UpdateStart() - self.Frame.SetFullReRender() - self.Frame.DeleteChildren(True) - flds = self.Class.__dict__ - self.Views = {} - self.Widgets = {} - for nm, val in flds.items(): - tags = self.FieldTags(nm) - if HasTagValue(tags, "view", "-") or nm == "Tags" or nm.startswith("ClassView"): - continue - lbl = gi.Label(self.Frame.AddNewChild(gi.KiT_Label(), "lbl_" + nm)) - lbl.SetText(nm) - dsc = self.FieldTagVal(nm, "desc") - if dsc != "": - lbl.Tooltip = dsc - if isinstance(val, go.GoClass): - fnm = self.Name + ":" + nm - if kit.IfaceIsNil(val): - print("Field %s is Nil in ClassView for obj: %s" % (fnm, str(self.Class))) - continue - vv = giv.ToValueView(val, tags) - giv.SetSoloValueIface(vv, val) - vw = self.Frame.AddNewChild(vv.WidgetType(), fnm) - vv.ConfigWidget(vw) - self.Views[nm] = vv - self.Widgets[nm] = vw - # todo: vv.ViewSig.Connect? - else: - vw = PyObjView(val, nm, self.Frame, self.Name, tags) - self.Widgets[nm] = vw - self.Frame.UpdateEnd(updt) - - def Update(self): - updt = self.Frame.UpdateStart() - flds = self.Class.__dict__ - for nm, val in flds.items(): - if nm in self.Views: - vv = self.Views[nm] - giv.SetSoloValueIface(vv, val) # always update in case it might have changed - vv.UpdateWidget() - elif nm in self.Widgets: - vw = self.Widgets[nm] - PyObjUpdtView(val, vw, nm) - self.Frame.UpdateEnd(updt) - -def ClassViewDialog(vp, obj, name, tags, opts): - """ - ClassViewDialog returns a dialog with ClassView editor for python - class objects under GoGi. - opts must be a giv.DlgOpts instance - """ - dlg = gi.NewStdDialog(opts.ToGiOpts(), opts.Ok, opts.Cancel) - frame = dlg.Frame() - prIdx = dlg.PromptWidgetIdx(frame) - - cv = obj.NewClassView(name) - cv.Frame = gi.Frame(frame.InsertNewChild(gi.KiT_Frame(), prIdx+1, "cv-frame")) - cv.Config() - - # sv.Viewport = dlg.Embed(gi.KiT_Viewport2D).(*gi.Viewport2D) - # if opts.Inactive { - # sv.SetInactive() - # } - - dlg.UpdateEndNoSig(True) - dlg.Open(0, 0, vp, go.nil) - return dlg - -# classviews is a dictionary of classviews -- needed for callbacks -classviews = {} - -def TagValue(tags, key): - """ returns tag value for given key """ - return giv.StructTagVal(key, tags) - -def HasTagValue(tags, key, value): - """ returns true if given key has given value """ - tval = giv.StructTagVal(key, tags) - return tval == value - -def PyObjView(val, nm, frame, ctxt, tags): - """ - PyObjView returns a gi.Widget representing the given Python value, - with given name. - frame = gi.Frame or layout to add widgets to -- also callback recv - ctxt = context for this object (e.g., name of owning struct) - """ - vw = 0 - fnm = ctxt + ":" + nm - if isinstance(val, Enum): - vw = gi.AddNewComboBox(frame, fnm) - vw.SetText(nm) - vw.SetPropStr("padding", "2px") - vw.SetPropStr("margin", "2px") - ItemsFromEnum(vw, val) - vw.ComboSig.Connect(frame, SetEnumCB) - elif isinstance(val, ClassViewObj): - if HasTagValue(tags, "view", "inline"): - sv = val.NewClassViewInline(ctxt + "_" + nm) # new full name - sv.Config() - frame.AddChild(sv.Lay) - vw = sv.Lay - else: - vw = gi.AddNewAction(frame, fnm) - vw.SetText(nm) - vw.SetPropStr("padding", "2px") - vw.SetPropStr("margin", "2px") - vw.SetPropStr("border-radius", "4px") - vw.ActionSig.Connect(frame, EditObjCB) - elif isinstance(val, bool): - vw = gi.AddNewCheckBox(frame, fnm) - vw.SetChecked(val) - vw.ButtonSig.Connect(frame, SetBoolValCB) - elif isinstance(val, (int, float)): - vw = gi.AddNewSpinBox(frame, fnm) - vw.SetValue(val) - if isinstance(val, int): - vw.SpinBoxSig.Connect(frame, SetIntValCB) - vw.Step = 1 - else: - vw.SpinBoxSig.Connect(frame, SetFloatValCB) - mv = TagValue(tags, "min") - if mv != "": - vw.SetMin(float(mv)) - mv = TagValue(tags, "max") - if mv != "": - vw.SetMax(float(mv)) - mv = TagValue(tags, "step") - if mv != "": - vw.Step = float(mv) - mv = TagValue(tags, "format") - if mv != "": - vw.Format = mv - else: - vw = gi.AddNewTextField(frame, fnm) - vw.SetText(str(val)) - vw.SetPropStr("min-width", "10em") - vw.TextFieldSig.Connect(frame, SetStrValCB) - mv = TagValue(tags, "width") - if mv != "": - vw.SetProp("width", mv + "ch") - if HasTagValue(tags, "inactive", "+"): - vw.SetInactive() - return vw - -def PyObjUpdtView(val, vw, nm): - """ - updates the given view widget for given value - """ - if isinstance(val, Enum): - if isinstance(vw, gi.ComboBox): - svw = gi.ComboBox(vw) - svw.SetCurVal(val.name) - else: - print("epygiv; Enum value: %s doesn't have ComboBox widget" % nm) - elif isinstance(val, go.GoClass): - pass - elif isinstance(val, ClassViewObj): - val.UpdateClassViewInline() - val.UpdateClassView() - elif isinstance(val, bool): - if isinstance(vw, gi.CheckBox): - svw = gi.CheckBox(vw) - svw.SetChecked(val) - else: - print("epygiv; bool value: %s doesn't have CheckBox widget" % nm) - elif isinstance(val, (int, float)): - if isinstance(vw, gi.SpinBox): - svw = gi.SpinBox(vw) - svw.SetValue(val) - else: - print("epygiv; numerical value: %s doesn't have SpinBox widget" % nm) - else: - if isinstance(vw, gi.TextField): - tvw = gi.TextField(vw) - tvw.SetText(str(val)) - else: - print("epygiv; object %s = %s doesn't have expected TextField widget" % (nm, val)) - -def SetIntValCB(recv, send, sig, data): - vw = gi.SpinBox(handle=send) - nm = vw.Name() - nms = nm.split(':') - cv = classviews[nms[0]] - setattr(cv.Class, nms[1], int(vw.Value)) - -def SetFloatValCB(recv, send, sig, data): - vw = gi.SpinBox(handle=send) - nm = vw.Name() - nms = nm.split(':') - cv = classviews[nms[0]] - setattr(cv.Class, nms[1], float(vw.Value)) - -def EditObjCB(recv, send, sig, data): - vw = gi.Action(handle=send) - nm = vw.Name() - nms = nm.split(':') - cv = classviews[nms[0]] - fld = getattr(cv.Class, nms[1]) - tags = cv.FieldTags(nms[1]) - nnm = nm.replace(":", "_") - return fld.OpenViewDialog(vw.Viewport, nnm, tags) - -def SetStrValCB(recv, send, sig, data): - if sig != gi.TextFieldDone: - return - vw = gi.TextField(handle=send) - nm = vw.Name() - nms = nm.split(':') - cv = classviews[nms[0]] - setattr(cv.Class, nms[1], vw.Text()) - -def SetBoolValCB(recv, send, sig, data): - if sig != gi.ButtonToggled: - return - vw = gi.CheckBox(handle=send) - nm = vw.Name() - # print("cb name:", nm) - nms = nm.split(':') - cv = classviews[nms[0]] - setattr(cv.Class, nms[1], vw.IsChecked() != 0) - -############## -# Enums - -def ItemsFromEnum(cb, enm): - nms = [] - typ = type(enm) - nnm = typ.__name__ + "N" # common convention of using the type name + N for last item in list - for en in typ: - if en.name != nnm: - nms.append(en.name) - cb.ItemsFromStringList(go.Slice_string(nms), False, 0) - cb.SetCurVal(enm.name) - -def SetEnumCB(recv, send, sig, data): - vw = gi.ComboBox(handle=send) - nm = vw.Name() - nms = nm.split(':') - idx = vw.CurIndex - cv = classviews[nms[0]] - flds = cv.Class.__dict__ - typ = type(flds[nms[1]]) - vl = typ(idx) - setattr(cv.Class, nms[1], vl) - - diff --git a/python/pyside/pyparams.py b/python/pyside/pyparams.py deleted file mode 100644 index f9e8f9654..000000000 --- a/python/pyside/pyparams.py +++ /dev/null @@ -1,36 +0,0 @@ -# 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. - -from leabra import go, params - -def ApplyParams(cls, sheet, setMsg): - """ - ApplyParams applies params.Sheet to cls - """ - flds = cls.__dict__ - for sl in sheet: - sel = params.Sel(handle=sl) - for nm, val in sel.Params: - flds = nm.split('.')[1:] - tcls = cls - for i, flnm in enumerate(flds): - # print("name: %s, value: %s\n" % (flnm, val)) - if flnm in flds: - cur = getattr(tcls, flnm) - if isinstance(cur, int): - setattr(tcls, flnm, int(val)) - elif isinstance(cur, float): - setattr(tcls, flnm, float(val)) - else: - if i == len(flds)-1: - setattr(tcls, flnm, val) - else: - tcls = cur - continue - if setMsg: - print("Field named: %s set to value: %s\n" % (flnm, val)) - else: - print("ApplyParams error: field: %s not found in class\n" % flnm) - - diff --git a/python/requirements.txt b/python/requirements.txt deleted file mode 100644 index 1133ac0e9..000000000 --- a/python/requirements.txt +++ /dev/null @@ -1,7 +0,0 @@ -pybindgen -setuptools -wheel -numpy -pandas -torch - diff --git a/python/setup.py b/python/setup.py deleted file mode 100644 index d9a5c0d3b..000000000 --- a/python/setup.py +++ /dev/null @@ -1,22 +0,0 @@ -import setuptools - -with open("README.md", "r") as fh: - long_description = fh.read() - -setuptools.setup( - name="leabra", - version="1.1.15", - author="emergent", - author_email="oreilly@ucdavis.edu", - description="Python interface to emergent neural network simulation system, in Go", - long_description=long_description, - long_description_content_type="text/markdown", - url="https://github.com/go-python/gopy", - packages=setuptools.find_packages(), - classifiers=[ - "Programming Language :: Python :: 3", - "License :: OSI Approved :: BSD License", - "Operating System :: OS Independent", - ], - include_package_data=True, -)