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    shapes: Option<Vec<(usize, usize)>>,
20    _marker: std::marker::PhantomData<T>,
21}
22
23impl<T> FloatCodec<T> {
24    /// Set the bounds of the `FloatGenes` in the [Genotype]. The default bounds
25    /// are equal to the min and max values.
26    pub fn with_bounds(mut self, range: Range<f32>) -> Self {
27        self.bounds = range;
28        self
29    }
30
31    /// Every impl of `Codec` uses the same encode function for the `FloatCodec`, just with a few
32    /// different parameters (e.g. `num_chromosomes` and `num_genes`). So, we can just use
33    /// the same function for all of them.
34    #[inline]
35    fn common_encode(&self) -> Genotype<FloatChromosome> {
36        if let Some(shapes) = &self.shapes {
37            Genotype::from(
38                shapes
39                    .iter()
40                    .map(|(rows, cols)| {
41                        FloatChromosome::from((
42                            rows * cols,
43                            self.value_range.clone(),
44                            self.bounds.clone(),
45                        ))
46                    })
47                    .collect::<Vec<FloatChromosome>>(),
48            )
49        } else {
50            Genotype::from(
51                (0..self.num_chromosomes)
52                    .map(|_| {
53                        FloatChromosome::from((
54                            self.num_genes,
55                            self.value_range.clone(),
56                            self.bounds.clone(),
57                        ))
58                    })
59                    .collect::<Vec<FloatChromosome>>(),
60            )
61        }
62    }
63}
64
65impl FloatCodec<Vec<Vec<Vec<f32>>>> {
66    pub fn tensor(shapes: Vec<(usize, usize)>, range: Range<f32>) -> Self {
67        FloatCodec {
68            num_chromosomes: shapes.len(),
69            num_genes: 0,
70            value_range: range.clone(),
71            bounds: range,
72            shapes: Some(shapes),
73            _marker: std::marker::PhantomData,
74        }
75    }
76}
77
78impl FloatCodec<Vec<Vec<f32>>> {
79    /// Create a new `FloatCodec` with the given number of chromosomes, genes, min, and max values.
80    /// The f_32 values for each `FloatGene` will be randomly generated between the min and max values.
81    pub fn matrix(rows: usize, cols: usize, range: Range<f32>) -> Self {
82        FloatCodec {
83            num_chromosomes: rows,
84            num_genes: cols,
85            value_range: range.clone(),
86            bounds: range,
87            shapes: None,
88            _marker: std::marker::PhantomData,
89        }
90    }
91}
92
93impl FloatCodec<Vec<f32>> {
94    /// Create a new `FloatCodec` with the given number of chromosomes, genes, min, and max values.
95    /// The f_32 values for each `FloatGene` will be randomly generated between the min and max values.
96    pub fn vector(count: usize, range: Range<f32>) -> Self {
97        FloatCodec {
98            num_chromosomes: 1,
99            num_genes: count,
100            value_range: range.clone(),
101            bounds: range,
102            shapes: None,
103            _marker: std::marker::PhantomData,
104        }
105    }
106}
107
108impl FloatCodec<f32> {
109    /// Create a new `FloatCodec` with the given number of chromosomes, genes, min, and max values.
110    /// The f_32 values for each `FloatGene` will be randomly generated between the min and max values.
111    pub fn scalar(range: Range<f32>) -> Self {
112        FloatCodec {
113            num_chromosomes: 1,
114            num_genes: 1,
115            value_range: range.clone(),
116            bounds: range,
117            shapes: None,
118            _marker: std::marker::PhantomData,
119        }
120    }
121}
122
123/// Implement the [Codec] for a `FloatCodec` with a `Vec<Vec<Vec<f32>>>` type.
124/// Unlike the other impls, this will decode to a 3D tensor of `f32` values.
125///
126/// # Example
127/// ``` rust
128/// use radiate_core::*;
129///
130/// // Create a new FloatCodec with 2 layers:
131/// // - First layer: 2 rows and 3 columns
132/// // - Second layer: 3 rows and 4 columns
133/// let codec = FloatCodec::tensor(vec![(2, 3), (3, 4)], 0.0..1.0);
134/// let genotype: Genotype<FloatChromosome> = codec.encode();
135/// let decoded: Vec<Vec<Vec<f32>>> = codec.decode(&genotype);
136///
137/// assert_eq!(decoded.len(), 2);
138/// assert_eq!(decoded[0].len(), 2);
139/// assert_eq!(decoded[0][0].len(), 3);
140/// assert_eq!(decoded[1].len(), 3);
141/// assert_eq!(decoded[1][0].len(), 4);
142/// ```
143impl Codec<FloatChromosome, Vec<Vec<Vec<f32>>>> for FloatCodec<Vec<Vec<Vec<f32>>>> {
144    #[inline]
145    fn encode(&self) -> Genotype<FloatChromosome> {
146        self.common_encode()
147    }
148
149    #[inline]
150    fn decode(&self, genotype: &Genotype<FloatChromosome>) -> Vec<Vec<Vec<f32>>> {
151        if let Some(shapes) = &self.shapes {
152            let mut layers = Vec::new();
153            for (i, chromosome) in genotype.iter().enumerate() {
154                layers.push(
155                    chromosome
156                        .iter()
157                        .as_slice()
158                        .chunks(shapes[i].1)
159                        .map(|chunk| {
160                            chunk
161                                .iter()
162                                .map(|gene| *gene.allele())
163                                .collect::<Vec<f32>>()
164                        })
165                        .collect::<Vec<Vec<f32>>>(),
166                );
167            }
168
169            layers
170        } else {
171            vec![
172                genotype
173                    .iter()
174                    .map(|chromosome| {
175                        chromosome
176                            .iter()
177                            .map(|gene| *gene.allele())
178                            .collect::<Vec<f32>>()
179                    })
180                    .collect::<Vec<Vec<f32>>>(),
181            ]
182        }
183    }
184}
185
186/// Implement the `Codec` trait for a `FloatCodec` with a `Vec<Vec<f32>>` type.
187/// This will decode to a matrix of `f32` values.
188/// The `encode` function creates a [Genotype] with `num_chromosomes` chromosomes
189/// and `num_genes` genes per chromosome.
190///
191/// * Example:
192/// ``` rust
193/// use radiate_core::*;
194///
195/// // Create a new FloatCodec with 3 chromosomes and 4 genes
196/// // per chromosome - a 3x4 matrix of f32 values.
197/// let codec = FloatCodec::matrix(3, 4, 0.0..1.0);
198/// let genotype: Genotype<FloatChromosome> = codec.encode();
199/// let decoded: Vec<Vec<f32>> = codec.decode(&genotype);
200///
201/// assert_eq!(decoded.len(), 3);
202/// assert_eq!(decoded[0].len(), 4);
203/// ```
204impl Codec<FloatChromosome, Vec<Vec<f32>>> for FloatCodec<Vec<Vec<f32>>> {
205    #[inline]
206    fn encode(&self) -> Genotype<FloatChromosome> {
207        self.common_encode()
208    }
209
210    #[inline]
211    fn decode(&self, genotype: &Genotype<FloatChromosome>) -> Vec<Vec<f32>> {
212        genotype
213            .iter()
214            .map(|chromosome| {
215                chromosome
216                    .iter()
217                    .map(|gene| *gene.allele())
218                    .collect::<Vec<f32>>()
219            })
220            .collect::<Vec<Vec<f32>>>()
221    }
222}
223
224/// Implement the `Codec` trait for a `FloatCodec` with a `Vec<f32>` type.
225/// This will decode to a vector of `f32` values.
226/// The `encode` function creates a [Genotype] with a single chromosomes
227/// and `num_genes` genes per chromosome.
228///
229/// # Example
230/// ``` rust
231/// use radiate_core::*;
232///
233/// // Create a new FloatCodec with 3 genes
234/// // per chromosome - a vector with 3 f32 values.
235/// let codec = FloatCodec::vector(3, 0.0..1.0);
236/// let genotype: Genotype<FloatChromosome> = codec.encode();
237/// let decoded: Vec<f32> = codec.decode(&genotype);
238///
239/// assert_eq!(decoded.len(), 3);
240/// ```
241impl Codec<FloatChromosome, Vec<f32>> for FloatCodec<Vec<f32>> {
242    #[inline]
243    fn encode(&self) -> Genotype<FloatChromosome> {
244        self.common_encode()
245    }
246
247    #[inline]
248    fn decode(&self, genotype: &Genotype<FloatChromosome>) -> Vec<f32> {
249        genotype
250            .iter()
251            .flat_map(|chromosome| {
252                chromosome
253                    .iter()
254                    .map(|gene| *gene.allele())
255                    .collect::<Vec<f32>>()
256            })
257            .collect::<Vec<f32>>()
258    }
259}
260
261/// Implement the `Codec` trait for a `FloatCodec` with a `f32` type.
262/// This will decode to a single `f32` value.
263/// The `encode` function creates a [Genotype] with a single chromosomes
264/// and a single gene per chromosome.
265///
266/// # Example
267/// ``` rust
268/// use radiate_core::*;
269///
270/// // Create a new FloatCodec with a single gene
271/// // per chromosome - a single f32 value.
272/// let codec = FloatCodec::scalar(0.0..1.0);
273/// let genotype: Genotype<FloatChromosome> = codec.encode();
274/// let decoded: f32 = codec.decode(&genotype);
275/// ```
276impl Codec<FloatChromosome, f32> for FloatCodec<f32> {
277    #[inline]
278    fn encode(&self) -> Genotype<FloatChromosome> {
279        self.common_encode()
280    }
281
282    #[inline]
283    fn decode(&self, genotype: &Genotype<FloatChromosome>) -> f32 {
284        genotype
285            .iter()
286            .flat_map(|chromosome| {
287                chromosome
288                    .iter()
289                    .map(|gene| *gene.allele())
290                    .collect::<Vec<f32>>()
291            })
292            .next()
293            .unwrap_or_default()
294    }
295}
296
297/// Implement the [Codec] trait for a Vec for [FloatChromosome].
298/// This is effectively the same as creating a [FloatCodec] matrix
299///
300/// # Example
301/// ``` rust
302/// use radiate_core::*;
303///
304/// let codec = vec![
305///     FloatChromosome::from((3, 0.0..1.0)),
306///     FloatChromosome::from((4, 0.0..1.0)),
307/// ];
308///
309/// let genotype: Genotype<FloatChromosome> = codec.encode();
310/// let decoded: Vec<Vec<f32>> = codec.decode(&genotype);
311///
312/// assert_eq!(decoded.len(), 2);
313/// assert_eq!(decoded[0].len(), 3);
314/// assert_eq!(decoded[1].len(), 4);
315/// ```
316impl Codec<FloatChromosome, Vec<Vec<f32>>> for Vec<FloatChromosome> {
317    #[inline]
318    fn encode(&self) -> Genotype<FloatChromosome> {
319        Genotype::from(
320            self.iter()
321                .map(|chromosome| {
322                    chromosome
323                        .iter()
324                        .map(|gene| gene.new_instance())
325                        .collect::<FloatChromosome>()
326                })
327                .collect::<Vec<FloatChromosome>>(),
328        )
329    }
330
331    #[inline]
332    fn decode(&self, genotype: &Genotype<FloatChromosome>) -> Vec<Vec<f32>> {
333        genotype
334            .iter()
335            .map(|chromosome| {
336                chromosome
337                    .iter()
338                    .map(|gene| *gene.allele())
339                    .collect::<Vec<f32>>()
340            })
341            .collect::<Vec<Vec<f32>>>()
342    }
343}
344
345/// Implement the [Codec] trait for a single [FloatChromosome].
346/// This is effectively the same as creating a [FloatCodec] vector
347///
348/// # Example
349/// ``` rust
350/// use radiate_core::*;
351///
352/// let codec = FloatChromosome::from((3, 0.0..1.0));
353/// let genotype: Genotype<FloatChromosome> = codec.encode();
354/// let decoded: Vec<f32> = codec.decode(&genotype);
355///
356/// assert_eq!(decoded.len(), 3);
357/// ```
358impl Codec<FloatChromosome, Vec<f32>> for FloatChromosome {
359    #[inline]
360    fn encode(&self) -> Genotype<FloatChromosome> {
361        Genotype::from(
362            self.iter()
363                .map(|gene| gene.new_instance())
364                .collect::<FloatChromosome>(),
365        )
366    }
367
368    #[inline]
369    fn decode(&self, genotype: &Genotype<FloatChromosome>) -> Vec<f32> {
370        genotype
371            .iter()
372            .flat_map(|chromosome| {
373                chromosome
374                    .iter()
375                    .map(|gene| *gene.allele())
376                    .collect::<Vec<f32>>()
377            })
378            .collect::<Vec<f32>>()
379    }
380}