1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
use rand::{Rng};
use rand::distributions::{IndependentSample, Range};
use serde::de::{DeserializeOwned};
use serde::ser::Serialize;
use std;

use context::*;
use math::*;
use neuro::{MultilayeredNetwork};
use problem::*;
use result::*;
use settings::*;


/// Trait representing functionality required to evolve an individual for optimization
/// and NN tuning tasks.
///
/// Contains functions to retrieve genes or neural network from an individual and get/set its fitness.
#[allow(dead_code, unused_variables)]
pub trait Individual{
    /// Creates a new individual with empty set of genes and NAN fitness.
    fn new() -> Self;
    /// Initializes an individual by allocating random vector of genes using Gaussian distribution.
    ///
    /// # Arguments
    /// * `size` - number of genes.
    /// * `rng` - mutable reference to the external RNG.
    fn init<R: Rng>(&mut self, size: usize, &mut R);
    /// Return current fitness value.
    fn get_fitness(&self) -> f32;
    /// Update fitness value.
    fn set_fitness(&mut self, fitness: f32);
    /// Return vector of genes.
    fn to_vec(&self) -> Option<&[f32]>;
    /// Return mutable vector of genes.
    fn to_vec_mut(&mut self) -> Option<&mut Vec<f32>>;
    /// Return `MultilayeredNetwork` object with weights assigned according to the genes' values.
    fn to_net(&mut self) -> Option<&MultilayeredNetwork> {None}
    /// Return mutable `MultilayeredNetwork` object with weights assigned according to the genes' values.
    fn to_net_mut(&mut self) -> Option<&mut MultilayeredNetwork> {None}
    /// Update individual's `MultilayeredNetwork` object and update genes according to the network weights.
    ///
    /// # Arguments:
    /// * `net` - neural network to update from.
    fn set_net(&mut self, net: MultilayeredNetwork) {}
}

/// Represents real-coded individual with genes encoded as vector of real numbers.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct RealCodedIndividual {
    /// Collection of individual genes.
    pub genes: Vec<f32>,
    /// Fitness value associated with the individual.
    pub fitness: f32,
}

impl RealCodedIndividual {
}

impl Individual for RealCodedIndividual{
    fn new() -> Self {
        RealCodedIndividual{genes: Vec::new(), fitness: std::f32::NAN}
    }

    fn init<R: Rng>(&mut self, size: usize, mut rng: &mut R) {
        self.genes = rand_vector_std_gauss(size as usize, rng);
    }

    fn get_fitness(&self) -> f32 {
        self.fitness
    }

    fn set_fitness(&mut self, fitness: f32) {
        self.fitness = fitness;
    }

    fn to_vec(&self) -> Option<&[f32]> {
        Some(&self.genes)
    }

    fn to_vec_mut(&mut self) -> Option<&mut Vec<f32>> {
        Some(&mut self.genes)
    }
}

//======================================================================

