GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/arith/arith_utilities.h Lines: 74 111 66.7 %
Date: 2021-11-07 Branches: 52 139 37.4 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Tim King, Andrew Reynolds, 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
 * Common functions for dealing with nodes.
14
 */
15
16
#include "cvc5_private.h"
17
18
#ifndef CVC5__THEORY__ARITH__ARITH_UTILITIES_H
19
#define CVC5__THEORY__ARITH__ARITH_UTILITIES_H
20
21
#include <unordered_map>
22
#include <unordered_set>
23
#include <vector>
24
25
#include "context/cdhashset.h"
26
#include "expr/node.h"
27
#include "expr/subs.h"
28
#include "theory/arith/arithvar.h"
29
#include "util/dense_map.h"
30
#include "util/integer.h"
31
#include "util/rational.h"
32
33
namespace cvc5 {
34
namespace theory {
35
namespace arith {
36
37
//Sets of Nodes
38
typedef std::unordered_set<Node> NodeSet;
39
typedef std::unordered_set<TNode> TNodeSet;
40
typedef context::CDHashSet<Node> CDNodeSet;
41
42
//Maps from Nodes -> ArithVars, and vice versa
43
typedef std::unordered_map<Node, ArithVar> NodeToArithVarMap;
44
typedef DenseMap<Node> ArithVarToNodeMap;
45
46
159530912
inline Node mkRationalNode(const Rational& q){
47
159530912
  return NodeManager::currentNM()->mkConst<Rational>(q);
48
}
49
50
9176
inline Node mkBoolNode(bool b){
51
9176
  return NodeManager::currentNM()->mkConst<bool>(b);
52
}
53
54
/** \f$ k \in {LT, LEQ, EQ, GEQ, GT} \f$ */
55
257307903
inline bool isRelationOperator(Kind k){
56
  using namespace kind;
57
58
257307903
  switch(k){
59
13317022
  case LT:
60
  case LEQ:
61
  case EQUAL:
62
  case GEQ:
63
  case GT:
64
13317022
    return true;
65
243990881
  default:
66
243990881
    return false;
67
  }
68
}
69
70
/**
71
 * Given a relational kind, k, return the kind k' s.t.
72
 * swapping the lefthand and righthand side is equivalent.
73
 *
74
 * The following equivalence should hold,
75
 *   (k l r) <=> (k' r l)
76
 */
77
79390
inline Kind reverseRelationKind(Kind k){
78
  using namespace kind;
79
80
79390
  switch(k){
81
12622
  case LT:    return GT;
82
3768
  case LEQ:   return GEQ;
83
11299
  case EQUAL: return EQUAL;
84
41848
  case GEQ:   return LEQ;
85
9853
  case GT:    return LT;
86
87
  default:
88
    Unreachable();
89
  }
90
}
91
92
379974
inline bool evaluateConstantPredicate(Kind k, const Rational& left, const Rational& right){
93
  using namespace kind;
94
95
379974
  switch(k){
96
  case LT:    return left <  right;
97
30543
  case LEQ:   return left <= right;
98
211044
  case EQUAL: return left == right;
99
138387
  case GEQ:   return left >= right;
100
  case GT:    return left >  right;
101
  default:
102
    Unreachable();
103
    return true;
104
  }
105
}
106
107
/**
108
 * Returns the appropriate coefficient for the infinitesimal given the kind
109
 * for an arithmetic atom inorder to represent strict inequalities as inequalities.
110
 *   x < c  becomes  x <= c + (-1) * \f$ \delta \f$
111
 *   x > c  becomes  x >= x + ( 1) * \f$ \delta \f$
112
 * Non-strict inequalities have a coefficient of zero.
113
 */
114
1203203
inline int deltaCoeff(Kind k){
115
1203203
  switch(k){
116
320259
  case kind::LT:
117
320259
    return -1;
118
  case kind::GT:
119
    return 1;
120
882944
  default:
121
882944
    return 0;
122
  }
123
}
124
125
/**
126
 * Given a literal to TheoryArith return a single kind to
127
 * to indicate its underlying structure.
128
 * The function returns the following in each case:
129
 * - (K left right) -> K where is a wildcard for EQUAL, LT, GT, LEQ, or GEQ:
130
 * - (NOT (EQUAL left right)) -> DISTINCT
131
 * - (NOT (LEQ left right))   -> GT
132
 * - (NOT (GEQ left right))   -> LT
133
 * - (NOT (LT left right))    -> GEQ
134
 * - (NOT (GT left right))    -> LEQ
135
 * If none of these match, it returns UNDEFINED_KIND.
136
 */
137
1768
inline Kind oldSimplifiedKind(TNode literal){
138
1768
  switch(literal.getKind()){
139
1768
  case kind::LT:
140
  case kind::GT:
141
  case kind::LEQ:
142
  case kind::GEQ:
143
  case kind::EQUAL:
144
1768
    return literal.getKind();
145
  case  kind::NOT:
146
    {
147
      TNode atom = literal[0];
148
      switch(atom.getKind()){
149
      case  kind::LEQ: //(not (LEQ x c)) <=> (GT x c)
150
        return  kind::GT;
151
      case  kind::GEQ: //(not (GEQ x c)) <=> (LT x c)
152
        return  kind::LT;
153
      case  kind::LT: //(not (LT x c)) <=> (GEQ x c)
154
        return  kind::GEQ;
155
      case  kind::GT: //(not (GT x c) <=> (LEQ x c)
156
        return  kind::LEQ;
157
      case  kind::EQUAL:
158
        return  kind::DISTINCT;
159
      default:
160
        Unreachable();
161
        return  kind::UNDEFINED_KIND;
162
      }
163
    }
164
  default:
165
    Unreachable();
166
    return kind::UNDEFINED_KIND;
167
  }
168
}
169
170
55388
inline Kind negateKind(Kind k){
171
55388
  switch(k){
172
  case kind::LT:       return kind::GEQ;
173
  case kind::GT:       return kind::LEQ;
174
19261
  case kind::LEQ:      return kind::GT;
175
36109
  case kind::GEQ:      return kind::LT;
176
18
  case kind::EQUAL:    return kind::DISTINCT;
177
  case kind::DISTINCT: return kind::EQUAL;
178
  default:
179
    return kind::UNDEFINED_KIND;
180
  }
181
}
182
183
inline Node negateConjunctionAsClause(TNode conjunction){
184
  Assert(conjunction.getKind() == kind::AND);
185
  NodeBuilder orBuilder(kind::OR);
186
187
  for(TNode::iterator i = conjunction.begin(), end=conjunction.end(); i != end; ++i){
188
    TNode child = *i;
189
    Node negatedChild = NodeBuilder(kind::NOT) << (child);
190
    orBuilder << negatedChild;
191
  }
192
  return orBuilder;
193
}
194
195
inline Node maybeUnaryConvert(NodeBuilder& builder)
196
{
197
  Assert(builder.getKind() == kind::OR || builder.getKind() == kind::AND
198
         || builder.getKind() == kind::PLUS || builder.getKind() == kind::MULT);
199
  Assert(builder.getNumChildren() >= 1);
200
  if(builder.getNumChildren() == 1){
201
    return builder[0];
202
  }else{
203
    return builder;
204
  }
205
}
206
207
5783
inline void flattenAnd(Node n, std::vector<TNode>& out){
208
5783
  Assert(n.getKind() == kind::AND);
209
22041
  for(Node::iterator i=n.begin(), i_end=n.end(); i != i_end; ++i){
210
32516
    Node curr = *i;
211
16258
    if(curr.getKind() == kind::AND){
212
3287
      flattenAnd(curr, out);
213
    }else{
214
12971
      out.push_back(curr);
215
    }
216
  }
217
5783
}
218
219
2496
inline Node flattenAnd(Node n){
220
4992
  std::vector<TNode> out;
221
2496
  flattenAnd(n, out);
222
4992
  return NodeManager::currentNM()->mkNode(kind::AND, out);
223
}
224
225
// Returns an node that is the identity of a select few kinds.
226
1807
inline Node getIdentity(Kind k){
227
1807
  switch(k){
228
  case kind::AND:
229
    return mkBoolNode(true);
230
  case kind::PLUS:
231
    return mkRationalNode(0);
232
1807
  case kind::MULT:
233
  case kind::NONLINEAR_MULT:
234
1807
    return mkRationalNode(1);
235
  default: Unreachable(); return Node::null();  // silence warning
236
  }
237
}
238
239
4208896
inline Node safeConstructNary(NodeBuilder& nb)
240
{
241
4208896
  switch (nb.getNumChildren()) {
242
    case 0:
243
      return getIdentity(nb.getKind());
244
3466358
    case 1:
245
3466358
      return nb[0];
246
742538
    default:
247
742538
      return (Node)nb;
248
  }
249
}
250
251
43071
inline Node safeConstructNary(Kind k, const std::vector<Node>& children) {
252
43071
  switch (children.size()) {
253
1807
    case 0:
254
1807
      return getIdentity(k);
255
21141
    case 1:
256
21141
      return children[0];
257
20123
    default:
258
20123
      return NodeManager::currentNM()->mkNode(k, children);
259
  }
260
}
261
262
// Returns the multiplication of a and b.
263
inline Node mkMult(Node a, Node b) {
264
  return NodeManager::currentNM()->mkNode(kind::MULT, a, b);
265
}
266
267
// Return a constraint that is equivalent to term being is in the range
268
// [start, end). This includes start and excludes end.
269
102
inline Node mkInRange(Node term, Node start, Node end) {
270
102
  NodeManager* nm = NodeManager::currentNM();
271
204
  Node above_start = nm->mkNode(kind::LEQ, start, term);
272
204
  Node below_end = nm->mkNode(kind::LT, term, end);
273
204
  return nm->mkNode(kind::AND, above_start, below_end);
274
}
275
276
// Creates an expression that constrains q to be equal to one of two expressions
277
// when n is 0 or not. Useful for division by 0 logic.
278
//   (ite (= n 0) (= q if_zero) (= q not_zero))
279
inline Node mkOnZeroIte(Node n, Node q, Node if_zero, Node not_zero) {
280
  Node zero = mkRationalNode(0);
281
  return n.eqNode(zero).iteNode(q.eqNode(if_zero), q.eqNode(not_zero));
282
}
283
284
1654
inline Node mkPi()
285
{
286
  return NodeManager::currentNM()->mkNullaryOperator(
287
1654
      NodeManager::currentNM()->realType(), kind::PI);
288
}
289
/** Join kinds, where k1 and k2 are arithmetic relations returns an
290
 * arithmetic relation ret such that
291
 * if (a <k1> b) and (a <k2> b), then (a <ret> b).
292
 */
293
Kind joinKinds(Kind k1, Kind k2);
294
295
/** Transitive kinds, where k1 and k2 are arithmetic relations returns an
296
 * arithmetic relation ret such that
297
 * if (a <k1> b) and (b <k2> c) then (a <ret> c).
298
 */
299
Kind transKinds(Kind k1, Kind k2);
300
301
/** Is k a transcendental function kind? */
302
bool isTranscendentalKind(Kind k);
303
/**
304
 * Get a lower/upper approximation of the constant r within the given
305
 * level of precision. In other words, this returns a constant c' such that
306
 *   c' <= c <= c' + 1/(10^prec) if isLower is true, or
307
 *   c' + 1/(10^prec) <= c <= c' if isLower is false.
308
 * where c' is a rational of the form n/d for some n and d <= 10^prec.
309
 */
310
Node getApproximateConstant(Node c, bool isLower, unsigned prec);
311
312
/** print rational approximation of cr with precision prec on trace c */
313
void printRationalApprox(const char* c, Node cr, unsigned prec = 5);
314
315
/** Arithmetic substitute
316
 *
317
 * This computes the substitution n { subs }, but with the caveat
318
 * that subterms of n that belong to a theory other than arithmetic are
319
 * not traversed. In other words, terms that belong to other theories are
320
 * treated as atomic variables. For example:
321
 *   (5*f(x) + 7*x ){ x -> 3 } returns 5*f(x) + 7*3.
322
 */
323
Node arithSubstitute(Node n, const Subs& sub);
324
325
/** Make the node u >= a ^ a >= l */
326
Node mkBounded(Node l, Node a, Node u);
327
328
Rational leastIntGreaterThan(const Rational&);
329
330
Rational greatestIntLessThan(const Rational&);
331
332
/** Negates a node in arithmetic proof normal form. */
333
Node negateProofLiteral(TNode n);
334
335
}  // namespace arith
336
}  // namespace theory
337
}  // namespace cvc5
338
339
#endif /* CVC5__THEORY__ARITH__ARITH_UTILITIES_H */