-
Notifications
You must be signed in to change notification settings - Fork 24
BrainStatesandLifeTimes
Brains can record their own states. Recording can be switched on an off with:
[brain]->setRecordActivity(true) // on
[brain]->setRecordActivity(false) // off
Brains record three continuous value time series (InputStates, OutputStates, HiddenStates) and lifeTimes(a list with the length of each lifetime). It is up to the brain developer to determine what data should go into each time series. Generally, Input and Output should be the input and output that the brain receives and delivers - and these can in theory be extracted directly using setInput() and readOutput() functions (although these are probably less efficient than other methods available from inside the brain. What data needs to appear in HiddenStates must be determined by the developer and will depend on the design of the brain. For Markov brains will deterministic state, HiddenStates are simply the hidden nodes, but for brains with stateful subcomponents, a proper recording of hidden states may require reading from individual components (such as neuron gates in a Markov Brain).
In addition, brains record lifeTimes. This is just a list with the number of updates between each brain reset. So if a brain existed in a world that had 4 possible initial states and which ran for 20 updates, the lifeTimes would be {20,20,20,20}. lifeTimes is a list so that we can handle cases where worlds don't always evaluate for the same number of updates (e.g. a world that stops evaluation when the agent provides a solution).
Brain states are recorded into TS::timeSeries (which are actually vector<vector>). You can read and write to them as any other vector. As a brain developer, you are responsible for loading data into these vectors, which can happen as part of [brain]->update();
TS::TimeSeries InputStates;
TS::TimeSeries OutputStates;
TS::TimeSeries HiddenStates;
Life times are recorded in a vector. This is initialized to 1 element with value 0 on creation to indicate that the brain has experienced one life time of duration 0.
std::vector<int> lifeTimes = { 0 }; // a vector of the durration of each lifetime
Every update you must increment lifeTimes.back(). This should probably happen in the [brain]->update() function.
lifeTimes.back()++
Every time [brain]->reset() is called, lifeTimes should have a new empty lifeTime appended. This is the default behavior in AbstractBrain. But if you override [brain]->reset() make sure that you add the following code to your version:
if (recordActivity) {
if (lifeTimes.back() != 0) {
lifeTimes.push_back(0);
}
}
Hidden nodes are recurrent. Sometimes Output is also recurrent. If we think about Input data, this is set before [brain]->update() is called and does not change, so for a given update, there is one input state. For non-recurrent Output there is also only one output state per call to [brain]->update(). but for recurrent nodes (hidden and recurrent output) for each [brain]->update() there are two states (before and after). This does not mean that there will be 2 times as many hidden states as input states because each "after" recurrent state on a given update is the "before" recurrent state on the next update. So there only needs to be one extra entry in recurrent state recordings versus non-recurrent state recordings.
As a brain developer, it is up to you to manage this process. it is suggested that on each [brain]->update() before the hidden (and input if recurrent) are altered and (if lifeTimes.back() == 0) that the recurrent state be recoded to it's respective state vector. This will result in recurrent state recordings being oversized or "bloated", but not to worry the time series and information tools are aware of bloated time series.
A special variable (bool recurrentOutput) is provided to establish if the output is recurrent (i.e. if the output from the prior update is provided to the brain on the current update - like hidden). This variable is false by default but should be set to true (in the constructor) if the output is recurrent. See the note above on recurrence regarding recording recurrent states and bloated time series.
You may be worried that the state information is being saved as double. This allows us to support brains with continuous value internal states. Functions can be found in Analyze/timeSeries.h to convert continuous value time series to discreet value time series. Information on TimeSeries discretization can be found in TimeSeries.
TS::TimeSeries getInputStates() {
return InputStates;
}
TS::TimeSeries getOutputStates() {
return OutputStates;
}
TS::TimeSeries getHiddenStates() {
return HiddenStates;
}
std::vector<int> getLifeTimes() {
return lifeTimes;
}
void resetStatesAndLifetimes() {
InputStates.clear();
OutputStates.clear();
HiddenStates.clear();
lifeTimes = { 0 };
}
home
welcome
MABE Parameter Widget
Installation and quick start
license
citations
release notes
developer contributions
consistency testing
Using MABE
Using Settings Files
Output Files
Creating Graphs with python
MABE framework
Defining Update
Brains
Markov Brain
Neuron Gate
Wire Brain
Human Brain
ConstantValues Brain
CGP Brain
Genetic Programing Brain
Artificial Neural Networks
Brains Structure and Connectome
Genomes
Circular Genome
Multi Genome
Genome Handlers
Genome Value Conversions
Organisms
Groups
Archivists
popFileColumns
Optimizers
Lexicase Optimizer
Worlds
Berry World
ComplexiPhi World
MultiThreadTemplate World
Utilities
DataMap
Parameters
Parameters Name Space
Adding Parameters to Code
ParametersTable
MTree
sequence function
Population Loading
PythonTools
MBuild
MGraph
MQ
findRelatedness
generatePhylogeny
Information Theory Tools
Brain States and Life Times
TimeSeries
Entropy Functions
Smearing
Fragmentation
State to State
Brain Infomation Tools
ProcessingTools