Add conversion of poly polynomial to cvc node. (#5218)
authorGereon Kremer <gereon.kremer@cs.rwth-aachen.de>
Sun, 11 Oct 2020 16:22:51 +0000 (18:22 +0200)
committerGitHub <noreply@github.com>
Sun, 11 Oct 2020 16:22:51 +0000 (11:22 -0500)
This PR adds a new utility function to convert a poly::Polynomial back to a cvc4 Node.

src/theory/arith/nl/poly_conversion.cpp
src/theory/arith/nl/poly_conversion.h

index 1280f9c8e4322470a61a72d0a8f44a7b271a2c3a..a76a781c49f81555bf4ddc8b4f9a6b03021e0097 100644 (file)
@@ -211,6 +211,70 @@ poly::Polynomial as_poly_polynomial(const CVC4::Node& n,
   return res;
 }
 
+namespace {
+/**
+ * Utility class that collects the monomial terms (as nodes) from the polynomial
+ * we are converting.
+ */
+struct CollectMonomialData
+{
+  CollectMonomialData(VariableMapper& v) : d_vm(v) {}
+
+  /** Mapper from poly variables to CVC4 variables */
+  VariableMapper& d_vm;
+  /** Collections of the monomial terms */
+  std::vector<Node> d_terms;
+  /** Caches the current node manager */
+  NodeManager* d_nm = NodeManager::currentNM();
+};
+/**
+ * Callback for lp_polynomial_traverse. Assumes data is actually a
+ * CollectMonomialData object and puts the polynomial into it.
+ */
+void collect_monomials(const lp_polynomial_context_t* ctx,
+                       lp_monomial_t* m,
+                       void* data)
+{
+  CollectMonomialData* d = static_cast<CollectMonomialData*>(data);
+  // constant
+  Node term =
+      d->d_nm->mkConst<Rational>(poly_utils::toRational(poly::Integer(&m->a)));
+  for (std::size_t i = 0; i < m->n; ++i)
+  {
+    // variable exponent pair
+    Node var = d->d_vm(m->p[i].x);
+    if (m->p[i].d > 1)
+    {
+      Node exp = d->d_nm->mkConst<Rational>(m->p[i].d);
+      term = d->d_nm->mkNode(
+          Kind::NONLINEAR_MULT, term, d->d_nm->mkNode(Kind::POW, var, exp));
+    }
+    else
+    {
+      term = d->d_nm->mkNode(Kind::NONLINEAR_MULT, term, var);
+    }
+  }
+  d->d_terms.emplace_back(term);
+}
+}  // namespace
+
+CVC4::Node as_cvc_polynomial(const poly::Polynomial& p, VariableMapper& vm)
+{
+  CollectMonomialData cmd(vm);
+  // Do the actual conversion
+  lp_polynomial_traverse(p.get_internal(), collect_monomials, &cmd);
+
+  if (cmd.d_terms.empty())
+  {
+    return cmd.d_nm->mkConst<Rational>(0);
+  }
+  if (cmd.d_terms.size() == 1)
+  {
+    return cmd.d_terms.front();
+  }
+  return cmd.d_nm->mkNode(Kind::PLUS, cmd.d_terms);
+}
+
 poly::SignCondition normalize_kind(CVC4::Kind kind,
                                    bool negated,
                                    poly::Polynomial& lhs)
@@ -496,15 +560,15 @@ Node excluding_interval_to_lemma(const Node& variable,
       if (allowNonlinearLemma)
       {
         Node poly = as_cvc_upolynomial(get_defining_polynomial(alg), variable);
-      return nm->mkNode(
-          Kind::OR,
+        return nm->mkNode(
+            Kind::OR,
             nm->mkNode(Kind::DISTINCT, poly, nm->mkConst(Rational(0))),
             nm->mkNode(Kind::LT,
                        variable,
                        nm->mkConst(poly_utils::toRationalBelow(lv))),
-          nm->mkNode(Kind::GT,
-                     variable,
-                     nm->mkConst(poly_utils::toRationalAbove(lv))));
+            nm->mkNode(Kind::GT,
+                       variable,
+                       nm->mkConst(poly_utils::toRationalAbove(lv))));
       }
       return Node();
     }
@@ -715,16 +779,19 @@ std::size_t bitsize(const poly::Value& v)
   return 0;
 }
 
-poly::IntervalAssignment getBounds(VariableMapper& vm, const BoundInference& bi) {
+poly::IntervalAssignment getBounds(VariableMapper& vm, const BoundInference& bi)
+{
   poly::IntervalAssignment res;
-  for (const auto& vb: bi.get()) {
+  for (const auto& vb : bi.get())
+  {
     poly::Variable v = vm(vb.first);
-    poly::Value l = vb.second.lower.isNull() ? poly::Value::minus_infty() : node_to_value(vb.second.lower, vb.first);
-    poly::Value u = vb.second.upper.isNull() ? poly::Value::plus_infty() : node_to_value(vb.second.upper, vb.first);
-    poly::Interval i(l,
-                     vb.second.lower_strict,
-                     u,
-                     vb.second.upper_strict);
+    poly::Value l = vb.second.lower.isNull()
+                        ? poly::Value::minus_infty()
+                        : node_to_value(vb.second.lower, vb.first);
+    poly::Value u = vb.second.upper.isNull()
+                        ? poly::Value::plus_infty()
+                        : node_to_value(vb.second.upper, vb.first);
+    poly::Interval i(l, vb.second.lower_strict, u, vb.second.upper_strict);
     res.set(v, i);
   }
   return res;
index b4d44c39d4951ca1bf15cd6d450c268baadf137f..37d816179897c98bd7cf5c7099ffd495faa891a6 100644 (file)
@@ -74,6 +74,17 @@ poly::Polynomial as_poly_polynomial(const CVC4::Node& n,
                                     VariableMapper& vm,
                                     poly::Rational& denominator);
 
+/**
+ * Constructs a node from the given polynomial.
+ *
+ * This methods does the straight-forward conversion from a polynomial into Node
+ * representation, using the given variable mapper.
+ * The resulting node is not minimized in any form (it may contain spurious
+ * multiplications with one or use NONLINEAR_MULT where regular MULT may be
+ * sufficient), so it may be sensible to rewrite it afterwards.
+ */
+CVC4::Node as_cvc_polynomial(const poly::Polynomial& p, VariableMapper& vm);
+
 /**
  * Constructs a constraints (a polynomial and a sign condition) from the given
  * node.