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