radiate_selectors/
lib.rs

1pub mod botzmann;
2pub mod elite;
3pub mod linear_rank;
4pub mod nsga2;
5pub mod random_selector;
6pub mod rank;
7pub mod roulette;
8pub mod steady_state;
9pub mod stochastic_sampling;
10pub mod tournament;
11
12use radiate_core::random_provider;
13
14pub use botzmann::BoltzmannSelector;
15pub use elite::EliteSelector;
16pub use linear_rank::LinearRankSelector;
17pub use nsga2::{NSGA2Selector, TournamentNSGA2Selector};
18pub use random_selector::RandomSelector;
19pub use rank::RankSelector;
20pub use roulette::RouletteSelector;
21pub use steady_state::SteadyStateSelector;
22pub use stochastic_sampling::StochasticUniversalSamplingSelector;
23pub use tournament::TournamentSelector;
24
25/// An iterator that generates random indices based on probabilities.
26/// This iterator is used in the RouletteWheel selection algorithm, and
27/// Boltzmann selection algorithm. This is essentially the 'roulette wheel'
28/// that is spun to select individuals from the population. The probability
29/// of selecting an individual is based on the fitness (probability) of the individual.
30/// The higher the fitness, the higher the probability of the individual being selected.
31pub(crate) struct ProbabilityWheelIterator<'a> {
32    probabilities: &'a [f32],
33    total: f32,
34    max_index: usize,
35    current: usize,
36}
37
38impl<'a> ProbabilityWheelIterator<'a> {
39    pub fn new(probabilities: &'a [f32], max_index: usize) -> Self {
40        let total = probabilities.iter().sum();
41        Self {
42            probabilities,
43            total,
44            max_index,
45            current: 0,
46        }
47    }
48}
49
50impl Iterator for ProbabilityWheelIterator<'_> {
51    type Item = usize;
52
53    fn next(&mut self) -> Option<Self::Item> {
54        // In `Radiate` there is a selector for surviving individuals (members who will be selected
55        // to be passed on to the next generation without any changes)
56        // and a selector for selecting individuals to be used in the
57        // next generation. Because of this, we don't select all the individuals
58        // in the population, we only select a certain number of individuals.
59        // If we have selected all the individuals that this selector is supposed to select, we return None.
60        if self.current >= self.max_index {
61            return None;
62        }
63
64        let mut value = random_provider::random::<f32>() * self.total;
65        let mut index = 0;
66
67        // We iterate over the probabilities of the individuals in the population - the 'wheel'
68        for (i, &prob) in self.probabilities.iter().enumerate() {
69            value -= prob;
70            if value <= 0.0 {
71                index = i;
72                break;
73            }
74        }
75
76        self.current += 1;
77        Some(index)
78    }
79}