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