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 |
157259079 |
inline Node mkRationalNode(const Rational& q){ |
47 |
157259079 |
return NodeManager::currentNM()->mkConst<Rational>(q); |
48 |
|
} |
49 |
|
|
50 |
11097 |
inline Node mkBoolNode(bool b){ |
51 |
11097 |
return NodeManager::currentNM()->mkConst<bool>(b); |
52 |
|
} |
53 |
|
|
54 |
|
/** \f$ k \in {LT, LEQ, EQ, GEQ, GT} \f$ */ |
55 |
254649472 |
inline bool isRelationOperator(Kind k){ |
56 |
|
using namespace kind; |
57 |
|
|
58 |
254649472 |
switch(k){ |
59 |
13352232 |
case LT: |
60 |
|
case LEQ: |
61 |
|
case EQUAL: |
62 |
|
case GEQ: |
63 |
|
case GT: |
64 |
13352232 |
return true; |
65 |
241297240 |
default: |
66 |
241297240 |
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 |
379968 |
inline bool evaluateConstantPredicate(Kind k, const Rational& left, const Rational& right){ |
93 |
|
using namespace kind; |
94 |
|
|
95 |
379968 |
switch(k){ |
96 |
|
case LT: return left < right; |
97 |
30561 |
case LEQ: return left <= right; |
98 |
211003 |
case EQUAL: return left == right; |
99 |
138404 |
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 |
1210241 |
inline int deltaCoeff(Kind k){ |
115 |
1210241 |
switch(k){ |
116 |
321081 |
case kind::LT: |
117 |
321081 |
return -1; |
118 |
|
case kind::GT: |
119 |
|
return 1; |
120 |
889160 |
default: |
121 |
889160 |
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 |
56339 |
inline Kind negateKind(Kind k){ |
171 |
56339 |
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 |
37060 |
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 |
5323 |
inline void flattenAnd(Node n, std::vector<TNode>& out){ |
208 |
5323 |
Assert(n.getKind() == kind::AND); |
209 |
20335 |
for(Node::iterator i=n.begin(), i_end=n.end(); i != i_end; ++i){ |
210 |
30024 |
Node curr = *i; |
211 |
15012 |
if(curr.getKind() == kind::AND){ |
212 |
3044 |
flattenAnd(curr, out); |
213 |
|
}else{ |
214 |
11968 |
out.push_back(curr); |
215 |
|
} |
216 |
|
} |
217 |
5323 |
} |
218 |
|
|
219 |
2279 |
inline Node flattenAnd(Node n){ |
220 |
4558 |
std::vector<TNode> out; |
221 |
2279 |
flattenAnd(n, out); |
222 |
4558 |
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 |
4229590 |
inline Node safeConstructNary(NodeBuilder& nb) |
240 |
|
{ |
241 |
4229590 |
switch (nb.getNumChildren()) { |
242 |
|
case 0: |
243 |
|
return getIdentity(nb.getKind()); |
244 |
3509693 |
case 1: |
245 |
3509693 |
return nb[0]; |
246 |
719897 |
default: |
247 |
719897 |
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 */ |