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