solverforge_solver/scope/
phase.rs1use std::cmp::Ordering;
4use std::time::Duration;
5use std::time::Instant;
6
7use solverforge_core::domain::PlanningSolution;
8use solverforge_scoring::Director;
9
10use super::solver::ProgressCallback;
11use super::SolverScope;
12use crate::stats::{AppliedMoveTelemetry, PhaseStats};
13
14pub struct PhaseScope<'t, 'a, S: PlanningSolution, D: Director<S>, BestCb = ()> {
23 solver_scope: &'a mut SolverScope<'t, S, D, BestCb>,
25 phase_index: usize,
27 starting_score: Option<S::Score>,
29 step_count: u64,
31 start_time: Instant,
33 stats: PhaseStats,
35}
36
37impl<'t, 'a, S: PlanningSolution, D: Director<S>, BestCb: ProgressCallback<S>>
38 PhaseScope<'t, 'a, S, D, BestCb>
39{
40 pub fn new(solver_scope: &'a mut SolverScope<'t, S, D, BestCb>, phase_index: usize) -> Self {
41 let starting_score = solver_scope.best_score().cloned();
42 Self {
43 solver_scope,
44 phase_index,
45 starting_score,
46 step_count: 0,
47 start_time: Instant::now(),
48 stats: PhaseStats::new(phase_index, "Unknown"),
49 }
50 }
51
52 pub fn with_phase_type(
53 solver_scope: &'a mut SolverScope<'t, S, D, BestCb>,
54 phase_index: usize,
55 phase_type: &'static str,
56 ) -> Self {
57 let starting_score = solver_scope.best_score().cloned();
58 Self {
59 solver_scope,
60 phase_index,
61 starting_score,
62 step_count: 0,
63 start_time: Instant::now(),
64 stats: PhaseStats::new(phase_index, phase_type),
65 }
66 }
67
68 pub fn phase_index(&self) -> usize {
69 self.phase_index
70 }
71
72 pub fn starting_score(&self) -> Option<&S::Score> {
73 self.starting_score.as_ref()
74 }
75
76 pub fn elapsed(&self) -> std::time::Duration {
77 self.start_time.elapsed()
78 }
79
80 pub fn step_count(&self) -> u64 {
81 self.step_count
82 }
83
84 pub fn increment_step_count(&mut self) -> u64 {
86 self.step_count += 1;
87 self.stats.record_step();
88 self.solver_scope.increment_step_count();
89 self.step_count
90 }
91
92 pub fn solver_scope(&self) -> &SolverScope<'t, S, D, BestCb> {
93 self.solver_scope
94 }
95
96 pub fn solver_scope_mut(&mut self) -> &mut SolverScope<'t, S, D, BestCb> {
97 self.solver_scope
98 }
99
100 pub fn score_director(&self) -> &D {
101 self.solver_scope.score_director()
102 }
103
104 pub(crate) fn score_director_mut(&mut self) -> &mut D {
105 self.solver_scope.score_director_mut()
106 }
107
108 pub fn mutate<T, F>(&mut self, mutate: F) -> T
109 where
110 F: FnOnce(&mut D) -> T,
111 {
112 self.solver_scope.mutate(mutate)
113 }
114
115 pub fn calculate_score(&mut self) -> S::Score {
117 self.stats.record_score_calculation();
118 self.solver_scope.calculate_score()
119 }
120
121 pub fn update_best_solution(&mut self) {
123 self.solver_scope.update_best_solution()
124 }
125
126 pub(crate) fn promote_current_solution_on_score_tie(&mut self) {
128 self.solver_scope.promote_current_solution_on_score_tie()
129 }
130
131 pub fn stats(&self) -> &PhaseStats {
132 &self.stats
133 }
134
135 pub fn stats_mut(&mut self) -> &mut PhaseStats {
136 &mut self.stats
137 }
138
139 pub fn record_generated_batch(&mut self, count: u64, duration: Duration) {
140 self.stats.record_generated_batch(count, duration);
141 self.solver_scope
142 .stats_mut()
143 .record_generated_batch(count, duration);
144 }
145
146 pub fn record_generated_move(&mut self, duration: Duration) {
147 self.record_generated_batch(1, duration);
148 }
149
150 pub fn record_selector_generated_move(&mut self, selector_index: usize, duration: Duration) {
151 self.stats
152 .record_selector_generated(selector_index, 1, duration);
153 self.solver_scope
154 .stats_mut()
155 .record_selector_generated(selector_index, 1, duration);
156 }
157
158 pub fn record_selector_generated_move_with_label(
159 &mut self,
160 selector_index: usize,
161 selector_label: impl Into<String>,
162 duration: Duration,
163 ) {
164 let selector_label = selector_label.into();
165 self.stats.record_selector_generated_with_label(
166 selector_index,
167 selector_label.clone(),
168 1,
169 duration,
170 );
171 self.solver_scope
172 .stats_mut()
173 .record_selector_generated_with_label(selector_index, selector_label, 1, duration);
174 }
175
176 pub fn record_generation_time(&mut self, duration: Duration) {
177 self.stats.record_generation_time(duration);
178 self.solver_scope
179 .stats_mut()
180 .record_generation_time(duration);
181 }
182
183 pub fn record_evaluated_move(&mut self, duration: Duration) {
184 self.stats.record_evaluated_move(duration);
185 self.solver_scope.record_evaluated_move(duration);
186 }
187
188 pub fn record_selector_evaluated_move(&mut self, selector_index: usize, duration: Duration) {
189 self.stats
190 .record_selector_evaluated(selector_index, duration);
191 self.solver_scope
192 .record_selector_evaluated(selector_index, duration);
193 }
194
195 pub fn record_move_accepted(&mut self) {
196 self.stats.record_move_accepted();
197 self.solver_scope.stats_mut().record_move_accepted();
198 }
199
200 pub fn record_move_applied(&mut self) {
201 self.stats.record_move_applied();
202 self.solver_scope.stats_mut().record_move_applied();
203 }
204
205 pub fn record_selector_move_accepted(&mut self, selector_index: usize) {
206 self.stats.record_selector_accepted(selector_index);
207 self.solver_scope
208 .stats_mut()
209 .record_selector_accepted(selector_index);
210 }
211
212 pub fn record_selector_move_applied(&mut self, selector_index: usize) {
213 self.stats.record_selector_applied(selector_index);
214 self.solver_scope
215 .stats_mut()
216 .record_selector_applied(selector_index);
217 }
218
219 pub fn record_move_not_doable(&mut self) {
220 self.stats.record_move_not_doable();
221 self.solver_scope.stats_mut().record_move_not_doable();
222 }
223
224 pub fn record_selector_move_not_doable(&mut self, selector_index: usize) {
225 self.stats.record_selector_not_doable(selector_index);
226 self.solver_scope
227 .stats_mut()
228 .record_selector_not_doable(selector_index);
229 }
230
231 pub fn record_move_acceptor_rejected(&mut self) {
232 self.stats.record_move_acceptor_rejected();
233 self.solver_scope
234 .stats_mut()
235 .record_move_acceptor_rejected();
236 }
237
238 pub fn record_selector_move_acceptor_rejected(&mut self, selector_index: usize) {
239 self.stats.record_selector_acceptor_rejected(selector_index);
240 self.solver_scope
241 .stats_mut()
242 .record_selector_acceptor_rejected(selector_index);
243 }
244
245 pub fn record_moves_forager_ignored(&mut self, count: u64) {
246 self.stats.record_moves_forager_ignored(count);
247 self.solver_scope
248 .stats_mut()
249 .record_moves_forager_ignored(count);
250 }
251
252 pub fn record_move_kind_generated(&mut self, move_label: &'static str) {
253 self.stats.record_move_kind_generated(move_label);
254 self.solver_scope
255 .stats_mut()
256 .record_move_kind_generated(move_label);
257 }
258
259 pub fn record_move_kind_evaluated(
260 &mut self,
261 move_label: &'static str,
262 score_ordering: Ordering,
263 ) {
264 self.stats
265 .record_move_kind_evaluated(move_label, score_ordering);
266 self.solver_scope
267 .stats_mut()
268 .record_move_kind_evaluated(move_label, score_ordering);
269 }
270
271 pub fn record_move_kind_evaluated_unscored(&mut self, move_label: &'static str) {
272 self.stats.record_move_kind_evaluated_unscored(move_label);
273 self.solver_scope
274 .stats_mut()
275 .record_move_kind_evaluated_unscored(move_label);
276 }
277
278 pub fn record_move_kind_accepted(&mut self, move_label: &'static str) {
279 self.stats.record_move_kind_accepted(move_label);
280 self.solver_scope
281 .stats_mut()
282 .record_move_kind_accepted(move_label);
283 }
284
285 pub fn record_move_kind_applied(&mut self, move_label: &'static str, score_improvement: f64) {
286 self.stats
287 .record_move_kind_applied(move_label, score_improvement);
288 self.solver_scope
289 .stats_mut()
290 .record_move_kind_applied(move_label, score_improvement);
291 }
292
293 pub fn record_move_kind_not_doable(&mut self, move_label: &'static str) {
294 self.stats.record_move_kind_not_doable(move_label);
295 self.solver_scope
296 .stats_mut()
297 .record_move_kind_not_doable(move_label);
298 }
299
300 pub fn record_move_kind_acceptor_rejected(
301 &mut self,
302 move_label: &'static str,
303 score_ordering: Ordering,
304 ) {
305 self.stats
306 .record_move_kind_acceptor_rejected(move_label, score_ordering);
307 self.solver_scope
308 .stats_mut()
309 .record_move_kind_acceptor_rejected(move_label, score_ordering);
310 }
311
312 pub fn record_move_kind_forager_ignored(&mut self, move_label: &'static str, count: u64) {
313 self.stats
314 .record_move_kind_forager_ignored(move_label, count);
315 self.solver_scope
316 .stats_mut()
317 .record_move_kind_forager_ignored(move_label, count);
318 }
319
320 pub fn record_applied_move_trace(&mut self, applied_move: AppliedMoveTelemetry) {
321 self.stats.record_applied_move_trace(applied_move);
322 self.solver_scope
323 .stats_mut()
324 .record_applied_move_trace(applied_move);
325 }
326
327 pub fn can_record_applied_move_trace(&self) -> bool {
328 self.stats.can_record_applied_move_trace()
329 }
330
331 pub fn record_move_hard_improving(&mut self) {
332 self.stats.record_move_hard_improving();
333 self.solver_scope.stats_mut().record_move_hard_improving();
334 }
335
336 pub fn record_move_hard_neutral(&mut self) {
337 self.stats.record_move_hard_neutral();
338 self.solver_scope.stats_mut().record_move_hard_neutral();
339 }
340
341 pub fn record_move_hard_worse(&mut self) {
342 self.stats.record_move_hard_worse();
343 self.solver_scope.stats_mut().record_move_hard_worse();
344 }
345
346 pub fn record_score_calculation(&mut self) {
347 self.stats.record_score_calculation();
348 self.solver_scope.record_score_calculation();
349 }
350
351 pub fn record_construction_slot_assigned(&mut self) {
352 self.stats.record_construction_slot_assigned();
353 self.solver_scope
354 .stats_mut()
355 .record_construction_slot_assigned();
356 }
357
358 pub fn record_construction_slot_kept(&mut self) {
359 self.stats.record_construction_slot_kept();
360 self.solver_scope
361 .stats_mut()
362 .record_construction_slot_kept();
363 }
364
365 pub fn record_construction_slot_no_doable(&mut self) {
366 self.stats.record_construction_slot_no_doable();
367 self.solver_scope
368 .stats_mut()
369 .record_construction_slot_no_doable();
370 }
371
372 pub fn record_scalar_assignment_required_remaining(
373 &mut self,
374 group_name: &'static str,
375 count: u64,
376 ) {
377 self.stats
378 .record_scalar_assignment_required_remaining(count);
379 self.solver_scope
380 .stats_mut()
381 .record_scalar_assignment_required_remaining(group_name, count);
382 }
383}