Skip to main content

radiate_core/codecs/
float.rs

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