1use std::collections::HashMap;
7use std::fmt;
8use std::sync::Arc;
9
10pub type CircuitBuilder<const N: usize> = Circuit<N>;
12
13use quantrs2_core::{
14 decomposition::{utils as decomp_utils, CompositeGate},
15 error::QuantRS2Result,
16 gate::{
17 multi::{
18 Fredkin,
19 ISwap,
20 Toffoli,
21 CH,
22 CNOT,
23 CRX,
24 CRY,
25 CRZ,
26 CS,
27 CY,
28 CZ,
29 DCX,
31 ECR,
32 RXX,
33 RYY,
34 RZX,
35 RZZ,
36 SWAP,
37 },
38 single::{
39 Hadamard,
40 Identity,
42 PGate,
43 PauliX,
44 PauliY,
45 PauliZ,
46 Phase,
47 PhaseDagger,
48 RotationX,
49 RotationY,
50 RotationZ,
51 SqrtX,
52 SqrtXDagger,
53 TDagger,
54 UGate,
55 T,
56 },
57 GateOp,
58 },
59 qubit::QubitId,
60 register::Register,
61};
62
63use scirs2_core::Complex64;
64use std::any::Any;
65use std::collections::HashSet;
66
67#[derive(Debug, Clone)]
69pub struct CircuitStats {
70 pub total_gates: usize,
72 pub gate_counts: HashMap<String, usize>,
74 pub depth: usize,
76 pub two_qubit_gates: usize,
78 pub multi_qubit_gates: usize,
80 pub gate_density: f64,
82 pub used_qubits: usize,
84 pub total_qubits: usize,
86}
87
88#[derive(Debug, Clone)]
90pub struct GatePool {
91 gates: HashMap<String, Arc<dyn GateOp + Send + Sync>>,
93}
94
95impl GatePool {
96 #[must_use]
98 pub fn new() -> Self {
99 let mut gates = HashMap::with_capacity(16);
100
101 for qubit_id in 0..32 {
103 let qubit = QubitId::new(qubit_id);
104
105 gates.insert(
107 format!("H_{qubit_id}"),
108 Arc::new(Hadamard { target: qubit }) as Arc<dyn GateOp + Send + Sync>,
109 );
110 gates.insert(
111 format!("X_{qubit_id}"),
112 Arc::new(PauliX { target: qubit }) as Arc<dyn GateOp + Send + Sync>,
113 );
114 gates.insert(
115 format!("Y_{qubit_id}"),
116 Arc::new(PauliY { target: qubit }) as Arc<dyn GateOp + Send + Sync>,
117 );
118 gates.insert(
119 format!("Z_{qubit_id}"),
120 Arc::new(PauliZ { target: qubit }) as Arc<dyn GateOp + Send + Sync>,
121 );
122 gates.insert(
123 format!("S_{qubit_id}"),
124 Arc::new(Phase { target: qubit }) as Arc<dyn GateOp + Send + Sync>,
125 );
126 gates.insert(
127 format!("T_{qubit_id}"),
128 Arc::new(T { target: qubit }) as Arc<dyn GateOp + Send + Sync>,
129 );
130 }
131
132 Self { gates }
133 }
134
135 pub fn get_gate<G: GateOp + Clone + Send + Sync + 'static>(
137 &mut self,
138 gate: G,
139 ) -> Arc<dyn GateOp + Send + Sync> {
140 let key = format!("{}_{:?}", gate.name(), gate.qubits());
141
142 if let Some(cached_gate) = self.gates.get(&key) {
143 cached_gate.clone()
144 } else {
145 let arc_gate = Arc::new(gate) as Arc<dyn GateOp + Send + Sync>;
146 self.gates.insert(key, arc_gate.clone());
147 arc_gate
148 }
149 }
150}
151
152impl Default for GatePool {
153 fn default() -> Self {
154 Self::new()
155 }
156}
157
158#[derive(Debug, Clone)]
160pub struct Measure {
161 pub target: QubitId,
162}
163
164impl GateOp for Measure {
165 fn name(&self) -> &'static str {
166 "measure"
167 }
168
169 fn qubits(&self) -> Vec<QubitId> {
170 vec![self.target]
171 }
172
173 fn is_parameterized(&self) -> bool {
174 false
175 }
176
177 fn matrix(&self) -> QuantRS2Result<Vec<Complex64>> {
178 Ok(vec![
180 Complex64::new(1.0, 0.0),
181 Complex64::new(0.0, 0.0),
182 Complex64::new(0.0, 0.0),
183 Complex64::new(1.0, 0.0),
184 ])
185 }
186
187 fn as_any(&self) -> &dyn Any {
188 self
189 }
190
191 fn clone_gate(&self) -> Box<dyn GateOp> {
192 Box::new(self.clone())
193 }
194}
195
196pub struct Circuit<const N: usize> {
198 gates: Vec<Arc<dyn GateOp + Send + Sync>>,
200 gate_pool: GatePool,
202}
203
204impl<const N: usize> Clone for Circuit<N> {
205 fn clone(&self) -> Self {
206 Self {
208 gates: self.gates.clone(),
209 gate_pool: self.gate_pool.clone(),
210 }
211 }
212}
213
214impl<const N: usize> fmt::Debug for Circuit<N> {
215 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
216 f.debug_struct("Circuit")
217 .field("num_qubits", &N)
218 .field("num_gates", &self.gates.len())
219 .finish()
220 }
221}
222
223impl<const N: usize> Circuit<N> {
224 #[must_use]
226 pub fn new() -> Self {
227 Self {
228 gates: Vec::with_capacity(64), gate_pool: GatePool::new(),
230 }
231 }
232
233 #[must_use]
235 pub fn with_capacity(capacity: usize) -> Self {
236 Self {
237 gates: Vec::with_capacity(capacity),
238 gate_pool: GatePool::new(),
239 }
240 }
241
242 pub fn add_gate<G: GateOp + Clone + Send + Sync + 'static>(
244 &mut self,
245 gate: G,
246 ) -> QuantRS2Result<&mut Self> {
247 for qubit in gate.qubits() {
249 if qubit.id() as usize >= N {
250 return Err(quantrs2_core::error::QuantRS2Error::InvalidInput(format!(
251 "Gate '{}' targets qubit {} which is out of range for {}-qubit circuit (valid range: 0-{})",
252 gate.name(),
253 qubit.id(),
254 N,
255 N - 1
256 )));
257 }
258 }
259
260 let gate_arc = self.gate_pool.get_gate(gate);
262 self.gates.push(gate_arc);
263 Ok(self)
264 }
265
266 pub fn add_gate_arc(
268 &mut self,
269 gate: Arc<dyn GateOp + Send + Sync>,
270 ) -> QuantRS2Result<&mut Self> {
271 for qubit in gate.qubits() {
273 if qubit.id() as usize >= N {
274 return Err(quantrs2_core::error::QuantRS2Error::InvalidInput(format!(
275 "Gate '{}' targets qubit {} which is out of range for {}-qubit circuit (valid range: 0-{})",
276 gate.name(),
277 qubit.id(),
278 N,
279 N - 1
280 )));
281 }
282 }
283
284 self.gates.push(gate);
285 Ok(self)
286 }
287
288 #[must_use]
290 pub fn gates(&self) -> &[Arc<dyn GateOp + Send + Sync>] {
291 &self.gates
292 }
293
294 #[must_use]
296 pub fn gates_as_boxes(&self) -> Vec<Box<dyn GateOp>> {
297 self.gates
298 .iter()
299 .map(|arc_gate| arc_gate.clone_gate())
300 .collect()
301 }
302
303 #[must_use]
307 pub fn count_gates_by_type(&self) -> HashMap<String, usize> {
308 let mut counts = HashMap::new();
309 for gate in &self.gates {
310 *counts.entry(gate.name().to_string()).or_insert(0) += 1;
311 }
312 counts
313 }
314
315 #[must_use]
317 pub fn calculate_depth(&self) -> usize {
318 if self.gates.is_empty() {
319 return 0;
320 }
321
322 let mut qubit_last_used = vec![0; N];
324 let mut max_depth = 0;
325
326 for (gate_idx, gate) in self.gates.iter().enumerate() {
327 let gate_qubits = gate.qubits();
328
329 let gate_start_depth = gate_qubits
331 .iter()
332 .map(|q| qubit_last_used[q.id() as usize])
333 .max()
334 .unwrap_or(0);
335
336 let gate_end_depth = gate_start_depth + 1;
337
338 for qubit in gate_qubits {
340 qubit_last_used[qubit.id() as usize] = gate_end_depth;
341 }
342
343 max_depth = max_depth.max(gate_end_depth);
344 }
345
346 max_depth
347 }
348
349 #[must_use]
351 pub fn count_two_qubit_gates(&self) -> usize {
352 self.gates
353 .iter()
354 .filter(|gate| gate.qubits().len() == 2)
355 .count()
356 }
357
358 #[must_use]
360 pub fn count_multi_qubit_gates(&self) -> usize {
361 self.gates
362 .iter()
363 .filter(|gate| gate.qubits().len() >= 3)
364 .count()
365 }
366
367 #[must_use]
369 pub fn calculate_critical_path(&self) -> usize {
370 self.calculate_depth()
371 }
372
373 #[must_use]
375 pub fn calculate_gate_density(&self) -> f64 {
376 if N == 0 {
377 0.0
378 } else {
379 self.gates.len() as f64 / N as f64
380 }
381 }
382
383 #[must_use]
385 pub fn get_used_qubits(&self) -> HashSet<QubitId> {
386 let mut used_qubits = HashSet::new();
387 for gate in &self.gates {
388 for qubit in gate.qubits() {
389 used_qubits.insert(qubit);
390 }
391 }
392 used_qubits
393 }
394
395 #[must_use]
397 pub fn uses_all_qubits(&self) -> bool {
398 self.get_used_qubits().len() == N
399 }
400
401 #[must_use]
403 pub fn gates_on_qubit(&self, target_qubit: QubitId) -> Vec<&Arc<dyn GateOp + Send + Sync>> {
404 self.gates
405 .iter()
406 .filter(|gate| gate.qubits().contains(&target_qubit))
407 .collect()
408 }
409
410 #[must_use]
412 pub fn gates_in_range(&self, start: usize, end: usize) -> &[Arc<dyn GateOp + Send + Sync>] {
413 let end = end.min(self.gates.len().saturating_sub(1));
414 let start = start.min(end);
415 &self.gates[start..=end]
416 }
417
418 #[must_use]
420 pub fn is_empty(&self) -> bool {
421 self.gates.is_empty()
422 }
423
424 #[must_use]
426 pub fn get_stats(&self) -> CircuitStats {
427 let gate_counts = self.count_gates_by_type();
428 let depth = self.calculate_depth();
429 let two_qubit_gates = self.count_two_qubit_gates();
430 let multi_qubit_gates = self.count_multi_qubit_gates();
431 let gate_density = self.calculate_gate_density();
432 let used_qubits = self.get_used_qubits().len();
433
434 CircuitStats {
435 total_gates: self.gates.len(),
436 gate_counts,
437 depth,
438 two_qubit_gates,
439 multi_qubit_gates,
440 gate_density,
441 used_qubits,
442 total_qubits: N,
443 }
444 }
445
446 #[must_use]
448 pub const fn num_qubits(&self) -> usize {
449 N
450 }
451
452 #[must_use]
454 pub fn num_gates(&self) -> usize {
455 self.gates.len()
456 }
457
458 #[must_use]
460 pub fn get_gate_names(&self) -> Vec<String> {
461 self.gates
462 .iter()
463 .map(|gate| gate.name().to_string())
464 .collect()
465 }
466
467 #[cfg(feature = "python")]
469 pub fn get_single_qubit_for_gate(&self, gate_type: &str, index: usize) -> pyo3::PyResult<u32> {
470 self.find_gate_by_type_and_index(gate_type, index)
471 .and_then(|gate| {
472 if gate.qubits().len() == 1 {
473 Some(gate.qubits()[0].id())
474 } else {
475 None
476 }
477 })
478 .ok_or_else(|| {
479 pyo3::exceptions::PyValueError::new_err(format!(
480 "Gate {gate_type} at index {index} not found or is not a single-qubit gate"
481 ))
482 })
483 }
484
485 #[cfg(feature = "python")]
487 pub fn get_rotation_params_for_gate(
488 &self,
489 gate_type: &str,
490 index: usize,
491 ) -> pyo3::PyResult<(u32, f64)> {
492 self.find_gate_by_type_and_index(gate_type, index)
495 .and_then(|gate| {
496 if gate.qubits().len() == 1 {
497 Some((gate.qubits()[0].id(), 0.0))
499 } else {
500 None
501 }
502 })
503 .ok_or_else(|| {
504 pyo3::exceptions::PyValueError::new_err(format!(
505 "Gate {gate_type} at index {index} not found or is not a rotation gate"
506 ))
507 })
508 }
509
510 #[cfg(feature = "python")]
512 pub fn get_two_qubit_params_for_gate(
513 &self,
514 gate_type: &str,
515 index: usize,
516 ) -> pyo3::PyResult<(u32, u32)> {
517 self.find_gate_by_type_and_index(gate_type, index)
518 .and_then(|gate| {
519 if gate.qubits().len() == 2 {
520 Some((gate.qubits()[0].id(), gate.qubits()[1].id()))
521 } else {
522 None
523 }
524 })
525 .ok_or_else(|| {
526 pyo3::exceptions::PyValueError::new_err(format!(
527 "Gate {gate_type} at index {index} not found or is not a two-qubit gate"
528 ))
529 })
530 }
531
532 #[cfg(feature = "python")]
534 pub fn get_controlled_rotation_params_for_gate(
535 &self,
536 gate_type: &str,
537 index: usize,
538 ) -> pyo3::PyResult<(u32, u32, f64)> {
539 self.find_gate_by_type_and_index(gate_type, index)
542 .and_then(|gate| {
543 if gate.qubits().len() == 2 {
544 Some((gate.qubits()[0].id(), gate.qubits()[1].id(), 0.0))
546 } else {
547 None
548 }
549 })
550 .ok_or_else(|| {
551 pyo3::exceptions::PyValueError::new_err(format!(
552 "Gate {gate_type} at index {index} not found or is not a controlled rotation gate"
553 ))
554 })
555 }
556
557 #[cfg(feature = "python")]
559 pub fn get_three_qubit_params_for_gate(
560 &self,
561 gate_type: &str,
562 index: usize,
563 ) -> pyo3::PyResult<(u32, u32, u32)> {
564 self.find_gate_by_type_and_index(gate_type, index)
565 .and_then(|gate| {
566 if gate.qubits().len() == 3 {
567 Some((
568 gate.qubits()[0].id(),
569 gate.qubits()[1].id(),
570 gate.qubits()[2].id(),
571 ))
572 } else {
573 None
574 }
575 })
576 .ok_or_else(|| {
577 pyo3::exceptions::PyValueError::new_err(format!(
578 "Gate {gate_type} at index {index} not found or is not a three-qubit gate"
579 ))
580 })
581 }
582
583 fn find_gate_by_type_and_index(&self, gate_type: &str, index: usize) -> Option<&dyn GateOp> {
585 let mut count = 0;
586 for gate in &self.gates {
587 if gate.name() == gate_type {
588 if count == index {
589 return Some(gate.as_ref());
590 }
591 count += 1;
592 }
593 }
594 None
595 }
596
597 pub fn h(&mut self, target: impl Into<QubitId>) -> QuantRS2Result<&mut Self> {
599 self.add_gate(Hadamard {
600 target: target.into(),
601 })
602 }
603
604 pub fn x(&mut self, target: impl Into<QubitId>) -> QuantRS2Result<&mut Self> {
606 self.add_gate(PauliX {
607 target: target.into(),
608 })
609 }
610
611 pub fn y(&mut self, target: impl Into<QubitId>) -> QuantRS2Result<&mut Self> {
613 self.add_gate(PauliY {
614 target: target.into(),
615 })
616 }
617
618 pub fn z(&mut self, target: impl Into<QubitId>) -> QuantRS2Result<&mut Self> {
620 self.add_gate(PauliZ {
621 target: target.into(),
622 })
623 }
624
625 pub fn rx(&mut self, target: impl Into<QubitId>, theta: f64) -> QuantRS2Result<&mut Self> {
627 self.add_gate(RotationX {
628 target: target.into(),
629 theta,
630 })
631 }
632
633 pub fn ry(&mut self, target: impl Into<QubitId>, theta: f64) -> QuantRS2Result<&mut Self> {
635 self.add_gate(RotationY {
636 target: target.into(),
637 theta,
638 })
639 }
640
641 pub fn rz(&mut self, target: impl Into<QubitId>, theta: f64) -> QuantRS2Result<&mut Self> {
643 self.add_gate(RotationZ {
644 target: target.into(),
645 theta,
646 })
647 }
648
649 pub fn s(&mut self, target: impl Into<QubitId>) -> QuantRS2Result<&mut Self> {
651 self.add_gate(Phase {
652 target: target.into(),
653 })
654 }
655
656 pub fn sdg(&mut self, target: impl Into<QubitId>) -> QuantRS2Result<&mut Self> {
658 self.add_gate(PhaseDagger {
659 target: target.into(),
660 })
661 }
662
663 pub fn t(&mut self, target: impl Into<QubitId>) -> QuantRS2Result<&mut Self> {
665 self.add_gate(T {
666 target: target.into(),
667 })
668 }
669
670 pub fn tdg(&mut self, target: impl Into<QubitId>) -> QuantRS2Result<&mut Self> {
672 self.add_gate(TDagger {
673 target: target.into(),
674 })
675 }
676
677 pub fn sx(&mut self, target: impl Into<QubitId>) -> QuantRS2Result<&mut Self> {
679 self.add_gate(SqrtX {
680 target: target.into(),
681 })
682 }
683
684 pub fn sxdg(&mut self, target: impl Into<QubitId>) -> QuantRS2Result<&mut Self> {
686 self.add_gate(SqrtXDagger {
687 target: target.into(),
688 })
689 }
690
691 pub fn cnot(
693 &mut self,
694 control: impl Into<QubitId>,
695 target: impl Into<QubitId>,
696 ) -> QuantRS2Result<&mut Self> {
697 self.add_gate(CNOT {
698 control: control.into(),
699 target: target.into(),
700 })
701 }
702
703 pub fn cx(
705 &mut self,
706 control: impl Into<QubitId>,
707 target: impl Into<QubitId>,
708 ) -> QuantRS2Result<&mut Self> {
709 self.cnot(control, target)
710 }
711
712 pub fn cy(
714 &mut self,
715 control: impl Into<QubitId>,
716 target: impl Into<QubitId>,
717 ) -> QuantRS2Result<&mut Self> {
718 self.add_gate(CY {
719 control: control.into(),
720 target: target.into(),
721 })
722 }
723
724 pub fn cz(
726 &mut self,
727 control: impl Into<QubitId>,
728 target: impl Into<QubitId>,
729 ) -> QuantRS2Result<&mut Self> {
730 self.add_gate(CZ {
731 control: control.into(),
732 target: target.into(),
733 })
734 }
735
736 pub fn ch(
738 &mut self,
739 control: impl Into<QubitId>,
740 target: impl Into<QubitId>,
741 ) -> QuantRS2Result<&mut Self> {
742 self.add_gate(CH {
743 control: control.into(),
744 target: target.into(),
745 })
746 }
747
748 pub fn cs(
750 &mut self,
751 control: impl Into<QubitId>,
752 target: impl Into<QubitId>,
753 ) -> QuantRS2Result<&mut Self> {
754 self.add_gate(CS {
755 control: control.into(),
756 target: target.into(),
757 })
758 }
759
760 pub fn crx(
762 &mut self,
763 control: impl Into<QubitId>,
764 target: impl Into<QubitId>,
765 theta: f64,
766 ) -> QuantRS2Result<&mut Self> {
767 self.add_gate(CRX {
768 control: control.into(),
769 target: target.into(),
770 theta,
771 })
772 }
773
774 pub fn cry(
776 &mut self,
777 control: impl Into<QubitId>,
778 target: impl Into<QubitId>,
779 theta: f64,
780 ) -> QuantRS2Result<&mut Self> {
781 self.add_gate(CRY {
782 control: control.into(),
783 target: target.into(),
784 theta,
785 })
786 }
787
788 pub fn crz(
790 &mut self,
791 control: impl Into<QubitId>,
792 target: impl Into<QubitId>,
793 theta: f64,
794 ) -> QuantRS2Result<&mut Self> {
795 self.add_gate(CRZ {
796 control: control.into(),
797 target: target.into(),
798 theta,
799 })
800 }
801
802 pub fn cp(
804 &mut self,
805 control: impl Into<QubitId>,
806 target: impl Into<QubitId>,
807 lambda: f64,
808 ) -> QuantRS2Result<&mut Self> {
809 self.crz(control, target, lambda)
811 }
812
813 pub fn swap(
815 &mut self,
816 qubit1: impl Into<QubitId>,
817 qubit2: impl Into<QubitId>,
818 ) -> QuantRS2Result<&mut Self> {
819 self.add_gate(SWAP {
820 qubit1: qubit1.into(),
821 qubit2: qubit2.into(),
822 })
823 }
824
825 pub fn toffoli(
827 &mut self,
828 control1: impl Into<QubitId>,
829 control2: impl Into<QubitId>,
830 target: impl Into<QubitId>,
831 ) -> QuantRS2Result<&mut Self> {
832 self.add_gate(Toffoli {
833 control1: control1.into(),
834 control2: control2.into(),
835 target: target.into(),
836 })
837 }
838
839 pub fn cswap(
841 &mut self,
842 control: impl Into<QubitId>,
843 target1: impl Into<QubitId>,
844 target2: impl Into<QubitId>,
845 ) -> QuantRS2Result<&mut Self> {
846 self.add_gate(Fredkin {
847 control: control.into(),
848 target1: target1.into(),
849 target2: target2.into(),
850 })
851 }
852
853 pub fn u(
860 &mut self,
861 target: impl Into<QubitId>,
862 theta: f64,
863 phi: f64,
864 lambda: f64,
865 ) -> QuantRS2Result<&mut Self> {
866 self.add_gate(UGate {
867 target: target.into(),
868 theta,
869 phi,
870 lambda,
871 })
872 }
873
874 pub fn p(&mut self, target: impl Into<QubitId>, lambda: f64) -> QuantRS2Result<&mut Self> {
878 self.add_gate(PGate {
879 target: target.into(),
880 lambda,
881 })
882 }
883
884 pub fn id(&mut self, target: impl Into<QubitId>) -> QuantRS2Result<&mut Self> {
886 self.add_gate(Identity {
887 target: target.into(),
888 })
889 }
890
891 pub fn iswap(
895 &mut self,
896 qubit1: impl Into<QubitId>,
897 qubit2: impl Into<QubitId>,
898 ) -> QuantRS2Result<&mut Self> {
899 self.add_gate(ISwap {
900 qubit1: qubit1.into(),
901 qubit2: qubit2.into(),
902 })
903 }
904
905 pub fn ecr(
907 &mut self,
908 control: impl Into<QubitId>,
909 target: impl Into<QubitId>,
910 ) -> QuantRS2Result<&mut Self> {
911 self.add_gate(ECR {
912 control: control.into(),
913 target: target.into(),
914 })
915 }
916
917 pub fn rxx(
921 &mut self,
922 qubit1: impl Into<QubitId>,
923 qubit2: impl Into<QubitId>,
924 theta: f64,
925 ) -> QuantRS2Result<&mut Self> {
926 self.add_gate(RXX {
927 qubit1: qubit1.into(),
928 qubit2: qubit2.into(),
929 theta,
930 })
931 }
932
933 pub fn ryy(
937 &mut self,
938 qubit1: impl Into<QubitId>,
939 qubit2: impl Into<QubitId>,
940 theta: f64,
941 ) -> QuantRS2Result<&mut Self> {
942 self.add_gate(RYY {
943 qubit1: qubit1.into(),
944 qubit2: qubit2.into(),
945 theta,
946 })
947 }
948
949 pub fn rzz(
953 &mut self,
954 qubit1: impl Into<QubitId>,
955 qubit2: impl Into<QubitId>,
956 theta: f64,
957 ) -> QuantRS2Result<&mut Self> {
958 self.add_gate(RZZ {
959 qubit1: qubit1.into(),
960 qubit2: qubit2.into(),
961 theta,
962 })
963 }
964
965 pub fn rzx(
969 &mut self,
970 control: impl Into<QubitId>,
971 target: impl Into<QubitId>,
972 theta: f64,
973 ) -> QuantRS2Result<&mut Self> {
974 self.add_gate(RZX {
975 control: control.into(),
976 target: target.into(),
977 theta,
978 })
979 }
980
981 pub fn dcx(
985 &mut self,
986 qubit1: impl Into<QubitId>,
987 qubit2: impl Into<QubitId>,
988 ) -> QuantRS2Result<&mut Self> {
989 self.add_gate(DCX {
990 qubit1: qubit1.into(),
991 qubit2: qubit2.into(),
992 })
993 }
994
995 pub fn ccx(
997 &mut self,
998 control1: impl Into<QubitId>,
999 control2: impl Into<QubitId>,
1000 target: impl Into<QubitId>,
1001 ) -> QuantRS2Result<&mut Self> {
1002 self.toffoli(control1, control2, target)
1003 }
1004
1005 pub fn fredkin(
1007 &mut self,
1008 control: impl Into<QubitId>,
1009 target1: impl Into<QubitId>,
1010 target2: impl Into<QubitId>,
1011 ) -> QuantRS2Result<&mut Self> {
1012 self.cswap(control, target1, target2)
1013 }
1014
1015 pub fn measure(&mut self, qubit: impl Into<QubitId>) -> QuantRS2Result<&mut Self> {
1020 let qubit_id = qubit.into();
1021 self.add_gate(Measure { target: qubit_id })?;
1022 Ok(self)
1023 }
1024
1025 pub fn reset(&mut self, _qubit: impl Into<QubitId>) -> QuantRS2Result<&mut Self> {
1030 Err(quantrs2_core::error::QuantRS2Error::UnsupportedOperation(
1031 "Reset operation is not yet implemented. Reset requires special quantum state manipulation.".to_string()
1032 ))
1033 }
1034
1035 pub fn barrier(&mut self, qubits: &[QubitId]) -> QuantRS2Result<&mut Self> {
1041 for &qubit in qubits {
1043 if qubit.id() as usize >= N {
1044 return Err(quantrs2_core::error::QuantRS2Error::InvalidQubitId(
1045 qubit.id(),
1046 ));
1047 }
1048 }
1049
1050 Ok(self)
1056 }
1057
1058 pub fn run<S: Simulator<N>>(&self, simulator: S) -> QuantRS2Result<Register<N>> {
1060 simulator.run(self)
1061 }
1062
1063 pub fn decompose(&self) -> QuantRS2Result<Self> {
1068 let mut decomposed = Self::new();
1069
1070 let boxed_gates = self.gates_as_boxes();
1072
1073 let simple_gates = decomp_utils::decompose_circuit(&boxed_gates)?;
1075
1076 for gate in simple_gates {
1078 decomposed.add_gate_box(gate)?;
1079 }
1080
1081 Ok(decomposed)
1082 }
1083
1084 #[must_use]
1086 pub const fn build(self) -> Self {
1087 self
1088 }
1089
1090 pub fn optimize(&self) -> QuantRS2Result<Self> {
1095 let mut optimized = Self::new();
1096
1097 let boxed_gates = self.gates_as_boxes();
1099
1100 let simplified_gates_result = decomp_utils::optimize_gate_sequence(&boxed_gates);
1102
1103 if let Ok(simplified_gates) = simplified_gates_result {
1105 for g in simplified_gates {
1107 optimized.add_gate_box(g)?;
1108 }
1109 }
1110
1111 Ok(optimized)
1112 }
1113
1114 fn add_gate_box(&mut self, gate: Box<dyn GateOp>) -> QuantRS2Result<&mut Self> {
1117 for qubit in gate.qubits() {
1119 if qubit.id() as usize >= N {
1120 return Err(quantrs2_core::error::QuantRS2Error::InvalidInput(format!(
1121 "Gate '{}' targets qubit {} which is out of range for {}-qubit circuit (valid range: 0-{})",
1122 gate.name(),
1123 qubit.id(),
1124 N,
1125 N - 1
1126 )));
1127 }
1128 }
1129
1130 let cloned_gate = gate.clone_gate();
1133
1134 if let Some(h_gate) = cloned_gate.as_any().downcast_ref::<Hadamard>() {
1136 self.gates
1137 .push(Arc::new(*h_gate) as Arc<dyn GateOp + Send + Sync>);
1138 } else if let Some(x_gate) = cloned_gate.as_any().downcast_ref::<PauliX>() {
1139 self.gates
1140 .push(Arc::new(*x_gate) as Arc<dyn GateOp + Send + Sync>);
1141 } else if let Some(y_gate) = cloned_gate.as_any().downcast_ref::<PauliY>() {
1142 self.gates
1143 .push(Arc::new(*y_gate) as Arc<dyn GateOp + Send + Sync>);
1144 } else if let Some(z_gate) = cloned_gate.as_any().downcast_ref::<PauliZ>() {
1145 self.gates
1146 .push(Arc::new(*z_gate) as Arc<dyn GateOp + Send + Sync>);
1147 } else if let Some(cnot_gate) = cloned_gate.as_any().downcast_ref::<CNOT>() {
1148 self.gates
1149 .push(Arc::new(*cnot_gate) as Arc<dyn GateOp + Send + Sync>);
1150 } else if let Some(measure_gate) = cloned_gate.as_any().downcast_ref::<Measure>() {
1151 self.gates
1152 .push(Arc::new(measure_gate.clone()) as Arc<dyn GateOp + Send + Sync>);
1153 } else {
1154 return Err(quantrs2_core::error::QuantRS2Error::UnsupportedOperation(
1157 format!(
1158 "Gate type '{}' not yet supported in Arc conversion",
1159 gate.name()
1160 ),
1161 ));
1162 }
1163
1164 Ok(self)
1165 }
1166
1167 pub fn create_composite(
1172 &self,
1173 start_idx: usize,
1174 end_idx: usize,
1175 name: &str,
1176 ) -> QuantRS2Result<CompositeGate> {
1177 if start_idx >= self.gates.len() || end_idx > self.gates.len() || start_idx >= end_idx {
1178 return Err(quantrs2_core::error::QuantRS2Error::InvalidInput(format!(
1179 "Invalid start/end indices ({}/{}) for circuit with {} gates",
1180 start_idx,
1181 end_idx,
1182 self.gates.len()
1183 )));
1184 }
1185
1186 let mut gates: Vec<Box<dyn GateOp>> = Vec::new();
1189 for gate in &self.gates[start_idx..end_idx] {
1190 gates.push(decomp_utils::clone_gate(gate.as_ref())?);
1191 }
1192
1193 let mut qubits = Vec::new();
1195 for gate in &gates {
1196 for qubit in gate.qubits() {
1197 if !qubits.contains(&qubit) {
1198 qubits.push(qubit);
1199 }
1200 }
1201 }
1202
1203 Ok(CompositeGate {
1204 gates,
1205 qubits,
1206 name: name.to_string(),
1207 })
1208 }
1209
1210 pub fn add_composite(&mut self, composite: &CompositeGate) -> QuantRS2Result<&mut Self> {
1212 for gate in &composite.gates {
1214 let gate_clone = decomp_utils::clone_gate(gate.as_ref())?;
1219 self.add_gate_box(gate_clone)?;
1220 }
1221
1222 Ok(self)
1223 }
1224
1225 pub fn measure_all(&mut self) -> QuantRS2Result<&mut Self> {
1229 for i in 0..N {
1230 self.measure(QubitId(i as u32))?;
1231 }
1232 Ok(self)
1233 }
1234
1235 #[must_use]
1237 pub fn with_classical_control(self) -> crate::classical::ClassicalCircuit<N> {
1238 let mut classical_circuit = crate::classical::ClassicalCircuit::new();
1239
1240 let _ = classical_circuit.add_classical_register("c", N);
1242
1243 for gate in self.gates {
1245 let boxed_gate = gate.clone_gate();
1246 classical_circuit
1247 .operations
1248 .push(crate::classical::CircuitOp::Quantum(boxed_gate));
1249 }
1250
1251 classical_circuit
1252 }
1253
1254 pub fn h_all(&mut self, qubits: &[u32]) -> QuantRS2Result<&mut Self> {
1264 for &qubit in qubits {
1265 self.h(QubitId::new(qubit))?;
1266 }
1267 Ok(self)
1268 }
1269
1270 pub fn x_all(&mut self, qubits: &[u32]) -> QuantRS2Result<&mut Self> {
1278 for &qubit in qubits {
1279 self.x(QubitId::new(qubit))?;
1280 }
1281 Ok(self)
1282 }
1283
1284 pub fn y_all(&mut self, qubits: &[u32]) -> QuantRS2Result<&mut Self> {
1286 for &qubit in qubits {
1287 self.y(QubitId::new(qubit))?;
1288 }
1289 Ok(self)
1290 }
1291
1292 pub fn z_all(&mut self, qubits: &[u32]) -> QuantRS2Result<&mut Self> {
1294 for &qubit in qubits {
1295 self.z(QubitId::new(qubit))?;
1296 }
1297 Ok(self)
1298 }
1299
1300 pub fn h_range(&mut self, range: std::ops::Range<u32>) -> QuantRS2Result<&mut Self> {
1308 for qubit in range {
1309 self.h(QubitId::new(qubit))?;
1310 }
1311 Ok(self)
1312 }
1313
1314 pub fn x_range(&mut self, range: std::ops::Range<u32>) -> QuantRS2Result<&mut Self> {
1316 for qubit in range {
1317 self.x(QubitId::new(qubit))?;
1318 }
1319 Ok(self)
1320 }
1321
1322 pub fn bell_state(&mut self, qubit1: u32, qubit2: u32) -> QuantRS2Result<&mut Self> {
1332 self.h(QubitId::new(qubit1))?;
1333 self.cnot(QubitId::new(qubit1), QubitId::new(qubit2))?;
1334 Ok(self)
1335 }
1336
1337 pub fn ghz_state(&mut self, qubits: &[u32]) -> QuantRS2Result<&mut Self> {
1345 if qubits.is_empty() {
1346 return Ok(self);
1347 }
1348
1349 self.h(QubitId::new(qubits[0]))?;
1351
1352 for i in 1..qubits.len() {
1354 self.cnot(QubitId::new(qubits[0]), QubitId::new(qubits[i]))?;
1355 }
1356
1357 Ok(self)
1358 }
1359
1360 pub fn w_state(&mut self, qubits: &[u32]) -> QuantRS2Result<&mut Self> {
1366 if qubits.is_empty() {
1367 return Ok(self);
1368 }
1369
1370 let n = qubits.len() as f64;
1371
1372 self.ry(QubitId::new(qubits[0]), 2.0 * (1.0 / n.sqrt()).acos())?;
1375
1376 for i in 1..qubits.len() {
1377 let angle = 2.0 * (1.0 / (n - i as f64).sqrt()).acos();
1378 self.cry(QubitId::new(qubits[i - 1]), QubitId::new(qubits[i]), angle)?;
1379 }
1380
1381 for i in 0..qubits.len() - 1 {
1383 self.cnot(QubitId::new(qubits[i + 1]), QubitId::new(qubits[i]))?;
1384 }
1385
1386 Ok(self)
1387 }
1388
1389 pub fn plus_state_all(&mut self) -> QuantRS2Result<&mut Self> {
1397 for i in 0..N {
1398 self.h(QubitId::new(i as u32))?;
1399 }
1400 Ok(self)
1401 }
1402
1403 pub fn rx_all(&mut self, qubits: &[u32], theta: f64) -> QuantRS2Result<&mut Self> {
1405 for &qubit in qubits {
1406 self.rx(QubitId::new(qubit), theta)?;
1407 }
1408 Ok(self)
1409 }
1410
1411 pub fn ry_all(&mut self, qubits: &[u32], theta: f64) -> QuantRS2Result<&mut Self> {
1413 for &qubit in qubits {
1414 self.ry(QubitId::new(qubit), theta)?;
1415 }
1416 Ok(self)
1417 }
1418
1419 pub fn rz_all(&mut self, qubits: &[u32], theta: f64) -> QuantRS2Result<&mut Self> {
1421 for &qubit in qubits {
1422 self.rz(QubitId::new(qubit), theta)?;
1423 }
1424 Ok(self)
1425 }
1426
1427 pub fn cnot_ladder(&mut self, qubits: &[u32]) -> QuantRS2Result<&mut Self> {
1435 if qubits.len() < 2 {
1436 return Ok(self);
1437 }
1438
1439 for i in 0..qubits.len() - 1 {
1440 self.cnot(QubitId::new(qubits[i]), QubitId::new(qubits[i + 1]))?;
1441 }
1442
1443 Ok(self)
1444 }
1445
1446 pub fn cnot_ring(&mut self, qubits: &[u32]) -> QuantRS2Result<&mut Self> {
1450 if qubits.len() < 2 {
1451 return Ok(self);
1452 }
1453
1454 self.cnot_ladder(qubits)?;
1456
1457 let last_idx = qubits.len() - 1;
1459 self.cnot(QubitId::new(qubits[last_idx]), QubitId::new(qubits[0]))?;
1460
1461 Ok(self)
1462 }
1463
1464 pub fn swap_ladder(&mut self, qubits: &[u32]) -> QuantRS2Result<&mut Self> {
1472 if qubits.len() < 2 {
1473 return Ok(self);
1474 }
1475
1476 for i in 0..qubits.len() - 1 {
1477 self.swap(QubitId::new(qubits[i]), QubitId::new(qubits[i + 1]))?;
1478 }
1479
1480 Ok(self)
1481 }
1482
1483 pub fn cz_ladder(&mut self, qubits: &[u32]) -> QuantRS2Result<&mut Self> {
1491 if qubits.len() < 2 {
1492 return Ok(self);
1493 }
1494
1495 for i in 0..qubits.len() - 1 {
1496 self.cz(QubitId::new(qubits[i]), QubitId::new(qubits[i + 1]))?;
1497 }
1498
1499 Ok(self)
1500 }
1501
1502 pub fn swap_all(&mut self, pairs: &[(u32, u32)]) -> QuantRS2Result<&mut Self> {
1513 for &(q1, q2) in pairs {
1514 self.swap(QubitId::new(q1), QubitId::new(q2))?;
1515 }
1516 Ok(self)
1517 }
1518
1519 pub fn cz_all(&mut self, pairs: &[(u32, u32)]) -> QuantRS2Result<&mut Self> {
1530 for &(q1, q2) in pairs {
1531 self.cz(QubitId::new(q1), QubitId::new(q2))?;
1532 }
1533 Ok(self)
1534 }
1535
1536 pub fn cnot_all(&mut self, pairs: &[(u32, u32)]) -> QuantRS2Result<&mut Self> {
1547 for &(control, target) in pairs {
1548 self.cnot(QubitId::new(control), QubitId::new(target))?;
1549 }
1550 Ok(self)
1551 }
1552
1553 pub fn barrier_all(&mut self, qubits: &[u32]) -> QuantRS2Result<&mut Self> {
1566 let qubit_ids: Vec<QubitId> = qubits.iter().map(|&q| QubitId::new(q)).collect();
1567 self.barrier(&qubit_ids)?;
1568 Ok(self)
1569 }
1570}
1571
1572impl<const N: usize> Default for Circuit<N> {
1573 fn default() -> Self {
1574 Self::new()
1575 }
1576}
1577
1578pub trait Simulator<const N: usize> {
1580 fn run(&self, circuit: &Circuit<N>) -> QuantRS2Result<Register<N>>;
1582}
1583
1584#[cfg(test)]
1585mod tests {
1586 use super::*;
1587
1588 #[test]
1589 fn test_h_all() -> QuantRS2Result<()> {
1590 let mut circuit = Circuit::<5>::new();
1591 circuit.h_all(&[0, 1, 2])?;
1592
1593 assert_eq!(circuit.gates().len(), 3);
1594 for gate in circuit.gates() {
1595 assert_eq!(gate.name(), "H");
1596 }
1597 Ok(())
1598 }
1599
1600 #[test]
1601 fn test_x_all() -> QuantRS2Result<()> {
1602 let mut circuit = Circuit::<5>::new();
1603 circuit.x_all(&[0, 2, 4])?;
1604
1605 assert_eq!(circuit.gates().len(), 3);
1606 for gate in circuit.gates() {
1607 assert_eq!(gate.name(), "X");
1608 }
1609 Ok(())
1610 }
1611
1612 #[test]
1613 fn test_y_all() -> QuantRS2Result<()> {
1614 let mut circuit = Circuit::<3>::new();
1615 circuit.y_all(&[0, 1, 2])?;
1616
1617 assert_eq!(circuit.gates().len(), 3);
1618 for gate in circuit.gates() {
1619 assert_eq!(gate.name(), "Y");
1620 }
1621 Ok(())
1622 }
1623
1624 #[test]
1625 fn test_z_all() -> QuantRS2Result<()> {
1626 let mut circuit = Circuit::<4>::new();
1627 circuit.z_all(&[1, 3])?;
1628
1629 assert_eq!(circuit.gates().len(), 2);
1630 for gate in circuit.gates() {
1631 assert_eq!(gate.name(), "Z");
1632 }
1633 Ok(())
1634 }
1635
1636 #[test]
1637 fn test_h_range() -> QuantRS2Result<()> {
1638 let mut circuit = Circuit::<5>::new();
1639 circuit.h_range(0..3)?;
1640
1641 assert_eq!(circuit.gates().len(), 3);
1642 for gate in circuit.gates() {
1643 assert_eq!(gate.name(), "H");
1644 }
1645 Ok(())
1646 }
1647
1648 #[test]
1649 fn test_x_range() -> QuantRS2Result<()> {
1650 let mut circuit = Circuit::<5>::new();
1651 circuit.x_range(1..4)?;
1652
1653 assert_eq!(circuit.gates().len(), 3);
1654 for gate in circuit.gates() {
1655 assert_eq!(gate.name(), "X");
1656 }
1657 Ok(())
1658 }
1659
1660 #[test]
1661 fn test_bell_state() -> QuantRS2Result<()> {
1662 let mut circuit = Circuit::<2>::new();
1663 circuit.bell_state(0, 1)?;
1664
1665 assert_eq!(circuit.gates().len(), 2);
1666 assert_eq!(circuit.gates()[0].name(), "H");
1667 assert_eq!(circuit.gates()[1].name(), "CNOT");
1668 Ok(())
1669 }
1670
1671 #[test]
1672 fn test_ghz_state() -> QuantRS2Result<()> {
1673 let mut circuit = Circuit::<4>::new();
1674 circuit.ghz_state(&[0, 1, 2, 3])?;
1675
1676 assert_eq!(circuit.gates().len(), 4);
1678 assert_eq!(circuit.gates()[0].name(), "H");
1679 for i in 1..4 {
1680 assert_eq!(circuit.gates()[i].name(), "CNOT");
1681 }
1682 Ok(())
1683 }
1684
1685 #[test]
1686 fn test_ghz_state_empty() -> QuantRS2Result<()> {
1687 let mut circuit = Circuit::<4>::new();
1688 circuit.ghz_state(&[])?;
1689
1690 assert_eq!(circuit.gates().len(), 0);
1691 Ok(())
1692 }
1693
1694 #[test]
1695 fn test_w_state() -> QuantRS2Result<()> {
1696 let mut circuit = Circuit::<3>::new();
1697 circuit.w_state(&[0, 1, 2])?;
1698
1699 assert!(!circuit.gates().is_empty());
1701 assert!(circuit
1703 .gates()
1704 .iter()
1705 .any(|g| g.name() == "RY" || g.name() == "CRY"));
1706 Ok(())
1707 }
1708
1709 #[test]
1710 fn test_w_state_empty() -> QuantRS2Result<()> {
1711 let mut circuit = Circuit::<3>::new();
1712 circuit.w_state(&[])?;
1713
1714 assert_eq!(circuit.gates().len(), 0);
1715 Ok(())
1716 }
1717
1718 #[test]
1719 fn test_plus_state_all() -> QuantRS2Result<()> {
1720 let mut circuit = Circuit::<4>::new();
1721 circuit.plus_state_all()?;
1722
1723 assert_eq!(circuit.gates().len(), 4);
1724 for gate in circuit.gates() {
1725 assert_eq!(gate.name(), "H");
1726 }
1727 Ok(())
1728 }
1729
1730 #[test]
1731 fn test_rx_all() -> QuantRS2Result<()> {
1732 let mut circuit = Circuit::<4>::new();
1733 let theta = std::f64::consts::PI / 4.0;
1734 circuit.rx_all(&[0, 1, 2], theta)?;
1735
1736 assert_eq!(circuit.gates().len(), 3);
1737 for gate in circuit.gates() {
1738 assert_eq!(gate.name(), "RX");
1739 }
1740 Ok(())
1741 }
1742
1743 #[test]
1744 fn test_ry_all() -> QuantRS2Result<()> {
1745 let mut circuit = Circuit::<4>::new();
1746 let theta = std::f64::consts::PI / 3.0;
1747 circuit.ry_all(&[0, 2], theta)?;
1748
1749 assert_eq!(circuit.gates().len(), 2);
1750 for gate in circuit.gates() {
1751 assert_eq!(gate.name(), "RY");
1752 }
1753 Ok(())
1754 }
1755
1756 #[test]
1757 fn test_rz_all() -> QuantRS2Result<()> {
1758 let mut circuit = Circuit::<5>::new();
1759 let theta = std::f64::consts::PI / 2.0;
1760 circuit.rz_all(&[1, 2, 3], theta)?;
1761
1762 assert_eq!(circuit.gates().len(), 3);
1763 for gate in circuit.gates() {
1764 assert_eq!(gate.name(), "RZ");
1765 }
1766 Ok(())
1767 }
1768
1769 #[test]
1770 fn test_cnot_ladder() -> QuantRS2Result<()> {
1771 let mut circuit = Circuit::<5>::new();
1772 circuit.cnot_ladder(&[0, 1, 2, 3])?;
1773
1774 assert_eq!(circuit.gates().len(), 3);
1775 for gate in circuit.gates() {
1776 assert_eq!(gate.name(), "CNOT");
1777 }
1778 Ok(())
1779 }
1780
1781 #[test]
1782 fn test_cnot_ladder_too_small() -> QuantRS2Result<()> {
1783 let mut circuit = Circuit::<5>::new();
1784 circuit.cnot_ladder(&[0])?;
1785
1786 assert_eq!(circuit.gates().len(), 0);
1787 Ok(())
1788 }
1789
1790 #[test]
1791 fn test_cnot_ring() -> QuantRS2Result<()> {
1792 let mut circuit = Circuit::<4>::new();
1793 circuit.cnot_ring(&[0, 1, 2, 3])?;
1794
1795 assert_eq!(circuit.gates().len(), 4);
1797 for gate in circuit.gates() {
1798 assert_eq!(gate.name(), "CNOT");
1799 }
1800 Ok(())
1801 }
1802
1803 #[test]
1804 fn test_cnot_ring_too_small() -> QuantRS2Result<()> {
1805 let mut circuit = Circuit::<4>::new();
1806 circuit.cnot_ring(&[0])?;
1807
1808 assert_eq!(circuit.gates().len(), 0);
1809 Ok(())
1810 }
1811
1812 #[test]
1813 fn test_combined_patterns() -> QuantRS2Result<()> {
1814 let mut circuit = Circuit::<5>::new();
1815
1816 circuit.plus_state_all()?;
1818
1819 circuit.cnot_ladder(&[0, 1, 2, 3, 4])?;
1821
1822 circuit.z_all(&[0, 2, 4])?;
1824
1825 let stats = circuit.get_stats();
1826 assert_eq!(stats.total_gates, 5 + 4 + 3); assert_eq!(stats.total_qubits, 5);
1828 Ok(())
1829 }
1830
1831 #[test]
1832 fn test_swap_ladder() -> QuantRS2Result<()> {
1833 let mut circuit = Circuit::<5>::new();
1834 circuit.swap_ladder(&[0, 1, 2, 3])?;
1835
1836 assert_eq!(circuit.gates().len(), 3); for gate in circuit.gates() {
1838 assert_eq!(gate.name(), "SWAP");
1839 }
1840 Ok(())
1841 }
1842
1843 #[test]
1844 fn test_swap_ladder_empty() -> QuantRS2Result<()> {
1845 let mut circuit = Circuit::<5>::new();
1846 circuit.swap_ladder(&[])?;
1847
1848 assert_eq!(circuit.gates().len(), 0);
1849 Ok(())
1850 }
1851
1852 #[test]
1853 fn test_swap_ladder_single() -> QuantRS2Result<()> {
1854 let mut circuit = Circuit::<5>::new();
1855 circuit.swap_ladder(&[0])?;
1856
1857 assert_eq!(circuit.gates().len(), 0);
1858 Ok(())
1859 }
1860
1861 #[test]
1862 fn test_cz_ladder() -> QuantRS2Result<()> {
1863 let mut circuit = Circuit::<4>::new();
1864 circuit.cz_ladder(&[0, 1, 2, 3])?;
1865
1866 assert_eq!(circuit.gates().len(), 3); for gate in circuit.gates() {
1868 assert_eq!(gate.name(), "CZ");
1869 }
1870 Ok(())
1871 }
1872
1873 #[test]
1874 fn test_cz_ladder_empty() -> QuantRS2Result<()> {
1875 let mut circuit = Circuit::<4>::new();
1876 circuit.cz_ladder(&[])?;
1877
1878 assert_eq!(circuit.gates().len(), 0);
1879 Ok(())
1880 }
1881
1882 #[test]
1883 fn test_swap_all() -> QuantRS2Result<()> {
1884 let mut circuit = Circuit::<6>::new();
1885 circuit.swap_all(&[(0, 1), (2, 3), (4, 5)])?;
1886
1887 assert_eq!(circuit.gates().len(), 3);
1888 for gate in circuit.gates() {
1889 assert_eq!(gate.name(), "SWAP");
1890 }
1891 Ok(())
1892 }
1893
1894 #[test]
1895 fn test_swap_all_empty() -> QuantRS2Result<()> {
1896 let mut circuit = Circuit::<6>::new();
1897 circuit.swap_all(&[])?;
1898
1899 assert_eq!(circuit.gates().len(), 0);
1900 Ok(())
1901 }
1902
1903 #[test]
1904 fn test_cz_all() -> QuantRS2Result<()> {
1905 let mut circuit = Circuit::<6>::new();
1906 circuit.cz_all(&[(0, 1), (2, 3), (4, 5)])?;
1907
1908 assert_eq!(circuit.gates().len(), 3);
1909 for gate in circuit.gates() {
1910 assert_eq!(gate.name(), "CZ");
1911 }
1912 Ok(())
1913 }
1914
1915 #[test]
1916 fn test_cz_all_empty() -> QuantRS2Result<()> {
1917 let mut circuit = Circuit::<6>::new();
1918 circuit.cz_all(&[])?;
1919
1920 assert_eq!(circuit.gates().len(), 0);
1921 Ok(())
1922 }
1923
1924 #[test]
1925 fn test_cnot_all() -> QuantRS2Result<()> {
1926 let mut circuit = Circuit::<6>::new();
1927 circuit.cnot_all(&[(0, 1), (2, 3), (4, 5)])?;
1928
1929 assert_eq!(circuit.gates().len(), 3);
1930 for gate in circuit.gates() {
1931 assert_eq!(gate.name(), "CNOT");
1932 }
1933 Ok(())
1934 }
1935
1936 #[test]
1937 fn test_cnot_all_empty() -> QuantRS2Result<()> {
1938 let mut circuit = Circuit::<6>::new();
1939 circuit.cnot_all(&[])?;
1940
1941 assert_eq!(circuit.gates().len(), 0);
1942 Ok(())
1943 }
1944
1945 #[test]
1946 fn test_barrier_all() -> QuantRS2Result<()> {
1947 let mut circuit = Circuit::<5>::new();
1948 circuit.h_all(&[0, 1, 2])?;
1949 circuit.barrier_all(&[0, 1, 2])?;
1950 circuit.cnot_ladder(&[0, 1, 2])?;
1951
1952 assert_eq!(circuit.gates().len(), 5);
1955 Ok(())
1956 }
1957
1958 #[test]
1959 fn test_barrier_all_empty() -> QuantRS2Result<()> {
1960 let mut circuit = Circuit::<5>::new();
1961 circuit.barrier_all(&[])?;
1962
1963 assert_eq!(circuit.gates().len(), 0);
1964 Ok(())
1965 }
1966
1967 #[test]
1968 fn test_advanced_entanglement_patterns() -> QuantRS2Result<()> {
1969 let mut circuit = Circuit::<6>::new();
1970
1971 circuit.h_all(&[0, 1, 2, 3, 4, 5])?;
1973
1974 circuit.barrier_all(&[0, 1, 2, 3, 4, 5])?;
1976
1977 circuit.cz_ladder(&[0, 1, 2, 3, 4, 5])?;
1979
1980 circuit.cnot_all(&[(0, 3), (1, 4), (2, 5)])?;
1982
1983 let stats = circuit.get_stats();
1984 assert_eq!(stats.total_gates, 14);
1986 assert_eq!(stats.total_qubits, 6);
1987 Ok(())
1988 }
1989}