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, ¤t_population, better_than);
let parent_pairings = pairing.pair(¤t_population, parents);
// Crossover
let mut offsprings = crossover.crossover(¤t_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
})
}