Skip to main content

solverforge_solver/heuristic/move/
list_union.rs

1/* ListMoveUnion - a monomorphized union of all list-variable move types.
2
3This allows local search to combine all list move types in a single arena
4without trait-object dispatch.
5*/
6
7use 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/// A monomorphized union of all list-variable move types.
20///
21/// Implements `Move<S>` by delegating to the inner variant.
22/// Enables combining `ListChangeMoveSelector`, `ListSwapMoveSelector`,
23/// `ListPermuteMoveSelector`, `SublistChangeMoveSelector`, `SublistSwapMoveSelector`,
24/// `ListReverseMoveSelector`, `KOptMoveSelector`, and
25/// `ListRuinMoveSelector` without type erasure.
26///
27/// # Example
28///
29/// ```
30/// use solverforge_solver::heuristic::r#move::ListMoveUnion;
31/// ```
32#[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}