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 super::{
13    KOptMove, ListChangeMove, ListMultiSwapMove, ListPermuteMove, ListReverseMove, ListRuinMove,
14    ListSwapMove, Move, MoveTabuSignature, SublistChangeMove, SublistSwapMove,
15};
16
17/// A monomorphized union of all list-variable move types.
18///
19/// Implements `Move<S>` by delegating to the inner variant.
20/// Enables combining `ListChangeMoveSelector`, `ListSwapMoveSelector`,
21/// `ListPermuteMoveSelector`, `SublistChangeMoveSelector`, `SublistSwapMoveSelector`,
22/// `ListReverseMoveSelector`, `KOptMoveSelector`, and
23/// `ListRuinMoveSelector` without type erasure.
24///
25/// # Example
26///
27/// ```
28/// use solverforge_solver::heuristic::r#move::ListMoveUnion;
29/// ```
30#[allow(clippy::large_enum_variant)]
31pub enum ListMoveUnion<S, V> {
32    ListChange(ListChangeMove<S, V>),
33    ListSwap(ListSwapMove<S, V>),
34    ListMultiSwap(ListMultiSwapMove<S, V>),
35    ListPermute(ListPermuteMove<S, V>),
36    SublistChange(SublistChangeMove<S, V>),
37    SublistSwap(SublistSwapMove<S, V>),
38    ListReverse(ListReverseMove<S, V>),
39    KOpt(KOptMove<S, V>),
40    ListRuin(ListRuinMove<S, V>),
41}
42
43pub enum ListMoveUnionUndo<S, V>
44where
45    S: PlanningSolution,
46    V: Clone + PartialEq + Send + Sync + Debug + 'static,
47{
48    ListChange(<ListChangeMove<S, V> as Move<S>>::Undo),
49    ListSwap(<ListSwapMove<S, V> as Move<S>>::Undo),
50    ListMultiSwap(<ListMultiSwapMove<S, V> as Move<S>>::Undo),
51    ListPermute(<ListPermuteMove<S, V> as Move<S>>::Undo),
52    SublistChange(<SublistChangeMove<S, V> as Move<S>>::Undo),
53    SublistSwap(<SublistSwapMove<S, V> as Move<S>>::Undo),
54    ListReverse(<ListReverseMove<S, V> as Move<S>>::Undo),
55    KOpt(<KOptMove<S, V> as Move<S>>::Undo),
56    ListRuin(<ListRuinMove<S, V> as Move<S>>::Undo),
57}
58
59impl<S, V> Clone for ListMoveUnion<S, V>
60where
61    S: PlanningSolution,
62    V: Clone + PartialEq + Send + Sync + Debug + 'static,
63{
64    fn clone(&self) -> Self {
65        match self {
66            Self::ListChange(m) => Self::ListChange(*m),
67            Self::ListSwap(m) => Self::ListSwap(*m),
68            Self::ListMultiSwap(m) => Self::ListMultiSwap(m.clone()),
69            Self::ListPermute(m) => Self::ListPermute(m.clone()),
70            Self::SublistChange(m) => Self::SublistChange(*m),
71            Self::SublistSwap(m) => Self::SublistSwap(*m),
72            Self::ListReverse(m) => Self::ListReverse(*m),
73            Self::KOpt(m) => Self::KOpt(m.clone()),
74            Self::ListRuin(m) => Self::ListRuin(m.clone()),
75        }
76    }
77}
78
79impl<S, V> Debug for ListMoveUnion<S, V>
80where
81    S: PlanningSolution,
82    V: Clone + PartialEq + Send + Sync + Debug + 'static,
83{
84    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
85        match self {
86            Self::ListChange(m) => m.fmt(f),
87            Self::ListSwap(m) => m.fmt(f),
88            Self::ListMultiSwap(m) => m.fmt(f),
89            Self::ListPermute(m) => m.fmt(f),
90            Self::SublistChange(m) => m.fmt(f),
91            Self::SublistSwap(m) => m.fmt(f),
92            Self::ListReverse(m) => m.fmt(f),
93            Self::KOpt(m) => m.fmt(f),
94            Self::ListRuin(m) => m.fmt(f),
95        }
96    }
97}
98
99impl<S, V> Move<S> for ListMoveUnion<S, V>
100where
101    S: PlanningSolution,
102    V: Clone + PartialEq + Send + Sync + Debug + 'static,
103{
104    type Undo = ListMoveUnionUndo<S, V>;
105
106    fn is_doable<D: Director<S>>(&self, score_director: &D) -> bool {
107        match self {
108            Self::ListChange(m) => m.is_doable(score_director),
109            Self::ListSwap(m) => m.is_doable(score_director),
110            Self::ListMultiSwap(m) => m.is_doable(score_director),
111            Self::ListPermute(m) => m.is_doable(score_director),
112            Self::SublistChange(m) => m.is_doable(score_director),
113            Self::SublistSwap(m) => m.is_doable(score_director),
114            Self::ListReverse(m) => m.is_doable(score_director),
115            Self::KOpt(m) => m.is_doable(score_director),
116            Self::ListRuin(m) => m.is_doable(score_director),
117        }
118    }
119
120    fn do_move<D: Director<S>>(&self, score_director: &mut D) -> Self::Undo {
121        match self {
122            Self::ListChange(m) => {
123                m.do_move(score_director);
124                ListMoveUnionUndo::ListChange(())
125            }
126            Self::ListSwap(m) => {
127                m.do_move(score_director);
128                ListMoveUnionUndo::ListSwap(())
129            }
130            Self::ListMultiSwap(m) => {
131                m.do_move(score_director);
132                ListMoveUnionUndo::ListMultiSwap(())
133            }
134            Self::ListPermute(m) => ListMoveUnionUndo::ListPermute(m.do_move(score_director)),
135            Self::SublistChange(m) => {
136                m.do_move(score_director);
137                ListMoveUnionUndo::SublistChange(())
138            }
139            Self::SublistSwap(m) => {
140                m.do_move(score_director);
141                ListMoveUnionUndo::SublistSwap(())
142            }
143            Self::ListReverse(m) => {
144                m.do_move(score_director);
145                ListMoveUnionUndo::ListReverse(())
146            }
147            Self::KOpt(m) => ListMoveUnionUndo::KOpt(m.do_move(score_director)),
148            Self::ListRuin(m) => ListMoveUnionUndo::ListRuin(m.do_move(score_director)),
149        }
150    }
151
152    fn undo_move<D: Director<S>>(&self, score_director: &mut D, undo: Self::Undo) {
153        match (self, undo) {
154            (Self::ListChange(m), ListMoveUnionUndo::ListChange(undo)) => {
155                m.undo_move(score_director, undo)
156            }
157            (Self::ListSwap(m), ListMoveUnionUndo::ListSwap(undo)) => {
158                m.undo_move(score_director, undo)
159            }
160            (Self::ListMultiSwap(m), ListMoveUnionUndo::ListMultiSwap(undo)) => {
161                m.undo_move(score_director, undo)
162            }
163            (Self::ListPermute(m), ListMoveUnionUndo::ListPermute(undo)) => {
164                m.undo_move(score_director, undo)
165            }
166            (Self::SublistChange(m), ListMoveUnionUndo::SublistChange(undo)) => {
167                m.undo_move(score_director, undo)
168            }
169            (Self::SublistSwap(m), ListMoveUnionUndo::SublistSwap(undo)) => {
170                m.undo_move(score_director, undo)
171            }
172            (Self::ListReverse(m), ListMoveUnionUndo::ListReverse(undo)) => {
173                m.undo_move(score_director, undo)
174            }
175            (Self::KOpt(m), ListMoveUnionUndo::KOpt(undo)) => m.undo_move(score_director, undo),
176            (Self::ListRuin(m), ListMoveUnionUndo::ListRuin(undo)) => {
177                m.undo_move(score_director, undo)
178            }
179            _ => panic!("list move undo shape must match move shape"),
180        }
181    }
182
183    fn descriptor_index(&self) -> usize {
184        match self {
185            Self::ListChange(m) => m.descriptor_index(),
186            Self::ListSwap(m) => m.descriptor_index(),
187            Self::ListMultiSwap(m) => m.descriptor_index(),
188            Self::ListPermute(m) => m.descriptor_index(),
189            Self::SublistChange(m) => m.descriptor_index(),
190            Self::SublistSwap(m) => m.descriptor_index(),
191            Self::ListReverse(m) => m.descriptor_index(),
192            Self::KOpt(m) => m.descriptor_index(),
193            Self::ListRuin(m) => m.descriptor_index(),
194        }
195    }
196
197    fn entity_indices(&self) -> &[usize] {
198        match self {
199            Self::ListChange(m) => m.entity_indices(),
200            Self::ListSwap(m) => m.entity_indices(),
201            Self::ListMultiSwap(m) => m.entity_indices(),
202            Self::ListPermute(m) => m.entity_indices(),
203            Self::SublistChange(m) => m.entity_indices(),
204            Self::SublistSwap(m) => m.entity_indices(),
205            Self::ListReverse(m) => m.entity_indices(),
206            Self::KOpt(m) => m.entity_indices(),
207            Self::ListRuin(m) => m.entity_indices(),
208        }
209    }
210
211    fn variable_name(&self) -> &str {
212        match self {
213            Self::ListChange(m) => m.variable_name(),
214            Self::ListSwap(m) => m.variable_name(),
215            Self::ListMultiSwap(m) => m.variable_name(),
216            Self::ListPermute(m) => m.variable_name(),
217            Self::SublistChange(m) => m.variable_name(),
218            Self::SublistSwap(m) => m.variable_name(),
219            Self::ListReverse(m) => m.variable_name(),
220            Self::KOpt(m) => m.variable_name(),
221            Self::ListRuin(m) => m.variable_name(),
222        }
223    }
224
225    fn telemetry_label(&self) -> &'static str {
226        match self {
227            Self::ListChange(m) => m.telemetry_label(),
228            Self::ListSwap(m) => m.telemetry_label(),
229            Self::ListMultiSwap(m) => m.telemetry_label(),
230            Self::ListPermute(m) => m.telemetry_label(),
231            Self::SublistChange(m) => m.telemetry_label(),
232            Self::SublistSwap(m) => m.telemetry_label(),
233            Self::ListReverse(m) => m.telemetry_label(),
234            Self::KOpt(m) => m.telemetry_label(),
235            Self::ListRuin(m) => m.telemetry_label(),
236        }
237    }
238
239    fn requires_hard_improvement(&self) -> bool {
240        match self {
241            Self::ListChange(m) => m.requires_hard_improvement(),
242            Self::ListSwap(m) => m.requires_hard_improvement(),
243            Self::ListMultiSwap(m) => m.requires_hard_improvement(),
244            Self::ListPermute(m) => m.requires_hard_improvement(),
245            Self::SublistChange(m) => m.requires_hard_improvement(),
246            Self::SublistSwap(m) => m.requires_hard_improvement(),
247            Self::ListReverse(m) => m.requires_hard_improvement(),
248            Self::KOpt(m) => m.requires_hard_improvement(),
249            Self::ListRuin(m) => m.requires_hard_improvement(),
250        }
251    }
252
253    fn requires_score_improvement(&self) -> bool {
254        match self {
255            Self::ListChange(m) => m.requires_score_improvement(),
256            Self::ListSwap(m) => m.requires_score_improvement(),
257            Self::ListMultiSwap(m) => m.requires_score_improvement(),
258            Self::ListPermute(m) => m.requires_score_improvement(),
259            Self::SublistChange(m) => m.requires_score_improvement(),
260            Self::SublistSwap(m) => m.requires_score_improvement(),
261            Self::ListReverse(m) => m.requires_score_improvement(),
262            Self::KOpt(m) => m.requires_score_improvement(),
263            Self::ListRuin(m) => m.requires_score_improvement(),
264        }
265    }
266
267    fn tabu_signature<D: Director<S>>(&self, score_director: &D) -> MoveTabuSignature {
268        match self {
269            Self::ListChange(m) => m.tabu_signature(score_director),
270            Self::ListSwap(m) => m.tabu_signature(score_director),
271            Self::ListMultiSwap(m) => m.tabu_signature(score_director),
272            Self::ListPermute(m) => m.tabu_signature(score_director),
273            Self::SublistChange(m) => m.tabu_signature(score_director),
274            Self::SublistSwap(m) => m.tabu_signature(score_director),
275            Self::ListReverse(m) => m.tabu_signature(score_director),
276            Self::KOpt(m) => m.tabu_signature(score_director),
277            Self::ListRuin(m) => m.tabu_signature(score_director),
278        }
279    }
280}