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) -> f64 {
57 1.0
58 }
59}
60
61pub trait BoundedMutationOperator<G: EvolutionaryGenome>: MutationOperator<G> {
65 fn mutate_bounded<R: Rng>(&self, genome: &mut G, bounds: &MultiBounds, rng: &mut R);
67}
68
69pub trait BoundedCrossoverOperator<G: EvolutionaryGenome>: CrossoverOperator<G> {
73 fn crossover_bounded<R: Rng>(
75 &self,
76 parent1: &G,
77 parent2: &G,
78 bounds: &MultiBounds,
79 rng: &mut R,
80 ) -> OperatorResult<(G, G)>;
81}
82
83#[cfg(test)]
84mod tests {
85 use super::*;
86 use crate::error::OperatorResult;
87 use crate::genome::real_vector::RealVector;
88 use crate::genome::traits::{EvolutionaryGenome, RealValuedGenome};
89
90 struct MockSelection;
92
93 impl SelectionOperator<RealVector> for MockSelection {
94 fn select<R: Rng>(&self, population: &[(RealVector, f64)], rng: &mut R) -> usize {
95 rng.gen_range(0..population.len())
96 }
97 }
98
99 struct MockCrossover;
101
102 impl CrossoverOperator<RealVector> for MockCrossover {
103 fn crossover<R: Rng>(
104 &self,
105 parent1: &RealVector,
106 parent2: &RealVector,
107 _rng: &mut R,
108 ) -> OperatorResult<(RealVector, RealVector)> {
109 OperatorResult::Success((parent2.clone(), parent1.clone()))
111 }
112 }
113
114 struct MockMutation;
116
117 impl MutationOperator<RealVector> for MockMutation {
118 fn mutate<R: Rng>(&self, genome: &mut RealVector, rng: &mut R) {
119 if let Some(genes) = genome.as_mut_slice() {
120 for gene in genes.iter_mut() {
121 *gene += rng.gen_range(-0.1..0.1);
122 }
123 }
124 }
125 }
126
127 #[test]
128 fn test_mock_selection() {
129 let mut rng = rand::thread_rng();
130 let population: Vec<(RealVector, f64)> = (0..10)
131 .map(|i| (RealVector::new(vec![i as f64]), i as f64))
132 .collect();
133
134 let selection = MockSelection;
135 let idx = selection.select(&population, &mut rng);
136 assert!(idx < population.len());
137 }
138
139 #[test]
140 fn test_mock_selection_many() {
141 let mut rng = rand::thread_rng();
142 let population: Vec<(RealVector, f64)> = (0..10)
143 .map(|i| (RealVector::new(vec![i as f64]), i as f64))
144 .collect();
145
146 let selection = MockSelection;
147 let indices = selection.select_many(&population, 5, &mut rng);
148 assert_eq!(indices.len(), 5);
149 for idx in indices {
150 assert!(idx < population.len());
151 }
152 }
153
154 #[test]
155 fn test_mock_crossover() {
156 let mut rng = rand::thread_rng();
157 let parent1 = RealVector::new(vec![1.0, 2.0, 3.0]);
158 let parent2 = RealVector::new(vec![4.0, 5.0, 6.0]);
159
160 let crossover = MockCrossover;
161 let result = crossover.crossover(&parent1, &parent2, &mut rng);
162 assert!(result.is_ok());
163
164 let (child1, child2) = result.genome().unwrap();
165 assert_eq!(child1.genes(), parent2.genes());
166 assert_eq!(child2.genes(), parent1.genes());
167 }
168
169 #[test]
170 fn test_mock_mutation() {
171 let mut rng = rand::thread_rng();
172 let original = RealVector::new(vec![1.0, 2.0, 3.0]);
173 let mut genome = original.clone();
174
175 let mutation = MockMutation;
176 mutation.mutate(&mut genome, &mut rng);
177
178 assert_ne!(genome, original);
181 }
182}