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