VirtualCPU.hpp

A simple virtual CPU styled after the original and extended Avidian architectures. @TODO.

  • Expanded heads?

  • expanded_nop_args useful?

  • Consider changing default return value for search functions

  • Consider switching to (or adding an optional mode) where nops are only curated as-needed instead of all at once

namespace emp
template<typename DERIVED>
class VirtualCPU
#include <VirtualCPU.hpp>

A simple virtual CPU styled after those seen in Avida.

This class represents a single virtual CPU following a genome of assembly-level instructions. By default, each CPU features four heads, two stacks, multiple registers, and a circular genome. Both the original and extended architectures are supported.

Public Types

using derived_t = DERIVED
using data_t = int32_t
using inst_t = Instruction
using inst_lib_t = VirtualCPU_InstLib<derived_t, data_t, 0>
using genome_t = Genome<Instruction, inst_lib_t>
using nop_vec_t = vector<size_t>
using stack_t = vector<data_t>

Public Functions

inline VirtualCPU(const genome_t &in_genome)

CONSTRUCTORS / DESTRUCTOR Create a new VirtualCPU with the same genome (and thus instruction library)

inline VirtualCPU()

Create a default VirtualCPU (no genome sequence, default instruction set)

VirtualCPU(const VirtualCPU&) = default

Create a perfect copy of passed VirtualCPU.

VirtualCPU(VirtualCPU&&) = default

Default move constructor.

inline virtual ~VirtualCPU()

Default destructor.

inline size_t GetGenomeSize() const

GETTERS Return size of original genome

inline size_t GetWorkingGenomeSize() const

Return size of working genome.

inline size_t GetNumRegs() const

Return the number of registers in the CPU.

inline size_t GetNumNops() const

Return the number of NOP instructions found in the CPU’s instruction library.

inline const std::unordered_map<int, data_t> &GetOutputs() const

Return the outputs of the CPU.

inline Ptr<const inst_lib_t> GetInstLib() const

Return a pointer to the CPU’s instruction library.

inline size_t GetNumInstsExecuted() const

Return the number of instructions that have been executed.

inline size_t GetNumInstsCopied() const

Return the number of instructions that have been copied.

inline void SetInputs(const vector<data_t> &vals)

SETTERS Copies passed vector into input map

inline bool Load(std::istream &input)

GENOME & INSTRUCTION MANIPULATION Load instructions from input stream

inline bool Load(const std::string &filename)

Load instructions from file.

inline bool LoadFromChars(const std::string &new_genome)

Load genome from a string of characters.

inline void PushInst(size_t idx)

Add a new instruction to the end of the genome, by index in the instruction library.

inline void PushInst(int idx)

Redirect literal ints to PushInst(size_t) overload.

inline void PushInst(char c)

Add a new instruction to the end of the genome, by the instruction’s symbol/char.

inline void PushInst(const std::string &name)

Add a new instruction to the end of the genome, by name.

inline void PushInst(const inst_t &inst)

Add a specified new instruction to the end of the genome.

inline void PushInst(const inst_t &inst, size_t count)

Add multiple copies of a specified instruction to the end of the genome.

inline inst_t GetDefaultInst() const

Return the first instruction in the instruction library.

inline void PushDefaultInst(size_t count = 1)

Add one or more default instructions to the end of the genome.

inline inst_t GetRandomInst(Random &rand)

Return a random instruction from the instruction library.

inline void SetInst(size_t pos, const inst_t &inst)

Overwrite the instruction at the given genome index with passed instruction.

inline void RandomizeInst(size_t pos, Random &rand)

Overwrite the instruction at the given genome index with a random instruction.

inline void PushRandomInst(Random &random, const size_t count = 1)

Add a random instruction from the instruction library to the end of the genome.

inline void InsertInst(const inst_t &inst, const size_t idx)

Insert the given instruction at the specified genome position.

inline void InsertRandomInst(const size_t idx, Random &random)

Inserts a random instruction at the given genome position.

inline void RemoveInst(const size_t idx)

Remove the instruction at the specified genome position.

inline void IncreaseCooldown(size_t val)

Increase the cooldown by some value, so instructions cannot be processed for longer.

inline void DecreaseCooldown(size_t val)

Decrease the cooldown by some value, so instructions can be processed sooner.

inline void ResetCooldown()

Reset the cooldown timer.

inline void ResetIP()

Move instruction pointer to beginning of the genome.

inline void ResetRH()

Move read head to beginning of the genome.

inline void ResetWH()

Move write head to beginning of the genome.

inline void ResetFH()

Move flow head to beginning of the genome.

inline void AdvanceIP(size_t steps = 1)

Advance the instruction pointer so many steps and wrap around the end of the genome.

inline void AdvanceRH(size_t steps = 1)

Advance the read head so many steps and wrap around the end of the genome.

inline void AdvanceWH(size_t steps = 1)

Advance the write head so many steps and wrap around the end of the genome.

