Skip to main content

radiate_alters/mutators/
arithmetic.rs

1use radiate_core::{
2    AlterContext, AlterResult, ArithmeticGene, Chromosome, Mutate, Rate, Valid, random_provider,
3};
4
5/// Arithmetic Mutator. Mutates genes by performing arithmetic operations on them.
6/// The [ArithmeticMutator] takes a rate parameter that determines the likelihood that
7/// a gene will be mutated. The [ArithmeticMutator] can perform addition, subtraction,
8/// multiplication, and division on genes.
9///
10/// This is a simple mutator that can be used with any gene that implements the
11/// `Add`, `Sub`, `Mul`, and `Div` traits - [ArithmeticGene] is a good example.
12#[derive(Debug, Clone)]
13pub struct ArithmeticMutator {
14    rate: Rate,
15}
16
17impl ArithmeticMutator {
18    /// Create a new instance of the `ArithmeticMutator` with the given rate.
19    /// The rate must be between 0.0 and 1.0.
20    pub fn new(rate: impl Into<Rate>) -> Self {
21        let rate = rate.into();
22        if !rate.is_valid() {
23            panic!("Rate {rate:?} is not valid. Must be between 0.0 and 1.0",);
24        }
25
26        Self { rate }
27    }
28}
29
30impl<G, C> Mutate<C> for ArithmeticMutator
31where
32    G: ArithmeticGene,
33    C: Chromosome<Gene = G>,
34{
35    fn rate(&self) -> Rate {
36        self.rate.clone()
37    }
38
39    /// Mutate a gene by performing an arithmetic operation on it.
40    /// Randomly select a number between 0 and 3, and perform the corresponding
41    /// arithmetic operation on the gene.
42    #[inline]
43    fn mutate_chromosome(&mut self, chromosome: &mut C, ctx: &mut AlterContext) -> AlterResult {
44        let mut mutations = 0;
45
46        for gene in chromosome.iter_mut() {
47            if random_provider::bool(ctx.rate()) {
48                let operator = random_provider::range(0..4);
49
50                let new_gene = match operator {
51                    0 => gene.clone() + gene.new_instance(),
52                    1 => gene.clone() - gene.new_instance(),
53                    2 => gene.clone() * gene.new_instance(),
54                    3 => gene.clone() / gene.new_instance(),
55                    _ => panic!("Invalid operator - this shouldn't happen: {}", operator),
56                };
57
58                *gene = new_gene;
59                mutations += 1;
60            }
61        }
62
63        AlterResult::from(mutations)
64    }
65}