quantrs2_core/
scirs2_auto_optimizer.rs

1//! Automatic Backend Optimization System with SciRS2 Intelligence
2//!
3//! This module provides intelligent automatic backend selection and optimization
4//! based on problem characteristics, available hardware, and performance requirements.
5//! Uses SciRS2's analysis capabilities to make optimal backend choices.
6
7use crate::error::{QuantRS2Error, QuantRS2Result};
8use crate::gate_translation::GateType;
9use crate::parallel_ops_stubs::*;
10use crate::platform::PlatformCapabilities;
11use scirs2_core::ndarray::{Array1, Array2};
12use scirs2_core::Complex64;
13use serde::{Deserialize, Serialize};
14use std::collections::{BTreeMap, HashMap, HashSet};
15use std::sync::Arc;
16use std::time::Duration;
17
18/// Automatic optimizer for backend selection and configuration
19pub struct AutoOptimizer {
20    /// Platform capabilities detector
21    platform_caps: Arc<PlatformCapabilities>,
22    /// Configuration for optimization decisions
23    config: AutoOptimizerConfig,
24    /// Problem analysis cache
25    analysis_cache: HashMap<String, ProblemAnalysis>,
26    /// Backend performance profiles
27    backend_profiles: HashMap<BackendType, PerformanceProfile>,
28    /// Resource monitor
29    resource_monitor: ResourceMonitor,
30}
31
32/// Configuration for the AutoOptimizer
33#[derive(Debug, Clone, Serialize, Deserialize)]
34pub struct AutoOptimizerConfig {
35    /// Enable automatic backend switching
36    pub enable_auto_switching: bool,
37    /// Performance vs accuracy trade-off (0.0 = max accuracy, 1.0 = max performance)
38    pub performance_bias: f64,
39    /// Maximum memory usage allowed (in GB)
40    pub max_memory_gb: f64,
41    /// Target execution time (None = no constraint)
42    pub target_time: Option<Duration>,
43    /// Enable GPU acceleration when available
44    pub enable_gpu: bool,
45    /// Enable distributed computation
46    pub enable_distributed: bool,
47    /// Minimum problem size for GPU acceleration
48    pub gpu_threshold_qubits: usize,
49    /// Minimum problem size for distributed computation
50    pub distributed_threshold_qubits: usize,
51    /// Cache analysis results
52    pub enable_caching: bool,
53    /// Resource monitoring interval
54    pub monitoring_interval: Duration,
55}
56
57impl Default for AutoOptimizerConfig {
58    fn default() -> Self {
59        Self {
60            enable_auto_switching: true,
61            performance_bias: 0.5,
62            max_memory_gb: 8.0,
63            target_time: Some(Duration::from_secs(300)), // 5 minutes
64            enable_gpu: true,
65            enable_distributed: false,
66            gpu_threshold_qubits: 12,
67            distributed_threshold_qubits: 20,
68            enable_caching: true,
69            monitoring_interval: Duration::from_millis(100),
70        }
71    }
72}
73
74/// Supported backend types
75#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
76pub enum BackendType {
77    /// Single-threaded CPU backend
78    CPUSingle,
79    /// Multi-threaded CPU backend
80    CPUParallel,
81    /// GPU-accelerated backend
82    GPU,
83    /// Distributed computing backend
84    Distributed,
85    /// Hybrid CPU+GPU backend
86    Hybrid,
87    /// Quantum hardware backend
88    Hardware,
89    /// Simulator with noise models
90    NoisySimulator,
91    /// High-precision simulator
92    HighPrecision,
93}
94
95/// Problem characteristics analysis
96#[derive(Debug, Clone, Serialize, Deserialize)]
97pub struct ProblemAnalysis {
98    /// Number of qubits
99    pub num_qubits: usize,
100    /// Circuit depth
101    pub circuit_depth: usize,
102    /// Gate composition analysis
103    pub gate_composition: GateComposition,
104    /// Entanglement analysis
105    pub entanglement_analysis: EntanglementAnalysis,
106    /// Memory requirements estimate
107    pub memory_estimate_gb: f64,
108    /// Computational complexity estimate
109    pub complexity_estimate: ComplexityEstimate,
110    /// Problem type classification
111    pub problem_type: ProblemType,
112    /// Parallelization potential
113    pub parallelization_potential: ParallelizationPotential,
114    /// Resource requirements
115    pub resource_requirements: ResourceRequirements,
116}
117
118/// Gate composition analysis
119#[derive(Debug, Clone, Serialize, Deserialize)]
120pub struct GateComposition {
121    /// Total number of gates
122    pub total_gates: usize,
123    /// Single-qubit gates count
124    pub single_qubit_gates: usize,
125    /// Two-qubit gates count
126    pub two_qubit_gates: usize,
127    /// Multi-qubit gates count
128    pub multi_qubit_gates: usize,
129    /// Gate type distribution
130    pub gate_types: HashMap<String, usize>,
131    /// Parameterized gates count
132    pub parameterized_gates: usize,
133    /// SIMD-friendly gates percentage
134    pub simd_friendly_percentage: f64,
135}
136
137/// Entanglement analysis
138#[derive(Debug, Clone, Serialize, Deserialize)]
139pub struct EntanglementAnalysis {
140    /// Maximum entanglement depth
141    pub max_entanglement_depth: usize,
142    /// Entanglement graph connectivity
143    pub connectivity_ratio: f64,
144    /// Separable subsystem count
145    pub separable_subsystems: usize,
146    /// Entanglement entropy estimate
147    pub entanglement_entropy: f64,
148}
149
150/// Computational complexity estimate
151#[derive(Debug, Clone, Serialize, Deserialize)]
152pub struct ComplexityEstimate {
153    /// Time complexity class
154    pub time_complexity: ComplexityClass,
155    /// Space complexity class
156    pub space_complexity: ComplexityClass,
157    /// Estimated operations count
158    pub operation_count: u64,
159    /// Memory access pattern
160    pub memory_pattern: MemoryPattern,
161    /// Parallelization factor
162    pub parallelization_factor: f64,
163}
164
165/// Complexity classes
166#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
167pub enum ComplexityClass {
168    Constant,
169    Logarithmic,
170    Linear,
171    Quadratic,
172    Exponential,
173    DoubleExponential,
174}
175
176/// Memory access patterns
177#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
178pub enum MemoryPattern {
179    Sequential,
180    Random,
181    Strided,
182    Blocked,
183    Hierarchical,
184}
185
186/// Problem type classifications
187#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
188pub enum ProblemType {
189    /// Quantum circuit simulation
190    Simulation,
191    /// Variational quantum eigensolver
192    VQE,
193    /// Quantum approximate optimization algorithm
194    QAOA,
195    /// Quantum machine learning
196    QML,
197    /// Quantum error correction
198    QEC,
199    /// Quantum Fourier transform
200    QFT,
201    /// Amplitude estimation
202    AmplitudeEstimation,
203    /// Quantum walk
204    QuantumWalk,
205    /// Custom algorithm
206    Custom,
207}
208
209/// Parallelization potential analysis
210#[derive(Debug, Clone, Serialize, Deserialize)]
211pub struct ParallelizationPotential {
212    /// Gate-level parallelism potential
213    pub gate_parallelism: f64,
214    /// State-level parallelism potential
215    pub state_parallelism: f64,
216    /// Batch processing potential
217    pub batch_potential: f64,
218    /// SIMD potential
219    pub simd_potential: f64,
220    /// GPU acceleration potential
221    pub gpu_potential: f64,
222    /// Distributed computing potential
223    pub distributed_potential: f64,
224}
225
226/// Resource requirements
227#[derive(Debug, Clone, Serialize, Deserialize)]
228pub struct ResourceRequirements {
229    /// Memory requirements (GB)
230    pub memory_gb: f64,
231    /// CPU cores required
232    pub cpu_cores: usize,
233    /// GPU memory required (GB)
234    pub gpu_memory_gb: f64,
235    /// Network bandwidth required (MB/s)
236    pub network_bandwidth_mbps: f64,
237    /// Storage requirements (GB)
238    pub storage_gb: f64,
239    /// Estimated execution time
240    pub estimated_time: Duration,
241}
242
243/// Backend performance profile
244#[derive(Debug, Clone, Serialize, Deserialize)]
245pub struct PerformanceProfile {
246    /// Backend type
247    pub backend_type: BackendType,
248    /// Performance metrics
249    pub metrics: PerformanceMetrics,
250    /// Resource utilization
251    pub resource_utilization: ResourceUtilization,
252    /// Supported problem sizes
253    pub problem_size_limits: ProblemSizeLimits,
254    /// Optimization recommendations
255    pub optimizations: Vec<OptimizationRecommendation>,
256}
257
258/// Performance metrics
259#[derive(Debug, Clone, Serialize, Deserialize)]
260pub struct PerformanceMetrics {
261    /// Throughput (operations/second)
262    pub throughput: f64,
263    /// Latency (seconds)
264    pub latency: f64,
265    /// Memory efficiency (0.0 to 1.0)
266    pub memory_efficiency: f64,
267    /// CPU utilization (0.0 to 1.0)
268    pub cpu_utilization: f64,
269    /// GPU utilization (0.0 to 1.0)
270    pub gpu_utilization: f64,
271    /// Energy efficiency (operations/watt)
272    pub energy_efficiency: f64,
273}
274
275/// Resource utilization
276#[derive(Debug, Clone, Serialize, Deserialize)]
277pub struct ResourceUtilization {
278    /// CPU usage percentage
279    pub cpu_usage: f64,
280    /// Memory usage (GB)
281    pub memory_usage_gb: f64,
282    /// GPU usage percentage
283    pub gpu_usage: f64,
284    /// GPU memory usage (GB)
285    pub gpu_memory_usage_gb: f64,
286    /// Network usage (MB/s)
287    pub network_usage_mbps: f64,
288}
289
290/// Problem size limits for each backend
291#[derive(Debug, Clone, Serialize, Deserialize)]
292pub struct ProblemSizeLimits {
293    /// Maximum number of qubits
294    pub max_qubits: usize,
295    /// Maximum circuit depth
296    pub max_depth: usize,
297    /// Maximum gates
298    pub max_gates: usize,
299    /// Maximum memory usage (GB)
300    pub max_memory_gb: f64,
301}
302
303/// Optimization recommendations
304#[derive(Debug, Clone, Serialize, Deserialize)]
305pub struct OptimizationRecommendation {
306    /// Recommendation type
307    pub recommendation_type: RecommendationType,
308    /// Description
309    pub description: String,
310    /// Expected performance improvement
311    pub expected_improvement: f64,
312    /// Implementation difficulty (1-10)
313    pub difficulty: u8,
314    /// Resource requirements
315    pub resource_cost: ResourceCost,
316}
317
318/// Types of optimization recommendations
319#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
320pub enum RecommendationType {
321    /// Use different backend
322    BackendSwitch,
323    /// Adjust parallelization
324    ParallelizationTuning,
325    /// Memory optimization
326    MemoryOptimization,
327    /// Algorithm-specific optimization
328    AlgorithmOptimization,
329    /// Hardware-specific optimization
330    HardwareOptimization,
331    /// Numerical precision adjustment
332    PrecisionAdjustment,
333}
334
335/// Resource cost for implementing recommendations
336#[derive(Debug, Clone, Serialize, Deserialize)]
337pub struct ResourceCost {
338    /// Additional memory required (GB)
339    pub memory_gb: f64,
340    /// Additional CPU cores required
341    pub cpu_cores: usize,
342    /// Additional GPU memory required (GB)
343    pub gpu_memory_gb: f64,
344    /// Setup time required
345    pub setup_time: Duration,
346}
347
348/// Resource monitoring system
349#[derive(Debug, Clone)]
350pub struct ResourceMonitor {
351    /// CPU usage history
352    pub cpu_history: Vec<f64>,
353    /// Memory usage history
354    pub memory_history: Vec<f64>,
355    /// GPU usage history
356    pub gpu_history: Vec<f64>,
357    /// Network usage history
358    pub network_history: Vec<f64>,
359    /// Monitoring interval
360    pub interval: Duration,
361}
362
363/// Backend selection result
364#[derive(Debug, Clone, Serialize, Deserialize)]
365pub struct BackendSelection {
366    /// Selected backend type
367    pub backend_type: BackendType,
368    /// Confidence score (0.0 to 1.0)
369    pub confidence: f64,
370    /// Reasoning for selection
371    pub reasoning: Vec<String>,
372    /// Expected performance
373    pub expected_performance: PerformanceMetrics,
374    /// Configuration parameters
375    pub configuration: BackendConfiguration,
376    /// Alternative backends
377    pub alternatives: Vec<(BackendType, f64)>,
378}
379
380/// Backend configuration parameters
381#[derive(Debug, Clone, Serialize, Deserialize)]
382pub struct BackendConfiguration {
383    /// Number of threads to use
384    pub num_threads: usize,
385    /// Batch size for parallel operations
386    pub batch_size: usize,
387    /// Memory allocation strategy
388    pub memory_strategy: MemoryStrategy,
389    /// Precision settings
390    pub precision_settings: PrecisionSettings,
391    /// GPU configuration
392    pub gpu_config: Option<GPUConfiguration>,
393    /// Distributed configuration
394    pub distributed_config: Option<DistributedConfiguration>,
395}
396
397/// Memory allocation strategies
398#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
399pub enum MemoryStrategy {
400    /// Standard heap allocation
401    Heap,
402    /// Memory pool allocation
403    Pool,
404    /// Memory-mapped allocation
405    MemoryMapped,
406    /// Shared memory allocation
407    Shared,
408}
409
410/// Precision settings
411#[derive(Debug, Clone, Serialize, Deserialize)]
412pub struct PrecisionSettings {
413    /// Floating-point precision
414    pub float_precision: FloatPrecision,
415    /// Numerical tolerance
416    pub tolerance: f64,
417    /// Adaptive precision enabled
418    pub adaptive_precision: bool,
419}
420
421/// Floating-point precision levels
422#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
423pub enum FloatPrecision {
424    /// Single precision (32-bit)
425    Single,
426    /// Double precision (64-bit)
427    Double,
428    /// Extended precision (80-bit)
429    Extended,
430    /// Quadruple precision (128-bit)
431    Quadruple,
432}
433
434/// GPU configuration
435#[derive(Debug, Clone, Serialize, Deserialize)]
436pub struct GPUConfiguration {
437    /// GPU device ID
438    pub device_id: usize,
439    /// Block size for GPU kernels
440    pub block_size: usize,
441    /// Grid size for GPU kernels
442    pub grid_size: usize,
443    /// Memory allocation strategy
444    pub memory_strategy: GPUMemoryStrategy,
445    /// Use unified memory
446    pub use_unified_memory: bool,
447}
448
449/// GPU memory allocation strategies
450#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
451pub enum GPUMemoryStrategy {
452    /// Standard GPU memory
453    Standard,
454    /// Unified memory
455    Unified,
456    /// Memory pool
457    Pool,
458    /// Pinned memory
459    Pinned,
460}
461
462/// Distributed configuration
463#[derive(Debug, Clone, Serialize, Deserialize)]
464pub struct DistributedConfiguration {
465    /// Number of nodes
466    pub num_nodes: usize,
467    /// Communication backend
468    pub comm_backend: CommunicationBackend,
469    /// Load balancing strategy
470    pub load_balancing: LoadBalancingStrategy,
471    /// Fault tolerance enabled
472    pub fault_tolerance: bool,
473}
474
475/// Communication backends for distributed computing
476#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
477pub enum CommunicationBackend {
478    /// MPI (Message Passing Interface)
479    MPI,
480    /// TCP/IP networking
481    TCP,
482    /// InfiniBand
483    InfiniBand,
484    /// Shared memory
485    SharedMemory,
486}
487
488/// Load balancing strategies
489#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
490pub enum LoadBalancingStrategy {
491    /// Static load balancing
492    Static,
493    /// Dynamic load balancing
494    Dynamic,
495    /// Work stealing
496    WorkStealing,
497    /// Hierarchical balancing
498    Hierarchical,
499}
500
501impl AutoOptimizer {
502    /// Create a new AutoOptimizer
503    pub fn new(config: AutoOptimizerConfig) -> QuantRS2Result<Self> {
504        let platform_caps = Arc::new(PlatformCapabilities::detect());
505        let analysis_cache = HashMap::new();
506        let backend_profiles = Self::initialize_backend_profiles(&platform_caps)?;
507        let resource_monitor = ResourceMonitor {
508            cpu_history: Vec::new(),
509            memory_history: Vec::new(),
510            gpu_history: Vec::new(),
511            network_history: Vec::new(),
512            interval: config.monitoring_interval,
513        };
514
515        Ok(Self {
516            platform_caps,
517            config,
518            analysis_cache,
519            backend_profiles,
520            resource_monitor,
521        })
522    }
523
524    /// Initialize backend performance profiles
525    fn initialize_backend_profiles(
526        platform_caps: &PlatformCapabilities,
527    ) -> QuantRS2Result<HashMap<BackendType, PerformanceProfile>> {
528        let mut profiles = HashMap::new();
529
530        // CPU Single-threaded profile
531        profiles.insert(
532            BackendType::CPUSingle,
533            PerformanceProfile {
534                backend_type: BackendType::CPUSingle,
535                metrics: PerformanceMetrics {
536                    throughput: 1000.0,
537                    latency: 0.001,
538                    memory_efficiency: 0.8,
539                    cpu_utilization: 0.25,
540                    gpu_utilization: 0.0,
541                    energy_efficiency: 100.0,
542                },
543                resource_utilization: ResourceUtilization {
544                    cpu_usage: 25.0,
545                    memory_usage_gb: 1.0,
546                    gpu_usage: 0.0,
547                    gpu_memory_usage_gb: 0.0,
548                    network_usage_mbps: 0.0,
549                },
550                problem_size_limits: ProblemSizeLimits {
551                    max_qubits: 20,
552                    max_depth: 1000,
553                    max_gates: 10000,
554                    max_memory_gb: 4.0,
555                },
556                optimizations: vec![OptimizationRecommendation {
557                    recommendation_type: RecommendationType::BackendSwitch,
558                    description: "Consider CPU parallel for larger problems".to_string(),
559                    expected_improvement: 3.0,
560                    difficulty: 2,
561                    resource_cost: ResourceCost {
562                        memory_gb: 0.5,
563                        cpu_cores: 3,
564                        gpu_memory_gb: 0.0,
565                        setup_time: Duration::from_millis(10),
566                    },
567                }],
568            },
569        );
570
571        // CPU Parallel profile
572        profiles.insert(
573            BackendType::CPUParallel,
574            PerformanceProfile {
575                backend_type: BackendType::CPUParallel,
576                metrics: PerformanceMetrics {
577                    throughput: platform_caps.cpu.logical_cores as f64 * 800.0,
578                    latency: 0.002,
579                    memory_efficiency: 0.7,
580                    cpu_utilization: 0.8,
581                    gpu_utilization: 0.0,
582                    energy_efficiency: 80.0,
583                },
584                resource_utilization: ResourceUtilization {
585                    cpu_usage: 80.0,
586                    memory_usage_gb: 2.0,
587                    gpu_usage: 0.0,
588                    gpu_memory_usage_gb: 0.0,
589                    network_usage_mbps: 0.0,
590                },
591                problem_size_limits: ProblemSizeLimits {
592                    max_qubits: 25,
593                    max_depth: 2000,
594                    max_gates: 50000,
595                    max_memory_gb: 16.0,
596                },
597                optimizations: vec![OptimizationRecommendation {
598                    recommendation_type: RecommendationType::ParallelizationTuning,
599                    description: "Optimize thread count for problem size".to_string(),
600                    expected_improvement: 1.5,
601                    difficulty: 3,
602                    resource_cost: ResourceCost {
603                        memory_gb: 1.0,
604                        cpu_cores: 0,
605                        gpu_memory_gb: 0.0,
606                        setup_time: Duration::from_millis(50),
607                    },
608                }],
609            },
610        );
611
612        // GPU profile (if available)
613        if platform_caps.has_gpu() {
614            profiles.insert(
615                BackendType::GPU,
616                PerformanceProfile {
617                    backend_type: BackendType::GPU,
618                    metrics: PerformanceMetrics {
619                        throughput: 50000.0,
620                        latency: 0.005,
621                        memory_efficiency: 0.9,
622                        cpu_utilization: 0.2,
623                        gpu_utilization: 0.8,
624                        energy_efficiency: 200.0,
625                    },
626                    resource_utilization: ResourceUtilization {
627                        cpu_usage: 20.0,
628                        memory_usage_gb: 2.0,
629                        gpu_usage: 80.0,
630                        gpu_memory_usage_gb: 4.0,
631                        network_usage_mbps: 0.0,
632                    },
633                    problem_size_limits: ProblemSizeLimits {
634                        max_qubits: 30,
635                        max_depth: 5000,
636                        max_gates: 100_000,
637                        max_memory_gb: 8.0,
638                    },
639                    optimizations: vec![OptimizationRecommendation {
640                        recommendation_type: RecommendationType::HardwareOptimization,
641                        description: "Optimize GPU kernel parameters".to_string(),
642                        expected_improvement: 2.0,
643                        difficulty: 7,
644                        resource_cost: ResourceCost {
645                            memory_gb: 1.0,
646                            cpu_cores: 0,
647                            gpu_memory_gb: 2.0,
648                            setup_time: Duration::from_millis(100),
649                        },
650                    }],
651                },
652            );
653        }
654
655        Ok(profiles)
656    }
657
658    /// Analyze problem characteristics
659    pub fn analyze_problem(
660        &mut self,
661        circuit_gates: &[GateType],
662        num_qubits: usize,
663        problem_type: ProblemType,
664    ) -> QuantRS2Result<ProblemAnalysis> {
665        // Create cache key
666        let cache_key = format!("{:?}-{}-{}", problem_type, num_qubits, circuit_gates.len());
667
668        if self.config.enable_caching {
669            if let Some(cached) = self.analysis_cache.get(&cache_key) {
670                return Ok(cached.clone());
671            }
672        }
673
674        let circuit_depth = Self::calculate_circuit_depth(circuit_gates);
675        let gate_composition = Self::analyze_gate_composition(circuit_gates);
676        let entanglement_analysis = Self::analyze_entanglement(circuit_gates, num_qubits);
677        let memory_estimate_gb = Self::estimate_memory_requirements(num_qubits, circuit_depth);
678        let complexity_estimate = Self::estimate_complexity(circuit_gates, num_qubits);
679        let parallelization_potential =
680            Self::analyze_parallelization_potential(circuit_gates, num_qubits, &gate_composition);
681        let resource_requirements = Self::estimate_resource_requirements(
682            num_qubits,
683            circuit_depth,
684            &complexity_estimate,
685            &parallelization_potential,
686        );
687
688        let analysis = ProblemAnalysis {
689            num_qubits,
690            circuit_depth,
691            gate_composition,
692            entanglement_analysis,
693            memory_estimate_gb,
694            complexity_estimate,
695            problem_type,
696            parallelization_potential,
697            resource_requirements,
698        };
699
700        if self.config.enable_caching {
701            self.analysis_cache.insert(cache_key, analysis.clone());
702        }
703
704        Ok(analysis)
705    }
706
707    /// Select optimal backend based on problem analysis
708    pub fn select_backend(&self, analysis: &ProblemAnalysis) -> QuantRS2Result<BackendSelection> {
709        let mut scores = HashMap::new();
710        let mut reasoning = Vec::new();
711
712        // Score each available backend
713        for (backend_type, profile) in &self.backend_profiles {
714            let score = self.score_backend(analysis, profile)?;
715            scores.insert(*backend_type, score);
716
717            // Add reasoning for high-scoring backends
718            if score > 0.7 {
719                reasoning.push(format!(
720                    "{:?} backend scores {:.2} due to good fit for problem characteristics",
721                    backend_type, score
722                ));
723            }
724        }
725
726        // Find best backend
727        let (best_backend, best_score) = scores
728            .iter()
729            .max_by(|a, b| a.1.partial_cmp(b.1).unwrap())
730            .ok_or_else(|| QuantRS2Error::InvalidInput("No backends available".to_string()))?;
731
732        // Generate alternatives
733        let mut alternatives: Vec<(BackendType, f64)> = scores
734            .iter()
735            .filter(|(backend, _)| *backend != best_backend)
736            .map(|(backend, score)| (*backend, *score))
737            .collect();
738        alternatives.sort_by(|a, b| b.1.partial_cmp(&a.1).unwrap());
739        alternatives.truncate(3); // Top 3 alternatives
740
741        // Generate configuration
742        let configuration = self.generate_backend_configuration(analysis, *best_backend)?;
743
744        // Get expected performance
745        let expected_performance = self.backend_profiles[best_backend].metrics.clone();
746
747        // Add selection reasoning
748        reasoning.push(format!(
749            "Selected {:?} backend with confidence {:.2}",
750            best_backend, best_score
751        ));
752
753        if analysis.num_qubits >= self.config.gpu_threshold_qubits && self.platform_caps.has_gpu() {
754            reasoning.push(
755                "Problem size exceeds GPU threshold, GPU acceleration recommended".to_string(),
756            );
757        }
758
759        if analysis.parallelization_potential.gate_parallelism > 0.5 {
760            reasoning.push("High gate parallelism potential detected".to_string());
761        }
762
763        Ok(BackendSelection {
764            backend_type: *best_backend,
765            confidence: *best_score,
766            reasoning,
767            expected_performance,
768            configuration,
769            alternatives,
770        })
771    }
772
773    /// Score a backend for the given problem
774    fn score_backend(
775        &self,
776        analysis: &ProblemAnalysis,
777        profile: &PerformanceProfile,
778    ) -> QuantRS2Result<f64> {
779        let mut score = 0.0;
780        let mut weight_sum = 0.0;
781
782        // Problem size compatibility
783        let size_weight = 0.3;
784        let size_score = if analysis.num_qubits <= profile.problem_size_limits.max_qubits {
785            1.0 - (analysis.num_qubits as f64 / profile.problem_size_limits.max_qubits as f64) * 0.5
786        } else {
787            0.0 // Cannot handle problem size
788        };
789        score += size_score * size_weight;
790        weight_sum += size_weight;
791
792        // Performance requirements
793        let perf_weight = 0.25;
794        let perf_score = match self.config.performance_bias {
795            bias if bias > 0.7 => profile.metrics.throughput / 10000.0, // Prefer high throughput
796            bias if bias < 0.3 => 1.0 / (profile.metrics.latency * 1000.0), // Prefer low latency
797            _ => {
798                (profile.metrics.throughput / 10000.0 + 1.0 / (profile.metrics.latency * 1000.0))
799                    / 2.0
800            }
801        };
802        score += perf_score.min(1.0) * perf_weight;
803        weight_sum += perf_weight;
804
805        // Resource constraints
806        let resource_weight = 0.2;
807        let resource_score = if analysis.memory_estimate_gb <= self.config.max_memory_gb {
808            1.0 - (analysis.memory_estimate_gb / self.config.max_memory_gb) * 0.3
809        } else {
810            0.0 // Exceeds memory limits
811        };
812        score += resource_score * resource_weight;
813        weight_sum += resource_weight;
814
815        // Backend-specific bonuses
816        let bonus_weight = 0.15;
817        let bonus_score = match profile.backend_type {
818            BackendType::GPU
819                if self.config.enable_gpu
820                    && analysis.num_qubits >= self.config.gpu_threshold_qubits =>
821            {
822                1.0
823            }
824            BackendType::CPUParallel
825                if analysis.parallelization_potential.gate_parallelism > 0.5 =>
826            {
827                0.8
828            }
829            BackendType::Distributed
830                if self.config.enable_distributed
831                    && analysis.num_qubits >= self.config.distributed_threshold_qubits =>
832            {
833                0.9
834            }
835            _ => 0.5,
836        };
837        score += bonus_score * bonus_weight;
838        weight_sum += bonus_weight;
839
840        // Parallelization potential alignment
841        let parallel_weight = 0.1;
842        let parallel_score = match profile.backend_type {
843            BackendType::GPU => analysis.parallelization_potential.gpu_potential,
844            BackendType::CPUParallel => analysis.parallelization_potential.gate_parallelism,
845            BackendType::Distributed => analysis.parallelization_potential.distributed_potential,
846            _ => 0.5,
847        };
848        score += parallel_score * parallel_weight;
849        weight_sum += parallel_weight;
850
851        // Normalize score
852        if weight_sum > 0.0 {
853            score /= weight_sum;
854        }
855
856        Ok(score.max(0.0).min(1.0))
857    }
858
859    /// Generate backend configuration
860    fn generate_backend_configuration(
861        &self,
862        analysis: &ProblemAnalysis,
863        backend_type: BackendType,
864    ) -> QuantRS2Result<BackendConfiguration> {
865        let num_threads = match backend_type {
866            BackendType::CPUParallel | BackendType::Hybrid => {
867                (self.platform_caps.cpu.logical_cores as f64 * 0.8).round() as usize
868            }
869            _ => 1,
870        };
871
872        let batch_size = match backend_type {
873            BackendType::GPU => 1024,
874            BackendType::CPUParallel => 64,
875            _ => 1,
876        };
877
878        let memory_strategy = match backend_type {
879            BackendType::GPU => MemoryStrategy::Pool,
880            BackendType::Distributed => MemoryStrategy::Shared,
881            _ => MemoryStrategy::Heap,
882        };
883
884        let precision_settings = PrecisionSettings {
885            float_precision: if analysis.problem_type == ProblemType::QEC {
886                FloatPrecision::Quadruple
887            } else {
888                FloatPrecision::Double
889            },
890            tolerance: 1e-12,
891            adaptive_precision: true,
892        };
893
894        let gpu_config = if backend_type == BackendType::GPU || backend_type == BackendType::Hybrid
895        {
896            Some(GPUConfiguration {
897                device_id: 0,
898                block_size: 256,
899                grid_size: (analysis.num_qubits * analysis.num_qubits + 255) / 256,
900                memory_strategy: GPUMemoryStrategy::Pool,
901                use_unified_memory: false, // Default to false, can be overridden based on GPU capabilities
902            })
903        } else {
904            None
905        };
906
907        let distributed_config = if backend_type == BackendType::Distributed {
908            Some(DistributedConfiguration {
909                num_nodes: 4,
910                comm_backend: CommunicationBackend::TCP,
911                load_balancing: LoadBalancingStrategy::Dynamic,
912                fault_tolerance: true,
913            })
914        } else {
915            None
916        };
917
918        Ok(BackendConfiguration {
919            num_threads,
920            batch_size,
921            memory_strategy,
922            precision_settings,
923            gpu_config,
924            distributed_config,
925        })
926    }
927
928    /// Calculate circuit depth
929    fn calculate_circuit_depth(gates: &[GateType]) -> usize {
930        // Simplified depth calculation - in reality would need dependency analysis
931        (gates.len() as f64 * 0.7).round() as usize
932    }
933
934    /// Analyze gate composition
935    fn analyze_gate_composition(gates: &[GateType]) -> GateComposition {
936        let mut gate_types = HashMap::new();
937        let mut single_qubit_gates = 0;
938        let mut two_qubit_gates = 0;
939        let mut multi_qubit_gates = 0;
940        let mut parameterized_gates = 0;
941
942        for gate in gates {
943            let gate_name = format!("{:?}", gate);
944            *gate_types.entry(gate_name).or_insert(0) += 1;
945
946            match gate {
947                GateType::H
948                | GateType::X
949                | GateType::Y
950                | GateType::Z
951                | GateType::S
952                | GateType::T
953                | GateType::Rx(_)
954                | GateType::Ry(_)
955                | GateType::Rz(_) => {
956                    single_qubit_gates += 1;
957                    if matches!(gate, GateType::Rx(_) | GateType::Ry(_) | GateType::Rz(_)) {
958                        parameterized_gates += 1;
959                    }
960                }
961                GateType::CNOT | GateType::CZ | GateType::SWAP => {
962                    two_qubit_gates += 1;
963                }
964                _ => {
965                    multi_qubit_gates += 1;
966                }
967            }
968        }
969
970        let total_gates = gates.len();
971        let simd_friendly_gates = single_qubit_gates + two_qubit_gates;
972        let simd_friendly_percentage = if total_gates > 0 {
973            simd_friendly_gates as f64 / total_gates as f64
974        } else {
975            0.0
976        };
977
978        GateComposition {
979            total_gates,
980            single_qubit_gates,
981            two_qubit_gates,
982            multi_qubit_gates,
983            gate_types,
984            parameterized_gates,
985            simd_friendly_percentage,
986        }
987    }
988
989    /// Analyze entanglement properties
990    fn analyze_entanglement(gates: &[GateType], num_qubits: usize) -> EntanglementAnalysis {
991        let mut entangling_gates = 0;
992        let mut connectivity_set = HashSet::new();
993
994        for gate in gates {
995            match gate {
996                GateType::CNOT | GateType::CZ | GateType::SWAP => {
997                    entangling_gates += 1;
998                    // Would need actual qubit indices for proper connectivity analysis
999                    connectivity_set.insert((0, 1)); // Simplified
1000                }
1001                _ => {}
1002            }
1003        }
1004
1005        let max_entanglement_depth = (entangling_gates as f64).log2().ceil() as usize;
1006        let connectivity_ratio =
1007            connectivity_set.len() as f64 / (num_qubits * (num_qubits - 1) / 2) as f64;
1008        let separable_subsystems = if entangling_gates == 0 { num_qubits } else { 1 };
1009        let entanglement_entropy = if entangling_gates > 0 {
1010            (num_qubits as f64).log2()
1011        } else {
1012            0.0
1013        };
1014
1015        EntanglementAnalysis {
1016            max_entanglement_depth,
1017            connectivity_ratio,
1018            separable_subsystems,
1019            entanglement_entropy,
1020        }
1021    }
1022
1023    /// Estimate memory requirements
1024    fn estimate_memory_requirements(num_qubits: usize, circuit_depth: usize) -> f64 {
1025        let state_vector_size = 2_usize.pow(num_qubits as u32);
1026        let complex_size = 16; // bytes per Complex64
1027        let base_memory = (state_vector_size * complex_size) as f64 / (1024.0 * 1024.0 * 1024.0);
1028        let overhead_factor = 1.5; // Account for intermediate calculations
1029        let depth_factor = 1.0 + (circuit_depth as f64 * 0.01);
1030
1031        base_memory * overhead_factor * depth_factor
1032    }
1033
1034    /// Estimate computational complexity
1035    fn estimate_complexity(gates: &[GateType], num_qubits: usize) -> ComplexityEstimate {
1036        let operation_count = gates.len() as u64 * 2_u64.pow(num_qubits as u32);
1037
1038        let time_complexity = if num_qubits <= 10 {
1039            ComplexityClass::Linear
1040        } else if num_qubits <= 20 {
1041            ComplexityClass::Quadratic
1042        } else {
1043            ComplexityClass::Exponential
1044        };
1045
1046        let space_complexity = if num_qubits <= 25 {
1047            ComplexityClass::Exponential
1048        } else {
1049            ComplexityClass::DoubleExponential
1050        };
1051
1052        let memory_pattern = if gates.len() > 1000 {
1053            MemoryPattern::Blocked
1054        } else {
1055            MemoryPattern::Sequential
1056        };
1057
1058        let parallelization_factor = if num_qubits >= 12 {
1059            (num_qubits as f64 / 4.0).min(8.0)
1060        } else {
1061            1.0
1062        };
1063
1064        ComplexityEstimate {
1065            time_complexity,
1066            space_complexity,
1067            operation_count,
1068            memory_pattern,
1069            parallelization_factor,
1070        }
1071    }
1072
1073    /// Analyze parallelization potential
1074    fn analyze_parallelization_potential(
1075        gates: &[GateType],
1076        num_qubits: usize,
1077        gate_composition: &GateComposition,
1078    ) -> ParallelizationPotential {
1079        let gate_parallelism = if gate_composition.single_qubit_gates > 0 {
1080            gate_composition.single_qubit_gates as f64 / gate_composition.total_gates as f64
1081        } else {
1082            0.0
1083        };
1084
1085        let state_parallelism = if num_qubits >= 8 {
1086            (num_qubits as f64 - 7.0) / 10.0
1087        } else {
1088            0.1
1089        };
1090
1091        let batch_potential = if gate_composition.total_gates > 100 {
1092            0.8
1093        } else {
1094            0.3
1095        };
1096
1097        let simd_potential = gate_composition.simd_friendly_percentage;
1098
1099        let gpu_potential = if num_qubits >= 12 && gate_composition.total_gates > 500 {
1100            0.9
1101        } else {
1102            0.2
1103        };
1104
1105        let distributed_potential = if num_qubits >= 20 { 0.8 } else { 0.1 };
1106
1107        ParallelizationPotential {
1108            gate_parallelism,
1109            state_parallelism,
1110            batch_potential,
1111            simd_potential,
1112            gpu_potential,
1113            distributed_potential,
1114        }
1115    }
1116
1117    /// Estimate resource requirements
1118    fn estimate_resource_requirements(
1119        num_qubits: usize,
1120        circuit_depth: usize,
1121        complexity: &ComplexityEstimate,
1122        parallelization: &ParallelizationPotential,
1123    ) -> ResourceRequirements {
1124        let memory_gb = Self::estimate_memory_requirements(num_qubits, circuit_depth);
1125
1126        let cpu_cores = if parallelization.gate_parallelism > 0.5 {
1127            (num_qubits / 2).max(2).min(16)
1128        } else {
1129            1
1130        };
1131
1132        let gpu_memory_gb = if parallelization.gpu_potential > 0.5 {
1133            memory_gb * 1.2
1134        } else {
1135            0.0
1136        };
1137
1138        let network_bandwidth_mbps = if parallelization.distributed_potential > 0.5 {
1139            100.0 * num_qubits as f64
1140        } else {
1141            0.0
1142        };
1143
1144        let storage_gb = memory_gb * 0.1; // For checkpointing and results
1145
1146        let base_time_ms = match complexity.time_complexity {
1147            ComplexityClass::Linear => circuit_depth as f64 * 0.1,
1148            ComplexityClass::Quadratic => circuit_depth as f64 * circuit_depth as f64 * 0.001,
1149            ComplexityClass::Exponential => 2.0_f64.powf(num_qubits as f64 * 0.5),
1150            _ => 1000.0,
1151        };
1152
1153        let estimated_time =
1154            Duration::from_millis((base_time_ms / complexity.parallelization_factor) as u64);
1155
1156        ResourceRequirements {
1157            memory_gb,
1158            cpu_cores,
1159            gpu_memory_gb,
1160            network_bandwidth_mbps,
1161            storage_gb,
1162            estimated_time,
1163        }
1164    }
1165
1166    /// Get optimization recommendations
1167    pub fn get_recommendations(
1168        &self,
1169        analysis: &ProblemAnalysis,
1170        selection: &BackendSelection,
1171    ) -> Vec<OptimizationRecommendation> {
1172        let mut recommendations = Vec::new();
1173
1174        // Memory optimization recommendations
1175        if analysis.memory_estimate_gb > self.config.max_memory_gb * 0.8 {
1176            recommendations.push(OptimizationRecommendation {
1177                recommendation_type: RecommendationType::MemoryOptimization,
1178                description:
1179                    "Consider using memory-efficient state representation or chunked computation"
1180                        .to_string(),
1181                expected_improvement: 0.6,
1182                difficulty: 6,
1183                resource_cost: ResourceCost {
1184                    memory_gb: -analysis.memory_estimate_gb * 0.3,
1185                    cpu_cores: 1,
1186                    gpu_memory_gb: 0.0,
1187                    setup_time: Duration::from_millis(200),
1188                },
1189            });
1190        }
1191
1192        // Backend switching recommendations
1193        if selection.confidence < 0.8 {
1194            for (alt_backend, score) in &selection.alternatives {
1195                if *score > selection.confidence {
1196                    recommendations.push(OptimizationRecommendation {
1197                        recommendation_type: RecommendationType::BackendSwitch,
1198                        description: format!(
1199                            "Consider switching to {:?} backend for better performance",
1200                            alt_backend
1201                        ),
1202                        expected_improvement: score - selection.confidence,
1203                        difficulty: 3,
1204                        resource_cost: ResourceCost {
1205                            memory_gb: 0.5,
1206                            cpu_cores: 0,
1207                            gpu_memory_gb: if *alt_backend == BackendType::GPU {
1208                                2.0
1209                            } else {
1210                                0.0
1211                            },
1212                            setup_time: Duration::from_millis(100),
1213                        },
1214                    });
1215                }
1216            }
1217        }
1218
1219        // Parallelization recommendations
1220        if analysis.parallelization_potential.gate_parallelism > 0.7
1221            && selection.backend_type == BackendType::CPUSingle
1222        {
1223            recommendations.push(OptimizationRecommendation {
1224                recommendation_type: RecommendationType::ParallelizationTuning,
1225                description:
1226                    "High parallelization potential detected - consider parallel CPU backend"
1227                        .to_string(),
1228                expected_improvement: analysis.parallelization_potential.gate_parallelism,
1229                difficulty: 4,
1230                resource_cost: ResourceCost {
1231                    memory_gb: 1.0,
1232                    cpu_cores: self.platform_caps.cpu.logical_cores - 1,
1233                    gpu_memory_gb: 0.0,
1234                    setup_time: Duration::from_millis(50),
1235                },
1236            });
1237        }
1238
1239        // GPU recommendations
1240        if analysis.parallelization_potential.gpu_potential > 0.8
1241            && selection.backend_type != BackendType::GPU
1242            && self.platform_caps.has_gpu()
1243        {
1244            recommendations.push(OptimizationRecommendation {
1245                recommendation_type: RecommendationType::HardwareOptimization,
1246                description: "Problem shows high GPU acceleration potential".to_string(),
1247                expected_improvement: analysis.parallelization_potential.gpu_potential,
1248                difficulty: 7,
1249                resource_cost: ResourceCost {
1250                    memory_gb: 1.0,
1251                    cpu_cores: 0,
1252                    gpu_memory_gb: analysis.memory_estimate_gb,
1253                    setup_time: Duration::from_millis(300),
1254                },
1255            });
1256        }
1257
1258        // Algorithm-specific recommendations
1259        match analysis.problem_type {
1260            ProblemType::VQE => {
1261                recommendations.push(OptimizationRecommendation {
1262                    recommendation_type: RecommendationType::AlgorithmOptimization,
1263                    description: "Consider using gradient-free optimization methods for VQE"
1264                        .to_string(),
1265                    expected_improvement: 0.3,
1266                    difficulty: 5,
1267                    resource_cost: ResourceCost {
1268                        memory_gb: 0.5,
1269                        cpu_cores: 0,
1270                        gpu_memory_gb: 0.0,
1271                        setup_time: Duration::from_millis(100),
1272                    },
1273                });
1274            }
1275            ProblemType::QAOA => {
1276                recommendations.push(OptimizationRecommendation {
1277                    recommendation_type: RecommendationType::AlgorithmOptimization,
1278                    description: "Consider using warm-start initialization for QAOA parameters"
1279                        .to_string(),
1280                    expected_improvement: 0.4,
1281                    difficulty: 4,
1282                    resource_cost: ResourceCost {
1283                        memory_gb: 0.2,
1284                        cpu_cores: 0,
1285                        gpu_memory_gb: 0.0,
1286                        setup_time: Duration::from_millis(50),
1287                    },
1288                });
1289            }
1290            _ => {}
1291        }
1292
1293        // Precision recommendations
1294        if analysis.problem_type == ProblemType::Simulation
1295            && selection.configuration.precision_settings.float_precision == FloatPrecision::Double
1296        {
1297            recommendations.push(OptimizationRecommendation {
1298                recommendation_type: RecommendationType::PrecisionAdjustment,
1299                description: "Consider single precision for simulation if acceptable accuracy"
1300                    .to_string(),
1301                expected_improvement: 0.5,
1302                difficulty: 2,
1303                resource_cost: ResourceCost {
1304                    memory_gb: -analysis.memory_estimate_gb * 0.5,
1305                    cpu_cores: 0,
1306                    gpu_memory_gb: 0.0,
1307                    setup_time: Duration::from_millis(10),
1308                },
1309            });
1310        }
1311
1312        recommendations
1313    }
1314
1315    /// Monitor and update backend selection dynamically
1316    pub fn monitor_and_update(
1317        &mut self,
1318        current_selection: &BackendSelection,
1319        current_performance: &PerformanceMetrics,
1320    ) -> QuantRS2Result<Option<BackendSelection>> {
1321        if !self.config.enable_auto_switching {
1322            return Ok(None);
1323        }
1324
1325        // Update resource monitoring
1326        self.update_resource_monitoring(current_performance)?;
1327
1328        // Check if current backend is underperforming
1329        let expected_performance = &current_selection.expected_performance;
1330        let performance_ratio = current_performance.throughput / expected_performance.throughput;
1331
1332        if performance_ratio < 0.7 {
1333            // Performance is significantly below expectations
1334            // Consider switching to a different backend
1335            // This would require re-analysis of the current problem
1336            // For now, return None indicating no change
1337            return Ok(None);
1338        }
1339
1340        // Check resource constraints
1341        if current_performance.memory_efficiency < 0.5 {
1342            // Memory efficiency is poor, might need optimization
1343            return Ok(None);
1344        }
1345
1346        Ok(None)
1347    }
1348
1349    /// Update resource monitoring
1350    fn update_resource_monitoring(
1351        &mut self,
1352        current_performance: &PerformanceMetrics,
1353    ) -> QuantRS2Result<()> {
1354        self.resource_monitor
1355            .cpu_history
1356            .push(current_performance.cpu_utilization);
1357        self.resource_monitor
1358            .memory_history
1359            .push(current_performance.memory_efficiency);
1360        self.resource_monitor
1361            .gpu_history
1362            .push(current_performance.gpu_utilization);
1363
1364        // Keep only recent history
1365        let max_history = 100;
1366        if self.resource_monitor.cpu_history.len() > max_history {
1367            self.resource_monitor.cpu_history.remove(0);
1368        }
1369        if self.resource_monitor.memory_history.len() > max_history {
1370            self.resource_monitor.memory_history.remove(0);
1371        }
1372        if self.resource_monitor.gpu_history.len() > max_history {
1373            self.resource_monitor.gpu_history.remove(0);
1374        }
1375
1376        Ok(())
1377    }
1378}
1379
1380#[cfg(test)]
1381mod tests {
1382    use super::*;
1383
1384    #[test]
1385    fn test_auto_optimizer_creation() {
1386        let config = AutoOptimizerConfig::default();
1387        let optimizer = AutoOptimizer::new(config);
1388        assert!(optimizer.is_ok());
1389    }
1390
1391    #[test]
1392    fn test_problem_analysis() {
1393        let config = AutoOptimizerConfig::default();
1394        let mut optimizer = AutoOptimizer::new(config).unwrap();
1395
1396        let gates = vec![
1397            GateType::H,
1398            GateType::CNOT,
1399            GateType::Rz("0.5".to_string()),
1400            GateType::X,
1401        ];
1402
1403        let analysis = optimizer.analyze_problem(&gates, 5, ProblemType::Simulation);
1404        assert!(analysis.is_ok());
1405
1406        let analysis = analysis.unwrap();
1407        assert_eq!(analysis.num_qubits, 5);
1408        assert_eq!(analysis.gate_composition.total_gates, 4);
1409        assert_eq!(analysis.problem_type, ProblemType::Simulation);
1410    }
1411
1412    #[test]
1413    fn test_backend_selection() {
1414        let config = AutoOptimizerConfig::default();
1415        let optimizer = AutoOptimizer::new(config).unwrap();
1416
1417        let analysis = ProblemAnalysis {
1418            num_qubits: 10,
1419            circuit_depth: 50,
1420            gate_composition: GateComposition {
1421                total_gates: 100,
1422                single_qubit_gates: 60,
1423                two_qubit_gates: 30,
1424                multi_qubit_gates: 10,
1425                gate_types: HashMap::new(),
1426                parameterized_gates: 20,
1427                simd_friendly_percentage: 0.9,
1428            },
1429            entanglement_analysis: EntanglementAnalysis {
1430                max_entanglement_depth: 5,
1431                connectivity_ratio: 0.3,
1432                separable_subsystems: 2,
1433                entanglement_entropy: 3.0,
1434            },
1435            memory_estimate_gb: 2.0,
1436            complexity_estimate: ComplexityEstimate {
1437                time_complexity: ComplexityClass::Quadratic,
1438                space_complexity: ComplexityClass::Exponential,
1439                operation_count: 1000000,
1440                memory_pattern: MemoryPattern::Sequential,
1441                parallelization_factor: 4.0,
1442            },
1443            problem_type: ProblemType::Simulation,
1444            parallelization_potential: ParallelizationPotential {
1445                gate_parallelism: 0.8,
1446                state_parallelism: 0.6,
1447                batch_potential: 0.7,
1448                simd_potential: 0.9,
1449                gpu_potential: 0.5,
1450                distributed_potential: 0.2,
1451            },
1452            resource_requirements: ResourceRequirements {
1453                memory_gb: 2.0,
1454                cpu_cores: 4,
1455                gpu_memory_gb: 0.0,
1456                network_bandwidth_mbps: 0.0,
1457                storage_gb: 0.2,
1458                estimated_time: Duration::from_secs(60),
1459            },
1460        };
1461
1462        let selection = optimizer.select_backend(&analysis);
1463        assert!(selection.is_ok());
1464
1465        let selection = selection.unwrap();
1466        assert!(selection.confidence > 0.0);
1467        assert!(!selection.reasoning.is_empty());
1468    }
1469
1470    #[test]
1471    fn test_recommendations() {
1472        let config = AutoOptimizerConfig::default();
1473        let optimizer = AutoOptimizer::new(config).unwrap();
1474
1475        let analysis = ProblemAnalysis {
1476            num_qubits: 15,
1477            circuit_depth: 100,
1478            gate_composition: GateComposition {
1479                total_gates: 200,
1480                single_qubit_gates: 120,
1481                two_qubit_gates: 60,
1482                multi_qubit_gates: 20,
1483                gate_types: HashMap::new(),
1484                parameterized_gates: 40,
1485                simd_friendly_percentage: 0.85,
1486            },
1487            entanglement_analysis: EntanglementAnalysis {
1488                max_entanglement_depth: 8,
1489                connectivity_ratio: 0.4,
1490                separable_subsystems: 1,
1491                entanglement_entropy: 4.0,
1492            },
1493            memory_estimate_gb: 8.0,
1494            complexity_estimate: ComplexityEstimate {
1495                time_complexity: ComplexityClass::Exponential,
1496                space_complexity: ComplexityClass::Exponential,
1497                operation_count: 10000000,
1498                memory_pattern: MemoryPattern::Blocked,
1499                parallelization_factor: 6.0,
1500            },
1501            problem_type: ProblemType::VQE,
1502            parallelization_potential: ParallelizationPotential {
1503                gate_parallelism: 0.85,
1504                state_parallelism: 0.7,
1505                batch_potential: 0.8,
1506                simd_potential: 0.85,
1507                gpu_potential: 0.9,
1508                distributed_potential: 0.3,
1509            },
1510            resource_requirements: ResourceRequirements {
1511                memory_gb: 8.0,
1512                cpu_cores: 6,
1513                gpu_memory_gb: 4.0,
1514                network_bandwidth_mbps: 0.0,
1515                storage_gb: 0.8,
1516                estimated_time: Duration::from_secs(300),
1517            },
1518        };
1519
1520        let selection = optimizer.select_backend(&analysis).unwrap();
1521        let recommendations = optimizer.get_recommendations(&analysis, &selection);
1522
1523        assert!(!recommendations.is_empty());
1524
1525        // Should have recommendations for high-performance problem
1526        let has_memory_rec = recommendations
1527            .iter()
1528            .any(|r| r.recommendation_type == RecommendationType::MemoryOptimization);
1529
1530        assert!(has_memory_rec || recommendations.len() > 0);
1531    }
1532}