Skip to main content

radiate_selectors/
lib.rs

1pub mod botzmann;
2pub mod elite;
3pub mod linear_rank;
4pub mod nsga2;
5pub mod nsga3;
6pub mod random_selector;
7pub mod rank;
8pub mod roulette;
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 nsga3::NSGA3Selector;
19pub use random_selector::RandomSelector;
20pub use rank::RankSelector;
21pub use roulette::RouletteSelector;
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 {
32    cdf: Vec<f32>,
33    max_index: usize,
34    current: usize,
35    uniform: bool,
36}
37
38impl ProbabilityWheelIterator {
39    pub fn new(probabilities: &[f32], max_index: usize) -> Self {
40        let mut cdf = Vec::with_capacity(probabilities.len());
41        let mut total = 0.0f32;
42
43        for &p in probabilities {
44            let w = if p.is_finite() && p > 0.0 { p } else { 0.0 };
45            total += w;
46            cdf.push(total);
47        }
48
49        let uniform = !total.is_finite() || total <= 0.0;
50        if !uniform && total != 1.0 {
51            let inv = 1.0 / total;
52            for v in &mut cdf {
53                *v *= inv;
54            }
55        }
56
57        Self {
58            cdf,
59            max_index,
60            current: 0,
61            uniform,
62        }
63    }
64}
65
66impl Iterator for ProbabilityWheelIterator {
67    type Item = usize;
68
69    #[inline]
70    fn next(&mut self) -> Option<Self::Item> {
71        if self.current >= self.max_index {
72            return None;
73        }
74
75        let n = self.cdf.len();
76        if n == 0 {
77            self.current += 1;
78            return Some(0);
79        }
80
81        let idx = if self.uniform {
82            let i = (random_provider::random::<f32>() * n as f32) as usize;
83            i.min(n.saturating_sub(1))
84        } else {
85            // threshold in [0, 1)
86            let r = random_provider::random::<f32>();
87            let i = self
88                .cdf
89                .binary_search_by(|v| v.partial_cmp(&r).unwrap_or(std::cmp::Ordering::Less))
90                .unwrap_or_else(|i| i);
91            i.min(n - 1)
92        };
93
94        self.current += 1;
95        Some(idx)
96    }
97}