quantrs2_core/
photonic.rs

1//! Photonic Quantum Computing
2//!
3//! This module implements photonic quantum computing operations including
4//! linear optical quantum gates, photon-based qubits, and measurement-based
5//! quantum computation in the photonic platform.
6
7use crate::error::{QuantRS2Error, QuantRS2Result};
8use scirs2_core::ndarray::{Array1, Array2};
9use scirs2_core::Complex64;
10use std::collections::HashMap;
11
12/// Photonic quantum gate types
13#[derive(Debug, Clone, Copy, PartialEq)]
14pub enum PhotonicGateType {
15    /// Beam splitter with reflectivity parameter
16    BeamSplitter { reflectivity: f64 },
17    /// Phase shifter with phase parameter
18    PhaseShifter { phase: f64 },
19    /// Mach-Zehnder interferometer
20    MachZehnder { phase1: f64, phase2: f64 },
21    /// Controlled-Z gate using linear optics
22    ControlledZ,
23    /// Controlled-NOT gate using linear optics
24    ControlledNot,
25    /// Hong-Ou-Mandel interference
26    HongOuMandel,
27    /// Photon number measurement
28    PhotonNumber,
29    /// Homodyne measurement
30    Homodyne { phase: f64 },
31    /// Heterodyne measurement
32    Heterodyne,
33}
34
35/// Photonic qubit encoding
36#[derive(Debug, Clone, Copy, PartialEq)]
37pub enum PhotonicEncoding {
38    /// Dual-rail encoding (path encoding)
39    DualRail,
40    /// Polarization encoding
41    Polarization,
42    /// Time-bin encoding
43    TimeBin,
44    /// Frequency encoding
45    Frequency,
46    /// Continuous variable encoding
47    ContinuousVariable,
48}
49
50/// Optical mode representation
51#[derive(Debug, Clone)]
52pub struct OpticalMode {
53    /// Mode index
54    pub mode_id: usize,
55    /// Photon number state amplitudes
56    pub fock_state: Array1<Complex64>,
57    /// Maximum photon number considered
58    pub max_photons: usize,
59    /// Mode frequency (optional)
60    pub frequency: Option<f64>,
61    /// Mode polarization (optional)
62    pub polarization: Option<String>,
63}
64
65impl OpticalMode {
66    /// Create vacuum state
67    pub fn vacuum(mode_id: usize, max_photons: usize) -> Self {
68        let mut fock_state = Array1::zeros(max_photons + 1);
69        fock_state[0] = Complex64::new(1.0, 0.0); // |0⟩ state
70
71        Self {
72            mode_id,
73            fock_state,
74            max_photons,
75            frequency: None,
76            polarization: None,
77        }
78    }
79
80    /// Create single photon state
81    pub fn single_photon(mode_id: usize, max_photons: usize) -> Self {
82        let mut fock_state = Array1::zeros(max_photons + 1);
83        fock_state[1] = Complex64::new(1.0, 0.0); // |1⟩ state
84
85        Self {
86            mode_id,
87            fock_state,
88            max_photons,
89            frequency: None,
90            polarization: None,
91        }
92    }
93
94    /// Create coherent state |α⟩
95    pub fn coherent(mode_id: usize, max_photons: usize, alpha: Complex64) -> Self {
96        let mut fock_state = Array1::zeros(max_photons + 1);
97
98        // |α⟩ = e^{-|α|²/2} Σ_n α^n/√(n!) |n⟩
99        let alpha_norm_sq = alpha.norm_sqr();
100        let prefactor = (-alpha_norm_sq / 2.0).exp();
101
102        let mut factorial = 1.0;
103        for n in 0..=max_photons {
104            if n > 0 {
105                factorial *= n as f64;
106            }
107
108            let coefficient = prefactor * alpha.powf(n as f64) / factorial.sqrt();
109            fock_state[n] = coefficient;
110        }
111
112        Self {
113            mode_id,
114            fock_state,
115            max_photons,
116            frequency: None,
117            polarization: None,
118        }
119    }
120
121    /// Get photon number expectation value
122    pub fn photon_number_expectation(&self) -> f64 {
123        let mut expectation = 0.0;
124        for n in 0..=self.max_photons {
125            expectation += (n as f64) * self.fock_state[n].norm_sqr();
126        }
127        expectation
128    }
129
130    /// Get probability of measuring n photons
131    pub fn photon_probability(&self, n: usize) -> f64 {
132        if n > self.max_photons {
133            0.0
134        } else {
135            self.fock_state[n].norm_sqr()
136        }
137    }
138}
139
140/// Photonic quantum system
141#[derive(Debug, Clone)]
142pub struct PhotonicSystem {
143    /// Number of optical modes
144    pub num_modes: usize,
145    /// Optical modes
146    pub modes: Vec<OpticalMode>,
147    /// System state in multi-mode Fock basis
148    pub state: Option<Array1<Complex64>>,
149    /// Maximum photons per mode
150    pub max_photons_per_mode: usize,
151    /// Total maximum photons in system
152    pub max_total_photons: usize,
153}
154
155impl PhotonicSystem {
156    /// Create new photonic system
157    pub fn new(num_modes: usize, max_photons_per_mode: usize) -> Self {
158        let modes = (0..num_modes)
159            .map(|i| OpticalMode::vacuum(i, max_photons_per_mode))
160            .collect();
161
162        let max_total_photons = num_modes * max_photons_per_mode;
163
164        Self {
165            num_modes,
166            modes,
167            state: None,
168            max_photons_per_mode,
169            max_total_photons,
170        }
171    }
172
173    /// Initialize system state from individual mode states
174    pub fn initialize_from_modes(&mut self) -> QuantRS2Result<()> {
175        let total_dim = (self.max_photons_per_mode + 1).pow(self.num_modes as u32);
176        let mut state = Array1::zeros(total_dim);
177
178        // Compute tensor product of all mode states
179        state[0] = Complex64::new(1.0, 0.0);
180
181        for (mode_idx, mode) in self.modes.iter().enumerate() {
182            let mut new_state = Array1::zeros(total_dim);
183            let mode_dim = self.max_photons_per_mode + 1;
184
185            for (state_idx, &amplitude) in state.iter().enumerate() {
186                if amplitude.norm() > 1e-12 {
187                    for (n, &mode_amp) in mode.fock_state.iter().enumerate() {
188                        if mode_amp.norm() > 1e-12 {
189                            let new_idx = state_idx + n * mode_dim.pow(mode_idx as u32);
190                            if new_idx < total_dim {
191                                new_state[new_idx] += amplitude * mode_amp;
192                            }
193                        }
194                    }
195                }
196            }
197            state = new_state;
198        }
199
200        self.state = Some(state);
201        Ok(())
202    }
203
204    /// Apply beam splitter between two modes
205    pub fn apply_beam_splitter(
206        &mut self,
207        mode1: usize,
208        mode2: usize,
209        reflectivity: f64,
210    ) -> QuantRS2Result<()> {
211        if mode1 >= self.num_modes || mode2 >= self.num_modes {
212            return Err(QuantRS2Error::InvalidInput(
213                "Mode index out of bounds".to_string(),
214            ));
215        }
216
217        if mode1 == mode2 {
218            return Err(QuantRS2Error::InvalidInput(
219                "Cannot apply beam splitter to same mode".to_string(),
220            ));
221        }
222
223        // Beam splitter transformation:
224        // a₁' = √r a₁ + √(1-r) e^{iφ} a₂
225        // a₂' = √(1-r) a₁ - √r e^{iφ} a₂
226        let r = reflectivity;
227        let t = (1.0 - r).sqrt();
228        let r_sqrt = r.sqrt();
229
230        // Apply transformation to individual modes first
231        let mode1_state = self.modes[mode1].fock_state.clone();
232        let mode2_state = self.modes[mode2].fock_state.clone();
233
234        let mut new_mode1_state = Array1::zeros(self.max_photons_per_mode + 1);
235        let mut new_mode2_state = Array1::zeros(self.max_photons_per_mode + 1);
236
237        // This is a simplified implementation - full beam splitter requires
238        // careful handling of multi-photon states
239        for n in 0..=self.max_photons_per_mode {
240            new_mode1_state[n] = r_sqrt * mode1_state[n] + t * mode2_state[n];
241            new_mode2_state[n] = t * mode1_state[n] - r_sqrt * mode2_state[n];
242        }
243
244        self.modes[mode1].fock_state = new_mode1_state;
245        self.modes[mode2].fock_state = new_mode2_state;
246
247        // Update system state
248        self.initialize_from_modes()?;
249
250        Ok(())
251    }
252
253    /// Apply phase shifter to a mode
254    pub fn apply_phase_shifter(&mut self, mode: usize, phase: f64) -> QuantRS2Result<()> {
255        if mode >= self.num_modes {
256            return Err(QuantRS2Error::InvalidInput(
257                "Mode index out of bounds".to_string(),
258            ));
259        }
260
261        // Phase shifter: |n⟩ → e^{inφ} |n⟩
262        for n in 0..=self.max_photons_per_mode {
263            let phase_factor = Complex64::new(0.0, (n as f64) * phase).exp();
264            self.modes[mode].fock_state[n] *= phase_factor;
265        }
266
267        // Update system state
268        self.initialize_from_modes()?;
269
270        Ok(())
271    }
272
273    /// Measure photon number in a mode
274    pub fn measure_photon_number(&mut self, mode: usize) -> QuantRS2Result<usize> {
275        if mode >= self.num_modes {
276            return Err(QuantRS2Error::InvalidInput(
277                "Mode index out of bounds".to_string(),
278            ));
279        }
280
281        // Get probabilities for each photon number
282        let probabilities: Vec<f64> = (0..=self.max_photons_per_mode)
283            .map(|n| self.modes[mode].photon_probability(n))
284            .collect();
285
286        // Sample outcome
287        use scirs2_core::random::prelude::*;
288        let mut rng = thread_rng();
289        let random_value: f64 = rng.gen();
290        let mut cumulative = 0.0;
291
292        for (n, &prob) in probabilities.iter().enumerate() {
293            cumulative += prob;
294            if random_value <= cumulative {
295                // Collapse state to definite photon number
296                let mut new_state = Array1::zeros(self.max_photons_per_mode + 1);
297                new_state[n] = Complex64::new(1.0, 0.0);
298                self.modes[mode].fock_state = new_state;
299
300                self.initialize_from_modes()?;
301                return Ok(n);
302            }
303        }
304
305        // Fallback
306        Ok(self.max_photons_per_mode)
307    }
308
309    /// Perform homodyne measurement
310    pub fn homodyne_measurement(&mut self, mode: usize, phase: f64) -> QuantRS2Result<f64> {
311        if mode >= self.num_modes {
312            return Err(QuantRS2Error::InvalidInput(
313                "Mode index out of bounds".to_string(),
314            ));
315        }
316
317        // Homodyne measurement of X_φ = a e^{-iφ} + a† e^{iφ}
318        // This is a simplified implementation
319        let expectation = self.quadrature_expectation(mode, phase)?;
320
321        // Add measurement noise (simplified)
322        use scirs2_core::random::prelude::*;
323        let mut rng = thread_rng();
324        let noise = rng.gen_range(-0.1..0.1); // Simplified noise model
325
326        Ok(expectation + noise)
327    }
328
329    /// Calculate quadrature expectation value
330    fn quadrature_expectation(&self, mode: usize, phase: f64) -> QuantRS2Result<f64> {
331        // Simplified calculation for demonstration
332        let photon_expectation = self.modes[mode].photon_number_expectation();
333        Ok(photon_expectation.sqrt() * phase.cos())
334    }
335}
336
337/// Photonic quantum gate
338#[derive(Debug, Clone)]
339pub struct PhotonicGate {
340    /// Gate type
341    pub gate_type: PhotonicGateType,
342    /// Target modes
343    pub target_modes: Vec<usize>,
344    /// Gate parameters
345    pub parameters: HashMap<String, f64>,
346}
347
348impl PhotonicGate {
349    /// Create beam splitter gate
350    pub fn beam_splitter(mode1: usize, mode2: usize, reflectivity: f64) -> Self {
351        Self {
352            gate_type: PhotonicGateType::BeamSplitter { reflectivity },
353            target_modes: vec![mode1, mode2],
354            parameters: {
355                let mut params = HashMap::new();
356                params.insert("reflectivity".to_string(), reflectivity);
357                params
358            },
359        }
360    }
361
362    /// Create phase shifter gate
363    pub fn phase_shifter(mode: usize, phase: f64) -> Self {
364        Self {
365            gate_type: PhotonicGateType::PhaseShifter { phase },
366            target_modes: vec![mode],
367            parameters: {
368                let mut params = HashMap::new();
369                params.insert("phase".to_string(), phase);
370                params
371            },
372        }
373    }
374
375    /// Create Mach-Zehnder interferometer
376    pub fn mach_zehnder(mode1: usize, mode2: usize, phase1: f64, phase2: f64) -> Self {
377        Self {
378            gate_type: PhotonicGateType::MachZehnder { phase1, phase2 },
379            target_modes: vec![mode1, mode2],
380            parameters: {
381                let mut params = HashMap::new();
382                params.insert("phase1".to_string(), phase1);
383                params.insert("phase2".to_string(), phase2);
384                params
385            },
386        }
387    }
388
389    /// Apply gate to photonic system
390    pub fn apply(&self, system: &mut PhotonicSystem) -> QuantRS2Result<()> {
391        match self.gate_type {
392            PhotonicGateType::BeamSplitter { reflectivity } => {
393                if self.target_modes.len() != 2 {
394                    return Err(QuantRS2Error::InvalidInput(
395                        "Beam splitter requires exactly 2 modes".to_string(),
396                    ));
397                }
398                system.apply_beam_splitter(self.target_modes[0], self.target_modes[1], reflectivity)
399            }
400            PhotonicGateType::PhaseShifter { phase } => {
401                if self.target_modes.len() != 1 {
402                    return Err(QuantRS2Error::InvalidInput(
403                        "Phase shifter requires exactly 1 mode".to_string(),
404                    ));
405                }
406                system.apply_phase_shifter(self.target_modes[0], phase)
407            }
408            PhotonicGateType::MachZehnder { phase1, phase2 } => {
409                if self.target_modes.len() != 2 {
410                    return Err(QuantRS2Error::InvalidInput(
411                        "Mach-Zehnder requires exactly 2 modes".to_string(),
412                    ));
413                }
414                // Mach-Zehnder = BS + PS + BS + PS
415                system.apply_beam_splitter(self.target_modes[0], self.target_modes[1], 0.5)?;
416                system.apply_phase_shifter(self.target_modes[0], phase1)?;
417                system.apply_phase_shifter(self.target_modes[1], phase2)?;
418                system.apply_beam_splitter(self.target_modes[0], self.target_modes[1], 0.5)
419            }
420            PhotonicGateType::ControlledZ => {
421                // Simplified CZ implementation using interference
422                if self.target_modes.len() != 2 {
423                    return Err(QuantRS2Error::InvalidInput(
424                        "Controlled-Z requires exactly 2 modes".to_string(),
425                    ));
426                }
427                // This is a placeholder - full implementation requires complex interferometry
428                system.apply_phase_shifter(self.target_modes[1], std::f64::consts::PI)
429            }
430            PhotonicGateType::ControlledNot => {
431                // Simplified CNOT implementation
432                if self.target_modes.len() != 2 {
433                    return Err(QuantRS2Error::InvalidInput(
434                        "Controlled-NOT requires exactly 2 modes".to_string(),
435                    ));
436                }
437                // Placeholder implementation
438                system.apply_beam_splitter(self.target_modes[0], self.target_modes[1], 0.5)
439            }
440            _ => Err(QuantRS2Error::InvalidInput(
441                "Gate type not yet implemented".to_string(),
442            )),
443        }
444    }
445}
446
447/// Photonic quantum circuit
448#[derive(Debug, Clone)]
449pub struct PhotonicCircuit {
450    /// Number of modes
451    pub num_modes: usize,
452    /// Sequence of photonic gates
453    pub gates: Vec<PhotonicGate>,
454    /// Maximum photons per mode
455    pub max_photons_per_mode: usize,
456}
457
458impl PhotonicCircuit {
459    /// Create new photonic circuit
460    pub fn new(num_modes: usize, max_photons_per_mode: usize) -> Self {
461        Self {
462            num_modes,
463            gates: Vec::new(),
464            max_photons_per_mode,
465        }
466    }
467
468    /// Add gate to circuit
469    pub fn add_gate(&mut self, gate: PhotonicGate) -> QuantRS2Result<()> {
470        // Validate gate targets
471        for &mode in &gate.target_modes {
472            if mode >= self.num_modes {
473                return Err(QuantRS2Error::InvalidInput(
474                    "Gate target mode out of bounds".to_string(),
475                ));
476            }
477        }
478
479        self.gates.push(gate);
480        Ok(())
481    }
482
483    /// Execute circuit on photonic system
484    pub fn execute(&self, system: &mut PhotonicSystem) -> QuantRS2Result<()> {
485        if system.num_modes != self.num_modes {
486            return Err(QuantRS2Error::InvalidInput(
487                "System and circuit mode count mismatch".to_string(),
488            ));
489        }
490
491        for gate in &self.gates {
492            gate.apply(system)?;
493        }
494
495        Ok(())
496    }
497
498    /// Optimize circuit for linear optics
499    pub fn optimize_linear_optics(&mut self) -> QuantRS2Result<()> {
500        // Combine consecutive phase shifters on same mode
501        let mut optimized_gates = Vec::new();
502        let mut i = 0;
503
504        while i < self.gates.len() {
505            let current_gate = &self.gates[i];
506
507            if let PhotonicGateType::PhaseShifter { phase } = current_gate.gate_type {
508                let mode = current_gate.target_modes[0];
509                let mut total_phase = phase;
510                let mut j = i + 1;
511
512                // Look for consecutive phase shifters on same mode
513                while j < self.gates.len() {
514                    if let PhotonicGateType::PhaseShifter { phase: next_phase } =
515                        self.gates[j].gate_type
516                    {
517                        if self.gates[j].target_modes[0] == mode {
518                            total_phase += next_phase;
519                            j += 1;
520                        } else {
521                            break;
522                        }
523                    } else {
524                        break;
525                    }
526                }
527
528                // Add optimized phase shifter
529                if (total_phase % (2.0 * std::f64::consts::PI)).abs() > 1e-10 {
530                    optimized_gates.push(PhotonicGate::phase_shifter(mode, total_phase));
531                }
532
533                i = j;
534            } else {
535                optimized_gates.push(current_gate.clone());
536                i += 1;
537            }
538        }
539
540        self.gates = optimized_gates;
541        Ok(())
542    }
543
544    /// Convert to matrix representation (for small systems)
545    pub fn to_matrix(&self) -> QuantRS2Result<Array2<Complex64>> {
546        let dim = (self.max_photons_per_mode + 1).pow(self.num_modes as u32);
547        let mut matrix = Array2::eye(dim);
548
549        for gate in &self.gates {
550            let gate_matrix = self.gate_to_matrix(gate)?;
551            matrix = gate_matrix.dot(&matrix);
552        }
553
554        Ok(matrix)
555    }
556
557    /// Convert single gate to matrix (simplified)
558    fn gate_to_matrix(&self, gate: &PhotonicGate) -> QuantRS2Result<Array2<Complex64>> {
559        let dim = (self.max_photons_per_mode + 1).pow(self.num_modes as u32);
560
561        match gate.gate_type {
562            PhotonicGateType::PhaseShifter { phase } => {
563                let mut matrix = Array2::eye(dim);
564                let mode = gate.target_modes[0];
565
566                // Apply phase to each Fock state
567                for i in 0..dim {
568                    let photon_count = self.extract_photon_count(i, mode);
569                    let phase_factor = Complex64::new(0.0, (photon_count as f64) * phase).exp();
570                    matrix[[i, i]] = phase_factor;
571                }
572
573                Ok(matrix)
574            }
575            _ => {
576                // Simplified - return identity for complex gates
577                Ok(Array2::eye(dim))
578            }
579        }
580    }
581
582    /// Extract photon count for specific mode from state index
583    fn extract_photon_count(&self, state_index: usize, mode: usize) -> usize {
584        let mode_dim = self.max_photons_per_mode + 1;
585        (state_index / mode_dim.pow(mode as u32)) % mode_dim
586    }
587}
588
589/// Photonic error correction
590#[derive(Debug, Clone)]
591pub struct PhotonicErrorCorrection {
592    /// Number of physical modes per logical qubit
593    pub physical_modes_per_logical: usize,
594    /// Error correction code type
595    pub code_type: String,
596    /// Syndrome measurement circuits
597    pub syndrome_circuits: Vec<PhotonicCircuit>,
598}
599
600impl PhotonicErrorCorrection {
601    /// Create simple repetition code for photonic qubits
602    pub fn repetition_code(num_repetitions: usize) -> Self {
603        Self {
604            physical_modes_per_logical: num_repetitions,
605            code_type: "Repetition".to_string(),
606            syndrome_circuits: Vec::new(),
607        }
608    }
609
610    /// Encode logical qubit into physical modes
611    pub fn encode_logical_qubit(
612        &self,
613        logical_state: &[Complex64; 2],
614        system: &mut PhotonicSystem,
615    ) -> QuantRS2Result<()> {
616        // Simplified encoding - replicate logical state across physical modes
617        for i in 0..self.physical_modes_per_logical {
618            system.modes[i].fock_state[0] = logical_state[0];
619            system.modes[i].fock_state[1] = logical_state[1];
620        }
621
622        system.initialize_from_modes()?;
623        Ok(())
624    }
625
626    /// Perform error correction
627    pub fn correct_errors(&self, system: &mut PhotonicSystem) -> QuantRS2Result<Vec<usize>> {
628        // Simplified error correction - majority vote
629        let mut corrections = Vec::new();
630
631        // This is a placeholder for actual syndrome measurement and correction
632        for i in 0..self.physical_modes_per_logical {
633            let photon_prob = system.modes[i].photon_probability(1);
634            if photon_prob > 0.5 {
635                corrections.push(i);
636            }
637        }
638
639        Ok(corrections)
640    }
641}
642
643#[cfg(test)]
644mod tests {
645    use super::*;
646
647    #[test]
648    fn test_optical_mode_creation() {
649        let vacuum = OpticalMode::vacuum(0, 5);
650        assert_eq!(vacuum.mode_id, 0);
651        assert_eq!(vacuum.max_photons, 5);
652        assert!((vacuum.fock_state[0] - Complex64::new(1.0, 0.0)).norm() < 1e-10);
653        assert!(vacuum.photon_number_expectation() < 1e-10);
654
655        let single_photon = OpticalMode::single_photon(1, 5);
656        assert!((single_photon.photon_number_expectation() - 1.0).abs() < 1e-10);
657    }
658
659    #[test]
660    fn test_coherent_state() {
661        let alpha = Complex64::new(1.0, 0.0);
662        let coherent = OpticalMode::coherent(0, 10, alpha);
663
664        // For |α⟩ with α = 1, expectation value should be |α|² = 1
665        assert!((coherent.photon_number_expectation() - 1.0).abs() < 0.1);
666    }
667
668    #[test]
669    fn test_photonic_system_initialization() {
670        let mut system = PhotonicSystem::new(3, 2);
671        assert_eq!(system.num_modes, 3);
672        assert_eq!(system.max_photons_per_mode, 2);
673
674        system.initialize_from_modes().unwrap();
675        assert!(system.state.is_some());
676    }
677
678    #[test]
679    fn test_beam_splitter() {
680        let mut system = PhotonicSystem::new(2, 3);
681
682        // Put single photon in mode 0
683        system.modes[0] = OpticalMode::single_photon(0, 3);
684        system.initialize_from_modes().unwrap();
685
686        // Apply 50-50 beam splitter
687        system.apply_beam_splitter(0, 1, 0.5).unwrap();
688
689        // Both modes should have some probability of containing the photon
690        let prob0 = system.modes[0].photon_probability(1);
691        let prob1 = system.modes[1].photon_probability(1);
692        assert!(prob0 > 0.0);
693        assert!(prob1 > 0.0);
694    }
695
696    #[test]
697    fn test_phase_shifter() {
698        let mut system = PhotonicSystem::new(1, 3);
699
700        // Start with single photon
701        system.modes[0] = OpticalMode::single_photon(0, 3);
702        system.initialize_from_modes().unwrap();
703
704        // Apply phase shift
705        let phase = std::f64::consts::PI / 2.0;
706        system.apply_phase_shifter(0, phase).unwrap();
707
708        // Photon number should be unchanged
709        assert!((system.modes[0].photon_number_expectation() - 1.0).abs() < 1e-10);
710
711        // Phase should be applied
712        let expected_phase = Complex64::new(0.0, phase).exp();
713        assert!((system.modes[0].fock_state[1] - expected_phase).norm() < 1e-10);
714    }
715
716    #[test]
717    fn test_photonic_gate_creation() {
718        let bs_gate = PhotonicGate::beam_splitter(0, 1, 0.3);
719        assert_eq!(bs_gate.target_modes, vec![0, 1]);
720        assert!((bs_gate.parameters["reflectivity"] - 0.3).abs() < 1e-10);
721
722        let ps_gate = PhotonicGate::phase_shifter(0, std::f64::consts::PI);
723        assert_eq!(ps_gate.target_modes, vec![0]);
724        assert!((ps_gate.parameters["phase"] - std::f64::consts::PI).abs() < 1e-10);
725    }
726
727    #[test]
728    fn test_photonic_circuit() {
729        let mut circuit = PhotonicCircuit::new(2, 2);
730
731        let bs_gate = PhotonicGate::beam_splitter(0, 1, 0.5);
732        let ps_gate = PhotonicGate::phase_shifter(0, std::f64::consts::PI / 4.0);
733
734        circuit.add_gate(bs_gate).unwrap();
735        circuit.add_gate(ps_gate).unwrap();
736
737        assert_eq!(circuit.gates.len(), 2);
738
739        let mut system = PhotonicSystem::new(2, 2);
740        circuit.execute(&mut system).unwrap();
741    }
742
743    #[test]
744    fn test_mach_zehnder_interferometer() {
745        let mut system = PhotonicSystem::new(2, 2);
746
747        // Single photon input
748        system.modes[0] = OpticalMode::single_photon(0, 2);
749        system.initialize_from_modes().unwrap();
750
751        // Create Mach-Zehnder
752        let mz_gate = PhotonicGate::mach_zehnder(0, 1, 0.0, std::f64::consts::PI);
753        mz_gate.apply(&mut system).unwrap();
754
755        // Check interference occurred
756        let prob0 = system.modes[0].photon_probability(1);
757        let prob1 = system.modes[1].photon_probability(1);
758        assert!((prob0 + prob1 - 1.0).abs() < 1e-10);
759    }
760
761    #[test]
762    fn test_photon_number_measurement() {
763        let mut system = PhotonicSystem::new(1, 3);
764
765        // Single photon state
766        system.modes[0] = OpticalMode::single_photon(0, 3);
767        system.initialize_from_modes().unwrap();
768
769        let measurement_result = system.measure_photon_number(0).unwrap();
770
771        // Should measure 1 photon (deterministic for pure state)
772        assert_eq!(measurement_result, 1);
773
774        // State should collapse to |1⟩
775        assert!((system.modes[0].photon_probability(1) - 1.0).abs() < 1e-10);
776    }
777
778    #[test]
779    fn test_homodyne_measurement() {
780        let mut system = PhotonicSystem::new(1, 3);
781
782        // Coherent state
783        let alpha = Complex64::new(2.0, 0.0);
784        system.modes[0] = OpticalMode::coherent(0, 3, alpha);
785        system.initialize_from_modes().unwrap();
786
787        let measurement_result = system.homodyne_measurement(0, 0.0).unwrap();
788
789        // Should get real measurement result
790        assert!(measurement_result.is_finite());
791    }
792
793    #[test]
794    fn test_circuit_optimization() {
795        let mut circuit = PhotonicCircuit::new(2, 2);
796
797        // Add consecutive phase shifters
798        circuit
799            .add_gate(PhotonicGate::phase_shifter(0, std::f64::consts::PI / 4.0))
800            .unwrap();
801        circuit
802            .add_gate(PhotonicGate::phase_shifter(0, std::f64::consts::PI / 4.0))
803            .unwrap();
804        circuit
805            .add_gate(PhotonicGate::phase_shifter(0, std::f64::consts::PI / 2.0))
806            .unwrap();
807
808        assert_eq!(circuit.gates.len(), 3);
809
810        circuit.optimize_linear_optics().unwrap();
811
812        // Should be optimized to single phase shifter
813        assert_eq!(circuit.gates.len(), 1);
814        if let PhotonicGateType::PhaseShifter { phase } = circuit.gates[0].gate_type {
815            assert!((phase - std::f64::consts::PI).abs() < 1e-10);
816        }
817    }
818
819    #[test]
820    fn test_photonic_error_correction() {
821        let error_correction = PhotonicErrorCorrection::repetition_code(3);
822        assert_eq!(error_correction.physical_modes_per_logical, 3);
823        assert_eq!(error_correction.code_type, "Repetition");
824
825        let mut system = PhotonicSystem::new(3, 2);
826        let logical_state = [Complex64::new(1.0, 0.0), Complex64::new(0.0, 0.0)]; // |0⟩
827
828        error_correction
829            .encode_logical_qubit(&logical_state, &mut system)
830            .unwrap();
831
832        let corrections = error_correction.correct_errors(&mut system).unwrap();
833        assert!(corrections.len() <= 3);
834    }
835}