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::{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 self.open_cursor(director).count()
85 }
86
87 fn append_moves<D: Director<S>>(
88 &self,
89 director: &D,
90 arena: &mut MoveArena<DynamicScalarChangeMove<S>>,
91 ) {
92 arena.extend(self.open_cursor(director));
93 }
94}