Last remaining fixes for eliminating subtyping (#8772)
authorAndrew Reynolds <andrew.j.reynolds@gmail.com>
Mon, 16 May 2022 22:46:41 +0000 (17:46 -0500)
committerGitHub <noreply@github.com>
Mon, 16 May 2022 22:46:41 +0000 (22:46 +0000)
Also fixes a debug failure for the nightlies.

This also changes mkTuple to not rely on subtyping (this method should regardless be deleted from our API, as it is not the recommended way of constructing tuples).

13 files changed:
NEWS.md
src/api/cpp/cvc5.cpp
src/api/cpp/cvc5.h
src/expr/array_store_all.cpp
src/theory/arith/linear/theory_arith_private.cpp
src/theory/arith/nl/ext/monomial_check.cpp
src/theory/sets/term_registry.cpp
src/theory/sets/term_registry.h
test/unit/api/cpp/solver_black.cpp
test/unit/api/java/SolverTest.java
test/unit/api/python/test_solver.py
test/unit/theory/theory_arith_white.cpp
test/unit/util/array_store_all_white.cpp

diff --git a/NEWS.md b/NEWS.md
index b9b13ae83ef6d3bd5a16f8dbe4e7a4db9c301a1d..f2910e9e1004b32e91b1464cbab5a7a946ec5950 100644 (file)
--- a/NEWS.md
+++ b/NEWS.md
@@ -13,6 +13,8 @@ cvc5 1.0.1
   integers and reals. Type rules for other operators like `APPLY_UF` now
   require their arguments to match the type of the function being applied, and
   do not assume integer/real subtyping.
+- The API method `mkTuple` no longer supports casting integers to reals when
+  constructing tuples.
 
 
 cvc5 1.0
index 05e247fd6547dbcb43e2697ae16d9eb1841e4a99..1bbc1bede5344f7d24901efbbe90d13ff9b772fd 100644 (file)
@@ -5145,38 +5145,6 @@ Term Solver::synthFunHelper(const std::string& symbol,
   return Term(this, fun);
 }
 
-Term Solver::ensureTermSort(const Term& term, const Sort& sort) const
-{
-  // Note: Term and sort are checked in the caller to avoid double checks
-  CVC5_API_CHECK(term.getSort() == sort
-                 || (term.getSort().isInteger() && sort.isReal()))
-      << "Expected conversion from Int to Real";
-  //////// all checks before this line
-
-  Sort t = term.getSort();
-  if (term.getSort() == sort)
-  {
-    return term;
-  }
-
-  // Integers are reals, too
-  Assert(t.d_type->isReal());
-  Term res = term;
-  if (t.isInteger())
-  {
-    // Must cast to Real to ensure correct type is passed to parametric type
-    // constructors. We do this cast using division with 1. This has the
-    // advantage wrt using TO_REAL since (constant) division is always included
-    // in the theory.
-    res = Term(this,
-               d_nodeMgr->mkNode(extToIntKind(DIVISION),
-                                 *res.d_node,
-                                 d_nodeMgr->mkConstInt(internal::Rational(1))));
-  }
-  Assert(res.getSort() == sort);
-  return res;
-}
-
 bool Solver::isValidInteger(const std::string& s) const
 {
   //////// all checks before this line
@@ -6023,11 +5991,16 @@ Term Solver::mkTuple(const std::vector<Sort>& sorts,
       << "Expected the same number of sorts and elements";
   CVC5_API_SOLVER_CHECK_SORTS(sorts);
   CVC5_API_SOLVER_CHECK_TERMS(terms);
+  for (size_t i = 0, size = sorts.size(); i < size; i++)
+  {
+    CVC5_API_CHECK(terms[i].getSort() == sorts[i])
+        << "Type mismatch in mkTuple";
+  }
   //////// all checks before this line
   std::vector<internal::Node> args;
   for (size_t i = 0, size = sorts.size(); i < size; i++)
   {
-    args.push_back(*(ensureTermSort(terms[i], sorts[i])).d_node);
+    args.push_back(*terms[i].d_node);
   }
 
   Sort s = mkTupleSortHelper(sorts);
@@ -6194,7 +6167,7 @@ Term Solver::simplify(const Term& term)
   CVC5_API_SOLVER_CHECK_TERM(term);
   //////// all checks before this line
   Term res = Term(this, d_slv->simplify(*term.d_node));
-  Assert(res.getSort().d_type->isSubtypeOf(*term.getSort().d_type));
+  Assert(*res.getSort().d_type == *term.getSort().d_type);
   return res;
   ////////
   CVC5_API_TRY_CATCH_END;
@@ -6335,7 +6308,7 @@ Term Solver::defineFun(const std::string& symbol,
   // SMT-LIB inputs in the Reals theory, where NUMERAL can be used to specify
   // reals. Instead of making our parser for numerals dependent on the logic,
   // we instead allow integers here in this case.
-  CVC5_API_CHECK(term.d_node->getType().isSubtypeOf(*sort.d_type))
+  CVC5_API_CHECK(term.d_node->getType() == *sort.d_type)
       << "Invalid sort of function body '" << term << "', expected '" << sort
       << "'";
 
@@ -6380,7 +6353,7 @@ Term Solver::defineFunRec(const std::string& symbol,
   CVC5_API_SOLVER_CHECK_TERM(term);
   CVC5_API_SOLVER_CHECK_CODOMAIN_SORT(sort);
   // we are permissive with subtypes, similar to defineFun
-  CVC5_API_CHECK(term.d_node->getType().isSubtypeOf(*sort.d_type))
+  CVC5_API_CHECK(term.d_node->getType() == *sort.d_type)
       << "Invalid sort of function body '" << term << "', expected '" << sort
       << "'";
 
@@ -6430,7 +6403,7 @@ Term Solver::defineFunRec(const Term& fun,
     CVC5_API_SOLVER_CHECK_BOUND_VARS_DEF_FUN(fun, bound_vars, domain_sorts);
     Sort codomain = fun.getSort().getFunctionCodomainSort();
     // we are permissive with subtypes, similar to defineFun
-    CVC5_API_CHECK(codomain.d_type->isSubtypeOf(term.d_node->getType()))
+    CVC5_API_CHECK(*codomain.d_type == term.d_node->getType())
         << "Invalid sort of function body '" << term << "', expected '"
         << codomain << "'";
   }
index 975093e8d33ee6a23394d813384246eebcd30585..6ad7b6a392443fad6b911a4308654a084775dfcd 100644 (file)
@@ -3444,8 +3444,7 @@ class CVC5_EXPORT Solver
   Term mkTerm(const Op& op, const std::vector<Term>& children = {}) const;
 
   /**
-   * Create a tuple term. Terms are automatically converted if sorts are
-   * compatible.
+   * Create a tuple term, where terms have the provided sorts.
    * @param sorts The sorts of the elements in the tuple.
    * @param terms The elements in the tuple.
    * @return The tuple Term.
@@ -5056,18 +5055,6 @@ class CVC5_EXPORT Solver
   /** Check whether string s is a valid decimal integer. */
   bool isValidInteger(const std::string& s) const;
 
-  /**
-   * If needed, convert this term to a given sort.
-   * 
-   * The sort of the term must be convertible into the target sort.
-   * Currently only Int to Real conversions are supported.
-   *
-   * @param t The term.
-   * @param s The target sort.
-   * @return The term wrapped into a sort conversion if needed.
-   */
-  Term ensureTermSort(const Term& t, const Sort& s) const;
-
   /**
    * Check that the given term is a valid closed term, which can be used as an
    * argument to, e.g., assert, get-value, block-model-values, etc.
index 1d8487be038174cd71eb85b2eb77358a33d62685..0d027de513bf183c19c81739e2470949ecf5bbe5 100644 (file)
@@ -38,7 +38,7 @@ ArrayStoreAll::ArrayStoreAll(const TypeNode& type, const Node& value)
       type.toString().c_str());
 
   PrettyCheckArgument(
-      value.getType().isComparableTo(type.getArrayConstituentType()),
+      value.getType() == type.getArrayConstituentType(),
       value,
       "expr type `%s' does not match constituent type of array type `%s'",
       value.getType().toString().c_str(),
index 29bec9c2820ddc6caf945929ab4d06538500855b..e97b329638af43ed60837545744b9b5c3df8d781 100644 (file)
@@ -974,7 +974,10 @@ Theory::PPAssertStatus TheoryArithPrivate::ppAssert(
       // x = (p - ax - c) * -1/a
       // Add the substitution if not recursive
       Assert(elim == rewrite(elim));
-
+      if (elim.getType().isInteger() && !minVar.getType().isInteger())
+      {
+        elim = NodeManager::currentNM()->mkNode(kind::TO_REAL, elim);
+      }
       if (right.size() > options().arith.ppAssertMaxSubSize)
       {
         Trace("simplify")
@@ -989,10 +992,6 @@ Theory::PPAssertStatus TheoryArithPrivate::ppAssert(
         // substitution is integral
         Trace("simplify") << "TheoryArithPrivate::solve(): substitution "
                           << minVar << " |-> " << elim << endl;
-        if (elim.getType().isInteger() && !minVar.getType().isInteger())
-        {
-          elim = NodeManager::currentNM()->mkNode(kind::TO_REAL, elim);
-        }
         Assert(elim.getType() == minVar.getType());
         outSubstitutions.addSubstitutionSolved(minVar, elim, tin);
         return Theory::PP_ASSERT_STATUS_SOLVED;
index 479b77130562471a3a5bfe0871afa1be66b08264..f2337a6292d35ac6f42248768e2a0305a5c12a8d 100644 (file)
@@ -720,7 +720,7 @@ void MonomialCheck::assignOrderIds(std::vector<Node>& vars,
 Node MonomialCheck::mkLit(Node a, Node b, int status, bool isAbsolute) const
 {
   NodeManager* nm = NodeManager::currentNM();
-  Assert(a.getType().isComparableTo(b.getType()));
+  Assert(a.getType().isRealOrInt() && b.getType().isRealOrInt());
   if (status == 0)
   {
     Node a_eq_b = mkEquality(a, b);
index e9f2bfa9912b5e02e1e60c4f53b9a187a029fc96..0ea0312c4f4b3bb46b145cc27d5de15193a6806b 100644 (file)
@@ -95,19 +95,6 @@ Node TermRegistry::getUnivSet(TypeNode tn)
   return n;
 }
 
-Node TermRegistry::getTypeConstraintSkolem(Node n, TypeNode tn)
-{
-  std::map<TypeNode, Node>::iterator it = d_tc_skolem[n].find(tn);
-  if (it == d_tc_skolem[n].end())
-  {
-    SkolemManager* sm = NodeManager::currentNM()->getSkolemManager();
-    Node k = sm->mkDummySkolem("tc_k", tn);
-    d_tc_skolem[n][tn] = k;
-    return k;
-  }
-  return it->second;
-}
-
 void TermRegistry::debugPrintSet(Node s, const char* c) const
 {
   if (s.getNumChildren() == 0)
index 1b460dc3cd0b53aa49662f989a439365d0f1554a..d15ae401d25cea54f861773b77503d193b679c01 100644 (file)
@@ -46,18 +46,6 @@ class TermRegistry : protected EnvObj
                InferenceManager& im,
                SkolemCache& skc,
                ProofNodeManager* pnm);
-  /** Get type constraint skolem
-   *
-   * The sets theory solver outputs equality lemmas of the form:
-   *   n = d_tc_skolem[n][tn]
-   * where the type of d_tc_skolem[n][tn] is tn, and the type
-   * of n is not a subtype of tn. This is required to handle benchmarks like
-   *   test/regress/regress0/sets/sets-of-sets-subtypes.smt2
-   * where for s : (Set Int) and t : (Set Real), we have that
-   *   ( s = t ^ y in t ) implies ( exists k : Int. y = k )
-   * The type constraint Skolem for (y, Int) is the skolemization of k above.
-   */
-  Node getTypeConstraintSkolem(Node n, TypeNode tn);
   /** get the proxy variable for set n
    *
    * Proxy variables are used to communicate information that otherwise would
@@ -88,8 +76,6 @@ class TermRegistry : protected EnvObj
   NodeMap d_proxy;
   /** Backwards map of above */
   NodeMap d_proxy_to_term;
-  /** Cache of type constraint skolems (see getTypeConstraintSkolem) */
-  std::map<Node, std::map<TypeNode, Node> > d_tc_skolem;
   /** Map from types to empty set of that type */
   std::map<TypeNode, Node> d_emptyset;
   /** Map from types to universe set of that type */
index da4bef952b8a32e8afb64601f4102b3584885639..7ad259fdb6848b554de781b01375de44f449a65c 100644 (file)
@@ -949,8 +949,9 @@ TEST_F(TestApiBlackSolver, mkTuple)
 {
   ASSERT_NO_THROW(d_solver.mkTuple({d_solver.mkBitVectorSort(3)},
                                    {d_solver.mkBitVector(3, "101", 2)}));
-  ASSERT_NO_THROW(
-      d_solver.mkTuple({d_solver.getRealSort()}, {d_solver.mkInteger("5")}));
+  ASSERT_THROW(
+      d_solver.mkTuple({d_solver.getRealSort()}, {d_solver.mkInteger("5")}),
+      CVC5ApiException);
 
   ASSERT_THROW(d_solver.mkTuple({}, {d_solver.mkBitVector(3, "101", 2)}),
                CVC5ApiException);
index e70e43d0c5a9437f1a0c4512e9a1da65c7de9d8f..f9384c288bdeeff7035c00324323530bb4fd42c7 100644 (file)
@@ -913,9 +913,10 @@ class SolverTest
     assertDoesNotThrow(()
                            -> d_solver.mkTuple(new Sort[] {d_solver.mkBitVectorSort(3)},
                                new Term[] {d_solver.mkBitVector(3, "101", 2)}));
-    assertDoesNotThrow(()
-                           -> d_solver.mkTuple(new Sort[] {d_solver.getRealSort()},
-                               new Term[] {d_solver.mkInteger("5")}));
+    assertThrows(CVC5ApiException.class,
+        ()
+            -> d_solver.mkTuple(new Sort[] {d_solver.getRealSort()},
+                new Term[] {d_solver.mkInteger("5")}));
 
     assertThrows(CVC5ApiException.class,
         () -> d_solver.mkTuple(new Sort[] {}, new Term[] {d_solver.mkBitVector(3, "101", 2)}));
index a8021ff47d22d315e335561b1bb1bd3f075aec95..4e0c4bbb012e5338d63ab0afe908fbe583c2c3ca 100644 (file)
@@ -908,7 +908,8 @@ def test_mk_true(solver):
 def test_mk_tuple(solver):
     solver.mkTuple([solver.mkBitVectorSort(3)],
                    [solver.mkBitVector(3, "101", 2)])
-    solver.mkTuple([solver.getRealSort()], [solver.mkInteger("5")])
+    with pytest.raises(RuntimeError):
+      solver.mkTuple([solver.getRealSort()], [solver.mkInteger("5")])
 
     with pytest.raises(RuntimeError):
         solver.mkTuple([], [solver.mkBitVector(3, "101", 2)])
index 9c5775790629bd7e5c5b163c8533bdff1267ba3c..981b9d3f140c873a940c72449538a66134e8ae1a 100644 (file)
@@ -117,9 +117,10 @@ TEST_F(TestTheoryWhiteArith, int_normal_form)
   ASSERT_EQ(Rewriter::rewrite(absX), absX);
 
   // (exp (+ 2 + x)) --> (* (exp x) (exp 1) (exp 1))
+  Node cr0 = d_nodeManager->mkConstReal(d_zero);
   Node t =
       d_nodeManager->mkNode(EXPONENTIAL, d_nodeManager->mkNode(ADD, c2, xr))
-          .eqNode(c0);
+          .eqNode(cr0);
   ASSERT_EQ(Rewriter::rewrite(Rewriter::rewrite(t)), Rewriter::rewrite(t));
 }
 }  // namespace test
index 91e3e0d26f79327027ce4d3a57982111776e1d89..ba1054a850a567a48b21daa2f97c238021a53ee2 100644 (file)
@@ -37,7 +37,7 @@ TEST_F(TestUtilWhiteArrayStoreAll, store_all)
                 d_nodeManager->mkConst(UninterpretedSortValue(usort, 0)));
   ArrayStoreAll(d_nodeManager->mkArrayType(d_nodeManager->mkBitVectorType(8),
                                            d_nodeManager->realType()),
-                d_nodeManager->mkConstInt(Rational(0)));
+                d_nodeManager->mkConstReal(Rational(0)));
   ArrayStoreAll(d_nodeManager->mkArrayType(d_nodeManager->mkBitVectorType(8),
                                            d_nodeManager->integerType()),
                 d_nodeManager->mkConstInt(Rational(0)));
@@ -57,6 +57,11 @@ TEST_F(TestUtilWhiteArrayStoreAll, type_errors)
                                                d_nodeManager->mkSort("U")),
                     d_nodeManager->mkConstReal(Rational(9, 2))),
       IllegalArgumentException);
+  ASSERT_THROW(ArrayStoreAll(
+      d_nodeManager->mkArrayType(d_nodeManager->mkBitVectorType(8),
+                                 d_nodeManager->realType()),
+      d_nodeManager->mkConstInt(Rational(0))),
+      IllegalArgumentException);
 }
 
 TEST_F(TestUtilWhiteArrayStoreAll, const_error)