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 [`Literal`] is assigned (either true or false) or is
62    /// currently unassigned.
63    fn evaluate_literal(&self, literal: Literal) -> Option<bool>;
64
65    /// Returns the holes in the domain which were created on the current checkpoint.
66    fn get_holes_at_current_checkpoint<Var: IntegerVariable>(
67        &self,
68        var: &Var,
69    ) -> impl Iterator<Item = i32>;
70
71    /// Returns all of the holes (currently) in the domain of `var` (including ones which were
72    /// created at previous decision levels).
73    fn get_holes<Var: IntegerVariable>(&self, var: &Var) -> impl Iterator<Item = i32>;
74
75    /// Returns `true` if the domain of the given variable is singleton (i.e., the variable is
76    /// fixed).
77    fn is_fixed<Var: IntegerVariable>(&self, var: &Var) -> bool;
78
79    /// Returns the fixed value if the domain of the given variable is singleton (i.e., the
80    /// variable is fixed).
81    fn fixed_value<Var: IntegerVariable>(&self, var: &Var) -> Option<i32>;
82
83    /// Returns the lowest value in the domain of `var`.
84    fn lower_bound<Var: IntegerVariable>(&self, var: &Var) -> i32;
85
86    /// Returns the lowest value in the domain of `var` at the given `trail_position`.
87    ///
88    /// The trail position can be retrieved when generating lazy explanations using
89    /// [`ExplanationContext::get_trail_position`].
90    fn lower_bound_at_trail_position<Var: IntegerVariable>(
91        &self,
92        var: &Var,
93        trail_position: usize,
94    ) -> i32;
95
96    /// Returns the highest value in the domain of `var`.
97    fn upper_bound<Var: IntegerVariable>(&self, var: &Var) -> i32;
98
99    /// Returns the highest value in the domain of `var` at the given `trail_position`.
100    ///
101    /// The trail position can be retrieved when generating lazy explanations using
102    /// [`ExplanationContext::get_trail_position`].
103    fn upper_bound_at_trail_position<Var: IntegerVariable>(
104        &self,
105        var: &Var,
106        trail_position: usize,
107    ) -> i32;
108
109    /// Returns whether the provided `value` is in the domain of `var`.
110    fn contains<Var: IntegerVariable>(&self, var: &Var, value: i32) -> bool;
111
112    /// Returns whether the provided `value` is in the domain of `var` at the given
113    /// `trail_position`.
114    ///
115    /// The trail position can be retrieved when generating lazy explanations using
116    /// [`ExplanationContext::get_trail_position`].
117    fn contains_at_trail_position<Var: IntegerVariable>(
118        &self,
119        var: &Var,
120        value: i32,
121        trail_position: usize,
122    ) -> bool;
123
124    /// Returns an [`Iterator`] over the values in the domain of the provided `var` (including the
125    /// lower-bound and upper-bound values).
126    fn iterate_domain<Var: IntegerVariable>(&self, var: &Var) -> impl Iterator<Item = i32>;
127
128    /// Returns whether the provided [`Predicate`] was posted as a decision (i.e., it was posted as
129    /// a [`Predicate`] without a reason).
130    fn is_decision_predicate(&self, predicate: Predicate) -> bool;
131
132    /// Returns whether the provided [`Predicate`] is an initial bound of its domain.
133    fn is_initial_bound(&self, predicate: Predicate) -> bool;
134
135    /// If the provided [`Predicate`] is true, then this method returns the checkpoint at which it
136    /// first become true; otherwise, it returns [`None`].
137    fn get_checkpoint_for_predicate(&self, predicate: Predicate) -> Option<usize>;
138
139    /// Returns the current value of the provided [`TrailedInteger`].
140    fn read_trailed_integer(&self, trailed_integer: TrailedInteger) -> i64;
141
142    /// Creates a new [`TrailedInteger`] assigned to the provided `initial_value`.
143    fn new_trailed_integer(&mut self, initial_value: i64) -> TrailedInteger;
144
145    /// Assigns the provided [`TrailedInteger`] to the provided `value`.
146    fn write_trailed_integer(&mut self, trailed_integer: TrailedInteger, value: i64);
147
148    /// Returns the current checkpoint.
149    fn get_checkpoint(&self) -> usize;
150
151    /// Returns the lowest value in the domain of `var` at the time of its creation.
152    fn initial_lower_bound(&self, var: DomainId) -> i32;
153
154    /// Returns the highest value in the domain of `var` at the time of its creation.
155    fn initial_upper_bound(&self, var: DomainId) -> i32;
156
157    /// Returns all of the holes present at the time of thecreation of `var`.
158    fn initial_holes(&self, var: DomainId) -> Vec<i32>;
159
160    /// Returns the number of currently defined domains.
161    fn number_of_domains(&self) -> u32;
162}
163
164impl<T: HasAssignments> ReadDomains for T {
165    fn evaluate_predicate(&self, predicate: Predicate) -> Option<bool> {
166        self.assignments().evaluate_predicate(predicate)
167    }
168
169    fn evaluate_literal(&self, literal: Literal) -> Option<bool> {
170        self.evaluate_predicate(literal.get_true_predicate())
171    }
172
173    fn get_holes_at_current_checkpoint<Var: IntegerVariable>(
174        &self,
175        var: &Var,
176    ) -> impl Iterator<Item = i32> {
177        var.get_holes_at_current_checkpoint(self.assignments())
178    }
179
180    fn get_holes<Var: IntegerVariable>(&self, var: &Var) -> impl Iterator<Item = i32> {
181        var.get_holes(self.assignments())
182    }
183
184    fn is_fixed<Var: IntegerVariable>(&self, var: &Var) -> bool {
185        self.lower_bound(var) == self.upper_bound(var)
186    }
187
188    fn fixed_value<Var: IntegerVariable>(&self, var: &Var) -> Option<i32> {
189        let lower_bound = self.lower_bound(var);
190        (lower_bound == self.upper_bound(var)).then_some(lower_bound)
191    }
192
193    fn lower_bound<Var: IntegerVariable>(&self, var: &Var) -> i32 {
194        var.lower_bound(self.assignments())
195    }
196
197    fn lower_bound_at_trail_position<Var: IntegerVariable>(
198        &self,
199        var: &Var,
200        trail_position: usize,
201    ) -> i32 {
202        var.lower_bound_at_trail_position(self.assignments(), trail_position)
203    }
204
205    fn upper_bound<Var: IntegerVariable>(&self, var: &Var) -> i32 {
206        var.upper_bound(self.assignments())
207    }
208
209    fn upper_bound_at_trail_position<Var: IntegerVariable>(
210        &self,
211        var: &Var,
212        trail_position: usize,
213    ) -> i32 {
214        var.upper_bound_at_trail_position(self.assignments(), trail_position)
215    }
216
217    fn contains<Var: IntegerVariable>(&self, var: &Var, value: i32) -> bool {
218        var.contains(self.assignments(), value)
219    }
220
221    fn contains_at_trail_position<Var: IntegerVariable>(
222        &self,
223        var: &Var,
224        value: i32,
225        trail_position: usize,
226    ) -> bool {
227        var.contains_at_trail_position(self.assignments(), value, trail_position)
228    }
229
230    fn iterate_domain<Var: IntegerVariable>(&self, var: &Var) -> impl Iterator<Item = i32> {
231        var.iterate_domain(self.assignments())
232    }
233
234    fn is_decision_predicate(&self, predicate: Predicate) -> bool {
235        self.assignments().is_decision_predicate(&predicate)
236    }
237
238    fn is_initial_bound(&self, predicate: Predicate) -> bool {
239        self.assignments().is_initial_bound(predicate)
240    }
241
242    fn get_checkpoint_for_predicate(&self, predicate: Predicate) -> Option<usize> {
243        self.assignments().get_checkpoint_for_predicate(&predicate)
244    }
245
246    fn read_trailed_integer(&self, trailed_integer: TrailedInteger) -> i64 {
247        self.trailed_values().read(trailed_integer)
248    }
249
250    fn new_trailed_integer(&mut self, initial_value: i64) -> TrailedInteger {
251        self.trailed_values_mut().grow(initial_value)
252    }
253
254    fn write_trailed_integer(&mut self, trailed_integer: TrailedInteger, value: i64) {
255        self.trailed_values_mut().assign(trailed_integer, value);
256    }
257
258    fn get_checkpoint(&self) -> usize {
259        self.assignments().get_checkpoint()
260    }
261
262    fn initial_lower_bound(&self, var: DomainId) -> i32 {
263        self.assignments().get_initial_lower_bound(var)
264    }
265
266    fn initial_upper_bound(&self, var: DomainId) -> i32 {
267        self.assignments().get_initial_upper_bound(var)
268    }
269
270    fn initial_holes(&self, var: DomainId) -> Vec<i32> {
271        self.assignments().get_initial_holes(var)
272    }
273
274    fn number_of_domains(&self) -> u32 {
275        self.assignments().num_domains()
276    }
277}