dlinear  0.0.1
Delta-complete SMT solver for linear programming
Loading...
Searching...
No Matches
PicosatSatSolver.cpp
1
6// IWYU pragma: no_include "picosat/picosat.h" // Already included in the header
7#include "PicosatSatSolver.h"
8
9#include <unordered_map>
10#include <vector>
11
12#include "dlinear/util/Config.h"
13#include "dlinear/util/ScopedUnorderedMap.hpp"
14#include "dlinear/util/Stats.h"
15#include "dlinear/util/Timer.h"
16#include "dlinear/util/exception.h"
17#include "dlinear/util/logging.h"
18
19namespace dlinear {
20
21PicosatSatSolver::PicosatSatSolver(PredicateAbstractor &predicate_abstractor, const std::string &class_name)
22 : SatSolver{predicate_abstractor, class_name}, sat_(picosat_init()), has_picosat_pop_used_{false} {
23 picosat_save_original_clauses(sat_);
24 if (config_.random_seed() != 0) {
25 picosat_set_seed(sat_, config_.random_seed());
26 DLINEAR_DEBUG_FMT("PicosatSatSolver::Set Random Seed {}", config_.random_seed());
27 }
28 picosat_set_global_default_phase(sat_, static_cast<int>(config_.sat_default_phase()));
29 DLINEAR_DEBUG_FMT("PicosatSatSolver::Set Default Phase {}", config_.sat_default_phase());
30}
31PicosatSatSolver::~PicosatSatSolver() { picosat_reset(sat_); }
32
33void PicosatSatSolver::MakeSatVar(const Variable &var) {
34 auto it = var_to_sat_.find(var.get_id());
35 // Found, no need to create the mapping
36 if (it != var_to_sat_.end()) return;
37
38 // It's not in the maps, let's make one and add it.
39 const int sat_var{picosat_inc_max_var(sat_)};
40 var_to_sat_.insert(var.get_id(), sat_var);
41 sat_to_var_.insert(sat_var, var);
42 DLINEAR_DEBUG_FMT("PicosatSatSolver::MakeSatVar({} ↦ {})", var, sat_var);
43}
44
45void PicosatSatSolver::AddLearnedClause(const LiteralSet &literals) {
46 for (const Literal &lit : literals) AddLiteral(!lit, true);
47 picosat_add(sat_, 0);
48}
49void PicosatSatSolver::AddLearnedClause(const Literal &lit) {
50 AddLiteral(!lit, true);
51 picosat_add(sat_, 0);
52}
53
54void PicosatSatSolver::AddLiteral(const Literal &l, bool learned) {
55 const auto &[var, truth] = l;
56 DLINEAR_ASSERT(var.get_type() == Variable::Type::BOOLEAN, "var must be Boolean");
57 // f = b or f = ¬b.
58 const int lit = truth ? var_to_sat_[var.get_id()] : -var_to_sat_[var.get_id()];
59 picosat_add(sat_, lit);
60 // If the literal is from the original formula, update the mapping lookup.
61 if (!learned) UpdateLookup(lit);
62}
63
64std::set<int> PicosatSatSolver::GetMainActiveLiterals() {
65 std::set<int> lits;
66 for (int i = 1; i <= picosat_variables(sat_); ++i) {
67 const int lit = i * (has_picosat_pop_used_ ? picosat_deref(sat_, i) : picosat_deref_partial(sat_, i));
68 if (lit == 0) continue;
69 lits.insert(lit);
70 }
71 // Use the superclass method to filter out literals that are not required by main clauses.
72 SatSolver::GetMainActiveLiterals(lits);
73 return lits;
74}
75
76std::optional<Model> PicosatSatSolver::CheckSat() {
77 TimerGuard timer_guard(&stats_.m_timer(), stats_.enabled());
78 stats_.Increase();
79
80 DLINEAR_DEBUG_FMT("PicosatSatSolver::CheckSat(#vars = {}, #clauses = {})", picosat_variables(sat_),
81 picosat_added_original_clauses(sat_));
82
83 // Call SAT solver.
84 const int ret{picosat_sat(sat_, -1)};
85
86 if (ret == PICOSAT_SATISFIABLE) {
87 return OnSatResult();
88 } else if (ret == PICOSAT_UNSATISFIABLE) {
89 DLINEAR_DEBUG("PicosatSatSolver::CheckSat() No solution.");
90 return {};
91 } else {
92 DLINEAR_ASSERT(ret == PICOSAT_UNKNOWN, "ret must be PICOSAT_UNKNOWN");
93 DLINEAR_RUNTIME_ERROR("PICOSAT returns PICOSAT_UNKNOWN.");
94 }
95}
96
97void PicosatSatSolver::AddClauseToSat(const Formula &f) {
98 cur_clause_start_ = main_clauses_copy_.size();
99 if (is_disjunction(f)) {
100 // f = l₁ ∨ ... ∨ lₙ
101 for (const Formula &l : get_operands(f)) SatSolver::AddLiteral(l);
102 } else {
103 // f = b or f = ¬b.
104 SatSolver::AddLiteral(f);
105 }
106 picosat_add(sat_, 0);
107 main_clauses_copy_.push_back(0);
108}
109
110void PicosatSatSolver::FixedTheoryLiterals(LiteralSet &fixed_literals) {
111 std::vector<int> clause;
112 clause.reserve(main_clauses_copy_.size());
113 for (const int sat_lit : main_clauses_copy_) {
114 if (sat_lit == 0) {
115 if (clause.size() == 1) {
116 DLINEAR_ASSERT(clause[0] != 0, "Clause must be either true or false");
117 const Variable &var = sat_to_var_[abs(clause[0])];
118 if (predicate_abstractor_.var_to_formula_map().contains(var)) fixed_literals.emplace(var, clause[0] > 0);
119 }
120 clause.clear();
121 continue;
122 }
123 clause.push_back(sat_lit);
124 }
125 DLINEAR_TRACE_FMT("PicosatSatSolver::FixedTheoryLiterals() fixed_literals = {}", fixed_literals);
126}
127
128void PicosatSatSolver::Assume(const Literal &lit) {
129 DLINEAR_TRACE_FMT("PicosatSatSolver::Assume({})", lit);
130 picosat_assume(sat_, lit.truth ? var_to_sat_[lit.var.get_id()] : -var_to_sat_[lit.var.get_id()]);
131}
132
133void PicosatSatSolver::Push() {
134 DLINEAR_DEBUG("PicosatSatSolver::Push()");
135 picosat_push(sat_);
136 var_to_sat_.push();
137 sat_to_var_.push();
138 cnf_variables_.push();
139 DLINEAR_RUNTIME_ERROR("picosat_push is bugged.");
140}
141void PicosatSatSolver::Pop() {
142 DLINEAR_DEBUG("PicosatSatSolver::Pop()");
143 cnf_variables_.pop();
144 var_to_sat_.pop();
145 sat_to_var_.pop();
146 picosat_pop(sat_);
147 has_picosat_pop_used_ = true;
148 DLINEAR_RUNTIME_ERROR("picosat_pop is bugged.");
149}
150
151} // namespace dlinear
The TimeGuard wraps a timer object and pauses it when the guard object is destructed.
Definition Timer.h:129
Represents a symbolic form of a first-order logic formula.
Represents a symbolic variable.
Global namespace for the dlinear library.
std::set< Literal > LiteralSet
A set of literals.
Definition literal.h:28
A literal is a variable with an associated truth value, indicating whether it is true or false.
Definition literal.h:24
bool truth
Truth value.
Definition literal.h:26
Variable var
Variable.
Definition literal.h:25