use super::*;
use crate::scope::SolverScope;
use crate::test_utils::{
create_scope, create_scope_with_score, create_test_scope, create_test_scope_with_score,
TestSolution,
};
use solverforge_core::domain::SolutionDescriptor;
use solverforge_core::score::SoftScore;
use solverforge_scoring::ScoreDirector;
use std::any::TypeId;
#[test]
fn test_step_count_termination() {
let mut scope = create_test_scope();
let term = StepCountTermination::new(3);
assert!(!term.is_terminated(&scope));
scope.increment_step_count();
scope.increment_step_count();
assert!(!term.is_terminated(&scope));
scope.increment_step_count();
assert!(term.is_terminated(&scope));
}
#[test]
fn test_best_score_termination_not_reached() {
let scope = create_test_scope_with_score(SoftScore::of(-5));
let term: BestScoreTermination<SoftScore> = BestScoreTermination::new(SoftScore::of(0));
assert!(!term.is_terminated(&scope));
}
#[test]
fn test_best_score_termination_reached() {
let scope = create_test_scope_with_score(SoftScore::of(0));
let term: BestScoreTermination<SoftScore> = BestScoreTermination::new(SoftScore::of(0));
assert!(term.is_terminated(&scope));
}
#[test]
fn test_best_score_termination_exceeded() {
let scope = create_test_scope_with_score(SoftScore::of(5));
let term: BestScoreTermination<SoftScore> = BestScoreTermination::new(SoftScore::of(0));
assert!(term.is_terminated(&scope));
}
#[test]
fn test_best_score_termination_no_score() {
let scope = create_test_scope();
let term: BestScoreTermination<SoftScore> = BestScoreTermination::new(SoftScore::of(0));
assert!(!term.is_terminated(&scope));
}
#[test]
fn test_best_score_feasible_termination() {
let scope = create_test_scope_with_score(SoftScore::of(0));
let term = BestScoreFeasibleTermination::<TestSolution, _>::score_at_least_zero();
assert!(term.is_terminated(&scope));
}
#[test]
fn test_best_score_feasible_termination_not_feasible() {
let scope = create_test_scope_with_score(SoftScore::of(-5));
let term = BestScoreFeasibleTermination::<TestSolution, _>::score_at_least_zero();
assert!(!term.is_terminated(&scope));
}
#[test]
fn test_best_score_feasible_termination_custom() {
let scope = create_test_scope_with_score(SoftScore::of(-3));
let term = BestScoreFeasibleTermination::<TestSolution, _>::new(|score: &SoftScore| {
*score >= SoftScore::of(-5)
});
assert!(term.is_terminated(&scope));
}
#[test]
fn test_unimproved_step_count_termination() {
let mut scope = create_test_scope_with_score(SoftScore::of(-10));
let term = UnimprovedStepCountTermination::<TestSolution>::new(3);
assert!(!term.is_terminated(&scope));
scope.increment_step_count();
assert!(!term.is_terminated(&scope));
scope.increment_step_count();
assert!(!term.is_terminated(&scope));
scope.increment_step_count();
assert!(term.is_terminated(&scope));
}
#[test]
fn test_unimproved_step_count_termination_with_improvement() {
let desc = SolutionDescriptor::new("Test", TypeId::of::<TestSolution>());
let director = ScoreDirector::simple(
TestSolution {
score: Some(SoftScore::of(-10)),
},
desc,
|_, _| 0,
);
let mut scope = SolverScope::new(director);
scope.set_best_solution(
TestSolution {
score: Some(SoftScore::of(-10)),
},
SoftScore::of(-10),
);
let term = UnimprovedStepCountTermination::<TestSolution>::new(3);
assert!(!term.is_terminated(&scope));
scope.increment_step_count();
assert!(!term.is_terminated(&scope));
scope.increment_step_count();
assert!(!term.is_terminated(&scope));
scope.set_best_solution(
TestSolution {
score: Some(SoftScore::of(-5)),
},
SoftScore::of(-5),
);
scope.increment_step_count();
assert!(!term.is_terminated(&scope));
scope.increment_step_count();
assert!(!term.is_terminated(&scope));
scope.increment_step_count();
assert!(!term.is_terminated(&scope));
scope.increment_step_count();
assert!(term.is_terminated(&scope)); }
#[test]
fn test_and_termination() {
let mut scope = create_test_scope_with_score(SoftScore::of(-10));
let term = AndTermination::new((
BestScoreTermination::new(SoftScore::of(0)),
StepCountTermination::new(3),
));
assert!(!term.is_terminated(&scope));
scope.increment_step_count();
scope.increment_step_count();
scope.increment_step_count();
assert!(!term.is_terminated(&scope));
scope.set_best_solution(
TestSolution {
score: Some(SoftScore::of(0)),
},
SoftScore::of(0),
);
assert!(term.is_terminated(&scope));
}
#[test]
fn test_or_termination() {
let mut scope = create_test_scope_with_score(SoftScore::of(-10));
let term = OrTermination::new((
BestScoreTermination::new(SoftScore::of(0)),
StepCountTermination::new(3),
));
assert!(!term.is_terminated(&scope));
scope.increment_step_count();
scope.increment_step_count();
scope.increment_step_count();
assert!(term.is_terminated(&scope));
}
#[test]
fn test_unimproved_time_termination_no_score() {
let scope = create_test_scope();
let term = UnimprovedTimeTermination::<TestSolution>::millis(10);
assert!(!term.is_terminated(&scope));
}
#[test]
fn test_unimproved_time_termination_initial_score() {
let scope = create_test_scope_with_score(SoftScore::of(-10));
let term = UnimprovedTimeTermination::<TestSolution>::millis(100);
assert!(!term.is_terminated(&scope));
}
use std::thread::sleep;
use std::time::Duration;
#[test]
fn test_diminished_not_terminated_during_grace_period() {
let termination =
DiminishedReturnsTermination::<TestSolution>::new(Duration::from_millis(100), 0.0);
let scope = create_scope_with_score(SoftScore::of(-100));
assert!(!termination.is_terminated(&scope));
}
#[test]
fn test_diminished_terminates_with_zero_improvement() {
let termination =
DiminishedReturnsTermination::<TestSolution>::new(Duration::from_millis(500), 0.1);
let scope = create_scope_with_score(SoftScore::of(-100));
assert!(!termination.is_terminated(&scope));
sleep(Duration::from_millis(50));
assert!(!termination.is_terminated(&scope));
sleep(Duration::from_millis(500));
assert!(termination.is_terminated(&scope));
}
#[test]
fn test_diminished_not_terminated_with_sufficient_improvement() {
let termination =
DiminishedReturnsTermination::<TestSolution>::new(Duration::from_millis(50), 10.0);
let mut scope = create_scope_with_score(SoftScore::of(-100));
assert!(!termination.is_terminated(&scope));
sleep(Duration::from_millis(60));
scope.set_best_solution(
TestSolution {
score: Some(SoftScore::of(0)),
},
SoftScore::of(0),
);
assert!(!termination.is_terminated(&scope));
}
#[test]
fn test_diminished_no_score_does_not_terminate() {
let termination =
DiminishedReturnsTermination::<TestSolution>::new(Duration::from_millis(10), 0.0);
let scope = create_scope();
sleep(Duration::from_millis(20));
assert!(!termination.is_terminated(&scope));
}