Skip to main content

radiate_core/genome/chromosomes/
int.rs

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