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;
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12pub(crate) enum StepControlPolicy {
13    ObserveConfigLimits,
14    CompleteMandatoryConstruction,
15}
16
17/// Scope for a single step within a phase.
18///
19/// # Type Parameters
20/// * `'t` - Lifetime of the termination flag
21/// * `'a` - Lifetime of the phase scope reference
22/// * `'b` - Lifetime of the solver scope reference
23/// * `S` - The planning solution type
24/// * `D` - The score director type
25/// * `BestCb` - The best-solution callback type
26pub struct StepScope<'t, 'a, 'b, S: PlanningSolution, D: Director<S>, BestCb = ()> {
27    // Reference to the parent phase scope.
28    phase_scope: &'a mut PhaseScope<'t, 'b, S, D, BestCb>,
29    // Index of this step within the phase (0-based).
30    step_index: u64,
31    // Score after this step.
32    step_score: Option<S::Score>,
33    control_policy: StepControlPolicy,
34}
35
36impl<'t, 'a, 'b, S: PlanningSolution, D: Director<S>, BestCb: ProgressCallback<S>>
37    StepScope<'t, 'a, 'b, S, D, BestCb>
38{
39    pub fn new(phase_scope: &'a mut PhaseScope<'t, 'b, S, D, BestCb>) -> Self {
40        Self::new_with_control_policy(phase_scope, StepControlPolicy::ObserveConfigLimits)
41    }
42
43    pub(crate) fn new_with_control_policy(
44        phase_scope: &'a mut PhaseScope<'t, 'b, S, D, BestCb>,
45        control_policy: StepControlPolicy,
46    ) -> Self {
47        let step_index = phase_scope.step_count();
48        Self {
49            phase_scope,
50            step_index,
51            step_score: None,
52            control_policy,
53        }
54    }
55
56    pub fn step_index(&self) -> u64 {
57        self.step_index
58    }
59
60    pub fn step_score(&self) -> Option<&S::Score> {
61        self.step_score.as_ref()
62    }
63
64    pub(crate) fn control_policy(&self) -> StepControlPolicy {
65        self.control_policy
66    }
67
68    pub(crate) fn pending_control(&self) -> PendingControl {
69        match self.control_policy {
70            StepControlPolicy::ObserveConfigLimits => {
71                self.phase_scope.solver_scope().pending_control()
72            }
73            StepControlPolicy::CompleteMandatoryConstruction => self
74                .phase_scope
75                .solver_scope()
76                .mandatory_construction_pending_control(),
77        }
78    }
79
80    pub fn set_step_score(&mut self, score: S::Score)
81    where
82        S::Score: Copy,
83    {
84        self.phase_scope.solver_scope_mut().set_current_score(score);
85        self.step_score = Some(score);
86    }
87
88    /// Marks this step as complete and increments counters.
89    pub fn complete(&mut self) {
90        self.phase_scope.increment_step_count();
91        self.phase_scope.solver_scope_mut().pause_if_requested();
92    }
93
94    pub fn phase_scope(&self) -> &PhaseScope<'t, 'b, S, D, BestCb> {
95        self.phase_scope
96    }
97
98    pub fn phase_scope_mut(&mut self) -> &mut PhaseScope<'t, 'b, S, D, BestCb> {
99        self.phase_scope
100    }
101
102    pub fn score_director(&self) -> &D {
103        self.phase_scope.score_director()
104    }
105
106    pub(crate) fn score_director_mut(&mut self) -> &mut D {
107        self.phase_scope.score_director_mut()
108    }
109
110    pub fn mutate<T, F>(&mut self, mutate: F) -> T
111    where
112        F: FnOnce(&mut D) -> T,
113    {
114        self.phase_scope.mutate(mutate)
115    }
116
117    pub(crate) fn apply_committed_move<M>(&mut self, mov: &M)
118    where
119        M: Move<S>,
120    {
121        self.phase_scope
122            .solver_scope_mut()
123            .apply_committed_move(mov);
124    }
125
126    pub(crate) fn apply_committed_change<F>(&mut self, change: F)
127    where
128        F: FnOnce(&mut D),
129    {
130        self.phase_scope
131            .solver_scope_mut()
132            .apply_committed_change(change);
133    }
134
135    /// Calculates the current score.
136    pub fn calculate_score(&mut self) -> S::Score {
137        self.phase_scope.calculate_score()
138    }
139}