Empirical
AvidaHardware.h
Go to the documentation of this file.
1 
15 #ifndef EMP_AVIDA_HARDWARE_H
16 #define EMP_AVIDA_HARDWARE_H
17 
18 #include <fstream>
19 #include <iostream>
20 #include <map>
21 
22 #include "../base/array.h"
23 #include "../base/Ptr.h"
24 #include "../base/vector.h"
25 #include "../tools/map_utils.h"
26 #include "../tools/Random.h"
27 #include "../tools/string_utils.h"
28 
29 namespace emp {
30 
33 
34  template <size_t CPU_SIZE=16>
35  class AvidaHardware {
36  public:
39 
42  enum class ScopeType { NONE=0, ROOT, BASIC, LOOP, FUNCTION };
43 
45  struct ScopeInfo {
46  size_t scope;
48  size_t start_pos;
49 
50  ScopeInfo() : scope(0), type(ScopeType::BASIC), start_pos(0) { ; }
51  ScopeInfo(size_t _s, ScopeType _t, size_t _p) : scope(_s), type(_t), start_pos(_p) { ; }
52  };
53 
55  struct RegBackup {
56  size_t scope;
57  size_t reg_id;
58  double value;
59 
60  RegBackup() : scope(0), reg_id(0), value(0.0) { ; }
61  RegBackup(size_t _s, size_t _r, double _v) : scope(_s), reg_id(_r), value(_v) { ; }
62  };
63 
64  // Hardware Components
66  std::unordered_map<int, double> inputs;
67  std::unordered_map<int, double> outputs;
70 
71  size_t inst_ptr;
75 
76  size_t error_count;
77 
80 
81 
82  public:
85  : regs(), inputs(), outputs(), stacks(), fun_starts(), inst_ptr(0)
87  {
88  scope_stack.emplace_back(0, ScopeType::ROOT, 0); // Initial scope.
89  for (size_t i = 0; i < CPU_SIZE; i++) {
90  regs[i] = (double) i;
91  fun_starts[i] = -1;
92  }
93  }
94 
97 
100 
102  virtual ~AvidaHardware<CPU_SIZE>() { ; }
103 
105  void ExitScope() {
106  emp_assert(scope_stack.size() > 1, CurScope());
107  emp_assert(scope_stack.size() <= CPU_SIZE, CurScope());
108 
109  // Restore any backed-up registers from this scope...
110  while (reg_stack.size() && reg_stack.back().scope == CurScope()) {
111  regs[reg_stack.back().reg_id] = reg_stack.back().value;
112  reg_stack.pop_back();
113  }
114 
115  // Remove the inner-most scope.
116  scope_stack.pop_back();
117  }
118 
120  virtual void Reset() {
121  // Initialize registers to their posision. So Reg0 = 0 and Reg11 = 11.
122  for (size_t i = 0; i < CPU_SIZE; i++) {
123  regs[i] = (double) i;
124  inputs.clear();
125  outputs.clear();
126  stacks[i].resize(0);
127  fun_starts[i] = -1;
128  }
129  inst_ptr = 0; // Move IP back to beginning
130  scope_stack.resize(1); // Reset to outermost scope.
131  reg_stack.resize(0); // Clear saved registers.
132  call_stack.resize(0); // Clear call history.
133  error_count = 0; // Clear all errors.
134  traits.resize(0); // Clear out traits
135  }
136 
138  void ResetIP() {
139  inst_ptr = 0;
140  while (scope_stack.size() > 1) ExitScope(); // Forcibly exit all scopes except root.
141  // Restore all remaining backed-up registers (likely backed up in outer-most scope).
142  while (reg_stack.size()) {
143  regs[reg_stack.back().reg_id] = reg_stack.back().value;
144  reg_stack.pop_back();
145  }
146  call_stack.resize(0);
147  }
148 
149  // Accessors
150  double GetReg(size_t id) const { return regs[id]; }
151  double GetInput(int id) const { return Find(inputs, id, 0.0); }
152  const std::unordered_map<int,double> & GetInputs() const { return inputs; }
153  size_t GetNumInputs() const { return inputs.size(); }
154  double GetOutput(int id) const { return Find(outputs, id, 0.0); }
155  const std::unordered_map<int,double> & GetOutputs() const { return outputs; }
156  size_t GetNumOutputs() const { return outputs.size(); }
157  const stack_t & GetStack(size_t id) const { return stacks[id]; }
158  int GetFunStart(size_t id) const { return fun_starts[id]; }
159  size_t GetIP() const { return inst_ptr; }
161  size_t CurScope() const { return scope_stack.back().scope; }
162  ScopeType CurScopeType() const { return scope_stack.back().type; }
165  size_t GetNumErrors() const { return error_count; }
166  double GetTrait(size_t id) const { return traits[id]; }
167  const emp::vector<double> & GetTraits() { return traits; }
168  size_t GetNumTraits() const { return traits.size(); }
169 
170  void SetReg(size_t id, double val) { regs[id] = val; }
171  void SetInput(int input_id, double value) { inputs[input_id] = value; }
172  void SetInputs(const std::unordered_map<int,double> & vals) { inputs = vals; }
173  void SetInputs(std::unordered_map<int,double> && vals) { inputs = std::move(vals); }
174  void SetOutput(int output_id, double value) { outputs[output_id] = value; }
175  void SetOutputs(const std::unordered_map<int,double> & vals) { outputs = vals; }
176  void SetOutputs(std::unordered_map<int,double> && vals) { outputs = std::move(vals); }
177  double PopStack(size_t id) {
178  if (stacks[id].size() == 0) return 0.0;
179  double out = stacks[id].back();
180  stacks[id].pop_back();
181  return out;
182  }
183  void PushStack(size_t id, double value) {
184  if (stacks[id].size() >= CPU_SIZE) return;
185  stacks[id].push_back(value);
186  }
187  void SetFunStart(size_t id, int value) { fun_starts[id] = value; }
188  void SetIP(size_t pos) { inst_ptr = pos; }
189  void PushRegInfo(size_t scope_id, size_t reg_id) {
190  reg_stack.emplace_back(scope_id, reg_id, regs[reg_id]);
191  }
192  void PushCallInfo(size_t pos) { call_stack.push_back(pos); }
193  void IncErrors() { error_count++; }
194  void SetTrait(size_t id, double val) {
195  if (id >= traits.size()) traits.resize(id+1, 0.0);
196  traits[id] = val;
197  }
198  void PushTrait(double val) { traits.push_back(val); }
199 
201  void PrintState(std::ostream & os=std::cout) const;
202 
203 
204  // Instruction helpers.
205  void IncReg(size_t reg_id) { ++regs[reg_id]; }
206  void DecReg(size_t reg_id) { --regs[reg_id]; }
207  void NotReg(size_t reg_id) { regs[reg_id] = (regs[reg_id] == 0.0); }
208  void AddRegs(size_t reg0_id, size_t reg1_id, size_t reg2_id) {
209  regs[reg2_id] = regs[reg0_id] + regs[reg1_id];
210  }
211  void SubRegs(size_t reg0_id, size_t reg1_id, size_t reg2_id) {
212  regs[reg2_id] = regs[reg0_id] - regs[reg1_id];
213  }
214  void MultRegs(size_t reg0_id, size_t reg1_id, size_t reg2_id) {
215  regs[reg2_id] = regs[reg0_id] * regs[reg1_id];
216  }
217  void DivRegs(size_t reg0_id, size_t reg1_id, size_t reg2_id) {
218  const double denom = regs[reg1_id];
219  if (denom == 0.0) ++error_count;
220  else regs[reg2_id] = regs[reg0_id] / denom;
221  }
222  void ModRegs(size_t reg0_id, size_t reg1_id, size_t reg2_id) {
223  const double base = regs[reg1_id];
224  if (base == 0.0) ++error_count;
225  else regs[reg2_id] = regs[reg0_id] / base;
226  }
227 
228  void RegTestEqu(size_t reg0_id, size_t reg1_id, size_t reg2_id) {
229  regs[reg2_id] = (regs[reg0_id] == regs[reg1_id]);
230  }
231  void RegTestNEqu(size_t reg0_id, size_t reg1_id, size_t reg2_id) {
232  regs[reg2_id] = (regs[reg0_id] != regs[reg1_id]);
233  }
234  void RegTestLess(size_t reg0_id, size_t reg1_id, size_t reg2_id) {
235  regs[reg2_id] = (regs[reg0_id] < regs[reg1_id]);
236  }
237 
238  };
239 
240 }
241 
242 
243 #endif
double PopStack(size_t id)
Definition: AvidaHardware.h:177
void SetIP(size_t pos)
Definition: AvidaHardware.h:188
std::unordered_map< int, double > inputs
Map of all available inputs (position -> value)
Definition: AvidaHardware.h:66
virtual void Reset()
Definition: AvidaHardware.h:120
void SetOutput(int output_id, double value)
Definition: AvidaHardware.h:174
double GetInput(int id) const
Definition: AvidaHardware.h:151
void SetReg(size_t id, double val)
Definition: AvidaHardware.h:170
size_t GetIP() const
Definition: AvidaHardware.h:159
size_t start_pos
Where in the code did this scope start?
Definition: AvidaHardware.h:48
As different scopes are stepped through, this class provides information about each one...
Definition: AvidaHardware.h:45
void RegTestEqu(size_t reg0_id, size_t reg1_id, size_t reg2_id)
Definition: AvidaHardware.h:228
void ResetIP()
Reset the instruction pointer to the beginning of the genome AND reset scope.
Definition: AvidaHardware.h:138
void SetInputs(const std::unordered_map< int, double > &vals)
Definition: AvidaHardware.h:172
void SetTrait(size_t id, double val)
Definition: AvidaHardware.h:194
void SetFunStart(size_t id, int value)
Definition: AvidaHardware.h:187
size_t scope
What is the depth of this scope?
Definition: AvidaHardware.h:46
size_t GetNumInputs() const
Definition: AvidaHardware.h:153
const emp::vector< double > & GetTraits()
Definition: AvidaHardware.h:167
emp::vector< RegBackup > reg_stack
What registers have been backed up?
Definition: AvidaHardware.h:73
void DecReg(size_t reg_id)
Definition: AvidaHardware.h:206
void MultRegs(size_t reg0_id, size_t reg1_id, size_t reg2_id)
Definition: AvidaHardware.h:214
void AddRegs(size_t reg0_id, size_t reg1_id, size_t reg2_id)
Definition: AvidaHardware.h:208
void push_back(PB_Ts &&...args)
Definition: vector.h:189
void SubRegs(size_t reg0_id, size_t reg1_id, size_t reg2_id)
Definition: AvidaHardware.h:211
std::unordered_map< int, double > outputs
Map of all outputs (position -> value)
Definition: AvidaHardware.h:67
emp::vector< size_t > GetCallStack() const
Definition: AvidaHardware.h:164
size_t size() const
Definition: vector.h:151
emp::vector< ScopeInfo > scope_stack
What scopes are we nested in?
Definition: AvidaHardware.h:72
double value
What value is being backed up?
Definition: AvidaHardware.h:58
void RegTestNEqu(size_t reg0_id, size_t reg1_id, size_t reg2_id)
Definition: AvidaHardware.h:231
void emplace_back(ARGS &&...args)
Definition: vector.h:219
double GetTrait(size_t id) const
Definition: AvidaHardware.h:166
void push_back(PB_Ts &&...args)
Definition: array.h:169
Definition: AvidaHardware.h:35
const stack_t & GetStack(size_t id) const
Definition: AvidaHardware.h:157
auto Find(const MAP_T &in_map, const KEY_T &key, const typename MAP_T::mapped_type &dval)
Definition: map_utils.h:29
size_t reg_id
Which register is this?
Definition: AvidaHardware.h:57
ScopeType type
What type is this scope? (ROOT, BASIC, LOOP, or FUNCTION)
Definition: AvidaHardware.h:47
size_t inst_ptr
Which code position should be executed next?
Definition: AvidaHardware.h:71
size_t GetNumOutputs() const
Definition: AvidaHardware.h:156
T & back()
Definition: array.h:156
emp::vector< ScopeInfo > GetScopeStack() const
Definition: AvidaHardware.h:160
void pop_back()
Definition: vector.h:194
void resize(size_t new_size)
Definition: array.h:165
double GetReg(size_t id) const
Definition: AvidaHardware.h:150
emp::array< stack_t, CPU_SIZE > stacks
Stacks for long-term storage.
Definition: AvidaHardware.h:68
ScopeType CurScopeType() const
Definition: AvidaHardware.h:162
void PushCallInfo(size_t pos)
Definition: AvidaHardware.h:192
void ModRegs(size_t reg0_id, size_t reg1_id, size_t reg2_id)
Definition: AvidaHardware.h:222
RegBackup()
Definition: AvidaHardware.h:60
size_t error_count
How many errors have occurred?
Definition: AvidaHardware.h:76
void PushRegInfo(size_t scope_id, size_t reg_id)
Definition: AvidaHardware.h:189
void PushTrait(double val)
Definition: AvidaHardware.h:198
emp::array< int, CPU_SIZE > fun_starts
Postions where functions being in genome.
Definition: AvidaHardware.h:69
void NotReg(size_t reg_id)
Definition: AvidaHardware.h:207
void resize(size_t new_size)
Definition: vector.h:161
void ExitScope()
Run every time we need to exit the current scope.
Definition: AvidaHardware.h:105
void SetOutputs(std::unordered_map< int, double > &&vals)
Definition: AvidaHardware.h:176
void SetInput(int input_id, double value)
Definition: AvidaHardware.h:171
size_t CurScope() const
Definition: AvidaHardware.h:161
size_t GetNumErrors() const
Definition: AvidaHardware.h:165
ScopeType
Definition: AvidaHardware.h:42
If we are in emscripten, make sure to include the header.
Definition: array.h:37
void SetOutputs(const std::unordered_map< int, double > &vals)
Definition: AvidaHardware.h:175
void IncErrors()
Definition: AvidaHardware.h:193
const std::unordered_map< int, double > & GetInputs() const
Definition: AvidaHardware.h:152
void DivRegs(size_t reg0_id, size_t reg1_id, size_t reg2_id)
Definition: AvidaHardware.h:217
#define emp_assert(...)
Definition: assert.h:199
T & back()
Definition: vector.h:183
emp::vector< RegBackup > GetRegStack() const
Definition: AvidaHardware.h:163
emp::vector< double > traits
A simple way of recording which traits a CPU has demonstrated, and at what qaulity.
Definition: AvidaHardware.h:79
void IncReg(size_t reg_id)
Definition: AvidaHardware.h:205
size_t scope
What scope should this register be restored in?
Definition: AvidaHardware.h:56
RegBackup(size_t _s, size_t _r, double _v)
Definition: AvidaHardware.h:61
emp::array< double, CPU_SIZE > regs
Registers used in the hardware.
Definition: AvidaHardware.h:65
void SetInputs(std::unordered_map< int, double > &&vals)
Definition: AvidaHardware.h:173
void PrintState(std::ostream &os=std::cout) const
Print out the state of the virtual CPU.
void pop_back()
Definition: array.h:170
size_t GetNumTraits() const
Definition: AvidaHardware.h:168
int GetFunStart(size_t id) const
Definition: AvidaHardware.h:158
const std::unordered_map< int, double > & GetOutputs() const
Definition: AvidaHardware.h:155
void PushStack(size_t id, double value)
Definition: AvidaHardware.h:183
ScopeInfo(size_t _s, ScopeType _t, size_t _p)
Definition: AvidaHardware.h:51
emp::vector< size_t > call_stack
What function calls have to be returned from?
Definition: AvidaHardware.h:74
double GetOutput(int id) const
Definition: AvidaHardware.h:154
void RegTestLess(size_t reg0_id, size_t reg1_id, size_t reg2_id)
Definition: AvidaHardware.h:234
Information about a register that is backed up, to be restored when current scope is exited...
Definition: AvidaHardware.h:55
ScopeInfo()
Definition: AvidaHardware.h:50