SNAPKITTYWEST's picture
push from SNAPKITTYWEST/carry-agent
80d7559 verified
Raw History Blame Contribute Delete
26.4 kB
// CARRY Quantum Simulator Core
// Pure First-Principles Quantum Simulation Engine
// Supports StateVector (|ψ⟩) & Density Matrix (ρ) simulation, Gates, Noise, and Measurements.
//
// DISCLAIMER & SAFETY REQUIREMENT:
// This system is explicitly a SIMULATOR AND RESEARCH PLATFORM.
// Simulated quantum entities are tagged with SIMULATED_* to distinguish from PHYSICAL_QUBIT.
use std::fmt;
/// Labels distinguishing simulated quantum constructs from physical hardware.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum QuantumEntityTag {
SimulatedQubit,
SimulatedQuantumState,
SimulatedEntanglement,
SimulatedTopologicalQubit,
PhysicalQubit, // Reserved for hardware disclaimers - never instantiated in simulator
}
impl fmt::Display for QuantumEntityTag {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
QuantumEntityTag::SimulatedQubit => write!(f, "SIMULATED_QUBIT"),
QuantumEntityTag::SimulatedQuantumState => write!(f, "SIMULATED_QUANTUM_STATE"),
QuantumEntityTag::SimulatedEntanglement => write!(f, "SIMULATED_ENTANGLEMENT"),
QuantumEntityTag::SimulatedTopologicalQubit => write!(f, "SIMULATED_TOPOLOGICAL_QUBIT"),
QuantumEntityTag::PhysicalQubit => write!(f, "PHYSICAL_QUBIT"),
}
}
}
/// Complex numbers for quantum amplitude representation (64-bit precision).
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Complex {
pub re: f64,
pub im: f64,
}
impl Complex {
pub fn new(re: f64, im: f64) -> Self {
Self { re, im }
}
pub fn zero() -> Self {
Self { re: 0.0, im: 0.0 }
}
pub fn one() -> Self {
Self { re: 1.0, im: 0.0 }
}
pub fn i() -> Self {
Self { re: 0.0, im: 1.0 }
}
pub fn norm_sq(&self) -> f64 {
self.re * self.re + self.im * self.im
}
pub fn norm(&self) -> f64 {
self.norm_sq().sqrt()
}
pub fn conj(&self) -> Self {
Self { re: self.re, im: -self.im }
}
pub fn add(&self, rhs: Self) -> Self {
Self { re: self.re + rhs.re, im: self.im + rhs.im }
}
pub fn sub(&self, rhs: Self) -> Self {
Self { re: self.re - rhs.re, im: self.im - rhs.im }
}
pub fn mul(&self, rhs: Self) -> Self {
Self {
re: self.re * rhs.re - self.im * rhs.im,
im: self.re * rhs.im + self.im * rhs.re,
}
}
pub fn scale(&self, s: f64) -> Self {
Self { re: self.re * s, im: self.im * s }
}
pub fn exp_i(theta: f64) -> Self {
Self { re: theta.cos(), im: theta.sin() }
}
}
impl fmt::Display for Complex {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.im >= 0.0 {
write!(f, "{:.4}+{:.4}i", self.re, self.im)
} else {
write!(f, "{:.4}{:.4}i", self.re, self.im)
}
}
}
/// Simulated Qubit entity.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Qubit {
pub id: usize,
pub label: String,
pub tag: QuantumEntityTag,
}
impl Qubit {
pub fn new(id: usize, label: impl Into<String>) -> Self {
Self {
id,
label: label.into(),
tag: QuantumEntityTag::SimulatedQubit,
}
}
}
/// Quantum Register containing multiple simulated qubits.
#[derive(Debug, Clone)]
pub struct QuantumRegister {
pub qubits: Vec<Qubit>,
pub tag: QuantumEntityTag,
}
impl QuantumRegister {
pub fn new(num_qubits: usize) -> Self {
let qubits = (0..num_qubits)
.map(|i| Qubit::new(i, format!("q{}", i)))
.collect();
Self {
qubits,
tag: QuantumEntityTag::SimulatedQubit,
}
}
pub fn num_qubits(&self) -> usize {
self.qubits.len()
}
}
/// Simulation Mode: StateVector vs Density Matrix.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SimulationMode {
StateVector,
DensityMatrix,
}
/// Quantum State representation: Pure Statevector (|ψ⟩) or Mixed Density Matrix (ρ).
#[derive(Debug, Clone)]
pub enum QuantumState {
StateVector {
num_qubits: usize,
amplitudes: Vec<Complex>,
tag: QuantumEntityTag,
},
DensityMatrix {
num_qubits: usize,
matrix: Vec<Vec<Complex>>, // 2^n x 2^n
tag: QuantumEntityTag,
},
}
impl QuantumState {
/// Initialize statevector |0...0⟩ for n qubits.
pub fn new_statevector(num_qubits: usize) -> Self {
let dim = 1 << num_qubits;
let mut amplitudes = vec![Complex::zero(); dim];
amplitudes[0] = Complex::one(); // |0...0⟩
QuantumState::StateVector {
num_qubits,
amplitudes,
tag: QuantumEntityTag::SimulatedQuantumState,
}
}
/// Initialize density matrix |0...0⟩⟨0...0| for n qubits.
pub fn new_density_matrix(num_qubits: usize) -> Self {
let dim = 1 << num_qubits;
let mut matrix = vec![vec![Complex::zero(); dim]; dim];
matrix[0][0] = Complex::one();
QuantumState::DensityMatrix {
num_qubits,
matrix,
tag: QuantumEntityTag::SimulatedQuantumState,
}
}
pub fn num_qubits(&self) -> usize {
match self {
QuantumState::StateVector { num_qubits, .. } => *num_qubits,
QuantumState::DensityMatrix { num_qubits, .. } => *num_qubits,
}
}
pub fn dimension(&self) -> usize {
1 << self.num_qubits()
}
pub fn tag(&self) -> QuantumEntityTag {
match self {
QuantumState::StateVector { tag, .. } => *tag,
QuantumState::DensityMatrix { tag, .. } => *tag,
}
}
/// Verify norm of statevector is 1.0 (or trace of density matrix is 1.0).
pub fn is_valid_state(&self) -> bool {
match self {
QuantumState::StateVector { amplitudes, .. } => {
let norm_sq: f64 = amplitudes.iter().map(|a| a.norm_sq()).sum();
(norm_sq - 1.0).abs() < 1e-6
}
QuantumState::DensityMatrix { matrix, .. } => {
let trace: f64 = (0..matrix.len()).map(|i| matrix[i][i].re).sum();
(trace - 1.0).abs() < 1e-6
}
}
}
/// Compute state purity Tr(ρ^2). For pure states, purity = 1.0.
pub fn purity(&self) -> f64 {
match self {
QuantumState::StateVector { .. } => 1.0,
QuantumState::DensityMatrix { matrix, .. } => {
let dim = matrix.len();
let mut trace_sq = 0.0;
for i in 0..dim {
for j in 0..dim {
// (ρ^2)_ii = sum_j ρ_ij * ρ_ji
let prod = matrix[i][j].mul(matrix[j][i]);
trace_sq += prod.re;
}
}
trace_sq
}
}
}
}
/// Standard single and multi-qubit quantum gate definitions.
#[derive(Debug, Clone)]
pub enum GateType {
I,
X,
Y,
Z,
H,
S,
T,
Rx(f64),
Ry(f64),
Rz(f64),
CNOT,
CZ,
SWAP,
CustomUnitary { label: String, matrix: Vec<Vec<Complex>> },
}
/// Gate operation with target and optional control qubits.
#[derive(Debug, Clone)]
pub struct Gate {
pub gate_type: GateType,
pub targets: Vec<usize>,
pub controls: Vec<usize>,
}
impl Gate {
pub fn h(target: usize) -> Self {
Self { gate_type: GateType::H, targets: vec![target], controls: vec![] }
}
pub fn x(target: usize) -> Self {
Self { gate_type: GateType::X, targets: vec![target], controls: vec![] }
}
pub fn y(target: usize) -> Self {
Self { gate_type: GateType::Y, targets: vec![target], controls: vec![] }
}
pub fn z(target: usize) -> Self {
Self { gate_type: GateType::Z, targets: vec![target], controls: vec![] }
}
pub fn s(target: usize) -> Self {
Self { gate_type: GateType::S, targets: vec![target], controls: vec![] }
}
pub fn t(target: usize) -> Self {
Self { gate_type: GateType::T, targets: vec![target], controls: vec![] }
}
pub fn rx(target: usize, theta: f64) -> Self {
Self { gate_type: GateType::Rx(theta), targets: vec![target], controls: vec![] }
}
pub fn ry(target: usize, theta: f64) -> Self {
Self { gate_type: GateType::Ry(theta), targets: vec![target], controls: vec![] }
}
pub fn rz(target: usize, theta: f64) -> Self {
Self { gate_type: GateType::Rz(theta), targets: vec![target], controls: vec![] }
}
pub fn cnot(control: usize, target: usize) -> Self {
Self { gate_type: GateType::CNOT, targets: vec![target], controls: vec![control] }
}
pub fn cz(control: usize, target: usize) -> Self {
Self { gate_type: GateType::CZ, targets: vec![target], controls: vec![control] }
}
pub fn swap(q1: usize, q2: usize) -> Self {
Self { gate_type: GateType::SWAP, targets: vec![q1, q2], controls: vec![] }
}
/// Return 2x2 matrix representation for single-qubit gate.
pub fn single_qubit_matrix(&self) -> Result<[[Complex; 2]; 2], String> {
let inv_sqrt2 = 1.0 / 2.0f64.sqrt();
match &self.gate_type {
GateType::I => Ok([
[Complex::one(), Complex::zero()],
[Complex::zero(), Complex::one()],
]),
GateType::X => Ok([
[Complex::zero(), Complex::one()],
[Complex::one(), Complex::zero()],
]),
GateType::Y => Ok([
[Complex::zero(), Complex::new(0.0, -1.0)],
[Complex::new(0.0, 1.0), Complex::zero()],
]),
GateType::Z => Ok([
[Complex::one(), Complex::zero()],
[Complex::zero(), Complex::new(-1.0, 0.0)],
]),
GateType::H => Ok([
[Complex::new(inv_sqrt2, 0.0), Complex::new(inv_sqrt2, 0.0)],
[Complex::new(inv_sqrt2, 0.0), Complex::new(-inv_sqrt2, 0.0)],
]),
GateType::S => Ok([
[Complex::one(), Complex::zero()],
[Complex::zero(), Complex::i()],
]),
GateType::T => Ok([
[Complex::one(), Complex::zero()],
[Complex::zero(), Complex::exp_i(std::f64::consts::FRAC_PI_4)],
]),
GateType::Rx(theta) => {
let cos = (theta / 2.0).cos();
let sin = (theta / 2.0).sin();
Ok([
[Complex::new(cos, 0.0), Complex::new(0.0, -sin)],
[Complex::new(0.0, -sin), Complex::new(cos, 0.0)],
])
}
GateType::Ry(theta) => {
let cos = (theta / 2.0).cos();
let sin = (theta / 2.0).sin();
Ok([
[Complex::new(cos, 0.0), Complex::new(-sin, 0.0)],
[Complex::new(sin, 0.0), Complex::new(cos, 0.0)],
])
}
GateType::Rz(theta) => Ok([
[Complex::exp_i(-theta / 2.0), Complex::zero()],
[Complex::zero(), Complex::exp_i(theta / 2.0)],
]),
_ => Err("Not a single qubit gate".into()),
}
}
}
/// Quantum Circuit containing sequence of gates and measurements.
#[derive(Debug, Clone)]
pub struct Circuit {
pub num_qubits: usize,
pub gates: Vec<Gate>,
}
impl Circuit {
pub fn new(num_qubits: usize) -> Self {
Self {
num_qubits,
gates: Vec::new(),
}
}
pub fn add_gate(&mut self, gate: Gate) {
self.gates.push(gate);
}
}
/// Noise & Error Models for quantum channel simulation.
#[derive(Debug, Clone)]
pub enum ErrorModel {
None,
BitFlip { probability: f64 },
PhaseFlip { probability: f64 },
Depolarizing { probability: f64 },
AmplitudeDamping { gamma: f64 },
}
/// Measurement result record.
#[derive(Debug, Clone)]
pub struct MeasurementResult {
pub qubit: usize,
pub outcome: u8, // 0 or 1
pub probability: f64,
}
/// Entanglement tracking graph.
#[derive(Debug, Clone)]
pub struct EntanglementGraph {
pub groups: Vec<Vec<usize>>,
pub tag: QuantumEntityTag,
}
impl EntanglementGraph {
pub fn new(num_qubits: usize) -> Self {
// Initially each qubit is independent
let groups = (0..num_qubits).map(|i| vec![i]).collect();
Self {
groups,
tag: QuantumEntityTag::SimulatedEntanglement,
}
}
pub fn entangle(&mut self, q1: usize, q2: usize) {
let g1_idx = self.groups.iter().position(|g| g.contains(&q1));
let g2_idx = self.groups.iter().position(|g| g.contains(&q2));
if let (Some(i1), Some(i2)) = (g1_idx, g2_idx) {
if i1 != i2 {
let mut g2 = self.groups.remove(i2.max(i1));
let g1_idx_adjusted = i1.min(i2);
self.groups[g1_idx_adjusted].append(&mut g2);
}
}
}
pub fn are_entangled(&self, q1: usize, q2: usize) -> bool {
self.groups.iter().any(|g| g.contains(&q1) && g.contains(&q2))
}
}
/// Simulation Executor Engine.
pub struct QuantumSimulator {
pub state: QuantumState,
pub entanglement_graph: EntanglementGraph,
pub error_model: ErrorModel,
}
impl QuantumSimulator {
pub fn new(num_qubits: usize, mode: SimulationMode, error_model: ErrorModel) -> Self {
let state = match mode {
SimulationMode::StateVector => QuantumState::new_statevector(num_qubits),
SimulationMode::DensityMatrix => QuantumState::new_density_matrix(num_qubits),
};
let entanglement_graph = EntanglementGraph::new(num_qubits);
Self {
state,
entanglement_graph,
error_model,
}
}
pub fn num_qubits(&self) -> usize {
self.state.num_qubits()
}
/// Apply a gate to the simulator state.
pub fn apply_gate(&mut self, gate: &Gate) -> Result<(), String> {
match &mut self.state {
QuantumState::StateVector { num_qubits, amplitudes, .. } => {
Self::apply_gate_to_statevector(*num_qubits, amplitudes, gate)?;
}
QuantumState::DensityMatrix { num_qubits, matrix, .. } => {
Self::apply_gate_to_density_matrix(*num_qubits, matrix, gate)?;
}
}
// Track entanglement if two-qubit gate
if gate.targets.len() + gate.controls.len() >= 2 {
let all_qubits: Vec<usize> = gate.controls.iter().chain(gate.targets.iter()).cloned().collect();
for window in all_qubits.windows(2) {
self.entanglement_graph.entangle(window[0], window[1]);
}
}
Ok(())
}
fn apply_gate_to_statevector(
num_qubits: usize,
amplitudes: &mut Vec<Complex>,
gate: &Gate,
) -> Result<(), String> {
let dim = 1 << num_qubits;
match &gate.gate_type {
GateType::H | GateType::X | GateType::Y | GateType::Z | GateType::S | GateType::T | GateType::Rx(_) | GateType::Ry(_) | GateType::Rz(_) => {
let target = gate.targets[0];
let matrix = gate.single_qubit_matrix()?;
let bit_mask = 1 << target;
let mut new_amps = amplitudes.clone();
for i in 0..dim {
if (i & bit_mask) == 0 {
let i0 = i;
let i1 = i | bit_mask;
let a0 = amplitudes[i0];
let a1 = amplitudes[i1];
new_amps[i0] = matrix[0][0].mul(a0).add(matrix[0][1].mul(a1));
new_amps[i1] = matrix[1][0].mul(a0).add(matrix[1][1].mul(a1));
}
}
*amplitudes = new_amps;
}
GateType::CNOT => {
let control = gate.controls[0];
let target = gate.targets[0];
let c_mask = 1 << control;
let t_mask = 1 << target;
for i in 0..dim {
if (i & c_mask) != 0 && (i & t_mask) == 0 {
let i0 = i;
let i1 = i | t_mask;
amplitudes.swap(i0, i1);
}
}
}
GateType::CZ => {
let control = gate.controls[0];
let target = gate.targets[0];
let c_mask = 1 << control;
let t_mask = 1 << target;
for i in 0..dim {
if (i & c_mask) != 0 && (i & t_mask) != 0 {
amplitudes[i] = amplitudes[i].scale(-1.0);
}
}
}
GateType::SWAP => {
let q1 = gate.targets[0];
let q2 = gate.targets[1];
let mask1 = 1 << q1;
let mask2 = 1 << q2;
for i in 0..dim {
let b1 = (i & mask1) != 0;
let b2 = (i & mask2) != 0;
if b1 && !b2 {
let i_other = (i & !mask1) | mask2;
if i < i_other {
amplitudes.swap(i, i_other);
}
}
}
}
GateType::I => {}
GateType::CustomUnitary { matrix, .. } => {
if gate.targets.len() == 1 {
let target = gate.targets[0];
let bit_mask = 1 << target;
let mut new_amps = amplitudes.clone();
for i in 0..dim {
if (i & bit_mask) == 0 {
let i0 = i;
let i1 = i | bit_mask;
let a0 = amplitudes[i0];
let a1 = amplitudes[i1];
new_amps[i0] = matrix[0][0].mul(a0).add(matrix[0][1].mul(a1));
new_amps[i1] = matrix[1][0].mul(a0).add(matrix[1][1].mul(a1));
}
}
*amplitudes = new_amps;
} else {
return Err("Multi-qubit custom unitaries not supported in basic vector engine".into());
}
}
}
Ok(())
}
fn apply_gate_to_density_matrix(
num_qubits: usize,
matrix: &mut Vec<Vec<Complex>>,
gate: &Gate,
) -> Result<(), String> {
// Density matrix transformation: ρ' = U ρ U†
let dim = 1 << num_qubits;
let mut u = vec![vec![Complex::zero(); dim]; dim];
for i in 0..dim {
u[i][i] = Complex::one();
}
let mut temp_amps = vec![Complex::zero(); dim];
// Build U matrix by applying gate to basis vectors
for col in 0..dim {
temp_amps.fill(Complex::zero());
temp_amps[col] = Complex::one();
Self::apply_gate_to_statevector(num_qubits, &mut temp_amps, gate)?;
for row in 0..dim {
u[row][col] = temp_amps[row];
}
}
// Compute U ρ U†
let mut temp = vec![vec![Complex::zero(); dim]; dim];
// Temp = U * ρ
for i in 0..dim {
for j in 0..dim {
let mut sum = Complex::zero();
for k in 0..dim {
sum = sum.add(u[i][k].mul(matrix[k][j]));
}
temp[i][j] = sum;
}
}
// Matrix = Temp * U†
for i in 0..dim {
for j in 0..dim {
let mut sum = Complex::zero();
for k in 0..dim {
sum = sum.add(temp[i][k].mul(u[j][k].conj()));
}
matrix[i][j] = sum;
}
}
Ok(())
}
/// Measure target qubit, returning probability of 1 and collapsing the state based on standard seed/threshold.
pub fn measure(&mut self, target: usize, random_draw: f64) -> Result<MeasurementResult, String> {
let num_qubits = self.state.num_qubits();
if target >= num_qubits {
return Err(format!("Target qubit {} out of bounds", target));
}
let bit_mask = 1 << target;
let prob_1 = match &self.state {
QuantumState::StateVector { amplitudes, .. } => {
amplitudes
.iter()
.enumerate()
.filter(|(idx, _)| (idx & bit_mask) != 0)
.map(|(_, amp)| amp.norm_sq())
.sum()
}
QuantumState::DensityMatrix { matrix, .. } => {
let dim = matrix.len();
(0..dim)
.filter(|idx| (idx & bit_mask) != 0)
.map(|idx| matrix[idx][idx].re)
.sum()
}
};
// CE-1 fix: clamp random_draw to [0,1) so callers cannot produce a
// zero-norm collapsed state by passing values >= 1.0 or < 0.0.
let random_draw = random_draw.clamp(0.0, 1.0 - f64::EPSILON);
let outcome = if random_draw < prob_1 { 1 } else { 0 };
// Collapse state
match &mut self.state {
QuantumState::StateVector { amplitudes, .. } => {
let norm = if outcome == 1 { prob_1.sqrt() } else { (1.0 - prob_1).sqrt() };
if norm <= 0.0 {
return Err(format!(
"MEASUREMENT_COLLAPSE_INVALID: outcome={} prob_1={} norm={}",
outcome, prob_1, norm
));
}
for (idx, amp) in amplitudes.iter_mut().enumerate() {
let matches = if outcome == 1 { (idx & bit_mask) != 0 } else { (idx & bit_mask) == 0 };
if matches {
*amp = amp.scale(1.0 / norm);
} else {
*amp = Complex::zero();
}
}
}
QuantumState::DensityMatrix { matrix, .. } => {
let dim = matrix.len();
let norm = if outcome == 1 { prob_1 } else { 1.0 - prob_1 };
for i in 0..dim {
for j in 0..dim {
let i_match = if outcome == 1 { (i & bit_mask) != 0 } else { (i & bit_mask) == 0 };
let j_match = if outcome == 1 { (j & bit_mask) != 0 } else { (j & bit_mask) == 0 };
if i_match && j_match && norm > 0.0 {
matrix[i][j] = matrix[i][j].scale(1.0 / norm);
} else {
matrix[i][j] = Complex::zero();
}
}
}
}
}
Ok(MeasurementResult {
qubit: target,
outcome,
probability: prob_1,
})
}
}
/// Execution Receipt generated at the completion of a quantum job or simulation cycle limit.
#[derive(Debug, Clone)]
pub struct ExecutionReceipt {
pub job_id: String,
pub status: String, // "SUCCESS", "HALT", "CYCLE_LIMIT", "UNSAT"
pub cycles_executed: usize,
pub qubits: usize,
pub gates: usize,
pub agents: usize,
pub entanglement_groups: usize,
pub measurements: usize,
pub icp_checks: usize,
pub asp_checks: usize,
pub failures: usize,
pub execution_time_ms: u128,
pub state_tag: QuantumEntityTag,
pub memory_bytes: usize,
}
impl fmt::Display for ExecutionReceipt {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(f, "═══════════════════════════════════════════════════════════════")?;
writeln!(f, " EXECUTION RECEIPT β€” CARRY QUANTUM SIMULATOR ")?;
writeln!(f, "═══════════════════════════════════════════════════════════════")?;
writeln!(f, " Job ID: {}", self.job_id)?;
writeln!(f, " Status: {}", self.status)?;
writeln!(f, " State Tag: {}", self.state_tag)?;
writeln!(f, " Cycles Executed: {}", self.cycles_executed)?;
writeln!(f, " Qubits: {}", self.qubits)?;
writeln!(f, " Gates: {}", self.gates)?;
writeln!(f, " Agents: {}", self.agents)?;
writeln!(f, " Entanglement Groups: {}", self.entanglement_groups)?;
writeln!(f, " Measurements: {}", self.measurements)?;
writeln!(f, " ICP Checks: {}", self.icp_checks)?;
writeln!(f, " ASP Checks: {}", self.asp_checks)?;
writeln!(f, " Failures: {}", self.failures)?;
writeln!(f, " Execution Time: {} ms", self.execution_time_ms)?;
writeln!(f, " Memory Consumption: {} bytes", self.memory_bytes)?;
writeln!(f, "═══════════════════════════════════════════════════════════════")
}
}