radiate_core/genome/chromosomes/
gene.rs

1use std::ops::{Add, Div, Mul, Sub};
2
3use crate::chromosomes::NumericAllele;
4
5/// A [`Valid`] type is a type that can be checked for validity. This is used for checking if a gene
6/// or a chromosome is valid. For example, a gene that represents a number between 0 and 1 can be checked
7/// for validity by ensuring that the allele is between 0 and 1.
8///
9/// The `GeneticEngine` will check the validity of the [Chromosome](super::chromosome::Chromosome) and `Phenotype` and remove any
10/// invalid individuals from the population, replacing them with new individuals at the given generation.
11pub trait Valid {
12    fn is_valid(&self) -> bool {
13        true
14    }
15}
16
17/// A [`Gene`] is a single unit of information in a [Chromosome](super::chromosome::Chromosome).
18/// This is the most basic building block of this entire library.
19///
20/// Any type that implements this trait can be used as a gene in a chromosome, as such
21/// it can be used in any genetic algorithm that uses this library.
22///
23/// # Example
24/// ```
25/// use radiate_core::*;
26///
27/// // A simple gene that represents a point.
28/// #[derive(Clone, Debug, PartialEq)]
29/// struct PointGene {
30///    allele: (f32, f32),
31/// }
32///
33/// // Implement the Gene trait for the PointGene.
34/// impl Gene for PointGene {
35///     type Allele = (f32, f32);
36///
37///     fn allele(&self) -> &Self::Allele {
38///         &self.allele
39///     }
40///
41///     fn allele_mut(&mut self) -> &mut Self::Allele {
42///         &mut self.allele
43///     }
44///
45///     fn new_instance(&self) -> Self {
46///        PointGene { allele: (0.0, 0.0) }
47///     }
48///
49///     fn with_allele(&self, allele: &Self::Allele) -> Self {
50///       PointGene { allele: *allele }
51///     }
52/// }
53///
54/// // You must also implement the [`Valid`] trait for the gene.
55/// // The default implementation of the [`Valid`] trait is to return true.
56/// impl Valid for PointGene {
57///    fn is_valid(&self) -> bool {
58///      let (x, y) = self.allele;
59///     // Check if the x and y values are between 0 and 1.
60///     x >= 0.0 && x <= 1.0 && y >= 0.0 && y <= 1.0
61///   }
62/// }
63/// ```
64pub trait Gene: Clone + Valid {
65    type Allele;
66
67    /// Get the `allele` of the [Gene]. This is the value that the [Gene] represents or "expresses".
68    fn allele(&self) -> &Self::Allele;
69
70    /// Get a mutable reference to the `allele` of the [Gene].
71    fn allele_mut(&mut self) -> &mut Self::Allele;
72
73    /// Create a new instance of the [Gene].
74    fn new_instance(&self) -> Self;
75
76    /// Create a new [Gene] with the given `allele`.
77    fn with_allele(&self, allele: &Self::Allele) -> Self;
78}
79
80pub trait BoundedGene: Gene {
81    fn min(&self) -> &Self::Allele;
82    fn max(&self) -> &Self::Allele;
83    fn bounds(&self) -> (&Self::Allele, &Self::Allele);
84}
85
86/// A [Gene] that represents a number. This gene can be used to represent any type of number,
87/// including integers, floats, etc. Essentially, any gene that can `Add`, `Sub`, `Mul`, and `Div`
88/// can be used as a [ArithmeticGene].
89pub trait ArithmeticGene:
90    Gene + Add<Output = Self> + Sub<Output = Self> + Mul<Output = Self> + Div<Output = Self>
91{
92    fn mean(&self, other: &Self) -> Self;
93}
94
95pub trait NumericGene: Gene
96where
97    Self::Allele: NumericAllele,
98{
99    fn allele_as_f32(&self) -> Option<f32> {
100        self.allele().cast_as_f32()
101    }
102
103    fn allele_as_i32(&self) -> Option<i32> {
104        self.allele().cast_as_i32()
105    }
106}
107
108impl<G, T> NumericGene for G
109where
110    G: Gene<Allele = T>,
111    T: NumericAllele,
112{
113}