jeans/
lib.rs

1#![warn(missing_docs)]
2#![warn(missing_doc_code_examples)]
3
4/*! This is a crate for implementing genetic algorithms. Specifically, this is for algorithms whose
5    solutions can be represented as a vector of floating point values.
6!*/
7
8use rand::Rng;
9use rand::seq::SliceRandom;
10
11pub mod functions;
12
13/// A settings object for storing all of the settings we might care about for a GA.
14///
15/// You should usually instantiate this using the default method. All member variables of this struct
16/// are public, which makes editing this easy. In most cases, simply reassign the member variables:
17/// ```
18/// let mut set = jeans::Settings::default();
19/// set.elitism = false;
20/// ```
21/// The most notable exception is for the `fitness_function` field. To set that, you have to use a
22/// special method:
23/// ```
24/// let mut set = jeans::Settings::default();
25/// set.set_fitness_function(| x: Vec<f64> | x[0] + x[1])
26/// ```
27pub struct Settings {
28    /// The size of the population
29    pub population_size: u32,
30    /// The number of generations
31    pub number_of_generations: u32,
32    /// The crossover probability
33    pub crossover_probability: f64,
34    /// The probability of mutation
35    pub mutation_probability: f64,
36    /// A `bool` indicating whether or not code should run in verbose mode
37    pub verbose: bool,
38    /// A `bool` indicating whether or not to implement elitism
39    pub elitism: bool,
40    /// The fraction of each generation that should be carried forward via elitism
41    pub elitism_fraction: f64,
42    /// Whether the package should maximize fitness (`true`) or minimize fitness (`false`)
43    pub maximize_fitness: bool,
44    /// The number of dimensions of the problem space
45    pub number_of_dimensions: u32,
46    /// The upper bounds for each dimension of the problem space
47    pub upper_bound: Vec<f64>,
48    /// The lower bounds for each dimension of the problem space
49    pub lower_bound: Vec<f64>,
50    /// The fitness function used to evaluate how good solutions are
51    pub fitness_function: Box<dyn FnMut(Vec<f64>) -> f64>,
52}
53
54/// Default values for all settings
55impl Default for Settings {
56    fn default() -> Self {
57        Self {
58            fitness_function: Box::new(crate::functions::summation),
59            population_size: 100,
60            number_of_generations: 100,
61            crossover_probability: 0.8,
62            mutation_probability: 0.1,
63            verbose: true,
64            elitism: true,
65            elitism_fraction: 0.2,
66            maximize_fitness: true,
67            number_of_dimensions: 2,
68            upper_bound: vec![ 1.0,  1.0],
69            lower_bound: vec![-1.0, -1.0],
70        }
71    }
72}
73
74impl Settings {
75    /// This functions allows you to set the fitness function
76    ///
77    /// For instance, you can use one of hte built-in function found [here](functions/index.html#functions):
78    /// ```
79    /// let mut set = jeans::Settings::default();
80    /// set.set_fitness_function(jeans::functions::sphere);
81    /// ```
82    /// Or you can use a lambda to implement your own:
83    /// ```
84    /// let mut set = jeans::Settings::default();
85    /// set.set_fitness_function(| x | x[0] + x[1]);
86    /// ```
87    /// Or you can define and use a completely new function
88    /// ```
89    /// fn fitness_whole_pizza(x: Vec<f64>) -> f64 {
90    ///     let mut fx = 0f64;
91    ///     for i in 0..x.len() {
92    ///         fx *= x[i]
93    ///     }
94    ///     fx
95    /// }
96    /// let mut set = jeans::Settings::default();
97    /// set.set_fitness_function(fitness_whole_pizza);
98    /// ```
99    pub fn set_fitness_function<F: 'static + FnMut(Vec<f64>) -> f64>(&mut self, f: F) {
100        self.fitness_function = Box::new(f);
101    }
102}
103
104
105/// This is an optimizer object. It does the actual heavy lifting.
106///
107/// In order to use the optimizer you first need to create a [`Settings`](struct.Settings.html) struct. That can then be
108/// passed to an `Optimizer` struct, and the `solve` method can be called to actually solve the problem.
109/// ```
110/// let mut set = jeans::Settings::default();
111/// let mut opt = jeans::Optimizer::new(set);
112/// opt.solve();
113/// ```
114/// In order to implement and use custom fitness functions, please see [`Settings::set_fitness_function`](struct.Settings.html#impl)
115pub struct Optimizer {
116    settings: Settings,
117    current_population: Population,
118    new_population: Population,
119    best_fitness: f64,
120    best_representation: Vec<f64>
121}
122
123impl Optimizer {
124
125    /// This method enables the creation of a new `Optimizer` struct given a [`Settings`](struct.Settings.html) struct
126    pub fn new(mut settings: Settings) -> Self {
127        Self {
128            current_population: Population::new(&mut settings),
129            new_population: Population::empty(),
130            settings: settings,
131            best_fitness: -f64::INFINITY,
132            best_representation: vec![]
133        }
134    }
135
136    /// This method is called to begin the solving process.
137    pub fn solve(&mut self) {
138        for _ in 0..self.settings.number_of_generations {
139            self.iterate();
140        }
141    }
142
143    /// This method is called to generate a report of the solving process.
144    pub fn report(&self) {
145        println!("{}", self.best_fitness);
146    }
147
148    fn check_bounds(&self, x: Individual) -> bool {
149        let mut state = true;
150        for i in 0..self.settings.number_of_dimensions as usize{
151            if x.representation[i] < self.settings.lower_bound[i] ||
152                x.representation[i] > self.settings.upper_bound[i] {
153                state = false;
154            }
155        }
156        state
157    }
158
159    fn iterate(&mut self) {
160        // Elitism
161        self.implement_elitism();
162
163        // Crossover
164        self.implement_crossover();
165
166        // Mutation
167        self.implement_mutation();
168
169        //Fill in the rest
170        self.fill_population();
171
172        // Get best
173        self.current_population = self.new_population.copy();
174        if self.current_population.get_best() > self.best_fitness {
175            self.best_fitness = self.current_population.get_best();
176        }
177
178        // Sort
179        self.current_population.sort();
180        self.new_population = Population::empty();
181        self.report();
182    }
183
184    fn implement_elitism(&mut self) {
185        // Elitism
186        if self.settings.elitism {
187            let number_of_elites: f64 = self.settings.elitism_fraction * self.settings.population_size as f64;
188            for i in (self.settings.population_size as usize - number_of_elites as usize)..self.settings.population_size as usize{
189                self.new_population.individuals.push(self.current_population.individuals[i].clone())
190            }
191        }
192    }
193
194    fn implement_crossover(&mut self) {
195        let number_of_crosses: f64 = self.settings.crossover_probability * self.settings.population_size as f64;
196        for i in (self.settings.population_size as usize - number_of_crosses as usize)..self.settings.population_size as usize{
197            let thingone = self.current_population.get_random();
198            let thingtwo = self.current_population.get_random();
199            self.new_population.individuals.push(thingone.cross(thingtwo))
200        }
201    }
202
203    fn implement_mutation(&mut self) {
204        for i in 0..self.settings.population_size as usize {
205            let mut rng = rand::thread_rng();
206            if rng.gen::<f64>() < self.settings.mutation_probability {
207                self.new_population.individuals.push(self.current_population.individuals[i].mutate())
208            }
209        }
210    }
211
212    fn fill_population(&mut self) {
213        while self.new_population.individuals.len() < self.settings.population_size as usize {
214            self.new_population.individuals.push(Individual::new(&mut self.settings));
215        }
216    }
217}
218
219
220//////////////////////////////////////////
221//// Population
222//////////////////////////////////////////
223struct Population {
224    individuals: Vec<Individual>,
225}
226
227impl Population {
228    fn new(mut settings: &mut Settings) -> Self {
229        let mut pop = vec![];
230        for _ in 0..settings.population_size {
231            pop.push(Individual::new(&mut settings))
232        }
233        Self {
234            individuals: pop,
235        }
236    }
237
238    fn empty() -> Self {
239        Self {
240            individuals: vec![],
241        }
242    }
243
244    fn copy(&self) -> Self {
245        let mut pop = Population::empty();
246        for indi in &self.individuals {
247            pop.individuals.push((*indi).clone());
248        }
249        pop
250    }
251
252    fn get_best(&self) -> f64 {
253        let mut best_fitness = -f64::INFINITY;
254        for i in 0..(*self).individuals.len() {
255            if self.individuals[i].fitness > best_fitness {
256                best_fitness = self.individuals[i].fitness;
257            }
258        }
259        best_fitness
260    }
261
262    fn get_mean(&self) {
263
264    }
265
266    fn get_std(&self) {
267
268    }
269
270    fn get_random(&mut self) -> Individual {
271        let option = self.individuals.choose_mut(&mut rand::thread_rng());
272        match option {
273            Some(x) => (*x).clone(),
274            None => self.individuals[self.individuals.len()-1].clone()
275        }
276
277    }
278
279    fn sort(&mut self) {
280        self.individuals.sort_unstable_by(|x, y| x.fitness.partial_cmp(&y.fitness).unwrap());
281    }
282}
283
284
285#[cfg(test)]
286mod population_tests {
287    use super::*;
288
289    #[test]
290    fn basic_inst() {
291        let x = Population::new(&mut Settings::default());
292    }
293
294    #[test]
295    fn empty_inst() {
296        let x = Population::empty();
297    }
298
299    #[test]
300    fn sort_check() {
301        let mut x = Population::new(&mut Settings::default());
302        x.sort();
303    }
304
305    #[test]
306    fn stat_check() {
307        let x = Population::new(&mut Settings::default());
308        x.get_best();
309        x.get_mean();
310        x.get_std();
311    }
312}
313
314/// This structure is for an individual, essentially representative of a single solution
315pub struct Individual {
316    representation: Vec<f64>,
317    fitness: f64,
318}
319
320impl Individual {
321    /// This creates a new individual
322    fn new(sets: &mut crate::Settings) -> Self {
323        let mut rng = rand::thread_rng();
324        let mut v: Vec<f64> = vec![];
325        for i in 0..sets.number_of_dimensions as usize {
326            v.push(rng.gen_range(sets.lower_bound[i], sets.upper_bound[i]));
327        }
328        Self {
329            representation: v.clone(),
330            fitness: (sets.fitness_function)(v.clone())
331        }
332    }
333
334    /// This clones the Individual
335    fn clone(&self) -> Self {
336        Self {
337            representation: self.representation.clone(),
338            fitness: self.fitness,
339        }
340    }
341
342    /// This returns a mutated version of the Individual
343    fn mutate(&self) -> Self {
344        self.clone()
345    }
346
347    /// Crossover
348    fn cross(&self, other_individual: Self) -> Self {
349        let mut v = vec![];
350        let mut rng = rand::thread_rng();
351        for i in 0..self.representation.len() {
352            if rng.gen::<f64>() < 0.5 {
353                v.push(self.representation[i])
354            } else {
355                v.push(other_individual.representation[i])
356            }
357        }
358
359        Self {
360            representation: v,
361            fitness: 0.0
362        }
363
364    }
365}
366
367
368#[cfg(test)]
369mod individual_tests {
370    use super::*;
371
372    #[test]
373    fn basic_inst() {
374        let x = Individual {
375            representation: vec![0.0, 0.0],
376            fitness: 0.0
377        };
378    }
379
380    #[test]
381    fn settings_inst() {
382        let x = Individual::new(&mut crate::Settings::default());
383    }
384
385    #[test]
386    fn clone_check() {
387        let x = Individual::new(&mut crate::Settings::default());
388        let y = x.clone();
389    }
390
391    #[test]
392    fn mutate_check() {
393        let x = Individual::new(&mut crate::Settings::default());
394        let y = x.mutate();
395    }
396}