use super::config::{
ActivationFunction, AlgorithmSelectionStrategy, AlgorithmType, ArchitectureSpec,
ConnectionPattern, DiversityCriteria, DiversityMethod, LayerSpec, LayerType,
OptimizationConfiguration, OptimizationSettings, OptimizerType, RegularizationConfig,
ResourceAllocation,
};
use super::features::ProblemFeatures;
use crate::applications::ApplicationResult;
use std::collections::{HashMap, VecDeque};
use std::time::{Duration, Instant};
pub struct AlgorithmPortfolio {
pub algorithms: HashMap<String, Algorithm>,
pub composition: PortfolioComposition,
pub selection_strategy: AlgorithmSelectionStrategy,
pub performance_history: HashMap<String, VecDeque<PerformanceRecord>>,
pub diversity_analyzer: DiversityAnalyzer,
}
#[derive(Debug)]
pub struct Algorithm {
pub id: String,
pub algorithm_type: AlgorithmType,
pub default_config: OptimizationConfiguration,
pub performance_stats: AlgorithmPerformanceStats,
pub applicability: ApplicabilityConditions,
}
#[derive(Debug, Clone)]
pub struct PortfolioComposition {
pub weights: HashMap<String, f64>,
pub selection_probabilities: HashMap<String, f64>,
pub last_update: Instant,
pub quality_score: f64,
}
#[derive(Debug, Clone)]
pub struct PerformanceRecord {
pub timestamp: Instant,
pub problem_features: ProblemFeatures,
pub performance: f64,
pub resource_usage: ResourceUsage,
pub context: HashMap<String, String>,
}
#[derive(Debug, Clone)]
pub struct ResourceUsage {
pub peak_cpu: f64,
pub peak_memory: usize,
pub gpu_utilization: f64,
pub energy_consumption: f64,
}
#[derive(Debug, Clone)]
pub struct AlgorithmPerformanceStats {
pub mean_performance: f64,
pub performance_variance: f64,
pub success_rate: f64,
pub avg_runtime: Duration,
pub scalability_factor: f64,
}
#[derive(Debug, Clone)]
pub struct ApplicabilityConditions {
pub size_range: (usize, usize),
pub suitable_domains: Vec<ProblemDomain>,
pub required_resources: ResourceRequirements,
pub performance_guarantees: Vec<PerformanceGuarantee>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ProblemDomain {
Combinatorial,
Portfolio,
Scheduling,
Graph,
MachineLearning,
Physics,
Chemistry,
Custom(String),
}
#[derive(Debug, Clone, PartialEq)]
pub struct ResourceRequirements {
pub memory: usize,
pub computation: f64,
pub training_time: Duration,
pub model_size: usize,
}
#[derive(Debug, Clone)]
pub struct PerformanceGuarantee {
pub guarantee_type: GuaranteeType,
pub confidence: f64,
pub conditions: Vec<String>,
}
#[derive(Debug, Clone, PartialEq)]
pub enum GuaranteeType {
MinimumPerformance(f64),
MaximumRuntime(Duration),
ResourceBounds(ResourceRequirements),
QualityBounds(f64, f64),
}
#[derive(Debug)]
pub struct DiversityAnalyzer {
pub metrics: Vec<DiversityMetric>,
pub methods: Vec<DiversityMethod>,
pub current_diversity: f64,
pub target_diversity: f64,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum DiversityMetric {
AlgorithmDiversity,
PerformanceDiversity,
FeatureDiversity,
ErrorDiversity,
PredictionDiversity,
}
impl AlgorithmPortfolio {
#[must_use]
pub fn new(config: super::config::PortfolioManagementConfig) -> Self {
Self {
algorithms: HashMap::new(),
composition: PortfolioComposition {
weights: HashMap::new(),
selection_probabilities: HashMap::new(),
last_update: Instant::now(),
quality_score: 0.8,
},
selection_strategy: config.selection_strategy,
performance_history: HashMap::new(),
diversity_analyzer: DiversityAnalyzer {
metrics: vec![DiversityMetric::AlgorithmDiversity],
methods: vec![DiversityMethod::KullbackLeibler],
current_diversity: 0.7,
target_diversity: 0.8,
},
}
}
pub fn select_algorithm(&self, features: &ProblemFeatures) -> ApplicationResult<String> {
let algorithm_id = if features.size < 100 {
"simulated_annealing"
} else if features.size < 500 {
"quantum_annealing"
} else {
"hybrid_approach"
};
Ok(algorithm_id.to_string())
}
pub fn update_portfolio(
&mut self,
algorithm_id: &str,
performance: f64,
features: &ProblemFeatures,
) {
let record = PerformanceRecord {
timestamp: Instant::now(),
problem_features: features.clone(),
performance,
resource_usage: ResourceUsage {
peak_cpu: 0.8,
peak_memory: 512,
gpu_utilization: 0.0,
energy_consumption: 100.0,
},
context: HashMap::new(),
};
self.performance_history
.entry(algorithm_id.to_string())
.or_insert_with(VecDeque::new)
.push_back(record);
if let Some(history) = self.performance_history.get_mut(algorithm_id) {
if history.len() > 1000 {
history.pop_front();
}
}
self.update_composition_weights();
}
fn update_composition_weights(&mut self) {
for (algorithm_id, history) in &self.performance_history {
if !history.is_empty() {
let avg_performance: f64 =
history.iter().map(|record| record.performance).sum::<f64>()
/ history.len() as f64;
self.composition
.weights
.insert(algorithm_id.clone(), avg_performance);
}
}
let total_weight: f64 = self.composition.weights.values().sum();
if total_weight > 0.0 {
for weight in self.composition.weights.values_mut() {
*weight /= total_weight;
}
}
self.composition.last_update = Instant::now();
}
pub fn get_statistics(&self) -> PortfolioStatistics {
let total_algorithms = self.algorithms.len();
let active_algorithms = self.composition.weights.len();
let avg_performance = if self.performance_history.is_empty() {
0.0
} else {
let total_records: usize = self
.performance_history
.values()
.map(std::collections::VecDeque::len)
.sum();
if total_records > 0 {
let total_performance: f64 = self
.performance_history
.values()
.flat_map(|history| history.iter())
.map(|record| record.performance)
.sum();
total_performance / total_records as f64
} else {
0.0
}
};
PortfolioStatistics {
total_algorithms,
active_algorithms,
avg_performance,
diversity_score: self.diversity_analyzer.current_diversity,
last_update: self.composition.last_update,
}
}
}
#[derive(Debug, Clone)]
pub struct PortfolioStatistics {
pub total_algorithms: usize,
pub active_algorithms: usize,
pub avg_performance: f64,
pub diversity_score: f64,
pub last_update: Instant,
}
#[cfg(test)]
mod tests {
use super::*;
use crate::meta_learning::config::*;
#[test]
fn test_portfolio_creation() {
let config = PortfolioManagementConfig::default();
let portfolio = AlgorithmPortfolio::new(config);
assert_eq!(portfolio.algorithms.len(), 0);
assert!(portfolio.composition.quality_score > 0.0);
}
#[test]
fn test_algorithm_selection() {
let config = PortfolioManagementConfig::default();
let portfolio = AlgorithmPortfolio::new(config);
let features = ProblemFeatures {
size: 50,
density: 0.3,
graph_features: crate::meta_learning::features::GraphFeatures::default(),
statistical_features: crate::meta_learning::features::StatisticalFeatures::default(),
spectral_features: crate::meta_learning::features::SpectralFeatures::default(),
domain_features: HashMap::new(),
};
let algorithm_id = portfolio.select_algorithm(&features);
assert!(algorithm_id.is_ok());
assert!(!algorithm_id
.expect("Algorithm selection should succeed")
.is_empty());
}
#[test]
fn test_portfolio_update() {
let config = PortfolioManagementConfig::default();
let mut portfolio = AlgorithmPortfolio::new(config);
let features = ProblemFeatures {
size: 100,
density: 0.5,
graph_features: crate::meta_learning::features::GraphFeatures::default(),
statistical_features: crate::meta_learning::features::StatisticalFeatures::default(),
spectral_features: crate::meta_learning::features::SpectralFeatures::default(),
domain_features: HashMap::new(),
};
portfolio.update_portfolio("test_algorithm", 0.9, &features);
assert!(portfolio.performance_history.contains_key("test_algorithm"));
assert_eq!(portfolio.performance_history["test_algorithm"].len(), 1);
}
#[test]
fn test_portfolio_statistics() {
let config = PortfolioManagementConfig::default();
let portfolio = AlgorithmPortfolio::new(config);
let stats = portfolio.get_statistics();
assert_eq!(stats.total_algorithms, 0);
assert_eq!(stats.active_algorithms, 0);
}
}