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