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