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