use crate::{
core::{context::Context, state::State},
fitness::{FitnessComparator, FitnessEvaluator},
};
use std::num::NonZero;
pub trait Observer<G, F, Fe, R, C> {
fn on_start(&mut self, _: &State<G, F>, _: &Context<Fe, R, C>) {}
fn on_generation(&mut self, _: &State<G, F>, _: &Context<Fe, R, C>) {}
fn on_end(&mut self, _: &State<G, F>, _: &Context<Fe, R, C>) {}
}
#[derive(Debug, Clone, Copy)]
pub struct StatsLogger {
every: usize,
}
impl StatsLogger {
pub fn new(n: NonZero<usize>) -> Self {
Self { every: n.get() }
}
}
impl Default for StatsLogger {
fn default() -> Self {
Self { every: 1 }
}
}
impl<G, F, Fe, R, C> Observer<G, F, Fe, R, C> for StatsLogger
where
F: std::fmt::Display + PartialOrd,
Fe: FitnessEvaluator<G, F>,
C: FitnessComparator<F>,
{
fn on_generation(&mut self, state: &State<G, F>, ctx: &Context<Fe, R, C>) {
if state.generation().is_multiple_of(self.every) {
let best = state.population().best(ctx.fitness_evaluator(), ctx.comparator());
println!(
"[gen {}] best fitness: {}",
state.generation(),
best.fitness(ctx.fitness_evaluator())
);
}
}
}
#[derive(Debug, Default, Clone, Copy)]
pub struct NoOp;
impl NoOp {
pub fn new() -> Self {
Self
}
}
impl<G, F, Fe, R, C> Observer<G, F, Fe, R, C> for NoOp {}
#[cfg(test)]
mod test;