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 |
137651048 |
Constant Constant::mkConstant(const Rational& rat) { |
33 |
137651048 |
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 |
198422762 |
bool Variable::isLeafMember(Node n){ |
69 |
595268286 |
return (!isRelationOperator(n.getKind())) && |
70 |
595268286 |
(Theory::isLeafOf(n, theory::THEORY_ARITH)); |
71 |
|
} |
72 |
|
|
73 |
172612416 |
VarList::VarList(Node n) : NodeWrapper(n) { Assert(isSorted(begin(), end())); } |
74 |
|
|
75 |
342223 |
bool Variable::isIAndMember(Node n) |
76 |
|
{ |
77 |
1026669 |
return n.getKind() == kind::IAND && Polynomial::isMember(n[0]) |
78 |
1368892 |
&& Polynomial::isMember(n[1]); |
79 |
|
} |
80 |
|
|
81 |
218952 |
bool Variable::isDivMember(Node n){ |
82 |
218952 |
switch(n.getKind()){ |
83 |
141313 |
case kind::DIVISION: |
84 |
|
case kind::INTS_DIVISION: |
85 |
|
case kind::INTS_MODULUS: |
86 |
|
case kind::DIVISION_TOTAL: |
87 |
|
case kind::INTS_DIVISION_TOTAL: |
88 |
|
case kind::INTS_MODULUS_TOTAL: |
89 |
141313 |
return Polynomial::isMember(n[0]) && Polynomial::isMember(n[1]); |
90 |
77639 |
default: |
91 |
77639 |
return false; |
92 |
|
} |
93 |
|
} |
94 |
|
|
95 |
2694064 |
bool Variable::isTranscendentalMember(Node n) { |
96 |
2694064 |
switch(n.getKind()){ |
97 |
1393366 |
case kind::EXPONENTIAL: |
98 |
|
case kind::SINE: |
99 |
|
case kind::COSINE: |
100 |
|
case kind::TANGENT: |
101 |
|
case kind::COSECANT: |
102 |
|
case kind::SECANT: |
103 |
|
case kind::COTANGENT: |
104 |
|
case kind::ARCSINE: |
105 |
|
case kind::ARCCOSINE: |
106 |
|
case kind::ARCTANGENT: |
107 |
|
case kind::ARCCOSECANT: |
108 |
|
case kind::ARCSECANT: |
109 |
|
case kind::ARCCOTANGENT: |
110 |
1393366 |
case kind::SQRT: return Polynomial::isMember(n[0]); |
111 |
1300698 |
case kind::PI: |
112 |
1300698 |
return true; |
113 |
|
default: |
114 |
|
return false; |
115 |
|
} |
116 |
|
} |
117 |
|
|
118 |
|
|
119 |
177122566 |
bool VarList::isSorted(iterator start, iterator end) { |
120 |
177122566 |
return std::is_sorted(start, end); |
121 |
|
} |
122 |
|
|
123 |
131998724 |
bool VarList::isMember(Node n) { |
124 |
131998724 |
if(Variable::isMember(n)) { |
125 |
96236725 |
return true; |
126 |
|
} |
127 |
35761999 |
if(n.getKind() == kind::NONLINEAR_MULT) { |
128 |
4751234 |
Node::iterator curr = n.begin(), end = n.end(); |
129 |
9502468 |
Node prev = *curr; |
130 |
4751234 |
if(!Variable::isMember(prev)) return false; |
131 |
|
|
132 |
|
Variable::VariableNodeCmp cmp; |
133 |
|
|
134 |
16374948 |
while( (++curr) != end) { |
135 |
5811857 |
if(!Variable::isMember(*curr)) return false; |
136 |
|
// prev <= curr : accept |
137 |
|
// !(prev <= curr) : reject |
138 |
|
// !(!(prev > curr)) : reject |
139 |
|
// curr < prev : reject |
140 |
5811857 |
if((cmp(*curr, prev))) return false; |
141 |
5811857 |
prev = *curr; |
142 |
|
} |
143 |
4751234 |
return true; |
144 |
|
} else { |
145 |
31010765 |
return false; |
146 |
|
} |
147 |
|
} |
148 |
|
|
149 |
119077741 |
int VarList::cmp(const VarList& vl) const { |
150 |
119077741 |
int dif = this->size() - vl.size(); |
151 |
119077741 |
if (dif == 0) { |
152 |
89121239 |
if(this->getNode() == vl.getNode()) { |
153 |
12838886 |
return 0; |
154 |
|
} |
155 |
|
|
156 |
76282353 |
Assert(!empty()); |
157 |
76282353 |
Assert(!vl.empty()); |
158 |
76282353 |
if(this->size() == 1){ |
159 |
71848869 |
return Variable::VariableNodeCmp::cmp(this->getNode(), vl.getNode()); |
160 |
|
} |
161 |
|
|
162 |
|
|
163 |
8866968 |
internal_iterator ii=this->internalBegin(), ie=this->internalEnd(); |
164 |
8866968 |
internal_iterator ci=vl.internalBegin(), ce=vl.internalEnd(); |
165 |
17201091 |
for(; ii != ie; ++ii, ++ci){ |
166 |
12945222 |
Node vi = *ii; |
167 |
12945222 |
Node vc = *ci; |
168 |
8689353 |
int tmp = Variable::VariableNodeCmp::cmp(vi, vc); |
169 |
8689353 |
if(tmp != 0){ |
170 |
4433484 |
return tmp; |
171 |
|
} |
172 |
|
} |
173 |
|
Unreachable(); |
174 |
29956502 |
} else if(dif < 0) { |
175 |
16795828 |
return -1; |
176 |
|
} else { |
177 |
13160674 |
return 1; |
178 |
|
} |
179 |
|
} |
180 |
|
|
181 |
172612416 |
VarList VarList::parseVarList(Node n) { |
182 |
172612416 |
return VarList(n); |
183 |
|
// if(Variable::isMember(n)) { |
184 |
|
// return VarList(Variable(n)); |
185 |
|
// } else { |
186 |
|
// Assert(n.getKind() == kind::MULT); |
187 |
|
// for(Node::iterator i=n.begin(), end = n.end(); i!=end; ++i) { |
188 |
|
// Assert(Variable::isMember(*i)); |
189 |
|
// } |
190 |
|
// return VarList(n); |
191 |
|
// } |
192 |
|
} |
193 |
|
|
194 |
1189834 |
VarList VarList::operator*(const VarList& other) const { |
195 |
1189834 |
if(this->empty()) { |
196 |
1131985 |
return other; |
197 |
57849 |
} else if(other.empty()) { |
198 |
12756 |
return *this; |
199 |
|
} else { |
200 |
90186 |
vector<Node> result; |
201 |
|
|
202 |
|
internal_iterator |
203 |
90186 |
thisBegin = this->internalBegin(), |
204 |
90186 |
thisEnd = this->internalEnd(), |
205 |
90186 |
otherBegin = other.internalBegin(), |
206 |
90186 |
otherEnd = other.internalEnd(); |
207 |
|
|
208 |
|
Variable::VariableNodeCmp cmp; |
209 |
45093 |
std::merge(thisBegin, thisEnd, otherBegin, otherEnd, std::back_inserter(result), cmp); |
210 |
|
|
211 |
45093 |
Assert(result.size() >= 2); |
212 |
90186 |
Node mult = NodeManager::currentNM()->mkNode(kind::NONLINEAR_MULT, result); |
213 |
45093 |
return VarList::parseVarList(mult); |
214 |
|
} |
215 |
|
} |
216 |
|
|
217 |
149121720 |
bool Monomial::isMember(TNode n){ |
218 |
149121720 |
if(n.getKind() == kind::CONST_RATIONAL) { |
219 |
20676640 |
return true; |
220 |
128445080 |
} else if(multStructured(n)) { |
221 |
24957029 |
return VarList::isMember(n[1]); |
222 |
|
} else { |
223 |
103488051 |
return VarList::isMember(n); |
224 |
|
} |
225 |
|
} |
226 |
|
|
227 |
71043532 |
Monomial Monomial::mkMonomial(const Constant& c, const VarList& vl) { |
228 |
71043532 |
if(c.isZero() || vl.empty() ) { |
229 |
4220072 |
return Monomial(c); |
230 |
66823460 |
} else if(c.isOne()) { |
231 |
1572284 |
return Monomial(vl); |
232 |
|
} else { |
233 |
65251176 |
return Monomial(c, vl); |
234 |
|
} |
235 |
|
} |
236 |
|
|
237 |
70858 |
Monomial Monomial::mkMonomial(const VarList& vl) { |
238 |
|
// acts like Monomial::mkMonomial( 1, vl) |
239 |
70858 |
if( vl.empty() ) { |
240 |
|
return Monomial::mkOne(); |
241 |
|
} else if(true){ |
242 |
70858 |
return Monomial(vl); |
243 |
|
} |
244 |
|
} |
245 |
|
|
246 |
206636497 |
Monomial Monomial::parseMonomial(Node n) { |
247 |
206636497 |
if(n.getKind() == kind::CONST_RATIONAL) { |
248 |
34069218 |
return Monomial(Constant(n)); |
249 |
172567279 |
} else if(multStructured(n)) { |
250 |
61252872 |
return Monomial::mkMonomial(Constant(n[0]),VarList::parseVarList(n[1])); |
251 |
|
} else { |
252 |
111314407 |
return Monomial(VarList::parseVarList(n)); |
253 |
|
} |
254 |
|
} |
255 |
7243691 |
Monomial Monomial::operator*(const Rational& q) const { |
256 |
7243691 |
if(q.isZero()){ |
257 |
|
return mkZero(); |
258 |
|
}else{ |
259 |
14487382 |
Constant newConstant = this->getConstant() * q; |
260 |
7243691 |
return Monomial::mkMonomial(newConstant, getVarList()); |
261 |
|
} |
262 |
|
} |
263 |
|
|
264 |
|
Monomial Monomial::operator*(const Constant& c) const { |
265 |
|
return (*this) * c.getValue(); |
266 |
|
// if(c.isZero()){ |
267 |
|
// return mkZero(); |
268 |
|
// }else{ |
269 |
|
// Constant newConstant = this->getConstant() * c; |
270 |
|
// return Monomial::mkMonomial(newConstant, getVarList()); |
271 |
|
// } |
272 |
|
} |
273 |
|
|
274 |
1189834 |
Monomial Monomial::operator*(const Monomial& mono) const { |
275 |
2379668 |
Constant newConstant = this->getConstant() * mono.getConstant(); |
276 |
2379668 |
VarList newVL = this->getVarList() * mono.getVarList(); |
277 |
|
|
278 |
2379668 |
return Monomial::mkMonomial(newConstant, newVL); |
279 |
|
} |
280 |
|
|
281 |
|
// vector<Monomial> Monomial::sumLikeTerms(const std::vector<Monomial> & monos) |
282 |
|
// { |
283 |
|
// Assert(isSorted(monos)); |
284 |
|
// vector<Monomial> outMonomials; |
285 |
|
// typedef vector<Monomial>::const_iterator iterator; |
286 |
|
// for(iterator rangeIter = monos.begin(), end=monos.end(); rangeIter != end;) |
287 |
|
// { |
288 |
|
// Rational constant = (*rangeIter).getConstant().getValue(); |
289 |
|
// VarList varList = (*rangeIter).getVarList(); |
290 |
|
// ++rangeIter; |
291 |
|
// while(rangeIter != end && varList == (*rangeIter).getVarList()) { |
292 |
|
// constant += (*rangeIter).getConstant().getValue(); |
293 |
|
// ++rangeIter; |
294 |
|
// } |
295 |
|
// if(constant != 0) { |
296 |
|
// Constant asConstant = Constant::mkConstant(constant); |
297 |
|
// Monomial nonZero = Monomial::mkMonomial(asConstant, varList); |
298 |
|
// outMonomials.push_back(nonZero); |
299 |
|
// } |
300 |
|
// } |
301 |
|
|
302 |
|
// Assert(isStrictlySorted(outMonomials)); |
303 |
|
// return outMonomials; |
304 |
|
// } |
305 |
|
|
306 |
2514709 |
void Monomial::sort(std::vector<Monomial>& m){ |
307 |
2514709 |
if(!isSorted(m)){ |
308 |
114733 |
std::sort(m.begin(), m.end()); |
309 |
|
} |
310 |
2514709 |
} |
311 |
|
|
312 |
8577728 |
void Monomial::combineAdjacentMonomials(std::vector<Monomial>& monos) { |
313 |
8577728 |
Assert(isSorted(monos)); |
314 |
|
size_t writePos, readPos, N; |
315 |
27993085 |
for(writePos = 0, readPos = 0, N = monos.size(); readPos < N;){ |
316 |
19415357 |
Monomial& atRead = monos[readPos]; |
317 |
19415357 |
const VarList& varList = atRead.getVarList(); |
318 |
|
|
319 |
19415357 |
size_t rangeEnd = readPos+1; |
320 |
27905013 |
for(; rangeEnd < N; rangeEnd++){ |
321 |
15091712 |
if(!(varList == monos[rangeEnd].getVarList())){ break; } |
322 |
|
} |
323 |
|
// monos[i] for i in [readPos, rangeEnd) has the same var list |
324 |
19415357 |
if(readPos+1 == rangeEnd){ // no addition needed |
325 |
15291468 |
if(!atRead.getConstant().isZero()){ |
326 |
26633522 |
Monomial cpy = atRead; // being paranoid here |
327 |
13316761 |
monos[writePos] = cpy; |
328 |
13316761 |
writePos++; |
329 |
|
} |
330 |
|
}else{ |
331 |
8247778 |
Rational constant(monos[readPos].getConstant().getValue()); |
332 |
8368717 |
for(size_t i=readPos+1; i < rangeEnd; ++i){ |
333 |
4244828 |
constant += monos[i].getConstant().getValue(); |
334 |
|
} |
335 |
4123889 |
if(!constant.isZero()){ |
336 |
2711766 |
Constant asConstant = Constant::mkConstant(constant); |
337 |
2711766 |
Monomial nonZero = Monomial::mkMonomial(asConstant, varList); |
338 |
1355883 |
monos[writePos] = nonZero; |
339 |
1355883 |
writePos++; |
340 |
|
} |
341 |
|
} |
342 |
19415357 |
Assert(rangeEnd > readPos); |
343 |
19415357 |
readPos = rangeEnd; |
344 |
|
} |
345 |
8577728 |
if(writePos > 0 ){ |
346 |
14333814 |
Monomial cp = monos[0]; |
347 |
7166907 |
Assert(writePos <= N); |
348 |
7166907 |
monos.resize(writePos, cp); |
349 |
|
}else{ |
350 |
1410821 |
monos.clear(); |
351 |
|
} |
352 |
8577728 |
Assert(isStrictlySorted(monos)); |
353 |
8577728 |
} |
354 |
|
|
355 |
|
void Monomial::print() const { |
356 |
|
Debug("normal-form") << getNode() << std::endl; |
357 |
|
} |
358 |
|
|
359 |
|
void Monomial::printList(const std::vector<Monomial>& list) { |
360 |
|
for(vector<Monomial>::const_iterator i = list.begin(), end = list.end(); i != end; ++i) { |
361 |
|
const Monomial& m =*i; |
362 |
|
m.print(); |
363 |
|
} |
364 |
|
} |
365 |
7124728 |
Polynomial Polynomial::operator+(const Polynomial& vl) const { |
366 |
|
|
367 |
14249456 |
std::vector<Monomial> sortedMonos; |
368 |
7124728 |
std::merge(begin(), end(), vl.begin(), vl.end(), std::back_inserter(sortedMonos)); |
369 |
|
|
370 |
7124728 |
Monomial::combineAdjacentMonomials(sortedMonos); |
371 |
|
//std::vector<Monomial> combined = Monomial::sumLikeTerms(sortedMonos); |
372 |
|
|
373 |
7124728 |
Polynomial result = mkPolynomial(sortedMonos); |
374 |
14249456 |
return result; |
375 |
|
} |
376 |
|
|
377 |
|
Polynomial Polynomial::exactDivide(const Integer& z) const { |
378 |
|
Assert(isIntegral()); |
379 |
|
if(z.isOne()){ |
380 |
|
return (*this); |
381 |
|
}else { |
382 |
|
Constant invz = Constant::mkConstant(Rational(1,z)); |
383 |
|
Polynomial prod = (*this) * Monomial::mkMonomial(invz); |
384 |
|
Assert(prod.isIntegral()); |
385 |
|
return prod; |
386 |
|
} |
387 |
|
} |
388 |
|
|
389 |
1462508 |
Polynomial Polynomial::sumPolynomials(const std::vector<Polynomial>& ps){ |
390 |
1462508 |
if(ps.empty()){ |
391 |
|
return mkZero(); |
392 |
1462508 |
}else if(ps.size() <= 4){ |
393 |
|
// if there are few enough polynomials just add them |
394 |
2906506 |
Polynomial p = ps[0]; |
395 |
1618272 |
for(size_t i = 1; i < ps.size(); ++i){ |
396 |
165019 |
p = p + ps[i]; |
397 |
|
} |
398 |
1453253 |
return p; |
399 |
|
}else{ |
400 |
|
// general case |
401 |
18510 |
std::map<Node, Rational> coeffs; |
402 |
75551 |
for(size_t i = 0, N = ps.size(); i<N; ++i){ |
403 |
66296 |
const Polynomial& p = ps[i]; |
404 |
238689 |
for(iterator pi = p.begin(), pend = p.end(); pi != pend; ++pi) { |
405 |
344786 |
Monomial m = *pi; |
406 |
172393 |
coeffs[m.getVarList().getNode()] += m.getConstant().getValue(); |
407 |
|
} |
408 |
|
} |
409 |
18510 |
std::vector<Monomial> monos; |
410 |
9255 |
std::map<Node, Rational>::const_iterator ci = coeffs.begin(), cend = coeffs.end(); |
411 |
149811 |
for(; ci != cend; ++ci){ |
412 |
70278 |
if(!(*ci).second.isZero()){ |
413 |
|
Constant c = Constant::mkConstant((*ci).second); |
414 |
|
Node n = (*ci).first; |
415 |
|
VarList vl = VarList::parseVarList(n); |
416 |
|
monos.push_back(Monomial::mkMonomial(c, vl)); |
417 |
|
} |
418 |
|
} |
419 |
9255 |
Monomial::sort(monos); |
420 |
9255 |
Monomial::combineAdjacentMonomials(monos); |
421 |
|
|
422 |
18510 |
Polynomial result = mkPolynomial(monos); |
423 |
9255 |
return result; |
424 |
|
} |
425 |
|
} |
426 |
|
|
427 |
2387525 |
Polynomial Polynomial::operator-(const Polynomial& vl) const { |
428 |
4775050 |
Constant negOne = Constant::mkConstant(Rational(-1)); |
429 |
|
|
430 |
4775050 |
return *this + (vl*negOne); |
431 |
|
} |
432 |
|
|
433 |
6902849 |
Polynomial Polynomial::operator*(const Rational& q) const{ |
434 |
6902849 |
if(q.isZero()){ |
435 |
|
return Polynomial::mkZero(); |
436 |
6902849 |
}else if(q.isOne()){ |
437 |
2404136 |
return *this; |
438 |
|
}else{ |
439 |
8997426 |
std::vector<Monomial> newMonos; |
440 |
10973173 |
for(iterator i = this->begin(), end = this->end(); i != end; ++i) { |
441 |
6474460 |
newMonos.push_back((*i)*q); |
442 |
|
} |
443 |
|
|
444 |
4498713 |
Assert(Monomial::isStrictlySorted(newMonos)); |
445 |
4498713 |
return Polynomial::mkPolynomial(newMonos); |
446 |
|
} |
447 |
|
} |
448 |
|
|
449 |
3630712 |
Polynomial Polynomial::operator*(const Constant& c) const{ |
450 |
3630712 |
return (*this) * c.getValue(); |
451 |
|
// if(c.isZero()){ |
452 |
|
// return Polynomial::mkZero(); |
453 |
|
// }else if(c.isOne()){ |
454 |
|
// return *this; |
455 |
|
// }else{ |
456 |
|
// std::vector<Monomial> newMonos; |
457 |
|
// for(iterator i = this->begin(), end = this->end(); i != end; ++i) { |
458 |
|
// newMonos.push_back((*i)*c); |
459 |
|
// } |
460 |
|
|
461 |
|
// Assert(Monomial::isStrictlySorted(newMonos)); |
462 |
|
// return Polynomial::mkPolynomial(newMonos); |
463 |
|
// } |
464 |
|
} |
465 |
|
|
466 |
1061920 |
Polynomial Polynomial::operator*(const Monomial& mono) const { |
467 |
1061920 |
if(mono.isZero()) { |
468 |
211 |
return Polynomial(mono); //Don't multiply by zero |
469 |
|
} else { |
470 |
2123418 |
std::vector<Monomial> newMonos; |
471 |
2251543 |
for(iterator i = this->begin(), end = this->end(); i != end; ++i) { |
472 |
1189834 |
newMonos.push_back(mono * (*i)); |
473 |
|
} |
474 |
|
|
475 |
|
// We may need to sort newMonos. |
476 |
|
// Suppose this = (+ x y), mono = x, (* x y).getId() < (* x x).getId() |
477 |
|
// newMonos = <(* x x), (* x y)> after this loop. |
478 |
|
// This is not sorted according to the current VarList order. |
479 |
1061709 |
Monomial::sort(newMonos); |
480 |
1061709 |
return Polynomial::mkPolynomial(newMonos); |
481 |
|
} |
482 |
|
} |
483 |
|
|
484 |
1055195 |
Polynomial Polynomial::operator*(const Polynomial& poly) const { |
485 |
1055195 |
Polynomial res = Polynomial::mkZero(); |
486 |
2117115 |
for(iterator i = this->begin(), end = this->end(); i != end; ++i) { |
487 |
2123840 |
Monomial curr = *i; |
488 |
2123840 |
Polynomial prod = poly * curr; |
489 |
2123840 |
Polynomial sum = res + prod; |
490 |
1061920 |
res = sum; |
491 |
|
} |
492 |
1055195 |
return res; |
493 |
|
} |
494 |
|
|
495 |
3731379 |
Monomial Polynomial::selectAbsMinimum() const { |
496 |
7462758 |
iterator iter = begin(), myend = end(); |
497 |
3731379 |
Assert(iter != myend); |
498 |
|
|
499 |
3731379 |
Monomial min = *iter; |
500 |
3731379 |
++iter; |
501 |
6437895 |
for(; iter != end(); ++iter){ |
502 |
2706516 |
Monomial curr = *iter; |
503 |
1353258 |
if(curr.absCmp(min) < 0){ |
504 |
74359 |
min = curr; |
505 |
|
} |
506 |
|
} |
507 |
7462758 |
return min; |
508 |
|
} |
509 |
|
|
510 |
1942061 |
bool Polynomial::leadingCoefficientIsAbsOne() const { |
511 |
1942061 |
return getHead().absCoefficientIsOne(); |
512 |
|
} |
513 |
5751453 |
bool Polynomial::leadingCoefficientIsPositive() const { |
514 |
5751453 |
return getHead().getConstant().isPositive(); |
515 |
|
} |
516 |
|
|
517 |
3224042 |
bool Polynomial::denominatorLCMIsOne() const { |
518 |
3224042 |
return denominatorLCM().isOne(); |
519 |
|
} |
520 |
|
|
521 |
3224042 |
bool Polynomial::numeratorGCDIsOne() const { |
522 |
3224042 |
return gcd().isOne(); |
523 |
|
} |
524 |
|
|
525 |
3471304 |
Integer Polynomial::gcd() const { |
526 |
3471304 |
Assert(isIntegral()); |
527 |
3471304 |
return numeratorGCD(); |
528 |
|
} |
529 |
|
|
530 |
7515160 |
Integer Polynomial::numeratorGCD() const { |
531 |
|
//We'll use the standardization that gcd(0, 0) = 0 |
532 |
|
//So that the gcd of the zero polynomial is gcd{0} = 0 |
533 |
15030320 |
iterator i=begin(), e=end(); |
534 |
7515160 |
Assert(i != e); |
535 |
|
|
536 |
7515160 |
Integer d = (*i).getConstant().getValue().getNumerator().abs(); |
537 |
7515160 |
if(d.isOne()){ |
538 |
7228951 |
return d; |
539 |
|
} |
540 |
286209 |
++i; |
541 |
465563 |
for(; i!=e; ++i){ |
542 |
377089 |
Integer c = (*i).getConstant().getValue().getNumerator(); |
543 |
287412 |
d = d.gcd(c); |
544 |
287412 |
if(d.isOne()){ |
545 |
197735 |
return d; |
546 |
|
} |
547 |
|
} |
548 |
88474 |
return d; |
549 |
|
} |
550 |
|
|
551 |
7267898 |
Integer Polynomial::denominatorLCM() const { |
552 |
7267898 |
Integer tmp(1); |
553 |
17981065 |
for (iterator i = begin(), e = end(); i != e; ++i) { |
554 |
21426334 |
const Integer denominator = (*i).getConstant().getValue().getDenominator(); |
555 |
10713167 |
tmp = tmp.lcm(denominator); |
556 |
|
} |
557 |
7267898 |
return tmp; |
558 |
|
} |
559 |
|
|
560 |
4496488 |
Constant Polynomial::getCoefficient(const VarList& vl) const{ |
561 |
|
//TODO improve to binary search... |
562 |
11799748 |
for(iterator iter=begin(), myend=end(); iter != myend; ++iter){ |
563 |
14668375 |
Monomial m = *iter; |
564 |
14668375 |
VarList curr = m.getVarList(); |
565 |
7365115 |
if(curr == vl){ |
566 |
61855 |
return m.getConstant(); |
567 |
|
} |
568 |
|
} |
569 |
4434633 |
return Constant::mkConstant(0); |
570 |
|
} |
571 |
|
|
572 |
334 |
Node Polynomial::computeQR(const Polynomial& p, const Integer& div){ |
573 |
334 |
Assert(p.isIntegral()); |
574 |
668 |
std::vector<Monomial> q_vec, r_vec; |
575 |
668 |
Integer tmp_q, tmp_r; |
576 |
1138 |
for(iterator iter = p.begin(), pend = p.end(); iter != pend; ++iter){ |
577 |
1608 |
Monomial curr = *iter; |
578 |
1608 |
VarList vl = curr.getVarList(); |
579 |
1608 |
Constant c = curr.getConstant(); |
580 |
|
|
581 |
1608 |
const Integer& a = c.getValue().getNumerator(); |
582 |
804 |
Integer::floorQR(tmp_q, tmp_r, a, div); |
583 |
1608 |
Constant q=Constant::mkConstant(tmp_q); |
584 |
1608 |
Constant r=Constant::mkConstant(tmp_r); |
585 |
804 |
if(!q.isZero()){ |
586 |
804 |
q_vec.push_back(Monomial::mkMonomial(q, vl)); |
587 |
|
} |
588 |
804 |
if(!r.isZero()){ |
589 |
448 |
r_vec.push_back(Monomial::mkMonomial(r, vl)); |
590 |
|
} |
591 |
|
} |
592 |
|
|
593 |
668 |
Polynomial p_q = Polynomial::mkPolynomial(q_vec); |
594 |
668 |
Polynomial p_r = Polynomial::mkPolynomial(r_vec); |
595 |
|
|
596 |
668 |
return NodeManager::currentNM()->mkNode(kind::PLUS, p_q.getNode(), p_r.getNode()); |
597 |
|
} |
598 |
|
|
599 |
|
|
600 |
737926 |
Monomial Polynomial::minimumVariableMonomial() const{ |
601 |
737926 |
Assert(!isConstant()); |
602 |
737926 |
if(singleton()){ |
603 |
455802 |
return getHead(); |
604 |
|
}else{ |
605 |
564248 |
iterator i = begin(); |
606 |
564248 |
Monomial first = *i; |
607 |
282124 |
if( first.isConstant() ){ |
608 |
197852 |
++i; |
609 |
197852 |
Assert(i != end()); |
610 |
197852 |
return *i; |
611 |
|
}else{ |
612 |
84272 |
return first; |
613 |
|
} |
614 |
|
} |
615 |
|
} |
616 |
|
|
617 |
1134778 |
bool Polynomial::variableMonomialAreStrictlyGreater(const Monomial& m) const{ |
618 |
1134778 |
if(isConstant()){ |
619 |
467710 |
return true; |
620 |
|
}else{ |
621 |
1334136 |
Monomial minimum = minimumVariableMonomial(); |
622 |
667068 |
Debug("nf::tmp") << "minimum " << minimum.getNode() << endl; |
623 |
667068 |
Debug("nf::tmp") << "m " << m.getNode() << endl; |
624 |
667068 |
return m < minimum; |
625 |
|
} |
626 |
|
} |
627 |
|
|
628 |
56211353 |
bool Polynomial::isMember(TNode n) { |
629 |
56211353 |
if(Monomial::isMember(n)){ |
630 |
39976018 |
return true; |
631 |
16235335 |
}else if(n.getKind() == kind::PLUS){ |
632 |
16235335 |
Assert(n.getNumChildren() >= 2); |
633 |
16235335 |
Node::iterator currIter = n.begin(), end = n.end(); |
634 |
32470670 |
Node prev = *currIter; |
635 |
16235335 |
if(!Monomial::isMember(prev)){ |
636 |
|
return false; |
637 |
|
} |
638 |
|
|
639 |
32470670 |
Monomial mprev = Monomial::parseMonomial(prev); |
640 |
16235335 |
++currIter; |
641 |
63296687 |
for(; currIter != end; ++currIter){ |
642 |
47061352 |
Node curr = *currIter; |
643 |
23530676 |
if(!Monomial::isMember(curr)){ |
644 |
|
return false; |
645 |
|
} |
646 |
47061352 |
Monomial mcurr = Monomial::parseMonomial(curr); |
647 |
23530676 |
if(!(mprev < mcurr)){ |
648 |
|
return false; |
649 |
|
} |
650 |
23530676 |
mprev = mcurr; |
651 |
|
} |
652 |
16235335 |
return true; |
653 |
|
} else { |
654 |
|
return false; |
655 |
|
} |
656 |
|
} |
657 |
|
|
658 |
334 |
Node SumPair::computeQR(const SumPair& sp, const Integer& div){ |
659 |
334 |
Assert(sp.isIntegral()); |
660 |
|
|
661 |
668 |
const Integer& constant = sp.getConstant().getValue().getNumerator(); |
662 |
|
|
663 |
668 |
Integer constant_q, constant_r; |
664 |
334 |
Integer::floorQR(constant_q, constant_r, constant, div); |
665 |
|
|
666 |
668 |
Node p_qr = Polynomial::computeQR(sp.getPolynomial(), div); |
667 |
334 |
Assert(p_qr.getKind() == kind::PLUS); |
668 |
334 |
Assert(p_qr.getNumChildren() == 2); |
669 |
|
|
670 |
668 |
Polynomial p_q = Polynomial::parsePolynomial(p_qr[0]); |
671 |
668 |
Polynomial p_r = Polynomial::parsePolynomial(p_qr[1]); |
672 |
|
|
673 |
668 |
SumPair sp_q(p_q, Constant::mkConstant(constant_q)); |
674 |
668 |
SumPair sp_r(p_r, Constant::mkConstant(constant_r)); |
675 |
|
|
676 |
668 |
return NodeManager::currentNM()->mkNode(kind::PLUS, sp_q.getNode(), sp_r.getNode()); |
677 |
|
} |
678 |
|
|
679 |
1361420 |
SumPair SumPair::mkSumPair(const Polynomial& p){ |
680 |
1361420 |
if(p.isConstant()){ |
681 |
|
Constant leadingConstant = p.getHead().getConstant(); |
682 |
|
return SumPair(Polynomial::mkZero(), leadingConstant); |
683 |
1361420 |
}else if(p.containsConstant()){ |
684 |
834779 |
Assert(!p.singleton()); |
685 |
834779 |
return SumPair(p.getTail(), p.getHead().getConstant()); |
686 |
|
}else{ |
687 |
526641 |
return SumPair(p, Constant::mkZero()); |
688 |
|
} |
689 |
|
} |
690 |
|
|
691 |
4260176 |
Comparison::Comparison(TNode n) : NodeWrapper(n) { Assert(isNormalForm()); } |
692 |
|
|
693 |
38998 |
SumPair Comparison::toSumPair() const { |
694 |
38998 |
Kind cmpKind = comparisonKind(); |
695 |
38998 |
switch(cmpKind){ |
696 |
|
case kind::LT: |
697 |
|
case kind::LEQ: |
698 |
|
case kind::GT: |
699 |
|
case kind::GEQ: |
700 |
|
{ |
701 |
|
TNode lit = getNode(); |
702 |
|
TNode atom = (cmpKind == kind::LT || cmpKind == kind::LEQ) ? lit[0] : lit; |
703 |
|
Polynomial p = Polynomial::parsePolynomial(atom[0]); |
704 |
|
Constant c = Constant::mkConstant(atom[1]); |
705 |
|
if(p.leadingCoefficientIsPositive()){ |
706 |
|
return SumPair(p, -c); |
707 |
|
}else{ |
708 |
|
return SumPair(-p, c); |
709 |
|
} |
710 |
|
} |
711 |
38998 |
case kind::EQUAL: |
712 |
|
case kind::DISTINCT: |
713 |
|
{ |
714 |
77996 |
Polynomial left = getLeft(); |
715 |
77996 |
Polynomial right = getRight(); |
716 |
38998 |
Debug("nf::tmp") << "left: " << left.getNode() << endl; |
717 |
38998 |
Debug("nf::tmp") << "right: " << right.getNode() << endl; |
718 |
38998 |
if(right.isConstant()){ |
719 |
14506 |
return SumPair(left, -right.getHead().getConstant()); |
720 |
24492 |
}else if(right.containsConstant()){ |
721 |
10656 |
Assert(!right.singleton()); |
722 |
|
|
723 |
21312 |
Polynomial noConstant = right.getTail(); |
724 |
10656 |
return SumPair(left - noConstant, -right.getHead().getConstant()); |
725 |
|
}else{ |
726 |
13836 |
return SumPair(left - right, Constant::mkZero()); |
727 |
|
} |
728 |
|
} |
729 |
|
default: Unhandled() << cmpKind; |
730 |
|
} |
731 |
|
} |
732 |
|
|
733 |
970497 |
Polynomial Comparison::normalizedVariablePart() const { |
734 |
970497 |
Kind cmpKind = comparisonKind(); |
735 |
970497 |
switch(cmpKind){ |
736 |
548305 |
case kind::LT: |
737 |
|
case kind::LEQ: |
738 |
|
case kind::GT: |
739 |
|
case kind::GEQ: |
740 |
|
{ |
741 |
1096610 |
TNode lit = getNode(); |
742 |
1096610 |
TNode atom = (cmpKind == kind::LT || cmpKind == kind::LEQ) ? lit[0] : lit; |
743 |
1096610 |
Polynomial p = Polynomial::parsePolynomial(atom[0]); |
744 |
548305 |
if(p.leadingCoefficientIsPositive()){ |
745 |
448308 |
return p; |
746 |
|
}else{ |
747 |
99997 |
return -p; |
748 |
|
} |
749 |
|
} |
750 |
422192 |
case kind::EQUAL: |
751 |
|
case kind::DISTINCT: |
752 |
|
{ |
753 |
844384 |
Polynomial left = getLeft(); |
754 |
844384 |
Polynomial right = getRight(); |
755 |
422192 |
if(right.isConstant()){ |
756 |
192176 |
return left; |
757 |
|
}else{ |
758 |
460032 |
Polynomial noConstant = right.containsConstant() ? right.getTail() : right; |
759 |
460032 |
Polynomial diff = left - noConstant; |
760 |
230016 |
if(diff.leadingCoefficientIsPositive()){ |
761 |
227304 |
return diff; |
762 |
|
}else{ |
763 |
2712 |
return -diff; |
764 |
|
} |
765 |
|
} |
766 |
|
} |
767 |
|
default: Unhandled() << cmpKind; |
768 |
|
} |
769 |
|
} |
770 |
|
|
771 |
969086 |
DeltaRational Comparison::normalizedDeltaRational() const { |
772 |
969086 |
Kind cmpKind = comparisonKind(); |
773 |
969086 |
int delta = deltaCoeff(cmpKind); |
774 |
969086 |
switch(cmpKind){ |
775 |
547098 |
case kind::LT: |
776 |
|
case kind::LEQ: |
777 |
|
case kind::GT: |
778 |
|
case kind::GEQ: |
779 |
|
{ |
780 |
1094196 |
Node lit = getNode(); |
781 |
1094196 |
Node atom = (cmpKind == kind::LT || cmpKind == kind::LEQ) ? lit[0] : lit; |
782 |
1094196 |
Polynomial left = Polynomial::parsePolynomial(atom[0]); |
783 |
547098 |
const Rational& q = atom[1].getConst<Rational>(); |
784 |
547098 |
if(left.leadingCoefficientIsPositive()){ |
785 |
447314 |
return DeltaRational(q, delta); |
786 |
|
}else{ |
787 |
99784 |
return DeltaRational(-q, -delta); |
788 |
|
} |
789 |
|
} |
790 |
421988 |
case kind::EQUAL: |
791 |
|
case kind::DISTINCT: |
792 |
|
{ |
793 |
843976 |
Polynomial right = getRight(); |
794 |
843976 |
Monomial firstRight = right.getHead(); |
795 |
421988 |
if(firstRight.isConstant()){ |
796 |
465112 |
DeltaRational c = DeltaRational(firstRight.getConstant().getValue(), 0); |
797 |
465112 |
Polynomial left = getLeft(); |
798 |
232556 |
if(!left.allIntegralVariables()){ |
799 |
22368 |
return c; |
800 |
|
//this is a qpolynomial and the sign of the leading |
801 |
|
//coefficient will not change after the diff below |
802 |
|
} else{ |
803 |
|
// the polynomial may be a z polynomial in which case |
804 |
|
// taking the diff is the simplest and obviously correct means |
805 |
420376 |
Polynomial diff = right.singleton() ? left : left - right.getTail(); |
806 |
210188 |
if(diff.leadingCoefficientIsPositive()){ |
807 |
209716 |
return c; |
808 |
|
}else{ |
809 |
472 |
return -c; |
810 |
|
} |
811 |
|
} |
812 |
|
}else{ // The constant is 0 sign cannot change |
813 |
189432 |
return DeltaRational(0, 0); |
814 |
|
} |
815 |
|
} |
816 |
|
default: Unhandled() << cmpKind; |
817 |
|
} |
818 |
|
} |
819 |
|
|
820 |
316986 |
std::tuple<Polynomial, Kind, Constant> Comparison::decompose( |
821 |
|
bool split_constant) const |
822 |
|
{ |
823 |
316986 |
Kind rel = getNode().getKind(); |
824 |
316986 |
if (rel == Kind::NOT) |
825 |
|
{ |
826 |
147783 |
switch (getNode()[0].getKind()) |
827 |
|
{ |
828 |
|
case kind::LEQ: rel = Kind::GT; break; |
829 |
|
case kind::LT: rel = Kind::GEQ; break; |
830 |
48471 |
case kind::EQUAL: rel = Kind::DISTINCT; break; |
831 |
|
case kind::DISTINCT: rel = Kind::EQUAL; break; |
832 |
99312 |
case kind::GEQ: rel = Kind::LT; break; |
833 |
|
case kind::GT: rel = Kind::LEQ; break; |
834 |
|
default: |
835 |
|
Assert(false) << "Unsupported relation: " << getNode()[0].getKind(); |
836 |
|
} |
837 |
|
} |
838 |
|
|
839 |
633972 |
Polynomial poly = getLeft() - getRight(); |
840 |
|
|
841 |
316986 |
if (!split_constant) |
842 |
|
{ |
843 |
|
return std::tuple<Polynomial, Kind, Constant>{ |
844 |
80 |
poly, rel, Constant::mkZero()}; |
845 |
|
} |
846 |
|
|
847 |
633812 |
Constant right = Constant::mkZero(); |
848 |
316906 |
if (poly.containsConstant()) |
849 |
|
{ |
850 |
132201 |
right = -poly.getHead().getConstant(); |
851 |
132201 |
poly = poly + Polynomial::mkPolynomial(right); |
852 |
|
} |
853 |
|
|
854 |
633812 |
Constant lcoeff = poly.getHead().getConstant(); |
855 |
316906 |
if (!lcoeff.isOne()) |
856 |
|
{ |
857 |
92258 |
Constant invlcoeff = lcoeff.inverse(); |
858 |
46129 |
if (lcoeff.isNegative()) |
859 |
|
{ |
860 |
39772 |
switch (rel) |
861 |
|
{ |
862 |
|
case kind::LEQ: rel = Kind::GEQ; break; |
863 |
20850 |
case kind::LT: rel = Kind::GT; break; |
864 |
486 |
case kind::EQUAL: break; |
865 |
376 |
case kind::DISTINCT: break; |
866 |
18060 |
case kind::GEQ: rel = Kind::LEQ; break; |
867 |
|
case kind::GT: rel = Kind::LT; break; |
868 |
|
default: Assert(false) << "Unsupported relation: " << rel; |
869 |
|
} |
870 |
|
} |
871 |
46129 |
poly = poly * invlcoeff; |
872 |
46129 |
right = right * invlcoeff; |
873 |
|
} |
874 |
|
|
875 |
316906 |
return std::tuple<Polynomial, Kind, Constant>{poly, rel, right}; |
876 |
|
} |
877 |
|
|
878 |
2259204 |
Comparison Comparison::parseNormalForm(TNode n) { |
879 |
2259204 |
Debug("polynomial") << "Comparison::parseNormalForm(" << n << ")"; |
880 |
2259204 |
Comparison result(n); |
881 |
2259204 |
Assert(result.isNormalForm()); |
882 |
2259204 |
return result; |
883 |
|
} |
884 |
|
|
885 |
696166 |
Node Comparison::toNode(Kind k, const Polynomial& l, const Constant& r) { |
886 |
696166 |
Assert(isRelationOperator(k)); |
887 |
696166 |
switch(k) { |
888 |
696166 |
case kind::GEQ: |
889 |
|
case kind::GT: |
890 |
1392332 |
return NodeManager::currentNM()->mkNode(k, l.getNode(), r.getNode()); |
891 |
|
default: Unhandled() << k; |
892 |
|
} |
893 |
|
} |
894 |
|
|
895 |
1304308 |
Node Comparison::toNode(Kind k, const Polynomial& l, const Polynomial& r) { |
896 |
1304308 |
Assert(isRelationOperator(k)); |
897 |
1304308 |
switch(k) { |
898 |
1304308 |
case kind::GEQ: |
899 |
|
case kind::EQUAL: |
900 |
|
case kind::GT: |
901 |
1304308 |
return NodeManager::currentNM()->mkNode(k, l.getNode(), r.getNode()); |
902 |
|
case kind::LEQ: |
903 |
|
return toNode(kind::GEQ, r, l).notNode(); |
904 |
|
case kind::LT: |
905 |
|
return toNode(kind::GT, r, l).notNode(); |
906 |
|
case kind::DISTINCT: |
907 |
|
return toNode(kind::EQUAL, r, l).notNode(); |
908 |
|
default: |
909 |
|
Unreachable(); |
910 |
|
} |
911 |
|
} |
912 |
|
|
913 |
8927050 |
bool Comparison::rightIsConstant() const { |
914 |
8927050 |
if(getNode().getKind() == kind::NOT){ |
915 |
1405156 |
return getNode()[0][1].getKind() == kind::CONST_RATIONAL; |
916 |
|
}else{ |
917 |
7521894 |
return getNode()[1].getKind() == kind::CONST_RATIONAL; |
918 |
|
} |
919 |
|
} |
920 |
|
|
921 |
|
size_t Comparison::getComplexity() const{ |
922 |
|
switch(comparisonKind()){ |
923 |
|
case kind::CONST_BOOLEAN: return 1; |
924 |
|
case kind::LT: |
925 |
|
case kind::LEQ: |
926 |
|
case kind::DISTINCT: |
927 |
|
case kind::EQUAL: |
928 |
|
case kind::GT: |
929 |
|
case kind::GEQ: |
930 |
|
return getLeft().getComplexity() + getRight().getComplexity(); |
931 |
|
default: Unhandled() << comparisonKind(); return -1; |
932 |
|
} |
933 |
|
} |
934 |
|
|
935 |
17433749 |
Polynomial Comparison::getLeft() const { |
936 |
34867498 |
TNode left; |
937 |
17433749 |
Kind k = comparisonKind(); |
938 |
17433749 |
switch(k){ |
939 |
3581375 |
case kind::LT: |
940 |
|
case kind::LEQ: |
941 |
|
case kind::DISTINCT: |
942 |
3581375 |
left = getNode()[0][0]; |
943 |
3581375 |
break; |
944 |
13852374 |
case kind::EQUAL: |
945 |
|
case kind::GT: |
946 |
|
case kind::GEQ: |
947 |
13852374 |
left = getNode()[0]; |
948 |
13852374 |
break; |
949 |
|
default: Unhandled() << k; |
950 |
|
} |
951 |
34867498 |
return Polynomial::parsePolynomial(left); |
952 |
|
} |
953 |
|
|
954 |
11616057 |
Polynomial Comparison::getRight() const { |
955 |
23232114 |
TNode right; |
956 |
11616057 |
Kind k = comparisonKind(); |
957 |
11616057 |
switch(k){ |
958 |
2030465 |
case kind::LT: |
959 |
|
case kind::LEQ: |
960 |
|
case kind::DISTINCT: |
961 |
2030465 |
right = getNode()[0][1]; |
962 |
2030465 |
break; |
963 |
9585592 |
case kind::EQUAL: |
964 |
|
case kind::GT: |
965 |
|
case kind::GEQ: |
966 |
9585592 |
right = getNode()[1]; |
967 |
9585592 |
break; |
968 |
|
default: Unhandled() << k; |
969 |
|
} |
970 |
23232114 |
return Polynomial::parsePolynomial(right); |
971 |
|
} |
972 |
|
|
973 |
|
// Polynomial Comparison::getLeft() const { |
974 |
|
// Node n = getNode(); |
975 |
|
// Node left = (n.getKind() == kind::NOT ? n[0]: n)[0]; |
976 |
|
// return Polynomial::parsePolynomial(left); |
977 |
|
// } |
978 |
|
|
979 |
|
// Polynomial Comparison::getRight() const { |
980 |
|
// Node n = getNode(); |
981 |
|
// Node right = (n.getKind() == kind::NOT ? n[0]: n)[1]; |
982 |
|
// return Polynomial::parsePolynomial(right); |
983 |
|
// } |
984 |
|
|
985 |
10916906 |
bool Comparison::isNormalForm() const { |
986 |
21833812 |
Node n = getNode(); |
987 |
10916906 |
Kind cmpKind = comparisonKind(n); |
988 |
10916906 |
Debug("nf::tmp") << "isNormalForm " << n << " " << cmpKind << endl; |
989 |
10916906 |
switch(cmpKind){ |
990 |
279635 |
case kind::CONST_BOOLEAN: |
991 |
279635 |
return true; |
992 |
|
case kind::GT: |
993 |
|
return isNormalGT(); |
994 |
3760947 |
case kind::GEQ: |
995 |
3760947 |
return isNormalGEQ(); |
996 |
4635798 |
case kind::EQUAL: |
997 |
4635798 |
return isNormalEquality(); |
998 |
1405156 |
case kind::LT: |
999 |
1405156 |
return isNormalLT(); |
1000 |
|
case kind::LEQ: |
1001 |
|
return isNormalLEQ(); |
1002 |
835370 |
case kind::DISTINCT: |
1003 |
835370 |
return isNormalDistinct(); |
1004 |
|
default: |
1005 |
|
return false; |
1006 |
|
} |
1007 |
|
} |
1008 |
|
|
1009 |
|
/** This must be (> qpolynomial constant) */ |
1010 |
|
bool Comparison::isNormalGT() const { |
1011 |
|
Node n = getNode(); |
1012 |
|
Assert(n.getKind() == kind::GT); |
1013 |
|
if(!rightIsConstant()){ |
1014 |
|
return false; |
1015 |
|
}else{ |
1016 |
|
Polynomial left = getLeft(); |
1017 |
|
if(left.containsConstant()){ |
1018 |
|
return false; |
1019 |
|
}else if(!left.leadingCoefficientIsAbsOne()){ |
1020 |
|
return false; |
1021 |
|
}else{ |
1022 |
|
return !left.isIntegral(); |
1023 |
|
} |
1024 |
|
} |
1025 |
|
} |
1026 |
|
|
1027 |
|
/** This must be (not (> qpolynomial constant)) */ |
1028 |
|
bool Comparison::isNormalLEQ() const { |
1029 |
|
Node n = getNode(); |
1030 |
|
Debug("nf::tmp") << "isNormalLEQ " << n << endl; |
1031 |
|
Assert(n.getKind() == kind::NOT); |
1032 |
|
Assert(n[0].getKind() == kind::GT); |
1033 |
|
if(!rightIsConstant()){ |
1034 |
|
return false; |
1035 |
|
}else{ |
1036 |
|
Polynomial left = getLeft(); |
1037 |
|
if(left.containsConstant()){ |
1038 |
|
return false; |
1039 |
|
}else if(!left.leadingCoefficientIsAbsOne()){ |
1040 |
|
return false; |
1041 |
|
}else{ |
1042 |
|
return !left.isIntegral(); |
1043 |
|
} |
1044 |
|
} |
1045 |
|
} |
1046 |
|
|
1047 |
|
|
1048 |
|
/** This must be (>= qpolynomial constant) or (>= zpolynomial constant) */ |
1049 |
3760947 |
bool Comparison::isNormalGEQ() const { |
1050 |
7521894 |
Node n = getNode(); |
1051 |
3760947 |
Assert(n.getKind() == kind::GEQ); |
1052 |
|
|
1053 |
3760947 |
Debug("nf::tmp") << "isNormalGEQ " << n << " " << rightIsConstant() << endl; |
1054 |
|
|
1055 |
3760947 |
if(!rightIsConstant()){ |
1056 |
|
return false; |
1057 |
|
}else{ |
1058 |
7521894 |
Polynomial left = getLeft(); |
1059 |
3760947 |
if(left.containsConstant()){ |
1060 |
|
return false; |
1061 |
|
}else{ |
1062 |
3760947 |
if(left.isIntegral()){ |
1063 |
2258624 |
return left.signNormalizedReducedSum(); |
1064 |
|
}else{ |
1065 |
1502323 |
return left.leadingCoefficientIsAbsOne(); |
1066 |
|
} |
1067 |
|
} |
1068 |
|
} |
1069 |
|
} |
1070 |
|
|
1071 |
|
/** This must be (not (>= qpolynomial constant)) or (not (>= zpolynomial constant)) */ |
1072 |
1405156 |
bool Comparison::isNormalLT() const { |
1073 |
2810312 |
Node n = getNode(); |
1074 |
1405156 |
Assert(n.getKind() == kind::NOT); |
1075 |
1405156 |
Assert(n[0].getKind() == kind::GEQ); |
1076 |
|
|
1077 |
1405156 |
if(!rightIsConstant()){ |
1078 |
|
return false; |
1079 |
|
}else{ |
1080 |
2810312 |
Polynomial left = getLeft(); |
1081 |
1405156 |
if(left.containsConstant()){ |
1082 |
|
return false; |
1083 |
|
}else{ |
1084 |
1405156 |
if(left.isIntegral()){ |
1085 |
965418 |
return left.signNormalizedReducedSum(); |
1086 |
|
}else{ |
1087 |
439738 |
return left.leadingCoefficientIsAbsOne(); |
1088 |
|
} |
1089 |
|
} |
1090 |
|
} |
1091 |
|
} |
1092 |
|
|
1093 |
|
|
1094 |
5471168 |
bool Comparison::isNormalEqualityOrDisequality() const { |
1095 |
10942336 |
Polynomial pleft = getLeft(); |
1096 |
|
|
1097 |
5471168 |
if(pleft.numMonomials() == 1){ |
1098 |
10942336 |
Monomial mleft = pleft.getHead(); |
1099 |
5471168 |
if(mleft.isConstant()){ |
1100 |
|
return false; |
1101 |
|
}else{ |
1102 |
10942336 |
Polynomial pright = getRight(); |
1103 |
5471168 |
if(allIntegralVariables()){ |
1104 |
4903779 |
const Rational& lcoeff = mleft.getConstant().getValue(); |
1105 |
4903779 |
if(pright.isConstant()){ |
1106 |
1960201 |
return pright.isIntegral() && lcoeff.isOne(); |
1107 |
|
} |
1108 |
5887156 |
Polynomial varRight = pright.containsConstant() ? pright.getTail() : pright; |
1109 |
2943578 |
if(lcoeff.sgn() <= 0){ |
1110 |
|
return false; |
1111 |
|
}else{ |
1112 |
5887156 |
Integer lcm = lcoeff.getDenominator().lcm(varRight.denominatorLCM()); |
1113 |
5887156 |
Integer g = lcoeff.getNumerator().gcd(varRight.numeratorGCD()); |
1114 |
2943578 |
Debug("nf::tmp") << lcm << " " << g << endl; |
1115 |
2943578 |
if(!lcm.isOne()){ |
1116 |
|
return false; |
1117 |
2943578 |
}else if(!g.isOne()){ |
1118 |
|
return false; |
1119 |
|
}else{ |
1120 |
5887156 |
Monomial absMinRight = varRight.selectAbsMinimum(); |
1121 |
2943578 |
Debug("nf::tmp") << mleft.getNode() << " " << absMinRight.getNode() << endl; |
1122 |
2943578 |
if( mleft.absCmp(absMinRight) < 0){ |
1123 |
77662 |
return true; |
1124 |
|
}else{ |
1125 |
2865916 |
return (!(absMinRight.absCmp(mleft)< 0)) && mleft < absMinRight; |
1126 |
|
} |
1127 |
|
} |
1128 |
|
} |
1129 |
|
}else{ |
1130 |
567389 |
if(mleft.coefficientIsOne()){ |
1131 |
1134778 |
Debug("nf::tmp") |
1132 |
567389 |
<< "dfklj " << mleft.getNode() << endl |
1133 |
567389 |
<< pright.getNode() << endl |
1134 |
1134778 |
<< pright.variableMonomialAreStrictlyGreater(mleft) |
1135 |
567389 |
<< endl; |
1136 |
567389 |
return pright.variableMonomialAreStrictlyGreater(mleft); |
1137 |
|
}else{ |
1138 |
|
return false; |
1139 |
|
} |
1140 |
|
} |
1141 |
|
} |
1142 |
|
}else{ |
1143 |
|
return false; |
1144 |
|
} |
1145 |
|
} |
1146 |
|
|
1147 |
|
/** This must be (= qvarlist qpolynomial) or (= zmonomial zpolynomial)*/ |
1148 |
4635798 |
bool Comparison::isNormalEquality() const { |
1149 |
4635798 |
Assert(getNode().getKind() == kind::EQUAL); |
1150 |
13907394 |
return Theory::theoryOf(getNode()[0].getType()) == THEORY_ARITH && |
1151 |
13907394 |
isNormalEqualityOrDisequality(); |
1152 |
|
} |
1153 |
|
|
1154 |
|
/** |
1155 |
|
* This must be (not (= qvarlist qpolynomial)) or |
1156 |
|
* (not (= zmonomial zpolynomial)). |
1157 |
|
*/ |
1158 |
835370 |
bool Comparison::isNormalDistinct() const { |
1159 |
835370 |
Assert(getNode().getKind() == kind::NOT); |
1160 |
835370 |
Assert(getNode()[0].getKind() == kind::EQUAL); |
1161 |
|
|
1162 |
2506110 |
return Theory::theoryOf(getNode()[0][0].getType()) == THEORY_ARITH && |
1163 |
2506110 |
isNormalEqualityOrDisequality(); |
1164 |
|
} |
1165 |
|
|
1166 |
70858 |
Node Comparison::mkRatEquality(const Polynomial& p){ |
1167 |
70858 |
Assert(!p.isConstant()); |
1168 |
70858 |
Assert(!p.allIntegralVariables()); |
1169 |
|
|
1170 |
141716 |
Monomial minimalVList = p.minimumVariableMonomial(); |
1171 |
141716 |
Constant coeffInv = -(minimalVList.getConstant().inverse()); |
1172 |
|
|
1173 |
141716 |
Polynomial newRight = (p - minimalVList) * coeffInv; |
1174 |
141716 |
Polynomial newLeft(Monomial::mkMonomial(minimalVList.getVarList())); |
1175 |
|
|
1176 |
141716 |
return toNode(kind::EQUAL, newLeft, newRight); |
1177 |
|
} |
1178 |
|
|
1179 |
261142 |
Node Comparison::mkRatInequality(Kind k, const Polynomial& p){ |
1180 |
261142 |
Assert(k == kind::GEQ || k == kind::GT); |
1181 |
261142 |
Assert(!p.isConstant()); |
1182 |
261142 |
Assert(!p.allIntegralVariables()); |
1183 |
|
|
1184 |
522284 |
SumPair sp = SumPair::mkSumPair(p); |
1185 |
522284 |
Polynomial left = sp.getPolynomial(); |
1186 |
522284 |
Constant right = - sp.getConstant(); |
1187 |
|
|
1188 |
522284 |
Monomial minimalVList = left.getHead(); |
1189 |
261142 |
Assert(!minimalVList.isConstant()); |
1190 |
|
|
1191 |
522284 |
Constant coeffInv = minimalVList.getConstant().inverse().abs(); |
1192 |
522284 |
Polynomial newLeft = left * coeffInv; |
1193 |
522284 |
Constant newRight = right * (coeffInv); |
1194 |
|
|
1195 |
522284 |
return toNode(k, newLeft, newRight); |
1196 |
|
} |
1197 |
|
|
1198 |
435024 |
Node Comparison::mkIntInequality(Kind k, const Polynomial& p){ |
1199 |
435024 |
Assert(kind::GT == k || kind::GEQ == k); |
1200 |
435024 |
Assert(!p.isConstant()); |
1201 |
435024 |
Assert(p.allIntegralVariables()); |
1202 |
|
|
1203 |
870048 |
SumPair sp = SumPair::mkSumPair(p); |
1204 |
870048 |
Polynomial left = sp.getPolynomial(); |
1205 |
870048 |
Rational right = - (sp.getConstant().getValue()); |
1206 |
|
|
1207 |
|
|
1208 |
870048 |
Monomial m = left.getHead(); |
1209 |
435024 |
Assert(!m.isConstant()); |
1210 |
|
|
1211 |
870048 |
Integer lcm = left.denominatorLCM(); |
1212 |
870048 |
Integer g = left.numeratorGCD(); |
1213 |
870048 |
Rational mult(lcm,g); |
1214 |
|
|
1215 |
870048 |
Polynomial newLeft = left * mult; |
1216 |
870048 |
Rational rightMult = right * mult; |
1217 |
|
|
1218 |
435024 |
bool negateResult = false; |
1219 |
435024 |
if(!newLeft.leadingCoefficientIsPositive()){ |
1220 |
|
// multiply by -1 |
1221 |
|
// a: left >= right or b: left > right |
1222 |
|
// becomes |
1223 |
|
// a: -left <= -right or b: -left < -right |
1224 |
|
// a: not (-left > -right) or b: (not -left >= -right) |
1225 |
83594 |
newLeft = -newLeft; |
1226 |
83594 |
rightMult = -rightMult; |
1227 |
83594 |
k = (kind::GT == k) ? kind::GEQ : kind::GT; |
1228 |
83594 |
negateResult = true; |
1229 |
|
// the later stages handle: |
1230 |
|
// a: not (-left >= -right + 1) or b: (not -left >= -right) |
1231 |
|
} |
1232 |
|
|
1233 |
870048 |
Node result = Node::null(); |
1234 |
435024 |
if(rightMult.isIntegral()){ |
1235 |
430871 |
if(k == kind::GT){ |
1236 |
|
// (> p z) |
1237 |
|
// (>= p (+ z 1)) |
1238 |
163116 |
Constant rightMultPlusOne = Constant::mkConstant(rightMult + 1); |
1239 |
81558 |
result = toNode(kind::GEQ, newLeft, rightMultPlusOne); |
1240 |
|
}else{ |
1241 |
698626 |
Constant newRight = Constant::mkConstant(rightMult); |
1242 |
349313 |
result = toNode(kind::GEQ, newLeft, newRight); |
1243 |
|
} |
1244 |
|
}else{ |
1245 |
|
//(>= l (/ n d)) |
1246 |
|
//(>= l (ceil (/ n d))) |
1247 |
|
//This also hold for GT as (ceil (/ n d)) > (/ n d) |
1248 |
8306 |
Integer ceilr = rightMult.ceiling(); |
1249 |
8306 |
Constant ceilRight = Constant::mkConstant(ceilr); |
1250 |
4153 |
result = toNode(kind::GEQ, newLeft, ceilRight); |
1251 |
|
} |
1252 |
435024 |
Assert(!result.isNull()); |
1253 |
435024 |
if(negateResult){ |
1254 |
83594 |
return result.notNode(); |
1255 |
|
}else{ |
1256 |
351430 |
return result; |
1257 |
|
} |
1258 |
|
} |
1259 |
|
|
1260 |
665254 |
Node Comparison::mkIntEquality(const Polynomial& p){ |
1261 |
665254 |
Assert(!p.isConstant()); |
1262 |
665254 |
Assert(p.allIntegralVariables()); |
1263 |
|
|
1264 |
1330508 |
SumPair sp = SumPair::mkSumPair(p); |
1265 |
1330508 |
Polynomial varPart = sp.getPolynomial(); |
1266 |
1330508 |
Constant constPart = sp.getConstant(); |
1267 |
|
|
1268 |
1330508 |
Integer lcm = varPart.denominatorLCM(); |
1269 |
1330508 |
Integer g = varPart.numeratorGCD(); |
1270 |
1330508 |
Constant mult = Constant::mkConstant(Rational(lcm,g)); |
1271 |
|
|
1272 |
1330508 |
Constant constMult = constPart * mult; |
1273 |
|
|
1274 |
665254 |
if(constMult.isIntegral()){ |
1275 |
1329512 |
Polynomial varPartMult = varPart * mult; |
1276 |
|
|
1277 |
1329512 |
Monomial m = varPartMult.selectAbsMinimum(); |
1278 |
664756 |
bool mIsPositive = m.getConstant().isPositive(); |
1279 |
|
|
1280 |
1329512 |
Polynomial noM = (varPartMult + (- m)) + Polynomial::mkPolynomial(constMult); |
1281 |
|
|
1282 |
|
// m + noM = 0 |
1283 |
1329512 |
Polynomial newRight = mIsPositive ? -noM : noM; |
1284 |
1329512 |
Polynomial newLeft = mIsPositive ? m : -m; |
1285 |
|
|
1286 |
664756 |
Assert(newRight.isIntegral()); |
1287 |
664756 |
return toNode(kind::EQUAL, newLeft, newRight); |
1288 |
|
}else{ |
1289 |
498 |
return mkBoolNode(false); |
1290 |
|
} |
1291 |
|
} |
1292 |
|
|
1293 |
2279113 |
Comparison Comparison::mkComparison(Kind k, const Polynomial& l, const Polynomial& r){ |
1294 |
|
|
1295 |
|
//Make this special case fast for sharing! |
1296 |
2279113 |
if((k == kind::EQUAL || k == kind::DISTINCT) && l.isVarList() && r.isVarList()){ |
1297 |
1138924 |
VarList vLeft = l.asVarList(); |
1298 |
1138924 |
VarList vRight = r.asVarList(); |
1299 |
|
|
1300 |
569462 |
if(vLeft == vRight){ |
1301 |
|
// return true for equalities and false for disequalities |
1302 |
768 |
return Comparison(k == kind::EQUAL); |
1303 |
|
}else{ |
1304 |
1137388 |
Node eqNode = vLeft < vRight ? toNode( kind::EQUAL, l, r) : toNode( kind::EQUAL, r, l); |
1305 |
1137388 |
Node forK = (k == kind::DISTINCT) ? eqNode.notNode() : eqNode; |
1306 |
568694 |
return Comparison(forK); |
1307 |
|
} |
1308 |
|
} |
1309 |
|
|
1310 |
|
//General case |
1311 |
3419302 |
Polynomial diff = l - r; |
1312 |
1709651 |
if(diff.isConstant()){ |
1313 |
277373 |
bool res = evaluateConstantPredicate(k, diff.asConstant(), Rational(0)); |
1314 |
277373 |
return Comparison(res); |
1315 |
|
}else{ |
1316 |
2864556 |
Node result = Node::null(); |
1317 |
1432278 |
bool isInteger = diff.allIntegralVariables(); |
1318 |
1432278 |
switch(k){ |
1319 |
736112 |
case kind::EQUAL: |
1320 |
736112 |
result = isInteger ? mkIntEquality(diff) : mkRatEquality(diff); |
1321 |
736112 |
break; |
1322 |
|
case kind::DISTINCT: |
1323 |
|
{ |
1324 |
|
Node eq = isInteger ? mkIntEquality(diff) : mkRatEquality(diff); |
1325 |
|
result = eq.notNode(); |
1326 |
|
} |
1327 |
|
break; |
1328 |
108684 |
case kind::LEQ: |
1329 |
|
case kind::LT: |
1330 |
|
{ |
1331 |
217368 |
Polynomial neg = - diff; |
1332 |
108684 |
Kind negKind = (k == kind::LEQ ? kind::GEQ : kind::GT); |
1333 |
108684 |
result = isInteger ? |
1334 |
108684 |
mkIntInequality(negKind, neg) : mkRatInequality(negKind, neg); |
1335 |
|
} |
1336 |
108684 |
break; |
1337 |
587482 |
case kind::GEQ: |
1338 |
|
case kind::GT: |
1339 |
587482 |
result = isInteger ? |
1340 |
|
mkIntInequality(k, diff) : mkRatInequality(k, diff); |
1341 |
587482 |
break; |
1342 |
|
default: Unhandled() << k; |
1343 |
|
} |
1344 |
1432278 |
Assert(!result.isNull()); |
1345 |
1432278 |
if(result.getKind() == kind::NOT && result[0].getKind() == kind::CONST_BOOLEAN){ |
1346 |
|
return Comparison(!(result[0].getConst<bool>())); |
1347 |
|
}else{ |
1348 |
2864556 |
Comparison cmp(result); |
1349 |
1432278 |
Assert(cmp.isNormalForm()); |
1350 |
1432278 |
return cmp; |
1351 |
|
} |
1352 |
|
} |
1353 |
|
} |
1354 |
|
|
1355 |
38998 |
bool Comparison::isBoolean() const { |
1356 |
38998 |
return getNode().getKind() == kind::CONST_BOOLEAN; |
1357 |
|
} |
1358 |
|
|
1359 |
|
|
1360 |
38998 |
bool Comparison::debugIsIntegral() const{ |
1361 |
38998 |
return getLeft().isIntegral() && getRight().isIntegral(); |
1362 |
|
} |
1363 |
|
|
1364 |
47919680 |
Kind Comparison::comparisonKind(TNode literal){ |
1365 |
47919680 |
switch(literal.getKind()){ |
1366 |
36713966 |
case kind::CONST_BOOLEAN: |
1367 |
|
case kind::GT: |
1368 |
|
case kind::GEQ: |
1369 |
|
case kind::EQUAL: |
1370 |
36713966 |
return literal.getKind(); |
1371 |
11205714 |
case kind::NOT: |
1372 |
|
{ |
1373 |
22411428 |
TNode negatedAtom = literal[0]; |
1374 |
11205714 |
switch(negatedAtom.getKind()){ |
1375 |
|
case kind::GT: //(not (GT x c)) <=> (LEQ x c) |
1376 |
|
return kind::LEQ; |
1377 |
5354567 |
case kind::GEQ: //(not (GEQ x c)) <=> (LT x c) |
1378 |
5354567 |
return kind::LT; |
1379 |
5851147 |
case kind::EQUAL: |
1380 |
5851147 |
return kind::DISTINCT; |
1381 |
|
default: |
1382 |
|
return kind::UNDEFINED_KIND; |
1383 |
|
} |
1384 |
|
} |
1385 |
|
default: |
1386 |
|
return kind::UNDEFINED_KIND; |
1387 |
|
} |
1388 |
|
} |
1389 |
|
|
1390 |
|
|
1391 |
|
Node Polynomial::makeAbsCondition(Variable v, Polynomial p){ |
1392 |
|
Polynomial zerop = Polynomial::mkZero(); |
1393 |
|
|
1394 |
|
Polynomial varp = Polynomial::mkPolynomial(v); |
1395 |
|
Comparison pLeq0 = Comparison::mkComparison(kind::LEQ, p, zerop); |
1396 |
|
Comparison negP = Comparison::mkComparison(kind::EQUAL, varp, -p); |
1397 |
|
Comparison posP = Comparison::mkComparison(kind::EQUAL, varp, p); |
1398 |
|
|
1399 |
|
Node absCnd = (pLeq0.getNode()).iteNode(negP.getNode(), posP.getNode()); |
1400 |
|
return absCnd; |
1401 |
|
} |
1402 |
|
|
1403 |
38998 |
bool Polynomial::isNonlinear() const { |
1404 |
|
|
1405 |
113109 |
for(iterator i=begin(), iend =end(); i != iend; ++i){ |
1406 |
150075 |
Monomial m = *i; |
1407 |
75964 |
if(m.isNonlinear()){ |
1408 |
1853 |
return true; |
1409 |
|
} |
1410 |
|
} |
1411 |
37145 |
return false; |
1412 |
|
} |
1413 |
|
|
1414 |
|
} //namespace arith |
1415 |
|
} //namespace theory |
1416 |
28191 |
} // namespace cvc5 |