~ruther/ctu-fee-eoa

ref: d8580bdc2c159bd7c925cfecb4a9d53921288722 ctu-fee-eoa/env/src/evolution.rs -rw-r--r-- 3.2 KiB
d8580bdc — Rutherther feat: add evolution algorithm a month ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
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
    })
}