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}