Skip to main content

solverforge_solver/scope/
step.rs

1// Step-level scope.
2
3use solverforge_core::domain::PlanningSolution;
4use solverforge_scoring::{Director, RecordingDirector};
5
6use crate::heuristic::r#move::Move;
7
8use super::solver::ProgressCallback;
9use super::PhaseScope;
10
11/// Scope for a single step within a phase.
12///
13/// # Type Parameters
14/// * `'t` - Lifetime of the termination flag
15/// * `'a` - Lifetime of the phase scope reference
16/// * `'b` - Lifetime of the solver scope reference
17/// * `S` - The planning solution type
18/// * `D` - The score director type
19/// * `BestCb` - The best-solution callback type
20pub struct StepScope<'t, 'a, 'b, S: PlanningSolution, D: Director<S>, BestCb = ()> {
21    // Reference to the parent phase scope.
22    phase_scope: &'a mut PhaseScope<'t, 'b, S, D, BestCb>,
23    // Index of this step within the phase (0-based).
24    step_index: u64,
25    // Score after this step.
26    step_score: Option<S::Score>,
27}
28
29impl<'t, 'a, 'b, S: PlanningSolution, D: Director<S>, BestCb: ProgressCallback<S>>
30    StepScope<'t, 'a, 'b, S, D, BestCb>
31{
32    pub fn new(phase_scope: &'a mut PhaseScope<'t, 'b, S, D, BestCb>) -> Self {
33        let step_index = phase_scope.step_count();
34        Self {
35            phase_scope,
36            step_index,
37            step_score: None,
38        }
39    }
40
41    pub fn step_index(&self) -> u64 {
42        self.step_index
43    }
44
45    pub fn step_score(&self) -> Option<&S::Score> {
46        self.step_score.as_ref()
47    }
48
49    pub fn set_step_score(&mut self, score: S::Score)
50    where
51        S::Score: Copy,
52    {
53        self.phase_scope.solver_scope_mut().set_current_score(score);
54        self.step_score = Some(score);
55    }
56
57    /// Marks this step as complete and increments counters.
58    pub fn complete(&mut self) {
59        self.phase_scope.increment_step_count();
60        self.phase_scope.solver_scope_mut().pause_if_requested();
61    }
62
63    pub fn phase_scope(&self) -> &PhaseScope<'t, 'b, S, D, BestCb> {
64        self.phase_scope
65    }
66
67    pub fn phase_scope_mut(&mut self) -> &mut PhaseScope<'t, 'b, S, D, BestCb> {
68        self.phase_scope
69    }
70
71    pub fn score_director(&self) -> &D {
72        self.phase_scope.score_director()
73    }
74
75    pub(crate) fn score_director_mut(&mut self) -> &mut D {
76        self.phase_scope.score_director_mut()
77    }
78
79    pub fn trial<T, F>(&mut self, trial: F) -> T
80    where
81        F: FnOnce(&mut RecordingDirector<'_, S, D>) -> T,
82    {
83        self.phase_scope.trial(trial)
84    }
85
86    pub fn mutate<T, F>(&mut self, mutate: F) -> T
87    where
88        F: FnOnce(&mut D) -> T,
89    {
90        self.phase_scope.mutate(mutate)
91    }
92
93    pub(crate) fn apply_committed_move<M>(&mut self, mov: &M)
94    where
95        M: Move<S>,
96    {
97        self.phase_scope
98            .solver_scope_mut()
99            .apply_committed_move(mov);
100    }
101
102    pub(crate) fn apply_committed_change<F>(&mut self, change: F)
103    where
104        F: FnOnce(&mut D),
105    {
106        self.phase_scope
107            .solver_scope_mut()
108            .apply_committed_change(change);
109    }
110
111    /// Calculates the current score.
112    pub fn calculate_score(&mut self) -> S::Score {
113        self.phase_scope.calculate_score()
114    }
115}