Skip to main content

pumpkin_core/propagation/
domains.rs

1use crate::engine::Assignments;
2use crate::engine::TrailedInteger;
3use crate::engine::TrailedValues;
4use crate::predicates::Predicate;
5#[cfg(doc)]
6use crate::propagation::ExplanationContext;
7use crate::variables::DomainId;
8use crate::variables::IntegerVariable;
9use crate::variables::Literal;
10
11/// Provides access to domain information to propagators.
12///
13/// Implements [`ReadDomains`] to expose information about the current variable domains such as the
14/// lower-bound of a particular variable.
15#[derive(Debug)]
16pub struct Domains<'a> {
17    pub(crate) assignments: &'a Assignments,
18    trailed_values: &'a mut TrailedValues,
19}
20
21impl<'a> Domains<'a> {
22    pub(crate) fn new(assignments: &'a Assignments, trailed_values: &'a mut TrailedValues) -> Self {
23        Domains {
24            assignments,
25            trailed_values,
26        }
27    }
28
29    pub fn reborrow(&mut self) -> Domains<'_> {
30        Domains::new(self.assignments, self.trailed_values)
31    }
32}
33
34/// A helper-trait for implementing [`ReadDomains`], which exposes the assignment.
35pub(crate) trait HasAssignments {
36    fn assignments(&self) -> &Assignments;
37    fn trailed_values(&self) -> &TrailedValues;
38    fn trailed_values_mut(&mut self) -> &mut TrailedValues;
39}
40
41impl HasAssignments for Domains<'_> {
42    fn assignments(&self) -> &Assignments {
43        self.assignments
44    }
45
46    fn trailed_values(&self) -> &TrailedValues {
47        self.trailed_values
48    }
49
50    fn trailed_values_mut(&mut self) -> &mut TrailedValues {
51        self.trailed_values
52    }
53}
54
55/// A trait defining functions for retrieving information about the current domains.
56pub trait ReadDomains {
57    /// Returns whether the provided [`Predicate`] is assigned (either true or false) or is
58    /// currently unassigned.
59    fn evaluate_predicate(&self, predicate: Predicate) -> Option<bool>;
60
61    /// Returns whether the provided [`Predicate`] is assigned (either true or false) or is
62    /// assigned at the provided trail position.
63    fn evaluate_predicate_at_trail_position(
64        &self,
65        predicate: Predicate,
66        trail_position: usize,
67    ) -> Option<bool>;
68
69    /// Returns whether the provided [`Literal`] is assigned (either true or false) or is
70    /// currently unassigned.
71    fn evaluate_literal(&self, literal: Literal) -> Option<bool>;
72
73    /// Returns the holes in the domain which were created on the current checkpoint.
74    fn get_holes_at_current_checkpoint<Var: IntegerVariable>(
75        &self,
76        var: &Var,
77    ) -> impl Iterator<Item = i32>;
78
79    /// Returns all of the holes (currently) in the domain of `var` (including ones which were
80    /// created at previous decision levels).
81    fn get_holes<Var: IntegerVariable>(&self, var: &Var) -> impl Iterator<Item = i32>;
82
83    /// Returns `true` if the domain of the given variable is singleton (i.e., the variable is
84    /// fixed).
85    fn is_fixed<Var: IntegerVariable>(&self, var: &Var) -> bool;
86
87    /// Returns the fixed value if the domain of the given variable is singleton (i.e., the
88    /// variable is fixed).
89    fn fixed_value<Var: IntegerVariable>(&self, var: &Var) -> Option<i32>;
90
91    /// Returns the lowest value in the domain of `var`.
92    fn lower_bound<Var: IntegerVariable>(&self, var: &Var) -> i32;
93
94    /// Returns the lowest value in the domain of `var` at the given `trail_position`.
95    ///
96    /// The trail position can be retrieved when generating lazy explanations using
97    /// [`ExplanationContext::get_trail_position`].
98    fn lower_bound_at_trail_position<Var: IntegerVariable>(
99        &self,
100        var: &Var,
101        trail_position: usize,
102    ) -> i32;
103
104    /// Returns the highest value in the domain of `var`.
105    fn upper_bound<Var: IntegerVariable>(&self, var: &Var) -> i32;
106
107    /// Returns the highest value in the domain of `var` at the given `trail_position`.
108    ///
109    /// The trail position can be retrieved when generating lazy explanations using
110    /// [`ExplanationContext::get_trail_position`].
111    fn upper_bound_at_trail_position<Var: IntegerVariable>(
112        &self,
113        var: &Var,
114        trail_position: usize,
115    ) -> i32;
116
117    /// Returns whether the provided `value` is in the domain of `var`.
118    fn contains<Var: IntegerVariable>(&self, var: &Var, value: i32) -> bool;
119
120    /// Returns whether the provided `value` is in the domain of `var` at the given
121    /// `trail_position`.
122    ///
123    /// The trail position can be retrieved when generating lazy explanations using
124    /// [`ExplanationContext::get_trail_position`].
125    fn contains_at_trail_position<Var: IntegerVariable>(
126        &self,
127        var: &Var,
128        value: i32,
129        trail_position: usize,
130    ) -> bool;
131
132    /// Returns an [`Iterator`] over the values in the domain of the provided `var` (including the
133    /// lower-bound and upper-bound values).
134    fn iterate_domain<Var: IntegerVariable>(&self, var: &Var) -> impl Iterator<Item = i32>;
135
136    /// Returns whether the provided [`Predicate`] was posted as a decision (i.e., it was posted as
137    /// a [`Predicate`] without a reason).
138    fn is_decision_predicate(&self, predicate: Predicate) -> bool;
139
140    /// Returns whether the provided [`Predicate`] is an initial bound of its domain.
141    fn is_initial_bound(&self, predicate: Predicate) -> bool;
142
143    /// If the provided [`Predicate`] is true, then this method returns the checkpoint at which it
144    /// first become true; otherwise, it returns [`None`].
145    fn get_checkpoint_for_predicate(&self, predicate: Predicate) -> Option<usize>;
146
147    /// Returns the current value of the provided [`TrailedInteger`].
148    fn read_trailed_integer(&self, trailed_integer: TrailedInteger) -> i64;
149
150    /// Creates a new [`TrailedInteger`] assigned to the provided `initial_value`.
151    fn new_trailed_integer(&mut self, initial_value: i64) -> TrailedInteger;
152
153    /// Assigns the provided [`TrailedInteger`] to the provided `value`.
154    fn write_trailed_integer(&mut self, trailed_integer: TrailedInteger, value: i64);
155
156    /// Returns the current checkpoint.
157    fn get_checkpoint(&self) -> usize;
158
159    /// Returns the lowest value in the domain of `var` at the time of its creation.
160    fn initial_lower_bound(&self, var: DomainId) -> i32;
161
162    /// Returns the highest value in the domain of `var` at the time of its creation.
163    fn initial_upper_bound(&self, var: DomainId) -> i32;
164
165    /// Returns all of the holes present at the time of thecreation of `var`.
166    fn initial_holes(&self, var: DomainId) -> Vec<i32>;
167
168    /// Returns the number of currently defined domains.
169    fn number_of_domains(&self) -> u32;
170}
171
172impl<T: HasAssignments> ReadDomains for T {
173    fn evaluate_predicate(&self, predicate: Predicate) -> Option<bool> {
174        self.assignments().evaluate_predicate(predicate)
175    }
176
177    fn evaluate_literal(&self, literal: Literal) -> Option<bool> {
178        self.evaluate_predicate(literal.get_true_predicate())
179    }
180
181    fn get_holes_at_current_checkpoint<Var: IntegerVariable>(
182        &self,
183        var: &Var,
184    ) -> impl Iterator<Item = i32> {
185        var.get_holes_at_current_checkpoint(self.assignments())
186    }
187
188    fn get_holes<Var: IntegerVariable>(&self, var: &Var) -> impl Iterator<Item = i32> {
189        var.get_holes(self.assignments())
190    }
191
192    fn is_fixed<Var: IntegerVariable>(&self, var: &Var) -> bool {
193        self.lower_bound(var) == self.upper_bound(var)
194    }
195
196    fn fixed_value<Var: IntegerVariable>(&self, var: &Var) -> Option<i32> {
197        let lower_bound = self.lower_bound(var);
198        (lower_bound == self.upper_bound(var)).then_some(lower_bound)
199    }
200
201    fn lower_bound<Var: IntegerVariable>(&self, var: &Var) -> i32 {
202        var.lower_bound(self.assignments())
203    }
204
205    fn lower_bound_at_trail_position<Var: IntegerVariable>(
206        &self,
207        var: &Var,
208        trail_position: usize,
209    ) -> i32 {
210        var.lower_bound_at_trail_position(self.assignments(), trail_position)
211    }
212
213    fn upper_bound<Var: IntegerVariable>(&self, var: &Var) -> i32 {
214        var.upper_bound(self.assignments())
215    }
216
217    fn upper_bound_at_trail_position<Var: IntegerVariable>(
218        &self,
219        var: &Var,
220        trail_position: usize,
221    ) -> i32 {
222        var.upper_bound_at_trail_position(self.assignments(), trail_position)
223    }
224
225    fn contains<Var: IntegerVariable>(&self, var: &Var, value: i32) -> bool {
226        var.contains(self.assignments(), value)
227    }
228
229    fn contains_at_trail_position<Var: IntegerVariable>(
230        &self,
231        var: &Var,
232        value: i32,
233        trail_position: usize,
234    ) -> bool {
235        var.contains_at_trail_position(self.assignments(), value, trail_position)
236    }
237
238    fn iterate_domain<Var: IntegerVariable>(&self, var: &Var) -> impl Iterator<Item = i32> {
239        var.iterate_domain(self.assignments())
240    }
241
242    fn is_decision_predicate(&self, predicate: Predicate) -> bool {
243        self.assignments().is_decision_predicate(&predicate)
244    }
245
246    fn is_initial_bound(&self, predicate: Predicate) -> bool {
247        self.assignments().is_initial_bound(predicate)
248    }
249
250    fn get_checkpoint_for_predicate(&self, predicate: Predicate) -> Option<usize> {
251        self.assignments().get_checkpoint_for_predicate(&predicate)
252    }
253
254    fn read_trailed_integer(&self, trailed_integer: TrailedInteger) -> i64 {
255        self.trailed_values().read(trailed_integer)
256    }
257
258    fn new_trailed_integer(&mut self, initial_value: i64) -> TrailedInteger {
259        self.trailed_values_mut().grow(initial_value)
260    }
261
262    fn write_trailed_integer(&mut self, trailed_integer: TrailedInteger, value: i64) {
263        self.trailed_values_mut().assign(trailed_integer, value);
264    }
265
266    fn get_checkpoint(&self) -> usize {
267        self.assignments().get_checkpoint()
268    }
269
270    fn initial_lower_bound(&self, var: DomainId) -> i32 {
271        self.assignments().get_initial_lower_bound(var)
272    }
273
274    fn initial_upper_bound(&self, var: DomainId) -> i32 {
275        self.assignments().get_initial_upper_bound(var)
276    }
277
278    fn initial_holes(&self, var: DomainId) -> Vec<i32> {
279        self.assignments().get_initial_holes(var)
280    }
281
282    fn number_of_domains(&self) -> u32 {
283        self.assignments().num_domains()
284    }
285
286    fn evaluate_predicate_at_trail_position(
287        &self,
288        predicate: Predicate,
289        trail_position: usize,
290    ) -> Option<bool> {
291        self.assignments()
292            .evaluate_predicate_at_trail_position(predicate, trail_position)
293    }
294}