quantrs2_sim/
circuit_interfaces.rs

1//! Efficient interfaces with circuit module for seamless integration.
2//!
3//! This module provides comprehensive bridge functionality between quantum circuit
4//! representations from the circuit module and various simulation backends in the
5//! sim module. It includes optimized gate translation, circuit analysis, and
6//! execution pipelines for maximum performance.
7
8use 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/// Circuit interface configuration
25#[derive(Debug, Clone)]
26pub struct CircuitInterfaceConfig {
27    /// Enable automatic backend selection
28    pub auto_backend_selection: bool,
29    /// Enable circuit optimization during translation
30    pub enable_optimization: bool,
31    /// Maximum qubits for state vector simulation
32    pub max_statevector_qubits: usize,
33    /// Maximum bond dimension for MPS simulation
34    pub max_mps_bond_dim: usize,
35    /// Enable parallel gate compilation
36    pub parallel_compilation: bool,
37    /// Cache compiled circuits
38    pub enable_circuit_cache: bool,
39    /// Maximum cache size
40    pub max_cache_size: usize,
41    /// Enable circuit analysis and profiling
42    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: 10_000,
55            enable_profiling: true,
56        }
57    }
58}
59
60/// Quantum gate types for circuit interface
61#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
62pub enum InterfaceGateType {
63    // Single-qubit gates
64    Identity,
65    PauliX,
66    X, // Alias for PauliX
67    PauliY,
68    PauliZ,
69    Hadamard,
70    H, // Alias for Hadamard
71    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    // Two-qubit gates
81    CNOT,
82    CZ,
83    CY,
84    SWAP,
85    ISwap,
86    CRX(f64),
87    CRY(f64),
88    CRZ(f64),
89    CPhase(f64),
90    // Three-qubit gates
91    Toffoli,
92    Fredkin,
93    // Multi-qubit gates
94    MultiControlledX(usize), // Number of control qubits
95    MultiControlledZ(usize),
96    // Custom gates
97    Custom(String, Array2<Complex64>),
98    // Measurement
99    Measure,
100    Reset,
101}
102
103// Custom Hash implementation since f64 doesn't implement Hash
104impl std::hash::Hash for InterfaceGateType {
105    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
106        use std::mem;
107        match self {
108            Self::Identity => 0u8.hash(state),
109            Self::PauliX => 1u8.hash(state),
110            Self::X => 2u8.hash(state),
111            Self::PauliY => 3u8.hash(state),
112            Self::PauliZ => 4u8.hash(state),
113            Self::Hadamard => 5u8.hash(state),
114            Self::H => 6u8.hash(state),
115            Self::S => 7u8.hash(state),
116            Self::T => 8u8.hash(state),
117            Self::Phase(angle) => {
118                9u8.hash(state);
119                angle.to_bits().hash(state);
120            }
121            Self::RX(angle) => {
122                10u8.hash(state);
123                angle.to_bits().hash(state);
124            }
125            Self::RY(angle) => {
126                11u8.hash(state);
127                angle.to_bits().hash(state);
128            }
129            Self::RZ(angle) => {
130                12u8.hash(state);
131                angle.to_bits().hash(state);
132            }
133            Self::U1(angle) => {
134                13u8.hash(state);
135                angle.to_bits().hash(state);
136            }
137            Self::U2(theta, phi) => {
138                14u8.hash(state);
139                theta.to_bits().hash(state);
140                phi.to_bits().hash(state);
141            }
142            Self::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            Self::CNOT => 16u8.hash(state),
149            Self::CZ => 17u8.hash(state),
150            Self::CY => 18u8.hash(state),
151            Self::SWAP => 19u8.hash(state),
152            Self::ISwap => 20u8.hash(state),
153            Self::CRX(angle) => {
154                21u8.hash(state);
155                angle.to_bits().hash(state);
156            }
157            Self::CRY(angle) => {
158                22u8.hash(state);
159                angle.to_bits().hash(state);
160            }
161            Self::CRZ(angle) => {
162                23u8.hash(state);
163                angle.to_bits().hash(state);
164            }
165            Self::CPhase(angle) => {
166                24u8.hash(state);
167                angle.to_bits().hash(state);
168            }
169            Self::Toffoli => 25u8.hash(state),
170            Self::Fredkin => 26u8.hash(state),
171            Self::MultiControlledX(n) => {
172                27u8.hash(state);
173                n.hash(state);
174            }
175            Self::MultiControlledZ(n) => {
176                28u8.hash(state);
177                n.hash(state);
178            }
179            Self::Custom(name, matrix) => {
180                29u8.hash(state);
181                name.hash(state);
182                // Hash matrix shape instead of all elements
183                matrix.shape().hash(state);
184            }
185            Self::Measure => 30u8.hash(state),
186            Self::Reset => 31u8.hash(state),
187        }
188    }
189}
190
191// Custom Eq implementation since f64 doesn't implement Eq
192impl Eq for InterfaceGateType {}
193
194/// Quantum gate representation for circuit interface
195#[derive(Debug, Clone, Serialize, Deserialize)]
196pub struct InterfaceGate {
197    /// Gate type and parameters
198    pub gate_type: InterfaceGateType,
199    /// Qubits this gate acts on
200    pub qubits: Vec<usize>,
201    /// Classical register targets (for measurements)
202    pub classical_targets: Vec<usize>,
203    /// Gate position in the circuit
204    pub position: usize,
205    /// Conditional execution (if classical bit is 1)
206    pub condition: Option<usize>,
207    /// Gate label for debugging
208    pub label: Option<String>,
209}
210
211impl InterfaceGate {
212    /// Create a new interface gate
213    #[must_use]
214    pub const fn new(gate_type: InterfaceGateType, qubits: Vec<usize>) -> Self {
215        Self {
216            gate_type,
217            qubits,
218            classical_targets: Vec::new(),
219            position: 0,
220            condition: None,
221            label: None,
222        }
223    }
224
225    /// Create a measurement gate
226    #[must_use]
227    pub fn measurement(qubit: usize, classical_bit: usize) -> Self {
228        Self {
229            gate_type: InterfaceGateType::Measure,
230            qubits: vec![qubit],
231            classical_targets: vec![classical_bit],
232            position: 0,
233            condition: None,
234            label: None,
235        }
236    }
237
238    /// Create a conditional gate
239    #[must_use]
240    pub const fn conditional(mut self, condition: usize) -> Self {
241        self.condition = Some(condition);
242        self
243    }
244
245    /// Add a label to the gate
246    #[must_use]
247    pub fn with_label(mut self, label: String) -> Self {
248        self.label = Some(label);
249        self
250    }
251
252    /// Get the unitary matrix for this gate
253    pub fn unitary_matrix(&self) -> Result<Array2<Complex64>> {
254        match &self.gate_type {
255            InterfaceGateType::Identity => Ok(Array2::eye(2)),
256            InterfaceGateType::PauliX => Ok(Array2::from_shape_vec(
257                (2, 2),
258                vec![
259                    Complex64::new(0.0, 0.0),
260                    Complex64::new(1.0, 0.0),
261                    Complex64::new(1.0, 0.0),
262                    Complex64::new(0.0, 0.0),
263                ],
264            )
265            // Safety: shape (2,2) requires exactly 4 elements which are provided
266            .expect("PauliX matrix shape matches data length")),
267            InterfaceGateType::PauliY => Ok(Array2::from_shape_vec(
268                (2, 2),
269                vec![
270                    Complex64::new(0.0, 0.0),
271                    Complex64::new(0.0, -1.0),
272                    Complex64::new(0.0, 1.0),
273                    Complex64::new(0.0, 0.0),
274                ],
275            )
276            // Safety: shape (2,2) requires exactly 4 elements which are provided
277            .expect("PauliY matrix shape matches data length")),
278            InterfaceGateType::PauliZ => Ok(Array2::from_shape_vec(
279                (2, 2),
280                vec![
281                    Complex64::new(1.0, 0.0),
282                    Complex64::new(0.0, 0.0),
283                    Complex64::new(0.0, 0.0),
284                    Complex64::new(-1.0, 0.0),
285                ],
286            )
287            // Safety: shape (2,2) requires exactly 4 elements which are provided
288            .expect("PauliZ matrix shape matches data length")),
289            InterfaceGateType::Hadamard => {
290                let inv_sqrt2 = 1.0 / (2.0_f64).sqrt();
291                Ok(Array2::from_shape_vec(
292                    (2, 2),
293                    vec![
294                        Complex64::new(inv_sqrt2, 0.0),
295                        Complex64::new(inv_sqrt2, 0.0),
296                        Complex64::new(inv_sqrt2, 0.0),
297                        Complex64::new(-inv_sqrt2, 0.0),
298                    ],
299                )
300                // Safety: shape (2,2) requires exactly 4 elements which are provided
301                .expect("Hadamard matrix shape matches data length"))
302            }
303            InterfaceGateType::S => Ok(Array2::from_shape_vec(
304                (2, 2),
305                vec![
306                    Complex64::new(1.0, 0.0),
307                    Complex64::new(0.0, 0.0),
308                    Complex64::new(0.0, 0.0),
309                    Complex64::new(0.0, 1.0),
310                ],
311            )
312            // Safety: shape (2,2) requires exactly 4 elements which are provided
313            .expect("S gate matrix shape matches data length")),
314            InterfaceGateType::T => {
315                let phase = Complex64::new(0.0, std::f64::consts::PI / 4.0).exp();
316                Ok(Array2::from_shape_vec(
317                    (2, 2),
318                    vec![
319                        Complex64::new(1.0, 0.0),
320                        Complex64::new(0.0, 0.0),
321                        Complex64::new(0.0, 0.0),
322                        phase,
323                    ],
324                )
325                // Safety: shape (2,2) requires exactly 4 elements which are provided
326                .expect("T gate matrix shape matches data length"))
327            }
328            InterfaceGateType::Phase(theta) => {
329                let phase = Complex64::new(0.0, *theta).exp();
330                Ok(Array2::from_shape_vec(
331                    (2, 2),
332                    vec![
333                        Complex64::new(1.0, 0.0),
334                        Complex64::new(0.0, 0.0),
335                        Complex64::new(0.0, 0.0),
336                        phase,
337                    ],
338                )
339                // Safety: shape (2,2) requires exactly 4 elements which are provided
340                .expect("Phase gate matrix shape matches data length"))
341            }
342            InterfaceGateType::RX(theta) => {
343                let cos_half = (theta / 2.0).cos();
344                let sin_half = (theta / 2.0).sin();
345                Ok(Array2::from_shape_vec(
346                    (2, 2),
347                    vec![
348                        Complex64::new(cos_half, 0.0),
349                        Complex64::new(0.0, -sin_half),
350                        Complex64::new(0.0, -sin_half),
351                        Complex64::new(cos_half, 0.0),
352                    ],
353                )
354                // Safety: shape (2,2) requires exactly 4 elements which are provided
355                .expect("RX gate matrix shape matches data length"))
356            }
357            InterfaceGateType::RY(theta) => {
358                let cos_half = (theta / 2.0).cos();
359                let sin_half = (theta / 2.0).sin();
360                Ok(Array2::from_shape_vec(
361                    (2, 2),
362                    vec![
363                        Complex64::new(cos_half, 0.0),
364                        Complex64::new(-sin_half, 0.0),
365                        Complex64::new(sin_half, 0.0),
366                        Complex64::new(cos_half, 0.0),
367                    ],
368                )
369                // Safety: shape (2,2) requires exactly 4 elements which are provided
370                .expect("RY gate matrix shape matches data length"))
371            }
372            InterfaceGateType::RZ(theta) => {
373                let exp_neg = Complex64::new(0.0, -theta / 2.0).exp();
374                let exp_pos = Complex64::new(0.0, theta / 2.0).exp();
375                Ok(Array2::from_shape_vec(
376                    (2, 2),
377                    vec![
378                        exp_neg,
379                        Complex64::new(0.0, 0.0),
380                        Complex64::new(0.0, 0.0),
381                        exp_pos,
382                    ],
383                )
384                // Safety: shape (2,2) requires exactly 4 elements which are provided
385                .expect("RZ gate matrix shape matches data length"))
386            }
387            InterfaceGateType::CNOT => Ok(Array2::from_shape_vec(
388                (4, 4),
389                vec![
390                    Complex64::new(1.0, 0.0),
391                    Complex64::new(0.0, 0.0),
392                    Complex64::new(0.0, 0.0),
393                    Complex64::new(0.0, 0.0),
394                    Complex64::new(0.0, 0.0),
395                    Complex64::new(1.0, 0.0),
396                    Complex64::new(0.0, 0.0),
397                    Complex64::new(0.0, 0.0),
398                    Complex64::new(0.0, 0.0),
399                    Complex64::new(0.0, 0.0),
400                    Complex64::new(0.0, 0.0),
401                    Complex64::new(1.0, 0.0),
402                    Complex64::new(0.0, 0.0),
403                    Complex64::new(0.0, 0.0),
404                    Complex64::new(1.0, 0.0),
405                    Complex64::new(0.0, 0.0),
406                ],
407            )
408            // Safety: shape (4,4) requires exactly 16 elements which are provided
409            .expect("CNOT matrix shape matches data length")),
410            InterfaceGateType::CZ => Ok(Array2::from_shape_vec(
411                (4, 4),
412                vec![
413                    Complex64::new(1.0, 0.0),
414                    Complex64::new(0.0, 0.0),
415                    Complex64::new(0.0, 0.0),
416                    Complex64::new(0.0, 0.0),
417                    Complex64::new(0.0, 0.0),
418                    Complex64::new(1.0, 0.0),
419                    Complex64::new(0.0, 0.0),
420                    Complex64::new(0.0, 0.0),
421                    Complex64::new(0.0, 0.0),
422                    Complex64::new(0.0, 0.0),
423                    Complex64::new(1.0, 0.0),
424                    Complex64::new(0.0, 0.0),
425                    Complex64::new(0.0, 0.0),
426                    Complex64::new(0.0, 0.0),
427                    Complex64::new(0.0, 0.0),
428                    Complex64::new(-1.0, 0.0),
429                ],
430            )
431            // Safety: shape (4,4) requires exactly 16 elements which are provided
432            .expect("CZ matrix shape matches data length")),
433            InterfaceGateType::SWAP => Ok(Array2::from_shape_vec(
434                (4, 4),
435                vec![
436                    Complex64::new(1.0, 0.0),
437                    Complex64::new(0.0, 0.0),
438                    Complex64::new(0.0, 0.0),
439                    Complex64::new(0.0, 0.0),
440                    Complex64::new(0.0, 0.0),
441                    Complex64::new(0.0, 0.0),
442                    Complex64::new(1.0, 0.0),
443                    Complex64::new(0.0, 0.0),
444                    Complex64::new(0.0, 0.0),
445                    Complex64::new(1.0, 0.0),
446                    Complex64::new(0.0, 0.0),
447                    Complex64::new(0.0, 0.0),
448                    Complex64::new(0.0, 0.0),
449                    Complex64::new(0.0, 0.0),
450                    Complex64::new(0.0, 0.0),
451                    Complex64::new(1.0, 0.0),
452                ],
453            )
454            // Safety: shape (4,4) requires exactly 16 elements which are provided
455            .expect("SWAP matrix shape matches data length")),
456            InterfaceGateType::MultiControlledZ(num_controls) => {
457                let total_qubits = num_controls + 1;
458                let dim = 1 << total_qubits;
459                let mut matrix = Array2::eye(dim);
460
461                // Apply Z to the target when all control qubits are |1⟩
462                let target_state = (1 << total_qubits) - 1; // All qubits in |1⟩ state
463                matrix[(target_state, target_state)] = Complex64::new(-1.0, 0.0);
464
465                Ok(matrix)
466            }
467            InterfaceGateType::MultiControlledX(num_controls) => {
468                let total_qubits = num_controls + 1;
469                let dim = 1 << total_qubits;
470                let mut matrix = Array2::eye(dim);
471
472                // Apply X to the target when all control qubits are |1⟩
473                let control_pattern = (1 << *num_controls) - 1; // All control qubits in |1⟩
474                let target_bit = 1 << num_controls;
475
476                // Swap the two states where only the target bit differs
477                let state0 = control_pattern; // Target qubit is |0⟩
478                let state1 = control_pattern | target_bit; // Target qubit is |1⟩
479
480                matrix[(state0, state0)] = Complex64::new(0.0, 0.0);
481                matrix[(state1, state1)] = Complex64::new(0.0, 0.0);
482                matrix[(state0, state1)] = Complex64::new(1.0, 0.0);
483                matrix[(state1, state0)] = Complex64::new(1.0, 0.0);
484
485                Ok(matrix)
486            }
487            InterfaceGateType::CPhase(phase) => {
488                let phase_factor = Complex64::new(0.0, *phase).exp();
489                Ok(Array2::from_shape_vec(
490                    (4, 4),
491                    vec![
492                        Complex64::new(1.0, 0.0),
493                        Complex64::new(0.0, 0.0),
494                        Complex64::new(0.0, 0.0),
495                        Complex64::new(0.0, 0.0),
496                        Complex64::new(0.0, 0.0),
497                        Complex64::new(1.0, 0.0),
498                        Complex64::new(0.0, 0.0),
499                        Complex64::new(0.0, 0.0),
500                        Complex64::new(0.0, 0.0),
501                        Complex64::new(0.0, 0.0),
502                        Complex64::new(1.0, 0.0),
503                        Complex64::new(0.0, 0.0),
504                        Complex64::new(0.0, 0.0),
505                        Complex64::new(0.0, 0.0),
506                        Complex64::new(0.0, 0.0),
507                        phase_factor,
508                    ],
509                )
510                // Safety: shape (4,4) requires exactly 16 elements which are provided
511                .expect("CPhase matrix shape matches data length"))
512            }
513            InterfaceGateType::Custom(_, matrix) => Ok(matrix.clone()),
514            _ => Err(SimulatorError::UnsupportedOperation(format!(
515                "Unitary matrix not available for gate type: {:?}",
516                self.gate_type
517            ))),
518        }
519    }
520
521    /// Check if this gate is a measurement
522    #[must_use]
523    pub const fn is_measurement(&self) -> bool {
524        matches!(self.gate_type, InterfaceGateType::Measure)
525    }
526
527    /// Check if this gate is unitary
528    #[must_use]
529    pub const fn is_unitary(&self) -> bool {
530        !matches!(
531            self.gate_type,
532            InterfaceGateType::Measure | InterfaceGateType::Reset
533        )
534    }
535
536    /// Get the number of qubits this gate acts on
537    #[must_use]
538    pub fn num_qubits(&self) -> usize {
539        match &self.gate_type {
540            InterfaceGateType::MultiControlledX(n) | InterfaceGateType::MultiControlledZ(n) => {
541                n + 1
542            }
543            _ => self.qubits.len(),
544        }
545    }
546}
547
548/// Quantum circuit representation for interface
549#[derive(Debug, Clone, Serialize, Deserialize)]
550pub struct InterfaceCircuit {
551    /// Number of qubits
552    pub num_qubits: usize,
553    /// Number of classical bits
554    pub num_classical: usize,
555    /// Gates in the circuit
556    pub gates: Vec<InterfaceGate>,
557    /// Circuit metadata
558    pub metadata: CircuitMetadata,
559}
560
561/// Circuit metadata
562#[derive(Debug, Clone, Default, Serialize, Deserialize)]
563pub struct CircuitMetadata {
564    /// Circuit name
565    pub name: Option<String>,
566    /// Circuit description
567    pub description: Option<String>,
568    /// Creation timestamp
569    #[serde(skip)]
570    pub created_at: Option<std::time::SystemTime>,
571    /// Circuit depth
572    pub depth: usize,
573    /// Number of two-qubit gates
574    pub two_qubit_gates: usize,
575    /// Circuit complexity score
576    pub complexity_score: f64,
577    /// Estimated classical simulation complexity
578    pub classical_complexity: Option<f64>,
579}
580
581impl InterfaceCircuit {
582    /// Create a new circuit
583    #[must_use]
584    pub fn new(num_qubits: usize, num_classical: usize) -> Self {
585        Self {
586            num_qubits,
587            num_classical,
588            gates: Vec::new(),
589            metadata: CircuitMetadata::default(),
590        }
591    }
592
593    /// Add a gate to the circuit
594    pub fn add_gate(&mut self, mut gate: InterfaceGate) {
595        gate.position = self.gates.len();
596        self.gates.push(gate);
597        self.update_metadata();
598    }
599
600    /// Add multiple gates to the circuit
601    pub fn add_gates(&mut self, gates: Vec<InterfaceGate>) {
602        for gate in gates {
603            self.add_gate(gate);
604        }
605    }
606
607    /// Update circuit metadata
608    fn update_metadata(&mut self) {
609        let depth = self.calculate_depth();
610        let two_qubit_gates = self.gates.iter().filter(|g| g.num_qubits() == 2).count();
611
612        let complexity_score = self.calculate_complexity_score();
613
614        self.metadata.depth = depth;
615        self.metadata.two_qubit_gates = two_qubit_gates;
616        self.metadata.complexity_score = complexity_score;
617    }
618
619    /// Calculate circuit depth
620    #[must_use]
621    pub fn calculate_depth(&self) -> usize {
622        if self.gates.is_empty() {
623            return 0;
624        }
625
626        let mut qubit_depths = vec![0; self.num_qubits];
627
628        for gate in &self.gates {
629            // Skip gates with invalid qubit indices
630            let valid_qubits: Vec<usize> = gate
631                .qubits
632                .iter()
633                .filter(|&&q| q < self.num_qubits)
634                .copied()
635                .collect();
636
637            if valid_qubits.is_empty() {
638                continue;
639            }
640
641            let max_depth = valid_qubits
642                .iter()
643                .map(|&q| qubit_depths[q])
644                .max()
645                .unwrap_or(0);
646
647            for &qubit in &valid_qubits {
648                qubit_depths[qubit] = max_depth + 1;
649            }
650        }
651
652        qubit_depths.into_iter().max().unwrap_or(0)
653    }
654
655    /// Calculate complexity score
656    fn calculate_complexity_score(&self) -> f64 {
657        let mut score = 0.0;
658
659        for gate in &self.gates {
660            let gate_score = match gate.num_qubits() {
661                1 => 1.0,
662                2 => 5.0,
663                3 => 25.0,
664                n => (5.0_f64).powi(n as i32 - 1),
665            };
666            score += gate_score;
667        }
668
669        score
670    }
671
672    /// Extract subcircuit
673    pub fn subcircuit(&self, start: usize, end: usize) -> Result<Self> {
674        if start >= end || end > self.gates.len() {
675            return Err(SimulatorError::InvalidInput(
676                "Invalid subcircuit range".to_string(),
677            ));
678        }
679
680        let mut subcircuit = Self::new(self.num_qubits, self.num_classical);
681        subcircuit.gates = self.gates[start..end].to_vec();
682        subcircuit.update_metadata();
683
684        Ok(subcircuit)
685    }
686
687    /// Optimize the circuit
688    pub fn optimize(&mut self) -> CircuitOptimizationResult {
689        let original_gates = self.gates.len();
690        let original_depth = self.metadata.depth;
691
692        // Apply various optimization passes
693        self.remove_identity_gates();
694        self.cancel_adjacent_gates();
695        self.merge_rotation_gates();
696        self.optimize_cnot_patterns();
697
698        self.update_metadata();
699
700        CircuitOptimizationResult {
701            original_gates,
702            optimized_gates: self.gates.len(),
703            original_depth,
704            optimized_depth: self.metadata.depth,
705            gates_eliminated: original_gates.saturating_sub(self.gates.len()),
706            depth_reduction: original_depth.saturating_sub(self.metadata.depth),
707        }
708    }
709
710    /// Remove identity gates
711    fn remove_identity_gates(&mut self) {
712        self.gates
713            .retain(|gate| !matches!(gate.gate_type, InterfaceGateType::Identity));
714    }
715
716    /// Cancel adjacent gates
717    fn cancel_adjacent_gates(&mut self) {
718        let mut i = 0;
719        while i + 1 < self.gates.len() {
720            if self.gates_cancel(&self.gates[i], &self.gates[i + 1]) {
721                self.gates.remove(i);
722                self.gates.remove(i);
723                if i > 0 {
724                    i = i.saturating_sub(1);
725                }
726            } else {
727                i += 1;
728            }
729        }
730    }
731
732    /// Check if two gates cancel each other
733    fn gates_cancel(&self, gate1: &InterfaceGate, gate2: &InterfaceGate) -> bool {
734        if gate1.qubits != gate2.qubits {
735            return false;
736        }
737
738        match (&gate1.gate_type, &gate2.gate_type) {
739            (InterfaceGateType::PauliX, InterfaceGateType::PauliX)
740            | (InterfaceGateType::PauliY, InterfaceGateType::PauliY)
741            | (InterfaceGateType::PauliZ, InterfaceGateType::PauliZ)
742            | (InterfaceGateType::Hadamard, InterfaceGateType::Hadamard)
743            | (InterfaceGateType::S, InterfaceGateType::S)
744            | (InterfaceGateType::CNOT, InterfaceGateType::CNOT)
745            | (InterfaceGateType::CZ, InterfaceGateType::CZ)
746            | (InterfaceGateType::SWAP, InterfaceGateType::SWAP) => true,
747            _ => false,
748        }
749    }
750
751    /// Merge rotation gates
752    fn merge_rotation_gates(&mut self) {
753        let mut i = 0;
754        while i + 1 < self.gates.len() {
755            if let Some(merged) = self.try_merge_rotations(&self.gates[i], &self.gates[i + 1]) {
756                self.gates[i] = merged;
757                self.gates.remove(i + 1);
758            } else {
759                i += 1;
760            }
761        }
762    }
763
764    /// Try to merge two rotation gates
765    fn try_merge_rotations(
766        &self,
767        gate1: &InterfaceGate,
768        gate2: &InterfaceGate,
769    ) -> Option<InterfaceGate> {
770        if gate1.qubits != gate2.qubits {
771            return None;
772        }
773
774        match (&gate1.gate_type, &gate2.gate_type) {
775            (InterfaceGateType::RX(angle1), InterfaceGateType::RX(angle2)) => Some(
776                InterfaceGate::new(InterfaceGateType::RX(angle1 + angle2), gate1.qubits.clone()),
777            ),
778            (InterfaceGateType::RY(angle1), InterfaceGateType::RY(angle2)) => Some(
779                InterfaceGate::new(InterfaceGateType::RY(angle1 + angle2), gate1.qubits.clone()),
780            ),
781            (InterfaceGateType::RZ(angle1), InterfaceGateType::RZ(angle2)) => Some(
782                InterfaceGate::new(InterfaceGateType::RZ(angle1 + angle2), gate1.qubits.clone()),
783            ),
784            _ => None,
785        }
786    }
787
788    /// Optimize CNOT patterns
789    fn optimize_cnot_patterns(&mut self) {
790        // Look for CNOT chains and optimize them
791        let mut i = 0;
792        while i + 2 < self.gates.len() {
793            if self.is_cnot_chain(i) {
794                self.optimize_cnot_chain(i);
795            }
796            i += 1;
797        }
798    }
799
800    /// Check if there's a CNOT chain starting at position i
801    fn is_cnot_chain(&self, start: usize) -> bool {
802        if start + 2 >= self.gates.len() {
803            return false;
804        }
805
806        for i in start..start + 3 {
807            if !matches!(self.gates[i].gate_type, InterfaceGateType::CNOT) {
808                return false;
809            }
810        }
811
812        true
813    }
814
815    /// Optimize a CNOT chain
816    fn optimize_cnot_chain(&mut self, start: usize) {
817        // Simple optimization: remove triple CNOTs with same control/target
818        if start + 2 < self.gates.len() {
819            let gate1 = &self.gates[start];
820            let gate2 = &self.gates[start + 1];
821            let gate3 = &self.gates[start + 2];
822
823            if gate1.qubits == gate2.qubits && gate2.qubits == gate3.qubits {
824                // Three identical CNOTs = one CNOT
825                self.gates.drain(start + 1..start + 3);
826            }
827        }
828    }
829}
830
831/// Circuit optimization result
832#[derive(Debug, Clone)]
833pub struct CircuitOptimizationResult {
834    /// Original number of gates
835    pub original_gates: usize,
836    /// Optimized number of gates
837    pub optimized_gates: usize,
838    /// Original circuit depth
839    pub original_depth: usize,
840    /// Optimized circuit depth
841    pub optimized_depth: usize,
842    /// Number of gates eliminated
843    pub gates_eliminated: usize,
844    /// Depth reduction achieved
845    pub depth_reduction: usize,
846}
847
848/// Circuit execution backend
849#[derive(Debug, Clone, Copy, PartialEq, Eq)]
850pub enum SimulationBackend {
851    /// State vector simulation
852    StateVector,
853    /// Matrix Product State simulation
854    MPS,
855    /// Stabilizer simulation (for Clifford circuits)
856    Stabilizer,
857    /// Sparse matrix simulation
858    Sparse,
859    /// Tensor network simulation
860    TensorNetwork,
861    /// Automatic backend selection
862    Auto,
863}
864
865/// Circuit interface for simulation backends
866pub struct CircuitInterface {
867    /// Configuration
868    config: CircuitInterfaceConfig,
869    /// `SciRS2` backend for optimization
870    backend: Option<SciRS2Backend>,
871    /// Circuit cache
872    circuit_cache: Arc<Mutex<HashMap<u64, CompiledCircuit>>>,
873    /// Performance statistics
874    stats: CircuitInterfaceStats,
875}
876
877/// Compiled circuit representation
878#[derive(Debug, Clone)]
879pub struct CompiledCircuit {
880    /// Original circuit
881    pub original: InterfaceCircuit,
882    /// Optimized gate sequence
883    pub optimized_gates: Vec<InterfaceGate>,
884    /// Backend-specific compiled representation
885    pub backend_data: BackendCompiledData,
886    /// Compilation metadata
887    pub metadata: CompilationMetadata,
888}
889
890/// Backend-specific compiled data
891#[derive(Debug, Clone)]
892pub enum BackendCompiledData {
893    StateVector {
894        unitary_matrices: Vec<Array2<Complex64>>,
895        gate_indices: Vec<Vec<usize>>,
896    },
897    MPS {
898        bond_dimensions: Vec<usize>,
899        truncation_thresholds: Vec<f64>,
900    },
901    Stabilizer {
902        clifford_sequence: Vec<StabilizerOp>,
903    },
904    Sparse {
905        sparse_matrices: Vec<CSRMatrix>,
906    },
907}
908
909/// Stabilizer operation for Clifford circuits
910#[derive(Debug, Clone)]
911pub enum StabilizerOp {
912    H(usize),
913    S(usize),
914    CNOT(usize, usize),
915    X(usize),
916    Y(usize),
917    Z(usize),
918}
919
920/// Compilation metadata
921#[derive(Debug, Clone)]
922pub struct CompilationMetadata {
923    /// Compilation time in milliseconds
924    pub compilation_time_ms: f64,
925    /// Backend used for compilation
926    pub backend: SimulationBackend,
927    /// Optimization passes applied
928    pub optimization_passes: Vec<String>,
929    /// Estimated execution time
930    pub estimated_execution_time_ms: f64,
931    /// Memory requirements estimate
932    pub estimated_memory_bytes: usize,
933}
934
935/// Circuit interface performance statistics
936#[derive(Debug, Clone, Default, Serialize, Deserialize)]
937pub struct CircuitInterfaceStats {
938    /// Total circuits compiled
939    pub circuits_compiled: usize,
940    /// Total compilation time
941    pub total_compilation_time_ms: f64,
942    /// Cache hit rate
943    pub cache_hit_rate: f64,
944    /// Backend selection counts
945    pub backend_selections: HashMap<String, usize>,
946    /// Optimization statistics
947    pub optimization_stats: OptimizationStats,
948}
949
950/// Optimization statistics
951#[derive(Debug, Clone, Default, Serialize, Deserialize)]
952pub struct OptimizationStats {
953    /// Total gates eliminated
954    pub total_gates_eliminated: usize,
955    /// Total depth reduction
956    pub total_depth_reduction: usize,
957    /// Average optimization ratio
958    pub average_optimization_ratio: f64,
959}
960
961impl CircuitInterface {
962    /// Create new circuit interface
963    pub fn new(config: CircuitInterfaceConfig) -> Result<Self> {
964        Ok(Self {
965            config,
966            backend: None,
967            circuit_cache: Arc::new(Mutex::new(HashMap::new())),
968            stats: CircuitInterfaceStats::default(),
969        })
970    }
971
972    /// Initialize with `SciRS2` backend
973    pub fn with_backend(mut self) -> Result<Self> {
974        self.backend = Some(SciRS2Backend::new());
975        Ok(self)
976    }
977
978    /// Compile circuit for execution
979    pub fn compile_circuit(
980        &mut self,
981        circuit: &InterfaceCircuit,
982        backend: SimulationBackend,
983    ) -> Result<CompiledCircuit> {
984        let start_time = std::time::Instant::now();
985
986        // Check cache first
987        let circuit_hash = self.calculate_circuit_hash(circuit);
988        if self.config.enable_circuit_cache {
989            let cache = self
990                .circuit_cache
991                .lock()
992                .expect("circuit cache lock should not be poisoned");
993            if let Some(compiled) = cache.get(&circuit_hash) {
994                self.stats.cache_hit_rate = self
995                    .stats
996                    .cache_hit_rate
997                    .mul_add(self.stats.circuits_compiled as f64, 1.0)
998                    / (self.stats.circuits_compiled + 1) as f64;
999                return Ok(compiled.clone());
1000            }
1001        }
1002
1003        // Select backend automatically if needed
1004        let selected_backend = if backend == SimulationBackend::Auto {
1005            self.select_optimal_backend(circuit)?
1006        } else {
1007            backend
1008        };
1009
1010        // Optimize circuit if enabled
1011        let mut optimized_circuit = circuit.clone();
1012        let mut optimization_passes = Vec::new();
1013
1014        if self.config.enable_optimization {
1015            let opt_result = optimized_circuit.optimize();
1016            optimization_passes.push("basic_optimization".to_string());
1017
1018            self.stats.optimization_stats.total_gates_eliminated += opt_result.gates_eliminated;
1019            self.stats.optimization_stats.total_depth_reduction += opt_result.depth_reduction;
1020        }
1021
1022        // Compile for specific backend
1023        let backend_data = self.compile_for_backend(&optimized_circuit, selected_backend)?;
1024
1025        // Estimate execution time and memory
1026        let estimated_execution_time_ms =
1027            self.estimate_execution_time(&optimized_circuit, selected_backend);
1028        let estimated_memory_bytes =
1029            self.estimate_memory_requirements(&optimized_circuit, selected_backend);
1030
1031        let compilation_time_ms = start_time.elapsed().as_secs_f64() * 1000.0;
1032
1033        let compiled = CompiledCircuit {
1034            original: circuit.clone(),
1035            optimized_gates: optimized_circuit.gates,
1036            backend_data,
1037            metadata: CompilationMetadata {
1038                compilation_time_ms,
1039                backend: selected_backend,
1040                optimization_passes,
1041                estimated_execution_time_ms,
1042                estimated_memory_bytes,
1043            },
1044        };
1045
1046        // Update cache
1047        if self.config.enable_circuit_cache {
1048            let mut cache = self
1049                .circuit_cache
1050                .lock()
1051                .expect("circuit cache lock should not be poisoned");
1052            if cache.len() >= self.config.max_cache_size {
1053                // Simple LRU: remove oldest entry
1054                if let Some(oldest_key) = cache.keys().next().copied() {
1055                    cache.remove(&oldest_key);
1056                }
1057            }
1058            cache.insert(circuit_hash, compiled.clone());
1059        }
1060
1061        // Update statistics
1062        self.stats.circuits_compiled += 1;
1063        self.stats.total_compilation_time_ms += compilation_time_ms;
1064        *self
1065            .stats
1066            .backend_selections
1067            .entry(format!("{selected_backend:?}"))
1068            .or_insert(0) += 1;
1069
1070        Ok(compiled)
1071    }
1072
1073    /// Execute compiled circuit
1074    pub fn execute_circuit(
1075        &mut self,
1076        compiled: &CompiledCircuit,
1077        initial_state: Option<Array1<Complex64>>,
1078    ) -> Result<CircuitExecutionResult> {
1079        let start_time = std::time::Instant::now();
1080
1081        let result = match compiled.metadata.backend {
1082            SimulationBackend::StateVector => self.execute_statevector(compiled, initial_state)?,
1083            SimulationBackend::MPS => self.execute_mps(compiled, initial_state)?,
1084            SimulationBackend::Stabilizer => self.execute_stabilizer(compiled)?,
1085            SimulationBackend::Sparse => self.execute_sparse(compiled, initial_state)?,
1086            #[cfg(feature = "advanced_math")]
1087            SimulationBackend::TensorNetwork => {
1088                self.execute_tensor_network(compiled, initial_state)?
1089            }
1090            #[cfg(not(feature = "advanced_math"))]
1091            SimulationBackend::TensorNetwork => {
1092                return Err(SimulatorError::UnsupportedOperation(
1093                    "Tensor network simulation requires advanced_math feature".to_string(),
1094                ))
1095            }
1096            SimulationBackend::Auto => {
1097                unreachable!("Auto backend should be resolved during compilation")
1098            }
1099        };
1100
1101        let execution_time_ms = start_time.elapsed().as_secs_f64() * 1000.0;
1102
1103        Ok(CircuitExecutionResult {
1104            final_state: result.final_state,
1105            measurement_results: result.measurement_results,
1106            classical_bits: result.classical_bits,
1107            execution_time_ms,
1108            backend_used: compiled.metadata.backend,
1109            memory_used_bytes: result.memory_used_bytes,
1110        })
1111    }
1112
1113    /// Select optimal backend for circuit
1114    fn select_optimal_backend(&self, circuit: &InterfaceCircuit) -> Result<SimulationBackend> {
1115        let num_qubits = circuit.num_qubits;
1116        let two_qubit_gates = circuit.metadata.two_qubit_gates;
1117        let total_gates = circuit.gates.len();
1118
1119        // Check if circuit is Clifford (can use stabilizer simulation)
1120        if self.is_clifford_circuit(circuit) {
1121            return Ok(SimulationBackend::Stabilizer);
1122        }
1123
1124        // For small circuits, use state vector
1125        if num_qubits <= self.config.max_statevector_qubits {
1126            return Ok(SimulationBackend::StateVector);
1127        }
1128
1129        // For circuits with low entanglement, use MPS
1130        let entanglement_score = two_qubit_gates as f64 / total_gates as f64;
1131        if entanglement_score < 0.3 {
1132            return Ok(SimulationBackend::MPS);
1133        }
1134
1135        // For very sparse circuits, use sparse simulation
1136        let sparsity_score = self.estimate_sparsity(circuit);
1137        if sparsity_score > 0.8 {
1138            return Ok(SimulationBackend::Sparse);
1139        }
1140
1141        // For highly structured circuits, use tensor networks
1142        if self.has_tensor_network_structure(circuit) {
1143            return Ok(SimulationBackend::TensorNetwork);
1144        }
1145
1146        // Default to MPS for large circuits
1147        Ok(SimulationBackend::MPS)
1148    }
1149
1150    /// Check if circuit is Clifford
1151    fn is_clifford_circuit(&self, circuit: &InterfaceCircuit) -> bool {
1152        circuit.gates.iter().all(|gate| {
1153            matches!(
1154                gate.gate_type,
1155                InterfaceGateType::Identity
1156                    | InterfaceGateType::PauliX
1157                    | InterfaceGateType::PauliY
1158                    | InterfaceGateType::PauliZ
1159                    | InterfaceGateType::Hadamard
1160                    | InterfaceGateType::S
1161                    | InterfaceGateType::CNOT
1162                    | InterfaceGateType::CZ
1163                    | InterfaceGateType::SWAP
1164                    | InterfaceGateType::Measure
1165                    | InterfaceGateType::Reset
1166            )
1167        })
1168    }
1169
1170    /// Estimate circuit sparsity
1171    fn estimate_sparsity(&self, circuit: &InterfaceCircuit) -> f64 {
1172        // Heuristic: circuits with many single-qubit gates are typically sparser
1173        let single_qubit_gates = circuit.gates.iter().filter(|g| g.num_qubits() == 1).count();
1174
1175        single_qubit_gates as f64 / circuit.gates.len() as f64
1176    }
1177
1178    /// Check if circuit has tensor network structure
1179    fn has_tensor_network_structure(&self, circuit: &InterfaceCircuit) -> bool {
1180        // Heuristic: circuits with regular structure and moderate entanglement
1181        let depth = circuit.metadata.depth;
1182        let num_qubits = circuit.num_qubits;
1183
1184        // Look for regular patterns
1185        depth > num_qubits && circuit.metadata.complexity_score > 100.0
1186    }
1187
1188    /// Compile circuit for specific backend
1189    fn compile_for_backend(
1190        &self,
1191        circuit: &InterfaceCircuit,
1192        backend: SimulationBackend,
1193    ) -> Result<BackendCompiledData> {
1194        match backend {
1195            SimulationBackend::StateVector => {
1196                let mut unitary_matrices = Vec::new();
1197                let mut gate_indices = Vec::new();
1198
1199                for gate in &circuit.gates {
1200                    if gate.is_unitary() {
1201                        unitary_matrices.push(gate.unitary_matrix()?);
1202                        gate_indices.push(gate.qubits.clone());
1203                    }
1204                }
1205
1206                Ok(BackendCompiledData::StateVector {
1207                    unitary_matrices,
1208                    gate_indices,
1209                })
1210            }
1211            SimulationBackend::MPS => {
1212                // Analyze circuit to determine optimal bond dimensions
1213                let bond_dimensions = self.calculate_optimal_bond_dimensions(circuit);
1214                let truncation_thresholds = vec![1e-12; circuit.gates.len()];
1215
1216                Ok(BackendCompiledData::MPS {
1217                    bond_dimensions,
1218                    truncation_thresholds,
1219                })
1220            }
1221            SimulationBackend::Stabilizer => {
1222                let mut clifford_sequence = Vec::new();
1223
1224                for gate in &circuit.gates {
1225                    match &gate.gate_type {
1226                        InterfaceGateType::Hadamard => {
1227                            clifford_sequence.push(StabilizerOp::H(gate.qubits[0]));
1228                        }
1229                        InterfaceGateType::S => {
1230                            clifford_sequence.push(StabilizerOp::S(gate.qubits[0]));
1231                        }
1232                        InterfaceGateType::PauliX => {
1233                            clifford_sequence.push(StabilizerOp::X(gate.qubits[0]));
1234                        }
1235                        InterfaceGateType::PauliY => {
1236                            clifford_sequence.push(StabilizerOp::Y(gate.qubits[0]));
1237                        }
1238                        InterfaceGateType::PauliZ => {
1239                            clifford_sequence.push(StabilizerOp::Z(gate.qubits[0]));
1240                        }
1241                        InterfaceGateType::CNOT => clifford_sequence
1242                            .push(StabilizerOp::CNOT(gate.qubits[0], gate.qubits[1])),
1243                        _ => {} // Skip non-Clifford gates
1244                    }
1245                }
1246
1247                Ok(BackendCompiledData::Stabilizer { clifford_sequence })
1248            }
1249            SimulationBackend::Sparse => {
1250                let sparse_matrices = Vec::new(); // Would be implemented with actual sparse matrix compilation
1251                Ok(BackendCompiledData::Sparse { sparse_matrices })
1252            }
1253            SimulationBackend::TensorNetwork => {
1254                // For now, use the same data as state vector
1255                let mut unitary_matrices = Vec::new();
1256                let mut gate_indices = Vec::new();
1257
1258                for gate in &circuit.gates {
1259                    if gate.is_unitary() {
1260                        unitary_matrices.push(gate.unitary_matrix()?);
1261                        gate_indices.push(gate.qubits.clone());
1262                    }
1263                }
1264
1265                Ok(BackendCompiledData::StateVector {
1266                    unitary_matrices,
1267                    gate_indices,
1268                })
1269            }
1270            SimulationBackend::Auto => unreachable!(),
1271        }
1272    }
1273
1274    /// Calculate optimal bond dimensions for MPS
1275    fn calculate_optimal_bond_dimensions(&self, circuit: &InterfaceCircuit) -> Vec<usize> {
1276        let base_bond_dim = self.config.max_mps_bond_dim.min(64);
1277        vec![base_bond_dim; circuit.num_qubits - 1]
1278    }
1279
1280    /// Execute state vector simulation
1281    fn execute_statevector(
1282        &self,
1283        compiled: &CompiledCircuit,
1284        initial_state: Option<Array1<Complex64>>,
1285    ) -> Result<BackendExecutionResult> {
1286        let _simulator = StateVectorSimulator::new();
1287
1288        // For now, use a placeholder implementation
1289        let num_qubits = compiled.original.num_qubits;
1290        let state_size = 1 << num_qubits;
1291
1292        let final_state = initial_state.unwrap_or_else(|| {
1293            let mut state = Array1::zeros(state_size);
1294            state[0] = Complex64::new(1.0, 0.0);
1295            state
1296        });
1297        let memory_used = final_state.len() * std::mem::size_of::<Complex64>();
1298
1299        Ok(BackendExecutionResult {
1300            final_state: Some(final_state),
1301            measurement_results: Vec::new(),
1302            classical_bits: vec![false; compiled.original.num_classical],
1303            memory_used_bytes: memory_used,
1304        })
1305    }
1306
1307    /// Execute MPS simulation
1308    fn execute_mps(
1309        &self,
1310        compiled: &CompiledCircuit,
1311        initial_state: Option<Array1<Complex64>>,
1312    ) -> Result<BackendExecutionResult> {
1313        // Placeholder implementation
1314        Ok(BackendExecutionResult {
1315            final_state: None,
1316            measurement_results: Vec::new(),
1317            classical_bits: vec![false; compiled.original.num_classical],
1318            memory_used_bytes: 0,
1319        })
1320    }
1321
1322    /// Execute stabilizer simulation
1323    fn execute_stabilizer(&self, compiled: &CompiledCircuit) -> Result<BackendExecutionResult> {
1324        // Placeholder implementation
1325        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    /// Execute sparse simulation
1334    fn execute_sparse(
1335        &self,
1336        compiled: &CompiledCircuit,
1337        initial_state: Option<Array1<Complex64>>,
1338    ) -> Result<BackendExecutionResult> {
1339        // Placeholder implementation
1340        Ok(BackendExecutionResult {
1341            final_state: None,
1342            measurement_results: Vec::new(),
1343            classical_bits: vec![false; compiled.original.num_classical],
1344            memory_used_bytes: 0,
1345        })
1346    }
1347
1348    /// Execute tensor network simulation
1349    #[cfg(feature = "advanced_math")]
1350    fn execute_tensor_network(
1351        &self,
1352        compiled: &CompiledCircuit,
1353        initial_state: Option<Array1<Complex64>>,
1354    ) -> Result<BackendExecutionResult> {
1355        // Placeholder implementation
1356        Ok(BackendExecutionResult {
1357            final_state: None,
1358            measurement_results: Vec::new(),
1359            classical_bits: vec![false; compiled.original.num_classical],
1360            memory_used_bytes: 0,
1361        })
1362    }
1363
1364    #[cfg(not(feature = "advanced_math"))]
1365    fn execute_tensor_network(
1366        &self,
1367        _compiled: &CompiledCircuit,
1368        _initial_state: Option<Array1<Complex64>>,
1369    ) -> Result<BackendExecutionResult> {
1370        Err(SimulatorError::UnsupportedOperation(
1371            "Tensor network simulation requires advanced_math feature".to_string(),
1372        ))
1373    }
1374
1375    /// Calculate circuit hash for caching
1376    fn calculate_circuit_hash(&self, circuit: &InterfaceCircuit) -> u64 {
1377        let mut hasher = DefaultHasher::new();
1378        circuit.num_qubits.hash(&mut hasher);
1379        circuit.num_classical.hash(&mut hasher);
1380
1381        for gate in &circuit.gates {
1382            // Hash gate type discriminant
1383            std::mem::discriminant(&gate.gate_type).hash(&mut hasher);
1384            // Hash gate parameters separately
1385            match &gate.gate_type {
1386                InterfaceGateType::Phase(angle)
1387                | InterfaceGateType::RX(angle)
1388                | InterfaceGateType::RY(angle)
1389                | InterfaceGateType::RZ(angle) => {
1390                    angle.to_bits().hash(&mut hasher);
1391                }
1392                _ => {}
1393            }
1394            gate.qubits.hash(&mut hasher);
1395        }
1396
1397        hasher.finish()
1398    }
1399
1400    /// Estimate execution time
1401    fn estimate_execution_time(
1402        &self,
1403        circuit: &InterfaceCircuit,
1404        backend: SimulationBackend,
1405    ) -> f64 {
1406        let base_time_per_gate = match backend {
1407            SimulationBackend::StateVector => 0.1, // ms per gate
1408            SimulationBackend::MPS => 1.0,
1409            SimulationBackend::Stabilizer => 0.01,
1410            SimulationBackend::Sparse => 0.5,
1411            SimulationBackend::TensorNetwork => 2.0,
1412            SimulationBackend::Auto => 1.0,
1413        };
1414
1415        circuit.gates.len() as f64 * base_time_per_gate * (1.1_f64).powi(circuit.num_qubits as i32)
1416    }
1417
1418    /// Estimate memory requirements
1419    fn estimate_memory_requirements(
1420        &self,
1421        circuit: &InterfaceCircuit,
1422        backend: SimulationBackend,
1423    ) -> usize {
1424        match backend {
1425            SimulationBackend::StateVector => {
1426                (1_usize << circuit.num_qubits) * std::mem::size_of::<Complex64>()
1427            }
1428            SimulationBackend::MPS => {
1429                circuit.num_qubits
1430                    * self.config.max_mps_bond_dim
1431                    * self.config.max_mps_bond_dim
1432                    * std::mem::size_of::<Complex64>()
1433            }
1434            SimulationBackend::Stabilizer => {
1435                circuit.num_qubits * circuit.num_qubits * 2 // Stabilizer tableau
1436            }
1437            SimulationBackend::Sparse => {
1438                circuit.gates.len() * 1000 * std::mem::size_of::<Complex64>() // Rough estimate
1439            }
1440            SimulationBackend::TensorNetwork => {
1441                circuit.num_qubits * 64 * std::mem::size_of::<Complex64>() // Bond dimension 64
1442            }
1443            SimulationBackend::Auto => 0,
1444        }
1445    }
1446
1447    /// Get performance statistics
1448    #[must_use]
1449    pub const fn get_stats(&self) -> &CircuitInterfaceStats {
1450        &self.stats
1451    }
1452
1453    /// Reset performance statistics
1454    pub fn reset_stats(&mut self) {
1455        self.stats = CircuitInterfaceStats::default();
1456    }
1457}
1458
1459/// Backend execution result
1460#[derive(Debug)]
1461struct BackendExecutionResult {
1462    final_state: Option<Array1<Complex64>>,
1463    measurement_results: Vec<bool>,
1464    classical_bits: Vec<bool>,
1465    memory_used_bytes: usize,
1466}
1467
1468/// Circuit execution result
1469#[derive(Debug)]
1470pub struct CircuitExecutionResult {
1471    /// Final quantum state (if available)
1472    pub final_state: Option<Array1<Complex64>>,
1473    /// Measurement results
1474    pub measurement_results: Vec<bool>,
1475    /// Classical bit values
1476    pub classical_bits: Vec<bool>,
1477    /// Execution time in milliseconds
1478    pub execution_time_ms: f64,
1479    /// Backend used for execution
1480    pub backend_used: SimulationBackend,
1481    /// Memory used in bytes
1482    pub memory_used_bytes: usize,
1483}
1484
1485/// Circuit interface utilities
1486pub struct CircuitInterfaceUtils;
1487
1488impl CircuitInterfaceUtils {
1489    /// Create a test circuit
1490    #[must_use]
1491    pub fn create_test_circuit(circuit_type: &str, num_qubits: usize) -> InterfaceCircuit {
1492        let mut circuit = InterfaceCircuit::new(num_qubits, num_qubits);
1493
1494        match circuit_type {
1495            "ghz" => {
1496                // GHZ state preparation
1497                circuit.add_gate(InterfaceGate::new(InterfaceGateType::Hadamard, vec![0]));
1498                for i in 1..num_qubits {
1499                    circuit.add_gate(InterfaceGate::new(InterfaceGateType::CNOT, vec![0, i]));
1500                }
1501            }
1502            "qft" => {
1503                // Quantum Fourier Transform
1504                for i in 0..num_qubits {
1505                    circuit.add_gate(InterfaceGate::new(InterfaceGateType::Hadamard, vec![i]));
1506                    for j in i + 1..num_qubits {
1507                        let angle = std::f64::consts::PI / f64::from(1 << (j - i));
1508                        circuit.add_gate(InterfaceGate::new(
1509                            InterfaceGateType::CRZ(angle),
1510                            vec![j, i],
1511                        ));
1512                    }
1513                }
1514            }
1515            "random" => {
1516                // Random circuit
1517                for _ in 0..num_qubits * 5 {
1518                    let qubit = fastrand::usize(0..num_qubits);
1519                    let gate_type = match fastrand::usize(0..4) {
1520                        0 => InterfaceGateType::Hadamard,
1521                        1 => InterfaceGateType::RX(fastrand::f64() * 2.0 * std::f64::consts::PI),
1522                        2 => InterfaceGateType::RY(fastrand::f64() * 2.0 * std::f64::consts::PI),
1523                        _ => InterfaceGateType::RZ(fastrand::f64() * 2.0 * std::f64::consts::PI),
1524                    };
1525                    circuit.add_gate(InterfaceGate::new(gate_type, vec![qubit]));
1526                }
1527            }
1528            _ => {
1529                // Identity circuit
1530                for i in 0..num_qubits {
1531                    circuit.add_gate(InterfaceGate::new(InterfaceGateType::Identity, vec![i]));
1532                }
1533            }
1534        }
1535
1536        circuit
1537    }
1538
1539    /// Benchmark circuit interface
1540    pub fn benchmark_interface(
1541        config: CircuitInterfaceConfig,
1542    ) -> Result<InterfaceBenchmarkResults> {
1543        let mut interface = CircuitInterface::new(config)?;
1544        let mut results = InterfaceBenchmarkResults::default();
1545
1546        let circuit_types = vec!["ghz", "qft", "random"];
1547        let qubit_counts = vec![5, 10, 15, 20];
1548
1549        for circuit_type in circuit_types {
1550            for &num_qubits in &qubit_counts {
1551                let circuit = Self::create_test_circuit(circuit_type, num_qubits);
1552
1553                let start = std::time::Instant::now();
1554                let compiled = interface.compile_circuit(&circuit, SimulationBackend::Auto)?;
1555                let compilation_time = start.elapsed().as_secs_f64() * 1000.0;
1556
1557                let start = std::time::Instant::now();
1558                let _result = interface.execute_circuit(&compiled, None)?;
1559                let execution_time = start.elapsed().as_secs_f64() * 1000.0;
1560
1561                results
1562                    .compilation_times
1563                    .push((format!("{circuit_type}_{num_qubits}"), compilation_time));
1564                results
1565                    .execution_times
1566                    .push((format!("{circuit_type}_{num_qubits}"), execution_time));
1567            }
1568        }
1569
1570        results.interface_stats = interface.get_stats().clone();
1571        Ok(results)
1572    }
1573}
1574
1575/// Interface benchmark results
1576#[derive(Debug, Clone, Default)]
1577pub struct InterfaceBenchmarkResults {
1578    /// Compilation times (`circuit_name`, `time_ms`)
1579    pub compilation_times: Vec<(String, f64)>,
1580    /// Execution times (`circuit_name`, `time_ms`)
1581    pub execution_times: Vec<(String, f64)>,
1582    /// Interface statistics
1583    pub interface_stats: CircuitInterfaceStats,
1584}
1585
1586#[cfg(test)]
1587mod tests {
1588    use super::*;
1589    use approx::assert_abs_diff_eq;
1590
1591    #[test]
1592    fn test_interface_gate_creation() {
1593        let gate = InterfaceGate::new(InterfaceGateType::Hadamard, vec![0]);
1594        assert_eq!(gate.qubits, vec![0]);
1595        assert!(gate.is_unitary());
1596        assert!(!gate.is_measurement());
1597    }
1598
1599    #[test]
1600    fn test_measurement_gate() {
1601        let gate = InterfaceGate::measurement(0, 0);
1602        assert!(gate.is_measurement());
1603        assert!(!gate.is_unitary());
1604        assert_eq!(gate.classical_targets, vec![0]);
1605    }
1606
1607    #[test]
1608    fn test_circuit_creation() {
1609        let mut circuit = InterfaceCircuit::new(3, 3);
1610        circuit.add_gate(InterfaceGate::new(InterfaceGateType::Hadamard, vec![0]));
1611        circuit.add_gate(InterfaceGate::new(InterfaceGateType::CNOT, vec![0, 1]));
1612
1613        assert_eq!(circuit.gates.len(), 2);
1614        assert_eq!(circuit.calculate_depth(), 2);
1615    }
1616
1617    #[test]
1618    fn test_circuit_optimization() {
1619        let mut circuit = InterfaceCircuit::new(2, 0);
1620        circuit.add_gate(InterfaceGate::new(InterfaceGateType::PauliX, vec![0]));
1621        circuit.add_gate(InterfaceGate::new(InterfaceGateType::PauliX, vec![0])); // Should cancel
1622        circuit.add_gate(InterfaceGate::new(InterfaceGateType::Identity, vec![1])); // Should be removed
1623
1624        let result = circuit.optimize();
1625        assert_eq!(result.gates_eliminated, 3); // All gates should be eliminated
1626    }
1627
1628    #[test]
1629    fn test_gate_unitary_matrices() {
1630        let hadamard = InterfaceGate::new(InterfaceGateType::Hadamard, vec![0]);
1631        let matrix = hadamard
1632            .unitary_matrix()
1633            .expect("should get Hadamard matrix");
1634
1635        let inv_sqrt2 = 1.0 / (2.0_f64).sqrt();
1636        assert_abs_diff_eq!(matrix[[0, 0]].re, inv_sqrt2, epsilon = 1e-10);
1637        assert_abs_diff_eq!(matrix[[1, 1]].re, -inv_sqrt2, epsilon = 1e-10);
1638    }
1639
1640    #[test]
1641    fn test_rotation_gate_merging() {
1642        let mut circuit = InterfaceCircuit::new(1, 0);
1643        circuit.add_gate(InterfaceGate::new(InterfaceGateType::RX(0.5), vec![0]));
1644        circuit.add_gate(InterfaceGate::new(InterfaceGateType::RX(0.3), vec![0]));
1645
1646        let _ = circuit.optimize();
1647        assert_eq!(circuit.gates.len(), 1);
1648
1649        if let InterfaceGateType::RX(angle) = &circuit.gates[0].gate_type {
1650            assert_abs_diff_eq!(*angle, 0.8, epsilon = 1e-10);
1651        } else {
1652            panic!("Expected merged RX gate");
1653        }
1654    }
1655
1656    #[test]
1657    fn test_circuit_interface_creation() {
1658        let config = CircuitInterfaceConfig::default();
1659        let _interface =
1660            CircuitInterface::new(config.clone()).expect("should create circuit interface");
1661        assert!(config.auto_backend_selection);
1662        assert!(config.enable_optimization);
1663        assert_eq!(config.max_statevector_qubits, 25);
1664    }
1665
1666    #[test]
1667    fn test_test_circuit_creation() {
1668        let ghz_circuit = CircuitInterfaceUtils::create_test_circuit("ghz", 3);
1669        assert_eq!(ghz_circuit.num_qubits, 3);
1670        assert_eq!(ghz_circuit.gates.len(), 3); // H + 2 CNOTs
1671
1672        let qft_circuit = CircuitInterfaceUtils::create_test_circuit("qft", 3);
1673        assert!(qft_circuit.gates.len() > 3); // Should have multiple gates
1674    }
1675
1676    #[test]
1677    fn test_circuit_metadata() {
1678        let circuit = CircuitInterfaceUtils::create_test_circuit("ghz", 4);
1679        assert_eq!(circuit.metadata.depth, 4); // H on qubit 0, then 3 CNOTs sequentially
1680        assert_eq!(circuit.metadata.two_qubit_gates, 3);
1681    }
1682
1683    #[test]
1684    fn test_clifford_detection() {
1685        let mut circuit = InterfaceCircuit::new(2, 0);
1686        circuit.add_gate(InterfaceGate::new(InterfaceGateType::Hadamard, vec![0]));
1687        circuit.add_gate(InterfaceGate::new(InterfaceGateType::CNOT, vec![0, 1]));
1688        circuit.add_gate(InterfaceGate::new(InterfaceGateType::S, vec![1]));
1689
1690        let config = CircuitInterfaceConfig::default();
1691        let interface = CircuitInterface::new(config).expect("should create circuit interface");
1692        assert!(interface.is_clifford_circuit(&circuit));
1693
1694        // Add non-Clifford gate
1695        circuit.add_gate(InterfaceGate::new(InterfaceGateType::T, vec![0]));
1696        assert!(!interface.is_clifford_circuit(&circuit));
1697    }
1698}