1use crate::simulator::{Simulator, SimulatorResult};
9use scirs2_core::ndarray::{Array2, ArrayView2};
10use scirs2_core::Complex64;
11use quantrs2_circuit::prelude::*;
12use quantrs2_core::gate::GateOp;
13use quantrs2_core::prelude::*;
14use scirs2_core::random::prelude::*;
15use std::collections::HashMap;
16use std::sync::Arc;
17
18#[derive(Debug, Clone)]
23pub struct StabilizerTableau {
24 num_qubits: usize,
26 x_matrix: Array2<bool>,
28 z_matrix: Array2<bool>,
30 phase: Vec<bool>,
32 destab_x: Array2<bool>,
34 destab_z: Array2<bool>,
36 destab_phase: Vec<bool>,
38}
39
40impl StabilizerTableau {
41 pub fn new(num_qubits: usize) -> Self {
43 let mut x_matrix = Array2::from_elem((num_qubits, num_qubits), false);
44 let mut z_matrix = Array2::from_elem((num_qubits, num_qubits), false);
45 let mut destab_x = Array2::from_elem((num_qubits, num_qubits), false);
46 let mut destab_z = Array2::from_elem((num_qubits, num_qubits), false);
47
48 for i in 0..num_qubits {
50 z_matrix[[i, i]] = true; destab_x[[i, i]] = true; }
53
54 Self {
55 num_qubits,
56 x_matrix,
57 z_matrix,
58 phase: vec![false; num_qubits],
59 destab_x,
60 destab_z,
61 destab_phase: vec![false; num_qubits],
62 }
63 }
64
65 pub fn apply_h(&mut self, qubit: usize) -> Result<(), QuantRS2Error> {
67 if qubit >= self.num_qubits {
68 return Err(QuantRS2Error::InvalidQubitId(qubit as u32));
69 }
70
71 for i in 0..self.num_qubits {
73 let x_val = self.x_matrix[[i, qubit]];
75 let z_val = self.z_matrix[[i, qubit]];
76
77 if x_val && z_val {
79 self.phase[i] = !self.phase[i];
80 }
81
82 self.x_matrix[[i, qubit]] = z_val;
84 self.z_matrix[[i, qubit]] = x_val;
85
86 let dx_val = self.destab_x[[i, qubit]];
88 let dz_val = self.destab_z[[i, qubit]];
89
90 if dx_val && dz_val {
91 self.destab_phase[i] = !self.destab_phase[i];
92 }
93
94 self.destab_x[[i, qubit]] = dz_val;
95 self.destab_z[[i, qubit]] = dx_val;
96 }
97
98 Ok(())
99 }
100
101 pub fn apply_s(&mut self, qubit: usize) -> Result<(), QuantRS2Error> {
103 if qubit >= self.num_qubits {
104 return Err(QuantRS2Error::InvalidQubitId(qubit as u32));
105 }
106
107 for i in 0..self.num_qubits {
110 if self.x_matrix[[i, qubit]] && !self.z_matrix[[i, qubit]] {
112 self.z_matrix[[i, qubit]] = true;
114 self.phase[i] = !self.phase[i]; }
116
117 if self.destab_x[[i, qubit]] && !self.destab_z[[i, qubit]] {
119 self.destab_z[[i, qubit]] = true;
120 self.destab_phase[i] = !self.destab_phase[i];
121 }
122 }
123
124 Ok(())
125 }
126
127 pub fn apply_cnot(&mut self, control: usize, target: usize) -> Result<(), QuantRS2Error> {
129 if control >= self.num_qubits || target >= self.num_qubits {
130 return Err(QuantRS2Error::InvalidQubitId(control.max(target) as u32));
131 }
132
133 if control == target {
134 return Err(QuantRS2Error::InvalidInput(
135 "CNOT control and target must be different".to_string(),
136 ));
137 }
138
139 for i in 0..self.num_qubits {
141 if self.x_matrix[[i, control]] {
143 self.x_matrix[[i, target]] ^= true;
144 }
145 if self.z_matrix[[i, target]] {
146 self.z_matrix[[i, control]] ^= true;
147 }
148
149 if self.destab_x[[i, control]] {
151 self.destab_x[[i, target]] ^= true;
152 }
153 if self.destab_z[[i, target]] {
154 self.destab_z[[i, control]] ^= true;
155 }
156 }
157
158 Ok(())
159 }
160
161 pub fn apply_x(&mut self, qubit: usize) -> Result<(), QuantRS2Error> {
163 if qubit >= self.num_qubits {
164 return Err(QuantRS2Error::InvalidQubitId(qubit as u32));
165 }
166
167 for i in 0..self.num_qubits {
169 if self.z_matrix[[i, qubit]] {
170 self.phase[i] = !self.phase[i];
171 }
172 if self.destab_z[[i, qubit]] {
173 self.destab_phase[i] = !self.destab_phase[i];
174 }
175 }
176
177 Ok(())
178 }
179
180 pub fn apply_y(&mut self, qubit: usize) -> Result<(), QuantRS2Error> {
182 if qubit >= self.num_qubits {
183 return Err(QuantRS2Error::InvalidQubitId(qubit as u32));
184 }
185
186 for i in 0..self.num_qubits {
188 let has_x = self.x_matrix[[i, qubit]];
189 let has_z = self.z_matrix[[i, qubit]];
190
191 if has_x != has_z {
192 self.phase[i] = !self.phase[i];
193 }
194
195 let has_dx = self.destab_x[[i, qubit]];
196 let has_dz = self.destab_z[[i, qubit]];
197
198 if has_dx != has_dz {
199 self.destab_phase[i] = !self.destab_phase[i];
200 }
201 }
202
203 Ok(())
204 }
205
206 pub fn apply_z(&mut self, qubit: usize) -> Result<(), QuantRS2Error> {
208 if qubit >= self.num_qubits {
209 return Err(QuantRS2Error::InvalidQubitId(qubit as u32));
210 }
211
212 for i in 0..self.num_qubits {
214 if self.x_matrix[[i, qubit]] {
215 self.phase[i] = !self.phase[i];
216 }
217 if self.destab_x[[i, qubit]] {
218 self.destab_phase[i] = !self.destab_phase[i];
219 }
220 }
221
222 Ok(())
223 }
224
225 pub fn measure(&mut self, qubit: usize) -> Result<bool, QuantRS2Error> {
228 if qubit >= self.num_qubits {
229 return Err(QuantRS2Error::InvalidQubitId(qubit as u32));
230 }
231
232 let mut anticommuting_row = None;
234
235 for i in 0..self.num_qubits {
236 if self.x_matrix[[i, qubit]] {
237 anticommuting_row = Some(i);
238 break;
239 }
240 }
241
242 match anticommuting_row {
243 Some(p) => {
244 for j in 0..self.num_qubits {
247 self.x_matrix[[p, j]] = false;
248 self.z_matrix[[p, j]] = j == qubit;
249 }
250
251 let mut rng = thread_rng();
253 let outcome = rng.gen_bool(0.5);
254 self.phase[p] = outcome;
255
256 for i in 0..self.num_qubits {
258 if i != p && self.x_matrix[[i, qubit]] {
259 for j in 0..self.num_qubits {
261 self.x_matrix[[i, j]] ^= self.x_matrix[[p, j]];
262 self.z_matrix[[i, j]] ^= self.z_matrix[[p, j]];
263 }
264 self.phase[i] ^= self.phase[p];
266 }
267 }
268
269 Ok(outcome) }
271 None => {
272 let mut outcome = false;
275
276 for i in 0..self.num_qubits {
277 if self.z_matrix[[i, qubit]] && !self.x_matrix[[i, qubit]] {
278 outcome = self.phase[i];
279 break;
280 }
281 }
282
283 Ok(outcome)
284 }
285 }
286 }
287
288 pub fn get_stabilizers(&self) -> Vec<String> {
290 let mut stabilizers = Vec::new();
291
292 for i in 0..self.num_qubits {
293 let mut stab = String::new();
294
295 if self.phase[i] {
297 stab.push('-');
298 } else {
299 stab.push('+');
300 }
301
302 for j in 0..self.num_qubits {
304 let has_x = self.x_matrix[[i, j]];
305 let has_z = self.z_matrix[[i, j]];
306
307 match (has_x, has_z) {
308 (false, false) => stab.push('I'),
309 (true, false) => stab.push('X'),
310 (false, true) => stab.push('Z'),
311 (true, true) => stab.push('Y'),
312 }
313 }
314
315 stabilizers.push(stab);
316 }
317
318 stabilizers
319 }
320}
321
322pub struct StabilizerSimulator {
324 tableau: StabilizerTableau,
325 measurement_record: Vec<(usize, bool)>,
326}
327
328impl StabilizerSimulator {
329 pub fn new(num_qubits: usize) -> Self {
331 Self {
332 tableau: StabilizerTableau::new(num_qubits),
333 measurement_record: Vec::new(),
334 }
335 }
336
337 pub fn apply_gate(&mut self, gate: StabilizerGate) -> Result<(), QuantRS2Error> {
339 match gate {
340 StabilizerGate::H(q) => self.tableau.apply_h(q),
341 StabilizerGate::S(q) => self.tableau.apply_s(q),
342 StabilizerGate::X(q) => self.tableau.apply_x(q),
343 StabilizerGate::Y(q) => self.tableau.apply_y(q),
344 StabilizerGate::Z(q) => self.tableau.apply_z(q),
345 StabilizerGate::CNOT(c, t) => self.tableau.apply_cnot(c, t),
346 }
347 }
348
349 pub fn measure(&mut self, qubit: usize) -> Result<bool, QuantRS2Error> {
351 let outcome = self.tableau.measure(qubit)?;
352 self.measurement_record.push((qubit, outcome));
353 Ok(outcome)
354 }
355
356 pub fn get_stabilizers(&self) -> Vec<String> {
358 self.tableau.get_stabilizers()
359 }
360
361 pub fn get_measurements(&self) -> &[(usize, bool)] {
363 &self.measurement_record
364 }
365
366 pub fn reset(&mut self) {
368 let num_qubits = self.tableau.num_qubits;
369 self.tableau = StabilizerTableau::new(num_qubits);
370 self.measurement_record.clear();
371 }
372
373 pub fn num_qubits(&self) -> usize {
375 self.tableau.num_qubits
376 }
377
378 pub fn get_statevector(&self) -> Vec<Complex64> {
381 let n = self.tableau.num_qubits;
382 let dim = 1 << n;
383 let mut state = vec![Complex64::new(0.0, 0.0); dim];
384
385 state[0] = Complex64::new(1.0, 0.0);
392 state
393 }
394}
395
396#[derive(Debug, Clone, Copy)]
398pub enum StabilizerGate {
399 H(usize),
400 S(usize),
401 X(usize),
402 Y(usize),
403 Z(usize),
404 CNOT(usize, usize),
405}
406
407pub fn is_clifford_circuit<const N: usize>(circuit: &Circuit<N>) -> bool {
409 circuit.gates().iter().all(|gate| {
412 matches!(
413 gate.name(),
414 "H" | "S" | "S†" | "CNOT" | "X" | "Y" | "Z" | "CZ" | "Phase" | "PhaseDagger"
415 )
416 })
417}
418
419fn gate_to_stabilizer(gate: &Arc<dyn GateOp + Send + Sync>) -> Option<StabilizerGate> {
421 let gate_name = gate.name();
422 let qubits = gate.qubits();
423
424 match gate_name {
425 "H" => {
426 if qubits.len() == 1 {
427 Some(StabilizerGate::H(qubits[0].0 as usize))
428 } else {
429 None
430 }
431 }
432 "S" | "Phase" => {
433 if qubits.len() == 1 {
434 Some(StabilizerGate::S(qubits[0].0 as usize))
435 } else {
436 None
437 }
438 }
439 "X" => {
440 if qubits.len() == 1 {
441 Some(StabilizerGate::X(qubits[0].0 as usize))
442 } else {
443 None
444 }
445 }
446 "Y" => {
447 if qubits.len() == 1 {
448 Some(StabilizerGate::Y(qubits[0].0 as usize))
449 } else {
450 None
451 }
452 }
453 "Z" => {
454 if qubits.len() == 1 {
455 Some(StabilizerGate::Z(qubits[0].0 as usize))
456 } else {
457 None
458 }
459 }
460 "CNOT" => {
461 if qubits.len() == 2 {
462 Some(StabilizerGate::CNOT(
463 qubits[0].0 as usize,
464 qubits[1].0 as usize,
465 ))
466 } else {
467 None
468 }
469 }
470 "CZ" => {
471 if qubits.len() == 2 {
472 None
476 } else {
477 None
478 }
479 }
480 _ => None,
481 }
482}
483
484impl Simulator for StabilizerSimulator {
486 fn run<const N: usize>(
487 &mut self,
488 circuit: &Circuit<N>,
489 ) -> crate::error::Result<SimulatorResult<N>> {
490 let mut sim = StabilizerSimulator::new(N);
492
493 for gate in circuit.gates() {
495 if let Some(stab_gate) = gate_to_stabilizer(gate) {
496 let _ = sim.apply_gate(stab_gate);
498 }
499 }
500
501 let amplitudes = sim.get_statevector();
503
504 Ok(SimulatorResult::new(amplitudes))
505 }
506}
507
508pub struct CliffordCircuitBuilder {
510 gates: Vec<StabilizerGate>,
511 num_qubits: usize,
512}
513
514impl CliffordCircuitBuilder {
515 pub fn new(num_qubits: usize) -> Self {
517 Self {
518 gates: Vec::new(),
519 num_qubits,
520 }
521 }
522
523 pub fn h(mut self, qubit: usize) -> Self {
525 self.gates.push(StabilizerGate::H(qubit));
526 self
527 }
528
529 pub fn s(mut self, qubit: usize) -> Self {
531 self.gates.push(StabilizerGate::S(qubit));
532 self
533 }
534
535 pub fn x(mut self, qubit: usize) -> Self {
537 self.gates.push(StabilizerGate::X(qubit));
538 self
539 }
540
541 pub fn y(mut self, qubit: usize) -> Self {
543 self.gates.push(StabilizerGate::Y(qubit));
544 self
545 }
546
547 pub fn z(mut self, qubit: usize) -> Self {
549 self.gates.push(StabilizerGate::Z(qubit));
550 self
551 }
552
553 pub fn cnot(mut self, control: usize, target: usize) -> Self {
555 self.gates.push(StabilizerGate::CNOT(control, target));
556 self
557 }
558
559 pub fn run(self) -> Result<StabilizerSimulator, QuantRS2Error> {
561 let mut sim = StabilizerSimulator::new(self.num_qubits);
562
563 for gate in self.gates {
564 sim.apply_gate(gate)?;
565 }
566
567 Ok(sim)
568 }
569}
570
571#[cfg(test)]
572mod tests {
573 use super::*;
574
575 #[test]
576 fn test_stabilizer_init() {
577 let sim = StabilizerSimulator::new(3);
578 let stabs = sim.get_stabilizers();
579
580 assert_eq!(stabs.len(), 3);
581 assert_eq!(stabs[0], "+ZII");
582 assert_eq!(stabs[1], "+IZI");
583 assert_eq!(stabs[2], "+IIZ");
584 }
585
586 #[test]
587 fn test_hadamard_gate() {
588 let mut sim = StabilizerSimulator::new(1);
589 sim.apply_gate(StabilizerGate::H(0)).unwrap();
590
591 let stabs = sim.get_stabilizers();
592 assert_eq!(stabs[0], "+X");
593 }
594
595 #[test]
596 fn test_bell_state() {
597 let mut sim = StabilizerSimulator::new(2);
598 sim.apply_gate(StabilizerGate::H(0)).unwrap();
599 sim.apply_gate(StabilizerGate::CNOT(0, 1)).unwrap();
600
601 let stabs = sim.get_stabilizers();
602 assert!(stabs.contains(&"+XX".to_string()));
603 assert!(stabs.contains(&"+ZZ".to_string()));
604 }
605
606 #[test]
607 fn test_ghz_state() {
608 let mut sim = StabilizerSimulator::new(3);
609 sim.apply_gate(StabilizerGate::H(0)).unwrap();
610 sim.apply_gate(StabilizerGate::CNOT(0, 1)).unwrap();
611 sim.apply_gate(StabilizerGate::CNOT(1, 2)).unwrap();
612
613 let stabs = sim.get_stabilizers();
614 assert!(stabs.contains(&"+XXX".to_string()));
615 assert!(stabs.contains(&"+ZZI".to_string()));
616 assert!(stabs.contains(&"+IZZ".to_string()));
617 }
618}