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;
pub struct Universe<T: Clone + Mutable + Reproducible + Evaluable> {
population: RandomWheel<T>,
generation: u32,
settings: Config
}
impl<T: Clone + Mutable + Reproducible + Evaluable> Universe<T> {
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
}
}
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();
}
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();
}
}
}
pub fn reproduce(&mut self) {
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
};
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 };
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;
}
}