Remove support for lazy BV extended function reductions and inferences (#6728)
authorAndrew Reynolds <andrew.j.reynolds@gmail.com>
Fri, 11 Jun 2021 13:54:32 +0000 (08:54 -0500)
committerGitHub <noreply@github.com>
Fri, 11 Jun 2021 13:54:32 +0000 (08:54 -0500)
solve-int-as-bv is now the preferred method for solving these benchmarks.

Adds solve-int-as-bv to a regression that became slow in my previous commit.

src/options/bv_options.toml
src/smt/set_defaults.cpp
src/theory/bv/bv_solver_lazy.cpp
src/theory/bv/bv_solver_lazy.h
src/theory/bv/bv_subtheory_core.cpp
src/theory/bv/bv_subtheory_core.h
src/theory/bv/theory_bv_rewriter.cpp
test/regress/regress1/bv/bv2nat-simp-range-sat.smt2

index fcad51cebebeaf395ce88c84922fb8a67c06c9b2..8d4c2b1de77baf71b12f2907e0de26d5bd3c3b66 100644 (file)
@@ -190,22 +190,6 @@ name   = "Bitvector Theory"
   default    = "false"
   help       = "simplify formula via Gaussian Elimination if applicable"
 
-[[option]]
-  name       = "bvLazyRewriteExtf"
-  category   = "regular"
-  long       = "bv-lazy-rewrite-extf"
-  type       = "bool"
-  default    = "true"
-  help       = "lazily rewrite extended functions like bv2nat and int2bv"
-
-[[option]]
-  name       = "bvLazyReduceExtf"
-  category   = "regular"
-  long       = "bv-lazy-reduce-extf"
-  type       = "bool"
-  default    = "false"
-  help       = "reduce extended functions like bv2nat and int2bv at last call instead of full effort"
-
 [[option]]
   name       = "bvAlgExtf"
   category   = "regular"
index 31d14c569bf574473c573199551936a53f7f72aa..67c5c5647bf9475bd04e27634336ad0616bb1758 100644 (file)
@@ -189,8 +189,6 @@ void setDefaults(LogicInfo& logic, bool isInternalSubsolver)
 
   if (options::solveBVAsInt() != options::SolveBVAsIntMode::OFF)
   {
-    // do not rewrite bv2nat eagerly
-    opts.bv.bvLazyRewriteExtf = true;
     if (options::boolToBitvector() != options::BoolToBVMode::OFF)
     {
       throw OptionException(
@@ -215,14 +213,6 @@ void setDefaults(LogicInfo& logic, bool isInternalSubsolver)
       logic.lock();
     }
   }
-  else if (options::bvSolver() == options::BVSolver::SIMPLE
-           || options::bvSolver() == options::BVSolver::BITBLAST)
-  {
-    // Only BVSolver::LAZY natively supports int2bv and nat2bv, for other
-    // solvers we need to eagerly eliminate the operators. Note this is only
-    // applied if we are not eliminating BV (e.g. with solveBVAsInt).
-    opts.bv.bvLazyReduceExtf = false;
-  }
 
   // set options about ackermannization
   if (options::ackermann() && options::produceModels()
@@ -1401,22 +1391,6 @@ void setDefaults(LogicInfo& logic, bool isInternalSubsolver)
     opts.arrays.arraysOptimizeLinear = false;
   }
 
-  if (!options::bitvectorEqualitySolver())
-  {
-    if (options::bvLazyRewriteExtf())
-    {
-      if (opts.bv.bvLazyRewriteExtfWasSetByUser)
-      {
-        throw OptionException(
-            "--bv-lazy-rewrite-extf requires --bv-eq-solver to be set");
-      }
-    }
-    Trace("smt")
-        << "disabling bvLazyRewriteExtf since equality solver is disabled"
-        << std::endl;
-    opts.bv.bvLazyRewriteExtf = false;
-  }
-
   if (options::stringFMF() && !opts.strings.stringProcessLoopModeWasSetByUser)
   {
     Trace("smt") << "settting stringProcessLoopMode to 'simple' since "
index fbd910bee9520b8a6dcfa447a1340abe7c0e7ddd..5210117b8055b7ceddc240bc2ede79937b918a6d 100644 (file)
@@ -233,18 +233,6 @@ void BVSolverLazy::check(Theory::Effort e)
     return;
   }
 
-  // last call : do reductions on extended bitvector functions
-  if (e == Theory::EFFORT_LAST_CALL)
-  {
-    CoreSolver* core = (CoreSolver*)d_subtheoryMap[SUB_CORE];
-    if (core)
-    {
-      // check extended functions at last call effort
-      core->checkExtf(e);
-    }
-    return;
-  }
-
   Debug("bitvector") << "BVSolverLazy::check(" << e << ")" << std::endl;
   TimerStat::CodeTimer codeTimer(d_statistics.d_solveTimer);
   // we may be getting new assertions so the model cache may not be sound
@@ -331,27 +319,6 @@ void BVSolverLazy::check(Theory::Effort e)
       break;
     }
   }
