1use std::fmt::Debug;
8use std::marker::PhantomData;
9
10use solverforge_core::domain::PlanningSolution;
11use solverforge_scoring::Director;
12
13use crate::heuristic::r#move::MoveArena;
14use crate::heuristic::r#move::{ChangeMove, Move, SwapMove};
15
16use super::entity::{EntityReference, EntitySelector, FromSolutionEntitySelector};
17use super::value_selector::{StaticValueSelector, ValueSelector};
18
19mod either;
20mod list_adapters;
21
22pub use either::{EitherChangeMoveSelector, EitherSwapMoveSelector};
23pub use list_adapters::{
24 ListMoveKOptSelector, ListMoveListChangeSelector, ListMoveListRuinSelector,
25 ListMoveNearbyKOptSelector,
26};
27
28pub trait MoveSelector<S: PlanningSolution, M: Move<S>>: Send + Debug {
37 fn open_cursor<'a, D: Director<S>>(
39 &'a self,
40 score_director: &D,
41 ) -> impl Iterator<Item = M> + 'a;
42
43 fn iter_moves<'a, D: Director<S>>(
45 &'a self,
46 score_director: &D,
47 ) -> impl Iterator<Item = M> + 'a {
48 self.open_cursor(score_director)
49 }
50
51 fn size<D: Director<S>>(&self, score_director: &D) -> usize;
52
53 fn append_moves<D: Director<S>>(&self, score_director: &D, arena: &mut MoveArena<M>) {
54 arena.extend(self.open_cursor(score_director));
55 }
56
57 fn is_never_ending(&self) -> bool {
59 false
60 }
61}
62
63pub struct ChangeMoveSelector<S, V, ES, VS> {
67 entity_selector: ES,
68 value_selector: VS,
69 getter: fn(&S, usize) -> Option<V>,
70 setter: fn(&mut S, usize, Option<V>),
71 descriptor_index: usize,
72 variable_name: &'static str,
73 _phantom: PhantomData<(fn() -> S, fn() -> V)>,
74}
75
76impl<S, V: Debug, ES: Debug, VS: Debug> Debug for ChangeMoveSelector<S, V, ES, VS> {
77 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
78 f.debug_struct("ChangeMoveSelector")
79 .field("entity_selector", &self.entity_selector)
80 .field("value_selector", &self.value_selector)
81 .field("descriptor_index", &self.descriptor_index)
82 .field("variable_name", &self.variable_name)
83 .finish()
84 }
85}
86
87impl<S: PlanningSolution, V: Clone, ES, VS> ChangeMoveSelector<S, V, ES, VS> {
88 pub fn new(
98 entity_selector: ES,
99 value_selector: VS,
100 getter: fn(&S, usize) -> Option<V>,
101 setter: fn(&mut S, usize, Option<V>),
102 descriptor_index: usize,
103 variable_name: &'static str,
104 ) -> Self {
105 Self {
106 entity_selector,
107 value_selector,
108 getter,
109 setter,
110 descriptor_index,
111 variable_name,
112 _phantom: PhantomData,
113 }
114 }
115}
116
117impl<S: PlanningSolution, V: Clone + Send + Sync + Debug + 'static>
118 ChangeMoveSelector<S, V, FromSolutionEntitySelector, StaticValueSelector<S, V>>
119{
120 pub fn simple(
121 getter: fn(&S, usize) -> Option<V>,
122 setter: fn(&mut S, usize, Option<V>),
123 descriptor_index: usize,
124 variable_name: &'static str,
125 values: Vec<V>,
126 ) -> Self {
127 Self {
128 entity_selector: FromSolutionEntitySelector::new(descriptor_index),
129 value_selector: StaticValueSelector::new(values),
130 getter,
131 setter,
132 descriptor_index,
133 variable_name,
134 _phantom: PhantomData,
135 }
136 }
137}
138
139impl<S, V, ES, VS> MoveSelector<S, ChangeMove<S, V>> for ChangeMoveSelector<S, V, ES, VS>
140where
141 S: PlanningSolution,
142 V: Clone + PartialEq + Send + Sync + Debug + 'static,
143 ES: EntitySelector<S>,
144 VS: ValueSelector<S, V>,
145{
146 fn open_cursor<'a, D: Director<S>>(
147 &'a self,
148 score_director: &D,
149 ) -> impl Iterator<Item = ChangeMove<S, V>> + 'a {
150 let descriptor_index = self.descriptor_index;
151 let variable_name = self.variable_name;
152 let getter = self.getter;
153 let setter = self.setter;
154 let value_selector = &self.value_selector;
155 let entity_values: Vec<_> = self
156 .entity_selector
157 .iter(score_director)
158 .map(|entity_ref| {
159 let values = value_selector
160 .iter_typed(
161 score_director,
162 entity_ref.descriptor_index,
163 entity_ref.entity_index,
164 )
165 .collect::<Vec<_>>();
166 (entity_ref, values)
167 })
168 .collect();
169
170 entity_values
171 .into_iter()
172 .flat_map(move |(entity_ref, values)| {
173 values.into_iter().map(move |value| {
174 ChangeMove::new(
175 entity_ref.entity_index,
176 Some(value),
177 getter,
178 setter,
179 variable_name,
180 descriptor_index,
181 )
182 })
183 })
184 }
185
186 fn size<D: Director<S>>(&self, score_director: &D) -> usize {
187 self.entity_selector
188 .iter(score_director)
189 .map(|entity_ref| {
190 self.value_selector.size(
191 score_director,
192 entity_ref.descriptor_index,
193 entity_ref.entity_index,
194 )
195 })
196 .sum()
197 }
198}
199
200pub struct SwapMoveSelector<S, V, LES, RES> {
204 left_entity_selector: LES,
205 right_entity_selector: RES,
206 getter: fn(&S, usize) -> Option<V>,
208 setter: fn(&mut S, usize, Option<V>),
210 descriptor_index: usize,
211 variable_name: &'static str,
212 _phantom: PhantomData<(fn() -> S, fn() -> V)>,
213}
214
215impl<S, V, LES: Debug, RES: Debug> Debug for SwapMoveSelector<S, V, LES, RES> {
216 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
217 f.debug_struct("SwapMoveSelector")
218 .field("left_entity_selector", &self.left_entity_selector)
219 .field("right_entity_selector", &self.right_entity_selector)
220 .field("descriptor_index", &self.descriptor_index)
221 .field("variable_name", &self.variable_name)
222 .finish()
223 }
224}
225
226impl<S: PlanningSolution, V, LES, RES> SwapMoveSelector<S, V, LES, RES> {
227 pub fn new(
228 left_entity_selector: LES,
229 right_entity_selector: RES,
230 getter: fn(&S, usize) -> Option<V>,
231 setter: fn(&mut S, usize, Option<V>),
232 descriptor_index: usize,
233 variable_name: &'static str,
234 ) -> Self {
235 Self {
236 left_entity_selector,
237 right_entity_selector,
238 getter,
239 setter,
240 descriptor_index,
241 variable_name,
242 _phantom: PhantomData,
243 }
244 }
245}
246
247impl<S: PlanningSolution, V>
248 SwapMoveSelector<S, V, FromSolutionEntitySelector, FromSolutionEntitySelector>
249{
250 pub fn simple(
258 getter: fn(&S, usize) -> Option<V>,
259 setter: fn(&mut S, usize, Option<V>),
260 descriptor_index: usize,
261 variable_name: &'static str,
262 ) -> Self {
263 Self {
264 left_entity_selector: FromSolutionEntitySelector::new(descriptor_index),
265 right_entity_selector: FromSolutionEntitySelector::new(descriptor_index),
266 getter,
267 setter,
268 descriptor_index,
269 variable_name,
270 _phantom: PhantomData,
271 }
272 }
273}
274
275impl<S, V, LES, RES> MoveSelector<S, SwapMove<S, V>> for SwapMoveSelector<S, V, LES, RES>
276where
277 S: PlanningSolution,
278 V: Clone + PartialEq + Send + Sync + Debug + 'static,
279 LES: EntitySelector<S>,
280 RES: EntitySelector<S>,
281{
282 fn open_cursor<'a, D: Director<S>>(
283 &'a self,
284 score_director: &D,
285 ) -> impl Iterator<Item = SwapMove<S, V>> + 'a {
286 let descriptor_index = self.descriptor_index;
287 let variable_name = self.variable_name;
288 let getter = self.getter;
289 let setter = self.setter;
290
291 let left_entities: Vec<EntityReference> =
293 self.left_entity_selector.iter(score_director).collect();
294 let right_entities: Vec<EntityReference> =
295 self.right_entity_selector.iter(score_director).collect();
296
297 let mut moves =
299 Vec::with_capacity(left_entities.len() * left_entities.len().saturating_sub(1) / 2);
300 for (i, left) in left_entities.iter().enumerate() {
301 for right in &right_entities[i + 1..] {
302 if left.descriptor_index == right.descriptor_index
303 && left.descriptor_index == descriptor_index
304 {
305 moves.push(SwapMove::new(
306 left.entity_index,
307 right.entity_index,
308 getter,
309 setter,
310 variable_name,
311 descriptor_index,
312 ));
313 }
314 }
315 }
316
317 moves.into_iter()
318 }
319
320 fn size<D: Director<S>>(&self, score_director: &D) -> usize {
321 let left_count = self.left_entity_selector.size(score_director);
322 let right_count = self.right_entity_selector.size(score_director);
323
324 if left_count == right_count {
325 left_count * left_count.saturating_sub(1) / 2
326 } else {
327 left_count * right_count / 2
328 }
329 }
330}
331
332#[cfg(test)]
333#[path = "move_selector_tests.rs"]
334mod tests;