radiate_core/codecs/
function.rs

1use crate::{Chromosome, Codec, Genotype};
2use std::sync::Arc;
3
4/// A `Codec` that uses functions to encode and decode a `Genotype` to and from a type `T`.
5/// Most of the other codecs in this module are more specialized and are used to create `Genotypes` of specific types of `Chromosomes`.
6/// This one, however, is more general and can be used to create `Genotypes` of any type of `Chromosome`.
7///
8/// # Example
9/// ``` rust
10/// use radiate_core::*;
11///
12/// const N_QUEENS: usize = 8;
13///
14/// fn main() {
15///     // this is a simple example of the NQueens problem.
16///     // The resulting codec type will be FnCodec<IntChromosome<i8>, Vec<i8>>.
17///     let codec = FnCodec::new()
18///         .with_encoder(|| {
19///             Genotype::from(IntChromosome::new((0..N_QUEENS)
20///                     .map(|_| IntGene::from(0..N_QUEENS as i8))
21///                     .collect(),
22///             ))
23///         })
24///         .with_decoder(|genotype| {
25///             genotype[0]
26///                 .genes()
27///                 .iter()
28///                 .map(|g| *g.allele())
29///                 .collect::<Vec<i8>>()
30///         });
31///
32///     // encode and decode
33///     let genotype: Genotype<IntChromosome<i8>> = codec.encode();
34///     let decoded: Vec<i8> = codec.decode(&genotype);
35/// }
36/// ```
37/// # Type Parameters
38/// - `C`: The type of chromosome used in the genotype, which must implement the `Chromosome` trait.
39/// - `T`: The type that the genotype will be decoded to.
40#[derive(Default, Clone)]
41pub struct FnCodec<C: Chromosome, T> {
42    encoder: Option<Arc<dyn Fn() -> Genotype<C>>>,
43    decoder: Option<Arc<dyn Fn(&Genotype<C>) -> T>>,
44}
45
46impl<C: Chromosome, T> FnCodec<C, T> {
47    pub fn new() -> Self {
48        FnCodec {
49            encoder: None,
50            decoder: None,
51        }
52    }
53
54    pub fn with_encoder<F>(mut self, encoder: F) -> Self
55    where
56        F: Fn() -> Genotype<C> + 'static,
57    {
58        self.encoder = Some(Arc::new(encoder));
59        self
60    }
61
62    pub fn with_decoder<F>(mut self, decoder: F) -> Self
63    where
64        F: Fn(&Genotype<C>) -> T + 'static,
65    {
66        self.decoder = Some(Arc::new(decoder));
67        self
68    }
69}
70
71impl<C: Chromosome, T> Codec<C, T> for FnCodec<C, T> {
72    fn encode(&self) -> Genotype<C> {
73        match &self.encoder {
74            Some(encoder) => encoder(),
75            None => panic!("Encoder function is not set"),
76        }
77    }
78
79    fn decode(&self, genotype: &Genotype<C>) -> T {
80        match &self.decoder {
81            Some(decoder) => decoder(genotype),
82            None => panic!("Decoder function is not set"),
83        }
84    }
85}