1use crate::error::{QuantRS2Error, QuantRS2Result};
8use ndarray::Array2;
9use num_complex::Complex64;
10use std::collections::HashMap;
11use std::fmt;
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
15pub enum Pauli {
16 I,
17 X,
18 Y,
19 Z,
20}
21
22impl Pauli {
23 pub fn matrix(&self) -> Array2<Complex64> {
25 match self {
26 Pauli::I => Array2::from_shape_vec(
27 (2, 2),
28 vec![
29 Complex64::new(1.0, 0.0),
30 Complex64::new(0.0, 0.0),
31 Complex64::new(0.0, 0.0),
32 Complex64::new(1.0, 0.0),
33 ],
34 )
35 .unwrap(),
36 Pauli::X => Array2::from_shape_vec(
37 (2, 2),
38 vec![
39 Complex64::new(0.0, 0.0),
40 Complex64::new(1.0, 0.0),
41 Complex64::new(1.0, 0.0),
42 Complex64::new(0.0, 0.0),
43 ],
44 )
45 .unwrap(),
46 Pauli::Y => Array2::from_shape_vec(
47 (2, 2),
48 vec![
49 Complex64::new(0.0, 0.0),
50 Complex64::new(0.0, -1.0),
51 Complex64::new(0.0, 1.0),
52 Complex64::new(0.0, 0.0),
53 ],
54 )
55 .unwrap(),
56 Pauli::Z => Array2::from_shape_vec(
57 (2, 2),
58 vec![
59 Complex64::new(1.0, 0.0),
60 Complex64::new(0.0, 0.0),
61 Complex64::new(0.0, 0.0),
62 Complex64::new(-1.0, 0.0),
63 ],
64 )
65 .unwrap(),
66 }
67 }
68
69 pub fn multiply(&self, other: &Pauli) -> (Complex64, Pauli) {
71 use Pauli::*;
72 match (self, other) {
73 (I, p) | (p, I) => (Complex64::new(1.0, 0.0), *p),
74 (X, X) | (Y, Y) | (Z, Z) => (Complex64::new(1.0, 0.0), I),
75 (X, Y) => (Complex64::new(0.0, 1.0), Z),
76 (Y, X) => (Complex64::new(0.0, -1.0), Z),
77 (Y, Z) => (Complex64::new(0.0, 1.0), X),
78 (Z, Y) => (Complex64::new(0.0, -1.0), X),
79 (Z, X) => (Complex64::new(0.0, 1.0), Y),
80 (X, Z) => (Complex64::new(0.0, -1.0), Y),
81 }
82 }
83}
84
85#[derive(Debug, Clone, PartialEq)]
87pub struct PauliString {
88 pub phase: Complex64,
90 pub paulis: Vec<Pauli>,
92}
93
94impl PauliString {
95 pub fn new(paulis: Vec<Pauli>) -> Self {
97 Self {
98 phase: Complex64::new(1.0, 0.0),
99 paulis,
100 }
101 }
102
103 pub fn identity(n: usize) -> Self {
105 Self::new(vec![Pauli::I; n])
106 }
107
108 pub fn weight(&self) -> usize {
110 self.paulis.iter().filter(|&&p| p != Pauli::I).count()
111 }
112
113 pub fn multiply(&self, other: &PauliString) -> QuantRS2Result<PauliString> {
115 if self.paulis.len() != other.paulis.len() {
116 return Err(QuantRS2Error::InvalidInput(
117 "Pauli strings must have same length".to_string(),
118 ));
119 }
120
121 let mut phase = self.phase * other.phase;
122 let mut paulis = Vec::with_capacity(self.paulis.len());
123
124 for (p1, p2) in self.paulis.iter().zip(&other.paulis) {
125 let (factor, result) = p1.multiply(p2);
126 phase *= factor;
127 paulis.push(result);
128 }
129
130 Ok(PauliString { phase, paulis })
131 }
132
133 pub fn commutes_with(&self, other: &PauliString) -> QuantRS2Result<bool> {
135 if self.paulis.len() != other.paulis.len() {
136 return Err(QuantRS2Error::InvalidInput(
137 "Pauli strings must have same length".to_string(),
138 ));
139 }
140
141 let mut commutation_count = 0;
142 for (p1, p2) in self.paulis.iter().zip(&other.paulis) {
143 if *p1 != Pauli::I && *p2 != Pauli::I && p1 != p2 {
144 commutation_count += 1;
145 }
146 }
147
148 Ok(commutation_count % 2 == 0)
149 }
150}
151
152impl fmt::Display for PauliString {
153 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
154 let phase_str = if self.phase == Complex64::new(1.0, 0.0) {
155 "+".to_string()
156 } else if self.phase == Complex64::new(-1.0, 0.0) {
157 "-".to_string()
158 } else if self.phase == Complex64::new(0.0, 1.0) {
159 "+i".to_string()
160 } else {
161 "-i".to_string()
162 };
163
164 write!(f, "{}", phase_str)?;
165 for p in &self.paulis {
166 write!(f, "{:?}", p)?;
167 }
168 Ok(())
169 }
170}
171
172#[derive(Debug, Clone)]
174pub struct StabilizerCode {
175 pub n: usize,
177 pub k: usize,
179 pub d: usize,
181 pub stabilizers: Vec<PauliString>,
183 pub logical_x: Vec<PauliString>,
185 pub logical_z: Vec<PauliString>,
187}
188
189impl StabilizerCode {
190 pub fn new(
192 n: usize,
193 k: usize,
194 d: usize,
195 stabilizers: Vec<PauliString>,
196 logical_x: Vec<PauliString>,
197 logical_z: Vec<PauliString>,
198 ) -> QuantRS2Result<Self> {
199 if stabilizers.len() > n - k {
203 return Err(QuantRS2Error::InvalidInput(format!(
204 "Too many stabilizers: got {}, maximum is {}",
205 stabilizers.len(),
206 n - k
207 )));
208 }
209
210 if logical_x.len() != k || logical_z.len() != k {
211 return Err(QuantRS2Error::InvalidInput(
212 "Number of logical operators must equal k".to_string(),
213 ));
214 }
215
216 for i in 0..stabilizers.len() {
218 for j in i + 1..stabilizers.len() {
219 if !stabilizers[i].commutes_with(&stabilizers[j])? {
220 return Err(QuantRS2Error::InvalidInput(
221 "Stabilizers must commute".to_string(),
222 ));
223 }
224 }
225 }
226
227 Ok(Self {
228 n,
229 k,
230 d,
231 stabilizers,
232 logical_x,
233 logical_z,
234 })
235 }
236
237 pub fn repetition_code() -> Self {
239 let stabilizers = vec![
240 PauliString::new(vec![Pauli::Z, Pauli::Z, Pauli::I]),
241 PauliString::new(vec![Pauli::I, Pauli::Z, Pauli::Z]),
242 ];
243
244 let logical_x = vec![PauliString::new(vec![Pauli::X, Pauli::X, Pauli::X])];
245 let logical_z = vec![PauliString::new(vec![Pauli::Z, Pauli::I, Pauli::I])];
246
247 Self::new(3, 1, 1, stabilizers, logical_x, logical_z).unwrap()
248 }
249
250 pub fn five_qubit_code() -> Self {
252 let stabilizers = vec![
253 PauliString::new(vec![Pauli::X, Pauli::Z, Pauli::Z, Pauli::X, Pauli::I]),
254 PauliString::new(vec![Pauli::I, Pauli::X, Pauli::Z, Pauli::Z, Pauli::X]),
255 PauliString::new(vec![Pauli::X, Pauli::I, Pauli::X, Pauli::Z, Pauli::Z]),
256 PauliString::new(vec![Pauli::Z, Pauli::X, Pauli::I, Pauli::X, Pauli::Z]),
257 ];
258
259 let logical_x = vec![PauliString::new(vec![
260 Pauli::X,
261 Pauli::X,
262 Pauli::X,
263 Pauli::X,
264 Pauli::X,
265 ])];
266 let logical_z = vec![PauliString::new(vec![
267 Pauli::Z,
268 Pauli::Z,
269 Pauli::Z,
270 Pauli::Z,
271 Pauli::Z,
272 ])];
273
274 Self::new(5, 1, 3, stabilizers, logical_x, logical_z).unwrap()
275 }
276
277 pub fn steane_code() -> Self {
279 let stabilizers = vec![
280 PauliString::new(vec![
281 Pauli::I,
282 Pauli::I,
283 Pauli::I,
284 Pauli::X,
285 Pauli::X,
286 Pauli::X,
287 Pauli::X,
288 ]),
289 PauliString::new(vec![
290 Pauli::I,
291 Pauli::X,
292 Pauli::X,
293 Pauli::I,
294 Pauli::I,
295 Pauli::X,
296 Pauli::X,
297 ]),
298 PauliString::new(vec![
299 Pauli::X,
300 Pauli::I,
301 Pauli::X,
302 Pauli::I,
303 Pauli::X,
304 Pauli::I,
305 Pauli::X,
306 ]),
307 PauliString::new(vec![
308 Pauli::I,
309 Pauli::I,
310 Pauli::I,
311 Pauli::Z,
312 Pauli::Z,
313 Pauli::Z,
314 Pauli::Z,
315 ]),
316 PauliString::new(vec![
317 Pauli::I,
318 Pauli::Z,
319 Pauli::Z,
320 Pauli::I,
321 Pauli::I,
322 Pauli::Z,
323 Pauli::Z,
324 ]),
325 PauliString::new(vec![
326 Pauli::Z,
327 Pauli::I,
328 Pauli::Z,
329 Pauli::I,
330 Pauli::Z,
331 Pauli::I,
332 Pauli::Z,
333 ]),
334 ];
335
336 let logical_x = vec![PauliString::new(vec![
337 Pauli::X,
338 Pauli::X,
339 Pauli::X,
340 Pauli::X,
341 Pauli::X,
342 Pauli::X,
343 Pauli::X,
344 ])];
345 let logical_z = vec![PauliString::new(vec![
346 Pauli::Z,
347 Pauli::Z,
348 Pauli::Z,
349 Pauli::Z,
350 Pauli::Z,
351 Pauli::Z,
352 Pauli::Z,
353 ])];
354
355 Self::new(7, 1, 3, stabilizers, logical_x, logical_z).unwrap()
356 }
357
358 pub fn syndrome(&self, error: &PauliString) -> QuantRS2Result<Vec<bool>> {
360 if error.paulis.len() != self.n {
361 return Err(QuantRS2Error::InvalidInput(
362 "Error must act on all physical qubits".to_string(),
363 ));
364 }
365
366 let mut syndrome = Vec::with_capacity(self.stabilizers.len());
367 for stabilizer in &self.stabilizers {
368 syndrome.push(!stabilizer.commutes_with(error)?);
369 }
370
371 Ok(syndrome)
372 }
373}
374
375#[derive(Debug, Clone)]
377pub struct SurfaceCode {
378 pub rows: usize,
380 pub cols: usize,
382 pub qubit_map: HashMap<(usize, usize), usize>,
384 pub x_stabilizers: Vec<Vec<usize>>,
386 pub z_stabilizers: Vec<Vec<usize>>,
387}
388
389impl SurfaceCode {
390 pub fn new(rows: usize, cols: usize) -> Self {
392 let mut qubit_map = HashMap::new();
393 let mut qubit_index = 0;
394
395 for r in 0..rows {
397 for c in 0..cols {
398 qubit_map.insert((r, c), qubit_index);
399 qubit_index += 1;
400 }
401 }
402
403 let mut x_stabilizers = Vec::new();
404 let mut z_stabilizers = Vec::new();
405
406 for r in 0..rows - 1 {
408 for c in 0..cols - 1 {
409 if (r + c) % 2 == 0 {
410 let stabilizer = vec![
411 qubit_map[&(r, c)],
412 qubit_map[&(r, c + 1)],
413 qubit_map[&(r + 1, c)],
414 qubit_map[&(r + 1, c + 1)],
415 ];
416 x_stabilizers.push(stabilizer);
417 }
418 }
419 }
420
421 for r in 0..rows - 1 {
423 for c in 0..cols - 1 {
424 if (r + c) % 2 == 1 {
425 let stabilizer = vec![
426 qubit_map[&(r, c)],
427 qubit_map[&(r, c + 1)],
428 qubit_map[&(r + 1, c)],
429 qubit_map[&(r + 1, c + 1)],
430 ];
431 z_stabilizers.push(stabilizer);
432 }
433 }
434 }
435
436 Self {
437 rows,
438 cols,
439 qubit_map,
440 x_stabilizers,
441 z_stabilizers,
442 }
443 }
444
445 pub fn distance(&self) -> usize {
447 self.rows.min(self.cols)
448 }
449
450 pub fn to_stabilizer_code(&self) -> StabilizerCode {
452 let n = self.qubit_map.len();
453 let mut stabilizers = Vec::new();
454
455 for x_stab in &self.x_stabilizers {
457 let mut paulis = vec![Pauli::I; n];
458 for &qubit in x_stab {
459 paulis[qubit] = Pauli::X;
460 }
461 stabilizers.push(PauliString::new(paulis));
462 }
463
464 for z_stab in &self.z_stabilizers {
466 let mut paulis = vec![Pauli::I; n];
467 for &qubit in z_stab {
468 paulis[qubit] = Pauli::Z;
469 }
470 stabilizers.push(PauliString::new(paulis));
471 }
472
473 let mut logical_x_paulis = vec![Pauli::I; n];
475 let mut logical_z_paulis = vec![Pauli::I; n];
476
477 for c in 0..self.cols {
479 if let Some(&qubit) = self.qubit_map.get(&(0, c)) {
480 logical_x_paulis[qubit] = Pauli::X;
481 }
482 }
483
484 for r in 0..self.rows {
486 if let Some(&qubit) = self.qubit_map.get(&(r, 0)) {
487 logical_z_paulis[qubit] = Pauli::Z;
488 }
489 }
490
491 let logical_x = vec![PauliString::new(logical_x_paulis)];
492 let logical_z = vec![PauliString::new(logical_z_paulis)];
493
494 StabilizerCode::new(n, 1, self.distance(), stabilizers, logical_x, logical_z).unwrap()
495 }
496}
497
498pub trait SyndromeDecoder {
500 fn decode(&self, syndrome: &[bool]) -> QuantRS2Result<PauliString>;
502}
503
504pub struct LookupDecoder {
506 syndrome_table: HashMap<Vec<bool>, PauliString>,
508}
509
510impl LookupDecoder {
511 pub fn new(code: &StabilizerCode) -> QuantRS2Result<Self> {
513 let mut syndrome_table = HashMap::new();
514
515 let max_weight = (code.d - 1) / 2;
517 let all_errors = Self::generate_pauli_errors(code.n, max_weight);
518
519 for error in all_errors {
520 let syndrome = code.syndrome(&error)?;
521
522 syndrome_table
524 .entry(syndrome)
525 .and_modify(|e: &mut PauliString| {
526 if error.weight() < e.weight() {
527 *e = error.clone();
528 }
529 })
530 .or_insert(error);
531 }
532
533 Ok(Self { syndrome_table })
534 }
535
536 fn generate_pauli_errors(n: usize, max_weight: usize) -> Vec<PauliString> {
538 let mut errors = vec![PauliString::identity(n)];
539
540 for weight in 1..=max_weight {
541 let weight_errors = Self::generate_weight_k_errors(n, weight);
542 errors.extend(weight_errors);
543 }
544
545 errors
546 }
547
548 fn generate_weight_k_errors(n: usize, k: usize) -> Vec<PauliString> {
550 let mut errors = Vec::new();
551 let paulis = [Pauli::X, Pauli::Y, Pauli::Z];
552
553 let positions = Self::combinations(n, k);
555
556 for pos_set in positions {
557 let pauli_combinations = Self::cartesian_power(&paulis, k);
559
560 for pauli_combo in pauli_combinations {
561 let mut error_paulis = vec![Pauli::I; n];
562 for (i, &pos) in pos_set.iter().enumerate() {
563 error_paulis[pos] = pauli_combo[i];
564 }
565 errors.push(PauliString::new(error_paulis));
566 }
567 }
568
569 errors
570 }
571
572 fn combinations(n: usize, k: usize) -> Vec<Vec<usize>> {
574 let mut result = Vec::new();
575 let mut combo = (0..k).collect::<Vec<_>>();
576
577 loop {
578 result.push(combo.clone());
579
580 let mut i = k;
582 while i > 0 && (i == k || combo[i] == n - k + i) {
583 i -= 1;
584 }
585
586 if i == 0 && combo[0] == n - k {
587 break;
588 }
589
590 combo[i] += 1;
592 for j in i + 1..k {
593 combo[j] = combo[j - 1] + 1;
594 }
595 }
596
597 result
598 }
599
600 fn cartesian_power<T: Clone>(set: &[T], k: usize) -> Vec<Vec<T>> {
602 if k == 0 {
603 return vec![vec![]];
604 }
605
606 let mut result = Vec::new();
607 let smaller = Self::cartesian_power(set, k - 1);
608
609 for item in set {
610 for mut combo in smaller.clone() {
611 combo.push(item.clone());
612 result.push(combo);
613 }
614 }
615
616 result
617 }
618}
619
620impl SyndromeDecoder for LookupDecoder {
621 fn decode(&self, syndrome: &[bool]) -> QuantRS2Result<PauliString> {
622 self.syndrome_table
623 .get(syndrome)
624 .cloned()
625 .ok_or_else(|| QuantRS2Error::InvalidInput("Unknown syndrome".to_string()))
626 }
627}
628
629pub struct MWPMDecoder {
631 surface_code: SurfaceCode,
632}
633
634impl MWPMDecoder {
635 pub fn new(surface_code: SurfaceCode) -> Self {
637 Self { surface_code }
638 }
639
640 pub fn decode_syndrome(
642 &self,
643 x_syndrome: &[bool],
644 z_syndrome: &[bool],
645 ) -> QuantRS2Result<PauliString> {
646 let n = self.surface_code.qubit_map.len();
647 let mut error_paulis = vec![Pauli::I; n];
648
649 let z_defects = self.find_defects(z_syndrome, &self.surface_code.z_stabilizers);
651 let x_corrections = self.minimum_weight_matching(&z_defects, Pauli::X)?;
652
653 for (qubit, pauli) in x_corrections {
654 error_paulis[qubit] = pauli;
655 }
656
657 let x_defects = self.find_defects(x_syndrome, &self.surface_code.x_stabilizers);
659 let z_corrections = self.minimum_weight_matching(&x_defects, Pauli::Z)?;
660
661 for (qubit, pauli) in z_corrections {
662 if error_paulis[qubit] != Pauli::I {
663 error_paulis[qubit] = Pauli::Y;
665 } else {
666 error_paulis[qubit] = pauli;
667 }
668 }
669
670 Ok(PauliString::new(error_paulis))
671 }
672
673 fn find_defects(&self, syndrome: &[bool], stabilizers: &[Vec<usize>]) -> Vec<usize> {
675 syndrome
676 .iter()
677 .enumerate()
678 .filter_map(|(i, &s)| if s { Some(i) } else { None })
679 .collect()
680 }
681
682 fn minimum_weight_matching(
684 &self,
685 defects: &[usize],
686 error_type: Pauli,
687 ) -> QuantRS2Result<Vec<(usize, Pauli)>> {
688 let mut corrections = Vec::new();
690
691 if defects.len() % 2 != 0 {
692 return Err(QuantRS2Error::InvalidInput(
693 "Odd number of defects".to_string(),
694 ));
695 }
696
697 let mut paired = vec![false; defects.len()];
699
700 for i in 0..defects.len() {
701 if paired[i] {
702 continue;
703 }
704
705 let mut min_dist = usize::MAX;
707 let mut min_j = i;
708
709 for j in i + 1..defects.len() {
710 if !paired[j] {
711 let dist = self.defect_distance(defects[i], defects[j]);
712 if dist < min_dist {
713 min_dist = dist;
714 min_j = j;
715 }
716 }
717 }
718
719 if min_j != i {
720 paired[i] = true;
721 paired[min_j] = true;
722
723 let path = self.shortest_path(defects[i], defects[min_j])?;
725 for qubit in path {
726 corrections.push((qubit, error_type));
727 }
728 }
729 }
730
731 Ok(corrections)
732 }
733
734 fn defect_distance(&self, defect1: usize, defect2: usize) -> usize {
736 (defect1 as isize - defect2 as isize).unsigned_abs()
738 }
739
740 fn shortest_path(&self, start: usize, end: usize) -> QuantRS2Result<Vec<usize>> {
742 let path = if start < end {
744 (start..=end).collect()
745 } else {
746 (end..=start).rev().collect()
747 };
748
749 Ok(path)
750 }
751}
752
753#[derive(Debug, Clone)]
755pub struct ColorCode {
756 pub n: usize,
758 pub faces: Vec<(Vec<usize>, Color)>,
760 pub vertex_map: HashMap<(i32, i32), usize>,
762}
763
764#[derive(Debug, Clone, Copy, PartialEq, Eq)]
765enum Color {
766 Red,
767 Green,
768 Blue,
769}
770
771impl ColorCode {
772 pub fn triangular(size: usize) -> Self {
774 let mut vertex_map = HashMap::new();
775 let mut qubit_index = 0;
776
777 for i in 0..size as i32 {
779 for j in 0..size as i32 {
780 vertex_map.insert((i, j), qubit_index);
781 qubit_index += 1;
782 }
783 }
784
785 let mut faces = Vec::new();
786
787 for i in 0..size as i32 - 1 {
789 for j in 0..size as i32 - 1 {
790 if let (Some(&q1), Some(&q2), Some(&q3)) = (
792 vertex_map.get(&(i, j)),
793 vertex_map.get(&(i + 1, j)),
794 vertex_map.get(&(i, j + 1)),
795 ) {
796 faces.push((vec![q1, q2, q3], Color::Red));
797 }
798
799 if let (Some(&q1), Some(&q2), Some(&q3)) = (
801 vertex_map.get(&(i + 1, j)),
802 vertex_map.get(&(i + 1, j + 1)),
803 vertex_map.get(&(i, j + 1)),
804 ) {
805 faces.push((vec![q1, q2, q3], Color::Green));
806 }
807 }
808 }
809
810 Self {
811 n: vertex_map.len(),
812 faces,
813 vertex_map,
814 }
815 }
816
817 pub fn to_stabilizer_code(&self) -> StabilizerCode {
819 let mut x_stabilizers = Vec::new();
820 let mut z_stabilizers = Vec::new();
821
822 for (qubits, color) in &self.faces {
823 let mut x_paulis = vec![Pauli::I; self.n];
825 for &q in qubits {
826 x_paulis[q] = Pauli::X;
827 }
828 x_stabilizers.push(PauliString::new(x_paulis));
829
830 let mut z_paulis = vec![Pauli::I; self.n];
832 for &q in qubits {
833 z_paulis[q] = Pauli::Z;
834 }
835 z_stabilizers.push(PauliString::new(z_paulis));
836 }
837
838 let mut stabilizers = x_stabilizers;
839 stabilizers.extend(z_stabilizers);
840
841 let logical_x = vec![PauliString::new(vec![Pauli::X; self.n])];
843 let logical_z = vec![PauliString::new(vec![Pauli::Z; self.n])];
844
845 StabilizerCode::new(
846 self.n,
847 1,
848 3, stabilizers,
850 logical_x,
851 logical_z,
852 )
853 .unwrap()
854 }
855}
856
857#[cfg(test)]
858mod tests {
859 use super::*;
860
861 #[test]
862 fn test_pauli_multiplication() {
863 let (phase, result) = Pauli::X.multiply(&Pauli::Y);
864 assert_eq!(result, Pauli::Z);
865 assert_eq!(phase, Complex64::new(0.0, 1.0));
866 }
867
868 #[test]
869 fn test_pauli_string_commutation() {
870 let ps1 = PauliString::new(vec![Pauli::X, Pauli::I]);
871 let ps2 = PauliString::new(vec![Pauli::Z, Pauli::I]);
872 assert!(!ps1.commutes_with(&ps2).unwrap());
873
874 let ps3 = PauliString::new(vec![Pauli::X, Pauli::I]);
875 let ps4 = PauliString::new(vec![Pauli::I, Pauli::Z]);
876 assert!(ps3.commutes_with(&ps4).unwrap());
877 }
878
879 #[test]
880 fn test_repetition_code() {
881 let code = StabilizerCode::repetition_code();
882 assert_eq!(code.n, 3);
883 assert_eq!(code.k, 1);
884 assert_eq!(code.d, 1);
885
886 let error = PauliString::new(vec![Pauli::X, Pauli::I, Pauli::I]);
888 let syndrome = code.syndrome(&error).unwrap();
889 assert_eq!(syndrome, vec![true, false]);
891 }
892
893 #[test]
894 fn test_steane_code() {
895 let code = StabilizerCode::steane_code();
896 assert_eq!(code.n, 7);
897 assert_eq!(code.k, 1);
898 assert_eq!(code.d, 3);
899
900 for i in 0..code.stabilizers.len() {
902 for j in i + 1..code.stabilizers.len() {
903 assert!(code.stabilizers[i]
904 .commutes_with(&code.stabilizers[j])
905 .unwrap());
906 }
907 }
908 }
909
910 #[test]
911 fn test_surface_code() {
912 let surface = SurfaceCode::new(3, 3);
913 assert_eq!(surface.distance(), 3);
914
915 let code = surface.to_stabilizer_code();
916 assert_eq!(code.n, 9);
917 assert_eq!(code.stabilizers.len(), 4);
919 }
920
921 #[test]
922 fn test_lookup_decoder() {
923 let code = StabilizerCode::repetition_code();
924 let decoder = LookupDecoder::new(&code).unwrap();
925
926 let trivial_syndrome = vec![false, false];
928 let decoded = decoder.decode(&trivial_syndrome).unwrap();
929 assert_eq!(decoded.weight(), 0); let error = PauliString::new(vec![Pauli::X, Pauli::I, Pauli::I]);
933 let syndrome = code.syndrome(&error).unwrap();
934
935 if let Ok(decoded_error) = decoder.decode(&syndrome) {
937 assert!(decoded_error.weight() <= 1);
939 }
940 }
941}