~ruther/ctu-fee-eoa

1f3a772d9049f75121cd08c0a2d3be01de87a1df — Rutherther a month ago 7898936
feat: Add replacement strategy
2 files changed, 223 insertions(+), 0 deletions(-)

M env/src/main.rs
A env/src/replacement.rs
M env/src/main.rs => env/src/main.rs +1 -0
@@ 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;

A env/src/replacement.rs => env/src/replacement.rs +222 -0
@@ 0,0 1,222 @@
use rand::{seq::IteratorRandom, RngCore};

use crate::{comparison::BetterThanOperator, fitness::FitnessFunction, selection::{Selection, TournamentSelection}};

#[derive(Clone)]
pub struct Population<TChromosome> {
    population: Vec<TChromosome>
}

#[derive(Clone)]
pub struct EvaluatedChromosome<TChromosome, TResult> {
    pub chromosome: TChromosome,
    pub evaluation: TResult,
}

#[derive(Clone)]
pub struct EvaluatedPopulation<TChromosome, TResult> {
    pub population: Vec<EvaluatedChromosome<TChromosome, TResult>>
}

impl<TChromosome> Population<TChromosome> {
    pub fn from_vec(vec: Vec<TChromosome>) -> Self {
        Self {
            population: vec
        }
    }

    pub fn evaluate<T: FitnessFunction<In = TChromosome>>(self, func: &T) -> Result<EvaluatedPopulation<TChromosome, T::Out>, T::Err> {
        EvaluatedPopulation::evaluate(
            self.population,
            func
        )
    }

    pub fn iter(&mut self) -> impl Iterator<Item = &TChromosome> {
        self.population.iter()
    }

    pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut TChromosome> {
        self.population.iter_mut()
    }
}

impl<TInput, TResult> EvaluatedChromosome<TInput, TResult> {
    pub fn deconstruct(self) -> (TInput, TResult) {
        (self.chromosome, self.evaluation)
    }
}

impl<TChromosome, TResult> EvaluatedPopulation<TChromosome, TResult> {
    pub fn new() -> Self {
        Self {
            population: vec![]
        }
    }

    pub fn evaluate<T: FitnessFunction<In = TChromosome, Out = TResult>>(chromosomes: Vec<TChromosome>, func: &T) -> Result<Self, T::Err> {
        Ok(EvaluatedPopulation::from_vec(
            chromosomes.into_iter()
                .map(|chromosome|
                     Ok(EvaluatedChromosome {
                         evaluation: func.fit(&chromosome)?,
                         chromosome
                     }))
                .collect::<Result<_, _>>()?))
    }

    pub fn from_vec(vec: Vec<EvaluatedChromosome<TChromosome, TResult>>) -> Self {
        Self {
            population: vec
        }
    }

    pub fn best_candidate(&self, better_than: &impl BetterThanOperator<TResult>) -> &EvaluatedChromosome<TChromosome, TResult> {
        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<TChromosome, TResult>) {
        self.population.push(c)
    }

    pub fn deconstruct(self) -> Vec<EvaluatedChromosome<TChromosome, TResult>> {
        self.population
    }

    fn join(&mut self, mut offsprings: EvaluatedPopulation<TChromosome, TResult>) {
        self.population.append(&mut offsprings.population);
    }

    pub fn iter(&mut self) -> impl Iterator<Item = &EvaluatedChromosome<TChromosome, TResult>> {
        self.population.iter()
    }

    pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut EvaluatedChromosome<TChromosome, TResult>> {
        self.population.iter_mut()
    }

}

impl<TChromosome, TResult: Copy> EvaluatedPopulation<TChromosome, TResult> {
    pub fn evaluations_vec(&self) -> Vec<TResult> {
        self.population
            .iter()
            .map(|individual| individual.evaluation)
            .collect()
    }
}

pub trait Replacement<TChromosome, TResult> {
    fn replace(
        &mut self,
        parents_evaluations: EvaluatedPopulation<TChromosome, TResult>,
        offsprings_evaluations: EvaluatedPopulation<TChromosome, TResult>,
        better_than: &dyn BetterThanOperator<TResult>
    ) -> EvaluatedPopulation<TChromosome, TResult>;
}

pub struct GenerationalReplacement;
impl<TInput, TResult> Replacement<TInput, TResult> for GenerationalReplacement {
    fn replace(
        &mut self,
        parents: EvaluatedPopulation<TInput, TResult>,
        mut offsprings: EvaluatedPopulation<TInput, TResult>,
        _: &dyn BetterThanOperator<TResult>
    ) -> EvaluatedPopulation<TInput, TResult> {
        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<dyn RngCore>
}

impl RandomReplacement {
    pub fn new() -> Self {
        Self {
            rng: Box::new(rand::rng())
        }
    }
}

impl<TInput, TResult> Replacement<TInput, TResult> for RandomReplacement {
    fn replace(
        &mut self,
        parents: EvaluatedPopulation<TInput, TResult>,
        offsprings: EvaluatedPopulation<TInput, TResult>,
        _: &dyn BetterThanOperator<TResult>
    ) -> EvaluatedPopulation<TInput, TResult> {
        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<f64>
}

impl TournamentReplacement {
    pub fn new(k: usize, p: f64) -> Self {
        TournamentReplacement {
            evaluation_pool: vec![],
            selection: TournamentSelection::new(
                k,
                p,
            )
        }
    }
}

impl<TInput, TResult: Copy> Replacement<TInput, TResult> for TournamentReplacement {
    fn replace(
        &mut self,
        parents: EvaluatedPopulation<TInput, TResult>,
        offsprings: EvaluatedPopulation<TInput, TResult>,
        better_than: &dyn BetterThanOperator<TResult>
    ) -> EvaluatedPopulation<TInput, TResult> {
        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::<Vec<_>>();

        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)
    }
}