1use quantrs2_circuit::prelude::*;
6use quantrs2_core::prelude::*;
7use scirs2_core::ndarray::{Array2, ArrayView2};
8use scirs2_core::random::prelude::*;
9use scirs2_core::Complex64;
10
11use super::functions::{phase, StabilizerPhase};
12
13pub struct CliffordCircuitBuilder {
15 gates: Vec<StabilizerGate>,
16 num_qubits: usize,
17}
18impl CliffordCircuitBuilder {
19 #[must_use]
21 pub const fn new(num_qubits: usize) -> Self {
22 Self {
23 gates: Vec::new(),
24 num_qubits,
25 }
26 }
27 #[must_use]
29 pub fn h(mut self, qubit: usize) -> Self {
30 self.gates.push(StabilizerGate::H(qubit));
31 self
32 }
33 #[must_use]
35 pub fn s(mut self, qubit: usize) -> Self {
36 self.gates.push(StabilizerGate::S(qubit));
37 self
38 }
39 #[must_use]
41 pub fn s_dag(mut self, qubit: usize) -> Self {
42 self.gates.push(StabilizerGate::SDag(qubit));
43 self
44 }
45 #[must_use]
47 pub fn sqrt_x(mut self, qubit: usize) -> Self {
48 self.gates.push(StabilizerGate::SqrtX(qubit));
49 self
50 }
51 #[must_use]
53 pub fn sqrt_x_dag(mut self, qubit: usize) -> Self {
54 self.gates.push(StabilizerGate::SqrtXDag(qubit));
55 self
56 }
57 #[must_use]
59 pub fn sqrt_y(mut self, qubit: usize) -> Self {
60 self.gates.push(StabilizerGate::SqrtY(qubit));
61 self
62 }
63 #[must_use]
65 pub fn sqrt_y_dag(mut self, qubit: usize) -> Self {
66 self.gates.push(StabilizerGate::SqrtYDag(qubit));
67 self
68 }
69 #[must_use]
71 pub fn x(mut self, qubit: usize) -> Self {
72 self.gates.push(StabilizerGate::X(qubit));
73 self
74 }
75 #[must_use]
77 pub fn y(mut self, qubit: usize) -> Self {
78 self.gates.push(StabilizerGate::Y(qubit));
79 self
80 }
81 #[must_use]
83 pub fn z(mut self, qubit: usize) -> Self {
84 self.gates.push(StabilizerGate::Z(qubit));
85 self
86 }
87 #[must_use]
89 pub fn cnot(mut self, control: usize, target: usize) -> Self {
90 self.gates.push(StabilizerGate::CNOT(control, target));
91 self
92 }
93 #[must_use]
95 pub fn cz(mut self, control: usize, target: usize) -> Self {
96 self.gates.push(StabilizerGate::CZ(control, target));
97 self
98 }
99 #[must_use]
101 pub fn cy(mut self, control: usize, target: usize) -> Self {
102 self.gates.push(StabilizerGate::CY(control, target));
103 self
104 }
105 #[must_use]
107 pub fn swap(mut self, qubit1: usize, qubit2: usize) -> Self {
108 self.gates.push(StabilizerGate::SWAP(qubit1, qubit2));
109 self
110 }
111 pub fn run(self) -> Result<StabilizerSimulator, QuantRS2Error> {
113 let mut sim = StabilizerSimulator::new(self.num_qubits);
114 for gate in self.gates {
115 sim.apply_gate(gate)?;
116 }
117 Ok(sim)
118 }
119}
120#[derive(Debug, Clone)]
131pub struct StabilizerTableau {
132 num_qubits: usize,
134 x_matrix: Array2<bool>,
136 z_matrix: Array2<bool>,
138 phase: Vec<StabilizerPhase>,
140 destab_x: Array2<bool>,
142 destab_z: Array2<bool>,
144 destab_phase: Vec<StabilizerPhase>,
146 stim_format: bool,
148}
149impl StabilizerTableau {
150 #[must_use]
152 pub fn new(num_qubits: usize) -> Self {
153 Self::with_format(num_qubits, false)
154 }
155 #[must_use]
161 pub fn with_format(num_qubits: usize, stim_format: bool) -> Self {
162 let mut x_matrix = Array2::from_elem((num_qubits, num_qubits), false);
163 let mut z_matrix = Array2::from_elem((num_qubits, num_qubits), false);
164 let mut destab_x = Array2::from_elem((num_qubits, num_qubits), false);
165 let mut destab_z = Array2::from_elem((num_qubits, num_qubits), false);
166 for i in 0..num_qubits {
167 z_matrix[[i, i]] = true;
168 destab_x[[i, i]] = true;
169 }
170 Self {
171 num_qubits,
172 x_matrix,
173 z_matrix,
174 phase: vec![phase::PLUS_ONE; num_qubits],
175 destab_x,
176 destab_z,
177 destab_phase: vec![phase::PLUS_ONE; num_qubits],
178 stim_format,
179 }
180 }
181 pub fn set_stim_format(&mut self, stim_format: bool) {
183 self.stim_format = stim_format;
184 }
185 #[must_use]
187 pub const fn is_stim_format(&self) -> bool {
188 self.stim_format
189 }
190 #[inline]
192 pub(crate) fn negate_phase(p: StabilizerPhase) -> StabilizerPhase {
193 (p + 2) & 3
194 }
195 #[inline]
197 pub(crate) fn multiply_by_i(p: StabilizerPhase) -> StabilizerPhase {
198 (p + 1) & 3
199 }
200 #[inline]
202 pub(crate) fn multiply_by_minus_i(p: StabilizerPhase) -> StabilizerPhase {
203 (p + 3) & 3
204 }
205 #[inline]
207 fn add_phases(p1: StabilizerPhase, p2: StabilizerPhase) -> StabilizerPhase {
208 (p1 + p2) & 3
209 }
210 #[inline]
214 fn rowsum_phase(x1: bool, z1: bool, x2: bool, z2: bool) -> StabilizerPhase {
215 match (x1, z1, x2, z2) {
216 (false, false, _, _) | (_, _, false, false) => 0,
217 (true, false, false, true) => 1,
218 (false, true, true, false) => 3,
219 (true, false, true, true) => 1,
220 (true, true, true, false) => 3,
221 (true, true, false, true) => 1,
222 (false, true, true, true) => 3,
223 (true, false, true, false) => 0,
224 (false, true, false, true) => 0,
225 (true, true, true, true) => 0,
226 }
227 }
228 fn compute_multiplication_phase(
231 &self,
232 result_x: &[bool],
233 result_z: &[bool],
234 row_idx: usize,
235 ) -> StabilizerPhase {
236 let mut total_phase: StabilizerPhase = 0;
237 for j in 0..self.num_qubits {
238 let phase_contrib = Self::rowsum_phase(
239 result_x[j],
240 result_z[j],
241 self.x_matrix[[row_idx, j]],
242 self.z_matrix[[row_idx, j]],
243 );
244 total_phase = Self::add_phases(total_phase, phase_contrib);
245 }
246 total_phase
247 }
248 pub fn apply_h(&mut self, qubit: usize) -> Result<(), QuantRS2Error> {
253 if qubit >= self.num_qubits {
254 return Err(QuantRS2Error::InvalidQubitId(qubit as u32));
255 }
256 for i in 0..self.num_qubits {
257 let x_val = self.x_matrix[[i, qubit]];
258 let z_val = self.z_matrix[[i, qubit]];
259 if x_val && z_val {
260 self.phase[i] = Self::negate_phase(self.phase[i]);
261 }
262 self.x_matrix[[i, qubit]] = z_val;
263 self.z_matrix[[i, qubit]] = x_val;
264 let dx_val = self.destab_x[[i, qubit]];
265 let dz_val = self.destab_z[[i, qubit]];
266 if dx_val && dz_val {
267 self.destab_phase[i] = Self::negate_phase(self.destab_phase[i]);
268 }
269 self.destab_x[[i, qubit]] = dz_val;
270 self.destab_z[[i, qubit]] = dx_val;
271 }
272 Ok(())
273 }
274 pub fn apply_s(&mut self, qubit: usize) -> Result<(), QuantRS2Error> {
284 if qubit >= self.num_qubits {
285 return Err(QuantRS2Error::InvalidQubitId(qubit as u32));
286 }
287 for i in 0..self.num_qubits {
288 let x_val = self.x_matrix[[i, qubit]];
289 let z_val = self.z_matrix[[i, qubit]];
290 if x_val {
291 if !z_val {
292 self.z_matrix[[i, qubit]] = true;
293 } else {
294 self.z_matrix[[i, qubit]] = false;
295 self.phase[i] = Self::negate_phase(self.phase[i]);
296 }
297 }
298 let dx_val = self.destab_x[[i, qubit]];
299 let dz_val = self.destab_z[[i, qubit]];
300 if dx_val {
301 if !dz_val {
302 self.destab_z[[i, qubit]] = true;
303 } else {
304 self.destab_z[[i, qubit]] = false;
305 self.destab_phase[i] = Self::negate_phase(self.destab_phase[i]);
306 }
307 }
308 }
309 Ok(())
310 }
311 pub fn apply_cnot(&mut self, control: usize, target: usize) -> Result<(), QuantRS2Error> {
313 if control >= self.num_qubits || target >= self.num_qubits {
314 return Err(QuantRS2Error::InvalidQubitId(control.max(target) as u32));
315 }
316 if control == target {
317 return Err(QuantRS2Error::InvalidInput(
318 "CNOT control and target must be different".to_string(),
319 ));
320 }
321 for i in 0..self.num_qubits {
322 if self.x_matrix[[i, control]] {
323 self.x_matrix[[i, target]] ^= true;
324 }
325 if self.z_matrix[[i, target]] {
326 self.z_matrix[[i, control]] ^= true;
327 }
328 if self.destab_x[[i, control]] {
329 self.destab_x[[i, target]] ^= true;
330 }
331 if self.destab_z[[i, target]] {
332 self.destab_z[[i, control]] ^= true;
333 }
334 }
335 Ok(())
336 }
337 pub fn apply_x(&mut self, qubit: usize) -> Result<(), QuantRS2Error> {
342 if qubit >= self.num_qubits {
343 return Err(QuantRS2Error::InvalidQubitId(qubit as u32));
344 }
345 for i in 0..self.num_qubits {
346 if self.z_matrix[[i, qubit]] {
347 self.phase[i] = Self::negate_phase(self.phase[i]);
348 }
349 if self.destab_z[[i, qubit]] {
350 self.destab_phase[i] = Self::negate_phase(self.destab_phase[i]);
351 }
352 }
353 Ok(())
354 }
355 pub fn apply_y(&mut self, qubit: usize) -> Result<(), QuantRS2Error> {
360 if qubit >= self.num_qubits {
361 return Err(QuantRS2Error::InvalidQubitId(qubit as u32));
362 }
363 for i in 0..self.num_qubits {
364 let has_x = self.x_matrix[[i, qubit]];
365 let has_z = self.z_matrix[[i, qubit]];
366 if has_x != has_z {
367 self.phase[i] = Self::negate_phase(self.phase[i]);
368 }
369 let has_dx = self.destab_x[[i, qubit]];
370 let has_dz = self.destab_z[[i, qubit]];
371 if has_dx != has_dz {
372 self.destab_phase[i] = Self::negate_phase(self.destab_phase[i]);
373 }
374 }
375 Ok(())
376 }
377 pub fn apply_z(&mut self, qubit: usize) -> Result<(), QuantRS2Error> {
382 if qubit >= self.num_qubits {
383 return Err(QuantRS2Error::InvalidQubitId(qubit as u32));
384 }
385 for i in 0..self.num_qubits {
386 if self.x_matrix[[i, qubit]] {
387 self.phase[i] = Self::negate_phase(self.phase[i]);
388 }
389 if self.destab_x[[i, qubit]] {
390 self.destab_phase[i] = Self::negate_phase(self.destab_phase[i]);
391 }
392 }
393 Ok(())
394 }
395 pub fn apply_s_dag(&mut self, qubit: usize) -> Result<(), QuantRS2Error> {
402 if qubit >= self.num_qubits {
403 return Err(QuantRS2Error::InvalidQubitId(qubit as u32));
404 }
405 for i in 0..self.num_qubits {
406 let x_val = self.x_matrix[[i, qubit]];
407 let z_val = self.z_matrix[[i, qubit]];
408 if x_val {
409 if !z_val {
410 self.z_matrix[[i, qubit]] = true;
411 self.phase[i] = Self::negate_phase(self.phase[i]);
412 } else {
413 self.z_matrix[[i, qubit]] = false;
414 }
415 }
416 let dx_val = self.destab_x[[i, qubit]];
417 let dz_val = self.destab_z[[i, qubit]];
418 if dx_val {
419 if !dz_val {
420 self.destab_z[[i, qubit]] = true;
421 self.destab_phase[i] = Self::negate_phase(self.destab_phase[i]);
422 } else {
423 self.destab_z[[i, qubit]] = false;
424 }
425 }
426 }
427 Ok(())
428 }
429 pub fn apply_sqrt_x(&mut self, qubit: usize) -> Result<(), QuantRS2Error> {
436 if qubit >= self.num_qubits {
437 return Err(QuantRS2Error::InvalidQubitId(qubit as u32));
438 }
439 for i in 0..self.num_qubits {
440 let x_val = self.x_matrix[[i, qubit]];
441 let z_val = self.z_matrix[[i, qubit]];
442 match (x_val, z_val) {
443 (false, false) => {}
444 (true, false) => {}
445 (false, true) => {
446 self.x_matrix[[i, qubit]] = true;
447 }
448 (true, true) => {
449 self.x_matrix[[i, qubit]] = false;
450 self.phase[i] = Self::negate_phase(self.phase[i]);
451 }
452 }
453 let dx_val = self.destab_x[[i, qubit]];
454 let dz_val = self.destab_z[[i, qubit]];
455 match (dx_val, dz_val) {
456 (false, false) => {}
457 (true, false) => {}
458 (false, true) => {
459 self.destab_x[[i, qubit]] = true;
460 }
461 (true, true) => {
462 self.destab_x[[i, qubit]] = false;
463 self.destab_phase[i] = Self::negate_phase(self.destab_phase[i]);
464 }
465 }
466 }
467 Ok(())
468 }
469 pub fn apply_sqrt_x_dag(&mut self, qubit: usize) -> Result<(), QuantRS2Error> {
476 if qubit >= self.num_qubits {
477 return Err(QuantRS2Error::InvalidQubitId(qubit as u32));
478 }
479 for i in 0..self.num_qubits {
480 let x_val = self.x_matrix[[i, qubit]];
481 let z_val = self.z_matrix[[i, qubit]];
482 match (x_val, z_val) {
483 (false, false) => {}
484 (true, false) => {}
485 (false, true) => {
486 self.x_matrix[[i, qubit]] = true;
487 self.phase[i] = Self::negate_phase(self.phase[i]);
488 }
489 (true, true) => {
490 self.x_matrix[[i, qubit]] = false;
491 }
492 }
493 let dx_val = self.destab_x[[i, qubit]];
494 let dz_val = self.destab_z[[i, qubit]];
495 match (dx_val, dz_val) {
496 (false, false) => {}
497 (true, false) => {}
498 (false, true) => {
499 self.destab_x[[i, qubit]] = true;
500 self.destab_phase[i] = Self::negate_phase(self.destab_phase[i]);
501 }
502 (true, true) => {
503 self.destab_x[[i, qubit]] = false;
504 }
505 }
506 }
507 Ok(())
508 }
509 pub fn apply_sqrt_y(&mut self, qubit: usize) -> Result<(), QuantRS2Error> {
516 if qubit >= self.num_qubits {
517 return Err(QuantRS2Error::InvalidQubitId(qubit as u32));
518 }
519 for i in 0..self.num_qubits {
520 let x_val = self.x_matrix[[i, qubit]];
521 let z_val = self.z_matrix[[i, qubit]];
522 match (x_val, z_val) {
523 (false, false) => {}
524 (true, false) => {
525 self.x_matrix[[i, qubit]] = false;
526 self.z_matrix[[i, qubit]] = true;
527 }
528 (false, true) => {
529 self.x_matrix[[i, qubit]] = true;
530 self.z_matrix[[i, qubit]] = false;
531 self.phase[i] = Self::negate_phase(self.phase[i]);
532 }
533 (true, true) => {}
534 }
535 let dx_val = self.destab_x[[i, qubit]];
536 let dz_val = self.destab_z[[i, qubit]];
537 match (dx_val, dz_val) {
538 (false, false) => {}
539 (true, false) => {
540 self.destab_x[[i, qubit]] = false;
541 self.destab_z[[i, qubit]] = true;
542 }
543 (false, true) => {
544 self.destab_x[[i, qubit]] = true;
545 self.destab_z[[i, qubit]] = false;
546 self.destab_phase[i] = Self::negate_phase(self.destab_phase[i]);
547 }
548 (true, true) => {}
549 }
550 }
551 Ok(())
552 }
553 pub fn apply_sqrt_y_dag(&mut self, qubit: usize) -> Result<(), QuantRS2Error> {
560 if qubit >= self.num_qubits {
561 return Err(QuantRS2Error::InvalidQubitId(qubit as u32));
562 }
563 for i in 0..self.num_qubits {
564 let x_val = self.x_matrix[[i, qubit]];
565 let z_val = self.z_matrix[[i, qubit]];
566 match (x_val, z_val) {
567 (false, false) => {}
568 (true, false) => {
569 self.x_matrix[[i, qubit]] = false;
570 self.z_matrix[[i, qubit]] = true;
571 self.phase[i] = Self::negate_phase(self.phase[i]);
572 }
573 (false, true) => {
574 self.x_matrix[[i, qubit]] = true;
575 self.z_matrix[[i, qubit]] = false;
576 }
577 (true, true) => {}
578 }
579 let dx_val = self.destab_x[[i, qubit]];
580 let dz_val = self.destab_z[[i, qubit]];
581 match (dx_val, dz_val) {
582 (false, false) => {}
583 (true, false) => {
584 self.destab_x[[i, qubit]] = false;
585 self.destab_z[[i, qubit]] = true;
586 self.destab_phase[i] = Self::negate_phase(self.destab_phase[i]);
587 }
588 (false, true) => {
589 self.destab_x[[i, qubit]] = true;
590 self.destab_z[[i, qubit]] = false;
591 }
592 (true, true) => {}
593 }
594 }
595 Ok(())
596 }
597 pub fn apply_cz(&mut self, control: usize, target: usize) -> Result<(), QuantRS2Error> {
602 if control >= self.num_qubits {
603 return Err(QuantRS2Error::InvalidQubitId(control as u32));
604 }
605 if target >= self.num_qubits {
606 return Err(QuantRS2Error::InvalidQubitId(target as u32));
607 }
608 for i in 0..self.num_qubits {
609 if self.x_matrix[[i, control]] && self.x_matrix[[i, target]] {
610 self.phase[i] = Self::negate_phase(self.phase[i]);
611 }
612 if self.x_matrix[[i, control]] {
613 self.z_matrix[[i, target]] = !self.z_matrix[[i, target]];
614 }
615 if self.x_matrix[[i, target]] {
616 self.z_matrix[[i, control]] = !self.z_matrix[[i, control]];
617 }
618 if self.destab_x[[i, control]] && self.destab_x[[i, target]] {
619 self.destab_phase[i] = Self::negate_phase(self.destab_phase[i]);
620 }
621 if self.destab_x[[i, control]] {
622 self.destab_z[[i, target]] = !self.destab_z[[i, target]];
623 }
624 if self.destab_x[[i, target]] {
625 self.destab_z[[i, control]] = !self.destab_z[[i, control]];
626 }
627 }
628 Ok(())
629 }
630 pub fn apply_cy(&mut self, control: usize, target: usize) -> Result<(), QuantRS2Error> {
632 if control >= self.num_qubits {
633 return Err(QuantRS2Error::InvalidQubitId(control as u32));
634 }
635 if target >= self.num_qubits {
636 return Err(QuantRS2Error::InvalidQubitId(target as u32));
637 }
638 self.apply_s_dag(target)?;
639 self.apply_cnot(control, target)?;
640 self.apply_s(target)?;
641 Ok(())
642 }
643 pub fn apply_swap(&mut self, qubit1: usize, qubit2: usize) -> Result<(), QuantRS2Error> {
645 if qubit1 >= self.num_qubits {
646 return Err(QuantRS2Error::InvalidQubitId(qubit1 as u32));
647 }
648 if qubit2 >= self.num_qubits {
649 return Err(QuantRS2Error::InvalidQubitId(qubit2 as u32));
650 }
651 self.apply_cnot(qubit1, qubit2)?;
652 self.apply_cnot(qubit2, qubit1)?;
653 self.apply_cnot(qubit1, qubit2)?;
654 Ok(())
655 }
656 pub fn measure(&mut self, qubit: usize) -> Result<bool, QuantRS2Error> {
663 if qubit >= self.num_qubits {
664 return Err(QuantRS2Error::InvalidQubitId(qubit as u32));
665 }
666 let mut anticommuting_row = None;
667 for i in 0..self.num_qubits {
668 if self.x_matrix[[i, qubit]] {
669 anticommuting_row = Some(i);
670 break;
671 }
672 }
673 if let Some(p) = anticommuting_row {
674 for j in 0..self.num_qubits {
675 self.x_matrix[[p, j]] = false;
676 self.z_matrix[[p, j]] = j == qubit;
677 }
678 let mut rng = thread_rng();
679 let outcome = rng.random_bool(0.5);
680 self.phase[p] = if outcome {
681 phase::MINUS_ONE
682 } else {
683 phase::PLUS_ONE
684 };
685 for i in 0..self.num_qubits {
686 if i != p && self.x_matrix[[i, qubit]] {
687 let mut total_phase_contrib: StabilizerPhase = 0;
688 for j in 0..self.num_qubits {
689 let phase_contrib = Self::rowsum_phase(
690 self.x_matrix[[i, j]],
691 self.z_matrix[[i, j]],
692 self.x_matrix[[p, j]],
693 self.z_matrix[[p, j]],
694 );
695 total_phase_contrib = Self::add_phases(total_phase_contrib, phase_contrib);
696 self.x_matrix[[i, j]] ^= self.x_matrix[[p, j]];
697 self.z_matrix[[i, j]] ^= self.z_matrix[[p, j]];
698 }
699 self.phase[i] = Self::add_phases(
700 Self::add_phases(self.phase[i], self.phase[p]),
701 total_phase_contrib,
702 );
703 }
704 }
705 Ok(outcome)
706 } else {
707 let mut pivot_row = None;
708 for i in 0..self.num_qubits {
709 if self.z_matrix[[i, qubit]] && !self.x_matrix[[i, qubit]] {
710 pivot_row = Some(i);
711 break;
712 }
713 }
714 let Some(pivot) = pivot_row else {
715 return Ok(false);
716 };
717 let mut result_x = vec![false; self.num_qubits];
718 let mut result_z = vec![false; self.num_qubits];
719 let mut result_phase = self.phase[pivot];
720 for j in 0..self.num_qubits {
721 result_x[j] = self.x_matrix[[pivot, j]];
722 result_z[j] = self.z_matrix[[pivot, j]];
723 }
724 for other_qubit in 0..self.num_qubits {
725 if other_qubit == qubit {
726 continue;
727 }
728 if result_z[other_qubit] && !result_x[other_qubit] {
729 for i in 0..self.num_qubits {
730 if i == pivot {
731 continue;
732 }
733 if self.z_matrix[[i, other_qubit]] && !self.x_matrix[[i, other_qubit]] {
734 let phase_contrib =
735 self.compute_multiplication_phase(&result_x, &result_z, i);
736 result_phase = Self::add_phases(result_phase, self.phase[i]);
737 result_phase = Self::add_phases(result_phase, phase_contrib);
738 for j in 0..self.num_qubits {
739 result_x[j] ^= self.x_matrix[[i, j]];
740 result_z[j] ^= self.z_matrix[[i, j]];
741 }
742 break;
743 }
744 }
745 }
746 }
747 let outcome = result_phase >= phase::MINUS_ONE;
748 Ok(outcome)
749 }
750 }
751 pub fn measure_x(&mut self, qubit: usize) -> Result<bool, QuantRS2Error> {
755 self.apply_h(qubit)?;
756 let outcome = self.measure(qubit)?;
757 self.apply_h(qubit)?;
758 Ok(outcome)
759 }
760 pub fn measure_y(&mut self, qubit: usize) -> Result<bool, QuantRS2Error> {
764 self.apply_s_dag(qubit)?;
765 self.apply_h(qubit)?;
766 let outcome = self.measure(qubit)?;
767 self.apply_h(qubit)?;
768 self.apply_s(qubit)?;
769 Ok(outcome)
770 }
771 pub fn reset(&mut self, qubit: usize) -> Result<(), QuantRS2Error> {
775 let outcome = self.measure(qubit)?;
776 if outcome {
777 self.apply_x(qubit)?;
778 }
779 Ok(())
780 }
781 #[must_use]
793 pub fn get_stabilizers(&self) -> Vec<String> {
794 let mut stabilizers = Vec::new();
795 let identity_char = if self.stim_format { '_' } else { 'I' };
796 for i in 0..self.num_qubits {
797 let mut stab = String::new();
798 match self.phase[i] & 3 {
799 phase::PLUS_ONE => stab.push('+'),
800 phase::PLUS_I => stab.push_str("+i"),
801 phase::MINUS_ONE => stab.push('-'),
802 phase::MINUS_I => stab.push_str("-i"),
803 _ => unreachable!(),
804 }
805 for j in 0..self.num_qubits {
806 let has_x = self.x_matrix[[i, j]];
807 let has_z = self.z_matrix[[i, j]];
808 match (has_x, has_z) {
809 (false, false) => stab.push(identity_char),
810 (true, false) => stab.push('X'),
811 (false, true) => stab.push('Z'),
812 (true, true) => stab.push('Y'),
813 }
814 }
815 stabilizers.push(stab);
816 }
817 stabilizers
818 }
819 #[must_use]
823 pub fn get_destabilizers(&self) -> Vec<String> {
824 let mut destabilizers = Vec::new();
825 let identity_char = if self.stim_format { '_' } else { 'I' };
826 for i in 0..self.num_qubits {
827 let mut destab = String::new();
828 match self.destab_phase[i] & 3 {
829 phase::PLUS_ONE => destab.push('+'),
830 phase::PLUS_I => destab.push_str("+i"),
831 phase::MINUS_ONE => destab.push('-'),
832 phase::MINUS_I => destab.push_str("-i"),
833 _ => unreachable!(),
834 }
835 for j in 0..self.num_qubits {
836 let has_x = self.destab_x[[i, j]];
837 let has_z = self.destab_z[[i, j]];
838 match (has_x, has_z) {
839 (false, false) => destab.push(identity_char),
840 (true, false) => destab.push('X'),
841 (false, true) => destab.push('Z'),
842 (true, true) => destab.push('Y'),
843 }
844 }
845 destabilizers.push(destab);
846 }
847 destabilizers
848 }
849}
850#[derive(Debug, Clone, Copy)]
852pub enum StabilizerGate {
853 H(usize),
854 S(usize),
855 SDag(usize),
856 SqrtX(usize),
857 SqrtXDag(usize),
858 SqrtY(usize),
859 SqrtYDag(usize),
860 X(usize),
861 Y(usize),
862 Z(usize),
863 CNOT(usize, usize),
864 CZ(usize, usize),
865 CY(usize, usize),
866 SWAP(usize, usize),
867}
868#[derive(Debug, Clone)]
870pub struct StabilizerSimulator {
871 pub tableau: StabilizerTableau,
873 measurement_record: Vec<(usize, bool)>,
874}
875impl StabilizerSimulator {
876 #[must_use]
878 pub fn new(num_qubits: usize) -> Self {
879 Self {
880 tableau: StabilizerTableau::new(num_qubits),
881 measurement_record: Vec::new(),
882 }
883 }
884 pub fn apply_gate(&mut self, gate: StabilizerGate) -> Result<(), QuantRS2Error> {
886 match gate {
887 StabilizerGate::H(q) => self.tableau.apply_h(q),
888 StabilizerGate::S(q) => self.tableau.apply_s(q),
889 StabilizerGate::SDag(q) => self.tableau.apply_s_dag(q),
890 StabilizerGate::SqrtX(q) => self.tableau.apply_sqrt_x(q),
891 StabilizerGate::SqrtXDag(q) => self.tableau.apply_sqrt_x_dag(q),
892 StabilizerGate::SqrtY(q) => self.tableau.apply_sqrt_y(q),
893 StabilizerGate::SqrtYDag(q) => self.tableau.apply_sqrt_y_dag(q),
894 StabilizerGate::X(q) => self.tableau.apply_x(q),
895 StabilizerGate::Y(q) => self.tableau.apply_y(q),
896 StabilizerGate::Z(q) => self.tableau.apply_z(q),
897 StabilizerGate::CNOT(c, t) => self.tableau.apply_cnot(c, t),
898 StabilizerGate::CZ(c, t) => self.tableau.apply_cz(c, t),
899 StabilizerGate::CY(c, t) => self.tableau.apply_cy(c, t),
900 StabilizerGate::SWAP(q1, q2) => self.tableau.apply_swap(q1, q2),
901 }
902 }
903 pub fn measure(&mut self, qubit: usize) -> Result<bool, QuantRS2Error> {
905 let outcome = self.tableau.measure(qubit)?;
906 self.measurement_record.push((qubit, outcome));
907 Ok(outcome)
908 }
909 #[must_use]
911 pub fn get_stabilizers(&self) -> Vec<String> {
912 self.tableau.get_stabilizers()
913 }
914 #[must_use]
916 pub fn get_measurements(&self) -> &[(usize, bool)] {
917 &self.measurement_record
918 }
919 pub fn reset(&mut self) {
921 let num_qubits = self.tableau.num_qubits;
922 self.tableau = StabilizerTableau::new(num_qubits);
923 self.measurement_record.clear();
924 }
925 #[must_use]
927 pub const fn num_qubits(&self) -> usize {
928 self.tableau.num_qubits
929 }
930 #[must_use]
933 pub fn get_statevector(&self) -> Vec<Complex64> {
934 let n = self.tableau.num_qubits;
935 let dim = 1 << n;
936 let mut state = vec![Complex64::new(0.0, 0.0); dim];
937 state[0] = Complex64::new(1.0, 0.0);
938 state
939 }
940}