1use crate::error::{QuantumError, Result};
15use crate::gate::Gate;
16use crate::types::{Complex, MeasurementOutcome, QubitIndex};
17
18use rand::rngs::StdRng;
19use rand::{Rng, SeedableRng};
20use std::fmt;
21use std::ops::{Add, AddAssign, Mul, Neg, Sub};
22
23#[derive(Clone, Copy, PartialEq)]
34pub struct Complex32 {
35 pub re: f32,
37 pub im: f32,
39}
40
41impl Complex32 {
42 pub const ZERO: Self = Self { re: 0.0, im: 0.0 };
44
45 pub const ONE: Self = Self { re: 1.0, im: 0.0 };
47
48 pub const I: Self = Self { re: 0.0, im: 1.0 };
50
51 #[inline]
53 pub fn new(re: f32, im: f32) -> Self {
54 Self { re, im }
55 }
56
57 #[inline]
59 pub fn norm_sq(&self) -> f32 {
60 self.re * self.re + self.im * self.im
61 }
62
63 #[inline]
65 pub fn norm(&self) -> f32 {
66 self.norm_sq().sqrt()
67 }
68
69 #[inline]
71 pub fn conj(&self) -> Self {
72 Self {
73 re: self.re,
74 im: -self.im,
75 }
76 }
77
78 #[inline]
80 pub fn from_f64(c: &Complex) -> Self {
81 Self {
82 re: c.re as f32,
83 im: c.im as f32,
84 }
85 }
86
87 #[inline]
89 pub fn to_f64(&self) -> Complex {
90 Complex {
91 re: self.re as f64,
92 im: self.im as f64,
93 }
94 }
95}
96
97impl Add for Complex32 {
102 type Output = Self;
103 #[inline]
104 fn add(self, rhs: Self) -> Self {
105 Self {
106 re: self.re + rhs.re,
107 im: self.im + rhs.im,
108 }
109 }
110}
111
112impl Sub for Complex32 {
113 type Output = Self;
114 #[inline]
115 fn sub(self, rhs: Self) -> Self {
116 Self {
117 re: self.re - rhs.re,
118 im: self.im - rhs.im,
119 }
120 }
121}
122
123impl Mul for Complex32 {
124 type Output = Self;
125 #[inline]
126 fn mul(self, rhs: Self) -> Self {
127 Self {
128 re: self.re * rhs.re - self.im * rhs.im,
129 im: self.re * rhs.im + self.im * rhs.re,
130 }
131 }
132}
133
134impl Neg for Complex32 {
135 type Output = Self;
136 #[inline]
137 fn neg(self) -> Self {
138 Self {
139 re: -self.re,
140 im: -self.im,
141 }
142 }
143}
144
145impl AddAssign for Complex32 {
146 #[inline]
147 fn add_assign(&mut self, rhs: Self) {
148 self.re += rhs.re;
149 self.im += rhs.im;
150 }
151}
152
153impl Mul<f32> for Complex32 {
154 type Output = Self;
155 #[inline]
156 fn mul(self, rhs: f32) -> Self {
157 Self {
158 re: self.re * rhs,
159 im: self.im * rhs,
160 }
161 }
162}
163
164impl fmt::Debug for Complex32 {
165 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
166 write!(f, "({}, {})", self.re, self.im)
167 }
168}
169
170impl fmt::Display for Complex32 {
171 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
172 if self.im >= 0.0 {
173 write!(f, "{}+{}i", self.re, self.im)
174 } else {
175 write!(f, "{}{}i", self.re, self.im)
176 }
177 }
178}
179
180pub const MAX_QUBITS_F32: u32 = 33;
186
187pub struct QuantumStateF32 {
194 amplitudes: Vec<Complex32>,
195 num_qubits: u32,
196 rng: StdRng,
197 measurement_record: Vec<MeasurementOutcome>,
198 gate_count: u64,
200}
201
202impl QuantumStateF32 {
207 pub fn new(num_qubits: u32) -> Result<Self> {
209 if num_qubits == 0 {
210 return Err(QuantumError::CircuitError(
211 "cannot create quantum state with 0 qubits".into(),
212 ));
213 }
214 if num_qubits > MAX_QUBITS_F32 {
215 return Err(QuantumError::QubitLimitExceeded {
216 requested: num_qubits,
217 maximum: MAX_QUBITS_F32,
218 });
219 }
220 let n = 1usize << num_qubits;
221 let mut amplitudes = vec![Complex32::ZERO; n];
222 amplitudes[0] = Complex32::ONE;
223 Ok(Self {
224 amplitudes,
225 num_qubits,
226 rng: StdRng::from_entropy(),
227 measurement_record: Vec::new(),
228 gate_count: 0,
229 })
230 }
231
232 pub fn new_with_seed(num_qubits: u32, seed: u64) -> Result<Self> {
234 if num_qubits == 0 {
235 return Err(QuantumError::CircuitError(
236 "cannot create quantum state with 0 qubits".into(),
237 ));
238 }
239 if num_qubits > MAX_QUBITS_F32 {
240 return Err(QuantumError::QubitLimitExceeded {
241 requested: num_qubits,
242 maximum: MAX_QUBITS_F32,
243 });
244 }
245 let n = 1usize << num_qubits;
246 let mut amplitudes = vec![Complex32::ZERO; n];
247 amplitudes[0] = Complex32::ONE;
248 Ok(Self {
249 amplitudes,
250 num_qubits,
251 rng: StdRng::seed_from_u64(seed),
252 measurement_record: Vec::new(),
253 gate_count: 0,
254 })
255 }
256
257 pub fn from_f64(state: &crate::state::QuantumState) -> Self {
261 let amplitudes: Vec<Complex32> = state
262 .state_vector()
263 .iter()
264 .map(|c| Complex32::from_f64(c))
265 .collect();
266 Self {
267 num_qubits: state.num_qubits(),
268 amplitudes,
269 rng: StdRng::from_entropy(),
270 measurement_record: state.measurement_record().to_vec(),
271 gate_count: 0,
272 }
273 }
274
275 pub fn to_f64(&self) -> Result<crate::state::QuantumState> {
281 let amps: Vec<Complex> = self.amplitudes.iter().map(|c| c.to_f64()).collect();
282 crate::state::QuantumState::from_amplitudes(amps, self.num_qubits)
283 }
284
285 pub fn num_qubits(&self) -> u32 {
291 self.num_qubits
292 }
293
294 pub fn num_amplitudes(&self) -> usize {
296 self.amplitudes.len()
297 }
298
299 pub fn probabilities(&self) -> Vec<f64> {
304 self.amplitudes
305 .iter()
306 .map(|a| a.norm_sq() as f64)
307 .collect()
308 }
309
310 pub fn estimate_memory(num_qubits: u32) -> usize {
314 (1usize << num_qubits) * std::mem::size_of::<Complex32>()
315 }
316
317 pub fn measurement_record(&self) -> &[MeasurementOutcome] {
319 &self.measurement_record
320 }
321
322 pub fn precision_error_bound(&self) -> f64 {
329 (self.gate_count as f64) * (f32::EPSILON as f64)
330 }
331
332 pub fn apply_gate(&mut self, gate: &Gate) -> Result<Vec<MeasurementOutcome>> {
340 for &q in gate.qubits().iter() {
342 self.validate_qubit(q)?;
343 }
344
345 match gate {
346 Gate::Barrier => Ok(vec![]),
347
348 Gate::Measure(q) => {
349 let outcome = self.measure(*q)?;
350 Ok(vec![outcome])
351 }
352
353 Gate::Reset(q) => {
354 self.reset_qubit(*q)?;
355 Ok(vec![])
356 }
357
358 Gate::CNOT(q1, q2)
360 | Gate::CZ(q1, q2)
361 | Gate::SWAP(q1, q2)
362 | Gate::Rzz(q1, q2, _) => {
363 if q1 == q2 {
364 return Err(QuantumError::CircuitError(format!(
365 "two-qubit gate requires distinct qubits, got {} and {}",
366 q1, q2
367 )));
368 }
369 let matrix_f64 = gate.matrix_2q().unwrap();
370 let matrix = convert_matrix_2q(&matrix_f64);
371 self.apply_two_qubit_gate(*q1, *q2, &matrix);
372 self.gate_count += 1;
373 Ok(vec![])
374 }
375
376 other => {
378 if let Some(matrix_f64) = other.matrix_1q() {
379 let q = other.qubits()[0];
380 let matrix = convert_matrix_1q(&matrix_f64);
381 self.apply_single_qubit_gate(q, &matrix);
382 self.gate_count += 1;
383 Ok(vec![])
384 } else {
385 Err(QuantumError::CircuitError(format!(
386 "unsupported gate: {:?}",
387 other
388 )))
389 }
390 }
391 }
392 }
393
394 pub fn apply_single_qubit_gate(
403 &mut self,
404 qubit: QubitIndex,
405 matrix: &[[Complex32; 2]; 2],
406 ) {
407 let step = 1usize << qubit;
408 let n = self.amplitudes.len();
409
410 let mut block_start = 0;
411 while block_start < n {
412 for i in block_start..block_start + step {
413 let j = i + step;
414 let a = self.amplitudes[i]; let b = self.amplitudes[j]; self.amplitudes[i] = matrix[0][0] * a + matrix[0][1] * b;
417 self.amplitudes[j] = matrix[1][0] * a + matrix[1][1] * b;
418 }
419 block_start += step << 1;
420 }
421 }
422
423 pub fn apply_two_qubit_gate(
431 &mut self,
432 q1: QubitIndex,
433 q2: QubitIndex,
434 matrix: &[[Complex32; 4]; 4],
435 ) {
436 let q1_bit = 1usize << q1;
437 let q2_bit = 1usize << q2;
438 let n = self.amplitudes.len();
439
440 for base in 0..n {
441 if base & q1_bit != 0 || base & q2_bit != 0 {
444 continue;
445 }
446
447 let idxs = [
448 base, base | q2_bit, base | q1_bit, base | q1_bit | q2_bit, ];
453
454 let vals = [
455 self.amplitudes[idxs[0]],
456 self.amplitudes[idxs[1]],
457 self.amplitudes[idxs[2]],
458 self.amplitudes[idxs[3]],
459 ];
460
461 for r in 0..4 {
462 self.amplitudes[idxs[r]] = matrix[r][0] * vals[0]
463 + matrix[r][1] * vals[1]
464 + matrix[r][2] * vals[2]
465 + matrix[r][3] * vals[3];
466 }
467 }
468 }
469
470 pub fn measure(&mut self, qubit: QubitIndex) -> Result<MeasurementOutcome> {
484 self.validate_qubit(qubit)?;
485
486 let qubit_bit = 1usize << qubit;
487 let n = self.amplitudes.len();
488
489 let mut p0: f32 = 0.0;
491 for i in 0..n {
492 if i & qubit_bit == 0 {
493 p0 += self.amplitudes[i].norm_sq();
494 }
495 }
496
497 let random: f64 = self.rng.gen();
498 let result = random >= p0 as f64; let prob_f32 = if result { 1.0_f32 - p0 } else { p0 };
500
501 let norm_factor = if prob_f32 > 0.0 {
503 1.0_f32 / prob_f32.sqrt()
504 } else {
505 0.0_f32
506 };
507
508 for i in 0..n {
510 let bit_is_one = i & qubit_bit != 0;
511 if bit_is_one == result {
512 self.amplitudes[i] = self.amplitudes[i] * norm_factor;
513 } else {
514 self.amplitudes[i] = Complex32::ZERO;
515 }
516 }
517
518 let outcome = MeasurementOutcome {
519 qubit,
520 result,
521 probability: prob_f32 as f64,
522 };
523 self.measurement_record.push(outcome.clone());
524 Ok(outcome)
525 }
526
527 fn reset_qubit(&mut self, qubit: QubitIndex) -> Result<()> {
535 let outcome = self.measure(qubit)?;
536 if outcome.result {
537 let x_matrix_f64 = Gate::X(qubit).matrix_1q().unwrap();
539 let x_matrix = convert_matrix_1q(&x_matrix_f64);
540 self.apply_single_qubit_gate(qubit, &x_matrix);
541 }
542 Ok(())
543 }
544
545 fn validate_qubit(&self, qubit: QubitIndex) -> Result<()> {
551 if qubit >= self.num_qubits {
552 return Err(QuantumError::InvalidQubitIndex {
553 index: qubit,
554 num_qubits: self.num_qubits,
555 });
556 }
557 Ok(())
558 }
559}
560
561fn convert_matrix_1q(m: &[[Complex; 2]; 2]) -> [[Complex32; 2]; 2] {
567 [
568 [Complex32::from_f64(&m[0][0]), Complex32::from_f64(&m[0][1])],
569 [Complex32::from_f64(&m[1][0]), Complex32::from_f64(&m[1][1])],
570 ]
571}
572
573fn convert_matrix_2q(m: &[[Complex; 4]; 4]) -> [[Complex32; 4]; 4] {
575 [
576 [
577 Complex32::from_f64(&m[0][0]),
578 Complex32::from_f64(&m[0][1]),
579 Complex32::from_f64(&m[0][2]),
580 Complex32::from_f64(&m[0][3]),
581 ],
582 [
583 Complex32::from_f64(&m[1][0]),
584 Complex32::from_f64(&m[1][1]),
585 Complex32::from_f64(&m[1][2]),
586 Complex32::from_f64(&m[1][3]),
587 ],
588 [
589 Complex32::from_f64(&m[2][0]),
590 Complex32::from_f64(&m[2][1]),
591 Complex32::from_f64(&m[2][2]),
592 Complex32::from_f64(&m[2][3]),
593 ],
594 [
595 Complex32::from_f64(&m[3][0]),
596 Complex32::from_f64(&m[3][1]),
597 Complex32::from_f64(&m[3][2]),
598 Complex32::from_f64(&m[3][3]),
599 ],
600 ]
601}
602
603#[cfg(test)]
608mod tests {
609 use super::*;
610
611 const EPS: f32 = 1e-6;
612
613 fn approx_eq_f32(a: f32, b: f32) -> bool {
614 (a - b).abs() < EPS
615 }
616
617 #[test]
618 fn complex32_arithmetic() {
619 let a = Complex32::new(1.0, 2.0);
620 let b = Complex32::new(3.0, -1.0);
621
622 let sum = a + b;
623 assert!(approx_eq_f32(sum.re, 4.0));
624 assert!(approx_eq_f32(sum.im, 1.0));
625
626 let diff = a - b;
627 assert!(approx_eq_f32(diff.re, -2.0));
628 assert!(approx_eq_f32(diff.im, 3.0));
629
630 let prod = a * b;
632 assert!(approx_eq_f32(prod.re, 5.0));
633 assert!(approx_eq_f32(prod.im, 5.0));
634
635 let neg = -a;
636 assert!(approx_eq_f32(neg.re, -1.0));
637 assert!(approx_eq_f32(neg.im, -2.0));
638
639 assert!(approx_eq_f32(a.norm_sq(), 5.0));
640 assert!(approx_eq_f32(a.conj().im, -2.0));
641 }
642
643 #[test]
644 fn complex32_f64_conversion() {
645 let c64 = Complex::new(1.5, -2.5);
646 let c32 = Complex32::from_f64(&c64);
647 assert!(approx_eq_f32(c32.re, 1.5));
648 assert!(approx_eq_f32(c32.im, -2.5));
649
650 let back = c32.to_f64();
651 assert!((back.re - 1.5).abs() < 1e-6);
652 assert!((back.im - (-2.5)).abs() < 1e-6);
653 }
654
655 #[test]
656 fn state_f32_creation() {
657 let state = QuantumStateF32::new(3).unwrap();
658 assert_eq!(state.num_qubits(), 3);
659 assert_eq!(state.num_amplitudes(), 8);
660
661 let probs = state.probabilities();
662 assert!((probs[0] - 1.0).abs() < 1e-6);
663 for &p in &probs[1..] {
664 assert!(p.abs() < 1e-6);
665 }
666 }
667
668 #[test]
669 fn state_f32_zero_qubits_error() {
670 assert!(QuantumStateF32::new(0).is_err());
671 }
672
673 #[test]
674 fn state_f32_memory_estimate() {
675 assert_eq!(QuantumStateF32::estimate_memory(3), 64);
677 assert_eq!(QuantumStateF32::estimate_memory(10), 8192);
679 }
680
681 #[test]
682 fn state_f32_h_gate() {
683 let mut state = QuantumStateF32::new_with_seed(1, 42).unwrap();
684 state.apply_gate(&Gate::H(0)).unwrap();
685
686 let probs = state.probabilities();
687 assert!((probs[0] - 0.5).abs() < 1e-5);
688 assert!((probs[1] - 0.5).abs() < 1e-5);
689 }
690
691 #[test]
692 fn state_f32_bell_state() {
693 let mut state = QuantumStateF32::new_with_seed(2, 42).unwrap();
694 state.apply_gate(&Gate::H(0)).unwrap();
695 state.apply_gate(&Gate::CNOT(0, 1)).unwrap();
696
697 let probs = state.probabilities();
698 assert!((probs[0] - 0.5).abs() < 1e-5);
700 assert!(probs[1].abs() < 1e-5);
701 assert!(probs[2].abs() < 1e-5);
702 assert!((probs[3] - 0.5).abs() < 1e-5);
703 }
704
705 #[test]
706 fn state_f32_measurement() {
707 let mut state = QuantumStateF32::new_with_seed(1, 42).unwrap();
708 state.apply_gate(&Gate::X(0)).unwrap();
709
710 let outcome = state.measure(0).unwrap();
711 assert!(outcome.result); assert!((outcome.probability - 1.0).abs() < 1e-5);
713 assert_eq!(state.measurement_record().len(), 1);
714 }
715
716 #[test]
717 fn state_f32_from_f64_roundtrip() {
718 let f64_state = crate::state::QuantumState::new_with_seed(3, 99).unwrap();
719 let f32_state = QuantumStateF32::from_f64(&f64_state);
720 assert_eq!(f32_state.num_qubits(), 3);
721 assert_eq!(f32_state.num_amplitudes(), 8);
722
723 let back = f32_state.to_f64().unwrap();
725 let p_orig = f64_state.probabilities();
726 let p_back = back.probabilities();
727 for (a, b) in p_orig.iter().zip(p_back.iter()) {
728 assert!((a - b).abs() < 1e-6);
729 }
730 }
731
732 #[test]
733 fn state_f32_precision_error_bound() {
734 let mut state = QuantumStateF32::new_with_seed(2, 42).unwrap();
735 assert_eq!(state.precision_error_bound(), 0.0);
736
737 state.apply_gate(&Gate::H(0)).unwrap();
738 state.apply_gate(&Gate::CNOT(0, 1)).unwrap();
739 let bound = state.precision_error_bound();
741 assert!(bound > 0.0);
742 assert!(bound < 1e-5); }
744
745 #[test]
746 fn state_f32_invalid_qubit() {
747 let mut state = QuantumStateF32::new(2).unwrap();
748 assert!(state.apply_gate(&Gate::H(5)).is_err());
749 }
750
751 #[test]
752 fn state_f32_distinct_qubits_check() {
753 let mut state = QuantumStateF32::new(2).unwrap();
754 assert!(state.apply_gate(&Gate::CNOT(0, 0)).is_err());
755 }
756}