Do not eliminate variables that are equal to unevaluatable terms (#4267)
authorAndrew Reynolds <andrew.j.reynolds@gmail.com>
Wed, 20 May 2020 02:48:01 +0000 (21:48 -0500)
committerGitHub <noreply@github.com>
Wed, 20 May 2020 02:48:01 +0000 (21:48 -0500)
When we eliminate a variable x -> v during simplification, it may be the case that v contains "unevaluated" operators like forall, choice, etc. Thus, we do not produce correct models for such inputs unless simplification is disabled.

This PR ensures we only eliminate variables when v contains only evaluated operators.

Additionally, the kinds registered as unevaluated were slightly modified so that when we are in a logic like QF_LIA, there are no registered unevaluated operators, hence the check above is unnecessary. This is to minimize the performance impact of this change.

Fixes #4500.

24 files changed:
src/expr/node_algorithm.cpp
src/expr/node_algorithm.h
src/theory/arith/theory_arith.cpp
src/theory/arith/theory_arith.h
src/theory/arith/theory_arith_private.cpp
src/theory/arrays/theory_arrays.cpp
src/theory/builtin/theory_builtin.cpp
src/theory/bv/theory_bv.cpp
src/theory/quantifiers/theory_quantifiers.cpp
src/theory/sets/theory_sets.cpp
src/theory/sets/theory_sets_private.cpp
src/theory/sets/theory_sets_private.h
src/theory/strings/theory_strings.cpp
src/theory/strings/theory_strings.h
src/theory/theory.cpp
src/theory/theory.h
src/theory/theory_model.cpp
src/theory/theory_model.h
test/regress/CMakeLists.txt
test/regress/regress0/quantifiers/quant-model-simplification.smt2 [new file with mode: 0644]
test/regress/regress1/ho/nested_lambdas-AGT034^2.smt2
test/regress/regress1/ho/nested_lambdas-sat-SYO056^1-delta.smt2
test/regress/regress1/sets/choose1.smt2
test/regress/regress1/sets/choose4.smt2

index 0c572f61524e2dce1ebb1d673960d7769c39fabc..44430f072149bb5f61208acc3efa9374eca9cc06 100644 (file)
@@ -155,6 +155,34 @@ bool hasSubtermKind(Kind k, Node n)
   return false;
 }
 
