radiate_core/genome/chromosomes/
int.rs

1use super::{
2    Chromosome,
3    gene::{ArithmeticGene, Gene, Valid},
4};
5use rand::distr::uniform::SampleUniform;
6use std::{
7    fmt::Debug,
8    fmt::Display,
9    ops::{Add, Div, Mul, Range, Sub},
10};
11
12use crate::{chromosomes::BoundedGene, random_provider};
13#[cfg(feature = "serde")]
14use serde::{Deserialize, Serialize};
15
16pub trait Integer<T>:
17    Copy
18    + Clone
19    + PartialOrd
20    + Debug
21    + PartialEq
22    + Add<Output = T>
23    + Sub<Output = T>
24    + Mul<Output = T>
25    + Div<Output = T>
26    + SampleUniform
27    + Display
28    + Default
29where
30    T: PartialEq + PartialOrd + Copy + Clone + Debug + Display + Default,
31{
32    const MIN: T;
33    const MAX: T;
34    const ZERO: T;
35    const ONE: T;
36    const TWO: T;
37
38    fn sat_add(self, rhs: T) -> T;
39    fn sat_sub(self, rhs: T) -> T;
40    fn sat_mul(self, rhs: T) -> T;
41    fn sat_div(self, rhs: T) -> T;
42    fn clamp(self, min: T, max: T) -> T;
43}
44
45#[macro_export]
46macro_rules! impl_integer {
47    ($($t:ty),*) => {
48        $(
49            impl Integer<$t> for $t {
50                const MIN: $t = <$t>::MIN;
51                const MAX: $t = <$t>::MAX;
52                const ZERO: $t = 0;
53                const ONE: $t = 1;
54                const TWO: $t = 2;
55
56                fn sat_add(self, rhs: $t) -> $t {
57                    self.saturating_add(rhs)
58                }
59
60                fn sat_sub(self, rhs: $t) -> $t {
61                    self.saturating_sub(rhs)
62                }
63
64                fn sat_mul(self, rhs: $t) -> $t {
65                    self.saturating_mul(rhs)
66                }
67
68                fn sat_div(self, rhs: $t) -> $t {
69                    if rhs == Self::ZERO {
70                        self.saturating_div(Self::ONE)
71                    } else {
72                        self.saturating_div(rhs)
73                    }
74                }
75
76                fn clamp(self, min: $t, max: $t) -> $t {
77                    if self < min {
78                        min
79                    } else if self > max {
80                        max
81                    } else {
82                        self
83                    }
84                }
85            }
86        )*
87    };
88}
89
90impl_integer!(i8, i16, i32, i64, i128, u8, u16, u32, u64, u128);
91
92/// A [`Gene`] that represents an integer value. This gene just wraps an integer value and provides
93/// functionality for it to be used in a genetic algorithm. In this [`Gene`] implementation, the
94/// `allele` is the integer value itself, the min and max values are the minimum and maximum values
95/// that the integer can be generated from, and the upper and lower bounds are the upper and lower bounds the gene will
96/// be subject to during crossover and mutation. If the `allele` exceedes the bounds, the [`Gene`] will be considered invalid.
97///
98/// [`IntGene`] is generic over `T` - the type of integer. The `Integer` trait is implemented
99/// for `i8`, `i16`, `i32`, `i64`, `i128`, `u8`, `u16`, `u32`, `u64`, and `u128`.
100///
101/// # Example
102/// ``` rust
103/// use radiate_core::*;
104///
105/// // Create a new IntGene with an allele of 5, the min value will be i32::MIN
106/// // and the max value will be i32::MAX - same for the upper and lower bounds.
107/// let gene: IntGene<i32> = 5.into();
108///
109/// // Create the same gene, but with a different method
110/// let gene = IntGene::from(5);
111///
112/// // Create a gene, but with a min value of 0 and a max value of 10. In this case,
113/// // the allele will be a random value between 0 and 10. The min and max values will
114/// // be set to 0 and 10, and the upper and lower bounds will be set to 0 and 10.
115/// let gene = IntGene::from(0..10);
116///
117/// // Create a gene with a min value of 0 and a max value of 10, but with upper and lower bounds of 10 and 0.
118/// // In this case, the allele will be a random value between 0 and 10, but the lower and upper bounds will be -10 and 10.
119/// let gene = IntGene::from((0..10, -10..10));
120/// ```
121///
122/// # Type Parameters
123/// - `T`: The type of integer used in the gene.
124#[derive(Clone, PartialEq, Default, Debug)]
125#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
126pub struct IntGene<T: Integer<T>> {
127    allele: T,
128    value_range: Range<T>,
129    bounds: Range<T>,
130}
131
132impl<T: Integer<T>> IntGene<T> {
133    /// Create a new [`IntGene`] with the given allele, value range and bounds.
134    pub fn new(allele: T, value_range: Range<T>, bounds: Range<T>) -> Self {
135        IntGene {
136            allele,
137            value_range,
138            bounds,
139        }
140    }
141}
142
143/// Implement the [`Gene`] trait for [`IntGene`]. This allows the [`IntGene`] to be used in a genetic algorithm.
144impl<T: Integer<T>> Gene for IntGene<T> {
145    type Allele = T;
146
147    fn allele(&self) -> &T {
148        &self.allele
149    }
150
151    fn allele_mut(&mut self) -> &mut T {
152        &mut self.allele
153    }
154
155    /// Create a new instance of the [`IntGene`] with a random allele between the min and max values.
156    fn new_instance(&self) -> IntGene<T> {
157        IntGene {
158            allele: random_provider::range(self.value_range.clone()),
159            value_range: self.value_range.clone(),
160            bounds: self.bounds.clone(),
161        }
162    }
163
164    fn with_allele(&self, allele: &T) -> IntGene<T> {
165        IntGene {
166            allele: *allele,
167            value_range: self.value_range.clone(),
168            bounds: self.bounds.clone(),
169        }
170    }
171}
172
173/// Implement the `Valid` trait for [`IntGene`]. This allows the [`IntGene`] to be checked for validity.
174/// An [`IntGene`] is valid if the `allele` is between the `min` and `max` values.
175///
176/// Note: the bounds are used for crossover and mutation.
177impl<T: Integer<T>> Valid for IntGene<T> {
178    fn is_valid(&self) -> bool {
179        self.allele >= self.bounds.start && self.allele <= self.bounds.end
180    }
181}
182
183/// Implement the `BoundedGene` trait for [`IntGene`]. This allows parts of radiate to
184/// access the 'min', 'max', and bounds values of the [`IntGene`].
185impl<T: Integer<T>> BoundedGene for IntGene<T> {
186    fn min(&self) -> &Self::Allele {
187        &self.value_range.start
188    }
189
190    fn max(&self) -> &Self::Allele {
191        &self.value_range.end
192    }
193
194    fn bounds(&self) -> (&Self::Allele, &Self::Allele) {
195        (&self.bounds.start, &self.bounds.end)
196    }
197}
198
199/// Implement the `ArithmeticGene` trait for [`IntGene`]. This allows the [`IntGene`] to be used in numeric
200/// operations. The `ArithmeticGene` trait is a superset of the [`Gene`] trait, and adds functionality
201/// for numeric operations such as addition, subtraction, multiplication, division and mean.
202impl<T: Integer<T>> ArithmeticGene for IntGene<T> {
203    fn mean(&self, other: &IntGene<T>) -> IntGene<T> {
204        IntGene {
205            allele: (self.allele.sat_add(other.allele)).sat_div(T::TWO),
206            value_range: self.value_range.clone(),
207            bounds: self.bounds.clone(),
208        }
209    }
210}
211
212impl<T: Integer<T>> Add for IntGene<T> {
213    type Output = IntGene<T>;
214
215    fn add(self, other: IntGene<T>) -> IntGene<T> {
216        IntGene {
217            allele: self
218                .allele
219                .sat_add(other.allele)
220                .clamp(self.bounds.start, self.bounds.end),
221            value_range: self.value_range.clone(),
222            bounds: self.bounds.clone(),
223        }
224    }
225}
226
227impl<T: Integer<T>> Sub for IntGene<T> {
228    type Output = IntGene<T>;
229
230    fn sub(self, other: IntGene<T>) -> IntGene<T> {
231        IntGene {
232            allele: self
233                .allele
234                .sat_sub(other.allele)
235                .clamp(self.bounds.start, self.bounds.end),
236            value_range: self.value_range.clone(),
237            bounds: self.bounds.clone(),
238        }
239    }
240}
241
242impl<T: Integer<T>> Mul for IntGene<T> {
243    type Output = IntGene<T>;
244
245    fn mul(self, other: IntGene<T>) -> IntGene<T> {
246        IntGene {
247            allele: self
248                .allele
249                .sat_mul(other.allele)
250                .clamp(self.bounds.start, self.bounds.end),
251            value_range: self.value_range.clone(),
252            bounds: self.bounds.clone(),
253        }
254    }
255}
256
257impl<T: Integer<T>> Div for IntGene<T> {
258    type Output = IntGene<T>;
259
260    fn div(self, other: IntGene<T>) -> IntGene<T> {
261        IntGene {
262            allele: self
263                .allele
264                .sat_div(other.allele)
265                .clamp(self.bounds.start, self.bounds.end),
266            value_range: self.value_range.clone(),
267            bounds: self.bounds.clone(),
268        }
269    }
270}
271
272impl<T: Integer<T>> From<T> for IntGene<T> {
273    fn from(allele: T) -> Self {
274        IntGene {
275            allele,
276            value_range: T::MIN..T::MAX,
277            bounds: T::MIN..T::MAX,
278        }
279    }
280}
281
282impl<T: Integer<T>> From<Range<T>> for IntGene<T> {
283    fn from(range: Range<T>) -> Self {
284        let (min, max) = (range.start, range.end);
285
286        IntGene {
287            allele: random_provider::range(range),
288            value_range: min..max,
289            bounds: min..max,
290        }
291    }
292}
293
294impl<T: Integer<T>> From<(Range<T>, Range<T>)> for IntGene<T> {
295    fn from((range, bounds): (Range<T>, Range<T>)) -> Self {
296        IntGene {
297            allele: random_provider::range(range.clone()),
298            value_range: range,
299            bounds,
300        }
301    }
302}
303
304impl<T: Integer<T>> std::fmt::Display for IntGene<T> {
305    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
306        write!(f, "{}", self.allele)
307    }
308}
309
310/// Represents a chromosome composed of integer genes.
311///
312/// An [`IntChromosome`] is generic over the integer type `T` and contains a vector of [`IntGene<T>`]
313/// instances. This structure is suitable for optimization problems where solutions are encoded
314/// as integers.
315///
316/// # Type Parameters
317///
318/// * `T` - The integer type used for genes (e.g., `i32`, `u32`).
319///
320/// # Fields
321///
322/// * `genes` - A vector of [`IntGene<T>`] representing the individual's genetic informationn.
323///
324/// # Example
325/// ``` rust
326/// use radiate_core::*;
327///
328/// // Create a new IntChromosome with a vector of IntGene instances.
329/// let genes = vec![IntGene::from(0..10), IntGene::from(10..20)];
330/// let chromosome = IntChromosome::new(genes);
331///
332/// // Check if the chromosome is valid.
333/// assert!(chromosome.is_valid());
334///
335#[derive(Clone, PartialEq, Default)]
336#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
337pub struct IntChromosome<I: Integer<I>> {
338    genes: Vec<IntGene<I>>,
339}
340
341impl<I: Integer<I>> IntChromosome<I> {
342    /// Given a vec of [IntGene]'s, create a new [IntChromosome].
343    pub fn new(genes: Vec<IntGene<I>>) -> Self {
344        IntChromosome { genes }
345    }
346}
347
348impl<I: Integer<I>> Chromosome for IntChromosome<I> {
349    type Gene = IntGene<I>;
350
351    fn genes(&self) -> &[Self::Gene] {
352        &self.genes
353    }
354
355    fn genes_mut(&mut self) -> &mut [Self::Gene] {
356        &mut self.genes
357    }
358}
359
360impl<T: Integer<T>> Valid for IntChromosome<T> {
361    fn is_valid(&self) -> bool {
362        self.genes.iter().all(|gene| gene.is_valid())
363    }
364}
365
366impl<T: Integer<T>> From<IntGene<T>> for IntChromosome<T> {
367    fn from(gene: IntGene<T>) -> Self {
368        IntChromosome { genes: vec![gene] }
369    }
370}
371
372impl<T: Integer<T>> From<Vec<IntGene<T>>> for IntChromosome<T> {
373    fn from(genes: Vec<IntGene<T>>) -> Self {
374        IntChromosome { genes }
375    }
376}
377
378impl<T: Integer<T>> From<(usize, Range<T>)> for IntChromosome<T> {
379    fn from((size, range): (usize, Range<T>)) -> Self {
380        IntChromosome {
381            genes: (0..size).map(|_| IntGene::from(range.clone())).collect(),
382        }
383    }
384}
385
386impl<T: Integer<T>> From<(usize, Range<T>, Range<T>)> for IntChromosome<T> {
387    fn from((size, range, bounds): (usize, Range<T>, Range<T>)) -> Self {
388        IntChromosome {
389            genes: (0..size)
390                .map(|_| IntGene::from((range.clone(), bounds.clone())))
391                .collect(),
392        }
393    }
394}
395
396impl<T: Integer<T>> From<Vec<T>> for IntChromosome<T> {
397    fn from(alleles: Vec<T>) -> Self {
398        IntChromosome {
399            genes: alleles.into_iter().map(IntGene::from).collect(),
400        }
401    }
402}
403
404impl<T: Integer<T>> FromIterator<IntGene<T>> for IntChromosome<T> {
405    fn from_iter<I: IntoIterator<Item = IntGene<T>>>(iter: I) -> Self {
406        IntChromosome {
407            genes: iter.into_iter().collect(),
408        }
409    }
410}
411
412impl<T: Integer<T>> IntoIterator for IntChromosome<T> {
413    type Item = IntGene<T>;
414    type IntoIter = std::vec::IntoIter<IntGene<T>>;
415
416    fn into_iter(self) -> Self::IntoIter {
417        self.genes.into_iter()
418    }
419}
420
421impl<T: Integer<T>> Debug for IntChromosome<T> {
422    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
423        write!(f, "{:?}", self.genes)
424    }
425}
426
427#[cfg(test)]
428mod tests {
429    use super::*;
430
431    #[test]
432    fn test_new() {
433        let gene = IntGene::from(0..10);
434        assert!(gene.allele >= 0 && gene.allele <= 10);
435    }
436
437    #[test]
438    fn test_new_instance() {
439        let gene = IntGene::from(0..10);
440        let new_gene = gene.new_instance();
441        assert!(new_gene.allele >= 0 && new_gene.allele <= 10);
442    }
443
444    #[test]
445    fn test_from_allele() {
446        let gene = IntGene::from(5);
447        let new_gene = gene.with_allele(&5);
448        assert_eq!(new_gene.allele, 5);
449    }
450
451    #[test]
452    fn test_is_valid() {
453        let gene = IntGene::from(0..10);
454        assert!(gene.is_valid());
455    }
456
457    #[test]
458    fn test_bounds() {
459        let gene_one = IntGene::from((0..10, 0..10));
460        let gene_two = IntGene::from((0..10, -100..100));
461
462        let (one_min, one_max) = gene_one.bounds();
463        let (two_min, two_max) = gene_two.bounds();
464
465        assert_eq!(*one_min, 0);
466        assert_eq!(*one_max, 10);
467        assert_eq!(*two_min, -100);
468        assert_eq!(*two_max, 100);
469        assert_eq!(gene_one.min(), &0);
470        assert_eq!(gene_one.max(), &10);
471        assert_eq!(gene_two.min(), &0);
472        assert_eq!(gene_two.max(), &10);
473        assert!(gene_one.is_valid());
474        assert!(gene_two.is_valid());
475    }
476
477    #[test]
478    fn test_mean() {
479        let gene = IntGene::from(5);
480        let other = IntGene::from(5);
481        let new_gene = gene.mean(&other);
482        assert_eq!(new_gene.allele, 5);
483    }
484
485    #[test]
486    fn test_int_arithmetic_doesnt_overflow() {
487        let gene = IntGene::<u8>::from(8_u8);
488        let other = IntGene::<u8>::from(8_u8);
489        let sixteen = IntGene::<u8>::from(16_u8);
490
491        assert_eq!((gene.clone() + other.clone()).allele, 16);
492        assert_eq!((gene.clone() - sixteen.clone()).allele, 0);
493        assert_eq!((gene.clone() * other.clone()).allele, 64);
494
495        let zero = IntGene::<u8>::from(0_u8);
496        assert_eq!((gene.clone() / zero.clone()).allele, 8);
497        assert_eq!((gene.clone() / other.clone()).allele, 1);
498
499        let max = IntGene::<u8>::from(u8::MAX);
500        assert_eq!((max.clone() + other.clone()).allele, u8::MAX);
501        assert_eq!((zero.clone() - other.clone()).allele, 0);
502
503        let i_eight = IntGene::<i8>::from(8_i8);
504        let i_other = IntGene::<i8>::from(8_i8);
505        let i_sixteen = IntGene::<i8>::from(16_i8);
506
507        assert_eq!((i_eight.clone() + i_other.clone()).allele, 16);
508        assert_eq!((i_eight.clone() - i_sixteen.clone()).allele, -8);
509        assert_eq!((i_eight.clone() * i_other.clone()).allele, 64);
510    }
511
512    #[test]
513    fn test_int_clamp_arithmetic_clamping() {
514        let gene = IntGene::new(5, 5..10, 0..10);
515        let other = IntGene::new(5, 8..10, 0..10);
516        let really_big = IntGene::new(100000, 0..10, 0..10);
517
518        let add = gene.clone() + other.clone();
519        let sub = gene.clone() - other.clone();
520        let mul = gene.clone() * other.clone();
521        let div = gene.clone() / other.clone();
522
523        let really_big_add = gene.clone() + really_big.clone();
524        let really_big_sub = gene.clone() - really_big.clone();
525        let really_big_mul = gene.clone() * really_big.clone();
526        let really_big_div = gene.clone() / really_big.clone();
527
528        assert_eq!(add.allele, 10);
529        assert_eq!(sub.allele, 0);
530        assert_eq!(mul.allele, 10);
531        assert_eq!(div.allele, 1);
532
533        assert_eq!(really_big_add.allele, 10);
534        assert_eq!(really_big_sub.allele, 0);
535        assert_eq!(really_big_mul.allele, 10);
536        assert_eq!(really_big_div.allele, 0);
537    }
538
539    #[test]
540    fn test_into() {
541        let gene: IntGene<i32> = 5.into();
542        assert_eq!(gene.allele, 5);
543    }
544
545    #[test]
546    fn test_chromosome_from_range() {
547        let chromosome = IntChromosome::from((10, 0..10));
548        assert_eq!(chromosome.genes.len(), 10);
549        for gene in &chromosome.genes {
550            assert!(gene.allele >= 0 && gene.allele <= 10);
551        }
552    }
553
554    #[test]
555    fn test_chromosome_from_range_with_bounds() {
556        let chromosome = IntChromosome::from((10, 0..10, -10..10));
557
558        assert_eq!(chromosome.genes.len(), 10);
559        for gene in &chromosome.genes {
560            assert!(gene.allele >= 0 && gene.allele <= 10);
561            assert_eq!(*gene.bounds().0, -10);
562            assert_eq!(*gene.bounds().1, 10);
563        }
564    }
565
566    #[test]
567    fn test_chromosome_from_alleles() {
568        let alleles = vec![1, 2, 3, 4, 5];
569        let chromosome = IntChromosome::from(alleles.clone());
570
571        assert_eq!(chromosome.genes.len(), 5);
572        for (i, gene) in chromosome.genes.iter().enumerate() {
573            assert_eq!(gene.allele, alleles[i]);
574        }
575    }
576
577    #[test]
578    fn test_gene_arithmetic() {
579        let gene_one = IntGene::from(5);
580        let gene_two = IntGene::from(5);
581        let zero_gene = IntGene::from(0);
582
583        let add = gene_one.clone() + gene_two.clone();
584        let sub = gene_one.clone() - gene_two.clone();
585        let mul = gene_one.clone() * gene_two.clone();
586        let div = gene_one.clone() / gene_two.clone();
587        let div_zero = gene_one.clone() / zero_gene.clone();
588        let mean = gene_one.mean(&gene_two);
589
590        assert_eq!(add.allele, 10);
591        assert_eq!(sub.allele, 0);
592        assert_eq!(mul.allele, 25);
593        assert_eq!(div.allele, 1);
594        assert_eq!(div_zero.allele, 5);
595        assert_eq!(mean.allele, 5);
596    }
597
598    #[test]
599    #[cfg(feature = "serde")]
600    fn test_int_gene_serialization() {
601        let gene = IntGene::from(-5_i32..5_i32);
602
603        assert!(gene.is_valid());
604
605        let serialized = serde_json::to_string(&gene).expect("Failed to serialize IntGene");
606        let deserialized: IntGene<i32> =
607            serde_json::from_str(&serialized).expect("Failed to deserialize IntGene");
608
609        let chromosome = IntChromosome::from((10, 0..10, -10..10));
610        let serialized_chromosome =
611            serde_json::to_string(&chromosome).expect("Failed to serialize IntChromosome");
612        let deserialized_chromosome: IntChromosome<i32> =
613            serde_json::from_str(&serialized_chromosome)
614                .expect("Failed to deserialize IntChromosome");
615
616        assert_eq!(gene, deserialized);
617        assert_eq!(chromosome, deserialized_chromosome);
618    }
619}