CBMC
qbf_bdd_core.cpp
Go to the documentation of this file.
1 /*******************************************************************\
2 
3 Module:
4 
5 Author: CM Wintersteiger
6 
7 \*******************************************************************/
8 
9 #include <solvers/prop/literal.h>
10 
11 #include <fstream>
12 
13 #include <util/arith_tools.h>
14 #include <util/invariant.h>
15 #include <util/std_expr.h>
16 
17 #include <cuddObj.hh> // CUDD Library
18 
20 // FIX FOR THE CUDD LIBRARY
21 
22 inline DdNode *DD::getNode() const
23 {
24  return node;
25 } // DD::getNode
29 #include "qbf_bdd_core.h"
30 
32 {
33  bdd_manager=new Cudd(0, 0);
34 }
35 
37 {
38  for(const BDD* model : model_bdds)
39  {
40  if(model)
41  delete model;
42  }
43  model_bdds.clear();
44 
45  delete(bdd_manager);
46  bdd_manager=NULL;
47 }
48 
50 {
52 
53  if(!is_quantified(l))
54  add_quantifier(quantifiert::EXISTENTIAL, l);
55 
56  return l;
57 }
58 
60 {
61  matrix=new BDD();
62  *matrix=bdd_manager->bddOne();
63 }
64 
66 {
67  for(const BDD* variable : bdd_variable_map)
68  {
69  if(variable)
70  delete variable;
71  }
72  bdd_variable_map.clear();
73 
74  if(matrix)
75  {
76  delete(matrix);
77  matrix=NULL;
78  }
79 }
80 
82 {
84 }
85 
86 std::string qbf_bdd_coret::solver_text() const
87 {
88  return "QBF/BDD/CORE";
89 }
90 
92 {
93  {
94  status() << solver_text() << ": "
95  << std::to_string(no_variables()) << " variables, "
96  << std::to_string(matrix->nodeCount()) << " nodes" << eom;
97  }
98 
99  model_bdds.resize(no_variables()+1, NULL);
100 
101  // Eliminate variables
102  for(auto it=quantifiers.rbegin();
103  it!=quantifiers.rend();
104  it++)
105  {
106  unsigned var=it->var_no;
107 
108  if(it->type==quantifiert::EXISTENTIAL)
109  {
110  #if 0
111  std::cout << "BDD E: " << var << ", " <<
112  matrix->nodeCount() << " nodes\n";
113  #endif
114 
115  BDD *model=new BDD();
116  const BDD &varbdd=*bdd_variable_map[var];
117  *model=matrix->AndAbstract(
118  varbdd.Xnor(bdd_manager->bddOne()),
119  varbdd);
120  model_bdds[var]=model;
121 
122  *matrix=matrix->ExistAbstract(*bdd_variable_map[var]);
123  }
124  else
125  {
126  INVARIANT(
127  it->type == quantifiert::UNIVERSAL,
128  "only handles quantified variables");
129  #if 0
130  std::cout << "BDD A: " << var << ", " <<
131  matrix->nodeCount() << " nodes\n";
132  #endif
133 
134  *matrix=matrix->UnivAbstract(*bdd_variable_map[var]);
135  }
136  }
137 
138  if(*matrix==bdd_manager->bddOne())
139  {
141  return P_SATISFIABLE;
142  }
143  else if(*matrix==bdd_manager->bddZero())
144  {
145  model_bdds.clear();
146  return P_UNSATISFIABLE;
147  }
148  else
149  return P_ERROR;
150 }
151 
153 {
155 }
156 
158 {
160 }
161 
163 {
165 
166  bdd_variable_map.resize(res.var_no()+1, NULL);
167  BDD &var=*(new BDD());
168  var=bdd_manager->bddVar();
169  bdd_variable_map[res.var_no()]=&var;
170 
171  return res;
172 }
173 
174 void qbf_bdd_coret::lcnf(const bvt &bv)
175 {
176  bvt new_bv;
177 
178  if(process_clause(bv, new_bv))
179  return;
180 
181  BDD clause(bdd_manager->bddZero());
182 
183  for(const literalt &l : new_bv)
184  {
185  BDD v(*bdd_variable_map[l.var_no()]);
186 
187  if(l.sign())
188  v=~v;
189 
190  clause|=v;
191  }
192 
193  *matrix&=clause;
194 }
195 
197 {
198  literalt nl=new_variable();
199 
200  BDD abdd(*bdd_variable_map[a.var_no()]);
201  BDD bbdd(*bdd_variable_map[b.var_no()]);
202 
203  if(a.sign())
204  abdd=~abdd;
205  if(b.sign())
206  bbdd=~bbdd;
207 
208  *bdd_variable_map[nl.var_no()]|=abdd | bbdd;
209 
210  return nl;
211 }
212 
214 {
215  for(const literalt &literal : bv)
216  {
217  if(literal==const_literal(true))
218  return literal;
219  }
220 
221  literalt nl=new_variable();
222 
223  BDD &orbdd=*bdd_variable_map[nl.var_no()];
224 
225  for(const literalt &literal : bv)
226  {
227  if(literal==const_literal(false))
228  continue;
229 
230  BDD v(*bdd_variable_map[literal.var_no()]);
231  if(literal.sign())
232  v=~v;
233 
234  orbdd|=v;
235  }
236 
237  return nl;
238 }
239 
241 {
242  status() << "Compressing Certificate" << eom;
243 
244  for(const quantifiert &quantifier : quantifiers)
245  {
246  if(quantifier.type==quantifiert::EXISTENTIAL)
247  {
248  const BDD &var=*bdd_variable_map[quantifier.var_no];
249  const BDD &model=*model_bdds[quantifier.var_no];
250 
251  if(model==bdd_manager->bddOne() ||
252  model==bdd_manager->bddZero())
253  {
254  for(const quantifiert &quantifier2 : quantifiers)
255  {
256  BDD &model2=*model_bdds[quantifier2.var_no];
257 
258  if(model==bdd_manager->bddZero())
259  model2=model2.AndAbstract(~var, var);
260  else
261  model2=model2.AndAbstract(var, var);
262  }
263  }
264  }
265  }
266 }
267 
269 {
270  quantifiert q;
272  !find_quantifier(l, q), "no model for unquantified variables");
273 
274  // universal?
275  if(q.type==quantifiert::UNIVERSAL)
276  {
277  INVARIANT(l.var_no() != 0, "input literal wasn't properly initialized");
278  variable_mapt::const_iterator it=variable_map.find(l.var_no());
279 
280  INVARIANT(
281  it != variable_map.end(), "variable not found in the variable map");
282 
283  const exprt &sym=it->second.first;
284  unsigned index=it->second.second;
285 
286  extractbit_exprt extract_expr(sym, from_integer(index, integer_typet()));
287 
288  if(l.sign())
289  extract_expr.negate();
290 
291  return extract_expr;
292  }
293  else
294  {
295  // skolem functions for existentials
296  INVARIANT(
297  q.type == quantifiert::EXISTENTIAL,
298  "only quantified literals are supported");
299 
300  function_cachet::const_iterator it=function_cache.find(l.var_no());
301  if(it!=function_cache.end())
302  {
303  #if 0
304  std::cout << "CACHE HIT for " << l.dimacs() << '\n';
305  #endif
306 
307  if(l.sign())
308  return not_exprt(it->second);
309  else
310  return it->second;
311  }
312 
313  // no cached function, so construct one
314 
315  INVARIANT(
316  model_bdds[l.var_no()] != nullptr,
317  "there must be a model BDD for the literal");
318  BDD &model=*model_bdds[l.var_no()];
319 
320  #if 0
321  std::cout << "Model " << l.var_no() << '\n';
322  model.PrintMinterm();
323  #endif
324 
325  int *cube;
326  DdGen *generator;
327 
328  or_exprt result;
329 
330  Cudd_ForeachPrime(
331  bdd_manager->getManager(),
332  model.getNode(),
333  model.getNode(),
334  generator,
335  cube)
336  {
337  and_exprt prime;
338 
339  #if 0
340  std::cout << "CUBE: ";
341  for(signed i=0; i<bdd_manager->ReadSize(); i++)
342  std::cout << cube[i];
343  std::cout << '\n';
344  #endif
345 
346  for(signed i=0; i<bdd_manager->ReadSize(); i++)
347  {
348  if(quantifiers[i].var_no==l.var_no())
349  break; // is this sound?
350 
351  if(cube[i]!=2)
352  {
353  exprt subf=f_get(literalt(quantifiers[i].var_no, (cube[i]==1)));
354  prime.add_to_operands(std::move(subf));
355  }
356  }
357 
358  simplify_extractbits(prime);
359 
360  if(prime.operands().empty())
361  result.copy_to_operands(true_exprt());
362  else if(prime.operands().size()==1)
363  result.add_to_operands(std::move(prime.op0()));
364  else
365  result.add_to_operands(std::move(prime));
366  }
367 
368  cube=NULL; // cube is free'd by nextCube
369 
370  exprt final;
371 
372  if(result.operands().empty())
373  final=false_exprt();
374  else if(result.operands().size()==1)
375  final=result.op0();
376  else
377  final=result;
378 
379  function_cache[l.var_no()]=final;
380 
381  if(l.sign())
382  return not_exprt(final);
383  else
384  return final;
385  }
386 }
387 
389 {
390  const BDD &model=*model_bdds[a.var_no()];
391 
392  if(model==bdd_manager->bddZero())
394  else if(model==bdd_manager->bddOne())
396  else
398 }
constant_exprt from_integer(const mp_integer &int_value, const typet &type)
Boolean AND.
Definition: std_expr.h:2120
bool process_clause(const bvt &bv, bvt &dest) const
filter 'true' from clause, eliminate duplicates, recognise trivially satisfied clauses
Definition: cnf.cpp:424
virtual literalt new_variable() override
Generate a new variable and return it as a literal.
Definition: cnf.cpp:385
virtual size_t no_variables() const override
Definition: cnf.h:42
Base class for all expressions.
Definition: expr.h:56
void copy_to_operands(const exprt &expr)
Copy the given argument to the end of exprt's operands.
Definition: expr.h:163
operandst & operands()
Definition: expr.h:94
void add_to_operands(const exprt &expr)
Add the given argument to the end of exprt's operands.
Definition: expr.h:170
Extracts a single bit of a bit-vector operand.
The Boolean constant false.
Definition: std_expr.h:3064
Unbounded, signed integers (mathematical integers, not bitvectors)
bool sign() const
Definition: literal.h:88
int dimacs() const
Definition: literal.h:117
var_not var_no() const
Definition: literal.h:83
exprt & op0()
Definition: std_expr.h:932
Boolean negation.
Definition: std_expr.h:2327
Boolean OR.
Definition: std_expr.h:2228
resultt
Definition: prop.h:101
tvt l_get(literalt a) const override
model_bddst model_bdds
Definition: qbf_bdd_core.h:27
const exprt f_get(literalt l) override
~qbf_bdd_certificatet(void) override
function_cachet function_cache
Definition: qbf_bdd_core.h:30
literalt new_variable(void) override
Generate a new variable and return it as a literal.
literalt new_variable() override
Generate a new variable and return it as a literal.
void lcnf(const bvt &bv) override
bool is_in_core(literalt l) const override
resultt prop_solve() override
~qbf_bdd_coret() override
tvt l_get(literalt a) const override
bdd_variable_mapt bdd_variable_map
Definition: qbf_bdd_core.h:47
modeltypet m_get(literalt a) const override
std::string solver_text() const override
literalt lor(literalt a, literalt b) override
void compress_certificate(void)
virtual void add_quantifier(const quantifiert &quantifier)
Definition: qdimacs_cnf.h:64
bool find_quantifier(const literalt l, quantifiert &q) const
quantifierst quantifiers
Definition: qdimacs_cnf.h:62
bool is_quantified(const literalt l) const
void simplify_extractbits(exprt &expr) const
variable_mapt variable_map
Definition: qdimacs_core.h:35
The Boolean constant true.
Definition: std_expr.h:3055
Definition: threeval.h:20
std::vector< literalt > bvt
Definition: literal.h:201
literalt const_literal(bool value)
Definition: literal.h:188
#define PRECONDITION_WITH_DIAGNOSTICS(CONDITION,...)
Definition: invariant.h:464
#define UNREACHABLE
This should be used to mark dead code.
Definition: invariant.h:525
#define UNIMPLEMENTED
Definition: invariant.h:558
API to expression classes.
std::string to_string(const string_not_contains_constraintt &expr)
Used for debug printing.