Skip to main content

pumpkin_core/engine/variables/
domain_id.rs

1use enumset::EnumSet;
2use pumpkin_checking::CheckerVariable;
3
4use super::TransformableVariable;
5use crate::containers::StorageKey;
6use crate::engine::Assignments;
7use crate::engine::notifications::DomainEvent;
8use crate::engine::notifications::OpaqueDomainEvent;
9use crate::engine::notifications::Watchers;
10use crate::engine::variables::AffineView;
11use crate::engine::variables::IntegerVariable;
12use crate::predicates::Predicate;
13use crate::predicates::PredicateConstructor;
14use crate::predicates::PredicateType;
15use crate::propagation::EventDispatcher;
16use crate::propagation::EventTarget;
17use crate::propagation::LocalId;
18use crate::pumpkin_assert_simple;
19
20/// A structure which represents the most basic [`IntegerVariable`]; it is simply the id which links
21/// to a domain (hence the name).
22#[derive(Clone, PartialEq, Eq, Copy, Hash, PartialOrd, Ord)]
23pub struct DomainId {
24    id: u32,
25}
26
27impl DomainId {
28    pub fn new(id: u32) -> Self {
29        pumpkin_assert_simple!(id >> 30 == 0, "The first two bits are used as flags");
30        DomainId { id }
31    }
32
33    pub fn id(&self) -> u32 {
34        self.id
35    }
36}
37
38impl EventTarget for DomainId {
39    fn register(
40        &self,
41        registration: &mut impl EventDispatcher,
42        events: EnumSet<DomainEvent>,
43        local_id: LocalId,
44    ) {
45        registration.register(*self, events, local_id);
46    }
47}
48
49impl CheckerVariable<Predicate> for DomainId {
50    fn does_atomic_constrain_self(&self, atomic: &Predicate) -> bool {
51        atomic.get_domain() == *self
52    }
53
54    fn atomic_less_than(&self, value: i32) -> Predicate {
55        use crate::predicate;
56
57        predicate![self <= value]
58    }
59
60    fn atomic_greater_than(&self, value: i32) -> Predicate {
61        use crate::predicate;
62
63        predicate![self >= value]
64    }
65
66    fn atomic_equal(&self, value: i32) -> Predicate {
67        use crate::predicate;
68
69        predicate![self == value]
70    }
71
72    fn atomic_not_equal(&self, value: i32) -> Predicate {
73        use crate::predicate;
74
75        predicate![self != value]
76    }
77
78    fn induced_lower_bound(
79        &self,
80        variable_state: &pumpkin_checking::VariableState<Predicate>,
81    ) -> pumpkin_checking::IntExt {
82        variable_state.lower_bound(self)
83    }
84
85    fn induced_upper_bound(
86        &self,
87        variable_state: &pumpkin_checking::VariableState<Predicate>,
88    ) -> pumpkin_checking::IntExt {
89        variable_state.upper_bound(self)
90    }
91
92    fn induced_fixed_value(
93        &self,
94        variable_state: &pumpkin_checking::VariableState<Predicate>,
95    ) -> Option<i32> {
96        variable_state.fixed_value(self)
97    }
98
99    fn induced_domain_contains(
100        &self,
101        variable_state: &pumpkin_checking::VariableState<Predicate>,
102        value: i32,
103    ) -> bool {
104        variable_state.contains(self, value)
105    }
106
107    fn induced_holes<'this, 'state>(
108        &'this self,
109        variable_state: &'state pumpkin_checking::VariableState<Predicate>,
110    ) -> impl Iterator<Item = i32> + 'state
111    where
112        'this: 'state,
113    {
114        variable_state.holes(self)
115    }
116
117    fn iter_induced_domain<'this, 'state>(
118        &'this self,
119        variable_state: &'state pumpkin_checking::VariableState<Predicate>,
120    ) -> Option<impl Iterator<Item = i32> + 'state>
121    where
122        'this: 'state,
123    {
124        variable_state.iter_domain(self)
125    }
126}
127
128impl IntegerVariable for DomainId {
129    type AffineView = AffineView<Self>;
130
131    fn lower_bound(&self, assignment: &Assignments) -> i32 {
132        assignment.get_lower_bound(*self)
133    }
134
135    fn lower_bound_at_trail_position(
136        &self,
137        assignment: &Assignments,
138        trail_position: usize,
139    ) -> i32 {
140        assignment.get_lower_bound_at_trail_position(*self, trail_position)
141    }
142
143    fn upper_bound(&self, assignment: &Assignments) -> i32 {
144        assignment.get_upper_bound(*self)
145    }
146
147    fn upper_bound_at_trail_position(
148        &self,
149        assignment: &Assignments,
150        trail_position: usize,
151    ) -> i32 {
152        assignment.get_upper_bound_at_trail_position(*self, trail_position)
153    }
154
155    fn contains(&self, assignment: &Assignments, value: i32) -> bool {
156        assignment.is_value_in_domain(*self, value)
157    }
158
159    fn contains_at_trail_position(
160        &self,
161        assignment: &Assignments,
162        value: i32,
163        trail_position: usize,
164    ) -> bool {
165        assignment.is_value_in_domain_at_trail_position(*self, value, trail_position)
166    }
167
168    fn iterate_domain(&self, assignment: &Assignments) -> impl Iterator<Item = i32> {
169        assignment.get_domain_iterator(*self)
170    }
171
172    fn unwatch_all(&self, watchers: &mut Watchers<'_>) {
173        watchers.unwatch_all(*self);
174    }
175
176    fn watch_all_backtrack(&self, watchers: &mut Watchers<'_>, events: EnumSet<DomainEvent>) {
177        watchers.watch_all_backtrack(*self, events);
178    }
179
180    fn unpack_event(&self, event: OpaqueDomainEvent) -> DomainEvent {
181        event.unwrap()
182    }
183
184    fn get_holes_at_current_checkpoint(
185        &self,
186        assignments: &Assignments,
187    ) -> impl Iterator<Item = i32> {
188        assignments.get_holes_at_current_checkpoint(*self)
189    }
190
191    fn get_holes(&self, assignments: &Assignments) -> impl Iterator<Item = i32> {
192        assignments.get_holes(*self)
193    }
194}
195
196impl TransformableVariable<AffineView<DomainId>> for DomainId {
197    fn scaled(&self, scale: i32) -> AffineView<DomainId> {
198        AffineView::new(*self, scale, 0)
199    }
200
201    fn offset(&self, offset: i32) -> AffineView<DomainId> {
202        AffineView::new(*self, 1, offset)
203    }
204}
205
206impl PredicateConstructor for DomainId {
207    type Value = i32;
208
209    fn equality_predicate(&self, bound: Self::Value) -> Predicate {
210        Predicate::new(*self, PredicateType::Equal, bound)
211    }
212
213    fn lower_bound_predicate(&self, bound: Self::Value) -> Predicate {
214        Predicate::new(*self, PredicateType::LowerBound, bound)
215    }
216
217    fn upper_bound_predicate(&self, bound: Self::Value) -> Predicate {
218        Predicate::new(*self, PredicateType::UpperBound, bound)
219    }
220
221    fn disequality_predicate(&self, bound: Self::Value) -> Predicate {
222        Predicate::new(*self, PredicateType::NotEqual, bound)
223    }
224}
225
226impl StorageKey for DomainId {
227    fn index(&self) -> usize {
228        self.id as usize
229    }
230
231    fn create_from_index(index: usize) -> Self {
232        DomainId { id: index as u32 }
233    }
234}
235
236impl std::fmt::Display for DomainId {
237    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
238        write!(f, "x{}", self.id)
239    }
240}
241
242impl std::fmt::Debug for DomainId {
243    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
244        write!(f, "x{}", self.id)
245    }
246}