radiate_core/genome/chromosomes/
float.rs

1use super::{
2    Chromosome,
3    gene::{ArithmeticGene, Gene, Valid},
4};
5use crate::random_provider;
6#[cfg(feature = "serde")]
7use serde::{Deserialize, Serialize};
8use std::{
9    fmt::{Debug, Display},
10    ops::{Add, Bound, Div, Mul, Range, RangeBounds, 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    pub fn bounds(&self) -> &Range<f32> {
59        &self.bounds
60    }
61}
62
63/// Implement the [`Valid`] trait for the [`FloatGene`].
64///
65/// The `is_valid` method checks if the `allele` of the [`FloatGene`] is between the `min` and `max` values.
66/// The `GeneticEngine` will check the validity of the [`Chromosome`] and `Phenotype` and remove any
67/// invalid individuals from the population, replacing them with new individuals at the given generation.
68impl Valid for FloatGene {
69    fn is_valid(&self) -> bool {
70        self.allele >= self.bounds.start && self.allele <= self.bounds.end
71    }
72}
73
74impl Gene for FloatGene {
75    type Allele = f32;
76
77    fn allele(&self) -> &f32 {
78        &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 ArithmeticGene 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 mean(&self, other: &FloatGene) -> FloatGene {
108        FloatGene {
109            allele: (self.allele + other.allele) / 2_f32,
110            value_range: self.value_range.clone(),
111            bounds: self.bounds.clone(),
112        }
113    }
114
115    fn from_f32(&self, value: f32) -> Self {
116        FloatGene {
117            allele: value,
118            value_range: self.value_range.clone(),
119            bounds: self.bounds.clone(),
120        }
121    }
122}
123
124impl RangeBounds<f32> for FloatGene {
125    fn start_bound(&self) -> Bound<&f32> {
126        self.bounds.start_bound()
127    }
128
129    fn end_bound(&self) -> Bound<&f32> {
130        self.bounds.end_bound()
131    }
132}
133
134impl Add for FloatGene {
135    type Output = FloatGene;
136
137    fn add(self, other: FloatGene) -> FloatGene {
138        FloatGene {
139            allele: self.allele + other.allele,
140            value_range: self.value_range.clone(),
141            bounds: self.bounds.clone(),
142        }
143    }
144}
145
146impl Sub for FloatGene {
147    type Output = FloatGene;
148
149    fn sub(self, other: FloatGene) -> FloatGene {
150        FloatGene {
151            allele: self.allele - other.allele,
152            value_range: self.value_range.clone(),
153            bounds: self.bounds.clone(),
154        }
155    }
156}
157
158impl Mul for FloatGene {
159    type Output = FloatGene;
160
161    fn mul(self, other: FloatGene) -> FloatGene {
162        FloatGene {
163            allele: self.allele * other.allele,
164            value_range: self.value_range.clone(),
165            bounds: self.bounds.clone(),
166        }
167    }
168}
169
170impl Div for FloatGene {
171    type Output = FloatGene;
172
173    fn div(self, other: FloatGene) -> FloatGene {
174        let denominator = if other.allele == 0.0 {
175            1.0
176        } else {
177            other.allele
178        };
179
180        FloatGene {
181            allele: self.allele / denominator,
182            value_range: self.value_range.clone(),
183            bounds: self.bounds.clone(),
184        }
185    }
186}
187
188impl Default for FloatGene {
189    fn default() -> Self {
190        FloatGene {
191            allele: 0.0,
192            value_range: MIN..MAX,
193            bounds: MIN..MAX,
194        }
195    }
196}
197
198impl From<FloatGene> for f32 {
199    fn from(gene: FloatGene) -> f32 {
200        gene.allele
201    }
202}
203
204impl From<f32> for FloatGene {
205    fn from(allele: f32) -> Self {
206        FloatGene {
207            allele,
208            value_range: MIN..MAX,
209            bounds: MIN..MAX,
210        }
211    }
212}
213
214impl From<Range<f32>> for FloatGene {
215    fn from(range: Range<f32>) -> Self {
216        let (min, max) = (range.start.max(MIN), range.end.min(MAX));
217
218        FloatGene {
219            allele: random_provider::range(range),
220            value_range: min..max,
221            bounds: min..max,
222        }
223    }
224}
225
226impl From<(Range<f32>, Range<f32>)> for FloatGene {
227    fn from((value_range, bounds): (Range<f32>, Range<f32>)) -> Self {
228        let value_range = value_range.start.max(MIN)..value_range.end.min(MAX);
229        let bounds = bounds.start.max(MIN)..bounds.end.min(MAX);
230        let allele = random_provider::range(value_range.clone());
231
232        FloatGene {
233            allele,
234            value_range,
235            bounds,
236        }
237    }
238}
239
240impl Display for FloatGene {
241    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
242        write!(f, "{}", self.allele)
243    }
244}
245
246/// Represents a chromosome composed of floating-point genes.
247///
248/// A [`FloatChromosome`] contains a vector of [`FloatGene`] instances, each representing
249/// a single floating-point value. This structure is typically used in problems where
250/// solutions are encoded as real numbers.
251///
252/// # Fields
253///
254/// * `genes` - A vector of [`FloatGene`] representing the individual's genetic information.
255///
256/// # Example
257/// ```rust
258/// use radiate_core::*;
259///
260/// let chromosome = FloatChromosome::from(vec![0.0, 1.0, 2.0]);
261/// let chromosome_allels = chromosome
262///     .iter()
263///     .map(|gene| *gene.allele())
264///     .collect::<Vec<f32>>();
265///
266/// assert!(chromosome.is_valid());
267/// assert_eq!(chromosome_allels.len(), 3);
268/// assert_eq!(chromosome_allels, vec![0.0, 1.0, 2.0]);
269///
270/// let ranged_chromo = FloatChromosome::from((3, 0.0..10.0));
271/// let ranged_chromo_allels = ranged_chromo
272///    .iter()
273///    .map(|gene| *gene.allele())
274///    .collect::<Vec<f32>>();
275///
276/// assert!(ranged_chromo.is_valid());
277/// assert_eq!(ranged_chromo_allels.len(), 3);
278/// for allele in ranged_chromo_allels {
279///    assert!(allele >= 0.0 && allele <= 10.0);
280/// }
281///```
282#[derive(Clone, PartialEq, Default)]
283#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
284pub struct FloatChromosome {
285    genes: Vec<FloatGene>,
286}
287
288impl FloatChromosome {
289    pub fn new(genes: Vec<FloatGene>) -> Self {
290        FloatChromosome { genes }
291    }
292}
293
294impl Chromosome for FloatChromosome {
295    type Gene = FloatGene;
296
297    fn genes(&self) -> &[Self::Gene] {
298        &self.genes
299    }
300
301    fn genes_mut(&mut self) -> &mut [Self::Gene] {
302        &mut self.genes
303    }
304}
305
306impl Valid for FloatChromosome {
307    fn is_valid(&self) -> bool {
308        self.genes.iter().all(|gene| gene.is_valid())
309    }
310}
311
312impl From<Vec<FloatGene>> for FloatChromosome {
313    fn from(genes: Vec<FloatGene>) -> Self {
314        FloatChromosome { genes }
315    }
316}
317
318impl From<Vec<f32>> for FloatChromosome {
319    fn from(alleles: Vec<f32>) -> Self {
320        FloatChromosome {
321            genes: alleles.into_iter().map(FloatGene::from).collect(),
322        }
323    }
324}
325
326impl From<(usize, Range<f32>)> for FloatChromosome {
327    fn from((size, range): (usize, Range<f32>)) -> Self {
328        FloatChromosome {
329            genes: (0..size).map(|_| FloatGene::from(range.clone())).collect(),
330        }
331    }
332}
333
334impl From<(usize, Range<f32>, Range<f32>)> for FloatChromosome {
335    fn from((size, range, bounds): (usize, Range<f32>, Range<f32>)) -> Self {
336        FloatChromosome {
337            genes: (0..size)
338                .map(|_| FloatGene::from((range.clone(), bounds.clone())))
339                .collect(),
340        }
341    }
342}
343
344impl Debug for FloatChromosome {
345    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
346        write!(f, "{:?}", self.genes)
347    }
348}
349
350#[cfg(test)]
351mod tests {
352
353    use super::*;
354
355    #[test]
356    fn test_new() {
357        let gene_one = FloatGene::from(0_f32..1_f32);
358        let gene_two = FloatGene::from((-1.0..1.0, -100.0..100.0));
359        let gene_three = FloatGene::new(10.0, (MIN * 10.0)..(MAX * 10.0), -1000.0..1000.0);
360
361        assert_eq!(*gene_one.min(), 0_f32);
362        assert_eq!(*gene_one.max(), 1_f32);
363        assert_eq!(gene_one.start_bound(), Bound::Included(&0_f32));
364        assert_eq!(gene_one.end_bound(), Bound::Excluded(&1_f32));
365        assert!(gene_one.is_valid());
366
367        assert_eq!(*gene_two.min(), -1.0);
368        assert_eq!(*gene_two.max(), 1.0);
369        assert_eq!(gene_two.start_bound(), Bound::Included(&-100.0));
370        assert_eq!(gene_two.end_bound(), Bound::Excluded(&100.0));
371        assert!(gene_two.is_valid());
372
373        assert_eq!(*gene_three.allele(), 10.0);
374        assert_eq!(*gene_three.min(), MIN);
375        assert_eq!(*gene_three.max(), MAX);
376        assert_eq!(gene_three.start_bound(), Bound::Included(&-1000.0));
377        assert_eq!(gene_three.end_bound(), Bound::Excluded(&1000.0));
378    }
379
380    #[test]
381    fn test_into() {
382        let gene = FloatGene::from(0_f32..1_f32);
383        let copy = gene.clone();
384        let allele: f32 = gene.into();
385        assert_eq!(allele, copy.allele);
386    }
387
388    #[test]
389    fn test_from() {
390        let gene = FloatGene::from(0_f32..1_f32);
391        let copy = gene.clone();
392        assert_eq!(gene, copy);
393    }
394
395    #[test]
396    fn test_is_valid() {
397        let gene = FloatGene::from(0_f32..1_f32);
398        assert!(gene.is_valid());
399        assert!(gene.allele >= 0_f32 && gene.allele <= 1_f32);
400    }
401
402    #[test]
403    fn test_chromosome() {
404        let chromosome = FloatChromosome::from((10, -1.0..1.0));
405
406        assert_eq!(chromosome.len(), 10);
407        assert!(chromosome.is_valid());
408        for gene in chromosome.iter() {
409            assert!(gene.is_valid());
410            assert!(gene.allele >= -1.0 && gene.allele <= 1.0);
411        }
412    }
413
414    #[test]
415    fn test_chromosome_from_vec() {
416        let chromosome = FloatChromosome::from(vec![0.0, 1.0, 2.0]);
417
418        assert_eq!(chromosome.len(), 3);
419        assert!(chromosome.is_valid());
420        for (gene, allele) in chromosome.iter().zip(vec![0.0, 1.0, 2.0]) {
421            assert!(gene.is_valid());
422            assert_eq!(gene.allele, allele);
423        }
424    }
425
426    #[test]
427    fn test_chromosome_from_range_with_bounds() {
428        let chromosome = FloatChromosome::from((3, 0.0..10.0, -10.0..10.0));
429
430        assert_eq!(chromosome.len(), 3);
431        assert!(chromosome.is_valid());
432        for gene in chromosome.iter() {
433            assert!(gene.is_valid());
434            assert!(gene.allele >= 0.0 && gene.allele <= 10.0);
435            assert!(gene.bounds.start >= -10.0 && gene.bounds.end <= 10.0);
436        }
437    }
438
439    #[test]
440    fn test_gene_arithmetic() {
441        let gene_one = FloatGene::from(5_f32);
442        let gene_two = FloatGene::from(10_f32);
443        let zero_gene = FloatGene::from(0_f32);
444
445        let add = gene_one.clone() + gene_two.clone();
446        let sub = gene_one.clone() - gene_two.clone();
447        let mul = gene_one.clone() * gene_two.clone();
448        let div = gene_one.clone() / gene_two.clone();
449        let mean = gene_one.clone().mean(&gene_two.clone());
450        let div_zero = gene_one.clone() / zero_gene.clone();
451
452        assert_eq!(add.allele, 15_f32);
453        assert_eq!(sub.allele, -5_f32);
454        assert_eq!(mul.allele, 50_f32);
455        assert_eq!(div.allele, 0.5_f32);
456        assert_eq!(mean.allele, 7.5_f32);
457        assert_eq!(div_zero.allele, 5_f32);
458    }
459
460    #[test]
461    #[cfg(feature = "serde")]
462    fn test_float_gene_serialization() {
463        let gene = FloatGene::from(0.5_f32..1.5_f32);
464
465        assert!(gene.is_valid());
466
467        let serialized = serde_json::to_string(&gene).expect("Failed to serialize FloatGene");
468        let deserialized: FloatGene =
469            serde_json::from_str(&serialized).expect("Failed to deserialize FloatGene");
470
471        let chromosome = FloatChromosome::from((10, 0.0..1.0, -1.0..1.0));
472        let serialized_chromosome =
473            serde_json::to_string(&chromosome).expect("Failed to serialize FloatChromosome");
474        let deserialized_chromosome: FloatChromosome = serde_json::from_str(&serialized_chromosome)
475            .expect("Failed to deserialize FloatChromosome");
476
477        assert_eq!(gene, deserialized);
478        assert_eq!(chromosome, deserialized_chromosome);
479    }
480}