1 /*********************                                                        */
2 /*! \file minisat.cpp
3  ** \verbatim
4  ** Top contributors (to current version):
5  **   Liana Hadarean, Dejan Jovanovic, Tim King
6  ** This file is part of the CVC4 project.
7  ** Copyright (c) 2009-2019 by the authors listed in the file AUTHORS
8  ** in the top-level source directory) and their institutional affiliations.
9  ** All rights reserved.  See the file COPYING in the top-level source
10  ** directory for licensing information.\endverbatim
11  **
12  ** \brief SAT Solver.
13  **
14  ** Implementation of the minisat interface for cvc4.
15  **/
16 
17 #include "prop/minisat/minisat.h"
18 
19 #include "options/base_options.h"
20 #include "options/decision_options.h"
21 #include "options/prop_options.h"
22 #include "options/smt_options.h"
23 #include "prop/minisat/simp/SimpSolver.h"
24 #include "proof/clause_id.h"
25 #include "proof/sat_proof.h"
26 #include "util/statistics_registry.h"
27 
28 namespace CVC4 {
29 namespace prop {
30 
31 //// DPllMinisatSatSolver
32 
MinisatSatSolver(StatisticsRegistry * registry)33 MinisatSatSolver::MinisatSatSolver(StatisticsRegistry* registry) :
34   d_minisat(NULL),
35   d_context(NULL),
36   d_statistics(registry)
37 {}
38 
~MinisatSatSolver()39 MinisatSatSolver::~MinisatSatSolver()
40 {
41   delete d_minisat;
42 }
43 
toSatVariable(Minisat::Var var)44 SatVariable MinisatSatSolver::toSatVariable(Minisat::Var var) {
45   if (var == var_Undef) {
46     return undefSatVariable;
47   }
48   return SatVariable(var);
49 }
50 
toMinisatLit(SatLiteral lit)51 Minisat::Lit MinisatSatSolver::toMinisatLit(SatLiteral lit) {
52   if (lit == undefSatLiteral) {
53     return Minisat::lit_Undef;
54   }
55   return Minisat::mkLit(lit.getSatVariable(), lit.isNegated());
56 }
57 
toSatLiteral(Minisat::Lit lit)58 SatLiteral MinisatSatSolver::toSatLiteral(Minisat::Lit lit) {
59   if (lit == Minisat::lit_Undef) {
60     return undefSatLiteral;
61   }
62 
63   return SatLiteral(SatVariable(Minisat::var(lit)),
64                     Minisat::sign(lit));
65 }
66 
toSatLiteralValue(Minisat::lbool res)67 SatValue MinisatSatSolver::toSatLiteralValue(Minisat::lbool res) {
68   if(res == (Minisat::lbool((uint8_t)0))) return SAT_VALUE_TRUE;
69   if(res == (Minisat::lbool((uint8_t)2))) return SAT_VALUE_UNKNOWN;
70   Assert(res == (Minisat::lbool((uint8_t)1)));
71   return SAT_VALUE_FALSE;
72 }
73 
toMinisatlbool(SatValue val)74 Minisat::lbool MinisatSatSolver::toMinisatlbool(SatValue val)
75 {
76   if(val == SAT_VALUE_TRUE) return Minisat::lbool((uint8_t)0);
77   if(val == SAT_VALUE_UNKNOWN) return Minisat::lbool((uint8_t)2);
78   Assert(val == SAT_VALUE_FALSE);
79   return Minisat::lbool((uint8_t)1);
80 }
81 
82 /*bool MinisatSatSolver::tobool(SatValue val)
83 {
84   if(val == SAT_VALUE_TRUE) return true;
85   Assert(val == SAT_VALUE_FALSE);
86   return false;
87   }*/
88 
toMinisatClause(SatClause & clause,Minisat::vec<Minisat::Lit> & minisat_clause)89 void MinisatSatSolver::toMinisatClause(SatClause& clause,
90                                            Minisat::vec<Minisat::Lit>& minisat_clause) {
91   for (unsigned i = 0; i < clause.size(); ++i) {
92     minisat_clause.push(toMinisatLit(clause[i]));
93   }
94   Assert(clause.size() == (unsigned)minisat_clause.size());
95 }
96 
toSatClause(const Minisat::Clause & clause,SatClause & sat_clause)97 void MinisatSatSolver::toSatClause(const Minisat::Clause& clause,
98                                        SatClause& sat_clause) {
99   for (int i = 0; i < clause.size(); ++i) {
100     sat_clause.push_back(toSatLiteral(clause[i]));
101   }
102   Assert((unsigned)clause.size() == sat_clause.size());
103 }
104 
initialize(context::Context * context,TheoryProxy * theoryProxy)105 void MinisatSatSolver::initialize(context::Context* context, TheoryProxy* theoryProxy) {
106 
107   d_context = context;
108 
109   if( options::decisionMode() != decision::DECISION_STRATEGY_INTERNAL ) {
110     Notice() << "minisat: Incremental solving is forced on (to avoid variable elimination)"
111              << " unless using internal decision strategy." << std::endl;
112   }
113 
114   // Create the solver
115   d_minisat = new Minisat::SimpSolver(theoryProxy, d_context,
116                                       options::incrementalSolving() ||
117                                       options::decisionMode() != decision::DECISION_STRATEGY_INTERNAL );
118 
119   d_statistics.init(d_minisat);
120 }
121 
122 // Like initialize() above, but called just before each search when in
123 // incremental mode
setupOptions()124 void MinisatSatSolver::setupOptions() {
125   // Copy options from CVC4 options structure into minisat, as appropriate
126 
127   // Set up the verbosity
128   d_minisat->verbosity = (options::verbosity() > 0) ? 1 : -1;
129 
130   // Set up the random decision parameters
131   d_minisat->random_var_freq = options::satRandomFreq();
132   // If 0, we use whatever we like (here, the Minisat default seed)
133   if(options::satRandomSeed() != 0) {
134     d_minisat->random_seed = double(options::satRandomSeed());
135   }
136 
137   // Give access to all possible options in the sat solver
138   d_minisat->var_decay = options::satVarDecay();
139   d_minisat->clause_decay = options::satClauseDecay();
140   d_minisat->restart_first = options::satRestartFirst();
141   d_minisat->restart_inc = options::satRestartInc();
142 }
143 
addClause(SatClause & clause,bool removable)144 ClauseId MinisatSatSolver::addClause(SatClause& clause, bool removable) {
145   Minisat::vec<Minisat::Lit> minisat_clause;
146   toMinisatClause(clause, minisat_clause);
147   ClauseId clause_id = ClauseIdError;
148   // FIXME: This relies on the invariant that when ok() is false
149   // the SAT solver does not add the clause (which is what Minisat currently does)
150   if (!ok()) {
151     return ClauseIdUndef;
152   }
153   d_minisat->addClause(minisat_clause, removable, clause_id);
154   PROOF( Assert (clause_id != ClauseIdError););
155   return clause_id;
156 }
157 
newVar(bool isTheoryAtom,bool preRegister,bool canErase)158 SatVariable MinisatSatSolver::newVar(bool isTheoryAtom, bool preRegister, bool canErase) {
159   return d_minisat->newVar(true, true, isTheoryAtom, preRegister, canErase);
160 }
161 
solve(unsigned long & resource)162 SatValue MinisatSatSolver::solve(unsigned long& resource) {
163   Trace("limit") << "SatSolver::solve(): have limit of " << resource << " conflicts" << std::endl;
164   setupOptions();
165   if(resource == 0) {
166     d_minisat->budgetOff();
167   } else {
168     d_minisat->setConfBudget(resource);
169   }
170   Minisat::vec<Minisat::Lit> empty;
171   unsigned long conflictsBefore = d_minisat->conflicts + d_minisat->resources_consumed;
172   SatValue result = toSatLiteralValue(d_minisat->solveLimited(empty));
173   d_minisat->clearInterrupt();
174   resource = d_minisat->conflicts + d_minisat->resources_consumed - conflictsBefore;
175   Trace("limit") << "SatSolver::solve(): it took " << resource << " conflicts" << std::endl;
176   return result;
177 }
178 
solve()179 SatValue MinisatSatSolver::solve() {
180   setupOptions();
181   d_minisat->budgetOff();
182   return toSatLiteralValue(d_minisat->solve());
183 }
184 
ok() const185 bool MinisatSatSolver::ok() const {
186   return d_minisat->okay();
187 }
188 
interrupt()189 void MinisatSatSolver::interrupt() {
190   d_minisat->interrupt();
191 }
192 
value(SatLiteral l)193 SatValue MinisatSatSolver::value(SatLiteral l) {
194   return toSatLiteralValue(d_minisat->value(toMinisatLit(l)));
195 }
196 
modelValue(SatLiteral l)197 SatValue MinisatSatSolver::modelValue(SatLiteral l){
198   return toSatLiteralValue(d_minisat->modelValue(toMinisatLit(l)));
199 }
200 
properExplanation(SatLiteral lit,SatLiteral expl) const201 bool MinisatSatSolver::properExplanation(SatLiteral lit, SatLiteral expl) const {
202   return true;
203 }
204 
requirePhase(SatLiteral lit)205 void MinisatSatSolver::requirePhase(SatLiteral lit) {
206   Assert(!d_minisat->rnd_pol);
207   Debug("minisat") << "requirePhase(" << lit << ")" << " " <<  lit.getSatVariable() << " " << lit.isNegated() << std::endl;
208   SatVariable v = lit.getSatVariable();
209   d_minisat->freezePolarity(v, lit.isNegated());
210 }
211 
isDecision(SatVariable decn) const212 bool MinisatSatSolver::isDecision(SatVariable decn) const {
213   return d_minisat->isDecision( decn );
214 }
215 
216 /** Incremental interface */
217 
getAssertionLevel() const218 unsigned MinisatSatSolver::getAssertionLevel() const {
219   return d_minisat->getAssertionLevel();
220 }
221 
push()222 void MinisatSatSolver::push() {
223   d_minisat->push();
224 }
225 
pop()226 void MinisatSatSolver::pop() {
227   d_minisat->pop();
228 }
229 
resetTrail()230 void MinisatSatSolver::resetTrail() { d_minisat->resetTrail(); }
231 
232 /// Statistics for MinisatSatSolver
233 
Statistics(StatisticsRegistry * registry)234 MinisatSatSolver::Statistics::Statistics(StatisticsRegistry* registry) :
235     d_registry(registry),
236     d_statStarts("sat::starts"),
237     d_statDecisions("sat::decisions"),
238     d_statRndDecisions("sat::rnd_decisions"),
239     d_statPropagations("sat::propagations"),
240     d_statConflicts("sat::conflicts"),
241     d_statClausesLiterals("sat::clauses_literals"),
242     d_statLearntsLiterals("sat::learnts_literals"),
243     d_statMaxLiterals("sat::max_literals"),
244     d_statTotLiterals("sat::tot_literals")
245 {
246   d_registry->registerStat(&d_statStarts);
247   d_registry->registerStat(&d_statDecisions);
248   d_registry->registerStat(&d_statRndDecisions);
249   d_registry->registerStat(&d_statPropagations);
250   d_registry->registerStat(&d_statConflicts);
251   d_registry->registerStat(&d_statClausesLiterals);
252   d_registry->registerStat(&d_statLearntsLiterals);
253   d_registry->registerStat(&d_statMaxLiterals);
254   d_registry->registerStat(&d_statTotLiterals);
255 }
256 
~Statistics()257 MinisatSatSolver::Statistics::~Statistics() {
258   d_registry->unregisterStat(&d_statStarts);
259   d_registry->unregisterStat(&d_statDecisions);
260   d_registry->unregisterStat(&d_statRndDecisions);
261   d_registry->unregisterStat(&d_statPropagations);
262   d_registry->unregisterStat(&d_statConflicts);
263   d_registry->unregisterStat(&d_statClausesLiterals);
264   d_registry->unregisterStat(&d_statLearntsLiterals);
265   d_registry->unregisterStat(&d_statMaxLiterals);
266   d_registry->unregisterStat(&d_statTotLiterals);
267 }
268 
init(Minisat::SimpSolver * d_minisat)269 void MinisatSatSolver::Statistics::init(Minisat::SimpSolver* d_minisat){
270   d_statStarts.setData(d_minisat->starts);
271   d_statDecisions.setData(d_minisat->decisions);
272   d_statRndDecisions.setData(d_minisat->rnd_decisions);
273   d_statPropagations.setData(d_minisat->propagations);
274   d_statConflicts.setData(d_minisat->conflicts);
275   d_statClausesLiterals.setData(d_minisat->clauses_literals);
276   d_statLearntsLiterals.setData(d_minisat->learnts_literals);
277   d_statMaxLiterals.setData(d_minisat->max_literals);
278   d_statTotLiterals.setData(d_minisat->tot_literals);
279 }
280 
281 } /* namespace CVC4::prop */
282 } /* namespace CVC4 */
283 
284 
285 namespace CVC4 {
286 template<>
toSatLiteral(Minisat::Solver::TLit lit)287 prop::SatLiteral toSatLiteral< CVC4::Minisat::Solver>(Minisat::Solver::TLit lit) {
288   return prop::MinisatSatSolver::toSatLiteral(lit);
289 }
290 
291 template<>
toSatClause(const CVC4::Minisat::Solver::TClause & minisat_cl,prop::SatClause & sat_cl)292 void toSatClause< CVC4::Minisat::Solver> (const CVC4::Minisat::Solver::TClause& minisat_cl,
293                                       prop::SatClause& sat_cl) {
294   prop::MinisatSatSolver::toSatClause(minisat_cl, sat_cl);
295 }
296 
297 } /* namespace CVC4 */
298