radiate_core/
alter.rs

1use crate::{Chromosome, Gene, Genotype, Metric, Population, math::indexes, random_provider};
2use crate::{Rate, metric};
3use radiate_utils::{ToSnakeCase, intern};
4use std::iter::once;
5use std::rc::Rc;
6
7#[macro_export]
8macro_rules! alters {
9    ($($struct_instance:expr),* $(,)?) => {
10        {
11            let mut vec: Vec<Alterer<_>> = Vec::new();
12            $(
13                vec.push($struct_instance.alterer());
14            )*
15            vec
16        }
17    };
18}
19
20/// The [AlterResult] struct is used to represent the result of an
21/// alteration operation. It contains the number of operations
22/// performed and a vector of metrics that were collected
23/// during the alteration process.
24pub struct AlterResult(pub usize, pub Option<Vec<Metric>>);
25
26impl AlterResult {
27    pub fn empty() -> Self {
28        Default::default()
29    }
30
31    pub fn count(&self) -> usize {
32        self.0
33    }
34
35    pub fn merge(&mut self, other: AlterResult) {
36        let AlterResult(other_count, other_metrics) = other;
37
38        self.0 += other_count;
39        if let Some(metrics) = other_metrics {
40            if let Some(self_metrics) = &mut self.1 {
41                self_metrics.extend(metrics);
42            } else {
43                self.1 = Some(metrics);
44            }
45        }
46    }
47}
48
49impl Default for AlterResult {
50    fn default() -> Self {
51        AlterResult(0, None)
52    }
53}
54
55impl From<usize> for AlterResult {
56    fn from(value: usize) -> Self {
57        AlterResult(value, None)
58    }
59}
60
61impl From<(usize, Vec<Metric>)> for AlterResult {
62    fn from((count, metrics): (usize, Vec<Metric>)) -> Self {
63        AlterResult(count, Some(metrics))
64    }
65}
66
67impl From<(usize, Metric)> for AlterResult {
68    fn from((count, metric): (usize, Metric)) -> Self {
69        AlterResult(count, Some(vec![metric]))
70    }
71}
72
73impl From<Metric> for AlterResult {
74    fn from(value: Metric) -> Self {
75        AlterResult(1, Some(vec![value]))
76    }
77}
78
79/// The [Alterer] enum is used to represent the different
80/// types of alterations that can be performed on a
81/// population - It can be either a mutation or a crossover operation.
82
83#[derive(Clone)]
84pub enum Alterer<C: Chromosome> {
85    Mutate(&'static str, Rate, Rc<dyn Mutate<C>>),
86    Crossover(&'static str, Rate, Rc<dyn Crossover<C>>),
87}
88
89impl<C: Chromosome> Alterer<C> {
90    pub fn name(&self) -> &str {
91        match &self {
92            Alterer::Mutate(name, _, _) => name,
93            Alterer::Crossover(name, _, _) => name,
94        }
95    }
96
97    pub fn rate(&self) -> &Rate {
98        match &self {
99            Alterer::Mutate(_, rate, _) => rate,
100            Alterer::Crossover(_, rate, _) => rate,
101        }
102    }
103
104    #[inline]
105    pub fn alter(&self, population: &mut Population<C>, generation: usize) -> Vec<Metric> {
106        match &self {
107            Alterer::Mutate(name, rate, m) => {
108                let rate_value = rate.value(generation);
109
110                let timer = std::time::Instant::now();
111                let AlterResult(count, metrics) = m.mutate(population, generation, rate_value);
112                let metric = metric!(name, (count, timer.elapsed()));
113
114                match metrics {
115                    Some(metrics) => metrics.into_iter().chain(once(metric)).collect(),
116                    None => vec![metric],
117                }
118            }
119            Alterer::Crossover(name, rate, c) => {
120                let rate_value = rate.value(generation);
121
122                let timer = std::time::Instant::now();
123                let AlterResult(count, metrics) = c.crossover(population, generation, rate_value);
124                let metric = metric!(name, (count, timer.elapsed()));
125
126                match metrics {
127                    Some(metrics) => metrics.into_iter().chain(once(metric)).collect(),
128                    None => vec![metric],
129                }
130            }
131        }
132    }
133}
134
135/// Minimum population size required to perform crossover - this ensures that there
136/// are enough individuals to select parents from. If the population size is
137/// less than this value, we will not be able to select two distinct parents.
138const MIN_POPULATION_SIZE: usize = 3;
139/// Minimum number of parents required for crossover operation. This is typically
140/// two, as crossover usually involves two parents to produce offspring.
141const MIN_NUM_PARENTS: usize = 2;
142
143/// The [Crossover] trait is used to define the crossover operation for a genetic algorithm.
144///
145/// In a genetic algorithm, crossover is a genetic operator used to vary the
146/// programming of a chromosome or chromosomes from one generation to the next.
147/// It is analogous to reproduction and biological crossover, upon which genetic algorithms are based.
148///
149/// A [Crossover] typically takes two parent [Chromosome]s and produces two or more offspring [Chromosome]s.
150/// This trait allows you to define your own crossover operation on either the entire population
151/// or a subset of the population. If a struct implements the [Crossover] trait but does not override
152/// any of the methods, the default implementation will perform a simple crossover operation on the
153/// entire population.
154pub trait Crossover<C: Chromosome>: Send + Sync {
155    fn name(&self) -> String {
156        std::any::type_name::<Self>()
157            .split("::")
158            .last()
159            .map(|s| s.to_snake_case())
160            .unwrap()
161    }
162
163    fn rate(&self) -> Rate {
164        Rate::default()
165    }
166
167    fn alterer(self) -> Alterer<C>
168    where
169        Self: Sized + 'static,
170    {
171        Alterer::Crossover(intern!(self.name()), self.rate(), Rc::new(self))
172    }
173
174    #[inline]
175    fn crossover(
176        &self,
177        population: &mut Population<C>,
178        generation: usize,
179        rate: f32,
180    ) -> AlterResult {
181        let mut result = AlterResult::default();
182
183        for i in 0..population.len() {
184            if random_provider::bool(rate) && population.len() > MIN_POPULATION_SIZE {
185                let parent_indexes =
186                    indexes::individual_indexes(i, population.len(), MIN_NUM_PARENTS);
187                let cross_result = self.cross(population, &parent_indexes, generation, rate);
188                result.merge(cross_result);
189            }
190        }
191
192        result
193    }
194
195    #[inline]
196    fn cross(
197        &self,
198        population: &mut Population<C>,
199        parent_indexes: &[usize],
200        generation: usize,
201        rate: f32,
202    ) -> AlterResult {
203        let mut result = AlterResult::default();
204
205        if let Some((one, two)) = population.get_pair_mut(parent_indexes[0], parent_indexes[1]) {
206            let cross_result = {
207                let geno_one = one.genotype_mut();
208                let geno_two = two.genotype_mut();
209
210                let min_len = std::cmp::min(geno_one.len(), geno_two.len());
211                let chromosome_index = random_provider::range(0..min_len);
212
213                let chrom_one = &mut geno_one[chromosome_index];
214                let chrom_two = &mut geno_two[chromosome_index];
215
216                self.cross_chromosomes(chrom_one, chrom_two, rate)
217            };
218
219            if cross_result.count() > 0 {
220                one.invalidate(generation);
221                two.invalidate(generation);
222                result.merge(cross_result);
223            }
224        }
225
226        result
227    }
228
229    #[inline]
230    fn cross_chromosomes(&self, chrom_one: &mut C, chrom_two: &mut C, rate: f32) -> AlterResult {
231        let mut cross_count = 0;
232
233        for i in 0..std::cmp::min(chrom_one.len(), chrom_two.len()) {
234            if random_provider::bool(rate) {
235                let gene_one = chrom_one.get(i);
236                let gene_two = chrom_two.get(i);
237
238                let new_gene_one = gene_one.with_allele(gene_two.allele());
239                let new_gene_two = gene_two.with_allele(gene_one.allele());
240
241                chrom_one.set(i, new_gene_one);
242                chrom_two.set(i, new_gene_two);
243
244                cross_count += 1;
245            }
246        }
247
248        AlterResult::from(cross_count)
249    }
250}
251
252pub trait Mutate<C: Chromosome>: Send + Sync {
253    fn name(&self) -> String {
254        std::any::type_name::<Self>()
255            .split("::")
256            .last()
257            .map(|s| s.to_snake_case())
258            .unwrap()
259    }
260
261    fn rate(&self) -> Rate {
262        Rate::default()
263    }
264
265    fn alterer(self) -> Alterer<C>
266    where
267        Self: Sized + 'static,
268    {
269        Alterer::Mutate(intern!(self.name()), self.rate(), Rc::new(self))
270    }
271
272    #[inline]
273    fn mutate(&self, population: &mut Population<C>, generation: usize, rate: f32) -> AlterResult {
274        let mut result = AlterResult::default();
275
276        for phenotype in population.iter_mut() {
277            let mutate_result = self.mutate_genotype(phenotype.genotype_mut(), rate);
278
279            if mutate_result.count() > 0 {
280                phenotype.invalidate(generation);
281            }
282
283            result.merge(mutate_result);
284        }
285
286        result
287    }
288
289    #[inline]
290    fn mutate_genotype(&self, genotype: &mut Genotype<C>, rate: f32) -> AlterResult {
291        let mut result = AlterResult::default();
292
293        for chromosome in genotype.iter_mut() {
294            let mutate_result = self.mutate_chromosome(chromosome, rate);
295            result.merge(mutate_result);
296        }
297
298        result
299    }
300
301    #[inline]
302    fn mutate_chromosome(&self, chromosome: &mut C, rate: f32) -> AlterResult {
303        let mut count = 0;
304        for gene in chromosome.iter_mut() {
305            if random_provider::bool(rate) {
306                *gene = self.mutate_gene(gene);
307                count += 1;
308            }
309        }
310
311        count.into()
312    }
313
314    #[inline]
315    fn mutate_gene(&self, gene: &C::Gene) -> C::Gene {
316        gene.new_instance()
317    }
318}