looper

package
v2.0.0-dev0.0.14 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 15, 2024 License: BSD-3-Clause Imports: 8 Imported by: 17

README

Looper: A flexible steppable control hierarchy

Docs: GoDoc

Looper implements a fully generic looping control system with extensible functionality at each level of the loop, with logic that supports reentrant stepping so each time it is Run it advances at any specified step size, with results that are identical to running.

Each loop implements the following logic:

OnStart()  // run at start of loop
do {
    Main() // run in loop
    <run subloops>
} while !IsDone() // test for completion
OnEnd()    // run after loop is done

The Loop object has the above function lists where function closures can be added to perform any relevant functionality.

Each level of loop holds a corresponding counter value, and the looper automatically increments and uses these counters to stop looping at a given level. Each Stack of loops is associated with a given etime.Mode, e.g., etime.Train or etime.Test.

Algorithm and Sim Integration

Specific algorithms use AddLevels to add inner, lower levels of loops to implement specific algorithm code (typically Phase and Cycle). Leabra and Axon use the Time struct as a context for holding the relevant counters and mode, which is then accessed directly in the callback functions as needed.

In cases where something must be done prior to looping through cycles (e.g., ApplyInputs and new phase startup methods), trigger it on the first cycle, before calling other functions, using a provided AddCycle0 function.

Concrete Example of Looping Logic

The stack_test.go can generate a trace the looping -- edit the if false to true to see.

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	// If you want to debug the flow of time, set this to true.
	PrintControlFlow = false

	// If PrintControlFlow = true, this cuts off printing at timescales
	// that are faster than this -- default is to print all.
	NoPrintBelow = etime.AllTimes
)

Functions

This section is empty.

Types

type Ctr

type Ctr struct {

	// current counter value
	Cur int

	// maximum counter value -- only used if > 0
	Max int

	// increment per iteration
	Inc int
}

Ctr combines an integer with a maximum value. It supports time tracking within looper.

func (*Ctr) Incr

func (ct *Ctr) Incr()

Incr increments the counter by 1. Does not interact with Max.

func (*Ctr) IsOverMax

func (ct *Ctr) IsOverMax() bool

IsOverMax returns true if counter is at or over Max (only if Max > 0)

func (*Ctr) Set

func (ct *Ctr) Set(cur int) bool

Set sets the Cur value with return value indicating whether it is different from current Cur.

func (*Ctr) SetCurMax

func (ct *Ctr) SetCurMax(cur, max int)

SetCurMax sets the Cur and Max values, as a convenience.

func (*Ctr) SetCurMaxPlusN

func (ct *Ctr) SetCurMaxPlusN(cur, n int)

SetCurMaxPlusN sets the Cur value and Max as Cur + N -- run N more beyond current.

func (*Ctr) SkipToMax

func (ct *Ctr) SkipToMax()

SkipToMax sets the counter to its Max value -- for skipping over rest of loop

type Event

type Event struct {

	// Might be 'plus' or 'minus' for example.
	Name string

	// The counter value upon which this Event occurs.
	AtCtr int

	// Callback function for the Event.
	OnEvent NamedFuncs
}

A Event has function(s) that can be called at a particular point in the loop, when the counter is AtCtr value.

func NewEvent

func NewEvent(name string, atCtr int, fun func()) *Event

NewEvent returns a new event with given name, function, at given counter

func (*Event) String

func (event *Event) String() string

String describes the Event in human readable text.

type Loop

type Loop struct {

	// Tracks time within the loop. Also tracks the maximum. OnStart, Main, and OnEnd will be called Ctr.Max times, or until IsDone is satisfied, whichever ends first.
	Counter Ctr

	// OnStart is called at the beginning of each loop.
	OnStart NamedFuncs

	// OnStart is called in the middle of each loop. In general, only use Main for the last Loop in a Stack. For example, actual Net updates might occur here.
	Main NamedFuncs

	// OnStart is called at the end of each loop.
	OnEnd NamedFuncs

	// If true, end loop. Maintained as an unordered map because they should not have side effects.
	IsDone NamedFuncsBool

	// Events occur when Ctr.Cur gets to their AtCtr.
	Events []*Event
}

Loop contains one level of a multi-level iteration scheme. It wraps around an inner loop recorded in a Stack, or around Main functions. It records how many times the loop should be repeated in the Counter. It records what happens at the beginning and end of each loop. For example, a loop with 1 start, 1 end, and a Counter with max=3 will do: Start, Inner, End, Start, Inner, End, Start, Inner, End Where the Inner loop is specified by a Stack or by Main, and Start and End are functions on the loop. See Stack for more details on how loops are combined.

func (*Loop) AddEvents

func (lp *Loop) AddEvents(events ...*Event)

AddEvents to the list of events.

func (*Loop) AddNewEvent

func (lp *Loop) AddNewEvent(name string, atCtr int, fun func()) *Event

AddNewEvent to the list.

func (*Loop) EventByName

func (lp *Loop) EventByName(name string) (*Event, bool)

EventByName returns event by name, false if not found

func (*Loop) SkipToMax

