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}