use super::program::{Instruction, Program}; use crate::core::{OnqError, QduId};
use crate::simulation::SimulationResult; use crate::simulation::engine::SimulationEngine; use std::collections::{HashMap, HashSet};
#[derive(Debug)]
pub struct OnqVm {
engine: Option<SimulationEngine>,
classical_memory: HashMap<String, u64>,
last_stabilization_outcomes: HashMap<QduId, u64>,
program_counter: usize,
is_halted: bool,
}
impl OnqVm {
pub fn new() -> Self {
Self {
engine: None,
classical_memory: HashMap::new(),
last_stabilization_outcomes: HashMap::new(),
program_counter: 0,
is_halted: false,
}
}
fn reset(&mut self) {
self.engine = None; self.classical_memory.clear();
self.last_stabilization_outcomes.clear();
self.program_counter = 0;
self.is_halted = false;
}
pub fn run(&mut self, program: &Program) -> Result<(), OnqError> {
self.reset();
println!("[VM RUN START]");
let all_qdus = Self::collect_qdus(program)?;
if !all_qdus.is_empty() {
self.engine = Some(SimulationEngine::init(&all_qdus)?);
println!("[VM Engine Initialized for {:?}]", all_qdus); } else {
self.engine = None;
println!("[VM Engine Not Needed (No QDUs)]"); }
let mut executed_instruction_count = 0; const MAX_INSTRUCTIONS: u64 = 1000;
while !self.is_halted {
if executed_instruction_count > MAX_INSTRUCTIONS {
return Err(OnqError::SimulationError {
message: format!(
"Execution exceeded maximum instruction limit ({}) - potential infinite loop?",
MAX_INSTRUCTIONS
),
});
}
executed_instruction_count += 1;
let pc = self.program_counter;
println!("[VM] PC={:04} Fetching...", pc); let instruction =
program
.get_instruction(pc)
.ok_or_else(|| OnqError::SimulationError {
message: format!(
"Program Counter ({}) out of bounds (0..{}).",
pc,
program.instruction_count()
),
})?;
println!("[VM] PC={:04} Executing: {:?}", pc, instruction);
self.program_counter += 1;
match instruction {
Instruction::QuantumOp(op) => {
if let Some(engine) = self.engine.as_mut() {
engine.apply_operation(op)?;
} else {
return Err(OnqError::InvalidOperation { message: "Cannot execute QuantumOp: SimulationEngine not initialized (no QDUs defined in program?).".to_string() });
}
}
Instruction::Stabilize { targets } => {
if targets.is_empty() {
println!("[VM] PC={:04} Stabilize: No targets.", pc); continue;
}
if let Some(engine) = self.engine.as_mut() {
let mut temp_result = SimulationResult::new();
println!(
"[VM] PC={:04} Calling engine.stabilize for {:?}",
pc, targets
); engine.stabilize(targets, &mut temp_result)?; println!(
"[VM] PC={:04} engine.stabilize finished. Temp result: {:?}",
pc, temp_result
);
self.last_stabilization_outcomes = temp_result.all_stable_outcomes().iter()
.filter_map(|(qid, state)| {
let resolved = state.get_resolved_value();
println!("[VM] PC={:04} Stabilize: QDU {}, State {:?}, Resolved Value: {:?}", pc, qid, state, resolved); resolved.map(|val| (*qid, val))
})
.collect();
println!(
"[VM] PC={:04} Stored last_stabilization_outcomes: {:?}",
pc, self.last_stabilization_outcomes
); } else {
return Err(OnqError::InvalidOperation {
message: "Cannot execute Stabilize: SimulationEngine not initialized."
.to_string(),
});
}
}
Instruction::Record { qdu, register } => {
println!("[VM] PC={:04} Attempting to record for QDU {}", pc, qdu); println!(
"[VM] PC={:04} Current last_stabilization_outcomes: {:?}",
pc, self.last_stabilization_outcomes
); let value_option = self.last_stabilization_outcomes.get(qdu);
println!(
"[VM] PC={:04} Value Option for QDU {}: {:?}",
pc, qdu, value_option
);
let value = value_option.ok_or_else(|| {
OnqError::InvalidOperation { message: format!("Cannot Record: QDU {} was not found in the last stabilization results ({:?}). Was Stabilize called immediately prior with this QDU?", qdu, self.last_stabilization_outcomes) }
})?;
println!(
"[VM] PC={:04} Recording value {} to register '{}'",
pc, value, register
); self.classical_memory.insert(register.clone(), *value);
println!(
"[VM] PC={:04} Classical memory now: {:?}",
pc, self.classical_memory
); }
Instruction::Label(_) => {
println!("[VM] PC={:04} Encountered Label (No-Op)", pc); }
Instruction::Jump(label) => {
let target_pc =
program
.get_label_pc(label)
.ok_or_else(|| OnqError::SimulationError {
message: format!(
"Runtime Error: Jump target label '{}' not found.",
label
),
})?;
println!(
"[VM] PC={:04} Jumping to label '{}' (PC={})",
pc, label, target_pc
); self.program_counter = target_pc; }
Instruction::BranchIfZero { register, label } => {
let reg_value = self.classical_memory.get(register).copied().unwrap_or(0); println!(
"[VM] PC={:04} BranchIfZero: Reg '{}' = {}",
pc, register, reg_value
); if reg_value == 0 {
let target_pc = program.get_label_pc(label).ok_or_else(|| {
OnqError::SimulationError {
message: format!(
"Runtime Error: Branch target label '{}' not found.",
label
),
}
})?;
println!(
"[VM] PC={:04} Branch taken to label '{}' (PC={})",
pc, label, target_pc
); self.program_counter = target_pc;
} else {
println!("[VM] PC={:04} Branch not taken.", pc); }
}
Instruction::LoadImmediate { register, value } => {
println!("[VM] PC={:04} LoadImm: Reg '{}' = {}", pc, register, value); self.classical_memory.insert(register.clone(), *value);
}
Instruction::Copy {
source_reg,
dest_reg,
} => {
let value = self.classical_memory.get(source_reg).copied().unwrap_or(0);
println!(
"[VM] PC={:04} Copy: Reg '{}' = {} from Reg '{}'",
pc, dest_reg, value, source_reg
); self.classical_memory.insert(dest_reg.clone(), value);
}
Instruction::OnqAdd {
r_dest,
r_src1,
r_src2,
} => {
let val1 = self.classical_memory.get(r_src1).copied().unwrap_or(0);
let val2 = self.classical_memory.get(r_src2).copied().unwrap_or(0);
self.classical_memory
.insert(r_dest.clone(), val1.wrapping_add(val2));
}
Instruction::Addi {
r_dest,
r_src,
value,
} => {
let val_src = self.classical_memory.get(r_src).copied().unwrap_or(0);
let result = val_src.wrapping_add(*value);
println!(
"[VM] PC={:04} Addi: Reg '{}' = {} + {} = {}",
pc, r_dest, val_src, value, result
); self.classical_memory.insert(r_dest.clone(), result);
}
Instruction::Sub {
r_dest,
r_src1,
r_src2,
} => {
let val1 = self.classical_memory.get(r_src1).copied().unwrap_or(0);
let val2 = self.classical_memory.get(r_src2).copied().unwrap_or(0);
self.classical_memory
.insert(r_dest.clone(), val1.wrapping_sub(val2));
}
Instruction::Mul {
r_dest,
r_src1,
r_src2,
} => {
let val1 = self.classical_memory.get(r_src1).copied().unwrap_or(0);
let val2 = self.classical_memory.get(r_src2).copied().unwrap_or(0);
self.classical_memory
.insert(r_dest.clone(), val1.wrapping_mul(val2));
}
Instruction::OnqNot { r_dest, r_src } => {
let val_src = self.classical_memory.get(r_src).copied().unwrap_or(0);
self.classical_memory.insert(r_dest.clone(), !val_src); }
Instruction::And {
r_dest,
r_src1,
r_src2,
} => {
let val1 = self.classical_memory.get(r_src1).copied().unwrap_or(0);
let val2 = self.classical_memory.get(r_src2).copied().unwrap_or(0);
self.classical_memory.insert(r_dest.clone(), val1 & val2); }
Instruction::Or {
r_dest,
r_src1,
r_src2,
} => {
let val1 = self.classical_memory.get(r_src1).copied().unwrap_or(0);
let val2 = self.classical_memory.get(r_src2).copied().unwrap_or(0);
self.classical_memory.insert(r_dest.clone(), val1 | val2); }
Instruction::Xor {
r_dest,
r_src1,
r_src2,
} => {
let val1 = self.classical_memory.get(r_src1).copied().unwrap_or(0);
let val2 = self.classical_memory.get(r_src2).copied().unwrap_or(0);
self.classical_memory.insert(r_dest.clone(), val1 ^ val2); }
Instruction::CmpEq {
r_dest,
r_src1,
r_src2,
} => {
let val1 = self.classical_memory.get(r_src1).copied().unwrap_or(0);
let val2 = self.classical_memory.get(r_src2).copied().unwrap_or(0);
let result = if val1 == val2 { 1 } else { 0 };
println!(
"[VM] PC={:04} CmpEq: Reg '{}' = ({} == {}) = {}",
pc, r_dest, val1, val2, result
); self.classical_memory.insert(r_dest.clone(), result);
}
Instruction::CmpLt {
r_dest,
r_src1,
r_src2,
} => {
let val1 = self.classical_memory.get(r_src1).copied().unwrap_or(0);
let val2 = self.classical_memory.get(r_src2).copied().unwrap_or(0);
self.classical_memory
.insert(r_dest.clone(), if val1 < val2 { 1 } else { 0 });
}
Instruction::Halt => {
println!("[VM] PC={:04} Halting.", pc); self.is_halted = true;
}
Instruction::NoOp => {
println!("[VM] PC={:04} NoOp.", pc); }
Instruction::CmpGt {
r_dest,
r_src1,
r_src2,
} => {
let val1 = self.classical_memory.get(r_src1).copied().unwrap_or(0);
let val2 = self.classical_memory.get(r_src2).copied().unwrap_or(0);
self.classical_memory
.insert(r_dest.clone(), if val1 > val2 { 1 } else { 0 });
}
}
if !self.is_halted && self.program_counter >= program.instruction_count() {
println!(
"[VM] PC={} Reached end of program. Halting.",
self.program_counter
); self.is_halted = true;
}
}
println!("[VM RUN END]"); Ok(())
}
fn collect_qdus(program: &Program) -> Result<HashSet<QduId>, OnqError> {
let mut qdus = HashSet::new();
for instruction in &program.instructions {
match instruction {
Instruction::QuantumOp(op) => {
qdus.extend(op.involved_qdus());
}
Instruction::Stabilize { targets } => {
qdus.extend(targets);
}
Instruction::Record { qdu, .. } => {
qdus.insert(*qdu);
}
_ => {}
}
}
Ok(qdus)
}
pub fn get_classical_register(&self, name: &str) -> u64 {
self.classical_memory.get(name).copied().unwrap_or(0)
}
pub fn get_classical_memory(&self) -> HashMap<String, u64> {
self.classical_memory.clone()
}
pub fn get_final_state(&self) -> Option<crate::PotentialityState> {
self.engine.as_ref().map(|e| e.get_state().clone())
}
}
impl Default for OnqVm {
fn default() -> Self {
Self::new()
}
}