solverforge_solver/phase/localsearch/acceptor/
late_acceptance.rs1use std::fmt::Debug;
4
5use solverforge_core::domain::PlanningSolution;
6
7use super::Acceptor;
8use crate::heuristic::r#move::MoveTabuSignature;
9
10pub struct LateAcceptanceAcceptor<S: PlanningSolution> {
33 late_acceptance_size: usize,
35 score_history: Vec<Option<S::Score>>,
37 current_index: usize,
39}
40
41impl<S: PlanningSolution> Debug for LateAcceptanceAcceptor<S> {
42 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
43 f.debug_struct("LateAcceptanceAcceptor")
44 .field("late_acceptance_size", &self.late_acceptance_size)
45 .field("current_index", &self.current_index)
46 .finish()
47 }
48}
49
50impl<S: PlanningSolution> Clone for LateAcceptanceAcceptor<S> {
51 fn clone(&self) -> Self {
52 Self {
53 late_acceptance_size: self.late_acceptance_size,
54 score_history: self.score_history.clone(),
55 current_index: self.current_index,
56 }
57 }
58}
59
60impl<S: PlanningSolution> LateAcceptanceAcceptor<S> {
61 pub fn new(late_acceptance_size: usize) -> Self {
70 assert!(
71 late_acceptance_size > 0,
72 "late_acceptance_size must be > 0, got 0"
73 );
74 Self {
75 late_acceptance_size,
76 score_history: vec![None; late_acceptance_size],
77 current_index: 0,
78 }
79 }
80}
81
82impl<S: PlanningSolution> Default for LateAcceptanceAcceptor<S> {
83 fn default() -> Self {
84 Self::new(400)
85 }
86}
87
88impl<S: PlanningSolution> Acceptor<S> for LateAcceptanceAcceptor<S> {
89 fn is_accepted(
90 &mut self,
91 last_step_score: &S::Score,
92 move_score: &S::Score,
93 _move_signature: Option<&MoveTabuSignature>,
94 ) -> bool {
95 if move_score >= last_step_score {
97 return true;
98 }
99
100 if let Some(late_score) = &self.score_history[self.current_index] {
102 move_score >= late_score
103 } else {
104 true
106 }
107 }
108
109 fn phase_started(&mut self, initial_score: &S::Score) {
110 for slot in &mut self.score_history {
112 *slot = Some(*initial_score);
113 }
114 self.current_index = 0;
115 }
116
117 fn step_ended(
118 &mut self,
119 step_score: &S::Score,
120 _accepted_move_signature: Option<&MoveTabuSignature>,
121 ) {
122 self.score_history[self.current_index] = Some(*step_score);
124 self.current_index = (self.current_index + 1) % self.late_acceptance_size;
125 }
126}