wafrift_evolution/evolution/crossover/
selection.rs1use crate::evolution::Chromosome;
2use rand::Rng;
3
4#[derive(Debug, Clone, Copy, PartialEq, Eq)]
6pub enum SelectionStrategy {
7 Standard,
8 Adaptive,
9 Roulette,
10}
11
12#[must_use]
14pub fn tournament_select<'a>(population: &'a [Chromosome], rng: &mut impl Rng) -> &'a Chromosome {
15 let tournament_size = 3_usize.min(population.len());
16 tournament_select_with_size(population, tournament_size, rng)
17}
18
19#[must_use]
21pub fn tournament_select_with_size<'a>(
22 population: &'a [Chromosome],
23 tournament_size: usize,
24 rng: &mut impl Rng,
25) -> &'a Chromosome {
26 let size = tournament_size.min(population.len());
27 let mut best_idx = rng.gen_range(0..population.len());
28 for _ in 1..size {
29 let candidate_idx = rng.gen_range(0..population.len());
30 if population[candidate_idx].fitness > population[best_idx].fitness {
31 best_idx = candidate_idx;
32 }
33 }
34 &population[best_idx]
35}
36
37#[must_use]
39pub fn roulette_select<'a>(population: &'a [Chromosome], rng: &mut impl Rng) -> &'a Chromosome {
40 if population.len() <= 1 {
41 return &population[0];
42 }
43 let total_fitness: f64 = population.iter().map(|c| c.fitness.max(0.0)).sum();
44 if total_fitness <= 0.0 {
45 return &population[rng.gen_range(0..population.len())];
46 }
47 let mut spin = rng.gen_range(0.0..total_fitness);
48 for chromosome in population {
49 spin -= chromosome.fitness.max(0.0);
50 if spin <= 0.0 {
51 return chromosome;
52 }
53 }
54 &population[population.len() - 1]
55}
56
57#[must_use]
59pub fn adaptive_select<'a>(
60 population: &'a [Chromosome],
61 diversity: f64,
62 rng: &mut impl Rng,
63) -> &'a Chromosome {
64 let base_size = 3_usize;
65 let max_size = (population.len() / 3).max(base_size);
66 let adjusted_size = base_size + ((max_size - base_size) as f64 * (1.0 - diversity)) as usize;
67 tournament_select_with_size(population, adjusted_size, rng)
68}