CBQI BV choice expressions (#1296)
authorAndrew Reynolds <andrew.j.reynolds@gmail.com>
Wed, 1 Nov 2017 18:35:07 +0000 (13:35 -0500)
committerGitHub <noreply@github.com>
Wed, 1 Nov 2017 18:35:07 +0000 (13:35 -0500)
* Use Hilbert choice expressions for cbqi bv. Failing in debug due to TNode issues currently.

* Minor

* Make unique bound variables for choice functions in BvInstantor, clean up.

* Incorporate missing optimizations

* Clang format

* Unused field.

* Minor

* Fix, add regression.

* Fix regression.

* Fix bug that led to incorrect cleanup of instantiations.

* Add missing regression

* Improve handling of choice rewriting.

* Fix

* Clang format

* Use canonical variables for choice functions in cbqi bv.

* Add regression

* Clang format.

* Address review.

* Clang format

12 files changed:
src/smt/term_formula_removal.cpp
src/smt/term_formula_removal.h
src/theory/quantifiers/bv_inverter.cpp
src/theory/quantifiers/bv_inverter.h
src/theory/quantifiers/ceg_instantiator.cpp
src/theory/quantifiers/ceg_instantiator.h
src/theory/quantifiers/ceg_t_instantiator.cpp
src/theory/quantifiers/ceg_t_instantiator.h
test/regress/regress0/quantifiers/Makefile.am
test/regress/regress0/quantifiers/NUM878.smt2 [new file with mode: 0644]
test/regress/regress0/quantifiers/ari118-bv-2occ-x.smt2 [new file with mode: 0644]
test/regress/regress0/quantifiers/psyco-107-bv.smt2 [new file with mode: 0644]

index 01cf59c152f7db94b3b8b908ef318cddc75bab57..c2f9facce6d7498febc45b5494f44c19fdc45a20 100644 (file)
@@ -150,7 +150,7 @@ Node RemoveTermFormulas::run(TNode node, std::vector<Node>& output,
 
     // The new assertion is the assumption that the body
     // of the choice operator holds for the Skolem
-    newAssertion = node[1].substitute(node[0], skolem);
+    newAssertion = node[1].substitute(node[0][0], skolem);
   }
 
   //if a non-variable Boolean term, replace it
index f84f9dc371c2ed15ecbbf8a7291510a4e00bd08a..371ca1f58841d175c8dc86e8f27d36dd893185c7 100644 (file)
@@ -50,7 +50,7 @@ public:
 
   /**
    * By introducing skolem variables, this function removes all occurrences of:
-   * (1) term ITEs
+   * (1) term ITEs,
    * (2) terms of type Boolean that are not Boolean term variables,
    * (3) lambdas, and
    * (4) Hilbert choice expressions.
index 957385a14d239a3d5df0348178b67f95ac0ae51f..d777dc4f8fa5c6a3eb75cbebc6d85d966ebe9818 100644 (file)
@@ -52,21 +52,7 @@ Node BvInverter::getSolveVariable(TypeNode tn)
   std::map<TypeNode, Node>::iterator its = d_solve_var.find(tn);
   if (its == d_solve_var.end())
   {
-    std::stringstream ss;
-    if (tn.isFunction())
-    {
-      Assert(tn.getNumChildren() == 2);
-      Assert(tn[0].isBoolean());
-      ss << "slv_f";
-    }
-    else
-    {
-      ss << "slv";
-    }
-    Node k = NodeManager::currentNM()->mkSkolem(ss.str(), tn);
-    // marked as a virtual term (it is eligible for instantiation)
-    VirtualTermSkolemAttribute vtsa;
-    k.setAttribute(vtsa, true);
+    Node k = NodeManager::currentNM()->mkSkolem("slv", tn);
     d_solve_var[tn] = k;
     return k;
   }
@@ -76,75 +62,50 @@ Node BvInverter::getSolveVariable(TypeNode tn)
   }
 }
 
-Node BvInverter::getInversionSkolemFor(Node cond, TypeNode tn)
+Node BvInverter::getInversionNode(Node cond, TypeNode tn, BvInverterQuery* m)
 {
   // condition should be rewritten
-  Assert(Rewriter::rewrite(cond) == cond);
-  std::unordered_map<Node, Node, NodeHashFunction>::iterator it =
-      d_inversion_skolem_cache.find(cond);
-  if (it == d_inversion_skolem_cache.end())
+  Node new_cond = Rewriter::rewrite(cond);
+  if (new_cond != cond)
   {
-    Node skv;
-    if (cond.getKind() == EQUAL)
+    Trace("cegqi-bv-skvinv-debug") << "Condition " << cond
+                                   << " was rewritten to " << new_cond
+                                   << std::endl;
+  }
+  Node c;
+  // optimization : if condition is ( x = v ) should just return v and not
+  // introduce a Skolem this can happen when we ask for the multiplicative
+  // inversion with bv1
+  TNode solve_var = getSolveVariable(tn);
+  if (new_cond.getKind() == EQUAL)
+  {
+    for (unsigned i = 0; i < 2; i++)
     {
-      // optimization : if condition is ( x = v ) should just return v and not
-      // introduce a Skolem this can happen when we ask for the multiplicative
-      // inversion with bv1
-      Node x = getSolveVariable(tn);
-      for (unsigned i = 0; i < 2; i++)
+      if (new_cond[i] == solve_var)
       {
-        if (cond[i] == x)
-        {
-          skv = cond[1 - i];
-          Trace("cegqi-bv-skvinv")
-              << "SKVINV : " << skv << " is trivially associated with conditon "
-              << cond << std::endl;
-          break;
-        }
+        c = new_cond[1 - i];
+        Trace("cegqi-bv-skvinv") << "SKVINV : " << c
+                                 << " is trivially associated with conditon "
+                                 << new_cond << std::endl;
+        break;
       }
     }
-    if (skv.isNull())
-    {
-      // TODO : compute the value if the condition is deterministic, e.g. calc
-      // multiplicative inverse of 2 constants
-      skv = NodeManager::currentNM()->mkSkolem(
-          "skvinv", tn, "created for BvInverter");
-      Trace("cegqi-bv-skvinv")
-          << "SKVINV : " << skv << " is the skolem associated with conditon "
-          << cond << std::endl;
-      // marked as a virtual term (it is eligible for instantiation)
-      VirtualTermSkolemAttribute vtsa;
-      skv.setAttribute(vtsa, true);
-    }
-    d_inversion_skolem_cache[cond] = skv;
-    return skv;
-  }
-  else
-  {
-    Assert(it->second.getType() == tn);
-    return it->second;
   }
-}
-
-Node BvInverter::getInversionSkolemFunctionFor(TypeNode tn)
-{
-  NodeManager* nm = NodeManager::currentNM();
-  // function maps conditions to skolems
-  TypeNode ftn = nm->mkFunctionType(nm->booleanType(), tn);
-  return getSolveVariable(ftn);
-}
-
-Node BvInverter::getInversionNode(Node cond, TypeNode tn)
-{
-  // condition should be rewritten
-  Node new_cond = Rewriter::rewrite(cond);
-  if (new_cond != cond)
+  // TODO : compute the value if the condition is deterministic, e.g. calc
+  // multiplicative inverse of 2 constants
+  if (c.isNull())
   {
-    Trace("bv-invert-debug") << "Condition " << cond << " was rewritten to "
-                             << new_cond << std::endl;
+    NodeManager* nm = NodeManager::currentNM();
+    Node x = m->getBoundVariable(tn);
+    Node ccond = new_cond.substitute(solve_var, x);
+    c = nm->mkNode(kind::CHOICE, nm->mkNode(BOUND_VAR_LIST, x), ccond);
+    Trace("cegqi-bv-skvinv") << "SKVINV : Make " << c << " for " << new_cond
+                             << std::endl;
   }
-  Node f = getInversionSkolemFunctionFor(tn);
-  return NodeManager::currentNM()->mkNode(kind::APPLY_UF, f, new_cond);
+  // currently shouldn't cache since
+  // the return value depends on the
+  // state of m (which bound variable is returned).
+  return c;
 }
 
 bool BvInverter::isInvertible(Kind k, unsigned index)
@@ -219,97 +180,6 @@ Node BvInverter::getPathToPv(
   return Node::null();
 }
 
-Node BvInverter::eliminateSkolemFunctions(TNode n,
-                                          std::vector<Node>& side_conditions)
-{
-  std::unordered_map<TNode, Node, TNodeHashFunction> visited;
-  std::unordered_map<TNode, Node, TNodeHashFunction>::iterator it;
-  std::stack<TNode> visit;
-  TNode cur;
-
-  visit.push(n);
-  do
-  {
-    cur = visit.top();
-    visit.pop();
-    it = visited.find(cur);
-
-    if (it == visited.end())
-    {
-      visited[cur] = Node::null();
-      visit.push(cur);
-      for (unsigned i = 0; i < cur.getNumChildren(); i++)
-      {
-        visit.push(cur[i]);
-      }
-    }
-    else if (it->second.isNull())
-    {
-      Trace("bv-invert-debug")
-          << "eliminateSkolemFunctions from " << cur << "..." << std::endl;
-
-      Node ret = cur;
-      bool childChanged = false;
-      std::vector<Node> children;
-      if (cur.getMetaKind() == kind::metakind::PARAMETERIZED)
-      {
-        children.push_back(cur.getOperator());
-      }
-      for (unsigned i = 0; i < cur.getNumChildren(); i++)
-      {
-        it = visited.find(cur[i]);
-        Assert(it != visited.end());
-        Assert(!it->second.isNull());
-        childChanged = childChanged || cur[i] != it->second;
-        children.push_back(it->second);
-      }
-      if (childChanged)
-      {
-        ret = NodeManager::currentNM()->mkNode(cur.getKind(), children);
-      }
-      // now, check if it is a skolem function
-      if (ret.getKind() == APPLY_UF)
-      {
-        Node op = ret.getOperator();
-        TypeNode tnp = op.getType();
-        // is this a skolem function?
-        std::map<TypeNode, Node>::iterator its = d_solve_var.find(tnp);
-        if (its != d_solve_var.end() && its->second == op)
-        {
-          Assert(ret.getNumChildren() == 1);
-          Assert(ret[0].getType().isBoolean());
-
-          Node cond = ret[0];
-          // must rewrite now to ensure we lookup the correct skolem
-          cond = Rewriter::rewrite(cond);
-
-          // if so, we replace by the (finalized) skolem variable
-          // Notice that since we are post-rewriting, skolem functions are
-          // already eliminated from cond
-          ret = getInversionSkolemFor(cond, ret.getType());
-
-          // also must add (substituted) side condition to vector
-          // substitute ( solve variable -> inversion skolem )
-          TNode solve_var = getSolveVariable(ret.getType());
-          TNode tret = ret;
-          cond = cond.substitute(solve_var, tret);
-          if (std::find(side_conditions.begin(), side_conditions.end(), cond)
-              == side_conditions.end())
-          {
-            side_conditions.push_back(cond);
-          }
-        }
-      }
-      Trace("bv-invert-debug") << "eliminateSkolemFunctions from " << cur
-                               << " returned " << ret << std::endl;
-      visited[cur] = ret;
-    }
-  } while (!visit.empty());
-  Assert(visited.find(n) != visited.end());
-  Assert(!visited.find(n)->second.isNull());
-  return visited[n];
-}
-
 Node BvInverter::getPathToPv(
     Node lit, Node pv, Node sv, Node pvs, std::vector<unsigned>& path)
 {
@@ -329,7 +199,7 @@ Node BvInverter::getPathToPv(
 Node BvInverter::solve_bv_lit(Node sv,
                               Node lit,
                               std::vector<unsigned>& path,
-                              BvInverterModelQuery* m,
+                              BvInverterQuery* m,
                               BvInverterStatus& status)
 {
   Assert(!path.empty());
@@ -413,7 +283,7 @@ Node BvInverter::solve_bv_lit(Node sv,
       }
       status.d_conds.push_back(sc);
       /* t = skv (fresh skolem constant)  */
-      Node skv = getInversionNode(sc, solve_tn);
+      Node skv = getInversionNode(sc, solve_tn, m);
       t = skv;
       if (!path.empty())
       {
@@ -469,7 +339,7 @@ Node BvInverter::solve_bv_lit(Node sv,
       }
       status.d_conds.push_back(sc);
       /* t = skv (fresh skolem constant)  */
-      Node skv = getInversionNode(sc, solve_tn);
+      Node skv = getInversionNode(sc, solve_tn, m);
       t = skv;
       if (!path.empty())
       {
@@ -502,7 +372,7 @@ Node BvInverter::solve_bv_lit(Node sv,
         Node sc = nm->mkNode(IMPLIES, scl, scr);
         status.d_conds.push_back(sc);
         /* t = skv (fresh skolem constant)  */
-        Node skv = getInversionNode(sc, solve_tn);
+        Node skv = getInversionNode(sc, solve_tn, m);
         t = skv;
         if (!path.empty())
         {
@@ -599,7 +469,7 @@ Node BvInverter::solve_bv_lit(Node sv,
 
           /* t = skv (fresh skolem constant)
            * get the skolem node for this side condition  */
-          Node skv = getInversionNode(sc, solve_tn);
+          Node skv = getInversionNode(sc, solve_tn, m);
           /* now solving with the skolem node as the RHS  */
           t = skv;
           break;
@@ -641,7 +511,7 @@ Node BvInverter::solve_bv_lit(Node sv,
           }
           Node sc = nm->mkNode(IMPLIES, scl, scr);
           status.d_conds.push_back(sc);
-          Node skv = getInversionNode(sc, solve_tn);
+          Node skv = getInversionNode(sc, solve_tn, m);
           t = skv;
           break;
         }
@@ -694,7 +564,7 @@ Node BvInverter::solve_bv_lit(Node sv,
 
           /* t = skv (fresh skolem constant)
            * get the skolem node for this side condition */
-          Node skv = getInversionNode(sc, solve_tn);
+          Node skv = getInversionNode(sc, solve_tn, m);
           /* now solving with the skolem node as the RHS */
           t = skv;
           break;
@@ -713,7 +583,7 @@ Node BvInverter::solve_bv_lit(Node sv,
           Node sc = nm->mkNode(IMPLIES, scl, scr);
           status.d_conds.push_back(sc);
           /* t = skv (fresh skolem constant)  */
-          Node skv = getInversionNode(sc, solve_tn);
+          Node skv = getInversionNode(sc, solve_tn, m);
           t = skv;
           break;
         }
@@ -749,7 +619,7 @@ Node BvInverter::solve_bv_lit(Node sv,
             Node sc = nm->mkNode(IMPLIES, scl, scr);
             status.d_conds.push_back(sc);
             /* t = skv (fresh skolem constant)  */
-            Node skv = getInversionNode(sc, solve_tn);
+            Node skv = getInversionNode(sc, solve_tn, m);
             t = skv;
           }
           else
@@ -793,7 +663,7 @@ Node BvInverter::solve_bv_lit(Node sv,
             Node sc = nm->mkNode(IMPLIES, scl, scr);
             status.d_conds.push_back(sc);
             /* t = skv (fresh skolem constant)  */
-            Node skv = getInversionNode(sc, solve_tn);
+            Node skv = getInversionNode(sc, solve_tn, m);
             t = skv;
           }
           else
@@ -863,7 +733,7 @@ Node BvInverter::solve_bv_lit(Node sv,
 
           /* t = skv (fresh skolem constant)
            * get the skolem node for this side condition */
-          Node skv = getInversionNode(sc, solve_tn);
+          Node skv = getInversionNode(sc, solve_tn, m);
           /* now solving with the skolem node as the RHS */
           t = skv;
           break;
index 1c60d11eabae83869ecde9111347887fc7caa37f..56f8d492bceb76f4d4583c99a7ef4743aa753219 100644 (file)
@@ -28,12 +28,20 @@ namespace CVC4 {
 namespace theory {
 namespace quantifiers {
 
-// virtual class for model queries
-class BvInverterModelQuery {
+/** BvInverterQuery
+ *
+ * This is a virtual class for queries
+ * required by the BvInverter class.
+ */
+class BvInverterQuery
+{
  public:
-  BvInverterModelQuery() {}
-  ~BvInverterModelQuery() {}
+  BvInverterQuery() {}
+  ~BvInverterQuery() {}
+  /** returns the current model value of n */
   virtual Node getModelValue(Node n) = 0;
+  /** returns a bound variable of type tn */
+  virtual Node getBoundVariable(TypeNode tn) = 0;
 };
 
 // class for storing information about the solved status
@@ -53,17 +61,26 @@ class BvInverter {
  public:
   BvInverter() {}
   ~BvInverter() {}
-
   /** get dummy fresh variable of type tn, used as argument for sv */
   Node getSolveVariable(TypeNode tn);
 
-  /** get inversion node, if :
+  /** get inversion node
+   *
+   * This expects a condition cond where:
+   *   (exists x. cond)
+   * is a BV tautology where x is getSolveVariable( tn ).
    *
-   *   f = getInversionSkolemFunctionFor( tn )
+   * It returns a term of the form:
+   *   (choice y. cond { x -> y })
+   * where y is a bound variable and x is getSolveVariable( tn ).
    *
-   * This returns f( cond ).
+   * In some cases, we may return a term t
+   * if cond implies an equality on the solve variable.
+   * For example, if cond is x = t where x is
+   * getSolveVariable( tn ), then we return t
+   * instead of introducing the choice function.
    */
-  Node getInversionNode(Node cond, TypeNode tn);
+  Node getInversionNode(Node cond, TypeNode tn, BvInverterQuery* m);
 
   /** Get path to pv in lit, replace that occurrence by sv and all others by
    * pvs. If return value R is non-null, then : lit.path = pv R.path = sv
@@ -72,62 +89,26 @@ class BvInverter {
   Node getPathToPv(Node lit, Node pv, Node sv, Node pvs,
                    std::vector<unsigned>& path);
 
-  /** eliminate skolem functions in node n
-   *
-   * This eliminates all Skolem functions from Node n and replaces them with
-   * finalized Skolem variables.
-   *
-   * For each skolem variable we introduce, we ensure its associated side
-   * condition is added to side_conditions.
-   *
-   * Apart from Skolem functions, all subterms of n should be eligible for
-   * instantiation.
-   */
-  Node eliminateSkolemFunctions(TNode n, std::vector<Node>& side_conditions);
-
   /** solve_bv_lit
    * solve for sv in lit, where lit.path = sv
    * status accumulates side conditions
    */
-  Node solve_bv_lit(Node sv, Node lit, std::vector<unsigned>& path,
-                    BvInverterModelQuery* m, BvInverterStatus& status);
+  Node solve_bv_lit(Node sv,
+                    Node lit,
+                    std::vector<unsigned>& path,
+                    BvInverterQuery* m,
+                    BvInverterStatus& status);
 
  private:
   /** dummy variables for each type */
   std::map<TypeNode, Node> d_solve_var;
 
-  /** stores the inversion skolems, for each condition */
-  std::unordered_map<Node, Node, NodeHashFunction> d_inversion_skolem_cache;
-
   /** helper function for getPathToPv */
   Node getPathToPv(Node lit, Node pv, Node sv, std::vector<unsigned>& path,
                    std::unordered_set<TNode, TNodeHashFunction>& visited);
 
   // is operator k invertible?
   bool isInvertible(Kind k, unsigned index);
-
-  /** get inversion skolem for condition
-   * precondition : exists x. cond( x ) is a tautology in BV,
-   *               where x is getSolveVariable( tn ).
-   * returns fresh skolem k of type tn, where we may assume cond( k ).
-   */
-  Node getInversionSkolemFor(Node cond, TypeNode tn);
-
-  /** get inversion skolem function for type tn.
-   *   This is a function of type ( Bool -> tn ) that is used for explicitly
-   * storing side conditions inside terms. For all ( cond, tn ), if :
-   *
-   *   f = getInversionSkolemFunctionFor( tn )
-   *   k = getInversionSkolemFor( cond, tn )
-   *   then:
-   *   f( cond ) is a placeholder for k.
-   *
-   * In the call eliminateSkolemFunctions, we replace all f( cond ) with k and
-   * add cond{ x -> k } to side_conditions. The advantage is that f( cond )
-   * explicitly contains the side condition so it automatically updates with
-   * substitutions.
-   */
-  Node getInversionSkolemFunctionFor(TypeNode tn);
 };
 
 }  // namespace quantifiers
index 57bfb2d141e6b65e6d6c4d3ccb4f2dd6f47cbc24..e7749cd92a4cae539e673a90114ecbf0873408c9 100644 (file)
@@ -46,24 +46,35 @@ CegInstantiator::~CegInstantiator() {
 void CegInstantiator::computeProgVars( Node n ){
   if( d_prog_var.find( n )==d_prog_var.end() ){
     d_prog_var[n].clear();
-    if( std::find( d_vars.begin(), d_vars.end(), n )!=d_vars.end() ){
-      d_prog_var[n][n] = true;
+    if (n.getKind() == kind::CHOICE)
+    {
+      Assert(d_prog_var.find(n[0][0]) == d_prog_var.end());
+      d_prog_var[n[0][0]].clear();
+    }
+    if (d_vars_set.find(n) != d_vars_set.end())
+    {
+      d_prog_var[n].insert(n);
     }else if( !d_out->isEligibleForInstantiation( n ) ){
-      d_inelig[n] = true;
+      d_inelig.insert(n);
       return;
     }
     for( unsigned i=0; i<n.getNumChildren(); i++ ){
       computeProgVars( n[i] );
       if( d_inelig.find( n[i] )!=d_inelig.end() ){
-        d_inelig[n] = true;
-      }
-      for( std::map< Node, bool >::iterator it = d_prog_var[n[i]].begin(); it != d_prog_var[n[i]].end(); ++it ){
-        d_prog_var[n][it->first] = true;
-      }
-      //selectors applied to program variables are also variables
-      if( n.getKind()==APPLY_SELECTOR_TOTAL && d_prog_var[n].find( n[0] )!=d_prog_var[n].end() ){
-        d_prog_var[n][n] = true;
+        d_inelig.insert(n);
       }
+      // all variables in child are contained in this
+      d_prog_var[n].insert(d_prog_var[n[i]].begin(), d_prog_var[n[i]].end());
+    }
+    // selectors applied to program variables are also variables
+    if (n.getKind() == APPLY_SELECTOR_TOTAL
+        && d_prog_var[n].find(n[0]) != d_prog_var[n].end())
+    {
+      d_prog_var[n].insert(n);
+    }
+    if (n.getKind() == kind::CHOICE)
+    {
+      d_prog_var.erase(n[0][0]);
     }
   }
 }
@@ -113,7 +124,8 @@ void CegInstantiator::unregisterInstantiationVariable( Node v ) {
 bool CegInstantiator::doAddInstantiation( SolvedForm& sf, unsigned i, unsigned effort ){
   if( i==d_vars.size() ){
     //solved for all variables, now construct instantiation
-    bool needsPostprocess = false;
+    bool needsPostprocess =
+        sf.d_vars.size() > d_vars.size() || !d_var_order_index.empty();
     std::vector< Instantiator * > pp_inst;
     std::map< Instantiator *, Node > pp_inst_to_var;
     std::vector< Node > lemmas;
@@ -522,8 +534,13 @@ bool CegInstantiator::doAddInstantiation( std::vector< Node >& vars, std::vector
 bool CegInstantiator::canApplyBasicSubstitution( Node n, std::vector< Node >& non_basic ){
   Assert( d_prog_var.find( n )!=d_prog_var.end() );
   if( !non_basic.empty() ){
-    for( std::map< Node, bool >::iterator it = d_prog_var[n].begin(); it != d_prog_var[n].end(); ++it ){
-      if( std::find( non_basic.begin(), non_basic.end(), it->first )!=non_basic.end() ){
+    for (std::unordered_set<Node, NodeHashFunction>::iterator it =
+             d_prog_var[n].begin();
+         it != d_prog_var[n].end();
+         ++it)
+    {
+      if (std::find(non_basic.begin(), non_basic.end(), *it) != non_basic.end())
+      {
         return false;
       }
     }
@@ -699,6 +716,7 @@ bool CegInstantiator::check() {
   for( unsigned r=0; r<2; r++ ){
     SolvedForm sf;
     d_stack_vars.clear();
+    d_bound_var_index.clear();
     //try to add an instantiation
     if( doAddInstantiation( sf, 0, r==0 ? 0 : 2 ) ){
       return true;
@@ -979,6 +997,26 @@ Node CegInstantiator::getModelValue( Node n ) {
   return d_qe->getModel()->getValue( n );
 }
 
+Node CegInstantiator::getBoundVariable(TypeNode tn)
+{
+  unsigned index = 0;
+  std::unordered_map<TypeNode, unsigned, TypeNodeHashFunction>::iterator itb =
+      d_bound_var_index.find(tn);
+  if (itb != d_bound_var_index.end())
+  {
+    index = itb->second;
+  }
+  d_bound_var_index[tn] = index + 1;
+  while (index >= d_bound_var[tn].size())
+  {
+    std::stringstream ss;
+    ss << "x" << index;
+    Node x = NodeManager::currentNM()->mkBoundVar(ss.str(), tn);
+    d_bound_var[tn].push_back(x);
+  }
+  return d_bound_var[tn][index];
+}
+
 void CegInstantiator::collectCeAtoms( Node n, std::map< Node, bool >& visited ) {
   if( n.getKind()==FORALL ){
     d_is_nested_quant = true;
@@ -1010,6 +1048,7 @@ void CegInstantiator::registerCounterexampleLemma( std::vector< Node >& lems, st
   //Assert( d_vars.empty() );
   d_vars.clear();
   d_vars.insert( d_vars.end(), ce_vars.begin(), ce_vars.end() );
+  d_vars_set.insert(ce_vars.begin(), ce_vars.end());
 
   //determine variable order: must do Reals before Ints
   if( !d_vars.empty() ){
index 0808b5ed09459623a72533fd5287aab33b7ee670..1e59bfb43d440082df96581c8d3ad5eaed5c5ab7 100644 (file)
@@ -40,8 +40,11 @@ public:
 
 class Instantiator;
 
-//stores properties for a variable to solve for in CEGQI
-//  For LIA, this includes the coefficient of the variable, and the bound type for the variable
+/** Term Properties
+ * stores properties for a variable to solve for in CEGQI
+ *  For LIA, this includes the coefficient of the variable, and the bound type
+ * for the variable.
+ */
 class TermProperties {
 public:
   TermProperties() : d_type(0) {}
@@ -76,9 +79,10 @@ public:
   }
 };
 
-//Solved form
-//  This specifies a substitution:
-//  { d_props[i].getModifiedTerm(d_vars[i]) -> d_subs[i] | i = 0...|d_vars| }
+/** Solved form
+ *  This specifies a substitution:
+ *  { d_props[i].getModifiedTerm(d_vars[i]) -> d_subs[i] | i = 0...|d_vars| }
+ */
 class SolvedForm {
 public:
   // list of variables
@@ -89,7 +93,7 @@ public:
   std::vector< TermProperties > d_props;
   // the variables that have non-basic information regarding how they are substituted
   //   an example is for linear arithmetic, we store "substitution with coefficients".
-  std::vector< Node > d_non_basic;
+  std::vector<Node> d_non_basic;
   // push the substitution pv_prop.getModifiedTerm(pv) -> n
   void push_back( Node pv, Node n, TermProperties& pv_prop ){
     d_vars.push_back( pv );
@@ -134,35 +138,105 @@ public:
   }
 };
 
+/** Ceg instantiator
+ *
+ * This class manages counterexample-guided quantifier instantiation
+ * for a single quantified formula.
+ */
 class CegInstantiator {
-private:
-  QuantifiersEngine * d_qe;
-  CegqiOutput * d_out;
+ private:
+  /** quantified formula associated with this instantiator */
+  QuantifiersEngine* d_qe;
+  /** output channel of this instantiator */
+  CegqiOutput* d_out;
+  /** whether we are using delta for virtual term substitution
+    * (for quantified LRA).
+    */
   bool d_use_vts_delta;
+  /** whether we are using infinity for virtual term substitution
+    * (for quantified LRA).
+    */
   bool d_use_vts_inf;
-  //program variable contains cache
-  std::map< Node, std::map< Node, bool > > d_prog_var;
-  std::map< Node, bool > d_inelig;
-  //current assertions
-  std::map< TheoryId, std::vector< Node > > d_curr_asserts;
-  std::map< Node, std::vector< Node > > d_curr_eqc;
-  std::map< TypeNode, std::vector< Node > > d_curr_type_eqc;
-  //auxiliary variables
-  std::vector< Node > d_aux_vars;
-  // relevant theory ids
-  std::vector< TheoryId > d_tids;
-  //literals to equalities for aux vars
-  std::map< Node, std::map< Node, Node > > d_aux_eq;
-  //the CE variables
-  std::vector< Node > d_vars;
-  //index of variables reported in instantiation
-  std::vector< unsigned > d_var_order_index;
-  //atoms of the CE lemma
+  /** cache from nodes to the set of variables it contains
+    * (from the quantified formula we are instantiating).
+    */
+  std::unordered_map<Node,
+                     std::unordered_set<Node, NodeHashFunction>,
+                     NodeHashFunction>
+      d_prog_var;
+  /** cache of the set of terms that we have established are
+   * ineligible for instantiation.
+    */
+  std::unordered_set<Node, NodeHashFunction> d_inelig;
+  /** current assertions per theory */
+  std::map<TheoryId, std::vector<Node> > d_curr_asserts;
+  /** map from representatives to the terms in their equivalence class */
+  std::map<Node, std::vector<Node> > d_curr_eqc;
+  /** map from types to representatives of that type */
+  std::map<TypeNode, std::vector<Node> > d_curr_type_eqc;
+  /** auxiliary variables
+   * These variables include the result of removing ITE
+   * terms from the quantified formula we are processing.
+   * These variables must be eliminated from constraints
+   * as a preprocess step to check().
+   */
+  std::vector<Node> d_aux_vars;
+  /** relevant theory ids
+   * A list of theory ids that contain at least one
+   * constraint in the body of the quantified formula we
+   * are processing.
+   */
+  std::vector<TheoryId> d_tids;
+  /** literals to equalities for aux vars
+   * This stores entries of the form
+   *   L -> ( k -> t )
+   * where
+   *   k is a variable in d_aux_vars,
+   *   L is a literal that if asserted implies that our
+   *    instantiation should map { k -> t }.
+   * For example, if a term of the form
+   *   ite( C, t1, t2 )
+   * was replaced by k, we get this (top-level) assertion:
+   *   ite( C, k=t1, k=t2 )
+   * The vector d_aux_eq contains the exact form of
+   * the literals in the above constraint that they would
+   * appear in assertions, meaning d_aux_eq may contain:
+   *   t1=k -> ( k -> t1 )
+   *   t2=k -> ( k -> t2 )
+   * where t1=k and t2=k are the rewritten form of
+   * k=t1 and k=t2 respectively.
+   */
+  std::map<Node, std::map<Node, Node> > d_aux_eq;
+  /** the variables we are instantiating
+   * These are the inst constants of the quantified formula
+   * we are processing.
+   */
+  std::vector<Node> d_vars;
+  /** set form of d_vars */
+  std::unordered_set<Node, NodeHashFunction> d_vars_set;
+  /** index of variables reported in instantiation */
+  std::vector<unsigned> d_var_order_index;
+  /** are we handled a nested quantified formula? */
   bool d_is_nested_quant;
-  std::vector< Node > d_ce_atoms;
-  //collect atoms
-  void collectCeAtoms( Node n, std::map< Node, bool >& visited );
-private:
+  /** the atoms of the CE lemma */
+  std::vector<Node> d_ce_atoms;
+  /** cache bound variables for type returned
+   * by getBoundVariable(...).
+   */
+  std::unordered_map<TypeNode, std::vector<Node>, TypeNodeHashFunction>
+      d_bound_var;
+  /** current index of bound variables for type.
+   * The next call to getBoundVariable(...) for
+   * type tn returns the d_bound_var_index[tn]^th
+   * element of d_bound_var[tn], or a fresh variable
+   * if not in bounds.
+   */
+  std::unordered_map<TypeNode, unsigned, TypeNodeHashFunction>
+      d_bound_var_index;
+  /** collect atoms */
+  void collectCeAtoms(Node n, std::map<Node, bool>& visited);
+
+ private:
   //map from variables to their instantiators
   std::map< Node, Instantiator * > d_instantiator;
   //cache of current substitutions tried between register/unregister
@@ -170,7 +244,7 @@ private:
   std::map< Node, unsigned > d_curr_index;
   //stack of temporary variables we are solving (e.g. subfields of datatypes)
   std::vector< Node > d_stack_vars;
-  //used instantiators
+  /** for each variable, the instantiator used for that variable */
   std::map< Node, Instantiator * > d_active_instantiators;
   //register variable
   void registerInstantiationVariable( Node v, unsigned index );
@@ -224,10 +298,16 @@ public:
   CegqiOutput * getOutput() { return d_out; }
   //get quantifiers engine
   QuantifiersEngine* getQuantifiersEngine() { return d_qe; }
-
-//interface for instantiators
-public:
+  //------------------------------interface for instantiators
+  /** push stack variable
+   * This adds a new variable to solve for in the stack
+   * of variables we are processing. This stack is only
+   * used for datatypes, where e.g. the DtInstantiator
+   * solving for a list x may push the stack "variables"
+   * head(x) and tail(x).
+   */
   void pushStackVariable( Node v );
+  /** pop stack variable */
   void popStackVariable();
   /** do add instantiation increment
    *
@@ -248,16 +328,27 @@ public:
                              SolvedForm& sf,
                              unsigned effort,
                              bool revertOnSuccess = false);
+  /** get the current model value of term n */
   Node getModelValue( Node n );
-public:
+  /** get bound variable for type
+   *
+   * This gets the next (canonical) bound variable of
+   * type tn. This can be used for instance when
+   * constructing instantiations that involve choice expressions.
+   */
+  Node getBoundVariable(TypeNode tn);
+  //------------------------------end interface for instantiators
   unsigned getNumCEAtoms() { return d_ce_atoms.size(); }
   Node getCEAtom( unsigned i ) { return d_ce_atoms[i]; }
-  // is eligible
+  /** is n a term that is eligible for instantiation? */
   bool isEligible( Node n );
-  // has variable
+  /** does n have variable pv? */
   bool hasVariable( Node n, Node pv );
+  /** are we using delta for LRA virtual term substitution? */
   bool useVtsDelta() { return d_use_vts_delta; }
+  /** are we using infinity for LRA virtual term substitution? */
   bool useVtsInfinity() { return d_use_vts_inf; }
+  /** are we processing a nested quantified formula? */
   bool hasNestedQuantification() { return d_is_nested_quant; }
 };
 
index 60566da1b5198fd79b38793560b98bfefc7ee0b4..756c63cb426b2426dee57091cf4ba51478062092 100644 (file)
@@ -846,16 +846,21 @@ bool EprInstantiator::processEqualTerms( CegInstantiator * ci, SolvedForm& sf, N
 }
 
 // this class can be used to query the model value through the CegInstaniator class
-class CegInstantiatorBvInverterModelQuery : public BvInverterModelQuery {
-public:
-  CegInstantiatorBvInverterModelQuery( CegInstantiator * ci ) : 
-    BvInverterModelQuery(), d_ci( ci ){}
-  ~CegInstantiatorBvInverterModelQuery(){}
-  // get the model value of n
+class CegInstantiatorBvInverterQuery : public BvInverterQuery
+{
+ public:
+  CegInstantiatorBvInverterQuery(CegInstantiator* ci)
+      : BvInverterQuery(), d_ci(ci)
+  {
+  }
+  ~CegInstantiatorBvInverterQuery() {}
+  /** return the model value of n */
   Node getModelValue( Node n ) {
     return d_ci->getModelValue( n );
   }
-protected:
+  /** get bound variable of type tn */
+  Node getBoundVariable(TypeNode tn) { return d_ci->getBoundVariable(tn); }
+ protected:
   // pointer to class that is able to query model values
   CegInstantiator * d_ci;
 };
@@ -891,10 +896,12 @@ void BvInstantiator::processLiteral(CegInstantiator* ci, SolvedForm& sf,
   std::vector< unsigned > path;
   Node sv = d_inverter->getSolveVariable( pv.getType() );
   Node pvs = ci->getModelValue( pv );
+  Trace("cegqi-bv") << "Get path to pv : " << lit << std::endl;
   Node slit = d_inverter->getPathToPv( lit, pv, sv, pvs, path );
   if( !slit.isNull() ){
-    CegInstantiatorBvInverterModelQuery m( ci );
+    CegInstantiatorBvInverterQuery m(ci);
     unsigned iid = d_inst_id_counter;
+    Trace("cegqi-bv") << "Solve lit to bv inverter : " << slit << std::endl;
     Node inst = d_inverter->solve_bv_lit( sv, slit, path, &m, d_inst_id_to_status[iid] );
     if( !inst.isNull() ){
       inst = Rewriter::rewrite(inst);
@@ -1010,7 +1017,7 @@ bool BvInstantiator::processAssertion(CegInstantiator* ci, SolvedForm& sf,
   if( options::cbqiBv() ){
     // get the best rewritten form of lit for solving for pv 
     //   this should remove instances of non-invertible operators, and "linearize" lit with respect to pv as much as possible
-    Node rlit = rewriteAssertionForSolvePv( pv, lit );
+    Node rlit = rewriteAssertionForSolvePv(ci, pv, lit);
     if( Trace.isOn("cegqi-bv") ){
       Trace("cegqi-bv") << "BvInstantiator::processAssertion : solve " << pv << " in " << lit << std::endl;
       if( lit!=rlit ){
@@ -1139,32 +1146,10 @@ bool BvInstantiator::processAssertions(CegInstantiator* ci, SolvedForm& sf,
   return false;
 }
 
-
-bool BvInstantiator::needsPostProcessInstantiationForVariable( CegInstantiator * ci, SolvedForm& sf, Node pv, unsigned effort ) {
-  // we may need to post-process the instantiation since inversion skolems need to be finalized
-  // TODO : technically skolem functions can appear in datatypes with bit-vector fields. We need to eliminate them there too.
-  return true;
-}
-
-bool BvInstantiator::postProcessInstantiationForVariable( CegInstantiator * ci, SolvedForm& sf, Node pv, unsigned effort, std::vector< Node >& lemmas ) {
-  Trace("cegqi-bv") << "BvInstantiator::postProcessInstantiation " << pv << std::endl;
-  Assert( std::find( sf.d_vars.begin(), sf.d_vars.end(), pv )!=sf.d_vars.end() );
-  unsigned index = std::find( sf.d_vars.begin(), sf.d_vars.end(), pv )-sf.d_vars.begin();
-  Trace("cegqi-bv") << "  postprocess : " << pv << " -> " << sf.d_subs[index] << std::endl;
-  // eliminate skolem functions from the substitution
-  unsigned prev_lem_size = lemmas.size();
-  sf.d_subs[index] = d_inverter->eliminateSkolemFunctions( sf.d_subs[index], lemmas );
-  if( Trace.isOn("cegqi-bv") ){
-    Trace("cegqi-bv") << "  got : " << pv << " -> " << sf.d_subs[index] << std::endl;
-    for( unsigned i=prev_lem_size; i<lemmas.size(); i++ ){
-      Trace("cegqi-bv") << "  side condition : " << lemmas[i] << std::endl;
-    }
-  }
-
-  return true;
-}
-  
-Node BvInstantiator::rewriteAssertionForSolvePv( Node pv, Node lit ) {
+Node BvInstantiator::rewriteAssertionForSolvePv(CegInstantiator* ci,
+                                                Node pv,
+                                                Node lit)
+{
   NodeManager* nm = NodeManager::currentNM();
   // result of rewriting the visited term
   std::unordered_map<TNode, Node, TNodeHashFunction> visited;
@@ -1180,10 +1165,34 @@ Node BvInstantiator::rewriteAssertionForSolvePv( Node pv, Node lit ) {
     it = visited.find(cur);
 
     if (it == visited.end()) {
-      visited[cur] = Node::null();
-      visit.push(cur);
-      for (unsigned i = 0; i < cur.getNumChildren(); i++) {
-        visit.push(cur[i]);
+      if (cur.getKind() == CHOICE)
+      {
+        // must replace variables of choice functions
+        // with new variables to avoid variable
+        // capture when considering substitutions
+        // with multiple literals.
+        Node bv = ci->getBoundVariable(cur[0][0].getType());
+        TNode var = cur[0][0];
+        Node sbody = cur[1].substitute(var, bv);
+        // we cannot cache the results of subterms
+        // of this choice expression since we are
+        // now in the context { cur[0][0] -> bv },
+        // hence we make a separate call to
+        // rewriteAssertionForSolvePv here,
+        // where the recursion depth is the maximum
+        // depth of nested choice expressions.
+        Node rsbody = rewriteAssertionForSolvePv(ci, pv, sbody);
+        visited[cur] =
+            nm->mkNode(CHOICE, nm->mkNode(BOUND_VAR_LIST, bv), rsbody);
+      }
+      else
+      {
+        visited[cur] = Node::null();
+        visit.push(cur);
+        for (unsigned i = 0; i < cur.getNumChildren(); i++)
+        {
+          visit.push(cur[i]);
+        }
       }
     } else if (it->second.isNull()) {
       Node ret;
@@ -1201,24 +1210,11 @@ Node BvInstantiator::rewriteAssertionForSolvePv( Node pv, Node lit ) {
         children.push_back(it->second);
         contains_pv = contains_pv || visited_contains_pv[cur[i]];
       }
-      
-      // [1] rewrite cases of non-invertible operators
-      
-      // if cur is urem( x, y ) where x contains pv but y does not, then
-      // rewrite urem( x, y ) ---> x - udiv( x, y )*y
-      if (cur.getKind()==BITVECTOR_UREM_TOTAL) {
-        if( visited_contains_pv[cur[0]] && !visited_contains_pv[cur[1]] ){
-          ret = nm->mkNode( BITVECTOR_SUB, children[0], 
-                  nm->mkNode( BITVECTOR_MULT,
-                    nm->mkNode( BITVECTOR_UDIV_TOTAL, children[0], children[1] ),
-                    children[1] ) );
-        }
-      }
-      
-      // [2] try to rewrite non-linear literals -> linear literals
-      
-      
-      // return original if the above steps do not produce a result
+
+      // rewrite the term
+      ret = rewriteTermForSolvePv(pv, cur, children, visited_contains_pv);
+
+      // return original if the above function does not produce a result
       if (ret.isNull()) {
         if (childChanged) {
           ret = NodeManager::currentNM()->mkNode(cur.getKind(), children);
@@ -1236,3 +1232,32 @@ Node BvInstantiator::rewriteAssertionForSolvePv( Node pv, Node lit ) {
   return visited[lit];
 }
 
+Node BvInstantiator::rewriteTermForSolvePv(
+    Node pv,
+    Node n,
+    std::vector<Node>& children,
+    std::unordered_map<TNode, bool, TNodeHashFunction>& contains_pv)
+{
+  NodeManager* nm = NodeManager::currentNM();
+
+  // [1] rewrite cases of non-invertible operators
+
+  // if n is urem( x, y ) where x contains pv but y does not, then
+  // rewrite urem( x, y ) ---> x - udiv( x, y )*y
+  if (n.getKind() == BITVECTOR_UREM_TOTAL)
+  {
+    if (contains_pv[n[0]] && !contains_pv[n[1]])
+    {
+      return nm->mkNode(
+          BITVECTOR_SUB,
+          children[0],
+          nm->mkNode(BITVECTOR_MULT,
+                     nm->mkNode(BITVECTOR_UDIV_TOTAL, children[0], children[1]),
+                     children[1]));
+    }
+  }
+
+  // [2] try to rewrite non-linear literals -> linear literals
+
+  return Node::null();
+}
index 9f47e72111db8148cdcbf2dfae789c6bb9ce04a2..30dd1bffad9630c2ba416dda0aa0b8736d0cf933 100644 (file)
@@ -101,7 +101,23 @@ private:
   /** rewrite assertion for solve pv
   * returns a literal that is equivalent to lit that leads to best solved form for pv
   */
-  Node rewriteAssertionForSolvePv( Node pv, Node lit );
+  Node rewriteAssertionForSolvePv(CegInstantiator* ci, Node pv, Node lit);
+  /** rewrite term for solve pv
+   * This is a helper function for rewriteAssertionForSolvePv.
+   * If this returns non-null value ret, then this indicates
+   * that n should be rewritten to ret. It is called as
+   * a "post-rewrite", that is, after the children of n
+   * have been rewritten and stored in the vector children.
+   *
+   * contains_pv stores whether certain nodes contain pv.
+   * where we guarantee that all subterms of terms in children
+   * appear in the domain of contains_pv.
+   */
+  Node rewriteTermForSolvePv(
+      Node pv,
+      Node n,
+      std::vector<Node>& children,
+      std::unordered_map<TNode, bool, TNodeHashFunction>& contains_pv);
   /** process literal, called from processAssertion
   * lit is the literal to solve for pv that has been rewritten according to
   * internal rules here.
@@ -121,8 +137,6 @@ private:
                         Node alit, unsigned effort);
   bool processAssertions(CegInstantiator* ci, SolvedForm& sf, Node pv,
                          unsigned effort);
-  bool needsPostProcessInstantiationForVariable( CegInstantiator * ci, SolvedForm& sf, Node pv, unsigned effort );
-  bool postProcessInstantiationForVariable( CegInstantiator * ci, SolvedForm& sf, Node pv, unsigned effort, std::vector< Node >& lemmas );
   bool useModelValue( CegInstantiator * ci, SolvedForm& sf, Node pv, unsigned effort ) { return true; }
   std::string identify() const { return "Bv"; }
 };
index 4cfdec90e638a841b609e636b961094846422a43..014f06aad241a822e368659978ac05d1f2eada72 100644 (file)
@@ -111,7 +111,10 @@ TESTS =    \
        qbv-test-invert-bvult-1.smt2 \
        intersection-example-onelane.proof-node22337.smt2 \
        nested9_true-unreach-call.i_575.smt2 \
-       small-pipeline-fixpoint-3.smt2
+       small-pipeline-fixpoint-3.smt2 \
+       NUM878.smt2 \
+       psyco-107-bv.smt2 \
+       ari118-bv-2occ-x.smt2
  
 
 # regression can be solved with --finite-model-find --fmf-inst-engine
diff --git a/test/regress/regress0/quantifiers/NUM878.smt2 b/test/regress/regress0/quantifiers/NUM878.smt2
new file mode 100644 (file)
index 0000000..8d78bf8
--- /dev/null
@@ -0,0 +1,7 @@
+; COMMAND-LINE: --cbqi-bv
+; EXPECT: unsat
+(set-logic BV)
+(set-info :status unsat)
+(assert (not (exists ((?X (_ BitVec 32))) (= (bvmul ?X ?X) ?X))))
+(check-sat)
+(exit)
diff --git a/test/regress/regress0/quantifiers/ari118-bv-2occ-x.smt2 b/test/regress/regress0/quantifiers/ari118-bv-2occ-x.smt2
new file mode 100644 (file)
index 0000000..2d70dfb
--- /dev/null
@@ -0,0 +1,8 @@
+; COMMAND-LINE: --cbqi-bv
+; EXPECT: unsat
+(set-logic BV)
+(set-info :status unsat)
+; two occurrences of x
+(assert (not (exists ((?X (_ BitVec 32)) (?Y (_ BitVec 32))) (= (bvmul ?X ?Y) ?X))))
+(check-sat)
+(exit)
diff --git a/test/regress/regress0/quantifiers/psyco-107-bv.smt2 b/test/regress/regress0/quantifiers/psyco-107-bv.smt2
new file mode 100644 (file)
index 0000000..82b54a2
--- /dev/null
@@ -0,0 +1,162 @@
+; COMMAND-LINE: --cbqi-bv --cbqi-bv-ineq=eq-boundary
+; EXPECT: unsat
+(set-logic BV)
+(set-info :status unsat)
+(declare-fun W_S1_V6 () Bool)
+(declare-fun W_S1_V4 () Bool)
+(declare-fun W_S1_V2 () Bool)
+(declare-fun W_S1_V3 () Bool)
+(declare-fun W_S1_V1 () Bool)
+(declare-fun R_E2_V1 () Bool)
+(declare-fun R_E2_V3 () Bool)
+(declare-fun R_E1_V3 () Bool)
+(declare-fun R_E1_V1 () Bool)
+(declare-fun R_E1_V6 () Bool)
+(declare-fun R_E1_V4 () Bool)
+(declare-fun R_E1_V5 () Bool)
+(declare-fun R_E1_V2 () Bool)
+(declare-fun DISJ_W_S1_R_E1 () Bool)
+(declare-fun R_S1_V6 () Bool)
+(declare-fun R_S1_V4 () Bool)
+(declare-fun R_S1_V5 () Bool)
+(declare-fun R_S1_V2 () Bool)
+(declare-fun R_S1_V3 () Bool)
+(declare-fun R_S1_V1 () Bool)
+(declare-fun DISJ_W_S1_R_S1 () Bool)
+(declare-fun R_E2_V6 () Bool)
+(declare-fun R_E2_V4 () Bool)
+(declare-fun R_E2_V5 () Bool)
+(declare-fun R_E2_V2 () Bool)
+(declare-fun DISJ_W_S1_R_E2 () Bool)
+(declare-fun W_S1_V5 () Bool)
+(assert
+ (let
+ (($x59848
+   (forall
+    ((V1_0 (_ BitVec 32)) (V3_0 (_ BitVec 32)) 
+     (V2_0 (_ BitVec 32)) (V5_0 (_ BitVec 32)) 
+     (V4_0 (_ BitVec 32)) (V6_0 (_ BitVec 32)) 
+     (MW_S1_V1 Bool) (MW_S1_V3 Bool) 
+     (MW_S1_V2 Bool) (MW_S1_V5 Bool) 
+     (MW_S1_V4 Bool) (MW_S1_V6 Bool) 
+     (S1_V1_!5000 (_ BitVec 32)) (S1_V3_!5001 (_ BitVec 32)) 
+     (S1_V2_!5002 (_ BitVec 32)) (E1_!4994 (_ BitVec 32)) 
+     (E1_!4997 (_ BitVec 32)) (E1_!4999 (_ BitVec 32)) 
+     (S1_V5_!5003 (_ BitVec 32)) (E2_!4995 (_ BitVec 32)) 
+     (E2_!4996 (_ BitVec 32)) (E2_!4998 (_ BitVec 32)) 
+     (S1_V4_!5004 (_ BitVec 32)) (S1_V6_!5005 (_ BitVec 32)))
+    (let ((?x62719 (ite MW_S1_V6 S1_V6_!5005 V6_0)))
+    (let (($x60064 (= V6_0 ?x62719)))
+    (let ((?x61425 (ite MW_S1_V4 S1_V4_!5004 V4_0)))
+    (let (($x59873 (= V4_0 ?x61425)))
+    (let ((?x59861 (ite MW_S1_V5 S1_V5_!5003 V5_0)))
+    (let (($x62312 (= V5_0 ?x59861)))
+    (let ((?x60966 (ite MW_S1_V2 S1_V2_!5002 V2_0)))
+    (let (($x61331 (= V2_0 ?x60966)))
+    (let ((?x62280 (ite MW_S1_V3 S1_V3_!5001 E2_!4998)))
+    (let ((?x60903 (bvadd (_ bv1 32) ?x62280)))
+    (let (($x61268 (= E2_!4996 ?x60903)))
+    (let ((?x60065 (ite MW_S1_V1 S1_V1_!5000 E1_!4999)))
+    (let (($x60169 (= E1_!4994 ?x60065)))
+    (let (($x62661 (and $x60169 $x61268 $x61331 $x62312 $x59873 $x60064)))
+    (let ((?x62301 (bvadd (bvneg (_ bv1 32)) ?x61425)))
+    (let (($x61124 (bvsge ?x62280 ?x62301)))
+    (let ((?x61096 (bvadd (bvneg (_ bv1 32)) ?x60966)))
+    (let (($x60960 (bvsge ?x60065 ?x61096)))
+    (let (($x62453 (bvsle V2_0 E1_!4999)))
+    (let (($x61140 (not $x62453)))
+    (let (($x60239 (bvsle V4_0 E2_!4998)))
+    (let (($x61367 (not $x60239)))
+    (let (($x59857 (bvsle V2_0 E1_!4997)))
+    (let (($x62570 (not $x59857)))
+    (let ((?x62418 (bvadd (bvneg (_ bv1 32)) V2_0)))
+    (let (($x60189 (bvsge E1_!4994 ?x62418)))
+    (let (($x62421 (bvsge E2_!4996 V4_0)))
+    (let (($x60898 (bvsle V2_0 E1_!4994)))
+    (let (($x59938 (not $x60898)))
+    (let (($x62400 (bvsle V4_0 E2_!4995)))
+    (let (($x60971 (not $x62400)))
+    (let
+    (($x62394
+      (and $x60971 $x59938 $x62421 $x60189 $x62570 $x61367 $x61140 $x60960
+      $x61124)))
+    (let (($x62485 (not $x62394)))
+    (let (($x60905 (not MW_S1_V6)))
+    (let (($x61285 (or $x60905 W_S1_V6)))
+    (let (($x61317 (not MW_S1_V4)))
+    (let (($x60137 (or $x61317 W_S1_V4)))
+    (let (($x62306 (not MW_S1_V2)))
+    (let (($x62708 (or $x62306 W_S1_V2)))
+    (let (($x62310 (not MW_S1_V3)))
+    (let (($x60291 (or $x62310 W_S1_V3)))
+    (let (($x62641 (not MW_S1_V1)))
+    (let (($x61174 (or $x62641 W_S1_V1)))
+    (let (($x62627 (= E2_!4998 E2_!4995)))
+    (let (($x60904 (= E1_!4997 E1_!4994)))
+    (let (($x128 (not R_E2_V1)))
+    (let (($x60161 (or $x128 $x60904)))
+    (let (($x62415 (not $x60161)))
+    (let (($x62645 (or $x62415 $x62627)))
+    (let (($x60924 (= E2_!4996 E2_!4998)))
+    (let (($x62711 (= E2_!4995 V3_0)))
+    (let (($x130 (not R_E2_V3)))
+    (let (($x62623 (or $x130 $x62711)))
+    (let (($x60954 (= E1_!4994 E1_!4997)))
+    (let (($x59868 (or $x128 $x60954)))
+    (let (($x62319 (and $x59868 $x62623)))
+    (let (($x62554 (not $x62319)))
+    (let (($x60985 (or $x62554 $x60924)))
+    (let (($x62256 (= E2_!4996 E2_!4995)))
+    (let (($x62540 (not $x62623)))
+    (let (($x60968 (or $x62540 $x62256)))
+    (let (($x62486 (= E1_!4999 E1_!4997)))
+    (let (($x60109 (= E2_!4998 V3_0)))
+    (let (($x115 (not R_E1_V3)))
+    (let (($x60129 (or $x115 $x60109)))
+    (let (($x60976 (= E1_!4997 V1_0)))
+    (let (($x113 (not R_E1_V1)))
+    (let (($x62568 (or $x113 $x60976)))
+    (let (($x60942 (and $x62568 $x60129)))
+    (let (($x60209 (not $x60942)))
+    (let (($x62263 (or $x60209 $x62486)))
+    (let (($x60965 (= E1_!4999 E1_!4994)))
+    (let (($x62348 (or $x60209 $x60965)))
+    (let
+    (($x60285
+      (and $x60954 $x62348 $x62263 $x60968 $x60985 $x62645 $x61174 $x60291
+      $x62708 $x60137 $x61285)))
+    (let (($x62430 (not $x60285))) (or $x62430 $x62485 $x62661)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
+ (let (($x56 (and W_S1_V6 R_E1_V6)))
+ (let (($x54 (and W_S1_V4 R_E1_V4)))
+ (let (($x50 (and W_S1_V2 R_E1_V2)))
+ (let (($x48 (and W_S1_V3 R_E1_V3)))
+ (let (($x46 (and W_S1_V1 R_E1_V1)))
+ (let (($x69 (or $x46 $x48 $x50 R_E1_V5 $x54 $x56)))
+ (let (($x70 (not $x69)))
+ (let (($x71 (= DISJ_W_S1_R_E1 $x70)))
+ (let (($x40 (and W_S1_V6 R_S1_V6)))
+ (let (($x38 (and W_S1_V4 R_S1_V4)))
+ (let (($x34 (and W_S1_V2 R_S1_V2)))
+ (let (($x32 (and W_S1_V3 R_S1_V3)))
+ (let (($x30 (and W_S1_V1 R_S1_V1)))
+ (let (($x66 (or $x30 $x32 $x34 R_S1_V5 $x38 $x40)))
+ (let (($x67 (not $x66)))
+ (let (($x68 (= DISJ_W_S1_R_S1 $x67)))
+ (let (($x24 (and W_S1_V6 R_E2_V6)))
+ (let (($x21 (and W_S1_V4 R_E2_V4)))
+ (let (($x16 (and W_S1_V2 R_E2_V2)))
+ (let (($x13 (and W_S1_V3 R_E2_V3)))
+ (let (($x10 (and W_S1_V1 R_E2_V1)))
+ (let (($x63 (or $x10 $x13 $x16 R_E2_V5 $x21 $x24)))
+ (let (($x64 (not $x63)))
+ (let (($x65 (= DISJ_W_S1_R_E2 $x64)))
+ (let (($x130 (not R_E2_V3)))
+ (let (($x115 (not R_E1_V3)))
+ (let (($x113 (not R_E1_V1)))
+ (let (($x60916 (and $x113 $x115)))
+ (let (($x62291 (or $x60916 $x130)))
+ (and $x62291 W_S1_V5 $x65 $x68 $x71 $x59848))))))))))))))))))))))))))))))))
+(assert R_E2_V3)
+(check-sat)
+(exit)
+