1use std::fmt::Debug;
8
9use solverforge_core::domain::PlanningSolution;
10use solverforge_scoring::Director;
11
12use crate::stats::CandidateTraceIdentity;
13
14use super::{
15 KOptMove, ListChangeMove, ListMultiSwapMove, ListPermuteMove, ListReverseMove, ListRuinMove,
16 ListSwapMove, Move, MoveTabuSignature, SublistChangeMove, SublistSwapMove,
17};
18
19#[allow(clippy::large_enum_variant)]
33pub enum ListMoveUnion<S, V> {
34 ListChange(ListChangeMove<S, V>),
35 ListSwap(ListSwapMove<S, V>),
36 ListMultiSwap(ListMultiSwapMove<S, V>),
37 ListPermute(ListPermuteMove<S, V>),
38 SublistChange(SublistChangeMove<S, V>),
39 SublistSwap(SublistSwapMove<S, V>),
40 ListReverse(ListReverseMove<S, V>),
41 KOpt(KOptMove<S, V>),
42 ListRuin(ListRuinMove<S, V>),
43}
44
45pub enum ListMoveUnionUndo<S, V>
46where
47 S: PlanningSolution,
48 V: Clone + PartialEq + Send + Sync + Debug + 'static,
49{
50 ListChange(<ListChangeMove<S, V> as Move<S>>::Undo),
51 ListSwap(<ListSwapMove<S, V> as Move<S>>::Undo),
52 ListMultiSwap(<ListMultiSwapMove<S, V> as Move<S>>::Undo),
53 ListPermute(<ListPermuteMove<S, V> as Move<S>>::Undo),
54 SublistChange(<SublistChangeMove<S, V> as Move<S>>::Undo),
55 SublistSwap(<SublistSwapMove<S, V> as Move<S>>::Undo),
56 ListReverse(<ListReverseMove<S, V> as Move<S>>::Undo),
57 KOpt(<KOptMove<S, V> as Move<S>>::Undo),
58 ListRuin(<ListRuinMove<S, V> as Move<S>>::Undo),
59}
60
61impl<S, V> Debug for ListMoveUnion<S, V>
62where
63 S: PlanningSolution,
64 V: Clone + PartialEq + Send + Sync + Debug + 'static,
65{
66 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
67 match self {
68 Self::ListChange(m) => m.fmt(f),
69 Self::ListSwap(m) => m.fmt(f),
70 Self::ListMultiSwap(m) => m.fmt(f),
71 Self::ListPermute(m) => m.fmt(f),
72 Self::SublistChange(m) => m.fmt(f),
73 Self::SublistSwap(m) => m.fmt(f),
74 Self::ListReverse(m) => m.fmt(f),
75 Self::KOpt(m) => m.fmt(f),
76 Self::ListRuin(m) => m.fmt(f),
77 }
78 }
79}
80
81impl<S, V> Move<S> for ListMoveUnion<S, V>
82where
83 S: PlanningSolution,
84 V: Clone + PartialEq + Send + Sync + Debug + 'static,
85{
86 type Undo = ListMoveUnionUndo<S, V>;
87
88 fn is_doable<D: Director<S>>(&self, score_director: &D) -> bool {
89 match self {
90 Self::ListChange(m) => m.is_doable(score_director),
91 Self::ListSwap(m) => m.is_doable(score_director),
92 Self::ListMultiSwap(m) => m.is_doable(score_director),
93 Self::ListPermute(m) => m.is_doable(score_director),
94 Self::SublistChange(m) => m.is_doable(score_director),
95 Self::SublistSwap(m) => m.is_doable(score_director),
96 Self::ListReverse(m) => m.is_doable(score_director),
97 Self::KOpt(m) => m.is_doable(score_director),
98 Self::ListRuin(m) => m.is_doable(score_director),
99 }
100 }
101
102 fn do_move<D: Director<S>>(&self, score_director: &mut D) -> Self::Undo {
103 match self {
104 Self::ListChange(m) => {
105 m.do_move(score_director);
106 ListMoveUnionUndo::ListChange(())
107 }
108 Self::ListSwap(m) => {
109 m.do_move(score_director);
110 ListMoveUnionUndo::ListSwap(())
111 }
112 Self::ListMultiSwap(m) => {
113 m.do_move(score_director);
114 ListMoveUnionUndo::ListMultiSwap(())
115 }
116 Self::ListPermute(m) => ListMoveUnionUndo::ListPermute(m.do_move(score_director)),
117 Self::SublistChange(m) => {
118 m.do_move(score_director);
119 ListMoveUnionUndo::SublistChange(())
120 }
121 Self::SublistSwap(m) => {
122 m.do_move(score_director);
123 ListMoveUnionUndo::SublistSwap(())
124 }
125 Self::ListReverse(m) => {
126 m.do_move(score_director);
127 ListMoveUnionUndo::ListReverse(())
128 }
129 Self::KOpt(m) => ListMoveUnionUndo::KOpt(m.do_move(score_director)),
130 Self::ListRuin(m) => ListMoveUnionUndo::ListRuin(m.do_move(score_director)),
131 }
132 }
133
134 fn do_move_with_scratch<D: Director<S>>(
135 &self,
136 score_director: &mut D,
137 journal_pool: &mut Vec<Self::Undo>,
138 ) -> Self::Undo {
139 match self {
140 Self::KOpt(m) => {
141 let mut journal = journal_pool
145 .iter()
146 .rposition(|undo| matches!(undo, ListMoveUnionUndo::KOpt(_)))
147 .map(|index| match journal_pool.swap_remove(index) {
148 ListMoveUnionUndo::KOpt(journal) => journal,
149 _ => unreachable!("rposition matched the KOpt shape"),
150 })
151 .unwrap_or_default();
152 m.do_move_into_journal(score_director, &mut journal);
153 ListMoveUnionUndo::KOpt(journal)
154 }
155 other => other.do_move(score_director),
156 }
157 }
158
159 fn undo_move_with_scratch<D: Director<S>>(
160 &self,
161 score_director: &mut D,
162 undo: Self::Undo,
163 journal_pool: &mut Vec<Self::Undo>,
164 ) {
165 match (self, undo) {
166 (Self::KOpt(m), ListMoveUnionUndo::KOpt(undo)) => {
167 m.undo_move(score_director, undo);
168 journal_pool.push(ListMoveUnionUndo::KOpt(
169 <KOptMove<S, V> as Move<S>>::Undo::new(),
170 ));
171 }
172 (other, undo) => other.undo_move(score_director, undo),
173 }
174 }
175
176 fn undo_move<D: Director<S>>(&self, score_director: &mut D, undo: Self::Undo) {
177 match (self, undo) {
178 (Self::ListChange(m), ListMoveUnionUndo::ListChange(undo)) => {
179 m.undo_move(score_director, undo)
180 }
181 (Self::ListSwap(m), ListMoveUnionUndo::ListSwap(undo)) => {
182 m.undo_move(score_director, undo)
183 }
184 (Self::ListMultiSwap(m), ListMoveUnionUndo::ListMultiSwap(undo)) => {
185 m.undo_move(score_director, undo)
186 }
187 (Self::ListPermute(m), ListMoveUnionUndo::ListPermute(undo)) => {
188 m.undo_move(score_director, undo)
189 }
190 (Self::SublistChange(m), ListMoveUnionUndo::SublistChange(undo)) => {
191 m.undo_move(score_director, undo)
192 }
193 (Self::SublistSwap(m), ListMoveUnionUndo::SublistSwap(undo)) => {
194 m.undo_move(score_director, undo)
195 }
196 (Self::ListReverse(m), ListMoveUnionUndo::ListReverse(undo)) => {
197 m.undo_move(score_director, undo)
198 }
199 (Self::KOpt(m), ListMoveUnionUndo::KOpt(undo)) => m.undo_move(score_director, undo),
200 (Self::ListRuin(m), ListMoveUnionUndo::ListRuin(undo)) => {
201 m.undo_move(score_director, undo)
202 }
203 _ => panic!("list move undo shape must match move shape"),
204 }
205 }
206
207 fn descriptor_index(&self) -> usize {
208 match self {
209 Self::ListChange(m) => m.descriptor_index(),
210 Self::ListSwap(m) => m.descriptor_index(),
211 Self::ListMultiSwap(m) => m.descriptor_index(),
212 Self::ListPermute(m) => m.descriptor_index(),
213 Self::SublistChange(m) => m.descriptor_index(),
214 Self::SublistSwap(m) => m.descriptor_index(),
215 Self::ListReverse(m) => m.descriptor_index(),
216 Self::KOpt(m) => m.descriptor_index(),
217 Self::ListRuin(m) => m.descriptor_index(),
218 }
219 }
220
221 fn entity_indices(&self) -> &[usize] {
222 match self {
223 Self::ListChange(m) => m.entity_indices(),
224 Self::ListSwap(m) => m.entity_indices(),
225 Self::ListMultiSwap(m) => m.entity_indices(),
226 Self::ListPermute(m) => m.entity_indices(),
227 Self::SublistChange(m) => m.entity_indices(),
228 Self::SublistSwap(m) => m.entity_indices(),
229 Self::ListReverse(m) => m.entity_indices(),
230 Self::KOpt(m) => m.entity_indices(),
231 Self::ListRuin(m) => m.entity_indices(),
232 }
233 }
234
235 fn variable_name(&self) -> &str {
236 match self {
237 Self::ListChange(m) => m.variable_name(),
238 Self::ListSwap(m) => m.variable_name(),
239 Self::ListMultiSwap(m) => m.variable_name(),
240 Self::ListPermute(m) => m.variable_name(),
241 Self::SublistChange(m) => m.variable_name(),
242 Self::SublistSwap(m) => m.variable_name(),
243 Self::ListReverse(m) => m.variable_name(),
244 Self::KOpt(m) => m.variable_name(),
245 Self::ListRuin(m) => m.variable_name(),
246 }
247 }
248
249 fn telemetry_label(&self) -> &'static str {
250 match self {
251 Self::ListChange(m) => m.telemetry_label(),
252 Self::ListSwap(m) => m.telemetry_label(),
253 Self::ListMultiSwap(m) => m.telemetry_label(),
254 Self::ListPermute(m) => m.telemetry_label(),
255 Self::SublistChange(m) => m.telemetry_label(),
256 Self::SublistSwap(m) => m.telemetry_label(),
257 Self::ListReverse(m) => m.telemetry_label(),
258 Self::KOpt(m) => m.telemetry_label(),
259 Self::ListRuin(m) => m.telemetry_label(),
260 }
261 }
262
263 fn requires_hard_improvement(&self) -> bool {
264 match self {
265 Self::ListChange(m) => m.requires_hard_improvement(),
266 Self::ListSwap(m) => m.requires_hard_improvement(),
267 Self::ListMultiSwap(m) => m.requires_hard_improvement(),
268 Self::ListPermute(m) => m.requires_hard_improvement(),
269 Self::SublistChange(m) => m.requires_hard_improvement(),
270 Self::SublistSwap(m) => m.requires_hard_improvement(),
271 Self::ListReverse(m) => m.requires_hard_improvement(),
272 Self::KOpt(m) => m.requires_hard_improvement(),
273 Self::ListRuin(m) => m.requires_hard_improvement(),
274 }
275 }
276
277 fn requires_score_improvement(&self) -> bool {
278 match self {
279 Self::ListChange(m) => m.requires_score_improvement(),
280 Self::ListSwap(m) => m.requires_score_improvement(),
281 Self::ListMultiSwap(m) => m.requires_score_improvement(),
282 Self::ListPermute(m) => m.requires_score_improvement(),
283 Self::SublistChange(m) => m.requires_score_improvement(),
284 Self::SublistSwap(m) => m.requires_score_improvement(),
285 Self::ListReverse(m) => m.requires_score_improvement(),
286 Self::KOpt(m) => m.requires_score_improvement(),
287 Self::ListRuin(m) => m.requires_score_improvement(),
288 }
289 }
290
291 fn borrowed_tabu_signature(&self) -> Option<&MoveTabuSignature> {
292 match self {
293 Self::ListChange(m) => m.borrowed_tabu_signature(),
294 Self::ListSwap(m) => m.borrowed_tabu_signature(),
295 Self::ListMultiSwap(m) => m.borrowed_tabu_signature(),
296 Self::ListPermute(m) => m.borrowed_tabu_signature(),
297 Self::SublistChange(m) => m.borrowed_tabu_signature(),
298 Self::SublistSwap(m) => m.borrowed_tabu_signature(),
299 Self::ListReverse(m) => m.borrowed_tabu_signature(),
300 Self::KOpt(m) => m.borrowed_tabu_signature(),
301 Self::ListRuin(m) => m.borrowed_tabu_signature(),
302 }
303 }
304
305 fn tabu_signature<D: Director<S>>(&self, score_director: &D) -> MoveTabuSignature {
306 match self {
307 Self::ListChange(m) => m.tabu_signature(score_director),
308 Self::ListSwap(m) => m.tabu_signature(score_director),
309 Self::ListMultiSwap(m) => m.tabu_signature(score_director),
310 Self::ListPermute(m) => m.tabu_signature(score_director),
311 Self::SublistChange(m) => m.tabu_signature(score_director),
312 Self::SublistSwap(m) => m.tabu_signature(score_director),
313 Self::ListReverse(m) => m.tabu_signature(score_director),
314 Self::KOpt(m) => m.tabu_signature(score_director),
315 Self::ListRuin(m) => m.tabu_signature(score_director),
316 }
317 }
318
319 fn candidate_trace_identity(&self) -> Option<CandidateTraceIdentity> {
320 match self {
321 Self::ListChange(m) => m.candidate_trace_identity(),
322 Self::ListSwap(m) => m.candidate_trace_identity(),
323 Self::ListMultiSwap(m) => m.candidate_trace_identity(),
324 Self::ListPermute(m) => m.candidate_trace_identity(),
325 Self::SublistChange(m) => m.candidate_trace_identity(),
326 Self::SublistSwap(m) => m.candidate_trace_identity(),
327 Self::ListReverse(m) => m.candidate_trace_identity(),
328 Self::KOpt(m) => m.candidate_trace_identity(),
329 Self::ListRuin(m) => m.candidate_trace_identity(),
330 }
331 }
332}