1struct DescriptorEntityValues {
2 entity_index: usize,
3 values: Vec<usize>,
4 current_assigned: bool,
5}
6
7pub struct DescriptorChangeMoveCursor<S>
8where
9 S: PlanningSolution,
10{
11 store: CandidateStore<S, DescriptorMoveUnion<S>>,
12 binding: VariableBinding,
13 solution_descriptor: SolutionDescriptor,
14 entity_values: Vec<DescriptorEntityValues>,
15 entity_offset: usize,
16 value_offset: usize,
17}
18
19impl<S> DescriptorChangeMoveCursor<S>
20where
21 S: PlanningSolution,
22{
23 fn new(
24 binding: VariableBinding,
25 solution_descriptor: SolutionDescriptor,
26 entity_values: Vec<DescriptorEntityValues>,
27 ) -> Self {
28 Self {
29 store: CandidateStore::new(),
30 binding,
31 solution_descriptor,
32 entity_values,
33 entity_offset: 0,
34 value_offset: 0,
35 }
36 }
37}
38
39impl<S> MoveCursor<S, DescriptorMoveUnion<S>> for DescriptorChangeMoveCursor<S>
40where
41 S: PlanningSolution + 'static,
42{
43 fn next_candidate(&mut self, _solution: &S) -> Option<CandidateId> {
44 while let Some(entity_values) = self.entity_values.get(self.entity_offset) {
45 if let Some(value) = entity_values.values.get(self.value_offset).copied() {
46 self.value_offset += 1;
47 return Some(self.store.push(DescriptorMoveUnion::Change(
48 DescriptorChangeMove::new(
49 self.binding.clone(),
50 entity_values.entity_index,
51 Some(value),
52 self.solution_descriptor.clone(),
53 ),
54 )));
55 }
56
57 if self.binding.allows_unassigned
58 && entity_values.current_assigned
59 && self.value_offset == entity_values.values.len()
60 {
61 self.value_offset += 1;
62 return Some(self.store.push(DescriptorMoveUnion::Change(
63 DescriptorChangeMove::new(
64 self.binding.clone(),
65 entity_values.entity_index,
66 None,
67 self.solution_descriptor.clone(),
68 ),
69 )));
70 }
71
72 self.entity_offset += 1;
73 self.value_offset = 0;
74 }
75 None
76 }
77
78 fn candidate(&self, id: CandidateId) -> Option<MoveCandidateRef<'_, S, DescriptorMoveUnion<S>>> {
79 self.store.candidate(id)
80 }
81
82 fn take_candidate(&mut self, id: CandidateId) -> DescriptorMoveUnion<S> {
83 self.store.take_candidate(id)
84 }
85
86 fn release_candidate(&mut self, id: CandidateId) -> bool {
87 self.store.release_candidate(id)
88 }
89}
90
91
92enum DescriptorSwapOrder {
93 All {
94 count: usize,
95 left_entity_index: usize,
96 right_entity_index: usize,
97 },
98 Explicit(std::vec::IntoIter<(usize, usize)>),
99}
100
101pub struct DescriptorSwapMoveCursor<S>
102where
103 S: PlanningSolution,
104{
105 store: CandidateStore<S, DescriptorMoveUnion<S>>,
106 binding: VariableBinding,
107 solution_descriptor: SolutionDescriptor,
108 legality_index: SwapLegalityIndex,
109 order: DescriptorSwapOrder,
110}
111
112impl<S> DescriptorSwapMoveCursor<S>
113where
114 S: PlanningSolution,
115{
116 fn all(
117 binding: VariableBinding,
118 solution_descriptor: SolutionDescriptor,
119 legality_index: SwapLegalityIndex,
120 count: usize,
121 ) -> Self {
122 Self {
123 store: CandidateStore::new(),
124 binding,
125 solution_descriptor,
126 legality_index,
127 order: DescriptorSwapOrder::All {
128 count,
129 left_entity_index: 0,
130 right_entity_index: 1,
131 },
132 }
133 }
134
135 fn explicit(
136 binding: VariableBinding,
137 solution_descriptor: SolutionDescriptor,
138 legality_index: SwapLegalityIndex,
139 pairs: Vec<(usize, usize)>,
140 ) -> Self {
141 Self {
142 store: CandidateStore::new(),
143 binding,
144 solution_descriptor,
145 legality_index,
146 order: DescriptorSwapOrder::Explicit(pairs.into_iter()),
147 }
148 }
149
150 fn next_pair(&mut self) -> Option<(usize, usize)> {
151 match &mut self.order {
152 DescriptorSwapOrder::All {
153 count,
154 left_entity_index,
155 right_entity_index,
156 } => {
157 while *left_entity_index < *count {
158 if *right_entity_index < *count {
159 let pair = (*left_entity_index, *right_entity_index);
160 *right_entity_index += 1;
161 return Some(pair);
162 }
163 *left_entity_index += 1;
164 *right_entity_index = left_entity_index.saturating_add(1);
165 }
166 None
167 }
168 DescriptorSwapOrder::Explicit(pairs) => pairs.next(),
169 }
170 }
171}
172
173impl<S> MoveCursor<S, DescriptorMoveUnion<S>> for DescriptorSwapMoveCursor<S>
174where
175 S: PlanningSolution + 'static,
176{
177 fn next_candidate(&mut self, _solution: &S) -> Option<CandidateId> {
178 while let Some((left_entity_index, right_entity_index)) = self.next_pair() {
179 let Some((left_value, right_value)) = self
180 .legality_index
181 .values_for_swap(left_entity_index, right_entity_index)
182 else {
183 continue;
184 };
185 return Some(self.store.push(DescriptorMoveUnion::Swap(
186 DescriptorSwapMove::new_validated(
187 self.binding.clone(),
188 left_entity_index,
189 left_value,
190 right_entity_index,
191 right_value,
192 self.solution_descriptor.clone(),
193 ),
194 )));
195 }
196 None
197 }
198
199 fn candidate(&self, id: CandidateId) -> Option<MoveCandidateRef<'_, S, DescriptorMoveUnion<S>>> {
200 self.store.candidate(id)
201 }
202
203 fn take_candidate(&mut self, id: CandidateId) -> DescriptorMoveUnion<S> {
204 self.store.take_candidate(id)
205 }
206
207 fn release_candidate(&mut self, id: CandidateId) -> bool {
208 self.store.release_candidate(id)
209 }
210}
211
212
213#[derive(Clone)]
214pub struct DescriptorChangeMoveSelector<S> {
215 binding: VariableBinding,
216 solution_descriptor: SolutionDescriptor,
217 allows_unassigned: bool,
218 value_candidate_limit: Option<usize>,
219 _phantom: PhantomData<fn() -> S>,
220}
221
222impl<S> Debug for DescriptorChangeMoveSelector<S> {
223 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
224 f.debug_struct("DescriptorChangeMoveSelector")
225 .field("binding", &self.binding)
226 .finish()
227 }
228}
229
230impl<S> DescriptorChangeMoveSelector<S> {
231 fn new(
232 binding: VariableBinding,
233 solution_descriptor: SolutionDescriptor,
234 value_candidate_limit: Option<usize>,
235 ) -> Self {
236 let allows_unassigned = binding.allows_unassigned;
237 Self {
238 binding,
239 solution_descriptor,
240 allows_unassigned,
241 value_candidate_limit,
242 _phantom: PhantomData,
243 }
244 }
245}
246
247impl<S> MoveSelector<S, DescriptorMoveUnion<S>> for DescriptorChangeMoveSelector<S>
248where
249 S: PlanningSolution + 'static,
250 S::Score: Score,
251{
252 type Cursor<'a>
253 = DescriptorChangeMoveCursor<S>
254 where
255 Self: 'a;
256
257 fn open_cursor<'a, D: Director<S>>(&'a self, score_director: &D) -> Self::Cursor<'a> {
258 let count = score_director
259 .entity_count(self.binding.descriptor_index)
260 .unwrap_or(0);
261 let solution = score_director.working_solution() as &dyn Any;
262 let entity_values = (0..count)
263 .map(|entity_index| {
264 let entity = self
265 .solution_descriptor
266 .get_entity(solution, self.binding.descriptor_index, entity_index)
267 .expect("entity lookup failed for change selector");
268 DescriptorEntityValues {
269 entity_index,
270 values: self.binding.candidate_values_for_entity_index(
271 &self.solution_descriptor,
272 solution,
273 entity_index,
274 self.value_candidate_limit,
275 ),
276 current_assigned: (self.binding.getter)(entity).is_some(),
277 }
278 })
279 .collect();
280 DescriptorChangeMoveCursor::new(
281 self.binding.clone(),
282 self.solution_descriptor.clone(),
283 entity_values,
284 )
285 }
286
287 fn size<D: Director<S>>(&self, score_director: &D) -> usize {
288 let count = score_director
289 .entity_count(self.binding.descriptor_index)
290 .unwrap_or(0);
291 let mut total = 0;
292 for entity_index in 0..count {
293 let entity = self
294 .solution_descriptor
295 .get_entity(
296 score_director.working_solution() as &dyn Any,
297 self.binding.descriptor_index,
298 entity_index,
299 )
300 .expect("entity lookup failed for change selector");
301 total += self
302 .binding
303 .candidate_values_for_entity_index(
304 &self.solution_descriptor,
305 score_director.working_solution() as &dyn Any,
306 entity_index,
307 self.value_candidate_limit,
308 )
309 .len()
310 + usize::from(self.allows_unassigned && (self.binding.getter)(entity).is_some());
311 }
312 total
313 }
314}
315
316#[derive(Clone)]
317pub struct DescriptorSwapMoveSelector<S> {
318 binding: VariableBinding,
319 solution_descriptor: SolutionDescriptor,
320 _phantom: PhantomData<fn() -> S>,
321}
322
323impl<S> Debug for DescriptorSwapMoveSelector<S> {
324 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
325 f.debug_struct("DescriptorSwapMoveSelector")
326 .field("binding", &self.binding)
327 .finish()
328 }
329}
330
331impl<S> DescriptorSwapMoveSelector<S> {
332 fn new(binding: VariableBinding, solution_descriptor: SolutionDescriptor) -> Self {
333 Self {
334 binding,
335 solution_descriptor,
336 _phantom: PhantomData,
337 }
338 }
339}
340
341impl<S> MoveSelector<S, DescriptorMoveUnion<S>> for DescriptorSwapMoveSelector<S>
342where
343 S: PlanningSolution + 'static,
344 S::Score: Score,
345{
346 type Cursor<'a>
347 = DescriptorSwapMoveCursor<S>
348 where
349 Self: 'a;
350
351 fn open_cursor<'a, D: Director<S>>(&'a self, score_director: &D) -> Self::Cursor<'a> {
352 let count = score_director
353 .entity_count(self.binding.descriptor_index)
354 .unwrap_or(0);
355 let binding = self.binding.clone();
356 let descriptor = self.solution_descriptor.clone();
357 let solution = score_director.working_solution() as &dyn Any;
358 let legality_index = SwapLegalityIndex::new(
359 &binding,
360 &descriptor,
361 solution,
362 count,
363 "entity lookup failed for swap selector",
364 );
365
366 DescriptorSwapMoveCursor::all(binding, descriptor, legality_index, count)
367 }
368
369 fn size<D: Director<S>>(&self, score_director: &D) -> usize {
370 let count = score_director
371 .entity_count(self.binding.descriptor_index)
372 .unwrap_or(0);
373 let solution = score_director.working_solution() as &dyn Any;
374 let legality_index = SwapLegalityIndex::new(
375 &self.binding,
376 &self.solution_descriptor,
377 solution,
378 count,
379 "entity lookup failed for swap selector",
380 );
381 legality_index.count_legal_pairs()
382 }
383}
384
385#[derive(Clone)]
386pub struct DescriptorNearbyChangeMoveSelector<S> {
387 binding: VariableBinding,
388 solution_descriptor: SolutionDescriptor,
389 max_nearby: usize,
390 value_candidate_limit: Option<usize>,
391 _phantom: PhantomData<fn() -> S>,
392}
393
394impl<S> Debug for DescriptorNearbyChangeMoveSelector<S> {
395 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
396 f.debug_struct("DescriptorNearbyChangeMoveSelector")
397 .field("binding", &self.binding)
398 .field("max_nearby", &self.max_nearby)
399 .field("value_candidate_limit", &self.value_candidate_limit)
400 .finish()
401 }
402}
403
404impl<S> MoveSelector<S, DescriptorMoveUnion<S>> for DescriptorNearbyChangeMoveSelector<S>
405where
406 S: PlanningSolution + 'static,
407 S::Score: Score,
408{
409 type Cursor<'a>
410 = DescriptorChangeMoveCursor<S>
411 where
412 Self: 'a;
413
414 fn open_cursor<'a, D: Director<S>>(&'a self, score_director: &D) -> Self::Cursor<'a> {
415 let distance_meter = self.binding.nearby_value_distance_meter;
416 let candidate_values = self
417 .binding
418 .nearby_value_candidates
419 .expect("nearby change requires nearby_value_candidates");
420 let solution = score_director.working_solution() as &dyn Any;
421 let count = score_director
422 .entity_count(self.binding.descriptor_index)
423 .unwrap_or(0);
424 let max_nearby = self.max_nearby;
425 let value_candidate_limit = self.value_candidate_limit;
426 let entity_values = (0..count)
427 .map(|entity_index| {
428 let entity = self
429 .solution_descriptor
430 .get_entity(solution, self.binding.descriptor_index, entity_index)
431 .expect("entity lookup failed for nearby change selector");
432 let current_value = (self.binding.getter)(entity);
433 let current_assigned = current_value.is_some();
434 let values = candidate_values(
435 solution,
436 entity_index,
437 self.binding.variable_index,
438 );
439 let limit = value_candidate_limit.unwrap_or(values.len());
440 let mut candidates: Vec<(usize, f64, usize)> = values
441 .iter()
442 .copied()
443 .take(limit)
444 .enumerate()
445 .filter_map(|(order, value)| {
446 if current_value == Some(value) {
447 return None;
448 }
449 let distance = distance_meter
450 .map(|meter| meter(solution, entity_index, value))
451 .unwrap_or(order as f64);
452 distance.is_finite().then_some((value, distance, order))
453 })
454 .collect();
455 truncate_nearby_candidates(&mut candidates, max_nearby);
456
457 DescriptorEntityValues {
458 entity_index,
459 values: candidates.into_iter().map(|(value, _, _)| value).collect(),
460 current_assigned,
461 }
462 })
463 .collect();
464 DescriptorChangeMoveCursor::new(
465 self.binding.clone(),
466 self.solution_descriptor.clone(),
467 entity_values,
468 )
469 }
470
471 fn size<D: Director<S>>(&self, score_director: &D) -> usize {
472 let solution = score_director.working_solution();
473 let mut cursor = self.open_cursor(score_director);
474 let mut count = 0;
475 while cursor.next_candidate(solution).is_some() {
476 count += 1;
477 }
478 count
479 }
480}
481
482#[derive(Clone)]
483pub struct DescriptorNearbySwapMoveSelector<S> {
484 binding: VariableBinding,
485 solution_descriptor: SolutionDescriptor,
486 max_nearby: usize,
487 _phantom: PhantomData<fn() -> S>,
488}
489
490impl<S> Debug for DescriptorNearbySwapMoveSelector<S> {
491 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
492 f.debug_struct("DescriptorNearbySwapMoveSelector")
493 .field("binding", &self.binding)
494 .field("max_nearby", &self.max_nearby)
495 .finish()
496 }
497}
498
499impl<S> MoveSelector<S, DescriptorMoveUnion<S>> for DescriptorNearbySwapMoveSelector<S>
500where
501 S: PlanningSolution + 'static,
502 S::Score: Score,
503{
504 type Cursor<'a>
505 = DescriptorSwapMoveCursor<S>
506 where
507 Self: 'a;
508
509 fn open_cursor<'a, D: Director<S>>(&'a self, score_director: &D) -> Self::Cursor<'a> {
510 let distance_meter = self.binding.nearby_entity_distance_meter;
511 let entity_candidates = self
512 .binding
513 .nearby_entity_candidates
514 .expect("nearby swap requires nearby_entity_candidates");
515 let solution = score_director.working_solution() as &dyn Any;
516 let count = score_director
517 .entity_count(self.binding.descriptor_index)
518 .unwrap_or(0);
519 let binding = self.binding.clone();
520 let descriptor = self.solution_descriptor.clone();
521 let max_nearby = self.max_nearby;
522 let legality_index = SwapLegalityIndex::new(
523 &binding,
524 &descriptor,
525 solution,
526 count,
527 "entity lookup failed for nearby swap selector",
528 );
529 let mut pairs = Vec::new();
530 for left_entity_index in 0..count {
531 let mut candidates: Vec<(usize, f64, usize)> = entity_candidates(
532 solution,
533 left_entity_index,
534 binding.variable_index,
535 )
536 .iter()
537 .copied()
538 .enumerate()
539 .filter_map(|(order, right_entity_index)| {
540 if right_entity_index <= left_entity_index || right_entity_index >= count {
541 return None;
542 }
543 if !legality_index.can_swap(left_entity_index, right_entity_index) {
544 return None;
545 }
546 let distance = distance_meter
547 .map(|meter| meter(solution, left_entity_index, right_entity_index))
548 .unwrap_or(order as f64);
549 distance
550 .is_finite()
551 .then_some((right_entity_index, distance, order))
552 })
553 .collect();
554 truncate_nearby_candidates(&mut candidates, max_nearby);
555 for (right_entity_index, _, _) in candidates {
556 let Some((left_value, right_value)) =
557 legality_index.values_for_swap(left_entity_index, right_entity_index)
558 else {
559 continue;
560 };
561 let _ = (left_value, right_value);
562 pairs.push((left_entity_index, right_entity_index));
563 }
564 }
565 DescriptorSwapMoveCursor::explicit(binding, descriptor, legality_index, pairs)
566 }
567
568 fn size<D: Director<S>>(&self, score_director: &D) -> usize {
569 let solution = score_director.working_solution();
570 let mut cursor = self.open_cursor(score_director);
571 let mut count = 0;
572 while cursor.next_candidate(solution).is_some() {
573 count += 1;
574 }
575 count
576 }
577}