solverforge_solver/termination/
best_score.rs1use std::fmt::Debug;
4
5use solverforge_core::domain::PlanningSolution;
6use solverforge_core::score::Score;
7use solverforge_scoring::ScoreDirector;
8
9use super::Termination;
10use crate::scope::SolverScope;
11
12#[derive(Debug, Clone)]
27pub struct BestScoreTermination<Sc: Score> {
28 target_score: Sc,
29}
30
31impl<Sc: Score> BestScoreTermination<Sc> {
32 pub fn new(target_score: Sc) -> Self {
34 Self { target_score }
35 }
36}
37
38impl<S, D, Sc> Termination<S, D> for BestScoreTermination<Sc>
39where
40 S: PlanningSolution<Score = Sc>,
41 D: ScoreDirector<S>,
42 Sc: Score,
43{
44 fn is_terminated(&self, solver_scope: &SolverScope<S, D>) -> bool {
45 solver_scope
46 .best_score()
47 .map(|score| *score >= self.target_score)
48 .unwrap_or(false)
49 }
50}
51
52pub struct BestScoreFeasibleTermination<S, F>
63where
64 S: PlanningSolution,
65 F: Fn(&S::Score) -> bool + Send + Sync,
66{
67 feasibility_check: F,
68 _phantom: std::marker::PhantomData<S>,
69}
70
71impl<S, F> Debug for BestScoreFeasibleTermination<S, F>
72where
73 S: PlanningSolution,
74 F: Fn(&S::Score) -> bool + Send + Sync,
75{
76 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
77 f.debug_struct("BestScoreFeasibleTermination").finish()
78 }
79}
80
81impl<S, F> BestScoreFeasibleTermination<S, F>
82where
83 S: PlanningSolution,
84 F: Fn(&S::Score) -> bool + Send + Sync,
85{
86 pub fn new(feasibility_check: F) -> Self {
88 Self {
89 feasibility_check,
90 _phantom: std::marker::PhantomData,
91 }
92 }
93}
94
95impl<S: PlanningSolution> BestScoreFeasibleTermination<S, fn(&S::Score) -> bool> {
96 pub fn score_at_least_zero() -> Self {
100 Self::new(|score| *score >= S::Score::zero())
101 }
102}
103
104impl<S, D, F> Termination<S, D> for BestScoreFeasibleTermination<S, F>
105where
106 S: PlanningSolution,
107 D: ScoreDirector<S>,
108 F: Fn(&S::Score) -> bool + Send + Sync,
109{
110 fn is_terminated(&self, solver_scope: &SolverScope<S, D>) -> bool {
111 solver_scope
112 .best_score()
113 .map(|score| (self.feasibility_check)(score))
114 .unwrap_or(false)
115 }
116}