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