OR-Tools  9.6
presolve_context.h
Go to the documentation of this file.
1 // Copyright 2010-2022 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_PRESOLVE_CONTEXT_H_
15 #define OR_TOOLS_SAT_PRESOLVE_CONTEXT_H_
16 
17 #include <cstdint>
18 #include <deque>
19 #include <string>
20 #include <tuple>
21 #include <utility>
22 #include <vector>
23 
24 #include "absl/base/attributes.h"
25 #include "absl/container/flat_hash_map.h"
26 #include "absl/container/flat_hash_set.h"
27 #include "absl/strings/str_cat.h"
28 #include "absl/types/span.h"
29 #include "ortools/base/logging.h"
30 #include "ortools/sat/cp_model.pb.h"
32 #include "ortools/sat/model.h"
34 #include "ortools/sat/sat_parameters.pb.h"
35 #include "ortools/sat/util.h"
37 #include "ortools/util/bitset.h"
38 #include "ortools/util/logging.h"
41 
42 namespace operations_research {
43 namespace sat {
44 
45 // We use some special constraint index in our variable <-> constraint graph.
46 constexpr int kObjectiveConstraint = -1;
47 constexpr int kAffineRelationConstraint = -2;
48 constexpr int kAssumptionsConstraint = -3;
49 
50 class PresolveContext;
51 
52 // When storing a reference to a literal, it is important not to forget when
53 // reading it back to take its representative. Otherwise, we might introduce
54 // literal that have already been removed, which will break invariants in a
55 // bunch of places.
56 class SavedLiteral {
57  public:
59  explicit SavedLiteral(int ref) : ref_(ref) {}
60  int Get(PresolveContext* context) const;
61 
62  private:
63  int ref_ = 0;
64 };
65 
66 // Same as SavedLiteral for variable.
67 //
68 // TODO(user): get rid of this, we don't have the notion of equivalent variable
69 // anymore, but the more general affine relation one. We just need to support
70 // general affine for the linear1 involving an absolute value.
72  public:
74  explicit SavedVariable(int ref) : ref_(ref) {}
75  int Get() const;
76 
77  private:
78  int ref_ = 0;
79 };
80 
81 // Wrap the CpModelProto we are presolving with extra data structure like the
82 // in-memory domain of each variables and the constraint variable graph.
84  public:
85  PresolveContext(Model* model, CpModelProto* cp_model, CpModelProto* mapping)
86  : working_model(cp_model),
87  mapping_model(mapping),
88  logger_(model->GetOrCreate<SolverLogger>()),
89  params_(*model->GetOrCreate<SatParameters>()),
90  time_limit_(model->GetOrCreate<TimeLimit>()),
91  random_(model->GetOrCreate<ModelRandomGenerator>()) {}
92 
93  // Helpers to adds new variables to the presolved model.
94  //
95  // TODO(user): We should control more how this is called so we can update
96  // a solution hint accordingly.
97  int NewIntVar(const Domain& domain);
98  int NewBoolVar();
99 
100  // Some expansion code use constant literal to be simpler to write. This will
101  // create a NewBoolVar() the first time, but later call will just returns it.
102  int GetTrueLiteral();
103  int GetFalseLiteral();
104 
105  // a => b.
106  void AddImplication(int a, int b);
107 
108  // b => x in [lb, ub].
109  void AddImplyInDomain(int b, int x, const Domain& domain);
110 
111  // Helpers to query the current domain of a variable.
112  bool DomainIsEmpty(int ref) const;
113  bool IsFixed(int ref) const;
114  bool CanBeUsedAsLiteral(int ref) const;
115  bool LiteralIsTrue(int lit) const;
116  bool LiteralIsFalse(int lit) const;
117  int64_t MinOf(int ref) const;
118  int64_t MaxOf(int ref) const;
119  int64_t FixedValue(int ref) const;
120  bool DomainContains(int ref, int64_t value) const;
121  Domain DomainOf(int ref) const;
122 
123  // Helper to query the state of an interval.
124  bool IntervalIsConstant(int ct_ref) const;
125  int64_t StartMin(int ct_ref) const;
126  int64_t StartMax(int ct_ref) const;
127  int64_t SizeMin(int ct_ref) const;
128  int64_t SizeMax(int ct_ref) const;
129  int64_t EndMin(int ct_ref) const;
130  int64_t EndMax(int ct_ref) const;
131  std::string IntervalDebugString(int ct_ref) const;
132 
133  // Helpers to query the current domain of a linear expression.
134  // This doesn't check for integer overflow, but our linear expression
135  // should be such that this cannot happen (tested at validation).
136  int64_t MinOf(const LinearExpressionProto& expr) const;
137  int64_t MaxOf(const LinearExpressionProto& expr) const;
138  bool IsFixed(const LinearExpressionProto& expr) const;
139  int64_t FixedValue(const LinearExpressionProto& expr) const;
140 
141  // Accepts any proto with two parallel vector .vars() and .coeffs(), like
142  // LinearConstraintProto or ObjectiveProto or LinearExpressionProto but beware
143  // that this ignore any offset.
144  template <typename ProtoWithVarsAndCoeffs>
145  std::pair<int64_t, int64_t> ComputeMinMaxActivity(
146  const ProtoWithVarsAndCoeffs& proto) const {
147  int64_t min_activity = 0;
148  int64_t max_activity = 0;
149  const int num_vars = proto.vars().size();
150  for (int i = 0; i < num_vars; ++i) {
151  const int var = proto.vars(i);
152  const int64_t coeff = proto.coeffs(i);
153  if (coeff > 0) {
154  min_activity += coeff * MinOf(var);
155  max_activity += coeff * MaxOf(var);
156  } else {
157  min_activity += coeff * MaxOf(var);
158  max_activity += coeff * MinOf(var);
159  }
160  }
161  return {min_activity, max_activity};
162  }
163 
164  // This methods only works for affine expressions (checked).
165  bool DomainContains(const LinearExpressionProto& expr, int64_t value) const;
166 
167  // Return a super-set of the domain of the linear expression.
168  Domain DomainSuperSetOf(const LinearExpressionProto& expr) const;
169 
170  // Returns true iff the expr is of the form a * literal + b.
171  // The other function can be used to get the literal that achieve MaxOf().
172  bool ExpressionIsAffineBoolean(const LinearExpressionProto& expr) const;
173  int LiteralForExpressionMax(const LinearExpressionProto& expr) const;
174 
175  // Returns true iff the expr is of the form 1 * var + 0.
176  bool ExpressionIsSingleVariable(const LinearExpressionProto& expr) const;
177 
178  // Returns true iff the expr is a literal (x or not(x)).
179  bool ExpressionIsALiteral(const LinearExpressionProto& expr,
180  int* literal = nullptr) const;
181 
182  // This function takes a positive variable reference.
183  bool DomainOfVarIsIncludedIn(int var, const Domain& domain) {
184  return domains[var].IsIncludedIn(domain);
185  }
186 
187  // Returns true if this ref only appear in one constraint.
188  bool VariableIsUniqueAndRemovable(int ref) const;
189 
190  // Returns true if this ref no longer appears in the model.
191  bool VariableIsNotUsedAnymore(int ref) const;
192 
193  // Functions to make sure that once we remove a variable, we no longer reuse
194  // it.
195  void MarkVariableAsRemoved(int ref);
196  bool VariableWasRemoved(int ref) const;
197 
198  // Same as VariableIsUniqueAndRemovable() except that in this case the
199  // variable also appear in the objective in addition to a single constraint.
200  bool VariableWithCostIsUnique(int ref) const;
201  bool VariableWithCostIsUniqueAndRemovable(int ref) const;
202 
203  // Returns true if an integer variable is only appearing in the rhs of
204  // constraints of the form lit => var in domain. When this is the case, then
205  // we can usually remove this variable and replace these constraints with
206  // the proper constraints on the enforcement literals.
208 
209  // Returns false if the new domain is empty. Sets 'domain_modified' (if
210  // provided) to true iff the domain is modified otherwise does not change it.
211  ABSL_MUST_USE_RESULT bool IntersectDomainWith(
212  int ref, const Domain& domain, bool* domain_modified = nullptr);
213 
214  // Returns false if the 'lit' doesn't have the desired value in the domain.
215  ABSL_MUST_USE_RESULT bool SetLiteralToFalse(int lit);
216  ABSL_MUST_USE_RESULT bool SetLiteralToTrue(int lit);
217 
218  // Same as IntersectDomainWith() but take a linear expression as input.
219  // If this expression if of size > 1, this does nothing for now, so it will
220  // only propagates for constant and affine expression.
221  ABSL_MUST_USE_RESULT bool IntersectDomainWith(
222  const LinearExpressionProto& expr, const Domain& domain,
223  bool* domain_modified = nullptr);
224 
225  // This function always return false. It is just a way to make a little bit
226  // more sure that we abort right away when infeasibility is detected.
227  ABSL_MUST_USE_RESULT bool NotifyThatModelIsUnsat(
228  const std::string& message = "") {
229  // TODO(user): Report any explanation for the client in a nicer way?
230  SOLVER_LOG(logger_, "INFEASIBLE: '", message, "'");
231  DCHECK(!is_unsat_);
232  is_unsat_ = true;
233  return false;
234  }
235  bool ModelIsUnsat() const { return is_unsat_; }
236 
237  // Stores a description of a rule that was just applied to have a summary of
238  // what the presolve did at the end.
239  void UpdateRuleStats(const std::string& name, int num_times = 1);
240 
241  // Updates the constraints <-> variables graph. This needs to be called each
242  // time a constraint is modified.
243  void UpdateConstraintVariableUsage(int c);
244 
245  // At the beginning of the presolve, we delay the costly creation of this
246  // "graph" until we at least ran some basic presolve. This is because during
247  // a LNS neighbhorhood, many constraints will be reduced significantly by
248  // this "simple" presolve.
250 
251  // Calls UpdateConstraintVariableUsage() on all newly created constraints.
253 
254  // Returns true if our current constraints <-> variables graph is ok.
255  // This is meant to be used in DEBUG mode only.
257 
258  // A "canonical domain" always have a MinOf() equal to zero.
259  // If needed we introduce a new variable with such canonical domain and
260  // add the relation X = Y + offset.
261  //
262  // This is useful in some corner case to avoid overflow.
263  //
264  // TODO(user): When we can always get rid of affine relation, it might be good
265  // to do a final pass to canonicalize all domains in a model after presolve.
266  void CanonicalizeVariable(int ref);
267 
268  // Given the relation (X * coeff % mod = rhs % mod), this creates a new
269  // variable so that X = mod * Y + cte.
270  //
271  // This requires mod != 0 and coeff != 0.
272  //
273  // Note that the new variable will have a canonical domain (i.e. min == 0).
274  // We also do not create anything if this fixes the given variable or the
275  // relation simplifies. Returns false if the model is infeasible.
276  bool CanonicalizeAffineVariable(int ref, int64_t coeff, int64_t mod,
277  int64_t rhs);
278 
279  // Adds the relation (ref_x = coeff * ref_y + offset) to the repository.
280  // Returns false if we detect infeasability because of this.
281  //
282  // Once the relation is added, it doesn't need to be enforced by a constraint
283  // in the model proto, since we will propagate such relation directly and add
284  // them to the proto at the end of the presolve.
285  //
286  // Note that this should always add a relation, even though it might need to
287  // create a new representative for both ref_x and ref_y in some cases. Like if
288  // x = 3z and y = 5t are already added, if we add x = 2y, we have 3z = 10t and
289  // can only resolve this by creating a new variable r such that z = 10r and t
290  // = 3r.
291  //
292  // All involved variables will be marked to appear in the special
293  // kAffineRelationConstraint. This will allow to identify when a variable is
294  // no longer needed (only appear there and is not a representative).
295  bool StoreAffineRelation(int ref_x, int ref_y, int64_t coeff, int64_t offset,
296  bool debug_no_recursion = false);
297 
298  // Adds the fact that ref_a == ref_b using StoreAffineRelation() above.
299  // Returns false if this makes the problem infeasible.
300  bool StoreBooleanEqualityRelation(int ref_a, int ref_b);
301 
302  // Stores/Get the relation target_ref = abs(ref); The first function returns
303  // false if it already exist and the second false if it is not present.
304  bool StoreAbsRelation(int target_ref, int ref);
305  bool GetAbsRelation(int target_ref, int* ref);
306 
307  // Returns the representative of a literal.
308  int GetLiteralRepresentative(int ref) const;
309 
310  // Returns another reference with exactly the same value.
311  int GetVariableRepresentative(int ref) const;
312 
313  // Used for statistics.
314  int NumAffineRelations() const { return affine_relations_.NumRelations(); }
315 
316  // Returns the representative of ref under the affine relations.
318 
319  // To facilitate debugging.
320  std::string RefDebugString(int ref) const;
321  std::string AffineRelationDebugString(int ref) const;
322 
323  // Makes sure the domain of ref and of its representative (ref = coeff * rep +
324  // offset) are in sync. Returns false on unsat.
325  bool PropagateAffineRelation(int ref);
326  bool PropagateAffineRelation(int ref, int rep, int64_t coeff, int64_t offset);
327 
328  // Creates the internal structure for any new variables in working_model.
329  void InitializeNewDomains();
330 
331  // Clears the "rules" statistics.
332  void ClearStats();
333 
334  // Inserts the given literal to encode ref == value.
335  // If an encoding already exists, it adds the two implications between
336  // the previous encoding and the new encoding.
337  //
338  // Important: This does not update the constraint<->variable graph, so
339  // ConstraintVariableGraphIsUpToDate() will be false until
340  // UpdateNewConstraintsVariableUsage() is called.
341  //
342  // Returns false if the model become UNSAT.
343  //
344  // TODO(user): This function is not always correct if
345  // !context->DomainOf(ref).contains(value), we could make it correct but it
346  // might be a bit expansive to do so. For now we just have a DCHECK().
347  bool InsertVarValueEncoding(int literal, int ref, int64_t value);
348 
349  // Gets the associated literal if it is already created. Otherwise
350  // create it, add the corresponding constraints and returns it.
351  //
352  // Important: This does not update the constraint<->variable graph, so
353  // ConstraintVariableGraphIsUpToDate() will be false until
354  // UpdateNewConstraintsVariableUsage() is called.
355  int GetOrCreateVarValueEncoding(int ref, int64_t value);
356 
357  // Gets the associated literal if it is already created. Otherwise
358  // create it, add the corresponding constraints and returns it.
359  //
360  // Important: This does not update the constraint<->variable graph, so
361  // ConstraintVariableGraphIsUpToDate() will be false until
362  // UpdateNewConstraintsVariableUsage() is called.
363  int GetOrCreateAffineValueEncoding(const LinearExpressionProto& expr,
364  int64_t value);
365 
366  // If not already done, adds a Boolean to represent any integer variables that
367  // take only two values. Make sure all the relevant affine and encoding
368  // relations are updated.
369  //
370  // Note that this might create a new Boolean variable.
372 
373  // Returns true if a literal attached to ref == var exists.
374  // It assigns the corresponding to `literal` if non null.
375  bool HasVarValueEncoding(int ref, int64_t value, int* literal = nullptr);
376 
377  // Returns true if we have literal <=> var = value for all values of var.
378  //
379  // TODO(user): If the domain was shrunk, we can have a false positive.
380  // Still it means that the number of values removed is greater than the number
381  // of values not encoded.
382  bool IsFullyEncoded(int ref) const;
383 
384  // This methods only works for affine expressions (checked).
385  // It returns true iff the expression is constant or its one variable is full
386  // encoded.
387  bool IsFullyEncoded(const LinearExpressionProto& expr) const;
388 
389  // Stores the fact that literal implies var == value.
390  // It returns true if that information is new.
391  bool StoreLiteralImpliesVarEqValue(int literal, int var, int64_t value);
392 
393  // Stores the fact that literal implies var != value.
394  // It returns true if that information is new.
395  bool StoreLiteralImpliesVarNEqValue(int literal, int var, int64_t value);
396 
397  // Objective handling functions. We load it at the beginning so that during
398  // presolve we can work on the more efficient hash_map representation.
399  //
400  // Note that ReadObjectiveFromProto() makes sure that var_to_constraints of
401  // all the variable that appear in the objective contains -1. This is later
402  // enforced by all the functions modifying the objective.
403  //
404  // Note(user): Because we process affine relation only on
405  // CanonicalizeObjective(), it is possible that when processing a
406  // canonicalized linear constraint, we don't detect that a variable in affine
407  // relation is in the objective. For now this is fine, because when this is
408  // the case, we also have an affine linear constraint, so we can't really do
409  // anything with that variable since it appear in at least two constraints.
410  void ReadObjectiveFromProto();
411  bool AddToObjectiveOffset(int64_t delta);
412  ABSL_MUST_USE_RESULT bool CanonicalizeOneObjectiveVariable(int var);
413  ABSL_MUST_USE_RESULT bool CanonicalizeObjective(bool simplify_domain = true);
414  void WriteObjectiveToProto() const;
415  ABSL_MUST_USE_RESULT bool ScaleFloatingPointObjective();
416 
417  // When the objective is singleton, we can always restrict the domain of var
418  // so that the current objective domain is non-constraining. Returns false
419  // on UNSAT.
421 
422  // Some function need the domain to be up to date in the proto.
423  // This make sures our in-memory domain are writted back to the proto.
424  void WriteVariableDomainsToProto() const;
425 
426  // Checks if the given exactly_one is included in the objective, and simplify
427  // the objective by adding a constant value to all the exactly one terms.
428  //
429  // Returns true if a simplification was done.
430  bool ExploitExactlyOneInObjective(absl::Span<const int> exactly_one);
431 
432  // We can always add a multiple of sum X - 1 == 0 to the objective.
433  // However, depending on which multiple we choose, this might break our
434  // overflow preconditions on the objective. So we return false and do nothing
435  // if this happens.
436  bool ShiftCostInExactlyOne(absl::Span<const int> exactly_one, int64_t shift);
437 
438  // Allows to manipulate the objective coefficients.
439  void RemoveVariableFromObjective(int ref);
440  void AddToObjective(int var, int64_t value);
441  void AddLiteralToObjective(int ref, int64_t value);
442 
443  // Given a variable defined by the given inequality that also appear in the
444  // objective, remove it from the objective by transferring its cost to other
445  // variables in the equality.
446  //
447  // Returns false, if the substitution cannot be done. This is the case if the
448  // model become UNSAT or if doing it will result in an objective that do not
449  // satisfy our overflow preconditions. Note that this can only happen if the
450  // substituted variable is not implied free (i.e. if its domain is smaller
451  // than the implied domain from the equality).
452  ABSL_MUST_USE_RESULT bool SubstituteVariableInObjective(
453  int var_in_equality, int64_t coeff_in_equality,
454  const ConstraintProto& equality);
455 
456  // Objective getters.
457  const Domain& ObjectiveDomain() const { return objective_domain_; }
458  const absl::flat_hash_map<int, int64_t>& ObjectiveMap() const {
459  return objective_map_;
460  }
461  int64_t ObjectiveCoeff(int var) const {
462  DCHECK_GE(var, 0);
463  const auto it = objective_map_.find(var);
464  return it == objective_map_.end() ? 0 : it->second;
465  }
467  return objective_domain_is_constraining_;
468  }
469 
470  // Advanced usage. This should be called when a variable can be removed from
471  // the problem, so we don't count it as part of an affine relation anymore.
474 
475  // Variable <-> constraint graph.
476  // The vector list is sorted and contains unique elements.
477  //
478  // Important: To properly handle the objective, var_to_constraints[objective]
479  // contains kObjectiveConstraint (i.e. -1) so that if the objective appear in
480  // only one constraint, the constraint cannot be simplified.
481  const std::vector<std::vector<int>>& ConstraintToVarsGraph() const {
483  return constraint_to_vars_;
484  }
485  const std::vector<int>& ConstraintToVars(int c) const {
487  return constraint_to_vars_[c];
488  }
489  const absl::flat_hash_set<int>& VarToConstraints(int var) const {
491  return var_to_constraints_[var];
492  }
493  int IntervalUsage(int c) const {
495  return interval_usage_[c];
496  }
497 
498  // Checks if a constraint contains an enforcement literal set to false,
499  // or if it has been cleared.
500  bool ConstraintIsInactive(int ct_index) const;
501 
502  // Checks if a constraint contains an enforcement literal not fixed, and
503  // no enforcement literals set to false.
504  bool ConstraintIsOptional(int ct_ref) const;
505 
506  // Make sure we never delete an "assumption" literal by using a special
507  // constraint for that.
509  for (const int ref : working_model->assumptions()) {
510  var_to_constraints_[PositiveRef(ref)].insert(kAssumptionsConstraint);
511  }
512  }
513 
514  // The "expansion" phase should be done once and allow to transform complex
515  // constraints into basic ones (see cp_model_expand.h). Some presolve rules
516  // need to know if the expansion was ran before beeing applied.
517  bool ModelIsExpanded() const { return model_is_expanded_; }
518  void NotifyThatModelIsExpanded() { model_is_expanded_ = true; }
519 
520  // The following helper adds the following constraint:
521  // result <=> (time_i <= time_j && active_i is true && active_j is true)
522  // and returns the (cached) literal result.
523  //
524  // Note that this cache should just be used temporarily and then cleared
525  // with ClearPrecedenceCache() because there is no mechanism to update the
526  // cached literals when literal equivalence are detected.
527  int GetOrCreateReifiedPrecedenceLiteral(const LinearExpressionProto& time_i,
528  const LinearExpressionProto& time_j,
529  int active_i, int active_j);
530 
531  std::tuple<int, int64_t, int, int64_t, int64_t, int, int>
532  GetReifiedPrecedenceKey(const LinearExpressionProto& time_i,
533  const LinearExpressionProto& time_j, int active_i,
534  int active_j);
535 
536  // Clear the precedence cache.
537  void ClearPrecedenceCache();
538 
539  // Logs stats to the logger.
540  void LogInfo();
541 
542  // Return the given index, or the index of an interval with the same data.
544 
545  SolverLogger* logger() const { return logger_; }
546  const SatParameters& params() const { return params_; }
547  TimeLimit* time_limit() { return time_limit_; }
548  ModelRandomGenerator* random() { return random_; }
549 
550  CpModelProto* working_model = nullptr;
551  CpModelProto* mapping_model = nullptr;
552 
553  // Indicate if we are allowed to remove irrelevant feasible solution from the
554  // set of feasible solution. For example, if a variable is unused, can we fix
555  // it to an arbitrary value (or its mimimum objective one)? This must be true
556  // if the client wants to enumerate all solutions or wants correct tightened
557  // bounds in the response.
559 
560  // Number of "rules" applied. This should be equal to the sum of all numbers
561  // in stats_by_rule_name. This is used to decide if we should do one more pass
562  // of the presolve or not. Note that depending on the presolve transformation,
563  // a rule can correspond to a tiny change or a big change. Because of that,
564  // this isn't a perfect proxy for the efficacy of the presolve.
566 
567  // Temporary storage.
568  std::vector<int> tmp_literals;
569  std::vector<Domain> tmp_term_domains;
570  std::vector<Domain> tmp_left_domains;
571  absl::flat_hash_set<int> tmp_literal_set;
572 
573  // Each time a domain is modified this is set to true.
575 
576  // Each time the constraint <-> variable graph is updated, we update this.
577  // A variable is added here iff its usage decreased and is now one or two.
579 
580  // Advanced presolve. See this class comment.
582 
583  private:
584  void EraseFromVarToConstraint(int var, int c);
585 
586  // Helper to add an affine relation x = c.y + o to the given repository.
587  bool AddRelation(int x, int y, int64_t c, int64_t o, AffineRelation* repo);
588 
589  void AddVariableUsage(int c);
590  void UpdateLinear1Usage(const ConstraintProto& ct, int c);
591 
592  // Makes sure we only insert encoding about the current representative.
593  //
594  // Returns false if ref cannot take the given value (it might not have been
595  // propagated yet).
596  bool CanonicalizeEncoding(int* ref, int64_t* value);
597 
598  // Inserts an half reified var value encoding (literal => var ==/!= value).
599  // It returns true if the new state is different from the old state.
600  // Not that if imply_eq is false, the literal will be stored in its negated
601  // form.
602  //
603  // Thus, if you detect literal <=> var == value, then two calls must be made:
604  // InsertHalfVarValueEncoding(literal, var, value, true);
605  // InsertHalfVarValueEncoding(NegatedRef(literal), var, value, false);
606  bool InsertHalfVarValueEncoding(int literal, int var, int64_t value,
607  bool imply_eq);
608 
609  // Insert fully reified var-value encoding.
610  void InsertVarValueEncodingInternal(int literal, int var, int64_t value,
611  bool add_constraints);
612 
613  SolverLogger* logger_;
614  const SatParameters& params_;
615  TimeLimit* time_limit_;
616  ModelRandomGenerator* random_;
617 
618  // Initially false, and set to true on the first inconsistency.
619  bool is_unsat_ = false;
620 
621  // The current domain of each variables.
622  std::vector<Domain> domains;
623 
624  // Internal representation of the objective. During presolve, we first load
625  // the objective in this format in order to have more efficient substitution
626  // on large problems (also because the objective is often dense). At the end
627  // we re-convert it to its proto form.
628  absl::flat_hash_map<int, int64_t> objective_map_;
629  int64_t objective_overflow_detection_;
630  std::vector<std::pair<int, int64_t>> tmp_entries_;
631  bool objective_domain_is_constraining_ = false;
632  Domain objective_domain_;
633  double objective_offset_;
634  double objective_scaling_factor_;
635  int64_t objective_integer_before_offset_;
636  int64_t objective_integer_after_offset_;
637  int64_t objective_integer_scaling_factor_;
638 
639  // Constraints <-> Variables graph.
640  std::vector<std::vector<int>> constraint_to_vars_;
641  std::vector<absl::flat_hash_set<int>> var_to_constraints_;
642 
643  // Number of constraints of the form [lit =>] var in domain.
644  std::vector<int> constraint_to_linear1_var_;
645  std::vector<int> var_to_num_linear1_;
646 
647  // We maintain how many time each interval is used.
648  std::vector<std::vector<int>> constraint_to_intervals_;
649  std::vector<int> interval_usage_;
650 
651  // Contains abs relation (key = abs(saved_variable)).
652  absl::flat_hash_map<int, SavedVariable> abs_relations_;
653 
654  // Used by GetTrueLiteral()/GetFalseLiteral().
655  bool true_literal_is_defined_ = false;
656  int true_literal_;
657 
658  // Contains variables with some encoded value: encoding_[i][v] points
659  // to the literal attached to the value v of the variable i.
660  absl::flat_hash_map<int, absl::flat_hash_map<int64_t, SavedLiteral>>
661  encoding_;
662 
663  // Contains the currently collected half value encodings:
664  // i.e.: literal => var ==/!= value
665  // The state is accumulated (adding x => var == value then !x => var != value)
666  // will deduce that x equivalent to var == value.
667  absl::flat_hash_map<int,
668  absl::flat_hash_map<int64_t, absl::flat_hash_set<int>>>
669  eq_half_encoding_;
670  absl::flat_hash_map<int,
671  absl::flat_hash_map<int64_t, absl::flat_hash_set<int>>>
672  neq_half_encoding_;
673 
674  // This regroups all the affine relations between variables. Note that the
675  // constraints used to detect such relations will be removed from the model at
676  // detection time. But we mark all the variables in affine relations as part
677  // of the kAffineRelationConstraint.
678  AffineRelation affine_relations_;
679 
680  std::vector<int> tmp_new_usage_;
681 
682  // Used by SetVariableAsRemoved() and VariableWasRemoved().
683  absl::flat_hash_set<int> removed_variables_;
684 
685  // Cache for the reified precedence literals created during the expansion of
686  // the reservoir constraint. This cache is only valid during the expansion
687  // phase, and is cleared afterwards.
688  absl::flat_hash_map<std::tuple<int, int64_t, int, int64_t, int64_t, int, int>,
689  int>
690  reified_precedences_cache_;
691 
692  // Just used to display statistics on the presolve rules that were used.
693  absl::flat_hash_map<std::string, int> stats_by_rule_name_;
694 
695  // Serialized proto (should be small) to index.
696  absl::flat_hash_map<std::string, int> interval_representative_;
697 
698  bool model_is_expanded_ = false;
699 };
700 
701 // Utility function to load the current problem into a in-memory representation
702 // that will be used for probing. Returns false if UNSAT.
703 bool LoadModelForProbing(PresolveContext* context, Model* local_model);
704 
705 } // namespace sat
706 } // namespace operations_research
707 
708 #endif // OR_TOOLS_SAT_PRESOLVE_CONTEXT_H_
We call domain any subset of Int64 = [kint64min, kint64max].
A simple class to enforce both an elapsed time limit and a deterministic time limit in the same threa...
Definition: time_limit.h:106
Class that owns everything related to a particular optimization model.
Definition: sat/model.h:42
bool CanonicalizeAffineVariable(int ref, int64_t coeff, int64_t mod, int64_t rhs)
bool ExpressionIsALiteral(const LinearExpressionProto &expr, int *literal=nullptr) const
bool StoreAbsRelation(int target_ref, int ref)
ABSL_MUST_USE_RESULT bool SubstituteVariableInObjective(int var_in_equality, int64_t coeff_in_equality, const ConstraintProto &equality)
const std::vector< std::vector< int > > & ConstraintToVarsGraph() const
PresolveContext(Model *model, CpModelProto *cp_model, CpModelProto *mapping)
void AddToObjective(int var, int64_t value)
ABSL_MUST_USE_RESULT bool IntersectDomainWith(int ref, const Domain &domain, bool *domain_modified=nullptr)
bool StoreLiteralImpliesVarNEqValue(int literal, int var, int64_t value)
int GetOrCreateReifiedPrecedenceLiteral(const LinearExpressionProto &time_i, const LinearExpressionProto &time_j, int active_i, int active_j)
ABSL_MUST_USE_RESULT bool CanonicalizeObjective(bool simplify_domain=true)
bool StoreBooleanEqualityRelation(int ref_a, int ref_b)
bool DomainOfVarIsIncludedIn(int var, const Domain &domain)
bool VariableWithCostIsUniqueAndRemovable(int ref) const
bool ExpressionIsSingleVariable(const LinearExpressionProto &expr) const
ABSL_MUST_USE_RESULT bool SetLiteralToTrue(int lit)
int GetOrCreateAffineValueEncoding(const LinearExpressionProto &expr, int64_t value)
ABSL_MUST_USE_RESULT bool ScaleFloatingPointObjective()
ABSL_MUST_USE_RESULT bool CanonicalizeOneObjectiveVariable(int var)
const std::vector< int > & ConstraintToVars(int c) const
std::pair< int64_t, int64_t > ComputeMinMaxActivity(const ProtoWithVarsAndCoeffs &proto) const
int GetOrCreateVarValueEncoding(int ref, int64_t value)
ABSL_MUST_USE_RESULT bool NotifyThatModelIsUnsat(const std::string &message="")
std::string AffineRelationDebugString(int ref) const
const absl::flat_hash_map< int, int64_t > & ObjectiveMap() const
bool InsertVarValueEncoding(int literal, int ref, int64_t value)
std::tuple< int, int64_t, int, int64_t, int64_t, int, int > GetReifiedPrecedenceKey(const LinearExpressionProto &time_i, const LinearExpressionProto &time_j, int active_i, int active_j)
bool HasVarValueEncoding(int ref, int64_t value, int *literal=nullptr)
bool DomainContains(int ref, int64_t value) const
bool ShiftCostInExactlyOne(absl::Span< const int > exactly_one, int64_t shift)
void UpdateRuleStats(const std::string &name, int num_times=1)
const SatParameters & params() const
AffineRelation::Relation GetAffineRelation(int ref) const
void AddLiteralToObjective(int ref, int64_t value)
bool StoreAffineRelation(int ref_x, int ref_y, int64_t coeff, int64_t offset, bool debug_no_recursion=false)
std::string IntervalDebugString(int ct_ref) const
const absl::flat_hash_set< int > & VarToConstraints(int var) const
ABSL_MUST_USE_RESULT bool SetLiteralToFalse(int lit)
int LiteralForExpressionMax(const LinearExpressionProto &expr) const
bool ExpressionIsAffineBoolean(const LinearExpressionProto &expr) const
bool ExploitExactlyOneInObjective(absl::Span< const int > exactly_one)
Domain DomainSuperSetOf(const LinearExpressionProto &expr) const
absl::flat_hash_set< int > tmp_literal_set
void AddImplyInDomain(int b, int x, const Domain &domain)
bool VariableIsOnlyUsedInEncodingAndMaybeInObjective(int ref) const
bool GetAbsRelation(int target_ref, int *ref)
bool StoreLiteralImpliesVarEqValue(int literal, int var, int64_t value)
int Get(PresolveContext *context) const
int64_t b
int64_t a
CpModelProto proto
const std::string name
const Constraint * ct
int64_t value
IntVar * var
Definition: expr_array.cc:1874
GRBmodel * model
GurobiMPCallbackContext * context
int index
constexpr int kAffineRelationConstraint
constexpr int kAssumptionsConstraint
bool LoadModelForProbing(PresolveContext *context, Model *local_model)
constexpr int kObjectiveConstraint
Collection of objects used to extend the Constraint Solver library.
Literal literal
Definition: optimization.cc:88
int64_t delta
Definition: resource.cc:1695
std::string message
Definition: trace.cc:399
#define SOLVER_LOG(logger,...)
Definition: util/logging.h:69