use std::collections::HashMap;
use super::architecture::ArchitectureCandidate;
pub struct PopulationManager<T: scirs2_core::numeric::Float> {
pub population: Vec<ArchitectureCandidate>,
pub config: PopulationConfig,
pub generation: usize,
pub stats: PopulationStats<T>,
}
#[derive(Debug, Clone)]
pub struct PopulationConfig {
pub size: usize,
pub elite_size: usize,
pub maintain_diversity: bool,
pub min_diversity: f64,
pub max_generations: usize,
}
#[derive(Debug, Clone)]
pub struct PopulationStats<T: scirs2_core::numeric::Float> {
pub best_fitness: T,
pub avg_fitness: T,
pub worst_fitness: T,
pub diversity: DiversityMetrics,
pub fitness_variance: T,
}
#[derive(Debug, Clone, Default)]
pub struct DiversityMetrics {
pub structural: f64,
pub behavioral: f64,
pub genetic: f64,
}
impl<T: scirs2_core::numeric::Float + Default + std::fmt::Debug + Send + Sync> PopulationManager<T> {
pub fn new(config: PopulationConfig) -> Self {
Self {
population: Vec::with_capacity(config.size),
config,
generation: 0,
stats: PopulationStats::default(),
}
}
pub fn initialize(&mut self, search_space: &super::space::ArchitectureSearchSpace) {
self.population.clear();
for i in 0..self.config.size {
let arch = search_space.sample_random();
let candidate = ArchitectureCandidate::new(format!("pop_init_{}", i), arch);
self.population.push(candidate);
}
self.update_statistics();
}
pub fn update_statistics(&mut self) {
if self.population.is_empty() {
return;
}
let fitnesses: Vec<T> = self.population
.iter()
.map(|c| scirs2_core::numeric::NumCast::from(c.performance.optimization_performance).unwrap_or_else(|| T::zero()))
.collect();
self.stats.best_fitness = fitnesses.iter().copied().fold(T::neg_infinity(), T::max);
self.stats.worst_fitness = fitnesses.iter().copied().fold(T::infinity(), T::min);
let sum = fitnesses.iter().fold(T::zero(), |acc, &x| acc + x);
self.stats.avg_fitness = sum / T::from(fitnesses.len()).expect("unwrap failed");
let mean = self.stats.avg_fitness;
let variance_sum = fitnesses.iter()
.map(|&x| (x - mean) * (x - mean))
.fold(T::zero(), |acc, x| acc + x);
self.stats.fitness_variance = variance_sum / T::from(fitnesses.len()).expect("unwrap failed");
}
}
impl Default for PopulationConfig {
fn default() -> Self {
Self {
size: 50,
elite_size: 5,
maintain_diversity: true,
min_diversity: 0.1,
max_generations: 100,
}
}
}
impl<T: scirs2_core::numeric::Float + Default + Send + Sync> Default for PopulationStats<T> {
fn default() -> Self {
Self {
best_fitness: T::zero(),
avg_fitness: T::zero(),
worst_fitness: T::zero(),
diversity: DiversityMetrics::default(),
fitness_variance: T::zero(),
}
}
}