pub mod cache;
pub mod placeholders;
pub mod prelude;
pub use self::cache::Cache as FitnessCache;
use crate::chromosome::Chromosome;
use crate::genotype::Genotype;
use crate::population::Population;
use crate::strategy::{StrategyAction, StrategyConfig, StrategyState};
use rayon::prelude::*;
use std::cell::RefCell;
use std::time::Instant;
use thread_local::ThreadLocal;
pub type FitnessValue = isize;
#[derive(Copy, Clone, Debug)]
pub enum FitnessOrdering {
Maximize,
Minimize,
}
pub type FitnessGenotype<F> = <F as Fitness>::Genotype;
pub type FitnessChromosome<F> = Chromosome<<<F as Fitness>::Genotype as Genotype>::Allele>;
pub type FitnessGenes<F> = Vec<<<F as Fitness>::Genotype as Genotype>::Allele>;
pub type FitnessPopulation<F> = Population<<<F as Fitness>::Genotype as Genotype>::Allele>;
pub trait Fitness: Clone + Send + Sync + std::fmt::Debug {
type Genotype: Genotype;
fn call_for_state_population<S: StrategyState<Self::Genotype>, C: StrategyConfig>(
&mut self,
genotype: &Self::Genotype,
state: &mut S,
config: &C,
thread_local: Option<&ThreadLocal<RefCell<Self>>>,
) {
let now = Instant::now();
self.call_for_population(
state.population_as_mut(),
genotype,
thread_local,
config.fitness_cache(),
);
state.add_duration(StrategyAction::Fitness, now.elapsed());
}
fn call_for_state_chromosome<S: StrategyState<Self::Genotype>, C: StrategyConfig>(
&mut self,
genotype: &Self::Genotype,
state: &mut S,
config: &C,
) {
if let Some(chromosome) = state.chromosome_as_mut() {
let now = Instant::now();
self.call_for_chromosome(chromosome, genotype, config.fitness_cache());
state.add_duration(StrategyAction::Fitness, now.elapsed());
}
}
fn call_for_population(
&mut self,
population: &mut FitnessPopulation<Self>,
genotype: &Self::Genotype,
thread_local: Option<&ThreadLocal<RefCell<Self>>>,
cache: Option<&FitnessCache>,
) {
if let Some(thread_local) = thread_local {
population
.chromosomes
.par_iter_mut()
.filter(|c| c.fitness_score().is_none())
.for_each_init(
|| {
thread_local
.get_or(|| std::cell::RefCell::new(self.clone()))
.borrow_mut()
},
|fitness, chromosome| {
fitness.call_for_chromosome(chromosome, genotype, cache);
},
);
} else {
population
.chromosomes
.iter_mut()
.filter(|c| c.fitness_score().is_none())
.for_each(|c| self.call_for_chromosome(c, genotype, cache));
}
}
fn call_for_chromosome(
&mut self,
chromosome: &mut FitnessChromosome<Self>,
genotype: &Self::Genotype,
cache: Option<&FitnessCache>,
) {
let value = match (cache, chromosome.genes_hash()) {
(Some(cache), Some(genes_hash)) => {
if let Some(value) = cache.read(genes_hash) {
Some(value)
} else if let Some(value) = self.calculate_for_chromosome(chromosome, genotype) {
cache.write(genes_hash, value);
Some(value)
} else {
None
}
}
_ => self.calculate_for_chromosome(chromosome, genotype),
};
chromosome.set_fitness_score(value);
}
fn calculate_for_chromosome(
&mut self,
chromosome: &FitnessChromosome<Self>,
genotype: &Self::Genotype,
) -> Option<FitnessValue>;
}