16#ifndef OR_TOOLS_SAT_SAT_BASE_H_
17#define OR_TOOLS_SAT_SAT_BASE_H_
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"
69 : index_(signed_value > 0 ? ((signed_value - 1) << 1)
70 : ((-signed_value - 1) << 1) ^ 1) {
71 CHECK_NE(signed_value, 0);
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) {}
85 operator LiteralIndex()
const {
return Index(); }
87 BooleanVariable
Variable()
const {
return BooleanVariable(index_ >> 1); }
91 LiteralIndex
Index()
const {
return LiteralIndex(index_); }
92 LiteralIndex
NegatedIndex()
const {
return LiteralIndex(index_ ^ 1); }
95 return (index_ & 1) ? -((index_ >> 1) + 1) : ((index_ >> 1) + 1);
108 template <
typename H>
110 return H::combine(std::move(h), literal.index_);
122template <
typename Sink,
typename... T>
128 absl::Span<const Literal> literals) {
131 for (
const Literal literal : literals) {
137 os << literal.DebugString();
147 std::vector<Literal> result(
input.size());
148 for (
int i = 0;
i < result.size(); ++
i) {
165 assignment_.Resize(LiteralIndex(num_variables << 1));
173 assignment_.Set(literal.
Index());
180 assignment_.ClearTwoBits(literal.
Index());
189 return assignment_.IsSet(literal.
Index());
192 return assignment_.AreOneOfTwoBitsSet(literal.
Index());
197 return assignment_.AreOneOfTwoBitsSet(LiteralIndex(var.value() << 1));
205 return Literal(var, assignment_.IsSet(LiteralIndex(var.value() << 1)));
225 : view_(assignment.assignment_.const_view()) {}
266 return absl::StrFormat(
"level:%d type:%d trail_index:%d",
level,
type,
270static_assert(
sizeof(AssignmentInfo) == 8,
271 "ERROR_AssignmentInfo_is_not_well_compacted");
291 current_info_.trail_index = 0;
292 current_info_.level = 0;
299 void Resize(
int num_variables);
308 current_info_.type = propagator_id;
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;
336 BooleanVariable reference_var) {
337 reference_var_with_same_reason_as_[true_literal.
Variable()] = reference_var;
348 if (assignment_.LiteralIsTrue(true_literal))
return true;
349 if (assignment_.LiteralIsFalse(true_literal)) {
356 const BooleanVariable var = true_literal.
Variable();
357 reasons_[var] = reasons_repository_[info_[var].trail_index];
358 old_type_[var] = info_[var].type;
377 absl::Span<const Literal>
Reason(BooleanVariable var,
378 int64_t conflict_id = -1)
const;
394 if (trail_index >= reasons_repository_.size()) {
395 reasons_repository_.resize(trail_index + 1);
397 reasons_repository_[trail_index].clear();
398 return &reasons_repository_[trail_index];
409 const BooleanVariable var = trail_[trail_index].Variable();
410 info_[var].type = propagator_id;
411 old_type_[var] = propagator_id;
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]);
422 current_info_.trail_index = target_trail_index;
434 failing_sat_clause_ =
nullptr;
440 if (
DEBUG_MODE && debug_checker_ !=
nullptr) {
441 CHECK(debug_checker_(conflict_));
455 int Index()
const {
return current_info_.trail_index; }
458 std::vector<Literal>::const_iterator
IteratorAt(
int index)
const {
459 return trail_.begin() + index;
465 DCHECK_LT(var, info_.size());
472 for (
int i = 0;
i < current_info_.trail_index; ++
i) {
473 if (!result.empty()) result +=
" ";
474 result += trail_[
i].DebugString();
480 std::function<
bool(absl::Span<const Literal> clause)> checker) {
481 debug_checker_ = std::move(checker);
485 int64_t num_untrailed_enqueues_ = 0;
488 std::vector<Literal> trail_;
489 std::vector<Literal> conflict_;
495 reference_var_with_same_reason_as_;
520 mutable std::deque<std::vector<Literal>> reasons_repository_;
526 std::vector<SatPropagator*> propagators_;
528 std::function<bool(absl::Span<const Literal> clause)> debug_checker_ =
588 LOG(FATAL) <<
"Not implemented.";
605 virtual bool IsEmpty()
const {
return false; }
618 const Trail& trail)
const {
620 LOG(INFO) <<
"Issue in '" <<
name_ <<
":"
622 <<
" trail_.Index()=" << trail.
Index();
628 LOG(INFO) <<
"Issue in '" <<
name_ <<
"':"
630 <<
" trail_.Index()=" << trail.
Index()
631 <<
" level_at_propagation_index="
640 assignment_.Resize(num_variables);
641 info_.resize(num_variables);
642 trail_.resize(num_variables);
643 reasons_.resize(num_variables);
647 old_type_.resize(num_variables);
648 reference_var_with_same_reason_as_.resize(num_variables);
652 if (propagators_.empty()) {
655 CHECK_LT(propagators_.size(), 16);
657 propagators_.push_back(propagator);
661 BooleanVariable var)
const {
665 var = reference_var_with_same_reason_as_[var];
674 var = reference_var_with_same_reason_as_[var];
677 const int type = info_[var].type;
682 int64_t conflict_id)
const {
688 if (
DEBUG_MODE && debug_checker_ !=
nullptr) {
689 std::vector<Literal> clause;
690 clause.assign(reasons_[var].begin(), reasons_[var].end());
691 clause.push_back(assignment_.GetTrueLiteralForAssignedVariable(var));
692 CHECK(debug_checker_(clause));
694 return reasons_[var];
702 DCHECK_LT(info.
type, propagators_.size());
703 DCHECK(propagators_[info.
type] !=
nullptr) << info.
type;
707 old_type_[var] = info.
type;
709 if (
DEBUG_MODE && debug_checker_ !=
nullptr) {
710 std::vector<Literal> clause;
711 clause.assign(reasons_[var].begin(), reasons_[var].end());
712 clause.push_back(assignment_.GetTrueLiteralForAssignedVariable(var));
713 CHECK(debug_checker_(clause));
715 return reasons_[var];
When speed matter, caching the base pointer helps.
AssignmentView(const VariablesAssignment &assignment)
bool LiteralIsFalse(Literal literal) const
bool LiteralIsTrue(Literal literal) const
bool operator<(const Literal &other) const
std::string DebugString() const
LiteralIndex NegatedIndex() const
bool operator!=(Literal other) const
friend H AbslHashValue(H h, Literal literal)
Literal(LiteralIndex index)
LiteralIndex Index() const
BooleanVariable Variable() const
Literal(BooleanVariable variable, bool is_positive)
Literal(int signed_value)
bool operator==(Literal other) const
Base class for all the SAT constraints.
virtual absl::Span< const Literal > Reason(const Trail &, int, int64_t) const
bool PropagatePreconditionsAreSatisfied(const Trail &trail) const
######################## Implementations below ########################
SatPropagator(const std::string &name)
int propagation_trail_index_
void SetPropagatorId(int id)
Sets/Gets this propagator unique id.
virtual void Untrail(const Trail &, int trail_index)
virtual bool Propagate(Trail *trail)=0
virtual bool IsEmpty() const
bool PropagationIsDone(const Trail &trail) const
Returns true iff all the trail was inspected by this propagator.
SatPropagator(const SatPropagator &)=delete
This type is neither copyable nor movable.
SatPropagator & operator=(const SatPropagator &)=delete
virtual ~SatPropagator()=default
BooleanVariable ReferenceVarWithSameReason(BooleanVariable var) const
std::vector< Literal >::const_iterator IteratorAt(int index) const
int NumVariables() const
Getters.
std::vector< Literal > * MutableConflict()
int64_t NumberOfEnqueues() const
const Literal & operator[](int index) const
void SetDecisionLevel(int level)
Changes the decision level used by the next Enqueue().
int AssignmentType(BooleanVariable var) const
Trail(const Trail &)=delete
This type is neither copyable nor movable.
void EnqueueSearchDecision(Literal true_literal)
Specific Enqueue() version for the search decision.
std::string DebugString() const
Print the current literals on the trail.
void Enqueue(Literal true_literal, int propagator_id)
void Untrail(int target_trail_index)
void EnqueueWithSameReasonAs(Literal true_literal, BooleanVariable reference_var)
absl::Span< const Literal > Reason(BooleanVariable var, int64_t conflict_id=-1) const
std::vector< Literal > * GetEmptyVectorToStoreReason() const
Shortcut for GetEmptyVectorToStoreReason(Index()).
void RegisterDebugChecker(std::function< bool(absl::Span< const Literal > clause)> checker)
void EnqueueWithUnitReason(Literal true_literal)
Specific Enqueue() version for a fixed variable.
int CurrentDecisionLevel() const
void ChangeReason(int trail_index, int propagator_id)
void SetFailingSatClause(SatClause *clause)
Trail & operator=(const Trail &)=delete
const AssignmentInfo & Info(BooleanVariable var) const
std::vector< Literal > * GetEmptyVectorToStoreReason(int trail_index) const
void RegisterPropagator(SatPropagator *propagator)
void SetCurrentPropagatorId(int propagator_id)
void FastEnqueue(Literal true_literal)
ABSL_MUST_USE_RESULT bool EnqueueWithStoredReason(Literal true_literal)
SatClause * FailingSatClause() const
absl::Span< const Literal > FailingClause() const
Returns the last conflict.
void Resize(int num_variables)
const VariablesAssignment & Assignment() const
bool VariableIsAssigned(BooleanVariable var) const
Returns true iff the given variable is assigned.
bool LiteralIsAssigned(Literal literal) const
friend class AssignmentView
VariablesAssignment & operator=(const VariablesAssignment &)=delete
Literal GetTrueLiteralForAssignedVariable(BooleanVariable var) const
bool LiteralIsFalse(Literal literal) const
int NumberOfVariables() const
void AssignFromTrueLiteral(Literal literal)
void UnassignLiteral(Literal literal)
VariablesAssignment(const VariablesAssignment &)=delete
This type is neither copyable nor movable.
VariablesAssignment()=default
void Resize(int num_variables)
VariablesAssignment(int num_variables)
bool LiteralIsTrue(Literal literal) const
const LiteralIndex kNoLiteralIndex(-1)
const LiteralIndex kTrueLiteralIndex(-2)
std::ostream & operator<<(std::ostream &os, const BoolVar &var)
const LiteralIndex kFalseLiteralIndex(-3)
std::vector< Literal > Literals(absl::Span< const int > input)
void AbslStringify(Sink &sink, EdgePosition e)
const BooleanVariable kNoBooleanVariable(-1)
In SWIG mode, we don't want anything besides these top-level includes.
static int input(yyscan_t yyscanner)
#define DEFINE_STRONG_INDEX_TYPE(index_type_name)
Information about a variable assignment.
std::string DebugString() const
int32_t trail_index
The index of this assignment in the trail.
static constexpr int kSearchDecision
static constexpr int kSameReasonAs
static constexpr int kFirstFreePropagationId
Propagator ids starts from there and are created dynamically.
static constexpr int kUnitReason
static constexpr int kCachedReason