use crate::fitness::FitnessEvaluator;
#[cfg(feature = "parallel")]
use std::sync::OnceLock as FitnessCell;
#[cfg(not(feature = "parallel"))]
use std::cell::OnceCell as FitnessCell;
#[derive(Debug, Clone)]
pub struct Individual<G, F> {
genome: G,
fitness: FitnessCell<F>,
}
impl<G, F> Individual<G, F> {
pub fn new(genome: G) -> Self {
Self {
genome,
fitness: FitnessCell::new(),
}
}
pub fn from_parts(genome: G, fitness: F) -> Self {
Self {
genome,
fitness: FitnessCell::from(fitness),
}
}
pub fn try_fitness(&self) -> Option<&F> {
self.fitness.get()
}
pub fn genome(&self) -> &G {
&self.genome
}
pub fn fitness<Fe>(&self, fitness_evaluator: &Fe) -> &F
where
Fe: FitnessEvaluator<G, F>,
{
self.fitness
.get_or_init(|| fitness_evaluator.evaluate(&self.genome))
}
pub fn clone_genome_only(&self) -> Self
where
G: Clone,
{
Self {
genome: self.genome.clone(),
fitness: FitnessCell::new(),
}
}
pub fn mutate_genome(self, f: impl FnOnce(&mut G)) -> Self {
let mut genome = self.genome;
f(&mut genome);
Self::new(genome)
}
}