quantrs2_device/continuous_variable/
measurements.rs

1//! Continuous variable quantum measurements
2//!
3//! This module implements various measurement schemes for CV quantum systems,
4//! including homodyne, heterodyne, photon number, and parity measurements.
5
6use super::{CVDeviceConfig, Complex, GaussianState};
7use crate::{DeviceError, DeviceResult};
8use scirs2_core::random::prelude::*;
9use scirs2_core::random::{Distribution, RandNormal, Poisson};
10use serde::{Deserialize, Serialize};
11use std::f64::consts::PI;
12
13// Alias for backward compatibility
14type Normal<T> = RandNormal<T>;
15
16/// Types of CV measurements
17#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
18pub enum CVMeasurementScheme {
19    /// Homodyne detection at specific phase
20    Homodyne { phase: f64 },
21    /// Heterodyne detection (simultaneous x and p)
22    Heterodyne,
23    /// Photon number measurement
24    PhotonNumber,
25    /// Parity measurement (even/odd photon number)
26    Parity,
27    /// Bell measurement for entangled modes
28    Bell { basis: BellBasis },
29    /// Fock state projection
30    FockProjection { n: usize },
31    /// Coherent state projection
32    CoherentProjection { alpha: Complex },
33}
34
35/// Bell measurement bases for CV systems
36#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
37pub enum BellBasis {
38    /// X-X correlation measurement
39    XBasis,
40    /// P-P correlation measurement
41    PBasis,
42    /// Mixed X-P correlation
43    MixedBasis { phase: f64 },
44}
45
46/// CV measurement result with statistics
47#[derive(Debug, Clone, Serialize, Deserialize)]
48pub struct CVMeasurementResult {
49    /// The measurement outcome
50    pub outcome: CVMeasurementOutcome,
51    /// Measurement fidelity/confidence
52    pub fidelity: f64,
53    /// Standard deviation of the measurement
54    pub standard_deviation: f64,
55    /// Number of samples used
56    pub sample_count: usize,
57    /// Timestamp
58    pub timestamp: f64,
59}
60
61/// Different types of measurement outcomes
62#[derive(Debug, Clone, Serialize, Deserialize)]
63pub enum CVMeasurementOutcome {
64    /// Real-valued outcome (homodyne)
65    Real(f64),
66    /// Complex-valued outcome (heterodyne)
67    Complex(Complex),
68    /// Integer outcome (photon number)
69    Integer(i32),
70    /// Boolean outcome (parity)
71    Boolean(bool),
72    /// Bell correlation outcome
73    BellCorrelation { correlation: f64, phase: f64 },
74}
75
76/// Configuration for CV measurements
77#[derive(Debug, Clone, Serialize, Deserialize)]
78pub struct CVMeasurementConfig {
79    /// Number of measurement samples
80    pub num_samples: usize,
81    /// Integration time (seconds)
82    pub integration_time: f64,
83    /// Local oscillator power (mW)
84    pub lo_power_mw: f64,
85    /// Detection bandwidth (Hz)
86    pub bandwidth_hz: f64,
87    /// Phase lock stability (rad RMS)
88    pub phase_stability: f64,
89    /// Enable post-processing
90    pub enable_post_processing: bool,
91    /// Calibration data
92    pub calibration: MeasurementCalibration,
93}
94
95/// Calibration data for CV measurements
96#[derive(Debug, Clone, Serialize, Deserialize)]
97pub struct MeasurementCalibration {
98    /// Detection efficiency per mode
99    pub efficiency: Vec<f64>,
100    /// Electronic noise level (dB)
101    pub electronic_noise_db: f64,
102    /// Dark count rate (Hz)
103    pub dark_count_rate: f64,
104    /// Gain calibration factors
105    pub gain_factors: Vec<f64>,
106    /// Phase calibration offsets
107    pub phase_offsets: Vec<f64>,
108}
109
110impl Default for CVMeasurementConfig {
111    fn default() -> Self {
112        Self {
113            num_samples: 10000,
114            integration_time: 0.001, // 1 ms
115            lo_power_mw: 10.0,
116            bandwidth_hz: 10e6,
117            phase_stability: 0.01,
118            enable_post_processing: true,
119            calibration: MeasurementCalibration::default(),
120        }
121    }
122}
123
124impl Default for MeasurementCalibration {
125    fn default() -> Self {
126        Self {
127            efficiency: vec![0.95; 10], // Default for up to 10 modes
128            electronic_noise_db: -90.0,
129            dark_count_rate: 100.0,
130            gain_factors: vec![1.0; 10],
131            phase_offsets: vec![0.0; 10],
132        }
133    }
134}
135
136/// CV measurement engine
137pub struct CVMeasurementEngine {
138    /// Measurement configuration
139    config: CVMeasurementConfig,
140    /// Current measurement results
141    measurement_history: Vec<CVMeasurementResult>,
142    /// Calibration state
143    is_calibrated: bool,
144}
145
146impl CVMeasurementEngine {
147    /// Create a new measurement engine
148    pub fn new(config: CVMeasurementConfig) -> Self {
149        Self {
150            config,
151            measurement_history: Vec::new(),
152            is_calibrated: false,
153        }
154    }
155
156    /// Calibrate the measurement system
157    pub async fn calibrate(&mut self) -> DeviceResult<()> {
158        println!("Calibrating CV measurement system...");
159
160        // Simulate calibration process
161        tokio::time::sleep(std::time::Duration::from_millis(500)).await;
162
163        // Update calibration factors
164        for i in 0..self.config.calibration.efficiency.len() {
165            self.config.calibration.efficiency[i] = 0.95 + 0.03 * thread_rng().gen::<f64>();
166            self.config.calibration.gain_factors[i] = 1.0 + 0.1 * (thread_rng().gen::<f64>() - 0.5);
167            self.config.calibration.phase_offsets[i] = 0.1 * (thread_rng().gen::<f64>() - 0.5);
168        }
169
170        self.is_calibrated = true;
171        println!("Calibration complete");
172        Ok(())
173    }
174
175    /// Perform homodyne measurement
176    pub async fn homodyne_measurement(
177        &mut self,
178        state: &mut GaussianState,
179        mode: usize,
180        phase: f64,
181    ) -> DeviceResult<CVMeasurementResult> {
182        if !self.is_calibrated {
183            return Err(DeviceError::DeviceNotInitialized(
184                "Measurement system not calibrated".to_string(),
185            ));
186        }
187
188        if mode >= state.num_modes {
189            return Err(DeviceError::InvalidInput(format!(
190                "Mode {} exceeds available modes",
191                mode
192            )));
193        }
194
195        // Apply phase offset calibration
196        let calibrated_phase = phase
197            + self
198                .config
199                .calibration
200                .phase_offsets
201                .get(mode)
202                .unwrap_or(&0.0);
203
204        // Get the theoretical mean and variance
205        let cos_phi = calibrated_phase.cos();
206        let sin_phi = calibrated_phase.sin();
207
208        let mean_x = state.mean_vector[2 * mode];
209        let mean_p = state.mean_vector[2 * mode + 1];
210        let theoretical_mean = cos_phi * mean_x + sin_phi * mean_p;
211
212        let var_x = state.covariancematrix[2 * mode][2 * mode];
213        let var_p = state.covariancematrix[2 * mode + 1][2 * mode + 1];
214        let cov_xp = state.covariancematrix[2 * mode][2 * mode + 1];
215
216        let theoretical_variance =
217            cos_phi.powi(2) * var_x + sin_phi.powi(2) * var_p + 2.0 * cos_phi * sin_phi * cov_xp;
218
219        // Add noise effects
220        let efficiency = self
221            .config
222            .calibration
223            .efficiency
224            .get(mode)
225            .unwrap_or(&0.95);
226        let gain = self
227            .config
228            .calibration
229            .gain_factors
230            .get(mode)
231            .unwrap_or(&1.0);
232
233        let noise_variance = self.calculate_detection_noise(mode);
234        let total_variance = theoretical_variance / efficiency + noise_variance;
235
236        // Perform multiple samples
237        let mut samples = Vec::new();
238        let distribution = Normal::new(theoretical_mean, total_variance.sqrt())
239            .map_err(|e| DeviceError::InvalidInput(format!("Distribution error: {}", e)))?;
240
241        let mut rng = StdRng::seed_from_u64(thread_rng().gen::<u64>());
242        for _ in 0..self.config.num_samples {
243            let sample = distribution.sample(&mut rng) * gain;
244            samples.push(sample);
245        }
246
247        // Calculate statistics
248        let mean_outcome = samples.iter().sum::<f64>() / samples.len() as f64;
249        let variance = samples
250            .iter()
251            .map(|x| (x - mean_outcome).powi(2))
252            .sum::<f64>()
253            / samples.len() as f64;
254        let std_dev = variance.sqrt();
255
256        // Estimate fidelity
257        let fidelity =
258            self.estimate_measurement_fidelity(&samples, theoretical_mean, total_variance);
259
260        let result = CVMeasurementResult {
261            outcome: CVMeasurementOutcome::Real(mean_outcome),
262            fidelity,
263            standard_deviation: std_dev,
264            sample_count: samples.len(),
265            timestamp: std::time::SystemTime::now()
266                .duration_since(std::time::UNIX_EPOCH)
267                .unwrap()
268                .as_secs_f64(),
269        };
270
271        // Condition the state on the measurement
272        state.condition_on_homodyne_measurement(mode, calibrated_phase, mean_outcome)?;
273
274        self.measurement_history.push(result.clone());
275        Ok(result)
276    }
277
278    /// Perform heterodyne measurement
279    pub async fn heterodyne_measurement(
280        &mut self,
281        state: &mut GaussianState,
282        mode: usize,
283    ) -> DeviceResult<CVMeasurementResult> {
284        if !self.is_calibrated {
285            return Err(DeviceError::DeviceNotInitialized(
286                "Measurement system not calibrated".to_string(),
287            ));
288        }
289
290        if mode >= state.num_modes {
291            return Err(DeviceError::InvalidInput(format!(
292                "Mode {} exceeds available modes",
293                mode
294            )));
295        }
296
297        let efficiency = self
298            .config
299            .calibration
300            .efficiency
301            .get(mode)
302            .unwrap_or(&0.95);
303        let gain = self
304            .config
305            .calibration
306            .gain_factors
307            .get(mode)
308            .unwrap_or(&1.0);
309
310        // Get state parameters
311        let mean_x = state.mean_vector[2 * mode];
312        let mean_p = state.mean_vector[2 * mode + 1];
313        let var_x = state.covariancematrix[2 * mode][2 * mode];
314        let var_p = state.covariancematrix[2 * mode + 1][2 * mode + 1];
315
316        // Add noise
317        let noise_variance = self.calculate_detection_noise(mode);
318
319        // Sample both quadratures
320        let mut x_samples = Vec::new();
321        let mut p_samples = Vec::new();
322
323        let x_distribution =
324            Normal::new(mean_x, (var_x / efficiency + noise_variance / 2.0).sqrt())
325                .map_err(|e| DeviceError::InvalidInput(format!("Distribution error: {}", e)))?;
326        let p_distribution =
327            Normal::new(mean_p, (var_p / efficiency + noise_variance / 2.0).sqrt())
328                .map_err(|e| DeviceError::InvalidInput(format!("Distribution error: {}", e)))?;
329
330        let mut rng = StdRng::seed_from_u64(thread_rng().gen::<u64>());
331        for _ in 0..self.config.num_samples {
332            x_samples.push(x_distribution.sample(&mut rng) * gain);
333            p_samples.push(p_distribution.sample(&mut rng) * gain);
334        }
335
336        // Calculate complex outcome
337        let mean_x_outcome = x_samples.iter().sum::<f64>() / x_samples.len() as f64;
338        let mean_p_outcome = p_samples.iter().sum::<f64>() / p_samples.len() as f64;
339
340        let complex_outcome = Complex::new(
341            (mean_x_outcome + mean_p_outcome * Complex::i().real) / (2.0_f64).sqrt(),
342            (mean_p_outcome - mean_x_outcome * Complex::i().imag) / (2.0_f64).sqrt(),
343        );
344
345        // Calculate standard deviation
346        let x_var = x_samples
347            .iter()
348            .map(|x| (x - mean_x_outcome).powi(2))
349            .sum::<f64>()
350            / x_samples.len() as f64;
351        let p_var = p_samples
352            .iter()
353            .map(|p| (p - mean_p_outcome).powi(2))
354            .sum::<f64>()
355            / p_samples.len() as f64;
356        let std_dev = (x_var + p_var).sqrt();
357
358        // Estimate fidelity
359        let theoretical_variance = (var_x + var_p) / efficiency + noise_variance;
360        let fidelity = 1.0 / (1.0 + theoretical_variance);
361
362        let result = CVMeasurementResult {
363            outcome: CVMeasurementOutcome::Complex(complex_outcome),
364            fidelity,
365            standard_deviation: std_dev,
366            sample_count: self.config.num_samples,
367            timestamp: std::time::SystemTime::now()
368                .duration_since(std::time::UNIX_EPOCH)
369                .unwrap()
370                .as_secs_f64(),
371        };
372
373        // Condition state (heterodyne destroys the mode)
374        state.condition_on_heterodyne_measurement(mode, complex_outcome)?;
375
376        self.measurement_history.push(result.clone());
377        Ok(result)
378    }
379
380    /// Perform photon number measurement (simplified for Gaussian states)
381    pub async fn photon_number_measurement(
382        &mut self,
383        state: &GaussianState,
384        mode: usize,
385    ) -> DeviceResult<CVMeasurementResult> {
386        if !self.is_calibrated {
387            return Err(DeviceError::DeviceNotInitialized(
388                "Measurement system not calibrated".to_string(),
389            ));
390        }
391
392        if mode >= state.num_modes {
393            return Err(DeviceError::InvalidInput(format!(
394                "Mode {} exceeds available modes",
395                mode
396            )));
397        }
398
399        // For Gaussian states, estimate photon number from second moments
400        let mean_x = state.mean_vector[2 * mode];
401        let mean_p = state.mean_vector[2 * mode + 1];
402        let var_x = state.covariancematrix[2 * mode][2 * mode];
403        let var_p = state.covariancematrix[2 * mode + 1][2 * mode + 1];
404
405        // Average photon number for Gaussian state
406        let mean_n = 0.5 * ((mean_x.powi(2) + mean_p.powi(2)) / 2.0 + (var_x + var_p) - 1.0);
407
408        // For thermal/squeezed states, photon number follows geometric/negative binomial distribution
409        // Simplified: just add Poissonian noise around the mean
410        let efficiency = self
411            .config
412            .calibration
413            .efficiency
414            .get(mode)
415            .unwrap_or(&0.95);
416        let dark_counts = self.config.calibration.dark_count_rate * self.config.integration_time;
417
418        let detected_n = mean_n * efficiency + dark_counts;
419
420        // Sample from Poisson-like distribution
421        let mut samples = Vec::new();
422        let mut rng = StdRng::seed_from_u64(thread_rng().gen::<u64>());
423        for _ in 0..self.config.num_samples {
424            let sample = if detected_n > 0.0 {
425                let poisson = Poisson::new(detected_n)
426                    .map_err(|e| DeviceError::InvalidInput(format!("Poisson error: {}", e)))?;
427                poisson.sample(&mut rng) as f64
428            } else {
429                0.0
430            };
431            samples.push(sample);
432        }
433
434        let mean_outcome = samples.iter().sum::<f64>() / samples.len() as f64;
435        let variance = samples
436            .iter()
437            .map(|x| (x - mean_outcome).powi(2))
438            .sum::<f64>()
439            / samples.len() as f64;
440
441        let rounded_outcome = mean_outcome.round() as i32;
442        let fidelity = 1.0 / (1.0 + variance / (mean_outcome + 1.0));
443
444        let result = CVMeasurementResult {
445            outcome: CVMeasurementOutcome::Integer(rounded_outcome),
446            fidelity,
447            standard_deviation: variance.sqrt(),
448            sample_count: samples.len(),
449            timestamp: std::time::SystemTime::now()
450                .duration_since(std::time::UNIX_EPOCH)
451                .unwrap()
452                .as_secs_f64(),
453        };
454
455        self.measurement_history.push(result.clone());
456        Ok(result)
457    }
458
459    /// Perform parity measurement
460    pub async fn parity_measurement(
461        &mut self,
462        state: &GaussianState,
463        mode: usize,
464    ) -> DeviceResult<CVMeasurementResult> {
465        // Parity measurement for Gaussian states
466        let photon_result = self.photon_number_measurement(state, mode).await?;
467
468        let parity = match photon_result.outcome {
469            CVMeasurementOutcome::Integer(n) => n % 2 == 0,
470            _ => {
471                return Err(DeviceError::InvalidInput(
472                    "Invalid photon number result".to_string(),
473                ))
474            }
475        };
476
477        let result = CVMeasurementResult {
478            outcome: CVMeasurementOutcome::Boolean(parity),
479            fidelity: photon_result.fidelity,
480            standard_deviation: if parity { 0.0 } else { 1.0 },
481            sample_count: photon_result.sample_count,
482            timestamp: std::time::SystemTime::now()
483                .duration_since(std::time::UNIX_EPOCH)
484                .unwrap()
485                .as_secs_f64(),
486        };
487
488        self.measurement_history.push(result.clone());
489        Ok(result)
490    }
491
492    /// Perform Bell measurement on two modes
493    pub async fn bell_measurement(
494        &mut self,
495        state: &mut GaussianState,
496        mode1: usize,
497        mode2: usize,
498        basis: BellBasis,
499    ) -> DeviceResult<CVMeasurementResult> {
500        if mode1 >= state.num_modes || mode2 >= state.num_modes {
501            return Err(DeviceError::InvalidInput(
502                "One or both modes exceed available modes".to_string(),
503            ));
504        }
505
506        let (phase1, phase2) = match basis {
507            BellBasis::XBasis => (0.0, 0.0),
508            BellBasis::PBasis => (PI / 2.0, PI / 2.0),
509            BellBasis::MixedBasis { phase } => (0.0, phase),
510        };
511
512        // Measure both modes
513        let result1 = self.homodyne_measurement(state, mode1, phase1).await?;
514        let result2 = self.homodyne_measurement(state, mode2, phase2).await?;
515
516        // Calculate correlation
517        let (val1, val2) = match (result1.outcome, result2.outcome) {
518            (CVMeasurementOutcome::Real(v1), CVMeasurementOutcome::Real(v2)) => (v1, v2),
519            _ => {
520                return Err(DeviceError::InvalidInput(
521                    "Invalid homodyne results".to_string(),
522                ))
523            }
524        };
525
526        let correlation = val1 * val2;
527        let avg_phase = (phase1 + phase2) / 2.0;
528
529        let result = CVMeasurementResult {
530            outcome: CVMeasurementOutcome::BellCorrelation {
531                correlation,
532                phase: avg_phase,
533            },
534            fidelity: (result1.fidelity + result2.fidelity) / 2.0,
535            standard_deviation: (result1.standard_deviation.powi(2)
536                + result2.standard_deviation.powi(2))
537            .sqrt(),
538            sample_count: result1.sample_count.min(result2.sample_count),
539            timestamp: std::time::SystemTime::now()
540                .duration_since(std::time::UNIX_EPOCH)
541                .unwrap()
542                .as_secs_f64(),
543        };
544
545        self.measurement_history.push(result.clone());
546        Ok(result)
547    }
548
549    /// Calculate detection noise
550    fn calculate_detection_noise(&self, mode: usize) -> f64 {
551        let electronic_noise = 10.0_f64.powf(self.config.calibration.electronic_noise_db / 10.0);
552        let efficiency = self
553            .config
554            .calibration
555            .efficiency
556            .get(mode)
557            .unwrap_or(&0.95);
558        let phase_noise = self.config.phase_stability.powi(2);
559
560        electronic_noise + (1.0 - efficiency) / efficiency + phase_noise
561    }
562
563    /// Estimate measurement fidelity based on sample statistics
564    fn estimate_measurement_fidelity(
565        &self,
566        samples: &[f64],
567        theoretical_mean: f64,
568        theoretical_variance: f64,
569    ) -> f64 {
570        let sample_mean = samples.iter().sum::<f64>() / samples.len() as f64;
571        let sample_variance = samples
572            .iter()
573            .map(|x| (x - sample_mean).powi(2))
574            .sum::<f64>()
575            / samples.len() as f64;
576
577        let mean_error = (sample_mean - theoretical_mean).abs();
578        let variance_error = (sample_variance - theoretical_variance).abs();
579
580        // Simple fidelity estimate
581        let fidelity = 1.0 / (1.0 + mean_error + variance_error);
582        fidelity.clamp(0.0, 1.0)
583    }
584
585    /// Get measurement history
586    pub fn get_measurement_history(&self) -> &[CVMeasurementResult] {
587        &self.measurement_history
588    }
589
590    /// Clear measurement history
591    pub fn clear_history(&mut self) {
592        self.measurement_history.clear();
593    }
594
595    /// Get measurement statistics
596    pub fn get_measurement_statistics(&self) -> MeasurementStatistics {
597        if self.measurement_history.is_empty() {
598            return MeasurementStatistics::default();
599        }
600
601        let total_measurements = self.measurement_history.len();
602        let avg_fidelity = self
603            .measurement_history
604            .iter()
605            .map(|r| r.fidelity)
606            .sum::<f64>()
607            / total_measurements as f64;
608
609        let avg_std_dev = self
610            .measurement_history
611            .iter()
612            .map(|r| r.standard_deviation)
613            .sum::<f64>()
614            / total_measurements as f64;
615
616        let total_samples = self
617            .measurement_history
618            .iter()
619            .map(|r| r.sample_count)
620            .sum::<usize>();
621
622        MeasurementStatistics {
623            total_measurements,
624            average_fidelity: avg_fidelity,
625            average_standard_deviation: avg_std_dev,
626            total_samples,
627            is_calibrated: self.is_calibrated,
628        }
629    }
630}
631
632/// Statistics for measurement performance
633#[derive(Debug, Clone, Serialize, Deserialize)]
634pub struct MeasurementStatistics {
635    pub total_measurements: usize,
636    pub average_fidelity: f64,
637    pub average_standard_deviation: f64,
638    pub total_samples: usize,
639    pub is_calibrated: bool,
640}
641
642impl Default for MeasurementStatistics {
643    fn default() -> Self {
644        Self {
645            total_measurements: 0,
646            average_fidelity: 0.0,
647            average_standard_deviation: 0.0,
648            total_samples: 0,
649            is_calibrated: false,
650        }
651    }
652}
653
654#[cfg(test)]
655mod tests {
656    use super::*;
657
658    #[tokio::test]
659    async fn test_measurement_engine_creation() {
660        let config = CVMeasurementConfig::default();
661        let engine = CVMeasurementEngine::new(config);
662        assert!(!engine.is_calibrated);
663        assert_eq!(engine.measurement_history.len(), 0);
664    }
665
666    #[tokio::test]
667    async fn test_calibration() {
668        let config = CVMeasurementConfig::default();
669        let mut engine = CVMeasurementEngine::new(config);
670
671        engine.calibrate().await.unwrap();
672        assert!(engine.is_calibrated);
673    }
674
675    #[tokio::test]
676    async fn test_homodyne_measurement() {
677        let config = CVMeasurementConfig::default();
678        let mut engine = CVMeasurementEngine::new(config);
679        engine.calibrate().await.unwrap();
680
681        let mut state =
682            GaussianState::coherent_state(2, vec![Complex::new(2.0, 0.0), Complex::new(0.0, 0.0)])
683                .unwrap();
684
685        let result = engine
686            .homodyne_measurement(&mut state, 0, 0.0)
687            .await
688            .unwrap();
689
690        match result.outcome {
691            CVMeasurementOutcome::Real(value) => {
692                assert!(value > 0.0); // Should measure positive x quadrature
693            }
694            _ => panic!("Expected real outcome"),
695        }
696
697        assert!(result.fidelity > 0.0);
698        assert_eq!(engine.measurement_history.len(), 1);
699    }
700
701    #[tokio::test]
702    async fn test_heterodyne_measurement() {
703        let config = CVMeasurementConfig::default();
704        let mut engine = CVMeasurementEngine::new(config);
705        engine.calibrate().await.unwrap();
706
707        let mut state = GaussianState::coherent_state(1, vec![Complex::new(1.0, 0.5)]).unwrap();
708
709        let result = engine.heterodyne_measurement(&mut state, 0).await.unwrap();
710
711        match result.outcome {
712            CVMeasurementOutcome::Complex(z) => {
713                assert!(z.magnitude() > 0.0);
714            }
715            _ => panic!("Expected complex outcome"),
716        }
717    }
718
719    #[tokio::test]
720    async fn test_photon_number_measurement() {
721        let config = CVMeasurementConfig::default();
722        let mut engine = CVMeasurementEngine::new(config);
723        engine.calibrate().await.unwrap();
724
725        let state = GaussianState::coherent_state(1, vec![Complex::new(2.0, 0.0)]).unwrap();
726
727        let result = engine.photon_number_measurement(&state, 0).await.unwrap();
728
729        match result.outcome {
730            CVMeasurementOutcome::Integer(n) => {
731                assert!(n >= 0); // Photon number should be non-negative
732            }
733            _ => panic!("Expected integer outcome"),
734        }
735    }
736
737    #[tokio::test]
738    async fn test_parity_measurement() {
739        let config = CVMeasurementConfig::default();
740        let mut engine = CVMeasurementEngine::new(config);
741        engine.calibrate().await.unwrap();
742
743        let state = GaussianState::vacuum_state(1);
744
745        let result = engine.parity_measurement(&state, 0).await.unwrap();
746
747        match result.outcome {
748            CVMeasurementOutcome::Boolean(parity) => {
749                // Vacuum state should have even parity (0 photons)
750                assert!(parity);
751            }
752            _ => panic!("Expected boolean outcome"),
753        }
754    }
755
756    #[test]
757    fn test_measurement_config_defaults() {
758        let config = CVMeasurementConfig::default();
759        assert_eq!(config.num_samples, 10000);
760        assert_eq!(config.integration_time, 0.001);
761        assert!(config.enable_post_processing);
762    }
763
764    #[test]
765    fn test_measurement_statistics() {
766        let config = CVMeasurementConfig::default();
767        let engine = CVMeasurementEngine::new(config);
768
769        let stats = engine.get_measurement_statistics();
770        assert_eq!(stats.total_measurements, 0);
771        assert!(!stats.is_calibrated);
772    }
773}