solverforge_solver/termination/
unimproved.rs1use std::cell::RefCell;
4use std::fmt::Debug;
5use std::marker::PhantomData;
6use std::time::{Duration, Instant};
7
8use solverforge_core::domain::PlanningSolution;
9use solverforge_core::score::Score;
10
11use super::Termination;
12use crate::scope::SolverScope;
13
14pub struct UnimprovedStepCountTermination<S: PlanningSolution> {
38 limit: u64,
39 state: RefCell<UnimprovedState<S::Score>>,
40 _phantom: PhantomData<fn() -> S>,
41}
42
43impl<S: PlanningSolution> Debug for UnimprovedStepCountTermination<S> {
44 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
45 let state = self.state.borrow();
46 f.debug_struct("UnimprovedStepCountTermination")
47 .field("limit", &self.limit)
48 .field("steps_since_improvement", &state.steps_since_improvement)
49 .finish()
50 }
51}
52
53#[derive(Clone)]
54struct UnimprovedState<Sc: Score> {
55 last_best_score: Option<Sc>,
56 steps_since_improvement: u64,
57 last_checked_step: Option<u64>,
58}
59
60impl<Sc: Score> Default for UnimprovedState<Sc> {
61 fn default() -> Self {
62 Self {
63 last_best_score: None,
64 steps_since_improvement: 0,
65 last_checked_step: None,
66 }
67 }
68}
69
70impl<S: PlanningSolution> UnimprovedStepCountTermination<S> {
71 pub fn new(limit: u64) -> Self {
73 Self {
74 limit,
75 state: RefCell::new(UnimprovedState::default()),
76 _phantom: PhantomData,
77 }
78 }
79}
80
81unsafe impl<S: PlanningSolution> Send for UnimprovedStepCountTermination<S> {}
84
85impl<S: PlanningSolution> Termination<S> for UnimprovedStepCountTermination<S> {
86 fn is_terminated(&self, solver_scope: &SolverScope<S>) -> bool {
87 let mut state = self.state.borrow_mut();
88 let current_step = solver_scope.total_step_count();
89
90 if state.last_checked_step == Some(current_step) {
92 return state.steps_since_improvement >= self.limit;
93 }
94 state.last_checked_step = Some(current_step);
95
96 let current_best = solver_scope.best_score();
97
98 match (&state.last_best_score, current_best) {
99 (None, Some(score)) => {
100 state.last_best_score = Some(score.clone());
102 state.steps_since_improvement = 0;
103 }
104 (Some(last), Some(current)) => {
105 if *current > *last {
106 state.last_best_score = Some(current.clone());
108 state.steps_since_improvement = 0;
109 } else {
110 state.steps_since_improvement += 1;
112 }
113 }
114 (Some(_), None) => {
115 state.steps_since_improvement += 1;
117 }
118 (None, None) => {
119 }
121 }
122
123 state.steps_since_improvement >= self.limit
124 }
125}
126
127pub struct UnimprovedTimeTermination<S: PlanningSolution> {
152 limit: Duration,
153 state: RefCell<UnimprovedTimeState<S::Score>>,
154 _phantom: PhantomData<fn() -> S>,
155}
156
157impl<S: PlanningSolution> Debug for UnimprovedTimeTermination<S> {
158 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
159 f.debug_struct("UnimprovedTimeTermination")
160 .field("limit", &self.limit)
161 .finish()
162 }
163}
164
165struct UnimprovedTimeState<Sc: Score> {
166 last_best_score: Option<Sc>,
167 last_improvement_time: Option<Instant>,
168}
169
170impl<Sc: Score> Default for UnimprovedTimeState<Sc> {
171 fn default() -> Self {
172 Self {
173 last_best_score: None,
174 last_improvement_time: None,
175 }
176 }
177}
178
179impl<S: PlanningSolution> UnimprovedTimeTermination<S> {
180 pub fn new(limit: Duration) -> Self {
182 Self {
183 limit,
184 state: RefCell::new(UnimprovedTimeState::default()),
185 _phantom: PhantomData,
186 }
187 }
188
189 pub fn millis(ms: u64) -> Self {
191 Self::new(Duration::from_millis(ms))
192 }
193
194 pub fn seconds(secs: u64) -> Self {
196 Self::new(Duration::from_secs(secs))
197 }
198}
199
200unsafe impl<S: PlanningSolution> Send for UnimprovedTimeTermination<S> {}
203
204impl<S: PlanningSolution> Termination<S> for UnimprovedTimeTermination<S> {
205 fn is_terminated(&self, solver_scope: &SolverScope<S>) -> bool {
206 let mut state = self.state.borrow_mut();
207 let current_best = solver_scope.best_score();
208 let now = Instant::now();
209
210 match (&state.last_best_score, current_best) {
211 (None, Some(score)) => {
212 state.last_best_score = Some(score.clone());
214 state.last_improvement_time = Some(now);
215 false
216 }
217 (Some(last), Some(current)) => {
218 if *current > *last {
219 state.last_best_score = Some(current.clone());
221 state.last_improvement_time = Some(now);
222 false
223 } else {
224 state
226 .last_improvement_time
227 .map(|t| now.duration_since(t) >= self.limit)
228 .unwrap_or(false)
229 }
230 }
231 (Some(_), None) => {
232 state
234 .last_improvement_time
235 .map(|t| now.duration_since(t) >= self.limit)
236 .unwrap_or(false)
237 }
238 (None, None) => {
239 false
241 }
242 }
243 }
244}