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}