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