use radiate_core::{
AlterContext, AlterResult, ArithmeticGene, Chromosome, Mutate, Rate, Valid, random_provider,
};
#[derive(Debug, Clone)]
pub struct ArithmeticMutator {
rate: Rate,
}
impl ArithmeticMutator {
pub fn new(rate: impl Into<Rate>) -> Self {
let rate = rate.into();
if !rate.is_valid() {
panic!("Rate {rate:?} is not valid. Must be between 0.0 and 1.0",);
}
Self { rate }
}
}
impl<G, C> Mutate<C> for ArithmeticMutator
where
G: ArithmeticGene,
C: Chromosome<Gene = G>,
{
fn rate(&self) -> Rate {
self.rate.clone()
}
#[inline]
fn mutate_chromosome(&self, chromosome: &mut C, ctx: &mut AlterContext) -> AlterResult {
let mut mutations = 0;
for gene in chromosome.iter_mut() {
if random_provider::bool(ctx.rate()) {
let operator = random_provider::range(0..4);
let new_gene = match operator {
0 => gene.clone() + gene.new_instance(),
1 => gene.clone() - gene.new_instance(),
2 => gene.clone() * gene.new_instance(),
3 => gene.clone() / gene.new_instance(),
_ => panic!("Invalid operator - this shouldn't happen: {}", operator),
};
*gene = new_gene;
mutations += 1;
}
}
AlterResult::from(mutations)
}
}