pumpkin_core/engine/variables/
literal.rs

1use std::ops::Not;
2
3use enumset::EnumSet;
4
5use super::DomainId;
6use super::IntegerVariable;
7use super::TransformableVariable;
8use crate::engine::notifications::DomainEvent;
9use crate::engine::notifications::OpaqueDomainEvent;
10use crate::engine::notifications::Watchers;
11use crate::engine::predicates::predicate::Predicate;
12use crate::engine::predicates::predicate_constructor::PredicateConstructor;
13use crate::engine::variables::AffineView;
14use crate::engine::Assignments;
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
17pub struct Literal {
18    integer_variable: AffineView<DomainId>,
19}
20
21impl Literal {
22    /// Creates a new literal wrapping the provided [`DomainId`].
23    ///
24    /// Note: the provided `domain_id` should have a domain between 0 and 1.
25    pub fn new(domain_id: DomainId) -> Literal {
26        Literal {
27            integer_variable: domain_id.scaled(1),
28        }
29    }
30
31    pub fn get_integer_variable(&self) -> AffineView<DomainId> {
32        self.integer_variable
33    }
34
35    pub fn get_true_predicate(&self) -> Predicate {
36        self.lower_bound_predicate(1)
37    }
38
39    pub fn get_false_predicate(&self) -> Predicate {
40        self.upper_bound_predicate(0)
41    }
42}
43
44impl Not for Literal {
45    type Output = Literal;
46
47    fn not(self) -> Self::Output {
48        Literal {
49            integer_variable: self.integer_variable.scaled(-1).offset(1),
50        }
51    }
52}
53
54impl IntegerVariable for Literal {
55    type AffineView = AffineView<Self>;
56
57    /// Returns the lower bound represented as a 0-1 value.
58    /// Literals that evaluate to true have a lower bound of 1.
59    /// Literal that evaluate to false have a lower bound of 0.
60    /// Unassigned literals have a lower bound of 0.
61    fn lower_bound(&self, assignment: &Assignments) -> i32 {
62        self.integer_variable.lower_bound(assignment)
63    }
64
65    fn lower_bound_at_trail_position(
66        &self,
67        assignment: &Assignments,
68        trail_position: usize,
69    ) -> i32 {
70        self.integer_variable
71            .lower_bound_at_trail_position(assignment, trail_position)
72    }
73
74    /// Returns the upper bound represented as a 0-1 value.
75    /// Literals that evaluate to true have an upper bound of 1.
76    /// Literal that evaluate to false have a upper bound of 0.
77    /// Unassigned literals have a upper bound of 1.
78    fn upper_bound(&self, assignment: &Assignments) -> i32 {
79        self.integer_variable.upper_bound(assignment)
80    }
81
82    fn upper_bound_at_trail_position(
83        &self,
84        assignment: &Assignments,
85        trail_position: usize,
86    ) -> i32 {
87        self.integer_variable
88            .upper_bound_at_trail_position(assignment, trail_position)
89    }
90
91    /// Returns whether the input value, when interpreted as a bool,
92    /// can be considered for the literal.
93    /// Literals that evaluate to true only contain value 1.
94    /// Literals that evaluate to false only contain value 0.
95    /// Unassigned literals contain both values 0 and 1.
96    fn contains(&self, assignment: &Assignments, value: i32) -> bool {
97        self.integer_variable.contains(assignment, value)
98    }
99
100    fn contains_at_trail_position(
101        &self,
102        assignment: &Assignments,
103        value: i32,
104        trail_position: usize,
105    ) -> bool {
106        self.integer_variable
107            .contains_at_trail_position(assignment, value, trail_position)
108    }
109
110    fn iterate_domain(&self, assignment: &Assignments) -> impl Iterator<Item = i32> {
111        self.integer_variable.iterate_domain(assignment)
112    }
113
114    fn watch_all(&self, watchers: &mut Watchers<'_>, events: EnumSet<DomainEvent>) {
115        self.integer_variable.watch_all(watchers, events)
116    }
117
118    fn unpack_event(&self, event: OpaqueDomainEvent) -> DomainEvent {
119        self.integer_variable.unpack_event(event)
120    }
121
122    fn watch_all_backtrack(&self, watchers: &mut Watchers<'_>, events: EnumSet<DomainEvent>) {
123        self.integer_variable.watch_all_backtrack(watchers, events)
124    }
125
126    fn get_holes_on_current_decision_level(
127        &self,
128        assignments: &Assignments,
129    ) -> impl Iterator<Item = i32> {
130        self.integer_variable
131            .get_holes_on_current_decision_level(assignments)
132    }
133
134    fn get_holes(&self, assignments: &Assignments) -> impl Iterator<Item = i32> {
135        self.integer_variable.get_holes(assignments)
136    }
137}
138
139impl PredicateConstructor for Literal {
140    type Value = i32;
141
142    fn lower_bound_predicate(&self, bound: Self::Value) -> Predicate {
143        self.integer_variable.lower_bound_predicate(bound)
144    }
145
146    fn upper_bound_predicate(&self, bound: Self::Value) -> Predicate {
147        self.integer_variable.upper_bound_predicate(bound)
148    }
149
150    fn equality_predicate(&self, bound: Self::Value) -> Predicate {
151        self.integer_variable.equality_predicate(bound)
152    }
153
154    fn disequality_predicate(&self, bound: Self::Value) -> Predicate {
155        self.integer_variable.disequality_predicate(bound)
156    }
157}
158
159impl TransformableVariable<AffineView<Literal>> for Literal {
160    fn scaled(&self, scale: i32) -> AffineView<Literal> {
161        AffineView::new(*self, scale, 0)
162    }
163
164    fn offset(&self, offset: i32) -> AffineView<Literal> {
165        AffineView::new(*self, 1, offset)
166    }
167}