strange_loop/
quantum_container.rs

1//! Quantum-classical hybrid computing containers
2//!
3//! This module implements quantum-inspired computing using classical containers
4//! that simulate superposition, entanglement, and quantum interference effects.
5
6use crate::error::{LoopError, Result};
7use crate::types::{ComplexVector, QuantumAmplitude};
8use num_complex::Complex64;
9use rand::{thread_rng, Rng};
10use serde::{Deserialize, Serialize};
11use std::collections::HashMap;
12
13/// Quantum state representation
14#[derive(Clone, Debug, Serialize, Deserialize)]
15pub struct QuantumState {
16    /// Number of qubits
17    pub num_qubits: usize,
18    /// Amplitude vector (2^num_qubits complex numbers)
19    pub amplitudes: ComplexVector,
20    /// Phase factors
21    pub phases: Vec<f64>,
22    /// Measurement probability cache
23    probability_cache: Option<Vec<f64>>,
24}
25
26impl QuantumState {
27    /// Create a new quantum state in |0...0⟩ state
28    pub fn new(num_qubits: usize) -> Result<Self> {
29        if num_qubits == 0 {
30            return Err(LoopError::quantum_error("Number of qubits must be positive"));
31        }
32        if num_qubits > 20 {
33            return Err(LoopError::quantum_error("Too many qubits (memory limit)"));
34        }
35
36        let num_states = 1 << num_qubits; // 2^num_qubits
37        let mut amplitudes = vec![Complex64::new(0.0, 0.0); num_states];
38        amplitudes[0] = Complex64::new(1.0, 0.0); // |0...0⟩ state
39
40        Ok(Self {
41            num_qubits,
42            amplitudes,
43            phases: vec![0.0; num_qubits],
44            probability_cache: None,
45        })
46    }
47
48    /// Create a uniform superposition state |+...+⟩
49    pub fn uniform_superposition(num_qubits: usize) -> Result<Self> {
50        let mut state = Self::new(num_qubits)?;
51        let num_states = 1 << num_qubits;
52        let amplitude = Complex64::new(1.0 / (num_states as f64).sqrt(), 0.0);
53
54        for i in 0..num_states {
55            state.amplitudes[i] = amplitude;
56        }
57
58        state.invalidate_cache();
59        Ok(state)
60    }
61
62    /// Create a random quantum state
63    pub fn random(num_qubits: usize) -> Result<Self> {
64        let mut state = Self::new(num_qubits)?;
65        let mut rng = thread_rng();
66        let num_states = 1 << num_qubits;
67
68        // Generate random complex amplitudes
69        for i in 0..num_states {
70            let real: f64 = rng.gen_range(-1.0..1.0);
71            let imag: f64 = rng.gen_range(-1.0..1.0);
72            state.amplitudes[i] = Complex64::new(real, imag);
73        }
74
75        // Normalize
76        state.normalize()?;
77        Ok(state)
78    }
79
80    /// Get the probability of measuring a specific state
81    pub fn get_probability(&self, state_index: usize) -> f64 {
82        if state_index >= self.amplitudes.len() {
83            return 0.0;
84        }
85        self.amplitudes[state_index].norm_sqr()
86    }
87
88    /// Get all probabilities
89    pub fn probabilities(&mut self) -> &[f64] {
90        if self.probability_cache.is_none() {
91            self.probability_cache = Some(
92                self.amplitudes.iter()
93                    .map(|amp| amp.norm_sqr())
94                    .collect()
95            );
96        }
97        self.probability_cache.as_ref().unwrap()
98    }
99
100    /// Normalize the quantum state
101    pub fn normalize(&mut self) -> Result<()> {
102        let norm_squared: f64 = self.amplitudes.iter()
103            .map(|amp| amp.norm_sqr())
104            .sum();
105
106        if norm_squared < f64::EPSILON {
107            return Err(LoopError::quantum_error("Cannot normalize zero state"));
108        }
109
110        let norm = norm_squared.sqrt();
111        for amplitude in &mut self.amplitudes {
112            *amplitude /= norm;
113        }
114
115        self.invalidate_cache();
116        Ok(())
117    }
118
119    /// Apply a single-qubit gate
120    pub fn apply_single_qubit_gate(&mut self, qubit: usize, gate: &Gate) -> Result<()> {
121        if qubit >= self.num_qubits {
122            return Err(LoopError::quantum_error("Qubit index out of range"));
123        }
124
125        let matrix = gate.matrix();
126        let mut new_amplitudes = self.amplitudes.clone();
127
128        for state in 0..(1 << self.num_qubits) {
129            let qubit_bit = (state >> qubit) & 1;
130            let other_state = state ^ (1 << qubit); // Flip the qubit bit
131
132            if qubit_bit == 0 {
133                // Apply gate transformation
134                let amp0 = self.amplitudes[state];
135                let amp1 = self.amplitudes[other_state];
136
137                new_amplitudes[state] = matrix[(0, 0)] * amp0 + matrix[(0, 1)] * amp1;
138                new_amplitudes[other_state] = matrix[(1, 0)] * amp0 + matrix[(1, 1)] * amp1;
139            }
140        }
141
142        self.amplitudes = new_amplitudes;
143        self.invalidate_cache();
144        Ok(())
145    }
146
147    /// Apply a two-qubit gate (like CNOT)
148    pub fn apply_two_qubit_gate(&mut self, control: usize, target: usize, gate: &TwoQubitGate) -> Result<()> {
149        if control >= self.num_qubits || target >= self.num_qubits {
150            return Err(LoopError::quantum_error("Qubit index out of range"));
151        }
152        if control == target {
153            return Err(LoopError::quantum_error("Control and target qubits must be different"));
154        }
155
156        let matrix = gate.matrix();
157        let mut new_amplitudes = self.amplitudes.clone();
158
159        for state in 0..(1 << self.num_qubits) {
160            let control_bit = (state >> control) & 1;
161            let target_bit = (state >> target) & 1;
162            let two_bit_state = (control_bit << 1) | target_bit;
163
164            // Find the other states that could contribute
165            let base_state = state & !(1 << control) & !(1 << target);
166            let states = [
167                base_state,
168                base_state | (1 << control),
169                base_state | (1 << target),
170                base_state | (1 << control) | (1 << target),
171            ];
172
173            // Apply the 4x4 transformation matrix
174            if state == states[two_bit_state] {
175                let mut new_amp = Complex64::new(0.0, 0.0);
176                for i in 0..4 {
177                    new_amp += matrix[(two_bit_state, i)] * self.amplitudes[states[i]];
178                }
179                new_amplitudes[state] = new_amp;
180            }
181        }
182
183        self.amplitudes = new_amplitudes;
184        self.invalidate_cache();
185        Ok(())
186    }
187
188    /// Measure the quantum state and collapse it
189    pub fn measure(&mut self) -> usize {
190        let probabilities = self.probabilities().to_vec();
191        let mut rng = thread_rng();
192        let random_value: f64 = rng.gen();
193
194        let mut cumulative_prob = 0.0;
195        for (index, &prob) in probabilities.iter().enumerate() {
196            cumulative_prob += prob;
197            if random_value <= cumulative_prob {
198                // Collapse to this state
199                self.amplitudes.fill(Complex64::new(0.0, 0.0));
200                self.amplitudes[index] = Complex64::new(1.0, 0.0);
201                self.invalidate_cache();
202                return index;
203            }
204        }
205
206        // Fallback (shouldn't happen with proper normalization)
207        let last_index = self.amplitudes.len() - 1;
208        self.amplitudes.fill(Complex64::new(0.0, 0.0));
209        self.amplitudes[last_index] = Complex64::new(1.0, 0.0);
210        self.invalidate_cache();
211        last_index
212    }
213
214    /// Measure a specific qubit
215    pub fn measure_qubit(&mut self, qubit: usize) -> Result<u8> {
216        if qubit >= self.num_qubits {
217            return Err(LoopError::quantum_error("Qubit index out of range"));
218        }
219
220        // Calculate probability of measuring |1⟩
221        let prob_one: f64 = self.amplitudes.iter()
222            .enumerate()
223            .filter(|(state, _)| (state >> qubit) & 1 == 1)
224            .map(|(_, amp)| amp.norm_sqr())
225            .sum();
226
227        let mut rng = thread_rng();
228        let result = if rng.gen::<f64>() < prob_one { 1 } else { 0 };
229
230        // Collapse the state
231        let norm_factor = if result == 1 { prob_one.sqrt() } else { (1.0 - prob_one).sqrt() };
232
233        for (state, amplitude) in self.amplitudes.iter_mut().enumerate() {
234            if ((state >> qubit) & 1) as u8 != result {
235                *amplitude = Complex64::new(0.0, 0.0);
236            } else {
237                *amplitude /= norm_factor;
238            }
239        }
240
241        self.invalidate_cache();
242        Ok(result)
243    }
244
245    /// Calculate the entanglement entropy between two qubits
246    pub fn entanglement_entropy(&self, qubit_a: usize, qubit_b: usize) -> Result<f64> {
247        if qubit_a >= self.num_qubits || qubit_b >= self.num_qubits {
248            return Err(LoopError::quantum_error("Qubit index out of range"));
249        }
250
251        // Simplified entanglement calculation
252        let mut joint_probs = HashMap::new();
253
254        for (state, amplitude) in self.amplitudes.iter().enumerate() {
255            let bit_a = (state >> qubit_a) & 1;
256            let bit_b = (state >> qubit_b) & 1;
257            let joint_state = (bit_a << 1) | bit_b;
258
259            *joint_probs.entry(joint_state).or_insert(0.0) += amplitude.norm_sqr();
260        }
261
262        // Calculate entropy
263        let mut entropy = 0.0;
264        for &prob in joint_probs.values() {
265            if prob > f64::EPSILON {
266                entropy -= prob * prob.log2();
267            }
268        }
269
270        Ok(entropy)
271    }
272
273    /// Get the fidelity with another quantum state
274    pub fn fidelity(&self, other: &QuantumState) -> Result<f64> {
275        if self.num_qubits != other.num_qubits {
276            return Err(LoopError::quantum_error("States must have the same number of qubits"));
277        }
278
279        let overlap: Complex64 = self.amplitudes.iter()
280            .zip(other.amplitudes.iter())
281            .map(|(a, b)| a.conj() * b)
282            .sum();
283
284        Ok(overlap.norm_sqr())
285    }
286
287    /// Apply a phase to a specific qubit
288    pub fn apply_phase(&mut self, qubit: usize, phase: f64) -> Result<()> {
289        if qubit >= self.num_qubits {
290            return Err(LoopError::quantum_error("Qubit index out of range"));
291        }
292
293        let phase_factor = Complex64::new(phase.cos(), phase.sin());
294
295        for (state, amplitude) in self.amplitudes.iter_mut().enumerate() {
296            if (state >> qubit) & 1 == 1 {
297                *amplitude *= phase_factor;
298            }
299        }
300
301        self.phases[qubit] += phase;
302        self.invalidate_cache();
303        Ok(())
304    }
305
306    /// Get the expectation value of a Pauli operator
307    pub fn expectation_pauli(&self, qubit: usize, pauli: PauliOperator) -> Result<f64> {
308        if qubit >= self.num_qubits {
309            return Err(LoopError::quantum_error("Qubit index out of range"));
310        }
311
312        match pauli {
313            PauliOperator::X => {
314                // ⟨ψ|X|ψ⟩
315                let mut expectation = 0.0;
316                for (state, amplitude) in self.amplitudes.iter().enumerate() {
317                    let flipped_state = state ^ (1 << qubit);
318                    expectation += 2.0 * (amplitude.conj() * self.amplitudes[flipped_state]).re;
319                }
320                Ok(expectation)
321            }
322            PauliOperator::Y => {
323                // ⟨ψ|Y|ψ⟩
324                let mut expectation = 0.0;
325                for (state, amplitude) in self.amplitudes.iter().enumerate() {
326                    let flipped_state = state ^ (1 << qubit);
327                    let sign = if (state >> qubit) & 1 == 0 { 1.0 } else { -1.0 };
328                    expectation += 2.0 * sign * (amplitude.conj() * self.amplitudes[flipped_state]).im;
329                }
330                Ok(expectation)
331            }
332            PauliOperator::Z => {
333                // ⟨ψ|Z|ψ⟩
334                let mut expectation = 0.0;
335                for (state, amplitude) in self.amplitudes.iter().enumerate() {
336                    let sign = if (state >> qubit) & 1 == 0 { 1.0 } else { -1.0 };
337                    expectation += sign * amplitude.norm_sqr();
338                }
339                Ok(expectation)
340            }
341        }
342    }
343
344    fn invalidate_cache(&mut self) {
345        self.probability_cache = None;
346    }
347}
348
349/// Pauli operators
350#[derive(Clone, Copy, Debug, PartialEq, Eq)]
351pub enum PauliOperator {
352    X, // Pauli-X (bit flip)
353    Y, // Pauli-Y
354    Z, // Pauli-Z (phase flip)
355}
356
357/// Single-qubit quantum gates
358#[derive(Clone, Debug)]
359pub enum Gate {
360    /// Identity gate
361    I,
362    /// Pauli-X gate (NOT)
363    X,
364    /// Pauli-Y gate
365    Y,
366    /// Pauli-Z gate
367    Z,
368    /// Hadamard gate
369    H,
370    /// Phase gate (S)
371    S,
372    /// T gate
373    T,
374    /// Rotation around X-axis
375    RX(f64),
376    /// Rotation around Y-axis
377    RY(f64),
378    /// Rotation around Z-axis
379    RZ(f64),
380    /// Custom 2x2 unitary matrix
381    Custom(nalgebra::Matrix2<Complex64>),
382}
383
384impl Gate {
385    /// Get the matrix representation of the gate
386    pub fn matrix(&self) -> nalgebra::Matrix2<Complex64> {
387        use nalgebra::Matrix2;
388
389        match self {
390            Gate::I => Matrix2::new(
391                Complex64::new(1.0, 0.0), Complex64::new(0.0, 0.0),
392                Complex64::new(0.0, 0.0), Complex64::new(1.0, 0.0),
393            ),
394            Gate::X => Matrix2::new(
395                Complex64::new(0.0, 0.0), Complex64::new(1.0, 0.0),
396                Complex64::new(1.0, 0.0), Complex64::new(0.0, 0.0),
397            ),
398            Gate::Y => Matrix2::new(
399                Complex64::new(0.0, 0.0), Complex64::new(0.0, -1.0),
400                Complex64::new(0.0, 1.0), Complex64::new(0.0, 0.0),
401            ),
402            Gate::Z => Matrix2::new(
403                Complex64::new(1.0, 0.0), Complex64::new(0.0, 0.0),
404                Complex64::new(0.0, 0.0), Complex64::new(-1.0, 0.0),
405            ),
406            Gate::H => {
407                let inv_sqrt2 = 1.0 / 2.0_f64.sqrt();
408                Matrix2::new(
409                    Complex64::new(inv_sqrt2, 0.0), Complex64::new(inv_sqrt2, 0.0),
410                    Complex64::new(inv_sqrt2, 0.0), Complex64::new(-inv_sqrt2, 0.0),
411                )
412            }
413            Gate::S => Matrix2::new(
414                Complex64::new(1.0, 0.0), Complex64::new(0.0, 0.0),
415                Complex64::new(0.0, 0.0), Complex64::new(0.0, 1.0),
416            ),
417            Gate::T => Matrix2::new(
418                Complex64::new(1.0, 0.0), Complex64::new(0.0, 0.0),
419                Complex64::new(0.0, 0.0), Complex64::new(1.0/2.0_f64.sqrt(), 1.0/2.0_f64.sqrt()),
420            ),
421            Gate::RX(theta) => {
422                let half_theta = theta / 2.0;
423                let cos_val = half_theta.cos();
424                let sin_val = half_theta.sin();
425                Matrix2::new(
426                    Complex64::new(cos_val, 0.0), Complex64::new(0.0, -sin_val),
427                    Complex64::new(0.0, -sin_val), Complex64::new(cos_val, 0.0),
428                )
429            }
430            Gate::RY(theta) => {
431                let half_theta = theta / 2.0;
432                let cos_val = half_theta.cos();
433                let sin_val = half_theta.sin();
434                Matrix2::new(
435                    Complex64::new(cos_val, 0.0), Complex64::new(-sin_val, 0.0),
436                    Complex64::new(sin_val, 0.0), Complex64::new(cos_val, 0.0),
437                )
438            }
439            Gate::RZ(theta) => {
440                let half_theta = theta / 2.0;
441                Matrix2::new(
442                    Complex64::new(half_theta.cos(), -half_theta.sin()), Complex64::new(0.0, 0.0),
443                    Complex64::new(0.0, 0.0), Complex64::new(half_theta.cos(), half_theta.sin()),
444                )
445            }
446            Gate::Custom(matrix) => *matrix,
447        }
448    }
449}
450
451/// Two-qubit quantum gates
452#[derive(Clone, Debug)]
453pub enum TwoQubitGate {
454    /// CNOT gate (controlled-X)
455    CNOT,
456    /// Controlled-Z gate
457    CZ,
458    /// SWAP gate
459    SWAP,
460    /// Custom 4x4 unitary matrix
461    Custom(nalgebra::Matrix4<Complex64>),
462}
463
464impl TwoQubitGate {
465    /// Get the matrix representation of the two-qubit gate
466    pub fn matrix(&self) -> nalgebra::Matrix4<Complex64> {
467        use nalgebra::Matrix4;
468
469        match self {
470            TwoQubitGate::CNOT => Matrix4::new(
471                Complex64::new(1.0, 0.0), Complex64::new(0.0, 0.0), Complex64::new(0.0, 0.0), Complex64::new(0.0, 0.0),
472                Complex64::new(0.0, 0.0), Complex64::new(1.0, 0.0), Complex64::new(0.0, 0.0), Complex64::new(0.0, 0.0),
473                Complex64::new(0.0, 0.0), Complex64::new(0.0, 0.0), Complex64::new(0.0, 0.0), Complex64::new(1.0, 0.0),
474                Complex64::new(0.0, 0.0), Complex64::new(0.0, 0.0), Complex64::new(1.0, 0.0), Complex64::new(0.0, 0.0),
475            ),
476            TwoQubitGate::CZ => Matrix4::new(
477                Complex64::new(1.0, 0.0), Complex64::new(0.0, 0.0), Complex64::new(0.0, 0.0), Complex64::new(0.0, 0.0),
478                Complex64::new(0.0, 0.0), Complex64::new(1.0, 0.0), Complex64::new(0.0, 0.0), Complex64::new(0.0, 0.0),
479                Complex64::new(0.0, 0.0), Complex64::new(0.0, 0.0), Complex64::new(1.0, 0.0), Complex64::new(0.0, 0.0),
480                Complex64::new(0.0, 0.0), Complex64::new(0.0, 0.0), Complex64::new(0.0, 0.0), Complex64::new(-1.0, 0.0),
481            ),
482            TwoQubitGate::SWAP => Matrix4::new(
483                Complex64::new(1.0, 0.0), Complex64::new(0.0, 0.0), Complex64::new(0.0, 0.0), Complex64::new(0.0, 0.0),
484                Complex64::new(0.0, 0.0), Complex64::new(0.0, 0.0), Complex64::new(1.0, 0.0), Complex64::new(0.0, 0.0),
485                Complex64::new(0.0, 0.0), Complex64::new(1.0, 0.0), Complex64::new(0.0, 0.0), Complex64::new(0.0, 0.0),
486                Complex64::new(0.0, 0.0), Complex64::new(0.0, 0.0), Complex64::new(0.0, 0.0), Complex64::new(1.0, 0.0),
487            ),
488            TwoQubitGate::Custom(matrix) => *matrix,
489        }
490    }
491}
492
493/// Quantum-classical hybrid container
494pub struct QuantumContainer {
495    quantum_state: QuantumState,
496    classical_memory: HashMap<String, f64>,
497    hybrid_operations: Vec<HybridOperation>,
498    entanglement_map: HashMap<(usize, usize), f64>,
499}
500
501impl QuantumContainer {
502    /// Create a new quantum container
503    pub fn new(num_qubits: usize) -> Self {
504        Self {
505            quantum_state: QuantumState::new(num_qubits).expect("Failed to create quantum state"),
506            classical_memory: HashMap::new(),
507            hybrid_operations: Vec::new(),
508            entanglement_map: HashMap::new(),
509        }
510    }
511
512    /// Set a superposition state
513    pub fn set_superposition_state(&mut self, state_index: usize, amplitude: QuantumAmplitude) {
514        if state_index < self.quantum_state.amplitudes.len() {
515            self.quantum_state.amplitudes[state_index] = amplitude;
516            self.quantum_state.invalidate_cache();
517        }
518    }
519
520    /// Get probability of a specific state
521    pub fn get_probability(&self, state_index: usize) -> f64 {
522        self.quantum_state.get_probability(state_index)
523    }
524
525    /// Measure the quantum state
526    pub fn measure(&mut self) -> usize {
527        self.quantum_state.measure()
528    }
529
530    /// Store classical data
531    pub fn store_classical(&mut self, key: String, value: f64) {
532        self.classical_memory.insert(key, value);
533    }
534
535    /// Retrieve classical data
536    pub fn get_classical(&self, key: &str) -> Option<f64> {
537        self.classical_memory.get(key).copied()
538    }
539
540    /// Perform quantum-classical hybrid operation
541    pub fn hybrid_operation(&mut self, operation: HybridOperation) -> Result<f64> {
542        match operation {
543            HybridOperation::QuantumToClassical { qubit, target_key } => {
544                let measurement = self.quantum_state.measure_qubit(qubit)? as f64;
545                self.classical_memory.insert(target_key, measurement);
546                Ok(measurement)
547            }
548            HybridOperation::ClassicalToQuantum { source_key, qubit, gate_type } => {
549                let classical_value = self.classical_memory.get(&source_key)
550                    .ok_or_else(|| LoopError::quantum_error("Classical key not found"))?;
551
552                match gate_type.as_str() {
553                    "RX" => self.quantum_state.apply_single_qubit_gate(qubit, &Gate::RX(*classical_value))?,
554                    "RY" => self.quantum_state.apply_single_qubit_gate(qubit, &Gate::RY(*classical_value))?,
555                    "RZ" => self.quantum_state.apply_single_qubit_gate(qubit, &Gate::RZ(*classical_value))?,
556                    _ => return Err(LoopError::quantum_error("Unknown gate type")),
557                }
558                Ok(*classical_value)
559            }
560            HybridOperation::EntanglementCheck { qubit_a, qubit_b } => {
561                let entropy = self.quantum_state.entanglement_entropy(qubit_a, qubit_b)?;
562                self.entanglement_map.insert((qubit_a, qubit_b), entropy);
563                Ok(entropy)
564            }
565        }
566    }
567
568    /// Apply quantum gate
569    pub fn apply_gate(&mut self, qubit: usize, gate: Gate) -> Result<()> {
570        self.quantum_state.apply_single_qubit_gate(qubit, &gate)
571    }
572
573    /// Apply two-qubit gate
574    pub fn apply_two_qubit_gate(&mut self, control: usize, target: usize, gate: TwoQubitGate) -> Result<()> {
575        self.quantum_state.apply_two_qubit_gate(control, target, &gate)
576    }
577
578    /// Get quantum state reference
579    pub fn quantum_state(&self) -> &QuantumState {
580        &self.quantum_state
581    }
582
583    /// Get quantum state mutably
584    pub fn quantum_state_mut(&mut self) -> &mut QuantumState {
585        &mut self.quantum_state
586    }
587
588    /// Get classical memory reference
589    pub fn classical_memory(&self) -> &HashMap<String, f64> {
590        &self.classical_memory
591    }
592
593    /// Create quantum superposition from classical probability distribution
594    pub fn create_superposition_from_classical(&mut self, probabilities: &[f64]) -> Result<()> {
595        if probabilities.len() != self.quantum_state.amplitudes.len() {
596            return Err(LoopError::quantum_error("Probability array length mismatch"));
597        }
598
599        // Convert probabilities to amplitudes (taking square root)
600        for (i, &prob) in probabilities.iter().enumerate() {
601            if prob < 0.0 {
602                return Err(LoopError::quantum_error("Probabilities must be non-negative"));
603            }
604            self.quantum_state.amplitudes[i] = Complex64::new(prob.sqrt(), 0.0);
605        }
606
607        self.quantum_state.normalize()?;
608        Ok(())
609    }
610
611    /// Evolve quantum state using classical feedback
612    pub fn classical_feedback_evolution(&mut self, feedback_fn: impl Fn(&HashMap<String, f64>) -> Vec<f64>) -> Result<()> {
613        let feedback = feedback_fn(&self.classical_memory);
614
615        // Apply feedback as rotation angles to qubits
616        for (i, &angle) in feedback.iter().enumerate() {
617            if i < self.quantum_state.num_qubits {
618                self.quantum_state.apply_phase(i, angle)?;
619            }
620        }
621
622        Ok(())
623    }
624
625    /// Calculate quantum-classical correlation
626    pub fn quantum_classical_correlation(&self, qubit: usize, classical_key: &str) -> Result<f64> {
627        let classical_value = self.classical_memory.get(classical_key)
628            .ok_or_else(|| LoopError::quantum_error("Classical key not found"))?;
629
630        // Calculate correlation between qubit expectation and classical value
631        let z_expectation = self.quantum_state.expectation_pauli(qubit, PauliOperator::Z)?;
632
633        // Simple correlation measure (could be enhanced)
634        Ok(z_expectation * classical_value)
635    }
636}
637
638/// Hybrid operations that bridge quantum and classical domains
639#[derive(Clone, Debug, Serialize, Deserialize)]
640pub enum HybridOperation {
641    /// Measure quantum state and store in classical memory
642    QuantumToClassical {
643        qubit: usize,
644        target_key: String,
645    },
646    /// Use classical value to control quantum gate
647    ClassicalToQuantum {
648        source_key: String,
649        qubit: usize,
650        gate_type: String,
651    },
652    /// Check entanglement between qubits
653    EntanglementCheck {
654        qubit_a: usize,
655        qubit_b: usize,
656    },
657}
658
659/// Superposition trait for objects that can exist in multiple states
660pub trait Superposition<T> {
661    /// Create superposition from multiple states
662    fn from_states(states: Vec<T>, amplitudes: Vec<Complex64>) -> Result<Self>
663    where
664        Self: Sized;
665
666    /// Collapse superposition to single state
667    fn collapse(&mut self) -> T;
668
669    /// Get probability of specific state
670    fn probability(&self, state: &T) -> f64;
671
672    /// Apply transformation to all states in superposition
673    fn transform<F>(&mut self, f: F) -> Result<()>
674    where
675        F: Fn(&mut T);
676}
677
678#[cfg(test)]
679mod tests {
680    use super::*;
681    use approx::assert_relative_eq;
682
683    #[test]
684    fn test_quantum_state_creation() {
685        let state = QuantumState::new(2).unwrap();
686        assert_eq!(state.num_qubits, 2);
687        assert_eq!(state.amplitudes.len(), 4);
688        assert_eq!(state.get_probability(0), 1.0); // |00⟩ state
689    }
690
691    #[test]
692    fn test_uniform_superposition() {
693        let state = QuantumState::uniform_superposition(2).unwrap();
694
695        // All states should have equal probability
696        for i in 0..4 {
697            assert_relative_eq!(state.get_probability(i), 0.25, epsilon = 1e-10);
698        }
699    }
700
701    #[test]
702    fn test_quantum_gate_application() {
703        let mut state = QuantumState::new(1).unwrap();
704
705        // Apply X gate - should flip |0⟩ to |1⟩
706        state.apply_single_qubit_gate(0, &Gate::X).unwrap();
707        assert_relative_eq!(state.get_probability(0), 0.0, epsilon = 1e-10);
708        assert_relative_eq!(state.get_probability(1), 1.0, epsilon = 1e-10);
709    }
710
711    #[test]
712    fn test_hadamard_gate() {
713        let mut state = QuantumState::new(1).unwrap();
714
715        // Apply Hadamard gate - should create equal superposition
716        state.apply_single_qubit_gate(0, &Gate::H).unwrap();
717        assert_relative_eq!(state.get_probability(0), 0.5, epsilon = 1e-10);
718        assert_relative_eq!(state.get_probability(1), 0.5, epsilon = 1e-10);
719    }
720
721    #[test]
722    fn test_cnot_gate() {
723        let mut state = QuantumState::new(2).unwrap();
724
725        // First create |+0⟩ = (|00⟩ + |10⟩)/√2
726        state.apply_single_qubit_gate(0, &Gate::H).unwrap();
727
728        // Then apply CNOT to create Bell state
729        state.apply_two_qubit_gate(0, 1, &TwoQubitGate::CNOT).unwrap();
730
731        // Should have |00⟩ and |11⟩ with equal probability
732        assert_relative_eq!(state.get_probability(0), 0.5, epsilon = 1e-10); // |00⟩
733        assert_relative_eq!(state.get_probability(3), 0.5, epsilon = 1e-10); // |11⟩
734        assert_relative_eq!(state.get_probability(1), 0.0, epsilon = 1e-10); // |01⟩
735        assert_relative_eq!(state.get_probability(2), 0.0, epsilon = 1e-10); // |10⟩
736    }
737
738    #[test]
739    fn test_measurement() {
740        let mut state = QuantumState::new(1).unwrap();
741        state.apply_single_qubit_gate(0, &Gate::H).unwrap(); // Equal superposition
742
743        let measurement = state.measure();
744        assert!(measurement == 0 || measurement == 1);
745
746        // After measurement, state should be collapsed
747        if measurement == 0 {
748            assert_relative_eq!(state.get_probability(0), 1.0, epsilon = 1e-10);
749        } else {
750            assert_relative_eq!(state.get_probability(1), 1.0, epsilon = 1e-10);
751        }
752    }
753
754    #[test]
755    fn test_qubit_measurement() {
756        let mut state = QuantumState::new(2).unwrap();
757        state.apply_single_qubit_gate(0, &Gate::H).unwrap(); // Superposition on first qubit
758
759        let result = state.measure_qubit(0).unwrap();
760        assert!(result == 0 || result == 1);
761
762        // First qubit should be collapsed, second should still be |0⟩
763        if result == 0 {
764            assert_relative_eq!(state.get_probability(0), 1.0, epsilon = 1e-10); // |00⟩
765        } else {
766            assert_relative_eq!(state.get_probability(2), 1.0, epsilon = 1e-10); // |10⟩
767        }
768    }
769
770    #[test]
771    fn test_pauli_expectation() {
772        let mut state = QuantumState::new(1).unwrap();
773
774        // For |0⟩ state, ⟨Z⟩ = 1
775        let z_exp = state.expectation_pauli(0, PauliOperator::Z).unwrap();
776        assert_relative_eq!(z_exp, 1.0, epsilon = 1e-10);
777
778        // Apply X gate to get |1⟩ state, ⟨Z⟩ = -1
779        state.apply_single_qubit_gate(0, &Gate::X).unwrap();
780        let z_exp = state.expectation_pauli(0, PauliOperator::Z).unwrap();
781        assert_relative_eq!(z_exp, -1.0, epsilon = 1e-10);
782    }
783
784    #[test]
785    fn test_quantum_container() {
786        let mut container = QuantumContainer::new(2);
787
788        // Store classical data
789        container.store_classical("test".to_string(), 3.14);
790        assert_eq!(container.get_classical("test"), Some(3.14));
791
792        // Test quantum-classical hybrid operation
793        let measurement = container.hybrid_operation(HybridOperation::QuantumToClassical {
794            qubit: 0,
795            target_key: "measurement".to_string(),
796        }).unwrap();
797
798        assert!(measurement == 0.0 || measurement == 1.0);
799        assert!(container.get_classical("measurement").is_some());
800    }
801
802    #[test]
803    fn test_entanglement_entropy() {
804        let mut state = QuantumState::new(2).unwrap();
805
806        // Create Bell state
807        state.apply_single_qubit_gate(0, &Gate::H).unwrap();
808        state.apply_two_qubit_gate(0, 1, &TwoQubitGate::CNOT).unwrap();
809
810        let entropy = state.entanglement_entropy(0, 1).unwrap();
811        assert!(entropy > 0.0); // Should have some entanglement
812    }
813
814    #[test]
815    fn test_state_fidelity() {
816        let state1 = QuantumState::new(1).unwrap();
817        let state2 = QuantumState::new(1).unwrap();
818
819        // Identical states should have fidelity 1
820        let fidelity = state1.fidelity(&state2).unwrap();
821        assert_relative_eq!(fidelity, 1.0, epsilon = 1e-10);
822    }
823
824    #[test]
825    fn test_phase_application() {
826        let mut state = QuantumState::new(1).unwrap();
827        state.apply_single_qubit_gate(0, &Gate::H).unwrap(); // Equal superposition
828
829        // Apply phase
830        state.apply_phase(0, std::f64::consts::PI/2.0).unwrap();
831
832        // Probability should be unchanged
833        assert_relative_eq!(state.get_probability(0), 0.5, epsilon = 1e-10);
834        assert_relative_eq!(state.get_probability(1), 0.5, epsilon = 1e-10);
835    }
836
837    #[test]
838    fn test_random_state() {
839        let state = QuantumState::random(2).unwrap();
840
841        // Check normalization
842        let total_prob: f64 = (0..4).map(|i| state.get_probability(i)).sum();
843        assert_relative_eq!(total_prob, 1.0, epsilon = 1e-10);
844    }
845
846    #[test]
847    fn test_superposition_from_classical() {
848        let mut container = QuantumContainer::new(2);
849        let probabilities = vec![0.4, 0.3, 0.2, 0.1];
850
851        container.create_superposition_from_classical(&probabilities).unwrap();
852
853        // Check that probabilities match (within numerical precision)
854        for (i, &expected_prob) in probabilities.iter().enumerate() {
855            let actual_prob = container.get_probability(i);
856            assert_relative_eq!(actual_prob, expected_prob, epsilon = 1e-10);
857        }
858    }
859}