OR-Tools  9.3
integer_search.h
Go to the documentation of this file.
1// Copyright 2010-2021 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"
42#include "ortools/sat/sat_parameters.pb.h"
47
48namespace operations_research {
49namespace 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 // Some search strategy need to take more than one decision at once. They can
92 // set this function that will be called on the next decision. It will be
93 // automatically deleted the first time it returns an empty decision.
95};
96
97// Given a base "fixed_search" function that should mainly control in which
98// order integer variables are lazily instantiated (and at what value), this
99// uses the current solver parameters to set the SearchHeuristics class in the
100// given model.
102
103// Callbacks that will be called when the search goes back to level 0.
104// Callbacks should return false if the propagation fails.
106 std::vector<std::function<bool()>> callbacks;
107};
108
109// Tries to find a feasible solution to the current model.
110//
111// This function continues from the current state of the solver and loop until
112// all variables are instantiated (i.e. the next decision is kNoLiteralIndex) or
113// a search limit is reached. It uses the heuristic from the SearchHeuristics
114// class in the model to decide when to restart and what next decision to take.
115//
116// Each time a restart happen, this increment the policy index modulo the number
117// of heuristics to act as a portfolio search.
119
120// Resets the solver to the given assumptions before calling
121// SolveIntegerProblem().
123 const std::vector<Literal>& assumptions, Model* model);
124
125// Only used in tests. Move to a test utility file.
126//
127// This configures the model SearchHeuristics with a simple default heuristic
128// and then call ResetAndSolveIntegerProblem() without any assumptions.
130
131// Returns decision corresponding to var at its lower bound.
132// Returns an invalid literal if the variable is fixed.
133IntegerLiteral AtMinValue(IntegerVariable var, IntegerTrail* integer_trail);
134
135// If a variable appear in the objective, branch on its best objective value.
137
138// Returns decision corresponding to var >= lb + max(1, (ub - lb) / 2). It also
139// CHECKs that the variable is not fixed.
141 IntegerTrail* integer_trail);
142
143// This method first tries var <= value. If this does not reduce the domain it
144// tries var >= value. If that also does not reduce the domain then returns
145// an invalid literal.
146IntegerLiteral SplitAroundGivenValue(IntegerVariable var, IntegerValue value,
147 Model* model);
148
149// Returns decision corresponding to var <= round(lp_value). If the variable
150// does not appear in the LP, this method returns an invalid literal.
152
153// Returns decision corresponding to var <= best_solution[var]. If no solution
154// has been found, this method returns a literal with kNoIntegerVariable. This
155// was suggested in paper: "Solution-Based Phase Saving for CP" (2018) by Emir
156// Demirovic, Geoffrey Chu, and Peter J. Stuckey.
158 Model* model);
159
160// Decision heuristic for SolveIntegerProblemWithLazyEncoding(). Returns a
161// function that will return the literal corresponding to the fact that the
162// first currently non-fixed variable value is <= its min. The function will
163// return kNoLiteralIndex if all the given variables are fixed.
164//
165// Note that this function will create the associated literal if needed.
167 const std::vector<IntegerVariable>& vars, Model* model);
168
169// Decision heuristic for SolveIntegerProblemWithLazyEncoding(). Like
170// FirstUnassignedVarAtItsMinHeuristic() but the function will return the
171// literal corresponding to the fact that the currently non-assigned variable
172// with the lowest min has a value <= this min.
173std::function<BooleanOrIntegerLiteral()>
175 const std::vector<IntegerVariable>& vars, Model* model);
176
177// Set the first unassigned Literal/Variable to its value.
178//
179// TODO(user): This is currently quadratic as we scan all variables to find the
180// first unassigned one. Fix. Note that this is also the case in many other
181// heuristics and should be fixed.
183 BooleanVariable bool_var = kNoBooleanVariable;
184 IntegerVariable int_var = kNoIntegerVariable;
185};
186std::function<BooleanOrIntegerLiteral()> FollowHint(
187 const std::vector<BooleanOrIntegerVariable>& vars,
188 const std::vector<IntegerValue>& values, Model* model);
189
190// Combines search heuristics in order: if the i-th one returns kNoLiteralIndex,
191// ask the (i+1)-th. If every heuristic returned kNoLiteralIndex,
192// returns kNoLiteralIndex.
194 std::vector<std::function<BooleanOrIntegerLiteral()>> heuristics);
195
196// Changes the value of the given decision by 'var_selection_heuristic'. We try
197// to see if the decision is "associated" with an IntegerVariable, and if it is
198// the case, we choose the new value by the first 'value_selection_heuristics'
199// that is applicable. If none of the heuristics are applicable then the given
200// decision by 'var_selection_heuristic' is returned.
202 std::vector<std::function<IntegerLiteral(IntegerVariable)>>
203 value_selection_heuristics,
204 std::function<BooleanOrIntegerLiteral()> var_selection_heuristic,
205 Model* model);
206
207// Changes the value of the given decision by 'var_selection_heuristic'
208// according to various value selection heuristics. Looks at the code to know
209// exactly what heuristic we use.
211 std::function<BooleanOrIntegerLiteral()> var_selection_heuristic,
212 Model* model);
213
214// Returns the BooleanOrIntegerLiteral advised by the underliying SAT solver.
216
217// Gets the branching variable using pseudo costs and combines it with a value
218// for branching.
220
221// Simple scheduling heuristic that looks at all the no-overlap constraints
222// and try to assign and perform the intervals that can be scheduled first.
224 Model* model);
225
226// Returns true if the number of variables in the linearized part represent
227// a large enough proportion of all the problem variables.
229
230// A restart policy that restarts every k failures.
231std::function<bool()> RestartEveryKFailures(int k, SatSolver* solver);
232
233// A restart policy that uses the underlying sat solver's policy.
234std::function<bool()> SatSolverRestartPolicy(Model* model);
235
236// Concatenates each input_heuristic with a default heuristic that instantiate
237// all the problem's Boolean variables, into a new vector.
238std::vector<std::function<BooleanOrIntegerLiteral()>> CompleteHeuristics(
239 const std::vector<std::function<BooleanOrIntegerLiteral()>>&
240 incomplete_heuristics,
241 const std::function<BooleanOrIntegerLiteral()>& completion_heuristic);
242
243// Specialized search that will continuously probe Boolean variables and bounds
244// of integer variables.
246 const std::vector<BooleanVariable>& bool_vars,
247 const std::vector<IntegerVariable>& int_vars, Model* model);
248
249// An helper class to share the code used by the different kind of search.
251 public:
253
254 // Executes some code before a new decision.
255 // Returns false if model is UNSAT.
257
258 // Calls the decision heuristics and extract a non-fixed literal.
259 // Note that we do not want to copy the function here.
260 LiteralIndex GetDecision(const std::function<BooleanOrIntegerLiteral()>& f);
261
262 // Tries to take the current decision, this might backjump.
263 // Returns false if the model is UNSAT.
264 bool TakeDecision(Literal decision);
265
266 private:
267 Model* model_;
268 SatSolver* sat_solver_;
269 IntegerTrail* integer_trail_;
270 IntegerEncoder* encoder_;
271 ImpliedBounds* implied_bounds_;
272 TimeLimit* time_limit_;
273 PseudoCosts* pseudo_costs_;
274 IntegerVariable objective_var_ = kNoIntegerVariable;
275};
276
277// This class will loop continuously on model variables and try to probe/shave
278// its bounds.
280 public:
281 // The model_proto is just used to construct the lists of variable to probe.
282 ContinuousProber(const CpModelProto& model_proto, Model* model);
283
284 // Starts or continues probing variables and their bounds.
285 // It returns:
286 // - SatSolver::INFEASIBLE if the problem is proven infeasible.
287 // - SatSolver::FEASIBLE when a feasible solution is found
288 // - SatSolver::LIMIT_REACHED if the limit stored in the model is reached
289 // Calling Probe() after it has returned FEASIBLE or LIMIT_REACHED will resume
290 // probing from its previous state.
292
293 private:
294 bool ImportFromSharedClasses();
295 SatSolver::Status ShaveLiteral(Literal literal);
296 bool ReportStatus(const SatSolver::Status status);
297 void LogStatistics();
298
299 // Variables to probe.
300 std::vector<BooleanVariable> bool_vars_;
301 std::vector<IntegerVariable> int_vars_;
302
303 // Model object.
304 Model* model_;
305 SatSolver* sat_solver_;
306 TimeLimit* time_limit_;
307 Trail* trail_;
308 IntegerTrail* integer_trail_;
309 IntegerEncoder* encoder_;
310 const SatParameters parameters_;
311 LevelZeroCallbackHelper* level_zero_callbacks_;
312 Prober* prober_;
313 SharedResponseManager* shared_response_manager_;
314 SharedBoundsManager* shared_bounds_manager_;
315
316 // Statistics.
317 int64_t num_literals_probed_ = 0;
318 int64_t num_bounds_shaved_ = 0;
319 int64_t num_bounds_tried_ = 0;
320
321 // Current state of the probe.
322 double active_limit_;
323 // TODO(user): use 2 vector<bool>.
324 absl::flat_hash_set<BooleanVariable> probed_bool_vars_;
325 absl::flat_hash_set<LiteralIndex> probed_literals_;
326 int iteration_ = 1;
327 absl::Time last_logging_time_;
328 int current_int_var_ = 0;
329 int current_bool_var_ = 0;
330};
331
332} // namespace sat
333} // namespace operations_research
334
335#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:35
GRBmodel * model
int index
std::vector< std::function< BooleanOrIntegerLiteral()> > CompleteHeuristics(const std::vector< std::function< BooleanOrIntegerLiteral()> > &incomplete_heuristics, const std::function< BooleanOrIntegerLiteral()> &completion_heuristic)
std::function< BooleanOrIntegerLiteral()> FirstUnassignedVarAtItsMinHeuristic(const std::vector< IntegerVariable > &vars, Model *model)
SatSolver::Status ResetAndSolveIntegerProblem(const std::vector< Literal > &assumptions, Model *model)
std::function< BooleanOrIntegerLiteral()> SequentialValueSelection(std::vector< std::function< IntegerLiteral(IntegerVariable)> > value_selection_heuristics, std::function< BooleanOrIntegerLiteral()> var_selection_heuristic, Model *model)
std::function< BooleanOrIntegerLiteral()> SequentialSearch(std::vector< std::function< BooleanOrIntegerLiteral()> > heuristics)
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)
IntegerLiteral SplitDomainUsingBestSolutionValue(IntegerVariable var, Model *model)
std::function< BooleanOrIntegerLiteral()> IntegerValueSelectionHeuristic(std::function< BooleanOrIntegerLiteral()> var_selection_heuristic, Model *model)
SatSolver::Status SolveIntegerProblem(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)
IntegerLiteral SplitAroundLpValue(IntegerVariable var, Model *model)
const BooleanVariable kNoBooleanVariable(-1)
bool LinearizedPartIsLarge(Model *model)
std::function< BooleanOrIntegerLiteral()> PseudoCost(Model *model)
Collection of objects used to extend the Constraint Solver library.
Literal literal
Definition: optimization.cc:89
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::vector< std::function< BooleanOrIntegerLiteral()> > decision_policies