Skip to main content

radiate_selectors/
linear_rank.rs

1use radiate_core::{Chromosome, Objective, Optimize, Population, Select, pareto, random_provider};
2
3pub struct LinearRankSelector {
4    selection_pressure: f32,
5}
6
7impl LinearRankSelector {
8    pub fn new(selection_pressure: f32) -> Self {
9        LinearRankSelector { selection_pressure }
10    }
11}
12
13impl<C: Chromosome + Clone> Select<C> for LinearRankSelector {
14    fn select(
15        &self,
16        population: &Population<C>,
17        objective: &Objective,
18        count: usize,
19    ) -> Population<C> {
20        let fitness_values = match objective {
21            Objective::Single(opt) => {
22                let scores = population
23                    .get_scores()
24                    .map(|score| score.as_f32())
25                    .collect::<Vec<f32>>();
26                let total = scores.iter().sum::<f32>();
27                let mut fitness_values =
28                    scores.iter().map(|&fit| fit / total).collect::<Vec<f32>>();
29
30                if let Optimize::Minimize = opt {
31                    fitness_values.reverse();
32                }
33
34                fitness_values
35            }
36            Objective::Multi(_) => {
37                let weights =
38                    pareto::weights(&population.get_scores().collect::<Vec<_>>(), objective);
39                let total_weights = weights.iter().sum::<f32>();
40                weights
41                    .iter()
42                    .map(|&fit| fit / total_weights)
43                    .collect::<Vec<f32>>()
44            }
45        };
46
47        let total_rank = (1..=fitness_values.len()).map(|i| i as f32).sum::<f32>();
48        let mut selected_population = Vec::with_capacity(count);
49
50        for _ in 0..count {
51            let target = random_provider::range(0.0..total_rank);
52            let mut cumulative_rank = 0.0;
53
54            for (rank, _) in fitness_values.iter().enumerate() {
55                cumulative_rank += (rank + 1) as f32 * self.selection_pressure;
56                if cumulative_rank > target {
57                    selected_population.push(population[rank].clone());
58                    break;
59                }
60            }
61        }
62
63        Population::new(selected_population)
64    }
65}