Fix policy for purifying arguments of exp (#8416)
authorAndrew Reynolds <andrew.j.reynolds@gmail.com>
Wed, 30 Mar 2022 19:17:09 +0000 (14:17 -0500)
committerGitHub <noreply@github.com>
Wed, 30 Mar 2022 19:17:09 +0000 (19:17 +0000)
This corrects the policy for when to purify exp. It ensures we purify exp whenever the kind is not a variable or constant, instead of when the kind is a transcendental function app. The latter permits problematic terms like (exp (* (exp 1.0) (exp 1.0)).

This also corrects an issue where information for ordering on variables would be skipped if we failed to produce a model value for a single variable, which was the original source of the error on #8415.

It furthermore fixes the PfRule ARITH_TRANS_EXP_APPROX_BELOW, which did not handle non-constant arguments of exp.

Fixes #8415.

src/proof/proof_rule.h
src/theory/arith/nl/ext/monomial_check.cpp
src/theory/arith/nl/transcendental/exponential_solver.cpp
src/theory/arith/nl/transcendental/proof_checker.cpp
src/theory/arith/nl/transcendental/transcendental_solver.cpp
src/theory/arith/nl/transcendental/transcendental_state.cpp
src/theory/theory_model_builder.cpp
test/regress/cli/CMakeLists.txt
test/regress/cli/regress0/nl/nta/issue8415-embed-arg.smt2 [new file with mode: 0644]

index 6231806d366b4385977fe7c853a2622018a3b8f3..e44802edde5f65523a70b2e91a1e7e005d93be33 100644 (file)
@@ -1734,12 +1734,12 @@ enum class PfRule : uint32_t
    * **Arithmetic -- Transcendentals -- Exp is approximated from below**
    *
    * .. math::
-   *   \inferrule{- \mid d,t}{exp(t) \geq \texttt{maclaurin}(\exp, d, t)}
+   *   \inferrule{- \mid d,c,t}{t \geq c \rightarrow exp(t) \geq \texttt{maclaurin}(\exp, d, c)}
    *
    * where :math:`d` is an odd positive number, :math:`t` an arithmetic term and
-   * :math:`\texttt{maclaurin}(\exp, d, t)` is the :math:`d`'th taylor
+   * :math:`\texttt{maclaurin}(\exp, d, c)` is the :math:`d`'th taylor
    * polynomial at zero (also called the Maclaurin series) of the exponential
-   * function evaluated at :math:`t`. The Maclaurin series for the exponential
+   * function evaluated at :math:`c`. The Maclaurin series for the exponential
    * function is the following:
    *
    * .. math::
index adcd084ddd7e0182a6b6f1b8b56f0eb52aba594f..2f20435f4c1501887c40995a7e4cab776b604c90 100644 (file)
@@ -109,11 +109,14 @@ void MonomialCheck::checkMagnitude(unsigned c)
   // ensure information is setup
   if (c == 0)
   {
+    Trace("nl-ext-proc") << "Assign order ids for " << d_data->d_ms_vars
+                         << "..." << std::endl;
     // sort by absolute values of abstract model values
     assignOrderIds(d_data->d_ms_vars, d_order_vars, false, true);
 
     // sort individual variable lists
-    Trace("nl-ext-proc") << "Assign order var lists..." << std::endl;
+    Trace("nl-ext-proc") << "Assign order var lists for " << d_data->d_ms
+                         << "..." << std::endl;
     d_data->d_mdb.sortVariablesByModel(d_data->d_ms, d_data->d_model);
   }
 
@@ -454,7 +457,8 @@ bool MonomialCheck::compareMonomial(
                              lem,
                              cmp_infers);
     }
-    Assert(d_order_vars.find(av) != d_order_vars.end());
+    Assert(d_order_vars.find(av) != d_order_vars.end())
+        << "Missing order information for variable " << av;
     avo = d_order_vars[av];
   }
   Node bv;
@@ -664,7 +668,7 @@ void MonomialCheck::assignOrderIds(std::vector<Node>& vars,
       Trace("nl-ext-mvo") << "..do not assign order to " << x << " : " << v
                           << std::endl;
       // don't assign for non-constant values (transcendental function apps)
-      break;
+      continue;
     }
     Trace("nl-ext-mvo") << "  order " << x << " : " << v << std::endl;
     if (v != prev)
index b869f2e72f5d81fc6851cf57a643ce94b5b3da85..93786f6468aba698d6b851c86c776170ebbc635b 100644 (file)
@@ -219,8 +219,6 @@ void ExponentialSolver::doTangentLemma(TNode e,
                         nm->mkNode(Kind::GEQ, e, poly_approx));
   Trace("nl-ext-exp") << "*** Tangent plane lemma (pre-rewrite): " << lem
                       << std::endl;
-  lem = rewrite(lem);
-  Trace("nl-ext-exp") << "*** Tangent plane lemma : " << lem << std::endl;
   Assert(d_data->d_model.computeAbstractModelValue(lem) == d_data->d_false);
   // Figure 3 : line 9
   CDProof* proof = nullptr;
