solverforge_solver/heuristic/move/
list_change.rs1use std::borrow::Cow;
12use std::fmt::Debug;
13
14use solverforge_core::domain::PlanningSolution;
15use solverforge_scoring::Director;
16
17use super::list_kernel::{
18 change_candidate_trace_identity, change_do_move, change_is_doable, change_tabu_signature,
19 change_undo_move, ChangeCoordinates, StaticListChangeAccess,
20};
21use super::{Move, MoveTabuSignature};
22
23pub struct ListChangeMove<S, V> {
75 source_entity_index: usize,
77 source_position: usize,
79 dest_entity_index: usize,
81 dest_position: usize,
83 list_len: fn(&S, usize) -> usize,
84 list_get: fn(&S, usize, usize) -> Option<V>,
85 list_remove: fn(&mut S, usize, usize) -> Option<V>,
87 list_insert: fn(&mut S, usize, usize, V),
89 variable_name: &'static str,
90 descriptor_index: usize,
91 indices: [usize; 2],
93}
94
95impl<S, V> Clone for ListChangeMove<S, V> {
96 fn clone(&self) -> Self {
97 *self
98 }
99}
100
101impl<S, V> Copy for ListChangeMove<S, V> {}
102
103impl<S, V: Debug> Debug for ListChangeMove<S, V> {
104 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
105 f.debug_struct("ListChangeMove")
106 .field("source_entity", &self.source_entity_index)
107 .field("source_position", &self.source_position)
108 .field("dest_entity", &self.dest_entity_index)
109 .field("dest_position", &self.dest_position)
110 .field("variable_name", &self.variable_name)
111 .finish()
112 }
113}
114
115impl<S, V> ListChangeMove<S, V> {
116 #[allow(clippy::too_many_arguments)]
130 pub fn new(
131 source_entity_index: usize,
132 source_position: usize,
133 dest_entity_index: usize,
134 dest_position: usize,
135 list_len: fn(&S, usize) -> usize,
136 list_get: fn(&S, usize, usize) -> Option<V>,
137 list_remove: fn(&mut S, usize, usize) -> Option<V>,
138 list_insert: fn(&mut S, usize, usize, V),
139 variable_name: &'static str,
140 descriptor_index: usize,
141 ) -> Self {
142 Self {
143 source_entity_index,
144 source_position,
145 dest_entity_index,
146 dest_position,
147 list_len,
148 list_get,
149 list_remove,
150 list_insert,
151 variable_name,
152 descriptor_index,
153 indices: [source_entity_index, dest_entity_index],
154 }
155 }
156
157 pub fn source_entity_index(&self) -> usize {
158 self.source_entity_index
159 }
160
161 pub fn source_position(&self) -> usize {
162 self.source_position
163 }
164
165 pub fn dest_entity_index(&self) -> usize {
166 self.dest_entity_index
167 }
168
169 pub fn dest_position(&self) -> usize {
170 self.dest_position
171 }
172
173 pub fn is_intra_list(&self) -> bool {
174 self.source_entity_index == self.dest_entity_index
175 }
176
177 fn access(&self) -> StaticListChangeAccess<S, V> {
178 StaticListChangeAccess {
179 list_len: self.list_len,
180 list_get: self.list_get,
181 list_remove: self.list_remove,
182 list_insert: self.list_insert,
183 variable_name: self.variable_name,
184 descriptor_index: self.descriptor_index,
185 }
186 }
187
188 fn coordinates(&self) -> ChangeCoordinates {
189 ChangeCoordinates {
190 source_entity: self.source_entity_index,
191 source_position: self.source_position,
192 destination_entity: self.dest_entity_index,
193 destination_position: self.dest_position,
194 }
195 }
196}
197
198impl<S, V> Move<S> for ListChangeMove<S, V>
199where
200 S: PlanningSolution,
201 V: Clone + PartialEq + Send + Sync + Debug + 'static,
202{
203 type Undo = ();
204
205 fn is_doable<D: Director<S>>(&self, score_director: &D) -> bool {
206 change_is_doable(&self.access(), self.coordinates(), score_director)
207 }
208
209 fn do_move<D: Director<S>>(&self, score_director: &mut D) -> Self::Undo {
210 change_do_move(&self.access(), self.coordinates(), score_director);
211 }
212
213 fn undo_move<D: Director<S>>(&self, score_director: &mut D, (): Self::Undo) {
214 change_undo_move(&self.access(), self.coordinates(), score_director);
215 }
216
217 fn descriptor_index(&self) -> usize {
218 self.descriptor_index
219 }
220
221 fn entity_indices(&self) -> &[usize] {
222 if self.is_intra_list() {
223 &self.indices[0..1]
224 } else {
225 &self.indices
226 }
227 }
228
229 fn variable_name(&self) -> &str {
230 self.variable_name
231 }
232
233 fn telemetry_label(&self) -> &'static str {
234 "list_change"
235 }
236
237 fn tabu_signature<D: Director<S>>(&self, score_director: &D) -> Cow<'_, MoveTabuSignature> {
238 Cow::Owned(change_tabu_signature(
239 &self.access(),
240 self.coordinates(),
241 score_director,
242 ))
243 }
244
245 fn candidate_trace_identity(&self) -> Option<crate::stats::CandidateTraceIdentity> {
246 Some(change_candidate_trace_identity(
247 &self.access(),
248 self.coordinates(),
249 ))
250 }
251}