1 /********************* */
2 /*! \file bv_subtheory_algebraic.cpp
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-2020 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
12 ** \brief Algebraic solver.
16 #include "theory/bv/bv_subtheory_algebraic.h"
18 #include <unordered_set>
20 #include "expr/node_algorithm.h"
21 #include "options/bv_options.h"
22 #include "printer/printer.h"
24 #include "smt/smt_engine.h"
25 #include "smt/smt_engine_scope.h"
26 #include "smt/smt_statistics_registry.h"
27 #include "smt_util/boolean_simplification.h"
28 #include "theory/bv/bv_quick_check.h"
29 #include "theory/bv/bv_solver_lazy.h"
30 #include "theory/bv/theory_bv_utils.h"
31 #include "theory/theory_model.h"
33 using namespace CVC4::context
;
34 using namespace CVC4::prop
;
35 using namespace CVC4::theory::bv::utils
;
42 /* ------------------------------------------------------------------------- */
46 /* Collect all variables under a given a node. */
47 void collectVariables(TNode node
, utils::NodeSet
& vars
)
49 std::vector
<TNode
> stack
;
50 std::unordered_set
<TNode
, TNodeHashFunction
> visited
;
52 stack
.push_back(node
);
53 while (!stack
.empty())
55 Node n
= stack
.back();
58 if (vars
.find(n
) != vars
.end()) continue;
59 if (visited
.find(n
) != visited
.end()) continue;
62 if (Theory::isLeafOf(n
, THEORY_BV
) && n
.getKind() != kind::CONST_BITVECTOR
)
67 stack
.insert(stack
.end(), n
.begin(), n
.end());
73 /* ------------------------------------------------------------------------- */
75 bool hasExpensiveBVOperators(TNode fact
);
76 Node
mergeExplanations(const std::vector
<Node
>& expls
);
77 Node
mergeExplanations(TNode expl1
, TNode expl2
);
80 SubstitutionEx::SubstitutionEx(theory::SubstitutionMap
* modelMap
)
83 , d_cacheInvalid(true)
84 , d_modelMap(modelMap
)
87 bool SubstitutionEx::addSubstitution(TNode from
, TNode to
, TNode reason
) {
88 Debug("bv-substitution") << "SubstitutionEx::addSubstitution: "<< from
89 <<" => "<< to
<< "\n" << " reason "<<reason
<< "\n";
91 if (d_substitutions
.find(from
) != d_substitutions
.end()) {
95 d_modelMap
->addSubstitution(from
, to
);
97 d_cacheInvalid
= true;
98 d_substitutions
[from
] = SubstitutionElement(to
, reason
);
102 Node
SubstitutionEx::apply(TNode node
) {
103 Debug("bv-substitution") << "SubstitutionEx::apply("<< node
<<")\n";
104 if (d_cacheInvalid
) {
106 d_cacheInvalid
= false;
109 SubstitutionsCache::iterator it
= d_cache
.find(node
);
111 if (it
!= d_cache
.end()) {
112 Node res
= it
->second
.to
;
113 Debug("bv-substitution") << " =>"<< res
<<"\n";
117 Node result
= internalApply(node
);
118 Debug("bv-substitution") << " =>"<< result
<<"\n";
122 Node
SubstitutionEx::internalApply(TNode node
) {
123 if (d_substitutions
.empty())
126 vector
<SubstitutionStackElement
> stack
;
127 stack
.push_back(SubstitutionStackElement(node
));
129 while (!stack
.empty()) {
130 SubstitutionStackElement head
= stack
.back();
133 TNode current
= head
.node
;
135 if (hasCache(current
)) {
139 // check if it has substitution
140 Substitutions::const_iterator it
= d_substitutions
.find(current
);
141 if (it
!= d_substitutions
.end()) {
142 vector
<Node
> reasons
;
143 TNode to
= it
->second
.to
;
144 reasons
.push_back(it
->second
.reason
);
145 // check if the thing we subsituted to has substitutions
146 TNode res
= internalApply(to
);
148 reasons
.push_back(getReason(to
));
149 Node reason
= mergeExplanations(reasons
);
150 storeCache(current
, res
, reason
);
154 // if no children then just continue
155 if(current
.getNumChildren() == 0) {
156 storeCache(current
, current
, utils::mkTrue());
160 // children already processed
161 if (head
.childrenAdded
) {
162 NodeBuilder
<> nb(current
.getKind());
163 std::vector
<Node
> reasons
;
165 if (current
.getMetaKind() == kind::metakind::PARAMETERIZED
) {
166 TNode op
= current
.getOperator();
167 Assert(hasCache(op
));
169 reasons
.push_back(getReason(op
));
171 for (unsigned i
= 0; i
< current
.getNumChildren(); ++i
) {
172 Assert(hasCache(current
[i
]));
173 nb
<< getCache(current
[i
]);
174 reasons
.push_back(getReason(current
[i
]));
177 // if the node is new apply substitutions to it
178 Node subst_result
= result
;
179 if (result
!= current
) {
180 subst_result
= result
!= current
? internalApply(result
) : result
;
181 reasons
.push_back(getReason(result
));
183 Node reason
= mergeExplanations(reasons
);
184 storeCache(current
, subst_result
, reason
);
187 // add children to stack
188 stack
.push_back(SubstitutionStackElement(current
, true));
189 if (current
.getMetaKind() == kind::metakind::PARAMETERIZED
) {
190 stack
.push_back(SubstitutionStackElement(current
.getOperator()));
192 for (unsigned i
= 0; i
< current
.getNumChildren(); ++i
) {
193 stack
.push_back(SubstitutionStackElement(current
[i
]));
198 Assert(hasCache(node
));
199 return getCache(node
);
202 Node
SubstitutionEx::explain(TNode node
) const {
203 if(!hasCache(node
)) {
204 return utils::mkTrue();
207 Debug("bv-substitution") << "SubstitutionEx::explain("<< node
<<")\n";
208 Node res
= getReason(node
);
209 Debug("bv-substitution") << " with "<< res
<<"\n";
213 Node
SubstitutionEx::getReason(TNode node
) const {
214 Assert(hasCache(node
));
215 SubstitutionsCache::const_iterator it
= d_cache
.find(node
);
216 return it
->second
.reason
;
219 bool SubstitutionEx::hasCache(TNode node
) const {
220 return d_cache
.find(node
) != d_cache
.end();
223 Node
SubstitutionEx::getCache(TNode node
) const {
224 Assert(hasCache(node
));
225 return d_cache
.find(node
)->second
.to
;
228 void SubstitutionEx::storeCache(TNode from
, TNode to
, Node reason
) {
229 // Debug("bv-substitution") << "SubstitutionEx::storeCache(" << from <<", " << to <<", "<< reason<<")\n";
230 Assert(!hasCache(from
));
231 d_cache
[from
] = SubstitutionElement(to
, reason
);
234 AlgebraicSolver::AlgebraicSolver(context::Context
* c
, BVSolverLazy
* bv
)
235 : SubtheorySolver(c
, bv
),
237 d_quickSolver(new BVQuickCheck("theory::bv::algebraic", bv
)),
238 d_isComplete(c
, false),
239 d_isDifficult(c
, false),
240 d_budget(options::bitvectorAlgebraicBudget()),
249 if (options::bitvectorQuickXplain())
252 new QuickXPlain("theory::bv::algebraic", d_quickSolver
.get()));
256 AlgebraicSolver::~AlgebraicSolver() {}
258 bool AlgebraicSolver::check(Theory::Effort e
)
260 Assert(options::bitblastMode() == options::BitblastMode::LAZY
);
262 if (!Theory::fullEffort(e
)) { return true; }
263 if (!useHeuristic()) { return true; }
265 TimerStat::CodeTimer
algebraicTimer(d_statistics
.d_solveTime
);
266 Debug("bv-subtheory-algebraic") << "AlgebraicSolver::check (" << e
<< ")\n";
268 ++(d_statistics
.d_numCallstoCheck
);
270 d_explanations
.clear();
272 d_inputAssertions
.clear();
274 std::vector
<WorklistElement
> worklist
;
276 uint64_t original_bb_cost
= 0;
278 NodeSet seen_assertions
;
279 // Processing assertions from scratch
280 for (AssertionQueue::const_iterator it
= assertionsBegin(); it
!= assertionsEnd(); ++it
) {
281 Debug("bv-subtheory-algebraic") << " " << *it
<< "\n";
282 TNode assertion
= *it
;
283 unsigned id
= worklist
.size();
284 d_ids
[assertion
] = id
;
285 worklist
.push_back(WorklistElement(assertion
, id
));
286 d_inputAssertions
.insert(assertion
);
287 storeExplanation(assertion
);
289 uint64_t assertion_size
= d_quickSolver
->computeAtomWeight(assertion
, seen_assertions
);
290 Assert(original_bb_cost
<= original_bb_cost
+ assertion_size
);
291 original_bb_cost
+= assertion_size
;
294 for (unsigned i
= 0; i
< worklist
.size(); ++i
) {
295 d_ids
[worklist
[i
].node
] = worklist
[i
].id
;
298 Debug("bv-subtheory-algebraic") << "Assertions " << worklist
.size() <<" : \n";
300 Assert(d_explanations
.size() == worklist
.size());
302 d_modelMap
.reset(new SubstitutionMap(d_context
));
303 SubstitutionEx
subst(d_modelMap
.get());
305 // first round of substitutions
306 processAssertions(worklist
, subst
);
308 if (!d_isDifficult
.get()) {
309 // skolemize all possible extracts
310 ExtractSkolemizer
skolemizer(d_modelMap
.get());
311 skolemizer
.skolemize(worklist
);
312 // second round of substitutions
313 processAssertions(worklist
, subst
);
317 uint64_t subst_bb_cost
= 0;
322 for (; r
< worklist
.size(); ++r
) {
324 TNode fact
= worklist
[r
].node
;
325 unsigned id
= worklist
[r
].id
;
327 if (fact
.isConst() &&
328 fact
.getConst
<bool>() == true) {
332 if (fact
.isConst() &&
333 fact
.getConst
<bool>() == false) {
334 // we have a conflict
335 Node conflict
= BooleanSimplification::simplify(d_explanations
[id
]);
336 d_bv
->setConflict(conflict
);
337 d_isComplete
.set(true);
338 Debug("bv-subtheory-algebraic") << " UNSAT: assertion simplfies to false with conflict: "<< conflict
<< "\n";
340 ++(d_statistics
.d_numSimplifiesToFalse
);
345 subst_bb_cost
+= d_quickSolver
->computeAtomWeight(fact
, subst_seen
);
346 worklist
[w
] = WorklistElement(fact
, id
);
347 Node expl
= BooleanSimplification::simplify(d_explanations
[id
]);
348 storeExplanation(id
, expl
);
356 if(Debug
.isOn("bv-subtheory-algebraic")) {
357 Debug("bv-subtheory-algebraic") << "Assertions post-substitutions " << worklist
.size() << ":\n";
358 for (unsigned i
= 0; i
< worklist
.size(); ++i
) {
359 Debug("bv-subtheory-algebraic") << " " << worklist
[i
].node
<< "\n";
364 // all facts solved to true
365 if (worklist
.empty()) {
366 Debug("bv-subtheory-algebraic") << " SAT: everything simplifies to true.\n";
367 ++(d_statistics
.d_numSimplifiesToTrue
);
372 double ratio
= ((double)subst_bb_cost
)/original_bb_cost
;
374 !d_isDifficult
.get()) {
375 // give up if problem not reduced enough
376 d_isComplete
.set(false);
380 d_quickSolver
->clearSolver();
382 d_quickSolver
->push();
383 std::vector
<Node
> facts
;
384 for (unsigned i
= 0; i
< worklist
.size(); ++i
) {
385 facts
.push_back(worklist
[i
].node
);
387 bool ok
= quickCheck(facts
);
389 Debug("bv-subtheory-algebraic") << "AlgebraicSolver::check done " << ok
<< ".\n";
393 bool AlgebraicSolver::quickCheck(std::vector
<Node
>& facts
) {
394 SatValue res
= d_quickSolver
->checkSat(facts
, d_budget
);
396 if (res
== SAT_VALUE_UNKNOWN
) {
397 d_isComplete
.set(false);
398 Debug("bv-subtheory-algebraic") << " Unknown.\n";
399 ++(d_statistics
.d_numUnknown
);
403 if (res
== SAT_VALUE_TRUE
) {
404 Debug("bv-subtheory-algebraic") << " Sat.\n";
405 ++(d_statistics
.d_numSat
);
407 d_isComplete
.set(true);
411 Assert(res
== SAT_VALUE_FALSE
);
412 Assert(d_quickSolver
->inConflict());
413 d_isComplete
.set(true);
414 Debug("bv-subtheory-algebraic") << " Unsat.\n";
416 ++(d_statistics
.d_numUnsat
);
419 Node conflict
= d_quickSolver
->getConflict();
420 Debug("bv-subtheory-algebraic") << " Conflict: " << conflict
<< "\n";
422 // singleton conflict
423 if (conflict
.getKind() != kind::AND
) {
424 Assert(d_ids
.find(conflict
) != d_ids
.end());
425 unsigned id
= d_ids
[conflict
];
426 Assert(id
< d_explanations
.size());
427 Node theory_confl
= d_explanations
[id
];
428 d_bv
->setConflict(theory_confl
);
432 Assert(conflict
.getKind() == kind::AND
);
433 if (options::bitvectorQuickXplain()) {
434 d_quickSolver
->popToZero();
435 Debug("bv-quick-xplain") << "AlgebraicSolver::quickCheck original conflict size " << conflict
.getNumChildren() << "\n";
436 conflict
= d_quickXplain
->minimizeConflict(conflict
);
437 Debug("bv-quick-xplain") << "AlgebraicSolver::quickCheck minimized conflict size " << conflict
.getNumChildren() << "\n";
440 vector
<TNode
> theory_confl
;
441 for (unsigned i
= 0; i
< conflict
.getNumChildren(); ++i
) {
442 TNode c
= conflict
[i
];
444 Assert(d_ids
.find(c
) != d_ids
.end());
445 unsigned c_id
= d_ids
[c
];
446 Assert(c_id
< d_explanations
.size());
447 TNode c_expl
= d_explanations
[c_id
];
448 theory_confl
.push_back(c_expl
);
451 Node confl
= BooleanSimplification::simplify(utils::mkAnd(theory_confl
));
453 Debug("bv-subtheory-algebraic") << " Out Conflict: " << confl
<< "\n";
458 void AlgebraicSolver::setConflict(TNode conflict
)
460 Node final_conflict
= conflict
;
461 if (options::bitvectorQuickXplain() &&
462 conflict
.getKind() == kind::AND
&&
463 conflict
.getNumChildren() > 4) {
464 final_conflict
= d_quickXplain
->minimizeConflict(conflict
);
466 d_bv
->setConflict(final_conflict
);
469 bool AlgebraicSolver::solve(TNode fact
, TNode reason
, SubstitutionEx
& subst
) {
470 if (fact
.getKind() != kind::EQUAL
) return false;
472 NodeManager
* nm
= NodeManager::currentNM();
473 TNode left
= fact
[0];
474 TNode right
= fact
[1];
476 if (left
.isVar() && !expr::hasSubterm(right
, left
))
478 bool changed
= subst
.addSubstitution(left
, right
, reason
);
481 if (right
.isVar() && !expr::hasSubterm(left
, right
))
483 bool changed
= subst
.addSubstitution(right
, left
, reason
);
487 // xor simplification
488 if (right
.getKind() == kind::BITVECTOR_XOR
&&
489 left
.getKind() == kind::BITVECTOR_XOR
) {
491 if (var
.getMetaKind() != kind::metakind::VARIABLE
)
494 // simplify xor with same variable on both sides
495 if (expr::hasSubterm(right
, var
))
497 std::vector
<Node
> right_children
;
498 for (unsigned i
= 0; i
< right
.getNumChildren(); ++i
) {
500 right_children
.push_back(right
[i
]);
502 Assert(right_children
.size());
503 Node new_right
= utils::mkNaryNode(kind::BITVECTOR_XOR
, right_children
);
504 std::vector
<Node
> left_children
;
505 for (unsigned i
= 1; i
< left
.getNumChildren(); ++i
) {
506 left_children
.push_back(left
[i
]);
508 Node new_left
= utils::mkNaryNode(kind::BITVECTOR_XOR
, left_children
);
509 Node new_fact
= nm
->mkNode(kind::EQUAL
, new_left
, new_right
);
510 bool changed
= subst
.addSubstitution(fact
, new_fact
, reason
);
514 NodeBuilder
<> nb(kind::BITVECTOR_XOR
);
515 for (unsigned i
= 1; i
< left
.getNumChildren(); ++i
) {
518 Node inverse
= left
.getNumChildren() == 2? (Node
)left
[1] : (Node
)nb
;
519 Node new_right
= nm
->mkNode(kind::BITVECTOR_XOR
, right
, inverse
);
520 bool changed
= subst
.addSubstitution(var
, new_right
, reason
);
525 // (a xor t = a) <=> (t = 0)
526 if (left
.getKind() == kind::BITVECTOR_XOR
527 && right
.getMetaKind() == kind::metakind::VARIABLE
528 && expr::hasSubterm(left
, right
))
531 Node new_left
= nm
->mkNode(kind::BITVECTOR_XOR
, var
, left
);
532 Node zero
= utils::mkConst(utils::getSize(var
), 0u);
533 Node new_fact
= nm
->mkNode(kind::EQUAL
, zero
, new_left
);
534 bool changed
= subst
.addSubstitution(fact
, new_fact
, reason
);
538 if (right
.getKind() == kind::BITVECTOR_XOR
539 && left
.getMetaKind() == kind::metakind::VARIABLE
540 && expr::hasSubterm(right
, left
))
543 Node new_right
= nm
->mkNode(kind::BITVECTOR_XOR
, var
, right
);
544 Node zero
= utils::mkConst(utils::getSize(var
), 0u);
545 Node new_fact
= nm
->mkNode(kind::EQUAL
, zero
, new_right
);
546 bool changed
= subst
.addSubstitution(fact
, new_fact
, reason
);
550 // (a xor b = 0) <=> (a = b)
551 if (left
.getKind() == kind::BITVECTOR_XOR
&&
552 left
.getNumChildren() == 2 &&
553 right
.getKind() == kind::CONST_BITVECTOR
&&
554 right
.getConst
<BitVector
>() == BitVector(utils::getSize(left
), 0u)) {
555 Node new_fact
= nm
->mkNode(kind::EQUAL
, left
[0], left
[1]);
556 bool changed
= subst
.addSubstitution(fact
, new_fact
, reason
);
564 bool AlgebraicSolver::isSubstitutableIn(TNode node
, TNode in
)
566 if (node
.getMetaKind() == kind::metakind::VARIABLE
567 && !expr::hasSubterm(in
, node
))
572 void AlgebraicSolver::processAssertions(std::vector
<WorklistElement
>& worklist
, SubstitutionEx
& subst
) {
573 NodeManager
* nm
= NodeManager::currentNM();
576 // d_bv->spendResource();
578 for (unsigned i
= 0; i
< worklist
.size(); ++i
) {
579 // apply current substitutions
580 Node current
= subst
.apply(worklist
[i
].node
);
581 unsigned current_id
= worklist
[i
].id
;
582 Node subst_expl
= subst
.explain(worklist
[i
].node
);
583 worklist
[i
] = WorklistElement(Rewriter::rewrite(current
), current_id
);
584 // explanation for this assertion
585 Node old_expl
= d_explanations
[current_id
];
586 Node new_expl
= mergeExplanations(subst_expl
, old_expl
);
587 storeExplanation(current_id
, new_expl
);
589 // use the new substitution to solve
590 if(solve(worklist
[i
].node
, new_expl
, subst
)) {
595 // check for concat slicings
596 for (unsigned i
= 0; i
< worklist
.size(); ++i
) {
597 TNode fact
= worklist
[i
].node
;
598 unsigned current_id
= worklist
[i
].id
;
600 if (fact
.getKind() != kind::EQUAL
) {
604 TNode left
= fact
[0];
605 TNode right
= fact
[1];
606 if (left
.getKind() != kind::BITVECTOR_CONCAT
||
607 right
.getKind() != kind::BITVECTOR_CONCAT
||
608 left
.getNumChildren() != right
.getNumChildren()) {
612 bool can_slice
= true;
613 for (unsigned j
= 0; j
< left
.getNumChildren(); ++j
) {
614 if (utils::getSize(left
[j
]) != utils::getSize(right
[j
]))
622 for (unsigned j
= 0; j
< left
.getNumChildren(); ++j
) {
623 Node eq_j
= nm
->mkNode(kind::EQUAL
, left
[j
], right
[j
]);
624 unsigned id
= d_explanations
.size();
625 TNode expl
= d_explanations
[current_id
];
626 storeExplanation(expl
);
627 worklist
.push_back(WorklistElement(eq_j
, id
));
630 worklist
[i
] = WorklistElement(utils::mkTrue(), worklist
[i
].id
);
633 Assert(d_explanations
.size() == worklist
.size());
637 void AlgebraicSolver::storeExplanation(unsigned id
, TNode explanation
) {
638 Assert(checkExplanation(explanation
));
639 d_explanations
[id
] = explanation
;
642 void AlgebraicSolver::storeExplanation(TNode explanation
) {
643 Assert(checkExplanation(explanation
));
644 d_explanations
.push_back(explanation
);
647 bool AlgebraicSolver::checkExplanation(TNode explanation
) {
648 Node simplified_explanation
= explanation
; //BooleanSimplification::simplify(explanation);
649 if (simplified_explanation
.getKind() != kind::AND
) {
650 return d_inputAssertions
.find(simplified_explanation
) != d_inputAssertions
.end();
652 for (unsigned i
= 0; i
< simplified_explanation
.getNumChildren(); ++i
) {
653 if (d_inputAssertions
.find(simplified_explanation
[i
]) == d_inputAssertions
.end()) {
661 bool AlgebraicSolver::isComplete() {
662 return d_isComplete
.get();
665 bool AlgebraicSolver::useHeuristic() {
669 double success_rate
= double(d_numSolved
)/double(d_numCalls
);
670 d_statistics
.d_useHeuristic
.setData(success_rate
);
671 return success_rate
> 0.8;
675 void AlgebraicSolver::assertFact(TNode fact
) {
676 d_assertionQueue
.push_back(fact
);
677 d_isComplete
.set(false);
678 if (!d_isDifficult
.get()) {
679 d_isDifficult
.set(hasExpensiveBVOperators(fact
));
683 EqualityStatus
AlgebraicSolver::getEqualityStatus(TNode a
, TNode b
) {
684 return EQUALITY_UNKNOWN
;
687 bool AlgebraicSolver::collectModelValues(TheoryModel
* model
,
688 const std::set
<Node
>& termSet
)
690 Debug("bitvector-model") << "AlgebraicSolver::collectModelValues\n";
691 AlwaysAssert(!d_quickSolver
->inConflict());
693 // collect relevant terms that the bv theory abstracts to variables
694 // (variables and parametric terms such as select apply_uf)
695 std::vector
<TNode
> variables
;
696 std::vector
<Node
> values
;
697 for (set
<Node
>::const_iterator it
= termSet
.begin(); it
!= termSet
.end(); ++it
) {
699 if (term
.getType().isBitVector() &&
700 (term
.getMetaKind() == kind::metakind::VARIABLE
||
701 Theory::theoryOf(term
) != THEORY_BV
)) {
702 variables
.push_back(term
);
703 values
.push_back(term
);
708 Debug("bitvector-model") << "Substitutions:\n";
709 for (unsigned i
= 0; i
< variables
.size(); ++i
) {
710 TNode current
= variables
[i
];
711 TNode subst
= Rewriter::rewrite(d_modelMap
->apply(current
));
712 Debug("bitvector-model") << " " << current
<< " => " << subst
<< "\n";
714 collectVariables(subst
, leaf_vars
);
717 Debug("bitvector-model") << "Model:\n";
719 for (NodeSet::const_iterator it
= leaf_vars
.begin(); it
!= leaf_vars
.end(); ++it
) {
721 Node value
= d_quickSolver
->getVarValue(var
, true);
722 Assert(!value
.isNull());
724 // may be a shared term that did not appear in the current assertions
725 // AJR: need to check whether already in map for cases where collectModelInfo is called multiple times in the same context
726 if (!value
.isNull() && !d_modelMap
->hasSubstitution(var
)) {
727 Debug("bitvector-model") << " " << var
<< " => " << value
<< "\n";
728 Assert(value
.getKind() == kind::CONST_BITVECTOR
);
729 d_modelMap
->addSubstitution(var
, value
);
733 Debug("bitvector-model") << "Final Model:\n";
734 for (unsigned i
= 0; i
< variables
.size(); ++i
) {
735 TNode current
= values
[i
];
736 TNode subst
= Rewriter::rewrite(d_modelMap
->apply(current
));
737 Debug("bitvector-model") << "AlgebraicSolver: " << variables
[i
] << " => " << subst
<< "\n";
738 // Doesn't have to be constant as it may be irrelevant
739 Assert(subst
.getKind() == kind::CONST_BITVECTOR
);
740 if (!model
->assertEquality(variables
[i
], subst
, true))
748 Node
AlgebraicSolver::getModelValue(TNode node
) {
752 AlgebraicSolver::Statistics::Statistics()
753 : d_numCallstoCheck("theory::bv::algebraic::NumCallsToCheck", 0)
754 , d_numSimplifiesToTrue("theory::bv::algebraic::NumSimplifiesToTrue", 0)
755 , d_numSimplifiesToFalse("theory::bv::algebraic::NumSimplifiesToFalse", 0)
756 , d_numUnsat("theory::bv::algebraic::NumUnsat", 0)
757 , d_numSat("theory::bv::algebraic::NumSat", 0)
758 , d_numUnknown("theory::bv::algebraic::NumUnknown", 0)
759 , d_solveTime("theory::bv::algebraic::SolveTime")
760 , d_useHeuristic("theory::bv::algebraic::UseHeuristic", 0.2)
762 smtStatisticsRegistry()->registerStat(&d_numCallstoCheck
);
763 smtStatisticsRegistry()->registerStat(&d_numSimplifiesToTrue
);
764 smtStatisticsRegistry()->registerStat(&d_numSimplifiesToFalse
);
765 smtStatisticsRegistry()->registerStat(&d_numUnsat
);
766 smtStatisticsRegistry()->registerStat(&d_numSat
);
767 smtStatisticsRegistry()->registerStat(&d_numUnknown
);
768 smtStatisticsRegistry()->registerStat(&d_solveTime
);
769 smtStatisticsRegistry()->registerStat(&d_useHeuristic
);
772 AlgebraicSolver::Statistics::~Statistics() {
773 smtStatisticsRegistry()->unregisterStat(&d_numCallstoCheck
);
774 smtStatisticsRegistry()->unregisterStat(&d_numSimplifiesToTrue
);
775 smtStatisticsRegistry()->unregisterStat(&d_numSimplifiesToFalse
);
776 smtStatisticsRegistry()->unregisterStat(&d_numUnsat
);
777 smtStatisticsRegistry()->unregisterStat(&d_numSat
);
778 smtStatisticsRegistry()->unregisterStat(&d_numUnknown
);
779 smtStatisticsRegistry()->unregisterStat(&d_solveTime
);
780 smtStatisticsRegistry()->unregisterStat(&d_useHeuristic
);
783 bool hasExpensiveBVOperatorsRec(TNode fact
, TNodeSet
& seen
) {
784 if (fact
.getKind() == kind::BITVECTOR_MULT
||
785 fact
.getKind() == kind::BITVECTOR_UDIV_TOTAL
||
786 fact
.getKind() == kind::BITVECTOR_UREM_TOTAL
) {
790 if (seen
.find(fact
) != seen
.end()) {
794 if (fact
.getNumChildren() == 0) {
797 for (unsigned i
= 0; i
< fact
.getNumChildren(); ++i
) {
798 bool difficult
= hasExpensiveBVOperatorsRec(fact
[i
], seen
);
806 bool hasExpensiveBVOperators(TNode fact
) {
808 return hasExpensiveBVOperatorsRec(fact
, seen
);
811 void ExtractSkolemizer::skolemize(std::vector
<WorklistElement
>& facts
) {
813 for (unsigned i
= 0; i
< facts
.size(); ++i
) {
814 TNode current
= facts
[i
].node
;
815 collectExtracts(current
, seen
);
818 for (VarExtractMap::iterator it
= d_varToExtract
.begin(); it
!= d_varToExtract
.end(); ++it
) {
819 ExtractList
& el
= it
->second
;
820 TNode var
= it
->first
;
821 Base
& base
= el
.base
;
823 unsigned bw
= utils::getSize(var
);
824 // compute decomposition
825 std::vector
<unsigned> cuts
;
826 for (unsigned i
= 1; i
<= bw
; ++i
) {
827 if (base
.isCutPoint(i
)) {
831 unsigned previous
= 0;
832 unsigned current
= 0;
833 std::vector
<Node
> skolems
;
834 for (unsigned i
= 0; i
< cuts
.size(); ++i
) {
837 int size
= current
- previous
;
839 Node sk
= utils::mkVar(size
);
840 skolems
.push_back(sk
);
843 if (current
< bw
-1) {
844 int size
= bw
- current
;
846 Node sk
= utils::mkVar(size
);
847 skolems
.push_back(sk
);
849 NodeBuilder
<> skolem_nb(kind::BITVECTOR_CONCAT
);
851 for (int i
= skolems
.size() - 1; i
>= 0; --i
) {
852 skolem_nb
<< skolems
[i
];
855 Node skolem_concat
= skolems
.size() == 1 ? (Node
)skolems
[0] : (Node
) skolem_nb
;
856 Assert(utils::getSize(skolem_concat
) == utils::getSize(var
));
857 storeSkolem(var
, skolem_concat
);
859 for (unsigned i
= 0; i
< el
.extracts
.size(); ++i
) {
860 unsigned h
= el
.extracts
[i
].high
;
861 unsigned l
= el
.extracts
[i
].low
;
862 Node extract
= utils::mkExtract(var
, h
, l
);
863 Node skolem_extract
= Rewriter::rewrite(utils::mkExtract(skolem_concat
, h
, l
));
864 Assert(skolem_extract
.getMetaKind() == kind::metakind::VARIABLE
865 || skolem_extract
.getKind() == kind::BITVECTOR_CONCAT
);
866 storeSkolem(extract
, skolem_extract
);
870 for (unsigned i
= 0; i
< facts
.size(); ++i
) {
871 facts
[i
] = WorklistElement(skolemize(facts
[i
].node
), facts
[i
].id
);
875 Node
ExtractSkolemizer::mkSkolem(Node node
) {
876 Assert(node
.getKind() == kind::BITVECTOR_EXTRACT
877 && node
[0].getMetaKind() == kind::metakind::VARIABLE
);
878 Assert(!d_skolemSubst
.hasSubstitution(node
));
879 return utils::mkVar(utils::getSize(node
));
882 void ExtractSkolemizer::unSkolemize(std::vector
<WorklistElement
>& facts
) {
883 for (unsigned i
= 0; i
< facts
.size(); ++i
) {
884 facts
[i
] = WorklistElement(unSkolemize(facts
[i
].node
), facts
[i
].id
);
888 void ExtractSkolemizer::storeSkolem(TNode node
, TNode skolem
) {
889 d_skolemSubst
.addSubstitution(node
, skolem
);
890 d_modelMap
->addSubstitution(node
, skolem
);
891 d_skolemSubstRev
.addSubstitution(skolem
, node
);
894 Node
ExtractSkolemizer::unSkolemize(TNode node
) {
895 return d_skolemSubstRev
.apply(node
);
898 Node
ExtractSkolemizer::skolemize(TNode node
) {
899 return d_skolemSubst
.apply(node
);
902 void ExtractSkolemizer::ExtractList::addExtract(Extract
& e
) {
903 extracts
.push_back(e
);
905 base
.sliceAt(e
.high
+1);
908 void ExtractSkolemizer::storeExtract(TNode var
, unsigned high
, unsigned low
) {
909 Assert(var
.getMetaKind() == kind::metakind::VARIABLE
);
910 if (d_varToExtract
.find(var
) == d_varToExtract
.end()) {
911 d_varToExtract
[var
] = ExtractList(utils::getSize(var
));
913 VarExtractMap::iterator it
= d_varToExtract
.find(var
);
914 ExtractList
& el
= it
->second
;
915 Extract
e(high
, low
);
919 void ExtractSkolemizer::collectExtracts(TNode node
, TNodeSet
& seen
) {
920 if (seen
.find(node
) != seen
.end()) {
924 if (node
.getKind() == kind::BITVECTOR_EXTRACT
&&
925 node
[0].getMetaKind() == kind::metakind::VARIABLE
) {
926 unsigned high
= utils::getExtractHigh(node
);
927 unsigned low
= utils::getExtractLow(node
);
929 storeExtract(var
, high
, low
);
934 if (node
.getNumChildren() == 0)
937 for (unsigned i
= 0; i
< node
.getNumChildren(); ++i
) {
938 collectExtracts(node
[i
], seen
);
943 ExtractSkolemizer::ExtractSkolemizer(theory::SubstitutionMap
* modelMap
)
946 , d_modelMap(modelMap
)
947 , d_skolemSubst(&d_emptyContext
)
948 , d_skolemSubstRev(&d_emptyContext
)
951 ExtractSkolemizer::~ExtractSkolemizer() {
954 Node
mergeExplanations(const std::vector
<Node
>& expls
) {
956 for (unsigned i
= 0; i
< expls
.size(); ++i
) {
957 TNode expl
= expls
[i
];
958 Assert(expl
.getType().isBoolean());
959 if (expl
.getKind() == kind::AND
) {
960 for (const TNode
& child
: expl
)
962 if (child
== utils::mkTrue()) continue;
963 literals
.insert(child
);
965 } else if (expl
!= utils::mkTrue()) {
966 literals
.insert(expl
);
970 if (literals
.size() == 0) {
971 return utils::mkTrue();
972 }else if (literals
.size() == 1) {
973 return *literals
.begin();
976 NodeBuilder
<> nb(kind::AND
);
978 for (TNodeSet::const_iterator it
= literals
.begin(); it
!= literals
.end(); ++it
) {
984 Node
mergeExplanations(TNode expl1
, TNode expl2
) {
985 std::vector
<Node
> expls
;
986 expls
.push_back(expl1
);
987 expls
.push_back(expl2
);
988 return mergeExplanations(expls
);
991 } /* namespace CVC4::theory::bv */
992 } /* namespace CVc4::theory */
993 } /* namespace CVC4 */