GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/arith/nl/ext/monomial.cpp Lines: 162 168 96.4 %
Date: 2021-05-22 Branches: 251 522 48.1 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Andrew Reynolds, Tim King, Andres Noetzli
4
 *
5
 * This file is part of the cvc5 project.
6
 *
7
 * Copyright (c) 2009-2021 by the authors listed in the file AUTHORS
8
 * in the top-level source directory and their institutional affiliations.
9
 * All rights reserved.  See the file COPYING in the top-level source
10
 * directory for licensing information.
11
 * ****************************************************************************
12
 *
13
 * Implementation of utilities for monomials.
14
 */
15
16
#include "theory/arith/nl/ext/monomial.h"
17
18
#include "theory/arith/arith_utilities.h"
19
#include "theory/arith/nl/nl_lemma_utils.h"
20
#include "theory/rewriter.h"
21
22
using namespace cvc5::kind;
23
24
namespace cvc5 {
25
namespace theory {
26
namespace arith {
27
namespace nl {
28
29
// Returns a[key] if key is in a or value otherwise.
30
59758
unsigned getCountWithDefault(const NodeMultiset& a, Node key, unsigned value)
31
{
32
59758
  NodeMultiset::const_iterator it = a.find(key);
33
59758
  return (it == a.end()) ? value : it->second;
34
}
35
// Given two multisets return the multiset difference a \ b.
36
6125
NodeMultiset diffMultiset(const NodeMultiset& a, const NodeMultiset& b)
37
{
38
6125
  NodeMultiset difference;
39
16740
  for (NodeMultiset::const_iterator it_a = a.begin(); it_a != a.end(); ++it_a)
40
  {
41
21230
    Node key = it_a->first;
42
10615
    const unsigned a_value = it_a->second;
43
10615
    const unsigned b_value = getCountWithDefault(b, key, 0);
44
10615
    if (a_value > b_value)
45
    {
46
8039
      difference[key] = a_value - b_value;
47
    }
48
  }
49
6125
  return difference;
50
}
51
52
// Return a vector containing a[key] repetitions of key in a multiset a.
53
6125
std::vector<Node> ExpandMultiset(const NodeMultiset& a)
54
{
55
6125
  std::vector<Node> expansion;
56
14164
  for (NodeMultiset::const_iterator it_a = a.begin(); it_a != a.end(); ++it_a)
57
  {
58
8039
    expansion.insert(expansion.end(), it_a->second, it_a->first);
59
  }
60
6125
  return expansion;
61
}
62
63
// status 0 : n equal, -1 : n superset, 1 : n subset
64
42281
void MonomialIndex::addTerm(Node n,
65
                            const std::vector<Node>& reps,
66
                            MonomialDb* nla,
67
                            int status,
68
                            unsigned argIndex)
69
{
70
42281
  if (status == 0)
71
  {
72
8111
    if (argIndex == reps.size())
73
    {
74
3694
      d_monos.push_back(n);
75
    }
76
    else
77
    {
78
4417
      d_data[reps[argIndex]].addTerm(n, reps, nla, status, argIndex + 1);
79
    }
80
  }
81
80911
  for (std::map<Node, MonomialIndex>::iterator it = d_data.begin();
82
80911
       it != d_data.end();
83
       ++it)
84
  {
85
38630
    if (status != 0 || argIndex == reps.size() || it->first != reps[argIndex])
86
    {
87
      // if we do not contain this variable, then if we were a superset,
88
      // fail (-2), otherwise we are subset.  if we do contain this
89
      // variable, then if we were equal, we are superset since variables
90
      // are ordered, otherwise we remain the same.
91
      int new_status =
92
68426
          std::find(reps.begin(), reps.end(), it->first) == reps.end()
93
35961
              ? (status >= 0 ? 1 : -2)
94
35961
              : (status == 0 ? -1 : status);
95
34213
      if (new_status != -2)
96
      {
97
34170
        it->second.addTerm(n, reps, nla, new_status, argIndex);
98
      }
99
    }
100
  }
101
  // compare for subsets
102
82094
  for (unsigned i = 0; i < d_monos.size(); i++)
103
  {
104
79626
    Node m = d_monos[i];
105
39813
    if (m != n)
106
    {
107
      // we are superset if we are equal and haven't traversed all variables
108
36119
      int cstatus = status == 0 ? (argIndex == reps.size() ? 0 : -1) : status;
109
72238
      Trace("nl-ext-mindex-debug") << "  compare " << n << " and " << m
110
36119
                                   << ", status = " << cstatus << std::endl;
111
36119
      if (cstatus <= 0 && nla->isMonomialSubset(m, n))
112
      {
113
3261
        nla->registerMonomialSubset(m, n);
114
3261
        Trace("nl-ext-mindex-debug") << "...success" << std::endl;
115
      }
116
32858
      else if (cstatus >= 0 && nla->isMonomialSubset(n, m))
117
      {
118
2864
        nla->registerMonomialSubset(n, m);
119
2864
        Trace("nl-ext-mindex-debug") << "...success (rev)" << std::endl;
120
      }
121
    }
122
  }
123
42281
}
124
125
4914
MonomialDb::MonomialDb()
126
{
127
4914
  d_one = NodeManager::currentNM()->mkConst(Rational(1));
128
4914
}
129
130
48647
void MonomialDb::registerMonomial(Node n)
131
{
132
48647
  if (std::find(d_monomials.begin(), d_monomials.end(), n) != d_monomials.end())
133
  {
134
44953
    return;
135
  }
136
3694
  d_monomials.push_back(n);
137
3694
  Trace("nl-ext-debug") << "Register monomial : " << n << std::endl;
138
3694
  Kind k = n.getKind();
139
3694
  if (k == NONLINEAR_MULT)
140
  {
141
    // get exponent count
142
1249
    unsigned nchild = n.getNumChildren();
143
4121
    for (unsigned i = 0; i < nchild; i++)
144
    {
145
2872
      d_m_exp[n][n[i]]++;
146
2872
      if (i == 0 || n[i] != n[i - 1])
147
      {
148
2401
        d_m_vlist[n].push_back(n[i]);
149
      }
150
    }
151
1249
    d_m_degree[n] = nchild;
152
  }
153
2445
  else if (n == d_one)
154
  {
155
429
    d_m_exp[n].clear();
156
429
    d_m_vlist[n].clear();
157
429
    d_m_degree[n] = 0;
158
  }
159
  else
160
  {
161
2016
    Assert(k != PLUS && k != MULT);
162
2016
    d_m_exp[n][n] = 1;
163
2016
    d_m_vlist[n].push_back(n);
164
2016
    d_m_degree[n] = 1;
165
  }
166
3694
  std::sort(d_m_vlist[n].begin(), d_m_vlist[n].end());
167
3694
  Trace("nl-ext-mindex") << "Add monomial to index : " << n << std::endl;
168
3694
  d_m_index.addTerm(n, d_m_vlist[n], this);
169
}
170
171
6125
void MonomialDb::registerMonomialSubset(Node a, Node b)
172
{
173
6125
  Assert(isMonomialSubset(a, b));
174
175
6125
  const NodeMultiset& a_exponent_map = getMonomialExponentMap(a);
176
6125
  const NodeMultiset& b_exponent_map = getMonomialExponentMap(b);
177
178
  std::vector<Node> diff_children =
179
12250
      ExpandMultiset(diffMultiset(b_exponent_map, a_exponent_map));
180
6125
  Assert(!diff_children.empty());
181
182
6125
  d_m_contain_parent[a].push_back(b);
183
6125
  d_m_contain_children[b].push_back(a);
184
185
12250
  Node mult_term = safeConstructNary(MULT, diff_children);
186
12250
  Node nlmult_term = safeConstructNary(NONLINEAR_MULT, diff_children);
187
6125
  d_m_contain_mult[a][b] = mult_term;
188
6125
  d_m_contain_umult[a][b] = nlmult_term;
189
12250
  Trace("nl-ext-mindex") << "..." << a << " is a subset of " << b
190
6125
                         << ", difference is " << mult_term << std::endl;
191
6125
}
192
193
42589
bool MonomialDb::isMonomialSubset(Node am, Node bm) const
194
{
195
42589
  const NodeMultiset& a = getMonomialExponentMap(am);
196
42589
  const NodeMultiset& b = getMonomialExponentMap(bm);
197
50834
  for (NodeMultiset::const_iterator it_a = a.begin(); it_a != a.end(); ++it_a)
198
  {
199
46829
    Node key = it_a->first;
200
38584
    const unsigned a_value = it_a->second;
201
38584
    const unsigned b_value = getCountWithDefault(b, key, 0);
202
38584
    if (a_value > b_value)
203
    {
204
30339
      return false;
205
    }
206
  }
207
12250
  return true;
208
}
209
210
143042
const NodeMultiset& MonomialDb::getMonomialExponentMap(Node monomial) const
211
{
212
143042
  MonomialExponentMap::const_iterator it = d_m_exp.find(monomial);
213
143042
  Assert(it != d_m_exp.end());
214
143042
  return it->second;
215
}
216
217
319503
unsigned MonomialDb::getExponent(Node monomial, Node v) const
218
{
219
319503
  MonomialExponentMap::const_iterator it = d_m_exp.find(monomial);
220
319503
  if (it == d_m_exp.end())
221
  {
222
    return 0;
223
  }
224
319503
  std::map<Node, unsigned>::const_iterator itv = it->second.find(v);
225
319503
  if (itv == it->second.end())
226
  {
227
    return 0;
228
  }
229
319503
  return itv->second;
230
}
231
232
566438
const std::vector<Node>& MonomialDb::getVariableList(Node monomial) const
233
{
234
  std::map<Node, std::vector<Node> >::const_iterator itvl =
235
566438
      d_m_vlist.find(monomial);
236
566438
  Assert(itvl != d_m_vlist.end());
237
566438
  return itvl->second;
238
}
239
240
17550
unsigned MonomialDb::getDegree(Node monomial) const
241
{
242
17550
  std::map<Node, unsigned>::const_iterator it = d_m_degree.find(monomial);
243
17550
  Assert(it != d_m_degree.end());
244
17550
  return it->second;
245
}
246
247
528
void MonomialDb::sortByDegree(std::vector<Node>& ms) const
248
{
249
528
  SortNonlinearDegree snlad(d_m_degree);
250
528
  std::sort(ms.begin(), ms.end(), snlad);
251
528
}
252
253
1608
void MonomialDb::sortVariablesByModel(std::vector<Node>& ms, NlModel& m)
254
{
255
1608
  SortNlModel smv;
256
1608
  smv.d_nlm = &m;
257
1608
  smv.d_isConcrete = false;
258
1608
  smv.d_isAbsolute = true;
259
1608
  smv.d_reverse_order = true;
260
11541
  for (const Node& msc : ms)
261
  {
262
9933
    std::sort(d_m_vlist[msc].begin(), d_m_vlist[msc].end(), smv);
263
  }
264
1608
}
265
266
21
const std::map<Node, std::vector<Node> >& MonomialDb::getContainsChildrenMap()
267
{
268
21
  return d_m_contain_children;
269
}
270
271
528
const std::map<Node, std::vector<Node> >& MonomialDb::getContainsParentMap()
272
{
273
528
  return d_m_contain_parent;
274
}
275
276
45272
Node MonomialDb::getContainsDiff(Node a, Node b) const
277
{
278
  std::map<Node, std::map<Node, Node> >::const_iterator it =
279
45272
      d_m_contain_mult.find(a);
280
45272
  if (it == d_m_contain_mult.end())
281
  {
282
    return Node::null();
283
  }
284
45272
  std::map<Node, Node>::const_iterator it2 = it->second.find(b);
285
45272
  if (it2 == it->second.end())
286
  {
287
    return Node::null();
288
  }
289
45272
  return it2->second;
290
}
291
292
44
Node MonomialDb::getContainsDiffNl(Node a, Node b) const
293
{
294
  std::map<Node, std::map<Node, Node> >::const_iterator it =
295
44
      d_m_contain_umult.find(a);
296
44
  if (it == d_m_contain_umult.end())
297
  {
298
    return Node::null();
299
  }
300
44
  std::map<Node, Node>::const_iterator it2 = it->second.find(b);
301
44
  if (it2 == it->second.end())
302
  {
303
    return Node::null();
304
  }
305
44
  return it2->second;
306
}
307
308
6150
Node MonomialDb::mkMonomialRemFactor(Node n,
309
                                     const NodeMultiset& n_exp_rem) const
310
{
311
12300
  std::vector<Node> children;
312
6150
  const NodeMultiset& exponent_map = getMonomialExponentMap(n);
313
16709
  for (NodeMultiset::const_iterator itme2 = exponent_map.begin();
314
16709
       itme2 != exponent_map.end();
315
       ++itme2)
316
  {
317
21118
    Node v = itme2->first;
318
10559
    unsigned inc = itme2->second;
319
21118
    Trace("nl-ext-mono-factor")
320
10559
        << "..." << inc << " factors of " << v << std::endl;
321
10559
    unsigned count_in_n_exp_rem = getCountWithDefault(n_exp_rem, v, 0);
322
10559
    Assert(count_in_n_exp_rem <= inc);
323
10559
    inc -= count_in_n_exp_rem;
324
21118
    Trace("nl-ext-mono-factor")
325
10559
        << "......rem, now " << inc << " factors of " << v << std::endl;
326
10559
    children.insert(children.end(), inc, v);
327
  }
328
6150
  Node ret = safeConstructNary(MULT, children);
329
6150
  ret = Rewriter::rewrite(ret);
330
6150
  Trace("nl-ext-mono-factor") << "...return : " << ret << std::endl;
331
12300
  return ret;
332
}
333
334
}  // namespace nl
335
}  // namespace arith
336
}  // namespace theory
337
28191
}  // namespace cvc5