1use crate::error::QuantRS2Error;
7use crate::gate_translation::GateType;
8use scirs2_core::Complex64;
9use crate::parallel_ops_stubs::*;
11use crate::buffer_pool::BufferPool;
13
14#[derive(Debug, Clone)]
16pub struct QuantumGate {
17 gate_type: GateType,
18 target_qubits: Vec<usize>,
19 control_qubits: Option<Vec<usize>>,
20}
21
22impl QuantumGate {
23 pub fn new(
24 gate_type: GateType,
25 target_qubits: Vec<usize>,
26 control_qubits: Option<Vec<usize>>,
27 ) -> Self {
28 Self {
29 gate_type,
30 target_qubits,
31 control_qubits,
32 }
33 }
34
35 pub fn gate_type(&self) -> &GateType {
36 &self.gate_type
37 }
38
39 pub fn target_qubits(&self) -> &[usize] {
40 &self.target_qubits
41 }
42
43 pub fn control_qubits(&self) -> Option<&[usize]> {
44 self.control_qubits.as_deref()
45 }
46}
47
48#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
50pub struct EquivalenceConfig {
51 pub absolute_tolerance: f64,
53 pub relative_tolerance: f64,
55 pub max_exact_qubits: usize,
57 pub use_probabilistic: bool,
59 pub num_test_vectors: usize,
61 pub enable_symmetry_detection: bool,
63 pub enable_simd: bool,
65 pub enable_parallel: bool,
67 pub memory_optimization_level: u8,
69 pub matrix_comparison_method: MatrixComparisonMethod,
71}
72
73impl Default for EquivalenceConfig {
74 fn default() -> Self {
75 Self {
76 absolute_tolerance: 1e-12,
77 relative_tolerance: 1e-10,
78 max_exact_qubits: 20,
79 use_probabilistic: true,
80 num_test_vectors: 100,
81 enable_symmetry_detection: true,
82 enable_simd: true,
83 enable_parallel: true,
84 memory_optimization_level: 2,
85 matrix_comparison_method: MatrixComparisonMethod::FrobeniusNorm,
86 }
87 }
88}
89
90#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
92pub enum MatrixComparisonMethod {
93 FrobeniusNorm,
95 SpectralNorm,
97 ElementWise,
99 SvdBased,
101}
102
103pub struct EquivalenceChecker {
105 config: EquivalenceConfig,
106 buffer_pool: Option<BufferPool<Complex64>>,
107}
108
109impl EquivalenceChecker {
110 pub fn new() -> Self {
112 let config = EquivalenceConfig::default();
113 Self::with_config(config)
114 }
115
116 pub fn with_config(config: EquivalenceConfig) -> Self {
118 let buffer_pool = if config.memory_optimization_level > 0 {
119 Some(BufferPool::<Complex64>::new()) } else {
121 None
122 };
123
124 Self {
125 config,
126 buffer_pool,
127 }
128 }
129
130 pub fn are_circuits_equivalent(
132 &self,
133 circuit1: &[QuantumGate],
134 circuit2: &[QuantumGate],
135 num_qubits: usize,
136 ) -> Result<bool, QuantRS2Error> {
137 if num_qubits <= self.config.max_exact_qubits {
138 self.exact_equivalence_check(circuit1, circuit2, num_qubits)
139 } else if self.config.use_probabilistic {
140 self.probabilistic_equivalence_check(circuit1, circuit2, num_qubits)
141 } else {
142 Err(QuantRS2Error::UnsupportedOperation(
143 "Circuit too large for exact verification and probabilistic checking disabled"
144 .into(),
145 ))
146 }
147 }
148
149 fn exact_equivalence_check(
151 &self,
152 circuit1: &[QuantumGate],
153 circuit2: &[QuantumGate],
154 num_qubits: usize,
155 ) -> Result<bool, QuantRS2Error> {
156 let matrix1 = self.compute_circuit_matrix(circuit1, num_qubits)?;
157 let matrix2 = self.compute_circuit_matrix(circuit2, num_qubits)?;
158
159 Ok(self.matrices_equivalent(&matrix1, &matrix2))
160 }
161
162 fn probabilistic_equivalence_check(
164 &self,
165 circuit1: &[QuantumGate],
166 circuit2: &[QuantumGate],
167 num_qubits: usize,
168 ) -> Result<bool, QuantRS2Error> {
169 use scirs2_core::random::prelude::*;
170 let mut rng = thread_rng();
171
172 for _ in 0..self.config.num_test_vectors {
173 let mut state: Vec<Complex64> = (0..(1 << num_qubits))
175 .map(|_| Complex64::new(rng.gen::<f64>() - 0.5, rng.gen::<f64>() - 0.5))
176 .collect();
177
178 let norm: f64 = state.iter().map(|c| c.norm_sqr()).sum::<f64>().sqrt();
180 state.iter_mut().for_each(|c| *c /= norm);
181
182 let result1 = self.apply_circuit_to_state(circuit1, &state, num_qubits)?;
183 let result2 = self.apply_circuit_to_state(circuit2, &state, num_qubits)?;
184
185 if !self.states_equivalent(&result1, &result2) {
186 return Ok(false);
187 }
188 }
189
190 Ok(true)
191 }
192
193 fn compute_circuit_matrix(
195 &self,
196 circuit: &[QuantumGate],
197 num_qubits: usize,
198 ) -> Result<Vec<Vec<Complex64>>, QuantRS2Error> {
199 let dim = 1 << num_qubits;
200 let mut matrix = vec![vec![Complex64::new(0.0, 0.0); dim]; dim];
201
202 for i in 0..dim {
204 matrix[i][i] = Complex64::new(1.0, 0.0);
205 }
206
207 for gate in circuit {
209 let gate_matrix = self.gate_to_matrix(gate, num_qubits)?;
210 matrix = self.multiply_matrices(&gate_matrix, &matrix);
211 }
212
213 Ok(matrix)
214 }
215
216 fn gate_to_matrix(
218 &self,
219 gate: &QuantumGate,
220 num_qubits: usize,
221 ) -> Result<Vec<Vec<Complex64>>, QuantRS2Error> {
222 use crate::gate_translation::GateType;
223
224 let dim = 1 << num_qubits;
225 let mut matrix = vec![vec![Complex64::new(0.0, 0.0); dim]; dim];
226
227 for i in 0..dim {
229 matrix[i][i] = Complex64::new(1.0, 0.0);
230 }
231
232 match gate.gate_type() {
233 GateType::X => {
234 self.apply_single_qubit_gate(
235 &mut matrix,
236 gate.target_qubits()[0],
237 &[
238 [Complex64::new(0.0, 0.0), Complex64::new(1.0, 0.0)],
239 [Complex64::new(1.0, 0.0), Complex64::new(0.0, 0.0)],
240 ],
241 num_qubits,
242 );
243 }
244 GateType::Y => {
245 self.apply_single_qubit_gate(
246 &mut matrix,
247 gate.target_qubits()[0],
248 &[
249 [Complex64::new(0.0, 0.0), Complex64::new(0.0, -1.0)],
250 [Complex64::new(0.0, 1.0), Complex64::new(0.0, 0.0)],
251 ],
252 num_qubits,
253 );
254 }
255 GateType::Z => {
256 self.apply_single_qubit_gate(
257 &mut matrix,
258 gate.target_qubits()[0],
259 &[
260 [Complex64::new(1.0, 0.0), Complex64::new(0.0, 0.0)],
261 [Complex64::new(0.0, 0.0), Complex64::new(-1.0, 0.0)],
262 ],
263 num_qubits,
264 );
265 }
266 GateType::H => {
267 let inv_sqrt2 = 1.0 / std::f64::consts::SQRT_2;
268 self.apply_single_qubit_gate(
269 &mut matrix,
270 gate.target_qubits()[0],
271 &[
272 [
273 Complex64::new(inv_sqrt2, 0.0),
274 Complex64::new(inv_sqrt2, 0.0),
275 ],
276 [
277 Complex64::new(inv_sqrt2, 0.0),
278 Complex64::new(-inv_sqrt2, 0.0),
279 ],
280 ],
281 num_qubits,
282 );
283 }
284 GateType::CNOT => {
285 if gate.target_qubits().len() >= 2 {
286 self.apply_cnot_gate(
287 &mut matrix,
288 gate.target_qubits()[0],
289 gate.target_qubits()[1],
290 num_qubits,
291 );
292 }
293 }
294 GateType::S => {
295 self.apply_single_qubit_gate(
296 &mut matrix,
297 gate.target_qubits()[0],
298 &[
299 [Complex64::new(1.0, 0.0), Complex64::new(0.0, 0.0)],
300 [Complex64::new(0.0, 0.0), Complex64::new(0.0, 1.0)],
301 ],
302 num_qubits,
303 );
304 }
305 GateType::T => {
306 let sqrt2_inv = 1.0 / std::f64::consts::SQRT_2;
307 self.apply_single_qubit_gate(
308 &mut matrix,
309 gate.target_qubits()[0],
310 &[
311 [Complex64::new(1.0, 0.0), Complex64::new(0.0, 0.0)],
312 [
313 Complex64::new(0.0, 0.0),
314 Complex64::new(sqrt2_inv, sqrt2_inv),
315 ],
316 ],
317 num_qubits,
318 );
319 }
320 GateType::SqrtX => {
321 let sqrt2_inv = 1.0 / std::f64::consts::SQRT_2;
322 self.apply_single_qubit_gate(
323 &mut matrix,
324 gate.target_qubits()[0],
325 &[
326 [Complex64::new(0.5, 0.5), Complex64::new(0.5, -0.5)],
327 [Complex64::new(0.5, -0.5), Complex64::new(0.5, 0.5)],
328 ],
329 num_qubits,
330 );
331 }
332 GateType::SqrtY => {
333 let sqrt2_inv = 1.0 / std::f64::consts::SQRT_2;
334 self.apply_single_qubit_gate(
335 &mut matrix,
336 gate.target_qubits()[0],
337 &[
338 [
339 Complex64::new(sqrt2_inv, 0.0),
340 Complex64::new(-sqrt2_inv, 0.0),
341 ],
342 [
343 Complex64::new(sqrt2_inv, 0.0),
344 Complex64::new(sqrt2_inv, 0.0),
345 ],
346 ],
347 num_qubits,
348 );
349 }
350 GateType::SqrtZ => {
351 self.apply_single_qubit_gate(
352 &mut matrix,
353 gate.target_qubits()[0],
354 &[
355 [Complex64::new(1.0, 0.0), Complex64::new(0.0, 0.0)],
356 [Complex64::new(0.0, 0.0), Complex64::new(0.0, 1.0)],
357 ],
358 num_qubits,
359 );
360 }
361 GateType::CZ => {
362 if gate.target_qubits().len() >= 2 {
363 self.apply_cz_gate(
364 &mut matrix,
365 gate.target_qubits()[0],
366 gate.target_qubits()[1],
367 num_qubits,
368 );
369 }
370 }
371 GateType::CY => {
372 if gate.target_qubits().len() >= 2 {
373 self.apply_controlled_gate(
374 &mut matrix,
375 gate.target_qubits()[0],
376 gate.target_qubits()[1],
377 &[
378 [Complex64::new(0.0, 0.0), Complex64::new(0.0, -1.0)],
379 [Complex64::new(0.0, 1.0), Complex64::new(0.0, 0.0)],
380 ],
381 num_qubits,
382 );
383 }
384 }
385 GateType::SWAP => {
386 if gate.target_qubits().len() >= 2 {
387 self.apply_swap_gate(
388 &mut matrix,
389 gate.target_qubits()[0],
390 gate.target_qubits()[1],
391 num_qubits,
392 );
393 }
394 }
395 GateType::ISwap => {
396 if gate.target_qubits().len() >= 2 {
397 self.apply_iswap_gate(
398 &mut matrix,
399 gate.target_qubits()[0],
400 gate.target_qubits()[1],
401 num_qubits,
402 );
403 }
404 }
405 _ => {
406 eprintln!(
408 "Warning: Gate type {:?} not fully implemented in equivalence checker",
409 gate.gate_type()
410 );
411 }
412 }
413
414 Ok(matrix)
415 }
416
417 fn apply_single_qubit_gate(
419 &self,
420 matrix: &mut Vec<Vec<Complex64>>,
421 target_qubit: usize,
422 gate_matrix: &[[Complex64; 2]; 2],
423 num_qubits: usize,
424 ) {
425 let dim = 1 << num_qubits;
426 let target_bit = 1 << target_qubit;
427
428 for i in 0..dim {
429 if i & target_bit == 0 {
430 let j = i | target_bit;
431 for k in 0..dim {
432 let old_i = matrix[i][k];
433 let old_j = matrix[j][k];
434 matrix[i][k] = gate_matrix[0][0] * old_i + gate_matrix[0][1] * old_j;
435 matrix[j][k] = gate_matrix[1][0] * old_i + gate_matrix[1][1] * old_j;
436 }
437 }
438 }
439 }
440
441 fn apply_cnot_gate(
443 &self,
444 matrix: &mut Vec<Vec<Complex64>>,
445 control_qubit: usize,
446 target_qubit: usize,
447 num_qubits: usize,
448 ) {
449 let dim = 1 << num_qubits;
450 let control_bit = 1 << control_qubit;
451 let target_bit = 1 << target_qubit;
452
453 for i in 0..dim {
454 if i & control_bit != 0 {
455 let j = i ^ target_bit;
456 if i != j {
457 for k in 0..dim {
458 let temp = matrix[i][k];
459 matrix[i][k] = matrix[j][k];
460 matrix[j][k] = temp;
461 }
462 }
463 }
464 }
465 }
466
467 fn apply_cz_gate(
469 &self,
470 matrix: &mut Vec<Vec<Complex64>>,
471 control_qubit: usize,
472 target_qubit: usize,
473 num_qubits: usize,
474 ) {
475 let dim = 1 << num_qubits;
476 let control_bit = 1 << control_qubit;
477 let target_bit = 1 << target_qubit;
478
479 for i in 0..dim {
480 if (i & control_bit != 0) && (i & target_bit != 0) {
481 for k in 0..dim {
482 matrix[i][k] *= -1.0;
483 }
484 }
485 }
486 }
487
488 fn apply_controlled_gate(
490 &self,
491 matrix: &mut Vec<Vec<Complex64>>,
492 control_qubit: usize,
493 target_qubit: usize,
494 gate_matrix: &[[Complex64; 2]; 2],
495 num_qubits: usize,
496 ) {
497 let dim = 1 << num_qubits;
498 let control_bit = 1 << control_qubit;
499 let target_bit = 1 << target_qubit;
500
501 for i in 0..dim {
502 if i & control_bit != 0 {
503 let j = i ^ target_bit;
504 for k in 0..dim {
505 let old_i = matrix[i][k];
506 let old_j = matrix[j][k];
507 matrix[i][k] = gate_matrix[0][0] * old_i + gate_matrix[0][1] * old_j;
508 matrix[j][k] = gate_matrix[1][0] * old_i + gate_matrix[1][1] * old_j;
509 }
510 }
511 }
512 }
513
514 fn apply_swap_gate(
516 &self,
517 matrix: &mut Vec<Vec<Complex64>>,
518 qubit1: usize,
519 qubit2: usize,
520 num_qubits: usize,
521 ) {
522 let dim = 1 << num_qubits;
523 let bit1 = 1 << qubit1;
524 let bit2 = 1 << qubit2;
525
526 for i in 0..dim {
527 let state1 = (i & bit1) != 0;
528 let state2 = (i & bit2) != 0;
529
530 if state1 != state2 {
531 let j = i ^ bit1 ^ bit2;
532 if i < j {
533 for k in 0..dim {
534 let temp = matrix[i][k];
535 matrix[i][k] = matrix[j][k];
536 matrix[j][k] = temp;
537 }
538 }
539 }
540 }
541 }
542
543 fn apply_iswap_gate(
545 &self,
546 matrix: &mut Vec<Vec<Complex64>>,
547 qubit1: usize,
548 qubit2: usize,
549 num_qubits: usize,
550 ) {
551 let dim = 1 << num_qubits;
552 let bit1 = 1 << qubit1;
553 let bit2 = 1 << qubit2;
554
555 for i in 0..dim {
556 let state1 = (i & bit1) != 0;
557 let state2 = (i & bit2) != 0;
558
559 if state1 != state2 {
560 let j = i ^ bit1 ^ bit2;
561 if i < j {
562 for k in 0..dim {
563 let temp = matrix[i][k];
564 matrix[i][k] = Complex64::new(0.0, 1.0) * matrix[j][k];
565 matrix[j][k] = Complex64::new(0.0, 1.0) * temp;
566 }
567 }
568 }
569 }
570 }
571
572 fn multiply_matrices(
574 &self,
575 a: &Vec<Vec<Complex64>>,
576 b: &Vec<Vec<Complex64>>,
577 ) -> Vec<Vec<Complex64>> {
578 if self.config.enable_simd || self.config.enable_parallel {
580 self.multiply_matrices_simd(a, b)
581 } else {
582 self.multiply_matrices_standard(a, b)
583 }
584 }
585
586 fn multiply_matrices_standard(
588 &self,
589 a: &Vec<Vec<Complex64>>,
590 b: &Vec<Vec<Complex64>>,
591 ) -> Vec<Vec<Complex64>> {
592 let n = a.len();
593 let mut result = vec![vec![Complex64::new(0.0, 0.0); n]; n];
594
595 for i in 0..n {
596 for j in 0..n {
597 for k in 0..n {
598 result[i][j] += a[i][k] * b[k][j];
599 }
600 }
601 }
602
603 result
604 }
605
606 fn multiply_matrices_simd(
608 &self,
609 a: &Vec<Vec<Complex64>>,
610 b: &Vec<Vec<Complex64>>,
611 ) -> Vec<Vec<Complex64>> {
612 let n = a.len();
613 let mut result = vec![vec![Complex64::new(0.0, 0.0); n]; n];
614
615 if self.config.enable_parallel && n > 64 {
617 result.par_iter_mut().enumerate().for_each(|(i, row)| {
618 for j in 0..n {
619 let mut sum = Complex64::new(0.0, 0.0);
620 for k in 0..n {
621 sum += a[i][k] * b[k][j];
622 }
623 row[j] = sum;
624 }
625 });
626 } else {
627 for i in 0..n {
629 for j in 0..n {
630 for k in 0..n {
631 result[i][j] += a[i][k] * b[k][j];
632 }
633 }
634 }
635 }
636
637 result
638 }
639
640 fn matrices_equivalent(
642 &self,
643 matrix1: &Vec<Vec<Complex64>>,
644 matrix2: &Vec<Vec<Complex64>>,
645 ) -> bool {
646 self.matrices_equivalent_enhanced(matrix1, matrix2)
648 }
649
650 fn matrices_equivalent_enhanced(
652 &self,
653 matrix1: &Vec<Vec<Complex64>>,
654 matrix2: &Vec<Vec<Complex64>>,
655 ) -> bool {
656 if matrix1.len() != matrix2.len() {
657 return false;
658 }
659
660 if self.config.enable_parallel && matrix1.len() > 32 {
661 matrix1
663 .par_iter()
664 .zip(matrix2.par_iter())
665 .all(|(row1, row2)| {
666 row1.iter().zip(row2.iter()).all(|(elem1, elem2)| {
667 self.complex_numbers_equivalent_scirs2(*elem1, *elem2)
668 })
669 })
670 } else {
671 for (row1, row2) in matrix1.iter().zip(matrix2.iter()) {
673 for (elem1, elem2) in row1.iter().zip(row2.iter()) {
674 if !self.complex_numbers_equivalent_scirs2(*elem1, *elem2) {
675 return false;
676 }
677 }
678 }
679 true
680 }
681 }
682
683 fn apply_circuit_to_state(
685 &self,
686 circuit: &[QuantumGate],
687 initial_state: &[Complex64],
688 num_qubits: usize,
689 ) -> Result<Vec<Complex64>, QuantRS2Error> {
690 let mut state = initial_state.to_vec();
691
692 for gate in circuit {
693 self.apply_gate_to_state(gate, &mut state, num_qubits)?;
694 }
695
696 Ok(state)
697 }
698
699 fn apply_gate_to_state(
701 &self,
702 gate: &QuantumGate,
703 state: &mut Vec<Complex64>,
704 num_qubits: usize,
705 ) -> Result<(), QuantRS2Error> {
706 use crate::gate_translation::GateType;
707
708 match gate.gate_type() {
709 GateType::X => {
710 let target = gate.target_qubits()[0];
711 let target_bit = 1 << target;
712 for i in 0..(1 << num_qubits) {
713 let j = i ^ target_bit;
714 if i < j {
715 state.swap(i, j);
716 }
717 }
718 }
719 GateType::Y => {
720 let target = gate.target_qubits()[0];
721 let target_bit = 1 << target;
722 for i in 0..(1 << num_qubits) {
723 let j = i ^ target_bit;
724 if i < j {
725 let temp = state[i];
726 state[i] = Complex64::new(0.0, 1.0) * state[j];
727 state[j] = Complex64::new(0.0, -1.0) * temp;
728 }
729 }
730 }
731 GateType::Z => {
732 let target = gate.target_qubits()[0];
733 let target_bit = 1 << target;
734 for i in 0..(1 << num_qubits) {
735 if i & target_bit != 0 {
736 state[i] *= -1.0;
737 }
738 }
739 }
740 GateType::H => {
741 let target = gate.target_qubits()[0];
742 let target_bit = 1 << target;
743 let inv_sqrt2 = 1.0 / std::f64::consts::SQRT_2;
744 for i in 0..(1 << num_qubits) {
745 let j = i ^ target_bit;
746 if i < j {
747 let temp = state[i];
748 state[i] = inv_sqrt2 * (temp + state[j]);
749 state[j] = inv_sqrt2 * (temp - state[j]);
750 }
751 }
752 }
753 GateType::CNOT => {
754 if gate.target_qubits().len() >= 2 {
755 let control = gate.target_qubits()[0];
756 let target = gate.target_qubits()[1];
757 let control_bit = 1 << control;
758 let target_bit = 1 << target;
759
760 for i in 0..(1 << num_qubits) {
761 if i & control_bit != 0 {
762 let j = i ^ target_bit;
763 if i != j {
764 state.swap(i, j);
765 }
766 }
767 }
768 }
769 }
770 GateType::S => {
771 let target = gate.target_qubits()[0];
772 let target_bit = 1 << target;
773 for i in 0..(1 << num_qubits) {
774 if i & target_bit != 0 {
775 state[i] *= Complex64::new(0.0, 1.0);
776 }
777 }
778 }
779 GateType::T => {
780 let target = gate.target_qubits()[0];
781 let target_bit = 1 << target;
782 let sqrt2_inv = 1.0 / std::f64::consts::SQRT_2;
783 let t_phase = Complex64::new(sqrt2_inv, sqrt2_inv);
784 for i in 0..(1 << num_qubits) {
785 if i & target_bit != 0 {
786 state[i] *= t_phase;
787 }
788 }
789 }
790 GateType::SqrtX => {
791 let target = gate.target_qubits()[0];
792 let target_bit = 1 << target;
793 for i in 0..(1 << num_qubits) {
794 let j = i ^ target_bit;
795 if i < j {
796 let temp = state[i];
797 state[i] =
798 Complex64::new(0.5, 0.5) * temp + Complex64::new(0.5, -0.5) * state[j];
799 state[j] =
800 Complex64::new(0.5, -0.5) * temp + Complex64::new(0.5, 0.5) * state[j];
801 }
802 }
803 }
804 GateType::SqrtY => {
805 let target = gate.target_qubits()[0];
806 let target_bit = 1 << target;
807 let sqrt2_inv = 1.0 / std::f64::consts::SQRT_2;
808 for i in 0..(1 << num_qubits) {
809 let j = i ^ target_bit;
810 if i < j {
811 let temp = state[i];
812 state[i] = sqrt2_inv * (temp - state[j]);
813 state[j] = sqrt2_inv * (temp + state[j]);
814 }
815 }
816 }
817 GateType::SqrtZ => {
818 let target = gate.target_qubits()[0];
819 let target_bit = 1 << target;
820 for i in 0..(1 << num_qubits) {
821 if i & target_bit != 0 {
822 state[i] *= Complex64::new(0.0, 1.0);
823 }
824 }
825 }
826 GateType::CZ => {
827 if gate.target_qubits().len() >= 2 {
828 let control = gate.target_qubits()[0];
829 let target = gate.target_qubits()[1];
830 let control_bit = 1 << control;
831 let target_bit = 1 << target;
832
833 for i in 0..(1 << num_qubits) {
834 if (i & control_bit != 0) && (i & target_bit != 0) {
835 state[i] *= -1.0;
836 }
837 }
838 }
839 }
840 GateType::CY => {
841 if gate.target_qubits().len() >= 2 {
842 let control = gate.target_qubits()[0];
843 let target = gate.target_qubits()[1];
844 let control_bit = 1 << control;
845 let target_bit = 1 << target;
846
847 for i in 0..(1 << num_qubits) {
848 if i & control_bit != 0 {
849 let j = i ^ target_bit;
850 if i < j {
851 let temp = state[i];
852 state[i] = Complex64::new(0.0, 1.0) * state[j];
853 state[j] = Complex64::new(0.0, -1.0) * temp;
854 }
855 }
856 }
857 }
858 }
859 GateType::SWAP => {
860 if gate.target_qubits().len() >= 2 {
861 let qubit1 = gate.target_qubits()[0];
862 let qubit2 = gate.target_qubits()[1];
863 let bit1 = 1 << qubit1;
864 let bit2 = 1 << qubit2;
865
866 for i in 0..(1 << num_qubits) {
867 let state1 = (i & bit1) != 0;
868 let state2 = (i & bit2) != 0;
869
870 if state1 != state2 {
871 let j = i ^ bit1 ^ bit2;
872 if i < j {
873 state.swap(i, j);
874 }
875 }
876 }
877 }
878 }
879 GateType::ISwap => {
880 if gate.target_qubits().len() >= 2 {
881 let qubit1 = gate.target_qubits()[0];
882 let qubit2 = gate.target_qubits()[1];
883 let bit1 = 1 << qubit1;
884 let bit2 = 1 << qubit2;
885
886 for i in 0..(1 << num_qubits) {
887 let state1 = (i & bit1) != 0;
888 let state2 = (i & bit2) != 0;
889
890 if state1 != state2 {
891 let j = i ^ bit1 ^ bit2;
892 if i < j {
893 let temp = state[i];
894 state[i] = Complex64::new(0.0, 1.0) * state[j];
895 state[j] = Complex64::new(0.0, 1.0) * temp;
896 }
897 }
898 }
899 }
900 }
901 _ => {
902 }
904 }
905
906 Ok(())
907 }
908
909 fn states_equivalent(&self, state1: &[Complex64], state2: &[Complex64]) -> bool {
911 state1
912 .iter()
913 .zip(state2.iter())
914 .all(|(s1, s2)| self.complex_numbers_equivalent(*s1, *s2))
915 }
916
917 fn complex_numbers_equivalent_scirs2(&self, z1: Complex64, z2: Complex64) -> bool {
919 let diff = z1 - z2;
921 let abs_error = diff.norm();
922
923 if abs_error <= self.config.absolute_tolerance {
925 return true;
926 }
927
928 let max_magnitude = z1.norm().max(z2.norm());
930 if max_magnitude > 0.0 {
931 let rel_error = abs_error / max_magnitude;
932 if rel_error <= self.config.relative_tolerance {
933 return true;
934 }
935 }
936
937 let machine_epsilon = f64::EPSILON;
939 abs_error <= 10.0 * machine_epsilon
940 }
941
942 fn complex_numbers_equivalent(&self, z1: Complex64, z2: Complex64) -> bool {
944 self.complex_numbers_equivalent_scirs2(z1, z2)
945 }
946
947 pub fn advanced_equivalence_check(
949 &self,
950 circuit1: &[QuantumGate],
951 circuit2: &[QuantumGate],
952 num_qubits: usize,
953 ) -> Result<EquivalenceResult, QuantRS2Error> {
954 let basic_equivalent = self.are_circuits_equivalent(circuit1, circuit2, num_qubits)?;
955
956 let mut result = EquivalenceResult {
957 equivalent: basic_equivalent,
958 phase_equivalent: false,
959 global_phase_difference: None,
960 symmetry_analysis: None,
961 };
962
963 if !basic_equivalent && self.config.enable_symmetry_detection {
964 result.phase_equivalent =
966 self.check_phase_equivalence(circuit1, circuit2, num_qubits)?;
967 }
968
969 Ok(result)
970 }
971
972 fn check_phase_equivalence(
974 &self,
975 circuit1: &[QuantumGate],
976 circuit2: &[QuantumGate],
977 num_qubits: usize,
978 ) -> Result<bool, QuantRS2Error> {
979 if num_qubits > self.config.max_exact_qubits {
980 return Ok(false); }
982
983 let matrix1 = self.compute_circuit_matrix(circuit1, num_qubits)?;
984 let matrix2 = self.compute_circuit_matrix(circuit2, num_qubits)?;
985
986 let mut global_phase = None;
988
989 for i in 0..matrix1.len() {
990 for j in 0..matrix1[i].len() {
991 if matrix1[i][j].norm() > self.config.absolute_tolerance
992 && matrix2[i][j].norm() > self.config.absolute_tolerance
993 {
994 let phase = matrix2[i][j] / matrix1[i][j];
995 if let Some(existing_phase) = global_phase {
996 if !self.complex_numbers_equivalent(phase, existing_phase) {
997 return Ok(false);
998 }
999 } else {
1000 global_phase = Some(phase);
1001 }
1002 }
1003 }
1004 }
1005
1006 if let Some(phase) = global_phase {
1008 for i in 0..matrix1.len() {
1009 for j in 0..matrix1[i].len() {
1010 let expected = matrix1[i][j] * phase;
1011 if !self.complex_numbers_equivalent(expected, matrix2[i][j]) {
1012 return Ok(false);
1013 }
1014 }
1015 }
1016 Ok(true)
1017 } else {
1018 Ok(true) }
1020 }
1021}
1022
1023#[derive(Debug, Clone)]
1025pub struct EquivalenceResult {
1026 pub equivalent: bool,
1028 pub phase_equivalent: bool,
1030 pub global_phase_difference: Option<Complex64>,
1032 pub symmetry_analysis: Option<SymmetryAnalysis>,
1034}
1035
1036#[derive(Debug, Clone)]
1038pub struct SymmetryAnalysis {
1039 pub symmetries: Vec<String>,
1041 pub canonical_form: Option<Vec<QuantumGate>>,
1043}
1044
1045#[cfg(test)]
1046mod tests {
1047 use super::*;
1048 use super::{GateType, QuantumGate};
1049
1050 #[test]
1051 fn test_identity_equivalence() {
1052 let checker = EquivalenceChecker::new();
1053 let circuit1 = vec![];
1054 let circuit2 = vec![];
1055
1056 assert!(checker
1057 .are_circuits_equivalent(&circuit1, &circuit2, 2)
1058 .unwrap());
1059 }
1060
1061 #[test]
1062 fn test_single_gate_equivalence() {
1063 let checker = EquivalenceChecker::new();
1064 let gate1 = QuantumGate::new(GateType::X, vec![0], None);
1065 let gate2 = QuantumGate::new(GateType::X, vec![0], None);
1066
1067 let circuit1 = vec![gate1];
1068 let circuit2 = vec![gate2];
1069
1070 assert!(checker
1071 .are_circuits_equivalent(&circuit1, &circuit2, 2)
1072 .unwrap());
1073 }
1074
1075 #[test]
1076 fn test_different_gates_not_equivalent() {
1077 let checker = EquivalenceChecker::new();
1078 let gate1 = QuantumGate::new(GateType::X, vec![0], None);
1079 let gate2 = QuantumGate::new(GateType::Y, vec![0], None);
1080
1081 let circuit1 = vec![gate1];
1082 let circuit2 = vec![gate2];
1083
1084 assert!(!checker
1085 .are_circuits_equivalent(&circuit1, &circuit2, 2)
1086 .unwrap());
1087 }
1088
1089 #[test]
1090 fn test_complex_number_equivalence() {
1091 let checker = EquivalenceChecker::new();
1092
1093 let z1 = Complex64::new(1.0, 0.0);
1094 let z2 = Complex64::new(1.0 + 1e-11, 0.0); assert!(checker.complex_numbers_equivalent(z1, z2));
1097
1098 let z3 = Complex64::new(1.0, 0.0);
1099 let z4 = Complex64::new(2.0, 0.0);
1100
1101 assert!(!checker.complex_numbers_equivalent(z3, z4));
1102 }
1103
1104 #[test]
1105 fn test_hadamard_equivalence() {
1106 let checker = EquivalenceChecker::new();
1107 let h_gate = QuantumGate::new(GateType::H, vec![0], None);
1108
1109 let circuit1 = vec![h_gate.clone(), h_gate.clone()];
1110 let circuit2 = vec![];
1111
1112 assert!(checker
1114 .are_circuits_equivalent(&circuit1, &circuit2, 1)
1115 .unwrap());
1116 }
1117
1118 #[test]
1119 fn test_s_gate_equivalence() {
1120 let checker = EquivalenceChecker::new();
1121 let s_gate = QuantumGate::new(GateType::S, vec![0], None);
1122
1123 let circuit1 = vec![
1124 s_gate.clone(),
1125 s_gate.clone(),
1126 s_gate.clone(),
1127 s_gate.clone(),
1128 ];
1129 let circuit2 = vec![];
1130
1131 assert!(checker
1133 .are_circuits_equivalent(&circuit1, &circuit2, 1)
1134 .unwrap());
1135 }
1136
1137 #[test]
1138 fn test_t_gate_equivalence() {
1139 let checker = EquivalenceChecker::new();
1140 let t_gate = QuantumGate::new(GateType::T, vec![0], None);
1141
1142 let circuit1 = vec![
1143 t_gate.clone(),
1144 t_gate.clone(),
1145 t_gate.clone(),
1146 t_gate.clone(),
1147 t_gate.clone(),
1148 t_gate.clone(),
1149 t_gate.clone(),
1150 t_gate.clone(),
1151 ];
1152 let circuit2 = vec![];
1153
1154 assert!(checker
1156 .are_circuits_equivalent(&circuit1, &circuit2, 1)
1157 .unwrap());
1158 }
1159
1160 #[test]
1161 fn test_sqrt_gate_equivalence() {
1162 let checker = EquivalenceChecker::new();
1163 let sqrt_x_gate = QuantumGate::new(GateType::SqrtX, vec![0], None);
1164
1165 let circuit1 = vec![sqrt_x_gate.clone(), sqrt_x_gate.clone()];
1166 let x_gate = QuantumGate::new(GateType::X, vec![0], None);
1167 let circuit2 = vec![x_gate];
1168
1169 assert!(checker
1171 .are_circuits_equivalent(&circuit1, &circuit2, 1)
1172 .unwrap());
1173 }
1174
1175 #[test]
1176 fn test_cz_gate_equivalence() {
1177 let checker = EquivalenceChecker::new();
1178 let cz_gate = QuantumGate::new(GateType::CZ, vec![0, 1], None);
1179
1180 let circuit1 = vec![cz_gate.clone(), cz_gate.clone()];
1181 let circuit2 = vec![];
1182
1183 assert!(checker
1185 .are_circuits_equivalent(&circuit1, &circuit2, 2)
1186 .unwrap());
1187 }
1188
1189 #[test]
1190 fn test_swap_gate_equivalence() {
1191 let checker = EquivalenceChecker::new();
1192 let swap_gate = QuantumGate::new(GateType::SWAP, vec![0, 1], None);
1193
1194 let circuit1 = vec![swap_gate.clone(), swap_gate.clone()];
1195 let circuit2 = vec![];
1196
1197 assert!(checker
1199 .are_circuits_equivalent(&circuit1, &circuit2, 2)
1200 .unwrap());
1201 }
1202
1203 #[test]
1204 fn test_iswap_gate_equivalence() {
1205 let checker = EquivalenceChecker::new();
1206 let iswap_gate = QuantumGate::new(GateType::ISwap, vec![0, 1], None);
1207
1208 let circuit1 = vec![
1210 iswap_gate.clone(),
1211 iswap_gate.clone(),
1212 iswap_gate.clone(),
1213 iswap_gate.clone(),
1214 ];
1215 let circuit2 = vec![];
1216
1217 assert!(checker
1219 .are_circuits_equivalent(&circuit1, &circuit2, 2)
1220 .unwrap());
1221 }
1222
1223 #[test]
1224 fn test_cnot_cz_hadamard_equivalence() {
1225 let checker = EquivalenceChecker::new();
1226
1227 let cnot1 = QuantumGate::new(GateType::CNOT, vec![0, 1], None);
1229 let cnot2 = QuantumGate::new(GateType::CNOT, vec![0, 1], None);
1230
1231 let circuit1 = vec![cnot1.clone(), cnot2.clone()];
1232 let circuit2 = vec![];
1233
1234 assert!(checker
1236 .are_circuits_equivalent(&circuit1, &circuit2, 2)
1237 .unwrap());
1238 }
1239
1240 #[test]
1241 fn test_advanced_equivalence_features() {
1242 let checker = EquivalenceChecker::new();
1243 let x_gate = QuantumGate::new(GateType::X, vec![0], None);
1244 let y_gate = QuantumGate::new(GateType::Y, vec![0], None);
1245
1246 let circuit1 = vec![x_gate.clone()];
1247 let circuit2 = vec![y_gate];
1248
1249 let result = checker
1250 .advanced_equivalence_check(&circuit1, &circuit2, 1)
1251 .unwrap();
1252
1253 assert!(!result.equivalent);
1255
1256 let x_circuit = vec![x_gate.clone()];
1258 let xx_circuit = vec![x_gate.clone(), x_gate.clone()];
1259
1260 let result2 = checker
1261 .advanced_equivalence_check(&x_circuit, &xx_circuit, 1)
1262 .unwrap();
1263
1264 assert!(!result2.equivalent);
1266 }
1267}