1 /********************* */
2 /*! \file theory_bv.cpp
3 ** \verbatim
4 ** Top contributors (to current version):
5 ** Liana Hadarean, Andrew Reynolds, Aina Niemetz
6 ** This file is part of the CVC4 project.
7 ** Copyright (c) 2009-2019 by the authors listed in the file AUTHORS
8 ** in the top-level source directory) and their institutional affiliations.
9 ** All rights reserved. See the file COPYING in the top-level source
10 ** directory for licensing information.\endverbatim
11 **
12 ** [[ Add lengthier description here ]]
13 ** \todo document this file
14 **/
15
16 #include "theory/bv/theory_bv.h"
17
18 #include "expr/node_algorithm.h"
19 #include "options/bv_options.h"
20 #include "options/smt_options.h"
21 #include "proof/proof_manager.h"
22 #include "proof/theory_proof.h"
23 #include "smt/smt_statistics_registry.h"
24 #include "theory/bv/abstraction.h"
25 #include "theory/bv/bv_eager_solver.h"
26 #include "theory/bv/bv_subtheory_algebraic.h"
27 #include "theory/bv/bv_subtheory_bitblast.h"
28 #include "theory/bv/bv_subtheory_core.h"
29 #include "theory/bv/bv_subtheory_inequality.h"
30 #include "theory/bv/slicer.h"
31 #include "theory/bv/theory_bv_rewrite_rules_normalization.h"
32 #include "theory/bv/theory_bv_rewrite_rules_simplification.h"
33 #include "theory/bv/theory_bv_rewriter.h"
34 #include "theory/bv/theory_bv_utils.h"
35 #include "theory/ext_theory.h"
36 #include "theory/theory_model.h"
37 #include "theory/valuation.h"
38
39 using namespace CVC4::context;
40 using namespace CVC4::theory::bv::utils;
41 using namespace std;
42
43 namespace CVC4 {
44 namespace theory {
45 namespace bv {
46
TheoryBV(context::Context * c,context::UserContext * u,OutputChannel & out,Valuation valuation,const LogicInfo & logicInfo,std::string name)47 TheoryBV::TheoryBV(context::Context* c,
48 context::UserContext* u,
49 OutputChannel& out,
50 Valuation valuation,
51 const LogicInfo& logicInfo,
52 std::string name)
53 : Theory(THEORY_BV, c, u, out, valuation, logicInfo, name),
54 d_context(c),
55 d_alreadyPropagatedSet(c),
56 d_sharedTermsSet(c),
57 d_subtheories(),
58 d_subtheoryMap(),
59 d_statistics(),
60 d_staticLearnCache(),
61 d_BVDivByZero(),
62 d_BVRemByZero(),
63 d_lemmasAdded(c, false),
64 d_conflict(c, false),
65 d_invalidateModelCache(c, true),
66 d_literalsToPropagate(c),
67 d_literalsToPropagateIndex(c, 0),
68 d_propagatedBy(c),
69 d_eagerSolver(),
70 d_abstractionModule(new AbstractionModule(getStatsPrefix(THEORY_BV))),
71 d_isCoreTheory(false),
72 d_calledPreregister(false),
73 d_needsLastCallCheck(false),
74 d_extf_range_infer(u),
75 d_extf_collapse_infer(u)
76 {
77 setupExtTheory();
78 getExtTheory()->addFunctionKind(kind::BITVECTOR_TO_NAT);
79 getExtTheory()->addFunctionKind(kind::INT_TO_BITVECTOR);
80 if (options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER) {
81 d_eagerSolver.reset(new EagerBitblastSolver(c, this));
82 return;
83 }
84
85 if (options::bitvectorEqualitySolver() && !options::proof())
86 {
87 d_subtheories.emplace_back(new CoreSolver(c, this));
88 d_subtheoryMap[SUB_CORE] = d_subtheories.back().get();
89 }
90
91 if (options::bitvectorInequalitySolver() && !options::proof())
92 {
93 d_subtheories.emplace_back(new InequalitySolver(c, u, this));
94 d_subtheoryMap[SUB_INEQUALITY] = d_subtheories.back().get();
95 }
96
97 if (options::bitvectorAlgebraicSolver() && !options::proof())
98 {
99 d_subtheories.emplace_back(new AlgebraicSolver(c, this));
100 d_subtheoryMap[SUB_ALGEBRAIC] = d_subtheories.back().get();
101 }
102
103 BitblastSolver* bb_solver = new BitblastSolver(c, this);
104 if (options::bvAbstraction())
105 {
106 bb_solver->setAbstraction(d_abstractionModule.get());
107 }
108 d_subtheories.emplace_back(bb_solver);
109 d_subtheoryMap[SUB_BITBLAST] = bb_solver;
110 }
111
~TheoryBV()112 TheoryBV::~TheoryBV() {}
113
setMasterEqualityEngine(eq::EqualityEngine * eq)114 void TheoryBV::setMasterEqualityEngine(eq::EqualityEngine* eq) {
115 if (options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER) {
116 return;
117 }
118 if (options::bitvectorEqualitySolver()) {
119 dynamic_cast<CoreSolver*>(d_subtheoryMap[SUB_CORE])->setMasterEqualityEngine(eq);
120 }
121 }
122
spendResource(unsigned amount)123 void TheoryBV::spendResource(unsigned amount)
124 {
125 getOutputChannel().spendResource(amount);
126 }
127
Statistics()128 TheoryBV::Statistics::Statistics():
129 d_avgConflictSize("theory::bv::AvgBVConflictSize"),
130 d_solveSubstitutions("theory::bv::NumSolveSubstitutions", 0),
131 d_solveTimer("theory::bv::solveTimer"),
132 d_numCallsToCheckFullEffort("theory::bv::NumFullCheckCalls", 0),
133 d_numCallsToCheckStandardEffort("theory::bv::NumStandardCheckCalls", 0),
134 d_weightComputationTimer("theory::bv::weightComputationTimer"),
135 d_numMultSlice("theory::bv::NumMultSliceApplied", 0)
136 {
137 smtStatisticsRegistry()->registerStat(&d_avgConflictSize);
138 smtStatisticsRegistry()->registerStat(&d_solveSubstitutions);
139 smtStatisticsRegistry()->registerStat(&d_solveTimer);
140 smtStatisticsRegistry()->registerStat(&d_numCallsToCheckFullEffort);
141 smtStatisticsRegistry()->registerStat(&d_numCallsToCheckStandardEffort);
142 smtStatisticsRegistry()->registerStat(&d_weightComputationTimer);
143 smtStatisticsRegistry()->registerStat(&d_numMultSlice);
144 }
145
~Statistics()146 TheoryBV::Statistics::~Statistics() {
147 smtStatisticsRegistry()->unregisterStat(&d_avgConflictSize);
148 smtStatisticsRegistry()->unregisterStat(&d_solveSubstitutions);
149 smtStatisticsRegistry()->unregisterStat(&d_solveTimer);
150 smtStatisticsRegistry()->unregisterStat(&d_numCallsToCheckFullEffort);
151 smtStatisticsRegistry()->unregisterStat(&d_numCallsToCheckStandardEffort);
152 smtStatisticsRegistry()->unregisterStat(&d_weightComputationTimer);
153 smtStatisticsRegistry()->unregisterStat(&d_numMultSlice);
154 }
155
getBVDivByZero(Kind k,unsigned width)156 Node TheoryBV::getBVDivByZero(Kind k, unsigned width) {
157 NodeManager* nm = NodeManager::currentNM();
158 if (k == kind::BITVECTOR_UDIV) {
159 if (d_BVDivByZero.find(width) == d_BVDivByZero.end()) {
160 // lazily create the function symbols
161 ostringstream os;
162 os << "BVUDivByZero_" << width;
163 Node divByZero = nm->mkSkolem(os.str(),
164 nm->mkFunctionType(nm->mkBitVectorType(width), nm->mkBitVectorType(width)),
165 "partial bvudiv", NodeManager::SKOLEM_EXACT_NAME);
166 d_BVDivByZero[width] = divByZero;
167 }
168 return d_BVDivByZero[width];
169 }
170 else if (k == kind::BITVECTOR_UREM) {
171 if (d_BVRemByZero.find(width) == d_BVRemByZero.end()) {
172 ostringstream os;
173 os << "BVURemByZero_" << width;
174 Node divByZero = nm->mkSkolem(os.str(),
175 nm->mkFunctionType(nm->mkBitVectorType(width), nm->mkBitVectorType(width)),
176 "partial bvurem", NodeManager::SKOLEM_EXACT_NAME);
177 d_BVRemByZero[width] = divByZero;
178 }
179 return d_BVRemByZero[width];
180 }
181
182 Unreachable();
183 }
184
finishInit()185 void TheoryBV::finishInit()
186 {
187 // these kinds are semi-evaluated in getModelValue (applications of this
188 // kind are treated as variables)
189 TheoryModel* tm = d_valuation.getModel();
190 Assert(tm != nullptr);
191 tm->setSemiEvaluatedKind(kind::BITVECTOR_ACKERMANNIZE_UDIV);
192 tm->setSemiEvaluatedKind(kind::BITVECTOR_ACKERMANNIZE_UREM);
193 }
194
expandDefinition(LogicRequest & logicRequest,Node node)195 Node TheoryBV::expandDefinition(LogicRequest &logicRequest, Node node) {
196 Debug("bitvector-expandDefinition") << "TheoryBV::expandDefinition(" << node << ")" << std::endl;
197
198 switch (node.getKind()) {
199 case kind::BITVECTOR_SDIV:
200 case kind::BITVECTOR_SREM:
201 case kind::BITVECTOR_SMOD:
202 return TheoryBVRewriter::eliminateBVSDiv(node);
203 break;
204
205 case kind::BITVECTOR_UDIV:
206 case kind::BITVECTOR_UREM: {
207 NodeManager* nm = NodeManager::currentNM();
208 unsigned width = node.getType().getBitVectorSize();
209
210 if (options::bitvectorDivByZeroConst()) {
211 Kind kind = node.getKind() == kind::BITVECTOR_UDIV ? kind::BITVECTOR_UDIV_TOTAL : kind::BITVECTOR_UREM_TOTAL;
212 return nm->mkNode(kind, node[0], node[1]);
213 }
214
215 TNode num = node[0], den = node[1];
216 Node den_eq_0 = nm->mkNode(kind::EQUAL, den, utils::mkZero(width));
217 Node divTotalNumDen = nm->mkNode(node.getKind() == kind::BITVECTOR_UDIV ? kind::BITVECTOR_UDIV_TOTAL :
218 kind::BITVECTOR_UREM_TOTAL, num, den);
219 Node divByZero = getBVDivByZero(node.getKind(), width);
220 Node divByZeroNum = nm->mkNode(kind::APPLY_UF, divByZero, num);
221 node = nm->mkNode(kind::ITE, den_eq_0, divByZeroNum, divTotalNumDen);
222 logicRequest.widenLogic(THEORY_UF);
223 return node;
224 }
225 break;
226
227 default:
228 return node;
229 break;
230 }
231
232 Unreachable();
233 }
234
235
preRegisterTerm(TNode node)236 void TheoryBV::preRegisterTerm(TNode node) {
237 d_calledPreregister = true;
238 Debug("bitvector-preregister") << "TheoryBV::preRegister(" << node << ")" << std::endl;
239
240 if (options::bitblastMode() == BITBLAST_MODE_EAGER)
241 {
242 // the aig bit-blaster option is set heuristically
243 // if bv abstraction is used
244 if (!d_eagerSolver->isInitialized())
245 {
246 d_eagerSolver->initialize();
247 }
248
249 if (node.getKind() == kind::BITVECTOR_EAGER_ATOM)
250 {
251 Node formula = node[0];
252 d_eagerSolver->assertFormula(formula);
253 }
254 return;
255 }
256
257 for (unsigned i = 0; i < d_subtheories.size(); ++i) {
258 d_subtheories[i]->preRegister(node);
259 }
260
261 // AJR : equality solver currently registers all terms to ExtTheory, if we want a lazy reduction without the bv equality solver, need to call this
262 //getExtTheory()->registerTermRec( node );
263 }
264
sendConflict()265 void TheoryBV::sendConflict() {
266 Assert(d_conflict);
267 if (d_conflictNode.isNull()) {
268 return;
269 } else {
270 Debug("bitvector") << indent() << "TheoryBV::check(): conflict " << d_conflictNode << std::endl;
271 d_out->conflict(d_conflictNode);
272 d_statistics.d_avgConflictSize.addEntry(d_conflictNode.getNumChildren());
273 d_conflictNode = Node::null();
274 }
275 }
276
checkForLemma(TNode fact)277 void TheoryBV::checkForLemma(TNode fact)
278 {
279 if (fact.getKind() == kind::EQUAL)
280 {
281 NodeManager* nm = NodeManager::currentNM();
282 if (fact[0].getKind() == kind::BITVECTOR_UREM_TOTAL)
283 {
284 TNode urem = fact[0];
285 TNode result = fact[1];
286 TNode divisor = urem[1];
287 Node result_ult_div = nm->mkNode(kind::BITVECTOR_ULT, result, divisor);
288 Node divisor_eq_0 =
289 nm->mkNode(kind::EQUAL, divisor, mkZero(getSize(divisor)));
290 Node split = nm->mkNode(
291 kind::OR, divisor_eq_0, nm->mkNode(kind::NOT, fact), result_ult_div);
292 lemma(split);
293 }
294 if (fact[1].getKind() == kind::BITVECTOR_UREM_TOTAL)
295 {
296 TNode urem = fact[1];
297 TNode result = fact[0];
298 TNode divisor = urem[1];
299 Node result_ult_div = nm->mkNode(kind::BITVECTOR_ULT, result, divisor);
300 Node divisor_eq_0 =
301 nm->mkNode(kind::EQUAL, divisor, mkZero(getSize(divisor)));
302 Node split = nm->mkNode(
303 kind::OR, divisor_eq_0, nm->mkNode(kind::NOT, fact), result_ult_div);
304 lemma(split);
305 }
306 }
307 }
308
check(Effort e)309 void TheoryBV::check(Effort e)
310 {
311 if (done() && e<Theory::EFFORT_FULL) {
312 return;
313 }
314
315 //last call : do reductions on extended bitvector functions
316 if (e == Theory::EFFORT_LAST_CALL) {
317 std::vector<Node> nred = getExtTheory()->getActive();
318 doExtfReductions(nred);
319 return;
320 }
321
322 TimerStat::CodeTimer checkTimer(d_checkTime);
323 Debug("bitvector") << "TheoryBV::check(" << e << ")" << std::endl;
324 TimerStat::CodeTimer codeTimer(d_statistics.d_solveTimer);
325 // we may be getting new assertions so the model cache may not be sound
326 d_invalidateModelCache.set(true);
327 // if we are using the eager solver
328 if (options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER) {
329 // this can only happen on an empty benchmark
330 if (!d_eagerSolver->isInitialized()) {
331 d_eagerSolver->initialize();
332 }
333 if (!Theory::fullEffort(e))
334 return;
335
336 std::vector<TNode> assertions;
337 while (!done()) {
338 TNode fact = get().assertion;
339 Assert (fact.getKind() == kind::BITVECTOR_EAGER_ATOM);
340 assertions.push_back(fact);
341 d_eagerSolver->assertFormula(fact[0]);
342 }
343
344 bool ok = d_eagerSolver->checkSat();
345 if (!ok) {
346 if (assertions.size() == 1) {
347 d_out->conflict(assertions[0]);
348 return;
349 }
350 Node conflict = utils::mkAnd(assertions);
351 d_out->conflict(conflict);
352 return;
353 }
354 return;
355 }
356
357
358 if (Theory::fullEffort(e)) {
359 ++(d_statistics.d_numCallsToCheckFullEffort);
360 } else {
361 ++(d_statistics.d_numCallsToCheckStandardEffort);
362 }
363 // if we are already in conflict just return the conflict
364 if (inConflict()) {
365 sendConflict();
366 return;
367 }
368
369 while (!done()) {
370 TNode fact = get().assertion;
371
372 checkForLemma(fact);
373
374 for (unsigned i = 0; i < d_subtheories.size(); ++i) {
375 d_subtheories[i]->assertFact(fact);
376 }
377 }
378
379 bool ok = true;
380 bool complete = false;
381 for (unsigned i = 0; i < d_subtheories.size(); ++i) {
382 Assert (!inConflict());
383 ok = d_subtheories[i]->check(e);
384 complete = d_subtheories[i]->isComplete();
385
386 if (!ok) {
387 // if we are in a conflict no need to check with other theories
388 Assert (inConflict());
389 sendConflict();
390 return;
391 }
392 if (complete) {
393 // if the last subtheory was complete we stop
394 break;
395 }
396 }
397
398 //check extended functions
399 if (Theory::fullEffort(e)) {
400 //do inferences (adds external lemmas) TODO: this can be improved to add internal inferences
401 std::vector< Node > nred;
402 if( getExtTheory()->doInferences( 0, nred ) ){
403 return;
404 }
405 d_needsLastCallCheck = false;
406 if( !nred.empty() ){
407 //other inferences involving bv2nat, int2bv
408 if( options::bvAlgExtf() ){
409 if( doExtfInferences( nred ) ){
410 return;
411 }
412 }
413 if( !options::bvLazyReduceExtf() ){
414 if( doExtfReductions( nred ) ){
415 return;
416 }
417 }else{
418 d_needsLastCallCheck = true;
419 }
420 }
421 }
422 }
423
doExtfInferences(std::vector<Node> & terms)424 bool TheoryBV::doExtfInferences(std::vector<Node>& terms)
425 {
426 NodeManager* nm = NodeManager::currentNM();
427 bool sentLemma = false;
428 eq::EqualityEngine* ee = getEqualityEngine();
429 std::map<Node, Node> op_map;
430 for (unsigned j = 0; j < terms.size(); j++)
431 {
432 TNode n = terms[j];
433 Assert(n.getKind() == kind::BITVECTOR_TO_NAT
434 || n.getKind() == kind::INT_TO_BITVECTOR);
435 if (n.getKind() == kind::BITVECTOR_TO_NAT)
436 {
437 // range lemmas
438 if (d_extf_range_infer.find(n) == d_extf_range_infer.end())
439 {
440 d_extf_range_infer.insert(n);
441 unsigned bvs = n[0].getType().getBitVectorSize();
442 Node min = nm->mkConst(Rational(0));
443 Node max = nm->mkConst(Rational(Integer(1).multiplyByPow2(bvs)));
444 Node lem = nm->mkNode(kind::AND,
445 nm->mkNode(kind::GEQ, n, min),
446 nm->mkNode(kind::LT, n, max));
447 Trace("bv-extf-lemma")
448 << "BV extf lemma (range) : " << lem << std::endl;
449 d_out->lemma(lem);
450 sentLemma = true;
451 }
452 }
453 Node r = (ee && ee->hasTerm(n[0])) ? ee->getRepresentative(n[0]) : n[0];
454 op_map[r] = n;
455 }
456 for (unsigned j = 0; j < terms.size(); j++)
457 {
458 TNode n = terms[j];
459 Node r = (ee && ee->hasTerm(n[0])) ? ee->getRepresentative(n) : n;
460 std::map<Node, Node>::iterator it = op_map.find(r);
461 if (it != op_map.end())
462 {
463 Node parent = it->second;
464 // Node cterm = parent[0]==n ? parent : nm->mkNode( parent.getOperator(),
465 // n );
466 Node cterm = parent[0].eqNode(n);
467 Trace("bv-extf-lemma-debug")
468 << "BV extf collapse based on : " << cterm << std::endl;
469 if (d_extf_collapse_infer.find(cterm) == d_extf_collapse_infer.end())
470 {
471 d_extf_collapse_infer.insert(cterm);
472
473 Node t = n[0];
474 if (t.getType() == parent.getType())
475 {
476 if (n.getKind() == kind::INT_TO_BITVECTOR)
477 {
478 Assert(t.getType().isInteger());
479 // congruent modulo 2^( bv width )
480 unsigned bvs = n.getType().getBitVectorSize();
481 Node coeff = nm->mkConst(Rational(Integer(1).multiplyByPow2(bvs)));
482 Node k = nm->mkSkolem(
483 "int_bv_cong", t.getType(), "for int2bv/bv2nat congruence");
484 t = nm->mkNode(kind::PLUS, t, nm->mkNode(kind::MULT, coeff, k));
485 }
486 Node lem = parent.eqNode(t);
487
488 if (parent[0] != n)
489 {
490 Assert(ee->areEqual(parent[0], n));
491 lem = nm->mkNode(kind::IMPLIES, parent[0].eqNode(n), lem);
492 }
493 // this handles inferences of the form, e.g.:
494 // ((_ int2bv w) (bv2nat x)) == x (if x is bit-width w)
495 // (bv2nat ((_ int2bv w) x)) == x + k*2^w for some k
496 Trace("bv-extf-lemma")
497 << "BV extf lemma (collapse) : " << lem << std::endl;
498 d_out->lemma(lem);
499 sentLemma = true;
500 }
501 }
502 Trace("bv-extf-lemma-debug")
503 << "BV extf f collapse based on : " << cterm << std::endl;
504 }
505 }
506 return sentLemma;
507 }
508
doExtfReductions(std::vector<Node> & terms)509 bool TheoryBV::doExtfReductions( std::vector< Node >& terms ) {
510 std::vector< Node > nredr;
511 if( getExtTheory()->doReductions( 0, terms, nredr ) ){
512 return true;
513 }
514 Assert( nredr.empty() );
515 return false;
516 }
517
needsCheckLastEffort()518 bool TheoryBV::needsCheckLastEffort() {
519 return d_needsLastCallCheck;
520 }
collectModelInfo(TheoryModel * m)521 bool TheoryBV::collectModelInfo(TheoryModel* m)
522 {
523 Assert(!inConflict());
524 if (options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER) {
525 if (!d_eagerSolver->collectModelInfo(m, true))
526 {
527 return false;
528 }
529 }
530 for (unsigned i = 0; i < d_subtheories.size(); ++i) {
531 if (d_subtheories[i]->isComplete()) {
532 return d_subtheories[i]->collectModelInfo(m, true);
533 }
534 }
535 return true;
536 }
537
getModelValue(TNode var)538 Node TheoryBV::getModelValue(TNode var) {
539 Assert(!inConflict());
540 for (unsigned i = 0; i < d_subtheories.size(); ++i) {
541 if (d_subtheories[i]->isComplete()) {
542 return d_subtheories[i]->getModelValue(var);
543 }
544 }
545 Unreachable();
546 }
547
propagate(Effort e)548 void TheoryBV::propagate(Effort e) {
549 Debug("bitvector") << indent() << "TheoryBV::propagate()" << std::endl;
550 if (options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER) {
551 return;
552 }
553
554 if (inConflict()) {
555 return;
556 }
557
558 // go through stored propagations
559 bool ok = true;
560 for (; d_literalsToPropagateIndex < d_literalsToPropagate.size() && ok; d_literalsToPropagateIndex = d_literalsToPropagateIndex + 1) {
561 TNode literal = d_literalsToPropagate[d_literalsToPropagateIndex];
562 // temporary fix for incremental bit-blasting
563 if (d_valuation.isSatLiteral(literal)) {
564 Debug("bitvector::propagate") << "TheoryBV:: propagating " << literal <<"\n";
565 ok = d_out->propagate(literal);
566 }
567 }
568
569 if (!ok) {
570 Debug("bitvector::propagate") << indent() << "TheoryBV::propagate(): conflict from theory engine" << std::endl;
571 setConflict();
572 }
573 }
574
575
getEqualityEngine()576 eq::EqualityEngine * TheoryBV::getEqualityEngine() {
577 CoreSolver* core = (CoreSolver*)d_subtheoryMap[SUB_CORE];
578 if( core ){
579 return core->getEqualityEngine();
580 }else{
581 return NULL;
582 }
583 }
584
getCurrentSubstitution(int effort,std::vector<Node> & vars,std::vector<Node> & subs,std::map<Node,std::vector<Node>> & exp)585 bool TheoryBV::getCurrentSubstitution( int effort, std::vector< Node >& vars, std::vector< Node >& subs, std::map< Node, std::vector< Node > >& exp ) {
586 eq::EqualityEngine * ee = getEqualityEngine();
587 if( ee ){
588 //get the constant equivalence classes
589 bool retVal = false;
590 for( unsigned i=0; i<vars.size(); i++ ){
591 Node n = vars[i];
592 if( ee->hasTerm( n ) ){
593 Node nr = ee->getRepresentative( n );
594 if( nr.isConst() ){
595 subs.push_back( nr );
596 exp[n].push_back( n.eqNode( nr ) );
597 retVal = true;
598 }else{
599 subs.push_back( n );
600 }
601 }else{
602 subs.push_back( n );
603 }
604 }
605 //return true if the substitution is non-trivial
606 return retVal;
607 }
608 return false;
609 }
610
getReduction(int effort,Node n,Node & nr)611 int TheoryBV::getReduction(int effort, Node n, Node& nr)
612 {
613 Trace("bv-ext") << "TheoryBV::checkExt : non-reduced : " << n << std::endl;
614 NodeManager* const nm = NodeManager::currentNM();
615 if (n.getKind() == kind::BITVECTOR_TO_NAT)
616 {
617 // taken from rewrite code
618 const unsigned size = utils::getSize(n[0]);
619 const Node z = nm->mkConst(Rational(0));
620 const Node bvone = utils::mkOne(1);
621 NodeBuilder<> result(kind::PLUS);
622 Integer i = 1;
623 for (unsigned bit = 0; bit < size; ++bit, i *= 2)
624 {
625 Node cond =
626 nm->mkNode(kind::EQUAL,
627 nm->mkNode(nm->mkConst(BitVectorExtract(bit, bit)), n[0]),
628 bvone);
629 result << nm->mkNode(kind::ITE, cond, nm->mkConst(Rational(i)), z);
630 }
631 nr = Node(result);
632 return -1;
633 }
634 else if (n.getKind() == kind::INT_TO_BITVECTOR)
635 {
636 // taken from rewrite code
637 const unsigned size = n.getOperator().getConst<IntToBitVector>().size;
638 const Node bvzero = utils::mkZero(1);
639 const Node bvone = utils::mkOne(1);
640 std::vector<Node> v;
641 Integer i = 2;
642 while (v.size() < size)
643 {
644 Node cond = nm->mkNode(
645 kind::GEQ,
646 nm->mkNode(kind::INTS_MODULUS_TOTAL, n[0], nm->mkConst(Rational(i))),
647 nm->mkConst(Rational(i, 2)));
648 cond = Rewriter::rewrite(cond);
649 v.push_back(nm->mkNode(kind::ITE, cond, bvone, bvzero));
650 i *= 2;
651 }
652 NodeBuilder<> result(kind::BITVECTOR_CONCAT);
653 result.append(v.rbegin(), v.rend());
654 nr = Node(result);
655 return -1;
656 }
657 return 0;
658 }
659
ppAssert(TNode in,SubstitutionMap & outSubstitutions)660 Theory::PPAssertStatus TheoryBV::ppAssert(TNode in,
661 SubstitutionMap& outSubstitutions)
662 {
663 switch (in.getKind())
664 {
665 case kind::EQUAL:
666 {
667 if (in[0].isVar() && !expr::hasSubterm(in[1], in[0]))
668 {
669 ++(d_statistics.d_solveSubstitutions);
670 outSubstitutions.addSubstitution(in[0], in[1]);
671 return PP_ASSERT_STATUS_SOLVED;
672 }
673 if (in[1].isVar() && !expr::hasSubterm(in[0], in[1]))
674 {
675 ++(d_statistics.d_solveSubstitutions);
676 outSubstitutions.addSubstitution(in[1], in[0]);
677 return PP_ASSERT_STATUS_SOLVED;
678 }
679 Node node = Rewriter::rewrite(in);
680 if ((node[0].getKind() == kind::BITVECTOR_EXTRACT && node[1].isConst())
681 || (node[1].getKind() == kind::BITVECTOR_EXTRACT
682 && node[0].isConst()))
683 {
684 Node extract = node[0].isConst() ? node[1] : node[0];
685 if (extract[0].getKind() == kind::VARIABLE)
686 {
687 Node c = node[0].isConst() ? node[0] : node[1];
688
689 unsigned high = utils::getExtractHigh(extract);
690 unsigned low = utils::getExtractLow(extract);
691 unsigned var_bitwidth = utils::getSize(extract[0]);
692 std::vector<Node> children;
693
694 if (low == 0)
695 {
696 Assert(high != var_bitwidth - 1);
697 unsigned skolem_size = var_bitwidth - high - 1;
698 Node skolem = utils::mkVar(skolem_size);
699 children.push_back(skolem);
700 children.push_back(c);
701 }
702 else if (high == var_bitwidth - 1)
703 {
704 unsigned skolem_size = low;
705 Node skolem = utils::mkVar(skolem_size);
706 children.push_back(c);
707 children.push_back(skolem);
708 }
709 else
710 {
711 unsigned skolem1_size = low;
712 unsigned skolem2_size = var_bitwidth - high - 1;
713 Node skolem1 = utils::mkVar(skolem1_size);
714 Node skolem2 = utils::mkVar(skolem2_size);
715 children.push_back(skolem2);
716 children.push_back(c);
717 children.push_back(skolem1);
718 }
719 Node concat = utils::mkConcat(children);
720 Assert(utils::getSize(concat) == utils::getSize(extract[0]));
721 outSubstitutions.addSubstitution(extract[0], concat);
722 return PP_ASSERT_STATUS_SOLVED;
723 }
724 }
725 }
726 break;
727 case kind::BITVECTOR_ULT:
728 case kind::BITVECTOR_SLT:
729 case kind::BITVECTOR_ULE:
730 case kind::BITVECTOR_SLE:
731
732 default:
733 // TODO other predicates
734 break;
735 }
736 return PP_ASSERT_STATUS_UNSOLVED;
737 }
738
ppRewrite(TNode t)739 Node TheoryBV::ppRewrite(TNode t)
740 {
741 Debug("bv-pp-rewrite") << "TheoryBV::ppRewrite " << t << "\n";
742 Node res = t;
743 if (options::bitwiseEq() && RewriteRule<BitwiseEq>::applies(t)) {
744 Node result = RewriteRule<BitwiseEq>::run<false>(t);
745 res = Rewriter::rewrite(result);
746 } else if (d_isCoreTheory && t.getKind() == kind::EQUAL) {
747 std::vector<Node> equalities;
748 Slicer::splitEqualities(t, equalities);
749 res = utils::mkAnd(equalities);
750 } else if (RewriteRule<UltPlusOne>::applies(t)) {
751 Node result = RewriteRule<UltPlusOne>::run<false>(t);
752 res = Rewriter::rewrite(result);
753 } else if( res.getKind() == kind::EQUAL &&
754 ((res[0].getKind() == kind::BITVECTOR_PLUS &&
755 RewriteRule<ConcatToMult>::applies(res[1])) ||
756 (res[1].getKind() == kind::BITVECTOR_PLUS &&
757 RewriteRule<ConcatToMult>::applies(res[0])))) {
758 Node mult = RewriteRule<ConcatToMult>::applies(res[0])?
759 RewriteRule<ConcatToMult>::run<false>(res[0]) :
760 RewriteRule<ConcatToMult>::run<true>(res[1]);
761 Node factor = mult[0];
762 Node sum = RewriteRule<ConcatToMult>::applies(res[0])? res[1] : res[0];
763 Node new_eq = NodeManager::currentNM()->mkNode(kind::EQUAL, sum, mult);
764 Node rewr_eq = RewriteRule<SolveEq>::run<true>(new_eq);
765 if (rewr_eq[0].isVar() || rewr_eq[1].isVar()){
766 res = Rewriter::rewrite(rewr_eq);
767 } else {
768 res = t;
769 }
770 } else if (RewriteRule<SignExtendEqConst>::applies(t)) {
771 res = RewriteRule<SignExtendEqConst>::run<false>(t);
772 } else if (RewriteRule<ZeroExtendEqConst>::applies(t)) {
773 res = RewriteRule<ZeroExtendEqConst>::run<false>(t);
774 }
775 else if (RewriteRule<NormalizeEqPlusNeg>::applies(t))
776 {
777 res = RewriteRule<NormalizeEqPlusNeg>::run<false>(t);
778 }
779
780 // if(t.getKind() == kind::EQUAL &&
781 // ((t[0].getKind() == kind::BITVECTOR_MULT && t[1].getKind() ==
782 // kind::BITVECTOR_PLUS) ||
783 // (t[1].getKind() == kind::BITVECTOR_MULT && t[0].getKind() ==
784 // kind::BITVECTOR_PLUS))) {
785 // // if we have an equality between a multiplication and addition
786 // // try to express multiplication in terms of addition
787 // Node mult = t[0].getKind() == kind::BITVECTOR_MULT? t[0] : t[1];
788 // Node add = t[0].getKind() == kind::BITVECTOR_PLUS? t[0] : t[1];
789 // if (RewriteRule<MultSlice>::applies(mult)) {
790 // Node new_mult = RewriteRule<MultSlice>::run<false>(mult);
791 // Node new_eq =
792 // Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::EQUAL,
793 // new_mult, add));
794
795 // // the simplification can cause the formula to blow up
796 // // only apply if formula reduced
797 // if (d_subtheoryMap.find(SUB_BITBLAST) != d_subtheoryMap.end()) {
798 // BitblastSolver* bv = (BitblastSolver*)d_subtheoryMap[SUB_BITBLAST];
799 // uint64_t old_size = bv->computeAtomWeight(t);
800 // Assert (old_size);
801 // uint64_t new_size = bv->computeAtomWeight(new_eq);
802 // double ratio = ((double)new_size)/old_size;
803 // if (ratio <= 0.4) {
804 // ++(d_statistics.d_numMultSlice);
805 // return new_eq;
806 // }
807 // }
808
809 // if (new_eq.getKind() == kind::CONST_BOOLEAN) {
810 // ++(d_statistics.d_numMultSlice);
811 // return new_eq;
812 // }
813 // }
814 // }
815
816 if (options::bvAbstraction() && t.getType().isBoolean()) {
817 d_abstractionModule->addInputAtom(res);
818 }
819 Debug("bv-pp-rewrite") << "to " << res << "\n";
820 return res;
821 }
822
presolve()823 void TheoryBV::presolve() {
824 Debug("bitvector") << "TheoryBV::presolve" << endl;
825 }
826
827 static int prop_count = 0;
828
storePropagation(TNode literal,SubTheory subtheory)829 bool TheoryBV::storePropagation(TNode literal, SubTheory subtheory)
830 {
831 Debug("bitvector::propagate") << indent() << getSatContext()->getLevel() << " " << "TheoryBV::storePropagation(" << literal << ", " << subtheory << ")" << std::endl;
832 prop_count++;
833
834 // If already in conflict, no more propagation
835 if (d_conflict) {
836 Debug("bitvector::propagate") << indent() << "TheoryBV::storePropagation(" << literal << ", " << subtheory << "): already in conflict" << std::endl;
837 return false;
838 }
839
840 // If propagated already, just skip
841 PropagatedMap::const_iterator find = d_propagatedBy.find(literal);
842 if (find != d_propagatedBy.end()) {
843 return true;
844 } else {
845 bool polarity = literal.getKind() != kind::NOT;
846 Node negatedLiteral = polarity ? literal.notNode() : (Node) literal[0];
847 find = d_propagatedBy.find(negatedLiteral);
848 if (find != d_propagatedBy.end() && (*find).second != subtheory) {
849 // Safe to ignore this one, subtheory should produce a conflict
850 return true;
851 }
852
853 d_propagatedBy[literal] = subtheory;
854 }
855
856 // Propagate differs depending on the subtheory
857 // * bitblaster needs to be left alone until it's done, otherwise it doesn't
858 // know how to explain
859 // * equality engine can propagate eagerly
860 // TODO(2348): Determine if ok should be set by propagate. If not, remove ok.
861 constexpr bool ok = true;
862 if (subtheory == SUB_CORE) {
863 d_out->propagate(literal);
864 if (!ok) {
865 setConflict();
866 }
867 } else {
868 d_literalsToPropagate.push_back(literal);
869 }
870 return ok;
871
872 }/* TheoryBV::propagate(TNode) */
873
874
explain(TNode literal,std::vector<TNode> & assumptions)875 void TheoryBV::explain(TNode literal, std::vector<TNode>& assumptions) {
876 Assert (wasPropagatedBySubtheory(literal));
877 SubTheory sub = getPropagatingSubtheory(literal);
878 d_subtheoryMap[sub]->explain(literal, assumptions);
879 }
880
881
explain(TNode node)882 Node TheoryBV::explain(TNode node) {
883 Debug("bitvector::explain") << "TheoryBV::explain(" << node << ")" << std::endl;
884 std::vector<TNode> assumptions;
885
886 // Ask for the explanation
887 explain(node, assumptions);
888 // this means that it is something true at level 0
889 if (assumptions.size() == 0) {
890 return utils::mkTrue();
891 }
892 // return the explanation
893 Node explanation = utils::mkAnd(assumptions);
894 Debug("bitvector::explain") << "TheoryBV::explain(" << node << ") => " << explanation << std::endl;
895 Debug("bitvector::explain") << "TheoryBV::explain done. \n";
896 return explanation;
897 }
898
899
addSharedTerm(TNode t)900 void TheoryBV::addSharedTerm(TNode t) {
901 Debug("bitvector::sharing") << indent() << "TheoryBV::addSharedTerm(" << t << ")" << std::endl;
902 d_sharedTermsSet.insert(t);
903 if (options::bitvectorEqualitySolver()) {
904 for (unsigned i = 0; i < d_subtheories.size(); ++i) {
905 d_subtheories[i]->addSharedTerm(t);
906 }
907 }
908 }
909
910
getEqualityStatus(TNode a,TNode b)911 EqualityStatus TheoryBV::getEqualityStatus(TNode a, TNode b)
912 {
913 if (options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER)
914 return EQUALITY_UNKNOWN;
915 Assert (options::bitblastMode() == theory::bv::BITBLAST_MODE_LAZY);
916 for (unsigned i = 0; i < d_subtheories.size(); ++i) {
917 EqualityStatus status = d_subtheories[i]->getEqualityStatus(a, b);
918 if (status != EQUALITY_UNKNOWN) {
919 return status;
920 }
921 }
922 return EQUALITY_UNKNOWN; ;
923 }
924
925
enableCoreTheorySlicer()926 void TheoryBV::enableCoreTheorySlicer() {
927 Assert (!d_calledPreregister);
928 d_isCoreTheory = true;
929 if (d_subtheoryMap.find(SUB_CORE) != d_subtheoryMap.end()) {
930 CoreSolver* core = (CoreSolver*)d_subtheoryMap[SUB_CORE];
931 core->enableSlicer();
932 }
933 }
934
935
ppStaticLearn(TNode in,NodeBuilder<> & learned)936 void TheoryBV::ppStaticLearn(TNode in, NodeBuilder<>& learned) {
937 if(d_staticLearnCache.find(in) != d_staticLearnCache.end()){
938 return;
939 }
940 d_staticLearnCache.insert(in);
941
942 if (in.getKind() == kind::EQUAL) {
943 if((in[0].getKind() == kind::BITVECTOR_PLUS && in[1].getKind() == kind::BITVECTOR_SHL) ||
944 (in[1].getKind() == kind::BITVECTOR_PLUS && in[0].getKind() == kind::BITVECTOR_SHL)) {
945 TNode p = in[0].getKind() == kind::BITVECTOR_PLUS ? in[0] : in[1];
946 TNode s = in[0].getKind() == kind::BITVECTOR_PLUS ? in[1] : in[0];
947
948 if(p.getNumChildren() == 2
949 && p[0].getKind() == kind::BITVECTOR_SHL
950 && p[1].getKind() == kind::BITVECTOR_SHL ){
951 unsigned size = utils::getSize(s);
952 Node one = utils::mkConst(size, 1u);
953 if(s[0] == one && p[0][0] == one && p[1][0] == one){
954 Node zero = utils::mkConst(size, 0u);
955 TNode b = p[0];
956 TNode c = p[1];
957 // (s : 1 << S) = (b : 1 << B) + (c : 1 << C)
958 Node b_eq_0 = b.eqNode(zero);
959 Node c_eq_0 = c.eqNode(zero);
960 Node b_eq_c = b.eqNode(c);
961
962 Node dis = NodeManager::currentNM()->mkNode(
963 kind::OR, b_eq_0, c_eq_0, b_eq_c);
964 Node imp = in.impNode(dis);
965 learned << imp;
966 }
967 }
968 }
969 }else if(in.getKind() == kind::AND){
970 for(size_t i = 0, N = in.getNumChildren(); i < N; ++i){
971 ppStaticLearn(in[i], learned);
972 }
973 }
974 }
975
applyAbstraction(const std::vector<Node> & assertions,std::vector<Node> & new_assertions)976 bool TheoryBV::applyAbstraction(const std::vector<Node>& assertions, std::vector<Node>& new_assertions) {
977 bool changed = d_abstractionModule->applyAbstraction(assertions, new_assertions);
978 if (changed &&
979 options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER &&
980 options::bitvectorAig()) {
981 // disable AIG mode
982 AlwaysAssert (!d_eagerSolver->isInitialized());
983 d_eagerSolver->turnOffAig();
984 d_eagerSolver->initialize();
985 }
986 return changed;
987 }
988
setProofLog(proof::BitVectorProof * bvp)989 void TheoryBV::setProofLog(proof::BitVectorProof* bvp)
990 {
991 if( options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER ){
992 d_eagerSolver->setProofLog(bvp);
993 }else{
994 for( unsigned i=0; i< d_subtheories.size(); i++ ){
995 d_subtheories[i]->setProofLog( bvp );
996 }
997 }
998 }
999
setConflict(Node conflict)1000 void TheoryBV::setConflict(Node conflict)
1001 {
1002 if (options::bvAbstraction())
1003 {
1004 NodeManager* const nm = NodeManager::currentNM();
1005 Node new_conflict = d_abstractionModule->simplifyConflict(conflict);
1006
1007 std::vector<Node> lemmas;
1008 lemmas.push_back(new_conflict);
1009 d_abstractionModule->generalizeConflict(new_conflict, lemmas);
1010 for (unsigned i = 0; i < lemmas.size(); ++i)
1011 {
1012 lemma(nm->mkNode(kind::NOT, lemmas[i]));
1013 }
1014 }
1015 d_conflict = true;
1016 d_conflictNode = conflict;
1017 }
1018
1019 } /* namespace CVC4::theory::bv */
1020 } /* namespace CVC4::theory */
1021 } /* namespace CVC4 */
1022