Skip to main content

quantrs2_sim/stabilizer/
functions.rs

1//! Auto-generated module
2//!
3//! 🤖 Generated with [SplitRS](https://github.com/cool-japan/splitrs)
4
5use quantrs2_circuit::prelude::*;
6use quantrs2_core::gate::GateOp;
7use quantrs2_core::prelude::*;
8use scirs2_core::random::prelude::*;
9use std::sync::Arc;
10
11use super::types::{
12    CliffordCircuitBuilder, StabilizerGate, StabilizerSimulator, StabilizerTableau,
13};
14
15/// Phase encoding for Stim compatibility
16/// 0 = +1, 1 = +i, 2 = -1, 3 = -i
17pub type StabilizerPhase = u8;
18/// Phase constants for clarity
19pub mod phase {
20    /// Phase +1
21    pub const PLUS_ONE: u8 = 0;
22    /// Phase +i
23    pub const PLUS_I: u8 = 1;
24    /// Phase -1
25    pub const MINUS_ONE: u8 = 2;
26    /// Phase -i
27    pub const MINUS_I: u8 = 3;
28}
29/// Check if a circuit can be simulated by the stabilizer simulator
30#[must_use]
31pub fn is_clifford_circuit<const N: usize>(circuit: &Circuit<N>) -> bool {
32    circuit.gates().iter().all(|gate| {
33        matches!(
34            gate.name(),
35            "H" | "S" | "S†" | "CNOT" | "X" | "Y" | "Z" | "CZ" | "Phase" | "PhaseDagger"
36        )
37    })
38}
39/// Convert a gate operation to a stabilizer gate
40pub(super) fn gate_to_stabilizer(gate: &Arc<dyn GateOp + Send + Sync>) -> Option<StabilizerGate> {
41    let gate_name = gate.name();
42    let qubits = gate.qubits();
43    match gate_name {
44        "H" => {
45            if qubits.len() == 1 {
46                Some(StabilizerGate::H(qubits[0].0 as usize))
47            } else {
48                None
49            }
50        }
51        "S" | "Phase" => {
52            if qubits.len() == 1 {
53                Some(StabilizerGate::S(qubits[0].0 as usize))
54            } else {
55                None
56            }
57        }
58        "X" => {
59            if qubits.len() == 1 {
60                Some(StabilizerGate::X(qubits[0].0 as usize))
61            } else {
62                None
63            }
64        }
65        "Y" => {
66            if qubits.len() == 1 {
67                Some(StabilizerGate::Y(qubits[0].0 as usize))
68            } else {
69                None
70            }
71        }
72        "Z" => {
73            if qubits.len() == 1 {
74                Some(StabilizerGate::Z(qubits[0].0 as usize))
75            } else {
76                None
77            }
78        }
79        "CNOT" => {
80            if qubits.len() == 2 {
81                Some(StabilizerGate::CNOT(
82                    qubits[0].0 as usize,
83                    qubits[1].0 as usize,
84                ))
85            } else {
86                None
87            }
88        }
89        "CZ" => {
90            if qubits.len() == 2 {
91                None
92            } else {
93                None
94            }
95        }
96        _ => None,
97    }
98}
99#[cfg(test)]
100mod tests {
101    use super::*;
102    #[test]
103    fn test_stabilizer_init() {
104        let sim = StabilizerSimulator::new(3);
105        let stabs = sim.get_stabilizers();
106        assert_eq!(stabs.len(), 3);
107        assert_eq!(stabs[0], "+ZII");
108        assert_eq!(stabs[1], "+IZI");
109        assert_eq!(stabs[2], "+IIZ");
110    }
111    #[test]
112    fn test_hadamard_gate() {
113        let mut sim = StabilizerSimulator::new(1);
114        sim.apply_gate(StabilizerGate::H(0))
115            .expect("Hadamard gate application should succeed");
116        let stabs = sim.get_stabilizers();
117        assert_eq!(stabs[0], "+X");
118    }
119    #[test]
120    fn test_bell_state() {
121        let mut sim = StabilizerSimulator::new(2);
122        sim.apply_gate(StabilizerGate::H(0))
123            .expect("Hadamard gate application should succeed");
124        sim.apply_gate(StabilizerGate::CNOT(0, 1))
125            .expect("CNOT gate application should succeed");
126        let stabs = sim.get_stabilizers();
127        assert!(stabs.contains(&"+XX".to_string()));
128        assert!(stabs.contains(&"+ZZ".to_string()));
129    }
130    #[test]
131    fn test_ghz_state() {
132        let mut sim = StabilizerSimulator::new(3);
133        sim.apply_gate(StabilizerGate::H(0))
134            .expect("Hadamard gate application should succeed");
135        sim.apply_gate(StabilizerGate::CNOT(0, 1))
136            .expect("CNOT gate application should succeed");
137        sim.apply_gate(StabilizerGate::CNOT(1, 2))
138            .expect("CNOT gate application should succeed");
139        let stabs = sim.get_stabilizers();
140        assert!(stabs.contains(&"+XXX".to_string()));
141        assert!(stabs.contains(&"+ZZI".to_string()));
142        assert!(stabs.contains(&"+IZZ".to_string()));
143    }
144    #[test]
145    fn test_s_dag_gate() {
146        let mut sim = StabilizerSimulator::new(1);
147        sim.apply_gate(StabilizerGate::S(0))
148            .expect("S gate application should succeed");
149        sim.apply_gate(StabilizerGate::SDag(0))
150            .expect("S† gate application should succeed");
151        let stabs = sim.get_stabilizers();
152        assert_eq!(stabs[0], "+Z");
153    }
154    #[test]
155    fn test_sqrt_x_gate() {
156        let mut sim1 = StabilizerSimulator::new(1);
157        sim1.apply_gate(StabilizerGate::SqrtX(0))
158            .expect("√X gate application should succeed");
159        sim1.apply_gate(StabilizerGate::SqrtX(0))
160            .expect("√X gate application should succeed");
161        let stabs1 = sim1.get_stabilizers();
162        let mut sim2 = StabilizerSimulator::new(1);
163        sim2.apply_gate(StabilizerGate::X(0))
164            .expect("X gate application should succeed");
165        let stabs2 = sim2.get_stabilizers();
166        assert!(stabs1[0] == "+Z" || stabs1[0] == "-Z");
167        assert!(stabs2[0] == "+Z" || stabs2[0] == "-Z");
168    }
169    #[test]
170    fn test_sqrt_y_gate() {
171        let mut sim1 = StabilizerSimulator::new(1);
172        sim1.apply_gate(StabilizerGate::SqrtY(0))
173            .expect("√Y gate application should succeed");
174        sim1.apply_gate(StabilizerGate::SqrtY(0))
175            .expect("√Y gate application should succeed");
176        let stabs1 = sim1.get_stabilizers();
177        let mut sim2 = StabilizerSimulator::new(1);
178        sim2.apply_gate(StabilizerGate::Y(0))
179            .expect("Y gate application should succeed");
180        let stabs2 = sim2.get_stabilizers();
181        assert_eq!(stabs1[0], stabs2[0]);
182    }
183    #[test]
184    fn test_cz_gate() {
185        let mut sim = StabilizerSimulator::new(2);
186        sim.apply_gate(StabilizerGate::H(0))
187            .expect("Hadamard gate application should succeed");
188        sim.apply_gate(StabilizerGate::H(1))
189            .expect("Hadamard gate application should succeed");
190        sim.apply_gate(StabilizerGate::CZ(0, 1))
191            .expect("CZ gate application should succeed");
192        let stabs = sim.get_stabilizers();
193        assert!(stabs.len() == 2);
194    }
195    #[test]
196    fn test_cy_gate() {
197        let mut sim = StabilizerSimulator::new(2);
198        sim.apply_gate(StabilizerGate::H(0))
199            .expect("Hadamard gate application should succeed");
200        sim.apply_gate(StabilizerGate::CY(0, 1))
201            .expect("CY gate application should succeed");
202        let stabs = sim.get_stabilizers();
203        assert!(stabs.len() == 2);
204    }
205    #[test]
206    fn test_swap_gate() {
207        let mut sim = StabilizerSimulator::new(2);
208        sim.apply_gate(StabilizerGate::X(1))
209            .expect("X gate application should succeed");
210        sim.apply_gate(StabilizerGate::SWAP(0, 1))
211            .expect("SWAP gate application should succeed");
212        let stabs = sim.get_stabilizers();
213        assert!(stabs.len() == 2);
214    }
215    #[test]
216    fn test_builder_pattern_new_gates() {
217        let sim = CliffordCircuitBuilder::new(2)
218            .h(0)
219            .s_dag(0)
220            .sqrt_x(1)
221            .cz(0, 1)
222            .run()
223            .expect("Circuit execution should succeed");
224        let stabs = sim.get_stabilizers();
225        assert!(stabs.len() == 2);
226    }
227    #[test]
228    fn test_large_clifford_circuit() {
229        let mut sim = StabilizerSimulator::new(100);
230        for i in 0..100 {
231            sim.apply_gate(StabilizerGate::H(i))
232                .expect("Hadamard gate application should succeed");
233        }
234        for i in 0..99 {
235            sim.apply_gate(StabilizerGate::CNOT(i, i + 1))
236                .expect("CNOT gate application should succeed");
237        }
238        let stabs = sim.get_stabilizers();
239        assert_eq!(stabs.len(), 100);
240    }
241    #[test]
242    fn test_measurement_randomness() {
243        let mut sim = StabilizerSimulator::new(1);
244        sim.apply_gate(StabilizerGate::H(0))
245            .expect("Hadamard gate application should succeed");
246        let mut outcomes = Vec::new();
247        for _ in 0..10 {
248            let mut test_sim = StabilizerSimulator::new(1);
249            test_sim
250                .apply_gate(StabilizerGate::H(0))
251                .expect("Hadamard gate application should succeed");
252            let outcome = test_sim.measure(0).expect("Measurement should succeed");
253            outcomes.push(outcome);
254        }
255        let first = outcomes[0];
256        let all_same = outcomes.iter().all(|&x| x == first);
257        assert!(
258            !all_same || outcomes.len() < 5,
259            "Measurements should show randomness"
260        );
261    }
262    #[test]
263    fn test_measure_x_basis() {
264        let mut sim = StabilizerSimulator::new(1);
265        sim.apply_gate(StabilizerGate::H(0))
266            .expect("Hadamard gate application should succeed");
267        let outcome = sim
268            .tableau
269            .measure_x(0)
270            .expect("X-basis measurement should succeed");
271        assert!(!outcome);
272    }
273    #[test]
274    fn test_measure_y_basis() {
275        let mut sim = StabilizerSimulator::new(1);
276        sim.apply_gate(StabilizerGate::H(0)).unwrap();
277        sim.apply_gate(StabilizerGate::S(0)).unwrap();
278        let stabs = sim.get_stabilizers();
279        assert_eq!(stabs[0], "+Y");
280        let outcome = sim
281            .tableau
282            .measure_y(0)
283            .expect("Y-basis measurement should succeed");
284        assert!(!outcome);
285    }
286    #[test]
287    fn test_reset_operation() {
288        let mut sim = StabilizerSimulator::new(1);
289        sim.apply_gate(StabilizerGate::X(0))
290            .expect("X gate application should succeed");
291        sim.tableau.reset(0).expect("Reset should succeed");
292        let outcome = sim.measure(0).expect("Measurement should succeed");
293        assert!(!outcome);
294        let stabs = sim.get_stabilizers();
295        assert_eq!(stabs[0], "+Z");
296    }
297    #[test]
298    fn test_reset_from_superposition() {
299        let mut sim = StabilizerSimulator::new(1);
300        sim.apply_gate(StabilizerGate::H(0))
301            .expect("Hadamard gate application should succeed");
302        sim.tableau.reset(0).expect("Reset should succeed");
303        let outcome = sim.measure(0).expect("Measurement should succeed");
304        assert!(!outcome);
305    }
306    #[test]
307    fn test_x_y_measurements_commute() {
308        let mut sim = StabilizerSimulator::new(2);
309        sim.apply_gate(StabilizerGate::H(0)).unwrap();
310        sim.apply_gate(StabilizerGate::H(1)).unwrap();
311        sim.apply_gate(StabilizerGate::S(1)).unwrap();
312        let _outcome_x = sim.tableau.measure_x(0).unwrap();
313        let _outcome_y = sim.tableau.measure_y(1).unwrap();
314    }
315    #[test]
316    fn test_imaginary_phase_tracking() {
317        let mut tableau = StabilizerTableau::new(1);
318        tableau.apply_h(0).unwrap();
319        tableau.apply_s(0).unwrap();
320        let stabs = tableau.get_stabilizers();
321        assert_eq!(stabs[0], "+Y");
322    }
323    #[test]
324    fn test_imaginary_phase_with_s_dag() {
325        let mut tableau = StabilizerTableau::new(1);
326        tableau.apply_h(0).unwrap();
327        tableau.apply_s_dag(0).unwrap();
328        let stabs = tableau.get_stabilizers();
329        assert_eq!(stabs[0], "-Y");
330    }
331    #[test]
332    fn test_stim_format_identity() {
333        let mut tableau = StabilizerTableau::with_format(2, true);
334        let stabs = tableau.get_stabilizers();
335        assert_eq!(stabs[0], "+Z_");
336        assert_eq!(stabs[1], "+_Z");
337        tableau.apply_h(0).unwrap();
338        let stabs = tableau.get_stabilizers();
339        assert_eq!(stabs[0], "+X_");
340        assert_eq!(stabs[1], "+_Z");
341    }
342    #[test]
343    fn test_standard_format_identity() {
344        let tableau = StabilizerTableau::with_format(2, false);
345        let stabs = tableau.get_stabilizers();
346        assert_eq!(stabs[0], "+ZI");
347        assert_eq!(stabs[1], "+IZ");
348    }
349    #[test]
350    fn test_destabilizers_output() {
351        let mut tableau = StabilizerTableau::new(2);
352        let destabs = tableau.get_destabilizers();
353        assert_eq!(destabs[0], "+XI");
354        assert_eq!(destabs[1], "+IX");
355        tableau.apply_h(0).unwrap();
356        let destabs = tableau.get_destabilizers();
357        assert_eq!(destabs[0], "+ZI");
358        assert_eq!(destabs[1], "+IX");
359    }
360    #[test]
361    fn test_phase_constants() {
362        assert_eq!(phase::PLUS_ONE, 0);
363        assert_eq!(phase::PLUS_I, 1);
364        assert_eq!(phase::MINUS_ONE, 2);
365        assert_eq!(phase::MINUS_I, 3);
366    }
367    #[test]
368    fn test_phase_arithmetic() {
369        assert_eq!(
370            StabilizerTableau::negate_phase(phase::PLUS_ONE),
371            phase::MINUS_ONE
372        );
373        assert_eq!(
374            StabilizerTableau::negate_phase(phase::PLUS_I),
375            phase::MINUS_I
376        );
377        assert_eq!(
378            StabilizerTableau::negate_phase(phase::MINUS_ONE),
379            phase::PLUS_ONE
380        );
381        assert_eq!(
382            StabilizerTableau::negate_phase(phase::MINUS_I),
383            phase::PLUS_I
384        );
385        assert_eq!(
386            StabilizerTableau::multiply_by_i(phase::PLUS_ONE),
387            phase::PLUS_I
388        );
389        assert_eq!(
390            StabilizerTableau::multiply_by_i(phase::PLUS_I),
391            phase::MINUS_ONE
392        );
393        assert_eq!(
394            StabilizerTableau::multiply_by_i(phase::MINUS_ONE),
395            phase::MINUS_I
396        );
397        assert_eq!(
398            StabilizerTableau::multiply_by_i(phase::MINUS_I),
399            phase::PLUS_ONE
400        );
401        assert_eq!(
402            StabilizerTableau::multiply_by_minus_i(phase::PLUS_ONE),
403            phase::MINUS_I
404        );
405        assert_eq!(
406            StabilizerTableau::multiply_by_minus_i(phase::PLUS_I),
407            phase::PLUS_ONE
408        );
409        assert_eq!(
410            StabilizerTableau::multiply_by_minus_i(phase::MINUS_ONE),
411            phase::PLUS_I
412        );
413        assert_eq!(
414            StabilizerTableau::multiply_by_minus_i(phase::MINUS_I),
415            phase::MINUS_ONE
416        );
417    }
418    #[test]
419    fn test_y_gate_phase_tracking() {
420        let mut tableau = StabilizerTableau::new(1);
421        tableau.apply_y(0).unwrap();
422        let stabs = tableau.get_stabilizers();
423        assert_eq!(stabs[0], "-Z");
424    }
425    #[test]
426    fn test_sqrt_gates_produce_imaginary_phases() {
427        let mut tableau = StabilizerTableau::new(1);
428        tableau.apply_sqrt_y(0).unwrap();
429        let stabs = tableau.get_stabilizers();
430        assert_eq!(stabs[0], "-X");
431    }
432}