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