Fix for non-linear models (#3410)
authorAndrew Reynolds <andrew.j.reynolds@gmail.com>
Mon, 28 Oct 2019 17:50:08 +0000 (12:50 -0500)
committerAhmed Irfan <43099566+ahmed-irfan@users.noreply.github.com>
Mon, 28 Oct 2019 17:50:08 +0000 (10:50 -0700)
* Towards fix for non-linear models

* Format

* Fix

* More

* Improve

* Format

* More

src/theory/arith/nonlinear_extension.cpp
src/theory/theory_model.cpp
test/regress/CMakeLists.txt
test/regress/regress0/nl/issue3407.smt2 [new file with mode: 0644]

index f067fda4758196a99919353a8d0c538edb3da6d8..4dfda79b7a7e91cdd8d867572720e6240c8aaaac 100644 (file)
@@ -2288,32 +2288,14 @@ int NonlinearExtension::checkLastCall(const std::vector<Node>& assertions,
 
 void NonlinearExtension::check(Theory::Effort e) {
   Trace("nl-ext") << std::endl;
-  Trace("nl-ext") << "NonlinearExtension::check, effort = " << e << std::endl;
+  Trace("nl-ext") << "NonlinearExtension::check, effort = " << e
+                  << ", built model = " << d_builtModel.get() << std::endl;
   if (d_builtModel.get())
   {
-    if (e == Theory::EFFORT_FULL)
-    {
-      return;
-    }
-    // now, record the approximations we used
-    NodeManager* nm = NodeManager::currentNM();
-    for (const std::pair<const Node, std::pair<Node, Node> >& cb :
-         d_check_model_bounds)
-    {
-      Node l = cb.second.first;
-      Node u = cb.second.second;
-      if (l != u)
-      {
-        Node v = cb.first;
-        Node pred =
-            nm->mkNode(AND, nm->mkNode(GEQ, v, l), nm->mkNode(GEQ, u, v));
-        pred = Rewriter::rewrite(pred);
-        d_containing.getValuation().getModel()->recordApproximation(v, pred);
-      }
-    }
-    return;
+    // already built model, nothing to do
   }
-  if (e == Theory::EFFORT_FULL) {
+  else if (e == Theory::EFFORT_FULL)
+  {
     d_containing.getExtTheory()->clearCache();
     d_needsLastCall = true;
     if (options::nlExtRewrites()) {
@@ -2328,7 +2310,9 @@ void NonlinearExtension::check(Theory::Effort e) {
         Trace("nl-ext") << "...sent lemmas." << std::endl;
       }
     }
-  } else {
+  }
+  else
+  {
     // get the assertions
     std::vector<Node> assertions;
     getAssertions(assertions);
@@ -2508,6 +2492,61 @@ void NonlinearExtension::check(Theory::Effort e) {
 
     } while (needsRecheck);
   }
+
+  // Did we internally determine a model exists? If so, we need to record some
+  // information in the theory engine's model class.
+  if (d_builtModel.get())
+  {
+    if (e < Theory::EFFORT_LAST_CALL)
+    {
+      // don't need to build the model yet
+      return;
+    }
+    // Record the approximations we used. This code calls the
+    // recordApproximation method of the model, which overrides the model
+    // values for variables that we solved for, using techniques specific to
+    // this class.
+    NodeManager* nm = NodeManager::currentNM();
+    TheoryModel* m = d_containing.getValuation().getModel();
+    for (const std::pair<const Node, std::pair<Node, Node> >& cb :
+         d_check_model_bounds)
+    {
+      Node l = cb.second.first;
+      Node u = cb.second.second;
+      Node pred;
+      Node v = cb.first;
+      if (l != u)
+      {
+        pred = nm->mkNode(AND, nm->mkNode(GEQ, v, l), nm->mkNode(GEQ, u, v));
+      }
+      else if (!m->areEqual(v, l))
+      {
+        // only record if value was not equal already
+        pred = v.eqNode(l);
+      }
+      if (!pred.isNull())
+      {
+        pred = Rewriter::rewrite(pred);
+        m->recordApproximation(v, pred);
+      }
+    }
+    // Also record the exact values we used. An exact value can be seen as a
+    // special kind approximation of the form (choice x. x = exact_value).
+    // Notice that the above term gets rewritten such that the choice function
+    // is eliminated.
+    for (size_t i = 0, num = d_check_model_vars.size(); i < num; i++)
+    {
+      Node v = d_check_model_vars[i];
+      Node s = d_check_model_subs[i];
+      if (!m->areEqual(v, s))
+      {
+        Node pred = v.eqNode(s);
+        pred = Rewriter::rewrite(pred);
+        m->recordApproximation(v, pred);
+      }
+    }
+    return;
+  }
 }
 
 void NonlinearExtension::presolve()
index f65d3a2033320e441c552b497e0dde2871ccb015..0d82d3f02dddfadfd3d168e14ae39826372fe356 100644 (file)
@@ -530,6 +530,8 @@ void TheoryModel::recordApproximation(TNode n, TNode pred)
   Assert(pred.getType().isBoolean());
   d_approximations[n] = pred;
   d_approx_list.push_back(std::pair<Node, Node>(n, pred));
+  // model cache is invalid
+  d_modelCache.clear();
 }
 void TheoryModel::setUsingModelCore()
 {
index c1264a122cc3fc6b2466e25f6def9a5cbd8b734e..134f42610983f1b7183507fd6a70fda96ce25e54 100644 (file)
@@ -536,6 +536,7 @@ set(regress_0_tests
   regress0/model-core.smt2
   regress0/nl/coeff-sat.smt2
   regress0/nl/ext-rew-aggr-test.smt2
+  regress0/nl/issue3407.smt2
   regress0/nl/magnitude-wrong-1020-m.smt2
   regress0/nl/mult-po.smt2
   regress0/nl/nia-wrong-tl.smt2
diff --git a/test/regress/regress0/nl/issue3407.smt2 b/test/regress/regress0/nl/issue3407.smt2
new file mode 100644 (file)
index 0000000..e4be74c
--- /dev/null
@@ -0,0 +1,8 @@
+; COMMAND-LINE: --no-check-models
+; EXPECT: sat
+(set-logic NRA)
+(set-info :status sat)
+(declare-fun a () Real)
+(declare-fun b () Real)
+(assert (= (* a b) 1))
+(check-sat)