radiate_rust/engines/selectors/
selector.rs

1use crate::engines::genome::genes::gene::Gene;
2use crate::engines::genome::population::Population;
3use crate::Optimize;
4use rand::Rng;
5
6pub trait Select<G, A> 
7where
8    G: Gene<G, A>
9{
10    fn select(&self, population: &Population<G, A>, optimize: &Optimize, count: usize) -> Population<G, A>;
11}
12
13#[allow(dead_code)]
14pub enum Selector {
15    Tournament(u8),
16    Roulette,
17    Rank,
18    Elitism,
19    Boltzmann(f32),
20}
21
22impl<G, A> Select<G, A> for Selector 
23where
24    G: Gene<G, A>
25{
26    #[inline]
27    fn select(&self, population: &Population<G, A>, optimize: &Optimize, count: usize) -> Population<G, A> {
28        match self {
29            Selector::Tournament(size) => {
30                let mut rng = rand::thread_rng();
31                let mut selected = Vec::with_capacity(count);
32
33                for _ in 0..count {
34                    let mut tournament = Vec::with_capacity(*size as usize);
35                    for _ in 0..*size {
36                        let idx = rng.gen_range(0..population.len());
37                        tournament.push(idx);
38                    }
39
40                    tournament.sort();
41
42                    selected.push(population.get(tournament[0]).clone());
43                }
44
45                Population::from_vec(selected)
46            }
47            Selector::Roulette => {
48                let mut selected = Vec::with_capacity(count);
49                let mut fitness_values = Vec::with_capacity(population.len());
50                let mut rng = rand::thread_rng();
51                
52                let total = population
53                    .iter()
54                    .map(|individual| match individual.score() {
55                        Some(score) => score.as_float(),
56                        None => 0.0,
57                    })
58                    .sum::<f32>();
59
60                for individual in population.iter() {
61                    let score = match individual.score() {
62                        Some(score) => score.as_float(),
63                        None => 0.0,
64                    };
65
66                    fitness_values.push(score / total);
67                }
68
69                if optimize == &Optimize::Minimize {
70                    fitness_values.reverse();
71                }
72
73                let total_fitness = fitness_values.iter().sum::<f32>();
74
75                for _ in 0..count {
76                    let mut idx = rng.gen_range(0.0..total_fitness);
77
78                    for i in 0..fitness_values.len() {
79                        idx -= fitness_values[i];
80                        if idx <= 0.0 {
81                            selected.push(population.get(i).clone());
82                            break;
83                        }
84                    }
85                }
86
87                Population::from_vec(selected)
88            }
89            Selector::Rank => {
90                let mut selected = Vec::with_capacity(count);
91                let mut rng = rand::thread_rng();
92
93                let total_rank = (population.len() * (population.len() + 1)) as f32 / 2.0;
94
95                for _ in 0..count {
96                    let mut idx = rng.gen_range(0.0..total_rank);
97                    let mut selected_idx = 0;
98                    for individual in population.iter() {
99                        idx -= (population.len() - selected_idx) as f32;
100                        if idx <= 0.0 {
101                            selected.push(individual.clone());
102                            break;
103                        }
104                        selected_idx += 1;
105                    }
106                }
107
108                Population::from_vec(selected)
109            }
110            Selector::Elitism => population
111                .iter()
112                .take(count)
113                .map(|individual| individual.clone())
114                .collect::<Population<G, A>>(),
115            Selector::Boltzmann(temperature) => {
116                let mut selected = Vec::with_capacity(count);
117                let mut rng = rand::thread_rng();
118
119                let mut min = population.get(0).score().as_ref().unwrap().as_float();
120                let mut max = min;
121
122                for individual in population.iter() {
123                    let score = individual.score().as_ref().unwrap().as_float();
124                    if score < min {
125                        min = score;
126                    }
127                    if score > max {
128                        max = score;
129                    }
130                }
131
132                let diff = max - min;
133                if diff == 0.0 {
134                    return population
135                        .iter()
136                        .take(count)
137                        .map(|individual| individual.clone())
138                        .collect::<Population<G, A>>();
139                }
140
141                let mut result = Vec::with_capacity(population.len());
142                for individual in population.iter() {
143                    let score = individual.score().as_ref().unwrap().as_float();
144                    let fitness = (score - min) / diff;
145                    let value = (temperature * fitness).exp();
146
147                    result.push(value);
148                }
149
150                let total_fitness = result.iter().sum::<f32>();
151                for i in 0..result.len() {
152                    result[i] /= total_fitness;
153                }
154
155                if optimize == &Optimize::Minimize {
156                    result.reverse();
157                }
158
159                let total_fitness = result.iter().sum::<f32>();
160
161                for _ in 0..count {
162                    let mut idx = rng.gen_range(0.0..total_fitness);
163
164                    for i in 0..result.len() {
165                        idx -= result[i];
166                        if idx <= 0.0 {
167                            selected.push(population.get(i).clone());
168                            break;
169                        }
170                    }
171                }
172
173                Population::from_vec(selected)
174            }
175        }
176    }
177}