solverforge_solver/heuristic/move/
list_multi_swap.rs1use std::borrow::Cow;
4use std::fmt::Debug;
5
6use smallvec::SmallVec;
7use solverforge_core::domain::PlanningSolution;
8use solverforge_scoring::Director;
9
10use super::list_kernel::{
11 multi_swap_do_move, multi_swap_entity_indices, multi_swap_is_doable, multi_swap_tabu_signature,
12 multi_swap_undo_move, MultiSwapCoordinates, StaticListSwapAccess,
13};
14use super::{Move, MoveTabuSignature};
15
16pub struct ListMultiSwapMove<S, V> {
22 swaps: MultiSwapCoordinates,
23 access: StaticListSwapAccess<S, V>,
24 indices: SmallVec<[usize; 4]>,
25 require_score_improvement: bool,
26}
27
28impl<S, V: Debug> Debug for ListMultiSwapMove<S, V> {
29 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
30 formatter
31 .debug_struct("ListMultiSwapMove")
32 .field("swaps", &self.swaps)
33 .field("variable_name", &self.access.variable_name)
34 .field("require_score_improvement", &self.require_score_improvement)
35 .finish()
36 }
37}
38
39impl<S, V> ListMultiSwapMove<S, V> {
40 pub fn new(
41 swaps: &[(usize, usize, usize)],
42 list_len: fn(&S, usize) -> usize,
43 list_get: fn(&S, usize, usize) -> Option<V>,
44 list_set: fn(&mut S, usize, usize, V),
45 variable_name: &'static str,
46 descriptor_index: usize,
47 ) -> Self {
48 Self {
49 swaps: swaps.iter().copied().collect(),
50 access: StaticListSwapAccess {
51 list_len,
52 list_get,
53 list_set,
54 variable_name,
55 descriptor_index,
56 },
57 indices: multi_swap_entity_indices(swaps),
58 require_score_improvement: false,
59 }
60 }
61
62 pub fn with_require_score_improvement(mut self, require_score_improvement: bool) -> Self {
63 self.require_score_improvement = require_score_improvement;
64 self
65 }
66
67 pub fn swaps(&self) -> &[(usize, usize, usize)] {
68 &self.swaps
69 }
70}
71
72impl<S, V> Move<S> for ListMultiSwapMove<S, V>
73where
74 S: PlanningSolution,
75 V: Clone + PartialEq + Send + Sync + Debug + 'static,
76{
77 type Undo = ();
78
79 fn is_doable<D: Director<S>>(&self, score_director: &D) -> bool {
80 multi_swap_is_doable(&self.access, &self.swaps, score_director)
81 }
82
83 fn do_move<D: Director<S>>(&self, score_director: &mut D) -> Self::Undo {
84 multi_swap_do_move(&self.access, &self.swaps, &self.indices, score_director)
85 }
86
87 fn undo_move<D: Director<S>>(&self, score_director: &mut D, (): Self::Undo) {
88 multi_swap_undo_move(&self.access, &self.swaps, &self.indices, score_director);
89 }
90
91 fn descriptor_index(&self) -> usize {
92 self.access.descriptor_index
93 }
94
95 fn entity_indices(&self) -> &[usize] {
96 &self.indices
97 }
98
99 fn variable_name(&self) -> &str {
100 self.access.variable_name
101 }
102
103 fn telemetry_label(&self) -> &'static str {
104 "list_multi_swap"
105 }
106
107 fn requires_score_improvement(&self) -> bool {
108 self.require_score_improvement
109 }
110
111 fn tabu_signature<D: Director<S>>(&self, score_director: &D) -> Cow<'_, MoveTabuSignature> {
112 Cow::Owned(multi_swap_tabu_signature(
113 &self.access,
114 &self.swaps,
115 &self.indices,
116 score_director,
117 ))
118 }
119}