Skip to main content

solverforge_solver/scope/
step.rs

1// Step-level scope.
2
3use solverforge_core::domain::PlanningSolution;
4use solverforge_scoring::Director;
5
6use crate::heuristic::r#move::Move;
7
8use super::solver::{PendingControl, ProgressCallback};
9use super::{PhaseScope, SolverScope};
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12pub(crate) enum StepControlPolicy {
13    ObserveConfigLimits,
14}
15
16impl StepControlPolicy {
17    pub(crate) fn for_required_construction(_required_only: bool) -> Self {
18        Self::ObserveConfigLimits
19    }
20
21    pub(crate) fn should_terminate_construction<S, D, ProgressCb>(
22        self,
23        solver_scope: &mut SolverScope<'_, S, D, ProgressCb>,
24    ) -> bool
25    where
26        S: PlanningSolution,
27        D: Director<S>,
28        ProgressCb: ProgressCallback<S>,
29    {
30        solver_scope.should_terminate_construction()
31    }
32}
33
34/// Scope for a single step within a phase.
35///
36/// # Type Parameters
37/// * `'t` - Lifetime of the termination flag
38/// * `'a` - Lifetime of the phase scope reference
39/// * `'b` - Lifetime of the solver scope reference
40/// * `S` - The planning solution type
41/// * `D` - The score director type
42/// * `BestCb` - The best-solution callback type
43pub struct StepScope<'t, 'a, 'b, S: PlanningSolution, D: Director<S>, BestCb = ()> {
44    // Reference to the parent phase scope.
45    phase_scope: &'a mut PhaseScope<'t, 'b, S, D, BestCb>,
46    // Index of this step within the phase (0-based).
47    step_index: u64,
48    // Score after this step.
49    step_score: Option<S::Score>,
50    control_policy: StepControlPolicy,
51    control_polling_required: bool,
52    progress_polling_required: bool,
53}
54
55impl<'t, 'a, 'b, S: PlanningSolution, D: Director<S>, BestCb: ProgressCallback<S>>
56    StepScope<'t, 'a, 'b, S, D, BestCb>
57{
58    pub fn new(phase_scope: &'a mut PhaseScope<'t, 'b, S, D, BestCb>) -> Self {
59        Self::new_with_control_policy(phase_scope, StepControlPolicy::ObserveConfigLimits)
60    }
61
62    pub(crate) fn new_with_control_policy(
63        phase_scope: &'a mut PhaseScope<'t, 'b, S, D, BestCb>,
64        control_policy: StepControlPolicy,
65    ) -> Self {
66        let step_index = phase_scope.step_count();
67        let control_polling_required = phase_scope.solver_scope().config_control_polling_required();
68        Self {
69            phase_scope,
70            step_index,
71            step_score: None,
72            control_policy,
73            control_polling_required,
74            progress_polling_required: BestCb::PUBLISHES_PROGRESS
75                || tracing::enabled!(tracing::Level::DEBUG),
76        }
77    }
78
79    pub fn step_index(&self) -> u64 {
80        self.step_index
81    }
82
83    pub fn step_score(&self) -> Option<&S::Score> {
84        self.step_score.as_ref()
85    }
86
87    pub(crate) fn control_policy(&self) -> StepControlPolicy {
88        self.control_policy
89    }
90
91    pub(crate) fn pending_control(&self) -> PendingControl {
92        if !self.control_polling_required {
93            return PendingControl::Continue;
94        }
95        self.phase_scope.solver_scope().pending_control()
96    }
97
98    pub(crate) fn progress_polling_required(&self) -> bool {
99        self.progress_polling_required
100    }
101
102    pub fn set_step_score(&mut self, score: S::Score)
103    where
104        S::Score: Copy,
105    {
106        self.phase_scope.solver_scope_mut().set_current_score(score);
107        self.phase_scope
108            .solver_scope_mut()
109            .observe_phase_step_score(score);
110        self.step_score = Some(score);
111    }
112
113    /// Marks this step as complete and increments counters.
114    pub fn complete(&mut self) {
115        self.phase_scope.increment_step_count();
116        self.phase_scope.solver_scope_mut().pause_if_requested();
117        self.phase_scope.report_progress_if_due();
118    }
119
120    pub fn phase_scope(&self) -> &PhaseScope<'t, 'b, S, D, BestCb> {
121        self.phase_scope
122    }
123
124    pub fn phase_scope_mut(&mut self) -> &mut PhaseScope<'t, 'b, S, D, BestCb> {
125        self.phase_scope
126    }
127
128    pub fn score_director(&self) -> &D {
129        self.phase_scope.score_director()
130    }
131
132    pub(crate) fn score_director_mut(&mut self) -> &mut D {
133        self.phase_scope.score_director_mut()
134    }
135
136    pub fn mutate<T, F>(&mut self, mutate: F) -> T
137    where
138        F: FnOnce(&mut D) -> T,
139    {
140        self.phase_scope.mutate(mutate)
141    }
142
143    pub(crate) fn apply_committed_move<M>(&mut self, mov: &M)
144    where
145        M: Move<S>,
146    {
147        self.phase_scope
148            .solver_scope_mut()
149            .apply_committed_move(mov);
150    }
151
152    pub(crate) fn apply_committed_change<F>(&mut self, change: F)
153    where
154        F: FnOnce(&mut D),
155    {
156        self.phase_scope
157            .solver_scope_mut()
158            .apply_committed_change(change);
159    }
160
161    /// Calculates the current score.
162    pub fn calculate_score(&mut self) -> S::Score {
163        self.phase_scope.calculate_score()
164    }
165}