radiate_alters/mutators/
jitter.rs

1use radiate_core::{
2    AlterResult, BoundedGene, Chromosome, FloatGene, Gene, Mutate, random_provider,
3};
4
5/// The `JitterMutator` is a simple mutator that adds a small random value to [FloatGene]s.
6///
7/// The magnitude parameter controls the maximum change that can be applied to a gene.
8/// For example, if the magnitude is set to 0.1, then the gene can be changed by a value
9/// between -0.1 and 0.1. This allows for fine-tuning of the mutation process,
10/// as smaller magnitudes will result in smaller changes to the genes, while larger
11/// magnitudes will result in larger changes.
12#[derive(Debug, Clone)]
13pub struct JitterMutator {
14    rate: f32,
15    magnitude: f32,
16}
17
18impl JitterMutator {
19    pub fn new(rate: f32, magnitude: f32) -> Self {
20        if !(0.0..=1.0).contains(&rate) {
21            panic!("Rate must be between 0 and 1");
22        }
23
24        if magnitude <= 0.0 {
25            panic!("Magnitude must be greater than 0");
26        }
27
28        Self { rate, magnitude }
29    }
30}
31
32impl<C> Mutate<C> for JitterMutator
33where
34    C: Chromosome<Gene = FloatGene>,
35{
36    fn rate(&self) -> f32 {
37        self.rate
38    }
39
40    #[inline]
41    fn mutate_chromosome(&self, chromosome: &mut C, rate: f32) -> AlterResult {
42        let mut count = 0;
43
44        for gene in chromosome.genes_mut() {
45            if random_provider::random::<f32>() < rate {
46                let change = random_provider::range(-1.0..1.0) * self.magnitude;
47                let new_allele = gene.allele() + change;
48                let (min, max) = gene.bounds();
49
50                (*gene.allele_mut()) = new_allele.clamp(*min, *max);
51                count += 1;
52            }
53        }
54
55        count.into()
56    }
57}