@@ -230,7 +228,7 @@ void ExponentialSolver::doTangentLemma(TNode e,
     proof->addStep(lem,
                    PfRule::ARITH_TRANS_EXP_APPROX_BELOW,
                    {},
-                   {nm->mkConstInt(Rational(d)), e[0]});
+                   {nm->mkConstInt(Rational(d)), c, e[0]});
   }
   d_data->d_im.addPendingLemma(
       lem, InferenceId::ARITH_NL_T_TANGENT, proof, true);
index d7b990db38720d57a6950542e09b117a7e875712..69854ef095df796beeb62c35e441a7063c58bcf7 100644 (file)
@@ -192,19 +192,24 @@ Node TranscendentalProofRuleChecker::checkInternal(
   else if (id == PfRule::ARITH_TRANS_EXP_APPROX_BELOW)
   {
     Assert(children.empty());
-    Assert(args.size() == 2);
+    Assert(args.size() == 3);
     Assert(args[0].isConst() && args[0].getType().isInteger());
-    Assert(args[1].getType().isReal());
+    Assert(args[1].isConst() && args[1].getType().isRealOrInt());
+    Assert(args[2].getType().isReal());
     std::uint64_t d =
         args[0].getConst<Rational>().getNumerator().toUnsignedInt();
-    Node t = args[1];
+    Node c = args[1];
+    Node t = args[2];
     TaylorGenerator tg;
     TaylorGenerator::ApproximationBounds bounds;
-    tg.getPolynomialApproximationBounds(Kind::EXPONENTIAL, d, bounds);
+    tg.getPolynomialApproximationBoundForArg(Kind::EXPONENTIAL, c, d, bounds);
     Evaluator eval(nullptr);
-    Node evalt = eval.eval(bounds.d_lower, {tg.getTaylorVariable()}, {t});
+    Node evalt = eval.eval(bounds.d_lower, {tg.getTaylorVariable()}, {c});
     return nm->mkNode(
-        Kind::GEQ, std::vector<Node>{nm->mkNode(Kind::EXPONENTIAL, t), evalt});
+        Kind::IMPLIES,
+        nm->mkNode(Kind::GEQ, t, c),
+        nm->mkNode(Kind::GEQ,
+                   std::vector<Node>{nm->mkNode(Kind::EXPONENTIAL, t), evalt}));
   }
   else if (id == PfRule::ARITH_TRANS_SINE_BOUNDS)
   {
index 0d5a75b866dd7a0a57c0b47893f64e82b62269e2..e0e1fc50f3cd9b4b3737c07a268aceb487ac9611 100644 (file)
@@ -265,6 +265,7 @@ bool TranscendentalSolver::checkTfTangentPlanesFun(Node tf, unsigned d)
 
   // Figure 3 : c
   Node c = d_tstate.d_model.computeAbstractModelValue(tf[0]);
+  Assert(c.isConst());
   int csign = c.getConst<Rational>().sgn();
   if (csign == 0)
   {
index dc5d2a4954b18e151d3646407a2a1909d2e06b52..8b117b87019a0755d85834eae88df616c3f769ac 100644 (file)
@@ -102,9 +102,11 @@ void TranscendentalState::init(const std::vector<Node>& xts,
       }
       else
       {
+        // for others, if all arguments are variables or constants, we don't
+        // have to purify
         for (const Node& ac : a)
         {
-          if (isTranscendentalKind(ac.getKind()))
+          if (!ac.isVar() && !ac.isConst())
           {
             consider = false;
             break;
index 942374a47742d0ec959a1c3ed666d668030811ac..2119054a2edce369f9eabf9920b6b7e3c1f4be4f 100644 (file)
@@ -527,8 +527,11 @@ bool TheoryEngineModelBuilder::buildModel(TheoryModel* tm)
           }
           else
           {
-            warning() << "Model values in the same equivalence class "
-                      << constRep << " " << n << std::endl;
+            // This is currently a trace message, as it often triggers for
+            // non-linear arithmetic before the model is refined enough to
+            // e.g. show transcendental function apps are not equal to rationals
+            Trace("model-warn") << "Model values in the same equivalence class "
+                                << constRep << " " << n << std::endl;
             if (!constRepBaseModelValue)
             {
               assignConstRep = isBaseValue;
index 47d07041356290ed3cedcabb2d27b1042de2a0b5..a4179b203f85c61804693d0afbb22a237ddc6d28 100644 (file)
@@ -816,6 +816,7 @@ set(regress_0_tests
   regress0/nl/nta/issue8183-tc-pi.smt2
   regress0/nl/nta/issue8208-red-nred.smt2
   regress0/nl/nta/issue8294-2-double-solve.smt2
+  regress0/nl/nta/issue8415-embed-arg.smt2
   regress0/nl/nta/proj-issue376.smt2
   regress0/nl/nta/proj-issue403.smt2
   regress0/nl/nta/proj-issue460-pi-value.smt2
diff --git a/test/regress/cli/regress0/nl/nta/issue8415-embed-arg.smt2 b/test/regress/cli/regress0/nl/nta/issue8415-embed-arg.smt2
new file mode 100644 (file)
index 0000000..1be656f
--- /dev/null
@@ -0,0 +1,6 @@
+(set-logic ALL)
+(set-info :status unsat)
+(declare-fun r8 () Real)
+(declare-fun v57 () Bool)
+(assert (and (= 0.0 (exp (exp (+ 1.0 1.0)))) (not (= 0 (* r8 (ite v57 1 0))))))
+(check-sat)