Google OR-Tools v9.11
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
integer_search.h
Go to the documentation of this file.
1// Copyright 2010-2024 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/types/span.h"
33#include "ortools/sat/clause.h"
34#include "ortools/sat/cp_model.pb.h"
36#include "ortools/sat/integer.h"
37#include "ortools/sat/model.h"
38#include "ortools/sat/probing.h"
42#include "ortools/sat/sat_parameters.pb.h"
45#include "ortools/sat/util.h"
48
49namespace operations_research {
50namespace sat {
51
52// This is used to hold the next decision the solver will take. It is either
53// a pure Boolean literal decision or correspond to an IntegerLiteral one.
54//
55// At most one of the two options should be set.
71
72// Model struct that contains the search heuristics used to find a feasible
73// solution to an integer problem.
74//
75// This is reset by ConfigureSearchHeuristics() and used by
76// SolveIntegerProblem(), see below.
78 // Decision and restart heuristics. The two vectors must be of the same size
79 // and restart_policies[i] will always be used in conjunction with
80 // decision_policies[i].
81 std::vector<std::function<BooleanOrIntegerLiteral()>> decision_policies;
82 std::vector<std::function<bool()>> restart_policies;
83
84 // Index in the vectors above that indicate the current configuration.
86
87 // Special decision functions that are constructed at loading time.
88 // These are used by ConfigureSearchHeuristics() to fill the policies above.
89
90 // Contains the search specified by the user in CpModelProto.
91 std::function<BooleanOrIntegerLiteral()> user_search = nullptr;
92
93 // Heuristic search build after introspecting the model. It can be used as
94 // a replacement of the user search. This can include dedicated scheduling or
95 // routing heuristics.
96 std::function<BooleanOrIntegerLiteral()> heuristic_search = nullptr;
97
98 // Default integer heuristic that will fix all integer variables.
100
101 // Fixed search, built from above building blocks.
102 std::function<BooleanOrIntegerLiteral()> fixed_search = nullptr;
103
104 // The search heuristic aims at following the given hint with minimum
105 // deviation.
106 std::function<BooleanOrIntegerLiteral()> hint_search = nullptr;
107
108 // Some search strategy need to take more than one decision at once. They can
109 // set this function that will be called on the next decision. It will be
110 // automatically deleted the first time it returns an empty decision.
112};
113
114// Given a base "fixed_search" function that should mainly control in which
115// order integer variables are lazily instantiated (and at what value), this
116// uses the current solver parameters to set the SearchHeuristics class in the
117// given model.
119
120// Callbacks that will be called when the search goes back to level 0.
121// Callbacks should return false if the propagation fails.
123 std::vector<std::function<bool()>> callbacks;
124};
125
126// Resets the solver to the given assumptions before calling
127// SolveIntegerProblem().
129 const std::vector<Literal>& assumptions, Model* model);
130
131// Only used in tests. Move to a test utility file.
132//
133// This configures the model SearchHeuristics with a simple default heuristic
134// and then call ResetAndSolveIntegerProblem() without any assumptions.
136
137// Returns decision corresponding to var at its lower bound.
138// Returns an invalid literal if the variable is fixed.
139IntegerLiteral AtMinValue(IntegerVariable var, IntegerTrail* integer_trail);
140
141// If a variable appear in the objective, branch on its best objective value.
143
144// Returns decision corresponding to var >= lb + max(1, (ub - lb) / 2). It also
145// CHECKs that the variable is not fixed.
147 IntegerTrail* integer_trail);
148
149// This method first tries var <= value. If this does not reduce the domain it
150// tries var >= value. If that also does not reduce the domain then returns
151// an invalid literal.
152IntegerLiteral SplitAroundGivenValue(IntegerVariable var, IntegerValue value,
153 Model* model);
154
155// Returns decision corresponding to var <= round(lp_value). If the variable
156// does not appear in the LP, this method returns an invalid literal.
158
159// Returns decision corresponding to var <= best_solution[var]. If no solution
160// has been found, this method returns a literal with kNoIntegerVariable. This
161// was suggested in paper: "Solution-Based Phase Saving for CP" (2018) by Emir
162// Demirovic, Geoffrey Chu, and Peter J. Stuckey.
164 Model* model);
165
166// Decision heuristic for SolveIntegerProblemWithLazyEncoding(). Returns a
167// function that will return the literal corresponding to the fact that the
168// first currently non-fixed variable value is <= its min. The function will
169// return kNoLiteralIndex if all the given variables are fixed.
170//
171// Note that this function will create the associated literal if needed.
173 const std::vector<IntegerVariable>& vars, Model* model);
174
175// Choose the variable with most fractional LP value.
177
178// Variant used for LbTreeSearch experimentation. Note that each decision is in
179// O(num_variables), but it is kind of ok with LbTreeSearch as we only call this
180// for "new" decision, not when we move around in the tree.
183
184// Decision heuristic for SolveIntegerProblemWithLazyEncoding(). Like
185// FirstUnassignedVarAtItsMinHeuristic() but the function will return the
186// literal corresponding to the fact that the currently non-assigned variable
187// with the lowest min has a value <= this min.
188std::function<BooleanOrIntegerLiteral()>
190 const std::vector<IntegerVariable>& vars, Model* model);
191
192// Set the first unassigned Literal/Variable to its value.
193//
194// TODO(user): This is currently quadratic as we scan all variables to find the
195// first unassigned one. Fix. Note that this is also the case in many other
196// heuristics and should be fixed.
198 BooleanVariable bool_var = kNoBooleanVariable;
199 IntegerVariable int_var = kNoIntegerVariable;
200};
201std::function<BooleanOrIntegerLiteral()> FollowHint(
202 const std::vector<BooleanOrIntegerVariable>& vars,
203 const std::vector<IntegerValue>& values, Model* model);
204
205// Combines search heuristics in order: if the i-th one returns kNoLiteralIndex,
206// ask the (i+1)-th. If every heuristic returned kNoLiteralIndex,
207// returns kNoLiteralIndex.
209 std::vector<std::function<BooleanOrIntegerLiteral()>> heuristics);
210
211// Changes the value of the given decision by 'var_selection_heuristic'. We try
212// to see if the decision is "associated" with an IntegerVariable, and if it is
213// the case, we choose the new value by the first 'value_selection_heuristics'
214// that is applicable. If none of the heuristics are applicable then the given
215// decision by 'var_selection_heuristic' is returned.
217 std::vector<std::function<IntegerLiteral(IntegerVariable)>>
218 value_selection_heuristics,
219 std::function<BooleanOrIntegerLiteral()> var_selection_heuristic,
220 Model* model);
221
222// Changes the value of the given decision by 'var_selection_heuristic'
223// according to various value selection heuristics. Looks at the code to know
224// exactly what heuristic we use.
226 std::function<BooleanOrIntegerLiteral()> var_selection_heuristic,
227 Model* model);
228
229// Returns the BooleanOrIntegerLiteral advised by the underlying SAT solver.
231
232// Gets the branching variable using pseudo costs and combines it with a value
233// for branching.
235
236// Simple scheduling heuristic that looks at all the no-overlap constraints
237// and try to assign and perform the intervals that can be scheduled first.
239 Model* model);
240
241// Compared to SchedulingSearchHeuristic() this one take decision on precedences
242// between tasks. Lazily creating a precedence Boolean for the task in
243// disjunction.
244//
245// Note that this one is meant to be used when all Boolean has been fixed, so
246// more as a "completion" heuristic rather than a fixed search one.
248 Model* model);
250 Model* model);
251
252// Returns true if the number of variables in the linearized part represent
253// a large enough proportion of all the problem variables.
255
256// A restart policy that restarts every k failures.
257std::function<bool()> RestartEveryKFailures(int k, SatSolver* solver);
258
259// A restart policy that uses the underlying sat solver's policy.
260std::function<bool()> SatSolverRestartPolicy(Model* model);
261
262// Concatenates each input_heuristic with a default heuristic that instantiate
263// all the problem's Boolean variables, into a new vector.
264std::vector<std::function<BooleanOrIntegerLiteral()>> CompleteHeuristics(
265 absl::Span<const std::function<BooleanOrIntegerLiteral()>>
266 incomplete_heuristics,
267 const std::function<BooleanOrIntegerLiteral()>& completion_heuristic);
268
269// An helper class to share the code used by the different kind of search.
271 public:
273
274 // Executes some code before a new decision.
275 // Returns false if model is UNSAT.
277
278 // Calls the decision heuristics and extract a non-fixed literal.
279 // Note that we do not want to copy the function here.
280 //
281 // Returns false if a conflict was found while trying to take a decision.
282 bool GetDecision(const std::function<BooleanOrIntegerLiteral()>& f,
283 LiteralIndex* decision);
284
285 // Inner function used by GetDecision().
286 // It will create a new associated literal if needed.
287 LiteralIndex GetDecisionLiteral(const BooleanOrIntegerLiteral& decision);
288
289 // Functions passed to GetDecision() might call this to notify a conflict
290 // was detected.
292 must_process_conflict_ = true;
293 }
294
295 // Tries to take the current decision, this might backjump.
296 // Returns false if the model is UNSAT.
297 bool TakeDecision(Literal decision);
298
299 // Tries to find a feasible solution to the current model.
300 //
301 // This function continues from the current state of the solver and loop until
302 // all variables are instantiated (i.e. the next decision is kNoLiteralIndex)
303 // or a search limit is reached. It uses the heuristic from the
304 // SearchHeuristics class in the model to decide when to restart and what next
305 // decision to take.
306 //
307 // Each time a restart happen, this increment the policy index modulo the
308 // number of heuristics to act as a portfolio search.
310
311 private:
312 const SatParameters& parameters_;
313 Model* model_;
314 SatSolver* sat_solver_;
315 IntegerTrail* integer_trail_;
316 IntegerEncoder* encoder_;
317 ImpliedBounds* implied_bounds_;
318 Prober* prober_;
319 ProductDetector* product_detector_;
320 TimeLimit* time_limit_;
321 PseudoCosts* pseudo_costs_;
322 Inprocessing* inprocessing_;
323
324 bool must_process_conflict_ = false;
325};
326
327// This class will loop continuously on model variables and try to probe/shave
328// its bounds.
330 public:
331 // The model_proto is just used to construct the lists of variable to probe.
332 ContinuousProber(const CpModelProto& model_proto, Model* model);
333
334 // Starts or continues probing variables and their bounds.
335 // It returns:
336 // - SatSolver::INFEASIBLE if the problem is proven infeasible.
337 // - SatSolver::FEASIBLE when a feasible solution is found
338 // - SatSolver::LIMIT_REACHED if the limit stored in the model is reached
339 // Calling Probe() after it has returned FEASIBLE or LIMIT_REACHED will resume
340 // probing from its previous state.
342
343 private:
344 static const int kTestLimitPeriod = 20;
345 static const int kLogPeriod = 1000;
346 static const int kSyncPeriod = 50;
347
348 SatSolver::Status ShaveLiteral(Literal literal);
349 bool ReportStatus(SatSolver::Status status);
350 void LogStatistics();
351 SatSolver::Status PeriodicSyncAndCheck();
352
353 // Variables to probe.
354 std::vector<BooleanVariable> bool_vars_;
355 std::vector<IntegerVariable> int_vars_;
356
357 // Model object.
358 Model* model_;
359 SatSolver* sat_solver_;
360 TimeLimit* time_limit_;
361 BinaryImplicationGraph* binary_implication_graph_;
362 ClauseManager* clause_manager_;
363 Trail* trail_;
364 IntegerTrail* integer_trail_;
365 IntegerEncoder* encoder_;
366 Inprocessing* inprocessing_;
367 const SatParameters parameters_;
368 LevelZeroCallbackHelper* level_zero_callbacks_;
369 Prober* prober_;
370 SharedResponseManager* shared_response_manager_;
371 SharedBoundsManager* shared_bounds_manager_;
372 ModelRandomGenerator* random_;
373
374 // Statistics.
375 int64_t num_literals_probed_ = 0;
376 int64_t num_bounds_shaved_ = 0;
377 int64_t num_bounds_tried_ = 0;
378 int64_t num_at_least_one_probed_ = 0;
379 int64_t num_at_most_one_probed_ = 0;
380
381 // Period counters;
382 int num_logs_remaining_ = 0;
383 int num_syncs_remaining_ = 0;
384 int num_test_limit_remaining_ = 0;
385
386 // Shaving management.
387 bool use_shaving_ = false;
388 int trail_index_at_start_of_iteration_ = 0;
389 int integer_trail_index_at_start_of_iteration_ = 0;
390
391 // Current state of the probe.
392 double active_limit_;
393 // TODO(user): use 2 vector<bool>.
394 absl::flat_hash_set<BooleanVariable> probed_bool_vars_;
395 absl::flat_hash_set<LiteralIndex> shaved_literals_;
396 int iteration_ = 1;
397 int current_int_var_ = 0;
398 int current_bool_var_ = 0;
399 int current_bv1_ = 0;
400 int current_bv2_ = 0;
401 int random_pair_of_bool_vars_probed_ = 0;
402 int random_triplet_of_bool_vars_probed_ = 0;
403 std::vector<std::vector<Literal>> tmp_dnf_;
404 std::vector<Literal> tmp_literals_;
405};
406
407} // namespace sat
408} // namespace operations_research
409
410#endif // OR_TOOLS_SAT_INTEGER_SEARCH_H_
ContinuousProber(const CpModelProto &model_proto, Model *model)
The model_proto is just used to construct the lists of variable to probe.
An helper class to share the code used by the different kind of search.
LiteralIndex GetDecisionLiteral(const BooleanOrIntegerLiteral &decision)
bool GetDecision(const std::function< BooleanOrIntegerLiteral()> &f, LiteralIndex *decision)
int64_t value
IntVar * var
absl::Status status
Definition g_gurobi.cc:44
GRBmodel * model
int literal
int index
void ConfigureSearchHeuristics(Model *model)
const LiteralIndex kNoLiteralIndex(-1)
std::function< BooleanOrIntegerLiteral()> DisjunctivePrecedenceSearchHeuristic(Model *model)
std::vector< std::function< BooleanOrIntegerLiteral()> > CompleteHeuristics(absl::Span< const std::function< BooleanOrIntegerLiteral()> > incomplete_heuristics, const std::function< BooleanOrIntegerLiteral()> &completion_heuristic)
std::function< BooleanOrIntegerLiteral()> BoolPseudoCostHeuristic(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()> IntegerValueSelectionHeuristic(std::function< BooleanOrIntegerLiteral()> var_selection_heuristic, Model *model)
IntegerLiteral SplitAroundLpValue(IntegerVariable var, Model *model)
const IntegerVariable kNoIntegerVariable(-1)
IntegerLiteral AtMinValue(IntegerVariable var, IntegerTrail *integer_trail)
SatSolver::Status SolveIntegerProblemWithLazyEncoding(Model *model)
std::function< BooleanOrIntegerLiteral()> PseudoCost(Model *model)
std::function< BooleanOrIntegerLiteral()> SchedulingSearchHeuristic(Model *model)
A simple heuristic for scheduling models.
IntegerLiteral SplitDomainUsingBestSolutionValue(IntegerVariable var, Model *model)
std::function< BooleanOrIntegerLiteral()> FirstUnassignedVarAtItsMinHeuristic(const std::vector< IntegerVariable > &vars, Model *model)
std::function< BooleanOrIntegerLiteral()> SatSolverHeuristic(Model *model)
Returns the BooleanOrIntegerLiteral advised by the underlying SAT solver.
std::function< bool()> RestartEveryKFailures(int k, SatSolver *solver)
A restart policy that restarts every k failures.
bool LinearizedPartIsLarge(Model *model)
IntegerLiteral SplitAroundGivenValue(IntegerVariable var, IntegerValue value, Model *model)
IntegerLiteral ChooseBestObjectiveValue(IntegerVariable var, Model *model)
If a variable appear in the objective, branch on its best objective value.
const BooleanVariable kNoBooleanVariable(-1)
SatSolver::Status ResetAndSolveIntegerProblem(const std::vector< Literal > &assumptions, Model *model)
std::function< bool()> SatSolverRestartPolicy(Model *model)
A restart policy that uses the underlying sat solver's policy.
std::function< BooleanOrIntegerLiteral()> LpPseudoCostHeuristic(Model *model)
IntegerLiteral GreaterOrEqualToMiddleValue(IntegerVariable var, IntegerTrail *integer_trail)
std::function< BooleanOrIntegerLiteral()> MostFractionalHeuristic(Model *model)
Choose the variable with most fractional LP value.
std::function< BooleanOrIntegerLiteral()> CumulativePrecedenceSearchHeuristic(Model *model)
std::function< BooleanOrIntegerLiteral()> UnassignedVarWithLowestMinAtItsMinHeuristic(const std::vector< IntegerVariable > &vars, Model *model)
std::function< BooleanOrIntegerLiteral()> FollowHint(const std::vector< BooleanOrIntegerVariable > &vars, const std::vector< IntegerValue > &values, Model *model)
std::function< BooleanOrIntegerLiteral()> SequentialSearch(std::vector< std::function< BooleanOrIntegerLiteral()> > heuristics)
In SWIG mode, we don't want anything besides these top-level includes.
std::vector< std::function< bool()> > callbacks
std::function< BooleanOrIntegerLiteral()> fixed_search
Fixed search, built from above building blocks.
std::function< BooleanOrIntegerLiteral()> heuristic_search
std::vector< std::function< bool()> > restart_policies
std::function< BooleanOrIntegerLiteral()> user_search
Contains the search specified by the user in CpModelProto.
std::vector< std::function< BooleanOrIntegerLiteral()> > decision_policies
std::function< BooleanOrIntegerLiteral()> hint_search
std::function< BooleanOrIntegerLiteral()> next_decision_override
std::function< BooleanOrIntegerLiteral()> integer_completion_search
Default integer heuristic that will fix all integer variables.
int policy_index
Index in the vectors above that indicate the current configuration.