Theory BV now sets up the default equality engine for BV solvers that do not use their own equality engine like e.g. the BV bitblast solver. This commit also adds the missing equality engine pieces to the BV bitblast solver (getEqualityStatus, explain).
lemmab << d_cnf->getNode(clause[i]);
}
Node lemma = lemmab;
- d_bv->d_inferManager.lemma(lemma, InferenceId::UNKNOWN);
+ d_bv->d_im.lemma(lemma, InferenceId::UNKNOWN);
} else {
- d_bv->d_inferManager.lemma(d_cnf->getNode(clause[0]), InferenceId::UNKNOWN);
+ d_bv->d_im.lemma(d_cnf->getNode(clause[0]), InferenceId::UNKNOWN);
}
}
void TLazyBitblaster::MinisatNotify::safePoint(ResourceManager::Resource r)
{
- d_bv->d_inferManager.safePoint(r);
+ d_bv->d_im.safePoint(r);
}
EqualityStatus TLazyBitblaster::getEqualityStatus(TNode a, TNode b)
{
public:
BVSolver(TheoryState& state, TheoryInferenceManager& inferMgr)
- : d_state(state), d_inferManager(inferMgr){};
+ : d_state(state), d_im(inferMgr){};
virtual ~BVSolver(){};
protected:
TheoryState& d_state;
- TheoryInferenceManager& d_inferManager;
+ TheoryInferenceManager& d_im;
};
} // namespace bv
d_nullRegistrar(new prop::NullRegistrar()),
d_nullContext(new context::Context()),
d_facts(s->getSatContext()),
+ d_invalidateModelCache(s->getSatContext(), true),
+ d_inSatMode(s->getSatContext(), false),
d_epg(pnm ? new EagerProofGenerator(pnm, s->getUserContext(), "")
: nullptr)
{
node_map.emplace(lit, fact);
}
+ d_invalidateModelCache.set(true);
prop::SatValue val = d_satSolver->solve(assumptions);
+ d_inSatMode = val == prop::SatValue::SAT_VALUE_TRUE;
+ Debug("bv-bitblast") << "d_inSatMode: " << d_inSatMode << std::endl;
if (val == prop::SatValue::SAT_VALUE_FALSE)
{
}
NodeManager* nm = NodeManager::currentNM();
- d_inferManager.conflict(nm->mkAnd(conflict), InferenceId::UNKNOWN);
+ d_im.conflict(nm->mkAnd(conflict), InferenceId::UNKNOWN);
}
}
return false; // Return false to enable equality engine reasoning in Theory.
}
+TrustNode BVSolverBitblast::explain(TNode n)
+{
+ Debug("bv-bitblast") << "explain called on " << n << std::endl;
+ return d_im.explainLit(n);
+}
+
bool BVSolverBitblast::collectModelValues(TheoryModel* m,
const std::set<Node>& termSet)
{
continue;
}
- Node value = getValueFromSatSolver(term);
+ Node value = getValueFromSatSolver(term, true);
Assert(value.isConst());
if (!m->assertEquality(term, value, true))
{
return true;
}
-Node BVSolverBitblast::getValueFromSatSolver(TNode node)
+EqualityStatus BVSolverBitblast::getEqualityStatus(TNode a, TNode b)
+{
+ Debug("bv-bitblast") << "getEqualityStatus on " << a << " and " << b
+ << std::endl;
+ if (!d_inSatMode)
+ {
+ Debug("bv-bitblast") << EQUALITY_UNKNOWN << std::endl;
+ return EQUALITY_UNKNOWN;
+ }
+ Node value_a = getValue(a);
+ Node value_b = getValue(b);
+
+ if (value_a == value_b)
+ {
+ Debug("bv-bitblast") << EQUALITY_TRUE_IN_MODEL << std::endl;
+ return EQUALITY_TRUE_IN_MODEL;
+ }
+ Debug("bv-bitblast") << EQUALITY_FALSE_IN_MODEL << std::endl;
+ return EQUALITY_FALSE_IN_MODEL;
+}
+
+Node BVSolverBitblast::getValueFromSatSolver(TNode node, bool initialize)
{
- /* If node was not bit-blasted return zero-initialized bit-vector. */
+ if (node.isConst())
+ {
+ return node;
+ }
+
if (!d_bitblaster->hasBBTerm(node))
{
- return utils::mkConst(utils::getSize(node), 0u);
+ return initialize ? utils::mkConst(utils::getSize(node), 0u) : Node();
}
std::vector<Node> bits;
}
else
{
+ if (!initialize) return Node();
bit = zero;
}
value = value * 2 + bit;
return utils::mkConst(bits.size(), value);
}
+Node BVSolverBitblast::getValue(TNode node)
+{
+ if (d_invalidateModelCache.get())
+ {
+ d_modelCache.clear();
+ }
+ d_invalidateModelCache.set(false);
+
+ std::vector<TNode> visit;
+
+ TNode cur;
+ visit.push_back(node);
+ do
+ {
+ cur = visit.back();
+ visit.pop_back();
+
+ auto it = d_modelCache.find(cur);
+ if (it != d_modelCache.end() && !it->second.isNull())
+ {
+ continue;
+ }
+
+ if (d_bitblaster->hasBBTerm(cur))
+ {
+ Node value = getValueFromSatSolver(cur, false);
+ if (value.isConst())
+ {
+ d_modelCache[cur] = value;
+ continue;
+ }
+ }
+ if (Theory::isLeafOf(cur, theory::THEORY_BV))
+ {
+ Node value = getValueFromSatSolver(cur, true);
+ d_modelCache[cur] = value;
+ continue;
+ }
+
+ if (it == d_modelCache.end())
+ {
+ visit.push_back(cur);
+ d_modelCache.emplace(cur, Node());
+ visit.insert(visit.end(), cur.begin(), cur.end());
+ }
+ else if (it->second.isNull())
+ {
+ NodeBuilder<> nb(cur.getKind());
+ if (cur.getMetaKind() == kind::metakind::PARAMETERIZED)
+ {
+ nb << cur.getOperator();
+ }
+
+ std::unordered_map<Node, Node, NodeHashFunction>::iterator iit;
+ for (const TNode& child : cur)
+ {
+ iit = d_modelCache.find(child);
+ Assert(iit != d_modelCache.end());
+ Assert(iit->second.isConst());
+ nb << iit->second;
+ }
+ it->second = Rewriter::rewrite(nb.constructNode());
+ }
+ } while (!visit.empty());
+
+ auto it = d_modelCache.find(node);
+ Assert(it != d_modelCache.end());
+ return it->second;
+}
+
} // namespace bv
} // namespace theory
} // namespace CVC4
bool isPrereg,
bool isInternal) override;
+ TrustNode explain(TNode n) override;
+
std::string identify() const override { return "BVSolverBitblast"; };
Theory::PPAssertStatus ppAssert(
return Theory::PPAssertStatus::PP_ASSERT_STATUS_UNSOLVED;
}
+ EqualityStatus getEqualityStatus(TNode a, TNode b) override;
+
bool collectModelValues(TheoryModel* m,
const std::set<Node>& termSet) override;
private:
- /** Get value of `node` from SAT solver. */
- Node getValueFromSatSolver(TNode node);
+ /**
+ * Get value of `node` from SAT solver.
+ *
+ * The `initialize` flag indicates whether bits should be zero-initialized
+ * if they were not bit-blasted yet.
+ */
+ Node getValueFromSatSolver(TNode node, bool initialize);
+
+ /**
+ * Get the current value of `node`.
+ *
+ * Computes the value if `node` was not yet bit-blasted.
+ */
+ Node getValue(TNode node);
+
+ /**
+ * Cache for getValue() calls.
+ *
+ * Is cleared at the beginning of a getValue() call if the
+ * `d_invalidateModelCache` flag is set to true.
+ */
+ std::unordered_map<Node, Node, NodeHashFunction> d_modelCache;
/** Bit-blaster used to bit-blast atoms/terms. */
std::unique_ptr<BBSimple> d_bitblaster;
- /** Used for initializing CnfStream> */
+ /** Used for initializing `d_cnfStream`. */
std::unique_ptr<prop::NullRegistrar> d_nullRegistrar;
std::unique_ptr<context::Context> d_nullContext;
/** Facts sent to this solver. */
context::CDList<Node> d_facts;
+ /** Flag indicating whether `d_modelCache` should be invalidated. */
+ context::CDO<bool> d_invalidateModelCache;
+
+ /** Indicates whether the last check() call was satisfiable. */
+ context::CDO<bool> d_inSatMode;
+
/** Proof generator that manages proofs for lemmas generated by this class. */
std::unique_ptr<EagerProofGenerator> d_epg;
context::UserContext* u,
ProofNodeManager* pnm,
std::string name)
- : BVSolver(bv.d_state, bv.d_inferMgr),
+ : BVSolver(bv.d_state, bv.d_im),
d_bv(bv),
d_context(c),
d_alreadyPropagatedSet(c),
void BVSolverLazy::spendResource(ResourceManager::Resource r)
{
- d_inferManager.spendResource(r);
+ d_im.spendResource(r);
}
BVSolverLazy::Statistics::Statistics()
{
Debug("bitvector") << indent() << "BVSolverLazy::check(): conflict "
<< d_conflictNode << std::endl;
- d_inferManager.conflict(d_conflictNode, InferenceId::UNKNOWN);
+ d_im.conflict(d_conflictNode, InferenceId::UNKNOWN);
d_statistics.d_avgConflictSize.addEntry(d_conflictNode.getNumChildren());
d_conflictNode = Node::null();
}
{
if (assertions.size() == 1)
{
- d_inferManager.conflict(assertions[0], InferenceId::UNKNOWN);
+ d_im.conflict(assertions[0], InferenceId::UNKNOWN);
return;
}
Node conflict = utils::mkAnd(assertions);
- d_inferManager.conflict(conflict, InferenceId::UNKNOWN);
+ d_im.conflict(conflict, InferenceId::UNKNOWN);
return;
}
return;
{
Debug("bitvector::propagate")
<< "BVSolverLazy:: propagating " << literal << "\n";
- ok = d_inferManager.propagateLit(literal);
+ ok = d_im.propagateLit(literal);
}
}
constexpr bool ok = true;
if (subtheory == SUB_CORE)
{
- d_inferManager.propagateLit(literal);
+ d_im.propagateLit(literal);
if (!ok)
{
setConflict();
void lemma(TNode node)
{
- d_inferManager.lemma(node, InferenceId::UNKNOWN);
+ d_im.lemma(node, InferenceId::UNKNOWN);
d_lemmasAdded = true;
}
if (d_epg == nullptr)
{
- d_inferManager.lemma(lemma, InferenceId::UNKNOWN);
+ d_im.lemma(lemma, InferenceId::UNKNOWN);
}
else
{
TrustNode tlem = d_epg->mkTrustNode(lemma, PfRule::BV_BITBLAST, {}, {fact});
- d_inferManager.trustedLemma(tlem, InferenceId::UNKNOWN);
+ d_im.trustedLemma(tlem, InferenceId::UNKNOWN);
}
}
if (d_epg == nullptr)
{
- d_inferManager.lemma(lemma, InferenceId::UNKNOWN);
+ d_im.lemma(lemma, InferenceId::UNKNOWN);
}
else
{
TrustNode tlem =
d_epg->mkTrustNode(lemma, PfRule::BV_EAGER_ATOM, {}, {fact});
- d_inferManager.trustedLemma(tlem, InferenceId::UNKNOWN);
+ d_im.trustedLemma(tlem, InferenceId::UNKNOWN);
}
std::unordered_set<Node, NodeHashFunction> bv_atoms;
bool CoreSolver::check(Theory::Effort e) {
Trace("bitvector::core") << "CoreSolver::check \n";
- d_bv->d_inferManager.spendResource(
- ResourceManager::Resource::TheoryCheckStep);
+ d_bv->d_im.spendResource(ResourceManager::Resource::TheoryCheckStep);
d_checkCalled = true;
Assert(!d_bv->inConflict());
nm->mkNode(kind::LT, n, max));
Trace("bv-extf-lemma")
<< "BV extf lemma (range) : " << lem << std::endl;
- d_bv->d_inferManager.lemma(lem, InferenceId::UNKNOWN);
+ d_bv->d_im.lemma(lem, InferenceId::UNKNOWN);
sentLemma = true;
}
}
// (bv2nat ((_ int2bv w) x)) == x + k*2^w for some k
Trace("bv-extf-lemma")
<< "BV extf lemma (collapse) : " << lem << std::endl;
- d_bv->d_inferManager.lemma(lem, InferenceId::UNKNOWN);
+ d_bv->d_im.lemma(lem, InferenceId::UNKNOWN);
sentLemma = true;
}
}
d_ufRemByZero(),
d_rewriter(),
d_state(c, u, valuation),
- d_inferMgr(*this, d_state, nullptr)
+ d_im(*this, d_state, nullptr),
+ d_notify(d_im)
{
switch (options::bvSolver())
{
case options::BVSolver::BITBLAST:
- d_internal.reset(new BVSolverBitblast(&d_state, d_inferMgr, pnm));
+ d_internal.reset(new BVSolverBitblast(&d_state, d_im, pnm));
break;
case options::BVSolver::LAZY:
default:
AlwaysAssert(options::bvSolver() == options::BVSolver::SIMPLE);
- d_internal.reset(new BVSolverSimple(&d_state, d_inferMgr, pnm));
+ d_internal.reset(new BVSolverSimple(&d_state, d_im, pnm));
}
d_theoryState = &d_state;
- d_inferManager = &d_inferMgr;
+ d_inferManager = &d_im;
}
TheoryBV::~TheoryBV() {}
bool TheoryBV::needsEqualityEngine(EeSetupInfo& esi)
{
- return d_internal->needsEqualityEngine(esi);
+ bool need_ee = d_internal->needsEqualityEngine(esi);
+
+ /* Set up default notify class for equality engine. */
+ if (need_ee && esi.d_notify == nullptr)
+ {
+ esi.d_notify = &d_notify;
+ esi.d_name = "theory::bv::ee";
+ }
+
+ return need_ee;
}
void TheoryBV::finishInit()
void TheoryBV::preRegisterTerm(TNode node)
{
d_internal->preRegisterTerm(node);
+
+ eq::EqualityEngine* ee = getEqualityEngine();
+ if (ee)
+ {
+ if (node.getKind() == kind::EQUAL)
+ {
+ ee->addTriggerPredicate(node);
+ }
+ else
+ {
+ ee->addTerm(node);
+ }
+ }
}
bool TheoryBV::preCheck(Effort e) { return d_internal->preCheck(e); }
#include "theory/bv/theory_bv_rewriter.h"
#include "theory/theory.h"
+#include "theory/theory_eq_notify.h"
namespace CVC4 {
namespace theory {
TheoryState d_state;
/** A (default) theory inference manager. */
- TheoryInferenceManager d_inferMgr;
+ TheoryInferenceManager d_im;
+
+ /** The notify class for equality engine. */
+ TheoryEqNotifyClass d_notify;
}; /* class TheoryBV */