/********************* */ /*! \file bitblaster.h ** \verbatim ** Top contributors (to current version): ** Liana Hadarean, Mathias Preiner, Alex Ozdemir ** This file is part of the CVC4 project. ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS ** in the top-level source directory) and their institutional affiliations. ** All rights reserved. See the file COPYING in the top-level source ** directory for licensing information.\endverbatim ** ** \brief Wrapper around the SAT solver used for bitblasting ** ** Wrapper around the SAT solver used for bitblasting. **/ #include "cvc4_private.h" #ifndef CVC4__THEORY__BV__BITBLAST__BITBLASTER_H #define CVC4__THEORY__BV__BITBLAST__BITBLASTER_H #include #include #include #include "expr/node.h" #include "proof/bitvector_proof.h" #include "prop/bv_sat_solver_notify.h" #include "prop/sat_solver_types.h" #include "theory/bv/bitblast/bitblast_strategies_template.h" #include "theory/theory_registrar.h" #include "theory/valuation.h" #include "util/resource_manager.h" namespace CVC4 { namespace theory { namespace bv { typedef std::unordered_set NodeSet; typedef std::unordered_set TNodeSet; /** * The Bitblaster that manages the mapping between Nodes * and their bitwise definition * */ template class TBitblaster { protected: typedef std::vector Bits; typedef std::unordered_map TermDefMap; typedef std::unordered_set TNodeSet; typedef std::unordered_map ModelCache; typedef void (*TermBBStrategy)(TNode, Bits&, TBitblaster*); typedef T (*AtomBBStrategy)(TNode, TBitblaster*); // caches and mappings TermDefMap d_termCache; ModelCache d_modelCache; // sat solver used for bitblasting and associated CnfStream std::unique_ptr d_nullContext; std::unique_ptr d_cnfStream; proof::BitVectorProof* d_bvp; void initAtomBBStrategies(); void initTermBBStrategies(); protected: /// function tables for the various bitblasting strategies indexed by node /// kind TermBBStrategy d_termBBStrategies[kind::LAST_KIND]; AtomBBStrategy d_atomBBStrategies[kind::LAST_KIND]; virtual Node getModelFromSatSolver(TNode node, bool fullModel) = 0; virtual prop::SatSolver* getSatSolver() = 0; public: TBitblaster(); virtual ~TBitblaster() {} virtual void bbAtom(TNode node) = 0; virtual void bbTerm(TNode node, Bits& bits) = 0; virtual void makeVariable(TNode node, Bits& bits) = 0; virtual T getBBAtom(TNode atom) const = 0; virtual bool hasBBAtom(TNode atom) const = 0; virtual void storeBBAtom(TNode atom, T atom_bb) = 0; bool hasBBTerm(TNode node) const; void getBBTerm(TNode node, Bits& bits) const; virtual void storeBBTerm(TNode term, const Bits& bits); virtual void setProofLog(proof::BitVectorProof* bvp); /** * Return a constant representing the value of a in the model. * If fullModel is true set unconstrained bits to 0. If not return * NullNode() for a fully or partially unconstrained. * */ Node getTermModel(TNode node, bool fullModel); void invalidateModelCache(); }; class MinisatEmptyNotify : public prop::BVSatSolverNotify { public: MinisatEmptyNotify() {} bool notify(prop::SatLiteral lit) override { return true; } void notify(prop::SatClause& clause) override {} void spendResource(ResourceManager::Resource r) override { NodeManager::currentResourceManager()->spendResource(r); } void safePoint(ResourceManager::Resource r) override {} }; // Bitblaster implementation template void TBitblaster::initAtomBBStrategies() { for (int i = 0; i < kind::LAST_KIND; ++i) { d_atomBBStrategies[i] = UndefinedAtomBBStrategy; } /// setting default bb strategies for atoms d_atomBBStrategies[kind::EQUAL] = DefaultEqBB; d_atomBBStrategies[kind::BITVECTOR_ULT] = DefaultUltBB; d_atomBBStrategies[kind::BITVECTOR_ULE] = DefaultUleBB; d_atomBBStrategies[kind::BITVECTOR_UGT] = DefaultUgtBB; d_atomBBStrategies[kind::BITVECTOR_UGE] = DefaultUgeBB; d_atomBBStrategies[kind::BITVECTOR_SLT] = DefaultSltBB; d_atomBBStrategies[kind::BITVECTOR_SLE] = DefaultSleBB; d_atomBBStrategies[kind::BITVECTOR_SGT] = DefaultSgtBB; d_atomBBStrategies[kind::BITVECTOR_SGE] = DefaultSgeBB; } template void TBitblaster::initTermBBStrategies() { for (int i = 0; i < kind::LAST_KIND; ++i) { d_termBBStrategies[i] = DefaultVarBB; } /// setting default bb strategies for terms: d_termBBStrategies[kind::CONST_BITVECTOR] = DefaultConstBB; d_termBBStrategies[kind::BITVECTOR_NOT] = DefaultNotBB; d_termBBStrategies[kind::BITVECTOR_CONCAT] = DefaultConcatBB; d_termBBStrategies[kind::BITVECTOR_AND] = DefaultAndBB; d_termBBStrategies[kind::BITVECTOR_OR] = DefaultOrBB; d_termBBStrategies[kind::BITVECTOR_XOR] = DefaultXorBB; d_termBBStrategies[kind::BITVECTOR_XNOR] = DefaultXnorBB; d_termBBStrategies[kind::BITVECTOR_NAND] = DefaultNandBB; d_termBBStrategies[kind::BITVECTOR_NOR] = DefaultNorBB; d_termBBStrategies[kind::BITVECTOR_COMP] = DefaultCompBB; d_termBBStrategies[kind::BITVECTOR_MULT] = DefaultMultBB; d_termBBStrategies[kind::BITVECTOR_PLUS] = DefaultPlusBB; d_termBBStrategies[kind::BITVECTOR_SUB] = DefaultSubBB; d_termBBStrategies[kind::BITVECTOR_NEG] = DefaultNegBB; d_termBBStrategies[kind::BITVECTOR_UDIV] = UndefinedTermBBStrategy; d_termBBStrategies[kind::BITVECTOR_UREM] = UndefinedTermBBStrategy; d_termBBStrategies[kind::BITVECTOR_UDIV_TOTAL] = DefaultUdivBB; d_termBBStrategies[kind::BITVECTOR_UREM_TOTAL] = DefaultUremBB; d_termBBStrategies[kind::BITVECTOR_SDIV] = UndefinedTermBBStrategy; d_termBBStrategies[kind::BITVECTOR_SREM] = UndefinedTermBBStrategy; d_termBBStrategies[kind::BITVECTOR_SMOD] = UndefinedTermBBStrategy; d_termBBStrategies[kind::BITVECTOR_SHL] = DefaultShlBB; d_termBBStrategies[kind::BITVECTOR_LSHR] = DefaultLshrBB; d_termBBStrategies[kind::BITVECTOR_ASHR] = DefaultAshrBB; d_termBBStrategies[kind::BITVECTOR_ULTBV] = DefaultUltbvBB; d_termBBStrategies[kind::BITVECTOR_SLTBV] = DefaultSltbvBB; d_termBBStrategies[kind::BITVECTOR_ITE] = DefaultIteBB; d_termBBStrategies[kind::BITVECTOR_EXTRACT] = DefaultExtractBB; d_termBBStrategies[kind::BITVECTOR_REPEAT] = DefaultRepeatBB; d_termBBStrategies[kind::BITVECTOR_ZERO_EXTEND] = DefaultZeroExtendBB; d_termBBStrategies[kind::BITVECTOR_SIGN_EXTEND] = DefaultSignExtendBB; d_termBBStrategies[kind::BITVECTOR_ROTATE_RIGHT] = DefaultRotateRightBB; d_termBBStrategies[kind::BITVECTOR_ROTATE_LEFT] = DefaultRotateLeftBB; } template TBitblaster::TBitblaster() : d_termCache(), d_modelCache(), d_nullContext(new context::Context()), d_cnfStream(), d_bvp(nullptr) { initAtomBBStrategies(); initTermBBStrategies(); } template bool TBitblaster::hasBBTerm(TNode node) const { return d_termCache.find(node) != d_termCache.end(); } template void TBitblaster::getBBTerm(TNode node, Bits& bits) const { Assert(hasBBTerm(node)); bits = d_termCache.find(node)->second; } template void TBitblaster::storeBBTerm(TNode node, const Bits& bits) { d_termCache.insert(std::make_pair(node, bits)); } template void TBitblaster::invalidateModelCache() { d_modelCache.clear(); } template void TBitblaster::setProofLog(proof::BitVectorProof* bvp) { if (THEORY_PROOF_ON()) { d_bvp = bvp; prop::SatSolver* satSolver = getSatSolver(); bvp->attachToSatSolver(*satSolver); prop::SatVariable t = satSolver->trueVar(); prop::SatVariable f = satSolver->falseVar(); bvp->initCnfProof(d_cnfStream.get(), d_nullContext.get(), t, f); } } template Node TBitblaster::getTermModel(TNode node, bool fullModel) { if (d_modelCache.find(node) != d_modelCache.end()) return d_modelCache[node]; if (node.isConst()) return node; Node value = getModelFromSatSolver(node, false); if (!value.isNull()) { Debug("bv-equality-status") << "TLazyBitblaster::getTermModel from SatSolver" << node << " => " << value << "\n"; d_modelCache[node] = value; Assert(value.isConst()); return value; } if (Theory::isLeafOf(node, theory::THEORY_BV)) { // if it is a leaf may ask for fullModel value = getModelFromSatSolver(node, true); Debug("bv-equality-status") << "TLazyBitblaster::getTermModel from VarValue" << node << " => " << value << "\n"; Assert((fullModel && !value.isNull() && value.isConst()) || !fullModel); if (!value.isNull()) { d_modelCache[node] = value; } return value; } Assert(node.getType().isBitVector()); NodeBuilder<> nb(node.getKind()); if (node.getMetaKind() == kind::metakind::PARAMETERIZED) { nb << node.getOperator(); } for (unsigned i = 0; i < node.getNumChildren(); ++i) { nb << getTermModel(node[i], fullModel); } value = nb; value = Rewriter::rewrite(value); Assert(value.isConst()); d_modelCache[node] = value; Debug("bv-term-model") << "TLazyBitblaster::getTermModel Building Value" << node << " => " << value << "\n"; return value; } } // namespace bv } // namespace theory } // namespace CVC4 #endif /* CVC4__THEORY__BV__BITBLAST__BITBLASTER_H */