inline void AdvanceFH(size_t steps = 1)

Advance the flow head so many steps and wrap around the end of the genome.

inline void SetIP(size_t pos)

Set the instruction pointer to the genome index, wrap around the end of the genome.

inline void SetRH(size_t pos)

Set the read head to the genome index, wrap around the end of the genome.

inline void SetWH(size_t pos)

Set the write head to the genome index, wrap around the end of the genome.

inline void SetFH(size_t pos)

Set the flow head to the genome index, wrap around the end of the genome.

inline void ResetModdedHead(size_t head_idx)

Set the specified head (which can wrap) to the beginning of the genome,.

inline void SetModdedHead(size_t head_idx, size_t pos)

Set the specified head (which can wrap) to the given genome position, wrap around the end of the genome

inline void AdvanceModdedHead(size_t head_idx, size_t steps = 1)

Advance the specified head (which can wrap) the given number of instructions, wrap around the end of the genome

inline size_t GetModdedHead(size_t head_idx)

Return the head POSITION of the specified head (can wrap)

inline void Initialize()

HARDWARE MANIPULATION Initializes the CPU by counting the number of NOP instructions in the instruction library and expanding the number of registers to match

inline void ResetHeads()

Reset all heads.

inline void ResetIO()

Reset all inputs and outputs.

inline void ResetMemory()

Reset all memory/data.

inline void ResetBookkeeping()

Reset all bookkeeping variables.

inline void ResetWorkingGenome()

Reset the working genome back to the original genome.

inline void ResetHardware()

Reset just the CPU hardware, but keep the original genome.

inline void ClearGenome()

Clear the main genome of the organism and reset all hardware.

inline void CurateNops()

Compile NOP instructions in genome into useful nop vectors for each instruction, and records the position of all LABEL instructions

inline void CountNops()

Determine the number of sequential NOP instructions in the instruction library

Starts at NopA and continues from there. Any missing instructions force count to stop. Last possible NOP instruction is NopW, as NopX is a special case in Avida.

inline void ExpandRegisters()

Expand the CPU’s registers to match the number of NOP instructions in the instruction library

inline size_t GetComplementNop(size_t idx)

NOP SEQUENCE METHODS For a given NOP instruction (as an index), return its complement index

inline nop_vec_t GetComplementNopSequence(const nop_vec_t &nop_vec)

For a vector of NOP instructions (as indices), return a vector of complement indices in the same order

inline bool CompareNopSequences(const nop_vec_t &search_vec, const nop_vec_t &compare_vec)

Check if a vector of NOP instructions is the same as the START of another vector.

inline bool CheckIfLastCopied(const nop_vec_t &label)

Check if the given vector of NOP instructions (as indices) were the last instructions to be copied by the CPU

inline size_t FindLabel_Reverse(bool start_local)

Search up the genome (backward) for a sequence of NOP instructions following a LABEL instruction that match the NOP sequence following the current instruction

Parameters:

start_local – If true, search from instruction pointer. If false, search from start of the genome

inline size_t FindLabel(bool start_local, bool reverse = false)

Search the genome for a sequence of NOP instructions following a LABEL instruction that match the NOP sequence following the current instruction

Parameters:
  • start_local – If true, search from instruction pointer. If false, search from start of the genome

  • reverse – If true, traverse the genome backward. If false, traverse forward

inline size_t FindNopSequence_Reverse(const nop_vec_t &search_vec, size_t start_idx)

Search up the genome (backward) for a sequence of NOP instructions that match the given NOP sequence

Parameters:
  • search_vec – The sequence of NOP instructions to search for

  • start_idx – Position in the genome to start the search

inline size_t FindNopSequence_Reverse(const nop_vec_t &search_vec, bool start_local)

Search up the genome (backward) for a sequence of NOP instructions that match the given NOP sequence

Parameters:
  • search_vec – The sequence of NOP instructions to search for

  • start_local – If true, search from instruction pointer. If false, search from start of the genome

inline size_t FindNopSequence_Reverse(bool start_local)

Search up the genome (backward) for a sequence of NOP instructions that match the NOP sequence following the current instruction

Parameters:

start_local – If true, search from instruction pointer. If false, search from start of the genome

inline size_t FindNopSequence(const nop_vec_t &search_vec, size_t start_idx, bool reverse = false)

Search the genome for a sequence of NOP instructions that match the given NOP sequence

Parameters:
  • search_vec – The sequence of NOP instructions to search for

  • start_idx – Position in the genome to start the search

inline size_t FindNopSequence(const nop_vec_t &search_vec, bool start_local, bool reverse = false)

Search the genome for a sequence of NOP instructions that match the given NOP sequence

Parameters:
  • search_vec – The sequence of NOP instructions to search for

  • start_local – If true, search from instruction pointer. If false, search from start of the genome

  • reverse – If true, traverse the genome backward. If false, traverse forward

inline size_t FindNopSequence(bool start_local, bool reverse = false)