func (lp *Loop) SkipToMax()

SkipToMax sets the counter to its Max value for this level. for skipping over rest of loop

type Manager

type Manager struct {

	// map of stacks by Mode
	Stacks map[etime.Modes]*Stack

	// The current evaluation mode.
	Mode etime.Modes
	// contains filtered or unexported fields
}

Manager holds data relating to multiple stacks of loops, as well as the logic for stepping through it. It also holds helper methods for constructing the data. It's also a control object for stepping through Stacks of Loops. It holds data about how the flow is going.

func NewManager

func NewManager() *Manager

NewManager returns a new initialized manager

func (*Manager) AddEventAllModes

func (man *Manager) AddEventAllModes(t etime.Times, event ...*Event)

AddEventAllModes adds Event(s) to all stacks at given time

func (*Manager) AddMainToAll

func (man *Manager) AddMainToAll(name string, fun func(mode etime.Modes, time etime.Times))

AddMainToAll adds given function taking mode and time args to Main in all stacks, loops

func (*Manager) AddOnEndToAll

func (man *Manager) AddOnEndToAll(name string, fun func(mode etime.Modes, time etime.Times))

AddOnEndToAll adds given function taking mode and time args to OnEnd in all stacks, loops

func (*Manager) AddOnStartToAll

func (man *Manager) AddOnStartToAll(name string, fun func(mode etime.Modes, time etime.Times))

AddOnStartToAll adds given function taking mode and time args to OnStart in all stacks, loops

func (*Manager) AddStack

func (man *Manager) AddStack(mode etime.Modes) *Stack

AddStack adds a new Stack for given mode

func (*Manager) ClearStep

func (man *Manager) ClearStep(mode etime.Modes)

ClearStep clears stepping variables from given mode, so it will run to completion in a subsequent Cont(). Called by Run

func (*Manager) Cont

func (man *Manager) Cont()

Cont continues running based on current state of the manager. This is common pathway for Step and Run, which set state and call Cont. Programatic calling of Step can continue with Cont.

func (*Manager) DocString

func (man *Manager) DocString() string

DocString returns an indented summary of the loops and functions in the stack.

func (*Manager) GetLoop

func (man *Manager) GetLoop(modes etime.Modes, times etime.Times) *Loop

GetLoop returns the Loop associated with an evaluation mode and timescale.

func (*Manager) Init

func (man *Manager) Init()

Init initializes the state of the manager, to be called on a newly created object.

func (*Manager) IsRunning

func (man *Manager) IsRunning() bool

IsRunning is True if running.

func (*Manager) ModeStack

func (man *Manager) ModeStack() *Stack

ModeStack returns the Stack for the current Mode

func (*Manager) ResetAndRun

func (man *Manager) ResetAndRun(mode etime.Modes)

ResetAndRun calls ResetCountersByMode on this mode and then Run. This ensures that the Stack is run from the start, regardless of what state it might have been in.

func (*Manager) ResetCounters

func (man *Manager) ResetCounters()

ResetCounters resets the Cur on all loop Counters, and resets the Manager's place in the loops.

func (*Manager) ResetCountersBelow

func (man *Manager) ResetCountersBelow(mode etime.Modes, time etime.Times)

ResetCountersBelow resets the Cur on all loop Counters below given level (inclusive), and resets the Manager's place in the loops.

func (*Manager) ResetCountersByMode

func (man *Manager) ResetCountersByMode(mode etime.Modes)

ResetCountersByMode resets counters for given mode.

func (*Manager) Run

func (man *Manager) Run(mode etime.Modes)

Run runs the stack of loops for given mode (Train, Test, etc). This resets any stepping settings for this stack and runs until completion or stopped externally.

func (*Manager) Step

func (man *Manager) Step(mode etime.Modes, numSteps int, stopscale etime.Times)

Step numSteps stopscales. Use this if you want to do exactly one trial or two epochs or 50 cycles or whatever

func (*Manager) Stop

func (man *Manager) Stop(level etime.Times)

Stop stops currently running stack of loops at given run time level

type NamedFunc

type NamedFunc struct {
	Name string
	Func func()
}

NamedFunc lets you keep an ordered map of functions.

type NamedFuncs

type NamedFuncs []NamedFunc

NamedFunc is an ordered map of functions.

func (*NamedFuncs) Add

func (funcs *NamedFuncs) Add(name string, fun func()) *NamedFuncs

Add adds a named function to a list.

func (*NamedFuncs) Delete

func (funcs *NamedFuncs) Delete(nm string) error

Delete deletes function of given name

func (*NamedFuncs) FindName

func (funcs *NamedFuncs) FindName(nm string) (int, error)

FindName finds index of function by name, returns not found err message if not found

func (*NamedFuncs) HasNameLike

func (funcs *NamedFuncs) HasNameLike(nameSubstring string) bool

HasNameLike checks if there's an existing function that contains a substring. This could be helpful to ensure that you don't add duplicate logic to a list of functions. If you plan on using this, add a comment documenting which name is important, because the default assumption is that names are just documentation.

func (*NamedFuncs) InsertAfter

