quantrs2_device/photonic/
noise_models.rs

1//! Photonic Noise Models
2//!
3//! This module implements noise models specific to photonic quantum computing systems,
4//! including loss, thermal noise, and detector inefficiencies.
5
6use serde::{Deserialize, Serialize};
7use std::collections::HashMap;
8use std::f64::consts::PI;
9use thiserror::Error;
10
11use super::continuous_variable::{CVError, CVResult, Complex, GaussianState};
12use super::{PhotonicMode, PhotonicSystemType};
13use crate::DeviceResult;
14
15/// Photonic noise model errors
16#[derive(Error, Debug)]
17pub enum PhotonicNoiseError {
18    #[error("Invalid noise parameter: {0}")]
19    InvalidParameter(String),
20    #[error("Noise model not supported: {0}")]
21    UnsupportedModel(String),
22    #[error("Noise application failed: {0}")]
23    ApplicationFailed(String),
24}
25
26/// Types of photonic noise
27#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
28pub enum PhotonicNoiseType {
29    /// Photon loss
30    Loss { rate: f64 },
31    /// Thermal noise
32    Thermal { temperature: f64, frequency: f64 },
33    /// Detector inefficiency
34    DetectorInefficiency { efficiency: f64 },
35    /// Phase noise
36    PhaseNoise { variance: f64 },
37    /// Amplitude noise
38    AmplitudeNoise { variance: f64 },
39    /// Cross-talk between modes
40    Crosstalk { coupling_strength: f64 },
41    /// Nonlinear noise
42    Nonlinear { coefficient: f64 },
43}
44
45/// Photonic noise model
46#[derive(Debug, Clone, Serialize, Deserialize)]
47pub struct PhotonicNoiseModel {
48    /// Types of noise included
49    pub noise_types: Vec<PhotonicNoiseType>,
50    /// Mode-specific noise parameters
51    pub mode_specific: HashMap<usize, Vec<PhotonicNoiseType>>,
52    /// Global noise parameters
53    pub global_parameters: NoiseParameters,
54}
55
56/// Global noise parameters
57#[derive(Debug, Clone, Serialize, Deserialize)]
58pub struct NoiseParameters {
59    /// Overall noise strength
60    pub noise_strength: f64,
61    /// Correlation time
62    pub correlation_time: f64,
63    /// Temperature of environment
64    pub environment_temperature: f64,
65    /// System bandwidth
66    pub bandwidth: f64,
67}
68
69impl Default for NoiseParameters {
70    fn default() -> Self {
71        Self {
72            noise_strength: 0.01,
73            correlation_time: 1e-6,        // 1 microsecond
74            environment_temperature: 0.01, // 10 mK in energy units
75            bandwidth: 1e9,                // 1 GHz
76        }
77    }
78}
79
80/// Photonic noise simulator
81pub struct PhotonicNoiseSimulator {
82    /// Active noise models
83    pub noise_models: Vec<PhotonicNoiseModel>,
84    /// Noise realization cache
85    pub noise_cache: HashMap<String, Vec<f64>>,
86    /// Random number generator state
87    rng_state: u64,
88}
89
90impl PhotonicNoiseSimulator {
91    pub fn new() -> Self {
92        Self {
93            noise_models: Vec::new(),
94            noise_cache: HashMap::new(),
95            rng_state: 42, // Simple seed
96        }
97    }
98
99    /// Apply noise to a Gaussian state
100    pub fn apply_noise(
101        &mut self,
102        state: &mut GaussianState,
103        noise_model: &PhotonicNoiseModel,
104    ) -> Result<(), PhotonicNoiseError> {
105        for noise_type in &noise_model.noise_types {
106            self.apply_noise_type(state, noise_type)?;
107        }
108
109        // Apply mode-specific noise
110        for (&mode, noise_types) in &noise_model.mode_specific {
111            if mode < state.num_modes {
112                for noise_type in noise_types {
113                    self.apply_mode_specific_noise(state, mode, noise_type)?;
114                }
115            }
116        }
117
118        Ok(())
119    }
120
121    /// Apply a specific type of noise
122    fn apply_noise_type(
123        &mut self,
124        state: &mut GaussianState,
125        noise_type: &PhotonicNoiseType,
126    ) -> Result<(), PhotonicNoiseError> {
127        match noise_type {
128            PhotonicNoiseType::Loss { rate } => {
129                self.apply_loss_noise(state, *rate)?;
130            }
131            PhotonicNoiseType::Thermal {
132                temperature,
133                frequency,
134            } => {
135                self.apply_thermal_noise(state, *temperature, *frequency)?;
136            }
137            PhotonicNoiseType::PhaseNoise { variance } => {
138                self.apply_phase_noise(state, *variance)?;
139            }
140            PhotonicNoiseType::AmplitudeNoise { variance } => {
141                self.apply_amplitude_noise(state, *variance)?;
142            }
143            PhotonicNoiseType::DetectorInefficiency { efficiency } => {
144                self.apply_detector_noise(state, *efficiency)?;
145            }
146            PhotonicNoiseType::Crosstalk { coupling_strength } => {
147                self.apply_crosstalk_noise(state, *coupling_strength)?;
148            }
149            PhotonicNoiseType::Nonlinear { coefficient } => {
150                self.apply_nonlinear_noise(state, *coefficient)?;
151            }
152        }
153        Ok(())
154    }
155
156    /// Apply photon loss noise
157    fn apply_loss_noise(
158        &mut self,
159        state: &mut GaussianState,
160        loss_rate: f64,
161    ) -> Result<(), PhotonicNoiseError> {
162        if !(0.0..=1.0).contains(&loss_rate) {
163            return Err(PhotonicNoiseError::InvalidParameter(format!(
164                "Loss rate must be between 0 and 1, got {loss_rate}"
165            )));
166        }
167
168        let transmission = 1.0 - loss_rate;
169
170        // Apply loss by scaling the covariance matrix
171        for mode in 0..state.num_modes {
172            let x_idx = 2 * mode;
173            let p_idx = 2 * mode + 1;
174
175            // Scale mean values
176            state.mean[x_idx] *= transmission.sqrt();
177            state.mean[p_idx] *= transmission.sqrt();
178
179            // Scale covariance matrix elements
180            state.covariance[x_idx][x_idx] =
181                transmission * state.covariance[x_idx][x_idx] + (1.0 - transmission) * 0.5;
182            state.covariance[p_idx][p_idx] =
183                transmission * state.covariance[p_idx][p_idx] + (1.0 - transmission) * 0.5;
184            state.covariance[x_idx][p_idx] *= transmission;
185            state.covariance[p_idx][x_idx] *= transmission;
186        }
187
188        Ok(())
189    }
190
191    /// Apply thermal noise
192    fn apply_thermal_noise(
193        &mut self,
194        state: &mut GaussianState,
195        temperature: f64,
196        frequency: f64,
197    ) -> Result<(), PhotonicNoiseError> {
198        if temperature < 0.0 {
199            return Err(PhotonicNoiseError::InvalidParameter(
200                "Temperature must be non-negative".to_string(),
201            ));
202        }
203
204        // Calculate thermal photon number: n_th = 1/(exp(hf/kT) - 1)
205        // Simplified: n_th ≈ kT/hf for kT << hf
206        let thermal_photons = temperature / frequency;
207
208        // Add thermal noise to all modes
209        for mode in 0..state.num_modes {
210            let x_idx = 2 * mode;
211            let p_idx = 2 * mode + 1;
212
213            // Add thermal variance
214            state.covariance[x_idx][x_idx] += thermal_photons;
215            state.covariance[p_idx][p_idx] += thermal_photons;
216        }
217
218        Ok(())
219    }
220
221    /// Apply phase noise
222    fn apply_phase_noise(
223        &mut self,
224        state: &mut GaussianState,
225        variance: f64,
226    ) -> Result<(), PhotonicNoiseError> {
227        if variance < 0.0 {
228            return Err(PhotonicNoiseError::InvalidParameter(
229                "Phase noise variance must be non-negative".to_string(),
230            ));
231        }
232
233        // Apply random phase rotation to each mode
234        for mode in 0..state.num_modes {
235            let phase_noise = self.generate_gaussian_noise(0.0, variance);
236            if let Err(e) = state.phase_rotation(phase_noise, mode) {
237                return Err(PhotonicNoiseError::ApplicationFailed(format!(
238                    "Failed to apply phase noise: {e:?}"
239                )));
240            }
241        }
242
243        Ok(())
244    }
245
246    /// Apply amplitude noise
247    fn apply_amplitude_noise(
248        &mut self,
249        state: &mut GaussianState,
250        variance: f64,
251    ) -> Result<(), PhotonicNoiseError> {
252        if variance < 0.0 {
253            return Err(PhotonicNoiseError::InvalidParameter(
254                "Amplitude noise variance must be non-negative".to_string(),
255            ));
256        }
257
258        // Add amplitude fluctuations to quadratures
259        for mode in 0..state.num_modes {
260            let x_idx = 2 * mode;
261            let p_idx = 2 * mode + 1;
262
263            let x_noise = self.generate_gaussian_noise(0.0, variance);
264            let p_noise = self.generate_gaussian_noise(0.0, variance);
265
266            state.mean[x_idx] += x_noise;
267            state.mean[p_idx] += p_noise;
268        }
269
270        Ok(())
271    }
272
273    /// Apply detector inefficiency noise
274    fn apply_detector_noise(
275        &mut self,
276        state: &mut GaussianState,
277        efficiency: f64,
278    ) -> Result<(), PhotonicNoiseError> {
279        if !(0.0..=1.0).contains(&efficiency) {
280            return Err(PhotonicNoiseError::InvalidParameter(format!(
281                "Detector efficiency must be between 0 and 1, got {efficiency}"
282            )));
283        }
284
285        // Detector inefficiency acts like loss but only affects measurements
286        // For simulation purposes, we model it as additional loss
287        self.apply_loss_noise(state, 1.0 - efficiency)
288    }
289
290    /// Apply crosstalk noise between modes
291    fn apply_crosstalk_noise(
292        &mut self,
293        state: &mut GaussianState,
294        coupling_strength: f64,
295    ) -> Result<(), PhotonicNoiseError> {
296        if state.num_modes < 2 {
297            return Ok(()); // No crosstalk for single mode
298        }
299
300        // Apply weak coupling between adjacent modes
301        for mode in 0..(state.num_modes - 1) {
302            let coupling_angle = coupling_strength * PI / 4.0;
303            if let Err(e) = state.beamsplitter(coupling_angle, 0.0, mode, mode + 1) {
304                return Err(PhotonicNoiseError::ApplicationFailed(format!(
305                    "Failed to apply crosstalk: {e:?}"
306                )));
307            }
308        }
309
310        Ok(())
311    }
312
313    /// Apply nonlinear noise
314    fn apply_nonlinear_noise(
315        &mut self,
316        state: &mut GaussianState,
317        coefficient: f64,
318    ) -> Result<(), PhotonicNoiseError> {
319        // Nonlinear noise is typically small and breaks Gaussianity
320        // For Gaussian states, we approximate with additional phase noise
321        let phase_variance = coefficient.abs() * 0.1;
322        self.apply_phase_noise(state, phase_variance)
323    }
324
325    /// Apply mode-specific noise
326    fn apply_mode_specific_noise(
327        &mut self,
328        state: &mut GaussianState,
329        mode: usize,
330        noise_type: &PhotonicNoiseType,
331    ) -> Result<(), PhotonicNoiseError> {
332        match noise_type {
333            PhotonicNoiseType::PhaseNoise { variance } => {
334                let phase_noise = self.generate_gaussian_noise(0.0, *variance);
335                if let Err(e) = state.phase_rotation(phase_noise, mode) {
336                    return Err(PhotonicNoiseError::ApplicationFailed(format!(
337                        "Mode-specific phase noise failed: {e:?}"
338                    )));
339                }
340            }
341            PhotonicNoiseType::AmplitudeNoise { variance } => {
342                let x_idx = 2 * mode;
343                let p_idx = 2 * mode + 1;
344
345                let x_noise = self.generate_gaussian_noise(0.0, *variance);
346                let p_noise = self.generate_gaussian_noise(0.0, *variance);
347
348                state.mean[x_idx] += x_noise;
349                state.mean[p_idx] += p_noise;
350            }
351            _ => {
352                // For other noise types, apply globally
353                self.apply_noise_type(state, noise_type)?;
354            }
355        }
356        Ok(())
357    }
358
359    /// Generate Gaussian noise (simplified implementation)
360    fn generate_gaussian_noise(&mut self, mean: f64, variance: f64) -> f64 {
361        // Simple Box-Muller transform
362        self.rng_state = self
363            .rng_state
364            .wrapping_mul(1_664_525)
365            .wrapping_add(1_013_904_223);
366        let u1 = (self.rng_state as f64) / (u64::MAX as f64);
367
368        self.rng_state = self
369            .rng_state
370            .wrapping_mul(1_664_525)
371            .wrapping_add(1_013_904_223);
372        let u2 = (self.rng_state as f64) / (u64::MAX as f64);
373
374        let z = (-2.0 * u1.ln()).sqrt() * (2.0 * PI * u2).cos();
375        variance.sqrt().mul_add(z, mean)
376    }
377
378    /// Create a realistic noise model for photonic systems
379    pub fn create_realistic_noise_model(
380        loss_rate: f64,
381        thermal_temperature: f64,
382        detector_efficiency: f64,
383    ) -> PhotonicNoiseModel {
384        let noise_types = vec![
385            PhotonicNoiseType::Loss { rate: loss_rate },
386            PhotonicNoiseType::Thermal {
387                temperature: thermal_temperature,
388                frequency: 1e14, // Optical frequency
389            },
390            PhotonicNoiseType::DetectorInefficiency {
391                efficiency: detector_efficiency,
392            },
393            PhotonicNoiseType::PhaseNoise { variance: 0.001 },
394            PhotonicNoiseType::AmplitudeNoise { variance: 0.0005 },
395        ];
396
397        PhotonicNoiseModel {
398            noise_types,
399            mode_specific: HashMap::new(),
400            global_parameters: NoiseParameters::default(),
401        }
402    }
403
404    /// Estimate noise impact on fidelity
405    pub fn estimate_noise_impact(
406        &self,
407        initial_fidelity: f64,
408        noise_model: &PhotonicNoiseModel,
409    ) -> f64 {
410        let mut fidelity = initial_fidelity;
411
412        for noise_type in &noise_model.noise_types {
413            match noise_type {
414                PhotonicNoiseType::Loss { rate } => {
415                    fidelity *= 1.0 - rate * 0.5; // Approximate impact
416                }
417                PhotonicNoiseType::Thermal { temperature, .. } => {
418                    fidelity *= 1.0 - temperature * 0.1;
419                }
420                PhotonicNoiseType::PhaseNoise { variance } => {
421                    fidelity *= 1.0 - variance * 2.0;
422                }
423                PhotonicNoiseType::DetectorInefficiency { efficiency } => {
424                    fidelity *= efficiency;
425                }
426                _ => {
427                    fidelity *= 0.99; // Small general impact
428                }
429            }
430        }
431
432        fidelity.clamp(0.0, 1.0)
433    }
434}
435
436impl Default for PhotonicNoiseSimulator {
437    fn default() -> Self {
438        Self::new()
439    }
440}
441
442#[cfg(test)]
443mod tests {
444    use super::*;
445    use crate::photonic::continuous_variable::GaussianState;
446
447    #[test]
448    fn test_noise_simulator_creation() {
449        let simulator = PhotonicNoiseSimulator::new();
450        assert_eq!(simulator.noise_models.len(), 0);
451    }
452
453    #[test]
454    fn test_loss_noise() {
455        let mut simulator = PhotonicNoiseSimulator::new();
456        let mut state = GaussianState::coherent(Complex::new(2.0, 0.0), 0, 1)
457            .expect("Coherent state creation should succeed");
458
459        let original_mean = state.mean[0];
460        simulator
461            .apply_loss_noise(&mut state, 0.1)
462            .expect("Loss noise application should succeed with valid rate");
463
464        // Mean should be reduced due to loss
465        assert!(state.mean[0] < original_mean);
466    }
467
468    #[test]
469    fn test_thermal_noise() {
470        let mut simulator = PhotonicNoiseSimulator::new();
471        let mut state = GaussianState::vacuum(1);
472
473        let original_variance = state.covariance[0][0];
474        simulator
475            .apply_thermal_noise(&mut state, 0.01, 1e14)
476            .expect("Thermal noise application should succeed with valid parameters");
477
478        // Variance should increase due to thermal noise
479        assert!(state.covariance[0][0] > original_variance);
480    }
481
482    #[test]
483    fn test_realistic_noise_model() {
484        let model = PhotonicNoiseSimulator::create_realistic_noise_model(0.05, 0.01, 0.9);
485        assert_eq!(model.noise_types.len(), 5);
486    }
487
488    #[test]
489    fn test_noise_impact_estimation() {
490        let simulator = PhotonicNoiseSimulator::new();
491        let model = PhotonicNoiseSimulator::create_realistic_noise_model(0.1, 0.01, 0.95);
492
493        let initial_fidelity = 0.99;
494        let final_fidelity = simulator.estimate_noise_impact(initial_fidelity, &model);
495
496        assert!(final_fidelity < initial_fidelity);
497        assert!(final_fidelity > 0.0);
498    }
499}