1use rand::Rng;
6
7#[cfg(feature = "parallel")]
8use rayon::prelude::*;
9
10use crate::fitness::traits::{Fitness, FitnessValue};
11use crate::genome::bounds::MultiBounds;
12use crate::genome::traits::EvolutionaryGenome;
13use crate::population::individual::Individual;
14
15#[derive(Clone, Debug)]
17pub struct Population<G, F = f64>
18where
19 G: EvolutionaryGenome,
20 F: FitnessValue,
21{
22 individuals: Vec<Individual<G, F>>,
24 generation: usize,
26}
27
28impl<G, F> Population<G, F>
29where
30 G: EvolutionaryGenome,
31 F: FitnessValue,
32{
33 pub fn new() -> Self {
35 Self {
36 individuals: Vec::new(),
37 generation: 0,
38 }
39 }
40
41 pub fn with_capacity(capacity: usize) -> Self {
43 Self {
44 individuals: Vec::with_capacity(capacity),
45 generation: 0,
46 }
47 }
48
49 pub fn from_individuals(individuals: Vec<Individual<G, F>>) -> Self {
51 Self {
52 individuals,
53 generation: 0,
54 }
55 }
56
57 pub fn random<R: Rng>(size: usize, bounds: &MultiBounds, rng: &mut R) -> Self {
59 let individuals = (0..size)
60 .map(|_| Individual::new(G::generate(rng, bounds)))
61 .collect();
62 Self {
63 individuals,
64 generation: 0,
65 }
66 }
67
68 pub fn generation(&self) -> usize {
70 self.generation
71 }
72
73 pub fn increment_generation(&mut self) {
75 self.generation += 1;
76 }
77
78 pub fn set_generation(&mut self, generation: usize) {
80 self.generation = generation;
81 }
82
83 pub fn len(&self) -> usize {
85 self.individuals.len()
86 }
87
88 pub fn is_empty(&self) -> bool {
90 self.individuals.is_empty()
91 }
92
93 pub fn get(&self, index: usize) -> Option<&Individual<G, F>> {
95 self.individuals.get(index)
96 }
97
98 pub fn get_mut(&mut self, index: usize) -> Option<&mut Individual<G, F>> {
100 self.individuals.get_mut(index)
101 }
102
103 pub fn push(&mut self, individual: Individual<G, F>) {
105 self.individuals.push(individual);
106 }
107
108 pub fn pop(&mut self) -> Option<Individual<G, F>> {
110 self.individuals.pop()
111 }
112
113 pub fn clear(&mut self) {
115 self.individuals.clear();
116 }
117
118 pub fn iter(&self) -> impl Iterator<Item = &Individual<G, F>> {
120 self.individuals.iter()
121 }
122
123 pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut Individual<G, F>> {
125 self.individuals.iter_mut()
126 }
127
128 pub fn individuals(&self) -> &[Individual<G, F>] {
130 &self.individuals
131 }
132
133 pub fn individuals_mut(&mut self) -> &mut Vec<Individual<G, F>> {
135 &mut self.individuals
136 }
137
138 pub fn into_individuals(self) -> Vec<Individual<G, F>> {
140 self.individuals
141 }
142
143 pub fn best(&self) -> Option<&Individual<G, F>> {
145 self.individuals
146 .iter()
147 .filter(|i| i.is_evaluated())
148 .max_by(|a, b| {
149 let fa = a
150 .fitness
151 .as_ref()
152 .map(|f| f.to_f64())
153 .unwrap_or(f64::NEG_INFINITY);
154 let fb = b
155 .fitness
156 .as_ref()
157 .map(|f| f.to_f64())
158 .unwrap_or(f64::NEG_INFINITY);
159 fa.partial_cmp(&fb).unwrap_or(std::cmp::Ordering::Equal)
160 })
161 }
162
163 pub fn worst(&self) -> Option<&Individual<G, F>> {
165 self.individuals
166 .iter()
167 .filter(|i| i.is_evaluated())
168 .min_by(|a, b| {
169 let fa = a
170 .fitness
171 .as_ref()
172 .map(|f| f.to_f64())
173 .unwrap_or(f64::INFINITY);
174 let fb = b
175 .fitness
176 .as_ref()
177 .map(|f| f.to_f64())
178 .unwrap_or(f64::INFINITY);
179 fa.partial_cmp(&fb).unwrap_or(std::cmp::Ordering::Equal)
180 })
181 }
182
183 pub fn sort_by_fitness(&mut self) {
185 self.individuals.sort_by(|a, b| {
186 let fa = a
187 .fitness
188 .as_ref()
189 .map(|f| f.to_f64())
190 .unwrap_or(f64::NEG_INFINITY);
191 let fb = b
192 .fitness
193 .as_ref()
194 .map(|f| f.to_f64())
195 .unwrap_or(f64::NEG_INFINITY);
196 fb.partial_cmp(&fa).unwrap_or(std::cmp::Ordering::Equal)
197 });
198 }
199
200 pub fn truncate_to_best(&mut self, size: usize) {
202 self.sort_by_fitness();
203 self.individuals.truncate(size);
204 }
205
206 pub fn all_evaluated(&self) -> bool {
208 self.individuals.iter().all(|i| i.is_evaluated())
209 }
210
211 pub fn count_evaluated(&self) -> usize {
213 self.individuals.iter().filter(|i| i.is_evaluated()).count()
214 }
215
216 pub fn as_selection_pool(&self) -> Vec<(&G, f64)> {
218 self.individuals
219 .iter()
220 .filter_map(|i| i.fitness.as_ref().map(|f| (&i.genome, f.to_f64())))
221 .collect()
222 }
223
224 pub fn as_fitness_pairs(&self) -> Vec<(G, f64)>
226 where
227 G: Clone,
228 {
229 self.individuals
230 .iter()
231 .filter_map(|i| i.fitness.as_ref().map(|f| (i.genome.clone(), f.to_f64())))
232 .collect()
233 }
234
235 pub fn evaluate<Fit>(&mut self, fitness: &Fit)
237 where
238 Fit: Fitness<Genome = G, Value = F>,
239 {
240 for individual in &mut self.individuals {
241 if !individual.is_evaluated() {
242 let f = fitness.evaluate(&individual.genome);
243 individual.set_fitness(f);
244 }
245 }
246 }
247
248 pub fn mean_fitness(&self) -> Option<f64> {
250 let evaluated: Vec<f64> = self
251 .individuals
252 .iter()
253 .filter_map(|i| i.fitness.as_ref().map(|f| f.to_f64()))
254 .collect();
255
256 if evaluated.is_empty() {
257 None
258 } else {
259 Some(evaluated.iter().sum::<f64>() / evaluated.len() as f64)
260 }
261 }
262
263 pub fn fitness_std(&self) -> Option<f64> {
265 let mean = self.mean_fitness()?;
266 let evaluated: Vec<f64> = self
267 .individuals
268 .iter()
269 .filter_map(|i| i.fitness.as_ref().map(|f| f.to_f64()))
270 .collect();
271
272 if evaluated.len() < 2 {
273 return None;
274 }
275
276 let variance = evaluated.iter().map(|f| (f - mean).powi(2)).sum::<f64>()
277 / (evaluated.len() - 1) as f64;
278 Some(variance.sqrt())
279 }
280
281 pub fn diversity(&self) -> f64 {
283 if self.len() < 2 {
284 return 0.0;
285 }
286
287 let mut total_distance = 0.0;
288 let mut count = 0;
289
290 for i in 0..self.len() {
291 for j in (i + 1)..self.len() {
292 total_distance += self.individuals[i]
293 .genome
294 .distance(&self.individuals[j].genome);
295 count += 1;
296 }
297 }
298
299 if count == 0 {
300 0.0
301 } else {
302 total_distance / count as f64
303 }
304 }
305}
306
307#[cfg(feature = "parallel")]
309impl<G, F> Population<G, F>
310where
311 G: EvolutionaryGenome + Send + Sync,
312 F: FitnessValue + Send,
313{
314 pub fn evaluate_parallel<Fit>(&mut self, fitness: &Fit)
316 where
317 Fit: Fitness<Genome = G, Value = F> + Sync,
318 {
319 self.individuals
320 .par_iter_mut()
321 .filter(|i| !i.is_evaluated())
322 .for_each(|individual| {
323 let f = fitness.evaluate(&individual.genome);
324 individual.set_fitness(f);
325 });
326 }
327}
328
329#[cfg(not(feature = "parallel"))]
331impl<G, F> Population<G, F>
332where
333 G: EvolutionaryGenome,
334 F: FitnessValue,
335{
336 pub fn evaluate_parallel<Fit>(&mut self, fitness: &Fit)
340 where
341 Fit: Fitness<Genome = G, Value = F>,
342 {
343 self.evaluate(fitness);
344 }
345}
346
347impl<G, F> Default for Population<G, F>
348where
349 G: EvolutionaryGenome,
350 F: FitnessValue,
351{
352 fn default() -> Self {
353 Self::new()
354 }
355}
356
357impl<G, F> std::ops::Index<usize> for Population<G, F>
358where
359 G: EvolutionaryGenome,
360 F: FitnessValue,
361{
362 type Output = Individual<G, F>;
363
364 fn index(&self, index: usize) -> &Self::Output {
365 &self.individuals[index]
366 }
367}
368
369impl<G, F> std::ops::IndexMut<usize> for Population<G, F>
370where
371 G: EvolutionaryGenome,
372 F: FitnessValue,
373{
374 fn index_mut(&mut self, index: usize) -> &mut Self::Output {
375 &mut self.individuals[index]
376 }
377}
378
379impl<G, F> IntoIterator for Population<G, F>
380where
381 G: EvolutionaryGenome,
382 F: FitnessValue,
383{
384 type Item = Individual<G, F>;
385 type IntoIter = std::vec::IntoIter<Individual<G, F>>;
386
387 fn into_iter(self) -> Self::IntoIter {
388 self.individuals.into_iter()
389 }
390}
391
392impl<G, F> FromIterator<Individual<G, F>> for Population<G, F>
393where
394 G: EvolutionaryGenome,
395 F: FitnessValue,
396{
397 fn from_iter<I: IntoIterator<Item = Individual<G, F>>>(iter: I) -> Self {
398 Self::from_individuals(iter.into_iter().collect())
399 }
400}
401
402#[cfg(test)]
403mod tests {
404 use super::*;
405 use crate::fitness::benchmarks::Sphere;
406 use crate::genome::real_vector::RealVector;
407
408 fn create_test_population() -> Population<RealVector> {
409 let individuals = vec![
410 Individual::with_fitness(RealVector::new(vec![1.0]), 10.0),
411 Individual::with_fitness(RealVector::new(vec![2.0]), 20.0),
412 Individual::with_fitness(RealVector::new(vec![3.0]), 30.0),
413 Individual::with_fitness(RealVector::new(vec![4.0]), 40.0),
414 Individual::with_fitness(RealVector::new(vec![5.0]), 50.0),
415 ];
416 Population::from_individuals(individuals)
417 }
418
419 #[test]
420 fn test_population_new() {
421 let pop: Population<RealVector> = Population::new();
422 assert!(pop.is_empty());
423 assert_eq!(pop.generation(), 0);
424 }
425
426 #[test]
427 fn test_population_random() {
428 let mut rng = rand::thread_rng();
429 let bounds = MultiBounds::symmetric(5.0, 3);
430 let pop: Population<RealVector> = Population::random(10, &bounds, &mut rng);
431
432 assert_eq!(pop.len(), 10);
433 assert!(!pop.all_evaluated());
434 }
435
436 #[test]
437 fn test_population_best_worst() {
438 let pop = create_test_population();
439
440 let best = pop.best().unwrap();
441 assert_eq!(best.fitness_f64(), 50.0);
442
443 let worst = pop.worst().unwrap();
444 assert_eq!(worst.fitness_f64(), 10.0);
445 }
446
447 #[test]
448 fn test_population_sort_by_fitness() {
449 let mut pop = create_test_population();
450 pop.sort_by_fitness();
451
452 let fitnesses: Vec<f64> = pop.iter().map(|i| i.fitness_f64()).collect();
453 assert_eq!(fitnesses, vec![50.0, 40.0, 30.0, 20.0, 10.0]);
454 }
455
456 #[test]
457 fn test_population_truncate_to_best() {
458 let mut pop = create_test_population();
459 pop.truncate_to_best(3);
460
461 assert_eq!(pop.len(), 3);
462 let fitnesses: Vec<f64> = pop.iter().map(|i| i.fitness_f64()).collect();
463 assert_eq!(fitnesses, vec![50.0, 40.0, 30.0]);
464 }
465
466 #[test]
467 fn test_population_mean_fitness() {
468 let pop = create_test_population();
469 let mean = pop.mean_fitness().unwrap();
470 assert_eq!(mean, 30.0); }
472
473 #[test]
474 fn test_population_fitness_std() {
475 let pop = create_test_population();
476 let std = pop.fitness_std().unwrap();
477 assert!((std - 15.81).abs() < 0.1);
481 }
482
483 #[test]
484 fn test_population_evaluate() {
485 let mut rng = rand::thread_rng();
486 let bounds = MultiBounds::symmetric(5.0, 3);
487 let mut pop: Population<RealVector> = Population::random(5, &bounds, &mut rng);
488
489 let fitness = Sphere::new(3);
490 pop.evaluate(&fitness);
491
492 assert!(pop.all_evaluated());
493 assert_eq!(pop.count_evaluated(), 5);
494 }
495
496 #[test]
497 fn test_population_evaluate_parallel() {
498 let mut rng = rand::thread_rng();
499 let bounds = MultiBounds::symmetric(5.0, 3);
500 let mut pop: Population<RealVector> = Population::random(100, &bounds, &mut rng);
501
502 let fitness = Sphere::new(3);
503 pop.evaluate_parallel(&fitness);
504
505 assert!(pop.all_evaluated());
506 assert_eq!(pop.count_evaluated(), 100);
507 }
508
509 #[test]
510 fn test_population_generation() {
511 let mut pop = create_test_population();
512 assert_eq!(pop.generation(), 0);
513
514 pop.increment_generation();
515 assert_eq!(pop.generation(), 1);
516
517 pop.set_generation(100);
518 assert_eq!(pop.generation(), 100);
519 }
520
521 #[test]
522 fn test_population_push_pop() {
523 let mut pop: Population<RealVector> = Population::new();
524
525 pop.push(Individual::with_fitness(RealVector::new(vec![1.0]), 10.0));
526 assert_eq!(pop.len(), 1);
527
528 let ind = pop.pop().unwrap();
529 assert_eq!(ind.fitness_f64(), 10.0);
530 assert!(pop.is_empty());
531 }
532
533 #[test]
534 fn test_population_indexing() {
535 let pop = create_test_population();
536 assert_eq!(pop[0].fitness_f64(), 10.0);
537 assert_eq!(pop[4].fitness_f64(), 50.0);
538 }
539
540 #[test]
541 fn test_population_as_selection_pool() {
542 let pop = create_test_population();
543 let pool = pop.as_selection_pool();
544
545 assert_eq!(pool.len(), 5);
546 assert_eq!(pool[0].1, 10.0);
547 assert_eq!(pool[4].1, 50.0);
548 }
549
550 #[test]
551 fn test_population_diversity() {
552 let individuals = vec![
553 Individual::with_fitness(RealVector::new(vec![0.0, 0.0]), 1.0),
554 Individual::with_fitness(RealVector::new(vec![1.0, 0.0]), 1.0),
555 Individual::with_fitness(RealVector::new(vec![0.0, 1.0]), 1.0),
556 ];
557 let pop = Population::from_individuals(individuals);
558
559 let diversity = pop.diversity();
560 assert!(diversity > 1.0 && diversity < 1.2);
562 }
563
564 #[test]
565 fn test_population_from_iterator() {
566 let individuals = vec![
567 Individual::with_fitness(RealVector::new(vec![1.0]), 10.0),
568 Individual::with_fitness(RealVector::new(vec![2.0]), 20.0),
569 ];
570 let pop: Population<RealVector> = individuals.into_iter().collect();
571
572 assert_eq!(pop.len(), 2);
573 }
574
575 #[test]
576 fn test_population_into_iterator() {
577 let pop = create_test_population();
578 let individuals: Vec<_> = pop.into_iter().collect();
579
580 assert_eq!(individuals.len(), 5);
581 }
582}