Skip to main content

radiate_core/codecs/
int.rs

1use radiate_utils::Integer;
2
3use super::Codec;
4use crate::genome::Gene;
5use crate::genome::genotype::Genotype;
6use crate::{Chromosome, IntChromosome};
7use std::ops::Range;
8
9/// A [Codec] for a [Genotype] of `IntGenes`. The `encode` function creates a [Genotype] with `num_chromosomes` chromosomes
10/// and `num_genes` genes per chromosome. The `decode` function creates a `Vec<Vec<T>>` from the [Genotype] where the inner `Vec`
11/// contains the alleles of the `IntGenes` in the chromosome. `T` must implement the `Integer` trait, meaning it must be one of
12/// `i8`, `i16`, `i32`, `i64`, `i128`, `u8`, `u16`, `u32`, `u64`, or `u128`.
13///
14/// The lower and upper bounds of the `IntGenes` can be set with the `with_bounds` function.
15/// The default bounds are equal to `min` and `max`.
16#[derive(Clone)]
17pub struct IntCodec<T: Integer, D = T> {
18    num_chromosomes: usize,
19    num_genes: usize,
20    value_range: Range<T>,
21    bounds: Range<T>,
22    _marker: std::marker::PhantomData<D>,
23}
24
25impl<T: Integer, D> IntCodec<T, D> {
26    pub fn with_bounds(mut self, bounds: Range<T>) -> Self {
27        self.bounds = bounds;
28        self
29    }
30
31    /// The different variants of `IntCodec` are all the same, so this function is used to create
32    /// a new `Genotype` with the given number of chromosomes and genes. The only difference between
33    /// them is the type `D`, which is either a `Vec<Vec<T>>`, `Vec<T>`, or `T`.
34    fn encode_common(&self) -> Genotype<IntChromosome<T>> {
35        Genotype::from(
36            (0..self.num_chromosomes)
37                .map(|_| {
38                    IntChromosome::from((
39                        self.num_genes,
40                        self.value_range.clone(),
41                        self.bounds.clone(),
42                    ))
43                })
44                .collect::<Vec<IntChromosome<T>>>(),
45        )
46    }
47}
48
49impl<T: Integer> IntCodec<T, Vec<Vec<T>>> {
50    /// Create a new `IntCodec` with the given number of chromosomes, genes, min, and max values.
51    /// The f_32 values for each `IntGene` will be randomly generated between the min and max values.
52    pub fn matrix(rows: usize, cols: usize, range: Range<T>) -> Self {
53        IntCodec {
54            num_chromosomes: rows,
55            num_genes: cols,
56            value_range: range.clone(),
57            bounds: range,
58            _marker: std::marker::PhantomData,
59        }
60    }
61}
62
63impl<T: Integer> IntCodec<T, Vec<T>> {
64    /// Create a new `IntCodec` with the given number of chromosomes, genes, min, and max values.
65    /// The f_32 values for each `IntGene` will be randomly generated between the min and max values.
66    pub fn vector(count: usize, range: Range<T>) -> Self {
67        IntCodec {
68            num_chromosomes: 1,
69            num_genes: count,
70            value_range: range.clone(),
71            bounds: range,
72            _marker: std::marker::PhantomData,
73        }
74    }
75}
76
77impl<T: Integer> IntCodec<T, T> {
78    /// Create a new `IntCodec` with the given number of chromosomes, genes, min, and max values.
79    /// The f_32 values for each `IntGene` will be randomly generated between the min and max values.
80    pub fn scalar(range: Range<T>) -> Self {
81        IntCodec {
82            num_chromosomes: 1,
83            num_genes: 1,
84            value_range: range.clone(),
85            bounds: range,
86            _marker: std::marker::PhantomData,
87        }
88    }
89}
90
91/// Implement the [Codec] trait for a [Genotype] of `IntGenes`. This will produce a [Genotype] with the
92/// given number of chromosomes and genes. The `decode` function will create a `Vec<Vec<T>>` or a matrix.
93///
94/// # Example
95/// ``` rust
96/// use radiate_core::*;
97///
98/// // Create a new IntCodec with 10 chromosomes with 10 genes
99/// // per chromosome - a matrix of i32 values.
100/// let codec = IntCodec::matrix(10, 10, 0..100);
101/// let genotype: Genotype<IntChromosome<i32>> = codec.encode();
102/// let decoded: Vec<Vec<i32>> = codec.decode(&genotype);
103/// ```
104impl<T: Integer> Codec<IntChromosome<T>, Vec<Vec<T>>> for IntCodec<T, Vec<Vec<T>>> {
105    fn encode(&self) -> Genotype<IntChromosome<T>> {
106        self.encode_common()
107    }
108
109    fn decode(&self, genotype: &Genotype<IntChromosome<T>>) -> Vec<Vec<T>> {
110        genotype
111            .iter()
112            .map(|chromosome| {
113                chromosome
114                    .iter()
115                    .map(|gene| *gene.allele())
116                    .collect::<Vec<T>>()
117            })
118            .collect::<Vec<Vec<T>>>()
119    }
120}
121
122/// Implement the [Codec] trait for a [Genotype] of `IntGenes`. This will produce a [Genotype] with a single
123/// chromosome and `num_genes` genes. The `decode` function will create a `Vec<T>` or a vector.
124///
125/// # Example
126/// ``` rust
127/// use radiate_core::*;
128///
129/// // Create a new IntCodec with 10 genes
130/// // per chromosome - a  vector of i32 values.
131/// let codec = IntCodec::vector(10, 0..100);
132/// let genotype: Genotype<IntChromosome<i32>> = codec.encode();
133/// let decoded: Vec<i32> = codec.decode(&genotype);
134/// ```
135impl<T: Integer> Codec<IntChromosome<T>, Vec<T>> for IntCodec<T, Vec<T>> {
136    fn encode(&self) -> Genotype<IntChromosome<T>> {
137        self.encode_common()
138    }
139
140    fn decode(&self, genotype: &Genotype<IntChromosome<T>>) -> Vec<T> {
141        genotype
142            .iter()
143            .flat_map(|chromosome| {
144                chromosome
145                    .iter()
146                    .map(|gene| *gene.allele())
147                    .collect::<Vec<T>>()
148            })
149            .collect::<Vec<T>>()
150    }
151}
152
153/// Implement the [Codec] trait for a [Genotype] of `IntGenes`. This will produce a [Genotype] with a single
154/// chromosome and a single gene. The `decode` function will create a `T` or a single value.
155/// The `encode` function creates a [Genotype] with a single chromosomes
156/// and a single gene per chromosome.
157///
158/// # Example
159/// ``` rust
160/// use radiate_core::*;
161///
162/// // Create a new IntCodec with a single gene
163/// // per chromosome - a single i32 value.
164/// let codec = IntCodec::scalar(0..100);
165/// let genotype: Genotype<IntChromosome<i32>> = codec.encode();
166/// let decoded: i32 = codec.decode(&genotype);
167/// ```
168impl<T: Integer> Codec<IntChromosome<T>, T> for IntCodec<T, T> {
169    fn encode(&self) -> Genotype<IntChromosome<T>> {
170        self.encode_common()
171    }
172
173    fn decode(&self, genotype: &Genotype<IntChromosome<T>>) -> T {
174        genotype
175            .iter()
176            .flat_map(|chromosome| {
177                chromosome
178                    .iter()
179                    .map(|gene| *gene.allele())
180                    .collect::<Vec<T>>()
181            })
182            .next()
183            .unwrap_or_default()
184    }
185}
186
187impl<T: Integer> Codec<IntChromosome<T>, Vec<Vec<T>>> for Vec<IntChromosome<T>> {
188    fn encode(&self) -> Genotype<IntChromosome<T>> {
189        Genotype::from(
190            self.iter()
191                .map(|chromosome| {
192                    chromosome
193                        .iter()
194                        .map(|gene| gene.new_instance())
195                        .collect::<IntChromosome<T>>()
196                })
197                .collect::<Vec<IntChromosome<T>>>(),
198        )
199    }
200
201    fn decode(&self, genotype: &Genotype<IntChromosome<T>>) -> Vec<Vec<T>> {
202        genotype
203            .iter()
204            .map(|chromosome| {
205                chromosome
206                    .iter()
207                    .map(|gene| *gene.allele())
208                    .collect::<Vec<T>>()
209            })
210            .collect::<Vec<Vec<T>>>()
211    }
212}
213
214impl<T: Integer> Codec<IntChromosome<T>, Vec<T>> for IntChromosome<T> {
215    fn encode(&self) -> Genotype<IntChromosome<T>> {
216        Genotype::from(
217            self.iter()
218                .map(|gene| gene.new_instance())
219                .collect::<IntChromosome<T>>(),
220        )
221    }
222
223    fn decode(&self, genotype: &Genotype<IntChromosome<T>>) -> Vec<T> {
224        genotype
225            .iter()
226            .flat_map(|chromosome| {
227                chromosome
228                    .iter()
229                    .map(|gene| *gene.allele())
230                    .collect::<Vec<T>>()
231            })
232            .collect::<Vec<T>>()
233    }
234}