solverforge_solver/scope/
phase.rs1use std::time::Duration;
4use std::time::Instant;
5
6use solverforge_core::domain::PlanningSolution;
7use solverforge_scoring::{Director, RecordingDirector};
8
9use super::solver::ProgressCallback;
10use super::SolverScope;
11use crate::stats::PhaseStats;
12
13pub struct PhaseScope<'t, 'a, S: PlanningSolution, D: Director<S>, BestCb = ()> {
22 solver_scope: &'a mut SolverScope<'t, S, D, BestCb>,
24 phase_index: usize,
26 starting_score: Option<S::Score>,
28 step_count: u64,
30 start_time: Instant,
32 stats: PhaseStats,
34}
35
36impl<'t, 'a, S: PlanningSolution, D: Director<S>, BestCb: ProgressCallback<S>>
37 PhaseScope<'t, 'a, S, D, BestCb>
38{
39 pub fn new(solver_scope: &'a mut SolverScope<'t, S, D, BestCb>, phase_index: usize) -> Self {
40 let starting_score = solver_scope.best_score().cloned();
41 Self {
42 solver_scope,
43 phase_index,
44 starting_score,
45 step_count: 0,
46 start_time: Instant::now(),
47 stats: PhaseStats::new(phase_index, "Unknown"),
48 }
49 }
50
51 pub fn with_phase_type(
52 solver_scope: &'a mut SolverScope<'t, S, D, BestCb>,
53 phase_index: usize,
54 phase_type: &'static str,
55 ) -> Self {
56 let starting_score = solver_scope.best_score().cloned();
57 Self {
58 solver_scope,
59 phase_index,
60 starting_score,
61 step_count: 0,
62 start_time: Instant::now(),
63 stats: PhaseStats::new(phase_index, phase_type),
64 }
65 }
66
67 pub fn phase_index(&self) -> usize {
68 self.phase_index
69 }
70
71 pub fn starting_score(&self) -> Option<&S::Score> {
72 self.starting_score.as_ref()
73 }
74
75 pub fn elapsed(&self) -> std::time::Duration {
76 self.start_time.elapsed()
77 }
78
79 pub fn step_count(&self) -> u64 {
80 self.step_count
81 }
82
83 pub fn increment_step_count(&mut self) -> u64 {
85 self.step_count += 1;
86 self.stats.record_step();
87 self.solver_scope.increment_step_count();
88 self.step_count
89 }
90
91 pub fn solver_scope(&self) -> &SolverScope<'t, S, D, BestCb> {
92 self.solver_scope
93 }
94
95 pub fn solver_scope_mut(&mut self) -> &mut SolverScope<'t, S, D, BestCb> {
96 self.solver_scope
97 }
98
99 pub fn score_director(&self) -> &D {
100 self.solver_scope.score_director()
101 }
102
103 pub(crate) fn score_director_mut(&mut self) -> &mut D {
104 self.solver_scope.score_director_mut()
105 }
106
107 pub fn trial<T, F>(&mut self, trial: F) -> T
108 where
109 F: FnOnce(&mut RecordingDirector<'_, S, D>) -> T,
110 {
111 self.solver_scope.trial(trial)
112 }
113
114 pub fn mutate<T, F>(&mut self, mutate: F) -> T
115 where
116 F: FnOnce(&mut D) -> T,
117 {
118 self.solver_scope.mutate(mutate)
119 }
120
121 pub fn calculate_score(&mut self) -> S::Score {
123 self.stats.record_score_calculation();
124 self.solver_scope.calculate_score()
125 }
126
127 pub fn update_best_solution(&mut self) {
129 self.solver_scope.update_best_solution()
130 }
131
132 pub(crate) fn promote_current_solution_on_score_tie(&mut self) {
134 self.solver_scope.promote_current_solution_on_score_tie()
135 }
136
137 pub fn stats(&self) -> &PhaseStats {
138 &self.stats
139 }
140
141 pub fn stats_mut(&mut self) -> &mut PhaseStats {
142 &mut self.stats
143 }
144
145 pub fn record_generated_batch(&mut self, count: u64, duration: Duration) {
146 self.stats.record_generated_batch(count, duration);
147 self.solver_scope
148 .stats_mut()
149 .record_generated_batch(count, duration);
150 }
151
152 pub fn record_generated_move(&mut self, duration: Duration) {
153 self.record_generated_batch(1, duration);
154 }
155
156 pub fn record_selector_generated_move(&mut self, selector_index: usize, duration: Duration) {
157 self.stats
158 .record_selector_generated(selector_index, 1, duration);
159 self.solver_scope
160 .stats_mut()
161 .record_selector_generated(selector_index, 1, duration);
162 }
163
164 pub fn record_selector_generated_move_with_label(
165 &mut self,
166 selector_index: usize,
167 selector_label: impl Into<String>,
168 duration: Duration,
169 ) {
170 let selector_label = selector_label.into();
171 self.stats.record_selector_generated_with_label(
172 selector_index,
173 selector_label.clone(),
174 1,
175 duration,
176 );
177 self.solver_scope
178 .stats_mut()
179 .record_selector_generated_with_label(selector_index, selector_label, 1, duration);
180 }
181
182 pub fn record_generation_time(&mut self, duration: Duration) {
183 self.stats.record_generation_time(duration);
184 self.solver_scope
185 .stats_mut()
186 .record_generation_time(duration);
187 }
188
189 pub fn record_evaluated_move(&mut self, duration: Duration) {
190 self.stats.record_evaluated_move(duration);
191 self.solver_scope
192 .stats_mut()
193 .record_evaluated_move(duration);
194 }
195
196 pub fn record_selector_evaluated_move(&mut self, selector_index: usize, duration: Duration) {
197 self.stats
198 .record_selector_evaluated(selector_index, duration);
199 self.solver_scope
200 .stats_mut()
201 .record_selector_evaluated(selector_index, duration);
202 }
203
204 pub fn record_move_accepted(&mut self) {
205 self.stats.record_move_accepted();
206 self.solver_scope.stats_mut().record_move_accepted();
207 }
208
209 pub fn record_move_applied(&mut self) {
210 self.stats.record_move_applied();
211 self.solver_scope.stats_mut().record_move_applied();
212 }
213
214 pub fn record_selector_move_accepted(&mut self, selector_index: usize) {
215 self.stats.record_selector_accepted(selector_index);
216 self.solver_scope
217 .stats_mut()
218 .record_selector_accepted(selector_index);
219 }
220
221 pub fn record_selector_move_applied(&mut self, selector_index: usize) {
222 self.stats.record_selector_applied(selector_index);
223 self.solver_scope
224 .stats_mut()
225 .record_selector_applied(selector_index);
226 }
227
228 pub fn record_move_not_doable(&mut self) {
229 self.stats.record_move_not_doable();
230 self.solver_scope.stats_mut().record_move_not_doable();
231 }
232
233 pub fn record_selector_move_not_doable(&mut self, selector_index: usize) {
234 self.stats.record_selector_not_doable(selector_index);
235 self.solver_scope
236 .stats_mut()
237 .record_selector_not_doable(selector_index);
238 }
239
240 pub fn record_move_acceptor_rejected(&mut self) {
241 self.stats.record_move_acceptor_rejected();
242 self.solver_scope
243 .stats_mut()
244 .record_move_acceptor_rejected();
245 }
246
247 pub fn record_selector_move_acceptor_rejected(&mut self, selector_index: usize) {
248 self.stats.record_selector_acceptor_rejected(selector_index);
249 self.solver_scope
250 .stats_mut()
251 .record_selector_acceptor_rejected(selector_index);
252 }
253
254 pub fn record_moves_forager_ignored(&mut self, count: u64) {
255 self.stats.record_moves_forager_ignored(count);
256 self.solver_scope
257 .stats_mut()
258 .record_moves_forager_ignored(count);
259 }
260
261 pub fn record_move_hard_improving(&mut self) {
262 self.stats.record_move_hard_improving();
263 self.solver_scope.stats_mut().record_move_hard_improving();
264 }
265
266 pub fn record_move_hard_neutral(&mut self) {
267 self.stats.record_move_hard_neutral();
268 self.solver_scope.stats_mut().record_move_hard_neutral();
269 }
270
271 pub fn record_move_hard_worse(&mut self) {
272 self.stats.record_move_hard_worse();
273 self.solver_scope.stats_mut().record_move_hard_worse();
274 }
275
276 pub fn record_score_calculation(&mut self) {
277 self.stats.record_score_calculation();
278 self.solver_scope.stats_mut().record_score_calculation();
279 }
280
281 pub fn record_construction_slot_assigned(&mut self) {
282 self.stats.record_construction_slot_assigned();
283 self.solver_scope
284 .stats_mut()
285 .record_construction_slot_assigned();
286 }
287
288 pub fn record_construction_slot_kept(&mut self) {
289 self.stats.record_construction_slot_kept();
290 self.solver_scope
291 .stats_mut()
292 .record_construction_slot_kept();
293 }
294
295 pub fn record_construction_slot_no_doable(&mut self) {
296 self.stats.record_construction_slot_no_doable();
297 self.solver_scope
298 .stats_mut()
299 .record_construction_slot_no_doable();
300 }
301}