16#ifndef ORTOOLS_SAT_SAT_BASE_H_
17#define ORTOOLS_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"
70 : index_(signed_value > 0 ? ((signed_value - 1) << 1)
71 : ((-signed_value - 1) << 1) ^ 1) {
72 CHECK_NE(signed_value, 0);
76 explicit Literal(LiteralIndex index) : index_(index.value()) {}
77 Literal(BooleanVariable variable,
bool is_positive)
78 : index_(is_positive ? (variable.value() << 1)
79 : (variable.value() << 1) ^ 1) {}
86 operator LiteralIndex()
const {
return Index(); }
88 BooleanVariable
Variable()
const {
return BooleanVariable(index_ >> 1); }
92 LiteralIndex
Index()
const {
return LiteralIndex(index_); }
93 LiteralIndex
NegatedIndex()
const {
return LiteralIndex(index_ ^ 1); }
96 return (index_ & 1) ? -((index_ >> 1) + 1) : ((index_ >> 1) + 1);
110 template <
typename H>
112 return H::combine(std::move(h), literal.index_);
124template <
typename Sink,
typename... T>
130 absl::Span<const Literal> literals) {
133 for (
const Literal literal : literals) {
139 os << literal.DebugString();
146 absl::Span<const LiteralIndex> literals) {
149 for (
const LiteralIndex index : literals) {
165 std::vector<Literal> result(
input.size());
166 for (
int i = 0;
i < result.size(); ++
i) {
183 assignment_.Resize(LiteralIndex(num_variables << 1));
191 assignment_.Set(literal.
Index());
198 assignment_.ClearTwoBits(literal.
Index());
207 return assignment_.IsSet(literal.
Index());
210 return assignment_.AreOneOfTwoBitsSet(literal.
Index());
215 return assignment_.AreOneOfTwoBitsSet(LiteralIndex(var.value() << 1));
223 return Literal(var, assignment_.IsSet(LiteralIndex(var.value() << 1)));
247 : view_(assignment.assignment_.const_view()) {}
269 ClauseId next_id_ = ClauseId(1);
301 return absl::StrFormat(
"level:%d type:%d trail_index:%d",
level,
type,
305static_assert(
sizeof(AssignmentInfo) == 8,
306 "ERROR_AssignmentInfo_is_not_well_compacted");
334 current_info_.trail_index = 0;
335 current_info_.level = 0;
342 void Resize(
int num_variables);
351 DCHECK(!assignment_.VariableIsAssigned(true_literal.
Variable()));
352 trail_[current_info_.trail_index] = true_literal;
353 current_info_.type = propagator_id;
354 info_[true_literal.
Variable()] = current_info_;
355 assignment_.AssignFromTrueLiteral(true_literal);
356 ++current_info_.trail_index;
359 Enqueue(true_literal, propagator_id);
360 if (use_chronological_backtracking_) {
361 info_[true_literal.
Variable()].level = level;
374 : trail_ptr_(trail_ptr),
375 current_info_(current_info),
377 bitset_(assignment->GetBitsetView()),
378 clause_ids_(clause_ids) {}
381 bitset_.Set(true_literal);
383 *info = *current_info_;
385 trail_ptr_[current_info_->trail_index++] = true_literal;
390 const BooleanVariable var = true_literal.
Variable();
391 if (var.value() >= clause_ids_->size()) {
394 (*clause_ids_)[var] = clause_id;
396 bitset_.Set(true_literal);
398 *info = *current_info_;
401 trail_ptr_[current_info_->trail_index++] = true_literal;
405 return bitset_[literal.
Index()];
419 current_info_.type = propagator_id;
420 return EnqueueHelper(trail_.data(), ¤t_info_, info_.data(),
421 &assignment_, &clause_ids_);
426 decisions_[current_decision_level_] =
428 current_info_.level = ++current_decision_level_;
434 if (current_decision_level_ == 0) {
437 current_info_.level = ++current_decision_level_;
439 CHECK_EQ(current_decision_level_, 1);
444 decisions_[level].literal = literal;
451 const std::vector<LiteralWithTrailIndex>&
Decisions()
const {
462 MaybeSetClauseId(true_literal, clause_id);
470 BooleanVariable reference_var) {
471 reference_var_with_same_reason_as_[true_literal.
Variable()] = reference_var;
486 if (assignment_.LiteralIsTrue(true_literal))
return true;
487 if (assignment_.LiteralIsFalse(true_literal)) {
490 failing_clause_id_ = clause_id;
494 MaybeSetClauseId(true_literal, clause_id);
496 const BooleanVariable var = true_literal.
Variable();
497 reasons_[var] = reasons_repository_[info_[var].trail_index];
498 old_type_[var] = info_[var].type;
503 for (
const Literal literal : reasons_[var]) {
504 level = std::max(level,
Info(literal.Variable()).
level);
506 info_[var].level = level;
525 absl::Span<const Literal>
Reason(BooleanVariable var,
526 int64_t conflict_id = -1)
const;
539 DCHECK_EQ(
Info(var).level, 0);
540 if (var.value() >= clause_ids_.size())
return kNoClauseId;
541 return clause_ids_[var];
549 if (var.value() >= clause_ids_.size())
return kNoClauseId;
550 return clause_ids_[var];
561 if (trail_index >= reasons_repository_.size()) {
562 reasons_repository_.resize(trail_index + 1);
564 reasons_repository_[trail_index].clear();
565 return &reasons_repository_[trail_index];
577 const BooleanVariable var = trail_[trail_index].Variable();
578 info_[var].type = propagator_id;
579 old_type_[var] = propagator_id;
588 current_decision_level_ = level;
589 current_info_.level = level;
590 return decisions_[level].trail_index;
596 const int index =
Index();
597 num_untrailed_enqueues_ += index - target_trail_index;
598 for (
int i = target_trail_index;
i < index; ++
i) {
599 assignment_.UnassignLiteral(trail_[
i]);
601 current_info_.trail_index = target_trail_index;
602 if (use_chronological_backtracking_) {
614 ++conflict_timestamp_;
615 failing_sat_clause_ =
nullptr;
625 if (
DEBUG_MODE && debug_checker_ !=
nullptr) {
626 CHECK(debug_checker_(conflict_));
635 failing_sat_clause_ = clause;
647 int Index()
const {
return current_info_.trail_index; }
650 std::vector<Literal>::const_iterator
IteratorAt(
int index)
const {
651 return trail_.begin() + index;
657 DCHECK_LT(var, info_.size());
666 for (
int i = 0;
i < current_info_.trail_index; ++
i) {
667 if (!result.empty()) result +=
" ";
668 result += trail_[
i].DebugString();
674 std::function<
bool(absl::Span<const Literal> clause)> checker) {
675 debug_checker_ = std::move(checker);
679 return use_chronological_backtracking_;
684 use_chronological_backtracking_ = enable;
688 std::vector<Literal>* conflict,
689 std::vector<Literal>* reason_used_to_infer_the_conflict,
690 std::vector<SatClause*>* subsumed_clauses)>;
693 resolution_ = std::move(resolution);
705 void MaybeSetClauseId(
Literal true_literal, ClauseId clause_id) {
707 const BooleanVariable var = true_literal.
Variable();
708 if (var.value() >= clause_ids_.size()) {
711 clause_ids_[var] = clause_id;
718 void ReimplyAll(
int old_trail_index);
720 bool use_chronological_backtracking_ =
false;
721 int64_t num_reimplied_literals_ = 0;
722 int64_t num_untrailed_enqueues_ = 0;
723 AssignmentInfo current_info_;
724 VariablesAssignment assignment_;
725 std::vector<Literal> trail_;
726 int64_t conflict_timestamp_ = 0;
727 std::vector<Literal> conflict_;
728 util_intops::StrongVector<BooleanVariable, AssignmentInfo> info_;
731 util_intops::StrongVector<BooleanVariable, ClauseId> clause_ids_;
732 SatClause* failing_sat_clause_;
733 ClauseId failing_clause_id_;
736 util_intops::StrongVector<BooleanVariable, BooleanVariable>
737 reference_var_with_same_reason_as_;
762 mutable std::deque<std::vector<Literal>> reasons_repository_;
763 mutable util_intops::StrongVector<BooleanVariable, absl::Span<const Literal>>
765 mutable util_intops::StrongVector<BooleanVariable, int> old_type_;
768 std::vector<SatPropagator*> propagators_;
770 std::function<bool(absl::Span<const Literal> clause)> debug_checker_ =
773 int last_num_reimplication_ = 0;
779 int current_decision_level_ = 0;
780 std::vector<LiteralWithTrailIndex> decisions_;
829 LOG(DFATAL) <<
"Reimply not implemented for " <<
name_ <<
".";
849 LOG(FATAL) <<
"Not implemented.";
868 virtual bool IsEmpty()
const {
return false; }
881 const Trail& trail)
const {
883 LOG(INFO) <<
"Issue in '" <<
name_ <<
":"
885 <<
" trail_.Index()=" << trail.
Index();
891 LOG(INFO) <<
"Issue in '" <<
name_ <<
"':"
893 <<
" trail_.Index()=" << trail.
Index()
894 <<
" level_at_propagation_index="
903 assignment_.Resize(num_variables);
904 info_.resize(num_variables);
905 trail_.resize(num_variables);
906 reasons_.resize(num_variables);
910 old_type_.resize(num_variables);
911 reference_var_with_same_reason_as_.resize(num_variables);
916 decisions_.resize(num_variables + 1);
920 if (propagators_.empty()) {
923 CHECK_LT(propagators_.size(), 16);
924 VLOG(2) <<
"Registering propagator " << propagator->
name() <<
" with id "
925 << propagators_.size();
927 propagators_.push_back(propagator);
931 BooleanVariable var)
const {
935 var = reference_var_with_same_reason_as_[var];
944 var = reference_var_with_same_reason_as_[var];
947 const int type = info_[var].type;
952 int64_t conflict_id)
const {
958 if (
DEBUG_MODE && debug_checker_ !=
nullptr) {
959 std::vector<Literal> clause;
960 clause.assign(reasons_[var].
begin(), reasons_[var].
end());
961 clause.push_back(assignment_.GetTrueLiteralForAssignedVariable(var));
962 CHECK(debug_checker_(clause)) <<
" for cached reason";
964 return reasons_[var];
972 DCHECK_LT(info.
type, propagators_.size());
973 DCHECK(propagators_[info.
type] !=
nullptr) << info.
type;
977 old_type_[var] = info.
type;
979 if (
DEBUG_MODE && debug_checker_ !=
nullptr) {
980 std::vector<Literal> clause;
981 clause.assign(reasons_[var].
begin(), reasons_[var].
end());
982 clause.push_back(assignment_.GetTrueLiteralForAssignedVariable(var));
983 CHECK(debug_checker_(clause)) <<
"for propagator_id=" << old_type_[var];
985 return reasons_[var];
988inline void Trail::ReimplyAll(
int old_trail_index) {
989 const int64_t initial_num_reimplied = num_reimplied_literals_;
990 for (
int i =
Index();
i < old_trail_index; ++
i) {
993 if (info.
level > current_info_.
level)
continue;
1008 propagators_[original_type]->Reimply(
this,
i);
1010 std::swap(reasons_repository_[
Index()], reasons_repository_[
i]);
1011 reasons_[literal.
Variable()] = reasons_repository_[
Index()];
1014 CHECK(!
Assignment().LiteralIsFalse(literal));
1018 num_reimplied_literals_ += assignment_.LiteralIsTrue(literal);
1020 last_num_reimplication_ = num_reimplied_literals_ - initial_num_reimplied;
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
virtual void Reimply(Trail *, int)
virtual absl::Span< const Literal > Reason(const Trail &, int, int64_t) const
bool PropagatePreconditionsAreSatisfied(const Trail &trail) const
SatPropagator(const std::string &name)
int propagation_trail_index_
void SetPropagatorId(int 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
SatPropagator(const SatPropagator &)=delete
const std::string & name() const
SatPropagator & operator=(const SatPropagator &)=delete
virtual ~SatPropagator()=default
void EnqueueWithUnitReason(Literal true_literal, ClauseId clause_id)
void EnqueueAtLevel(Literal true_literal, int level)
EnqueueHelper(Literal *trail_ptr, AssignmentInfo *current_info, AssignmentInfo *info_ptr, VariablesAssignment *assignment, util_intops::StrongVector< BooleanVariable, ClauseId > *clause_ids)
bool LiteralIsTrue(Literal literal) const
bool LiteralIsFalse(Literal literal) const
void EnqueueAtLevel(Literal true_literal, int propagator_id, int level)
BooleanVariable ReferenceVarWithSameReason(BooleanVariable var) const
std::vector< Literal >::const_iterator IteratorAt(int index) const
void EnableChronologicalBacktracking(bool enable)
ConflictResolutionFunction GetConflictResolutionFunction()
std::vector< Literal > * MutableConflict()
int64_t NumberOfEnqueues() const
const Literal & operator[](int index) const
int AssignmentType(BooleanVariable var) const
Trail(const Trail &)=delete
void EnqueueSearchDecision(Literal true_literal)
void SetConflictResolutionFunction(ConflictResolutionFunction resolution)
std::string DebugString() const
void Enqueue(Literal true_literal, int propagator_id)
void Untrail(int target_trail_index)
ClauseId GetUnitClauseId(BooleanVariable var) const
void EnqueueWithSameReasonAs(Literal true_literal, BooleanVariable reference_var)
void EnqueueAssumption(Literal assumptions)
absl::Span< const Literal > Reason(BooleanVariable var, int64_t conflict_id=-1) const
std::vector< Literal > * GetEmptyVectorToStoreReason() const
int NumReimplicationsOnLastUntrail() const
int PrepareBacktrack(int level)
std::function< void( std::vector< Literal > *conflict, std::vector< Literal > *reason_used_to_infer_the_conflict, std::vector< SatClause * > *subsumed_clauses)> ConflictResolutionFunction
void RegisterDebugChecker(std::function< bool(absl::Span< const Literal > clause)> checker)
void EnqueueWithUnitReason(Literal true_literal)
ABSL_MUST_USE_RESULT bool EnqueueWithStoredReason(ClauseId clause_id, Literal true_literal)
int CurrentDecisionLevel() const
EnqueueHelper GetEnqueueHelper(int propagator_id)
void ChangeReason(int trail_index, int propagator_id)
void OverrideDecision(int level, Literal literal)
int AssignmentLevel(Literal lit) const
void SetFailingSatClause(SatClause *clause)
ClauseId GetStoredReasonClauseId(BooleanVariable var) const
bool ChronologicalBacktrackingEnabled() const
Trail & operator=(const Trail &)=delete
const AssignmentInfo & Info(BooleanVariable var) const
std::vector< Literal > * GetEmptyVectorToStoreReason(int trail_index) const
void RegisterPropagator(SatPropagator *propagator)
ClauseId FailingClauseId() const
SatClause * FailingSatClause() const
const std::vector< LiteralWithTrailIndex > & Decisions() const
absl::Span< const Literal > FailingClause() const
int64_t conflict_timestamp() const
void Resize(int num_variables)
void EnqueueWithUnitReason(ClauseId clause_id, Literal true_literal)
const VariablesAssignment & Assignment() const
bool VariableIsAssigned(BooleanVariable var) const
bool LiteralIsAssigned(Literal literal) const
friend class AssignmentView
Bitset64< LiteralIndex >::View GetBitsetView()
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
VariablesAssignment()=default
void Resize(int num_variables)
VariablesAssignment(int num_variables)
bool LiteralIsTrue(Literal literal) const
void resize(size_type new_size)
const LiteralIndex kNoLiteralIndex(-1)
const LiteralIndex kTrueLiteralIndex(-2)
std::ostream & operator<<(std::ostream &os, const BoolVar &var)
constexpr ClauseId kNoClauseId(0)
const LiteralIndex kFalseLiteralIndex(-3)
std::vector< Literal > Literals(absl::Span< const int > input)
void AbslStringify(Sink &sink, EdgePosition e)
const BooleanVariable kNoBooleanVariable(-1)
ClosedInterval::Iterator end(ClosedInterval interval)
ClosedInterval::Iterator begin(ClosedInterval interval)
static int input(yyscan_t yyscanner)
#define DEFINE_STRONG_INT_TYPE(type_name, value_type)
#define DEFINE_STRONG_INDEX_TYPE(index_type_name)
std::string DebugString() const
static constexpr int kSearchDecision
static constexpr int kSameReasonAs
static constexpr int kFirstFreePropagationId
static constexpr int kUnitReason
static constexpr int kCachedReason
LiteralWithTrailIndex()=default
LiteralWithTrailIndex(Literal l, int i)