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