radiate_core/codecs/
float.rs

1use super::Codec;
2use crate::genome::Gene;
3use crate::genome::genotype::Genotype;
4use crate::{Chromosome, FloatChromosome};
5use std::ops::Range;
6
7/// A [Codec] for a [Genotype] of `FloatGenes`. The `encode` function creates a [Genotype] with `num_chromosomes` chromosomes
8/// and `num_genes` genes per chromosome. The `decode` function creates a `Vec<Vec<f32>>` from the [Genotype] where the inner `Vec`
9/// contains the alleles of the `FloatGenes` in the chromosome - the `f32` values.
10///
11/// The lower and upper bounds of the `FloatGenes` can be set with the `with_bounds` function.
12/// The default bounds are equal to `min` and `max` values.
13#[derive(Clone)]
14pub struct FloatCodec<T = f32> {
15    num_chromosomes: usize,
16    num_genes: usize,
17    value_range: Range<f32>,
18    bounds: Range<f32>,
19    _marker: std::marker::PhantomData<T>,
20}
21
22impl<T> FloatCodec<T> {
23    /// Set the bounds of the `FloatGenes` in the [Genotype]. The default bounds
24    /// are equal to the min and max values.
25    pub fn with_bounds(mut self, range: Range<f32>) -> Self {
26        self.bounds = range;
27        self
28    }
29
30    /// Every impl of `Codec` uses the same encode function for the `FloatCodec`, just with a few
31    /// different parameters (e.g. `num_chromosomes` and `num_genes`). So, we can just use
32    /// the same function for all of them.
33    fn common_encode(&self) -> Genotype<FloatChromosome> {
34        Genotype::from(
35            (0..self.num_chromosomes)
36                .map(|_| {
37                    FloatChromosome::from((
38                        self.num_genes,
39                        self.value_range.clone(),
40                        self.bounds.clone(),
41                    ))
42                })
43                .collect::<Vec<FloatChromosome>>(),
44        )
45    }
46}
47
48impl FloatCodec<Vec<Vec<f32>>> {
49    /// Create a new `FloatCodec` with the given number of chromosomes, genes, min, and max values.
50    /// The f_32 values for each `FloatGene` will be randomly generated between the min and max values.
51    pub fn matrix(rows: usize, cols: usize, range: Range<f32>) -> Self {
52        FloatCodec {
53            num_chromosomes: rows,
54            num_genes: cols,
55            value_range: range.clone(),
56            bounds: range,
57            _marker: std::marker::PhantomData,
58        }
59    }
60}
61
62impl FloatCodec<Vec<f32>> {
63    /// Create a new `FloatCodec` with the given number of chromosomes, genes, min, and max values.
64    /// The f_32 values for each `FloatGene` will be randomly generated between the min and max values.
65    pub fn vector(count: usize, range: Range<f32>) -> Self {
66        FloatCodec {
67            num_chromosomes: 1,
68            num_genes: count,
69            value_range: range.clone(),
70            bounds: range,
71            _marker: std::marker::PhantomData,
72        }
73    }
74}
75
76impl FloatCodec<f32> {
77    /// Create a new `FloatCodec` with the given number of chromosomes, genes, min, and max values.
78    /// The f_32 values for each `FloatGene` will be randomly generated between the min and max values.
79    pub fn scalar(range: Range<f32>) -> Self {
80        FloatCodec {
81            num_chromosomes: 1,
82            num_genes: 1,
83            value_range: range.clone(),
84            bounds: range,
85            _marker: std::marker::PhantomData,
86        }
87    }
88}
89
90/// Implement the `Codec` trait for a `FloatCodec` with a `Vec<Vec<f32>>` type.
91/// This will decode to a matrix of `f32` values.
92/// The `encode` function creates a [Genotype] with `num_chromosomes` chromosomes
93/// and `num_genes` genes per chromosome.
94///
95/// * Example:
96/// ``` rust
97/// use radiate_core::*;
98///
99/// // Create a new FloatCodec with 3 chromosomes and 4 genes
100/// // per chromosome - a 3x4 matrix of f32 values.
101/// let codec = FloatCodec::matrix(3, 4, 0.0..1.0);
102/// let genotype: Genotype<FloatChromosome> = codec.encode();
103/// let decoded: Vec<Vec<f32>> = codec.decode(&genotype);
104///
105/// assert_eq!(decoded.len(), 3);
106/// assert_eq!(decoded[0].len(), 4);
107/// ```
108impl Codec<FloatChromosome, Vec<Vec<f32>>> for FloatCodec<Vec<Vec<f32>>> {
109    fn encode(&self) -> Genotype<FloatChromosome> {
110        self.common_encode()
111    }
112
113    fn decode(&self, genotype: &Genotype<FloatChromosome>) -> Vec<Vec<f32>> {
114        genotype
115            .iter()
116            .map(|chromosome| {
117                chromosome
118                    .iter()
119                    .map(|gene| *gene.allele())
120                    .collect::<Vec<f32>>()
121            })
122            .collect::<Vec<Vec<f32>>>()
123    }
124}
125
126/// Implement the `Codec` trait for a `FloatCodec` with a `Vec<f32>` type.
127/// This will decode to a vector of `f32` values.
128/// The `encode` function creates a [Genotype] with a single chromosomes
129/// and `num_genes` genes per chromosome.
130///
131/// # Example
132/// ``` rust
133/// use radiate_core::*;
134///
135/// // Create a new FloatCodec with 3 genes
136/// // per chromosome - a vector with 3 f32 values.
137/// let codec = FloatCodec::vector(3, 0.0..1.0);
138/// let genotype: Genotype<FloatChromosome> = codec.encode();
139/// let decoded: Vec<f32> = codec.decode(&genotype);
140///
141/// assert_eq!(decoded.len(), 3);
142/// ```
143impl Codec<FloatChromosome, Vec<f32>> for FloatCodec<Vec<f32>> {
144    fn encode(&self) -> Genotype<FloatChromosome> {
145        self.common_encode()
146    }
147
148    fn decode(&self, genotype: &Genotype<FloatChromosome>) -> Vec<f32> {
149        genotype
150            .iter()
151            .flat_map(|chromosome| {
152                chromosome
153                    .iter()
154                    .map(|gene| *gene.allele())
155                    .collect::<Vec<f32>>()
156            })
157            .collect::<Vec<f32>>()
158    }
159}
160
161/// Implement the `Codec` trait for a `FloatCodec` with a `f32` type.
162/// This will decode to a single `f32` value.
163/// The `encode` function creates a [Genotype] with a single chromosomes
164/// and a single gene per chromosome.
165///
166/// # Example
167/// ``` rust
168/// use radiate_core::*;
169///
170/// // Create a new FloatCodec with a single gene
171/// // per chromosome - a single f32 value.
172/// let codec = FloatCodec::scalar(0.0..1.0);
173/// let genotype: Genotype<FloatChromosome> = codec.encode();
174/// let decoded: f32 = codec.decode(&genotype);
175/// ```
176impl Codec<FloatChromosome, f32> for FloatCodec<f32> {
177    fn encode(&self) -> Genotype<FloatChromosome> {
178        self.common_encode()
179    }
180
181    fn decode(&self, genotype: &Genotype<FloatChromosome>) -> f32 {
182        genotype
183            .iter()
184            .flat_map(|chromosome| {
185                chromosome
186                    .iter()
187                    .map(|gene| *gene.allele())
188                    .collect::<Vec<f32>>()
189            })
190            .next()
191            .unwrap_or_default()
192    }
193}
194
195/// Implement the [Codec] trait for a Vec for [FloatChromosome].
196/// This is effectively the same as creating a [FloatCodec] matrix
197///
198/// # Example
199/// ``` rust
200/// use radiate_core::*;
201///
202/// let codec = vec![
203///     FloatChromosome::from((3, 0.0..1.0)),
204///     FloatChromosome::from((4, 0.0..1.0)),
205/// ];
206///
207/// let genotype: Genotype<FloatChromosome> = codec.encode();
208/// let decoded: Vec<Vec<f32>> = codec.decode(&genotype);
209///
210/// assert_eq!(decoded.len(), 2);
211/// assert_eq!(decoded[0].len(), 3);
212/// assert_eq!(decoded[1].len(), 4);
213/// ```
214impl Codec<FloatChromosome, Vec<Vec<f32>>> for Vec<FloatChromosome> {
215    fn encode(&self) -> Genotype<FloatChromosome> {
216        Genotype::from(
217            self.iter()
218                .map(|chromosome| {
219                    chromosome
220                        .iter()
221                        .map(|gene| gene.new_instance())
222                        .collect::<FloatChromosome>()
223                })
224                .collect::<Vec<FloatChromosome>>(),
225        )
226    }
227
228    fn decode(&self, genotype: &Genotype<FloatChromosome>) -> Vec<Vec<f32>> {
229        genotype
230            .iter()
231            .map(|chromosome| {
232                chromosome
233                    .iter()
234                    .map(|gene| *gene.allele())
235                    .collect::<Vec<f32>>()
236            })
237            .collect::<Vec<Vec<f32>>>()
238    }
239}
240
241/// Implement the [Codec] trait for a single [FloatChromosome].
242/// This is effectively the same as creating a [FloatCodec] vector
243///
244//// # Example
245/// ``` rust
246/// use radiate_core::*;
247///
248/// let codec = FloatChromosome::from((3, 0.0..1.0));
249/// let genotype: Genotype<FloatChromosome> = codec.encode();
250/// let decoded: Vec<f32> = codec.decode(&genotype);
251///
252/// assert_eq!(decoded.len(), 3);
253/// ```
254impl Codec<FloatChromosome, Vec<f32>> for FloatChromosome {
255    fn encode(&self) -> Genotype<FloatChromosome> {
256        Genotype::from(
257            self.iter()
258                .map(|gene| gene.new_instance())
259                .collect::<FloatChromosome>(),
260        )
261    }
262
263    fn decode(&self, genotype: &Genotype<FloatChromosome>) -> Vec<f32> {
264        genotype
265            .iter()
266            .flat_map(|chromosome| {
267                chromosome
268                    .iter()
269                    .map(|gene| *gene.allele())
270                    .collect::<Vec<f32>>()
271            })
272            .collect::<Vec<f32>>()
273    }
274}