Skip to main content

pumpkin_core/branching/
brancher.rs

1use std::fmt::Debug;
2
3use enum_map::Enum;
4
5#[cfg(doc)]
6use crate::Solver;
7#[cfg(doc)]
8use crate::basic_types::Random;
9use crate::basic_types::SolutionReference;
10#[cfg(doc)]
11use crate::branching;
12use crate::branching::SelectionContext;
13#[cfg(doc)]
14use crate::branching::branchers::dynamic_brancher::DynamicBrancher;
15#[cfg(doc)]
16use crate::branching::value_selection::ValueSelector;
17#[cfg(doc)]
18use crate::branching::variable_selection::VariableSelector;
19#[cfg(doc)]
20use crate::create_statistics_struct;
21use crate::engine::predicates::predicate::Predicate;
22use crate::engine::variables::DomainId;
23#[cfg(doc)]
24use crate::results::solution_iterator::SolutionIterator;
25use crate::statistics::StatisticLogger;
26
27/// A trait for definining a branching strategy (oftentimes utilising a [`VariableSelector`] and a
28/// [`ValueSelector`]).
29///
30/// In general, implementations of this trait define how the search of the solver proceeds (i.e. it
31/// controls how the solver determines which part of the search space to explore). It is required
32/// that the resulting decision creates a smaller domain for at least 1 of the variables (and more
33/// domains can be affected due to subsequent inference). See [`branching`] for
34/// example usages.
35///
36/// If the [`Brancher`] (or any component thereof) is implemented incorrectly then the
37/// behaviour of the solver is undefined.
38pub trait Brancher: Debug {
39    /// Logs statistics of the brancher using the provided [`StatisticLogger`].
40    ///
41    /// It is recommended to create a struct through the [`create_statistics_struct!`] macro!
42    fn log_statistics(&self, _statistic_logger: StatisticLogger) {}
43
44    /// Returns the next decision concerning a single variable and value; it returns the
45    /// [`Predicate`] corresponding to this decision (or [`None`] if all variables under
46    /// consideration are assigned).
47    ///
48    /// Note that this method **cannot** perform the assignment of the decision, it should only
49    /// return a suggestion in the form of a [`Predicate`]; the [`SelectionContext`] is
50    /// only mutable to account for the usage of random generators (e.g. see [`Random`]).
51    fn next_decision(&mut self, context: &mut SelectionContext) -> Option<Predicate>;
52
53    /// A function which is called after a conflict has been found and processed but (currently)
54    /// does not provide any additional information.
55    ///
56    /// To receive information about this event, use [`BrancherEvent::Conflict`] in
57    /// [`Self::subscribe_to_events`]
58    fn on_conflict(&mut self) {}
59
60    /// A function which is called whenever a backtrack occurs in the [`Solver`].
61    ///
62    /// To receive information about this event, use [`BrancherEvent::Backtrack`] in
63    /// [`Self::subscribe_to_events`]
64    fn on_backtrack(&mut self) {}
65
66    /// This method is called when a solution is found; this will either be called when a new
67    /// incumbent solution is found (i.e. a solution with a better objective value than previously
68    /// known) or when a new solution is found when iterating over solutions using
69    /// [`SolutionIterator`].
70    ///
71    /// To receive information about this event, use [`BrancherEvent::Solution`] in
72    /// [`Self::subscribe_to_events`]
73    fn on_solution(&mut self, _solution: SolutionReference) {}
74
75    /// A function which is called after a [`DomainId`] is unassigned during backtracking (i.e. when
76    /// it was fixed but is no longer), specifically, it provides `variable` which is the
77    /// [`DomainId`] which has been reset and `value` which is the value to which the variable was
78    /// previously fixed. This method could thus be called multiple times in a single
79    /// backtracking operation by the solver.
80    ///
81    /// To receive information about this event, use [`BrancherEvent::UnassignInteger`] in
82    /// [`Self::subscribe_to_events`]
83    fn on_unassign_integer(&mut self, _variable: DomainId, _value: i32) {}
84
85    /// A function which is called when a [`Predicate`] appears in a conflict during conflict
86    /// analysis.
87    ///
88    /// To receive information about this event, use
89    /// [`BrancherEvent::AppearanceInConflictPredicate`] in [`Self::subscribe_to_events`]
90    fn on_appearance_in_conflict_predicate(&mut self, _predicate: Predicate) {}
91
92    /// This method is called whenever a restart is performed.
93    /// To receive information about this event, use [`BrancherEvent::Restart`] in
94    /// [`Self::subscribe_to_events`]
95    fn on_restart(&mut self) {}
96
97    /// Called after backtracking.
98    /// Used to reset internal data structures to account for the backtrack.
99    ///
100    /// To receive information about this event, use [`BrancherEvent::Synchronise`] in
101    /// [`Self::subscribe_to_events`]
102    fn synchronise(&mut self, _context: &mut SelectionContext) {}
103
104    /// This method returns whether a restart is *currently* pointless for the [`Brancher`].
105    ///
106    /// For example, if a [`Brancher`] is using a static search strategy then a restart is
107    /// pointless; however, if a [`Brancher`] is using a variable selector which
108    /// changes throughout the search process then restarting is not pointless.
109    ///
110    /// Note that even if the [`Brancher`] has indicated that a restart is pointless, it could be
111    /// that the restart is still performed (e.g. if this [`Brancher`] is a subcomponent of another
112    /// [`Brancher`] and it is not the only `is_restart_pointless` response which is taken into
113    /// account).
114    fn is_restart_pointless(&mut self) -> bool {
115        true
116    }
117
118    /// Indicates which [`BrancherEvent`] are relevant for this particular [`Brancher`].
119    ///
120    /// This can be used by [`Brancher::subscribe_to_events`] to determine upon which
121    /// events which [`VariableSelector`] should be called.
122    fn subscribe_to_events(&self) -> Vec<BrancherEvent>;
123}
124
125/// The events which can occur for a [`Brancher`]. Used for returning which events are relevant in
126/// [`Brancher::subscribe_to_events`], [`VariableSelector::subscribe_to_events`],
127/// and [`ValueSelector::subscribe_to_events`].
128#[derive(Debug, Clone, Copy, Enum, Hash, PartialEq, Eq)]
129pub enum BrancherEvent {
130    /// Event for when a conflict is detected
131    Conflict,
132    /// Event for when a backtrack is performed
133    Backtrack,
134    /// Event for when a solution has been found
135    Solution,
136    /// Event for when an integer variable has become unassigned
137    UnassignInteger,
138    /// Event for when a predicate appears during conflict analysis
139    AppearanceInConflictPredicate,
140    /// Event for when a restart occurs
141    Restart,
142    /// Event which is called with the new state after a backtrack has occurred
143    Synchronise,
144}