1use alloc::vec::Vec;
2
3use crate::{cascade_sum::cascade_sum, chromosome::Chromosome};
4
5fn invert_normalize<T, I: Iterator<Item = T>>(values: I) -> impl Iterator<Item = f64>
6where
7 T: Into<f64> + Clone,
8 I: Clone,
9{
10 let coefficients = values.map(|v| -> f64 { 1_f64 / v.into() });
11 let sum: f64 = coefficients.clone().sum();
12 coefficients.map(move |v| v / sum)
13}
14
15#[cfg(test)]
16mod tests {
17 use alloc::vec::Vec;
18
19 #[test]
20 fn invert_normalize_test() {
21 use crate::selector::invert_normalize;
22 assert_eq!(
23 invert_normalize(vec![2, 4, 8, 8].into_iter()).collect::<Vec<_>>(),
24 vec![0.5, 0.25, 0.125, 0.125]
25 );
26 }
27}
28
29pub trait Selector<T> {
31 fn select_chromosome<R: rand::RngCore>(
33 &self,
34 chromosomes: &[Chromosome<T>],
35 rng: &mut R,
36 ) -> Vec<Chromosome<T>>;
37 fn is_ideal_chromosome(&self, chromosome: &Chromosome<T>) -> bool;
39}
40
41pub trait Fitness {
46 type Value;
47 fn fitness(&self, chromosome: &Chromosome<Self::Value>) -> Self::Value;
48 fn is_ideal_fitness(&self, fitness: Self::Value) -> bool;
49}
50
51#[derive(Debug)]
63pub struct FitnessSelector<F> {
64 fitness: F,
65}
66
67impl<F: Fitness> From<F> for FitnessSelector<F> {
68 fn from(value: F) -> Self {
69 FitnessSelector { fitness: value }
70 }
71}
72
73fn abs64(v: f64) -> f64 {
74 #[cfg(feature = "std")]
75 {
76 v.abs()
77 }
78 #[cfg(not(feature = "std"))]
79 if v >= 0. {
80 v
81 } else {
82 -v
83 }
84}
85
86impl<T: Into<f64> + Clone, F: Fitness<Value = T>> Selector<T> for FitnessSelector<F> {
87 fn select_chromosome<R: rand::RngCore>(
88 &self,
89 chromosomes: &[Chromosome<T>],
90 rng: &mut R,
91 ) -> Vec<Chromosome<T>> {
92 let fitness = chromosomes.iter().map(|c| self.fitness.fitness(c));
93 let nfv = cascade_sum(invert_normalize(fitness).map(abs64).collect());
94
95 let mut result: Vec<Chromosome<T>> = Vec::with_capacity(chromosomes.len());
96 while result.len() < chromosomes.len() {
97 match nfv.random_index(rng) {
98 Some(i) => result.push(chromosomes[i].clone()),
99 _ => {}
100 };
101 }
102 result
103 }
104
105 fn is_ideal_chromosome(&self, chromosome: &Chromosome<T>) -> bool {
106 self.fitness
107 .is_ideal_fitness(self.fitness.fitness(chromosome))
108 }
109}