Skip to main content

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}