solverforge_solver/heuristic/move/
sublist_change.rs1use std::fmt::Debug;
12use std::marker::PhantomData;
13
14use solverforge_core::domain::PlanningSolution;
15use solverforge_scoring::Director;
16
17use super::list_kernel::{
18 sublist_change_candidate_trace_identity, sublist_change_do_move, sublist_change_is_doable,
19 sublist_change_tabu_signature, sublist_change_undo_move, StaticListWindowAccess,
20};
21use super::segment_layout::SegmentRelocationCoords;
22use super::{Move, MoveTabuSignature};
23
24pub struct SublistChangeMove<S, V> {
83 source_entity_index: usize,
85 source_start: usize,
87 source_end: usize,
89 dest_entity_index: usize,
91 dest_position: usize,
93 list_len: fn(&S, usize) -> usize,
94 list_get: fn(&S, usize, usize) -> Option<V>,
95 sublist_remove: fn(&mut S, usize, usize, usize) -> Vec<V>,
97 sublist_insert: fn(&mut S, usize, usize, Vec<V>),
99 variable_name: &'static str,
100 descriptor_index: usize,
101 indices: [usize; 2],
103 _phantom: PhantomData<fn() -> V>,
104}
105
106impl<S, V> Clone for SublistChangeMove<S, V> {
107 fn clone(&self) -> Self {
108 *self
109 }
110}
111
112impl<S, V> Copy for SublistChangeMove<S, V> {}
113
114impl<S, V: Debug> Debug for SublistChangeMove<S, V> {
115 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
116 f.debug_struct("SublistChangeMove")
117 .field("source_entity", &self.source_entity_index)
118 .field("source_range", &(self.source_start..self.source_end))
119 .field("dest_entity", &self.dest_entity_index)
120 .field("dest_position", &self.dest_position)
121 .field("variable_name", &self.variable_name)
122 .finish()
123 }
124}
125
126impl<S, V> SublistChangeMove<S, V> {
127 #[allow(clippy::too_many_arguments)]
142 pub fn new(
143 source_entity_index: usize,
144 source_start: usize,
145 source_end: usize,
146 dest_entity_index: usize,
147 dest_position: usize,
148 list_len: fn(&S, usize) -> usize,
149 list_get: fn(&S, usize, usize) -> Option<V>,
150 sublist_remove: fn(&mut S, usize, usize, usize) -> Vec<V>,
151 sublist_insert: fn(&mut S, usize, usize, Vec<V>),
152 variable_name: &'static str,
153 descriptor_index: usize,
154 ) -> Self {
155 Self {
156 source_entity_index,
157 source_start,
158 source_end,
159 dest_entity_index,
160 dest_position,
161 list_len,
162 list_get,
163 sublist_remove,
164 sublist_insert,
165 variable_name,
166 descriptor_index,
167 indices: [source_entity_index, dest_entity_index],
168 _phantom: PhantomData,
169 }
170 }
171
172 pub fn source_entity_index(&self) -> usize {
173 self.source_entity_index
174 }
175
176 pub fn source_start(&self) -> usize {
177 self.source_start
178 }
179
180 pub fn source_end(&self) -> usize {
181 self.source_end
182 }
183
184 pub fn sublist_len(&self) -> usize {
185 self.source_end.saturating_sub(self.source_start)
186 }
187
188 pub fn dest_entity_index(&self) -> usize {
189 self.dest_entity_index
190 }
191
192 pub fn dest_position(&self) -> usize {
193 self.dest_position
194 }
195
196 pub fn is_intra_list(&self) -> bool {
197 self.source_entity_index == self.dest_entity_index
198 }
199
200 fn access(&self) -> StaticListWindowAccess<S, V> {
201 StaticListWindowAccess {
202 list_len: self.list_len,
203 list_get: self.list_get,
204 sublist_remove: self.sublist_remove,
205 sublist_insert: self.sublist_insert,
206 variable_name: self.variable_name,
207 descriptor_index: self.descriptor_index,
208 }
209 }
210
211 fn coordinates(&self) -> SegmentRelocationCoords {
212 SegmentRelocationCoords::new(
213 self.source_entity_index,
214 self.source_start,
215 self.source_end,
216 self.dest_entity_index,
217 self.dest_position,
218 )
219 }
220}
221
222impl<S, V> Move<S> for SublistChangeMove<S, V>
223where
224 S: PlanningSolution,
225 V: Clone + Send + Sync + Debug + 'static,
226{
227 type Undo = ();
228
229 fn is_doable<D: Director<S>>(&self, score_director: &D) -> bool {
230 sublist_change_is_doable(&self.access(), self.coordinates(), score_director)
231 }
232
233 fn do_move<D: Director<S>>(&self, score_director: &mut D) -> Self::Undo {
234 sublist_change_do_move(&self.access(), self.coordinates(), score_director);
235 }
236
237 fn undo_move<D: Director<S>>(&self, score_director: &mut D, (): Self::Undo) {
238 sublist_change_undo_move(&self.access(), self.coordinates(), score_director);
239 }
240
241 fn descriptor_index(&self) -> usize {
242 self.descriptor_index
243 }
244
245 fn entity_indices(&self) -> &[usize] {
246 if self.is_intra_list() {
247 &self.indices[0..1]
248 } else {
249 &self.indices
250 }
251 }
252
253 fn variable_name(&self) -> &str {
254 self.variable_name
255 }
256
257 fn telemetry_label(&self) -> &'static str {
258 "sublist_change"
259 }
260
261 fn tabu_signature<D: Director<S>>(&self, score_director: &D) -> MoveTabuSignature {
262 sublist_change_tabu_signature(&self.access(), self.coordinates(), score_director)
263 }
264
265 fn candidate_trace_identity(&self) -> Option<crate::stats::CandidateTraceIdentity> {
266 Some(sublist_change_candidate_trace_identity(
267 &self.access(),
268 self.coordinates(),
269 ))
270 }
271}