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