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};
23
24#[cfg(all(feature = "gpu", not(target_os = "macos")))]
25use crate::gpu::SciRS2GpuStateVectorSimulator;
26use scirs2_core::parallel_ops::current_num_threads; use scirs2_core::Complex64;
28use serde::{Deserialize, Serialize};
29use std::collections::HashMap;
30use std::sync::Arc;
31use std::time::{Duration, Instant};
32
33#[derive(Debug, Clone, Serialize, Deserialize)]
35pub struct AutoOptimizerConfig {
36 pub enable_profiling: bool,
38 pub memory_budget: usize,
40 pub cpu_utilization_threshold: f64,
42 pub gpu_check_timeout: Duration,
44 pub enable_distributed: bool,
46 pub scirs2_optimization_level: OptimizationLevel,
48 pub fallback_strategy: FallbackStrategy,
50 pub analysis_depth: AnalysisDepth,
52 pub performance_cache_size: usize,
54 pub backend_preferences: Vec<BackendType>,
56}
57
58impl Default for AutoOptimizerConfig {
59 fn default() -> Self {
60 Self {
61 enable_profiling: true,
62 memory_budget: 8 * 1024 * 1024 * 1024, cpu_utilization_threshold: 0.8,
64 gpu_check_timeout: Duration::from_millis(1000),
65 enable_distributed: true,
66 scirs2_optimization_level: OptimizationLevel::Aggressive,
67 fallback_strategy: FallbackStrategy::Conservative,
68 analysis_depth: AnalysisDepth::Deep,
69 performance_cache_size: 1000,
70 backend_preferences: vec![
71 BackendType::SciRS2Gpu,
72 BackendType::LargeScale,
73 BackendType::Distributed,
74 BackendType::StateVector,
75 ],
76 }
77 }
78}
79
80#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
82pub enum BackendType {
83 StateVector,
85 SciRS2Gpu,
87 LargeScale,
89 Distributed,
91 Auto,
93}
94
95#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
97pub enum OptimizationLevel {
98 None,
100 Basic,
102 Advanced,
104 Aggressive,
106}
107
108#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
110pub enum FallbackStrategy {
111 Conservative,
113 Aggressive,
115 Fail,
117}
118
119#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
121pub enum AnalysisDepth {
122 Quick,
124 Standard,
126 Deep,
128}
129
130#[derive(Debug, Clone)]
132pub struct CircuitCharacteristics {
133 pub num_qubits: usize,
135 pub num_gates: usize,
137 pub circuit_depth: usize,
139 pub gate_distribution: HashMap<String, usize>,
141 pub parallelism_potential: f64,
143 pub memory_requirement: usize,
145 pub complexity_score: f64,
147 pub two_qubit_density: f64,
149 pub connectivity_properties: ConnectivityProperties,
151 pub entanglement_depth: usize,
153 pub noise_susceptibility: f64,
155}
156
157#[derive(Debug, Clone)]
159pub struct ConnectivityProperties {
160 pub max_degree: usize,
162 pub avg_degree: f64,
164 pub connected_components: usize,
166 pub diameter: usize,
168 pub clustering_coefficient: f64,
170}
171
172#[derive(Debug, Clone)]
174pub struct BackendRecommendation {
175 pub backend_type: BackendType,
177 pub confidence: f64,
179 pub expected_improvement: f64,
181 pub estimated_execution_time: Duration,
183 pub estimated_memory_usage: usize,
185 pub reasoning: String,
187 pub alternatives: Vec<(BackendType, f64)>,
189 pub prediction_model: String,
191}
192
193#[derive(Debug, Clone)]
195pub struct PerformanceMetrics {
196 pub execution_time: Duration,
198 pub memory_usage: usize,
200 pub cpu_utilization: f64,
202 pub gpu_utilization: Option<f64>,
204 pub throughput: f64,
206 pub error_rate: f64,
208}
209
210#[derive(Debug, Clone)]
212pub struct PerformanceHistory {
213 pub circuit_hash: u64,
215 pub backend_type: BackendType,
217 pub metrics: PerformanceMetrics,
219 pub timestamp: Instant,
221}
222
223pub struct AutoOptimizer {
225 config: AutoOptimizerConfig,
227 circuit_optimizer: CircuitOptimizer,
229 parallel_engine: AutoParallelEngine,
231 performance_cache: Vec<PerformanceHistory>,
233 backend_availability: HashMap<BackendType, bool>,
235 scirs2_analyzer: SciRS2CircuitAnalyzer,
237}
238
239struct SciRS2CircuitAnalyzer {
241 enable_advanced_features: bool,
243}
244
245impl AutoOptimizer {
246 pub fn new() -> Self {
248 Self::with_config(AutoOptimizerConfig::default())
249 }
250
251 pub fn with_config(config: AutoOptimizerConfig) -> Self {
253 let optimization_config = OptimizationConfig {
254 enable_gate_fusion: true,
255 enable_redundant_elimination: true,
256 enable_commutation_reordering: true,
257 enable_single_qubit_optimization: true,
258 enable_two_qubit_optimization: true,
259 max_passes: 3,
260 enable_depth_reduction: true,
261 };
262
263 let parallel_config = AutoParallelConfig {
264 max_threads: current_num_threads(), min_gates_for_parallel: 20,
266 strategy: crate::automatic_parallelization::ParallelizationStrategy::Hybrid,
267 ..Default::default()
268 };
269
270 Self {
271 config,
272 circuit_optimizer: CircuitOptimizer::with_config(optimization_config),
273 parallel_engine: AutoParallelEngine::new(parallel_config),
274 performance_cache: Vec::new(),
275 backend_availability: HashMap::new(),
276 scirs2_analyzer: SciRS2CircuitAnalyzer {
277 enable_advanced_features: true,
278 },
279 }
280 }
281
282 pub fn analyze_circuit<const N: usize>(
284 &self,
285 circuit: &Circuit<N>,
286 ) -> QuantRS2Result<CircuitCharacteristics> {
287 let start_time = Instant::now();
288
289 let num_qubits = circuit.num_qubits();
291 let num_gates = circuit.num_gates();
292 let circuit_depth = self.calculate_circuit_depth(circuit);
293
294 let gate_distribution = self.analyze_gate_distribution(circuit);
296
297 let parallelism_potential = self.analyze_parallelism_potential(circuit)?;
299
300 let memory_requirement = self.estimate_memory_requirement(num_qubits, num_gates);
302
303 let complexity_score = self.calculate_complexity_score(circuit)?;
305
306 let two_qubit_density = self.calculate_two_qubit_density(circuit);
308
309 let connectivity_properties = self.analyze_connectivity(circuit)?;
311
312 let entanglement_depth = self.estimate_entanglement_depth(circuit)?;
314
315 let noise_susceptibility = self.analyze_noise_susceptibility(circuit);
317
318 let analysis_time = start_time.elapsed();
319 if self.config.enable_profiling {
320 println!("Circuit analysis completed in {analysis_time:?}");
321 }
322
323 Ok(CircuitCharacteristics {
324 num_qubits,
325 num_gates,
326 circuit_depth,
327 gate_distribution,
328 parallelism_potential,
329 memory_requirement,
330 complexity_score,
331 two_qubit_density,
332 connectivity_properties,
333 entanglement_depth,
334 noise_susceptibility,
335 })
336 }
337
338 pub fn recommend_backend<const N: usize>(
340 &mut self,
341 circuit: &Circuit<N>,
342 ) -> QuantRS2Result<BackendRecommendation> {
343 let characteristics = self.analyze_circuit(circuit)?;
345
346 self.update_backend_availability()?;
348
349 if let Some(cached_result) = self.check_performance_cache(&characteristics) {
351 return Ok(self.build_recommendation_from_cache(cached_result));
352 }
353
354 let recommendation = self.generate_backend_recommendation(&characteristics)?;
356
357 Ok(recommendation)
358 }
359
360 pub fn execute_optimized<const N: usize>(
362 &mut self,
363 circuit: &Circuit<N>,
364 ) -> Result<SimulatorResult<N>> {
365 let recommendation = self
367 .recommend_backend(circuit)
368 .map_err(|e| SimulatorError::ComputationError(e.to_string()))?;
369
370 if self.config.enable_profiling {
371 println!(
372 "Using {} backend (confidence: {:.2})",
373 self.backend_type_name(recommendation.backend_type),
374 recommendation.confidence
375 );
376 println!("Reasoning: {}", recommendation.reasoning);
377 }
378
379 let start_time = Instant::now();
381 let register = self.execute_with_backend(circuit, recommendation.backend_type)?;
382 let execution_time = start_time.elapsed();
383
384 let result = self.register_to_simulator_result(register);
386
387 if self.config.enable_profiling {
389 self.record_performance_metrics(circuit, recommendation.backend_type, execution_time);
390 println!("Execution completed in {execution_time:?}");
391 }
392
393 Ok(result)
394 }
395
396 fn calculate_circuit_depth<const N: usize>(&self, circuit: &Circuit<N>) -> usize {
398 let mut qubit_depths = HashMap::new();
399 let mut max_depth = 0;
400
401 for gate in circuit.gates() {
402 let qubits = gate.qubits();
403
404 let input_depth = qubits
406 .iter()
407 .map(|&q| qubit_depths.get(&q).copied().unwrap_or(0))
408 .max()
409 .unwrap_or(0);
410
411 let new_depth = input_depth + 1;
412
413 for &qubit in &qubits {
415 qubit_depths.insert(qubit, new_depth);
416 }
417
418 max_depth = max_depth.max(new_depth);
419 }
420
421 max_depth
422 }
423
424 fn analyze_gate_distribution<const N: usize>(
426 &self,
427 circuit: &Circuit<N>,
428 ) -> HashMap<String, usize> {
429 let mut distribution = HashMap::new();
430
431 for gate in circuit.gates() {
432 let gate_name = gate.name().to_string();
433 *distribution.entry(gate_name).or_insert(0) += 1;
434 }
435
436 distribution
437 }
438
439 fn analyze_parallelism_potential<const N: usize>(
441 &self,
442 circuit: &Circuit<N>,
443 ) -> QuantRS2Result<f64> {
444 let analysis = self.parallel_engine.analyze_circuit(circuit)?;
446 Ok(analysis.efficiency)
447 }
448
449 const fn estimate_memory_requirement(&self, num_qubits: usize, num_gates: usize) -> usize {
451 let state_vector_size = (1 << num_qubits) * std::mem::size_of::<Complex64>();
453
454 let overhead = num_gates * 64; state_vector_size + overhead
458 }
459
460 fn calculate_complexity_score<const N: usize>(
462 &self,
463 circuit: &Circuit<N>,
464 ) -> QuantRS2Result<f64> {
465 let num_qubits = circuit.num_qubits() as f64;
466 let num_gates = circuit.num_gates() as f64;
467 let depth = self.calculate_circuit_depth(circuit) as f64;
468
469 let gate_complexity = num_gates * (num_qubits.log2() + 1.0);
471 let depth_complexity = depth * num_qubits;
472 let entanglement_complexity = self.estimate_entanglement_complexity(circuit)?;
473
474 Ok((gate_complexity + depth_complexity + entanglement_complexity) / 1000.0)
475 }
476
477 fn estimate_entanglement_complexity<const N: usize>(
479 &self,
480 circuit: &Circuit<N>,
481 ) -> QuantRS2Result<f64> {
482 let mut entanglement_score = 0.0;
483
484 for gate in circuit.gates() {
485 let qubits = gate.qubits();
486 if qubits.len() >= 2 {
487 entanglement_score += qubits.len() as f64 * qubits.len() as f64;
489 }
490 }
491
492 Ok(entanglement_score)
493 }
494
495 fn calculate_two_qubit_density<const N: usize>(&self, circuit: &Circuit<N>) -> f64 {
497 let total_gates = circuit.num_gates();
498 if total_gates == 0 {
499 return 0.0;
500 }
501
502 let two_qubit_gates = circuit
503 .gates()
504 .iter()
505 .filter(|gate| gate.qubits().len() >= 2)
506 .count();
507
508 two_qubit_gates as f64 / total_gates as f64
509 }
510
511 fn analyze_connectivity<const N: usize>(
513 &self,
514 circuit: &Circuit<N>,
515 ) -> QuantRS2Result<ConnectivityProperties> {
516 let mut qubit_connections: HashMap<QubitId, Vec<QubitId>> = HashMap::new();
517
518 for gate in circuit.gates() {
520 let qubits = gate.qubits();
521 if qubits.len() >= 2 {
522 for i in 0..qubits.len() {
523 for j in (i + 1)..qubits.len() {
524 qubit_connections
525 .entry(qubits[i])
526 .or_default()
527 .push(qubits[j]);
528 qubit_connections
529 .entry(qubits[j])
530 .or_default()
531 .push(qubits[i]);
532 }
533 }
534 }
535 }
536
537 let max_degree = qubit_connections
539 .values()
540 .map(|connections| connections.len())
541 .max()
542 .unwrap_or(0);
543
544 let avg_degree = if qubit_connections.is_empty() {
545 0.0
546 } else {
547 qubit_connections
548 .values()
549 .map(|connections| connections.len())
550 .sum::<usize>() as f64
551 / qubit_connections.len() as f64
552 };
553
554 let connected_components = 1; let diameter = circuit.num_qubits().min(6); let clustering_coefficient = 0.5; Ok(ConnectivityProperties {
564 max_degree,
565 avg_degree,
566 connected_components,
567 diameter,
568 clustering_coefficient,
569 })
570 }
571
572 fn estimate_entanglement_depth<const N: usize>(
574 &self,
575 circuit: &Circuit<N>,
576 ) -> QuantRS2Result<usize> {
577 let two_qubit_gates = circuit
579 .gates()
580 .iter()
581 .filter(|gate| gate.qubits().len() >= 2)
582 .count();
583
584 let depth_estimate = (two_qubit_gates as f64).sqrt().ceil() as usize;
586 Ok(depth_estimate.min(circuit.num_qubits()))
587 }
588
589 fn analyze_noise_susceptibility<const N: usize>(&self, circuit: &Circuit<N>) -> f64 {
591 let depth = self.calculate_circuit_depth(circuit) as f64;
592 let two_qubit_density = self.calculate_two_qubit_density(circuit);
593
594 (depth / 100.0 + two_qubit_density).min(1.0)
596 }
597
598 fn update_backend_availability(&mut self) -> QuantRS2Result<()> {
600 #[cfg(all(feature = "gpu", not(target_os = "macos")))]
602 let gpu_available = SciRS2GpuStateVectorSimulator::is_available();
603 #[cfg(any(not(feature = "gpu"), target_os = "macos"))]
604 let gpu_available = false;
605
606 self.backend_availability
607 .insert(BackendType::SciRS2Gpu, gpu_available);
608
609 self.backend_availability
611 .insert(BackendType::StateVector, true);
612 self.backend_availability
613 .insert(BackendType::LargeScale, true);
614
615 self.backend_availability
617 .insert(BackendType::Distributed, false);
618
619 Ok(())
620 }
621
622 fn check_performance_cache(
624 &self,
625 characteristics: &CircuitCharacteristics,
626 ) -> Option<&PerformanceHistory> {
627 self.performance_cache
630 .iter()
631 .find(|&entry| self.are_characteristics_similar(characteristics, entry))
632 .map(|v| v as _)
633 }
634
635 const fn are_characteristics_similar(
637 &self,
638 characteristics: &CircuitCharacteristics,
639 entry: &PerformanceHistory,
640 ) -> bool {
641 false }
644
645 fn build_recommendation_from_cache(
647 &self,
648 cache_entry: &PerformanceHistory,
649 ) -> BackendRecommendation {
650 BackendRecommendation {
651 backend_type: cache_entry.backend_type,
652 confidence: 0.9, expected_improvement: 0.0,
654 estimated_execution_time: cache_entry.metrics.execution_time,
655 estimated_memory_usage: cache_entry.metrics.memory_usage,
656 reasoning: "Based on cached performance data for similar circuits".to_string(),
657 alternatives: Vec::new(),
658 prediction_model: "Cache-based".to_string(),
659 }
660 }
661
662 fn generate_backend_recommendation(
664 &self,
665 characteristics: &CircuitCharacteristics,
666 ) -> QuantRS2Result<BackendRecommendation> {
667 let mut scores: HashMap<BackendType, f64> = HashMap::new();
668 let mut reasoning = String::new();
669
670 for &backend_type in &self.config.backend_preferences {
672 if !self
673 .backend_availability
674 .get(&backend_type)
675 .unwrap_or(&false)
676 {
677 continue;
678 }
679
680 let score = self.score_backend_for_characteristics(backend_type, characteristics);
681 scores.insert(backend_type, score);
682 }
683
684 let (best_backend, best_score) = scores
686 .into_iter()
687 .max_by(|(_, a), (_, b)| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal))
688 .unwrap_or((BackendType::StateVector, 0.5));
689
690 reasoning = self.generate_recommendation_reasoning(best_backend, characteristics);
692
693 let estimated_execution_time = self.estimate_execution_time(best_backend, characteristics);
695 let estimated_memory_usage = characteristics.memory_requirement;
696
697 Ok(BackendRecommendation {
698 backend_type: best_backend,
699 confidence: best_score,
700 expected_improvement: (best_score - 0.5).max(0.0) * 2.0, estimated_execution_time,
702 estimated_memory_usage,
703 reasoning,
704 alternatives: Vec::new(),
705 prediction_model: "SciRS2-guided heuristic".to_string(),
706 })
707 }
708
709 fn score_backend_for_characteristics(
711 &self,
712 backend_type: BackendType,
713 characteristics: &CircuitCharacteristics,
714 ) -> f64 {
715 let mut score: f64 = 0.5; match backend_type {
718 BackendType::StateVector => {
719 if characteristics.num_qubits <= 20 {
721 score += 0.3;
722 }
723 if characteristics.num_gates <= 1000 {
724 score += 0.2;
725 }
726 }
727 BackendType::SciRS2Gpu => {
728 if characteristics.num_qubits >= 10 && characteristics.num_qubits <= 30 {
730 score += 0.4;
731 }
732 if characteristics.parallelism_potential > 0.5 {
733 score += 0.3;
734 }
735 if characteristics.two_qubit_density > 0.3 {
736 score += 0.2;
737 }
738 }
739 BackendType::LargeScale => {
740 if characteristics.num_qubits >= 20 {
742 score += 0.4;
743 }
744 if characteristics.complexity_score > 0.5 {
745 score += 0.3;
746 }
747 }
748 BackendType::Distributed => {
749 if characteristics.num_qubits >= 30 {
751 score += 0.5;
752 }
753 if characteristics.memory_requirement > self.config.memory_budget / 2 {
754 score += 0.3;
755 }
756 }
757 BackendType::Auto => {
758 score = 0.1;
760 }
761 }
762
763 score.min(1.0)
764 }
765
766 fn generate_recommendation_reasoning(
768 &self,
769 backend_type: BackendType,
770 characteristics: &CircuitCharacteristics,
771 ) -> String {
772 match backend_type {
773 BackendType::StateVector => {
774 format!("CPU state vector simulator recommended for {} qubits, {} gates. Suitable for small circuits with straightforward execution.",
775 characteristics.num_qubits, characteristics.num_gates)
776 }
777 BackendType::SciRS2Gpu => {
778 format!("SciRS2 GPU simulator recommended for {} qubits, {} gates. High parallelism potential ({:.2}) and two-qubit gate density ({:.2}) make GPU acceleration beneficial.",
779 characteristics.num_qubits, characteristics.num_gates, characteristics.parallelism_potential, characteristics.two_qubit_density)
780 }
781 BackendType::LargeScale => {
782 format!("Large-scale simulator recommended for {} qubits, {} gates. Circuit complexity ({:.2}) and depth ({}) require optimized memory management.",
783 characteristics.num_qubits, characteristics.num_gates, characteristics.complexity_score, characteristics.circuit_depth)
784 }
785 BackendType::Distributed => {
786 format!("Distributed simulator recommended for {} qubits, {} gates. Memory requirement ({:.1} MB) exceeds single-node capacity.",
787 characteristics.num_qubits, characteristics.num_gates, characteristics.memory_requirement as f64 / (1024.0 * 1024.0))
788 }
789 BackendType::Auto => "Automatic backend selection".to_string(),
790 }
791 }
792
793 fn estimate_execution_time(
795 &self,
796 backend_type: BackendType,
797 characteristics: &CircuitCharacteristics,
798 ) -> Duration {
799 let base_time_ms = match backend_type {
800 BackendType::StateVector => characteristics.num_gates as u64 * 10,
801 BackendType::SciRS2Gpu => characteristics.num_gates as u64 * 2,
802 BackendType::LargeScale => characteristics.num_gates as u64 * 5,
803 BackendType::Distributed => characteristics.num_gates as u64 * 15,
804 BackendType::Auto => characteristics.num_gates as u64 * 10,
805 };
806
807 let complexity_factor = characteristics.complexity_score.mul_add(2.0, 1.0) as u64;
809 Duration::from_millis(base_time_ms * complexity_factor)
810 }
811
812 fn execute_with_backend<const N: usize>(
814 &self,
815 circuit: &Circuit<N>,
816 backend_type: BackendType,
817 ) -> Result<Register<N>> {
818 match backend_type {
819 BackendType::StateVector => {
820 let simulator = StateVectorSimulator::new();
821 simulator
822 .run(circuit)
823 .map_err(|e| SimulatorError::ComputationError(e.to_string()))
824 .and_then(|result| {
825 Register::with_amplitudes(result.amplitudes().to_vec())
826 .map_err(|e| SimulatorError::ComputationError(e.to_string()))
827 })
828 }
829 BackendType::SciRS2Gpu => {
830 #[cfg(all(feature = "gpu", not(target_os = "macos")))]
831 {
832 let mut simulator = SciRS2GpuStateVectorSimulator::new()
833 .map_err(|e| SimulatorError::ComputationError(e.to_string()))?;
834 use crate::simulator::Simulator;
835 simulator
836 .run(circuit)
837 .map_err(|e| SimulatorError::ComputationError(e.to_string()))
838 .and_then(|result| {
839 Register::with_amplitudes(result.amplitudes().to_vec())
840 .map_err(|e| SimulatorError::ComputationError(e.to_string()))
841 })
842 }
843 #[cfg(any(not(feature = "gpu"), target_os = "macos"))]
844 {
845 let simulator = StateVectorSimulator::new();
847 simulator
848 .run(circuit)
849 .map_err(|e| SimulatorError::ComputationError(e.to_string()))
850 .and_then(|result| {
851 Register::with_amplitudes(result.amplitudes().to_vec())
852 .map_err(|e| SimulatorError::ComputationError(e.to_string()))
853 })
854 }
855 }
856 BackendType::LargeScale => {
857 let config = LargeScaleSimulatorConfig::default();
859 let simulator = LargeScaleQuantumSimulator::new(config)
860 .map_err(|e| SimulatorError::ComputationError(e.to_string()))?;
861 simulator
862 .run(circuit)
863 .map_err(|e| SimulatorError::ComputationError(e.to_string()))
864 }
865 BackendType::Distributed => {
866 let config = LargeScaleSimulatorConfig::default();
868 let simulator = LargeScaleQuantumSimulator::new(config)
869 .map_err(|e| SimulatorError::ComputationError(e.to_string()))?;
870 simulator
871 .run(circuit)
872 .map_err(|e| SimulatorError::ComputationError(e.to_string()))
873 }
874 BackendType::Auto => {
875 let simulator = StateVectorSimulator::new();
877 simulator
878 .run(circuit)
879 .map_err(|e| SimulatorError::ComputationError(e.to_string()))
880 }
881 }
882 }
883
884 fn register_to_simulator_result<const N: usize>(
886 &self,
887 register: Register<N>,
888 ) -> SimulatorResult<N> {
889 let amplitudes = register.amplitudes().to_vec();
891
892 SimulatorResult {
893 amplitudes,
894 num_qubits: N,
895 }
896 }
897
898 fn record_performance_metrics<const N: usize>(
900 &mut self,
901 circuit: &Circuit<N>,
902 backend_type: BackendType,
903 execution_time: Duration,
904 ) {
905 let metrics = PerformanceMetrics {
906 execution_time,
907 memory_usage: 0, cpu_utilization: 0.0, gpu_utilization: None,
910 throughput: circuit.num_gates() as f64 / execution_time.as_secs_f64(),
911 error_rate: 0.0,
912 };
913
914 let history_entry = PerformanceHistory {
915 circuit_hash: self.compute_circuit_hash(circuit),
916 backend_type,
917 metrics,
918 timestamp: Instant::now(),
919 };
920
921 self.performance_cache.push(history_entry);
922
923 if self.performance_cache.len() > self.config.performance_cache_size {
925 self.performance_cache.remove(0);
926 }
927 }
928
929 fn compute_circuit_hash<const N: usize>(&self, circuit: &Circuit<N>) -> u64 {
931 use std::collections::hash_map::DefaultHasher;
932 use std::hash::{Hash, Hasher};
933
934 let mut hasher = DefaultHasher::new();
935 circuit.num_gates().hash(&mut hasher);
936 circuit.num_qubits().hash(&mut hasher);
937
938 for gate in circuit.gates() {
939 gate.name().hash(&mut hasher);
940 gate.qubits().len().hash(&mut hasher);
941 }
942
943 hasher.finish()
944 }
945
946 const fn backend_type_name(&self, backend_type: BackendType) -> &'static str {
948 match backend_type {
949 BackendType::StateVector => "CPU StateVector",
950 BackendType::SciRS2Gpu => "SciRS2 GPU",
951 BackendType::LargeScale => "Large-Scale",
952 BackendType::Distributed => "Distributed",
953 BackendType::Auto => "Auto",
954 }
955 }
956
957 pub fn get_performance_summary(&self) -> String {
959 let total_circuits = self.performance_cache.len();
960 if total_circuits == 0 {
961 return "No performance data available".to_string();
962 }
963
964 let avg_execution_time = self
965 .performance_cache
966 .iter()
967 .map(|entry| entry.metrics.execution_time.as_millis())
968 .sum::<u128>()
969 / total_circuits as u128;
970
971 let backend_usage: HashMap<BackendType, usize> =
972 self.performance_cache
973 .iter()
974 .fold(HashMap::new(), |mut acc, entry| {
975 *acc.entry(entry.backend_type).or_insert(0) += 1;
976 acc
977 });
978
979 let mut summary = "AutoOptimizer Performance Summary\n".to_string();
980 summary.push_str(&format!("Total circuits processed: {total_circuits}\n"));
981 summary.push_str(&format!("Average execution time: {avg_execution_time}ms\n"));
982 summary.push_str("Backend usage:\n");
983
984 for (backend, count) in backend_usage {
985 let percentage = (count as f64 / total_circuits as f64) * 100.0;
986 summary.push_str(&format!(
987 " {}: {} ({:.1}%)\n",
988 self.backend_type_name(backend),
989 count,
990 percentage
991 ));
992 }
993
994 summary
995 }
996}
997
998impl Default for AutoOptimizer {
999 fn default() -> Self {
1000 Self::new()
1001 }
1002}
1003
1004impl SciRS2CircuitAnalyzer {
1005 const fn analyze_circuit_with_scirs2<const N: usize>(
1007 &self,
1008 _circuit: &Circuit<N>,
1009 ) -> QuantRS2Result<f64> {
1010 Ok(0.7) }
1014}
1015
1016pub fn execute_with_auto_optimization<const N: usize>(
1018 circuit: &Circuit<N>,
1019) -> Result<SimulatorResult<N>> {
1020 let mut optimizer = AutoOptimizer::new();
1021 optimizer.execute_optimized(circuit)
1022}
1023
1024pub fn recommend_backend_for_circuit<const N: usize>(
1026 circuit: &Circuit<N>,
1027) -> QuantRS2Result<BackendRecommendation> {
1028 let mut optimizer = AutoOptimizer::new();
1029 optimizer.recommend_backend(circuit)
1030}
1031
1032#[cfg(test)]
1033mod tests {
1034 use super::*;
1035 use quantrs2_circuit::builder::CircuitBuilder;
1036
1037 #[test]
1038 fn test_auto_optimizer_creation() {
1039 let optimizer = AutoOptimizer::new();
1040 assert!(optimizer.config.enable_profiling);
1041 }
1042
1043 #[test]
1044 fn test_circuit_characteristics_analysis() {
1045 let optimizer = AutoOptimizer::new();
1046
1047 let mut builder = CircuitBuilder::<4>::new();
1049 let _ = builder.h(0);
1050 let _ = builder.cnot(0, 1);
1051 let _ = builder.h(2);
1052 let _ = builder.cnot(2, 3);
1053 let circuit = builder.build();
1054
1055 let characteristics = optimizer.analyze_circuit(&circuit).unwrap();
1056
1057 assert_eq!(characteristics.num_qubits, 4);
1058 assert_eq!(characteristics.num_gates, 4);
1059 assert!(characteristics.circuit_depth > 0);
1060 assert!(characteristics.two_qubit_density > 0.0);
1061 }
1062
1063 #[test]
1064 fn test_backend_recommendation() {
1065 let mut optimizer = AutoOptimizer::new();
1066
1067 let mut builder = CircuitBuilder::<2>::new();
1069 let _ = builder.h(0);
1070 let _ = builder.cnot(0, 1);
1071 let circuit = builder.build();
1072
1073 let recommendation = optimizer.recommend_backend(&circuit).unwrap();
1074
1075 assert!(recommendation.confidence > 0.0);
1076 assert!(!recommendation.reasoning.is_empty());
1077 }
1078
1079 #[test]
1080 fn test_execute_with_optimization() {
1081 let mut optimizer = AutoOptimizer::new();
1082
1083 let mut builder = CircuitBuilder::<2>::new();
1085 let _ = builder.h(0);
1086 let _ = builder.cnot(0, 1);
1087 let circuit = builder.build();
1088
1089 let result = optimizer.execute_optimized(&circuit);
1090 assert!(result.is_ok());
1091
1092 if let Ok(sim_result) = result {
1093 assert_eq!(sim_result.num_qubits, 2);
1094 assert_eq!(sim_result.amplitudes.len(), 4);
1095 }
1096 }
1097
1098 #[test]
1099 fn test_convenience_functions() {
1100 let mut builder = CircuitBuilder::<2>::new();
1102 let _ = builder.h(0);
1103 let _ = builder.cnot(0, 1);
1104 let circuit = builder.build();
1105
1106 let recommendation = recommend_backend_for_circuit(&circuit);
1108 assert!(recommendation.is_ok());
1109
1110 let result = execute_with_auto_optimization(&circuit);
1112 assert!(result.is_ok());
1113 }
1114}