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 fn common_encode(&self) -> Genotype<FloatChromosome> {
34 Genotype::from(
35 (0..self.num_chromosomes)
36 .map(|_| {
37 FloatChromosome::from((
38 self.num_genes,
39 self.value_range.clone(),
40 self.bounds.clone(),
41 ))
42 })
43 .collect::<Vec<FloatChromosome>>(),
44 )
45 }
46}
47
48impl FloatCodec<Vec<Vec<f32>>> {
49 /// Create a new `FloatCodec` with the given number of chromosomes, genes, min, and max values.
50 /// The f_32 values for each `FloatGene` will be randomly generated between the min and max values.
51 pub fn matrix(rows: usize, cols: usize, range: Range<f32>) -> Self {
52 FloatCodec {
53 num_chromosomes: rows,
54 num_genes: cols,
55 value_range: range.clone(),
56 bounds: range,
57 _marker: std::marker::PhantomData,
58 }
59 }
60}
61
62impl FloatCodec<Vec<f32>> {
63 /// Create a new `FloatCodec` with the given number of chromosomes, genes, min, and max values.
64 /// The f_32 values for each `FloatGene` will be randomly generated between the min and max values.
65 pub fn vector(count: usize, range: Range<f32>) -> Self {
66 FloatCodec {
67 num_chromosomes: 1,
68 num_genes: count,
69 value_range: range.clone(),
70 bounds: range,
71 _marker: std::marker::PhantomData,
72 }
73 }
74}
75
76impl FloatCodec<f32> {
77 /// Create a new `FloatCodec` with the given number of chromosomes, genes, min, and max values.
78 /// The f_32 values for each `FloatGene` will be randomly generated between the min and max values.
79 pub fn scalar(range: Range<f32>) -> Self {
80 FloatCodec {
81 num_chromosomes: 1,
82 num_genes: 1,
83 value_range: range.clone(),
84 bounds: range,
85 _marker: std::marker::PhantomData,
86 }
87 }
88}
89
90/// Implement the `Codec` trait for a `FloatCodec` with a `Vec<Vec<f32>>` type.
91/// This will decode to a matrix of `f32` values.
92/// The `encode` function creates a [Genotype] with `num_chromosomes` chromosomes
93/// and `num_genes` genes per chromosome.
94///
95/// * Example:
96/// ``` rust
97/// use radiate_core::*;
98///
99/// // Create a new FloatCodec with 3 chromosomes and 4 genes
100/// // per chromosome - a 3x4 matrix of f32 values.
101/// let codec = FloatCodec::matrix(3, 4, 0.0..1.0);
102/// let genotype: Genotype<FloatChromosome> = codec.encode();
103/// let decoded: Vec<Vec<f32>> = codec.decode(&genotype);
104///
105/// assert_eq!(decoded.len(), 3);
106/// assert_eq!(decoded[0].len(), 4);
107/// ```
108impl Codec<FloatChromosome, Vec<Vec<f32>>> for FloatCodec<Vec<Vec<f32>>> {
109 fn encode(&self) -> Genotype<FloatChromosome> {
110 self.common_encode()
111 }
112
113 fn decode(&self, genotype: &Genotype<FloatChromosome>) -> Vec<Vec<f32>> {
114 genotype
115 .iter()
116 .map(|chromosome| {
117 chromosome
118 .iter()
119 .map(|gene| *gene.allele())
120 .collect::<Vec<f32>>()
121 })
122 .collect::<Vec<Vec<f32>>>()
123 }
124}
125
126/// Implement the `Codec` trait for a `FloatCodec` with a `Vec<f32>` type.
127/// This will decode to a vector of `f32` values.
128/// The `encode` function creates a [Genotype] with a single chromosomes
129/// and `num_genes` genes per chromosome.
130///
131/// # Example
132/// ``` rust
133/// use radiate_core::*;
134///
135/// // Create a new FloatCodec with 3 genes
136/// // per chromosome - a vector with 3 f32 values.
137/// let codec = FloatCodec::vector(3, 0.0..1.0);
138/// let genotype: Genotype<FloatChromosome> = codec.encode();
139/// let decoded: Vec<f32> = codec.decode(&genotype);
140///
141/// assert_eq!(decoded.len(), 3);
142/// ```
143impl Codec<FloatChromosome, Vec<f32>> for FloatCodec<Vec<f32>> {
144 fn encode(&self) -> Genotype<FloatChromosome> {
145 self.common_encode()
146 }
147
148 fn decode(&self, genotype: &Genotype<FloatChromosome>) -> Vec<f32> {
149 genotype
150 .iter()
151 .flat_map(|chromosome| {
152 chromosome
153 .iter()
154 .map(|gene| *gene.allele())
155 .collect::<Vec<f32>>()
156 })
157 .collect::<Vec<f32>>()
158 }
159}
160
161/// Implement the `Codec` trait for a `FloatCodec` with a `f32` type.
162/// This will decode to a single `f32` value.
163/// The `encode` function creates a [Genotype] with a single chromosomes
164/// and a single gene per chromosome.
165///
166/// # Example
167/// ``` rust
168/// use radiate_core::*;
169///
170/// // Create a new FloatCodec with a single gene
171/// // per chromosome - a single f32 value.
172/// let codec = FloatCodec::scalar(0.0..1.0);
173/// let genotype: Genotype<FloatChromosome> = codec.encode();
174/// let decoded: f32 = codec.decode(&genotype);
175/// ```
176impl Codec<FloatChromosome, f32> for FloatCodec<f32> {
177 fn encode(&self) -> Genotype<FloatChromosome> {
178 self.common_encode()
179 }
180
181 fn decode(&self, genotype: &Genotype<FloatChromosome>) -> f32 {
182 genotype
183 .iter()
184 .flat_map(|chromosome| {
185 chromosome
186 .iter()
187 .map(|gene| *gene.allele())
188 .collect::<Vec<f32>>()
189 })
190 .next()
191 .unwrap_or_default()
192 }
193}
194
195/// Implement the [Codec] trait for a Vec for [FloatChromosome].
196/// This is effectively the same as creating a [FloatCodec] matrix
197///
198/// # Example
199/// ``` rust
200/// use radiate_core::*;
201///
202/// let codec = vec![
203/// FloatChromosome::from((3, 0.0..1.0)),
204/// FloatChromosome::from((4, 0.0..1.0)),
205/// ];
206///
207/// let genotype: Genotype<FloatChromosome> = codec.encode();
208/// let decoded: Vec<Vec<f32>> = codec.decode(&genotype);
209///
210/// assert_eq!(decoded.len(), 2);
211/// assert_eq!(decoded[0].len(), 3);
212/// assert_eq!(decoded[1].len(), 4);
213/// ```
214impl Codec<FloatChromosome, Vec<Vec<f32>>> for Vec<FloatChromosome> {
215 fn encode(&self) -> Genotype<FloatChromosome> {
216 Genotype::from(
217 self.iter()
218 .map(|chromosome| {
219 chromosome
220 .iter()
221 .map(|gene| gene.new_instance())
222 .collect::<FloatChromosome>()
223 })
224 .collect::<Vec<FloatChromosome>>(),
225 )
226 }
227
228 fn decode(&self, genotype: &Genotype<FloatChromosome>) -> Vec<Vec<f32>> {
229 genotype
230 .iter()
231 .map(|chromosome| {
232 chromosome
233 .iter()
234 .map(|gene| *gene.allele())
235 .collect::<Vec<f32>>()
236 })
237 .collect::<Vec<Vec<f32>>>()
238 }
239}
240
241/// Implement the [Codec] trait for a single [FloatChromosome].
242/// This is effectively the same as creating a [FloatCodec] vector
243///
244//// # Example
245/// ``` rust
246/// use radiate_core::*;
247///
248/// let codec = FloatChromosome::from((3, 0.0..1.0));
249/// let genotype: Genotype<FloatChromosome> = codec.encode();
250/// let decoded: Vec<f32> = codec.decode(&genotype);
251///
252/// assert_eq!(decoded.len(), 3);
253/// ```
254impl Codec<FloatChromosome, Vec<f32>> for FloatChromosome {
255 fn encode(&self) -> Genotype<FloatChromosome> {
256 Genotype::from(
257 self.iter()
258 .map(|gene| gene.new_instance())
259 .collect::<FloatChromosome>(),
260 )
261 }
262
263 fn decode(&self, genotype: &Genotype<FloatChromosome>) -> Vec<f32> {
264 genotype
265 .iter()
266 .flat_map(|chromosome| {
267 chromosome
268 .iter()
269 .map(|gene| *gene.allele())
270 .collect::<Vec<f32>>()
271 })
272 .collect::<Vec<f32>>()
273 }
274}