Skip to main content

solverforge_solver/phase/
traits.rs

1// Phase trait definition.
2
3use std::fmt::Debug;
4
5use solverforge_core::domain::PlanningSolution;
6use solverforge_scoring::Director;
7
8use crate::scope::ProgressCallback;
9use crate::scope::SolverScope;
10use crate::stats::CandidateTracePhasePlan;
11
12/// A phase of the solving process.
13///
14/// Phases are executed in sequence by the solver. Each phase has its own
15/// strategy for exploring or constructing solutions.
16///
17/// # Type Parameters
18/// * `S` - The planning solution type
19/// * `D` - The score director type
20/// * `BestCb` - The best-solution callback type (default `()`)
21pub trait Phase<S: PlanningSolution, D: Director<S>, BestCb: ProgressCallback<S> = ()>:
22    Send + Debug
23{
24    /* Executes this phase.
25
26    The phase should inspect the current state through immutable accessors,
27    use typed move undo for speculative work, use `mutate(...)` for committed
28    arbitrary changes, and update the best solution when improvements are found.
29    */
30    fn solve(&mut self, solver_scope: &mut SolverScope<'_, S, D, BestCb>);
31
32    fn phase_type_name(&self) -> &'static str;
33
34    /// Whether this phase owns a structural completion gate that must pass
35    /// before the initial working solution can be published as a best solution.
36    fn defers_initial_best_solution_publication(&self) -> bool {
37        false
38    }
39
40    /// Runs once when the enclosing solver reaches its terminal boundary.
41    ///
42    /// The solver invokes this after it has attempted every configured
43    /// top-level phase and before it snapshots final statistics. It runs for
44    /// ordinary completion as well as cancellation or configured termination,
45    /// including phases whose [`Self::solve`] method was skipped. Implementors
46    /// can use it to publish terminal-only diagnostics; the default preserves
47    /// the existing phase lifecycle unchanged.
48    fn on_solver_terminal(&mut self, _solver_scope: &mut SolverScope<'_, S, D, BestCb>) {}
49
50    /// Returns the exact resolved-plan provenance this phase can prove.
51    ///
52    /// A phase that does not override this method is deliberately marked
53    /// opaque.  Candidate traces must never synthesize a lookalike plan for
54    /// custom or foreign phases; a consumer can then reject that comparison
55    /// rather than accepting a misleading fallback.
56    fn candidate_trace_plan(&self) -> CandidateTracePhasePlan {
57        CandidateTracePhasePlan::opaque(self.phase_type_name())
58    }
59}
60
61// Unit type implements Phase as a no-op (empty phase list).
62impl<S: PlanningSolution, D: Director<S>, BestCb: ProgressCallback<S>> Phase<S, D, BestCb> for () {
63    fn solve(&mut self, _solver_scope: &mut SolverScope<'_, S, D, BestCb>) {
64        // No-op: empty phase list does nothing
65    }
66
67    fn phase_type_name(&self) -> &'static str {
68        "NoOp"
69    }
70
71    fn candidate_trace_plan(&self) -> CandidateTracePhasePlan {
72        CandidateTracePhasePlan::known(
73            "solverforge.phase.no_op",
74            std::iter::empty::<(String, String)>(),
75            Vec::new(),
76        )
77    }
78}