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::{Fredkin, Toffoli, CH, CNOT, CRX, CRY, CRZ, CS, CY, CZ, SWAP},
18 single::{
19 Hadamard, PauliX, PauliY, PauliZ, Phase, PhaseDagger, RotationX, RotationY, RotationZ,
20 SqrtX, SqrtXDagger, TDagger, T,
21 },
22 GateOp,
23 },
24 qubit::QubitId,
25 register::Register,
26};
27
28use scirs2_core::Complex64;
29use std::any::Any;
30use std::collections::HashSet;
31
32#[derive(Debug, Clone)]
34pub struct CircuitStats {
35 pub total_gates: usize,
37 pub gate_counts: HashMap<String, usize>,
39 pub depth: usize,
41 pub two_qubit_gates: usize,
43 pub multi_qubit_gates: usize,
45 pub gate_density: f64,
47 pub used_qubits: usize,
49 pub total_qubits: usize,
51}
52
53#[derive(Debug, Clone)]
55pub struct GatePool {
56 gates: HashMap<String, Arc<dyn GateOp + Send + Sync>>,
58}
59
60impl GatePool {
61 pub fn new() -> Self {
63 let mut gates = HashMap::with_capacity(16);
64
65 for qubit_id in 0..32 {
67 let qubit = QubitId::new(qubit_id);
68
69 gates.insert(
71 format!("H_{}", qubit_id),
72 Arc::new(Hadamard { target: qubit }) as Arc<dyn GateOp + Send + Sync>,
73 );
74 gates.insert(
75 format!("X_{}", qubit_id),
76 Arc::new(PauliX { target: qubit }) as Arc<dyn GateOp + Send + Sync>,
77 );
78 gates.insert(
79 format!("Y_{}", qubit_id),
80 Arc::new(PauliY { target: qubit }) as Arc<dyn GateOp + Send + Sync>,
81 );
82 gates.insert(
83 format!("Z_{}", qubit_id),
84 Arc::new(PauliZ { target: qubit }) as Arc<dyn GateOp + Send + Sync>,
85 );
86 gates.insert(
87 format!("S_{}", qubit_id),
88 Arc::new(Phase { target: qubit }) as Arc<dyn GateOp + Send + Sync>,
89 );
90 gates.insert(
91 format!("T_{}", qubit_id),
92 Arc::new(T { target: qubit }) as Arc<dyn GateOp + Send + Sync>,
93 );
94 }
95
96 Self { gates }
97 }
98
99 pub fn get_gate<G: GateOp + Clone + Send + Sync + 'static>(
101 &mut self,
102 gate: G,
103 ) -> Arc<dyn GateOp + Send + Sync> {
104 let key = format!("{}_{:?}", gate.name(), gate.qubits());
105
106 if let Some(cached_gate) = self.gates.get(&key) {
107 cached_gate.clone()
108 } else {
109 let arc_gate = Arc::new(gate) as Arc<dyn GateOp + Send + Sync>;
110 self.gates.insert(key, arc_gate.clone());
111 arc_gate
112 }
113 }
114}
115
116impl Default for GatePool {
117 fn default() -> Self {
118 Self::new()
119 }
120}
121
122#[derive(Debug, Clone)]
124pub struct Measure {
125 pub target: QubitId,
126}
127
128impl GateOp for Measure {
129 fn name(&self) -> &'static str {
130 "measure"
131 }
132
133 fn qubits(&self) -> Vec<QubitId> {
134 vec![self.target]
135 }
136
137 fn is_parameterized(&self) -> bool {
138 false
139 }
140
141 fn matrix(&self) -> QuantRS2Result<Vec<Complex64>> {
142 Ok(vec![
144 Complex64::new(1.0, 0.0),
145 Complex64::new(0.0, 0.0),
146 Complex64::new(0.0, 0.0),
147 Complex64::new(1.0, 0.0),
148 ])
149 }
150
151 fn as_any(&self) -> &dyn Any {
152 self
153 }
154
155 fn clone_gate(&self) -> Box<dyn GateOp> {
156 Box::new(self.clone())
157 }
158}
159
160pub struct Circuit<const N: usize> {
162 gates: Vec<Arc<dyn GateOp + Send + Sync>>,
164 gate_pool: GatePool,
166}
167
168impl<const N: usize> Clone for Circuit<N> {
169 fn clone(&self) -> Self {
170 Self {
172 gates: self.gates.clone(),
173 gate_pool: self.gate_pool.clone(),
174 }
175 }
176}
177
178impl<const N: usize> fmt::Debug for Circuit<N> {
179 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
180 f.debug_struct("Circuit")
181 .field("num_qubits", &N)
182 .field("num_gates", &self.gates.len())
183 .finish()
184 }
185}
186
187impl<const N: usize> Circuit<N> {
188 pub fn new() -> Self {
190 Self {
191 gates: Vec::with_capacity(64), gate_pool: GatePool::new(),
193 }
194 }
195
196 pub fn with_capacity(capacity: usize) -> Self {
198 Self {
199 gates: Vec::with_capacity(capacity),
200 gate_pool: GatePool::new(),
201 }
202 }
203
204 pub fn add_gate<G: GateOp + Clone + Send + Sync + 'static>(
206 &mut self,
207 gate: G,
208 ) -> QuantRS2Result<&mut Self> {
209 for qubit in gate.qubits() {
211 if qubit.id() as usize >= N {
212 return Err(quantrs2_core::error::QuantRS2Error::InvalidInput(format!(
213 "Gate '{}' targets qubit {} which is out of range for {}-qubit circuit (valid range: 0-{})",
214 gate.name(),
215 qubit.id(),
216 N,
217 N - 1
218 )));
219 }
220 }
221
222 let gate_arc = self.gate_pool.get_gate(gate);
224 self.gates.push(gate_arc);
225 Ok(self)
226 }
227
228 pub fn add_gate_arc(
230 &mut self,
231 gate: Arc<dyn GateOp + Send + Sync>,
232 ) -> QuantRS2Result<&mut Self> {
233 for qubit in gate.qubits() {
235 if qubit.id() as usize >= N {
236 return Err(quantrs2_core::error::QuantRS2Error::InvalidInput(format!(
237 "Gate '{}' targets qubit {} which is out of range for {}-qubit circuit (valid range: 0-{})",
238 gate.name(),
239 qubit.id(),
240 N,
241 N - 1
242 )));
243 }
244 }
245
246 self.gates.push(gate);
247 Ok(self)
248 }
249
250 pub fn gates(&self) -> &[Arc<dyn GateOp + Send + Sync>] {
252 &self.gates
253 }
254
255 pub fn gates_as_boxes(&self) -> Vec<Box<dyn GateOp>> {
257 self.gates
258 .iter()
259 .map(|arc_gate| arc_gate.clone_gate())
260 .collect()
261 }
262
263 pub fn count_gates_by_type(&self) -> HashMap<String, usize> {
267 let mut counts = HashMap::new();
268 for gate in &self.gates {
269 *counts.entry(gate.name().to_string()).or_insert(0) += 1;
270 }
271 counts
272 }
273
274 pub fn calculate_depth(&self) -> usize {
276 if self.gates.is_empty() {
277 return 0;
278 }
279
280 let mut qubit_last_used = vec![0; N];
282 let mut max_depth = 0;
283
284 for (gate_idx, gate) in self.gates.iter().enumerate() {
285 let gate_qubits = gate.qubits();
286
287 let gate_start_depth = gate_qubits
289 .iter()
290 .map(|q| qubit_last_used[q.id() as usize])
291 .max()
292 .unwrap_or(0);
293
294 let gate_end_depth = gate_start_depth + 1;
295
296 for qubit in gate_qubits {
298 qubit_last_used[qubit.id() as usize] = gate_end_depth;
299 }
300
301 max_depth = max_depth.max(gate_end_depth);
302 }
303
304 max_depth
305 }
306
307 pub fn count_two_qubit_gates(&self) -> usize {
309 self.gates
310 .iter()
311 .filter(|gate| gate.qubits().len() == 2)
312 .count()
313 }
314
315 pub fn count_multi_qubit_gates(&self) -> usize {
317 self.gates
318 .iter()
319 .filter(|gate| gate.qubits().len() >= 3)
320 .count()
321 }
322
323 pub fn calculate_critical_path(&self) -> usize {
325 self.calculate_depth()
326 }
327
328 pub fn calculate_gate_density(&self) -> f64 {
330 if N == 0 {
331 0.0
332 } else {
333 self.gates.len() as f64 / N as f64
334 }
335 }
336
337 pub fn get_used_qubits(&self) -> HashSet<QubitId> {
339 let mut used_qubits = HashSet::new();
340 for gate in &self.gates {
341 for qubit in gate.qubits() {
342 used_qubits.insert(qubit);
343 }
344 }
345 used_qubits
346 }
347
348 pub fn uses_all_qubits(&self) -> bool {
350 self.get_used_qubits().len() == N
351 }
352
353 pub fn gates_on_qubit(&self, target_qubit: QubitId) -> Vec<&Arc<dyn GateOp + Send + Sync>> {
355 self.gates
356 .iter()
357 .filter(|gate| gate.qubits().contains(&target_qubit))
358 .collect()
359 }
360
361 pub fn gates_in_range(&self, start: usize, end: usize) -> &[Arc<dyn GateOp + Send + Sync>] {
363 let end = end.min(self.gates.len().saturating_sub(1));
364 let start = start.min(end);
365 &self.gates[start..=end]
366 }
367
368 pub fn is_empty(&self) -> bool {
370 self.gates.is_empty()
371 }
372
373 pub fn get_stats(&self) -> CircuitStats {
375 let gate_counts = self.count_gates_by_type();
376 let depth = self.calculate_depth();
377 let two_qubit_gates = self.count_two_qubit_gates();
378 let multi_qubit_gates = self.count_multi_qubit_gates();
379 let gate_density = self.calculate_gate_density();
380 let used_qubits = self.get_used_qubits().len();
381
382 CircuitStats {
383 total_gates: self.gates.len(),
384 gate_counts,
385 depth,
386 two_qubit_gates,
387 multi_qubit_gates,
388 gate_density,
389 used_qubits,
390 total_qubits: N,
391 }
392 }
393
394 pub fn num_qubits(&self) -> usize {
396 N
397 }
398
399 pub fn num_gates(&self) -> usize {
401 self.gates.len()
402 }
403
404 pub fn get_gate_names(&self) -> Vec<String> {
406 self.gates
407 .iter()
408 .map(|gate| gate.name().to_string())
409 .collect()
410 }
411
412 pub fn get_single_qubit_for_gate(&self, gate_type: &str, index: usize) -> pyo3::PyResult<u32> {
414 self.find_gate_by_type_and_index(gate_type, index)
415 .and_then(|gate| {
416 if gate.qubits().len() == 1 {
417 Some(gate.qubits()[0].id())
418 } else {
419 None
420 }
421 })
422 .ok_or_else(|| {
423 pyo3::exceptions::PyValueError::new_err(format!(
424 "Gate {} at index {} not found or is not a single-qubit gate",
425 gate_type, index
426 ))
427 })
428 }
429
430 pub fn get_rotation_params_for_gate(
432 &self,
433 gate_type: &str,
434 index: usize,
435 ) -> pyo3::PyResult<(u32, f64)> {
436 self.find_gate_by_type_and_index(gate_type, index)
439 .and_then(|gate| {
440 if gate.qubits().len() == 1 {
441 Some((gate.qubits()[0].id(), 0.0))
443 } else {
444 None
445 }
446 })
447 .ok_or_else(|| {
448 pyo3::exceptions::PyValueError::new_err(format!(
449 "Gate {} at index {} not found or is not a rotation gate",
450 gate_type, index
451 ))
452 })
453 }
454
455 pub fn get_two_qubit_params_for_gate(
457 &self,
458 gate_type: &str,
459 index: usize,
460 ) -> pyo3::PyResult<(u32, u32)> {
461 self.find_gate_by_type_and_index(gate_type, index)
462 .and_then(|gate| {
463 if gate.qubits().len() == 2 {
464 Some((gate.qubits()[0].id(), gate.qubits()[1].id()))
465 } else {
466 None
467 }
468 })
469 .ok_or_else(|| {
470 pyo3::exceptions::PyValueError::new_err(format!(
471 "Gate {} at index {} not found or is not a two-qubit gate",
472 gate_type, index
473 ))
474 })
475 }
476
477 pub fn get_controlled_rotation_params_for_gate(
479 &self,
480 gate_type: &str,
481 index: usize,
482 ) -> pyo3::PyResult<(u32, u32, f64)> {
483 self.find_gate_by_type_and_index(gate_type, index)
486 .and_then(|gate| {
487 if gate.qubits().len() == 2 {
488 Some((gate.qubits()[0].id(), gate.qubits()[1].id(), 0.0))
490 } else {
491 None
492 }
493 })
494 .ok_or_else(|| {
495 pyo3::exceptions::PyValueError::new_err(format!(
496 "Gate {} at index {} not found or is not a controlled rotation gate",
497 gate_type, index
498 ))
499 })
500 }
501
502 pub fn get_three_qubit_params_for_gate(
504 &self,
505 gate_type: &str,
506 index: usize,
507 ) -> pyo3::PyResult<(u32, u32, u32)> {
508 self.find_gate_by_type_and_index(gate_type, index)
509 .and_then(|gate| {
510 if gate.qubits().len() == 3 {
511 Some((
512 gate.qubits()[0].id(),
513 gate.qubits()[1].id(),
514 gate.qubits()[2].id(),
515 ))
516 } else {
517 None
518 }
519 })
520 .ok_or_else(|| {
521 pyo3::exceptions::PyValueError::new_err(format!(
522 "Gate {} at index {} not found or is not a three-qubit gate",
523 gate_type, index
524 ))
525 })
526 }
527
528 fn find_gate_by_type_and_index(&self, gate_type: &str, index: usize) -> Option<&dyn GateOp> {
530 let mut count = 0;
531 for gate in &self.gates {
532 if gate.name() == gate_type {
533 if count == index {
534 return Some(gate.as_ref());
535 }
536 count += 1;
537 }
538 }
539 None
540 }
541
542 pub fn h(&mut self, target: impl Into<QubitId>) -> QuantRS2Result<&mut Self> {
544 self.add_gate(Hadamard {
545 target: target.into(),
546 })
547 }
548
549 pub fn x(&mut self, target: impl Into<QubitId>) -> QuantRS2Result<&mut Self> {
551 self.add_gate(PauliX {
552 target: target.into(),
553 })
554 }
555
556 pub fn y(&mut self, target: impl Into<QubitId>) -> QuantRS2Result<&mut Self> {
558 self.add_gate(PauliY {
559 target: target.into(),
560 })
561 }
562
563 pub fn z(&mut self, target: impl Into<QubitId>) -> QuantRS2Result<&mut Self> {
565 self.add_gate(PauliZ {
566 target: target.into(),
567 })
568 }
569
570 pub fn rx(&mut self, target: impl Into<QubitId>, theta: f64) -> QuantRS2Result<&mut Self> {
572 self.add_gate(RotationX {
573 target: target.into(),
574 theta,
575 })
576 }
577
578 pub fn ry(&mut self, target: impl Into<QubitId>, theta: f64) -> QuantRS2Result<&mut Self> {
580 self.add_gate(RotationY {
581 target: target.into(),
582 theta,
583 })
584 }
585
586 pub fn rz(&mut self, target: impl Into<QubitId>, theta: f64) -> QuantRS2Result<&mut Self> {
588 self.add_gate(RotationZ {
589 target: target.into(),
590 theta,
591 })
592 }
593
594 pub fn s(&mut self, target: impl Into<QubitId>) -> QuantRS2Result<&mut Self> {
596 self.add_gate(Phase {
597 target: target.into(),
598 })
599 }
600
601 pub fn sdg(&mut self, target: impl Into<QubitId>) -> QuantRS2Result<&mut Self> {
603 self.add_gate(PhaseDagger {
604 target: target.into(),
605 })
606 }
607
608 pub fn t(&mut self, target: impl Into<QubitId>) -> QuantRS2Result<&mut Self> {
610 self.add_gate(T {
611 target: target.into(),
612 })
613 }
614
615 pub fn tdg(&mut self, target: impl Into<QubitId>) -> QuantRS2Result<&mut Self> {
617 self.add_gate(TDagger {
618 target: target.into(),
619 })
620 }
621
622 pub fn sx(&mut self, target: impl Into<QubitId>) -> QuantRS2Result<&mut Self> {
624 self.add_gate(SqrtX {
625 target: target.into(),
626 })
627 }
628
629 pub fn sxdg(&mut self, target: impl Into<QubitId>) -> QuantRS2Result<&mut Self> {
631 self.add_gate(SqrtXDagger {
632 target: target.into(),
633 })
634 }
635
636 pub fn cnot(
638 &mut self,
639 control: impl Into<QubitId>,
640 target: impl Into<QubitId>,
641 ) -> QuantRS2Result<&mut Self> {
642 self.add_gate(CNOT {
643 control: control.into(),
644 target: target.into(),
645 })
646 }
647
648 pub fn cx(
650 &mut self,
651 control: impl Into<QubitId>,
652 target: impl Into<QubitId>,
653 ) -> QuantRS2Result<&mut Self> {
654 self.cnot(control, target)
655 }
656
657 pub fn cy(
659 &mut self,
660 control: impl Into<QubitId>,
661 target: impl Into<QubitId>,
662 ) -> QuantRS2Result<&mut Self> {
663 self.add_gate(CY {
664 control: control.into(),
665 target: target.into(),
666 })
667 }
668
669 pub fn cz(
671 &mut self,
672 control: impl Into<QubitId>,
673 target: impl Into<QubitId>,
674 ) -> QuantRS2Result<&mut Self> {
675 self.add_gate(CZ {
676 control: control.into(),
677 target: target.into(),
678 })
679 }
680
681 pub fn ch(
683 &mut self,
684 control: impl Into<QubitId>,
685 target: impl Into<QubitId>,
686 ) -> QuantRS2Result<&mut Self> {
687 self.add_gate(CH {
688 control: control.into(),
689 target: target.into(),
690 })
691 }
692
693 pub fn cs(
695 &mut self,
696 control: impl Into<QubitId>,
697 target: impl Into<QubitId>,
698 ) -> QuantRS2Result<&mut Self> {
699 self.add_gate(CS {
700 control: control.into(),
701 target: target.into(),
702 })
703 }
704
705 pub fn crx(
707 &mut self,
708 control: impl Into<QubitId>,
709 target: impl Into<QubitId>,
710 theta: f64,
711 ) -> QuantRS2Result<&mut Self> {
712 self.add_gate(CRX {
713 control: control.into(),
714 target: target.into(),
715 theta,
716 })
717 }
718
719 pub fn cry(
721 &mut self,
722 control: impl Into<QubitId>,
723 target: impl Into<QubitId>,
724 theta: f64,
725 ) -> QuantRS2Result<&mut Self> {
726 self.add_gate(CRY {
727 control: control.into(),
728 target: target.into(),
729 theta,
730 })
731 }
732
733 pub fn crz(
735 &mut self,
736 control: impl Into<QubitId>,
737 target: impl Into<QubitId>,
738 theta: f64,
739 ) -> QuantRS2Result<&mut Self> {
740 self.add_gate(CRZ {
741 control: control.into(),
742 target: target.into(),
743 theta,
744 })
745 }
746
747 pub fn cp(
749 &mut self,
750 control: impl Into<QubitId>,
751 target: impl Into<QubitId>,
752 lambda: f64,
753 ) -> QuantRS2Result<&mut Self> {
754 self.crz(control, target, lambda)
756 }
757
758 pub fn swap(
760 &mut self,
761 qubit1: impl Into<QubitId>,
762 qubit2: impl Into<QubitId>,
763 ) -> QuantRS2Result<&mut Self> {
764 self.add_gate(SWAP {
765 qubit1: qubit1.into(),
766 qubit2: qubit2.into(),
767 })
768 }
769
770 pub fn toffoli(
772 &mut self,
773 control1: impl Into<QubitId>,
774 control2: impl Into<QubitId>,
775 target: impl Into<QubitId>,
776 ) -> QuantRS2Result<&mut Self> {
777 self.add_gate(Toffoli {
778 control1: control1.into(),
779 control2: control2.into(),
780 target: target.into(),
781 })
782 }
783
784 pub fn cswap(
786 &mut self,
787 control: impl Into<QubitId>,
788 target1: impl Into<QubitId>,
789 target2: impl Into<QubitId>,
790 ) -> QuantRS2Result<&mut Self> {
791 self.add_gate(Fredkin {
792 control: control.into(),
793 target1: target1.into(),
794 target2: target2.into(),
795 })
796 }
797
798 pub fn measure(&mut self, qubit: impl Into<QubitId>) -> QuantRS2Result<&mut Self> {
803 let qubit_id = qubit.into();
804 self.add_gate(Measure { target: qubit_id })?;
805 Ok(self)
806 }
807
808 pub fn reset(&mut self, _qubit: impl Into<QubitId>) -> QuantRS2Result<&mut Self> {
813 Err(quantrs2_core::error::QuantRS2Error::UnsupportedOperation(
814 "Reset operation is not yet implemented. Reset requires special quantum state manipulation.".to_string()
815 ))
816 }
817
818 pub fn barrier(&mut self, qubits: &[QubitId]) -> QuantRS2Result<&mut Self> {
824 for &qubit in qubits {
826 if qubit.id() as usize >= N {
827 return Err(quantrs2_core::error::QuantRS2Error::InvalidQubitId(
828 qubit.id(),
829 ));
830 }
831 }
832
833 Ok(self)
839 }
840
841 pub fn run<S: Simulator<N>>(&self, simulator: S) -> QuantRS2Result<Register<N>> {
843 simulator.run(self)
844 }
845
846 pub fn decompose(&self) -> QuantRS2Result<Self> {
851 let mut decomposed = Self::new();
852
853 let boxed_gates = self.gates_as_boxes();
855
856 let simple_gates = decomp_utils::decompose_circuit(&boxed_gates)?;
858
859 for gate in simple_gates {
861 decomposed.add_gate_box(gate)?;
862 }
863
864 Ok(decomposed)
865 }
866
867 pub fn build(self) -> Self {
869 self
870 }
871
872 pub fn optimize(&self) -> QuantRS2Result<Self> {
877 let mut optimized = Self::new();
878
879 let boxed_gates = self.gates_as_boxes();
881
882 let simplified_gates_result = decomp_utils::optimize_gate_sequence(&boxed_gates);
884
885 if let Ok(simplified_gates) = simplified_gates_result {
887 for g in simplified_gates {
889 optimized.add_gate_box(g)?;
890 }
891 }
892
893 Ok(optimized)
894 }
895
896 fn add_gate_box(&mut self, gate: Box<dyn GateOp>) -> QuantRS2Result<&mut Self> {
899 for qubit in gate.qubits() {
901 if qubit.id() as usize >= N {
902 return Err(quantrs2_core::error::QuantRS2Error::InvalidInput(format!(
903 "Gate '{}' targets qubit {} which is out of range for {}-qubit circuit (valid range: 0-{})",
904 gate.name(),
905 qubit.id(),
906 N,
907 N - 1
908 )));
909 }
910 }
911
912 let cloned_gate = gate.clone_gate();
915
916 if let Some(h_gate) = cloned_gate.as_any().downcast_ref::<Hadamard>() {
918 self.gates
919 .push(Arc::new(h_gate.clone()) as Arc<dyn GateOp + Send + Sync>);
920 } else if let Some(x_gate) = cloned_gate.as_any().downcast_ref::<PauliX>() {
921 self.gates
922 .push(Arc::new(x_gate.clone()) as Arc<dyn GateOp + Send + Sync>);
923 } else if let Some(y_gate) = cloned_gate.as_any().downcast_ref::<PauliY>() {
924 self.gates
925 .push(Arc::new(y_gate.clone()) as Arc<dyn GateOp + Send + Sync>);
926 } else if let Some(z_gate) = cloned_gate.as_any().downcast_ref::<PauliZ>() {
927 self.gates
928 .push(Arc::new(z_gate.clone()) as Arc<dyn GateOp + Send + Sync>);
929 } else if let Some(cnot_gate) = cloned_gate.as_any().downcast_ref::<CNOT>() {
930 self.gates
931 .push(Arc::new(cnot_gate.clone()) as Arc<dyn GateOp + Send + Sync>);
932 } else if let Some(measure_gate) = cloned_gate.as_any().downcast_ref::<Measure>() {
933 self.gates
934 .push(Arc::new(measure_gate.clone()) as Arc<dyn GateOp + Send + Sync>);
935 } else {
936 return Err(quantrs2_core::error::QuantRS2Error::UnsupportedOperation(
939 format!(
940 "Gate type '{}' not yet supported in Arc conversion",
941 gate.name()
942 ),
943 ));
944 }
945
946 Ok(self)
947 }
948
949 pub fn create_composite(
954 &self,
955 start_idx: usize,
956 end_idx: usize,
957 name: &str,
958 ) -> QuantRS2Result<CompositeGate> {
959 if start_idx >= self.gates.len() || end_idx > self.gates.len() || start_idx >= end_idx {
960 return Err(quantrs2_core::error::QuantRS2Error::InvalidInput(format!(
961 "Invalid start/end indices ({}/{}) for circuit with {} gates",
962 start_idx,
963 end_idx,
964 self.gates.len()
965 )));
966 }
967
968 let mut gates: Vec<Box<dyn GateOp>> = Vec::new();
971 for gate in &self.gates[start_idx..end_idx] {
972 gates.push(decomp_utils::clone_gate(gate.as_ref())?);
973 }
974
975 let mut qubits = Vec::new();
977 for gate in &gates {
978 for qubit in gate.qubits() {
979 if !qubits.contains(&qubit) {
980 qubits.push(qubit);
981 }
982 }
983 }
984
985 Ok(CompositeGate {
986 gates,
987 qubits,
988 name: name.to_string(),
989 })
990 }
991
992 pub fn add_composite(&mut self, composite: &CompositeGate) -> QuantRS2Result<&mut Self> {
994 for gate in &composite.gates {
996 let gate_clone = decomp_utils::clone_gate(gate.as_ref())?;
1001 self.add_gate_box(gate_clone)?;
1002 }
1003
1004 Ok(self)
1005 }
1006
1007 pub fn measure_all(&mut self) -> QuantRS2Result<&mut Self> {
1011 for i in 0..N {
1012 self.measure(QubitId(i as u32))?;
1013 }
1014 Ok(self)
1015 }
1016
1017 pub fn with_classical_control(self) -> crate::classical::ClassicalCircuit<N> {
1019 let mut classical_circuit = crate::classical::ClassicalCircuit::new();
1020
1021 let _ = classical_circuit.add_classical_register("c", N);
1023
1024 for gate in self.gates {
1026 let boxed_gate = gate.clone_gate();
1027 classical_circuit
1028 .operations
1029 .push(crate::classical::CircuitOp::Quantum(boxed_gate));
1030 }
1031
1032 classical_circuit
1033 }
1034}
1035
1036impl<const N: usize> Default for Circuit<N> {
1037 fn default() -> Self {
1038 Self::new()
1039 }
1040}
1041
1042pub trait Simulator<const N: usize> {
1044 fn run(&self, circuit: &Circuit<N>) -> QuantRS2Result<Register<N>>;
1046}