solverforge_solver/heuristic/move/
swap.rs1use std::fmt::Debug;
13
14use solverforge_core::domain::PlanningSolution;
15use solverforge_scoring::Director;
16
17use super::metadata::{
18 encode_option_debug, encode_usize, ordered_coordinate_pair, scoped_move_identity,
19 MoveTabuScope, TABU_OP_SWAP,
20};
21use super::{Move, MoveTabuSignature};
22
23pub struct SwapMove<S, V> {
55 left_entity_index: usize,
56 right_entity_index: usize,
57 getter: fn(&S, usize, usize) -> Option<V>,
59 setter: fn(&mut S, usize, usize, Option<V>),
61 variable_index: usize,
62 variable_name: &'static str,
63 descriptor_index: usize,
64 indices: [usize; 2],
66}
67
68impl<S, V> Clone for SwapMove<S, V> {
69 fn clone(&self) -> Self {
70 *self
71 }
72}
73
74impl<S, V> Copy for SwapMove<S, V> {}
75
76impl<S, V: Debug> Debug for SwapMove<S, V> {
77 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
78 f.debug_struct("SwapMove")
79 .field("left_entity_index", &self.left_entity_index)
80 .field("right_entity_index", &self.right_entity_index)
81 .field("descriptor_index", &self.descriptor_index)
82 .field("variable_index", &self.variable_index)
83 .field("variable_name", &self.variable_name)
84 .finish()
85 }
86}
87
88impl<S, V> SwapMove<S, V> {
89 pub fn new(
99 left_entity_index: usize,
100 right_entity_index: usize,
101 getter: fn(&S, usize, usize) -> Option<V>,
102 setter: fn(&mut S, usize, usize, Option<V>),
103 variable_index: usize,
104 variable_name: &'static str,
105 descriptor_index: usize,
106 ) -> Self {
107 Self {
108 left_entity_index,
109 right_entity_index,
110 getter,
111 setter,
112 variable_index,
113 variable_name,
114 descriptor_index,
115 indices: [left_entity_index, right_entity_index],
116 }
117 }
118
119 pub fn left_entity_index(&self) -> usize {
120 self.left_entity_index
121 }
122
123 pub fn right_entity_index(&self) -> usize {
124 self.right_entity_index
125 }
126}
127
128impl<S, V> Move<S> for SwapMove<S, V>
129where
130 S: PlanningSolution,
131 V: Clone + PartialEq + Send + Sync + Debug + 'static,
132{
133 type Undo = (Option<V>, Option<V>);
134
135 fn is_doable<D: Director<S>>(&self, score_director: &D) -> bool {
136 if self.left_entity_index == self.right_entity_index {
138 return false;
139 }
140
141 let left_val = (self.getter)(
143 score_director.working_solution(),
144 self.left_entity_index,
145 self.variable_index,
146 );
147 let right_val = (self.getter)(
148 score_director.working_solution(),
149 self.right_entity_index,
150 self.variable_index,
151 );
152
153 left_val != right_val
155 }
156
157 fn do_move<D: Director<S>>(&self, score_director: &mut D) -> Self::Undo {
158 let left_value = (self.getter)(
160 score_director.working_solution(),
161 self.left_entity_index,
162 self.variable_index,
163 );
164 let right_value = (self.getter)(
165 score_director.working_solution(),
166 self.right_entity_index,
167 self.variable_index,
168 );
169
170 score_director.before_variable_changed(self.descriptor_index, self.left_entity_index);
172 score_director.before_variable_changed(self.descriptor_index, self.right_entity_index);
173
174 (self.setter)(
176 score_director.working_solution_mut(),
177 self.left_entity_index,
178 self.variable_index,
179 right_value.clone(),
180 );
181 (self.setter)(
182 score_director.working_solution_mut(),
183 self.right_entity_index,
184 self.variable_index,
185 left_value.clone(),
186 );
187
188 score_director.after_variable_changed(self.descriptor_index, self.left_entity_index);
190 score_director.after_variable_changed(self.descriptor_index, self.right_entity_index);
191
192 (left_value, right_value)
193 }
194
195 fn undo_move<D: Director<S>>(&self, score_director: &mut D, undo: Self::Undo) {
196 score_director.before_variable_changed(self.descriptor_index, self.left_entity_index);
197 score_director.before_variable_changed(self.descriptor_index, self.right_entity_index);
198 (self.setter)(
199 score_director.working_solution_mut(),
200 self.left_entity_index,
201 self.variable_index,
202 undo.0,
203 );
204 (self.setter)(
205 score_director.working_solution_mut(),
206 self.right_entity_index,
207 self.variable_index,
208 undo.1,
209 );
210 score_director.after_variable_changed(self.descriptor_index, self.left_entity_index);
211 score_director.after_variable_changed(self.descriptor_index, self.right_entity_index);
212 }
213
214 fn descriptor_index(&self) -> usize {
215 self.descriptor_index
216 }
217
218 fn entity_indices(&self) -> &[usize] {
219 &self.indices
220 }
221
222 fn variable_name(&self) -> &str {
223 self.variable_name
224 }
225
226 fn tabu_signature<D: Director<S>>(&self, score_director: &D) -> MoveTabuSignature {
227 let left_val = (self.getter)(
228 score_director.working_solution(),
229 self.left_entity_index,
230 self.variable_index,
231 );
232 let right_val = (self.getter)(
233 score_director.working_solution(),
234 self.right_entity_index,
235 self.variable_index,
236 );
237 let left_id = encode_option_debug(left_val.as_ref());
238 let right_id = encode_option_debug(right_val.as_ref());
239 let left_entity_id = encode_usize(self.left_entity_index);
240 let right_entity_id = encode_usize(self.right_entity_index);
241 let scope = MoveTabuScope::new(self.descriptor_index, self.variable_name);
242 let entity_pair = ordered_coordinate_pair((left_entity_id, 0), (right_entity_id, 0));
243 let move_id = scoped_move_identity(
244 scope,
245 TABU_OP_SWAP,
246 entity_pair.into_iter().map(|(entity_id, _)| entity_id),
247 );
248
249 MoveTabuSignature::new(scope, move_id.clone(), move_id)
250 .with_entity_tokens([
251 scope.entity_token(left_entity_id),
252 scope.entity_token(right_entity_id),
253 ])
254 .with_destination_value_tokens([
255 scope.value_token(right_id),
256 scope.value_token(left_id),
257 ])
258 }
259}