CBMC
satcheck_minisat2.cpp
Go to the documentation of this file.
1 /*******************************************************************\
2 
3 Module:
4 
5 Author: Daniel Kroening, kroening@kroening.com
6 
7 \*******************************************************************/
8 
9 #include "satcheck_minisat2.h"
10 
11 #ifndef _WIN32
12 # include <signal.h>
13 # include <unistd.h>
14 #endif
15 
16 #include <limits>
17 
18 #include <util/invariant.h>
19 #include <util/threeval.h>
20 
21 #include <minisat/core/Solver.h>
22 #include <minisat/simp/SimpSolver.h>
23 
24 #ifndef l_False
25 # define l_False Minisat::l_False
26 # define l_True Minisat::l_True
27 #endif
28 
29 #ifndef HAVE_MINISAT2
30 #error "Expected HAVE_MINISAT2"
31 #endif
32 
33 void convert(const bvt &bv, Minisat::vec<Minisat::Lit> &dest)
34 {
36  bv.size() <= static_cast<std::size_t>(std::numeric_limits<int>::max()));
37  dest.capacity(static_cast<int>(bv.size()));
38 
39  for(const auto &literal : bv)
40  {
41  if(!literal.is_false())
42  dest.push(Minisat::mkLit(literal.var_no(), literal.sign()));
43  }
44 }
45 
46 void convert_assumptions(const bvt &bv, Minisat::vec<Minisat::Lit> &dest)
47 {
49  bv.size() <= static_cast<std::size_t>(std::numeric_limits<int>::max()));
50  dest.capacity(static_cast<int>(bv.size()));
51 
52  for(const auto &literal : bv)
53  {
54  // when converting assumptions, ignore 'true'
55  if(!literal.is_true())
56  dest.push(Minisat::mkLit(literal.var_no(), literal.sign()));
57  }
58 }
59 
60 template<typename T>
62 {
63  if(a.is_true())
64  return tvt(true);
65  else if(a.is_false())
66  return tvt(false);
67 
68  tvt result;
69 
70  if(a.var_no()>=(unsigned)solver->model.size())
71  return tvt::unknown();
72 
73  using Minisat::lbool;
74 
75  if(solver->model[a.var_no()]==l_True)
76  result=tvt(true);
77  else if(solver->model[a.var_no()]==l_False)
78  result=tvt(false);
79  else
80  return tvt::unknown();
81 
82  if(a.sign())
83  result=!result;
84 
85  return result;
86 }
87 
88 template<typename T>
90 {
92 
93  using Minisat::lbool;
94 
95  try
96  {
97  add_variables();
98  solver->setPolarity(a.var_no(), value ? l_True : l_False);
99  }
100  catch(Minisat::OutOfMemoryException)
101  {
102  log.error() << "SAT checker ran out of memory" << messaget::eom;
103  status = statust::ERROR;
104  throw std::bad_alloc();
105  }
106 }
107 
108 template<typename T>
110 {
111  solver->interrupt();
112 }
113 
114 template<typename T>
116 {
117  solver->clearInterrupt();
118 }
119 
121 {
122  return "MiniSAT 2.2.1 without simplifier";
123 }
124 
126 {
127  return "MiniSAT 2.2.1 with simplifier";
128 }
129 
130 template<typename T>
132 {
133  while((unsigned)solver->nVars()<no_variables())
134  solver->newVar();
135 }
136 
137 template<typename T>
139 {
140  try
141  {
142  add_variables();
143 
144  for(const auto &literal : bv)
145  {
146  if(literal.is_true())
147  return;
148  else if(!literal.is_false())
149  {
150  INVARIANT(
151  literal.var_no() < (unsigned)solver->nVars(),
152  "variable not added yet");
153  }
154  }
155 
156  Minisat::vec<Minisat::Lit> c;
157 
158  convert(bv, c);
159 
160  // Note the underscore.
161  // Add a clause to the solver without making superflous internal copy.
162 
163  solver->addClause_(c);
164 
165  if(solver_hardness)
166  {
167  // To map clauses to lines of program code, track clause indices in the
168  // dimacs cnf output. Dimacs output is generated after processing
169  // clauses to remove duplicates and clauses that are trivially true.
170  // Here, a clause is checked to see if it can be thus eliminated. If
171  // not, add the clause index to list of clauses in
172  // solver_hardnesst::register_clause().
173  static size_t cnf_clause_index = 0;
174  bvt cnf;
175  bool clause_removed = process_clause(bv, cnf);
176 
177  if(!clause_removed)
178  cnf_clause_index++;
179 
180  solver_hardness->register_clause(
181  bv, cnf, cnf_clause_index, !clause_removed);
182  }
183 
184  clause_counter++;
185  }
186  catch(const Minisat::OutOfMemoryException &)
187  {
188  log.error() << "SAT checker ran out of memory" << messaget::eom;
189  status = statust::ERROR;
190  throw std::bad_alloc();
191  }
192 }
193 
194 #ifndef _WIN32
195 
196 static Minisat::Solver *solver_to_interrupt=nullptr;
197 
198 static void interrupt_solver(int signum)
199 {
200  (void)signum; // unused parameter -- just removing the name trips up cpplint
201  solver_to_interrupt->interrupt();
202 }
203 
204 #endif
205 
206 template <typename T>
208 {
209  PRECONDITION(status != statust::ERROR);
210 
211  log.statistics() << (no_variables() - 1) << " variables, "
212  << solver->nClauses() << " clauses" << messaget::eom;
213 
214  try
215  {
216  add_variables();
217 
218  if(!solver->okay())
219  {
220  log.status() << "SAT checker inconsistent: instance is UNSATISFIABLE"
221  << messaget::eom;
222  status = statust::UNSAT;
223  return resultt::P_UNSATISFIABLE;
224  }
225 
226  // if assumptions contains false, we need this to be UNSAT
227  for(const auto &assumption : assumptions)
228  {
229  if(assumption.is_false())
230  {
231  log.status() << "got FALSE as assumption: instance is UNSATISFIABLE"
232  << messaget::eom;
233  status = statust::UNSAT;
234  return resultt::P_UNSATISFIABLE;
235  }
236  }
237 
238  Minisat::vec<Minisat::Lit> solver_assumptions;
239  convert_assumptions(assumptions, solver_assumptions);
240 
241  using Minisat::lbool;
242 
243 #ifndef _WIN32
244 
245  void (*old_handler)(int) = SIG_ERR;
246 
247  if(time_limit_seconds != 0)
248  {
249  solver_to_interrupt = solver.get();
250  old_handler = signal(SIGALRM, interrupt_solver);
251  if(old_handler == SIG_ERR)
252  log.warning() << "Failed to set solver time limit" << messaget::eom;
253  else
254  alarm(time_limit_seconds);
255  }
256 
257  lbool solver_result = solver->solveLimited(solver_assumptions);
258 
259  if(old_handler != SIG_ERR)
260  {
261  alarm(0);
262  signal(SIGALRM, old_handler);
263  solver_to_interrupt = solver.get();
264  }
265 
266 #else // _WIN32
267 
268  if(time_limit_seconds != 0)
269  {
270  log.warning() << "Time limit ignored (not supported on Win32 yet)"
271  << messaget::eom;
272  }
273 
274  lbool solver_result = solver->solve(solver_assumptions) ? l_True : l_False;
275 
276 #endif
277 
278  if(solver_result == l_True)
279  {
280  log.status() << "SAT checker: instance is SATISFIABLE" << messaget::eom;
281  CHECK_RETURN(solver->model.size() > 0);
282  status = statust::SAT;
283  return resultt::P_SATISFIABLE;
284  }
285 
286  if(solver_result == l_False)
287  {
288  log.status() << "SAT checker: instance is UNSATISFIABLE" << messaget::eom;
289  status = statust::UNSAT;
290  return resultt::P_UNSATISFIABLE;
291  }
292 
293  log.status() << "SAT checker: timed out or other error" << messaget::eom;
294  status = statust::ERROR;
295  return resultt::P_ERROR;
296  }
297  catch(const Minisat::OutOfMemoryException &)
298  {
299  log.error() << "SAT checker ran out of memory" << messaget::eom;
300  status=statust::ERROR;
301  return resultt::P_ERROR;
302  }
303 }
304 
305 template<typename T>
307 {
309 
310  try
311  {
312  unsigned v = a.var_no();
313  bool sign = a.sign();
314 
315  // MiniSat2 kills the model in case of UNSAT
316  solver->model.growTo(v + 1);
317  value ^= sign;
318  solver->model[v] = Minisat::lbool(value);
319  }
320  catch(const Minisat::OutOfMemoryException &)
321  {
322  log.error() << "SAT checker ran out of memory" << messaget::eom;
323  status = statust::ERROR;
324  throw std::bad_alloc();
325  }
326 }
327 
328 template <typename T>
330  message_handlert &message_handler)
331  : cnf_solvert(message_handler),
332  solver(std::make_unique<T>()),
333  time_limit_seconds(0)
334 {
335 }
336 
337 template <typename T>
339 
340 template<typename T>
342 {
343  int v=a.var_no();
344 
345  for(int i=0; i<solver->conflict.size(); i++)
346  if(var(solver->conflict[i])==v)
347  return true;
348 
349  return false;
350 }
351 
354 
356 {
357  try
358  {
359  if(!a.is_constant())
360  {
361  add_variables();
362  solver->setFrozen(a.var_no(), true);
363  }
364  }
365  catch(const Minisat::OutOfMemoryException &)
366  {
367  log.error() << "SAT checker ran out of memory" << messaget::eom;
369  throw std::bad_alloc();
370  }
371 }
372 
374 {
376 
377  return solver->isEliminated(a.var_no());
378 }
statust status
Definition: cnf.h:87
bool is_true() const
Definition: literal.h:156
bool sign() const
Definition: literal.h:88
bool is_constant() const
Definition: literal.h:166
var_not var_no() const
Definition: literal.h:83
bool is_false() const
Definition: literal.h:161
mstreamt & error() const
Definition: message.h:399
static eomt eom
Definition: message.h:297
resultt
Definition: prop.h:101
messaget log
Definition: prop.h:134
bool is_in_conflict(literalt a) const override
Returns true if an assumption is in the final conflict.
std::unique_ptr< Minisat::SimpSolver > solver
~satcheck_minisat2_baset() override
A default destructor defined in the .cpp is used to ensure the unique_ptr to the solver is correctly ...
resultt do_prop_solve(const bvt &) override
satcheck_minisat2_baset(message_handlert &message_handler)
void set_polarity(literalt a, bool value)
void lcnf(const bvt &bv) override final
tvt l_get(literalt a) const override final
void set_assignment(literalt a, bool value) override
std::string solver_text() const override
void set_frozen(literalt a) override final
bool is_eliminated(literalt a) const
std::string solver_text() const override final
Definition: threeval.h:20
static tvt unknown()
Definition: threeval.h:33
std::vector< literalt > bvt
Definition: literal.h:201
double log(double x)
Definition: math.c:2776
static Minisat::Solver * solver_to_interrupt
static void interrupt_solver(int signum)
void convert_assumptions(const bvt &bv, Minisat::vec< Minisat::Lit > &dest)
void convert(const bvt &bv, Minisat::vec< Minisat::Lit > &dest)
#define l_True
#define l_False
void solver(std::vector< framet > &frames, const std::unordered_set< symbol_exprt, irep_hash > &address_taken, const solver_optionst &solver_options, const namespacet &ns, std::vector< propertyt > &properties, std::size_t property_index)
Definition: solver.cpp:44
#define CHECK_RETURN(CONDITION)
Definition: invariant.h:495
#define PRECONDITION(CONDITION)
Definition: invariant.h:463
#define INVARIANT(CONDITION, REASON)
This macro uses the wrapper function 'invariant_violated_string'.
Definition: invariant.h:423