solverforge_solver/heuristic/selector/
mimic.rs1use std::fmt::Debug;
14use std::sync::{Arc, RwLock};
15
16use solverforge_core::domain::PlanningSolution;
17use solverforge_scoring::ScoreDirector;
18
19use super::entity::{EntityReference, EntitySelector};
20
21#[derive(Debug, Default)]
23struct MimicState {
24 has_next_recorded: bool,
26 has_next: bool,
28 next_recorded: bool,
30 recorded_entity: Option<EntityReference>,
32}
33
34#[derive(Debug, Clone)]
36pub struct MimicRecorder {
37 state: Arc<RwLock<MimicState>>,
38 id: String,
40}
41
42impl MimicRecorder {
43 pub fn new(id: impl Into<String>) -> Self {
45 Self {
46 state: Arc::new(RwLock::new(MimicState::default())),
47 id: id.into(),
48 }
49 }
50
51 fn record_has_next(&self, has_next: bool) {
53 let mut state = self.state.write().unwrap();
54 state.has_next_recorded = true;
55 state.has_next = has_next;
56 state.next_recorded = false;
57 state.recorded_entity = None;
58 }
59
60 fn record_next(&self, entity: EntityReference) {
62 let mut state = self.state.write().unwrap();
63 state.has_next_recorded = true;
64 state.has_next = true;
65 state.next_recorded = true;
66 state.recorded_entity = Some(entity);
67 }
68
69 pub fn get_has_next(&self) -> Option<bool> {
71 let state = self.state.read().unwrap();
72 if state.has_next_recorded {
73 Some(state.has_next)
74 } else {
75 None
76 }
77 }
78
79 pub fn get_recorded_entity(&self) -> Option<EntityReference> {
81 let state = self.state.read().unwrap();
82 if state.next_recorded {
83 state.recorded_entity
84 } else {
85 None
86 }
87 }
88
89 pub fn id(&self) -> &str {
91 &self.id
92 }
93
94 pub fn reset(&self) {
96 *self.state.write().unwrap() = MimicState::default();
97 }
98}
99
100pub struct MimicRecordingEntitySelector<S: PlanningSolution> {
106 child: Box<dyn EntitySelector<S>>,
108 recorder: MimicRecorder,
110}
111
112impl<S: PlanningSolution> MimicRecordingEntitySelector<S> {
113 pub fn new(child: Box<dyn EntitySelector<S>>, recorder: MimicRecorder) -> Self {
115 Self { child, recorder }
116 }
117
118 pub fn recorder(&self) -> MimicRecorder {
120 self.recorder.clone()
121 }
122}
123
124impl<S: PlanningSolution> Debug for MimicRecordingEntitySelector<S> {
125 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
126 f.debug_struct("MimicRecordingEntitySelector")
127 .field("child", &self.child)
128 .field("recorder_id", &self.recorder.id)
129 .finish()
130 }
131}
132
133impl<S: PlanningSolution> EntitySelector<S> for MimicRecordingEntitySelector<S> {
134 fn iter<'a>(
135 &'a self,
136 score_director: &'a dyn ScoreDirector<S>,
137 ) -> Box<dyn Iterator<Item = EntityReference> + 'a> {
138 self.recorder.reset();
140
141 let child_iter = self.child.iter(score_director);
142 Box::new(RecordingIterator {
143 inner: child_iter,
144 recorder: &self.recorder,
145 })
146 }
147
148 fn size(&self, score_director: &dyn ScoreDirector<S>) -> usize {
149 self.child.size(score_director)
150 }
151
152 fn is_never_ending(&self) -> bool {
153 self.child.is_never_ending()
154 }
155}
156
157struct RecordingIterator<'a> {
159 inner: Box<dyn Iterator<Item = EntityReference> + 'a>,
160 recorder: &'a MimicRecorder,
161}
162
163impl<'a> Iterator for RecordingIterator<'a> {
164 type Item = EntityReference;
165
166 fn next(&mut self) -> Option<Self::Item> {
167 let next = self.inner.next();
168 match next {
169 Some(entity) => {
170 self.recorder.record_next(entity);
171 Some(entity)
172 }
173 None => {
174 self.recorder.record_has_next(false);
175 None
176 }
177 }
178 }
179}
180
181pub struct MimicReplayingEntitySelector {
186 recorder: MimicRecorder,
188}
189
190impl MimicReplayingEntitySelector {
191 pub fn new(recorder: MimicRecorder) -> Self {
193 Self { recorder }
194 }
195}
196
197impl Debug for MimicReplayingEntitySelector {
198 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
199 f.debug_struct("MimicReplayingEntitySelector")
200 .field("recorder_id", &self.recorder.id)
201 .finish()
202 }
203}
204
205impl<S: PlanningSolution> EntitySelector<S> for MimicReplayingEntitySelector {
206 fn iter<'a>(
207 &'a self,
208 _score_director: &'a dyn ScoreDirector<S>,
209 ) -> Box<dyn Iterator<Item = EntityReference> + 'a> {
210 Box::new(ReplayingIterator {
211 recorder: &self.recorder,
212 returned: false,
213 })
214 }
215
216 fn size(&self, _score_director: &dyn ScoreDirector<S>) -> usize {
217 if self.recorder.get_recorded_entity().is_some() {
219 1
220 } else {
221 0
222 }
223 }
224
225 fn is_never_ending(&self) -> bool {
226 false
227 }
228}
229
230struct ReplayingIterator<'a> {
232 recorder: &'a MimicRecorder,
233 returned: bool,
234}
235
236impl<'a> Iterator for ReplayingIterator<'a> {
237 type Item = EntityReference;
238
239 fn next(&mut self) -> Option<Self::Item> {
240 if self.returned {
241 return None;
242 }
243
244 match self.recorder.get_recorded_entity() {
246 Some(entity) => {
247 self.returned = true;
248 Some(entity)
249 }
250 None => {
251 match self.recorder.get_has_next() {
253 Some(false) => None, Some(true) => panic!(
255 "MimicReplayingEntitySelector: Recording selector's hasNext() was true \
256 but next() was never called. Ensure the recording selector's iterator \
257 is advanced before using the replaying selector."
258 ),
259 None => panic!(
260 "MimicReplayingEntitySelector: No recording found. \
261 The recording selector must be iterated before the replaying selector."
262 ),
263 }
264 }
265 }
266 }
267}
268
269#[cfg(test)]
270mod tests {
271 use super::*;
272 use crate::heuristic::selector::entity::FromSolutionEntitySelector;
273 use solverforge_core::domain::{EntityDescriptor, SolutionDescriptor, TypedEntityExtractor};
274 use solverforge_core::score::SimpleScore;
275 use solverforge_scoring::SimpleScoreDirector;
276 use std::any::TypeId;
277
278 #[allow(dead_code)]
279 #[derive(Clone, Debug)]
280 struct Queen {
281 id: i64,
282 row: Option<i32>,
283 }
284
285 #[derive(Clone, Debug)]
286 struct NQueensSolution {
287 queens: Vec<Queen>,
288 score: Option<SimpleScore>,
289 }
290
291 impl PlanningSolution for NQueensSolution {
292 type Score = SimpleScore;
293
294 fn score(&self) -> Option<Self::Score> {
295 self.score
296 }
297
298 fn set_score(&mut self, score: Option<Self::Score>) {
299 self.score = score;
300 }
301 }
302
303 fn get_queens(s: &NQueensSolution) -> &Vec<Queen> {
304 &s.queens
305 }
306
307 fn get_queens_mut(s: &mut NQueensSolution) -> &mut Vec<Queen> {
308 &mut s.queens
309 }
310
311 fn create_test_director(
312 n: usize,
313 ) -> SimpleScoreDirector<NQueensSolution, impl Fn(&NQueensSolution) -> SimpleScore> {
314 let queens: Vec<_> = (0..n)
315 .map(|i| Queen {
316 id: i as i64,
317 row: Some(i as i32),
318 })
319 .collect();
320
321 let solution = NQueensSolution {
322 queens,
323 score: None,
324 };
325
326 let extractor = Box::new(TypedEntityExtractor::new(
327 "Queen",
328 "queens",
329 get_queens,
330 get_queens_mut,
331 ));
332 let entity_desc = EntityDescriptor::new("Queen", TypeId::of::<Queen>(), "queens")
333 .with_extractor(extractor);
334
335 let descriptor =
336 SolutionDescriptor::new("NQueensSolution", TypeId::of::<NQueensSolution>())
337 .with_entity(entity_desc);
338
339 SimpleScoreDirector::with_calculator(solution, descriptor, |_| SimpleScore::of(0))
340 }
341
342 #[test]
343 fn test_mimic_recording_selector() {
344 let director = create_test_director(3);
345
346 let solution = director.working_solution();
348 for (i, queen) in solution.queens.iter().enumerate() {
349 assert_eq!(queen.id, i as i64);
350 }
351
352 let recorder = MimicRecorder::new("test");
353 let child = Box::new(FromSolutionEntitySelector::new(0));
354 let recording = MimicRecordingEntitySelector::new(child, recorder);
355
356 let entities: Vec<_> = recording.iter(&director).collect();
357 assert_eq!(entities.len(), 3);
358 assert_eq!(entities[0], EntityReference::new(0, 0));
359 assert_eq!(entities[1], EntityReference::new(0, 1));
360 assert_eq!(entities[2], EntityReference::new(0, 2));
361 }
362
363 #[test]
364 fn test_mimic_replaying_selector() {
365 let director = create_test_director(3);
366
367 let recorder = MimicRecorder::new("test");
368 let child = Box::new(FromSolutionEntitySelector::new(0));
369 let recording = MimicRecordingEntitySelector::new(child, recorder.clone());
370 let replaying = MimicReplayingEntitySelector::new(recorder);
371
372 let mut recording_iter = recording.iter(&director);
374
375 let first = recording_iter.next().unwrap();
377 assert_eq!(first, EntityReference::new(0, 0));
378
379 let replayed: Vec<_> = replaying.iter(&director).collect();
381 assert_eq!(replayed.len(), 1);
382 assert_eq!(replayed[0], EntityReference::new(0, 0));
383
384 let second = recording_iter.next().unwrap();
386 assert_eq!(second, EntityReference::new(0, 1));
387
388 let replayed: Vec<_> = replaying.iter(&director).collect();
390 assert_eq!(replayed.len(), 1);
391 assert_eq!(replayed[0], EntityReference::new(0, 1));
392 }
393
394 #[test]
395 fn test_mimic_synchronized_iteration() {
396 let director = create_test_director(3);
397
398 let recorder = MimicRecorder::new("test");
399 let child = Box::new(FromSolutionEntitySelector::new(0));
400 let recording = MimicRecordingEntitySelector::new(child, recorder.clone());
401 let replaying = MimicReplayingEntitySelector::new(recorder);
402
403 for recorded in recording.iter(&director) {
406 let replayed: Vec<_> = replaying.iter(&director).collect();
407 assert_eq!(replayed.len(), 1);
408 assert_eq!(replayed[0], recorded);
409 }
410 }
411
412 #[test]
413 fn test_mimic_empty_selector() {
414 let director = create_test_director(0);
415
416 let recorder = MimicRecorder::new("test");
417 let child = Box::new(FromSolutionEntitySelector::new(0));
418 let recording = MimicRecordingEntitySelector::new(child, recorder.clone());
419 let replaying = MimicReplayingEntitySelector::new(recorder);
420
421 let entities: Vec<_> = recording.iter(&director).collect();
423 assert_eq!(entities.len(), 0);
424
425 let replayed: Vec<_> = replaying.iter(&director).collect();
427 assert_eq!(replayed.len(), 0);
428 }
429}