OR-Tools  9.6
sat_decision.h
Go to the documentation of this file.
1 // Copyright 2010-2022 Google LLC
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 
14 #ifndef OR_TOOLS_SAT_SAT_DECISION_H_
15 #define OR_TOOLS_SAT_SAT_DECISION_H_
16 
17 #include <cstdint>
18 #include <utility>
19 #include <vector>
20 
23 #include "ortools/sat/model.h"
25 #include "ortools/sat/sat_base.h"
26 #include "ortools/sat/sat_parameters.pb.h"
27 #include "ortools/sat/util.h"
28 #include "ortools/util/bitset.h"
30 
31 namespace operations_research {
32 namespace sat {
33 
34 // Implement the SAT branching policy responsible for deciding the next Boolean
35 // variable to branch on, and its polarity (true or false).
37  public:
38  explicit SatDecisionPolicy(Model* model);
39 
40  // Notifies that more variables are now present. Note that currently this may
41  // change the current variable order because the priority queue need to be
42  // reconstructed.
43  void IncreaseNumVariables(int num_variables);
44 
45  // Reinitializes the decision heuristics (which variables to choose with which
46  // polarity) according to the current parameters. Note that this also resets
47  // the activity of the variables to 0. Note that this function is lazy, and
48  // the work will only happen on the first NextBranch() to cover the cases when
49  // this policy is not used at all.
51 
52  // Returns next decision to branch upon. This shouldn't be called if all the
53  // variables are assigned.
55 
56  // Updates statistics about literal occurrences in constraints.
57  // Input is a canonical linear constraint of the form (terms <= rhs).
58  void UpdateWeightedSign(const std::vector<LiteralWithCoeff>& terms,
59  Coefficient rhs);
60 
61  // Bumps the activity of all variables appearing in the conflict. All literals
62  // must be currently assigned. See VSIDS decision heuristic: Chaff:
63  // Engineering an Efficient SAT Solver. M.W. Moskewicz et al. ANNUAL ACM IEEE
64  // DESIGN AUTOMATION CONFERENCE 2001.
65  void BumpVariableActivities(const std::vector<Literal>& literals);
66 
67  // Updates the increment used for activity bumps. This is basically the same
68  // as decaying all the variable activities, but it is a lot more efficient.
70 
71  // Called on Untrail() so that we can update the set of possible decisions.
72  void Untrail(int target_trail_index);
73 
74  // Called on a new conflict before Untrail(). The trail before the given index
75  // is used in the phase saving heuristic as a partial assignment.
76  void BeforeConflict(int trail_index);
77 
78  // By default, we alternate between a stable phase (better suited for finding
79  // SAT solution) and a more restart heavy phase more suited for proving UNSAT.
80  // This changes a bit the polarity heuristics and is controlled from within
81  // SatRestartPolicy.
82  void SetStablePhase(bool is_stable) { in_stable_phase_ = is_stable; }
83  bool InStablePhase() const { return in_stable_phase_; }
84 
85  // This is used to temporarily disable phase_saving when we do some probing
86  // during search for instance.
87  void MaybeEnablePhaseSaving(bool save_phase) {
88  maybe_enable_phase_saving_ = save_phase;
89  }
90 
91  // Gives a hint so the solver tries to find a solution with the given literal
92  // set to true. Currently this take precedence over the phase saving heuristic
93  // and a variable with a preference will always be branched on according to
94  // this preference.
95  //
96  // The weight is used as a tie-breaker between variable with the same
97  // activities. Larger weight will be selected first. A weight of zero is the
98  // default value for the other variables.
99  //
100  // Note(user): Having a lot of different weights may slow down the priority
101  // queue operations if there is millions of variables.
103 
104  // Returns the vector of the current assignment preferences.
105  std::vector<std::pair<Literal, double>> AllPreferences() const;
106 
107  // Returns the current activity of a BooleanVariable.
108  double Activity(Literal l) const {
109  if (l.Variable() < activities_.size()) return activities_[l.Variable()];
110  return 0.0;
111  }
112 
113  private:
114  // Computes an initial variable ordering.
115  void InitializeVariableOrdering();
116 
117  // Rescales activity value of all variables when one of them reached the max.
118  void RescaleVariableActivities(double scaling_factor);
119 
120  // Reinitializes the initial polarity of all the variables with an index
121  // greater than or equal to the given one.
122  void ResetInitialPolarity(int from, bool inverted = false);
123 
124  // Code used for resetting the initial polarity at the beginning of each
125  // phase.
126  void RephaseIfNeeded();
127  void UseLongestAssignmentAsInitialPolarity();
128  void FlipCurrentPolarity();
129  void RandomizeCurrentPolarity();
130 
131  // Adds the given variable to var_ordering_ or updates its priority if it is
132  // already present.
133  void PqInsertOrUpdate(BooleanVariable var);
134 
135  // Singleton model objects.
136  const SatParameters& parameters_;
137  const Trail& trail_;
138  ModelRandomGenerator* random_;
139 
140  // Variable ordering (priority will be adjusted dynamically). queue_elements_
141  // holds the elements used by var_ordering_ (it uses pointers).
142  //
143  // Note that we recover the variable that a WeightedVarQueueElement refers to
144  // by its position in the queue_elements_ vector, and we can recover the later
145  // using (pointer - &queue_elements_[0]).
146  struct WeightedVarQueueElement {
147  // Interface for the IntegerPriorityQueue.
148  int Index() const { return var.value(); }
149 
150  // Priority order. The IntegerPriorityQueue returns the largest element
151  // first.
152  //
153  // Note(user): We used to also break ties using the variable index, however
154  // this has two drawbacks:
155  // - On problem with many variables, this slow down quite a lot the priority
156  // queue operations (which do as little work as possible and hence benefit
157  // from having the majority of elements with a priority of 0).
158  // - It seems to be a bad heuristics. One reason could be that the priority
159  // queue will automatically diversify the choice of the top variables
160  // amongst the ones with the same priority.
161  //
162  // Note(user): For the same reason as explained above, it is probably a good
163  // idea not to have too many different values for the tie_breaker field. I
164  // am not even sure we should have such a field...
165  bool operator<(const WeightedVarQueueElement& other) const {
166  return weight < other.weight ||
167  (weight == other.weight && (tie_breaker < other.tie_breaker));
168  }
169 
170  BooleanVariable var;
171  float tie_breaker;
172 
173  // TODO(user): Experiment with float. In the rest of the code, we use
174  // double, but maybe we don't need that much precision. Using float here may
175  // save memory and make the PQ operations faster.
176  double weight;
177  };
178  static_assert(sizeof(WeightedVarQueueElement) == 16,
179  "ERROR_WeightedVarQueueElement_is_not_well_compacted");
180 
181  bool var_ordering_is_initialized_ = false;
182  IntegerPriorityQueue<WeightedVarQueueElement> var_ordering_;
183 
184  // This is used for the branching heuristic described in "Learning Rate Based
185  // Branching Heuristic for SAT solvers", J.H.Liang, V. Ganesh, P. Poupart,
186  // K.Czarnecki, SAT 2016.
187  //
188  // The entries are sorted by trail index, and one can get the number of
189  // conflicts during which a variable at a given trail index i was assigned by
190  // summing the entry.count for all entries with a trail index greater than i.
191  struct NumConflictsStackEntry {
192  int trail_index;
193  int64_t count;
194  };
195  int64_t num_conflicts_ = 0;
196  std::vector<NumConflictsStackEntry> num_conflicts_stack_;
197 
198  // Whether the priority of the given variable needs to be updated in
199  // var_ordering_. Note that this is only accessed for assigned variables and
200  // that for efficiency it is indexed by trail indices. If
201  // pq_need_update_for_var_at_trail_index_[trail_->Info(var).trail_index] is
202  // true when we untrail var, then either var need to be inserted in the queue,
203  // or we need to notify that its priority has changed.
204  BitQueue64 pq_need_update_for_var_at_trail_index_;
205 
206  // Increment used to bump the variable activities.
207  double variable_activity_increment_ = 1.0;
208 
209  // Stores variable activity and the number of time each variable was "bumped".
210  // The later is only used with the ERWA heuristic.
214 
215  // If the polarity if forced (externally) we always use this first.
216  absl::StrongVector<BooleanVariable, bool> has_forced_polarity_;
218 
219  // If we are in a stable phase, we follow the current target.
220  bool in_stable_phase_ = false;
221  int target_length_ = 0;
222  absl::StrongVector<BooleanVariable, bool> has_target_polarity_;
224 
225  // Otherwise we follow var_polarity_ which is reset at the beginning of
226  // each new polarity phase. This is also overwritten by phase saving.
227  // Each phase last for an arithmetically increasing number of conflicts.
229  bool maybe_enable_phase_saving_ = true;
230  int64_t polarity_phase_ = 0;
231  int64_t num_conflicts_until_rephase_ = 1000;
232 
233  // The longest partial assignment since the last reset.
234  std::vector<Literal> best_partial_assignment_;
235 
236  // Used in initial polarity computation.
238 
239  // Used in InitializeVariableOrdering().
240  std::vector<BooleanVariable> tmp_variables_;
241 };
242 
243 } // namespace sat
244 } // namespace operations_research
245 
246 #endif // OR_TOOLS_SAT_SAT_DECISION_H_
size_type size() const
BooleanVariable Variable() const
Definition: sat_base.h:86
Class that owns everything related to a particular optimization model.
Definition: sat/model.h:42
std::vector< std::pair< Literal, double > > AllPreferences() const
void IncreaseNumVariables(int num_variables)
Definition: sat_decision.cc:41
void SetAssignmentPreference(Literal literal, double weight)
void MaybeEnablePhaseSaving(bool save_phase)
Definition: sat_decision.h:87
void Untrail(int target_trail_index)
void BumpVariableActivities(const std::vector< Literal > &literals)
void UpdateWeightedSign(const std::vector< LiteralWithCoeff > &terms, Coefficient rhs)
IntVar * var
Definition: expr_array.cc:1874
GRBmodel * model
std::tuple< int64_t, int64_t, const double > Coefficient
Collection of objects used to extend the Constraint Solver library.
Literal literal
Definition: optimization.cc:88
int64_t weight
Definition: pack.cc:510