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, ES> {
111 child: ES,
113 recorder: MimicRecorder,
115 _phantom: std::marker::PhantomData<fn() -> S>,
117}
118
119impl<S, ES> MimicRecordingEntitySelector<S, ES> {
120 pub fn new(child: ES, recorder: MimicRecorder) -> Self {
122 Self {
123 child,
124 recorder,
125 _phantom: std::marker::PhantomData,
126 }
127 }
128
129 pub fn recorder(&self) -> MimicRecorder {
131 self.recorder.clone()
132 }
133}
134
135impl<S: PlanningSolution, ES: Debug> Debug for MimicRecordingEntitySelector<S, ES> {
136 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
137 f.debug_struct("MimicRecordingEntitySelector")
138 .field("child", &self.child)
139 .field("recorder_id", &self.recorder.id)
140 .finish()
141 }
142}
143
144impl<S, ES> EntitySelector<S> for MimicRecordingEntitySelector<S, ES>
145where
146 S: PlanningSolution,
147 ES: EntitySelector<S>,
148{
149 fn iter<'a, D: ScoreDirector<S>>(
150 &'a self,
151 score_director: &'a D,
152 ) -> Box<dyn Iterator<Item = EntityReference> + 'a> {
153 self.recorder.reset();
155
156 let child_iter = self.child.iter(score_director);
157 Box::new(RecordingIterator {
158 inner: child_iter,
159 recorder: &self.recorder,
160 })
161 }
162
163 fn size<D: ScoreDirector<S>>(&self, score_director: &D) -> usize {
164 self.child.size(score_director)
165 }
166
167 fn is_never_ending(&self) -> bool {
168 self.child.is_never_ending()
169 }
170}
171
172struct RecordingIterator<'a> {
174 inner: Box<dyn Iterator<Item = EntityReference> + 'a>,
175 recorder: &'a MimicRecorder,
176}
177
178impl<'a> Iterator for RecordingIterator<'a> {
179 type Item = EntityReference;
180
181 fn next(&mut self) -> Option<Self::Item> {
182 let next = self.inner.next();
183 match next {
184 Some(entity) => {
185 self.recorder.record_next(entity);
186 Some(entity)
187 }
188 None => {
189 self.recorder.record_has_next(false);
190 None
191 }
192 }
193 }
194}
195
196pub struct MimicReplayingEntitySelector {
201 recorder: MimicRecorder,
203}
204
205impl MimicReplayingEntitySelector {
206 pub fn new(recorder: MimicRecorder) -> Self {
208 Self { recorder }
209 }
210}
211
212impl Debug for MimicReplayingEntitySelector {
213 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
214 f.debug_struct("MimicReplayingEntitySelector")
215 .field("recorder_id", &self.recorder.id)
216 .finish()
217 }
218}
219
220impl<S: PlanningSolution> EntitySelector<S> for MimicReplayingEntitySelector {
221 fn iter<'a, D: ScoreDirector<S>>(
222 &'a self,
223 _score_director: &'a D,
224 ) -> Box<dyn Iterator<Item = EntityReference> + 'a> {
225 Box::new(ReplayingIterator {
226 recorder: &self.recorder,
227 returned: false,
228 })
229 }
230
231 fn size<D: ScoreDirector<S>>(&self, _score_director: &D) -> usize {
232 if self.recorder.get_recorded_entity().is_some() {
234 1
235 } else {
236 0
237 }
238 }
239
240 fn is_never_ending(&self) -> bool {
241 false
242 }
243}
244
245struct ReplayingIterator<'a> {
247 recorder: &'a MimicRecorder,
248 returned: bool,
249}
250
251impl<'a> Iterator for ReplayingIterator<'a> {
252 type Item = EntityReference;
253
254 fn next(&mut self) -> Option<Self::Item> {
255 if self.returned {
256 return None;
257 }
258
259 match self.recorder.get_recorded_entity() {
261 Some(entity) => {
262 self.returned = true;
263 Some(entity)
264 }
265 None => {
266 match self.recorder.get_has_next() {
268 Some(false) => None, Some(true) => panic!(
270 "MimicReplayingEntitySelector: Recording selector's hasNext() was true \
271 but next() was never called. Ensure the recording selector's iterator \
272 is advanced before using the replaying selector."
273 ),
274 None => panic!(
275 "MimicReplayingEntitySelector: No recording found. \
276 The recording selector must be iterated before the replaying selector."
277 ),
278 }
279 }
280 }
281 }
282}
283
284#[cfg(test)]
285mod tests {
286 use super::*;
287 use crate::heuristic::selector::entity::FromSolutionEntitySelector;
288 use solverforge_core::domain::{EntityDescriptor, SolutionDescriptor, TypedEntityExtractor};
289 use solverforge_core::score::SimpleScore;
290 use solverforge_scoring::SimpleScoreDirector;
291 use std::any::TypeId;
292
293 #[derive(Clone, Debug)]
294 struct Queen {
295 id: i64,
296 }
297
298 #[derive(Clone, Debug)]
299 struct NQueensSolution {
300 queens: Vec<Queen>,
301 score: Option<SimpleScore>,
302 }
303
304 impl PlanningSolution for NQueensSolution {
305 type Score = SimpleScore;
306
307 fn score(&self) -> Option<Self::Score> {
308 self.score
309 }
310
311 fn set_score(&mut self, score: Option<Self::Score>) {
312 self.score = score;
313 }
314 }
315
316 fn get_queens(s: &NQueensSolution) -> &Vec<Queen> {
317 &s.queens
318 }
319
320 fn get_queens_mut(s: &mut NQueensSolution) -> &mut Vec<Queen> {
321 &mut s.queens
322 }
323
324 fn create_test_director(
325 n: usize,
326 ) -> SimpleScoreDirector<NQueensSolution, impl Fn(&NQueensSolution) -> SimpleScore> {
327 let queens: Vec<_> = (0..n).map(|i| Queen { id: i as i64 }).collect();
328
329 let solution = NQueensSolution {
330 queens,
331 score: None,
332 };
333
334 let extractor = Box::new(TypedEntityExtractor::new(
335 "Queen",
336 "queens",
337 get_queens,
338 get_queens_mut,
339 ));
340 let entity_desc = EntityDescriptor::new("Queen", TypeId::of::<Queen>(), "queens")
341 .with_extractor(extractor);
342
343 let descriptor =
344 SolutionDescriptor::new("NQueensSolution", TypeId::of::<NQueensSolution>())
345 .with_entity(entity_desc);
346
347 SimpleScoreDirector::with_calculator(solution, descriptor, |_| SimpleScore::of(0))
348 }
349
350 #[test]
351 fn test_mimic_recording_selector() {
352 let director = create_test_director(3);
353
354 let solution = director.working_solution();
356 for (i, queen) in solution.queens.iter().enumerate() {
357 assert_eq!(queen.id, i as i64);
358 }
359
360 let recorder = MimicRecorder::new("test");
361 let child = FromSolutionEntitySelector::new(0);
362 let recording = MimicRecordingEntitySelector::new(child, recorder);
363
364 let entities: Vec<_> = recording.iter(&director).collect();
365 assert_eq!(entities.len(), 3);
366 assert_eq!(entities[0], EntityReference::new(0, 0));
367 assert_eq!(entities[1], EntityReference::new(0, 1));
368 assert_eq!(entities[2], EntityReference::new(0, 2));
369 }
370
371 #[test]
372 fn test_mimic_replaying_selector() {
373 let director = create_test_director(3);
374
375 let recorder = MimicRecorder::new("test");
376 let child = FromSolutionEntitySelector::new(0);
377 let recording = MimicRecordingEntitySelector::new(child, recorder.clone());
378 let replaying = MimicReplayingEntitySelector::new(recorder);
379
380 let mut recording_iter = recording.iter(&director);
382
383 let first = recording_iter.next().unwrap();
385 assert_eq!(first, EntityReference::new(0, 0));
386
387 let replayed: Vec<_> = replaying.iter(&director).collect();
389 assert_eq!(replayed.len(), 1);
390 assert_eq!(replayed[0], EntityReference::new(0, 0));
391
392 let second = recording_iter.next().unwrap();
394 assert_eq!(second, EntityReference::new(0, 1));
395
396 let replayed: Vec<_> = replaying.iter(&director).collect();
398 assert_eq!(replayed.len(), 1);
399 assert_eq!(replayed[0], EntityReference::new(0, 1));
400 }
401
402 #[test]
403 fn test_mimic_synchronized_iteration() {
404 let director = create_test_director(3);
405
406 let recorder = MimicRecorder::new("test");
407 let child = FromSolutionEntitySelector::new(0);
408 let recording = MimicRecordingEntitySelector::new(child, recorder.clone());
409 let replaying = MimicReplayingEntitySelector::new(recorder);
410
411 for recorded in recording.iter(&director) {
414 let replayed: Vec<_> = replaying.iter(&director).collect();
415 assert_eq!(replayed.len(), 1);
416 assert_eq!(replayed[0], recorded);
417 }
418 }
419
420 #[test]
421 fn test_mimic_empty_selector() {
422 let director = create_test_director(0);
423
424 let recorder = MimicRecorder::new("test");
425 let child = FromSolutionEntitySelector::new(0);
426 let recording = MimicRecordingEntitySelector::new(child, recorder.clone());
427 let replaying = MimicReplayingEntitySelector::new(recorder);
428
429 let entities: Vec<_> = recording.iter(&director).collect();
431 assert_eq!(entities.len(), 0);
432
433 let replayed: Vec<_> = replaying.iter(&director).collect();
435 assert_eq!(replayed.len(), 0);
436 }
437}