1use crate::{
8 automatic_parallelization::{AutoParallelConfig, AutoParallelEngine},
9 circuit_optimization::{CircuitOptimizer, OptimizationConfig},
10 distributed_simulator::{DistributedQuantumSimulator, DistributedSimulatorConfig},
11 error::{Result, SimulatorError},
12 large_scale_simulator::{LargeScaleQuantumSimulator, LargeScaleSimulatorConfig},
13 simulator::SimulatorResult,
14 statevector::StateVectorSimulator,
15};
16use quantrs2_circuit::builder::{Circuit, Simulator};
17use quantrs2_core::{
18 error::{QuantRS2Error, QuantRS2Result},
19 gate::GateOp,
20 qubit::QubitId,
21 register::Register,
22};
23use std::fmt::Write;
24
25#[cfg(all(feature = "gpu", not(target_os = "macos")))]
26use crate::gpu::SciRS2GpuStateVectorSimulator;
27use scirs2_core::parallel_ops::current_num_threads; use scirs2_core::Complex64;
29use serde::{Deserialize, Serialize};
30use std::collections::HashMap;
31use std::sync::Arc;
32use std::time::{Duration, Instant};
33
34#[derive(Debug, Clone, Serialize, Deserialize)]
36pub struct AutoOptimizerConfig {
37 pub enable_profiling: bool,
39 pub memory_budget: usize,
41 pub cpu_utilization_threshold: f64,
43 pub gpu_check_timeout: Duration,
45 pub enable_distributed: bool,
47 pub scirs2_optimization_level: OptimizationLevel,
49 pub fallback_strategy: FallbackStrategy,
51 pub analysis_depth: AnalysisDepth,
53 pub performance_cache_size: usize,
55 pub backend_preferences: Vec<BackendType>,
57}
58
59impl Default for AutoOptimizerConfig {
60 fn default() -> Self {
61 Self {
62 enable_profiling: true,
63 memory_budget: 8 * 1024 * 1024 * 1024, cpu_utilization_threshold: 0.8,
65 gpu_check_timeout: Duration::from_millis(1000),
66 enable_distributed: true,
67 scirs2_optimization_level: OptimizationLevel::Aggressive,
68 fallback_strategy: FallbackStrategy::Conservative,
69 analysis_depth: AnalysisDepth::Deep,
70 performance_cache_size: 1000,
71 backend_preferences: vec![
72 BackendType::SciRS2Gpu,
73 BackendType::LargeScale,
74 BackendType::Distributed,
75 BackendType::StateVector,
76 ],
77 }
78 }
79}
80
81#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
83pub enum BackendType {
84 StateVector,
86 SciRS2Gpu,
88 LargeScale,
90 Distributed,
92 Auto,
94}
95
96#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
98pub enum OptimizationLevel {
99 None,
101 Basic,
103 Advanced,
105 Aggressive,
107}
108
109#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
111pub enum FallbackStrategy {
112 Conservative,
114 Aggressive,
116 Fail,
118}
119
120#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
122pub enum AnalysisDepth {
123 Quick,
125 Standard,
127 Deep,
129}
130
131#[derive(Debug, Clone)]
133pub struct CircuitCharacteristics {
134 pub num_qubits: usize,
136 pub num_gates: usize,
138 pub circuit_depth: usize,
140 pub gate_distribution: HashMap<String, usize>,
142 pub parallelism_potential: f64,
144 pub memory_requirement: usize,
146 pub complexity_score: f64,
148 pub two_qubit_density: f64,
150 pub connectivity_properties: ConnectivityProperties,
152 pub entanglement_depth: usize,
154 pub noise_susceptibility: f64,
156}
157
158#[derive(Debug, Clone)]
160pub struct ConnectivityProperties {
161 pub max_degree: usize,
163 pub avg_degree: f64,
165 pub connected_components: usize,
167 pub diameter: usize,
169 pub clustering_coefficient: f64,
171}
172
173#[derive(Debug, Clone)]
175pub struct BackendRecommendation {
176 pub backend_type: BackendType,
178 pub confidence: f64,
180 pub expected_improvement: f64,
182 pub estimated_execution_time: Duration,
184 pub estimated_memory_usage: usize,
186 pub reasoning: String,
188 pub alternatives: Vec<(BackendType, f64)>,
190 pub prediction_model: String,
192}
193
194#[derive(Debug, Clone)]
196pub struct PerformanceMetrics {
197 pub execution_time: Duration,
199 pub memory_usage: usize,
201 pub cpu_utilization: f64,
203 pub gpu_utilization: Option<f64>,
205 pub throughput: f64,
207 pub error_rate: f64,
209}
210
211#[derive(Debug, Clone)]
213pub struct PerformanceHistory {
214 pub circuit_hash: u64,
216 pub backend_type: BackendType,
218 pub metrics: PerformanceMetrics,
220 pub timestamp: Instant,
222}
223
224pub struct AutoOptimizer {
226 config: AutoOptimizerConfig,
228 circuit_optimizer: CircuitOptimizer,
230 parallel_engine: AutoParallelEngine,
232 performance_cache: Vec<PerformanceHistory>,
234 backend_availability: HashMap<BackendType, bool>,
236 scirs2_analyzer: SciRS2CircuitAnalyzer,
238}
239
240struct SciRS2CircuitAnalyzer {
242 enable_advanced_features: bool,
244}
245
246impl AutoOptimizer {
247 #[must_use]
249 pub fn new() -> Self {
250 Self::with_config(AutoOptimizerConfig::default())
251 }
252
253 #[must_use]
255 pub fn with_config(config: AutoOptimizerConfig) -> Self {
256 let optimization_config = OptimizationConfig {
257 enable_gate_fusion: true,
258 enable_redundant_elimination: true,
259 enable_commutation_reordering: true,
260 enable_single_qubit_optimization: true,
261 enable_two_qubit_optimization: true,
262 max_passes: 3,
263 enable_depth_reduction: true,
264 };
265
266 let parallel_config = AutoParallelConfig {
267 max_threads: current_num_threads(), min_gates_for_parallel: 20,
269 strategy: crate::automatic_parallelization::ParallelizationStrategy::Hybrid,
270 ..Default::default()
271 };
272
273 Self {
274 config,
275 circuit_optimizer: CircuitOptimizer::with_config(optimization_config),
276 parallel_engine: AutoParallelEngine::new(parallel_config),
277 performance_cache: Vec::new(),
278 backend_availability: HashMap::new(),
279 scirs2_analyzer: SciRS2CircuitAnalyzer {
280 enable_advanced_features: true,
281 },
282 }
283 }
284
285 pub fn analyze_circuit<const N: usize>(
287 &self,
288 circuit: &Circuit<N>,
289 ) -> QuantRS2Result<CircuitCharacteristics> {
290 let start_time = Instant::now();
291
292 let num_qubits = circuit.num_qubits();
294 let num_gates = circuit.num_gates();
295 let circuit_depth = self.calculate_circuit_depth(circuit);
296
297 let gate_distribution = self.analyze_gate_distribution(circuit);
299
300 let parallelism_potential = self.analyze_parallelism_potential(circuit)?;
302
303 let memory_requirement = self.estimate_memory_requirement(num_qubits, num_gates);
305
306 let complexity_score = self.calculate_complexity_score(circuit)?;
308
309 let two_qubit_density = self.calculate_two_qubit_density(circuit);
311
312 let connectivity_properties = self.analyze_connectivity(circuit)?;
314
315 let entanglement_depth = self.estimate_entanglement_depth(circuit)?;
317
318 let noise_susceptibility = self.analyze_noise_susceptibility(circuit);
320
321 let analysis_time = start_time.elapsed();
322 if self.config.enable_profiling {
323 println!("Circuit analysis completed in {analysis_time:?}");
324 }
325
326 Ok(CircuitCharacteristics {
327 num_qubits,
328 num_gates,
329 circuit_depth,
330 gate_distribution,
331 parallelism_potential,
332 memory_requirement,
333 complexity_score,
334 two_qubit_density,
335 connectivity_properties,
336 entanglement_depth,
337 noise_susceptibility,
338 })
339 }
340
341 pub fn recommend_backend<const N: usize>(
343 &mut self,
344 circuit: &Circuit<N>,
345 ) -> QuantRS2Result<BackendRecommendation> {
346 let characteristics = self.analyze_circuit(circuit)?;
348
349 self.update_backend_availability()?;
351
352 if let Some(cached_result) = self.check_performance_cache(&characteristics) {
354 return Ok(self.build_recommendation_from_cache(cached_result));
355 }
356
357 let recommendation = self.generate_backend_recommendation(&characteristics)?;
359
360 Ok(recommendation)
361 }
362
363 pub fn execute_optimized<const N: usize>(
365 &mut self,
366 circuit: &Circuit<N>,
367 ) -> Result<SimulatorResult<N>> {
368 let recommendation = self
370 .recommend_backend(circuit)
371 .map_err(|e| SimulatorError::ComputationError(e.to_string()))?;
372
373 if self.config.enable_profiling {
374 println!(
375 "Using {} backend (confidence: {:.2})",
376 self.backend_type_name(recommendation.backend_type),
377 recommendation.confidence
378 );
379 println!("Reasoning: {}", recommendation.reasoning);
380 }
381
382 let start_time = Instant::now();
384 let register = self.execute_with_backend(circuit, recommendation.backend_type)?;
385 let execution_time = start_time.elapsed();
386
387 let result = self.register_to_simulator_result(register);
389
390 if self.config.enable_profiling {
392 self.record_performance_metrics(circuit, recommendation.backend_type, execution_time);
393 println!("Execution completed in {execution_time:?}");
394 }
395
396 Ok(result)
397 }
398
399 fn calculate_circuit_depth<const N: usize>(&self, circuit: &Circuit<N>) -> usize {
401 let mut qubit_depths = HashMap::new();
402 let mut max_depth = 0;
403
404 for gate in circuit.gates() {
405 let qubits = gate.qubits();
406
407 let input_depth = qubits
409 .iter()
410 .map(|&q| qubit_depths.get(&q).copied().unwrap_or(0))
411 .max()
412 .unwrap_or(0);
413
414 let new_depth = input_depth + 1;
415
416 for &qubit in &qubits {
418 qubit_depths.insert(qubit, new_depth);
419 }
420
421 max_depth = max_depth.max(new_depth);
422 }
423
424 max_depth
425 }
426
427 fn analyze_gate_distribution<const N: usize>(
429 &self,
430 circuit: &Circuit<N>,
431 ) -> HashMap<String, usize> {
432 let mut distribution = HashMap::new();
433
434 for gate in circuit.gates() {
435 let gate_name = gate.name().to_string();
436 *distribution.entry(gate_name).or_insert(0) += 1;
437 }
438
439 distribution
440 }
441
442 fn analyze_parallelism_potential<const N: usize>(
444 &self,
445 circuit: &Circuit<N>,
446 ) -> QuantRS2Result<f64> {
447 let analysis = self.parallel_engine.analyze_circuit(circuit)?;
449 Ok(analysis.efficiency)
450 }
451
452 const fn estimate_memory_requirement(&self, num_qubits: usize, num_gates: usize) -> usize {
454 let state_vector_size = (1 << num_qubits) * std::mem::size_of::<Complex64>();
456
457 let overhead = num_gates * 64; state_vector_size + overhead
461 }
462
463 fn calculate_complexity_score<const N: usize>(
465 &self,
466 circuit: &Circuit<N>,
467 ) -> QuantRS2Result<f64> {
468 let num_qubits = circuit.num_qubits() as f64;
469 let num_gates = circuit.num_gates() as f64;
470 let depth = self.calculate_circuit_depth(circuit) as f64;
471
472 let gate_complexity = num_gates * (num_qubits.log2() + 1.0);
474 let depth_complexity = depth * num_qubits;
475 let entanglement_complexity = self.estimate_entanglement_complexity(circuit)?;
476
477 Ok((gate_complexity + depth_complexity + entanglement_complexity) / 1000.0)
478 }
479
480 fn estimate_entanglement_complexity<const N: usize>(
482 &self,
483 circuit: &Circuit<N>,
484 ) -> QuantRS2Result<f64> {
485 let mut entanglement_score = 0.0;
486
487 for gate in circuit.gates() {
488 let qubits = gate.qubits();
489 if qubits.len() >= 2 {
490 entanglement_score += qubits.len() as f64 * qubits.len() as f64;
492 }
493 }
494
495 Ok(entanglement_score)
496 }
497
498 fn calculate_two_qubit_density<const N: usize>(&self, circuit: &Circuit<N>) -> f64 {
500 let total_gates = circuit.num_gates();
501 if total_gates == 0 {
502 return 0.0;
503 }
504
505 let two_qubit_gates = circuit
506 .gates()
507 .iter()
508 .filter(|gate| gate.qubits().len() >= 2)
509 .count();
510
511 two_qubit_gates as f64 / total_gates as f64
512 }
513
514 fn analyze_connectivity<const N: usize>(
516 &self,
517 circuit: &Circuit<N>,
518 ) -> QuantRS2Result<ConnectivityProperties> {
519 let mut qubit_connections: HashMap<QubitId, Vec<QubitId>> = HashMap::new();
520
521 for gate in circuit.gates() {
523 let qubits = gate.qubits();
524 if qubits.len() >= 2 {
525 for i in 0..qubits.len() {
526 for j in (i + 1)..qubits.len() {
527 qubit_connections
528 .entry(qubits[i])
529 .or_default()
530 .push(qubits[j]);
531 qubit_connections
532 .entry(qubits[j])
533 .or_default()
534 .push(qubits[i]);
535 }
536 }
537 }
538 }
539
540 let max_degree = qubit_connections
542 .values()
543 .map(std::vec::Vec::len)
544 .max()
545 .unwrap_or(0);
546
547 let avg_degree = if qubit_connections.is_empty() {
548 0.0
549 } else {
550 qubit_connections
551 .values()
552 .map(std::vec::Vec::len)
553 .sum::<usize>() as f64
554 / qubit_connections.len() as f64
555 };
556
557 let connected_components = 1; let diameter = circuit.num_qubits().min(6); let clustering_coefficient = 0.5; Ok(ConnectivityProperties {
567 max_degree,
568 avg_degree,
569 connected_components,
570 diameter,
571 clustering_coefficient,
572 })
573 }
574
575 fn estimate_entanglement_depth<const N: usize>(
577 &self,
578 circuit: &Circuit<N>,
579 ) -> QuantRS2Result<usize> {
580 let two_qubit_gates = circuit
582 .gates()
583 .iter()
584 .filter(|gate| gate.qubits().len() >= 2)
585 .count();
586
587 let depth_estimate = (two_qubit_gates as f64).sqrt().ceil() as usize;
589 Ok(depth_estimate.min(circuit.num_qubits()))
590 }
591
592 fn analyze_noise_susceptibility<const N: usize>(&self, circuit: &Circuit<N>) -> f64 {
594 let depth = self.calculate_circuit_depth(circuit) as f64;
595 let two_qubit_density = self.calculate_two_qubit_density(circuit);
596
597 (depth / 100.0 + two_qubit_density).min(1.0)
599 }
600
601 fn update_backend_availability(&mut self) -> QuantRS2Result<()> {
603 #[cfg(all(feature = "gpu", not(target_os = "macos")))]
605 let gpu_available = SciRS2GpuStateVectorSimulator::is_available();
606 #[cfg(any(not(feature = "gpu"), target_os = "macos"))]
607 let gpu_available = false;
608
609 self.backend_availability
610 .insert(BackendType::SciRS2Gpu, gpu_available);
611
612 self.backend_availability
614 .insert(BackendType::StateVector, true);
615 self.backend_availability
616 .insert(BackendType::LargeScale, true);
617
618 self.backend_availability
620 .insert(BackendType::Distributed, false);
621
622 Ok(())
623 }
624
625 fn check_performance_cache(
627 &self,
628 characteristics: &CircuitCharacteristics,
629 ) -> Option<&PerformanceHistory> {
630 self.performance_cache
633 .iter()
634 .find(|&entry| self.are_characteristics_similar(characteristics, entry))
635 .map(|v| v as _)
636 }
637
638 const fn are_characteristics_similar(
640 &self,
641 characteristics: &CircuitCharacteristics,
642 entry: &PerformanceHistory,
643 ) -> bool {
644 false }
647
648 fn build_recommendation_from_cache(
650 &self,
651 cache_entry: &PerformanceHistory,
652 ) -> BackendRecommendation {
653 BackendRecommendation {
654 backend_type: cache_entry.backend_type,
655 confidence: 0.9, expected_improvement: 0.0,
657 estimated_execution_time: cache_entry.metrics.execution_time,
658 estimated_memory_usage: cache_entry.metrics.memory_usage,
659 reasoning: "Based on cached performance data for similar circuits".to_string(),
660 alternatives: Vec::new(),
661 prediction_model: "Cache-based".to_string(),
662 }
663 }
664
665 fn generate_backend_recommendation(
667 &self,
668 characteristics: &CircuitCharacteristics,
669 ) -> QuantRS2Result<BackendRecommendation> {
670 let mut scores: HashMap<BackendType, f64> = HashMap::new();
671 let mut reasoning = String::new();
672
673 for &backend_type in &self.config.backend_preferences {
675 if !self
676 .backend_availability
677 .get(&backend_type)
678 .unwrap_or(&false)
679 {
680 continue;
681 }
682
683 let score = self.score_backend_for_characteristics(backend_type, characteristics);
684 scores.insert(backend_type, score);
685 }
686
687 let (best_backend, best_score) = scores
689 .into_iter()
690 .max_by(|(_, a), (_, b)| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal))
691 .unwrap_or((BackendType::StateVector, 0.5));
692
693 reasoning = self.generate_recommendation_reasoning(best_backend, characteristics);
695
696 let estimated_execution_time = self.estimate_execution_time(best_backend, characteristics);
698 let estimated_memory_usage = characteristics.memory_requirement;
699
700 Ok(BackendRecommendation {
701 backend_type: best_backend,
702 confidence: best_score,
703 expected_improvement: (best_score - 0.5).max(0.0) * 2.0, estimated_execution_time,
705 estimated_memory_usage,
706 reasoning,
707 alternatives: Vec::new(),
708 prediction_model: "SciRS2-guided heuristic".to_string(),
709 })
710 }
711
712 fn score_backend_for_characteristics(
714 &self,
715 backend_type: BackendType,
716 characteristics: &CircuitCharacteristics,
717 ) -> f64 {
718 let mut score: f64 = 0.5; match backend_type {
721 BackendType::StateVector => {
722 if characteristics.num_qubits <= 20 {
724 score += 0.3;
725 }
726 if characteristics.num_gates <= 1000 {
727 score += 0.2;
728 }
729 }
730 BackendType::SciRS2Gpu => {
731 if characteristics.num_qubits >= 10 && characteristics.num_qubits <= 30 {
733 score += 0.4;
734 }
735 if characteristics.parallelism_potential > 0.5 {
736 score += 0.3;
737 }
738 if characteristics.two_qubit_density > 0.3 {
739 score += 0.2;
740 }
741 }
742 BackendType::LargeScale => {
743 if characteristics.num_qubits >= 20 {
745 score += 0.4;
746 }
747 if characteristics.complexity_score > 0.5 {
748 score += 0.3;
749 }
750 }
751 BackendType::Distributed => {
752 if characteristics.num_qubits >= 30 {
754 score += 0.5;
755 }
756 if characteristics.memory_requirement > self.config.memory_budget / 2 {
757 score += 0.3;
758 }
759 }
760 BackendType::Auto => {
761 score = 0.1;
763 }
764 }
765
766 score.min(1.0)
767 }
768
769 fn generate_recommendation_reasoning(
771 &self,
772 backend_type: BackendType,
773 characteristics: &CircuitCharacteristics,
774 ) -> String {
775 match backend_type {
776 BackendType::StateVector => {
777 format!("CPU state vector simulator recommended for {} qubits, {} gates. Suitable for small circuits with straightforward execution.",
778 characteristics.num_qubits, characteristics.num_gates)
779 }
780 BackendType::SciRS2Gpu => {
781 format!("SciRS2 GPU simulator recommended for {} qubits, {} gates. High parallelism potential ({:.2}) and two-qubit gate density ({:.2}) make GPU acceleration beneficial.",
782 characteristics.num_qubits, characteristics.num_gates, characteristics.parallelism_potential, characteristics.two_qubit_density)
783 }
784 BackendType::LargeScale => {
785 format!("Large-scale simulator recommended for {} qubits, {} gates. Circuit complexity ({:.2}) and depth ({}) require optimized memory management.",
786 characteristics.num_qubits, characteristics.num_gates, characteristics.complexity_score, characteristics.circuit_depth)
787 }
788 BackendType::Distributed => {
789 format!("Distributed simulator recommended for {} qubits, {} gates. Memory requirement ({:.1} MB) exceeds single-node capacity.",
790 characteristics.num_qubits, characteristics.num_gates, characteristics.memory_requirement as f64 / (1024.0 * 1024.0))
791 }
792 BackendType::Auto => "Automatic backend selection".to_string(),
793 }
794 }
795
796 fn estimate_execution_time(
798 &self,
799 backend_type: BackendType,
800 characteristics: &CircuitCharacteristics,
801 ) -> Duration {
802 let base_time_ms = match backend_type {
803 BackendType::StateVector => characteristics.num_gates as u64 * 10,
804 BackendType::SciRS2Gpu => characteristics.num_gates as u64 * 2,
805 BackendType::LargeScale => characteristics.num_gates as u64 * 5,
806 BackendType::Distributed => characteristics.num_gates as u64 * 15,
807 BackendType::Auto => characteristics.num_gates as u64 * 10,
808 };
809
810 let complexity_factor = characteristics.complexity_score.mul_add(2.0, 1.0) as u64;
812 Duration::from_millis(base_time_ms * complexity_factor)
813 }
814
815 fn execute_with_backend<const N: usize>(
817 &self,
818 circuit: &Circuit<N>,
819 backend_type: BackendType,
820 ) -> Result<Register<N>> {
821 match backend_type {
822 BackendType::StateVector => {
823 let simulator = StateVectorSimulator::new();
824 simulator
825 .run(circuit)
826 .map_err(|e| SimulatorError::ComputationError(e.to_string()))
827 .and_then(|result| {
828 Register::with_amplitudes(result.amplitudes().to_vec())
829 .map_err(|e| SimulatorError::ComputationError(e.to_string()))
830 })
831 }
832 BackendType::SciRS2Gpu => {
833 #[cfg(all(feature = "gpu", not(target_os = "macos")))]
834 {
835 let mut simulator = SciRS2GpuStateVectorSimulator::new()
836 .map_err(|e| SimulatorError::ComputationError(e.to_string()))?;
837 use crate::simulator::Simulator;
838 simulator
839 .run(circuit)
840 .map_err(|e| SimulatorError::ComputationError(e.to_string()))
841 .and_then(|result| {
842 Register::with_amplitudes(result.amplitudes().to_vec())
843 .map_err(|e| SimulatorError::ComputationError(e.to_string()))
844 })
845 }
846 #[cfg(any(not(feature = "gpu"), target_os = "macos"))]
847 {
848 let simulator = StateVectorSimulator::new();
850 simulator
851 .run(circuit)
852 .map_err(|e| SimulatorError::ComputationError(e.to_string()))
853 .and_then(|result| {
854 Register::with_amplitudes(result.amplitudes().to_vec())
855 .map_err(|e| SimulatorError::ComputationError(e.to_string()))
856 })
857 }
858 }
859 BackendType::LargeScale => {
860 let config = LargeScaleSimulatorConfig::default();
862 let simulator = LargeScaleQuantumSimulator::new(config)
863 .map_err(|e| SimulatorError::ComputationError(e.to_string()))?;
864 simulator
865 .run(circuit)
866 .map_err(|e| SimulatorError::ComputationError(e.to_string()))
867 }
868 BackendType::Distributed => {
869 let config = LargeScaleSimulatorConfig::default();
871 let simulator = LargeScaleQuantumSimulator::new(config)
872 .map_err(|e| SimulatorError::ComputationError(e.to_string()))?;
873 simulator
874 .run(circuit)
875 .map_err(|e| SimulatorError::ComputationError(e.to_string()))
876 }
877 BackendType::Auto => {
878 let simulator = StateVectorSimulator::new();
880 simulator
881 .run(circuit)
882 .map_err(|e| SimulatorError::ComputationError(e.to_string()))
883 }
884 }
885 }
886
887 fn register_to_simulator_result<const N: usize>(
889 &self,
890 register: Register<N>,
891 ) -> SimulatorResult<N> {
892 let amplitudes = register.amplitudes().to_vec();
894
895 SimulatorResult {
896 amplitudes,
897 num_qubits: N,
898 }
899 }
900
901 fn record_performance_metrics<const N: usize>(
903 &mut self,
904 circuit: &Circuit<N>,
905 backend_type: BackendType,
906 execution_time: Duration,
907 ) {
908 let metrics = PerformanceMetrics {
909 execution_time,
910 memory_usage: 0, cpu_utilization: 0.0, gpu_utilization: None,
913 throughput: circuit.num_gates() as f64 / execution_time.as_secs_f64(),
914 error_rate: 0.0,
915 };
916
917 let history_entry = PerformanceHistory {
918 circuit_hash: self.compute_circuit_hash(circuit),
919 backend_type,
920 metrics,
921 timestamp: Instant::now(),
922 };
923
924 self.performance_cache.push(history_entry);
925
926 if self.performance_cache.len() > self.config.performance_cache_size {
928 self.performance_cache.remove(0);
929 }
930 }
931
932 fn compute_circuit_hash<const N: usize>(&self, circuit: &Circuit<N>) -> u64 {
934 use std::collections::hash_map::DefaultHasher;
935 use std::hash::{Hash, Hasher};
936
937 let mut hasher = DefaultHasher::new();
938 circuit.num_gates().hash(&mut hasher);
939 circuit.num_qubits().hash(&mut hasher);
940
941 for gate in circuit.gates() {
942 gate.name().hash(&mut hasher);
943 gate.qubits().len().hash(&mut hasher);
944 }
945
946 hasher.finish()
947 }
948
949 const fn backend_type_name(&self, backend_type: BackendType) -> &'static str {
951 match backend_type {
952 BackendType::StateVector => "CPU StateVector",
953 BackendType::SciRS2Gpu => "SciRS2 GPU",
954 BackendType::LargeScale => "Large-Scale",
955 BackendType::Distributed => "Distributed",
956 BackendType::Auto => "Auto",
957 }
958 }
959
960 #[must_use]
962 pub fn get_performance_summary(&self) -> String {
963 let total_circuits = self.performance_cache.len();
964 if total_circuits == 0 {
965 return "No performance data available".to_string();
966 }
967
968 let avg_execution_time = self
969 .performance_cache
970 .iter()
971 .map(|entry| entry.metrics.execution_time.as_millis())
972 .sum::<u128>()
973 / total_circuits as u128;
974
975 let backend_usage: HashMap<BackendType, usize> =
976 self.performance_cache
977 .iter()
978 .fold(HashMap::new(), |mut acc, entry| {
979 *acc.entry(entry.backend_type).or_insert(0) += 1;
980 acc
981 });
982
983 let mut summary = "AutoOptimizer Performance Summary\n".to_string();
984 writeln!(summary, "Total circuits processed: {total_circuits}")
985 .expect("Writing to String should never fail");
986 writeln!(summary, "Average execution time: {avg_execution_time}ms")
987 .expect("Writing to String should never fail");
988 summary.push_str("Backend usage:\n");
989
990 for (backend, count) in backend_usage {
991 let percentage = (count as f64 / total_circuits as f64) * 100.0;
992 writeln!(
993 summary,
994 " {}: {} ({:.1}%)",
995 self.backend_type_name(backend),
996 count,
997 percentage
998 )
999 .expect("Writing to String should never fail");
1000 }
1001
1002 summary
1003 }
1004}
1005
1006impl Default for AutoOptimizer {
1007 fn default() -> Self {
1008 Self::new()
1009 }
1010}
1011
1012impl SciRS2CircuitAnalyzer {
1013 const fn analyze_circuit_with_scirs2<const N: usize>(
1015 &self,
1016 _circuit: &Circuit<N>,
1017 ) -> QuantRS2Result<f64> {
1018 Ok(0.7) }
1022}
1023
1024pub fn execute_with_auto_optimization<const N: usize>(
1026 circuit: &Circuit<N>,
1027) -> Result<SimulatorResult<N>> {
1028 let mut optimizer = AutoOptimizer::new();
1029 optimizer.execute_optimized(circuit)
1030}
1031
1032pub fn recommend_backend_for_circuit<const N: usize>(
1034 circuit: &Circuit<N>,
1035) -> QuantRS2Result<BackendRecommendation> {
1036 let mut optimizer = AutoOptimizer::new();
1037 optimizer.recommend_backend(circuit)
1038}
1039
1040#[cfg(test)]
1041mod tests {
1042 use super::*;
1043 use quantrs2_circuit::builder::CircuitBuilder;
1044
1045 #[test]
1046 fn test_auto_optimizer_creation() {
1047 let optimizer = AutoOptimizer::new();
1048 assert!(optimizer.config.enable_profiling);
1049 }
1050
1051 #[test]
1052 fn test_circuit_characteristics_analysis() {
1053 let optimizer = AutoOptimizer::new();
1054
1055 let mut builder = CircuitBuilder::<4>::new();
1057 let _ = builder.h(0);
1058 let _ = builder.cnot(0, 1);
1059 let _ = builder.h(2);
1060 let _ = builder.cnot(2, 3);
1061 let circuit = builder.build();
1062
1063 let characteristics = optimizer
1064 .analyze_circuit(&circuit)
1065 .expect("Failed to analyze circuit characteristics");
1066
1067 assert_eq!(characteristics.num_qubits, 4);
1068 assert_eq!(characteristics.num_gates, 4);
1069 assert!(characteristics.circuit_depth > 0);
1070 assert!(characteristics.two_qubit_density > 0.0);
1071 }
1072
1073 #[test]
1074 fn test_backend_recommendation() {
1075 let mut optimizer = AutoOptimizer::new();
1076
1077 let mut builder = CircuitBuilder::<2>::new();
1079 let _ = builder.h(0);
1080 let _ = builder.cnot(0, 1);
1081 let circuit = builder.build();
1082
1083 let recommendation = optimizer
1084 .recommend_backend(&circuit)
1085 .expect("Failed to get backend recommendation");
1086
1087 assert!(recommendation.confidence > 0.0);
1088 assert!(!recommendation.reasoning.is_empty());
1089 }
1090
1091 #[test]
1092 fn test_execute_with_optimization() {
1093 let mut optimizer = AutoOptimizer::new();
1094
1095 let mut builder = CircuitBuilder::<2>::new();
1097 let _ = builder.h(0);
1098 let _ = builder.cnot(0, 1);
1099 let circuit = builder.build();
1100
1101 let result = optimizer.execute_optimized(&circuit);
1102 assert!(result.is_ok());
1103
1104 if let Ok(sim_result) = result {
1105 assert_eq!(sim_result.num_qubits, 2);
1106 assert_eq!(sim_result.amplitudes.len(), 4);
1107 }
1108 }
1109
1110 #[test]
1111 fn test_convenience_functions() {
1112 let mut builder = CircuitBuilder::<2>::new();
1114 let _ = builder.h(0);
1115 let _ = builder.cnot(0, 1);
1116 let circuit = builder.build();
1117
1118 let recommendation = recommend_backend_for_circuit(&circuit);
1120 assert!(recommendation.is_ok());
1121
1122 let result = execute_with_auto_optimization(&circuit);
1124 assert!(result.is_ok());
1125 }
1126}