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