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}