pumpkin_core/propagation/contexts/
propagation_context.rs1use enumset::EnumSet;
2
3use crate::basic_types::PredicateId;
4use crate::engine::Assignments;
5use crate::engine::EmptyDomain;
6use crate::engine::EmptyDomainConflict;
7use crate::engine::TrailedValues;
8use crate::engine::notifications::NotificationEngine;
9use crate::engine::notifications::Watchers;
10use crate::engine::predicates::predicate::Predicate;
11use crate::engine::reason::Reason;
12use crate::engine::reason::ReasonStore;
13use crate::engine::reason::StoredReason;
14use crate::engine::variables::Literal;
15use crate::propagation::DomainEvent;
16use crate::propagation::DomainEvents;
17use crate::propagation::Domains;
18use crate::propagation::EventDispatcher;
19use crate::propagation::HasAssignments;
20use crate::propagation::LocalId;
21#[cfg(doc)]
22use crate::propagation::Propagator;
23#[cfg(doc)]
24use crate::propagation::PropagatorConstructorContext;
25use crate::propagation::PropagatorId;
26use crate::propagation::PropagatorVarId;
27#[cfg(doc)]
28use crate::propagation::ReadDomains;
29use crate::pumpkin_assert_simple;
30use crate::variables::DomainId;
31use crate::variables::IntegerVariable;
32
33#[derive(Debug)]
40pub struct NotificationContext<'a> {
41 pub(crate) trailed_values: &'a mut TrailedValues,
42 pub(crate) assignments: &'a Assignments,
43}
44
45impl<'a> NotificationContext<'a> {
46 pub(crate) fn new(trailed_values: &'a mut TrailedValues, assignments: &'a Assignments) -> Self {
47 Self {
48 trailed_values,
49 assignments,
50 }
51 }
52
53 pub fn domains(&mut self) -> Domains<'_> {
55 Domains::new(self.assignments, self.trailed_values)
56 }
57
58 pub fn reborrow(&mut self) -> NotificationContext<'_> {
59 NotificationContext {
60 trailed_values: self.trailed_values,
61 assignments: self.assignments,
62 }
63 }
64}
65
66impl<'a> HasAssignments for NotificationContext<'a> {
67 fn assignments(&self) -> &Assignments {
68 self.assignments
69 }
70
71 fn trailed_values(&self) -> &TrailedValues {
72 self.trailed_values
73 }
74
75 fn trailed_values_mut(&mut self) -> &mut TrailedValues {
76 self.trailed_values
77 }
78}
79
80#[derive(Debug)]
85pub struct PropagationContext<'a> {
86 pub(crate) trailed_values: &'a mut TrailedValues,
87 pub(crate) assignments: &'a mut Assignments,
88 pub(crate) reason_store: &'a mut ReasonStore,
89 pub(crate) propagator_id: PropagatorId,
90 pub(crate) notification_engine: &'a mut NotificationEngine,
91 reification_literal: Option<Literal>,
92}
93
94impl<'a> HasAssignments for PropagationContext<'a> {
95 fn assignments(&self) -> &Assignments {
96 self.assignments
97 }
98
99 fn trailed_values(&self) -> &TrailedValues {
100 self.trailed_values
101 }
102
103 fn trailed_values_mut(&mut self) -> &mut TrailedValues {
104 self.trailed_values
105 }
106}
107
108impl<'a> PropagationContext<'a> {
109 pub(crate) fn new(
110 trailed_values: &'a mut TrailedValues,
111 assignments: &'a mut Assignments,
112 reason_store: &'a mut ReasonStore,
113 notification_engine: &'a mut NotificationEngine,
114 propagator_id: PropagatorId,
115 ) -> Self {
116 PropagationContext {
117 trailed_values,
118 assignments,
119 reason_store,
120 propagator_id,
121 notification_engine,
122 reification_literal: None,
123 }
124 }
125
126 pub fn register_predicate(&mut self, predicate: Predicate) -> PredicateId {
131 self.notification_engine.watch_predicate(
132 predicate,
133 self.propagator_id,
134 self.trailed_values,
135 self.assignments,
136 )
137 }
138
139 pub fn unregister_predicate(&mut self, predicate_id: PredicateId) {
141 self.notification_engine
142 .unwatch_predicate(predicate_id, self.propagator_id);
143 }
144
145 pub fn register_domain_event(
147 &mut self,
148 var: impl IntegerVariable,
149 domain_events: DomainEvents,
150 local_id: LocalId,
151 ) {
152 var.register(
153 &mut NotificationEngineWatchers {
154 notificaton_engine: self.notification_engine,
155 propagator_id: self.propagator_id,
156 },
157 domain_events.events(),
158 local_id,
159 );
160 }
161
162 pub fn unregister_domain_event(&mut self, var: impl IntegerVariable, local_id: LocalId) {
164 let propagator_var = PropagatorVarId {
165 propagator: self.propagator_id,
166 variable: local_id,
167 };
168
169 let mut watchers = Watchers::new(propagator_var, self.notification_engine);
170 var.unwatch_all(&mut watchers);
171 }
172
173 pub fn get_predicate(&mut self, predicate_id: PredicateId) -> Predicate {
175 self.notification_engine.get_predicate(predicate_id)
176 }
177
178 pub fn get_id(&mut self, predicate: Predicate) -> PredicateId {
182 self.notification_engine.get_id(predicate)
183 }
184
185 pub(crate) fn with_reification(&mut self, reification_literal: Literal) {
187 pumpkin_assert_simple!(
188 self.reification_literal.is_none(),
189 "cannot reify an already reified propagation context"
190 );
191
192 self.reification_literal = Some(reification_literal);
193 }
194
195 pub fn domains(&mut self) -> Domains<'_> {
197 Domains::new(self.assignments, self.trailed_values)
198 }
199
200 pub(crate) fn get_checkpoint(&self) -> usize {
201 self.assignments.get_checkpoint()
202 }
203
204 pub(crate) fn is_predicate_id_falsified(&mut self, predicate_id: PredicateId) -> bool {
207 self.notification_engine
208 .is_predicate_id_falsified(predicate_id, self.assignments)
209 }
210
211 pub(crate) fn is_predicate_id_satisfied(&mut self, predicate_id: PredicateId) -> bool {
214 self.notification_engine
215 .is_predicate_id_satisfied(predicate_id, self.assignments)
216 }
217
218 pub(crate) fn evaluate_predicate_id(&mut self, predicate_id: PredicateId) -> Option<bool> {
219 self.notification_engine
220 .evaluate_predicate_id(predicate_id, self.assignments)
221 }
222
223 pub(crate) fn num_predicate_ids(&self) -> usize {
225 self.notification_engine.num_predicate_ids()
226 }
227
228 pub fn reborrow(&mut self) -> PropagationContext<'_> {
229 PropagationContext {
230 trailed_values: self.trailed_values,
231 assignments: self.assignments,
232 reason_store: self.reason_store,
233 propagator_id: self.propagator_id,
234 notification_engine: self.notification_engine,
235 reification_literal: self.reification_literal,
236 }
237 }
238}
239
240impl PropagationContext<'_> {
241 pub fn post(
248 &mut self,
249 predicate: Predicate,
250 reason: impl Into<Reason>,
251 ) -> Result<(), EmptyDomainConflict> {
252 let slot = self.reason_store.new_slot();
253
254 let modification_result = self.assignments.post_predicate(
255 predicate,
256 Some(slot.reason_ref()),
257 self.notification_engine,
258 );
259
260 match modification_result {
261 Ok(false) => Ok(()),
262 Ok(true) => {
263 let _ = slot.populate(
264 self.propagator_id,
265 build_reason(reason, self.reification_literal),
266 );
267 Ok(())
268 }
269 Err(EmptyDomain) => {
270 let _ = slot.populate(
271 self.propagator_id,
272 build_reason(reason, self.reification_literal),
273 );
274 let (trigger_predicate, trigger_reason) =
275 self.assignments.remove_last_trail_element();
276
277 Err(EmptyDomainConflict {
278 trigger_predicate,
279 trigger_reason: Some(trigger_reason),
280 })
281 }
282 }
283 }
284}
285
286pub(crate) fn build_reason(
287 reason: impl Into<Reason>,
288 reification_literal: Option<Literal>,
289) -> StoredReason {
290 match reason.into() {
291 Reason::Eager(mut conjunction, inference_code) => {
292 conjunction.extend(
293 reification_literal
294 .iter()
295 .map(|lit| lit.get_true_predicate()),
296 );
297 StoredReason::Eager(conjunction, inference_code)
298 }
299 Reason::DynamicLazy(code) => StoredReason::DynamicLazy(code),
300 }
301}
302
303struct NotificationEngineWatchers<'a> {
307 propagator_id: PropagatorId,
308 notificaton_engine: &'a mut NotificationEngine,
309}
310
311impl EventDispatcher for NotificationEngineWatchers<'_> {
312 fn register(&mut self, domain_id: DomainId, events: EnumSet<DomainEvent>, local_id: LocalId) {
313 self.notificaton_engine.register(
314 domain_id,
315 events,
316 PropagatorVarId {
317 propagator: self.propagator_id,
318 variable: local_id,
319 },
320 );
321 }
322}