radiate_core/codecs/
int.rs

1use super::Codec;
2use crate::genome::Gene;
3use crate::genome::genotype::Genotype;
4use crate::{Chromosome, IntChromosome, Integer};
5use std::ops::Range;
6
7/// A `Codec` for a `Genotype` of `IntGenes`. The `encode` function creates a `Genotype` with `num_chromosomes` chromosomes
8/// and `num_genes` genes per chromosome. The `decode` function creates a `Vec<Vec<T>>` from the `Genotype` where the inner `Vec`
9/// contains the alleles of the `IntGenes` in the chromosome. `T` must implement the `Integer` trait, meaning it must be one of
10/// `i8`, `i16`, `i32`, `i64`, `i128`, `u8`, `u16`, `u32`, `u64`, or `u128`.
11///
12/// The lower and upper bounds of the `IntGenes` can be set with the `with_bounds` function.
13/// The default bounds are equal to `min` and `max`.
14#[derive(Clone)]
15pub struct IntCodec<T: Integer<T>, D = T> {
16    num_chromosomes: usize,
17    num_genes: usize,
18    value_range: Range<T>,
19    bounds: Range<T>,
20    _marker: std::marker::PhantomData<D>,
21}
22
23impl<T: Integer<T>, D> IntCodec<T, D> {
24    pub fn with_bounds(mut self, bounds: Range<T>) -> Self {
25        self.bounds = bounds;
26        self
27    }
28
29    /// The different variants of `IntCodec` are all the same, so this function is used to create
30    /// a new `Genotype` with the given number of chromosomes and genes. The only difference between
31    /// them is the type `D`, which is either a `Vec<Vec<T>>`, `Vec<T>`, or `T`.
32    fn encode_common(&self) -> Genotype<IntChromosome<T>> {
33        Genotype::from(
34            (0..self.num_chromosomes)
35                .map(|_| {
36                    IntChromosome::from((
37                        self.num_genes,
38                        self.value_range.clone(),
39                        self.bounds.clone(),
40                    ))
41                })
42                .collect::<Vec<IntChromosome<T>>>(),
43        )
44    }
45}
46
47impl<T: Integer<T>> IntCodec<T, Vec<Vec<T>>> {
48    /// Create a new `IntCodec` with the given number of chromosomes, genes, min, and max values.
49    /// The f_32 values for each `IntGene` will be randomly generated between the min and max values.
50    pub fn matrix(rows: usize, cols: usize, range: Range<T>) -> Self {
51        IntCodec {
52            num_chromosomes: rows,
53            num_genes: cols,
54            value_range: range.clone(),
55            bounds: range,
56            _marker: std::marker::PhantomData,
57        }
58    }
59}
60
61impl<T: Integer<T>> IntCodec<T, Vec<T>> {
62    /// Create a new `IntCodec` with the given number of chromosomes, genes, min, and max values.
63    /// The f_32 values for each `IntGene` will be randomly generated between the min and max values.
64    pub fn vector(count: usize, range: Range<T>) -> Self {
65        IntCodec {
66            num_chromosomes: 1,
67            num_genes: count,
68            value_range: range.clone(),
69            bounds: range,
70            _marker: std::marker::PhantomData,
71        }
72    }
73}
74
75impl<T: Integer<T>> IntCodec<T, T> {
76    /// Create a new `IntCodec` with the given number of chromosomes, genes, min, and max values.
77    /// The f_32 values for each `IntGene` will be randomly generated between the min and max values.
78    pub fn scalar(range: Range<T>) -> Self {
79        IntCodec {
80            num_chromosomes: 1,
81            num_genes: 1,
82            value_range: range.clone(),
83            bounds: range,
84            _marker: std::marker::PhantomData,
85        }
86    }
87}
88
89/// Implement the `Codec` trait for a `Genotype` of `IntGenes`. This will produce a `Genotype` with the given number of chromosomes
90/// and genes. The `decode` function will create a `Vec<Vec<T>>` or a matrix.
91impl<T: Integer<T>> Codec<IntChromosome<T>, Vec<Vec<T>>> for IntCodec<T, Vec<Vec<T>>> {
92    fn encode(&self) -> Genotype<IntChromosome<T>> {
93        self.encode_common()
94    }
95
96    fn decode(&self, genotype: &Genotype<IntChromosome<T>>) -> Vec<Vec<T>> {
97        genotype
98            .iter()
99            .map(|chromosome| {
100                chromosome
101                    .iter()
102                    .map(|gene| *gene.allele())
103                    .collect::<Vec<T>>()
104            })
105            .collect::<Vec<Vec<T>>>()
106    }
107}
108
109/// Implement the `Codec` trait for a `Genotype` of `IntGenes`. This will produce a `Genotype` with a single
110/// chromosome and `num_genes` genes. The `decode` function will create a `Vec<T>` or a vector.
111impl<T: Integer<T>> Codec<IntChromosome<T>, Vec<T>> for IntCodec<T, Vec<T>> {
112    fn encode(&self) -> Genotype<IntChromosome<T>> {
113        self.encode_common()
114    }
115
116    fn decode(&self, genotype: &Genotype<IntChromosome<T>>) -> Vec<T> {
117        genotype
118            .iter()
119            .flat_map(|chromosome| {
120                chromosome
121                    .iter()
122                    .map(|gene| *gene.allele())
123                    .collect::<Vec<T>>()
124            })
125            .collect::<Vec<T>>()
126    }
127}
128
129/// Implement the `Codec` trait for a `Genotype` of `IntGenes`. This will produce a `Genotype` with a single
130/// chromosome and a single gene. The `decode` function will create a `T` or a single value.
131impl<T: Integer<T>> Codec<IntChromosome<T>, T> for IntCodec<T, T> {
132    fn encode(&self) -> Genotype<IntChromosome<T>> {
133        self.encode_common()
134    }
135
136    fn decode(&self, genotype: &Genotype<IntChromosome<T>>) -> T {
137        genotype
138            .iter()
139            .flat_map(|chromosome| {
140                chromosome
141                    .iter()
142                    .map(|gene| *gene.allele())
143                    .collect::<Vec<T>>()
144            })
145            .next()
146            .unwrap_or_default()
147    }
148}