radiate_core/genome/chromosomes/
float.rs

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