rust_monster/ga/
ga_simple.rs

1// TODO: COPYRIGHT, USE & AUTHORS
2use super::ga_core::{GAConfig, GAFactory, GAFlags, GeneticAlgorithm, GASolution};
3use super::ga_population::GAPopulation;
4use super::ga_random::{GARandomCtx, GASeed};
5
6// Simple Genetic Algorithm Config
7#[derive(Copy, Clone, Default, Debug)]
8// TODO: RUST DOCS! 
9pub struct SimpleGeneticAlgorithmCfg
10{
11    pub d_seed : GASeed,
12    pub pconv  : f32,
13    pub is_min : bool,
14
15    // GAConfig Trait
16    pub max_generations         : i32, 
17    pub flags                   : GAFlags, 
18    pub probability_crossover   : f32,
19    pub probability_mutation    : f32,
20
21    // Simple GA
22    pub elitism : bool,
23}
24impl GAConfig for SimpleGeneticAlgorithmCfg
25{
26    fn flags(&self) -> GAFlags
27    {
28        self.flags
29    }
30    fn max_generations(&self) -> i32
31    {
32        self.max_generations
33    }
34    fn probability_crossover(&self) -> f32
35    {
36        self.probability_crossover
37    }
38    fn probability_mutation(&self) -> f32
39    {
40        self.probability_mutation 
41    }
42}
43impl SimpleGeneticAlgorithmCfg
44{
45    fn elitism(&self) -> bool
46    {
47        self.elitism
48    }
49}
50
51/// Simple Genetic Algorithm 
52///
53/// A basic implementation of a Genetic Algorithm.
54///
55/// This genetic algorithm is the 'simple' genetic algorithm that Goldberg describes 
56/// in his book. It uses non-overlapping populations. When you create a simple genetic 
57/// algorithm, you must specify either an individual or a population of individuals. 
58/// The new genetic algorithm will clone the individual(s) that you specify to make 
59/// its own population. You can change most of the genetic algorithm behaviors after 
60/// creation and during the course of the evolution.
61///
62/// The simple genetic algorithm creates an initial population by cloning the individual 
63/// or population you pass when you create it. Each generation the algorithm creates 
64/// an entirely new population of individuals by selecting from the previous population 
65/// then mating to produce the new offspring for the new population. This process continues 
66/// until the stopping criteria are met (determined by the terminator).
67///
68/// Elitism is optional. By default, elitism is on, meaning that the best individual 
69/// from each generation is carried over to the next generation.
70///
71pub struct SimpleGeneticAlgorithm<T: GASolution>
72{
73  current_generation : i32, 
74  config : SimpleGeneticAlgorithmCfg,
75  population : GAPopulation<T>,
76  rng_ctx : GARandomCtx,
77}
78impl<T: GASolution> SimpleGeneticAlgorithm<T>
79{
80    // TODO: Document this -new- pattern and others from the
81    // pattern GitHub
82    pub fn new(cfg: SimpleGeneticAlgorithmCfg,
83               factory: Option<&mut GAFactory<T>>,
84               population: Option<GAPopulation<T>>) -> SimpleGeneticAlgorithm<T>
85    {
86        let p : GAPopulation<T>;
87        match factory
88        {
89            Some(f) => {
90                p = f.initial_population();
91            },
92            None => {
93                match population
94                {
95                    Some(p_) =>
96                    {
97                        p = p_;
98                    },
99                    None =>
100                    {
101                        panic!("Simple Genetic Algorithm - either factory or population need to be provided");
102                    }
103                }
104            }
105        }
106
107        //TODO: Some sort of generator for the name of the rng would be good
108        SimpleGeneticAlgorithm { current_generation: 0, config : cfg, population : p, rng_ctx : GARandomCtx::from_seed(cfg.d_seed, String::from("")) }
109    }
110}
111impl<T: GASolution> GeneticAlgorithm<T> for SimpleGeneticAlgorithm <T>
112{
113    fn config(&mut self) -> &GAConfig
114    {
115        &self.config
116    }
117
118    fn population(&mut self) -> &mut GAPopulation<T>
119    {
120        &mut self.population
121    }
122
123    fn initialize_internal(&mut self)
124    {
125        assert!(self.population().size() > 0);
126        self.population.sort();
127    }
128
129    fn step_internal(&mut self) -> i32
130    {
131        let mut new_individuals : Vec<T> = vec![];
132
133        // Create new individuals 
134        for _ in 0..self.population.size()
135        {
136            let ind = self.population.select();
137            let mut new_ind = ind.clone();
138            if self.rng_ctx.test_value(self.config.probability_crossover())
139            {
140                let ind_2 = self.population.select();
141                new_ind = ind.crossover(ind_2);
142            }
143
144            new_ind.mutate(self.config.probability_mutation());
145
146            new_individuals.push(new_ind);
147        }
148
149        // Evaluate the new population
150//        self.population.swap(new_individuals);
151        self.population.evaluate();
152        self.population.sort();
153
154        let best_old_individual = self.population.best().clone();
155
156        if self.config.elitism()
157        {
158            if best_old_individual.fitness() > self.population.worst().fitness()
159            {
160                // population.swap_individual(best_old_individual, ...)
161            }
162        }
163
164        self.current_generation += 1;
165        self.current_generation
166    }
167
168    fn done_internal(&mut self) -> bool
169    {
170        self.current_generation >= self.config().max_generations() 
171    }
172}