Skip to main content

radiate_core/genome/chromosomes/
float.rs

1use super::{
2    Chromosome,
3    gene::{ArithmeticGene, BoundedGene, Gene, Valid},
4};
5use crate::random_provider;
6use radiate_utils::Float;
7#[cfg(feature = "serde")]
8use serde::{Deserialize, Serialize};
9use std::{
10    fmt::{Debug, Display},
11    ops::{Add, Div, Mul, Range, Sub},
12};
13
14/// Minimum and maximum values for the [FloatGene] allele.
15/// This should be large enough to cover most practical use cases
16/// but small enough to avoid overflow or underflow issues in calculations.
17/// 1e18 = 1 quintillion
18
19/// A [`Gene`] that represents a floating point number.
20/// The `allele` is the in the case of the [`FloatGene`] a f32. The `min` and `max` values
21/// default to [MIN] and [MAX] respectively. The `min` and `max` values are used to
22/// generate a random number between the `min` and `max` values, which is the `allele` of the [`FloatGene`].
23/// The `upper_bound` and `lower_bound` are used to set the bounds of the [`FloatGene`] when it is used
24/// in a `BoundGene` context (crossover or mutation). The `upper_bound` and `lower_bound`
25/// default to [MAX] and [MIN] respectively.
26///
27/// # Example
28/// ``` rust
29/// use radiate_core::*;
30///
31/// // Create a new FloatGene with a min value of 0 and a max value of 1 meaning the
32/// // allele will be a random number between 0 and 1.
33/// // The upper_bound and lower_bound are set to 0 and 1 respectively.
34/// let gene = FloatGene::from(0_f32..1_f32);
35///
36/// // Create a new FloatGene with a min of 0 and a max of 1 and set the upper_bound
37/// // and lower_bound to 0 and 100 respectively.
38/// let gene = FloatGene::from((0_f32..1_f32, 0_f32..100_f32));
39/// ```
40#[derive(Clone, PartialEq, Debug)]
41#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
42pub struct FloatGene<F: Float> {
43    allele: F,
44    value_range: Range<F>,
45    bounds: Range<F>,
46}
47
48impl<F: Float> FloatGene<F> {
49    /// Creates a new [`FloatGene`] with the given `allele`, `value_range`, and `bounds`.
50    pub fn new(allele: F, value_range: Range<F>, bounds: Range<F>) -> Self {
51        FloatGene {
52            allele,
53            value_range: value_range.start.max(F::MIN)..value_range.end.min(F::MAX),
54            bounds: bounds.start.max(F::MIN)..bounds.end.min(F::MAX),
55        }
56    }
57}
58
59/// Implement the [`Valid`] trait for the [`FloatGene`].
60///
61/// The `is_valid` method checks if the `allele` of the [`FloatGene`] is between the `min` and `max` values.
62/// The `GeneticEngine` will check the validity of the [`Chromosome`] and `Phenotype` and remove any
63/// invalid individuals from the population, replacing them with new individuals at the given generation.
64impl<F: Float> Valid for FloatGene<F> {
65    fn is_valid(&self) -> bool {
66        self.allele >= self.bounds.start && self.allele <= self.bounds.end
67    }
68}
69
70impl<F: Float> Gene for FloatGene<F> {
71    type Allele = F;
72
73    fn allele(&self) -> &F {
74        &self.allele
75    }
76
77    fn allele_mut(&mut self) -> &mut F {
78        &mut self.allele
79    }
80
81    fn new_instance(&self) -> FloatGene<F> {
82        FloatGene {
83            allele: random_provider::range(self.value_range.clone()),
84            value_range: self.value_range.clone(),
85            bounds: self.bounds.clone(),
86        }
87    }
88
89    fn with_allele(&self, allele: &F) -> FloatGene<F> {
90        FloatGene {
91            allele: *allele,
92            value_range: self.value_range.clone(),
93            bounds: self.bounds.clone(),
94        }
95    }
96}
97
98impl<F: Float> BoundedGene for FloatGene<F> {
99    fn min(&self) -> &Self::Allele {
100        &self.value_range.start
101    }
102
103    fn max(&self) -> &Self::Allele {
104        &self.value_range.end
105    }
106
107    fn bounds(&self) -> (&Self::Allele, &Self::Allele) {
108        (&self.bounds.start, &self.bounds.end)
109    }
110}
111
112impl<F: Float> ArithmeticGene for FloatGene<F> {
113    fn mean(&self, other: &FloatGene<F>) -> FloatGene<F> {
114        FloatGene {
115            allele: F::safe_mul(F::safe_add(*self.allele(), *other.allele()), F::HALF)
116                .safe_clamp(self.bounds.start, self.bounds.end),
117            value_range: self.value_range.clone(),
118            bounds: self.bounds.clone(),
119        }
120    }
121}
122
123impl<F: Float> Add for FloatGene<F> {
124    type Output = FloatGene<F>;
125
126    fn add(self, other: FloatGene<F>) -> FloatGene<F> {
127        FloatGene {
128            allele: F::safe_add(self.allele, other.allele)
129                .safe_clamp(self.bounds.start, self.bounds.end),
130            value_range: self.value_range.clone(),
131            bounds: self.bounds.clone(),
132        }
133    }
134}
135
136impl<F: Float> Sub for FloatGene<F> {
137    type Output = FloatGene<F>;
138
139    fn sub(self, other: FloatGene<F>) -> FloatGene<F> {
140        FloatGene {
141            allele: F::safe_sub(self.allele, 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<F: Float> Mul for FloatGene<F> {
150    type Output = FloatGene<F>;
151
152    fn mul(self, other: FloatGene<F>) -> FloatGene<F> {
153        FloatGene {
154            allele: F::safe_mul(self.allele, other.allele)
155                .safe_clamp(self.bounds.start, self.bounds.end),
156            value_range: self.value_range.clone(),
157            bounds: self.bounds.clone(),
158        }
159    }
160}
161
162impl<F: Float> Div for FloatGene<F> {
163    type Output = FloatGene<F>;
164
165    fn div(self, other: FloatGene<F>) -> FloatGene<F> {
166        FloatGene {
167            allele: F::safe_div(self.allele, other.allele)
168                .safe_clamp(self.bounds.start, self.bounds.end),
169            value_range: self.value_range.clone(),
170            bounds: self.bounds.clone(),
171        }
172    }
173}
174
175impl<F: Float> Default for FloatGene<F> {
176    fn default() -> Self {
177        FloatGene {
178            allele: F::ZERO,
179            value_range: F::MIN..F::MAX,
180            bounds: F::MIN..F::MAX,
181        }
182    }
183}
184
185impl<F: Float> From<F> for FloatGene<F> {
186    fn from(allele: F) -> Self {
187        FloatGene {
188            allele,
189            value_range: F::MIN..F::MAX,
190            bounds: F::MIN..F::MAX,
191        }
192    }
193}
194
195impl<F: Float> From<Range<F>> for FloatGene<F> {
196    fn from(range: Range<F>) -> Self {
197        let (min, max) = (range.start.max(F::MIN), range.end.min(F::MAX));
198
199        FloatGene {
200            allele: random_provider::range(range),
201            value_range: min..max,
202            bounds: min..max,
203        }
204    }
205}
206
207impl<F: Float> From<(Range<F>, Range<F>)> for FloatGene<F> {
208    fn from((value_range, bounds): (Range<F>, Range<F>)) -> Self {
209        let value_range = value_range.start.max(F::MIN)..value_range.end.min(F::MAX);
210        let bounds = bounds.start.max(F::MIN)..bounds.end.min(F::MAX);
211        let allele = random_provider::range(value_range.clone());
212
213        FloatGene {
214            allele,
215            value_range,
216            bounds,
217        }
218    }
219}
220
221impl<F: Float> Display for FloatGene<F> {
222    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
223        write!(f, "{}", self.allele)
224    }
225}
226
227/// Represents a chromosome composed of floating-point genes.
228///
229/// A [`FloatChromosome`] contains a vector of [`FloatGene`] instances, each representing
230/// a single floating-point value. This structure is typically used in problems where
231/// solutions are encoded as real numbers.
232///
233/// # Fields
234///
235/// * `genes` - A vector of [`FloatGene`] representing the individual's genetic information.
236///
237/// # Example
238/// ```rust
239/// use radiate_core::*;
240///
241/// // Create a chromosome with 3 genes with alleles 0.0, 1.0, and 2.0 respectively
242/// let chromosome = FloatChromosome::from(vec![0.0, 1.0, 2.0]);
243/// let chromosome_alleles = chromosome
244///     .iter()
245///     .map(|gene| *gene.allele())
246///     .collect::<Vec<f32>>();
247///
248/// assert!(chromosome.is_valid());
249/// assert_eq!(chromosome_alleles.len(), 3);
250/// assert_eq!(chromosome_alleles, vec![0.0, 1.0, 2.0]);
251///
252/// // Create a chromosome with 3 genes all with alleles in the range 0.0 to 10.0
253/// let ranged_chromo = FloatChromosome::from((3, 0.0..10.0));
254/// let ranged_chromo_alleles = ranged_chromo
255///    .iter()
256///    .map(|gene| *gene.allele())
257///    .collect::<Vec<f32>>();
258///
259/// assert!(ranged_chromo.is_valid());
260/// assert_eq!(ranged_chromo_alleles.len(), 3);
261/// for allele in ranged_chromo_alleles {
262///    assert!(allele >= 0.0 && allele <= 10.0);
263/// }
264///```
265#[derive(Clone, PartialEq, Default)]
266#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
267pub struct FloatChromosome<F: Float> {
268    genes: Vec<FloatGene<F>>,
269}
270
271impl<F: Float> FloatChromosome<F> {
272    pub fn new(genes: Vec<FloatGene<F>>) -> Self {
273        FloatChromosome { genes }
274    }
275}
276
277impl<F: Float> Chromosome for FloatChromosome<F> {
278    type Gene = FloatGene<F>;
279
280    fn as_slice(&self) -> &[Self::Gene] {
281        &self.genes
282    }
283
284    fn as_mut_slice(&mut self) -> &mut [Self::Gene] {
285        &mut self.genes
286    }
287}
288
289impl<F: Float> Valid for FloatChromosome<F> {
290    fn is_valid(&self) -> bool {
291        self.genes.iter().all(|gene| gene.is_valid())
292    }
293}
294
295impl<F: Float> From<FloatGene<F>> for FloatChromosome<F> {
296    fn from(gene: FloatGene<F>) -> Self {
297        FloatChromosome { genes: vec![gene] }
298    }
299}
300
301impl<F: Float> From<Vec<FloatGene<F>>> for FloatChromosome<F> {
302    fn from(genes: Vec<FloatGene<F>>) -> Self {
303        FloatChromosome { genes }
304    }
305}
306
307impl<F: Float> From<Vec<F>> for FloatChromosome<F> {
308    fn from(alleles: Vec<F>) -> Self {
309        FloatChromosome {
310            genes: alleles.into_iter().map(FloatGene::from).collect(),
311        }
312    }
313}
314
315impl<F: Float> From<(usize, Range<F>)> for FloatChromosome<F> {
316    fn from((size, range): (usize, Range<F>)) -> Self {
317        FloatChromosome {
318            genes: (0..size).map(|_| FloatGene::from(range.clone())).collect(),
319        }
320    }
321}
322
323impl<F: Float> From<(usize, Range<F>, Range<F>)> for FloatChromosome<F> {
324    fn from((size, range, bounds): (usize, Range<F>, Range<F>)) -> Self {
325        FloatChromosome {
326            genes: (0..size)
327                .map(|_| FloatGene::from((range.clone(), bounds.clone())))
328                .collect(),
329        }
330    }
331}
332
333impl<F: Float> FromIterator<FloatGene<F>> for FloatChromosome<F> {
334    fn from_iter<I: IntoIterator<Item = FloatGene<F>>>(iter: I) -> Self {
335        FloatChromosome {
336            genes: iter.into_iter().collect(),
337        }
338    }
339}
340
341impl<F: Float> IntoIterator for FloatChromosome<F> {
342    type Item = FloatGene<F>;
343    type IntoIter = std::vec::IntoIter<FloatGene<F>>;
344
345    fn into_iter(self) -> Self::IntoIter {
346        self.genes.into_iter()
347    }
348}
349
350impl<F: Float> Debug for FloatChromosome<F> {
351    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
352        write!(f, "{:?}", self.genes)
353    }
354}
355
356#[cfg(test)]
357mod tests {
358
359    use super::*;
360
361    const MIN: f32 = -1e18;
362    const MAX: f32 = 1e18;
363
364    #[test]
365    fn test_new() {
366        let gene_one = FloatGene::from(0_f32..1_f32);
367        let gene_two = FloatGene::from((-1.0..1.0, -100.0..100.0));
368        let gene_three = FloatGene::new(10.0, (MIN * 10.0)..(MAX * 10.0), -1000.0..1000.0);
369
370        // assert_eq!(*gene_one.min(), 0_f32);
371        assert_eq!(*gene_one.max(), 1_f32);
372        assert_eq!(gene_one.bounds().0, &0_f32);
373        assert_eq!(gene_one.bounds().1, &1_f32);
374        assert!(gene_one.is_valid());
375
376        // assert_eq!(*gene_two.min(), -1.0);
377        assert_eq!(*gene_two.max(), 1.0);
378        assert_eq!(gene_two.bounds().0, &-100.0);
379        assert_eq!(gene_two.bounds().1, &100.0);
380        assert!(gene_two.is_valid());
381
382        assert_eq!(*gene_three.allele(), 10.0);
383        // assert_eq!(*gene_three.min(), MIN);
384        assert_eq!(*gene_three.max(), MAX * 10.0);
385        assert_eq!(gene_three.bounds().0, &-1000.0);
386        assert_eq!(gene_three.bounds().1, &1000.0);
387    }
388
389    #[test]
390    fn test_from() {
391        let gene = FloatGene::from(0_f32..1_f32);
392        let copy = gene.clone();
393        assert_eq!(gene, copy);
394    }
395
396    #[test]
397    fn test_is_valid() {
398        let gene = FloatGene::from(0_f32..1_f32);
399        assert!(gene.is_valid());
400        assert!(gene.allele >= 0_f32 && gene.allele <= 1_f32);
401    }
402
403    #[test]
404    fn test_gene_clamping() {
405        let one = FloatGene::new(5.0, 0.0..10.0, 0.0..10.0);
406        let two = FloatGene::new(5.0, 0.0..10.0, 0.0..10.0);
407        let really_big = FloatGene::new(100000.0, 0.0..10.0, 0.0..10.0);
408
409        let add = one.clone() + two.clone();
410        let sub = one.clone() - two.clone();
411        let mul = one.clone() * two.clone();
412        let div = one.clone() / two.clone();
413
414        assert_eq!(add.allele, 10.0);
415        assert_eq!(sub.allele, 0.0);
416        assert_eq!(mul.allele, 10.0);
417        assert_eq!(div.allele, 1.0);
418
419        let big_add = one.clone() + really_big.clone();
420        let big_sub = one.clone() - really_big.clone();
421        let big_mul = one.clone() * really_big.clone();
422        let big_div = really_big.clone() / one.clone();
423
424        assert_eq!(big_add.allele, 10.0);
425        assert_eq!(big_sub.allele, 0.0);
426        assert_eq!(big_mul.allele, 10.0);
427        assert_eq!(big_div.allele, 10.0);
428    }
429
430    #[test]
431    fn test_chromosome() {
432        let chromosome = FloatChromosome::from((10, -1.0..1.0));
433
434        assert_eq!(chromosome.len(), 10);
435        assert!(chromosome.is_valid());
436        for gene in chromosome.iter() {
437            assert!(gene.is_valid());
438            assert!(gene.allele >= -1.0 && gene.allele <= 1.0);
439        }
440    }
441
442    #[test]
443    fn test_chromosome_from_vec() {
444        let chromosome = FloatChromosome::from(vec![0.0, 1.0, 2.0]);
445
446        assert_eq!(chromosome.len(), 3);
447        assert!(chromosome.is_valid());
448        for (gene, allele) in chromosome.iter().zip(vec![0.0, 1.0, 2.0]) {
449            assert!(gene.is_valid());
450            assert_eq!(gene.allele, allele);
451        }
452    }
453
454    #[test]
455    fn test_chromosome_from_range_with_bounds() {
456        let chromosome = FloatChromosome::from((3, 0.0..10.0, -10.0..10.0));
457
458        assert_eq!(chromosome.len(), 3);
459        assert!(chromosome.is_valid());
460        for gene in chromosome.iter() {
461            assert!(gene.is_valid());
462            assert!(gene.allele >= 0.0 && gene.allele <= 10.0);
463            assert!(gene.bounds.start >= -10.0 && gene.bounds.end <= 10.0);
464        }
465    }
466
467    #[test]
468    fn test_gene_arithmetic() {
469        let gene_one = FloatGene::from(5_f32);
470        let gene_two = FloatGene::from(10_f32);
471        let zero_gene = FloatGene::from(0_f32);
472
473        let add = gene_one.clone() + gene_two.clone();
474        let sub = gene_one.clone() - gene_two.clone();
475        let mul = gene_one.clone() * gene_two.clone();
476        let div = gene_one.clone() / gene_two.clone();
477        let mean = gene_one.clone().mean(&gene_two.clone());
478        let div_zero = gene_one.clone() / zero_gene.clone();
479
480        assert_eq!(add.allele, 15_f32);
481        assert_eq!(sub.allele, -5_f32);
482        assert_eq!(mul.allele, 50_f32);
483        assert_eq!(div.allele, 0.5_f32);
484        assert_eq!(mean.allele, 7.5_f32);
485        assert_eq!(div_zero.allele, 5_f32);
486    }
487
488    #[test]
489    #[cfg(feature = "serde")]
490    fn test_float_gene_serialization() {
491        let gene = FloatGene::from(0.5_f32..1.5_f32);
492
493        assert!(gene.is_valid());
494
495        let serialized = serde_json::to_string(&gene).expect("Failed to serialize FloatGene");
496        let deserialized: FloatGene<f32> =
497            serde_json::from_str(&serialized).expect("Failed to deserialize FloatGene");
498
499        let chromosome = FloatChromosome::from((10, 0.0..1.0, -1.0..1.0));
500        let serialized_chromosome =
501            serde_json::to_string(&chromosome).expect("Failed to serialize FloatChromosome");
502        let deserialized_chromosome: FloatChromosome<f32> =
503            serde_json::from_str(&serialized_chromosome)
504                .expect("Failed to deserialize FloatChromosome");
505
506        assert_eq!(gene, deserialized);
507        assert_eq!(chromosome, deserialized_chromosome);
508    }
509}