quantrs2_device/continuous_variable/
gaussian_states.rs1use super::{CVDeviceConfig, CVEntanglementMeasures, CVModeState, Complex};
7use crate::{DeviceError, DeviceResult};
8use scirs2_core::random::prelude::*;
9use scirs2_core::random::{Distribution, RandNormal};
10type Normal<T> = RandNormal<T>;
12use serde::{Deserialize, Serialize};
13use std::f64::consts::PI;
14
15#[derive(Debug, Clone, Serialize, Deserialize)]
17pub struct GaussianState {
18 pub num_modes: usize,
20 pub mean_vector: Vec<f64>,
22 pub covariancematrix: Vec<Vec<f64>>,
24 symplectic_matrix: Vec<Vec<f64>>,
26}
27
28impl GaussianState {
29 pub fn vacuum_state(num_modes: usize) -> Self {
31 let vector_size = 2 * num_modes;
32 let mean_vector = vec![0.0; vector_size];
33
34 let mut covariancematrix = vec![vec![0.0; vector_size]; vector_size];
36 for i in 0..vector_size {
37 covariancematrix[i][i] = 0.5;
38 }
39
40 let symplectic_matrix = Self::build_symplectic_matrix(num_modes);
41
42 Self {
43 num_modes,
44 mean_vector,
45 covariancematrix,
46 symplectic_matrix,
47 }
48 }
49
50 pub fn coherent_state(num_modes: usize, displacements: Vec<Complex>) -> DeviceResult<Self> {
52 if displacements.len() != num_modes {
53 return Err(DeviceError::InvalidInput(
54 "Number of displacements must match number of modes".to_string(),
55 ));
56 }
57
58 let mut state = Self::vacuum_state(num_modes);
59
60 for (i, displacement) in displacements.iter().enumerate() {
62 state.mean_vector[2 * i] = displacement.real * (2.0_f64).sqrt(); state.mean_vector[2 * i + 1] = displacement.imag * (2.0_f64).sqrt();
64 }
66
67 Ok(state)
68 }
69
70 pub fn squeezed_vacuum_state(
72 num_modes: usize,
73 squeezing_params: Vec<f64>,
74 squeezing_phases: Vec<f64>,
75 ) -> DeviceResult<Self> {
76 if squeezing_params.len() != num_modes || squeezing_phases.len() != num_modes {
77 return Err(DeviceError::InvalidInput(
78 "Squeezing parameters and phases must match number of modes".to_string(),
79 ));
80 }
81
82 let mut state = Self::vacuum_state(num_modes);
83
84 for i in 0..num_modes {
86 state.apply_squeezing(i, squeezing_params[i], squeezing_phases[i])?;
87 }
88
89 Ok(state)
90 }
91
92 fn build_symplectic_matrix(num_modes: usize) -> Vec<Vec<f64>> {
94 let size = 2 * num_modes;
95 let mut omega = vec![vec![0.0; size]; size];
96
97 for i in 0..num_modes {
98 omega[2 * i][2 * i + 1] = 1.0;
99 omega[2 * i + 1][2 * i] = -1.0;
100 }
101
102 omega
103 }
104
105 pub fn apply_displacement(&mut self, mode: usize, displacement: Complex) -> DeviceResult<()> {
107 if mode >= self.num_modes {
108 return Err(DeviceError::InvalidInput(format!(
109 "Mode {mode} exceeds available modes"
110 )));
111 }
112
113 self.mean_vector[2 * mode] += displacement.real * (2.0_f64).sqrt();
115 self.mean_vector[2 * mode + 1] += displacement.imag * (2.0_f64).sqrt();
116
117 Ok(())
118 }
119
120 pub fn apply_squeezing(&mut self, mode: usize, r: f64, phi: f64) -> DeviceResult<()> {
122 if mode >= self.num_modes {
123 return Err(DeviceError::InvalidInput(format!(
124 "Mode {mode} exceeds available modes"
125 )));
126 }
127
128 let cos_phi = phi.cos();
129 let sin_phi = phi.sin();
130 let cosh_r = r.cosh();
131 let sinh_r = r.sinh();
132
133 let s11 = sinh_r.mul_add(-cos_phi, cosh_r); let s12 = -sinh_r * sin_phi; let s21 = -sinh_r * sin_phi; let s22 = sinh_r.mul_add(cos_phi, cosh_r); let i = 2 * mode;
142 let j = 2 * mode + 1;
143
144 let old_covar = self.covariancematrix.clone();
145
146 for a in 0..2 * self.num_modes {
148 for b in 0..2 * self.num_modes {
149 if (a == i || a == j) && (b == i || b == j) {
150 let mut new_val = 0.0;
151
152 for k in &[i, j] {
153 for l in &[i, j] {
154 let s_ak = if a == i {
155 if *k == i {
156 s11
157 } else {
158 s12
159 }
160 } else if *k == i {
161 s21
162 } else {
163 s22
164 };
165
166 let s_bl = if b == i {
167 if *l == i {
168 s11
169 } else {
170 s12
171 }
172 } else if *l == i {
173 s21
174 } else {
175 s22
176 };
177
178 new_val += s_ak * old_covar[*k][*l] * s_bl;
179 }
180 }
181
182 self.covariancematrix[a][b] = new_val;
183 } else if a == i || a == j {
184 let s_a = if a == i { [s11, s12] } else { [s21, s22] };
186 self.covariancematrix[a][b] =
187 s_a[0].mul_add(old_covar[i][b], s_a[1] * old_covar[j][b]);
188 } else if b == i || b == j {
189 let s_b = if b == i { [s11, s21] } else { [s12, s22] };
191 self.covariancematrix[a][b] =
192 old_covar[a][i].mul_add(s_b[0], old_covar[a][j] * s_b[1]);
193 }
194 }
195 }
196
197 Ok(())
198 }
199
200 pub fn apply_two_mode_squeezing(
202 &mut self,
203 mode1: usize,
204 mode2: usize,
205 r: f64,
206 phi: f64,
207 ) -> DeviceResult<()> {
208 if mode1 >= self.num_modes || mode2 >= self.num_modes {
209 return Err(DeviceError::InvalidInput(
210 "One or both modes exceed available modes".to_string(),
211 ));
212 }
213
214 let cos_phi = phi.cos();
215 let sin_phi = phi.sin();
216 let cosh_r = r.cosh();
217 let sinh_r = r.sinh();
218
219 let indices = [2 * mode1, 2 * mode1 + 1, 2 * mode2, 2 * mode2 + 1];
221 let old_covar = self.covariancematrix.clone();
222
223 let mut transform = [[0.0; 4]; 4];
225 transform[0][0] = cosh_r;
226 transform[0][2] = sinh_r * cos_phi;
227 transform[0][3] = sinh_r * sin_phi;
228 transform[1][1] = cosh_r;
229 transform[1][2] = sinh_r * sin_phi;
230 transform[1][3] = -sinh_r * cos_phi;
231 transform[2][0] = sinh_r * cos_phi;
232 transform[2][1] = sinh_r * sin_phi;
233 transform[2][2] = cosh_r;
234 transform[3][0] = sinh_r * sin_phi;
235 transform[3][1] = -sinh_r * cos_phi;
236 transform[3][3] = cosh_r;
237
238 for i in 0..4 {
240 for j in 0..4 {
241 let mut new_val = 0.0;
242 for k in 0..4 {
243 for l in 0..4 {
244 new_val +=
245 transform[i][k] * old_covar[indices[k]][indices[l]] * transform[j][l];
246 }
247 }
248 self.covariancematrix[indices[i]][indices[j]] = new_val;
249 }
250 }
251
252 Ok(())
253 }
254
255 pub fn apply_beamsplitter(
257 &mut self,
258 mode1: usize,
259 mode2: usize,
260 transmittance: f64,
261 phase: f64,
262 ) -> DeviceResult<()> {
263 if mode1 >= self.num_modes || mode2 >= self.num_modes {
264 return Err(DeviceError::InvalidInput(
265 "One or both modes exceed available modes".to_string(),
266 ));
267 }
268
269 let t = transmittance.sqrt();
270 let r = (1.0 - transmittance).sqrt();
271 let cos_phi = phase.cos();
272 let sin_phi = phase.sin();
273
274 let indices = [2 * mode1, 2 * mode1 + 1, 2 * mode2, 2 * mode2 + 1];
276 let old_mean = self.mean_vector.clone();
277 let old_covar = self.covariancematrix.clone();
278
279 let mean1_x = old_mean[2 * mode1];
281 let mean1_p = old_mean[2 * mode1 + 1];
282 let mean2_x = old_mean[2 * mode2];
283 let mean2_p = old_mean[2 * mode2 + 1];
284
285 self.mean_vector[2 * mode1] =
286 (r * sin_phi).mul_add(-mean2_p, t.mul_add(mean1_x, r * cos_phi * mean2_x));
287 self.mean_vector[2 * mode1 + 1] =
288 (r * cos_phi).mul_add(mean2_p, t.mul_add(mean1_p, r * sin_phi * mean2_x));
289 self.mean_vector[2 * mode2] = t.mul_add(
290 mean2_x,
291 (-r * cos_phi).mul_add(mean1_x, r * sin_phi * mean1_p),
292 );
293 self.mean_vector[2 * mode2 + 1] = t.mul_add(
294 mean2_p,
295 (r * sin_phi).mul_add(mean1_x, r * cos_phi * mean1_p),
296 );
297
298 let mut transform = [[0.0; 4]; 4];
300 transform[0][0] = t;
301 transform[0][2] = r * cos_phi;
302 transform[0][3] = -r * sin_phi;
303 transform[1][1] = t;
304 transform[1][2] = r * sin_phi;
305 transform[1][3] = r * cos_phi;
306 transform[2][0] = -r * cos_phi;
307 transform[2][1] = r * sin_phi;
308 transform[2][2] = t;
309 transform[3][0] = r * sin_phi;
310 transform[3][1] = r * cos_phi;
311 transform[3][3] = t;
312
313 for i in 0..4 {
315 for j in 0..4 {
316 let mut new_val = 0.0;
317 for k in 0..4 {
318 for l in 0..4 {
319 new_val +=
320 transform[i][k] * old_covar[indices[k]][indices[l]] * transform[j][l];
321 }
322 }
323 self.covariancematrix[indices[i]][indices[j]] = new_val;
324 }
325 }
326
327 Ok(())
328 }
329
330 pub fn apply_phase_rotation(&mut self, mode: usize, phi: f64) -> DeviceResult<()> {
332 if mode >= self.num_modes {
333 return Err(DeviceError::InvalidInput(format!(
334 "Mode {mode} exceeds available modes"
335 )));
336 }
337
338 let cos_phi = phi.cos();
339 let sin_phi = phi.sin();
340
341 let mean_x = self.mean_vector[2 * mode];
343 let mean_p = self.mean_vector[2 * mode + 1];
344
345 self.mean_vector[2 * mode] = cos_phi.mul_add(mean_x, sin_phi * mean_p);
346 self.mean_vector[2 * mode + 1] = (-sin_phi).mul_add(mean_x, cos_phi * mean_p);
347
348 let indices = [2 * mode, 2 * mode + 1];
350 let old_covar = self.covariancematrix.clone();
351
352 let transform = [[cos_phi, sin_phi], [-sin_phi, cos_phi]];
353
354 for i in 0..2 {
356 for j in 0..2 {
357 let mut new_val = 0.0;
358 for k in 0..2 {
359 for l in 0..2 {
360 new_val +=
361 transform[i][k] * old_covar[indices[k]][indices[l]] * transform[j][l];
362 }
363 }
364 self.covariancematrix[indices[i]][indices[j]] = new_val;
365 }
366 }
367
368 Ok(())
369 }
370
371 pub fn homodyne_measurement(
373 &mut self,
374 mode: usize,
375 phase: f64,
376 config: &CVDeviceConfig,
377 ) -> DeviceResult<f64> {
378 if mode >= self.num_modes {
379 return Err(DeviceError::InvalidInput(format!(
380 "Mode {mode} exceeds available modes"
381 )));
382 }
383
384 let cos_phi = phase.cos();
386 let sin_phi = phase.sin();
387
388 let mean_result = cos_phi.mul_add(
390 self.mean_vector[2 * mode],
391 sin_phi * self.mean_vector[2 * mode + 1],
392 );
393
394 let var_x = self.covariancematrix[2 * mode][2 * mode];
396 let var_p = self.covariancematrix[2 * mode + 1][2 * mode + 1];
397 let cov_xp = self.covariancematrix[2 * mode][2 * mode + 1];
398
399 let variance = (2.0 * cos_phi * sin_phi).mul_add(
400 cov_xp,
401 (cos_phi * cos_phi).mul_add(var_x, sin_phi * sin_phi * var_p),
402 );
403
404 let noise_variance = self.calculate_measurement_noise(config);
406 let total_variance = variance + noise_variance;
407
408 let mut rng = StdRng::seed_from_u64(thread_rng().gen::<u64>());
410 let noise: f64 = Normal::new(0.0, total_variance.sqrt())
411 .map_err(|e| DeviceError::InvalidInput(format!("Distribution error: {e}")))?
412 .sample(&mut rng);
413
414 let result = mean_result + noise;
415
416 self.condition_on_homodyne_measurement(mode, phase, result)?;
418
419 Ok(result)
420 }
421
422 pub fn heterodyne_measurement(
424 &mut self,
425 mode: usize,
426 config: &CVDeviceConfig,
427 ) -> DeviceResult<Complex> {
428 if mode >= self.num_modes {
429 return Err(DeviceError::InvalidInput(format!(
430 "Mode {mode} exceeds available modes"
431 )));
432 }
433
434 let mean_x = self.mean_vector[2 * mode];
436 let mean_p = self.mean_vector[2 * mode + 1];
437
438 let var_x = self.covariancematrix[2 * mode][2 * mode];
439 let var_p = self.covariancematrix[2 * mode + 1][2 * mode + 1];
440
441 let noise_variance = self.calculate_measurement_noise(config);
443 let mut rng = StdRng::seed_from_u64(thread_rng().gen::<u64>());
444
445 let noise_x: f64 = Normal::new(0.0, (var_x + noise_variance / 2.0).sqrt())
446 .map_err(|e| DeviceError::InvalidInput(format!("Distribution error: {e}")))?
447 .sample(&mut rng);
448
449 let noise_p: f64 = Normal::new(0.0, (var_p + noise_variance / 2.0).sqrt())
450 .map_err(|e| DeviceError::InvalidInput(format!("Distribution error: {e}")))?
451 .sample(&mut rng);
452
453 let result_x = mean_x + noise_x;
454 let result_p = mean_p + noise_p;
455
456 let result = Complex::new(
457 result_p.mul_add(Complex::i().real, result_x) / (2.0_f64).sqrt(),
458 result_x.mul_add(-Complex::i().imag, result_p) / (2.0_f64).sqrt(),
459 );
460
461 self.condition_on_heterodyne_measurement(mode, result)?;
463
464 Ok(result)
465 }
466
467 fn calculate_measurement_noise(&self, config: &CVDeviceConfig) -> f64 {
469 let electronic_noise = 10.0_f64.powf(config.electronic_noise_db / 10.0);
471 let efficiency_loss = 1.0 / config.detection_efficiency - 1.0;
472 let thermal_noise = 2.0 * config.temperature_k / 0.01; electronic_noise + efficiency_loss + thermal_noise
475 }
476
477 pub fn condition_on_homodyne_measurement(
479 &mut self,
480 mode: usize,
481 phase: f64,
482 result: f64,
483 ) -> DeviceResult<()> {
484 let cos_phi = phase.cos();
488 let sin_phi = phase.sin();
489
490 self.mean_vector[2 * mode] = result * cos_phi / (2.0_f64).sqrt();
492 self.mean_vector[2 * mode + 1] = result * sin_phi / (2.0_f64).sqrt();
493
494 let measured_var = (cos_phi * cos_phi).mul_add(
496 self.covariancematrix[2 * mode][2 * mode],
497 sin_phi * sin_phi * self.covariancematrix[2 * mode + 1][2 * mode + 1],
498 );
499
500 let reduction_factor = 0.1; self.covariancematrix[2 * mode][2 * mode] *= reduction_factor;
502 self.covariancematrix[2 * mode + 1][2 * mode + 1] *= reduction_factor;
503
504 Ok(())
505 }
506
507 pub fn condition_on_heterodyne_measurement(
509 &mut self,
510 mode: usize,
511 _result: Complex,
512 ) -> DeviceResult<()> {
513 self.reset_mode_to_vacuum(mode)
515 }
516
517 pub fn reset_mode_to_vacuum(&mut self, mode: usize) -> DeviceResult<()> {
519 if mode >= self.num_modes {
520 return Err(DeviceError::InvalidInput(format!(
521 "Mode {mode} exceeds available modes"
522 )));
523 }
524
525 self.mean_vector[2 * mode] = 0.0;
527 self.mean_vector[2 * mode + 1] = 0.0;
528
529 self.covariancematrix[2 * mode][2 * mode] = 0.5;
531 self.covariancematrix[2 * mode + 1][2 * mode + 1] = 0.5;
532 self.covariancematrix[2 * mode][2 * mode + 1] = 0.0;
533 self.covariancematrix[2 * mode + 1][2 * mode] = 0.0;
534
535 for i in 0..2 * self.num_modes {
537 if i != 2 * mode && i != 2 * mode + 1 {
538 self.covariancematrix[2 * mode][i] = 0.0;
539 self.covariancematrix[2 * mode + 1][i] = 0.0;
540 self.covariancematrix[i][2 * mode] = 0.0;
541 self.covariancematrix[i][2 * mode + 1] = 0.0;
542 }
543 }
544
545 Ok(())
546 }
547
548 pub fn get_mode_state(&self, mode: usize) -> DeviceResult<CVModeState> {
550 if mode >= self.num_modes {
551 return Err(DeviceError::InvalidInput(format!(
552 "Mode {mode} exceeds available modes"
553 )));
554 }
555
556 let mean_amplitude = Complex::new(
557 self.mean_vector[2 * mode] / (2.0_f64).sqrt(),
558 self.mean_vector[2 * mode + 1] / (2.0_f64).sqrt(),
559 );
560
561 let var_x = self.covariancematrix[2 * mode][2 * mode];
562 let var_p = self.covariancematrix[2 * mode + 1][2 * mode + 1];
563
564 let (squeezing_parameter, squeezing_phase) = self.calculate_squeezing(mode);
566
567 let purity = self.calculate_mode_purity(mode);
569
570 Ok(CVModeState {
571 mean_amplitude,
572 quadrature_variances: (var_x, var_p),
573 squeezing_parameter,
574 squeezing_phase,
575 purity,
576 })
577 }
578
579 fn calculate_squeezing(&self, mode: usize) -> (f64, f64) {
581 let var_x = self.covariancematrix[2 * mode][2 * mode];
582 let var_p = self.covariancematrix[2 * mode + 1][2 * mode + 1];
583 let cov_xp = self.covariancematrix[2 * mode][2 * mode + 1];
584
585 let delta = (var_x - var_p).mul_add(var_x - var_p, 4.0 * cov_xp.powi(2));
587 let min_var = 0.5 * (var_x + var_p - delta.sqrt());
588 let max_var = 0.5 * (var_x + var_p + delta.sqrt());
589
590 let squeezing_parameter = if min_var < 0.5 {
591 -0.5 * (2.0 * min_var).ln()
592 } else {
593 0.0
594 };
595
596 let squeezing_phase = if cov_xp.abs() > 1e-10 {
597 0.5 * (2.0 * cov_xp / (var_x - var_p)).atan()
598 } else {
599 0.0
600 };
601
602 (squeezing_parameter, squeezing_phase)
603 }
604
605 fn calculate_mode_purity(&self, mode: usize) -> f64 {
607 let var_x = self.covariancematrix[2 * mode][2 * mode];
608 let var_p = self.covariancematrix[2 * mode + 1][2 * mode + 1];
609 let cov_xp = self.covariancematrix[2 * mode][2 * mode + 1];
610
611 let det = cov_xp.mul_add(-cov_xp, var_x * var_p);
612 1.0 / (4.0 * det)
613 }
614
615 pub fn calculate_average_squeezing(&self) -> f64 {
617 let mut total_squeezing = 0.0;
618 for mode in 0..self.num_modes {
619 let (squeezing, _) = self.calculate_squeezing(mode);
620 total_squeezing += squeezing;
621 }
622 total_squeezing / self.num_modes as f64
623 }
624
625 pub fn calculate_purity(&self) -> f64 {
627 let mut total_purity = 0.0;
629 for mode in 0..self.num_modes {
630 total_purity += self.calculate_mode_purity(mode);
631 }
632 total_purity / self.num_modes as f64
633 }
634
635 pub fn calculate_entanglement_entropy(&self) -> f64 {
637 let mut entropy = 0.0;
639
640 for mode in 0..self.num_modes {
641 let var_x = self.covariancematrix[2 * mode][2 * mode];
642 let var_p = self.covariancematrix[2 * mode + 1][2 * mode + 1];
643 let cov_xp = self.covariancematrix[2 * mode][2 * mode + 1];
644
645 let det = cov_xp.mul_add(-cov_xp, var_x * var_p);
646 if det > 0.25 {
647 let eigenvalue = det.sqrt();
648 entropy += (eigenvalue + 0.5).mul_add(
649 (eigenvalue + 0.5).ln(),
650 -((eigenvalue - 0.5) * (eigenvalue - 0.5).ln()),
651 );
652 }
653 }
654
655 entropy
656 }
657
658 pub fn calculate_entanglement_measures(&self) -> CVEntanglementMeasures {
660 let entropy = self.calculate_entanglement_entropy();
662
663 CVEntanglementMeasures {
664 logarithmic_negativity: entropy * 0.5,
665 entanglement_of_formation: entropy * 0.7,
666 mutual_information: entropy * 1.2,
667 epr_correlation: self.calculate_epr_correlation(),
668 }
669 }
670
671 fn calculate_epr_correlation(&self) -> f64 {
673 if self.num_modes < 2 {
674 return 0.0;
675 }
676
677 let cov_x1x2 = self.covariancematrix[0][2];
679 let cov_p1p2 = self.covariancematrix[1][3];
680
681 f64::midpoint(cov_x1x2.abs(), cov_p1p2.abs())
682 }
683}
684
685#[cfg(test)]
688mod tests {
689 use super::*;
690
691 #[test]
692 fn test_vacuum_state_creation() {
693 let state = GaussianState::vacuum_state(2);
694 assert_eq!(state.num_modes, 2);
695 assert_eq!(state.mean_vector.len(), 4);
696 assert_eq!(state.covariancematrix.len(), 4);
697
698 assert!((state.covariancematrix[0][0] - 0.5).abs() < 1e-10);
700 assert!((state.covariancematrix[1][1] - 0.5).abs() < 1e-10);
701 }
702
703 #[test]
704 fn test_coherent_state_creation() {
705 let displacements = vec![Complex::new(1.0, 0.5), Complex::new(0.0, 1.0)];
706 let state = GaussianState::coherent_state(2, displacements)
707 .expect("Coherent state creation should succeed");
708
709 assert!(state.mean_vector[0] > 0.0); assert!(state.mean_vector[1] > 0.0); }
712
713 #[test]
714 fn test_displacement_operation() {
715 let mut state = GaussianState::vacuum_state(1);
716 let displacement = Complex::new(2.0, 1.0);
717
718 state
719 .apply_displacement(0, displacement)
720 .expect("Displacement operation should succeed");
721
722 assert!((state.mean_vector[0] - 2.0 * (2.0_f64).sqrt()).abs() < 1e-10);
723 assert!((state.mean_vector[1] - 1.0 * (2.0_f64).sqrt()).abs() < 1e-10);
724 }
725
726 #[test]
727 fn test_squeezing_operation() {
728 let mut state = GaussianState::vacuum_state(1);
729
730 state
731 .apply_squeezing(0, 1.0, 0.0)
732 .expect("Squeezing operation should succeed");
733
734 assert!(state.covariancematrix[0][0] < 0.5); assert!(state.covariancematrix[1][1] > 0.5); }
738
739 #[test]
740 fn test_beamsplitter_operation() {
741 let mut state =
742 GaussianState::coherent_state(2, vec![Complex::new(1.0, 0.0), Complex::new(0.0, 0.0)])
743 .expect("Coherent state creation should succeed");
744
745 let initial_energy = state.mean_vector[0].powi(2)
746 + state.mean_vector[1].powi(2)
747 + state.mean_vector[2].powi(2)
748 + state.mean_vector[3].powi(2);
749
750 state
751 .apply_beamsplitter(0, 1, 0.5, 0.0)
752 .expect("Beamsplitter operation should succeed");
753
754 let final_energy = state.mean_vector[0].powi(2)
755 + state.mean_vector[1].powi(2)
756 + state.mean_vector[2].powi(2)
757 + state.mean_vector[3].powi(2);
758
759 assert!((initial_energy - final_energy).abs() < 1e-10);
761 }
762
763 #[test]
764 fn test_mode_state_calculation() {
765 let state = GaussianState::squeezed_vacuum_state(1, vec![1.0], vec![0.0])
766 .expect("Squeezed vacuum state creation should succeed");
767
768 let mode_state = state
769 .get_mode_state(0)
770 .expect("Getting mode state should succeed");
771 assert!(mode_state.squeezing_parameter > 0.0);
772 assert!((mode_state.squeezing_phase).abs() < 1e-10);
773 }
774}