17#ifndef OR_TOOLS_SAT_CLAUSE_H_
18#define OR_TOOLS_SAT_CLAUSE_H_
27#include "absl/base/attributes.h"
28#include "absl/container/flat_hash_map.h"
29#include "absl/container/flat_hash_set.h"
30#include "absl/container/inlined_vector.h"
31#include "absl/functional/any_invocable.h"
32#include "absl/log/check.h"
33#include "absl/random/bit_gen_ref.h"
34#include "absl/types/span.h"
39#include "ortools/sat/sat_parameters.pb.h"
62 void operator delete(
void* p) {
67 int size()
const {
return size_; }
77 const Literal*
end()
const {
return &(literals_[size_]); }
93 return absl::Span<const Literal>(&(literals_[1]), size_ - 1);
97 absl::Span<const Literal>
AsSpan()
const {
98 return absl::Span<const Literal>(&(literals_[0]), size_);
121 Literal* literals() {
return &(literals_[0]); }
126 void Clear() { size_ = 0; }
130 void Rewrite(absl::Span<const Literal> new_clause) {
132 for (
const Literal l : new_clause) literals_[size_++] = l;
139 Literal literals_[0];
170 void Resize(
int num_variables);
174 absl::Span<const Literal>
Reason(
const Trail& trail,
int trail_index,
175 int64_t conflict_id)
const final;
183 bool AddClause(absl::Span<const Literal> literals,
Trail* trail,
int lbd);
184 bool AddClause(absl::Span<const Literal> literals);
189 Trail* trail,
int lbd);
224 return clauses_info_.contains(clause);
228 return &clauses_info_;
234 return num_inspected_clause_literals_;
244 drat_proof_handler_ = drat_proof_handler;
252 for (; to_minimize_index_ < clauses_.size(); ++to_minimize_index_) {
253 if (clauses_[to_minimize_index_]->IsRemoved())
continue;
255 return clauses_[to_minimize_index_++];
261 for (; to_probe_index_ < clauses_.size(); ++to_probe_index_) {
262 if (clauses_[to_probe_index_]->IsRemoved())
continue;
263 return clauses_[to_probe_index_++];
291 SatClause* clause, absl::Span<const Literal> new_clause);
326 return watchers_on_false_[false_literal];
330 absl::AnyInvocable<
void(
int lbd, absl::Span<const Literal>)>
331 add_clause_callback) {
332 add_clause_callback_ = std::move(add_clause_callback);
342 bool PropagateOnFalse(
Literal false_literal,
Trail* trail);
357 std::vector<SatClause*> reasons_;
362 bool is_clean_ =
true;
367 int64_t num_inspected_clauses_;
368 int64_t num_inspected_clause_literals_;
369 int64_t num_watched_clauses_;
373 bool all_clauses_are_attached_ =
true;
380 std::vector<SatClause*> clauses_;
382 int to_minimize_index_ = 0;
383 int to_probe_index_ = 0;
386 absl::flat_hash_map<SatClause*, ClauseInfo> clauses_info_;
390 absl::AnyInvocable<void(
int lbd, absl::Span<const Literal>)>
391 add_clause_callback_ =
nullptr;
417 std::pair<int, int> p(c.a.SignedValue(), c.b.SignedValue());
418 if (p.first > p.second) std::swap(p.first, p.second);
419 if (set_.find(p) == set_.end()) {
421 newly_added_.push_back(c);
428 const std::vector<BinaryClause>&
newly_added()
const {
return newly_added_; }
432 absl::flat_hash_set<std::pair<int, int>> set_;
433 std::vector<BinaryClause> newly_added_;
484 stats_(
"BinaryImplicationGraph"),
488 at_most_one_max_expansion_size_(
489 model->GetOrCreate<SatParameters>()
490 ->at_most_one_max_expansion_size()) {
501 LOG(INFO) <<
"num_redundant_implications " << num_redundant_implications_;
507 absl::Span<const Literal>
Reason(
const Trail& trail,
int trail_index,
508 int64_t conflict_id)
const final;
511 void Resize(
int num_variables);
515 return num_implications_ == 0 && at_most_ones_.empty();
543 add_binary_callback_ = f;
557 ABSL_MUST_USE_RESULT
bool AddAtMostOne(absl::Span<const Literal> at_most_one);
570 std::vector<Literal>* c);
574 std::vector<Literal>* c,
575 absl::BitGenRef random);
596 bool IsDag()
const {
return is_dag_; }
602 return reverse_topological_order_;
608 return implications_[l];
615 if (l.
Index() >= representative_of_.size())
return l;
617 return Literal(representative_of_[l]);
643 int64_t max_num_explored_nodes = 1e8);
655 const std::vector<Literal>& literals,
656 const std::vector<double>& lp_values);
663 std::vector<Literal>* literals);
683 CHECK_EQ(num_redundant_literals_ % 2, 0);
684 return num_redundant_literals_;
689 return num_redundant_implications_;
706 template <
typename Output>
711 absl::flat_hash_set<std::pair<LiteralIndex, LiteralIndex>>
713 for (LiteralIndex
i(0);
i < implications_.size(); ++
i) {
715 for (
const Literal b : implications_[
i]) {
720 if (
a <
b && duplicate_detection.insert({a, b}).second) {
721 out->AddBinaryClause(
a,
b);
728 drat_proof_handler_ = drat_proof_handler;
736 reasons_[trail_index] = new_reason.
Negated();
759 return estimated_sizes_[
literal];
772 BooleanVariable
var, std::deque<std::vector<Literal>>* postsolve_clauses);
775 std::deque<std::vector<Literal>>* postsolve_clauses);
781 int64_t
WorkDone()
const {
return work_done_in_mark_descendants_; }
784 template <
bool use_weight = true>
786 absl::Span<const Literal> at_most_one,
802 void NotifyPossibleDuplicate(
Literal a);
806 bool FixLiteral(
Literal true_literal);
812 bool PropagateOnTrue(
Literal true_literal,
Trail* trail);
815 void RemoveRedundantLiterals(std::vector<Literal>* conflict);
819 void MarkDescendants(
Literal root);
825 std::vector<Literal> ExpandAtMostOne(absl::Span<const Literal> at_most_one,
826 int64_t max_num_explored_nodes);
835 bool CleanUpAndAddAtMostOnes(
int base_index);
838 bool InvariantsAreOk();
842 absl::Span<const Literal> AtMostOne(
int start)
const;
852 std::deque<Literal> reasons_;
866 int64_t num_implications_ = 0;
870 std::vector<Literal> to_clean_;
885 std::vector<Literal> at_most_one_buffer_;
886 const int at_most_one_max_expansion_size_;
887 int at_most_one_iterator_ = 0;
898 std::vector<std::vector<Literal>> tmp_cuts_;
901 int64_t num_propagations_ = 0;
902 int64_t num_inspections_ = 0;
903 int64_t num_minimization_ = 0;
904 int64_t num_literals_removed_ = 0;
905 int64_t num_redundant_implications_ = 0;
906 int64_t num_redundant_literals_ = 0;
916 std::vector<Literal> dfs_stack_;
920 int64_t work_done_in_mark_descendants_ = 0;
921 std::vector<Literal> bfs_stack_;
926 std::vector<std::pair<Literal, Literal>> tmp_removed_;
929 bool is_dag_ =
false;
930 std::vector<LiteralIndex> reverse_topological_order_;
935 std::vector<Literal> direct_implications_;
936 std::vector<Literal> direct_implications_of_negated_literal_;
942 int num_processed_fixed_variables_ = 0;
944 bool enable_sharing_ =
true;
945 std::function<void(
Literal,
Literal)> add_binary_callback_ =
nullptr;
948extern template std::vector<Literal>
950 const absl::Span<const Literal> at_most_one,
954extern template std::vector<Literal>
956 const absl::Span<const Literal> at_most_one,
Base class to print a nice summary of a group of statistics.
std::string StatString() const
A simple class to manage a set of binary clauses.
const std::vector< BinaryClause > & newly_added() const
Returns the newly added BinaryClause since the last ClearNewlyAdded() call.
BinaryClauseManager()=default
BinaryClauseManager(const BinaryClauseManager &)=delete
This type is neither copyable nor movable.
BinaryClauseManager & operator=(const BinaryClauseManager &)=delete
int64_t num_propagations() const
Number of literal propagated by this class (including conflicts).
void ResetAtMostOneIterator()
Restarts the at_most_one iterator.
bool ComputeTransitiveReduction(bool log_info=false)
Literal RepresentativeOf(Literal l) const
int64_t num_redundant_literals() const
void Resize(int num_variables)
Resizes the data structure.
void ExtractAllBinaryClauses(Output *out) const
BinaryImplicationGraph(const BinaryImplicationGraph &)=delete
This type is neither copyable nor movable.
int64_t num_implications() const
bool Propagate(Trail *trail) final
SatPropagator interface.
int64_t num_minimization() const
MinimizeClause() stats.
void RemoveDuplicates()
Clean up implications list that might have duplicates.
void MinimizeConflictWithReachability(std::vector< Literal > *c)
std::vector< Literal > ExpandAtMostOneWithWeight(absl::Span< const Literal > at_most_one, const util_intops::StrongVector< LiteralIndex, bool > &can_be_included, const util_intops::StrongVector< LiteralIndex, double > &expanded_lp_values)
Same as ExpandAtMostOne() but try to maximize the weight in the clique.
int64_t num_literals_removed() const
bool TransformIntoMaxCliques(std::vector< std::vector< Literal > > *at_most_ones, int64_t max_num_explored_nodes=1e8)
void CleanupAllRemovedAndFixedVariables()
int64_t NumImplicationOnVariableRemoval(BooleanVariable var)
int64_t num_redundant_implications() const
Number of implications removed by transitive reduction.
bool IsEmpty() const final
Returns true if there is no constraints in this class.
bool AddBinaryClause(Literal a, Literal b)
int DirectImplicationsEstimatedSize(Literal literal) const
void RemoveFixedVariables()
absl::Span< const Literal > NextAtMostOne()
Returns the next at_most_one, or a span of size 0 when finished.
BinaryImplicationGraph(Model *model)
bool AddImplication(Literal a, Literal b)
void RemoveBooleanVariable(BooleanVariable var, std::deque< std::vector< Literal > > *postsolve_clauses)
For all possible a => var => b, add a => b.
bool IsRedundant(Literal l) const
void MinimizeConflictExperimental(const Trail &trail, std::vector< Literal > *c)
void MinimizeConflictFirstWithTransitiveReduction(const Trail &trail, std::vector< Literal > *c, absl::BitGenRef random)
bool DetectEquivalences(bool log_info=false)
void SetDratProofHandler(DratProofHandler *drat_proof_handler)
void SetAdditionCallback(std::function< void(Literal, Literal)> f)
void MinimizeConflictFirst(const Trail &trail, std::vector< Literal > *c, SparseBitset< BooleanVariable > *marked)
const std::vector< Literal > & DirectImplications(Literal literal)
const std::vector< std::vector< Literal > > & GenerateAtMostOnesWithLargeWeight(const std::vector< Literal > &literals, const std::vector< double > &lp_values)
absl::Span< const Literal > Reason(const Trail &trail, int trail_index, int64_t conflict_id) const final
void RemoveAllRedundantVariables(std::deque< std::vector< Literal > > *postsolve_clauses)
int64_t literal_size() const
const std::vector< LiteralIndex > & ReverseTopologicalOrder() const
void ChangeReason(int trail_index, Literal new_reason)
bool FindFailedLiteralAroundVar(BooleanVariable var, bool *is_unsat)
BinaryImplicationGraph & operator=(const BinaryImplicationGraph &)=delete
LiteralIndex RandomImpliedLiteral(Literal lhs)
ABSL_MUST_USE_RESULT bool AddAtMostOne(absl::Span< const Literal > at_most_one)
bool IsRemoved(Literal l) const
std::vector< absl::Span< const Literal > > HeuristicAmoPartition(std::vector< Literal > *literals)
const absl::InlinedVector< Literal, 6 > & Implications(Literal l) const
~BinaryImplicationGraph() override
void EnableSharing(bool enable)
int64_t num_inspections() const
Number of literals inspected by this class during propagation.
SatClause * InprocessingAddClause(absl::Span< const Literal > new_clause)
void ResetToProbeIndex()
Restart the scans.
int64_t num_removable_clauses() const
void LazyDetach(SatClause *clause)
void InprocessingRemoveClause(SatClause *clause)
These must only be called between [Detach/Attach]AllClauses() calls.
SatClause * NextClauseToMinimize()
void ResetToMinimizeIndex()
int64_t num_clauses() const
bool IsRemovable(SatClause *const clause) const
void Detach(SatClause *clause)
~ClauseManager() override
void DeleteRemovedClauses()
absl::Span< const Literal > Reason(const Trail &trail, int trail_index, int64_t conflict_id) const final
int64_t num_inspected_clauses() const
Total number of clauses inspected during calls to PropagateOnFalse().
ClauseManager(const ClauseManager &)=delete
This type is neither copyable nor movable.
bool AddClause(absl::Span< const Literal > literals, Trail *trail, int lbd)
Adds a new clause and perform initial propagation for this clause only.
int64_t literal_size() const
The number of different literals (always twice the number of variables).
int64_t num_inspected_clause_literals() const
SatClause * NextClauseToProbe()
int64_t num_watched_clauses() const
Number of clauses currently watched.
void SetDratProofHandler(DratProofHandler *drat_proof_handler)
ClauseManager(Model *model)
--— ClauseManager --—
SatClause * ReasonClause(int trail_index) const
void SetAddClauseCallback(absl::AnyInvocable< void(int lbd, absl::Span< const Literal >)> add_clause_callback)
absl::flat_hash_map< SatClause *, ClauseInfo > * mutable_clauses_info()
SatClause * AddRemovableClause(absl::Span< const Literal > literals, Trail *trail, int lbd)
const std::vector< SatClause * > & AllClausesInCreationOrder() const
void Resize(int num_variables)
Must be called before adding clauses referring to such variables.
ClauseManager & operator=(const ClauseManager &)=delete
ABSL_MUST_USE_RESULT bool InprocessingFixLiteral(Literal true_literal)
This one do not need the clause to be detached.
void Attach(SatClause *clause, Trail *trail)
ABSL_MUST_USE_RESULT bool InprocessingRewriteClause(SatClause *clause, absl::Span< const Literal > new_clause)
const std::vector< Watcher > & WatcherListOnFalse(Literal false_literal) const
bool Propagate(Trail *trail) final
SatPropagator API.
LiteralIndex Index() const
const Literal * end() const
Literal FirstLiteral() const
static SatClause * Create(absl::Span< const Literal > literals)
--— SatClause --—
absl::Span< const Literal > AsSpan() const
Returns a Span<> representation of the clause.
const Literal * begin() const
Allows for range based iteration: for (Literal literal : clause) {}.
absl::Span< const Literal > PropagationReason() const
bool IsSatisfied(const VariablesAssignment &assignment) const
Literal PropagatedLiteral() const
int size() const
Number of literals in the clause.
std::string DebugString() const
bool RemoveFixedLiteralsAndTestIfTrue(const VariablesAssignment &assignment)
Literal SecondLiteral() const
Base class for all the SAT constraints.
void ChangeReason(int trail_index, int propagator_id)
void RegisterPropagator(SatPropagator *propagator)
const VariablesAssignment & Assignment() const
bool LiteralIsTrue(Literal literal) const
const LiteralIndex kNoLiteralIndex(-1)
In SWIG mode, we don't want anything besides these top-level includes.
#define IF_STATS_ENABLED(instructions)
A binary clause. This is used by BinaryClauseManager.
bool operator!=(BinaryClause o) const
BinaryClause(Literal _a, Literal _b)
bool operator==(BinaryClause o) const
bool protected_during_next_cleanup
Watcher(SatClause *c, Literal b, int i=2)