pumpkin_core/propagation/constructor.rs
1use super::Domains;
2use super::LocalId;
3use super::Propagator;
4use super::PropagatorId;
5use super::PropagatorVarId;
6#[cfg(doc)]
7use crate::Solver;
8use crate::basic_types::PredicateId;
9use crate::engine::Assignments;
10use crate::engine::State;
11use crate::engine::TrailedValues;
12use crate::engine::notifications::Watchers;
13#[cfg(doc)]
14use crate::engine::variables::AffineView;
15#[cfg(doc)]
16use crate::engine::variables::DomainId;
17use crate::predicates::Predicate;
18#[cfg(doc)]
19use crate::propagation::DomainEvent;
20use crate::propagation::DomainEvents;
21use crate::propagation::EventsToRegister;
22use crate::propagation::RuntimeCheckers;
23use crate::variables::IntegerVariable;
24
25/// A propagator constructor creates a fully initialized instance of a [`Propagator`].
26///
27/// The constructor is responsible for:
28/// 1) Indicating on which [`DomainEvent`]s the propagator should be enqueued (via the
29/// [`PropagatorConstructorContext`]).
30/// 2) Initialising the [`PropagatorConstructor::PropagatorImpl`] and its structures.
31pub trait PropagatorConstructor {
32 /// The propagator that is produced by this constructor.
33 type PropagatorImpl: Propagator + Clone;
34
35 /// Create the propagator instance from `Self`.
36 ///
37 /// Returns a [`PropagatorSpec`] that contains:
38 /// - the propagator instance,
39 /// - the events for which the propagator should be enqueued,
40 /// - and the runtime checkers that verify the propagator's behavior.
41 fn create(self, context: PropagatorConstructorContext) -> PropagatorSpec<Self::PropagatorImpl>;
42}
43
44/// The result of [`PropagatorConstructor::create`].
45///
46/// Contains an initialized [`Propagator`], alongside runtime checkers and the events that should
47/// cause the propagator to be enqueued.
48#[derive(Clone, Debug)]
49pub struct PropagatorSpec<P> {
50 /// The domain events the propagator needs to be be registered for.
51 pub registration: EventsToRegister,
52 /// Any runtime checkers that verify the propagator's implementation.
53 pub checkers: RuntimeCheckers,
54 /// The propagator
55 pub propagator: P,
56}
57
58/// [`PropagatorConstructorContext`] is used when [`Propagator`]s are initialised after creation.
59///
60/// It represents a communication point between the [`Solver`] and the [`Propagator`].
61/// Propagators use the [`PropagatorConstructorContext`] to register to domain changes
62/// of variables and to retrieve the current bounds of variables.
63#[derive(Debug)]
64pub struct PropagatorConstructorContext<'a> {
65 state: &'a mut State,
66 pub(crate) propagator_id: PropagatorId,
67}
68
69impl PropagatorConstructorContext<'_> {
70 pub(crate) fn new<'a>(
71 propagator_id: PropagatorId,
72 state: &'a mut State,
73 ) -> PropagatorConstructorContext<'a> {
74 PropagatorConstructorContext {
75 propagator_id,
76 state,
77 }
78 }
79
80 /// Get domain information.
81 pub fn domains(&mut self) -> Domains<'_> {
82 Domains::new(&self.state.assignments, &mut self.state.trailed_values)
83 }
84
85 /// Register the propagator to be enqueued when the given [`Predicate`] becomes true.
86 /// Returns the [`PredicateId`] used by the solver to track the predicate.
87 pub fn register_predicate(&mut self, predicate: Predicate) -> PredicateId {
88 self.state.notification_engine.watch_predicate(
89 predicate,
90 self.propagator_id,
91 &mut self.state.trailed_values,
92 &self.state.assignments,
93 )
94 }
95
96 /// Subscribes the propagator to the given [`DomainEvents`] when they are undone during
97 /// backtracking. The [`LocalId`]s used to register the variable should be the same here.
98 ///
99 /// The domain events determine when [`Propagator::notify_backtrack()`] will be called on the
100 /// propagator. The [`LocalId`] is internal information related to the propagator,
101 /// which is used when calling [`Propagator::notify_backtrack()`] to identify the variable.
102 ///
103 /// Each variable *must* have a unique [`LocalId`]. Most often this would be its index of the
104 /// variable in the internal array of variables.
105 ///
106 /// Note that the [`LocalId`] is used to differentiate between [`DomainId`]s and
107 /// [`AffineView`]s.
108 pub fn register_backtrack<Var: IntegerVariable>(
109 &mut self,
110 var: Var,
111 domain_events: DomainEvents,
112 local_id: LocalId,
113 ) {
114 let propagator_var = PropagatorVarId {
115 propagator: self.propagator_id,
116 variable: local_id,
117 };
118
119 let mut watchers = Watchers::new(propagator_var, &mut self.state.notification_engine);
120 var.watch_all_backtrack(&mut watchers, domain_events.events());
121 }
122
123 /// Reborrow the current context to a new value with a shorter lifetime. Should be used when
124 /// passing `Self` to another function that takes ownership, but the value is still needed
125 /// afterwards.
126 pub fn reborrow(&mut self) -> PropagatorConstructorContext<'_> {
127 PropagatorConstructorContext {
128 propagator_id: self.propagator_id,
129 state: self.state,
130 }
131 }
132}
133
134mod private {
135 use super::*;
136 use crate::propagation::HasAssignments;
137
138 impl HasAssignments for PropagatorConstructorContext<'_> {
139 fn assignments(&self) -> &Assignments {
140 &self.state.assignments
141 }
142
143 fn trailed_values(&self) -> &TrailedValues {
144 &self.state.trailed_values
145 }
146
147 fn trailed_values_mut(&mut self) -> &mut TrailedValues {
148 &mut self.state.trailed_values
149 }
150 }
151}