Skip to main content

solverforge_solver/builder/
context.rs

1// Context types that carry domain function pointers into the builder layer.
2
3use std::marker::PhantomData;
4
5use crate::heuristic::selector::k_opt::ListPositionDistanceMeter;
6use crate::heuristic::selector::nearby_list_change::CrossEntityDistanceMeter;
7
8/* Adapts a `CrossEntityDistanceMeter` to `ListPositionDistanceMeter` for intra-entity use.
9
10`NearbyKOptMoveSelector` requires a `ListPositionDistanceMeter` (4-param intra-entity),
11but `ListContext.intra_distance_meter` is a `CrossEntityDistanceMeter` (5-param).
12This adapter bridges the two by always calling with `src_entity_idx == dst_entity_idx`.
13*/
14#[derive(Debug, Clone)]
15pub struct IntraDistanceAdapter<T>(pub T);
16
17impl<S, T: CrossEntityDistanceMeter<S>> ListPositionDistanceMeter<S> for IntraDistanceAdapter<T> {
18    fn distance(&self, solution: &S, entity_idx: usize, pos_a: usize, pos_b: usize) -> f64 {
19        self.0
20            .distance(solution, entity_idx, pos_a, entity_idx, pos_b)
21    }
22}
23
24/// Function-pointer context for basic (non-list) variable solvers.
25///
26/// Carries all domain callbacks needed to construct move selectors
27/// without requiring `dyn` or closures.
28pub struct BasicContext<S> {
29    pub get_variable: fn(&S, usize) -> Option<usize>,
30    pub set_variable: fn(&mut S, usize, Option<usize>),
31    // All valid values for the variable.
32    pub values: Vec<usize>,
33    // Descriptor index for the entity collection.
34    pub descriptor_index: usize,
35    // Variable field name.
36    pub variable_field: &'static str,
37}
38
39impl<S> std::fmt::Debug for BasicContext<S> {
40    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
41        f.debug_struct("BasicContext")
42            .field("descriptor_index", &self.descriptor_index)
43            .field("variable_field", &self.variable_field)
44            .field("values_len", &self.values.len())
45            .finish()
46    }
47}
48
49/// Function-pointer context for list variable solvers.
50///
51/// Carries all domain callbacks and distance meters needed to construct
52/// list move selectors without requiring `dyn` or closures.
53pub struct ListContext<S, V, DM, IDM> {
54    pub list_len: fn(&S, usize) -> usize,
55    // Removes element at `pos` from entity `i`, returning it (returns `None` if out of bounds).
56    pub list_remove: fn(&mut S, usize, usize) -> Option<V>,
57    // Inserts `val` at `pos` in entity `i`.
58    pub list_insert: fn(&mut S, usize, usize, V),
59    pub list_get: fn(&S, usize, usize) -> Option<V>,
60    // Replaces element at `pos` in entity `i`.
61    pub list_set: fn(&mut S, usize, usize, V),
62    // Reverses the segment `[start, end)` in entity `i`.
63    pub list_reverse: fn(&mut S, usize, usize, usize),
64    // Removes segment `[start, end)` from entity `i`.
65    pub sublist_remove: fn(&mut S, usize, usize, usize) -> Vec<V>,
66    // Inserts `items` at `pos` in entity `i`.
67    pub sublist_insert: fn(&mut S, usize, usize, Vec<V>),
68    // Removes element at `pos` from entity `i` for ruin moves (panics if out of bounds).
69    pub ruin_remove: fn(&mut S, usize, usize) -> V,
70    // Inserts `val` at `pos` in entity `i` for ruin reinsertion.
71    pub ruin_insert: fn(&mut S, usize, usize, V),
72    pub entity_count: fn(&S) -> usize,
73    // Cross-entity (inter-route) distance meter.
74    pub cross_distance_meter: DM,
75    // Intra-entity (intra-route) distance meter.
76    pub intra_distance_meter: IDM,
77    // List variable field name.
78    pub variable_name: &'static str,
79    // Descriptor index for the list owner entity collection.
80    pub descriptor_index: usize,
81    _phantom: PhantomData<(fn() -> S, fn() -> V)>,
82}
83
84impl<S, V, DM, IDM> ListContext<S, V, DM, IDM> {
85    #[allow(clippy::too_many_arguments)]
86    pub fn new(
87        list_len: fn(&S, usize) -> usize,
88        list_remove: fn(&mut S, usize, usize) -> Option<V>,
89        list_insert: fn(&mut S, usize, usize, V),
90        list_get: fn(&S, usize, usize) -> Option<V>,
91        list_set: fn(&mut S, usize, usize, V),
92        list_reverse: fn(&mut S, usize, usize, usize),
93        sublist_remove: fn(&mut S, usize, usize, usize) -> Vec<V>,
94        sublist_insert: fn(&mut S, usize, usize, Vec<V>),
95        ruin_remove: fn(&mut S, usize, usize) -> V,
96        ruin_insert: fn(&mut S, usize, usize, V),
97        entity_count: fn(&S) -> usize,
98        cross_distance_meter: DM,
99        intra_distance_meter: IDM,
100        variable_name: &'static str,
101        descriptor_index: usize,
102    ) -> Self {
103        Self {
104            list_len,
105            list_remove,
106            list_insert,
107            list_get,
108            list_set,
109            list_reverse,
110            sublist_remove,
111            sublist_insert,
112            ruin_remove,
113            ruin_insert,
114            entity_count,
115            cross_distance_meter,
116            intra_distance_meter,
117            variable_name,
118            descriptor_index,
119            _phantom: PhantomData,
120        }
121    }
122}
123
124impl<S, V, DM: std::fmt::Debug, IDM: std::fmt::Debug> std::fmt::Debug
125    for ListContext<S, V, DM, IDM>
126{
127    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
128        f.debug_struct("ListContext")
129            .field("variable_name", &self.variable_name)
130            .field("descriptor_index", &self.descriptor_index)
131            .finish()
132    }
133}