Preserve types in rewriter and make core type rules strict (#8740)
authorAndrew Reynolds <andrew.j.reynolds@gmail.com>
Thu, 12 May 2022 17:48:27 +0000 (12:48 -0500)
committerGitHub <noreply@github.com>
Thu, 12 May 2022 17:48:27 +0000 (17:48 +0000)
This is the key step for eliminating the use of subtyping.

This makes several changes:
(1) CONST_INTEGER is now used for integer constants, which is now exported in the API. The type rule for CONST_RATIONAL is changed to always return Real, even if its value is integral. This means we can distinguish real and integer versions of the integers. Note this also implies that the rewriter now fully preserves types, as rewriting TO_REAL applied to a constant integer will return a constant integral rational.
(2) The type rules for EQUAL, DISTINCT, ITE and APPLY_UF are made strict, in other words, we given a type exception for equalities between an Int and a Real. This restriction impacts the API.
(3) The arithmetic rewrite for (Real) equality casts integers to reals as needed to ensure Reals are only made equal to Reals. The net effect is that TO_REAL may appear on either side of equalities.
(4) The core arithmetic theory solver is modified in several places to be made robust to TO_REAL occurring as the top symbol of sides of equality.

Several assertions are strengthened or added to ensure that equalities and substitutions are between terms of the same type, when it is necessary to do so.

Two quantifiers regressions are modified since the solving techniques are not robust to TO_REAL. A few unit tests are fixed to use proper types.

39 files changed:
NEWS.md
src/api/cpp/cvc5.cpp
src/api/cpp/cvc5.h
src/api/cpp/cvc5_kind.h
src/expr/mkmetakind
src/expr/node_manager_template.cpp
src/parser/smt2/smt2.cpp
src/printer/smt2/smt2_printer.cpp
src/prop/prop_engine.cpp
src/theory/arith/arith_msum.cpp
src/theory/arith/linear/congruence_manager.cpp
src/theory/arith/linear/constraint.cpp
src/theory/arith/linear/normal_form.cpp
src/theory/arith/nl/nl_model.cpp
src/theory/arith/rewriter/rewrite_atom.cpp
src/theory/arith/theory_arith.cpp
src/theory/arith/theory_arith_type_rules.cpp
src/theory/booleans/theory_bool_type_rules.cpp
src/theory/builtin/theory_builtin_type_rules.cpp
src/theory/datatypes/sygus_datatype_utils.cpp
src/theory/quantifiers/cegqi/ceg_instantiator.cpp
src/theory/quantifiers/fmf/full_model_check.cpp
src/theory/quantifiers/fmf/full_model_check.h
src/theory/quantifiers/sygus/type_info.cpp
src/theory/rewriter.cpp
src/theory/theory_engine.cpp
src/theory/theory_model.cpp
src/theory/uf/theory_uf_type_rules.cpp
test/regress/cli/regress0/nl/issue8744-int.smt2
test/regress/cli/regress0/nl/issue8744-real-cov.smt2
test/regress/cli/regress0/nl/issue8744-real.smt2
test/regress/cli/regress0/nl/nta/issue8147-unc-model.smt2
test/regress/cli/regress1/fmf/issue3626.smt2
test/regress/cli/regress1/fmf/sort-inf-int-real.smt2
test/regress/cli/regress1/nl/bad-050217.smt2
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

diff --git a/NEWS.md b/NEWS.md
index 98fc47dcb111ee629806101e6bdc1cf8be756143..b9b13ae83ef6d3bd5a16f8dbe4e7a4db9c301a1d 100644 (file)
--- a/NEWS.md
+++ b/NEWS.md
@@ -7,6 +7,12 @@ cvc5 1.0.1
 
 - Removed support for non-standard `declare-funs`, `declare-consts`, and
   `declare-sorts` commands.
+- The kind for integer constants is now `CONST_INTEGER`, while real constants
+  continue to have kind `CONST_RATIONAL`.
+- Type rules for (dis)equality and if-then-else no longer allow mixing
+  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.
 
 
 cvc5 1.0
index e0999dbff92402b059b06fbb8e7d481d30dfc699..29208c2cdbd5def836359e9d2b6052e61d26eaa5 100644 (file)
@@ -168,6 +168,7 @@ const static std::unordered_map<Kind, std::pair<internal::Kind, std::string>>
         KIND_ENUM(ARCCOTANGENT, internal::Kind::ARCCOTANGENT),
         KIND_ENUM(SQRT, internal::Kind::SQRT),
         KIND_ENUM(CONST_RATIONAL, internal::Kind::CONST_RATIONAL),
+        KIND_ENUM(CONST_INTEGER, internal::Kind::CONST_INTEGER),
         KIND_ENUM(LT, internal::Kind::LT),
         KIND_ENUM(LEQ, internal::Kind::LEQ),
         KIND_ENUM(GT, internal::Kind::GT),
@@ -465,6 +466,7 @@ const static std::unordered_map<internal::Kind,
         {internal::Kind::SQRT, SQRT},
         {internal::Kind::DIVISIBLE_OP, DIVISIBLE},
         {internal::Kind::CONST_RATIONAL, CONST_RATIONAL},
+        {internal::Kind::CONST_INTEGER, CONST_INTEGER},
         {internal::Kind::LT, LT},
         {internal::Kind::LEQ, LEQ},
         {internal::Kind::GT, GT},
index 5043970d9cb3c523a14197c868caa994206831cf..0e7dd5da33da54938b49a7c60c3e99145e2f6c99 100644 (file)
@@ -1390,51 +1390,60 @@ class CVC5_EXPORT Term
   int32_t getRealOrIntegerValueSign() const;
   /**
    * @return True if the term is an integer value that fits within int32_t.
+   * Note that this method will return true for integer constants and real
+   * constants that have integer value.
    */
   bool isInt32Value() const;
   /**
-   * Get the `int32_t` representation of  this integer value.
+   * Get the `int32_t` representation of this integral value.
    * @note Asserts isInt32Value().
    * @return This integer value as a `int32_t`.
    */
   int32_t getInt32Value() const;
   /**
    * @return True if the term is an integer value that fits within uint32_t.
+   * Note that this method will return true for integer constants and real
+   * constants that have integral value.
    */
   bool isUInt32Value() const;
   /**
-   * Get the `uint32_t` representation of this integer value.
+   * Get the `uint32_t` representation of this integral value.
    * @note Asserts isUInt32Value().
    * @return This integer value as a `uint32_t`.
    */
   uint32_t getUInt32Value() const;
   /**
    * @return True if the term is an integer value that fits within int64_t.
+   * Note that this method will return true for integer constants and real
+   * constants that have integral value.
    */
   bool isInt64Value() const;
   /**
-   * Get the `int64_t` representation of this integer value.
+   * Get the `int64_t` representation of this integral value.
    * @note Asserts isInt64Value().
    * @return This integer value as a `int64_t`.
    */
   int64_t getInt64Value() const;
   /**
    * @return True if the term is an integer value that fits within uint64_t.
+   * Note that this method will return true for integer constants and real
+   * constants that have integral value.
    */
   bool isUInt64Value() const;
   /**
-   * Get the `uint64_t` representation of this integer value.
+   * Get the `uint64_t` representation of this integral value.
    * @note Asserts isUInt64Value().
    * @return This integer value as a `uint64_t`.
    */
   uint64_t getUInt64Value() const;
   /**
-   * @return True if the term is an integer value.
+   * @return True if the term is an integer constant or a real constant that
+   * has an integral value.
    */
   bool isIntegerValue() const;
   /**
    * @note Asserts isIntegerValue().
-   * @return The integer term in (decimal) string representation.
+   * @return The integral term in (decimal) string representation.
    */
   std::string getIntegerValue() const;
 
index a7fa5644c658e381dc37338447198baaad89f123..2e1fc435fd78b09a36929a7cd670aa4b2a4614cf 100644 (file)
@@ -903,17 +903,24 @@ enum Kind : int32_t
    */
   DIVISIBLE,
   /**
-   * Multiple-precision rational constant.
+   * Arbitrary-precision rational constant.
    *
    * - Create Term of this Kind with:
    *
-   *   - Solver::mkInteger(const std::string&) const
-   *   - Solver::mkInteger(int64_t) const
    *   - Solver::mkReal(const std::string&) const
    *   - Solver::mkReal(int64_t) const
    *   - Solver::mkReal(int64_t, int64_t) const
    */
   CONST_RATIONAL,
+  /**
+   * Arbitrary-precision integer constant.
+   *
+   * - Create Term of this Kind with:
+   *
+   *   - Solver::mkInteger(const std::string&) const
+   *   - Solver::mkInteger(int64_t) const
+   */
+  CONST_INTEGER,
   /**
    * Less than, chainable.
    *
index c11ec8df2ca19959ccf2cd6661bac1dbe3ae8289..874a6c16ec4c1a953c2d05500afb5d336c5addcd 100755 (executable)
@@ -265,8 +265,8 @@ $2 ${class};"
 
 template <>
 ${class} const& NodeValue::getConst< ${class} >() const {
-  AssertArgument(getKind() == ::cvc5::internal::kind::$1, *this,
-                 \"Improper kind for getConst<${class}>()\");
+  //AssertArgument(getKind() == ::cvc5::internal::kind::$1, *this,
+  //               \"Improper kind for getConst<${class}>()\");
   // To support non-inlined CONSTANT-kinded NodeValues (those that are
   // \"constructed\" when initially checking them against the NodeManager
   // pool), we must check d_nchildren here.
index 419cf50556293cc16300dd0e07298b7d7a295d57..6259971cca420cb65ca1509af27d3ce6e91930ae 100644 (file)
@@ -1337,9 +1337,8 @@ Node NodeManager::mkConstReal(const Rational& r)
 
 Node NodeManager::mkConstInt(const Rational& r)
 {
-  // !!!! Note will update to CONST_INTEGER.
   Assert(r.isIntegral());
-  return mkConst(kind::CONST_RATIONAL, r);
+  return mkConst(kind::CONST_INTEGER, r);
 }
 
 Node NodeManager::mkConstRealOrInt(const Rational& r)
index dad36788ea4dcbaa56a3cd40ab71b6f53b6a7cb1..cf28d0ac8cafbb5766e767a82b771f9d06d2ec77 100644 (file)
@@ -1342,10 +1342,7 @@ cvc5::Term Smt2::mkAnd(const std::vector<cvc5::Term>& es) const
 
 bool Smt2::isConstInt(const cvc5::Term& t)
 {
-  cvc5::Kind k = t.getKind();
-  // !!! Note when arithmetic subtyping is eliminated, this will update to
-  // CONST_INTEGER.
-  return k == cvc5::CONST_RATIONAL && t.getSort().isInteger();
+  return t.getKind() == cvc5::CONST_INTEGER;
 }
 
 }  // namespace parser
index 3cda30e18190138d84f51bc1b48542dc2e1f172a..8f879916f90e093b9b1d9f82c96da208012bfa30 100644 (file)
@@ -66,11 +66,11 @@ namespace smt2 {
 
 static void toStreamRational(std::ostream& out,
                              const Rational& r,
-                             bool decimal,
+                             bool isReal,
                              Variant v)
 {
   bool neg = r.sgn() < 0;
-  // Print the rational, possibly as decimal.
+  // Print the rational, possibly as a real.
   // Notice that we print (/ (- 5) 3) instead of (- (/ 5 3)),
   // the former is compliant with real values in the smt lib standard.
   if (r.isIntegral())
@@ -83,7 +83,7 @@ static void toStreamRational(std::ostream& out,
     {
       out << r;
     }
-    if (decimal)
+    if (isReal)
     {
       out << ".0";
     }
@@ -94,6 +94,7 @@ static void toStreamRational(std::ostream& out,
   }
   else
   {
+    Assert (isReal);
     out << "(/ ";
     if (neg)
     {
@@ -243,6 +244,12 @@ void Smt2Printer::toStream(std::ostream& out,
       out << smtKindString(n.getConst<Kind>(), d_variant);
       break;
     case kind::CONST_RATIONAL: {
+      const Rational& r = n.getConst<Rational>();
+      toStreamRational(out, r, true, d_variant);
+      break;
+    }
+    case kind::CONST_INTEGER:
+    {
       const Rational& r = n.getConst<Rational>();
       toStreamRational(out, r, false, d_variant);
       break;
@@ -509,7 +516,8 @@ void Smt2Printer::toStream(std::ostream& out,
       // the logic is mixed int/real. The former occurs more frequently.
       bool is_int = force_nt.isInteger();
       // If constant rational, print as special case
-      if (type_asc_arg.getKind() == kind::CONST_RATIONAL)
+      Kind ka = type_asc_arg.getKind();
+      if (ka == kind::CONST_RATIONAL || ka == kind::CONST_INTEGER)
       {
         const Rational& r = type_asc_arg.getConst<Rational>();
         toStreamRational(out, r, !is_int, d_variant);
index fdbcf96675a2ddebb3a9c118db4b23425dc03204..4ee596f6f979ef0c0f1ac6c61669df8a704c3e5f 100644 (file)
@@ -175,6 +175,7 @@ void PropEngine::notifyTopLevelSubstitution(const Node& lhs,
     Node eq = SkolemManager::getOriginalForm(lhs.eqNode(rhs));
     output(OutputTag::SUBS) << "(substitution " << eq << ")" << std::endl;
   }
+  Assert(lhs.getType() == rhs.getType());
 }
 
 void PropEngine::assertInputFormulas(
index c3b18ac6b95095ff7db80a40ad17ab179de620ab..354982350b2670df5a2d1487d6a17342ecd61c9d 100644 (file)
@@ -242,6 +242,7 @@ int ArithMSum::isolate(
       }
       // note that conversely this utility will never use a real value as
       // the solution for an integer, thus the types should match now
+      Assert(val.getType() == vc.getType());
     }
     veq = nm->mkNode(k, inOrder ? vc : val, inOrder ? val : vc);
   }
index 8ab23f79cb1d477ded5e3e51124d464b7dd5be8b..bcceb37d0b1dfbf31f4fe8b829d067579ee051db 100644 (file)
@@ -444,8 +444,9 @@ void ArithCongruenceManager::addWatchedPair(ArithVar s, TNode x, TNode y){
   ++(d_statistics.d_watchedVariables);
 
   d_watchedVariables.add(s);
-
-  Node eq = x.eqNode(y);
+  // must ensure types are correct, thus, add TO_REAL if necessary here
+  std::pair<Node, Node> p = mkSameType(x, y);
+  Node eq = p.first.eqNode(p.second);
   d_watchedEqualities.set(s, eq);
 }
 
index 628750973856f528866234496dc550e15f489047..71daeed581510c03514e0164a11a7370939aa96c 100644 (file)
@@ -658,8 +658,11 @@ bool Constraint::sanityChecking(Node n) const {
   Kind k = cmp.comparisonKind();
   Polynomial pleft = cmp.normalizedVariablePart();
   Assert(k == EQUAL || k == DISTINCT || pleft.leadingCoefficientIsPositive());
-  Assert(k != EQUAL || Monomial::isMember(n[0]));
-  Assert(k != DISTINCT || Monomial::isMember(n[0][0]));
+  Assert(k != EQUAL
+         || Monomial::isMember(n[0].getKind() == TO_REAL ? n[0][0] : n[0]));
+  Assert(k != DISTINCT
+         || Monomial::isMember(n[0][0].getKind() == TO_REAL ? n[0][0][0]
+                                                            : n[0][0]));
 
   TNode left = pleft.getNode();
   DeltaRational right = cmp.normalizedDeltaRational();
index 1002235966f1134815b9d6ac0e4a1ea156a5ee20..41d6db8979e988bd78ad116ee4a47f502d937cf7 100644 (file)
@@ -961,13 +961,21 @@ Polynomial Comparison::getLeft() const {
   switch(k){
   case kind::LT:
   case kind::LEQ:
+    left = getNode()[0][0];
+    Assert(left.getKind() != kind::TO_REAL);
+    break;
   case kind::DISTINCT:
     left = getNode()[0][0];
+    left = left.getKind() == kind::TO_REAL ? left[0] : left;
     break;
   case kind::EQUAL:
+    left = getNode()[0];
+    left = left.getKind() == kind::TO_REAL ? left[0] : left;
+    break;
   case kind::GT:
   case kind::GEQ:
     left = getNode()[0];
+    Assert(left.getKind() != kind::TO_REAL);
     break;
   default: Unhandled() << k;
   }
@@ -980,13 +988,21 @@ Polynomial Comparison::getRight() const {
   switch(k){
   case kind::LT:
   case kind::LEQ:
+    right = getNode()[0][1];
+    Assert(right.getKind() != kind::TO_REAL);
+    break;
   case kind::DISTINCT:
     right = getNode()[0][1];
+    right = right.getKind() == kind::TO_REAL ? right[0] : right;
     break;
   case kind::EQUAL:
+    right = getNode()[1];
+    right = right.getKind() == kind::TO_REAL ? right[0] : right;
+    break;
   case kind::GT:
   case kind::GEQ:
     right = getNode()[1];
+    Assert(right.getKind() != kind::TO_REAL);
     break;
   default: Unhandled() << k;
   }
index 4add4e798a11f695e4950f4ce14f66a858ba75ee..55f327b3a3c0cb856c8de8b3084773383d28687e 100644 (file)
@@ -126,6 +126,7 @@ Node NlModel::computeModelValue(TNode n, bool isConcrete)
   }
   Trace("nl-ext-mv-debug") << "computed " << (isConcrete ? "M" : "M_A") << "["
                            << n << "] = " << ret << std::endl;
+  Assert(n.getType() == ret.getType());
   cache[n] = ret;
   return ret;
 }
index f12124a4e52016e931d6156b0ef9abf701d019bf..ebd94c16b991d4d74e8c613897ef3c12b5651b8c 100644 (file)
@@ -297,7 +297,10 @@ Node buildIntegerEquality(Sum&& sum)
   Trace("arith-rewriter::debug")
       << "\tbuilding " << left << " = " << sum << std::endl;
 
-  return buildRelation(Kind::EQUAL, left, collectSum(sum));
+  Node rhs = collectSum(sum);
+  Assert(left.getType().isInteger());
+  Assert(rhs.getType().isInteger());
+  return buildRelation(Kind::EQUAL, left, rhs);
 }
 
 Node buildRealEquality(Sum&& sum)
@@ -313,7 +316,15 @@ Node buildRealEquality(Sum&& sum)
   {
     s.second = s.second / lcoeff;
   }
-  return buildRelation(Kind::EQUAL, lterm.first, collectSum(sum));
+  // Must ensure real for both sides. This may change one but not both
+  // terms.
+  Node lhs = lterm.first;
+  lhs = ensureReal(lhs);
+  Node rhs = collectSum(sum);
+  rhs = ensureReal(rhs);
+  Assert(lhs.getType().isReal() && !lhs.getType().isInteger());
+  Assert(rhs.getType().isReal() && !rhs.getType().isInteger());
+  return buildRelation(Kind::EQUAL, lhs, rhs);
 }
 
 Node buildIntegerInequality(Sum&& sum, Kind k)
index 4e8e1a40928ab75f432348d52c7cc3bad146ca0b..bd1a04dfd1f117ca19c7df31488beea34ea4dc1d 100644 (file)
@@ -293,8 +293,8 @@ bool TheoryArith::collectModelValues(TheoryModel* m,
     {
       continue;
     }
-    // maps to constant of comparable type
-    Assert(p.first.getType().isComparableTo(p.second.getType()));
+    // maps to constant of same type
+    Assert(p.first.getType() == p.second.getType());
     if (m->assertEquality(p.first, p.second, true))
     {
       continue;
@@ -395,8 +395,7 @@ bool TheoryArith::sanityCheckIntegerModel()
   {
     for (CVC5_UNUSED const auto& p : d_arithModelCache)
     {
-      // will change to strict type equal
-      Assert(p.second.getType().isSubtypeOf(p.second.getType()));
+      Assert(p.first.getType() == p.second.getType());
     }
   }
   bool addedLemma = false;
index 31dede3a953d20b7bd5b5b94d2d2cf5c0989762d..b709e2d6a4fc0d78222a6b89996489087223dd0f 100644 (file)
@@ -25,12 +25,23 @@ TypeNode ArithConstantTypeRule::computeType(NodeManager* nodeManager,
                                             TNode n,
                                             bool check)
 {
-  Assert(n.getKind() == kind::CONST_RATIONAL);
-  if (n.getConst<Rational>().isIntegral())
+  // we use different kinds for constant integers and reals
+  if (n.getKind() == kind::CONST_RATIONAL)
   {
-    return nodeManager->integerType();
+    // constant rationals are always real type, even if their value is integral
+    return nodeManager->realType();
   }
-  return nodeManager->realType();
+  Assert(n.getKind() == kind::CONST_INTEGER);
+  // constant integers should always have integral value
+  if (check)
+  {
+    if (!n.getConst<Rational>().isIntegral())
+    {
+      throw TypeCheckingExceptionPrivate(
+          n, "making an integer constant from a non-integral rational");
+    }
+  }
+  return nodeManager->integerType();
 }
 
 TypeNode ArithRealAlgebraicNumberOpTypeRule::computeType(
index 65b69a91f12d192f050be549f766d8f0f100f824..43a3b9c0608f4bd5ce63046c0e938d926aac2285 100644 (file)
@@ -47,28 +47,25 @@ TypeNode BooleanTypeRule::computeType(NodeManager* nodeManager,
 TypeNode IteTypeRule::computeType(NodeManager* nodeManager, TNode n, bool check)
 {
   TypeNode thenType = n[1].getType(check);
-  TypeNode elseType = n[2].getType(check);
-  TypeNode iteType = TypeNode::leastCommonTypeNode(thenType, elseType);
   if (check)
   {
-    TypeNode booleanType = nodeManager->booleanType();
-    if (n[0].getType(check) != booleanType)
-    {
-      throw TypeCheckingExceptionPrivate(n, "condition of ITE is not Boolean");
-    }
-    if (iteType.isNull())
+    TypeNode elseType = n[2].getType(check);
+    if (thenType != elseType)
     {
       std::stringstream ss;
-      ss << "Both branches of the ITE must be a subtype of a common type."
-         << std::endl
+      ss << "Branches of the ITE must have the same type." << std::endl
          << "then branch: " << n[1] << std::endl
          << "its type   : " << thenType << std::endl
          << "else branch: " << n[2] << std::endl
          << "its type   : " << elseType << std::endl;
       throw TypeCheckingExceptionPrivate(n, ss.str());
     }
+    if (!n[0].getType(check).isBoolean())
+    {
+      throw TypeCheckingExceptionPrivate(n, "condition of ITE is not Boolean");
+    }
   }
-  return iteType;
+  return thenType;
 }
 
 }  // namespace boolean
index b7698b23e4cc93d5e9ff4f14e056f03b42ffe1ea..cd3c1250ddbd86f8466c5d8cdfd751976f343e9c 100644 (file)
@@ -34,17 +34,16 @@ TypeNode EqualityTypeRule::computeType(NodeManager* nodeManager,
     TypeNode lhsType = n[0].getType(check);
     TypeNode rhsType = n[1].getType(check);
 
-    if (TypeNode::leastCommonTypeNode(lhsType, rhsType).isNull())
+    if (lhsType != rhsType)
     {
       std::stringstream ss;
-      ss << "Subexpressions must have a common base type:" << std::endl;
+      ss << "Subexpressions must have the same type:" << std::endl;
       ss << "Equation: " << n << std::endl;
       ss << "Type 1: " << lhsType << std::endl;
       ss << "Type 2: " << rhsType << std::endl;
 
       throw TypeCheckingExceptionPrivate(n, ss.str());
     }
-    // TODO : check isFirstClass for these types? (github issue #1202)
   }
   return booleanType;
 }
@@ -61,8 +60,7 @@ TypeNode DistinctTypeRule::computeType(NodeManager* nodeManager,
     for (++child_it; child_it != child_it_end; ++child_it)
     {
       TypeNode currentType = (*child_it).getType();
-      joinType = TypeNode::leastCommonTypeNode(joinType, currentType);
-      if (joinType.isNull())
+      if (joinType != currentType)
       {
         throw TypeCheckingExceptionPrivate(
             n, "Not all arguments are of the same type");
index 6b833cb8138ffc62e422d9fe0bda35e57a3b74e8..ca5c4419c6e17a7abf9bb2d0d4f4dc579520e114 100644 (file)
@@ -170,7 +170,9 @@ Node mkSygusTerm(const DType& dt,
       opn = getExpandedDefinitionForm(op);
     }
   }
-  return mkSygusTerm(opn, children, doBetaReduction);
+  Node ret = mkSygusTerm(opn, children, doBetaReduction);
+  Assert(ret.getType() == dt.getSygusType());
+  return ret;
 }
 
 Node mkSygusTerm(Node op,
index 5320638bed9850ecca7471bbc7f81f490ac9ca5c..8ef7f3d6fcb36803feb11a3c414979af0220f9a5 100644 (file)
@@ -146,7 +146,7 @@ void TermProperties::composeProperty(TermProperties& p)
 // push the substitution pv_prop.getModifiedTerm(pv) -> n
 void SolvedForm::push_back(Node pv, Node n, TermProperties& pv_prop)
 {
-  Assert(n.getType().isSubtypeOf(pv.getType()));
+  Assert(n.getType() == pv.getType());
   d_vars.push_back(pv);
   d_subs.push_back(n);
   d_props.push_back(pv_prop);
@@ -945,7 +945,7 @@ bool CegInstantiator::constructInstantiationInc(Node pv,
                                                 SolvedForm& sf,
                                                 bool revertOnSuccess)
 {
-  Assert(n.getType().isSubtypeOf(pv.getType()));
+  Assert(n.getType() == pv.getType());
   Node cnode = pv_prop.getCacheNode();
   if( d_curr_subs_proc[pv][n].find( cnode )==d_curr_subs_proc[pv][n].end() ){
     d_curr_subs_proc[pv][n][cnode] = true;
@@ -957,7 +957,7 @@ bool CegInstantiator::constructInstantiationInc(Node pv,
                          << ") ";
       Node mod_pv = pv_prop.getModifiedTerm( pv );
       Trace("cegqi-inst-debug") << mod_pv << " -> " << n << std::endl;
-      Assert(n.getType().isSubtypeOf(pv.getType()));
+      Assert(n.getType() == pv.getType());
     }
     //must ensure variables have been computed for n
     computeProgVars( n );
index 0304043e9af3d03cba437b93d8cb16650ef8abe9..6a419f08efbced22296fa1166d9fcf0929ccbe1b 100644 (file)
@@ -954,11 +954,6 @@ void FullModelChecker::doCheck(FirstOrderModelFmc * fm, Node f, Def & d, Node n
     doCheck( fm, f, d, n[0] );
     doNegate( d );
   }
-  else if (n.getKind() == kind::TO_REAL)
-  {
-    // no-op
-    doCheck(fm, f, d, n[0]);
-  }
   else if( n.getKind() == kind::FORALL ){
     d.addEntry(fm, mkCondDefault(fm, f), Node::null());
   }
@@ -1306,7 +1301,8 @@ bool FullModelChecker::doMeet( FirstOrderModelFmc * fm, std::vector< Node > & co
   return true;
 }
 
-Node FullModelChecker::mkCond( std::vector< Node > & cond ) {
+Node FullModelChecker::mkCond(const std::vector<Node>& cond)
+{
   return NodeManager::currentNM()->mkNode(APPLY_UF, cond);
 }
 
index 973dd072466ebb0889eff5b3c39ef0b0d2905ef8..c4d08505f0030f13a3848cb8b5aa1b3a4ccbe3c3 100644 (file)
@@ -147,7 +147,7 @@ protected:
                              std::vector< Node > & cond, std::vector<Node> & val );
   int isCompat( FirstOrderModelFmc * fm, std::vector< Node > & cond, Node c );
   bool doMeet( FirstOrderModelFmc * fm, std::vector< Node > & cond, Node c );
-  Node mkCond( std::vector< Node > & cond );
+  Node mkCond(const std::vector<Node>& cond);
   Node mkCondDefault( FirstOrderModelFmc * fm, Node f );
   void mkCondDefaultVec( FirstOrderModelFmc * fm, Node f, std::vector< Node > & cond );
   void mkCondVec( Node n, std::vector< Node > & cond );
index 4f5ec9cbdb2e477d486c5c2ccdec61819b48f82d..9d2f276f3a7dfdd03a75232150c7919e3daa9097 100644 (file)
@@ -122,7 +122,7 @@ void SygusTypeInfo::initialize(TermDbSygus* tds, TypeNode tn)
         TypeNode ct = dt[i].getArgType(j);
         TypeNode cbt = tds->sygusToBuiltinType(ct);
         TypeNode lat = sop[0][j].getType();
-        AlwaysAssert(cbt.isSubtypeOf(lat))
+        AlwaysAssert(cbt == lat)
             << "In sygus datatype " << dt.getName()
             << ", argument to a lambda constructor is not " << lat << std::endl;
       }
index bf74c028191fe097e1dc3d1feace58a0aa294122..2b2ef939d883dffcd6641f914974f304f7f38870 100644 (file)
@@ -219,9 +219,8 @@ Node Rewriter::rewriteTo(theory::TheoryId theoryId,
           TheoryId newTheory = theoryOf(newNode);
           rewriteStackTop.d_node = newNode;
           rewriteStackTop.d_theoryId = newTheory;
-          Assert(
-              newNode.getType().isSubtypeOf(rewriteStackTop.d_node.getType()))
-              << "Pre-rewriting " << rewriteStackTop.d_node
+          Assert(newNode.getType() == rewriteStackTop.d_node.getType())
+              << "Pre-rewriting " << rewriteStackTop.d_node << " to " << newNode
               << " does not preserve type";
           // In the pre-rewrite, if changing theories, we just call the other
           // theories pre-rewrite. If the kind of the node was changed, then we
@@ -310,8 +309,8 @@ Node Rewriter::rewriteTo(theory::TheoryId theoryId,
         // We continue with the response we got
         TNode newNode = response.d_node;
         TheoryId newTheoryId = theoryOf(newNode);
-        Assert(newNode.getType().isSubtypeOf(rewriteStackTop.d_node.getType()))
-            << "Post-rewriting " << rewriteStackTop.d_node
+        Assert(newNode.getType() == rewriteStackTop.d_node.getType())
+            << "Post-rewriting " << rewriteStackTop.d_node << " to " << newNode
             << " does not preserve type";
         if (newTheoryId != rewriteStackTop.getTheoryId()
             || response.d_status == REWRITE_AGAIN_FULL)
@@ -403,8 +402,9 @@ Node Rewriter::rewriteTo(theory::TheoryId theoryId,
     if (rewriteStack.size() == 1) {
       Assert(!isEquality || rewriteStackTop.d_node.getKind() == kind::EQUAL
              || rewriteStackTop.d_node.isConst());
-      Assert(rewriteStackTop.d_node.getType().isSubtypeOf(node.getType()))
-          << "Rewriting " << node << " does not preserve type";
+      Assert(rewriteStackTop.d_node.getType() == node.getType())
+          << "Rewriting " << node << " to " << rewriteStackTop.d_node
+          << " does not preserve type";
       return rewriteStackTop.d_node;
     }
 
index 55a15e2abd9bc1e86fadc8523bc339040cceaf14..fed582cc5d0e10d3704fcd4ed2c9ba1e5faed95e 100644 (file)
@@ -1077,8 +1077,9 @@ bool TheoryEngine::propagate(TNode literal, theory::TheoryId theory) {
 
 const LogicInfo& TheoryEngine::getLogicInfo() const { return d_logicInfo; }
 
-theory::EqualityStatus TheoryEngine::getEqualityStatus(TNode a, TNode b) {
-  Assert(a.getType().isComparableTo(b.getType()));
+theory::EqualityStatus TheoryEngine::getEqualityStatus(TNode a, TNode b)
+{
+  Assert(a.getType() == b.getType());
   return d_sharedSolver->getEqualityStatus(a, b);
 }
 
index 6465743c1a07a41728c415d5119329a8cea02f02..52c78151c76a1c4f8164f39b008d15ba752f7270 100644 (file)
@@ -155,7 +155,7 @@ Node TheoryModel::getValue(TNode n) const
   }
   Trace("model-getvalue") << "[model-getvalue] getValue( " << n << " ): " << std::endl
                           << "[model-getvalue] returning " << nn << std::endl;
-  Assert(nn.getType().isSubtypeOf(n.getType()));
+  Assert(nn.getType() == n.getType());
   return nn;
 }
 
index 31ecde0a11378ce806481d47f52fc945e6235cfa..84a54025f9a4d3160bd357d8d33c18b33cb8bfd3 100644 (file)
@@ -50,7 +50,7 @@ TypeNode UfTypeRule::computeType(NodeManager* nodeManager, TNode n, bool check)
     {
       TypeNode currentArgument = (*argument_it).getType();
       TypeNode currentArgumentType = *argument_type_it;
-      if (!currentArgument.isSubtypeOf(currentArgumentType))
+      if (currentArgument != currentArgumentType)
       {
         std::stringstream ss;
         ss << "argument type is not a subtype of the function's argument "
index 80e9009e97d7a3c06ca9ae0520450431290f303a..ddee6a5691346e4c24459b92e24c4266c9828062 100644 (file)
@@ -4,5 +4,5 @@
 (declare-const x Bool)
 (declare-fun v () Int)
 (declare-fun r () Int)
-(assert (forall ((a Int)) (= (< v r) (= (= 0 (/ r v)) (distinct x (> (- r) 1))))))
-(check-sat)
\ No newline at end of file
+(assert (forall ((a Int)) (= (< v r) (= (= 0.0 (/ r v)) (distinct x (> (- r) 1))))))
+(check-sat)
index 16d3f8b702bb6363a51c4713560d5e0fadd00767..5da4054ce6dc16c27af7b5746cc93d1f5075c833 100644 (file)
@@ -5,5 +5,5 @@
 (declare-const x Bool)
 (declare-fun v () Real)
 (declare-fun r () Real)
-(assert (forall ((a Real)) (= (< v r) (= (= 0 (/ r v)) (distinct x (> (- r) 1))))))
-(check-sat)
\ No newline at end of file
+(assert (forall ((a Real)) (= (< v r) (= (= 0.0 (/ r v)) (distinct x (> (- r) 1))))))
+(check-sat)
index 3c3fee924904d9614d2f5cb9134dede57c5d081b..32ec9c7d2af720df9a645cdcd85043a9377c3047 100644 (file)
@@ -4,5 +4,5 @@
 (declare-const x Bool)
 (declare-fun v () Real)
 (declare-fun r () Real)
-(assert (forall ((a Real)) (= (< v r) (= (= 0 (/ r v)) (distinct x (> (- r) 1))))))
-(check-sat)
\ No newline at end of file
+(assert (forall ((a Real)) (= (< v r) (= (= 0.0 (/ r v)) (distinct x (> (- r) 1))))))
+(check-sat)
index 20f0a619004311b57044cf21dbd83be2a8014e63..fff6365b01363e91211150b2673729e4f194e00f 100644 (file)
@@ -1,3 +1,5 @@
+; COMMAND-LINE: -q
+; EXPECT: sat
 (set-logic ALL)
 (set-info :status sat)
 (declare-const x Bool)
index 5e2c3a46803790899272cabfb83e162ad538c0ea..99dc2022df1d4e01ad7a19b78b8610341ccb9f2c 100644 (file)
@@ -1,4 +1,3 @@
-; COMMAND-LINE: --fmf-bound --no-cegqi
 ; EXPECT: sat
 (set-logic ALL)
 (assert (forall ((a Int)) (or (distinct (/ 0 0) (to_real a)) (= (/ 0 a) 0.0))))
index 5f908db6e328a8b9b33c68f533457ff9c0d0d65b..e6e8fc9743e1a258d4697357a6c1200b8b584f47 100644 (file)
@@ -1,5 +1,5 @@
 ; COMMAND-LINE: --finite-model-find --sort-inference
-; EXPECT: sat
+; EXPECT: unknown
 (set-logic UFLIRA)
 (set-info :status sat)
 (declare-fun f (Int) Int)
@@ -11,5 +11,5 @@
 (assert (= (to_real (f 4)) (g 8)))
 (assert (= (to_real (h 5.0)) 0.0))
 ; Sort inference fails to infer that x can be uninterpreted in this example,
-; however, fmf is able to reason that all instances are sat.
+; fmf is unable to show sat due to use of to_real.
 (check-sat)
index 4f3cf89515bd7f3ac81eda9c80466555dfe359f6..3bc0df2cf8f71dd3a9a5c73b744fa87140777841 100644 (file)
@@ -1,4 +1,4 @@
-; COMMAND-LINE: --nl-ext=full
+; COMMAND-LINE: --nl-ext=full -q
 ; EXPECT: sat
 (set-logic QF_NRAT)
 (set-info :status sat)
index b8d05446dc4e89f4050e52e910ded8f59e5fcab4..da4bef952b8a32e8afb64601f4102b3584885639 100644 (file)
@@ -2128,7 +2128,7 @@ void checkSimpleSeparationConstraints(Solver* solver)
   Term heap = solver->mkTerm(cvc5::Kind::SEP_PTO, {p, x});
   solver->assertFormula(heap);
   Term nil = solver->mkSepNil(integer);
-  solver->assertFormula(nil.eqTerm(solver->mkReal(5)));
+  solver->assertFormula(nil.eqTerm(solver->mkInteger(5)));
   solver->checkSat();
 }
 }  // namespace
index 7b2de58f4ccbd98ff854c2ad451e0033cc459716..e70e43d0c5a9437f1a0c4512e9a1da65c7de9d8f 100644 (file)
@@ -2133,7 +2133,7 @@ class SolverTest
     Term heap = solver.mkTerm(SEP_PTO, p, x);
     solver.assertFormula(heap);
     Term nil = solver.mkSepNil(integer);
-    solver.assertFormula(nil.eqTerm(solver.mkReal(5)));
+    solver.assertFormula(nil.eqTerm(solver.mkInteger(5)));
     solver.checkSat();
   }
 
index cb7340495d775d1211a3ff153be004d3519aeef1..a8021ff47d22d315e335561b1bb1bd3f075aec95 100644 (file)
@@ -1587,7 +1587,7 @@ def checkSimpleSeparationConstraints(slv):
     heap = slv.mkTerm(Kind.SEP_PTO, p, x)
     slv.assertFormula(heap)
     nil = slv.mkSepNil(integer)
-    slv.assertFormula(nil.eqTerm(slv.mkReal(5)))
+    slv.assertFormula(nil.eqTerm(slv.mkInteger(5)))
     slv.checkSat()
 
 
index d9c8abbb7f11182cef287560c7f68cc5a7b63e23..9c5775790629bd7e5c5b163c8533bdff1267ba3c 100644 (file)
@@ -83,9 +83,9 @@ TEST_F(TestTheoryWhiteArith, int_normal_form)
 {
   Node x = d_nodeManager->mkVar(*d_intType);
   Node xr = d_nodeManager->mkVar(*d_realType);
-  Node c0 = d_nodeManager->mkConstReal(d_zero);
-  Node c1 = d_nodeManager->mkConstReal(d_one);
-  Node c2 = d_nodeManager->mkConstReal(Rational(2));
+  Node c0 = d_nodeManager->mkConstInt(d_zero);
+  Node c1 = d_nodeManager->mkConstInt(d_one);
+  Node c2 = d_nodeManager->mkConstInt(Rational(2));
 
   Node geq0 = d_nodeManager->mkNode(GEQ, x, c0);
   Node geq1 = d_nodeManager->mkNode(GEQ, x, c1);