1use quantrs2_core::error::{QuantRS2Error, QuantRS2Result};
7use scirs2_core::Complex64;
8use serde::{Deserialize, Serialize};
9use std::collections::HashMap;
10use std::sync::{Arc, Mutex};
11use std::time::{Duration, Instant};
12
13#[derive(Debug, Clone)]
15pub struct SimulationDiagnostics {
16 error_tracker: Arc<Mutex<ErrorTracker>>,
18 performance_monitor: Arc<Mutex<PerformanceMonitor>>,
20 memory_tracker: Arc<Mutex<MemoryTracker>>,
22 circuit_analyzer: Arc<Mutex<CircuitAnalyzer>>,
24}
25
26#[derive(Debug, Default)]
28struct ErrorTracker {
29 error_counts: HashMap<ErrorCategory, usize>,
31 recent_errors: Vec<(Instant, ErrorInfo)>,
33 error_patterns: HashMap<String, usize>,
35 critical_threshold: usize,
37}
38
39#[derive(Debug, Default)]
41struct PerformanceMonitor {
42 operation_times: HashMap<String, OperationStats>,
44 gate_performance: HashMap<String, GateStats>,
46 allocation_patterns: Vec<(Instant, usize, String)>,
48 throughput_metrics: ThroughputMetrics,
50}
51
52#[derive(Debug, Default)]
54struct MemoryTracker {
55 peak_memory: HashMap<String, usize>,
57 efficiency_metrics: MemoryEfficiencyMetrics,
59 buffer_pool_stats: BufferPoolStats,
61 leak_detection: LeakDetectionStats,
63 allocation_patterns: Vec<(Instant, usize, String)>,
65}
66
67#[derive(Debug, Default)]
69struct CircuitAnalyzer {
70 complexity_metrics: ComplexityMetrics,
72 gate_statistics: HashMap<String, usize>,
74 optimization_opportunities: Vec<OptimizationRecommendation>,
76 health_score: f64,
78}
79
80#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, Serialize, Deserialize)]
82pub enum ErrorCategory {
83 Memory,
85 Circuit,
87 QubitIndex,
89 Computation,
91 Hardware,
93 Configuration,
95 Concurrency,
97 Unknown,
99}
100
101#[derive(Debug, Clone, Serialize, Deserialize)]
103pub struct ErrorInfo {
104 pub category: ErrorCategory,
105 pub message: String,
106 pub context: HashMap<String, String>,
107 pub severity: ErrorSeverity,
108 pub suggested_fix: Option<String>,
109}
110
111#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
113pub enum ErrorSeverity {
114 Low,
115 Medium,
116 High,
117 Critical,
118}
119
120#[derive(Debug, Default, Clone)]
122struct OperationStats {
123 total_time: Duration,
124 call_count: usize,
125 min_time: Option<Duration>,
126 max_time: Option<Duration>,
127 recent_times: Vec<Duration>,
128}
129
130#[derive(Debug, Default, Clone)]
132struct GateStats {
133 total_applications: usize,
134 total_time: Duration,
135 average_time: Duration,
136 qubits_affected: Vec<usize>,
137 efficiency_score: f64,
138}
139
140#[derive(Debug, Default, Clone)]
142struct ThroughputMetrics {
143 gates_per_second: f64,
144 qubits_simulated_per_second: f64,
145 circuits_completed: usize,
146 average_circuit_time: Duration,
147}
148
149#[derive(Debug, Default, Clone)]
151struct MemoryEfficiencyMetrics {
152 buffer_reuse_rate: f64,
153 allocation_efficiency: f64,
154 peak_to_average_ratio: f64,
155 fragmentation_score: f64,
156}
157
158#[derive(Debug, Default, Clone)]
160struct BufferPoolStats {
161 total_allocations: usize,
162 total_reuses: usize,
163 cache_hit_rate: f64,
164 average_buffer_lifetime: Duration,
165}
166
167#[derive(Debug, Default, Clone)]
169struct LeakDetectionStats {
170 suspicious_allocations: usize,
171 memory_growth_rate: f64,
172 long_lived_allocations: usize,
173}
174
175#[derive(Debug, Default, Clone)]
177struct ComplexityMetrics {
178 total_gates: usize,
179 depth: usize,
180 width: usize,
181 entanglement_measure: f64,
182 parallelization_potential: f64,
183}
184
185#[derive(Debug, Clone, Serialize, Deserialize)]
187pub struct OptimizationRecommendation {
188 pub category: OptimizationCategory,
189 pub description: String,
190 pub expected_improvement: f64,
191 pub implementation_difficulty: Difficulty,
192 pub priority: Priority,
193}
194
195#[derive(Debug, Clone, Serialize, Deserialize)]
197pub enum OptimizationCategory {
198 GateFusion,
199 CircuitReordering,
200 MemoryOptimization,
201 ParallelizationOpportunity,
202 AlgorithmicImprovement,
203}
204
205#[derive(Debug, Clone, Serialize, Deserialize)]
207pub enum Difficulty {
208 Easy,
209 Medium,
210 Hard,
211}
212
213#[derive(Debug, Clone, Serialize, Deserialize)]
215pub enum Priority {
216 Low,
217 Medium,
218 High,
219 Critical,
220}
221
222#[derive(Debug, Serialize, Deserialize)]
224pub struct DiagnosticReport {
225 pub timestamp: String,
226 pub error_summary: ErrorSummary,
227 pub performance_summary: PerformanceSummary,
228 pub memory_summary: MemorySummary,
229 pub circuit_analysis: CircuitAnalysisSummary,
230 pub recommendations: Vec<OptimizationRecommendation>,
231 pub overall_health_score: f64,
232}
233
234#[derive(Debug, Serialize, Deserialize)]
235pub struct ErrorSummary {
236 pub total_errors: usize,
237 pub errors_by_category: HashMap<ErrorCategory, usize>,
238 pub critical_errors: usize,
239 pub error_rate: f64,
240}
241
242#[derive(Debug, Serialize, Deserialize)]
243pub struct PerformanceSummary {
244 pub average_gate_time: f64,
245 pub gates_per_second: f64,
246 pub memory_efficiency: f64,
247 pub parallelization_efficiency: f64,
248}
249
250#[derive(Debug, Serialize, Deserialize)]
251pub struct MemorySummary {
252 pub peak_memory_usage: usize,
253 pub buffer_pool_efficiency: f64,
254 pub memory_leak_risk: f64,
255 pub allocation_efficiency: f64,
256}
257
258#[derive(Debug, Serialize, Deserialize)]
259pub struct CircuitAnalysisSummary {
260 pub complexity_score: f64,
261 pub optimization_potential: f64,
262 pub gate_distribution: HashMap<String, usize>,
263 pub depth_analysis: DepthAnalysis,
264}
265
266#[derive(Debug, Serialize, Deserialize)]
267pub struct DepthAnalysis {
268 pub total_depth: usize,
269 pub critical_path_length: usize,
270 pub parallelization_opportunities: usize,
271}
272
273impl SimulationDiagnostics {
274 #[must_use]
276 pub fn new() -> Self {
277 Self {
278 error_tracker: Arc::new(Mutex::new(ErrorTracker::default())),
279 performance_monitor: Arc::new(Mutex::new(PerformanceMonitor::default())),
280 memory_tracker: Arc::new(Mutex::new(MemoryTracker::default())),
281 circuit_analyzer: Arc::new(Mutex::new(CircuitAnalyzer::default())),
282 }
283 }
284
285 pub fn record_error(&self, error: &QuantRS2Error, context: HashMap<String, String>) {
287 let error_info = self.categorize_error(error, context);
288
289 if let Ok(mut tracker) = self.error_tracker.lock() {
290 tracker.record_error(error_info);
291 }
292 }
293
294 pub fn record_operation_time(&self, operation: &str, duration: Duration) {
296 if let Ok(mut monitor) = self.performance_monitor.lock() {
297 monitor.record_operation(operation.to_string(), duration);
298 }
299 }
300
301 pub fn record_gate_performance(&self, gate_name: &str, qubits: &[usize], duration: Duration) {
303 if let Ok(mut monitor) = self.performance_monitor.lock() {
304 monitor.record_gate_performance(gate_name.to_string(), qubits.to_vec(), duration);
305 }
306 }
307
308 pub fn record_memory_allocation(&self, size: usize, operation: &str) {
310 if let Ok(mut tracker) = self.memory_tracker.lock() {
311 tracker.record_allocation(size, operation.to_string());
312 }
313 }
314
315 pub fn analyze_circuit<const N: usize>(&self, circuit: &quantrs2_circuit::builder::Circuit<N>) {
317 if let Ok(mut analyzer) = self.circuit_analyzer.lock() {
318 analyzer.analyze_circuit(circuit);
319 }
320 }
321
322 #[must_use]
324 pub fn generate_report(&self) -> DiagnosticReport {
325 let timestamp = chrono::Utc::now().to_rfc3339();
326
327 let error_summary = self
328 .error_tracker
329 .lock()
330 .map(|tracker| tracker.generate_summary())
331 .unwrap_or_default();
332
333 let performance_summary = self
334 .performance_monitor
335 .lock()
336 .map(|monitor| monitor.generate_summary())
337 .unwrap_or_default();
338
339 let memory_summary = self
340 .memory_tracker
341 .lock()
342 .map(|tracker| tracker.generate_summary())
343 .unwrap_or_default();
344
345 let circuit_analysis = self
346 .circuit_analyzer
347 .lock()
348 .map(|analyzer| analyzer.generate_summary())
349 .unwrap_or_default();
350
351 let recommendations = self.generate_recommendations();
352 let overall_health_score =
353 self.calculate_health_score(&error_summary, &performance_summary, &memory_summary);
354
355 DiagnosticReport {
356 timestamp,
357 error_summary,
358 performance_summary,
359 memory_summary,
360 circuit_analysis,
361 recommendations,
362 overall_health_score,
363 }
364 }
365
366 fn categorize_error(
368 &self,
369 error: &QuantRS2Error,
370 context: HashMap<String, String>,
371 ) -> ErrorInfo {
372 let (category, severity, suggested_fix) = match error {
373 QuantRS2Error::InvalidQubitId(_) => (
374 ErrorCategory::QubitIndex,
375 ErrorSeverity::High,
376 Some("Check qubit indices are within circuit bounds".to_string()),
377 ),
378 QuantRS2Error::CircuitValidationFailed(_) => (
379 ErrorCategory::Circuit,
380 ErrorSeverity::Medium,
381 Some("Validate circuit structure before simulation".to_string()),
382 ),
383 QuantRS2Error::LinalgError(_) => (
384 ErrorCategory::Computation,
385 ErrorSeverity::High,
386 Some("Check matrix dimensions and numerical stability".to_string()),
387 ),
388 QuantRS2Error::UnsupportedOperation(_) => (
389 ErrorCategory::Configuration,
390 ErrorSeverity::Medium,
391 Some("Use supported gate types for this simulator".to_string()),
392 ),
393 QuantRS2Error::InvalidInput(_) => (
394 ErrorCategory::Configuration,
395 ErrorSeverity::Medium,
396 Some("Validate input parameters before operation".to_string()),
397 ),
398 _ => (ErrorCategory::Unknown, ErrorSeverity::Low, None),
399 };
400
401 ErrorInfo {
402 category,
403 message: error.to_string(),
404 context,
405 severity,
406 suggested_fix,
407 }
408 }
409
410 fn generate_recommendations(&self) -> Vec<OptimizationRecommendation> {
412 let mut recommendations = Vec::new();
413
414 if let Ok(monitor) = self.performance_monitor.lock() {
416 if !monitor.gate_performance.is_empty() {
417 let avg_gate_time: Duration = monitor
418 .gate_performance
419 .values()
420 .map(|stats| stats.average_time)
421 .sum::<Duration>()
422 / monitor.gate_performance.len() as u32;
423
424 if avg_gate_time > Duration::from_millis(1) {
425 recommendations.push(OptimizationRecommendation {
426 category: OptimizationCategory::GateFusion,
427 description: "Consider gate fusion to reduce operation overhead"
428 .to_string(),
429 expected_improvement: 0.3,
430 implementation_difficulty: Difficulty::Medium,
431 priority: Priority::High,
432 });
433 }
434 }
435 }
436
437 if let Ok(tracker) = self.memory_tracker.lock() {
439 if tracker.efficiency_metrics.buffer_reuse_rate < 0.7 {
440 recommendations.push(OptimizationRecommendation {
441 category: OptimizationCategory::MemoryOptimization,
442 description: "Improve buffer pool utilization for better memory efficiency"
443 .to_string(),
444 expected_improvement: 0.25,
445 implementation_difficulty: Difficulty::Easy,
446 priority: Priority::Medium,
447 });
448 }
449 }
450
451 if let Ok(analyzer) = self.circuit_analyzer.lock() {
453 if analyzer.complexity_metrics.parallelization_potential > 0.5 {
454 recommendations.push(OptimizationRecommendation {
455 category: OptimizationCategory::ParallelizationOpportunity,
456 description:
457 "Circuit has high parallelization potential - consider parallel execution"
458 .to_string(),
459 expected_improvement: 0.4,
460 implementation_difficulty: Difficulty::Hard,
461 priority: Priority::High,
462 });
463 }
464 }
465
466 recommendations
467 }
468
469 fn calculate_health_score(
471 &self,
472 error_summary: &ErrorSummary,
473 performance_summary: &PerformanceSummary,
474 memory_summary: &MemorySummary,
475 ) -> f64 {
476 let error_score = if error_summary.total_errors == 0 {
477 1.0
478 } else {
479 error_summary.error_rate.min(0.5).mul_add(-2.0, 1.0)
480 };
481
482 let performance_score = (performance_summary.gates_per_second / 1000.0).min(1.0);
483 let memory_score = memory_summary.buffer_pool_efficiency;
484
485 memory_score.mul_add(0.3, error_score * 0.4 + performance_score * 0.3) * 100.0
486 }
487}
488
489impl ErrorTracker {
490 fn record_error(&mut self, error_info: ErrorInfo) {
491 *self.error_counts.entry(error_info.category).or_insert(0) += 1;
492 self.recent_errors
493 .push((Instant::now(), error_info.clone()));
494
495 let pattern = format!(
497 "{:?}:{}",
498 error_info.category,
499 error_info
500 .message
501 .split_whitespace()
502 .take(3)
503 .collect::<Vec<_>>()
504 .join(" ")
505 );
506 *self.error_patterns.entry(pattern).or_insert(0) += 1;
507
508 if self.recent_errors.len() > 100 {
510 self.recent_errors.remove(0);
511 }
512 }
513
514 fn generate_summary(&self) -> ErrorSummary {
515 let total_errors = self.recent_errors.len();
516 let critical_errors = self
517 .recent_errors
518 .iter()
519 .filter(|(_, error)| matches!(error.severity, ErrorSeverity::Critical))
520 .count();
521
522 let error_rate = if total_errors > 0 {
523 critical_errors as f64 / total_errors as f64
524 } else {
525 0.0
526 };
527
528 ErrorSummary {
529 total_errors,
530 errors_by_category: self.error_counts.clone(),
531 critical_errors,
532 error_rate,
533 }
534 }
535}
536
537impl PerformanceMonitor {
538 fn record_operation(&mut self, operation: String, duration: Duration) {
539 let stats = self.operation_times.entry(operation).or_default();
540 stats.total_time += duration;
541 stats.call_count += 1;
542
543 stats.min_time = Some(stats.min_time.map_or(duration, |min| min.min(duration)));
544 stats.max_time = Some(stats.max_time.map_or(duration, |max| max.max(duration)));
545
546 stats.recent_times.push(duration);
547 if stats.recent_times.len() > 50 {
548 stats.recent_times.remove(0);
549 }
550 }
551
552 fn record_gate_performance(
553 &mut self,
554 gate_name: String,
555 qubits: Vec<usize>,
556 duration: Duration,
557 ) {
558 let stats = self.gate_performance.entry(gate_name).or_default();
559 stats.total_applications += 1;
560 stats.total_time += duration;
561 stats.average_time = stats.total_time / stats.total_applications as u32;
562 stats.qubits_affected.extend(qubits);
563
564 stats.efficiency_score =
566 1000.0 / (duration.as_nanos() as f64 / stats.qubits_affected.len() as f64);
567 }
568
569 fn generate_summary(&self) -> PerformanceSummary {
570 let average_gate_time = if self.gate_performance.is_empty() {
571 0.0
572 } else {
573 self.gate_performance
574 .values()
575 .map(|stats| stats.average_time.as_nanos() as f64)
576 .sum::<f64>()
577 / self.gate_performance.len() as f64
578 };
579
580 let gates_per_second = if average_gate_time > 0.0 {
581 1_000_000_000.0 / average_gate_time
582 } else {
583 0.0
584 };
585
586 PerformanceSummary {
587 average_gate_time,
588 gates_per_second,
589 memory_efficiency: self.compute_memory_efficiency(),
590 parallelization_efficiency: self.compute_parallelization_efficiency(),
591 }
592 }
593
594 fn compute_memory_efficiency(&self) -> f64 {
599 if self.allocation_patterns.is_empty() {
600 return 0.0;
601 }
602 let mut seen_sizes: std::collections::HashSet<usize> = std::collections::HashSet::new();
603 let mut reusable = 0usize;
604 for (_, size, _) in &self.allocation_patterns {
605 if seen_sizes.contains(size) {
606 reusable += 1;
607 } else {
608 seen_sizes.insert(*size);
609 }
610 }
611 reusable as f64 / self.allocation_patterns.len() as f64
612 }
613
614 fn compute_parallelization_efficiency(&self) -> f64 {
622 if self.throughput_metrics.circuits_completed == 0 {
625 return 0.0;
626 }
627 let gates = self.throughput_metrics.gates_per_second;
630 let qubits = self.throughput_metrics.qubits_simulated_per_second;
631 if gates <= 0.0 || qubits <= 0.0 {
632 return 0.0;
633 }
634 (qubits / gates).clamp(0.0, 1.0)
635 }
636}
637
638impl MemoryTracker {
639 fn record_allocation(&mut self, size: usize, operation: String) {
640 self.allocation_patterns
641 .push((Instant::now(), size, operation.clone()));
642
643 let current_peak = self.peak_memory.entry(operation).or_insert(0);
645 *current_peak = (*current_peak).max(size);
646
647 if self.allocation_patterns.len() > 1000 {
649 self.allocation_patterns.remove(0);
650 }
651 }
652
653 fn generate_summary(&self) -> MemorySummary {
654 let peak_memory_usage = self.peak_memory.values().max().copied().unwrap_or(0);
655
656 MemorySummary {
657 peak_memory_usage,
658 buffer_pool_efficiency: self.compute_buffer_pool_efficiency(),
659 memory_leak_risk: self.compute_memory_leak_risk(),
660 allocation_efficiency: self.compute_allocation_efficiency(),
661 }
662 }
663
664 fn compute_buffer_pool_efficiency(&self) -> f64 {
672 let recorded =
673 self.buffer_pool_stats.total_allocations + self.buffer_pool_stats.total_reuses;
674 if recorded > 0 {
675 return self.buffer_pool_stats.total_reuses as f64 / recorded as f64;
676 }
677
678 if self.allocation_patterns.is_empty() {
679 return 0.0;
680 }
681
682 let mut seen_sizes: std::collections::HashSet<usize> = std::collections::HashSet::new();
683 let mut reusable = 0usize;
684 for (_, size, _) in &self.allocation_patterns {
685 if seen_sizes.contains(size) {
686 reusable += 1;
687 } else {
688 seen_sizes.insert(*size);
689 }
690 }
691 reusable as f64 / self.allocation_patterns.len() as f64
692 }
693
694 fn compute_allocation_efficiency(&self) -> f64 {
702 if self.allocation_patterns.is_empty() {
703 return 0.0;
704 }
705 let total_allocated: usize = self
706 .allocation_patterns
707 .iter()
708 .map(|(_, size, _)| *size)
709 .sum();
710 if total_allocated == 0 {
711 return 0.0;
712 }
713 let peak = self.peak_memory.values().max().copied().unwrap_or(0);
714 (peak as f64 / total_allocated as f64).clamp(0.0, 1.0)
715 }
716
717 fn compute_memory_leak_risk(&self) -> f64 {
726 if self.leak_detection.memory_growth_rate > 0.0 {
727 return self.leak_detection.memory_growth_rate.clamp(0.0, 1.0);
728 }
729
730 let count = self.allocation_patterns.len();
731 if count < 2 {
732 return 0.0;
733 }
734 let mid = count / 2;
735 let first_sum: usize = self.allocation_patterns[..mid]
736 .iter()
737 .map(|(_, size, _)| *size)
738 .sum();
739 let second_sum: usize = self.allocation_patterns[mid..]
740 .iter()
741 .map(|(_, size, _)| *size)
742 .sum();
743 let first_mean = first_sum as f64 / mid.max(1) as f64;
744 let second_mean = second_sum as f64 / (count - mid).max(1) as f64;
745 if first_mean <= 0.0 {
746 return 0.0;
747 }
748 let growth = (second_mean - first_mean) / first_mean;
749 growth.clamp(0.0, 1.0)
750 }
751}
752
753impl CircuitAnalyzer {
754 fn analyze_circuit<const N: usize>(&mut self, circuit: &quantrs2_circuit::builder::Circuit<N>) {
755 self.complexity_metrics.width = N;
756 self.complexity_metrics.total_gates = circuit.gates().len();
757
758 for gate in circuit.gates() {
760 *self
761 .gate_statistics
762 .entry(gate.name().to_string())
763 .or_insert(0) += 1;
764 }
765
766 self.complexity_metrics.depth = Self::compute_circuit_depth(circuit);
770
771 self.complexity_metrics.entanglement_measure = self.calculate_entanglement_measure();
773 self.complexity_metrics.parallelization_potential =
774 self.calculate_parallelization_potential(circuit);
775
776 self.health_score = self.calculate_circuit_health();
778 }
779
780 fn compute_circuit_depth<const N: usize>(
787 circuit: &quantrs2_circuit::builder::Circuit<N>,
788 ) -> usize {
789 let mut qubit_depths: HashMap<u32, usize> = HashMap::new();
790 let mut max_depth = 0usize;
791 for gate in circuit.gates() {
792 let qubits = gate.qubits();
793 let input_depth = qubits
794 .iter()
795 .map(|q| qubit_depths.get(&q.id()).copied().unwrap_or(0))
796 .max()
797 .unwrap_or(0);
798 let new_depth = input_depth + 1;
799 for q in &qubits {
800 qubit_depths.insert(q.id(), new_depth);
801 }
802 max_depth = max_depth.max(new_depth);
803 }
804 max_depth
805 }
806
807 fn calculate_entanglement_measure(&self) -> f64 {
808 let two_qubit_gates = self
810 .gate_statistics
811 .iter()
812 .filter(|(name, _)| matches!(name.as_str(), "CNOT" | "CZ" | "SWAP" | "CY" | "CH"))
813 .map(|(_, count)| *count)
814 .sum::<usize>();
815
816 two_qubit_gates as f64 / self.complexity_metrics.total_gates.max(1) as f64
817 }
818
819 fn calculate_parallelization_potential<const N: usize>(
828 &self,
829 circuit: &quantrs2_circuit::builder::Circuit<N>,
830 ) -> f64 {
831 let total_gates = self.complexity_metrics.total_gates;
832 if total_gates == 0 {
833 return 0.0;
834 }
835 let depth = if self.complexity_metrics.depth > 0 {
836 self.complexity_metrics.depth
837 } else {
838 Self::compute_circuit_depth(circuit)
839 };
840 (1.0 - depth as f64 / total_gates as f64).clamp(0.0, 1.0)
841 }
842
843 fn calculate_circuit_health(&self) -> f64 {
844 let depth_score = if self.complexity_metrics.depth > 0 {
846 1.0 / (1.0 + (self.complexity_metrics.depth as f64 / 100.0))
847 } else {
848 1.0
849 };
850
851 let complexity_score = 1.0 - self.complexity_metrics.entanglement_measure.min(1.0);
852 let parallelization_score = self.complexity_metrics.parallelization_potential;
853
854 (depth_score + complexity_score + parallelization_score) / 3.0 * 100.0
855 }
856
857 fn generate_summary(&self) -> CircuitAnalysisSummary {
858 CircuitAnalysisSummary {
859 complexity_score: self.complexity_metrics.entanglement_measure * 100.0,
860 optimization_potential: self.complexity_metrics.parallelization_potential * 100.0,
861 gate_distribution: self.gate_statistics.clone(),
862 depth_analysis: DepthAnalysis {
863 total_depth: self.complexity_metrics.depth,
864 critical_path_length: self.complexity_metrics.depth,
866 parallelization_opportunities: (self.complexity_metrics.parallelization_potential
867 * 10.0) as usize,
868 },
869 }
870 }
871}
872
873impl Default for ErrorSummary {
874 fn default() -> Self {
875 Self {
876 total_errors: 0,
877 errors_by_category: HashMap::new(),
878 critical_errors: 0,
879 error_rate: 0.0,
880 }
881 }
882}
883
884impl Default for PerformanceSummary {
885 fn default() -> Self {
886 Self {
887 average_gate_time: 0.0,
888 gates_per_second: 0.0,
889 memory_efficiency: 0.0,
890 parallelization_efficiency: 0.0,
891 }
892 }
893}
894
895impl Default for MemorySummary {
896 fn default() -> Self {
897 Self {
898 peak_memory_usage: 0,
899 buffer_pool_efficiency: 0.0,
900 memory_leak_risk: 0.0,
901 allocation_efficiency: 0.0,
902 }
903 }
904}
905
906impl Default for CircuitAnalysisSummary {
907 fn default() -> Self {
908 Self {
909 complexity_score: 0.0,
910 optimization_potential: 0.0,
911 gate_distribution: HashMap::new(),
912 depth_analysis: DepthAnalysis {
913 total_depth: 0,
914 critical_path_length: 0,
915 parallelization_opportunities: 0,
916 },
917 }
918 }
919}
920
921impl Default for SimulationDiagnostics {
922 fn default() -> Self {
923 Self::new()
924 }
925}
926
927#[cfg(test)]
928mod tests {
929 use super::*;
930
931 #[test]
932 fn test_diagnostics_creation() {
933 let diagnostics = SimulationDiagnostics::new();
934 let report = diagnostics.generate_report();
935
936 assert_eq!(report.error_summary.total_errors, 0);
937 assert!(report.overall_health_score >= 0.0);
938 }
939
940 #[test]
941 fn test_error_recording() {
942 let diagnostics = SimulationDiagnostics::new();
943 let error = QuantRS2Error::InvalidQubitId(5);
944 let mut context = HashMap::new();
945 context.insert("operation".to_string(), "gate_application".to_string());
946
947 diagnostics.record_error(&error, context);
948
949 let report = diagnostics.generate_report();
950 assert_eq!(report.error_summary.total_errors, 1);
951 assert!(report
952 .error_summary
953 .errors_by_category
954 .contains_key(&ErrorCategory::QubitIndex));
955 }
956
957 #[test]
958 fn test_performance_recording() {
959 let diagnostics = SimulationDiagnostics::new();
960
961 diagnostics.record_operation_time("gate_application", Duration::from_millis(10));
962 diagnostics.record_gate_performance("H", &[0], Duration::from_micros(500));
963
964 let report = diagnostics.generate_report();
965 assert!(report.performance_summary.average_gate_time > 0.0);
966 }
967}