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