Refactor check-model handling in SmtEngine (#3723)
authorAndrew Reynolds <andrew.j.reynolds@gmail.com>
Fri, 7 Feb 2020 20:47:46 +0000 (14:47 -0600)
committerGitHub <noreply@github.com>
Fri, 7 Feb 2020 20:47:46 +0000 (14:47 -0600)
src/smt/smt_engine.cpp
test/regress/CMakeLists.txt
test/regress/regress0/nl/issue3718.smt2 [new file with mode: 0644]
test/regress/regress1/rewriterules/datatypes_sat.smt2
test/regress/regress1/rewriterules/length_gen_020_sat.smt2

index 6a63a991f029798ef9c78ae19d6c9abc491f33c2..4cb76eda6cb9d5d2ef8df2f556461738a0b0e485 100644 (file)
@@ -4784,21 +4784,11 @@ void SmtEngine::checkModel(bool hardFailure) {
     Debug("boolean-terms") << "++ got " << n << endl;
     Notice() << "SmtEngine::checkModel(): -- substitutes to " << n << endl;
 
-    if( n.getKind() != kind::REWRITE_RULE ){
-      // In case it's a quantifier (or contains one), look up its value before
-      // simplifying, or the quantifier might be irreparably altered.
-      n = m->getValue(n);
-      Notice() << "SmtEngine::checkModel(): -- get value : " << n << std::endl;
-    } else {
-      // Note this "skip" is done here, rather than above.  This is
-      // because (1) the quantifier could in principle simplify to false,
-      // which should be reported, and (2) checking for the quantifier
-      // above, before simplification, doesn't catch buried quantifiers
-      // anyway (those not at the top-level).
-      Notice() << "SmtEngine::checkModel(): -- skipping rewrite-rules assertion"
-               << endl;
-      continue;
-    }
+    // We look up the value before simplifying. If n contains quantifiers,
+    // this may increases the chance of finding its value before the node is
+    // altered by simplification below.
+    n = m->getValue(n);
+    Notice() << "SmtEngine::checkModel(): -- get value : " << n << std::endl;
 
     // Simplify the result.
     n = d_private->simplify(n);
@@ -4820,36 +4810,56 @@ void SmtEngine::checkModel(bool hardFailure) {
     n = m->getValue(n);
     Notice() << "SmtEngine::checkModel(): -- model-substitutes to " << n << endl;
 
-    if( d_logic.isQuantified() ){
-      // AJR: since quantified formulas are not checkable, we assign them to true/false based on the satisfying assignment.
-      // however, quantified formulas can be modified during preprocess, so they may not correspond to those in the satisfying assignment.
-      // hence we use a relaxed version of check model here.
-      // this is necessary until preprocessing passes explicitly record how they rewrite quantified formulas
-      if( hardFailure && !n.isConst() && n.getKind() != kind::LAMBDA ){
-        Notice() << "SmtEngine::checkModel(): -- relax check model wrt quantified formulas..." << endl;
-        AlwaysAssert(expr::hasClosure(n));
-        Warning() << "Warning : SmtEngine::checkModel(): cannot check simplified assertion : " << n << endl;
+    if (n.isConst())
+    {
+      if (n.getConst<bool>())
+      {
+        // assertion is true, everything is fine
         continue;
       }
-    }else{
-      AlwaysAssert(!hardFailure || n.isConst() || n.getKind() == kind::LAMBDA);
     }
-    // The result should be == true.
-    if(n != NodeManager::currentNM()->mkConst(true)) {
-      Notice() << "SmtEngine::checkModel(): *** PROBLEM: EXPECTED `TRUE' ***"
-               << endl;
-      stringstream ss;
-      ss << "SmtEngine::checkModel(): "
-         << "ERRORS SATISFYING ASSERTIONS WITH MODEL:" << endl
-         << "assertion:     " << *i << endl
-         << "simplifies to: " << n << endl
-         << "expected `true'." << endl
-         << "Run with `--check-models -v' for additional diagnostics.";
-      if(hardFailure) {
-        InternalError() << ss.str();
-      } else {
-        Warning() << ss.str() << endl;
-      }
+
+    // Otherwise, we did not succeed in showing the current assertion to be
+    // true. This may either indicate that our model is wrong, or that we cannot
+    // check it. The latter may be the case for several reasons.
+    // For example, quantified formulas are not checkable, although we assign
+    // them to true/false based on the satisfying assignment. However,
+    // quantified formulas can be modified during preprocess, so they may not
+    // correspond to those in the satisfying assignment. Hence we throw
+    // warnings for assertions that do not simplify to either true or false.
+    // Other theories such as non-linear arithmetic (in particular,
+    // transcendental functions) also have the property of not being able to
+    // be checked precisely here.
+    // Note that warnings like these can be avoided for quantified formulas
+    // by making preprocessing passes explicitly record how they
+    // rewrite quantified formulas (see cvc4-wishues#43).
+    if (!n.isConst())
+    {
+      // Not constant, print a less severe warning message here.
+      Warning() << "Warning : SmtEngine::checkModel(): cannot check simplified "
+                   "assertion : "
+                << n << endl;
+      continue;
+    }
+    // Assertions that simplify to false result in an InternalError or
+    // Warning being thrown below (when hardFailure is false).
+    Notice() << "SmtEngine::checkModel(): *** PROBLEM: EXPECTED `TRUE' ***"
+             << endl;
+    stringstream ss;
+    ss << "SmtEngine::checkModel(): "
+       << "ERRORS SATISFYING ASSERTIONS WITH MODEL:" << endl
+       << "assertion:     " << *i << endl
+       << "simplifies to: " << n << endl
+       << "expected `true'." << endl
+       << "Run with `--check-models -v' for additional diagnostics.";
+    if (hardFailure)
+    {
+      // internal error if hardFailure is true
+      InternalError() << ss.str();
+    }
+    else
+    {
+      Warning() << ss.str() << endl;
     }
   }
   Notice() << "SmtEngine::checkModel(): all assertions checked out OK !" << endl;
index ef33adb598339f20e129fa0a87c15b0fb9b90d0b..ada5230d95b3fa88e81241e475446678985e150e 100644 (file)
@@ -558,6 +558,7 @@ set(regress_0_tests
   regress0/nl/issue3411.smt2
   regress0/nl/issue3475.smt2
   regress0/nl/issue3652.smt2
+  regress0/nl/issue3718.smt2
   regress0/nl/issue3719.smt2
   regress0/nl/magnitude-wrong-1020-m.smt2
   regress0/nl/mult-po.smt2
diff --git a/test/regress/regress0/nl/issue3718.smt2 b/test/regress/regress0/nl/issue3718.smt2
new file mode 100644 (file)
index 0000000..363c1cb
--- /dev/null
@@ -0,0 +1,6 @@
+; COMMAND-LINE: --quiet
+; EXPECT: sat
+(set-logic QF_NRAT)
+(set-info :status sat)
+(assert (= (sqrt 0) 0))
+(check-sat)
index 428598c5b5892b185ff9f0851d9c203e50f323da..ab32e41904bbd9960ab82b275d7f52f4b75cf2eb 100644 (file)
@@ -1,4 +1,4 @@
-; COMMAND-LINE: --rewrite-rules
+; COMMAND-LINE: --rewrite-rules --quiet
 ;; try to solve datatypes with rewriterules
 (set-logic AUFLIA)
 (set-info :status sat)
index 70511d9b302cd1fe29be40ab61ad90af20fd7c8e..d46065c73e8e9ff15a5523b1d8f53f25b4236d8b 100644 (file)
@@ -1,4 +1,4 @@
-; COMMAND-LINE: --rewrite-rules
+; COMMAND-LINE: --rewrite-rules --quiet
 ;; Same than length.smt2 but the nil case is not a rewrite rule
 ;; So here the rewrite rules have no guards length