OR-Tools  9.6
integer_search.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 // This file contains all the top-level logic responsible for driving the search
15 // of a satisfiability integer problem. What decision we take next, which new
16 // Literal associated to an IntegerLiteral we create and when we restart.
17 //
18 // For an optimization problem, our algorithm solves a sequence of decision
19 // problem using this file as an entry point. Note that some heuristics here
20 // still use the objective if there is one in order to orient the search towards
21 // good feasible solution though.
22 
23 #ifndef OR_TOOLS_SAT_INTEGER_SEARCH_H_
24 #define OR_TOOLS_SAT_INTEGER_SEARCH_H_
25 
26 #include <stdint.h>
27 
28 #include <functional>
29 #include <vector>
30 
31 #include "absl/container/flat_hash_set.h"
32 #include "absl/time/time.h"
33 #include "ortools/sat/cp_model.pb.h"
36 #include "ortools/sat/integer.h"
38 #include "ortools/sat/model.h"
39 #include "ortools/sat/probing.h"
41 #include "ortools/sat/sat_base.h"
42 #include "ortools/sat/sat_parameters.pb.h"
43 #include "ortools/sat/sat_solver.h"
47 
48 namespace operations_research {
49 namespace sat {
50 
51 // This is used to hold the next decision the solver will take. It is either
52 // a pure Boolean literal decision or correspond to an IntegerLiteral one.
53 //
54 // At most one of the two options should be set.
57  explicit BooleanOrIntegerLiteral(LiteralIndex index)
60  : integer_literal(i_lit) {}
61 
62  bool HasValue() const {
65  }
66 
69 };
70 
71 // Model struct that contains the search heuristics used to find a feasible
72 // solution to an integer problem.
73 //
74 // This is reset by ConfigureSearchHeuristics() and used by
75 // SolveIntegerProblem(), see below.
77  // Decision and restart heuristics. The two vectors must be of the same size
78  // and restart_policies[i] will always be used in conjunction with
79  // decision_policies[i].
80  std::vector<std::function<BooleanOrIntegerLiteral()>> decision_policies;
81  std::vector<std::function<bool()>> restart_policies;
82 
83  // Index in the vectors above that indicate the current configuration.
85 
86  // Two special decision functions that are constructed at loading time.
87  // These are used by ConfigureSearchHeuristics() to fill the policies above.
88  std::function<BooleanOrIntegerLiteral()> fixed_search = nullptr;
89  std::function<BooleanOrIntegerLiteral()> hint_search = nullptr;
90 
91  // This is currently only filled and used by PARTIAL_FIXED_SEARCH.
92  // It contains only the part specified in the input cp model proto.
93  std::function<BooleanOrIntegerLiteral()> user_search = nullptr;
94 
95  // Some search strategy need to take more than one decision at once. They can
96  // set this function that will be called on the next decision. It will be
97  // automatically deleted the first time it returns an empty decision.
98  std::function<BooleanOrIntegerLiteral()> next_decision_override = nullptr;
99 };
100 
101 // Given a base "fixed_search" function that should mainly control in which
102 // order integer variables are lazily instantiated (and at what value), this
103 // uses the current solver parameters to set the SearchHeuristics class in the
104 // given model.
106 
107 // Callbacks that will be called when the search goes back to level 0.
108 // Callbacks should return false if the propagation fails.
110  std::vector<std::function<bool()>> callbacks;
111 };
112 
113 // Resets the solver to the given assumptions before calling
114 // SolveIntegerProblem().
116  const std::vector<Literal>& assumptions, Model* model);
117 
118 // Only used in tests. Move to a test utility file.
119 //
120 // This configures the model SearchHeuristics with a simple default heuristic
121 // and then call ResetAndSolveIntegerProblem() without any assumptions.
123 
124 // Returns decision corresponding to var at its lower bound.
125 // Returns an invalid literal if the variable is fixed.
126 IntegerLiteral AtMinValue(IntegerVariable var, IntegerTrail* integer_trail);
127 
128 // If a variable appear in the objective, branch on its best objective value.
130 
131 // Returns decision corresponding to var >= lb + max(1, (ub - lb) / 2). It also
132 // CHECKs that the variable is not fixed.
134  IntegerTrail* integer_trail);
135 
136 // This method first tries var <= value. If this does not reduce the domain it
137 // tries var >= value. If that also does not reduce the domain then returns
138 // an invalid literal.
139 IntegerLiteral SplitAroundGivenValue(IntegerVariable var, IntegerValue value,
140  Model* model);
141 
142 // Returns decision corresponding to var <= round(lp_value). If the variable
143 // does not appear in the LP, this method returns an invalid literal.
144 IntegerLiteral SplitAroundLpValue(IntegerVariable var, Model* model);
145 
146 // Returns decision corresponding to var <= best_solution[var]. If no solution
147 // has been found, this method returns a literal with kNoIntegerVariable. This
148 // was suggested in paper: "Solution-Based Phase Saving for CP" (2018) by Emir
149 // Demirovic, Geoffrey Chu, and Peter J. Stuckey.
151  Model* model);
152 
153 // Decision heuristic for SolveIntegerProblemWithLazyEncoding(). Returns a
154 // function that will return the literal corresponding to the fact that the
155 // first currently non-fixed variable value is <= its min. The function will
156 // return kNoLiteralIndex if all the given variables are fixed.
157 //
158 // Note that this function will create the associated literal if needed.
160  const std::vector<IntegerVariable>& vars, Model* model);
161 
162 // Decision heuristic for SolveIntegerProblemWithLazyEncoding(). Like
163 // FirstUnassignedVarAtItsMinHeuristic() but the function will return the
164 // literal corresponding to the fact that the currently non-assigned variable
165 // with the lowest min has a value <= this min.
166 std::function<BooleanOrIntegerLiteral()>
168  const std::vector<IntegerVariable>& vars, Model* model);
169 
170 // Set the first unassigned Literal/Variable to its value.
171 //
172 // TODO(user): This is currently quadratic as we scan all variables to find the
173 // first unassigned one. Fix. Note that this is also the case in many other
174 // heuristics and should be fixed.
176  BooleanVariable bool_var = kNoBooleanVariable;
177  IntegerVariable int_var = kNoIntegerVariable;
178 };
179 std::function<BooleanOrIntegerLiteral()> FollowHint(
180  const std::vector<BooleanOrIntegerVariable>& vars,
181  const std::vector<IntegerValue>& values, Model* model);
182 
183 // Combines search heuristics in order: if the i-th one returns kNoLiteralIndex,
184 // ask the (i+1)-th. If every heuristic returned kNoLiteralIndex,
185 // returns kNoLiteralIndex.
187  std::vector<std::function<BooleanOrIntegerLiteral()>> heuristics);
188 
189 // Changes the value of the given decision by 'var_selection_heuristic'. We try
190 // to see if the decision is "associated" with an IntegerVariable, and if it is
191 // the case, we choose the new value by the first 'value_selection_heuristics'
192 // that is applicable. If none of the heuristics are applicable then the given
193 // decision by 'var_selection_heuristic' is returned.
195  std::vector<std::function<IntegerLiteral(IntegerVariable)>>
196  value_selection_heuristics,
197  std::function<BooleanOrIntegerLiteral()> var_selection_heuristic,
198  Model* model);
199 
200 // Changes the value of the given decision by 'var_selection_heuristic'
201 // according to various value selection heuristics. Looks at the code to know
202 // exactly what heuristic we use.
204  std::function<BooleanOrIntegerLiteral()> var_selection_heuristic,
205  Model* model);
206 
207 // Returns the BooleanOrIntegerLiteral advised by the underliying SAT solver.
209 
210 // Gets the branching variable using pseudo costs and combines it with a value
211 // for branching.
212 std::function<BooleanOrIntegerLiteral()> PseudoCost(Model* model);
213 
214 // Simple scheduling heuristic that looks at all the no-overlap constraints
215 // and try to assign and perform the intervals that can be scheduled first.
217  Model* model);
218 
219 // Returns true if the number of variables in the linearized part represent
220 // a large enough proportion of all the problem variables.
222 
223 // A restart policy that restarts every k failures.
224 std::function<bool()> RestartEveryKFailures(int k, SatSolver* solver);
225 
226 // A restart policy that uses the underlying sat solver's policy.
227 std::function<bool()> SatSolverRestartPolicy(Model* model);
228 
229 // Concatenates each input_heuristic with a default heuristic that instantiate
230 // all the problem's Boolean variables, into a new vector.
231 std::vector<std::function<BooleanOrIntegerLiteral()>> CompleteHeuristics(
232  const std::vector<std::function<BooleanOrIntegerLiteral()>>&
233  incomplete_heuristics,
234  const std::function<BooleanOrIntegerLiteral()>& completion_heuristic);
235 
236 // Specialized search that will continuously probe Boolean variables and bounds
237 // of integer variables.
239  const std::vector<BooleanVariable>& bool_vars,
240  const std::vector<IntegerVariable>& int_vars, Model* model);
241 
242 // An helper class to share the code used by the different kind of search.
244  public:
245  explicit IntegerSearchHelper(Model* model);
246 
247  // Executes some code before a new decision.
248  // Returns false if model is UNSAT.
249  bool BeforeTakingDecision();
250 
251  // Calls the decision heuristics and extract a non-fixed literal.
252  // Note that we do not want to copy the function here.
253  LiteralIndex GetDecision(const std::function<BooleanOrIntegerLiteral()>& f);
254 
255  // Tries to take the current decision, this might backjump.
256  // Returns false if the model is UNSAT.
257  bool TakeDecision(Literal decision);
258 
259  // Tries to find a feasible solution to the current model.
260  //
261  // This function continues from the current state of the solver and loop until
262  // all variables are instantiated (i.e. the next decision is kNoLiteralIndex)
263  // or a search limit is reached. It uses the heuristic from the
264  // SearchHeuristics class in the model to decide when to restart and what next
265  // decision to take.
266  //
267  // Each time a restart happen, this increment the policy index modulo the
268  // number of heuristics to act as a portfolio search.
270 
271  private:
272  const SatParameters& parameters_;
273  Model* model_;
274  SatSolver* sat_solver_;
275  IntegerTrail* integer_trail_;
276  IntegerEncoder* encoder_;
277  ImpliedBounds* implied_bounds_;
278  Prober* prober_;
279  ProductDetector* product_detector_;
280  TimeLimit* time_limit_;
281  PseudoCosts* pseudo_costs_;
282  IntegerVariable objective_var_ = kNoIntegerVariable;
283 };
284 
285 // This class will loop continuously on model variables and try to probe/shave
286 // its bounds.
288  public:
289  // The model_proto is just used to construct the lists of variable to probe.
290  ContinuousProber(const CpModelProto& model_proto, Model* model);
291 
292  // Starts or continues probing variables and their bounds.
293  // It returns:
294  // - SatSolver::INFEASIBLE if the problem is proven infeasible.
295  // - SatSolver::FEASIBLE when a feasible solution is found
296  // - SatSolver::LIMIT_REACHED if the limit stored in the model is reached
297  // Calling Probe() after it has returned FEASIBLE or LIMIT_REACHED will resume
298  // probing from its previous state.
300 
301  private:
302  bool ImportFromSharedClasses();
303  SatSolver::Status ShaveLiteral(Literal literal);
304  bool ReportStatus(const SatSolver::Status status);
305  void LogStatistics();
306 
307  // Variables to probe.
308  std::vector<BooleanVariable> bool_vars_;
309  std::vector<IntegerVariable> int_vars_;
310 
311  // Model object.
312  Model* model_;
313  SatSolver* sat_solver_;
314  TimeLimit* time_limit_;
315  Trail* trail_;
316  IntegerTrail* integer_trail_;
317  IntegerEncoder* encoder_;
318  const SatParameters parameters_;
319  LevelZeroCallbackHelper* level_zero_callbacks_;
320  Prober* prober_;
321  SharedResponseManager* shared_response_manager_;
322  SharedBoundsManager* shared_bounds_manager_;
323 
324  // Statistics.
325  int64_t num_literals_probed_ = 0;
326  int64_t num_bounds_shaved_ = 0;
327  int64_t num_bounds_tried_ = 0;
328 
329  // Current state of the probe.
330  double active_limit_;
331  // TODO(user): use 2 vector<bool>.
332  absl::flat_hash_set<BooleanVariable> probed_bool_vars_;
333  absl::flat_hash_set<LiteralIndex> probed_literals_;
334  int iteration_ = 1;
335  absl::Time last_logging_time_;
336  int current_int_var_ = 0;
337  int current_bool_var_ = 0;
338 };
339 
340 } // namespace sat
341 } // namespace operations_research
342 
343 #endif // OR_TOOLS_SAT_INTEGER_SEARCH_H_
A simple class to enforce both an elapsed time limit and a deterministic time limit in the same threa...
Definition: time_limit.h:106
ContinuousProber(const CpModelProto &model_proto, Model *model)
LiteralIndex GetDecision(const std::function< BooleanOrIntegerLiteral()> &f)
Class that owns everything related to a particular optimization model.
Definition: sat/model.h:42
CpModelProto const * model_proto
int64_t value
IntVar * var
Definition: expr_array.cc:1874
absl::Status status
Definition: g_gurobi.cc:41
GRBmodel * model
int index
std::function< BooleanOrIntegerLiteral()> FirstUnassignedVarAtItsMinHeuristic(const std::vector< IntegerVariable > &vars, Model *model)
SatSolver::Status ResetAndSolveIntegerProblem(const std::vector< Literal > &assumptions, Model *model)
const LiteralIndex kNoLiteralIndex(-1)
IntegerLiteral AtMinValue(IntegerVariable var, IntegerTrail *integer_trail)
IntegerLiteral GreaterOrEqualToMiddleValue(IntegerVariable var, IntegerTrail *integer_trail)
IntegerLiteral SplitAroundGivenValue(IntegerVariable var, IntegerValue value, Model *model)
std::function< BooleanOrIntegerLiteral()> UnassignedVarWithLowestMinAtItsMinHeuristic(const std::vector< IntegerVariable > &vars, Model *model)
SatSolver::Status SolveIntegerProblemWithLazyEncoding(Model *model)
std::function< bool()> SatSolverRestartPolicy(Model *model)
const IntegerVariable kNoIntegerVariable(-1)
std::function< BooleanOrIntegerLiteral()> FollowHint(const std::vector< BooleanOrIntegerVariable > &vars, const std::vector< IntegerValue > &values, Model *model)
std::function< bool()> RestartEveryKFailures(int k, SatSolver *solver)
std::function< BooleanOrIntegerLiteral()> SchedulingSearchHeuristic(Model *model)
IntegerLiteral ChooseBestObjectiveValue(IntegerVariable var, Model *model)
void ConfigureSearchHeuristics(Model *model)
std::vector< std::function< BooleanOrIntegerLiteral()> > CompleteHeuristics(const std::vector< std::function< BooleanOrIntegerLiteral()>> &incomplete_heuristics, const std::function< BooleanOrIntegerLiteral()> &completion_heuristic)
IntegerLiteral SplitDomainUsingBestSolutionValue(IntegerVariable var, Model *model)
std::function< BooleanOrIntegerLiteral()> IntegerValueSelectionHeuristic(std::function< BooleanOrIntegerLiteral()> var_selection_heuristic, Model *model)
std::function< BooleanOrIntegerLiteral()> SatSolverHeuristic(Model *model)
SatSolver::Status ContinuousProbing(const std::vector< BooleanVariable > &bool_vars, const std::vector< IntegerVariable > &int_vars, Model *model)
std::function< BooleanOrIntegerLiteral()> SequentialSearch(std::vector< std::function< BooleanOrIntegerLiteral()>> heuristics)
IntegerLiteral SplitAroundLpValue(IntegerVariable var, Model *model)
const BooleanVariable kNoBooleanVariable(-1)
bool LinearizedPartIsLarge(Model *model)
std::function< BooleanOrIntegerLiteral()> PseudoCost(Model *model)
std::function< BooleanOrIntegerLiteral()> SequentialValueSelection(std::vector< std::function< IntegerLiteral(IntegerVariable)>> value_selection_heuristics, std::function< BooleanOrIntegerLiteral()> var_selection_heuristic, Model *model)
Collection of objects used to extend the Constraint Solver library.
Literal literal
Definition: optimization.cc:88
std::vector< std::function< bool()> > callbacks
std::vector< std::function< bool()> > restart_policies
std::function< BooleanOrIntegerLiteral()> hint_search
std::function< BooleanOrIntegerLiteral()> fixed_search
std::function< BooleanOrIntegerLiteral()> next_decision_override
std::function< BooleanOrIntegerLiteral()> user_search
std::vector< std::function< BooleanOrIntegerLiteral()> > decision_policies