Skip to main content

solverforge_solver/builder/context/scalar/
variable.rs

1use std::fmt;
2
3use super::value_source::ValueSource;
4
5pub type ScalarGetter<S> = fn(&S, usize, usize) -> Option<usize>;
6pub type ScalarSetter<S> = fn(&mut S, usize, usize, Option<usize>);
7pub type ScalarCandidateValues<S> = for<'a> fn(&'a S, usize, usize) -> &'a [usize];
8pub type NearbyValueDistanceMeter<S> = fn(&S, usize, usize, usize) -> Option<f64>;
9pub type NearbyEntityDistanceMeter<S> = fn(&S, usize, usize, usize) -> Option<f64>;
10pub type ConstructionEntityOrderKey<S> = fn(&S, usize, usize) -> Option<i64>;
11pub type ConstructionValueOrderKey<S> = fn(&S, usize, usize, usize) -> Option<i64>;
12
13pub struct ScalarVariableContext<S> {
14    pub descriptor_index: usize,
15    pub variable_index: usize,
16    pub entity_type_name: &'static str,
17    pub entity_count: fn(&S) -> usize,
18    pub variable_name: &'static str,
19    pub getter: ScalarGetter<S>,
20    pub setter: ScalarSetter<S>,
21    pub value_source: ValueSource<S>,
22    pub allows_unassigned: bool,
23    pub candidate_values: Option<ScalarCandidateValues<S>>,
24    pub nearby_value_candidates: Option<ScalarCandidateValues<S>>,
25    pub nearby_entity_candidates: Option<ScalarCandidateValues<S>>,
26    pub nearby_value_distance_meter: Option<NearbyValueDistanceMeter<S>>,
27    pub nearby_entity_distance_meter: Option<NearbyEntityDistanceMeter<S>>,
28    pub construction_entity_order_key: Option<ConstructionEntityOrderKey<S>>,
29    pub construction_value_order_key: Option<ConstructionValueOrderKey<S>>,
30}
31
32impl<S> Clone for ScalarVariableContext<S> {
33    fn clone(&self) -> Self {
34        *self
35    }
36}
37
38impl<S> Copy for ScalarVariableContext<S> {}
39
40impl<S> ScalarVariableContext<S> {
41    #[allow(clippy::too_many_arguments)]
42    pub fn new(
43        descriptor_index: usize,
44        variable_index: usize,
45        entity_type_name: &'static str,
46        entity_count: fn(&S) -> usize,
47        variable_name: &'static str,
48        getter: ScalarGetter<S>,
49        setter: ScalarSetter<S>,
50        value_source: ValueSource<S>,
51        allows_unassigned: bool,
52    ) -> Self {
53        Self {
54            descriptor_index,
55            variable_index,
56            entity_type_name,
57            entity_count,
58            variable_name,
59            getter,
60            setter,
61            value_source,
62            allows_unassigned,
63            candidate_values: None,
64            nearby_value_candidates: None,
65            nearby_entity_candidates: None,
66            nearby_value_distance_meter: None,
67            nearby_entity_distance_meter: None,
68            construction_entity_order_key: None,
69            construction_value_order_key: None,
70        }
71    }
72
73    pub fn with_nearby_value_distance_meter(mut self, meter: NearbyValueDistanceMeter<S>) -> Self {
74        self.nearby_value_distance_meter = Some(meter);
75        self
76    }
77
78    pub fn with_candidate_values(mut self, provider: ScalarCandidateValues<S>) -> Self {
79        self.candidate_values = Some(provider);
80        self
81    }
82
83    pub fn with_nearby_value_candidates(mut self, provider: ScalarCandidateValues<S>) -> Self {
84        self.nearby_value_candidates = Some(provider);
85        self
86    }
87
88    pub fn with_nearby_entity_candidates(mut self, provider: ScalarCandidateValues<S>) -> Self {
89        self.nearby_entity_candidates = Some(provider);
90        self
91    }
92
93    pub fn with_nearby_entity_distance_meter(
94        mut self,
95        meter: NearbyEntityDistanceMeter<S>,
96    ) -> Self {
97        self.nearby_entity_distance_meter = Some(meter);
98        self
99    }
100
101    pub fn with_construction_entity_order_key(
102        mut self,
103        order_key: ConstructionEntityOrderKey<S>,
104    ) -> Self {
105        self.construction_entity_order_key = Some(order_key);
106        self
107    }
108
109    pub fn with_construction_value_order_key(
110        mut self,
111        order_key: ConstructionValueOrderKey<S>,
112    ) -> Self {
113        self.construction_value_order_key = Some(order_key);
114        self
115    }
116
117    pub fn matches_target(&self, entity_class: Option<&str>, variable_name: Option<&str>) -> bool {
118        entity_class.is_none_or(|name| name == self.entity_type_name)
119            && variable_name.is_none_or(|name| name == self.variable_name)
120    }
121
122    pub fn current_value(&self, solution: &S, entity_index: usize) -> Option<usize> {
123        (self.getter)(solution, entity_index, self.variable_index)
124    }
125
126    pub fn set_value(&self, solution: &mut S, entity_index: usize, value: Option<usize>) {
127        (self.setter)(solution, entity_index, self.variable_index, value);
128    }
129
130    pub fn values_for_entity(&self, solution: &S, entity_index: usize) -> Vec<usize> {
131        match self.value_source {
132            ValueSource::Empty => Vec::new(),
133            ValueSource::CountableRange { from, to } => (from..to).collect(),
134            ValueSource::SolutionCount {
135                count_fn,
136                provider_index,
137            } => (0..count_fn(solution, provider_index)).collect(),
138            ValueSource::EntitySlice { values_for_entity } => {
139                values_for_entity(solution, entity_index, self.variable_index).to_vec()
140            }
141        }
142    }
143
144    pub fn candidate_values_for_entity(
145        &self,
146        solution: &S,
147        entity_index: usize,
148        value_candidate_limit: Option<usize>,
149    ) -> Vec<usize> {
150        if let Some(provider) = self.candidate_values {
151            let values = provider(solution, entity_index, self.variable_index);
152            return match value_candidate_limit {
153                Some(limit) => values.iter().copied().take(limit).collect(),
154                None => values.to_vec(),
155            };
156        }
157
158        match self.value_source {
159            ValueSource::Empty => Vec::new(),
160            ValueSource::CountableRange { from, to } => {
161                let end = value_candidate_limit
162                    .map(|limit| from.saturating_add(limit).min(to))
163                    .unwrap_or(to);
164                (from..end).collect()
165            }
166            ValueSource::SolutionCount {
167                count_fn,
168                provider_index,
169            } => {
170                let count = count_fn(solution, provider_index);
171                let end = value_candidate_limit
172                    .map(|limit| limit.min(count))
173                    .unwrap_or(count);
174                (0..end).collect()
175            }
176            ValueSource::EntitySlice { values_for_entity } => {
177                let values = values_for_entity(solution, entity_index, self.variable_index);
178                match value_candidate_limit {
179                    Some(limit) => values.iter().copied().take(limit).collect(),
180                    None => values.to_vec(),
181                }
182            }
183        }
184    }
185
186    pub fn has_values_for_entity(&self, solution: &S, entity_index: usize) -> bool {
187        match self.value_source {
188            ValueSource::Empty => false,
189            ValueSource::CountableRange { from, to } => from < to,
190            ValueSource::SolutionCount {
191                count_fn,
192                provider_index,
193            } => count_fn(solution, provider_index) > 0,
194            ValueSource::EntitySlice { values_for_entity } => {
195                !values_for_entity(solution, entity_index, self.variable_index).is_empty()
196            }
197        }
198    }
199
200    pub fn value_is_legal(
201        &self,
202        solution: &S,
203        entity_index: usize,
204        candidate: Option<usize>,
205    ) -> bool {
206        let Some(value) = candidate else {
207            return self.allows_unassigned;
208        };
209        match self.value_source {
210            ValueSource::Empty => false,
211            ValueSource::CountableRange { from, to } => from <= value && value < to,
212            ValueSource::SolutionCount {
213                count_fn,
214                provider_index,
215            } => value < count_fn(solution, provider_index),
216            ValueSource::EntitySlice { values_for_entity } => {
217                values_for_entity(solution, entity_index, self.variable_index).contains(&value)
218            }
219        }
220    }
221
222    pub fn nearby_value_distance(
223        &self,
224        solution: &S,
225        entity_index: usize,
226        value: usize,
227    ) -> Option<f64> {
228        self.nearby_value_distance_meter
229            .and_then(|meter| meter(solution, entity_index, self.variable_index, value))
230    }
231
232    pub fn nearby_entity_distance(
233        &self,
234        solution: &S,
235        left_entity_index: usize,
236        right_entity_index: usize,
237    ) -> Option<f64> {
238        self.nearby_entity_distance_meter.and_then(|meter| {
239            meter(
240                solution,
241                left_entity_index,
242                right_entity_index,
243                self.variable_index,
244            )
245        })
246    }
247
248    pub fn construction_entity_order_key(&self, solution: &S, entity_index: usize) -> Option<i64> {
249        self.construction_entity_order_key
250            .and_then(|order_key| order_key(solution, entity_index, self.variable_index))
251    }
252
253    pub fn construction_value_order_key(
254        &self,
255        solution: &S,
256        entity_index: usize,
257        value: usize,
258    ) -> Option<i64> {
259        self.construction_value_order_key
260            .and_then(|order_key| order_key(solution, entity_index, self.variable_index, value))
261    }
262}
263
264impl<S> fmt::Debug for ScalarVariableContext<S> {
265    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
266        f.debug_struct("ScalarVariableContext")
267            .field("descriptor_index", &self.descriptor_index)
268            .field("variable_index", &self.variable_index)
269            .field("entity_type_name", &self.entity_type_name)
270            .field("variable_name", &self.variable_name)
271            .field("value_source", &self.value_source)
272            .field("allows_unassigned", &self.allows_unassigned)
273            .field("has_candidate_values", &self.candidate_values.is_some())
274            .field(
275                "has_nearby_value_candidates",
276                &self.nearby_value_candidates.is_some(),
277            )
278            .field(
279                "has_nearby_entity_candidates",
280                &self.nearby_entity_candidates.is_some(),
281            )
282            .field(
283                "has_nearby_value_distance_meter",
284                &self.nearby_value_distance_meter.is_some(),
285            )
286            .field(
287                "has_nearby_entity_distance_meter",
288                &self.nearby_entity_distance_meter.is_some(),
289            )
290            .field(
291                "has_construction_entity_order_key",
292                &self.construction_entity_order_key.is_some(),
293            )
294            .field(
295                "has_construction_value_order_key",
296                &self.construction_value_order_key.is_some(),
297            )
298            .finish()
299    }
300}