19 #ifndef EMP_PROCESSOR_H 20 #define EMP_PROCESSOR_H 26 #include "../base/array.h" 27 #include "../base/Ptr.h" 28 #include "../base/vector.h" 29 #include "../tools/map_utils.h" 30 #include "../tools/Random.h" 31 #include "../tools/string_utils.h" 37 template <
typename HARDWARE>
51 if (new_scope > cur_scope) {
52 scope_stack.emplace_back(new_scope, type, inst_ptr);
58 inst_ptr = scope_stack.back().start_pos;
67 inst_ptr = call_stack.back();
68 if (inst_ptr >= genome.sequence.size()) {
71 call_stack.pop_back();
91 while (inst_ptr+1 < genome.sequence.size()) {
93 const size_t test_scope =
InstScope(genome.sequence[inst_ptr]);
96 if (test_scope && test_scope <= scope) {
106 : genome(in_genome), regs(), inputs(), outputs(), stacks(), fun_starts()
107 , inst_ptr(0), scope_stack(), reg_stack(), call_stack(), errors(0), traits()
110 for (
size_t i = 0; i < CPU_SIZE; i++) {
111 regs[i] = (double) i;
133 return genome < other.genome;
138 genome.sequence.resize(0);
146 for (
size_t i = 0; i < CPU_SIZE; i++) {
147 regs[i] = (double) i;
154 scope_stack.resize(1);
156 call_stack.resize(0);
163 while (scope_stack.size() > 1) ExitScope();
165 while (reg_stack.size()) {
166 regs[reg_stack.back().reg_id] = reg_stack.back().value;
167 reg_stack.pop_back();
169 call_stack.resize(0);
174 inst_t
GetInst(
size_t pos)
const {
return genome.sequence[pos]; }
176 const size_t GetSize()
const {
return genome.sequence.size(); }
177 double GetReg(
size_t id)
const {
return regs[id]; }
179 const std::unordered_map<int,double> &
GetInputs()
const {
return inputs; }
182 const std::unordered_map<int,double> &
GetOutputs()
const {
return outputs; }
184 const stack_t &
GetStack(
size_t id)
const {
return stacks[id]; }
186 size_t GetIP()
const {
return inst_ptr; }
188 size_t CurScope()
const {
return scope_stack.back().scope; }
194 double GetTrait(
size_t id)
const {
return traits[id]; }
198 void SetInst(
size_t pos,
const inst_t & inst) { genome.sequence[pos] = inst; }
199 void SetInst(
size_t pos,
size_t id,
size_t a0=0,
size_t a1=0,
size_t a2=0) {
200 genome.sequence[pos].Set(
id, a0, a1, a2);
203 void SetReg(
size_t id,
double val) { regs[id] = val; }
204 void SetInput(
int input_id,
double value) { inputs[input_id] = value; }
205 void SetInputs(
const std::unordered_map<int,double> & vals) { inputs = vals; }
206 void SetInputs(std::unordered_map<int,double> && vals) { inputs = std::move(vals); }
207 void SetOutput(
int output_id,
double value) { outputs[output_id] = value; }
208 void SetOutputs(
const std::unordered_map<int,double> & vals) { outputs = vals; }
209 void SetOutputs(std::unordered_map<int,double> && vals) { outputs = std::move(vals); }
211 if (stacks[
id].size() == 0)
return 0.0;
212 double out = stacks[id].back();
213 stacks[id].pop_back();
217 if (stacks[
id].size() >= STACK_CAP)
return;
218 stacks[id].push_back(value);
220 void SetFunStart(
size_t id,
int value) { fun_starts[id] = value; }
221 void SetIP(
size_t pos) { inst_ptr = pos; }
223 reg_stack.emplace_back(scope_id, reg_id, regs[reg_id]);
228 if (
id >= traits.size()) traits.resize(
id+1, 0.0);
234 return inst_t(rand.
GetUInt(genome.inst_lib->GetSize()),
240 void PushInst(
size_t id,
size_t a0=0,
size_t a1=0,
size_t a2=0) {
241 genome.sequence.emplace_back(
id, a0, a1, a2);
243 void PushInst(
const std::string & name,
size_t a0=0,
size_t a1=0,
size_t a2=0) {
244 size_t id = genome.inst_lib->GetID(name);
245 genome.sequence.emplace_back(
id, a0, a1, a2);
250 for (
size_t i = 0; i < count; i++) {
256 bool Load(std::istream & input);
259 void ProcessInst(
const inst_t & inst) { genome.inst_lib->ProcessInst(*
this, inst); }
262 size_t InstScope(
const inst_t & inst)
const;
267 if (inst_ptr >= genome.sequence.size())
ResetIP();
268 genome.inst_lib->ProcessInst(*
this, genome.sequence[inst_ptr]);
276 void PrintInst(
const inst_t & inst, std::ostream & os=std::cout)
const;
279 void PrintGenome(std::ostream & os=std::cout)
const;
280 void PrintGenome(
const std::string & filename)
const;
286 void PrintState(std::ostream & os=std::cout)
const;
289 void Trace(
size_t num_inst, std::ostream & os=std::cout) {
292 void Trace(
size_t num_inst,
const std::string & filename) {
293 std::ofstream of(filename);
300 static void Inst_Inc(
this_t & hw,
const inst_t & inst) { ++hw.regs[inst.args[0]]; }
301 static void Inst_Dec(
this_t & hw,
const inst_t & inst) { --hw.regs[inst.args[0]]; }
302 static void Inst_Not(
this_t & hw,
const inst_t & inst) { hw.regs[inst.args[0]] = (hw.regs[inst.args[0]] == 0.0); }
303 static void Inst_SetReg(
this_t & hw,
const inst_t & inst) { hw.regs[inst.args[0]] = (double) inst.args[1]; }
304 static void Inst_Add(
this_t & hw,
const inst_t & inst) { hw.regs[inst.args[2]] = hw.regs[inst.args[0]] + hw.regs[inst.args[1]]; }
305 static void Inst_Sub(
this_t & hw,
const inst_t & inst) { hw.regs[inst.args[2]] = hw.regs[inst.args[0]] - hw.regs[inst.args[1]]; }
306 static void Inst_Mult(
this_t & hw,
const inst_t & inst) { hw.regs[inst.args[2]] = hw.regs[inst.args[0]] * hw.regs[inst.args[1]]; }
309 const double denom = hw.regs[inst.args[1]];
310 if (denom == 0.0) ++hw.errors;
311 else hw.regs[inst.args[2]] = hw.regs[inst.args[0]] / denom;
315 const double base = hw.regs[inst.args[1]];
316 if (base == 0.0) ++hw.errors;
317 else hw.regs[inst.args[2]] = hw.regs[inst.args[0]] / base;
320 static void Inst_TestEqu(
this_t & hw,
const inst_t & inst) { hw.regs[inst.args[2]] = (hw.regs[inst.args[0]] == hw.regs[inst.args[1]]); }
321 static void Inst_TestNEqu(
this_t & hw,
const inst_t & inst) { hw.regs[inst.args[2]] = (hw.regs[inst.args[0]] != hw.regs[inst.args[1]]); }
322 static void Inst_TestLess(
this_t & hw,
const inst_t & inst) { hw.regs[inst.args[2]] = (hw.regs[inst.args[0]] < hw.regs[inst.args[1]]); }
326 if (hw.regs[inst.args[0]] == 0.0) hw.
BypassScope(inst.args[1]);
332 if (hw.regs[inst.args[0]] == 0.0) hw.
BypassScope(inst.args[1]);
338 if (hw.regs[inst.args[0]] == 0.0) hw.
BypassScope(inst.args[1]);
339 else hw.regs[inst.args[0]]--;
347 hw.fun_starts[inst.args[0]] = (int) hw.inst_ptr;
353 size_t def_pos = (size_t) hw.fun_starts[inst.args[0]];
354 if (def_pos >= hw.genome.sequence.size()
358 size_t fun_scope = hw.genome.sequence[def_pos].args[1];
360 hw.call_stack.push_back(hw.inst_ptr+1);
361 hw.inst_ptr = def_pos+1;
369 int input_id = (int) hw.regs[ inst.args[0] ];
370 hw.regs[inst.args[1]] =
Find(hw.inputs, input_id, 0.0);
375 int output_id = (int) hw.regs[ inst.args[1] ];
376 hw.outputs[output_id] = hw.regs[inst.args[0]];
379 static void Inst_CopyVal(
this_t & hw,
const inst_t & inst) { hw.regs[inst.args[1]] = hw.regs[inst.args[0]]; }
382 hw.reg_stack.emplace_back(hw.
CurScope(), inst.args[0], hw.regs[inst.args[0]]);
388 template <
typename HARDWARE>
390 if (genome.inst_lib->GetScopeType(inst.id) ==
ScopeType::NONE)
return 0;
391 return inst.args[ genome.inst_lib->GetScopeArg(inst.id) ] + 1;
394 template <
typename HARDWARE>
396 os << genome.inst_lib->GetName(inst.id);
397 const size_t num_args = genome.inst_lib->GetNumArgs(inst.id);
398 for (
size_t i = 0; i < num_args; i++) {
399 os <<
' ' << inst.args[i];
403 template <
typename HARDWARE>
405 size_t cur_scope = 0;
407 for (
const inst_t & inst : genome.sequence) {
411 if (new_scope == cur_scope) {
412 for (
size_t i = 0; i < cur_scope; i++) os <<
' ';
415 if (new_scope < cur_scope) {
416 cur_scope = new_scope-1;
420 for (
size_t i = 0; i < cur_scope; i++) os <<
' ';
423 if (new_scope > cur_scope) os <<
" --> ";
424 cur_scope = new_scope;
430 template <
typename HARDWARE>
432 std::ofstream of(filename);
437 template <
typename HARDWARE>
440 size_t new_scope = CPU_SIZE+1;
441 if (inst_ptr >= genome.sequence.size()) new_scope = 0;
443 size_t inst_scope =
InstScope(genome.sequence[inst_ptr]);
444 if (inst_scope) new_scope = inst_scope;
448 if (new_scope > CPU_SIZE || new_scope >
CurScope())
return inst_ptr;
452 return scope_stack.back().start_pos;
457 size_t next_pos = call_stack.back();
458 if (next_pos >= genome.sequence.size()) next_pos = 0;
463 if (inst_ptr >= genome.sequence.size())
return 0;
469 template <
typename HARDWARE>
474 for (
size_t i = 0; i < CPU_SIZE; i++) os <<
"[" << regs[i] <<
"] ";
477 for (
auto & x : inputs) os <<
"[" << x.first <<
"," << x.second <<
"] ";
478 os <<
"\n OUTPUTS: ";
480 for (
auto & x : outputs) os <<
"[" << x.first <<
"," << x.second <<
"] ";
483 os <<
"IP:" << inst_ptr;
484 if (inst_ptr != next_inst) os <<
"(-> " << next_inst <<
")";
487 if (next_inst < genome.sequence.size()) {
488 PrintInst(genome.sequence[next_inst], os);
491 <<
" errors: " << errors
502 template <
typename HARDWARE>
504 static inst_lib_t inst_lib;
506 if (inst_lib.GetSize() == 0) {
507 inst_lib.AddInst(
"Inc",
Inst_Inc, 1,
"Increment value in reg Arg1");
508 inst_lib.AddInst(
"Dec",
Inst_Dec, 1,
"Decrement value in reg Arg1");
509 inst_lib.AddInst(
"Not",
Inst_Not, 1,
"Logically toggle value in reg Arg1");
510 inst_lib.AddInst(
"SetReg",
Inst_SetReg, 2,
"Set reg Arg1 to numerical value Arg2");
511 inst_lib.AddInst(
"Add",
Inst_Add, 3,
"regs: Arg3 = Arg1 + Arg2");
512 inst_lib.AddInst(
"Sub",
Inst_Sub, 3,
"regs: Arg3 = Arg1 - Arg2");
513 inst_lib.AddInst(
"Mult",
Inst_Mult, 3,
"regs: Arg3 = Arg1 * Arg2");
514 inst_lib.AddInst(
"Div",
Inst_Div, 3,
"regs: Arg3 = Arg1 / Arg2");
515 inst_lib.AddInst(
"Mod",
Inst_Mod, 3,
"regs: Arg3 = Arg1 % Arg2");
516 inst_lib.AddInst(
"TestEqu",
Inst_TestEqu, 3,
"regs: Arg3 = (Arg1 == Arg2)");
517 inst_lib.AddInst(
"TestNEqu",
Inst_TestNEqu, 3,
"regs: Arg3 = (Arg1 != Arg2)");
518 inst_lib.AddInst(
"TestLess",
Inst_TestLess, 3,
"regs: Arg3 = (Arg1 < Arg2)");
522 inst_lib.AddInst(
"Break",
Inst_Break, 1,
"Break out of scope Arg1");
525 inst_lib.AddInst(
"Call",
Inst_Call, 1,
"Call previously defined function Arg1");
526 inst_lib.AddInst(
"Push",
Inst_Push, 2,
"Push reg Arg1 onto stack Arg2");
527 inst_lib.AddInst(
"Pop",
Inst_Pop, 2,
"Pop stack Arg1 into reg Arg2");
528 inst_lib.AddInst(
"Input",
Inst_Input, 2,
"Pull next value from input Arg1 into reg Arg2");
529 inst_lib.AddInst(
"Output",
Inst_Output, 2,
"Push reg Arg1 into output Arg2");
530 inst_lib.AddInst(
"CopyVal",
Inst_CopyVal, 2,
"Copy reg Arg1 into reg Arg2");
531 inst_lib.AddInst(
"ScopeReg",
Inst_ScopeReg, 1,
"Backup reg Arg1; restore at end of scope");
533 for (
size_t i = 0; i < CPU_SIZE; i++) {
535 inst_lib.AddArg(
to_string(
"Reg",
'A'+(
char)i), i);
ScopeType CurScopeType() const
Definition: Processor.h:189
double GetOutput(int id) const
Definition: Processor.h:181
static void Inst_CopyVal(this_t &hw, const inst_t &inst)
Definition: Processor.h:379
static void Inst_Define(this_t &hw, const inst_t &inst)
Definition: Processor.h:345
void SingleProcess()
Process the NEXT instruction pointed to be the instruction pointer.
Definition: Processor.h:265
void IncErrors()
Definition: Processor.h:226
This file maintains information about instructions availabel in virtual hardware. ...
static void Inst_TestLess(this_t &hw, const inst_t &inst)
Definition: Processor.h:322
std::string to_string(ALL_TYPES &&...all_values)
Definition: string_utils.h:511
static void Inst_Call(this_t &hw, const inst_t &inst)
Definition: Processor.h:351
ScopeType GetScopeType(size_t id)
Definition: Processor.h:190
static void Inst_Sub(this_t &hw, const inst_t &inst)
Definition: Processor.h:305
static const inst_lib_t & DefaultInstLib()
This static function can be used to access the generic AvidaGP instruction library.
Definition: Processor.h:503
emp::vector< ScopeInfo > GetScopeStack() const
Definition: Processor.h:187
static void Inst_Div(this_t &hw, const inst_t &inst)
Definition: Processor.h:308
bool UpdateScope(size_t new_scope, ScopeType type=ScopeType::BASIC)
Definition: Processor.h:47
static void Inst_Mult(this_t &hw, const inst_t &inst)
Definition: Processor.h:306
const genome_t & GetGenome() const
Definition: Processor.h:175
static void Inst_Push(this_t &hw, const inst_t &inst)
Definition: Processor.h:364
size_t PredictNextInst() const
Figure out which instruction is going to actually be run next SingleProcess()
Definition: Processor.h:438
void PushTrait(double val)
Definition: Processor.h:231
void SetInputs(const std::unordered_map< int, double > &vals)
Definition: Processor.h:205
static void Inst_ScopeReg(this_t &hw, const inst_t &inst)
Definition: Processor.h:381
A versatile and non-patterned pseudo-random-number generator (Mersenne Twister).
Definition: ce_random.h:52
double PopStack(size_t id)
Definition: Processor.h:210
static void Inst_Inc(this_t &hw, const inst_t &inst)
Instructions.
Definition: Processor.h:300
emp::vector< size_t > GetCallStack() const
Definition: Processor.h:192
size_t CurScope() const
Definition: Processor.h:188
HARDWARE hw
Definition: Processor.h:42
size_t GetNumTraits() const
Definition: Processor.h:196
void SetReg(size_t id, double val)
Definition: Processor.h:203
bool operator<(const this_t &other) const
Definition: Processor.h:132
void SetIP(size_t pos)
Definition: Processor.h:221
double GetTrait(size_t id) const
Definition: Processor.h:194
void PushInst(size_t id, size_t a0=0, size_t a1=0, size_t a2=0)
Definition: Processor.h:240
void Trace(size_t num_inst, std::ostream &os=std::cout)
Trace the instructions being exectured, with full CPU details.
Definition: Processor.h:289
static void Inst_If(this_t &hw, const inst_t &inst)
Definition: Processor.h:324
constexpr uint32_t GetUInt(const uint32_t max)
Definition: ce_random.h:191
void RandomizeInst(size_t pos, Random &rand)
Definition: Processor.h:238
void SetGenome(const genome_t &g)
Definition: Processor.h:202
Ptr< const inst_lib_t > GetInstLib() const
Definition: Processor.h:173
void SetInst(size_t pos, const inst_t &inst)
Definition: Processor.h:198
void PrintInst(const inst_t &inst, std::ostream &os=std::cout) const
Print out a single instruction, with its arguments.
Definition: Processor.h:395
void SetFunStart(size_t id, int value)
Definition: Processor.h:220
const size_t GetSize() const
Definition: Processor.h:176
auto Find(const MAP_T &in_map, const KEY_T &key, const typename MAP_T::mapped_type &dval)
Definition: map_utils.h:29
void BypassScope(size_t scope)
Definition: Processor.h:86
static const PrintStr endl("<br>")
Pre-define emp::endl to insert a "<br>" and thus acting like a newline.
static void Inst_Break(this_t &hw, const inst_t &inst)
Definition: Processor.h:342
size_t GetNumInputs() const
Definition: Processor.h:180
size_t InstScope(const inst_t &inst) const
Determine the scope associated with a particular instruction.
Definition: Processor.h:389
static void Inst_Output(this_t &hw, const inst_t &inst)
Definition: Processor.h:373
void PushInst(const std::string &name, size_t a0=0, size_t a1=0, size_t a2=0)
Definition: Processor.h:243
bool Load(std::istream &input)
void ResetIP()
Reset the instruction pointer to the beginning of the genome AND reset scope.
Definition: Processor.h:161
void PrintGenome(std::ostream &os=std::cout) const
Print out this program.
Definition: Processor.h:404
static void Inst_Countdown(this_t &hw, const inst_t &inst)
Definition: Processor.h:335
void PushRegInfo(size_t scope_id, size_t reg_id)
Definition: Processor.h:222
inst_t GetInst(size_t pos) const
Definition: Processor.h:174
void SetOutput(int output_id, double value)
Definition: Processor.h:207
void PushRandom(Random &rand, const size_t count=1)
Definition: Processor.h:249
const std::unordered_map< int, double > & GetInputs() const
Definition: Processor.h:179
const emp::vector< double > & GetTraits()
Definition: Processor.h:195
static void Inst_TestNEqu(this_t &hw, const inst_t &inst)
Definition: Processor.h:321
void SetInput(int input_id, double value)
Definition: Processor.h:204
void SetInst(size_t pos, size_t id, size_t a0=0, size_t a1=0, size_t a2=0)
Definition: Processor.h:199
static void Inst_Scope(this_t &hw, const inst_t &inst)
Definition: Processor.h:343
size_t GetNumErrors() const
Definition: Processor.h:193
static void Inst_TestEqu(this_t &hw, const inst_t &inst)
Definition: Processor.h:320
void Trace(size_t num_inst, const std::string &filename)
Definition: Processor.h:292
void SetInputs(std::unordered_map< int, double > &&vals)
Definition: Processor.h:206
If we are in emscripten, make sure to include the header.
Definition: array.h:37
void PrintState(std::ostream &os=std::cout) const
Print out the state of the virtual CPU.
Definition: Processor.h:470
int GetFunStart(size_t id) const
Definition: Processor.h:185
void SetTrait(size_t id, double val)
Definition: Processor.h:227
size_t GetIP() const
Definition: Processor.h:186
A single instruction in a linear genome.
Definition: LinearCode.h:20
Build a debug wrapper emp::vector around std::vector.
Definition: vector.h:42
void SetOutputs(const std::unordered_map< int, double > &vals)
Definition: Processor.h:208
ScopeType
Definition: InstLib.h:27
double GetInput(int id) const
Definition: Processor.h:178
void SetOutputs(std::unordered_map< int, double > &&vals)
Definition: Processor.h:209
void Process(size_t num_inst)
Process the next SERIES of instructions, directed by the instruction pointer.
Definition: Processor.h:273
static void Inst_Dec(this_t &hw, const inst_t &inst)
Definition: Processor.h:301
void PushInst(Instruction &&inst)
Definition: Processor.h:248
#define emp_assert(...)
Definition: assert.h:199
size_t GetNumOutputs() const
Definition: Processor.h:183
InstLib maintains a set of instructions for use in virtual hardware.
Definition: InstLib.h:34
static void Inst_Input(this_t &hw, const inst_t &inst)
Definition: Processor.h:367
static void Inst_Add(this_t &hw, const inst_t &inst)
Definition: Processor.h:304
const stack_t & GetStack(size_t id) const
Definition: Processor.h:184
static void Inst_While(this_t &hw, const inst_t &inst)
Definition: Processor.h:329
void Reset()
Reset the entire CPU to a starting state, without a genome.
Definition: Processor.h:137
static void Inst_Pop(this_t &hw, const inst_t &inst)
Definition: Processor.h:365
void PushStack(size_t id, double value)
Definition: Processor.h:216
virtual void ResetHardware()
Reset just the CPU hardware, but keep the genome and traits.
Definition: Processor.h:144
void ProcessInst(const inst_t &inst)
Process a specified instruction, provided by the caller.
Definition: Processor.h:259
emp::vector< RegBackup > GetRegStack() const
Definition: Processor.h:191
inst_t GetRandomInst(Random &rand)
Definition: Processor.h:233
static void Inst_SetReg(this_t &hw, const inst_t &inst)
Definition: Processor.h:303
void PushInst(const Instruction &inst)
Definition: Processor.h:247
double GetReg(size_t id) const
Definition: Processor.h:177
const std::unordered_map< int, double > & GetOutputs() const
Definition: Processor.h:182
void PushCallInfo(size_t pos)
Definition: Processor.h:225
static void Inst_Mod(this_t &hw, const inst_t &inst)
Definition: Processor.h:314
static void Inst_Not(this_t &hw, const inst_t &inst)
Definition: Processor.h:302
Definition: Processor.h:38