pumpkin_core/propagation/contexts/
propagation_context.rs1use crate::basic_types::PredicateId;
2use crate::engine::Assignments;
3use crate::engine::EmptyDomain;
4use crate::engine::EmptyDomainConflict;
5use crate::engine::TrailedValues;
6use crate::engine::notifications::NotificationEngine;
7use crate::engine::notifications::Watchers;
8use crate::engine::predicates::predicate::Predicate;
9use crate::engine::reason::Reason;
10use crate::engine::reason::ReasonStore;
11use crate::engine::reason::StoredReason;
12use crate::engine::variables::Literal;
13use crate::propagation::DomainEvents;
14use crate::propagation::Domains;
15use crate::propagation::HasAssignments;
16use crate::propagation::LocalId;
17#[cfg(doc)]
18use crate::propagation::Propagator;
19#[cfg(doc)]
20use crate::propagation::PropagatorConstructorContext;
21use crate::propagation::PropagatorId;
22use crate::propagation::PropagatorVarId;
23#[cfg(doc)]
24use crate::propagation::ReadDomains;
25use crate::pumpkin_assert_simple;
26use crate::variables::IntegerVariable;
27
28#[derive(Debug)]
35pub struct NotificationContext<'a> {
36 pub(crate) trailed_values: &'a mut TrailedValues,
37 pub(crate) assignments: &'a Assignments,
38}
39
40impl<'a> NotificationContext<'a> {
41 pub(crate) fn new(trailed_values: &'a mut TrailedValues, assignments: &'a Assignments) -> Self {
42 Self {
43 trailed_values,
44 assignments,
45 }
46 }
47
48 pub fn domains(&mut self) -> Domains<'_> {
50 Domains::new(self.assignments, self.trailed_values)
51 }
52
53 pub fn reborrow(&mut self) -> NotificationContext<'_> {
54 NotificationContext {
55 trailed_values: self.trailed_values,
56 assignments: self.assignments,
57 }
58 }
59}
60
61impl<'a> HasAssignments for NotificationContext<'a> {
62 fn assignments(&self) -> &Assignments {
63 self.assignments
64 }
65
66 fn trailed_values(&self) -> &TrailedValues {
67 self.trailed_values
68 }
69
70 fn trailed_values_mut(&mut self) -> &mut TrailedValues {
71 self.trailed_values
72 }
73}
74
75#[derive(Debug)]
80pub struct PropagationContext<'a> {
81 pub(crate) trailed_values: &'a mut TrailedValues,
82 pub(crate) assignments: &'a mut Assignments,
83 pub(crate) reason_store: &'a mut ReasonStore,
84 pub(crate) propagator_id: PropagatorId,
85 pub(crate) notification_engine: &'a mut NotificationEngine,
86 reification_literal: Option<Literal>,
87}
88
89impl<'a> HasAssignments for PropagationContext<'a> {
90 fn assignments(&self) -> &Assignments {
91 self.assignments
92 }
93
94 fn trailed_values(&self) -> &TrailedValues {
95 self.trailed_values
96 }
97
98 fn trailed_values_mut(&mut self) -> &mut TrailedValues {
99 self.trailed_values
100 }
101}
102
103impl<'a> PropagationContext<'a> {
104 pub(crate) fn new(
105 trailed_values: &'a mut TrailedValues,
106 assignments: &'a mut Assignments,
107 reason_store: &'a mut ReasonStore,
108 notification_engine: &'a mut NotificationEngine,
109 propagator_id: PropagatorId,
110 ) -> Self {
111 PropagationContext {
112 trailed_values,
113 assignments,
114 reason_store,
115 propagator_id,
116 notification_engine,
117 reification_literal: None,
118 }
119 }
120
121 pub fn register_predicate(&mut self, predicate: Predicate) -> PredicateId {
126 self.notification_engine.watch_predicate(
127 predicate,
128 self.propagator_id,
129 self.trailed_values,
130 self.assignments,
131 )
132 }
133
134 pub fn unregister_predicate(&mut self, predicate_id: PredicateId) {
136 self.notification_engine
137 .unwatch_predicate(predicate_id, self.propagator_id);
138 }
139
140 pub fn register_domain_event(
144 &mut self,
145 var: impl IntegerVariable,
146 domain_events: DomainEvents,
147 local_id: LocalId,
148 ) {
149 let propagator_var = PropagatorVarId {
150 propagator: self.propagator_id,
151 variable: local_id,
152 };
153
154 let mut watchers = Watchers::new(propagator_var, self.notification_engine);
155 var.watch_all(&mut watchers, domain_events.events());
156 }
157
158 pub fn unregister_domain_event(&mut self, var: impl IntegerVariable, local_id: LocalId) {
160 let propagator_var = PropagatorVarId {
161 propagator: self.propagator_id,
162 variable: local_id,
163 };
164
165 let mut watchers = Watchers::new(propagator_var, self.notification_engine);
166 var.unwatch_all(&mut watchers);
167 }
168
169 pub fn get_predicate(&mut self, predicate_id: PredicateId) -> Predicate {
171 self.notification_engine.get_predicate(predicate_id)
172 }
173
174 pub fn get_id(&mut self, predicate: Predicate) -> PredicateId {
178 self.notification_engine.get_id(predicate)
179 }
180
181 pub(crate) fn with_reification(&mut self, reification_literal: Literal) {
183 pumpkin_assert_simple!(
184 self.reification_literal.is_none(),
185 "cannot reify an already reified propagation context"
186 );
187
188 self.reification_literal = Some(reification_literal);
189 }
190
191 pub fn domains(&mut self) -> Domains<'_> {
193 Domains::new(self.assignments, self.trailed_values)
194 }
195
196 pub(crate) fn get_checkpoint(&self) -> usize {
197 self.assignments.get_checkpoint()
198 }
199
200 pub(crate) fn is_predicate_id_falsified(&mut self, predicate_id: PredicateId) -> bool {
203 self.notification_engine
204 .is_predicate_id_falsified(predicate_id, self.assignments)
205 }
206
207 pub(crate) fn is_predicate_id_satisfied(&mut self, predicate_id: PredicateId) -> bool {
210 self.notification_engine
211 .is_predicate_id_satisfied(predicate_id, self.assignments)
212 }
213
214 pub(crate) fn num_predicate_ids(&self) -> usize {
216 self.notification_engine.num_predicate_ids()
217 }
218
219 pub fn reborrow(&mut self) -> PropagationContext<'_> {
220 PropagationContext {
221 trailed_values: self.trailed_values,
222 assignments: self.assignments,
223 reason_store: self.reason_store,
224 propagator_id: self.propagator_id,
225 notification_engine: self.notification_engine,
226 reification_literal: self.reification_literal,
227 }
228 }
229}
230
231impl PropagationContext<'_> {
232 pub fn post(
239 &mut self,
240 predicate: Predicate,
241 reason: impl Into<Reason>,
242 ) -> Result<(), EmptyDomainConflict> {
243 let slot = self.reason_store.new_slot();
244
245 let modification_result = self.assignments.post_predicate(
246 predicate,
247 Some(slot.reason_ref()),
248 self.notification_engine,
249 );
250
251 match modification_result {
252 Ok(false) => Ok(()),
253 Ok(true) => {
254 let _ = slot.populate(
255 self.propagator_id,
256 build_reason(reason, self.reification_literal),
257 );
258 Ok(())
259 }
260 Err(EmptyDomain) => {
261 let _ = slot.populate(
262 self.propagator_id,
263 build_reason(reason, self.reification_literal),
264 );
265 let (trigger_predicate, trigger_reason) =
266 self.assignments.remove_last_trail_element();
267
268 Err(EmptyDomainConflict {
269 trigger_predicate,
270 trigger_reason: Some(trigger_reason),
271 })
272 }
273 }
274 }
275}
276
277pub(crate) fn build_reason(
278 reason: impl Into<Reason>,
279 reification_literal: Option<Literal>,
280) -> StoredReason {
281 match reason.into() {
282 Reason::Eager(mut conjunction, inference_code) => {
283 conjunction.extend(
284 reification_literal
285 .iter()
286 .map(|lit| lit.get_true_predicate()),
287 );
288 StoredReason::Eager(conjunction, inference_code)
289 }
290 Reason::DynamicLazy(code) => StoredReason::DynamicLazy(code),
291 }
292}