genetic_algorithm_traits/population.rs
1use crate::individual::Individual;
2use crate::utils::argsort;
3
4/// The container for your individuals in a genetic algorithm.
5pub trait Population<'a> {
6 /// The Type of individuals your population should consist of.
7 type Individual: Individual<'a> + 'a;
8 /// The iteratore type if you iterate over your individuals. It depends on the data container you use
9 /// to store individuals in your implementation of `Population`.
10 type IndividualCollection: Iterator<Item = &'a <Self as Population<'a>>::Individual>;
11 /// Given the pool of current individuals, compute the fitness of your individuals to solve the
12 /// problem at hand.
13 ///
14 /// # Arguments
15 ///
16 /// * `cost_data` - The data neccessary to assess the fitness of an individual.
17 ///
18 fn fitnesses(
19 &'a self,
20 cost_data: &'a <<Self as Population<'a>>::Individual as Individual<'a>>::IndividualCost,
21 ) -> Vec<(f64, &Self::Individual)> {
22 self.iter()
23 .map(|solution| (solution.fitness(cost_data), solution))
24 .collect()
25 }
26 /// Get the n fittest individuals in your population.
27 ///
28 /// # Arguments
29 ///
30 /// * `n` - The number of individuals you would like to get
31 /// * `cost_data` - The cost data structure your individuals need to compute
32 /// their fitness.
33 ///
34 fn get_n_fittest(
35 &'a self,
36 n: usize,
37 cost_data: &'a <<Self as Population<'a>>::Individual as Individual<'a>>::IndividualCost,
38 ) -> Vec<Self::Individual> {
39 let individuals_by_fitness = self.fitnesses(cost_data);
40 argsort(
41 &individuals_by_fitness
42 .iter()
43 .map(|(fitness, _)| *fitness)
44 .collect::<Vec<f64>>(),
45 )
46 .iter()
47 .take(n)
48 .map(|idx| individuals_by_fitness[*idx].1.clone())
49 .collect()
50 }
51 /// Get the n fittest individuals in your population as population routes object. This is typically used
52 /// to select the top n inidividuals, before continuing to evolve the routes further.
53 ///
54 /// # Arguments
55 ///
56 /// * `n` - The number of individuals you would like to have.
57 /// * `cost_data` - The cost data structure your indivudals need to compute their fitness.
58 ///
59 fn get_fittest_population(
60 &'a self,
61 n: usize,
62 cost_data: &'a <<Self as Population<'a>>::Individual as Individual<'a>>::IndividualCost,
63 ) -> Self;
64 /// Evolve your population.
65 ///
66 /// The evolution consists of the following stages:
67 /// 1) `crossover` between all 1,...,n indivials. Each individual will not be `crossover`ed
68 /// with itself, but as the crossover is not neccessarily symmetric `indivdual_a.crossover(indivual_b)` as well
69 /// as `individual_b.crossover(individual_a)` will be computed.
70 /// 2) `mutate` is applied to all individuals.
71 ///
72 /// The difference to the `evolve_individuals` function is that this needs to be implemented in the struct
73 /// that implements this trait because how the population is constructed depends on the representation you
74 /// choose to use. Please use the `evolve_individuals`-function to get the updated inviduals. You could use an
75 /// iterator or implement the `From<Vec<Individuals>>`-trait.
76 ///
77 /// # Arguments
78 ///
79 /// * `mutate_prob` - The probabilty of an inviduals beeing mutated. Is applied via `individuals.mutate`.
80 fn evolve(&self, mutate_prob: f32) -> Self;
81 /// Evolve your population.
82 ///
83 /// The evolution consists of the following stages:
84 /// 1) `crossover` between all 1,...,n indivials. Each individual will not be `crossover`ed
85 /// with itself, but as the crossover is not neccessarily symmetric `indivdual_a.crossover(indivual_b)` as well
86 /// as `individual_b.crossover(individual_a)` will be computed.
87 /// 2) `mutate` is applied to all individuals.
88 ///
89 /// # Arguments
90 ///
91 /// * `mutate_prob` - The probabilty of an inviduals beeing mutated. Is applied via `individuals.mutate`.
92 // TODO: I only use `Vec` here because the type of the iterator is too complicated.
93 // this creates overhead and should be optimized
94 fn evolve_individuals(&'a self, mutate_prob: f32) -> Vec<Self::Individual> {
95 self
96 // for all individuals 1 .. n crossover with all other individuals excluding the same individual.
97 .iter()
98 .enumerate()
99 .map(|(idx, main_individual)| {
100 self.iter()
101 // Skip the individual itself, e.g. don't crossover the individual with itself.
102 .enumerate()
103 .filter(move |&(individual_index, _)| individual_index != idx)
104 .map(|(_, individual)| {
105 main_individual.crossover(individual).mutate(mutate_prob)
106 })
107 })
108 .flatten()
109 .chain(self.iter().cloned())
110 .collect()
111 }
112 /// Iterate over the individuals in your population.
113 fn iter(&'a self) -> Self::IndividualCollection;
114}