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 enum ValueSource<S> {
8 Empty,
9 CountableRange {
10 from: usize,
11 to: usize,
12 },
13 SolutionCount {
14 count_fn: fn(&S) -> usize,
15 },
16 EntitySlice {
17 values_for_entity: for<'a> fn(&'a S, usize) -> &'a [usize],
18 },
19}
20
21impl<S> Clone for ValueSource<S> {
22 fn clone(&self) -> Self {
23 *self
24 }
25}
26
27impl<S> Copy for ValueSource<S> {}
28
29impl<S> fmt::Debug for ValueSource<S> {
30 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
31 match self {
32 Self::Empty => write!(f, "ValueSource::Empty"),
33 Self::CountableRange { from, to } => {
34 write!(f, "ValueSource::CountableRange({from}..{to})")
35 }
36 Self::SolutionCount { .. } => write!(f, "ValueSource::SolutionCount(..)"),
37 Self::EntitySlice { .. } => write!(f, "ValueSource::EntitySlice(..)"),
38 }
39 }
40}
41
42pub struct ScalarVariableContext<S> {
43 pub descriptor_index: usize,
44 pub entity_type_name: &'static str,
45 pub entity_count: fn(&S) -> usize,
46 pub variable_name: &'static str,
47 pub getter: fn(&S, usize) -> Option<usize>,
48 pub setter: fn(&mut S, usize, Option<usize>),
49 pub value_source: ValueSource<S>,
50 pub allows_unassigned: bool,
51}
52
53impl<S> Clone for ScalarVariableContext<S> {
54 fn clone(&self) -> Self {
55 *self
56 }
57}
58
59impl<S> Copy for ScalarVariableContext<S> {}
60
61impl<S> ScalarVariableContext<S> {
62 #[allow(clippy::too_many_arguments)]
63 pub fn new(
64 descriptor_index: usize,
65 entity_type_name: &'static str,
66 entity_count: fn(&S) -> usize,
67 variable_name: &'static str,
68 getter: fn(&S, usize) -> Option<usize>,
69 setter: fn(&mut S, usize, Option<usize>),
70 value_source: ValueSource<S>,
71 allows_unassigned: bool,
72 ) -> Self {
73 Self {
74 descriptor_index,
75 entity_type_name,
76 entity_count,
77 variable_name,
78 getter,
79 setter,
80 value_source,
81 allows_unassigned,
82 }
83 }
84
85 pub fn matches_target(&self, entity_class: Option<&str>, variable_name: Option<&str>) -> bool {
86 entity_class.is_none_or(|name| name == self.entity_type_name)
87 && variable_name.is_none_or(|name| name == self.variable_name)
88 }
89}
90
91impl<S> fmt::Debug for ScalarVariableContext<S> {
92 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
93 f.debug_struct("ScalarVariableContext")
94 .field("descriptor_index", &self.descriptor_index)
95 .field("entity_type_name", &self.entity_type_name)
96 .field("variable_name", &self.variable_name)
97 .field("value_source", &self.value_source)
98 .field("allows_unassigned", &self.allows_unassigned)
99 .finish()
100 }
101}
102
103#[derive(Debug, Clone)]
104pub struct IntraDistanceAdapter<T>(pub T);
105
106impl<S, T: CrossEntityDistanceMeter<S>> ListPositionDistanceMeter<S> for IntraDistanceAdapter<T> {
107 fn distance(&self, solution: &S, entity_idx: usize, pos_a: usize, pos_b: usize) -> f64 {
108 self.0
109 .distance(solution, entity_idx, pos_a, entity_idx, pos_b)
110 }
111}
112
113pub struct ListVariableContext<S, V, DM, IDM> {
114 pub entity_type_name: &'static str,
115 pub list_len: fn(&S, usize) -> usize,
116 pub list_remove: fn(&mut S, usize, usize) -> Option<V>,
117 pub list_insert: fn(&mut S, usize, usize, V),
118 pub list_get: fn(&S, usize, usize) -> Option<V>,
119 pub list_set: fn(&mut S, usize, usize, V),
120 pub list_reverse: fn(&mut S, usize, usize, usize),
121 pub sublist_remove: fn(&mut S, usize, usize, usize) -> Vec<V>,
122 pub sublist_insert: fn(&mut S, usize, usize, Vec<V>),
123 pub ruin_remove: fn(&mut S, usize, usize) -> V,
124 pub ruin_insert: fn(&mut S, usize, usize, V),
125 pub entity_count: fn(&S) -> usize,
126 pub cross_distance_meter: DM,
127 pub intra_distance_meter: IDM,
128 pub variable_name: &'static str,
129 pub descriptor_index: usize,
130 _phantom: PhantomData<(fn() -> S, fn() -> V)>,
131}
132
133impl<S, V, DM: Clone, IDM: Clone> Clone for ListVariableContext<S, V, DM, IDM> {
134 fn clone(&self) -> Self {
135 Self {
136 entity_type_name: self.entity_type_name,
137 list_len: self.list_len,
138 list_remove: self.list_remove,
139 list_insert: self.list_insert,
140 list_get: self.list_get,
141 list_set: self.list_set,
142 list_reverse: self.list_reverse,
143 sublist_remove: self.sublist_remove,
144 sublist_insert: self.sublist_insert,
145 ruin_remove: self.ruin_remove,
146 ruin_insert: self.ruin_insert,
147 entity_count: self.entity_count,
148 cross_distance_meter: self.cross_distance_meter.clone(),
149 intra_distance_meter: self.intra_distance_meter.clone(),
150 variable_name: self.variable_name,
151 descriptor_index: self.descriptor_index,
152 _phantom: PhantomData,
153 }
154 }
155}
156
157impl<S, V, DM, IDM> ListVariableContext<S, V, DM, IDM> {
158 #[allow(clippy::too_many_arguments)]
159 pub fn new(
160 entity_type_name: &'static str,
161 list_len: fn(&S, usize) -> usize,
162 list_remove: fn(&mut S, usize, usize) -> Option<V>,
163 list_insert: fn(&mut S, usize, usize, V),
164 list_get: fn(&S, usize, usize) -> Option<V>,
165 list_set: fn(&mut S, usize, usize, V),
166 list_reverse: fn(&mut S, usize, usize, usize),
167 sublist_remove: fn(&mut S, usize, usize, usize) -> Vec<V>,
168 sublist_insert: fn(&mut S, usize, usize, Vec<V>),
169 ruin_remove: fn(&mut S, usize, usize) -> V,
170 ruin_insert: fn(&mut S, usize, usize, V),
171 entity_count: fn(&S) -> usize,
172 cross_distance_meter: DM,
173 intra_distance_meter: IDM,
174 variable_name: &'static str,
175 descriptor_index: usize,
176 ) -> Self {
177 Self {
178 entity_type_name,
179 list_len,
180 list_remove,
181 list_insert,
182 list_get,
183 list_set,
184 list_reverse,
185 sublist_remove,
186 sublist_insert,
187 ruin_remove,
188 ruin_insert,
189 entity_count,
190 cross_distance_meter,
191 intra_distance_meter,
192 variable_name,
193 descriptor_index,
194 _phantom: PhantomData,
195 }
196 }
197
198 pub fn matches_target(&self, entity_class: Option<&str>, variable_name: Option<&str>) -> bool {
199 entity_class.is_none_or(|name| name == self.entity_type_name)
200 && variable_name.is_none_or(|name| name == self.variable_name)
201 }
202}
203
204impl<S, V, DM: fmt::Debug, IDM: fmt::Debug> fmt::Debug for ListVariableContext<S, V, DM, IDM> {
205 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
206 f.debug_struct("ListVariableContext")
207 .field("entity_type_name", &self.entity_type_name)
208 .field("variable_name", &self.variable_name)
209 .field("descriptor_index", &self.descriptor_index)
210 .finish()
211 }
212}
213
214pub enum VariableContext<S, V, DM, IDM> {
215 Scalar(ScalarVariableContext<S>),
216 List(ListVariableContext<S, V, DM, IDM>),
217}
218
219impl<S, V, DM: Clone, IDM: Clone> Clone for VariableContext<S, V, DM, IDM> {
220 fn clone(&self) -> Self {
221 match self {
222 Self::Scalar(variable) => Self::Scalar(*variable),
223 Self::List(variable) => Self::List(variable.clone()),
224 }
225 }
226}
227
228impl<S, V, DM: fmt::Debug, IDM: fmt::Debug> fmt::Debug for VariableContext<S, V, DM, IDM> {
229 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
230 match self {
231 Self::Scalar(variable) => variable.fmt(f),
232 Self::List(variable) => variable.fmt(f),
233 }
234 }
235}
236
237pub struct ModelContext<S, V, DM, IDM> {
238 variables: Vec<VariableContext<S, V, DM, IDM>>,
239 _phantom: PhantomData<(fn() -> S, fn() -> V)>,
240}
241
242impl<S, V, DM, IDM> ModelContext<S, V, DM, IDM> {
243 pub fn new(variables: Vec<VariableContext<S, V, DM, IDM>>) -> Self {
244 Self {
245 variables,
246 _phantom: PhantomData,
247 }
248 }
249
250 pub fn variables(&self) -> &[VariableContext<S, V, DM, IDM>] {
251 &self.variables
252 }
253
254 pub fn is_empty(&self) -> bool {
255 self.variables.is_empty()
256 }
257
258 pub fn has_list_variables(&self) -> bool {
259 self.variables
260 .iter()
261 .any(|variable| matches!(variable, VariableContext::List(_)))
262 }
263
264 pub fn scalar_variables(&self) -> impl Iterator<Item = &ScalarVariableContext<S>> {
265 self.variables.iter().filter_map(|variable| match variable {
266 VariableContext::Scalar(ctx) => Some(ctx),
267 VariableContext::List(_) => None,
268 })
269 }
270
271 pub fn list_variables(&self) -> impl Iterator<Item = &ListVariableContext<S, V, DM, IDM>> {
272 self.variables.iter().filter_map(|variable| match variable {
273 VariableContext::List(ctx) => Some(ctx),
274 VariableContext::Scalar(_) => None,
275 })
276 }
277}
278
279impl<S, V, DM: fmt::Debug, IDM: fmt::Debug> fmt::Debug for ModelContext<S, V, DM, IDM> {
280 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
281 f.debug_struct("ModelContext")
282 .field("variables", &self.variables)
283 .finish()
284 }
285}