Search up the genome (backward) for a sequence of NOP instructions that match the NOP sequence following the current instruction

Parameters:
  • start_local – If true, search from instruction pointer. If false, search from start of the genome

  • reverse – If true, traverse the genome backward. If false, traverse forward

inline void StackPush(size_t reg_idx)

STACK MANIPULATION Push the value in the specified register on top of the active stack

inline void StackPop(size_t reg_idx)

Remove the value from the top of the active stack and store it in the specified register

inline void StackSwap()

Swap which stack is active.

inline data_t GetStackVal(size_t stack_idx, size_t val_idx)

Fetch the nth value of the specified stack.

inline void SingleProcess(bool verbose = true)

PROCESSING Process the next instruction pointed to be the instruction pointer

inline void Process(size_t num_inst = 1, bool verbose = true)

Process the next SERIES of instructions, directed by the instruction pointer.

inline std::string GetWorkingGenomeString() const

STATE -> STRING FUNCTIONS Return the working genome in string form.

Each instruction is represented by a single character, dictated by the instruction’s ID.

inline std::string GetGenomeString() const

Return the original genome in string form.

Each instruction is represented by a single character, dictated by the instruction’s ID.

inline std::string GetRawGenomeString() const

Return the original genome in string form, without the genome length.

Each instruction is represented by a single character, dictated by the instruction’s ID.

inline void PrintDetails(std::ostream &os = std::cout)

Output the state of the CPU’s heads and registers to the specified output stream.

Public Members

bool are_nops_counted = false

in the CPU’s library have been counted

Flag detailing if the number of NOP instructions

bool are_regs_expanded = false

Flag signaling if the number of registers have been expanded to accommodate the number of NOP instructions in the library

bool nops_need_curated = true

Flag signaling that NOP instructions need curated.

bool expanded_nop_args = false

Flag signaling that CPU is used the expanded.

vector<data_t> regs

Vector of registers.

std::unordered_map<int, data_t> inputs

(position -> value)

Map of all available inputs

std::unordered_map<int, data_t> outputs

Map of all outputs (position -> value)

array<stack_t, NUM_STACKS> stacks

Array of stacks for this CPU.

size_t inst_ptr

instruction to be executed

Instruction pointer, signifies next

size_t flow_head

values

Flow head, used for moving heads and

size_t read_head

copy next

Read head, signals what instruction to

size_t write_head

instruction

Write head, signals where to copy next

size_t cooldown_timer = 0

Decrease this value instead ///// HELPER CONSTRUCTS.

Do not process inst if value > 0.

unordered_map<size_t, size_t> nop_id_map

NOP inst id -> Nop index (e.g., NopA -> 0, NopB -> 1, NopE -> 5)

vector<size_t> label_idx_vec

Vector of LABEL instructions indices in genome ///// GENOME.

genome_t genome

that should not change in any way

Preserved copy of genome from organism creation/birth

genome_t genome_working

Working copy of genome that can mutate, resize, and change ///// BOOKKEEPING.

size_t active_stack_idx = 0

Index of CPU’s active stack.

vector<size_t> copied_inst_id_vec

Vector of instructions that have been copied

size_t num_insts_executed = 0

Number of instructions that have been executed.

Public Static Attributes

static constexpr size_t NUM_STACKS = 2

Number of stacks in this CPU (currently 2)

static constexpr size_t MAX_NOPS = 23

Maximum number of nop instructions supported.

Protected Attributes

size_t num_regs = 0

Number of registers found in this CPU.

size_t num_nops = 0

Number of NOP instructions found in this CPU’s library.

struct Instruction : public inst_lib_t::InstructionBase
#include <VirtualCPU.hpp>

Representation of a single instruction in the CPU’s genome.

Only contains the necessary information for which instruction is being represented as well as any data it needs in the genome. Does NOT contain the actual logic of the instruction, nor the name. These are handled by the instruction library itself.

Public Functions

Instruction() = delete
inline Instruction(size_t _idx, size_t _id = 0, vector<size_t> _nop_vec = {})
Instruction(const Instruction&) = default
Instruction(Instruction&&) = default
Instruction &operator=(const Instruction&) = default
Instruction &operator=(Instruction&&) = default
inline bool operator<(const Instruction &in) const
inline bool operator==(const Instruction &in) const
inline bool operator!=(const Instruction &in) const
inline bool operator>(const Instruction &in) const
inline bool operator>=(const Instruction &in) const
inline bool operator<=(const Instruction &in) const
inline void Set(size_t _idx, size_t _id, vector<size_t> _nop_vec = {})
inline size_t GetIndex() const override

Public Members

size_t idx
size_t id

Index of the instruction in the instruction library.

vector<size_t> nop_vec

Identifier for the instruction that gives the user flexibility over the instruction (e.g., what symbol it should use in a string representation)

bool has_been_executed = false

instructions following this instruction in the genome

Representation of the contiguous sequence of NOP

bool has_been_copied = false

Has this instruction been executed?