Skip to main content

pumpkin_core/engine/variables/
literal.rs

1use std::ops::Not;
2
3use enumset::EnumSet;
4use pumpkin_checking::CheckerVariable;
5use pumpkin_checking::IntExt;
6use pumpkin_checking::VariableState;
7
8use super::DomainId;
9use super::IntegerVariable;
10use super::TransformableVariable;
11use crate::engine::Assignments;
12use crate::engine::notifications::DomainEvent;
13use crate::engine::notifications::OpaqueDomainEvent;
14use crate::engine::notifications::Watchers;
15use crate::engine::predicates::predicate::Predicate;
16use crate::engine::predicates::predicate_constructor::PredicateConstructor;
17use crate::engine::variables::AffineView;
18use crate::propagation::EventDispatcher;
19use crate::propagation::EventTarget;
20use crate::propagation::LocalId;
21
22#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
23pub struct Literal {
24    integer_variable: AffineView<DomainId>,
25}
26
27impl Literal {
28    /// Creates a new literal wrapping the provided [`DomainId`].
29    ///
30    /// Note: the provided `domain_id` should have a domain between 0 and 1.
31    pub fn new(domain_id: DomainId) -> Literal {
32        Literal {
33            integer_variable: domain_id.scaled(1),
34        }
35    }
36
37    pub fn get_integer_variable(&self) -> AffineView<DomainId> {
38        self.integer_variable
39    }
40
41    pub fn get_true_predicate(&self) -> Predicate {
42        self.lower_bound_predicate(1)
43    }
44
45    pub fn get_false_predicate(&self) -> Predicate {
46        self.upper_bound_predicate(0)
47    }
48}
49
50impl Not for Literal {
51    type Output = Literal;
52
53    fn not(self) -> Self::Output {
54        Literal {
55            integer_variable: self.integer_variable.scaled(-1).offset(1),
56        }
57    }
58}
59
60/// Forwards a function implementation to the field on self.
61macro_rules! forward {
62    (
63        $field:ident,
64        fn $(<$($lt:lifetime),+>)? $name:ident(
65            & $($lt_self:lifetime)? self,
66            $($param_name:ident : $param_type:ty),*
67        ) -> $return_type:ty
68        $(where $($where_clause:tt)*)?
69    ) => {
70        fn $name$(<$($lt),+>)?(
71            & $($lt_self)? self,
72            $($param_name: $param_type),*
73        ) -> $return_type $(where $($where_clause)*)? {
74            self.$field.$name($($param_name),*)
75        }
76    }
77}
78
79impl EventTarget for Literal {
80    fn register(
81        &self,
82        registration: &mut impl EventDispatcher,
83        events: EnumSet<DomainEvent>,
84        local_id: LocalId,
85    ) {
86        self.integer_variable
87            .register(registration, events, local_id);
88    }
89}
90
91impl CheckerVariable<Predicate> for Literal {
92    forward!(integer_variable, fn does_atomic_constrain_self(&self, atomic: &Predicate) -> bool);
93    forward!(integer_variable, fn atomic_less_than(&self, value: i32) -> Predicate);
94    forward!(integer_variable, fn atomic_greater_than(&self, value: i32) -> Predicate);
95    forward!(integer_variable, fn atomic_not_equal(&self, value: i32) -> Predicate);
96    forward!(integer_variable, fn atomic_equal(&self, value: i32) -> Predicate);
97
98    forward!(integer_variable, fn induced_lower_bound(&self, variable_state: &VariableState<Predicate>) -> IntExt);
99    forward!(integer_variable, fn induced_upper_bound(&self, variable_state: &VariableState<Predicate>) -> IntExt);
100    forward!(integer_variable, fn induced_fixed_value(&self, variable_state: &VariableState<Predicate>) -> Option<i32>);
101    forward!(integer_variable, fn induced_domain_contains(&self, variable_state: &VariableState<Predicate>, value: i32) -> bool);
102    forward!(
103        integer_variable,
104        fn <'this, 'state> induced_holes(
105            &'this self,
106            variable_state: &'state VariableState<Predicate>
107        ) -> impl Iterator<Item = i32> + 'state
108        where
109            'this: 'state,
110    );
111    forward!(
112        integer_variable,
113        fn <'this, 'state> iter_induced_domain(
114            &'this self,
115            variable_state: &'state VariableState<Predicate>
116        ) -> Option<impl Iterator<Item = i32> + 'state>
117        where
118            'this: 'state,
119    );
120}
121
122impl IntegerVariable for Literal {
123    type AffineView = AffineView<Self>;
124
125    /// Returns the lower bound represented as a 0-1 value.
126    /// Literals that evaluate to true have a lower bound of 1.
127    /// Literal that evaluate to false have a lower bound of 0.
128    /// Unassigned literals have a lower bound of 0.
129    fn lower_bound(&self, assignment: &Assignments) -> i32 {
130        self.integer_variable.lower_bound(assignment)
131    }
132
133    fn lower_bound_at_trail_position(
134        &self,
135        assignment: &Assignments,
136        trail_position: usize,
137    ) -> i32 {
138        self.integer_variable
139            .lower_bound_at_trail_position(assignment, trail_position)
140    }
141
142    /// Returns the upper bound represented as a 0-1 value.
143    /// Literals that evaluate to true have an upper bound of 1.
144    /// Literal that evaluate to false have a upper bound of 0.
145    /// Unassigned literals have a upper bound of 1.
146    fn upper_bound(&self, assignment: &Assignments) -> i32 {
147        self.integer_variable.upper_bound(assignment)
148    }
149
150    fn upper_bound_at_trail_position(
151        &self,
152        assignment: &Assignments,
153        trail_position: usize,
154    ) -> i32 {
155        self.integer_variable
156            .upper_bound_at_trail_position(assignment, trail_position)
157    }
158
159    /// Returns whether the input value, when interpreted as a bool,
160    /// can be considered for the literal.
161    /// Literals that evaluate to true only contain value 1.
162    /// Literals that evaluate to false only contain value 0.
163    /// Unassigned literals contain both values 0 and 1.
164    fn contains(&self, assignment: &Assignments, value: i32) -> bool {
165        self.integer_variable.contains(assignment, value)
166    }
167
168    fn contains_at_trail_position(
169        &self,
170        assignment: &Assignments,
171        value: i32,
172        trail_position: usize,
173    ) -> bool {
174        self.integer_variable
175            .contains_at_trail_position(assignment, value, trail_position)
176    }
177
178    fn iterate_domain(&self, assignment: &Assignments) -> impl Iterator<Item = i32> {
179        self.integer_variable.iterate_domain(assignment)
180    }
181
182    fn unwatch_all(&self, watchers: &mut Watchers<'_>) {
183        self.integer_variable.unwatch_all(watchers)
184    }
185
186    fn unpack_event(&self, event: OpaqueDomainEvent) -> DomainEvent {
187        self.integer_variable.unpack_event(event)
188    }
189
190    fn watch_all_backtrack(&self, watchers: &mut Watchers<'_>, events: EnumSet<DomainEvent>) {
191        self.integer_variable.watch_all_backtrack(watchers, events)
192    }
193
194    fn get_holes_at_current_checkpoint(
195        &self,
196        assignments: &Assignments,
197    ) -> impl Iterator<Item = i32> {
198        self.integer_variable
199            .get_holes_at_current_checkpoint(assignments)
200    }
201
202    fn get_holes(&self, assignments: &Assignments) -> impl Iterator<Item = i32> {
203        self.integer_variable.get_holes(assignments)
204    }
205}
206
207impl PredicateConstructor for Literal {
208    type Value = i32;
209
210    fn lower_bound_predicate(&self, bound: Self::Value) -> Predicate {
211        self.integer_variable.lower_bound_predicate(bound)
212    }
213
214    fn upper_bound_predicate(&self, bound: Self::Value) -> Predicate {
215        self.integer_variable.upper_bound_predicate(bound)
216    }
217
218    fn equality_predicate(&self, bound: Self::Value) -> Predicate {
219        self.integer_variable.equality_predicate(bound)
220    }
221
222    fn disequality_predicate(&self, bound: Self::Value) -> Predicate {
223        self.integer_variable.disequality_predicate(bound)
224    }
225}
226
227impl TransformableVariable<AffineView<Literal>> for Literal {
228    fn scaled(&self, scale: i32) -> AffineView<Literal> {
229        AffineView::new(*self, scale, 0)
230    }
231
232    fn offset(&self, offset: i32) -> AffineView<Literal> {
233        AffineView::new(*self, 1, offset)
234    }
235}