From 1f3a772d9049f75121cd08c0a2d3be01de87a1df Mon Sep 17 00:00:00 2001 From: Rutherther Date: Sun, 26 Oct 2025 21:42:10 +0100 Subject: [PATCH] feat: Add replacement strategy --- env/src/main.rs | 1 + env/src/replacement.rs | 222 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 223 insertions(+) create mode 100644 env/src/replacement.rs diff --git a/env/src/main.rs b/env/src/main.rs index ece1053c649b82f126ae8011e45bd94adf4827c2..1a9fa9efd93412a9f642460bd2af37b8228b38de 100644 --- a/env/src/main.rs +++ b/env/src/main.rs @@ -2,6 +2,7 @@ pub mod fitness; pub mod crossover; pub mod bounded; pub mod selection; +pub mod replacement; pub mod initializer; pub mod terminating; pub mod perturbation; diff --git a/env/src/replacement.rs b/env/src/replacement.rs new file mode 100644 index 0000000000000000000000000000000000000000..3c79db67e44370ae69ce61d95a67e61a0e671bcb --- /dev/null +++ b/env/src/replacement.rs @@ -0,0 +1,222 @@ +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) + } +}