use crate::{
core::{context::Context, offspring::Offspring, state::State},
fitness::{FitnessComparator, FitnessEvaluator},
operators::GeneticOperator,
};
use rand::{Rng, seq::IndexedRandom};
use std::num::NonZero;
#[derive(Debug)]
pub struct Tournament {
tournament_size: usize,
}
impl Tournament {
pub fn new(tournament_size: NonZero<usize>) -> Self {
Self {
tournament_size: tournament_size.get(),
}
}
}
impl<G, F, R, Fe, C> GeneticOperator<G, F, Fe, R, C> for Tournament
where
G: Clone,
F: PartialOrd + Clone,
R: Rng,
Fe: FitnessEvaluator<G, F>,
C: FitnessComparator<F>,
{
fn apply(&self, state: &State<G, F>, ctx: &mut Context<Fe, R, C>) -> Offspring<G, F> {
let population = state.population();
assert!(!population.is_empty());
let mut best = unsafe { population.choose(ctx.rng()).unwrap_unchecked() };
for _ in 1..self.tournament_size {
let candidate = unsafe { population.as_slice().choose(ctx.rng()).unwrap_unchecked() };
if ctx.comparator().is_better(
candidate.fitness(ctx.fitness_evaluator()),
best.fitness(ctx.fitness_evaluator()),
) {
best = candidate;
}
}
let selected = best.clone_genome_only();
Offspring::Single(selected)
}
}