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 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 if let Some(p) = anticommuting_row {
243 for j in 0..self.num_qubits {
246 self.x_matrix[[p, j]] = false;
247 self.z_matrix[[p, j]] = j == qubit;
248 }
249
250 let mut rng = thread_rng();
252 let outcome = rng.gen_bool(0.5);
253 self.phase[p] = outcome;
254
255 for i in 0..self.num_qubits {
257 if i != p && self.x_matrix[[i, qubit]] {
258 for j in 0..self.num_qubits {
260 self.x_matrix[[i, j]] ^= self.x_matrix[[p, j]];
261 self.z_matrix[[i, j]] ^= self.z_matrix[[p, j]];
262 }
263 self.phase[i] ^= self.phase[p];
265 }
266 }
267
268 Ok(outcome) } else {
270 let mut outcome = false;
273
274 for i in 0..self.num_qubits {
275 if self.z_matrix[[i, qubit]] && !self.x_matrix[[i, qubit]] {
276 outcome = self.phase[i];
277 break;
278 }
279 }
280
281 Ok(outcome)
282 }
283 }
284
285 pub fn get_stabilizers(&self) -> Vec<String> {
287 let mut stabilizers = Vec::new();
288
289 for i in 0..self.num_qubits {
290 let mut stab = String::new();
291
292 if self.phase[i] {
294 stab.push('-');
295 } else {
296 stab.push('+');
297 }
298
299 for j in 0..self.num_qubits {
301 let has_x = self.x_matrix[[i, j]];
302 let has_z = self.z_matrix[[i, j]];
303
304 match (has_x, has_z) {
305 (false, false) => stab.push('I'),
306 (true, false) => stab.push('X'),
307 (false, true) => stab.push('Z'),
308 (true, true) => stab.push('Y'),
309 }
310 }
311
312 stabilizers.push(stab);
313 }
314
315 stabilizers
316 }
317}
318
319pub struct StabilizerSimulator {
321 tableau: StabilizerTableau,
322 measurement_record: Vec<(usize, bool)>,
323}
324
325impl StabilizerSimulator {
326 pub fn new(num_qubits: usize) -> Self {
328 Self {
329 tableau: StabilizerTableau::new(num_qubits),
330 measurement_record: Vec::new(),
331 }
332 }
333
334 pub fn apply_gate(&mut self, gate: StabilizerGate) -> Result<(), QuantRS2Error> {
336 match gate {
337 StabilizerGate::H(q) => self.tableau.apply_h(q),
338 StabilizerGate::S(q) => self.tableau.apply_s(q),
339 StabilizerGate::X(q) => self.tableau.apply_x(q),
340 StabilizerGate::Y(q) => self.tableau.apply_y(q),
341 StabilizerGate::Z(q) => self.tableau.apply_z(q),
342 StabilizerGate::CNOT(c, t) => self.tableau.apply_cnot(c, t),
343 }
344 }
345
346 pub fn measure(&mut self, qubit: usize) -> Result<bool, QuantRS2Error> {
348 let outcome = self.tableau.measure(qubit)?;
349 self.measurement_record.push((qubit, outcome));
350 Ok(outcome)
351 }
352
353 pub fn get_stabilizers(&self) -> Vec<String> {
355 self.tableau.get_stabilizers()
356 }
357
358 pub fn get_measurements(&self) -> &[(usize, bool)] {
360 &self.measurement_record
361 }
362
363 pub fn reset(&mut self) {
365 let num_qubits = self.tableau.num_qubits;
366 self.tableau = StabilizerTableau::new(num_qubits);
367 self.measurement_record.clear();
368 }
369
370 pub const fn num_qubits(&self) -> usize {
372 self.tableau.num_qubits
373 }
374
375 pub fn get_statevector(&self) -> Vec<Complex64> {
378 let n = self.tableau.num_qubits;
379 let dim = 1 << n;
380 let mut state = vec![Complex64::new(0.0, 0.0); dim];
381
382 state[0] = Complex64::new(1.0, 0.0);
389 state
390 }
391}
392
393#[derive(Debug, Clone, Copy)]
395pub enum StabilizerGate {
396 H(usize),
397 S(usize),
398 X(usize),
399 Y(usize),
400 Z(usize),
401 CNOT(usize, usize),
402}
403
404pub fn is_clifford_circuit<const N: usize>(circuit: &Circuit<N>) -> bool {
406 circuit.gates().iter().all(|gate| {
409 matches!(
410 gate.name(),
411 "H" | "S" | "S†" | "CNOT" | "X" | "Y" | "Z" | "CZ" | "Phase" | "PhaseDagger"
412 )
413 })
414}
415
416fn gate_to_stabilizer(gate: &Arc<dyn GateOp + Send + Sync>) -> Option<StabilizerGate> {
418 let gate_name = gate.name();
419 let qubits = gate.qubits();
420
421 match gate_name {
422 "H" => {
423 if qubits.len() == 1 {
424 Some(StabilizerGate::H(qubits[0].0 as usize))
425 } else {
426 None
427 }
428 }
429 "S" | "Phase" => {
430 if qubits.len() == 1 {
431 Some(StabilizerGate::S(qubits[0].0 as usize))
432 } else {
433 None
434 }
435 }
436 "X" => {
437 if qubits.len() == 1 {
438 Some(StabilizerGate::X(qubits[0].0 as usize))
439 } else {
440 None
441 }
442 }
443 "Y" => {
444 if qubits.len() == 1 {
445 Some(StabilizerGate::Y(qubits[0].0 as usize))
446 } else {
447 None
448 }
449 }
450 "Z" => {
451 if qubits.len() == 1 {
452 Some(StabilizerGate::Z(qubits[0].0 as usize))
453 } else {
454 None
455 }
456 }
457 "CNOT" => {
458 if qubits.len() == 2 {
459 Some(StabilizerGate::CNOT(
460 qubits[0].0 as usize,
461 qubits[1].0 as usize,
462 ))
463 } else {
464 None
465 }
466 }
467 "CZ" => {
468 if qubits.len() == 2 {
469 None
473 } else {
474 None
475 }
476 }
477 _ => None,
478 }
479}
480
481impl Simulator for StabilizerSimulator {
483 fn run<const N: usize>(
484 &mut self,
485 circuit: &Circuit<N>,
486 ) -> crate::error::Result<SimulatorResult<N>> {
487 let mut sim = Self::new(N);
489
490 for gate in circuit.gates() {
492 if let Some(stab_gate) = gate_to_stabilizer(gate) {
493 let _ = sim.apply_gate(stab_gate);
495 }
496 }
497
498 let amplitudes = sim.get_statevector();
500
501 Ok(SimulatorResult::new(amplitudes))
502 }
503}
504
505pub struct CliffordCircuitBuilder {
507 gates: Vec<StabilizerGate>,
508 num_qubits: usize,
509}
510
511impl CliffordCircuitBuilder {
512 pub const fn new(num_qubits: usize) -> Self {
514 Self {
515 gates: Vec::new(),
516 num_qubits,
517 }
518 }
519
520 pub fn h(mut self, qubit: usize) -> Self {
522 self.gates.push(StabilizerGate::H(qubit));
523 self
524 }
525
526 pub fn s(mut self, qubit: usize) -> Self {
528 self.gates.push(StabilizerGate::S(qubit));
529 self
530 }
531
532 pub fn x(mut self, qubit: usize) -> Self {
534 self.gates.push(StabilizerGate::X(qubit));
535 self
536 }
537
538 pub fn y(mut self, qubit: usize) -> Self {
540 self.gates.push(StabilizerGate::Y(qubit));
541 self
542 }
543
544 pub fn z(mut self, qubit: usize) -> Self {
546 self.gates.push(StabilizerGate::Z(qubit));
547 self
548 }
549
550 pub fn cnot(mut self, control: usize, target: usize) -> Self {
552 self.gates.push(StabilizerGate::CNOT(control, target));
553 self
554 }
555
556 pub fn run(self) -> Result<StabilizerSimulator, QuantRS2Error> {
558 let mut sim = StabilizerSimulator::new(self.num_qubits);
559
560 for gate in self.gates {
561 sim.apply_gate(gate)?;
562 }
563
564 Ok(sim)
565 }
566}
567
568#[cfg(test)]
569mod tests {
570 use super::*;
571
572 #[test]
573 fn test_stabilizer_init() {
574 let sim = StabilizerSimulator::new(3);
575 let stabs = sim.get_stabilizers();
576
577 assert_eq!(stabs.len(), 3);
578 assert_eq!(stabs[0], "+ZII");
579 assert_eq!(stabs[1], "+IZI");
580 assert_eq!(stabs[2], "+IIZ");
581 }
582
583 #[test]
584 fn test_hadamard_gate() {
585 let mut sim = StabilizerSimulator::new(1);
586 sim.apply_gate(StabilizerGate::H(0)).unwrap();
587
588 let stabs = sim.get_stabilizers();
589 assert_eq!(stabs[0], "+X");
590 }
591
592 #[test]
593 fn test_bell_state() {
594 let mut sim = StabilizerSimulator::new(2);
595 sim.apply_gate(StabilizerGate::H(0)).unwrap();
596 sim.apply_gate(StabilizerGate::CNOT(0, 1)).unwrap();
597
598 let stabs = sim.get_stabilizers();
599 assert!(stabs.contains(&"+XX".to_string()));
600 assert!(stabs.contains(&"+ZZ".to_string()));
601 }
602
603 #[test]
604 fn test_ghz_state() {
605 let mut sim = StabilizerSimulator::new(3);
606 sim.apply_gate(StabilizerGate::H(0)).unwrap();
607 sim.apply_gate(StabilizerGate::CNOT(0, 1)).unwrap();
608 sim.apply_gate(StabilizerGate::CNOT(1, 2)).unwrap();
609
610 let stabs = sim.get_stabilizers();
611 assert!(stabs.contains(&"+XXX".to_string()));
612 assert!(stabs.contains(&"+ZZI".to_string()));
613 assert!(stabs.contains(&"+IZZ".to_string()));
614 }
615}