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 CanonicalizeLinMax(ConstraintProto* ct);
141
142 // For the linear constraints, we have more than one function.
143 bool CanonicalizeLinear(ConstraintProto* ct);
144 bool PropagateDomainsInLinear(int c, ConstraintProto* ct);
145 bool RemoveSingletonInLinear(ConstraintProto* ct);
146 bool PresolveSmallLinear(ConstraintProto* ct);
147 bool PresolveLinearOfSizeOne(ConstraintProto* ct);
148 bool PresolveLinearOfSizeTwo(ConstraintProto* ct);
149 bool PresolveLinearOnBooleans(ConstraintProto* ct);
150 bool AddVarAffineRepresentativeFromLinearEquality(int target_index,
152 bool PresolveLinearEqualityWithModulo(ConstraintProto* ct);
153
154 bool DetectAndProcessOneSidedLinearConstraint(int c, ConstraintProto* ct);
155
156 // SetPPC is short for set packing, partitioning and covering constraints.
157 // These are sum of booleans <=, = and >= 1 respectively.
158 bool ProcessSetPPC();
159
160 // This detects and converts constraints of the form:
161 // "X = sum Boolean * value", with "sum Boolean <= 1".
162 //
163 // Note that it is not super fast, so it shouldn't be called too often.
164 void ExtractEncodingFromLinear();
165 bool ProcessEncodingFromLinear(int linear_encoding_ct_index,
166 const ConstraintProto& at_most_or_exactly_one,
167 int64_t* num_unique_terms,
168 int64_t* num_multiple_terms);
169
170 // Removes dominated constraints or fixes some variables for given pair of
171 // setppc constraints. This assumes that literals in constraint c1 is subset
172 // of literals in constraint c2.
173 bool ProcessSetPPCSubset(int c1, int c2, const std::vector<int>& c2_minus_c1,
174 const std::vector<int>& original_constraint_index,
175 std::vector<bool>* marked_for_removal);
176
177 void PresolvePureSatPart();
178
179 // Extracts AtMostOne constraint from Linear constraint.
180 void ExtractAtMostOneFromLinear(ConstraintProto* ct);
181
182 // Returns true if the constraint changed.
183 bool DivideLinearByGcd(ConstraintProto* ct);
184
185 void ExtractEnforcementLiteralFromLinearConstraint(int ct_index,
187
188 // Extracts cliques from bool_and and small at_most_one constraints and
189 // transforms them into maximal cliques.
190 void TransformIntoMaxCliques();
191
192 // Converts bool_or and at_most_one of size 2 to bool_and.
193 void ExtractBoolAnd();
194
195 void ExpandObjective();
196
197 void TryToSimplifyDomain(int var);
198
199 void MergeNoOverlapConstraints();
200
201 // Boths function are responsible for dealing with affine relations.
202 // The second one returns false on UNSAT.
203 void EncodeAllAffineRelations();
204 bool PresolveAffineRelationIfAny(int var);
205
206 bool ExploitEquivalenceRelations(int c, ConstraintProto* ct);
207
208 ABSL_MUST_USE_RESULT bool RemoveConstraint(ConstraintProto* ct);
209 ABSL_MUST_USE_RESULT bool MarkConstraintAsFalse(ConstraintProto* ct);
210
211 std::vector<int>* postsolve_mapping_;
212 PresolveContext* context_;
213 SolverLogger* logger_;
214
215 // Used by CanonicalizeLinearExpressionInternal().
216 std::vector<std::pair<int, int64_t>> tmp_terms_;
217};
218
219// This helper class perform copy with simplification from a model and a
220// partial assignment to another model. The purpose is to miminize the size of
221// the copied model, as well as to reduce the pressure on the memory sub-system.
222//
223// It is currently used by the LNS part, but could be used with any other scheme
224// that generates partial assignments.
226 public:
228
229 // Copies all constraints from in_model to working model of the context.
230 //
231 // During the process, it will read variable domains from the context, and
232 // simplify constraints to minimize the size of the copied model.
233 // Thus it is important that the context->working_model already have the
234 // variables part copied.
235 //
236 // It returns false iff the model is proven infeasible.
237 //
238 // It does not clear the constraints part of the working model of the context.
240 const CpModelProto& in_model,
241 const std::vector<int>& ignored_constraints);
242
243 private:
244 // Overwrites the out_model to be unsat. Returns false.
245 bool CreateUnsatModel();
246
247 void CopyEnforcementLiterals(const ConstraintProto& orig,
248 ConstraintProto* dest);
249 bool OneEnforcementLiteralIsFalse(const ConstraintProto& ct) const;
250
251 // All these functions return false if the constraint is found infeasible.
252 bool CopyBoolOr(const ConstraintProto& ct);
253 bool CopyBoolAnd(const ConstraintProto& ct);
254 bool CopyLinear(const ConstraintProto& ct);
255 bool CopyAtMostOne(const ConstraintProto& ct);
256 bool CopyExactlyOne(const ConstraintProto& ct);
257 bool CopyInterval(const ConstraintProto& ct, int c);
258
259 PresolveContext* context_;
260 int64_t skipped_non_zero_ = 0;
261
262 // Temp vectors.
263 std::vector<int> non_fixed_variables_;
264 std::vector<int64_t> non_fixed_coefficients_;
265 absl::flat_hash_map<int, int> interval_mapping_;
266 int starting_constraint_index_ = 0;
267 std::vector<int> temp_enforcement_literals_;
268 std::vector<int> temp_literals_;
269};
270
271// Import the constraints from the in_model to the presolve context.
272// It performs on the fly simplification, and returns false if the
273// model is proved infeasible.
276
277// Copies the non constraint, non variables part of the model.
279 const CpModelProto& in_model, PresolveContext* context);
280
281// Convenient wrapper to call the full presolve.
283 std::vector<int>* postsolve_mapping);
284
285// Returns the index of duplicate constraints in the given proto in the first
286// element of each pair. The second element of each pair is the "representative"
287// that is the first constraint in the proto in a set of duplicate constraints.
288//
289// Empty constraints are ignored. We also do a bit more:
290// - We ignore names when comparing constraint.
291// - For linear constraints, we ignore the domain. This is because we can
292// just merge them if the constraints are the same.
293//
294// Visible here for testing. This is meant to be called at the end of the
295// presolve where constraints have been canonicalized.
296std::vector<std::pair<int, int>> FindDuplicateConstraints(
298
299} // namespace sat
300} // namespace operations_research
301
302#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)
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.