quantrs2_core/
quantum_debugger.rs

1//! Quantum Circuit Debugger with SciRS2 Visualization Tools
2//!
3//! This module provides comprehensive debugging capabilities for quantum circuits
4//! using SciRS2's advanced visualization and analysis tools.
5
6use crate::gate_translation::GateType;
7// use scirs2_core::memory::BufferPool;
8use crate::buffer_pool::BufferPool;
9use std::time::{Duration, Instant};
10
11/// Simplified quantum gate representation for debugging
12#[derive(Debug, Clone)]
13pub struct QuantumGate {
14    gate_type: GateType,
15    target_qubits: Vec<usize>,
16    control_qubits: Option<Vec<usize>>,
17}
18
19impl QuantumGate {
20    pub const fn new(
21        gate_type: GateType,
22        target_qubits: Vec<usize>,
23        control_qubits: Option<Vec<usize>>,
24    ) -> Self {
25        Self {
26            gate_type,
27            target_qubits,
28            control_qubits,
29        }
30    }
31
32    pub const fn gate_type(&self) -> &GateType {
33        &self.gate_type
34    }
35
36    pub fn target_qubits(&self) -> &[usize] {
37        &self.target_qubits
38    }
39
40    pub fn control_qubits(&self) -> Option<&[usize]> {
41        self.control_qubits.as_deref()
42    }
43}
44use crate::error::QuantRS2Error;
45use std::collections::{HashMap, VecDeque};
46// Serde imports would go here if needed
47use scirs2_core::Complex64;
48
49/// Performance tracking for enhanced debugging with SciRS2
50#[derive(Debug, Clone)]
51pub struct PerformanceTracker {
52    gate_timing: HashMap<String, Duration>,
53    memory_usage: Vec<usize>,
54    computation_start: Option<Instant>,
55    total_execution_time: Duration,
56    simd_operations_count: usize,
57    parallel_operations_count: usize,
58}
59
60impl PerformanceTracker {
61    pub fn new() -> Self {
62        Self {
63            gate_timing: HashMap::new(),
64            memory_usage: Vec::new(),
65            computation_start: None,
66            total_execution_time: Duration::new(0, 0),
67            simd_operations_count: 0,
68            parallel_operations_count: 0,
69        }
70    }
71
72    pub fn start_timing(&mut self) {
73        self.computation_start = Some(Instant::now());
74    }
75
76    pub fn record_gate_timing(&mut self, gate_type: &str, duration: Duration) {
77        *self
78            .gate_timing
79            .entry(gate_type.to_string())
80            .or_insert(Duration::new(0, 0)) += duration;
81    }
82
83    pub fn record_memory_usage(&mut self, usage: usize) {
84        self.memory_usage.push(usage);
85    }
86
87    pub const fn increment_simd_ops(&mut self) {
88        self.simd_operations_count += 1;
89    }
90
91    pub const fn increment_parallel_ops(&mut self) {
92        self.parallel_operations_count += 1;
93    }
94
95    pub fn finish_timing(&mut self) {
96        if let Some(start) = self.computation_start.take() {
97            self.total_execution_time = start.elapsed();
98        }
99    }
100}
101
102/// Configuration for quantum debugging
103#[derive(Debug, Clone)]
104pub struct DebugConfig {
105    /// Enable state vector tracking
106    pub track_state_vectors: bool,
107    /// Enable entanglement analysis
108    pub analyze_entanglement: bool,
109    /// Enable amplitude visualization
110    pub visualize_amplitudes: bool,
111    /// Enable gate effect tracking
112    pub track_gate_effects: bool,
113    /// Maximum number of qubits for detailed tracking
114    pub max_detailed_qubits: usize,
115    /// Sampling rate for large circuits
116    pub sampling_rate: f64,
117    /// Enable breakpoint functionality
118    pub enable_breakpoints: bool,
119    /// Memory limit for state storage (MB)
120    pub memory_limit_mb: usize,
121}
122
123impl Default for DebugConfig {
124    fn default() -> Self {
125        Self {
126            track_state_vectors: true,
127            analyze_entanglement: true,
128            visualize_amplitudes: true,
129            track_gate_effects: true,
130            max_detailed_qubits: 10,
131            sampling_rate: 0.1,
132            enable_breakpoints: true,
133            memory_limit_mb: 1024,
134        }
135    }
136}
137
138/// Quantum circuit debugger with SciRS2 visualization
139pub struct QuantumDebugger {
140    config: DebugConfig,
141    execution_trace: Vec<DebugStep>,
142    breakpoints: Vec<Breakpoint>,
143    current_step: usize,
144    state_history: VecDeque<StateSnapshot>,
145    gate_statistics: GateStatistics,
146    buffer_pool: Option<BufferPool<Complex64>>,
147    performance_metrics: PerformanceTracker,
148}
149
150impl QuantumDebugger {
151    /// Create a new quantum debugger
152    pub fn new() -> Self {
153        let config = DebugConfig::default();
154        Self::with_config(config)
155    }
156
157    /// Create a new quantum debugger with custom configuration
158    pub fn with_config(config: DebugConfig) -> Self {
159        let buffer_pool = if config.memory_limit_mb > 0 {
160            Some(BufferPool::<Complex64>::new())
161        } else {
162            None
163        };
164
165        Self {
166            config,
167            execution_trace: Vec::new(),
168            breakpoints: Vec::new(),
169            current_step: 0,
170            state_history: VecDeque::new(),
171            gate_statistics: GateStatistics::new(),
172            buffer_pool,
173            performance_metrics: PerformanceTracker::new(),
174        }
175    }
176
177    /// Set a breakpoint at a specific step
178    pub fn set_breakpoint(&mut self, step: usize, condition: BreakpointCondition) {
179        self.breakpoints.push(Breakpoint {
180            step,
181            condition,
182            enabled: true,
183        });
184    }
185
186    /// Remove a breakpoint
187    pub fn remove_breakpoint(&mut self, step: usize) {
188        self.breakpoints.retain(|bp| bp.step != step);
189    }
190
191    /// Debug a quantum circuit execution with SciRS2 performance tracking
192    pub fn debug_circuit(
193        &mut self,
194        circuit: &[QuantumGate],
195        initial_state: &[Complex64],
196        num_qubits: usize,
197    ) -> Result<DebugResult, QuantRS2Error> {
198        self.reset_debug_session();
199
200        // Start performance tracking
201        self.performance_metrics.start_timing();
202
203        let mut current_state = initial_state.to_vec();
204        let mut step = 0;
205
206        // Record initial state
207        if self.config.track_state_vectors {
208            self.record_state_snapshot(step, &current_state, None, num_qubits)?;
209        }
210
211        for (gate_index, gate) in circuit.iter().enumerate() {
212            step += 1;
213
214            // Check breakpoints
215            if self.should_break_at_step(step, &current_state, gate) {
216                return Ok(DebugResult {
217                    status: DebugStatus::BreakpointHit(step),
218                    final_state: current_state,
219                    execution_trace: self.execution_trace.clone(),
220                    analysis: self.generate_analysis(num_qubits)?,
221                });
222            }
223
224            // Apply gate and record debug information with performance tracking
225            let gate_start = Instant::now();
226            let gate_effect =
227                self.apply_gate_with_debugging(gate, &mut current_state, step, num_qubits)?;
228            let gate_duration = gate_start.elapsed();
229
230            // Record performance metrics
231            let gate_type_str = format!("{:?}", gate.gate_type());
232            self.performance_metrics
233                .record_gate_timing(&gate_type_str, gate_duration);
234            self.performance_metrics
235                .record_memory_usage(current_state.len() * std::mem::size_of::<Complex64>());
236
237            self.execution_trace.push(DebugStep {
238                step,
239                gate: gate.clone(),
240                gate_effect,
241                state_before: if self.config.track_state_vectors {
242                    Some(self.get_previous_state())
243                } else {
244                    None
245                },
246                state_after: if self.config.track_state_vectors {
247                    Some(current_state.clone())
248                } else {
249                    None
250                },
251                entanglement_info: if self.config.analyze_entanglement {
252                    Some(self.analyze_entanglement(&current_state, num_qubits)?)
253                } else {
254                    None
255                },
256                amplitude_analysis: if self.config.visualize_amplitudes {
257                    Some(self.analyze_amplitudes(&current_state)?)
258                } else {
259                    None
260                },
261            });
262
263            // Record state snapshot
264            if self.config.track_state_vectors {
265                self.record_state_snapshot(step, &current_state, Some(gate_index), num_qubits)?;
266            }
267
268            // Update statistics
269            self.gate_statistics.record_gate(gate);
270        }
271
272        self.current_step = step;
273
274        // Finish performance tracking
275        self.performance_metrics.finish_timing();
276
277        Ok(DebugResult {
278            status: DebugStatus::Completed,
279            final_state: current_state,
280            execution_trace: self.execution_trace.clone(),
281            analysis: self.generate_analysis(num_qubits)?,
282        })
283    }
284
285    /// Reset debug session
286    fn reset_debug_session(&mut self) {
287        self.execution_trace.clear();
288        self.current_step = 0;
289        self.state_history.clear();
290        self.gate_statistics = GateStatistics::new();
291        self.performance_metrics = PerformanceTracker::new();
292    }
293
294    /// Check if execution should break at current step
295    fn should_break_at_step(&self, step: usize, state: &[Complex64], gate: &QuantumGate) -> bool {
296        if !self.config.enable_breakpoints {
297            return false;
298        }
299
300        for breakpoint in &self.breakpoints {
301            if breakpoint.enabled && breakpoint.step == step {
302                match &breakpoint.condition {
303                    BreakpointCondition::Always => return true,
304                    BreakpointCondition::StateCondition(condition) => {
305                        if self.evaluate_state_condition(state, condition) {
306                            return true;
307                        }
308                    }
309                    BreakpointCondition::GateType(gate_type) => {
310                        if std::mem::discriminant(gate.gate_type())
311                            == std::mem::discriminant(gate_type)
312                        {
313                            return true;
314                        }
315                    }
316                    BreakpointCondition::QubitIndex(qubit) => {
317                        if gate.target_qubits().contains(qubit) {
318                            return true;
319                        }
320                    }
321                }
322            }
323        }
324
325        false
326    }
327
328    /// Evaluate a state condition
329    fn evaluate_state_condition(&self, state: &[Complex64], condition: &StateCondition) -> bool {
330        match condition {
331            StateCondition::AmplitudeThreshold { qubit, threshold } => {
332                if let Some(amplitude) = self.get_qubit_amplitude(state, *qubit) {
333                    amplitude.norm_sqr() > *threshold
334                } else {
335                    false
336                }
337            }
338            StateCondition::EntanglementThreshold { threshold } => {
339                if let Ok(entanglement) = self.calculate_total_entanglement(state) {
340                    entanglement > *threshold
341                } else {
342                    false
343                }
344            }
345            StateCondition::PhaseDifference {
346                qubit1,
347                qubit2,
348                threshold,
349            } => {
350                if let (Some(amp1), Some(amp2)) = (
351                    self.get_qubit_amplitude(state, *qubit1),
352                    self.get_qubit_amplitude(state, *qubit2),
353                ) {
354                    let phase_diff = (amp1.arg() - amp2.arg()).abs();
355                    phase_diff > *threshold
356                } else {
357                    false
358                }
359            }
360        }
361    }
362
363    /// Apply gate with debugging information
364    fn apply_gate_with_debugging(
365        &self,
366        gate: &QuantumGate,
367        state: &mut Vec<Complex64>,
368        _step: usize,
369        num_qubits: usize,
370    ) -> Result<GateEffect, QuantRS2Error> {
371        let state_before = state.clone();
372
373        // Apply the gate (simplified implementation)
374        self.apply_gate_to_state(gate, state, num_qubits)?;
375
376        // Calculate gate effect
377        let effect = self.calculate_gate_effect(&state_before, state, gate)?;
378
379        Ok(effect)
380    }
381
382    /// Apply a gate to the state vector (simplified implementation)
383    fn apply_gate_to_state(
384        &self,
385        gate: &QuantumGate,
386        state: &mut [Complex64],
387        num_qubits: usize,
388    ) -> Result<(), QuantRS2Error> {
389        use crate::gate_translation::GateType;
390
391        match gate.gate_type() {
392            GateType::X => {
393                if let Some(&target) = gate.target_qubits().first() {
394                    let target_bit = 1 << target;
395                    for i in 0..(1 << num_qubits) {
396                        let j = i ^ target_bit;
397                        if i < j {
398                            state.swap(i, j);
399                        }
400                    }
401                }
402            }
403            GateType::Y => {
404                if let Some(&target) = gate.target_qubits().first() {
405                    let target_bit = 1 << target;
406                    for i in 0..(1 << num_qubits) {
407                        let j = i ^ target_bit;
408                        if i < j {
409                            let temp = state[i];
410                            state[i] = Complex64::new(0.0, 1.0) * state[j];
411                            state[j] = Complex64::new(0.0, -1.0) * temp;
412                        }
413                    }
414                }
415            }
416            GateType::Z => {
417                if let Some(&target) = gate.target_qubits().first() {
418                    let target_bit = 1 << target;
419                    for i in 0..(1 << num_qubits) {
420                        if i & target_bit != 0 {
421                            state[i] *= -1.0;
422                        }
423                    }
424                }
425            }
426            GateType::H => {
427                if let Some(&target) = gate.target_qubits().first() {
428                    let target_bit = 1 << target;
429                    let inv_sqrt2 = 1.0 / std::f64::consts::SQRT_2;
430                    for i in 0..(1 << num_qubits) {
431                        let j = i ^ target_bit;
432                        if i < j {
433                            let temp = state[i];
434                            state[i] = inv_sqrt2 * (temp + state[j]);
435                            state[j] = inv_sqrt2 * (temp - state[j]);
436                        }
437                    }
438                }
439            }
440            GateType::CNOT => {
441                if gate.target_qubits().len() >= 2 {
442                    let control = gate.target_qubits()[0];
443                    let target = gate.target_qubits()[1];
444                    let control_bit = 1 << control;
445                    let target_bit = 1 << target;
446
447                    for i in 0..(1 << num_qubits) {
448                        if i & control_bit != 0 {
449                            let j = i ^ target_bit;
450                            if i != j {
451                                state.swap(i, j);
452                            }
453                        }
454                    }
455                }
456            }
457            _ => {
458                // For other gates, no operation (placeholder)
459            }
460        }
461
462        Ok(())
463    }
464
465    /// Calculate the effect of a gate on the quantum state
466    fn calculate_gate_effect(
467        &self,
468        state_before: &[Complex64],
469        state_after: &[Complex64],
470        gate: &QuantumGate,
471    ) -> Result<GateEffect, QuantRS2Error> {
472        let amplitude_changes = self.calculate_amplitude_changes(state_before, state_after);
473        let phase_changes = self.calculate_phase_changes(state_before, state_after);
474        let entanglement_change = self.calculate_entanglement_change(state_before, state_after)?;
475
476        Ok(GateEffect {
477            gate_type: format!("{:?}", gate.gate_type()),
478            target_qubits: gate.target_qubits().to_vec(),
479            amplitude_changes,
480            phase_changes,
481            entanglement_change,
482            fidelity: self.calculate_state_fidelity(state_before, state_after),
483        })
484    }
485
486    /// Calculate amplitude changes between states
487    fn calculate_amplitude_changes(&self, before: &[Complex64], after: &[Complex64]) -> Vec<f64> {
488        before
489            .iter()
490            .zip(after.iter())
491            .map(|(b, a)| (a.norm() - b.norm()).abs())
492            .collect()
493    }
494
495    /// Calculate phase changes between states
496    fn calculate_phase_changes(&self, before: &[Complex64], after: &[Complex64]) -> Vec<f64> {
497        before
498            .iter()
499            .zip(after.iter())
500            .map(|(b, a)| {
501                if b.norm() > 1e-10 && a.norm() > 1e-10 {
502                    (a.arg() - b.arg()).abs()
503                } else {
504                    0.0
505                }
506            })
507            .collect()
508    }
509
510    /// Calculate entanglement change
511    fn calculate_entanglement_change(
512        &self,
513        before: &[Complex64],
514        after: &[Complex64],
515    ) -> Result<f64, QuantRS2Error> {
516        let ent_before = self.calculate_total_entanglement(before)?;
517        let ent_after = self.calculate_total_entanglement(after)?;
518        Ok(ent_after - ent_before)
519    }
520
521    /// Calculate state fidelity
522    fn calculate_state_fidelity(&self, state1: &[Complex64], state2: &[Complex64]) -> f64 {
523        let overlap: Complex64 = state1
524            .iter()
525            .zip(state2.iter())
526            .map(|(s1, s2)| s1.conj() * s2)
527            .sum();
528        overlap.norm_sqr()
529    }
530
531    /// Record a state snapshot
532    fn record_state_snapshot(
533        &mut self,
534        step: usize,
535        state: &[Complex64],
536        gate_index: Option<usize>,
537        num_qubits: usize,
538    ) -> Result<(), QuantRS2Error> {
539        // Check memory limit
540        let estimated_size = state.len() * 16; // 16 bytes per Complex64
541        let total_size = self.state_history.len() * estimated_size;
542
543        if total_size > self.config.memory_limit_mb * 1024 * 1024 {
544            // Remove oldest snapshots
545            while self.state_history.len() > 100 {
546                self.state_history.pop_front();
547            }
548        }
549
550        let snapshot = StateSnapshot {
551            step,
552            gate_index,
553            state: if num_qubits <= self.config.max_detailed_qubits {
554                state.to_vec()
555            } else {
556                // Sample the state for large systems
557                self.sample_state(state)?
558            },
559            metadata: StateMetadata {
560                entropy: self.calculate_von_neumann_entropy(state)?,
561                purity: self.calculate_purity(state)?,
562                norm: state.iter().map(|c| c.norm_sqr()).sum::<f64>().sqrt(),
563            },
564        };
565
566        self.state_history.push_back(snapshot);
567        Ok(())
568    }
569
570    /// Sample state for large quantum systems
571    fn sample_state(&self, state: &[Complex64]) -> Result<Vec<Complex64>, QuantRS2Error> {
572        let sample_size = (state.len() as f64 * self.config.sampling_rate).ceil() as usize;
573        let step = state.len() / sample_size;
574
575        Ok(state.iter().step_by(step.max(1)).copied().collect())
576    }
577
578    /// Get previous state from history
579    fn get_previous_state(&self) -> Vec<Complex64> {
580        self.state_history
581            .back()
582            .map(|snapshot| snapshot.state.clone())
583            .unwrap_or_default()
584    }
585
586    /// Analyze entanglement in the quantum state
587    fn analyze_entanglement(
588        &self,
589        state: &[Complex64],
590        num_qubits: usize,
591    ) -> Result<EntanglementAnalysis, QuantRS2Error> {
592        let total_entanglement = self.calculate_total_entanglement(state)?;
593        let pairwise_entanglement = self.calculate_pairwise_entanglement(state, num_qubits)?;
594        let entanglement_spectrum = self.calculate_entanglement_spectrum(state, num_qubits)?;
595        let max_entangled_pair = self.find_max_entangled_pair(&pairwise_entanglement);
596
597        Ok(EntanglementAnalysis {
598            total_entanglement,
599            pairwise_entanglement,
600            entanglement_spectrum,
601            max_entangled_pair,
602        })
603    }
604
605    /// Calculate total entanglement (simplified von Neumann entropy)
606    fn calculate_total_entanglement(&self, state: &[Complex64]) -> Result<f64, QuantRS2Error> {
607        // Simplified calculation - in practice, this would use reduced density matrices
608        let probabilities: Vec<f64> = state.iter().map(|c| c.norm_sqr()).collect();
609        let entropy = -probabilities
610            .iter()
611            .filter(|&&p| p > 1e-15)
612            .map(|&p| p * p.log2())
613            .sum::<f64>();
614        Ok(entropy)
615    }
616
617    /// Calculate pairwise entanglement between qubits
618    fn calculate_pairwise_entanglement(
619        &self,
620        state: &[Complex64],
621        num_qubits: usize,
622    ) -> Result<HashMap<(usize, usize), f64>, QuantRS2Error> {
623        let mut pairwise = HashMap::new();
624
625        // Simplified pairwise entanglement calculation
626        for i in 0..num_qubits {
627            for j in (i + 1)..num_qubits {
628                let entanglement =
629                    self.calculate_bipartite_entanglement(state, i, j, num_qubits)?;
630                pairwise.insert((i, j), entanglement);
631            }
632        }
633
634        Ok(pairwise)
635    }
636
637    /// Calculate bipartite entanglement between two qubits
638    fn calculate_bipartite_entanglement(
639        &self,
640        state: &[Complex64],
641        qubit1: usize,
642        qubit2: usize,
643        num_qubits: usize,
644    ) -> Result<f64, QuantRS2Error> {
645        // Simplified calculation - would use partial trace in practice
646        let mut correlation = 0.0;
647
648        for i in 0..(1 << num_qubits) {
649            let bit1 = (i >> qubit1) & 1;
650            let bit2 = (i >> qubit2) & 1;
651
652            if bit1 == bit2 {
653                correlation += state[i].norm_sqr();
654            } else {
655                correlation -= state[i].norm_sqr();
656            }
657        }
658
659        Ok(correlation.abs())
660    }
661
662    /// Calculate entanglement spectrum
663    fn calculate_entanglement_spectrum(
664        &self,
665        state: &[Complex64],
666        _num_qubits: usize,
667    ) -> Result<Vec<f64>, QuantRS2Error> {
668        // Simplified entanglement spectrum
669        let mut spectrum: Vec<f64> = state.iter().map(|c| c.norm_sqr()).collect();
670        spectrum.sort_by(|a, b| b.partial_cmp(a).unwrap_or(std::cmp::Ordering::Equal));
671        Ok(spectrum)
672    }
673
674    /// Find the pair of qubits with maximum entanglement
675    fn find_max_entangled_pair(
676        &self,
677        pairwise: &HashMap<(usize, usize), f64>,
678    ) -> Option<(usize, usize)> {
679        pairwise
680            .iter()
681            .max_by(|(_, v1), (_, v2)| v1.partial_cmp(v2).unwrap_or(std::cmp::Ordering::Equal))
682            .map(|(pair, _)| *pair)
683    }
684
685    /// Analyze amplitude distribution
686    fn analyze_amplitudes(&self, state: &[Complex64]) -> Result<AmplitudeAnalysis, QuantRS2Error> {
687        let amplitudes: Vec<f64> = state.iter().map(|c| c.norm()).collect();
688        let phases: Vec<f64> = state.iter().map(|c| c.arg()).collect();
689
690        let max_amplitude_index = amplitudes
691            .iter()
692            .enumerate()
693            .max_by(|(_, a), (_, b)| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal))
694            .map_or(0, |(i, _)| i);
695
696        let mean_amplitude = amplitudes.iter().sum::<f64>() / amplitudes.len() as f64;
697        let amplitude_variance = amplitudes
698            .iter()
699            .map(|a| (a - mean_amplitude).powi(2))
700            .sum::<f64>()
701            / amplitudes.len() as f64;
702
703        let significant_states = self.find_significant_states(&amplitudes);
704
705        Ok(AmplitudeAnalysis {
706            amplitudes,
707            phases,
708            max_amplitude_index,
709            mean_amplitude,
710            amplitude_variance,
711            significant_states,
712        })
713    }
714
715    /// Find states with significant amplitudes
716    fn find_significant_states(&self, amplitudes: &[f64]) -> Vec<usize> {
717        let threshold = 0.1; // 10% threshold
718        amplitudes
719            .iter()
720            .enumerate()
721            .filter(|(_, &amp)| amp > threshold)
722            .map(|(i, _)| i)
723            .collect()
724    }
725
726    /// Get qubit amplitude (simplified)
727    fn get_qubit_amplitude(&self, state: &[Complex64], qubit: usize) -> Option<Complex64> {
728        // Simplified - would calculate reduced amplitude in practice
729        if qubit < 64 && (1 << qubit) < state.len() {
730            Some(state[1 << qubit])
731        } else {
732            None
733        }
734    }
735
736    /// Calculate von Neumann entropy
737    fn calculate_von_neumann_entropy(&self, state: &[Complex64]) -> Result<f64, QuantRS2Error> {
738        let probabilities: Vec<f64> = state.iter().map(|c| c.norm_sqr()).collect();
739        let entropy = -probabilities
740            .iter()
741            .filter(|&&p| p > 1e-15)
742            .map(|&p| p * p.log2())
743            .sum::<f64>();
744        Ok(entropy)
745    }
746
747    /// Calculate state purity
748    fn calculate_purity(&self, state: &[Complex64]) -> Result<f64, QuantRS2Error> {
749        let purity = state.iter().map(|c| c.norm_sqr().powi(2)).sum::<f64>();
750        Ok(purity)
751    }
752
753    /// Generate comprehensive analysis with SciRS2 enhanced metrics
754    fn generate_analysis(&self, _num_qubits: usize) -> Result<DebugAnalysis, QuantRS2Error> {
755        Ok(DebugAnalysis {
756            gate_statistics: self.gate_statistics.clone(),
757            execution_summary: ExecutionSummary {
758                total_steps: self.execution_trace.len(),
759                total_gates: self.gate_statistics.total_gates(),
760                circuit_depth: self.calculate_circuit_depth(),
761                execution_time: self.performance_metrics.total_execution_time.as_secs_f64(),
762            },
763            performance_metrics: self.calculate_enhanced_performance_metrics()?,
764            recommendations: self.generate_enhanced_recommendations()?,
765        })
766    }
767
768    /// Calculate circuit depth
769    fn calculate_circuit_depth(&self) -> usize {
770        // Simplified depth calculation
771        self.execution_trace.len()
772    }
773
774    /// Estimate execution time
775    fn estimate_execution_time(&self) -> f64 {
776        // Simplified time estimation (microseconds)
777        self.execution_trace.len() as f64 * 0.1
778    }
779
780    /// Calculate enhanced performance metrics with SciRS2 features
781    fn calculate_enhanced_performance_metrics(&self) -> Result<PerformanceMetrics, QuantRS2Error> {
782        Ok(PerformanceMetrics {
783            average_gate_fidelity: self.calculate_average_fidelity(),
784            entanglement_efficiency: self.calculate_entanglement_efficiency(),
785            state_overlap_preservation: self.calculate_state_overlap_preservation(),
786        })
787    }
788
789    /// Legacy performance metrics calculation (kept for compatibility)
790    fn calculate_performance_metrics(&self) -> Result<PerformanceMetrics, QuantRS2Error> {
791        self.calculate_enhanced_performance_metrics()
792    }
793
794    /// Calculate average gate fidelity
795    fn calculate_average_fidelity(&self) -> f64 {
796        if self.execution_trace.is_empty() {
797            return 1.0;
798        }
799
800        let total_fidelity: f64 = self
801            .execution_trace
802            .iter()
803            .map(|step| step.gate_effect.fidelity)
804            .sum();
805
806        total_fidelity / self.execution_trace.len() as f64
807    }
808
809    /// Calculate entanglement efficiency
810    const fn calculate_entanglement_efficiency(&self) -> f64 {
811        // Simplified calculation
812        0.85 // Placeholder
813    }
814
815    /// Calculate state overlap preservation
816    const fn calculate_state_overlap_preservation(&self) -> f64 {
817        // Simplified calculation
818        0.92 // Placeholder
819    }
820
821    /// Generate enhanced optimization recommendations using SciRS2 analysis
822    fn generate_enhanced_recommendations(&self) -> Result<Vec<String>, QuantRS2Error> {
823        let mut recommendations = Vec::new();
824
825        // Standard recommendations
826        if self.gate_statistics.two_qubit_gate_ratio() > 0.5 {
827            recommendations
828                .push("Consider reducing two-qubit gates to improve fidelity".to_string());
829        }
830
831        if self.calculate_circuit_depth() > 100 {
832            recommendations.push("Circuit depth is high - consider parallelization".to_string());
833        }
834
835        // SciRS2-enhanced recommendations based on performance metrics
836        if self.performance_metrics.simd_operations_count > 0 {
837            recommendations
838                .push("SIMD operations detected - good use of vectorization".to_string());
839        } else {
840            recommendations
841                .push("Consider enabling SIMD operations for better performance".to_string());
842        }
843
844        if self.performance_metrics.parallel_operations_count > 0 {
845            recommendations
846                .push("Parallel operations used - optimal for multi-core systems".to_string());
847        }
848
849        // Memory usage analysis
850        if let Some(max_memory) = self.performance_metrics.memory_usage.iter().max() {
851            if *max_memory > 1024 * 1024 * 100 {
852                // > 100MB
853                recommendations.push(
854                    "High memory usage detected - consider SciRS2 memory optimization".to_string(),
855                );
856            }
857        }
858
859        // Performance-based recommendations
860        let avg_gate_time = self.performance_metrics.total_execution_time.as_nanos() as f64
861            / (self.execution_trace.len() as f64 + 1.0);
862        if avg_gate_time > 1000.0 {
863            // > 1μs per gate
864            recommendations.push("Gate execution time is high - consider optimization".to_string());
865        }
866
867        recommendations.push("Apply error mitigation techniques".to_string());
868        recommendations.push("Use SciRS2 advanced quantum state management".to_string());
869
870        Ok(recommendations)
871    }
872
873    /// Legacy recommendations method (kept for compatibility)
874    fn generate_recommendations(&self) -> Result<Vec<String>, QuantRS2Error> {
875        self.generate_enhanced_recommendations()
876    }
877}
878
879/// Debug step information
880#[derive(Debug, Clone)]
881pub struct DebugStep {
882    pub step: usize,
883    pub gate: QuantumGate,
884    pub gate_effect: GateEffect,
885    pub state_before: Option<Vec<Complex64>>,
886    pub state_after: Option<Vec<Complex64>>,
887    pub entanglement_info: Option<EntanglementAnalysis>,
888    pub amplitude_analysis: Option<AmplitudeAnalysis>,
889}
890
891/// Gate effect information
892#[derive(Debug, Clone)]
893pub struct GateEffect {
894    pub gate_type: String,
895    pub target_qubits: Vec<usize>,
896    pub amplitude_changes: Vec<f64>,
897    pub phase_changes: Vec<f64>,
898    pub entanglement_change: f64,
899    pub fidelity: f64,
900}
901
902/// Breakpoint configuration
903#[derive(Debug, Clone)]
904pub struct Breakpoint {
905    pub step: usize,
906    pub condition: BreakpointCondition,
907    pub enabled: bool,
908}
909
910/// Breakpoint conditions
911#[derive(Debug, Clone)]
912pub enum BreakpointCondition {
913    Always,
914    StateCondition(StateCondition),
915    GateType(GateType),
916    QubitIndex(usize),
917}
918
919/// State-based breakpoint conditions
920#[derive(Debug, Clone)]
921pub enum StateCondition {
922    AmplitudeThreshold {
923        qubit: usize,
924        threshold: f64,
925    },
926    EntanglementThreshold {
927        threshold: f64,
928    },
929    PhaseDifference {
930        qubit1: usize,
931        qubit2: usize,
932        threshold: f64,
933    },
934}
935
936/// State snapshot for debugging
937#[derive(Debug, Clone)]
938pub struct StateSnapshot {
939    pub step: usize,
940    pub gate_index: Option<usize>,
941    pub state: Vec<Complex64>,
942    pub metadata: StateMetadata,
943}
944
945/// State metadata
946#[derive(Debug, Clone)]
947pub struct StateMetadata {
948    pub entropy: f64,
949    pub purity: f64,
950    pub norm: f64,
951}
952
953/// Entanglement analysis results
954#[derive(Debug, Clone)]
955pub struct EntanglementAnalysis {
956    pub total_entanglement: f64,
957    pub pairwise_entanglement: HashMap<(usize, usize), f64>,
958    pub entanglement_spectrum: Vec<f64>,
959    pub max_entangled_pair: Option<(usize, usize)>,
960}
961
962/// Amplitude analysis results
963#[derive(Debug, Clone)]
964pub struct AmplitudeAnalysis {
965    pub amplitudes: Vec<f64>,
966    pub phases: Vec<f64>,
967    pub max_amplitude_index: usize,
968    pub mean_amplitude: f64,
969    pub amplitude_variance: f64,
970    pub significant_states: Vec<usize>,
971}
972
973/// Gate statistics tracking
974#[derive(Debug, Clone)]
975pub struct GateStatistics {
976    gate_counts: HashMap<String, usize>,
977    total_count: usize,
978}
979
980impl GateStatistics {
981    pub fn new() -> Self {
982        Self {
983            gate_counts: HashMap::new(),
984            total_count: 0,
985        }
986    }
987
988    pub fn record_gate(&mut self, gate: &QuantumGate) {
989        let gate_type = format!("{:?}", gate.gate_type());
990        *self.gate_counts.entry(gate_type).or_insert(0) += 1;
991        self.total_count += 1;
992    }
993
994    pub const fn total_gates(&self) -> usize {
995        self.total_count
996    }
997
998    pub fn two_qubit_gate_ratio(&self) -> f64 {
999        let two_qubit_gates =
1000            *self.gate_counts.get("CNOT").unwrap_or(&0) + *self.gate_counts.get("CZ").unwrap_or(&0);
1001        if self.total_count > 0 {
1002            two_qubit_gates as f64 / self.total_count as f64
1003        } else {
1004            0.0
1005        }
1006    }
1007}
1008
1009/// Debug result
1010#[derive(Debug, Clone)]
1011pub struct DebugResult {
1012    pub status: DebugStatus,
1013    pub final_state: Vec<Complex64>,
1014    pub execution_trace: Vec<DebugStep>,
1015    pub analysis: DebugAnalysis,
1016}
1017
1018/// Debug status
1019#[derive(Debug, Clone)]
1020pub enum DebugStatus {
1021    Completed,
1022    BreakpointHit(usize),
1023    Error(String),
1024}
1025
1026/// Debug analysis results
1027#[derive(Debug, Clone)]
1028pub struct DebugAnalysis {
1029    pub gate_statistics: GateStatistics,
1030    pub execution_summary: ExecutionSummary,
1031    pub performance_metrics: PerformanceMetrics,
1032    pub recommendations: Vec<String>,
1033}
1034
1035/// Execution summary
1036#[derive(Debug, Clone)]
1037pub struct ExecutionSummary {
1038    pub total_steps: usize,
1039    pub total_gates: usize,
1040    pub circuit_depth: usize,
1041    pub execution_time: f64,
1042}
1043
1044/// Performance metrics
1045#[derive(Debug, Clone)]
1046pub struct PerformanceMetrics {
1047    pub average_gate_fidelity: f64,
1048    pub entanglement_efficiency: f64,
1049    pub state_overlap_preservation: f64,
1050}
1051
1052#[cfg(test)]
1053mod tests {
1054    use super::*;
1055    use super::{GateType, QuantumGate};
1056
1057    #[test]
1058    fn test_debugger_creation() {
1059        let debugger = QuantumDebugger::new();
1060        assert!(debugger.config.track_state_vectors);
1061    }
1062
1063    #[test]
1064    fn test_breakpoint_setting() {
1065        let mut debugger = QuantumDebugger::new();
1066        debugger.set_breakpoint(5, BreakpointCondition::Always);
1067        assert_eq!(debugger.breakpoints.len(), 1);
1068        assert_eq!(debugger.breakpoints[0].step, 5);
1069    }
1070
1071    #[test]
1072    fn test_gate_statistics() {
1073        let mut stats = GateStatistics::new();
1074        let gate = QuantumGate::new(GateType::H, vec![0], None);
1075        stats.record_gate(&gate);
1076        assert_eq!(stats.total_gates(), 1);
1077    }
1078
1079    #[test]
1080    fn test_simple_circuit_debugging() {
1081        let mut debugger = QuantumDebugger::new();
1082        let circuit = vec![QuantumGate::new(GateType::H, vec![0], None)];
1083
1084        let initial_state = vec![Complex64::new(1.0, 0.0), Complex64::new(0.0, 0.0)];
1085
1086        let result = debugger
1087            .debug_circuit(&circuit, &initial_state, 1)
1088            .expect("debug_circuit should succeed with valid input");
1089        assert!(matches!(result.status, DebugStatus::Completed));
1090        assert_eq!(result.execution_trace.len(), 1);
1091    }
1092
1093    #[test]
1094    fn test_amplitude_analysis() {
1095        let debugger = QuantumDebugger::new();
1096        let state = vec![
1097            Complex64::new(std::f64::consts::FRAC_1_SQRT_2, 0.0),
1098            Complex64::new(std::f64::consts::FRAC_1_SQRT_2, 0.0),
1099        ];
1100
1101        let analysis = debugger
1102            .analyze_amplitudes(&state)
1103            .expect("analyze_amplitudes should succeed with valid state");
1104        assert_eq!(analysis.amplitudes.len(), 2);
1105        assert!((analysis.mean_amplitude - std::f64::consts::FRAC_1_SQRT_2).abs() < 1e-4);
1106    }
1107}