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> Clone for ListMoveUnion<S, V>
62where
63 S: PlanningSolution,
64 V: Clone + PartialEq + Send + Sync + Debug + 'static,
65{
66 fn clone(&self) -> Self {
67 match self {
68 Self::ListChange(m) => Self::ListChange(*m),
69 Self::ListSwap(m) => Self::ListSwap(*m),
70 Self::ListMultiSwap(m) => Self::ListMultiSwap(m.clone()),
71 Self::ListPermute(m) => Self::ListPermute(m.clone()),
72 Self::SublistChange(m) => Self::SublistChange(*m),
73 Self::SublistSwap(m) => Self::SublistSwap(*m),
74 Self::ListReverse(m) => Self::ListReverse(*m),
75 Self::KOpt(m) => Self::KOpt(m.clone()),
76 Self::ListRuin(m) => Self::ListRuin(m.clone()),
77 }
78 }
79}
80
81impl<S, V> Debug for ListMoveUnion<S, V>
82where
83 S: PlanningSolution,
84 V: Clone + PartialEq + Send + Sync + Debug + 'static,
85{
86 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
87 match self {
88 Self::ListChange(m) => m.fmt(f),
89 Self::ListSwap(m) => m.fmt(f),
90 Self::ListMultiSwap(m) => m.fmt(f),
91 Self::ListPermute(m) => m.fmt(f),
92 Self::SublistChange(m) => m.fmt(f),
93 Self::SublistSwap(m) => m.fmt(f),
94 Self::ListReverse(m) => m.fmt(f),
95 Self::KOpt(m) => m.fmt(f),
96 Self::ListRuin(m) => m.fmt(f),
97 }
98 }
99}
100
101impl<S, V> Move<S> for ListMoveUnion<S, V>
102where
103 S: PlanningSolution,
104 V: Clone + PartialEq + Send + Sync + Debug + 'static,
105{
106 type Undo = ListMoveUnionUndo<S, V>;
107
108 fn is_doable<D: Director<S>>(&self, score_director: &D) -> bool {
109 match self {
110 Self::ListChange(m) => m.is_doable(score_director),
111 Self::ListSwap(m) => m.is_doable(score_director),
112 Self::ListMultiSwap(m) => m.is_doable(score_director),
113 Self::ListPermute(m) => m.is_doable(score_director),
114 Self::SublistChange(m) => m.is_doable(score_director),
115 Self::SublistSwap(m) => m.is_doable(score_director),
116 Self::ListReverse(m) => m.is_doable(score_director),
117 Self::KOpt(m) => m.is_doable(score_director),
118 Self::ListRuin(m) => m.is_doable(score_director),
119 }
120 }
121
122 fn do_move<D: Director<S>>(&self, score_director: &mut D) -> Self::Undo {
123 match self {
124 Self::ListChange(m) => {
125 m.do_move(score_director);
126 ListMoveUnionUndo::ListChange(())
127 }
128 Self::ListSwap(m) => {
129 m.do_move(score_director);
130 ListMoveUnionUndo::ListSwap(())
131 }
132 Self::ListMultiSwap(m) => {
133 m.do_move(score_director);
134 ListMoveUnionUndo::ListMultiSwap(())
135 }
136 Self::ListPermute(m) => ListMoveUnionUndo::ListPermute(m.do_move(score_director)),
137 Self::SublistChange(m) => {
138 m.do_move(score_director);
139 ListMoveUnionUndo::SublistChange(())
140 }
141 Self::SublistSwap(m) => {
142 m.do_move(score_director);
143 ListMoveUnionUndo::SublistSwap(())
144 }
145 Self::ListReverse(m) => {
146 m.do_move(score_director);
147 ListMoveUnionUndo::ListReverse(())
148 }
149 Self::KOpt(m) => ListMoveUnionUndo::KOpt(m.do_move(score_director)),
150 Self::ListRuin(m) => ListMoveUnionUndo::ListRuin(m.do_move(score_director)),
151 }
152 }
153
154 fn undo_move<D: Director<S>>(&self, score_director: &mut D, undo: Self::Undo) {
155 match (self, undo) {
156 (Self::ListChange(m), ListMoveUnionUndo::ListChange(undo)) => {
157 m.undo_move(score_director, undo)
158 }
159 (Self::ListSwap(m), ListMoveUnionUndo::ListSwap(undo)) => {
160 m.undo_move(score_director, undo)
161 }
162 (Self::ListMultiSwap(m), ListMoveUnionUndo::ListMultiSwap(undo)) => {
163 m.undo_move(score_director, undo)
164 }
165 (Self::ListPermute(m), ListMoveUnionUndo::ListPermute(undo)) => {
166 m.undo_move(score_director, undo)
167 }
168 (Self::SublistChange(m), ListMoveUnionUndo::SublistChange(undo)) => {
169 m.undo_move(score_director, undo)
170 }
171 (Self::SublistSwap(m), ListMoveUnionUndo::SublistSwap(undo)) => {
172 m.undo_move(score_director, undo)
173 }
174 (Self::ListReverse(m), ListMoveUnionUndo::ListReverse(undo)) => {
175 m.undo_move(score_director, undo)
176 }
177 (Self::KOpt(m), ListMoveUnionUndo::KOpt(undo)) => m.undo_move(score_director, undo),
178 (Self::ListRuin(m), ListMoveUnionUndo::ListRuin(undo)) => {
179 m.undo_move(score_director, undo)
180 }
181 _ => panic!("list move undo shape must match move shape"),
182 }
183 }
184
185 fn descriptor_index(&self) -> usize {
186 match self {
187 Self::ListChange(m) => m.descriptor_index(),
188 Self::ListSwap(m) => m.descriptor_index(),
189 Self::ListMultiSwap(m) => m.descriptor_index(),
190 Self::ListPermute(m) => m.descriptor_index(),
191 Self::SublistChange(m) => m.descriptor_index(),
192 Self::SublistSwap(m) => m.descriptor_index(),
193 Self::ListReverse(m) => m.descriptor_index(),
194 Self::KOpt(m) => m.descriptor_index(),
195 Self::ListRuin(m) => m.descriptor_index(),
196 }
197 }
198
199 fn entity_indices(&self) -> &[usize] {
200 match self {
201 Self::ListChange(m) => m.entity_indices(),
202 Self::ListSwap(m) => m.entity_indices(),
203 Self::ListMultiSwap(m) => m.entity_indices(),
204 Self::ListPermute(m) => m.entity_indices(),
205 Self::SublistChange(m) => m.entity_indices(),
206 Self::SublistSwap(m) => m.entity_indices(),
207 Self::ListReverse(m) => m.entity_indices(),
208 Self::KOpt(m) => m.entity_indices(),
209 Self::ListRuin(m) => m.entity_indices(),
210 }
211 }
212
213 fn variable_name(&self) -> &str {
214 match self {
215 Self::ListChange(m) => m.variable_name(),
216 Self::ListSwap(m) => m.variable_name(),
217 Self::ListMultiSwap(m) => m.variable_name(),
218 Self::ListPermute(m) => m.variable_name(),
219 Self::SublistChange(m) => m.variable_name(),
220 Self::SublistSwap(m) => m.variable_name(),
221 Self::ListReverse(m) => m.variable_name(),
222 Self::KOpt(m) => m.variable_name(),
223 Self::ListRuin(m) => m.variable_name(),
224 }
225 }
226
227 fn telemetry_label(&self) -> &'static str {
228 match self {
229 Self::ListChange(m) => m.telemetry_label(),
230 Self::ListSwap(m) => m.telemetry_label(),
231 Self::ListMultiSwap(m) => m.telemetry_label(),
232 Self::ListPermute(m) => m.telemetry_label(),
233 Self::SublistChange(m) => m.telemetry_label(),
234 Self::SublistSwap(m) => m.telemetry_label(),
235 Self::ListReverse(m) => m.telemetry_label(),
236 Self::KOpt(m) => m.telemetry_label(),
237 Self::ListRuin(m) => m.telemetry_label(),
238 }
239 }
240
241 fn requires_hard_improvement(&self) -> bool {
242 match self {
243 Self::ListChange(m) => m.requires_hard_improvement(),
244 Self::ListSwap(m) => m.requires_hard_improvement(),
245 Self::ListMultiSwap(m) => m.requires_hard_improvement(),
246 Self::ListPermute(m) => m.requires_hard_improvement(),
247 Self::SublistChange(m) => m.requires_hard_improvement(),
248 Self::SublistSwap(m) => m.requires_hard_improvement(),
249 Self::ListReverse(m) => m.requires_hard_improvement(),
250 Self::KOpt(m) => m.requires_hard_improvement(),
251 Self::ListRuin(m) => m.requires_hard_improvement(),
252 }
253 }
254
255 fn requires_score_improvement(&self) -> bool {
256 match self {
257 Self::ListChange(m) => m.requires_score_improvement(),
258 Self::ListSwap(m) => m.requires_score_improvement(),
259 Self::ListMultiSwap(m) => m.requires_score_improvement(),
260 Self::ListPermute(m) => m.requires_score_improvement(),
261 Self::SublistChange(m) => m.requires_score_improvement(),
262 Self::SublistSwap(m) => m.requires_score_improvement(),
263 Self::ListReverse(m) => m.requires_score_improvement(),
264 Self::KOpt(m) => m.requires_score_improvement(),
265 Self::ListRuin(m) => m.requires_score_improvement(),
266 }
267 }
268
269 fn tabu_signature<D: Director<S>>(&self, score_director: &D) -> MoveTabuSignature {
270 match self {
271 Self::ListChange(m) => m.tabu_signature(score_director),
272 Self::ListSwap(m) => m.tabu_signature(score_director),
273 Self::ListMultiSwap(m) => m.tabu_signature(score_director),
274 Self::ListPermute(m) => m.tabu_signature(score_director),
275 Self::SublistChange(m) => m.tabu_signature(score_director),
276 Self::SublistSwap(m) => m.tabu_signature(score_director),
277 Self::ListReverse(m) => m.tabu_signature(score_director),
278 Self::KOpt(m) => m.tabu_signature(score_director),
279 Self::ListRuin(m) => m.tabu_signature(score_director),
280 }
281 }
282
283 fn candidate_trace_identity(&self) -> Option<CandidateTraceIdentity> {
284 match self {
285 Self::ListChange(m) => m.candidate_trace_identity(),
286 Self::ListSwap(m) => m.candidate_trace_identity(),
287 Self::ListMultiSwap(m) => m.candidate_trace_identity(),
288 Self::ListPermute(m) => m.candidate_trace_identity(),
289 Self::SublistChange(m) => m.candidate_trace_identity(),
290 Self::SublistSwap(m) => m.candidate_trace_identity(),
291 Self::ListReverse(m) => m.candidate_trace_identity(),
292 Self::KOpt(m) => m.candidate_trace_identity(),
293 Self::ListRuin(m) => m.candidate_trace_identity(),
294 }
295 }
296}