From 6a215adc290533fdce062cadd40ef38708201f41 Mon Sep 17 00:00:00 2001 From: Claus Matzinger Date: Tue, 3 Jul 2018 09:40:13 +0200 Subject: [PATCH 1/5] seq WASM compatibility --- Cargo.toml | 2 +- src/sim/seq.rs | 23 ++++++----------------- 2 files changed, 7 insertions(+), 18 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 64faaba3..acef89b3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,5 +11,5 @@ license = "MIT/Apache-2.0" documentation = "https://docs.rs/rsgenetic/" [dependencies] -rand = "0.3" +rand = "^0.5" rayon = "1.0.0" diff --git a/src/sim/seq.rs b/src/sim/seq.rs index 5a48218b..65b30466 100644 --- a/src/sim/seq.rs +++ b/src/sim/seq.rs @@ -27,8 +27,10 @@ use super::*; use super::select::*; use super::iterlimit::*; use super::earlystopper::*; -use std::time::Instant; +use std::boxed::Box; use std::marker::PhantomData; +use rand::prng::XorShiftRng; + /// A sequential implementation of `::sim::Simulation`. /// The genetic algorithm is run in a single thread. @@ -42,7 +44,6 @@ where iter_limit: IterLimit, selector: Box>, earlystopper: Option>, - duration: Option, error: Option, phantom: PhantomData<&'a T>, } @@ -63,7 +64,6 @@ where iter_limit: IterLimit::new(100), selector: Box::new(MaximizeSelector::new(3)), earlystopper: None, - duration: Some(0), error: None, phantom: PhantomData::default(), }, @@ -71,7 +71,6 @@ where } fn step(&mut self) -> StepResult { - let time_start; if self.population.is_empty() { self.error = Some( @@ -88,8 +87,7 @@ where }; if !should_stop { - time_start = Instant::now(); - + let mut children: Vec; { // Perform selection @@ -120,15 +118,6 @@ where } self.iter_limit.inc(); - self.duration = match self.duration { - Some(x) => { - let elapsed = time_start.elapsed(); - let y = elapsed.as_secs() as NanoSecond * 1_000_000_000 - + u64::from(elapsed.subsec_nanos()) as NanoSecond; - Some(x + y) - } - None => None, - }; StepResult::Success // Not done yet, but successful } else { @@ -169,7 +158,7 @@ where } fn time(&self) -> Option { - self.duration + None } fn population(&self) -> Vec { @@ -185,7 +174,7 @@ where /// Kill off phenotypes using stochastic universal sampling. fn kill_off(&mut self, count: usize) { let ratio = self.population.len() / count; - let mut i = ::rand::thread_rng().gen_range::(0, self.population.len()); + let mut i = XorShiftRng::new_unseeded().gen_range::(0, self.population.len()); for _ in 0..count { self.population.swap_remove(i); i += ratio; From 1434f0b4c06e0bbf84264d0ed38b958905592a37 Mon Sep 17 00:00:00 2001 From: Claus Matzinger Date: Tue, 7 Aug 2018 13:07:46 +0200 Subject: [PATCH 2/5] Finished an interface for collecting statistics --- Cargo.toml | 4 +- examples/enum_phenotype.rs | 3 +- examples/max_parabole.rs | 3 +- examples/max_parabole_steps.rs | 3 +- examples/truck_loading.rs | 3 +- src/lib.rs | 4 + src/sim/mod.rs | 15 +- src/sim/seq.rs | 282 ++++++++++++++++++++++++++++++--- src/stats.rs | 38 +++++ 9 files changed, 330 insertions(+), 25 deletions(-) create mode 100644 src/stats.rs diff --git a/Cargo.toml b/Cargo.toml index acef89b3..d8320ee6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,5 +11,5 @@ license = "MIT/Apache-2.0" documentation = "https://docs.rs/rsgenetic/" [dependencies] -rand = "^0.5" -rayon = "1.0.0" +rand = "^0.5.4" +rayon = "1.0.2" diff --git a/examples/enum_phenotype.rs b/examples/enum_phenotype.rs index 9bcb89e9..89b456f9 100644 --- a/examples/enum_phenotype.rs +++ b/examples/enum_phenotype.rs @@ -24,6 +24,7 @@ use rsgenetic::sim::*; use rsgenetic::sim::seq::Simulator; use rsgenetic::sim::select::*; use rsgenetic::pheno::*; +use rsgenetic::stats::NoStats; #[derive(Clone, Copy, Debug)] struct MyPhenotype { @@ -76,7 +77,7 @@ fn main() { population.push(MyPhenotype { variant: MyVariant::Variant2, value: i }) } #[allow(deprecated)] - let mut s = Simulator::builder(&mut population) + let mut s: Simulator<_, _, NoStats> = Simulator::builder(&mut population) .set_selector(Box::new(MaximizeSelector::new(10))) .set_max_iters(100) .build(); diff --git a/examples/max_parabole.rs b/examples/max_parabole.rs index 7164222b..78d7a2d1 100644 --- a/examples/max_parabole.rs +++ b/examples/max_parabole.rs @@ -25,6 +25,7 @@ use rsgenetic::sim::select::*; use rsgenetic::pheno::*; use rand::distributions::{IndependentSample, Range}; use std::cmp::Ordering; +use rsgenetic::stats::NoStats; struct MyFitness { f: f64, @@ -104,7 +105,7 @@ impl Clone for MyData { fn main() { let mut population = (-300..300).map(|i| MyData { x: f64::from(i) }).collect(); - let mut s = Simulator::builder(&mut population) + let mut s: Simulator<_,_, NoStats> = Simulator::builder(&mut population) .set_selector(Box::new(StochasticSelector::new(10))) .set_max_iters(50) .build(); diff --git a/examples/max_parabole_steps.rs b/examples/max_parabole_steps.rs index a565aa61..2d098246 100644 --- a/examples/max_parabole_steps.rs +++ b/examples/max_parabole_steps.rs @@ -24,6 +24,7 @@ extern crate rsgenetic; use rsgenetic::sim::*; use rsgenetic::sim::seq::Simulator; use rsgenetic::sim::select::*; +use rsgenetic::stats::NoStats; use rsgenetic::pheno::*; use rand::distributions::{IndependentSample, Range}; use std::cmp::Ordering; @@ -106,7 +107,7 @@ impl Clone for MyData { fn main() { let mut population = (-300..300).map(|i| MyData { x: f64::from(i) }).collect(); - let mut s = Simulator::builder(&mut population) + let mut s: Simulator<_, _, NoStats> = Simulator::builder(&mut population) .set_selector(Box::new(StochasticSelector::new(10))) .set_max_iters(50) .build(); diff --git a/examples/truck_loading.rs b/examples/truck_loading.rs index 83c54eb2..aacd8c06 100644 --- a/examples/truck_loading.rs +++ b/examples/truck_loading.rs @@ -25,6 +25,7 @@ extern crate rand; extern crate rsgenetic; use rsgenetic::sim::*; +use rsgenetic::stats::NoStats; use rsgenetic::sim::seq::Simulator; use rsgenetic::sim::select::*; use rsgenetic::pheno::*; @@ -126,7 +127,7 @@ fn main() { population.push(LoadingScheme { scheme: pheno }); } #[allow(deprecated)] - let mut s = Simulator::builder(&mut population) + let mut s: Simulator<_, _, NoStats> = Simulator::builder(&mut population) .set_selector(Box::new(MaximizeSelector::new(10))) .set_max_iters(100) .build(); diff --git a/src/lib.rs b/src/lib.rs index d573cd22..de8a85cd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -182,6 +182,10 @@ extern crate rayon; /// Contains the definition of a Phenotype. pub mod pheno; + +/// Contains a way to collect information on steps via a trait. +pub mod stats; + /// Contains implementations of Simulators, which can run genetic algorithms. pub mod sim; /// Contains code used by unit tests. diff --git a/src/sim/mod.rs b/src/sim/mod.rs index 0e228c46..1ec37f65 100644 --- a/src/sim/mod.rs +++ b/src/sim/mod.rs @@ -15,6 +15,9 @@ // limitations under the License. use pheno::{Fitness, Phenotype}; +use stats::StatsCollector; +use std::cell::RefCell; +use std::rc::Rc; pub mod seq; pub mod select; @@ -58,14 +61,24 @@ pub enum RunResult { } /// A `Simulation` is an execution of a genetic algorithm. -pub trait Simulation<'a, T, F> +pub trait Simulation<'a, T, F, S> where T: Phenotype, F: Fitness, + S: StatsCollector, { /// A `Builder` is used to create instances of a `Simulation`. type B: Builder; + + /// Create a `Builder` to create an instance. + /// + /// `population` is a required parameter of any `Simulation`, which + /// is why it is a parameter of this function. + fn builder_with_stats(population: &'a mut Vec, sc: Option>>) -> Self::B + where + Self: Sized; + /// Create a `Builder` to create an instance. /// /// `population` is a required parameter of any `Simulation`, which diff --git a/src/sim/seq.rs b/src/sim/seq.rs index 65b30466..6a17c679 100644 --- a/src/sim/seq.rs +++ b/src/sim/seq.rs @@ -22,23 +22,38 @@ use pheno::Phenotype; use pheno::Fitness; +use stats::StatsCollector; + +use rand::prelude::*; +use stats::NoStats; use rand::Rng; +use rand::SeedableRng; +use rand::prng::XorShiftRng; use super::*; use super::select::*; use super::iterlimit::*; use super::earlystopper::*; use std::boxed::Box; use std::marker::PhantomData; -use rand::prng::XorShiftRng; +use rand::rngs::OsRng; +use std::rc::Rc; +use std::cell::RefCell; + +#[cfg(not(target="wasm32-unknown-unknown"))] +type RandomGenerator = OsRng; + +#[cfg(target="wasm32-unknown-unknown")] +type RandomGenerator = XorShiftRng; /// A sequential implementation of `::sim::Simulation`. /// The genetic algorithm is run in a single thread. #[derive(Debug)] -pub struct Simulator<'a, T, F> +pub struct Simulator<'a, T, F, S> where T: 'a + Phenotype, F: Fitness, + S: StatsCollector, { population: &'a mut Vec, iter_limit: IterLimit, @@ -46,18 +61,187 @@ where earlystopper: Option>, error: Option, phantom: PhantomData<&'a T>, + stats: Option>>, + rng: Rc>, +} + + + +#[cfg(not(target="wasm32-unknown-unknown"))] +impl<'a, T, F, S> Simulation<'a, T, F, S> for Simulator<'a, T, F, S> +where + T: Phenotype, + F: Fitness, + S: StatsCollector, +{ + type B = SimulatorBuilder<'a, T, F, S>; + + #[allow(deprecated)] + fn builder_with_stats(population: &'a mut Vec, sc: Option>>) -> SimulatorBuilder<'a, T, F, S> { + SimulatorBuilder { + sim: Simulator { + population: population, + iter_limit: IterLimit::new(100), + selector: Box::new(MaximizeSelector::new(3)), + earlystopper: None, + error: None, + phantom: PhantomData::default(), + stats: sc, + rng: Rc::new(RefCell::new(OsRng::new().unwrap())), + }, + } + } + + /// Create builder. + #[allow(deprecated)] + fn builder(population: &'a mut Vec) -> SimulatorBuilder<'a, T, F, S> { + SimulatorBuilder { + sim: Simulator { + population: population, + iter_limit: IterLimit::new(100), + selector: Box::new(MaximizeSelector::new(3)), + earlystopper: None, + error: None, + phantom: PhantomData::default(), + stats: None, + rng: Rc::new(RefCell::new(OsRng::new().unwrap())), + }, + } + } + + fn step(&mut self) -> StepResult { + + if self.population.is_empty() { + self.error = Some( + "Tried to run a simulator without a population, or the \ + population was empty." + .to_string(), + ); + return StepResult::Failure; + } + + let should_stop = match self.earlystopper { + Some(ref x) => self.iter_limit.reached() || x.reached(), + None => self.iter_limit.reached(), + }; + + if let Some(ref mut s) = self.stats { + s.borrow_mut().before_step(&self.population.into_iter().map(|p| p.fitness())); + } + + if !should_stop { + + let mut children: Vec; + { + // Perform selection + let parents = match self.selector.select(self.population) { + Ok(parents) => parents, + Err(e) => { + self.error = Some(e); + return StepResult::Failure; + } + }; + // Create children from the selected parents and mutate them. + children = parents + .iter() + .map(|&(a, b)| a.crossover(b).mutate()) + .collect(); + } + // Kill off parts of the population at random to make room for the children + self.kill_off(children.len()); + self.population.append(&mut children); + + if let Some(ref mut stopper) = self.earlystopper { + let highest_fitness = self.population + .iter() + .max_by_key(|x| x.fitness()) + .unwrap() + .fitness(); + stopper.update(highest_fitness); + } + + self.iter_limit.inc(); + + if let Some(ref mut s) = self.stats { + s.borrow_mut().after_step(&self.population.into_iter().map(|p| p.fitness())); + } + + StepResult::Success // Not done yet, but successful + } else { + StepResult::Done + } + } + + #[allow(deprecated)] + fn checked_step(&mut self) -> StepResult { + if self.error.is_some() { + panic!("Attempt to step a Simulator after an error!") + } else { + self.step() + } + } + + #[allow(deprecated)] + fn run(&mut self) -> RunResult { + // Loop until Failure or Done. + loop { + match self.step() { + StepResult::Success => {} + StepResult::Failure => return RunResult::Failure, + StepResult::Done => return RunResult::Done, + } + } + } + + fn get(&'a self) -> SimResult<'a, T> { + match self.error { + Some(ref e) => Err(e), + None => Ok(self.population.iter().max_by_key(|x| x.fitness()).unwrap()), + } + } + + fn iterations(&self) -> u64 { + self.iter_limit.get() + } + + fn time(&self) -> Option { + None + } + + fn population(&self) -> Vec { + self.population.clone() + } } -impl<'a, T, F> Simulation<'a, T, F> for Simulator<'a, T, F> +#[cfg(target="wasm32-unknown-unknown")] +impl<'a, T, F, S> Simulation<'a, T, F, S> for Simulator<'a, T, F, S> where T: Phenotype, F: Fitness, + S: StatsCollector, { - type B = SimulatorBuilder<'a, T, F>; + type B = SimulatorBuilder<'a, T, F, S>; + + /// Create builder. + #[allow(deprecated)] + fn builder_with_stats(population: &'a mut Vec, sc: Option>>) -> SimulatorBuilder<'a, T, F, S, XorShiftRng> { + SimulatorBuilder { + sim: Simulator { + population: population, + iter_limit: IterLimit::new(100), + selector: Box::new(MaximizeSelector::new(3)), + earlystopper: None, + error: None, + phantom: PhantomData::default(), + stats: sc, + rng: XorShiftRng::from_seed([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]), + }, + } + } /// Create builder. #[allow(deprecated)] - fn builder(population: &'a mut Vec) -> SimulatorBuilder<'a, T, F> { + fn builder(population: &'a mut Vec) -> SimulatorBuilder<'a, T, F, NoStats, XorShiftRng> { SimulatorBuilder { sim: Simulator { population: population, @@ -66,6 +250,8 @@ where earlystopper: None, error: None, phantom: PhantomData::default(), + stats: None, + rng: XorShiftRng::from_seed([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]), }, } } @@ -86,6 +272,10 @@ where None => self.iter_limit.reached(), }; + if let Some(ref mut s) = self.stats { + s.borrow_mut().before_step(&self.population.into_iter().map(|p| p.fitness())); + } + if !should_stop { let mut children: Vec; @@ -119,6 +309,10 @@ where self.iter_limit.inc(); + if let Some(ref mut s) = self.stats { + s.borrow_mut().after_step(&self.population.into_iter().map(|p| p.fitness())); + } + StepResult::Success // Not done yet, but successful } else { StepResult::Done @@ -166,15 +360,16 @@ where } } -impl<'a, T, F> Simulator<'a, T, F> +impl<'a, T, F, S> Simulator<'a, T, F, S> where T: Phenotype, F: Fitness, + S: StatsCollector, { /// Kill off phenotypes using stochastic universal sampling. fn kill_off(&mut self, count: usize) { let ratio = self.population.len() / count; - let mut i = XorShiftRng::new_unseeded().gen_range::(0, self.population.len()); + let mut i: usize = self.rng.borrow_mut().gen_range(0, self.population.len()); for _ in 0..count { self.population.swap_remove(i); i += ratio; @@ -185,18 +380,20 @@ where /// A `Builder` for the `Simulator` type. #[derive(Debug)] -pub struct SimulatorBuilder<'a, T, F> +pub struct SimulatorBuilder<'a, T, F, S> where T: 'a + Phenotype, F: Fitness, + S: StatsCollector, { - sim: Simulator<'a, T, F>, + sim: Simulator<'a, T, F, S>, } -impl<'a, T, F> SimulatorBuilder<'a, T, F> +impl<'a, T, F, S> SimulatorBuilder<'a, T, F, S> where T: Phenotype, F: Fitness, + S: StatsCollector, { /// Set the selector of the resulting `Simulator`. /// @@ -206,7 +403,7 @@ where self } - /// Set the maximum number of iterations of the resulting `Simulator`. + /// Set the maximum number of iterations of the resulting `Simulator`. /// /// The `Simulator` will stop running after this number of iterations. /// @@ -216,6 +413,28 @@ where self } + /// Set the maximum number of iterations of the resulting `Simulator`. + /// + /// The `Simulator` will stop running after this number of iterations. + /// + /// Returns itself for chaining purposes. + pub fn set_stats_collector(mut self, sc: Option>>) -> Self { + + self.sim.stats = sc; + self + } + + /// Set the maximum number of iterations of the resulting `Simulator`. + /// + /// The `Simulator` will stop running after this number of iterations. + /// + /// Returns itself for chaining purposes. + pub fn set_rng(mut self, rng: Rc>) -> Self { + self.sim.rng = rng; + self + } + + /// Set early stopping. If for `n_iters` iterations, the change in the highest fitness /// is smaller than `delta`, the simulator will stop running. /// @@ -226,12 +445,13 @@ where } } -impl<'a, T, F> Builder> for SimulatorBuilder<'a, T, F> +impl<'a, T, F, S> Builder> for SimulatorBuilder<'a, T, F, S> where T: Phenotype, F: Fitness, + S: StatsCollector, { - fn build(self) -> Simulator<'a, T, F> { + fn build(self) -> Simulator<'a, T, F, S> { self.sim } } @@ -243,12 +463,38 @@ mod tests { use sim::select::*; use test::Test; use test::MyFitness; + use rand::OsRng; + use stats::NoStats; + #[test] fn test_kill_off_count() { let selector = MaximizeSelector::new(2); let mut population: Vec = (0..100).map(|i| Test { f: i }).collect(); - let mut s = seq::Simulator::builder(&mut population) + let mut s: seq::Simulator = seq::Simulator::builder(&mut population) + .set_selector(Box::new(selector)) + .build(); + s.kill_off(10); + assert_eq!(s.population.len(), 90); + } + + + #[test] + fn test_stats_collector() { + let selector = MaximizeSelector::new(2); + let mut population: Vec = (0..100).map(|i| Test { f: i }).collect(); + let mut s: seq::Simulator<_, _, NoStats> = seq::Simulator::builder(&mut population) + .set_selector(Box::new(selector)) + .build(); + s.kill_off(10); + assert_eq!(s.population.len(), 90); + } + + #[test] + fn test_() { + let selector = MaximizeSelector::new(2); + let mut population: Vec = (0..100).map(|i| Test { f: i }).collect(); + let mut s: seq::Simulator<_, _, NoStats> = seq::Simulator::builder(&mut population) .set_selector(Box::new(selector)) .build(); s.kill_off(10); @@ -259,7 +505,7 @@ mod tests { fn test_max_iters() { let selector = MaximizeSelector::new(2); let mut population: Vec = (0..100).map(|i| Test { f: i }).collect(); - let mut s = seq::Simulator::builder(&mut population) + let mut s: seq::Simulator<_, _, NoStats> = seq::Simulator::builder(&mut population) .set_selector(Box::new(selector)) .set_max_iters(2) .build(); @@ -271,7 +517,7 @@ mod tests { fn test_early_stopping() { let selector = MaximizeSelector::new(2); let mut population: Vec = (0..100).map(|_| Test { f: 0 }).collect(); - let mut s = seq::Simulator::builder(&mut population) + let mut s: seq::Simulator<_, _, NoStats> = seq::Simulator::builder(&mut population) .set_selector(Box::new(selector)) .set_early_stop(MyFitness { f: 10 }, 5) .set_max_iters(10) @@ -284,7 +530,7 @@ mod tests { fn test_selector_error_propagate() { let selector = MaximizeSelector::new(0); let mut population: Vec = (0..100).map(|i| Test { f: i }).collect(); - let mut s = seq::Simulator::builder(&mut population) + let mut s: seq::Simulator<_, _, NoStats> = seq::Simulator::builder(&mut population) .set_selector(Box::new(selector)) .build(); s.run(); @@ -296,7 +542,7 @@ mod tests { let selector = MaximizeSelector::new(0); let mut population: Vec = (0..100).map(|i| Test { f: i }).collect(); let population_len = population.len(); - let s = seq::Simulator::builder(&mut population) + let s: seq::Simulator<_, _, NoStats> = seq::Simulator::builder(&mut population) .set_selector(Box::new(selector)) .build(); let gotten_population = s.population(); diff --git a/src/stats.rs b/src/stats.rs new file mode 100644 index 00000000..7c97dc71 --- /dev/null +++ b/src/stats.rs @@ -0,0 +1,38 @@ +// file: stats.rs +// +// Copyright 2015-2017 The RsGenetic Developers +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use pheno::Fitness; + +/// A collector for potential stats on the population's fitness or timing. +/// +pub trait StatsCollector +{ + ///Executed before a step, passing the current population's fitness + /// + fn before_step(&mut self, pop_fitness: &Iterator) where + F: Fitness {} + + /// Executed after a step passing in the current population's fitness. + /// + fn after_step(&mut self, pop_fitness: &Iterator) where + F: Fitness {} +} + +/// A NOOP implementation for common fitness types +/// +#[derive(Debug, Clone, Copy)] +pub struct NoStats {} +impl StatsCollector for NoStats {} From cac99d405e9dc69c67a0398225adde46645501b3 Mon Sep 17 00:00:00 2001 From: Claus Matzinger Date: Tue, 7 Aug 2018 13:24:41 +0200 Subject: [PATCH 3/5] code deduplication --- src/sim/seq.rs | 155 +++---------------------------------------------- 1 file changed, 7 insertions(+), 148 deletions(-) diff --git a/src/sim/seq.rs b/src/sim/seq.rs index 6a17c679..d3403ebb 100644 --- a/src/sim/seq.rs +++ b/src/sim/seq.rs @@ -67,7 +67,6 @@ where -#[cfg(not(target="wasm32-unknown-unknown"))] impl<'a, T, F, S> Simulation<'a, T, F, S> for Simulator<'a, T, F, S> where T: Phenotype, @@ -77,6 +76,7 @@ where type B = SimulatorBuilder<'a, T, F, S>; #[allow(deprecated)] + #[cfg(not(target="wasm32-unknown-unknown"))] fn builder_with_stats(population: &'a mut Vec, sc: Option>>) -> SimulatorBuilder<'a, T, F, S> { SimulatorBuilder { sim: Simulator { @@ -92,139 +92,9 @@ where } } - /// Create builder. - #[allow(deprecated)] - fn builder(population: &'a mut Vec) -> SimulatorBuilder<'a, T, F, S> { - SimulatorBuilder { - sim: Simulator { - population: population, - iter_limit: IterLimit::new(100), - selector: Box::new(MaximizeSelector::new(3)), - earlystopper: None, - error: None, - phantom: PhantomData::default(), - stats: None, - rng: Rc::new(RefCell::new(OsRng::new().unwrap())), - }, - } - } - - fn step(&mut self) -> StepResult { - - if self.population.is_empty() { - self.error = Some( - "Tried to run a simulator without a population, or the \ - population was empty." - .to_string(), - ); - return StepResult::Failure; - } - - let should_stop = match self.earlystopper { - Some(ref x) => self.iter_limit.reached() || x.reached(), - None => self.iter_limit.reached(), - }; - - if let Some(ref mut s) = self.stats { - s.borrow_mut().before_step(&self.population.into_iter().map(|p| p.fitness())); - } - - if !should_stop { - - let mut children: Vec; - { - // Perform selection - let parents = match self.selector.select(self.population) { - Ok(parents) => parents, - Err(e) => { - self.error = Some(e); - return StepResult::Failure; - } - }; - // Create children from the selected parents and mutate them. - children = parents - .iter() - .map(|&(a, b)| a.crossover(b).mutate()) - .collect(); - } - // Kill off parts of the population at random to make room for the children - self.kill_off(children.len()); - self.population.append(&mut children); - - if let Some(ref mut stopper) = self.earlystopper { - let highest_fitness = self.population - .iter() - .max_by_key(|x| x.fitness()) - .unwrap() - .fitness(); - stopper.update(highest_fitness); - } - - self.iter_limit.inc(); - - if let Some(ref mut s) = self.stats { - s.borrow_mut().after_step(&self.population.into_iter().map(|p| p.fitness())); - } - - StepResult::Success // Not done yet, but successful - } else { - StepResult::Done - } - } - - #[allow(deprecated)] - fn checked_step(&mut self) -> StepResult { - if self.error.is_some() { - panic!("Attempt to step a Simulator after an error!") - } else { - self.step() - } - } - - #[allow(deprecated)] - fn run(&mut self) -> RunResult { - // Loop until Failure or Done. - loop { - match self.step() { - StepResult::Success => {} - StepResult::Failure => return RunResult::Failure, - StepResult::Done => return RunResult::Done, - } - } - } - - fn get(&'a self) -> SimResult<'a, T> { - match self.error { - Some(ref e) => Err(e), - None => Ok(self.population.iter().max_by_key(|x| x.fitness()).unwrap()), - } - } - - fn iterations(&self) -> u64 { - self.iter_limit.get() - } - - fn time(&self) -> Option { - None - } - - fn population(&self) -> Vec { - self.population.clone() - } -} - -#[cfg(target="wasm32-unknown-unknown")] -impl<'a, T, F, S> Simulation<'a, T, F, S> for Simulator<'a, T, F, S> -where - T: Phenotype, - F: Fitness, - S: StatsCollector, -{ - type B = SimulatorBuilder<'a, T, F, S>; - - /// Create builder. - #[allow(deprecated)] - fn builder_with_stats(population: &'a mut Vec, sc: Option>>) -> SimulatorBuilder<'a, T, F, S, XorShiftRng> { + #[cfg(target="wasm32-unknown-unknown")] + fn builder_with_stats(population: &'a mut Vec, sc: Option>>) -> SimulatorBuilder<'a, T, F, S> { + let seed = [0u32, 0u32, 0u32, 1u32]; SimulatorBuilder { sim: Simulator { population: population, @@ -234,26 +104,15 @@ where error: None, phantom: PhantomData::default(), stats: sc, - rng: XorShiftRng::from_seed([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]), + rng: Rc::new(RefCell::new(XorShiftRng::from_seed(seed).unwrap())), }, } } /// Create builder. #[allow(deprecated)] - fn builder(population: &'a mut Vec) -> SimulatorBuilder<'a, T, F, NoStats, XorShiftRng> { - SimulatorBuilder { - sim: Simulator { - population: population, - iter_limit: IterLimit::new(100), - selector: Box::new(MaximizeSelector::new(3)), - earlystopper: None, - error: None, - phantom: PhantomData::default(), - stats: None, - rng: XorShiftRng::from_seed([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]), - }, - } + fn builder(population: &'a mut Vec) -> SimulatorBuilder<'a, T, F, S> { + Self::builder_with_stats(population, None) } fn step(&mut self) -> StepResult { From 7663128a61c9e35c4c089ad6a3cf2ec7f3f53da5 Mon Sep 17 00:00:00 2001 From: Claus Matzinger Date: Tue, 7 Aug 2018 16:01:40 +0200 Subject: [PATCH 4/5] adjusted the statscollector trait --- examples/max_parabole.rs | 5 ++++- examples/max_parabole_steps.rs | 4 +++- src/sim/mod.rs | 2 +- src/sim/seq.rs | 18 ++++++++++-------- src/stats.rs | 13 +++++++------ src/test.rs | 6 ++++++ 6 files changed, 31 insertions(+), 17 deletions(-) diff --git a/examples/max_parabole.rs b/examples/max_parabole.rs index 78d7a2d1..3c4266bc 100644 --- a/examples/max_parabole.rs +++ b/examples/max_parabole.rs @@ -25,7 +25,8 @@ use rsgenetic::sim::select::*; use rsgenetic::pheno::*; use rand::distributions::{IndependentSample, Range}; use std::cmp::Ordering; -use rsgenetic::stats::NoStats; +use rsgenetic::stats::{StatsCollector, NoStats}; + struct MyFitness { f: f64, @@ -62,6 +63,8 @@ impl Fitness for MyFitness { } } } +impl StatsCollector for NoStats {} + struct MyData { x: f64, diff --git a/examples/max_parabole_steps.rs b/examples/max_parabole_steps.rs index 2d098246..0174ef97 100644 --- a/examples/max_parabole_steps.rs +++ b/examples/max_parabole_steps.rs @@ -24,7 +24,7 @@ extern crate rsgenetic; use rsgenetic::sim::*; use rsgenetic::sim::seq::Simulator; use rsgenetic::sim::select::*; -use rsgenetic::stats::NoStats; +use rsgenetic::stats::{NoStats, StatsCollector}; use rsgenetic::pheno::*; use rand::distributions::{IndependentSample, Range}; use std::cmp::Ordering; @@ -64,6 +64,8 @@ impl Fitness for MyFitness { } } } +impl StatsCollector for NoStats {} + struct MyData { x: f64, diff --git a/src/sim/mod.rs b/src/sim/mod.rs index 1ec37f65..a6d64093 100644 --- a/src/sim/mod.rs +++ b/src/sim/mod.rs @@ -65,7 +65,7 @@ pub trait Simulation<'a, T, F, S> where T: Phenotype, F: Fitness, - S: StatsCollector, + S: StatsCollector, { /// A `Builder` is used to create instances of a `Simulation`. type B: Builder; diff --git a/src/sim/seq.rs b/src/sim/seq.rs index d3403ebb..0c1580b4 100644 --- a/src/sim/seq.rs +++ b/src/sim/seq.rs @@ -53,7 +53,7 @@ pub struct Simulator<'a, T, F, S> where T: 'a + Phenotype, F: Fitness, - S: StatsCollector, + S: StatsCollector, { population: &'a mut Vec, iter_limit: IterLimit, @@ -71,7 +71,7 @@ impl<'a, T, F, S> Simulation<'a, T, F, S> for Simulator<'a, T, F, S> where T: Phenotype, F: Fitness, - S: StatsCollector, + S: StatsCollector, { type B = SimulatorBuilder<'a, T, F, S>; @@ -132,7 +132,8 @@ where }; if let Some(ref mut s) = self.stats { - s.borrow_mut().before_step(&self.population.into_iter().map(|p| p.fitness())); + let fitness: Vec = self.population.into_iter().map(|p| p.fitness()).collect(); + s.borrow_mut().before_step(&fitness); } if !should_stop { @@ -169,7 +170,8 @@ where self.iter_limit.inc(); if let Some(ref mut s) = self.stats { - s.borrow_mut().after_step(&self.population.into_iter().map(|p| p.fitness())); + let fitness: Vec = self.population.into_iter().map(|p| p.fitness()).collect(); + s.borrow_mut().after_step(&fitness); } StepResult::Success // Not done yet, but successful @@ -223,7 +225,7 @@ impl<'a, T, F, S> Simulator<'a, T, F, S> where T: Phenotype, F: Fitness, - S: StatsCollector, + S: StatsCollector, { /// Kill off phenotypes using stochastic universal sampling. fn kill_off(&mut self, count: usize) { @@ -243,7 +245,7 @@ pub struct SimulatorBuilder<'a, T, F, S> where T: 'a + Phenotype, F: Fitness, - S: StatsCollector, + S: StatsCollector, { sim: Simulator<'a, T, F, S>, } @@ -252,7 +254,7 @@ impl<'a, T, F, S> SimulatorBuilder<'a, T, F, S> where T: Phenotype, F: Fitness, - S: StatsCollector, + S: StatsCollector, { /// Set the selector of the resulting `Simulator`. /// @@ -308,7 +310,7 @@ impl<'a, T, F, S> Builder> for SimulatorBuilder<'a, T, F, where T: Phenotype, F: Fitness, - S: StatsCollector, + S: StatsCollector, { fn build(self) -> Simulator<'a, T, F, S> { self.sim diff --git a/src/stats.rs b/src/stats.rs index 7c97dc71..d885a2c6 100644 --- a/src/stats.rs +++ b/src/stats.rs @@ -18,21 +18,22 @@ use pheno::Fitness; /// A collector for potential stats on the population's fitness or timing. /// -pub trait StatsCollector +pub trait StatsCollector { ///Executed before a step, passing the current population's fitness /// - fn before_step(&mut self, pop_fitness: &Iterator) where - F: Fitness {} + fn before_step(&mut self, pop_fitness: &[F]) {} /// Executed after a step passing in the current population's fitness. /// - fn after_step(&mut self, pop_fitness: &Iterator) where - F: Fitness {} + fn after_step(&mut self, pop_fitness: &[F]) {} } /// A NOOP implementation for common fitness types /// #[derive(Debug, Clone, Copy)] pub struct NoStats {} -impl StatsCollector for NoStats {} +impl StatsCollector for NoStats {} +impl StatsCollector for NoStats {} +impl StatsCollector for NoStats {} +impl StatsCollector for NoStats {} \ No newline at end of file diff --git a/src/test.rs b/src/test.rs index 5dbfe628..ffe28248 100644 --- a/src/test.rs +++ b/src/test.rs @@ -19,6 +19,8 @@ use pheno::*; use std::cmp; +use stats::{StatsCollector, NoStats}; + #[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq)] pub struct MyFitness { @@ -37,6 +39,8 @@ impl Fitness for MyFitness { } } + + #[derive(Clone, Copy)] pub struct Test { pub f: i64, @@ -63,3 +67,5 @@ impl Phenotype for Test { } } } + +impl StatsCollector for NoStats {} From 6c7329c0b1f58ac4763a40bc752ba53756a89e12 Mon Sep 17 00:00:00 2001 From: Claus Matzinger Date: Tue, 7 Aug 2018 16:33:27 +0200 Subject: [PATCH 5/5] fixed conditional build --- src/sim/seq.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/sim/seq.rs b/src/sim/seq.rs index 0c1580b4..0386c324 100644 --- a/src/sim/seq.rs +++ b/src/sim/seq.rs @@ -25,6 +25,7 @@ use pheno::Fitness; use stats::StatsCollector; use rand::prelude::*; +use rand::rngs::*; use stats::NoStats; use rand::Rng; use rand::SeedableRng; @@ -35,14 +36,14 @@ use super::iterlimit::*; use super::earlystopper::*; use std::boxed::Box; use std::marker::PhantomData; -use rand::rngs::OsRng; + use std::rc::Rc; use std::cell::RefCell; -#[cfg(not(target="wasm32-unknown-unknown"))] +#[cfg(not(target_arch="wasm32"))] type RandomGenerator = OsRng; -#[cfg(target="wasm32-unknown-unknown")] +#[cfg(target_arch="wasm32")] type RandomGenerator = XorShiftRng; @@ -76,7 +77,7 @@ where type B = SimulatorBuilder<'a, T, F, S>; #[allow(deprecated)] - #[cfg(not(target="wasm32-unknown-unknown"))] + #[cfg(not(target_arch="wasm32"))] fn builder_with_stats(population: &'a mut Vec, sc: Option>>) -> SimulatorBuilder<'a, T, F, S> { SimulatorBuilder { sim: Simulator { @@ -92,9 +93,9 @@ where } } - #[cfg(target="wasm32-unknown-unknown")] + #[cfg(target_arch="wasm32")] fn builder_with_stats(population: &'a mut Vec, sc: Option>>) -> SimulatorBuilder<'a, T, F, S> { - let seed = [0u32, 0u32, 0u32, 1u32]; + let seed = [0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8]; SimulatorBuilder { sim: Simulator { population: population, @@ -104,7 +105,7 @@ where error: None, phantom: PhantomData::default(), stats: sc, - rng: Rc::new(RefCell::new(XorShiftRng::from_seed(seed).unwrap())), + rng: Rc::new(RefCell::new(XorShiftRng::from_seed(seed))), }, } } @@ -324,7 +325,6 @@ mod tests { use sim::select::*; use test::Test; use test::MyFitness; - use rand::OsRng; use stats::NoStats;