1use crate::gate_translation::GateType;
7use crate::buffer_pool::BufferPool;
9use std::time::{Duration, Instant};
10
11#[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};
46use scirs2_core::Complex64;
48
49#[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#[derive(Debug, Clone)]
104pub struct DebugConfig {
105 pub track_state_vectors: bool,
107 pub analyze_entanglement: bool,
109 pub visualize_amplitudes: bool,
111 pub track_gate_effects: bool,
113 pub max_detailed_qubits: usize,
115 pub sampling_rate: f64,
117 pub enable_breakpoints: bool,
119 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
138pub 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 pub fn new() -> Self {
153 let config = DebugConfig::default();
154 Self::with_config(config)
155 }
156
157 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 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 pub fn remove_breakpoint(&mut self, step: usize) {
188 self.breakpoints.retain(|bp| bp.step != step);
189 }
190
191 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 self.performance_metrics.start_timing();
202
203 let mut current_state = initial_state.to_vec();
204 let mut step = 0;
205
206 if self.config.track_state_vectors {
208 self.record_state_snapshot(step, ¤t_state, None, num_qubits)?;
209 }
210
211 for (gate_index, gate) in circuit.iter().enumerate() {
212 step += 1;
213
214 if self.should_break_at_step(step, ¤t_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 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 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(¤t_state, num_qubits)?)
253 } else {
254 None
255 },
256 amplitude_analysis: if self.config.visualize_amplitudes {
257 Some(self.analyze_amplitudes(¤t_state)?)
258 } else {
259 None
260 },
261 });
262
263 if self.config.track_state_vectors {
265 self.record_state_snapshot(step, ¤t_state, Some(gate_index), num_qubits)?;
266 }
267
268 self.gate_statistics.record_gate(gate);
270 }
271
272 self.current_step = step;
273
274 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 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 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 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 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 self.apply_gate_to_state(gate, state, num_qubits)?;
375
376 let effect = self.calculate_gate_effect(&state_before, state, gate)?;
378
379 Ok(effect)
380 }
381
382 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 }
460 }
461
462 Ok(())
463 }
464
465 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 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 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 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 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 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 let estimated_size = state.len() * 16; let total_size = self.state_history.len() * estimated_size;
542
543 if total_size > self.config.memory_limit_mb * 1024 * 1024 {
544 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 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 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 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 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 fn calculate_total_entanglement(&self, state: &[Complex64]) -> Result<f64, QuantRS2Error> {
607 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 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 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 fn calculate_bipartite_entanglement(
639 &self,
640 state: &[Complex64],
641 qubit1: usize,
642 qubit2: usize,
643 num_qubits: usize,
644 ) -> Result<f64, QuantRS2Error> {
645 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 fn calculate_entanglement_spectrum(
664 &self,
665 state: &[Complex64],
666 _num_qubits: usize,
667 ) -> Result<Vec<f64>, QuantRS2Error> {
668 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 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 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(&litudes);
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 fn find_significant_states(&self, amplitudes: &[f64]) -> Vec<usize> {
717 let threshold = 0.1; amplitudes
719 .iter()
720 .enumerate()
721 .filter(|(_, &)| amp > threshold)
722 .map(|(i, _)| i)
723 .collect()
724 }
725
726 fn get_qubit_amplitude(&self, state: &[Complex64], qubit: usize) -> Option<Complex64> {
728 if qubit < 64 && (1 << qubit) < state.len() {
730 Some(state[1 << qubit])
731 } else {
732 None
733 }
734 }
735
736 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 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 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 fn calculate_circuit_depth(&self) -> usize {
770 self.execution_trace.len()
772 }
773
774 fn estimate_execution_time(&self) -> f64 {
776 self.execution_trace.len() as f64 * 0.1
778 }
779
780 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 fn calculate_performance_metrics(&self) -> Result<PerformanceMetrics, QuantRS2Error> {
791 self.calculate_enhanced_performance_metrics()
792 }
793
794 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 const fn calculate_entanglement_efficiency(&self) -> f64 {
811 0.85 }
814
815 const fn calculate_state_overlap_preservation(&self) -> f64 {
817 0.92 }
820
821 fn generate_enhanced_recommendations(&self) -> Result<Vec<String>, QuantRS2Error> {
823 let mut recommendations = Vec::new();
824
825 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 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 if let Some(max_memory) = self.performance_metrics.memory_usage.iter().max() {
851 if *max_memory > 1024 * 1024 * 100 {
852 recommendations.push(
854 "High memory usage detected - consider SciRS2 memory optimization".to_string(),
855 );
856 }
857 }
858
859 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 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 fn generate_recommendations(&self) -> Result<Vec<String>, QuantRS2Error> {
875 self.generate_enhanced_recommendations()
876 }
877}
878
879#[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#[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#[derive(Debug, Clone)]
904pub struct Breakpoint {
905 pub step: usize,
906 pub condition: BreakpointCondition,
907 pub enabled: bool,
908}
909
910#[derive(Debug, Clone)]
912pub enum BreakpointCondition {
913 Always,
914 StateCondition(StateCondition),
915 GateType(GateType),
916 QubitIndex(usize),
917}
918
919#[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#[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#[derive(Debug, Clone)]
947pub struct StateMetadata {
948 pub entropy: f64,
949 pub purity: f64,
950 pub norm: f64,
951}
952
953#[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#[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#[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#[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#[derive(Debug, Clone)]
1020pub enum DebugStatus {
1021 Completed,
1022 BreakpointHit(usize),
1023 Error(String),
1024}
1025
1026#[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#[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#[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}