Google OR-Tools v9.11
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
sat_base.h
Go to the documentation of this file.
1// Copyright 2010-2024 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// Basic types and classes used by the sat solver.
15
16#ifndef OR_TOOLS_SAT_SAT_BASE_H_
17#define OR_TOOLS_SAT_SAT_BASE_H_
18
19#include <algorithm>
20#include <cstdint>
21#include <deque>
22#include <functional>
23#include <ostream>
24#include <string>
25#include <utility>
26#include <vector>
27
28#include "absl/base/attributes.h"
29#include "absl/log/check.h"
30#include "absl/strings/str_format.h"
31#include "absl/types/span.h"
34#include "ortools/util/bitset.h"
36
37namespace operations_research {
38namespace sat {
39
40// Index of a variable (>= 0).
41DEFINE_STRONG_INDEX_TYPE(BooleanVariable);
42const BooleanVariable kNoBooleanVariable(-1);
43
44// Index of a literal (>= 0), see Literal below.
46const LiteralIndex kNoLiteralIndex(-1);
47
48// Special values used in some API to indicate a literal that is always true
49// or always false.
50const LiteralIndex kTrueLiteralIndex(-2);
51const LiteralIndex kFalseLiteralIndex(-3);
52
53// A literal is used to represent a variable or its negation. If it represents
54// the variable it is said to be positive. If it represent its negation, it is
55// said to be negative. We support two representations as an integer.
56//
57// The "signed" encoding of a literal is convenient for input/output and is used
58// in the cnf file format. For a 0-based variable index x, (x + 1) represent the
59// variable x and -(x + 1) represent its negation. The signed value 0 is an
60// undefined literal and this class can never contain it.
61//
62// The "index" encoding of a literal is convenient as an index to an array
63// and is the one used internally for efficiency. It is always positive or zero,
64// and for a 0-based variable index x, (x << 1) encode the variable x and the
65// same number XOR 1 encode its negation.
66class Literal {
67 public:
68 explicit Literal(int signed_value)
69 : index_(signed_value > 0 ? ((signed_value - 1) << 1)
70 : ((-signed_value - 1) << 1) ^ 1) {
71 CHECK_NE(signed_value, 0);
72 }
73
74 Literal() = default;
75 explicit Literal(LiteralIndex index) : index_(index.value()) {}
76 Literal(BooleanVariable variable, bool is_positive)
77 : index_(is_positive ? (variable.value() << 1)
78 : (variable.value() << 1) ^ 1) {}
79
80 // We want a literal to be implicitly converted to a LiteralIndex().
81 // Before this, we used to have many literal.Index() that didn't add anything.
82 //
83 // TODO(user): LiteralIndex might not even be needed, but because of the
84 // signed value business, it is still safer with it.
85 operator LiteralIndex() const { return Index(); } // NOLINT
86
87 BooleanVariable Variable() const { return BooleanVariable(index_ >> 1); }
88 bool IsPositive() const { return !(index_ & 1); }
89 bool IsNegative() const { return (index_ & 1); }
90
91 LiteralIndex Index() const { return LiteralIndex(index_); }
92 LiteralIndex NegatedIndex() const { return LiteralIndex(index_ ^ 1); }
93
94 int SignedValue() const {
95 return (index_ & 1) ? -((index_ >> 1) + 1) : ((index_ >> 1) + 1);
96 }
97
98 Literal Negated() const { return Literal(NegatedIndex()); }
99
100 std::string DebugString() const {
101 return absl::StrFormat("%+d", SignedValue());
102 }
103
104 bool operator==(Literal other) const { return index_ == other.index_; }
105 bool operator!=(Literal other) const { return index_ != other.index_; }
106 bool operator<(const Literal& other) const { return index_ < other.index_; }
107
108 template <typename H>
110 return H::combine(std::move(h), literal.index_);
111 }
112
113 private:
114 int index_;
115};
116
117inline std::ostream& operator<<(std::ostream& os, Literal literal) {
118 os << literal.DebugString();
119 return os;
120}
121
122template <typename Sink, typename... T>
123void AbslStringify(Sink& sink, Literal arg) {
124 absl::Format(&sink, "%s", arg.DebugString());
125}
126
127inline std::ostream& operator<<(std::ostream& os,
128 absl::Span<const Literal> literals) {
129 os << "[";
130 bool first = true;
131 for (const Literal literal : literals) {
132 if (first) {
133 first = false;
134 } else {
135 os << ",";
136 }
137 os << literal.DebugString();
138 }
139 os << "]";
140 return os;
141}
142
143// Only used for testing to use the classical SAT notation for a literal. This
144// allows to write Literals({+1, -4, +3}) for the clause with BooleanVariable 0
145// and 2 appearing positively and 3 negatively.
146inline std::vector<Literal> Literals(absl::Span<const int> input) {
147 std::vector<Literal> result(input.size());
148 for (int i = 0; i < result.size(); ++i) {
149 result[i] = Literal(input[i]);
150 }
151 return result;
152}
153
154// Holds the current variable assignment of the solver.
155// Each variable can be unassigned or be assigned to true or false.
157 public:
159 explicit VariablesAssignment(int num_variables) { Resize(num_variables); }
160
161 // This type is neither copyable nor movable.
164 void Resize(int num_variables) {
165 assignment_.Resize(LiteralIndex(num_variables << 1));
166 }
167
168 // Makes the given literal true by assigning its underlying variable to either
169 // true or false depending on the literal sign. This can only be called on an
170 // unassigned variable.
172 DCHECK(!VariableIsAssigned(literal.Variable()));
173 assignment_.Set(literal.Index());
174 }
175
176 // Unassign the variable corresponding to the given literal.
177 // This can only be called on an assigned variable.
179 DCHECK(VariableIsAssigned(literal.Variable()));
180 assignment_.ClearTwoBits(literal.Index());
181 }
182
183 // Literal getters. Note that both can be false, in which case the
184 // corresponding variable is not assigned.
186 return assignment_.IsSet(literal.NegatedIndex());
187 }
189 return assignment_.IsSet(literal.Index());
190 }
192 return assignment_.AreOneOfTwoBitsSet(literal.Index());
193 }
194
195 // Returns true iff the given variable is assigned.
196 bool VariableIsAssigned(BooleanVariable var) const {
197 return assignment_.AreOneOfTwoBitsSet(LiteralIndex(var.value() << 1));
198 }
199
200 // Returns the literal of the given variable that is assigned to true.
201 // That is, depending on the variable, it can be the positive literal or the
202 // negative one. Only call this on an assigned variable.
204 DCHECK(VariableIsAssigned(var));
205 return Literal(var, assignment_.IsSet(LiteralIndex(var.value() << 1)));
206 }
207
208 int NumberOfVariables() const { return assignment_.size().value() / 2; }
209
210 private:
211 // The encoding is as follows:
212 // - assignment_.IsSet(literal.Index()) means literal is true.
213 // - assignment_.IsSet(literal.Index() ^ 1]) means literal is false.
214 // - If both are false, then the variable (and the literal) is unassigned.
215 Bitset64<LiteralIndex> assignment_;
216
217 friend class AssignmentView;
218};
219
220// For "hot" loop, it is better not to reload the Bitset64 pointer on each
221// check.
223 public:
224 explicit AssignmentView(const VariablesAssignment& assignment)
225 : view_(assignment.assignment_.const_view()) {}
226
228 return view_[literal.NegatedIndex()];
229 }
230
231 bool LiteralIsTrue(Literal literal) const { return view_[literal.Index()]; }
232
233 private:
235};
236
237// Forward declaration.
238class SatClause;
239class SatPropagator;
240
241// Information about a variable assignment.
243 // The decision level at which this assignment was made. This starts at 0 and
244 // increases each time the solver takes a search decision.
245 //
246 // TODO(user): We may be able to get rid of that for faster enqueues. Most of
247 // the code only need to know if this is 0 or the highest level, and for the
248 // LBD computation, the literal of the conflict are already ordered by level,
249 // so we could do it fairly efficiently.
250 //
251 // TODO(user): We currently don't support more than 2^28 decision levels. That
252 // should be enough for most practical problem, but we should fail properly if
253 // this limit is reached.
254 uint32_t level : 28;
255
256 // The type of assignment (see AssignmentType below).
257 //
258 // Note(user): We currently don't support more than 16 types of assignment.
259 // This is checked in RegisterPropagator().
260 mutable uint32_t type : 4;
261
262 // The index of this assignment in the trail.
263 int32_t trail_index;
264
265 std::string DebugString() const {
266 return absl::StrFormat("level:%d type:%d trail_index:%d", level, type,
268 }
269};
270static_assert(sizeof(AssignmentInfo) == 8,
271 "ERROR_AssignmentInfo_is_not_well_compacted");
272
273// Each literal on the trail will have an associated propagation "type" which is
274// either one of these special types or the id of a propagator.
276 static constexpr int kCachedReason = 0;
277 static constexpr int kUnitReason = 1;
278 static constexpr int kSearchDecision = 2;
279 static constexpr int kSameReasonAs = 3;
280
281 // Propagator ids starts from there and are created dynamically.
282 static constexpr int kFirstFreePropagationId = 4;
283};
284
285// The solver trail stores the assignment made by the solver in order.
286// This class is responsible for maintaining the assignment of each variable
287// and the information of each assignment.
288class Trail {
289 public:
291 current_info_.trail_index = 0;
292 current_info_.level = 0;
293 }
294
295 // This type is neither copyable nor movable.
296 Trail(const Trail&) = delete;
297 Trail& operator=(const Trail&) = delete;
298
299 void Resize(int num_variables);
300
301 // Registers a propagator. This assigns a unique id to this propagator and
302 // calls SetPropagatorId() on it.
303 void RegisterPropagator(SatPropagator* propagator);
304
305 // Enqueues the assignment that make the given literal true on the trail. This
306 // should only be called on unassigned variables.
307 void SetCurrentPropagatorId(int propagator_id) {
308 current_info_.type = propagator_id;
309 }
310 void FastEnqueue(Literal true_literal) {
311 DCHECK(!assignment_.VariableIsAssigned(true_literal.Variable()));
312 trail_[current_info_.trail_index] = true_literal;
313 info_[true_literal.Variable()] = current_info_;
314 assignment_.AssignFromTrueLiteral(true_literal);
315 ++current_info_.trail_index;
316 }
317 void Enqueue(Literal true_literal, int propagator_id) {
318 SetCurrentPropagatorId(propagator_id);
319 FastEnqueue(true_literal);
320 }
321
322 // Specific Enqueue() version for the search decision.
323 void EnqueueSearchDecision(Literal true_literal) {
325 }
326
327 // Specific Enqueue() version for a fixed variable.
328 void EnqueueWithUnitReason(Literal true_literal) {
330 }
331
332 // Some constraints propagate a lot of literals at once. In these cases, it is
333 // more efficient to have all the propagated literals except the first one
334 // referring to the reason of the first of them.
336 BooleanVariable reference_var) {
337 reference_var_with_same_reason_as_[true_literal.Variable()] = reference_var;
339 }
340
341 // Enqueues the given literal using the current content of
342 // GetEmptyVectorToStoreReason() as the reason. This API is a bit more
343 // leanient and does not require the literal to be unassigned. If it is
344 // already assigned to false, then MutableConflict() will be set appropriately
345 // and this will return false otherwise this will enqueue the literal and
346 // returns true.
347 ABSL_MUST_USE_RESULT bool EnqueueWithStoredReason(Literal true_literal) {
348 if (assignment_.LiteralIsTrue(true_literal)) return true;
349 if (assignment_.LiteralIsFalse(true_literal)) {
350 *MutableConflict() = reasons_repository_[Index()];
351 MutableConflict()->push_back(true_literal);
352 return false;
353 }
354
356 const BooleanVariable var = true_literal.Variable();
357 reasons_[var] = reasons_repository_[info_[var].trail_index];
358 old_type_[var] = info_[var].type;
360 return true;
361 }
362
363 // Returns the reason why this variable was assigned.
364 //
365 // Note that this shouldn't be called on a variable at level zero, because we
366 // don't cleanup the reason data for these variables but the underlying
367 // clauses may have been deleted.
368 //
369 // If conflict_id >= 0, this indicate that this was called as part of the
370 // first-UIP procedure. It has a few implication:
371 // - The reason do not need to be cached and can be adapted to the current
372 // conflict.
373 // - Some data can be reused between two calls about the same conflict.
374 // - Note however that if the reason is a simple clause, we shouldn't adapt
375 // it because we rely on extra fact in the first UIP code where we detect
376 // subsumed clauses for instance.
377 absl::Span<const Literal> Reason(BooleanVariable var,
378 int64_t conflict_id = -1) const;
379
380 // Returns the "type" of an assignment (see AssignmentType). Note that this
381 // function never returns kSameReasonAs or kCachedReason, it instead returns
382 // the initial type that caused this assignment. As such, it is different
383 // from Info(var).type and the latter should not be used outside this class.
384 int AssignmentType(BooleanVariable var) const;
385
386 // If a variable was propagated with EnqueueWithSameReasonAs(), returns its
387 // reference variable. Otherwise return the given variable.
388 BooleanVariable ReferenceVarWithSameReason(BooleanVariable var) const;
389
390 // This can be used to get a location at which the reason for the literal
391 // at trail_index on the trail can be stored. This clears the vector before
392 // returning it.
393 std::vector<Literal>* GetEmptyVectorToStoreReason(int trail_index) const {
394 if (trail_index >= reasons_repository_.size()) {
395 reasons_repository_.resize(trail_index + 1);
396 }
397 reasons_repository_[trail_index].clear();
398 return &reasons_repository_[trail_index];
399 }
400
401 // Shortcut for GetEmptyVectorToStoreReason(Index()).
402 std::vector<Literal>* GetEmptyVectorToStoreReason() const {
404 }
405
406 // Explicitly overwrite the reason so that the given propagator will be
407 // asked for it. This is currently only used by the BinaryImplicationGraph.
408 void ChangeReason(int trail_index, int propagator_id) {
409 const BooleanVariable var = trail_[trail_index].Variable();
410 info_[var].type = propagator_id;
411 old_type_[var] = propagator_id;
412 }
413
414 // Reverts the trail and underlying assignment to the given target trail
415 // index. Note that we do not touch the assignment info.
416 void Untrail(int target_trail_index) {
417 const int index = Index();
418 num_untrailed_enqueues_ += index - target_trail_index;
419 for (int i = target_trail_index; i < index; ++i) {
420 assignment_.UnassignLiteral(trail_[i]);
421 }
422 current_info_.trail_index = target_trail_index;
423 }
424
425 // Changes the decision level used by the next Enqueue().
426 void SetDecisionLevel(int level) { current_info_.level = level; }
427 int CurrentDecisionLevel() const { return current_info_.level; }
428
429 // Generic interface to set the current failing clause.
430 //
431 // Returns the address of a vector where a client can store the current
432 // conflict. This vector will be returned by the FailingClause() call.
433 std::vector<Literal>* MutableConflict() {
434 failing_sat_clause_ = nullptr;
435 return &conflict_;
436 }
437
438 // Returns the last conflict.
439 absl::Span<const Literal> FailingClause() const {
440 if (DEBUG_MODE && debug_checker_ != nullptr) {
441 CHECK(debug_checker_(conflict_));
442 }
443 return conflict_;
444 }
445
446 // Specific SatClause interface so we can update the conflict clause activity.
447 // Note that MutableConflict() automatically sets this to nullptr, so we can
448 // know whether or not the last conflict was caused by a clause.
449 void SetFailingSatClause(SatClause* clause) { failing_sat_clause_ = clause; }
450 SatClause* FailingSatClause() const { return failing_sat_clause_; }
451
452 // Getters.
453 int NumVariables() const { return trail_.size(); }
454 int64_t NumberOfEnqueues() const { return num_untrailed_enqueues_ + Index(); }
455 int Index() const { return current_info_.trail_index; }
456 // This accessor can return trail_.end(). operator[] cannot. This allows
457 // normal std:vector operations, such as assign(begin, end).
458 std::vector<Literal>::const_iterator IteratorAt(int index) const {
459 return trail_.begin() + index;
460 }
461 const Literal& operator[](int index) const { return trail_[index]; }
462 const VariablesAssignment& Assignment() const { return assignment_; }
463 const AssignmentInfo& Info(BooleanVariable var) const {
464 DCHECK_GE(var, 0);
465 DCHECK_LT(var, info_.size());
466 return info_[var];
467 }
468
469 // Print the current literals on the trail.
470 std::string DebugString() const {
471 std::string result;
472 for (int i = 0; i < current_info_.trail_index; ++i) {
473 if (!result.empty()) result += " ";
474 result += trail_[i].DebugString();
475 }
476 return result;
477 }
478
480 std::function<bool(absl::Span<const Literal> clause)> checker) {
481 debug_checker_ = std::move(checker);
482 }
483
484 private:
485 int64_t num_untrailed_enqueues_ = 0;
486 AssignmentInfo current_info_;
487 VariablesAssignment assignment_;
488 std::vector<Literal> trail_;
489 std::vector<Literal> conflict_;
491 SatClause* failing_sat_clause_;
492
493 // Data used by EnqueueWithSameReasonAs().
495 reference_var_with_same_reason_as_;
496
497 // Reason cache. Mutable since we want the API to be the same whether the
498 // reason are cached or not.
499 //
500 // When a reason is computed for the first time, we change the type of the
501 // variable assignment to kCachedReason so that we know that if it is needed
502 // again the reason can just be retrieved by a direct access to reasons_. The
503 // old type is saved in old_type_ and can be retrieved by
504 // AssignmentType().
505 //
506 // Note(user): Changing the type is not "clean" but it is efficient. The idea
507 // is that it is important to do as little as possible when pushing/popping
508 // literals on the trail. Computing the reason happens a lot less often, so it
509 // is okay to do slightly more work then. Note also, that we don't need to
510 // do anything on "untrail", the kCachedReason type will be overwritten when
511 // the same variable is assigned again.
512 //
513 // TODO(user): An alternative would be to change the sign of the type. This
514 // would remove the need for a separate old_type_ vector, but it requires
515 // more bits for the type filed in AssignmentInfo.
516 //
517 // Note that we use a deque for the reason repository so that if we add
518 // variables, the memory address of the vectors (kept in reasons_) are still
519 // valid.
520 mutable std::deque<std::vector<Literal>> reasons_repository_;
522 reasons_;
524
525 // This is used by RegisterPropagator() and Reason().
526 std::vector<SatPropagator*> propagators_;
527
528 std::function<bool(absl::Span<const Literal> clause)> debug_checker_ =
529 nullptr;
530};
531
532// Base class for all the SAT constraints.
534 public:
535 explicit SatPropagator(const std::string& name)
537
538 // This type is neither copyable nor movable.
539 SatPropagator(const SatPropagator&) = delete;
541 virtual ~SatPropagator() = default;
542
543 // Sets/Gets this propagator unique id.
544 void SetPropagatorId(int id) { propagator_id_ = id; }
545 int PropagatorId() const { return propagator_id_; }
546
547 // Inspects the trail from propagation_trail_index_ until at least one literal
548 // is propagated. Returns false iff a conflict is detected (in which case
549 // trail->SetFailingClause() must be called).
550 //
551 // This must update propagation_trail_index_ so that all the literals before
552 // it have been propagated. In particular, if nothing was propagated, then
553 // PropagationIsDone() must return true.
554 virtual bool Propagate(Trail* trail) = 0;
555
556 // Reverts the state so that all the literals with a trail index greater or
557 // equal to the given one are not processed for propagation. Note that the
558 // trail current decision level is already reverted before this is called.
559 //
560 // TODO(user): Currently this is called at each Backtrack(), but we could
561 // bundle the calls in case multiple conflict one after the other are detected
562 // even before the Propagate() call of a SatPropagator is called.
563 //
564 // TODO(user): It is not yet 100% the case, but this can be guaranteed to be
565 // called with a trail index that will always be the start of a new decision
566 // level.
567 virtual void Untrail(const Trail& /*trail*/, int trail_index) {
568 propagation_trail_index_ = std::min(propagation_trail_index_, trail_index);
569 }
570
571 // Explains why the literal at given trail_index was propagated by returning a
572 // reason for this propagation. This will only be called for literals that are
573 // on the trail and were propagated by this class.
574 //
575 // The interpretation is that because all the literals of a reason were
576 // assigned to false, we could deduce the assignment of the given variable.
577 //
578 // The returned Span has to be valid until the literal is untrailed. A client
579 // can use trail_.GetEmptyVectorToStoreReason() if it doesn't have a memory
580 // location that already contains the reason.
581 //
582 // If conlict id is positive, then this is called during first UIP resolution
583 // and we will backtrack over this literal right away, so we don't need to
584 // have a span that survive more than once.
585 virtual absl::Span<const Literal> Reason(const Trail& /*trail*/,
586 int /*trail_index*/,
587 int64_t /*conflict_id*/) const {
588 LOG(FATAL) << "Not implemented.";
589 return {};
590 }
591
592 // Returns true if all the preconditions for Propagate() are satisfied.
593 // This is just meant to be used in a DCHECK.
594 bool PropagatePreconditionsAreSatisfied(const Trail& trail) const;
595
596 // Returns true iff all the trail was inspected by this propagator.
597 bool PropagationIsDone(const Trail& trail) const {
598 return propagation_trail_index_ == trail.Index();
599 }
600
601 // Small optimization: If a propagator does not contain any "constraints"
602 // there is no point calling propagate on it. Before each propagation, the
603 // solver will checks for emptiness, and construct an optimized list of
604 // propagator before looping many time over the list.
605 virtual bool IsEmpty() const { return false; }
606
607 protected:
608 const std::string name_;
611};
612
613// ######################## Implementations below ########################
614
615// TODO(user): A few of these method should be moved in a .cc
616
618 const Trail& trail) const {
619 if (propagation_trail_index_ > trail.Index()) {
620 LOG(INFO) << "Issue in '" << name_ << ":"
621 << " propagation_trail_index_=" << propagation_trail_index_
622 << " trail_.Index()=" << trail.Index();
623 return false;
624 }
625 if (propagation_trail_index_ < trail.Index() &&
626 trail.Info(trail[propagation_trail_index_].Variable()).level !=
627 trail.CurrentDecisionLevel()) {
628 LOG(INFO) << "Issue in '" << name_ << "':" << " propagation_trail_index_="
629 << propagation_trail_index_ << " trail_.Index()=" << trail.Index()
630 << " level_at_propagation_index="
631 << trail.Info(trail[propagation_trail_index_].Variable()).level
632 << " current_decision_level=" << trail.CurrentDecisionLevel();
633 return false;
634 }
635 return true;
636}
637
638inline void Trail::Resize(int num_variables) {
639 assignment_.Resize(num_variables);
640 info_.resize(num_variables);
641 trail_.resize(num_variables);
642 reasons_.resize(num_variables);
643
644 // TODO(user): these vectors are not always used. Initialize them
645 // dynamically.
646 old_type_.resize(num_variables);
647 reference_var_with_same_reason_as_.resize(num_variables);
648}
649
650inline void Trail::RegisterPropagator(SatPropagator* propagator) {
651 if (propagators_.empty()) {
652 propagators_.resize(AssignmentType::kFirstFreePropagationId);
653 }
654 CHECK_LT(propagators_.size(), 16);
655 propagator->SetPropagatorId(propagators_.size());
656 propagators_.push_back(propagator);
657}
658
660 BooleanVariable var) const {
661 DCHECK(Assignment().VariableIsAssigned(var));
662 // Note that we don't use AssignmentType() here.
663 if (info_[var].type == AssignmentType::kSameReasonAs) {
664 var = reference_var_with_same_reason_as_[var];
665 DCHECK(Assignment().VariableIsAssigned(var));
666 DCHECK_NE(info_[var].type, AssignmentType::kSameReasonAs);
667 }
668 return var;
669}
670
671inline int Trail::AssignmentType(BooleanVariable var) const {
672 if (info_[var].type == AssignmentType::kSameReasonAs) {
673 var = reference_var_with_same_reason_as_[var];
674 DCHECK_NE(info_[var].type, AssignmentType::kSameReasonAs);
675 }
676 const int type = info_[var].type;
677 return type != AssignmentType::kCachedReason ? type : old_type_[var];
678}
679
680inline absl::Span<const Literal> Trail::Reason(BooleanVariable var,
681 int64_t conflict_id) const {
682 // Special case for AssignmentType::kSameReasonAs to avoid a recursive call.
684
685 // Fast-track for cached reason.
686 if (info_[var].type == AssignmentType::kCachedReason) {
687 if (DEBUG_MODE && debug_checker_ != nullptr) {
688 std::vector<Literal> clause;
689 clause.assign(reasons_[var].begin(), reasons_[var].end());
690 clause.push_back(assignment_.GetTrueLiteralForAssignedVariable(var));
691 CHECK(debug_checker_(clause));
692 }
693 return reasons_[var];
694 }
695
696 const AssignmentInfo& info = info_[var];
697 if (info.type == AssignmentType::kUnitReason ||
699 reasons_[var] = {};
700 } else {
701 DCHECK_LT(info.type, propagators_.size());
702 DCHECK(propagators_[info.type] != nullptr) << info.type;
703 reasons_[var] =
704 propagators_[info.type]->Reason(*this, info.trail_index, conflict_id);
705 }
706 old_type_[var] = info.type;
708 if (DEBUG_MODE && debug_checker_ != nullptr) {
709 std::vector<Literal> clause;
710 clause.assign(reasons_[var].begin(), reasons_[var].end());
711 clause.push_back(assignment_.GetTrueLiteralForAssignedVariable(var));
712 CHECK(debug_checker_(clause));
713 }
714 return reasons_[var];
715}
716
717} // namespace sat
718} // namespace operations_research
719
720#endif // OR_TOOLS_SAT_SAT_BASE_H_
When speed matter, caching the base pointer helps.
Definition bitset.h:421
bool IsSet(IndexType i) const
Returns true if the bit at position i is set.
Definition bitset.h:538
IndexType size() const
Returns how many bits this Bitset64 can hold.
Definition bitset.h:468
void ClearTwoBits(IndexType i)
Clears the bits at position i and i ^ 1.
Definition bitset.h:524
void Resize(IndexType size)
Definition bitset.h:479
bool AreOneOfTwoBitsSet(IndexType i) const
Returns true if the bit at position i or the one at position i ^ 1 is set.
Definition bitset.h:531
void Set(IndexType i)
Sets the bit at position i to 1.
Definition bitset.h:548
AssignmentView(const VariablesAssignment &assignment)
Definition sat_base.h:224
bool LiteralIsFalse(Literal literal) const
Definition sat_base.h:227
bool LiteralIsTrue(Literal literal) const
Definition sat_base.h:231
bool operator<(const Literal &other) const
Definition sat_base.h:106
std::string DebugString() const
Definition sat_base.h:100
LiteralIndex NegatedIndex() const
Definition sat_base.h:92
bool operator!=(Literal other) const
Definition sat_base.h:105
friend H AbslHashValue(H h, Literal literal)
Definition sat_base.h:109
Literal(LiteralIndex index)
Definition sat_base.h:75
LiteralIndex Index() const
Definition sat_base.h:91
BooleanVariable Variable() const
Definition sat_base.h:87
Literal(BooleanVariable variable, bool is_positive)
Definition sat_base.h:76
bool operator==(Literal other) const
Definition sat_base.h:104
Base class for all the SAT constraints.
Definition sat_base.h:533
virtual absl::Span< const Literal > Reason(const Trail &, int, int64_t) const
Definition sat_base.h:585
bool PropagatePreconditionsAreSatisfied(const Trail &trail) const
######################## Implementations below ########################
Definition sat_base.h:617
SatPropagator(const std::string &name)
Definition sat_base.h:535
void SetPropagatorId(int id)
Sets/Gets this propagator unique id.
Definition sat_base.h:544
virtual void Untrail(const Trail &, int trail_index)
Definition sat_base.h:567
virtual bool Propagate(Trail *trail)=0
bool PropagationIsDone(const Trail &trail) const
Returns true iff all the trail was inspected by this propagator.
Definition sat_base.h:597
SatPropagator(const SatPropagator &)=delete
This type is neither copyable nor movable.
SatPropagator & operator=(const SatPropagator &)=delete
BooleanVariable ReferenceVarWithSameReason(BooleanVariable var) const
Definition sat_base.h:659
std::vector< Literal >::const_iterator IteratorAt(int index) const
Definition sat_base.h:458
int NumVariables() const
Getters.
Definition sat_base.h:453
std::vector< Literal > * MutableConflict()
Definition sat_base.h:433
int64_t NumberOfEnqueues() const
Definition sat_base.h:454
const Literal & operator[](int index) const
Definition sat_base.h:461
void SetDecisionLevel(int level)
Changes the decision level used by the next Enqueue().
Definition sat_base.h:426
int AssignmentType(BooleanVariable var) const
Definition sat_base.h:671
Trail(const Trail &)=delete
This type is neither copyable nor movable.
void EnqueueSearchDecision(Literal true_literal)
Specific Enqueue() version for the search decision.
Definition sat_base.h:323
std::string DebugString() const
Print the current literals on the trail.
Definition sat_base.h:470
void Enqueue(Literal true_literal, int propagator_id)
Definition sat_base.h:317
void Untrail(int target_trail_index)
Definition sat_base.h:416
void EnqueueWithSameReasonAs(Literal true_literal, BooleanVariable reference_var)
Definition sat_base.h:335
absl::Span< const Literal > Reason(BooleanVariable var, int64_t conflict_id=-1) const
Definition sat_base.h:680
std::vector< Literal > * GetEmptyVectorToStoreReason() const
Shortcut for GetEmptyVectorToStoreReason(Index()).
Definition sat_base.h:402
void RegisterDebugChecker(std::function< bool(absl::Span< const Literal > clause)> checker)
Definition sat_base.h:479
void EnqueueWithUnitReason(Literal true_literal)
Specific Enqueue() version for a fixed variable.
Definition sat_base.h:328
void ChangeReason(int trail_index, int propagator_id)
Definition sat_base.h:408
void SetFailingSatClause(SatClause *clause)
Definition sat_base.h:449
Trail & operator=(const Trail &)=delete
const AssignmentInfo & Info(BooleanVariable var) const
Definition sat_base.h:463
std::vector< Literal > * GetEmptyVectorToStoreReason(int trail_index) const
Definition sat_base.h:393
void RegisterPropagator(SatPropagator *propagator)
Definition sat_base.h:650
void SetCurrentPropagatorId(int propagator_id)
Definition sat_base.h:307
void FastEnqueue(Literal true_literal)
Definition sat_base.h:310
ABSL_MUST_USE_RESULT bool EnqueueWithStoredReason(Literal true_literal)
Definition sat_base.h:347
SatClause * FailingSatClause() const
Definition sat_base.h:450
absl::Span< const Literal > FailingClause() const
Returns the last conflict.
Definition sat_base.h:439
void Resize(int num_variables)
Definition sat_base.h:638
const VariablesAssignment & Assignment() const
Definition sat_base.h:462
bool VariableIsAssigned(BooleanVariable var) const
Returns true iff the given variable is assigned.
Definition sat_base.h:196
bool LiteralIsAssigned(Literal literal) const
Definition sat_base.h:191
VariablesAssignment & operator=(const VariablesAssignment &)=delete
Literal GetTrueLiteralForAssignedVariable(BooleanVariable var) const
Definition sat_base.h:203
bool LiteralIsFalse(Literal literal) const
Definition sat_base.h:185
VariablesAssignment(const VariablesAssignment &)=delete
This type is neither copyable nor movable.
bool LiteralIsTrue(Literal literal) const
Definition sat_base.h:188
void resize(size_type new_size)
const std::string name
A name for logging purposes.
int64_t value
IntVar * var
int literal
int index
const bool DEBUG_MODE
Definition macros.h:24
void AbslStringify(Sink &sink, Literal arg)
Definition sat_base.h:123
const LiteralIndex kNoLiteralIndex(-1)
const LiteralIndex kTrueLiteralIndex(-2)
std::ostream & operator<<(std::ostream &os, const BoolVar &var)
Definition cp_model.cc:89
const LiteralIndex kFalseLiteralIndex(-3)
std::vector< Literal > Literals(absl::Span< const int > input)
Definition sat_base.h:146
const BooleanVariable kNoBooleanVariable(-1)
In SWIG mode, we don't want anything besides these top-level includes.
static int input(yyscan_t yyscanner)
std::optional< int64_t > end
#define DEFINE_STRONG_INDEX_TYPE(index_type_name)
Information about a variable assignment.
Definition sat_base.h:242
int32_t trail_index
The index of this assignment in the trail.
Definition sat_base.h:263
static constexpr int kFirstFreePropagationId
Propagator ids starts from there and are created dynamically.
Definition sat_base.h:282