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 allows_unassigned: bool,
74 _phantom: PhantomData<(fn() -> S, fn() -> V)>,
75}
76
77impl<S, V: Debug, ES: Debug, VS: Debug> Debug for ChangeMoveSelector<S, V, ES, VS> {
78 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
79 f.debug_struct("ChangeMoveSelector")
80 .field("entity_selector", &self.entity_selector)
81 .field("value_selector", &self.value_selector)
82 .field("descriptor_index", &self.descriptor_index)
83 .field("variable_name", &self.variable_name)
84 .field("allows_unassigned", &self.allows_unassigned)
85 .finish()
86 }
87}
88
89impl<S: PlanningSolution, V: Clone, ES, VS> ChangeMoveSelector<S, V, ES, VS> {
90 pub fn new(
100 entity_selector: ES,
101 value_selector: VS,
102 getter: fn(&S, usize) -> Option<V>,
103 setter: fn(&mut S, usize, Option<V>),
104 descriptor_index: usize,
105 variable_name: &'static str,
106 ) -> Self {
107 Self {
108 entity_selector,
109 value_selector,
110 getter,
111 setter,
112 descriptor_index,
113 variable_name,
114 allows_unassigned: false,
115 _phantom: PhantomData,
116 }
117 }
118
119 pub fn with_allows_unassigned(mut self, allows_unassigned: bool) -> Self {
120 self.allows_unassigned = allows_unassigned;
121 self
122 }
123}
124
125impl<S: PlanningSolution, V: Clone + Send + Sync + Debug + 'static>
126 ChangeMoveSelector<S, V, FromSolutionEntitySelector, StaticValueSelector<S, V>>
127{
128 pub fn simple(
129 getter: fn(&S, usize) -> Option<V>,
130 setter: fn(&mut S, usize, Option<V>),
131 descriptor_index: usize,
132 variable_name: &'static str,
133 values: Vec<V>,
134 ) -> Self {
135 Self {
136 entity_selector: FromSolutionEntitySelector::new(descriptor_index),
137 value_selector: StaticValueSelector::new(values),
138 getter,
139 setter,
140 descriptor_index,
141 variable_name,
142 allows_unassigned: false,
143 _phantom: PhantomData,
144 }
145 }
146}
147
148impl<S, V, ES, VS> MoveSelector<S, ChangeMove<S, V>> for ChangeMoveSelector<S, V, ES, VS>
149where
150 S: PlanningSolution,
151 V: Clone + PartialEq + Send + Sync + Debug + 'static,
152 ES: EntitySelector<S>,
153 VS: ValueSelector<S, V>,
154{
155 fn open_cursor<'a, D: Director<S>>(
156 &'a self,
157 score_director: &D,
158 ) -> impl Iterator<Item = ChangeMove<S, V>> + 'a {
159 let descriptor_index = self.descriptor_index;
160 let variable_name = self.variable_name;
161 let getter = self.getter;
162 let setter = self.setter;
163 let allows_unassigned = self.allows_unassigned;
164 let value_selector = &self.value_selector;
165 let solution = score_director.working_solution();
166 let entity_values: Vec<_> = self
167 .entity_selector
168 .iter(score_director)
169 .map(|entity_ref| {
170 let current_assigned = getter(solution, entity_ref.entity_index).is_some();
171 let values = value_selector.iter_typed(
172 score_director,
173 entity_ref.descriptor_index,
174 entity_ref.entity_index,
175 );
176 (entity_ref, values, current_assigned)
177 })
178 .collect();
179
180 entity_values
181 .into_iter()
182 .flat_map(move |(entity_ref, values, current_assigned)| {
183 let to_none = (allows_unassigned && current_assigned).then(|| {
184 ChangeMove::new(
185 entity_ref.entity_index,
186 None,
187 getter,
188 setter,
189 variable_name,
190 descriptor_index,
191 )
192 });
193 values
194 .map(move |value| {
195 ChangeMove::new(
196 entity_ref.entity_index,
197 Some(value),
198 getter,
199 setter,
200 variable_name,
201 descriptor_index,
202 )
203 })
204 .chain(to_none)
205 })
206 }
207
208 fn size<D: Director<S>>(&self, score_director: &D) -> usize {
209 self.entity_selector
210 .iter(score_director)
211 .map(|entity_ref| {
212 self.value_selector.size(
213 score_director,
214 entity_ref.descriptor_index,
215 entity_ref.entity_index,
216 ) + usize::from(
217 self.allows_unassigned
218 && (self.getter)(
219 score_director.working_solution(),
220 entity_ref.entity_index,
221 )
222 .is_some(),
223 )
224 })
225 .sum()
226 }
227}
228
229pub struct SwapMoveSelector<S, V, LES, RES> {
233 left_entity_selector: LES,
234 right_entity_selector: RES,
235 getter: fn(&S, usize) -> Option<V>,
237 setter: fn(&mut S, usize, Option<V>),
239 descriptor_index: usize,
240 variable_name: &'static str,
241 _phantom: PhantomData<(fn() -> S, fn() -> V)>,
242}
243
244impl<S, V, LES: Debug, RES: Debug> Debug for SwapMoveSelector<S, V, LES, RES> {
245 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
246 f.debug_struct("SwapMoveSelector")
247 .field("left_entity_selector", &self.left_entity_selector)
248 .field("right_entity_selector", &self.right_entity_selector)
249 .field("descriptor_index", &self.descriptor_index)
250 .field("variable_name", &self.variable_name)
251 .finish()
252 }
253}
254
255impl<S: PlanningSolution, V, LES, RES> SwapMoveSelector<S, V, LES, RES> {
256 pub fn new(
257 left_entity_selector: LES,
258 right_entity_selector: RES,
259 getter: fn(&S, usize) -> Option<V>,
260 setter: fn(&mut S, usize, Option<V>),
261 descriptor_index: usize,
262 variable_name: &'static str,
263 ) -> Self {
264 Self {
265 left_entity_selector,
266 right_entity_selector,
267 getter,
268 setter,
269 descriptor_index,
270 variable_name,
271 _phantom: PhantomData,
272 }
273 }
274}
275
276impl<S: PlanningSolution, V>
277 SwapMoveSelector<S, V, FromSolutionEntitySelector, FromSolutionEntitySelector>
278{
279 pub fn simple(
287 getter: fn(&S, usize) -> Option<V>,
288 setter: fn(&mut S, usize, Option<V>),
289 descriptor_index: usize,
290 variable_name: &'static str,
291 ) -> Self {
292 Self {
293 left_entity_selector: FromSolutionEntitySelector::new(descriptor_index),
294 right_entity_selector: FromSolutionEntitySelector::new(descriptor_index),
295 getter,
296 setter,
297 descriptor_index,
298 variable_name,
299 _phantom: PhantomData,
300 }
301 }
302}
303
304impl<S, V, LES, RES> MoveSelector<S, SwapMove<S, V>> for SwapMoveSelector<S, V, LES, RES>
305where
306 S: PlanningSolution,
307 V: Clone + PartialEq + Send + Sync + Debug + 'static,
308 LES: EntitySelector<S>,
309 RES: EntitySelector<S>,
310{
311 fn open_cursor<'a, D: Director<S>>(
312 &'a self,
313 score_director: &D,
314 ) -> impl Iterator<Item = SwapMove<S, V>> + 'a {
315 let descriptor_index = self.descriptor_index;
316 let variable_name = self.variable_name;
317 let getter = self.getter;
318 let setter = self.setter;
319
320 let left_entities: Vec<EntityReference> =
322 self.left_entity_selector.iter(score_director).collect();
323 let right_entities: Vec<EntityReference> =
324 self.right_entity_selector.iter(score_director).collect();
325
326 let mut moves =
328 Vec::with_capacity(left_entities.len() * left_entities.len().saturating_sub(1) / 2);
329 for (i, left) in left_entities.iter().enumerate() {
330 for right in &right_entities[i + 1..] {
331 if left.descriptor_index == right.descriptor_index
332 && left.descriptor_index == descriptor_index
333 {
334 moves.push(SwapMove::new(
335 left.entity_index,
336 right.entity_index,
337 getter,
338 setter,
339 variable_name,
340 descriptor_index,
341 ));
342 }
343 }
344 }
345
346 moves.into_iter()
347 }
348
349 fn size<D: Director<S>>(&self, score_director: &D) -> usize {
350 let left_count = self.left_entity_selector.size(score_director);
351 let right_count = self.right_entity_selector.size(score_director);
352
353 if left_count == right_count {
354 left_count * left_count.saturating_sub(1) / 2
355 } else {
356 left_count * right_count / 2
357 }
358 }
359}