quantrs2_anneal/meta_learning/
portfolio.rs1use super::config::{
7 ActivationFunction, AlgorithmSelectionStrategy, AlgorithmType, ArchitectureSpec,
8 ConnectionPattern, DiversityCriteria, DiversityMethod, LayerSpec, LayerType,
9 OptimizationConfiguration, OptimizationSettings, OptimizerType, RegularizationConfig,
10 ResourceAllocation,
11};
12use super::features::ProblemFeatures;
13use crate::applications::ApplicationResult;
14use std::collections::{HashMap, VecDeque};
15use std::time::{Duration, Instant};
16
17pub struct AlgorithmPortfolio {
19 pub algorithms: HashMap<String, Algorithm>,
21 pub composition: PortfolioComposition,
23 pub selection_strategy: AlgorithmSelectionStrategy,
25 pub performance_history: HashMap<String, VecDeque<PerformanceRecord>>,
27 pub diversity_analyzer: DiversityAnalyzer,
29}
30
31#[derive(Debug)]
33pub struct Algorithm {
34 pub id: String,
36 pub algorithm_type: AlgorithmType,
38 pub default_config: OptimizationConfiguration,
40 pub performance_stats: AlgorithmPerformanceStats,
42 pub applicability: ApplicabilityConditions,
44}
45
46#[derive(Debug, Clone)]
48pub struct PortfolioComposition {
49 pub weights: HashMap<String, f64>,
51 pub selection_probabilities: HashMap<String, f64>,
53 pub last_update: Instant,
55 pub quality_score: f64,
57}
58
59#[derive(Debug, Clone)]
61pub struct PerformanceRecord {
62 pub timestamp: Instant,
64 pub problem_features: ProblemFeatures,
66 pub performance: f64,
68 pub resource_usage: ResourceUsage,
70 pub context: HashMap<String, String>,
72}
73
74#[derive(Debug, Clone)]
76pub struct ResourceUsage {
77 pub peak_cpu: f64,
79 pub peak_memory: usize,
81 pub gpu_utilization: f64,
83 pub energy_consumption: f64,
85}
86
87#[derive(Debug, Clone)]
89pub struct AlgorithmPerformanceStats {
90 pub mean_performance: f64,
92 pub performance_variance: f64,
94 pub success_rate: f64,
96 pub avg_runtime: Duration,
98 pub scalability_factor: f64,
100}
101
102#[derive(Debug, Clone)]
104pub struct ApplicabilityConditions {
105 pub size_range: (usize, usize),
107 pub suitable_domains: Vec<ProblemDomain>,
109 pub required_resources: ResourceRequirements,
111 pub performance_guarantees: Vec<PerformanceGuarantee>,
113}
114
115#[derive(Debug, Clone, PartialEq, Eq)]
117pub enum ProblemDomain {
118 Combinatorial,
120 Portfolio,
122 Scheduling,
124 Graph,
126 MachineLearning,
128 Physics,
130 Chemistry,
132 Custom(String),
134}
135
136#[derive(Debug, Clone, PartialEq)]
138pub struct ResourceRequirements {
139 pub memory: usize,
141 pub computation: f64,
143 pub training_time: Duration,
145 pub model_size: usize,
147}
148
149#[derive(Debug, Clone)]
151pub struct PerformanceGuarantee {
152 pub guarantee_type: GuaranteeType,
154 pub confidence: f64,
156 pub conditions: Vec<String>,
158}
159
160#[derive(Debug, Clone, PartialEq)]
162pub enum GuaranteeType {
163 MinimumPerformance(f64),
165 MaximumRuntime(Duration),
167 ResourceBounds(ResourceRequirements),
169 QualityBounds(f64, f64),
171}
172
173#[derive(Debug)]
175pub struct DiversityAnalyzer {
176 pub metrics: Vec<DiversityMetric>,
178 pub methods: Vec<DiversityMethod>,
180 pub current_diversity: f64,
182 pub target_diversity: f64,
184}
185
186#[derive(Debug, Clone, PartialEq, Eq)]
188pub enum DiversityMetric {
189 AlgorithmDiversity,
191 PerformanceDiversity,
193 FeatureDiversity,
195 ErrorDiversity,
197 PredictionDiversity,
199}
200
201impl AlgorithmPortfolio {
202 #[must_use]
203 pub fn new(config: super::config::PortfolioManagementConfig) -> Self {
204 Self {
205 algorithms: HashMap::new(),
206 composition: PortfolioComposition {
207 weights: HashMap::new(),
208 selection_probabilities: HashMap::new(),
209 last_update: Instant::now(),
210 quality_score: 0.8,
211 },
212 selection_strategy: config.selection_strategy,
213 performance_history: HashMap::new(),
214 diversity_analyzer: DiversityAnalyzer {
215 metrics: vec![DiversityMetric::AlgorithmDiversity],
216 methods: vec![DiversityMethod::KullbackLeibler],
217 current_diversity: 0.7,
218 target_diversity: 0.8,
219 },
220 }
221 }
222
223 pub fn select_algorithm(&self, features: &ProblemFeatures) -> ApplicationResult<String> {
225 let algorithm_id = if features.size < 100 {
227 "simulated_annealing"
228 } else if features.size < 500 {
229 "quantum_annealing"
230 } else {
231 "hybrid_approach"
232 };
233
234 Ok(algorithm_id.to_string())
235 }
236
237 pub fn update_portfolio(
239 &mut self,
240 algorithm_id: &str,
241 performance: f64,
242 features: &ProblemFeatures,
243 ) {
244 let record = PerformanceRecord {
246 timestamp: Instant::now(),
247 problem_features: features.clone(),
248 performance,
249 resource_usage: ResourceUsage {
250 peak_cpu: 0.8,
251 peak_memory: 512,
252 gpu_utilization: 0.0,
253 energy_consumption: 100.0,
254 },
255 context: HashMap::new(),
256 };
257
258 self.performance_history
259 .entry(algorithm_id.to_string())
260 .or_insert_with(VecDeque::new)
261 .push_back(record);
262
263 if let Some(history) = self.performance_history.get_mut(algorithm_id) {
265 if history.len() > 1000 {
266 history.pop_front();
267 }
268 }
269
270 self.update_composition_weights();
272 }
273
274 fn update_composition_weights(&mut self) {
276 for (algorithm_id, history) in &self.performance_history {
277 if !history.is_empty() {
278 let avg_performance: f64 =
279 history.iter().map(|record| record.performance).sum::<f64>()
280 / history.len() as f64;
281
282 self.composition
283 .weights
284 .insert(algorithm_id.clone(), avg_performance);
285 }
286 }
287
288 let total_weight: f64 = self.composition.weights.values().sum();
290 if total_weight > 0.0 {
291 for weight in self.composition.weights.values_mut() {
292 *weight /= total_weight;
293 }
294 }
295
296 self.composition.last_update = Instant::now();
297 }
298
299 pub fn get_statistics(&self) -> PortfolioStatistics {
301 let total_algorithms = self.algorithms.len();
302 let active_algorithms = self.composition.weights.len();
303 let avg_performance = if self.performance_history.is_empty() {
304 0.0
305 } else {
306 let total_records: usize = self
307 .performance_history
308 .values()
309 .map(std::collections::VecDeque::len)
310 .sum();
311
312 if total_records > 0 {
313 let total_performance: f64 = self
314 .performance_history
315 .values()
316 .flat_map(|history| history.iter())
317 .map(|record| record.performance)
318 .sum();
319 total_performance / total_records as f64
320 } else {
321 0.0
322 }
323 };
324
325 PortfolioStatistics {
326 total_algorithms,
327 active_algorithms,
328 avg_performance,
329 diversity_score: self.diversity_analyzer.current_diversity,
330 last_update: self.composition.last_update,
331 }
332 }
333}
334
335#[derive(Debug, Clone)]
337pub struct PortfolioStatistics {
338 pub total_algorithms: usize,
340 pub active_algorithms: usize,
342 pub avg_performance: f64,
344 pub diversity_score: f64,
346 pub last_update: Instant,
348}
349
350#[cfg(test)]
351mod tests {
352 use super::*;
353 use crate::meta_learning::config::*;
354
355 #[test]
356 fn test_portfolio_creation() {
357 let config = PortfolioManagementConfig::default();
358 let portfolio = AlgorithmPortfolio::new(config);
359
360 assert_eq!(portfolio.algorithms.len(), 0);
361 assert!(portfolio.composition.quality_score > 0.0);
362 }
363
364 #[test]
365 fn test_algorithm_selection() {
366 let config = PortfolioManagementConfig::default();
367 let portfolio = AlgorithmPortfolio::new(config);
368
369 let features = ProblemFeatures {
370 size: 50,
371 density: 0.3,
372 graph_features: crate::meta_learning::features::GraphFeatures::default(),
373 statistical_features: crate::meta_learning::features::StatisticalFeatures::default(),
374 spectral_features: crate::meta_learning::features::SpectralFeatures::default(),
375 domain_features: HashMap::new(),
376 };
377
378 let algorithm_id = portfolio.select_algorithm(&features);
379 assert!(algorithm_id.is_ok());
380 assert!(!algorithm_id
381 .expect("Algorithm selection should succeed")
382 .is_empty());
383 }
384
385 #[test]
386 fn test_portfolio_update() {
387 let config = PortfolioManagementConfig::default();
388 let mut portfolio = AlgorithmPortfolio::new(config);
389
390 let features = ProblemFeatures {
391 size: 100,
392 density: 0.5,
393 graph_features: crate::meta_learning::features::GraphFeatures::default(),
394 statistical_features: crate::meta_learning::features::StatisticalFeatures::default(),
395 spectral_features: crate::meta_learning::features::SpectralFeatures::default(),
396 domain_features: HashMap::new(),
397 };
398
399 portfolio.update_portfolio("test_algorithm", 0.9, &features);
400
401 assert!(portfolio.performance_history.contains_key("test_algorithm"));
402 assert_eq!(portfolio.performance_history["test_algorithm"].len(), 1);
403 }
404
405 #[test]
406 fn test_portfolio_statistics() {
407 let config = PortfolioManagementConfig::default();
408 let portfolio = AlgorithmPortfolio::new(config);
409
410 let stats = portfolio.get_statistics();
411 assert_eq!(stats.total_algorithms, 0);
412 assert_eq!(stats.active_algorithms, 0);
413 }
414}