+bool hasSubtermKinds(const std::unordered_set<Kind, kind::KindHashFunction>& ks,
+                     Node n)
+{
+  if (ks.empty())
+  {
+    return false;
+  }
+  std::unordered_set<TNode, TNodeHashFunction> visited;
+  std::vector<TNode> visit;
+  TNode cur;
+  visit.push_back(n);
+  do
+  {
+    cur = visit.back();
+    visit.pop_back();
+    if (visited.find(cur) == visited.end())
+    {
+      if (ks.find(cur.getKind()) != ks.end())
+      {
+        return true;
+      }
+      visited.insert(cur);
+      visit.insert(visit.end(), cur.begin(), cur.end());
+    }
+  } while (!visit.empty());
+  return false;
+}
+
 bool hasSubterm(TNode n, const std::vector<Node>& t, bool strict)
 {
   if (t.empty())
index 5e042d5911ee8b94fb7957e92bd790058deb1531..894dce7c69567261be23ce514e86c5564dba6d34 100644 (file)
@@ -51,6 +51,14 @@ bool hasSubtermMulti(TNode n, TNode t);
  */
 bool hasSubtermKind(Kind k, Node n);
 
+/**
+ * @param ks The kinds of node to check
+ * @param n The node to search in.
+ * @return true iff there is a term in n that has any kind ks
+ */
+bool hasSubtermKinds(const std::unordered_set<Kind, kind::KindHashFunction>& ks,
+                     Node n);
+
 /**
  * Check if the node n has a subterm that occurs in t.
  * @param n The node to search in
index cdb6c77f3688ceb405d6ea305b8bc5dfd9d358e4..e65369f96c83ab8983419a0cd8df622666d8762a 100644 (file)
@@ -63,6 +63,18 @@ void TheoryArith::preRegisterTerm(TNode n){
   d_internal->preRegisterTerm(n);
 }
 
+void TheoryArith::finishInit()
+{
+  TheoryModel* tm = d_valuation.getModel();
+  Assert(tm != nullptr);
+  if (getLogicInfo().isTheoryEnabled(THEORY_ARITH)
+      && getLogicInfo().areTranscendentalsUsed())
+  {
+    // witness is used to eliminate square root
+    tm->setUnevaluatedKind(kind::WITNESS);
+  }
+}
+
 Node TheoryArith::expandDefinition(Node node)
 {
   return d_internal->expandDefinition(node);
index f15db32a1b0540567292cde780148ed8ca190291..8672f71459b523bb8a5cd91dd684b5a66c814ce6 100644 (file)
@@ -58,6 +58,8 @@ public:
    */
   void preRegisterTerm(TNode n) override;
 
+  void finishInit() override;
+
   Node expandDefinition(Node node) override;
 
   void setMasterEqualityEngine(eq::EqualityEngine* eq) override;
index 0f2f4bbf4798cd70257cd9d72d6fbcd19c94011a..7fdab203401cfac16bdad996ef61f7642e2131db 100644 (file)
@@ -1337,7 +1337,8 @@ Theory::PPAssertStatus TheoryArithPrivate::ppAssert(TNode in, SubstitutionMap& o
     if (m.getVarList().singleton()){
       VarList vl = m.getVarList();
       Node var = vl.getNode();
-      if (var.getKind() == kind::VARIABLE){
+      if (var.isVar())
+      {
         // if vl.isIntegral then m.getConstant().isOne()
         if(!vl.isIntegral() || m.getConstant().isOne()){
           minVar = var;
@@ -1362,15 +1363,8 @@ Theory::PPAssertStatus TheoryArithPrivate::ppAssert(TNode in, SubstitutionMap& o
             << minVar << ":" << elim << endl;
         Debug("simplify") << right.size() << endl;
       }
-      else if (expr::hasSubterm(elim, minVar))
-      {
-        Debug("simplify") << "TheoryArithPrivate::solve(): can't substitute "
-                             "due to recursive pattern with sharing: "
-                          << minVar << ":" << elim << endl;
-      }
-      else if (!minVar.getType().isInteger() || right.isIntegral())
+      else if (d_containing.isLegalElimination(minVar, elim))
       {
-        Assert(!expr::hasSubterm(elim, minVar));
         // cannot eliminate integers here unless we know the resulting
         // substitution is integral
         Debug("simplify") << "TheoryArithPrivate::solve(): substitution "
@@ -1382,7 +1376,6 @@ Theory::PPAssertStatus TheoryArithPrivate::ppAssert(TNode in, SubstitutionMap& o
       else
       {
         Debug("simplify") << "TheoryArithPrivate::solve(): can't substitute "
-                             "b/c it's integer: "
                           << minVar << ":" << minVar.getType() << " |-> "
                           << elim << ":" << elim.getType() << endl;
       }
index e4b1e1c4c510243bccda92b40b6ab2b48750ee96..5085c00ec906d167b7840dc535a2285b2a83aa1b 100644 (file)
@@ -355,14 +355,12 @@ Theory::PPAssertStatus TheoryArrays::ppAssert(TNode in, SubstitutionMap& outSubs
     {
       d_ppFacts.push_back(in);
       d_ppEqualityEngine.assertEquality(in, true, in);
-      if (in[0].isVar() && !expr::hasSubterm(in[1], in[0])
-          && (in[1].getType()).isSubtypeOf(in[0].getType()))
+      if (in[0].isVar() && isLegalElimination(in[0], in[1]))
       {
         outSubstitutions.addSubstitution(in[0], in[1]);
         return PP_ASSERT_STATUS_SOLVED;
       }
-      if (in[1].isVar() && !expr::hasSubterm(in[0], in[1])
-          && (in[0].getType()).isSubtypeOf(in[1].getType()))
+      if (in[1].isVar() && isLegalElimination(in[1], in[0]))
       {
         outSubstitutions.addSubstitution(in[1], in[0]);
         return PP_ASSERT_STATUS_SOLVED;
index 1667e55056dddd02234db55fcef8f8412b6fbbbd..a49903f13dd3bbf15ac316be8ce85312770dd709 100644 (file)
@@ -43,10 +43,13 @@ std::string TheoryBuiltin::identify() const
 
 void TheoryBuiltin::finishInit()
 {
-  // choice nodes are not evaluated in getModelValue
-  TheoryModel* theoryModel = d_valuation.getModel();
-  Assert(theoryModel != nullptr);
-  theoryModel->setUnevaluatedKind(kind::WITNESS);
+  // Notice that choice is an unevaluated kind belonging to this theory.
+  // However, it should be set as an unevaluated kind where it is used, e.g.
+  // in the quantifiers theory. This ensures that a logic like QF_LIA, which
+  // includes the builtin theory, does not mark any kinds as unevaluated and
+  // hence it is easy to check for illegal eliminations via TheoryModel
+  // (see TheoryModel::isLegalElimination) since there are no unevaluated kinds
+  // present.
 }
 
 }  // namespace builtin
index 32791415e53337904141add4cf21a0c3677682f6..fd8459641ab75d977ac6c342444f867c1e83e122 100644 (file)
@@ -634,13 +634,13 @@ Theory::PPAssertStatus TheoryBV::ppAssert(TNode in,
   {
     case kind::EQUAL:
     {
-      if (in[0].isVar() && !expr::hasSubterm(in[1], in[0]))
+      if (in[0].isVar() && isLegalElimination(in[0], in[1]))
       {
         ++(d_statistics.d_solveSubstitutions);
         outSubstitutions.addSubstitution(in[0], in[1]);
         return PP_ASSERT_STATUS_SOLVED;
       }
-      if (in[1].isVar() && !expr::hasSubterm(in[0], in[1]))
+      if (in[1].isVar() && isLegalElimination(in[1], in[0]))
       {
         ++(d_statistics.d_solveSubstitutions);
         outSubstitutions.addSubstitution(in[1], in[0]);
@@ -652,7 +652,7 @@ Theory::PPAssertStatus TheoryBV::ppAssert(TNode in,
               && node[0].isConst()))
       {
         Node extract = node[0].isConst() ? node[1] : node[0];
-        if (extract[0].getKind() == kind::VARIABLE)
+        if (extract[0].isVar())
         {
           Node c = node[0].isConst() ? node[0] : node[1];
 
@@ -688,8 +688,11 @@ Theory::PPAssertStatus TheoryBV::ppAssert(TNode in,
           }
           Node concat = utils::mkConcat(children);
           Assert(utils::getSize(concat) == utils::getSize(extract[0]));
-          outSubstitutions.addSubstitution(extract[0], concat);
-          return PP_ASSERT_STATUS_SOLVED;
+          if (isLegalElimination(extract[0], concat))
+          {
+            outSubstitutions.addSubstitution(extract[0], concat);
+            return PP_ASSERT_STATUS_SOLVED;
+          }
         }
       }
     }
index 6407e0d6d50332c89109d526ebbd7599a5aefedc..9242bec7c621e810493325efeb4bb9fcd01decc5 100644 (file)
@@ -58,6 +58,8 @@ void TheoryQuantifiers::finishInit()
   Assert(tm != nullptr);
   tm->setUnevaluatedKind(EXISTS);
   tm->setUnevaluatedKind(FORALL);
+  // witness is used in several instantiation strategies
+  tm->setUnevaluatedKind(WITNESS);
 }
 
 void TheoryQuantifiers::preRegisterTerm(TNode n) {
index 8430987f29c92b09227cede3b56a1b1a13857f60..b5c2590d57e0985eb5226101429d4800c02db7ee 100644 (file)
@@ -56,6 +56,8 @@ void TheorySets::finishInit()
   TheoryModel* tm = d_valuation.getModel();
   Assert(tm != nullptr);
   tm->setUnevaluatedKind(COMPREHENSION);
+  // choice is used to eliminate witness
+  tm->setUnevaluatedKind(WITNESS);
 }
 
 void TheorySets::addSharedTerm(TNode n) {
@@ -123,7 +125,41 @@ Node TheorySets::expandDefinition(Node n)
 }
 
 Theory::PPAssertStatus TheorySets::ppAssert(TNode in, SubstitutionMap& outSubstitutions) {
-  return d_internal->ppAssert( in, outSubstitutions );
+  Debug("sets-proc") << "ppAssert : " << in << std::endl;
+  Theory::PPAssertStatus status = Theory::PP_ASSERT_STATUS_UNSOLVED;
+
+  // this is based off of Theory::ppAssert
+  if (in.getKind() == kind::EQUAL)
+  {
+    if (in[0].isVar() && isLegalElimination(in[0], in[1]))
+    {
+      // We cannot solve for sets if setsExt is enabled, since universe set
+      // may appear when this option is enabled, and solving for such a set
+      // impacts the semantics of universe set, see
+      // regress0/sets/pre-proc-univ.smt2
+      if (!in[0].getType().isSet() || !options::setsExt())
+      {
+        outSubstitutions.addSubstitution(in[0], in[1]);
+        status = Theory::PP_ASSERT_STATUS_SOLVED;
+      }
+    }
+    else if (in[1].isVar() && isLegalElimination(in[1], in[0]))
+    {
+      if (!in[0].getType().isSet() || !options::setsExt())
+      {
+        outSubstitutions.addSubstitution(in[1], in[0]);
+        status = Theory::PP_ASSERT_STATUS_SOLVED;
+      }
+    }
+    else if (in[0].isConst() && in[1].isConst())
+    {
+      if (in[0] != in[1])
+      {
+        status = Theory::PP_ASSERT_STATUS_CONFLICT;
+      }
+    }
+  }
+  return status;
 }
 
 void TheorySets::presolve() {
index fbf1e6fcf5664f5f60871555a0498ec2fdc84577..78f6fa8b5603170fce05068c5aa1db3fcc1c8363 100644 (file)
@@ -1536,46 +1536,6 @@ Node TheorySetsPrivate::getChooseFunction(const TypeNode& setType)
   return chooseSkolem;
 }
 
-Theory::PPAssertStatus TheorySetsPrivate::ppAssert(
-    TNode in, SubstitutionMap& outSubstitutions)
-{
-  Debug("sets-proc") << "ppAssert : " << in << std::endl;
-  Theory::PPAssertStatus status = Theory::PP_ASSERT_STATUS_UNSOLVED;
-
-  // TODO: allow variable elimination for sets when setsExt = true
-
-  // this is based off of Theory::ppAssert
-  if (in.getKind() == kind::EQUAL)
-  {
-    if (in[0].isVar() && !expr::hasSubterm(in[1], in[0])
-        && (in[1].getType()).isSubtypeOf(in[0].getType()))
-    {
-      if (!in[0].getType().isSet() || !options::setsExt())
-      {
-        outSubstitutions.addSubstitution(in[0], in[1]);
-        status = Theory::PP_ASSERT_STATUS_SOLVED;
-      }
-    }
-    else if (in[1].isVar() && !expr::hasSubterm(in[0], in[1])
-             && (in[0].getType()).isSubtypeOf(in[1].getType()))
-    {
-      if (!in[1].getType().isSet() || !options::setsExt())
-      {
-        outSubstitutions.addSubstitution(in[1], in[0]);
-        status = Theory::PP_ASSERT_STATUS_SOLVED;
-      }
-    }
-    else if (in[0].isConst() && in[1].isConst())
-    {
-      if (in[0] != in[1])
-      {
-        status = Theory::PP_ASSERT_STATUS_CONFLICT;
-      }
-    }
-  }
-  return status;
-}
-
 void TheorySetsPrivate::presolve() { d_state.reset(); }
 
 /**************************** eq::NotifyClass *****************************/
index a7e6f69ee6077f29eadbc657cf7b4991008deb58..da42ad1fe50daba4312dcc5f2d4303fa52719688 100644 (file)
@@ -210,8 +210,6 @@ class TheorySetsPrivate {
    * so that it makes theory-specific calls to evaluate interpreted symbols.
    */
   Node expandDefinition(Node n);
-
-  Theory::PPAssertStatus ppAssert(TNode in, SubstitutionMap& outSubstitutions);
   
   void presolve();
 
index b98bd1dea5d658cbe048b5b47cdd9ca10702502d..6f3b4c0cbbe4f1e08226788d1be82b6992da353a 100644 (file)
@@ -135,6 +135,13 @@ TheoryStrings::~TheoryStrings() {
 
 }
 
+void TheoryStrings::finishInit()
+{
+  TheoryModel* tm = d_valuation.getModel();
+  // witness is used to eliminate str.from_code
+  tm->setUnevaluatedKind(WITNESS);
+}
+
 bool TheoryStrings::areCareDisequal( TNode x, TNode y ) {
   Assert(d_equalityEngine.hasTerm(x));
   Assert(d_equalityEngine.hasTerm(y));
index 2e78198e3f5015f6d10cc8e0fe4738cb19053f7d..7c99b6968e17e6bf20aebf50b0cf70ebb1a50f2e 100644 (file)
@@ -108,6 +108,9 @@ class TheoryStrings : public Theory {
                 const LogicInfo& logicInfo);
   ~TheoryStrings();
 
+  /** finish initialization */
+  void finishInit() override;
+
   TheoryRewriter* getTheoryRewriter() override { return &d_rewriter; }
 
   void setMasterEqualityEngine(eq::EqualityEngine* eq) override;
index 635a3216a5587152e2581969873bdf73bec443d4..3069461faef707f5855457e3f7a02a0fc2f62414 100644 (file)
@@ -268,6 +268,28 @@ void Theory::debugPrintFacts() const{
   printFacts(DebugChannel.getStream());
 }
 
+bool Theory::isLegalElimination(TNode x, TNode val)
+{
+  Assert(x.isVar());
+  if (expr::hasSubterm(val, x))
+  {
+    return false;
+  }
+  if (!val.getType().isSubtypeOf(x.getType()))
+  {
+    return false;
+  }
+  if (!options::produceModels())
+  {
+    // don't care about the model, we are fine
+    return true;
+  }
+  // if there is a model object
+  TheoryModel* tm = d_valuation.getModel();
+  Assert(tm != nullptr);
+  return tm->isLegalElimination(x, val);
+}
+
 std::unordered_set<TNode, TNodeHashFunction> Theory::currentlySharedTerms() const{
   std::unordered_set<TNode, TNodeHashFunction> currentlyShared;
   for (shared_terms_iterator i = shared_terms_begin(),
@@ -337,15 +359,13 @@ Theory::PPAssertStatus Theory::ppAssert(TNode in,
     // 1) x is a variable
     // 2) x is not in the term t
     // 3) x : T and t : S, then S <: T
-    if (in[0].isVar() && !expr::hasSubterm(in[1], in[0])
-        && (in[1].getType()).isSubtypeOf(in[0].getType())
+    if (in[0].isVar() && isLegalElimination(in[0], in[1])
         && in[0].getKind() != kind::BOOLEAN_TERM_VARIABLE)
     {
       outSubstitutions.addSubstitution(in[0], in[1]);
       return PP_ASSERT_STATUS_SOLVED;
     }
-    if (in[1].isVar() && !expr::hasSubterm(in[0], in[1])
-        && (in[0].getType()).isSubtypeOf(in[1].getType())
+    if (in[1].isVar() && isLegalElimination(in[1], in[0])
         && in[1].getKind() != kind::BOOLEAN_TERM_VARIABLE)
     {
       outSubstitutions.addSubstitution(in[1], in[0]);
index c777f164f44ca1f09c15da644edf597d4494cf66..366a943ef9f5e7813d30eb0ea7c5f12e22736bbc 100644 (file)
@@ -248,8 +248,24 @@ class Theory {
   void printFacts(std::ostream& os) const;
   void debugPrintFacts() const;
 
-public:
+  /** is legal elimination
+   *
+   * Returns true if x -> val is a legal elimination of variable x. This is
+   * useful for ppAssert, when x = val is an entailed equality. This function
+   * determines whether indeed x can be eliminated from the problem via the
+   * substituion x -> val.
+   *
+   * The following criteria imply that x -> val is *not* a legal elimination:
+   * (1) If x is contained in val,
+   * (2) If the type of val is not a subtype of the type of x,
+   * (3) If val contains an operator that cannot be evaluated, and produceModels
+   * is true. For example, x -> sqrt(2) is not a legal elimination if we
+   * are producing models. This is because we care about the value of x, and
+   * its value must be computed (approximated) by the non-linear solver.
+   */
+  bool isLegalElimination(TNode x, TNode val);
 
+ public:
   /**
    * Return the ID of the theory responsible for the given type.
    */
index f24e4fc669304e8ef3bbe04f4bde1856cea4a516..567b5c4e4e030d81a420282618f7b1d7d1727e55 100644 (file)
@@ -13,6 +13,7 @@
  **/
 #include "theory/theory_model.h"
 
+#include "expr/node_algorithm.h"
 #include "options/quantifiers_options.h"
 #include "options/smt_options.h"
 #include "options/uf_options.h"
@@ -56,7 +57,6 @@ TheoryModel::TheoryModel(context::Context* c,
   {
     setSemiEvaluatedKind(kind::APPLY_UF);
   }
-  setUnevaluatedKind(kind::BOUND_VARIABLE);
 }
 
 TheoryModel::~TheoryModel()
@@ -203,19 +203,20 @@ Node TheoryModel::getModelValue(TNode n) const
   }
   Debug("model-getvalue-debug") << "Get model value " << n << " ... ";
   Debug("model-getvalue-debug") << d_equalityEngine->hasTerm(n) << std::endl;
-  if (n.isConst())
+  Kind nk = n.getKind();
+  if (n.isConst() || nk == BOUND_VARIABLE)
   {
     d_modelCache[n] = n;
     return n;
   }
 
   Node ret = n;
-  Kind nk = n.getKind();
   NodeManager* nm = NodeManager::currentNM();
 
   // if it is an evaluated kind, compute model values for children and evaluate
   if (n.getNumChildren() > 0
-      && d_not_evaluated_kinds.find(nk) == d_not_evaluated_kinds.end())
+      && d_unevaluated_kinds.find(nk) == d_unevaluated_kinds.end()
+      && d_semi_evaluated_kinds.find(nk) == d_semi_evaluated_kinds.end())
   {
     Debug("model-getvalue-debug")
         << "Get model value children " << n << std::endl;
@@ -308,10 +309,8 @@ Node TheoryModel::getModelValue(TNode n) const
   }
 
   // if we are a evaluated or semi-evaluated kind, return an arbitrary value
-  // if we are not in the d_not_evaluated_kinds map, we are evaluated
-  // if we are in the d_semi_evaluated_kinds, we are semi-evaluated
-  if (d_not_evaluated_kinds.find(nk) == d_not_evaluated_kinds.end()
-      || d_semi_evaluated_kinds.find(nk) != d_semi_evaluated_kinds.end())
+  // if we are not in the d_unevaluated_kinds map, we are evaluated
+  if (d_unevaluated_kinds.find(nk) == d_unevaluated_kinds.end())
   {
     if (t.isFunction() || t.isPredicate())
     {
@@ -617,17 +616,18 @@ void TheoryModel::recordModelCoreSymbol(Expr sym)
   d_model_core.insert(Node::fromExpr(sym));
 }
 
-void TheoryModel::setUnevaluatedKind(Kind k)
-{
-  d_not_evaluated_kinds.insert(k);
-}
+void TheoryModel::setUnevaluatedKind(Kind k) { d_unevaluated_kinds.insert(k); }
 
 void TheoryModel::setSemiEvaluatedKind(Kind k)
 {
-  d_not_evaluated_kinds.insert(k);
   d_semi_evaluated_kinds.insert(k);
 }
 
+bool TheoryModel::isLegalElimination(TNode x, TNode val)
+{
+  return !expr::hasSubtermKinds(d_unevaluated_kinds, val);
+}
+
 bool TheoryModel::hasTerm(TNode a)
 {
   return d_equalityEngine->hasTerm( a );
index d984fbc6bf11c43954b949fff089ba1fcf5db99f..1deec82d94a3f3c747a491fb149595e1acf89375 100644 (file)
@@ -266,6 +266,13 @@ public:
    */
   void setUnevaluatedKind(Kind k);
   void setSemiEvaluatedKind(Kind k);
+  /** is legal elimination
+   *
+   * Returns true if x -> val is a legal elimination of variable x.
+   * In particular, this ensures that val does not have any subterms that
+   * are of unevaluated kinds.
+   */
+  bool isLegalElimination(TNode x, TNode val);
   //---------------------------- end building the model
 
   // ------------------- general equality queries
@@ -356,8 +363,8 @@ public:
   std::map<Node, Node> d_approximations;
   /** list of all approximations */
   std::vector<std::pair<Node, Node> > d_approx_list;
-  /** a set of kinds that are not evaluated */
-  std::unordered_set<Kind, kind::KindHashFunction> d_not_evaluated_kinds;
+  /** a set of kinds that are unevaluated */
+  std::unordered_set<Kind, kind::KindHashFunction> d_unevaluated_kinds;
   /** a set of kinds that are semi-evaluated */
   std::unordered_set<Kind, kind::KindHashFunction> d_semi_evaluated_kinds;
   /**
index 8a9151c176982da5b6e67e03fbda6159be6666ee..6f948b02b2b8a3ff257138a5313e7240b74a3f45 100644 (file)
@@ -766,6 +766,7 @@ set(regress_0_tests
   regress0/quantifiers/qbv-test-invert-concat-1.smt2
   regress0/quantifiers/qbv-test-invert-sign-extend.smt2
   regress0/quantifiers/qcf-rel-dom-opt.smt2
+  regress0/quantifiers/quant-model-simplification.smt2
   regress0/quantifiers/rew-to-scala.smt2
   regress0/quantifiers/simp-len.smt2
   regress0/quantifiers/simp-typ-test.smt2
diff --git a/test/regress/regress0/quantifiers/quant-model-simplification.smt2 b/test/regress/regress0/quantifiers/quant-model-simplification.smt2
new file mode 100644 (file)
index 0000000..ce75aff
--- /dev/null
@@ -0,0 +1,9 @@
+; COMMAND-LINE: --finite-model-find
+; EXPECT: sat
+(set-logic UFLIA)
+(set-info :status sat)
+(declare-sort U 0)
+(declare-fun b () Int)
+(declare-fun P (U) Bool)
+(assert (= b (ite (forall ((x U)) (P x)) 2 3)))
+(check-sat)
index 2818452b8727217a4e27399b954c7bda368406fe..731fd4431817412c85481e1ad9205271e6584897 100644 (file)
@@ -1,4 +1,4 @@
-; COMMAND-LINE: --uf-ho --no-check-unsat-cores --no-check-proofs
+; COMMAND-LINE: --uf-ho --no-check-unsat-cores --no-check-proofs --no-produce-models
 ; EXPECT: unsat
 
 (set-logic ALL)
@@ -98,4 +98,4 @@
 (assert (not (mvalid (very_much_likes jan cola))))
 (set-info :filename "AGT034^2")
 
-(check-sat)
\ No newline at end of file
+(check-sat)
index 9211adfb51a58f2a7e817a43ec6ac8f4a454c8a6..6743e00d47f173349acaf55c6c158b2a0cebff9f 100644 (file)
                     (Psi (-> $$unsorted Bool)) (__flatten_var_0 $$unsorted))
             (mor (mnot Phi) Psi __flatten_var_0))))
 
-(declare-fun mbox ((-> $$unsorted $$unsorted Bool) (-> $$unsorted Bool) $$unsorted) Bool)
-(assert (= mbox
+(define-fun mbox () (-> (-> $$unsorted $$unsorted Bool) (-> $$unsorted Bool) $$unsorted Bool)
           (lambda ((R (-> $$unsorted $$unsorted Bool)) (Phi (-> $$unsorted Bool)) (W $$unsorted))
-            (forall ((V $$unsorted)) (or (not (R W V)) (Phi V)) ))))
+            (forall ((V $$unsorted)) (or (not (R W V)) (Phi V)) )))
 
 (assert (not (forall ((R (-> $$unsorted $$unsorted Bool)))
                (mvalid
index 420a0fde0cd5da5f6a76cc1f9b4d31acf42bedf2..0e937169eaba01547b3096834eef331eb3d71809 100644 (file)
@@ -1,4 +1,4 @@
-; COMMAND-LINE: --no-check-models
+; COMMAND-LINE: --quiet
 (set-logic ALL)
 (set-info :status sat)
 (set-option :produce-models true)
index df7c510d3108e29029d29e309309a3ef7f628f52..6cb97c3e31b7fa65c60a66ed47de61686ad7b400 100644 (file)
@@ -1,4 +1,4 @@
-; COMMAND-LINE: --no-check-models
+; COMMAND-LINE: --quiet
 (set-logic ALL)
 (set-info :status sat)
 (set-option :produce-models true)
@@ -6,8 +6,6 @@
 (declare-fun a () Int)
 (assert (not (= A (as emptyset (Set Int)))))
 (assert (member 10 A))
-; this line raises an assertion error
 (assert (= a (choose A)))
-; this line raises an assertion error
 ;(assert (exists ((x Int)) (and (= x (choose A)) (= x a))))
-(check-sat)
\ No newline at end of file
+(check-sat)