-
-  // check extended functions
-  if (Theory::fullEffort(e))
-  {
-    CoreSolver* core = (CoreSolver*)d_subtheoryMap[SUB_CORE];
-    if (core)
-    {
-      // check extended functions at full effort
-      core->checkExtf(e);
-    }
-  }
-}
-
-bool BVSolverLazy::needsCheckLastEffort()
-{
-  CoreSolver* core = (CoreSolver*)d_subtheoryMap[SUB_CORE];
-  if (core)
-  {
-    return core->needsCheckLastEffort();
-  }
-  return false;
 }
 
 bool BVSolverLazy::collectModelValues(TheoryModel* m,
index 9b3a2f1faf74d31de681a332678658ecfe6649c2..4f73354bc7b1cb19ec31de7f5eceb2daec56f03f 100644 (file)
@@ -82,8 +82,6 @@ class BVSolverLazy : public BVSolver
 
   bool preCheck(Theory::Effort e) override;
 
-  bool needsCheckLastEffort() override;
-
   void propagate(Theory::Effort e) override;
 
   TrustNode explain(TNode n) override;
index 2589418cc9b8cd32f4ea2c129ec274865d07a350..fa71641ad7e59e665ac5e330e6ae1bf99c3d5935 100644 (file)
@@ -32,64 +32,6 @@ using namespace cvc5::theory;
 using namespace cvc5::theory::bv;
 using namespace cvc5::theory::bv::utils;
 
-bool CoreSolverExtTheoryCallback::getCurrentSubstitution(
-    int effort,
-    const std::vector<Node>& vars,
-    std::vector<Node>& subs,
-    std::map<Node, std::vector<Node> >& exp)
-{
-  if (d_equalityEngine == nullptr)
-  {
-    return false;
-  }
-  // get the constant equivalence classes
-  bool retVal = false;
-  for (const Node& n : vars)
-  {
-    if (d_equalityEngine->hasTerm(n))
-    {
-      Node nr = d_equalityEngine->getRepresentative(n);
-      if (nr.isConst())
-      {
-        subs.push_back(nr);
-        exp[n].push_back(n.eqNode(nr));
-        retVal = true;
-      }
-      else
-      {
-        subs.push_back(n);
-      }
-    }
-    else
-    {
-      subs.push_back(n);
-    }
-  }
-  // return true if the substitution is non-trivial
-  return retVal;
-}
-
-bool CoreSolverExtTheoryCallback::getReduction(int effort,
-                                               Node n,
-                                               Node& nr,
-                                               bool& satDep)
-{
-  Trace("bv-ext") << "TheoryBV::checkExt : non-reduced : " << n << std::endl;
-  if (n.getKind() == kind::BITVECTOR_TO_NAT)
-  {
-    nr = utils::eliminateBv2Nat(n);
-    satDep = false;
-    return true;
-  }
-  else if (n.getKind() == kind::INT_TO_BITVECTOR)
-  {
-    nr = utils::eliminateInt2Bv(n);
-    satDep = false;
-    return true;
-  }
-  return false;
-}
-
 CoreSolver::CoreSolver(context::Context* c, BVSolverLazy* bv)
     : SubtheorySolver(c, bv),
       d_notify(*this),
@@ -98,18 +40,8 @@ CoreSolver::CoreSolver(context::Context* c, BVSolverLazy* bv)
       d_preregisterCalled(false),
       d_checkCalled(false),
       d_bv(bv),
-      d_extTheoryCb(),
-      d_extTheory(new ExtTheory(d_extTheoryCb,
-                                bv->d_bv.getSatContext(),
-                                bv->d_bv.getUserContext(),
-                                bv->d_bv.getOutputChannel())),
-      d_reasons(c),
-      d_needsLastCallCheck(false),
-      d_extf_range_infer(bv->d_bv.getUserContext()),
-      d_extf_collapse_infer(bv->d_bv.getUserContext())
+      d_reasons(c)
 {
-  d_extTheory->addFunctionKind(kind::BITVECTOR_TO_NAT);
-  d_extTheory->addFunctionKind(kind::INT_TO_BITVECTOR);
 }
 
 CoreSolver::~CoreSolver() {}
@@ -167,11 +99,6 @@ void CoreSolver::preRegister(TNode node) {
     d_equalityEngine->addTriggerPredicate(node);
   } else {
     d_equalityEngine->addTerm(node);
-    // Register with the extended theory, for context-dependent simplification.
-    // Notice we do this for registered terms but not internally generated
-    // equivalence classes. The two should roughly cooincide. Since ExtTheory is
-    // being used as a heuristic, it is good enough to be registered here.
-    d_extTheory->registerTerm(node);
   }
 }
 
