quantrs2_anneal/applications/
unified.rs

1//! Unified Problem Interface and Solver Factory
2//!
3//! This module provides a comprehensive unified interface for all industry-specific
4//! optimization problems, along with a solver factory that can automatically
5//! select and configure appropriate solvers based on problem characteristics.
6
7use super::{
8    energy, finance, healthcare, logistics, manufacturing, telecommunications, ApplicationError,
9    ApplicationResult, IndustryConstraint, IndustryObjective, IndustrySolution,
10    OptimizationProblem, ProblemCategory,
11};
12use crate::ising::IsingModel;
13use crate::qubo::{QuboBuilder, QuboFormulation};
14use crate::simulator::{
15    AnnealingParams, AnnealingResult, ClassicalAnnealingSimulator, QuantumAnnealingSimulator,
16};
17use std::any::Any;
18use std::collections::HashMap;
19use std::fmt::Debug;
20
21/// Unified solution type that can represent different kinds of optimization solutions
22#[derive(Debug, Clone)]
23pub enum UnifiedSolution {
24    /// Binary solution vector (for discrete optimization)
25    Binary(Vec<i8>),
26    /// Continuous solution vector (for continuous optimization)
27    Continuous(Vec<f64>),
28    /// Mixed binary-continuous solution
29    Mixed {
30        binary: Vec<i8>,
31        continuous: Vec<f64>,
32    },
33    /// Industry-specific solution data
34    Custom(serde_json::Value),
35}
36
37impl UnifiedSolution {
38    /// Get the binary part of the solution if available
39    #[must_use]
40    pub const fn binary(&self) -> Option<&Vec<i8>> {
41        match self {
42            Self::Binary(b) => Some(b),
43            Self::Mixed { binary, .. } => Some(binary),
44            _ => None,
45        }
46    }
47
48    /// Get the continuous part of the solution if available
49    #[must_use]
50    pub const fn continuous(&self) -> Option<&Vec<f64>> {
51        match self {
52            Self::Continuous(c) => Some(c),
53            Self::Mixed { continuous, .. } => Some(continuous),
54            _ => None,
55        }
56    }
57}
58
59/// Unified problem interface that extends the base optimization problem trait
60pub trait UnifiedProblem:
61    OptimizationProblem<Solution = UnifiedSolution, ObjectiveValue = f64> + Debug + Send + Sync
62{
63    /// Get the industry category of this problem
64    fn category(&self) -> ProblemCategory;
65
66    /// Get the industry name
67    fn industry(&self) -> &'static str;
68
69    /// Get problem complexity estimate (small, medium, large)
70    fn complexity(&self) -> ProblemComplexity;
71
72    /// Get recommended solver configuration
73    fn recommended_solver_config(&self) -> SolverConfiguration;
74
75    /// Get problem-specific constraints
76    fn constraints(&self) -> Vec<IndustryConstraint>;
77
78    /// Get problem objective
79    fn objective(&self) -> IndustryObjective;
80
81    /// Get expected solution quality bounds
82    fn solution_bounds(&self) -> Option<(f64, f64)>; // (lower_bound, upper_bound)
83
84    /// Convert to Any for downcasting
85    fn as_any(&self) -> &dyn Any;
86
87    /// Clone into a boxed unified problem
88    fn clone_unified(&self) -> Box<dyn UnifiedProblem>;
89}
90
91/// Problem complexity categories for solver selection
92#[derive(Debug, Clone, PartialEq, Eq)]
93pub enum ProblemComplexity {
94    /// Small problems (< 100 variables)
95    Small,
96    /// Medium problems (100-1000 variables)
97    Medium,
98    /// Large problems (1000-10_000 variables)
99    Large,
100    /// Extra large problems (> `10_000` variables)
101    ExtraLarge,
102}
103
104/// Solver configuration recommendations
105#[derive(Debug, Clone)]
106pub struct SolverConfiguration {
107    /// Preferred solver type
108    pub solver_type: SolverType,
109    /// Annealing parameters
110    pub annealing_params: AnnealingParams,
111    /// Hardware requirements
112    pub hardware_requirements: HardwareRequirements,
113    /// Optimization hints
114    pub optimization_hints: Vec<OptimizationHint>,
115}
116
117/// Available solver types
118#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
119pub enum SolverType {
120    #[default]
121    /// Classical simulated annealing
122    Classical,
123    /// Quantum annealing simulator
124    QuantumSimulator,
125    /// D-Wave quantum annealer
126    DWave,
127    /// Hybrid classical-quantum
128    Hybrid,
129    /// Problem-specific heuristic
130    Heuristic,
131}
132
133/// Hardware requirements for solving
134#[derive(Debug, Clone)]
135pub struct HardwareRequirements {
136    /// Minimum memory (GB)
137    pub min_memory_gb: f64,
138    /// Recommended CPU cores
139    pub recommended_cores: usize,
140    /// GPU acceleration beneficial
141    pub gpu_acceleration: bool,
142    /// Quantum hardware required
143    pub quantum_hardware: bool,
144}
145
146/// Optimization hints for solver configuration
147#[derive(Debug, Clone)]
148pub enum OptimizationHint {
149    /// Problem has sparse structure
150    SparseStructure,
151    /// Problem has many local minima
152    MultiModal,
153    /// Problem is highly constrained
154    HighlyConstrained,
155    /// Real-time solving required
156    RealTime,
157    /// High precision required
158    HighPrecision,
159    /// Approximate solution acceptable
160    ApproximateOk,
161}
162
163/// Comprehensive solver factory for all problem types
164#[derive(Debug, Clone)]
165pub struct UnifiedSolverFactory {
166    /// Default solver configurations by category
167    default_configs: HashMap<ProblemCategory, SolverConfiguration>,
168    /// Available solver backends
169    available_solvers: Vec<SolverType>,
170    /// Performance cache for solver selection
171    performance_cache: HashMap<String, f64>,
172}
173
174impl Default for UnifiedSolverFactory {
175    fn default() -> Self {
176        Self::new()
177    }
178}
179
180impl UnifiedSolverFactory {
181    /// Create a new solver factory with default configurations
182    #[must_use]
183    pub fn new() -> Self {
184        let mut factory = Self {
185            default_configs: HashMap::new(),
186            available_solvers: vec![SolverType::Classical, SolverType::QuantumSimulator],
187            performance_cache: HashMap::new(),
188        };
189
190        factory.initialize_default_configs();
191        factory
192    }
193
194    /// Initialize default configurations for different problem categories
195    fn initialize_default_configs(&mut self) {
196        // Finance problems - typically medium complexity, precision important
197        self.default_configs.insert(
198            ProblemCategory::Portfolio,
199            SolverConfiguration {
200                solver_type: SolverType::Classical,
201                annealing_params: AnnealingParams {
202                    num_sweeps: 10_000,
203                    num_repetitions: 20,
204                    initial_temperature: 2.0,
205                    final_temperature: 0.01,
206                    temperature_schedule: crate::simulator::TemperatureSchedule::Linear,
207                    ..Default::default()
208                },
209                hardware_requirements: HardwareRequirements {
210                    min_memory_gb: 2.0,
211                    recommended_cores: 4,
212                    gpu_acceleration: false,
213                    quantum_hardware: false,
214                },
215                optimization_hints: vec![OptimizationHint::HighPrecision],
216            },
217        );
218
219        // Logistics problems - complex routing, heuristics often helpful
220        self.default_configs.insert(
221            ProblemCategory::Routing,
222            SolverConfiguration {
223                solver_type: SolverType::Hybrid,
224                annealing_params: AnnealingParams {
225                    num_sweeps: 15_000,
226                    num_repetitions: 25,
227                    initial_temperature: 3.0,
228                    final_temperature: 0.005,
229                    temperature_schedule: crate::simulator::TemperatureSchedule::Exponential(0.95),
230                    ..Default::default()
231                },
232                hardware_requirements: HardwareRequirements {
233                    min_memory_gb: 4.0,
234                    recommended_cores: 8,
235                    gpu_acceleration: true,
236                    quantum_hardware: false,
237                },
238                optimization_hints: vec![
239                    OptimizationHint::MultiModal,
240                    OptimizationHint::HighlyConstrained,
241                ],
242            },
243        );
244
245        // Network design - large sparse problems
246        self.default_configs.insert(
247            ProblemCategory::NetworkDesign,
248            SolverConfiguration {
249                solver_type: SolverType::QuantumSimulator,
250                annealing_params: AnnealingParams {
251                    num_sweeps: 25_000,
252                    num_repetitions: 40,
253                    initial_temperature: 5.0,
254                    final_temperature: 0.001,
255                    temperature_schedule: crate::simulator::TemperatureSchedule::Linear,
256                    ..Default::default()
257                },
258                hardware_requirements: HardwareRequirements {
259                    min_memory_gb: 8.0,
260                    recommended_cores: 16,
261                    gpu_acceleration: true,
262                    quantum_hardware: false,
263                },
264                optimization_hints: vec![OptimizationHint::SparseStructure],
265            },
266        );
267
268        // Add more default configurations as needed
269        self.add_remaining_default_configs();
270    }
271
272    /// Add remaining default configurations
273    fn add_remaining_default_configs(&mut self) {
274        // Resource allocation problems
275        self.default_configs.insert(
276            ProblemCategory::ResourceAllocation,
277            SolverConfiguration {
278                solver_type: SolverType::Classical,
279                annealing_params: AnnealingParams::default(),
280                hardware_requirements: HardwareRequirements {
281                    min_memory_gb: 1.0,
282                    recommended_cores: 2,
283                    gpu_acceleration: false,
284                    quantum_hardware: false,
285                },
286                optimization_hints: vec![OptimizationHint::HighlyConstrained],
287            },
288        );
289
290        // Supply chain optimization
291        self.default_configs.insert(
292            ProblemCategory::SupplyChain,
293            SolverConfiguration {
294                solver_type: SolverType::Hybrid,
295                annealing_params: AnnealingParams {
296                    num_sweeps: 20_000,
297                    num_repetitions: 30,
298                    initial_temperature: 4.0,
299                    final_temperature: 0.01,
300                    ..Default::default()
301                },
302                hardware_requirements: HardwareRequirements {
303                    min_memory_gb: 6.0,
304                    recommended_cores: 12,
305                    gpu_acceleration: true,
306                    quantum_hardware: false,
307                },
308                optimization_hints: vec![OptimizationHint::MultiModal],
309            },
310        );
311    }
312
313    /// Create a problem from industry and type specifications
314    pub fn create_problem(
315        &self,
316        industry: &str,
317        problem_type: &str,
318        config: HashMap<String, serde_json::Value>,
319    ) -> ApplicationResult<Box<dyn UnifiedProblem>> {
320        match (industry, problem_type) {
321            ("finance", "portfolio") => {
322                let problem = self.create_finance_portfolio(config)?;
323                Ok(Box::new(problem) as Box<dyn UnifiedProblem>)
324            }
325            ("logistics", "vrp") => {
326                let problem = self.create_logistics_vrp(config)?;
327                Ok(Box::new(problem) as Box<dyn UnifiedProblem>)
328            }
329            ("telecommunications", "network") => {
330                let problem = self.create_telecom_network(config)?;
331                Ok(Box::new(problem) as Box<dyn UnifiedProblem>)
332            }
333            ("energy", "grid") => {
334                let problem = self.create_energy_grid(config)?;
335                Ok(Box::new(problem) as Box<dyn UnifiedProblem>)
336            }
337            ("manufacturing", "scheduling") => {
338                let problem = self.create_manufacturing_scheduling(config)?;
339                Ok(Box::new(problem) as Box<dyn UnifiedProblem>)
340            }
341            ("healthcare", "resource") => {
342                let problem = self.create_healthcare_resource(config)?;
343                Ok(Box::new(problem) as Box<dyn UnifiedProblem>)
344            }
345            _ => Err(ApplicationError::InvalidConfiguration(format!(
346                "Unknown problem type: {industry} / {problem_type}"
347            ))),
348        }
349    }
350
351    /// Solve any unified problem with automatic solver selection
352    pub fn solve_problem(
353        &self,
354        problem: &dyn UnifiedProblem,
355        custom_config: Option<SolverConfiguration>,
356    ) -> ApplicationResult<UnifiedSolution> {
357        // Get solver configuration (custom or default)
358        let config = custom_config.unwrap_or_else(|| self.get_recommended_config(problem));
359
360        // Validate problem
361        problem.validate()?;
362
363        // Convert to QUBO
364        let (qubo_model, _var_map) = problem.to_qubo()?;
365
366        // Solve based on configuration
367        let result = match config.solver_type {
368            SolverType::Classical => self.solve_classical(&qubo_model, &config.annealing_params)?,
369            SolverType::QuantumSimulator => {
370                self.solve_quantum_simulator(&qubo_model, &config.annealing_params)?
371            }
372            SolverType::Hybrid => self.solve_hybrid(&qubo_model, &config.annealing_params)?,
373            _ => {
374                return Err(ApplicationError::OptimizationError(
375                    "Solver type not yet implemented".to_string(),
376                ))
377            }
378        };
379
380        // Create unified solution using the enum variant
381        Ok(UnifiedSolution::Binary(result.best_spins))
382    }
383
384    /// Get recommended configuration for a problem
385    fn get_recommended_config(&self, problem: &dyn UnifiedProblem) -> SolverConfiguration {
386        // Use category defaults if available, otherwise problem's own recommendation
387        let mut config = self
388            .default_configs
389            .get(&problem.category())
390            .cloned()
391            .unwrap_or_else(|| problem.recommended_solver_config());
392
393        // Adjust based on problem complexity
394        self.adjust_config_for_complexity(&mut config, problem.complexity());
395
396        config
397    }
398
399    /// Adjust configuration based on problem complexity
400    fn adjust_config_for_complexity(
401        &self,
402        config: &mut SolverConfiguration,
403        complexity: ProblemComplexity,
404    ) {
405        match complexity {
406            ProblemComplexity::Small => {
407                config.annealing_params.num_sweeps = config.annealing_params.num_sweeps.min(5000);
408                config.annealing_params.num_repetitions =
409                    config.annealing_params.num_repetitions.min(10);
410            }
411            ProblemComplexity::Medium => {
412                // Keep default values
413            }
414            ProblemComplexity::Large => {
415                config.annealing_params.num_sweeps = config.annealing_params.num_sweeps.max(20_000);
416                config.annealing_params.num_repetitions =
417                    config.annealing_params.num_repetitions.max(30);
418                config.hardware_requirements.min_memory_gb *= 2.0;
419            }
420            ProblemComplexity::ExtraLarge => {
421                config.annealing_params.num_sweeps = config.annealing_params.num_sweeps.max(50_000);
422                config.annealing_params.num_repetitions =
423                    config.annealing_params.num_repetitions.max(50);
424                config.hardware_requirements.min_memory_gb *= 4.0;
425                config.solver_type = SolverType::Hybrid; // Force hybrid for very large problems
426            }
427        }
428    }
429
430    /// Solve using classical annealing
431    fn solve_classical(
432        &self,
433        qubo_model: &crate::ising::QuboModel,
434        params: &AnnealingParams,
435    ) -> ApplicationResult<crate::simulator::AnnealingSolution> {
436        let ising = IsingModel::from_qubo(qubo_model);
437
438        let simulator = ClassicalAnnealingSimulator::new(params.clone())
439            .map_err(|e| ApplicationError::OptimizationError(e.to_string()))?;
440
441        simulator
442            .solve(&ising)
443            .map_err(|e| ApplicationError::OptimizationError(e.to_string()))
444    }
445
446    /// Solve using quantum simulator
447    fn solve_quantum_simulator(
448        &self,
449        qubo_model: &crate::ising::QuboModel,
450        params: &AnnealingParams,
451    ) -> ApplicationResult<crate::simulator::AnnealingSolution> {
452        let ising = IsingModel::from_qubo(qubo_model);
453
454        let simulator = QuantumAnnealingSimulator::new(params.clone())
455            .map_err(|e| ApplicationError::OptimizationError(e.to_string()))?;
456
457        simulator
458            .solve(&ising)
459            .map_err(|e| ApplicationError::OptimizationError(e.to_string()))
460    }
461
462    /// Solve using hybrid approach
463    fn solve_hybrid(
464        &self,
465        qubo_model: &crate::ising::QuboModel,
466        params: &AnnealingParams,
467    ) -> ApplicationResult<crate::simulator::AnnealingSolution> {
468        // For now, use classical as fallback
469        // In future, implement actual hybrid solver
470        self.solve_classical(qubo_model, params)
471    }
472
473    /// Create finance portfolio problem from configuration
474    fn create_finance_portfolio(
475        &self,
476        config: HashMap<String, serde_json::Value>,
477    ) -> ApplicationResult<UnifiedPortfolioOptimization> {
478        // Extract configuration parameters
479        let num_assets = config
480            .get("num_assets")
481            .and_then(serde_json::Value::as_u64)
482            .unwrap_or(10) as usize;
483
484        let budget = config
485            .get("budget")
486            .and_then(serde_json::Value::as_f64)
487            .unwrap_or(1_000_000.0);
488
489        let risk_tolerance = config
490            .get("risk_tolerance")
491            .and_then(serde_json::Value::as_f64)
492            .unwrap_or(0.5);
493
494        // Generate sample data
495        let expected_returns: Vec<f64> = (0..num_assets)
496            .map(|i| 0.03 + 0.07 * (i as f64) / (num_assets as f64))
497            .collect();
498
499        let covariance_matrix = self.create_sample_covariance_matrix(num_assets, 0.2);
500
501        let portfolio = finance::PortfolioOptimization::new(
502            expected_returns,
503            covariance_matrix,
504            budget,
505            risk_tolerance,
506        )?;
507
508        Ok(UnifiedPortfolioOptimization { inner: portfolio })
509    }
510
511    /// Create logistics VRP problem from configuration
512    fn create_logistics_vrp(
513        &self,
514        config: HashMap<String, serde_json::Value>,
515    ) -> ApplicationResult<UnifiedVehicleRoutingProblem> {
516        let num_vehicles = config
517            .get("num_vehicles")
518            .and_then(serde_json::Value::as_u64)
519            .unwrap_or(3) as usize;
520
521        let num_customers = config
522            .get("num_customers")
523            .and_then(serde_json::Value::as_u64)
524            .unwrap_or(10) as usize;
525
526        // Generate sample problem
527        let mut locations = vec![(0.0, 0.0)]; // Depot
528        let mut demands = vec![0.0]; // Depot demand
529
530        for i in 0..num_customers {
531            let angle = 2.0 * std::f64::consts::PI * i as f64 / num_customers as f64;
532            let radius = (i as f64).mul_add(0.1, 1.0);
533            locations.push((radius * angle.cos(), radius * angle.sin()));
534            demands.push((i as f64).mul_add(2.0, 5.0));
535        }
536
537        let capacities = vec![50.0; num_vehicles];
538
539        let vrp =
540            logistics::VehicleRoutingProblem::new(num_vehicles, capacities, locations, demands)?;
541
542        Ok(UnifiedVehicleRoutingProblem { inner: vrp })
543    }
544
545    /// Create telecommunications network problem from configuration
546    fn create_telecom_network(
547        &self,
548        config: HashMap<String, serde_json::Value>,
549    ) -> ApplicationResult<UnifiedNetworkTopologyOptimization> {
550        let num_nodes = config
551            .get("num_nodes")
552            .and_then(serde_json::Value::as_u64)
553            .unwrap_or(6) as usize;
554
555        // Generate fully connected potential connections
556        let mut potential_connections = Vec::new();
557        let mut connection_costs = Vec::new();
558
559        for i in 0..num_nodes {
560            for j in (i + 1)..num_nodes {
561                potential_connections.push((i, j));
562                connection_costs.push(((i + j) as f64).mul_add(1.5, 5.0));
563            }
564        }
565
566        let traffic_demands = vec![vec![2.0; num_nodes]; num_nodes];
567
568        let network = telecommunications::NetworkTopologyOptimization::new(
569            num_nodes,
570            potential_connections,
571            connection_costs,
572            traffic_demands,
573        )?;
574
575        Ok(UnifiedNetworkTopologyOptimization { inner: network })
576    }
577
578    /// Create energy grid problem from configuration
579    fn create_energy_grid(
580        &self,
581        _config: HashMap<String, serde_json::Value>,
582    ) -> ApplicationResult<UnifiedEnergyGridOptimization> {
583        // Placeholder - would create actual energy grid problem
584        Err(ApplicationError::InvalidConfiguration(
585            "Energy grid problem creation not yet implemented".to_string(),
586        ))
587    }
588
589    /// Create manufacturing scheduling problem from configuration
590    fn create_manufacturing_scheduling(
591        &self,
592        _config: HashMap<String, serde_json::Value>,
593    ) -> ApplicationResult<UnifiedManufacturingScheduling> {
594        // Placeholder - would create actual manufacturing problem
595        Err(ApplicationError::InvalidConfiguration(
596            "Manufacturing scheduling problem creation not yet implemented".to_string(),
597        ))
598    }
599
600    /// Create healthcare resource problem from configuration
601    fn create_healthcare_resource(
602        &self,
603        _config: HashMap<String, serde_json::Value>,
604    ) -> ApplicationResult<UnifiedHealthcareResourceOptimization> {
605        // Placeholder - would create actual healthcare problem
606        Err(ApplicationError::InvalidConfiguration(
607            "Healthcare resource problem creation not yet implemented".to_string(),
608        ))
609    }
610
611    /// Helper to create sample covariance matrix
612    fn create_sample_covariance_matrix(&self, n: usize, base_volatility: f64) -> Vec<Vec<f64>> {
613        let mut matrix = vec![vec![0.0; n]; n];
614
615        for i in 0..n {
616            for j in 0..n {
617                if i == j {
618                    matrix[i][j] =
619                        base_volatility * base_volatility * (1.0 + 0.5 * (i as f64) / (n as f64));
620                } else {
621                    let correlation = 0.1 * (1.0 - (i as f64 - j as f64).abs() / (n as f64));
622                    let vol_i = (matrix[i][i]).sqrt();
623                    let vol_j = (matrix[j][j]).sqrt();
624                    matrix[i][j] = correlation * vol_i * vol_j;
625                }
626            }
627        }
628
629        matrix
630    }
631}
632
633// Removed duplicate UnifiedSolution struct definition - using enum version instead
634
635/// Convergence information for the solving process
636#[derive(Debug, Clone)]
637pub struct ConvergenceInfo {
638    /// Whether the solver converged
639    pub converged: bool,
640    /// Final energy/objective value
641    pub final_energy: f64,
642    /// Energy variance across repetitions
643    pub energy_variance: f64,
644    /// Acceptance rate during annealing
645    pub acceptance_rate: f64,
646}
647
648/// Information about the problem that was solved
649#[derive(Debug, Clone)]
650pub struct ProblemInfo {
651    /// Industry name
652    pub industry: String,
653    /// Problem category
654    pub category: ProblemCategory,
655    /// Problem complexity
656    pub complexity: ProblemComplexity,
657    /// Number of variables
658    pub num_variables: usize,
659    /// Number of constraints
660    pub num_constraints: usize,
661}
662
663// Wrapper types for existing problems to implement UnifiedProblem
664// These would be expanded for all problem types
665
666/// Unified wrapper for portfolio optimization
667#[derive(Debug, Clone)]
668pub struct UnifiedPortfolioOptimization {
669    inner: finance::PortfolioOptimization,
670}
671
672/// Unified wrapper for vehicle routing
673#[derive(Debug, Clone)]
674pub struct UnifiedVehicleRoutingProblem {
675    inner: logistics::VehicleRoutingProblem,
676}
677
678/// Unified wrapper for network topology optimization
679#[derive(Debug, Clone)]
680pub struct UnifiedNetworkTopologyOptimization {
681    inner: telecommunications::NetworkTopologyOptimization,
682}
683
684// Placeholder types for other industries
685#[derive(Debug, Clone)]
686pub struct UnifiedEnergyGridOptimization {
687    // Would contain actual energy problem
688}
689
690#[derive(Debug, Clone)]
691pub struct UnifiedManufacturingScheduling {
692    // Would contain actual manufacturing problem
693}
694
695#[derive(Debug, Clone)]
696pub struct UnifiedHealthcareResourceOptimization {
697    // Would contain actual healthcare problem
698}
699
700// Implement UnifiedProblem for all wrapper types
701// This is where the unified interface comes together
702
703impl OptimizationProblem for UnifiedPortfolioOptimization {
704    type Solution = UnifiedSolution;
705    type ObjectiveValue = f64;
706
707    fn description(&self) -> String {
708        self.inner.description()
709    }
710
711    fn size_metrics(&self) -> HashMap<String, usize> {
712        self.inner.size_metrics()
713    }
714
715    fn validate(&self) -> ApplicationResult<()> {
716        self.inner.validate()
717    }
718
719    fn to_qubo(&self) -> ApplicationResult<(crate::ising::QuboModel, HashMap<String, usize>)> {
720        self.inner.to_qubo()
721    }
722
723    fn evaluate_solution(
724        &self,
725        solution: &Self::Solution,
726    ) -> ApplicationResult<Self::ObjectiveValue> {
727        match solution {
728            UnifiedSolution::Binary(binary_sol) => {
729                // Convert binary solution to PortfolioSolution for evaluation
730                // Create equal weights for selected assets (simplified conversion)
731                let num_assets = binary_sol.len();
732                let weights: Vec<f64> = binary_sol
733                    .iter()
734                    .map(|&x| if x == 1 { 1.0 / num_assets as f64 } else { 0.0 })
735                    .collect();
736                let portfolio_sol = finance::PortfolioSolution {
737                    weights,
738                    metrics: finance::PortfolioMetrics {
739                        expected_return: 0.0,
740                        volatility: 0.0,
741                        sharpe_ratio: 0.0,
742                        max_drawdown: 0.0,
743                        var_95: 0.0,
744                        cvar_95: 0.0,
745                    },
746                };
747                self.inner.evaluate_solution(&portfolio_sol)
748            }
749            UnifiedSolution::Custom(_) => {
750                // Custom solutions not supported for portfolio optimization
751                Err(ApplicationError::OptimizationError(
752                    "Custom solution format not supported for portfolio optimization".to_string(),
753                ))
754            }
755            _ => Err(ApplicationError::OptimizationError(
756                "Unsupported solution type for portfolio optimization".to_string(),
757            )),
758        }
759    }
760
761    fn is_feasible(&self, solution: &Self::Solution) -> bool {
762        match solution {
763            UnifiedSolution::Binary(binary_sol) => {
764                // Convert binary solution to PortfolioSolution for feasibility check
765                let num_assets = binary_sol.len();
766                let weights: Vec<f64> = binary_sol
767                    .iter()
768                    .map(|&x| if x == 1 { 1.0 / num_assets as f64 } else { 0.0 })
769                    .collect();
770                let portfolio_sol = finance::PortfolioSolution {
771                    weights,
772                    metrics: finance::PortfolioMetrics {
773                        expected_return: 0.0,
774                        volatility: 0.0,
775                        sharpe_ratio: 0.0,
776                        max_drawdown: 0.0,
777                        var_95: 0.0,
778                        cvar_95: 0.0,
779                    },
780                };
781                self.inner.is_feasible(&portfolio_sol)
782            }
783            UnifiedSolution::Custom(_) => {
784                // Custom solution format not supported for portfolio optimization
785                false
786            }
787            _ => false,
788        }
789    }
790}
791
792impl UnifiedProblem for UnifiedPortfolioOptimization {
793    fn category(&self) -> ProblemCategory {
794        ProblemCategory::Portfolio
795    }
796
797    fn industry(&self) -> &'static str {
798        "finance"
799    }
800
801    fn complexity(&self) -> ProblemComplexity {
802        let num_assets = self.inner.expected_returns.len();
803        match num_assets {
804            0..=10 => ProblemComplexity::Small,
805            11..=50 => ProblemComplexity::Medium,
806            51..=200 => ProblemComplexity::Large,
807            _ => ProblemComplexity::ExtraLarge,
808        }
809    }
810
811    fn recommended_solver_config(&self) -> SolverConfiguration {
812        SolverConfiguration {
813            solver_type: SolverType::Classical,
814            annealing_params: AnnealingParams {
815                num_sweeps: 10_000,
816                num_repetitions: 20,
817                initial_temperature: 2.0,
818                final_temperature: 0.01,
819                ..Default::default()
820            },
821            hardware_requirements: HardwareRequirements {
822                min_memory_gb: 2.0,
823                recommended_cores: 4,
824                gpu_acceleration: false,
825                quantum_hardware: false,
826            },
827            optimization_hints: vec![OptimizationHint::HighPrecision],
828        }
829    }
830
831    fn constraints(&self) -> Vec<IndustryConstraint> {
832        let mut constraints = vec![IndustryConstraint::Budget {
833            limit: self.inner.budget,
834        }];
835
836        // Add regulatory constraints if any
837        constraints.extend(self.inner.regulatory_constraints.clone());
838
839        constraints
840    }
841
842    fn objective(&self) -> IndustryObjective {
843        IndustryObjective::MultiObjective(vec![
844            (IndustryObjective::MaximizeProfit, 1.0),
845            (IndustryObjective::MinimizeRisk, self.inner.risk_tolerance),
846        ])
847    }
848
849    fn solution_bounds(&self) -> Option<(f64, f64)> {
850        // Rough bounds based on expected returns and risk
851        let max_return: f64 = self.inner.expected_returns.iter().sum();
852        let min_return = self
853            .inner
854            .expected_returns
855            .iter()
856            .fold(0.0f64, |a, &b| a.min(b));
857        Some((min_return, max_return))
858    }
859
860    fn as_any(&self) -> &dyn Any {
861        self
862    }
863
864    fn clone_unified(&self) -> Box<dyn UnifiedProblem> {
865        Box::new(self.clone())
866    }
867}
868
869// Implement OptimizationProblem for other wrapper types
870impl OptimizationProblem for UnifiedVehicleRoutingProblem {
871    type Solution = UnifiedSolution;
872    type ObjectiveValue = f64;
873
874    fn description(&self) -> String {
875        self.inner.description()
876    }
877
878    fn size_metrics(&self) -> HashMap<String, usize> {
879        self.inner.size_metrics()
880    }
881
882    fn validate(&self) -> ApplicationResult<()> {
883        self.inner.validate()
884    }
885
886    fn to_qubo(&self) -> ApplicationResult<(crate::ising::QuboModel, HashMap<String, usize>)> {
887        self.inner.to_qubo()
888    }
889
890    fn evaluate_solution(
891        &self,
892        solution: &Self::Solution,
893    ) -> ApplicationResult<Self::ObjectiveValue> {
894        match solution {
895            UnifiedSolution::Binary(binary_sol) => {
896                // Simple conversion for VRP - treat as route assignments
897                let route: Vec<usize> = binary_sol
898                    .iter()
899                    .enumerate()
900                    .filter(|(_, &x)| x == 1)
901                    .map(|(i, _)| i)
902                    .collect();
903                let route_stats = logistics::RouteStatistics {
904                    vehicle_id: 0,
905                    distance: 0.0,
906                    duration: 0.0,
907                    capacity_utilization: 0.5,
908                    customers_served: route.len(),
909                    time_violations: 0,
910                };
911                let route_sol = logistics::VehicleRoutingSolution {
912                    routes: vec![route],
913                    total_distance: 0.0,
914                    total_cost: 0.0,
915                    route_stats: vec![route_stats],
916                };
917                self.inner.evaluate_solution(&route_sol)
918            }
919            _ => Err(ApplicationError::OptimizationError(
920                "Unsupported solution type for VRP".to_string(),
921            )),
922        }
923    }
924
925    fn is_feasible(&self, solution: &Self::Solution) -> bool {
926        match solution {
927            UnifiedSolution::Binary(binary_sol) => {
928                let route: Vec<usize> = binary_sol
929                    .iter()
930                    .enumerate()
931                    .filter(|(_, &x)| x == 1)
932                    .map(|(i, _)| i)
933                    .collect();
934                let route_stats = logistics::RouteStatistics {
935                    vehicle_id: 0,
936                    distance: 0.0,
937                    duration: 0.0,
938                    capacity_utilization: 0.5,
939                    customers_served: route.len(),
940                    time_violations: 0,
941                };
942                let route_sol = logistics::VehicleRoutingSolution {
943                    routes: vec![route],
944                    total_distance: 0.0,
945                    total_cost: 0.0,
946                    route_stats: vec![route_stats],
947                };
948                self.inner.is_feasible(&route_sol)
949            }
950            _ => false,
951        }
952    }
953}
954
955impl UnifiedProblem for UnifiedVehicleRoutingProblem {
956    fn category(&self) -> ProblemCategory {
957        ProblemCategory::Routing
958    }
959
960    fn industry(&self) -> &'static str {
961        "logistics"
962    }
963
964    fn complexity(&self) -> ProblemComplexity {
965        let num_locations = self.inner.locations.len();
966        match num_locations {
967            0..=20 => ProblemComplexity::Small,
968            21..=100 => ProblemComplexity::Medium,
969            101..=500 => ProblemComplexity::Large,
970            _ => ProblemComplexity::ExtraLarge,
971        }
972    }
973
974    fn recommended_solver_config(&self) -> SolverConfiguration {
975        SolverConfiguration {
976            solver_type: SolverType::Hybrid,
977            annealing_params: AnnealingParams::default(),
978            hardware_requirements: HardwareRequirements {
979                min_memory_gb: 4.0,
980                recommended_cores: 8,
981                gpu_acceleration: true,
982                quantum_hardware: false,
983            },
984            optimization_hints: vec![OptimizationHint::MultiModal],
985        }
986    }
987
988    fn constraints(&self) -> Vec<IndustryConstraint> {
989        vec![IndustryConstraint::Capacity {
990            resource: "vehicle".to_string(),
991            limit: 100.0,
992        }]
993    }
994
995    fn objective(&self) -> IndustryObjective {
996        IndustryObjective::MinimizeCost
997    }
998
999    fn solution_bounds(&self) -> Option<(f64, f64)> {
1000        Some((0.0, 1000.0)) // Rough bounds for VRP cost
1001    }
1002
1003    fn as_any(&self) -> &dyn Any {
1004        self
1005    }
1006
1007    fn clone_unified(&self) -> Box<dyn UnifiedProblem> {
1008        Box::new(self.clone())
1009    }
1010}
1011
1012// Implement for other wrapper types with minimal implementations
1013impl OptimizationProblem for UnifiedNetworkTopologyOptimization {
1014    type Solution = UnifiedSolution;
1015    type ObjectiveValue = f64;
1016
1017    fn description(&self) -> String {
1018        self.inner.description()
1019    }
1020
1021    fn size_metrics(&self) -> HashMap<String, usize> {
1022        self.inner.size_metrics()
1023    }
1024
1025    fn validate(&self) -> ApplicationResult<()> {
1026        self.inner.validate()
1027    }
1028
1029    fn to_qubo(&self) -> ApplicationResult<(crate::ising::QuboModel, HashMap<String, usize>)> {
1030        self.inner.to_qubo()
1031    }
1032
1033    fn evaluate_solution(
1034        &self,
1035        solution: &Self::Solution,
1036    ) -> ApplicationResult<Self::ObjectiveValue> {
1037        match solution {
1038            UnifiedSolution::Binary(binary_sol) => {
1039                let network_topology = telecommunications::NetworkTopology {
1040                    active_connections: binary_sol.iter().map(|&x| x == 1).collect(),
1041                    total_cost: 0.0,
1042                    connectivity: 0.8,
1043                    average_latency: 10.0,
1044                    performance_metrics: telecommunications::TelecomMetrics {
1045                        throughput: 10.0,
1046                        packet_loss_rate: 0.01,
1047                        jitter: 5.0,
1048                        availability: 0.99,
1049                        mtbf: 1000.0,
1050                        coverage_area: 100.0,
1051                    },
1052                };
1053                self.inner.evaluate_solution(&network_topology)
1054            }
1055            _ => Err(ApplicationError::OptimizationError(
1056                "Unsupported solution type for network optimization".to_string(),
1057            )),
1058        }
1059    }
1060
1061    fn is_feasible(&self, solution: &Self::Solution) -> bool {
1062        match solution {
1063            UnifiedSolution::Binary(binary_sol) => {
1064                let network_topology = telecommunications::NetworkTopology {
1065                    active_connections: binary_sol.iter().map(|&x| x == 1).collect(),
1066                    total_cost: 0.0,
1067                    connectivity: 0.8,
1068                    average_latency: 10.0,
1069                    performance_metrics: telecommunications::TelecomMetrics {
1070                        throughput: 10.0,
1071                        packet_loss_rate: 0.01,
1072                        jitter: 5.0,
1073                        availability: 0.99,
1074                        mtbf: 1000.0,
1075                        coverage_area: 100.0,
1076                    },
1077                };
1078                self.inner.is_feasible(&network_topology)
1079            }
1080            _ => false,
1081        }
1082    }
1083}
1084
1085impl UnifiedProblem for UnifiedNetworkTopologyOptimization {
1086    fn category(&self) -> ProblemCategory {
1087        ProblemCategory::NetworkDesign
1088    }
1089
1090    fn industry(&self) -> &'static str {
1091        "telecommunications"
1092    }
1093
1094    fn complexity(&self) -> ProblemComplexity {
1095        ProblemComplexity::Medium // Default complexity
1096    }
1097
1098    fn recommended_solver_config(&self) -> SolverConfiguration {
1099        SolverConfiguration {
1100            solver_type: SolverType::QuantumSimulator,
1101            annealing_params: AnnealingParams::default(),
1102            hardware_requirements: HardwareRequirements {
1103                min_memory_gb: 8.0,
1104                recommended_cores: 16,
1105                gpu_acceleration: true,
1106                quantum_hardware: false,
1107            },
1108            optimization_hints: vec![OptimizationHint::SparseStructure],
1109        }
1110    }
1111
1112    fn constraints(&self) -> Vec<IndustryConstraint> {
1113        vec![]
1114    }
1115
1116    fn objective(&self) -> IndustryObjective {
1117        IndustryObjective::MinimizeCost
1118    }
1119
1120    fn solution_bounds(&self) -> Option<(f64, f64)> {
1121        Some((0.0, 500.0))
1122    }
1123
1124    fn as_any(&self) -> &dyn Any {
1125        self
1126    }
1127
1128    fn clone_unified(&self) -> Box<dyn UnifiedProblem> {
1129        Box::new(self.clone())
1130    }
1131}
1132
1133// Placeholder implementations for other wrapper types
1134impl OptimizationProblem for UnifiedEnergyGridOptimization {
1135    type Solution = UnifiedSolution;
1136    type ObjectiveValue = f64;
1137
1138    fn description(&self) -> String {
1139        "Energy grid optimization problem".to_string()
1140    }
1141
1142    fn size_metrics(&self) -> HashMap<String, usize> {
1143        HashMap::new()
1144    }
1145
1146    fn validate(&self) -> ApplicationResult<()> {
1147        Ok(())
1148    }
1149
1150    fn to_qubo(&self) -> ApplicationResult<(crate::ising::QuboModel, HashMap<String, usize>)> {
1151        Err(ApplicationError::OptimizationError(
1152            "Energy grid QUBO not implemented".to_string(),
1153        ))
1154    }
1155
1156    fn evaluate_solution(
1157        &self,
1158        _solution: &Self::Solution,
1159    ) -> ApplicationResult<Self::ObjectiveValue> {
1160        Ok(0.0)
1161    }
1162
1163    fn is_feasible(&self, _solution: &Self::Solution) -> bool {
1164        true
1165    }
1166}
1167
1168impl UnifiedProblem for UnifiedEnergyGridOptimization {
1169    fn category(&self) -> ProblemCategory {
1170        ProblemCategory::ResourceAllocation
1171    }
1172
1173    fn industry(&self) -> &'static str {
1174        "energy"
1175    }
1176
1177    fn complexity(&self) -> ProblemComplexity {
1178        ProblemComplexity::Medium
1179    }
1180
1181    fn recommended_solver_config(&self) -> SolverConfiguration {
1182        SolverConfiguration {
1183            solver_type: SolverType::Classical,
1184            annealing_params: AnnealingParams::default(),
1185            hardware_requirements: HardwareRequirements {
1186                min_memory_gb: 4.0,
1187                recommended_cores: 8,
1188                gpu_acceleration: false,
1189                quantum_hardware: false,
1190            },
1191            optimization_hints: vec![],
1192        }
1193    }
1194
1195    fn constraints(&self) -> Vec<IndustryConstraint> {
1196        vec![]
1197    }
1198
1199    fn objective(&self) -> IndustryObjective {
1200        IndustryObjective::MinimizeCost
1201    }
1202
1203    fn solution_bounds(&self) -> Option<(f64, f64)> {
1204        Some((0.0, 100.0))
1205    }
1206
1207    fn as_any(&self) -> &dyn Any {
1208        self
1209    }
1210
1211    fn clone_unified(&self) -> Box<dyn UnifiedProblem> {
1212        Box::new(self.clone())
1213    }
1214}
1215
1216impl OptimizationProblem for UnifiedManufacturingScheduling {
1217    type Solution = UnifiedSolution;
1218    type ObjectiveValue = f64;
1219
1220    fn description(&self) -> String {
1221        "Manufacturing scheduling problem".to_string()
1222    }
1223
1224    fn size_metrics(&self) -> HashMap<String, usize> {
1225        HashMap::new()
1226    }
1227
1228    fn validate(&self) -> ApplicationResult<()> {
1229        Ok(())
1230    }
1231
1232    fn to_qubo(&self) -> ApplicationResult<(crate::ising::QuboModel, HashMap<String, usize>)> {
1233        Err(ApplicationError::OptimizationError(
1234            "Manufacturing QUBO not implemented".to_string(),
1235        ))
1236    }
1237
1238    fn evaluate_solution(
1239        &self,
1240        _solution: &Self::Solution,
1241    ) -> ApplicationResult<Self::ObjectiveValue> {
1242        Ok(0.0)
1243    }
1244
1245    fn is_feasible(&self, _solution: &Self::Solution) -> bool {
1246        true
1247    }
1248}
1249
1250impl UnifiedProblem for UnifiedManufacturingScheduling {
1251    fn category(&self) -> ProblemCategory {
1252        ProblemCategory::ResourceAllocation
1253    }
1254
1255    fn industry(&self) -> &'static str {
1256        "manufacturing"
1257    }
1258
1259    fn complexity(&self) -> ProblemComplexity {
1260        ProblemComplexity::Medium
1261    }
1262
1263    fn recommended_solver_config(&self) -> SolverConfiguration {
1264        SolverConfiguration {
1265            solver_type: SolverType::Classical,
1266            annealing_params: AnnealingParams::default(),
1267            hardware_requirements: HardwareRequirements {
1268                min_memory_gb: 2.0,
1269                recommended_cores: 4,
1270                gpu_acceleration: false,
1271                quantum_hardware: false,
1272            },
1273            optimization_hints: vec![],
1274        }
1275    }
1276
1277    fn constraints(&self) -> Vec<IndustryConstraint> {
1278        vec![]
1279    }
1280
1281    fn objective(&self) -> IndustryObjective {
1282        IndustryObjective::MaximizeEfficiency
1283    }
1284
1285    fn solution_bounds(&self) -> Option<(f64, f64)> {
1286        Some((0.0, 100.0))
1287    }
1288
1289    fn as_any(&self) -> &dyn Any {
1290        self
1291    }
1292
1293    fn clone_unified(&self) -> Box<dyn UnifiedProblem> {
1294        Box::new(self.clone())
1295    }
1296}
1297
1298impl OptimizationProblem for UnifiedHealthcareResourceOptimization {
1299    type Solution = UnifiedSolution;
1300    type ObjectiveValue = f64;
1301
1302    fn description(&self) -> String {
1303        "Healthcare resource optimization problem".to_string()
1304    }
1305
1306    fn size_metrics(&self) -> HashMap<String, usize> {
1307        HashMap::new()
1308    }
1309
1310    fn validate(&self) -> ApplicationResult<()> {
1311        Ok(())
1312    }
1313
1314    fn to_qubo(&self) -> ApplicationResult<(crate::ising::QuboModel, HashMap<String, usize>)> {
1315        Err(ApplicationError::OptimizationError(
1316            "Healthcare QUBO not implemented".to_string(),
1317        ))
1318    }
1319
1320    fn evaluate_solution(
1321        &self,
1322        _solution: &Self::Solution,
1323    ) -> ApplicationResult<Self::ObjectiveValue> {
1324        Ok(0.0)
1325    }
1326
1327    fn is_feasible(&self, _solution: &Self::Solution) -> bool {
1328        true
1329    }
1330}
1331
1332impl UnifiedProblem for UnifiedHealthcareResourceOptimization {
1333    fn category(&self) -> ProblemCategory {
1334        ProblemCategory::ResourceAllocation
1335    }
1336
1337    fn industry(&self) -> &'static str {
1338        "healthcare"
1339    }
1340
1341    fn complexity(&self) -> ProblemComplexity {
1342        ProblemComplexity::Medium
1343    }
1344
1345    fn recommended_solver_config(&self) -> SolverConfiguration {
1346        SolverConfiguration {
1347            solver_type: SolverType::Classical,
1348            annealing_params: AnnealingParams::default(),
1349            hardware_requirements: HardwareRequirements {
1350                min_memory_gb: 2.0,
1351                recommended_cores: 4,
1352                gpu_acceleration: false,
1353                quantum_hardware: false,
1354            },
1355            optimization_hints: vec![],
1356        }
1357    }
1358
1359    fn constraints(&self) -> Vec<IndustryConstraint> {
1360        vec![]
1361    }
1362
1363    fn objective(&self) -> IndustryObjective {
1364        IndustryObjective::MaximizeEfficiency
1365    }
1366
1367    fn solution_bounds(&self) -> Option<(f64, f64)> {
1368        Some((0.0, 100.0))
1369    }
1370
1371    fn as_any(&self) -> &dyn Any {
1372        self
1373    }
1374
1375    fn clone_unified(&self) -> Box<dyn UnifiedProblem> {
1376        Box::new(self.clone())
1377    }
1378}
1379
1380/// Performance benchmarking for the unified solver
1381pub fn run_unified_benchmark(
1382    factory: &UnifiedSolverFactory,
1383    industry: &str,
1384    problem_sizes: Vec<usize>,
1385) -> ApplicationResult<UnifiedBenchmarkResults> {
1386    let mut results = UnifiedBenchmarkResults::new();
1387
1388    for size in problem_sizes {
1389        // Create benchmark problems
1390        let problems = super::create_benchmark_suite(industry, &format!("{size}"))?;
1391
1392        for (i, problem) in problems.iter().enumerate() {
1393            let start_time = std::time::Instant::now();
1394
1395            // This would require converting to UnifiedProblem
1396            // For now, placeholder measurement
1397            let solve_time = start_time.elapsed().as_secs_f64() * 1000.0;
1398
1399            results.add_result(
1400                format!("{industry}_{size}_problem_{i}"),
1401                solve_time,
1402                0.0,
1403                true,
1404            );
1405        }
1406    }
1407
1408    Ok(results)
1409}
1410
1411/// Benchmark results for unified solver performance
1412#[derive(Debug, Clone)]
1413pub struct UnifiedBenchmarkResults {
1414    /// Results by problem identifier
1415    pub results: HashMap<String, BenchmarkResult>,
1416    /// Overall statistics
1417    pub statistics: BenchmarkStatistics,
1418}
1419
1420impl UnifiedBenchmarkResults {
1421    fn new() -> Self {
1422        Self {
1423            results: HashMap::new(),
1424            statistics: BenchmarkStatistics::default(),
1425        }
1426    }
1427
1428    fn add_result(
1429        &mut self,
1430        problem_id: String,
1431        solve_time: f64,
1432        objective_value: f64,
1433        converged: bool,
1434    ) {
1435        let result = BenchmarkResult {
1436            solve_time_ms: solve_time,
1437            objective_value,
1438            converged,
1439        };
1440
1441        self.results.insert(problem_id, result);
1442        self.update_statistics();
1443    }
1444
1445    fn update_statistics(&mut self) {
1446        let solve_times: Vec<f64> = self.results.values().map(|r| r.solve_time_ms).collect();
1447        let convergence_rate = self.results.values().filter(|r| r.converged).count() as f64
1448            / self.results.len() as f64;
1449
1450        self.statistics = BenchmarkStatistics {
1451            avg_solve_time: solve_times.iter().sum::<f64>() / solve_times.len() as f64,
1452            min_solve_time: solve_times.iter().fold(f64::INFINITY, |a, &b| a.min(b)),
1453            max_solve_time: solve_times.iter().fold(0.0, |a, &b| a.max(b)),
1454            convergence_rate,
1455            total_problems_solved: self.results.len(),
1456        };
1457    }
1458}
1459
1460/// Individual benchmark result
1461#[derive(Debug, Clone)]
1462pub struct BenchmarkResult {
1463    pub solve_time_ms: f64,
1464    pub objective_value: f64,
1465    pub converged: bool,
1466}
1467
1468/// Overall benchmark statistics
1469#[derive(Debug, Clone, Default)]
1470pub struct BenchmarkStatistics {
1471    pub avg_solve_time: f64,
1472    pub min_solve_time: f64,
1473    pub max_solve_time: f64,
1474    pub convergence_rate: f64,
1475    pub total_problems_solved: usize,
1476}
1477
1478#[cfg(test)]
1479mod tests {
1480    use super::*;
1481    use serde_json::json;
1482
1483    #[test]
1484    fn test_solver_factory_creation() {
1485        let factory = UnifiedSolverFactory::new();
1486        assert!(!factory.default_configs.is_empty());
1487        assert!(factory.available_solvers.contains(&SolverType::Classical));
1488    }
1489
1490    #[test]
1491    fn test_problem_creation() {
1492        let factory = UnifiedSolverFactory::new();
1493        let config = HashMap::from([
1494            ("num_assets".to_string(), json!(5)),
1495            ("budget".to_string(), json!(100_000.0)),
1496            ("risk_tolerance".to_string(), json!(0.3)),
1497        ]);
1498
1499        let problem = factory.create_problem("finance", "portfolio", config);
1500        assert!(problem.is_ok());
1501
1502        let unified_problem = problem.expect("problem creation should succeed");
1503        assert_eq!(unified_problem.industry(), "finance");
1504        assert_eq!(unified_problem.category(), ProblemCategory::Portfolio);
1505    }
1506
1507    #[test]
1508    fn test_complexity_classification() {
1509        let factory = UnifiedSolverFactory::new();
1510        let config = HashMap::from([("num_assets".to_string(), json!(5))]);
1511
1512        let problem = factory
1513            .create_problem("finance", "portfolio", config)
1514            .expect("problem creation should succeed");
1515        assert_eq!(problem.complexity(), ProblemComplexity::Small);
1516    }
1517
1518    #[test]
1519    fn test_solver_configuration_adjustment() {
1520        let factory = UnifiedSolverFactory::new();
1521        let mut config = SolverConfiguration {
1522            solver_type: SolverType::Classical,
1523            annealing_params: AnnealingParams::default(),
1524            hardware_requirements: HardwareRequirements {
1525                min_memory_gb: 1.0,
1526                recommended_cores: 2,
1527                gpu_acceleration: false,
1528                quantum_hardware: false,
1529            },
1530            optimization_hints: vec![],
1531        };
1532
1533        factory.adjust_config_for_complexity(&mut config, ProblemComplexity::Large);
1534        assert!(config.annealing_params.num_sweeps >= 20_000);
1535        assert!(config.hardware_requirements.min_memory_gb >= 2.0);
1536    }
1537}