Empirical
AvidaGP.h
Go to the documentation of this file.
1 
19 #ifndef EMP_AVIDA_GP_H
20 #define EMP_AVIDA_GP_H
21 
22 #include <fstream>
23 #include <iostream>
24 #include <map>
25 
26 #include "../base/array.h"
27 #include "../base/Ptr.h"
28 #include "../base/vector.h"
29 #include "../tools/File.h"
30 #include "../tools/map_utils.h"
31 #include "../tools/Random.h"
32 #include "../tools/string_utils.h"
33 
34 #include "AvidaCPU_InstLib.h"
35 
36 namespace emp {
37 
38  template <typename HARDWARE>
39  class AvidaCPU_Base {
40  public:
41  static constexpr size_t CPU_SIZE = 16; // Num arg values (for regs, stacks, functions, etc)
42  static constexpr size_t INST_ARGS = 3; // Max num args per instruction.
43  static constexpr size_t STACK_CAP = 16; // Max size for stacks.
44 
45  struct Instruction;
46  struct Genome;
47 
49  using hardware_t = HARDWARE;
51  using genome_t = Genome;
52  using arg_t = size_t; // All arguments are non-negative ints (indecies!)
53 
57 
58  struct Instruction {
59  size_t id;
61 
62  Instruction(size_t _id=0, size_t a0=0, size_t a1=0, size_t a2=0)
63  : id(_id), args() { args[0] = a0; args[1] = a1; args[2] = a2; }
64  Instruction(const Instruction &) = default;
65  Instruction(Instruction &&) = default;
66 
67  Instruction & operator=(const Instruction &) = default;
68  Instruction & operator=(Instruction &&) = default;
69  bool operator<(const Instruction & other) const {
70  return std::tie(id, args) < std::tie(other.id, other.args);
71  }
72 
73  void Set(size_t _id, size_t _a0=0, size_t _a1=0, size_t _a2=0)
74  { id = _id; args[0] = _a0; args[1] = _a1; args[2] = _a2; }
75 
76  bool operator==(const Instruction & in) const { return id == in.id && args == in.args; }
77  };
78 
79  struct Genome {
81 
84 
85  Genome() = default;
86  Genome(Ptr<const inst_lib_t> _inst_lib, const sequence_t & _seq=sequence_t(0))
87  : inst_lib(_inst_lib), sequence(_seq) { ; }
88  Genome(const inst_lib_t & _inst_lib, const sequence_t & _seq=sequence_t(0))
89  : inst_lib(&_inst_lib), sequence(_seq) { ; }
90  Genome(const Genome &) = default;
91  Genome(Genome &&) = default;
92  ~Genome() { ; }
93 
94  size_t Hash() const {
95  std::size_t seed = sequence.size();
96  for(auto& i : sequence) {
97  seed ^= i.id + 0x9e3779b9 + (seed << 6) + (seed >> 2);
98  }
99  return seed;
100  }
101  struct hash_t { size_t operator()(const Genome & g) const { return g.Hash(); } };
102 
103 
104  Genome & operator=(const Genome &) = default;
105  Genome & operator=(Genome &&) = default;
106 
107  bool operator==(const Genome& other) const { return sequence == other.sequence; }
108  bool operator!=(const Genome& other) const { return sequence != other.sequence; }
109  bool operator< (const Genome& other) const { return sequence < other.sequence; }
110  bool operator<=(const Genome& other) const { return sequence <= other.sequence; }
111  bool operator> (const Genome& other) const { return sequence > other.sequence; }
112  bool operator>=(const Genome& other) const { return sequence >= other.sequence; }
113  };
114 
115  struct ScopeInfo {
116  size_t scope;
118  size_t start_pos;
119 
120  ScopeInfo() : scope(0), type(ScopeType::BASIC), start_pos(0) { ; }
121  ScopeInfo(size_t _s, ScopeType _t, size_t _p) : scope(_s), type(_t), start_pos(_p) { ; }
122  };
123 
124  struct RegBackup {
125  size_t scope;
126  size_t reg_id;
127  double value;
128 
129  RegBackup() : scope(0), reg_id(0), value(0.0) { ; }
130  RegBackup(size_t _s, size_t _r, double _v) : scope(_s), reg_id(_r), value(_v) { ; }
131  };
132 
133  // Virtual CPU Components!
135  emp::array<double, CPU_SIZE> regs; // Registers used in the hardware.
136  std::unordered_map<int, double> inputs; // Map of all available inputs (position -> value)
137  std::unordered_map<int, double> outputs; // Map of all outputs (position -> value)
138  emp::array< stack_t, CPU_SIZE > stacks; // Stacks for long-term storage.
139  emp::array< int, CPU_SIZE > fun_starts; // Postions where functions being in genome.
140 
141  size_t inst_ptr;
145 
146  size_t errors;
147 
148  // A simple way of recording which traits a CPU has demonstrated, and at what qaulity.
150 
151  // Run every time we need to exit the current scope.
152  void ExitScope() {
153  emp_assert(scope_stack.size() > 1, CurScope());
154  emp_assert(scope_stack.size() <= CPU_SIZE, CurScope());
155 
156  // Restore any backed-up registers from this scope...
157  while (reg_stack.size() && reg_stack.back().scope == CurScope()) {
158  regs[reg_stack.back().reg_id] = reg_stack.back().value;
159  reg_stack.pop_back();
160  }
161 
162  // Remove the inner-most scope.
163  scope_stack.pop_back();
164  }
165 
166  // This function is run every time scope changed (if, while, scope instructions, etc.)
167  // If we are moving to an outer scope (lower value) we need to close the scope we are in,
168  // potentially continuing with a loop.
169  bool UpdateScope(size_t new_scope, ScopeType type=ScopeType::BASIC) {
170  const size_t cur_scope = CurScope();
171  new_scope++; // Scopes are stored as one higher than regs (Outer is 0)
172  // Test if we are entering a deeper scope.
173  if (new_scope > cur_scope) {
174  scope_stack.emplace_back(new_scope, type, inst_ptr);
175  return true;
176  }
177 
178  // Otherwise we are potentially exiting the current scope. Loop back instead?
179  if (CurScopeType() == ScopeType::LOOP) {
180  inst_ptr = scope_stack.back().start_pos; // Move back to the beginning of the loop.
181  ExitScope(); // Clear former scope
182  ProcessInst( genome.sequence[inst_ptr] ); // Process loops start again.
183  return false; // We did NOT enter the new scope.
184  }
185 
186  // Or are we exiting a function?
188  // @CAO Make sure we exit multiple scopes if needed to close the function...
189  inst_ptr = call_stack.back(); // Return from the function call.
190  if (inst_ptr >= genome.sequence.size()) { // Test if call occured at end of genome.
191  ResetIP(); // ...and reset to the begnning if so.
192  } else {
193  call_stack.pop_back(); // Clear the return position from the call stack.
194  ExitScope(); // Leave the function scope.
195  }
196  ProcessInst( genome.sequence[inst_ptr] ); // Process the new instruction instead.
197  return false; // We did NOT enter the new scope.
198  }
199 
200  // If we made it here, we must simply exit the current scope and test again.
201  ExitScope();
202 
203  return UpdateScope(new_scope, type);
204  }
205 
206  // This function fast-forwards to the end of the specified scope.
207  // NOTE: Bypass scope always drops out of the innermost scope no matter the arg provided.
208  void BypassScope(size_t scope) {
209  scope++; // Scopes are stored as one higher than regs (Outer is 0)
210  if (CurScope() < scope) return; // Only continue if break is relevant for current scope.
211 
212  ExitScope();
213  while (inst_ptr+1 < genome.sequence.size()) {
214  inst_ptr++;
215  const size_t test_scope = InstScope(genome.sequence[inst_ptr]);
216 
217  // If this instruction sets the scope AND it's outside the one we want to end, stop here!
218  if (test_scope && test_scope <= scope) {
219  inst_ptr--;
220  break;
221  }
222  }
223  }
224 
225  public:
227  AvidaCPU_Base(const genome_t & in_genome)
228  : genome(in_genome), regs(), inputs(), outputs(), stacks(), fun_starts()
229  , inst_ptr(0), scope_stack(), reg_stack(), call_stack(), errors(0), traits()
230  {
231  scope_stack.emplace_back(0, ScopeType::ROOT, 0); // Initial scope.
232  for (size_t i = 0; i < CPU_SIZE; i++) {
233  regs[i] = (double) i;
234  fun_starts[i] = -1;
235  }
236  }
237 
239  AvidaCPU_Base() : AvidaCPU_Base(Genome(inst_lib_t::DefaultInstLib())) { ; }
240 
242  AvidaCPU_Base(Ptr<const inst_lib_t> inst_lib) : AvidaCPU_Base(Genome(inst_lib)) { ; }
243  AvidaCPU_Base(const inst_lib_t & inst_lib) : AvidaCPU_Base(Genome(&inst_lib)) { ; }
244 
246  AvidaCPU_Base(const AvidaCPU_Base &) = default;
247 
249  AvidaCPU_Base(AvidaCPU_Base &&) = default;
250 
252  virtual ~AvidaCPU_Base() { ; }
253 
254  bool operator<(const this_t & other) const {
255  return genome < other.genome;
256  }
257 
259  void Reset() {
260  genome.sequence.resize(0); // Clear out genome
261  traits.resize(0); // Clear out traits
262  ResetHardware(); // Reset the full hardware
263  }
264 
266  virtual void ResetHardware() {
267  // Initialize registers to their posision. So Reg0 = 0 and Reg11 = 11.
268  for (size_t i = 0; i < CPU_SIZE; i++) {
269  regs[i] = (double) i;
270  inputs.clear();
271  outputs.clear();
272  stacks[i].resize(0);
273  fun_starts[i] = -1;
274  }
275  inst_ptr = 0; // Move IP back to beginning
276  scope_stack.resize(1); // Reset to outermost scope.
277  reg_stack.resize(0); // Clear saved registers.
278  call_stack.resize(0); // Clear call history.
279  errors = 0; // Clear all errors.
280  }
281 
283  void ResetIP() {
284  inst_ptr = 0;
285  while (scope_stack.size() > 1) ExitScope(); // Forcibly exit all scopes except root.
286  // Restore all remaining backed-up registers (likely backed up in outer-most scope).
287  while (reg_stack.size()) {
288  regs[reg_stack.back().reg_id] = reg_stack.back().value;
289  reg_stack.pop_back();
290  }
291  call_stack.resize(0);
292  }
293 
294  // Accessors
295  Ptr<const inst_lib_t> GetInstLib() const { return genome.inst_lib; }
296  inst_t GetInst(size_t pos) const { return genome.sequence[pos]; }
297  const genome_t & GetGenome() const { return genome; }
298  const size_t GetSize() const { return genome.sequence.size(); }
299  double GetReg(size_t id) const { return regs[id]; }
300  double GetInput(int id) const { return Find(inputs, id, 0.0); }
301  const std::unordered_map<int,double> & GetInputs() const { return inputs; }
302  size_t GetNumInputs() const { return inputs.size(); }
303  double GetOutput(int id) const { return Find(outputs, id, 0.0); }
304  const std::unordered_map<int,double> & GetOutputs() const { return outputs; }
305  size_t GetNumOutputs() const { return outputs.size(); }
306  const stack_t & GetStack(size_t id) const { return stacks[id]; }
307  int GetFunStart(size_t id) const { return fun_starts[id]; }
308  size_t GetIP() const { return inst_ptr; }
310  size_t CurScope() const { return scope_stack.back().scope; }
311  ScopeType CurScopeType() const { return scope_stack.back().type; }
312  ScopeType GetScopeType(size_t id) { return genome.inst_lib->GetScopeType(id); }
315  size_t GetNumErrors() const { return errors; }
316  double GetTrait(size_t id) const { return traits[id]; }
317  const emp::vector<double> & GetTraits() { return traits; }
318  size_t GetNumTraits() const { return traits.size(); }
319 
320  void SetInst(size_t pos, const inst_t & inst) { genome.sequence[pos] = inst; }
321  void SetInst(size_t pos, size_t id, size_t a0=0, size_t a1=0, size_t a2=0) {
322  genome.sequence[pos].Set(id, a0, a1, a2);
323  }
324  void SetGenome(const genome_t & g) { genome = g; }
325  void SetReg(size_t id, double val) { regs[id] = val; }
326  void SetInput(int input_id, double value) { inputs[input_id] = value; }
327  void SetInputs(const std::unordered_map<int,double> & vals) { inputs = vals; }
328  void SetInputs(std::unordered_map<int,double> && vals) { inputs = std::move(vals); }
329  void SetOutput(int output_id, double value) { outputs[output_id] = value; }
330  void SetOutputs(const std::unordered_map<int,double> & vals) { outputs = vals; }
331  void SetOutputs(std::unordered_map<int,double> && vals) { outputs = std::move(vals); }
332  double PopStack(size_t id) {
333  if (stacks[id].size() == 0) return 0.0;
334  double out = stacks[id].back();
335  stacks[id].pop_back();
336  return out;
337  }
338  void PushStack(size_t id, double value) {
339  if (stacks[id].size() >= STACK_CAP) return;
340  stacks[id].push_back(value);
341  }
342  void SetFunStart(size_t id, int value) { fun_starts[id] = value; }
343  void SetIP(size_t pos) { inst_ptr = pos; }
344  void PushRegInfo(size_t scope_id, size_t reg_id) {
345  reg_stack.emplace_back(scope_id, reg_id, regs[reg_id]);
346  }
347  void PushCallInfo(size_t pos) { call_stack.push_back(pos); }
348  void IncErrors() { errors++; }
349  void SetTrait(size_t id, double val) {
350  if (id >= traits.size()) traits.resize(id+1, 0.0);
351  traits[id] = val;
352  }
353  void PushTrait(double val) { traits.push_back(val); }
354 
356  return inst_t(rand.GetUInt(genome.inst_lib->GetSize()),
357  rand.GetUInt(CPU_SIZE), rand.GetUInt(CPU_SIZE), rand.GetUInt(CPU_SIZE));
358  }
359 
360  void RandomizeInst(size_t pos, Random & rand) { SetInst(pos, GetRandomInst(rand) ); }
361 
362  void PushInst(size_t id, size_t a0=0, size_t a1=0, size_t a2=0) {
363  genome.sequence.emplace_back(id, a0, a1, a2);
364  }
365  void PushInst(const std::string & name, size_t a0=0, size_t a1=0, size_t a2=0) {
366  size_t id = genome.inst_lib->GetID(name);
367  genome.sequence.emplace_back(id, a0, a1, a2);
368  }
369  void PushInst(const Instruction & inst) { genome.sequence.emplace_back(inst); }
370  void PushInst(Instruction && inst) { genome.sequence.emplace_back(inst); }
371  void PushInstString(std::string info) {
372  size_t id = genome.inst_lib->GetID( string_pop(info) );
373  size_t arg1 = info.size() ? from_string<size_t>(string_pop(info)) : 0;
374  size_t arg2 = info.size() ? from_string<size_t>(string_pop(info)) : 0;
375  size_t arg3 = info.size() ? from_string<size_t>(string_pop(info)) : 0;
376  PushInst(id, arg1, arg2, arg3);
377  }
378  void PushRandom(Random & rand, const size_t count=1) {
379  for (size_t i = 0; i < count; i++) {
380  PushInst(GetRandomInst(rand));
381  }
382  }
383 
384  // Loading whole genomes.
385  bool Load(std::istream & input);
386  bool Load(const std::string & filename) { std::ifstream is(filename); return Load(is); }
387 
389  void ProcessInst(const inst_t & inst) { genome.inst_lib->ProcessInst(ToPtr(this), inst); }
390 
392  size_t InstScope(const inst_t & inst) const;
393 
395  void SingleProcess() {
396  emp_assert(genome.sequence.size() > 0); // A genome must exist to be processed.
397  if (inst_ptr >= genome.sequence.size()) ResetIP();
398  genome.inst_lib->ProcessInst(ToPtr(this), genome.sequence[inst_ptr]);
399  inst_ptr++;
400  }
401 
403  void Process(size_t num_inst) { for (size_t i = 0; i < num_inst; i++) SingleProcess(); }
404 
406  void PrintInst(const inst_t & inst, std::ostream & os=std::cout) const;
407 
409  void PrintGenome(std::ostream & os=std::cout) const;
410  void PrintGenome(const std::string & filename) const;
411 
413  size_t PredictNextInst() const;
414 
416  void PrintState(std::ostream & os=std::cout) const;
417 
419  void Trace(size_t num_inst, std::ostream & os=std::cout) {
420  for (size_t i = 0; i < num_inst; i++) { PrintState(os); SingleProcess(); }
421  }
422  void Trace(size_t num_inst, const std::string & filename) {
423  std::ofstream of(filename);
424  Trace(num_inst, of);
425  of.close();
426  }
427 
428  };
429 
430  template <typename HARDWARE>
431  bool AvidaCPU_Base<HARDWARE>::Load(std::istream & input) {
432  File file(input);
433  file.RemoveComments("--"); // Remove all comments beginning with -- (including --> and ----)
434  file.CompressWhitespace(); // Trim down remaining whitespace.
435  file.Apply( [this](std::string & info){ PushInstString(info); } );
436  return true;
437  }
438 
439  template <typename HARDWARE>
441  if (genome.inst_lib->GetScopeType(inst.id) == ScopeType::NONE) return 0;
442  return inst.args[ genome.inst_lib->GetScopeArg(inst.id) ] + 1;
443  }
444 
445  template <typename HARDWARE>
446  void AvidaCPU_Base<HARDWARE>::PrintInst(const inst_t & inst, std::ostream & os) const {
447  os << genome.inst_lib->GetName(inst.id);
448  const size_t num_args = genome.inst_lib->GetNumArgs(inst.id);
449  for (size_t i = 0; i < num_args; i++) {
450  os << ' ' << inst.args[i];
451  }
452  }
453 
454  template <typename HARDWARE>
455  void AvidaCPU_Base<HARDWARE>::PrintGenome(std::ostream & os) const {
456  size_t cur_scope = 0;
457 
458  for (const inst_t & inst : genome.sequence) {
459  size_t new_scope = InstScope(inst);
460 
461  if (new_scope) {
462  if (new_scope == cur_scope) {
463  for (size_t i = 0; i < cur_scope; i++) os << ' ';
464  os << "----\n";
465  }
466  if (new_scope < cur_scope) {
467  cur_scope = new_scope-1;
468  }
469  }
470 
471  for (size_t i = 0; i < cur_scope; i++) os << ' ';
472  PrintInst(inst, os);
473  if (new_scope) {
474  if (new_scope > cur_scope) os << " --> ";
475  cur_scope = new_scope;
476  }
477  os << '\n';
478  }
479  }
480 
481  template <typename HARDWARE>
482  void AvidaCPU_Base<HARDWARE>::PrintGenome(const std::string & filename) const {
483  std::ofstream of(filename);
484  PrintGenome(of);
485  of.close();
486  }
487 
488  template <typename HARDWARE>
490  // Determine if we are changing scope.
491  size_t new_scope = CPU_SIZE+1; // Default to invalid scope.
492  if (inst_ptr >= genome.sequence.size()) new_scope = 0;
493  else {
494  size_t inst_scope = InstScope(genome.sequence[inst_ptr]);
495  if (inst_scope) new_scope = inst_scope;
496  }
497 
498  // If we are not changing scope OR we are going to a deeper scope, execute next!
499  if (new_scope > CPU_SIZE || new_scope > CurScope()) return inst_ptr;
500 
501  // If we are at the end of a loop, assume we will jump back to the beginning.
502  if (CurScopeType() == ScopeType::LOOP) {
503  return scope_stack.back().start_pos;
504  }
505 
506  // If we are at the end of a function, assume we will jump back to the call.
508  size_t next_pos = call_stack.back();
509  if (next_pos >= genome.sequence.size()) next_pos = 0;
510  return next_pos;
511  }
512 
513  // If we have run past the end of the genome, we will start over.
514  if (inst_ptr >= genome.sequence.size()) return 0;
515 
516  // Otherwise, we exit the scope normally.
517  return inst_ptr;
518  }
519 
520  template <typename HARDWARE>
521  void AvidaCPU_Base<HARDWARE>::PrintState(std::ostream & os) const {
522  size_t next_inst = PredictNextInst();
523 
524  os << " REGS: ";
525  for (size_t i = 0; i < CPU_SIZE; i++) os << "[" << regs[i] << "] ";
526  os << "\n INPUTS: ";
527  // for (size_t i = 0; i < CPU_SIZE; i++) os << "[" << Find(inputs, (int)i, 0.0) << "] ";
528  for (auto & x : inputs) os << "[" << x.first << "," << x.second << "] ";
529  os << "\n OUTPUTS: ";
530  //for (size_t i = 0; i < CPU_SIZE; i++) os << "[" << Find(outputs, (int)i, 0.0) << "] ";
531  for (auto & x : outputs) os << "[" << x.first << "," << x.second << "] ";
532  os << std::endl;
533 
534  os << "IP:" << inst_ptr;
535  if (inst_ptr != next_inst) os << "(-> " << next_inst << ")";
536  os << " scope:" << CurScope()
537  << " (";
538  if (next_inst < genome.sequence.size()) { // For interpreter mode
539  PrintInst(genome.sequence[next_inst], os);
540  }
541  os << ")"
542  << " errors: " << errors
543  << std::endl;
544 
545  // @CAO Still need:
546  // emp::array< emp::vector<double>, CPU_SIZE > stacks;
547  // emp::array< int, CPU_SIZE> fun_starts;
548  // emp::vector<RegBackup> reg_stack;
549  // emp::vector<size_t> call_stack;
550  }
551 
552  class AvidaGP : public AvidaCPU_Base<AvidaGP> {
553  public:
555  using typename base_t::genome_t;
556  using typename base_t::inst_lib_t;
557 
558  AvidaGP(const genome_t & in_genome) : AvidaCPU_Base(in_genome) { ; }
559  AvidaGP(Ptr<const inst_lib_t> inst_lib) : AvidaCPU_Base(Genome(inst_lib)) { ; }
560  AvidaGP(const inst_lib_t & inst_lib) : AvidaCPU_Base(Genome(&inst_lib)) { ; }
561 
562  AvidaGP() = default;
563  AvidaGP(const AvidaGP &) = default;
564  AvidaGP(AvidaGP &&) = default;
565 
566  virtual ~AvidaGP() { ; }
567  };
568 }
569 
570 
571 #endif
Genome genome_t
Definition: AvidaGP.h:51
Ptr< T > ToPtr(T *_in, bool own=false)
Convert a T* to a Ptr<T>. By default, don&#39;t track.
Definition: Ptr.h:816
void PrintGenome(std::ostream &os=std::cout) const
Print out this program.
Definition: AvidaGP.h:455
size_t GetNumTraits() const
Definition: AvidaGP.h:318
inst_t GetRandomInst(Random &rand)
Definition: AvidaGP.h:355
AvidaCPU_Base()
Create a default AvidaCPU (no genome sequence, default instruction set)
Definition: AvidaGP.h:239
void PushInstString(std::string info)
Definition: AvidaGP.h:371
void PushInst(const std::string &name, size_t a0=0, size_t a1=0, size_t a2=0)
Definition: AvidaGP.h:365
void Trace(size_t num_inst, const std::string &filename)
Definition: AvidaGP.h:422
emp::vector< RegBackup > GetRegStack() const
Definition: AvidaGP.h:313
Definition: AvidaCPU_InstLib.h:23
void SetOutputs(const std::unordered_map< int, double > &vals)
Definition: AvidaGP.h:330
virtual ~AvidaCPU_Base()
Destructor.
Definition: AvidaGP.h:252
size_t GetNumErrors() const
Definition: AvidaGP.h:315
void SetOutputs(std::unordered_map< int, double > &&vals)
Definition: AvidaGP.h:331
emp::array< stack_t, CPU_SIZE > stacks
Definition: AvidaGP.h:138
const stack_t & GetStack(size_t id) const
Definition: AvidaGP.h:306
void RandomizeInst(size_t pos, Random &rand)
Definition: AvidaGP.h:360
size_t start_pos
Definition: AvidaGP.h:118
Ptr< const inst_lib_t > inst_lib
Definition: AvidaGP.h:82
virtual void ResetHardware()
Reset just the CPU hardware, but keep the genome and traits.
Definition: AvidaGP.h:266
A specialized version of InstLib to handle AvidaCPU Instructions.
const emp::vector< double > & GetTraits()
Definition: AvidaGP.h:317
A class to maintin files for loading, writing, storing, and easy access to components.
Definition: File.h:32
A versatile and non-patterned pseudo-random-number generator (Mersenne Twister).
Definition: ce_random.h:52
double GetInput(int id) const
Definition: AvidaGP.h:300
void ResetIP()
Reset the instruction pointer to the beginning of the genome AND reset scope.
Definition: AvidaGP.h:283
void SetInputs(const std::unordered_map< int, double > &vals)
Definition: AvidaGP.h:327
Genome(const inst_lib_t &_inst_lib, const sequence_t &_seq=sequence_t(0))
Definition: AvidaGP.h:88
void SetInst(size_t pos, size_t id, size_t a0=0, size_t a1=0, size_t a2=0)
Definition: AvidaGP.h:321
emp::vector< size_t > call_stack
Definition: AvidaGP.h:144
void PushRegInfo(size_t scope_id, size_t reg_id)
Definition: AvidaGP.h:344
void push_back(PB_Ts &&...args)
Definition: vector.h:189
void Trace(size_t num_inst, std::ostream &os=std::cout)
Trace the instructions being exectured, with full CPU details.
Definition: AvidaGP.h:419
void SetInput(int input_id, double value)
Definition: AvidaGP.h:326
void PushStack(size_t id, double value)
Definition: AvidaGP.h:338
AvidaGP(Ptr< const inst_lib_t > inst_lib)
Definition: AvidaGP.h:559
File & Apply(const std::function< void(std::string &)> &fun)
Apply a string manipulation function to all lines in the file.
Definition: File.h:178
int GetFunStart(size_t id) const
Definition: AvidaGP.h:307
void ExitScope()
Definition: AvidaGP.h:152
arg_set_t args
Definition: AvidaGP.h:60
std::unordered_map< int, double > outputs
Definition: AvidaGP.h:137
AvidaGP(const genome_t &in_genome)
Definition: AvidaGP.h:558
void Reset()
Reset the entire CPU to a starting state, without a genome.
Definition: AvidaGP.h:259
emp::vector< double > traits
Definition: AvidaGP.h:149
double GetTrait(size_t id) const
Definition: AvidaGP.h:316
void SetInst(size_t pos, const inst_t &inst)
Definition: AvidaGP.h:320
bool operator<=(const Genome &other) const
Definition: AvidaGP.h:110
size_t InstScope(const inst_t &inst) const
Determine the scope associated with a particular instruction.
Definition: AvidaGP.h:440
size_t size() const
Definition: vector.h:151
ScopeType CurScopeType() const
Definition: AvidaGP.h:311
bool operator==(const Genome &other) const
Definition: AvidaGP.h:107
void emplace_back(ARGS &&...args)
Definition: vector.h:219
ScopeType GetScopeType(size_t id)
Definition: AvidaGP.h:312
void Set(size_t _id, size_t _a0=0, size_t _a1=0, size_t _a2=0)
Definition: AvidaGP.h:73
Instruction & operator=(const Instruction &)=default
constexpr uint32_t GetUInt(const uint32_t max)
Definition: ce_random.h:191
ScopeType type
Definition: AvidaGP.h:117
RegBackup(size_t _s, size_t _r, double _v)
Definition: AvidaGP.h:130
emp::array< double, CPU_SIZE > regs
Definition: AvidaGP.h:135
void push_back(PB_Ts &&...args)
Definition: array.h:169
bool Load(std::istream &input)
Definition: AvidaGP.h:431
void SingleProcess()
Process the NEXT instruction pointed to be the instruction pointer.
Definition: AvidaGP.h:395
bool operator>=(const Genome &other) const
Definition: AvidaGP.h:112
Definition: AvidaGP.h:101
auto Find(const MAP_T &in_map, const KEY_T &key, const typename MAP_T::mapped_type &dval)
Definition: map_utils.h:29
genome_t genome
Definition: AvidaGP.h:134
std::string string_pop(std::string &in_string, const char delim=' ')
Definition: string_utils.h:303
bool Load(const std::string &filename)
Definition: AvidaGP.h:386
double GetOutput(int id) const
Definition: AvidaGP.h:303
static const PrintStr endl("<br>")
Pre-define emp::endl to insert a "<br>" and thus acting like a newline.
T & back()
Definition: array.h:156
void pop_back()
Definition: vector.h:194
void resize(size_t new_size)
Definition: array.h:165
Definition: AvidaGP.h:79
void Process(size_t num_inst)
Process the next SERIES of instructions, directed by the instruction pointer.
Definition: AvidaGP.h:403
void SetTrait(size_t id, double val)
Definition: AvidaGP.h:349
AvidaCPU_Base(const inst_lib_t &inst_lib)
Definition: AvidaGP.h:243
double PopStack(size_t id)
Definition: AvidaGP.h:332
double GetReg(size_t id) const
Definition: AvidaGP.h:299
bool operator!=(const Genome &other) const
Definition: AvidaGP.h:108
AvidaGP(const inst_lib_t &inst_lib)
Definition: AvidaGP.h:560
Genome(Ptr< const inst_lib_t > _inst_lib, const sequence_t &_seq=sequence_t(0))
Definition: AvidaGP.h:86
emp::vector< ScopeInfo > GetScopeStack() const
Definition: AvidaGP.h:309
bool operator<(const this_t &other) const
Definition: AvidaGP.h:254
bool UpdateScope(size_t new_scope, ScopeType type=ScopeType::BASIC)
Definition: AvidaGP.h:169
size_t reg_id
Definition: AvidaGP.h:126
size_t GetNumInputs() const
Definition: AvidaGP.h:302
Instruction(size_t _id=0, size_t a0=0, size_t a1=0, size_t a2=0)
Definition: AvidaGP.h:62
void PushInst(const Instruction &inst)
Definition: AvidaGP.h:369
const std::unordered_map< int, double > & GetOutputs() const
Definition: AvidaGP.h:304
std::unordered_map< int, double > inputs
Definition: AvidaGP.h:136
static constexpr size_t CPU_SIZE
Definition: AvidaGP.h:41
void PushTrait(double val)
Definition: AvidaGP.h:353
void BypassScope(size_t scope)
Definition: AvidaGP.h:208
virtual ~AvidaGP()
Definition: AvidaGP.h:566
Definition: AvidaGP.h:124
size_t scope
Definition: AvidaGP.h:116
~Genome()
Definition: AvidaGP.h:92
void resize(size_t new_size)
Definition: vector.h:161
emp::vector< ScopeInfo > scope_stack
Definition: AvidaGP.h:142
size_t id
Definition: AvidaGP.h:59
size_t Hash() const
Definition: AvidaGP.h:94
bool operator==(const Instruction &in) const
Definition: AvidaGP.h:76
const size_t GetSize() const
Definition: AvidaGP.h:298
File & RemoveComments(const std::string &marker)
A technique to remove all comments in a file.
Definition: File.h:224
void SetIP(size_t pos)
Definition: AvidaGP.h:343
emp::vector< size_t > GetCallStack() const
Definition: AvidaGP.h:314
const genome_t & GetGenome() const
Definition: AvidaGP.h:297
AvidaCPU_Base(const genome_t &in_genome)
Create a new AvidaCPU seeding it with a genome.
Definition: AvidaGP.h:227
void PrintInst(const inst_t &inst, std::ostream &os=std::cout) const
Print out a single instruction, with its arguments.
Definition: AvidaGP.h:446
If we are in emscripten, make sure to include the header.
Definition: array.h:37
void PushInst(Instruction &&inst)
Definition: AvidaGP.h:370
void SetReg(size_t id, double val)
Definition: AvidaGP.h:325
A single instruction in a linear genome.
Definition: LinearCode.h:20
RegBackup()
Definition: AvidaGP.h:129
Definition: Ptr.h:711
void SetFunStart(size_t id, int value)
Definition: AvidaGP.h:342
ScopeType
Definition: InstLib.h:27
size_t errors
Definition: AvidaGP.h:146
size_t operator()(const Genome &g) const
Definition: AvidaGP.h:101
#define emp_assert(...)
Definition: assert.h:199
void IncErrors()
Definition: AvidaGP.h:348
void PushRandom(Random &rand, const size_t count=1)
Definition: AvidaGP.h:378
T & back()
Definition: vector.h:183
void PrintState(std::ostream &os=std::cout) const
Print out the state of the virtual CPU.
Definition: AvidaGP.h:521
size_t GetIP() const
Definition: AvidaGP.h:308
static constexpr size_t STACK_CAP
Definition: AvidaGP.h:43
inst_t GetInst(size_t pos) const
Definition: AvidaGP.h:296
size_t inst_ptr
Definition: AvidaGP.h:141
ScopeInfo(size_t _s, ScopeType _t, size_t _p)
Definition: AvidaGP.h:121
sequence_t sequence
Definition: AvidaGP.h:83
ScopeInfo()
Definition: AvidaGP.h:120
void SetOutput(int output_id, double value)
Definition: AvidaGP.h:329
void PushCallInfo(size_t pos)
Definition: AvidaGP.h:347
size_t CurScope() const
Definition: AvidaGP.h:310
size_t scope
Definition: AvidaGP.h:125
void pop_back()
Definition: array.h:170
emp::array< int, CPU_SIZE > fun_starts
Definition: AvidaGP.h:139
Definition: AvidaGP.h:39
double value
Definition: AvidaGP.h:127
size_t GetNumOutputs() const
Definition: AvidaGP.h:305
void ProcessInst(const inst_t &inst)
Process a specified instruction, provided by the caller.
Definition: AvidaGP.h:389
Instruction inst_t
Definition: AvidaGP.h:50
size_t arg_t
Definition: AvidaGP.h:52
void SetInputs(std::unordered_map< int, double > &&vals)
Definition: AvidaGP.h:328
const std::unordered_map< int, double > & GetInputs() const
Definition: AvidaGP.h:301
size_t PredictNextInst() const
Figure out which instruction is going to actually be run next SingleProcess()
Definition: AvidaGP.h:489
Ptr< const inst_lib_t > GetInstLib() const
Definition: AvidaGP.h:295
void SetGenome(const genome_t &g)
Definition: AvidaGP.h:324
File & CompressWhitespace()
Definition: File.h:202
emp::vector< RegBackup > reg_stack
Definition: AvidaGP.h:143
AvidaCPU_Base(Ptr< const inst_lib_t > inst_lib)
Create an AvidaCPU with a specified instruction set (but no genome sequence)
Definition: AvidaGP.h:242
Definition: AvidaGP.h:115
bool operator<(const Instruction &other) const
Definition: AvidaGP.h:69
Definition: AvidaGP.h:58
static constexpr size_t INST_ARGS
Definition: AvidaGP.h:42
Genome genome_t
Definition: AvidaGP.h:51
void PushInst(size_t id, size_t a0=0, size_t a1=0, size_t a2=0)
Definition: AvidaGP.h:362
Definition: AvidaGP.h:552