quantrs2_core/error_correction/
stabilizer.rs

1//! Stabilizer code implementation
2
3use super::pauli::{Pauli, PauliString};
4use crate::error::{QuantRS2Error, QuantRS2Result};
5
6/// Stabilizer code definition
7#[derive(Debug, Clone)]
8pub struct StabilizerCode {
9    /// Number of physical qubits
10    pub n: usize,
11    /// Number of logical qubits
12    pub k: usize,
13    /// Minimum distance
14    pub d: usize,
15    /// Stabilizer generators
16    pub stabilizers: Vec<PauliString>,
17    /// Logical X operators
18    pub logical_x: Vec<PauliString>,
19    /// Logical Z operators
20    pub logical_z: Vec<PauliString>,
21}
22
23impl StabilizerCode {
24    /// Create a new stabilizer code
25    pub fn new(
26        n: usize,
27        k: usize,
28        d: usize,
29        stabilizers: Vec<PauliString>,
30        logical_x: Vec<PauliString>,
31        logical_z: Vec<PauliString>,
32    ) -> QuantRS2Result<Self> {
33        // Validate code parameters
34        // Note: For surface codes and other topological codes,
35        // some stabilizers may be linearly dependent, so we allow more flexibility
36        if stabilizers.len() > 2 * (n - k) {
37            return Err(QuantRS2Error::InvalidInput(format!(
38                "Too many stabilizers: got {}, maximum is {}",
39                stabilizers.len(),
40                2 * (n - k)
41            )));
42        }
43
44        if logical_x.len() != k || logical_z.len() != k {
45            return Err(QuantRS2Error::InvalidInput(
46                "Number of logical operators must equal k".to_string(),
47            ));
48        }
49
50        // Check that stabilizers commute
51        for i in 0..stabilizers.len() {
52            for j in i + 1..stabilizers.len() {
53                if !stabilizers[i].commutes_with(&stabilizers[j])? {
54                    return Err(QuantRS2Error::InvalidInput(
55                        "Stabilizers must commute".to_string(),
56                    ));
57                }
58            }
59        }
60
61        Ok(Self {
62            n,
63            k,
64            d,
65            stabilizers,
66            logical_x,
67            logical_z,
68        })
69    }
70
71    /// Create the 3-qubit repetition code
72    pub fn repetition_code() -> Self {
73        let stabilizers = vec![
74            PauliString::new(vec![Pauli::Z, Pauli::Z, Pauli::I]),
75            PauliString::new(vec![Pauli::I, Pauli::Z, Pauli::Z]),
76        ];
77
78        let logical_x = vec![PauliString::new(vec![Pauli::X, Pauli::X, Pauli::X])];
79        let logical_z = vec![PauliString::new(vec![Pauli::Z, Pauli::I, Pauli::I])];
80
81        Self::new(3, 1, 1, stabilizers, logical_x, logical_z)
82            .expect("3-qubit repetition code: verified standard code parameters are always valid")
83    }
84
85    /// Create the 5-qubit perfect code
86    pub fn five_qubit_code() -> Self {
87        let stabilizers = vec![
88            PauliString::new(vec![Pauli::X, Pauli::Z, Pauli::Z, Pauli::X, Pauli::I]),
89            PauliString::new(vec![Pauli::I, Pauli::X, Pauli::Z, Pauli::Z, Pauli::X]),
90            PauliString::new(vec![Pauli::X, Pauli::I, Pauli::X, Pauli::Z, Pauli::Z]),
91            PauliString::new(vec![Pauli::Z, Pauli::X, Pauli::I, Pauli::X, Pauli::Z]),
92        ];
93
94        let logical_x = vec![PauliString::new(vec![
95            Pauli::X,
96            Pauli::X,
97            Pauli::X,
98            Pauli::X,
99            Pauli::X,
100        ])];
101        let logical_z = vec![PauliString::new(vec![
102            Pauli::Z,
103            Pauli::Z,
104            Pauli::Z,
105            Pauli::Z,
106            Pauli::Z,
107        ])];
108
109        Self::new(5, 1, 3, stabilizers, logical_x, logical_z)
110            .expect("5-qubit perfect code: verified standard code parameters are always valid")
111    }
112
113    /// Create the 7-qubit Steane code
114    pub fn steane_code() -> Self {
115        let stabilizers = vec![
116            PauliString::new(vec![
117                Pauli::I,
118                Pauli::I,
119                Pauli::I,
120                Pauli::X,
121                Pauli::X,
122                Pauli::X,
123                Pauli::X,
124            ]),
125            PauliString::new(vec![
126                Pauli::I,
127                Pauli::X,
128                Pauli::X,
129                Pauli::I,
130                Pauli::I,
131                Pauli::X,
132                Pauli::X,
133            ]),
134            PauliString::new(vec![
135                Pauli::X,
136                Pauli::I,
137                Pauli::X,
138                Pauli::I,
139                Pauli::X,
140                Pauli::I,
141                Pauli::X,
142            ]),
143            PauliString::new(vec![
144                Pauli::I,
145                Pauli::I,
146                Pauli::I,
147                Pauli::Z,
148                Pauli::Z,
149                Pauli::Z,
150                Pauli::Z,
151            ]),
152            PauliString::new(vec![
153                Pauli::I,
154                Pauli::Z,
155                Pauli::Z,
156                Pauli::I,
157                Pauli::I,
158                Pauli::Z,
159                Pauli::Z,
160            ]),
161            PauliString::new(vec![
162                Pauli::Z,
163                Pauli::I,
164                Pauli::Z,
165                Pauli::I,
166                Pauli::Z,
167                Pauli::I,
168                Pauli::Z,
169            ]),
170        ];
171
172        let logical_x = vec![PauliString::new(vec![
173            Pauli::X,
174            Pauli::X,
175            Pauli::X,
176            Pauli::X,
177            Pauli::X,
178            Pauli::X,
179            Pauli::X,
180        ])];
181        let logical_z = vec![PauliString::new(vec![
182            Pauli::Z,
183            Pauli::Z,
184            Pauli::Z,
185            Pauli::Z,
186            Pauli::Z,
187            Pauli::Z,
188            Pauli::Z,
189        ])];
190
191        Self::new(7, 1, 3, stabilizers, logical_x, logical_z)
192            .expect("7-qubit Steane code: verified standard code parameters are always valid")
193    }
194
195    /// Get syndrome for a given error
196    pub fn syndrome(&self, error: &PauliString) -> QuantRS2Result<Vec<bool>> {
197        if error.paulis.len() != self.n {
198            return Err(QuantRS2Error::InvalidInput(
199                "Error must act on all physical qubits".to_string(),
200            ));
201        }
202
203        let mut syndrome = Vec::with_capacity(self.stabilizers.len());
204        for stabilizer in &self.stabilizers {
205            syndrome.push(!stabilizer.commutes_with(error)?);
206        }
207
208        Ok(syndrome)
209    }
210}