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 list variable solvers.
25///
26/// Carries all domain callbacks and distance meters needed to construct
27/// list move selectors without requiring `dyn` or closures.
28pub struct ListContext<S, V, DM, IDM> {
29    pub list_len: fn(&S, usize) -> usize,
30    // Removes element at `pos` from entity `i`, returning it (returns `None` if out of bounds).
31    pub list_remove: fn(&mut S, usize, usize) -> Option<V>,
32    // Inserts `val` at `pos` in entity `i`.
33    pub list_insert: fn(&mut S, usize, usize, V),
34    pub list_get: fn(&S, usize, usize) -> Option<V>,
35    // Replaces element at `pos` in entity `i`.
36    pub list_set: fn(&mut S, usize, usize, V),
37    // Reverses the segment `[start, end)` in entity `i`.
38    pub list_reverse: fn(&mut S, usize, usize, usize),
39    // Removes segment `[start, end)` from entity `i`.
40    pub sublist_remove: fn(&mut S, usize, usize, usize) -> Vec<V>,
41    // Inserts `items` at `pos` in entity `i`.
42    pub sublist_insert: fn(&mut S, usize, usize, Vec<V>),
43    // Removes element at `pos` from entity `i` for ruin moves (panics if out of bounds).
44    pub ruin_remove: fn(&mut S, usize, usize) -> V,
45    // Inserts `val` at `pos` in entity `i` for ruin reinsertion.
46    pub ruin_insert: fn(&mut S, usize, usize, V),
47    pub entity_count: fn(&S) -> usize,
48    // Cross-entity (inter-route) distance meter.
49    pub cross_distance_meter: DM,
50    // Intra-entity (intra-route) distance meter.
51    pub intra_distance_meter: IDM,
52    // List variable field name.
53    pub variable_name: &'static str,
54    // Descriptor index for the list owner entity collection.
55    pub descriptor_index: usize,
56    _phantom: PhantomData<(fn() -> S, fn() -> V)>,
57}
58
59impl<S, V, DM, IDM> ListContext<S, V, DM, IDM> {
60    #[allow(clippy::too_many_arguments)]
61    pub fn new(
62        list_len: fn(&S, usize) -> usize,
63        list_remove: fn(&mut S, usize, usize) -> Option<V>,
64        list_insert: fn(&mut S, usize, usize, V),
65        list_get: fn(&S, usize, usize) -> Option<V>,
66        list_set: fn(&mut S, usize, usize, V),
67        list_reverse: fn(&mut S, usize, usize, usize),
68        sublist_remove: fn(&mut S, usize, usize, usize) -> Vec<V>,
69        sublist_insert: fn(&mut S, usize, usize, Vec<V>),
70        ruin_remove: fn(&mut S, usize, usize) -> V,
71        ruin_insert: fn(&mut S, usize, usize, V),
72        entity_count: fn(&S) -> usize,
73        cross_distance_meter: DM,
74        intra_distance_meter: IDM,
75        variable_name: &'static str,
76        descriptor_index: usize,
77    ) -> Self {
78        Self {
79            list_len,
80            list_remove,
81            list_insert,
82            list_get,
83            list_set,
84            list_reverse,
85            sublist_remove,
86            sublist_insert,
87            ruin_remove,
88            ruin_insert,
89            entity_count,
90            cross_distance_meter,
91            intra_distance_meter,
92            variable_name,
93            descriptor_index,
94            _phantom: PhantomData,
95        }
96    }
97}
98
99impl<S, V, DM: std::fmt::Debug, IDM: std::fmt::Debug> std::fmt::Debug
100    for ListContext<S, V, DM, IDM>
101{
102    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
103        f.debug_struct("ListContext")
104            .field("variable_name", &self.variable_name)
105            .field("descriptor_index", &self.descriptor_index)
106            .finish()
107    }
108}