Skip to main content

solverforge_solver/termination/
score_calculation_count.rs

1//! Score calculation count termination.
2
3use std::fmt::Debug;
4use std::marker::PhantomData;
5
6use solverforge_core::domain::PlanningSolution;
7use solverforge_scoring::Director;
8
9use super::Termination;
10use crate::scope::BestSolutionCallback;
11use crate::scope::SolverScope;
12
13/// Terminates when a maximum number of score calculations is reached.
14///
15/// # Example
16///
17/// ```
18/// use solverforge_solver::termination::ScoreCalculationCountTermination;
19/// use solverforge_core::score::SoftScore;
20/// use solverforge_core::domain::PlanningSolution;
21///
22/// #[derive(Clone)]
23/// struct MySolution;
24/// impl PlanningSolution for MySolution {
25///     type Score = SoftScore;
26///     fn score(&self) -> Option<Self::Score> { None }
27///     fn set_score(&mut self, _: Option<Self::Score>) {}
28/// }
29///
30/// // Terminate after 10,000 score calculations
31/// let termination = ScoreCalculationCountTermination::<MySolution>::new(10_000);
32/// ```
33#[derive(Clone)]
34pub struct ScoreCalculationCountTermination<S: PlanningSolution> {
35    limit: u64,
36    _phantom: PhantomData<fn() -> S>,
37}
38
39impl<S: PlanningSolution> Debug for ScoreCalculationCountTermination<S> {
40    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
41        f.debug_struct("ScoreCalculationCountTermination")
42            .field("limit", &self.limit)
43            .finish()
44    }
45}
46
47impl<S: PlanningSolution> ScoreCalculationCountTermination<S> {
48    /// Creates a new score calculation count termination.
49    ///
50    /// # Arguments
51    /// * `limit` - Maximum score calculations before terminating
52    pub fn new(limit: u64) -> Self {
53        Self {
54            limit,
55            _phantom: PhantomData,
56        }
57    }
58}
59
60impl<S: PlanningSolution, D: Director<S>, BestCb: BestSolutionCallback<S>> Termination<S, D, BestCb>
61    for ScoreCalculationCountTermination<S>
62{
63    fn is_terminated(&self, solver_scope: &SolverScope<'_, S, D, BestCb>) -> bool {
64        solver_scope.stats().score_calculations >= self.limit
65    }
66
67    fn install_inphase_limits(&self, solver_scope: &mut SolverScope<S, D, BestCb>) {
68        let limit = match solver_scope.inphase_score_calc_count_limit {
69            Some(existing) => existing.min(self.limit),
70            None => self.limit,
71        };
72        solver_scope.inphase_score_calc_count_limit = Some(limit);
73    }
74}