quantrs2_device/unified_benchmarking/
optimization.rs1use serde::{Deserialize, Serialize};
4use std::collections::{HashMap, VecDeque};
5use std::time::SystemTime;
6
7use super::results::{OptimizationResult, UnifiedBenchmarkResult};
8
9pub struct OptimizationEngine {
11 objective_functions: HashMap<String, Box<dyn Fn(&UnifiedBenchmarkResult) -> f64 + Send + Sync>>,
12 optimization_history: VecDeque<OptimizationResult>,
13 current_strategy: OptimizationStrategy,
14}
15
16#[derive(Debug, Clone, Serialize, Deserialize)]
17pub struct OptimizationStrategy {
18 pub strategy_name: String,
19 pub parameters: HashMap<String, f64>,
20 pub last_updated: SystemTime,
21 pub effectiveness_score: f64,
22}
23
24impl Default for OptimizationEngine {
25 fn default() -> Self {
26 Self::new()
27 }
28}
29
30impl OptimizationEngine {
31 pub fn new() -> Self {
32 Self {
33 objective_functions: HashMap::new(),
34 optimization_history: VecDeque::new(),
35 current_strategy: OptimizationStrategy {
36 strategy_name: "default".to_string(),
37 parameters: HashMap::new(),
38 last_updated: SystemTime::now(),
39 effectiveness_score: 0.0,
40 },
41 }
42 }
43
44 pub fn register_objective<F>(&mut self, name: impl Into<String>, f: F)
48 where
49 F: Fn(&UnifiedBenchmarkResult) -> f64 + Send + Sync + 'static,
50 {
51 self.objective_functions.insert(name.into(), Box::new(f));
52 }
53
54 pub fn optimize(&mut self, result: &UnifiedBenchmarkResult) -> Vec<OptimizationResult> {
63 let mut new_results: Vec<OptimizationResult> = Vec::new();
64
65 let start = std::time::Instant::now();
66
67 for (name, func) in &self.objective_functions {
68 let score = func(result);
69
70 let best_historical = self
72 .optimization_history
73 .iter()
74 .filter(|r| r.objective_function == *name)
75 .map(|r| r.optimal_value)
76 .fold(f64::NEG_INFINITY, f64::max);
77
78 let improvement = if best_historical.is_finite() {
79 score - best_historical
80 } else {
81 0.0
82 };
83
84 let opt_result = OptimizationResult {
85 objective_function: name.clone(),
86 optimal_solution: vec![score],
87 optimal_value: score,
88 convergence_history: vec![score],
89 optimization_time: start.elapsed(),
90 };
91 new_results.push(opt_result.clone());
92 self.optimization_history.push_back(opt_result);
93 }
94
95 while self.optimization_history.len() > 10_000 {
97 self.optimization_history.pop_front();
98 }
99
100 let n = new_results.len();
102 if n > 0 {
103 let total_improvement: f64 = new_results.iter().map(|r| r.optimal_value).sum();
104 self.current_strategy.effectiveness_score = total_improvement / n as f64;
105 self.current_strategy.last_updated = SystemTime::now();
106 }
107
108 new_results
109 }
110
111 pub fn current_strategy(&self) -> &OptimizationStrategy {
113 &self.current_strategy
114 }
115
116 pub fn history(&self) -> &VecDeque<OptimizationResult> {
118 &self.optimization_history
119 }
120}
121
122#[cfg(test)]
123mod tests {
124 use super::*;
125
126 #[test]
127 fn test_new_engine_has_empty_history() {
128 let engine = OptimizationEngine::new();
129 assert!(
130 engine.history().is_empty(),
131 "new engine must have empty history"
132 );
133 }
134
135 #[test]
136 fn test_default_engine_matches_new() {
137 let e1 = OptimizationEngine::new();
138 let e2 = OptimizationEngine::default();
139 assert_eq!(
140 e1.current_strategy().strategy_name,
141 e2.current_strategy().strategy_name,
142 );
143 }
144
145 #[test]
146 fn test_register_objective_increases_objective_count() {
147 let mut engine = OptimizationEngine::new();
148 assert_eq!(engine.objective_functions.len(), 0);
149 engine.register_objective("test_obj", |_| 1.0);
150 assert_eq!(engine.objective_functions.len(), 1);
151 }
152
153 #[test]
154 fn test_current_strategy_initial_effectiveness() {
155 let engine = OptimizationEngine::new();
156 assert_eq!(
157 engine.current_strategy().effectiveness_score,
158 0.0,
159 "initial effectiveness_score must be 0"
160 );
161 }
162}