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 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}