solverforge_solver/heuristic/selector/move_selector/
change.rs1pub struct ChangeMoveSelector<S, V, ES, VS> {
3 entity_selector: ES,
4 value_selector: VS,
5 getter: fn(&S, usize, usize) -> Option<V>,
6 setter: fn(&mut S, usize, usize, Option<V>),
7 descriptor_index: usize,
8 variable_index: usize,
9 variable_name: &'static str,
10 allows_unassigned: bool,
11 _phantom: PhantomData<(fn() -> S, fn() -> V)>,
12}
13
14impl<S, V: Debug, ES: Debug, VS: Debug> Debug for ChangeMoveSelector<S, V, ES, VS> {
15 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
16 f.debug_struct("ChangeMoveSelector")
17 .field("entity_selector", &self.entity_selector)
18 .field("value_selector", &self.value_selector)
19 .field("descriptor_index", &self.descriptor_index)
20 .field("variable_index", &self.variable_index)
21 .field("variable_name", &self.variable_name)
22 .field("allows_unassigned", &self.allows_unassigned)
23 .finish()
24 }
25}
26
27impl<S: PlanningSolution, V: Clone, ES, VS> ChangeMoveSelector<S, V, ES, VS> {
28 pub fn new(
29 entity_selector: ES,
30 value_selector: VS,
31 getter: fn(&S, usize, usize) -> Option<V>,
32 setter: fn(&mut S, usize, usize, Option<V>),
33 descriptor_index: usize,
34 variable_index: usize,
35 variable_name: &'static str,
36 ) -> Self {
37 Self {
38 entity_selector,
39 value_selector,
40 getter,
41 setter,
42 descriptor_index,
43 variable_index,
44 variable_name,
45 allows_unassigned: false,
46 _phantom: PhantomData,
47 }
48 }
49
50 pub fn with_allows_unassigned(mut self, allows_unassigned: bool) -> Self {
51 self.allows_unassigned = allows_unassigned;
52 self
53 }
54}
55
56impl<S: PlanningSolution, V: Clone + Send + Sync + Debug + 'static>
57 ChangeMoveSelector<S, V, FromSolutionEntitySelector, StaticValueSelector<S, V>>
58{
59 pub fn simple(
60 getter: fn(&S, usize, usize) -> Option<V>,
61 setter: fn(&mut S, usize, usize, Option<V>),
62 descriptor_index: usize,
63 variable_index: usize,
64 variable_name: &'static str,
65 values: Vec<V>,
66 ) -> Self {
67 Self {
68 entity_selector: FromSolutionEntitySelector::new(descriptor_index),
69 value_selector: StaticValueSelector::new(values),
70 getter,
71 setter,
72 descriptor_index,
73 variable_index,
74 variable_name,
75 allows_unassigned: false,
76 _phantom: PhantomData,
77 }
78 }
79}
80
81impl<S, V, ES, VS> MoveSelector<S, ChangeMove<S, V>> for ChangeMoveSelector<S, V, ES, VS>
82where
83 S: PlanningSolution,
84 V: Clone + PartialEq + Send + Sync + Debug + 'static,
85 ES: EntitySelector<S>,
86 VS: ValueSelector<S, V>,
87{
88 type Cursor<'a>
89 = ArenaMoveCursor<S, ChangeMove<S, V>>
90 where
91 Self: 'a;
92
93 fn open_cursor<'a, D: Director<S>>(&'a self, score_director: &D) -> Self::Cursor<'a> {
94 let descriptor_index = self.descriptor_index;
95 let variable_index = self.variable_index;
96 let variable_name = self.variable_name;
97 let getter = self.getter;
98 let setter = self.setter;
99 let allows_unassigned = self.allows_unassigned;
100 let value_selector = &self.value_selector;
101 let solution = score_director.working_solution();
102 let entity_values: Vec<_> = self
103 .entity_selector
104 .iter(score_director)
105 .map(|entity_ref| {
106 let current_assigned =
107 getter(solution, entity_ref.entity_index, variable_index).is_some();
108 let values = value_selector.iter(
109 score_director,
110 entity_ref.descriptor_index,
111 entity_ref.entity_index,
112 );
113 (entity_ref, values, current_assigned)
114 })
115 .collect();
116
117 let iter =
118 entity_values
119 .into_iter()
120 .flat_map(move |(entity_ref, values, current_assigned)| {
121 let to_none = (allows_unassigned && current_assigned).then(|| {
122 ChangeMove::new(
123 entity_ref.entity_index,
124 None,
125 getter,
126 setter,
127 variable_index,
128 variable_name,
129 descriptor_index,
130 )
131 });
132 values
133 .map(move |value| {
134 ChangeMove::new(
135 entity_ref.entity_index,
136 Some(value),
137 getter,
138 setter,
139 variable_index,
140 variable_name,
141 descriptor_index,
142 )
143 })
144 .chain(to_none)
145 });
146 ArenaMoveCursor::from_moves(iter)
147 }
148
149 fn size<D: Director<S>>(&self, score_director: &D) -> usize {
150 self.entity_selector
151 .iter(score_director)
152 .map(|entity_ref| {
153 self.value_selector.size(
154 score_director,
155 entity_ref.descriptor_index,
156 entity_ref.entity_index,
157 ) + usize::from(
158 self.allows_unassigned
159 && (self.getter)(
160 score_director.working_solution(),
161 entity_ref.entity_index,
162 self.variable_index,
163 )
164 .is_some(),
165 )
166 })
167 .sum()
168 }
169}
170