use super::*;
pub struct GeneticAlgorithmParameters {
pub population_size: usize,
pub elitism_rate: f64,
pub crossover_rate: f64,
pub mutation_rate: f64,
pub selection_strategy: SelectionStrategy,
}
impl Default for GeneticAlgorithmParameters {
fn default() -> Self {
Self {
population_size: 100,
elitism_rate: 0.01,
crossover_rate: 0.8,
mutation_rate: 0.1,
selection_strategy: SelectionStrategy::RouletteWheel,
}
}
}
impl EvolutionParameters for GeneticAlgorithmParameters {
fn initial_population_size(&self) -> usize {
self.population_size
}
fn max_population_size(&self) -> usize {
self.population_size
}
fn validate(&self) {
assert!(self.population_size != 0);
assert!((0.0..1.0).contains(&self.elitism_rate));
assert!((0.0..=1.0).contains(&self.crossover_rate));
assert!((0.0..=1.0).contains(&self.mutation_rate));
}
}
pub struct GeneticAlgorithm<M: EvolutionModel> {
model: M,
population_size: usize,
elite_size: usize,
breeding: ReproductionParameters<M>,
}
impl<M: EvolutionModel> EvolutionAlgorithm<M> for GeneticAlgorithm<M> {
type Parameters = GeneticAlgorithmParameters;
#[inline]
fn model(&self) -> &M {
&self.model
}
#[inline]
fn reproduction_parameters(&self) -> (&ReproductionParameters<M>, usize) {
(&self.breeding, self.population_size)
}
#[inline]
fn configure(&mut self, parameters: &GeneticAlgorithmParameters) {
parameters.validate();
self.population_size = parameters.population_size;
self.elite_size = interpolate_usize(0, parameters.population_size, parameters.elitism_rate);
self.breeding.crossover_rate = parameters.crossover_rate;
self.breeding.mutation_rate = parameters.mutation_rate;
self.breeding.parent_selector = parameters.selection_strategy.create_selector();
}
#[inline]
fn select_elites(
&self,
population: &Population<M::Individual>,
elites: &mut Vec<M::Individual>,
) {
if self.elite_size != 0 {
let range_start = population.len().saturating_sub(self.elite_size);
elites.extend(population[range_start..].iter().cloned());
}
}
#[inline]
fn prepare_for_next_population(&mut self, population: &Population<M::Individual>) {
self.model.pre_generation(population, &mut self.breeding);
self.breeding.parent_selector.prepare(population);
}
}
impl<M: EvolutionModel> From<M> for GeneticAlgorithm<M> {
fn from(model: M) -> Self {
Self {
model,
population_size: Default::default(),
elite_size: Default::default(),
breeding: Default::default(),
}
}
}
impl<M: EvolutionModel + Default> Default for GeneticAlgorithm<M> {
fn default() -> Self {
Self::from(M::default())
}
}