oxicuda_quantum/algorithm/
error_correction.rs1use crate::error::{QuantumError, QuantumResult};
24use crate::gates::controlled::apply_cnot;
25use crate::gates::hadamard::gate_h;
26use crate::gates::parametric::gate_ry;
27use crate::statevec::apply_1q::{apply_1q_controlled, apply_1q_inplace};
28use crate::statevec::state::StateVector;
29
30pub fn prepare_ghz(n_qubits: usize) -> QuantumResult<StateVector> {
35 if n_qubits == 0 || n_qubits > 30 {
36 return Err(QuantumError::InvalidQubitCount { n: n_qubits });
37 }
38 let mut sv = StateVector::new_zero_state(n_qubits)?;
39 apply_1q_inplace(&mut sv, 0, &gate_h())?;
40 for q in 1..n_qubits {
41 apply_cnot(&mut sv, q - 1, q)?;
42 }
43 Ok(sv)
44}
45
46pub fn prepare_w(n_qubits: usize) -> QuantumResult<StateVector> {
57 if n_qubits == 0 || n_qubits > 30 {
58 return Err(QuantumError::InvalidQubitCount { n: n_qubits });
59 }
60 let mut sv = StateVector::new_zero_state(n_qubits)?;
61 if n_qubits == 1 {
62 apply_1q_inplace(&mut sv, 0, &crate::gates::pauli::gate_x())?;
63 return Ok(sv);
64 }
65 apply_1q_inplace(&mut sv, 0, &crate::gates::pauli::gate_x())?;
68 for k in 0..n_qubits - 1 {
71 let remaining = (n_qubits - k) as f32;
72 let theta = 2.0 * (1.0 / remaining).sqrt().acos();
74 apply_1q_controlled(&mut sv, k, k + 1, &gate_ry(theta))?;
76 apply_cnot(&mut sv, k + 1, k)?;
78 }
79 Ok(sv)
80}
81
82pub fn bit_flip_encode(state: &mut StateVector) -> QuantumResult<()> {
91 if state.n_qubits != 3 {
92 return Err(QuantumError::InvalidQubitCount { n: state.n_qubits });
93 }
94 apply_cnot(state, 0, 1)?;
95 apply_cnot(state, 0, 2)?;
96 Ok(())
97}
98
99fn bit_flip_syndrome(state: &StateVector) -> (bool, bool) {
103 let mut p_s0 = [0.0f32; 2];
105 let mut p_s1 = [0.0f32; 2];
106 for (idx, amp) in state.amps.iter().enumerate() {
107 let pr = amp.norm_sqr();
108 if pr == 0.0 {
109 continue;
110 }
111 let b0 = idx & 1;
112 let b1 = (idx >> 1) & 1;
113 let b2 = (idx >> 2) & 1;
114 p_s0[b0 ^ b1] += pr;
115 p_s1[b1 ^ b2] += pr;
116 }
117 (p_s0[1] > p_s0[0], p_s1[1] > p_s1[0])
118}
119
120pub fn bit_flip_correct(state: &mut StateVector) -> QuantumResult<Option<usize>> {
132 if state.n_qubits != 3 {
133 return Err(QuantumError::InvalidQubitCount { n: state.n_qubits });
134 }
135 let (s0, s1) = bit_flip_syndrome(state);
136 let correct_qubit = match (s0, s1) {
137 (false, false) => None,
138 (true, false) => Some(0),
139 (true, true) => Some(1),
140 (false, true) => Some(2),
141 };
142 if let Some(q) = correct_qubit {
143 apply_1q_inplace(state, q, &crate::gates::pauli::gate_x())?;
144 }
145 Ok(correct_qubit)
146}
147
148pub fn phase_flip_encode(state: &mut StateVector) -> QuantumResult<()> {
157 bit_flip_encode(state)?;
158 for q in 0..3 {
159 apply_1q_inplace(state, q, &gate_h())?;
160 }
161 Ok(())
162}
163
164pub fn phase_flip_correct(state: &mut StateVector) -> QuantumResult<Option<usize>> {
172 if state.n_qubits != 3 {
173 return Err(QuantumError::InvalidQubitCount { n: state.n_qubits });
174 }
175 for q in 0..3 {
177 apply_1q_inplace(state, q, &gate_h())?;
178 }
179 let corrected = bit_flip_correct(state)?;
180 for q in 0..3 {
182 apply_1q_inplace(state, q, &gate_h())?;
183 }
184 Ok(corrected)
185}
186
187#[cfg(test)]
188mod tests {
189 use super::*;
190 use crate::gates::pauli::{gate_x, gate_z};
191
192 const INV_SQRT2: f32 = std::f32::consts::FRAC_1_SQRT_2;
193
194 #[test]
195 fn ghz_two_qubit_is_bell() {
196 let sv = prepare_ghz(2).expect("valid 2-qubit GHZ state");
197 assert!((sv.amps[0].re - INV_SQRT2).abs() < 1e-5);
198 assert!((sv.amps[3].re - INV_SQRT2).abs() < 1e-5);
199 assert!(sv.amps[1].norm() < 1e-5);
200 assert!(sv.amps[2].norm() < 1e-5);
201 }
202
203 #[test]
204 fn ghz_three_qubit_amplitudes() {
205 let sv = prepare_ghz(3).expect("valid 3-qubit GHZ state");
206 assert!((sv.amps[0].re - INV_SQRT2).abs() < 1e-5, "|000>");
207 assert!((sv.amps[7].re - INV_SQRT2).abs() < 1e-5, "|111>");
208 for i in 1..7 {
210 assert!(sv.amps[i].norm() < 1e-5, "amp[{i}]={:?}", sv.amps[i]);
211 }
212 }
213
214 #[test]
215 fn ghz_norm_preserved() {
216 for n in 1..=5 {
217 let sv = prepare_ghz(n).expect("valid n-qubit GHZ state");
218 assert!((sv.norm_sq() - 1.0).abs() < 1e-4, "n={n}");
219 }
220 }
221
222 #[test]
223 fn ghz_invalid_qubit_count() {
224 assert!(prepare_ghz(0).is_err());
225 assert!(prepare_ghz(31).is_err());
226 }
227
228 #[test]
229 fn w_state_single_excitation_amplitudes() {
230 let sv = prepare_w(3).expect("valid 3-qubit W state");
231 let amp = (1.0f32 / 3.0).sqrt();
232 for &i in &[1usize, 2, 4] {
234 assert!(
235 (sv.amps[i].norm() - amp).abs() < 1e-4,
236 "amp[{i}]={:?}",
237 sv.amps[i]
238 );
239 }
240 for &i in &[0usize, 3, 5, 6, 7] {
242 assert!(sv.amps[i].norm() < 1e-4, "amp[{i}]={:?}", sv.amps[i]);
243 }
244 }
245
246 #[test]
247 fn w_state_norm_is_one() {
248 for n in 1..=5 {
249 let sv = prepare_w(n).expect("valid n-qubit W state");
250 assert!((sv.norm_sq() - 1.0).abs() < 1e-4, "n={n}");
251 }
252 }
253
254 #[test]
255 fn w_state_exactly_one_excitation() {
256 let sv = prepare_w(4).expect("valid 4-qubit W state");
258 for (idx, amp) in sv.amps.iter().enumerate() {
259 if amp.norm() > 1e-4 {
260 assert_eq!(idx.count_ones(), 1, "idx={idx:b} has weight ≠ 1");
261 }
262 }
263 }
264
265 #[test]
266 fn w_state_uniform_marginals() {
267 let n = 4;
269 let sv = prepare_w(n).expect("valid 4-qubit W state");
270 for q in 0..n {
271 let p1 = sv
272 .measure_prob(q, true)
273 .expect("valid qubit index for probability measurement");
274 assert!((p1 - 1.0 / n as f32).abs() < 1e-4, "q={q} p1={p1}");
275 }
276 }
277
278 #[test]
279 fn bit_flip_encode_logical_one() {
280 let mut sv = StateVector::new_zero_state(3).expect("valid 3-qubit zero state");
282 apply_1q_inplace(&mut sv, 0, &gate_x()).expect("X gate on qubit 0 succeeds");
283 bit_flip_encode(&mut sv).expect("bit-flip encoding succeeds on 3-qubit state");
284 assert!((sv.amps[7].norm() - 1.0).abs() < 1e-5, "expected |111>");
285 }
286
287 #[test]
288 fn bit_flip_corrects_single_error_on_each_qubit() {
289 for err_q in 0..3 {
290 let mut sv = StateVector::new_zero_state(3).expect("valid 3-qubit zero state");
292 apply_1q_inplace(&mut sv, 0, &gate_x()).expect("X gate on qubit 0 succeeds");
293 bit_flip_encode(&mut sv).expect("bit-flip encoding succeeds on 3-qubit state");
294 apply_1q_inplace(&mut sv, err_q, &gate_x())
296 .expect("X error injection on target qubit succeeds");
297 let corrected = bit_flip_correct(&mut sv).expect("bit-flip correction succeeds");
299 assert_eq!(corrected, Some(err_q), "error on {err_q}");
300 assert!((sv.amps[7].norm() - 1.0).abs() < 1e-5, "err_q={err_q}");
302 }
303 }
304
305 #[test]
306 fn bit_flip_no_error_detected() {
307 let mut sv = StateVector::new_zero_state(3).expect("valid 3-qubit zero state");
308 bit_flip_encode(&mut sv).expect("bit-flip encoding of |000> succeeds"); let corrected =
310 bit_flip_correct(&mut sv).expect("bit-flip correction on clean state succeeds");
311 assert_eq!(corrected, None);
312 assert!((sv.amps[0].norm() - 1.0).abs() < 1e-5);
313 }
314
315 #[test]
316 fn bit_flip_preserves_superposition_after_correction() {
317 let mut sv = StateVector::new_zero_state(3).expect("valid 3-qubit zero state");
319 apply_1q_inplace(&mut sv, 0, &gate_h()).expect("Hadamard gate on qubit 0 succeeds");
320 bit_flip_encode(&mut sv).expect("bit-flip encoding of superposition succeeds");
321 let before0 = sv.amps[0];
322 let before7 = sv.amps[7];
323 apply_1q_inplace(&mut sv, 1, &gate_x()).expect("X error injection on qubit 1 succeeds");
324 let corrected =
325 bit_flip_correct(&mut sv).expect("bit-flip correction restores superposition");
326 assert_eq!(corrected, Some(1));
327 assert!((sv.amps[0] - before0).norm() < 1e-5);
328 assert!((sv.amps[7] - before7).norm() < 1e-5);
329 }
330
331 #[test]
332 fn bit_flip_wrong_qubit_count_errors() {
333 let mut sv = StateVector::new_zero_state(2).expect("valid 2-qubit zero state");
334 assert!(bit_flip_encode(&mut sv).is_err());
335 assert!(bit_flip_correct(&mut sv).is_err());
336 }
337
338 #[test]
339 fn phase_flip_corrects_single_z_error() {
340 for err_q in 0..3 {
341 let mut sv = StateVector::new_zero_state(3).expect("valid 3-qubit zero state");
343 apply_1q_inplace(&mut sv, 0, &gate_x()).expect("X gate on qubit 0 succeeds");
344 phase_flip_encode(&mut sv).expect("phase-flip encoding succeeds on 3-qubit state");
345 let encoded = sv.clone();
346 apply_1q_inplace(&mut sv, err_q, &gate_z())
348 .expect("Z error injection on target qubit succeeds");
349 let corrected = phase_flip_correct(&mut sv).expect("phase-flip correction succeeds");
351 assert_eq!(corrected, Some(err_q), "z-error on {err_q}");
352 for i in 0..8 {
354 assert!(
355 (sv.amps[i] - encoded.amps[i]).norm() < 1e-4,
356 "err_q={err_q} amp[{i}]"
357 );
358 }
359 }
360 }
361
362 #[test]
363 fn phase_flip_no_error_detected() {
364 let mut sv = StateVector::new_zero_state(3).expect("valid 3-qubit zero state");
365 phase_flip_encode(&mut sv).expect("phase-flip encoding succeeds");
366 let corrected =
367 phase_flip_correct(&mut sv).expect("phase-flip correction on clean state succeeds");
368 assert_eq!(corrected, None);
369 }
370}