use radiate_core::{
AlterContext, AlterResult, BoundedGene, Chromosome, FloatGene, Gene, Mutate, Rate, Valid,
random_provider,
};
use radiate_utils::{Float, Primitive};
#[derive(Debug, Clone)]
pub struct GaussianMutator {
rate: Rate,
}
impl GaussianMutator {
pub fn new(rate: impl Into<Rate>) -> Self {
let rate = rate.into();
if !rate.is_valid() {
panic!("Rate is not valid: {:?}", rate);
}
GaussianMutator { rate }
}
}
impl<F, C> Mutate<C> for GaussianMutator
where
F: Float + Primitive,
C: Chromosome<Gene = FloatGene<F>>,
{
fn rate(&self) -> Rate {
self.rate.clone()
}
#[inline]
fn mutate_chromosome(&self, chromosome: &mut C, ctx: &mut AlterContext) -> AlterResult {
let mut count = 0;
random_provider::with_rng(|rand| {
for gene in chromosome.as_mut_slice() {
if rand.bool(ctx.rate()) {
let min = gene.min().extract::<f64>().unwrap();
let max = gene.max().extract::<f64>().unwrap();
let std_dev = (max - min) * 0.25;
let value = gene.allele().extract::<f64>().unwrap();
let gaussian = rand.gaussian(value, std_dev);
let allele = gaussian.clamp(min, max);
*gene.allele_mut() = allele.extract::<F>().unwrap();
count += 1;
}
}
});
AlterResult::from(count)
}
}