use std::fmt::Debug;
use rayon::prelude::*;
use super::BreedStrategy;
use crate::{
error::{GeneticError, Result},
phenotype::Phenotype,
};
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, Clone)]
pub struct OrdinaryStrategy {
}
impl OrdinaryStrategy {
pub fn new() -> Self {
Self {}
}
#[deprecated(
since = "0.1.0",
note = "Set parallel_threshold in EvolutionOptions instead"
)]
pub fn new_with_threshold(_parallel_threshold: usize) -> Self {
Self {}
}
}
impl Default for OrdinaryStrategy {
fn default() -> Self {
Self::new()
}
}
impl<Pheno> BreedStrategy<Pheno> for OrdinaryStrategy
where
Pheno: Phenotype + Send + Sync,
{
fn breed(
&self,
parents: &[Pheno],
evol_options: &crate::evolution::options::EvolutionOptions,
rng: &mut crate::rng::RandomNumberGenerator,
) -> Result<Vec<Pheno>> {
if parents.is_empty() {
return Err(GeneticError::EmptyPopulation);
}
let winner_previous_generation = parents[0].clone();
let mut children = Vec::with_capacity(evol_options.get_num_offspring());
children.push(winner_previous_generation.clone());
let crossover_parents: Vec<&Pheno> = parents.iter().skip(1).collect();
let num_mutation_only = evol_options
.get_num_offspring()
.saturating_sub(parents.len());
let total_offspring = crossover_parents.len() + num_mutation_only;
let parallel_threshold = evol_options.get_parallel_threshold();
if total_offspring >= parallel_threshold {
if !crossover_parents.is_empty() {
let crossover_children: Vec<Pheno> = crossover_parents
.into_par_iter()
.map(|parent| {
let mut child = winner_previous_generation.clone();
child.crossover(parent);
child.mutate_thread_local();
child
})
.collect();
children.extend(crossover_children);
}
if num_mutation_only > 0 {
let mutation_children: Vec<Pheno> = (0..num_mutation_only)
.into_par_iter()
.map(|_| {
let mut child = winner_previous_generation.clone();
child.mutate_thread_local();
child
})
.collect();
children.extend(mutation_children);
}
} else {
for parent in crossover_parents {
let mut child = winner_previous_generation.clone();
child.crossover(parent);
child.mutate(rng);
children.push(child);
}
for _ in 0..num_mutation_only {
let mut child = winner_previous_generation.clone();
child.mutate(rng);
children.push(child);
}
}
Ok(children)
}
}
#[cfg(test)]
mod tests {
use crate::{
breeding::BreedStrategy, evolution::options::EvolutionOptions, phenotype::Phenotype,
rng::RandomNumberGenerator,
};
#[allow(unused)]
#[test]
fn test_breed() {
let mut rng = RandomNumberGenerator::new();
let evol_options = EvolutionOptions::default();
let strategy = super::OrdinaryStrategy::default();
#[derive(Clone, Copy, Debug)]
struct MockPhenotype;
impl Phenotype for MockPhenotype {
fn crossover(&mut self, _other: &Self) {}
fn mutate(&mut self, _rng: &mut RandomNumberGenerator) {}
}
let mut parents = Vec::<MockPhenotype>::new();
parents.extend((0..5).map(|_| MockPhenotype));
let children = strategy.breed(&parents, &evol_options, &mut rng).unwrap();
assert_eq!(children.len(), evol_options.get_num_offspring());
}
#[test]
fn test_breed_empty_parents() {
let mut rng = RandomNumberGenerator::new();
let evol_options = EvolutionOptions::default();
let strategy = super::OrdinaryStrategy::default();
#[derive(Clone, Copy, Debug)]
struct MockPhenotype;
impl Phenotype for MockPhenotype {
fn crossover(&mut self, _other: &Self) {}
fn mutate(&mut self, _rng: &mut RandomNumberGenerator) {}
}
let parents = Vec::<MockPhenotype>::new();
let result = strategy.breed(&parents, &evol_options, &mut rng);
assert!(result.is_err());
match result {
Err(crate::error::GeneticError::EmptyPopulation) => (),
_ => panic!("Expected EmptyPopulation error"),
}
}
}