calco 0.1.0

Generic interface to work with genetic algorithms.
Documentation
extern crate rand;
use self::rand::Rng;

extern crate random_wheel;
use self::random_wheel::RandomWheel;

use super::config::Config;
use mutable::Mutable;
use reproducible::Reproducible;
use evaluable::Evaluable;
// use probaselection::ProbaSelection;

/*// put that somewhere else
impl<T: Clone + Sized> ProbaSelection<T> for RandomWheel<T> {

    fn push(&self, proba: f32, data: T) {

        self.push(proba, data);
    }

    fn pop(&self) -> Option<T> {

        self.pop()
    }
}*/

pub struct Universe<T: Clone + Mutable + Reproducible + Evaluable> {

    population: RandomWheel<T>,
    generation: u32,
    settings: Config
}

impl<T: Clone + Mutable + Reproducible + Evaluable> Universe<T> {

    /// create new populate universe
    pub fn from_pop(config: Config, pop: Vec<T>) -> Universe<T> {

        match config.check() {
            Err(mess) => panic!(mess),
            Ok(_) => { }
        }

        let tores = if config.pop_max >= pop.len() {
            config.pop_max - pop.len()
        } else {
            panic!("{} is greater than population max!", pop.len());
        };

        let mut tmp_pop = RandomWheel::from_vec(pop);
        tmp_pop.reserve(tores);

        Universe{
            population: tmp_pop,
            generation: 0,
            settings: config
        }
    }

    /// call the evaluate method of each individual of the population
    pub fn evaluate(&mut self) {

        for &mut (ref mut proba, ref mut ind) in self.population.iter_mut() {
            *proba = ind.evaluate();
        }
        self.population.compute_proba_sum();
    }

    /// for each individual in the population, check if it will mutate.
    /// then it call mutate on each.
    pub fn mutate(&mut self) {

        for &mut (_, ref mut ind) in self.population.iter_mut() {

            if rand::thread_rng().gen_range(0., 1.) < self.settings.mutate_ratio {
                ind.mutate();
            }
        }
    }

    /// will choose two individuals in the population and call the reproduce
    /// method of the first with the second in parameter.
    /// Put the new childrens in a new population (don't evaluate them).
    /// It will keep the first half of the precedent population
    /// by fitness-proportinal-popping or minus if the new population
    /// exceed population_max value.
    pub fn reproduce(&mut self) {

        // TO DO ?!?
        // implementation of trait Iterator then call .next() infinitly
        // .take(nb_generations)

        if self.population.len() < 2 {
            panic!("Population does not contain enought individual (< 2)!");
        }

        let mut new_pop = RandomWheel::with_capacity(self.settings.pop_max);
        let pop_len = self.population.len();

        for _ in 0..(pop_len / 2) {

            let father_opt = self.population.pop();
            match (&father_opt, self.population.peek()) {

                (&Some((_, ref father)), Some((_, ref mother))) => {

                    for child in father.reproduce_with(mother) {

                        if new_pop.len() < self.settings.pop_max {
                            new_pop.push(1.0, child);
                        }
                    }
                },
                _ => break
            };

            // re-push father poped previously
            // (to have different father and mother)
            match father_opt {
                Some((proba, indi)) => self.population.push(proba, indi),
                None => { }
            };
        }

        let toadd = if new_pop.len() < self.population.len() {
            self.population.len() - new_pop.len()
        } else { 0 };

        // DON'T PUSH OTHER INDIVIDUALS THAN THE PREVIOUSLY SELECTED ?!?
        for _ in 0..toadd {
            match self.population.pop() {
                Some((_, indi)) => new_pop.push(1.0, indi),
                None => break
            }
        }

        self.population = new_pop;
        self.generation += 1;
    }
}