fugue_evo/operators/
traits.rs1use rand::Rng;
6
7use crate::error::OperatorResult;
8use crate::genome::bounds::MultiBounds;
9use crate::genome::traits::EvolutionaryGenome;
10
11pub trait SelectionOperator<G: EvolutionaryGenome>: Send + Sync {
15 fn select<R: Rng>(
19 &self,
20 population: &[(G, f64)], rng: &mut R,
22 ) -> usize;
23
24 fn select_many<R: Rng>(
26 &self,
27 population: &[(G, f64)],
28 count: usize,
29 rng: &mut R,
30 ) -> Vec<usize> {
31 (0..count).map(|_| self.select(population, rng)).collect()
32 }
33}
34
35pub trait CrossoverOperator<G: EvolutionaryGenome>: Send + Sync {
39 fn crossover<R: Rng>(&self, parent1: &G, parent2: &G, rng: &mut R) -> OperatorResult<(G, G)>;
41
42 fn crossover_probability(&self) -> f64 {
44 1.0
45 }
46}
47
48pub trait MutationOperator<G: EvolutionaryGenome>: Send + Sync {
52 fn mutate<R: Rng>(&self, genome: &mut G, rng: &mut R);
54
55 fn mutation_probability(&self) -> Option<f64> {
65 Some(1.0)
66 }
67}
68
69pub trait BoundedMutationOperator<G: EvolutionaryGenome>: MutationOperator<G> {
73 fn mutate_bounded<R: Rng>(&self, genome: &mut G, bounds: &MultiBounds, rng: &mut R);
75}
76
77pub trait BoundedCrossoverOperator<G: EvolutionaryGenome>: CrossoverOperator<G> {
81 fn crossover_bounded<R: Rng>(
83 &self,
84 parent1: &G,
85 parent2: &G,
86 bounds: &MultiBounds,
87 rng: &mut R,
88 ) -> OperatorResult<(G, G)>;
89}
90
91#[cfg(test)]
92mod tests {
93 use super::*;
94 use crate::error::OperatorResult;
95 use crate::genome::real_vector::RealVector;
96 use crate::genome::traits::{EvolutionaryGenome, RealValuedGenome};
97
98 struct MockSelection;
100
101 impl SelectionOperator<RealVector> for MockSelection {
102 fn select<R: Rng>(&self, population: &[(RealVector, f64)], rng: &mut R) -> usize {
103 rng.gen_range(0..population.len())
104 }
105 }
106
107 struct MockCrossover;
109
110 impl CrossoverOperator<RealVector> for MockCrossover {
111 fn crossover<R: Rng>(
112 &self,
113 parent1: &RealVector,
114 parent2: &RealVector,
115 _rng: &mut R,
116 ) -> OperatorResult<(RealVector, RealVector)> {
117 OperatorResult::Success((parent2.clone(), parent1.clone()))
119 }
120 }
121
122 struct MockMutation;
124
125 impl MutationOperator<RealVector> for MockMutation {
126 fn mutate<R: Rng>(&self, genome: &mut RealVector, rng: &mut R) {
127 if let Some(genes) = genome.as_mut_slice() {
128 for gene in genes.iter_mut() {
129 *gene += rng.gen_range(-0.1..0.1);
130 }
131 }
132 }
133 }
134
135 #[test]
136 fn test_mock_selection() {
137 let mut rng = rand::thread_rng();
138 let population: Vec<(RealVector, f64)> = (0..10)
139 .map(|i| (RealVector::new(vec![i as f64]), i as f64))
140 .collect();
141
142 let selection = MockSelection;
143 let idx = selection.select(&population, &mut rng);
144 assert!(idx < population.len());
145 }
146
147 #[test]
148 fn test_mock_selection_many() {
149 let mut rng = rand::thread_rng();
150 let population: Vec<(RealVector, f64)> = (0..10)
151 .map(|i| (RealVector::new(vec![i as f64]), i as f64))
152 .collect();
153
154 let selection = MockSelection;
155 let indices = selection.select_many(&population, 5, &mut rng);
156 assert_eq!(indices.len(), 5);
157 for idx in indices {
158 assert!(idx < population.len());
159 }
160 }
161
162 #[test]
163 fn test_mock_crossover() {
164 let mut rng = rand::thread_rng();
165 let parent1 = RealVector::new(vec![1.0, 2.0, 3.0]);
166 let parent2 = RealVector::new(vec![4.0, 5.0, 6.0]);
167
168 let crossover = MockCrossover;
169 let result = crossover.crossover(&parent1, &parent2, &mut rng);
170 assert!(result.is_ok());
171
172 let (child1, child2) = result.genome().unwrap();
173 assert_eq!(child1.genes(), parent2.genes());
174 assert_eq!(child2.genes(), parent1.genes());
175 }
176
177 #[test]
178 fn test_mock_mutation() {
179 let mut rng = rand::thread_rng();
180 let original = RealVector::new(vec![1.0, 2.0, 3.0]);
181 let mut genome = original.clone();
182
183 let mutation = MockMutation;
184 mutation.mutate(&mut genome, &mut rng);
185
186 assert_ne!(genome, original);
189 }
190}