solverforge_solver/heuristic/selector/
dynamic_scalar_change.rs1use std::fmt::{self, Debug};
4
5use solverforge_core::domain::{DynamicScalarVariableSlot, PlanningSolution};
6use solverforge_core::score::Score;
7use solverforge_scoring::Director;
8
9use crate::heuristic::r#move::{DynamicScalarChangeMove, MoveArena};
10
11use super::move_selector::{MoveCursor, MoveSelector, MoveStreamContext};
12use super::scalar_neighborhood::{
13 dynamic_slot, emit_dynamic_scalar_change_move, RuntimeScalarFacadeCursor,
14 ScalarNeighborhoodLeaf, ScalarNeighborhoodSpec,
15};
16
17pub struct DynamicScalarChangeMoveSelector<S> {
21 leaf: ScalarNeighborhoodLeaf<S>,
22}
23
24pub type DynamicScalarChangeMoveCursor<S> =
25 RuntimeScalarFacadeCursor<S, DynamicScalarChangeMove<S>>;
26
27impl<S> DynamicScalarChangeMoveSelector<S>
28where
29 S: PlanningSolution,
30{
31 pub fn new(slot: DynamicScalarVariableSlot<S>, value_candidate_limit: Option<usize>) -> Self {
32 let leaf = ScalarNeighborhoodLeaf::from_spec(
33 ScalarNeighborhoodSpec::Change {
34 value_candidate_limit,
35 },
36 dynamic_slot(slot),
37 None,
38 )
39 .expect("ordinary dynamic scalar slots always provide a candidate stream");
40 Self { leaf }
41 }
42}
43
44impl<S> Debug for DynamicScalarChangeMoveSelector<S>
45where
46 S: PlanningSolution,
47{
48 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
49 formatter
50 .debug_struct("DynamicScalarChangeMoveSelector")
51 .field("leaf", &self.leaf)
52 .finish()
53 }
54}
55
56impl<S> MoveSelector<S, DynamicScalarChangeMove<S>> for DynamicScalarChangeMoveSelector<S>
57where
58 S: PlanningSolution,
59 S::Score: Score,
60{
61 type Cursor<'a>
62 = DynamicScalarChangeMoveCursor<S>
63 where
64 Self: 'a;
65
66 fn open_cursor<'a, D: Director<S>>(&'a self, director: &D) -> Self::Cursor<'a> {
67 self.open_cursor_with_context(director, MoveStreamContext::default())
68 }
69
70 fn open_cursor_with_context<'a, D: Director<S>>(
71 &'a self,
72 director: &D,
73 context: MoveStreamContext,
74 ) -> Self::Cursor<'a> {
75 let mut stream_state = self.leaf.new_stream_state();
76 RuntimeScalarFacadeCursor::new(
77 self.leaf
78 .open_cursor_with_stream_state(&mut stream_state, director, context),
79 emit_dynamic_scalar_change_move::<S>,
80 )
81 }
82
83 fn size<D: Director<S>>(&self, director: &D) -> usize {
84 let solution = director.working_solution();
85 let mut cursor = self.open_cursor(director);
86 let mut count = 0;
87 while cursor.next_candidate(solution).is_some() {
88 count += 1;
89 }
90 count
91 }
92
93 fn append_moves<D: Director<S>>(
94 &self,
95 director: &D,
96 arena: &mut MoveArena<DynamicScalarChangeMove<S>>,
97 ) {
98 let solution = director.working_solution();
99 let mut cursor = self.open_cursor(director);
100 while let Some(id) = cursor.next_candidate(solution) {
101 arena.push(cursor.take_candidate(id));
102 }
103 }
104}