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 
30 namespace operations_research {
31 namespace 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.
40 void 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,
139  LinearExpressionProto* exp);
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.
226 class ModelCopy {
227  public:
228  explicit ModelCopy(PresolveContext* context);
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 //
310 // Visible here for testing. This is meant to be called at the end of the
311 // presolve where constraints have been canonicalized.
312 std::vector<std::pair<int, int>> FindDuplicateConstraints(
313  const CpModelProto& model_proto);
314 
315 } // namespace sat
316 } // namespace operations_research
317 
318 #endif // OR_TOOLS_SAT_CP_MODEL_PRESOLVE_H_
std::vector< std::pair< int, int > > FindDuplicateConstraints(const CpModelProto &model_proto)
CpModelProto proto
bool ImportConstraintsWithBasicPresolveIntoContext(const CpModelProto &in_model, PresolveContext *context)
void CopyEverythingExceptVariablesAndConstraintsFieldsIntoContext(const CpModelProto &in_model, PresolveContext *context)
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 const * model_proto
CpSolverStatus PresolveCpModel(PresolveContext *context, std::vector< int > *postsolve_mapping)
Collection of objects used to extend the Constraint Solver library.
IntVar * var
Definition: expr_array.cc:1874
void ApplyVariableMapping(const std::vector< int > &mapping, const PresolveContext &context)
GurobiMPCallbackContext * context
const Constraint * ct