1use super::{CVDeviceConfig, Complex, GaussianState};
7use crate::{DeviceError, DeviceResult};
8use scirs2_core::random::prelude::*;
9use scirs2_core::random::{Distribution, Poisson, RandNormal};
10use serde::{Deserialize, Serialize};
11use std::f64::consts::PI;
12
13type Normal<T> = RandNormal<T>;
15
16#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
18pub enum CVMeasurementScheme {
19 Homodyne { phase: f64 },
21 Heterodyne,
23 PhotonNumber,
25 Parity,
27 Bell { basis: BellBasis },
29 FockProjection { n: usize },
31 CoherentProjection { alpha: Complex },
33}
34
35#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
37pub enum BellBasis {
38 XBasis,
40 PBasis,
42 MixedBasis { phase: f64 },
44}
45
46#[derive(Debug, Clone, Serialize, Deserialize)]
48pub struct CVMeasurementResult {
49 pub outcome: CVMeasurementOutcome,
51 pub fidelity: f64,
53 pub standard_deviation: f64,
55 pub sample_count: usize,
57 pub timestamp: f64,
59}
60
61#[derive(Debug, Clone, Serialize, Deserialize)]
63pub enum CVMeasurementOutcome {
64 Real(f64),
66 Complex(Complex),
68 Integer(i32),
70 Boolean(bool),
72 BellCorrelation { correlation: f64, phase: f64 },
74}
75
76#[derive(Debug, Clone, Serialize, Deserialize)]
78pub struct CVMeasurementConfig {
79 pub num_samples: usize,
81 pub integration_time: f64,
83 pub lo_power_mw: f64,
85 pub bandwidth_hz: f64,
87 pub phase_stability: f64,
89 pub enable_post_processing: bool,
91 pub calibration: MeasurementCalibration,
93}
94
95#[derive(Debug, Clone, Serialize, Deserialize)]
97pub struct MeasurementCalibration {
98 pub efficiency: Vec<f64>,
100 pub electronic_noise_db: f64,
102 pub dark_count_rate: f64,
104 pub gain_factors: Vec<f64>,
106 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, 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], 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
136pub struct CVMeasurementEngine {
138 config: CVMeasurementConfig,
140 measurement_history: Vec<CVMeasurementResult>,
142 is_calibrated: bool,
144}
145
146impl CVMeasurementEngine {
147 pub const fn new(config: CVMeasurementConfig) -> Self {
149 Self {
150 config,
151 measurement_history: Vec::new(),
152 is_calibrated: false,
153 }
154 }
155
156 pub async fn calibrate(&mut self) -> DeviceResult<()> {
158 println!("Calibrating CV measurement system...");
159
160 tokio::time::sleep(std::time::Duration::from_millis(500)).await;
162
163 for i in 0..self.config.calibration.efficiency.len() {
165 self.config.calibration.efficiency[i] =
166 0.03f64.mul_add(thread_rng().gen::<f64>(), 0.95);
167 self.config.calibration.gain_factors[i] =
168 0.1f64.mul_add(thread_rng().gen::<f64>() - 0.5, 1.0);
169 self.config.calibration.phase_offsets[i] = 0.1 * (thread_rng().gen::<f64>() - 0.5);
170 }
171
172 self.is_calibrated = true;
173 println!("Calibration complete");
174 Ok(())
175 }
176
177 pub async fn homodyne_measurement(
179 &mut self,
180 state: &mut GaussianState,
181 mode: usize,
182 phase: f64,
183 ) -> DeviceResult<CVMeasurementResult> {
184 if !self.is_calibrated {
185 return Err(DeviceError::DeviceNotInitialized(
186 "Measurement system not calibrated".to_string(),
187 ));
188 }
189
190 if mode >= state.num_modes {
191 return Err(DeviceError::InvalidInput(format!(
192 "Mode {mode} exceeds available modes"
193 )));
194 }
195
196 let calibrated_phase = phase
198 + self
199 .config
200 .calibration
201 .phase_offsets
202 .get(mode)
203 .unwrap_or(&0.0);
204
205 let cos_phi = calibrated_phase.cos();
207 let sin_phi = calibrated_phase.sin();
208
209 let mean_x = state.mean_vector[2 * mode];
210 let mean_p = state.mean_vector[2 * mode + 1];
211 let theoretical_mean = cos_phi * mean_x + sin_phi * mean_p;
212
213 let var_x = state.covariancematrix[2 * mode][2 * mode];
214 let var_p = state.covariancematrix[2 * mode + 1][2 * mode + 1];
215 let cov_xp = state.covariancematrix[2 * mode][2 * mode + 1];
216
217 let theoretical_variance = (2.0 * cos_phi * sin_phi).mul_add(
218 cov_xp,
219 cos_phi.powi(2).mul_add(var_x, sin_phi.powi(2) * var_p),
220 );
221
222 let efficiency = self
224 .config
225 .calibration
226 .efficiency
227 .get(mode)
228 .unwrap_or(&0.95);
229 let gain = self
230 .config
231 .calibration
232 .gain_factors
233 .get(mode)
234 .unwrap_or(&1.0);
235
236 let noise_variance = self.calculate_detection_noise(mode);
237 let total_variance = theoretical_variance / efficiency + noise_variance;
238
239 let mut samples = Vec::new();
241 let distribution = Normal::new(theoretical_mean, total_variance.sqrt())
242 .map_err(|e| DeviceError::InvalidInput(format!("Distribution error: {e}")))?;
243
244 let mut rng = StdRng::seed_from_u64(thread_rng().gen::<u64>());
245 for _ in 0..self.config.num_samples {
246 let sample = distribution.sample(&mut rng) * gain;
247 samples.push(sample);
248 }
249
250 let mean_outcome = samples.iter().sum::<f64>() / samples.len() as f64;
252 let variance = samples
253 .iter()
254 .map(|x| (x - mean_outcome).powi(2))
255 .sum::<f64>()
256 / samples.len() as f64;
257 let std_dev = variance.sqrt();
258
259 let fidelity =
261 self.estimate_measurement_fidelity(&samples, theoretical_mean, total_variance);
262
263 let result = CVMeasurementResult {
264 outcome: CVMeasurementOutcome::Real(mean_outcome),
265 fidelity,
266 standard_deviation: std_dev,
267 sample_count: samples.len(),
268 timestamp: std::time::SystemTime::now()
269 .duration_since(std::time::UNIX_EPOCH)
270 .unwrap_or_default()
271 .as_secs_f64(),
272 };
273
274 state.condition_on_homodyne_measurement(mode, calibrated_phase, mean_outcome)?;
276
277 self.measurement_history.push(result.clone());
278 Ok(result)
279 }
280
281 pub async fn heterodyne_measurement(
283 &mut self,
284 state: &mut GaussianState,
285 mode: usize,
286 ) -> DeviceResult<CVMeasurementResult> {
287 if !self.is_calibrated {
288 return Err(DeviceError::DeviceNotInitialized(
289 "Measurement system not calibrated".to_string(),
290 ));
291 }
292
293 if mode >= state.num_modes {
294 return Err(DeviceError::InvalidInput(format!(
295 "Mode {mode} exceeds available modes"
296 )));
297 }
298
299 let efficiency = self
300 .config
301 .calibration
302 .efficiency
303 .get(mode)
304 .unwrap_or(&0.95);
305 let gain = self
306 .config
307 .calibration
308 .gain_factors
309 .get(mode)
310 .unwrap_or(&1.0);
311
312 let mean_x = state.mean_vector[2 * mode];
314 let mean_p = state.mean_vector[2 * mode + 1];
315 let var_x = state.covariancematrix[2 * mode][2 * mode];
316 let var_p = state.covariancematrix[2 * mode + 1][2 * mode + 1];
317
318 let noise_variance = self.calculate_detection_noise(mode);
320
321 let mut x_samples = Vec::new();
323 let mut p_samples = Vec::new();
324
325 let x_distribution =
326 Normal::new(mean_x, (var_x / efficiency + noise_variance / 2.0).sqrt())
327 .map_err(|e| DeviceError::InvalidInput(format!("Distribution error: {e}")))?;
328 let p_distribution =
329 Normal::new(mean_p, (var_p / efficiency + noise_variance / 2.0).sqrt())
330 .map_err(|e| DeviceError::InvalidInput(format!("Distribution error: {e}")))?;
331
332 let mut rng = StdRng::seed_from_u64(thread_rng().gen::<u64>());
333 for _ in 0..self.config.num_samples {
334 x_samples.push(x_distribution.sample(&mut rng) * gain);
335 p_samples.push(p_distribution.sample(&mut rng) * gain);
336 }
337
338 let mean_x_outcome = x_samples.iter().sum::<f64>() / x_samples.len() as f64;
340 let mean_p_outcome = p_samples.iter().sum::<f64>() / p_samples.len() as f64;
341
342 let complex_outcome = Complex::new(
343 mean_p_outcome.mul_add(Complex::i().real, mean_x_outcome) / (2.0_f64).sqrt(),
344 mean_x_outcome.mul_add(-Complex::i().imag, mean_p_outcome) / (2.0_f64).sqrt(),
345 );
346
347 let x_var = x_samples
349 .iter()
350 .map(|x| (x - mean_x_outcome).powi(2))
351 .sum::<f64>()
352 / x_samples.len() as f64;
353 let p_var = p_samples
354 .iter()
355 .map(|p| (p - mean_p_outcome).powi(2))
356 .sum::<f64>()
357 / p_samples.len() as f64;
358 let std_dev = (x_var + p_var).sqrt();
359
360 let theoretical_variance = (var_x + var_p) / efficiency + noise_variance;
362 let fidelity = 1.0 / (1.0 + theoretical_variance);
363
364 let result = CVMeasurementResult {
365 outcome: CVMeasurementOutcome::Complex(complex_outcome),
366 fidelity,
367 standard_deviation: std_dev,
368 sample_count: self.config.num_samples,
369 timestamp: std::time::SystemTime::now()
370 .duration_since(std::time::UNIX_EPOCH)
371 .unwrap_or_default()
372 .as_secs_f64(),
373 };
374
375 state.condition_on_heterodyne_measurement(mode, complex_outcome)?;
377
378 self.measurement_history.push(result.clone());
379 Ok(result)
380 }
381
382 pub async fn photon_number_measurement(
384 &mut self,
385 state: &GaussianState,
386 mode: usize,
387 ) -> DeviceResult<CVMeasurementResult> {
388 if !self.is_calibrated {
389 return Err(DeviceError::DeviceNotInitialized(
390 "Measurement system not calibrated".to_string(),
391 ));
392 }
393
394 if mode >= state.num_modes {
395 return Err(DeviceError::InvalidInput(format!(
396 "Mode {mode} exceeds available modes"
397 )));
398 }
399
400 let mean_x = state.mean_vector[2 * mode];
402 let mean_p = state.mean_vector[2 * mode + 1];
403 let var_x = state.covariancematrix[2 * mode][2 * mode];
404 let var_p = state.covariancematrix[2 * mode + 1][2 * mode + 1];
405
406 let mean_n = 0.5 * (mean_p.mul_add(mean_p, mean_x.powi(2)) / 2.0 + (var_x + var_p) - 1.0);
408
409 let efficiency = self
412 .config
413 .calibration
414 .efficiency
415 .get(mode)
416 .unwrap_or(&0.95);
417 let dark_counts = self.config.calibration.dark_count_rate * self.config.integration_time;
418
419 let detected_n = mean_n * efficiency + dark_counts;
420
421 let mut samples = Vec::new();
423 let mut rng = StdRng::seed_from_u64(thread_rng().gen::<u64>());
424 for _ in 0..self.config.num_samples {
425 let sample = if detected_n > 0.0 {
426 let poisson = Poisson::new(detected_n)
427 .map_err(|e| DeviceError::InvalidInput(format!("Poisson error: {e}")))?;
428 poisson.sample(&mut rng) as f64
429 } else {
430 0.0
431 };
432 samples.push(sample);
433 }
434
435 let mean_outcome = samples.iter().sum::<f64>() / samples.len() as f64;
436 let variance = samples
437 .iter()
438 .map(|x| (x - mean_outcome).powi(2))
439 .sum::<f64>()
440 / samples.len() as f64;
441
442 let rounded_outcome = mean_outcome.round() as i32;
443 let fidelity = 1.0 / (1.0 + variance / (mean_outcome + 1.0));
444
445 let result = CVMeasurementResult {
446 outcome: CVMeasurementOutcome::Integer(rounded_outcome),
447 fidelity,
448 standard_deviation: variance.sqrt(),
449 sample_count: samples.len(),
450 timestamp: std::time::SystemTime::now()
451 .duration_since(std::time::UNIX_EPOCH)
452 .unwrap_or_default()
453 .as_secs_f64(),
454 };
455
456 self.measurement_history.push(result.clone());
457 Ok(result)
458 }
459
460 pub async fn parity_measurement(
462 &mut self,
463 state: &GaussianState,
464 mode: usize,
465 ) -> DeviceResult<CVMeasurementResult> {
466 let photon_result = self.photon_number_measurement(state, mode).await?;
468
469 let parity = match photon_result.outcome {
470 CVMeasurementOutcome::Integer(n) => n % 2 == 0,
471 _ => {
472 return Err(DeviceError::InvalidInput(
473 "Invalid photon number result".to_string(),
474 ))
475 }
476 };
477
478 let result = CVMeasurementResult {
479 outcome: CVMeasurementOutcome::Boolean(parity),
480 fidelity: photon_result.fidelity,
481 standard_deviation: if parity { 0.0 } else { 1.0 },
482 sample_count: photon_result.sample_count,
483 timestamp: std::time::SystemTime::now()
484 .duration_since(std::time::UNIX_EPOCH)
485 .unwrap_or_default()
486 .as_secs_f64(),
487 };
488
489 self.measurement_history.push(result.clone());
490 Ok(result)
491 }
492
493 pub async fn bell_measurement(
495 &mut self,
496 state: &mut GaussianState,
497 mode1: usize,
498 mode2: usize,
499 basis: BellBasis,
500 ) -> DeviceResult<CVMeasurementResult> {
501 if mode1 >= state.num_modes || mode2 >= state.num_modes {
502 return Err(DeviceError::InvalidInput(
503 "One or both modes exceed available modes".to_string(),
504 ));
505 }
506
507 let (phase1, phase2) = match basis {
508 BellBasis::XBasis => (0.0, 0.0),
509 BellBasis::PBasis => (PI / 2.0, PI / 2.0),
510 BellBasis::MixedBasis { phase } => (0.0, phase),
511 };
512
513 let result1 = self.homodyne_measurement(state, mode1, phase1).await?;
515 let result2 = self.homodyne_measurement(state, mode2, phase2).await?;
516
517 let (val1, val2) = match (result1.outcome, result2.outcome) {
519 (CVMeasurementOutcome::Real(v1), CVMeasurementOutcome::Real(v2)) => (v1, v2),
520 _ => {
521 return Err(DeviceError::InvalidInput(
522 "Invalid homodyne results".to_string(),
523 ))
524 }
525 };
526
527 let correlation = val1 * val2;
528 let avg_phase = f64::midpoint(phase1, phase2);
529
530 let result = CVMeasurementResult {
531 outcome: CVMeasurementOutcome::BellCorrelation {
532 correlation,
533 phase: avg_phase,
534 },
535 fidelity: f64::midpoint(result1.fidelity, result2.fidelity),
536 standard_deviation: result1.standard_deviation.hypot(result2.standard_deviation),
537 sample_count: result1.sample_count.min(result2.sample_count),
538 timestamp: std::time::SystemTime::now()
539 .duration_since(std::time::UNIX_EPOCH)
540 .unwrap_or_default()
541 .as_secs_f64(),
542 };
543
544 self.measurement_history.push(result.clone());
545 Ok(result)
546 }
547
548 fn calculate_detection_noise(&self, mode: usize) -> f64 {
550 let electronic_noise = 10.0_f64.powf(self.config.calibration.electronic_noise_db / 10.0);
551 let efficiency = self
552 .config
553 .calibration
554 .efficiency
555 .get(mode)
556 .unwrap_or(&0.95);
557 let phase_noise = self.config.phase_stability.powi(2);
558
559 electronic_noise + (1.0 - efficiency) / efficiency + phase_noise
560 }
561
562 fn estimate_measurement_fidelity(
564 &self,
565 samples: &[f64],
566 theoretical_mean: f64,
567 theoretical_variance: f64,
568 ) -> f64 {
569 let sample_mean = samples.iter().sum::<f64>() / samples.len() as f64;
570 let sample_variance = samples
571 .iter()
572 .map(|x| (x - sample_mean).powi(2))
573 .sum::<f64>()
574 / samples.len() as f64;
575
576 let mean_error = (sample_mean - theoretical_mean).abs();
577 let variance_error = (sample_variance - theoretical_variance).abs();
578
579 let fidelity = 1.0 / (1.0 + mean_error + variance_error);
581 fidelity.clamp(0.0, 1.0)
582 }
583
584 pub fn get_measurement_history(&self) -> &[CVMeasurementResult] {
586 &self.measurement_history
587 }
588
589 pub fn clear_history(&mut self) {
591 self.measurement_history.clear();
592 }
593
594 pub fn get_measurement_statistics(&self) -> MeasurementStatistics {
596 if self.measurement_history.is_empty() {
597 return MeasurementStatistics::default();
598 }
599
600 let total_measurements = self.measurement_history.len();
601 let avg_fidelity = self
602 .measurement_history
603 .iter()
604 .map(|r| r.fidelity)
605 .sum::<f64>()
606 / total_measurements as f64;
607
608 let avg_std_dev = self
609 .measurement_history
610 .iter()
611 .map(|r| r.standard_deviation)
612 .sum::<f64>()
613 / total_measurements as f64;
614
615 let total_samples = self
616 .measurement_history
617 .iter()
618 .map(|r| r.sample_count)
619 .sum::<usize>();
620
621 MeasurementStatistics {
622 total_measurements,
623 average_fidelity: avg_fidelity,
624 average_standard_deviation: avg_std_dev,
625 total_samples,
626 is_calibrated: self.is_calibrated,
627 }
628 }
629}
630
631#[derive(Debug, Clone, Serialize, Deserialize)]
633pub struct MeasurementStatistics {
634 pub total_measurements: usize,
635 pub average_fidelity: f64,
636 pub average_standard_deviation: f64,
637 pub total_samples: usize,
638 pub is_calibrated: bool,
639}
640
641impl Default for MeasurementStatistics {
642 fn default() -> Self {
643 Self {
644 total_measurements: 0,
645 average_fidelity: 0.0,
646 average_standard_deviation: 0.0,
647 total_samples: 0,
648 is_calibrated: false,
649 }
650 }
651}
652
653#[cfg(test)]
654mod tests {
655 use super::*;
656
657 #[tokio::test]
658 async fn test_measurement_engine_creation() {
659 let config = CVMeasurementConfig::default();
660 let engine = CVMeasurementEngine::new(config);
661 assert!(!engine.is_calibrated);
662 assert_eq!(engine.measurement_history.len(), 0);
663 }
664
665 #[tokio::test]
666 async fn test_calibration() {
667 let config = CVMeasurementConfig::default();
668 let mut engine = CVMeasurementEngine::new(config);
669
670 engine
671 .calibrate()
672 .await
673 .expect("Engine calibration should succeed");
674 assert!(engine.is_calibrated);
675 }
676
677 #[tokio::test]
678 async fn test_homodyne_measurement() {
679 let config = CVMeasurementConfig::default();
680 let mut engine = CVMeasurementEngine::new(config);
681 engine
682 .calibrate()
683 .await
684 .expect("Engine calibration should succeed");
685
686 let mut state =
687 GaussianState::coherent_state(2, vec![Complex::new(2.0, 0.0), Complex::new(0.0, 0.0)])
688 .expect("Coherent state creation should succeed");
689
690 let result = engine
691 .homodyne_measurement(&mut state, 0, 0.0)
692 .await
693 .expect("Homodyne measurement should succeed");
694
695 match result.outcome {
696 CVMeasurementOutcome::Real(value) => {
697 assert!(value > 0.0); }
699 _ => panic!("Expected real outcome"),
700 }
701
702 assert!(result.fidelity > 0.0);
703 assert_eq!(engine.measurement_history.len(), 1);
704 }
705
706 #[tokio::test]
707 async fn test_heterodyne_measurement() {
708 let config = CVMeasurementConfig::default();
709 let mut engine = CVMeasurementEngine::new(config);
710 engine
711 .calibrate()
712 .await
713 .expect("Engine calibration should succeed");
714
715 let mut state = GaussianState::coherent_state(1, vec![Complex::new(1.0, 0.5)])
716 .expect("Coherent state creation should succeed");
717
718 let result = engine
719 .heterodyne_measurement(&mut state, 0)
720 .await
721 .expect("Heterodyne measurement should succeed");
722
723 match result.outcome {
724 CVMeasurementOutcome::Complex(z) => {
725 assert!(z.magnitude() > 0.0);
726 }
727 _ => panic!("Expected complex outcome"),
728 }
729 }
730
731 #[tokio::test]
732 async fn test_photon_number_measurement() {
733 let config = CVMeasurementConfig::default();
734 let mut engine = CVMeasurementEngine::new(config);
735 engine
736 .calibrate()
737 .await
738 .expect("Engine calibration should succeed");
739
740 let state = GaussianState::coherent_state(1, vec![Complex::new(2.0, 0.0)])
741 .expect("Coherent state creation should succeed");
742
743 let result = engine
744 .photon_number_measurement(&state, 0)
745 .await
746 .expect("Photon number measurement should succeed");
747
748 match result.outcome {
749 CVMeasurementOutcome::Integer(n) => {
750 assert!(n >= 0); }
752 _ => panic!("Expected integer outcome"),
753 }
754 }
755
756 #[tokio::test]
757 async fn test_parity_measurement() {
758 let config = CVMeasurementConfig::default();
759 let mut engine = CVMeasurementEngine::new(config);
760 engine
761 .calibrate()
762 .await
763 .expect("Engine calibration should succeed");
764
765 let state = GaussianState::vacuum_state(1);
766
767 let result = engine
768 .parity_measurement(&state, 0)
769 .await
770 .expect("Parity measurement should succeed");
771
772 match result.outcome {
773 CVMeasurementOutcome::Boolean(parity) => {
774 assert!(parity);
776 }
777 _ => panic!("Expected boolean outcome"),
778 }
779 }
780
781 #[test]
782 fn test_measurement_config_defaults() {
783 let config = CVMeasurementConfig::default();
784 assert_eq!(config.num_samples, 10000);
785 assert_eq!(config.integration_time, 0.001);
786 assert!(config.enable_post_processing);
787 }
788
789 #[test]
790 fn test_measurement_statistics() {
791 let config = CVMeasurementConfig::default();
792 let engine = CVMeasurementEngine::new(config);
793
794 let stats = engine.get_measurement_statistics();
795 assert_eq!(stats.total_measurements, 0);
796 assert!(!stats.is_calibrated);
797 }
798}