This commit moves and refactors the ppRewrite() and ppStaticLearn() code from the layered solver to TheoryBV in order to apply a default set of preprocessing rules for each solver. BV solver can still implement additional rules.
Note: Some of the rewrite rules in ppRewrite() have been removed since cluster runs showed that they don't improve anything, but actually makes the solver a lot worse.
default = "false"
help = "assert input assertions on user-level 0 instead of assuming them in the bit-vector SAT solver"
+
+[[option]]
+ name = "rwExtendEq"
+ category = "expert"
+ long = "bv-rw-extend-eq"
+ type = "bool"
+ default = "false"
+ help = "enable additional rewrites over zero/sign extend over equalities with constants (useful on BV/2017-Preiner-scholl-smt08)"
if (t.getNumChildren() != 2) return false;
TNode a = t[0];
TNode b = t[1];
- unsigned size = bv::utils::getSize(t);
- if (size < 2) return false;
+ if (bv::utils::getSize(t) < 2) return false;
Node diff =
rewrite(NodeManager::currentNM()->mkNode(kind::BITVECTOR_SUB, a, b));
return (diff.isConst()
- && (diff == bv::utils::mkConst(size, 1u)
- || diff == bv::utils::mkOnes(size)));
+ && (bv::utils::isOne(diff) || bv::utils::isOnes(diff)));
}
Node BvIntroPow2::rewritePowerOfTwo(TNode node)
TNode term = bv::utils::isZero(node[0]) ? node[1] : node[0];
TNode a = term[0];
TNode b = term[1];
- unsigned size = bv::utils::getSize(term);
+ uint32_t size = bv::utils::getSize(term);
Node diff = rewrite(nm->mkNode(kind::BITVECTOR_SUB, a, b));
Assert(diff.isConst());
- TNode x = diff == bv::utils::mkConst(size, 1u) ? a : b;
- Node one = bv::utils::mkConst(size, 1u);
+ Node one = bv::utils::mkOne(size);
+ TNode x = diff == one ? a : b;
Node sk = bv::utils::mkVar(size);
Node sh = nm->mkNode(kind::BITVECTOR_SHL, one, sk);
Node x_eq_sh = nm->mkNode(kind::EQUAL, x, sh);
* Only to be called on top level assertions.
*/
Node rewritePowerOfTwo(TNode node);
- /** Does the traversal of assertions and applies rweritePowerOfTwo. */
+ /** Does the traversal of assertions and applies rewritePowerOfTwo. */
Node pow2Rewrite(Node node, std::unordered_map<Node, Node>& cache);
};
d_subtheories(),
d_subtheoryMap(),
d_statistics(),
- d_staticLearnCache(),
d_lemmasAdded(c, false),
d_conflict(c, false),
d_invalidateModelCache(c, true),
}
}
-TrustNode BVSolverLayered::ppRewrite(TNode t)
-{
- Debug("bv-pp-rewrite") << "BVSolverLayered::ppRewrite " << t << "\n";
- Node res = t;
- if (options().bv.bitwiseEq && RewriteRule<BitwiseEq>::applies(t))
- {
- Node result = RewriteRule<BitwiseEq>::run<false>(t);
- res = rewrite(result);
- }
- else if (RewriteRule<UltAddOne>::applies(t))
- {
- Node result = RewriteRule<UltAddOne>::run<false>(t);
- res = rewrite(result);
- }
- else if (res.getKind() == kind::EQUAL
- && ((res[0].getKind() == kind::BITVECTOR_ADD
- && RewriteRule<ConcatToMult>::applies(res[1]))
- || (res[1].getKind() == kind::BITVECTOR_ADD
- && RewriteRule<ConcatToMult>::applies(res[0]))))
- {
- Node mult = RewriteRule<ConcatToMult>::applies(res[0])
- ? RewriteRule<ConcatToMult>::run<false>(res[0])
- : RewriteRule<ConcatToMult>::run<true>(res[1]);
- Node factor = mult[0];
- Node sum = RewriteRule<ConcatToMult>::applies(res[0]) ? res[1] : res[0];
- Node new_eq = NodeManager::currentNM()->mkNode(kind::EQUAL, sum, mult);
- Node rewr_eq = RewriteRule<SolveEq>::run<true>(new_eq);
- if (rewr_eq[0].isVar() || rewr_eq[1].isVar())
- {
- res = rewrite(rewr_eq);
- }
- else
- {
- res = t;
- }
- }
- else if (RewriteRule<SignExtendEqConst>::applies(t))
- {
- res = RewriteRule<SignExtendEqConst>::run<false>(t);
- }
- else if (RewriteRule<ZeroExtendEqConst>::applies(t))
- {
- res = RewriteRule<ZeroExtendEqConst>::run<false>(t);
- }
- else if (RewriteRule<NormalizeEqAddNeg>::applies(t))
- {
- res = RewriteRule<NormalizeEqAddNeg>::run<false>(t);
- }
-
- // if(t.getKind() == kind::EQUAL &&
- // ((t[0].getKind() == kind::BITVECTOR_MULT && t[1].getKind() ==
- // kind::BITVECTOR_ADD) ||
- // (t[1].getKind() == kind::BITVECTOR_MULT && t[0].getKind() ==
- // kind::BITVECTOR_ADD))) {
- // // if we have an equality between a multiplication and addition
- // // try to express multiplication in terms of addition
- // Node mult = t[0].getKind() == kind::BITVECTOR_MULT? t[0] : t[1];
- // Node add = t[0].getKind() == kind::BITVECTOR_ADD? t[0] : t[1];
- // if (RewriteRule<MultSlice>::applies(mult)) {
- // Node new_mult = RewriteRule<MultSlice>::run<false>(mult);
- // Node new_eq =
- // rewrite(NodeManager::currentNM()->mkNode(kind::EQUAL,
- // new_mult, add));
-
- // // the simplification can cause the formula to blow up
- // // only apply if formula reduced
- // if (d_subtheoryMap.find(SUB_BITBLAST) != d_subtheoryMap.end()) {
- // BitblastSolver* bv = (BitblastSolver*)d_subtheoryMap[SUB_BITBLAST];
- // uint64_t old_size = bv->computeAtomWeight(t);
- // Assert (old_size);
- // uint64_t new_size = bv->computeAtomWeight(new_eq);
- // double ratio = ((double)new_size)/old_size;
- // if (ratio <= 0.4) {
- // ++(d_statistics.d_numMultSlice);
- // return new_eq;
- // }
- // }
-
- // if (new_eq.getKind() == kind::CONST_BOOLEAN) {
- // ++(d_statistics.d_numMultSlice);
- // return new_eq;
- // }
- // }
- // }
-
- if (options().bv.bvAbstraction && t.getType().isBoolean())
- {
- d_abstractionModule->addInputAtom(res);
- }
- Debug("bv-pp-rewrite") << "to " << res << "\n";
- if (res != t)
- {
- return TrustNode::mkTrustRewrite(t, res, nullptr);
- }
- return TrustNode::null();
-}
-
void BVSolverLayered::presolve()
{
Debug("bitvector") << "BVSolverLayered::presolve" << std::endl;
;
}
-void BVSolverLayered::ppStaticLearn(TNode in, NodeBuilder& learned)
-{
- if (d_staticLearnCache.find(in) != d_staticLearnCache.end())
- {
- return;
- }
- d_staticLearnCache.insert(in);
-
- if (in.getKind() == kind::EQUAL)
- {
- if ((in[0].getKind() == kind::BITVECTOR_ADD
- && in[1].getKind() == kind::BITVECTOR_SHL)
- || (in[1].getKind() == kind::BITVECTOR_ADD
- && in[0].getKind() == kind::BITVECTOR_SHL))
- {
- TNode p = in[0].getKind() == kind::BITVECTOR_ADD ? in[0] : in[1];
- TNode s = in[0].getKind() == kind::BITVECTOR_ADD ? in[1] : in[0];
-
- if (p.getNumChildren() == 2 && p[0].getKind() == kind::BITVECTOR_SHL
- && p[1].getKind() == kind::BITVECTOR_SHL)
- {
- unsigned size = utils::getSize(s);
- Node one = utils::mkConst(size, 1u);
- if (s[0] == one && p[0][0] == one && p[1][0] == one)
- {
- Node zero = utils::mkConst(size, 0u);
- TNode b = p[0];
- TNode c = p[1];
- // (s : 1 << S) = (b : 1 << B) + (c : 1 << C)
- Node b_eq_0 = b.eqNode(zero);
- Node c_eq_0 = c.eqNode(zero);
- Node b_eq_c = b.eqNode(c);
-
- Node dis = NodeManager::currentNM()->mkNode(
- kind::OR, b_eq_0, c_eq_0, b_eq_c);
- Node imp = in.impNode(dis);
- learned << imp;
- }
- }
- }
- }
- else if (in.getKind() == kind::AND)
- {
- for (size_t i = 0, N = in.getNumChildren(); i < N; ++i)
- {
- ppStaticLearn(in[i], learned);
- }
- }
-}
-
bool BVSolverLayered::applyAbstraction(const std::vector<Node>& assertions,
std::vector<Node>& new_assertions)
{
return std::string("BVSolverLayered");
}
- TrustNode ppRewrite(TNode t) override;
-
- void ppStaticLearn(TNode in, NodeBuilder& learned) override;
-
void presolve() override;
bool applyAbstraction(const std::vector<Node>& assertions,
typedef std::unordered_set<TNode> TNodeSet;
typedef std::unordered_set<Node> NodeSet;
- NodeSet d_staticLearnCache;
typedef std::unordered_map<Node, Node> NodeToNode;
#include "theory/bv/bv_solver_bitblast.h"
#include "theory/bv/bv_solver_bitblast_internal.h"
#include "theory/bv/bv_solver_layered.h"
+#include "theory/bv/theory_bv_rewrite_rules_normalization.h"
+#include "theory/bv/theory_bv_rewrite_rules_simplification.h"
#include "theory/bv/theory_bv_utils.h"
#include "theory/ee_setup_info.h"
#include "theory/trust_substitutions.h"
{
return texp;
}
+
+ Debug("theory-bv-pp-rewrite") << "ppRewrite " << t << "\n";
+ Node res = t;
+ if (options().bv.bitwiseEq && RewriteRule<BitwiseEq>::applies(t))
+ {
+ res = rewrite(RewriteRule<BitwiseEq>::run<false>(t));
+ }
+ // useful on QF_BV/space/ndist
+ else if (RewriteRule<UltAddOne>::applies(t))
+ {
+ res = rewrite(RewriteRule<UltAddOne>::run<false>(t));
+ }
+ // Useful for BV/2017-Preiner-scholl-smt08, but not for QF_BV
+ else if (options().bv.rwExtendEq)
+ {
+ if (RewriteRule<SignExtendEqConst>::applies(t))
+ {
+ res = RewriteRule<SignExtendEqConst>::run<false>(t);
+ }
+ else if (RewriteRule<ZeroExtendEqConst>::applies(t))
+ {
+ res = RewriteRule<ZeroExtendEqConst>::run<false>(t);
+ }
+ }
+
+ Debug("theory-bv-pp-rewrite") << "to " << res << "\n";
+ if (res != t)
+ {
+ return TrustNode::mkTrustRewrite(t, res, nullptr);
+ }
+
return d_internal->ppRewrite(t);
}
void TheoryBV::ppStaticLearn(TNode in, NodeBuilder& learned)
{
+ if (in.getKind() == kind::EQUAL)
+ {
+ // Only useful in combination with --bv-intro-pow2 on
+ // QF_BV/pspace/power2sum benchmarks.
+ //
+ // Matches for equality:
+ //
+ // (= (bvadd (bvshl 1 x) (bvshl 1 y)) (bvshl 1 z))
+ //
+ // and does case analysis on the sum of two power of twos.
+ if ((in[0].getKind() == kind::BITVECTOR_ADD
+ && in[1].getKind() == kind::BITVECTOR_SHL)
+ || (in[1].getKind() == kind::BITVECTOR_ADD
+ && in[0].getKind() == kind::BITVECTOR_SHL))
+ {
+ TNode p = in[0].getKind() == kind::BITVECTOR_ADD ? in[0] : in[1];
+ TNode s = in[0].getKind() == kind::BITVECTOR_ADD ? in[1] : in[0];
+
+ if (p.getNumChildren() == 2 && p[0].getKind() == kind::BITVECTOR_SHL
+ && p[1].getKind() == kind::BITVECTOR_SHL)
+ {
+ if (utils::isOne(s[0]) && utils::isOne(p[0][0])
+ && utils::isOne(p[1][0]))
+ {
+ Node zero = utils::mkZero(utils::getSize(s));
+ TNode b = p[0];
+ TNode c = p[1];
+ // (s : 1 << S) = (b : 1 << B) + (c : 1 << C)
+ Node b_eq_0 = b.eqNode(zero);
+ Node c_eq_0 = c.eqNode(zero);
+ Node b_eq_c = b.eqNode(c);
+
+ Node dis = NodeManager::currentNM()->mkNode(
+ kind::OR, b_eq_0, c_eq_0, b_eq_c);
+ Node imp = in.impNode(dis);
+ learned << imp;
+ }
+ }
+ }
+ }
+
d_internal->ppStaticLearn(in, learned);
}