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