radiate_core/genome/chromosomes/
int.rs

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