OR-Tools  9.3
optimization.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#ifndef OR_TOOLS_SAT_OPTIMIZATION_H_
15#define OR_TOOLS_SAT_OPTIMIZATION_H_
16
17#include <functional>
18#include <vector>
19
20#include "absl/random/bit_gen_ref.h"
21#include "ortools/sat/boolean_problem.pb.h"
23#include "ortools/sat/integer.h"
25#include "ortools/sat/model.h"
28#include "ortools/sat/sat_parameters.pb.h"
31
32namespace operations_research {
33namespace sat {
34
35// Like MinimizeCore() with a slower but strictly better heuristic. This
36// algorithm should produce a minimal core with respect to propagation. We put
37// each literal of the initial core "last" at least once, so if such literal can
38// be inferred by propagation by any subset of the other literal, it will be
39// removed.
40//
41// Note that the literal of the minimized core will stay in the same order.
42//
43// TODO(user): Avoid spending too much time trying to minimize a core.
44void MinimizeCoreWithPropagation(TimeLimit* limit, SatSolver* solver,
45 std::vector<Literal>* core);
46
47// Because the Solve*() functions below are also used in scripts that requires a
48// special output format, we use this to tell them whether or not to use the
49// default logging framework or simply stdout. Most users should just use
50// DEFAULT_LOG.
52
53// All the Solve*() functions below reuse the SatSolver::Status with a slightly
54// different meaning:
55// - FEASIBLE: The problem has been solved to optimality.
56// - INFEASIBLE: Same meaning, the decision version is already unsat.
57// - LIMIT_REACHED: we may have some feasible solution (if solution is
58// non-empty), but the optimality is not proven.
59
60// Implements the "Fu & Malik" algorithm described in:
61// Zhaohui Fu, Sharad Malik, "On solving the Partial MAX-SAT problem", 2006,
62// International Conference on Theory and Applications of Satisfiability
63// Testing. (SAT’06), LNCS 4121.
64//
65// This algorithm requires all the objective weights to be the same (CHECKed)
66// and currently only works on minimization problems. The problem is assumed to
67// be already loaded into the given solver.
68//
69// TODO(user): double-check the correctness if the objective coefficients are
70// negative.
72 const LinearBooleanProblem& problem,
73 SatSolver* solver,
74 std::vector<bool>* solution);
75
76// The WPM1 algorithm is a generalization of the Fu & Malik algorithm to
77// weighted problems. Note that if all objective weights are the same, this is
78// almost the same as SolveWithFuMalik() but the encoding of the constraints is
79// slightly different.
80//
81// Ansotegui, C., Bonet, M.L., Levy, J.: Solving (weighted) partial MaxSAT
82// through satisfiability testing. In: Proc. of the 12th Int. Conf. on Theory and
83// Applications of Satisfiability Testing (SAT’09). pp. 427-440 (2009)
85 const LinearBooleanProblem& problem,
86 SatSolver* solver, std::vector<bool>* solution);
87
88// Solves num_times the decision version of the given problem with different
89// random parameters. Keep the best solution (regarding the objective) and
90// returns it in solution. The problem is assumed to be already loaded into the
91// given solver.
93 LogBehavior log, const LinearBooleanProblem& problem, int num_times,
94 absl::BitGenRef random, SatSolver* solver, std::vector<bool>* solution);
95
96// Starts by solving the decision version of the given LinearBooleanProblem and
97// then simply add a constraint to find a lower objective that the current best
98// solution and repeat until the problem becomes unsat.
99//
100// The problem is assumed to be already loaded into the given solver. If
101// solution is initially a feasible solution, the search will starts from there.
102// solution will be updated with the best solution found so far.
104 const LinearBooleanProblem& problem,
105 SatSolver* solver,
106 std::vector<bool>* solution);
107
108// Similar algorithm as the one used by qmaxsat, this is a linear scan with the
109// at-most k constraint encoded in SAT. This only works on problems with
110// constant weights.
112 LogBehavior log, const LinearBooleanProblem& problem, SatSolver* solver,
113 std::vector<bool>* solution);
114
115// This is an original algorithm. It is a mix between the cardinality encoding
116// and the Fu & Malik algorithm. It also works on general weighted instances.
118 LogBehavior log, const LinearBooleanProblem& problem, SatSolver* solver,
119 std::vector<bool>* solution);
120
121// Model-based API to minimize a given IntegerVariable by solving a sequence of
122// decision problem. Each problem is solved using SolveIntegerProblem(). Returns
123// the status of the last solved decision problem.
124//
125// The feasible_solution_observer function will be called each time a new
126// feasible solution is found.
127//
128// Note that this function will resume the search from the current state of the
129// solver, and it is up to the client to backtrack to the root node if needed.
131 IntegerVariable objective_var,
132 const std::function<void()>& feasible_solution_observer, Model* model);
133
134// Use a low conflict limit and performs a binary search to try to restrict the
135// domain of objective_var.
137 IntegerVariable objective_var,
138 const std::function<void()>& feasible_solution_observer, Model* model);
139
140// Same as MinimizeIntegerVariableWithLinearScanAndLazyEncoding() but use
141// a core-based approach instead. Note that the given objective_var is just used
142// for reporting the lower-bound/upper-bound and do not need to be linked with
143// its linear representation.
144//
145// Unlike MinimizeIntegerVariableWithLinearScanAndLazyEncoding() this function
146// just return the last solver status. In particular if it is INFEASIBLE but
147// feasible_solution_observer() was called, it means we are at OPTIMAL.
149 public:
150 CoreBasedOptimizer(IntegerVariable objective_var,
151 const std::vector<IntegerVariable>& variables,
152 const std::vector<IntegerValue>& coefficients,
153 std::function<void()> feasible_solution_observer,
154 Model* model);
155
156 // TODO(user): Change the algo slighlty to allow resuming from the last
157 // aborted position. Currently, the search is "resumable", but it will restart
158 // some of the work already done, so it might just never find anything.
160
161 // A different way to encode the objective as core are found. This one do
162 // not introduce IntegerVariable and encode everything in Boolean.
163 //
164 // It seems to be more powerful, but it isn't completely implemented yet.
165 // TODO(user):
166 // - Make it work for integer variable in the objective.
167 // - Only call it if the objective domain is not too large?
168 // - Support resuming for interleaved search.
169 // - Implement all core heurisitics.
171 const std::vector<Literal>& literals,
172 const std::vector<Coefficient>& coefficients, Coefficient offset);
173
174 private:
175 CoreBasedOptimizer(const CoreBasedOptimizer&) = delete;
176 CoreBasedOptimizer& operator=(const CoreBasedOptimizer&) = delete;
177
178 struct ObjectiveTerm {
179 IntegerVariable var;
180 IntegerValue weight;
181 int depth; // Only for logging/debugging.
182 IntegerValue old_var_lb;
183
184 // An upper bound on the optimal solution if we were to optimize only this
185 // term. This is used by the cover optimization code.
186 IntegerValue cover_ub;
187 };
188
189 // This will be called each time a feasible solution is found. Returns false
190 // if a conflict was detected while trying to constrain the objective to a
191 // smaller value.
192 bool ProcessSolution();
193
194 // Use the gap an implied bounds to propagated the bounds of the objective
195 // variables and of its terms.
196 bool PropagateObjectiveBounds();
197
198 // Heuristic that aim to find the "real" lower bound of the objective on each
199 // core by using a linear scan optimization approach.
200 bool CoverOptimization();
201
202 // Computes the next stratification threshold.
203 // Sets it to zero if all the assumptions where already considered.
204 void ComputeNextStratificationThreshold();
205
206 // If we have an "at most one can be false" between literals with a positive
207 // cost, you then know that at least n - 1 will contribute to the cost, and
208 // you can increase the objective lower bound. This is the same as having
209 // a real "at most one" constraint on the negation of such literals.
210 //
211 // This detects such "at most ones" and rewrite the objective accordingly.
212 // For each at most one, the rewrite create a new Boolean variable and update
213 // the cost so that the trivial objective lower bound reflect the increase.
214 //
215 // TODO(user) : Code that as a general presolve rule? I am not sure adding
216 // the extra Booleans is always a good idea though. Especially since the LP
217 // will see the same lower bound that what is computed by this.
218 void PresolveObjectiveWithAtMostOne(std::vector<Literal>* literals,
219 std::vector<Coefficient>* coefficients,
220 Coefficient* offset);
221
222 SatParameters* parameters_;
223 SatSolver* sat_solver_;
224 TimeLimit* time_limit_;
225 BinaryImplicationGraph* implications_;
226 IntegerTrail* integer_trail_;
227 IntegerEncoder* integer_encoder_;
228 Model* model_;
229
230 IntegerVariable objective_var_;
231 std::vector<ObjectiveTerm> terms_;
232 IntegerValue stratification_threshold_;
233 std::function<void()> feasible_solution_observer_;
234
235 // This is used to not add the objective equation more than once if we
236 // solve in "chunk".
237 bool already_switched_to_linear_scan_ = false;
238
239 // Set to true when we need to abort early.
240 //
241 // TODO(user): This is only used for the stop after first solution parameter
242 // which should likely be handled differently by simply using the normal way
243 // to stop a solver from the feasible solution callback.
244 bool stop_ = false;
245};
246
247} // namespace sat
248} // namespace operations_research
249
250#endif // OR_TOOLS_SAT_OPTIMIZATION_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
CoreBasedOptimizer(IntegerVariable objective_var, const std::vector< IntegerVariable > &variables, const std::vector< IntegerValue > &coefficients, std::function< void()> feasible_solution_observer, Model *model)
SatSolver::Status OptimizeWithSatEncoding(const std::vector< Literal > &literals, const std::vector< Coefficient > &coefficients, Coefficient offset)
Class that owns everything related to a particular optimization model.
Definition: sat/model.h:42
IntVar * var
Definition: expr_array.cc:1874
absl::Span< const double > coefficients
GRBmodel * model
std::tuple< int64_t, int64_t, const double > Coefficient
void RestrictObjectiveDomainWithBinarySearch(IntegerVariable objective_var, const std::function< void()> &feasible_solution_observer, Model *model)
SatSolver::Status SolveWithCardinalityEncodingAndCore(LogBehavior log, const LinearBooleanProblem &problem, SatSolver *solver, std::vector< bool > *solution)
SatSolver::Status SolveWithLinearScan(LogBehavior log, const LinearBooleanProblem &problem, SatSolver *solver, std::vector< bool > *solution)
SatSolver::Status SolveWithRandomParameters(LogBehavior log, const LinearBooleanProblem &problem, int num_times, absl::BitGenRef random, SatSolver *solver, std::vector< bool > *solution)
SatSolver::Status SolveWithWPM1(LogBehavior log, const LinearBooleanProblem &problem, SatSolver *solver, std::vector< bool > *solution)
void MinimizeCoreWithPropagation(TimeLimit *limit, SatSolver *solver, std::vector< Literal > *core)
SatSolver::Status SolveWithFuMalik(LogBehavior log, const LinearBooleanProblem &problem, SatSolver *solver, std::vector< bool > *solution)
SatSolver::Status SolveWithCardinalityEncoding(LogBehavior log, const LinearBooleanProblem &problem, SatSolver *solver, std::vector< bool > *solution)
SatSolver::Status MinimizeIntegerVariableWithLinearScanAndLazyEncoding(IntegerVariable objective_var, const std::function< void()> &feasible_solution_observer, Model *model)
Collection of objects used to extend the Constraint Solver library.
int64_t weight
Definition: pack.cc:510