scirs2_optimize/multi_objective/selection/
mod.rs1use crate::multi_objective::solutions::Solution;
6use rand::seq::SliceRandom;
7use rand::Rng;
8
9pub trait SelectionOperator {
11 fn select(&self, population: &[Solution], n_select: usize) -> Vec<Solution>;
13}
14
15#[derive(Debug, Clone)]
17pub struct TournamentSelection {
18 tournament_size: usize,
19}
20
21impl TournamentSelection {
22 pub fn new(tournament_size: usize) -> Self {
23 Self { tournament_size }
24 }
25
26 fn binary_tournament(&self, population: &[Solution]) -> Solution {
27 let mut rng = rand::rng();
28 let idx1 = rng.gen_range(0..population.len());
29 let idx2 = rng.gen_range(0..population.len());
30
31 let sol1 = &population[idx1];
32 let sol2 = &population[idx2];
33
34 if sol1.rank < sol2.rank {
36 sol1.clone()
37 } else if sol2.rank < sol1.rank {
38 sol2.clone()
39 } else {
40 if sol1.crowding_distance > sol2.crowding_distance {
42 sol1.clone()
43 } else {
44 sol2.clone()
45 }
46 }
47 }
48}
49
50impl SelectionOperator for TournamentSelection {
51 fn select(&self, population: &[Solution], n_select: usize) -> Vec<Solution> {
52 let mut selected = Vec::with_capacity(n_select);
53
54 for _ in 0..n_select {
55 selected.push(self.binary_tournament(population));
56 }
57
58 selected
59 }
60}
61
62#[derive(Debug, Clone)]
64pub struct RandomSelection;
65
66impl RandomSelection {
67 pub fn new() -> Self {
68 Self
69 }
70}
71
72impl SelectionOperator for RandomSelection {
73 fn select(&self, population: &[Solution], n_select: usize) -> Vec<Solution> {
74 let mut rng = rand::rng();
75 let mut selected = Vec::with_capacity(n_select);
76 for _ in 0..n_select.min(population.len()) {
77 let idx = rng.gen_range(0..population.len());
78 selected.push(population[idx].clone());
79 }
80 selected
81 }
82}
83
84#[derive(Debug, Clone)]
86pub struct RouletteWheelSelection;
87
88impl RouletteWheelSelection {
89 pub fn new() -> Self {
90 Self
91 }
92}
93
94impl SelectionOperator for RouletteWheelSelection {
95 fn select(&self, population: &[Solution], n_select: usize) -> Vec<Solution> {
96 let mut rng = rand::rng();
97 let mut selected = Vec::with_capacity(n_select);
98
99 let max_rank = population.iter().map(|s| s.rank).max().unwrap_or(1);
101 let fitness_scores: Vec<f64> = population
102 .iter()
103 .map(|s| (max_rank + 1 - s.rank) as f64)
104 .collect();
105
106 let total_fitness: f64 = fitness_scores.iter().sum();
107
108 for _ in 0..n_select {
109 let mut accumulator = 0.0;
110 let random_value = rng.random::<f64>() * total_fitness;
111
112 for (i, &fitness) in fitness_scores.iter().enumerate() {
113 accumulator += fitness;
114 if accumulator >= random_value {
115 selected.push(population[i].clone());
116 break;
117 }
118 }
119 }
120
121 selected
122 }
123}
124
125#[derive(Debug, Clone)]
127pub struct TruncationSelection;
128
129impl TruncationSelection {
130 pub fn new() -> Self {
131 Self
132 }
133}
134
135impl SelectionOperator for TruncationSelection {
136 fn select(&self, population: &[Solution], n_select: usize) -> Vec<Solution> {
137 let mut sorted = population.to_vec();
138 sorted.sort_by(|a, b| {
139 a.rank.cmp(&b.rank).then(
140 b.crowding_distance
141 .partial_cmp(&a.crowding_distance)
142 .unwrap(),
143 )
144 });
145
146 sorted.into_iter().take(n_select).collect()
147 }
148}