1 /********************* */
2 /*! \file abstraction.cpp
3 ** \verbatim
4 ** Top contributors (to current version):
5 ** Liana Hadarean, Aina Niemetz, Mathias Preiner
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 ** [[ Add lengthier description here ]]
13 ** \todo document this file
14 **/
15 #include "theory/bv/abstraction.h"
16
17 #include "options/bv_options.h"
18 #include "smt/dump.h"
19 #include "smt/smt_statistics_registry.h"
20 #include "theory/bv/theory_bv_utils.h"
21 #include "theory/rewriter.h"
22
23
24 using namespace CVC4;
25 using namespace CVC4::theory;
26 using namespace CVC4::theory::bv;
27 using namespace CVC4::context;
28
29 using namespace std;
30 using namespace CVC4::theory::bv::utils;
31
applyAbstraction(const std::vector<Node> & assertions,std::vector<Node> & new_assertions)32 bool AbstractionModule::applyAbstraction(const std::vector<Node>& assertions,
33 std::vector<Node>& new_assertions)
34 {
35 Debug("bv-abstraction") << "AbstractionModule::applyAbstraction\n";
36
37 TimerStat::CodeTimer abstractionTimer(d_statistics.d_abstractionTime);
38
39 TNodeSet seen;
40 for (unsigned i = 0; i < assertions.size(); ++i)
41 {
42 if (assertions[i].getKind() == kind::OR)
43 {
44 for (unsigned j = 0; j < assertions[i].getNumChildren(); ++j)
45 {
46 if (!isConjunctionOfAtoms(assertions[i][j], seen))
47 {
48 continue;
49 }
50 Node signature = computeSignature(assertions[i][j]);
51 storeSignature(signature, assertions[i][j]);
52 Debug("bv-abstraction") << " assertion: " << assertions[i][j] << "\n";
53 Debug("bv-abstraction") << " signature: " << signature << "\n";
54 }
55 }
56 }
57 finalizeSignatures();
58
59 for (unsigned i = 0; i < assertions.size(); ++i)
60 {
61 if (assertions[i].getKind() == kind::OR
62 && assertions[i][0].getKind() == kind::AND)
63 {
64 std::vector<Node> new_children;
65 for (unsigned j = 0; j < assertions[i].getNumChildren(); ++j)
66 {
67 if (hasSignature(assertions[i][j]))
68 {
69 new_children.push_back(abstractSignatures(assertions[i][j]));
70 }
71 else
72 {
73 new_children.push_back(assertions[i][j]);
74 }
75 }
76 new_assertions.push_back(utils::mkOr(new_children));
77 }
78 else
79 {
80 // assertions that are not changed
81 new_assertions.push_back(assertions[i]);
82 }
83 }
84
85 if (options::skolemizeArguments())
86 {
87 skolemizeArguments(new_assertions);
88 }
89
90 // if we are using the eager solver reverse the abstraction
91 if (options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER)
92 {
93 if (d_funcToSignature.size() == 0)
94 {
95 // we did not change anything
96 return false;
97 }
98 NodeNodeMap seen;
99 for (unsigned i = 0; i < new_assertions.size(); ++i)
100 {
101 new_assertions[i] = reverseAbstraction(new_assertions[i], seen);
102 }
103 // we undo the abstraction functions so the logic is QF_BV still
104 return true;
105 }
106
107 // return true if we have created new function symbols for the problem
108 return d_funcToSignature.size() != 0;
109 }
110
isConjunctionOfAtoms(TNode node,TNodeSet & seen)111 bool AbstractionModule::isConjunctionOfAtoms(TNode node, TNodeSet& seen)
112 {
113 if (seen.find(node)!= seen.end())
114 return true;
115
116 if (!node.getType().isBitVector() && node.getKind() != kind::AND)
117 {
118 return utils::isBVPredicate(node);
119 }
120
121 if (node.getNumChildren() == 0)
122 return true;
123
124 for (unsigned i = 0; i < node.getNumChildren(); ++i) {
125 if (!isConjunctionOfAtoms(node[i], seen))
126 {
127 return false;
128 }
129 }
130 seen.insert(node);
131 return true;
132 }
133
134
reverseAbstraction(Node assertion,NodeNodeMap & seen)135 Node AbstractionModule::reverseAbstraction(Node assertion, NodeNodeMap& seen) {
136
137 if (seen.find(assertion) != seen.end())
138 return seen[assertion];
139
140 if (isAbstraction(assertion)) {
141 Node interp = getInterpretation(assertion);
142 seen[assertion] = interp;
143 Assert (interp.getType() == assertion.getType());
144 return interp;
145 }
146
147 if (assertion.getNumChildren() == 0) {
148 seen[assertion] = assertion;
149 return assertion;
150 }
151
152 NodeBuilder<> result(assertion.getKind());
153 if (assertion.getMetaKind() == kind::metakind::PARAMETERIZED) {
154 result << assertion.getOperator();
155 }
156
157 for (unsigned i = 0; i < assertion.getNumChildren(); ++i) {
158 result << reverseAbstraction(assertion[i], seen);
159 }
160 Node res = result;
161 seen[assertion] = res;
162 return res;
163 }
164
skolemizeArguments(std::vector<Node> & assertions)165 void AbstractionModule::skolemizeArguments(std::vector<Node>& assertions)
166 {
167 NodeManager* nm = NodeManager::currentNM();
168 for (unsigned i = 0; i < assertions.size(); ++i)
169 {
170 TNode assertion = assertions[i];
171 if (assertion.getKind() != kind::OR) continue;
172
173 bool is_skolemizable = true;
174 for (unsigned k = 0; k < assertion.getNumChildren(); ++k)
175 {
176 if (assertion[k].getKind() != kind::EQUAL
177 || assertion[k][0].getKind() != kind::APPLY_UF
178 || assertion[k][1].getKind() != kind::CONST_BITVECTOR
179 || assertion[k][1].getConst<BitVector>() != BitVector(1, 1u))
180 {
181 is_skolemizable = false;
182 break;
183 }
184 }
185
186 if (!is_skolemizable) continue;
187
188 ArgsTable assertion_table;
189
190 // collect function symbols and their arguments
191 for (unsigned j = 0; j < assertion.getNumChildren(); ++j)
192 {
193 TNode current = assertion[j];
194 Assert(current.getKind() == kind::EQUAL
195 && current[0].getKind() == kind::APPLY_UF);
196 TNode func = current[0];
197 ArgsVec args;
198 for (unsigned k = 0; k < func.getNumChildren(); ++k)
199 {
200 args.push_back(func[k]);
201 }
202 assertion_table.addEntry(func.getOperator(), args);
203 }
204
205 NodeBuilder<> assertion_builder(kind::OR);
206 // construct skolemized assertion
207 for (ArgsTable::iterator it = assertion_table.begin();
208 it != assertion_table.end();
209 ++it)
210 {
211 // for each function symbol
212 ++(d_statistics.d_numArgsSkolemized);
213 TNode func = it->first;
214 ArgsTableEntry& args = it->second;
215 NodeBuilder<> skolem_func(kind::APPLY_UF);
216 skolem_func << func;
217 std::vector<Node> skolem_args;
218
219 for (unsigned j = 0; j < args.getArity(); ++j)
220 {
221 bool all_same = true;
222 for (unsigned k = 1; k < args.getNumEntries(); ++k)
223 {
224 if (args.getEntry(k)[j] != args.getEntry(0)[j]) all_same = false;
225 }
226 Node new_arg = all_same
227 ? (Node)args.getEntry(0)[j]
228 : utils::mkVar(utils::getSize(args.getEntry(0)[j]));
229 skolem_args.push_back(new_arg);
230 skolem_func << new_arg;
231 }
232
233 Node skolem_func_eq1 =
234 nm->mkNode(kind::EQUAL, (Node)skolem_func, utils::mkConst(1, 1u));
235
236 // enumerate arguments assignments
237 std::vector<Node> or_assignments;
238 for (ArgsTableEntry::iterator it = args.begin(); it != args.end(); ++it)
239 {
240 NodeBuilder<> arg_assignment(kind::AND);
241 ArgsVec& args = *it;
242 for (unsigned k = 0; k < args.size(); ++k)
243 {
244 Node eq = nm->mkNode(kind::EQUAL, args[k], skolem_args[k]);
245 arg_assignment << eq;
246 }
247 or_assignments.push_back(arg_assignment);
248 }
249
250 Node new_func_def =
251 utils::mkAnd(skolem_func_eq1, utils::mkOr(or_assignments));
252 assertion_builder << new_func_def;
253 }
254 Node new_assertion = assertion_builder;
255 Debug("bv-abstraction-dbg") << "AbstractionModule::skolemizeArguments "
256 << assertions[i] << " => \n";
257 Debug("bv-abstraction-dbg") << " " << new_assertion;
258 assertions[i] = new_assertion;
259 }
260 }
261
storeSignature(Node signature,TNode assertion)262 void AbstractionModule::storeSignature(Node signature, TNode assertion) {
263 if(d_signatures.find(signature) == d_signatures.end()) {
264 d_signatures[signature] = 0;
265 }
266 d_signatures[signature] = d_signatures[signature] + 1;
267 d_assertionToSignature[assertion] = signature;
268 }
269
computeSignature(TNode node)270 Node AbstractionModule::computeSignature(TNode node) {
271 resetSignatureIndex();
272 NodeNodeMap cache;
273 Node sig = computeSignatureRec(node, cache);
274 return sig;
275 }
276
getSignatureSkolem(TNode node)277 Node AbstractionModule::getSignatureSkolem(TNode node)
278 {
279 Assert(node.getMetaKind() == kind::metakind::VARIABLE);
280 NodeManager* nm = NodeManager::currentNM();
281 unsigned bitwidth = utils::getSize(node);
282 if (d_signatureSkolems.find(bitwidth) == d_signatureSkolems.end())
283 {
284 d_signatureSkolems[bitwidth] = vector<Node>();
285 }
286
287 vector<Node>& skolems = d_signatureSkolems[bitwidth];
288 // get the index of bv variables of this size
289 unsigned index = getBitwidthIndex(bitwidth);
290 Assert(skolems.size() + 1 >= index);
291 if (skolems.size() == index)
292 {
293 ostringstream os;
294 os << "sig_" << bitwidth << "_" << index;
295 skolems.push_back(nm->mkSkolem(os.str(),
296 nm->mkBitVectorType(bitwidth),
297 "skolem for computing signatures"));
298 }
299 ++(d_signatureIndices[bitwidth]);
300 return skolems[index];
301 }
302
getBitwidthIndex(unsigned bitwidth)303 unsigned AbstractionModule::getBitwidthIndex(unsigned bitwidth) {
304 if (d_signatureIndices.find(bitwidth) == d_signatureIndices.end()) {
305 d_signatureIndices[bitwidth] = 0;
306 }
307 return d_signatureIndices[bitwidth];
308 }
309
resetSignatureIndex()310 void AbstractionModule::resetSignatureIndex() {
311 for (IndexMap::iterator it = d_signatureIndices.begin(); it != d_signatureIndices.end(); ++it) {
312 it->second = 0;
313 }
314 }
315
hasSignature(Node node)316 bool AbstractionModule::hasSignature(Node node) {
317 return d_assertionToSignature.find(node) != d_assertionToSignature.end();
318 }
319
getGeneralizedSignature(Node node)320 Node AbstractionModule::getGeneralizedSignature(Node node) {
321 NodeNodeMap::const_iterator it = d_assertionToSignature.find(node);
322 Assert (it != d_assertionToSignature.end());
323 Node generalized_signature = getGeneralization(it->second);
324 return generalized_signature;
325 }
326
computeSignatureRec(TNode node,NodeNodeMap & cache)327 Node AbstractionModule::computeSignatureRec(TNode node, NodeNodeMap& cache) {
328 if (cache.find(node) != cache.end()) {
329 return cache.find(node)->second;
330 }
331
332 if (node.getNumChildren() == 0) {
333 if (node.getKind() == kind::CONST_BITVECTOR)
334 return node;
335
336 Node sig = getSignatureSkolem(node);
337 cache[node] = sig;
338 return sig;
339 }
340
341 NodeBuilder<> builder(node.getKind());
342 if (node.getMetaKind() == kind::metakind::PARAMETERIZED) {
343 builder << node.getOperator();
344 }
345 for (unsigned i = 0; i < node.getNumChildren(); ++i) {
346 Node converted = computeSignatureRec(node[i], cache);
347 builder << converted;
348 }
349 Node result = builder;
350 cache[node] = result;
351 return result;
352 }
353
354 /**
355 * Returns 0, if the two are equal,
356 * 1 if s is a generalization of t
357 * 2 if t is a generalization of s
358 * -1 if the two cannot be unified
359 *
360 * @param s
361 * @param t
362 *
363 * @return
364 */
comparePatterns(TNode s,TNode t)365 int AbstractionModule::comparePatterns(TNode s, TNode t) {
366 if (s.getKind() == kind::SKOLEM &&
367 t.getKind() == kind::SKOLEM) {
368 return 0;
369 }
370
371 if (s.getKind() == kind::CONST_BITVECTOR &&
372 t.getKind() == kind::CONST_BITVECTOR) {
373 if (s == t) {
374 return 0;
375 } else {
376 return -1;
377 }
378 }
379
380 if (s.getKind() == kind::SKOLEM &&
381 t.getKind() == kind::CONST_BITVECTOR) {
382 return 1;
383 }
384
385 if (s.getKind() == kind::CONST_BITVECTOR &&
386 t.getKind() == kind::SKOLEM) {
387 return 2;
388 }
389
390 if (s.getNumChildren() != t.getNumChildren() ||
391 s.getKind() != t.getKind())
392 return -1;
393
394 int unify = 0;
395 for (unsigned i = 0; i < s.getNumChildren(); ++i) {
396 int unify_i = comparePatterns(s[i], t[i]);
397 if (unify_i < 0)
398 return -1;
399 if (unify == 0) {
400 unify = unify_i;
401 } else if (unify != unify_i && unify_i != 0) {
402 return -1;
403 }
404 }
405 return unify;
406 }
407
getGeneralization(TNode term)408 TNode AbstractionModule::getGeneralization(TNode term) {
409 NodeNodeMap::iterator it = d_sigToGeneralization.find(term);
410 // if not in the map we add it
411 if (it == d_sigToGeneralization.end()) {
412 d_sigToGeneralization[term] = term;
413 return term;
414 }
415 // doesn't have a generalization
416 if (it->second == term)
417 return term;
418
419 TNode generalization = getGeneralization(it->second);
420 Assert (generalization != term);
421 d_sigToGeneralization[term] = generalization;
422 return generalization;
423 }
424
storeGeneralization(TNode s,TNode t)425 void AbstractionModule::storeGeneralization(TNode s, TNode t) {
426 Assert (s == getGeneralization(s));
427 Assert (t == getGeneralization(t));
428 d_sigToGeneralization[s] = t;
429 }
430
finalizeSignatures()431 void AbstractionModule::finalizeSignatures()
432 {
433 NodeManager* nm = NodeManager::currentNM();
434 Debug("bv-abstraction")
435 << "AbstractionModule::finalizeSignatures num signatures = "
436 << d_signatures.size() << "\n";
437 TNodeSet new_signatures;
438
439 // "unify" signatures
440 for (SignatureMap::const_iterator ss = d_signatures.begin();
441 ss != d_signatures.end();
442 ++ss)
443 {
444 for (SignatureMap::const_iterator tt = ss; tt != d_signatures.end(); ++tt)
445 {
446 TNode t = getGeneralization(tt->first);
447 TNode s = getGeneralization(ss->first);
448
449 if (t != s)
450 {
451 int status = comparePatterns(s, t);
452 Assert(status);
453 if (status < 0) continue;
454 if (status == 1)
455 {
456 storeGeneralization(t, s);
457 }
458 else
459 {
460 storeGeneralization(s, t);
461 }
462 }
463 }
464 }
465 // keep only most general signatures
466 for (SignatureMap::iterator it = d_signatures.begin();
467 it != d_signatures.end();)
468 {
469 TNode sig = it->first;
470 TNode gen = getGeneralization(sig);
471 if (sig != gen)
472 {
473 Assert(d_signatures.find(gen) != d_signatures.end());
474 // update the count
475 d_signatures[gen] += d_signatures[sig];
476 d_signatures.erase(it++);
477 }
478 else
479 {
480 ++it;
481 }
482 }
483
484 // remove signatures that are not frequent enough
485 for (SignatureMap::iterator it = d_signatures.begin();
486 it != d_signatures.end();)
487 {
488 if (it->second <= 7)
489 {
490 d_signatures.erase(it++);
491 }
492 else
493 {
494 ++it;
495 }
496 }
497
498 for (SignatureMap::const_iterator it = d_signatures.begin();
499 it != d_signatures.end();
500 ++it)
501 {
502 TNode signature = it->first;
503 // we already processed this signature
504 Assert(d_signatureToFunc.find(signature) == d_signatureToFunc.end());
505
506 Debug("bv-abstraction") << "Processing signature " << signature << " count "
507 << it->second << "\n";
508 std::vector<TypeNode> arg_types;
509 TNodeSet seen;
510 collectArgumentTypes(signature, arg_types, seen);
511 Assert(signature.getType().isBoolean());
512 // make function return a bitvector of size 1
513 // Node bv_function = nm->mkNode(kind::ITE, signature, utils::mkConst(1,
514 // 1u), utils::mkConst(1, 0u));
515 TypeNode range = nm->mkBitVectorType(1);
516
517 TypeNode abs_type = nm->mkFunctionType(arg_types, range);
518 Node abs_func =
519 nm->mkSkolem("abs_$$", abs_type, "abstraction function for bv theory");
520 Debug("bv-abstraction") << " abstracted by function " << abs_func << "\n";
521
522 // NOTE: signature expression type is BOOLEAN
523 d_signatureToFunc[signature] = abs_func;
524 d_funcToSignature[abs_func] = signature;
525 }
526
527 d_statistics.d_numFunctionsAbstracted.setData(d_signatureToFunc.size());
528
529 Debug("bv-abstraction") << "AbstractionModule::finalizeSignatures abstracted "
530 << d_signatureToFunc.size() << " signatures. \n";
531 }
532
collectArgumentTypes(TNode sig,std::vector<TypeNode> & types,TNodeSet & seen)533 void AbstractionModule::collectArgumentTypes(TNode sig, std::vector<TypeNode>& types, TNodeSet& seen) {
534 if (seen.find(sig) != seen.end())
535 return;
536
537 if (sig.getKind() == kind::SKOLEM) {
538 types.push_back(sig.getType());
539 seen.insert(sig);
540 return;
541 }
542
543 for (unsigned i = 0; i < sig.getNumChildren(); ++i) {
544 collectArgumentTypes(sig[i], types, seen);
545 seen.insert(sig);
546 }
547 }
548
collectArguments(TNode node,TNode signature,std::vector<Node> & args,TNodeSet & seen)549 void AbstractionModule::collectArguments(TNode node, TNode signature, std::vector<Node>& args, TNodeSet& seen) {
550 if (seen.find(node)!= seen.end())
551 return;
552
553 if (node.getMetaKind() == kind::metakind::VARIABLE
554 || node.getKind() == kind::CONST_BITVECTOR)
555 {
556 // a constant in the node can either map to an argument of the abstraction
557 // or can be hard-coded and part of the abstraction
558 if (signature.getKind() == kind::SKOLEM) {
559 args.push_back(node);
560 seen.insert(node);
561 } else {
562 Assert (signature.getKind() == kind::CONST_BITVECTOR);
563 }
564 //
565 return;
566 }
567 Assert (node.getKind() == signature.getKind() &&
568 node.getNumChildren() == signature.getNumChildren());
569
570 for (unsigned i = 0; i < node.getNumChildren(); ++i) {
571 collectArguments(node[i], signature[i], args, seen);
572 seen.insert(node);
573 }
574 }
575
abstractSignatures(TNode assertion)576 Node AbstractionModule::abstractSignatures(TNode assertion)
577 {
578 Debug("bv-abstraction") << "AbstractionModule::abstractSignatures "
579 << assertion << "\n";
580 NodeManager* nm = NodeManager::currentNM();
581 // assume the assertion has been fully abstracted
582 Node signature = getGeneralizedSignature(assertion);
583
584 Debug("bv-abstraction") << " with sig " << signature << "\n";
585 NodeNodeMap::iterator it = d_signatureToFunc.find(signature);
586 if (it != d_signatureToFunc.end())
587 {
588 std::vector<Node> args;
589 TNode func = it->second;
590 // pushing the function symbol
591 args.push_back(func);
592 TNodeSet seen;
593 collectArguments(assertion, signature, args, seen);
594 std::vector<TNode> real_args;
595 for (unsigned i = 1; i < args.size(); ++i)
596 {
597 real_args.push_back(args[i]);
598 }
599 d_argsTable.addEntry(func, real_args);
600 Node result = nm->mkNode(
601 kind::EQUAL,
602 nm->mkNode(kind::APPLY_UF, args), utils::mkConst(1, 1u));
603 Debug("bv-abstraction") << "=> " << result << "\n";
604 Assert(result.getType() == assertion.getType());
605 return result;
606 }
607 return assertion;
608 }
609
isAbstraction(TNode node)610 bool AbstractionModule::isAbstraction(TNode node) {
611 if (node.getKind() != kind::EQUAL)
612 return false;
613 if ((node[0].getKind() != kind::CONST_BITVECTOR ||
614 node[1].getKind() != kind::APPLY_UF) &&
615 (node[1].getKind() != kind::CONST_BITVECTOR ||
616 node[0].getKind() != kind::APPLY_UF))
617 return false;
618
619 TNode constant = node[0].getKind() == kind::CONST_BITVECTOR ? node[0] : node[1];
620 TNode func = node[0].getKind() == kind::APPLY_UF ? node[0] : node[1];
621 Assert (constant.getKind() == kind::CONST_BITVECTOR &&
622 func.getKind() == kind::APPLY_UF);
623 if (utils::getSize(constant) != 1)
624 return false;
625 if (constant != utils::mkConst(1, 1u))
626 return false;
627
628 TNode func_symbol = func.getOperator();
629 if (d_funcToSignature.find(func_symbol) == d_funcToSignature.end())
630 return false;
631
632 return true;
633 }
634
getInterpretation(TNode node)635 Node AbstractionModule::getInterpretation(TNode node) {
636 Assert (isAbstraction(node));
637 TNode constant = node[0].getKind() == kind::CONST_BITVECTOR ? node[0] : node[1];
638 TNode apply = node[0].getKind() == kind::APPLY_UF ? node[0] : node[1];
639 Assert (constant.getKind() == kind::CONST_BITVECTOR &&
640 apply.getKind() == kind::APPLY_UF);
641
642 Node func = apply.getOperator();
643 Assert (d_funcToSignature.find(func) != d_funcToSignature.end());
644
645 Node sig = d_funcToSignature[func];
646
647 // substitute arguments in signature
648 TNodeTNodeMap seen;
649 unsigned index = 0;
650 Node result = substituteArguments(sig, apply, index, seen);
651 Assert (result.getType().isBoolean());
652 Assert (index == apply.getNumChildren());
653 // Debug("bv-abstraction") << "AbstractionModule::getInterpretation " << node << "\n";
654 // Debug("bv-abstraction") << " => " << result << "\n";
655 return result;
656 }
657
substituteArguments(TNode signature,TNode apply,unsigned & index,TNodeTNodeMap & seen)658 Node AbstractionModule::substituteArguments(TNode signature, TNode apply, unsigned& index, TNodeTNodeMap& seen) {
659 if (seen.find(signature) != seen.end()) {
660 return seen[signature];
661 }
662
663 if (signature.getKind() == kind::SKOLEM) {
664 // return corresponding argument and increment counter
665 seen[signature] = apply[index];
666 return apply[index++];
667 }
668
669 if (signature.getNumChildren() == 0) {
670 Assert(signature.getMetaKind() != kind::metakind::VARIABLE);
671 seen[signature] = signature;
672 return signature;
673 }
674
675 NodeBuilder<> builder(signature.getKind());
676 if (signature.getMetaKind() == kind::metakind::PARAMETERIZED) {
677 builder << signature.getOperator();
678 }
679
680 for (unsigned i = 0; i < signature.getNumChildren(); ++i) {
681 Node child = substituteArguments(signature[i], apply, index, seen);
682 builder << child;
683 }
684
685 Node result = builder;
686 seen[signature]= result;
687
688 return result;
689 }
690
simplifyConflict(TNode conflict)691 Node AbstractionModule::simplifyConflict(TNode conflict) {
692 if (Dump.isOn("bv-abstraction")) {
693 NodeNodeMap seen;
694 Node c = reverseAbstraction(conflict, seen);
695 Dump("bv-abstraction") << PushCommand();
696 Dump("bv-abstraction") << AssertCommand(c.toExpr());
697 Dump("bv-abstraction") << CheckSatCommand();
698 Dump("bv-abstraction") << PopCommand();
699 }
700
701 Debug("bv-abstraction-dbg") << "AbstractionModule::simplifyConflict " << conflict << "\n";
702 if (conflict.getKind() != kind::AND)
703 return conflict;
704
705 std::vector<Node> conjuncts;
706 for (unsigned i = 0; i < conflict.getNumChildren(); ++i)
707 conjuncts.push_back(conflict[i]);
708
709 theory::SubstitutionMap subst(new context::Context());
710 for (unsigned i = 0; i < conjuncts.size(); ++i) {
711 TNode conjunct = conjuncts[i];
712 // substitute s -> t
713 Node s, t;
714
715 if (conjunct.getKind() == kind::EQUAL) {
716 if (conjunct[0].getMetaKind() == kind::metakind::VARIABLE &&
717 conjunct[1].getKind() == kind::CONST_BITVECTOR) {
718 s = conjunct[0];
719 t = conjunct[1];
720 }
721 else if (conjunct[1].getMetaKind() == kind::metakind::VARIABLE &&
722 conjunct[0].getKind() == kind::CONST_BITVECTOR) {
723 s = conjunct[1];
724 t = conjunct[0];
725 } else {
726 continue;
727 }
728
729 Assert (!subst.hasSubstitution(s));
730 Assert (!t.isNull() &&
731 !s.isNull() &&
732 s!= t);
733 subst.addSubstitution(s, t);
734
735 for (unsigned k = 0; k < conjuncts.size(); k++) {
736 conjuncts[k] = subst.apply(conjuncts[k]);
737 }
738 }
739 }
740 Node new_conflict = Rewriter::rewrite(utils::mkAnd(conjuncts));
741
742 Debug("bv-abstraction") << "AbstractionModule::simplifyConflict conflict " << conflict <<"\n";
743 Debug("bv-abstraction") << " => " << new_conflict <<"\n";
744
745 if (Dump.isOn("bv-abstraction")) {
746
747 NodeNodeMap seen;
748 Node nc = reverseAbstraction(new_conflict, seen);
749 Dump("bv-abstraction") << PushCommand();
750 Dump("bv-abstraction") << AssertCommand(nc.toExpr());
751 Dump("bv-abstraction") << CheckSatCommand();
752 Dump("bv-abstraction") << PopCommand();
753 }
754
755 return new_conflict;
756 }
757
758
DebugPrintInstantiations(const std::vector<std::vector<ArgsVec>> & instantiations,const std::vector<TNode> functions)759 void DebugPrintInstantiations(const std::vector< std::vector<ArgsVec> >& instantiations,
760 const std::vector<TNode> functions) {
761 // print header
762 Debug("bv-abstraction-dbg") <<"[ ";
763 for (unsigned i = 0; i < functions.size(); ++i) {
764 for (unsigned j = 1; j < functions[i].getNumChildren(); ++j) {
765 Debug("bv-abstraction-dgb") << functions[i][j] <<" ";
766 }
767 Debug("bv-abstraction-dgb") << " || ";
768 }
769 Debug("bv-abstraction-dbg") <<"]\n";
770
771 for (unsigned i = 0; i < instantiations.size(); ++i) {
772 Debug("bv-abstraction-dbg") <<"[";
773 const std::vector<ArgsVec>& inst = instantiations[i];
774 for (unsigned j = 0; j < inst.size(); ++j) {
775 for (unsigned k = 0; k < inst[j].size(); ++k) {
776 Debug("bv-abstraction-dbg") << inst[j][k] << " ";
777 }
778 Debug("bv-abstraction-dbg") << " || ";
779 }
780 Debug("bv-abstraction-dbg") <<"]\n";
781 }
782 }
783
generalizeConflict(TNode conflict,std::vector<Node> & lemmas)784 void AbstractionModule::generalizeConflict(TNode conflict, std::vector<Node>& lemmas) {
785 Debug("bv-abstraction") << "AbstractionModule::generalizeConflict " << conflict << "\n";
786 std::vector<TNode> functions;
787
788 // collect abstract functions
789 if (conflict.getKind() != kind::AND) {
790 if (isAbstraction(conflict)) {
791 Assert (conflict[0].getKind() == kind::APPLY_UF);
792 functions.push_back(conflict[0]);
793 }
794 } else {
795 for (unsigned i = 0; i < conflict.getNumChildren(); ++i) {
796 TNode conjunct = conflict[i];
797 if (isAbstraction(conjunct)) {
798 Assert (conjunct[0].getKind() == kind::APPLY_UF);
799 functions.push_back(conjunct[0]);
800 }
801 }
802 }
803
804 // if (functions.size() >= 3) {
805 // // dump conflict
806 // NodeNodeMap seen;
807 // Node reversed = reverseAbstraction(conflict, seen);
808 // std::cout << "CONFLICT " << reversed << "\n";
809 // }
810
811
812 if (functions.size() == 0 || functions.size() > options::bvNumFunc()) {
813 return;
814 }
815
816
817 // Skolemize function arguments to avoid confusion in pattern matching
818 SubstitutionMap skolem_subst(new context::Context());
819 SubstitutionMap reverse_skolem(new context::Context());
820 makeFreshSkolems(conflict, skolem_subst, reverse_skolem);
821
822 Node skolemized_conflict = skolem_subst.apply(conflict);
823 for (unsigned i = 0; i < functions.size(); ++i) {
824 functions[i] = skolem_subst.apply(functions[i]);
825 }
826
827 conflict = skolem_subst.apply(conflict);
828
829 LemmaInstantiatior inst(functions, d_argsTable, conflict);
830 std::vector<Node> new_lemmas;
831 inst.generateInstantiations(new_lemmas);
832 for (unsigned i = 0; i < new_lemmas.size(); ++i) {
833 TNode lemma = reverse_skolem.apply(new_lemmas[i]);
834 if (d_addedLemmas.find(lemma) == d_addedLemmas.end()) {
835 lemmas.push_back(lemma);
836 Debug("bv-abstraction-gen") << "adding lemma " << lemma << "\n";
837 storeLemma(lemma);
838
839 if (Dump.isOn("bv-abstraction")) {
840 NodeNodeMap seen;
841 Node l = reverseAbstraction(lemma, seen);
842 Dump("bv-abstraction") << PushCommand();
843 Dump("bv-abstraction") << AssertCommand(l.toExpr());
844 Dump("bv-abstraction") << CheckSatCommand();
845 Dump("bv-abstraction") << PopCommand();
846 }
847 }
848 }
849 }
850
next(int val,int index)851 int AbstractionModule::LemmaInstantiatior::next(int val, int index) {
852 if (val < d_maxMatch[index] - 1)
853 return val + 1;
854 return -1;
855 }
856
857 /**
858 * Assumes the stack without top is consistent, and checks that the
859 * full stack is consistent
860 *
861 * @param stack
862 *
863 * @return
864 */
isConsistent(const vector<int> & stack)865 bool AbstractionModule::LemmaInstantiatior::isConsistent(const vector<int>& stack) {
866 if (stack.empty())
867 return true;
868
869 unsigned current = stack.size() - 1;
870 TNode func = d_functions[current];
871 ArgsTableEntry& matches = d_argsTable.getEntry(func.getOperator());
872 ArgsVec& args = matches.getEntry(stack[current]);
873 Assert (args.size() == func.getNumChildren());
874 for (unsigned k = 0; k < args.size(); ++k) {
875 TNode s = func[k];
876 TNode t = args[k];
877
878 TNode s0 = s;
879 while (d_subst.hasSubstitution(s0)) {
880 s0 = d_subst.getSubstitution(s0);
881 }
882
883 TNode t0 = t;
884 while (d_subst.hasSubstitution(t0)) {
885 t0 = d_subst.getSubstitution(t0);
886 }
887
888 if (s0.isConst() && t0.isConst()) {
889 if (s0 != t0)
890 return false; // fail
891 else
892 continue;
893 }
894
895 if(s0.getMetaKind() == kind::metakind::VARIABLE &&
896 t0.isConst()) {
897 d_subst.addSubstitution(s0, t0);
898 continue;
899 }
900
901 if (s0.isConst() &&
902 t0.getMetaKind() == kind::metakind::VARIABLE) {
903 d_subst.addSubstitution(t0, s0);
904 continue;
905 }
906
907 Assert (s0.getMetaKind() == kind::metakind::VARIABLE &&
908 t0.getMetaKind() == kind::metakind::VARIABLE);
909
910 if (s0 != t0) {
911 d_subst.addSubstitution(s0, t0);
912 }
913 }
914 return true;
915 }
916
accept(const vector<int> & stack)917 bool AbstractionModule::LemmaInstantiatior::accept(const vector<int>& stack) {
918 return stack.size() == d_functions.size();
919 }
920
mkLemma()921 void AbstractionModule::LemmaInstantiatior::mkLemma() {
922 Node lemma = d_subst.apply(d_conflict);
923 // Debug("bv-abstraction-gen") << "AbstractionModule::LemmaInstantiatior::mkLemma " << lemma <<"\n";
924 d_lemmas.push_back(lemma);
925 }
926
backtrack(vector<int> & stack)927 void AbstractionModule::LemmaInstantiatior::backtrack(vector<int>& stack) {
928 if (!isConsistent(stack))
929 return;
930
931 if (accept(stack)) {
932 mkLemma();
933 return;
934 }
935
936 int x = 0;
937 while (x != -1) {
938 d_ctx->push();
939 stack.push_back(x);
940 backtrack(stack);
941
942 d_ctx->pop();
943 stack.pop_back();
944 x = next(x, stack.size());
945 }
946 }
947
948
generateInstantiations(std::vector<Node> & lemmas)949 void AbstractionModule::LemmaInstantiatior::generateInstantiations(std::vector<Node>& lemmas) {
950 Debug("bv-abstraction-gen") << "AbstractionModule::LemmaInstantiatior::generateInstantiations ";
951
952 std::vector<int> stack;
953 backtrack(stack);
954 Assert (d_ctx->getLevel() == 0);
955 Debug("bv-abstraction-gen") << "numLemmas=" << d_lemmas.size() <<"\n";
956 lemmas.swap(d_lemmas);
957 }
958
makeFreshSkolems(TNode node,SubstitutionMap & map,SubstitutionMap & reverse_map)959 void AbstractionModule::makeFreshSkolems(TNode node, SubstitutionMap& map, SubstitutionMap& reverse_map) {
960 if (map.hasSubstitution(node)) {
961 return;
962 }
963 if (node.getMetaKind() == kind::metakind::VARIABLE) {
964 Node skolem = utils::mkVar(utils::getSize(node));
965 map.addSubstitution(node, skolem);
966 reverse_map.addSubstitution(skolem, node);
967 return;
968 }
969 if (node.isConst())
970 return;
971
972 for (unsigned i = 0; i < node.getNumChildren(); ++i) {
973 makeFreshSkolems(node[i], map, reverse_map);
974 }
975 }
976
makeFreshArgs(TNode func,std::vector<Node> & fresh_args)977 void AbstractionModule::makeFreshArgs(TNode func, std::vector<Node>& fresh_args) {
978 Assert (fresh_args.size() == 0);
979 Assert (func.getKind() == kind::APPLY_UF);
980 TNodeNodeMap d_map;
981 for (unsigned i = 0; i < func.getNumChildren(); ++i) {
982 TNode arg = func[i];
983 if (arg.isConst()) {
984 fresh_args.push_back(arg);
985 continue;
986 }
987 Assert (arg.getMetaKind() == kind::metakind::VARIABLE);
988 TNodeNodeMap::iterator it = d_map.find(arg);
989 if (it != d_map.end()) {
990 fresh_args.push_back(it->second);
991 } else {
992 Node skolem = utils::mkVar(utils::getSize(arg));
993 d_map[arg] = skolem;
994 fresh_args.push_back(skolem);
995 }
996 }
997 Assert (fresh_args.size() == func.getNumChildren());
998 }
999
tryMatching(const std::vector<Node> & ss,const std::vector<TNode> & tt,TNode conflict)1000 Node AbstractionModule::tryMatching(const std::vector<Node>& ss, const std::vector<TNode>& tt, TNode conflict) {
1001 Assert (ss.size() == tt.size());
1002
1003 Debug("bv-abstraction-dbg") << "AbstractionModule::tryMatching conflict = " << conflict << "\n";
1004 if (Debug.isOn("bv-abstraction-dbg")) {
1005 Debug("bv-abstraction-dbg") << " Match: ";
1006 for (unsigned i = 0; i < ss.size(); ++i) {
1007 Debug("bv-abstraction-dbg") << ss[i] <<" ";
1008
1009 }
1010 Debug("bv-abstraction-dbg") << "\n To: ";
1011 for (unsigned i = 0; i < tt.size(); ++i) {
1012 Debug("bv-abstraction-dbg") << tt[i] <<" ";
1013 }
1014 Debug("bv-abstraction-dbg") <<"\n";
1015 }
1016
1017
1018 SubstitutionMap subst(new context::Context());
1019
1020 for (unsigned i = 0; i < ss.size(); ++i) {
1021 TNode s = ss[i];
1022 TNode t = tt[i];
1023
1024 TNode s0 = subst.hasSubstitution(s) ? subst.getSubstitution(s) : s;
1025 TNode t0 = subst.hasSubstitution(t) ? subst.getSubstitution(t) : t;
1026
1027 if (s0.isConst() && t0.isConst()) {
1028 if (s0 != t0)
1029 return Node(); // fail
1030 else
1031 continue;
1032 }
1033
1034 if(s0.getMetaKind() == kind::metakind::VARIABLE &&
1035 t0.isConst()) {
1036 subst.addSubstitution(s0, t0);
1037 continue;
1038 }
1039
1040 if (s0.isConst() &&
1041 t0.getMetaKind() == kind::metakind::VARIABLE) {
1042 subst.addSubstitution(t0, s0);
1043 continue;
1044 }
1045
1046 Assert (s0.getMetaKind() == kind::metakind::VARIABLE &&
1047 t0.getMetaKind() == kind::metakind::VARIABLE);
1048
1049 Assert (s0 != t0);
1050 subst.addSubstitution(s0, t0);
1051 }
1052
1053 Node res = subst.apply(conflict);
1054 Debug("bv-abstraction-dbg") << " Lemma: " << res <<"\n";
1055 return res;
1056 }
1057
storeLemma(TNode lemma)1058 void AbstractionModule::storeLemma(TNode lemma) {
1059 d_addedLemmas.insert(lemma);
1060 if (lemma.getKind() == kind::AND) {
1061 for (unsigned i = 0; i < lemma.getNumChildren(); i++) {
1062 TNode atom = lemma[i];
1063 atom = atom.getKind() == kind::NOT ? atom[0] : atom;
1064 Assert (atom.getKind() != kind::NOT);
1065 Assert (utils::isBVPredicate(atom));
1066 d_lemmaAtoms.insert(atom);
1067 }
1068 } else {
1069 lemma = lemma.getKind() == kind::NOT? lemma[0] : lemma;
1070 Assert (utils::isBVPredicate(lemma));
1071 d_lemmaAtoms.insert(lemma);
1072 }
1073 }
1074
1075
isLemmaAtom(TNode node) const1076 bool AbstractionModule::isLemmaAtom(TNode node) const {
1077 Assert (node.getType().isBoolean());
1078 node = node.getKind() == kind::NOT? node[0] : node;
1079
1080 return d_inputAtoms.find(node) == d_inputAtoms.end() &&
1081 d_lemmaAtoms.find(node) != d_lemmaAtoms.end();
1082 }
1083
addInputAtom(TNode atom)1084 void AbstractionModule::addInputAtom(TNode atom) {
1085 if (options::bitblastMode() == theory::bv::BITBLAST_MODE_LAZY) {
1086 d_inputAtoms.insert(atom);
1087 }
1088 }
1089
addArguments(const ArgsVec & args)1090 void AbstractionModule::ArgsTableEntry::addArguments(const ArgsVec& args) {
1091 Assert (args.size() == d_arity);
1092 d_data.push_back(args);
1093 }
1094
addEntry(TNode signature,const ArgsVec & args)1095 void AbstractionModule::ArgsTable::addEntry(TNode signature, const ArgsVec& args) {
1096 if (d_data.find(signature) == d_data.end()) {
1097 d_data[signature] = ArgsTableEntry(args.size());
1098 }
1099 ArgsTableEntry& entry = d_data[signature];
1100 entry.addArguments(args);
1101 }
1102
1103
hasEntry(TNode signature) const1104 bool AbstractionModule::ArgsTable::hasEntry(TNode signature) const {
1105 return d_data.find(signature) != d_data.end();
1106 }
1107
getEntry(TNode signature)1108 AbstractionModule::ArgsTableEntry& AbstractionModule::ArgsTable::getEntry(TNode signature) {
1109 Assert (hasEntry(signature));
1110 return d_data.find(signature)->second;
1111 }
1112
Statistics(const std::string & name)1113 AbstractionModule::Statistics::Statistics(const std::string& name)
1114 : d_numFunctionsAbstracted(name + "::abstraction::NumFunctionsAbstracted",
1115 0),
1116 d_numArgsSkolemized(name + "::abstraction::NumArgsSkolemized", 0),
1117 d_abstractionTime(name + "::abstraction::AbstractionTime")
1118 {
1119 smtStatisticsRegistry()->registerStat(&d_numFunctionsAbstracted);
1120 smtStatisticsRegistry()->registerStat(&d_numArgsSkolemized);
1121 smtStatisticsRegistry()->registerStat(&d_abstractionTime);
1122 }
1123
~Statistics()1124 AbstractionModule::Statistics::~Statistics() {
1125 smtStatisticsRegistry()->unregisterStat(&d_numFunctionsAbstracted);
1126 smtStatisticsRegistry()->unregisterStat(&d_numArgsSkolemized);
1127 smtStatisticsRegistry()->unregisterStat(&d_abstractionTime);
1128 }
1129