Skip to main content

radiate_core/
alter.rs

1use crate::{Chromosome, Gene, Genotype, Metric, Population, math::indexes, random_provider};
2use crate::{Lineage, LineageUpdate, Rate, metric};
3use radiate_utils::{ToSnakeCase, intern};
4use std::iter::once;
5use std::sync::Arc;
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(
25    pub usize,
26    pub Option<Vec<Metric>>,
27    pub Option<Vec<LineageUpdate>>,
28);
29
30impl AlterResult {
31    pub fn empty() -> Self {
32        Default::default()
33    }
34
35    pub fn count(&self) -> usize {
36        self.0
37    }
38
39    pub fn update_lineage(&mut self, lineage: impl Into<LineageUpdate>) {
40        let lineage = lineage.into();
41        if let Some(self_lineage) = &mut self.2 {
42            self_lineage.push(lineage);
43        } else {
44            self.2 = Some(vec![lineage]);
45        }
46    }
47
48    pub fn merge(&mut self, other: AlterResult) {
49        let AlterResult(other_count, other_metrics, other_lineage) = other;
50
51        self.0 += other_count;
52        if let Some(metrics) = other_metrics {
53            if let Some(self_metrics) = &mut self.1 {
54                self_metrics.extend(metrics);
55            } else {
56                self.1 = Some(metrics);
57            }
58        }
59
60        if let Some(lineage) = other_lineage {
61            if let Some(self_lineage) = &mut self.2 {
62                self_lineage.extend(lineage);
63            } else {
64                self.2 = Some(lineage);
65            }
66        }
67    }
68}
69
70impl Default for AlterResult {
71    fn default() -> Self {
72        AlterResult(0, None, None)
73    }
74}
75
76impl From<usize> for AlterResult {
77    fn from(value: usize) -> Self {
78        AlterResult(value, None, None)
79    }
80}
81
82impl From<(usize, Vec<Metric>)> for AlterResult {
83    fn from((count, metrics): (usize, Vec<Metric>)) -> Self {
84        AlterResult(count, Some(metrics), None)
85    }
86}
87
88impl From<(usize, Metric)> for AlterResult {
89    fn from((count, metric): (usize, Metric)) -> Self {
90        AlterResult(count, Some(vec![metric]), None)
91    }
92}
93
94impl From<Metric> for AlterResult {
95    fn from(value: Metric) -> Self {
96        AlterResult(1, Some(vec![value]), None)
97    }
98}
99
100impl From<(usize, LineageUpdate)> for AlterResult {
101    fn from((count, lineage): (usize, LineageUpdate)) -> Self {
102        AlterResult(count, None, Some(vec![lineage]))
103    }
104}
105
106impl From<(usize, Vec<Metric>, Vec<LineageUpdate>)> for AlterResult {
107    fn from((count, metrics, lineage): (usize, Vec<Metric>, Vec<LineageUpdate>)) -> Self {
108        AlterResult(count, Some(metrics), Some(lineage))
109    }
110}
111
112impl From<(Vec<Metric>, Vec<LineageUpdate>)> for AlterResult {
113    fn from((metrics, lineage): (Vec<Metric>, Vec<LineageUpdate>)) -> Self {
114        AlterResult(metrics.len(), Some(metrics), Some(lineage))
115    }
116}
117
118/// The [Alterer] enum is used to represent the different
119/// types of alterations that can be performed on a
120/// population - It can be either a mutation or a crossover operation.
121
122#[derive(Clone)]
123pub enum Alterer<C: Chromosome> {
124    Mutate(&'static str, Rate, Arc<dyn Mutate<C>>),
125    Crossover(&'static str, Rate, Arc<dyn Crossover<C>>),
126}
127
128impl<C: Chromosome> Alterer<C> {
129    pub fn name(&self) -> &str {
130        match &self {
131            Alterer::Mutate(name, _, _) => name,
132            Alterer::Crossover(name, _, _) => name,
133        }
134    }
135
136    pub fn rate(&self) -> &Rate {
137        match &self {
138            Alterer::Mutate(_, rate, _) => rate,
139            Alterer::Crossover(_, rate, _) => rate,
140        }
141    }
142
143    #[inline]
144    pub fn alter(
145        &self,
146        population: &mut Population<C>,
147        lineage: &mut Lineage,
148        generation: usize,
149    ) -> Vec<Metric> {
150        match &self {
151            Alterer::Mutate(name, rate, m) => {
152                let (rate_value, rate_metric) = Self::rate_metric(generation, rate, name);
153
154                let timer = std::time::Instant::now();
155                let AlterResult(count, metrics, lineage_events) =
156                    m.mutate(population, generation, rate_value);
157
158                if let Some(lineage_events) = lineage_events {
159                    lineage.extend(name, lineage_events);
160                }
161
162                let metric = metric!(name, (count, timer.elapsed()));
163
164                match metrics {
165                    Some(metrics) => metrics
166                        .into_iter()
167                        .chain(once(metric))
168                        .chain(once(rate_metric))
169                        .collect(),
170                    None => vec![metric, rate_metric],
171                }
172            }
173            Alterer::Crossover(name, rate, c) => {
174                let (rate_value, rate_metric) = Self::rate_metric(generation, rate, name);
175
176                let timer = std::time::Instant::now();
177                let AlterResult(count, metrics, lineage_events) =
178                    c.crossover(population, generation, rate_value);
179
180                if let Some(lineage_events) = lineage_events {
181                    lineage.extend(name, lineage_events);
182                }
183
184                let metric = metric!(name, (count, timer.elapsed()));
185
186                match metrics {
187                    Some(metrics) => metrics
188                        .into_iter()
189                        .chain(once(metric))
190                        .chain(once(rate_metric))
191                        .collect(),
192                    None => vec![metric, rate_metric],
193                }
194            }
195        }
196    }
197
198    #[inline]
199    fn rate_metric(generation: usize, rate: &Rate, name: &str) -> (f32, Metric) {
200        let rate_value = rate.value(generation);
201        let metric = metric!(radiate_utils::intern!(format!("{}_rate", name)), rate_value);
202
203        (rate_value, metric)
204    }
205}
206
207/// Minimum population size required to perform crossover - this ensures that there
208/// are enough individuals to select parents from. If the population size is
209/// less than this value, we will not be able to select two distinct parents.
210const MIN_POPULATION_SIZE: usize = 3;
211/// Minimum number of parents required for crossover operation. This is typically
212/// two, as crossover usually involves two parents to produce offspring.
213const MIN_NUM_PARENTS: usize = 2;
214
215/// The [Crossover] trait is used to define the crossover operation for a genetic algorithm.
216///
217/// In a genetic algorithm, crossover is a genetic operator used to vary the
218/// programming of a chromosome or chromosomes from one generation to the next.
219/// It is analogous to reproduction and biological crossover.
220///
221/// A [Crossover] typically takes two parent [Chromosome]s and produces two or more offspring [Chromosome]s.
222/// This trait allows you to define your own crossover operation on either the entire population
223/// or a subset of the population. If a struct implements the [Crossover] trait but does not override
224/// any of the methods, the default implementation will perform a simple crossover operation on the
225/// entire population.
226pub trait Crossover<C: Chromosome>: Send + Sync {
227    fn name(&self) -> String {
228        std::any::type_name::<Self>()
229            .split("::")
230            .last()
231            .map(|s| s.to_snake_case())
232            .unwrap()
233    }
234
235    fn rate(&self) -> Rate {
236        Rate::default()
237    }
238
239    fn alterer(self) -> Alterer<C>
240    where
241        Self: Sized + 'static,
242    {
243        Alterer::Crossover(intern!(self.name()), self.rate(), Arc::new(self))
244    }
245
246    #[inline]
247    fn crossover(
248        &self,
249        population: &mut Population<C>,
250        generation: usize,
251        rate: f32,
252    ) -> AlterResult {
253        let mut result = AlterResult::default();
254
255        for i in 0..population.len() {
256            if random_provider::bool(rate) && population.len() > MIN_POPULATION_SIZE {
257                let parent_indexes =
258                    indexes::individual_indexes(i, population.len(), MIN_NUM_PARENTS);
259                let cross_result = self.cross(population, &parent_indexes, generation, rate);
260                result.merge(cross_result);
261            }
262        }
263
264        result
265    }
266
267    #[inline]
268    fn cross(
269        &self,
270        population: &mut Population<C>,
271        parent_indexes: &[usize],
272        generation: usize,
273        rate: f32,
274    ) -> AlterResult {
275        let mut result = AlterResult::default();
276
277        if let Some((one, two)) = population.get_pair_mut(parent_indexes[0], parent_indexes[1]) {
278            let mut cross_result = {
279                let geno_one = one.genotype_mut();
280                let geno_two = two.genotype_mut();
281
282                let min_len = std::cmp::min(geno_one.len(), geno_two.len());
283                let chromosome_index = random_provider::range(0..min_len);
284
285                let chrom_one = &mut geno_one[chromosome_index];
286                let chrom_two = &mut geno_two[chromosome_index];
287
288                self.cross_chromosomes(chrom_one, chrom_two, rate)
289            };
290
291            if cross_result.count() > 0 {
292                let parent_lineage = (one.family(), two.family());
293                let parent_ids = (one.id(), two.id());
294                one.invalidate(generation);
295                two.invalidate(generation);
296
297                cross_result.update_lineage((parent_lineage, parent_ids, one.id()));
298                cross_result.update_lineage((parent_lineage, parent_ids, two.id()));
299                result.merge(cross_result);
300            }
301        }
302
303        result
304    }
305
306    #[inline]
307    fn cross_chromosomes(&self, chrom_one: &mut C, chrom_two: &mut C, rate: f32) -> AlterResult {
308        let mut cross_count = 0;
309
310        for i in 0..std::cmp::min(chrom_one.len(), chrom_two.len()) {
311            if random_provider::bool(rate) {
312                let gene_one = chrom_one.get(i);
313                let gene_two = chrom_two.get(i);
314
315                let new_gene_one = gene_one.with_allele(gene_two.allele());
316                let new_gene_two = gene_two.with_allele(gene_one.allele());
317
318                chrom_one.set(i, new_gene_one);
319                chrom_two.set(i, new_gene_two);
320
321                cross_count += 1;
322            }
323        }
324
325        AlterResult::from(cross_count)
326    }
327}
328
329pub trait Mutate<C: Chromosome>: Send + Sync {
330    fn name(&self) -> String {
331        std::any::type_name::<Self>()
332            .split("::")
333            .last()
334            .map(|s| s.to_snake_case())
335            .unwrap()
336    }
337
338    fn rate(&self) -> Rate {
339        Rate::default()
340    }
341
342    fn alterer(self) -> Alterer<C>
343    where
344        Self: Sized + 'static,
345    {
346        Alterer::Mutate(intern!(self.name()), self.rate(), Arc::new(self))
347    }
348
349    #[inline]
350    fn mutate(&self, population: &mut Population<C>, generation: usize, rate: f32) -> AlterResult {
351        let mut result = AlterResult::default();
352
353        for phenotype in population.iter_mut() {
354            let mutate_result = self.mutate_genotype(phenotype.genotype_mut(), rate);
355
356            if mutate_result.count() > 0 {
357                let parent = (phenotype.family(), phenotype.id());
358                phenotype.invalidate(generation);
359                result.update_lineage((parent, phenotype.id()));
360            }
361
362            result.merge(mutate_result);
363        }
364
365        result
366    }
367
368    #[inline]
369    fn mutate_genotype(&self, genotype: &mut Genotype<C>, rate: f32) -> AlterResult {
370        let mut result = AlterResult::default();
371
372        for chromosome in genotype.iter_mut() {
373            let mutate_result = self.mutate_chromosome(chromosome, rate);
374            result.merge(mutate_result);
375        }
376
377        result
378    }
379
380    #[inline]
381    fn mutate_chromosome(&self, chromosome: &mut C, rate: f32) -> AlterResult {
382        let mut count = 0;
383        for gene in chromosome.iter_mut() {
384            if random_provider::bool(rate) {
385                *gene = self.mutate_gene(gene);
386                count += 1;
387            }
388        }
389
390        count.into()
391    }
392
393    #[inline]
394    fn mutate_gene(&self, gene: &C::Gene) -> C::Gene {
395        gene.new_instance()
396    }
397}