solverforge_solver/heuristic/move/
pillar_swap.rs1use std::fmt::Debug;
13
14use solverforge_core::domain::PlanningSolution;
15use solverforge_scoring::Director;
16
17use super::Move;
18
19pub struct PillarSwapMove<S, V> {
28 left_indices: Vec<usize>,
29 right_indices: Vec<usize>,
30 descriptor_index: usize,
31 variable_name: &'static str,
32 getter: fn(&S, usize) -> Option<V>,
34 setter: fn(&mut S, usize, Option<V>),
36}
37
38impl<S, V: Clone> Clone for PillarSwapMove<S, V> {
39 fn clone(&self) -> Self {
40 Self {
41 left_indices: self.left_indices.clone(),
42 right_indices: self.right_indices.clone(),
43 descriptor_index: self.descriptor_index,
44 variable_name: self.variable_name,
45 getter: self.getter,
46 setter: self.setter,
47 }
48 }
49}
50
51impl<S, V: Debug> Debug for PillarSwapMove<S, V> {
52 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
53 f.debug_struct("PillarSwapMove")
54 .field("left_indices", &self.left_indices)
55 .field("right_indices", &self.right_indices)
56 .field("descriptor_index", &self.descriptor_index)
57 .field("variable_name", &self.variable_name)
58 .finish()
59 }
60}
61
62impl<S, V> PillarSwapMove<S, V> {
63 pub fn new(
73 left_indices: Vec<usize>,
74 right_indices: Vec<usize>,
75 getter: fn(&S, usize) -> Option<V>,
76 setter: fn(&mut S, usize, Option<V>),
77 variable_name: &'static str,
78 descriptor_index: usize,
79 ) -> Self {
80 Self {
81 left_indices,
82 right_indices,
83 descriptor_index,
84 variable_name,
85 getter,
86 setter,
87 }
88 }
89
90 pub fn left_indices(&self) -> &[usize] {
91 &self.left_indices
92 }
93
94 pub fn right_indices(&self) -> &[usize] {
95 &self.right_indices
96 }
97}
98
99impl<S, V> Move<S> for PillarSwapMove<S, V>
100where
101 S: PlanningSolution,
102 V: Clone + PartialEq + Send + Sync + Debug + 'static,
103{
104 fn is_doable<D: Director<S>>(&self, score_director: &D) -> bool {
105 if self.left_indices.is_empty() || self.right_indices.is_empty() {
106 return false;
107 }
108
109 let count = score_director.entity_count(self.descriptor_index);
110 let max = count.unwrap_or(0);
111
112 for &idx in self.left_indices.iter().chain(&self.right_indices) {
114 if idx >= max {
115 return false;
116 }
117 }
118
119 let left_val = self
121 .left_indices
122 .first()
123 .map(|&idx| (self.getter)(score_director.working_solution(), idx));
124 let right_val = self
125 .right_indices
126 .first()
127 .map(|&idx| (self.getter)(score_director.working_solution(), idx));
128
129 left_val != right_val
130 }
131
132 fn do_move<D: Director<S>>(&self, score_director: &mut D) {
133 let left_old: Vec<(usize, Option<V>)> = self
135 .left_indices
136 .iter()
137 .map(|&idx| (idx, (self.getter)(score_director.working_solution(), idx)))
138 .collect();
139 let right_old: Vec<(usize, Option<V>)> = self
140 .right_indices
141 .iter()
142 .map(|&idx| (idx, (self.getter)(score_director.working_solution(), idx)))
143 .collect();
144
145 let left_value = left_old.first().and_then(|(_, v)| v.clone());
147 let right_value = right_old.first().and_then(|(_, v)| v.clone());
148
149 for &idx in self.left_indices.iter().chain(&self.right_indices) {
151 score_director.before_variable_changed(self.descriptor_index, idx);
152 }
153
154 for &idx in &self.left_indices {
156 (self.setter)(
157 score_director.working_solution_mut(),
158 idx,
159 right_value.clone(),
160 );
161 }
162 for &idx in &self.right_indices {
164 (self.setter)(
165 score_director.working_solution_mut(),
166 idx,
167 left_value.clone(),
168 );
169 }
170
171 for &idx in self.left_indices.iter().chain(&self.right_indices) {
173 score_director.after_variable_changed(self.descriptor_index, idx);
174 }
175
176 let setter = self.setter;
178 score_director.register_undo(Box::new(move |s: &mut S| {
179 for (idx, old_value) in left_old {
180 setter(s, idx, old_value);
181 }
182 for (idx, old_value) in right_old {
183 setter(s, idx, old_value);
184 }
185 }));
186 }
187
188 fn descriptor_index(&self) -> usize {
189 self.descriptor_index
190 }
191
192 fn entity_indices(&self) -> &[usize] {
193 &self.left_indices
195 }
196
197 fn variable_name(&self) -> &str {
198 self.variable_name
199 }
200}