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