darwin_rs/
population_builder.rs

1//! This module defines helper functions (builder pattern) to create a valid population.
2//!
3//! darwin-rs: evolutionary algorithms with Rust
4//!
5//! Written by Willi Kappler, Version 0.4 (2017.06.26)
6//!
7//! Repository: https://github.com/willi-kappler/darwin-rs
8//!
9//! License: MIT
10//!
11//! This library allows you to write evolutionary algorithms (EA) in Rust.
12//! Examples provided: TSP, Sudoku, Queens Problem, OCR
13//!
14//!
15
16use std;
17
18use individual::{Individual, IndividualWrapper};
19use population::Population;
20
21/// This is a helper struct in order to build (configure) a valid population.
22/// See builder pattern: https://en.wikipedia.org/wiki/Builder_pattern
23///
24/// Maybe use phantom types, see https://github.com/willi-kappler/darwin-rs/issues/9
25pub struct PopulationBuilder<T: Individual> {
26    /// The actual simulation
27    population: Population<T>,
28}
29
30error_chain! {
31    errors {
32        IndividualsTooLow
33        LimitEndTooLow
34    }
35}
36
37/// This implementation contains all the helper method to build (configure) a valid population.
38impl<T: Individual + Clone> PopulationBuilder<T> {
39    /// Start with this method, it must always be called as the first one.
40    /// It creates a default population with some dummy (but invalid) values.
41    pub fn new() -> PopulationBuilder<T> {
42        PopulationBuilder {
43            population: Population {
44                num_of_individuals: 0,
45                population: Vec::new(),
46                reset_limit: 0,
47                reset_limit_start: 1000,
48                reset_limit_end: 10000,
49                reset_limit_increment: 1000,
50                reset_counter: 0,
51                id: 1,
52                fitness_counter: 0
53            }
54        }
55    }
56
57    /// Sets the initial population provided inside a vector, length must be >= 3
58    pub fn initial_population(mut self, individuals: &[T]) -> PopulationBuilder<T> {
59        self.population.num_of_individuals = individuals.len() as u32;
60
61        for individual in individuals {
62            self.population.population.push(IndividualWrapper {
63                individual: (*individual).clone(),
64                fitness: std::f64::MAX,
65                num_of_mutations: 1,
66                id: self.population.id,
67            });
68        }
69
70        self
71    }
72
73    /// Configures the mutation rates (number of mutation runs) for all the individuals
74    /// in the population: The first individual will mutate once, the second will mutate twice,
75    /// the nth individual will Mutate n-times per iteration.
76    pub fn increasing_mutation_rate(mut self) -> PopulationBuilder<T> {
77        let mut mutation_rate = 1;
78
79        for wrapper in &mut self.population.population {
80            wrapper.num_of_mutations = mutation_rate;
81            mutation_rate += 1;
82        }
83
84        self
85    }
86
87    /// Configures the mutation rates (number of mutation runs) for all the individuals in the
88    /// population: Instead of a linear growing mutation rate like in the
89    /// `increasing_mutation_rate` function above this sets an exponention mutation rate for
90    /// all the individuals. The first individual will mutate base^1 times, the second will
91    /// mutate base^2 times, and nth will mutate base^n times per iteration.
92    pub fn increasing_exp_mutation_rate(mut self, base: f64) -> PopulationBuilder<T> {
93        let mut mutation_rate = 1;
94
95        for wrapper in &mut self.population.population {
96            wrapper.num_of_mutations = base.powi(mutation_rate).floor() as u32;
97            mutation_rate += 1;
98        }
99
100        self
101    }
102
103    /// Configures the mutation rates (number of mutation runs) for all the individuals in the
104    /// population: This allows to specify an arbitrary mutation scheme for each individual.
105    /// The number of rates must be equal to the number of individuals.
106    pub fn mutation_rate(mut self, mutation_rate: Vec<u32>) -> PopulationBuilder<T> {
107        // TODO: better error handling
108        assert!(self.population.population.len() == mutation_rate.len());
109
110        for (individual, mutation_rate) in self.population
111            .population
112            .iter_mut()
113            .zip(mutation_rate.into_iter()) {
114            individual.num_of_mutations = mutation_rate;
115        }
116
117        self
118    }
119
120    /// Configures the reset limit for the population. If reset_limit_end is greater than zero
121    /// then a reset counter is increased each iteration. If that counter is greater than the
122    /// limit, all individuals will be resetted, the limit will be increased by 1000 and the
123    /// counter is set back to zero. Default value for reset_limit_start is 1000.
124    pub fn reset_limit_start(mut self, reset_limit_start: u32) -> PopulationBuilder<T> {
125        self.population.reset_limit_start = reset_limit_start;
126        self.population.reset_limit = reset_limit_start;
127        self
128    }
129
130    /// Configures the end value for the reset_limit. If the reset_limit >= reset_limit_end
131    /// then the reset_limit will be resetted to the start value reset_limit_start.
132    /// Default value for reset_limit_end is 100000.
133    /// If reset_limit_end == 0 then the reset limit feature will be disabled.
134    pub fn reset_limit_end(mut self, reset_limit_end: u32) -> PopulationBuilder<T> {
135        self.population.reset_limit_end = reset_limit_end;
136        self
137    }
138
139    /// Configure the increment for the reset_limit. If the reset_limit is reached, its value
140    /// is incrementet by the amount of reset_limit_increment.
141    pub fn reset_limit_increment(mut self, reset_limit_increment: u32) -> PopulationBuilder<T> {
142        self.population.reset_limit_increment = reset_limit_increment;
143        self
144    }
145
146    /// Set the population id. Currently this is only used for statistics.
147    pub fn set_id(mut self, id: u32) -> PopulationBuilder<T> {
148        for individual in &mut self.population.population {
149            individual.id = id;
150        }
151
152        self.population.id = id;
153        self
154    }
155
156    /// This checks the configuration of the simulation and returns an PopError or Ok if no PopErrors
157    /// where found.
158    pub fn finalize(self) -> Result<Population<T>> {
159        match self.population {
160            Population { num_of_individuals: 0...2, ..} => {
161                Err(ErrorKind::IndividualsTooLow.into())
162            }
163            Population { reset_limit_start: start,
164                         reset_limit_end: end, ..} if (end > 0) && (start >= end) => {
165                Err(ErrorKind::LimitEndTooLow.into())
166            }
167            _ => Ok(self.population)
168        }
169    }
170}