Skip to main content

solverforge_solver/scope/
phase.rs

1// Phase-level scope.
2
3use std::time::Instant;
4
5use solverforge_core::domain::PlanningSolution;
6use solverforge_scoring::Director;
7
8use super::solver::BestSolutionCallback;
9use super::SolverScope;
10use crate::stats::PhaseStats;
11
12/// Scope for a single phase of solving.
13///
14/// # Type Parameters
15/// * `'t` - Lifetime of the termination flag
16/// * `'a` - 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 PhaseScope<'t, 'a, S: PlanningSolution, D: Director<S>, BestCb = ()> {
21    // Reference to the parent solver scope.
22    solver_scope: &'a mut SolverScope<'t, S, D, BestCb>,
23    // Index of this phase (0-based).
24    phase_index: usize,
25    // Score at the start of this phase.
26    starting_score: Option<S::Score>,
27    // Number of steps in this phase.
28    step_count: u64,
29    // When this phase started.
30    start_time: Instant,
31    // Phase statistics.
32    stats: PhaseStats,
33}
34
35impl<'t, 'a, S: PlanningSolution, D: Director<S>, BestCb: BestSolutionCallback<S>>
36    PhaseScope<'t, 'a, S, D, BestCb>
37{
38    pub fn new(solver_scope: &'a mut SolverScope<'t, S, D, BestCb>, phase_index: usize) -> Self {
39        let starting_score = solver_scope.best_score().cloned();
40        Self {
41            solver_scope,
42            phase_index,
43            starting_score,
44            step_count: 0,
45            start_time: Instant::now(),
46            stats: PhaseStats::new(phase_index, "Unknown"),
47        }
48    }
49
50    pub fn with_phase_type(
51        solver_scope: &'a mut SolverScope<'t, S, D, BestCb>,
52        phase_index: usize,
53        phase_type: &'static str,
54    ) -> Self {
55        let starting_score = solver_scope.best_score().cloned();
56        Self {
57            solver_scope,
58            phase_index,
59            starting_score,
60            step_count: 0,
61            start_time: Instant::now(),
62            stats: PhaseStats::new(phase_index, phase_type),
63        }
64    }
65
66    pub fn phase_index(&self) -> usize {
67        self.phase_index
68    }
69
70    pub fn starting_score(&self) -> Option<&S::Score> {
71        self.starting_score.as_ref()
72    }
73
74    pub fn elapsed(&self) -> std::time::Duration {
75        self.start_time.elapsed()
76    }
77
78    pub fn step_count(&self) -> u64 {
79        self.step_count
80    }
81
82    /// Increments the phase step count.
83    pub fn increment_step_count(&mut self) -> u64 {
84        self.step_count += 1;
85        self.solver_scope.increment_step_count();
86        self.step_count
87    }
88
89    pub fn solver_scope(&self) -> &SolverScope<'t, S, D, BestCb> {
90        self.solver_scope
91    }
92
93    pub fn solver_scope_mut(&mut self) -> &mut SolverScope<'t, S, D, BestCb> {
94        self.solver_scope
95    }
96
97    pub fn score_director(&self) -> &D {
98        self.solver_scope.score_director()
99    }
100
101    pub fn score_director_mut(&mut self) -> &mut D {
102        self.solver_scope.score_director_mut()
103    }
104
105    /// Calculates the current score.
106    pub fn calculate_score(&mut self) -> S::Score {
107        self.solver_scope.calculate_score()
108    }
109
110    /// Updates best solution.
111    pub fn update_best_solution(&mut self) {
112        self.solver_scope.update_best_solution()
113    }
114
115    pub fn stats(&self) -> &PhaseStats {
116        &self.stats
117    }
118
119    pub fn stats_mut(&mut self) -> &mut PhaseStats {
120        &mut self.stats
121    }
122}