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