revonet/
ea.rs

1use rand::{Rng};
2use rand::distributions::{IndependentSample, Range};
3use serde::de::{DeserializeOwned};
4use serde::ser::Serialize;
5use std;
6
7use context::*;
8use math::*;
9use neuro::{MultilayeredNetwork};
10use problem::*;
11use result::*;
12use settings::*;
13
14
15/// Trait representing functionality required to evolve an individual for optimization
16/// and NN tuning tasks.
17///
18/// Contains functions to retrieve genes or neural network from an individual and get/set its fitness.
19#[allow(dead_code, unused_variables)]
20pub trait Individual{
21    /// Creates a new individual with empty set of genes and NAN fitness.
22    fn new() -> Self;
23    /// Initializes an individual by allocating random vector of genes using Gaussian distribution.
24    ///
25    /// # Arguments
26    /// * `size` - number of genes.
27    /// * `rng` - mutable reference to the external RNG.
28    fn init<R: Rng>(&mut self, size: usize, &mut R);
29    /// Return current fitness value.
30    fn get_fitness(&self) -> f32;
31    /// Update fitness value.
32    fn set_fitness(&mut self, fitness: f32);
33    /// Return vector of genes.
34    fn to_vec(&self) -> Option<&[f32]>;
35    /// Return mutable vector of genes.
36    fn to_vec_mut(&mut self) -> Option<&mut Vec<f32>>;
37    /// Return `MultilayeredNetwork` object with weights assigned according to the genes' values.
38    fn to_net(&mut self) -> Option<&MultilayeredNetwork> {None}
39    /// Return mutable `MultilayeredNetwork` object with weights assigned according to the genes' values.
40    fn to_net_mut(&mut self) -> Option<&mut MultilayeredNetwork> {None}
41    /// Update individual's `MultilayeredNetwork` object and update genes according to the network weights.
42    ///
43    /// # Arguments:
44    /// * `net` - neural network to update from.
45    fn set_net(&mut self, net: MultilayeredNetwork) {}
46}
47
48/// Represents real-coded individual with genes encoded as vector of real numbers.
49#[derive(Clone, Debug, Deserialize, Serialize)]
50pub struct RealCodedIndividual {
51    /// Collection of individual genes.
52    pub genes: Vec<f32>,
53    /// Fitness value associated with the individual.
54    pub fitness: f32,
55}
56
57impl RealCodedIndividual {
58}
59
60impl Individual for RealCodedIndividual{
61    fn new() -> Self {
62        RealCodedIndividual{genes: Vec::new(), fitness: std::f32::NAN}
63    }
64
65    fn init<R: Rng>(&mut self, size: usize, mut rng: &mut R) {
66        self.genes = rand_vector_std_gauss(size as usize, rng);
67    }
68
69    fn get_fitness(&self) -> f32 {
70        self.fitness
71    }
72
73    fn set_fitness(&mut self, fitness: f32) {
74        self.fitness = fitness;
75    }
76
77    fn to_vec(&self) -> Option<&[f32]> {
78        Some(&self.genes)
79    }
80
81    fn to_vec_mut(&mut self) -> Option<&mut Vec<f32>> {
82        Some(&mut self.genes)
83    }
84}
85
86//======================================================================
87
88/// Trait for an evolutionary algorithm.
89/// Defines functions which are typical for running a common EA.
90/// To implement a trait a function `breed` should be implemented.
91pub trait EA<'a, P> where P: Problem {
92    type IndType: Individual+Clone+Serialize+DeserializeOwned;
93
94    fn run_multiple(&mut self, settings: EASettings, run_num: u32) -> Result<EAResultMultiple<Self::IndType>, ()> {
95        let run_ress = (0..run_num).into_iter()
96                            .map(|_| {
97                                self.run(settings.clone()).expect("Error during GA run").clone()
98                            })
99                            .collect::<Vec<EAResult<Self::IndType>>>();
100        let res = EAResultMultiple::new(&run_ress);
101        Ok(res)
102    }
103
104    /// "Main" function for the EA which runs a cycle for an evolutionary search.
105    ///
106    /// # Arguments:
107    /// * `ctx` - `EAContext` object containing information regarding current EA run.
108    /// * `problem` - reference to the `Problem` trait which specifies an objective function.
109    /// * `gen_count` - number of generations (iterations) for search.
110    fn run_with_context(&self, ctx: &mut EAContext<Self::IndType>, problem: &P, gen_count: u32) { // -> Result<Rc<&'a EAResult<T>>, ()> {
111        // let mut ctx = self.get_context_mut();
112        // println!("run_with_context");
113        for t in 0..gen_count {
114            // evaluation
115            // println!("evaluation");
116            self.evaluate(ctx, problem);
117
118            // selection
119            // println!("selection");
120            let sel_inds = self.select(ctx);
121
122            // crossover
123            // println!("crossover");
124            let mut children: Vec<Self::IndType> = Vec::with_capacity(ctx.settings.pop_size as usize);
125            self.breed(ctx, &sel_inds,  &mut children);
126
127            // next gen
128            // println!("next_generation");
129            self.next_generation(ctx, &children);
130
131            println!("> {} : {:?}", t, ctx.fitness);
132            println!(" Best fitness at generation {} : {}\n", t, min(&ctx.fitness));
133        }
134        // Ok(Rc::new(&ctx.result))
135    }
136
137    /// Function to evaluate current population for the given `problem`. In result of evaluation
138    ///   fitness for every individual is updated as well as statistics regarding mean, min, max
139    ///   fitness values.
140    ///
141    /// # Arguments:
142    /// * `ctx` - `EAContext` object containing information regarding current EA run.
143    /// * `problem` - reference to the `Problem` trait which specifies an objective function.
144    fn evaluate(&self, ctx: &mut EAContext<Self::IndType>, problem: &P) {
145        // ctx.fitness = evaluate(&mut ctx.population, problem, &mut ctx.result);
146        let cur_result = &mut ctx.result;
147        let popul = &mut ctx.population;
148
149        ctx.fitness = popul.iter_mut().map(|ref mut ind| {
150                let f = problem.compute(ind as &mut Self::IndType);
151                // println!(".");
152                ind.set_fitness(f);
153                f
154            }).collect::<Vec<f32>>();
155        let fits = &ctx.fitness;
156        // println!("{:?}", fits);
157        if cur_result.first_hit_fe_count == 0 {
158            for k in 0..fits.len() {
159                if problem.is_solution(fits[k]) {
160                    cur_result.first_hit_fe_count = cur_result.fe_count + (k+1) as u32;
161                    break;
162                }
163            }
164        }
165
166        cur_result.avg_fitness.push(mean(&fits));
167        cur_result.max_fitness.push(max(&fits));
168
169        let last_min_fitness = min(&fits);
170        cur_result.min_fitness.push(last_min_fitness);
171        if cur_result.best.get_fitness().is_nan() || (cur_result.best.get_fitness() > last_min_fitness) {
172            let idx = (&fits).iter().position(|&x| x == last_min_fitness).expect("Min fitness is not found");
173            cur_result.best = popul[idx].clone();
174            cur_result.best_fe_count = cur_result.fe_count + (idx+1) as u32;
175        }
176        cur_result.best.set_fitness(last_min_fitness);
177        cur_result.fe_count += fits.len() as u32;
178    }
179
180    /// Function to select individuals for breeding. Updates given `ctx`.
181    ///
182    /// # Arguments:
183    /// * `ctx` - `EAContext` object containing information regarding current EA run.
184    fn select(&self, ctx: &mut EAContext<Self::IndType>) -> Vec<usize> {
185        select_tournament(&ctx.fitness, ctx.settings.tour_size, &mut ctx.rng)
186    }
187
188    /// Function to prepare population for the next generation. By default copies children obtained
189    ///   in result of `breed` to the `ctx.population`.
190    ///
191    /// # Arguments:
192    /// * `ctx` - `EAContext` object containing information regarding current EA run.
193    /// * `children` - reference to the vector of children individuals which should
194    ///                get to the next generation.
195    fn next_generation(&self, ctx: &mut EAContext<Self::IndType>, children: &Vec<Self::IndType>) {
196        ctx.population = Vec::with_capacity(children.len());
197        for k in 0..children.len() {
198            ctx.population.push(children[k].clone());
199        }
200        // ctx.population = children.iter().map(|ref c| c.clone()).collect::<Vec<T>>();
201        ctx.population.truncate(ctx.settings.pop_size as usize);
202    }
203
204    /// Function to create children individuals using current context and selected individuals.
205    ///
206    /// # Arguments:
207    /// * `ctx` - `EAContext` object containing information regarding current EA run.
208    /// * `sel_inds` - vector of indices of individuals from `ctx.population` selected for breeding.
209    /// * `children` - reference to the container to store resulting children individuals.
210    fn breed(&self, ctx: &mut EAContext<Self::IndType>, sel_inds: &Vec<usize>, children: &mut Vec<Self::IndType>);
211
212    /// Run evolutionary algorithm and return `EAResult` object.
213    ///
214    /// # Arguments:
215    /// * `settings` - `EASettings` object.
216    // fn run(&mut self, settings: EASettings) -> Result<&EAResult<Self::IndType>, ()>;
217    fn run(&mut self, settings: EASettings) -> Result<&EAResult<Self::IndType>, ()>;
218}
219
220/// Creates population of given size. Uses `problem.get_random_individual` to generate a
221/// new individual
222///
223/// # Arguments:
224/// * `pop_size` - population size.
225/// * `ind_size` - default size (number of genes) of individuals.
226/// * `rng` - reference to pre-initialized RNG.
227/// * `problem` - reference to the object implementing `Problem` trait.
228pub fn create_population<T: Individual, P: Problem, R: Rng+Sized>(pop_size: u32, ind_size: u32, mut rng: &mut R, problem: &P) -> Vec<T> {
229    println!("Creating population of {} individuals having size {}", pop_size, ind_size);
230    let mut res = Vec::with_capacity(pop_size as usize);
231    for _ in 0..pop_size {
232        res.push(problem.get_random_individual::<T, R>(ind_size as usize, rng));
233    }
234    res
235}
236
237/// Implementation of the [tournament selection](https://en.wikipedia.org/wiki/Tournament_selection).
238///
239/// # Arguments:
240/// * `fits` - fitness values. i-th element should be equal to the fitness of the i-th individual
241///            in population.
242/// * `tour_size` - tournament size. The bigger the higher is the selective pressure (more strict
243///                 selection). Minimal acceptable value is 2.
244/// * `rng` - reference to pre-initialized RNG.
245fn select_tournament(fits: &Vec<f32>, tour_size: u32, mut rng: &mut Rng) -> Vec<usize> {
246    let range = Range::new(0, fits.len());
247    let mut sel_inds: Vec<usize> = Vec::with_capacity(fits.len());  // vector of indices of selected inds. +1 in case of elite RealCodedindividual is used.
248    for _ in 0..fits.len() {
249        let tour_inds = (0..tour_size).map(|_| range.ind_sample(&mut rng)).collect::<Vec<usize>>();
250        let winner = tour_inds.iter().fold(tour_inds[0], |w_idx, &k|
251            if fits[w_idx] < fits[k] {w_idx}
252            else {k}
253        );
254        sel_inds.push(winner);
255    }
256    sel_inds
257}
258
259/// Get copy of the individual having the best fitness value.
260///
261/// # Arguments:
262/// * `popul` - vector of individuals to select from.
263pub fn get_best_individual<T: Individual+Clone>(popul: &Vec<T>) -> T {
264    let min_fitness = popul.into_iter().fold(std::f32::MAX, |s, ref ind| if s < ind.get_fitness() {s} else {ind.get_fitness()});
265    let idx = popul.into_iter().position(|ref x| x.get_fitness() == min_fitness).expect("Min fitness is not found");
266    popul[idx].clone()
267}
268
269//========================================================
270
271#[allow(unused_imports)]
272#[cfg(test)]
273mod test {
274    use rand;
275
276    use ea::*;
277    use math::*;
278
279    #[test]
280    fn test_tournament_selection() {
281        const IND_COUNT: usize = 100;
282        const TRIAL_COUNT: u32 = 100;
283
284        let mut prev_mean = 0.5f32;   // avg value in a random array in [0; 1].
285        let mut rng = rand::thread_rng();
286        for t in 2..10 {
287            let mut cur_mean = 0f32;
288            // compute mean fitness for the selected population for TRIAL_COUNT trials.
289            for _ in 0..TRIAL_COUNT {
290                let fitness_vals = rand_vector(IND_COUNT, &mut rng);
291                let sel_inds = select_tournament(&fitness_vals, t, &mut rng);
292                let tmp_mean = sel_inds.iter().fold(0f32, |s, &idx| s + fitness_vals[idx]) / IND_COUNT as f32;
293                cur_mean += tmp_mean;
294            }
295            cur_mean /= TRIAL_COUNT as f32;
296            // bigger tournaments should give smaller average fitness in selected population.
297            assert!(cur_mean < prev_mean);
298            prev_mean = cur_mean;
299        }
300
301    }
302}