use std::time::Instant;
use jobsteal::make_pool;
use individual::{Individual, IndividualWrapper};
use population::Population;
#[derive(Debug,Clone)]
pub enum SimulationType {
EndIteration(u32),
EndFitness(f64),
EndFactor(f64),
}
pub struct Simulation<T: Individual + Send + Sync> {
pub type_of_simulation: SimulationType,
pub num_of_threads: usize,
pub habitat: Vec<Population<T>>,
pub total_time_in_ms: f64,
pub simulation_result: SimulationResult<T>,
pub share_fittest: bool,
pub num_of_global_fittest: usize,
pub output_every: u32,
pub output_every_counter: u32,
pub share_every: u32,
pub share_counter: u32
}
#[derive(Clone)]
pub struct SimulationResult<T: Individual + Send + Sync> {
pub improvement_factor: f64,
pub original_fitness: f64,
pub fittest: Vec<IndividualWrapper<T>>,
pub iteration_counter: u32
}
impl<T: Individual + Send + Sync + Clone> Simulation<T> {
pub fn run(&mut self) {
let start_time = Instant::now();
for population in &mut self.habitat {
population.calculate_fitness();
}
let mut iteration_counter = 0;
let mut pool = make_pool(self.num_of_threads).unwrap();
self.simulation_result = SimulationResult {
improvement_factor: 0.0,
original_fitness: self.habitat[0].population[0].fitness,
fittest: vec![self.habitat[0].population[0].clone()],
iteration_counter: 0
};
info!("original_fitness: {}", self.simulation_result.original_fitness);
match self.type_of_simulation {
SimulationType::EndIteration(end_iteration) => {
for _ in 0..end_iteration {
pool.scope(|scope|
for population in &mut self.habitat {
scope.submit(move || { population.run_body() });
});
self.update_results();
};
self.simulation_result.iteration_counter = end_iteration;
}
SimulationType::EndFactor(end_factor) => {
loop {
iteration_counter += 1;
pool.scope(|scope|
for population in &mut self.habitat {
scope.submit(move || { population.run_body() });
});
self.update_results();
if self.simulation_result.improvement_factor <= end_factor {
break;
}
};
self.simulation_result.iteration_counter = iteration_counter;
}
SimulationType::EndFitness(end_fitness) => {
loop {
iteration_counter += 1;
pool.scope(|scope|
for population in &mut self.habitat {
scope.submit(move || { population.run_body() });
});
self.update_results();
if self.simulation_result.fittest[0].fitness <= end_fitness {
break;
}
};
self.simulation_result.iteration_counter = iteration_counter;
}
}
let elapsed = start_time.elapsed();
self.total_time_in_ms = elapsed.as_secs() as f64 * 1000.0 + elapsed.subsec_nanos() as f64 / 1000_000.0;
}
pub fn print_fitness(&self) {
for wrapper in &self.simulation_result.fittest {
info!("fitness: {}, num_of_mutations: {}, population: {}",
wrapper.fitness, wrapper.num_of_mutations, wrapper.id);
}
}
fn update_results(&mut self) {
let mut new_fittest_found = false;
self.output_every_counter += 1;
for population in &mut self.habitat {
if population.population[0].fitness < self.simulation_result.fittest[0].fitness {
new_fittest_found = true;
self.simulation_result.fittest.insert(0, population.population[0].clone());
self.simulation_result.fittest.truncate(self.num_of_global_fittest);
population.fitness_counter += 1;
if self.output_every_counter >= self.output_every {
info!("new fittest: fitness: {}, population id: {}, counter: {}", population.population[0].fitness,population.id,
population.fitness_counter);
self.output_every_counter = 0
}
population.population[0].individual.new_fittest_found();
}
}
self.share_counter += 1;
if self.share_fittest && new_fittest_found && (self.share_counter >= self.share_every) {
for population in &mut self.habitat {
population.population[0] = self.simulation_result.fittest[0].clone();
}
self.share_counter = 0;
}
self.simulation_result.improvement_factor =
self.simulation_result.fittest[0].fitness /
self.simulation_result.original_fitness;
}
}