use rand::{seq::IteratorRandom, RngCore}; use crate::{comparison::BetterThanOperator, fitness::FitnessFunction, selection::{Selection, TournamentSelection}}; #[derive(Clone)] pub struct Population { population: Vec } #[derive(Clone)] pub struct EvaluatedChromosome { pub chromosome: TChromosome, pub evaluation: TResult, } #[derive(Clone)] pub struct EvaluatedPopulation { pub population: Vec> } impl Population { pub fn from_vec(vec: Vec) -> Self { Self { population: vec } } pub fn evaluate>(self, func: &T) -> Result, T::Err> { EvaluatedPopulation::evaluate( self.population, func ) } pub fn iter(&mut self) -> impl Iterator { self.population.iter() } pub fn iter_mut(&mut self) -> impl Iterator { self.population.iter_mut() } } impl EvaluatedChromosome { pub fn deconstruct(self) -> (TInput, TResult) { (self.chromosome, self.evaluation) } } impl EvaluatedPopulation { pub fn new() -> Self { Self { population: vec![] } } pub fn evaluate>(chromosomes: Vec, func: &T) -> Result { Ok(EvaluatedPopulation::from_vec( chromosomes.into_iter() .map(|chromosome| Ok(EvaluatedChromosome { evaluation: func.fit(&chromosome)?, chromosome })) .collect::>()?)) } pub fn from_vec(vec: Vec>) -> Self { Self { population: vec } } pub fn best_candidate(&self, better_than: &impl BetterThanOperator) -> &EvaluatedChromosome { let mut best_so_far = &self.population[0]; for individual in self.population.iter().skip(1) { if better_than.better_than(&individual.evaluation, &best_so_far.evaluation) { best_so_far = individual; } } best_so_far } pub fn add(&mut self, c: EvaluatedChromosome) { self.population.push(c) } pub fn deconstruct(self) -> Vec> { self.population } fn join(&mut self, mut offsprings: EvaluatedPopulation) { self.population.append(&mut offsprings.population); } pub fn iter(&mut self) -> impl Iterator> { self.population.iter() } pub fn iter_mut(&mut self) -> impl Iterator> { self.population.iter_mut() } } impl EvaluatedPopulation { pub fn evaluations_vec(&self) -> Vec { self.population .iter() .map(|individual| individual.evaluation) .collect() } } pub trait Replacement { fn replace( &mut self, parents_evaluations: EvaluatedPopulation, offsprings_evaluations: EvaluatedPopulation, better_than: &dyn BetterThanOperator ) -> EvaluatedPopulation; } pub struct GenerationalReplacement; impl Replacement for GenerationalReplacement { fn replace( &mut self, parents: EvaluatedPopulation, mut offsprings: EvaluatedPopulation, _: &dyn BetterThanOperator ) -> EvaluatedPopulation { let count = parents.population.len(); if count == offsprings.population.len() { return offsprings; } offsprings.join(parents); offsprings.population.truncate(count); // let population = offsprings.deconstruct(); // population.truncate(count); // EvaluatedPopulation::from_vec(population) offsprings } } pub struct RandomReplacement { rng: Box } impl RandomReplacement { pub fn new() -> Self { Self { rng: Box::new(rand::rng()) } } } impl Replacement for RandomReplacement { fn replace( &mut self, parents: EvaluatedPopulation, offsprings: EvaluatedPopulation, _: &dyn BetterThanOperator ) -> EvaluatedPopulation { let count = parents.population.len(); EvaluatedPopulation::from_vec( parents.deconstruct() .into_iter() .chain(offsprings.deconstruct().into_iter()) .choose_multiple(&mut self.rng, count)) } } pub struct TournamentReplacement { selection: TournamentSelection, evaluation_pool: Vec } impl TournamentReplacement { pub fn new(k: usize, p: f64) -> Self { TournamentReplacement { evaluation_pool: vec![], selection: TournamentSelection::new( k, p, ) } } } impl Replacement for TournamentReplacement { fn replace( &mut self, parents: EvaluatedPopulation, offsprings: EvaluatedPopulation, better_than: &dyn BetterThanOperator ) -> EvaluatedPopulation { let count = parents.population.len(); let mut population = parents; population.join(offsprings); self.evaluation_pool.clear(); // TODO: use a pool instead of allocating vector every run of this function let selected = self.selection.select(count, &population, better_than) .collect::>(); let mut population = population.deconstruct(); for (write_idx, read_idx) in selected.into_iter().enumerate() { population.swap(read_idx, write_idx); } population.truncate(count); EvaluatedPopulation::from_vec(population) } }