Empirical
AvidaCPU_InstLib.h
Go to the documentation of this file.
1 
10 #ifndef EMP_AVIDA_CPU_INST_LIB_H
11 #define EMP_AVIDA_CPU_INST_LIB_H
12 
13 #include "../tools/math.h"
14 
15 #include "InstLib.h"
16 
17 namespace emp {
18 
21 
22  template <typename HARDWARE_T, typename ARG_T=size_t, size_t ARG_COUNT=3>
23  struct AvidaCPU_InstLib : public InstLib<HARDWARE_T, ARG_T, ARG_COUNT> {
24  using hardware_t = HARDWARE_T;
25  using arg_t = ARG_T;
27  using inst_t = typename hardware_t::inst_t;
28 
29  static constexpr size_t arg_count = ARG_COUNT;
30 
31  // Instructions
32 
33  // One-input math
34  static void Inst_Inc(hardware_t & hw, const inst_t & inst) { ++hw.regs[inst.args[0]]; }
35  static void Inst_Dec(hardware_t & hw, const inst_t & inst) { --hw.regs[inst.args[0]]; }
36 
37  // Two-input math
38  static void Inst_Not(hardware_t & hw, const inst_t & inst) {
39  hw.regs[inst.args[0]] = (hw.regs[inst.args[0]] == 0.0);
40  }
41  static void Inst_SetReg(hardware_t & hw, const inst_t & inst) {
42  hw.regs[inst.args[0]] = (double) inst.args[1];
43  }
44  static void Inst_Add(hardware_t & hw, const inst_t & inst) {
45  hw.regs[inst.args[2]] = hw.regs[inst.args[0]] + hw.regs[inst.args[1]];
46  }
47  static void Inst_Sub(hardware_t & hw, const inst_t & inst) {
48  hw.regs[inst.args[2]] = hw.regs[inst.args[0]] - hw.regs[inst.args[1]];
49  }
50  static void Inst_Mult(hardware_t & hw, const inst_t & inst) {
51  hw.regs[inst.args[2]] = hw.regs[inst.args[0]] * hw.regs[inst.args[1]];
52  }
53 
54  static void Inst_Div(hardware_t & hw, const inst_t & inst) {
55  const double denom = hw.regs[inst.args[1]];
56  if (denom == 0.0) ++hw.errors;
57  else hw.regs[inst.args[2]] = hw.regs[inst.args[0]] / denom;
58  }
59 
60  static void Inst_Mod(hardware_t & hw, const inst_t & inst) {
61  const double base = hw.regs[inst.args[1]];
62  if (base == 0.0) ++hw.errors;
63  else hw.regs[inst.args[2]] = emp::Mod( hw.regs[inst.args[0]], base);
64  }
65 
66  // Comparisons
67  static void Inst_TestEqu(hardware_t & hw, const inst_t & inst) {
68  hw.regs[inst.args[2]] = (hw.regs[inst.args[0]] == hw.regs[inst.args[1]]);
69  }
70  static void Inst_TestNEqu(hardware_t & hw, const inst_t & inst) {
71  hw.regs[inst.args[2]] = (hw.regs[inst.args[0]] != hw.regs[inst.args[1]]);
72  }
73  static void Inst_TestLess(hardware_t & hw, const inst_t & inst) {
74  hw.regs[inst.args[2]] = (hw.regs[inst.args[0]] < hw.regs[inst.args[1]]);
75  }
76 
77  // Others...
78  static void Inst_If(hardware_t & hw, const inst_t & inst) { // args[0] = test, args[1] = scope
79  if (hw.UpdateScope(inst.args[1]) == false) return; // If previous scope is unfinished, stop!
80  if (hw.regs[inst.args[0]] == 0.0) hw.BypassScope(inst.args[1]); // If test fails, move to scope end.
81  }
82 
83  static void Inst_While(hardware_t & hw, const inst_t & inst) {
84  // UpdateScope returns false if previous scope isn't finished (e.g., while needs to loop)
85  if (hw.UpdateScope(inst.args[1], ScopeType::LOOP) == false) return;
86  if (hw.regs[inst.args[0]] == 0.0) hw.BypassScope(inst.args[1]); // If test fails, move to scope end.
87  }
88 
89  static void Inst_Countdown(hardware_t & hw, const inst_t & inst) { // Same as while, but auto-decriments test each loop.
90  // UpdateScope returns false if previous scope isn't finished (e.g., while needs to loop)
91  if (hw.UpdateScope(inst.args[1], ScopeType::LOOP) == false) return;
92  if (hw.regs[inst.args[0]] == 0.0) hw.BypassScope(inst.args[1]); // If test fails, move to scope end.
93  else hw.regs[inst.args[0]]--;
94  }
95 
96  static void Inst_Break(hardware_t & hw, const inst_t & inst) { hw.BypassScope(inst.args[0]); }
97  static void Inst_Scope(hardware_t & hw, const inst_t & inst) { hw.UpdateScope(inst.args[0]); }
98 
99  static void Inst_Define(hardware_t & hw, const inst_t & inst) {
100  if (hw.UpdateScope(inst.args[1]) == false) return; // Update which scope we are in.
101  hw.fun_starts[inst.args[0]] = (int) hw.inst_ptr; // Record where function should be exectuted.
102  hw.BypassScope(inst.args[1]); // Skip over the function definition for now.
103  }
104 
105  static void Inst_Call(hardware_t & hw, const inst_t & inst) {
106  // Make sure function exists and is still in place.
107  size_t def_pos = (size_t) hw.fun_starts[inst.args[0]];
108  if (def_pos >= hw.genome.sequence.size()
109  || hw.GetScopeType(hw.genome.sequence[def_pos].id) != ScopeType::FUNCTION) return;
110 
111  // Go back into the function's original scope (call is in that scope)
112  size_t fun_scope = hw.genome.sequence[def_pos].args[1];
113  if (hw.UpdateScope(fun_scope, ScopeType::FUNCTION) == false) return;
114  hw.call_stack.push_back(hw.inst_ptr+1); // Back up the call position
115  hw.inst_ptr = def_pos+1; // Jump to the function body (will adavance)
116  }
117 
118  static void Inst_Push(hardware_t & hw, const inst_t & inst) {
119  hw.PushStack(inst.args[1], hw.regs[inst.args[0]]);
120  }
121  static void Inst_Pop(hardware_t & hw, const inst_t & inst) {
122  hw.regs[inst.args[1]] = hw.PopStack(inst.args[0]);
123  }
124 
125  static void Inst_Input(hardware_t & hw, const inst_t & inst) {
126  // Determine the input ID and grab it if it exists; if not, return 0.0
127  int input_id = (int) hw.regs[ inst.args[0] ];
128  hw.regs[inst.args[1]] = Find(hw.inputs, input_id, 0.0);
129  }
130 
131  static void Inst_Output(hardware_t & hw, const inst_t & inst) {
132  // Save the date in the target reg to the specified output position.
133  int output_id = (int) hw.regs[ inst.args[1] ]; // Grab ID from register.
134  hw.outputs[output_id] = hw.regs[inst.args[0]]; // Copy target reg to appropriate output.
135  }
136 
137  static void Inst_CopyVal(hardware_t & hw, const inst_t & inst) {
138  hw.regs[inst.args[1]] = hw.regs[inst.args[0]];
139  }
140 
141  static void Inst_ScopeReg(hardware_t & hw, const inst_t & inst) {
142  hw.reg_stack.emplace_back(hw.CurScope(), inst.args[0], hw.regs[inst.args[0]]);
143  }
144 
145  static const this_t & DefaultInstLib() {
146  static this_t inst_lib;
147 
148  if (inst_lib.GetSize() == 0) {
149  inst_lib.AddInst("Inc", Inst_Inc, 1, "Increment value in reg Arg1");
150  inst_lib.AddInst("Dec", Inst_Dec, 1, "Decrement value in reg Arg1");
151  inst_lib.AddInst("Not", Inst_Not, 1, "Logically toggle value in reg Arg1");
152  inst_lib.AddInst("SetReg", Inst_SetReg, 2, "Set reg Arg1 to numerical value Arg2");
153  inst_lib.AddInst("Add", Inst_Add, 3, "regs: Arg3 = Arg1 + Arg2");
154  inst_lib.AddInst("Sub", Inst_Sub, 3, "regs: Arg3 = Arg1 - Arg2");
155  inst_lib.AddInst("Mult", Inst_Mult, 3, "regs: Arg3 = Arg1 * Arg2");
156  inst_lib.AddInst("Div", Inst_Div, 3, "regs: Arg3 = Arg1 / Arg2");
157  inst_lib.AddInst("Mod", Inst_Mod, 3, "regs: Arg3 = Arg1 % Arg2");
158  inst_lib.AddInst("TestEqu", Inst_TestEqu, 3, "regs: Arg3 = (Arg1 == Arg2)");
159  inst_lib.AddInst("TestNEqu", Inst_TestNEqu, 3, "regs: Arg3 = (Arg1 != Arg2)");
160  inst_lib.AddInst("TestLess", Inst_TestLess, 3, "regs: Arg3 = (Arg1 < Arg2)");
161  inst_lib.AddInst("If", Inst_If, 2, "If reg Arg1 != 0, scope -> Arg2; else skip scope", ScopeType::BASIC, 1);
162  inst_lib.AddInst("While", Inst_While, 2, "Until reg Arg1 != 0, repeat scope Arg2; else skip", ScopeType::LOOP, 1);
163  inst_lib.AddInst("Countdown", Inst_Countdown, 2, "Countdown reg Arg1 to zero; scope to Arg2", ScopeType::LOOP, 1);
164  inst_lib.AddInst("Break", Inst_Break, 1, "Break out of scope Arg1");
165  inst_lib.AddInst("Scope", Inst_Scope, 1, "Enter scope Arg1", ScopeType::BASIC, 0);
166  inst_lib.AddInst("Define", Inst_Define, 2, "Build function Arg1 in scope Arg2", ScopeType::FUNCTION, 1);
167  inst_lib.AddInst("Call", Inst_Call, 1, "Call previously defined function Arg1");
168  inst_lib.AddInst("Push", Inst_Push, 2, "Push reg Arg1 onto stack Arg2");
169  inst_lib.AddInst("Pop", Inst_Pop, 2, "Pop stack Arg1 into reg Arg2");
170  inst_lib.AddInst("Input", Inst_Input, 2, "Pull next value from input Arg1 into reg Arg2");
171  inst_lib.AddInst("Output", Inst_Output, 2, "Push reg Arg1 into output Arg2");
172  inst_lib.AddInst("CopyVal", Inst_CopyVal, 2, "Copy reg Arg1 into reg Arg2");
173  inst_lib.AddInst("ScopeReg", Inst_ScopeReg, 1, "Backup reg Arg1; restore at end of scope");
174 
175  for (size_t i = 0; i < hardware_t::CPU_SIZE; i++) {
176  inst_lib.AddArg(to_string((int)i), i); // Args can be called by value
177  inst_lib.AddArg(to_string("Reg", 'A'+(char)i), i); // ...or as a register.
178  }
179  }
180 
181  return inst_lib;
182  }
183  };
184 
185 }
186 
187 #endif
static void Inst_Pop(hardware_t &hw, const inst_t &inst)
Definition: AvidaCPU_InstLib.h:121
static void Inst_Add(hardware_t &hw, const inst_t &inst)
Definition: AvidaCPU_InstLib.h:44
static void Inst_Scope(hardware_t &hw, const inst_t &inst)
Definition: AvidaCPU_InstLib.h:97
static void Inst_CopyVal(hardware_t &hw, const inst_t &inst)
Definition: AvidaCPU_InstLib.h:137
This file maintains information about instructions availabel in virtual hardware. ...
std::string to_string(ALL_TYPES &&...all_values)
Definition: string_utils.h:511
Definition: AvidaCPU_InstLib.h:23
static void Inst_ScopeReg(hardware_t &hw, const inst_t &inst)
Definition: AvidaCPU_InstLib.h:141
static void Inst_Mod(hardware_t &hw, const inst_t &inst)
Definition: AvidaCPU_InstLib.h:60
static void Inst_SetReg(hardware_t &hw, const inst_t &inst)
Definition: AvidaCPU_InstLib.h:41
static void Inst_TestEqu(hardware_t &hw, const inst_t &inst)
Definition: AvidaCPU_InstLib.h:67
void AddArg(const std::string &name, arg_t value)
Specify a keyword and arg value.
Definition: InstLib.h:155
size_t GetSize() const
Get the number of instructions in this set.
Definition: InstLib.h:99
HARDWARE_T hardware_t
Definition: AvidaCPU_InstLib.h:24
typename hardware_t::inst_t inst_t
Definition: AvidaCPU_InstLib.h:27
static void Inst_Countdown(hardware_t &hw, const inst_t &inst)
Definition: AvidaCPU_InstLib.h:89
static void Inst_While(hardware_t &hw, const inst_t &inst)
Definition: AvidaCPU_InstLib.h:83
emp::vector< InstDef > inst_lib
Full definitions for instructions.
Definition: InstLib.h:60
static void Inst_Input(hardware_t &hw, const inst_t &inst)
Definition: AvidaCPU_InstLib.h:125
ARG_T arg_t
Definition: AvidaCPU_InstLib.h:25
static constexpr size_t arg_count
Definition: AvidaCPU_InstLib.h:29
static void Inst_Break(hardware_t &hw, const inst_t &inst)
Definition: AvidaCPU_InstLib.h:96
auto Find(const MAP_T &in_map, const KEY_T &key, const typename MAP_T::mapped_type &dval)
Definition: map_utils.h:29
constexpr int Mod(int in_val, int mod_val)
% is actually remainder; Mod is a proper modulus command that handles negative #&#39;s correctly ...
Definition: math.h:26
static void Inst_Sub(hardware_t &hw, const inst_t &inst)
Definition: AvidaCPU_InstLib.h:47
static void Inst_TestLess(hardware_t &hw, const inst_t &inst)
Definition: AvidaCPU_InstLib.h:73
static void Inst_Define(hardware_t &hw, const inst_t &inst)
Definition: AvidaCPU_InstLib.h:99
static void Inst_Dec(hardware_t &hw, const inst_t &inst)
Definition: AvidaCPU_InstLib.h:35
static void Inst_Not(hardware_t &hw, const inst_t &inst)
Definition: AvidaCPU_InstLib.h:38
static void Inst_TestNEqu(hardware_t &hw, const inst_t &inst)
Definition: AvidaCPU_InstLib.h:70
If we are in emscripten, make sure to include the header.
Definition: array.h:37
static void Inst_Call(hardware_t &hw, const inst_t &inst)
Definition: AvidaCPU_InstLib.h:105
static void Inst_If(hardware_t &hw, const inst_t &inst)
Definition: AvidaCPU_InstLib.h:78
void AddInst(const std::string &name, const fun_t &fun_call, size_t num_args=0, const std::string &desc="", ScopeType scope_type=ScopeType::NONE, size_t scope_arg=(size_t)-1, const inst_properties_t &inst_properties=inst_properties_t())
Add a new instruction to the set.
Definition: InstLib.h:140
InstLib maintains a set of instructions for use in virtual hardware.
Definition: InstLib.h:34
static void Inst_Div(hardware_t &hw, const inst_t &inst)
Definition: AvidaCPU_InstLib.h:54
static void Inst_Inc(hardware_t &hw, const inst_t &inst)
Definition: AvidaCPU_InstLib.h:34
static void Inst_Mult(hardware_t &hw, const inst_t &inst)
Definition: AvidaCPU_InstLib.h:50
static const this_t & DefaultInstLib()
Definition: AvidaCPU_InstLib.h:145
static void Inst_Push(hardware_t &hw, const inst_t &inst)
Definition: AvidaCPU_InstLib.h:118
static void Inst_Output(hardware_t &hw, const inst_t &inst)
Definition: AvidaCPU_InstLib.h:131