solverforge_solver/scope/
phase.rs1use std::time::Duration;
4use std::time::Instant;
5
6use solverforge_core::domain::PlanningSolution;
7use solverforge_scoring::Director;
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 mutate<T, F>(&mut self, mutate: F) -> T
108 where
109 F: FnOnce(&mut D) -> T,
110 {
111 self.solver_scope.mutate(mutate)
112 }
113
114 pub fn calculate_score(&mut self) -> S::Score {
116 self.stats.record_score_calculation();
117 self.solver_scope.calculate_score()
118 }
119
120 pub fn update_best_solution(&mut self) {
122 self.solver_scope.update_best_solution()
123 }
124
125 pub(crate) fn promote_current_solution_on_score_tie(&mut self) {
127 self.solver_scope.promote_current_solution_on_score_tie()
128 }
129
130 pub fn stats(&self) -> &PhaseStats {
131 &self.stats
132 }
133
134 pub fn stats_mut(&mut self) -> &mut PhaseStats {
135 &mut self.stats
136 }
137
138 pub fn record_generated_batch(&mut self, count: u64, duration: Duration) {
139 self.stats.record_generated_batch(count, duration);
140 self.solver_scope
141 .stats_mut()
142 .record_generated_batch(count, duration);
143 }
144
145 pub fn record_generated_move(&mut self, duration: Duration) {
146 self.record_generated_batch(1, duration);
147 }
148
149 pub fn record_selector_generated_move(&mut self, selector_index: usize, duration: Duration) {
150 self.stats
151 .record_selector_generated(selector_index, 1, duration);
152 self.solver_scope
153 .stats_mut()
154 .record_selector_generated(selector_index, 1, duration);
155 }
156
157 pub fn record_selector_generated_move_with_label(
158 &mut self,
159 selector_index: usize,
160 selector_label: impl Into<String>,
161 duration: Duration,
162 ) {
163 let selector_label = selector_label.into();
164 self.stats.record_selector_generated_with_label(
165 selector_index,
166 selector_label.clone(),
167 1,
168 duration,
169 );
170 self.solver_scope
171 .stats_mut()
172 .record_selector_generated_with_label(selector_index, selector_label, 1, duration);
173 }
174
175 pub fn record_generation_time(&mut self, duration: Duration) {
176 self.stats.record_generation_time(duration);
177 self.solver_scope
178 .stats_mut()
179 .record_generation_time(duration);
180 }
181
182 pub fn record_evaluated_move(&mut self, duration: Duration) {
183 self.stats.record_evaluated_move(duration);
184 self.solver_scope.record_evaluated_move(duration);
185 }
186
187 pub fn record_selector_evaluated_move(&mut self, selector_index: usize, duration: Duration) {
188 self.stats
189 .record_selector_evaluated(selector_index, duration);
190 self.solver_scope
191 .record_selector_evaluated(selector_index, duration);
192 }
193
194 pub fn record_move_accepted(&mut self) {
195 self.stats.record_move_accepted();
196 self.solver_scope.stats_mut().record_move_accepted();
197 }
198
199 pub fn record_move_applied(&mut self) {
200 self.stats.record_move_applied();
201 self.solver_scope.stats_mut().record_move_applied();
202 }
203
204 pub fn record_selector_move_accepted(&mut self, selector_index: usize) {
205 self.stats.record_selector_accepted(selector_index);
206 self.solver_scope
207 .stats_mut()
208 .record_selector_accepted(selector_index);
209 }
210
211 pub fn record_selector_move_applied(&mut self, selector_index: usize) {
212 self.stats.record_selector_applied(selector_index);
213 self.solver_scope
214 .stats_mut()
215 .record_selector_applied(selector_index);
216 }
217
218 pub fn record_move_not_doable(&mut self) {
219 self.stats.record_move_not_doable();
220 self.solver_scope.stats_mut().record_move_not_doable();
221 }
222
223 pub fn record_selector_move_not_doable(&mut self, selector_index: usize) {
224 self.stats.record_selector_not_doable(selector_index);
225 self.solver_scope
226 .stats_mut()
227 .record_selector_not_doable(selector_index);
228 }
229
230 pub fn record_move_acceptor_rejected(&mut self) {
231 self.stats.record_move_acceptor_rejected();
232 self.solver_scope
233 .stats_mut()
234 .record_move_acceptor_rejected();
235 }
236
237 pub fn record_selector_move_acceptor_rejected(&mut self, selector_index: usize) {
238 self.stats.record_selector_acceptor_rejected(selector_index);
239 self.solver_scope
240 .stats_mut()
241 .record_selector_acceptor_rejected(selector_index);
242 }
243
244 pub fn record_moves_forager_ignored(&mut self, count: u64) {
245 self.stats.record_moves_forager_ignored(count);
246 self.solver_scope
247 .stats_mut()
248 .record_moves_forager_ignored(count);
249 }
250
251 pub fn record_move_hard_improving(&mut self) {
252 self.stats.record_move_hard_improving();
253 self.solver_scope.stats_mut().record_move_hard_improving();
254 }
255
256 pub fn record_move_hard_neutral(&mut self) {
257 self.stats.record_move_hard_neutral();
258 self.solver_scope.stats_mut().record_move_hard_neutral();
259 }
260
261 pub fn record_move_hard_worse(&mut self) {
262 self.stats.record_move_hard_worse();
263 self.solver_scope.stats_mut().record_move_hard_worse();
264 }
265
266 pub fn record_score_calculation(&mut self) {
267 self.stats.record_score_calculation();
268 self.solver_scope.record_score_calculation();
269 }
270
271 pub fn record_construction_slot_assigned(&mut self) {
272 self.stats.record_construction_slot_assigned();
273 self.solver_scope
274 .stats_mut()
275 .record_construction_slot_assigned();
276 }
277
278 pub fn record_construction_slot_kept(&mut self) {
279 self.stats.record_construction_slot_kept();
280 self.solver_scope
281 .stats_mut()
282 .record_construction_slot_kept();
283 }
284
285 pub fn record_construction_slot_no_doable(&mut self) {
286 self.stats.record_construction_slot_no_doable();
287 self.solver_scope
288 .stats_mut()
289 .record_construction_slot_no_doable();
290 }
291
292 pub fn record_scalar_assignment_required_remaining(
293 &mut self,
294 group_name: &'static str,
295 count: u64,
296 ) {
297 self.stats
298 .record_scalar_assignment_required_remaining(count);
299 self.solver_scope
300 .stats_mut()
301 .record_scalar_assignment_required_remaining(group_name, count);
302 }
303}