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
9pub fn usize_element_source_key<S>(_solution: &S, element: &usize) -> usize {
13 *element
14}
15
16impl<S, T: CrossEntityDistanceMeter<S>> ListPositionDistanceMeter<S> for IntraDistanceAdapter<T> {
17 fn distance(&self, solution: &S, entity_idx: usize, pos_a: usize, pos_b: usize) -> f64 {
18 self.0
19 .distance(solution, entity_idx, pos_a, entity_idx, pos_b)
20 }
21}
22
23pub struct ListVariableSlot<S, V, DM, IDM> {
24 pub entity_type_name: &'static str,
25 pub element_count: fn(&S) -> usize,
26 pub assigned_elements: fn(&S) -> Vec<V>,
27 pub list_len: fn(&S, usize) -> usize,
28 pub list_remove: fn(&mut S, usize, usize) -> Option<V>,
29 pub construction_list_remove: fn(&mut S, usize, usize) -> V,
30 pub list_insert: fn(&mut S, usize, usize, V),
31 pub list_get: fn(&S, usize, usize) -> Option<V>,
32 pub list_set: fn(&mut S, usize, usize, V),
33 pub list_reverse: fn(&mut S, usize, usize, usize),
34 pub sublist_remove: fn(&mut S, usize, usize, usize) -> Vec<V>,
35 pub sublist_insert: fn(&mut S, usize, usize, Vec<V>),
36 pub ruin_remove: fn(&mut S, usize, usize) -> V,
37 pub ruin_insert: fn(&mut S, usize, usize, V),
38 pub index_to_element: fn(&S, usize) -> V,
39 pub element_source_key: fn(&S, &V) -> usize,
43 pub entity_count: fn(&S) -> usize,
44 pub cross_distance_meter: DM,
45 pub intra_distance_meter: IDM,
46 pub variable_name: &'static str,
47 pub descriptor_index: usize,
48 pub route_get_fn: Option<fn(&S, usize) -> Vec<usize>>,
49 pub route_set_fn: Option<fn(&mut S, usize, Vec<usize>)>,
50 pub route_depot_fn: Option<fn(&S, usize) -> usize>,
51 pub route_distance_fn: Option<fn(&S, usize, usize, usize) -> i64>,
52 pub route_feasible_fn: Option<fn(&S, usize, &[usize]) -> bool>,
53 pub savings_depot_fn: Option<fn(&S, usize) -> usize>,
54 pub savings_metric_class_fn: Option<fn(&S, usize) -> usize>,
55 pub savings_distance_fn: Option<fn(&S, usize, usize, usize) -> i64>,
56 pub savings_feasible_fn: Option<fn(&S, usize, &[usize]) -> bool>,
57 pub element_owner_fn: Option<fn(&S, &V) -> Option<usize>>,
58 pub construction_element_order_key: Option<fn(&S, V) -> i64>,
59 pub precedence_duration_fn: Option<fn(&S, V) -> usize>,
60 pub precedence_successors_fn: Option<fn(&S, V, &mut Vec<V>)>,
61 _phantom: PhantomData<(fn() -> S, fn() -> V)>,
62}
63
64impl<S, V, DM: Clone, IDM: Clone> Clone for ListVariableSlot<S, V, DM, IDM> {
65 fn clone(&self) -> Self {
66 Self {
67 entity_type_name: self.entity_type_name,
68 element_count: self.element_count,
69 assigned_elements: self.assigned_elements,
70 list_len: self.list_len,
71 list_remove: self.list_remove,
72 construction_list_remove: self.construction_list_remove,
73 list_insert: self.list_insert,
74 list_get: self.list_get,
75 list_set: self.list_set,
76 list_reverse: self.list_reverse,
77 sublist_remove: self.sublist_remove,
78 sublist_insert: self.sublist_insert,
79 ruin_remove: self.ruin_remove,
80 ruin_insert: self.ruin_insert,
81 index_to_element: self.index_to_element,
82 element_source_key: self.element_source_key,
83 entity_count: self.entity_count,
84 cross_distance_meter: self.cross_distance_meter.clone(),
85 intra_distance_meter: self.intra_distance_meter.clone(),
86 variable_name: self.variable_name,
87 descriptor_index: self.descriptor_index,
88 route_get_fn: self.route_get_fn,
89 route_set_fn: self.route_set_fn,
90 route_depot_fn: self.route_depot_fn,
91 route_distance_fn: self.route_distance_fn,
92 route_feasible_fn: self.route_feasible_fn,
93 savings_depot_fn: self.savings_depot_fn,
94 savings_metric_class_fn: self.savings_metric_class_fn,
95 savings_distance_fn: self.savings_distance_fn,
96 savings_feasible_fn: self.savings_feasible_fn,
97 element_owner_fn: self.element_owner_fn,
98 construction_element_order_key: self.construction_element_order_key,
99 precedence_duration_fn: self.precedence_duration_fn,
100 precedence_successors_fn: self.precedence_successors_fn,
101 _phantom: PhantomData,
102 }
103 }
104}
105
106impl<S, V, DM, IDM> ListVariableSlot<S, V, DM, IDM> {
107 #[allow(clippy::too_many_arguments)]
108 pub fn new(
109 entity_type_name: &'static str,
110 element_count: fn(&S) -> usize,
111 assigned_elements: fn(&S) -> Vec<V>,
112 list_len: fn(&S, usize) -> usize,
113 list_remove: fn(&mut S, usize, usize) -> Option<V>,
114 construction_list_remove: fn(&mut S, usize, usize) -> V,
115 list_insert: fn(&mut S, usize, usize, V),
116 list_get: fn(&S, usize, usize) -> Option<V>,
117 list_set: fn(&mut S, usize, usize, V),
118 list_reverse: fn(&mut S, usize, usize, usize),
119 sublist_remove: fn(&mut S, usize, usize, usize) -> Vec<V>,
120 sublist_insert: fn(&mut S, usize, usize, Vec<V>),
121 ruin_remove: fn(&mut S, usize, usize) -> V,
122 ruin_insert: fn(&mut S, usize, usize, V),
123 index_to_element: fn(&S, usize) -> V,
124 element_source_key: fn(&S, &V) -> usize,
125 entity_count: fn(&S) -> usize,
126 cross_distance_meter: DM,
127 intra_distance_meter: IDM,
128 variable_name: &'static str,
129 descriptor_index: usize,
130 route_get_fn: Option<fn(&S, usize) -> Vec<usize>>,
131 route_set_fn: Option<fn(&mut S, usize, Vec<usize>)>,
132 route_depot_fn: Option<fn(&S, usize) -> usize>,
133 route_distance_fn: Option<fn(&S, usize, usize, usize) -> i64>,
134 route_feasible_fn: Option<fn(&S, usize, &[usize]) -> bool>,
135 savings_depot_fn: Option<fn(&S, usize) -> usize>,
136 savings_metric_class_fn: Option<fn(&S, usize) -> usize>,
137 savings_distance_fn: Option<fn(&S, usize, usize, usize) -> i64>,
138 savings_feasible_fn: Option<fn(&S, usize, &[usize]) -> bool>,
139 ) -> Self {
140 Self {
141 entity_type_name,
142 element_count,
143 assigned_elements,
144 list_len,
145 list_remove,
146 construction_list_remove,
147 list_insert,
148 list_get,
149 list_set,
150 list_reverse,
151 sublist_remove,
152 sublist_insert,
153 ruin_remove,
154 ruin_insert,
155 index_to_element,
156 element_source_key,
157 entity_count,
158 cross_distance_meter,
159 intra_distance_meter,
160 variable_name,
161 descriptor_index,
162 route_get_fn,
163 route_set_fn,
164 route_depot_fn,
165 route_distance_fn,
166 route_feasible_fn,
167 savings_depot_fn,
168 savings_metric_class_fn,
169 savings_distance_fn,
170 savings_feasible_fn,
171 element_owner_fn: None,
172 construction_element_order_key: None,
173 precedence_duration_fn: None,
174 precedence_successors_fn: None,
175 _phantom: PhantomData,
176 }
177 }
178
179 pub fn with_element_owner_fn(
180 mut self,
181 element_owner_fn: Option<fn(&S, &V) -> Option<usize>>,
182 ) -> Self {
183 self.element_owner_fn = element_owner_fn;
184 self
185 }
186
187 pub fn with_construction_element_order_key(
188 mut self,
189 construction_element_order_key: Option<fn(&S, V) -> i64>,
190 ) -> Self {
191 self.construction_element_order_key = construction_element_order_key;
192 self
193 }
194
195 pub fn with_precedence_hooks(
196 mut self,
197 duration_fn: Option<fn(&S, V) -> usize>,
198 successors_fn: Option<fn(&S, V, &mut Vec<V>)>,
199 ) -> Self {
200 self.precedence_duration_fn = duration_fn;
201 self.precedence_successors_fn = successors_fn;
202 self
203 }
204
205 pub fn matches_target(&self, entity_class: Option<&str>, variable_name: Option<&str>) -> bool {
206 entity_class.is_none_or(|name| name == self.entity_type_name)
207 && variable_name.is_none_or(|name| name == self.variable_name)
208 }
209
210 pub fn has_unassigned_elements(&self, solution: &S) -> bool {
211 (self.assigned_elements)(solution).len() < (self.element_count)(solution)
212 }
213
214 pub fn has_list_content(&self, solution: &S) -> bool {
215 (0..(self.entity_count)(solution))
216 .any(|entity_index| (self.list_len)(solution, entity_index) > 0)
217 }
218
219 pub fn supports_clarke_wright(&self) -> bool {
220 self.route_set_fn.is_some()
221 && self.savings_depot_fn.is_some()
222 && self.savings_distance_fn.is_some()
223 && self.savings_feasible_fn.is_some()
224 }
225
226 pub fn supports_k_opt(&self) -> bool {
227 self.route_get_fn.is_some()
228 && self.route_set_fn.is_some()
229 && self.route_depot_fn.is_some()
230 && self.route_distance_fn.is_some()
231 }
232
233 pub fn supports_ruin(&self) -> bool {
234 true
235 }
236
237 pub fn supports_precedence_moves(&self) -> bool {
238 self.precedence_duration_fn.is_some() && self.precedence_successors_fn.is_some()
239 }
240}
241
242impl<S, V, DM: fmt::Debug, IDM: fmt::Debug> fmt::Debug for ListVariableSlot<S, V, DM, IDM> {
243 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
244 f.debug_struct("ListVariableSlot")
245 .field("entity_type_name", &self.entity_type_name)
246 .field("variable_name", &self.variable_name)
247 .field("descriptor_index", &self.descriptor_index)
248 .finish()
249 }
250}