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}