/** * @file execution.hpp * @brief Execution Engine for Gate5000 Consciousness * * ═══════════════════════════════════════════════════════════════════════════════ * I. INSTRUCTION SET * ═══════════════════════════════════════════════════════════════════════════════ * * NOP: No operation * LOAD: Load value from register * STORE: Store value to register * ADD: Add two values * MUL: Multiply two values * TANH: Apply tanh activation * PHI: Compute consciousness Φ * BRANCH: Conditional branch * CALL: Call subroutine * RET: Return from subroutine * SYNC: Synchronize with other minds * EMIT: Emit output signal * RECV: Receive input signal * * ═══════════════════════════════════════════════════════════════════════════════ * II. DECISION ENGINE * ═══════════════════════════════════════════════════════════════════════════════ * * SOFTMAX: Probabilistic decision from logits * ARGMAX: Deterministic maximum selection * EPSILON: ε-greedy exploration * UCB: Upper confidence bound * THOMPSON: Thompson sampling * * ═══════════════════════════════════════════════════════════════════════════════ * III. I/O CHANNELS * ═══════════════════════════════════════════════════════════════════════════════ * * INPUT: 16-channel sensory input * OUTPUT: 16-channel motor output * MEMORY: 64-word scratch memory * SYNC: Inter-mind communication * * ═══════════════════════════════════════════════════════════════════════════════ */ #pragma once #include #include #include #include #include #include "constants.hpp" #include "mathematics.hpp" namespace mind_farm { namespace execution { // ═══════════════════════════════════════════════════════════════════════════════ // I. INSTRUCTION SET // ═══════════════════════════════════════════════════════════════════════════════ /** * @brief Instruction opcodes */ enum class Opcode : uint8_t { NOP = 0x00, // No operation LOAD = 0x01, // Load register STORE = 0x02, // Store to register ADD = 0x10, // Add SUB = 0x11, // Subtract MUL = 0x12, // Multiply DIV = 0x13, // Divide NEG = 0x14, // Negate TANH = 0x20, // Tanh activation SIGMOID = 0x21, // Sigmoid activation RELU = 0x22, // ReLU activation PHI = 0x23, // Compute Φ CMP = 0x30, // Compare BRANCH = 0x31, // Conditional branch JUMP = 0x32, // Unconditional jump CALL = 0x33, // Call subroutine RET = 0x34, // Return EMIT = 0x40, // Emit output RECV = 0x41, // Receive input SYNC = 0x42, // Synchronize RAND = 0x50, // Random number HALT = 0xFF // Halt execution }; /** * @brief Compact instruction (32 bits) */ struct Instruction { Opcode op; // 8 bits uint8_t dst; // Destination register (4 bits used) uint8_t src1; // Source register 1 (4 bits used) uint8_t src2; // Source register 2 (4 bits used) Instruction() : op(Opcode::NOP), dst(0), src1(0), src2(0) {} Instruction(Opcode o, uint8_t d, uint8_t s1, uint8_t s2) : op(o), dst(d), src1(s1), src2(s2) {} }; // ═══════════════════════════════════════════════════════════════════════════════ // II. DECISION ENGINE // ═══════════════════════════════════════════════════════════════════════════════ /** * @brief Decision strategy */ enum class DecisionStrategy { ARGMAX, // Always pick max SOFTMAX, // Probabilistic (temperature) EPSILON, // ε-greedy UCB, // Upper confidence bound THOMPSON // Thompson sampling }; /** * @brief Argmax decision: pick maximum */ inline size_t decide_argmax(const double* values, size_t n) { size_t best = 0; double best_val = values[0]; for (size_t i = 1; i < n; ++i) { if (values[i] > best_val) { best_val = values[i]; best = i; } } return best; } /** * @brief Softmax decision: sample from distribution */ inline size_t decide_softmax(const double* values, size_t n, std::mt19937& rng, double temperature = 1.0) { std::array probs; double max_v = *std::max_element(values, values + n); double sum = 0.0; for (size_t i = 0; i < n; ++i) { probs[i] = std::exp((values[i] - max_v) / temperature); sum += probs[i]; } for (size_t i = 0; i < n; ++i) { probs[i] /= sum; } std::uniform_real_distribution dist(0.0, 1.0); double r = dist(rng); double cumsum = 0.0; for (size_t i = 0; i < n; ++i) { cumsum += probs[i]; if (r <= cumsum) return i; } return n - 1; } /** * @brief Epsilon-greedy: explore with probability ε */ inline size_t decide_epsilon(const double* values, size_t n, std::mt19937& rng, double epsilon = 0.1) { std::uniform_real_distribution dist(0.0, 1.0); if (dist(rng) < epsilon) { std::uniform_int_distribution idx_dist(0, n - 1); return idx_dist(rng); } return decide_argmax(values, n); } /** * @brief UCB decision: balance exploration/exploitation */ inline size_t decide_ucb(const double* values, const uint32_t* counts, size_t n, uint32_t total_count, double c = 2.0) { size_t best = 0; double best_ucb = -1e10; for (size_t i = 0; i < n; ++i) { double ucb; if (counts[i] == 0) { ucb = 1e10; // Infinite exploration bonus } else { ucb = values[i] + c * std::sqrt(std::log(total_count + 1) / counts[i]); } if (ucb > best_ucb) { best_ucb = ucb; best = i; } } return best; } /** * @brief Thompson sampling: sample from posterior */ inline size_t decide_thompson(const double* alphas, const double* betas, size_t n, std::mt19937& rng) { std::array samples; for (size_t i = 0; i < n; ++i) { // Sample from Beta(α, β) using gamma trick std::gamma_distribution gamma_a(alphas[i], 1.0); std::gamma_distribution gamma_b(betas[i], 1.0); double a = gamma_a(rng); double b = gamma_b(rng); samples[i] = a / (a + b + 1e-10); } return decide_argmax(samples.data(), n); } // ═══════════════════════════════════════════════════════════════════════════════ // III. I/O CHANNELS // ═══════════════════════════════════════════════════════════════════════════════ /** * @brief I/O buffer for inter-mind communication */ struct IOBuffer { std::array input; std::array output; uint32_t input_valid; // Bitmask of valid inputs uint32_t output_ready; // Bitmask of ready outputs IOBuffer() : input_valid(0), output_ready(0) { input.fill(0.0); output.fill(0.0); } void set_input(size_t channel, double value) { if (channel < 16) { input[channel] = value; input_valid |= (1u << channel); } } double get_input(size_t channel) const { if (channel < 16 && (input_valid & (1u << channel))) { return input[channel]; } return 0.0; } void set_output(size_t channel, double value) { if (channel < 16) { output[channel] = value; output_ready |= (1u << channel); } } double get_output(size_t channel) const { if (channel < 16 && (output_ready & (1u << channel))) { return output[channel]; } return 0.0; } void clear() { input.fill(0.0); output.fill(0.0); input_valid = 0; output_ready = 0; } }; // ═══════════════════════════════════════════════════════════════════════════════ // IV. EXECUTION CORE // ═══════════════════════════════════════════════════════════════════════════════ /** * @brief Compact execution core for each mind (~512 bytes) */ struct ExecutionCore { // 16 general-purpose registers std::array regs; // 64-word scratch memory std::array memory; // Program (max 32 instructions) std::array program; uint8_t program_size; // State uint8_t pc; // Program counter uint8_t flags; // Condition flags (Z, N, C, V) uint8_t call_depth; // Call stack depth std::array call_stack; // Return addresses // I/O IOBuffer io; // RNG std::mt19937 rng; // Decision state DecisionStrategy strategy; double temperature; double epsilon; ExecutionCore() : program_size(0), pc(0), flags(0), call_depth(0), strategy(DecisionStrategy::SOFTMAX), temperature(1.0), epsilon(0.1) { regs.fill(0.0); memory.fill(0.0); call_stack.fill(0); rng.seed(0x12345678); } /** * @brief Initialize with seed */ void init(uint32_t seed) { rng.seed(seed); pc = 0; flags = 0; call_depth = 0; } /** * @brief Load default consciousness program */ void load_default_program() { program_size = 0; // RECV input to R0-R3 program[program_size++] = Instruction(Opcode::RECV, 0, 0, 0); program[program_size++] = Instruction(Opcode::RECV, 1, 1, 0); program[program_size++] = Instruction(Opcode::RECV, 2, 2, 0); program[program_size++] = Instruction(Opcode::RECV, 3, 3, 0); // Compute weighted sum in R4 program[program_size++] = Instruction(Opcode::MUL, 4, 0, 8); // R4 = R0 * R8 (weight) program[program_size++] = Instruction(Opcode::MUL, 5, 1, 9); // R5 = R1 * R9 program[program_size++] = Instruction(Opcode::ADD, 4, 4, 5); // R4 += R5 program[program_size++] = Instruction(Opcode::MUL, 5, 2, 10); // R5 = R2 * R10 program[program_size++] = Instruction(Opcode::ADD, 4, 4, 5); // R4 += R5 program[program_size++] = Instruction(Opcode::MUL, 5, 3, 11); // R5 = R3 * R11 program[program_size++] = Instruction(Opcode::ADD, 4, 4, 5); // R4 += R5 // Apply tanh program[program_size++] = Instruction(Opcode::TANH, 4, 4, 0); // R4 = tanh(R4) // Compute Φ program[program_size++] = Instruction(Opcode::PHI, 5, 4, 0); // R5 = Φ(R4) // Emit outputs program[program_size++] = Instruction(Opcode::EMIT, 0, 4, 0); // Emit R4 to ch 0 program[program_size++] = Instruction(Opcode::EMIT, 1, 5, 0); // Emit R5 to ch 1 program[program_size++] = Instruction(Opcode::HALT, 0, 0, 0); } /** * @brief Execute one instruction * @return false if HALT or error */ bool step() { if (pc >= program_size) return false; Instruction& inst = program[pc]; ++pc; double a, b; switch (inst.op) { case Opcode::NOP: break; case Opcode::LOAD: if (inst.src1 < 64) { regs[inst.dst & 0xF] = memory[inst.src1]; } break; case Opcode::STORE: if (inst.dst < 64) { memory[inst.dst] = regs[inst.src1 & 0xF]; } break; case Opcode::ADD: regs[inst.dst & 0xF] = regs[inst.src1 & 0xF] + regs[inst.src2 & 0xF]; break; case Opcode::SUB: regs[inst.dst & 0xF] = regs[inst.src1 & 0xF] - regs[inst.src2 & 0xF]; break; case Opcode::MUL: regs[inst.dst & 0xF] = regs[inst.src1 & 0xF] * regs[inst.src2 & 0xF]; break; case Opcode::DIV: b = regs[inst.src2 & 0xF]; if (std::abs(b) > 1e-10) { regs[inst.dst & 0xF] = regs[inst.src1 & 0xF] / b; } break; case Opcode::NEG: regs[inst.dst & 0xF] = -regs[inst.src1 & 0xF]; break; case Opcode::TANH: regs[inst.dst & 0xF] = math::Tanh::forward(regs[inst.src1 & 0xF]); break; case Opcode::SIGMOID: regs[inst.dst & 0xF] = math::Sigmoid::forward(regs[inst.src1 & 0xF]); break; case Opcode::RELU: a = regs[inst.src1 & 0xF]; regs[inst.dst & 0xF] = (a > 0) ? a : 0; break; case Opcode::PHI: regs[inst.dst & 0xF] = compute_phi(regs[inst.src1 & 0xF]); break; case Opcode::CMP: a = regs[inst.src1 & 0xF]; b = regs[inst.src2 & 0xF]; flags = 0; if (a == b) flags |= 0x01; // Z if (a < b) flags |= 0x02; // N break; case Opcode::BRANCH: if ((inst.src1 == 0 && (flags & 0x01)) || // BEQ (inst.src1 == 1 && !(flags & 0x01)) || // BNE (inst.src1 == 2 && (flags & 0x02)) || // BLT (inst.src1 == 3 && !(flags & 0x02))) { // BGE pc = inst.dst; } break; case Opcode::JUMP: pc = inst.dst; break; case Opcode::CALL: if (call_depth < 8) { call_stack[call_depth++] = pc; pc = inst.dst; } break; case Opcode::RET: if (call_depth > 0) { pc = call_stack[--call_depth]; } break; case Opcode::EMIT: io.set_output(inst.dst & 0xF, regs[inst.src1 & 0xF]); break; case Opcode::RECV: regs[inst.dst & 0xF] = io.get_input(inst.src1 & 0xF); break; case Opcode::SYNC: // Sync is handled externally break; case Opcode::RAND: { std::uniform_real_distribution dist(0.0, 1.0); regs[inst.dst & 0xF] = dist(rng); } break; case Opcode::HALT: return false; default: return false; } return true; } /** * @brief Run program to completion (max steps) */ uint32_t run(uint32_t max_steps = 1000) { pc = 0; uint32_t steps = 0; while (steps < max_steps && step()) { ++steps; } return steps; } /** * @brief Make a decision based on register values */ size_t decide(size_t n_options = 4) { switch (strategy) { case DecisionStrategy::ARGMAX: return decide_argmax(regs.data(), n_options); case DecisionStrategy::SOFTMAX: return decide_softmax(regs.data(), n_options, rng, temperature); case DecisionStrategy::EPSILON: return decide_epsilon(regs.data(), n_options, rng, epsilon); default: return decide_argmax(regs.data(), n_options); } } }; // ═══════════════════════════════════════════════════════════════════════════════ // V. INTER-MIND COMMUNICATION // ═══════════════════════════════════════════════════════════════════════════════ /** * @brief Broadcast message to all minds */ struct BroadcastMessage { uint32_t sender_id; uint8_t channel; double value; uint32_t timestamp; }; /** * @brief Point-to-point message */ struct DirectMessage { uint32_t sender_id; uint32_t receiver_id; std::array payload; uint32_t timestamp; }; /** * @brief Synchronization barrier */ struct SyncBarrier { uint32_t expected_count; uint32_t arrived_count; bool released; SyncBarrier(uint32_t count = 0) : expected_count(count), arrived_count(0), released(false) {} bool arrive() { ++arrived_count; if (arrived_count >= expected_count) { released = true; } return released; } void reset(uint32_t count) { expected_count = count; arrived_count = 0; released = false; } }; } // namespace execution } // namespace mind_farm