use radiate_core::{
AlterContext, AlterResult, BoundedGene, Chromosome, FloatGene, Gene, Mutate, Rate, Valid,
random_provider,
};
use radiate_utils::Float;
#[derive(Debug, Clone)]
pub struct JitterMutator {
rate: Rate,
magnitude: f32,
}
impl JitterMutator {
pub fn new(rate: impl Into<Rate>, magnitude: f32) -> Self {
let rate = rate.into();
if !rate.is_valid() {
panic!("Rate is not valid: {:?}", rate);
}
if magnitude <= 0.0 {
panic!("Magnitude must be greater than 0");
}
Self { rate, magnitude }
}
}
impl<F, C> Mutate<C> for JitterMutator
where
F: Float,
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;
let mag = F::from(self.magnitude).unwrap();
random_provider::with_rng(|rand| {
for gene in chromosome.as_mut_slice() {
if rand.bool(ctx.rate()) {
let change = rand.range(-F::ONE..F::ONE) * mag;
let new_allele = *gene.allele() + change;
let (min, max) = gene.bounds();
(*gene.allele_mut()) = new_allele.clamp(*min, *max);
count += 1;
}
}
});
AlterResult::from(count)
}
}