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) -> usize,
15 provider_index: usize,
16 },
17 EntitySlice {
18 values_for_entity: for<'a> fn(&'a S, usize, usize) -> &'a [usize],
19 },
20}
21
22impl<S> Clone for ValueSource<S> {
23 fn clone(&self) -> Self {
24 *self
25 }
26}
27
28impl<S> Copy for ValueSource<S> {}
29
30impl<S> fmt::Debug for ValueSource<S> {
31 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
32 match self {
33 Self::Empty => write!(f, "ValueSource::Empty"),
34 Self::CountableRange { from, to } => {
35 write!(f, "ValueSource::CountableRange({from}..{to})")
36 }
37 Self::SolutionCount { provider_index, .. } => {
38 write!(f, "ValueSource::SolutionCount(provider={provider_index})")
39 }
40 Self::EntitySlice { .. } => write!(f, "ValueSource::EntitySlice(..)"),
41 }
42 }
43}
44
45pub type ScalarGetter<S> = fn(&S, usize, usize) -> Option<usize>;
46pub type ScalarSetter<S> = fn(&mut S, usize, usize, Option<usize>);
47pub type NearbyValueDistanceMeter<S> = fn(&S, usize, usize, usize) -> Option<f64>;
48pub type NearbyEntityDistanceMeter<S> = fn(&S, usize, usize, usize) -> Option<f64>;
49pub type ConstructionEntityOrderKey<S> = fn(&S, usize, usize) -> Option<i64>;
50pub type ConstructionValueOrderKey<S> = fn(&S, usize, usize, usize) -> Option<i64>;
51
52pub struct ScalarVariableContext<S> {
53 pub descriptor_index: usize,
54 pub variable_index: usize,
55 pub entity_type_name: &'static str,
56 pub entity_count: fn(&S) -> usize,
57 pub variable_name: &'static str,
58 pub getter: ScalarGetter<S>,
59 pub setter: ScalarSetter<S>,
60 pub value_source: ValueSource<S>,
61 pub allows_unassigned: bool,
62 pub nearby_value_distance_meter: Option<NearbyValueDistanceMeter<S>>,
63 pub nearby_entity_distance_meter: Option<NearbyEntityDistanceMeter<S>>,
64 pub construction_entity_order_key: Option<ConstructionEntityOrderKey<S>>,
65 pub construction_value_order_key: Option<ConstructionValueOrderKey<S>>,
66}
67
68impl<S> Clone for ScalarVariableContext<S> {
69 fn clone(&self) -> Self {
70 *self
71 }
72}
73
74impl<S> Copy for ScalarVariableContext<S> {}
75
76impl<S> ScalarVariableContext<S> {
77 #[allow(clippy::too_many_arguments)]
78 pub fn new(
79 descriptor_index: usize,
80 variable_index: usize,
81 entity_type_name: &'static str,
82 entity_count: fn(&S) -> usize,
83 variable_name: &'static str,
84 getter: ScalarGetter<S>,
85 setter: ScalarSetter<S>,
86 value_source: ValueSource<S>,
87 allows_unassigned: bool,
88 ) -> Self {
89 Self {
90 descriptor_index,
91 variable_index,
92 entity_type_name,
93 entity_count,
94 variable_name,
95 getter,
96 setter,
97 value_source,
98 allows_unassigned,
99 nearby_value_distance_meter: None,
100 nearby_entity_distance_meter: None,
101 construction_entity_order_key: None,
102 construction_value_order_key: None,
103 }
104 }
105
106 pub fn with_nearby_value_distance_meter(mut self, meter: NearbyValueDistanceMeter<S>) -> Self {
107 self.nearby_value_distance_meter = Some(meter);
108 self
109 }
110
111 pub fn with_nearby_entity_distance_meter(
112 mut self,
113 meter: NearbyEntityDistanceMeter<S>,
114 ) -> Self {
115 self.nearby_entity_distance_meter = Some(meter);
116 self
117 }
118
119 pub fn with_construction_entity_order_key(
120 mut self,
121 order_key: ConstructionEntityOrderKey<S>,
122 ) -> Self {
123 self.construction_entity_order_key = Some(order_key);
124 self
125 }
126
127 pub fn with_construction_value_order_key(
128 mut self,
129 order_key: ConstructionValueOrderKey<S>,
130 ) -> Self {
131 self.construction_value_order_key = Some(order_key);
132 self
133 }
134
135 pub fn matches_target(&self, entity_class: Option<&str>, variable_name: Option<&str>) -> bool {
136 entity_class.is_none_or(|name| name == self.entity_type_name)
137 && variable_name.is_none_or(|name| name == self.variable_name)
138 }
139
140 pub fn current_value(&self, solution: &S, entity_index: usize) -> Option<usize> {
141 (self.getter)(solution, entity_index, self.variable_index)
142 }
143
144 pub fn set_value(&self, solution: &mut S, entity_index: usize, value: Option<usize>) {
145 (self.setter)(solution, entity_index, self.variable_index, value);
146 }
147
148 pub fn values_for_entity(&self, solution: &S, entity_index: usize) -> Vec<usize> {
149 match self.value_source {
150 ValueSource::Empty => Vec::new(),
151 ValueSource::CountableRange { from, to } => (from..to).collect(),
152 ValueSource::SolutionCount {
153 count_fn,
154 provider_index,
155 } => (0..count_fn(solution, provider_index)).collect(),
156 ValueSource::EntitySlice { values_for_entity } => {
157 values_for_entity(solution, entity_index, self.variable_index).to_vec()
158 }
159 }
160 }
161
162 pub fn has_values_for_entity(&self, solution: &S, entity_index: usize) -> bool {
163 match self.value_source {
164 ValueSource::Empty => false,
165 ValueSource::CountableRange { from, to } => from < to,
166 ValueSource::SolutionCount {
167 count_fn,
168 provider_index,
169 } => count_fn(solution, provider_index) > 0,
170 ValueSource::EntitySlice { values_for_entity } => {
171 !values_for_entity(solution, entity_index, self.variable_index).is_empty()
172 }
173 }
174 }
175
176 pub fn nearby_value_distance(
177 &self,
178 solution: &S,
179 entity_index: usize,
180 value: usize,
181 ) -> Option<f64> {
182 self.nearby_value_distance_meter
183 .and_then(|meter| meter(solution, entity_index, self.variable_index, value))
184 }
185
186 pub fn nearby_entity_distance(
187 &self,
188 solution: &S,
189 left_entity_index: usize,
190 right_entity_index: usize,
191 ) -> Option<f64> {
192 self.nearby_entity_distance_meter.and_then(|meter| {
193 meter(
194 solution,
195 left_entity_index,
196 right_entity_index,
197 self.variable_index,
198 )
199 })
200 }
201
202 pub fn construction_entity_order_key(&self, solution: &S, entity_index: usize) -> Option<i64> {
203 self.construction_entity_order_key
204 .and_then(|order_key| order_key(solution, entity_index, self.variable_index))
205 }
206
207 pub fn construction_value_order_key(
208 &self,
209 solution: &S,
210 entity_index: usize,
211 value: usize,
212 ) -> Option<i64> {
213 self.construction_value_order_key
214 .and_then(|order_key| order_key(solution, entity_index, self.variable_index, value))
215 }
216}
217
218impl<S> fmt::Debug for ScalarVariableContext<S> {
219 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
220 f.debug_struct("ScalarVariableContext")
221 .field("descriptor_index", &self.descriptor_index)
222 .field("variable_index", &self.variable_index)
223 .field("entity_type_name", &self.entity_type_name)
224 .field("variable_name", &self.variable_name)
225 .field("value_source", &self.value_source)
226 .field("allows_unassigned", &self.allows_unassigned)
227 .field(
228 "has_nearby_value_distance_meter",
229 &self.nearby_value_distance_meter.is_some(),
230 )
231 .field(
232 "has_nearby_entity_distance_meter",
233 &self.nearby_entity_distance_meter.is_some(),
234 )
235 .field(
236 "has_construction_entity_order_key",
237 &self.construction_entity_order_key.is_some(),
238 )
239 .field(
240 "has_construction_value_order_key",
241 &self.construction_value_order_key.is_some(),
242 )
243 .finish()
244 }
245}
246
247#[derive(Debug, Clone)]
248pub struct IntraDistanceAdapter<T>(pub T);
249
250impl<S, T: CrossEntityDistanceMeter<S>> ListPositionDistanceMeter<S> for IntraDistanceAdapter<T> {
251 fn distance(&self, solution: &S, entity_idx: usize, pos_a: usize, pos_b: usize) -> f64 {
252 self.0
253 .distance(solution, entity_idx, pos_a, entity_idx, pos_b)
254 }
255}
256
257pub struct ListVariableContext<S, V, DM, IDM> {
258 pub entity_type_name: &'static str,
259 pub element_count: fn(&S) -> usize,
260 pub assigned_elements: fn(&S) -> Vec<V>,
261 pub list_len: fn(&S, usize) -> usize,
262 pub list_remove: fn(&mut S, usize, usize) -> Option<V>,
263 pub construction_list_remove: fn(&mut S, usize, usize) -> V,
264 pub list_insert: fn(&mut S, usize, usize, V),
265 pub list_get: fn(&S, usize, usize) -> Option<V>,
266 pub list_set: fn(&mut S, usize, usize, V),
267 pub list_reverse: fn(&mut S, usize, usize, usize),
268 pub sublist_remove: fn(&mut S, usize, usize, usize) -> Vec<V>,
269 pub sublist_insert: fn(&mut S, usize, usize, Vec<V>),
270 pub ruin_remove: fn(&mut S, usize, usize) -> V,
271 pub ruin_insert: fn(&mut S, usize, usize, V),
272 pub index_to_element: fn(&S, usize) -> V,
273 pub entity_count: fn(&S) -> usize,
274 pub cross_distance_meter: DM,
275 pub intra_distance_meter: IDM,
276 pub variable_name: &'static str,
277 pub descriptor_index: usize,
278 pub merge_feasible_fn: Option<fn(&S, &[usize]) -> bool>,
279 pub cw_depot_fn: Option<fn(&S) -> usize>,
280 pub cw_distance_fn: Option<fn(&S, usize, usize) -> i64>,
281 pub cw_element_load_fn: Option<fn(&S, usize) -> i64>,
282 pub cw_capacity_fn: Option<fn(&S) -> i64>,
283 pub cw_assign_route_fn: Option<fn(&mut S, usize, Vec<V>)>,
284 pub k_opt_get_route: Option<fn(&S, usize) -> Vec<usize>>,
285 pub k_opt_set_route: Option<fn(&mut S, usize, Vec<usize>)>,
286 pub k_opt_depot_fn: Option<fn(&S, usize) -> usize>,
287 pub k_opt_distance_fn: Option<fn(&S, usize, usize) -> i64>,
288 pub k_opt_feasible_fn: Option<fn(&S, usize, &[usize]) -> bool>,
289 _phantom: PhantomData<(fn() -> S, fn() -> V)>,
290}
291
292impl<S, V, DM: Clone, IDM: Clone> Clone for ListVariableContext<S, V, DM, IDM> {
293 fn clone(&self) -> Self {
294 Self {
295 entity_type_name: self.entity_type_name,
296 element_count: self.element_count,
297 assigned_elements: self.assigned_elements,
298 list_len: self.list_len,
299 list_remove: self.list_remove,
300 construction_list_remove: self.construction_list_remove,
301 list_insert: self.list_insert,
302 list_get: self.list_get,
303 list_set: self.list_set,
304 list_reverse: self.list_reverse,
305 sublist_remove: self.sublist_remove,
306 sublist_insert: self.sublist_insert,
307 ruin_remove: self.ruin_remove,
308 ruin_insert: self.ruin_insert,
309 index_to_element: self.index_to_element,
310 entity_count: self.entity_count,
311 cross_distance_meter: self.cross_distance_meter.clone(),
312 intra_distance_meter: self.intra_distance_meter.clone(),
313 variable_name: self.variable_name,
314 descriptor_index: self.descriptor_index,
315 merge_feasible_fn: self.merge_feasible_fn,
316 cw_depot_fn: self.cw_depot_fn,
317 cw_distance_fn: self.cw_distance_fn,
318 cw_element_load_fn: self.cw_element_load_fn,
319 cw_capacity_fn: self.cw_capacity_fn,
320 cw_assign_route_fn: self.cw_assign_route_fn,
321 k_opt_get_route: self.k_opt_get_route,
322 k_opt_set_route: self.k_opt_set_route,
323 k_opt_depot_fn: self.k_opt_depot_fn,
324 k_opt_distance_fn: self.k_opt_distance_fn,
325 k_opt_feasible_fn: self.k_opt_feasible_fn,
326 _phantom: PhantomData,
327 }
328 }
329}
330
331impl<S, V, DM, IDM> ListVariableContext<S, V, DM, IDM> {
332 #[allow(clippy::too_many_arguments)]
333 pub fn new(
334 entity_type_name: &'static str,
335 element_count: fn(&S) -> usize,
336 assigned_elements: fn(&S) -> Vec<V>,
337 list_len: fn(&S, usize) -> usize,
338 list_remove: fn(&mut S, usize, usize) -> Option<V>,
339 construction_list_remove: fn(&mut S, usize, usize) -> V,
340 list_insert: fn(&mut S, usize, usize, V),
341 list_get: fn(&S, usize, usize) -> Option<V>,
342 list_set: fn(&mut S, usize, usize, V),
343 list_reverse: fn(&mut S, usize, usize, usize),
344 sublist_remove: fn(&mut S, usize, usize, usize) -> Vec<V>,
345 sublist_insert: fn(&mut S, usize, usize, Vec<V>),
346 ruin_remove: fn(&mut S, usize, usize) -> V,
347 ruin_insert: fn(&mut S, usize, usize, V),
348 index_to_element: fn(&S, usize) -> V,
349 entity_count: fn(&S) -> usize,
350 cross_distance_meter: DM,
351 intra_distance_meter: IDM,
352 variable_name: &'static str,
353 descriptor_index: usize,
354 merge_feasible_fn: Option<fn(&S, &[usize]) -> bool>,
355 cw_depot_fn: Option<fn(&S) -> usize>,
356 cw_distance_fn: Option<fn(&S, usize, usize) -> i64>,
357 cw_element_load_fn: Option<fn(&S, usize) -> i64>,
358 cw_capacity_fn: Option<fn(&S) -> i64>,
359 cw_assign_route_fn: Option<fn(&mut S, usize, Vec<V>)>,
360 k_opt_get_route: Option<fn(&S, usize) -> Vec<usize>>,
361 k_opt_set_route: Option<fn(&mut S, usize, Vec<usize>)>,
362 k_opt_depot_fn: Option<fn(&S, usize) -> usize>,
363 k_opt_distance_fn: Option<fn(&S, usize, usize) -> i64>,
364 k_opt_feasible_fn: Option<fn(&S, usize, &[usize]) -> bool>,
365 ) -> Self {
366 Self {
367 entity_type_name,
368 element_count,
369 assigned_elements,
370 list_len,
371 list_remove,
372 construction_list_remove,
373 list_insert,
374 list_get,
375 list_set,
376 list_reverse,
377 sublist_remove,
378 sublist_insert,
379 ruin_remove,
380 ruin_insert,
381 index_to_element,
382 entity_count,
383 cross_distance_meter,
384 intra_distance_meter,
385 variable_name,
386 descriptor_index,
387 merge_feasible_fn,
388 cw_depot_fn,
389 cw_distance_fn,
390 cw_element_load_fn,
391 cw_capacity_fn,
392 cw_assign_route_fn,
393 k_opt_get_route,
394 k_opt_set_route,
395 k_opt_depot_fn,
396 k_opt_distance_fn,
397 k_opt_feasible_fn,
398 _phantom: PhantomData,
399 }
400 }
401
402 pub fn matches_target(&self, entity_class: Option<&str>, variable_name: Option<&str>) -> bool {
403 entity_class.is_none_or(|name| name == self.entity_type_name)
404 && variable_name.is_none_or(|name| name == self.variable_name)
405 }
406}
407
408impl<S, V, DM: fmt::Debug, IDM: fmt::Debug> fmt::Debug for ListVariableContext<S, V, DM, IDM> {
409 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
410 f.debug_struct("ListVariableContext")
411 .field("entity_type_name", &self.entity_type_name)
412 .field("variable_name", &self.variable_name)
413 .field("descriptor_index", &self.descriptor_index)
414 .finish()
415 }
416}
417
418pub enum VariableContext<S, V, DM, IDM> {
419 Scalar(ScalarVariableContext<S>),
420 List(ListVariableContext<S, V, DM, IDM>),
421}
422
423impl<S, V, DM: Clone, IDM: Clone> Clone for VariableContext<S, V, DM, IDM> {
424 fn clone(&self) -> Self {
425 match self {
426 Self::Scalar(variable) => Self::Scalar(*variable),
427 Self::List(variable) => Self::List(variable.clone()),
428 }
429 }
430}
431
432impl<S, V, DM: fmt::Debug, IDM: fmt::Debug> fmt::Debug for VariableContext<S, V, DM, IDM> {
433 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
434 match self {
435 Self::Scalar(variable) => variable.fmt(f),
436 Self::List(variable) => variable.fmt(f),
437 }
438 }
439}
440
441pub struct ModelContext<S, V, DM, IDM> {
442 variables: Vec<VariableContext<S, V, DM, IDM>>,
443 _phantom: PhantomData<(fn() -> S, fn() -> V)>,
444}
445
446impl<S, V, DM: Clone, IDM: Clone> Clone for ModelContext<S, V, DM, IDM> {
447 fn clone(&self) -> Self {
448 Self {
449 variables: self.variables.clone(),
450 _phantom: PhantomData,
451 }
452 }
453}
454
455impl<S, V, DM, IDM> ModelContext<S, V, DM, IDM> {
456 pub fn new(variables: Vec<VariableContext<S, V, DM, IDM>>) -> Self {
457 Self {
458 variables,
459 _phantom: PhantomData,
460 }
461 }
462
463 pub fn variables(&self) -> &[VariableContext<S, V, DM, IDM>] {
464 &self.variables
465 }
466
467 pub fn is_empty(&self) -> bool {
468 self.variables.is_empty()
469 }
470
471 pub fn has_list_variables(&self) -> bool {
472 self.variables
473 .iter()
474 .any(|variable| matches!(variable, VariableContext::List(_)))
475 }
476
477 pub fn scalar_variables(&self) -> impl Iterator<Item = &ScalarVariableContext<S>> {
478 self.variables.iter().filter_map(|variable| match variable {
479 VariableContext::Scalar(ctx) => Some(ctx),
480 VariableContext::List(_) => None,
481 })
482 }
483
484 pub fn list_variables(&self) -> impl Iterator<Item = &ListVariableContext<S, V, DM, IDM>> {
485 self.variables.iter().filter_map(|variable| match variable {
486 VariableContext::List(ctx) => Some(ctx),
487 VariableContext::Scalar(_) => None,
488 })
489 }
490}
491
492impl<S, V, DM: fmt::Debug, IDM: fmt::Debug> fmt::Debug for ModelContext<S, V, DM, IDM> {
493 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
494 f.debug_struct("ModelContext")
495 .field("variables", &self.variables)
496 .finish()
497 }
498}