1use crate::error::{QuantRS2Error, QuantRS2Result};
8use ndarray::Array2;
9use num_complex::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 coords = [
1196 (2 * r, c),
1197 (2 * r + 1, c),
1198 (2 * ((r + self.rows - 1) % self.rows), c),
1199 (2 * r + 1, (c + self.cols - 1) % self.cols),
1200 ];
1201
1202 for &coord in &coords {
1203 if let Some(&qubit) = self.qubit_map.get(&coord) {
1204 paulis[qubit] = Pauli::X;
1205 }
1206 }
1207
1208 stabilizers.push(PauliString::new(paulis));
1209 }
1210 }
1211
1212 for r in 0..self.rows {
1214 for c in 0..self.cols {
1215 let mut paulis = vec![Pauli::I; n];
1216
1217 let coords = [
1219 (2 * r, c),
1220 (2 * r, (c + 1) % self.cols),
1221 (2 * r + 1, c),
1222 (2 * ((r + 1) % self.rows), c),
1223 ];
1224
1225 for &coord in &coords {
1226 if let Some(&qubit) = self.qubit_map.get(&coord) {
1227 paulis[qubit] = Pauli::Z;
1228 }
1229 }
1230
1231 stabilizers.push(PauliString::new(paulis));
1232 }
1233 }
1234
1235 let mut logical_x1 = vec![Pauli::I; n];
1237 let mut logical_z1 = vec![Pauli::I; n];
1238 let mut logical_x2 = vec![Pauli::I; n];
1239 let mut logical_z2 = vec![Pauli::I; n];
1240
1241 for c in 0..self.cols {
1243 if let Some(&qubit) = self.qubit_map.get(&(0, c)) {
1244 logical_x1[qubit] = Pauli::X;
1245 }
1246 if let Some(&qubit) = self.qubit_map.get(&(1, c)) {
1247 logical_z2[qubit] = Pauli::Z;
1248 }
1249 }
1250
1251 for r in 0..self.rows {
1253 if let Some(&qubit) = self.qubit_map.get(&(2 * r + 1, 0)) {
1254 logical_x2[qubit] = Pauli::X;
1255 }
1256 if let Some(&qubit) = self.qubit_map.get(&(2 * r, 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; let mut weights = Vec::new();
1285
1286 let mut w1 = Vec::new();
1288 for _ in 0..hidden_size {
1289 let mut row = Vec::new();
1290 for _ in 0..input_size {
1291 row.push((rand::random::<f64>() - 0.5) * 0.1);
1292 }
1293 w1.push(row);
1294 }
1295 weights.push(w1.into_iter().flatten().collect());
1296
1297 let mut w2 = Vec::new();
1299 for _ in 0..output_size {
1300 let mut row = Vec::new();
1301 for _ in 0..hidden_size {
1302 row.push((rand::random::<f64>() - 0.5) * 0.1);
1303 }
1304 w2.push(row);
1305 }
1306 weights.push(w2.into_iter().flatten().collect());
1307
1308 Self { code, weights }
1309 }
1310
1311 fn predict(&self, syndrome: &[bool]) -> Vec<f64> {
1313 let input: Vec<f64> = syndrome
1314 .iter()
1315 .map(|&b| if b { 1.0 } else { 0.0 })
1316 .collect();
1317
1318 let hidden_size = 2 * input.len();
1321 let mut hidden = vec![0.0; hidden_size];
1322
1323 for i in 0..hidden_size {
1325 for j in 0..input.len() {
1326 if i * input.len() + j < self.weights[0].len() {
1327 hidden[i] += input[j] * self.weights[0][i * input.len() + j];
1328 }
1329 }
1330 hidden[i] = hidden[i].tanh(); }
1332
1333 let output_size = self.code.n * 3;
1335 let mut output = vec![0.0; output_size];
1336
1337 for i in 0..output_size {
1338 for j in 0..hidden_size {
1339 if i * hidden_size + j < self.weights[1].len() {
1340 output[i] += hidden[j] * self.weights[1][i * hidden_size + j];
1341 }
1342 }
1343 }
1344
1345 output
1346 }
1347}
1348
1349impl SyndromeDecoder for MLDecoder {
1350 fn decode(&self, syndrome: &[bool]) -> QuantRS2Result<PauliString> {
1351 let prediction = self.predict(syndrome);
1352
1353 let mut paulis = Vec::with_capacity(self.code.n);
1355
1356 for qubit in 0..self.code.n {
1357 let base_idx = qubit * 3;
1358 if base_idx + 2 < prediction.len() {
1359 let x_prob = prediction[base_idx];
1360 let y_prob = prediction[base_idx + 1];
1361 let z_prob = prediction[base_idx + 2];
1362
1363 if x_prob > y_prob && x_prob > z_prob && x_prob > 0.5 {
1365 paulis.push(Pauli::X);
1366 } else if y_prob > z_prob && y_prob > 0.5 {
1367 paulis.push(Pauli::Y);
1368 } else if z_prob > 0.5 {
1369 paulis.push(Pauli::Z);
1370 } else {
1371 paulis.push(Pauli::I);
1372 }
1373 } else {
1374 paulis.push(Pauli::I);
1375 }
1376 }
1377
1378 Ok(PauliString::new(paulis))
1379 }
1380}
1381
1382pub mod real_time {
1386 use super::*;
1387 use std::collections::VecDeque;
1388 use std::sync::{Arc, Mutex, RwLock};
1389 use std::thread;
1390 use std::time::{Duration, Instant};
1391
1392 pub trait QuantumHardwareInterface: Send + Sync {
1394 fn measure_syndromes(&self) -> QuantRS2Result<Vec<bool>>;
1396
1397 fn apply_correction(&self, correction: &PauliString) -> QuantRS2Result<()>;
1399
1400 fn get_error_characteristics(&self) -> QuantRS2Result<HardwareErrorCharacteristics>;
1402
1403 fn is_ready(&self) -> bool;
1405
1406 fn get_latency_stats(&self) -> QuantRS2Result<LatencyStats>;
1408 }
1409
1410 #[derive(Debug, Clone)]
1412 pub struct HardwareErrorCharacteristics {
1413 pub single_qubit_error_rates: Vec<f64>,
1415 pub two_qubit_error_rates: Vec<f64>,
1417 pub measurement_error_rates: Vec<f64>,
1419 pub correlated_errors: Vec<CorrelatedErrorPattern>,
1421 pub temporal_variation: f64,
1423 }
1424
1425 #[derive(Debug, Clone)]
1427 pub struct CorrelatedErrorPattern {
1428 pub qubits: Vec<usize>,
1429 pub probability: f64,
1430 pub pauli_pattern: PauliString,
1431 }
1432
1433 #[derive(Debug, Clone)]
1435 pub struct LatencyStats {
1436 pub syndrome_measurement_time: Duration,
1437 pub decoding_time: Duration,
1438 pub correction_application_time: Duration,
1439 pub total_cycle_time: Duration,
1440 pub throughput_hz: f64,
1441 }
1442
1443 pub struct SyndromeStreamProcessor {
1445 buffer: Arc<Mutex<VecDeque<SyndromePacket>>>,
1446 decoder: Arc<dyn SyndromeDecoder + Send + Sync>,
1447 hardware: Arc<dyn QuantumHardwareInterface>,
1448 performance_monitor: Arc<RwLock<PerformanceMonitor>>,
1449 config: RealTimeConfig,
1450 }
1451
1452 #[derive(Debug, Clone)]
1454 pub struct SyndromePacket {
1455 pub syndrome: Vec<bool>,
1456 pub timestamp: Instant,
1457 pub sequence_number: u64,
1458 pub measurement_fidelity: f64,
1459 }
1460
1461 #[derive(Debug, Clone)]
1463 pub struct RealTimeConfig {
1464 pub max_latency: Duration,
1465 pub buffer_size: usize,
1466 pub parallel_workers: usize,
1467 pub adaptive_threshold: bool,
1468 pub hardware_feedback: bool,
1469 pub performance_logging: bool,
1470 }
1471
1472 impl Default for RealTimeConfig {
1473 fn default() -> Self {
1474 Self {
1475 max_latency: Duration::from_micros(100), buffer_size: 1000,
1477 parallel_workers: 4,
1478 adaptive_threshold: true,
1479 hardware_feedback: true,
1480 performance_logging: true,
1481 }
1482 }
1483 }
1484
1485 #[derive(Debug, Clone)]
1487 pub struct PerformanceMonitor {
1488 pub cycles_processed: u64,
1489 pub errors_corrected: u64,
1490 pub false_positives: u64,
1491 pub latency_histogram: Vec<Duration>,
1492 pub throughput_samples: VecDeque<f64>,
1493 pub start_time: Instant,
1494 }
1495
1496 impl PerformanceMonitor {
1497 pub fn new() -> Self {
1498 Self {
1499 cycles_processed: 0,
1500 errors_corrected: 0,
1501 false_positives: 0,
1502 latency_histogram: Vec::new(),
1503 throughput_samples: VecDeque::new(),
1504 start_time: Instant::now(),
1505 }
1506 }
1507
1508 pub fn record_cycle(&mut self, latency: Duration, error_corrected: bool) {
1509 self.cycles_processed += 1;
1510 if error_corrected {
1511 self.errors_corrected += 1;
1512 }
1513 self.latency_histogram.push(latency);
1514
1515 let elapsed = self.start_time.elapsed();
1517 if elapsed.as_secs_f64() > 0.0 {
1518 let throughput = self.cycles_processed as f64 / elapsed.as_secs_f64();
1519 self.throughput_samples.push_back(throughput);
1520
1521 if self.throughput_samples.len() > 100 {
1523 self.throughput_samples.pop_front();
1524 }
1525 }
1526 }
1527
1528 pub fn average_latency(&self) -> Duration {
1529 if self.latency_histogram.is_empty() {
1530 return Duration::from_nanos(0);
1531 }
1532
1533 let total_nanos: u64 = self
1534 .latency_histogram
1535 .iter()
1536 .map(|d| d.as_nanos() as u64)
1537 .sum();
1538 Duration::from_nanos(total_nanos / self.latency_histogram.len() as u64)
1539 }
1540
1541 pub fn current_throughput(&self) -> f64 {
1542 self.throughput_samples.back().copied().unwrap_or(0.0)
1543 }
1544
1545 pub fn error_correction_rate(&self) -> f64 {
1546 if self.cycles_processed == 0 {
1547 0.0
1548 } else {
1549 self.errors_corrected as f64 / self.cycles_processed as f64
1550 }
1551 }
1552 }
1553
1554 impl SyndromeStreamProcessor {
1555 pub fn new(
1557 decoder: Arc<dyn SyndromeDecoder + Send + Sync>,
1558 hardware: Arc<dyn QuantumHardwareInterface>,
1559 config: RealTimeConfig,
1560 ) -> Self {
1561 Self {
1562 buffer: Arc::new(Mutex::new(VecDeque::with_capacity(config.buffer_size))),
1563 decoder,
1564 hardware,
1565 performance_monitor: Arc::new(RwLock::new(PerformanceMonitor::new())),
1566 config,
1567 }
1568 }
1569
1570 pub fn start_processing(&self) -> QuantRS2Result<thread::JoinHandle<()>> {
1572 let buffer = Arc::clone(&self.buffer);
1573 let decoder = Arc::clone(&self.decoder);
1574 let hardware = Arc::clone(&self.hardware);
1575 let monitor = Arc::clone(&self.performance_monitor);
1576 let config = self.config.clone();
1577
1578 let handle = thread::spawn(move || {
1579 let mut sequence_number = 0u64;
1580
1581 loop {
1582 let cycle_start = Instant::now();
1583
1584 if !hardware.is_ready() {
1586 thread::sleep(Duration::from_micros(10));
1587 continue;
1588 }
1589
1590 match hardware.measure_syndromes() {
1592 Ok(syndrome) => {
1593 let packet = SyndromePacket {
1594 syndrome: syndrome.clone(),
1595 timestamp: Instant::now(),
1596 sequence_number,
1597 measurement_fidelity: 0.99, };
1599
1600 {
1602 let mut buf = buffer.lock().unwrap();
1603 if buf.len() >= config.buffer_size {
1604 buf.pop_front(); }
1606 buf.push_back(packet);
1607 }
1608
1609 let has_error = syndrome.iter().any(|&x| x);
1611 let mut error_corrected = false;
1612
1613 if has_error {
1614 match decoder.decode(&syndrome) {
1615 Ok(correction) => {
1616 match hardware.apply_correction(&correction) {
1617 Ok(()) => {
1618 error_corrected = true;
1619 }
1620 Err(e) => {
1621 eprintln!("Failed to apply correction: {}", e);
1622 }
1623 }
1624 }
1625 Err(e) => {
1626 eprintln!("Decoding failed: {}", e);
1627 }
1628 }
1629 }
1630
1631 let cycle_time = cycle_start.elapsed();
1633 {
1634 let mut mon = monitor.write().unwrap();
1635 mon.record_cycle(cycle_time, error_corrected);
1636 }
1637
1638 if cycle_time > config.max_latency {
1640 eprintln!("Warning: Error correction cycle exceeded max latency: {:?} > {:?}",
1641 cycle_time, config.max_latency);
1642 }
1643
1644 sequence_number += 1;
1645 }
1646 Err(e) => {
1647 eprintln!("Failed to measure syndromes: {}", e);
1648 thread::sleep(Duration::from_micros(10));
1649 }
1650 }
1651
1652 thread::sleep(Duration::from_micros(1));
1654 }
1655 });
1656
1657 Ok(handle)
1658 }
1659
1660 pub fn get_performance_stats(&self) -> PerformanceMonitor {
1662 (*self.performance_monitor.read().unwrap()).clone()
1663 }
1664
1665 pub fn get_buffer_status(&self) -> (usize, usize) {
1667 let buffer = self.buffer.lock().unwrap();
1668 (buffer.len(), self.config.buffer_size)
1669 }
1670 }
1671
1672 pub struct AdaptiveThresholdDecoder {
1674 base_decoder: Arc<dyn SyndromeDecoder + Send + Sync>,
1675 error_characteristics: Arc<RwLock<HardwareErrorCharacteristics>>,
1676 learning_rate: f64,
1677 threshold_history: VecDeque<f64>,
1678 }
1679
1680 impl AdaptiveThresholdDecoder {
1681 pub fn new(
1682 base_decoder: Arc<dyn SyndromeDecoder + Send + Sync>,
1683 initial_characteristics: HardwareErrorCharacteristics,
1684 ) -> Self {
1685 Self {
1686 base_decoder,
1687 error_characteristics: Arc::new(RwLock::new(initial_characteristics)),
1688 learning_rate: 0.01,
1689 threshold_history: VecDeque::with_capacity(1000),
1690 }
1691 }
1692
1693 pub fn update_characteristics(
1695 &mut self,
1696 new_characteristics: HardwareErrorCharacteristics,
1697 ) {
1698 *self.error_characteristics.write().unwrap() = new_characteristics;
1699 }
1700
1701 pub fn adapt_thresholds(&mut self, syndrome: &[bool], correction_success: bool) {
1703 let error_weight = syndrome.iter().filter(|&&x| x).count() as f64;
1704
1705 if correction_success {
1706 self.threshold_history.push_back(error_weight);
1708 } else {
1709 self.threshold_history.push_back(error_weight * 0.8);
1711 }
1712
1713 if self.threshold_history.len() > 100 {
1714 self.threshold_history.pop_front();
1715 }
1716 }
1717
1718 pub fn current_threshold(&self) -> f64 {
1720 if self.threshold_history.is_empty() {
1721 return 1.0; }
1723
1724 let sum: f64 = self.threshold_history.iter().sum();
1725 sum / self.threshold_history.len() as f64
1726 }
1727 }
1728
1729 impl SyndromeDecoder for AdaptiveThresholdDecoder {
1730 fn decode(&self, syndrome: &[bool]) -> QuantRS2Result<PauliString> {
1731 let threshold = self.current_threshold();
1732 let error_weight = syndrome.iter().filter(|&&x| x).count() as f64;
1733
1734 if error_weight > threshold {
1736 self.base_decoder.decode(syndrome)
1738 } else {
1739 Ok(PauliString::new(vec![Pauli::I; syndrome.len()]))
1741 }
1742 }
1743 }
1744
1745 pub struct ParallelSyndromeDecoder {
1747 base_decoder: Arc<dyn SyndromeDecoder + Send + Sync>,
1748 worker_count: usize,
1749 }
1750
1751 impl ParallelSyndromeDecoder {
1752 pub fn new(
1753 base_decoder: Arc<dyn SyndromeDecoder + Send + Sync>,
1754 worker_count: usize,
1755 ) -> Self {
1756 Self {
1757 base_decoder,
1758 worker_count,
1759 }
1760 }
1761
1762 pub fn decode_batch(&self, syndromes: &[Vec<bool>]) -> QuantRS2Result<Vec<PauliString>> {
1764 let chunk_size = (syndromes.len() + self.worker_count - 1) / self.worker_count;
1765 let mut handles = Vec::new();
1766
1767 for chunk in syndromes.chunks(chunk_size) {
1768 let decoder = Arc::clone(&self.base_decoder);
1769 let chunk_data: Vec<Vec<bool>> = chunk.to_vec();
1770
1771 let handle = thread::spawn(move || {
1772 let mut results = Vec::new();
1773 for syndrome in chunk_data {
1774 match decoder.decode(&syndrome) {
1775 Ok(correction) => results.push(correction),
1776 Err(_) => {
1777 results.push(PauliString::new(vec![Pauli::I; syndrome.len()]))
1778 }
1779 }
1780 }
1781 results
1782 });
1783
1784 handles.push(handle);
1785 }
1786
1787 let mut all_results = Vec::new();
1788 for handle in handles {
1789 match handle.join() {
1790 Ok(chunk_results) => all_results.extend(chunk_results),
1791 Err(_) => {
1792 return Err(QuantRS2Error::ComputationError(
1793 "Parallel decoding failed".to_string(),
1794 ))
1795 }
1796 }
1797 }
1798
1799 Ok(all_results)
1800 }
1801 }
1802
1803 impl SyndromeDecoder for ParallelSyndromeDecoder {
1804 fn decode(&self, syndrome: &[bool]) -> QuantRS2Result<PauliString> {
1805 self.base_decoder.decode(syndrome)
1806 }
1807 }
1808
1809 pub struct MockQuantumHardware {
1811 error_rate: f64,
1812 latency: Duration,
1813 syndrome_length: usize,
1814 }
1815
1816 impl MockQuantumHardware {
1817 pub fn new(error_rate: f64, latency: Duration, syndrome_length: usize) -> Self {
1818 Self {
1819 error_rate,
1820 latency,
1821 syndrome_length,
1822 }
1823 }
1824 }
1825
1826 impl QuantumHardwareInterface for MockQuantumHardware {
1827 fn measure_syndromes(&self) -> QuantRS2Result<Vec<bool>> {
1828 thread::sleep(self.latency);
1829
1830 let mut syndrome = vec![false; self.syndrome_length];
1832 for i in 0..self.syndrome_length {
1833 if rand::random::<f64>() < self.error_rate {
1834 syndrome[i] = true;
1835 }
1836 }
1837
1838 Ok(syndrome)
1839 }
1840
1841 fn apply_correction(&self, _correction: &PauliString) -> QuantRS2Result<()> {
1842 thread::sleep(self.latency / 2);
1843 Ok(())
1844 }
1845
1846 fn get_error_characteristics(&self) -> QuantRS2Result<HardwareErrorCharacteristics> {
1847 Ok(HardwareErrorCharacteristics {
1848 single_qubit_error_rates: vec![self.error_rate; self.syndrome_length],
1849 two_qubit_error_rates: vec![self.error_rate * 10.0; self.syndrome_length / 2],
1850 measurement_error_rates: vec![self.error_rate * 0.1; self.syndrome_length],
1851 correlated_errors: Vec::new(),
1852 temporal_variation: 0.01,
1853 })
1854 }
1855
1856 fn is_ready(&self) -> bool {
1857 true
1858 }
1859
1860 fn get_latency_stats(&self) -> QuantRS2Result<LatencyStats> {
1861 Ok(LatencyStats {
1862 syndrome_measurement_time: self.latency,
1863 decoding_time: Duration::from_micros(10),
1864 correction_application_time: self.latency / 2,
1865 total_cycle_time: self.latency + Duration::from_micros(10) + self.latency / 2,
1866 throughput_hz: 1.0 / (self.latency.as_secs_f64() * 1.5 + 10e-6),
1867 })
1868 }
1869 }
1870}
1871
1872pub mod logical_gates {
1876 use super::*;
1877
1878 #[derive(Debug, Clone)]
1880 pub struct LogicalGateOp {
1881 pub code: StabilizerCode,
1883 pub physical_operations: Vec<PhysicalGateSequence>,
1885 pub logical_qubits: Vec<usize>,
1887 pub error_propagation: ErrorPropagationAnalysis,
1889 }
1890
1891 #[derive(Debug, Clone)]
1893 pub struct PhysicalGateSequence {
1894 pub target_qubits: Vec<usize>,
1896 pub pauli_sequence: Vec<PauliString>,
1898 pub timing_constraints: Option<TimingConstraints>,
1900 pub error_correction_rounds: usize,
1902 }
1903
1904 #[derive(Debug, Clone)]
1906 pub struct ErrorPropagationAnalysis {
1907 pub single_qubit_propagation: Vec<ErrorPropagationPath>,
1909 pub two_qubit_propagation: Vec<ErrorPropagationPath>,
1911 pub max_error_weight: usize,
1913 pub fault_tolerance_threshold: f64,
1915 }
1916
1917 #[derive(Debug, Clone)]
1919 pub struct ErrorPropagationPath {
1920 pub initial_error: PauliString,
1922 pub final_error: PauliString,
1924 pub probability: f64,
1926 pub correctable: bool,
1928 }
1929
1930 #[derive(Debug, Clone)]
1932 pub struct TimingConstraints {
1933 pub max_operation_time: std::time::Duration,
1935 pub sync_points: Vec<usize>,
1937 pub parallel_groups: Vec<Vec<usize>>,
1939 }
1940
1941 pub struct LogicalGateSynthesizer {
1943 codes: Vec<StabilizerCode>,
1945 strategies: Vec<SynthesisStrategy>,
1947 error_threshold: f64,
1949 }
1950
1951 #[derive(Debug, Clone)]
1953 pub enum SynthesisStrategy {
1954 Transversal,
1956 MagicStateDistillation,
1958 LatticeSurgery,
1960 CodeDeformation,
1962 Braiding,
1964 }
1965
1966 impl LogicalGateSynthesizer {
1967 pub fn new(error_threshold: f64) -> Self {
1969 Self {
1970 codes: Vec::new(),
1971 strategies: vec![
1972 SynthesisStrategy::Transversal,
1973 SynthesisStrategy::MagicStateDistillation,
1974 SynthesisStrategy::LatticeSurgery,
1975 ],
1976 error_threshold,
1977 }
1978 }
1979
1980 pub fn add_code(&mut self, code: StabilizerCode) {
1982 self.codes.push(code);
1983 }
1984
1985 pub fn synthesize_logical_x(
1987 &self,
1988 code: &StabilizerCode,
1989 logical_qubit: usize,
1990 ) -> QuantRS2Result<LogicalGateOp> {
1991 if logical_qubit >= code.k {
1992 return Err(QuantRS2Error::InvalidInput(format!(
1993 "Logical qubit {} exceeds code dimension {}",
1994 logical_qubit, code.k
1995 )));
1996 }
1997
1998 let logical_x_operator = &code.logical_x[logical_qubit];
2000
2001 let physical_ops = vec![PhysicalGateSequence {
2002 target_qubits: (0..code.n).collect(),
2003 pauli_sequence: vec![logical_x_operator.clone()],
2004 timing_constraints: None,
2005 error_correction_rounds: 1,
2006 }];
2007
2008 let error_analysis = self.analyze_error_propagation(code, &physical_ops)?;
2009
2010 Ok(LogicalGateOp {
2011 code: code.clone(),
2012 physical_operations: physical_ops,
2013 logical_qubits: vec![logical_qubit],
2014 error_propagation: error_analysis,
2015 })
2016 }
2017
2018 pub fn synthesize_logical_z(
2020 &self,
2021 code: &StabilizerCode,
2022 logical_qubit: usize,
2023 ) -> QuantRS2Result<LogicalGateOp> {
2024 if logical_qubit >= code.k {
2025 return Err(QuantRS2Error::InvalidInput(format!(
2026 "Logical qubit {} exceeds code dimension {}",
2027 logical_qubit, code.k
2028 )));
2029 }
2030
2031 let logical_z_operator = &code.logical_z[logical_qubit];
2032
2033 let physical_ops = vec![PhysicalGateSequence {
2034 target_qubits: (0..code.n).collect(),
2035 pauli_sequence: vec![logical_z_operator.clone()],
2036 timing_constraints: None,
2037 error_correction_rounds: 1,
2038 }];
2039
2040 let error_analysis = self.analyze_error_propagation(code, &physical_ops)?;
2041
2042 Ok(LogicalGateOp {
2043 code: code.clone(),
2044 physical_operations: physical_ops,
2045 logical_qubits: vec![logical_qubit],
2046 error_propagation: error_analysis,
2047 })
2048 }
2049
2050 pub fn synthesize_logical_h(
2052 &self,
2053 code: &StabilizerCode,
2054 logical_qubit: usize,
2055 ) -> QuantRS2Result<LogicalGateOp> {
2056 if logical_qubit >= code.k {
2057 return Err(QuantRS2Error::InvalidInput(format!(
2058 "Logical qubit {} exceeds code dimension {}",
2059 logical_qubit, code.k
2060 )));
2061 }
2062
2063 let physical_ops = vec![PhysicalGateSequence {
2066 target_qubits: (0..code.n).collect(),
2067 pauli_sequence: self.generate_hadamard_sequence(code, logical_qubit)?,
2068 timing_constraints: Some(TimingConstraints {
2069 max_operation_time: std::time::Duration::from_micros(100),
2070 sync_points: vec![code.n / 2],
2071 parallel_groups: vec![(0..code.n).collect()],
2072 }),
2073 error_correction_rounds: 2, }];
2075
2076 let error_analysis = self.analyze_error_propagation(code, &physical_ops)?;
2077
2078 Ok(LogicalGateOp {
2079 code: code.clone(),
2080 physical_operations: physical_ops,
2081 logical_qubits: vec![logical_qubit],
2082 error_propagation: error_analysis,
2083 })
2084 }
2085
2086 pub fn synthesize_logical_cnot(
2088 &self,
2089 code: &StabilizerCode,
2090 control_qubit: usize,
2091 target_qubit: usize,
2092 ) -> QuantRS2Result<LogicalGateOp> {
2093 if control_qubit >= code.k || target_qubit >= code.k {
2094 return Err(QuantRS2Error::InvalidInput(
2095 "Control or target qubit exceeds code dimension".to_string(),
2096 ));
2097 }
2098
2099 if control_qubit == target_qubit {
2100 return Err(QuantRS2Error::InvalidInput(
2101 "Control and target qubits must be different".to_string(),
2102 ));
2103 }
2104
2105 let cnot_sequence = self.generate_cnot_sequence(code, control_qubit, target_qubit)?;
2107
2108 let physical_ops = vec![PhysicalGateSequence {
2109 target_qubits: (0..code.n).collect(),
2110 pauli_sequence: cnot_sequence,
2111 timing_constraints: Some(TimingConstraints {
2112 max_operation_time: std::time::Duration::from_micros(200),
2113 sync_points: vec![],
2114 parallel_groups: vec![], }),
2116 error_correction_rounds: 2,
2117 }];
2118
2119 let error_analysis = self.analyze_error_propagation(code, &physical_ops)?;
2120
2121 Ok(LogicalGateOp {
2122 code: code.clone(),
2123 physical_operations: physical_ops,
2124 logical_qubits: vec![control_qubit, target_qubit],
2125 error_propagation: error_analysis,
2126 })
2127 }
2128
2129 pub fn synthesize_logical_t(
2131 &self,
2132 code: &StabilizerCode,
2133 logical_qubit: usize,
2134 ) -> QuantRS2Result<LogicalGateOp> {
2135 if logical_qubit >= code.k {
2136 return Err(QuantRS2Error::InvalidInput(format!(
2137 "Logical qubit {} exceeds code dimension {}",
2138 logical_qubit, code.k
2139 )));
2140 }
2141
2142 let magic_state_prep = self.prepare_magic_state(code)?;
2144 let injection_sequence =
2145 self.inject_magic_state(code, logical_qubit, &magic_state_prep)?;
2146
2147 let physical_ops = vec![magic_state_prep, injection_sequence];
2148
2149 let error_analysis = self.analyze_error_propagation(code, &physical_ops)?;
2150
2151 Ok(LogicalGateOp {
2152 code: code.clone(),
2153 physical_operations: physical_ops,
2154 logical_qubits: vec![logical_qubit],
2155 error_propagation: error_analysis,
2156 })
2157 }
2158
2159 fn generate_hadamard_sequence(
2161 &self,
2162 code: &StabilizerCode,
2163 _logical_qubit: usize,
2164 ) -> QuantRS2Result<Vec<PauliString>> {
2165 let mut sequence = Vec::new();
2168
2169 sequence.push(PauliString::new(vec![Pauli::I; code.n]));
2173
2174 Ok(sequence)
2175 }
2176
2177 fn generate_cnot_sequence(
2179 &self,
2180 code: &StabilizerCode,
2181 _control: usize,
2182 _target: usize,
2183 ) -> QuantRS2Result<Vec<PauliString>> {
2184 let mut sequence = Vec::new();
2187
2188 sequence.push(PauliString::new(vec![Pauli::I; code.n]));
2190
2191 Ok(sequence)
2192 }
2193
2194 fn prepare_magic_state(
2196 &self,
2197 code: &StabilizerCode,
2198 ) -> QuantRS2Result<PhysicalGateSequence> {
2199 Ok(PhysicalGateSequence {
2202 target_qubits: (0..code.n).collect(),
2203 pauli_sequence: vec![PauliString::new(vec![Pauli::I; code.n])],
2204 timing_constraints: Some(TimingConstraints {
2205 max_operation_time: std::time::Duration::from_millis(1),
2206 sync_points: vec![],
2207 parallel_groups: vec![(0..code.n).collect()],
2208 }),
2209 error_correction_rounds: 5, })
2211 }
2212
2213 fn inject_magic_state(
2215 &self,
2216 code: &StabilizerCode,
2217 _logical_qubit: usize,
2218 _magic_state: &PhysicalGateSequence,
2219 ) -> QuantRS2Result<PhysicalGateSequence> {
2220 Ok(PhysicalGateSequence {
2222 target_qubits: (0..code.n).collect(),
2223 pauli_sequence: vec![PauliString::new(vec![Pauli::I; code.n])],
2224 timing_constraints: Some(TimingConstraints {
2225 max_operation_time: std::time::Duration::from_micros(500),
2226 sync_points: vec![code.n / 2],
2227 parallel_groups: vec![],
2228 }),
2229 error_correction_rounds: 3,
2230 })
2231 }
2232
2233 fn analyze_error_propagation(
2235 &self,
2236 code: &StabilizerCode,
2237 physical_ops: &[PhysicalGateSequence],
2238 ) -> QuantRS2Result<ErrorPropagationAnalysis> {
2239 let mut single_qubit_propagation = Vec::new();
2240 let mut two_qubit_propagation = Vec::new();
2241 let mut max_error_weight = 0;
2242
2243 for i in 0..code.n {
2245 for pauli in [Pauli::X, Pauli::Y, Pauli::Z] {
2246 let mut initial_error = vec![Pauli::I; code.n];
2247 initial_error[i] = pauli;
2248 let initial_pauli_string = PauliString::new(initial_error);
2249
2250 let final_error = self.propagate_error(&initial_pauli_string, physical_ops)?;
2252 let error_weight = final_error.weight();
2253 max_error_weight = max_error_weight.max(error_weight);
2254
2255 let correctable = self.is_error_correctable(code, &final_error)?;
2257
2258 single_qubit_propagation.push(ErrorPropagationPath {
2259 initial_error: initial_pauli_string,
2260 final_error,
2261 probability: 1.0 / (3.0 * code.n as f64), correctable,
2263 });
2264 }
2265 }
2266
2267 for i in 0..code.n.min(5) {
2269 for j in (i + 1)..code.n.min(5) {
2271 let mut initial_error = vec![Pauli::I; code.n];
2272 initial_error[i] = Pauli::X;
2273 initial_error[j] = Pauli::X;
2274 let initial_pauli_string = PauliString::new(initial_error);
2275
2276 let final_error = self.propagate_error(&initial_pauli_string, physical_ops)?;
2277 let error_weight = final_error.weight();
2278 max_error_weight = max_error_weight.max(error_weight);
2279
2280 let correctable = self.is_error_correctable(code, &final_error)?;
2281
2282 two_qubit_propagation.push(ErrorPropagationPath {
2283 initial_error: initial_pauli_string,
2284 final_error,
2285 probability: 1.0 / (code.n * (code.n - 1)) as f64,
2286 correctable,
2287 });
2288 }
2289 }
2290
2291 Ok(ErrorPropagationAnalysis {
2292 single_qubit_propagation,
2293 two_qubit_propagation,
2294 max_error_weight,
2295 fault_tolerance_threshold: self.error_threshold,
2296 })
2297 }
2298
2299 fn propagate_error(
2301 &self,
2302 error: &PauliString,
2303 _physical_ops: &[PhysicalGateSequence],
2304 ) -> QuantRS2Result<PauliString> {
2305 Ok(error.clone())
2308 }
2309
2310 fn is_error_correctable(
2312 &self,
2313 code: &StabilizerCode,
2314 error: &PauliString,
2315 ) -> QuantRS2Result<bool> {
2316 Ok(error.weight() <= (code.d + 1) / 2)
2319 }
2320 }
2321
2322 pub struct LogicalCircuitSynthesizer {
2324 gate_synthesizer: LogicalGateSynthesizer,
2325 optimization_passes: Vec<OptimizationPass>,
2326 }
2327
2328 #[derive(Debug, Clone)]
2330 pub enum OptimizationPass {
2331 PauliOptimization,
2333 ErrorCorrectionOptimization,
2335 ParallelizationOptimization,
2337 MagicStateOptimization,
2339 }
2340
2341 impl LogicalCircuitSynthesizer {
2342 pub fn new(error_threshold: f64) -> Self {
2343 Self {
2344 gate_synthesizer: LogicalGateSynthesizer::new(error_threshold),
2345 optimization_passes: vec![
2346 OptimizationPass::PauliOptimization,
2347 OptimizationPass::ErrorCorrectionOptimization,
2348 OptimizationPass::ParallelizationOptimization,
2349 OptimizationPass::MagicStateOptimization,
2350 ],
2351 }
2352 }
2353
2354 pub fn add_code(&mut self, code: StabilizerCode) {
2356 self.gate_synthesizer.add_code(code);
2357 }
2358
2359 pub fn synthesize_circuit(
2361 &self,
2362 code: &StabilizerCode,
2363 gate_sequence: &[(&str, Vec<usize>)], ) -> QuantRS2Result<Vec<LogicalGateOp>> {
2365 let mut logical_gates = Vec::new();
2366
2367 for (gate_name, targets) in gate_sequence {
2368 match gate_name.to_lowercase().as_str() {
2369 "x" | "pauli_x" => {
2370 if targets.len() != 1 {
2371 return Err(QuantRS2Error::InvalidInput(
2372 "X gate requires exactly one target".to_string(),
2373 ));
2374 }
2375 logical_gates.push(
2376 self.gate_synthesizer
2377 .synthesize_logical_x(code, targets[0])?,
2378 );
2379 }
2380 "z" | "pauli_z" => {
2381 if targets.len() != 1 {
2382 return Err(QuantRS2Error::InvalidInput(
2383 "Z gate requires exactly one target".to_string(),
2384 ));
2385 }
2386 logical_gates.push(
2387 self.gate_synthesizer
2388 .synthesize_logical_z(code, targets[0])?,
2389 );
2390 }
2391 "h" | "hadamard" => {
2392 if targets.len() != 1 {
2393 return Err(QuantRS2Error::InvalidInput(
2394 "H gate requires exactly one target".to_string(),
2395 ));
2396 }
2397 logical_gates.push(
2398 self.gate_synthesizer
2399 .synthesize_logical_h(code, targets[0])?,
2400 );
2401 }
2402 "cnot" | "cx" => {
2403 if targets.len() != 2 {
2404 return Err(QuantRS2Error::InvalidInput(
2405 "CNOT gate requires exactly two targets".to_string(),
2406 ));
2407 }
2408 logical_gates.push(
2409 self.gate_synthesizer
2410 .synthesize_logical_cnot(code, targets[0], targets[1])?,
2411 );
2412 }
2413 "t" => {
2414 if targets.len() != 1 {
2415 return Err(QuantRS2Error::InvalidInput(
2416 "T gate requires exactly one target".to_string(),
2417 ));
2418 }
2419 logical_gates.push(
2420 self.gate_synthesizer
2421 .synthesize_logical_t(code, targets[0])?,
2422 );
2423 }
2424 _ => {
2425 return Err(QuantRS2Error::UnsupportedOperation(format!(
2426 "Unsupported logical gate: {}",
2427 gate_name
2428 )));
2429 }
2430 }
2431 }
2432
2433 self.optimize_circuit(logical_gates)
2435 }
2436
2437 fn optimize_circuit(
2439 &self,
2440 mut circuit: Vec<LogicalGateOp>,
2441 ) -> QuantRS2Result<Vec<LogicalGateOp>> {
2442 for pass in &self.optimization_passes {
2443 circuit = self.apply_optimization_pass(circuit, pass)?;
2444 }
2445 Ok(circuit)
2446 }
2447
2448 fn apply_optimization_pass(
2450 &self,
2451 circuit: Vec<LogicalGateOp>,
2452 pass: &OptimizationPass,
2453 ) -> QuantRS2Result<Vec<LogicalGateOp>> {
2454 match pass {
2455 OptimizationPass::PauliOptimization => self.optimize_pauli_gates(circuit),
2456 OptimizationPass::ErrorCorrectionOptimization => {
2457 self.optimize_error_correction(circuit)
2458 }
2459 OptimizationPass::ParallelizationOptimization => {
2460 self.optimize_parallelization(circuit)
2461 }
2462 OptimizationPass::MagicStateOptimization => self.optimize_magic_states(circuit),
2463 }
2464 }
2465
2466 fn optimize_pauli_gates(
2468 &self,
2469 circuit: Vec<LogicalGateOp>,
2470 ) -> QuantRS2Result<Vec<LogicalGateOp>> {
2471 Ok(circuit) }
2474
2475 fn optimize_error_correction(
2477 &self,
2478 circuit: Vec<LogicalGateOp>,
2479 ) -> QuantRS2Result<Vec<LogicalGateOp>> {
2480 Ok(circuit) }
2483
2484 fn optimize_parallelization(
2486 &self,
2487 circuit: Vec<LogicalGateOp>,
2488 ) -> QuantRS2Result<Vec<LogicalGateOp>> {
2489 Ok(circuit) }
2492
2493 fn optimize_magic_states(
2495 &self,
2496 circuit: Vec<LogicalGateOp>,
2497 ) -> QuantRS2Result<Vec<LogicalGateOp>> {
2498 Ok(circuit) }
2501
2502 pub fn estimate_resources(&self, circuit: &[LogicalGateOp]) -> LogicalCircuitResources {
2504 let mut total_physical_operations = 0;
2505 let mut total_error_correction_rounds = 0;
2506 let mut max_parallelism = 0;
2507 let mut magic_states_required = 0;
2508
2509 for gate in circuit {
2510 total_physical_operations += gate.physical_operations.len();
2511 for op in &gate.physical_operations {
2512 total_error_correction_rounds += op.error_correction_rounds;
2513 if let Some(constraints) = &op.timing_constraints {
2514 max_parallelism = max_parallelism.max(constraints.parallel_groups.len());
2515 }
2516 }
2517
2518 if gate.logical_qubits.len() == 1 {
2520 magic_states_required += 1;
2522 }
2523 }
2524
2525 LogicalCircuitResources {
2526 total_physical_operations,
2527 total_error_correction_rounds,
2528 max_parallelism,
2529 magic_states_required,
2530 estimated_depth: circuit.len(),
2531 estimated_time: std::time::Duration::from_millis(
2532 (total_error_correction_rounds * 10) as u64,
2533 ),
2534 }
2535 }
2536 }
2537
2538 #[derive(Debug, Clone)]
2540 pub struct LogicalCircuitResources {
2541 pub total_physical_operations: usize,
2542 pub total_error_correction_rounds: usize,
2543 pub max_parallelism: usize,
2544 pub magic_states_required: usize,
2545 pub estimated_depth: usize,
2546 pub estimated_time: std::time::Duration,
2547 }
2548}
2549
2550pub mod adaptive_threshold {
2554 use super::*;
2555 use std::collections::{HashMap, VecDeque};
2556 use std::time::{Duration, Instant};
2557
2558 pub struct AdaptiveThresholdEstimator {
2560 error_history: VecDeque<ErrorObservation>,
2562 noise_model: NoiseModel,
2564 estimation_algorithm: ThresholdEstimationAlgorithm,
2566 performance_tracker: PerformanceTracker,
2568 config: AdaptiveConfig,
2570 }
2571
2572 #[derive(Debug, Clone)]
2574 pub struct ErrorObservation {
2575 pub syndrome: Vec<bool>,
2577 pub correction: PauliString,
2579 pub success: bool,
2581 pub observed_error_rate: f64,
2583 pub timestamp: Instant,
2585 pub environment: EnvironmentalConditions,
2587 }
2588
2589 #[derive(Debug, Clone)]
2591 pub struct EnvironmentalConditions {
2592 pub temperature: f64,
2594 pub magnetic_field: f64,
2596 pub vibration_level: f64,
2598 pub emi_level: f64,
2600 pub uptime: f64,
2602 }
2603
2604 #[derive(Debug, Clone)]
2606 pub struct NoiseModel {
2607 pub single_qubit_rates: HashMap<(usize, Pauli), f64>,
2609 pub correlated_rates: HashMap<(usize, usize), f64>,
2611 pub temporal_correlation: f64,
2613 pub environment_sensitivity: EnvironmentSensitivity,
2615 pub confidence: f64,
2617 }
2618
2619 #[derive(Debug, Clone)]
2621 pub struct EnvironmentSensitivity {
2622 pub temperature_coeff: f64,
2624 pub magnetic_field_coeff: f64,
2626 pub vibration_coeff: f64,
2628 pub emi_coeff: f64,
2630 pub drift_coeff: f64,
2632 }
2633
2634 #[derive(Debug, Clone)]
2636 pub enum ThresholdEstimationAlgorithm {
2637 Bayesian {
2639 prior_strength: f64,
2640 update_rate: f64,
2641 },
2642 MachineLearning {
2644 model_type: MLModelType,
2645 training_window: usize,
2646 },
2647 KalmanFilter {
2649 process_noise: f64,
2650 measurement_noise: f64,
2651 },
2652 ExponentialAverage { alpha: f64 },
2654 }
2655
2656 #[derive(Debug, Clone)]
2658 pub enum MLModelType {
2659 LinearRegression,
2660 RandomForest,
2661 NeuralNetwork { hidden_layers: Vec<usize> },
2662 SupportVectorMachine,
2663 }
2664
2665 #[derive(Debug, Clone)]
2667 pub struct PerformanceTracker {
2668 pub successful_corrections: u64,
2670 pub failed_corrections: u64,
2672 pub false_positives: u64,
2674 pub false_negatives: u64,
2676 pub average_latency: Duration,
2678 pub threshold_accuracy: f64,
2680 }
2681
2682 #[derive(Debug, Clone)]
2684 pub struct AdaptiveConfig {
2685 pub max_history_size: usize,
2687 pub min_observations: usize,
2689 pub update_frequency: Duration,
2691 pub confidence_threshold: f64,
2693 pub environmental_monitoring: bool,
2695 pub real_time_adaptation: bool,
2697 }
2698
2699 #[derive(Debug, Clone)]
2701 pub struct ThresholdRecommendation {
2702 pub threshold: f64,
2704 pub confidence: f64,
2706 pub predicted_error_rate: f64,
2708 pub recommendation_quality: f64,
2710 pub environmental_impact: f64,
2712 }
2713
2714 impl Default for AdaptiveConfig {
2715 fn default() -> Self {
2716 Self {
2717 max_history_size: 10000,
2718 min_observations: 100,
2719 update_frequency: Duration::from_secs(30),
2720 confidence_threshold: 0.8,
2721 environmental_monitoring: true,
2722 real_time_adaptation: true,
2723 }
2724 }
2725 }
2726
2727 impl Default for EnvironmentalConditions {
2728 fn default() -> Self {
2729 Self {
2730 temperature: 300.0, magnetic_field: 0.0,
2732 vibration_level: 0.0,
2733 emi_level: 0.0,
2734 uptime: 0.0,
2735 }
2736 }
2737 }
2738
2739 impl Default for EnvironmentSensitivity {
2740 fn default() -> Self {
2741 Self {
2742 temperature_coeff: 1e-5,
2743 magnetic_field_coeff: 1e-3,
2744 vibration_coeff: 1e-4,
2745 emi_coeff: 1e-4,
2746 drift_coeff: 1e-7,
2747 }
2748 }
2749 }
2750
2751 impl Default for NoiseModel {
2752 fn default() -> Self {
2753 Self {
2754 single_qubit_rates: HashMap::new(),
2755 correlated_rates: HashMap::new(),
2756 temporal_correlation: 0.1,
2757 environment_sensitivity: EnvironmentSensitivity::default(),
2758 confidence: 0.5,
2759 }
2760 }
2761 }
2762
2763 impl PerformanceTracker {
2764 pub fn new() -> Self {
2765 Self {
2766 successful_corrections: 0,
2767 failed_corrections: 0,
2768 false_positives: 0,
2769 false_negatives: 0,
2770 average_latency: Duration::from_nanos(0),
2771 threshold_accuracy: 0.0,
2772 }
2773 }
2774
2775 pub fn precision(&self) -> f64 {
2776 let total_positive = self.successful_corrections + self.false_positives;
2777 if total_positive == 0 {
2778 1.0
2779 } else {
2780 self.successful_corrections as f64 / total_positive as f64
2781 }
2782 }
2783
2784 pub fn recall(&self) -> f64 {
2785 let total_actual_positive = self.successful_corrections + self.false_negatives;
2786 if total_actual_positive == 0 {
2787 1.0
2788 } else {
2789 self.successful_corrections as f64 / total_actual_positive as f64
2790 }
2791 }
2792
2793 pub fn f1_score(&self) -> f64 {
2794 let p = self.precision();
2795 let r = self.recall();
2796 if p + r == 0.0 {
2797 0.0
2798 } else {
2799 2.0 * p * r / (p + r)
2800 }
2801 }
2802 }
2803
2804 impl AdaptiveThresholdEstimator {
2805 pub fn new(
2807 initial_noise_model: NoiseModel,
2808 algorithm: ThresholdEstimationAlgorithm,
2809 config: AdaptiveConfig,
2810 ) -> Self {
2811 Self {
2812 error_history: VecDeque::with_capacity(config.max_history_size),
2813 noise_model: initial_noise_model,
2814 estimation_algorithm: algorithm,
2815 performance_tracker: PerformanceTracker::new(),
2816 config,
2817 }
2818 }
2819
2820 pub fn add_observation(&mut self, observation: ErrorObservation) {
2822 if self.error_history.len() >= self.config.max_history_size {
2824 self.error_history.pop_front();
2825 }
2826 self.error_history.push_back(observation.clone());
2827
2828 self.update_performance_tracking(&observation);
2830
2831 if self.config.real_time_adaptation
2833 && self.error_history.len() >= self.config.min_observations
2834 {
2835 self.update_noise_model();
2836 }
2837 }
2838
2839 pub fn estimate_threshold(
2841 &self,
2842 syndrome: &[bool],
2843 environment: &EnvironmentalConditions,
2844 ) -> f64 {
2845 match &self.estimation_algorithm {
2846 ThresholdEstimationAlgorithm::Bayesian {
2847 prior_strength,
2848 update_rate,
2849 } => self.bayesian_threshold_estimation(
2850 syndrome,
2851 environment,
2852 *prior_strength,
2853 *update_rate,
2854 ),
2855 ThresholdEstimationAlgorithm::MachineLearning {
2856 model_type,
2857 training_window,
2858 } => self.ml_threshold_estimation(
2859 syndrome,
2860 environment,
2861 model_type,
2862 *training_window,
2863 ),
2864 ThresholdEstimationAlgorithm::KalmanFilter {
2865 process_noise,
2866 measurement_noise,
2867 } => self.kalman_threshold_estimation(
2868 syndrome,
2869 environment,
2870 *process_noise,
2871 *measurement_noise,
2872 ),
2873 ThresholdEstimationAlgorithm::ExponentialAverage { alpha } => {
2874 self.exponential_average_threshold(syndrome, environment, *alpha)
2875 }
2876 }
2877 }
2878
2879 pub fn get_threshold_recommendation(&self, syndrome: &[bool]) -> ThresholdRecommendation {
2881 let current_env = EnvironmentalConditions::default(); let threshold = self.estimate_threshold(syndrome, ¤t_env);
2883 let confidence = self.noise_model.confidence;
2884 let predicted_rate = self.predict_error_rate(¤t_env, Duration::from_secs(60));
2885
2886 ThresholdRecommendation {
2887 threshold,
2888 confidence,
2889 predicted_error_rate: predicted_rate,
2890 recommendation_quality: self.assess_recommendation_quality(),
2891 environmental_impact: self.assess_environmental_impact(¤t_env),
2892 }
2893 }
2894
2895 pub fn predict_error_rate(
2897 &self,
2898 environment: &EnvironmentalConditions,
2899 horizon: Duration,
2900 ) -> f64 {
2901 let base_rate = self.calculate_base_error_rate();
2902 let environmental_factor = self.calculate_environmental_factor(environment);
2903 let temporal_factor = self.calculate_temporal_factor(horizon);
2904
2905 base_rate * environmental_factor * temporal_factor
2906 }
2907
2908 fn bayesian_threshold_estimation(
2910 &self,
2911 syndrome: &[bool],
2912 environment: &EnvironmentalConditions,
2913 prior_strength: f64,
2914 update_rate: f64,
2915 ) -> f64 {
2916 let syndrome_weight = syndrome.iter().filter(|&&x| x).count() as f64;
2917 let base_threshold = self.calculate_base_threshold(syndrome_weight);
2918
2919 let historical_adjustment = self.calculate_historical_adjustment(update_rate);
2921
2922 let env_adjustment = self.calculate_environmental_adjustment(environment);
2924
2925 let prior = base_threshold;
2927 let likelihood_weight = 1.0 / (1.0 + prior_strength);
2928
2929 prior * (1.0 - likelihood_weight)
2930 + (base_threshold + historical_adjustment + env_adjustment) * likelihood_weight
2931 }
2932
2933 fn ml_threshold_estimation(
2935 &self,
2936 syndrome: &[bool],
2937 environment: &EnvironmentalConditions,
2938 model_type: &MLModelType,
2939 training_window: usize,
2940 ) -> f64 {
2941 let features = self.extract_features(syndrome, environment);
2943
2944 let training_data = self.get_recent_observations(training_window);
2946
2947 match model_type {
2948 MLModelType::LinearRegression => {
2949 self.linear_regression_predict(&features, &training_data)
2950 }
2951 _ => {
2952 self.linear_regression_predict(&features, &training_data)
2954 }
2955 }
2956 }
2957
2958 fn kalman_threshold_estimation(
2960 &self,
2961 syndrome: &[bool],
2962 _environment: &EnvironmentalConditions,
2963 process_noise: f64,
2964 measurement_noise: f64,
2965 ) -> f64 {
2966 let syndrome_weight = syndrome.iter().filter(|&&x| x).count() as f64;
2967 let base_threshold = self.calculate_base_threshold(syndrome_weight);
2968
2969 let prediction_error = self.calculate_prediction_error();
2971 let kalman_gain = process_noise / (process_noise + measurement_noise);
2972
2973 base_threshold + kalman_gain * prediction_error
2974 }
2975
2976 fn exponential_average_threshold(
2978 &self,
2979 syndrome: &[bool],
2980 _environment: &EnvironmentalConditions,
2981 alpha: f64,
2982 ) -> f64 {
2983 let syndrome_weight = syndrome.iter().filter(|&&x| x).count() as f64;
2984 let current_threshold = self.calculate_base_threshold(syndrome_weight);
2985
2986 if let Some(_last_obs) = self.error_history.back() {
2987 let last_threshold = syndrome_weight; alpha * current_threshold + (1.0 - alpha) * last_threshold
2989 } else {
2990 current_threshold
2991 }
2992 }
2993
2994 fn calculate_base_error_rate(&self) -> f64 {
2996 if self.error_history.is_empty() {
2997 return 0.001; }
2999
3000 let recent_errors: Vec<_> = self.error_history.iter().rev().take(100).collect();
3001
3002 let total_errors = recent_errors.len() as f64;
3003 let failed_corrections = recent_errors.iter().filter(|obs| !obs.success).count() as f64;
3004
3005 failed_corrections / total_errors
3006 }
3007
3008 fn calculate_environmental_factor(&self, environment: &EnvironmentalConditions) -> f64 {
3009 let sensitivity = &self.noise_model.environment_sensitivity;
3010
3011 1.0 + sensitivity.temperature_coeff * (environment.temperature - 300.0)
3012 + sensitivity.magnetic_field_coeff * environment.magnetic_field
3013 + sensitivity.vibration_coeff * environment.vibration_level
3014 + sensitivity.emi_coeff * environment.emi_level
3015 + sensitivity.drift_coeff * environment.uptime
3016 }
3017
3018 fn calculate_temporal_factor(&self, horizon: Duration) -> f64 {
3019 let temporal_corr = self.noise_model.temporal_correlation;
3020 let time_factor = horizon.as_secs_f64() / 3600.0; 1.0 + temporal_corr * time_factor
3023 }
3024
3025 fn calculate_base_threshold(&self, syndrome_weight: f64) -> f64 {
3026 (syndrome_weight + 1.0) / 10.0
3028 }
3029
3030 fn calculate_historical_adjustment(&self, update_rate: f64) -> f64 {
3031 if self.error_history.is_empty() {
3032 return 0.0;
3033 }
3034
3035 let recent_success_rate = self.calculate_recent_success_rate();
3036 update_rate * (0.5 - recent_success_rate) }
3038
3039 fn calculate_environmental_adjustment(&self, environment: &EnvironmentalConditions) -> f64 {
3040 let env_factor = self.calculate_environmental_factor(environment);
3041 (env_factor - 1.0) * 0.1 }
3043
3044 fn calculate_recent_success_rate(&self) -> f64 {
3045 let recent_window = 50.min(self.error_history.len());
3046 if recent_window == 0 {
3047 return 0.5;
3048 }
3049
3050 let recent_successes = self
3051 .error_history
3052 .iter()
3053 .rev()
3054 .take(recent_window)
3055 .filter(|obs| obs.success)
3056 .count();
3057
3058 recent_successes as f64 / recent_window as f64
3059 }
3060
3061 fn calculate_prediction_error(&self) -> f64 {
3062 let target_success_rate = 0.95;
3064 let actual_success_rate = self.calculate_recent_success_rate();
3065 target_success_rate - actual_success_rate
3066 }
3067
3068 fn extract_features(
3069 &self,
3070 syndrome: &[bool],
3071 environment: &EnvironmentalConditions,
3072 ) -> Vec<f64> {
3073 let mut features = vec![
3074 syndrome.iter().filter(|&&x| x).count() as f64,
3075 environment.temperature,
3076 environment.magnetic_field,
3077 environment.vibration_level,
3078 environment.emi_level,
3079 environment.uptime,
3080 ];
3081
3082 for &bit in syndrome {
3084 features.push(if bit { 1.0 } else { 0.0 });
3085 }
3086
3087 features
3088 }
3089
3090 fn get_recent_observations(&self, window: usize) -> Vec<ErrorObservation> {
3091 self.error_history
3092 .iter()
3093 .rev()
3094 .take(window)
3095 .cloned()
3096 .collect()
3097 }
3098
3099 fn linear_regression_predict(
3100 &self,
3101 _features: &[f64],
3102 training_data: &[ErrorObservation],
3103 ) -> f64 {
3104 if training_data.is_empty() {
3106 return 0.5;
3107 }
3108
3109 let avg_syndrome_weight: f64 = training_data
3110 .iter()
3111 .map(|obs| obs.syndrome.iter().filter(|&&x| x).count() as f64)
3112 .sum::<f64>()
3113 / training_data.len() as f64;
3114
3115 (avg_syndrome_weight + 1.0) / 10.0
3116 }
3117
3118 fn update_performance_tracking(&mut self, observation: &ErrorObservation) {
3119 if observation.success {
3120 self.performance_tracker.successful_corrections += 1;
3121 } else {
3122 self.performance_tracker.failed_corrections += 1;
3123 }
3124
3125 let total = self.performance_tracker.successful_corrections
3127 + self.performance_tracker.failed_corrections;
3128 if total > 0 {
3129 self.performance_tracker.threshold_accuracy =
3130 self.performance_tracker.successful_corrections as f64 / total as f64;
3131 }
3132 }
3133
3134 fn update_noise_model(&mut self) {
3135 let recent_window = self.config.min_observations.min(self.error_history.len());
3136 let recent_observations: Vec<ErrorObservation> = self
3137 .error_history
3138 .iter()
3139 .rev()
3140 .take(recent_window)
3141 .cloned()
3142 .collect();
3143
3144 self.update_single_qubit_rates(&recent_observations);
3146
3147 self.update_model_confidence(&recent_observations);
3149 }
3150
3151 fn update_single_qubit_rates(&mut self, observations: &[ErrorObservation]) {
3152 for obs in observations {
3154 for (i, pauli) in obs.correction.paulis.iter().enumerate() {
3155 if *pauli != Pauli::I {
3156 let key = (i, *pauli);
3157 let current_rate = self
3158 .noise_model
3159 .single_qubit_rates
3160 .get(&key)
3161 .copied()
3162 .unwrap_or(0.001);
3163 let new_rate = if obs.success {
3164 current_rate * 0.99
3165 } else {
3166 current_rate * 1.01
3167 };
3168 self.noise_model.single_qubit_rates.insert(key, new_rate);
3169 }
3170 }
3171 }
3172 }
3173
3174 fn update_model_confidence(&mut self, observations: &[ErrorObservation]) {
3175 if observations.is_empty() {
3176 return;
3177 }
3178
3179 let success_rate = observations.iter().filter(|obs| obs.success).count() as f64
3180 / observations.len() as f64;
3181
3182 let stability = 1.0 - (success_rate - 0.5).abs() * 2.0;
3184 self.noise_model.confidence = self.noise_model.confidence * 0.95 + stability * 0.05;
3185 }
3186
3187 fn assess_recommendation_quality(&self) -> f64 {
3188 let confidence_component = self.noise_model.confidence;
3190 let performance_component = self.performance_tracker.threshold_accuracy;
3191 let history_component =
3192 (self.error_history.len() as f64 / self.config.max_history_size as f64).min(1.0);
3193
3194 (confidence_component + performance_component + history_component) / 3.0
3195 }
3196
3197 fn assess_environmental_impact(&self, environment: &EnvironmentalConditions) -> f64 {
3198 let env_factor = self.calculate_environmental_factor(environment);
3199 (env_factor - 1.0).abs()
3200 }
3201 }
3202}
3203
3204#[cfg(test)]
3205mod tests {
3206 use super::*;
3207
3208 #[test]
3209 fn test_pauli_multiplication() {
3210 let (phase, result) = Pauli::X.multiply(&Pauli::Y);
3211 assert_eq!(result, Pauli::Z);
3212 assert_eq!(phase, Complex64::new(0.0, 1.0));
3213 }
3214
3215 #[test]
3216 fn test_pauli_string_commutation() {
3217 let ps1 = PauliString::new(vec![Pauli::X, Pauli::I]);
3218 let ps2 = PauliString::new(vec![Pauli::Z, Pauli::I]);
3219 assert!(!ps1.commutes_with(&ps2).unwrap());
3220
3221 let ps3 = PauliString::new(vec![Pauli::X, Pauli::I]);
3222 let ps4 = PauliString::new(vec![Pauli::I, Pauli::Z]);
3223 assert!(ps3.commutes_with(&ps4).unwrap());
3224 }
3225
3226 #[test]
3227 fn test_repetition_code() {
3228 let code = StabilizerCode::repetition_code();
3229 assert_eq!(code.n, 3);
3230 assert_eq!(code.k, 1);
3231 assert_eq!(code.d, 1);
3232
3233 let error = PauliString::new(vec![Pauli::X, Pauli::I, Pauli::I]);
3235 let syndrome = code.syndrome(&error).unwrap();
3236 assert_eq!(syndrome, vec![true, false]);
3238 }
3239
3240 #[test]
3241 fn test_steane_code() {
3242 let code = StabilizerCode::steane_code();
3243 assert_eq!(code.n, 7);
3244 assert_eq!(code.k, 1);
3245 assert_eq!(code.d, 3);
3246
3247 for i in 0..code.stabilizers.len() {
3249 for j in i + 1..code.stabilizers.len() {
3250 assert!(code.stabilizers[i]
3251 .commutes_with(&code.stabilizers[j])
3252 .unwrap());
3253 }
3254 }
3255 }
3256
3257 #[test]
3258 fn test_surface_code() {
3259 let surface = SurfaceCode::new(3, 3);
3260 assert_eq!(surface.distance(), 3);
3261
3262 let code = surface.to_stabilizer_code();
3263 assert_eq!(code.n, 9);
3264 assert_eq!(code.stabilizers.len(), 4);
3266 }
3267
3268 #[test]
3269 fn test_lookup_decoder() {
3270 let code = StabilizerCode::repetition_code();
3271 let decoder = LookupDecoder::new(&code).unwrap();
3272
3273 let trivial_syndrome = vec![false, false];
3275 let decoded = decoder.decode(&trivial_syndrome).unwrap();
3276 assert_eq!(decoded.weight(), 0); let error = PauliString::new(vec![Pauli::X, Pauli::I, Pauli::I]);
3280 let syndrome = code.syndrome(&error).unwrap();
3281
3282 if let Ok(decoded_error) = decoder.decode(&syndrome) {
3284 assert!(decoded_error.weight() <= 1);
3286 }
3287 }
3288
3289 #[test]
3290 fn test_concatenated_codes() {
3291 let inner_code = StabilizerCode::repetition_code();
3292 let outer_code = StabilizerCode::repetition_code();
3293 let concat_code = ConcatenatedCode::new(inner_code, outer_code);
3294
3295 assert_eq!(concat_code.total_qubits(), 9); assert_eq!(concat_code.logical_qubits(), 1);
3297 assert_eq!(concat_code.distance(), 1); let logical_state = vec![Complex64::new(1.0, 0.0), Complex64::new(0.0, 0.0)];
3301 let encoded = concat_code.encode(&logical_state).unwrap();
3302 assert_eq!(encoded.len(), 512); let error = PauliString::new(vec![
3306 Pauli::X,
3307 Pauli::I,
3308 Pauli::I,
3309 Pauli::I,
3310 Pauli::I,
3311 Pauli::I,
3312 Pauli::I,
3313 Pauli::I,
3314 Pauli::I,
3315 ]);
3316 let corrected = concat_code.correct_error(&encoded, &error).unwrap();
3317
3318 assert_eq!(corrected.len(), 512);
3320 }
3321
3322 #[test]
3323 fn test_hypergraph_product_codes() {
3324 let h1 = Array2::from_shape_vec((2, 3), vec![1, 1, 0, 0, 1, 1]).unwrap();
3326 let h2 = Array2::from_shape_vec((2, 3), vec![1, 0, 1, 1, 1, 0]).unwrap();
3327
3328 let hpc = HypergraphProductCode::new(h1, h2);
3329
3330 assert_eq!(hpc.n, 12); assert_eq!(hpc.k, 1); let stab_code = hpc.to_stabilizer_code();
3335 assert!(stab_code.stabilizers.len() > 0);
3336 }
3337
3338 #[test]
3339 fn test_quantum_ldpc_codes() {
3340 let qldpc = QuantumLDPCCode::bicycle_code(3, 4);
3341 assert_eq!(qldpc.n, 24); assert_eq!(qldpc.k, 2);
3343
3344 let stab_code = qldpc.to_stabilizer_code();
3345 assert!(stab_code.stabilizers.len() > 0);
3346
3347 for stabilizer in &stab_code.stabilizers {
3349 assert!(stabilizer.weight() <= qldpc.max_weight);
3350 }
3351 }
3352
3353 #[test]
3354 #[ignore] fn test_topological_codes() {
3356 let toric = ToricCode::new(2, 2);
3357 assert_eq!(toric.logical_qubits(), 2);
3358 assert_eq!(toric.distance(), 2);
3359
3360 let stab_code = toric.to_stabilizer_code();
3361 assert_eq!(stab_code.n, 8); assert_eq!(stab_code.k, 2);
3363
3364 for i in 0..stab_code.stabilizers.len() {
3366 for j in i + 1..stab_code.stabilizers.len() {
3367 assert!(stab_code.stabilizers[i]
3368 .commutes_with(&stab_code.stabilizers[j])
3369 .unwrap());
3370 }
3371 }
3372 }
3373
3374 #[test]
3375 fn test_ml_decoder() {
3376 let surface = SurfaceCode::new(3, 3);
3377 let decoder = MLDecoder::new(surface.to_stabilizer_code());
3378
3379 let syndrome = vec![true, false, true, false];
3381 let decoded = decoder.decode(&syndrome);
3382
3383 assert!(decoded.is_ok() || syndrome.iter().filter(|&&x| x).count() % 2 == 1);
3385 }
3386
3387 #[test]
3388 fn test_real_time_mock_hardware() {
3389 use crate::error_correction::real_time::*;
3390 use std::time::Duration;
3391
3392 let hardware = MockQuantumHardware::new(0.01, Duration::from_micros(10), 4);
3393
3394 let syndrome = hardware.measure_syndromes().unwrap();
3396 assert_eq!(syndrome.len(), 4);
3397
3398 let characteristics = hardware.get_error_characteristics().unwrap();
3400 assert_eq!(characteristics.single_qubit_error_rates.len(), 4);
3401
3402 let stats = hardware.get_latency_stats().unwrap();
3404 assert!(stats.throughput_hz > 0.0);
3405
3406 assert!(hardware.is_ready());
3407 }
3408
3409 #[test]
3410 fn test_real_time_performance_monitor() {
3411 use crate::error_correction::real_time::*;
3412 use std::time::Duration;
3413
3414 let mut monitor = PerformanceMonitor::new();
3415
3416 monitor.record_cycle(Duration::from_micros(10), true);
3418 monitor.record_cycle(Duration::from_micros(20), false);
3419 monitor.record_cycle(Duration::from_micros(15), true);
3420
3421 assert_eq!(monitor.cycles_processed, 3);
3422 assert_eq!(monitor.errors_corrected, 2);
3423 assert_eq!(monitor.error_correction_rate(), 2.0 / 3.0);
3424 assert!(monitor.average_latency().as_micros() > 10);
3425 assert!(monitor.current_throughput() > 0.0);
3426 }
3427
3428 #[test]
3429 fn test_real_time_adaptive_decoder() {
3430 use crate::error_correction::real_time::*;
3431 use std::sync::Arc;
3432
3433 let code = StabilizerCode::repetition_code();
3434 let base_decoder = Arc::new(LookupDecoder::new(&code).unwrap());
3435 let characteristics = HardwareErrorCharacteristics {
3436 single_qubit_error_rates: vec![0.01; 3],
3437 two_qubit_error_rates: vec![0.1; 1],
3438 measurement_error_rates: vec![0.001; 3],
3439 correlated_errors: Vec::new(),
3440 temporal_variation: 0.01,
3441 };
3442
3443 let mut adaptive_decoder = AdaptiveThresholdDecoder::new(base_decoder, characteristics);
3444
3445 let initial_threshold = adaptive_decoder.current_threshold();
3447 assert_eq!(initial_threshold, 1.0); adaptive_decoder.adapt_thresholds(&[false, false], true); let new_threshold = adaptive_decoder.current_threshold();
3453 assert!(new_threshold != initial_threshold); let syndrome = vec![false, false]; let result = adaptive_decoder.decode(&syndrome);
3458 assert!(result.is_ok(), "Decoding failed: {:?}", result.err());
3459 }
3460
3461 #[test]
3462 fn test_real_time_parallel_decoder() {
3463 use crate::error_correction::real_time::*;
3464 use std::sync::Arc;
3465
3466 let code = StabilizerCode::repetition_code();
3467 let base_decoder = Arc::new(LookupDecoder::new(&code).unwrap());
3468 let parallel_decoder = ParallelSyndromeDecoder::new(base_decoder, 2);
3469
3470 let syndrome = vec![false, false]; let result = parallel_decoder.decode(&syndrome);
3473 assert!(result.is_ok(), "Decoding failed: {:?}", result.err());
3474
3475 let syndromes = vec![
3477 vec![false, false], vec![false, false],
3479 vec![false, false],
3480 vec![false, false],
3481 ];
3482
3483 let results = parallel_decoder.decode_batch(&syndromes);
3484 assert!(results.is_ok());
3485 let corrections = results.unwrap();
3486 assert_eq!(corrections.len(), 4);
3487 }
3488
3489 #[test]
3490 fn test_real_time_syndrome_stream_processor() {
3491 use crate::error_correction::real_time::*;
3492 use std::sync::Arc;
3493 use std::time::Duration;
3494
3495 let code = StabilizerCode::repetition_code();
3496 let decoder = Arc::new(LookupDecoder::new(&code).unwrap());
3497 let hardware = Arc::new(MockQuantumHardware::new(0.01, Duration::from_micros(1), 3));
3498 let config = RealTimeConfig {
3499 max_latency: Duration::from_millis(1),
3500 buffer_size: 10,
3501 parallel_workers: 1,
3502 adaptive_threshold: false,
3503 hardware_feedback: false,
3504 performance_logging: true,
3505 };
3506
3507 let processor = SyndromeStreamProcessor::new(decoder, hardware, config);
3508
3509 let (current, max) = processor.get_buffer_status();
3511 assert_eq!(current, 0);
3512 assert_eq!(max, 10);
3513
3514 let stats = processor.get_performance_stats();
3516 assert_eq!(stats.cycles_processed, 0);
3517 assert_eq!(stats.errors_corrected, 0);
3518 }
3519
3520 #[test]
3521 fn test_logical_gate_synthesizer() {
3522 use crate::error_correction::logical_gates::*;
3523
3524 let code = StabilizerCode::repetition_code();
3525 let synthesizer = LogicalGateSynthesizer::new(0.01);
3526
3527 let logical_x = synthesizer.synthesize_logical_x(&code, 0);
3529 assert!(logical_x.is_ok());
3530
3531 let x_gate = logical_x.unwrap();
3532 assert_eq!(x_gate.logical_qubits, vec![0]);
3533 assert_eq!(x_gate.physical_operations.len(), 1);
3534 assert!(x_gate.error_propagation.single_qubit_propagation.len() > 0);
3535
3536 let logical_z = synthesizer.synthesize_logical_z(&code, 0);
3538 assert!(logical_z.is_ok());
3539
3540 let z_gate = logical_z.unwrap();
3541 assert_eq!(z_gate.logical_qubits, vec![0]);
3542 assert_eq!(z_gate.physical_operations.len(), 1);
3543
3544 let logical_h = synthesizer.synthesize_logical_h(&code, 0);
3546 assert!(logical_h.is_ok());
3547
3548 let h_gate = logical_h.unwrap();
3549 assert_eq!(h_gate.logical_qubits, vec![0]);
3550 assert_eq!(h_gate.physical_operations.len(), 1);
3551 assert_eq!(h_gate.physical_operations[0].error_correction_rounds, 2);
3552
3553 let invalid_gate = synthesizer.synthesize_logical_x(&code, 5);
3555 assert!(invalid_gate.is_err());
3556 }
3557
3558 #[test]
3559 fn test_logical_circuit_synthesizer() {
3560 use crate::error_correction::logical_gates::*;
3561
3562 let code = StabilizerCode::repetition_code();
3563 let synthesizer = LogicalCircuitSynthesizer::new(0.01);
3564
3565 let gate_sequence = vec![("x", vec![0]), ("h", vec![0]), ("z", vec![0])];
3567
3568 let circuit = synthesizer.synthesize_circuit(&code, &gate_sequence);
3569 assert!(circuit.is_ok());
3570
3571 let logical_circuit = circuit.unwrap();
3572 assert_eq!(logical_circuit.len(), 3);
3573
3574 let resources = synthesizer.estimate_resources(&logical_circuit);
3576 assert!(resources.total_physical_operations > 0);
3577 assert!(resources.total_error_correction_rounds > 0);
3578 assert_eq!(resources.estimated_depth, 3);
3579
3580 let invalid_sequence = vec![("invalid_gate", vec![0])];
3582 let invalid_circuit = synthesizer.synthesize_circuit(&code, &invalid_sequence);
3583 assert!(invalid_circuit.is_err());
3584
3585 let wrong_cnot = vec![("cnot", vec![0])]; let wrong_circuit = synthesizer.synthesize_circuit(&code, &wrong_cnot);
3588 assert!(wrong_circuit.is_err());
3589 }
3590
3591 #[test]
3592 fn test_logical_t_gate_synthesis() {
3593 use crate::error_correction::logical_gates::*;
3594
3595 let code = StabilizerCode::repetition_code();
3596 let synthesizer = LogicalGateSynthesizer::new(0.01);
3597
3598 let logical_t = synthesizer.synthesize_logical_t(&code, 0);
3600 assert!(logical_t.is_ok());
3601
3602 let t_gate = logical_t.unwrap();
3603 assert_eq!(t_gate.logical_qubits, vec![0]);
3604 assert_eq!(t_gate.physical_operations.len(), 2); assert!(t_gate.physical_operations[0].error_correction_rounds >= 5);
3608 }
3609
3610 #[test]
3611 fn test_error_propagation_analysis() {
3612 use crate::error_correction::logical_gates::*;
3613
3614 let code = StabilizerCode::repetition_code();
3615 let synthesizer = LogicalGateSynthesizer::new(0.01);
3616
3617 let logical_x = synthesizer.synthesize_logical_x(&code, 0).unwrap();
3618
3619 let analysis = &logical_x.error_propagation;
3621 assert!(analysis.single_qubit_propagation.len() > 0);
3622 assert!(analysis.max_error_weight >= 0);
3623 assert_eq!(analysis.fault_tolerance_threshold, 0.01);
3624
3625 let correctable_count = analysis
3627 .single_qubit_propagation
3628 .iter()
3629 .filter(|path| path.correctable)
3630 .count();
3631 assert!(correctable_count > 0);
3632 }
3633
3634 #[test]
3635 fn test_pauli_string_weight() {
3636 use crate::error_correction::logical_gates::*;
3637
3638 let identity_string = PauliString::new(vec![Pauli::I, Pauli::I, Pauli::I]);
3639 assert_eq!(identity_string.weight(), 0);
3640
3641 let single_error = PauliString::new(vec![Pauli::X, Pauli::I, Pauli::I]);
3642 assert_eq!(single_error.weight(), 1);
3643
3644 let multi_error = PauliString::new(vec![Pauli::X, Pauli::Y, Pauli::Z]);
3645 assert_eq!(multi_error.weight(), 3);
3646 }
3647
3648 #[test]
3649 fn test_logical_circuit_with_multiple_gates() {
3650 use crate::error_correction::logical_gates::*;
3651
3652 let code = StabilizerCode::repetition_code();
3653 let synthesizer = LogicalCircuitSynthesizer::new(0.01);
3654
3655 let gate_sequence = vec![
3657 ("h", vec![0]), ("x", vec![0]), ("z", vec![0]), ("h", vec![0]), ];
3662
3663 let circuit = synthesizer.synthesize_circuit(&code, &gate_sequence);
3664 assert!(circuit.is_ok());
3665
3666 let logical_circuit = circuit.unwrap();
3667 assert_eq!(logical_circuit.len(), 4);
3668
3669 for gate in &logical_circuit {
3671 assert_eq!(gate.logical_qubits, vec![0]);
3672 }
3673
3674 let resources = synthesizer.estimate_resources(&logical_circuit);
3676 assert_eq!(resources.estimated_depth, 4);
3677 assert!(resources.total_error_correction_rounds >= 4); }
3679
3680 #[test]
3681 fn test_adaptive_threshold_estimator() {
3682 use crate::error_correction::adaptive_threshold::*;
3683 use std::time::Duration;
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 mut 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}