Skip to main content

solverforge_solver/builder/context/
list.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 struct IntraDistanceAdapter<T>(pub T);
8
9impl<S, T: CrossEntityDistanceMeter<S>> ListPositionDistanceMeter<S> for IntraDistanceAdapter<T> {
10    fn distance(&self, solution: &S, entity_idx: usize, pos_a: usize, pos_b: usize) -> f64 {
11        self.0
12            .distance(solution, entity_idx, pos_a, entity_idx, pos_b)
13    }
14}
15
16pub struct ListVariableSlot<S, V, DM, IDM> {
17    pub entity_type_name: &'static str,
18    pub element_count: fn(&S) -> usize,
19    pub assigned_elements: fn(&S) -> Vec<V>,
20    pub list_len: fn(&S, usize) -> usize,
21    pub list_remove: fn(&mut S, usize, usize) -> Option<V>,
22    pub construction_list_remove: fn(&mut S, usize, usize) -> V,
23    pub list_insert: fn(&mut S, usize, usize, V),
24    pub list_get: fn(&S, usize, usize) -> Option<V>,
25    pub list_set: fn(&mut S, usize, usize, V),
26    pub list_reverse: fn(&mut S, usize, usize, usize),
27    pub sublist_remove: fn(&mut S, usize, usize, usize) -> Vec<V>,
28    pub sublist_insert: fn(&mut S, usize, usize, Vec<V>),
29    pub ruin_remove: fn(&mut S, usize, usize) -> V,
30    pub ruin_insert: fn(&mut S, usize, usize, V),
31    pub index_to_element: fn(&S, usize) -> V,
32    pub entity_count: fn(&S) -> usize,
33    pub cross_distance_meter: DM,
34    pub intra_distance_meter: IDM,
35    pub variable_name: &'static str,
36    pub descriptor_index: usize,
37    pub route_get_fn: Option<fn(&S, usize) -> Vec<usize>>,
38    pub route_set_fn: Option<fn(&mut S, usize, Vec<usize>)>,
39    pub route_depot_fn: Option<fn(&S, usize) -> usize>,
40    pub route_distance_fn: Option<fn(&S, usize, usize, usize) -> i64>,
41    pub route_feasible_fn: Option<fn(&S, usize, &[usize]) -> bool>,
42    _phantom: PhantomData<(fn() -> S, fn() -> V)>,
43}
44
45impl<S, V, DM: Clone, IDM: Clone> Clone for ListVariableSlot<S, V, DM, IDM> {
46    fn clone(&self) -> Self {
47        Self {
48            entity_type_name: self.entity_type_name,
49            element_count: self.element_count,
50            assigned_elements: self.assigned_elements,
51            list_len: self.list_len,
52            list_remove: self.list_remove,
53            construction_list_remove: self.construction_list_remove,
54            list_insert: self.list_insert,
55            list_get: self.list_get,
56            list_set: self.list_set,
57            list_reverse: self.list_reverse,
58            sublist_remove: self.sublist_remove,
59            sublist_insert: self.sublist_insert,
60            ruin_remove: self.ruin_remove,
61            ruin_insert: self.ruin_insert,
62            index_to_element: self.index_to_element,
63            entity_count: self.entity_count,
64            cross_distance_meter: self.cross_distance_meter.clone(),
65            intra_distance_meter: self.intra_distance_meter.clone(),
66            variable_name: self.variable_name,
67            descriptor_index: self.descriptor_index,
68            route_get_fn: self.route_get_fn,
69            route_set_fn: self.route_set_fn,
70            route_depot_fn: self.route_depot_fn,
71            route_distance_fn: self.route_distance_fn,
72            route_feasible_fn: self.route_feasible_fn,
73            _phantom: PhantomData,
74        }
75    }
76}
77
78impl<S, V, DM, IDM> ListVariableSlot<S, V, DM, IDM> {
79    #[allow(clippy::too_many_arguments)]
80    pub fn new(
81        entity_type_name: &'static str,
82        element_count: fn(&S) -> usize,
83        assigned_elements: fn(&S) -> Vec<V>,
84        list_len: fn(&S, usize) -> usize,
85        list_remove: fn(&mut S, usize, usize) -> Option<V>,
86        construction_list_remove: fn(&mut S, usize, usize) -> V,
87        list_insert: fn(&mut S, usize, usize, V),
88        list_get: fn(&S, usize, usize) -> Option<V>,
89        list_set: fn(&mut S, usize, usize, V),
90        list_reverse: fn(&mut S, usize, usize, usize),
91        sublist_remove: fn(&mut S, usize, usize, usize) -> Vec<V>,
92        sublist_insert: fn(&mut S, usize, usize, Vec<V>),
93        ruin_remove: fn(&mut S, usize, usize) -> V,
94        ruin_insert: fn(&mut S, usize, usize, V),
95        index_to_element: fn(&S, usize) -> V,
96        entity_count: fn(&S) -> usize,
97        cross_distance_meter: DM,
98        intra_distance_meter: IDM,
99        variable_name: &'static str,
100        descriptor_index: usize,
101        route_get_fn: Option<fn(&S, usize) -> Vec<usize>>,
102        route_set_fn: Option<fn(&mut S, usize, Vec<usize>)>,
103        route_depot_fn: Option<fn(&S, usize) -> usize>,
104        route_distance_fn: Option<fn(&S, usize, usize, usize) -> i64>,
105        route_feasible_fn: Option<fn(&S, usize, &[usize]) -> bool>,
106    ) -> Self {
107        Self {
108            entity_type_name,
109            element_count,
110            assigned_elements,
111            list_len,
112            list_remove,
113            construction_list_remove,
114            list_insert,
115            list_get,
116            list_set,
117            list_reverse,
118            sublist_remove,
119            sublist_insert,
120            ruin_remove,
121            ruin_insert,
122            index_to_element,
123            entity_count,
124            cross_distance_meter,
125            intra_distance_meter,
126            variable_name,
127            descriptor_index,
128            route_get_fn,
129            route_set_fn,
130            route_depot_fn,
131            route_distance_fn,
132            route_feasible_fn,
133            _phantom: PhantomData,
134        }
135    }
136
137    pub fn matches_target(&self, entity_class: Option<&str>, variable_name: Option<&str>) -> bool {
138        entity_class.is_none_or(|name| name == self.entity_type_name)
139            && variable_name.is_none_or(|name| name == self.variable_name)
140    }
141
142    pub fn has_unassigned_elements(&self, solution: &S) -> bool {
143        (self.assigned_elements)(solution).len() < (self.element_count)(solution)
144    }
145
146    pub fn has_list_content(&self, solution: &S) -> bool {
147        (0..(self.entity_count)(solution))
148            .any(|entity_index| (self.list_len)(solution, entity_index) > 0)
149    }
150
151    pub fn supports_clarke_wright(&self) -> bool {
152        self.route_set_fn.is_some()
153            && self.route_depot_fn.is_some()
154            && self.route_distance_fn.is_some()
155            && self.route_feasible_fn.is_some()
156    }
157
158    pub fn supports_k_opt(&self) -> bool {
159        self.route_get_fn.is_some()
160            && self.route_set_fn.is_some()
161            && self.route_depot_fn.is_some()
162            && self.route_distance_fn.is_some()
163    }
164
165    pub fn supports_ruin(&self) -> bool {
166        true
167    }
168}
169
170impl<S, V, DM: fmt::Debug, IDM: fmt::Debug> fmt::Debug for ListVariableSlot<S, V, DM, IDM> {
171    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
172        f.debug_struct("ListVariableSlot")
173            .field("entity_type_name", &self.entity_type_name)
174            .field("variable_name", &self.variable_name)
175            .field("descriptor_index", &self.descriptor_index)
176            .finish()
177    }
178}