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
25pub(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 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}