summaryrefslogtreecommitdiff
path: root/src/theory/arith/nl/nl_monomial.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/theory/arith/nl/nl_monomial.cpp')
-rw-r--r--src/theory/arith/nl/nl_monomial.cpp336
1 files changed, 336 insertions, 0 deletions
diff --git a/src/theory/arith/nl/nl_monomial.cpp b/src/theory/arith/nl/nl_monomial.cpp
new file mode 100644
index 000000000..e8e7aceba
--- /dev/null
+++ b/src/theory/arith/nl/nl_monomial.cpp
@@ -0,0 +1,336 @@
+/********************* */
+/*! \file nl_monomial.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2019 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Implementation of utilities for monomials
+ **/
+
+#include "theory/arith/nl/nl_monomial.h"
+
+#include "theory/arith/arith_utilities.h"
+#include "theory/arith/nl/nl_lemma_utils.h"
+#include "theory/rewriter.h"
+
+using namespace CVC4::kind;
+
+namespace CVC4 {
+namespace theory {
+namespace arith {
+namespace nl {
+
+// Returns a[key] if key is in a or value otherwise.
+unsigned getCountWithDefault(const NodeMultiset& a, Node key, unsigned value)
+{
+ NodeMultiset::const_iterator it = a.find(key);
+ return (it == a.end()) ? value : it->second;
+}
+// Given two multisets return the multiset difference a \ b.
+NodeMultiset diffMultiset(const NodeMultiset& a, const NodeMultiset& b)
+{
+ NodeMultiset difference;
+ for (NodeMultiset::const_iterator it_a = a.begin(); it_a != a.end(); ++it_a)
+ {
+ Node key = it_a->first;
+ const unsigned a_value = it_a->second;
+ const unsigned b_value = getCountWithDefault(b, key, 0);
+ if (a_value > b_value)
+ {
+ difference[key] = a_value - b_value;
+ }
+ }
+ return difference;
+}
+
+// Return a vector containing a[key] repetitions of key in a multiset a.
+std::vector<Node> ExpandMultiset(const NodeMultiset& a)
+{
+ std::vector<Node> expansion;
+ for (NodeMultiset::const_iterator it_a = a.begin(); it_a != a.end(); ++it_a)
+ {
+ expansion.insert(expansion.end(), it_a->second, it_a->first);
+ }
+ return expansion;
+}
+
+// status 0 : n equal, -1 : n superset, 1 : n subset
+void MonomialIndex::addTerm(Node n,
+ const std::vector<Node>& reps,
+ MonomialDb* nla,
+ int status,
+ unsigned argIndex)
+{
+ if (status == 0)
+ {
+ if (argIndex == reps.size())
+ {
+ d_monos.push_back(n);
+ }
+ else
+ {
+ d_data[reps[argIndex]].addTerm(n, reps, nla, status, argIndex + 1);
+ }
+ }
+ for (std::map<Node, MonomialIndex>::iterator it = d_data.begin();
+ it != d_data.end();
+ ++it)
+ {
+ if (status != 0 || argIndex == reps.size() || it->first != reps[argIndex])
+ {
+ // if we do not contain this variable, then if we were a superset,
+ // fail (-2), otherwise we are subset. if we do contain this
+ // variable, then if we were equal, we are superset since variables
+ // are ordered, otherwise we remain the same.
+ int new_status =
+ std::find(reps.begin(), reps.end(), it->first) == reps.end()
+ ? (status >= 0 ? 1 : -2)
+ : (status == 0 ? -1 : status);
+ if (new_status != -2)
+ {
+ it->second.addTerm(n, reps, nla, new_status, argIndex);
+ }
+ }
+ }
+ // compare for subsets
+ for (unsigned i = 0; i < d_monos.size(); i++)
+ {
+ Node m = d_monos[i];
+ if (m != n)
+ {
+ // we are superset if we are equal and haven't traversed all variables
+ int cstatus = status == 0 ? (argIndex == reps.size() ? 0 : -1) : status;
+ Trace("nl-ext-mindex-debug") << " compare " << n << " and " << m
+ << ", status = " << cstatus << std::endl;
+ if (cstatus <= 0 && nla->isMonomialSubset(m, n))
+ {
+ nla->registerMonomialSubset(m, n);
+ Trace("nl-ext-mindex-debug") << "...success" << std::endl;
+ }
+ else if (cstatus >= 0 && nla->isMonomialSubset(n, m))
+ {
+ nla->registerMonomialSubset(n, m);
+ Trace("nl-ext-mindex-debug") << "...success (rev)" << std::endl;
+ }
+ }
+ }
+}
+
+MonomialDb::MonomialDb()
+{
+ d_one = NodeManager::currentNM()->mkConst(Rational(1));
+}
+
+void MonomialDb::registerMonomial(Node n)
+{
+ if (std::find(d_monomials.begin(), d_monomials.end(), n) != d_monomials.end())
+ {
+ return;
+ }
+ d_monomials.push_back(n);
+ Trace("nl-ext-debug") << "Register monomial : " << n << std::endl;
+ Kind k = n.getKind();
+ if (k == NONLINEAR_MULT)
+ {
+ // get exponent count
+ unsigned nchild = n.getNumChildren();
+ for (unsigned i = 0; i < nchild; i++)
+ {
+ d_m_exp[n][n[i]]++;
+ if (i == 0 || n[i] != n[i - 1])
+ {
+ d_m_vlist[n].push_back(n[i]);
+ }
+ }
+ d_m_degree[n] = nchild;
+ }
+ else if (n == d_one)
+ {
+ d_m_exp[n].clear();
+ d_m_vlist[n].clear();
+ d_m_degree[n] = 0;
+ }
+ else
+ {
+ Assert(k != PLUS && k != MULT);
+ d_m_exp[n][n] = 1;
+ d_m_vlist[n].push_back(n);
+ d_m_degree[n] = 1;
+ }
+ std::sort(d_m_vlist[n].begin(), d_m_vlist[n].end());
+ Trace("nl-ext-mindex") << "Add monomial to index : " << n << std::endl;
+ d_m_index.addTerm(n, d_m_vlist[n], this);
+}
+
+void MonomialDb::registerMonomialSubset(Node a, Node b)
+{
+ Assert(isMonomialSubset(a, b));
+
+ const NodeMultiset& a_exponent_map = getMonomialExponentMap(a);
+ const NodeMultiset& b_exponent_map = getMonomialExponentMap(b);
+
+ std::vector<Node> diff_children =
+ ExpandMultiset(diffMultiset(b_exponent_map, a_exponent_map));
+ Assert(!diff_children.empty());
+
+ d_m_contain_parent[a].push_back(b);
+ d_m_contain_children[b].push_back(a);
+
+ Node mult_term = safeConstructNary(MULT, diff_children);
+ Node nlmult_term = safeConstructNary(NONLINEAR_MULT, diff_children);
+ d_m_contain_mult[a][b] = mult_term;
+ d_m_contain_umult[a][b] = nlmult_term;
+ Trace("nl-ext-mindex") << "..." << a << " is a subset of " << b
+ << ", difference is " << mult_term << std::endl;
+}
+
+bool MonomialDb::isMonomialSubset(Node am, Node bm) const
+{
+ const NodeMultiset& a = getMonomialExponentMap(am);
+ const NodeMultiset& b = getMonomialExponentMap(bm);
+ for (NodeMultiset::const_iterator it_a = a.begin(); it_a != a.end(); ++it_a)
+ {
+ Node key = it_a->first;
+ const unsigned a_value = it_a->second;
+ const unsigned b_value = getCountWithDefault(b, key, 0);
+ if (a_value > b_value)
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+const NodeMultiset& MonomialDb::getMonomialExponentMap(Node monomial) const
+{
+ MonomialExponentMap::const_iterator it = d_m_exp.find(monomial);
+ Assert(it != d_m_exp.end());
+ return it->second;
+}
+
+unsigned MonomialDb::getExponent(Node monomial, Node v) const
+{
+ MonomialExponentMap::const_iterator it = d_m_exp.find(monomial);
+ if (it == d_m_exp.end())
+ {
+ return 0;
+ }
+ std::map<Node, unsigned>::const_iterator itv = it->second.find(v);
+ if (itv == it->second.end())
+ {
+ return 0;
+ }
+ return itv->second;
+}
+
+const std::vector<Node>& MonomialDb::getVariableList(Node monomial) const
+{
+ std::map<Node, std::vector<Node> >::const_iterator itvl =
+ d_m_vlist.find(monomial);
+ Assert(itvl != d_m_vlist.end());
+ return itvl->second;
+}
+
+unsigned MonomialDb::getDegree(Node monomial) const
+{
+ std::map<Node, unsigned>::const_iterator it = d_m_degree.find(monomial);
+ Assert(it != d_m_degree.end());
+ return it->second;
+}
+
+void MonomialDb::sortByDegree(std::vector<Node>& ms) const
+{
+ SortNonlinearDegree snlad(d_m_degree);
+ std::sort(ms.begin(), ms.end(), snlad);
+}
+
+void MonomialDb::sortVariablesByModel(std::vector<Node>& ms, NlModel& m)
+{
+ SortNlModel smv;
+ smv.d_nlm = &m;
+ smv.d_isConcrete = false;
+ smv.d_isAbsolute = true;
+ smv.d_reverse_order = true;
+ for (const Node& msc : ms)
+ {
+ std::sort(d_m_vlist[msc].begin(), d_m_vlist[msc].end(), smv);
+ }
+}
+
+const std::map<Node, std::vector<Node> >& MonomialDb::getContainsChildrenMap()
+{
+ return d_m_contain_children;
+}
+
+const std::map<Node, std::vector<Node> >& MonomialDb::getContainsParentMap()
+{
+ return d_m_contain_parent;
+}
+
+Node MonomialDb::getContainsDiff(Node a, Node b) const
+{
+ std::map<Node, std::map<Node, Node> >::const_iterator it =
+ d_m_contain_mult.find(a);
+ if (it == d_m_contain_umult.end())
+ {
+ return Node::null();
+ }
+ std::map<Node, Node>::const_iterator it2 = it->second.find(b);
+ if (it2 == it->second.end())
+ {
+ return Node::null();
+ }
+ return it2->second;
+}
+
+Node MonomialDb::getContainsDiffNl(Node a, Node b) const
+{
+ std::map<Node, std::map<Node, Node> >::const_iterator it =
+ d_m_contain_umult.find(a);
+ if (it == d_m_contain_umult.end())
+ {
+ return Node::null();
+ }
+ std::map<Node, Node>::const_iterator it2 = it->second.find(b);
+ if (it2 == it->second.end())
+ {
+ return Node::null();
+ }
+ return it2->second;
+}
+
+Node MonomialDb::mkMonomialRemFactor(Node n,
+ const NodeMultiset& n_exp_rem) const
+{
+ std::vector<Node> children;
+ const NodeMultiset& exponent_map = getMonomialExponentMap(n);
+ for (NodeMultiset::const_iterator itme2 = exponent_map.begin();
+ itme2 != exponent_map.end();
+ ++itme2)
+ {
+ Node v = itme2->first;
+ unsigned inc = itme2->second;
+ Trace("nl-ext-mono-factor")
+ << "..." << inc << " factors of " << v << std::endl;
+ unsigned count_in_n_exp_rem = getCountWithDefault(n_exp_rem, v, 0);
+ Assert(count_in_n_exp_rem <= inc);
+ inc -= count_in_n_exp_rem;
+ Trace("nl-ext-mono-factor")
+ << "......rem, now " << inc << " factors of " << v << std::endl;
+ children.insert(children.end(), inc, v);
+ }
+ Node ret = safeConstructNary(MULT, children);
+ ret = Rewriter::rewrite(ret);
+ Trace("nl-ext-mono-factor") << "...return : " << ret << std::endl;
+ return ret;
+}
+
+} // namespace nl
+} // namespace arith
+} // namespace theory
+} // namespace CVC4
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback