solverforge_config/phase.rs
1use serde::{Deserialize, Serialize};
2
3use crate::acceptor::AcceptorConfig;
4use crate::forager::ForagerConfig;
5use crate::move_selector::{MoveSelectorConfig, VariableTargetConfig};
6use crate::solver_config::MoveThreadCount;
7use crate::termination::TerminationConfig;
8
9// Phase configuration.
10#[derive(Debug, Clone, Deserialize, Serialize)]
11#[serde(tag = "type", rename_all = "snake_case")]
12pub enum PhaseConfig {
13 // Construction heuristic phase.
14 ConstructionHeuristic(ConstructionHeuristicConfig),
15
16 // Local search phase.
17 LocalSearch(LocalSearchConfig),
18
19 // Partitioned search phase.
20 PartitionedSearch(PartitionedSearchConfig),
21
22 // Custom phase.
23 Custom(CustomPhaseConfig),
24}
25
26fn default_k() -> usize {
27 2
28}
29
30// Construction heuristic configuration.
31#[derive(Debug, Clone, Deserialize, Serialize)]
32#[serde(rename_all = "snake_case")]
33pub struct ConstructionHeuristicConfig {
34 // Type of construction heuristic.
35 #[serde(default)]
36 pub construction_heuristic_type: ConstructionHeuristicType,
37
38 // Whether nullable scalar variables may keep their current unassigned value during
39 // construction, or must receive a candidate when one exists.
40 #[serde(default)]
41 pub construction_obligation: ConstructionObligation,
42
43 // Optional variable target.
44 #[serde(flatten)]
45 pub target: VariableTargetConfig,
46
47 // k for ListKOpt (default 2).
48 #[serde(default = "default_k")]
49 pub k: usize,
50
51 // Optional cap for scalar value candidates generated per entity.
52 pub value_candidate_limit: Option<usize>,
53
54 // Optional named scalar group for atomic grouped scalar construction.
55 pub group_name: Option<String>,
56
57 // Optional cap for grouped scalar candidates generated per provider call.
58 pub group_candidate_limit: Option<usize>,
59
60 // Phase termination configuration.
61 pub termination: Option<TerminationConfig>,
62}
63
64impl Default for ConstructionHeuristicConfig {
65 fn default() -> Self {
66 Self {
67 construction_heuristic_type: ConstructionHeuristicType::default(),
68 construction_obligation: ConstructionObligation::default(),
69 target: VariableTargetConfig::default(),
70 k: default_k(),
71 value_candidate_limit: None,
72 group_name: None,
73 group_candidate_limit: None,
74 termination: None,
75 }
76 }
77}
78
79// Construction obligation for nullable scalar variables.
80#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Deserialize, Serialize)]
81#[serde(rename_all = "snake_case")]
82pub enum ConstructionObligation {
83 // Preserve current behavior: unassigned nullable variables may remain unassigned.
84 #[default]
85 PreserveUnassigned,
86
87 // If a nullable scalar variable is unassigned and has a doable candidate, construction
88 // must assign one instead of comparing against the unassigned baseline.
89 AssignWhenCandidateExists,
90}
91
92// Construction heuristic types.
93#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Deserialize, Serialize)]
94#[serde(rename_all = "snake_case")]
95pub enum ConstructionHeuristicType {
96 // First fit heuristic (scalar variables).
97 #[default]
98 FirstFit,
99
100 // First fit decreasing. Scalar-only; requires `construction_entity_order_key`.
101 FirstFitDecreasing,
102
103 // Weakest fit heuristic. Scalar-only; requires `construction_value_order_key`.
104 WeakestFit,
105
106 // Weakest fit decreasing. Scalar-only; requires both scalar construction order keys.
107 WeakestFitDecreasing,
108
109 // Strongest fit heuristic. Scalar-only; requires `construction_value_order_key`.
110 StrongestFit,
111
112 // Strongest fit decreasing. Scalar-only; requires both scalar construction order keys.
113 StrongestFitDecreasing,
114
115 // Cheapest insertion (greedy, scalar variables).
116 CheapestInsertion,
117
118 // Allocate entity from queue. Scalar-only; requires `construction_entity_order_key`.
119 AllocateEntityFromQueue,
120
121 // Allocate to value from queue. Scalar-only; requires `construction_value_order_key`.
122 AllocateToValueFromQueue,
123
124 // List round-robin construction: distributes elements evenly across entities and validates the
125 // list construction hook surface before phase build.
126 ListRoundRobin,
127
128 // List cheapest insertion: inserts each element at the score-minimizing position and validates
129 // the list construction hook surface before phase build.
130 ListCheapestInsertion,
131
132 // List regret insertion: inserts elements in order of highest placement regret and validates
133 // the list construction hook surface before phase build.
134 ListRegretInsertion,
135
136 // List Clarke-Wright savings: greedy route merging by savings value; requires the declared
137 // owner-aware route hooks and validates them before phase build.
138 ListClarkeWright,
139
140 // List k-opt: per-route k-opt polishing (k=2 is exact 2-opt); requires the declared
141 // owner-aware route hooks and validates them before phase build.
142 ListKOpt,
143}
144
145// Local search type.
146#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Deserialize, Serialize)]
147#[serde(rename_all = "snake_case")]
148pub enum LocalSearchType {
149 // Standard acceptor/forager local search.
150 #[default]
151 AcceptorForager,
152
153 // Variable Neighborhood Descent over ordered neighborhoods.
154 VariableNeighborhoodDescent,
155}
156
157// Local search configuration.
158#[derive(Debug, Clone, Default, Deserialize, Serialize)]
159#[serde(rename_all = "snake_case")]
160pub struct LocalSearchConfig {
161 // Local search type.
162 #[serde(default)]
163 pub local_search_type: LocalSearchType,
164
165 // Acceptor configuration.
166 pub acceptor: Option<AcceptorConfig>,
167
168 // Forager configuration.
169 pub forager: Option<ForagerConfig>,
170
171 // Move selector configuration.
172 pub move_selector: Option<MoveSelectorConfig>,
173
174 // Ordered neighborhood selectors for Variable Neighborhood Descent.
175 #[serde(default)]
176 pub neighborhoods: Vec<MoveSelectorConfig>,
177
178 // Phase termination configuration.
179 pub termination: Option<TerminationConfig>,
180}
181
182// Partitioned search configuration.
183#[derive(Debug, Clone, Default, Deserialize, Serialize)]
184#[serde(rename_all = "snake_case")]
185pub struct PartitionedSearchConfig {
186 // Compile-time registered partitioner name.
187 pub partitioner: Option<String>,
188
189 // Thread count for child partitions.
190 #[serde(default)]
191 pub thread_count: MoveThreadCount,
192
193 // Whether to log partition progress.
194 #[serde(default)]
195 pub log_progress: bool,
196
197 // Optional child phase list to run inside each partition.
198 #[serde(default)]
199 pub child_phases: Vec<PhaseConfig>,
200
201 // Phase termination configuration.
202 pub termination: Option<TerminationConfig>,
203}
204
205// Custom phase configuration.
206#[derive(Debug, Clone, Default, Deserialize, Serialize)]
207#[serde(rename_all = "snake_case")]
208pub struct CustomPhaseConfig {
209 // Compile-time registered custom phase name.
210 pub name: String,
211}