~ruther/ctu-fee-eoa

62595f5e13c66e19b57db343ff0856f28df40522 — Rutherther a month ago 7a235cb
chore: move population structs to separate module
M codes/eoa_lib/src/crossover.rs => codes/eoa_lib/src/crossover.rs +1 -1
@@ 4,7 4,7 @@ use nalgebra::{allocator::Allocator, DefaultAllocator, Dim, OVector, Scalar, U1}
use rand::{seq::IteratorRandom, Rng, RngCore};
use rand_distr::Uniform;

use crate::{binary_string::BinaryString, pairing::ParentPairing, replacement::{EvaluatedPopulation, Population}};
use crate::{binary_string::BinaryString, pairing::ParentPairing, population::{EvaluatedPopulation, Population}};

pub trait Crossover<const D: usize> {
    type Chromosome;

M codes/eoa_lib/src/evolution.rs => codes/eoa_lib/src/evolution.rs +2 -2
@@ 1,7 1,7 @@
use std::error::Error;
use rand::RngCore;

use crate::{comparison::BetterThanOperator, crossover::Crossover, fitness::FitnessFunction, pairing::Pairing, perturbation::PerturbationOperator, replacement::{EvaluatedChromosome, EvaluatedPopulation, Population, Replacement}, selection::Selection};
use crate::{comparison::BetterThanOperator, crossover::Crossover, fitness::FitnessFunction, pairing::Pairing, perturbation::PerturbationOperator, population::{EvaluatedChromosome, EvaluatedPopulation, Population}, replacement::Replacement, selection::Selection};

#[derive(Clone, Debug)]
pub struct EvolutionCandidate<TInput, TResult> {


@@ 173,7 173,7 @@ pub fn evolution_algorithm
pub mod tests {
    use nalgebra::Const;

    use crate::{binary_string::BinaryString, comparison::MinimizingOperator, crossover::BinaryOnePointCrossover, fitness::one_max::OneMax, initializer::{Initializer, RandomInitializer}, pairing::AdjacentPairing, perturbation::{BinaryStringBitPerturbation, BinaryStringFlipPerturbation, BinaryStringSingleBitPerturbation, CombinedPerturbation, MutationPerturbation}, replacement::{BestReplacement, Population, TournamentReplacement}, selection::TournamentSelection};
    use crate::{binary_string::BinaryString, comparison::MinimizingOperator, crossover::BinaryOnePointCrossover, fitness::one_max::OneMax, initializer::{Initializer, RandomInitializer}, pairing::AdjacentPairing, perturbation::{BinaryStringBitPerturbation, BinaryStringFlipPerturbation, BinaryStringSingleBitPerturbation, CombinedPerturbation, MutationPerturbation}, population::Population, replacement::{BestReplacement, TournamentReplacement}, selection::TournamentSelection};

    use super::evolution_algorithm;


M codes/eoa_lib/src/lib.rs => codes/eoa_lib/src/lib.rs +1 -0
@@ 1,5 1,6 @@
pub mod fitness;
pub mod pairing;
pub mod population;
pub mod evolution;
pub mod crossover;
pub mod bounded;

M codes/eoa_lib/src/pairing.rs => codes/eoa_lib/src/pairing.rs +1 -1
@@ 2,7 2,7 @@ use std::marker::PhantomData;

use nalgebra::{Const, OVector, SVector};

use crate::replacement::EvaluatedPopulation;
use crate::population::EvaluatedPopulation;

pub type ParentPairing<const D: usize> = OVector<usize, Const<D>>;


A codes/eoa_lib/src/population.rs => codes/eoa_lib/src/population.rs +138 -0
@@ 0,0 1,138 @@
use crate::{comparison::BetterThanOperator, fitness::FitnessFunction};

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

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

#[derive(Clone, Debug)]
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 from_iterator(iter: impl Iterator<Item = TChromosome>) -> Self {
        Self::from_vec(iter.collect())
    }

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

    pub fn evaluate_mut<TResult>(self, func: &mut dyn FnMut(&TChromosome) -> TResult) -> EvaluatedPopulation<TChromosome, TResult> {
        EvaluatedPopulation::evaluate_mut(
            self.population,
            func
        )
    }

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

    pub fn iter(&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 evaluate_mut(chromosomes: Vec<TChromosome>, func: &mut dyn FnMut(&TChromosome) -> TResult) -> Self {
        EvaluatedPopulation::from_vec(
            chromosomes.into_iter()
                .map(|chromosome|
                     EvaluatedChromosome {
                         evaluation: func(&chromosome),
                         chromosome
                     })
                .collect::<Vec<_>>())
    }

    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
    }

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

