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 ScalarVariableSlot<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 ScalarVariableSlot<S> {
33    fn clone(&self) -> Self {
34        *self
35    }
36}
37
38impl<S> Copy for ScalarVariableSlot<S> {}
39
40impl<S> ScalarVariableSlot<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 supports_nearby_change(&self) -> bool {
123        self.nearby_value_candidates.is_some()
124    }
125
126    pub fn supports_nearby_swap(&self) -> bool {
127        self.nearby_entity_candidates.is_some()
128    }
129
130    pub fn current_value(&self, solution: &S, entity_index: usize) -> Option<usize> {
131        (self.getter)(solution, entity_index, self.variable_index)
132    }
133
134    pub fn set_value(&self, solution: &mut S, entity_index: usize, value: Option<usize>) {
135        (self.setter)(solution, entity_index, self.variable_index, value);
136    }
137
138    pub fn values_for_entity(&self, solution: &S, entity_index: usize) -> Vec<usize> {
139        match self.value_source {
140            ValueSource::Empty => Vec::new(),
141            ValueSource::CountableRange { from, to } => (from..to).collect(),
142            ValueSource::SolutionCount {
143                count_fn,
144                provider_index,
145            } => (0..count_fn(solution, provider_index)).collect(),
146            ValueSource::EntitySlice { values_for_entity } => {
147                values_for_entity(solution, entity_index, self.variable_index).to_vec()
148            }
149        }
150    }
151
152    pub fn candidate_values_for_entity(
153        &self,
154        solution: &S,
155        entity_index: usize,
156        value_candidate_limit: Option<usize>,
157    ) -> Vec<usize> {
158        if let Some(provider) = self.candidate_values {
159            let values = provider(solution, entity_index, self.variable_index);
160            return match value_candidate_limit {
161                Some(limit) => values.iter().copied().take(limit).collect(),
162                None => values.to_vec(),
163            };
164        }
165
166        match self.value_source {
167            ValueSource::Empty => Vec::new(),
168            ValueSource::CountableRange { from, to } => {
169                let end = value_candidate_limit
170                    .map(|limit| from.saturating_add(limit).min(to))
171                    .unwrap_or(to);
172                (from..end).collect()
173            }
174            ValueSource::SolutionCount {
175                count_fn,
176                provider_index,
177            } => {
178                let count = count_fn(solution, provider_index);
179                let end = value_candidate_limit
180                    .map(|limit| limit.min(count))
181                    .unwrap_or(count);
182                (0..end).collect()
183            }
184            ValueSource::EntitySlice { values_for_entity } => {
185                let values = values_for_entity(solution, entity_index, self.variable_index);
186                match value_candidate_limit {
187                    Some(limit) => values.iter().copied().take(limit).collect(),
188                    None => values.to_vec(),
189                }
190            }
191        }
192    }
193
194    pub fn has_values_for_entity(&self, solution: &S, entity_index: usize) -> bool {
195        match self.value_source {
196            ValueSource::Empty => false,
197            ValueSource::CountableRange { from, to } => from < to,
198            ValueSource::SolutionCount {
199                count_fn,
200                provider_index,
201            } => count_fn(solution, provider_index) > 0,
202            ValueSource::EntitySlice { values_for_entity } => {
203                !values_for_entity(solution, entity_index, self.variable_index).is_empty()
204            }
205        }
206    }
207
208    pub fn value_is_legal(
209        &self,
210        solution: &S,
211        entity_index: usize,
212        candidate: Option<usize>,
213    ) -> bool {
214        let Some(value) = candidate else {
215            return self.allows_unassigned;
216        };
217        match self.value_source {
218            ValueSource::Empty => false,
219            ValueSource::CountableRange { from, to } => from <= value && value < to,
220            ValueSource::SolutionCount {
221                count_fn,
222                provider_index,
223            } => value < count_fn(solution, provider_index),
224            ValueSource::EntitySlice { values_for_entity } => {
225                values_for_entity(solution, entity_index, self.variable_index).contains(&value)
226            }
227        }
228    }
229
230    pub fn nearby_value_distance(
231        &self,
232        solution: &S,
233        entity_index: usize,
234        value: usize,
235    ) -> Option<f64> {
236        self.nearby_value_distance_meter
237            .and_then(|meter| meter(solution, entity_index, self.variable_index, value))
238    }
239
240    pub fn nearby_entity_distance(
241        &self,
242        solution: &S,
243        left_entity_index: usize,
244        right_entity_index: usize,
245    ) -> Option<f64> {
246        self.nearby_entity_distance_meter.and_then(|meter| {
247            meter(
248                solution,
249                left_entity_index,
250                right_entity_index,
251                self.variable_index,
252            )
253        })
254    }
255
256    pub fn construction_entity_order_key(&self, solution: &S, entity_index: usize) -> Option<i64> {
257        self.construction_entity_order_key
258            .and_then(|order_key| order_key(solution, entity_index, self.variable_index))
259    }
260
261    pub fn construction_value_order_key(
262        &self,
263        solution: &S,
264        entity_index: usize,
265        value: usize,
266    ) -> Option<i64> {
267        self.construction_value_order_key
268            .and_then(|order_key| order_key(solution, entity_index, self.variable_index, value))
269    }
270}
271
272impl<S> fmt::Debug for ScalarVariableSlot<S> {
273    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
274        f.debug_struct("ScalarVariableSlot")
275            .field("descriptor_index", &self.descriptor_index)
276            .field("variable_index", &self.variable_index)
277            .field("entity_type_name", &self.entity_type_name)
278            .field("variable_name", &self.variable_name)
279            .field("value_source", &self.value_source)
280            .field("allows_unassigned", &self.allows_unassigned)
281            .field("has_candidate_values", &self.candidate_values.is_some())
282            .field(
283                "has_nearby_value_candidates",
284                &self.nearby_value_candidates.is_some(),
285            )
286            .field(
287                "has_nearby_entity_candidates",
288                &self.nearby_entity_candidates.is_some(),
289            )
290            .field(
291                "has_nearby_value_distance_meter",
292                &self.nearby_value_distance_meter.is_some(),
293            )
294            .field(
295                "has_nearby_entity_distance_meter",
296                &self.nearby_entity_distance_meter.is_some(),
297            )
298            .field(
299                "has_construction_entity_order_key",
300                &self.construction_entity_order_key.is_some(),
301            )
302            .field(
303                "has_construction_value_order_key",
304                &self.construction_value_order_key.is_some(),
305            )
306            .finish()
307    }
308}