solverforge_solver/phase/localsearch/acceptor/
step_counting.rs1use std::fmt::Debug;
4
5use solverforge_core::domain::PlanningSolution;
6
7use super::Acceptor;
8use crate::heuristic::r#move::MoveTabuSignature;
9
10pub struct StepCountingHillClimbingAcceptor<S: PlanningSolution> {
38 step_count_limit: u64,
40 steps_since_improvement: u64,
42 best_score: Option<S::Score>,
44}
45
46impl<S: PlanningSolution> Debug for StepCountingHillClimbingAcceptor<S> {
47 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
48 f.debug_struct("StepCountingHillClimbingAcceptor")
49 .field("step_count_limit", &self.step_count_limit)
50 .field("steps_since_improvement", &self.steps_since_improvement)
51 .finish()
52 }
53}
54
55impl<S: PlanningSolution> Clone for StepCountingHillClimbingAcceptor<S> {
56 fn clone(&self) -> Self {
57 Self {
58 step_count_limit: self.step_count_limit,
59 steps_since_improvement: self.steps_since_improvement,
60 best_score: self.best_score,
61 }
62 }
63}
64
65impl<S: PlanningSolution> StepCountingHillClimbingAcceptor<S> {
66 pub fn new(step_count_limit: u64) -> Self {
71 Self {
72 step_count_limit,
73 steps_since_improvement: 0,
74 best_score: None,
75 }
76 }
77}
78
79impl<S: PlanningSolution> Default for StepCountingHillClimbingAcceptor<S> {
80 fn default() -> Self {
81 Self::new(100)
82 }
83}
84
85impl<S: PlanningSolution> Acceptor<S> for StepCountingHillClimbingAcceptor<S> {
86 fn is_accepted(
87 &mut self,
88 last_step_score: &S::Score,
89 move_score: &S::Score,
90 _move_signature: Option<&MoveTabuSignature>,
91 ) -> bool {
92 if move_score > last_step_score {
94 return true;
95 }
96
97 self.steps_since_improvement < self.step_count_limit
99 }
100
101 fn phase_started(&mut self, initial_score: &S::Score) {
102 self.best_score = Some(*initial_score);
103 self.steps_since_improvement = 0;
104 }
105
106 fn step_ended(
107 &mut self,
108 step_score: &S::Score,
109 _accepted_move_signature: Option<&MoveTabuSignature>,
110 ) {
111 let improved = match &self.best_score {
113 Some(best) => step_score > best,
114 None => true,
115 };
116
117 if improved {
118 self.best_score = Some(*step_score);
119 self.steps_since_improvement = 0;
120 } else {
121 self.steps_since_improvement += 1;
122 }
123 }
124
125 fn phase_ended(&mut self) {
126 self.best_score = None;
127 self.steps_since_improvement = 0;
128 }
129}
130
131#[cfg(test)]
132mod tests;