use super::iterlimit::*;
use pheno::Fitness;
#[derive(Copy, Clone, Debug)]
pub struct EarlyStopper<F: Fitness> {
delta: F,
previous: F,
iter_limit: IterLimit,
}
impl<F: Fitness> EarlyStopper<F> {
pub fn new(delta: F, n_iters: u64) -> EarlyStopper<F> {
EarlyStopper {
delta,
previous: F::zero(),
iter_limit: IterLimit::new(n_iters),
}
}
pub fn update(&mut self, fitness: F) {
if self.previous.abs_diff(&fitness) < self.delta {
self.previous = fitness;
self.iter_limit.inc();
} else {
self.iter_limit.reset();
}
}
pub fn reached(&self) -> bool {
self.iter_limit.reached()
}
}
#[cfg(test)]
mod tests {
use super::EarlyStopper;
use test::MyFitness;
impl MyFitness {
fn new(f: i64) -> MyFitness {
MyFitness { f }
}
}
#[test]
fn test_early_stopper_reset() {
let mut stopper = EarlyStopper::new(MyFitness::new(10), 5);
for _ in 0..4 {
stopper.update(MyFitness::new(1));
}
assert_eq!(stopper.reached(), false);
stopper.update(MyFitness::new(20));
assert_eq!(stopper.reached(), false);
}
#[test]
fn test_early_stopper_reached() {
let mut stopper = EarlyStopper::new(MyFitness::new(10), 5);
for _ in 0..5 {
stopper.update(MyFitness::new(1));
}
assert!(stopper.reached());
}
}