    pub fn iter(&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()
    }
}

M codes/eoa_lib/src/replacement.rs => codes/eoa_lib/src/replacement.rs +1 -138
@@ 1,7 1,7 @@
use rand::{seq::IteratorRandom, RngCore};
use std::fmt::Debug;

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

fn extract_by_indices<T>(mut x: Vec<T>, mut idxs: Vec<usize>) -> Vec<T> {
    idxs.sort_unstable_by(|a, b| b.cmp(a));


@@ 17,143 17,6 @@ fn extract_by_indices<T>(mut x: Vec<T>, mut idxs: Vec<usize>) -> Vec<T> {
    result
}

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

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

#[derive(Clone, Debug)]
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 from_iterator(iter: impl Iterator<Item = TChromosome>) -> Self {
        Self::from_vec(iter.collect())
    }

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

    pub fn evaluate_mut<TResult>(self, func: &mut dyn FnMut(&TChromosome) -> TResult) -> EvaluatedPopulation<TChromosome, TResult> {
        EvaluatedPopulation::evaluate_mut(
            self.population,
            func
        )
    }

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

    pub fn iter(&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 evaluate_mut(chromosomes: Vec<TChromosome>, func: &mut dyn FnMut(&TChromosome) -> TResult) -> Self {
        EvaluatedPopulation::from_vec(
            chromosomes.into_iter()
                .map(|chromosome|
                     EvaluatedChromosome {
                         evaluation: func(&chromosome),
                         chromosome
                     })
                .collect::<Vec<_>>())
    }

    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(&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(
        &self,

M codes/eoa_lib/src/selection.rs => codes/eoa_lib/src/selection.rs +1 -1
@@ 3,7 3,7 @@ use rand::{seq::IteratorRandom, Rng, RngCore};
use rand_distr::uniform::{SampleRange, SampleUniform};
use std::{cmp::Ordering, fmt::Debug, ops::{AddAssign, Sub}};

use crate::{comparison::BetterThanOperator, replacement::EvaluatedPopulation};
use crate::{comparison::BetterThanOperator, population::EvaluatedPopulation};

pub trait Selection<TChromosome, TResult> {
    fn select(&self,

M codes/tsp_hw01/src/crossovers.rs => codes/tsp_hw01/src/crossovers.rs +7 -7
@@ 1,7 1,7 @@
use std::marker::PhantomData;
use nalgebra::{allocator::Allocator, Const, DefaultAllocator, Dim, OMatrix, OVector, U1};
use rand::{prelude::IteratorRandom, Rng, RngCore};
use eoa_lib::replacement::Population;
use eoa_lib::population::Population;
use itertools::Itertools;
use eoa_lib::crossover::Crossover;
use crate::tsp::NodePermutation;


@@ 26,7 26,7 @@ where

    fn crossover(
        &self,
        parents: &eoa_lib::replacement::EvaluatedPopulation<Self::Chromosome, Self::Out>,
        parents: &eoa_lib::population::EvaluatedPopulation<Self::Chromosome, Self::Out>,
        pairs: impl Iterator<Item = eoa_lib::pairing::ParentPairing<2>>,
        _: &mut dyn RngCore
    ) -> Population<Self::Chromosome> {


@@ 62,10 62,10 @@ where

    fn crossover(
        &self,
        parents: &eoa_lib::replacement::EvaluatedPopulation<Self::Chromosome, Self::Out>,
        parents: &eoa_lib::population::EvaluatedPopulation<Self::Chromosome, Self::Out>,
        pairs: impl Iterator<Item = eoa_lib::pairing::ParentPairing<2>>,
        rng: &mut dyn RngCore
    ) -> eoa_lib::replacement::Population<Self::Chromosome> {
    ) -> eoa_lib::population::Population<Self::Chromosome> {
        let mut offsprings = vec![];

        let permutation = &parents.population[0].chromosome.permutation;


@@ 225,7 225,7 @@ where

    fn crossover(
        &self,
        parents: &eoa_lib::replacement::EvaluatedPopulation<Self::Chromosome, Self::Out>,
        parents: &eoa_lib::population::EvaluatedPopulation<Self::Chromosome, Self::Out>,
        pairs: impl Iterator<Item = eoa_lib::pairing::ParentPairing<2>>,
        rng: &mut dyn RngCore
    ) -> Population<Self::Chromosome> {


@@ 309,7 309,7 @@ where

    fn crossover(
        &self,
        parents: &eoa_lib::replacement::EvaluatedPopulation<Self::Chromosome, Self::Out>,
        parents: &eoa_lib::population::EvaluatedPopulation<Self::Chromosome, Self::Out>,
        pairs: impl Iterator<Item = eoa_lib::pairing::ParentPairing<2>>,
        rng: &mut dyn RngCore
    ) -> Population<Self::Chromosome> {


@@ 343,7 343,7 @@ mod tests {
    use std::convert::Infallible;
    use nalgebra::{SVector, U6};
    use rand::{rngs::StdRng, RngCore, SeedableRng};
    use eoa_lib::{fitness::FitnessFunction, initializer::Initializer, pairing::{AdjacentPairing, Pairing}, replacement::Population};
    use eoa_lib::{fitness::FitnessFunction, initializer::Initializer, pairing::{AdjacentPairing, Pairing}, population::Population};
    use crate::initializers::TSPRandomInitializer;
    use crate::tsp::{NodePermutation, TSPInstance};


M codes/tsp_hw01/src/main.rs => codes/tsp_hw01/src/main.rs +7 -7
@@ 262,7 262,7 @@ fn run_evolution_algorithm(instance: &TSPInstance<Dyn>) -> Result<PlotData, Box<
    let population_size = EA_POPULATION_SIZE;
    let initial_population = initializer.initialize(dimension, population_size, &mut rng);

    let initial_population = eoa_lib::replacement::Population::from_vec(initial_population);
    let initial_population = eoa_lib::population::Population::from_vec(initial_population);

    // Run evolution algorithm
    let parents_count = EA_PARENTS_COUNT;


@@ 328,7 328,7 @@ fn run_evolution_algorithm_mst(instance: &TSPInstance<Dyn>) -> Result<PlotData, 
    let population_size = EA_POPULATION_SIZE;
    let initial_population = initializer.initialize(dimension, population_size, &mut rng);

    let initial_population = eoa_lib::replacement::Population::from_vec(initial_population);
    let initial_population = eoa_lib::population::Population::from_vec(initial_population);

    // Run evolution algorithm
    let parents_count = EA_PARENTS_COUNT;


@@ 394,7 394,7 @@ fn run_evolution_algorithm_nn(instance: &TSPInstance<Dyn>) -> Result<PlotData, B
    let population_size = EA_POPULATION_SIZE;
    let initial_population = initializer.initialize(dimension, population_size, &mut rng);

    let initial_population = eoa_lib::replacement::Population::from_vec(initial_population);
    let initial_population = eoa_lib::population::Population::from_vec(initial_population);

    // Run evolution algorithm
    let parents_count = EA_PARENTS_COUNT;


@@ 460,7 460,7 @@ fn run_evolution_algorithm_cx(instance: &TSPInstance<Dyn>) -> Result<PlotData, B
    let population_size = EA_POPULATION_SIZE;
    let initial_population = initializer.initialize(dimension, population_size, &mut rng);

    let initial_population = eoa_lib::replacement::Population::from_vec(initial_population);
    let initial_population = eoa_lib::population::Population::from_vec(initial_population);

    // Run evolution algorithm
    let parents_count = EA_PARENTS_COUNT;


@@ 518,7 518,7 @@ fn run_evolution_algorithm_pmx(instance: &TSPInstance<Dyn>) -> Result<PlotData, 
    let population_size = EA_POPULATION_SIZE;
    let initial_population = initializer.initialize(dimension, population_size, &mut rng);

    let initial_population = eoa_lib::replacement::Population::from_vec(initial_population);
    let initial_population = eoa_lib::population::Population::from_vec(initial_population);

    // Run evolution algorithm
    let parents_count = EA_PARENTS_COUNT;


@@ 576,7 576,7 @@ fn run_evolution_algorithm_erx(instance: &TSPInstance<Dyn>) -> Result<PlotData, 
    let population_size = EA_POPULATION_SIZE;
    let initial_population = initializer.initialize(dimension, population_size, &mut rng);

    let initial_population = eoa_lib::replacement::Population::from_vec(initial_population);
    let initial_population = eoa_lib::population::Population::from_vec(initial_population);

    // Run evolution algorithm
    let parents_count = EA_PARENTS_COUNT;


@@ 636,7 636,7 @@ fn run_evolution_algorithm_binary(instance: &TSPInstance<Dyn>) -> Result<PlotDat
    // Create initial population
    let population_size = EA_POPULATION_SIZE;
    let initial_population = initializer.initialize(input_dimension, population_size, &mut rng);
    let initial_population = eoa_lib::replacement::Population::from_vec(initial_population);
    let initial_population = eoa_lib::population::Population::from_vec(initial_population);

    let fitness = TSPBinaryStringWrapper::new(instance, input_dimension, output_dimension).unwrap();