1use crate::error::{QuantRS2Error, QuantRS2Result};
8use scirs2_core::ndarray::Array2;
9use scirs2_core::Complex64;
10use std::collections::HashMap;
11use std::fmt;
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
15pub enum Pauli {
16 I,
17 X,
18 Y,
19 Z,
20}
21
22impl Pauli {
23 pub fn matrix(&self) -> Array2<Complex64> {
25 match self {
26 Self::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 .expect("Pauli I matrix: 2x2 shape with 4 elements is always valid"),
36 Self::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 .expect("Pauli X matrix: 2x2 shape with 4 elements is always valid"),
46 Self::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 .expect("Pauli Y matrix: 2x2 shape with 4 elements is always valid"),
56 Self::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 .expect("Pauli Z matrix: 2x2 shape with 4 elements is always valid"),
66 }
67 }
68
69 pub const fn multiply(&self, other: &Self) -> (Complex64, Self) {
71 use Pauli::{I, X, Y, Z};
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 const 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: &Self) -> QuantRS2Result<Self> {
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(Self { phase, paulis })
131 }
132
133 pub fn commutes_with(&self, other: &Self) -> 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)
248 .expect("3-qubit repetition code: verified standard code parameters are always valid")
249 }
250
251 pub fn five_qubit_code() -> Self {
253 let stabilizers = vec![
254 PauliString::new(vec![Pauli::X, Pauli::Z, Pauli::Z, Pauli::X, Pauli::I]),
255 PauliString::new(vec![Pauli::I, Pauli::X, Pauli::Z, Pauli::Z, Pauli::X]),
256 PauliString::new(vec![Pauli::X, Pauli::I, Pauli::X, Pauli::Z, Pauli::Z]),
257 PauliString::new(vec![Pauli::Z, Pauli::X, Pauli::I, Pauli::X, Pauli::Z]),
258 ];
259
260 let logical_x = vec![PauliString::new(vec![
261 Pauli::X,
262 Pauli::X,
263 Pauli::X,
264 Pauli::X,
265 Pauli::X,
266 ])];
267 let logical_z = vec![PauliString::new(vec![
268 Pauli::Z,
269 Pauli::Z,
270 Pauli::Z,
271 Pauli::Z,
272 Pauli::Z,
273 ])];
274
275 Self::new(5, 1, 3, stabilizers, logical_x, logical_z)
276 .expect("5-qubit perfect code: verified standard code parameters are always valid")
277 }
278
279 pub fn steane_code() -> Self {
281 let stabilizers = vec![
282 PauliString::new(vec![
283 Pauli::I,
284 Pauli::I,
285 Pauli::I,
286 Pauli::X,
287 Pauli::X,
288 Pauli::X,
289 Pauli::X,
290 ]),
291 PauliString::new(vec![
292 Pauli::I,
293 Pauli::X,
294 Pauli::X,
295 Pauli::I,
296 Pauli::I,
297 Pauli::X,
298 Pauli::X,
299 ]),
300 PauliString::new(vec![
301 Pauli::X,
302 Pauli::I,
303 Pauli::X,
304 Pauli::I,
305 Pauli::X,
306 Pauli::I,
307 Pauli::X,
308 ]),
309 PauliString::new(vec![
310 Pauli::I,
311 Pauli::I,
312 Pauli::I,
313 Pauli::Z,
314 Pauli::Z,
315 Pauli::Z,
316 Pauli::Z,
317 ]),
318 PauliString::new(vec![
319 Pauli::I,
320 Pauli::Z,
321 Pauli::Z,
322 Pauli::I,
323 Pauli::I,
324 Pauli::Z,
325 Pauli::Z,
326 ]),
327 PauliString::new(vec![
328 Pauli::Z,
329 Pauli::I,
330 Pauli::Z,
331 Pauli::I,
332 Pauli::Z,
333 Pauli::I,
334 Pauli::Z,
335 ]),
336 ];
337
338 let logical_x = vec![PauliString::new(vec![
339 Pauli::X,
340 Pauli::X,
341 Pauli::X,
342 Pauli::X,
343 Pauli::X,
344 Pauli::X,
345 Pauli::X,
346 ])];
347 let logical_z = vec![PauliString::new(vec![
348 Pauli::Z,
349 Pauli::Z,
350 Pauli::Z,
351 Pauli::Z,
352 Pauli::Z,
353 Pauli::Z,
354 Pauli::Z,
355 ])];
356
357 Self::new(7, 1, 3, stabilizers, logical_x, logical_z)
358 .expect("7-qubit Steane code: verified standard code parameters are always valid")
359 }
360
361 pub fn syndrome(&self, error: &PauliString) -> QuantRS2Result<Vec<bool>> {
363 if error.paulis.len() != self.n {
364 return Err(QuantRS2Error::InvalidInput(
365 "Error must act on all physical qubits".to_string(),
366 ));
367 }
368
369 let mut syndrome = Vec::with_capacity(self.stabilizers.len());
370 for stabilizer in &self.stabilizers {
371 syndrome.push(!stabilizer.commutes_with(error)?);
372 }
373
374 Ok(syndrome)
375 }
376}
377
378#[derive(Debug, Clone)]
380pub struct SurfaceCode {
381 pub rows: usize,
383 pub cols: usize,
385 pub qubit_map: HashMap<(usize, usize), usize>,
387 pub x_stabilizers: Vec<Vec<usize>>,
389 pub z_stabilizers: Vec<Vec<usize>>,
390}
391
392impl SurfaceCode {
393 pub fn new(rows: usize, cols: usize) -> Self {
395 let mut qubit_map = HashMap::new();
396 let mut qubit_index = 0;
397
398 for r in 0..rows {
400 for c in 0..cols {
401 qubit_map.insert((r, c), qubit_index);
402 qubit_index += 1;
403 }
404 }
405
406 let mut x_stabilizers = Vec::new();
407 let mut z_stabilizers = Vec::new();
408
409 for r in 0..rows - 1 {
411 for c in 0..cols - 1 {
412 if (r + c) % 2 == 0 {
413 let stabilizer = vec![
414 qubit_map[&(r, c)],
415 qubit_map[&(r, c + 1)],
416 qubit_map[&(r + 1, c)],
417 qubit_map[&(r + 1, c + 1)],
418 ];
419 x_stabilizers.push(stabilizer);
420 }
421 }
422 }
423
424 for r in 0..rows - 1 {
426 for c in 0..cols - 1 {
427 if (r + c) % 2 == 1 {
428 let stabilizer = vec![
429 qubit_map[&(r, c)],
430 qubit_map[&(r, c + 1)],
431 qubit_map[&(r + 1, c)],
432 qubit_map[&(r + 1, c + 1)],
433 ];
434 z_stabilizers.push(stabilizer);
435 }
436 }
437 }
438
439 Self {
440 rows,
441 cols,
442 qubit_map,
443 x_stabilizers,
444 z_stabilizers,
445 }
446 }
447
448 pub fn distance(&self) -> usize {
450 self.rows.min(self.cols)
451 }
452
453 pub fn to_stabilizer_code(&self) -> QuantRS2Result<StabilizerCode> {
455 let n = self.qubit_map.len();
456 let mut stabilizers = Vec::new();
457
458 for x_stab in &self.x_stabilizers {
460 let mut paulis = vec![Pauli::I; n];
461 for &qubit in x_stab {
462 paulis[qubit] = Pauli::X;
463 }
464 stabilizers.push(PauliString::new(paulis));
465 }
466
467 for z_stab in &self.z_stabilizers {
469 let mut paulis = vec![Pauli::I; n];
470 for &qubit in z_stab {
471 paulis[qubit] = Pauli::Z;
472 }
473 stabilizers.push(PauliString::new(paulis));
474 }
475
476 let mut logical_x_paulis = vec![Pauli::I; n];
478 let mut logical_z_paulis = vec![Pauli::I; n];
479
480 for c in 0..self.cols {
482 if let Some(&qubit) = self.qubit_map.get(&(0, c)) {
483 logical_x_paulis[qubit] = Pauli::X;
484 }
485 }
486
487 for r in 0..self.rows {
489 if let Some(&qubit) = self.qubit_map.get(&(r, 0)) {
490 logical_z_paulis[qubit] = Pauli::Z;
491 }
492 }
493
494 let logical_x = vec![PauliString::new(logical_x_paulis)];
495 let logical_z = vec![PauliString::new(logical_z_paulis)];
496
497 StabilizerCode::new(n, 1, self.distance(), stabilizers, logical_x, logical_z)
498 }
499}
500
501pub trait SyndromeDecoder {
503 fn decode(&self, syndrome: &[bool]) -> QuantRS2Result<PauliString>;
505}
506
507pub struct LookupDecoder {
509 syndrome_table: HashMap<Vec<bool>, PauliString>,
511}
512
513impl LookupDecoder {
514 pub fn new(code: &StabilizerCode) -> QuantRS2Result<Self> {
516 let mut syndrome_table = HashMap::new();
517
518 let max_weight = (code.d - 1) / 2;
520 let all_errors = Self::generate_pauli_errors(code.n, max_weight);
521
522 for error in all_errors {
523 let syndrome = code.syndrome(&error)?;
524
525 syndrome_table
527 .entry(syndrome)
528 .and_modify(|e: &mut PauliString| {
529 if error.weight() < e.weight() {
530 *e = error.clone();
531 }
532 })
533 .or_insert(error);
534 }
535
536 Ok(Self { syndrome_table })
537 }
538
539 fn generate_pauli_errors(n: usize, max_weight: usize) -> Vec<PauliString> {
541 let mut errors = vec![PauliString::identity(n)];
542
543 for weight in 1..=max_weight {
544 let weight_errors = Self::generate_weight_k_errors(n, weight);
545 errors.extend(weight_errors);
546 }
547
548 errors
549 }
550
551 fn generate_weight_k_errors(n: usize, k: usize) -> Vec<PauliString> {
553 let mut errors = Vec::new();
554 let paulis = [Pauli::X, Pauli::Y, Pauli::Z];
555
556 let positions = Self::combinations(n, k);
558
559 for pos_set in positions {
560 let pauli_combinations = Self::cartesian_power(&paulis, k);
562
563 for pauli_combo in pauli_combinations {
564 let mut error_paulis = vec![Pauli::I; n];
565 for (i, &pos) in pos_set.iter().enumerate() {
566 error_paulis[pos] = pauli_combo[i];
567 }
568 errors.push(PauliString::new(error_paulis));
569 }
570 }
571
572 errors
573 }
574
575 fn combinations(n: usize, k: usize) -> Vec<Vec<usize>> {
577 let mut result = Vec::new();
578 let mut combo = (0..k).collect::<Vec<_>>();
579
580 loop {
581 result.push(combo.clone());
582
583 let mut i = k;
585 while i > 0 && (i == k || combo[i] == n - k + i) {
586 i -= 1;
587 }
588
589 if i == 0 && combo[0] == n - k {
590 break;
591 }
592
593 combo[i] += 1;
595 for j in i + 1..k {
596 combo[j] = combo[j - 1] + 1;
597 }
598 }
599
600 result
601 }
602
603 fn cartesian_power<T: Clone>(set: &[T], k: usize) -> Vec<Vec<T>> {
605 if k == 0 {
606 return vec![vec![]];
607 }
608
609 let mut result = Vec::new();
610 let smaller = Self::cartesian_power(set, k - 1);
611
612 for item in set {
613 for mut combo in smaller.clone() {
614 combo.push(item.clone());
615 result.push(combo);
616 }
617 }
618
619 result
620 }
621}
622
623impl SyndromeDecoder for LookupDecoder {
624 fn decode(&self, syndrome: &[bool]) -> QuantRS2Result<PauliString> {
625 self.syndrome_table
626 .get(syndrome)
627 .cloned()
628 .ok_or_else(|| QuantRS2Error::InvalidInput("Unknown syndrome".to_string()))
629 }
630}
631
632pub struct MWPMDecoder {
634 surface_code: SurfaceCode,
635}
636
637impl MWPMDecoder {
638 pub const fn new(surface_code: SurfaceCode) -> Self {
640 Self { surface_code }
641 }
642
643 pub fn decode_syndrome(
645 &self,
646 x_syndrome: &[bool],
647 z_syndrome: &[bool],
648 ) -> QuantRS2Result<PauliString> {
649 let n = self.surface_code.qubit_map.len();
650 let mut error_paulis = vec![Pauli::I; n];
651
652 let z_defects = self.find_defects(z_syndrome, &self.surface_code.z_stabilizers);
654 let x_corrections = self.minimum_weight_matching(&z_defects, Pauli::X)?;
655
656 for (qubit, pauli) in x_corrections {
657 error_paulis[qubit] = pauli;
658 }
659
660 let x_defects = self.find_defects(x_syndrome, &self.surface_code.x_stabilizers);
662 let z_corrections = self.minimum_weight_matching(&x_defects, Pauli::Z)?;
663
664 for (qubit, pauli) in z_corrections {
665 if error_paulis[qubit] == Pauli::I {
666 error_paulis[qubit] = pauli;
667 } else {
668 error_paulis[qubit] = Pauli::Y;
670 }
671 }
672
673 Ok(PauliString::new(error_paulis))
674 }
675
676 fn find_defects(&self, syndrome: &[bool], _stabilizers: &[Vec<usize>]) -> Vec<usize> {
678 syndrome
679 .iter()
680 .enumerate()
681 .filter_map(|(i, &s)| if s { Some(i) } else { None })
682 .collect()
683 }
684
685 fn minimum_weight_matching(
687 &self,
688 defects: &[usize],
689 error_type: Pauli,
690 ) -> QuantRS2Result<Vec<(usize, Pauli)>> {
691 let mut corrections = Vec::new();
693
694 if defects.len() % 2 != 0 {
695 return Err(QuantRS2Error::InvalidInput(
696 "Odd number of defects".to_string(),
697 ));
698 }
699
700 let mut paired = vec![false; defects.len()];
702
703 for i in 0..defects.len() {
704 if paired[i] {
705 continue;
706 }
707
708 let mut min_dist = usize::MAX;
710 let mut min_j = i;
711
712 for j in i + 1..defects.len() {
713 if !paired[j] {
714 let dist = self.defect_distance(defects[i], defects[j]);
715 if dist < min_dist {
716 min_dist = dist;
717 min_j = j;
718 }
719 }
720 }
721
722 if min_j != i {
723 paired[i] = true;
724 paired[min_j] = true;
725
726 let path = self.shortest_path(defects[i], defects[min_j])?;
728 for qubit in path {
729 corrections.push((qubit, error_type));
730 }
731 }
732 }
733
734 Ok(corrections)
735 }
736
737 const fn defect_distance(&self, defect1: usize, defect2: usize) -> usize {
739 (defect1 as isize - defect2 as isize).unsigned_abs()
741 }
742
743 fn shortest_path(&self, start: usize, end: usize) -> QuantRS2Result<Vec<usize>> {
745 let path = if start < end {
747 (start..=end).collect()
748 } else {
749 (end..=start).rev().collect()
750 };
751
752 Ok(path)
753 }
754}
755
756#[derive(Debug, Clone)]
758pub struct ColorCode {
759 pub n: usize,
761 pub faces: Vec<(Vec<usize>, Color)>,
763 pub vertex_map: HashMap<(i32, i32), usize>,
765}
766
767#[derive(Debug, Clone, Copy, PartialEq, Eq)]
768pub enum Color {
769 Red,
770 Green,
771 Blue,
772}
773
774impl ColorCode {
775 pub fn triangular(size: usize) -> Self {
777 let mut vertex_map = HashMap::new();
778 let mut qubit_index = 0;
779
780 for i in 0..size as i32 {
782 for j in 0..size as i32 {
783 vertex_map.insert((i, j), qubit_index);
784 qubit_index += 1;
785 }
786 }
787
788 let mut faces = Vec::new();
789
790 for i in 0..size as i32 - 1 {
792 for j in 0..size as i32 - 1 {
793 if let (Some(&q1), Some(&q2), Some(&q3)) = (
795 vertex_map.get(&(i, j)),
796 vertex_map.get(&(i + 1, j)),
797 vertex_map.get(&(i, j + 1)),
798 ) {
799 faces.push((vec![q1, q2, q3], Color::Red));
800 }
801
802 if let (Some(&q1), Some(&q2), Some(&q3)) = (
804 vertex_map.get(&(i + 1, j)),
805 vertex_map.get(&(i + 1, j + 1)),
806 vertex_map.get(&(i, j + 1)),
807 ) {
808 faces.push((vec![q1, q2, q3], Color::Green));
809 }
810 }
811 }
812
813 Self {
814 n: vertex_map.len(),
815 faces,
816 vertex_map,
817 }
818 }
819
820 pub fn to_stabilizer_code(&self) -> QuantRS2Result<StabilizerCode> {
822 let mut x_stabilizers = Vec::new();
823 let mut z_stabilizers = Vec::new();
824
825 for (qubits, _color) in &self.faces {
826 let mut x_paulis = vec![Pauli::I; self.n];
828 for &q in qubits {
829 x_paulis[q] = Pauli::X;
830 }
831 x_stabilizers.push(PauliString::new(x_paulis));
832
833 let mut z_paulis = vec![Pauli::I; self.n];
835 for &q in qubits {
836 z_paulis[q] = Pauli::Z;
837 }
838 z_stabilizers.push(PauliString::new(z_paulis));
839 }
840
841 let mut stabilizers = x_stabilizers;
842 stabilizers.extend(z_stabilizers);
843
844 let logical_x = vec![PauliString::new(vec![Pauli::X; self.n])];
846 let logical_z = vec![PauliString::new(vec![Pauli::Z; self.n])];
847
848 StabilizerCode::new(
849 self.n,
850 1,
851 3, stabilizers,
853 logical_x,
854 logical_z,
855 )
856 }
857}
858
859#[derive(Debug, Clone)]
861pub struct ConcatenatedCode {
862 pub inner_code: StabilizerCode,
864 pub outer_code: StabilizerCode,
866}
867
868impl ConcatenatedCode {
869 pub const fn new(inner_code: StabilizerCode, outer_code: StabilizerCode) -> Self {
871 Self {
872 inner_code,
873 outer_code,
874 }
875 }
876
877 pub const fn total_qubits(&self) -> usize {
879 self.inner_code.n * self.outer_code.n
880 }
881
882 pub const fn logical_qubits(&self) -> usize {
884 self.inner_code.k * self.outer_code.k
885 }
886
887 pub const fn distance(&self) -> usize {
889 self.inner_code.d * self.outer_code.d
890 }
891
892 pub fn encode(&self, logical_state: &[Complex64]) -> QuantRS2Result<Vec<Complex64>> {
894 if logical_state.len() != 1 << self.logical_qubits() {
895 return Err(QuantRS2Error::InvalidInput(
896 "Logical state dimension mismatch".to_string(),
897 ));
898 }
899
900 let outer_encoded = self.encode_with_code(logical_state, &self.outer_code)?;
902
903 let mut final_encoded = vec![Complex64::new(0.0, 0.0); 1 << self.total_qubits()];
905
906 for (i, &litude) in outer_encoded.iter().enumerate() {
909 if amplitude.norm() > 1e-10 {
910 final_encoded[i * (1 << self.inner_code.n)] = amplitude;
911 }
912 }
913
914 Ok(final_encoded)
915 }
916
917 pub fn correct_error(
919 &self,
920 encoded_state: &[Complex64],
921 error: &PauliString,
922 ) -> QuantRS2Result<Vec<Complex64>> {
923 if error.paulis.len() != self.total_qubits() {
924 return Err(QuantRS2Error::InvalidInput(
925 "Error must act on all physical qubits".to_string(),
926 ));
927 }
928
929 let mut corrected = encoded_state.to_vec();
932
933 for (i, &pauli) in error.paulis.iter().enumerate() {
935 if pauli != Pauli::I && i < corrected.len() {
936 corrected[i] *= -1.0;
938 }
939 }
940
941 Ok(corrected)
942 }
943
944 fn encode_with_code(
946 &self,
947 state: &[Complex64],
948 code: &StabilizerCode,
949 ) -> QuantRS2Result<Vec<Complex64>> {
950 let mut encoded = vec![Complex64::new(0.0, 0.0); 1 << code.n];
952
953 for (i, &litude) in state.iter().enumerate() {
954 if i < encoded.len() {
955 encoded[i * (1 << (code.n - code.k))] = amplitude;
956 }
957 }
958
959 Ok(encoded)
960 }
961}
962
963#[derive(Debug, Clone)]
965pub struct HypergraphProductCode {
966 pub n: usize,
968 pub k: usize,
970 pub x_stabilizers: Vec<PauliString>,
972 pub z_stabilizers: Vec<PauliString>,
974}
975
976impl HypergraphProductCode {
977 pub fn new(h1: Array2<u8>, h2: Array2<u8>) -> Self {
979 let (m1, n1) = h1.dim();
980 let (m2, n2) = h2.dim();
981
982 let n = n1 * m2 + m1 * n2;
983 let k = (n1 - m1) * (n2 - m2);
984
985 let mut x_stabilizers = Vec::new();
986 let mut z_stabilizers = Vec::new();
987
988 for i in 0..m1 {
990 for j in 0..m2 {
991 let mut paulis = vec![Pauli::I; n];
992
993 for l in 0..n1 {
995 if h1[[i, l]] == 1 {
996 paulis[l * m2 + j] = Pauli::X;
997 }
998 }
999
1000 x_stabilizers.push(PauliString::new(paulis));
1001 }
1002 }
1003
1004 for i in 0..m1 {
1006 for j in 0..m2 {
1007 let mut paulis = vec![Pauli::I; n];
1008
1009 for l in 0..n2 {
1011 if h2[[j, l]] == 1 {
1012 paulis[n1 * m2 + i * n2 + l] = Pauli::Z;
1013 }
1014 }
1015
1016 z_stabilizers.push(PauliString::new(paulis));
1017 }
1018 }
1019
1020 Self {
1021 n,
1022 k,
1023 x_stabilizers,
1024 z_stabilizers,
1025 }
1026 }
1027
1028 pub fn to_stabilizer_code(&self) -> QuantRS2Result<StabilizerCode> {
1030 let mut stabilizers = self.x_stabilizers.clone();
1031 stabilizers.extend(self.z_stabilizers.clone());
1032
1033 let logical_x = vec![PauliString::new(vec![Pauli::X; self.n])];
1035 let logical_z = vec![PauliString::new(vec![Pauli::Z; self.n])];
1036
1037 StabilizerCode::new(
1038 self.n,
1039 self.k,
1040 3, stabilizers,
1042 logical_x,
1043 logical_z,
1044 )
1045 }
1046}
1047
1048#[derive(Debug, Clone)]
1050pub struct QuantumLDPCCode {
1051 pub n: usize,
1053 pub k: usize,
1055 pub max_weight: usize,
1057 pub x_stabilizers: Vec<PauliString>,
1059 pub z_stabilizers: Vec<PauliString>,
1061}
1062
1063impl QuantumLDPCCode {
1064 pub fn bicycle_code(a: usize, b: usize) -> Self {
1066 let n = 2 * a * b;
1067 let k = 2;
1068 let max_weight = 6; let mut x_stabilizers = Vec::new();
1071 let mut z_stabilizers = Vec::new();
1072
1073 for i in 0..a {
1075 for j in 0..b {
1076 let mut x_paulis = vec![Pauli::I; n];
1078 let base_idx = i * b + j;
1079
1080 x_paulis[base_idx] = Pauli::X;
1082 x_paulis[(base_idx + 1) % (a * b)] = Pauli::X;
1083 x_paulis[(base_idx + b) % (a * b)] = Pauli::X;
1084 x_paulis[a * b + base_idx] = Pauli::X;
1085 x_paulis[a * b + (base_idx + 1) % (a * b)] = Pauli::X;
1086 x_paulis[a * b + (base_idx + b) % (a * b)] = Pauli::X;
1087
1088 x_stabilizers.push(PauliString::new(x_paulis));
1089
1090 let mut z_paulis = vec![Pauli::I; n];
1092 z_paulis[base_idx] = Pauli::Z;
1093 z_paulis[(base_idx + a) % (a * b)] = Pauli::Z;
1094 z_paulis[(base_idx + 1) % (a * b)] = Pauli::Z;
1095 z_paulis[a * b + base_idx] = Pauli::Z;
1096 z_paulis[a * b + (base_idx + a) % (a * b)] = Pauli::Z;
1097 z_paulis[a * b + (base_idx + 1) % (a * b)] = Pauli::Z;
1098
1099 z_stabilizers.push(PauliString::new(z_paulis));
1100 }
1101 }
1102
1103 Self {
1104 n,
1105 k,
1106 max_weight,
1107 x_stabilizers,
1108 z_stabilizers,
1109 }
1110 }
1111
1112 pub fn to_stabilizer_code(&self) -> QuantRS2Result<StabilizerCode> {
1114 let mut stabilizers = self.x_stabilizers.clone();
1115 stabilizers.extend(self.z_stabilizers.clone());
1116
1117 let logical_x = vec![
1119 PauliString::new(vec![Pauli::X; self.n]),
1120 PauliString::new(vec![Pauli::Y; self.n]),
1121 ];
1122 let logical_z = vec![
1123 PauliString::new(vec![Pauli::Z; self.n]),
1124 PauliString::new(vec![Pauli::Y; self.n]),
1125 ];
1126
1127 StabilizerCode::new(
1128 self.n,
1129 self.k,
1130 4, stabilizers,
1132 logical_x,
1133 logical_z,
1134 )
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 const 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) -> QuantRS2Result<StabilizerCode> {
1186 let n = self.qubit_map.len();
1187 let mut stabilizers = Vec::new();
1188
1189 for r in 0..self.rows {
1191 for c in 0..self.cols {
1192 let mut paulis = vec![Pauli::I; n];
1193
1194 let h_edge_below = (2 * r, c);
1196 let h_edge_above = (2 * ((r + self.rows - 1) % self.rows), c);
1197 let v_edge_left = (2 * r + 1, (c + self.cols - 1) % self.cols);
1198 let v_edge_right = (2 * r + 1, c);
1199
1200 for &coord in &[h_edge_below, h_edge_above, v_edge_left, v_edge_right] {
1201 if let Some(&qubit) = self.qubit_map.get(&coord) {
1202 paulis[qubit] = Pauli::X;
1203 }
1204 }
1205
1206 stabilizers.push(PauliString::new(paulis));
1207 }
1208 }
1209
1210 for r in 0..self.rows {
1212 for c in 0..self.cols {
1213 let mut paulis = vec![Pauli::I; n];
1214
1215 let h_edge_top = (2 * r, c);
1217 let h_edge_bottom = (2 * ((r + 1) % self.rows), c);
1218 let v_edge_left = (2 * r + 1, c);
1219 let v_edge_right = (2 * r + 1, (c + 1) % self.cols);
1220
1221 for &coord in &[h_edge_top, h_edge_bottom, v_edge_left, v_edge_right] {
1222 if let Some(&qubit) = self.qubit_map.get(&coord) {
1223 paulis[qubit] = Pauli::Z;
1224 }
1225 }
1226
1227 stabilizers.push(PauliString::new(paulis));
1228 }
1229 }
1230
1231 let mut logical_x1 = vec![Pauli::I; n];
1233 let mut logical_z1 = vec![Pauli::I; n];
1234 let mut logical_x2 = vec![Pauli::I; n];
1235 let mut logical_z2 = vec![Pauli::I; n];
1236
1237 for c in 0..self.cols {
1239 if let Some(&qubit) = self.qubit_map.get(&(1, c)) {
1241 logical_x1[qubit] = Pauli::X;
1242 }
1243 if let Some(&qubit) = self.qubit_map.get(&(0, c)) {
1245 logical_z2[qubit] = Pauli::Z;
1246 }
1247 }
1248
1249 for r in 0..self.rows {
1251 if let Some(&qubit) = self.qubit_map.get(&(2 * r, 0)) {
1253 logical_x2[qubit] = Pauli::X;
1254 }
1255 if let Some(&qubit) = self.qubit_map.get(&(2 * r + 1, 0)) {
1257 logical_z1[qubit] = Pauli::Z;
1258 }
1259 }
1260
1261 let logical_x = vec![PauliString::new(logical_x1), PauliString::new(logical_x2)];
1262 let logical_z = vec![PauliString::new(logical_z1), PauliString::new(logical_z2)];
1263
1264 StabilizerCode::new(n, 2, self.distance(), stabilizers, logical_x, logical_z)
1265 }
1266}
1267
1268pub struct MLDecoder {
1270 code: StabilizerCode,
1272 weights: Vec<Vec<f64>>,
1274}
1275
1276impl MLDecoder {
1277 pub fn new(code: StabilizerCode) -> Self {
1279 let input_size = code.stabilizers.len();
1281 let hidden_size = 2 * input_size;
1282 let output_size = code.n * 3; use scirs2_core::random::prelude::*;
1285 let mut rng = thread_rng();
1286 let mut weights = Vec::new();
1287
1288 let mut w1 = Vec::new();
1290 for _ in 0..hidden_size {
1291 let mut row = Vec::new();
1292 for _ in 0..input_size {
1293 row.push((rng.gen::<f64>() - 0.5) * 0.1);
1294 }
1295 w1.push(row);
1296 }
1297 weights.push(w1.into_iter().flatten().collect());
1298
1299 let mut w2 = Vec::new();
1301 for _ in 0..output_size {
1302 let mut row = Vec::new();
1303 for _ in 0..hidden_size {
1304 row.push((rng.gen::<f64>() - 0.5) * 0.1);
1305 }
1306 w2.push(row);
1307 }
1308 weights.push(w2.into_iter().flatten().collect());
1309
1310 Self { code, weights }
1311 }
1312
1313 fn predict(&self, syndrome: &[bool]) -> Vec<f64> {
1315 let input: Vec<f64> = syndrome
1316 .iter()
1317 .map(|&b| if b { 1.0 } else { 0.0 })
1318 .collect();
1319
1320 let hidden_size = 2 * input.len();
1323 let mut hidden = vec![0.0; hidden_size];
1324
1325 for i in 0..hidden_size {
1327 for j in 0..input.len() {
1328 if i * input.len() + j < self.weights[0].len() {
1329 hidden[i] += input[j] * self.weights[0][i * input.len() + j];
1330 }
1331 }
1332 hidden[i] = hidden[i].tanh(); }
1334
1335 let output_size = self.code.n * 3;
1337 let mut output = vec![0.0; output_size];
1338
1339 for i in 0..output_size {
1340 for j in 0..hidden_size {
1341 if i * hidden_size + j < self.weights[1].len() {
1342 output[i] += hidden[j] * self.weights[1][i * hidden_size + j];
1343 }
1344 }
1345 }
1346
1347 output
1348 }
1349}
1350
1351impl SyndromeDecoder for MLDecoder {
1352 fn decode(&self, syndrome: &[bool]) -> QuantRS2Result<PauliString> {
1353 let prediction = self.predict(syndrome);
1354
1355 let mut paulis = Vec::with_capacity(self.code.n);
1357
1358 for qubit in 0..self.code.n {
1359 let base_idx = qubit * 3;
1360 if base_idx + 2 < prediction.len() {
1361 let x_prob = prediction[base_idx];
1362 let y_prob = prediction[base_idx + 1];
1363 let z_prob = prediction[base_idx + 2];
1364
1365 if x_prob > y_prob && x_prob > z_prob && x_prob > 0.5 {
1367 paulis.push(Pauli::X);
1368 } else if y_prob > z_prob && y_prob > 0.5 {
1369 paulis.push(Pauli::Y);
1370 } else if z_prob > 0.5 {
1371 paulis.push(Pauli::Z);
1372 } else {
1373 paulis.push(Pauli::I);
1374 }
1375 } else {
1376 paulis.push(Pauli::I);
1377 }
1378 }
1379
1380 Ok(PauliString::new(paulis))
1381 }
1382}
1383
1384pub mod real_time {
1388 use super::*;
1389 use std::collections::VecDeque;
1390 use std::sync::{Arc, Mutex, RwLock};
1391 use std::thread;
1392 use std::time::{Duration, Instant};
1393
1394 pub trait QuantumHardwareInterface: Send + Sync {
1396 fn measure_syndromes(&self) -> QuantRS2Result<Vec<bool>>;
1398
1399 fn apply_correction(&self, correction: &PauliString) -> QuantRS2Result<()>;
1401
1402 fn get_error_characteristics(&self) -> QuantRS2Result<HardwareErrorCharacteristics>;
1404
1405 fn is_ready(&self) -> bool;
1407
1408 fn get_latency_stats(&self) -> QuantRS2Result<LatencyStats>;
1410 }
1411
1412 #[derive(Debug, Clone)]
1414 pub struct HardwareErrorCharacteristics {
1415 pub single_qubit_error_rates: Vec<f64>,
1417 pub two_qubit_error_rates: Vec<f64>,
1419 pub measurement_error_rates: Vec<f64>,
1421 pub correlated_errors: Vec<CorrelatedErrorPattern>,
1423 pub temporal_variation: f64,
1425 }
1426
1427 #[derive(Debug, Clone)]
1429 pub struct CorrelatedErrorPattern {
1430 pub qubits: Vec<usize>,
1431 pub probability: f64,
1432 pub pauli_pattern: PauliString,
1433 }
1434
1435 #[derive(Debug, Clone)]
1437 pub struct LatencyStats {
1438 pub syndrome_measurement_time: Duration,
1439 pub decoding_time: Duration,
1440 pub correction_application_time: Duration,
1441 pub total_cycle_time: Duration,
1442 pub throughput_hz: f64,
1443 }
1444
1445 pub struct SyndromeStreamProcessor {
1447 buffer: Arc<Mutex<VecDeque<SyndromePacket>>>,
1448 decoder: Arc<dyn SyndromeDecoder + Send + Sync>,
1449 hardware: Arc<dyn QuantumHardwareInterface>,
1450 performance_monitor: Arc<RwLock<PerformanceMonitor>>,
1451 config: RealTimeConfig,
1452 }
1453
1454 #[derive(Debug, Clone)]
1456 pub struct SyndromePacket {
1457 pub syndrome: Vec<bool>,
1458 pub timestamp: Instant,
1459 pub sequence_number: u64,
1460 pub measurement_fidelity: f64,
1461 }
1462
1463 #[derive(Debug, Clone)]
1465 pub struct RealTimeConfig {
1466 pub max_latency: Duration,
1467 pub buffer_size: usize,
1468 pub parallel_workers: usize,
1469 pub adaptive_threshold: bool,
1470 pub hardware_feedback: bool,
1471 pub performance_logging: bool,
1472 }
1473
1474 impl Default for RealTimeConfig {
1475 fn default() -> Self {
1476 Self {
1477 max_latency: Duration::from_micros(100), buffer_size: 1000,
1479 parallel_workers: 4,
1480 adaptive_threshold: true,
1481 hardware_feedback: true,
1482 performance_logging: true,
1483 }
1484 }
1485 }
1486
1487 #[derive(Debug, Clone)]
1489 pub struct PerformanceMonitor {
1490 pub cycles_processed: u64,
1491 pub errors_corrected: u64,
1492 pub false_positives: u64,
1493 pub latency_histogram: Vec<Duration>,
1494 pub throughput_samples: VecDeque<f64>,
1495 pub start_time: Instant,
1496 }
1497
1498 impl PerformanceMonitor {
1499 pub fn new() -> Self {
1500 Self {
1501 cycles_processed: 0,
1502 errors_corrected: 0,
1503 false_positives: 0,
1504 latency_histogram: Vec::new(),
1505 throughput_samples: VecDeque::new(),
1506 start_time: Instant::now(),
1507 }
1508 }
1509
1510 pub fn record_cycle(&mut self, latency: Duration, error_corrected: bool) {
1511 self.cycles_processed += 1;
1512 if error_corrected {
1513 self.errors_corrected += 1;
1514 }
1515 self.latency_histogram.push(latency);
1516
1517 let elapsed = self.start_time.elapsed();
1519 if elapsed.as_secs_f64() > 0.0 {
1520 let throughput = self.cycles_processed as f64 / elapsed.as_secs_f64();
1521 self.throughput_samples.push_back(throughput);
1522
1523 if self.throughput_samples.len() > 100 {
1525 self.throughput_samples.pop_front();
1526 }
1527 }
1528 }
1529
1530 pub fn average_latency(&self) -> Duration {
1531 if self.latency_histogram.is_empty() {
1532 return Duration::from_nanos(0);
1533 }
1534
1535 let total_nanos: u64 = self
1536 .latency_histogram
1537 .iter()
1538 .map(|d| d.as_nanos() as u64)
1539 .sum();
1540 Duration::from_nanos(total_nanos / self.latency_histogram.len() as u64)
1541 }
1542
1543 pub fn current_throughput(&self) -> f64 {
1544 self.throughput_samples.back().copied().unwrap_or(0.0)
1545 }
1546
1547 pub fn error_correction_rate(&self) -> f64 {
1548 if self.cycles_processed == 0 {
1549 0.0
1550 } else {
1551 self.errors_corrected as f64 / self.cycles_processed as f64
1552 }
1553 }
1554 }
1555
1556 impl SyndromeStreamProcessor {
1557 pub fn new(
1559 decoder: Arc<dyn SyndromeDecoder + Send + Sync>,
1560 hardware: Arc<dyn QuantumHardwareInterface>,
1561 config: RealTimeConfig,
1562 ) -> Self {
1563 Self {
1564 buffer: Arc::new(Mutex::new(VecDeque::with_capacity(config.buffer_size))),
1565 decoder,
1566 hardware,
1567 performance_monitor: Arc::new(RwLock::new(PerformanceMonitor::new())),
1568 config,
1569 }
1570 }
1571
1572 pub fn start_processing(&self) -> QuantRS2Result<thread::JoinHandle<()>> {
1574 let buffer = Arc::clone(&self.buffer);
1575 let decoder = Arc::clone(&self.decoder);
1576 let hardware = Arc::clone(&self.hardware);
1577 let monitor = Arc::clone(&self.performance_monitor);
1578 let config = self.config.clone();
1579
1580 let handle = thread::spawn(move || {
1581 let mut sequence_number = 0u64;
1582
1583 loop {
1584 let cycle_start = Instant::now();
1585
1586 if !hardware.is_ready() {
1588 thread::sleep(Duration::from_micros(10));
1589 continue;
1590 }
1591
1592 match hardware.measure_syndromes() {
1594 Ok(syndrome) => {
1595 let packet = SyndromePacket {
1596 syndrome: syndrome.clone(),
1597 timestamp: Instant::now(),
1598 sequence_number,
1599 measurement_fidelity: 0.99, };
1601
1602 {
1604 let mut buf = buffer.lock().expect("Syndrome buffer lock poisoned");
1605 if buf.len() >= config.buffer_size {
1606 buf.pop_front(); }
1608 buf.push_back(packet);
1609 }
1610
1611 let has_error = syndrome.iter().any(|&x| x);
1613 let mut error_corrected = false;
1614
1615 if has_error {
1616 match decoder.decode(&syndrome) {
1617 Ok(correction) => {
1618 match hardware.apply_correction(&correction) {
1619 Ok(()) => {
1620 error_corrected = true;
1621 }
1622 Err(e) => {
1623 eprintln!("Failed to apply correction: {e}");
1624 }
1625 }
1626 }
1627 Err(e) => {
1628 eprintln!("Decoding failed: {e}");
1629 }
1630 }
1631 }
1632
1633 let cycle_time = cycle_start.elapsed();
1635 {
1636 let mut mon =
1637 monitor.write().expect("Performance monitor lock poisoned");
1638 mon.record_cycle(cycle_time, error_corrected);
1639 }
1640
1641 if cycle_time > config.max_latency {
1643 eprintln!("Warning: Error correction cycle exceeded max latency: {:?} > {:?}",
1644 cycle_time, config.max_latency);
1645 }
1646
1647 sequence_number += 1;
1648 }
1649 Err(e) => {
1650 eprintln!("Failed to measure syndromes: {e}");
1651 thread::sleep(Duration::from_micros(10));
1652 }
1653 }
1654
1655 thread::sleep(Duration::from_micros(1));
1657 }
1658 });
1659
1660 Ok(handle)
1661 }
1662
1663 pub fn get_performance_stats(&self) -> PerformanceMonitor {
1665 (*self
1666 .performance_monitor
1667 .read()
1668 .expect("Performance monitor lock poisoned"))
1669 .clone()
1670 }
1671
1672 pub fn get_buffer_status(&self) -> (usize, usize) {
1674 let buffer = self.buffer.lock().expect("Syndrome buffer lock poisoned");
1675 (buffer.len(), self.config.buffer_size)
1676 }
1677 }
1678
1679 pub struct AdaptiveThresholdDecoder {
1681 base_decoder: Arc<dyn SyndromeDecoder + Send + Sync>,
1682 error_characteristics: Arc<RwLock<HardwareErrorCharacteristics>>,
1683 learning_rate: f64,
1684 threshold_history: VecDeque<f64>,
1685 }
1686
1687 impl AdaptiveThresholdDecoder {
1688 pub fn new(
1689 base_decoder: Arc<dyn SyndromeDecoder + Send + Sync>,
1690 initial_characteristics: HardwareErrorCharacteristics,
1691 ) -> Self {
1692 Self {
1693 base_decoder,
1694 error_characteristics: Arc::new(RwLock::new(initial_characteristics)),
1695 learning_rate: 0.01,
1696 threshold_history: VecDeque::with_capacity(1000),
1697 }
1698 }
1699
1700 pub fn update_characteristics(
1702 &mut self,
1703 new_characteristics: HardwareErrorCharacteristics,
1704 ) {
1705 *self
1706 .error_characteristics
1707 .write()
1708 .expect("Error characteristics lock poisoned") = new_characteristics;
1709 }
1710
1711 pub fn adapt_thresholds(&mut self, syndrome: &[bool], correction_success: bool) {
1713 let error_weight = syndrome.iter().filter(|&&x| x).count() as f64;
1714
1715 if correction_success {
1716 self.threshold_history.push_back(error_weight);
1718 } else {
1719 self.threshold_history.push_back(error_weight * 0.8);
1721 }
1722
1723 if self.threshold_history.len() > 100 {
1724 self.threshold_history.pop_front();
1725 }
1726 }
1727
1728 pub fn current_threshold(&self) -> f64 {
1730 if self.threshold_history.is_empty() {
1731 return 1.0; }
1733
1734 let sum: f64 = self.threshold_history.iter().sum();
1735 sum / self.threshold_history.len() as f64
1736 }
1737 }
1738
1739 impl SyndromeDecoder for AdaptiveThresholdDecoder {
1740 fn decode(&self, syndrome: &[bool]) -> QuantRS2Result<PauliString> {
1741 let threshold = self.current_threshold();
1742 let error_weight = syndrome.iter().filter(|&&x| x).count() as f64;
1743
1744 if error_weight > threshold {
1746 self.base_decoder.decode(syndrome)
1748 } else {
1749 Ok(PauliString::new(vec![Pauli::I; syndrome.len()]))
1751 }
1752 }
1753 }
1754
1755 pub struct ParallelSyndromeDecoder {
1757 base_decoder: Arc<dyn SyndromeDecoder + Send + Sync>,
1758 worker_count: usize,
1759 }
1760
1761 impl ParallelSyndromeDecoder {
1762 pub fn new(
1763 base_decoder: Arc<dyn SyndromeDecoder + Send + Sync>,
1764 worker_count: usize,
1765 ) -> Self {
1766 Self {
1767 base_decoder,
1768 worker_count,
1769 }
1770 }
1771
1772 pub fn decode_batch(&self, syndromes: &[Vec<bool>]) -> QuantRS2Result<Vec<PauliString>> {
1774 let chunk_size = (syndromes.len() + self.worker_count - 1) / self.worker_count;
1775 let mut handles = Vec::new();
1776
1777 for chunk in syndromes.chunks(chunk_size) {
1778 let decoder = Arc::clone(&self.base_decoder);
1779 let chunk_data: Vec<Vec<bool>> = chunk.to_vec();
1780
1781 let handle = thread::spawn(move || {
1782 let mut results = Vec::new();
1783 for syndrome in chunk_data {
1784 match decoder.decode(&syndrome) {
1785 Ok(correction) => results.push(correction),
1786 Err(_) => {
1787 results.push(PauliString::new(vec![Pauli::I; syndrome.len()]));
1788 }
1789 }
1790 }
1791 results
1792 });
1793
1794 handles.push(handle);
1795 }
1796
1797 let mut all_results = Vec::new();
1798 for handle in handles {
1799 match handle.join() {
1800 Ok(chunk_results) => all_results.extend(chunk_results),
1801 Err(_) => {
1802 return Err(QuantRS2Error::ComputationError(
1803 "Parallel decoding failed".to_string(),
1804 ))
1805 }
1806 }
1807 }
1808
1809 Ok(all_results)
1810 }
1811 }
1812
1813 impl SyndromeDecoder for ParallelSyndromeDecoder {
1814 fn decode(&self, syndrome: &[bool]) -> QuantRS2Result<PauliString> {
1815 self.base_decoder.decode(syndrome)
1816 }
1817 }
1818
1819 pub struct MockQuantumHardware {
1821 error_rate: f64,
1822 latency: Duration,
1823 syndrome_length: usize,
1824 }
1825
1826 impl MockQuantumHardware {
1827 pub const fn new(error_rate: f64, latency: Duration, syndrome_length: usize) -> Self {
1828 Self {
1829 error_rate,
1830 latency,
1831 syndrome_length,
1832 }
1833 }
1834 }
1835
1836 impl QuantumHardwareInterface for MockQuantumHardware {
1837 fn measure_syndromes(&self) -> QuantRS2Result<Vec<bool>> {
1838 thread::sleep(self.latency);
1839
1840 use scirs2_core::random::prelude::*;
1842 let mut rng = thread_rng();
1843 let mut syndrome = vec![false; self.syndrome_length];
1844 for i in 0..self.syndrome_length {
1845 if rng.gen::<f64>() < self.error_rate {
1846 syndrome[i] = true;
1847 }
1848 }
1849
1850 Ok(syndrome)
1851 }
1852
1853 fn apply_correction(&self, _correction: &PauliString) -> QuantRS2Result<()> {
1854 thread::sleep(self.latency / 2);
1855 Ok(())
1856 }
1857
1858 fn get_error_characteristics(&self) -> QuantRS2Result<HardwareErrorCharacteristics> {
1859 Ok(HardwareErrorCharacteristics {
1860 single_qubit_error_rates: vec![self.error_rate; self.syndrome_length],
1861 two_qubit_error_rates: vec![self.error_rate * 10.0; self.syndrome_length / 2],
1862 measurement_error_rates: vec![self.error_rate * 0.1; self.syndrome_length],
1863 correlated_errors: Vec::new(),
1864 temporal_variation: 0.01,
1865 })
1866 }
1867
1868 fn is_ready(&self) -> bool {
1869 true
1870 }
1871
1872 fn get_latency_stats(&self) -> QuantRS2Result<LatencyStats> {
1873 Ok(LatencyStats {
1874 syndrome_measurement_time: self.latency,
1875 decoding_time: Duration::from_micros(10),
1876 correction_application_time: self.latency / 2,
1877 total_cycle_time: self.latency + Duration::from_micros(10) + self.latency / 2,
1878 throughput_hz: 1.0 / self.latency.as_secs_f64().mul_add(1.5, 10e-6),
1879 })
1880 }
1881 }
1882}
1883
1884pub mod logical_gates {
1888 use super::*;
1889
1890 #[derive(Debug, Clone)]
1892 pub struct LogicalGateOp {
1893 pub code: StabilizerCode,
1895 pub physical_operations: Vec<PhysicalGateSequence>,
1897 pub logical_qubits: Vec<usize>,
1899 pub error_propagation: ErrorPropagationAnalysis,
1901 }
1902
1903 #[derive(Debug, Clone)]
1905 pub struct PhysicalGateSequence {
1906 pub target_qubits: Vec<usize>,
1908 pub pauli_sequence: Vec<PauliString>,
1910 pub timing_constraints: Option<TimingConstraints>,
1912 pub error_correction_rounds: usize,
1914 }
1915
1916 #[derive(Debug, Clone)]
1918 pub struct ErrorPropagationAnalysis {
1919 pub single_qubit_propagation: Vec<ErrorPropagationPath>,
1921 pub two_qubit_propagation: Vec<ErrorPropagationPath>,
1923 pub max_error_weight: usize,
1925 pub fault_tolerance_threshold: f64,
1927 }
1928
1929 #[derive(Debug, Clone)]
1931 pub struct ErrorPropagationPath {
1932 pub initial_error: PauliString,
1934 pub final_error: PauliString,
1936 pub probability: f64,
1938 pub correctable: bool,
1940 }
1941
1942 #[derive(Debug, Clone)]
1944 pub struct TimingConstraints {
1945 pub max_operation_time: std::time::Duration,
1947 pub sync_points: Vec<usize>,
1949 pub parallel_groups: Vec<Vec<usize>>,
1951 }
1952
1953 pub struct LogicalGateSynthesizer {
1955 codes: Vec<StabilizerCode>,
1957 strategies: Vec<SynthesisStrategy>,
1959 error_threshold: f64,
1961 }
1962
1963 #[derive(Debug, Clone)]
1965 pub enum SynthesisStrategy {
1966 Transversal,
1968 MagicStateDistillation,
1970 LatticeSurgery,
1972 CodeDeformation,
1974 Braiding,
1976 }
1977
1978 impl LogicalGateSynthesizer {
1979 pub fn new(error_threshold: f64) -> Self {
1981 Self {
1982 codes: Vec::new(),
1983 strategies: vec![
1984 SynthesisStrategy::Transversal,
1985 SynthesisStrategy::MagicStateDistillation,
1986 SynthesisStrategy::LatticeSurgery,
1987 ],
1988 error_threshold,
1989 }
1990 }
1991
1992 pub fn add_code(&mut self, code: StabilizerCode) {
1994 self.codes.push(code);
1995 }
1996
1997 pub fn synthesize_logical_x(
1999 &self,
2000 code: &StabilizerCode,
2001 logical_qubit: usize,
2002 ) -> QuantRS2Result<LogicalGateOp> {
2003 if logical_qubit >= code.k {
2004 return Err(QuantRS2Error::InvalidInput(format!(
2005 "Logical qubit {} exceeds code dimension {}",
2006 logical_qubit, code.k
2007 )));
2008 }
2009
2010 let logical_x_operator = &code.logical_x[logical_qubit];
2012
2013 let physical_ops = vec![PhysicalGateSequence {
2014 target_qubits: (0..code.n).collect(),
2015 pauli_sequence: vec![logical_x_operator.clone()],
2016 timing_constraints: None,
2017 error_correction_rounds: 1,
2018 }];
2019
2020 let error_analysis = self.analyze_error_propagation(code, &physical_ops)?;
2021
2022 Ok(LogicalGateOp {
2023 code: code.clone(),
2024 physical_operations: physical_ops,
2025 logical_qubits: vec![logical_qubit],
2026 error_propagation: error_analysis,
2027 })
2028 }
2029
2030 pub fn synthesize_logical_z(
2032 &self,
2033 code: &StabilizerCode,
2034 logical_qubit: usize,
2035 ) -> QuantRS2Result<LogicalGateOp> {
2036 if logical_qubit >= code.k {
2037 return Err(QuantRS2Error::InvalidInput(format!(
2038 "Logical qubit {} exceeds code dimension {}",
2039 logical_qubit, code.k
2040 )));
2041 }
2042
2043 let logical_z_operator = &code.logical_z[logical_qubit];
2044
2045 let physical_ops = vec![PhysicalGateSequence {
2046 target_qubits: (0..code.n).collect(),
2047 pauli_sequence: vec![logical_z_operator.clone()],
2048 timing_constraints: None,
2049 error_correction_rounds: 1,
2050 }];
2051
2052 let error_analysis = self.analyze_error_propagation(code, &physical_ops)?;
2053
2054 Ok(LogicalGateOp {
2055 code: code.clone(),
2056 physical_operations: physical_ops,
2057 logical_qubits: vec![logical_qubit],
2058 error_propagation: error_analysis,
2059 })
2060 }
2061
2062 pub fn synthesize_logical_h(
2064 &self,
2065 code: &StabilizerCode,
2066 logical_qubit: usize,
2067 ) -> QuantRS2Result<LogicalGateOp> {
2068 if logical_qubit >= code.k {
2069 return Err(QuantRS2Error::InvalidInput(format!(
2070 "Logical qubit {} exceeds code dimension {}",
2071 logical_qubit, code.k
2072 )));
2073 }
2074
2075 let physical_ops = vec![PhysicalGateSequence {
2078 target_qubits: (0..code.n).collect(),
2079 pauli_sequence: self.generate_hadamard_sequence(code, logical_qubit)?,
2080 timing_constraints: Some(TimingConstraints {
2081 max_operation_time: std::time::Duration::from_micros(100),
2082 sync_points: vec![code.n / 2],
2083 parallel_groups: vec![(0..code.n).collect()],
2084 }),
2085 error_correction_rounds: 2, }];
2087
2088 let error_analysis = self.analyze_error_propagation(code, &physical_ops)?;
2089
2090 Ok(LogicalGateOp {
2091 code: code.clone(),
2092 physical_operations: physical_ops,
2093 logical_qubits: vec![logical_qubit],
2094 error_propagation: error_analysis,
2095 })
2096 }
2097
2098 pub fn synthesize_logical_cnot(
2100 &self,
2101 code: &StabilizerCode,
2102 control_qubit: usize,
2103 target_qubit: usize,
2104 ) -> QuantRS2Result<LogicalGateOp> {
2105 if control_qubit >= code.k || target_qubit >= code.k {
2106 return Err(QuantRS2Error::InvalidInput(
2107 "Control or target qubit exceeds code dimension".to_string(),
2108 ));
2109 }
2110
2111 if control_qubit == target_qubit {
2112 return Err(QuantRS2Error::InvalidInput(
2113 "Control and target qubits must be different".to_string(),
2114 ));
2115 }
2116
2117 let cnot_sequence = self.generate_cnot_sequence(code, control_qubit, target_qubit)?;
2119
2120 let physical_ops = vec![PhysicalGateSequence {
2121 target_qubits: (0..code.n).collect(),
2122 pauli_sequence: cnot_sequence,
2123 timing_constraints: Some(TimingConstraints {
2124 max_operation_time: std::time::Duration::from_micros(200),
2125 sync_points: vec![],
2126 parallel_groups: vec![], }),
2128 error_correction_rounds: 2,
2129 }];
2130
2131 let error_analysis = self.analyze_error_propagation(code, &physical_ops)?;
2132
2133 Ok(LogicalGateOp {
2134 code: code.clone(),
2135 physical_operations: physical_ops,
2136 logical_qubits: vec![control_qubit, target_qubit],
2137 error_propagation: error_analysis,
2138 })
2139 }
2140
2141 pub fn synthesize_logical_t(
2143 &self,
2144 code: &StabilizerCode,
2145 logical_qubit: usize,
2146 ) -> QuantRS2Result<LogicalGateOp> {
2147 if logical_qubit >= code.k {
2148 return Err(QuantRS2Error::InvalidInput(format!(
2149 "Logical qubit {} exceeds code dimension {}",
2150 logical_qubit, code.k
2151 )));
2152 }
2153
2154 let magic_state_prep = self.prepare_magic_state(code)?;
2156 let injection_sequence =
2157 self.inject_magic_state(code, logical_qubit, &magic_state_prep)?;
2158
2159 let physical_ops = vec![magic_state_prep, injection_sequence];
2160
2161 let error_analysis = self.analyze_error_propagation(code, &physical_ops)?;
2162
2163 Ok(LogicalGateOp {
2164 code: code.clone(),
2165 physical_operations: physical_ops,
2166 logical_qubits: vec![logical_qubit],
2167 error_propagation: error_analysis,
2168 })
2169 }
2170
2171 fn generate_hadamard_sequence(
2173 &self,
2174 code: &StabilizerCode,
2175 _logical_qubit: usize,
2176 ) -> QuantRS2Result<Vec<PauliString>> {
2177 let mut sequence = Vec::new();
2180
2181 sequence.push(PauliString::new(vec![Pauli::I; code.n]));
2185
2186 Ok(sequence)
2187 }
2188
2189 fn generate_cnot_sequence(
2191 &self,
2192 code: &StabilizerCode,
2193 _control: usize,
2194 _target: usize,
2195 ) -> QuantRS2Result<Vec<PauliString>> {
2196 let mut sequence = Vec::new();
2199
2200 sequence.push(PauliString::new(vec![Pauli::I; code.n]));
2202
2203 Ok(sequence)
2204 }
2205
2206 fn prepare_magic_state(
2208 &self,
2209 code: &StabilizerCode,
2210 ) -> QuantRS2Result<PhysicalGateSequence> {
2211 Ok(PhysicalGateSequence {
2214 target_qubits: (0..code.n).collect(),
2215 pauli_sequence: vec![PauliString::new(vec![Pauli::I; code.n])],
2216 timing_constraints: Some(TimingConstraints {
2217 max_operation_time: std::time::Duration::from_millis(1),
2218 sync_points: vec![],
2219 parallel_groups: vec![(0..code.n).collect()],
2220 }),
2221 error_correction_rounds: 5, })
2223 }
2224
2225 fn inject_magic_state(
2227 &self,
2228 code: &StabilizerCode,
2229 _logical_qubit: usize,
2230 _magic_state: &PhysicalGateSequence,
2231 ) -> QuantRS2Result<PhysicalGateSequence> {
2232 Ok(PhysicalGateSequence {
2234 target_qubits: (0..code.n).collect(),
2235 pauli_sequence: vec![PauliString::new(vec![Pauli::I; code.n])],
2236 timing_constraints: Some(TimingConstraints {
2237 max_operation_time: std::time::Duration::from_micros(500),
2238 sync_points: vec![code.n / 2],
2239 parallel_groups: vec![],
2240 }),
2241 error_correction_rounds: 3,
2242 })
2243 }
2244
2245 fn analyze_error_propagation(
2247 &self,
2248 code: &StabilizerCode,
2249 physical_ops: &[PhysicalGateSequence],
2250 ) -> QuantRS2Result<ErrorPropagationAnalysis> {
2251 let mut single_qubit_propagation = Vec::new();
2252 let mut two_qubit_propagation = Vec::new();
2253 let mut max_error_weight = 0;
2254
2255 for i in 0..code.n {
2257 for pauli in [Pauli::X, Pauli::Y, Pauli::Z] {
2258 let mut initial_error = vec![Pauli::I; code.n];
2259 initial_error[i] = pauli;
2260 let initial_pauli_string = PauliString::new(initial_error);
2261
2262 let final_error = self.propagate_error(&initial_pauli_string, physical_ops)?;
2264 let error_weight = final_error.weight();
2265 max_error_weight = max_error_weight.max(error_weight);
2266
2267 let correctable = self.is_error_correctable(code, &final_error)?;
2269
2270 single_qubit_propagation.push(ErrorPropagationPath {
2271 initial_error: initial_pauli_string,
2272 final_error,
2273 probability: 1.0 / (3.0 * code.n as f64), correctable,
2275 });
2276 }
2277 }
2278
2279 for i in 0..code.n.min(5) {
2281 for j in (i + 1)..code.n.min(5) {
2283 let mut initial_error = vec![Pauli::I; code.n];
2284 initial_error[i] = Pauli::X;
2285 initial_error[j] = Pauli::X;
2286 let initial_pauli_string = PauliString::new(initial_error);
2287
2288 let final_error = self.propagate_error(&initial_pauli_string, physical_ops)?;
2289 let error_weight = final_error.weight();
2290 max_error_weight = max_error_weight.max(error_weight);
2291
2292 let correctable = self.is_error_correctable(code, &final_error)?;
2293
2294 two_qubit_propagation.push(ErrorPropagationPath {
2295 initial_error: initial_pauli_string,
2296 final_error,
2297 probability: 1.0 / (code.n * (code.n - 1)) as f64,
2298 correctable,
2299 });
2300 }
2301 }
2302
2303 Ok(ErrorPropagationAnalysis {
2304 single_qubit_propagation,
2305 two_qubit_propagation,
2306 max_error_weight,
2307 fault_tolerance_threshold: self.error_threshold,
2308 })
2309 }
2310
2311 fn propagate_error(
2313 &self,
2314 error: &PauliString,
2315 _physical_ops: &[PhysicalGateSequence],
2316 ) -> QuantRS2Result<PauliString> {
2317 Ok(error.clone())
2320 }
2321
2322 fn is_error_correctable(
2324 &self,
2325 code: &StabilizerCode,
2326 error: &PauliString,
2327 ) -> QuantRS2Result<bool> {
2328 Ok(error.weight() <= (code.d + 1) / 2)
2331 }
2332 }
2333
2334 pub struct LogicalCircuitSynthesizer {
2336 gate_synthesizer: LogicalGateSynthesizer,
2337 optimization_passes: Vec<OptimizationPass>,
2338 }
2339
2340 #[derive(Debug, Clone)]
2342 pub enum OptimizationPass {
2343 PauliOptimization,
2345 ErrorCorrectionOptimization,
2347 ParallelizationOptimization,
2349 MagicStateOptimization,
2351 }
2352
2353 impl LogicalCircuitSynthesizer {
2354 pub fn new(error_threshold: f64) -> Self {
2355 Self {
2356 gate_synthesizer: LogicalGateSynthesizer::new(error_threshold),
2357 optimization_passes: vec![
2358 OptimizationPass::PauliOptimization,
2359 OptimizationPass::ErrorCorrectionOptimization,
2360 OptimizationPass::ParallelizationOptimization,
2361 OptimizationPass::MagicStateOptimization,
2362 ],
2363 }
2364 }
2365
2366 pub fn add_code(&mut self, code: StabilizerCode) {
2368 self.gate_synthesizer.add_code(code);
2369 }
2370
2371 pub fn synthesize_circuit(
2373 &self,
2374 code: &StabilizerCode,
2375 gate_sequence: &[(&str, Vec<usize>)], ) -> QuantRS2Result<Vec<LogicalGateOp>> {
2377 let mut logical_gates = Vec::new();
2378
2379 for (gate_name, targets) in gate_sequence {
2380 match gate_name.to_lowercase().as_str() {
2381 "x" | "pauli_x" => {
2382 if targets.len() != 1 {
2383 return Err(QuantRS2Error::InvalidInput(
2384 "X gate requires exactly one target".to_string(),
2385 ));
2386 }
2387 logical_gates.push(
2388 self.gate_synthesizer
2389 .synthesize_logical_x(code, targets[0])?,
2390 );
2391 }
2392 "z" | "pauli_z" => {
2393 if targets.len() != 1 {
2394 return Err(QuantRS2Error::InvalidInput(
2395 "Z gate requires exactly one target".to_string(),
2396 ));
2397 }
2398 logical_gates.push(
2399 self.gate_synthesizer
2400 .synthesize_logical_z(code, targets[0])?,
2401 );
2402 }
2403 "h" | "hadamard" => {
2404 if targets.len() != 1 {
2405 return Err(QuantRS2Error::InvalidInput(
2406 "H gate requires exactly one target".to_string(),
2407 ));
2408 }
2409 logical_gates.push(
2410 self.gate_synthesizer
2411 .synthesize_logical_h(code, targets[0])?,
2412 );
2413 }
2414 "cnot" | "cx" => {
2415 if targets.len() != 2 {
2416 return Err(QuantRS2Error::InvalidInput(
2417 "CNOT gate requires exactly two targets".to_string(),
2418 ));
2419 }
2420 logical_gates.push(
2421 self.gate_synthesizer
2422 .synthesize_logical_cnot(code, targets[0], targets[1])?,
2423 );
2424 }
2425 "t" => {
2426 if targets.len() != 1 {
2427 return Err(QuantRS2Error::InvalidInput(
2428 "T gate requires exactly one target".to_string(),
2429 ));
2430 }
2431 logical_gates.push(
2432 self.gate_synthesizer
2433 .synthesize_logical_t(code, targets[0])?,
2434 );
2435 }
2436 _ => {
2437 return Err(QuantRS2Error::UnsupportedOperation(format!(
2438 "Unsupported logical gate: {gate_name}"
2439 )));
2440 }
2441 }
2442 }
2443
2444 self.optimize_circuit(logical_gates)
2446 }
2447
2448 fn optimize_circuit(
2450 &self,
2451 mut circuit: Vec<LogicalGateOp>,
2452 ) -> QuantRS2Result<Vec<LogicalGateOp>> {
2453 for pass in &self.optimization_passes {
2454 circuit = self.apply_optimization_pass(circuit, pass)?;
2455 }
2456 Ok(circuit)
2457 }
2458
2459 const fn apply_optimization_pass(
2461 &self,
2462 circuit: Vec<LogicalGateOp>,
2463 pass: &OptimizationPass,
2464 ) -> QuantRS2Result<Vec<LogicalGateOp>> {
2465 match pass {
2466 OptimizationPass::PauliOptimization => self.optimize_pauli_gates(circuit),
2467 OptimizationPass::ErrorCorrectionOptimization => {
2468 self.optimize_error_correction(circuit)
2469 }
2470 OptimizationPass::ParallelizationOptimization => {
2471 self.optimize_parallelization(circuit)
2472 }
2473 OptimizationPass::MagicStateOptimization => self.optimize_magic_states(circuit),
2474 }
2475 }
2476
2477 const fn optimize_pauli_gates(
2479 &self,
2480 circuit: Vec<LogicalGateOp>,
2481 ) -> QuantRS2Result<Vec<LogicalGateOp>> {
2482 Ok(circuit) }
2485
2486 const fn optimize_error_correction(
2488 &self,
2489 circuit: Vec<LogicalGateOp>,
2490 ) -> QuantRS2Result<Vec<LogicalGateOp>> {
2491 Ok(circuit) }
2494
2495 const fn optimize_parallelization(
2497 &self,
2498 circuit: Vec<LogicalGateOp>,
2499 ) -> QuantRS2Result<Vec<LogicalGateOp>> {
2500 Ok(circuit) }
2503
2504 const fn optimize_magic_states(
2506 &self,
2507 circuit: Vec<LogicalGateOp>,
2508 ) -> QuantRS2Result<Vec<LogicalGateOp>> {
2509 Ok(circuit) }
2512
2513 pub fn estimate_resources(&self, circuit: &[LogicalGateOp]) -> LogicalCircuitResources {
2515 let mut total_physical_operations = 0;
2516 let mut total_error_correction_rounds = 0;
2517 let mut max_parallelism = 0;
2518 let mut magic_states_required = 0;
2519
2520 for gate in circuit {
2521 total_physical_operations += gate.physical_operations.len();
2522 for op in &gate.physical_operations {
2523 total_error_correction_rounds += op.error_correction_rounds;
2524 if let Some(constraints) = &op.timing_constraints {
2525 max_parallelism = max_parallelism.max(constraints.parallel_groups.len());
2526 }
2527 }
2528
2529 if gate.logical_qubits.len() == 1 {
2531 magic_states_required += 1;
2533 }
2534 }
2535
2536 LogicalCircuitResources {
2537 total_physical_operations,
2538 total_error_correction_rounds,
2539 max_parallelism,
2540 magic_states_required,
2541 estimated_depth: circuit.len(),
2542 estimated_time: std::time::Duration::from_millis(
2543 (total_error_correction_rounds * 10) as u64,
2544 ),
2545 }
2546 }
2547 }
2548
2549 #[derive(Debug, Clone)]
2551 pub struct LogicalCircuitResources {
2552 pub total_physical_operations: usize,
2553 pub total_error_correction_rounds: usize,
2554 pub max_parallelism: usize,
2555 pub magic_states_required: usize,
2556 pub estimated_depth: usize,
2557 pub estimated_time: std::time::Duration,
2558 }
2559}
2560
2561pub mod adaptive_threshold {
2565 use super::*;
2566 use std::collections::{HashMap, VecDeque};
2567 use std::time::{Duration, Instant};
2568
2569 pub struct AdaptiveThresholdEstimator {
2571 error_history: VecDeque<ErrorObservation>,
2573 noise_model: NoiseModel,
2575 estimation_algorithm: ThresholdEstimationAlgorithm,
2577 performance_tracker: PerformanceTracker,
2579 config: AdaptiveConfig,
2581 }
2582
2583 #[derive(Debug, Clone)]
2585 pub struct ErrorObservation {
2586 pub syndrome: Vec<bool>,
2588 pub correction: PauliString,
2590 pub success: bool,
2592 pub observed_error_rate: f64,
2594 pub timestamp: Instant,
2596 pub environment: EnvironmentalConditions,
2598 }
2599
2600 #[derive(Debug, Clone)]
2602 pub struct EnvironmentalConditions {
2603 pub temperature: f64,
2605 pub magnetic_field: f64,
2607 pub vibration_level: f64,
2609 pub emi_level: f64,
2611 pub uptime: f64,
2613 }
2614
2615 #[derive(Debug, Clone)]
2617 pub struct NoiseModel {
2618 pub single_qubit_rates: HashMap<(usize, Pauli), f64>,
2620 pub correlated_rates: HashMap<(usize, usize), f64>,
2622 pub temporal_correlation: f64,
2624 pub environment_sensitivity: EnvironmentSensitivity,
2626 pub confidence: f64,
2628 }
2629
2630 #[derive(Debug, Clone)]
2632 pub struct EnvironmentSensitivity {
2633 pub temperature_coeff: f64,
2635 pub magnetic_field_coeff: f64,
2637 pub vibration_coeff: f64,
2639 pub emi_coeff: f64,
2641 pub drift_coeff: f64,
2643 }
2644
2645 #[derive(Debug, Clone)]
2647 pub enum ThresholdEstimationAlgorithm {
2648 Bayesian {
2650 prior_strength: f64,
2651 update_rate: f64,
2652 },
2653 MachineLearning {
2655 model_type: MLModelType,
2656 training_window: usize,
2657 },
2658 KalmanFilter {
2660 process_noise: f64,
2661 measurement_noise: f64,
2662 },
2663 ExponentialAverage { alpha: f64 },
2665 }
2666
2667 #[derive(Debug, Clone)]
2669 pub enum MLModelType {
2670 LinearRegression,
2671 RandomForest,
2672 NeuralNetwork { hidden_layers: Vec<usize> },
2673 SupportVectorMachine,
2674 }
2675
2676 #[derive(Debug, Clone)]
2678 pub struct PerformanceTracker {
2679 pub successful_corrections: u64,
2681 pub failed_corrections: u64,
2683 pub false_positives: u64,
2685 pub false_negatives: u64,
2687 pub average_latency: Duration,
2689 pub threshold_accuracy: f64,
2691 }
2692
2693 #[derive(Debug, Clone)]
2695 pub struct AdaptiveConfig {
2696 pub max_history_size: usize,
2698 pub min_observations: usize,
2700 pub update_frequency: Duration,
2702 pub confidence_threshold: f64,
2704 pub environmental_monitoring: bool,
2706 pub real_time_adaptation: bool,
2708 }
2709
2710 #[derive(Debug, Clone)]
2712 pub struct ThresholdRecommendation {
2713 pub threshold: f64,
2715 pub confidence: f64,
2717 pub predicted_error_rate: f64,
2719 pub recommendation_quality: f64,
2721 pub environmental_impact: f64,
2723 }
2724
2725 impl Default for AdaptiveConfig {
2726 fn default() -> Self {
2727 Self {
2728 max_history_size: 10000,
2729 min_observations: 100,
2730 update_frequency: Duration::from_secs(30),
2731 confidence_threshold: 0.8,
2732 environmental_monitoring: true,
2733 real_time_adaptation: true,
2734 }
2735 }
2736 }
2737
2738 impl Default for EnvironmentalConditions {
2739 fn default() -> Self {
2740 Self {
2741 temperature: 300.0, magnetic_field: 0.0,
2743 vibration_level: 0.0,
2744 emi_level: 0.0,
2745 uptime: 0.0,
2746 }
2747 }
2748 }
2749
2750 impl Default for EnvironmentSensitivity {
2751 fn default() -> Self {
2752 Self {
2753 temperature_coeff: 1e-5,
2754 magnetic_field_coeff: 1e-3,
2755 vibration_coeff: 1e-4,
2756 emi_coeff: 1e-4,
2757 drift_coeff: 1e-7,
2758 }
2759 }
2760 }
2761
2762 impl Default for NoiseModel {
2763 fn default() -> Self {
2764 Self {
2765 single_qubit_rates: HashMap::new(),
2766 correlated_rates: HashMap::new(),
2767 temporal_correlation: 0.1,
2768 environment_sensitivity: EnvironmentSensitivity::default(),
2769 confidence: 0.5,
2770 }
2771 }
2772 }
2773
2774 impl PerformanceTracker {
2775 pub const fn new() -> Self {
2776 Self {
2777 successful_corrections: 0,
2778 failed_corrections: 0,
2779 false_positives: 0,
2780 false_negatives: 0,
2781 average_latency: Duration::from_nanos(0),
2782 threshold_accuracy: 0.0,
2783 }
2784 }
2785
2786 pub fn precision(&self) -> f64 {
2787 let total_positive = self.successful_corrections + self.false_positives;
2788 if total_positive == 0 {
2789 1.0
2790 } else {
2791 self.successful_corrections as f64 / total_positive as f64
2792 }
2793 }
2794
2795 pub fn recall(&self) -> f64 {
2796 let total_actual_positive = self.successful_corrections + self.false_negatives;
2797 if total_actual_positive == 0 {
2798 1.0
2799 } else {
2800 self.successful_corrections as f64 / total_actual_positive as f64
2801 }
2802 }
2803
2804 pub fn f1_score(&self) -> f64 {
2805 let p = self.precision();
2806 let r = self.recall();
2807 if p + r == 0.0 {
2808 0.0
2809 } else {
2810 2.0 * p * r / (p + r)
2811 }
2812 }
2813 }
2814
2815 impl AdaptiveThresholdEstimator {
2816 pub fn new(
2818 initial_noise_model: NoiseModel,
2819 algorithm: ThresholdEstimationAlgorithm,
2820 config: AdaptiveConfig,
2821 ) -> Self {
2822 Self {
2823 error_history: VecDeque::with_capacity(config.max_history_size),
2824 noise_model: initial_noise_model,
2825 estimation_algorithm: algorithm,
2826 performance_tracker: PerformanceTracker::new(),
2827 config,
2828 }
2829 }
2830
2831 pub fn add_observation(&mut self, observation: ErrorObservation) {
2833 if self.error_history.len() >= self.config.max_history_size {
2835 self.error_history.pop_front();
2836 }
2837 self.error_history.push_back(observation.clone());
2838
2839 self.update_performance_tracking(&observation);
2841
2842 if self.config.real_time_adaptation
2844 && self.error_history.len() >= self.config.min_observations
2845 {
2846 self.update_noise_model();
2847 }
2848 }
2849
2850 pub fn estimate_threshold(
2852 &self,
2853 syndrome: &[bool],
2854 environment: &EnvironmentalConditions,
2855 ) -> f64 {
2856 match &self.estimation_algorithm {
2857 ThresholdEstimationAlgorithm::Bayesian {
2858 prior_strength,
2859 update_rate,
2860 } => self.bayesian_threshold_estimation(
2861 syndrome,
2862 environment,
2863 *prior_strength,
2864 *update_rate,
2865 ),
2866 ThresholdEstimationAlgorithm::MachineLearning {
2867 model_type,
2868 training_window,
2869 } => self.ml_threshold_estimation(
2870 syndrome,
2871 environment,
2872 model_type,
2873 *training_window,
2874 ),
2875 ThresholdEstimationAlgorithm::KalmanFilter {
2876 process_noise,
2877 measurement_noise,
2878 } => self.kalman_threshold_estimation(
2879 syndrome,
2880 environment,
2881 *process_noise,
2882 *measurement_noise,
2883 ),
2884 ThresholdEstimationAlgorithm::ExponentialAverage { alpha } => {
2885 self.exponential_average_threshold(syndrome, environment, *alpha)
2886 }
2887 }
2888 }
2889
2890 pub fn get_threshold_recommendation(&self, syndrome: &[bool]) -> ThresholdRecommendation {
2892 let current_env = EnvironmentalConditions::default(); let threshold = self.estimate_threshold(syndrome, ¤t_env);
2894 let confidence = self.noise_model.confidence;
2895 let predicted_rate = self.predict_error_rate(¤t_env, Duration::from_secs(60));
2896
2897 ThresholdRecommendation {
2898 threshold,
2899 confidence,
2900 predicted_error_rate: predicted_rate,
2901 recommendation_quality: self.assess_recommendation_quality(),
2902 environmental_impact: self.assess_environmental_impact(¤t_env),
2903 }
2904 }
2905
2906 pub fn predict_error_rate(
2908 &self,
2909 environment: &EnvironmentalConditions,
2910 horizon: Duration,
2911 ) -> f64 {
2912 let base_rate = self.calculate_base_error_rate();
2913 let environmental_factor = self.calculate_environmental_factor(environment);
2914 let temporal_factor = self.calculate_temporal_factor(horizon);
2915
2916 base_rate * environmental_factor * temporal_factor
2917 }
2918
2919 fn bayesian_threshold_estimation(
2921 &self,
2922 syndrome: &[bool],
2923 environment: &EnvironmentalConditions,
2924 prior_strength: f64,
2925 update_rate: f64,
2926 ) -> f64 {
2927 let syndrome_weight = syndrome.iter().filter(|&&x| x).count() as f64;
2928 let base_threshold = self.calculate_base_threshold(syndrome_weight);
2929
2930 let historical_adjustment = self.calculate_historical_adjustment(update_rate);
2932
2933 let env_adjustment = self.calculate_environmental_adjustment(environment);
2935
2936 let prior = base_threshold;
2938 let likelihood_weight = 1.0 / (1.0 + prior_strength);
2939
2940 prior.mul_add(
2941 1.0 - likelihood_weight,
2942 (base_threshold + historical_adjustment + env_adjustment) * likelihood_weight,
2943 )
2944 }
2945
2946 fn ml_threshold_estimation(
2948 &self,
2949 syndrome: &[bool],
2950 environment: &EnvironmentalConditions,
2951 model_type: &MLModelType,
2952 training_window: usize,
2953 ) -> f64 {
2954 let features = self.extract_features(syndrome, environment);
2956
2957 let training_data = self.get_recent_observations(training_window);
2959
2960 match model_type {
2961 MLModelType::LinearRegression => {
2962 self.linear_regression_predict(&features, &training_data)
2963 }
2964 _ => {
2965 self.linear_regression_predict(&features, &training_data)
2967 }
2968 }
2969 }
2970
2971 fn kalman_threshold_estimation(
2973 &self,
2974 syndrome: &[bool],
2975 _environment: &EnvironmentalConditions,
2976 process_noise: f64,
2977 measurement_noise: f64,
2978 ) -> f64 {
2979 let syndrome_weight = syndrome.iter().filter(|&&x| x).count() as f64;
2980 let base_threshold = self.calculate_base_threshold(syndrome_weight);
2981
2982 let prediction_error = self.calculate_prediction_error();
2984 let kalman_gain = process_noise / (process_noise + measurement_noise);
2985
2986 kalman_gain.mul_add(prediction_error, base_threshold)
2987 }
2988
2989 fn exponential_average_threshold(
2991 &self,
2992 syndrome: &[bool],
2993 _environment: &EnvironmentalConditions,
2994 alpha: f64,
2995 ) -> f64 {
2996 let syndrome_weight = syndrome.iter().filter(|&&x| x).count() as f64;
2997 let current_threshold = self.calculate_base_threshold(syndrome_weight);
2998
2999 if let Some(_last_obs) = self.error_history.back() {
3000 let last_threshold = syndrome_weight; alpha.mul_add(current_threshold, (1.0 - alpha) * last_threshold)
3002 } else {
3003 current_threshold
3004 }
3005 }
3006
3007 fn calculate_base_error_rate(&self) -> f64 {
3009 if self.error_history.is_empty() {
3010 return 0.001; }
3012
3013 let recent_errors: Vec<_> = self.error_history.iter().rev().take(100).collect();
3014
3015 let total_errors = recent_errors.len() as f64;
3016 let failed_corrections = recent_errors.iter().filter(|obs| !obs.success).count() as f64;
3017
3018 failed_corrections / total_errors
3019 }
3020
3021 fn calculate_environmental_factor(&self, environment: &EnvironmentalConditions) -> f64 {
3022 let sensitivity = &self.noise_model.environment_sensitivity;
3023
3024 sensitivity.drift_coeff.mul_add(
3025 environment.uptime,
3026 sensitivity.emi_coeff.mul_add(
3027 environment.emi_level,
3028 sensitivity.vibration_coeff.mul_add(
3029 environment.vibration_level,
3030 sensitivity.magnetic_field_coeff.mul_add(
3031 environment.magnetic_field,
3032 sensitivity
3033 .temperature_coeff
3034 .mul_add(environment.temperature - 300.0, 1.0),
3035 ),
3036 ),
3037 ),
3038 )
3039 }
3040
3041 fn calculate_temporal_factor(&self, horizon: Duration) -> f64 {
3042 let temporal_corr = self.noise_model.temporal_correlation;
3043 let time_factor = horizon.as_secs_f64() / 3600.0; temporal_corr.mul_add(time_factor, 1.0)
3046 }
3047
3048 fn calculate_base_threshold(&self, syndrome_weight: f64) -> f64 {
3049 (syndrome_weight + 1.0) / 10.0
3051 }
3052
3053 fn calculate_historical_adjustment(&self, update_rate: f64) -> f64 {
3054 if self.error_history.is_empty() {
3055 return 0.0;
3056 }
3057
3058 let recent_success_rate = self.calculate_recent_success_rate();
3059 update_rate * (0.5 - recent_success_rate) }
3061
3062 fn calculate_environmental_adjustment(&self, environment: &EnvironmentalConditions) -> f64 {
3063 let env_factor = self.calculate_environmental_factor(environment);
3064 (env_factor - 1.0) * 0.1 }
3066
3067 fn calculate_recent_success_rate(&self) -> f64 {
3068 let recent_window = 50.min(self.error_history.len());
3069 if recent_window == 0 {
3070 return 0.5;
3071 }
3072
3073 let recent_successes = self
3074 .error_history
3075 .iter()
3076 .rev()
3077 .take(recent_window)
3078 .filter(|obs| obs.success)
3079 .count();
3080
3081 recent_successes as f64 / recent_window as f64
3082 }
3083
3084 fn calculate_prediction_error(&self) -> f64 {
3085 let target_success_rate = 0.95;
3087 let actual_success_rate = self.calculate_recent_success_rate();
3088 target_success_rate - actual_success_rate
3089 }
3090
3091 fn extract_features(
3092 &self,
3093 syndrome: &[bool],
3094 environment: &EnvironmentalConditions,
3095 ) -> Vec<f64> {
3096 let mut features = vec![
3097 syndrome.iter().filter(|&&x| x).count() as f64,
3098 environment.temperature,
3099 environment.magnetic_field,
3100 environment.vibration_level,
3101 environment.emi_level,
3102 environment.uptime,
3103 ];
3104
3105 for &bit in syndrome {
3107 features.push(if bit { 1.0 } else { 0.0 });
3108 }
3109
3110 features
3111 }
3112
3113 fn get_recent_observations(&self, window: usize) -> Vec<ErrorObservation> {
3114 self.error_history
3115 .iter()
3116 .rev()
3117 .take(window)
3118 .cloned()
3119 .collect()
3120 }
3121
3122 fn linear_regression_predict(
3123 &self,
3124 _features: &[f64],
3125 training_data: &[ErrorObservation],
3126 ) -> f64 {
3127 if training_data.is_empty() {
3129 return 0.5;
3130 }
3131
3132 let avg_syndrome_weight: f64 = training_data
3133 .iter()
3134 .map(|obs| obs.syndrome.iter().filter(|&&x| x).count() as f64)
3135 .sum::<f64>()
3136 / training_data.len() as f64;
3137
3138 (avg_syndrome_weight + 1.0) / 10.0
3139 }
3140
3141 fn update_performance_tracking(&mut self, observation: &ErrorObservation) {
3142 if observation.success {
3143 self.performance_tracker.successful_corrections += 1;
3144 } else {
3145 self.performance_tracker.failed_corrections += 1;
3146 }
3147
3148 let total = self.performance_tracker.successful_corrections
3150 + self.performance_tracker.failed_corrections;
3151 if total > 0 {
3152 self.performance_tracker.threshold_accuracy =
3153 self.performance_tracker.successful_corrections as f64 / total as f64;
3154 }
3155 }
3156
3157 fn update_noise_model(&mut self) {
3158 let recent_window = self.config.min_observations.min(self.error_history.len());
3159 let recent_observations: Vec<ErrorObservation> = self
3160 .error_history
3161 .iter()
3162 .rev()
3163 .take(recent_window)
3164 .cloned()
3165 .collect();
3166
3167 self.update_single_qubit_rates(&recent_observations);
3169
3170 self.update_model_confidence(&recent_observations);
3172 }
3173
3174 fn update_single_qubit_rates(&mut self, observations: &[ErrorObservation]) {
3175 for obs in observations {
3177 for (i, pauli) in obs.correction.paulis.iter().enumerate() {
3178 if *pauli != Pauli::I {
3179 let key = (i, *pauli);
3180 let current_rate = self
3181 .noise_model
3182 .single_qubit_rates
3183 .get(&key)
3184 .copied()
3185 .unwrap_or(0.001);
3186 let new_rate = if obs.success {
3187 current_rate * 0.99
3188 } else {
3189 current_rate * 1.01
3190 };
3191 self.noise_model.single_qubit_rates.insert(key, new_rate);
3192 }
3193 }
3194 }
3195 }
3196
3197 fn update_model_confidence(&mut self, observations: &[ErrorObservation]) {
3198 if observations.is_empty() {
3199 return;
3200 }
3201
3202 let success_rate = observations.iter().filter(|obs| obs.success).count() as f64
3203 / observations.len() as f64;
3204
3205 let stability = (success_rate - 0.5).abs().mul_add(-2.0, 1.0);
3207 self.noise_model.confidence =
3208 self.noise_model.confidence.mul_add(0.95, stability * 0.05);
3209 }
3210
3211 fn assess_recommendation_quality(&self) -> f64 {
3212 let confidence_component = self.noise_model.confidence;
3214 let performance_component = self.performance_tracker.threshold_accuracy;
3215 let history_component =
3216 (self.error_history.len() as f64 / self.config.max_history_size as f64).min(1.0);
3217
3218 (confidence_component + performance_component + history_component) / 3.0
3219 }
3220
3221 fn assess_environmental_impact(&self, environment: &EnvironmentalConditions) -> f64 {
3222 let env_factor = self.calculate_environmental_factor(environment);
3223 (env_factor - 1.0).abs()
3224 }
3225 }
3226}
3227
3228#[cfg(test)]
3229mod tests {
3230 use super::*;
3231
3232 #[test]
3233 fn test_pauli_multiplication() {
3234 let (phase, result) = Pauli::X.multiply(&Pauli::Y);
3235 assert_eq!(result, Pauli::Z);
3236 assert_eq!(phase, Complex64::new(0.0, 1.0));
3237 }
3238
3239 #[test]
3240 fn test_pauli_string_commutation() {
3241 let ps1 = PauliString::new(vec![Pauli::X, Pauli::I]);
3242 let ps2 = PauliString::new(vec![Pauli::Z, Pauli::I]);
3243 assert!(!ps1
3244 .commutes_with(&ps2)
3245 .expect("Commutation check should succeed"));
3246
3247 let ps3 = PauliString::new(vec![Pauli::X, Pauli::I]);
3248 let ps4 = PauliString::new(vec![Pauli::I, Pauli::Z]);
3249 assert!(ps3
3250 .commutes_with(&ps4)
3251 .expect("Commutation check should succeed"));
3252 }
3253
3254 #[test]
3255 fn test_repetition_code() {
3256 let code = StabilizerCode::repetition_code();
3257 assert_eq!(code.n, 3);
3258 assert_eq!(code.k, 1);
3259 assert_eq!(code.d, 1);
3260
3261 let error = PauliString::new(vec![Pauli::X, Pauli::I, Pauli::I]);
3263 let syndrome = code
3264 .syndrome(&error)
3265 .expect("Syndrome extraction should succeed");
3266 assert_eq!(syndrome, vec![true, false]);
3268 }
3269
3270 #[test]
3271 fn test_steane_code() {
3272 let code = StabilizerCode::steane_code();
3273 assert_eq!(code.n, 7);
3274 assert_eq!(code.k, 1);
3275 assert_eq!(code.d, 3);
3276
3277 for i in 0..code.stabilizers.len() {
3279 for j in i + 1..code.stabilizers.len() {
3280 assert!(code.stabilizers[i]
3281 .commutes_with(&code.stabilizers[j])
3282 .expect("Stabilizer commutation check should succeed"));
3283 }
3284 }
3285 }
3286
3287 #[test]
3288 fn test_surface_code() {
3289 let surface = SurfaceCode::new(3, 3);
3290 assert_eq!(surface.distance(), 3);
3291
3292 let code = surface
3293 .to_stabilizer_code()
3294 .expect("Surface code conversion should succeed");
3295 assert_eq!(code.n, 9);
3296 assert_eq!(code.stabilizers.len(), 4);
3298 }
3299
3300 #[test]
3301 fn test_lookup_decoder() {
3302 let code = StabilizerCode::repetition_code();
3303 let decoder = LookupDecoder::new(&code).expect("Lookup decoder creation should succeed");
3304
3305 let trivial_syndrome = vec![false, false];
3307 let decoded = decoder
3308 .decode(&trivial_syndrome)
3309 .expect("Decoding trivial syndrome should succeed");
3310 assert_eq!(decoded.weight(), 0); let error = PauliString::new(vec![Pauli::X, Pauli::I, Pauli::I]);
3314 let syndrome = code
3315 .syndrome(&error)
3316 .expect("Syndrome extraction should succeed");
3317
3318 if let Ok(decoded_error) = decoder.decode(&syndrome) {
3320 assert!(decoded_error.weight() <= 1);
3322 }
3323 }
3324
3325 #[test]
3326 fn test_concatenated_codes() {
3327 let inner_code = StabilizerCode::repetition_code();
3328 let outer_code = StabilizerCode::repetition_code();
3329 let concat_code = ConcatenatedCode::new(inner_code, outer_code);
3330
3331 assert_eq!(concat_code.total_qubits(), 9); assert_eq!(concat_code.logical_qubits(), 1);
3333 assert_eq!(concat_code.distance(), 1); let logical_state = vec![Complex64::new(1.0, 0.0), Complex64::new(0.0, 0.0)];
3337 let encoded = concat_code
3338 .encode(&logical_state)
3339 .expect("Encoding should succeed");
3340 assert_eq!(encoded.len(), 512); let error = PauliString::new(vec![
3344 Pauli::X,
3345 Pauli::I,
3346 Pauli::I,
3347 Pauli::I,
3348 Pauli::I,
3349 Pauli::I,
3350 Pauli::I,
3351 Pauli::I,
3352 Pauli::I,
3353 ]);
3354 let corrected = concat_code
3355 .correct_error(&encoded, &error)
3356 .expect("Error correction should succeed");
3357
3358 assert_eq!(corrected.len(), 512);
3360 }
3361
3362 #[test]
3363 fn test_hypergraph_product_codes() {
3364 let h1 = Array2::from_shape_vec((2, 3), vec![1, 1, 0, 0, 1, 1])
3366 .expect("Array creation for h1 should succeed");
3367 let h2 = Array2::from_shape_vec((2, 3), vec![1, 0, 1, 1, 1, 0])
3368 .expect("Array creation for h2 should succeed");
3369
3370 let hpc = HypergraphProductCode::new(h1, h2);
3371
3372 assert_eq!(hpc.n, 12); assert_eq!(hpc.k, 1); let stab_code = hpc
3377 .to_stabilizer_code()
3378 .expect("Hypergraph product code conversion should succeed");
3379 assert!(!stab_code.stabilizers.is_empty());
3380 }
3381
3382 #[test]
3383 fn test_quantum_ldpc_codes() {
3384 let qldpc = QuantumLDPCCode::bicycle_code(3, 4);
3385 assert_eq!(qldpc.n, 24); assert_eq!(qldpc.k, 2);
3387
3388 let stab_code = qldpc
3389 .to_stabilizer_code()
3390 .expect("Quantum LDPC code conversion should succeed");
3391 assert!(!stab_code.stabilizers.is_empty());
3392
3393 for stabilizer in &stab_code.stabilizers {
3395 assert!(stabilizer.weight() <= qldpc.max_weight);
3396 }
3397 }
3398
3399 #[test]
3400 fn test_topological_codes() {
3401 let toric = ToricCode::new(2, 2);
3402 assert_eq!(toric.logical_qubits(), 2);
3403 assert_eq!(toric.distance(), 2);
3404
3405 let stab_code = toric
3406 .to_stabilizer_code()
3407 .expect("Toric code conversion should succeed");
3408 assert_eq!(stab_code.n, 8); assert_eq!(stab_code.k, 2);
3410
3411 for i in 0..stab_code.stabilizers.len() {
3413 for j in i + 1..stab_code.stabilizers.len() {
3414 assert!(stab_code.stabilizers[i]
3415 .commutes_with(&stab_code.stabilizers[j])
3416 .expect("Stabilizer commutation check should succeed"));
3417 }
3418 }
3419 }
3420
3421 #[test]
3422 fn test_ml_decoder() {
3423 let surface = SurfaceCode::new(3, 3);
3424 let decoder = MLDecoder::new(
3425 surface
3426 .to_stabilizer_code()
3427 .expect("Surface code conversion should succeed"),
3428 );
3429
3430 let syndrome = vec![true, false, true, false];
3432 let decoded = decoder.decode(&syndrome);
3433
3434 assert!(decoded.is_ok() || syndrome.iter().filter(|&&x| x).count() % 2 == 1);
3436 }
3437
3438 #[test]
3439 fn test_real_time_mock_hardware() {
3440 use crate::error_correction::real_time::*;
3441 use std::time::Duration;
3442
3443 let hardware = MockQuantumHardware::new(0.01, Duration::from_micros(10), 4);
3444
3445 let syndrome = hardware
3447 .measure_syndromes()
3448 .expect("Syndrome measurement should succeed");
3449 assert_eq!(syndrome.len(), 4);
3450
3451 let characteristics = hardware
3453 .get_error_characteristics()
3454 .expect("Getting error characteristics should succeed");
3455 assert_eq!(characteristics.single_qubit_error_rates.len(), 4);
3456
3457 let stats = hardware
3459 .get_latency_stats()
3460 .expect("Getting latency stats should succeed");
3461 assert!(stats.throughput_hz > 0.0);
3462
3463 assert!(hardware.is_ready());
3464 }
3465
3466 #[test]
3467 fn test_real_time_performance_monitor() {
3468 use crate::error_correction::real_time::*;
3469 use std::time::Duration;
3470
3471 let mut monitor = PerformanceMonitor::new();
3472
3473 monitor.record_cycle(Duration::from_micros(10), true);
3475 monitor.record_cycle(Duration::from_micros(20), false);
3476 monitor.record_cycle(Duration::from_micros(15), true);
3477
3478 assert_eq!(monitor.cycles_processed, 3);
3479 assert_eq!(monitor.errors_corrected, 2);
3480 assert_eq!(monitor.error_correction_rate(), 2.0 / 3.0);
3481 assert!(monitor.average_latency().as_micros() > 10);
3482 assert!(monitor.current_throughput() > 0.0);
3483 }
3484
3485 #[test]
3486 fn test_real_time_adaptive_decoder() {
3487 use crate::error_correction::real_time::*;
3488 use std::sync::Arc;
3489
3490 let code = StabilizerCode::repetition_code();
3491 let base_decoder =
3492 Arc::new(LookupDecoder::new(&code).expect("Lookup decoder creation should succeed"));
3493 let characteristics = HardwareErrorCharacteristics {
3494 single_qubit_error_rates: vec![0.01; 3],
3495 two_qubit_error_rates: vec![0.1; 1],
3496 measurement_error_rates: vec![0.001; 3],
3497 correlated_errors: Vec::new(),
3498 temporal_variation: 0.01,
3499 };
3500
3501 let mut adaptive_decoder = AdaptiveThresholdDecoder::new(base_decoder, characteristics);
3502
3503 let initial_threshold = adaptive_decoder.current_threshold();
3505 assert_eq!(initial_threshold, 1.0); adaptive_decoder.adapt_thresholds(&[false, false], true); let new_threshold = adaptive_decoder.current_threshold();
3511 assert!(new_threshold != initial_threshold); let syndrome = vec![false, false]; let result = adaptive_decoder.decode(&syndrome);
3516 assert!(result.is_ok(), "Decoding failed: {:?}", result.err());
3517 }
3518
3519 #[test]
3520 fn test_real_time_parallel_decoder() {
3521 use crate::error_correction::real_time::*;
3522 use std::sync::Arc;
3523
3524 let code = StabilizerCode::repetition_code();
3525 let base_decoder =
3526 Arc::new(LookupDecoder::new(&code).expect("Lookup decoder creation should succeed"));
3527 let parallel_decoder = ParallelSyndromeDecoder::new(base_decoder, 2);
3528
3529 let syndrome = vec![false, false]; let result = parallel_decoder.decode(&syndrome);
3532 assert!(result.is_ok(), "Decoding failed: {:?}", result.err());
3533
3534 let syndromes = vec![
3536 vec![false, false], vec![false, false],
3538 vec![false, false],
3539 vec![false, false],
3540 ];
3541
3542 let results = parallel_decoder.decode_batch(&syndromes);
3543 assert!(results.is_ok());
3544 let corrections = results.expect("Batch decoding should succeed");
3545 assert_eq!(corrections.len(), 4);
3546 }
3547
3548 #[test]
3549 fn test_real_time_syndrome_stream_processor() {
3550 use crate::error_correction::real_time::*;
3551 use std::sync::Arc;
3552 use std::time::Duration;
3553
3554 let code = StabilizerCode::repetition_code();
3555 let decoder =
3556 Arc::new(LookupDecoder::new(&code).expect("Lookup decoder creation should succeed"));
3557 let hardware = Arc::new(MockQuantumHardware::new(0.01, Duration::from_micros(1), 3));
3558 let config = RealTimeConfig {
3559 max_latency: Duration::from_millis(1),
3560 buffer_size: 10,
3561 parallel_workers: 1,
3562 adaptive_threshold: false,
3563 hardware_feedback: false,
3564 performance_logging: true,
3565 };
3566
3567 let processor = SyndromeStreamProcessor::new(decoder, hardware, config);
3568
3569 let (current, max) = processor.get_buffer_status();
3571 assert_eq!(current, 0);
3572 assert_eq!(max, 10);
3573
3574 let stats = processor.get_performance_stats();
3576 assert_eq!(stats.cycles_processed, 0);
3577 assert_eq!(stats.errors_corrected, 0);
3578 }
3579
3580 #[test]
3581 fn test_logical_gate_synthesizer() {
3582 use crate::error_correction::logical_gates::*;
3583
3584 let code = StabilizerCode::repetition_code();
3585 let synthesizer = LogicalGateSynthesizer::new(0.01);
3586
3587 let logical_x = synthesizer.synthesize_logical_x(&code, 0);
3589 assert!(logical_x.is_ok());
3590
3591 let x_gate = logical_x.expect("Logical X synthesis should succeed");
3592 assert_eq!(x_gate.logical_qubits, vec![0]);
3593 assert_eq!(x_gate.physical_operations.len(), 1);
3594 assert!(!x_gate.error_propagation.single_qubit_propagation.is_empty());
3595
3596 let logical_z = synthesizer.synthesize_logical_z(&code, 0);
3598 assert!(logical_z.is_ok());
3599
3600 let z_gate = logical_z.expect("Logical Z synthesis should succeed");
3601 assert_eq!(z_gate.logical_qubits, vec![0]);
3602 assert_eq!(z_gate.physical_operations.len(), 1);
3603
3604 let logical_h = synthesizer.synthesize_logical_h(&code, 0);
3606 assert!(logical_h.is_ok());
3607
3608 let h_gate = logical_h.expect("Logical H synthesis should succeed");
3609 assert_eq!(h_gate.logical_qubits, vec![0]);
3610 assert_eq!(h_gate.physical_operations.len(), 1);
3611 assert_eq!(h_gate.physical_operations[0].error_correction_rounds, 2);
3612
3613 let invalid_gate = synthesizer.synthesize_logical_x(&code, 5);
3615 assert!(invalid_gate.is_err());
3616 }
3617
3618 #[test]
3619 fn test_logical_circuit_synthesizer() {
3620 use crate::error_correction::logical_gates::*;
3621
3622 let code = StabilizerCode::repetition_code();
3623 let synthesizer = LogicalCircuitSynthesizer::new(0.01);
3624
3625 let gate_sequence = vec![("x", vec![0]), ("h", vec![0]), ("z", vec![0])];
3627
3628 let circuit = synthesizer.synthesize_circuit(&code, &gate_sequence);
3629 assert!(circuit.is_ok());
3630
3631 let logical_circuit = circuit.expect("Circuit synthesis should succeed");
3632 assert_eq!(logical_circuit.len(), 3);
3633
3634 let resources = synthesizer.estimate_resources(&logical_circuit);
3636 assert!(resources.total_physical_operations > 0);
3637 assert!(resources.total_error_correction_rounds > 0);
3638 assert_eq!(resources.estimated_depth, 3);
3639
3640 let invalid_sequence = vec![("invalid_gate", vec![0])];
3642 let invalid_circuit = synthesizer.synthesize_circuit(&code, &invalid_sequence);
3643 assert!(invalid_circuit.is_err());
3644
3645 let wrong_cnot = vec![("cnot", vec![0])]; let wrong_circuit = synthesizer.synthesize_circuit(&code, &wrong_cnot);
3648 assert!(wrong_circuit.is_err());
3649 }
3650
3651 #[test]
3652 fn test_logical_t_gate_synthesis() {
3653 use crate::error_correction::logical_gates::*;
3654
3655 let code = StabilizerCode::repetition_code();
3656 let synthesizer = LogicalGateSynthesizer::new(0.01);
3657
3658 let logical_t = synthesizer.synthesize_logical_t(&code, 0);
3660 assert!(logical_t.is_ok());
3661
3662 let t_gate = logical_t.expect("Logical T synthesis should succeed");
3663 assert_eq!(t_gate.logical_qubits, vec![0]);
3664 assert_eq!(t_gate.physical_operations.len(), 2); assert!(t_gate.physical_operations[0].error_correction_rounds >= 5);
3668 }
3669
3670 #[test]
3671 fn test_error_propagation_analysis() {
3672 use crate::error_correction::logical_gates::*;
3673
3674 let code = StabilizerCode::repetition_code();
3675 let synthesizer = LogicalGateSynthesizer::new(0.01);
3676
3677 let logical_x = synthesizer
3678 .synthesize_logical_x(&code, 0)
3679 .expect("Logical X synthesis should succeed");
3680
3681 let analysis = &logical_x.error_propagation;
3683 assert!(!analysis.single_qubit_propagation.is_empty());
3684 assert_eq!(analysis.fault_tolerance_threshold, 0.01);
3686
3687 let correctable_count = analysis
3689 .single_qubit_propagation
3690 .iter()
3691 .filter(|path| path.correctable)
3692 .count();
3693 assert!(correctable_count > 0);
3694 }
3695
3696 #[test]
3697 fn test_pauli_string_weight() {
3698 let identity_string = PauliString::new(vec![Pauli::I, Pauli::I, Pauli::I]);
3699 assert_eq!(identity_string.weight(), 0);
3700
3701 let single_error = PauliString::new(vec![Pauli::X, Pauli::I, Pauli::I]);
3702 assert_eq!(single_error.weight(), 1);
3703
3704 let multi_error = PauliString::new(vec![Pauli::X, Pauli::Y, Pauli::Z]);
3705 assert_eq!(multi_error.weight(), 3);
3706 }
3707
3708 #[test]
3709 fn test_logical_circuit_with_multiple_gates() {
3710 use crate::error_correction::logical_gates::*;
3711
3712 let code = StabilizerCode::repetition_code();
3713 let synthesizer = LogicalCircuitSynthesizer::new(0.01);
3714
3715 let gate_sequence = vec![
3717 ("h", vec![0]), ("x", vec![0]), ("z", vec![0]), ("h", vec![0]), ];
3722
3723 let circuit = synthesizer.synthesize_circuit(&code, &gate_sequence);
3724 assert!(circuit.is_ok());
3725
3726 let logical_circuit = circuit.expect("Circuit synthesis should succeed");
3727 assert_eq!(logical_circuit.len(), 4);
3728
3729 for gate in &logical_circuit {
3731 assert_eq!(gate.logical_qubits, vec![0]);
3732 }
3733
3734 let resources = synthesizer.estimate_resources(&logical_circuit);
3736 assert_eq!(resources.estimated_depth, 4);
3737 assert!(resources.total_error_correction_rounds >= 4); }
3739
3740 #[test]
3741 fn test_adaptive_threshold_estimator() {
3742 use crate::error_correction::adaptive_threshold::*;
3743
3744 let noise_model = NoiseModel::default();
3745 let algorithm = ThresholdEstimationAlgorithm::Bayesian {
3746 prior_strength: 1.0,
3747 update_rate: 0.1,
3748 };
3749 let config = AdaptiveConfig::default();
3750
3751 let mut estimator = AdaptiveThresholdEstimator::new(noise_model, algorithm, config);
3752
3753 let syndrome = vec![true, false];
3755 let env = EnvironmentalConditions::default();
3756 let threshold = estimator.estimate_threshold(&syndrome, &env);
3757 assert!(threshold > 0.0);
3758 assert!(threshold < 1.0);
3759
3760 let observation = ErrorObservation {
3762 syndrome: syndrome.clone(),
3763 correction: PauliString::new(vec![Pauli::X, Pauli::I]),
3764 success: true,
3765 observed_error_rate: 0.01,
3766 timestamp: std::time::Instant::now(),
3767 environment: env.clone(),
3768 };
3769
3770 estimator.add_observation(observation);
3771
3772 let recommendation = estimator.get_threshold_recommendation(&syndrome);
3774 assert!(recommendation.threshold > 0.0);
3775 assert!(recommendation.confidence >= 0.0 && recommendation.confidence <= 1.0);
3776 assert!(recommendation.predicted_error_rate >= 0.0);
3777 }
3778
3779 #[test]
3780 fn test_performance_tracker() {
3781 use crate::error_correction::adaptive_threshold::*;
3782
3783 let mut tracker = PerformanceTracker::new();
3784
3785 assert_eq!(tracker.successful_corrections, 0);
3787 assert_eq!(tracker.failed_corrections, 0);
3788 assert_eq!(tracker.precision(), 1.0); assert_eq!(tracker.recall(), 1.0);
3790 assert_eq!(tracker.f1_score(), 1.0); tracker.successful_corrections = 8;
3794 tracker.failed_corrections = 2;
3795 tracker.false_positives = 1;
3796 tracker.false_negatives = 1;
3797
3798 assert_eq!(tracker.precision(), 8.0 / 9.0); assert_eq!(tracker.recall(), 8.0 / 9.0); assert!(tracker.f1_score() > 0.0);
3802 }
3803
3804 #[test]
3805 fn test_environmental_conditions() {
3806 use crate::error_correction::adaptive_threshold::*;
3807
3808 let mut env = EnvironmentalConditions::default();
3809 assert_eq!(env.temperature, 300.0); assert_eq!(env.magnetic_field, 0.0);
3811
3812 env.temperature = 310.0; env.vibration_level = 0.1;
3815
3816 let noise_model = NoiseModel::default();
3817 let algorithm = ThresholdEstimationAlgorithm::ExponentialAverage { alpha: 0.5 };
3818 let config = AdaptiveConfig::default();
3819
3820 let estimator = AdaptiveThresholdEstimator::new(noise_model, algorithm, config);
3821
3822 let syndrome = vec![false, false];
3824 let threshold_normal =
3825 estimator.estimate_threshold(&syndrome, &EnvironmentalConditions::default());
3826 let threshold_hot = estimator.estimate_threshold(&syndrome, &env);
3827
3828 assert!(threshold_normal >= 0.0);
3830 assert!(threshold_hot >= 0.0);
3831 }
3832
3833 #[test]
3834 fn test_different_threshold_algorithms() {
3835 use crate::error_correction::adaptive_threshold::*;
3836
3837 let noise_model = NoiseModel::default();
3838 let config = AdaptiveConfig::default();
3839
3840 let bayesian_alg = ThresholdEstimationAlgorithm::Bayesian {
3842 prior_strength: 1.0,
3843 update_rate: 0.1,
3844 };
3845 let bayesian_estimator =
3846 AdaptiveThresholdEstimator::new(noise_model.clone(), bayesian_alg, config.clone());
3847
3848 let kalman_alg = ThresholdEstimationAlgorithm::KalmanFilter {
3850 process_noise: 0.01,
3851 measurement_noise: 0.1,
3852 };
3853 let kalman_estimator =
3854 AdaptiveThresholdEstimator::new(noise_model.clone(), kalman_alg, config.clone());
3855
3856 let exp_alg = ThresholdEstimationAlgorithm::ExponentialAverage { alpha: 0.3 };
3858 let exp_estimator =
3859 AdaptiveThresholdEstimator::new(noise_model.clone(), exp_alg, config.clone());
3860
3861 let ml_alg = ThresholdEstimationAlgorithm::MachineLearning {
3863 model_type: MLModelType::LinearRegression,
3864 training_window: 50,
3865 };
3866 let ml_estimator = AdaptiveThresholdEstimator::new(noise_model, ml_alg, config);
3867
3868 let syndrome = vec![true, false];
3869 let env = EnvironmentalConditions::default();
3870
3871 let bayesian_threshold = bayesian_estimator.estimate_threshold(&syndrome, &env);
3873 let kalman_threshold = kalman_estimator.estimate_threshold(&syndrome, &env);
3874 let exp_threshold = exp_estimator.estimate_threshold(&syndrome, &env);
3875 let ml_threshold = ml_estimator.estimate_threshold(&syndrome, &env);
3876
3877 assert!(bayesian_threshold > 0.0);
3878 assert!(kalman_threshold > 0.0);
3879 assert!(exp_threshold > 0.0);
3880 assert!(ml_threshold > 0.0);
3881 }
3882
3883 #[test]
3884 fn test_noise_model_updates() {
3885 use crate::error_correction::adaptive_threshold::*;
3886
3887 let noise_model = NoiseModel::default();
3888 let algorithm = ThresholdEstimationAlgorithm::Bayesian {
3889 prior_strength: 1.0,
3890 update_rate: 0.1,
3891 };
3892 let config = AdaptiveConfig {
3893 min_observations: 2, real_time_adaptation: true,
3895 ..AdaptiveConfig::default()
3896 };
3897
3898 let mut estimator = AdaptiveThresholdEstimator::new(noise_model, algorithm, config);
3899
3900 for i in 0..5 {
3902 let observation = ErrorObservation {
3903 syndrome: vec![i % 2 == 0, i % 3 == 0],
3904 correction: PauliString::new(vec![Pauli::X, Pauli::I]),
3905 success: i % 4 != 0, observed_error_rate: 0.01,
3907 timestamp: std::time::Instant::now(),
3908 environment: EnvironmentalConditions::default(),
3909 };
3910 estimator.add_observation(observation);
3911 }
3912
3913 let recommendation = estimator.get_threshold_recommendation(&[true, false]);
3915 assert!(recommendation.confidence > 0.0);
3916 assert!(recommendation.recommendation_quality > 0.0);
3917 }
3918}