1 |
|
/****************************************************************************** |
2 |
|
* Top contributors (to current version): |
3 |
|
* Tim King, Gereon Kremer, Andrew Reynolds |
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 |
|
* [[ Add one-line brief description here ]] |
14 |
|
* |
15 |
|
* [[ Add lengthier description here ]] |
16 |
|
* \todo document this file |
17 |
|
*/ |
18 |
|
#include "theory/arith/normal_form.h" |
19 |
|
|
20 |
|
#include <list> |
21 |
|
|
22 |
|
#include "base/output.h" |
23 |
|
#include "theory/arith/arith_utilities.h" |
24 |
|
#include "theory/theory.h" |
25 |
|
|
26 |
|
using namespace std; |
27 |
|
|
28 |
|
namespace cvc5 { |
29 |
|
namespace theory { |
30 |
|
namespace arith { |
31 |
|
|
32 |
150733889 |
Constant Constant::mkConstant(const Rational& rat) { |
33 |
150733889 |
return Constant(mkRationalNode(rat)); |
34 |
|
} |
35 |
|
|
36 |
|
size_t Variable::getComplexity() const{ |
37 |
|
return 1u; |
38 |
|
} |
39 |
|
|
40 |
|
size_t VarList::getComplexity() const{ |
41 |
|
if(empty()){ |
42 |
|
return 1; |
43 |
|
}else if(singleton()){ |
44 |
|
return 1; |
45 |
|
}else{ |
46 |
|
return size() + 1; |
47 |
|
} |
48 |
|
} |
49 |
|
|
50 |
|
size_t Monomial::getComplexity() const{ |
51 |
|
return getConstant().getComplexity() + getVarList().getComplexity(); |
52 |
|
} |
53 |
|
|
54 |
|
size_t Polynomial::getComplexity() const{ |
55 |
|
size_t cmp = 0; |
56 |
|
iterator i = begin(), e = end(); |
57 |
|
for(; i != e; ++i){ |
58 |
|
Monomial m = *i; |
59 |
|
cmp += m.getComplexity(); |
60 |
|
} |
61 |
|
return cmp; |
62 |
|
} |
63 |
|
|
64 |
|
size_t Constant::getComplexity() const{ |
65 |
|
return getValue().complexity(); |
66 |
|
} |
67 |
|
|
68 |
208510162 |
bool Variable::isLeafMember(Node n){ |
69 |
625530486 |
return (!isRelationOperator(n.getKind())) && |
70 |
625530486 |
(Theory::isLeafOf(n, theory::THEORY_ARITH)); |
71 |
|
} |
72 |
|
|
73 |
188129368 |
VarList::VarList(Node n) : NodeWrapper(n) { Assert(isSorted(begin(), end())); } |
74 |
|
|
75 |
342313 |
bool Variable::isIAndMember(Node n) |
76 |
|
{ |
77 |
1026939 |
return n.getKind() == kind::IAND && Polynomial::isMember(n[0]) |
78 |
1369252 |
&& Polynomial::isMember(n[1]); |
79 |
|
} |
80 |
|
|
81 |
55499 |
bool Variable::isPow2Member(Node n) |
82 |
|
{ |
83 |
55499 |
return n.getKind() == kind::POW2 && Polynomial::isMember(n[0]); |
84 |
|
} |
85 |
|
|
86 |
239789 |
bool Variable::isDivMember(Node n){ |
87 |
239789 |
switch(n.getKind()){ |
88 |
152841 |
case kind::DIVISION: |
89 |
|
case kind::INTS_DIVISION: |
90 |
|
case kind::INTS_MODULUS: |
91 |
|
case kind::DIVISION_TOTAL: |
92 |
|
case kind::INTS_DIVISION_TOTAL: |
93 |
|
case kind::INTS_MODULUS_TOTAL: |
94 |
152841 |
return Polynomial::isMember(n[0]) && Polynomial::isMember(n[1]); |
95 |
86948 |
default: |
96 |
86948 |
return false; |
97 |
|
} |
98 |
|
} |
99 |
|
|
100 |
2681423 |
bool Variable::isTranscendentalMember(Node n) { |
101 |
2681423 |
switch(n.getKind()){ |
102 |
1387186 |
case kind::EXPONENTIAL: |
103 |
|
case kind::SINE: |
104 |
|
case kind::COSINE: |
105 |
|
case kind::TANGENT: |
106 |
|
case kind::COSECANT: |
107 |
|
case kind::SECANT: |
108 |
|
case kind::COTANGENT: |
109 |
|
case kind::ARCSINE: |
110 |
|
case kind::ARCCOSINE: |
111 |
|
case kind::ARCTANGENT: |
112 |
|
case kind::ARCCOSECANT: |
113 |
|
case kind::ARCSECANT: |
114 |
|
case kind::ARCCOTANGENT: |
115 |
1387186 |
case kind::SQRT: return Polynomial::isMember(n[0]); |
116 |
1294237 |
case kind::PI: |
117 |
1294237 |
return true; |
118 |
|
default: |
119 |
|
return false; |
120 |
|
} |
121 |
|
} |
122 |
|
|
123 |
|
|
124 |
192462299 |
bool VarList::isSorted(iterator start, iterator end) { |
125 |
192462299 |
return std::is_sorted(start, end); |
126 |
|
} |
127 |
|
|
128 |
142346625 |
bool VarList::isMember(Node n) { |
129 |
142346625 |
if(Variable::isMember(n)) { |
130 |
104689202 |
return true; |
131 |
|
} |
132 |
37657423 |
if(n.getKind() == kind::NONLINEAR_MULT) { |
133 |
4583836 |
Node::iterator curr = n.begin(), end = n.end(); |
134 |
9167672 |
Node prev = *curr; |
135 |
4583836 |
if(!Variable::isMember(prev)) return false; |
136 |
|
|
137 |
|
Variable::VariableNodeCmp cmp; |
138 |
|
|
139 |
15083812 |
while( (++curr) != end) { |
140 |
5249988 |
if(!Variable::isMember(*curr)) return false; |
141 |
|
// prev <= curr : accept |
142 |
|
// !(prev <= curr) : reject |
143 |
|
// !(!(prev > curr)) : reject |
144 |
|
// curr < prev : reject |
145 |
5249988 |
if((cmp(*curr, prev))) return false; |
146 |
5249988 |
prev = *curr; |
147 |
|
} |
148 |
4583836 |
return true; |
149 |
|
} else { |
150 |
33073587 |
return false; |
151 |
|
} |
152 |
|
} |
153 |
|
|
154 |
133627522 |
int VarList::cmp(const VarList& vl) const { |
155 |
133627522 |
int dif = this->size() - vl.size(); |
156 |
133627522 |
if (dif == 0) { |
157 |
98852144 |
if(this->getNode() == vl.getNode()) { |
158 |
14084285 |
return 0; |
159 |
|
} |
160 |
|
|
161 |
84767859 |
Assert(!empty()); |
162 |
84767859 |
Assert(!vl.empty()); |
163 |
84767859 |
if(this->size() == 1){ |
164 |
80368119 |
return Variable::VariableNodeCmp::cmp(this->getNode(), vl.getNode()); |
165 |
|
} |
166 |
|
|
167 |
|
|
168 |
8799480 |
internal_iterator ii=this->internalBegin(), ie=this->internalEnd(); |
169 |
8799480 |
internal_iterator ci=vl.internalBegin(), ce=vl.internalEnd(); |
170 |
17090403 |
for(; ii != ie; ++ii, ++ci){ |
171 |
12860182 |
Node vi = *ii; |
172 |
12860182 |
Node vc = *ci; |
173 |
8629961 |
int tmp = Variable::VariableNodeCmp::cmp(vi, vc); |
174 |
8629961 |
if(tmp != 0){ |
175 |
4399740 |
return tmp; |
176 |
|
} |
177 |
|
} |
178 |
|
Unreachable(); |
179 |
34775378 |
} else if(dif < 0) { |
180 |
19424501 |
return -1; |
181 |
|
} else { |
182 |
15350877 |
return 1; |
183 |
|
} |
184 |
|
} |
185 |
|
|
186 |
188129368 |
VarList VarList::parseVarList(Node n) { |
187 |
188129368 |
return VarList(n); |
188 |
|
// if(Variable::isMember(n)) { |
189 |
|
// return VarList(Variable(n)); |
190 |
|
// } else { |
191 |
|
// Assert(n.getKind() == kind::MULT); |
192 |
|
// for(Node::iterator i=n.begin(), end = n.end(); i!=end; ++i) { |
193 |
|
// Assert(Variable::isMember(*i)); |
194 |
|
// } |
195 |
|
// return VarList(n); |
196 |
|
// } |
197 |
|
} |
198 |
|
|
199 |
1334145 |
VarList VarList::operator*(const VarList& other) const { |
200 |
1334145 |
if(this->empty()) { |
201 |
1278782 |
return other; |
202 |
55363 |
} else if(other.empty()) { |
203 |
12724 |
return *this; |
204 |
|
} else { |
205 |
85278 |
vector<Node> result; |
206 |
|
|
207 |
|
internal_iterator |
208 |
85278 |
thisBegin = this->internalBegin(), |
209 |
85278 |
thisEnd = this->internalEnd(), |
210 |
85278 |
otherBegin = other.internalBegin(), |
211 |
85278 |
otherEnd = other.internalEnd(); |
212 |
|
|
213 |
|
Variable::VariableNodeCmp cmp; |
214 |
42639 |
std::merge(thisBegin, thisEnd, otherBegin, otherEnd, std::back_inserter(result), cmp); |
215 |
|
|
216 |
42639 |
Assert(result.size() >= 2); |
217 |
85278 |
Node mult = NodeManager::currentNM()->mkNode(kind::NONLINEAR_MULT, result); |
218 |
42639 |
return VarList::parseVarList(mult); |
219 |
|
} |
220 |
|
} |
221 |
|
|
222 |
161636177 |
bool Monomial::isMember(TNode n){ |
223 |
161636177 |
if(n.getKind() == kind::CONST_RATIONAL) { |
224 |
23140094 |
return true; |
225 |
138496083 |
} else if(multStructured(n)) { |
226 |
26083249 |
return VarList::isMember(n[1]); |
227 |
|
} else { |
228 |
112412834 |
return VarList::isMember(n); |
229 |
|
} |
230 |
|
} |
231 |
|
|
232 |
76505266 |
Monomial Monomial::mkMonomial(const Constant& c, const VarList& vl) { |
233 |
76505266 |
if(c.isZero() || vl.empty() ) { |
234 |
4661444 |
return Monomial(c); |
235 |
71843822 |
} else if(c.isOne()) { |
236 |
1794532 |
return Monomial(vl); |
237 |
|
} else { |
238 |
70049290 |
return Monomial(c, vl); |
239 |
|
} |
240 |
|
} |
241 |
|
|
242 |
71871 |
Monomial Monomial::mkMonomial(const VarList& vl) { |
243 |
|
// acts like Monomial::mkMonomial( 1, vl) |
244 |
71871 |
if( vl.empty() ) { |
245 |
|
return Monomial::mkOne(); |
246 |
|
} else if(true){ |
247 |
71871 |
return Monomial(vl); |
248 |
|
} |
249 |
|
} |
250 |
|
|
251 |
226658505 |
Monomial Monomial::parseMonomial(Node n) { |
252 |
226658505 |
if(n.getKind() == kind::CONST_RATIONAL) { |
253 |
38571820 |
return Monomial(Constant(n)); |
254 |
188086685 |
} else if(multStructured(n)) { |
255 |
65628554 |
return Monomial::mkMonomial(Constant(n[0]),VarList::parseVarList(n[1])); |
256 |
|
} else { |
257 |
122458131 |
return Monomial(VarList::parseVarList(n)); |
258 |
|
} |
259 |
|
} |
260 |
8043529 |
Monomial Monomial::operator*(const Rational& q) const { |
261 |
8043529 |
if(q.isZero()){ |
262 |
|
return mkZero(); |
263 |
|
}else{ |
264 |
16087058 |
Constant newConstant = this->getConstant() * q; |
265 |
8043529 |
return Monomial::mkMonomial(newConstant, getVarList()); |
266 |
|
} |
267 |
|
} |
268 |
|
|
269 |
|
Monomial Monomial::operator*(const Constant& c) const { |
270 |
|
return (*this) * c.getValue(); |
271 |
|
// if(c.isZero()){ |
272 |
|
// return mkZero(); |
273 |
|
// }else{ |
274 |
|
// Constant newConstant = this->getConstant() * c; |
275 |
|
// return Monomial::mkMonomial(newConstant, getVarList()); |
276 |
|
// } |
277 |
|
} |
278 |
|
|
279 |
1334145 |
Monomial Monomial::operator*(const Monomial& mono) const { |
280 |
2668290 |
Constant newConstant = this->getConstant() * mono.getConstant(); |
281 |
2668290 |
VarList newVL = this->getVarList() * mono.getVarList(); |
282 |
|
|
283 |
2668290 |
return Monomial::mkMonomial(newConstant, newVL); |
284 |
|
} |
285 |
|
|
286 |
|
// vector<Monomial> Monomial::sumLikeTerms(const std::vector<Monomial> & monos) |
287 |
|
// { |
288 |
|
// Assert(isSorted(monos)); |
289 |
|
// vector<Monomial> outMonomials; |
290 |
|
// typedef vector<Monomial>::const_iterator iterator; |
291 |
|
// for(iterator rangeIter = monos.begin(), end=monos.end(); rangeIter != end;) |
292 |
|
// { |
293 |
|
// Rational constant = (*rangeIter).getConstant().getValue(); |
294 |
|
// VarList varList = (*rangeIter).getVarList(); |
295 |
|
// ++rangeIter; |
296 |
|
// while(rangeIter != end && varList == (*rangeIter).getVarList()) { |
297 |
|
// constant += (*rangeIter).getConstant().getValue(); |
298 |
|
// ++rangeIter; |
299 |
|
// } |
300 |
|
// if(constant != 0) { |
301 |
|
// Constant asConstant = Constant::mkConstant(constant); |
302 |
|
// Monomial nonZero = Monomial::mkMonomial(asConstant, varList); |
303 |
|
// outMonomials.push_back(nonZero); |
304 |
|
// } |
305 |
|
// } |
306 |
|
|
307 |
|
// Assert(isStrictlySorted(outMonomials)); |
308 |
|
// return outMonomials; |
309 |
|
// } |
310 |
|
|
311 |
2991849 |
void Monomial::sort(std::vector<Monomial>& m){ |
312 |
2991849 |
if(!isSorted(m)){ |
313 |
137541 |
std::sort(m.begin(), m.end()); |
314 |
|
} |
315 |
2991849 |
} |
316 |
|
|
317 |
9656756 |
void Monomial::combineAdjacentMonomials(std::vector<Monomial>& monos) { |
318 |
9656756 |
Assert(isSorted(monos)); |
319 |
|
size_t writePos, readPos, N; |
320 |
31671877 |
for(writePos = 0, readPos = 0, N = monos.size(); readPos < N;){ |
321 |
22015121 |
Monomial& atRead = monos[readPos]; |
322 |
22015121 |
const VarList& varList = atRead.getVarList(); |
323 |
|
|
324 |
22015121 |
size_t rangeEnd = readPos+1; |
325 |
31336575 |
for(; rangeEnd < N; rangeEnd++){ |
326 |
17028577 |
if(!(varList == monos[rangeEnd].getVarList())){ break; } |
327 |
|
} |
328 |
|
// monos[i] for i in [readPos, rangeEnd) has the same var list |
329 |
22015121 |
if(readPos+1 == rangeEnd){ // no addition needed |
330 |
17490010 |
if(!atRead.getConstant().isZero()){ |
331 |
30722094 |
Monomial cpy = atRead; // being paranoid here |
332 |
15361047 |
monos[writePos] = cpy; |
333 |
15361047 |
writePos++; |
334 |
|
} |
335 |
|
}else{ |
336 |
9050222 |
Rational constant(monos[readPos].getConstant().getValue()); |
337 |
9185838 |
for(size_t i=readPos+1; i < rangeEnd; ++i){ |
338 |
4660727 |
constant += monos[i].getConstant().getValue(); |
339 |
|
} |
340 |
4525111 |
if(!constant.isZero()){ |
341 |
2995572 |
Constant asConstant = Constant::mkConstant(constant); |
342 |
2995572 |
Monomial nonZero = Monomial::mkMonomial(asConstant, varList); |
343 |
1497786 |
monos[writePos] = nonZero; |
344 |
1497786 |
writePos++; |
345 |
|
} |
346 |
|
} |
347 |
22015121 |
Assert(rangeEnd > readPos); |
348 |
22015121 |
readPos = rangeEnd; |
349 |
|
} |
350 |
9656756 |
if(writePos > 0 ){ |
351 |
16241224 |
Monomial cp = monos[0]; |
352 |
8120612 |
Assert(writePos <= N); |
353 |
8120612 |
monos.resize(writePos, cp); |
354 |
|
}else{ |
355 |
1536144 |
monos.clear(); |
356 |
|
} |
357 |
9656756 |
Assert(isStrictlySorted(monos)); |
358 |
9656756 |
} |
359 |
|
|
360 |
|
void Monomial::print() const { |
361 |
|
Debug("normal-form") << getNode() << std::endl; |
362 |
|
} |
363 |
|
|
364 |
|
void Monomial::printList(const std::vector<Monomial>& list) { |
365 |
|
for(vector<Monomial>::const_iterator i = list.begin(), end = list.end(); i != end; ++i) { |
366 |
|
const Monomial& m =*i; |
367 |
|
m.print(); |
368 |
|
} |
369 |
|
} |
370 |
7847371 |
Polynomial Polynomial::operator+(const Polynomial& vl) const { |
371 |
|
|
372 |
15694742 |
std::vector<Monomial> sortedMonos; |
373 |
7847371 |
std::merge(begin(), end(), vl.begin(), vl.end(), std::back_inserter(sortedMonos)); |
374 |
|
|
375 |
7847371 |
Monomial::combineAdjacentMonomials(sortedMonos); |
376 |
|
//std::vector<Monomial> combined = Monomial::sumLikeTerms(sortedMonos); |
377 |
|
|
378 |
7847371 |
Polynomial result = mkPolynomial(sortedMonos); |
379 |
15694742 |
return result; |
380 |
|
} |
381 |
|
|
382 |
|
Polynomial Polynomial::exactDivide(const Integer& z) const { |
383 |
|
Assert(isIntegral()); |
384 |
|
if(z.isOne()){ |
385 |
|
return (*this); |
386 |
|
}else { |
387 |
|
Constant invz = Constant::mkConstant(Rational(1,z)); |
388 |
|
Polynomial prod = (*this) * Monomial::mkMonomial(invz); |
389 |
|
Assert(prod.isIntegral()); |
390 |
|
return prod; |
391 |
|
} |
392 |
|
} |
393 |
|
|
394 |
1824086 |
Polynomial Polynomial::sumPolynomials(const std::vector<Polynomial>& ps){ |
395 |
1824086 |
if(ps.empty()){ |
396 |
|
return mkZero(); |
397 |
1824086 |
}else if(ps.size() <= 4){ |
398 |
|
// if there are few enough polynomials just add them |
399 |
3629202 |
Polynomial p = ps[0]; |
400 |
2030318 |
for(size_t i = 1; i < ps.size(); ++i){ |
401 |
215717 |
p = p + ps[i]; |
402 |
|
} |
403 |
1814601 |
return p; |
404 |
|
}else{ |
405 |
|
// general case |
406 |
18970 |
std::map<Node, Rational> coeffs; |
407 |
78799 |
for(size_t i = 0, N = ps.size(); i<N; ++i){ |
408 |
69314 |
const Polynomial& p = ps[i]; |
409 |
247373 |
for(iterator pi = p.begin(), pend = p.end(); pi != pend; ++pi) { |
410 |
356118 |
Monomial m = *pi; |
411 |
178059 |
coeffs[m.getVarList().getNode()] += m.getConstant().getValue(); |
412 |
|
} |
413 |
|
} |
414 |
18970 |
std::vector<Monomial> monos; |
415 |
9485 |
std::map<Node, Rational>::const_iterator ci = coeffs.begin(), cend = coeffs.end(); |
416 |
158981 |
for(; ci != cend; ++ci){ |
417 |
74748 |
if(!(*ci).second.isZero()){ |
418 |
|
Constant c = Constant::mkConstant((*ci).second); |
419 |
|
Node n = (*ci).first; |
420 |
|
VarList vl = VarList::parseVarList(n); |
421 |
|
monos.push_back(Monomial::mkMonomial(c, vl)); |
422 |
|
} |
423 |
|
} |
424 |
9485 |
Monomial::sort(monos); |
425 |
9485 |
Monomial::combineAdjacentMonomials(monos); |
426 |
|
|
427 |
18970 |
Polynomial result = mkPolynomial(monos); |
428 |
9485 |
return result; |
429 |
|
} |
430 |
|
} |
431 |
|
|
432 |
2573186 |
Polynomial Polynomial::operator-(const Polynomial& vl) const { |
433 |
5146372 |
Constant negOne = Constant::mkConstant(Rational(-1)); |
434 |
|
|
435 |
5146372 |
return *this + (vl*negOne); |
436 |
|
} |
437 |
|
|
438 |
7479494 |
Polynomial Polynomial::operator*(const Rational& q) const{ |
439 |
7479494 |
if(q.isZero()){ |
440 |
|
return Polynomial::mkZero(); |
441 |
7479494 |
}else if(q.isOne()){ |
442 |
2622686 |
return *this; |
443 |
|
}else{ |
444 |
9713616 |
std::vector<Monomial> newMonos; |
445 |
11987425 |
for(iterator i = this->begin(), end = this->end(); i != end; ++i) { |
446 |
7130617 |
newMonos.push_back((*i)*q); |
447 |
|
} |
448 |
|
|
449 |
4856808 |
Assert(Monomial::isStrictlySorted(newMonos)); |
450 |
4856808 |
return Polynomial::mkPolynomial(newMonos); |
451 |
|
} |
452 |
|
} |
453 |
|
|
454 |
3920991 |
Polynomial Polynomial::operator*(const Constant& c) const{ |
455 |
3920991 |
return (*this) * c.getValue(); |
456 |
|
// if(c.isZero()){ |
457 |
|
// return Polynomial::mkZero(); |
458 |
|
// }else if(c.isOne()){ |
459 |
|
// return *this; |
460 |
|
// }else{ |
461 |
|
// std::vector<Monomial> newMonos; |
462 |
|
// for(iterator i = this->begin(), end = this->end(); i != end; ++i) { |
463 |
|
// newMonos.push_back((*i)*c); |
464 |
|
// } |
465 |
|
|
466 |
|
// Assert(Monomial::isStrictlySorted(newMonos)); |
467 |
|
// return Polynomial::mkPolynomial(newMonos); |
468 |
|
// } |
469 |
|
} |
470 |
|
|
471 |
1182771 |
Polynomial Polynomial::operator*(const Monomial& mono) const { |
472 |
1182771 |
if(mono.isZero()) { |
473 |
307 |
return Polynomial(mono); //Don't multiply by zero |
474 |
|
} else { |
475 |
2364928 |
std::vector<Monomial> newMonos; |
476 |
2516609 |
for(iterator i = this->begin(), end = this->end(); i != end; ++i) { |
477 |
1334145 |
newMonos.push_back(mono * (*i)); |
478 |
|
} |
479 |
|
|
480 |
|
// We may need to sort newMonos. |
481 |
|
// Suppose this = (+ x y), mono = x, (* x y).getId() < (* x x).getId() |
482 |
|
// newMonos = <(* x x), (* x y)> after this loop. |
483 |
|
// This is not sorted according to the current VarList order. |
484 |
1182464 |
Monomial::sort(newMonos); |
485 |
1182464 |
return Polynomial::mkPolynomial(newMonos); |
486 |
|
} |
487 |
|
} |
488 |
|
|
489 |
1175755 |
Polynomial Polynomial::operator*(const Polynomial& poly) const { |
490 |
1175755 |
Polynomial res = Polynomial::mkZero(); |
491 |
2358526 |
for(iterator i = this->begin(), end = this->end(); i != end; ++i) { |
492 |
2365542 |
Monomial curr = *i; |
493 |
2365542 |
Polynomial prod = poly * curr; |
494 |
2365542 |
Polynomial sum = res + prod; |
495 |
1182771 |
res = sum; |
496 |
|
} |
497 |
1175755 |
return res; |
498 |
|
} |
499 |
|
|
500 |
4296619 |
Monomial Polynomial::selectAbsMinimum() const { |
501 |
8593238 |
iterator iter = begin(), myend = end(); |
502 |
4296619 |
Assert(iter != myend); |
503 |
|
|
504 |
4296619 |
Monomial min = *iter; |
505 |
4296619 |
++iter; |
506 |
7826011 |
for(; iter != end(); ++iter){ |
507 |
3529392 |
Monomial curr = *iter; |
508 |
1764696 |
if(curr.absCmp(min) < 0){ |
509 |
69694 |
min = curr; |
510 |
|
} |
511 |
|
} |
512 |
8593238 |
return min; |
513 |
|
} |
514 |
|
|
515 |
1914255 |
bool Polynomial::leadingCoefficientIsAbsOne() const { |
516 |
1914255 |
return getHead().absCoefficientIsOne(); |
517 |
|
} |
518 |
6121584 |
bool Polynomial::leadingCoefficientIsPositive() const { |
519 |
6121584 |
return getHead().getConstant().isPositive(); |
520 |
|
} |
521 |
|
|
522 |
3426944 |
bool Polynomial::denominatorLCMIsOne() const { |
523 |
3426944 |
return denominatorLCM().isOne(); |
524 |
|
} |
525 |
|
|
526 |
3426944 |
bool Polynomial::numeratorGCDIsOne() const { |
527 |
3426944 |
return gcd().isOne(); |
528 |
|
} |
529 |
|
|
530 |
3664292 |
Integer Polynomial::gcd() const { |
531 |
3664292 |
Assert(isIntegral()); |
532 |
3664292 |
return numeratorGCD(); |
533 |
|
} |
534 |
|
|
535 |
8315584 |
Integer Polynomial::numeratorGCD() const { |
536 |
|
//We'll use the standardization that gcd(0, 0) = 0 |
537 |
|
//So that the gcd of the zero polynomial is gcd{0} = 0 |
538 |
16631168 |
iterator i=begin(), e=end(); |
539 |
8315584 |
Assert(i != e); |
540 |
|
|
541 |
8315584 |
Integer d = (*i).getConstant().getValue().getNumerator().abs(); |
542 |
8315584 |
if(d.isOne()){ |
543 |
8034441 |
return d; |
544 |
|
} |
545 |
281143 |
++i; |
546 |
454873 |
for(; i!=e; ++i){ |
547 |
366778 |
Integer c = (*i).getConstant().getValue().getNumerator(); |
548 |
279913 |
d = d.gcd(c); |
549 |
279913 |
if(d.isOne()){ |
550 |
193048 |
return d; |
551 |
|
} |
552 |
|
} |
553 |
88095 |
return d; |
554 |
|
} |
555 |
|
|
556 |
8078236 |
Integer Polynomial::denominatorLCM() const { |
557 |
8078236 |
Integer tmp(1); |
558 |
20193731 |
for (iterator i = begin(), e = end(); i != e; ++i) { |
559 |
24230990 |
const Integer denominator = (*i).getConstant().getValue().getDenominator(); |
560 |
12115495 |
tmp = tmp.lcm(denominator); |
561 |
|
} |
562 |
8078236 |
return tmp; |
563 |
|
} |
564 |
|
|
565 |
4319961 |
Constant Polynomial::getCoefficient(const VarList& vl) const{ |
566 |
|
//TODO improve to binary search... |
567 |
11212490 |
for(iterator iter=begin(), myend=end(); iter != myend; ++iter){ |
568 |
13842520 |
Monomial m = *iter; |
569 |
13842520 |
VarList curr = m.getVarList(); |
570 |
6949991 |
if(curr == vl){ |
571 |
57462 |
return m.getConstant(); |
572 |
|
} |
573 |
|
} |
574 |
4262499 |
return Constant::mkConstant(0); |
575 |
|
} |
576 |
|
|
577 |
334 |
Node Polynomial::computeQR(const Polynomial& p, const Integer& div){ |
578 |
334 |
Assert(p.isIntegral()); |
579 |
668 |
std::vector<Monomial> q_vec, r_vec; |
580 |
668 |
Integer tmp_q, tmp_r; |
581 |
1138 |
for(iterator iter = p.begin(), pend = p.end(); iter != pend; ++iter){ |
582 |
1608 |
Monomial curr = *iter; |
583 |
1608 |
VarList vl = curr.getVarList(); |
584 |
1608 |
Constant c = curr.getConstant(); |
585 |
|
|
586 |
1608 |
const Integer& a = c.getValue().getNumerator(); |
587 |
804 |
Integer::floorQR(tmp_q, tmp_r, a, div); |
588 |
1608 |
Constant q=Constant::mkConstant(tmp_q); |
589 |
1608 |
Constant r=Constant::mkConstant(tmp_r); |
590 |
804 |
if(!q.isZero()){ |
591 |
804 |
q_vec.push_back(Monomial::mkMonomial(q, vl)); |
592 |
|
} |
593 |
804 |
if(!r.isZero()){ |
594 |
448 |
r_vec.push_back(Monomial::mkMonomial(r, vl)); |
595 |
|
} |
596 |
|
} |
597 |
|
|
598 |
668 |
Polynomial p_q = Polynomial::mkPolynomial(q_vec); |
599 |
668 |
Polynomial p_r = Polynomial::mkPolynomial(r_vec); |
600 |
|
|
601 |
668 |
return NodeManager::currentNM()->mkNode(kind::PLUS, p_q.getNode(), p_r.getNode()); |
602 |
|
} |
603 |
|
|
604 |
|
|
605 |
739189 |
Monomial Polynomial::minimumVariableMonomial() const{ |
606 |
739189 |
Assert(!isConstant()); |
607 |
739189 |
if(singleton()){ |
608 |
448482 |
return getHead(); |
609 |
|
}else{ |
610 |
581414 |
iterator i = begin(); |
611 |
581414 |
Monomial first = *i; |
612 |
290707 |
if( first.isConstant() ){ |
613 |
208750 |
++i; |
614 |
208750 |
Assert(i != end()); |
615 |
208750 |
return *i; |
616 |
|
}else{ |
617 |
81957 |
return first; |
618 |
|
} |
619 |
|
} |
620 |
|
} |
621 |
|
|
622 |
1141584 |
bool Polynomial::variableMonomialAreStrictlyGreater(const Monomial& m) const{ |
623 |
1141584 |
if(isConstant()){ |
624 |
474266 |
return true; |
625 |
|
}else{ |
626 |
1334636 |
Monomial minimum = minimumVariableMonomial(); |
627 |
667318 |
Debug("nf::tmp") << "minimum " << minimum.getNode() << endl; |
628 |
667318 |
Debug("nf::tmp") << "m " << m.getNode() << endl; |
629 |
667318 |
return m < minimum; |
630 |
|
} |
631 |
|
} |
632 |
|
|
633 |
60644016 |
bool Polynomial::isMember(TNode n) { |
634 |
60644016 |
if(Monomial::isMember(n)){ |
635 |
43341050 |
return true; |
636 |
17302966 |
}else if(n.getKind() == kind::PLUS){ |
637 |
17302966 |
Assert(n.getNumChildren() >= 2); |
638 |
17302966 |
Node::iterator currIter = n.begin(), end = n.end(); |
639 |
34605932 |
Node prev = *currIter; |
640 |
17302966 |
if(!Monomial::isMember(prev)){ |
641 |
|
return false; |
642 |
|
} |
643 |
|
|
644 |
34605932 |
Monomial mprev = Monomial::parseMonomial(prev); |
645 |
17302966 |
++currIter; |
646 |
68406088 |
for(; currIter != end; ++currIter){ |
647 |
51103122 |
Node curr = *currIter; |
648 |
25551561 |
if(!Monomial::isMember(curr)){ |
649 |
|
return false; |
650 |
|
} |
651 |
51103122 |
Monomial mcurr = Monomial::parseMonomial(curr); |
652 |
25551561 |
if(!(mprev < mcurr)){ |
653 |
|
return false; |
654 |
|
} |
655 |
25551561 |
mprev = mcurr; |
656 |
|
} |
657 |
17302966 |
return true; |
658 |
|
} else { |
659 |
|
return false; |
660 |
|
} |
661 |
|
} |
662 |
|
|
663 |
334 |
Node SumPair::computeQR(const SumPair& sp, const Integer& div){ |
664 |
334 |
Assert(sp.isIntegral()); |
665 |
|
|
666 |
668 |
const Integer& constant = sp.getConstant().getValue().getNumerator(); |
667 |
|
|
668 |
668 |
Integer constant_q, constant_r; |
669 |
334 |
Integer::floorQR(constant_q, constant_r, constant, div); |
670 |
|
|
671 |
668 |
Node p_qr = Polynomial::computeQR(sp.getPolynomial(), div); |
672 |
334 |
Assert(p_qr.getKind() == kind::PLUS); |
673 |
334 |
Assert(p_qr.getNumChildren() == 2); |
674 |
|
|
675 |
668 |
Polynomial p_q = Polynomial::parsePolynomial(p_qr[0]); |
676 |
668 |
Polynomial p_r = Polynomial::parsePolynomial(p_qr[1]); |
677 |
|
|
678 |
668 |
SumPair sp_q(p_q, Constant::mkConstant(constant_q)); |
679 |
668 |
SumPair sp_r(p_r, Constant::mkConstant(constant_r)); |
680 |
|
|
681 |
668 |
return NodeManager::currentNM()->mkNode(kind::PLUS, sp_q.getNode(), sp_r.getNode()); |
682 |
|
} |
683 |
|
|
684 |
1517538 |
SumPair SumPair::mkSumPair(const Polynomial& p){ |
685 |
1517538 |
if(p.isConstant()){ |
686 |
|
Constant leadingConstant = p.getHead().getConstant(); |
687 |
|
return SumPair(Polynomial::mkZero(), leadingConstant); |
688 |
1517538 |
}else if(p.containsConstant()){ |
689 |
945413 |
Assert(!p.singleton()); |
690 |
945413 |
return SumPair(p.getTail(), p.getHead().getConstant()); |
691 |
|
}else{ |
692 |
572125 |
return SumPair(p, Constant::mkZero()); |
693 |
|
} |
694 |
|
} |
695 |
|
|
696 |
4578510 |
Comparison::Comparison(TNode n) : NodeWrapper(n) { Assert(isNormalForm()); } |
697 |
|
|
698 |
36967 |
SumPair Comparison::toSumPair() const { |
699 |
36967 |
Kind cmpKind = comparisonKind(); |
700 |
36967 |
switch(cmpKind){ |
701 |
|
case kind::LT: |
702 |
|
case kind::LEQ: |
703 |
|
case kind::GT: |
704 |
|
case kind::GEQ: |
705 |
|
{ |
706 |
|
TNode lit = getNode(); |
707 |
|
TNode atom = (cmpKind == kind::LT || cmpKind == kind::LEQ) ? lit[0] : lit; |
708 |
|
Polynomial p = Polynomial::parsePolynomial(atom[0]); |
709 |
|
Constant c = Constant::mkConstant(atom[1]); |
710 |
|
if(p.leadingCoefficientIsPositive()){ |
711 |
|
return SumPair(p, -c); |
712 |
|
}else{ |
713 |
|
return SumPair(-p, c); |
714 |
|
} |
715 |
|
} |
716 |
36967 |
case kind::EQUAL: |
717 |
|
case kind::DISTINCT: |
718 |
|
{ |
719 |
73934 |
Polynomial left = getLeft(); |
720 |
73934 |
Polynomial right = getRight(); |
721 |
36967 |
Debug("nf::tmp") << "left: " << left.getNode() << endl; |
722 |
36967 |
Debug("nf::tmp") << "right: " << right.getNode() << endl; |
723 |
36967 |
if(right.isConstant()){ |
724 |
14340 |
return SumPair(left, -right.getHead().getConstant()); |
725 |
22627 |
}else if(right.containsConstant()){ |
726 |
10435 |
Assert(!right.singleton()); |
727 |
|
|
728 |
20870 |
Polynomial noConstant = right.getTail(); |
729 |
10435 |
return SumPair(left - noConstant, -right.getHead().getConstant()); |
730 |
|
}else{ |
731 |
12192 |
return SumPair(left - right, Constant::mkZero()); |
732 |
|
} |
733 |
|
} |
734 |
|
default: Unhandled() << cmpKind; |
735 |
|
} |
736 |
|
} |
737 |
|
|
738 |
1046201 |
Polynomial Comparison::normalizedVariablePart() const { |
739 |
1046201 |
Kind cmpKind = comparisonKind(); |
740 |
1046201 |
switch(cmpKind){ |
741 |
572613 |
case kind::LT: |
742 |
|
case kind::LEQ: |
743 |
|
case kind::GT: |
744 |
|
case kind::GEQ: |
745 |
|
{ |
746 |
1145226 |
TNode lit = getNode(); |
747 |
1145226 |
TNode atom = (cmpKind == kind::LT || cmpKind == kind::LEQ) ? lit[0] : lit; |
748 |
1145226 |
Polynomial p = Polynomial::parsePolynomial(atom[0]); |
749 |
572613 |
if(p.leadingCoefficientIsPositive()){ |
750 |
473188 |
return p; |
751 |
|
}else{ |
752 |
99425 |
return -p; |
753 |
|
} |
754 |
|
} |
755 |
473588 |
case kind::EQUAL: |
756 |
|
case kind::DISTINCT: |
757 |
|
{ |
758 |
947176 |
Polynomial left = getLeft(); |
759 |
947176 |
Polynomial right = getRight(); |
760 |
473588 |
if(right.isConstant()){ |
761 |
219228 |
return left; |
762 |
|
}else{ |
763 |
508720 |
Polynomial noConstant = right.containsConstant() ? right.getTail() : right; |
764 |
508720 |
Polynomial diff = left - noConstant; |
765 |
254360 |
if(diff.leadingCoefficientIsPositive()){ |
766 |
251744 |
return diff; |
767 |
|
}else{ |
768 |
2616 |
return -diff; |
769 |
|
} |
770 |
|
} |
771 |
|
} |
772 |
|
default: Unhandled() << cmpKind; |
773 |
|
} |
774 |
|
} |
775 |
|
|
776 |
1044838 |
DeltaRational Comparison::normalizedDeltaRational() const { |
777 |
1044838 |
Kind cmpKind = comparisonKind(); |
778 |
1044838 |
int delta = deltaCoeff(cmpKind); |
779 |
1044838 |
switch(cmpKind){ |
780 |
571469 |
case kind::LT: |
781 |
|
case kind::LEQ: |
782 |
|
case kind::GT: |
783 |
|
case kind::GEQ: |
784 |
|
{ |
785 |
1142938 |
Node lit = getNode(); |
786 |
1142938 |
Node atom = (cmpKind == kind::LT || cmpKind == kind::LEQ) ? lit[0] : lit; |
787 |
1142938 |
Polynomial left = Polynomial::parsePolynomial(atom[0]); |
788 |
571469 |
const Rational& q = atom[1].getConst<Rational>(); |
789 |
571469 |
if(left.leadingCoefficientIsPositive()){ |
790 |
472239 |
return DeltaRational(q, delta); |
791 |
|
}else{ |
792 |
99230 |
return DeltaRational(-q, -delta); |
793 |
|
} |
794 |
|
} |
795 |
473369 |
case kind::EQUAL: |
796 |
|
case kind::DISTINCT: |
797 |
|
{ |
798 |
946738 |
Polynomial right = getRight(); |
799 |
946738 |
Monomial firstRight = right.getHead(); |
800 |
473369 |
if(firstRight.isConstant()){ |
801 |
531784 |
DeltaRational c = DeltaRational(firstRight.getConstant().getValue(), 0); |
802 |
531784 |
Polynomial left = getLeft(); |
803 |
265892 |
if(!left.allIntegralVariables()){ |
804 |
23800 |
return c; |
805 |
|
//this is a qpolynomial and the sign of the leading |
806 |
|
//coefficient will not change after the diff below |
807 |
|
} else{ |
808 |
|
// the polynomial may be a z polynomial in which case |
809 |
|
// taking the diff is the simplest and obviously correct means |
810 |
484184 |
Polynomial diff = right.singleton() ? left : left - right.getTail(); |
811 |
242092 |
if(diff.leadingCoefficientIsPositive()){ |
812 |
241552 |
return c; |
813 |
|
}else{ |
814 |
540 |
return -c; |
815 |
|
} |
816 |
|
} |
817 |
|
}else{ // The constant is 0 sign cannot change |
818 |
207477 |
return DeltaRational(0, 0); |
819 |
|
} |
820 |
|
} |
821 |
|
default: Unhandled() << cmpKind; |
822 |
|
} |
823 |
|
} |
824 |
|
|
825 |
293418 |
std::tuple<Polynomial, Kind, Constant> Comparison::decompose( |
826 |
|
bool split_constant) const |
827 |
|
{ |
828 |
293418 |
Kind rel = getNode().getKind(); |
829 |
293418 |
if (rel == Kind::NOT) |
830 |
|
{ |
831 |
133686 |
switch (getNode()[0].getKind()) |
832 |
|
{ |
833 |
|
case kind::LEQ: rel = Kind::GT; break; |
834 |
|
case kind::LT: rel = Kind::GEQ; break; |
835 |
44180 |
case kind::EQUAL: rel = Kind::DISTINCT; break; |
836 |
|
case kind::DISTINCT: rel = Kind::EQUAL; break; |
837 |
89506 |
case kind::GEQ: rel = Kind::LT; break; |
838 |
|
case kind::GT: rel = Kind::LEQ; break; |
839 |
|
default: |
840 |
|
Assert(false) << "Unsupported relation: " << getNode()[0].getKind(); |
841 |
|
} |
842 |
|
} |
843 |
|
|
844 |
586836 |
Polynomial poly = getLeft() - getRight(); |
845 |
|
|
846 |
293418 |
if (!split_constant) |
847 |
|
{ |
848 |
|
return std::tuple<Polynomial, Kind, Constant>{ |
849 |
80 |
poly, rel, Constant::mkZero()}; |
850 |
|
} |
851 |
|
|
852 |
586676 |
Constant right = Constant::mkZero(); |
853 |
293338 |
if (poly.containsConstant()) |
854 |
|
{ |
855 |
121104 |
right = -poly.getHead().getConstant(); |
856 |
121104 |
poly = poly + Polynomial::mkPolynomial(right); |
857 |
|
} |
858 |
|
|
859 |
586676 |
Constant lcoeff = poly.getHead().getConstant(); |
860 |
293338 |
if (!lcoeff.isOne()) |
861 |
|
{ |
862 |
85002 |
Constant invlcoeff = lcoeff.inverse(); |
863 |
42501 |
if (lcoeff.isNegative()) |
864 |
|
{ |
865 |
36749 |
switch (rel) |
866 |
|
{ |
867 |
|
case kind::LEQ: rel = Kind::GEQ; break; |
868 |
18737 |
case kind::LT: rel = Kind::GT; break; |
869 |
470 |
case kind::EQUAL: break; |
870 |
258 |
case kind::DISTINCT: break; |
871 |
17284 |
case kind::GEQ: rel = Kind::LEQ; break; |
872 |
|
case kind::GT: rel = Kind::LT; break; |
873 |
|
default: Assert(false) << "Unsupported relation: " << rel; |
874 |
|
} |
875 |
|
} |
876 |
42501 |
poly = poly * invlcoeff; |
877 |
42501 |
right = right * invlcoeff; |
878 |
|
} |
879 |
|
|
880 |
293338 |
return std::tuple<Polynomial, Kind, Constant>{poly, rel, right}; |
881 |
|
} |
882 |
|
|
883 |
2387112 |
Comparison Comparison::parseNormalForm(TNode n) { |
884 |
2387112 |
Debug("polynomial") << "Comparison::parseNormalForm(" << n << ")"; |
885 |
2387112 |
Comparison result(n); |
886 |
2387112 |
Assert(result.isNormalForm()); |
887 |
2387112 |
return result; |
888 |
|
} |
889 |
|
|
890 |
728103 |
Node Comparison::toNode(Kind k, const Polynomial& l, const Constant& r) { |
891 |
728103 |
Assert(isRelationOperator(k)); |
892 |
728103 |
switch(k) { |
893 |
728103 |
case kind::GEQ: |
894 |
|
case kind::GT: |
895 |
1456206 |
return NodeManager::currentNM()->mkNode(k, l.getNode(), r.getNode()); |
896 |
|
default: Unhandled() << k; |
897 |
|
} |
898 |
|
} |
899 |
|
|
900 |
1462791 |
Node Comparison::toNode(Kind k, const Polynomial& l, const Polynomial& r) { |
901 |
1462791 |
Assert(isRelationOperator(k)); |
902 |
1462791 |
switch(k) { |
903 |
1462791 |
case kind::GEQ: |
904 |
|
case kind::EQUAL: |
905 |
|
case kind::GT: |
906 |
1462791 |
return NodeManager::currentNM()->mkNode(k, l.getNode(), r.getNode()); |
907 |
|
case kind::LEQ: |
908 |
|
return toNode(kind::GEQ, r, l).notNode(); |
909 |
|
case kind::LT: |
910 |
|
return toNode(kind::GT, r, l).notNode(); |
911 |
|
case kind::DISTINCT: |
912 |
|
return toNode(kind::EQUAL, r, l).notNode(); |
913 |
|
default: |
914 |
|
Unreachable(); |
915 |
|
} |
916 |
|
} |
917 |
|
|
918 |
9230908 |
bool Comparison::rightIsConstant() const { |
919 |
9230908 |
if(getNode().getKind() == kind::NOT){ |
920 |
1451490 |
return getNode()[0][1].getKind() == kind::CONST_RATIONAL; |
921 |
|
}else{ |
922 |
7779418 |
return getNode()[1].getKind() == kind::CONST_RATIONAL; |
923 |
|
} |
924 |
|
} |
925 |
|
|
926 |
|
size_t Comparison::getComplexity() const{ |
927 |
|
switch(comparisonKind()){ |
928 |
|
case kind::CONST_BOOLEAN: return 1; |
929 |
|
case kind::LT: |
930 |
|
case kind::LEQ: |
931 |
|
case kind::DISTINCT: |
932 |
|
case kind::EQUAL: |
933 |
|
case kind::GT: |
934 |
|
case kind::GEQ: |
935 |
|
return getLeft().getComplexity() + getRight().getComplexity(); |
936 |
|
default: Unhandled() << comparisonKind(); return -1; |
937 |
|
} |
938 |
|
} |
939 |
|
|
940 |
19032900 |
Polynomial Comparison::getLeft() const { |
941 |
38065800 |
TNode left; |
942 |
19032900 |
Kind k = comparisonKind(); |
943 |
19032900 |
switch(k){ |
944 |
3811931 |
case kind::LT: |
945 |
|
case kind::LEQ: |
946 |
|
case kind::DISTINCT: |
947 |
3811931 |
left = getNode()[0][0]; |
948 |
3811931 |
break; |
949 |
15220969 |
case kind::EQUAL: |
950 |
|
case kind::GT: |
951 |
|
case kind::GEQ: |
952 |
15220969 |
left = getNode()[0]; |
953 |
15220969 |
break; |
954 |
|
default: Unhandled() << k; |
955 |
|
} |
956 |
38065800 |
return Polynomial::parsePolynomial(left); |
957 |
|
} |
958 |
|
|
959 |
13042538 |
Polynomial Comparison::getRight() const { |
960 |
26085076 |
TNode right; |
961 |
13042538 |
Kind k = comparisonKind(); |
962 |
13042538 |
switch(k){ |
963 |
2218768 |
case kind::LT: |
964 |
|
case kind::LEQ: |
965 |
|
case kind::DISTINCT: |
966 |
2218768 |
right = getNode()[0][1]; |
967 |
2218768 |
break; |
968 |
10823770 |
case kind::EQUAL: |
969 |
|
case kind::GT: |
970 |
|
case kind::GEQ: |
971 |
10823770 |
right = getNode()[1]; |
972 |
10823770 |
break; |
973 |
|
default: Unhandled() << k; |
974 |
|
} |
975 |
26085076 |
return Polynomial::parsePolynomial(right); |
976 |
|
} |
977 |
|
|
978 |
|
// Polynomial Comparison::getLeft() const { |
979 |
|
// Node n = getNode(); |
980 |
|
// Node left = (n.getKind() == kind::NOT ? n[0]: n)[0]; |
981 |
|
// return Polynomial::parsePolynomial(left); |
982 |
|
// } |
983 |
|
|
984 |
|
// Polynomial Comparison::getRight() const { |
985 |
|
// Node n = getNode(); |
986 |
|
// Node right = (n.getKind() == kind::NOT ? n[0]: n)[1]; |
987 |
|
// return Polynomial::parsePolynomial(right); |
988 |
|
// } |
989 |
|
|
990 |
11792571 |
bool Comparison::isNormalForm() const { |
991 |
23585142 |
Node n = getNode(); |
992 |
11792571 |
Kind cmpKind = comparisonKind(n); |
993 |
11792571 |
Debug("nf::tmp") << "isNormalForm " << n << " " << cmpKind << endl; |
994 |
11792571 |
switch(cmpKind){ |
995 |
302846 |
case kind::CONST_BOOLEAN: |
996 |
302846 |
return true; |
997 |
|
case kind::GT: |
998 |
|
return isNormalGT(); |
999 |
3889709 |
case kind::GEQ: |
1000 |
3889709 |
return isNormalGEQ(); |
1001 |
5231825 |
case kind::EQUAL: |
1002 |
5231825 |
return isNormalEquality(); |
1003 |
1451490 |
case kind::LT: |
1004 |
1451490 |
return isNormalLT(); |
1005 |
|
case kind::LEQ: |
1006 |
|
return isNormalLEQ(); |
1007 |
916701 |
case kind::DISTINCT: |
1008 |
916701 |
return isNormalDistinct(); |
1009 |
|
default: |
1010 |
|
return false; |
1011 |
|
} |
1012 |
|
} |
1013 |
|
|
1014 |
|
/** This must be (> qpolynomial constant) */ |
1015 |
|
bool Comparison::isNormalGT() const { |
1016 |
|
Node n = getNode(); |
1017 |
|
Assert(n.getKind() == kind::GT); |
1018 |
|
if(!rightIsConstant()){ |
1019 |
|
return false; |
1020 |
|
}else{ |
1021 |
|
Polynomial left = getLeft(); |
1022 |
|
if(left.containsConstant()){ |
1023 |
|
return false; |
1024 |
|
}else if(!left.leadingCoefficientIsAbsOne()){ |
1025 |
|
return false; |
1026 |
|
}else{ |
1027 |
|
return !left.isIntegral(); |
1028 |
|
} |
1029 |
|
} |
1030 |
|
} |
1031 |
|
|
1032 |
|
/** This must be (not (> qpolynomial constant)) */ |
1033 |
|
bool Comparison::isNormalLEQ() const { |
1034 |
|
Node n = getNode(); |
1035 |
|
Debug("nf::tmp") << "isNormalLEQ " << n << endl; |
1036 |
|
Assert(n.getKind() == kind::NOT); |
1037 |
|
Assert(n[0].getKind() == kind::GT); |
1038 |
|
if(!rightIsConstant()){ |
1039 |
|
return false; |
1040 |
|
}else{ |
1041 |
|
Polynomial left = getLeft(); |
1042 |
|
if(left.containsConstant()){ |
1043 |
|
return false; |
1044 |
|
}else if(!left.leadingCoefficientIsAbsOne()){ |
1045 |
|
return false; |
1046 |
|
}else{ |
1047 |
|
return !left.isIntegral(); |
1048 |
|
} |
1049 |
|
} |
1050 |
|
} |
1051 |
|
|
1052 |
|
|
1053 |
|
/** This must be (>= qpolynomial constant) or (>= zpolynomial constant) */ |
1054 |
3889709 |
bool Comparison::isNormalGEQ() const { |
1055 |
7779418 |
Node n = getNode(); |
1056 |
3889709 |
Assert(n.getKind() == kind::GEQ); |
1057 |
|
|
1058 |
3889709 |
Debug("nf::tmp") << "isNormalGEQ " << n << " " << rightIsConstant() << endl; |
1059 |
|
|
1060 |
3889709 |
if(!rightIsConstant()){ |
1061 |
|
return false; |
1062 |
|
}else{ |
1063 |
7779418 |
Polynomial left = getLeft(); |
1064 |
3889709 |
if(left.containsConstant()){ |
1065 |
|
return false; |
1066 |
|
}else{ |
1067 |
3889709 |
if(left.isIntegral()){ |
1068 |
2407392 |
return left.signNormalizedReducedSum(); |
1069 |
|
}else{ |
1070 |
1482317 |
return left.leadingCoefficientIsAbsOne(); |
1071 |
|
} |
1072 |
|
} |
1073 |
|
} |
1074 |
|
} |
1075 |
|
|
1076 |
|
/** This must be (not (>= qpolynomial constant)) or (not (>= zpolynomial constant)) */ |
1077 |
1451490 |
bool Comparison::isNormalLT() const { |
1078 |
2902980 |
Node n = getNode(); |
1079 |
1451490 |
Assert(n.getKind() == kind::NOT); |
1080 |
1451490 |
Assert(n[0].getKind() == kind::GEQ); |
1081 |
|
|
1082 |
1451490 |
if(!rightIsConstant()){ |
1083 |
|
return false; |
1084 |
|
}else{ |
1085 |
2902980 |
Polynomial left = getLeft(); |
1086 |
1451490 |
if(left.containsConstant()){ |
1087 |
|
return false; |
1088 |
|
}else{ |
1089 |
1451490 |
if(left.isIntegral()){ |
1090 |
1019552 |
return left.signNormalizedReducedSum(); |
1091 |
|
}else{ |
1092 |
431938 |
return left.leadingCoefficientIsAbsOne(); |
1093 |
|
} |
1094 |
|
} |
1095 |
|
} |
1096 |
|
} |
1097 |
|
|
1098 |
|
|
1099 |
6148526 |
bool Comparison::isNormalEqualityOrDisequality() const { |
1100 |
12297052 |
Polynomial pleft = getLeft(); |
1101 |
|
|
1102 |
6148526 |
if(pleft.numMonomials() == 1){ |
1103 |
12297052 |
Monomial mleft = pleft.getHead(); |
1104 |
6148526 |
if(mleft.isConstant()){ |
1105 |
|
return false; |
1106 |
|
}else{ |
1107 |
12297052 |
Polynomial pright = getRight(); |
1108 |
6148526 |
if(allIntegralVariables()){ |
1109 |
5577734 |
const Rational& lcoeff = mleft.getConstant().getValue(); |
1110 |
5577734 |
if(pright.isConstant()){ |
1111 |
2186466 |
return pright.isIntegral() && lcoeff.isOne(); |
1112 |
|
} |
1113 |
6782536 |
Polynomial varRight = pright.containsConstant() ? pright.getTail() : pright; |
1114 |
3391268 |
if(lcoeff.sgn() <= 0){ |
1115 |
|
return false; |
1116 |
|
}else{ |
1117 |
6782536 |
Integer lcm = lcoeff.getDenominator().lcm(varRight.denominatorLCM()); |
1118 |
6782536 |
Integer g = lcoeff.getNumerator().gcd(varRight.numeratorGCD()); |
1119 |
3391268 |
Debug("nf::tmp") << lcm << " " << g << endl; |
1120 |
3391268 |
if(!lcm.isOne()){ |
1121 |
|
return false; |
1122 |
3391268 |
}else if(!g.isOne()){ |
1123 |
|
return false; |
1124 |
|
}else{ |
1125 |
6782536 |
Monomial absMinRight = varRight.selectAbsMinimum(); |
1126 |
3391268 |
Debug("nf::tmp") << mleft.getNode() << " " << absMinRight.getNode() << endl; |
1127 |
3391268 |
if( mleft.absCmp(absMinRight) < 0){ |
1128 |
76157 |
return true; |
1129 |
|
}else{ |
1130 |
3315111 |
return (!(absMinRight.absCmp(mleft)< 0)) && mleft < absMinRight; |
1131 |
|
} |
1132 |
|
} |
1133 |
|
} |
1134 |
|
}else{ |
1135 |
570792 |
if(mleft.coefficientIsOne()){ |
1136 |
1141584 |
Debug("nf::tmp") |
1137 |
570792 |
<< "dfklj " << mleft.getNode() << endl |
1138 |
570792 |
<< pright.getNode() << endl |
1139 |
1141584 |
<< pright.variableMonomialAreStrictlyGreater(mleft) |
1140 |
570792 |
<< endl; |
1141 |
570792 |
return pright.variableMonomialAreStrictlyGreater(mleft); |
1142 |
|
}else{ |
1143 |
|
return false; |
1144 |
|
} |
1145 |
|
} |
1146 |
|
} |
1147 |
|
}else{ |
1148 |
|
return false; |
1149 |
|
} |
1150 |
|
} |
1151 |
|
|
1152 |
|
/** This must be (= qvarlist qpolynomial) or (= zmonomial zpolynomial)*/ |
1153 |
5231825 |
bool Comparison::isNormalEquality() const { |
1154 |
5231825 |
Assert(getNode().getKind() == kind::EQUAL); |
1155 |
15695475 |
return Theory::theoryOf(getNode()[0].getType()) == THEORY_ARITH && |
1156 |
15695475 |
isNormalEqualityOrDisequality(); |
1157 |
|
} |
1158 |
|
|
1159 |
|
/** |
1160 |
|
* This must be (not (= qvarlist qpolynomial)) or |
1161 |
|
* (not (= zmonomial zpolynomial)). |
1162 |
|
*/ |
1163 |
916701 |
bool Comparison::isNormalDistinct() const { |
1164 |
916701 |
Assert(getNode().getKind() == kind::NOT); |
1165 |
916701 |
Assert(getNode()[0].getKind() == kind::EQUAL); |
1166 |
|
|
1167 |
2750103 |
return Theory::theoryOf(getNode()[0][0].getType()) == THEORY_ARITH && |
1168 |
2750103 |
isNormalEqualityOrDisequality(); |
1169 |
|
} |
1170 |
|
|
1171 |
71871 |
Node Comparison::mkRatEquality(const Polynomial& p){ |
1172 |
71871 |
Assert(!p.isConstant()); |
1173 |
71871 |
Assert(!p.allIntegralVariables()); |
1174 |
|
|
1175 |
143742 |
Monomial minimalVList = p.minimumVariableMonomial(); |
1176 |
143742 |
Constant coeffInv = -(minimalVList.getConstant().inverse()); |
1177 |
|
|
1178 |
143742 |
Polynomial newRight = (p - minimalVList) * coeffInv; |
1179 |
143742 |
Polynomial newLeft(Monomial::mkMonomial(minimalVList.getVarList())); |
1180 |
|
|
1181 |
143742 |
return toNode(kind::EQUAL, newLeft, newRight); |
1182 |
|
} |
1183 |
|
|
1184 |
257514 |
Node Comparison::mkRatInequality(Kind k, const Polynomial& p){ |
1185 |
257514 |
Assert(k == kind::GEQ || k == kind::GT); |
1186 |
257514 |
Assert(!p.isConstant()); |
1187 |
257514 |
Assert(!p.allIntegralVariables()); |
1188 |
|
|
1189 |
515028 |
SumPair sp = SumPair::mkSumPair(p); |
1190 |
515028 |
Polynomial left = sp.getPolynomial(); |
1191 |
515028 |
Constant right = - sp.getConstant(); |
1192 |
|
|
1193 |
515028 |
Monomial minimalVList = left.getHead(); |
1194 |
257514 |
Assert(!minimalVList.isConstant()); |
1195 |
|
|
1196 |
515028 |
Constant coeffInv = minimalVList.getConstant().inverse().abs(); |
1197 |
515028 |
Polynomial newLeft = left * coeffInv; |
1198 |
515028 |
Constant newRight = right * (coeffInv); |
1199 |
|
|
1200 |
515028 |
return toNode(k, newLeft, newRight); |
1201 |
|
} |
1202 |
|
|
1203 |
470589 |
Node Comparison::mkIntInequality(Kind k, const Polynomial& p){ |
1204 |
470589 |
Assert(kind::GT == k || kind::GEQ == k); |
1205 |
470589 |
Assert(!p.isConstant()); |
1206 |
470589 |
Assert(p.allIntegralVariables()); |
1207 |
|
|
1208 |
941178 |
SumPair sp = SumPair::mkSumPair(p); |
1209 |
941178 |
Polynomial left = sp.getPolynomial(); |
1210 |
941178 |
Rational right = - (sp.getConstant().getValue()); |
1211 |
|
|
1212 |
|
|
1213 |
941178 |
Monomial m = left.getHead(); |
1214 |
470589 |
Assert(!m.isConstant()); |
1215 |
|
|
1216 |
941178 |
Integer lcm = left.denominatorLCM(); |
1217 |
941178 |
Integer g = left.numeratorGCD(); |
1218 |
941178 |
Rational mult(lcm,g); |
1219 |
|
|
1220 |
941178 |
Polynomial newLeft = left * mult; |
1221 |
941178 |
Rational rightMult = right * mult; |
1222 |
|
|
1223 |
470589 |
bool negateResult = false; |
1224 |
470589 |
if(!newLeft.leadingCoefficientIsPositive()){ |
1225 |
|
// multiply by -1 |
1226 |
|
// a: left >= right or b: left > right |
1227 |
|
// becomes |
1228 |
|
// a: -left <= -right or b: -left < -right |
1229 |
|
// a: not (-left > -right) or b: (not -left >= -right) |
1230 |
91377 |
newLeft = -newLeft; |
1231 |
91377 |
rightMult = -rightMult; |
1232 |
91377 |
k = (kind::GT == k) ? kind::GEQ : kind::GT; |
1233 |
91377 |
negateResult = true; |
1234 |
|
// the later stages handle: |
1235 |
|
// a: not (-left >= -right + 1) or b: (not -left >= -right) |
1236 |
|
} |
1237 |
|
|
1238 |
941178 |
Node result = Node::null(); |
1239 |
470589 |
if(rightMult.isIntegral()){ |
1240 |
465838 |
if(k == kind::GT){ |
1241 |
|
// (> p z) |
1242 |
|
// (>= p (+ z 1)) |
1243 |
178118 |
Constant rightMultPlusOne = Constant::mkConstant(rightMult + 1); |
1244 |
89059 |
result = toNode(kind::GEQ, newLeft, rightMultPlusOne); |
1245 |
|
}else{ |
1246 |
753558 |
Constant newRight = Constant::mkConstant(rightMult); |
1247 |
376779 |
result = toNode(kind::GEQ, newLeft, newRight); |
1248 |
|
} |
1249 |
|
}else{ |
1250 |
|
//(>= l (/ n d)) |
1251 |
|
//(>= l (ceil (/ n d))) |
1252 |
|
//This also hold for GT as (ceil (/ n d)) > (/ n d) |
1253 |
9502 |
Integer ceilr = rightMult.ceiling(); |
1254 |
9502 |
Constant ceilRight = Constant::mkConstant(ceilr); |
1255 |
4751 |
result = toNode(kind::GEQ, newLeft, ceilRight); |
1256 |
|
} |
1257 |
470589 |
Assert(!result.isNull()); |
1258 |
470589 |
if(negateResult){ |
1259 |
91377 |
return result.notNode(); |
1260 |
|
}else{ |
1261 |
379212 |
return result; |
1262 |
|
} |
1263 |
|
} |
1264 |
|
|
1265 |
789435 |
Node Comparison::mkIntEquality(const Polynomial& p){ |
1266 |
789435 |
Assert(!p.isConstant()); |
1267 |
789435 |
Assert(p.allIntegralVariables()); |
1268 |
|
|
1269 |
1578870 |
SumPair sp = SumPair::mkSumPair(p); |
1270 |
1578870 |
Polynomial varPart = sp.getPolynomial(); |
1271 |
1578870 |
Constant constPart = sp.getConstant(); |
1272 |
|
|
1273 |
1578870 |
Integer lcm = varPart.denominatorLCM(); |
1274 |
1578870 |
Integer g = varPart.numeratorGCD(); |
1275 |
1578870 |
Constant mult = Constant::mkConstant(Rational(lcm,g)); |
1276 |
|
|
1277 |
1578870 |
Constant constMult = constPart * mult; |
1278 |
|
|
1279 |
789435 |
if(constMult.isIntegral()){ |
1280 |
1577862 |
Polynomial varPartMult = varPart * mult; |
1281 |
|
|
1282 |
1577862 |
Monomial m = varPartMult.selectAbsMinimum(); |
1283 |
788931 |
bool mIsPositive = m.getConstant().isPositive(); |
1284 |
|
|
1285 |
1577862 |
Polynomial noM = (varPartMult + (- m)) + Polynomial::mkPolynomial(constMult); |
1286 |
|
|
1287 |
|
// m + noM = 0 |
1288 |
1577862 |
Polynomial newRight = mIsPositive ? -noM : noM; |
1289 |
1577862 |
Polynomial newLeft = mIsPositive ? m : -m; |
1290 |
|
|
1291 |
788931 |
Assert(newRight.isIntegral()); |
1292 |
788931 |
return toNode(kind::EQUAL, newLeft, newRight); |
1293 |
|
}else{ |
1294 |
504 |
return mkBoolNode(false); |
1295 |
|
} |
1296 |
|
} |
1297 |
|
|
1298 |
2492732 |
Comparison Comparison::mkComparison(Kind k, const Polynomial& l, const Polynomial& r){ |
1299 |
|
|
1300 |
|
//Make this special case fast for sharing! |
1301 |
2492732 |
if((k == kind::EQUAL || k == kind::DISTINCT) && l.isVarList() && r.isVarList()){ |
1302 |
1206056 |
VarList vLeft = l.asVarList(); |
1303 |
1206056 |
VarList vRight = r.asVarList(); |
1304 |
|
|
1305 |
603028 |
if(vLeft == vRight){ |
1306 |
|
// return true for equalities and false for disequalities |
1307 |
1039 |
return Comparison(k == kind::EQUAL); |
1308 |
|
}else{ |
1309 |
1203978 |
Node eqNode = vLeft < vRight ? toNode( kind::EQUAL, l, r) : toNode( kind::EQUAL, r, l); |
1310 |
1203978 |
Node forK = (k == kind::DISTINCT) ? eqNode.notNode() : eqNode; |
1311 |
601989 |
return Comparison(forK); |
1312 |
|
} |
1313 |
|
} |
1314 |
|
|
1315 |
|
//General case |
1316 |
3779408 |
Polynomial diff = l - r; |
1317 |
1889704 |
if(diff.isConstant()){ |
1318 |
300295 |
bool res = evaluateConstantPredicate(k, diff.asConstant(), Rational(0)); |
1319 |
300295 |
return Comparison(res); |
1320 |
|
}else{ |
1321 |
3178818 |
Node result = Node::null(); |
1322 |
1589409 |
bool isInteger = diff.allIntegralVariables(); |
1323 |
1589409 |
switch(k){ |
1324 |
861306 |
case kind::EQUAL: |
1325 |
861306 |
result = isInteger ? mkIntEquality(diff) : mkRatEquality(diff); |
1326 |
861306 |
break; |
1327 |
|
case kind::DISTINCT: |
1328 |
|
{ |
1329 |
|
Node eq = isInteger ? mkIntEquality(diff) : mkRatEquality(diff); |
1330 |
|
result = eq.notNode(); |
1331 |
|
} |
1332 |
|
break; |
1333 |
110815 |
case kind::LEQ: |
1334 |
|
case kind::LT: |
1335 |
|
{ |
1336 |
221630 |
Polynomial neg = - diff; |
1337 |
110815 |
Kind negKind = (k == kind::LEQ ? kind::GEQ : kind::GT); |
1338 |
110815 |
result = isInteger ? |
1339 |
110815 |
mkIntInequality(negKind, neg) : mkRatInequality(negKind, neg); |
1340 |
|
} |
1341 |
110815 |
break; |
1342 |
617288 |
case kind::GEQ: |
1343 |
|
case kind::GT: |
1344 |
617288 |
result = isInteger ? |
1345 |
|
mkIntInequality(k, diff) : mkRatInequality(k, diff); |
1346 |
617288 |
break; |
1347 |
|
default: Unhandled() << k; |
1348 |
|
} |
1349 |
1589409 |
Assert(!result.isNull()); |
1350 |
1589409 |
if(result.getKind() == kind::NOT && result[0].getKind() == kind::CONST_BOOLEAN){ |
1351 |
|
return Comparison(!(result[0].getConst<bool>())); |
1352 |
|
}else{ |
1353 |
3178818 |
Comparison cmp(result); |
1354 |
1589409 |
Assert(cmp.isNormalForm()); |
1355 |
1589409 |
return cmp; |
1356 |
|
} |
1357 |
|
} |
1358 |
|
} |
1359 |
|
|
1360 |
36967 |
bool Comparison::isBoolean() const { |
1361 |
36967 |
return getNode().getKind() == kind::CONST_BOOLEAN; |
1362 |
|
} |
1363 |
|
|
1364 |
|
|
1365 |
36967 |
bool Comparison::debugIsIntegral() const{ |
1366 |
36967 |
return getLeft().isIntegral() && getRight().isIntegral(); |
1367 |
|
} |
1368 |
|
|
1369 |
52616892 |
Kind Comparison::comparisonKind(TNode literal){ |
1370 |
52616892 |
switch(literal.getKind()){ |
1371 |
40585680 |
case kind::CONST_BOOLEAN: |
1372 |
|
case kind::GT: |
1373 |
|
case kind::GEQ: |
1374 |
|
case kind::EQUAL: |
1375 |
40585680 |
return literal.getKind(); |
1376 |
12031212 |
case kind::NOT: |
1377 |
|
{ |
1378 |
24062424 |
TNode negatedAtom = literal[0]; |
1379 |
12031212 |
switch(negatedAtom.getKind()){ |
1380 |
|
case kind::GT: //(not (GT x c)) <=> (LEQ x c) |
1381 |
|
return kind::LEQ; |
1382 |
5567086 |
case kind::GEQ: //(not (GEQ x c)) <=> (LT x c) |
1383 |
5567086 |
return kind::LT; |
1384 |
6464126 |
case kind::EQUAL: |
1385 |
6464126 |
return kind::DISTINCT; |
1386 |
|
default: |
1387 |
|
return kind::UNDEFINED_KIND; |
1388 |
|
} |
1389 |
|
} |
1390 |
|
default: |
1391 |
|
return kind::UNDEFINED_KIND; |
1392 |
|
} |
1393 |
|
} |
1394 |
|
|
1395 |
|
|
1396 |
|
Node Polynomial::makeAbsCondition(Variable v, Polynomial p){ |
1397 |
|
Polynomial zerop = Polynomial::mkZero(); |
1398 |
|
|
1399 |
|
Polynomial varp = Polynomial::mkPolynomial(v); |
1400 |
|
Comparison pLeq0 = Comparison::mkComparison(kind::LEQ, p, zerop); |
1401 |
|
Comparison negP = Comparison::mkComparison(kind::EQUAL, varp, -p); |
1402 |
|
Comparison posP = Comparison::mkComparison(kind::EQUAL, varp, p); |
1403 |
|
|
1404 |
|
Node absCnd = (pLeq0.getNode()).iteNode(negP.getNode(), posP.getNode()); |
1405 |
|
return absCnd; |
1406 |
|
} |
1407 |
|
|
1408 |
36967 |
bool Polynomial::isNonlinear() const { |
1409 |
|
|
1410 |
108691 |
for(iterator i=begin(), iend =end(); i != iend; ++i){ |
1411 |
145185 |
Monomial m = *i; |
1412 |
73461 |
if(m.isNonlinear()){ |
1413 |
1737 |
return true; |
1414 |
|
} |
1415 |
|
} |
1416 |
35230 |
return false; |
1417 |
|
} |
1418 |
|
|
1419 |
|
} //namespace arith |
1420 |
|
} //namespace theory |
1421 |
29286 |
} // namespace cvc5 |