1use scirs2_core::ndarray::{Array1, Array2};
9use scirs2_core::Complex64;
10use serde::{Deserialize, Serialize};
11use std::collections::hash_map::DefaultHasher;
12use std::collections::HashMap;
13use std::hash::{Hash, Hasher};
14use std::sync::{Arc, Mutex};
15
16use crate::error::{Result, SimulatorError};
17use crate::scirs2_integration::SciRS2Backend;
18use crate::sparse::CSRMatrix;
19use crate::statevector::StateVectorSimulator;
20#[cfg(feature = "advanced_math")]
21#[allow(unused_imports)]
22use crate::tensor_network::TensorNetwork;
23
24#[derive(Debug, Clone)]
26pub struct CircuitInterfaceConfig {
27 pub auto_backend_selection: bool,
29 pub enable_optimization: bool,
31 pub max_statevector_qubits: usize,
33 pub max_mps_bond_dim: usize,
35 pub parallel_compilation: bool,
37 pub enable_circuit_cache: bool,
39 pub max_cache_size: usize,
41 pub enable_profiling: bool,
43}
44
45impl Default for CircuitInterfaceConfig {
46 fn default() -> Self {
47 Self {
48 auto_backend_selection: true,
49 enable_optimization: true,
50 max_statevector_qubits: 25,
51 max_mps_bond_dim: 1024,
52 parallel_compilation: true,
53 enable_circuit_cache: true,
54 max_cache_size: 10000,
55 enable_profiling: true,
56 }
57 }
58}
59
60#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
62pub enum InterfaceGateType {
63 Identity,
65 PauliX,
66 X, PauliY,
68 PauliZ,
69 Hadamard,
70 H, S,
72 T,
73 Phase(f64),
74 RX(f64),
75 RY(f64),
76 RZ(f64),
77 U1(f64),
78 U2(f64, f64),
79 U3(f64, f64, f64),
80 CNOT,
82 CZ,
83 CY,
84 SWAP,
85 ISwap,
86 CRX(f64),
87 CRY(f64),
88 CRZ(f64),
89 CPhase(f64),
90 Toffoli,
92 Fredkin,
93 MultiControlledX(usize), MultiControlledZ(usize),
96 Custom(String, Array2<Complex64>),
98 Measure,
100 Reset,
101}
102
103impl std::hash::Hash for InterfaceGateType {
105 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
106 use std::mem;
107 match self {
108 InterfaceGateType::Identity => 0u8.hash(state),
109 InterfaceGateType::PauliX => 1u8.hash(state),
110 InterfaceGateType::X => 2u8.hash(state),
111 InterfaceGateType::PauliY => 3u8.hash(state),
112 InterfaceGateType::PauliZ => 4u8.hash(state),
113 InterfaceGateType::Hadamard => 5u8.hash(state),
114 InterfaceGateType::H => 6u8.hash(state),
115 InterfaceGateType::S => 7u8.hash(state),
116 InterfaceGateType::T => 8u8.hash(state),
117 InterfaceGateType::Phase(angle) => {
118 9u8.hash(state);
119 angle.to_bits().hash(state);
120 }
121 InterfaceGateType::RX(angle) => {
122 10u8.hash(state);
123 angle.to_bits().hash(state);
124 }
125 InterfaceGateType::RY(angle) => {
126 11u8.hash(state);
127 angle.to_bits().hash(state);
128 }
129 InterfaceGateType::RZ(angle) => {
130 12u8.hash(state);
131 angle.to_bits().hash(state);
132 }
133 InterfaceGateType::U1(angle) => {
134 13u8.hash(state);
135 angle.to_bits().hash(state);
136 }
137 InterfaceGateType::U2(theta, phi) => {
138 14u8.hash(state);
139 theta.to_bits().hash(state);
140 phi.to_bits().hash(state);
141 }
142 InterfaceGateType::U3(theta, phi, lambda) => {
143 15u8.hash(state);
144 theta.to_bits().hash(state);
145 phi.to_bits().hash(state);
146 lambda.to_bits().hash(state);
147 }
148 InterfaceGateType::CNOT => 16u8.hash(state),
149 InterfaceGateType::CZ => 17u8.hash(state),
150 InterfaceGateType::CY => 18u8.hash(state),
151 InterfaceGateType::SWAP => 19u8.hash(state),
152 InterfaceGateType::ISwap => 20u8.hash(state),
153 InterfaceGateType::CRX(angle) => {
154 21u8.hash(state);
155 angle.to_bits().hash(state);
156 }
157 InterfaceGateType::CRY(angle) => {
158 22u8.hash(state);
159 angle.to_bits().hash(state);
160 }
161 InterfaceGateType::CRZ(angle) => {
162 23u8.hash(state);
163 angle.to_bits().hash(state);
164 }
165 InterfaceGateType::CPhase(angle) => {
166 24u8.hash(state);
167 angle.to_bits().hash(state);
168 }
169 InterfaceGateType::Toffoli => 25u8.hash(state),
170 InterfaceGateType::Fredkin => 26u8.hash(state),
171 InterfaceGateType::MultiControlledX(n) => {
172 27u8.hash(state);
173 n.hash(state);
174 }
175 InterfaceGateType::MultiControlledZ(n) => {
176 28u8.hash(state);
177 n.hash(state);
178 }
179 InterfaceGateType::Custom(name, matrix) => {
180 29u8.hash(state);
181 name.hash(state);
182 matrix.shape().hash(state);
184 }
185 InterfaceGateType::Measure => 30u8.hash(state),
186 InterfaceGateType::Reset => 31u8.hash(state),
187 }
188 }
189}
190
191impl Eq for InterfaceGateType {}
193
194#[derive(Debug, Clone, Serialize, Deserialize)]
196pub struct InterfaceGate {
197 pub gate_type: InterfaceGateType,
199 pub qubits: Vec<usize>,
201 pub classical_targets: Vec<usize>,
203 pub position: usize,
205 pub condition: Option<usize>,
207 pub label: Option<String>,
209}
210
211impl InterfaceGate {
212 pub fn new(gate_type: InterfaceGateType, qubits: Vec<usize>) -> Self {
214 Self {
215 gate_type,
216 qubits,
217 classical_targets: Vec::new(),
218 position: 0,
219 condition: None,
220 label: None,
221 }
222 }
223
224 pub fn measurement(qubit: usize, classical_bit: usize) -> Self {
226 Self {
227 gate_type: InterfaceGateType::Measure,
228 qubits: vec![qubit],
229 classical_targets: vec![classical_bit],
230 position: 0,
231 condition: None,
232 label: None,
233 }
234 }
235
236 pub fn conditional(mut self, condition: usize) -> Self {
238 self.condition = Some(condition);
239 self
240 }
241
242 pub fn with_label(mut self, label: String) -> Self {
244 self.label = Some(label);
245 self
246 }
247
248 pub fn unitary_matrix(&self) -> Result<Array2<Complex64>> {
250 match &self.gate_type {
251 InterfaceGateType::Identity => Ok(Array2::eye(2)),
252 InterfaceGateType::PauliX => Ok(Array2::from_shape_vec(
253 (2, 2),
254 vec![
255 Complex64::new(0.0, 0.0),
256 Complex64::new(1.0, 0.0),
257 Complex64::new(1.0, 0.0),
258 Complex64::new(0.0, 0.0),
259 ],
260 )
261 .unwrap()),
262 InterfaceGateType::PauliY => Ok(Array2::from_shape_vec(
263 (2, 2),
264 vec![
265 Complex64::new(0.0, 0.0),
266 Complex64::new(0.0, -1.0),
267 Complex64::new(0.0, 1.0),
268 Complex64::new(0.0, 0.0),
269 ],
270 )
271 .unwrap()),
272 InterfaceGateType::PauliZ => Ok(Array2::from_shape_vec(
273 (2, 2),
274 vec![
275 Complex64::new(1.0, 0.0),
276 Complex64::new(0.0, 0.0),
277 Complex64::new(0.0, 0.0),
278 Complex64::new(-1.0, 0.0),
279 ],
280 )
281 .unwrap()),
282 InterfaceGateType::Hadamard => {
283 let inv_sqrt2 = 1.0 / (2.0_f64).sqrt();
284 Ok(Array2::from_shape_vec(
285 (2, 2),
286 vec![
287 Complex64::new(inv_sqrt2, 0.0),
288 Complex64::new(inv_sqrt2, 0.0),
289 Complex64::new(inv_sqrt2, 0.0),
290 Complex64::new(-inv_sqrt2, 0.0),
291 ],
292 )
293 .unwrap())
294 }
295 InterfaceGateType::S => Ok(Array2::from_shape_vec(
296 (2, 2),
297 vec![
298 Complex64::new(1.0, 0.0),
299 Complex64::new(0.0, 0.0),
300 Complex64::new(0.0, 0.0),
301 Complex64::new(0.0, 1.0),
302 ],
303 )
304 .unwrap()),
305 InterfaceGateType::T => {
306 let phase = Complex64::new(0.0, std::f64::consts::PI / 4.0).exp();
307 Ok(Array2::from_shape_vec(
308 (2, 2),
309 vec![
310 Complex64::new(1.0, 0.0),
311 Complex64::new(0.0, 0.0),
312 Complex64::new(0.0, 0.0),
313 phase,
314 ],
315 )
316 .unwrap())
317 }
318 InterfaceGateType::Phase(theta) => {
319 let phase = Complex64::new(0.0, *theta).exp();
320 Ok(Array2::from_shape_vec(
321 (2, 2),
322 vec![
323 Complex64::new(1.0, 0.0),
324 Complex64::new(0.0, 0.0),
325 Complex64::new(0.0, 0.0),
326 phase,
327 ],
328 )
329 .unwrap())
330 }
331 InterfaceGateType::RX(theta) => {
332 let cos_half = (theta / 2.0).cos();
333 let sin_half = (theta / 2.0).sin();
334 Ok(Array2::from_shape_vec(
335 (2, 2),
336 vec![
337 Complex64::new(cos_half, 0.0),
338 Complex64::new(0.0, -sin_half),
339 Complex64::new(0.0, -sin_half),
340 Complex64::new(cos_half, 0.0),
341 ],
342 )
343 .unwrap())
344 }
345 InterfaceGateType::RY(theta) => {
346 let cos_half = (theta / 2.0).cos();
347 let sin_half = (theta / 2.0).sin();
348 Ok(Array2::from_shape_vec(
349 (2, 2),
350 vec![
351 Complex64::new(cos_half, 0.0),
352 Complex64::new(-sin_half, 0.0),
353 Complex64::new(sin_half, 0.0),
354 Complex64::new(cos_half, 0.0),
355 ],
356 )
357 .unwrap())
358 }
359 InterfaceGateType::RZ(theta) => {
360 let exp_neg = Complex64::new(0.0, -theta / 2.0).exp();
361 let exp_pos = Complex64::new(0.0, theta / 2.0).exp();
362 Ok(Array2::from_shape_vec(
363 (2, 2),
364 vec![
365 exp_neg,
366 Complex64::new(0.0, 0.0),
367 Complex64::new(0.0, 0.0),
368 exp_pos,
369 ],
370 )
371 .unwrap())
372 }
373 InterfaceGateType::CNOT => Ok(Array2::from_shape_vec(
374 (4, 4),
375 vec![
376 Complex64::new(1.0, 0.0),
377 Complex64::new(0.0, 0.0),
378 Complex64::new(0.0, 0.0),
379 Complex64::new(0.0, 0.0),
380 Complex64::new(0.0, 0.0),
381 Complex64::new(1.0, 0.0),
382 Complex64::new(0.0, 0.0),
383 Complex64::new(0.0, 0.0),
384 Complex64::new(0.0, 0.0),
385 Complex64::new(0.0, 0.0),
386 Complex64::new(0.0, 0.0),
387 Complex64::new(1.0, 0.0),
388 Complex64::new(0.0, 0.0),
389 Complex64::new(0.0, 0.0),
390 Complex64::new(1.0, 0.0),
391 Complex64::new(0.0, 0.0),
392 ],
393 )
394 .unwrap()),
395 InterfaceGateType::CZ => Ok(Array2::from_shape_vec(
396 (4, 4),
397 vec![
398 Complex64::new(1.0, 0.0),
399 Complex64::new(0.0, 0.0),
400 Complex64::new(0.0, 0.0),
401 Complex64::new(0.0, 0.0),
402 Complex64::new(0.0, 0.0),
403 Complex64::new(1.0, 0.0),
404 Complex64::new(0.0, 0.0),
405 Complex64::new(0.0, 0.0),
406 Complex64::new(0.0, 0.0),
407 Complex64::new(0.0, 0.0),
408 Complex64::new(1.0, 0.0),
409 Complex64::new(0.0, 0.0),
410 Complex64::new(0.0, 0.0),
411 Complex64::new(0.0, 0.0),
412 Complex64::new(0.0, 0.0),
413 Complex64::new(-1.0, 0.0),
414 ],
415 )
416 .unwrap()),
417 InterfaceGateType::SWAP => Ok(Array2::from_shape_vec(
418 (4, 4),
419 vec![
420 Complex64::new(1.0, 0.0),
421 Complex64::new(0.0, 0.0),
422 Complex64::new(0.0, 0.0),
423 Complex64::new(0.0, 0.0),
424 Complex64::new(0.0, 0.0),
425 Complex64::new(0.0, 0.0),
426 Complex64::new(1.0, 0.0),
427 Complex64::new(0.0, 0.0),
428 Complex64::new(0.0, 0.0),
429 Complex64::new(1.0, 0.0),
430 Complex64::new(0.0, 0.0),
431 Complex64::new(0.0, 0.0),
432 Complex64::new(0.0, 0.0),
433 Complex64::new(0.0, 0.0),
434 Complex64::new(0.0, 0.0),
435 Complex64::new(1.0, 0.0),
436 ],
437 )
438 .unwrap()),
439 InterfaceGateType::MultiControlledZ(num_controls) => {
440 let total_qubits = num_controls + 1;
441 let dim = 1 << total_qubits;
442 let mut matrix = Array2::eye(dim);
443
444 let target_state = (1 << total_qubits) - 1; matrix[(target_state, target_state)] = Complex64::new(-1.0, 0.0);
447
448 Ok(matrix)
449 }
450 InterfaceGateType::MultiControlledX(num_controls) => {
451 let total_qubits = num_controls + 1;
452 let dim = 1 << total_qubits;
453 let mut matrix = Array2::eye(dim);
454
455 let control_pattern = (1 << *num_controls) - 1; let target_bit = 1 << num_controls;
458
459 let state0 = control_pattern; let state1 = control_pattern | target_bit; matrix[(state0, state0)] = Complex64::new(0.0, 0.0);
464 matrix[(state1, state1)] = Complex64::new(0.0, 0.0);
465 matrix[(state0, state1)] = Complex64::new(1.0, 0.0);
466 matrix[(state1, state0)] = Complex64::new(1.0, 0.0);
467
468 Ok(matrix)
469 }
470 InterfaceGateType::CPhase(phase) => {
471 let phase_factor = Complex64::new(0.0, *phase).exp();
472 Ok(Array2::from_shape_vec(
473 (4, 4),
474 vec![
475 Complex64::new(1.0, 0.0),
476 Complex64::new(0.0, 0.0),
477 Complex64::new(0.0, 0.0),
478 Complex64::new(0.0, 0.0),
479 Complex64::new(0.0, 0.0),
480 Complex64::new(1.0, 0.0),
481 Complex64::new(0.0, 0.0),
482 Complex64::new(0.0, 0.0),
483 Complex64::new(0.0, 0.0),
484 Complex64::new(0.0, 0.0),
485 Complex64::new(1.0, 0.0),
486 Complex64::new(0.0, 0.0),
487 Complex64::new(0.0, 0.0),
488 Complex64::new(0.0, 0.0),
489 Complex64::new(0.0, 0.0),
490 phase_factor,
491 ],
492 )
493 .unwrap())
494 }
495 InterfaceGateType::Custom(_, matrix) => Ok(matrix.clone()),
496 _ => Err(SimulatorError::UnsupportedOperation(format!(
497 "Unitary matrix not available for gate type: {:?}",
498 self.gate_type
499 ))),
500 }
501 }
502
503 pub fn is_measurement(&self) -> bool {
505 matches!(self.gate_type, InterfaceGateType::Measure)
506 }
507
508 pub fn is_unitary(&self) -> bool {
510 !matches!(
511 self.gate_type,
512 InterfaceGateType::Measure | InterfaceGateType::Reset
513 )
514 }
515
516 pub fn num_qubits(&self) -> usize {
518 match &self.gate_type {
519 InterfaceGateType::MultiControlledX(n) | InterfaceGateType::MultiControlledZ(n) => {
520 n + 1
521 }
522 _ => self.qubits.len(),
523 }
524 }
525}
526
527#[derive(Debug, Clone, Serialize, Deserialize)]
529pub struct InterfaceCircuit {
530 pub num_qubits: usize,
532 pub num_classical: usize,
534 pub gates: Vec<InterfaceGate>,
536 pub metadata: CircuitMetadata,
538}
539
540#[derive(Debug, Clone, Default, Serialize, Deserialize)]
542pub struct CircuitMetadata {
543 pub name: Option<String>,
545 pub description: Option<String>,
547 #[serde(skip)]
549 pub created_at: Option<std::time::SystemTime>,
550 pub depth: usize,
552 pub two_qubit_gates: usize,
554 pub complexity_score: f64,
556 pub classical_complexity: Option<f64>,
558}
559
560impl InterfaceCircuit {
561 pub fn new(num_qubits: usize, num_classical: usize) -> Self {
563 Self {
564 num_qubits,
565 num_classical,
566 gates: Vec::new(),
567 metadata: CircuitMetadata::default(),
568 }
569 }
570
571 pub fn add_gate(&mut self, mut gate: InterfaceGate) {
573 gate.position = self.gates.len();
574 self.gates.push(gate);
575 self.update_metadata();
576 }
577
578 pub fn add_gates(&mut self, gates: Vec<InterfaceGate>) {
580 for gate in gates {
581 self.add_gate(gate);
582 }
583 }
584
585 fn update_metadata(&mut self) {
587 let depth = self.calculate_depth();
588 let two_qubit_gates = self.gates.iter().filter(|g| g.num_qubits() == 2).count();
589
590 let complexity_score = self.calculate_complexity_score();
591
592 self.metadata.depth = depth;
593 self.metadata.two_qubit_gates = two_qubit_gates;
594 self.metadata.complexity_score = complexity_score;
595 }
596
597 pub fn calculate_depth(&self) -> usize {
599 if self.gates.is_empty() {
600 return 0;
601 }
602
603 let mut qubit_depths = vec![0; self.num_qubits];
604
605 for gate in &self.gates {
606 let valid_qubits: Vec<usize> = gate
608 .qubits
609 .iter()
610 .filter(|&&q| q < self.num_qubits)
611 .copied()
612 .collect();
613
614 if valid_qubits.is_empty() {
615 continue;
616 }
617
618 let max_depth = valid_qubits
619 .iter()
620 .map(|&q| qubit_depths[q])
621 .max()
622 .unwrap_or(0);
623
624 for &qubit in &valid_qubits {
625 qubit_depths[qubit] = max_depth + 1;
626 }
627 }
628
629 qubit_depths.into_iter().max().unwrap_or(0)
630 }
631
632 fn calculate_complexity_score(&self) -> f64 {
634 let mut score = 0.0;
635
636 for gate in &self.gates {
637 let gate_score = match gate.num_qubits() {
638 1 => 1.0,
639 2 => 5.0,
640 3 => 25.0,
641 n => (5.0_f64).powi(n as i32 - 1),
642 };
643 score += gate_score;
644 }
645
646 score
647 }
648
649 pub fn subcircuit(&self, start: usize, end: usize) -> Result<InterfaceCircuit> {
651 if start >= end || end > self.gates.len() {
652 return Err(SimulatorError::InvalidInput(
653 "Invalid subcircuit range".to_string(),
654 ));
655 }
656
657 let mut subcircuit = InterfaceCircuit::new(self.num_qubits, self.num_classical);
658 subcircuit.gates = self.gates[start..end].to_vec();
659 subcircuit.update_metadata();
660
661 Ok(subcircuit)
662 }
663
664 pub fn optimize(&mut self) -> CircuitOptimizationResult {
666 let original_gates = self.gates.len();
667 let original_depth = self.metadata.depth;
668
669 self.remove_identity_gates();
671 self.cancel_adjacent_gates();
672 self.merge_rotation_gates();
673 self.optimize_cnot_patterns();
674
675 self.update_metadata();
676
677 CircuitOptimizationResult {
678 original_gates,
679 optimized_gates: self.gates.len(),
680 original_depth,
681 optimized_depth: self.metadata.depth,
682 gates_eliminated: original_gates.saturating_sub(self.gates.len()),
683 depth_reduction: original_depth.saturating_sub(self.metadata.depth),
684 }
685 }
686
687 fn remove_identity_gates(&mut self) {
689 self.gates
690 .retain(|gate| !matches!(gate.gate_type, InterfaceGateType::Identity));
691 }
692
693 fn cancel_adjacent_gates(&mut self) {
695 let mut i = 0;
696 while i + 1 < self.gates.len() {
697 if self.gates_cancel(&self.gates[i], &self.gates[i + 1]) {
698 self.gates.remove(i);
699 self.gates.remove(i);
700 if i > 0 {
701 i = i.saturating_sub(1);
702 }
703 } else {
704 i += 1;
705 }
706 }
707 }
708
709 fn gates_cancel(&self, gate1: &InterfaceGate, gate2: &InterfaceGate) -> bool {
711 if gate1.qubits != gate2.qubits {
712 return false;
713 }
714
715 match (&gate1.gate_type, &gate2.gate_type) {
716 (InterfaceGateType::PauliX, InterfaceGateType::PauliX)
717 | (InterfaceGateType::PauliY, InterfaceGateType::PauliY)
718 | (InterfaceGateType::PauliZ, InterfaceGateType::PauliZ)
719 | (InterfaceGateType::Hadamard, InterfaceGateType::Hadamard)
720 | (InterfaceGateType::S, InterfaceGateType::S)
721 | (InterfaceGateType::CNOT, InterfaceGateType::CNOT)
722 | (InterfaceGateType::CZ, InterfaceGateType::CZ)
723 | (InterfaceGateType::SWAP, InterfaceGateType::SWAP) => true,
724 _ => false,
725 }
726 }
727
728 fn merge_rotation_gates(&mut self) {
730 let mut i = 0;
731 while i + 1 < self.gates.len() {
732 if let Some(merged) = self.try_merge_rotations(&self.gates[i], &self.gates[i + 1]) {
733 self.gates[i] = merged;
734 self.gates.remove(i + 1);
735 } else {
736 i += 1;
737 }
738 }
739 }
740
741 fn try_merge_rotations(
743 &self,
744 gate1: &InterfaceGate,
745 gate2: &InterfaceGate,
746 ) -> Option<InterfaceGate> {
747 if gate1.qubits != gate2.qubits {
748 return None;
749 }
750
751 match (&gate1.gate_type, &gate2.gate_type) {
752 (InterfaceGateType::RX(angle1), InterfaceGateType::RX(angle2)) => Some(
753 InterfaceGate::new(InterfaceGateType::RX(angle1 + angle2), gate1.qubits.clone()),
754 ),
755 (InterfaceGateType::RY(angle1), InterfaceGateType::RY(angle2)) => Some(
756 InterfaceGate::new(InterfaceGateType::RY(angle1 + angle2), gate1.qubits.clone()),
757 ),
758 (InterfaceGateType::RZ(angle1), InterfaceGateType::RZ(angle2)) => Some(
759 InterfaceGate::new(InterfaceGateType::RZ(angle1 + angle2), gate1.qubits.clone()),
760 ),
761 _ => None,
762 }
763 }
764
765 fn optimize_cnot_patterns(&mut self) {
767 let mut i = 0;
769 while i + 2 < self.gates.len() {
770 if self.is_cnot_chain(i) {
771 self.optimize_cnot_chain(i);
772 }
773 i += 1;
774 }
775 }
776
777 fn is_cnot_chain(&self, start: usize) -> bool {
779 if start + 2 >= self.gates.len() {
780 return false;
781 }
782
783 for i in start..start + 3 {
784 if !matches!(self.gates[i].gate_type, InterfaceGateType::CNOT) {
785 return false;
786 }
787 }
788
789 true
790 }
791
792 fn optimize_cnot_chain(&mut self, start: usize) {
794 if start + 2 < self.gates.len() {
796 let gate1 = &self.gates[start];
797 let gate2 = &self.gates[start + 1];
798 let gate3 = &self.gates[start + 2];
799
800 if gate1.qubits == gate2.qubits && gate2.qubits == gate3.qubits {
801 self.gates.drain(start + 1..start + 3);
803 }
804 }
805 }
806}
807
808#[derive(Debug, Clone)]
810pub struct CircuitOptimizationResult {
811 pub original_gates: usize,
813 pub optimized_gates: usize,
815 pub original_depth: usize,
817 pub optimized_depth: usize,
819 pub gates_eliminated: usize,
821 pub depth_reduction: usize,
823}
824
825#[derive(Debug, Clone, Copy, PartialEq, Eq)]
827pub enum SimulationBackend {
828 StateVector,
830 MPS,
832 Stabilizer,
834 Sparse,
836 TensorNetwork,
838 Auto,
840}
841
842pub struct CircuitInterface {
844 config: CircuitInterfaceConfig,
846 backend: Option<SciRS2Backend>,
848 circuit_cache: Arc<Mutex<HashMap<u64, CompiledCircuit>>>,
850 stats: CircuitInterfaceStats,
852}
853
854#[derive(Debug, Clone)]
856pub struct CompiledCircuit {
857 pub original: InterfaceCircuit,
859 pub optimized_gates: Vec<InterfaceGate>,
861 pub backend_data: BackendCompiledData,
863 pub metadata: CompilationMetadata,
865}
866
867#[derive(Debug, Clone)]
869pub enum BackendCompiledData {
870 StateVector {
871 unitary_matrices: Vec<Array2<Complex64>>,
872 gate_indices: Vec<Vec<usize>>,
873 },
874 MPS {
875 bond_dimensions: Vec<usize>,
876 truncation_thresholds: Vec<f64>,
877 },
878 Stabilizer {
879 clifford_sequence: Vec<StabilizerOp>,
880 },
881 Sparse {
882 sparse_matrices: Vec<CSRMatrix>,
883 },
884}
885
886#[derive(Debug, Clone)]
888pub enum StabilizerOp {
889 H(usize),
890 S(usize),
891 CNOT(usize, usize),
892 X(usize),
893 Y(usize),
894 Z(usize),
895}
896
897#[derive(Debug, Clone)]
899pub struct CompilationMetadata {
900 pub compilation_time_ms: f64,
902 pub backend: SimulationBackend,
904 pub optimization_passes: Vec<String>,
906 pub estimated_execution_time_ms: f64,
908 pub estimated_memory_bytes: usize,
910}
911
912#[derive(Debug, Clone, Default, Serialize, Deserialize)]
914pub struct CircuitInterfaceStats {
915 pub circuits_compiled: usize,
917 pub total_compilation_time_ms: f64,
919 pub cache_hit_rate: f64,
921 pub backend_selections: HashMap<String, usize>,
923 pub optimization_stats: OptimizationStats,
925}
926
927#[derive(Debug, Clone, Default, Serialize, Deserialize)]
929pub struct OptimizationStats {
930 pub total_gates_eliminated: usize,
932 pub total_depth_reduction: usize,
934 pub average_optimization_ratio: f64,
936}
937
938impl CircuitInterface {
939 pub fn new(config: CircuitInterfaceConfig) -> Result<Self> {
941 Ok(Self {
942 config,
943 backend: None,
944 circuit_cache: Arc::new(Mutex::new(HashMap::new())),
945 stats: CircuitInterfaceStats::default(),
946 })
947 }
948
949 pub fn with_backend(mut self) -> Result<Self> {
951 self.backend = Some(SciRS2Backend::new());
952 Ok(self)
953 }
954
955 pub fn compile_circuit(
957 &mut self,
958 circuit: &InterfaceCircuit,
959 backend: SimulationBackend,
960 ) -> Result<CompiledCircuit> {
961 let start_time = std::time::Instant::now();
962
963 let circuit_hash = self.calculate_circuit_hash(circuit);
965 if self.config.enable_circuit_cache {
966 let cache = self.circuit_cache.lock().unwrap();
967 if let Some(compiled) = cache.get(&circuit_hash) {
968 self.stats.cache_hit_rate =
969 (self.stats.cache_hit_rate * self.stats.circuits_compiled as f64 + 1.0)
970 / (self.stats.circuits_compiled + 1) as f64;
971 return Ok(compiled.clone());
972 }
973 }
974
975 let selected_backend = if backend == SimulationBackend::Auto {
977 self.select_optimal_backend(circuit)?
978 } else {
979 backend
980 };
981
982 let mut optimized_circuit = circuit.clone();
984 let mut optimization_passes = Vec::new();
985
986 if self.config.enable_optimization {
987 let opt_result = optimized_circuit.optimize();
988 optimization_passes.push("basic_optimization".to_string());
989
990 self.stats.optimization_stats.total_gates_eliminated += opt_result.gates_eliminated;
991 self.stats.optimization_stats.total_depth_reduction += opt_result.depth_reduction;
992 }
993
994 let backend_data = self.compile_for_backend(&optimized_circuit, selected_backend)?;
996
997 let estimated_execution_time_ms =
999 self.estimate_execution_time(&optimized_circuit, selected_backend);
1000 let estimated_memory_bytes =
1001 self.estimate_memory_requirements(&optimized_circuit, selected_backend);
1002
1003 let compilation_time_ms = start_time.elapsed().as_secs_f64() * 1000.0;
1004
1005 let compiled = CompiledCircuit {
1006 original: circuit.clone(),
1007 optimized_gates: optimized_circuit.gates,
1008 backend_data,
1009 metadata: CompilationMetadata {
1010 compilation_time_ms,
1011 backend: selected_backend,
1012 optimization_passes,
1013 estimated_execution_time_ms,
1014 estimated_memory_bytes,
1015 },
1016 };
1017
1018 if self.config.enable_circuit_cache {
1020 let mut cache = self.circuit_cache.lock().unwrap();
1021 if cache.len() >= self.config.max_cache_size {
1022 if let Some(oldest_key) = cache.keys().next().copied() {
1024 cache.remove(&oldest_key);
1025 }
1026 }
1027 cache.insert(circuit_hash, compiled.clone());
1028 }
1029
1030 self.stats.circuits_compiled += 1;
1032 self.stats.total_compilation_time_ms += compilation_time_ms;
1033 *self
1034 .stats
1035 .backend_selections
1036 .entry(format!("{:?}", selected_backend))
1037 .or_insert(0) += 1;
1038
1039 Ok(compiled)
1040 }
1041
1042 pub fn execute_circuit(
1044 &mut self,
1045 compiled: &CompiledCircuit,
1046 initial_state: Option<Array1<Complex64>>,
1047 ) -> Result<CircuitExecutionResult> {
1048 let start_time = std::time::Instant::now();
1049
1050 let result = match compiled.metadata.backend {
1051 SimulationBackend::StateVector => self.execute_statevector(compiled, initial_state)?,
1052 SimulationBackend::MPS => self.execute_mps(compiled, initial_state)?,
1053 SimulationBackend::Stabilizer => self.execute_stabilizer(compiled)?,
1054 SimulationBackend::Sparse => self.execute_sparse(compiled, initial_state)?,
1055 #[cfg(feature = "advanced_math")]
1056 SimulationBackend::TensorNetwork => {
1057 self.execute_tensor_network(compiled, initial_state)?
1058 }
1059 #[cfg(not(feature = "advanced_math"))]
1060 SimulationBackend::TensorNetwork => {
1061 return Err(SimulatorError::UnsupportedOperation(
1062 "Tensor network simulation requires advanced_math feature".to_string(),
1063 ))
1064 }
1065 SimulationBackend::Auto => {
1066 unreachable!("Auto backend should be resolved during compilation")
1067 }
1068 };
1069
1070 let execution_time_ms = start_time.elapsed().as_secs_f64() * 1000.0;
1071
1072 Ok(CircuitExecutionResult {
1073 final_state: result.final_state,
1074 measurement_results: result.measurement_results,
1075 classical_bits: result.classical_bits,
1076 execution_time_ms,
1077 backend_used: compiled.metadata.backend,
1078 memory_used_bytes: result.memory_used_bytes,
1079 })
1080 }
1081
1082 fn select_optimal_backend(&self, circuit: &InterfaceCircuit) -> Result<SimulationBackend> {
1084 let num_qubits = circuit.num_qubits;
1085 let two_qubit_gates = circuit.metadata.two_qubit_gates;
1086 let total_gates = circuit.gates.len();
1087
1088 if self.is_clifford_circuit(circuit) {
1090 return Ok(SimulationBackend::Stabilizer);
1091 }
1092
1093 if num_qubits <= self.config.max_statevector_qubits {
1095 return Ok(SimulationBackend::StateVector);
1096 }
1097
1098 let entanglement_score = two_qubit_gates as f64 / total_gates as f64;
1100 if entanglement_score < 0.3 {
1101 return Ok(SimulationBackend::MPS);
1102 }
1103
1104 let sparsity_score = self.estimate_sparsity(circuit);
1106 if sparsity_score > 0.8 {
1107 return Ok(SimulationBackend::Sparse);
1108 }
1109
1110 if self.has_tensor_network_structure(circuit) {
1112 return Ok(SimulationBackend::TensorNetwork);
1113 }
1114
1115 Ok(SimulationBackend::MPS)
1117 }
1118
1119 fn is_clifford_circuit(&self, circuit: &InterfaceCircuit) -> bool {
1121 circuit.gates.iter().all(|gate| {
1122 matches!(
1123 gate.gate_type,
1124 InterfaceGateType::Identity
1125 | InterfaceGateType::PauliX
1126 | InterfaceGateType::PauliY
1127 | InterfaceGateType::PauliZ
1128 | InterfaceGateType::Hadamard
1129 | InterfaceGateType::S
1130 | InterfaceGateType::CNOT
1131 | InterfaceGateType::CZ
1132 | InterfaceGateType::SWAP
1133 | InterfaceGateType::Measure
1134 | InterfaceGateType::Reset
1135 )
1136 })
1137 }
1138
1139 fn estimate_sparsity(&self, circuit: &InterfaceCircuit) -> f64 {
1141 let single_qubit_gates = circuit.gates.iter().filter(|g| g.num_qubits() == 1).count();
1143
1144 single_qubit_gates as f64 / circuit.gates.len() as f64
1145 }
1146
1147 fn has_tensor_network_structure(&self, circuit: &InterfaceCircuit) -> bool {
1149 let depth = circuit.metadata.depth;
1151 let num_qubits = circuit.num_qubits;
1152
1153 depth > num_qubits && circuit.metadata.complexity_score > 100.0
1155 }
1156
1157 fn compile_for_backend(
1159 &self,
1160 circuit: &InterfaceCircuit,
1161 backend: SimulationBackend,
1162 ) -> Result<BackendCompiledData> {
1163 match backend {
1164 SimulationBackend::StateVector => {
1165 let mut unitary_matrices = Vec::new();
1166 let mut gate_indices = Vec::new();
1167
1168 for gate in &circuit.gates {
1169 if gate.is_unitary() {
1170 unitary_matrices.push(gate.unitary_matrix()?);
1171 gate_indices.push(gate.qubits.clone());
1172 }
1173 }
1174
1175 Ok(BackendCompiledData::StateVector {
1176 unitary_matrices,
1177 gate_indices,
1178 })
1179 }
1180 SimulationBackend::MPS => {
1181 let bond_dimensions = self.calculate_optimal_bond_dimensions(circuit);
1183 let truncation_thresholds = vec![1e-12; circuit.gates.len()];
1184
1185 Ok(BackendCompiledData::MPS {
1186 bond_dimensions,
1187 truncation_thresholds,
1188 })
1189 }
1190 SimulationBackend::Stabilizer => {
1191 let mut clifford_sequence = Vec::new();
1192
1193 for gate in &circuit.gates {
1194 match &gate.gate_type {
1195 InterfaceGateType::Hadamard => {
1196 clifford_sequence.push(StabilizerOp::H(gate.qubits[0]))
1197 }
1198 InterfaceGateType::S => {
1199 clifford_sequence.push(StabilizerOp::S(gate.qubits[0]))
1200 }
1201 InterfaceGateType::PauliX => {
1202 clifford_sequence.push(StabilizerOp::X(gate.qubits[0]))
1203 }
1204 InterfaceGateType::PauliY => {
1205 clifford_sequence.push(StabilizerOp::Y(gate.qubits[0]))
1206 }
1207 InterfaceGateType::PauliZ => {
1208 clifford_sequence.push(StabilizerOp::Z(gate.qubits[0]))
1209 }
1210 InterfaceGateType::CNOT => clifford_sequence
1211 .push(StabilizerOp::CNOT(gate.qubits[0], gate.qubits[1])),
1212 _ => {} }
1214 }
1215
1216 Ok(BackendCompiledData::Stabilizer { clifford_sequence })
1217 }
1218 SimulationBackend::Sparse => {
1219 let sparse_matrices = Vec::new(); Ok(BackendCompiledData::Sparse { sparse_matrices })
1221 }
1222 SimulationBackend::TensorNetwork => {
1223 let mut unitary_matrices = Vec::new();
1225 let mut gate_indices = Vec::new();
1226
1227 for gate in &circuit.gates {
1228 if gate.is_unitary() {
1229 unitary_matrices.push(gate.unitary_matrix()?);
1230 gate_indices.push(gate.qubits.clone());
1231 }
1232 }
1233
1234 Ok(BackendCompiledData::StateVector {
1235 unitary_matrices,
1236 gate_indices,
1237 })
1238 }
1239 SimulationBackend::Auto => unreachable!(),
1240 }
1241 }
1242
1243 fn calculate_optimal_bond_dimensions(&self, circuit: &InterfaceCircuit) -> Vec<usize> {
1245 let base_bond_dim = self.config.max_mps_bond_dim.min(64);
1246 vec![base_bond_dim; circuit.num_qubits - 1]
1247 }
1248
1249 fn execute_statevector(
1251 &self,
1252 compiled: &CompiledCircuit,
1253 initial_state: Option<Array1<Complex64>>,
1254 ) -> Result<BackendExecutionResult> {
1255 let _simulator = StateVectorSimulator::new();
1256
1257 let num_qubits = compiled.original.num_qubits;
1259 let state_size = 1 << num_qubits;
1260
1261 let final_state = initial_state.unwrap_or_else(|| {
1262 let mut state = Array1::zeros(state_size);
1263 state[0] = Complex64::new(1.0, 0.0);
1264 state
1265 });
1266 let memory_used = final_state.len() * std::mem::size_of::<Complex64>();
1267
1268 Ok(BackendExecutionResult {
1269 final_state: Some(final_state),
1270 measurement_results: Vec::new(),
1271 classical_bits: vec![false; compiled.original.num_classical],
1272 memory_used_bytes: memory_used,
1273 })
1274 }
1275
1276 fn execute_mps(
1278 &self,
1279 compiled: &CompiledCircuit,
1280 initial_state: Option<Array1<Complex64>>,
1281 ) -> Result<BackendExecutionResult> {
1282 Ok(BackendExecutionResult {
1284 final_state: None,
1285 measurement_results: Vec::new(),
1286 classical_bits: vec![false; compiled.original.num_classical],
1287 memory_used_bytes: 0,
1288 })
1289 }
1290
1291 fn execute_stabilizer(&self, compiled: &CompiledCircuit) -> Result<BackendExecutionResult> {
1293 Ok(BackendExecutionResult {
1295 final_state: None,
1296 measurement_results: Vec::new(),
1297 classical_bits: vec![false; compiled.original.num_classical],
1298 memory_used_bytes: 0,
1299 })
1300 }
1301
1302 fn execute_sparse(
1304 &self,
1305 compiled: &CompiledCircuit,
1306 initial_state: Option<Array1<Complex64>>,
1307 ) -> Result<BackendExecutionResult> {
1308 Ok(BackendExecutionResult {
1310 final_state: None,
1311 measurement_results: Vec::new(),
1312 classical_bits: vec![false; compiled.original.num_classical],
1313 memory_used_bytes: 0,
1314 })
1315 }
1316
1317 #[cfg(feature = "advanced_math")]
1319 fn execute_tensor_network(
1320 &self,
1321 compiled: &CompiledCircuit,
1322 initial_state: Option<Array1<Complex64>>,
1323 ) -> Result<BackendExecutionResult> {
1324 Ok(BackendExecutionResult {
1326 final_state: None,
1327 measurement_results: Vec::new(),
1328 classical_bits: vec![false; compiled.original.num_classical],
1329 memory_used_bytes: 0,
1330 })
1331 }
1332
1333 #[cfg(not(feature = "advanced_math"))]
1334 fn execute_tensor_network(
1335 &self,
1336 _compiled: &CompiledCircuit,
1337 _initial_state: Option<Array1<Complex64>>,
1338 ) -> Result<BackendExecutionResult> {
1339 Err(SimulatorError::UnsupportedOperation(
1340 "Tensor network simulation requires advanced_math feature".to_string(),
1341 ))
1342 }
1343
1344 fn calculate_circuit_hash(&self, circuit: &InterfaceCircuit) -> u64 {
1346 let mut hasher = DefaultHasher::new();
1347 circuit.num_qubits.hash(&mut hasher);
1348 circuit.num_classical.hash(&mut hasher);
1349
1350 for gate in &circuit.gates {
1351 std::mem::discriminant(&gate.gate_type).hash(&mut hasher);
1353 match &gate.gate_type {
1355 InterfaceGateType::Phase(angle)
1356 | InterfaceGateType::RX(angle)
1357 | InterfaceGateType::RY(angle)
1358 | InterfaceGateType::RZ(angle) => {
1359 angle.to_bits().hash(&mut hasher);
1360 }
1361 _ => {}
1362 }
1363 gate.qubits.hash(&mut hasher);
1364 }
1365
1366 hasher.finish()
1367 }
1368
1369 fn estimate_execution_time(
1371 &self,
1372 circuit: &InterfaceCircuit,
1373 backend: SimulationBackend,
1374 ) -> f64 {
1375 let base_time_per_gate = match backend {
1376 SimulationBackend::StateVector => 0.1, SimulationBackend::MPS => 1.0,
1378 SimulationBackend::Stabilizer => 0.01,
1379 SimulationBackend::Sparse => 0.5,
1380 SimulationBackend::TensorNetwork => 2.0,
1381 SimulationBackend::Auto => 1.0,
1382 };
1383
1384 circuit.gates.len() as f64 * base_time_per_gate * (1.1_f64).powi(circuit.num_qubits as i32)
1385 }
1386
1387 fn estimate_memory_requirements(
1389 &self,
1390 circuit: &InterfaceCircuit,
1391 backend: SimulationBackend,
1392 ) -> usize {
1393 let base_memory = match backend {
1394 SimulationBackend::StateVector => {
1395 (1_usize << circuit.num_qubits) * std::mem::size_of::<Complex64>()
1396 }
1397 SimulationBackend::MPS => {
1398 circuit.num_qubits
1399 * self.config.max_mps_bond_dim
1400 * self.config.max_mps_bond_dim
1401 * std::mem::size_of::<Complex64>()
1402 }
1403 SimulationBackend::Stabilizer => {
1404 circuit.num_qubits * circuit.num_qubits * 2 }
1406 SimulationBackend::Sparse => {
1407 circuit.gates.len() * 1000 * std::mem::size_of::<Complex64>() }
1409 SimulationBackend::TensorNetwork => {
1410 circuit.num_qubits * 64 * std::mem::size_of::<Complex64>() }
1412 SimulationBackend::Auto => 0,
1413 };
1414
1415 base_memory
1416 }
1417
1418 pub fn get_stats(&self) -> &CircuitInterfaceStats {
1420 &self.stats
1421 }
1422
1423 pub fn reset_stats(&mut self) {
1425 self.stats = CircuitInterfaceStats::default();
1426 }
1427}
1428
1429#[derive(Debug)]
1431struct BackendExecutionResult {
1432 final_state: Option<Array1<Complex64>>,
1433 measurement_results: Vec<bool>,
1434 classical_bits: Vec<bool>,
1435 memory_used_bytes: usize,
1436}
1437
1438#[derive(Debug)]
1440pub struct CircuitExecutionResult {
1441 pub final_state: Option<Array1<Complex64>>,
1443 pub measurement_results: Vec<bool>,
1445 pub classical_bits: Vec<bool>,
1447 pub execution_time_ms: f64,
1449 pub backend_used: SimulationBackend,
1451 pub memory_used_bytes: usize,
1453}
1454
1455pub struct CircuitInterfaceUtils;
1457
1458impl CircuitInterfaceUtils {
1459 pub fn create_test_circuit(circuit_type: &str, num_qubits: usize) -> InterfaceCircuit {
1461 let mut circuit = InterfaceCircuit::new(num_qubits, num_qubits);
1462
1463 match circuit_type {
1464 "ghz" => {
1465 circuit.add_gate(InterfaceGate::new(InterfaceGateType::Hadamard, vec![0]));
1467 for i in 1..num_qubits {
1468 circuit.add_gate(InterfaceGate::new(InterfaceGateType::CNOT, vec![0, i]));
1469 }
1470 }
1471 "qft" => {
1472 for i in 0..num_qubits {
1474 circuit.add_gate(InterfaceGate::new(InterfaceGateType::Hadamard, vec![i]));
1475 for j in i + 1..num_qubits {
1476 let angle = std::f64::consts::PI / (1 << (j - i)) as f64;
1477 circuit.add_gate(InterfaceGate::new(
1478 InterfaceGateType::CRZ(angle),
1479 vec![j, i],
1480 ));
1481 }
1482 }
1483 }
1484 "random" => {
1485 for _ in 0..num_qubits * 5 {
1487 let qubit = fastrand::usize(0..num_qubits);
1488 let gate_type = match fastrand::usize(0..4) {
1489 0 => InterfaceGateType::Hadamard,
1490 1 => InterfaceGateType::RX(fastrand::f64() * 2.0 * std::f64::consts::PI),
1491 2 => InterfaceGateType::RY(fastrand::f64() * 2.0 * std::f64::consts::PI),
1492 _ => InterfaceGateType::RZ(fastrand::f64() * 2.0 * std::f64::consts::PI),
1493 };
1494 circuit.add_gate(InterfaceGate::new(gate_type, vec![qubit]));
1495 }
1496 }
1497 _ => {
1498 for i in 0..num_qubits {
1500 circuit.add_gate(InterfaceGate::new(InterfaceGateType::Identity, vec![i]));
1501 }
1502 }
1503 }
1504
1505 circuit
1506 }
1507
1508 pub fn benchmark_interface(
1510 config: CircuitInterfaceConfig,
1511 ) -> Result<InterfaceBenchmarkResults> {
1512 let mut interface = CircuitInterface::new(config)?;
1513 let mut results = InterfaceBenchmarkResults::default();
1514
1515 let circuit_types = vec!["ghz", "qft", "random"];
1516 let qubit_counts = vec![5, 10, 15, 20];
1517
1518 for circuit_type in circuit_types {
1519 for &num_qubits in &qubit_counts {
1520 let circuit = Self::create_test_circuit(circuit_type, num_qubits);
1521
1522 let start = std::time::Instant::now();
1523 let compiled = interface.compile_circuit(&circuit, SimulationBackend::Auto)?;
1524 let compilation_time = start.elapsed().as_secs_f64() * 1000.0;
1525
1526 let start = std::time::Instant::now();
1527 let _result = interface.execute_circuit(&compiled, None)?;
1528 let execution_time = start.elapsed().as_secs_f64() * 1000.0;
1529
1530 results
1531 .compilation_times
1532 .push((format!("{}_{}", circuit_type, num_qubits), compilation_time));
1533 results
1534 .execution_times
1535 .push((format!("{}_{}", circuit_type, num_qubits), execution_time));
1536 }
1537 }
1538
1539 results.interface_stats = interface.get_stats().clone();
1540 Ok(results)
1541 }
1542}
1543
1544#[derive(Debug, Clone, Default)]
1546pub struct InterfaceBenchmarkResults {
1547 pub compilation_times: Vec<(String, f64)>,
1549 pub execution_times: Vec<(String, f64)>,
1551 pub interface_stats: CircuitInterfaceStats,
1553}
1554
1555#[cfg(test)]
1556mod tests {
1557 use super::*;
1558 use approx::assert_abs_diff_eq;
1559
1560 #[test]
1561 fn test_interface_gate_creation() {
1562 let gate = InterfaceGate::new(InterfaceGateType::Hadamard, vec![0]);
1563 assert_eq!(gate.qubits, vec![0]);
1564 assert!(gate.is_unitary());
1565 assert!(!gate.is_measurement());
1566 }
1567
1568 #[test]
1569 fn test_measurement_gate() {
1570 let gate = InterfaceGate::measurement(0, 0);
1571 assert!(gate.is_measurement());
1572 assert!(!gate.is_unitary());
1573 assert_eq!(gate.classical_targets, vec![0]);
1574 }
1575
1576 #[test]
1577 fn test_circuit_creation() {
1578 let mut circuit = InterfaceCircuit::new(3, 3);
1579 circuit.add_gate(InterfaceGate::new(InterfaceGateType::Hadamard, vec![0]));
1580 circuit.add_gate(InterfaceGate::new(InterfaceGateType::CNOT, vec![0, 1]));
1581
1582 assert_eq!(circuit.gates.len(), 2);
1583 assert_eq!(circuit.calculate_depth(), 2);
1584 }
1585
1586 #[test]
1587 fn test_circuit_optimization() {
1588 let mut circuit = InterfaceCircuit::new(2, 0);
1589 circuit.add_gate(InterfaceGate::new(InterfaceGateType::PauliX, vec![0]));
1590 circuit.add_gate(InterfaceGate::new(InterfaceGateType::PauliX, vec![0])); circuit.add_gate(InterfaceGate::new(InterfaceGateType::Identity, vec![1])); let result = circuit.optimize();
1594 assert_eq!(result.gates_eliminated, 3); }
1596
1597 #[test]
1598 fn test_gate_unitary_matrices() {
1599 let hadamard = InterfaceGate::new(InterfaceGateType::Hadamard, vec![0]);
1600 let matrix = hadamard.unitary_matrix().unwrap();
1601
1602 let inv_sqrt2 = 1.0 / (2.0_f64).sqrt();
1603 assert_abs_diff_eq!(matrix[[0, 0]].re, inv_sqrt2, epsilon = 1e-10);
1604 assert_abs_diff_eq!(matrix[[1, 1]].re, -inv_sqrt2, epsilon = 1e-10);
1605 }
1606
1607 #[test]
1608 fn test_rotation_gate_merging() {
1609 let mut circuit = InterfaceCircuit::new(1, 0);
1610 circuit.add_gate(InterfaceGate::new(InterfaceGateType::RX(0.5), vec![0]));
1611 circuit.add_gate(InterfaceGate::new(InterfaceGateType::RX(0.3), vec![0]));
1612
1613 let _ = circuit.optimize();
1614 assert_eq!(circuit.gates.len(), 1);
1615
1616 if let InterfaceGateType::RX(angle) = &circuit.gates[0].gate_type {
1617 assert_abs_diff_eq!(*angle, 0.8, epsilon = 1e-10);
1618 } else {
1619 panic!("Expected merged RX gate");
1620 }
1621 }
1622
1623 #[test]
1624 fn test_circuit_interface_config() {
1625 let config = CircuitInterfaceConfig::default();
1626 assert!(config.auto_backend_selection);
1627 assert!(config.enable_optimization);
1628 assert_eq!(config.max_statevector_qubits, 25);
1629 }
1630
1631 #[test]
1632 fn test_test_circuit_creation() {
1633 let ghz_circuit = CircuitInterfaceUtils::create_test_circuit("ghz", 3);
1634 assert_eq!(ghz_circuit.num_qubits, 3);
1635 assert_eq!(ghz_circuit.gates.len(), 3); let qft_circuit = CircuitInterfaceUtils::create_test_circuit("qft", 3);
1638 assert!(qft_circuit.gates.len() > 3); }
1640
1641 #[test]
1642 fn test_circuit_metadata() {
1643 let circuit = CircuitInterfaceUtils::create_test_circuit("ghz", 4);
1644 assert_eq!(circuit.metadata.depth, 4); assert_eq!(circuit.metadata.two_qubit_gates, 3);
1646 }
1647
1648 #[test]
1649 fn test_clifford_detection() {
1650 let mut circuit = InterfaceCircuit::new(2, 0);
1651 circuit.add_gate(InterfaceGate::new(InterfaceGateType::Hadamard, vec![0]));
1652 circuit.add_gate(InterfaceGate::new(InterfaceGateType::CNOT, vec![0, 1]));
1653 circuit.add_gate(InterfaceGate::new(InterfaceGateType::S, vec![1]));
1654
1655 let config = CircuitInterfaceConfig::default();
1656 let interface = CircuitInterface::new(config).unwrap();
1657 assert!(interface.is_clifford_circuit(&circuit));
1658
1659 circuit.add_gate(InterfaceGate::new(InterfaceGateType::T, vec![0]));
1661 assert!(!interface.is_clifford_circuit(&circuit));
1662 }
1663}