/// Trait for an evolutionary algorithm.
/// Defines functions which are typical for running a common EA.
/// To implement a trait a function `breed` should be implemented.
pub trait EA<'a, P> where P: Problem {
    type IndType: Individual+Clone+Serialize+DeserializeOwned;

    fn run_multiple(&mut self, settings: EASettings, run_num: u32) -> Result<EAResultMultiple<Self::IndType>, ()> {
        let run_ress = (0..run_num).into_iter()
                            .map(|_| {
                                self.run(settings.clone()).expect("Error during GA run").clone()
                            })
                            .collect::<Vec<EAResult<Self::IndType>>>();
        let res = EAResultMultiple::new(&run_ress);
        Ok(res)
    }

    /// "Main" function for the EA which runs a cycle for an evolutionary search.
    ///
    /// # Arguments:
    /// * `ctx` - `EAContext` object containing information regarding current EA run.
    /// * `problem` - reference to the `Problem` trait which specifies an objective function.
    /// * `gen_count` - number of generations (iterations) for search.
    fn run_with_context(&self, ctx: &mut EAContext<Self::IndType>, problem: &P, gen_count: u32) { // -> Result<Rc<&'a EAResult<T>>, ()> {
        // let mut ctx = self.get_context_mut();
        // println!("run_with_context");
        for t in 0..gen_count {
            // evaluation
            // println!("evaluation");
            self.evaluate(ctx, problem);

            // selection
            // println!("selection");
            let sel_inds = self.select(ctx);

            // crossover
            // println!("crossover");
            let mut children: Vec<Self::IndType> = Vec::with_capacity(ctx.settings.pop_size as usize);
            self.breed(ctx, &sel_inds,  &mut children);

            // next gen
            // println!("next_generation");
            self.next_generation(ctx, &children);

            println!("> {} : {:?}", t, ctx.fitness);
            println!(" Best fitness at generation {} : {}\n", t, min(&ctx.fitness));
        }
        // Ok(Rc::new(&ctx.result))
    }

    /// Function to evaluate current population for the given `problem`. In result of evaluation
    ///   fitness for every individual is updated as well as statistics regarding mean, min, max
    ///   fitness values.
    ///
    /// # Arguments:
    /// * `ctx` - `EAContext` object containing information regarding current EA run.
    /// * `problem` - reference to the `Problem` trait which specifies an objective function.
    fn evaluate(&self, ctx: &mut EAContext<Self::IndType>, problem: &P) {
        // ctx.fitness = evaluate(&mut ctx.population, problem, &mut ctx.result);
        let cur_result = &mut ctx.result;
        let popul = &mut ctx.population;

        ctx.fitness = popul.iter_mut().map(|ref mut ind| {
                let f = problem.compute(ind as &mut Self::IndType);
                // println!(".");
                ind.set_fitness(f);
                f
            }).collect::<Vec<f32>>();
        let fits = &ctx.fitness;
        // println!("{:?}", fits);
        if cur_result.first_hit_fe_count == 0 {
            for k in 0..fits.len() {
                if problem.is_solution(fits[k]) {
                    cur_result.first_hit_fe_count = cur_result.fe_count + (k+1) as u32;
                    break;
                }
            }
        }

        cur_result.avg_fitness.push(mean(&fits));
        cur_result.max_fitness.push(max(&fits));

        let last_min_fitness = min(&fits);
        cur_result.min_fitness.push(last_min_fitness);
        if cur_result.best.get_fitness().is_nan() || (cur_result.best.get_fitness() > last_min_fitness) {
            let idx = (&fits).iter().position(|&x| x == last_min_fitness).expect("Min fitness is not found");
            cur_result.best = popul[idx].clone();
            cur_result.best_fe_count = cur_result.fe_count + (idx+1) as u32;
        }
        cur_result.best.set_fitness(last_min_fitness);
        cur_result.fe_count += fits.len() as u32;
    }

    /// Function to select individuals for breeding. Updates given `ctx`.
    ///
    /// # Arguments:
    /// * `ctx` - `EAContext` object containing information regarding current EA run.
    fn select(&self, ctx: &mut EAContext<Self::IndType>) -> Vec<usize> {
        select_tournament(&ctx.fitness, ctx.settings.tour_size, &mut ctx.rng)
    }

    /// Function to prepare population for the next generation. By default copies children obtained
    ///   in result of `breed` to the `ctx.population`.
    ///
    /// # Arguments:
    /// * `ctx` - `EAContext` object containing information regarding current EA run.
    /// * `children` - reference to the vector of children individuals which should
    ///                get to the next generation.
    fn next_generation(&self, ctx: &mut EAContext<Self::IndType>, children: &Vec<Self::IndType>) {
        ctx.population = Vec::with_capacity(children.len());
        for k in 0..children.len() {
            ctx.population.push(children[k].clone());
        }
        // ctx.population = children.iter().map(|ref c| c.clone()).collect::<Vec<T>>();
        ctx.population.truncate(ctx.settings.pop_size as usize);
    }

    /// Function to create children individuals using current context and selected individuals.
    ///
    /// # Arguments:
    /// * `ctx` - `EAContext` object containing information regarding current EA run.
    /// * `sel_inds` - vector of indices of individuals from `ctx.population` selected for breeding.
    /// * `children` - reference to the container to store resulting children individuals.
    fn breed(&self, ctx: &mut EAContext<Self::IndType>, sel_inds: &Vec<usize>, children: &mut Vec<Self::IndType>);

    /// Run evolutionary algorithm and return `EAResult` object.
    ///
    /// # Arguments:
    /// * `settings` - `EASettings` object.
    // fn run(&mut self, settings: EASettings) -> Result<&EAResult<Self::IndType>, ()>;
    fn run(&mut self, settings: EASettings) -> Result<&EAResult<Self::IndType>, ()>;
}

