Skip to main content

solverforge_config/
move_selector.rs

1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Clone, Default, Deserialize, Serialize, PartialEq, Eq)]
4#[serde(rename_all = "snake_case")]
5pub struct VariableTargetConfig {
6    pub entity_class: Option<String>,
7    pub variable_name: Option<String>,
8}
9
10// Move selector configuration.
11#[derive(Debug, Clone, Deserialize, Serialize)]
12#[serde(tag = "type", rename_all = "snake_case")]
13pub enum MoveSelectorConfig {
14    // Change move selector (scalar variables).
15    ChangeMoveSelector(ChangeMoveConfig),
16
17    // Swap move selector (scalar variables).
18    SwapMoveSelector(SwapMoveConfig),
19
20    // Nearby change move selector (scalar variables).
21    NearbyChangeMoveSelector(NearbyChangeMoveConfig),
22
23    // Nearby swap move selector (scalar variables).
24    NearbySwapMoveSelector(NearbySwapMoveConfig),
25
26    // Pillar change move selector (scalar variables).
27    PillarChangeMoveSelector(PillarChangeMoveConfig),
28
29    // Pillar swap move selector (scalar variables).
30    PillarSwapMoveSelector(PillarSwapMoveConfig),
31
32    // Ruin-and-recreate move selector (scalar variables).
33    RuinRecreateMoveSelector(RuinRecreateMoveSelectorConfig),
34
35    // List change move selector — relocates single elements within/between routes.
36    ListChangeMoveSelector(ListChangeMoveConfig),
37
38    // Nearby list change move selector — distance-pruned element relocation.
39    NearbyListChangeMoveSelector(NearbyListChangeMoveConfig),
40
41    // List swap move selector — swaps single elements within/between routes.
42    ListSwapMoveSelector(ListSwapMoveConfig),
43
44    // Nearby list swap move selector — distance-pruned element swap.
45    NearbyListSwapMoveSelector(NearbyListSwapMoveConfig),
46
47    // Sublist change move selector (Or-opt) — relocates contiguous segments.
48    SublistChangeMoveSelector(SublistChangeMoveConfig),
49
50    // Sublist swap move selector — swaps contiguous segments between routes.
51    SublistSwapMoveSelector(SublistSwapMoveConfig),
52
53    // List reverse move selector (2-opt) — reverses segments within a route.
54    ListReverseMoveSelector(ListReverseMoveConfig),
55
56    // K-opt move selector — generalised route reconnection.
57    KOptMoveSelector(KOptMoveSelectorConfig),
58
59    // List ruin move selector (LNS) — removes elements for reinsertion.
60    ListRuinMoveSelector(ListRuinMoveSelectorConfig),
61
62    // Neighborhood that limits the number of yielded candidates from a child selector while
63    // preserving selector order.
64    LimitedNeighborhood(LimitedNeighborhoodConfig),
65
66    // Union of multiple selectors.
67    UnionMoveSelector(UnionMoveSelectorConfig),
68
69    // Cartesian product of selectors. Evaluates the right child on the left preview state,
70    // composes tabu ids in selector order, and rejects left children that require full score
71    // evaluation during preview.
72    CartesianProductMoveSelector(CartesianProductConfig),
73}
74
75// Change move configuration.
76#[derive(Debug, Clone, Default, Deserialize, Serialize)]
77#[serde(rename_all = "snake_case")]
78pub struct ChangeMoveConfig {
79    #[serde(flatten)]
80    pub target: VariableTargetConfig,
81}
82
83// Swap move configuration.
84#[derive(Debug, Clone, Default, Deserialize, Serialize)]
85#[serde(rename_all = "snake_case")]
86pub struct SwapMoveConfig {
87    #[serde(flatten)]
88    pub target: VariableTargetConfig,
89}
90
91// Nearby change move configuration.
92#[derive(Debug, Clone, Deserialize, Serialize)]
93#[serde(rename_all = "snake_case")]
94pub struct NearbyChangeMoveConfig {
95    pub max_nearby: usize,
96    #[serde(flatten)]
97    pub target: VariableTargetConfig,
98}
99
100impl Default for NearbyChangeMoveConfig {
101    fn default() -> Self {
102        Self {
103            max_nearby: 10,
104            target: VariableTargetConfig::default(),
105        }
106    }
107}
108
109// Nearby swap move configuration.
110#[derive(Debug, Clone, Deserialize, Serialize)]
111#[serde(rename_all = "snake_case")]
112pub struct NearbySwapMoveConfig {
113    pub max_nearby: usize,
114    #[serde(flatten)]
115    pub target: VariableTargetConfig,
116}
117
118impl Default for NearbySwapMoveConfig {
119    fn default() -> Self {
120        Self {
121            max_nearby: 10,
122            target: VariableTargetConfig::default(),
123        }
124    }
125}
126
127// Pillar change move configuration.
128#[derive(Debug, Clone, Default, Deserialize, Serialize)]
129#[serde(rename_all = "snake_case")]
130pub struct PillarChangeMoveConfig {
131    pub minimum_sub_pillar_size: usize,
132    pub maximum_sub_pillar_size: usize,
133    #[serde(flatten)]
134    pub target: VariableTargetConfig,
135}
136
137// Pillar swap move configuration.
138#[derive(Debug, Clone, Default, Deserialize, Serialize)]
139#[serde(rename_all = "snake_case")]
140pub struct PillarSwapMoveConfig {
141    pub minimum_sub_pillar_size: usize,
142    pub maximum_sub_pillar_size: usize,
143    #[serde(flatten)]
144    pub target: VariableTargetConfig,
145}
146
147#[derive(Debug, Clone, Copy, Default, Deserialize, Serialize, PartialEq, Eq)]
148#[serde(rename_all = "snake_case")]
149pub enum RecreateHeuristicType {
150    FirstFit,
151    #[default]
152    CheapestInsertion,
153}
154
155// Ruin-and-recreate move configuration.
156#[derive(Debug, Clone, Deserialize, Serialize)]
157#[serde(rename_all = "snake_case")]
158pub struct RuinRecreateMoveSelectorConfig {
159    pub min_ruin_count: usize,
160    pub max_ruin_count: usize,
161    pub moves_per_step: Option<usize>,
162    pub recreate_heuristic_type: RecreateHeuristicType,
163    #[serde(flatten)]
164    pub target: VariableTargetConfig,
165}
166
167impl Default for RuinRecreateMoveSelectorConfig {
168    fn default() -> Self {
169        Self {
170            min_ruin_count: 2,
171            max_ruin_count: 5,
172            moves_per_step: None,
173            recreate_heuristic_type: RecreateHeuristicType::CheapestInsertion,
174            target: VariableTargetConfig::default(),
175        }
176    }
177}
178
179// Configuration for `ListChangeMoveSelector`.
180#[derive(Debug, Clone, Default, Deserialize, Serialize)]
181#[serde(rename_all = "snake_case")]
182pub struct ListChangeMoveConfig {
183    #[serde(flatten)]
184    pub target: VariableTargetConfig,
185}
186
187// Configuration for `NearbyListChangeMoveSelector`.
188#[derive(Debug, Clone, Deserialize, Serialize)]
189#[serde(rename_all = "snake_case")]
190pub struct NearbyListChangeMoveConfig {
191    // Maximum nearby destination positions to consider per source element.
192    pub max_nearby: usize,
193    #[serde(flatten)]
194    pub target: VariableTargetConfig,
195}
196
197impl Default for NearbyListChangeMoveConfig {
198    fn default() -> Self {
199        Self {
200            max_nearby: 10,
201            target: VariableTargetConfig::default(),
202        }
203    }
204}
205
206// Configuration for `ListSwapMoveSelector`.
207#[derive(Debug, Clone, Default, Deserialize, Serialize)]
208#[serde(rename_all = "snake_case")]
209pub struct ListSwapMoveConfig {
210    #[serde(flatten)]
211    pub target: VariableTargetConfig,
212}
213
214// Configuration for `NearbyListSwapMoveSelector`.
215#[derive(Debug, Clone, Deserialize, Serialize)]
216#[serde(rename_all = "snake_case")]
217pub struct NearbyListSwapMoveConfig {
218    // Maximum nearby swap partners to consider per source element.
219    pub max_nearby: usize,
220    #[serde(flatten)]
221    pub target: VariableTargetConfig,
222}
223
224impl Default for NearbyListSwapMoveConfig {
225    fn default() -> Self {
226        Self {
227            max_nearby: 10,
228            target: VariableTargetConfig::default(),
229        }
230    }
231}
232
233// Configuration for `SublistChangeMoveSelector` (Or-opt).
234#[derive(Debug, Clone, Deserialize, Serialize)]
235#[serde(rename_all = "snake_case")]
236pub struct SublistChangeMoveConfig {
237    // Minimum segment size (inclusive). Default: 1.
238    pub min_sublist_size: usize,
239    // Maximum segment size (inclusive). Default: 3.
240    pub max_sublist_size: usize,
241    #[serde(flatten)]
242    pub target: VariableTargetConfig,
243}
244
245impl Default for SublistChangeMoveConfig {
246    fn default() -> Self {
247        Self {
248            min_sublist_size: 1,
249            max_sublist_size: 3,
250            target: VariableTargetConfig::default(),
251        }
252    }
253}
254
255// Configuration for `SublistSwapMoveSelector`.
256#[derive(Debug, Clone, Deserialize, Serialize)]
257#[serde(rename_all = "snake_case")]
258pub struct SublistSwapMoveConfig {
259    // Minimum segment size (inclusive). Default: 1.
260    pub min_sublist_size: usize,
261    // Maximum segment size (inclusive). Default: 3.
262    pub max_sublist_size: usize,
263    #[serde(flatten)]
264    pub target: VariableTargetConfig,
265}
266
267impl Default for SublistSwapMoveConfig {
268    fn default() -> Self {
269        Self {
270            min_sublist_size: 1,
271            max_sublist_size: 3,
272            target: VariableTargetConfig::default(),
273        }
274    }
275}
276
277// Configuration for `ListReverseMoveSelector` (2-opt).
278#[derive(Debug, Clone, Default, Deserialize, Serialize)]
279#[serde(rename_all = "snake_case")]
280pub struct ListReverseMoveConfig {
281    #[serde(flatten)]
282    pub target: VariableTargetConfig,
283}
284
285// Configuration for `KOptMoveSelector`.
286#[derive(Debug, Clone, Deserialize, Serialize)]
287#[serde(rename_all = "snake_case")]
288pub struct KOptMoveSelectorConfig {
289    // K value (number of cuts). Default: 3.
290    pub k: usize,
291    // Minimum segment length between cuts. Default: 1.
292    pub min_segment_len: usize,
293    // Maximum nearby positions to consider per cut. Default: 0 (full enumeration).
294    // When > 0, uses distance-pruned NearbyKOptMoveSelector instead of full KOptMoveSelector.
295    pub max_nearby: usize,
296    #[serde(flatten)]
297    pub target: VariableTargetConfig,
298}
299
300impl Default for KOptMoveSelectorConfig {
301    fn default() -> Self {
302        Self {
303            k: 3,
304            min_segment_len: 1,
305            max_nearby: 0,
306            target: VariableTargetConfig::default(),
307        }
308    }
309}
310
311// Configuration for `ListRuinMoveSelector` (LNS).
312#[derive(Debug, Clone, Deserialize, Serialize)]
313#[serde(rename_all = "snake_case")]
314pub struct ListRuinMoveSelectorConfig {
315    // Minimum number of elements to ruin per move. Default: 2.
316    pub min_ruin_count: usize,
317    // Maximum number of elements to ruin per move. Default: 5.
318    pub max_ruin_count: usize,
319    // Number of ruin moves to generate per step. Default: 10.
320    pub moves_per_step: Option<usize>,
321    #[serde(flatten)]
322    pub target: VariableTargetConfig,
323}
324
325impl Default for ListRuinMoveSelectorConfig {
326    fn default() -> Self {
327        Self {
328            min_ruin_count: 2,
329            max_ruin_count: 5,
330            moves_per_step: None,
331            target: VariableTargetConfig::default(),
332        }
333    }
334}
335
336// Configuration for `LimitedNeighborhood`.
337#[derive(Debug, Clone, Deserialize, Serialize)]
338#[serde(rename_all = "snake_case")]
339pub struct LimitedNeighborhoodConfig {
340    // Maximum number of moves yielded from the child selector.
341    pub selected_count_limit: usize,
342    // Child selector to wrap.
343    pub selector: Box<MoveSelectorConfig>,
344}
345
346// Union move selector configuration.
347#[derive(Debug, Clone, Default, Deserialize, Serialize)]
348#[serde(rename_all = "snake_case")]
349pub struct UnionMoveSelectorConfig {
350    // Child selectors.
351    pub selectors: Vec<MoveSelectorConfig>,
352}
353
354// Cartesian product move selector configuration.
355#[derive(Debug, Clone, Default, Deserialize, Serialize)]
356#[serde(rename_all = "snake_case")]
357pub struct CartesianProductConfig {
358    // Child selectors.
359    pub selectors: Vec<MoveSelectorConfig>,
360}