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, ListReverseMove, ListRuinMove, ListSwapMove, Move, MoveTabuSignature,
14    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/// `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    SublistChange(SublistChangeMove<S, V>),
35    SublistSwap(SublistSwapMove<S, V>),
36    ListReverse(ListReverseMove<S, V>),
37    KOpt(KOptMove<S, V>),
38    ListRuin(ListRuinMove<S, V>),
39}
40
41pub enum ListMoveUnionUndo<S, V>
42where
43    S: PlanningSolution,
44    V: Clone + PartialEq + Send + Sync + Debug + 'static,
45{
46    ListChange(<ListChangeMove<S, V> as Move<S>>::Undo),
47    ListSwap(<ListSwapMove<S, V> as Move<S>>::Undo),
48    SublistChange(<SublistChangeMove<S, V> as Move<S>>::Undo),
49    SublistSwap(<SublistSwapMove<S, V> as Move<S>>::Undo),
50    ListReverse(<ListReverseMove<S, V> as Move<S>>::Undo),
51    KOpt(<KOptMove<S, V> as Move<S>>::Undo),
52    ListRuin(<ListRuinMove<S, V> as Move<S>>::Undo),
53}
54
55impl<S, V> Clone for ListMoveUnion<S, V>
56where
57    S: PlanningSolution,
58    V: Clone + PartialEq + Send + Sync + Debug + 'static,
59{
60    fn clone(&self) -> Self {
61        match self {
62            Self::ListChange(m) => Self::ListChange(*m),
63            Self::ListSwap(m) => Self::ListSwap(*m),
64            Self::SublistChange(m) => Self::SublistChange(*m),
65            Self::SublistSwap(m) => Self::SublistSwap(*m),
66            Self::ListReverse(m) => Self::ListReverse(*m),
67            Self::KOpt(m) => Self::KOpt(m.clone()),
68            Self::ListRuin(m) => Self::ListRuin(m.clone()),
69        }
70    }
71}
72
73impl<S, V> Debug for ListMoveUnion<S, V>
74where
75    S: PlanningSolution,
76    V: Clone + PartialEq + Send + Sync + Debug + 'static,
77{
78    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
79        match self {
80            Self::ListChange(m) => m.fmt(f),
81            Self::ListSwap(m) => m.fmt(f),
82            Self::SublistChange(m) => m.fmt(f),
83            Self::SublistSwap(m) => m.fmt(f),
84            Self::ListReverse(m) => m.fmt(f),
85            Self::KOpt(m) => m.fmt(f),
86            Self::ListRuin(m) => m.fmt(f),
87        }
88    }
89}
90
91impl<S, V> Move<S> for ListMoveUnion<S, V>
92where
93    S: PlanningSolution,
94    V: Clone + PartialEq + Send + Sync + Debug + 'static,
95{
96    type Undo = ListMoveUnionUndo<S, V>;
97
98    fn is_doable<D: Director<S>>(&self, score_director: &D) -> bool {
99        match self {
100            Self::ListChange(m) => m.is_doable(score_director),
101            Self::ListSwap(m) => m.is_doable(score_director),
102            Self::SublistChange(m) => m.is_doable(score_director),
103            Self::SublistSwap(m) => m.is_doable(score_director),
104            Self::ListReverse(m) => m.is_doable(score_director),
105            Self::KOpt(m) => m.is_doable(score_director),
106            Self::ListRuin(m) => m.is_doable(score_director),
107        }
108    }
109
110    fn do_move<D: Director<S>>(&self, score_director: &mut D) -> Self::Undo {
111        match self {
112            Self::ListChange(m) => {
113                m.do_move(score_director);
114                ListMoveUnionUndo::ListChange(())
115            }
116            Self::ListSwap(m) => {
117                m.do_move(score_director);
118                ListMoveUnionUndo::ListSwap(())
119            }
120            Self::SublistChange(m) => {
121                m.do_move(score_director);
122                ListMoveUnionUndo::SublistChange(())
123            }
124            Self::SublistSwap(m) => {
125                m.do_move(score_director);
126                ListMoveUnionUndo::SublistSwap(())
127            }
128            Self::ListReverse(m) => {
129                m.do_move(score_director);
130                ListMoveUnionUndo::ListReverse(())
131            }
132            Self::KOpt(m) => ListMoveUnionUndo::KOpt(m.do_move(score_director)),
133            Self::ListRuin(m) => ListMoveUnionUndo::ListRuin(m.do_move(score_director)),
134        }
135    }
136
137    fn undo_move<D: Director<S>>(&self, score_director: &mut D, undo: Self::Undo) {
138        match (self, undo) {
139            (Self::ListChange(m), ListMoveUnionUndo::ListChange(undo)) => {
140                m.undo_move(score_director, undo)
141            }
142            (Self::ListSwap(m), ListMoveUnionUndo::ListSwap(undo)) => {
143                m.undo_move(score_director, undo)
144            }
145            (Self::SublistChange(m), ListMoveUnionUndo::SublistChange(undo)) => {
146                m.undo_move(score_director, undo)
147            }
148            (Self::SublistSwap(m), ListMoveUnionUndo::SublistSwap(undo)) => {
149                m.undo_move(score_director, undo)
150            }
151            (Self::ListReverse(m), ListMoveUnionUndo::ListReverse(undo)) => {
152                m.undo_move(score_director, undo)
153            }
154            (Self::KOpt(m), ListMoveUnionUndo::KOpt(undo)) => m.undo_move(score_director, undo),
155            (Self::ListRuin(m), ListMoveUnionUndo::ListRuin(undo)) => {
156                m.undo_move(score_director, undo)
157            }
158            _ => panic!("list move undo shape must match move shape"),
159        }
160    }
161
162    fn descriptor_index(&self) -> usize {
163        match self {
164            Self::ListChange(m) => m.descriptor_index(),
165            Self::ListSwap(m) => m.descriptor_index(),
166            Self::SublistChange(m) => m.descriptor_index(),
167            Self::SublistSwap(m) => m.descriptor_index(),
168            Self::ListReverse(m) => m.descriptor_index(),
169            Self::KOpt(m) => m.descriptor_index(),
170            Self::ListRuin(m) => m.descriptor_index(),
171        }
172    }
173
174    fn entity_indices(&self) -> &[usize] {
175        match self {
176            Self::ListChange(m) => m.entity_indices(),
177            Self::ListSwap(m) => m.entity_indices(),
178            Self::SublistChange(m) => m.entity_indices(),
179            Self::SublistSwap(m) => m.entity_indices(),
180            Self::ListReverse(m) => m.entity_indices(),
181            Self::KOpt(m) => m.entity_indices(),
182            Self::ListRuin(m) => m.entity_indices(),
183        }
184    }
185
186    fn variable_name(&self) -> &str {
187        match self {
188            Self::ListChange(m) => m.variable_name(),
189            Self::ListSwap(m) => m.variable_name(),
190            Self::SublistChange(m) => m.variable_name(),
191            Self::SublistSwap(m) => m.variable_name(),
192            Self::ListReverse(m) => m.variable_name(),
193            Self::KOpt(m) => m.variable_name(),
194            Self::ListRuin(m) => m.variable_name(),
195        }
196    }
197
198    fn tabu_signature<D: Director<S>>(&self, score_director: &D) -> MoveTabuSignature {
199        match self {
200            Self::ListChange(m) => m.tabu_signature(score_director),
201            Self::ListSwap(m) => m.tabu_signature(score_director),
202            Self::SublistChange(m) => m.tabu_signature(score_director),
203            Self::SublistSwap(m) => m.tabu_signature(score_director),
204            Self::ListReverse(m) => m.tabu_signature(score_director),
205            Self::KOpt(m) => m.tabu_signature(score_director),
206            Self::ListRuin(m) => m.tabu_signature(score_director),
207        }
208    }
209}