use crate::error::Result;
use crate::nas_engine::{
MultiObjectiveConfig, ObjectiveConfig, ObjectiveType, OptimizationDirection,
OptimizerArchitecture, SearchResult,
};
use crate::EvaluationMetric;
use scirs2_core::numeric::Float;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::fmt::Debug;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CoverageMetrics<T: Float + Debug + Send + Sync + 'static> {
pub objective_space_coverage: T,
pub reference_distance: T,
pub epsilon_dominance: T,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum CreationMethod {
RandomGeneration,
Crossover,
Mutation,
LocalSearch,
Repair,
Custom,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FrontMetrics<T: Float + Debug + Send + Sync + 'static> {
pub hypervolume: T,
pub spread: T,
pub spacing: T,
pub convergence: T,
pub num_solutions: usize,
pub coverage: CoverageMetrics<T>,
}
#[derive(Debug, Clone)]
pub struct Individual<T: Float + Debug + Send + Sync + 'static> {
pub architecture: OptimizerArchitecture<T>,
pub objectives: Vec<T>,
pub constraints: Vec<T>,
pub rank: usize,
pub crowding_distance: T,
pub fitness: T,
pub id: String,
}
#[derive(Debug, Clone)]
pub struct MultiObjectiveStatistics<T: Float + Debug + Send + Sync + 'static> {
pub generation: usize,
pub total_evaluations: usize,
pub pareto_front_size: usize,
pub best_hypervolume: T,
pub convergence_history: Vec<T>,
pub diversity_history: Vec<T>,
pub algorithm_metrics: HashMap<String, T>,
}
impl<T: Float + Debug + Default + Send + Sync> Default for MultiObjectiveStatistics<T> {
fn default() -> Self {
Self {
generation: 0,
total_evaluations: 0,
pareto_front_size: 0,
best_hypervolume: T::zero(),
convergence_history: Vec::new(),
diversity_history: Vec::new(),
algorithm_metrics: HashMap::new(),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ObjectiveBounds<T: Float + Debug + Send + Sync + 'static> {
pub min_values: Vec<T>,
pub max_values: Vec<T>,
pub ideal_point: Vec<T>,
pub nadir_point: Vec<T>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ParetoFront<T: Float + Debug + Send + Sync + 'static> {
pub solutions: Vec<ParetoSolution<T>>,
pub objective_bounds: ObjectiveBounds<T>,
pub metrics: FrontMetrics<T>,
pub generation: usize,
pub last_updated: std::time::SystemTime,
}
impl<T: Float + Debug + Default + Send + Sync> ParetoFront<T> {
pub(super) fn new() -> Self {
Self {
solutions: Vec::new(),
objective_bounds: ObjectiveBounds {
min_values: Vec::new(),
max_values: Vec::new(),
ideal_point: Vec::new(),
nadir_point: Vec::new(),
},
metrics: FrontMetrics {
hypervolume: T::zero(),
spread: T::zero(),
spacing: T::zero(),
convergence: T::zero(),
num_solutions: 0,
coverage: CoverageMetrics {
objective_space_coverage: T::zero(),
reference_distance: T::zero(),
epsilon_dominance: T::zero(),
},
},
generation: 0,
last_updated: std::time::SystemTime::now(),
}
}
}
impl<T: Float + Debug + Default + Send + Sync> Default for ParetoFront<T> {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ParetoSolution<T: Float + Debug + Send + Sync + 'static> {
pub architecture: OptimizerArchitecture<T>,
pub objectives: Vec<T>,
pub constraint_violations: Vec<T>,
pub rank: usize,
pub crowding_distance: T,
pub metadata: SolutionMetadata,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SolutionMetadata {
pub id: String,
pub generation: usize,
pub evaluation_count: usize,
pub parents: Vec<String>,
pub creation_method: CreationMethod,
}
pub fn evaluation_metric_for_objective(objective_type: &ObjectiveType) -> EvaluationMetric {
match objective_type {
ObjectiveType::Accuracy => EvaluationMetric::Accuracy,
ObjectiveType::Loss => EvaluationMetric::FinalPerformance,
ObjectiveType::TrainingTime => EvaluationMetric::TrainingTime,
ObjectiveType::InferenceTime => EvaluationMetric::ComputationTime,
ObjectiveType::MemoryUsage => EvaluationMetric::MemoryUsage,
ObjectiveType::EnergyConsumption => EvaluationMetric::ComputationTime,
ObjectiveType::ModelSize => EvaluationMetric::MemoryUsage,
ObjectiveType::Performance => EvaluationMetric::FinalPerformance,
ObjectiveType::Efficiency => EvaluationMetric::ComputationalEfficiency,
ObjectiveType::Robustness => EvaluationMetric::Robustness,
ObjectiveType::Interpretability => EvaluationMetric::FinalPerformance,
ObjectiveType::Fairness => EvaluationMetric::FinalPerformance,
ObjectiveType::Privacy => EvaluationMetric::FinalPerformance,
ObjectiveType::Sustainability => EvaluationMetric::ComputationalEfficiency,
ObjectiveType::Cost => EvaluationMetric::ComputationalEfficiency,
ObjectiveType::Custom(_) => EvaluationMetric::FinalPerformance,
}
}
pub fn objective_vector_for_result<T: Float + Debug + Send + Sync + 'static>(
objectives: &[ObjectiveConfig<T>],
result: &SearchResult<T>,
) -> Vec<T> {
objectives
.iter()
.map(|objective| {
let metric = evaluation_metric_for_objective(&objective.objective_type);
result
.evaluation_results
.metric_scores
.get(&metric)
.copied()
.unwrap_or_else(T::zero)
})
.collect()
}
pub fn objective_directions<T: Float + Debug + Send + Sync + 'static>(
objectives: &[ObjectiveConfig<T>],
) -> Vec<OptimizationDirection> {
objectives
.iter()
.map(|objective| objective.direction.clone())
.collect()
}
pub trait MultiObjectiveOptimizer<T: Float + Debug + Send + Sync + 'static>: Send + Sync {
fn initialize(&mut self, config: &MultiObjectiveConfig<T>) -> Result<()>;
fn update_pareto_front(&mut self, results: &[SearchResult<T>]) -> Result<ParetoFront<T>>;
fn get_pareto_front(&self) -> &ParetoFront<T>;
fn select_candidates(
&mut self,
population: &[OptimizerArchitecture<T>],
objectives: &[T],
) -> Result<Vec<OptimizerArchitecture<T>>>;
fn name(&self) -> &str;
fn get_statistics(&self) -> MultiObjectiveStatistics<T>;
}