Empirical
EventDrivenGP.h
Go to the documentation of this file.
1 #ifndef EMP_EVENT_DRIVEN_GP_H
2 #define EMP_EVENT_DRIVEN_GP_H
3 
4 #include <functional>
5 #include <tuple>
6 #include <unordered_map>
7 #include <deque>
8 #include <utility>
9 #include "InstLib.h"
10 #include "EventLib.h"
11 #include "../tools/BitSet.h"
12 #include "../tools/BitVector.h"
13 #include "../tools/map_utils.h"
14 #include "../tools/string_utils.h"
15 #include "../tools/Random.h"
16 #include "../base/vector.h"
17 #include "../base/Ptr.h"
18 #include "../base/array.h"
19 #include "../control/SignalControl.h"
20 #include "../control/Signal.h"
21 
22 // Developer Notes:
23 // * Program struct's PrintProgram prints program in a maximally readable format. However, this format
24 // is not currently acceptable for input into EventDrivenGP's Load function.
25 // * Will remedy this by adding another PrintProgram function to print in a format acceptable by EventDrivenGP's
26 // Load function. This PrintProgram will be less readable, but will more fully describe the program (it won't hide anything).
27 // * @amlalejini - TODO:
28 // [ ] operator= overrides.
29 // [ ] Add in warnings about 'no actively running core' if active_cores.size() == 0 (can happen post-ResetHardware())
30 
31 namespace emp {
32 
97  template<size_t AFFINITY_WIDTH>
99  public:
101  static constexpr size_t MAX_INST_ARGS = 3;
102 
103  using EventDrivenGP_t = EventDrivenGP_AW<AFFINITY_WIDTH>; //< Resolved type for this templated class.
104  using mem_key_t = int; //< Hardware memory map key type.
105  using mem_val_t = double; //< Hardware memory map value type.
106  using memory_t = std::unordered_map<mem_key_t, mem_val_t>; //< Hardware memory map type.
107  using arg_t = int; //< Instruction argument type.
108  using arg_set_t = emp::array<arg_t, MAX_INST_ARGS>; //< Instruction argument set type.
109  using affinity_t = BitSet<AFFINITY_WIDTH>; //< Affinity type alias.
110  using properties_t = std::unordered_set<std::string>; //< Event/Instruction properties type.
111 
112  // A few default values. WARNING: I have no actual reason to believe these are the best defaults.
113  static constexpr size_t DEFAULT_MAX_CORES = 8;
114  static constexpr size_t DEFAULT_MAX_CALL_DEPTH = 128;
115  static constexpr mem_val_t DEFAULT_MEM_VALUE = 0.0;
116  static constexpr double DEFAULT_MIN_BIND_THRESH = 0.5;
117 
120  struct Event {
121  size_t id; //< Event ID. Used to lookup event type in event library.
122  affinity_t affinity; //< Event affinity. Used to match what function this event should bind to.
123  memory_t msg; //< Event message. Packet of information associated with event.
124  properties_t properties; //< Event properties. Properties of this instance of an event.
125 
126  Event(size_t _id=0, const affinity_t & aff=affinity_t(), const memory_t & _msg=memory_t(),
127  const properties_t & _properties=properties_t())
128  : id(_id), affinity(aff), msg(_msg), properties(_properties) { ; }
129  Event(const Event &) = default;
130  Event(Event &&) = default;
131 
132  Event & operator=(const Event &) = default;
133  Event & operator=(Event &&) = default;
134 
136  bool HasProperty(std::string property) const { return properties.count(property); }
137 
138  };
139 
144  enum class BlockType { NONE=0, BASIC, LOOP };
147  struct Block {
148  size_t begin; //< Instruction position where block begins.
149  size_t end; //< Instruction position where block ends.
150  BlockType type; //< Block type.
151 
152  Block(size_t _begin=0, size_t _end=0, BlockType _type=BlockType::BASIC)
153  : begin(_begin), end(_end), type(_type) { ; }
154  };
155 
159  struct State {
160  memory_t local_mem; //< Local memory map. By default, most instructions operate on local memory.
161  memory_t input_mem; //< Input memory map.
162  memory_t output_mem; //< Output memory map.
163  double default_mem_val; //< Default memory value. If memory map is accessed using key that doesn't exist in the map, the default memory value is returned.
164 
165  size_t func_ptr; //< Function pointer.
166  size_t inst_ptr; //< Instruction pointer.
167  emp::vector<Block> block_stack; //< Stack of blocks (top is current block status).
168  bool is_main; //< Indicates if this state is main or not.
169 
170  State(mem_val_t _default_mem_val = 0.0, bool _is_main=false)
171  : local_mem(), input_mem(), output_mem(), default_mem_val(_default_mem_val),
172  func_ptr(0), inst_ptr(0), block_stack(), is_main(_is_main) { ; }
173  State(const State &) = default;
174  State(State &&) = default;
175 
177  void Reset() {
178  local_mem.clear();
179  input_mem.clear();
180  output_mem.clear();
181  func_ptr = 0; inst_ptr = 0;
182  block_stack.clear();
183  }
184 
186  size_t GetFP() const { return func_ptr; }
187 
189  size_t GetIP() const { return inst_ptr; }
190 
192  mem_val_t GetDefaultMemValue() const { return default_mem_val; }
193 
195  void SetIP(size_t ip) { inst_ptr = ip; }
196 
198  void SetFP(size_t fp) { func_ptr = fp; }
199 
201  void SetDefaultMemValue(mem_val_t val) { default_mem_val = val; }
202 
204  void AdvanceIP(size_t inc = 1) { inst_ptr += inc; }
205 
207  bool IsMain() const { return is_main; }
208 
210  memory_t & GetLocalMemory() { return local_mem; }
211 
213  memory_t & GetInputMemory() { return input_mem; }
214 
216  memory_t & GetOutputMemory() { return output_mem; }
217 
220  mem_val_t GetLocal(mem_key_t key) const { return Find(local_mem, key, default_mem_val); }
221 
224  mem_val_t GetInput(mem_key_t key) const { return Find(input_mem, key, default_mem_val); }
225 
228  mem_val_t GetOutput(mem_key_t key) const { return Find(output_mem, key, default_mem_val); }
229 
231  void SetLocal(mem_key_t key, mem_val_t value) { local_mem[key] = value; }
232 
234  void SetInput(mem_key_t key, mem_val_t value) { input_mem[key] = value; }
235 
237  void SetOutput(mem_key_t key, mem_val_t value) { output_mem[key] = value; }
238 
242  if (!Has(local_mem, key)) local_mem[key] = default_mem_val;
243  return local_mem[key];
244  }
245 
249  if (!Has(input_mem, key)) input_mem[key] = default_mem_val;
250  return input_mem[key];
251  }
252 
256  if (!Has(output_mem, key)) output_mem[key] = default_mem_val;
257  return output_mem[key];
258  }
259  };
260 
266  struct Instruction {
267  size_t id; //< Instruction ID. Used to lookup instruction type using an instruction library.
268  arg_set_t args; //< Instruction arguments. Currently hardcoded maximum of 3.
269  affinity_t affinity; //< Instruction affinity.
270 
271  Instruction(size_t _id=0, arg_t a0=0, arg_t a1=0, arg_t a2=0, const affinity_t & _aff=affinity_t())
272  : id(_id), args(), affinity(_aff) { args[0] = a0; args[1] = a1; args[2] = a2; }
273  Instruction(const Instruction &) = default;
274  Instruction(Instruction &&) = default;
275 
276  Instruction & operator=(const Instruction &) = default;
277  Instruction & operator=(Instruction &&) = default;
278 
279  void Set(size_t _id, arg_t _a0=0, arg_t _a1=0, arg_t _a2=0, const affinity_t & _aff=affinity_t())
280  { id = _id; args[0] = _a0; args[1] = _a1; args[2] = _a2; affinity = _aff; }
281 
282  void Set(const Instruction & other) {
283  id = other.id;
284  args[0] = other.args[0]; args[1] = other.args[1]; args[2] = other.args[2];
285  affinity = other.affinity;
286  }
287 
288  bool operator==(const Instruction & in) const {
289  return id == in.id && args == in.args && affinity == in.affinity;
290  }
291  bool operator!=(const Instruction & in) const { return !(*this == in); }
292 
293  bool operator<(const Instruction & other) const {
294  return std::tie(id, args, affinity) < std::tie(other.id, other.args, other.affinity);
295  }
296 
297  };
298 
299  using inst_t = Instruction; //< Convenient Instruction type alias.
300  using inst_seq_t = emp::vector<inst_t>; //< Convenient type alias for instruction sequence.
301  using event_t = Event; //< Event type alias.
302  using inst_lib_t = InstLib<EventDrivenGP_t>; //< Instruction library type alias.
303  using event_lib_t = EventLib<EventDrivenGP_t>; //< Event library type alias.
304 
309  struct Function {
310  affinity_t affinity; //< Function affinity. Analogous to the function's name.
311  inst_seq_t inst_seq; //< Instruction sequence. Sequence of instructions that make up the function.
312 
313  Function(const affinity_t & _aff=affinity_t(), const inst_seq_t & _seq=inst_seq_t())
314  : affinity(_aff), inst_seq(_seq) { ; }
315 
316  inst_t & operator[](size_t id) { return inst_seq[id]; }
317  const inst_t & operator[](size_t id) const { return inst_seq[id]; }
318 
319  bool operator==(const Function & in) const {
320  return inst_seq == in.inst_seq && affinity == in.affinity;
321  }
322  bool operator!=(const Function & in) const { return !(*this == in); }
323 
324  bool operator<(const Function & other) const {
325  return std::tie(inst_seq, affinity) < std::tie(other.inst_seq, other.affinity);
326  }
327 
328  size_t GetSize() const { return inst_seq.size(); }
329 
331 
332  void PushInst(size_t id, arg_t a0, arg_t a1, arg_t a2, const affinity_t & aff) {
333  inst_seq.emplace_back(id, a0, a1, a2, aff);
334  }
335 
336  void PushInst(const inst_t & inst) {
337  inst_seq.emplace_back(inst);
338  }
339 
340  void SetInst(size_t pos, size_t id, arg_t a0, arg_t a1, arg_t a2, const affinity_t & aff) {
341  inst_seq[pos].Set(id, a0, a1, a2);
342  }
343 
344  void SetInst(size_t pos, const inst_t & inst) {
345  inst_seq[pos].Set(inst);
346  }
347 
348  };
349 
355  struct Program {
356  using program_t = emp::vector<Function>; //< Convenient type alias for sequence of functions.
357 
358  Ptr<const inst_lib_t> inst_lib; //< Pointer to const instruction library associated with this program.
359  program_t program; //< Sequence of functions that make up this program.
360 
362  : inst_lib(_ilib), program(_prgm) { ; }
363  Program(const Program &) = default;
364 
365  void Clear() { program.clear(); }
366 
367  Function & operator[](size_t id) { return program[id]; }
368  const Function & operator[](size_t id) const { return program[id]; }
369 
370  bool operator==(const Program & in) const { return program == in.program; }
371  bool operator!=(const Program & in) const { return !(*this == in); }
372 
373  bool operator<(const Program & other) const {
374  return program < other.program;
375  }
376 
378  size_t GetSize() const { return program.size(); }
379 
381  size_t GetInstCnt() const {
382  size_t cnt = 0;
383  for (size_t i = 0; i < GetSize(); ++i) cnt += program[i].GetSize();
384  return cnt;
385  }
386 
387  Ptr<const inst_lib_t> GetInstLib() const { return inst_lib; }
388 
389  bool ValidPosition(size_t fID, size_t pos) const {
390  return fID < program.size() && pos < program[fID].GetSize();
391  }
392  bool ValidFunction(size_t fID) const { return fID < program.size(); }
393 
394  void SetProgram(const program_t & _program) { program = _program; }
395 
396  void PushFunction(const Function & _function) { program.emplace_back(_function); }
397  void PushFunction(const affinity_t & _aff=affinity_t(), const inst_seq_t & _seq=inst_seq_t()) {
398  program.emplace_back(_aff, _seq);
399  }
404  void PushInst(size_t id, arg_t a0=0, arg_t a1=0, arg_t a2=0,
405  const affinity_t & aff=affinity_t(), int fID=-1)
406  {
407  size_t fp;
408  if (program.empty()) { program.emplace_back(); fp = 0; }
409  else if (fID < 0 || fID >= (int)program.size()) { fp = program.size() - 1; }
410  else fp = (size_t)fID;
411  program[fp].PushInst(id, a0, a1, a2, aff);
412  }
413 
418  void PushInst(const std::string & name, arg_t a0=0, arg_t a1=0, arg_t a2=0,
419  const affinity_t & aff=affinity_t(), int fID=-1)
420  {
421  size_t fp;
422  size_t id = inst_lib->GetID(name);
423  if (program.empty()) { program.emplace_back(); fp = 0; }
424  else if (fID < 0 || fID >= (int)program.size()) { fp = program.size() - 1; }
425  else fp = (size_t)fID;
426  program[fp].PushInst(id, a0, a1, a2, aff);
427  }
428 
433  void PushInst(const inst_t & inst, int fID=-1) {
434  size_t fp;
435  if (program.empty()) { program.emplace_back(); fp = 0; }
436  else if (fID < 0 || fID >= (int)program.size()) { fp = program.size() - 1; }
437  else fp = (size_t)fID;
438  program[fp].PushInst(inst);
439  }
440 
441  void SetInst(size_t fID, size_t pos, size_t id, arg_t a0=0, arg_t a1=0, arg_t a2=0,
442  const affinity_t & aff=affinity_t()) {
443  emp_assert(ValidPosition(fID, pos));
444  program[fID].SetInst(pos, id, a0, a1, a2, aff);
445  }
446 
447  void SetInst(size_t fID, size_t pos, const inst_t & inst) {
448  emp_assert(ValidPosition(fID, pos));
449  program[fID].SetInst(pos, inst);
450  }
451 
461  void Load(std::istream & input) {
462  // Clear current program.
463  Clear();
464  std::string cur_line;
465  emp::vector<std::string> line_components;
466  while (!input.eof()) {
467  std::getline(input, cur_line);
468  remove_whitespace(cur_line); // Clear out whitespace.
469  if (cur_line == empty_string()) continue; // Skip empty lines.
470  // Are we looking the beginning of a function?
471  slice(cur_line, line_components, '-');
472  if (to_lower(line_components[0]) == "fn" && line_components.size() > 1) {
473  // Extract function affinity.
474  std::string & aff_str = line_components[1];
475  affinity_t fun_aff;
476  for (size_t i = 0; i < aff_str.size(); ++i) {
477  if (i >= fun_aff.GetSize()) break;
478  if (aff_str[i] == '1') fun_aff.Set(fun_aff.GetSize() - i - 1, true);
479  }
480  PushFunction(fun_aff);
481  } else {
482  // We must be looking at an instruction.
483  affinity_t inst_aff;
484  int a0 = 0; int a1 = 0; int a2 = 0;
485  // Is there an affinity?
486  size_t aff_begin = cur_line.find_first_of('[');
487  size_t aff_end = cur_line.find_first_of(']');
488  if ((aff_begin != std::string::npos) && (aff_end != std::string::npos) && (aff_begin < aff_end)) {
489  // Found affinity.
490  std::string aff_str = string_get_range(cur_line, aff_begin+1, aff_end-(aff_begin+1));
491  for (size_t i = 0; i < aff_str.size(); ++i) {
492  if (i >= inst_aff.GetSize()) break;
493  if (aff_str[i] == '1') inst_aff.Set(inst_aff.GetSize() - i - 1, true);
494  }
495  // Pop affinity from cur_line.
496  cur_line = string_get_range(cur_line, 0, aff_begin) + string_get_word(cur_line, aff_end+1);
497  }
498  // Are there arguments?
499  size_t args_begin = cur_line.find_first_of('(');
500  size_t args_end = cur_line.find_first_of(')');
501  size_t args_cnt = 0;
502  if ((args_begin != std::string::npos) && (args_end != std::string::npos) && (args_begin < args_end)) {
503  // Found some arguments.
504  std::string args_str = string_get_range(cur_line, args_begin+1, args_end-(args_begin+1));
505  line_components.clear();
506  // Extract arguments from arg str.
507  slice(args_str, line_components, ',');
508  if (args_cnt < line_components.size()) {
509  emp_assert(is_valid(line_components[args_cnt], [](char c){ return is_digit(c) || c=='-'; })); // Yes yes, this doesn't catch case when '-' is in middle of the number...oh well.
510  a0 = std::stoi(line_components[args_cnt]); ++args_cnt;
511  }
512  if (args_cnt < line_components.size()) {
513  emp_assert(is_valid(line_components[args_cnt], [](char c){ return is_digit(c) || c=='-'; }));
514  a1 = std::stoi(line_components[args_cnt]); ++args_cnt;
515  }
516  if (args_cnt < line_components.size()) {
517  emp_assert(is_valid(line_components[args_cnt], [](char c){ return is_digit(c) || c=='-'; }));
518  a2 = std::stoi(line_components[args_cnt]); ++args_cnt;
519  }
520  // Pop arguments from current line.
521  cur_line = string_get_range(cur_line, 0, args_begin) + string_get_word(cur_line, args_end+1);
522  }
523  // All that's left should be the instruction name.
524  emp_assert(inst_lib->GetID(cur_line) != (size_t)-1);
525  // Push instruction to program.
526  PushInst(cur_line, a0, a1, a2, inst_aff);
527  }
528  }
529  }
530 
532  void PrintInst(const inst_t & inst, std::ostream & os=std::cout) {
533  os << inst_lib->GetName(inst.id);
534  if (inst_lib->HasProperty(inst.id, "affinity")) {
535  os << ' '; inst.affinity.Print(os);
536  }
537  const size_t num_args = inst_lib->GetNumArgs(inst.id);
538  for (size_t i = 0; i < num_args; i++) {
539  os << ' ' << inst.args[i];
540  }
541  }
542 
544  void PrintInstFull(const inst_t & inst, std::ostream & os=std::cout) {
545  os << inst_lib->GetName(inst.id);
546  os << '['; inst.affinity.Print(os); os << ']';
547  os << '(';
548  for (size_t i = 0; i < MAX_INST_ARGS - 1; i++) {
549  os << inst.args[i] << ',';
550  } if (MAX_INST_ARGS > 0) { os << inst.args[MAX_INST_ARGS-1]; }
551  os << ')';
552  }
553 
555  void PrintProgram(std::ostream & os=std::cout) {
556  for (size_t fID = 0; fID < GetSize(); fID++) {
557  // Print out function name (affinity).
558  os << "Fn-" << fID << " ";
559  program[fID].affinity.Print(os);
560  os << ":\n";
561  int depth = 0;
562  for (size_t i = 0; i < program[fID].GetSize(); i++) {
563  const inst_t & inst = program[fID].inst_seq[i];
564  int num_spaces = 2 + (2 * depth);
565  for (int s = 0; s < num_spaces; s++) os << ' ';
566  PrintInst(inst, os);
567  os << '\n';
568  if (inst_lib->HasProperty(inst.id, "block_def")) {
569  // is block def?
570  depth++;
571  } else if (inst_lib->HasProperty(inst.id, "block_close") && depth > 0) {
572  // is block close?
573  depth--;
574  }
575  }
576  os << '\n';
577  }
578  }
579 
581  void PrintProgramFull(std::ostream & os=std::cout) {
582  for (size_t fID = 0; fID < GetSize(); fID++) {
583  // Print out function name (affinity).
584  os << "Fn-";
585  program[fID].affinity.Print(os);
586  os << ":\n";
587  int depth = 0;
588  for (size_t i = 0; i < program[fID].GetSize(); i++) {
589  const inst_t & inst = program[fID][i];
590  int num_spaces = 2 + (2 * depth);
591  for (int s = 0; s < num_spaces; s++) os << ' ';
592  PrintInstFull(inst, os);
593  os << '\n';
594  if (inst_lib->HasProperty(inst.id, "block_def")) {
595  // is block def?
596  depth++;
597  } else if (inst_lib->HasProperty(inst.id, "block_close") && depth > 0) {
598  // is block close?
599  depth--;
600  }
601  }
602  os << '\n';
603  }
604  }
605 
606  };
607 
608  using program_t = Program; //< Program type alias.
609  using exec_stk_t = emp::vector<State>; //< Execution Stack/Core type alias.
611  using fun_event_handler_t = std::function<void(EventDrivenGP_t &, const event_t &)>;
612 
613  protected:
614  Ptr<const event_lib_t> event_lib; //< Pointer to const event library associated with this hardware.
615  Ptr<Random> random_ptr; //< Pointer to random object to use.
616  bool random_owner; //< Does this hardware own it's random object? (necessary for cleanup responsibility resolution)
617  program_t program; //< Hardware's associated program (set of functions).
618  memory_t shared_mem; //< Hardware's shared memory map. All cores have access to the same shared memory.
619  std::deque<event_t> event_queue; //< Hardware's event queue. Where events go to be handled (in order of reception).
620  emp::vector<double> traits; //< Generic traits vector. Whatever uses the hardware must define/keep track of what traits mean.
621  size_t errors; //< Errors committed by hardware while executing. (e.g. divide by 0, etc.)
622  size_t max_cores; //< Maximum number of parallel execution stacks that can be spawned. Increasing this value drastically slows things down.
623  size_t max_call_depth; //< Maximum depth of calls per execution stack.
624  double default_mem_value; //< Default value for memory access.
625  double min_bind_thresh; //< Minimum bit string match threshold for function calls/event binding, etc.
626  bool stochastic_fun_call; //< Are candidate function calls with == binding strength chosen stochastically?
627  emp::vector<exec_stk_t> cores; //< Vector of cores. Not all will be active at all given points in time.
628  emp::vector<size_t> active_cores; //< Vector of active core IDs. Maintains relative ordering or active cores.
629  emp::vector<size_t> inactive_cores; //< Vector of inactive core IDs.
630  std::deque<size_t> pending_cores; //< Queue of core IDs pending activation.
631  size_t exec_core_id; //< core ID of the currently executing core.
632  bool is_executing; //< True when mid-execution of all cores. (On every CPU cycle: execute all cores).
633 
634  // TODO: disallow configuration of hardware while executing. (and any other functions that could sent things into a bad state)
635 
636  public:
640  : event_lib(_elib),
641  random_ptr(rnd), random_owner(false),
642  program(_ilib),
643  shared_mem(),
644  event_queue(),
645  traits(), errors(0),
646  max_cores(DEFAULT_MAX_CORES), max_call_depth(DEFAULT_MAX_CALL_DEPTH),
647  default_mem_value(DEFAULT_MEM_VALUE), min_bind_thresh(DEFAULT_MIN_BIND_THRESH),
648  stochastic_fun_call(true),
649  cores(max_cores), active_cores(), inactive_cores(max_cores), pending_cores(),
650  exec_core_id(0), is_executing(false)
651  {
652  // If no random provided, create one.
653  if (!rnd) NewRandom();
654  // Add all available cores to inactive.
655  for (size_t i = 0; i < inactive_cores.size(); ++i)
656  inactive_cores[i] = (inactive_cores.size() - 1) - i;
657  // Spin up main core (will spin up on function ID = 0).
658  SpawnCore(0, memory_t(), true);
659  }
660 
661  EventDrivenGP_AW(inst_lib_t & _ilib, event_lib_t & _elib, Ptr<Random> rnd=nullptr)
662  : EventDrivenGP_AW(&_ilib, &_elib, rnd) { ; }
663 
665  : EventDrivenGP_AW(DefaultInstLib(), _elib, rnd) { ; }
666 
669 
671  : event_lib(in.event_lib),
672  random_ptr(in.random_ptr), random_owner(in.random_owner),
673  program(in.program),
674  shared_mem(in.shared_mem),
675  event_queue(in.event_queue),
676  traits(in.traits), errors(in.errors),
677  max_cores(in.max_cores), max_call_depth(in.max_call_depth),
678  default_mem_value(in.default_mem_value), min_bind_thresh(in.min_bind_thresh),
679  stochastic_fun_call(in.stochastic_fun_call),
680  cores(in.cores),
681  active_cores(in.active_cores), inactive_cores(in.inactive_cores),
682  pending_cores(in.pending_cores),
683  exec_core_id(in.exec_core_id), is_executing(in.is_executing)
684  {
685  in.random_ptr = nullptr;
686  in.random_owner = false;
687  in.event_lib = nullptr;
688  in.program.inst_lib = nullptr;
689  }
690 
692  : event_lib(in.event_lib),
693  random_ptr(nullptr), random_owner(false),
694  program(in.program),
695  shared_mem(in.shared_mem),
696  event_queue(in.event_queue),
697  traits(in.traits), errors(in.errors),
698  max_cores(in.max_cores), max_call_depth(in.max_call_depth),
699  default_mem_value(in.default_mem_value), min_bind_thresh(in.min_bind_thresh),
700  stochastic_fun_call(in.stochastic_fun_call),
701  cores(in.cores),
702  active_cores(in.active_cores), inactive_cores(in.inactive_cores),
703  pending_cores(in.pending_cores),
704  exec_core_id(in.exec_core_id), is_executing(in.is_executing)
705  {
706  if (in.random_owner) NewRandom();
707  else random_ptr = in.random_ptr;
708  }
709 
711  if (random_owner) random_ptr.Delete();
712  }
713 
714  // ---------- Hardware Control ----------
717  void Reset() {
718  emp_assert(!is_executing);
719  ResetHardware();
720  traits.clear();
721  program.Clear();
722  }
723 
726  void ResetHardware() {
727  emp_assert(!is_executing);
728  shared_mem.clear();
729  event_queue.clear();
730  for (size_t i = 0; i < cores.size(); ++i) cores[i].clear();
731  active_cores.clear();
732  pending_cores.clear();
733  inactive_cores.resize(max_cores);
734  // Add all available cores to inactive.
735  for (size_t i = 0; i < inactive_cores.size(); ++i)
736  inactive_cores[i] = (inactive_cores.size() - 1) - i;
737  exec_core_id = (size_t)-1;
738  errors = 0;
739  is_executing = false;
740  }
741 
746  void SpawnCore(const affinity_t & affinity, double threshold, const memory_t & input_mem=memory_t(), bool is_main=false) {
747  if (!inactive_cores.size()) return; // If there are no unclaimed cores, just return.
748  size_t fID;
749  emp::vector<size_t> best_matches(FindBestFuncMatch(affinity, threshold));
750  if (best_matches.empty()) return;
751  if (best_matches.size() == 1.0) fID = best_matches[0];
752  else if (stochastic_fun_call) fID = best_matches[(size_t)random_ptr->GetUInt(0, best_matches.size())];
753  else fID = best_matches[0];
754  SpawnCore(fID, input_mem, is_main);
755  }
756 
760  void SpawnCore(size_t fID, const memory_t & input_mem=memory_t(), bool is_main=false) {
761  if (!inactive_cores.size()) return; // If there are no unclaimed cores, just return.
762  // Which core should we spin up?
763  size_t core_id = inactive_cores.back();
764  inactive_cores.pop_back(); // Claim that core!
765  exec_stk_t & exec_stk = cores[core_id];
766  exec_stk.clear(); // Make sure we clear out the core (in case anyone left behind their dirty laundry).
767  exec_stk.emplace_back(default_mem_value, is_main);
768  State & state = exec_stk.back();
769  state.input_mem = input_mem;
770  state.SetIP(0);
771  state.SetFP(fID);
772  // Spin up new core.
773  // Mark core as pending if currently executing; otherwise, mark it as active.
774  if (is_executing) pending_cores.push_back(core_id);
775  else active_cores.push_back(core_id);
776  }
777 
778  // ---------- Accessors ----------
780  Ptr<const inst_lib_t> GetInstLib() const { return program.GetInstLib(); }
781 
784 
786  Random & GetRandom() { return *random_ptr; }
787 
790 
792  const program_t & GetConstProgram() const { return program; }
793  program_t & GetProgram() { return program; }
794 
795 
797  const Function & GetFunction(size_t fID) const {
799  return program[fID];
800  }
801 
803  const inst_t & GetInst(size_t fID, size_t pos) const {
804  emp_assert(ValidPosition(fID, pos));
805  return program[fID].inst_seq[pos];
806  }
807 
809  double GetTrait(size_t id) const { emp_assert(id < traits.size()); return traits[id]; }
810 
812  size_t GetNumErrors() const { return errors; }
813 
816  double GetMinBindThresh() const { return min_bind_thresh; }
817 
819  size_t GetMaxCores() const { return max_cores; }
820 
822  size_t GetMaxCallDepth() const { return max_call_depth; }
823 
826 
829  bool IsStochasticFunCall() const { return stochastic_fun_call; }
830 
834 
838  size_t GetCurCoreID() { return exec_core_id; }
839 
841  exec_stk_t & GetCurCore() { emp_assert(exec_core_id < cores.size()); return cores[exec_core_id]; }
842 
845  emp_assert(exec_core_id < cores.size() && cores[exec_core_id].size());
846  return cores[exec_core_id].back();
847  }
848 
851 
854  mem_val_t GetShared(mem_key_t key) const { return Find(shared_mem, key, default_mem_value); }
855 
859  if (!Has(shared_mem, key)) shared_mem[key] = default_mem_value;
860  return (shared_mem)[key];
861  }
862 
863  // ------- Configuration -------
866  void SetMinBindThresh(double val) {
867  emp_assert(val >= 0.0);
868  min_bind_thresh = emp::Max(val, 0.0);
869  }
870 
877  void SetMaxCores(size_t val) {
878  emp_assert(val > 0 && !is_executing);
879  // Resize cores to max_cores.
880  cores.resize(val);
881  if (val > max_cores) {
882  // Increasing total available cores, add new cores to inactive_cores vector.
883  // To decrease risk of unexpected behavior, maintain reverse ordering of inactive_cores.
884  // - Because this is a configuration function, it's fine for it to be pretty slow. As such, I'll take the easy way out here.
885  for (size_t i = max_cores; i < val; i++)
886  inactive_cores.insert(inactive_cores.begin(), i);
887  } else if (val < max_cores) {
888  // Decreasing total available cores, adjust active and inactive core vectors (maintain relative ordering in each).
889  // - No need to worry about pending core queue as SetMaxCores is ill-defined/not allowed when is_executing is true.
890  // Fix active_cores (maintain relative ordering).
891  size_t ac_idx = 0;
892  size_t ac_cnt = active_cores.size();
893  size_t ac_adjust = 0;
894  while (ac_idx < ac_cnt) {
895  size_t core_id = active_cores[ac_idx];
896  if (core_id >= val) { // Do we need to eliminate this core_id from active cores?
897  // If yes, set to -1 and increment adjust.
898  active_cores[ac_idx - ac_adjust] = (size_t)-1;
899  ++ac_adjust;
900  } else if (ac_adjust) { // Still valid core ID, so do we need to defragment?
901  active_cores[ac_idx] = (size_t)-1;
902  active_cores[ac_idx - ac_adjust] = core_id;
903  }
904  ++ac_idx;
905  }
906  active_cores.resize(ac_cnt - ac_adjust);
907  // Fix inactive cores (maintain relative ordering).
908  size_t ic_idx = 0;
909  size_t ic_cnt = inactive_cores.size();
910  size_t ic_adjust = 0;
911  while (ic_idx < ic_cnt) {
912  size_t core_id = inactive_cores[ic_idx];
913  if (core_id >= val) { // Do we need to eliminate this core_id from inactive cores?
914  // If yes, set to -1 and increment adjust.
915  inactive_cores[ic_idx - ic_adjust] = (size_t)-1;
916  ++ic_adjust;
917  } else if (ic_adjust) { // Still valid core ID, so do we need to defragment?
918  inactive_cores[ic_idx] = (size_t)-1;
919  inactive_cores[ic_idx - ic_adjust] = core_id;
920  }
921  ++ic_idx;
922  }
923  inactive_cores.resize(ic_cnt - ic_adjust);
924  // Make sure exec_core_id is still valid.
925  if (active_cores.size()) exec_core_id = active_cores[0];
926  } // No need to do anything if val == max_cores.
927 
928  max_cores = val; // Update max_cores.
929  }
930 
934  void SetMaxCallDepth(size_t val) { emp_assert(val > 0); max_call_depth = val; }
935 
938  default_mem_value = val;
939  // Propagate default mem value through execution stacks.
940  for (size_t i = 0; i < cores.size(); ++i)
941  for (size_t k = 0; k < cores[i].size(); ++k)
942  cores[i][k].SetDefaultMemValue(val);
943  }
944 
947  void SetStochasticFunCall(bool val) { stochastic_fun_call = val; }
948 
951  void SetTrait(size_t id, double val) {
952  if (id >= traits.size()) traits.resize(id+1, 0.0);
953  traits[id] = val;
954  }
955 
958  void IncTrait(size_t id, double inc=1.0) {
959  if (id >= traits.size()) traits.resize(id+1, 0.0);
960  traits[id] += inc;
961  }
962 
965  void DecTrait(size_t id, double dec=1.0) {
966  if (id >= traits.size()) traits.resize(id+1, 0.0);
967  traits[id] -= dec;
968  }
969 
971  void PushTrait(double val) { traits.emplace_back(val); }
972 
974  void SetInst(size_t fID, size_t pos, const inst_t & inst) {
975  emp_assert(ValidPosition(fID, pos));
976  program.SetInst(fID, pos, inst);
977  }
978 
980  void SetInst(size_t fID, size_t pos, size_t id, arg_t a0=0, arg_t a1=0, arg_t a2=0,
981  const affinity_t & aff=affinity_t()) {
982  emp_assert(ValidPosition(fID, pos));
983  program.SetInst(fID, pos, id, a0, a1, a2, aff);
984  }
985 
987  void SetProgram(const program_t & _program) { program = _program; }
988 
990  void PushFunction(const Function & _function) { program.PushFunction(_function); }
991 
993  void PushFunction(const affinity_t & _aff=affinity_t(), const inst_seq_t & _seq=inst_seq_t()) {
994  program.PushFunction(_aff, _seq);
995  }
996 
1001  void PushInst(size_t id, arg_t a0=0, arg_t a1=0, arg_t a2=0,
1002  const affinity_t & aff=affinity_t(), int fID=-1)
1003  { program.PushInst(id, a0, a1, a2, aff, fID); }
1004 
1009  void PushInst(const std::string & name, arg_t a0=0, arg_t a1=0, arg_t a2=0,
1010  const affinity_t & aff=affinity_t(), int fID=-1)
1011  { program.PushInst(name, a0, a1, a2, aff, fID); }
1012 
1017  void PushInst(const inst_t & inst, int fID=-1) { program.PushInst(inst, fID); }
1018 
1028  void Load(std::istream & input) { program.Load(input); }
1029 
1030  // ---------- Hardware Utilities ----------
1032  void NewRandom(int seed=-1) {
1033  if (random_owner) random_ptr.Delete();
1034  else random_ptr = nullptr;
1035  random_ptr.New(seed);
1036  random_owner = true;
1037  }
1038 
1041  bool ValidPosition(size_t fID, size_t pos) const { return program.ValidPosition(fID, pos); }
1042 
1044  bool ValidFunction(size_t fID) const { return program.ValidFunction(fID); }
1045 
1047  void SetShared(mem_key_t key, mem_val_t value) { shared_mem[key] = value; }
1048 
1051  size_t FindEndOfBlock(size_t fp, size_t ip) {
1053  Ptr<const inst_lib_t> inst_lib = program.inst_lib;
1054  int depth_counter = 1;
1055  while (true) {
1056  if (!ValidPosition(fp, ip)) break;
1057  const inst_t & inst = GetInst(fp, ip);
1058  if (inst_lib->HasProperty(inst.id, "block_def")) {
1059  ++depth_counter;
1060  } else if (inst_lib->HasProperty(inst.id, "block_close")) {
1061  --depth_counter;
1062  // If depth is ever 0 after subtracting, we've found the close for initial block.
1063  if (depth_counter == 0) break;
1064  }
1065  ++ip;
1066  }
1067  return ip;
1068  }
1069 
1074  void CloseBlock() {
1075  State & state = GetCurState();
1076  // If there aren't any blocks to close, just return.
1077  if (state.block_stack.empty()) return;
1078  Block & block = state.block_stack.back();
1079  // Any special circumstances (e.g. looping) go below:
1080  switch (block.type) {
1081  case BlockType::LOOP:
1082  // Move IP to beginning of block.
1083  state.SetIP(block.begin);
1084  break;
1085  default:
1086  break;
1087  }
1088  // Pop the block.
1089  state.block_stack.pop_back();
1090  }
1091 
1093  void OpenBlock(size_t begin, size_t end, BlockType type) {
1094  State & state = GetCurState();
1095  state.block_stack.emplace_back(begin, end, type);
1096  }
1097 
1100  void BreakBlock() {
1101  State & state = GetCurState();
1102  if (!state.block_stack.empty()) {
1103  state.SetIP(state.block_stack.back().end);
1104  state.block_stack.pop_back();
1105  if (ValidPosition(state.GetFP(), state.GetIP())) state.AdvanceIP();
1106  }
1107  }
1108 
1110  emp::vector<size_t> FindBestFuncMatch(const affinity_t & affinity, double threshold) {
1111  emp::vector<size_t> best_matches;
1112  for (size_t i=0; i < program.GetSize(); ++i) {
1113  double bind = SimpleMatchCoeff(program[i].affinity, affinity);
1114  if (bind == threshold) best_matches.push_back(i);
1115  else if (bind > threshold) {
1116  best_matches.resize(1);
1117  best_matches[0] = i;
1118  threshold = bind;
1119  }
1120  }
1121  return best_matches;
1122  }
1123 
1126  void CallFunction(const affinity_t & affinity, double threshold) {
1127  // Are we at max call depth? -- If so, call fails.
1128  if (GetCurCore().size() >= max_call_depth) return;
1129  size_t fID;
1130  emp::vector<size_t> best_matches(FindBestFuncMatch(affinity, threshold));
1131  if (best_matches.empty()) return;
1132  if (best_matches.size() == 1.0) fID = best_matches[0];
1133  else if (stochastic_fun_call) fID = best_matches[(size_t)random_ptr->GetUInt(0, best_matches.size())];
1134  else fID = best_matches[0];
1135  CallFunction(fID);
1136  }
1137 
1140  void CallFunction(size_t fID) {
1141  emp_assert(ValidPosition(fID, 0));
1142  exec_stk_t & core = GetCurCore();
1143  // Are we at max call depth? -- If so, call fails.
1144  if (core.size() >= max_call_depth) return;
1145  // Push new state onto stack.
1146  core.emplace_back();
1147  State & new_state = core.back();
1148  State & caller_state = core[core.size() - 2];
1149  // Configure new state.
1150  new_state.SetFP(fID);
1151  new_state.SetIP(0);
1152  for (auto mem : caller_state.local_mem) {
1153  new_state.SetInput(mem.first, mem.second);
1154  }
1155  }
1156 
1160  // Grab the returning state and then pop it off the call stack.
1161  State & returning_state = GetCurState();
1162  // No returning from main.
1163  if (returning_state.IsMain()) return;
1164  // Is there anything to return to?
1165  exec_stk_t & core = GetCurCore();
1166  if (core.size() > 1) {
1167  // If so, copy returning state's output memory into caller state's local memory.
1168  State & caller_state = core[core.size() - 2];
1169  for (auto mem : returning_state.output_mem) caller_state.SetLocal(mem.first, mem.second);
1170  }
1171  // Pop returned state.
1172  core.pop_back();
1173  }
1174 
1175  // ---------- Hardware Execution ----------
1177  void ProcessInst(const inst_t & inst) { program.inst_lib->ProcessInst(*this, inst); }
1178 
1180  void HandleEvent(const event_t & event) { event_lib->HandleEvent(*this, event); }
1181 
1183  void TriggerEvent(const event_t & event) { event_lib->TriggerEvent(*this, event); }
1184 
1186  void TriggerEvent(const std::string & name, const affinity_t & affinity=affinity_t(),
1187  const memory_t & msg=memory_t(), const properties_t & properties=properties_t()) {
1188  const size_t id = event_lib->GetID(name);
1189  event_t event(id, affinity, msg, properties);
1190  event_lib->TriggerEvent(*this, event);
1191  }
1192 
1194  void TriggerEvent(size_t id, const affinity_t & affinity=affinity_t(),
1195  const memory_t & msg=memory_t(), const properties_t & properties=properties_t()) {
1196  event_t event(id, affinity, msg, properties);
1197  event_lib->TriggerEvent(*this, event);
1198  }
1199 
1201  void QueueEvent(const event_t & event) { event_queue.emplace_back(event); }
1202 
1204  void QueueEvent(const std::string & name, const affinity_t & affinity=affinity_t(),
1205  const memory_t & msg=memory_t(), const properties_t & properties=properties_t()) {
1206  const size_t id = event_lib->GetID(name);
1207  event_queue.emplace_back(id, affinity, msg, properties);
1208  }
1209 
1211  void QueueEvent(size_t id, const affinity_t & affinity=affinity_t(),
1212  const memory_t & msg=memory_t(), const properties_t & properties=properties_t()) {
1213  event_queue.emplace_back(id, affinity, msg, properties);
1214  }
1215 
1217  void SingleProcess() {
1218  emp_assert(program.GetSize()); // Must have a program before this is allowed.
1219  // Handle events.
1220  while (!event_queue.empty()) {
1221  HandleEvent(event_queue.front());
1222  event_queue.pop_front();
1223  }
1224  // Distribute 1 unit of computational time to each core.
1225  size_t active_core_idx = 0;
1226  size_t core_cnt = active_cores.size();
1227  size_t adjust = 0;
1228  is_executing = true;
1229  while (active_core_idx < core_cnt) {
1230  // Set the current core to core at core_idx.
1231  exec_core_id = active_cores[active_core_idx]; // Here's the core we're about to execute.
1232  // Do we need to move current core over in the execution core vector to make it contiguous?
1233  if (adjust) {
1234  active_cores[active_core_idx] = (size_t)-1;
1235  active_cores[active_core_idx - adjust] = exec_core_id;
1236  }
1237  // Execute the core.
1238  // * What function/instruction am I on?
1239  State & cur_state = GetCurState();
1240  const size_t ip = cur_state.inst_ptr;
1241  const size_t fp = cur_state.func_ptr;
1242  // fp needs to be valid here (and always, really). Shame shame if it's not.
1244  // If instruction pointer hanging off end of function sequence:
1245  if (ip >= program[fp].GetSize()) {
1246  if (!cur_state.block_stack.empty()) {
1247  // - If there's a block to close, close it.
1248  CloseBlock();
1249  } else if (cur_state.is_main && GetCurCore().size() == 1) {
1250  // - If this is the main function, and we're at the bottom of the call stack, wrap.
1251  cur_state.inst_ptr = 0;
1252  } else {
1253  // - Otherwise, return from function call.
1254  ReturnFunction(); // NOTE: This might invalidate our cur_state reference.
1255  }
1256  } else { // If instruction pointer is valid:
1257  // First, advance the instruction pointer by 1. This may invalidate the IP, but that's okay.
1258  cur_state.inst_ptr += 1;
1259  // Run instruction @ fp, ip.
1260  program.inst_lib->ProcessInst(*this, program[fp].inst_seq[ip]);
1261  }
1262  // After processing, is the core still active?
1263  if (GetCurCore().empty()) {
1264  // Free core. Mark as inactive.
1265  active_cores[active_core_idx - adjust] = (size_t)-1;
1266  inactive_cores.emplace_back(exec_core_id);
1267  ++adjust;
1268  }
1269  ++active_core_idx;
1270  }
1271  is_executing = false;
1272  // Update execution stack size to be accurate.
1273  active_cores.resize(core_cnt - adjust);
1274  // Spawn any cores that happened during execution.
1275  while (pending_cores.size()) {
1276  active_cores.emplace_back(pending_cores.front());
1277  pending_cores.pop_front();
1278  }
1279  // Set cur core to be first execution stack (which should always be main).
1280  if (active_cores.size()) exec_core_id = active_cores[0];
1281  }
1282 
1284  void Process(size_t num_inst) {
1285  for (size_t i = 0; i < num_inst; i++) SingleProcess();
1286  }
1287 
1288  // ---------- Printing ----------
1290  void PrintEvent(const event_t & event, std::ostream & os=std::cout) {
1291  os << "[" << event_lib->GetName(event.id) << ","; event.affinity.Print(os); os << ",(";
1292  for (const auto & mem : event.msg) std::cout << "{" << mem.first << ":" << mem.second << "}";
1293  os << "),(Properties:";
1294  for (const auto & property : event.properties) std::cout << " " << property;
1295  os << ")]";
1296  }
1297 
1299  void PrintInst(const inst_t & inst, std::ostream & os=std::cout) {
1300  program.PrintInst(inst, os);
1301  }
1302 
1304  void PrintTraits(std::ostream & os=std::cout) {
1305  if (traits.size() == 0) { os << "[]"; return; }
1306  os << "[";
1307  for (size_t i = 0; i < traits.size() - 1; ++i) {
1308  os << traits[i] << ", ";
1309  } os << traits[traits.size() - 1] << "]";
1310  }
1311 
1313  void PrintProgram(std::ostream & os=std::cout) {
1314  program.PrintProgram(os);
1315  }
1316 
1318  void PrintProgramFull(std::ostream & os=std::cout) {
1319  program.PrintProgramFull(os);
1320  }
1321 
1323  void PrintState(std::ostream & os=std::cout) {
1324  // Print format:
1325  // Shared memory: [Key:value, ....]
1326  // Core 0:
1327  // Call Stack (stack size):
1328  // State
1329  // ---
1330  // State
1331  // ---
1332  // ...
1333  // Print shared memory
1334  os << "Shared memory: ";
1335  for (auto mem : shared_mem) os << '{' << mem.first << ':' << mem.second << '}'; os << '\n';
1336  os << "Traits: "; PrintTraits(os); os << "\n";
1337  os << "Errors: " << errors << "\n";
1338  // Print events.
1339  os << "Event queue: ";
1340  for (auto event : event_queue) { PrintEvent(event, os); os << " "; }
1341  os << "\n";
1342  // Print each active core.
1343  for (size_t i = 0; i < active_cores.size(); ++i) {
1344  size_t core_id = active_cores[i];
1345  const exec_stk_t & core = cores[core_id];
1346  os << "Core " << i << "(CID=" << core_id << "):\n" << " Call stack (" << core.size() << "):\n --TOP--\n";
1347  for (size_t k = core.size() - 1; k < core.size(); --k) {
1348  emp_assert(core.size() != (size_t)-1);
1349  // IP, FP, local mem, input mem, output mem
1350  const State & state = core[k];
1351  os << " Inst ptr: " << state.inst_ptr << " (";
1352  if (ValidPosition(state.func_ptr, state.inst_ptr))
1353  PrintInst(GetInst(state.func_ptr, state.inst_ptr), os);
1354  else
1355  os << "NONE";
1356  os << ")" << "\n";
1357  os << " Func ptr: " << state.func_ptr << "\n";
1358  os << " Input memory: ";
1359  for (auto mem : state.input_mem) os << "{" << mem.first << ":" << mem.second << "}"; os << "\n";
1360  os << " Local memory: ";
1361  for (auto mem : state.local_mem) os << "{" << mem.first << ":" << mem.second << "}"; os << "\n";
1362  os << " Output memory: ";
1363  for (auto mem : state.output_mem) os << "{" << mem.first << ":" << mem.second << "}"; os << "\n";
1364  os << " ---\n";
1365  }
1366  }
1367  }
1368 
1369  // -- Default Instructions --
1373  static void Inst_Inc(EventDrivenGP_t & hw, const inst_t & inst) {
1374  State & state = hw.GetCurState();
1375  ++state.AccessLocal(inst.args[0]);
1376  }
1377 
1381  static void Inst_Dec(EventDrivenGP_t & hw, const inst_t & inst) {
1382  State & state = hw.GetCurState();
1383  --state.AccessLocal(inst.args[0]);
1384  }
1385 
1389  static void Inst_Not(EventDrivenGP_t & hw, const inst_t & inst) {
1390  State & state = hw.GetCurState();
1391  state.SetLocal(inst.args[0], state.GetLocal(inst.args[0]) == 0.0);
1392  }
1393 
1397  static void Inst_Add(EventDrivenGP_t & hw, const inst_t & inst) {
1398  State & state = hw.GetCurState();
1399  state.SetLocal(inst.args[2], state.AccessLocal(inst.args[0]) + state.AccessLocal(inst.args[1]));
1400  }
1401 
1405  static void Inst_Sub(EventDrivenGP_t & hw, const inst_t & inst) {
1406  State & state = hw.GetCurState();
1407  state.SetLocal(inst.args[2], state.AccessLocal(inst.args[0]) - state.AccessLocal(inst.args[1]));
1408  }
1409 
1413  static void Inst_Mult(EventDrivenGP_t & hw, const inst_t & inst) {
1414  State & state = hw.GetCurState();
1415  state.SetLocal(inst.args[2], state.AccessLocal(inst.args[0]) * state.AccessLocal(inst.args[1]));
1416  }
1417 
1422  static void Inst_Div(EventDrivenGP_t & hw, const inst_t & inst) {
1423  State & state = hw.GetCurState();
1424  const double denom = state.AccessLocal(inst.args[1]);
1425  if (denom == 0.0) ++hw.errors;
1426  else state.SetLocal(inst.args[2], state.AccessLocal(inst.args[0]) / denom);
1427  }
1428 
1433  static void Inst_Mod(EventDrivenGP_t & hw, const inst_t & inst) {
1434  State & state = hw.GetCurState();
1435  const int base = (int)state.AccessLocal(inst.args[1]);
1436  const int num = (int)state.AccessLocal(inst.args[0]);
1437  if (base == 0) ++hw.errors;
1438  else state.SetLocal(inst.args[2], static_cast<int64_t>(num) % static_cast<int64_t>(base));
1439  }
1440 
1444  static void Inst_TestEqu(EventDrivenGP_t & hw, const inst_t & inst) {
1445  State & state = hw.GetCurState();
1446  state.SetLocal(inst.args[2], state.AccessLocal(inst.args[0]) == state.AccessLocal(inst.args[1]));
1447  }
1448 
1452  static void Inst_TestNEqu(EventDrivenGP_t & hw, const inst_t & inst) {
1453  State & state = hw.GetCurState();
1454  state.SetLocal(inst.args[2], state.AccessLocal(inst.args[0]) != state.AccessLocal(inst.args[1]));
1455  }
1456 
1460  static void Inst_TestLess(EventDrivenGP_t & hw, const inst_t & inst) {
1461  State & state = hw.GetCurState();
1462  state.SetLocal(inst.args[2], state.AccessLocal(inst.args[0]) < state.AccessLocal(inst.args[1]));
1463  }
1464 
1468  static void Inst_If(EventDrivenGP_t & hw, const inst_t & inst) {
1469  State & state = hw.GetCurState();
1470  // Find EOBLK.
1471  size_t eob = hw.FindEndOfBlock(state.GetFP(), state.GetIP());
1472  if (state.AccessLocal(inst.args[0]) == 0.0) {
1473  // Skip to EOBLK.
1474  state.SetIP(eob);
1475  // Advance past the block close if not at eofun.
1476  if (hw.ValidPosition(state.GetFP(), eob)) state.AdvanceIP();
1477  } else {
1478  // Open BLK
1479  hw.OpenBlock(state.GetIP() - 1, eob, BlockType::BASIC);
1480  }
1481  }
1482 
1486  static void Inst_While(EventDrivenGP_t & hw, const inst_t & inst) {
1487  State & state = hw.GetCurState();
1488  size_t eob = hw.FindEndOfBlock(state.GetFP(), state.GetIP());
1489  if (state.AccessLocal(inst.args[0]) == 0.0) {
1490  // Skip to EOBLK.
1491  state.SetIP(eob);
1492  // Advance past the block close if not at eofun.
1493  if (hw.ValidPosition(state.GetFP(), eob)) state.AdvanceIP();
1494  } else {
1495  // Open blk.
1496  hw.OpenBlock(state.GetIP() - 1, eob, BlockType::LOOP);
1497  }
1498  }
1499 
1503  static void Inst_Countdown(EventDrivenGP_t & hw, const inst_t & inst) {
1504  State & state = hw.GetCurState();
1505  size_t eob = hw.FindEndOfBlock(state.GetFP(), state.GetIP());
1506  if (state.AccessLocal(inst.args[0]) == 0.0) {
1507  // Skip to EOBLK.
1508  state.SetIP(eob);
1509  // Advance past the block close if not at eofun.
1510  if (hw.ValidPosition(state.GetFP(), eob)) state.AdvanceIP();
1511  } else {
1512  // Decrement Arg1
1513  --state.AccessLocal(inst.args[0]);
1514  // Open blk.
1515  hw.OpenBlock(state.GetIP() - 1, eob, BlockType::LOOP);
1516  }
1517  }
1518 
1522  static void Inst_Break(EventDrivenGP_t & hw, const inst_t & inst) {
1523  hw.BreakBlock();
1524  }
1525 
1529  static void Inst_Close(EventDrivenGP_t & hw, const inst_t & inst) {
1530  hw.CloseBlock();
1531  }
1532 
1536  static void Inst_Call(EventDrivenGP_t & hw, const inst_t & inst) {
1537  hw.CallFunction(inst.affinity, hw.GetMinBindThresh());
1538  }
1539 
1543  static void Inst_Return(EventDrivenGP_t & hw, const inst_t & inst) {
1544  hw.ReturnFunction();
1545  }
1546 
1550  static void Inst_SetMem(EventDrivenGP_t & hw, const inst_t & inst) {
1551  State & state = hw.GetCurState();
1552  state.SetLocal(inst.args[0], (double)inst.args[1]);
1553  }
1554 
1558  static void Inst_CopyMem(EventDrivenGP_t & hw, const inst_t & inst) {
1559  State & state = hw.GetCurState();
1560  state.SetLocal(inst.args[1], state.AccessLocal(inst.args[0]));
1561  }
1562 
1566  static void Inst_SwapMem(EventDrivenGP_t & hw, const inst_t & inst) {
1567  State & state = hw.GetCurState();
1568  double val0 = state.AccessLocal(inst.args[0]);
1569  state.SetLocal(inst.args[0], state.GetLocal(inst.args[1]));
1570  state.SetLocal(inst.args[1], val0);
1571  }
1572 
1576  static void Inst_Input(EventDrivenGP_t & hw, const inst_t & inst) {
1577  State & state = hw.GetCurState();
1578  state.SetLocal(inst.args[1], state.AccessInput(inst.args[0]));
1579  }
1580 
1584  static void Inst_Output(EventDrivenGP_t & hw, const inst_t & inst) {
1585  State & state = hw.GetCurState();
1586  state.SetOutput(inst.args[1], state.AccessLocal(inst.args[0]));
1587  }
1588 
1592  static void Inst_Commit(EventDrivenGP_t & hw, const inst_t & inst) {
1593  State & state = hw.GetCurState();
1594  hw.SetShared(inst.args[1], state.AccessLocal(inst.args[0]));
1595  }
1596 
1600  static void Inst_Pull(EventDrivenGP_t & hw, const inst_t & inst) {
1601  State & state = hw.GetCurState();
1602  state.SetLocal(inst.args[1], hw.AccessShared(inst.args[0]));
1603  }
1604 
1608  static void Inst_Nop(EventDrivenGP_t & hw, const inst_t & inst) { ; }
1609 
1615  static void Inst_BroadcastMsg(EventDrivenGP_t & hw, const inst_t & inst) {
1616  State & state = hw.GetCurState();
1617  hw.TriggerEvent("Message", inst.affinity, state.output_mem, {"broadcast"});
1618  }
1619 
1625  static void Inst_SendMsg(EventDrivenGP_t & hw, const inst_t & inst) {
1626  State & state = hw.GetCurState();
1627  hw.TriggerEvent("Message", inst.affinity, state.output_mem, {"send"});
1628  }
1629 
1632  static inst_lib_t inst_lib;
1633  if (inst_lib.GetSize() == 0) {
1634  inst_lib.AddInst("Inc", Inst_Inc, 1, "Increment value in local memory Arg1");
1635  inst_lib.AddInst("Dec", Inst_Dec, 1, "Decrement value in local memory Arg1");
1636  inst_lib.AddInst("Not", Inst_Not, 1, "Logically toggle value in local memory Arg1");
1637  inst_lib.AddInst("Add", Inst_Add, 3, "Local memory: Arg3 = Arg1 + Arg2");
1638  inst_lib.AddInst("Sub", Inst_Sub, 3, "Local memory: Arg3 = Arg1 - Arg2");
1639  inst_lib.AddInst("Mult", Inst_Mult, 3, "Local memory: Arg3 = Arg1 * Arg2");
1640  inst_lib.AddInst("Div", Inst_Div, 3, "Local memory: Arg3 = Arg1 / Arg2");
1641  inst_lib.AddInst("Mod", Inst_Mod, 3, "Local memory: Arg3 = Arg1 % Arg2");
1642  inst_lib.AddInst("TestEqu", Inst_TestEqu, 3, "Local memory: Arg3 = (Arg1 == Arg2)");
1643  inst_lib.AddInst("TestNEqu", Inst_TestNEqu, 3, "Local memory: Arg3 = (Arg1 != Arg2)");
1644  inst_lib.AddInst("TestLess", Inst_TestLess, 3, "Local memory: Arg3 = (Arg1 < Arg2)");
1645  inst_lib.AddInst("If", Inst_If, 1, "Local memory: If Arg1 != 0, proceed; else, skip block.", ScopeType::BASIC, 0, {"block_def"});
1646  inst_lib.AddInst("While", Inst_While, 1, "Local memory: If Arg1 != 0, loop; else, skip block.", ScopeType::BASIC, 0, {"block_def"});
1647  inst_lib.AddInst("Countdown", Inst_Countdown, 1, "Local memory: Countdown Arg1 to zero.", ScopeType::BASIC, 0, {"block_def"});
1648  inst_lib.AddInst("Close", Inst_Close, 0, "Close current block if there is a block to close.", ScopeType::BASIC, 0, {"block_close"});
1649  inst_lib.AddInst("Break", Inst_Break, 0, "Break out of current block.");
1650  inst_lib.AddInst("Call", Inst_Call, 0, "Call function that best matches call affinity.", ScopeType::BASIC, 0, {"affinity"});
1651  inst_lib.AddInst("Return", Inst_Return, 0, "Return from current function if possible.");
1652  inst_lib.AddInst("SetMem", Inst_SetMem, 2, "Local memory: Arg1 = numerical value of Arg2");
1653  inst_lib.AddInst("CopyMem", Inst_CopyMem, 2, "Local memory: Arg1 = Arg2");
1654  inst_lib.AddInst("SwapMem", Inst_SwapMem, 2, "Local memory: Swap values of Arg1 and Arg2.");
1655  inst_lib.AddInst("Input", Inst_Input, 2, "Input memory Arg1 => Local memory Arg2.");
1656  inst_lib.AddInst("Output", Inst_Output, 2, "Local memory Arg1 => Output memory Arg2.");
1657  inst_lib.AddInst("Commit", Inst_Commit, 2, "Local memory Arg1 => Shared memory Arg2.");
1658  inst_lib.AddInst("Pull", Inst_Pull, 2, "Shared memory Arg1 => Shared memory Arg2.");
1659  inst_lib.AddInst("BroadcastMsg", Inst_BroadcastMsg, 0, "Broadcast output memory as message event.", ScopeType::BASIC, 0, {"affinity"});
1660  inst_lib.AddInst("SendMsg", Inst_SendMsg, 0, "Send output memory as message event.", ScopeType::BASIC, 0, {"affinity"});
1661  inst_lib.AddInst("Nop", Inst_Nop, 0, "No operation.");
1662  }
1663  return &inst_lib;
1664  }
1665 
1670  static void HandleEvent_Message(EventDrivenGP_t & hw, const event_t & event) {
1671  // Spawn new core.
1672  hw.SpawnCore(event.affinity, hw.GetMinBindThresh(), event.msg);
1673  }
1674 
1679  static event_lib_t event_lib;
1680  if (event_lib.GetSize() == 0) {
1681  event_lib.AddEvent("Message", HandleEvent_Message, "Event for exchanging messages (agent-agent, world-agent, etc.)");
1682  }
1683  return &event_lib;
1684  }
1685  };
1686 
1689 }
1690 
1691 #endif
Instruction(size_t _id=0, arg_t a0=0, arg_t a1=0, arg_t a2=0, const affinity_t &_aff=affinity_t())
Definition: EventDrivenGP.h:271
static std::string string_get_range(const std::string &in_string, std::size_t start_pos, std::size_t end_pos)
Get a segment from the beginning of a string as another string, leaving original untouched.
Definition: string_utils.h:295
Program(Ptr< const inst_lib_t > _ilib, const program_t &_prgm=program_t())
Definition: EventDrivenGP.h:361
void SingleProcess()
Advance hardware by single instruction.
Definition: EventDrivenGP.h:1217
void SetInst(size_t fID, size_t pos, size_t id, arg_t a0=0, arg_t a1=0, arg_t a2=0, const affinity_t &aff=affinity_t())
Definition: EventDrivenGP.h:441
static const std::string & empty_string()
Definition: string_utils.h:29
BlockType
Definition: EventDrivenGP.h:144
bool ValidFunction(size_t fID) const
Definition: EventDrivenGP.h:392
iterator insert(ARGS &&...args)
Definition: vector.h:201
static void Inst_TestLess(EventDrivenGP_t &hw, const inst_t &inst)
Definition: EventDrivenGP.h:1460
void QueueEvent(const std::string &name, const affinity_t &affinity=affinity_t(), const memory_t &msg=memory_t(), const properties_t &properties=properties_t())
Queue event by name.
Definition: EventDrivenGP.h:1204
Random & GetRandom()
Get reference to random number generator used by this hardware.
Definition: EventDrivenGP.h:786
size_t GetInstCnt() const
Get the total number of instructions across all functions that make up this program.
Definition: EventDrivenGP.h:381
const Function & operator[](size_t id) const
Definition: EventDrivenGP.h:368
size_t GetNumErrors() const
Get current number of errors committed by this hardware.
Definition: EventDrivenGP.h:812
std::function< void(EventDrivenGP_t &, const event_t &)> fun_event_handler_t
Event handler function type alias.
Definition: EventDrivenGP.h:611
emp::vector< exec_stk_t > & GetCores()
Definition: EventDrivenGP.h:833
static void Inst_Mod(EventDrivenGP_t &hw, const inst_t &inst)
Definition: EventDrivenGP.h:1433
Ptr< const inst_lib_t > GetInstLib() const
Definition: EventDrivenGP.h:387
static void Inst_Break(EventDrivenGP_t &hw, const inst_t &inst)
Definition: EventDrivenGP.h:1522
size_t id
Definition: EventDrivenGP.h:267
bool is_main
Definition: EventDrivenGP.h:168
void PrintInst(const inst_t &inst, std::ostream &os=std::cout)
Print out a single instruction with its arguments.
Definition: EventDrivenGP.h:532
static void Inst_While(EventDrivenGP_t &hw, const inst_t &inst)
Definition: EventDrivenGP.h:1486
void Set(size_t index, bool value)
Set the bit as a specified index.
Definition: BitSet.h:231
const program_t & GetConstProgram() const
Get program loaded on this hardware.
Definition: EventDrivenGP.h:792
size_t begin
Definition: EventDrivenGP.h:148
inst_seq_t inst_seq
Definition: EventDrivenGP.h:311
This file maintains information about instructions availabel in virtual hardware. ...
static void Inst_SetMem(EventDrivenGP_t &hw, const inst_t &inst)
Definition: EventDrivenGP.h:1550
bool IsMain() const
Is this a main state?
Definition: EventDrivenGP.h:207
bool operator<(const Program &other) const
Definition: EventDrivenGP.h:373
void SetMaxCores(size_t val)
Definition: EventDrivenGP.h:877
static constexpr size_t DEFAULT_MAX_CALL_DEPTH
Definition: EventDrivenGP.h:114
void PrintState(std::ostream &os=std::cout)
Print out current state (full) of virtual hardware using given output stream (default = std::cout)...
Definition: EventDrivenGP.h:1323
void CallFunction(size_t fID)
Definition: EventDrivenGP.h:1140
void CallFunction(const affinity_t &affinity, double threshold)
Definition: EventDrivenGP.h:1126
void SetMinBindThresh(double val)
Definition: EventDrivenGP.h:866
void NewRandom(int seed=-1)
Generate new random number generator for this hardware object with the given seed value...
Definition: EventDrivenGP.h:1032
void SetTrait(size_t id, double val)
Definition: EventDrivenGP.h:951
static void Inst_Nop(EventDrivenGP_t &hw, const inst_t &inst)
Definition: EventDrivenGP.h:1608
void QueueEvent(size_t id, const affinity_t &affinity=affinity_t(), const memory_t &msg=memory_t(), const properties_t &properties=properties_t())
Queue event by id.
Definition: EventDrivenGP.h:1211
void AddEvent(const std::string &name, const fun_t &handler_fun, const std::string &desc="", const properties_t &event_properties=properties_t())
Add a new event to the event library.
Definition: EventLib.h:86
void Delete()
Definition: Ptr.h:737
program_t program
Definition: EventDrivenGP.h:617
bool ValidPosition(size_t fID, size_t pos) const
Definition: EventDrivenGP.h:389
static void Inst_Inc(EventDrivenGP_t &hw, const inst_t &inst)
Definition: EventDrivenGP.h:1373
size_t GetCurCoreID()
Definition: EventDrivenGP.h:838
size_t GetIP() const
Get instruction pointer.
Definition: EventDrivenGP.h:189
emp::vector< size_t > FindBestFuncMatch(const affinity_t &affinity, double threshold)
Find best matching functions (by ID) given affinity.
Definition: EventDrivenGP.h:1110
void SetProgram(const program_t &_program)
Definition: EventDrivenGP.h:394
mem_val_t & AccessLocal(mem_key_t key)
Definition: EventDrivenGP.h:241
affinity_t affinity
Definition: EventDrivenGP.h:269
void SpawnCore(const affinity_t &affinity, double threshold, const memory_t &input_mem=memory_t(), bool is_main=false)
Definition: EventDrivenGP.h:746
void SetInput(mem_key_t key, mem_val_t value)
Set input memory specified by key to value.
Definition: EventDrivenGP.h:234
static void Inst_Close(EventDrivenGP_t &hw, const inst_t &inst)
Definition: EventDrivenGP.h:1529
static void remove_whitespace(std::string &in_string)
Remove all whitespace from anywhere within a string.
Definition: string_utils.h:392
void SetOutput(mem_key_t key, mem_val_t value)
Set output memory specified by key to value.
Definition: EventDrivenGP.h:237
affinity_t & GetAffinity()
Definition: EventDrivenGP.h:330
void Set(size_t _id, arg_t _a0=0, arg_t _a1=0, arg_t _a2=0, const affinity_t &_aff=affinity_t())
Definition: EventDrivenGP.h:279
double min_bind_thresh
Definition: EventDrivenGP.h:625
mem_val_t & AccessShared(mem_key_t key)
Definition: EventDrivenGP.h:858
size_t GetSize() const
Get the number of instructions in this set.
Definition: InstLib.h:99
static void Inst_Input(EventDrivenGP_t &hw, const inst_t &inst)
Definition: EventDrivenGP.h:1576
void PrintTraits(std::ostream &os=std::cout)
Print hardware traits using given output stream (default = std::cout).
Definition: EventDrivenGP.h:1304
static void Inst_Add(EventDrivenGP_t &hw, const inst_t &inst)
Definition: EventDrivenGP.h:1397
const inst_t & GetInst(size_t fID, size_t pos) const
Get reference to particular instruction in hardware&#39;s program given function ID and instruction posit...
Definition: EventDrivenGP.h:803
void TriggerEvent(size_t id, const affinity_t &affinity=affinity_t(), const memory_t &msg=memory_t(), const properties_t &properties=properties_t())
Trigger an event (from this hardware).
Definition: EventDrivenGP.h:1194
void PrintProgram(std::ostream &os=std::cout)
Print out entire program.
Definition: EventDrivenGP.h:555
void SetMaxCallDepth(size_t val)
Definition: EventDrivenGP.h:934
static constexpr size_t DEFAULT_MAX_CORES
Definition: EventDrivenGP.h:113
mem_val_t GetShared(mem_key_t key) const
Definition: EventDrivenGP.h:854
double mem_val_t
Definition: EventDrivenGP.h:105
~EventDrivenGP_AW()
Definition: EventDrivenGP.h:710
std::deque< event_t > event_queue
Definition: EventDrivenGP.h:619
emp::vector< Block > block_stack
Definition: EventDrivenGP.h:167
A versatile and non-patterned pseudo-random-number generator (Mersenne Twister).
Definition: ce_random.h:52
EventDrivenGP_AW(EventDrivenGP_t &&in)
Definition: EventDrivenGP.h:670
static void Inst_Div(EventDrivenGP_t &hw, const inst_t &inst)
Definition: EventDrivenGP.h:1422
std::string string_get_word(const std::string &in_string, size_t start_pos=0)
Return a prefix of a string, up to the first whitespace (do not modify the original string) ...
Definition: string_utils.h:332
affinity_t affinity
Definition: EventDrivenGP.h:310
double default_mem_value
Definition: EventDrivenGP.h:624
memory_t & GetInputMemory()
Get a reference to the input memory map for this state.
Definition: EventDrivenGP.h:213
void Reset()
Definition: EventDrivenGP.h:717
void OpenBlock(size_t begin, size_t end, BlockType type)
Open a block in the current local program state as specified by begin, end, and type.
Definition: EventDrivenGP.h:1093
static void slice(const std::string &in_string, emp::vector< std::string > &out_set, char delim='\n')
Cut up a string based on the provided delimitor; fill them in to the provided vector.
Definition: string_utils.h:421
static void Inst_Countdown(EventDrivenGP_t &hw, const inst_t &inst)
Definition: EventDrivenGP.h:1503
void SetInst(size_t fID, size_t pos, size_t id, arg_t a0=0, arg_t a1=0, arg_t a2=0, const affinity_t &aff=affinity_t())
Shortcut to this hardware object&#39;s program&#39;s SetInst function of the same signature.
Definition: EventDrivenGP.h:980
static void Inst_Pull(EventDrivenGP_t &hw, const inst_t &inst)
Definition: EventDrivenGP.h:1600
static constexpr size_t GetSize()
How many bits are in this BitSet?
Definition: BitSet.h:220
static Ptr< const EventLib< EventDrivenGP_t > > DefaultEventLib()
Definition: EventDrivenGP.h:1678
mem_val_t GetLocal(mem_key_t key) const
Definition: EventDrivenGP.h:220
size_t id
Definition: EventDrivenGP.h:121
void push_back(PB_Ts &&...args)
Definition: vector.h:189
std::unordered_map< mem_key_t, mem_val_t > memory_t
Definition: EventDrivenGP.h:106
void PushTrait(double val)
Push a trait onto end of traits vector.
Definition: EventDrivenGP.h:971
memory_t input_mem
Definition: EventDrivenGP.h:161
mem_val_t GetOutput(mem_key_t key) const
Definition: EventDrivenGP.h:228
void ReturnFunction()
Definition: EventDrivenGP.h:1159
size_t errors
Definition: EventDrivenGP.h:621
EventDrivenGP_AW(inst_lib_t &_ilib, event_lib_t &_elib, Ptr< Random > rnd=nullptr)
Definition: EventDrivenGP.h:661
arg_set_t args
Definition: EventDrivenGP.h:268
bool IsStochasticFunCall() const
Definition: EventDrivenGP.h:829
EventDrivenGP_AW(Ptr< const event_lib_t > _elib, Ptr< Random > rnd=nullptr)
Definition: EventDrivenGP.h:664
memory_t local_mem
Definition: EventDrivenGP.h:160
size_t GetFP() const
Get function pointer.
Definition: EventDrivenGP.h:186
A linear GP (inspired by AvidaGP) virtual hardware CPU that supports an event-driven programming para...
Definition: EventDrivenGP.h:98
void SetInst(size_t pos, size_t id, arg_t a0, arg_t a1, arg_t a2, const affinity_t &aff)
Definition: EventDrivenGP.h:340
EventDrivenGP_AW(Ptr< Random > rnd=nullptr)
Definition: EventDrivenGP.h:667
size_t GetSize() const
Get the number of events registered to this event library.
Definition: EventLib.h:77
size_t size() const
Definition: vector.h:151
Definition: EventLib.h:21
static void Inst_Return(EventDrivenGP_t &hw, const inst_t &inst)
Definition: EventDrivenGP.h:1543
static void Inst_Sub(EventDrivenGP_t &hw, const inst_t &inst)
Definition: EventDrivenGP.h:1405
mem_val_t GetDefaultMemValue() const
Get the default memory value for local/shared/input/output memory maps.
Definition: EventDrivenGP.h:825
void QueueEvent(const event_t &event)
Queue an event (to be handled by this hardware).
Definition: EventDrivenGP.h:1201
void emplace_back(ARGS &&...args)
Definition: vector.h:219
static void Inst_TestEqu(EventDrivenGP_t &hw, const inst_t &inst)
Definition: EventDrivenGP.h:1444
mem_val_t & AccessOutput(mem_key_t key)
Definition: EventDrivenGP.h:255
bool is_executing
Definition: EventDrivenGP.h:632
void ProcessInst(const inst_t &inst)
Process a single instruction, provided by the caller.
Definition: EventDrivenGP.h:1177
void SetInst(size_t fID, size_t pos, const inst_t &inst)
Shortcut to this hardware object&#39;s program&#39;s SetInst function of the same signature.
Definition: EventDrivenGP.h:974
memory_t & GetOutputMemory()
Get a reference to the output memory map for this state.
Definition: EventDrivenGP.h:216
static Ptr< const InstLib< EventDrivenGP_t > > DefaultInstLib()
Get a pointer to const default instruction library. Will only construct the default instruction libra...
Definition: EventDrivenGP.h:1631
void SetIP(size_t ip)
Set instruction pointer to given value, ip.
Definition: EventDrivenGP.h:195
std::unordered_set< std::string > properties_t
Definition: EventDrivenGP.h:110
Program program_t
Definition: EventDrivenGP.h:608
static void Inst_Dec(EventDrivenGP_t &hw, const inst_t &inst)
Definition: EventDrivenGP.h:1381
bool operator!=(const Function &in) const
Definition: EventDrivenGP.h:322
bool operator!=(const Instruction &in) const
Definition: EventDrivenGP.h:291
static void Inst_Call(EventDrivenGP_t &hw, const inst_t &inst)
Definition: EventDrivenGP.h:1536
void PushFunction(const affinity_t &_aff=affinity_t(), const inst_seq_t &_seq=inst_seq_t())
Shortcut to this hardware object&#39;s program&#39;s PushFunction operation of the same signature.
Definition: EventDrivenGP.h:993
auto Find(const MAP_T &in_map, const KEY_T &key, const typename MAP_T::mapped_type &dval)
Definition: map_utils.h:29
static void HandleEvent_Message(EventDrivenGP_t &hw, const event_t &event)
Definition: EventDrivenGP.h:1670
void Process(size_t num_inst)
Advance hardware by some arbitrary number instructions.
Definition: EventDrivenGP.h:1284
void PrintInst(const inst_t &inst, std::ostream &os=std::cout)
Print given instruction using given output stream (default = std::cout).
Definition: EventDrivenGP.h:1299
static void Inst_Commit(EventDrivenGP_t &hw, const inst_t &inst)
Definition: EventDrivenGP.h:1592
static constexpr size_t MAX_INST_ARGS
Maximum number of instruction arguments. Currently hardcoded. At some point, will make flexible...
Definition: EventDrivenGP.h:101
Function & operator[](size_t id)
Definition: EventDrivenGP.h:367
static void Inst_If(EventDrivenGP_t &hw, const inst_t &inst)
Definition: EventDrivenGP.h:1468
void PrintProgram(std::ostream &os=std::cout)
Print out entire program using given output stream (default = std::cout).
Definition: EventDrivenGP.h:1313
EventDrivenGP_AW(Ptr< const inst_lib_t > _ilib, Ptr< const event_lib_t > _elib, Ptr< Random > rnd=nullptr)
Definition: EventDrivenGP.h:639
size_t func_ptr
Definition: EventDrivenGP.h:165
void pop_back()
Definition: vector.h:194
int arg_t
Definition: EventDrivenGP.h:107
void PushInst(const inst_t &inst, int fID=-1)
Definition: EventDrivenGP.h:1017
size_t GetMaxCallDepth() const
Get the maximum call depth allowed on this hardware object (max call states allowed on a single core&#39;...
Definition: EventDrivenGP.h:822
void BreakBlock()
Definition: EventDrivenGP.h:1100
bool ValidFunction(size_t fID) const
Is the function given by function ID (fID) a valid function in this hardware object&#39;s program...
Definition: EventDrivenGP.h:1044
Ptr< const event_lib_t > event_lib
Definition: EventDrivenGP.h:614
properties_t properties
Definition: EventDrivenGP.h:124
bool operator!=(const Program &in) const
Definition: EventDrivenGP.h:371
program_t program
Definition: EventDrivenGP.h:359
bool HasProperty(std::string property) const
Does event object have given property?
Definition: EventDrivenGP.h:136
static constexpr double DEFAULT_MIN_BIND_THRESH
Definition: EventDrivenGP.h:116
void PushInst(size_t id, arg_t a0=0, arg_t a1=0, arg_t a2=0, const affinity_t &aff=affinity_t(), int fID=-1)
Definition: EventDrivenGP.h:404
void Clear()
Definition: EventDrivenGP.h:365
void SetStochasticFunCall(bool val)
Definition: EventDrivenGP.h:947
static std::string to_lower(std::string value)
Convert a string to all lowercase.
Definition: string_utils.h:132
int mem_key_t
Definition: EventDrivenGP.h:104
static void Inst_BroadcastMsg(EventDrivenGP_t &hw, const inst_t &inst)
Definition: EventDrivenGP.h:1615
bool operator<(const Function &other) const
Definition: EventDrivenGP.h:324
void Print(std::ostream &out=std::cout) const
Print all bits to the provided output stream.
Definition: BitSet.h:333
void SetShared(mem_key_t key, mem_val_t value)
Set given shared memory map location (key) to given value.
Definition: EventDrivenGP.h:1047
void PushInst(const inst_t &inst, int fID=-1)
Definition: EventDrivenGP.h:433
void PushFunction(const Function &_function)
Shortcut to this hardware object&#39;s program&#39;s PushFunction operation of the same signature.
Definition: EventDrivenGP.h:990
void Reset()
Reset state object.
Definition: EventDrivenGP.h:177
memory_t output_mem
Definition: EventDrivenGP.h:162
constexpr T Max(T in1)
Max of only one element is that element itself!
Definition: math.h:61
size_t end
Definition: EventDrivenGP.h:149
size_t max_call_depth
Definition: EventDrivenGP.h:623
void SpawnCore(size_t fID, const memory_t &input_mem=memory_t(), bool is_main=false)
Definition: EventDrivenGP.h:760
size_t GetSize() const
Definition: EventDrivenGP.h:328
const Function & GetFunction(size_t fID) const
Get reference to a particular function in hardware&#39;s program.
Definition: EventDrivenGP.h:797
void Load(std::istream &input)
Definition: EventDrivenGP.h:461
Ptr< Random > GetRandomPtr()
Get pointer to random number generator used by this hardware.
Definition: EventDrivenGP.h:789
void Load(std::istream &input)
Definition: EventDrivenGP.h:1028
bool Has(const MAP_T &in_map, const KEY_T &key)
Take any map type, and run find to determine if a key is present.
Definition: map_utils.h:21
bool is_digit(char test_char)
Determine if a character is a digit.
Definition: string_utils.h:185
double GetTrait(size_t id) const
Get a particular trait given its ID.
Definition: EventDrivenGP.h:809
State & GetCurState()
Get a reference to the current local call state.
Definition: EventDrivenGP.h:844
void PrintInstFull(const inst_t &inst, std::ostream &os=std::cout)
Fully print out a single instruction with its arguments/affinity.
Definition: EventDrivenGP.h:544
size_t inst_ptr
Definition: EventDrivenGP.h:166
void PushInst(size_t id, arg_t a0=0, arg_t a1=0, arg_t a2=0, const affinity_t &aff=affinity_t(), int fID=-1)
Definition: EventDrivenGP.h:1001
emp::vector< size_t > inactive_cores
Definition: EventDrivenGP.h:629
void resize(size_t new_size)
Definition: vector.h:161
BitSet< AFFINITY_WIDTH > affinity_t
Definition: EventDrivenGP.h:109
Block(size_t _begin=0, size_t _end=0, BlockType _type=BlockType::BASIC)
Definition: EventDrivenGP.h:152
memory_t & GetLocalMemory()
Get a reference to the local memory map for this state.
Definition: EventDrivenGP.h:210
emp::vector< size_t > active_cores
Definition: EventDrivenGP.h:628
void TriggerEvent(const std::string &name, const affinity_t &affinity=affinity_t(), const memory_t &msg=memory_t(), const properties_t &properties=properties_t())
Trigger an event (from this hardware).
Definition: EventDrivenGP.h:1186
Definition: EventDrivenGP.h:309
bool operator==(const Function &in) const
Definition: EventDrivenGP.h:319
size_t exec_core_id
Definition: EventDrivenGP.h:631
double default_mem_val
Definition: EventDrivenGP.h:163
static constexpr mem_val_t DEFAULT_MEM_VALUE
Definition: EventDrivenGP.h:115
void SetDefaultMemValue(mem_val_t val)
Set default memory value to given value, val.
Definition: EventDrivenGP.h:201
void IncTrait(size_t id, double inc=1.0)
Definition: EventDrivenGP.h:958
void PushFunction(const Function &_function)
Definition: EventDrivenGP.h:396
iterator begin() noexcept
Definition: vector.h:153
size_t FindEndOfBlock(size_t fp, size_t ip)
Definition: EventDrivenGP.h:1051
program_t & GetProgram()
Definition: EventDrivenGP.h:793
void DecTrait(size_t id, double dec=1.0)
Definition: EventDrivenGP.h:965
exec_stk_t & GetCurCore()
Get a reference to the current core/execution stack.
Definition: EventDrivenGP.h:841
Definition: EventDrivenGP.h:120
double SimpleMatchCoeff(const BitSet< NUM_BITS > &in1, const BitSet< NUM_BITS > &in2)
Computes simple matching coefficient (https://en.wikipedia.org/wiki/Simple_matching_coefficient).
Definition: BitSet.h:595
If we are in emscripten, make sure to include the header.
Definition: array.h:37
static void Inst_SwapMem(EventDrivenGP_t &hw, const inst_t &inst)
Definition: EventDrivenGP.h:1566
void PushInst(const std::string &name, arg_t a0=0, arg_t a1=0, arg_t a2=0, const affinity_t &aff=affinity_t(), int fID=-1)
Definition: EventDrivenGP.h:1009
void ResetHardware()
Definition: EventDrivenGP.h:726
Definition: EventDrivenGP.h:266
static void Inst_Mult(EventDrivenGP_t &hw, const inst_t &inst)
Definition: EventDrivenGP.h:1413
Definition: Ptr.h:711
static void Inst_TestNEqu(EventDrivenGP_t &hw, const inst_t &inst)
Definition: EventDrivenGP.h:1452
Build a debug wrapper emp::vector around std::vector.
Definition: vector.h:42
Ptr< Random > random_ptr
Definition: EventDrivenGP.h:615
void AdvanceIP(size_t inc=1)
Advance instruction pointer by amount given by inc.
Definition: EventDrivenGP.h:204
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
memory_t & GetSharedMem()
Get a reference to hardware&#39;s shared memory map.
Definition: EventDrivenGP.h:850
size_t GetMaxCores() const
Get the maximum number of cores allowed to run simultaneously on this hardware object.
Definition: EventDrivenGP.h:819
static void Inst_CopyMem(EventDrivenGP_t &hw, const inst_t &inst)
Definition: EventDrivenGP.h:1558
memory_t shared_mem
Definition: EventDrivenGP.h:618
#define emp_assert(...)
Definition: assert.h:199
InstLib maintains a set of instructions for use in virtual hardware.
Definition: InstLib.h:34
T & back()
Definition: vector.h:183
mem_val_t GetDefaultMemValue() const
Get default memory value.
Definition: EventDrivenGP.h:192
affinity_t affinity
Definition: EventDrivenGP.h:122
Definition: EventDrivenGP.h:355
memory_t msg
Definition: EventDrivenGP.h:123
void SetLocal(mem_key_t key, mem_val_t value)
Set local memory specified by key to value.
Definition: EventDrivenGP.h:231
Event(size_t _id=0, const affinity_t &aff=affinity_t(), const memory_t &_msg=memory_t(), const properties_t &_properties=properties_t())
Definition: EventDrivenGP.h:126
emp::vector< exec_stk_t > cores
Definition: EventDrivenGP.h:627
Ptr< const inst_lib_t > inst_lib
Definition: EventDrivenGP.h:358
emp::vector< inst_t > inst_seq_t
Definition: EventDrivenGP.h:300
Event & operator=(const Event &)=default
EventDrivenGP_AW(const EventDrivenGP_t &in)
Definition: EventDrivenGP.h:691
void CloseBlock()
Definition: EventDrivenGP.h:1074
void New(T &&...args)
Definition: Ptr.h:735
void TriggerEvent(const event_t &event)
Trigger an event (from this hardware).
Definition: EventDrivenGP.h:1183
inst_t & operator[](size_t id)
Definition: EventDrivenGP.h:316
Ptr< const event_lib_t > GetEventLib() const
Get event library associated with hardware.
Definition: EventDrivenGP.h:783
void PrintEvent(const event_t &event, std::ostream &os=std::cout)
Print given event using given output stream (default = std::cout).
Definition: EventDrivenGP.h:1290
Ptr< const inst_lib_t > GetInstLib() const
Get instruction library associated with hardware&#39;s program.
Definition: EventDrivenGP.h:780
static void Inst_Output(EventDrivenGP_t &hw, const inst_t &inst)
Definition: EventDrivenGP.h:1584
bool random_owner
Definition: EventDrivenGP.h:616
void PrintProgramFull(std::ostream &os=std::cout)
Print out entire program.
Definition: EventDrivenGP.h:581
bool operator==(const Instruction &in) const
Definition: EventDrivenGP.h:288
void SetFP(size_t fp)
Set function pointer to given value, fp.
Definition: EventDrivenGP.h:198
void HandleEvent(const event_t &event)
Handle an event (on this hardware).
Definition: EventDrivenGP.h:1180
void PushInst(size_t id, arg_t a0, arg_t a1, arg_t a2, const affinity_t &aff)
Definition: EventDrivenGP.h:332
void PushInst(const std::string &name, arg_t a0=0, arg_t a1=0, arg_t a2=0, const affinity_t &aff=affinity_t(), int fID=-1)
Definition: EventDrivenGP.h:418
mem_val_t & AccessInput(mem_key_t key)
Definition: EventDrivenGP.h:248
emp::vector< double > traits
Definition: EventDrivenGP.h:620
double GetMinBindThresh() const
Definition: EventDrivenGP.h:816
size_t max_cores
Definition: EventDrivenGP.h:622
void SetInst(size_t fID, size_t pos, const inst_t &inst)
Definition: EventDrivenGP.h:447
std::deque< size_t > pending_cores
Definition: EventDrivenGP.h:630
void PrintProgramFull(std::ostream &os=std::cout)
Print out entire program using given output stream (default = std::cout).
Definition: EventDrivenGP.h:1318
void Set(const Instruction &other)
Definition: EventDrivenGP.h:282
mem_val_t GetInput(mem_key_t key) const
Definition: EventDrivenGP.h:224
static void Inst_SendMsg(EventDrivenGP_t &hw, const inst_t &inst)
Definition: EventDrivenGP.h:1625
bool stochastic_fun_call
Definition: EventDrivenGP.h:626
State(mem_val_t _default_mem_val=0.0, bool _is_main=false)
Definition: EventDrivenGP.h:170
size_t GetSize() const
Get number of functions that make up this program.
Definition: EventDrivenGP.h:378
void SetInst(size_t pos, const inst_t &inst)
Definition: EventDrivenGP.h:344
bool ValidPosition(size_t fID, size_t pos) const
Definition: EventDrivenGP.h:1041
constexpr size_t GetSize(T(&)[N])
Determine the size of a built-in array.
Definition: functions.h:81
void SetDefaultMemValue(mem_val_t val)
Configure the default memory value.
Definition: EventDrivenGP.h:937
void SetProgram(const program_t &_program)
Set program for this hardware object.
Definition: EventDrivenGP.h:987
static void Inst_Not(EventDrivenGP_t &hw, const inst_t &inst)
Definition: EventDrivenGP.h:1389
Function(const affinity_t &_aff=affinity_t(), const inst_seq_t &_seq=inst_seq_t())
Definition: EventDrivenGP.h:313
bool operator<(const Instruction &other) const
Definition: EventDrivenGP.h:293
void PushFunction(const affinity_t &_aff=affinity_t(), const inst_seq_t &_seq=inst_seq_t())
Definition: EventDrivenGP.h:397
bool is_valid(char test_char)
If no functions are provided to is_valid(), always return false as base case.
Definition: string_utils.h:261
void PushInst(const inst_t &inst)
Definition: EventDrivenGP.h:336
bool operator==(const Program &in) const
Definition: EventDrivenGP.h:370
BlockType type
Definition: EventDrivenGP.h:150
Definition: EventDrivenGP.h:147
Definition: EventDrivenGP.h:159
const inst_t & operator[](size_t id) const
Definition: EventDrivenGP.h:317