/// Creates population of given size. Uses `problem.get_random_individual` to generate a
/// new individual
///
/// # Arguments:
/// * `pop_size` - population size.
/// * `ind_size` - default size (number of genes) of individuals.
/// * `rng` - reference to pre-initialized RNG.
/// * `problem` - reference to the object implementing `Problem` trait.
pub fn create_population<T: Individual, P: Problem, R: Rng+Sized>(pop_size: u32, ind_size: u32, mut rng: &mut R, problem: &P) -> Vec<T> {
    println!("Creating population of {} individuals having size {}", pop_size, ind_size);
    let mut res = Vec::with_capacity(pop_size as usize);
    for _ in 0..pop_size {
        res.push(problem.get_random_individual::<T, R>(ind_size as usize, rng));
    }
    res
}

/// Implementation of the [tournament selection](https://en.wikipedia.org/wiki/Tournament_selection).
///
/// # Arguments:
/// * `fits` - fitness values. i-th element should be equal to the fitness of the i-th individual
///            in population.
/// * `tour_size` - tournament size. The bigger the higher is the selective pressure (more strict
///                 selection). Minimal acceptable value is 2.
/// * `rng` - reference to pre-initialized RNG.
fn select_tournament(fits: &Vec<f32>, tour_size: u32, mut rng: &mut Rng) -> Vec<usize> {
    let range = Range::new(0, fits.len());
    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.
    for _ in 0..fits.len() {
        let tour_inds = (0..tour_size).map(|_| range.ind_sample(&mut rng)).collect::<Vec<usize>>();
        let winner = tour_inds.iter().fold(tour_inds[0], |w_idx, &k|
            if fits[w_idx] < fits[k] {w_idx}
            else {k}
        );
        sel_inds.push(winner);
    }
    sel_inds
}

/// Get copy of the individual having the best fitness value.
///
/// # Arguments:
/// * `popul` - vector of individuals to select from.
pub fn get_best_individual<T: Individual+Clone>(popul: &Vec<T>) -> T {
    let min_fitness = popul.into_iter().fold(std::f32::MAX, |s, ref ind| if s < ind.get_fitness() {s} else {ind.get_fitness()});
    let idx = popul.into_iter().position(|ref x| x.get_fitness() == min_fitness).expect("Min fitness is not found");
    popul[idx].clone()
}

//========================================================

#[allow(unused_imports)]
#[cfg(test)]
mod test {
    use rand;

    use ea::*;
    use math::*;

    #[test]
    fn test_tournament_selection() {
        const IND_COUNT: usize = 100;
        const TRIAL_COUNT: u32 = 100;

        let mut prev_mean = 0.5f32;   // avg value in a random array in [0; 1].
        let mut rng = rand::thread_rng();
        for t in 2..10 {
            let mut cur_mean = 0f32;
            // compute mean fitness for the selected population for TRIAL_COUNT trials.
            for _ in 0..TRIAL_COUNT {
                let fitness_vals = rand_vector(IND_COUNT, &mut rng);
                let sel_inds = select_tournament(&fitness_vals, t, &mut rng);
                let tmp_mean = sel_inds.iter().fold(0f32, |s, &idx| s + fitness_vals[idx]) / IND_COUNT as f32;
                cur_mean += tmp_mean;
            }
            cur_mean /= TRIAL_COUNT as f32;
            // bigger tournaments should give smaller average fitness in selected population.
            assert!(cur_mean < prev_mean);
            prev_mean = cur_mean;
        }

    }
}