OR-Tools  9.2
cp_model_presolve.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_CP_MODEL_PRESOLVE_H_
15#define OR_TOOLS_SAT_CP_MODEL_PRESOLVE_H_
16
17#include <cstdint>
18#include <vector>
19
26#include "ortools/util/bitset.h"
29
30namespace operations_research {
31namespace sat {
32
33// Replaces all the instance of a variable i (and the literals referring to it)
34// by mapping[i]. The definition of variables i is also moved to its new index.
35// Variables with a negative mapping value are ignored and it is an error if
36// such variable is referenced anywhere (this is CHECKed).
37//
38// The image of the mapping should be dense in [0, new_num_variables), this is
39// also CHECKed.
40void ApplyVariableMapping(const std::vector<int>& mapping,
41 const PresolveContext& context);
42
43// Presolves the initial content of presolved_model.
44//
45// This also creates a mapping model that encode the correspondence between the
46// two problems. This works as follow:
47// - The first variables of mapping_model are in one to one correspondence with
48// the variables of the initial model.
49// - The presolved_model variables are in one to one correspondence with the
50// variable at the indices given by postsolve_mapping in the mapping model.
51// - Fixing one of the two sets of variables and solving the model will assign
52// the other set to a feasible solution of the other problem. Moreover, the
53// objective value of these solutions will be the same. Note that solving such
54// problems will take little time in practice because the propagation will
55// basically do all the work.
56//
57// Note(user): an optimization model can be transformed into a decision problem,
58// if for instance the objective is fixed, or independent from the rest of the
59// problem.
60//
61// TODO(user): Identify disconnected components and returns a vector of
62// presolved model? If we go this route, it may be nicer to store the indices
63// inside the model. We can add a IntegerVariableProto::initial_index;
65 public:
67 std::vector<int>* postsolve_mapping);
68
69 // We returns the status of the problem after presolve:
70 // - UNKNOWN if everything was ok.
71 // - INFEASIBLE if the model was proven so during presolve
72 // - MODEL_INVALID if the model caused some issues, like if we are not able
73 // to scale a floating point objective with enough precision.
75
76 // Executes presolve method for the given constraint. Public for testing only.
77 bool PresolveOneConstraint(int c);
78
79 // Public for testing only.
81
82 private:
83 // A simple helper that logs the rules applied so far and return INFEASIBLE.
84 CpSolverStatus InfeasibleStatus();
85
86 // Runs the inner loop of the presolver.
87 void PresolveToFixPoint();
88
89 // Runs the probing.
90 void Probe();
91
92 // Presolve functions.
93 //
94 // They should return false only if the constraint <-> variable graph didn't
95 // change. This is just an optimization, returning true is always correct.
96 //
97 // Invariant about UNSAT: All these functions should abort right away if
98 // context_.IsUnsat() is true. And the only way to change the status to unsat
99 // is through ABSL_MUST_USE_RESULT function that should also abort right away
100 // the current code. This way we shouldn't keep doing computation on an
101 // inconsistent state.
102 // TODO(user): Make these public and unit test.
103 bool PresolveAllDiff(ConstraintProto* ct);
104 bool PresolveAutomaton(ConstraintProto* ct);
105 bool PresolveElement(ConstraintProto* ct);
106 bool PresolveIntAbs(ConstraintProto* ct);
107 bool PresolveIntDiv(ConstraintProto* ct);
108 bool PresolveIntMod(ConstraintProto* ct);
109 bool PresolveIntProd(ConstraintProto* ct);
110 bool PresolveInterval(int c, ConstraintProto* ct);
111 bool PresolveInverse(ConstraintProto* ct);
112 bool PresolveLinMax(ConstraintProto* ct);
113 bool PresolveTable(ConstraintProto* ct);
114
115 bool PresolveCumulative(ConstraintProto* ct);
116 bool PresolveNoOverlap(ConstraintProto* ct);
117 bool PresolveNoOverlap2D(int c, ConstraintProto* ct);
118 bool PresolveReservoir(ConstraintProto* ct);
119
120 bool PresolveCircuit(ConstraintProto* ct);
121 bool PresolveRoutes(ConstraintProto* ct);
122
123 bool PresolveAtMostOrExactlyOne(ConstraintProto* ct);
124 bool PresolveAtMostOne(ConstraintProto* ct);
125 bool PresolveExactlyOne(ConstraintProto* ct);
126
127 bool PresolveBoolAnd(ConstraintProto* ct);
128 bool PresolveBoolOr(ConstraintProto* ct);
129 bool PresolveBoolXor(ConstraintProto* ct);
130 bool PresolveEnforcementLiteral(ConstraintProto* ct);
131
132 // Regroups terms and substitute affine relations.
133 // Returns true if the set of variables in the expression changed.
134 template <typename ProtoWithVarsAndCoeffs>
135 bool CanonicalizeLinearExpressionInternal(const ConstraintProto& ct,
136 ProtoWithVarsAndCoeffs* proto,
137 int64_t* offset);
138 bool CanonicalizeLinearExpression(const ConstraintProto& ct,
140 bool CanonicalizeLinearArgument(const ConstraintProto& ct,
142
143 // For the linear constraints, we have more than one function.
144 bool CanonicalizeLinear(ConstraintProto* ct);
145 bool PropagateDomainsInLinear(int c, ConstraintProto* ct);
146 bool RemoveSingletonInLinear(ConstraintProto* ct);
147 bool PresolveSmallLinear(ConstraintProto* ct);
148 bool PresolveLinearOfSizeOne(ConstraintProto* ct);
149 bool PresolveLinearOfSizeTwo(ConstraintProto* ct);
150 bool PresolveLinearOnBooleans(ConstraintProto* ct);
151 bool AddVarAffineRepresentativeFromLinearEquality(int target_index,
153 bool PresolveLinearEqualityWithModulo(ConstraintProto* ct);
154
155 bool DetectAndProcessOneSidedLinearConstraint(int c, ConstraintProto* ct);
156
157 // SetPPC is short for set packing, partitioning and covering constraints.
158 // These are sum of booleans <=, = and >= 1 respectively.
159 bool ProcessSetPPC();
160
161 // This detects and converts constraints of the form:
162 // "X = sum Boolean * value", with "sum Boolean <= 1".
163 //
164 // Note that it is not super fast, so it shouldn't be called too often.
165 void ExtractEncodingFromLinear();
166 bool ProcessEncodingFromLinear(int linear_encoding_ct_index,
167 const ConstraintProto& at_most_or_exactly_one,
168 int64_t* num_unique_terms,
169 int64_t* num_multiple_terms);
170
171 // Removes dominated constraints or fixes some variables for given pair of
172 // setppc constraints. This assumes that literals in constraint c1 is subset
173 // of literals in constraint c2.
174 bool ProcessSetPPCSubset(int c1, int c2, const std::vector<int>& c2_minus_c1,
175 const std::vector<int>& original_constraint_index,
176 std::vector<bool>* marked_for_removal);
177
178 void PresolvePureSatPart();
179
180 // Extracts AtMostOne constraint from Linear constraint.
181 void ExtractAtMostOneFromLinear(ConstraintProto* ct);
182
183 // Returns true if the constraint changed.
184 bool DivideLinearByGcd(ConstraintProto* ct);
185
186 void ExtractEnforcementLiteralFromLinearConstraint(int ct_index,
188
189 // Extracts cliques from bool_and and small at_most_one constraints and
190 // transforms them into maximal cliques.
191 void TransformIntoMaxCliques();
192
193 // Converts bool_or and at_most_one of size 2 to bool_and.
194 void ExtractBoolAnd();
195
196 void ExpandObjective();
197
198 void TryToSimplifyDomain(int var);
199
200 void MergeNoOverlapConstraints();
201
202 // Boths function are responsible for dealing with affine relations.
203 // The second one returns false on UNSAT.
204 void EncodeAllAffineRelations();
205 bool PresolveAffineRelationIfAny(int var);
206
207 bool ExploitEquivalenceRelations(int c, ConstraintProto* ct);
208
209 ABSL_MUST_USE_RESULT bool RemoveConstraint(ConstraintProto* ct);
210 ABSL_MUST_USE_RESULT bool MarkConstraintAsFalse(ConstraintProto* ct);
211
212 std::vector<int>* postsolve_mapping_;
213 PresolveContext* context_;
214 SolverLogger* logger_;
215
216 // Used by CanonicalizeLinearExpressionInternal().
217 std::vector<std::pair<int, int64_t>> tmp_terms_;
218};
219
220// This helper class perform copy with simplification from a model and a
221// partial assignment to another model. The purpose is to miminize the size of
222// the copied model, as well as to reduce the pressure on the memory sub-system.
223//
224// It is currently used by the LNS part, but could be used with any other scheme
225// that generates partial assignments.
227 public:
229
230 // Copies all constraints from in_model to working model of the context.
231 //
232 // During the process, it will read variable domains from the context, and
233 // simplify constraints to minimize the size of the copied model.
234 // Thus it is important that the context->working_model already have the
235 // variables part copied.
236 //
237 // It returns false iff the model is proven infeasible.
238 //
239 // It does not clear the constraints part of the working model of the context.
240 //
241 // Note(user): If first_copy is true, we will reorder the scheduling
242 // constraint so that they only use reference to previously defined intervals.
243 // This allow to be more efficient later in a few preprocessing steps.
244 bool ImportAndSimplifyConstraints(const CpModelProto& in_model,
245 const std::vector<int>& ignored_constraints,
246 bool first_copy = false);
247
248 private:
249 // Overwrites the out_model to be unsat. Returns false.
250 bool CreateUnsatModel();
251
252 void CopyEnforcementLiterals(const ConstraintProto& orig,
253 ConstraintProto* dest);
254 bool OneEnforcementLiteralIsFalse(const ConstraintProto& ct) const;
255
256 // All these functions return false if the constraint is found infeasible.
257 bool CopyBoolOr(const ConstraintProto& ct);
258 bool CopyBoolAnd(const ConstraintProto& ct);
259 bool CopyLinear(const ConstraintProto& ct);
260 bool CopyAtMostOne(const ConstraintProto& ct);
261 bool CopyExactlyOne(const ConstraintProto& ct);
262 bool CopyInterval(const ConstraintProto& ct, int c);
263
264 // These function remove unperformed intervals. Note that they requires
265 // interval to appear before (validated) as they test unperformed by testing
266 // if interval_mapping_ is empty.
267 void CopyAndMapNoOverlap(const ConstraintProto& ct);
268 void CopyAndMapNoOverlap2D(const ConstraintProto& ct);
269 void CopyAndMapCumulative(const ConstraintProto& ct);
270
271 PresolveContext* context_;
272 int64_t skipped_non_zero_ = 0;
273
274 // Temp vectors.
275 std::vector<int> non_fixed_variables_;
276 std::vector<int64_t> non_fixed_coefficients_;
277 absl::flat_hash_map<int, int> interval_mapping_;
278 int starting_constraint_index_ = 0;
279 std::vector<int> temp_enforcement_literals_;
280 std::vector<int> temp_literals_;
281};
282
283// Import the constraints from the in_model to the presolve context.
284// It performs on the fly simplification, and returns false if the
285// model is proved infeasible.
286//
287// This should only be called on the first copy of the user given model.
288// Note that this reorder all constraints that use intervals last. We loose the
289// user-defined order, but hopefully that should not matter too much.
292
293// Copies the non constraint, non variables part of the model.
295 const CpModelProto& in_model, PresolveContext* context);
296
297// Convenient wrapper to call the full presolve.
299 std::vector<int>* postsolve_mapping);
300
301// Returns the index of duplicate constraints in the given proto in the first
302// element of each pair. The second element of each pair is the "representative"
303// that is the first constraint in the proto in a set of duplicate constraints.
304//
305// Empty constraints are ignored. We also do a bit more:
306// - We ignore names when comparing constraint.
307// - For linear constraints, we ignore the domain. This is because we can
308// just merge them if the constraints are the same.
309// - We return the special kObjectiveConstraint (< 0) representative if a linear
310// constraint is parallel to the objective and has no enforcement literals.
311// The domain of such constraint can just be merged with the objective domain.
312//
313// Visible here for testing. This is meant to be called at the end of the
314// presolve where constraints have been canonicalized.
315std::vector<std::pair<int, int>> FindDuplicateConstraints(
317
318} // namespace sat
319} // namespace operations_research
320
321#endif // OR_TOOLS_SAT_CP_MODEL_PRESOLVE_H_
CpModelPresolver(PresolveContext *context, std::vector< int > *postsolve_mapping)
bool ImportAndSimplifyConstraints(const CpModelProto &in_model, const std::vector< int > &ignored_constraints, bool first_copy=false)
CpModelProto proto
CpModelProto const * model_proto
const Constraint * ct
IntVar * var
Definition: expr_array.cc:1874
GurobiMPCallbackContext * context
void CopyEverythingExceptVariablesAndConstraintsFieldsIntoContext(const CpModelProto &in_model, PresolveContext *context)
bool ImportConstraintsWithBasicPresolveIntoContext(const CpModelProto &in_model, PresolveContext *context)
std::vector< std::pair< int, int > > FindDuplicateConstraints(const CpModelProto &model_proto)
CpSolverStatus PresolveCpModel(PresolveContext *context, std::vector< int > *postsolve_mapping)
void ApplyVariableMapping(const std::vector< int > &mapping, const PresolveContext &context)
Collection of objects used to extend the Constraint Solver library.