@@ -489,142 +416,3 @@ CoreSolver::Statistics::Statistics()
         "theory::bv::CoreSolver::NumCallsToCheck"))
 {
 }
-
-void CoreSolver::checkExtf(Theory::Effort e)
-{
-  if (e == Theory::EFFORT_LAST_CALL)
-  {
-    std::vector<Node> nred = d_extTheory->getActive();
-    doExtfReductions(nred);
-  }
-  Assert(e == Theory::EFFORT_FULL);
-  // do inferences (adds external lemmas)  TODO: this can be improved to add
-  // internal inferences
-  std::vector<Node> nred;
-  if (d_extTheory->doInferences(0, nred))
-  {
-    return;
-  }
-  d_needsLastCallCheck = false;
-  if (!nred.empty())
-  {
-    // other inferences involving bv2nat, int2bv
-    if (options::bvAlgExtf())
-    {
-      if (doExtfInferences(nred))
-      {
-        return;
-      }
-    }
-    if (!options::bvLazyReduceExtf())
-    {
-      if (doExtfReductions(nred))
-      {
-        return;
-      }
-    }
-    else
-    {
-      d_needsLastCallCheck = true;
-    }
-  }
-}
-
-bool CoreSolver::needsCheckLastEffort() const { return d_needsLastCallCheck; }
-
-bool CoreSolver::doExtfInferences(std::vector<Node>& terms)
-{
-  NodeManager* nm = NodeManager::currentNM();
-  SkolemManager* sm = nm->getSkolemManager();
-  bool sentLemma = false;
-  eq::EqualityEngine* ee = d_equalityEngine;
-  std::map<Node, Node> op_map;
-  for (unsigned j = 0; j < terms.size(); j++)
-  {
-    TNode n = terms[j];
-    Assert(n.getKind() == kind::BITVECTOR_TO_NAT
-           || n.getKind() == kind::INT_TO_BITVECTOR);
-    if (n.getKind() == kind::BITVECTOR_TO_NAT)
-    {
-      // range lemmas
-      if (d_extf_range_infer.find(n) == d_extf_range_infer.end())
-      {
-        d_extf_range_infer.insert(n);
-        unsigned bvs = n[0].getType().getBitVectorSize();
-        Node min = nm->mkConst(Rational(0));
-        Node max = nm->mkConst(Rational(Integer(1).multiplyByPow2(bvs)));
-        Node lem = nm->mkNode(kind::AND,
-                              nm->mkNode(kind::GEQ, n, min),
-                              nm->mkNode(kind::LT, n, max));
-        Trace("bv-extf-lemma")
-            << "BV extf lemma (range) : " << lem << std::endl;
-        d_bv->d_im.lemma(lem, InferenceId::BV_EXTF_LEMMA);
-        sentLemma = true;
-      }
-    }
-    Node r = (ee && ee->hasTerm(n[0])) ? ee->getRepresentative(n[0]) : n[0];
-    op_map[r] = n;
-  }
-  for (unsigned j = 0; j < terms.size(); j++)
-  {
-    TNode n = terms[j];
-    Node r = (ee && ee->hasTerm(n[0])) ? ee->getRepresentative(n) : n;
-    std::map<Node, Node>::iterator it = op_map.find(r);
-    if (it != op_map.end())
-    {
-      Node parent = it->second;
-      // Node cterm = parent[0]==n ? parent : nm->mkNode( parent.getOperator(),
-      // n );
-      Node cterm = parent[0].eqNode(n);
-      Trace("bv-extf-lemma-debug")
-          << "BV extf collapse based on : " << cterm << std::endl;
-      if (d_extf_collapse_infer.find(cterm) == d_extf_collapse_infer.end())
-      {
-        d_extf_collapse_infer.insert(cterm);
-
-        Node t = n[0];
-        if (t.getType() == parent.getType())
-        {
-          if (n.getKind() == kind::INT_TO_BITVECTOR)
-          {
-            Assert(t.getType().isInteger());
-            // congruent modulo 2^( bv width )
-            unsigned bvs = n.getType().getBitVectorSize();
-            Node coeff = nm->mkConst(Rational(Integer(1).multiplyByPow2(bvs)));
-            Node k = sm->mkDummySkolem(
-                "int_bv_cong", t.getType(), "for int2bv/bv2nat congruence");
-            t = nm->mkNode(kind::PLUS, t, nm->mkNode(kind::MULT, coeff, k));
-          }
-          Node lem = parent.eqNode(t);
-
-          if (parent[0] != n)
-          {
-            Assert(ee->areEqual(parent[0], n));
-            lem = nm->mkNode(kind::IMPLIES, parent[0].eqNode(n), lem);
-          }
-          // this handles inferences of the form, e.g.:
-          //   ((_ int2bv w) (bv2nat x)) == x (if x is bit-width w)
-          //   (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_im.lemma(lem, InferenceId::BV_EXTF_COLLAPSE);
-          sentLemma = true;
-        }
-      }
-      Trace("bv-extf-lemma-debug")
-          << "BV extf f collapse based on : " << cterm << std::endl;
-    }
-  }
-  return sentLemma;
-}
-
-bool CoreSolver::doExtfReductions(std::vector<Node>& terms)
-{
-  std::vector<Node> nredr;
-  if (d_extTheory->doReductions(0, terms, nredr))
-  {
-    return true;
-  }
-  Assert(nredr.empty());
-  return false;
-}
index 0dfcfdde4d2042bddf3e6bb9adb561af049698a8..46c4559ea7906fed94a3ba17ddbd6df81d52c7c7 100644 (file)
 
 #include "context/cdhashset.h"
 #include "theory/bv/bv_subtheory.h"
