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