Google OR-Tools v9.15
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
integer.h
Go to the documentation of this file.
1// Copyright 2010-2025 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 ORTOOLS_SAT_INTEGER_H_
15#define ORTOOLS_SAT_INTEGER_H_
16
17#include <stdlib.h>
18
19#include <algorithm>
20#include <cstdint>
21#include <deque>
22#include <functional>
23#include <limits>
24#include <optional>
25#include <string>
26#include <utility>
27#include <vector>
28
29#include "absl/base/attributes.h"
30#include "absl/container/btree_map.h"
31#include "absl/container/flat_hash_map.h"
32#include "absl/container/inlined_vector.h"
33#include "absl/log/check.h"
34#include "absl/strings/str_cat.h"
35#include "absl/types/span.h"
38#include "ortools/sat/clause.h"
41#include "ortools/sat/model.h"
45#include "ortools/util/bitset.h"
46#include "ortools/util/rev.h"
50
51namespace operations_research {
52namespace sat {
53
54using InlinedIntegerLiteralVector = absl::InlinedVector<IntegerLiteral, 2>;
56 absl::InlinedVector<std::pair<IntegerVariable, IntegerValue>, 2>;
57
60 IntegerValue left_value;
61 IntegerValue right_value;
62
63 // Used for testing.
64 bool operator==(const LiteralValueValue& rhs) const {
65 return literal.Index() == rhs.literal.Index() &&
67 }
68
69 std::string DebugString() const {
70 return absl::StrCat("(lit(", literal.Index().value(), ") * ",
71 left_value.value(), " * ", right_value.value(), ")");
72 }
73};
74
75// Sometimes we propagate fact with no reason at a positive level, those
76// will automatically be fixed on the next restart.
77//
78// Note that for integer literal, we already remore all "stale" entry, however
79// this is still needed to properly update the InitialVariableDomain().
80//
81// TODO(user): we should update the initial domain right away, but this as
82// some complication to clean up first.
84 std::vector<Literal> literal_to_fix;
85 std::vector<IntegerLiteral> integer_literal_to_fix;
86};
87
88// Each integer variable x will be associated with a set of literals encoding
89// (x >= v) for some values of v. This class maintains the relationship between
90// the integer variables and such literals which can be created by a call to
91// CreateAssociatedLiteral().
92//
93// The advantage of creating such Boolean variables is that the SatSolver which
94// is driving the search can then take this variable as a decision and maintain
95// these variables activity and so on. These variables can also be propagated
96// directly by the learned clauses.
97//
98// This class also support a non-lazy full domain encoding which will create one
99// literal per possible value in the domain. See FullyEncodeVariable(). This is
100// meant to be called by constraints that directly work on the variable values
101// like a table constraint or an all-diff constraint.
102//
103// TODO(user): We could also lazily create precedences Booleans between two
104// arbitrary IntegerVariable. This is better done in the PrecedencesPropagator
105// though.
107 public:
108 explicit IntegerEncoder(Model* model)
109 : sat_solver_(model->GetOrCreate<SatSolver>()),
110 trail_(model->GetOrCreate<Trail>()),
111 clause_id_generator_(model->GetOrCreate<ClauseIdGenerator>()),
112 lrat_proof_handler_(model->Mutable<LratProofHandler>()),
113 delayed_to_fix_(model->GetOrCreate<DelayedRootLevelDeduction>()),
114 domains_(*model->GetOrCreate<IntegerDomains>()),
115 num_created_variables_(0) {}
116
117 // This type is neither copyable nor movable.
120
122 VLOG(1) << "#variables created = " << num_created_variables_;
123 }
124
125 // Memory optimization: you can call this before encoding variables.
126 void ReserveSpaceForNumVariables(int num_vars);
127
128 // Fully encode a variable using its current initial domain.
129 // If the variable is already fully encoded, this does nothing.
130 //
131 // This creates new Booleans variables as needed:
132 // 1) num_values for the literals X == value. Except when there is just
133 // two value in which case only one variable is created.
134 // 2) num_values - 3 for the literals X >= value or X <= value (using their
135 // negation). The -3 comes from the fact that we can reuse the equality
136 // literals for the two extreme points.
137 //
138 // The encoding for NegationOf(var) is automatically created too. It reuses
139 // the same Boolean variable as the encoding of var.
140 //
141 // TODO(user): It is currently only possible to call that at the decision
142 // level zero because we cannot add ternary clause in the middle of the
143 // search (for now). This is Checked.
144 void FullyEncodeVariable(IntegerVariable var);
145
146 // Returns true if we know that PartialDomainEncoding(var) span the full
147 // domain of var. This is always true if FullyEncodeVariable(var) has been
148 // called.
149 bool VariableIsFullyEncoded(IntegerVariable var) const;
150
151 // Returns the list of literal <=> var == value currently associated to the
152 // given variable. The result is sorted by value. We filter literal at false,
153 // and if a literal is true, then you will get a singleton. To be sure to get
154 // the full set of encoded value, then you should call this at level zero.
155 //
156 // The FullDomainEncoding() just check VariableIsFullyEncoded() and returns
157 // the same result.
158 //
159 // WARNING: The reference returned is only valid until the next call to one
160 // of these functions.
161 const std::vector<ValueLiteralPair>& FullDomainEncoding(
162 IntegerVariable var) const;
163 const std::vector<ValueLiteralPair>& PartialDomainEncoding(
164 IntegerVariable var) const;
165
166 // Returns the "canonical" (i_lit, negation of i_lit) pair. This mainly
167 // deal with domain with initial hole like [1,2][5,6] so that if one ask
168 // for x <= 3, this get canonicalized in the pair (x <= 2, x >= 5).
169 //
170 // Note that it is an error to call this with a literal that is trivially true
171 // or trivially false according to the initial variable domain. This is
172 // CHECKed to make sure we don't create wasteful literal.
173 //
174 // TODO(user): This is linear in the domain "complexity", we can do better if
175 // needed.
176 std::pair<IntegerLiteral, IntegerLiteral> Canonicalize(
177 IntegerLiteral i_lit) const;
178
179 // Returns true if the given variable has a "complex" domain.
180 bool VariableDomainHasHoles(IntegerVariable var) {
181 return domains_[GetPositiveOnlyIndex(var)].NumIntervals() > 1;
182 }
183
184 // Returns, after creating it if needed, a Boolean literal such that:
185 // - if true, then the IntegerLiteral is true.
186 // - if false, then the negated IntegerLiteral is true.
187 //
188 // Note that this "canonicalize" the given literal first.
189 //
190 // This add the proper implications with the two "neighbor" literals of this
191 // one if they exist. This is the "list encoding" in: Thibaut Feydy, Peter J.
192 // Stuckey, "Lazy Clause Generation Reengineered", CP 2009.
195 IntegerValue value);
196
197 // Associates the Boolean literal to (X >= bound) or (X == value). If a
198 // literal was already associated to this fact, this will add an equality
199 // constraints between both literals. If the fact is trivially true or false,
200 // this will fix the given literal.
202 void AssociateToIntegerEqualValue(Literal literal, IntegerVariable var,
203 IntegerValue value);
204
205 // Returns kNoLiteralIndex if there is no associated or the associated literal
206 // otherwise.
207 //
208 // Tricky: for domain with hole, like [0,1][5,6], we assume some equivalence
209 // classes, like >=2, >=3, >=4 are all the same as >= 5.
210 //
211 // Note that GetAssociatedLiteral() should not be called with trivially true
212 // or trivially false literal. This is DCHECKed.
214 LiteralIndex GetAssociatedLiteral(IntegerLiteral i_lit) const;
215 LiteralIndex GetAssociatedEqualityLiteral(IntegerVariable var,
216 IntegerValue value) const;
217
218 // Advanced usage. It is more efficient to create the associated literals in
219 // order, but it might be annoying to do so. Instead, you can first call
220 // DisableImplicationBetweenLiteral() and when you are done creating all the
221 // associated literals, you can call (only at level zero)
222 // AddAllImplicationsBetweenAssociatedLiterals() which will also turn back on
223 // the implications between literals for the one that will be added
224 // afterwards.
225 void DisableImplicationBetweenLiteral() { add_implications_ = false; }
227
228 // Returns the IntegerLiterals that were associated with the given Literal.
230 if (lit.Index() >= reverse_encoding_.size()) {
231 return empty_integer_literal_vector_;
232 }
233 return reverse_encoding_[lit];
234 }
235
236 // Returns the variable == value pairs that were associated with the given
237 // Literal. Note that only positive IntegerVariable appears here.
239 if (lit.Index() >= reverse_equality_encoding_.size()) {
240 return empty_integer_value_vector_;
241 }
242 return reverse_equality_encoding_[lit];
243 }
244
245 // Returns all the variables for which this literal is associated to either
246 // var >= value or var == value.
247 const std::vector<IntegerVariable>& GetAllAssociatedVariables(
248 Literal lit) const {
249 temp_associated_vars_.clear();
250 for (const IntegerLiteral l : GetIntegerLiterals(lit)) {
251 temp_associated_vars_.push_back(l.var);
252 }
253 for (const auto& [var, value] : GetEqualityLiterals(lit)) {
254 temp_associated_vars_.push_back(var);
255 }
256 return temp_associated_vars_;
257 }
258
259 // If it exists, returns a [0, 1] integer variable which is equal to 1 iff the
260 // given literal is true. Returns kNoIntegerVariable if such variable does not
261 // exist. Note that one can create one by creating a new IntegerVariable and
262 // calling AssociateToIntegerEqualValue().
263 //
264 // Note that this will only return "positive" IntegerVariable.
265 IntegerVariable GetLiteralView(Literal lit) const {
266 if (lit.Index() >= literal_view_.size()) return kNoIntegerVariable;
267 const IntegerVariable result = literal_view_[lit];
268 DCHECK(result == kNoIntegerVariable || VariableIsPositive(result));
269 return result;
270 }
271
272 // If this is true, then a literal can be linearized with an affine expression
273 // involving an integer variable.
274 ABSL_MUST_USE_RESULT bool LiteralOrNegationHasView(
275 Literal lit, IntegerVariable* view = nullptr,
276 bool* view_is_direct = nullptr) const;
277
278 // Returns a Boolean literal associated with a bound lower than or equal to
279 // the one of the given IntegerLiteral. If the given IntegerLiteral is true,
280 // then the returned literal should be true too. Returns kNoLiteralIndex if no
281 // such literal was created.
282 //
283 // Ex: if 'i' is (x >= 4) and we already created a literal associated to
284 // (x >= 2) but not to (x >= 3), we will return the literal associated with
285 // (x >= 2).
287 IntegerValue* bound) const;
288 LiteralIndex SearchForLiteralAtOrAfter(IntegerLiteral i_lit,
289 IntegerValue* bound) const;
290
291 // Gets the literal always set to true, make it if it does not exist.
293 if (literal_index_true_ == kNoLiteralIndex) {
294 DCHECK_EQ(0, sat_solver_->CurrentDecisionLevel());
295 const Literal literal_true =
296 Literal(sat_solver_->NewBooleanVariable(), true);
297 literal_index_true_ = literal_true.Index();
298
299 ClauseId clause_id = kNoClauseId;
300 if (lrat_proof_handler_ != nullptr) {
301 clause_id = clause_id_generator_->GetNextId();
302 // We cannot prove `literal_true` by unit propagation, but we can with a
303 // RAT inference (trivial here since there are no clauses containing the
304 // negation of the pivot `literal_true`).
305 lrat_proof_handler_->AddInferredClause(clause_id, {literal_true}, {});
306 }
307 trail_->EnqueueWithUnitReason(clause_id, literal_true);
308 }
309 return Literal(literal_index_true_);
310 }
312
313 // Returns the set of Literal associated to IntegerLiteral of the form var >=
314 // value. We make a copy, because this can be easily invalidated when calling
315 // any function of this class. So it is less efficient but safer.
316 std::vector<ValueLiteralPair> PartialGreaterThanEncoding(
317 IntegerVariable var) const;
318
319 // Makes sure all element in the >= encoding are non-trivial and canonical.
320 // The input variable must be positive.
321 bool UpdateEncodingOnInitialDomainChange(IntegerVariable var, Domain domain);
322
323 // All IntegerVariable passed to the functions above must be in
324 // [0, NumVariables).
325 int NumVariables() const { return 2 * encoding_by_var_.size(); }
326
327 private:
328 // Adds the implications:
329 // Literal(before) <= associated_lit <= Literal(after).
330 // Arguments:
331 // - map is just encoding_by_var_[associated_lit.var] and is passed as a
332 // slight optimization.
333 // - 'it' is the current position of associated_lit in map, i.e. we must have
334 // it->second == associated_lit.
335 void AddImplications(
336 const absl::btree_map<IntegerValue, Literal>& map,
337 absl::btree_map<IntegerValue, Literal>::const_iterator it,
338 Literal associated_lit);
339
340 SatSolver* sat_solver_;
341 Trail* trail_;
342 ClauseIdGenerator* clause_id_generator_;
343 LratProofHandler* lrat_proof_handler_;
344 DelayedRootLevelDeduction* delayed_to_fix_;
345 const IntegerDomains& domains_;
346
347 bool add_implications_ = true;
348 int64_t num_created_variables_ = 0;
349
350 // We keep all the literals associated to an Integer variable in a map ordered
351 // by bound (so we can properly add implications between the literals
352 // corresponding to the same variable).
353 //
354 // Note that we only keep this for positive variable.
355 // The one for the negation can be inferred by it.
356 //
357 // Like x >= 1 x >= 4 x >= 5
358 // Correspond to x <= 0 x <= 3 x <= 4
359 // That is -x >= 0 -x >= -2 -x >= -4
360 //
361 // With potentially stronger <= bound if we fall into domain holes.
362 //
363 // TODO(user): Remove the entry no longer needed because of level zero
364 // propagations.
365 util_intops::StrongVector<PositiveOnlyIndex,
366 absl::btree_map<IntegerValue, Literal>>
367 encoding_by_var_;
368
369 // Store for a given LiteralIndex the list of its associated IntegerLiterals.
370 const InlinedIntegerLiteralVector empty_integer_literal_vector_;
372 reverse_encoding_;
373 const InlinedIntegerValueVector empty_integer_value_vector_;
375 reverse_equality_encoding_;
376
377 // Used by GetAllAssociatedVariables().
378 mutable std::vector<IntegerVariable> temp_associated_vars_;
379
380 // Store for a given LiteralIndex its IntegerVariable view or kNoVariableIndex
381 // if there is none. Note that only positive IntegerVariable will appear here.
383
384 // Mapping (variable == value) -> associated literal. Note that even if
385 // there is more than one literal associated to the same fact, we just keep
386 // the first one that was added.
387 //
388 // Note that we only keep positive IntegerVariable here to reduce memory
389 // usage.
390 absl::flat_hash_map<std::pair<PositiveOnlyIndex, IntegerValue>, Literal>
391 equality_to_associated_literal_;
392
393 // Mutable because this is lazily cleaned-up by PartialDomainEncoding().
394 mutable util_intops::StrongVector<PositiveOnlyIndex,
395 absl::InlinedVector<ValueLiteralPair, 2>>
396 equality_by_var_;
397
398 // Variables that are fully encoded.
400
401 // A literal that is always true, convenient to encode trivial domains.
402 // This will be lazily created when needed.
403 LiteralIndex literal_index_true_ = kNoLiteralIndex;
404
405 // Temporary memory used by FullyEncodeVariable().
406 std::vector<IntegerValue> tmp_values_;
407 std::vector<ValueLiteralPair> tmp_encoding_;
408
409 // Temporary memory for the result of PartialDomainEncoding().
410 mutable std::vector<ValueLiteralPair> partial_encoding_;
411};
412
413// The reason is the union of all of these fact.
414//
415// WARNING: the Span<> will not be valid forever, so this IntegerReason
416// class should just be used temporarily during conflict resolution, and not
417// keep in persistent storage.
419 void clear() {
421 slack = 0;
422
425 integer_literals = {};
426 vars = {};
427 coeffs = {};
428 }
429
430 bool empty() const {
431 return boolean_literals_at_true.empty() &&
432 boolean_literals_at_false.empty() && integer_literals.empty() &&
433 vars.empty();
434 }
435
436 // Note the integer_literals are always "true". But for Booleans, we support
437 // both specification. Just listing true literals make more sense, but
438 // historically in the SAT world, a span into (n - 1) literals of a clause is
439 // used as a reason, where all the literals there are false.
440 absl::Span<const Literal> boolean_literals_at_true;
441 absl::Span<const Literal> boolean_literals_at_false;
442 absl::Span<const IntegerLiteral> integer_literals;
443
444 // Expresses the fact that the propagated_i_lit is true assuming the lower
445 // bound for all variables in the linear expression at the time of
446 // @index_at_propagation and the reasons above.
447 //
448 // WARNING: to avoid copying stuff around, vars/coeffs will contain an entry
449 // for propagated_i_lit.var that should be ignored.
450 //
451 // The slack and individual coefficients indicate by how much the bounds at
452 // the time might be relaxed and still explain propagated_i_lit correctly.
454 IntegerValue slack;
456 absl::Span<const IntegerVariable> vars;
457 absl::Span<const IntegerValue> coeffs;
458};
459
461 public:
463 virtual ~LazyReasonInterface() = default;
464
465 virtual std::string LazyReasonName() const = 0;
466
467 // When called, this must fill the given reason (which is already cleared).
468 // Note that some fields of IntegerReason like index_at_propagation and
469 // propagated_i_lit are already filled.
470 //
471 // Remark: integer_literal[reason.index_at_propagation] might not exist or has
472 // nothing to do with what was propagated.
473 virtual void Explain(int id, IntegerLiteral to_explain,
474 IntegerReason* reason) = 0;
475};
476
477// This is used by the IntegerConflictResolution class.
478//
479// An ordered sequence of index, the "reason" for each index should be
480// a sequence of lower indices.
481//
482// TODO(user): We could use a single int32_t if we use a generic trail. Or
483// alternatively, push "place_holder" to the boolean trail. But for
484// non-chronological backtracking, having the assignment level here seems nice.
486 constexpr static int kNoIntegerIndex = std::numeric_limits<int>::max();
487
488 int level;
491
492 bool IsBoolean() const { return integer_index == kNoIntegerIndex; }
493 bool IsInteger() const { return integer_index != kNoIntegerIndex; }
494
495 // By convention, for all indices sharing the same bool_index, we need all
496 // IsInteger() indices to be before the unique IsBoolean() one.
497 bool operator<(const GlobalTrailIndex& o) const {
498 if (level != o.level) return level < o.level;
499 if (bool_index != o.bool_index) return bool_index < o.bool_index;
500 return integer_index < o.integer_index;
501 }
502
503 bool operator==(const GlobalTrailIndex& o) const {
504 return level == o.level && bool_index == o.bool_index &&
506 }
507
508 bool operator<=(const GlobalTrailIndex& o) const {
509 return *this == o || *this < o;
510 }
511
512 bool operator>=(const GlobalTrailIndex& o) const { return !(*this < o); }
513
514 bool operator>(const GlobalTrailIndex& o) const { return !(*this <= o); }
515};
516
517// Index used to store reasons.
519
520// This class maintains a set of integer variables with their current bounds.
521// Bounds can be propagated from an external "source" and this class helps
522// to maintain the reason for each propagation.
523class IntegerTrail final : public SatPropagator {
524 public:
525 explicit IntegerTrail(Model* model)
526 : SatPropagator("IntegerTrail"),
527 delayed_to_fix_(model->GetOrCreate<DelayedRootLevelDeduction>()),
528 domains_(model->GetOrCreate<IntegerDomains>()),
529 encoder_(model->GetOrCreate<IntegerEncoder>()),
530 trail_(model->GetOrCreate<Trail>()),
531 sat_solver_(model->GetOrCreate<SatSolver>()),
532 time_limit_(model->GetOrCreate<TimeLimit>()),
533 parameters_(*model->GetOrCreate<SatParameters>()) {
534 model->GetOrCreate<SatSolver>()->AddPropagator(this);
535 }
536
537 // This type is neither copyable nor movable.
538 IntegerTrail(const IntegerTrail&) = delete;
540 ~IntegerTrail() final;
541
542 // SatPropagator interface. These functions make sure the current bounds
543 // information is in sync with the current solver literal trail. Any
544 // class/propagator using this class must make sure it is synced to the
545 // correct state before calling any of its functions.
546 bool Propagate(Trail* trail) final;
547 void Untrail(const Trail& trail, int literal_trail_index) final;
548 absl::Span<const Literal> Reason(const Trail& trail, int trail_index,
549 int64_t conflict_id) const final;
550
551 // Warning the conflict is only set just after ReportConflict() was called
552 // here. It will be destroyed as soon as ReasonAsGlobalIndex() is used.
554 if (trail_->conflict_timestamp() != global_id_conflict_timestamp_) {
555 tmp_reason_.clear();
556 tmp_reason_.boolean_literals_at_false = trail_->FailingClause();
557 }
558 return tmp_reason_;
559 }
560
561 // Returns the reason for the propagation with given "global" index.
562 // This will correctly handle boolean/integer reasons.
563 //
564 // If index.IsInteger(), one can provide the bound that need to be explained,
565 // which might be lower than the one that was propagated.
567 GlobalTrailIndex index, std::optional<IntegerValue> needed_bound);
568
569 // Returns the number of created integer variables.
570 //
571 // Note that this is twice the number of call to AddIntegerVariable() since
572 // we automatically create the NegationOf() variable too.
573 IntegerVariable NumIntegerVariables() const {
574 return IntegerVariable(var_lbs_.size());
575 }
576
577 // Optimization: you can call this before calling AddIntegerVariable()
578 // num_vars time.
579 void ReserveSpaceForNumVariables(int num_vars);
580
581 // Adds a new integer variable. Adding integer variable can only be done when
582 // the decision level is zero (checked). The given bounds are INCLUSIVE and
583 // must not cross.
584 //
585 // Note on integer overflow: 'upper_bound - lower_bound' must fit on an
586 // int64_t, this is DCHECKed. More generally, depending on the constraints
587 // that are added, the bounds magnitude must be small enough to satisfy each
588 // constraint overflow precondition.
589 IntegerVariable AddIntegerVariable(IntegerValue lower_bound,
590 IntegerValue upper_bound);
591
592 // Same as above but for a more complex domain specified as a sorted list of
593 // disjoint intervals. See the Domain class.
594 IntegerVariable AddIntegerVariable(const Domain& domain);
595
596 // Returns the initial domain of the given variable. Note that the min/max
597 // are updated with level zero propagation, but not holes.
598 const Domain& InitialVariableDomain(IntegerVariable var) const;
599
600 // Takes the intersection with the current initial variable domain.
601 //
602 // TODO(user): There is some memory inefficiency if this is called many time
603 // because of the underlying data structure we use. In practice, when used
604 // with a presolve, this is not often used, so that is fine though.
605 bool UpdateInitialDomain(IntegerVariable var, Domain domain);
606
607 // Same as AddIntegerVariable(value, value), but this is a bit more efficient
608 // because it reuses another constant with the same value if its exist.
609 //
610 // Note(user): Creating constant integer variable is a bit wasteful, but not
611 // that much, and it allows to simplify a lot of constraints that do not need
612 // to handle this case any differently than the general one. Maybe there is a
613 // better solution, but this is not really high priority as of December 2016.
614 IntegerVariable GetOrCreateConstantIntegerVariable(IntegerValue value);
615 int NumConstantVariables() const;
616
617 // Same as AddIntegerVariable() but uses the maximum possible range. Note
618 // that since we take negation of bounds in various places, we make sure that
619 // we don't have overflow when we take the negation of the lower bound or of
620 // the upper bound.
624
625 // Returns the current lower/upper bound of the given integer variable.
626 IntegerValue LowerBound(IntegerVariable i) const;
627 IntegerValue UpperBound(IntegerVariable i) const;
628
629 // If one needs to do a lot of LowerBound()/UpperBound() it will be faster
630 // to cache the current pointer to the underlying vector.
631 const IntegerValue* LowerBoundsData() const { return var_lbs_.data(); }
632
633 // Checks if the variable is fixed.
634 bool IsFixed(IntegerVariable i) const;
635
636 // Checks that the variable is fixed and returns its value.
637 IntegerValue FixedValue(IntegerVariable i) const;
638
639 // Same as above for an affine expression.
640 IntegerValue LowerBound(AffineExpression expr) const;
641 IntegerValue UpperBound(AffineExpression expr) const;
642 IntegerValue UpperBound(LinearExpression2 expr) const;
643 bool IsFixed(AffineExpression expr) const;
644 IntegerValue FixedValue(AffineExpression expr) const;
645
646 // Returns the integer literal that represent the current lower/upper bound of
647 // the given integer variable.
648 IntegerLiteral LowerBoundAsLiteral(IntegerVariable i) const;
649 IntegerLiteral UpperBoundAsLiteral(IntegerVariable i) const;
650
651 // Returns the integer literal that represent the current lower/upper bound of
652 // the given affine expression. In case the expression is constant, it returns
653 // IntegerLiteral::TrueLiteral().
656
657 // Returns the current value (if known) of an IntegerLiteral.
660 bool IsTrueAtLevelZero(IntegerLiteral l) const;
661
662 // Returns globally valid lower/upper bound on the given integer variable.
663 IntegerValue LevelZeroLowerBound(IntegerVariable var) const;
664 IntegerValue LevelZeroUpperBound(IntegerVariable var) const;
665
666 // Returns globally valid lower/upper bound on the given affine expression.
667 IntegerValue LevelZeroLowerBound(AffineExpression exp) const;
668 IntegerValue LevelZeroUpperBound(AffineExpression exp) const;
669
670 // Returns globally valid lower/upper bound on the given linear expression.
671 IntegerValue LevelZeroLowerBound(LinearExpression2 expr) const;
672 IntegerValue LevelZeroUpperBound(LinearExpression2 expr) const;
673
674 // Returns true if the variable is fixed at level 0.
675 bool IsFixedAtLevelZero(IntegerVariable var) const;
676
677 // Returns true if the affine expression is fixed at level 0.
678 bool IsFixedAtLevelZero(AffineExpression expr) const;
679
680 // Advanced usage.
681 // Returns the current lower bound assuming the literal is true.
682 IntegerValue ConditionalLowerBound(Literal l, IntegerVariable i) const;
683 IntegerValue ConditionalLowerBound(Literal l, AffineExpression expr) const;
684
685 // Returns the current upper bound assuming the literal is true.
686 IntegerValue ConditionalUpperBound(Literal l, IntegerVariable i) const;
687 IntegerValue ConditionalUpperBound(Literal l, AffineExpression expr) const;
688
689 // Advanced usage. Given the reason for
690 // (Sum_i coeffs[i] * reason[i].var >= current_lb) initially in reason,
691 // this function relaxes the reason given that we only need the explanation of
692 // (Sum_i coeffs[i] * reason[i].var >= current_lb - slack).
693 //
694 // Preconditions:
695 // - coeffs must be of same size as reason, and all entry must be positive.
696 // - *reason must initially contains the trivial initial reason, that is
697 // the current lower-bound of each variables.
698 //
699 // TODO(user): Requiring all initial literal to be at their current bound is
700 // not really clean. Maybe we can change the API to only take IntegerVariable
701 // and produce the reason directly.
702 //
703 // TODO(user): change API so that this work is performed during the conflict
704 // analysis where we can be smarter in how we relax the reason. Note however
705 // that this function is mainly used when we have a conflict, so this is not
706 // really high priority.
707 //
708 // TODO(user): Test that the code work in the presence of integer overflow.
709 void RelaxLinearReason(IntegerValue slack,
710 absl::Span<const IntegerValue> coeffs,
711 std::vector<IntegerLiteral>* reason) const;
712
713 // Same as above but take in IntegerVariables instead of IntegerLiterals.
714 void AppendRelaxedLinearReason(IntegerValue slack,
715 absl::Span<const IntegerValue> coeffs,
716 absl::Span<const IntegerVariable> vars,
717 std::vector<IntegerLiteral>* reason) const;
718
719 // Same as above but relax the given trail indices.
720 void RelaxLinearReason(IntegerValue slack,
721 absl::Span<const IntegerValue> coeffs,
722 std::vector<int>* trail_indices) const;
723
724 // Removes from the reasons the literal that are always true.
725 // This is mainly useful for experiments/testing.
726 void RemoveLevelZeroBounds(std::vector<IntegerLiteral>* reason) const;
727
728 // Enqueue new information about a variable bound. Calling this with a less
729 // restrictive bound than the current one will have no effect.
730 //
731 // The reason for this "assignment" must be provided as:
732 // - A set of Literal currently being all false.
733 // - A set of IntegerLiteral currently being all true.
734 //
735 // IMPORTANT: Notice the inversed sign in the literal reason. This is a bit
736 // confusing but internally SAT use this direction for efficiency.
737 //
738 // Note(user): Duplicates Literal/IntegerLiteral are supported because we call
739 // STLSortAndRemoveDuplicates() in MergeReasonInto(), but maybe they shouldn't
740 // for efficiency reason.
741 //
742 // TODO(user): If the given bound is equal to the current bound, maybe the new
743 // reason is better? how to decide and what to do in this case? to think about
744 // it. Currently we simply don't do anything.
745 ABSL_MUST_USE_RESULT bool Enqueue(IntegerLiteral i_lit) {
746 return EnqueueInternal(i_lit, false, {}, {});
747 }
748 ABSL_MUST_USE_RESULT bool Enqueue(
749 IntegerLiteral i_lit, absl::Span<const Literal> literal_reason,
750 absl::Span<const IntegerLiteral> integer_reason) {
751 return EnqueueInternal(i_lit, false, literal_reason, integer_reason);
752 }
753
754 // Enqueue new information about a variable bound. It has the same behavior
755 // as the Enqueue() method, except that it accepts true and false integer
756 // literals, both for i_lit, and for the integer reason.
757 //
758 // This method will do nothing if i_lit is a true literal. It will report a
759 // conflict if i_lit is a false literal, and enqueue i_lit normally otherwise.
760 // Furthemore, it will check that the integer reason does not contain any
761 // false literals, and will remove true literals before calling
762 // ReportConflict() or Enqueue().
763 ABSL_MUST_USE_RESULT bool SafeEnqueue(
764 IntegerLiteral i_lit, absl::Span<const IntegerLiteral> integer_reason);
765 ABSL_MUST_USE_RESULT bool SafeEnqueue(
766 IntegerLiteral i_lit, absl::Span<const Literal> literal_reason,
767 absl::Span<const IntegerLiteral> integer_reason);
768
769 // Pushes the given integer literal assuming that the Boolean literal is true.
770 // This can do a few things:
771 // - If lit it true, add it to the reason and push the integer bound.
772 // - If the bound is infeasible, push lit to false.
773 // - If the underlying variable is optional and also controlled by lit, push
774 // the bound even if lit is not assigned.
775 ABSL_MUST_USE_RESULT bool ConditionalEnqueue(
776 Literal lit, IntegerLiteral i_lit, std::vector<Literal>* literal_reason,
777 std::vector<IntegerLiteral>* integer_reason);
778
779 // Same as Enqueue(), but takes an extra argument which if smaller than
780 // integer_trail_.size() is interpreted as the trail index of an old Enqueue()
781 // that had the same reason as this one. Note that the given Span must still
782 // be valid as they are used in case of conflict.
783 //
784 // TODO(user): This currently cannot refer to a trail_index with a lazy
785 // reason. Fix or at least check that this is the case.
786 ABSL_MUST_USE_RESULT bool Enqueue(
787 IntegerLiteral i_lit, absl::Span<const Literal> literal_reason,
788 absl::Span<const IntegerLiteral> integer_reason,
789 int trail_index_with_same_reason) {
790 return EnqueueInternal(i_lit, false, literal_reason, integer_reason,
791 trail_index_with_same_reason);
792 }
793
794 // Lazy reason API.
795 ABSL_MUST_USE_RESULT bool EnqueueWithLazyReason(
796 IntegerLiteral i_lit, int id, IntegerValue propagation_slack,
797 LazyReasonInterface* explainer) {
798 const int trail_index = integer_trail_.size();
799 lazy_reasons_.push_back(
800 LazyReasonEntry{explainer, propagation_slack, i_lit, id, trail_index});
801 return EnqueueInternal(i_lit, true, {}, {});
802 }
803
804 // These temporary vector can be used by the lazy reason explainer to fill
805 // the IntegerReason spans. Note that we clear them on each call.
806 std::vector<Literal>& ClearedMutableTmpLiterals() {
807 tmp_lazy_reason_boolean_literals_.clear();
808 return tmp_lazy_reason_boolean_literals_;
809 }
810 std::vector<IntegerLiteral>& ClearedMutableTmpIntegerLiterals() {
811 tmp_lazy_reason_integer_literals_.clear();
812 return tmp_lazy_reason_integer_literals_;
813 }
814
815 // Sometimes we infer some root level bounds but we are not at the root level.
816 // In this case, we will update the level-zero bounds right away, but will
817 // delay the current push until the next restart.
818 //
819 // Note that if you want to also push the literal at the current level, then
820 // just calling Enqueue() is enough. Since there is no reason, the literal
821 // will still be recorded properly.
822 ABSL_MUST_USE_RESULT bool RootLevelEnqueue(IntegerLiteral i_lit);
823
824 // Enqueues the given literal on the trail.
825 // See the comment of Enqueue() for the reason format.
826 ABSL_MUST_USE_RESULT bool EnqueueLiteral(
827 Literal literal, absl::Span<const Literal> literal_reason,
828 absl::Span<const IntegerLiteral> integer_reason);
829
830 ABSL_MUST_USE_RESULT bool SafeEnqueueLiteral(
831 Literal literal, absl::Span<const Literal> literal_reason,
832 absl::Span<const IntegerLiteral> integer_reason);
833
834 // Returns the reason (as set of Literal currently false) for a given integer
835 // literal. Note that the bound must be less restrictive than the current
836 // bound (checked).
837 std::vector<Literal> ReasonFor(IntegerLiteral literal) const;
838
839 // Appends the reason for the given integer literals to the output and call
840 // STLSortAndRemoveDuplicates() on it. This function accept "constant"
841 // literal.
842 void MergeReasonInto(absl::Span<const IntegerLiteral> literals,
843 std::vector<Literal>* output) const;
844
845 // Returns the number of enqueues that changed a variable bounds. We don't
846 // count enqueues called with a less restrictive bound than the current one.
847 //
848 // Note(user): this can be used to see if any of the bounds changed. Just
849 // looking at the integer trail index is not enough because at level zero it
850 // doesn't change since we directly update the "fixed" bounds.
851 int64_t num_enqueues() const { return num_enqueues_; }
852 int64_t timestamp() const { return num_enqueues_ + num_untrails_; }
853
854 // Same as num_enqueues but only count the level zero changes.
855 int64_t num_level_zero_enqueues() const { return num_level_zero_enqueues_; }
856
857 // All the registered bitsets will be set to one each time a LbVar is
858 // modified. It is up to the client to clear it if it wants to be notified
859 // with the newly modified variables.
862 watchers_.push_back(p);
863 }
864
865 IntegerVariable VarAtIndex(int integer_trail_index) const {
866 return integer_trail_[integer_trail_index].var;
867 }
868 IntegerLiteral IntegerLiteralAtIndex(int integer_trail_index) const {
870 integer_trail_[integer_trail_index].var,
871 integer_trail_[integer_trail_index].bound);
872 }
873 int GetFirstIndexBefore(IntegerVariable var, GlobalTrailIndex source_index,
874 int starting_integer_index) {
875 CHECK_GE(var, 0);
876 CHECK_LT(var, var_trail_index_.size());
877 int index = std::min(starting_integer_index, var_trail_index_[var]);
878 while (true) {
879 // Did we reach root level?
880 if (index < static_cast<int>(var_lbs_.size())) return -1;
881 CHECK_LT(index, integer_trail_.size());
882 CHECK_EQ(integer_trail_[index].var, var);
883 if (GlobalIndexAt(index) < source_index) return index;
884 index = integer_trail_[index].prev_trail_index;
885 }
886 }
887 int PreviousTrailIndex(int integer_trail_index) const {
888 if (integer_trail_index < var_lbs_.size()) {
889 CHECK_EQ(integer_trail_[integer_trail_index].prev_trail_index, -1);
890 }
891 return integer_trail_[integer_trail_index].prev_trail_index;
892 }
893 GlobalTrailIndex GlobalIndexAt(int integer_index) const {
894 CHECK_GE(integer_index, var_lbs_.size());
895 CHECK_NE(integer_trail_[integer_index].var, kNoIntegerVariable);
896
897 const auto& entry = extra_trail_info_[integer_index];
898 CHECK_NE(entry.assignment_level, 0);
899 return GlobalTrailIndex{entry.assignment_level, entry.bool_trail_index,
900 integer_index};
901 }
902
903 // Helper functions to report a conflict. Always return false so a client can
904 // simply do: return integer_trail_->ReportConflict(...);
905 bool ReportConflict(absl::Span<const Literal> literal_reason,
906 absl::Span<const IntegerLiteral> integer_reason) {
907 DCHECK(ReasonIsValid(IntegerLiteral::FalseLiteral(), literal_reason,
908 integer_reason));
909 std::vector<Literal>* conflict = trail_->MutableConflict();
910 if (new_conflict_resolution_) {
911 global_id_conflict_timestamp_ = trail_->conflict_timestamp();
912
913 // Copy.
914 tmp_reason_.clear();
915 tmp_literal_reason_.assign(literal_reason.begin(), literal_reason.end());
916 tmp_integer_reason_.assign(integer_reason.begin(), integer_reason.end());
917 tmp_reason_.boolean_literals_at_false = tmp_literal_reason_;
918 tmp_reason_.integer_literals = tmp_integer_reason_;
919 return false;
920 }
921
922 conflict->assign(literal_reason.begin(), literal_reason.end());
923 MergeReasonInto(integer_reason, conflict);
924 return false;
925 }
926 bool ReportConflict(absl::Span<const IntegerLiteral> integer_reason) {
927 return ReportConflict({}, integer_reason);
928 }
929
930 // Returns true if the variable lower bound is still the one from level zero.
931 bool VariableLowerBoundIsFromLevelZero(IntegerVariable var) const {
932 return var_trail_index_[var] < var_lbs_.size();
933 }
934
935 // Registers a reversible class. This class will always be synced with the
936 // correct decision level.
938 reversible_classes_.push_back(rev);
939 }
940
941 int Index() const { return integer_trail_.size(); }
942
943 // Inspects the trail and output all the non-level zero bounds (one per
944 // variables) to the output. The algo is sparse if there is only a few
945 // propagations on the trail.
946 void AppendNewBounds(std::vector<IntegerLiteral>* output) const;
947
948 // Inspects the trail and output all the non-level zero bounds from the base
949 // index (one per variables) to the output. The algo is sparse if there is
950 // only a few propagations on the trail.
951 void AppendNewBoundsFrom(int base_index,
952 std::vector<IntegerLiteral>* output) const;
953
954 // Returns the trail index < threshold of a TrailEntry about var. Returns -1
955 // if there is no such entry (at a positive decision level). This is basically
956 // the trail index of the lower bound of var at the time.
957 //
958 // Important: We do some optimization internally, so this should only be
959 // used from within a LazyReasonFunction().
960 int FindTrailIndexOfVarBefore(IntegerVariable var, int threshold) const;
961
962 // Basic heuristic to detect when we are in a propagation loop, and suggest
963 // a good variable to branch on (taking the middle value) to get out of it.
964 bool InPropagationLoop() const;
966 IntegerVariable NextVariableToBranchOnInPropagationLoop() const;
967
968 // If we had an incomplete propagation, it is important to fix all the
969 // variables and not really on the propagation to do so. This is related to
970 // the InPropagationLoop() code above.
972 IntegerVariable FirstUnassignedVariable() const;
973
974 // Return true if we can fix new fact at level zero.
976 return !delayed_to_fix_->literal_to_fix.empty() ||
977 !delayed_to_fix_->integer_literal_to_fix.empty();
978 }
979
980 // If this is set, and in debug mode, we will call this on all conflict to
981 // be checked for potential issue. Usually against a known optimal solution.
983 std::function<bool(absl::Span<const Literal> clause,
984 absl::Span<const IntegerLiteral> integers)>
985 checker) {
986 debug_checker_ = std::move(checker);
987 }
988
989 // Tricky: we cannot rely on the parameters
990 // use_new_integer_conflict_resolution, because they are many codepath when
991 // the IntegerConflictResolution class is not yet registered, like in
992 // presolve.
993 //
994 // TODO(user): Ideally if the parameter is on, we should just use it
995 // everywhere, find a way.
996 void UseNewConflictResolution() { new_conflict_resolution_ = true; }
997
998 // Saves the given reason and returns a new reason index.
999 // The content can be retrieved by the ReasonAsSpan() functions as long as
1000 // the reason index is valid.
1001 //
1002 // Warning: a reason_index is only valid until we backtrack over it, at which
1003 // time the memory used by the reason will be reclaimed.
1004 //
1005 // This is mostly an internal API, but it is exposed so that we can store
1006 // payload in a lazy reasons.
1008 absl::Span<const Literal> literal_reason,
1009 absl::Span<const IntegerLiteral> integer_reason);
1010 absl::Span<const IntegerLiteral> IntegerReasonAsSpan(ReasonIndex index) const;
1011 absl::Span<const Literal> LiteralReasonAsSpan(ReasonIndex index) const;
1012
1013 private:
1014 // All integer_trail_.push_back() should go through this.
1015 void PushOnTrail(IntegerLiteral i_lit, int prev_trail_index,
1016 int bool_trail_index, ReasonIndex reason_index,
1017 int assignment_level);
1018
1019 // Used for DHECKs to validate the reason given to the public functions above.
1020 // Tests that all Literal are false. Tests that all IntegerLiteral are true.
1021 bool ReasonIsValid(absl::Span<const Literal> literal_reason,
1022 absl::Span<const IntegerLiteral> integer_reason);
1023
1024 // Same as above, but with the literal for which this is the reason for.
1025 bool ReasonIsValid(Literal lit, absl::Span<const Literal> literal_reason,
1026 absl::Span<const IntegerLiteral> integer_reason);
1027 bool ReasonIsValid(IntegerLiteral i_lit,
1028 absl::Span<const Literal> literal_reason,
1029 absl::Span<const IntegerLiteral> integer_reason);
1030
1031 // If the variable has holes in its domain, make sure the literal is
1032 // canonicalized.
1033 void CanonicalizeLiteralIfNeeded(IntegerLiteral* i_lit);
1034
1035 // Called by the Enqueue() functions that detected a conflict. This does some
1036 // common conflict initialization that must terminate by a call to
1037 // MergeReasonIntoInternal(conflict) where conflict is the returned vector.
1038 std::vector<Literal>* InitializeConflict(
1039 IntegerLiteral integer_literal, bool use_lazy_reason,
1040 absl::Span<const Literal> literals_reason,
1041 absl::Span<const IntegerLiteral> bounds_reason);
1042
1043 // Internal implementation of the different public Enqueue() functions.
1044 ABSL_MUST_USE_RESULT bool EnqueueInternal(
1045 IntegerLiteral i_lit, bool use_lazy_reason,
1046 absl::Span<const Literal> literal_reason,
1047 absl::Span<const IntegerLiteral> integer_reason,
1048 int trail_index_with_same_reason = std::numeric_limits<int>::max());
1049
1050 // Internal implementation of the EnqueueLiteral() functions.
1051 ABSL_MUST_USE_RESULT bool EnqueueLiteralInternal(
1052 Literal literal, bool use_lazy_reason,
1053 absl::Span<const Literal> literal_reason,
1054 absl::Span<const IntegerLiteral> integer_reason);
1055
1056 // Same as EnqueueInternal() but for the case where we push an IntegerLiteral
1057 // because an associated Literal is true (and we know it). In this case, we
1058 // have less work to do, so this has the same effect but is faster.
1059 ABSL_MUST_USE_RESULT bool EnqueueAssociatedIntegerLiteral(
1060 IntegerLiteral i_lit, Literal literal_reason);
1061
1062 // Does the work of MergeReasonInto() when queue_ is already initialized.
1063 void MergeReasonIntoInternal(std::vector<Literal>* output,
1064 int64_t conflict_id) const;
1065
1066 // Returns the lowest trail index of a TrailEntry that can be used to explain
1067 // the given IntegerLiteral. The literal must be currently true but not true
1068 // at level zero (DCHECKed).
1069 int FindLowestTrailIndexThatExplainBound(IntegerLiteral i_lit) const;
1070
1071 // This must be called before Dependencies() or AppendLiteralsReason().
1072 //
1073 // TODO(user): Not really robust, try to find a better way.
1074 void ComputeLazyReasonIfNeeded(ReasonIndex index) const;
1075
1076 // Helper function to return the "dependencies" of a bound assignment.
1077 // All the TrailEntry at these indices are part of the reason for this
1078 // assignment.
1079 //
1080 // Important: The returned Span is only valid up to the next call.
1081 absl::Span<const int> Dependencies(ReasonIndex index) const;
1082
1083 // Helper function to append the Literal part of the reason for this bound
1084 // assignment. We use added_variables_ to not add the same literal twice.
1085 // Note that looking at literal.Variable() is enough since all the literals
1086 // of a reason must be false.
1087 void AppendLiteralsReason(ReasonIndex index,
1088 std::vector<Literal>* output) const;
1089
1090 // Returns some debugging info.
1091 std::string DebugString();
1092
1093 // Information for each integer variable about its current lower bound and
1094 // position of the last TrailEntry in the trail referring to this var.
1097
1098 // This is used by FindLowestTrailIndexThatExplainBound() and
1099 // FindTrailIndexOfVarBefore() to speed up the lookup. It keeps a trail index
1100 // for each variable that may or may not point to a TrailEntry regarding this
1101 // variable. The validity of the index is verified before being used.
1102 //
1103 // The cache will only be updated with trail_index >= threshold.
1104 mutable int var_trail_index_cache_threshold_ = 0;
1106 var_trail_index_cache_;
1107
1108 // Used by GetOrCreateConstantIntegerVariable() to return already created
1109 // constant variables that share the same value.
1110 absl::flat_hash_map<IntegerValue, IntegerVariable> constant_map_;
1111
1112 // The integer trail. It always start by num_vars sentinel values with the
1113 // level 0 bounds (in one to one correspondence with var_lbs_).
1114 struct TrailEntry {
1115 IntegerValue bound;
1116 IntegerVariable var;
1117 int32_t prev_trail_index = -1;
1118
1119 // Index in literals_reason_start_/bounds_reason_starts_ If this is negative
1120 // then it is a lazy reason.
1121 ReasonIndex reason_index = ReasonIndex(0);
1122 };
1123 std::vector<TrailEntry> integer_trail_;
1124
1125 // trail->CurrentDecisionLevel() and trail_->Index() at the time this entry
1126 // was added. This is only used when use_new_integer_conflict_resolution is
1127 // true.
1128 struct ExtraTrailEntry {
1129 int32_t assignment_level;
1130 int32_t bool_trail_index;
1131 };
1132 std::vector<ExtraTrailEntry> extra_trail_info_;
1133
1134 struct LazyReasonEntry {
1135 LazyReasonInterface* explainer;
1136 IntegerValue propagation_slack;
1137 IntegerLiteral propagated_i_lit;
1138 int id;
1139 int trail_index_at_propagation_time;
1140
1141 // TODO(user): I am not sure we need to store
1142 // trail_index_at_propagation_time as we will know it when we call this
1143 // Explain function. Make sure this is the case and just clean this up.
1144 // We can assume the info refer the time when this entry was added.
1145 void Explain(IntegerValue bound_to_explain, IntegerReason* reason) const {
1146 DCHECK_LE(bound_to_explain, propagated_i_lit.bound);
1147 reason->clear();
1148 reason->slack = propagation_slack;
1149 reason->propagated_i_lit = propagated_i_lit;
1150 reason->index_at_propagation = trail_index_at_propagation_time;
1151 explainer->Explain(id,
1152 IntegerLiteral::GreaterOrEqual(propagated_i_lit.var,
1153 bound_to_explain),
1154 reason);
1155 }
1156
1157 void Explain(IntegerReason* reason) const {
1158 Explain(propagated_i_lit.bound, reason);
1159 }
1160 };
1161 std::vector<int> lazy_reason_decision_levels_;
1162 util_intops::StrongVector<ReasonIndex, LazyReasonEntry> lazy_reasons_;
1163
1164 // Start of each decision levels in integer_trail_.
1165 // TODO(user): use more general reversible mechanism?
1166 std::vector<int> integer_search_levels_;
1167
1168 // Buffer to store the reason of each trail entry.
1169 std::vector<ReasonIndex> reason_decision_levels_;
1170 util_intops::StrongVector<ReasonIndex, int> literals_reason_starts_;
1171 std::vector<Literal> literals_reason_buffer_;
1172
1173 // The last two vectors are in one to one correspondence. Dependencies() will
1174 // "cache" the result of the conversion from IntegerLiteral to trail indices
1175 // in trail_index_reason_buffer_.
1176 util_intops::StrongVector<ReasonIndex, int> bounds_reason_starts_;
1177 mutable util_intops::StrongVector<ReasonIndex, int> cached_sizes_;
1178 std::vector<IntegerLiteral> bounds_reason_buffer_;
1179 mutable std::vector<int> trail_index_reason_buffer_;
1180
1181 // Temporary data for IntegerReason.
1182 IntegerReason tmp_reason_;
1183 std::vector<Literal> tmp_lazy_reason_boolean_literals_;
1184 std::vector<IntegerLiteral> tmp_lazy_reason_integer_literals_;
1185
1186 // Temporary for use with tmp_reason_.
1187 // Tricky: these cannot be the same as the one used by lazy reason.
1188 std::vector<Literal> tmp_boolean_literals_;
1189 std::vector<IntegerLiteral> tmp_integer_literals_;
1190
1191 // Temporary vector filled by calls to LazyReasonFunction().
1192 mutable IntegerReason tmp_lazy_reason_;
1193 mutable std::vector<Literal> lazy_reason_literals_;
1194 mutable std::vector<int> lazy_reason_trail_indices_;
1195 mutable std::vector<int> tmp_trail_indices_;
1196 mutable std::vector<IntegerValue> tmp_coeffs_;
1197
1198 // Temporary data used by MergeReasonInto().
1199 mutable bool has_dependency_ = false;
1200 mutable std::vector<int> tmp_queue_;
1201 mutable std::vector<IntegerVariable> tmp_to_clear_;
1202 mutable util_intops::StrongVector<IntegerVariable, int>
1203 tmp_var_to_trail_index_in_queue_;
1204 mutable SparseBitset<BooleanVariable> added_variables_;
1205
1206 // Temporary heap used by RelaxLinearReason();
1207 struct RelaxHeapEntry {
1208 int index;
1209 IntegerValue coeff;
1210 int64_t diff;
1211 bool operator<(const RelaxHeapEntry& o) const { return index < o.index; }
1212 };
1213 mutable std::vector<RelaxHeapEntry> relax_heap_;
1214 mutable std::vector<int> tmp_indices_;
1215
1216 // Temporary data used by AppendNewBounds().
1217 mutable SparseBitset<IntegerVariable> tmp_marked_;
1218
1219 // Temporary data used by SafeEnqueue();
1220 std::vector<IntegerLiteral> tmp_cleaned_reason_;
1221
1222 // For EnqueueLiteral(), we store the reason index at its Boolean trail index.
1223 std::vector<ReasonIndex> boolean_trail_index_to_reason_index_;
1224
1225 // We need to know if we skipped some propagation in the current branch.
1226 // This is reverted as we backtrack over it.
1227 int first_level_without_full_propagation_ = -1;
1228
1229 // This is used to detect when MergeReasonIntoInternal() is called multiple
1230 // time while processing the same conflict. It allows to optimize the reason
1231 // and the time taken to compute it.
1232 mutable int64_t last_conflict_id_ = -1;
1233 mutable bool info_is_valid_on_subsequent_last_level_expansion_ = false;
1234 mutable util_intops::StrongVector<IntegerVariable, int>
1235 var_to_trail_index_at_lower_level_;
1236 mutable std::vector<int> tmp_seen_;
1237 mutable std::vector<IntegerVariable> to_clear_for_lower_level_;
1238
1239 int64_t global_id_conflict_timestamp_ = 0;
1240 int64_t num_enqueues_ = 0;
1241 int64_t num_untrails_ = 0;
1242 int64_t num_level_zero_enqueues_ = 0;
1243 mutable int64_t num_decisions_to_break_loop_ = 0;
1244
1245 std::vector<SparseBitset<IntegerVariable>*> watchers_;
1246 std::vector<ReversibleInterface*> reversible_classes_;
1247
1248 mutable int64_t work_done_in_find_indices_ = 0;
1249
1250 mutable Domain temp_domain_;
1251 DelayedRootLevelDeduction* delayed_to_fix_;
1252 IntegerDomains* domains_;
1253 IntegerEncoder* encoder_;
1254 Trail* trail_;
1255 SatSolver* sat_solver_;
1256 TimeLimit* time_limit_;
1257 const SatParameters& parameters_;
1258
1259 bool new_conflict_resolution_ = false;
1260
1261 std::vector<Literal> tmp_literal_reason_;
1262 std::vector<IntegerLiteral> tmp_integer_reason_;
1263
1264 // Temporary "hash" to keep track of all the conditional enqueue that were
1265 // done. Note that we currently do not keep any reason for them, and as such,
1266 // we can only use this in heuristics. See ConditionalLowerBound().
1267 absl::flat_hash_map<std::pair<LiteralIndex, IntegerVariable>, IntegerValue>
1268 conditional_lbs_;
1269
1270 std::function<bool(absl::Span<const Literal> clause,
1271 absl::Span<const IntegerLiteral> integers)>
1272 debug_checker_ = nullptr;
1273};
1274
1275// Base class for CP like propagators.
1277 public:
1279 virtual ~PropagatorInterface() = default;
1280
1281 // This will be called after one or more literals that are watched by this
1282 // propagator changed. It will also always be called on the first propagation
1283 // cycle after registration.
1284 virtual bool Propagate() = 0;
1285
1286 // This will only be called on a non-empty vector, otherwise Propagate() will
1287 // be called. The passed vector will contain the "watch index" of all the
1288 // literals that were given one at registration and that changed since the
1289 // last call to Propagate(). This is only true when going down in the search
1290 // tree, on backjump this list will be cleared.
1291 //
1292 // Notes:
1293 // - The indices may contain duplicates if the same integer variable as been
1294 // updated many times or if different watched literals have the same
1295 // watch_index.
1296 // - At level zero, it will not contain any indices associated with literals
1297 // that were already fixed when the propagator was registered. Only the
1298 // indices of the literals modified after the registration will be present.
1299 virtual bool IncrementalPropagate(const std::vector<int>& /*watch_indices*/) {
1300 LOG(FATAL) << "Not implemented.";
1301 return false; // Remove warning in Windows
1302 }
1303};
1304
1305// Singleton for basic reversible types. We need the wrapper so that they can be
1306// accessed with model->GetOrCreate<>() and properly registered at creation.
1307class RevIntRepository : public RevRepository<int> {
1308 public:
1309 explicit RevIntRepository(Model* model) {
1310 model->GetOrCreate<IntegerTrail>()->RegisterReversibleClass(this);
1311 }
1312};
1313class RevIntegerValueRepository : public RevRepository<IntegerValue> {
1314 public:
1316 model->GetOrCreate<IntegerTrail>()->RegisterReversibleClass(this);
1317 }
1318};
1319
1320// This class allows registering Propagator that will be called if a
1321// watched Literal or LbVar changes.
1322//
1323// TODO(user): Move this to its own file. Add unit tests!
1325 public:
1326 explicit GenericLiteralWatcher(Model* model);
1327
1328 // This type is neither copyable nor movable.
1331
1332 ~GenericLiteralWatcher() final = default;
1333
1334 // Memory optimization: you can call this before registering watchers.
1335 void ReserveSpaceForNumVariables(int num_vars);
1336
1337 // On propagate, the registered propagators will be called if they need to
1338 // until a fixed point is reached. Propagators with low ids will tend to be
1339 // called first, but it ultimately depends on their "waking" order.
1340 bool Propagate(Trail* trail) final;
1341 void Untrail(const Trail& trail, int literal_trail_index) final;
1342
1343 // Registers a propagator and returns its unique ids.
1344 int Register(PropagatorInterface* propagator);
1345
1346 // Changes the priority of the propagator with given id. The priority is a
1347 // non-negative integer. Propagators with a lower priority will always be
1348 // run before the ones with a higher one. The default priority is one.
1349 void SetPropagatorPriority(int id, int priority);
1350
1351 // The default behavior is to assume that a propagator does not need to be
1352 // called twice in a row. However, propagators on which this is called will be
1353 // called again if they change one of their own watched variables.
1355
1356 // Whether we call a propagator even if its watched variables didn't change.
1357 // This is only used when we are back to level zero. This was introduced for
1358 // the LP propagator where we might need to continue an interrupted solve or
1359 // add extra cuts at level zero.
1360 void AlwaysCallAtLevelZero(int id);
1361
1362 // Watches the corresponding quantity. The propagator with given id will be
1363 // called if it changes. Note that WatchLiteral() only trigger when the
1364 // literal becomes true.
1365 //
1366 // If watch_index is specified, it is associated with the watched literal.
1367 // Doing this will cause IncrementalPropagate() to be called (see the
1368 // documentation of this interface for more detail).
1369 void WatchLiteral(Literal l, int id, int watch_index = -1);
1370 void WatchLowerBound(IntegerVariable var, int id, int watch_index = -1);
1371 void WatchUpperBound(IntegerVariable var, int id, int watch_index = -1);
1372 void WatchIntegerVariable(IntegerVariable i, int id, int watch_index = -1);
1373
1374 // Because the coeff is always positive, watching an affine expression is
1375 // the same as watching its var.
1377 WatchLowerBound(e.var, id);
1378 }
1380 WatchUpperBound(e.var, id);
1381 }
1385
1386 // No-op overload for "constant" IntegerVariable that are sometimes templated
1387 // as an IntegerValue.
1388 void WatchLowerBound(IntegerValue /*i*/, int /*id*/) {}
1389 void WatchUpperBound(IntegerValue /*i*/, int /*id*/) {}
1390 void WatchIntegerVariable(IntegerValue /*v*/, int /*id*/) {}
1391
1392 // Registers a reversible class with a given propagator. This class will be
1393 // changed to the correct state just before the propagator is called.
1394 //
1395 // Doing it just before should minimize cache-misses and bundle as much as
1396 // possible the "backtracking" together. Many propagators only watches a
1397 // few variables and will not be called at each decision levels.
1399
1400 // Registers a reversible int with a given propagator. The int will be changed
1401 // to its correct value just before Propagate() is called.
1402 //
1403 // Note that this will work in O(num_rev_int_of_propagator_id) per call to
1404 // Propagate() and happens at most once per decision level. As such this is
1405 // meant for classes that have just a few reversible ints or that will have a
1406 // similar complexity anyway.
1407 //
1408 // Alternatively, one can directly get the underlying RevRepository<int> with
1409 // a call to model.Get<>(), and use SaveWithStamp() before each modification
1410 // to have just a slight overhead per int updates. This later option is what
1411 // is usually done in a CP solver at the cost of a slightly more complex API.
1412 void RegisterReversibleInt(int id, int* rev);
1413
1414 // A simple form of incremental update is to maintain state as we dive into
1415 // the search tree but forget everything on every backtrack. A propagator
1416 // can be called many times by decision, so this can make a large proportion
1417 // of the calls incremental.
1418 //
1419 // This allows to achieve this with a really low overhead.
1420 //
1421 // The propagator can define a bool rev_is_in_dive_ = false; and at the
1422 // beginning of each propagate do:
1423 // const bool no_backtrack_since_last_call = rev_is_in_dive_;
1424 // watcher_->SetUntilNextBacktrack(&rev_is_in_dive_);
1425 void SetUntilNextBacktrack(bool* is_in_dive) {
1426 if (!*is_in_dive) {
1427 *is_in_dive = true;
1428 bool_to_reset_on_backtrack_.push_back(is_in_dive);
1429 }
1430 }
1431
1432 // Returns the number of registered propagators.
1433 int NumPropagators() const { return in_queue_.size(); }
1434
1435 // Set a callback for new variable bounds at level 0.
1436 //
1437 // This will be called (only at level zero) with the list of IntegerVariable
1438 // with changed lower bounds. Note that it might be called more than once
1439 // during the same propagation cycle if we fix variables in "stages".
1440 //
1441 // Also note that this will be called if some BooleanVariable where fixed even
1442 // if no IntegerVariable are changed, so the passed vector to the function
1443 // might be empty.
1445 const std::function<void(const std::vector<IntegerVariable>&)> cb) {
1446 level_zero_modified_variable_callback_.push_back(cb);
1447 }
1448
1449 // This will be called not too often during propagation (when we finish
1450 // propagating one priority). If it returns true, we will stop propagation
1451 // there. It is used by LbTreeSearch as we can stop as soon as the objective
1452 // lower bound crossed a threshold and do not need to call expensive
1453 // propagator when this is the case.
1454 void SetStopPropagationCallback(std::function<bool()> callback) {
1455 stop_propagation_callback_ = callback;
1456 }
1457
1458 // Returns the id of the propagator we are currently calling. This is meant
1459 // to be used from inside Propagate() in case a propagator was registered
1460 // more than once at different priority for instance.
1461 int GetCurrentId() const { return current_id_; }
1462
1463 // Add the given propagator to its queue.
1464 //
1465 // Warning: This will have no effect if called from within the propagation of
1466 // a propagator since the propagator is still marked as "in the queue" until
1467 // its propagation is done. Use CallAgainDuringThisPropagation() if that is
1468 // what you need instead.
1469 void CallOnNextPropagate(int id);
1470
1471 void CallAgainDuringThisPropagation() { call_again_ = true; };
1472
1473 private:
1474 // Updates queue_ and in_queue_ with the propagator ids that need to be
1475 // called.
1476 void UpdateCallingNeeds(Trail* trail);
1477
1478 TimeLimit* time_limit_;
1479 IntegerTrail* integer_trail_;
1480 RevIntRepository* rev_int_repository_;
1481
1482 struct WatchData {
1483 int id;
1484 int watch_index;
1485 bool operator==(const WatchData& o) const {
1486 return id == o.id && watch_index == o.watch_index;
1487 }
1488 };
1490 literal_to_watcher_;
1492 var_to_watcher_;
1493 std::vector<PropagatorInterface*> watchers_;
1494 SparseBitset<IntegerVariable> modified_vars_;
1495
1496 // For RegisterLevelZeroModifiedVariablesCallback().
1497 SparseBitset<IntegerVariable> modified_vars_for_callback_;
1498
1499 // Propagator ids that needs to be called. There is one queue per priority but
1500 // just one Boolean to indicate if a propagator is in one of them.
1501 std::vector<std::deque<int>> queue_by_priority_;
1502 std::vector<bool> in_queue_;
1503
1504 // Data for each propagator.
1506 std::vector<bool> id_need_reversible_support_;
1507 std::vector<int> id_to_level_at_last_call_;
1508 RevVector<IdType, int> id_to_greatest_common_level_since_last_call_;
1509 std::vector<std::vector<ReversibleInterface*>> id_to_reversible_classes_;
1510 std::vector<std::vector<int*>> id_to_reversible_ints_;
1511
1512 std::vector<std::vector<int>> id_to_watch_indices_;
1513 std::vector<int> id_to_priority_;
1514 std::vector<int> id_to_idempotence_;
1515
1516 // Special propagators that needs to always be called at level zero.
1517 std::vector<int> propagator_ids_to_call_at_level_zero_;
1518
1519 // The id of the propagator we just called.
1520 int current_id_;
1521 bool call_again_ = false;
1522
1523 std::vector<std::function<void(const std::vector<IntegerVariable>&)>>
1524 level_zero_modified_variable_callback_;
1525
1526 std::function<bool()> stop_propagation_callback_;
1527
1528 std::vector<bool*> bool_to_reset_on_backtrack_;
1529};
1530
1531// ============================================================================
1532// Implementation.
1533// ============================================================================
1534
1535inline IntegerValue IntegerTrail::LowerBound(IntegerVariable i) const {
1536 return var_lbs_[i];
1538
1539inline IntegerValue IntegerTrail::UpperBound(IntegerVariable i) const {
1540 return -var_lbs_[NegationOf(i)];
1542
1543inline bool IntegerTrail::IsFixed(IntegerVariable i) const {
1544 return var_lbs_[i] == -var_lbs_[NegationOf(i)];
1546
1547inline IntegerValue IntegerTrail::FixedValue(IntegerVariable i) const {
1548 DCHECK(IsFixed(i));
1549 return var_lbs_[i];
1550}
1551
1552inline IntegerValue IntegerTrail::ConditionalLowerBound(
1553 Literal l, IntegerVariable i) const {
1554 const auto it = conditional_lbs_.find({l.Index(), i});
1555 if (it != conditional_lbs_.end()) {
1556 return std::max(var_lbs_[i], it->second);
1557 }
1558 return var_lbs_[i];
1559}
1560
1561inline IntegerValue IntegerTrail::ConditionalLowerBound(
1562 Literal l, AffineExpression expr) const {
1563 if (expr.var == kNoIntegerVariable) return expr.constant;
1564 return ConditionalLowerBound(l, expr.var) * expr.coeff + expr.constant;
1565}
1566
1567inline IntegerValue IntegerTrail::ConditionalUpperBound(
1568 Literal l, IntegerVariable i) const {
1570}
1571
1572inline IntegerValue IntegerTrail::ConditionalUpperBound(
1573 Literal l, AffineExpression expr) const {
1574 if (expr.var == kNoIntegerVariable) return expr.constant;
1575 return ConditionalUpperBound(l, expr.var) * expr.coeff + expr.constant;
1576}
1577
1579 IntegerVariable i) const {
1584 IntegerVariable i) const {
1586}
1587
1588inline IntegerValue IntegerTrail::LowerBound(AffineExpression expr) const {
1589 if (expr.var == kNoIntegerVariable) return expr.constant;
1590 return LowerBound(expr.var) * expr.coeff + expr.constant;
1591}
1592
1593inline IntegerValue IntegerTrail::UpperBound(AffineExpression expr) const {
1594 if (expr.var == kNoIntegerVariable) return expr.constant;
1595 return UpperBound(expr.var) * expr.coeff + expr.constant;
1596}
1597
1598inline IntegerValue IntegerTrail::UpperBound(LinearExpression2 expr) const {
1599 IntegerValue result = 0;
1600 for (int i = 0; i < 2; ++i) {
1601 if (expr.coeffs[i] == 0) {
1602 continue;
1603 } else if (expr.coeffs[i] > 0) {
1604 result += expr.coeffs[i] * UpperBound(expr.vars[i]);
1605 } else {
1606 result += expr.coeffs[i] * LowerBound(expr.vars[i]);
1607 }
1608 }
1609 return result;
1610}
1611
1612inline bool IntegerTrail::IsFixed(AffineExpression expr) const {
1613 if (expr.var == kNoIntegerVariable) return true;
1614 return IsFixed(expr.var);
1615}
1616
1617inline IntegerValue IntegerTrail::FixedValue(AffineExpression expr) const {
1618 if (expr.var == kNoIntegerVariable) return expr.constant;
1619 return FixedValue(expr.var) * expr.coeff + expr.constant;
1620}
1621
1623 AffineExpression expr) const {
1629 AffineExpression expr) const {
1631 return IntegerLiteral::LowerOrEqual(expr.var, UpperBound(expr.var));
1632}
1633
1635 return l.bound <= LowerBound(l.var);
1637
1639 return l.bound > UpperBound(l.var);
1641
1643 return l.bound <= LevelZeroLowerBound(l.var);
1645
1646// The level zero bounds are stored at the beginning of the trail and they also
1647// serves as sentinels. Their index match the variables index.
1648inline IntegerValue IntegerTrail::LevelZeroLowerBound(
1649 IntegerVariable var) const {
1650 DCHECK_GE(var, 0);
1651 DCHECK_LT(var, integer_trail_.size());
1652 return integer_trail_[var.value()].bound;
1653}
1654
1655inline IntegerValue IntegerTrail::LevelZeroUpperBound(
1656 IntegerVariable var) const {
1657 return -integer_trail_[NegationOf(var).value()].bound;
1658}
1659
1660inline bool IntegerTrail::IsFixedAtLevelZero(IntegerVariable var) const {
1661 return integer_trail_[var.value()].bound ==
1662 -integer_trail_[NegationOf(var).value()].bound;
1663}
1664
1665inline IntegerValue IntegerTrail::LevelZeroLowerBound(
1666 AffineExpression expr) const {
1667 if (expr.var == kNoIntegerVariable) return expr.constant;
1668 return expr.ValueAt(LevelZeroLowerBound(expr.var));
1669}
1670
1671inline IntegerValue IntegerTrail::LevelZeroUpperBound(
1672 AffineExpression expr) const {
1673 if (expr.var == kNoIntegerVariable) return expr.constant;
1674 return expr.ValueAt(LevelZeroUpperBound(expr.var));
1675}
1676
1677inline IntegerValue IntegerTrail::LevelZeroLowerBound(
1678 LinearExpression2 expr) const {
1680 IntegerValue result = 0;
1681 for (int i = 0; i < 2; ++i) {
1682 if (expr.coeffs[i] != 0) {
1683 result += expr.coeffs[i] * LevelZeroLowerBound(expr.vars[i]);
1684 }
1685 }
1686 return result;
1687}
1688
1689inline IntegerValue IntegerTrail::LevelZeroUpperBound(
1690 LinearExpression2 expr) const {
1691 expr.SimpleCanonicalization();
1692 IntegerValue result = 0;
1693 for (int i = 0; i < 2; ++i) {
1694 if (expr.coeffs[i] != 0) {
1695 result += expr.coeffs[i] * LevelZeroUpperBound(expr.vars[i]);
1696 }
1697 }
1698 return result;
1699}
1700
1701inline bool IntegerTrail::IsFixedAtLevelZero(AffineExpression expr) const {
1702 if (expr.var == kNoIntegerVariable) return true;
1703 return IsFixedAtLevelZero(expr.var);
1704}
1705
1706inline void GenericLiteralWatcher::WatchLiteral(Literal l, int id,
1707 int watch_index) {
1708 if (l.Index() >= literal_to_watcher_.size()) {
1709 literal_to_watcher_.resize(l.Index().value() + 1);
1710 }
1711 literal_to_watcher_[l].push_back({id, watch_index});
1712}
1713
1714inline void GenericLiteralWatcher::WatchLowerBound(IntegerVariable var, int id,
1715 int watch_index) {
1716 if (var == kNoIntegerVariable) return;
1717 if (var.value() >= var_to_watcher_.size()) {
1718 var_to_watcher_.resize(var.value() + 1);
1719 }
1720
1721 // Minor optim, so that we don't watch the same variable twice. Propagator
1722 // code is easier this way since for example when one wants to watch both
1723 // an interval start and interval end, both might have the same underlying
1724 // variable.
1725 const WatchData data = {id, watch_index};
1726 if (!var_to_watcher_[var].empty() && var_to_watcher_[var].back() == data) {
1727 return;
1728 }
1729 var_to_watcher_[var].push_back(data);
1730}
1731
1732inline void GenericLiteralWatcher::WatchUpperBound(IntegerVariable var, int id,
1733 int watch_index) {
1734 if (var == kNoIntegerVariable) return;
1735 WatchLowerBound(NegationOf(var), id, watch_index);
1736}
1737
1738inline void GenericLiteralWatcher::WatchIntegerVariable(IntegerVariable i,
1739 int id,
1740 int watch_index) {
1741 WatchLowerBound(i, id, watch_index);
1742 WatchUpperBound(i, id, watch_index);
1743}
1744
1745// ============================================================================
1746// Model based functions.
1747//
1748// Note that in the model API, we simply use int64_t for the integer values, so
1749// that it is nicer for the client. Internally these are converted to
1750// IntegerValue which is typechecked.
1751// ============================================================================
1752
1753inline std::function<BooleanVariable(Model*)> NewBooleanVariable() {
1754 return [=](Model* model) {
1755 return model->GetOrCreate<SatSolver>()->NewBooleanVariable();
1756 };
1758
1759inline std::function<IntegerVariable(Model*)> ConstantIntegerVariable(
1760 int64_t value) {
1761 return [=](Model* model) {
1762 return model->GetOrCreate<IntegerTrail>()
1763 ->GetOrCreateConstantIntegerVariable(IntegerValue(value));
1764 };
1765}
1766
1767inline std::function<IntegerVariable(Model*)> NewIntegerVariable(int64_t lb,
1768 int64_t ub) {
1769 return [=](Model* model) {
1770 CHECK_LE(lb, ub);
1771 return model->GetOrCreate<IntegerTrail>()->AddIntegerVariable(
1772 IntegerValue(lb), IntegerValue(ub));
1773 };
1774}
1775
1776inline std::function<IntegerVariable(Model*)> NewIntegerVariable(
1777 const Domain& domain) {
1778 return [=](Model* model) {
1779 return model->GetOrCreate<IntegerTrail>()->AddIntegerVariable(domain);
1781}
1782
1783// Creates a 0-1 integer variable "view" of the given literal. It will have a
1784// value of 1 when the literal is true, and 0 when the literal is false.
1785inline IntegerVariable CreateNewIntegerVariableFromLiteral(Literal lit,
1786 Model* model) {
1787 auto* encoder = model->GetOrCreate<IntegerEncoder>();
1788 const IntegerVariable candidate = encoder->GetLiteralView(lit);
1789 if (candidate != kNoIntegerVariable) return candidate;
1790
1791 IntegerVariable var;
1792 auto* integer_trail = model->GetOrCreate<IntegerTrail>();
1793 const auto& assignment = model->GetOrCreate<SatSolver>()->Assignment();
1794 if (assignment.LiteralIsTrue(lit)) {
1795 var = integer_trail->GetOrCreateConstantIntegerVariable(IntegerValue(1));
1796 } else if (assignment.LiteralIsFalse(lit)) {
1797 var = integer_trail->GetOrCreateConstantIntegerVariable(IntegerValue(0));
1798 } else {
1799 var = integer_trail->AddIntegerVariable(IntegerValue(0), IntegerValue(1));
1800 }
1801
1802 encoder->AssociateToIntegerEqualValue(lit, var, IntegerValue(1));
1803 DCHECK_NE(encoder->GetLiteralView(lit), kNoIntegerVariable);
1804 return var;
1805}
1806
1807// Deprecated.
1808inline std::function<IntegerVariable(Model*)> NewIntegerVariableFromLiteral(
1809 Literal lit) {
1810 return [=](Model* model) {
1811 return CreateNewIntegerVariableFromLiteral(lit, model);
1813}
1814
1815inline std::function<int64_t(const Model&)> LowerBound(IntegerVariable v) {
1816 return [=](const Model& model) {
1817 return model.Get<IntegerTrail>()->LowerBound(v).value();
1818 };
1820
1821inline std::function<int64_t(const Model&)> UpperBound(IntegerVariable v) {
1822 return [=](const Model& model) {
1823 return model.Get<IntegerTrail>()->UpperBound(v).value();
1824 };
1826
1827inline std::function<bool(const Model&)> IsFixed(IntegerVariable v) {
1828 return [=](const Model& model) {
1829 const IntegerTrail* trail = model.Get<IntegerTrail>();
1830 return trail->LowerBound(v) == trail->UpperBound(v);
1832}
1833
1834// This checks that the variable is fixed.
1835inline std::function<int64_t(const Model&)> Value(IntegerVariable v) {
1836 return [=](const Model& model) {
1837 const IntegerTrail* trail = model.Get<IntegerTrail>();
1838 CHECK_EQ(trail->LowerBound(v), trail->UpperBound(v)) << v;
1839 return trail->LowerBound(v).value();
1840 };
1841}
1842
1843inline std::function<void(Model*)> GreaterOrEqual(IntegerVariable v,
1844 int64_t lb) {
1845 return [=](Model* model) {
1846 if (!model->GetOrCreate<IntegerTrail>()->Enqueue(
1848 std::vector<Literal>(), std::vector<IntegerLiteral>())) {
1849 model->GetOrCreate<SatSolver>()->NotifyThatModelIsUnsat();
1850 VLOG(1) << "Model trivially infeasible, variable " << v
1851 << " has upper bound " << model->Get(UpperBound(v))
1852 << " and GreaterOrEqual() was called with a lower bound of "
1853 << lb;
1854 }
1855 };
1856}
1857
1858inline std::function<void(Model*)> LowerOrEqual(IntegerVariable v, int64_t ub) {
1859 return [=](Model* model) {
1860 if (!model->GetOrCreate<IntegerTrail>()->Enqueue(
1861 IntegerLiteral::LowerOrEqual(v, IntegerValue(ub)),
1862 std::vector<Literal>(), std::vector<IntegerLiteral>())) {
1863 model->GetOrCreate<SatSolver>()->NotifyThatModelIsUnsat();
1864 VLOG(1) << "Model trivially infeasible, variable " << v
1865 << " has lower bound " << model->Get(LowerBound(v))
1866 << " and LowerOrEqual() was called with an upper bound of " << ub;
1867 }
1868 };
1869}
1870
1871// Fix v to a given value.
1872inline std::function<void(Model*)> Equality(IntegerVariable v, int64_t value) {
1873 return [=](Model* model) {
1874 model->Add(LowerOrEqual(v, value));
1875 model->Add(GreaterOrEqual(v, value));
1877}
1878
1879// TODO(user): This is one of the rare case where it is better to use Equality()
1880// rather than two Implications(). Maybe we should modify our internal
1881// implementation to use half-reified encoding? that is do not propagate the
1882// direction integer-bound => literal, but just literal => integer-bound? This
1883// is the same as using different underlying variable for an integer literal and
1884// its negation.
1885inline std::function<void(Model*)> Implication(
1886 absl::Span<const Literal> enforcement_literals, IntegerLiteral i) {
1887 return [=](Model* model) {
1888 auto* sat_solver = model->GetOrCreate<SatSolver>();
1889 auto* integer_trail = model->GetOrCreate<IntegerTrail>();
1890 if (i.bound <= integer_trail->LowerBound(i.var)) {
1891 // Always true! nothing to do.
1892 } else if (i.bound > integer_trail->UpperBound(i.var)) {
1893 // Always false.
1894 std::vector<Literal> clause;
1895 for (const Literal literal : enforcement_literals) {
1896 clause.push_back(literal.Negated());
1897 }
1898 sat_solver->AddClauseDuringSearch(clause);
1899 } else {
1900 // TODO(user): Double check what happen when we associate a trivially
1901 // true or false literal.
1902 IntegerEncoder* encoder = model->GetOrCreate<IntegerEncoder>();
1903 std::vector<Literal> clause{encoder->GetOrCreateAssociatedLiteral(i)};
1904 for (const Literal literal : enforcement_literals) {
1905 clause.push_back(literal.Negated());
1906 }
1907 sat_solver->AddClauseDuringSearch(clause);
1908 }
1909 };
1910}
1911
1912// in_interval => v in [lb, ub].
1913inline std::function<void(Model*)> ImpliesInInterval(Literal in_interval,
1914 IntegerVariable v,
1915 int64_t lb, int64_t ub) {
1916 return [=](Model* model) {
1917 if (lb == ub) {
1918 IntegerEncoder* encoder = model->GetOrCreate<IntegerEncoder>();
1919 model->Add(Implication({in_interval},
1921 v, IntegerValue(lb))));
1922 return;
1923 }
1924 model->Add(Implication(
1925 {in_interval}, IntegerLiteral::GreaterOrEqual(v, IntegerValue(lb))));
1926 model->Add(Implication({in_interval},
1927 IntegerLiteral::LowerOrEqual(v, IntegerValue(ub))));
1928 };
1929}
1930
1931// Calling model.Add(FullyEncodeVariable(var)) will create one literal per value
1932// in the domain of var (if not already done), and wire everything correctly.
1933// This also returns the full encoding, see the FullDomainEncoding() method of
1934// the IntegerEncoder class.
1935inline std::function<std::vector<ValueLiteralPair>(Model*)> FullyEncodeVariable(
1936 IntegerVariable var) {
1937 return [=](Model* model) {
1938 IntegerEncoder* encoder = model->GetOrCreate<IntegerEncoder>();
1939 if (!encoder->VariableIsFullyEncoded(var)) {
1940 encoder->FullyEncodeVariable(var);
1941 }
1942 return encoder->FullDomainEncoding(var);
1943 };
1944}
1945
1946} // namespace sat
1947} // namespace operations_research
1948
1949#endif // ORTOOLS_SAT_INTEGER_H_
Definition model.h:345
void ClearAndResize(IntegerType size)
Definition bitset.h:852
void WatchUpperBound(AffineExpression e, int id)
Definition integer.h:1379
void WatchAffineExpression(AffineExpression e, int id)
Definition integer.h:1382
void WatchLiteral(Literal l, int id, int watch_index=-1)
Definition integer.h:1708
void WatchUpperBound(IntegerVariable var, int id, int watch_index=-1)
Definition integer.h:1734
void Untrail(const Trail &trail, int literal_trail_index) final
Definition integer.cc:2639
void WatchLowerBound(IntegerVariable var, int id, int watch_index=-1)
Definition integer.h:1716
void RegisterLevelZeroModifiedVariablesCallback(const std::function< void(const std::vector< IntegerVariable > &)> cb)
Definition integer.h:1444
void SetStopPropagationCallback(std::function< bool()> callback)
Definition integer.h:1454
void SetPropagatorPriority(int id, int priority)
Definition integer.cc:2700
void WatchIntegerVariable(IntegerVariable i, int id, int watch_index=-1)
Definition integer.h:1740
void RegisterReversibleClass(int id, ReversibleInterface *rev)
Definition integer.cc:2716
int Register(PropagatorInterface *propagator)
Definition integer.cc:2674
GenericLiteralWatcher & operator=(const GenericLiteralWatcher &)=delete
GenericLiteralWatcher(const GenericLiteralWatcher &)=delete
const std::vector< ValueLiteralPair > & FullDomainEncoding(IntegerVariable var) const
Definition integer.cc:146
IntegerEncoder & operator=(const IntegerEncoder &)=delete
std::pair< IntegerLiteral, IntegerLiteral > Canonicalize(IntegerLiteral i_lit) const
Definition integer.cc:247
void AssociateToIntegerLiteral(Literal literal, IntegerLiteral i_lit)
Definition integer.cc:365
const InlinedIntegerValueVector & GetEqualityLiterals(Literal lit) const
Definition integer.h:238
IntegerVariable GetLiteralView(Literal lit) const
Definition integer.h:265
void FullyEncodeVariable(IntegerVariable var)
Definition integer.cc:80
IntegerEncoder(const IntegerEncoder &)=delete
bool VariableIsFullyEncoded(IntegerVariable var) const
Definition integer.cc:111
bool IsFixedOrHasAssociatedLiteral(IntegerLiteral i_lit) const
Definition integer.cc:524
const std::vector< ValueLiteralPair > & PartialDomainEncoding(IntegerVariable var) const
Definition integer.cc:152
LiteralIndex GetAssociatedEqualityLiteral(IntegerVariable var, IntegerValue value) const
Definition integer.cc:318
const InlinedIntegerLiteralVector & GetIntegerLiterals(Literal lit) const
Definition integer.h:229
LiteralIndex SearchForLiteralAtOrBefore(IntegerLiteral i_lit, IntegerValue *bound) const
Definition integer.cc:547
void ReserveSpaceForNumVariables(int num_vars)
Definition integer.cc:74
Literal GetOrCreateAssociatedLiteral(IntegerLiteral i_lit)
Definition integer.cc:274
LiteralIndex SearchForLiteralAtOrAfter(IntegerLiteral i_lit, IntegerValue *bound) const
Definition integer.cc:575
void AssociateToIntegerEqualValue(Literal literal, IntegerVariable var, IntegerValue value)
Definition integer.cc:435
ABSL_MUST_USE_RESULT bool LiteralOrNegationHasView(Literal lit, IntegerVariable *view=nullptr, bool *view_is_direct=nullptr) const
Definition integer.cc:600
const std::vector< IntegerVariable > & GetAllAssociatedVariables(Literal lit) const
Definition integer.h:247
std::vector< ValueLiteralPair > PartialGreaterThanEncoding(IntegerVariable var) const
Definition integer.cc:620
LiteralIndex GetAssociatedLiteral(IntegerLiteral i_lit) const
Definition integer.cc:533
bool VariableDomainHasHoles(IntegerVariable var)
Definition integer.h:180
bool UpdateEncodingOnInitialDomainChange(IntegerVariable var, Domain domain)
Definition integer.cc:656
Literal GetOrCreateLiteralAssociatedToEquality(IntegerVariable var, IntegerValue value)
Definition integer.cc:328
ABSL_MUST_USE_RESULT bool ConditionalEnqueue(Literal lit, IntegerLiteral i_lit, std::vector< Literal > *literal_reason, std::vector< IntegerLiteral > *integer_reason)
Definition integer.cc:1361
absl::Span< const Literal > Reason(const Trail &trail, int trail_index, int64_t conflict_id) const final
Definition integer.cc:2328
IntegerValue LowerBound(IntegerVariable i) const
Definition integer.h:1537
absl::Span< const IntegerLiteral > IntegerReasonAsSpan(ReasonIndex index) const
Definition integer.cc:2028
void RemoveLevelZeroBounds(std::vector< IntegerLiteral > *reason) const
Definition integer.cc:1180
ABSL_MUST_USE_RESULT bool Enqueue(IntegerLiteral i_lit, absl::Span< const Literal > literal_reason, absl::Span< const IntegerLiteral > integer_reason)
Definition integer.h:748
int FindTrailIndexOfVarBefore(IntegerVariable var, int threshold) const
Definition integer.cc:965
bool VariableLowerBoundIsFromLevelZero(IntegerVariable var) const
Definition integer.h:931
IntegerTrail & operator=(const IntegerTrail &)=delete
absl::Span< const Literal > LiteralReasonAsSpan(ReasonIndex index) const
Definition integer.cc:2073
IntegerVariable VarAtIndex(int integer_trail_index) const
Definition integer.h:865
std::vector< Literal > & ClearedMutableTmpLiterals()
Definition integer.h:806
void RegisterWatcher(SparseBitset< IntegerVariable > *p)
Definition integer.h:860
IntegerLiteral UpperBoundAsLiteral(IntegerVariable i) const
Definition integer.h:1585
bool IsFixedAtLevelZero(IntegerVariable var) const
Definition integer.h:1662
IntegerLiteral IntegerLiteralAtIndex(int integer_trail_index) const
Definition integer.h:868
ABSL_MUST_USE_RESULT bool SafeEnqueue(IntegerLiteral i_lit, absl::Span< const IntegerLiteral > integer_reason)
Definition integer.cc:1336
void RelaxLinearReason(IntegerValue slack, absl::Span< const IntegerValue > coeffs, std::vector< IntegerLiteral > *reason) const
Definition integer.cc:1046
bool IntegerLiteralIsTrue(IntegerLiteral l) const
Definition integer.h:1636
int GetFirstIndexBefore(IntegerVariable var, GlobalTrailIndex source_index, int starting_integer_index)
Definition integer.h:873
IntegerValue UpperBound(IntegerVariable i) const
Definition integer.h:1541
void AppendNewBoundsFrom(int base_index, std::vector< IntegerLiteral > *output) const
Definition integer.cc:2412
IntegerValue FixedValue(IntegerVariable i) const
Definition integer.h:1549
std::vector< IntegerLiteral > & ClearedMutableTmpIntegerLiterals()
Definition integer.h:810
bool IntegerLiteralIsFalse(IntegerLiteral l) const
Definition integer.h:1640
IntegerLiteral LowerBoundAsLiteral(IntegerVariable i) const
Definition integer.h:1580
void RegisterReversibleClass(ReversibleInterface *rev)
Definition integer.h:937
bool ReportConflict(absl::Span< const Literal > literal_reason, absl::Span< const IntegerLiteral > integer_reason)
Definition integer.h:905
int PreviousTrailIndex(int integer_trail_index) const
Definition integer.h:887
const IntegerReason & GetIntegerReason(GlobalTrailIndex index, std::optional< IntegerValue > needed_bound)
Definition integer.cc:2367
void AppendRelaxedLinearReason(IntegerValue slack, absl::Span< const IntegerValue > coeffs, absl::Span< const IntegerVariable > vars, std::vector< IntegerLiteral > *reason) const
Definition integer.cc:1068
IntegerTrail(const IntegerTrail &)=delete
bool ReportConflict(absl::Span< const IntegerLiteral > integer_reason)
Definition integer.h:926
ABSL_MUST_USE_RESULT bool EnqueueWithLazyReason(IntegerLiteral i_lit, int id, IntegerValue propagation_slack, LazyReasonInterface *explainer)
Definition integer.h:795
bool IsTrueAtLevelZero(IntegerLiteral l) const
Definition integer.h:1644
const IntegerReason & IntegerConflict()
Definition integer.h:553
void AppendNewBounds(std::vector< IntegerLiteral > *output) const
Definition integer.cc:2406
bool UpdateInitialDomain(IntegerVariable var, Domain domain)
Definition integer.cc:905
bool IsFixed(IntegerVariable i) const
Definition integer.h:1545
IntegerVariable NumIntegerVariables() const
Definition integer.h:573
ABSL_MUST_USE_RESULT bool Enqueue(IntegerLiteral i_lit, absl::Span< const Literal > literal_reason, absl::Span< const IntegerLiteral > integer_reason, int trail_index_with_same_reason)
Definition integer.h:786
IntegerValue ConditionalLowerBound(Literal l, IntegerVariable i) const
Definition integer.h:1554
IntegerVariable NextVariableToBranchOnInPropagationLoop() const
Definition integer.cc:1595
IntegerValue ConditionalUpperBound(Literal l, IntegerVariable i) const
Definition integer.h:1569
const IntegerValue * LowerBoundsData() const
Definition integer.h:631
ABSL_MUST_USE_RESULT bool SafeEnqueueLiteral(Literal literal, absl::Span< const Literal > literal_reason, absl::Span< const IntegerLiteral > integer_reason)
Definition integer.cc:1504
void RegisterDebugChecker(std::function< bool(absl::Span< const Literal > clause, absl::Span< const IntegerLiteral > integers)> checker)
Definition integer.h:982
GlobalTrailIndex GlobalIndexAt(int integer_index) const
Definition integer.h:893
ABSL_MUST_USE_RESULT bool RootLevelEnqueue(IntegerLiteral i_lit)
Definition integer.cc:1285
IntegerValue LevelZeroUpperBound(IntegerVariable var) const
Definition integer.h:1657
void MergeReasonInto(absl::Span< const IntegerLiteral > literals, std::vector< Literal > *output) const
Definition integer.cc:2102
ABSL_MUST_USE_RESULT bool EnqueueLiteral(Literal literal, absl::Span< const Literal > literal_reason, absl::Span< const IntegerLiteral > integer_reason)
Definition integer.cc:1498
const Domain & InitialVariableDomain(IntegerVariable var) const
Definition integer.cc:895
IntegerValue LevelZeroLowerBound(IntegerVariable var) const
Definition integer.h:1650
void Untrail(const Trail &trail, int literal_trail_index) final
Definition integer.cc:787
ABSL_MUST_USE_RESULT bool Enqueue(IntegerLiteral i_lit)
Definition integer.h:745
IntegerVariable FirstUnassignedVariable() const
Definition integer.cc:1628
void ReserveSpaceForNumVariables(int num_vars)
Definition integer.cc:840
bool Propagate(Trail *trail) final
Definition integer.cc:723
IntegerVariable GetOrCreateConstantIntegerVariable(IntegerValue value)
Definition integer.cc:944
std::vector< Literal > ReasonFor(IntegerLiteral literal) const
Definition integer.cc:2096
ReasonIndex AppendReasonToInternalBuffers(absl::Span< const Literal > literal_reason, absl::Span< const IntegerLiteral > integer_reason)
Definition integer.cc:1646
virtual void Explain(int id, IntegerLiteral to_explain, IntegerReason *reason)=0
virtual std::string LazyReasonName() const =0
LiteralIndex Index() const
Definition sat_base.h:92
virtual bool IncrementalPropagate(const std::vector< int > &)
Definition integer.h:1299
SatPropagator(const std::string &name)
Definition sat_base.h:786
void AddPropagator(SatPropagator *propagator)
void push_back(const value_type &val)
std::function< std::vector< ValueLiteralPair >(Model *)> FullyEncodeVariable(IntegerVariable var)
Definition integer.h:1939
std::function< IntegerVariable(Model *)> NewIntegerVariableFromLiteral(Literal lit)
Definition integer.h:1812
constexpr IntegerValue kMaxIntegerValue(std::numeric_limits< IntegerValue::ValueType >::max() - 1)
std::function< void(Model *)> Equality(IntegerVariable v, int64_t value)
Definition integer.h:1876
bool operator==(const BoolArgumentProto &lhs, const BoolArgumentProto &rhs)
const LiteralIndex kNoLiteralIndex(-1)
std::function< int64_t(const Model &)> LowerBound(IntegerVariable v)
Definition integer.h:1819
std::function< BooleanVariable(Model *)> NewBooleanVariable()
Definition integer.h:1757
std::function< void(Model *)> LowerOrEqual(IntegerVariable v, int64_t ub)
Definition integer.h:1862
std::vector< IntegerVariable > NegationOf(absl::Span< const IntegerVariable > vars)
Definition integer.cc:52
std::function< bool(const Model &)> IsFixed(IntegerVariable v)
Definition integer.h:1831
constexpr IntegerValue kMinIntegerValue(-kMaxIntegerValue.value())
const IntegerVariable kNoIntegerVariable(-1)
absl::InlinedVector< std::pair< IntegerVariable, IntegerValue >, 2 > InlinedIntegerValueVector
Definition integer.h:55
std::function< void(Model *)> Implication(absl::Span< const Literal > enforcement_literals, IntegerLiteral i)
Definition integer.h:1889
std::function< IntegerVariable(Model *)> ConstantIntegerVariable(int64_t value)
Definition integer.h:1763
constexpr ClauseId kNoClauseId(0)
std::function< int64_t(const Model &)> Value(IntegerVariable v)
Definition integer.h:1839
std::function< int64_t(const Model &)> UpperBound(IntegerVariable v)
Definition integer.h:1825
std::function< IntegerVariable(Model *)> NewIntegerVariable(int64_t lb, int64_t ub)
Definition integer.h:1771
std::function< void(Model *)> GreaterOrEqual(IntegerVariable v, int64_t lb)
Definition integer.h:1847
absl::InlinedVector< IntegerLiteral, 2 > InlinedIntegerLiteralVector
Definition integer.h:54
PositiveOnlyIndex GetPositiveOnlyIndex(IntegerVariable var)
std::function< void(Model *)> ImpliesInInterval(Literal in_interval, IntegerVariable v, int64_t lb, int64_t ub)
Definition integer.h:1917
bool VariableIsPositive(IntegerVariable i)
IntegerVariable CreateNewIntegerVariableFromLiteral(Literal lit, Model *model)
Definition integer.h:1789
OR-Tools root namespace.
#define DEFINE_STRONG_INDEX_TYPE(index_type_name)
Definition model.h:50
IntegerValue ValueAt(IntegerValue var_value) const
std::vector< IntegerLiteral > integer_literal_to_fix
Definition integer.h:85
bool operator>=(const GlobalTrailIndex &o) const
Definition integer.h:512
bool operator<=(const GlobalTrailIndex &o) const
Definition integer.h:508
bool operator<(const GlobalTrailIndex &o) const
Definition integer.h:497
bool operator==(const GlobalTrailIndex &o) const
Definition integer.h:503
bool operator>(const GlobalTrailIndex &o) const
Definition integer.h:514
static IntegerLiteral GreaterOrEqual(IntegerVariable i, IntegerValue bound)
static IntegerLiteral LowerOrEqual(IntegerVariable i, IntegerValue bound)
absl::Span< const Literal > boolean_literals_at_false
Definition integer.h:441
absl::Span< const IntegerValue > coeffs
Definition integer.h:457
absl::Span< const Literal > boolean_literals_at_true
Definition integer.h:440
absl::Span< const IntegerVariable > vars
Definition integer.h:456
absl::Span< const IntegerLiteral > integer_literals
Definition integer.h:442
bool operator==(const LiteralValueValue &rhs) const
Definition integer.h:64