genetic_algorithm/fitness/
placeholders.rs

1//! placeholders for testing and bootstrapping, not really used in practice
2use crate::allele::RangeAllele;
3use crate::chromosome::GenesOwner;
4use crate::fitness::{Fitness, FitnessChromosome, FitnessPopulation, FitnessValue};
5use crate::genotype::{
6    BinaryGenotype, BitGenotype, DynamicMatrixGenotype, Genotype, StaticMatrixGenotype,
7};
8use rand::distributions::uniform::SampleUniform;
9use rand::distributions::{Distribution, Uniform};
10use rand::rngs::SmallRng;
11use rand::SeedableRng;
12use std::marker::PhantomData;
13use std::ops::Range;
14use std::{thread, time};
15
16/// placeholder for testing and bootstrapping, not really used in practice
17#[derive(Clone, Debug)]
18pub struct Zero<G: Genotype>(PhantomData<G>);
19impl<G: Genotype> Zero<G> {
20    pub fn new() -> Self {
21        Self(PhantomData)
22    }
23}
24impl<G: Genotype> Default for Zero<G> {
25    fn default() -> Self {
26        Self::new()
27    }
28}
29impl<G: Genotype> Fitness for Zero<G> {
30    type Genotype = G;
31    fn calculate_for_chromosome(
32        &mut self,
33        _chromosome: &FitnessChromosome<Self>,
34        _genotype: &Self::Genotype,
35    ) -> Option<FitnessValue> {
36        Some(0)
37    }
38}
39
40/// placeholder for testing and bootstrapping, not really used in practice
41#[derive(Clone, Debug)]
42pub struct CountTrue;
43impl Fitness for CountTrue {
44    type Genotype = BinaryGenotype;
45    fn calculate_for_chromosome(
46        &mut self,
47        chromosome: &FitnessChromosome<Self>,
48        _genotype: &Self::Genotype,
49    ) -> Option<FitnessValue> {
50        Some(chromosome.genes.iter().filter(|&value| *value).count() as FitnessValue)
51    }
52}
53
54/// placeholder for testing and bootstrapping, not really used in practice
55#[derive(Clone, Debug)]
56pub struct CountOnes;
57impl Fitness for CountOnes {
58    type Genotype = BitGenotype;
59    fn calculate_for_chromosome(
60        &mut self,
61        chromosome: &FitnessChromosome<Self>,
62        _genotype: &Self::Genotype,
63    ) -> Option<FitnessValue> {
64        Some(chromosome.genes.count_ones(..) as FitnessValue)
65    }
66}
67
68/// placeholder for testing and bootstrapping, not really used in practice
69/// Sums the genes and converts to [FitnessValue]
70/// There are 2 constructors:
71/// * new(), precision is defaulted to 1.0
72/// * new_with_precision(precision)
73#[derive(Clone, Debug)]
74pub struct SumGenes<G: Genotype> {
75    precision: f64,
76    _phantom: PhantomData<G>,
77}
78impl<G: Genotype> SumGenes<G> {
79    pub fn new() -> Self {
80        Self::default()
81    }
82    pub fn new_with_precision(precision: f64) -> Self {
83        Self {
84            precision,
85            ..Default::default()
86        }
87    }
88}
89impl<G: Genotype> Default for SumGenes<G> {
90    fn default() -> Self {
91        Self {
92            precision: 1.0_f64,
93            _phantom: PhantomData,
94        }
95    }
96}
97impl<G: Genotype> Fitness for SumGenes<G>
98where
99    G::Allele: Into<f64>,
100    G::Genes: IntoIterator<Item = G::Allele>,
101    G::Chromosome: GenesOwner<Genes = G::Genes>,
102{
103    type Genotype = G;
104    fn calculate_for_chromosome(
105        &mut self,
106        chromosome: &FitnessChromosome<Self>,
107        _genotype: &Self::Genotype,
108    ) -> Option<FitnessValue> {
109        let sum: f64 = chromosome
110            .genes()
111            .clone()
112            .into_iter()
113            .fold(0.0_f64, |acc, e| acc + e.into());
114        Some((sum / self.precision) as FitnessValue)
115    }
116}
117
118/// placeholder for testing and bootstrapping, not really used in practice
119/// Sums the dynamic matrix rows and converts to vector of [FitnessValue]
120/// There are 2 constructors:
121/// * new(), precision is defaulted to 1.0
122/// * new_with_precision(precision)
123#[derive(Clone, Debug)]
124pub struct SumDynamicMatrix<T: RangeAllele + Into<f64>>
125where
126    T: SampleUniform,
127    Uniform<T>: Send + Sync,
128{
129    precision: f64,
130    _phantom: PhantomData<T>,
131}
132impl<T: RangeAllele + Into<f64>> SumDynamicMatrix<T>
133where
134    T: SampleUniform,
135    Uniform<T>: Send + Sync,
136{
137    pub fn new() -> Self {
138        Self::default()
139    }
140    pub fn new_with_precision(precision: f64) -> Self {
141        Self {
142            precision,
143            ..Default::default()
144        }
145    }
146}
147impl<T: RangeAllele + Into<f64>> Default for SumDynamicMatrix<T>
148where
149    T: SampleUniform,
150    Uniform<T>: Send + Sync,
151{
152    fn default() -> Self {
153        Self {
154            precision: 1.0_f64,
155            _phantom: PhantomData,
156        }
157    }
158}
159impl<T: RangeAllele + Into<f64>> Fitness for SumDynamicMatrix<T>
160where
161    T: SampleUniform,
162    Uniform<T>: Send + Sync,
163{
164    type Genotype = DynamicMatrixGenotype<T>;
165    fn calculate_for_population(
166        &mut self,
167        _population: &FitnessPopulation<Self>,
168        genotype: &Self::Genotype,
169    ) -> Vec<Option<FitnessValue>> {
170        genotype
171            .data
172            .chunks(genotype.genes_size())
173            .map(|genes| {
174                (genes.iter().copied().fold(0.0_f64, |acc, e| acc + e.into()) / self.precision)
175                    as FitnessValue
176            })
177            .map(Some)
178            .collect()
179    }
180}
181
182/// placeholder for testing and bootstrapping, not really used in practice
183/// Sums the static matrix rows and converts to vector of [FitnessValue]
184/// There are 2 constructors:
185/// * new(), precision is defaulted to 1.0
186/// * new_with_precision(precision)
187#[derive(Clone, Debug)]
188pub struct SumStaticMatrix<T: RangeAllele + Into<f64>, const N: usize, const M: usize>
189where
190    T: SampleUniform,
191    Uniform<T>: Send + Sync,
192{
193    precision: f64,
194    _phantom: PhantomData<T>,
195}
196impl<T: RangeAllele + Into<f64>, const N: usize, const M: usize> SumStaticMatrix<T, N, M>
197where
198    T: SampleUniform,
199    Uniform<T>: Send + Sync,
200{
201    pub fn new() -> Self {
202        Self::default()
203    }
204    pub fn new_with_precision(precision: f64) -> Self {
205        Self {
206            precision,
207            ..Default::default()
208        }
209    }
210}
211impl<T: RangeAllele + Into<f64>, const N: usize, const M: usize> Default
212    for SumStaticMatrix<T, N, M>
213where
214    T: SampleUniform,
215    Uniform<T>: Send + Sync,
216{
217    fn default() -> Self {
218        Self {
219            precision: 1.0_f64,
220            _phantom: PhantomData,
221        }
222    }
223}
224
225impl<T: RangeAllele + Into<f64>, const N: usize, const M: usize> Fitness
226    for SumStaticMatrix<T, N, M>
227where
228    T: SampleUniform,
229    Uniform<T>: Send + Sync,
230{
231    type Genotype = StaticMatrixGenotype<T, N, M>;
232    fn calculate_for_population(
233        &mut self,
234        _population: &FitnessPopulation<Self>,
235        genotype: &Self::Genotype,
236    ) -> Vec<Option<FitnessValue>> {
237        genotype
238            .data
239            .iter()
240            .map(|genes| {
241                (genes.iter().copied().fold(0.0_f64, |acc, e| acc + e.into()) / self.precision)
242                    as FitnessValue
243            })
244            .map(Some)
245            .collect()
246    }
247}
248
249/// placeholder for testing and benchmarking, not used in practice
250#[derive(Debug)]
251pub struct CountTrueWithSleep {
252    pub micro_seconds: u64,
253    pub print_on_clone: bool,
254}
255impl CountTrueWithSleep {
256    pub fn new(micro_seconds: u64, print_on_clone: bool) -> Self {
257        Self {
258            micro_seconds,
259            print_on_clone,
260        }
261    }
262}
263impl Fitness for CountTrueWithSleep {
264    type Genotype = BinaryGenotype;
265    fn calculate_for_chromosome(
266        &mut self,
267        chromosome: &FitnessChromosome<Self>,
268        _genotype: &Self::Genotype,
269    ) -> Option<FitnessValue> {
270        thread::sleep(time::Duration::from_micros(self.micro_seconds));
271        Some(chromosome.genes.iter().filter(|&value| *value).count() as FitnessValue)
272    }
273}
274impl Clone for CountTrueWithSleep {
275    fn clone(&self) -> Self {
276        if self.print_on_clone {
277            println!("Cloned CountTrueWithSleep: {:?}", thread::current().id());
278        }
279        Self {
280            micro_seconds: self.micro_seconds,
281            print_on_clone: self.print_on_clone,
282        }
283    }
284}
285
286/// placeholder for testing and bootstrapping, not really used in practice
287#[derive(Clone, Debug)]
288pub struct Countdown<G: Genotype>(usize, PhantomData<G>);
289impl<G: Genotype> Countdown<G> {
290    pub fn new(start: usize) -> Self {
291        Self(start, PhantomData)
292    }
293}
294impl<G: Genotype> Fitness for Countdown<G> {
295    type Genotype = G;
296    fn calculate_for_chromosome(
297        &mut self,
298        _chromosome: &FitnessChromosome<Self>,
299        _genotype: &Self::Genotype,
300    ) -> Option<FitnessValue> {
301        if self.0 == 0 {
302            Some(0)
303        } else {
304            self.0 -= 1;
305            Some(self.0 as FitnessValue)
306        }
307    }
308}
309
310/// placeholder for testing and bootstrapping, not really used in practice
311#[derive(Clone, Debug)]
312pub struct CountdownNoisy<G: Genotype> {
313    start: usize,
314    step: usize,
315    noise_sampler: Uniform<usize>,
316    rng: SmallRng,
317    _phantom: PhantomData<G>,
318}
319impl<G: Genotype> CountdownNoisy<G> {
320    pub fn new(start: usize, step: usize, noise_range: Range<usize>) -> Self {
321        Self {
322            start,
323            step,
324            noise_sampler: Uniform::from(noise_range),
325            rng: SmallRng::seed_from_u64(0),
326            _phantom: PhantomData,
327        }
328    }
329}
330impl<G: Genotype> Fitness for CountdownNoisy<G> {
331    type Genotype = G;
332    fn calculate_for_chromosome(
333        &mut self,
334        _chromosome: &FitnessChromosome<Self>,
335        _genotype: &Self::Genotype,
336    ) -> Option<FitnessValue> {
337        if self.start == 0 {
338            Some(0)
339        } else {
340            self.start -= 1;
341            let base = (self.start / self.step + 1) * self.step;
342            let result = base + self.noise_sampler.sample(&mut self.rng);
343            Some(result as FitnessValue)
344        }
345    }
346}