Skip to main content

solverforge_solver/builder/
context.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 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 element_count: fn(&S) -> usize,
116    pub assigned_elements: fn(&S) -> Vec<V>,
117    pub list_len: fn(&S, usize) -> usize,
118    pub list_remove: fn(&mut S, usize, usize) -> Option<V>,
119    pub construction_list_remove: fn(&mut S, usize, usize) -> V,
120    pub list_insert: fn(&mut S, usize, usize, V),
121    pub list_get: fn(&S, usize, usize) -> Option<V>,
122    pub list_set: fn(&mut S, usize, usize, V),
123    pub list_reverse: fn(&mut S, usize, usize, usize),
124    pub sublist_remove: fn(&mut S, usize, usize, usize) -> Vec<V>,
125    pub sublist_insert: fn(&mut S, usize, usize, Vec<V>),
126    pub ruin_remove: fn(&mut S, usize, usize) -> V,
127    pub ruin_insert: fn(&mut S, usize, usize, V),
128    pub index_to_element: fn(&S, usize) -> V,
129    pub entity_count: fn(&S) -> usize,
130    pub cross_distance_meter: DM,
131    pub intra_distance_meter: IDM,
132    pub variable_name: &'static str,
133    pub descriptor_index: usize,
134    pub merge_feasible_fn: Option<fn(&S, &[usize]) -> bool>,
135    pub cw_depot_fn: Option<fn(&S) -> usize>,
136    pub cw_distance_fn: Option<fn(&S, usize, usize) -> i64>,
137    pub cw_element_load_fn: Option<fn(&S, usize) -> i64>,
138    pub cw_capacity_fn: Option<fn(&S) -> i64>,
139    pub cw_assign_route_fn: Option<fn(&mut S, usize, Vec<V>)>,
140    pub k_opt_get_route: Option<fn(&S, usize) -> Vec<usize>>,
141    pub k_opt_set_route: Option<fn(&mut S, usize, Vec<usize>)>,
142    pub k_opt_depot_fn: Option<fn(&S, usize) -> usize>,
143    pub k_opt_distance_fn: Option<fn(&S, usize, usize) -> i64>,
144    pub k_opt_feasible_fn: Option<fn(&S, usize, &[usize]) -> bool>,
145    _phantom: PhantomData<(fn() -> S, fn() -> V)>,
146}
147
148impl<S, V, DM: Clone, IDM: Clone> Clone for ListVariableContext<S, V, DM, IDM> {
149    fn clone(&self) -> Self {
150        Self {
151            entity_type_name: self.entity_type_name,
152            element_count: self.element_count,
153            assigned_elements: self.assigned_elements,
154            list_len: self.list_len,
155            list_remove: self.list_remove,
156            construction_list_remove: self.construction_list_remove,
157            list_insert: self.list_insert,
158            list_get: self.list_get,
159            list_set: self.list_set,
160            list_reverse: self.list_reverse,
161            sublist_remove: self.sublist_remove,
162            sublist_insert: self.sublist_insert,
163            ruin_remove: self.ruin_remove,
164            ruin_insert: self.ruin_insert,
165            index_to_element: self.index_to_element,
166            entity_count: self.entity_count,
167            cross_distance_meter: self.cross_distance_meter.clone(),
168            intra_distance_meter: self.intra_distance_meter.clone(),
169            variable_name: self.variable_name,
170            descriptor_index: self.descriptor_index,
171            merge_feasible_fn: self.merge_feasible_fn,
172            cw_depot_fn: self.cw_depot_fn,
173            cw_distance_fn: self.cw_distance_fn,
174            cw_element_load_fn: self.cw_element_load_fn,
175            cw_capacity_fn: self.cw_capacity_fn,
176            cw_assign_route_fn: self.cw_assign_route_fn,
177            k_opt_get_route: self.k_opt_get_route,
178            k_opt_set_route: self.k_opt_set_route,
179            k_opt_depot_fn: self.k_opt_depot_fn,
180            k_opt_distance_fn: self.k_opt_distance_fn,
181            k_opt_feasible_fn: self.k_opt_feasible_fn,
182            _phantom: PhantomData,
183        }
184    }
185}
186
187impl<S, V, DM, IDM> ListVariableContext<S, V, DM, IDM> {
188    #[allow(clippy::too_many_arguments)]
189    pub fn new(
190        entity_type_name: &'static str,
191        element_count: fn(&S) -> usize,
192        assigned_elements: fn(&S) -> Vec<V>,
193        list_len: fn(&S, usize) -> usize,
194        list_remove: fn(&mut S, usize, usize) -> Option<V>,
195        construction_list_remove: fn(&mut S, usize, usize) -> V,
196        list_insert: fn(&mut S, usize, usize, V),
197        list_get: fn(&S, usize, usize) -> Option<V>,
198        list_set: fn(&mut S, usize, usize, V),
199        list_reverse: fn(&mut S, usize, usize, usize),
200        sublist_remove: fn(&mut S, usize, usize, usize) -> Vec<V>,
201        sublist_insert: fn(&mut S, usize, usize, Vec<V>),
202        ruin_remove: fn(&mut S, usize, usize) -> V,
203        ruin_insert: fn(&mut S, usize, usize, V),
204        index_to_element: fn(&S, usize) -> V,
205        entity_count: fn(&S) -> usize,
206        cross_distance_meter: DM,
207        intra_distance_meter: IDM,
208        variable_name: &'static str,
209        descriptor_index: usize,
210        merge_feasible_fn: Option<fn(&S, &[usize]) -> bool>,
211        cw_depot_fn: Option<fn(&S) -> usize>,
212        cw_distance_fn: Option<fn(&S, usize, usize) -> i64>,
213        cw_element_load_fn: Option<fn(&S, usize) -> i64>,
214        cw_capacity_fn: Option<fn(&S) -> i64>,
215        cw_assign_route_fn: Option<fn(&mut S, usize, Vec<V>)>,
216        k_opt_get_route: Option<fn(&S, usize) -> Vec<usize>>,
217        k_opt_set_route: Option<fn(&mut S, usize, Vec<usize>)>,
218        k_opt_depot_fn: Option<fn(&S, usize) -> usize>,
219        k_opt_distance_fn: Option<fn(&S, usize, usize) -> i64>,
220        k_opt_feasible_fn: Option<fn(&S, usize, &[usize]) -> bool>,
221    ) -> Self {
222        Self {
223            entity_type_name,
224            element_count,
225            assigned_elements,
226            list_len,
227            list_remove,
228            construction_list_remove,
229            list_insert,
230            list_get,
231            list_set,
232            list_reverse,
233            sublist_remove,
234            sublist_insert,
235            ruin_remove,
236            ruin_insert,
237            index_to_element,
238            entity_count,
239            cross_distance_meter,
240            intra_distance_meter,
241            variable_name,
242            descriptor_index,
243            merge_feasible_fn,
244            cw_depot_fn,
245            cw_distance_fn,
246            cw_element_load_fn,
247            cw_capacity_fn,
248            cw_assign_route_fn,
249            k_opt_get_route,
250            k_opt_set_route,
251            k_opt_depot_fn,
252            k_opt_distance_fn,
253            k_opt_feasible_fn,
254            _phantom: PhantomData,
255        }
256    }
257
258    pub fn matches_target(&self, entity_class: Option<&str>, variable_name: Option<&str>) -> bool {
259        entity_class.is_none_or(|name| name == self.entity_type_name)
260            && variable_name.is_none_or(|name| name == self.variable_name)
261    }
262}
263
264impl<S, V, DM: fmt::Debug, IDM: fmt::Debug> fmt::Debug for ListVariableContext<S, V, DM, IDM> {
265    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
266        f.debug_struct("ListVariableContext")
267            .field("entity_type_name", &self.entity_type_name)
268            .field("variable_name", &self.variable_name)
269            .field("descriptor_index", &self.descriptor_index)
270            .finish()
271    }
272}
273
274pub enum VariableContext<S, V, DM, IDM> {
275    Scalar(ScalarVariableContext<S>),
276    List(ListVariableContext<S, V, DM, IDM>),
277}
278
279impl<S, V, DM: Clone, IDM: Clone> Clone for VariableContext<S, V, DM, IDM> {
280    fn clone(&self) -> Self {
281        match self {
282            Self::Scalar(variable) => Self::Scalar(*variable),
283            Self::List(variable) => Self::List(variable.clone()),
284        }
285    }
286}
287
288impl<S, V, DM: fmt::Debug, IDM: fmt::Debug> fmt::Debug for VariableContext<S, V, DM, IDM> {
289    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
290        match self {
291            Self::Scalar(variable) => variable.fmt(f),
292            Self::List(variable) => variable.fmt(f),
293        }
294    }
295}
296
297pub struct ModelContext<S, V, DM, IDM> {
298    variables: Vec<VariableContext<S, V, DM, IDM>>,
299    _phantom: PhantomData<(fn() -> S, fn() -> V)>,
300}
301
302impl<S, V, DM: Clone, IDM: Clone> Clone for ModelContext<S, V, DM, IDM> {
303    fn clone(&self) -> Self {
304        Self {
305            variables: self.variables.clone(),
306            _phantom: PhantomData,
307        }
308    }
309}
310
311impl<S, V, DM, IDM> ModelContext<S, V, DM, IDM> {
312    pub fn new(variables: Vec<VariableContext<S, V, DM, IDM>>) -> Self {
313        Self {
314            variables,
315            _phantom: PhantomData,
316        }
317    }
318
319    pub fn variables(&self) -> &[VariableContext<S, V, DM, IDM>] {
320        &self.variables
321    }
322
323    pub fn is_empty(&self) -> bool {
324        self.variables.is_empty()
325    }
326
327    pub fn has_list_variables(&self) -> bool {
328        self.variables
329            .iter()
330            .any(|variable| matches!(variable, VariableContext::List(_)))
331    }
332
333    pub fn scalar_variables(&self) -> impl Iterator<Item = &ScalarVariableContext<S>> {
334        self.variables.iter().filter_map(|variable| match variable {
335            VariableContext::Scalar(ctx) => Some(ctx),
336            VariableContext::List(_) => None,
337        })
338    }
339
340    pub fn list_variables(&self) -> impl Iterator<Item = &ListVariableContext<S, V, DM, IDM>> {
341        self.variables.iter().filter_map(|variable| match variable {
342            VariableContext::List(ctx) => Some(ctx),
343            VariableContext::Scalar(_) => None,
344        })
345    }
346}
347
348impl<S, V, DM: fmt::Debug, IDM: fmt::Debug> fmt::Debug for ModelContext<S, V, DM, IDM> {
349    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
350        f.debug_struct("ModelContext")
351            .field("variables", &self.variables)
352            .finish()
353    }
354}