1use crate::simulator::{Simulator, SimulatorResult};
9use quantrs2_circuit::prelude::*;
10use quantrs2_core::gate::GateOp;
11use quantrs2_core::prelude::*;
12use scirs2_core::ndarray::{Array2, ArrayView2};
13use scirs2_core::random::prelude::*;
14use scirs2_core::Complex64;
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 #[must_use]
43 pub fn new(num_qubits: usize) -> Self {
44 let mut x_matrix = Array2::from_elem((num_qubits, num_qubits), false);
45 let mut z_matrix = Array2::from_elem((num_qubits, num_qubits), false);
46 let mut destab_x = Array2::from_elem((num_qubits, num_qubits), false);
47 let mut destab_z = Array2::from_elem((num_qubits, num_qubits), false);
48
49 for i in 0..num_qubits {
51 z_matrix[[i, i]] = true; destab_x[[i, i]] = true; }
54
55 Self {
56 num_qubits,
57 x_matrix,
58 z_matrix,
59 phase: vec![false; num_qubits],
60 destab_x,
61 destab_z,
62 destab_phase: vec![false; num_qubits],
63 }
64 }
65
66 pub fn apply_h(&mut self, qubit: usize) -> Result<(), QuantRS2Error> {
68 if qubit >= self.num_qubits {
69 return Err(QuantRS2Error::InvalidQubitId(qubit as u32));
70 }
71
72 for i in 0..self.num_qubits {
74 let x_val = self.x_matrix[[i, qubit]];
76 let z_val = self.z_matrix[[i, qubit]];
77
78 if x_val && z_val {
80 self.phase[i] = !self.phase[i];
81 }
82
83 self.x_matrix[[i, qubit]] = z_val;
85 self.z_matrix[[i, qubit]] = x_val;
86
87 let dx_val = self.destab_x[[i, qubit]];
89 let dz_val = self.destab_z[[i, qubit]];
90
91 if dx_val && dz_val {
92 self.destab_phase[i] = !self.destab_phase[i];
93 }
94
95 self.destab_x[[i, qubit]] = dz_val;
96 self.destab_z[[i, qubit]] = dx_val;
97 }
98
99 Ok(())
100 }
101
102 pub fn apply_s(&mut self, qubit: usize) -> Result<(), QuantRS2Error> {
104 if qubit >= self.num_qubits {
105 return Err(QuantRS2Error::InvalidQubitId(qubit as u32));
106 }
107
108 for i in 0..self.num_qubits {
111 if self.x_matrix[[i, qubit]] && !self.z_matrix[[i, qubit]] {
113 self.z_matrix[[i, qubit]] = true;
115 self.phase[i] = !self.phase[i]; }
117
118 if self.destab_x[[i, qubit]] && !self.destab_z[[i, qubit]] {
120 self.destab_z[[i, qubit]] = true;
121 self.destab_phase[i] = !self.destab_phase[i];
122 }
123 }
124
125 Ok(())
126 }
127
128 pub fn apply_cnot(&mut self, control: usize, target: usize) -> Result<(), QuantRS2Error> {
130 if control >= self.num_qubits || target >= self.num_qubits {
131 return Err(QuantRS2Error::InvalidQubitId(control.max(target) as u32));
132 }
133
134 if control == target {
135 return Err(QuantRS2Error::InvalidInput(
136 "CNOT control and target must be different".to_string(),
137 ));
138 }
139
140 for i in 0..self.num_qubits {
142 if self.x_matrix[[i, control]] {
144 self.x_matrix[[i, target]] ^= true;
145 }
146 if self.z_matrix[[i, target]] {
147 self.z_matrix[[i, control]] ^= true;
148 }
149
150 if self.destab_x[[i, control]] {
152 self.destab_x[[i, target]] ^= true;
153 }
154 if self.destab_z[[i, target]] {
155 self.destab_z[[i, control]] ^= true;
156 }
157 }
158
159 Ok(())
160 }
161
162 pub fn apply_x(&mut self, qubit: usize) -> Result<(), QuantRS2Error> {
164 if qubit >= self.num_qubits {
165 return Err(QuantRS2Error::InvalidQubitId(qubit as u32));
166 }
167
168 for i in 0..self.num_qubits {
170 if self.z_matrix[[i, qubit]] {
171 self.phase[i] = !self.phase[i];
172 }
173 if self.destab_z[[i, qubit]] {
174 self.destab_phase[i] = !self.destab_phase[i];
175 }
176 }
177
178 Ok(())
179 }
180
181 pub fn apply_y(&mut self, qubit: usize) -> Result<(), QuantRS2Error> {
183 if qubit >= self.num_qubits {
184 return Err(QuantRS2Error::InvalidQubitId(qubit as u32));
185 }
186
187 for i in 0..self.num_qubits {
189 let has_x = self.x_matrix[[i, qubit]];
190 let has_z = self.z_matrix[[i, qubit]];
191
192 if has_x != has_z {
193 self.phase[i] = !self.phase[i];
194 }
195
196 let has_dx = self.destab_x[[i, qubit]];
197 let has_dz = self.destab_z[[i, qubit]];
198
199 if has_dx != has_dz {
200 self.destab_phase[i] = !self.destab_phase[i];
201 }
202 }
203
204 Ok(())
205 }
206
207 pub fn apply_z(&mut self, qubit: usize) -> Result<(), QuantRS2Error> {
209 if qubit >= self.num_qubits {
210 return Err(QuantRS2Error::InvalidQubitId(qubit as u32));
211 }
212
213 for i in 0..self.num_qubits {
215 if self.x_matrix[[i, qubit]] {
216 self.phase[i] = !self.phase[i];
217 }
218 if self.destab_x[[i, qubit]] {
219 self.destab_phase[i] = !self.destab_phase[i];
220 }
221 }
222
223 Ok(())
224 }
225
226 pub fn measure(&mut self, qubit: usize) -> Result<bool, QuantRS2Error> {
229 if qubit >= self.num_qubits {
230 return Err(QuantRS2Error::InvalidQubitId(qubit as u32));
231 }
232
233 let mut anticommuting_row = None;
235
236 for i in 0..self.num_qubits {
237 if self.x_matrix[[i, qubit]] {
238 anticommuting_row = Some(i);
239 break;
240 }
241 }
242
243 if let Some(p) = anticommuting_row {
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) } else {
271 let mut outcome = false;
274
275 for i in 0..self.num_qubits {
276 if self.z_matrix[[i, qubit]] && !self.x_matrix[[i, qubit]] {
277 outcome = self.phase[i];
278 break;
279 }
280 }
281
282 Ok(outcome)
283 }
284 }
285
286 #[must_use]
288 pub fn get_stabilizers(&self) -> Vec<String> {
289 let mut stabilizers = Vec::new();
290
291 for i in 0..self.num_qubits {
292 let mut stab = String::new();
293
294 if self.phase[i] {
296 stab.push('-');
297 } else {
298 stab.push('+');
299 }
300
301 for j in 0..self.num_qubits {
303 let has_x = self.x_matrix[[i, j]];
304 let has_z = self.z_matrix[[i, j]];
305
306 match (has_x, has_z) {
307 (false, false) => stab.push('I'),
308 (true, false) => stab.push('X'),
309 (false, true) => stab.push('Z'),
310 (true, true) => stab.push('Y'),
311 }
312 }
313
314 stabilizers.push(stab);
315 }
316
317 stabilizers
318 }
319}
320
321pub struct StabilizerSimulator {
323 tableau: StabilizerTableau,
324 measurement_record: Vec<(usize, bool)>,
325}
326
327impl StabilizerSimulator {
328 #[must_use]
330 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 #[must_use]
358 pub fn get_stabilizers(&self) -> Vec<String> {
359 self.tableau.get_stabilizers()
360 }
361
362 #[must_use]
364 pub fn get_measurements(&self) -> &[(usize, bool)] {
365 &self.measurement_record
366 }
367
368 pub fn reset(&mut self) {
370 let num_qubits = self.tableau.num_qubits;
371 self.tableau = StabilizerTableau::new(num_qubits);
372 self.measurement_record.clear();
373 }
374
375 #[must_use]
377 pub const fn num_qubits(&self) -> usize {
378 self.tableau.num_qubits
379 }
380
381 #[must_use]
384 pub fn get_statevector(&self) -> Vec<Complex64> {
385 let n = self.tableau.num_qubits;
386 let dim = 1 << n;
387 let mut state = vec![Complex64::new(0.0, 0.0); dim];
388
389 state[0] = Complex64::new(1.0, 0.0);
396 state
397 }
398}
399
400#[derive(Debug, Clone, Copy)]
402pub enum StabilizerGate {
403 H(usize),
404 S(usize),
405 X(usize),
406 Y(usize),
407 Z(usize),
408 CNOT(usize, usize),
409}
410
411#[must_use]
413pub fn is_clifford_circuit<const N: usize>(circuit: &Circuit<N>) -> bool {
414 circuit.gates().iter().all(|gate| {
417 matches!(
418 gate.name(),
419 "H" | "S" | "S†" | "CNOT" | "X" | "Y" | "Z" | "CZ" | "Phase" | "PhaseDagger"
420 )
421 })
422}
423
424fn gate_to_stabilizer(gate: &Arc<dyn GateOp + Send + Sync>) -> Option<StabilizerGate> {
426 let gate_name = gate.name();
427 let qubits = gate.qubits();
428
429 match gate_name {
430 "H" => {
431 if qubits.len() == 1 {
432 Some(StabilizerGate::H(qubits[0].0 as usize))
433 } else {
434 None
435 }
436 }
437 "S" | "Phase" => {
438 if qubits.len() == 1 {
439 Some(StabilizerGate::S(qubits[0].0 as usize))
440 } else {
441 None
442 }
443 }
444 "X" => {
445 if qubits.len() == 1 {
446 Some(StabilizerGate::X(qubits[0].0 as usize))
447 } else {
448 None
449 }
450 }
451 "Y" => {
452 if qubits.len() == 1 {
453 Some(StabilizerGate::Y(qubits[0].0 as usize))
454 } else {
455 None
456 }
457 }
458 "Z" => {
459 if qubits.len() == 1 {
460 Some(StabilizerGate::Z(qubits[0].0 as usize))
461 } else {
462 None
463 }
464 }
465 "CNOT" => {
466 if qubits.len() == 2 {
467 Some(StabilizerGate::CNOT(
468 qubits[0].0 as usize,
469 qubits[1].0 as usize,
470 ))
471 } else {
472 None
473 }
474 }
475 "CZ" => {
476 if qubits.len() == 2 {
477 None
481 } else {
482 None
483 }
484 }
485 _ => None,
486 }
487}
488
489impl Simulator for StabilizerSimulator {
491 fn run<const N: usize>(
492 &mut self,
493 circuit: &Circuit<N>,
494 ) -> crate::error::Result<SimulatorResult<N>> {
495 let mut sim = Self::new(N);
497
498 for gate in circuit.gates() {
500 if let Some(stab_gate) = gate_to_stabilizer(gate) {
501 let _ = sim.apply_gate(stab_gate);
503 }
504 }
505
506 let amplitudes = sim.get_statevector();
508
509 Ok(SimulatorResult::new(amplitudes))
510 }
511}
512
513pub struct CliffordCircuitBuilder {
515 gates: Vec<StabilizerGate>,
516 num_qubits: usize,
517}
518
519impl CliffordCircuitBuilder {
520 #[must_use]
522 pub const fn new(num_qubits: usize) -> Self {
523 Self {
524 gates: Vec::new(),
525 num_qubits,
526 }
527 }
528
529 #[must_use]
531 pub fn h(mut self, qubit: usize) -> Self {
532 self.gates.push(StabilizerGate::H(qubit));
533 self
534 }
535
536 #[must_use]
538 pub fn s(mut self, qubit: usize) -> Self {
539 self.gates.push(StabilizerGate::S(qubit));
540 self
541 }
542
543 #[must_use]
545 pub fn x(mut self, qubit: usize) -> Self {
546 self.gates.push(StabilizerGate::X(qubit));
547 self
548 }
549
550 #[must_use]
552 pub fn y(mut self, qubit: usize) -> Self {
553 self.gates.push(StabilizerGate::Y(qubit));
554 self
555 }
556
557 #[must_use]
559 pub fn z(mut self, qubit: usize) -> Self {
560 self.gates.push(StabilizerGate::Z(qubit));
561 self
562 }
563
564 #[must_use]
566 pub fn cnot(mut self, control: usize, target: usize) -> Self {
567 self.gates.push(StabilizerGate::CNOT(control, target));
568 self
569 }
570
571 pub fn run(self) -> Result<StabilizerSimulator, QuantRS2Error> {
573 let mut sim = StabilizerSimulator::new(self.num_qubits);
574
575 for gate in self.gates {
576 sim.apply_gate(gate)?;
577 }
578
579 Ok(sim)
580 }
581}
582
583#[cfg(test)]
584mod tests {
585 use super::*;
586
587 #[test]
588 fn test_stabilizer_init() {
589 let sim = StabilizerSimulator::new(3);
590 let stabs = sim.get_stabilizers();
591
592 assert_eq!(stabs.len(), 3);
593 assert_eq!(stabs[0], "+ZII");
594 assert_eq!(stabs[1], "+IZI");
595 assert_eq!(stabs[2], "+IIZ");
596 }
597
598 #[test]
599 fn test_hadamard_gate() {
600 let mut sim = StabilizerSimulator::new(1);
601 sim.apply_gate(StabilizerGate::H(0))
602 .expect("Hadamard gate application should succeed");
603
604 let stabs = sim.get_stabilizers();
605 assert_eq!(stabs[0], "+X");
606 }
607
608 #[test]
609 fn test_bell_state() {
610 let mut sim = StabilizerSimulator::new(2);
611 sim.apply_gate(StabilizerGate::H(0))
612 .expect("Hadamard gate application should succeed");
613 sim.apply_gate(StabilizerGate::CNOT(0, 1))
614 .expect("CNOT gate application should succeed");
615
616 let stabs = sim.get_stabilizers();
617 assert!(stabs.contains(&"+XX".to_string()));
618 assert!(stabs.contains(&"+ZZ".to_string()));
619 }
620
621 #[test]
622 fn test_ghz_state() {
623 let mut sim = StabilizerSimulator::new(3);
624 sim.apply_gate(StabilizerGate::H(0))
625 .expect("Hadamard gate application should succeed");
626 sim.apply_gate(StabilizerGate::CNOT(0, 1))
627 .expect("CNOT gate application should succeed");
628 sim.apply_gate(StabilizerGate::CNOT(1, 2))
629 .expect("CNOT gate application should succeed");
630
631 let stabs = sim.get_stabilizers();
632 assert!(stabs.contains(&"+XXX".to_string()));
633 assert!(stabs.contains(&"+ZZI".to_string()));
634 assert!(stabs.contains(&"+IZZ".to_string()));
635 }
636}