-#include "theory/ext_theory.h"
 
 namespace cvc5 {
 namespace theory {
 namespace bv {
 
-class Base;
-
-/** An extended theory callback used by the core solver */
-class CoreSolverExtTheoryCallback : public ExtTheoryCallback
-{
- public:
-  CoreSolverExtTheoryCallback() : d_equalityEngine(nullptr) {}
-  /** Get current substitution based on the underlying equality engine. */
-  bool getCurrentSubstitution(int effort,
-                              const std::vector<Node>& vars,
-                              std::vector<Node>& subs,
-                              std::map<Node, std::vector<Node> >& exp) override;
-  /** Get reduction. */
-  bool getReduction(int effort, Node n, Node& nr, bool& satDep) override;
-  /** The underlying equality engine */
-  eq::EqualityEngine* d_equalityEngine;
-};
-
 /**
  * Bitvector equality solver
  */
@@ -96,10 +77,6 @@ class CoreSolver : public SubtheorySolver {
   BVSolverLazy* d_bv;
   /** Pointer to the equality engine of the parent */
   eq::EqualityEngine* d_equalityEngine;
-  /** The extended theory callback */
-  CoreSolverExtTheoryCallback d_extTheoryCb;
-  /** Extended theory module, for context-dependent simplification. */
-  std::unique_ptr<ExtTheory> d_extTheory;
 
   /** To make sure we keep the explanations */
   context::CDHashSet<Node> d_reasons;
@@ -109,36 +86,6 @@ class CoreSolver : public SubtheorySolver {
   bool isCompleteForTerm(TNode term, TNodeBoolMap& seen);
   Statistics d_statistics;
 
-  /** Whether we need a last call effort check */
-  bool d_needsLastCallCheck;
-  /** For extended functions */
-  context::CDHashSet<Node> d_extf_range_infer;
-  context::CDHashSet<Node> d_extf_collapse_infer;
-
-  /** do extended function inferences
-   *
-   * This method adds lemmas on the output channel of TheoryBV based on
-   * reasoning about extended functions, such as bv2nat and int2bv. Examples
-   * of lemmas added by this method include:
-   *   0 <= ((_ int2bv w) x) < 2^w
-   *   ((_ int2bv w) (bv2nat x)) = x
-   *   (bv2nat ((_ int2bv w) x)) == x + k*2^w
-   * The purpose of these lemmas is to recognize easy conflicts before fully
-   * reducing extended functions based on their full semantics.
-   */
-  bool doExtfInferences(std::vector<Node>& terms);
-  /** do extended function reductions
-   *
-   * This method adds lemmas on the output channel of TheoryBV based on
-   * reducing all extended function applications that are preregistered to
-   * this theory and have not already been reduced by context-dependent
-   * simplification (see theory/ext_theory.h). Examples of lemmas added by
-   * this method include:
-   *   (bv2nat x) = (ite ((_ extract w w-1) x) 2^{w-1} 0) + ... +
-   *                (ite ((_ extract 1 0) x) 1 0)
-   */
-  bool doExtfReductions(std::vector<Node>& terms);
-
  public:
   CoreSolver(context::Context* c, BVSolverLazy* bv);
   ~CoreSolver();
@@ -154,9 +101,6 @@ class CoreSolver : public SubtheorySolver {
   EqualityStatus getEqualityStatus(TNode a, TNode b) override;
   bool hasTerm(TNode node) const;
   void addTermToEqualityEngine(TNode node);
-  /** check extended functions at the given effort */
-  void checkExtf(Theory::Effort e);
-  bool needsCheckLastEffort() const;
 };
 
 }
index 4e10767631e5e9050e9ca12465eba8ec6c934519..97ca24437851d003be810eb81073ddbc2c2f08e4 100644 (file)
@@ -65,16 +65,14 @@ TrustNode TheoryBVRewriter::expandDefinition(Node node)
     case kind::BITVECTOR_SREM:
     case kind::BITVECTOR_SMOD: ret = eliminateBVSDiv(node); break;
     case kind::BITVECTOR_TO_NAT:
-      if (!options::bvLazyReduceExtf())
-      {
+
         ret = utils::eliminateBv2Nat(node);
-      }
+      
       break;
     case kind::INT_TO_BITVECTOR:
-      if (!options::bvLazyReduceExtf())
-      {
+
         ret = utils::eliminateInt2Bv(node);
-      }
+      
       break;
     default: break;
   }
@@ -646,8 +644,8 @@ RewriteResponse TheoryBVRewriter::RewriteRedand(TNode node, bool prerewrite){
 }
 
 RewriteResponse TheoryBVRewriter::RewriteBVToNat(TNode node, bool prerewrite) {
-  //do not use lazy rewrite strategy if equality solver is disabled
-  if( node[0].isConst() || !options::bvLazyRewriteExtf() ){
+  if (node[0].isConst())
+  {
     Node resultNode = LinearRewriteStrategy
       < RewriteRule<BVToNatEliminate>
       >::apply(node);
@@ -658,8 +656,8 @@ RewriteResponse TheoryBVRewriter::RewriteBVToNat(TNode node, bool prerewrite) {
 }
 
 RewriteResponse TheoryBVRewriter::RewriteIntToBV(TNode node, bool prerewrite) {
-  //do not use lazy rewrite strategy if equality solver is disabled
-  if( node[0].isConst() || !options::bvLazyRewriteExtf() ){
+  if (node[0].isConst())
+  {
     Node resultNode = LinearRewriteStrategy
       < RewriteRule<IntToBVEliminate>
       >::apply(node);
index 9da8d4ca81548186d7dc73940dbd921061e4fdcc..66b286da1099a1ebf0e407a440ab579a60d3b7ae 100644 (file)
@@ -1,3 +1,5 @@
+; COMMAND-LINE: --solve-bv-as-int=sum
+; EXPECT: sat
 (set-logic ALL)
 (set-info :status sat)
 (declare-fun t () (_ BitVec 16))