solverforge_solver/phase/localsearch/acceptor/
great_deluge.rs1use std::fmt::Debug;
4
5use solverforge_core::domain::PlanningSolution;
6use solverforge_core::score::Score;
7
8use super::Acceptor;
9
10pub struct GreatDelugeAcceptor<S: PlanningSolution> {
41 rain_speed: f64,
43 water_level: Option<S::Score>,
45 initial_abs_score: Option<S::Score>,
47}
48
49impl<S: PlanningSolution> Debug for GreatDelugeAcceptor<S> {
50 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
51 f.debug_struct("GreatDelugeAcceptor")
52 .field("rain_speed", &self.rain_speed)
53 .finish()
54 }
55}
56
57impl<S: PlanningSolution> Clone for GreatDelugeAcceptor<S> {
58 fn clone(&self) -> Self {
59 Self {
60 rain_speed: self.rain_speed,
61 water_level: self.water_level,
62 initial_abs_score: self.initial_abs_score,
63 }
64 }
65}
66
67impl<S: PlanningSolution> GreatDelugeAcceptor<S> {
68 pub fn new(rain_speed: f64) -> Self {
74 Self {
75 rain_speed,
76 water_level: None,
77 initial_abs_score: None,
78 }
79 }
80}
81
82impl<S: PlanningSolution> Default for GreatDelugeAcceptor<S> {
83 fn default() -> Self {
84 Self::new(0.001)
85 }
86}
87
88impl<S: PlanningSolution> Acceptor<S> for GreatDelugeAcceptor<S> {
89 fn is_accepted(&self, last_step_score: &S::Score, move_score: &S::Score) -> bool {
90 if move_score > last_step_score {
92 return true;
93 }
94
95 match &self.water_level {
97 Some(water_level) => move_score >= water_level,
98 None => true, }
100 }
101
102 fn phase_started(&mut self, initial_score: &S::Score) {
103 self.water_level = Some(*initial_score);
104 self.initial_abs_score = Some(initial_score.abs());
105 }
106
107 fn step_ended(&mut self, _step_score: &S::Score) {
108 if let (Some(water), Some(abs_score)) = (&self.water_level, &self.initial_abs_score) {
110 let increment = abs_score.multiply(self.rain_speed);
111 self.water_level = Some(*water + increment);
112 }
113 }
114
115 fn phase_ended(&mut self) {
116 self.water_level = None;
117 self.initial_abs_score = None;
118 }
119}
120
121#[cfg(test)]
122mod tests {
123 use super::*;
124 use solverforge_core::score::SimpleScore;
125
126 #[derive(Clone)]
127 struct TestSolution {
128 score: Option<SimpleScore>,
129 }
130
131 impl PlanningSolution for TestSolution {
132 type Score = SimpleScore;
133 fn score(&self) -> Option<Self::Score> {
134 self.score
135 }
136 fn set_score(&mut self, score: Option<Self::Score>) {
137 self.score = score;
138 }
139 }
140
141 #[test]
142 fn test_accepts_improving_moves() {
143 let mut acceptor = GreatDelugeAcceptor::<TestSolution>::new(0.001);
144 acceptor.phase_started(&SimpleScore::of(-100));
145
146 assert!(acceptor.is_accepted(&SimpleScore::of(-100), &SimpleScore::of(-50)));
148 }
149
150 #[test]
151 fn test_accepts_above_water_level() {
152 let mut acceptor = GreatDelugeAcceptor::<TestSolution>::new(0.001);
153 acceptor.phase_started(&SimpleScore::of(-100));
154
155 assert!(acceptor.is_accepted(&SimpleScore::of(-100), &SimpleScore::of(-100)));
157
158 assert!(acceptor.is_accepted(&SimpleScore::of(-100), &SimpleScore::of(-90)));
160 }
161
162 #[test]
163 fn test_rejects_below_water_level() {
164 let mut acceptor = GreatDelugeAcceptor::<TestSolution>::new(0.001);
165 acceptor.phase_started(&SimpleScore::of(-100));
166
167 assert!(!acceptor.is_accepted(&SimpleScore::of(-100), &SimpleScore::of(-110)));
169 }
170
171 #[test]
172 fn test_water_rises_over_time() {
173 let mut acceptor = GreatDelugeAcceptor::<TestSolution>::new(0.1);
174 acceptor.phase_started(&SimpleScore::of(-100));
175
176 assert!(acceptor.is_accepted(&SimpleScore::of(-100), &SimpleScore::of(-100)));
179 assert!(!acceptor.is_accepted(&SimpleScore::of(-100), &SimpleScore::of(-101)));
181
182 acceptor.step_ended(&SimpleScore::of(-100));
184 assert!(acceptor.is_accepted(&SimpleScore::of(-90), &SimpleScore::of(-90)));
186 assert!(!acceptor.is_accepted(&SimpleScore::of(-90), &SimpleScore::of(-91)));
188
189 acceptor.step_ended(&SimpleScore::of(-90));
191 assert!(acceptor.is_accepted(&SimpleScore::of(-80), &SimpleScore::of(-80)));
193 assert!(!acceptor.is_accepted(&SimpleScore::of(-80), &SimpleScore::of(-81)));
195 }
196
197 #[test]
198 fn test_phase_reset() {
199 let mut acceptor = GreatDelugeAcceptor::<TestSolution>::new(0.1);
200 acceptor.phase_started(&SimpleScore::of(-100));
201 acceptor.step_ended(&SimpleScore::of(-100));
202 acceptor.phase_ended();
203
204 acceptor.phase_started(&SimpleScore::of(-50));
206 assert!(acceptor.is_accepted(&SimpleScore::of(-50), &SimpleScore::of(-50)));
208 assert!(!acceptor.is_accepted(&SimpleScore::of(-50), &SimpleScore::of(-51)));
209 }
210}