Skip to main content

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}