1use crate::error::{Result, SimulatorError};
20use crate::stabilizer::{StabilizerSimulator, StabilizerTableau};
21use crate::stim_parser::{
22 MeasurementBasis, PauliTarget, PauliType, SingleQubitGateType, StimCircuit, StimInstruction,
23 TwoQubitGateType,
24};
25use scirs2_core::random::prelude::*;
26
27#[derive(Debug, Clone)]
29pub struct DetectorRecord {
30 pub index: usize,
32 pub coordinates: Vec<f64>,
34 pub record_targets: Vec<i32>,
36 pub expected_parity: bool,
38}
39
40#[derive(Debug, Clone)]
42pub struct ObservableRecord {
43 pub index: usize,
45 pub record_targets: Vec<i32>,
47}
48
49#[derive(Debug, Clone)]
51pub struct StimExecutor {
52 simulator: StabilizerSimulator,
54 measurement_record: Vec<bool>,
56 detectors: Vec<DetectorRecord>,
58 observables: Vec<ObservableRecord>,
60 last_error_triggered: bool,
62 num_qubits: usize,
64}
65
66impl StimExecutor {
67 #[must_use]
69 pub fn new(num_qubits: usize) -> Self {
70 Self {
71 simulator: StabilizerSimulator::new(num_qubits),
72 measurement_record: Vec::new(),
73 detectors: Vec::new(),
74 observables: Vec::new(),
75 last_error_triggered: false,
76 num_qubits,
77 }
78 }
79
80 #[must_use]
82 pub fn from_circuit(circuit: &StimCircuit) -> Self {
83 Self::new(circuit.num_qubits)
84 }
85
86 pub fn execute(&mut self, circuit: &StimCircuit) -> Result<ExecutionResult> {
88 self.measurement_record.clear();
90 self.detectors.clear();
91 self.observables.clear();
92 self.last_error_triggered = false;
93
94 for instruction in &circuit.instructions {
96 self.execute_instruction(instruction)?;
97 }
98
99 let detector_values = self.compute_detector_values();
101 let observable_values = self.compute_observable_values();
102
103 Ok(ExecutionResult {
104 measurement_record: self.measurement_record.clone(),
105 detector_values,
106 observable_values,
107 num_measurements: self.measurement_record.len(),
108 num_detectors: self.detectors.len(),
109 num_observables: self.observables.len(),
110 })
111 }
112
113 fn execute_instruction(&mut self, instruction: &StimInstruction) -> Result<()> {
115 match instruction {
116 StimInstruction::SingleQubitGate { gate_type, qubit } => {
118 self.execute_single_qubit_gate(*gate_type, *qubit)?;
119 }
120 StimInstruction::TwoQubitGate {
121 gate_type,
122 control,
123 target,
124 } => {
125 self.execute_two_qubit_gate(*gate_type, *control, *target)?;
126 }
127
128 StimInstruction::Measure { basis, qubits } => {
130 self.execute_measurement(*basis, qubits)?;
131 }
132
133 StimInstruction::Reset { qubits } => {
135 self.execute_reset(qubits)?;
136 }
137
138 StimInstruction::MeasureReset { basis, qubits } => {
140 self.execute_measure_reset(*basis, qubits)?;
141 }
142
143 StimInstruction::Detector {
145 coordinates,
146 record_targets,
147 } => {
148 self.process_detector(coordinates, record_targets)?;
149 }
150 StimInstruction::ObservableInclude {
151 observable_index,
152 record_targets,
153 } => {
154 self.process_observable(*observable_index, record_targets)?;
155 }
156
157 StimInstruction::XError {
159 probability,
160 qubits,
161 } => {
162 self.execute_x_error(*probability, qubits)?;
163 }
164 StimInstruction::YError {
165 probability,
166 qubits,
167 } => {
168 self.execute_y_error(*probability, qubits)?;
169 }
170 StimInstruction::ZError {
171 probability,
172 qubits,
173 } => {
174 self.execute_z_error(*probability, qubits)?;
175 }
176 StimInstruction::Depolarize1 {
177 probability,
178 qubits,
179 } => {
180 self.execute_depolarize1(*probability, qubits)?;
181 }
182 StimInstruction::Depolarize2 {
183 probability,
184 qubit_pairs,
185 } => {
186 self.execute_depolarize2(*probability, qubit_pairs)?;
187 }
188 StimInstruction::CorrelatedError {
189 probability,
190 targets,
191 } => {
192 self.execute_correlated_error(*probability, targets)?;
193 }
194 StimInstruction::ElseCorrelatedError {
195 probability,
196 targets,
197 } => {
198 self.execute_else_correlated_error(*probability, targets)?;
199 }
200 StimInstruction::PauliChannel1 { px, py, pz, qubits } => {
201 self.execute_pauli_channel_1(*px, *py, *pz, qubits)?;
202 }
203 StimInstruction::PauliChannel2 {
204 probabilities,
205 qubit_pairs,
206 } => {
207 self.execute_pauli_channel_2(probabilities, qubit_pairs)?;
208 }
209
210 StimInstruction::Comment(_)
212 | StimInstruction::Tick
213 | StimInstruction::ShiftCoords { .. }
214 | StimInstruction::QubitCoords { .. } => {}
215
216 StimInstruction::Repeat {
218 count,
219 instructions,
220 } => {
221 for _ in 0..*count {
222 for inst in instructions {
223 self.execute_instruction(inst)?;
224 }
225 }
226 }
227 }
228
229 Ok(())
230 }
231
232 fn execute_single_qubit_gate(
234 &mut self,
235 gate_type: SingleQubitGateType,
236 qubit: usize,
237 ) -> Result<()> {
238 let gate = gate_type.to_stabilizer_gate(qubit);
239 self.simulator.apply_gate(gate).map_err(|e| {
240 SimulatorError::InvalidOperation(format!("Gate execution failed: {:?}", e))
241 })
242 }
243
244 fn execute_two_qubit_gate(
246 &mut self,
247 gate_type: TwoQubitGateType,
248 control: usize,
249 target: usize,
250 ) -> Result<()> {
251 let gate = gate_type.to_stabilizer_gate(control, target);
252 self.simulator.apply_gate(gate).map_err(|e| {
253 SimulatorError::InvalidOperation(format!("Gate execution failed: {:?}", e))
254 })
255 }
256
257 fn execute_measurement(&mut self, basis: MeasurementBasis, qubits: &[usize]) -> Result<()> {
259 for &qubit in qubits {
260 let outcome = match basis {
261 MeasurementBasis::Z => self.simulator.measure(qubit),
262 MeasurementBasis::X => self.simulator.tableau.measure_x(qubit),
263 MeasurementBasis::Y => self.simulator.tableau.measure_y(qubit),
264 }
265 .map_err(|e| {
266 SimulatorError::InvalidOperation(format!("Measurement failed: {:?}", e))
267 })?;
268
269 self.measurement_record.push(outcome);
270 }
271 Ok(())
272 }
273
274 fn execute_reset(&mut self, qubits: &[usize]) -> Result<()> {
276 for &qubit in qubits {
277 self.simulator
278 .tableau
279 .reset(qubit)
280 .map_err(|e| SimulatorError::InvalidOperation(format!("Reset failed: {:?}", e)))?;
281 }
282 Ok(())
283 }
284
285 fn execute_measure_reset(&mut self, basis: MeasurementBasis, qubits: &[usize]) -> Result<()> {
287 self.execute_measurement(basis, qubits)?;
288 self.execute_reset(qubits)
289 }
290
291 fn process_detector(&mut self, coordinates: &[f64], record_targets: &[i32]) -> Result<()> {
293 let detector = DetectorRecord {
294 index: self.detectors.len(),
295 coordinates: coordinates.to_vec(),
296 record_targets: record_targets.to_vec(),
297 expected_parity: false, };
299 self.detectors.push(detector);
300 Ok(())
301 }
302
303 fn process_observable(
305 &mut self,
306 observable_index: usize,
307 record_targets: &[i32],
308 ) -> Result<()> {
309 while self.observables.len() <= observable_index {
311 self.observables.push(ObservableRecord {
312 index: self.observables.len(),
313 record_targets: Vec::new(),
314 });
315 }
316
317 self.observables[observable_index]
319 .record_targets
320 .extend_from_slice(record_targets);
321
322 Ok(())
323 }
324
325 pub fn compute_detector_values(&self) -> Vec<bool> {
327 self.detectors
328 .iter()
329 .map(|detector| {
330 let parity = self.compute_record_parity(&detector.record_targets);
331 parity != detector.expected_parity
333 })
334 .collect()
335 }
336
337 pub fn compute_observable_values(&self) -> Vec<bool> {
339 self.observables
340 .iter()
341 .map(|observable| self.compute_record_parity(&observable.record_targets))
342 .collect()
343 }
344
345 fn compute_record_parity(&self, record_targets: &[i32]) -> bool {
347 let record_len = self.measurement_record.len() as i32;
348
349 record_targets
350 .iter()
351 .filter_map(|&idx| {
352 let abs_idx = if idx < 0 {
354 (record_len + idx) as usize
355 } else {
356 idx as usize
357 };
358
359 self.measurement_record.get(abs_idx).copied()
360 })
361 .fold(false, |acc, x| acc ^ x)
362 }
363
364 fn execute_x_error(&mut self, probability: f64, qubits: &[usize]) -> Result<()> {
368 let mut rng = thread_rng();
369 for &qubit in qubits {
370 if rng.gen_bool(probability) {
371 self.simulator
372 .apply_gate(crate::stabilizer::StabilizerGate::X(qubit))
373 .map_err(|e| {
374 SimulatorError::InvalidOperation(format!("X error failed: {:?}", e))
375 })?;
376 }
377 }
378 Ok(())
379 }
380
381 fn execute_y_error(&mut self, probability: f64, qubits: &[usize]) -> Result<()> {
383 let mut rng = thread_rng();
384 for &qubit in qubits {
385 if rng.gen_bool(probability) {
386 self.simulator
387 .apply_gate(crate::stabilizer::StabilizerGate::Y(qubit))
388 .map_err(|e| {
389 SimulatorError::InvalidOperation(format!("Y error failed: {:?}", e))
390 })?;
391 }
392 }
393 Ok(())
394 }
395
396 fn execute_z_error(&mut self, probability: f64, qubits: &[usize]) -> Result<()> {
398 let mut rng = thread_rng();
399 for &qubit in qubits {
400 if rng.gen_bool(probability) {
401 self.simulator
402 .apply_gate(crate::stabilizer::StabilizerGate::Z(qubit))
403 .map_err(|e| {
404 SimulatorError::InvalidOperation(format!("Z error failed: {:?}", e))
405 })?;
406 }
407 }
408 Ok(())
409 }
410
411 fn execute_depolarize1(&mut self, probability: f64, qubits: &[usize]) -> Result<()> {
413 let mut rng = thread_rng();
414 for &qubit in qubits {
416 if rng.gen_bool(probability) {
417 let error_type: u8 = rng.gen_range(0..3);
418 let gate = match error_type {
419 0 => crate::stabilizer::StabilizerGate::X(qubit),
420 1 => crate::stabilizer::StabilizerGate::Y(qubit),
421 _ => crate::stabilizer::StabilizerGate::Z(qubit),
422 };
423 self.simulator.apply_gate(gate).map_err(|e| {
424 SimulatorError::InvalidOperation(format!("Depolarizing error failed: {:?}", e))
425 })?;
426 }
427 }
428 Ok(())
429 }
430
431 fn execute_depolarize2(
433 &mut self,
434 probability: f64,
435 qubit_pairs: &[(usize, usize)],
436 ) -> Result<()> {
437 let mut rng = thread_rng();
438 for &(q1, q2) in qubit_pairs {
440 if rng.gen_bool(probability) {
441 let error_idx: u8 = rng.gen_range(0..15);
443 let (pauli1, pauli2) = Self::two_qubit_pauli_from_index(error_idx);
444 self.apply_pauli_to_qubit(pauli1, q1)?;
445 self.apply_pauli_to_qubit(pauli2, q2)?;
446 }
447 }
448 Ok(())
449 }
450
451 fn execute_correlated_error(
453 &mut self,
454 probability: f64,
455 targets: &[PauliTarget],
456 ) -> Result<()> {
457 let mut rng = thread_rng();
458 self.last_error_triggered = rng.gen_bool(probability);
459
460 if self.last_error_triggered {
461 for target in targets {
462 self.apply_pauli_to_qubit(target.pauli, target.qubit)?;
463 }
464 }
465 Ok(())
466 }
467
468 fn execute_else_correlated_error(
470 &mut self,
471 probability: f64,
472 targets: &[PauliTarget],
473 ) -> Result<()> {
474 if !self.last_error_triggered {
476 let mut rng = thread_rng();
477 self.last_error_triggered = rng.gen_bool(probability);
478
479 if self.last_error_triggered {
480 for target in targets {
481 self.apply_pauli_to_qubit(target.pauli, target.qubit)?;
482 }
483 }
484 }
485 Ok(())
487 }
488
489 fn execute_pauli_channel_1(
491 &mut self,
492 px: f64,
493 py: f64,
494 pz: f64,
495 qubits: &[usize],
496 ) -> Result<()> {
497 let mut rng = thread_rng();
498 for &qubit in qubits {
499 let r: f64 = rng.gen();
500 if r < px {
501 self.simulator
502 .apply_gate(crate::stabilizer::StabilizerGate::X(qubit))
503 .map_err(|e| {
504 SimulatorError::InvalidOperation(format!("Pauli channel failed: {:?}", e))
505 })?;
506 } else if r < px + py {
507 self.simulator
508 .apply_gate(crate::stabilizer::StabilizerGate::Y(qubit))
509 .map_err(|e| {
510 SimulatorError::InvalidOperation(format!("Pauli channel failed: {:?}", e))
511 })?;
512 } else if r < px + py + pz {
513 self.simulator
514 .apply_gate(crate::stabilizer::StabilizerGate::Z(qubit))
515 .map_err(|e| {
516 SimulatorError::InvalidOperation(format!("Pauli channel failed: {:?}", e))
517 })?;
518 }
519 }
521 Ok(())
522 }
523
524 fn execute_pauli_channel_2(
526 &mut self,
527 probabilities: &[f64],
528 qubit_pairs: &[(usize, usize)],
529 ) -> Result<()> {
530 if probabilities.len() != 15 {
531 return Err(SimulatorError::InvalidOperation(
532 "PAULI_CHANNEL_2 requires 15 probabilities".to_string(),
533 ));
534 }
535
536 let mut rng = thread_rng();
537 for &(q1, q2) in qubit_pairs {
538 let r: f64 = rng.gen();
539 let mut cumulative = 0.0;
540
541 for (i, &p) in probabilities.iter().enumerate() {
542 cumulative += p;
543 if r < cumulative {
544 let (pauli1, pauli2) = Self::two_qubit_pauli_from_index(i as u8);
545 self.apply_pauli_to_qubit(pauli1, q1)?;
546 self.apply_pauli_to_qubit(pauli2, q2)?;
547 break;
548 }
549 }
550 }
551 Ok(())
552 }
553
554 fn apply_pauli_to_qubit(&mut self, pauli: PauliType, qubit: usize) -> Result<()> {
556 let gate = match pauli {
557 PauliType::I => return Ok(()), PauliType::X => crate::stabilizer::StabilizerGate::X(qubit),
559 PauliType::Y => crate::stabilizer::StabilizerGate::Y(qubit),
560 PauliType::Z => crate::stabilizer::StabilizerGate::Z(qubit),
561 };
562 self.simulator.apply_gate(gate).map_err(|e| {
563 SimulatorError::InvalidOperation(format!("Pauli application failed: {:?}", e))
564 })
565 }
566
567 fn two_qubit_pauli_from_index(idx: u8) -> (PauliType, PauliType) {
570 let idx = idx + 1; let p1 = idx / 4;
574 let p2 = idx % 4;
575
576 let to_pauli = |i| match i {
577 0 => PauliType::I,
578 1 => PauliType::X,
579 2 => PauliType::Y,
580 _ => PauliType::Z,
581 };
582
583 (to_pauli(p1), to_pauli(p2))
584 }
585
586 #[must_use]
590 pub fn measurement_record(&self) -> &[bool] {
591 &self.measurement_record
592 }
593
594 #[must_use]
596 pub fn detectors(&self) -> &[DetectorRecord] {
597 &self.detectors
598 }
599
600 #[must_use]
602 pub fn observables(&self) -> &[ObservableRecord] {
603 &self.observables
604 }
605
606 #[must_use]
608 pub fn simulator(&self) -> &StabilizerSimulator {
609 &self.simulator
610 }
611
612 #[must_use]
614 pub fn get_stabilizers(&self) -> Vec<String> {
615 self.simulator.get_stabilizers()
616 }
617
618 #[must_use]
620 pub fn num_qubits(&self) -> usize {
621 self.num_qubits
622 }
623}
624
625#[derive(Debug, Clone)]
627pub struct ExecutionResult {
628 pub measurement_record: Vec<bool>,
630 pub detector_values: Vec<bool>,
632 pub observable_values: Vec<bool>,
634 pub num_measurements: usize,
636 pub num_detectors: usize,
638 pub num_observables: usize,
640}
641
642impl ExecutionResult {
643 #[must_use]
645 pub fn any_detector_fired(&self) -> bool {
646 self.detector_values.iter().any(|&x| x)
647 }
648
649 #[must_use]
651 pub fn detector_fire_count(&self) -> usize {
652 self.detector_values.iter().filter(|&&x| x).count()
653 }
654
655 #[must_use]
657 pub fn packed_measurements(&self) -> Vec<u8> {
658 self.measurement_record
659 .chunks(8)
660 .map(|chunk| {
661 let mut byte = 0u8;
662 for (i, &bit) in chunk.iter().enumerate() {
663 if bit {
664 byte |= 1 << i;
665 }
666 }
667 byte
668 })
669 .collect()
670 }
671
672 #[must_use]
674 pub fn packed_detectors(&self) -> Vec<u8> {
675 self.detector_values
676 .chunks(8)
677 .map(|chunk| {
678 let mut byte = 0u8;
679 for (i, &bit) in chunk.iter().enumerate() {
680 if bit {
681 byte |= 1 << i;
682 }
683 }
684 byte
685 })
686 .collect()
687 }
688}
689
690#[cfg(test)]
691mod tests {
692 use super::*;
693
694 #[test]
695 fn test_basic_execution() {
696 let circuit_str = r#"
697 H 0
698 CNOT 0 1
699 M 0 1
700 "#;
701
702 let circuit = StimCircuit::from_str(circuit_str).unwrap();
703 let mut executor = StimExecutor::from_circuit(&circuit);
704 let result = executor.execute(&circuit).unwrap();
705
706 assert_eq!(result.num_measurements, 2);
707 assert_eq!(result.measurement_record[0], result.measurement_record[1]);
709 }
710
711 #[test]
712 fn test_detector_execution() {
713 let circuit_str = r#"
716 M 0 1
717 DETECTOR rec[-1] rec[-2]
718 "#;
719
720 let circuit = StimCircuit::from_str(circuit_str).unwrap();
721 let mut executor = StimExecutor::from_circuit(&circuit);
722 let result = executor.execute(&circuit).unwrap();
723
724 assert_eq!(result.num_detectors, 1);
725 assert!(!result.measurement_record[0]);
727 assert!(!result.measurement_record[1]);
728 assert!(!result.detector_values[0]);
729 }
730
731 #[test]
732 fn test_detector_with_error() {
733 let circuit_str = r#"
736 X 0
737 M 0 1
738 DETECTOR rec[-1] rec[-2]
739 "#;
740
741 let circuit = StimCircuit::from_str(circuit_str).unwrap();
742 let mut executor = StimExecutor::from_circuit(&circuit);
743 let result = executor.execute(&circuit).unwrap();
744
745 assert_eq!(result.num_detectors, 1);
746 assert!(result.measurement_record[0]);
748 assert!(!result.measurement_record[1]);
749 assert!(result.detector_values[0]);
750 }
751
752 #[test]
753 fn test_observable_execution() {
754 let circuit_str = r#"
755 H 0
756 CNOT 0 1
757 M 0 1
758 OBSERVABLE_INCLUDE(0) rec[-1]
759 OBSERVABLE_INCLUDE(1) rec[-2]
760 "#;
761
762 let circuit = StimCircuit::from_str(circuit_str).unwrap();
763 let mut executor = StimExecutor::from_circuit(&circuit);
764 let result = executor.execute(&circuit).unwrap();
765
766 assert_eq!(result.num_observables, 2);
767 }
768
769 #[test]
770 fn test_measure_reset() {
771 let circuit_str = r#"
772 H 0
773 MR 0
774 M 0
775 "#;
776
777 let circuit = StimCircuit::from_str(circuit_str).unwrap();
778 let mut executor = StimExecutor::from_circuit(&circuit);
779 let result = executor.execute(&circuit).unwrap();
780
781 assert_eq!(result.num_measurements, 2);
782 assert!(!result.measurement_record[1]);
784 }
785
786 #[test]
787 fn test_noise_execution() {
788 let circuit_str = r#"
790 X_ERROR(1.0) 0
791 M 0
792 "#;
793
794 let circuit = StimCircuit::from_str(circuit_str).unwrap();
795 let mut executor = StimExecutor::from_circuit(&circuit);
796 let result = executor.execute(&circuit).unwrap();
797
798 assert!(result.measurement_record[0]);
800 }
801
802 #[test]
803 fn test_correlated_error() {
804 let circuit_str = r#"
806 E(1.0) X0 X1
807 M 0 1
808 "#;
809
810 let circuit = StimCircuit::from_str(circuit_str).unwrap();
811 let mut executor = StimExecutor::from_circuit(&circuit);
812 let result = executor.execute(&circuit).unwrap();
813
814 assert!(result.measurement_record[0]);
816 assert!(result.measurement_record[1]);
817 }
818
819 #[test]
820 fn test_else_correlated_error() {
821 let circuit_str = r#"
823 E(1.0) X0
824 ELSE_CORRELATED_ERROR(1.0) X1
825 M 0 1
826 "#;
827
828 let circuit = StimCircuit::from_str(circuit_str).unwrap();
829 let mut executor = StimExecutor::from_circuit(&circuit);
830 let result = executor.execute(&circuit).unwrap();
831
832 assert!(result.measurement_record[0]); assert!(!result.measurement_record[1]); }
836
837 #[test]
838 fn test_packed_measurements() {
839 let mut result = ExecutionResult {
840 measurement_record: vec![true, false, true, true, false, false, true, false, true],
841 detector_values: vec![],
842 observable_values: vec![],
843 num_measurements: 9,
844 num_detectors: 0,
845 num_observables: 0,
846 };
847
848 let packed = result.packed_measurements();
849 assert_eq!(packed[0], 0b01001101);
852 assert_eq!(packed[1], 0b00000001);
853 }
854
855 #[test]
856 fn test_detector_fire_count() {
857 let result = ExecutionResult {
858 measurement_record: vec![],
859 detector_values: vec![true, false, true, true, false],
860 observable_values: vec![],
861 num_measurements: 0,
862 num_detectors: 5,
863 num_observables: 0,
864 };
865
866 assert!(result.any_detector_fired());
867 assert_eq!(result.detector_fire_count(), 3);
868 }
869}