func (funcs *NamedFuncs) InsertAfter(after, nm string, f func()) error

InsertAfter inserts function after other function of given name

func (*NamedFuncs) InsertAt

func (funcs *NamedFuncs) InsertAt(i int, nm string, f func())

InsertAt inserts function at given index

func (*NamedFuncs) InsertBefore

func (funcs *NamedFuncs) InsertBefore(before, nm string, f func()) error

InsertBefore inserts function before other function of given name

func (*NamedFuncs) Prepend

func (funcs *NamedFuncs) Prepend(nm string, f func())

Prepend adds a function to the start of the list

func (*NamedFuncs) Replace

func (funcs *NamedFuncs) Replace(nm string, f func()) error

Replace replaces function with other function of given name

func (*NamedFuncs) String

func (funcs *NamedFuncs) String() string

String describes named functions.

type NamedFuncsBool

type NamedFuncsBool map[string]func() bool

NamedFuncsBool is like NamedFuncs, but for functions that return a bool.

func (*NamedFuncsBool) Add

func (funcs *NamedFuncsBool) Add(name string, f func() bool)

Add adds a function by name.

type Stack

type Stack struct {

	// evaluation mode for this stack
	Mode etime.Modes

	// An ordered map of Loops, from the outer loop at the start to the inner loop at the end.
	Loops map[etime.Times]*Loop

	// The list and order of time scales looped over by this stack of loops,  ordered from top to bottom, so longer timescales like Run should be at the beginning and shorter timescales like Trial should be and the end.
	Order []etime.Times

	// If true, stop model at the end of the current StopLevel.
	StopNext bool

	// If true, stop model ASAP.
	StopFlag bool

	// Time level to stop at the end of.
	StopLevel etime.Times

	// How many iterations at StopLevel before actually stopping.
	StopIterations int

	// Saved Time level for stepping -- what was set for last step or by gui.
	StepLevel etime.Times

	// Saved number of steps for stepping -- what was set for last step or by gui.
	StepIterations int
}

Stack contains a list of Loops Ordered from top to bottom. For example, a Stack might be created like this:

mystack := manager.AddStack(etime.Train).AddTime(etime.Run, 2).AddTime(etime.Trial, 3)
myStack.Loops[etime.Run].OnStart.Add("NewRun", initRunFunc)
myStack.Loops[etime.Trial].OnStart.Add("PresentTrial", trialFunc)

When run, myStack will behave like this: initRunFunc, trialFunc, trialFunc, trialFunc, initRunFunc, trialFunc, trialFunc, trialFunc

func (*Stack) AddMainToAll

func (stack *Stack) AddMainToAll(name string, fun func(mode etime.Modes, time etime.Times))

AddMainToAll adds given function taking mode and time args to Main in all loops

func (*Stack) AddOnEndToAll

func (stack *Stack) AddOnEndToAll(name string, fun func(mode etime.Modes, time etime.Times))

AddOnEndToAll adds given function taking mode and time args to OnEnd in all loops

func (*Stack) AddOnStartToAll

func (stack *Stack) AddOnStartToAll(name string, fun func(mode etime.Modes, time etime.Times))

AddOnStartToAll adds given function taking mode and time args to OnStart in all loops

func (*Stack) AddTime

func (stack *Stack) AddTime(time etime.Times, ctrMax int) *Stack

AddTime adds a new timescale to this Stack with a given ctrMax number of iterations. The order in which this method is invoked is important, as it adds loops in order from top to bottom. Sets a default increment of 1 for the counter -- see AddTimeIncr for different increment.

func (*Stack) AddTimeIncr

func (stack *Stack) AddTimeIncr(time etime.Times, ctrMax, ctrIncr int) *Stack

AddTimeIncr adds a new timescale to this Stack with a given ctrMax number of iterations, and increment per step. The order in which this method is invoked is important, as it adds loops in order from top to bottom.

func (*Stack) ClearStep

func (stack *Stack) ClearStep()

ClearStep clears stepping control state

func (*Stack) CtrsToStats

func (stack *Stack) CtrsToStats(stats *estats.Stats)

CtrsToStats sets the current counter values to estats Int values by their time names only (no eval Mode). These values can then be read by elog LogItems to record the counters in logs. Typically, a TrialName string is also expected to be set, to describe the current trial (Step) contents in a useful way, and other relevant info (e.g., group / category info) can also be set.

func (*Stack) Init

func (stack *Stack) Init(mode etime.Modes)

Init initializes new data structures for a newly created object

func (*Stack) SetStep

func (stack *Stack) SetStep(numSteps int, stopscale etime.Times)

SetStep sets stepping to given level and iterations

func (*Stack) TimeAbove

func (stack *Stack) TimeAbove(time etime.Times) etime.Times

TimeAbove returns the time above the given time in the stack returning etime.NoTime if this is the highest level, or given time does not exist in order.

func (*Stack) TimeBelow

func (stack *Stack) TimeBelow(time etime.Times) etime.Times

TimeBelow returns the time below the given time in the stack returning etime.NoTime if this is the lowest level, or given time does not exist in order.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL