Skip to main content

optlib/genetic/
mod.rs

1//! The module with genetic algorithm implementation.
2//!
3//! # Terms
4//! * "chromosomes" are points in the search space.
5//! Usually chromosome is single value or vector of values.
6//! * "Fitness" is value of goal function value in genetic algorithm.
7//! * "Generation" is iteration number of genetic algorithm.
8//! * "Individual" is agent in genetic algorithm (point in the search space and value of goal
9//! function).
10
11pub mod creation;
12pub mod cross;
13pub mod mutation;
14pub mod pairing;
15pub mod pre_birth;
16pub mod selection;
17
18use std::cmp::Ordering;
19use std::f64;
20use std::ops;
21use std::slice;
22
23use crate::tools::logging::Logger;
24use crate::tools::stopchecker::StopChecker;
25use crate::{Agent, AgentsState, AlgorithmState, Goal, IterativeOptimizer, Optimizer, Solution};
26
27/// Struct for single point (agent) in the search space
28///
29/// `T` - type of a point in the search space for goal function (chromosomes).
30#[derive(Debug)]
31pub struct Individual<T> {
32    /// Point in the search space.
33    chromosomes: T,
34
35    /// Value of goal function for the point in the search space.
36    fitness: f64,
37
38    /// True if individual will pass to text generation.
39    alive: bool,
40}
41
42impl<T: Clone> Clone for Individual<T> {
43    fn clone(&self) -> Individual<T> {
44        Individual {
45            chromosomes: self.chromosomes.clone(),
46            fitness: self.fitness,
47            alive: self.alive,
48        }
49    }
50}
51
52impl<T> Agent<T> for Individual<T> {
53    fn get_goal(&self) -> f64 {
54        self.fitness
55    }
56
57    fn get_parameter(&self) -> &T {
58        &self.chromosomes
59    }
60}
61
62impl<T> Individual<T> {
63    /// Return reference to chromosomes.
64    pub fn get_chromosomes(&self) -> &T {
65        &self.chromosomes
66    }
67
68    /// Return value of the goal function.
69    pub fn get_fitness(&self) -> f64 {
70        self.fitness
71    }
72
73    /// Returns true if the individual go into the next generation and false otherwise.
74    pub fn is_alive(&self) -> bool {
75        self.alive
76    }
77
78    /// Kill individual. The individual do not go into next generation.
79    pub fn kill(&mut self) {
80        self.alive = false;
81    }
82}
83
84/// Stores all individuals for current generation.
85///
86/// `T` - type of a point in the search space for goal function (chromosomes).
87pub struct Population<'a, T> {
88    // Trait object for goal function.
89    goal: Box<dyn Goal<T> + 'a>,
90
91    individuals: Vec<Individual<T>>,
92
93    // The best individual for current generation.
94    best_individual: Option<Individual<T>>,
95
96    // The worst individual for current generation.
97    worst_individual: Option<Individual<T>>,
98
99    // Generation number.
100    iteration: usize,
101}
102
103impl<'a, T: Clone> Population<'a, T> {
104    /// Find new the best and the worst individuals
105    fn update_best_worst_individuals(&mut self) {
106        // Update the best individual
107        let best = self
108            .individuals
109            .iter()
110            .min_by(|ind_1, ind_2| self.individuals_min_cmp(ind_1, ind_2));
111
112        if let Some(ref individual) = best {
113            self.best_individual = Some((*individual).clone());
114        }
115
116        // Update the worst individual
117        let worst = self
118            .individuals
119            .iter()
120            .max_by(|ind_1, ind_2| self.individuals_max_cmp(ind_1, ind_2));
121
122        if let Some(ref individual) = worst {
123            self.worst_individual = Some((*individual).clone());
124        }
125    }
126}
127
128impl<'a, T: Clone> AgentsState<T> for Population<'a, T> {
129    type Agent = Individual<T>;
130
131    /// Returns vector with references to all agents
132    fn get_agents(&self) -> Vec<&Self::Agent> {
133        let mut agents: Vec<&Self::Agent> = Vec::with_capacity(self.len());
134        for individual in self.individuals.iter() {
135            agents.push(individual);
136        }
137
138        agents
139    }
140}
141
142impl<'a, T> Population<'a, T> {
143    /// Create new `Population` struct
144    /// # Parameters
145    /// * `goal` - trait object for goal function
146    fn new(goal: Box<dyn Goal<T> + 'a>) -> Self {
147        Population {
148            goal,
149            individuals: vec![],
150            best_individual: None,
151            worst_individual: None,
152            iteration: 0,
153        }
154    }
155
156    /// Remove all individuals and go to generation 0.
157    fn reset(&mut self) {
158        self.individuals.clear();
159        self.best_individual = None;
160        self.worst_individual = None;
161        self.iteration = 0;
162    }
163
164    /// Create new `Individual` struct with `chromosomes` and add it to population.
165    fn push(&mut self, chromosomes: T) {
166        let fitness = self.goal.get(&chromosomes);
167        let new_individual = Individual {
168            chromosomes,
169            fitness,
170            alive: true,
171        };
172
173        self.individuals.push(new_individual);
174    }
175
176    /// Create new individuals (`Individual` struct) for all items in `chromosomes_list` and add
177    /// them to population.
178    fn append(&mut self, chromosomes_list: Vec<T>) {
179        for chromosome in chromosomes_list {
180            self.push(chromosome);
181        }
182    }
183
184    /// Returns iterator for all individuals (`Individual` struct) in population.
185    pub fn iter(&self) -> slice::Iter<Individual<T>> {
186        self.individuals.iter()
187    }
188
189    /// Returns mut iterator for all individuals (`Individual` struct) in population.
190    pub fn iter_mut(&mut self) -> slice::IterMut<Individual<T>> {
191        self.individuals.iter_mut()
192    }
193
194    /// Returns iteration number (generation number).
195    pub fn get_iteration(&self) -> usize {
196        self.iteration
197    }
198
199    /// Return count of live individuals
200    pub fn len_alive(&self) -> usize {
201        self.individuals
202            .iter()
203            .filter(|individual| individual.is_alive())
204            .count()
205    }
206
207    /// Returns the best individual in the population if exists or None otherwise.
208    pub fn get_best(&self) -> &Option<Individual<T>> {
209        &self.best_individual
210    }
211
212    /// Returns the worst individual in the population if exists or None otherwise.
213    pub fn get_worst(&self) -> &Option<Individual<T>> {
214        &self.worst_individual
215    }
216
217    /// Returns count of the individuals in the population.
218    pub fn len(&self) -> usize {
219        self.individuals.len()
220    }
221
222    /// Function to find individual with minimal fitness.
223    ///
224    /// NaN fitness greater others.
225    fn individuals_min_cmp(
226        &self,
227        individual_1: &Individual<T>,
228        individual_2: &Individual<T>,
229    ) -> Ordering {
230        let goal_1 = individual_1.get_goal();
231        let goal_2 = individual_2.get_goal();
232
233        if goal_1.is_nan() && goal_2.is_nan() {
234            Ordering::Greater
235        } else if goal_1.is_nan() {
236            Ordering::Greater
237        } else if goal_2.is_nan() {
238            Ordering::Less
239        } else {
240            goal_1.partial_cmp(&goal_2).unwrap()
241        }
242    }
243
244    /// Function to find individual with maximal fitness.
245    ///
246    /// NaN fitness less others.
247    fn individuals_max_cmp(
248        &self,
249        individual_1: &Individual<T>,
250        individual_2: &Individual<T>,
251    ) -> Ordering {
252        let goal_1 = individual_1.get_goal();
253        let goal_2 = individual_2.get_goal();
254
255        if goal_1.is_nan() && goal_2.is_nan() {
256            Ordering::Less
257        } else if goal_1.is_nan() {
258            Ordering::Less
259        } else if goal_2.is_nan() {
260            Ordering::Greater
261        } else {
262            goal_1.partial_cmp(&goal_2).unwrap()
263        }
264    }
265
266    /// Switch to next iteration (generation)
267    fn next_iteration(&mut self) {
268        self.iteration += 1;
269    }
270
271    fn remove_dead(&mut self) {
272        self.individuals.retain(|individual| individual.is_alive());
273    }
274}
275
276/// Index trait implementation for Population
277impl<'a, T> ops::Index<usize> for Population<'a, T> {
278    type Output = Individual<T>;
279
280    fn index(&self, index: usize) -> &Individual<T> {
281        &self.individuals[index]
282    }
283}
284
285/// IndexMut trait implementation for Population
286impl<'a, T> ops::IndexMut<usize> for Population<'a, T> {
287    fn index_mut<'b>(&'b mut self, index: usize) -> &'b mut Individual<T> {
288        &mut self.individuals[index]
289    }
290}
291
292impl<'a, T: Clone> AlgorithmState<T> for Population<'a, T> {
293    fn get_best_solution(&self) -> Option<(T, f64)> {
294        match &self.best_individual {
295            None => None,
296            Some(individual) => Some((individual.chromosomes.clone(), individual.fitness)),
297        }
298    }
299
300    fn get_iteration(&self) -> usize {
301        self.iteration
302    }
303}
304
305/// The trait to create initial individuals for population.
306///
307/// `T` - type of a point in the search space for goal function (chromosomes).
308pub trait Creator<T> {
309    /// Must return vector of the chromosomes of a new individuals for population
310    fn create(&mut self) -> Vec<T>;
311}
312
313/// The trait with cross algorithm.
314///
315/// `T` - type of a point in the search space for goal function (chromosomes).
316pub trait Cross<T> {
317    /// The method accepts slice of references to parent chromosomes (`parents`),
318    /// must return vector of chromosomes of children. The children will be added to population
319    /// after mutation.
320    fn cross(&mut self, parents: &[&T]) -> Vec<T>;
321}
322
323/// The trait with mutation algorithm.
324///
325/// `T` - type of a point in the search space for goal function (chromosomes).
326pub trait Mutation<T> {
327    /// The method accepts reference to chromosomes of single individual and must return new
328    /// chromosomes (possibly modified). New individuals will be created with the chromosomes after
329    /// mutation.
330    fn mutation(&mut self, chromosomes: &T) -> T;
331}
332
333/// The trait may be used after mutation but before birth of the individuals.
334///
335/// `T` - type of a point in the search space for goal function (chromosomes).
336pub trait PreBirth<T> {
337    /// The method may modify chromosomes list before birth of the individuals.
338    fn pre_birth(&mut self, population: &Population<T>, new_chromosomes: &mut Vec<T>);
339}
340
341/// The trait with selection algorithm.
342///
343/// `T` - type of a point in the search space for goal function (chromosomes).
344pub trait Selection<T> {
345    /// The method kills bad individuals. The method must call `Individual::kill()` method for
346    /// individuals which will not go to next generation.
347    fn kill(&mut self, population: &mut Population<T>);
348}
349
350/// The trait to select individuals to pairing.
351///
352/// `T` - type of a point in the search space for goal function (chromosomes).
353pub trait Pairing<T> {
354    /// The method must select individuals to cross. Returns vector of vector with individuals
355    /// numbers in `population`. Selected individuals will parents for new children.
356    fn get_pairs(&mut self, population: &Population<T>) -> Vec<Vec<usize>>;
357}
358
359/// The main struct for an user. `GeneticOptimizer` implements `Optimizer` trait and keep all parts
360/// of genetic algorithm as trait objects: `Creator`, `Pairing`, `Cross`, `Mutation`, `Selection`,
361/// `StopChecker` and, if needed, `Logger`.
362/// The trait run genetic algorithm.
363///
364/// `T` - type of a point in the search space for goal function (chromosomes).
365pub struct GeneticOptimizer<'a, T> {
366    stop_checker: Box<dyn StopChecker<T> + 'a>,
367    creator: Box<dyn Creator<T> + 'a>,
368    pairing: Box<dyn Pairing<T> + 'a>,
369    cross: Box<dyn Cross<T> + 'a>,
370    mutation: Box<dyn Mutation<T> + 'a>,
371    selections: Vec<Box<dyn Selection<T> + 'a>>,
372    pre_births: Vec<Box<dyn PreBirth<T> + 'a>>,
373    loggers: Vec<Box<dyn Logger<T> + 'a>>,
374    population: Population<'a, T>,
375}
376
377impl<'a, T: Clone> GeneticOptimizer<'a, T> {
378    /// Create a new `GeneticOptimizer`.
379    pub fn new(
380        goal: Box<dyn Goal<T> + 'a>,
381        stop_checker: Box<dyn StopChecker<T> + 'a>,
382        creator: Box<dyn Creator<T> + 'a>,
383        pairing: Box<dyn Pairing<T> + 'a>,
384        cross: Box<dyn Cross<T> + 'a>,
385        mutation: Box<dyn Mutation<T> + 'a>,
386        selections: Vec<Box<dyn Selection<T> + 'a>>,
387        pre_births: Vec<Box<dyn PreBirth<T> + 'a>>,
388    ) -> GeneticOptimizer<'a, T> {
389        GeneticOptimizer {
390            creator,
391            stop_checker,
392            pairing,
393            cross,
394            mutation,
395            selections,
396            pre_births,
397            loggers: vec![],
398            population: Population::new(goal),
399        }
400    }
401
402    pub fn set_loggers(&mut self, loggers: Vec<Box<dyn Logger<T> + 'a>>) {
403        self.loggers = loggers;
404    }
405
406    /// Replace the trait object of pairing algorithm.
407    pub fn set_pairing(&mut self, pairing: Box<dyn Pairing<T>>) {
408        self.pairing = pairing;
409    }
410
411    /// Replace the trait object of cross algorithm.
412    pub fn set_cross(&mut self, cross: Box<dyn Cross<T>>) {
413        self.cross = cross;
414    }
415
416    /// Replace the trait object of mutation algorithm.
417    pub fn set_mutation(&mut self, mutation: Box<dyn Mutation<T>>) {
418        self.mutation = mutation;
419    }
420
421    /// Replace the trait object of selection algorithm.
422    pub fn set_selection(&mut self, selections: Vec<Box<dyn Selection<T>>>) {
423        self.selections = selections;
424    }
425
426    /// Replace the trait object of selection algorithm.
427    pub fn set_pre_birth(&mut self, pre_births: Vec<Box<dyn PreBirth<T>>>) {
428        self.pre_births = pre_births;
429    }
430
431    /// Replace the trait object of stop checker algorithm.
432    pub fn set_stop_checker(&mut self, stop_checker: Box<dyn StopChecker<T>>) {
433        self.stop_checker = stop_checker;
434    }
435
436    fn run_pairing(&mut self) -> Vec<T> {
437        let pairs: Vec<Vec<usize>> = self.pairing.get_pairs(&self.population);
438        let mut new_chromosomes: Vec<T> = Vec::with_capacity(pairs.len());
439
440        for pair in pairs {
441            let mut cross_chromosomes = Vec::with_capacity(pair.len());
442            for i in pair {
443                cross_chromosomes.push(self.population[i].get_chromosomes());
444            }
445
446            let mut child_chromosomes = self.cross.cross(&cross_chromosomes);
447            new_chromosomes.append(&mut child_chromosomes);
448        }
449
450        new_chromosomes
451    }
452}
453
454impl<'a, T: Clone> IterativeOptimizer<T> for GeneticOptimizer<'a, T> {
455    /// Do new iterations of genetic algorithm.
456    fn next_iterations(&mut self) -> Option<Solution<T>> {
457        for logger in &mut self.loggers {
458            logger.resume(&self.population);
459        }
460
461        while !self.stop_checker.can_stop(&self.population) {
462            // Pairing
463            let mut children_chromo_list = self.run_pairing();
464
465            // Mutation
466            let mut children_mutants: Vec<T> = children_chromo_list
467                .iter_mut()
468                .map(|chromo| self.mutation.mutation(chromo))
469                .collect();
470
471            // May be change new chromosomes vector before birth
472            for pre_birth in &mut self.pre_births {
473                pre_birth.pre_birth(&self.population, &mut children_mutants);
474            }
475
476            // Create new individuals by new chromosomes and add new individuals to population
477            self.population.append(children_mutants);
478
479            // Selection
480            for selection in &mut self.selections {
481                selection.kill(&mut self.population);
482            }
483
484            self.population.remove_dead();
485
486            self.population.update_best_worst_individuals();
487
488            self.population.next_iteration();
489
490            for logger in &mut self.loggers {
491                logger.next_iteration(&self.population);
492            }
493        }
494
495        for logger in &mut self.loggers {
496            logger.finish(&self.population);
497        }
498
499        match &self.population.best_individual {
500            None => None,
501            Some(individual) => Some((individual.chromosomes.clone(), individual.fitness)),
502        }
503    }
504}
505
506impl<'a, T: Clone> Optimizer<T> for GeneticOptimizer<'a, T> {
507    /// Run genetic algorithm
508    fn find_min(&mut self) -> Option<(T, f64)> {
509        self.population.reset();
510        let start_chromo_list = self.creator.create();
511
512        // Create individuals from chromosomes
513        self.population.append(start_chromo_list);
514
515        for logger in &mut self.loggers {
516            logger.start(&self.population);
517        }
518
519        self.next_iterations()
520    }
521}