radiate_rust/engines/selectors/
selector.rs1use 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}