~ruther/ctu-fee-eoa

d8580bdc2c159bd7c925cfecb4a9d53921288722 — Rutherther a month ago d4df388
feat: add evolution algorithm
2 files changed, 90 insertions(+), 0 deletions(-)

A env/src/evolution.rs
M env/src/main.rs
A env/src/evolution.rs => env/src/evolution.rs +89 -0
@@ 0,0 1,89 @@
use std::error::Error;

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

pub struct EvolutionCandidate<TInput, TResult> {
    pub evaluated_chromosome: EvaluatedChromosome<TInput, TResult>,
    pub iteration: usize
}

pub struct EvolutionCandidatePopulation<TInput, TResult> {
    pub current_population: EvaluatedPopulation<TInput, TResult>,
    pub iteration: usize
}

pub struct EvolutionStats<TInput, TResult> {
    pub best_candidates: Vec<EvolutionCandidate<TInput, TResult>>,
}

pub struct EvolutionResult<TInput, TResult> {
    pub population: EvaluatedPopulation<TInput, TResult>,
    pub stats: EvolutionStats<TInput, TResult>,
    pub iterations: usize
}

pub fn evolution_algorithm<TChromosome: Clone, TResult: Clone>(
    initial_population: Population<TChromosome>,
    parents_count: usize,
    fitness: &impl FitnessFunction<In = TChromosome, Out = TResult>,
    selection: &mut impl Selection<TChromosome, TResult>,
    pairing: &mut impl Pairing<Chromosome = TChromosome, Out = TResult>,
    crossover: &mut impl Crossover<Chromosome = TChromosome, Out = TResult>,
    perturbation: &mut impl PerturbationOperator<Chromosome = TChromosome>,
    replacement: &mut impl Replacement<TChromosome, TResult>,
    better_than: &impl BetterThanOperator<TResult>,
    // TODO: termination condition
    iterations: usize
) -> Result<EvolutionResult<TChromosome, TResult>, Box<dyn Error>> {
    let mut current_population = initial_population.evaluate(fitness)?;

    let mut last_best_candidate = EvolutionCandidate {
        evaluated_chromosome: current_population.best_candidate(better_than).clone(),
        iteration: 0
    };
    let mut stats: EvolutionStats<TChromosome, TResult> = EvolutionStats {
        best_candidates: vec![]
    };

    for iteration in 0..iterations {
        // Figure out best candidate and save it if better than last time
        let best_candidate = current_population.best_candidate(better_than);

        if better_than.better_than(
            &best_candidate.evaluation,
            &last_best_candidate.evaluated_chromosome.evaluation
        ) {
            stats.best_candidates.push(last_best_candidate);

            last_best_candidate = EvolutionCandidate {
                evaluated_chromosome: best_candidate.clone(),
                iteration
            }
        }

        // Selection
        let parents = selection.select(parents_count, &current_population, better_than);
        let parent_pairings = pairing.pair(&current_population, parents);

        // Crossover
        let mut offsprings = crossover.crossover(&current_population, parent_pairings);

        // Mutation
        for offspring in offsprings.iter_mut() {
            *offspring = perturbation.perturb(offspring);
        }

        let evaluated_offsprings = offsprings.evaluate(fitness)?;

        // Replace
        current_population = replacement.replace(current_population, evaluated_offsprings, better_than);
    }

    stats.best_candidates.push(last_best_candidate);

    Ok(EvolutionResult {
        population: current_population,
        stats,
        iterations
    })
}

M env/src/main.rs => env/src/main.rs +1 -0
@@ 1,5 1,6 @@
pub mod fitness;
pub mod pairing;
pub mod evolution;
pub mod crossover;
pub mod bounded;
pub mod selection;