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_type:?} backend scores {score:.2} due to good fit for problem characteristics"
721                ));
722            }
723        }
724
725        // Find best backend
726        let (best_backend, best_score) = scores
727            .iter()
728            .max_by(|a, b| a.1.partial_cmp(b.1).unwrap_or(std::cmp::Ordering::Equal))
729            .ok_or_else(|| QuantRS2Error::InvalidInput("No backends available".to_string()))?;
730
731        // Generate alternatives
732        let mut alternatives: Vec<(BackendType, f64)> = scores
733            .iter()
734            .filter(|(backend, _)| *backend != best_backend)
735            .map(|(backend, score)| (*backend, *score))
736            .collect();
737        alternatives.sort_by(|a, b| b.1.partial_cmp(&a.1).unwrap_or(std::cmp::Ordering::Equal));
738        alternatives.truncate(3); // Top 3 alternatives
739
740        // Generate configuration
741        let configuration = self.generate_backend_configuration(analysis, *best_backend)?;
742
743        // Get expected performance
744        let expected_performance = self.backend_profiles[best_backend].metrics.clone();
745
746        // Add selection reasoning
747        reasoning.push(format!(
748            "Selected {best_backend:?} backend with confidence {best_score:.2}"
749        ));
750
751        if analysis.num_qubits >= self.config.gpu_threshold_qubits && self.platform_caps.has_gpu() {
752            reasoning.push(
753                "Problem size exceeds GPU threshold, GPU acceleration recommended".to_string(),
754            );
755        }
756
757        if analysis.parallelization_potential.gate_parallelism > 0.5 {
758            reasoning.push("High gate parallelism potential detected".to_string());
759        }
760
761        Ok(BackendSelection {
762            backend_type: *best_backend,
763            confidence: *best_score,
764            reasoning,
765            expected_performance,
766            configuration,
767            alternatives,
768        })
769    }
770
771    /// Score a backend for the given problem
772    fn score_backend(
773        &self,
774        analysis: &ProblemAnalysis,
775        profile: &PerformanceProfile,
776    ) -> QuantRS2Result<f64> {
777        let mut score = 0.0;
778        let mut weight_sum = 0.0;
779
780        // Problem size compatibility
781        let size_weight = 0.3;
782        let size_score = if analysis.num_qubits <= profile.problem_size_limits.max_qubits {
783            (analysis.num_qubits as f64 / profile.problem_size_limits.max_qubits as f64)
784                .mul_add(-0.5, 1.0)
785        } else {
786            0.0 // Cannot handle problem size
787        };
788        score += size_score * size_weight;
789        weight_sum += size_weight;
790
791        // Performance requirements
792        let perf_weight = 0.25;
793        let perf_score = match self.config.performance_bias {
794            bias if bias > 0.7 => profile.metrics.throughput / 10000.0, // Prefer high throughput
795            bias if bias < 0.3 => 1.0 / (profile.metrics.latency * 1000.0), // Prefer low latency
796            _ => f64::midpoint(
797                profile.metrics.throughput / 10000.0,
798                1.0 / (profile.metrics.latency * 1000.0),
799            ),
800        };
801        score += perf_score.min(1.0) * perf_weight;
802        weight_sum += perf_weight;
803
804        // Resource constraints
805        let resource_weight = 0.2;
806        let resource_score = if analysis.memory_estimate_gb <= self.config.max_memory_gb {
807            (analysis.memory_estimate_gb / self.config.max_memory_gb).mul_add(-0.3, 1.0)
808        } else {
809            0.0 // Exceeds memory limits
810        };
811        score += resource_score * resource_weight;
812        weight_sum += resource_weight;
813
814        // Backend-specific bonuses
815        let bonus_weight = 0.15;
816        let bonus_score = match profile.backend_type {
817            BackendType::GPU
818                if self.config.enable_gpu
819                    && analysis.num_qubits >= self.config.gpu_threshold_qubits =>
820            {
821                1.0
822            }
823            BackendType::CPUParallel
824                if analysis.parallelization_potential.gate_parallelism > 0.5 =>
825            {
826                0.8
827            }
828            BackendType::Distributed
829                if self.config.enable_distributed
830                    && analysis.num_qubits >= self.config.distributed_threshold_qubits =>
831            {
832                0.9
833            }
834            _ => 0.5,
835        };
836        score += bonus_score * bonus_weight;
837        weight_sum += bonus_weight;
838
839        // Parallelization potential alignment
840        let parallel_weight = 0.1;
841        let parallel_score = match profile.backend_type {
842            BackendType::GPU => analysis.parallelization_potential.gpu_potential,
843            BackendType::CPUParallel => analysis.parallelization_potential.gate_parallelism,
844            BackendType::Distributed => analysis.parallelization_potential.distributed_potential,
845            _ => 0.5,
846        };
847        score += parallel_score * parallel_weight;
848        weight_sum += parallel_weight;
849
850        // Normalize score
851        if weight_sum > 0.0 {
852            score /= weight_sum;
853        }
854
855        Ok(score.clamp(0.0, 1.0))
856    }
857
858    /// Generate backend configuration
859    fn generate_backend_configuration(
860        &self,
861        analysis: &ProblemAnalysis,
862        backend_type: BackendType,
863    ) -> QuantRS2Result<BackendConfiguration> {
864        let num_threads = match backend_type {
865            BackendType::CPUParallel | BackendType::Hybrid => {
866                (self.platform_caps.cpu.logical_cores as f64 * 0.8).round() as usize
867            }
868            _ => 1,
869        };
870
871        let batch_size = match backend_type {
872            BackendType::GPU => 1024,
873            BackendType::CPUParallel => 64,
874            _ => 1,
875        };
876
877        let memory_strategy = match backend_type {
878            BackendType::GPU => MemoryStrategy::Pool,
879            BackendType::Distributed => MemoryStrategy::Shared,
880            _ => MemoryStrategy::Heap,
881        };
882
883        let precision_settings = PrecisionSettings {
884            float_precision: if analysis.problem_type == ProblemType::QEC {
885                FloatPrecision::Quadruple
886            } else {
887                FloatPrecision::Double
888            },
889            tolerance: 1e-12,
890            adaptive_precision: true,
891        };
892
893        let gpu_config = if backend_type == BackendType::GPU || backend_type == BackendType::Hybrid
894        {
895            Some(GPUConfiguration {
896                device_id: 0,
897                block_size: 256,
898                grid_size: (analysis.num_qubits * analysis.num_qubits + 255) / 256,
899                memory_strategy: GPUMemoryStrategy::Pool,
900                use_unified_memory: false, // Default to false, can be overridden based on GPU capabilities
901            })
902        } else {
903            None
904        };
905
906        let distributed_config = if backend_type == BackendType::Distributed {
907            Some(DistributedConfiguration {
908                num_nodes: 4,
909                comm_backend: CommunicationBackend::TCP,
910                load_balancing: LoadBalancingStrategy::Dynamic,
911                fault_tolerance: true,
912            })
913        } else {
914            None
915        };
916
917        Ok(BackendConfiguration {
918            num_threads,
919            batch_size,
920            memory_strategy,
921            precision_settings,
922            gpu_config,
923            distributed_config,
924        })
925    }
926
927    /// Calculate circuit depth
928    fn calculate_circuit_depth(gates: &[GateType]) -> usize {
929        // Simplified depth calculation - in reality would need dependency analysis
930        (gates.len() as f64 * 0.7).round() as usize
931    }
932
933    /// Analyze gate composition
934    fn analyze_gate_composition(gates: &[GateType]) -> GateComposition {
935        let mut gate_types = HashMap::new();
936        let mut single_qubit_gates = 0;
937        let mut two_qubit_gates = 0;
938        let mut multi_qubit_gates = 0;
939        let mut parameterized_gates = 0;
940
941        for gate in gates {
942            let gate_name = format!("{gate:?}");
943            *gate_types.entry(gate_name).or_insert(0) += 1;
944
945            match gate {
946                GateType::H
947                | GateType::X
948                | GateType::Y
949                | GateType::Z
950                | GateType::S
951                | GateType::T
952                | GateType::Rx(_)
953                | GateType::Ry(_)
954                | GateType::Rz(_) => {
955                    single_qubit_gates += 1;
956                    if matches!(gate, GateType::Rx(_) | GateType::Ry(_) | GateType::Rz(_)) {
957                        parameterized_gates += 1;
958                    }
959                }
960                GateType::CNOT | GateType::CZ | GateType::SWAP => {
961                    two_qubit_gates += 1;
962                }
963                _ => {
964                    multi_qubit_gates += 1;
965                }
966            }
967        }
968
969        let total_gates = gates.len();
970        let simd_friendly_gates = single_qubit_gates + two_qubit_gates;
971        let simd_friendly_percentage = if total_gates > 0 {
972            simd_friendly_gates as f64 / total_gates as f64
973        } else {
974            0.0
975        };
976
977        GateComposition {
978            total_gates,
979            single_qubit_gates,
980            two_qubit_gates,
981            multi_qubit_gates,
982            gate_types,
983            parameterized_gates,
984            simd_friendly_percentage,
985        }
986    }
987
988    /// Analyze entanglement properties
989    fn analyze_entanglement(gates: &[GateType], num_qubits: usize) -> EntanglementAnalysis {
990        let mut entangling_gates = 0;
991        let mut connectivity_set = HashSet::new();
992
993        for gate in gates {
994            match gate {
995                GateType::CNOT | GateType::CZ | GateType::SWAP => {
996                    entangling_gates += 1;
997                    // Would need actual qubit indices for proper connectivity analysis
998                    connectivity_set.insert((0, 1)); // Simplified
999                }
1000                _ => {}
1001            }
1002        }
1003
1004        let max_entanglement_depth = (entangling_gates as f64).log2().ceil() as usize;
1005        let connectivity_ratio =
1006            connectivity_set.len() as f64 / (num_qubits * (num_qubits - 1) / 2) as f64;
1007        let separable_subsystems = if entangling_gates == 0 { num_qubits } else { 1 };
1008        let entanglement_entropy = if entangling_gates > 0 {
1009            (num_qubits as f64).log2()
1010        } else {
1011            0.0
1012        };
1013
1014        EntanglementAnalysis {
1015            max_entanglement_depth,
1016            connectivity_ratio,
1017            separable_subsystems,
1018            entanglement_entropy,
1019        }
1020    }
1021
1022    /// Estimate memory requirements
1023    fn estimate_memory_requirements(num_qubits: usize, circuit_depth: usize) -> f64 {
1024        let state_vector_size = 2_usize.pow(num_qubits as u32);
1025        let complex_size = 16; // bytes per Complex64
1026        let base_memory = (state_vector_size * complex_size) as f64 / (1024.0 * 1024.0 * 1024.0);
1027        let overhead_factor = 1.5; // Account for intermediate calculations
1028        let depth_factor = (circuit_depth as f64).mul_add(0.01, 1.0);
1029
1030        base_memory * overhead_factor * depth_factor
1031    }
1032
1033    /// Estimate computational complexity
1034    fn estimate_complexity(gates: &[GateType], num_qubits: usize) -> ComplexityEstimate {
1035        let operation_count = gates.len() as u64 * 2_u64.pow(num_qubits as u32);
1036
1037        let time_complexity = if num_qubits <= 10 {
1038            ComplexityClass::Linear
1039        } else if num_qubits <= 20 {
1040            ComplexityClass::Quadratic
1041        } else {
1042            ComplexityClass::Exponential
1043        };
1044
1045        let space_complexity = if num_qubits <= 25 {
1046            ComplexityClass::Exponential
1047        } else {
1048            ComplexityClass::DoubleExponential
1049        };
1050
1051        let memory_pattern = if gates.len() > 1000 {
1052            MemoryPattern::Blocked
1053        } else {
1054            MemoryPattern::Sequential
1055        };
1056
1057        let parallelization_factor = if num_qubits >= 12 {
1058            (num_qubits as f64 / 4.0).min(8.0)
1059        } else {
1060            1.0
1061        };
1062
1063        ComplexityEstimate {
1064            time_complexity,
1065            space_complexity,
1066            operation_count,
1067            memory_pattern,
1068            parallelization_factor,
1069        }
1070    }
1071
1072    /// Analyze parallelization potential
1073    fn analyze_parallelization_potential(
1074        gates: &[GateType],
1075        num_qubits: usize,
1076        gate_composition: &GateComposition,
1077    ) -> ParallelizationPotential {
1078        let gate_parallelism = if gate_composition.single_qubit_gates > 0 {
1079            gate_composition.single_qubit_gates as f64 / gate_composition.total_gates as f64
1080        } else {
1081            0.0
1082        };
1083
1084        let state_parallelism = if num_qubits >= 8 {
1085            (num_qubits as f64 - 7.0) / 10.0
1086        } else {
1087            0.1
1088        };
1089
1090        let batch_potential = if gate_composition.total_gates > 100 {
1091            0.8
1092        } else {
1093            0.3
1094        };
1095
1096        let simd_potential = gate_composition.simd_friendly_percentage;
1097
1098        let gpu_potential = if num_qubits >= 12 && gate_composition.total_gates > 500 {
1099            0.9
1100        } else {
1101            0.2
1102        };
1103
1104        let distributed_potential = if num_qubits >= 20 { 0.8 } else { 0.1 };
1105
1106        ParallelizationPotential {
1107            gate_parallelism,
1108            state_parallelism,
1109            batch_potential,
1110            simd_potential,
1111            gpu_potential,
1112            distributed_potential,
1113        }
1114    }
1115
1116    /// Estimate resource requirements
1117    fn estimate_resource_requirements(
1118        num_qubits: usize,
1119        circuit_depth: usize,
1120        complexity: &ComplexityEstimate,
1121        parallelization: &ParallelizationPotential,
1122    ) -> ResourceRequirements {
1123        let memory_gb = Self::estimate_memory_requirements(num_qubits, circuit_depth);
1124
1125        let cpu_cores = if parallelization.gate_parallelism > 0.5 {
1126            (num_qubits / 2).clamp(2, 16)
1127        } else {
1128            1
1129        };
1130
1131        let gpu_memory_gb = if parallelization.gpu_potential > 0.5 {
1132            memory_gb * 1.2
1133        } else {
1134            0.0
1135        };
1136
1137        let network_bandwidth_mbps = if parallelization.distributed_potential > 0.5 {
1138            100.0 * num_qubits as f64
1139        } else {
1140            0.0
1141        };
1142
1143        let storage_gb = memory_gb * 0.1; // For checkpointing and results
1144
1145        let base_time_ms = match complexity.time_complexity {
1146            ComplexityClass::Linear => circuit_depth as f64 * 0.1,
1147            ComplexityClass::Quadratic => circuit_depth as f64 * circuit_depth as f64 * 0.001,
1148            ComplexityClass::Exponential => (num_qubits as f64 * 0.5).exp2(),
1149            _ => 1000.0,
1150        };
1151
1152        let estimated_time =
1153            Duration::from_millis((base_time_ms / complexity.parallelization_factor) as u64);
1154
1155        ResourceRequirements {
1156            memory_gb,
1157            cpu_cores,
1158            gpu_memory_gb,
1159            network_bandwidth_mbps,
1160            storage_gb,
1161            estimated_time,
1162        }
1163    }
1164
1165    /// Get optimization recommendations
1166    pub fn get_recommendations(
1167        &self,
1168        analysis: &ProblemAnalysis,
1169        selection: &BackendSelection,
1170    ) -> Vec<OptimizationRecommendation> {
1171        let mut recommendations = Vec::new();
1172
1173        // Memory optimization recommendations
1174        if analysis.memory_estimate_gb > self.config.max_memory_gb * 0.8 {
1175            recommendations.push(OptimizationRecommendation {
1176                recommendation_type: RecommendationType::MemoryOptimization,
1177                description:
1178                    "Consider using memory-efficient state representation or chunked computation"
1179                        .to_string(),
1180                expected_improvement: 0.6,
1181                difficulty: 6,
1182                resource_cost: ResourceCost {
1183                    memory_gb: -analysis.memory_estimate_gb * 0.3,
1184                    cpu_cores: 1,
1185                    gpu_memory_gb: 0.0,
1186                    setup_time: Duration::from_millis(200),
1187                },
1188            });
1189        }
1190
1191        // Backend switching recommendations
1192        if selection.confidence < 0.8 {
1193            for (alt_backend, score) in &selection.alternatives {
1194                if *score > selection.confidence {
1195                    recommendations.push(OptimizationRecommendation {
1196                        recommendation_type: RecommendationType::BackendSwitch,
1197                        description: format!(
1198                            "Consider switching to {alt_backend:?} backend for better performance"
1199                        ),
1200                        expected_improvement: score - selection.confidence,
1201                        difficulty: 3,
1202                        resource_cost: ResourceCost {
1203                            memory_gb: 0.5,
1204                            cpu_cores: 0,
1205                            gpu_memory_gb: if *alt_backend == BackendType::GPU {
1206                                2.0
1207                            } else {
1208                                0.0
1209                            },
1210                            setup_time: Duration::from_millis(100),
1211                        },
1212                    });
1213                }
1214            }
1215        }
1216
1217        // Parallelization recommendations
1218        if analysis.parallelization_potential.gate_parallelism > 0.7
1219            && selection.backend_type == BackendType::CPUSingle
1220        {
1221            recommendations.push(OptimizationRecommendation {
1222                recommendation_type: RecommendationType::ParallelizationTuning,
1223                description:
1224                    "High parallelization potential detected - consider parallel CPU backend"
1225                        .to_string(),
1226                expected_improvement: analysis.parallelization_potential.gate_parallelism,
1227                difficulty: 4,
1228                resource_cost: ResourceCost {
1229                    memory_gb: 1.0,
1230                    cpu_cores: self.platform_caps.cpu.logical_cores - 1,
1231                    gpu_memory_gb: 0.0,
1232                    setup_time: Duration::from_millis(50),
1233                },
1234            });
1235        }
1236
1237        // GPU recommendations
1238        if analysis.parallelization_potential.gpu_potential > 0.8
1239            && selection.backend_type != BackendType::GPU
1240            && self.platform_caps.has_gpu()
1241        {
1242            recommendations.push(OptimizationRecommendation {
1243                recommendation_type: RecommendationType::HardwareOptimization,
1244                description: "Problem shows high GPU acceleration potential".to_string(),
1245                expected_improvement: analysis.parallelization_potential.gpu_potential,
1246                difficulty: 7,
1247                resource_cost: ResourceCost {
1248                    memory_gb: 1.0,
1249                    cpu_cores: 0,
1250                    gpu_memory_gb: analysis.memory_estimate_gb,
1251                    setup_time: Duration::from_millis(300),
1252                },
1253            });
1254        }
1255
1256        // Algorithm-specific recommendations
1257        match analysis.problem_type {
1258            ProblemType::VQE => {
1259                recommendations.push(OptimizationRecommendation {
1260                    recommendation_type: RecommendationType::AlgorithmOptimization,
1261                    description: "Consider using gradient-free optimization methods for VQE"
1262                        .to_string(),
1263                    expected_improvement: 0.3,
1264                    difficulty: 5,
1265                    resource_cost: ResourceCost {
1266                        memory_gb: 0.5,
1267                        cpu_cores: 0,
1268                        gpu_memory_gb: 0.0,
1269                        setup_time: Duration::from_millis(100),
1270                    },
1271                });
1272            }
1273            ProblemType::QAOA => {
1274                recommendations.push(OptimizationRecommendation {
1275                    recommendation_type: RecommendationType::AlgorithmOptimization,
1276                    description: "Consider using warm-start initialization for QAOA parameters"
1277                        .to_string(),
1278                    expected_improvement: 0.4,
1279                    difficulty: 4,
1280                    resource_cost: ResourceCost {
1281                        memory_gb: 0.2,
1282                        cpu_cores: 0,
1283                        gpu_memory_gb: 0.0,
1284                        setup_time: Duration::from_millis(50),
1285                    },
1286                });
1287            }
1288            _ => {}
1289        }
1290
1291        // Precision recommendations
1292        if analysis.problem_type == ProblemType::Simulation
1293            && selection.configuration.precision_settings.float_precision == FloatPrecision::Double
1294        {
1295            recommendations.push(OptimizationRecommendation {
1296                recommendation_type: RecommendationType::PrecisionAdjustment,
1297                description: "Consider single precision for simulation if acceptable accuracy"
1298                    .to_string(),
1299                expected_improvement: 0.5,
1300                difficulty: 2,
1301                resource_cost: ResourceCost {
1302                    memory_gb: -analysis.memory_estimate_gb * 0.5,
1303                    cpu_cores: 0,
1304                    gpu_memory_gb: 0.0,
1305                    setup_time: Duration::from_millis(10),
1306                },
1307            });
1308        }
1309
1310        recommendations
1311    }
1312
1313    /// Monitor and update backend selection dynamically
1314    pub fn monitor_and_update(
1315        &mut self,
1316        current_selection: &BackendSelection,
1317        current_performance: &PerformanceMetrics,
1318    ) -> QuantRS2Result<Option<BackendSelection>> {
1319        if !self.config.enable_auto_switching {
1320            return Ok(None);
1321        }
1322
1323        // Update resource monitoring
1324        self.update_resource_monitoring(current_performance)?;
1325
1326        // Check if current backend is underperforming
1327        let expected_performance = &current_selection.expected_performance;
1328        let performance_ratio = current_performance.throughput / expected_performance.throughput;
1329
1330        if performance_ratio < 0.7 {
1331            // Performance is significantly below expectations
1332            // Consider switching to a different backend
1333            // This would require re-analysis of the current problem
1334            // For now, return None indicating no change
1335            return Ok(None);
1336        }
1337
1338        // Check resource constraints
1339        if current_performance.memory_efficiency < 0.5 {
1340            // Memory efficiency is poor, might need optimization
1341            return Ok(None);
1342        }
1343
1344        Ok(None)
1345    }
1346
1347    /// Update resource monitoring
1348    fn update_resource_monitoring(
1349        &mut self,
1350        current_performance: &PerformanceMetrics,
1351    ) -> QuantRS2Result<()> {
1352        self.resource_monitor
1353            .cpu_history
1354            .push(current_performance.cpu_utilization);
1355        self.resource_monitor
1356            .memory_history
1357            .push(current_performance.memory_efficiency);
1358        self.resource_monitor
1359            .gpu_history
1360            .push(current_performance.gpu_utilization);
1361
1362        // Keep only recent history
1363        let max_history = 100;
1364        if self.resource_monitor.cpu_history.len() > max_history {
1365            self.resource_monitor.cpu_history.remove(0);
1366        }
1367        if self.resource_monitor.memory_history.len() > max_history {
1368            self.resource_monitor.memory_history.remove(0);
1369        }
1370        if self.resource_monitor.gpu_history.len() > max_history {
1371            self.resource_monitor.gpu_history.remove(0);
1372        }
1373
1374        Ok(())
1375    }
1376}
1377
1378#[cfg(test)]
1379mod tests {
1380    use super::*;
1381
1382    #[test]
1383    fn test_auto_optimizer_creation() {
1384        let config = AutoOptimizerConfig::default();
1385        let optimizer = AutoOptimizer::new(config);
1386        assert!(optimizer.is_ok());
1387    }
1388
1389    #[test]
1390    fn test_problem_analysis() {
1391        let config = AutoOptimizerConfig::default();
1392        let mut optimizer = AutoOptimizer::new(config).expect("Failed to create AutoOptimizer");
1393
1394        let gates = vec![
1395            GateType::H,
1396            GateType::CNOT,
1397            GateType::Rz("0.5".to_string()),
1398            GateType::X,
1399        ];
1400
1401        let analysis = optimizer.analyze_problem(&gates, 5, ProblemType::Simulation);
1402        assert!(analysis.is_ok());
1403
1404        let analysis = analysis.expect("Failed to analyze problem");
1405        assert_eq!(analysis.num_qubits, 5);
1406        assert_eq!(analysis.gate_composition.total_gates, 4);
1407        assert_eq!(analysis.problem_type, ProblemType::Simulation);
1408    }
1409
1410    #[test]
1411    fn test_backend_selection() {
1412        let config = AutoOptimizerConfig::default();
1413        let optimizer = AutoOptimizer::new(config).expect("Failed to create AutoOptimizer");
1414
1415        let analysis = ProblemAnalysis {
1416            num_qubits: 10,
1417            circuit_depth: 50,
1418            gate_composition: GateComposition {
1419                total_gates: 100,
1420                single_qubit_gates: 60,
1421                two_qubit_gates: 30,
1422                multi_qubit_gates: 10,
1423                gate_types: HashMap::new(),
1424                parameterized_gates: 20,
1425                simd_friendly_percentage: 0.9,
1426            },
1427            entanglement_analysis: EntanglementAnalysis {
1428                max_entanglement_depth: 5,
1429                connectivity_ratio: 0.3,
1430                separable_subsystems: 2,
1431                entanglement_entropy: 3.0,
1432            },
1433            memory_estimate_gb: 2.0,
1434            complexity_estimate: ComplexityEstimate {
1435                time_complexity: ComplexityClass::Quadratic,
1436                space_complexity: ComplexityClass::Exponential,
1437                operation_count: 1000000,
1438                memory_pattern: MemoryPattern::Sequential,
1439                parallelization_factor: 4.0,
1440            },
1441            problem_type: ProblemType::Simulation,
1442            parallelization_potential: ParallelizationPotential {
1443                gate_parallelism: 0.8,
1444                state_parallelism: 0.6,
1445                batch_potential: 0.7,
1446                simd_potential: 0.9,
1447                gpu_potential: 0.5,
1448                distributed_potential: 0.2,
1449            },
1450            resource_requirements: ResourceRequirements {
1451                memory_gb: 2.0,
1452                cpu_cores: 4,
1453                gpu_memory_gb: 0.0,
1454                network_bandwidth_mbps: 0.0,
1455                storage_gb: 0.2,
1456                estimated_time: Duration::from_secs(60),
1457            },
1458        };
1459
1460        let selection = optimizer.select_backend(&analysis);
1461        assert!(selection.is_ok());
1462
1463        let selection = selection.expect("Failed to select backend");
1464        assert!(selection.confidence > 0.0);
1465        assert!(!selection.reasoning.is_empty());
1466    }
1467
1468    #[test]
1469    fn test_recommendations() {
1470        let config = AutoOptimizerConfig::default();
1471        let optimizer = AutoOptimizer::new(config).expect("Failed to create AutoOptimizer");
1472
1473        let analysis = ProblemAnalysis {
1474            num_qubits: 15,
1475            circuit_depth: 100,
1476            gate_composition: GateComposition {
1477                total_gates: 200,
1478                single_qubit_gates: 120,
1479                two_qubit_gates: 60,
1480                multi_qubit_gates: 20,
1481                gate_types: HashMap::new(),
1482                parameterized_gates: 40,
1483                simd_friendly_percentage: 0.85,
1484            },
1485            entanglement_analysis: EntanglementAnalysis {
1486                max_entanglement_depth: 8,
1487                connectivity_ratio: 0.4,
1488                separable_subsystems: 1,
1489                entanglement_entropy: 4.0,
1490            },
1491            memory_estimate_gb: 8.0,
1492            complexity_estimate: ComplexityEstimate {
1493                time_complexity: ComplexityClass::Exponential,
1494                space_complexity: ComplexityClass::Exponential,
1495                operation_count: 10000000,
1496                memory_pattern: MemoryPattern::Blocked,
1497                parallelization_factor: 6.0,
1498            },
1499            problem_type: ProblemType::VQE,
1500            parallelization_potential: ParallelizationPotential {
1501                gate_parallelism: 0.85,
1502                state_parallelism: 0.7,
1503                batch_potential: 0.8,
1504                simd_potential: 0.85,
1505                gpu_potential: 0.9,
1506                distributed_potential: 0.3,
1507            },
1508            resource_requirements: ResourceRequirements {
1509                memory_gb: 8.0,
1510                cpu_cores: 6,
1511                gpu_memory_gb: 4.0,
1512                network_bandwidth_mbps: 0.0,
1513                storage_gb: 0.8,
1514                estimated_time: Duration::from_secs(300),
1515            },
1516        };
1517
1518        let selection = optimizer
1519            .select_backend(&analysis)
1520            .expect("Failed to select backend");
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.is_empty());
1531    }
1532}