quantrs2_sim/stabilizer/
functions.rs1use 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
15pub type StabilizerPhase = u8;
18pub mod phase {
20 pub const PLUS_ONE: u8 = 0;
22 pub const PLUS_I: u8 = 1;
24 pub const MINUS_ONE: u8 = 2;
26 pub const MINUS_I: u8 = 3;
28}
29#[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}
39pub(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}