use std::f64;
use super::super::AlgorithmState;
pub trait StopChecker<T> {
fn can_stop(&mut self, state: &dyn AlgorithmState<T>) -> bool;
}
pub struct CompositeAny<T> {
stop_checkers: Vec<Box<dyn StopChecker<T>>>,
}
impl<T> CompositeAny<T> {
pub fn new(stop_checkers: Vec<Box<dyn StopChecker<T>>>) -> Self {
assert!(stop_checkers.len() != 0);
Self { stop_checkers }
}
}
impl<T> StopChecker<T> for CompositeAny<T> {
fn can_stop(&mut self, state: &dyn AlgorithmState<T>) -> bool {
for checker in &mut self.stop_checkers {
if checker.can_stop(state) {
return true;
}
}
false
}
}
pub struct CompositeAll<T> {
stop_checkers: Vec<Box<dyn StopChecker<T>>>,
}
impl<T> CompositeAll<T> {
pub fn new(stop_checkers: Vec<Box<dyn StopChecker<T>>>) -> Self {
assert!(stop_checkers.len() != 0);
Self { stop_checkers }
}
}
impl<T> StopChecker<T> for CompositeAll<T> {
fn can_stop(&mut self, state: &dyn AlgorithmState<T>) -> bool {
for checker in &mut self.stop_checkers {
if !checker.can_stop(state) {
return false;
}
}
true
}
}
pub struct MaxIterations {
max_iter: usize,
}
impl MaxIterations {
pub fn new(max_iter: usize) -> Self {
MaxIterations { max_iter }
}
}
impl<T> StopChecker<T> for MaxIterations {
fn can_stop(&mut self, state: &dyn AlgorithmState<T>) -> bool {
state.get_iteration() >= self.max_iter
}
}
pub struct GoalNotChange {
max_iter: usize,
delta: f64,
old_goal: f64,
change_iter: usize,
}
impl GoalNotChange {
pub fn new(max_iter: usize, delta: f64) -> Self {
GoalNotChange {
max_iter,
delta,
old_goal: f64::MAX,
change_iter: 0,
}
}
}
impl<T> StopChecker<T> for GoalNotChange {
fn can_stop(&mut self, state: &dyn AlgorithmState<T>) -> bool {
match state.get_best_solution() {
None => false,
Some((_, best_goal)) => {
let delta = (best_goal - self.old_goal).abs();
if delta > self.delta {
self.old_goal = best_goal;
self.change_iter = state.get_iteration();
}
(state.get_iteration() - self.change_iter) > self.max_iter
}
}
}
}
pub struct Threshold {
threshold: f64,
}
impl Threshold {
pub fn new(threshold: f64) -> Self {
Self { threshold }
}
}
impl<T> StopChecker<T> for Threshold {
fn can_stop(&mut self, state: &dyn AlgorithmState<T>) -> bool {
match state.get_best_solution() {
None => false,
Some((_, goal)) => goal <= self.threshold,
}
}
}