Skip to main content

solverforge_solver/builder/
context.rs

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}