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