1 /*********************                                                        */
2 /*! \file bv_subtheory_algebraic.cpp
3  ** \verbatim
4  ** Top contributors (to current version):
5  **   Liana Hadarean, Aina Niemetz, Tim King
6  ** This file is part of the CVC4 project.
7  ** Copyright (c) 2009-2019 by the authors listed in the file AUTHORS
8  ** in the top-level source directory) and their institutional affiliations.
9  ** All rights reserved.  See the file COPYING in the top-level source
10  ** directory for licensing information.\endverbatim
11  **
12  ** \brief Algebraic solver.
13  **
14  ** Algebraic solver.
15  **/
16 #include "theory/bv/bv_subtheory_algebraic.h"
17 
18 #include <unordered_set>
19 
20 #include "expr/node_algorithm.h"
21 #include "options/bv_options.h"
22 #include "smt/smt_statistics_registry.h"
23 #include "smt_util/boolean_simplification.h"
24 #include "theory/bv/bv_quick_check.h"
25 #include "theory/bv/theory_bv.h"
26 #include "theory/bv/theory_bv_utils.h"
27 #include "theory/theory_model.h"
28 
29 using namespace CVC4::context;
30 using namespace CVC4::prop;
31 using namespace CVC4::theory::bv::utils;
32 using namespace std;
33 
34 namespace CVC4 {
35 namespace theory {
36 namespace bv {
37 
38 /* ------------------------------------------------------------------------- */
39 
40 namespace {
41 
42 /* Collect all variables under a given a node.  */
collectVariables(TNode node,utils::NodeSet & vars)43 void collectVariables(TNode node, utils::NodeSet& vars)
44 {
45   std::vector<TNode> stack;
46   std::unordered_set<TNode, TNodeHashFunction> visited;
47 
48   stack.push_back(node);
49   while (!stack.empty())
50   {
51     Node n = stack.back();
52     stack.pop_back();
53 
54     if (vars.find(n) != vars.end()) continue;
55     if (visited.find(n) != visited.end()) continue;
56     visited.insert(n);
57 
58     if (Theory::isLeafOf(n, THEORY_BV) && n.getKind() != kind::CONST_BITVECTOR)
59     {
60       vars.insert(n);
61       continue;
62     }
63     stack.insert(stack.end(), n.begin(), n.end());
64   }
65 }
66 
67 };
68 
69 /* ------------------------------------------------------------------------- */
70 
71 bool hasExpensiveBVOperators(TNode fact);
72 Node mergeExplanations(const std::vector<Node>& expls);
73 Node mergeExplanations(TNode expl1, TNode expl2);
74 
75 
SubstitutionEx(theory::SubstitutionMap * modelMap)76 SubstitutionEx::SubstitutionEx(theory::SubstitutionMap* modelMap)
77   : d_substitutions()
78   , d_cache()
79   , d_cacheInvalid(true)
80   , d_modelMap(modelMap)
81 {}
82 
addSubstitution(TNode from,TNode to,TNode reason)83 bool SubstitutionEx::addSubstitution(TNode from, TNode to, TNode reason) {
84   Debug("bv-substitution") << "SubstitutionEx::addSubstitution: "<< from
85                            <<" => "<< to << "\n" << " reason "<<reason << "\n";
86   Assert (from != to);
87   if (d_substitutions.find(from) != d_substitutions.end()) {
88     return false;
89   }
90 
91   d_modelMap->addSubstitution(from, to);
92 
93   d_cacheInvalid = true;
94   d_substitutions[from] = SubstitutionElement(to, reason);
95   return true;
96 }
97 
apply(TNode node)98 Node SubstitutionEx::apply(TNode node) {
99   Debug("bv-substitution") << "SubstitutionEx::apply("<< node <<")\n";
100   if (d_cacheInvalid) {
101     d_cache.clear();
102     d_cacheInvalid = false;
103   }
104 
105   SubstitutionsCache::iterator it = d_cache.find(node);
106 
107   if (it != d_cache.end()) {
108     Node res = it->second.to;
109     Debug("bv-substitution") << "   =>"<< res <<"\n";
110     return res;
111   }
112 
113   Node result = internalApply(node);
114   Debug("bv-substitution") << "   =>"<< result <<"\n";
115   return result;
116 }
117 
internalApply(TNode node)118 Node SubstitutionEx::internalApply(TNode node) {
119   if (d_substitutions.empty())
120     return node;
121 
122   vector<SubstitutionStackElement> stack;
123   stack.push_back(SubstitutionStackElement(node));
124 
125   while (!stack.empty()) {
126     SubstitutionStackElement head = stack.back();
127     stack.pop_back();
128 
129     TNode current = head.node;
130 
131     if (hasCache(current)) {
132       continue;
133     }
134 
135     // check if it has substitution
136     Substitutions::const_iterator it = d_substitutions.find(current);
137     if (it != d_substitutions.end()) {
138       vector<Node> reasons;
139       TNode to = it->second.to;
140       reasons.push_back(it->second.reason);
141       // check if the thing we subsituted to has substitutions
142       TNode res = internalApply(to);
143       // update reasons
144       reasons.push_back(getReason(to));
145       Node reason = mergeExplanations(reasons);
146       storeCache(current, res, reason);
147       continue;
148     }
149 
150     // if no children then just continue
151     if(current.getNumChildren() == 0) {
152       storeCache(current, current, utils::mkTrue());
153       continue;
154     }
155 
156     // children already processed
157     if (head.childrenAdded) {
158       NodeBuilder<> nb(current.getKind());
159       std::vector<Node> reasons;
160 
161       if (current.getMetaKind() == kind::metakind::PARAMETERIZED) {
162         TNode op = current.getOperator();
163         Assert (hasCache(op));
164         nb << getCache(op);
165         reasons.push_back(getReason(op));
166       }
167       for (unsigned i = 0; i < current.getNumChildren(); ++i) {
168         Assert (hasCache(current[i]));
169         nb << getCache(current[i]);
170         reasons.push_back(getReason(current[i]));
171       }
172       Node result = nb;
173       // if the node is new apply substitutions to it
174       Node subst_result = result;
175       if (result != current) {
176         subst_result = result!= current? internalApply(result) : result;
177         reasons.push_back(getReason(result));
178       }
179       Node reason = mergeExplanations(reasons);
180       storeCache(current, subst_result, reason);
181       continue;
182     } else {
183       // add children to stack
184       stack.push_back(SubstitutionStackElement(current, true));
185       if (current.getMetaKind() == kind::metakind::PARAMETERIZED) {
186         stack.push_back(SubstitutionStackElement(current.getOperator()));
187       }
188       for (unsigned i = 0; i < current.getNumChildren(); ++i) {
189         stack.push_back(SubstitutionStackElement(current[i]));
190       }
191     }
192   }
193 
194   Assert(hasCache(node));
195   return getCache(node);
196 }
197 
explain(TNode node) const198 Node SubstitutionEx::explain(TNode node) const {
199   if(!hasCache(node)) {
200     return utils::mkTrue();
201   }
202 
203   Debug("bv-substitution") << "SubstitutionEx::explain("<< node <<")\n";
204   Node res = getReason(node);
205   Debug("bv-substitution") << "  with "<< res <<"\n";
206   return res;
207 }
208 
getReason(TNode node) const209 Node SubstitutionEx::getReason(TNode node) const {
210   Assert(hasCache(node));
211   SubstitutionsCache::const_iterator it = d_cache.find(node);
212   return it->second.reason;
213 }
214 
hasCache(TNode node) const215 bool SubstitutionEx::hasCache(TNode node) const {
216   return d_cache.find(node) != d_cache.end();
217 }
218 
getCache(TNode node) const219 Node SubstitutionEx::getCache(TNode node) const {
220   Assert (hasCache(node));
221   return d_cache.find(node)->second.to;
222 }
223 
storeCache(TNode from,TNode to,Node reason)224 void SubstitutionEx::storeCache(TNode from, TNode to, Node reason) {
225   //  Debug("bv-substitution") << "SubstitutionEx::storeCache(" << from <<", " << to <<", "<< reason<<")\n";
226   Assert (!hasCache(from));
227   d_cache[from] = SubstitutionElement(to, reason);
228 }
229 
AlgebraicSolver(context::Context * c,TheoryBV * bv)230 AlgebraicSolver::AlgebraicSolver(context::Context* c, TheoryBV* bv)
231     : SubtheorySolver(c, bv),
232       d_modelMap(),
233       d_quickSolver(new BVQuickCheck("theory::bv::algebraic", bv)),
234       d_isComplete(c, false),
235       d_isDifficult(c, false),
236       d_budget(options::bitvectorAlgebraicBudget()),
237       d_explanations(),
238       d_inputAssertions(),
239       d_ids(),
240       d_numSolved(0),
241       d_numCalls(0),
242       d_quickXplain(),
243       d_statistics()
244 {
245   if (options::bitvectorQuickXplain())
246   {
247     d_quickXplain.reset(
248         new QuickXPlain("theory::bv::algebraic", d_quickSolver.get()));
249   }
250 }
251 
~AlgebraicSolver()252 AlgebraicSolver::~AlgebraicSolver() {}
253 
check(Theory::Effort e)254 bool AlgebraicSolver::check(Theory::Effort e)
255 {
256   Assert(options::bitblastMode() == theory::bv::BITBLAST_MODE_LAZY);
257 
258   if (!Theory::fullEffort(e)) { return true; }
259   if (!useHeuristic()) { return true; }
260 
261   TimerStat::CodeTimer algebraicTimer(d_statistics.d_solveTime);
262   Debug("bv-subtheory-algebraic") << "AlgebraicSolver::check (" << e << ")\n";
263   ++(d_numCalls);
264   ++(d_statistics.d_numCallstoCheck);
265 
266   d_explanations.clear();
267   d_ids.clear();
268   d_inputAssertions.clear();
269 
270   std::vector<WorklistElement> worklist;
271 
272   uint64_t original_bb_cost = 0;
273 
274   NodeManager* nm = NodeManager::currentNM();
275   NodeSet seen_assertions;
276   // Processing assertions from scratch
277   for (AssertionQueue::const_iterator it = assertionsBegin(); it != assertionsEnd(); ++it) {
278     Debug("bv-subtheory-algebraic") << "   " << *it << "\n";
279     TNode assertion = *it;
280     unsigned id = worklist.size();
281     d_ids[assertion] = id;
282     worklist.push_back(WorklistElement(assertion, id));
283     d_inputAssertions.insert(assertion);
284     storeExplanation(assertion);
285 
286     uint64_t assertion_size = d_quickSolver->computeAtomWeight(assertion, seen_assertions);
287     Assert (original_bb_cost <= original_bb_cost + assertion_size);
288     original_bb_cost+= assertion_size;
289   }
290 
291   for (unsigned i = 0; i < worklist.size(); ++i) {
292     d_ids[worklist[i].node] = worklist[i].id;
293   }
294 
295   Debug("bv-subtheory-algebraic") << "Assertions " << worklist.size() <<" : \n";
296 
297   Assert (d_explanations.size() == worklist.size());
298 
299   d_modelMap.reset(new SubstitutionMap(d_context));
300   SubstitutionEx subst(d_modelMap.get());
301 
302   // first round of substitutions
303   processAssertions(worklist, subst);
304 
305   if (!d_isDifficult.get()) {
306     // skolemize all possible extracts
307     ExtractSkolemizer skolemizer(d_modelMap.get());
308     skolemizer.skolemize(worklist);
309     // second round of substitutions
310     processAssertions(worklist, subst);
311   }
312 
313   NodeSet subst_seen;
314   uint64_t subst_bb_cost = 0;
315 
316   unsigned r = 0;
317   unsigned w = 0;
318 
319   for (; r < worklist.size(); ++r) {
320 
321     TNode fact = worklist[r].node;
322     unsigned id = worklist[r].id;
323 
324     if (Dump.isOn("bv-algebraic")) {
325       Node expl = d_explanations[id];
326       Node query = utils::mkNot(nm->mkNode(kind::IMPLIES, expl, fact));
327       Dump("bv-algebraic") << EchoCommand("ThoeryBV::AlgebraicSolver::substitution explanation");
328       Dump("bv-algebraic") << PushCommand();
329       Dump("bv-algebraic") << AssertCommand(query.toExpr());
330       Dump("bv-algebraic") << CheckSatCommand();
331       Dump("bv-algebraic") << PopCommand();
332     }
333 
334     if (fact.isConst() &&
335         fact.getConst<bool>() == true) {
336       continue;
337     }
338 
339     if (fact.isConst() &&
340         fact.getConst<bool>() == false) {
341       // we have a conflict
342       Node conflict = BooleanSimplification::simplify(d_explanations[id]);
343       d_bv->setConflict(conflict);
344       d_isComplete.set(true);
345       Debug("bv-subtheory-algebraic") << " UNSAT: assertion simplfies to false with conflict: "<< conflict << "\n";
346 
347       if (Dump.isOn("bv-algebraic")) {
348         Dump("bv-algebraic") << EchoCommand("TheoryBV::AlgebraicSolver::conflict");
349         Dump("bv-algebraic") << PushCommand();
350         Dump("bv-algebraic") << AssertCommand(conflict.toExpr());
351         Dump("bv-algebraic") << CheckSatCommand();
352         Dump("bv-algebraic") << PopCommand();
353       }
354 
355 
356       ++(d_statistics.d_numSimplifiesToFalse);
357       ++(d_numSolved);
358       return false;
359     }
360 
361     subst_bb_cost+= d_quickSolver->computeAtomWeight(fact, subst_seen);
362     worklist[w] = WorklistElement(fact, id);
363     Node expl =  BooleanSimplification::simplify(d_explanations[id]);
364     storeExplanation(id, expl);
365     d_ids[fact] = id;
366     ++w;
367   }
368 
369   worklist.resize(w);
370 
371 
372   if(Debug.isOn("bv-subtheory-algebraic")) {
373     Debug("bv-subtheory-algebraic") << "Assertions post-substitutions " << worklist.size() << ":\n";
374     for (unsigned i = 0; i < worklist.size(); ++i) {
375       Debug("bv-subtheory-algebraic") << "   " << worklist[i].node << "\n";
376     }
377   }
378 
379 
380   // all facts solved to true
381   if (worklist.empty()) {
382     Debug("bv-subtheory-algebraic") << " SAT: everything simplifies to true.\n";
383     ++(d_statistics.d_numSimplifiesToTrue);
384     ++(d_numSolved);
385     return true;
386   }
387 
388   double ratio = ((double)subst_bb_cost)/original_bb_cost;
389   if (ratio > 0.5 ||
390       !d_isDifficult.get()) {
391     // give up if problem not reduced enough
392     d_isComplete.set(false);
393     return true;
394   }
395 
396   d_quickSolver->clearSolver();
397 
398   d_quickSolver->push();
399   std::vector<Node> facts;
400   for (unsigned i = 0; i < worklist.size(); ++i) {
401     facts.push_back(worklist[i].node);
402   }
403   bool ok = quickCheck(facts);
404 
405   Debug("bv-subtheory-algebraic") << "AlgebraicSolver::check done " << ok << ".\n";
406   return ok;
407 }
408 
quickCheck(std::vector<Node> & facts)409 bool AlgebraicSolver::quickCheck(std::vector<Node>& facts) {
410   SatValue res = d_quickSolver->checkSat(facts, d_budget);
411 
412   if (res == SAT_VALUE_UNKNOWN) {
413     d_isComplete.set(false);
414     Debug("bv-subtheory-algebraic") << " Unknown.\n";
415     ++(d_statistics.d_numUnknown);
416     return true;
417   }
418 
419   if (res == SAT_VALUE_TRUE) {
420     Debug("bv-subtheory-algebraic") << " Sat.\n";
421     ++(d_statistics.d_numSat);
422     ++(d_numSolved);
423     d_isComplete.set(true);
424     return true;
425   }
426 
427   Assert (res == SAT_VALUE_FALSE);
428   Assert (d_quickSolver->inConflict());
429   d_isComplete.set(true);
430   Debug("bv-subtheory-algebraic") << " Unsat.\n";
431   ++(d_numSolved);
432   ++(d_statistics.d_numUnsat);
433 
434 
435   Node conflict = d_quickSolver->getConflict();
436   Debug("bv-subtheory-algebraic") << " Conflict: " << conflict << "\n";
437 
438   // singleton conflict
439   if (conflict.getKind() != kind::AND) {
440     Assert (d_ids.find(conflict) != d_ids.end());
441     unsigned id = d_ids[conflict];
442     Assert (id < d_explanations.size());
443     Node theory_confl = d_explanations[id];
444     d_bv->setConflict(theory_confl);
445     return false;
446   }
447 
448   Assert (conflict.getKind() == kind::AND);
449   if (options::bitvectorQuickXplain()) {
450     d_quickSolver->popToZero();
451     Debug("bv-quick-xplain") << "AlgebraicSolver::quickCheck original conflict size " << conflict.getNumChildren() << "\n";
452     conflict = d_quickXplain->minimizeConflict(conflict);
453     Debug("bv-quick-xplain") << "AlgebraicSolver::quickCheck minimized conflict size " << conflict.getNumChildren() << "\n";
454   }
455 
456   vector<TNode> theory_confl;
457   for (unsigned i = 0; i < conflict.getNumChildren(); ++i) {
458     TNode c = conflict[i];
459 
460     Assert (d_ids.find(c) != d_ids.end());
461     unsigned c_id = d_ids[c];
462     Assert (c_id < d_explanations.size());
463     TNode c_expl = d_explanations[c_id];
464     theory_confl.push_back(c_expl);
465   }
466 
467   Node confl = BooleanSimplification::simplify(utils::mkAnd(theory_confl));
468 
469   Debug("bv-subtheory-algebraic") << " Out Conflict: " << confl << "\n";
470   setConflict(confl);
471   return false;
472 }
473 
setConflict(TNode conflict)474 void AlgebraicSolver::setConflict(TNode conflict) {
475   Node final_conflict = conflict;
476   if (options::bitvectorQuickXplain() &&
477       conflict.getKind() == kind::AND &&
478       conflict.getNumChildren() > 4) {
479     final_conflict = d_quickXplain->minimizeConflict(conflict);
480   }
481   d_bv->setConflict(final_conflict);
482 }
483 
solve(TNode fact,TNode reason,SubstitutionEx & subst)484 bool AlgebraicSolver::solve(TNode fact, TNode reason, SubstitutionEx& subst) {
485   if (fact.getKind() != kind::EQUAL) return false;
486 
487   NodeManager* nm = NodeManager::currentNM();
488   TNode left = fact[0];
489   TNode right = fact[1];
490 
491   if (left.isVar() && !expr::hasSubterm(right, left))
492   {
493     bool changed = subst.addSubstitution(left, right, reason);
494     return changed;
495   }
496   if (right.isVar() && !expr::hasSubterm(left, right))
497   {
498     bool changed = subst.addSubstitution(right, left, reason);
499     return changed;
500   }
501 
502   // xor simplification
503   if (right.getKind() == kind::BITVECTOR_XOR &&
504       left.getKind() == kind::BITVECTOR_XOR) {
505     TNode var = left[0];
506     if (var.getMetaKind() != kind::metakind::VARIABLE)
507       return false;
508 
509     // simplify xor with same variable on both sides
510     if (expr::hasSubterm(right, var))
511     {
512       std::vector<Node> right_children;
513       for (unsigned i = 0; i < right.getNumChildren(); ++i) {
514         if (right[i] != var)
515           right_children.push_back(right[i]);
516       }
517       Assert (right_children.size());
518       Node new_right = utils::mkNaryNode(kind::BITVECTOR_XOR, right_children);
519       std::vector<Node> left_children;
520       for (unsigned i = 1; i < left.getNumChildren(); ++i) {
521         left_children.push_back(left[i]);
522       }
523       Node new_left = utils::mkNaryNode(kind::BITVECTOR_XOR, left_children);
524       Node new_fact = nm->mkNode(kind::EQUAL, new_left, new_right);
525       bool changed = subst.addSubstitution(fact, new_fact, reason);
526       return changed;
527     }
528 
529     NodeBuilder<> nb(kind::BITVECTOR_XOR);
530     for (unsigned i = 1; i < left.getNumChildren(); ++i) {
531       nb << left[i];
532     }
533     Node inverse = left.getNumChildren() == 2? (Node)left[1] : (Node)nb;
534     Node new_right = nm->mkNode(kind::BITVECTOR_XOR, right, inverse);
535     bool changed = subst.addSubstitution(var, new_right, reason);
536 
537     if (Dump.isOn("bv-algebraic")) {
538       Node query = utils::mkNot(nm->mkNode(
539           kind::EQUAL, fact, nm->mkNode(kind::EQUAL, var, new_right)));
540       Dump("bv-algebraic") << EchoCommand("ThoeryBV::AlgebraicSolver::substitution explanation");
541       Dump("bv-algebraic") << PushCommand();
542       Dump("bv-algebraic") << AssertCommand(query.toExpr());
543       Dump("bv-algebraic") << CheckSatCommand();
544       Dump("bv-algebraic") << PopCommand();
545     }
546 
547 
548     return changed;
549   }
550 
551   // (a xor t = a) <=> (t = 0)
552   if (left.getKind() == kind::BITVECTOR_XOR
553       && right.getMetaKind() == kind::metakind::VARIABLE
554       && expr::hasSubterm(left, right))
555   {
556     TNode var = right;
557     Node new_left = nm->mkNode(kind::BITVECTOR_XOR, var, left);
558     Node zero = utils::mkConst(utils::getSize(var), 0u);
559     Node new_fact = nm->mkNode(kind::EQUAL, zero, new_left);
560     bool changed = subst.addSubstitution(fact, new_fact, reason);
561     return changed;
562   }
563 
564   if (right.getKind() == kind::BITVECTOR_XOR
565       && left.getMetaKind() == kind::metakind::VARIABLE
566       && expr::hasSubterm(right, left))
567   {
568     TNode var = left;
569     Node new_right = nm->mkNode(kind::BITVECTOR_XOR, var, right);
570     Node zero = utils::mkConst(utils::getSize(var), 0u);
571     Node new_fact = nm->mkNode(kind::EQUAL, zero, new_right);
572     bool changed = subst.addSubstitution(fact, new_fact, reason);
573     return changed;
574   }
575 
576   // (a xor b = 0) <=> (a = b)
577   if (left.getKind() == kind::BITVECTOR_XOR &&
578       left.getNumChildren() == 2 &&
579       right.getKind() == kind::CONST_BITVECTOR &&
580       right.getConst<BitVector>() == BitVector(utils::getSize(left), 0u)) {
581     Node new_fact = nm->mkNode(kind::EQUAL, left[0], left[1]);
582     bool changed = subst.addSubstitution(fact, new_fact, reason);
583     return changed;
584   }
585 
586 
587   return false;
588 }
589 
isSubstitutableIn(TNode node,TNode in)590 bool AlgebraicSolver::isSubstitutableIn(TNode node, TNode in)
591 {
592   if (node.getMetaKind() == kind::metakind::VARIABLE
593       && !expr::hasSubterm(in, node))
594     return true;
595   return false;
596 }
597 
processAssertions(std::vector<WorklistElement> & worklist,SubstitutionEx & subst)598 void AlgebraicSolver::processAssertions(std::vector<WorklistElement>& worklist, SubstitutionEx& subst) {
599   NodeManager* nm = NodeManager::currentNM();
600   bool changed = true;
601   while(changed) {
602     // d_bv->spendResource();
603     changed = false;
604     for (unsigned i = 0; i < worklist.size(); ++i) {
605       // apply current substitutions
606       Node current = subst.apply(worklist[i].node);
607       unsigned current_id = worklist[i].id;
608       Node subst_expl = subst.explain(worklist[i].node);
609       worklist[i] = WorklistElement(Rewriter::rewrite(current), current_id);
610       // explanation for this assertion
611       Node old_expl = d_explanations[current_id];
612       Node new_expl = mergeExplanations(subst_expl, old_expl);
613       storeExplanation(current_id, new_expl);
614 
615       // use the new substitution to solve
616       if(solve(worklist[i].node, new_expl, subst)) {
617         changed = true;
618       }
619     }
620 
621     // check for concat slicings
622     for (unsigned i = 0; i < worklist.size(); ++i) {
623       TNode fact = worklist[i].node;
624       unsigned current_id = worklist[i].id;
625 
626       if (fact.getKind() != kind::EQUAL) {
627         continue;
628       }
629 
630       TNode left = fact[0];
631       TNode right = fact[1];
632       if (left.getKind() != kind::BITVECTOR_CONCAT ||
633           right.getKind() != kind::BITVECTOR_CONCAT ||
634           left.getNumChildren() != right.getNumChildren()) {
635         continue;
636       }
637 
638       bool can_slice = true;
639       for (unsigned j = 0; j < left.getNumChildren(); ++j) {
640         if (utils::getSize(left[j]) != utils::getSize(right[j]))
641           can_slice = false;
642       }
643 
644       if (!can_slice) {
645         continue;
646       }
647 
648       for (unsigned j = 0; j < left.getNumChildren(); ++j) {
649         Node eq_j = nm->mkNode(kind::EQUAL, left[j], right[j]);
650         unsigned id = d_explanations.size();
651         TNode expl = d_explanations[current_id];
652         storeExplanation(expl);
653         worklist.push_back(WorklistElement(eq_j, id));
654         d_ids[eq_j] = id;
655       }
656       worklist[i] = WorklistElement(utils::mkTrue(), worklist[i].id);
657       changed = true;
658     }
659     Assert (d_explanations.size() == worklist.size());
660   }
661 }
662 
storeExplanation(unsigned id,TNode explanation)663 void AlgebraicSolver::storeExplanation(unsigned id, TNode explanation) {
664   Assert (checkExplanation(explanation));
665   d_explanations[id] = explanation;
666 }
667 
storeExplanation(TNode explanation)668 void AlgebraicSolver::storeExplanation(TNode explanation) {
669   Assert (checkExplanation(explanation));
670   d_explanations.push_back(explanation);
671 }
672 
checkExplanation(TNode explanation)673 bool AlgebraicSolver::checkExplanation(TNode explanation) {
674   Node simplified_explanation = explanation; //BooleanSimplification::simplify(explanation);
675   if (simplified_explanation.getKind() != kind::AND) {
676     return d_inputAssertions.find(simplified_explanation) != d_inputAssertions.end();
677   }
678   for (unsigned i = 0; i < simplified_explanation.getNumChildren(); ++i) {
679     if (d_inputAssertions.find(simplified_explanation[i]) == d_inputAssertions.end()) {
680       return false;
681     }
682   }
683   return true;
684 }
685 
686 
isComplete()687 bool AlgebraicSolver::isComplete() {
688   return d_isComplete.get();
689 }
690 
useHeuristic()691 bool AlgebraicSolver::useHeuristic() {
692   if (d_numCalls == 0)
693     return true;
694 
695   double success_rate = double(d_numSolved)/double(d_numCalls);
696   d_statistics.d_useHeuristic.setData(success_rate);
697   return success_rate > 0.8;
698 }
699 
700 
assertFact(TNode fact)701 void AlgebraicSolver::assertFact(TNode fact) {
702   d_assertionQueue.push_back(fact);
703   d_isComplete.set(false);
704   if (!d_isDifficult.get()) {
705     d_isDifficult.set(hasExpensiveBVOperators(fact));
706   }
707 }
708 
getEqualityStatus(TNode a,TNode b)709 EqualityStatus AlgebraicSolver::getEqualityStatus(TNode a, TNode b) {
710   return EQUALITY_UNKNOWN;
711 }
712 
collectModelInfo(TheoryModel * model,bool fullModel)713 bool AlgebraicSolver::collectModelInfo(TheoryModel* model, bool fullModel)
714 {
715   Debug("bitvector-model") << "AlgebraicSolver::collectModelInfo\n";
716   AlwaysAssert (!d_quickSolver->inConflict());
717   set<Node> termSet;
718   d_bv->computeRelevantTerms(termSet);
719 
720   // collect relevant terms that the bv theory abstracts to variables
721   // (variables and parametric terms such as select apply_uf)
722   std::vector<TNode> variables;
723   std::vector<Node> values;
724   for (set<Node>::const_iterator it = termSet.begin(); it != termSet.end(); ++it) {
725     TNode term = *it;
726     if (term.getType().isBitVector() &&
727         (term.getMetaKind() == kind::metakind::VARIABLE ||
728          Theory::theoryOf(term) != THEORY_BV)) {
729       variables.push_back(term);
730       values.push_back(term);
731     }
732   }
733 
734   NodeSet leaf_vars;
735   Debug("bitvector-model") << "Substitutions:\n";
736   for (unsigned i = 0; i < variables.size(); ++i) {
737     TNode current = variables[i];
738     TNode subst = Rewriter::rewrite(d_modelMap->apply(current));
739     Debug("bitvector-model") << "   " << current << " => " << subst << "\n";
740     values[i] = subst;
741     collectVariables(subst, leaf_vars);
742   }
743 
744   Debug("bitvector-model") << "Model:\n";
745 
746   for (NodeSet::const_iterator it = leaf_vars.begin(); it != leaf_vars.end(); ++it) {
747     TNode var = *it;
748     Node value = d_quickSolver->getVarValue(var, true);
749     Assert (!value.isNull() || !fullModel);
750 
751     // may be a shared term that did not appear in the current assertions
752     // AJR: need to check whether already in map for cases where collectModelInfo is called multiple times in the same context
753     if (!value.isNull() && !d_modelMap->hasSubstitution(var)) {
754       Debug("bitvector-model") << "   " << var << " => " << value << "\n";
755       Assert (value.getKind() == kind::CONST_BITVECTOR);
756       d_modelMap->addSubstitution(var, value);
757     }
758   }
759 
760   Debug("bitvector-model") << "Final Model:\n";
761   for (unsigned i = 0; i < variables.size(); ++i) {
762     TNode current = values[i];
763     TNode subst = Rewriter::rewrite(d_modelMap->apply(current));
764     Debug("bitvector-model") << "AlgebraicSolver:   " << variables[i] << " => " << subst << "\n";
765     // Doesn't have to be constant as it may be irrelevant
766     Assert (subst.getKind() == kind::CONST_BITVECTOR);
767     if (!model->assertEquality(variables[i], subst, true))
768     {
769       return false;
770     }
771   }
772   return true;
773  }
774 
getModelValue(TNode node)775 Node AlgebraicSolver::getModelValue(TNode node) {
776   return Node::null();
777 }
778 
Statistics()779 AlgebraicSolver::Statistics::Statistics()
780   : d_numCallstoCheck("theory::bv::algebraic::NumCallsToCheck", 0)
781   , d_numSimplifiesToTrue("theory::bv::algebraic::NumSimplifiesToTrue", 0)
782   , d_numSimplifiesToFalse("theory::bv::algebraic::NumSimplifiesToFalse", 0)
783   , d_numUnsat("theory::bv::algebraic::NumUnsat", 0)
784   , d_numSat("theory::bv::algebraic::NumSat", 0)
785   , d_numUnknown("theory::bv::algebraic::NumUnknown", 0)
786   , d_solveTime("theory::bv::algebraic::SolveTime")
787   , d_useHeuristic("theory::bv::algebraic::UseHeuristic", 0.2)
788 {
789   smtStatisticsRegistry()->registerStat(&d_numCallstoCheck);
790   smtStatisticsRegistry()->registerStat(&d_numSimplifiesToTrue);
791   smtStatisticsRegistry()->registerStat(&d_numSimplifiesToFalse);
792   smtStatisticsRegistry()->registerStat(&d_numUnsat);
793   smtStatisticsRegistry()->registerStat(&d_numSat);
794   smtStatisticsRegistry()->registerStat(&d_numUnknown);
795   smtStatisticsRegistry()->registerStat(&d_solveTime);
796   smtStatisticsRegistry()->registerStat(&d_useHeuristic);
797 }
798 
~Statistics()799 AlgebraicSolver::Statistics::~Statistics() {
800   smtStatisticsRegistry()->unregisterStat(&d_numCallstoCheck);
801   smtStatisticsRegistry()->unregisterStat(&d_numSimplifiesToTrue);
802   smtStatisticsRegistry()->unregisterStat(&d_numSimplifiesToFalse);
803   smtStatisticsRegistry()->unregisterStat(&d_numUnsat);
804   smtStatisticsRegistry()->unregisterStat(&d_numSat);
805   smtStatisticsRegistry()->unregisterStat(&d_numUnknown);
806   smtStatisticsRegistry()->unregisterStat(&d_solveTime);
807   smtStatisticsRegistry()->unregisterStat(&d_useHeuristic);
808 }
809 
hasExpensiveBVOperatorsRec(TNode fact,TNodeSet & seen)810 bool hasExpensiveBVOperatorsRec(TNode fact, TNodeSet& seen) {
811   if (fact.getKind() == kind::BITVECTOR_MULT ||
812       fact.getKind() == kind::BITVECTOR_UDIV_TOTAL ||
813       fact.getKind() == kind::BITVECTOR_UREM_TOTAL) {
814     return true;
815   }
816 
817   if (seen.find(fact) != seen.end()) {
818     return false;
819   }
820 
821   if (fact.getNumChildren() == 0) {
822     return false;
823   }
824   for (unsigned i = 0; i < fact.getNumChildren(); ++i) {
825     bool difficult = hasExpensiveBVOperatorsRec(fact[i], seen);
826     if (difficult)
827       return true;
828   }
829   seen.insert(fact);
830   return false;
831 }
832 
hasExpensiveBVOperators(TNode fact)833 bool hasExpensiveBVOperators(TNode fact) {
834   TNodeSet seen;
835   return hasExpensiveBVOperatorsRec(fact, seen);
836 }
837 
skolemize(std::vector<WorklistElement> & facts)838 void ExtractSkolemizer::skolemize(std::vector<WorklistElement>& facts) {
839   TNodeSet seen;
840   for (unsigned i = 0; i < facts.size(); ++i) {
841     TNode current = facts[i].node;
842     collectExtracts(current, seen);
843   }
844 
845   for (VarExtractMap::iterator it = d_varToExtract.begin(); it != d_varToExtract.end(); ++it) {
846     ExtractList& el = it->second;
847     TNode var = it->first;
848     Base& base = el.base;
849 
850     unsigned bw = utils::getSize(var);
851     // compute decomposition
852     std::vector<unsigned> cuts;
853     for (unsigned i = 1; i <= bw; ++i) {
854       if (base.isCutPoint(i)) {
855         cuts.push_back(i);
856       }
857     }
858     unsigned previous = 0;
859     unsigned current = 0;
860     std::vector<Node> skolems;
861     for (unsigned i = 0; i < cuts.size(); ++i) {
862       current = cuts[i];
863       Assert (current > 0);
864       int size = current - previous;
865       Assert (size > 0);
866       Node sk = utils::mkVar(size);
867       skolems.push_back(sk);
868       previous = current;
869     }
870     if (current < bw -1) {
871       int size = bw - current;
872       Assert (size > 0);
873       Node sk = utils::mkVar(size);
874       skolems.push_back(sk);
875     }
876     NodeBuilder<> skolem_nb(kind::BITVECTOR_CONCAT);
877 
878     for (int i = skolems.size() - 1; i >= 0; --i) {
879       skolem_nb << skolems[i];
880     }
881 
882     Node skolem_concat = skolems.size() == 1 ? (Node)skolems[0] : (Node) skolem_nb;
883     Assert (utils::getSize(skolem_concat) == utils::getSize(var));
884     storeSkolem(var, skolem_concat);
885 
886     for (unsigned i = 0; i < el.extracts.size(); ++i) {
887       unsigned h = el.extracts[i].high;
888       unsigned l = el.extracts[i].low;
889       Node extract = utils::mkExtract(var, h, l);
890       Node skolem_extract = Rewriter::rewrite(utils::mkExtract(skolem_concat, h, l));
891       Assert (skolem_extract.getMetaKind() == kind::metakind::VARIABLE ||
892               skolem_extract.getKind() == kind::BITVECTOR_CONCAT);
893       storeSkolem(extract, skolem_extract);
894     }
895   }
896 
897   for (unsigned i = 0; i < facts.size(); ++i) {
898     facts[i] = WorklistElement(skolemize(facts[i].node), facts[i].id);
899   }
900 }
901 
mkSkolem(Node node)902 Node ExtractSkolemizer::mkSkolem(Node node) {
903   Assert (node.getKind() == kind::BITVECTOR_EXTRACT &&
904           node[0].getMetaKind() == kind::metakind::VARIABLE);
905   Assert (!d_skolemSubst.hasSubstitution(node));
906   return utils::mkVar(utils::getSize(node));
907 }
908 
unSkolemize(std::vector<WorklistElement> & facts)909 void ExtractSkolemizer::unSkolemize(std::vector<WorklistElement>& facts) {
910   for (unsigned i = 0; i < facts.size(); ++i) {
911     facts[i] = WorklistElement(unSkolemize(facts[i].node), facts[i].id);
912   }
913 }
914 
storeSkolem(TNode node,TNode skolem)915 void ExtractSkolemizer::storeSkolem(TNode node, TNode skolem) {
916   d_skolemSubst.addSubstitution(node, skolem);
917   d_modelMap->addSubstitution(node, skolem);
918   d_skolemSubstRev.addSubstitution(skolem, node);
919 }
920 
unSkolemize(TNode node)921 Node ExtractSkolemizer::unSkolemize(TNode node) {
922   return d_skolemSubstRev.apply(node);
923 }
924 
skolemize(TNode node)925 Node ExtractSkolemizer::skolemize(TNode node) {
926   return d_skolemSubst.apply(node);
927 }
928 
addExtract(Extract & e)929 void ExtractSkolemizer::ExtractList::addExtract(Extract& e) {
930   extracts.push_back(e);
931   base.sliceAt(e.low);
932   base.sliceAt(e.high+1);
933 }
934 
storeExtract(TNode var,unsigned high,unsigned low)935 void ExtractSkolemizer::storeExtract(TNode var, unsigned high, unsigned low) {
936   Assert (var.getMetaKind() == kind::metakind::VARIABLE);
937   if (d_varToExtract.find(var) == d_varToExtract.end()) {
938     d_varToExtract[var] = ExtractList(utils::getSize(var));
939   }
940   VarExtractMap::iterator it = d_varToExtract.find(var);
941   ExtractList& el = it->second;
942   Extract e(high, low);
943   el.addExtract(e);
944 }
945 
collectExtracts(TNode node,TNodeSet & seen)946 void ExtractSkolemizer::collectExtracts(TNode node, TNodeSet& seen) {
947   if (seen.find(node) != seen.end()) {
948     return;
949   }
950 
951   if (node.getKind() == kind::BITVECTOR_EXTRACT &&
952       node[0].getMetaKind() == kind::metakind::VARIABLE) {
953     unsigned high = utils::getExtractHigh(node);
954     unsigned low = utils::getExtractLow(node);
955     TNode var = node[0];
956     storeExtract(var, high, low);
957     seen.insert(node);
958     return;
959   }
960 
961   if (node.getNumChildren() == 0)
962     return;
963 
964   for (unsigned i = 0; i < node.getNumChildren(); ++i) {
965     collectExtracts(node[i], seen);
966   }
967   seen.insert(node);
968 }
969 
ExtractSkolemizer(theory::SubstitutionMap * modelMap)970 ExtractSkolemizer::ExtractSkolemizer(theory::SubstitutionMap* modelMap)
971   : d_emptyContext()
972   , d_varToExtract()
973   , d_modelMap(modelMap)
974   , d_skolemSubst(&d_emptyContext)
975   , d_skolemSubstRev(&d_emptyContext)
976 {}
977 
~ExtractSkolemizer()978 ExtractSkolemizer::~ExtractSkolemizer() {
979 }
980 
mergeExplanations(const std::vector<Node> & expls)981 Node mergeExplanations(const std::vector<Node>& expls) {
982   TNodeSet literals;
983   for (unsigned i = 0; i < expls.size(); ++i) {
984     TNode expl = expls[i];
985     Assert (expl.getType().isBoolean());
986     if (expl.getKind() == kind::AND) {
987       for (unsigned i = 0; i < expl.getNumChildren(); ++i) {
988         TNode child = expl[i];
989         if (child == utils::mkTrue())
990           continue;
991         literals.insert(child);
992       }
993     } else if (expl != utils::mkTrue()) {
994       literals.insert(expl);
995     }
996   }
997 
998   if (literals.size() == 0) {
999     return utils::mkTrue();
1000   }else if (literals.size() == 1) {
1001     return *literals.begin();
1002   }
1003 
1004   NodeBuilder<> nb(kind::AND);
1005 
1006   for (TNodeSet::const_iterator it = literals.begin(); it!= literals.end(); ++it) {
1007     nb << *it;
1008   }
1009   return nb;
1010 }
1011 
mergeExplanations(TNode expl1,TNode expl2)1012 Node mergeExplanations(TNode expl1, TNode expl2) {
1013   std::vector<Node> expls;
1014   expls.push_back(expl1);
1015   expls.push_back(expl2);
1016   return mergeExplanations(expls);
1017 }
1018 
1019 } /* namespace CVC4::theory::bv */
1020 } /* namespace CVc4::theory */
1021 } /* namespace CVC4 */
1022