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>> {
152 self.individuals
153 .iter()
154 .filter(|i| i.is_evaluated())
155 .max_by(|a, b| {
156 a.fitness
157 .as_ref()
158 .expect("filtered to evaluated individuals")
159 .cmp_by_quality(
160 b.fitness
161 .as_ref()
162 .expect("filtered to evaluated individuals"),
163 )
164 })
165 }
166
167 pub fn worst(&self) -> Option<&Individual<G, F>> {
172 self.individuals
173 .iter()
174 .filter(|i| i.is_evaluated())
175 .min_by(|a, b| {
176 a.fitness
177 .as_ref()
178 .expect("filtered to evaluated individuals")
179 .cmp_by_quality(
180 b.fitness
181 .as_ref()
182 .expect("filtered to evaluated individuals"),
183 )
184 })
185 }
186
187 pub fn sort_by_fitness(&mut self) {
193 self.individuals.sort_by(|a, b| {
194 match (a.fitness.as_ref(), b.fitness.as_ref()) {
195 (Some(fa), Some(fb)) => fb.cmp_by_quality(fa),
197 (Some(_), None) => std::cmp::Ordering::Less,
199 (None, Some(_)) => std::cmp::Ordering::Greater,
200 (None, None) => std::cmp::Ordering::Equal,
201 }
202 });
203 }
204
205 pub fn truncate_to_best(&mut self, size: usize) {
207 self.sort_by_fitness();
208 self.individuals.truncate(size);
209 }
210
211 pub fn all_evaluated(&self) -> bool {
213 self.individuals.iter().all(|i| i.is_evaluated())
214 }
215
216 pub fn count_evaluated(&self) -> usize {
218 self.individuals.iter().filter(|i| i.is_evaluated()).count()
219 }
220
221 pub fn as_selection_pool(&self) -> Vec<(&G, f64)> {
223 self.individuals
224 .iter()
225 .filter_map(|i| i.fitness.as_ref().map(|f| (&i.genome, f.to_f64())))
226 .collect()
227 }
228
229 pub fn as_fitness_pairs(&self) -> Vec<(G, f64)>
231 where
232 G: Clone,
233 {
234 self.individuals
235 .iter()
236 .filter_map(|i| i.fitness.as_ref().map(|f| (i.genome.clone(), f.to_f64())))
237 .collect()
238 }
239
240 pub fn evaluate<Fit>(&mut self, fitness: &Fit)
242 where
243 Fit: Fitness<Genome = G, Value = F>,
244 {
245 for individual in &mut self.individuals {
246 if !individual.is_evaluated() {
247 let f = fitness.evaluate(&individual.genome);
248 individual.set_fitness(f);
249 }
250 }
251 }
252
253 pub fn mean_fitness(&self) -> Option<f64> {
255 let evaluated: Vec<f64> = self
256 .individuals
257 .iter()
258 .filter_map(|i| i.fitness.as_ref().map(|f| f.to_f64()))
259 .collect();
260
261 if evaluated.is_empty() {
262 None
263 } else {
264 Some(evaluated.iter().sum::<f64>() / evaluated.len() as f64)
265 }
266 }
267
268 pub fn fitness_std(&self) -> Option<f64> {
270 let mean = self.mean_fitness()?;
271 let evaluated: Vec<f64> = self
272 .individuals
273 .iter()
274 .filter_map(|i| i.fitness.as_ref().map(|f| f.to_f64()))
275 .collect();
276
277 if evaluated.len() < 2 {
278 return None;
279 }
280
281 let variance = evaluated.iter().map(|f| (f - mean).powi(2)).sum::<f64>()
282 / (evaluated.len() - 1) as f64;
283 Some(variance.sqrt())
284 }
285
286 pub fn diversity(&self) -> f64 {
288 if self.len() < 2 {
289 return 0.0;
290 }
291
292 let mut total_distance = 0.0;
293 let mut count = 0;
294
295 for i in 0..self.len() {
296 for j in (i + 1)..self.len() {
297 total_distance += self.individuals[i]
298 .genome
299 .distance(&self.individuals[j].genome);
300 count += 1;
301 }
302 }
303
304 if count == 0 {
305 0.0
306 } else {
307 total_distance / count as f64
308 }
309 }
310}
311
312#[cfg(feature = "parallel")]
314impl<G, F> Population<G, F>
315where
316 G: EvolutionaryGenome + Send + Sync,
317 F: FitnessValue + Send,
318{
319 pub fn evaluate_parallel<Fit>(&mut self, fitness: &Fit)
321 where
322 Fit: Fitness<Genome = G, Value = F> + Sync,
323 {
324 self.individuals
325 .par_iter_mut()
326 .filter(|i| !i.is_evaluated())
327 .for_each(|individual| {
328 let f = fitness.evaluate(&individual.genome);
329 individual.set_fitness(f);
330 });
331 }
332}
333
334#[cfg(not(feature = "parallel"))]
336impl<G, F> Population<G, F>
337where
338 G: EvolutionaryGenome,
339 F: FitnessValue,
340{
341 pub fn evaluate_parallel<Fit>(&mut self, fitness: &Fit)
345 where
346 Fit: Fitness<Genome = G, Value = F>,
347 {
348 self.evaluate(fitness);
349 }
350}
351
352impl<G, F> Default for Population<G, F>
353where
354 G: EvolutionaryGenome,
355 F: FitnessValue,
356{
357 fn default() -> Self {
358 Self::new()
359 }
360}
361
362impl<G, F> std::ops::Index<usize> for Population<G, F>
363where
364 G: EvolutionaryGenome,
365 F: FitnessValue,
366{
367 type Output = Individual<G, F>;
368
369 fn index(&self, index: usize) -> &Self::Output {
370 &self.individuals[index]
371 }
372}
373
374impl<G, F> std::ops::IndexMut<usize> for Population<G, F>
375where
376 G: EvolutionaryGenome,
377 F: FitnessValue,
378{
379 fn index_mut(&mut self, index: usize) -> &mut Self::Output {
380 &mut self.individuals[index]
381 }
382}
383
384impl<G, F> IntoIterator for Population<G, F>
385where
386 G: EvolutionaryGenome,
387 F: FitnessValue,
388{
389 type Item = Individual<G, F>;
390 type IntoIter = std::vec::IntoIter<Individual<G, F>>;
391
392 fn into_iter(self) -> Self::IntoIter {
393 self.individuals.into_iter()
394 }
395}
396
397impl<G, F> FromIterator<Individual<G, F>> for Population<G, F>
398where
399 G: EvolutionaryGenome,
400 F: FitnessValue,
401{
402 fn from_iter<I: IntoIterator<Item = Individual<G, F>>>(iter: I) -> Self {
403 Self::from_individuals(iter.into_iter().collect())
404 }
405}
406
407#[cfg(test)]
408mod tests {
409 use super::*;
410 use crate::fitness::benchmarks::Sphere;
411 use crate::fitness::traits::ParetoFitness;
412 use crate::genome::real_vector::RealVector;
413
414 fn create_test_population() -> Population<RealVector> {
415 let individuals = vec![
416 Individual::with_fitness(RealVector::new(vec![1.0]), 10.0),
417 Individual::with_fitness(RealVector::new(vec![2.0]), 20.0),
418 Individual::with_fitness(RealVector::new(vec![3.0]), 30.0),
419 Individual::with_fitness(RealVector::new(vec![4.0]), 40.0),
420 Individual::with_fitness(RealVector::new(vec![5.0]), 50.0),
421 ];
422 Population::from_individuals(individuals)
423 }
424
425 #[test]
426 fn test_population_new() {
427 let pop: Population<RealVector> = Population::new();
428 assert!(pop.is_empty());
429 assert_eq!(pop.generation(), 0);
430 }
431
432 #[test]
433 fn test_population_random() {
434 let mut rng = rand::thread_rng();
435 let bounds = MultiBounds::symmetric(5.0, 3);
436 let pop: Population<RealVector> = Population::random(10, &bounds, &mut rng);
437
438 assert_eq!(pop.len(), 10);
439 assert!(!pop.all_evaluated());
440 }
441
442 #[test]
443 fn test_population_best_worst() {
444 let pop = create_test_population();
445
446 let best = pop.best().unwrap();
447 assert_eq!(best.fitness_f64(), 50.0);
448
449 let worst = pop.worst().unwrap();
450 assert_eq!(worst.fitness_f64(), 10.0);
451 }
452
453 #[test]
454 fn test_best_ignores_nan_fitness() {
455 let mut individuals = vec![
461 Individual::with_fitness(RealVector::new(vec![1.0]), 10.0),
462 Individual::with_fitness(RealVector::new(vec![3.0]), 30.0),
463 Individual::with_fitness(RealVector::new(vec![2.0]), 20.0),
464 ];
465 let mut nan_ind = Individual::new(RealVector::new(vec![9.0]));
468 nan_ind.fitness = Some(f64::NAN);
469 individuals.push(nan_ind);
470
471 let pop = Population::from_individuals(individuals);
472 assert_eq!(pop.best().unwrap().fitness_f64(), 30.0);
473 assert!(pop.worst().unwrap().fitness_f64().is_nan());
477 }
478
479 #[test]
480 fn test_best_worst_sort_use_is_better_than_for_pareto() {
481 let mut good = ParetoFitness::new(vec![0.0, 0.0]);
489 good.rank = 0;
490 good.crowding_distance = f64::INFINITY;
491
492 let mut bad = ParetoFitness::new(vec![9.0, 9.0]);
493 bad.rank = 50;
494 bad.crowding_distance = f64::INFINITY;
495
496 assert_eq!(good.to_f64(), bad.to_f64()); let individuals = vec![
500 Individual::with_fitness(RealVector::new(vec![0.0]), good.clone()),
501 Individual::with_fitness(RealVector::new(vec![1.0]), bad.clone()),
502 ];
503 let mut pop: Population<RealVector, ParetoFitness> =
504 Population::from_individuals(individuals);
505
506 assert_eq!(pop.best().unwrap().fitness.as_ref().unwrap().rank, 0);
507 assert_eq!(pop.worst().unwrap().fitness.as_ref().unwrap().rank, 50);
508
509 pop.sort_by_fitness();
510 assert_eq!(pop[0].fitness.as_ref().unwrap().rank, 0); assert_eq!(pop[1].fitness.as_ref().unwrap().rank, 50);
512 }
513
514 #[test]
515 fn test_population_sort_by_fitness() {
516 let mut pop = create_test_population();
517 pop.sort_by_fitness();
518
519 let fitnesses: Vec<f64> = pop.iter().map(|i| i.fitness_f64()).collect();
520 assert_eq!(fitnesses, vec![50.0, 40.0, 30.0, 20.0, 10.0]);
521 }
522
523 #[test]
524 fn test_population_truncate_to_best() {
525 let mut pop = create_test_population();
526 pop.truncate_to_best(3);
527
528 assert_eq!(pop.len(), 3);
529 let fitnesses: Vec<f64> = pop.iter().map(|i| i.fitness_f64()).collect();
530 assert_eq!(fitnesses, vec![50.0, 40.0, 30.0]);
531 }
532
533 #[test]
534 fn test_population_mean_fitness() {
535 let pop = create_test_population();
536 let mean = pop.mean_fitness().unwrap();
537 assert_eq!(mean, 30.0); }
539
540 #[test]
541 fn test_population_fitness_std() {
542 let pop = create_test_population();
543 let std = pop.fitness_std().unwrap();
544 assert!((std - 15.81).abs() < 0.1);
548 }
549
550 #[test]
551 fn test_population_evaluate() {
552 let mut rng = rand::thread_rng();
553 let bounds = MultiBounds::symmetric(5.0, 3);
554 let mut pop: Population<RealVector> = Population::random(5, &bounds, &mut rng);
555
556 let fitness = Sphere::new(3);
557 pop.evaluate(&fitness);
558
559 assert!(pop.all_evaluated());
560 assert_eq!(pop.count_evaluated(), 5);
561 }
562
563 #[test]
564 fn test_population_evaluate_parallel() {
565 let mut rng = rand::thread_rng();
566 let bounds = MultiBounds::symmetric(5.0, 3);
567 let mut pop: Population<RealVector> = Population::random(100, &bounds, &mut rng);
568
569 let fitness = Sphere::new(3);
570 pop.evaluate_parallel(&fitness);
571
572 assert!(pop.all_evaluated());
573 assert_eq!(pop.count_evaluated(), 100);
574 }
575
576 #[test]
577 fn test_population_generation() {
578 let mut pop = create_test_population();
579 assert_eq!(pop.generation(), 0);
580
581 pop.increment_generation();
582 assert_eq!(pop.generation(), 1);
583
584 pop.set_generation(100);
585 assert_eq!(pop.generation(), 100);
586 }
587
588 #[test]
589 fn test_population_push_pop() {
590 let mut pop: Population<RealVector> = Population::new();
591
592 pop.push(Individual::with_fitness(RealVector::new(vec![1.0]), 10.0));
593 assert_eq!(pop.len(), 1);
594
595 let ind = pop.pop().unwrap();
596 assert_eq!(ind.fitness_f64(), 10.0);
597 assert!(pop.is_empty());
598 }
599
600 #[test]
601 fn test_population_indexing() {
602 let pop = create_test_population();
603 assert_eq!(pop[0].fitness_f64(), 10.0);
604 assert_eq!(pop[4].fitness_f64(), 50.0);
605 }
606
607 #[test]
608 fn test_population_as_selection_pool() {
609 let pop = create_test_population();
610 let pool = pop.as_selection_pool();
611
612 assert_eq!(pool.len(), 5);
613 assert_eq!(pool[0].1, 10.0);
614 assert_eq!(pool[4].1, 50.0);
615 }
616
617 #[test]
618 fn test_population_diversity() {
619 let individuals = vec![
620 Individual::with_fitness(RealVector::new(vec![0.0, 0.0]), 1.0),
621 Individual::with_fitness(RealVector::new(vec![1.0, 0.0]), 1.0),
622 Individual::with_fitness(RealVector::new(vec![0.0, 1.0]), 1.0),
623 ];
624 let pop = Population::from_individuals(individuals);
625
626 let diversity = pop.diversity();
627 assert!(diversity > 1.0 && diversity < 1.2);
629 }
630
631 #[test]
632 fn test_population_from_iterator() {
633 let individuals = vec![
634 Individual::with_fitness(RealVector::new(vec![1.0]), 10.0),
635 Individual::with_fitness(RealVector::new(vec![2.0]), 20.0),
636 ];
637 let pop: Population<RealVector> = individuals.into_iter().collect();
638
639 assert_eq!(pop.len(), 2);
640 }
641
642 #[test]
643 fn test_population_into_iterator() {
644 let pop = create_test_population();
645 let individuals: Vec<_> = pop.into_iter().collect();
646
647 assert_eq!(individuals.len(), 5);
648 }
649}