use std::{
cell::RefCell,
ops::{Add, AddAssign},
time::{Duration, SystemTime},
};
pub trait TerminationCriteria<Solution> {
fn terminate(&self, solution: &Solution) -> bool;
}
pub struct OrTerminator<Solution> {
terminators: Vec<Box<dyn TerminationCriteria<Solution>>>,
}
pub struct IterationTerminator {
n: usize,
iteration: RefCell<usize>,
}
pub struct TimeTerminator {
time_end: SystemTime,
}
pub struct AndTerminator<Solution> {
terminators: Vec<Box<dyn TerminationCriteria<Solution>>>,
}
enum AggregateTermination {
Any,
All,
}
pub struct TerminatorBuilder<Solution> {
terminators: Vec<Box<dyn TerminationCriteria<Solution>>>,
aggregator: AggregateTermination,
}
pub struct Terminator;
impl IterationTerminator {
pub fn new(iterations_max: usize) -> Self {
Self {
n: iterations_max,
iteration: RefCell::new(0),
}
}
}
impl TimeTerminator {
pub fn new(computation_time_max: Duration) -> Self {
let now = std::time::SystemTime::now();
Self {
time_end: now.add(computation_time_max),
}
}
}
impl Terminator {
pub fn builder<Solution>() -> TerminatorBuilder<Solution> {
TerminatorBuilder {
aggregator: AggregateTermination::Any,
terminators: vec![],
}
}
}
impl<Solution> TerminatorBuilder<Solution> {
pub fn build(self) -> Box<dyn TerminationCriteria<Solution>>
where
Solution: 'static,
{
match self.aggregator {
AggregateTermination::All => Box::new(AndTerminator {
terminators: self.terminators,
}),
AggregateTermination::Any => Box::new(OrTerminator {
terminators: self.terminators,
}),
}
}
pub fn criterium<T: TerminationCriteria<Solution> + 'static>(mut self, criterium: T) -> Self {
self.terminators.push(Box::new(criterium));
self
}
pub fn iterations(mut self, n: usize) -> Self {
self.terminators.push(Box::new(IterationTerminator {
n,
iteration: RefCell::new(0),
}));
self
}
pub fn computation_time(mut self, computation_time_max: Duration) -> Self {
let time_end = std::time::SystemTime::now() + computation_time_max;
self.terminators.push(Box::new(TimeTerminator { time_end }));
self
}
pub fn all(mut self) -> Self {
self.aggregator = AggregateTermination::All;
self
}
pub fn any(mut self) -> Self {
self.aggregator = AggregateTermination::Any;
self
}
}
impl<Solution> TerminationCriteria<Solution> for OrTerminator<Solution> {
fn terminate(&self, solution: &Solution) -> bool {
self.terminators.iter().any(|x| x.terminate(solution))
}
}
impl<Solution> TerminationCriteria<Solution> for AndTerminator<Solution> {
fn terminate(&self, solution: &Solution) -> bool {
self.terminators.iter().all(|x| x.terminate(solution))
}
}
impl<Solution> TerminationCriteria<Solution> for IterationTerminator {
fn terminate(&self, _solution: &Solution) -> bool {
self.iteration.borrow_mut().add_assign(1);
if *self.iteration.borrow() == self.n {
true
} else {
false
}
}
}
impl<Solution> TerminationCriteria<Solution> for TimeTerminator {
fn terminate(&self, _solution: &Solution) -> bool {
let now = std::time::SystemTime::now();
now >= self.time_end
}
}