1use std::fmt;
2use std::marker::PhantomData;
3
4use crate::heuristic::selector::k_opt::ListPositionDistanceMeter;
5use crate::heuristic::selector::nearby_list_change::CrossEntityDistanceMeter;
6
7pub enum ValueSource<S> {
8 Empty,
9 CountableRange {
10 from: usize,
11 to: usize,
12 },
13 SolutionCount {
14 count_fn: fn(&S) -> usize,
15 },
16 EntitySlice {
17 values_for_entity: for<'a> fn(&'a S, usize) -> &'a [usize],
18 },
19}
20
21impl<S> Clone for ValueSource<S> {
22 fn clone(&self) -> Self {
23 *self
24 }
25}
26
27impl<S> Copy for ValueSource<S> {}
28
29impl<S> fmt::Debug for ValueSource<S> {
30 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
31 match self {
32 Self::Empty => write!(f, "ValueSource::Empty"),
33 Self::CountableRange { from, to } => {
34 write!(f, "ValueSource::CountableRange({from}..{to})")
35 }
36 Self::SolutionCount { .. } => write!(f, "ValueSource::SolutionCount(..)"),
37 Self::EntitySlice { .. } => write!(f, "ValueSource::EntitySlice(..)"),
38 }
39 }
40}
41
42pub struct ScalarVariableContext<S> {
43 pub descriptor_index: usize,
44 pub entity_type_name: &'static str,
45 pub entity_count: fn(&S) -> usize,
46 pub variable_name: &'static str,
47 pub getter: fn(&S, usize) -> Option<usize>,
48 pub setter: fn(&mut S, usize, Option<usize>),
49 pub value_source: ValueSource<S>,
50 pub allows_unassigned: bool,
51}
52
53impl<S> Clone for ScalarVariableContext<S> {
54 fn clone(&self) -> Self {
55 *self
56 }
57}
58
59impl<S> Copy for ScalarVariableContext<S> {}
60
61impl<S> ScalarVariableContext<S> {
62 #[allow(clippy::too_many_arguments)]
63 pub fn new(
64 descriptor_index: usize,
65 entity_type_name: &'static str,
66 entity_count: fn(&S) -> usize,
67 variable_name: &'static str,
68 getter: fn(&S, usize) -> Option<usize>,
69 setter: fn(&mut S, usize, Option<usize>),
70 value_source: ValueSource<S>,
71 allows_unassigned: bool,
72 ) -> Self {
73 Self {
74 descriptor_index,
75 entity_type_name,
76 entity_count,
77 variable_name,
78 getter,
79 setter,
80 value_source,
81 allows_unassigned,
82 }
83 }
84
85 pub fn matches_target(&self, entity_class: Option<&str>, variable_name: Option<&str>) -> bool {
86 entity_class.is_none_or(|name| name == self.entity_type_name)
87 && variable_name.is_none_or(|name| name == self.variable_name)
88 }
89}
90
91impl<S> fmt::Debug for ScalarVariableContext<S> {
92 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
93 f.debug_struct("ScalarVariableContext")
94 .field("descriptor_index", &self.descriptor_index)
95 .field("entity_type_name", &self.entity_type_name)
96 .field("variable_name", &self.variable_name)
97 .field("value_source", &self.value_source)
98 .field("allows_unassigned", &self.allows_unassigned)
99 .finish()
100 }
101}
102
103#[derive(Debug, Clone)]
104pub struct IntraDistanceAdapter<T>(pub T);
105
106impl<S, T: CrossEntityDistanceMeter<S>> ListPositionDistanceMeter<S> for IntraDistanceAdapter<T> {
107 fn distance(&self, solution: &S, entity_idx: usize, pos_a: usize, pos_b: usize) -> f64 {
108 self.0
109 .distance(solution, entity_idx, pos_a, entity_idx, pos_b)
110 }
111}
112
113pub struct ListVariableContext<S, V, DM, IDM> {
114 pub entity_type_name: &'static str,
115 pub element_count: fn(&S) -> usize,
116 pub assigned_elements: fn(&S) -> Vec<V>,
117 pub list_len: fn(&S, usize) -> usize,
118 pub list_remove: fn(&mut S, usize, usize) -> Option<V>,
119 pub construction_list_remove: fn(&mut S, usize, usize) -> V,
120 pub list_insert: fn(&mut S, usize, usize, V),
121 pub list_get: fn(&S, usize, usize) -> Option<V>,
122 pub list_set: fn(&mut S, usize, usize, V),
123 pub list_reverse: fn(&mut S, usize, usize, usize),
124 pub sublist_remove: fn(&mut S, usize, usize, usize) -> Vec<V>,
125 pub sublist_insert: fn(&mut S, usize, usize, Vec<V>),
126 pub ruin_remove: fn(&mut S, usize, usize) -> V,
127 pub ruin_insert: fn(&mut S, usize, usize, V),
128 pub index_to_element: fn(&S, usize) -> V,
129 pub entity_count: fn(&S) -> usize,
130 pub cross_distance_meter: DM,
131 pub intra_distance_meter: IDM,
132 pub variable_name: &'static str,
133 pub descriptor_index: usize,
134 pub merge_feasible_fn: Option<fn(&S, &[usize]) -> bool>,
135 pub cw_depot_fn: Option<fn(&S) -> usize>,
136 pub cw_distance_fn: Option<fn(&S, usize, usize) -> i64>,
137 pub cw_element_load_fn: Option<fn(&S, usize) -> i64>,
138 pub cw_capacity_fn: Option<fn(&S) -> i64>,
139 pub cw_assign_route_fn: Option<fn(&mut S, usize, Vec<V>)>,
140 pub k_opt_get_route: Option<fn(&S, usize) -> Vec<usize>>,
141 pub k_opt_set_route: Option<fn(&mut S, usize, Vec<usize>)>,
142 pub k_opt_depot_fn: Option<fn(&S, usize) -> usize>,
143 pub k_opt_distance_fn: Option<fn(&S, usize, usize) -> i64>,
144 pub k_opt_feasible_fn: Option<fn(&S, usize, &[usize]) -> bool>,
145 _phantom: PhantomData<(fn() -> S, fn() -> V)>,
146}
147
148impl<S, V, DM: Clone, IDM: Clone> Clone for ListVariableContext<S, V, DM, IDM> {
149 fn clone(&self) -> Self {
150 Self {
151 entity_type_name: self.entity_type_name,
152 element_count: self.element_count,
153 assigned_elements: self.assigned_elements,
154 list_len: self.list_len,
155 list_remove: self.list_remove,
156 construction_list_remove: self.construction_list_remove,
157 list_insert: self.list_insert,
158 list_get: self.list_get,
159 list_set: self.list_set,
160 list_reverse: self.list_reverse,
161 sublist_remove: self.sublist_remove,
162 sublist_insert: self.sublist_insert,
163 ruin_remove: self.ruin_remove,
164 ruin_insert: self.ruin_insert,
165 index_to_element: self.index_to_element,
166 entity_count: self.entity_count,
167 cross_distance_meter: self.cross_distance_meter.clone(),
168 intra_distance_meter: self.intra_distance_meter.clone(),
169 variable_name: self.variable_name,
170 descriptor_index: self.descriptor_index,
171 merge_feasible_fn: self.merge_feasible_fn,
172 cw_depot_fn: self.cw_depot_fn,
173 cw_distance_fn: self.cw_distance_fn,
174 cw_element_load_fn: self.cw_element_load_fn,
175 cw_capacity_fn: self.cw_capacity_fn,
176 cw_assign_route_fn: self.cw_assign_route_fn,
177 k_opt_get_route: self.k_opt_get_route,
178 k_opt_set_route: self.k_opt_set_route,
179 k_opt_depot_fn: self.k_opt_depot_fn,
180 k_opt_distance_fn: self.k_opt_distance_fn,
181 k_opt_feasible_fn: self.k_opt_feasible_fn,
182 _phantom: PhantomData,
183 }
184 }
185}
186
187impl<S, V, DM, IDM> ListVariableContext<S, V, DM, IDM> {
188 #[allow(clippy::too_many_arguments)]
189 pub fn new(
190 entity_type_name: &'static str,
191 element_count: fn(&S) -> usize,
192 assigned_elements: fn(&S) -> Vec<V>,
193 list_len: fn(&S, usize) -> usize,
194 list_remove: fn(&mut S, usize, usize) -> Option<V>,
195 construction_list_remove: fn(&mut S, usize, usize) -> V,
196 list_insert: fn(&mut S, usize, usize, V),
197 list_get: fn(&S, usize, usize) -> Option<V>,
198 list_set: fn(&mut S, usize, usize, V),
199 list_reverse: fn(&mut S, usize, usize, usize),
200 sublist_remove: fn(&mut S, usize, usize, usize) -> Vec<V>,
201 sublist_insert: fn(&mut S, usize, usize, Vec<V>),
202 ruin_remove: fn(&mut S, usize, usize) -> V,
203 ruin_insert: fn(&mut S, usize, usize, V),
204 index_to_element: fn(&S, usize) -> V,
205 entity_count: fn(&S) -> usize,
206 cross_distance_meter: DM,
207 intra_distance_meter: IDM,
208 variable_name: &'static str,
209 descriptor_index: usize,
210 merge_feasible_fn: Option<fn(&S, &[usize]) -> bool>,
211 cw_depot_fn: Option<fn(&S) -> usize>,
212 cw_distance_fn: Option<fn(&S, usize, usize) -> i64>,
213 cw_element_load_fn: Option<fn(&S, usize) -> i64>,
214 cw_capacity_fn: Option<fn(&S) -> i64>,
215 cw_assign_route_fn: Option<fn(&mut S, usize, Vec<V>)>,
216 k_opt_get_route: Option<fn(&S, usize) -> Vec<usize>>,
217 k_opt_set_route: Option<fn(&mut S, usize, Vec<usize>)>,
218 k_opt_depot_fn: Option<fn(&S, usize) -> usize>,
219 k_opt_distance_fn: Option<fn(&S, usize, usize) -> i64>,
220 k_opt_feasible_fn: Option<fn(&S, usize, &[usize]) -> bool>,
221 ) -> Self {
222 Self {
223 entity_type_name,
224 element_count,
225 assigned_elements,
226 list_len,
227 list_remove,
228 construction_list_remove,
229 list_insert,
230 list_get,
231 list_set,
232 list_reverse,
233 sublist_remove,
234 sublist_insert,
235 ruin_remove,
236 ruin_insert,
237 index_to_element,
238 entity_count,
239 cross_distance_meter,
240 intra_distance_meter,
241 variable_name,
242 descriptor_index,
243 merge_feasible_fn,
244 cw_depot_fn,
245 cw_distance_fn,
246 cw_element_load_fn,
247 cw_capacity_fn,
248 cw_assign_route_fn,
249 k_opt_get_route,
250 k_opt_set_route,
251 k_opt_depot_fn,
252 k_opt_distance_fn,
253 k_opt_feasible_fn,
254 _phantom: PhantomData,
255 }
256 }
257
258 pub fn matches_target(&self, entity_class: Option<&str>, variable_name: Option<&str>) -> bool {
259 entity_class.is_none_or(|name| name == self.entity_type_name)
260 && variable_name.is_none_or(|name| name == self.variable_name)
261 }
262}
263
264impl<S, V, DM: fmt::Debug, IDM: fmt::Debug> fmt::Debug for ListVariableContext<S, V, DM, IDM> {
265 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
266 f.debug_struct("ListVariableContext")
267 .field("entity_type_name", &self.entity_type_name)
268 .field("variable_name", &self.variable_name)
269 .field("descriptor_index", &self.descriptor_index)
270 .finish()
271 }
272}
273
274pub enum VariableContext<S, V, DM, IDM> {
275 Scalar(ScalarVariableContext<S>),
276 List(ListVariableContext<S, V, DM, IDM>),
277}
278
279impl<S, V, DM: Clone, IDM: Clone> Clone for VariableContext<S, V, DM, IDM> {
280 fn clone(&self) -> Self {
281 match self {
282 Self::Scalar(variable) => Self::Scalar(*variable),
283 Self::List(variable) => Self::List(variable.clone()),
284 }
285 }
286}
287
288impl<S, V, DM: fmt::Debug, IDM: fmt::Debug> fmt::Debug for VariableContext<S, V, DM, IDM> {
289 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
290 match self {
291 Self::Scalar(variable) => variable.fmt(f),
292 Self::List(variable) => variable.fmt(f),
293 }
294 }
295}
296
297pub struct ModelContext<S, V, DM, IDM> {
298 variables: Vec<VariableContext<S, V, DM, IDM>>,
299 _phantom: PhantomData<(fn() -> S, fn() -> V)>,
300}
301
302impl<S, V, DM: Clone, IDM: Clone> Clone for ModelContext<S, V, DM, IDM> {
303 fn clone(&self) -> Self {
304 Self {
305 variables: self.variables.clone(),
306 _phantom: PhantomData,
307 }
308 }
309}
310
311impl<S, V, DM, IDM> ModelContext<S, V, DM, IDM> {
312 pub fn new(variables: Vec<VariableContext<S, V, DM, IDM>>) -> Self {
313 Self {
314 variables,
315 _phantom: PhantomData,
316 }
317 }
318
319 pub fn variables(&self) -> &[VariableContext<S, V, DM, IDM>] {
320 &self.variables
321 }
322
323 pub fn is_empty(&self) -> bool {
324 self.variables.is_empty()
325 }
326
327 pub fn has_list_variables(&self) -> bool {
328 self.variables
329 .iter()
330 .any(|variable| matches!(variable, VariableContext::List(_)))
331 }
332
333 pub fn scalar_variables(&self) -> impl Iterator<Item = &ScalarVariableContext<S>> {
334 self.variables.iter().filter_map(|variable| match variable {
335 VariableContext::Scalar(ctx) => Some(ctx),
336 VariableContext::List(_) => None,
337 })
338 }
339
340 pub fn list_variables(&self) -> impl Iterator<Item = &ListVariableContext<S, V, DM, IDM>> {
341 self.variables.iter().filter_map(|variable| match variable {
342 VariableContext::List(ctx) => Some(ctx),
343 VariableContext::Scalar(_) => None,
344 })
345 }
346}
347
348impl<S, V, DM: fmt::Debug, IDM: fmt::Debug> fmt::Debug for ModelContext<S, V, DM, IDM> {
349 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
350 f.debug_struct("ModelContext")
351 .field("variables", &self.variables)
352 .finish()
353 }
354}