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