1use crate::error::{QuantRS2Error, QuantRS2Result};
8use scirs2_core::ndarray::Array2;
9use scirs2_core::Complex64;
10use std::collections::HashMap;
11use std::fmt;
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
15pub enum Pauli {
16 I,
17 X,
18 Y,
19 Z,
20}
21
22impl Pauli {
23 pub fn matrix(&self) -> Array2<Complex64> {
25 match self {
26 Pauli::I => Array2::from_shape_vec(
27 (2, 2),
28 vec![
29 Complex64::new(1.0, 0.0),
30 Complex64::new(0.0, 0.0),
31 Complex64::new(0.0, 0.0),
32 Complex64::new(1.0, 0.0),
33 ],
34 )
35 .unwrap(),
36 Pauli::X => Array2::from_shape_vec(
37 (2, 2),
38 vec![
39 Complex64::new(0.0, 0.0),
40 Complex64::new(1.0, 0.0),
41 Complex64::new(1.0, 0.0),
42 Complex64::new(0.0, 0.0),
43 ],
44 )
45 .unwrap(),
46 Pauli::Y => Array2::from_shape_vec(
47 (2, 2),
48 vec![
49 Complex64::new(0.0, 0.0),
50 Complex64::new(0.0, -1.0),
51 Complex64::new(0.0, 1.0),
52 Complex64::new(0.0, 0.0),
53 ],
54 )
55 .unwrap(),
56 Pauli::Z => Array2::from_shape_vec(
57 (2, 2),
58 vec![
59 Complex64::new(1.0, 0.0),
60 Complex64::new(0.0, 0.0),
61 Complex64::new(0.0, 0.0),
62 Complex64::new(-1.0, 0.0),
63 ],
64 )
65 .unwrap(),
66 }
67 }
68
69 pub fn multiply(&self, other: &Pauli) -> (Complex64, Pauli) {
71 use Pauli::*;
72 match (self, other) {
73 (I, p) | (p, I) => (Complex64::new(1.0, 0.0), *p),
74 (X, X) | (Y, Y) | (Z, Z) => (Complex64::new(1.0, 0.0), I),
75 (X, Y) => (Complex64::new(0.0, 1.0), Z),
76 (Y, X) => (Complex64::new(0.0, -1.0), Z),
77 (Y, Z) => (Complex64::new(0.0, 1.0), X),
78 (Z, Y) => (Complex64::new(0.0, -1.0), X),
79 (Z, X) => (Complex64::new(0.0, 1.0), Y),
80 (X, Z) => (Complex64::new(0.0, -1.0), Y),
81 }
82 }
83}
84
85#[derive(Debug, Clone, PartialEq)]
87pub struct PauliString {
88 pub phase: Complex64,
90 pub paulis: Vec<Pauli>,
92}
93
94impl PauliString {
95 pub fn new(paulis: Vec<Pauli>) -> Self {
97 Self {
98 phase: Complex64::new(1.0, 0.0),
99 paulis,
100 }
101 }
102
103 pub fn identity(n: usize) -> Self {
105 Self::new(vec![Pauli::I; n])
106 }
107
108 pub fn weight(&self) -> usize {
110 self.paulis.iter().filter(|&&p| p != Pauli::I).count()
111 }
112
113 pub fn multiply(&self, other: &PauliString) -> QuantRS2Result<PauliString> {
115 if self.paulis.len() != other.paulis.len() {
116 return Err(QuantRS2Error::InvalidInput(
117 "Pauli strings must have same length".to_string(),
118 ));
119 }
120
121 let mut phase = self.phase * other.phase;
122 let mut paulis = Vec::with_capacity(self.paulis.len());
123
124 for (p1, p2) in self.paulis.iter().zip(&other.paulis) {
125 let (factor, result) = p1.multiply(p2);
126 phase *= factor;
127 paulis.push(result);
128 }
129
130 Ok(PauliString { phase, paulis })
131 }
132
133 pub fn commutes_with(&self, other: &PauliString) -> QuantRS2Result<bool> {
135 if self.paulis.len() != other.paulis.len() {
136 return Err(QuantRS2Error::InvalidInput(
137 "Pauli strings must have same length".to_string(),
138 ));
139 }
140
141 let mut commutation_count = 0;
142 for (p1, p2) in self.paulis.iter().zip(&other.paulis) {
143 if *p1 != Pauli::I && *p2 != Pauli::I && p1 != p2 {
144 commutation_count += 1;
145 }
146 }
147
148 Ok(commutation_count % 2 == 0)
149 }
150}
151
152impl fmt::Display for PauliString {
153 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
154 let phase_str = if self.phase == Complex64::new(1.0, 0.0) {
155 "+".to_string()
156 } else if self.phase == Complex64::new(-1.0, 0.0) {
157 "-".to_string()
158 } else if self.phase == Complex64::new(0.0, 1.0) {
159 "+i".to_string()
160 } else {
161 "-i".to_string()
162 };
163
164 write!(f, "{}", phase_str)?;
165 for p in &self.paulis {
166 write!(f, "{:?}", p)?;
167 }
168 Ok(())
169 }
170}
171
172#[derive(Debug, Clone)]
174pub struct StabilizerCode {
175 pub n: usize,
177 pub k: usize,
179 pub d: usize,
181 pub stabilizers: Vec<PauliString>,
183 pub logical_x: Vec<PauliString>,
185 pub logical_z: Vec<PauliString>,
187}
188
189impl StabilizerCode {
190 pub fn new(
192 n: usize,
193 k: usize,
194 d: usize,
195 stabilizers: Vec<PauliString>,
196 logical_x: Vec<PauliString>,
197 logical_z: Vec<PauliString>,
198 ) -> QuantRS2Result<Self> {
199 if stabilizers.len() > 2 * (n - k) {
203 return Err(QuantRS2Error::InvalidInput(format!(
204 "Too many stabilizers: got {}, maximum is {}",
205 stabilizers.len(),
206 2 * (n - k)
207 )));
208 }
209
210 if logical_x.len() != k || logical_z.len() != k {
211 return Err(QuantRS2Error::InvalidInput(
212 "Number of logical operators must equal k".to_string(),
213 ));
214 }
215
216 for i in 0..stabilizers.len() {
218 for j in i + 1..stabilizers.len() {
219 if !stabilizers[i].commutes_with(&stabilizers[j])? {
220 return Err(QuantRS2Error::InvalidInput(
221 "Stabilizers must commute".to_string(),
222 ));
223 }
224 }
225 }
226
227 Ok(Self {
228 n,
229 k,
230 d,
231 stabilizers,
232 logical_x,
233 logical_z,
234 })
235 }
236
237 pub fn repetition_code() -> Self {
239 let stabilizers = vec![
240 PauliString::new(vec![Pauli::Z, Pauli::Z, Pauli::I]),
241 PauliString::new(vec![Pauli::I, Pauli::Z, Pauli::Z]),
242 ];
243
244 let logical_x = vec![PauliString::new(vec![Pauli::X, Pauli::X, Pauli::X])];
245 let logical_z = vec![PauliString::new(vec![Pauli::Z, Pauli::I, Pauli::I])];
246
247 Self::new(3, 1, 1, stabilizers, logical_x, logical_z).unwrap()
248 }
249
250 pub fn five_qubit_code() -> Self {
252 let stabilizers = vec![
253 PauliString::new(vec![Pauli::X, Pauli::Z, Pauli::Z, Pauli::X, Pauli::I]),
254 PauliString::new(vec![Pauli::I, Pauli::X, Pauli::Z, Pauli::Z, Pauli::X]),
255 PauliString::new(vec![Pauli::X, Pauli::I, Pauli::X, Pauli::Z, Pauli::Z]),
256 PauliString::new(vec![Pauli::Z, Pauli::X, Pauli::I, Pauli::X, Pauli::Z]),
257 ];
258
259 let logical_x = vec![PauliString::new(vec![
260 Pauli::X,
261 Pauli::X,
262 Pauli::X,
263 Pauli::X,
264 Pauli::X,
265 ])];
266 let logical_z = vec![PauliString::new(vec![
267 Pauli::Z,
268 Pauli::Z,
269 Pauli::Z,
270 Pauli::Z,
271 Pauli::Z,
272 ])];
273
274 Self::new(5, 1, 3, stabilizers, logical_x, logical_z).unwrap()
275 }
276
277 pub fn steane_code() -> Self {
279 let stabilizers = vec![
280 PauliString::new(vec![
281 Pauli::I,
282 Pauli::I,
283 Pauli::I,
284 Pauli::X,
285 Pauli::X,
286 Pauli::X,
287 Pauli::X,
288 ]),
289 PauliString::new(vec![
290 Pauli::I,
291 Pauli::X,
292 Pauli::X,
293 Pauli::I,
294 Pauli::I,
295 Pauli::X,
296 Pauli::X,
297 ]),
298 PauliString::new(vec![
299 Pauli::X,
300 Pauli::I,
301 Pauli::X,
302 Pauli::I,
303 Pauli::X,
304 Pauli::I,
305 Pauli::X,
306 ]),
307 PauliString::new(vec![
308 Pauli::I,
309 Pauli::I,
310 Pauli::I,
311 Pauli::Z,
312 Pauli::Z,
313 Pauli::Z,
314 Pauli::Z,
315 ]),
316 PauliString::new(vec![
317 Pauli::I,
318 Pauli::Z,
319 Pauli::Z,
320 Pauli::I,
321 Pauli::I,
322 Pauli::Z,
323 Pauli::Z,
324 ]),
325 PauliString::new(vec![
326 Pauli::Z,
327 Pauli::I,
328 Pauli::Z,
329 Pauli::I,
330 Pauli::Z,
331 Pauli::I,
332 Pauli::Z,
333 ]),
334 ];
335
336 let logical_x = vec![PauliString::new(vec![
337 Pauli::X,
338 Pauli::X,
339 Pauli::X,
340 Pauli::X,
341 Pauli::X,
342 Pauli::X,
343 Pauli::X,
344 ])];
345 let logical_z = vec![PauliString::new(vec![
346 Pauli::Z,
347 Pauli::Z,
348 Pauli::Z,
349 Pauli::Z,
350 Pauli::Z,
351 Pauli::Z,
352 Pauli::Z,
353 ])];
354
355 Self::new(7, 1, 3, stabilizers, logical_x, logical_z).unwrap()
356 }
357
358 pub fn syndrome(&self, error: &PauliString) -> QuantRS2Result<Vec<bool>> {
360 if error.paulis.len() != self.n {
361 return Err(QuantRS2Error::InvalidInput(
362 "Error must act on all physical qubits".to_string(),
363 ));
364 }
365
366 let mut syndrome = Vec::with_capacity(self.stabilizers.len());
367 for stabilizer in &self.stabilizers {
368 syndrome.push(!stabilizer.commutes_with(error)?);
369 }
370
371 Ok(syndrome)
372 }
373}
374
375#[derive(Debug, Clone)]
377pub struct SurfaceCode {
378 pub rows: usize,
380 pub cols: usize,
382 pub qubit_map: HashMap<(usize, usize), usize>,
384 pub x_stabilizers: Vec<Vec<usize>>,
386 pub z_stabilizers: Vec<Vec<usize>>,
387}
388
389impl SurfaceCode {
390 pub fn new(rows: usize, cols: usize) -> Self {
392 let mut qubit_map = HashMap::new();
393 let mut qubit_index = 0;
394
395 for r in 0..rows {
397 for c in 0..cols {
398 qubit_map.insert((r, c), qubit_index);
399 qubit_index += 1;
400 }
401 }
402
403 let mut x_stabilizers = Vec::new();
404 let mut z_stabilizers = Vec::new();
405
406 for r in 0..rows - 1 {
408 for c in 0..cols - 1 {
409 if (r + c) % 2 == 0 {
410 let stabilizer = vec![
411 qubit_map[&(r, c)],
412 qubit_map[&(r, c + 1)],
413 qubit_map[&(r + 1, c)],
414 qubit_map[&(r + 1, c + 1)],
415 ];
416 x_stabilizers.push(stabilizer);
417 }
418 }
419 }
420
421 for r in 0..rows - 1 {
423 for c in 0..cols - 1 {
424 if (r + c) % 2 == 1 {
425 let stabilizer = vec![
426 qubit_map[&(r, c)],
427 qubit_map[&(r, c + 1)],
428 qubit_map[&(r + 1, c)],
429 qubit_map[&(r + 1, c + 1)],
430 ];
431 z_stabilizers.push(stabilizer);
432 }
433 }
434 }
435
436 Self {
437 rows,
438 cols,
439 qubit_map,
440 x_stabilizers,
441 z_stabilizers,
442 }
443 }
444
445 pub fn distance(&self) -> usize {
447 self.rows.min(self.cols)
448 }
449
450 pub fn to_stabilizer_code(&self) -> StabilizerCode {
452 let n = self.qubit_map.len();
453 let mut stabilizers = Vec::new();
454
455 for x_stab in &self.x_stabilizers {
457 let mut paulis = vec![Pauli::I; n];
458 for &qubit in x_stab {
459 paulis[qubit] = Pauli::X;
460 }
461 stabilizers.push(PauliString::new(paulis));
462 }
463
464 for z_stab in &self.z_stabilizers {
466 let mut paulis = vec![Pauli::I; n];
467 for &qubit in z_stab {
468 paulis[qubit] = Pauli::Z;
469 }
470 stabilizers.push(PauliString::new(paulis));
471 }
472
473 let mut logical_x_paulis = vec![Pauli::I; n];
475 let mut logical_z_paulis = vec![Pauli::I; n];
476
477 for c in 0..self.cols {
479 if let Some(&qubit) = self.qubit_map.get(&(0, c)) {
480 logical_x_paulis[qubit] = Pauli::X;
481 }
482 }
483
484 for r in 0..self.rows {
486 if let Some(&qubit) = self.qubit_map.get(&(r, 0)) {
487 logical_z_paulis[qubit] = Pauli::Z;
488 }
489 }
490
491 let logical_x = vec![PauliString::new(logical_x_paulis)];
492 let logical_z = vec![PauliString::new(logical_z_paulis)];
493
494 StabilizerCode::new(n, 1, self.distance(), stabilizers, logical_x, logical_z).unwrap()
495 }
496}
497
498pub trait SyndromeDecoder {
500 fn decode(&self, syndrome: &[bool]) -> QuantRS2Result<PauliString>;
502}
503
504pub struct LookupDecoder {
506 syndrome_table: HashMap<Vec<bool>, PauliString>,
508}
509
510impl LookupDecoder {
511 pub fn new(code: &StabilizerCode) -> QuantRS2Result<Self> {
513 let mut syndrome_table = HashMap::new();
514
515 let max_weight = (code.d - 1) / 2;
517 let all_errors = Self::generate_pauli_errors(code.n, max_weight);
518
519 for error in all_errors {
520 let syndrome = code.syndrome(&error)?;
521
522 syndrome_table
524 .entry(syndrome)
525 .and_modify(|e: &mut PauliString| {
526 if error.weight() < e.weight() {
527 *e = error.clone();
528 }
529 })
530 .or_insert(error);
531 }
532
533 Ok(Self { syndrome_table })
534 }
535
536 fn generate_pauli_errors(n: usize, max_weight: usize) -> Vec<PauliString> {
538 let mut errors = vec![PauliString::identity(n)];
539
540 for weight in 1..=max_weight {
541 let weight_errors = Self::generate_weight_k_errors(n, weight);
542 errors.extend(weight_errors);
543 }
544
545 errors
546 }
547
548 fn generate_weight_k_errors(n: usize, k: usize) -> Vec<PauliString> {
550 let mut errors = Vec::new();
551 let paulis = [Pauli::X, Pauli::Y, Pauli::Z];
552
553 let positions = Self::combinations(n, k);
555
556 for pos_set in positions {
557 let pauli_combinations = Self::cartesian_power(&paulis, k);
559
560 for pauli_combo in pauli_combinations {
561 let mut error_paulis = vec![Pauli::I; n];
562 for (i, &pos) in pos_set.iter().enumerate() {
563 error_paulis[pos] = pauli_combo[i];
564 }
565 errors.push(PauliString::new(error_paulis));
566 }
567 }
568
569 errors
570 }
571
572 fn combinations(n: usize, k: usize) -> Vec<Vec<usize>> {
574 let mut result = Vec::new();
575 let mut combo = (0..k).collect::<Vec<_>>();
576
577 loop {
578 result.push(combo.clone());
579
580 let mut i = k;
582 while i > 0 && (i == k || combo[i] == n - k + i) {
583 i -= 1;
584 }
585
586 if i == 0 && combo[0] == n - k {
587 break;
588 }
589
590 combo[i] += 1;
592 for j in i + 1..k {
593 combo[j] = combo[j - 1] + 1;
594 }
595 }
596
597 result
598 }
599
600 fn cartesian_power<T: Clone>(set: &[T], k: usize) -> Vec<Vec<T>> {
602 if k == 0 {
603 return vec![vec![]];
604 }
605
606 let mut result = Vec::new();
607 let smaller = Self::cartesian_power(set, k - 1);
608
609 for item in set {
610 for mut combo in smaller.clone() {
611 combo.push(item.clone());
612 result.push(combo);
613 }
614 }
615
616 result
617 }
618}
619
620impl SyndromeDecoder for LookupDecoder {
621 fn decode(&self, syndrome: &[bool]) -> QuantRS2Result<PauliString> {
622 self.syndrome_table
623 .get(syndrome)
624 .cloned()
625 .ok_or_else(|| QuantRS2Error::InvalidInput("Unknown syndrome".to_string()))
626 }
627}
628
629pub struct MWPMDecoder {
631 surface_code: SurfaceCode,
632}
633
634impl MWPMDecoder {
635 pub fn new(surface_code: SurfaceCode) -> Self {
637 Self { surface_code }
638 }
639
640 pub fn decode_syndrome(
642 &self,
643 x_syndrome: &[bool],
644 z_syndrome: &[bool],
645 ) -> QuantRS2Result<PauliString> {
646 let n = self.surface_code.qubit_map.len();
647 let mut error_paulis = vec![Pauli::I; n];
648
649 let z_defects = self.find_defects(z_syndrome, &self.surface_code.z_stabilizers);
651 let x_corrections = self.minimum_weight_matching(&z_defects, Pauli::X)?;
652
653 for (qubit, pauli) in x_corrections {
654 error_paulis[qubit] = pauli;
655 }
656
657 let x_defects = self.find_defects(x_syndrome, &self.surface_code.x_stabilizers);
659 let z_corrections = self.minimum_weight_matching(&x_defects, Pauli::Z)?;
660
661 for (qubit, pauli) in z_corrections {
662 if error_paulis[qubit] != Pauli::I {
663 error_paulis[qubit] = Pauli::Y;
665 } else {
666 error_paulis[qubit] = pauli;
667 }
668 }
669
670 Ok(PauliString::new(error_paulis))
671 }
672
673 fn find_defects(&self, syndrome: &[bool], _stabilizers: &[Vec<usize>]) -> Vec<usize> {
675 syndrome
676 .iter()
677 .enumerate()
678 .filter_map(|(i, &s)| if s { Some(i) } else { None })
679 .collect()
680 }
681
682 fn minimum_weight_matching(
684 &self,
685 defects: &[usize],
686 error_type: Pauli,
687 ) -> QuantRS2Result<Vec<(usize, Pauli)>> {
688 let mut corrections = Vec::new();
690
691 if defects.len() % 2 != 0 {
692 return Err(QuantRS2Error::InvalidInput(
693 "Odd number of defects".to_string(),
694 ));
695 }
696
697 let mut paired = vec![false; defects.len()];
699
700 for i in 0..defects.len() {
701 if paired[i] {
702 continue;
703 }
704
705 let mut min_dist = usize::MAX;
707 let mut min_j = i;
708
709 for j in i + 1..defects.len() {
710 if !paired[j] {
711 let dist = self.defect_distance(defects[i], defects[j]);
712 if dist < min_dist {
713 min_dist = dist;
714 min_j = j;
715 }
716 }
717 }
718
719 if min_j != i {
720 paired[i] = true;
721 paired[min_j] = true;
722
723 let path = self.shortest_path(defects[i], defects[min_j])?;
725 for qubit in path {
726 corrections.push((qubit, error_type));
727 }
728 }
729 }
730
731 Ok(corrections)
732 }
733
734 fn defect_distance(&self, defect1: usize, defect2: usize) -> usize {
736 (defect1 as isize - defect2 as isize).unsigned_abs()
738 }
739
740 fn shortest_path(&self, start: usize, end: usize) -> QuantRS2Result<Vec<usize>> {
742 let path = if start < end {
744 (start..=end).collect()
745 } else {
746 (end..=start).rev().collect()
747 };
748
749 Ok(path)
750 }
751}
752
753#[derive(Debug, Clone)]
755pub struct ColorCode {
756 pub n: usize,
758 pub faces: Vec<(Vec<usize>, Color)>,
760 pub vertex_map: HashMap<(i32, i32), usize>,
762}
763
764#[derive(Debug, Clone, Copy, PartialEq, Eq)]
765pub enum Color {
766 Red,
767 Green,
768 Blue,
769}
770
771impl ColorCode {
772 pub fn triangular(size: usize) -> Self {
774 let mut vertex_map = HashMap::new();
775 let mut qubit_index = 0;
776
777 for i in 0..size as i32 {
779 for j in 0..size as i32 {
780 vertex_map.insert((i, j), qubit_index);
781 qubit_index += 1;
782 }
783 }
784
785 let mut faces = Vec::new();
786
787 for i in 0..size as i32 - 1 {
789 for j in 0..size as i32 - 1 {
790 if let (Some(&q1), Some(&q2), Some(&q3)) = (
792 vertex_map.get(&(i, j)),
793 vertex_map.get(&(i + 1, j)),
794 vertex_map.get(&(i, j + 1)),
795 ) {
796 faces.push((vec![q1, q2, q3], Color::Red));
797 }
798
799 if let (Some(&q1), Some(&q2), Some(&q3)) = (
801 vertex_map.get(&(i + 1, j)),
802 vertex_map.get(&(i + 1, j + 1)),
803 vertex_map.get(&(i, j + 1)),
804 ) {
805 faces.push((vec![q1, q2, q3], Color::Green));
806 }
807 }
808 }
809
810 Self {
811 n: vertex_map.len(),
812 faces,
813 vertex_map,
814 }
815 }
816
817 pub fn to_stabilizer_code(&self) -> StabilizerCode {
819 let mut x_stabilizers = Vec::new();
820 let mut z_stabilizers = Vec::new();
821
822 for (qubits, _color) in &self.faces {
823 let mut x_paulis = vec![Pauli::I; self.n];
825 for &q in qubits {
826 x_paulis[q] = Pauli::X;
827 }
828 x_stabilizers.push(PauliString::new(x_paulis));
829
830 let mut z_paulis = vec![Pauli::I; self.n];
832 for &q in qubits {
833 z_paulis[q] = Pauli::Z;
834 }
835 z_stabilizers.push(PauliString::new(z_paulis));
836 }
837
838 let mut stabilizers = x_stabilizers;
839 stabilizers.extend(z_stabilizers);
840
841 let logical_x = vec![PauliString::new(vec![Pauli::X; self.n])];
843 let logical_z = vec![PauliString::new(vec![Pauli::Z; self.n])];
844
845 StabilizerCode::new(
846 self.n,
847 1,
848 3, stabilizers,
850 logical_x,
851 logical_z,
852 )
853 .unwrap()
854 }
855}
856
857#[derive(Debug, Clone)]
859pub struct ConcatenatedCode {
860 pub inner_code: StabilizerCode,
862 pub outer_code: StabilizerCode,
864}
865
866impl ConcatenatedCode {
867 pub fn new(inner_code: StabilizerCode, outer_code: StabilizerCode) -> Self {
869 Self {
870 inner_code,
871 outer_code,
872 }
873 }
874
875 pub fn total_qubits(&self) -> usize {
877 self.inner_code.n * self.outer_code.n
878 }
879
880 pub fn logical_qubits(&self) -> usize {
882 self.inner_code.k * self.outer_code.k
883 }
884
885 pub fn distance(&self) -> usize {
887 self.inner_code.d * self.outer_code.d
888 }
889
890 pub fn encode(&self, logical_state: &[Complex64]) -> QuantRS2Result<Vec<Complex64>> {
892 if logical_state.len() != 1 << self.logical_qubits() {
893 return Err(QuantRS2Error::InvalidInput(
894 "Logical state dimension mismatch".to_string(),
895 ));
896 }
897
898 let outer_encoded = self.encode_with_code(logical_state, &self.outer_code)?;
900
901 let mut final_encoded = vec![Complex64::new(0.0, 0.0); 1 << self.total_qubits()];
903
904 for (i, &litude) in outer_encoded.iter().enumerate() {
907 if amplitude.norm() > 1e-10 {
908 final_encoded[i * (1 << self.inner_code.n)] = amplitude;
909 }
910 }
911
912 Ok(final_encoded)
913 }
914
915 pub fn correct_error(
917 &self,
918 encoded_state: &[Complex64],
919 error: &PauliString,
920 ) -> QuantRS2Result<Vec<Complex64>> {
921 if error.paulis.len() != self.total_qubits() {
922 return Err(QuantRS2Error::InvalidInput(
923 "Error must act on all physical qubits".to_string(),
924 ));
925 }
926
927 let mut corrected = encoded_state.to_vec();
930
931 for (i, &pauli) in error.paulis.iter().enumerate() {
933 if pauli != Pauli::I && i < corrected.len() {
934 corrected[i] *= -1.0;
936 }
937 }
938
939 Ok(corrected)
940 }
941
942 fn encode_with_code(
944 &self,
945 state: &[Complex64],
946 code: &StabilizerCode,
947 ) -> QuantRS2Result<Vec<Complex64>> {
948 let mut encoded = vec![Complex64::new(0.0, 0.0); 1 << code.n];
950
951 for (i, &litude) in state.iter().enumerate() {
952 if i < encoded.len() {
953 encoded[i * (1 << (code.n - code.k))] = amplitude;
954 }
955 }
956
957 Ok(encoded)
958 }
959}
960
961#[derive(Debug, Clone)]
963pub struct HypergraphProductCode {
964 pub n: usize,
966 pub k: usize,
968 pub x_stabilizers: Vec<PauliString>,
970 pub z_stabilizers: Vec<PauliString>,
972}
973
974impl HypergraphProductCode {
975 pub fn new(h1: Array2<u8>, h2: Array2<u8>) -> Self {
977 let (m1, n1) = h1.dim();
978 let (m2, n2) = h2.dim();
979
980 let n = n1 * m2 + m1 * n2;
981 let k = (n1 - m1) * (n2 - m2);
982
983 let mut x_stabilizers = Vec::new();
984 let mut z_stabilizers = Vec::new();
985
986 for i in 0..m1 {
988 for j in 0..m2 {
989 let mut paulis = vec![Pauli::I; n];
990
991 for l in 0..n1 {
993 if h1[[i, l]] == 1 {
994 paulis[l * m2 + j] = Pauli::X;
995 }
996 }
997
998 x_stabilizers.push(PauliString::new(paulis));
999 }
1000 }
1001
1002 for i in 0..m1 {
1004 for j in 0..m2 {
1005 let mut paulis = vec![Pauli::I; n];
1006
1007 for l in 0..n2 {
1009 if h2[[j, l]] == 1 {
1010 paulis[n1 * m2 + i * n2 + l] = Pauli::Z;
1011 }
1012 }
1013
1014 z_stabilizers.push(PauliString::new(paulis));
1015 }
1016 }
1017
1018 Self {
1019 n,
1020 k,
1021 x_stabilizers,
1022 z_stabilizers,
1023 }
1024 }
1025
1026 pub fn to_stabilizer_code(&self) -> StabilizerCode {
1028 let mut stabilizers = self.x_stabilizers.clone();
1029 stabilizers.extend(self.z_stabilizers.clone());
1030
1031 let logical_x = vec![PauliString::new(vec![Pauli::X; self.n])];
1033 let logical_z = vec![PauliString::new(vec![Pauli::Z; self.n])];
1034
1035 StabilizerCode::new(
1036 self.n,
1037 self.k,
1038 3, stabilizers,
1040 logical_x,
1041 logical_z,
1042 )
1043 .unwrap()
1044 }
1045}
1046
1047#[derive(Debug, Clone)]
1049pub struct QuantumLDPCCode {
1050 pub n: usize,
1052 pub k: usize,
1054 pub max_weight: usize,
1056 pub x_stabilizers: Vec<PauliString>,
1058 pub z_stabilizers: Vec<PauliString>,
1060}
1061
1062impl QuantumLDPCCode {
1063 pub fn bicycle_code(a: usize, b: usize) -> Self {
1065 let n = 2 * a * b;
1066 let k = 2;
1067 let max_weight = 6; let mut x_stabilizers = Vec::new();
1070 let mut z_stabilizers = Vec::new();
1071
1072 for i in 0..a {
1074 for j in 0..b {
1075 let mut x_paulis = vec![Pauli::I; n];
1077 let base_idx = i * b + j;
1078
1079 x_paulis[base_idx] = Pauli::X;
1081 x_paulis[(base_idx + 1) % (a * b)] = Pauli::X;
1082 x_paulis[(base_idx + b) % (a * b)] = Pauli::X;
1083 x_paulis[a * b + base_idx] = Pauli::X;
1084 x_paulis[a * b + (base_idx + 1) % (a * b)] = Pauli::X;
1085 x_paulis[a * b + (base_idx + b) % (a * b)] = Pauli::X;
1086
1087 x_stabilizers.push(PauliString::new(x_paulis));
1088
1089 let mut z_paulis = vec![Pauli::I; n];
1091 z_paulis[base_idx] = Pauli::Z;
1092 z_paulis[(base_idx + a) % (a * b)] = Pauli::Z;
1093 z_paulis[(base_idx + 1) % (a * b)] = Pauli::Z;
1094 z_paulis[a * b + base_idx] = Pauli::Z;
1095 z_paulis[a * b + (base_idx + a) % (a * b)] = Pauli::Z;
1096 z_paulis[a * b + (base_idx + 1) % (a * b)] = Pauli::Z;
1097
1098 z_stabilizers.push(PauliString::new(z_paulis));
1099 }
1100 }
1101
1102 Self {
1103 n,
1104 k,
1105 max_weight,
1106 x_stabilizers,
1107 z_stabilizers,
1108 }
1109 }
1110
1111 pub fn to_stabilizer_code(&self) -> StabilizerCode {
1113 let mut stabilizers = self.x_stabilizers.clone();
1114 stabilizers.extend(self.z_stabilizers.clone());
1115
1116 let logical_x = vec![
1118 PauliString::new(vec![Pauli::X; self.n]),
1119 PauliString::new(vec![Pauli::Y; self.n]),
1120 ];
1121 let logical_z = vec![
1122 PauliString::new(vec![Pauli::Z; self.n]),
1123 PauliString::new(vec![Pauli::Y; self.n]),
1124 ];
1125
1126 StabilizerCode::new(
1127 self.n,
1128 self.k,
1129 4, stabilizers,
1131 logical_x,
1132 logical_z,
1133 )
1134 .unwrap()
1135 }
1136}
1137
1138#[derive(Debug, Clone)]
1140pub struct ToricCode {
1141 pub rows: usize,
1143 pub cols: usize,
1145 pub qubit_map: HashMap<(usize, usize), usize>,
1147}
1148
1149impl ToricCode {
1150 pub fn new(rows: usize, cols: usize) -> Self {
1152 let mut qubit_map = HashMap::new();
1153 let mut qubit_index = 0;
1154
1155 for r in 0..rows {
1157 for c in 0..cols {
1158 qubit_map.insert((2 * r, c), qubit_index);
1160 qubit_index += 1;
1161 qubit_map.insert((2 * r + 1, c), qubit_index);
1163 qubit_index += 1;
1164 }
1165 }
1166
1167 Self {
1168 rows,
1169 cols,
1170 qubit_map,
1171 }
1172 }
1173
1174 pub fn logical_qubits(&self) -> usize {
1176 2 }
1178
1179 pub fn distance(&self) -> usize {
1181 self.rows.min(self.cols)
1182 }
1183
1184 pub fn to_stabilizer_code(&self) -> StabilizerCode {
1186 let n = self.qubit_map.len();
1187 let mut stabilizers = Vec::new();
1188
1189 for r in 0..self.rows {
1191 for c in 0..self.cols {
1192 let mut paulis = vec![Pauli::I; n];
1193
1194 let h_edge_below = (2 * r, c);
1196 let h_edge_above = (2 * ((r + self.rows - 1) % self.rows), c);
1197 let v_edge_left = (2 * r + 1, (c + self.cols - 1) % self.cols);
1198 let v_edge_right = (2 * r + 1, c);
1199
1200 for &coord in &[h_edge_below, h_edge_above, v_edge_left, v_edge_right] {
1201 if let Some(&qubit) = self.qubit_map.get(&coord) {
1202 paulis[qubit] = Pauli::X;
1203 }
1204 }
1205
1206 stabilizers.push(PauliString::new(paulis));
1207 }
1208 }
1209
1210 for r in 0..self.rows {
1212 for c in 0..self.cols {
1213 let mut paulis = vec![Pauli::I; n];
1214
1215 let h_edge_top = (2 * r, c);
1217 let h_edge_bottom = (2 * ((r + 1) % self.rows), c);
1218 let v_edge_left = (2 * r + 1, c);
1219 let v_edge_right = (2 * r + 1, (c + 1) % self.cols);
1220
1221 for &coord in &[h_edge_top, h_edge_bottom, v_edge_left, v_edge_right] {
1222 if let Some(&qubit) = self.qubit_map.get(&coord) {
1223 paulis[qubit] = Pauli::Z;
1224 }
1225 }
1226
1227 stabilizers.push(PauliString::new(paulis));
1228 }
1229 }
1230
1231 let mut logical_x1 = vec![Pauli::I; n];
1233 let mut logical_z1 = vec![Pauli::I; n];
1234 let mut logical_x2 = vec![Pauli::I; n];
1235 let mut logical_z2 = vec![Pauli::I; n];
1236
1237 for c in 0..self.cols {
1239 if let Some(&qubit) = self.qubit_map.get(&(1, c)) {
1241 logical_x1[qubit] = Pauli::X;
1242 }
1243 if let Some(&qubit) = self.qubit_map.get(&(0, c)) {
1245 logical_z2[qubit] = Pauli::Z;
1246 }
1247 }
1248
1249 for r in 0..self.rows {
1251 if let Some(&qubit) = self.qubit_map.get(&(2 * r, 0)) {
1253 logical_x2[qubit] = Pauli::X;
1254 }
1255 if let Some(&qubit) = self.qubit_map.get(&(2 * r + 1, 0)) {
1257 logical_z1[qubit] = Pauli::Z;
1258 }
1259 }
1260
1261 let logical_x = vec![PauliString::new(logical_x1), PauliString::new(logical_x2)];
1262 let logical_z = vec![PauliString::new(logical_z1), PauliString::new(logical_z2)];
1263
1264 StabilizerCode::new(n, 2, self.distance(), stabilizers, logical_x, logical_z).unwrap()
1265 }
1266}
1267
1268pub struct MLDecoder {
1270 code: StabilizerCode,
1272 weights: Vec<Vec<f64>>,
1274}
1275
1276impl MLDecoder {
1277 pub fn new(code: StabilizerCode) -> Self {
1279 let input_size = code.stabilizers.len();
1281 let hidden_size = 2 * input_size;
1282 let output_size = code.n * 3; use scirs2_core::random::prelude::*;
1285 let mut rng = thread_rng();
1286 let mut weights = Vec::new();
1287
1288 let mut w1 = Vec::new();
1290 for _ in 0..hidden_size {
1291 let mut row = Vec::new();
1292 for _ in 0..input_size {
1293 row.push((rng.gen::<f64>() - 0.5) * 0.1);
1294 }
1295 w1.push(row);
1296 }
1297 weights.push(w1.into_iter().flatten().collect());
1298
1299 let mut w2 = Vec::new();
1301 for _ in 0..output_size {
1302 let mut row = Vec::new();
1303 for _ in 0..hidden_size {
1304 row.push((rng.gen::<f64>() - 0.5) * 0.1);
1305 }
1306 w2.push(row);
1307 }
1308 weights.push(w2.into_iter().flatten().collect());
1309
1310 Self { code, weights }
1311 }
1312
1313 fn predict(&self, syndrome: &[bool]) -> Vec<f64> {
1315 let input: Vec<f64> = syndrome
1316 .iter()
1317 .map(|&b| if b { 1.0 } else { 0.0 })
1318 .collect();
1319
1320 let hidden_size = 2 * input.len();
1323 let mut hidden = vec![0.0; hidden_size];
1324
1325 for i in 0..hidden_size {
1327 for j in 0..input.len() {
1328 if i * input.len() + j < self.weights[0].len() {
1329 hidden[i] += input[j] * self.weights[0][i * input.len() + j];
1330 }
1331 }
1332 hidden[i] = hidden[i].tanh(); }
1334
1335 let output_size = self.code.n * 3;
1337 let mut output = vec![0.0; output_size];
1338
1339 for i in 0..output_size {
1340 for j in 0..hidden_size {
1341 if i * hidden_size + j < self.weights[1].len() {
1342 output[i] += hidden[j] * self.weights[1][i * hidden_size + j];
1343 }
1344 }
1345 }
1346
1347 output
1348 }
1349}
1350
1351impl SyndromeDecoder for MLDecoder {
1352 fn decode(&self, syndrome: &[bool]) -> QuantRS2Result<PauliString> {
1353 let prediction = self.predict(syndrome);
1354
1355 let mut paulis = Vec::with_capacity(self.code.n);
1357
1358 for qubit in 0..self.code.n {
1359 let base_idx = qubit * 3;
1360 if base_idx + 2 < prediction.len() {
1361 let x_prob = prediction[base_idx];
1362 let y_prob = prediction[base_idx + 1];
1363 let z_prob = prediction[base_idx + 2];
1364
1365 if x_prob > y_prob && x_prob > z_prob && x_prob > 0.5 {
1367 paulis.push(Pauli::X);
1368 } else if y_prob > z_prob && y_prob > 0.5 {
1369 paulis.push(Pauli::Y);
1370 } else if z_prob > 0.5 {
1371 paulis.push(Pauli::Z);
1372 } else {
1373 paulis.push(Pauli::I);
1374 }
1375 } else {
1376 paulis.push(Pauli::I);
1377 }
1378 }
1379
1380 Ok(PauliString::new(paulis))
1381 }
1382}
1383
1384pub mod real_time {
1388 use super::*;
1389 use std::collections::VecDeque;
1390 use std::sync::{Arc, Mutex, RwLock};
1391 use std::thread;
1392 use std::time::{Duration, Instant};
1393
1394 pub trait QuantumHardwareInterface: Send + Sync {
1396 fn measure_syndromes(&self) -> QuantRS2Result<Vec<bool>>;
1398
1399 fn apply_correction(&self, correction: &PauliString) -> QuantRS2Result<()>;
1401
1402 fn get_error_characteristics(&self) -> QuantRS2Result<HardwareErrorCharacteristics>;
1404
1405 fn is_ready(&self) -> bool;
1407
1408 fn get_latency_stats(&self) -> QuantRS2Result<LatencyStats>;
1410 }
1411
1412 #[derive(Debug, Clone)]
1414 pub struct HardwareErrorCharacteristics {
1415 pub single_qubit_error_rates: Vec<f64>,
1417 pub two_qubit_error_rates: Vec<f64>,
1419 pub measurement_error_rates: Vec<f64>,
1421 pub correlated_errors: Vec<CorrelatedErrorPattern>,
1423 pub temporal_variation: f64,
1425 }
1426
1427 #[derive(Debug, Clone)]
1429 pub struct CorrelatedErrorPattern {
1430 pub qubits: Vec<usize>,
1431 pub probability: f64,
1432 pub pauli_pattern: PauliString,
1433 }
1434
1435 #[derive(Debug, Clone)]
1437 pub struct LatencyStats {
1438 pub syndrome_measurement_time: Duration,
1439 pub decoding_time: Duration,
1440 pub correction_application_time: Duration,
1441 pub total_cycle_time: Duration,
1442 pub throughput_hz: f64,
1443 }
1444
1445 pub struct SyndromeStreamProcessor {
1447 buffer: Arc<Mutex<VecDeque<SyndromePacket>>>,
1448 decoder: Arc<dyn SyndromeDecoder + Send + Sync>,
1449 hardware: Arc<dyn QuantumHardwareInterface>,
1450 performance_monitor: Arc<RwLock<PerformanceMonitor>>,
1451 config: RealTimeConfig,
1452 }
1453
1454 #[derive(Debug, Clone)]
1456 pub struct SyndromePacket {
1457 pub syndrome: Vec<bool>,
1458 pub timestamp: Instant,
1459 pub sequence_number: u64,
1460 pub measurement_fidelity: f64,
1461 }
1462
1463 #[derive(Debug, Clone)]
1465 pub struct RealTimeConfig {
1466 pub max_latency: Duration,
1467 pub buffer_size: usize,
1468 pub parallel_workers: usize,
1469 pub adaptive_threshold: bool,
1470 pub hardware_feedback: bool,
1471 pub performance_logging: bool,
1472 }
1473
1474 impl Default for RealTimeConfig {
1475 fn default() -> Self {
1476 Self {
1477 max_latency: Duration::from_micros(100), buffer_size: 1000,
1479 parallel_workers: 4,
1480 adaptive_threshold: true,
1481 hardware_feedback: true,
1482 performance_logging: true,
1483 }
1484 }
1485 }
1486
1487 #[derive(Debug, Clone)]
1489 pub struct PerformanceMonitor {
1490 pub cycles_processed: u64,
1491 pub errors_corrected: u64,
1492 pub false_positives: u64,
1493 pub latency_histogram: Vec<Duration>,
1494 pub throughput_samples: VecDeque<f64>,
1495 pub start_time: Instant,
1496 }
1497
1498 impl PerformanceMonitor {
1499 pub fn new() -> Self {
1500 Self {
1501 cycles_processed: 0,
1502 errors_corrected: 0,
1503 false_positives: 0,
1504 latency_histogram: Vec::new(),
1505 throughput_samples: VecDeque::new(),
1506 start_time: Instant::now(),
1507 }
1508 }
1509
1510 pub fn record_cycle(&mut self, latency: Duration, error_corrected: bool) {
1511 self.cycles_processed += 1;
1512 if error_corrected {
1513 self.errors_corrected += 1;
1514 }
1515 self.latency_histogram.push(latency);
1516
1517 let elapsed = self.start_time.elapsed();
1519 if elapsed.as_secs_f64() > 0.0 {
1520 let throughput = self.cycles_processed as f64 / elapsed.as_secs_f64();
1521 self.throughput_samples.push_back(throughput);
1522
1523 if self.throughput_samples.len() > 100 {
1525 self.throughput_samples.pop_front();
1526 }
1527 }
1528 }
1529
1530 pub fn average_latency(&self) -> Duration {
1531 if self.latency_histogram.is_empty() {
1532 return Duration::from_nanos(0);
1533 }
1534
1535 let total_nanos: u64 = self
1536 .latency_histogram
1537 .iter()
1538 .map(|d| d.as_nanos() as u64)
1539 .sum();
1540 Duration::from_nanos(total_nanos / self.latency_histogram.len() as u64)
1541 }
1542
1543 pub fn current_throughput(&self) -> f64 {
1544 self.throughput_samples.back().copied().unwrap_or(0.0)
1545 }
1546
1547 pub fn error_correction_rate(&self) -> f64 {
1548 if self.cycles_processed == 0 {
1549 0.0
1550 } else {
1551 self.errors_corrected as f64 / self.cycles_processed as f64
1552 }
1553 }
1554 }
1555
1556 impl SyndromeStreamProcessor {
1557 pub fn new(
1559 decoder: Arc<dyn SyndromeDecoder + Send + Sync>,
1560 hardware: Arc<dyn QuantumHardwareInterface>,
1561 config: RealTimeConfig,
1562 ) -> Self {
1563 Self {
1564 buffer: Arc::new(Mutex::new(VecDeque::with_capacity(config.buffer_size))),
1565 decoder,
1566 hardware,
1567 performance_monitor: Arc::new(RwLock::new(PerformanceMonitor::new())),
1568 config,
1569 }
1570 }
1571
1572 pub fn start_processing(&self) -> QuantRS2Result<thread::JoinHandle<()>> {
1574 let buffer = Arc::clone(&self.buffer);
1575 let decoder = Arc::clone(&self.decoder);
1576 let hardware = Arc::clone(&self.hardware);
1577 let monitor = Arc::clone(&self.performance_monitor);
1578 let config = self.config.clone();
1579
1580 let handle = thread::spawn(move || {
1581 let mut sequence_number = 0u64;
1582
1583 loop {
1584 let cycle_start = Instant::now();
1585
1586 if !hardware.is_ready() {
1588 thread::sleep(Duration::from_micros(10));
1589 continue;
1590 }
1591
1592 match hardware.measure_syndromes() {
1594 Ok(syndrome) => {
1595 let packet = SyndromePacket {
1596 syndrome: syndrome.clone(),
1597 timestamp: Instant::now(),
1598 sequence_number,
1599 measurement_fidelity: 0.99, };
1601
1602 {
1604 let mut buf = buffer.lock().unwrap();
1605 if buf.len() >= config.buffer_size {
1606 buf.pop_front(); }
1608 buf.push_back(packet);
1609 }
1610
1611 let has_error = syndrome.iter().any(|&x| x);
1613 let mut error_corrected = false;
1614
1615 if has_error {
1616 match decoder.decode(&syndrome) {
1617 Ok(correction) => {
1618 match hardware.apply_correction(&correction) {
1619 Ok(()) => {
1620 error_corrected = true;
1621 }
1622 Err(e) => {
1623 eprintln!("Failed to apply correction: {}", e);
1624 }
1625 }
1626 }
1627 Err(e) => {
1628 eprintln!("Decoding failed: {}", e);
1629 }
1630 }
1631 }
1632
1633 let cycle_time = cycle_start.elapsed();
1635 {
1636 let mut mon = monitor.write().unwrap();
1637 mon.record_cycle(cycle_time, error_corrected);
1638 }
1639
1640 if cycle_time > config.max_latency {
1642 eprintln!("Warning: Error correction cycle exceeded max latency: {:?} > {:?}",
1643 cycle_time, config.max_latency);
1644 }
1645
1646 sequence_number += 1;
1647 }
1648 Err(e) => {
1649 eprintln!("Failed to measure syndromes: {}", e);
1650 thread::sleep(Duration::from_micros(10));
1651 }
1652 }
1653
1654 thread::sleep(Duration::from_micros(1));
1656 }
1657 });
1658
1659 Ok(handle)
1660 }
1661
1662 pub fn get_performance_stats(&self) -> PerformanceMonitor {
1664 (*self.performance_monitor.read().unwrap()).clone()
1665 }
1666
1667 pub fn get_buffer_status(&self) -> (usize, usize) {
1669 let buffer = self.buffer.lock().unwrap();
1670 (buffer.len(), self.config.buffer_size)
1671 }
1672 }
1673
1674 pub struct AdaptiveThresholdDecoder {
1676 base_decoder: Arc<dyn SyndromeDecoder + Send + Sync>,
1677 error_characteristics: Arc<RwLock<HardwareErrorCharacteristics>>,
1678 learning_rate: f64,
1679 threshold_history: VecDeque<f64>,
1680 }
1681
1682 impl AdaptiveThresholdDecoder {
1683 pub fn new(
1684 base_decoder: Arc<dyn SyndromeDecoder + Send + Sync>,
1685 initial_characteristics: HardwareErrorCharacteristics,
1686 ) -> Self {
1687 Self {
1688 base_decoder,
1689 error_characteristics: Arc::new(RwLock::new(initial_characteristics)),
1690 learning_rate: 0.01,
1691 threshold_history: VecDeque::with_capacity(1000),
1692 }
1693 }
1694
1695 pub fn update_characteristics(
1697 &mut self,
1698 new_characteristics: HardwareErrorCharacteristics,
1699 ) {
1700 *self.error_characteristics.write().unwrap() = new_characteristics;
1701 }
1702
1703 pub fn adapt_thresholds(&mut self, syndrome: &[bool], correction_success: bool) {
1705 let error_weight = syndrome.iter().filter(|&&x| x).count() as f64;
1706
1707 if correction_success {
1708 self.threshold_history.push_back(error_weight);
1710 } else {
1711 self.threshold_history.push_back(error_weight * 0.8);
1713 }
1714
1715 if self.threshold_history.len() > 100 {
1716 self.threshold_history.pop_front();
1717 }
1718 }
1719
1720 pub fn current_threshold(&self) -> f64 {
1722 if self.threshold_history.is_empty() {
1723 return 1.0; }
1725
1726 let sum: f64 = self.threshold_history.iter().sum();
1727 sum / self.threshold_history.len() as f64
1728 }
1729 }
1730
1731 impl SyndromeDecoder for AdaptiveThresholdDecoder {
1732 fn decode(&self, syndrome: &[bool]) -> QuantRS2Result<PauliString> {
1733 let threshold = self.current_threshold();
1734 let error_weight = syndrome.iter().filter(|&&x| x).count() as f64;
1735
1736 if error_weight > threshold {
1738 self.base_decoder.decode(syndrome)
1740 } else {
1741 Ok(PauliString::new(vec![Pauli::I; syndrome.len()]))
1743 }
1744 }
1745 }
1746
1747 pub struct ParallelSyndromeDecoder {
1749 base_decoder: Arc<dyn SyndromeDecoder + Send + Sync>,
1750 worker_count: usize,
1751 }
1752
1753 impl ParallelSyndromeDecoder {
1754 pub fn new(
1755 base_decoder: Arc<dyn SyndromeDecoder + Send + Sync>,
1756 worker_count: usize,
1757 ) -> Self {
1758 Self {
1759 base_decoder,
1760 worker_count,
1761 }
1762 }
1763
1764 pub fn decode_batch(&self, syndromes: &[Vec<bool>]) -> QuantRS2Result<Vec<PauliString>> {
1766 let chunk_size = (syndromes.len() + self.worker_count - 1) / self.worker_count;
1767 let mut handles = Vec::new();
1768
1769 for chunk in syndromes.chunks(chunk_size) {
1770 let decoder = Arc::clone(&self.base_decoder);
1771 let chunk_data: Vec<Vec<bool>> = chunk.to_vec();
1772
1773 let handle = thread::spawn(move || {
1774 let mut results = Vec::new();
1775 for syndrome in chunk_data {
1776 match decoder.decode(&syndrome) {
1777 Ok(correction) => results.push(correction),
1778 Err(_) => {
1779 results.push(PauliString::new(vec![Pauli::I; syndrome.len()]))
1780 }
1781 }
1782 }
1783 results
1784 });
1785
1786 handles.push(handle);
1787 }
1788
1789 let mut all_results = Vec::new();
1790 for handle in handles {
1791 match handle.join() {
1792 Ok(chunk_results) => all_results.extend(chunk_results),
1793 Err(_) => {
1794 return Err(QuantRS2Error::ComputationError(
1795 "Parallel decoding failed".to_string(),
1796 ))
1797 }
1798 }
1799 }
1800
1801 Ok(all_results)
1802 }
1803 }
1804
1805 impl SyndromeDecoder for ParallelSyndromeDecoder {
1806 fn decode(&self, syndrome: &[bool]) -> QuantRS2Result<PauliString> {
1807 self.base_decoder.decode(syndrome)
1808 }
1809 }
1810
1811 pub struct MockQuantumHardware {
1813 error_rate: f64,
1814 latency: Duration,
1815 syndrome_length: usize,
1816 }
1817
1818 impl MockQuantumHardware {
1819 pub fn new(error_rate: f64, latency: Duration, syndrome_length: usize) -> Self {
1820 Self {
1821 error_rate,
1822 latency,
1823 syndrome_length,
1824 }
1825 }
1826 }
1827
1828 impl QuantumHardwareInterface for MockQuantumHardware {
1829 fn measure_syndromes(&self) -> QuantRS2Result<Vec<bool>> {
1830 thread::sleep(self.latency);
1831
1832 use scirs2_core::random::prelude::*;
1834 let mut rng = thread_rng();
1835 let mut syndrome = vec![false; self.syndrome_length];
1836 for i in 0..self.syndrome_length {
1837 if rng.gen::<f64>() < self.error_rate {
1838 syndrome[i] = true;
1839 }
1840 }
1841
1842 Ok(syndrome)
1843 }
1844
1845 fn apply_correction(&self, _correction: &PauliString) -> QuantRS2Result<()> {
1846 thread::sleep(self.latency / 2);
1847 Ok(())
1848 }
1849
1850 fn get_error_characteristics(&self) -> QuantRS2Result<HardwareErrorCharacteristics> {
1851 Ok(HardwareErrorCharacteristics {
1852 single_qubit_error_rates: vec![self.error_rate; self.syndrome_length],
1853 two_qubit_error_rates: vec![self.error_rate * 10.0; self.syndrome_length / 2],
1854 measurement_error_rates: vec![self.error_rate * 0.1; self.syndrome_length],
1855 correlated_errors: Vec::new(),
1856 temporal_variation: 0.01,
1857 })
1858 }
1859
1860 fn is_ready(&self) -> bool {
1861 true
1862 }
1863
1864 fn get_latency_stats(&self) -> QuantRS2Result<LatencyStats> {
1865 Ok(LatencyStats {
1866 syndrome_measurement_time: self.latency,
1867 decoding_time: Duration::from_micros(10),
1868 correction_application_time: self.latency / 2,
1869 total_cycle_time: self.latency + Duration::from_micros(10) + self.latency / 2,
1870 throughput_hz: 1.0 / (self.latency.as_secs_f64() * 1.5 + 10e-6),
1871 })
1872 }
1873 }
1874}
1875
1876pub mod logical_gates {
1880 use super::*;
1881
1882 #[derive(Debug, Clone)]
1884 pub struct LogicalGateOp {
1885 pub code: StabilizerCode,
1887 pub physical_operations: Vec<PhysicalGateSequence>,
1889 pub logical_qubits: Vec<usize>,
1891 pub error_propagation: ErrorPropagationAnalysis,
1893 }
1894
1895 #[derive(Debug, Clone)]
1897 pub struct PhysicalGateSequence {
1898 pub target_qubits: Vec<usize>,
1900 pub pauli_sequence: Vec<PauliString>,
1902 pub timing_constraints: Option<TimingConstraints>,
1904 pub error_correction_rounds: usize,
1906 }
1907
1908 #[derive(Debug, Clone)]
1910 pub struct ErrorPropagationAnalysis {
1911 pub single_qubit_propagation: Vec<ErrorPropagationPath>,
1913 pub two_qubit_propagation: Vec<ErrorPropagationPath>,
1915 pub max_error_weight: usize,
1917 pub fault_tolerance_threshold: f64,
1919 }
1920
1921 #[derive(Debug, Clone)]
1923 pub struct ErrorPropagationPath {
1924 pub initial_error: PauliString,
1926 pub final_error: PauliString,
1928 pub probability: f64,
1930 pub correctable: bool,
1932 }
1933
1934 #[derive(Debug, Clone)]
1936 pub struct TimingConstraints {
1937 pub max_operation_time: std::time::Duration,
1939 pub sync_points: Vec<usize>,
1941 pub parallel_groups: Vec<Vec<usize>>,
1943 }
1944
1945 pub struct LogicalGateSynthesizer {
1947 codes: Vec<StabilizerCode>,
1949 strategies: Vec<SynthesisStrategy>,
1951 error_threshold: f64,
1953 }
1954
1955 #[derive(Debug, Clone)]
1957 pub enum SynthesisStrategy {
1958 Transversal,
1960 MagicStateDistillation,
1962 LatticeSurgery,
1964 CodeDeformation,
1966 Braiding,
1968 }
1969
1970 impl LogicalGateSynthesizer {
1971 pub fn new(error_threshold: f64) -> Self {
1973 Self {
1974 codes: Vec::new(),
1975 strategies: vec![
1976 SynthesisStrategy::Transversal,
1977 SynthesisStrategy::MagicStateDistillation,
1978 SynthesisStrategy::LatticeSurgery,
1979 ],
1980 error_threshold,
1981 }
1982 }
1983
1984 pub fn add_code(&mut self, code: StabilizerCode) {
1986 self.codes.push(code);
1987 }
1988
1989 pub fn synthesize_logical_x(
1991 &self,
1992 code: &StabilizerCode,
1993 logical_qubit: usize,
1994 ) -> QuantRS2Result<LogicalGateOp> {
1995 if logical_qubit >= code.k {
1996 return Err(QuantRS2Error::InvalidInput(format!(
1997 "Logical qubit {} exceeds code dimension {}",
1998 logical_qubit, code.k
1999 )));
2000 }
2001
2002 let logical_x_operator = &code.logical_x[logical_qubit];
2004
2005 let physical_ops = vec![PhysicalGateSequence {
2006 target_qubits: (0..code.n).collect(),
2007 pauli_sequence: vec![logical_x_operator.clone()],
2008 timing_constraints: None,
2009 error_correction_rounds: 1,
2010 }];
2011
2012 let error_analysis = self.analyze_error_propagation(code, &physical_ops)?;
2013
2014 Ok(LogicalGateOp {
2015 code: code.clone(),
2016 physical_operations: physical_ops,
2017 logical_qubits: vec![logical_qubit],
2018 error_propagation: error_analysis,
2019 })
2020 }
2021
2022 pub fn synthesize_logical_z(
2024 &self,
2025 code: &StabilizerCode,
2026 logical_qubit: usize,
2027 ) -> QuantRS2Result<LogicalGateOp> {
2028 if logical_qubit >= code.k {
2029 return Err(QuantRS2Error::InvalidInput(format!(
2030 "Logical qubit {} exceeds code dimension {}",
2031 logical_qubit, code.k
2032 )));
2033 }
2034
2035 let logical_z_operator = &code.logical_z[logical_qubit];
2036
2037 let physical_ops = vec![PhysicalGateSequence {
2038 target_qubits: (0..code.n).collect(),
2039 pauli_sequence: vec![logical_z_operator.clone()],
2040 timing_constraints: None,
2041 error_correction_rounds: 1,
2042 }];
2043
2044 let error_analysis = self.analyze_error_propagation(code, &physical_ops)?;
2045
2046 Ok(LogicalGateOp {
2047 code: code.clone(),
2048 physical_operations: physical_ops,
2049 logical_qubits: vec![logical_qubit],
2050 error_propagation: error_analysis,
2051 })
2052 }
2053
2054 pub fn synthesize_logical_h(
2056 &self,
2057 code: &StabilizerCode,
2058 logical_qubit: usize,
2059 ) -> QuantRS2Result<LogicalGateOp> {
2060 if logical_qubit >= code.k {
2061 return Err(QuantRS2Error::InvalidInput(format!(
2062 "Logical qubit {} exceeds code dimension {}",
2063 logical_qubit, code.k
2064 )));
2065 }
2066
2067 let physical_ops = vec![PhysicalGateSequence {
2070 target_qubits: (0..code.n).collect(),
2071 pauli_sequence: self.generate_hadamard_sequence(code, logical_qubit)?,
2072 timing_constraints: Some(TimingConstraints {
2073 max_operation_time: std::time::Duration::from_micros(100),
2074 sync_points: vec![code.n / 2],
2075 parallel_groups: vec![(0..code.n).collect()],
2076 }),
2077 error_correction_rounds: 2, }];
2079
2080 let error_analysis = self.analyze_error_propagation(code, &physical_ops)?;
2081
2082 Ok(LogicalGateOp {
2083 code: code.clone(),
2084 physical_operations: physical_ops,
2085 logical_qubits: vec![logical_qubit],
2086 error_propagation: error_analysis,
2087 })
2088 }
2089
2090 pub fn synthesize_logical_cnot(
2092 &self,
2093 code: &StabilizerCode,
2094 control_qubit: usize,
2095 target_qubit: usize,
2096 ) -> QuantRS2Result<LogicalGateOp> {
2097 if control_qubit >= code.k || target_qubit >= code.k {
2098 return Err(QuantRS2Error::InvalidInput(
2099 "Control or target qubit exceeds code dimension".to_string(),
2100 ));
2101 }
2102
2103 if control_qubit == target_qubit {
2104 return Err(QuantRS2Error::InvalidInput(
2105 "Control and target qubits must be different".to_string(),
2106 ));
2107 }
2108
2109 let cnot_sequence = self.generate_cnot_sequence(code, control_qubit, target_qubit)?;
2111
2112 let physical_ops = vec![PhysicalGateSequence {
2113 target_qubits: (0..code.n).collect(),
2114 pauli_sequence: cnot_sequence,
2115 timing_constraints: Some(TimingConstraints {
2116 max_operation_time: std::time::Duration::from_micros(200),
2117 sync_points: vec![],
2118 parallel_groups: vec![], }),
2120 error_correction_rounds: 2,
2121 }];
2122
2123 let error_analysis = self.analyze_error_propagation(code, &physical_ops)?;
2124
2125 Ok(LogicalGateOp {
2126 code: code.clone(),
2127 physical_operations: physical_ops,
2128 logical_qubits: vec![control_qubit, target_qubit],
2129 error_propagation: error_analysis,
2130 })
2131 }
2132
2133 pub fn synthesize_logical_t(
2135 &self,
2136 code: &StabilizerCode,
2137 logical_qubit: usize,
2138 ) -> QuantRS2Result<LogicalGateOp> {
2139 if logical_qubit >= code.k {
2140 return Err(QuantRS2Error::InvalidInput(format!(
2141 "Logical qubit {} exceeds code dimension {}",
2142 logical_qubit, code.k
2143 )));
2144 }
2145
2146 let magic_state_prep = self.prepare_magic_state(code)?;
2148 let injection_sequence =
2149 self.inject_magic_state(code, logical_qubit, &magic_state_prep)?;
2150
2151 let physical_ops = vec![magic_state_prep, injection_sequence];
2152
2153 let error_analysis = self.analyze_error_propagation(code, &physical_ops)?;
2154
2155 Ok(LogicalGateOp {
2156 code: code.clone(),
2157 physical_operations: physical_ops,
2158 logical_qubits: vec![logical_qubit],
2159 error_propagation: error_analysis,
2160 })
2161 }
2162
2163 fn generate_hadamard_sequence(
2165 &self,
2166 code: &StabilizerCode,
2167 _logical_qubit: usize,
2168 ) -> QuantRS2Result<Vec<PauliString>> {
2169 let mut sequence = Vec::new();
2172
2173 sequence.push(PauliString::new(vec![Pauli::I; code.n]));
2177
2178 Ok(sequence)
2179 }
2180
2181 fn generate_cnot_sequence(
2183 &self,
2184 code: &StabilizerCode,
2185 _control: usize,
2186 _target: usize,
2187 ) -> QuantRS2Result<Vec<PauliString>> {
2188 let mut sequence = Vec::new();
2191
2192 sequence.push(PauliString::new(vec![Pauli::I; code.n]));
2194
2195 Ok(sequence)
2196 }
2197
2198 fn prepare_magic_state(
2200 &self,
2201 code: &StabilizerCode,
2202 ) -> QuantRS2Result<PhysicalGateSequence> {
2203 Ok(PhysicalGateSequence {
2206 target_qubits: (0..code.n).collect(),
2207 pauli_sequence: vec![PauliString::new(vec![Pauli::I; code.n])],
2208 timing_constraints: Some(TimingConstraints {
2209 max_operation_time: std::time::Duration::from_millis(1),
2210 sync_points: vec![],
2211 parallel_groups: vec![(0..code.n).collect()],
2212 }),
2213 error_correction_rounds: 5, })
2215 }
2216
2217 fn inject_magic_state(
2219 &self,
2220 code: &StabilizerCode,
2221 _logical_qubit: usize,
2222 _magic_state: &PhysicalGateSequence,
2223 ) -> QuantRS2Result<PhysicalGateSequence> {
2224 Ok(PhysicalGateSequence {
2226 target_qubits: (0..code.n).collect(),
2227 pauli_sequence: vec![PauliString::new(vec![Pauli::I; code.n])],
2228 timing_constraints: Some(TimingConstraints {
2229 max_operation_time: std::time::Duration::from_micros(500),
2230 sync_points: vec![code.n / 2],
2231 parallel_groups: vec![],
2232 }),
2233 error_correction_rounds: 3,
2234 })
2235 }
2236
2237 fn analyze_error_propagation(
2239 &self,
2240 code: &StabilizerCode,
2241 physical_ops: &[PhysicalGateSequence],
2242 ) -> QuantRS2Result<ErrorPropagationAnalysis> {
2243 let mut single_qubit_propagation = Vec::new();
2244 let mut two_qubit_propagation = Vec::new();
2245 let mut max_error_weight = 0;
2246
2247 for i in 0..code.n {
2249 for pauli in [Pauli::X, Pauli::Y, Pauli::Z] {
2250 let mut initial_error = vec![Pauli::I; code.n];
2251 initial_error[i] = pauli;
2252 let initial_pauli_string = PauliString::new(initial_error);
2253
2254 let final_error = self.propagate_error(&initial_pauli_string, physical_ops)?;
2256 let error_weight = final_error.weight();
2257 max_error_weight = max_error_weight.max(error_weight);
2258
2259 let correctable = self.is_error_correctable(code, &final_error)?;
2261
2262 single_qubit_propagation.push(ErrorPropagationPath {
2263 initial_error: initial_pauli_string,
2264 final_error,
2265 probability: 1.0 / (3.0 * code.n as f64), correctable,
2267 });
2268 }
2269 }
2270
2271 for i in 0..code.n.min(5) {
2273 for j in (i + 1)..code.n.min(5) {
2275 let mut initial_error = vec![Pauli::I; code.n];
2276 initial_error[i] = Pauli::X;
2277 initial_error[j] = Pauli::X;
2278 let initial_pauli_string = PauliString::new(initial_error);
2279
2280 let final_error = self.propagate_error(&initial_pauli_string, physical_ops)?;
2281 let error_weight = final_error.weight();
2282 max_error_weight = max_error_weight.max(error_weight);
2283
2284 let correctable = self.is_error_correctable(code, &final_error)?;
2285
2286 two_qubit_propagation.push(ErrorPropagationPath {
2287 initial_error: initial_pauli_string,
2288 final_error,
2289 probability: 1.0 / (code.n * (code.n - 1)) as f64,
2290 correctable,
2291 });
2292 }
2293 }
2294
2295 Ok(ErrorPropagationAnalysis {
2296 single_qubit_propagation,
2297 two_qubit_propagation,
2298 max_error_weight,
2299 fault_tolerance_threshold: self.error_threshold,
2300 })
2301 }
2302
2303 fn propagate_error(
2305 &self,
2306 error: &PauliString,
2307 _physical_ops: &[PhysicalGateSequence],
2308 ) -> QuantRS2Result<PauliString> {
2309 Ok(error.clone())
2312 }
2313
2314 fn is_error_correctable(
2316 &self,
2317 code: &StabilizerCode,
2318 error: &PauliString,
2319 ) -> QuantRS2Result<bool> {
2320 Ok(error.weight() <= (code.d + 1) / 2)
2323 }
2324 }
2325
2326 pub struct LogicalCircuitSynthesizer {
2328 gate_synthesizer: LogicalGateSynthesizer,
2329 optimization_passes: Vec<OptimizationPass>,
2330 }
2331
2332 #[derive(Debug, Clone)]
2334 pub enum OptimizationPass {
2335 PauliOptimization,
2337 ErrorCorrectionOptimization,
2339 ParallelizationOptimization,
2341 MagicStateOptimization,
2343 }
2344
2345 impl LogicalCircuitSynthesizer {
2346 pub fn new(error_threshold: f64) -> Self {
2347 Self {
2348 gate_synthesizer: LogicalGateSynthesizer::new(error_threshold),
2349 optimization_passes: vec![
2350 OptimizationPass::PauliOptimization,
2351 OptimizationPass::ErrorCorrectionOptimization,
2352 OptimizationPass::ParallelizationOptimization,
2353 OptimizationPass::MagicStateOptimization,
2354 ],
2355 }
2356 }
2357
2358 pub fn add_code(&mut self, code: StabilizerCode) {
2360 self.gate_synthesizer.add_code(code);
2361 }
2362
2363 pub fn synthesize_circuit(
2365 &self,
2366 code: &StabilizerCode,
2367 gate_sequence: &[(&str, Vec<usize>)], ) -> QuantRS2Result<Vec<LogicalGateOp>> {
2369 let mut logical_gates = Vec::new();
2370
2371 for (gate_name, targets) in gate_sequence {
2372 match gate_name.to_lowercase().as_str() {
2373 "x" | "pauli_x" => {
2374 if targets.len() != 1 {
2375 return Err(QuantRS2Error::InvalidInput(
2376 "X gate requires exactly one target".to_string(),
2377 ));
2378 }
2379 logical_gates.push(
2380 self.gate_synthesizer
2381 .synthesize_logical_x(code, targets[0])?,
2382 );
2383 }
2384 "z" | "pauli_z" => {
2385 if targets.len() != 1 {
2386 return Err(QuantRS2Error::InvalidInput(
2387 "Z gate requires exactly one target".to_string(),
2388 ));
2389 }
2390 logical_gates.push(
2391 self.gate_synthesizer
2392 .synthesize_logical_z(code, targets[0])?,
2393 );
2394 }
2395 "h" | "hadamard" => {
2396 if targets.len() != 1 {
2397 return Err(QuantRS2Error::InvalidInput(
2398 "H gate requires exactly one target".to_string(),
2399 ));
2400 }
2401 logical_gates.push(
2402 self.gate_synthesizer
2403 .synthesize_logical_h(code, targets[0])?,
2404 );
2405 }
2406 "cnot" | "cx" => {
2407 if targets.len() != 2 {
2408 return Err(QuantRS2Error::InvalidInput(
2409 "CNOT gate requires exactly two targets".to_string(),
2410 ));
2411 }
2412 logical_gates.push(
2413 self.gate_synthesizer
2414 .synthesize_logical_cnot(code, targets[0], targets[1])?,
2415 );
2416 }
2417 "t" => {
2418 if targets.len() != 1 {
2419 return Err(QuantRS2Error::InvalidInput(
2420 "T gate requires exactly one target".to_string(),
2421 ));
2422 }
2423 logical_gates.push(
2424 self.gate_synthesizer
2425 .synthesize_logical_t(code, targets[0])?,
2426 );
2427 }
2428 _ => {
2429 return Err(QuantRS2Error::UnsupportedOperation(format!(
2430 "Unsupported logical gate: {}",
2431 gate_name
2432 )));
2433 }
2434 }
2435 }
2436
2437 self.optimize_circuit(logical_gates)
2439 }
2440
2441 fn optimize_circuit(
2443 &self,
2444 mut circuit: Vec<LogicalGateOp>,
2445 ) -> QuantRS2Result<Vec<LogicalGateOp>> {
2446 for pass in &self.optimization_passes {
2447 circuit = self.apply_optimization_pass(circuit, pass)?;
2448 }
2449 Ok(circuit)
2450 }
2451
2452 fn apply_optimization_pass(
2454 &self,
2455 circuit: Vec<LogicalGateOp>,
2456 pass: &OptimizationPass,
2457 ) -> QuantRS2Result<Vec<LogicalGateOp>> {
2458 match pass {
2459 OptimizationPass::PauliOptimization => self.optimize_pauli_gates(circuit),
2460 OptimizationPass::ErrorCorrectionOptimization => {
2461 self.optimize_error_correction(circuit)
2462 }
2463 OptimizationPass::ParallelizationOptimization => {
2464 self.optimize_parallelization(circuit)
2465 }
2466 OptimizationPass::MagicStateOptimization => self.optimize_magic_states(circuit),
2467 }
2468 }
2469
2470 fn optimize_pauli_gates(
2472 &self,
2473 circuit: Vec<LogicalGateOp>,
2474 ) -> QuantRS2Result<Vec<LogicalGateOp>> {
2475 Ok(circuit) }
2478
2479 fn optimize_error_correction(
2481 &self,
2482 circuit: Vec<LogicalGateOp>,
2483 ) -> QuantRS2Result<Vec<LogicalGateOp>> {
2484 Ok(circuit) }
2487
2488 fn optimize_parallelization(
2490 &self,
2491 circuit: Vec<LogicalGateOp>,
2492 ) -> QuantRS2Result<Vec<LogicalGateOp>> {
2493 Ok(circuit) }
2496
2497 fn optimize_magic_states(
2499 &self,
2500 circuit: Vec<LogicalGateOp>,
2501 ) -> QuantRS2Result<Vec<LogicalGateOp>> {
2502 Ok(circuit) }
2505
2506 pub fn estimate_resources(&self, circuit: &[LogicalGateOp]) -> LogicalCircuitResources {
2508 let mut total_physical_operations = 0;
2509 let mut total_error_correction_rounds = 0;
2510 let mut max_parallelism = 0;
2511 let mut magic_states_required = 0;
2512
2513 for gate in circuit {
2514 total_physical_operations += gate.physical_operations.len();
2515 for op in &gate.physical_operations {
2516 total_error_correction_rounds += op.error_correction_rounds;
2517 if let Some(constraints) = &op.timing_constraints {
2518 max_parallelism = max_parallelism.max(constraints.parallel_groups.len());
2519 }
2520 }
2521
2522 if gate.logical_qubits.len() == 1 {
2524 magic_states_required += 1;
2526 }
2527 }
2528
2529 LogicalCircuitResources {
2530 total_physical_operations,
2531 total_error_correction_rounds,
2532 max_parallelism,
2533 magic_states_required,
2534 estimated_depth: circuit.len(),
2535 estimated_time: std::time::Duration::from_millis(
2536 (total_error_correction_rounds * 10) as u64,
2537 ),
2538 }
2539 }
2540 }
2541
2542 #[derive(Debug, Clone)]
2544 pub struct LogicalCircuitResources {
2545 pub total_physical_operations: usize,
2546 pub total_error_correction_rounds: usize,
2547 pub max_parallelism: usize,
2548 pub magic_states_required: usize,
2549 pub estimated_depth: usize,
2550 pub estimated_time: std::time::Duration,
2551 }
2552}
2553
2554pub mod adaptive_threshold {
2558 use super::*;
2559 use std::collections::{HashMap, VecDeque};
2560 use std::time::{Duration, Instant};
2561
2562 pub struct AdaptiveThresholdEstimator {
2564 error_history: VecDeque<ErrorObservation>,
2566 noise_model: NoiseModel,
2568 estimation_algorithm: ThresholdEstimationAlgorithm,
2570 performance_tracker: PerformanceTracker,
2572 config: AdaptiveConfig,
2574 }
2575
2576 #[derive(Debug, Clone)]
2578 pub struct ErrorObservation {
2579 pub syndrome: Vec<bool>,
2581 pub correction: PauliString,
2583 pub success: bool,
2585 pub observed_error_rate: f64,
2587 pub timestamp: Instant,
2589 pub environment: EnvironmentalConditions,
2591 }
2592
2593 #[derive(Debug, Clone)]
2595 pub struct EnvironmentalConditions {
2596 pub temperature: f64,
2598 pub magnetic_field: f64,
2600 pub vibration_level: f64,
2602 pub emi_level: f64,
2604 pub uptime: f64,
2606 }
2607
2608 #[derive(Debug, Clone)]
2610 pub struct NoiseModel {
2611 pub single_qubit_rates: HashMap<(usize, Pauli), f64>,
2613 pub correlated_rates: HashMap<(usize, usize), f64>,
2615 pub temporal_correlation: f64,
2617 pub environment_sensitivity: EnvironmentSensitivity,
2619 pub confidence: f64,
2621 }
2622
2623 #[derive(Debug, Clone)]
2625 pub struct EnvironmentSensitivity {
2626 pub temperature_coeff: f64,
2628 pub magnetic_field_coeff: f64,
2630 pub vibration_coeff: f64,
2632 pub emi_coeff: f64,
2634 pub drift_coeff: f64,
2636 }
2637
2638 #[derive(Debug, Clone)]
2640 pub enum ThresholdEstimationAlgorithm {
2641 Bayesian {
2643 prior_strength: f64,
2644 update_rate: f64,
2645 },
2646 MachineLearning {
2648 model_type: MLModelType,
2649 training_window: usize,
2650 },
2651 KalmanFilter {
2653 process_noise: f64,
2654 measurement_noise: f64,
2655 },
2656 ExponentialAverage { alpha: f64 },
2658 }
2659
2660 #[derive(Debug, Clone)]
2662 pub enum MLModelType {
2663 LinearRegression,
2664 RandomForest,
2665 NeuralNetwork { hidden_layers: Vec<usize> },
2666 SupportVectorMachine,
2667 }
2668
2669 #[derive(Debug, Clone)]
2671 pub struct PerformanceTracker {
2672 pub successful_corrections: u64,
2674 pub failed_corrections: u64,
2676 pub false_positives: u64,
2678 pub false_negatives: u64,
2680 pub average_latency: Duration,
2682 pub threshold_accuracy: f64,
2684 }
2685
2686 #[derive(Debug, Clone)]
2688 pub struct AdaptiveConfig {
2689 pub max_history_size: usize,
2691 pub min_observations: usize,
2693 pub update_frequency: Duration,
2695 pub confidence_threshold: f64,
2697 pub environmental_monitoring: bool,
2699 pub real_time_adaptation: bool,
2701 }
2702
2703 #[derive(Debug, Clone)]
2705 pub struct ThresholdRecommendation {
2706 pub threshold: f64,
2708 pub confidence: f64,
2710 pub predicted_error_rate: f64,
2712 pub recommendation_quality: f64,
2714 pub environmental_impact: f64,
2716 }
2717
2718 impl Default for AdaptiveConfig {
2719 fn default() -> Self {
2720 Self {
2721 max_history_size: 10000,
2722 min_observations: 100,
2723 update_frequency: Duration::from_secs(30),
2724 confidence_threshold: 0.8,
2725 environmental_monitoring: true,
2726 real_time_adaptation: true,
2727 }
2728 }
2729 }
2730
2731 impl Default for EnvironmentalConditions {
2732 fn default() -> Self {
2733 Self {
2734 temperature: 300.0, magnetic_field: 0.0,
2736 vibration_level: 0.0,
2737 emi_level: 0.0,
2738 uptime: 0.0,
2739 }
2740 }
2741 }
2742
2743 impl Default for EnvironmentSensitivity {
2744 fn default() -> Self {
2745 Self {
2746 temperature_coeff: 1e-5,
2747 magnetic_field_coeff: 1e-3,
2748 vibration_coeff: 1e-4,
2749 emi_coeff: 1e-4,
2750 drift_coeff: 1e-7,
2751 }
2752 }
2753 }
2754
2755 impl Default for NoiseModel {
2756 fn default() -> Self {
2757 Self {
2758 single_qubit_rates: HashMap::new(),
2759 correlated_rates: HashMap::new(),
2760 temporal_correlation: 0.1,
2761 environment_sensitivity: EnvironmentSensitivity::default(),
2762 confidence: 0.5,
2763 }
2764 }
2765 }
2766
2767 impl PerformanceTracker {
2768 pub fn new() -> Self {
2769 Self {
2770 successful_corrections: 0,
2771 failed_corrections: 0,
2772 false_positives: 0,
2773 false_negatives: 0,
2774 average_latency: Duration::from_nanos(0),
2775 threshold_accuracy: 0.0,
2776 }
2777 }
2778
2779 pub fn precision(&self) -> f64 {
2780 let total_positive = self.successful_corrections + self.false_positives;
2781 if total_positive == 0 {
2782 1.0
2783 } else {
2784 self.successful_corrections as f64 / total_positive as f64
2785 }
2786 }
2787
2788 pub fn recall(&self) -> f64 {
2789 let total_actual_positive = self.successful_corrections + self.false_negatives;
2790 if total_actual_positive == 0 {
2791 1.0
2792 } else {
2793 self.successful_corrections as f64 / total_actual_positive as f64
2794 }
2795 }
2796
2797 pub fn f1_score(&self) -> f64 {
2798 let p = self.precision();
2799 let r = self.recall();
2800 if p + r == 0.0 {
2801 0.0
2802 } else {
2803 2.0 * p * r / (p + r)
2804 }
2805 }
2806 }
2807
2808 impl AdaptiveThresholdEstimator {
2809 pub fn new(
2811 initial_noise_model: NoiseModel,
2812 algorithm: ThresholdEstimationAlgorithm,
2813 config: AdaptiveConfig,
2814 ) -> Self {
2815 Self {
2816 error_history: VecDeque::with_capacity(config.max_history_size),
2817 noise_model: initial_noise_model,
2818 estimation_algorithm: algorithm,
2819 performance_tracker: PerformanceTracker::new(),
2820 config,
2821 }
2822 }
2823
2824 pub fn add_observation(&mut self, observation: ErrorObservation) {
2826 if self.error_history.len() >= self.config.max_history_size {
2828 self.error_history.pop_front();
2829 }
2830 self.error_history.push_back(observation.clone());
2831
2832 self.update_performance_tracking(&observation);
2834
2835 if self.config.real_time_adaptation
2837 && self.error_history.len() >= self.config.min_observations
2838 {
2839 self.update_noise_model();
2840 }
2841 }
2842
2843 pub fn estimate_threshold(
2845 &self,
2846 syndrome: &[bool],
2847 environment: &EnvironmentalConditions,
2848 ) -> f64 {
2849 match &self.estimation_algorithm {
2850 ThresholdEstimationAlgorithm::Bayesian {
2851 prior_strength,
2852 update_rate,
2853 } => self.bayesian_threshold_estimation(
2854 syndrome,
2855 environment,
2856 *prior_strength,
2857 *update_rate,
2858 ),
2859 ThresholdEstimationAlgorithm::MachineLearning {
2860 model_type,
2861 training_window,
2862 } => self.ml_threshold_estimation(
2863 syndrome,
2864 environment,
2865 model_type,
2866 *training_window,
2867 ),
2868 ThresholdEstimationAlgorithm::KalmanFilter {
2869 process_noise,
2870 measurement_noise,
2871 } => self.kalman_threshold_estimation(
2872 syndrome,
2873 environment,
2874 *process_noise,
2875 *measurement_noise,
2876 ),
2877 ThresholdEstimationAlgorithm::ExponentialAverage { alpha } => {
2878 self.exponential_average_threshold(syndrome, environment, *alpha)
2879 }
2880 }
2881 }
2882
2883 pub fn get_threshold_recommendation(&self, syndrome: &[bool]) -> ThresholdRecommendation {
2885 let current_env = EnvironmentalConditions::default(); let threshold = self.estimate_threshold(syndrome, ¤t_env);
2887 let confidence = self.noise_model.confidence;
2888 let predicted_rate = self.predict_error_rate(¤t_env, Duration::from_secs(60));
2889
2890 ThresholdRecommendation {
2891 threshold,
2892 confidence,
2893 predicted_error_rate: predicted_rate,
2894 recommendation_quality: self.assess_recommendation_quality(),
2895 environmental_impact: self.assess_environmental_impact(¤t_env),
2896 }
2897 }
2898
2899 pub fn predict_error_rate(
2901 &self,
2902 environment: &EnvironmentalConditions,
2903 horizon: Duration,
2904 ) -> f64 {
2905 let base_rate = self.calculate_base_error_rate();
2906 let environmental_factor = self.calculate_environmental_factor(environment);
2907 let temporal_factor = self.calculate_temporal_factor(horizon);
2908
2909 base_rate * environmental_factor * temporal_factor
2910 }
2911
2912 fn bayesian_threshold_estimation(
2914 &self,
2915 syndrome: &[bool],
2916 environment: &EnvironmentalConditions,
2917 prior_strength: f64,
2918 update_rate: f64,
2919 ) -> f64 {
2920 let syndrome_weight = syndrome.iter().filter(|&&x| x).count() as f64;
2921 let base_threshold = self.calculate_base_threshold(syndrome_weight);
2922
2923 let historical_adjustment = self.calculate_historical_adjustment(update_rate);
2925
2926 let env_adjustment = self.calculate_environmental_adjustment(environment);
2928
2929 let prior = base_threshold;
2931 let likelihood_weight = 1.0 / (1.0 + prior_strength);
2932
2933 prior * (1.0 - likelihood_weight)
2934 + (base_threshold + historical_adjustment + env_adjustment) * likelihood_weight
2935 }
2936
2937 fn ml_threshold_estimation(
2939 &self,
2940 syndrome: &[bool],
2941 environment: &EnvironmentalConditions,
2942 model_type: &MLModelType,
2943 training_window: usize,
2944 ) -> f64 {
2945 let features = self.extract_features(syndrome, environment);
2947
2948 let training_data = self.get_recent_observations(training_window);
2950
2951 match model_type {
2952 MLModelType::LinearRegression => {
2953 self.linear_regression_predict(&features, &training_data)
2954 }
2955 _ => {
2956 self.linear_regression_predict(&features, &training_data)
2958 }
2959 }
2960 }
2961
2962 fn kalman_threshold_estimation(
2964 &self,
2965 syndrome: &[bool],
2966 _environment: &EnvironmentalConditions,
2967 process_noise: f64,
2968 measurement_noise: f64,
2969 ) -> f64 {
2970 let syndrome_weight = syndrome.iter().filter(|&&x| x).count() as f64;
2971 let base_threshold = self.calculate_base_threshold(syndrome_weight);
2972
2973 let prediction_error = self.calculate_prediction_error();
2975 let kalman_gain = process_noise / (process_noise + measurement_noise);
2976
2977 base_threshold + kalman_gain * prediction_error
2978 }
2979
2980 fn exponential_average_threshold(
2982 &self,
2983 syndrome: &[bool],
2984 _environment: &EnvironmentalConditions,
2985 alpha: f64,
2986 ) -> f64 {
2987 let syndrome_weight = syndrome.iter().filter(|&&x| x).count() as f64;
2988 let current_threshold = self.calculate_base_threshold(syndrome_weight);
2989
2990 if let Some(_last_obs) = self.error_history.back() {
2991 let last_threshold = syndrome_weight; alpha * current_threshold + (1.0 - alpha) * last_threshold
2993 } else {
2994 current_threshold
2995 }
2996 }
2997
2998 fn calculate_base_error_rate(&self) -> f64 {
3000 if self.error_history.is_empty() {
3001 return 0.001; }
3003
3004 let recent_errors: Vec<_> = self.error_history.iter().rev().take(100).collect();
3005
3006 let total_errors = recent_errors.len() as f64;
3007 let failed_corrections = recent_errors.iter().filter(|obs| !obs.success).count() as f64;
3008
3009 failed_corrections / total_errors
3010 }
3011
3012 fn calculate_environmental_factor(&self, environment: &EnvironmentalConditions) -> f64 {
3013 let sensitivity = &self.noise_model.environment_sensitivity;
3014
3015 1.0 + sensitivity.temperature_coeff * (environment.temperature - 300.0)
3016 + sensitivity.magnetic_field_coeff * environment.magnetic_field
3017 + sensitivity.vibration_coeff * environment.vibration_level
3018 + sensitivity.emi_coeff * environment.emi_level
3019 + sensitivity.drift_coeff * environment.uptime
3020 }
3021
3022 fn calculate_temporal_factor(&self, horizon: Duration) -> f64 {
3023 let temporal_corr = self.noise_model.temporal_correlation;
3024 let time_factor = horizon.as_secs_f64() / 3600.0; 1.0 + temporal_corr * time_factor
3027 }
3028
3029 fn calculate_base_threshold(&self, syndrome_weight: f64) -> f64 {
3030 (syndrome_weight + 1.0) / 10.0
3032 }
3033
3034 fn calculate_historical_adjustment(&self, update_rate: f64) -> f64 {
3035 if self.error_history.is_empty() {
3036 return 0.0;
3037 }
3038
3039 let recent_success_rate = self.calculate_recent_success_rate();
3040 update_rate * (0.5 - recent_success_rate) }
3042
3043 fn calculate_environmental_adjustment(&self, environment: &EnvironmentalConditions) -> f64 {
3044 let env_factor = self.calculate_environmental_factor(environment);
3045 (env_factor - 1.0) * 0.1 }
3047
3048 fn calculate_recent_success_rate(&self) -> f64 {
3049 let recent_window = 50.min(self.error_history.len());
3050 if recent_window == 0 {
3051 return 0.5;
3052 }
3053
3054 let recent_successes = self
3055 .error_history
3056 .iter()
3057 .rev()
3058 .take(recent_window)
3059 .filter(|obs| obs.success)
3060 .count();
3061
3062 recent_successes as f64 / recent_window as f64
3063 }
3064
3065 fn calculate_prediction_error(&self) -> f64 {
3066 let target_success_rate = 0.95;
3068 let actual_success_rate = self.calculate_recent_success_rate();
3069 target_success_rate - actual_success_rate
3070 }
3071
3072 fn extract_features(
3073 &self,
3074 syndrome: &[bool],
3075 environment: &EnvironmentalConditions,
3076 ) -> Vec<f64> {
3077 let mut features = vec![
3078 syndrome.iter().filter(|&&x| x).count() as f64,
3079 environment.temperature,
3080 environment.magnetic_field,
3081 environment.vibration_level,
3082 environment.emi_level,
3083 environment.uptime,
3084 ];
3085
3086 for &bit in syndrome {
3088 features.push(if bit { 1.0 } else { 0.0 });
3089 }
3090
3091 features
3092 }
3093
3094 fn get_recent_observations(&self, window: usize) -> Vec<ErrorObservation> {
3095 self.error_history
3096 .iter()
3097 .rev()
3098 .take(window)
3099 .cloned()
3100 .collect()
3101 }
3102
3103 fn linear_regression_predict(
3104 &self,
3105 _features: &[f64],
3106 training_data: &[ErrorObservation],
3107 ) -> f64 {
3108 if training_data.is_empty() {
3110 return 0.5;
3111 }
3112
3113 let avg_syndrome_weight: f64 = training_data
3114 .iter()
3115 .map(|obs| obs.syndrome.iter().filter(|&&x| x).count() as f64)
3116 .sum::<f64>()
3117 / training_data.len() as f64;
3118
3119 (avg_syndrome_weight + 1.0) / 10.0
3120 }
3121
3122 fn update_performance_tracking(&mut self, observation: &ErrorObservation) {
3123 if observation.success {
3124 self.performance_tracker.successful_corrections += 1;
3125 } else {
3126 self.performance_tracker.failed_corrections += 1;
3127 }
3128
3129 let total = self.performance_tracker.successful_corrections
3131 + self.performance_tracker.failed_corrections;
3132 if total > 0 {
3133 self.performance_tracker.threshold_accuracy =
3134 self.performance_tracker.successful_corrections as f64 / total as f64;
3135 }
3136 }
3137
3138 fn update_noise_model(&mut self) {
3139 let recent_window = self.config.min_observations.min(self.error_history.len());
3140 let recent_observations: Vec<ErrorObservation> = self
3141 .error_history
3142 .iter()
3143 .rev()
3144 .take(recent_window)
3145 .cloned()
3146 .collect();
3147
3148 self.update_single_qubit_rates(&recent_observations);
3150
3151 self.update_model_confidence(&recent_observations);
3153 }
3154
3155 fn update_single_qubit_rates(&mut self, observations: &[ErrorObservation]) {
3156 for obs in observations {
3158 for (i, pauli) in obs.correction.paulis.iter().enumerate() {
3159 if *pauli != Pauli::I {
3160 let key = (i, *pauli);
3161 let current_rate = self
3162 .noise_model
3163 .single_qubit_rates
3164 .get(&key)
3165 .copied()
3166 .unwrap_or(0.001);
3167 let new_rate = if obs.success {
3168 current_rate * 0.99
3169 } else {
3170 current_rate * 1.01
3171 };
3172 self.noise_model.single_qubit_rates.insert(key, new_rate);
3173 }
3174 }
3175 }
3176 }
3177
3178 fn update_model_confidence(&mut self, observations: &[ErrorObservation]) {
3179 if observations.is_empty() {
3180 return;
3181 }
3182
3183 let success_rate = observations.iter().filter(|obs| obs.success).count() as f64
3184 / observations.len() as f64;
3185
3186 let stability = 1.0 - (success_rate - 0.5).abs() * 2.0;
3188 self.noise_model.confidence = self.noise_model.confidence * 0.95 + stability * 0.05;
3189 }
3190
3191 fn assess_recommendation_quality(&self) -> f64 {
3192 let confidence_component = self.noise_model.confidence;
3194 let performance_component = self.performance_tracker.threshold_accuracy;
3195 let history_component =
3196 (self.error_history.len() as f64 / self.config.max_history_size as f64).min(1.0);
3197
3198 (confidence_component + performance_component + history_component) / 3.0
3199 }
3200
3201 fn assess_environmental_impact(&self, environment: &EnvironmentalConditions) -> f64 {
3202 let env_factor = self.calculate_environmental_factor(environment);
3203 (env_factor - 1.0).abs()
3204 }
3205 }
3206}
3207
3208#[cfg(test)]
3209mod tests {
3210 use super::*;
3211
3212 #[test]
3213 fn test_pauli_multiplication() {
3214 let (phase, result) = Pauli::X.multiply(&Pauli::Y);
3215 assert_eq!(result, Pauli::Z);
3216 assert_eq!(phase, Complex64::new(0.0, 1.0));
3217 }
3218
3219 #[test]
3220 fn test_pauli_string_commutation() {
3221 let ps1 = PauliString::new(vec![Pauli::X, Pauli::I]);
3222 let ps2 = PauliString::new(vec![Pauli::Z, Pauli::I]);
3223 assert!(!ps1.commutes_with(&ps2).unwrap());
3224
3225 let ps3 = PauliString::new(vec![Pauli::X, Pauli::I]);
3226 let ps4 = PauliString::new(vec![Pauli::I, Pauli::Z]);
3227 assert!(ps3.commutes_with(&ps4).unwrap());
3228 }
3229
3230 #[test]
3231 fn test_repetition_code() {
3232 let code = StabilizerCode::repetition_code();
3233 assert_eq!(code.n, 3);
3234 assert_eq!(code.k, 1);
3235 assert_eq!(code.d, 1);
3236
3237 let error = PauliString::new(vec![Pauli::X, Pauli::I, Pauli::I]);
3239 let syndrome = code.syndrome(&error).unwrap();
3240 assert_eq!(syndrome, vec![true, false]);
3242 }
3243
3244 #[test]
3245 fn test_steane_code() {
3246 let code = StabilizerCode::steane_code();
3247 assert_eq!(code.n, 7);
3248 assert_eq!(code.k, 1);
3249 assert_eq!(code.d, 3);
3250
3251 for i in 0..code.stabilizers.len() {
3253 for j in i + 1..code.stabilizers.len() {
3254 assert!(code.stabilizers[i]
3255 .commutes_with(&code.stabilizers[j])
3256 .unwrap());
3257 }
3258 }
3259 }
3260
3261 #[test]
3262 fn test_surface_code() {
3263 let surface = SurfaceCode::new(3, 3);
3264 assert_eq!(surface.distance(), 3);
3265
3266 let code = surface.to_stabilizer_code();
3267 assert_eq!(code.n, 9);
3268 assert_eq!(code.stabilizers.len(), 4);
3270 }
3271
3272 #[test]
3273 fn test_lookup_decoder() {
3274 let code = StabilizerCode::repetition_code();
3275 let decoder = LookupDecoder::new(&code).unwrap();
3276
3277 let trivial_syndrome = vec![false, false];
3279 let decoded = decoder.decode(&trivial_syndrome).unwrap();
3280 assert_eq!(decoded.weight(), 0); let error = PauliString::new(vec![Pauli::X, Pauli::I, Pauli::I]);
3284 let syndrome = code.syndrome(&error).unwrap();
3285
3286 if let Ok(decoded_error) = decoder.decode(&syndrome) {
3288 assert!(decoded_error.weight() <= 1);
3290 }
3291 }
3292
3293 #[test]
3294 fn test_concatenated_codes() {
3295 let inner_code = StabilizerCode::repetition_code();
3296 let outer_code = StabilizerCode::repetition_code();
3297 let concat_code = ConcatenatedCode::new(inner_code, outer_code);
3298
3299 assert_eq!(concat_code.total_qubits(), 9); assert_eq!(concat_code.logical_qubits(), 1);
3301 assert_eq!(concat_code.distance(), 1); let logical_state = vec![Complex64::new(1.0, 0.0), Complex64::new(0.0, 0.0)];
3305 let encoded = concat_code.encode(&logical_state).unwrap();
3306 assert_eq!(encoded.len(), 512); let error = PauliString::new(vec![
3310 Pauli::X,
3311 Pauli::I,
3312 Pauli::I,
3313 Pauli::I,
3314 Pauli::I,
3315 Pauli::I,
3316 Pauli::I,
3317 Pauli::I,
3318 Pauli::I,
3319 ]);
3320 let corrected = concat_code.correct_error(&encoded, &error).unwrap();
3321
3322 assert_eq!(corrected.len(), 512);
3324 }
3325
3326 #[test]
3327 fn test_hypergraph_product_codes() {
3328 let h1 = Array2::from_shape_vec((2, 3), vec![1, 1, 0, 0, 1, 1]).unwrap();
3330 let h2 = Array2::from_shape_vec((2, 3), vec![1, 0, 1, 1, 1, 0]).unwrap();
3331
3332 let hpc = HypergraphProductCode::new(h1, h2);
3333
3334 assert_eq!(hpc.n, 12); assert_eq!(hpc.k, 1); let stab_code = hpc.to_stabilizer_code();
3339 assert!(!stab_code.stabilizers.is_empty());
3340 }
3341
3342 #[test]
3343 fn test_quantum_ldpc_codes() {
3344 let qldpc = QuantumLDPCCode::bicycle_code(3, 4);
3345 assert_eq!(qldpc.n, 24); assert_eq!(qldpc.k, 2);
3347
3348 let stab_code = qldpc.to_stabilizer_code();
3349 assert!(!stab_code.stabilizers.is_empty());
3350
3351 for stabilizer in &stab_code.stabilizers {
3353 assert!(stabilizer.weight() <= qldpc.max_weight);
3354 }
3355 }
3356
3357 #[test]
3358 fn test_topological_codes() {
3359 let toric = ToricCode::new(2, 2);
3360 assert_eq!(toric.logical_qubits(), 2);
3361 assert_eq!(toric.distance(), 2);
3362
3363 let stab_code = toric.to_stabilizer_code();
3364 assert_eq!(stab_code.n, 8); assert_eq!(stab_code.k, 2);
3366
3367 for i in 0..stab_code.stabilizers.len() {
3369 for j in i + 1..stab_code.stabilizers.len() {
3370 assert!(stab_code.stabilizers[i]
3371 .commutes_with(&stab_code.stabilizers[j])
3372 .unwrap());
3373 }
3374 }
3375 }
3376
3377 #[test]
3378 fn test_ml_decoder() {
3379 let surface = SurfaceCode::new(3, 3);
3380 let decoder = MLDecoder::new(surface.to_stabilizer_code());
3381
3382 let syndrome = vec![true, false, true, false];
3384 let decoded = decoder.decode(&syndrome);
3385
3386 assert!(decoded.is_ok() || syndrome.iter().filter(|&&x| x).count() % 2 == 1);
3388 }
3389
3390 #[test]
3391 fn test_real_time_mock_hardware() {
3392 use crate::error_correction::real_time::*;
3393 use std::time::Duration;
3394
3395 let hardware = MockQuantumHardware::new(0.01, Duration::from_micros(10), 4);
3396
3397 let syndrome = hardware.measure_syndromes().unwrap();
3399 assert_eq!(syndrome.len(), 4);
3400
3401 let characteristics = hardware.get_error_characteristics().unwrap();
3403 assert_eq!(characteristics.single_qubit_error_rates.len(), 4);
3404
3405 let stats = hardware.get_latency_stats().unwrap();
3407 assert!(stats.throughput_hz > 0.0);
3408
3409 assert!(hardware.is_ready());
3410 }
3411
3412 #[test]
3413 fn test_real_time_performance_monitor() {
3414 use crate::error_correction::real_time::*;
3415 use std::time::Duration;
3416
3417 let mut monitor = PerformanceMonitor::new();
3418
3419 monitor.record_cycle(Duration::from_micros(10), true);
3421 monitor.record_cycle(Duration::from_micros(20), false);
3422 monitor.record_cycle(Duration::from_micros(15), true);
3423
3424 assert_eq!(monitor.cycles_processed, 3);
3425 assert_eq!(monitor.errors_corrected, 2);
3426 assert_eq!(monitor.error_correction_rate(), 2.0 / 3.0);
3427 assert!(monitor.average_latency().as_micros() > 10);
3428 assert!(monitor.current_throughput() > 0.0);
3429 }
3430
3431 #[test]
3432 fn test_real_time_adaptive_decoder() {
3433 use crate::error_correction::real_time::*;
3434 use std::sync::Arc;
3435
3436 let code = StabilizerCode::repetition_code();
3437 let base_decoder = Arc::new(LookupDecoder::new(&code).unwrap());
3438 let characteristics = HardwareErrorCharacteristics {
3439 single_qubit_error_rates: vec![0.01; 3],
3440 two_qubit_error_rates: vec![0.1; 1],
3441 measurement_error_rates: vec![0.001; 3],
3442 correlated_errors: Vec::new(),
3443 temporal_variation: 0.01,
3444 };
3445
3446 let mut adaptive_decoder = AdaptiveThresholdDecoder::new(base_decoder, characteristics);
3447
3448 let initial_threshold = adaptive_decoder.current_threshold();
3450 assert_eq!(initial_threshold, 1.0); adaptive_decoder.adapt_thresholds(&[false, false], true); let new_threshold = adaptive_decoder.current_threshold();
3456 assert!(new_threshold != initial_threshold); let syndrome = vec![false, false]; let result = adaptive_decoder.decode(&syndrome);
3461 assert!(result.is_ok(), "Decoding failed: {:?}", result.err());
3462 }
3463
3464 #[test]
3465 fn test_real_time_parallel_decoder() {
3466 use crate::error_correction::real_time::*;
3467 use std::sync::Arc;
3468
3469 let code = StabilizerCode::repetition_code();
3470 let base_decoder = Arc::new(LookupDecoder::new(&code).unwrap());
3471 let parallel_decoder = ParallelSyndromeDecoder::new(base_decoder, 2);
3472
3473 let syndrome = vec![false, false]; let result = parallel_decoder.decode(&syndrome);
3476 assert!(result.is_ok(), "Decoding failed: {:?}", result.err());
3477
3478 let syndromes = vec![
3480 vec![false, false], vec![false, false],
3482 vec![false, false],
3483 vec![false, false],
3484 ];
3485
3486 let results = parallel_decoder.decode_batch(&syndromes);
3487 assert!(results.is_ok());
3488 let corrections = results.unwrap();
3489 assert_eq!(corrections.len(), 4);
3490 }
3491
3492 #[test]
3493 fn test_real_time_syndrome_stream_processor() {
3494 use crate::error_correction::real_time::*;
3495 use std::sync::Arc;
3496 use std::time::Duration;
3497
3498 let code = StabilizerCode::repetition_code();
3499 let decoder = Arc::new(LookupDecoder::new(&code).unwrap());
3500 let hardware = Arc::new(MockQuantumHardware::new(0.01, Duration::from_micros(1), 3));
3501 let config = RealTimeConfig {
3502 max_latency: Duration::from_millis(1),
3503 buffer_size: 10,
3504 parallel_workers: 1,
3505 adaptive_threshold: false,
3506 hardware_feedback: false,
3507 performance_logging: true,
3508 };
3509
3510 let processor = SyndromeStreamProcessor::new(decoder, hardware, config);
3511
3512 let (current, max) = processor.get_buffer_status();
3514 assert_eq!(current, 0);
3515 assert_eq!(max, 10);
3516
3517 let stats = processor.get_performance_stats();
3519 assert_eq!(stats.cycles_processed, 0);
3520 assert_eq!(stats.errors_corrected, 0);
3521 }
3522
3523 #[test]
3524 fn test_logical_gate_synthesizer() {
3525 use crate::error_correction::logical_gates::*;
3526
3527 let code = StabilizerCode::repetition_code();
3528 let synthesizer = LogicalGateSynthesizer::new(0.01);
3529
3530 let logical_x = synthesizer.synthesize_logical_x(&code, 0);
3532 assert!(logical_x.is_ok());
3533
3534 let x_gate = logical_x.unwrap();
3535 assert_eq!(x_gate.logical_qubits, vec![0]);
3536 assert_eq!(x_gate.physical_operations.len(), 1);
3537 assert!(!x_gate.error_propagation.single_qubit_propagation.is_empty());
3538
3539 let logical_z = synthesizer.synthesize_logical_z(&code, 0);
3541 assert!(logical_z.is_ok());
3542
3543 let z_gate = logical_z.unwrap();
3544 assert_eq!(z_gate.logical_qubits, vec![0]);
3545 assert_eq!(z_gate.physical_operations.len(), 1);
3546
3547 let logical_h = synthesizer.synthesize_logical_h(&code, 0);
3549 assert!(logical_h.is_ok());
3550
3551 let h_gate = logical_h.unwrap();
3552 assert_eq!(h_gate.logical_qubits, vec![0]);
3553 assert_eq!(h_gate.physical_operations.len(), 1);
3554 assert_eq!(h_gate.physical_operations[0].error_correction_rounds, 2);
3555
3556 let invalid_gate = synthesizer.synthesize_logical_x(&code, 5);
3558 assert!(invalid_gate.is_err());
3559 }
3560
3561 #[test]
3562 fn test_logical_circuit_synthesizer() {
3563 use crate::error_correction::logical_gates::*;
3564
3565 let code = StabilizerCode::repetition_code();
3566 let synthesizer = LogicalCircuitSynthesizer::new(0.01);
3567
3568 let gate_sequence = vec![("x", vec![0]), ("h", vec![0]), ("z", vec![0])];
3570
3571 let circuit = synthesizer.synthesize_circuit(&code, &gate_sequence);
3572 assert!(circuit.is_ok());
3573
3574 let logical_circuit = circuit.unwrap();
3575 assert_eq!(logical_circuit.len(), 3);
3576
3577 let resources = synthesizer.estimate_resources(&logical_circuit);
3579 assert!(resources.total_physical_operations > 0);
3580 assert!(resources.total_error_correction_rounds > 0);
3581 assert_eq!(resources.estimated_depth, 3);
3582
3583 let invalid_sequence = vec![("invalid_gate", vec![0])];
3585 let invalid_circuit = synthesizer.synthesize_circuit(&code, &invalid_sequence);
3586 assert!(invalid_circuit.is_err());
3587
3588 let wrong_cnot = vec![("cnot", vec![0])]; let wrong_circuit = synthesizer.synthesize_circuit(&code, &wrong_cnot);
3591 assert!(wrong_circuit.is_err());
3592 }
3593
3594 #[test]
3595 fn test_logical_t_gate_synthesis() {
3596 use crate::error_correction::logical_gates::*;
3597
3598 let code = StabilizerCode::repetition_code();
3599 let synthesizer = LogicalGateSynthesizer::new(0.01);
3600
3601 let logical_t = synthesizer.synthesize_logical_t(&code, 0);
3603 assert!(logical_t.is_ok());
3604
3605 let t_gate = logical_t.unwrap();
3606 assert_eq!(t_gate.logical_qubits, vec![0]);
3607 assert_eq!(t_gate.physical_operations.len(), 2); assert!(t_gate.physical_operations[0].error_correction_rounds >= 5);
3611 }
3612
3613 #[test]
3614 fn test_error_propagation_analysis() {
3615 use crate::error_correction::logical_gates::*;
3616
3617 let code = StabilizerCode::repetition_code();
3618 let synthesizer = LogicalGateSynthesizer::new(0.01);
3619
3620 let logical_x = synthesizer.synthesize_logical_x(&code, 0).unwrap();
3621
3622 let analysis = &logical_x.error_propagation;
3624 assert!(!analysis.single_qubit_propagation.is_empty());
3625 assert_eq!(analysis.fault_tolerance_threshold, 0.01);
3627
3628 let correctable_count = analysis
3630 .single_qubit_propagation
3631 .iter()
3632 .filter(|path| path.correctable)
3633 .count();
3634 assert!(correctable_count > 0);
3635 }
3636
3637 #[test]
3638 fn test_pauli_string_weight() {
3639 let identity_string = PauliString::new(vec![Pauli::I, Pauli::I, Pauli::I]);
3640 assert_eq!(identity_string.weight(), 0);
3641
3642 let single_error = PauliString::new(vec![Pauli::X, Pauli::I, Pauli::I]);
3643 assert_eq!(single_error.weight(), 1);
3644
3645 let multi_error = PauliString::new(vec![Pauli::X, Pauli::Y, Pauli::Z]);
3646 assert_eq!(multi_error.weight(), 3);
3647 }
3648
3649 #[test]
3650 fn test_logical_circuit_with_multiple_gates() {
3651 use crate::error_correction::logical_gates::*;
3652
3653 let code = StabilizerCode::repetition_code();
3654 let synthesizer = LogicalCircuitSynthesizer::new(0.01);
3655
3656 let gate_sequence = vec![
3658 ("h", vec![0]), ("x", vec![0]), ("z", vec![0]), ("h", vec![0]), ];
3663
3664 let circuit = synthesizer.synthesize_circuit(&code, &gate_sequence);
3665 assert!(circuit.is_ok());
3666
3667 let logical_circuit = circuit.unwrap();
3668 assert_eq!(logical_circuit.len(), 4);
3669
3670 for gate in &logical_circuit {
3672 assert_eq!(gate.logical_qubits, vec![0]);
3673 }
3674
3675 let resources = synthesizer.estimate_resources(&logical_circuit);
3677 assert_eq!(resources.estimated_depth, 4);
3678 assert!(resources.total_error_correction_rounds >= 4); }
3680
3681 #[test]
3682 fn test_adaptive_threshold_estimator() {
3683 use crate::error_correction::adaptive_threshold::*;
3684
3685 let noise_model = NoiseModel::default();
3686 let algorithm = ThresholdEstimationAlgorithm::Bayesian {
3687 prior_strength: 1.0,
3688 update_rate: 0.1,
3689 };
3690 let config = AdaptiveConfig::default();
3691
3692 let mut estimator = AdaptiveThresholdEstimator::new(noise_model, algorithm, config);
3693
3694 let syndrome = vec![true, false];
3696 let env = EnvironmentalConditions::default();
3697 let threshold = estimator.estimate_threshold(&syndrome, &env);
3698 assert!(threshold > 0.0);
3699 assert!(threshold < 1.0);
3700
3701 let observation = ErrorObservation {
3703 syndrome: syndrome.clone(),
3704 correction: PauliString::new(vec![Pauli::X, Pauli::I]),
3705 success: true,
3706 observed_error_rate: 0.01,
3707 timestamp: std::time::Instant::now(),
3708 environment: env.clone(),
3709 };
3710
3711 estimator.add_observation(observation);
3712
3713 let recommendation = estimator.get_threshold_recommendation(&syndrome);
3715 assert!(recommendation.threshold > 0.0);
3716 assert!(recommendation.confidence >= 0.0 && recommendation.confidence <= 1.0);
3717 assert!(recommendation.predicted_error_rate >= 0.0);
3718 }
3719
3720 #[test]
3721 fn test_performance_tracker() {
3722 use crate::error_correction::adaptive_threshold::*;
3723
3724 let mut tracker = PerformanceTracker::new();
3725
3726 assert_eq!(tracker.successful_corrections, 0);
3728 assert_eq!(tracker.failed_corrections, 0);
3729 assert_eq!(tracker.precision(), 1.0); assert_eq!(tracker.recall(), 1.0);
3731 assert_eq!(tracker.f1_score(), 1.0); tracker.successful_corrections = 8;
3735 tracker.failed_corrections = 2;
3736 tracker.false_positives = 1;
3737 tracker.false_negatives = 1;
3738
3739 assert_eq!(tracker.precision(), 8.0 / 9.0); assert_eq!(tracker.recall(), 8.0 / 9.0); assert!(tracker.f1_score() > 0.0);
3743 }
3744
3745 #[test]
3746 fn test_environmental_conditions() {
3747 use crate::error_correction::adaptive_threshold::*;
3748
3749 let mut env = EnvironmentalConditions::default();
3750 assert_eq!(env.temperature, 300.0); assert_eq!(env.magnetic_field, 0.0);
3752
3753 env.temperature = 310.0; env.vibration_level = 0.1;
3756
3757 let noise_model = NoiseModel::default();
3758 let algorithm = ThresholdEstimationAlgorithm::ExponentialAverage { alpha: 0.5 };
3759 let config = AdaptiveConfig::default();
3760
3761 let estimator = AdaptiveThresholdEstimator::new(noise_model, algorithm, config);
3762
3763 let syndrome = vec![false, false];
3765 let threshold_normal =
3766 estimator.estimate_threshold(&syndrome, &EnvironmentalConditions::default());
3767 let threshold_hot = estimator.estimate_threshold(&syndrome, &env);
3768
3769 assert!(threshold_normal >= 0.0);
3771 assert!(threshold_hot >= 0.0);
3772 }
3773
3774 #[test]
3775 fn test_different_threshold_algorithms() {
3776 use crate::error_correction::adaptive_threshold::*;
3777
3778 let noise_model = NoiseModel::default();
3779 let config = AdaptiveConfig::default();
3780
3781 let bayesian_alg = ThresholdEstimationAlgorithm::Bayesian {
3783 prior_strength: 1.0,
3784 update_rate: 0.1,
3785 };
3786 let bayesian_estimator =
3787 AdaptiveThresholdEstimator::new(noise_model.clone(), bayesian_alg, config.clone());
3788
3789 let kalman_alg = ThresholdEstimationAlgorithm::KalmanFilter {
3791 process_noise: 0.01,
3792 measurement_noise: 0.1,
3793 };
3794 let kalman_estimator =
3795 AdaptiveThresholdEstimator::new(noise_model.clone(), kalman_alg, config.clone());
3796
3797 let exp_alg = ThresholdEstimationAlgorithm::ExponentialAverage { alpha: 0.3 };
3799 let exp_estimator =
3800 AdaptiveThresholdEstimator::new(noise_model.clone(), exp_alg, config.clone());
3801
3802 let ml_alg = ThresholdEstimationAlgorithm::MachineLearning {
3804 model_type: MLModelType::LinearRegression,
3805 training_window: 50,
3806 };
3807 let ml_estimator = AdaptiveThresholdEstimator::new(noise_model, ml_alg, config);
3808
3809 let syndrome = vec![true, false];
3810 let env = EnvironmentalConditions::default();
3811
3812 let bayesian_threshold = bayesian_estimator.estimate_threshold(&syndrome, &env);
3814 let kalman_threshold = kalman_estimator.estimate_threshold(&syndrome, &env);
3815 let exp_threshold = exp_estimator.estimate_threshold(&syndrome, &env);
3816 let ml_threshold = ml_estimator.estimate_threshold(&syndrome, &env);
3817
3818 assert!(bayesian_threshold > 0.0);
3819 assert!(kalman_threshold > 0.0);
3820 assert!(exp_threshold > 0.0);
3821 assert!(ml_threshold > 0.0);
3822 }
3823
3824 #[test]
3825 fn test_noise_model_updates() {
3826 use crate::error_correction::adaptive_threshold::*;
3827
3828 let noise_model = NoiseModel::default();
3829 let algorithm = ThresholdEstimationAlgorithm::Bayesian {
3830 prior_strength: 1.0,
3831 update_rate: 0.1,
3832 };
3833 let config = AdaptiveConfig {
3834 min_observations: 2, real_time_adaptation: true,
3836 ..AdaptiveConfig::default()
3837 };
3838
3839 let mut estimator = AdaptiveThresholdEstimator::new(noise_model, algorithm, config);
3840
3841 for i in 0..5 {
3843 let observation = ErrorObservation {
3844 syndrome: vec![i % 2 == 0, i % 3 == 0],
3845 correction: PauliString::new(vec![Pauli::X, Pauli::I]),
3846 success: i % 4 != 0, observed_error_rate: 0.01,
3848 timestamp: std::time::Instant::now(),
3849 environment: EnvironmentalConditions::default(),
3850 };
3851 estimator.add_observation(observation);
3852 }
3853
3854 let recommendation = estimator.get_threshold_recommendation(&[true, false]);
3856 assert!(recommendation.confidence > 0.0);
3857 assert!(recommendation.recommendation_quality > 0.0);
3858 }
3859}