Skip to main content

solverforge_solver/builder/context/scalar/
group.rs

1use std::fmt;
2
3use crate::planning::{
4    ScalarAssignmentDeclaration, ScalarCandidateProvider, ScalarEdit, ScalarGroup, ScalarGroupKind,
5    ScalarGroupLimits,
6};
7
8use super::value_source::ValueSource;
9use super::variable::{ScalarGetter, ScalarSetter, ScalarVariableSlot};
10
11pub struct ScalarGroupMemberBinding<S> {
12    pub descriptor_index: usize,
13    pub variable_index: usize,
14    pub entity_type_name: &'static str,
15    pub variable_name: &'static str,
16    pub getter: ScalarGetter<S>,
17    pub setter: ScalarSetter<S>,
18    pub value_source: ValueSource<S>,
19    pub entity_count: fn(&S) -> usize,
20    pub candidate_values: Option<super::variable::ScalarCandidateValues<S>>,
21    pub allows_unassigned: bool,
22}
23
24impl<S> Clone for ScalarGroupMemberBinding<S> {
25    fn clone(&self) -> Self {
26        *self
27    }
28}
29
30impl<S> Copy for ScalarGroupMemberBinding<S> {}
31
32impl<S> ScalarGroupMemberBinding<S> {
33    pub fn from_scalar_slot(slot: ScalarVariableSlot<S>) -> Self {
34        Self {
35            descriptor_index: slot.descriptor_index,
36            variable_index: slot.variable_index,
37            entity_type_name: slot.entity_type_name,
38            variable_name: slot.variable_name,
39            getter: slot.getter,
40            setter: slot.setter,
41            value_source: slot.value_source,
42            entity_count: slot.entity_count,
43            candidate_values: slot.candidate_values,
44            allows_unassigned: slot.allows_unassigned,
45        }
46    }
47
48    pub fn current_value(&self, solution: &S, entity_index: usize) -> Option<usize> {
49        (self.getter)(solution, entity_index, self.variable_index)
50    }
51
52    pub fn value_is_legal(
53        &self,
54        solution: &S,
55        entity_index: usize,
56        candidate: Option<usize>,
57    ) -> bool {
58        let Some(value) = candidate else {
59            return self.allows_unassigned;
60        };
61        match self.value_source {
62            ValueSource::Empty => false,
63            ValueSource::CountableRange { from, to } => from <= value && value < to,
64            ValueSource::SolutionCount {
65                count_fn,
66                provider_index,
67            } => value < count_fn(solution, provider_index),
68            ValueSource::EntitySlice { values_for_entity } => {
69                values_for_entity(solution, entity_index, self.variable_index).contains(&value)
70            }
71        }
72    }
73
74    pub fn entity_count(&self, solution: &S) -> usize {
75        (self.entity_count)(solution)
76    }
77
78    pub fn candidate_values(
79        &self,
80        solution: &S,
81        entity_index: usize,
82        value_candidate_limit: Option<usize>,
83    ) -> Vec<usize> {
84        if let Some(candidate_values) = self.candidate_values {
85            let values = candidate_values(solution, entity_index, self.variable_index);
86            return match value_candidate_limit {
87                Some(limit) => values.iter().copied().take(limit).collect(),
88                None => values.to_vec(),
89            };
90        }
91        match self.value_source {
92            ValueSource::Empty => Vec::new(),
93            ValueSource::CountableRange { from, to } => {
94                let end = value_candidate_limit
95                    .map(|limit| from.saturating_add(limit).min(to))
96                    .unwrap_or(to);
97                (from..end).collect()
98            }
99            ValueSource::SolutionCount {
100                count_fn,
101                provider_index,
102            } => {
103                let count = count_fn(solution, provider_index);
104                let end = value_candidate_limit
105                    .map(|limit| limit.min(count))
106                    .unwrap_or(count);
107                (0..end).collect()
108            }
109            ValueSource::EntitySlice { values_for_entity } => {
110                let values = values_for_entity(solution, entity_index, self.variable_index);
111                match value_candidate_limit {
112                    Some(limit) => values.iter().copied().take(limit).collect(),
113                    None => values.to_vec(),
114                }
115            }
116        }
117    }
118}
119
120impl<S> fmt::Debug for ScalarGroupMemberBinding<S> {
121    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
122        f.debug_struct("ScalarGroupMemberBinding")
123            .field("descriptor_index", &self.descriptor_index)
124            .field("variable_index", &self.variable_index)
125            .field("entity_type_name", &self.entity_type_name)
126            .field("variable_name", &self.variable_name)
127            .field("value_source", &self.value_source)
128            .field("allows_unassigned", &self.allows_unassigned)
129            .finish()
130    }
131}
132
133pub struct ScalarGroupBinding<S> {
134    pub group_name: &'static str,
135    pub members: Vec<ScalarGroupMemberBinding<S>>,
136    pub kind: ScalarGroupBindingKind<S>,
137    pub limits: ScalarGroupLimits,
138}
139
140pub enum ScalarGroupBindingKind<S> {
141    Candidates {
142        candidate_provider: ScalarCandidateProvider<S>,
143    },
144    Assignment(ScalarAssignmentBinding<S>),
145}
146
147impl<S> Clone for ScalarGroupBindingKind<S> {
148    fn clone(&self) -> Self {
149        *self
150    }
151}
152
153impl<S> Copy for ScalarGroupBindingKind<S> {}
154
155pub struct ScalarAssignmentBinding<S> {
156    pub target: ScalarGroupMemberBinding<S>,
157    pub required_entity: Option<fn(&S, usize) -> bool>,
158    pub capacity_key: Option<fn(&S, usize, usize) -> Option<usize>>,
159    pub position_key: Option<fn(&S, usize) -> i64>,
160    pub sequence_key: Option<fn(&S, usize, usize) -> Option<usize>>,
161    pub entity_order: Option<fn(&S, usize) -> i64>,
162    pub value_order: Option<fn(&S, usize, usize) -> i64>,
163}
164
165impl<S> Clone for ScalarAssignmentBinding<S> {
166    fn clone(&self) -> Self {
167        *self
168    }
169}
170
171impl<S> Copy for ScalarAssignmentBinding<S> {}
172
173impl<S> ScalarAssignmentBinding<S> {
174    fn bind(
175        group_name: &'static str,
176        members: &[ScalarGroupMemberBinding<S>],
177        declaration: ScalarAssignmentDeclaration<S>,
178    ) -> Self {
179        assert_eq!(
180            members.len(),
181            1,
182            "assignment scalar group `{group_name}` must target exactly one scalar planning variable",
183        );
184        let target = members[0];
185        assert!(
186            target.allows_unassigned,
187            "assignment scalar group `{group_name}` target {}.{} must allow unassigned values",
188            target.entity_type_name, target.variable_name,
189        );
190        Self {
191            target,
192            required_entity: declaration.required_entity,
193            capacity_key: declaration.capacity_key,
194            position_key: declaration.position_key,
195            sequence_key: declaration.sequence_key,
196            entity_order: declaration.entity_order,
197            value_order: declaration.value_order,
198        }
199    }
200
201    pub fn entity_count(&self, solution: &S) -> usize {
202        self.target.entity_count(solution)
203    }
204
205    pub fn current_value(&self, solution: &S, entity_index: usize) -> Option<usize> {
206        self.target.current_value(solution, entity_index)
207    }
208
209    pub fn is_required(&self, solution: &S, entity_index: usize) -> bool {
210        self.required_entity
211            .map(|required_entity| required_entity(solution, entity_index))
212            .unwrap_or(false)
213    }
214
215    pub fn capacity_key(&self, solution: &S, entity_index: usize, value: usize) -> Option<usize> {
216        self.capacity_key
217            .and_then(|capacity_key| capacity_key(solution, entity_index, value))
218    }
219
220    pub fn position_key(&self, solution: &S, entity_index: usize) -> Option<i64> {
221        self.position_key
222            .map(|position_key| position_key(solution, entity_index))
223    }
224
225    pub fn sequence_key(&self, solution: &S, entity_index: usize, value: usize) -> Option<usize> {
226        self.sequence_key
227            .and_then(|sequence_key| sequence_key(solution, entity_index, value))
228    }
229
230    pub fn entity_order_key(&self, solution: &S, entity_index: usize) -> Option<i64> {
231        self.entity_order
232            .map(|entity_order| entity_order(solution, entity_index))
233    }
234
235    pub fn value_order_key(&self, solution: &S, entity_index: usize, value: usize) -> Option<i64> {
236        self.value_order
237            .map(|value_order| value_order(solution, entity_index, value))
238    }
239
240    pub fn candidate_values(
241        &self,
242        solution: &S,
243        entity_index: usize,
244        value_candidate_limit: Option<usize>,
245    ) -> Vec<usize> {
246        let mut values =
247            self.target
248                .candidate_values(solution, entity_index, value_candidate_limit);
249        values.sort_by_key(|value| (self.value_order_key(solution, entity_index, *value), *value));
250        values
251    }
252
253    pub fn value_is_legal(&self, solution: &S, entity_index: usize, value: Option<usize>) -> bool {
254        self.target.value_is_legal(solution, entity_index, value)
255    }
256
257    pub fn edit(&self, entity_index: usize, value: Option<usize>) -> ScalarEdit<S> {
258        ScalarEdit::from_descriptor_index(
259            self.target.descriptor_index,
260            entity_index,
261            self.target.variable_name,
262            value,
263        )
264    }
265}
266
267impl<S> ScalarGroupBinding<S> {
268    pub fn bind(group: ScalarGroup<S>, scalar_slots: &[ScalarVariableSlot<S>]) -> Self {
269        let members = group
270            .targets()
271            .iter()
272            .map(|target| {
273                let descriptor_index = target.descriptor_index();
274                let variable_name = target.variable_name();
275                let slot = scalar_slots
276                    .iter()
277                    .copied()
278                    .find(|slot| {
279                        slot.descriptor_index == descriptor_index
280                            && slot.variable_name == variable_name
281                    })
282                    .unwrap_or_else(|| {
283                        panic!(
284                            "scalar group `{}` targets unknown scalar variable `{}` on descriptor {}",
285                            group.group_name(),
286                            variable_name,
287                            descriptor_index
288                        )
289                    });
290                ScalarGroupMemberBinding::from_scalar_slot(slot)
291            })
292            .collect::<Vec<_>>();
293
294        let kind = match group.kind() {
295            ScalarGroupKind::Assignment(declaration) => ScalarGroupBindingKind::Assignment(
296                ScalarAssignmentBinding::bind(group.group_name(), &members, declaration),
297            ),
298            ScalarGroupKind::Candidates { candidate_provider } => {
299                ScalarGroupBindingKind::Candidates { candidate_provider }
300            }
301        };
302
303        Self {
304            group_name: group.group_name(),
305            members,
306            kind,
307            limits: group.limits(),
308        }
309    }
310
311    pub fn member_for_edit(&self, edit: &ScalarEdit<S>) -> Option<ScalarGroupMemberBinding<S>> {
312        self.members.iter().copied().find(|member| {
313            member.descriptor_index == edit.descriptor_index()
314                && member.variable_name == edit.variable_name()
315        })
316    }
317}
318
319impl<S> Clone for ScalarGroupBinding<S> {
320    fn clone(&self) -> Self {
321        Self {
322            group_name: self.group_name,
323            members: self.members.clone(),
324            kind: self.kind,
325            limits: self.limits,
326        }
327    }
328}
329
330impl<S> fmt::Debug for ScalarGroupBinding<S> {
331    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
332        f.debug_struct("ScalarGroupBinding")
333            .field("group_name", &self.group_name)
334            .field("members", &self.members)
335            .finish_non_exhaustive()
336    }
337}
338
339pub fn bind_scalar_groups<S>(
340    groups: Vec<ScalarGroup<S>>,
341    scalar_slots: &[ScalarVariableSlot<S>],
342) -> Vec<ScalarGroupBinding<S>> {
343    groups
344        .into_iter()
345        .map(|group| ScalarGroupBinding::bind(group, scalar_slots))
346        .collect()
347}