1 /*****************************************************************************/
2 /*!
3 * \file arith_theorem_producer.cpp
4 *
5 * Author: Vijay Ganesh, Sergey Berezin
6 *
7 * Created: Dec 13 02:09:04 GMT 2002
8 *
9 * <hr>
10 *
11 * License to use, copy, modify, sell and/or distribute this software
12 * and its documentation for any purpose is hereby granted without
13 * royalty, subject to the terms and conditions defined in the \ref
14 * LICENSE file provided with this distribution.
15 *
16 * <hr>
17 *
18 */
19 /*****************************************************************************/
20 // CLASS: ArithProofRules
21 //
22 // AUTHOR: Sergey Berezin, 12/11/2002
23 // AUTHOR: Vijay Ganesh, 05/30/2003
24 //
25 // Description: TRUSTED implementation of arithmetic proof rules.
26 //
27 ///////////////////////////////////////////////////////////////////////////////
28
29 // This code is trusted
30 #define _CVC3_TRUSTED_
31
32 #include "arith_theorem_producer.h"
33 #include "theory_core.h"
34 #include "theory_arith_new.h"
35
36 using namespace std;
37 using namespace CVC3;
38
39 ////////////////////////////////////////////////////////////////////
40 // TheoryArith: trusted method for creating ArithTheoremProducer
41 ////////////////////////////////////////////////////////////////////
42
createProofRules()43 ArithProofRules* TheoryArithNew::createProofRules() {
44 return new ArithTheoremProducer(theoryCore()->getTM(), this);
45 }
46
47 ////////////////////////////////////////////////////////////////////
48 // Canonization rules
49 ////////////////////////////////////////////////////////////////////
50
51
52 #define CLASS_NAME "ArithTheoremProducer"
53
54 // Rule for variables: e == 1 * e
varToMult(const Expr & e)55 Theorem ArithTheoremProducer::varToMult(const Expr& e) {
56 Proof pf;
57 if(withProof()) pf = newPf("var_to_mult", e);
58 return newRWTheorem(e, (rat(1) * e), Assumptions::emptyAssump(), pf);
59 }
60
61 // Rule for unary minus: -e == (-1) * e
uMinusToMult(const Expr & e)62 Theorem ArithTheoremProducer::uMinusToMult(const Expr& e) {
63 // The proof object to use
64 Proof pf;
65
66 // If the proof is needed set it up
67 if(withProof()) pf = newPf("uminus_to_mult", e);
68
69 // Return the rewrite theorem explaining the rewrite
70 return newRWTheorem((-e), (rat(-1) * e), Assumptions::emptyAssump(), pf);
71 }
72
73
74 // ==> x - y = x + (-1) * y
minusToPlus(const Expr & x,const Expr & y)75 Theorem ArithTheoremProducer::minusToPlus(const Expr& x, const Expr& y) {
76 // The proof object to use
77 Proof pf;
78
79 // If proof is needed, set it up
80 if (withProof()) pf = newPf("minus_to_plus", x, y);
81
82 // Return a new rewrite theorem describing the change
83 return newRWTheorem((x-y), (x + (rat(-1) * y)), Assumptions::emptyAssump(), pf);
84 }
85
86
87 // Rule for unary minus: -e == e/(-1)
88 // This is to reduce the number of almost identical rules for uminus and div
canonUMinusToDivide(const Expr & e)89 Theorem ArithTheoremProducer::canonUMinusToDivide(const Expr& e) {
90 Proof pf;
91 if(withProof()) pf = newPf("canon_uminus", e);
92 return newRWTheorem((-e), (e / rat(-1)), Assumptions::emptyAssump(), pf);
93 }
94
95 // Rules for division by constant
96
97 // (c)/(d) ==> (c/d). When d==0, c/0 = 0 (our total extension).
canonDivideConst(const Expr & c,const Expr & d)98 Theorem ArithTheoremProducer::canonDivideConst(const Expr& c,
99 const Expr& d) {
100 // Make sure c and d are a const
101 if(CHECK_PROOFS) {
102 CHECK_SOUND(isRational(c),
103 CLASS_NAME "::canonDivideConst:\n c not a constant: "
104 + c.toString());
105 CHECK_SOUND(isRational(d),
106 CLASS_NAME "::canonDivideConst:\n d not a constant: "
107 + d.toString());
108 }
109 Proof pf;
110 if(withProof())
111 pf = newPf("canon_divide_const", c, d, d_hole);
112 const Rational& dr = d.getRational();
113 return newRWTheorem((c/d), (rat(dr==0? 0 : (c.getRational()/dr))), Assumptions::emptyAssump(), pf);
114 }
115
116 // (c * x)/d ==> (c/d) * x, takes (c*x) and d
canonDivideMult(const Expr & cx,const Expr & d)117 Theorem ArithTheoremProducer::canonDivideMult(const Expr& cx,
118 const Expr& d) {
119 // Check the format of c*x
120 if(CHECK_PROOFS) {
121 CHECK_SOUND(isMult(cx) && isRational(cx[0]),
122 CLASS_NAME "::canonDivideMult:\n "
123 "Not a (c * x) expression: "
124 + cx.toString());
125 CHECK_SOUND(isRational(d),
126 CLASS_NAME "::canonDivideMult:\n "
127 "d is not a constant: " + d.toString());
128 }
129 const Rational& dr = d.getRational();
130 Rational cdr(dr==0? 0 : (cx[0].getRational()/dr));
131 Expr cd(rat(cdr));
132 Proof pf;
133 if(withProof())
134 pf = newPf("canon_divide_mult", cx[0], cx[1], d);
135 // (c/d) may be == 1, so we also need to canonize 1*x to x
136 if(cdr == 1)
137 return newRWTheorem((cx/d), (cx[1]), Assumptions::emptyAssump(), pf);
138 else if(cdr == 0) // c/0 == 0 case
139 return newRWTheorem((cx/d), cd, Assumptions::emptyAssump(), pf);
140 else
141 return newRWTheorem((cx/d), (cd*cx[1]), Assumptions::emptyAssump(), pf);
142 }
143
144 // (+ t1 ... tn)/d ==> (+ (t1/d) ... (tn/d))
canonDividePlus(const Expr & sum,const Expr & d)145 Theorem ArithTheoremProducer::canonDividePlus(const Expr& sum, const Expr& d) {
146 if(CHECK_PROOFS) {
147 CHECK_SOUND(isPlus(sum) && sum.arity() >= 2 && isRational(sum[0]),
148 CLASS_NAME "::canonUMinusPlus:\n "
149 "Expr is not a canonical sum: "
150 + sum.toString());
151 CHECK_SOUND(isRational(d),
152 CLASS_NAME "::canonUMinusPlus:\n "
153 "d is not a const: " + d.toString());
154 }
155 // First, propagate '/d' down to the args
156 Proof pf;
157 if(withProof())
158 pf = newPf("canon_divide_plus", rat(sum.arity()),
159 sum.begin(), sum.end());
160 vector<Expr> newKids;
161 for(Expr::iterator i=sum.begin(), iend=sum.end(); i!=iend; ++i)
162 newKids.push_back((*i)/d);
163 // (+ t1 ... tn)/d == (+ (t1/d) ... (tn/d))
164 return newRWTheorem((sum/d), (plusExpr(newKids)), Assumptions::emptyAssump(), pf);
165 }
166
167 // x/(d) ==> (1/d) * x, unless d == 1
canonDivideVar(const Expr & e,const Expr & d)168 Theorem ArithTheoremProducer::canonDivideVar(const Expr& e, const Expr& d) {
169 if(CHECK_PROOFS) {
170 CHECK_SOUND(isRational(d),
171 CLASS_NAME "::canonDivideVar:\n "
172 "d is not a const: " + d.toString());
173 }
174 Proof pf;
175
176 if(withProof())
177 pf = newPf("canon_divide_var", e);
178
179 const Rational& dr = d.getRational();
180 if(dr == 1)
181 return newRWTheorem(e/d, e, Assumptions::emptyAssump(), pf);
182 if(dr == 0) // e/0 == 0 (total extension of division)
183 return newRWTheorem(e/d, d, Assumptions::emptyAssump(), pf);
184 else
185 return newRWTheorem(e/d, rat(1/dr) * e, Assumptions::emptyAssump(), pf);
186 }
187
188
189 // Multiplication
190 // (MULT expr1 expr2 expr3 ...)
191 // Each expr is in canonical form, i.e. it can be a
192 // 1) Rational constant
193 // 2) Arithmetic Leaf (var or term from another theory)
194 // 3) (POW rational leaf)
195 // where rational cannot be 0 or 1
196 // 4) (MULT rational mterm'_1 ...) where each mterm' is of type (2) or (3)
197 // If rational == 1 then there should be at least two mterms
198 // 5) (PLUS rational sterm_1 ...) where each sterm is of
199 // type (2) or (3) or (4)
200 // if rational == 0 then there should be at least two sterms
201
202
simplifiedMultExpr(std::vector<Expr> & mulKids)203 Expr ArithTheoremProducer::simplifiedMultExpr(std::vector<Expr> & mulKids) {
204
205 // Check that the number of kids is at least 1 and that the first one is rational
206 DebugAssert(mulKids.size() >= 1 && mulKids[0].isRational(), "");
207
208 // If the number of kids is only one, return the kid, no multiplication is necessary
209 if (mulKids.size() == 1) return mulKids[0];
210 // Otherwise return the multiplication of given expression
211 else return multExpr(mulKids);
212 }
213
canonMultConstMult(const Expr & c,const Expr & e)214 Expr ArithTheoremProducer::canonMultConstMult(const Expr & c, const Expr & e) {
215
216 // The constant must be a rational and e must be a multiplication
217 DebugAssert(c.isRational() && e.getKind() == MULT, "ArithTheoremProducer::canonMultConstMult: c must be a rational a e must be a MULT");
218
219 // Multiplication must include a rational multiplier
220 DebugAssert ((e.arity() > 1) && (e[0].isRational()), "arith_theorem_producer::canonMultConstMult: a canonized MULT expression must have \
221 arity greater than 1: and first child must be rational " + e.toString());
222
223 // The kids of the new multiplication
224 std::vector<Expr> mulKids;
225
226 // Create new multiplication expression, multiplying the constant with the given constant
227 Expr::iterator i = e.begin();
228 mulKids.push_back(rat(c.getRational() * (*i).getRational()));
229 // All the rest, just push them to the kids vector
230 for(i ++; i != e.end(); i ++)
231 mulKids.push_back(*i);
232
233 // Return the simplified multiplication expression
234 return simplifiedMultExpr(mulKids);
235 }
236
canonMultConstPlus(const Expr & e1,const Expr & e2)237 Expr ArithTheoremProducer::canonMultConstPlus(const Expr & e1, const Expr & e2) {
238
239 // e1 must be a rational and e2 must be a sum in canonic form
240 DebugAssert(e1.isRational() && e2.getKind() == PLUS && e2.arity() > 0, "");
241
242 // Vector to hold all the sum terms
243 std::vector<Theorem> thmPlusVector;
244
245 // Go through all the sum terms and multiply them with the constant
246 for(Expr::iterator i = e2.begin(); i != e2.end(); i++)
247 thmPlusVector.push_back(canonMultMtermMterm(e1*(*i)));
248
249 // Substitute the canonized terms into the sum
250 Theorem thmPlus1 = d_theoryArith->substitutivityRule(e2.getOp(), thmPlusVector);
251
252 // Return the resulting expression
253 return thmPlus1.getRHS();
254 }
255
canonMultPowPow(const Expr & e1,const Expr & e2)256 Expr ArithTheoremProducer::canonMultPowPow(const Expr & e1,
257 const Expr & e2)
258 {
259 DebugAssert(e1.getKind() == POW && e2.getKind() == POW, "");
260 // (POW r1 leaf1) * (POW r2 leaf2)
261 Expr leaf1 = e1[1];
262 Expr leaf2 = e2[1];
263 Expr can_expr;
264 if (leaf1 == leaf2) {
265 Rational rsum = e1[0].getRational() + e2[0].getRational();
266 if (rsum == 0) {
267 return rat(1);
268 }
269 else if (rsum == 1) {
270 return leaf1;
271 }
272 else
273 {
274 return powExpr(rat(rsum), leaf1);
275 }
276 }
277 else
278 {
279 std::vector<Expr> mulKids;
280 mulKids.push_back(rat(1));
281 // the leafs should be put in decreasing order
282 if (leaf1 < leaf2) {
283 mulKids.push_back(e2);
284 mulKids.push_back(e1);
285 }
286 else
287 {
288 mulKids.push_back(e1);
289 mulKids.push_back(e2);
290 }
291 // FIXME: don't really need to simplify, just wrap up a MULT?
292 return simplifiedMultExpr(mulKids);
293 }
294 }
295
canonMultPowLeaf(const Expr & e1,const Expr & e2)296 Expr ArithTheoremProducer::canonMultPowLeaf(const Expr & e1,
297 const Expr & e2)
298 {
299 DebugAssert(e1.getKind() == POW, "");
300 // (POW r1 leaf1) * leaf2
301 Expr leaf1 = e1[1];
302 Expr leaf2 = e2;
303 Expr can_expr;
304 if (leaf1 == leaf2) {
305 Rational rsum = e1[0].getRational() + 1;
306 if (rsum == 0) {
307 return rat(1);
308 }
309 else if (rsum == 1) {
310 return leaf1;
311 }
312 else
313 {
314 return powExpr(rat(rsum), leaf1);
315 }
316 }
317 else
318 {
319 std::vector<Expr> mulKids;
320 mulKids.push_back(rat(1));
321 // the leafs should be put in decreasing order
322 if (leaf1 < leaf2) {
323 mulKids.push_back(e2);
324 mulKids.push_back(e1);
325 }
326 else
327 {
328 mulKids.push_back(e1);
329 mulKids.push_back(e2);
330 }
331 return simplifiedMultExpr(mulKids);
332 }
333 }
334
canonMultLeafLeaf(const Expr & e1,const Expr & e2)335 Expr ArithTheoremProducer::canonMultLeafLeaf(const Expr & e1,
336 const Expr & e2)
337 {
338 // leaf1 * leaf2
339 Expr leaf1 = e1;
340 Expr leaf2 = e2;
341 Expr can_expr;
342 if (leaf1 == leaf2) {
343 return powExpr(rat(2), leaf1);
344 }
345 else
346 {
347 std::vector<Expr> mulKids;
348 mulKids.push_back(rat(1));
349 // the leafs should be put in decreasing order
350 if (leaf1 < leaf2) {
351 mulKids.push_back(e2);
352 mulKids.push_back(e1);
353 }
354 else
355 {
356 mulKids.push_back(e1);
357 mulKids.push_back(e2);
358 }
359 return simplifiedMultExpr(mulKids);
360 }
361 }
362
canonMultLeafOrPowMult(const Expr & e1,const Expr & e2)363 Expr ArithTheoremProducer::canonMultLeafOrPowMult(const Expr & e1,
364 const Expr & e2)
365 {
366 DebugAssert(e2.getKind() == MULT, "");
367 // Leaf * (MULT rat1 mterm1 ...)
368 // (POW r1 leaf1) * (MULT rat1 mterm1 ...) where
369 // each mterm is a leaf or (POW r leaf). Furthermore the leafs
370 // in the mterms are in descending order
371 Expr leaf1 = e1.getKind() == POW ? e1[1] : e1;
372 std::vector<Expr> mulKids;
373 DebugAssert(e2.arity() > 1, "MULT expr must have arity 2 or more");
374 Expr::iterator i = e2.begin();
375 // push the rational
376 mulKids.push_back(*i);
377 ++i;
378 // Now i points to the first mterm
379 for(; i != e2.end(); ++i) {
380 Expr leaf2 = ((*i).getKind() == POW) ? (*i)[1] : (*i);
381 if (leaf1 == leaf2) {
382 Rational r1 = e1.getKind() == POW ? e1[0].getRational() : 1;
383 Rational r2 =
384 ((*i).getKind() == POW ? (*i)[0].getRational() : 1);
385 // if r1 + r2 == 0 then it is the case of x^n * x^{-n}
386 // So, nothing needs to be added
387 if (r1 + r2 != 0) {
388 if (r1 + r2 == 1) {
389 mulKids.push_back(leaf1);
390 }
391 else
392 {
393 mulKids.push_back(powExpr(rat(r1 + r2), leaf1));
394 }
395 }
396 break;
397 }
398 // This ensures that the leaves in the mterms are also arranged
399 // in decreasing order
400 // Note that this will need to be changed if we want the order to
401 // be increasing order.
402 else if (leaf2 < leaf1) {
403 mulKids.push_back(e1);
404 mulKids.push_back(*i);
405 break;
406 }
407 else // leaf1 < leaf2
408 mulKids.push_back(*i);
409 }
410 if (i == e2.end()) {
411 mulKids.push_back(e1);
412 }
413 else
414 {
415 // e1 and *i have already been added
416 for (++i; i != e2.end(); ++i) {
417 mulKids.push_back(*i);
418 }
419 }
420 return simplifiedMultExpr(mulKids);
421 }
422
423 // Local class for ordering monomials; note, that it flips the
424 // ordering given by greaterthan(), to sort in ascending order.
425 class MonomialLess {
426 public:
operator ()(const Expr & e1,const Expr & e2) const427 bool operator()(const Expr& e1, const Expr& e2) const {
428 return ArithTheoremProducer::greaterthan(e1,e2);
429 }
430 };
431
432 typedef map<Expr,Rational,MonomialLess> MonomMap;
433
canonCombineLikeTerms(const std::vector<Expr> & sumExprs)434 Expr ArithTheoremProducer::canonCombineLikeTerms(const std::vector<Expr> & sumExprs) {
435
436 Rational constant = 0; // The constant at the begining of the sum
437 MonomMap sumHashMap; // The hash map of the summands, so that we can gather them and sum in the right order
438 vector<Expr> sumKids; // The kids of the sum
439
440 // Add each distinct mterm (not including the rational) into an appropriate hash map entry
441 std::vector<Expr>::const_iterator i = sumExprs.begin();
442 std::vector<Expr>::const_iterator i_end = sumExprs.end();
443 for (; i != i_end; i++) {
444 // Take the current expression (it must be a multiplication, a leaf or a rational number)
445 Expr mul = *i;
446
447 // If it's a rational, just add it to the constant factor c
448 if (mul.isRational())
449 constant = constant + mul.getRational();
450 else {
451 // Depending on the type of the expression decide what to do with this sum term
452 switch (mul.getKind()) {
453
454 // Multiplication is
455 case MULT: {
456
457 // The multiplication must be of arity > 1 and the first one must be rational
458 DebugAssert(mul.arity() > 1 && mul[0].isRational(),"If sum term is multiplication it must have the first term a rational, and at least another one");
459
460 // Get the rational constant of multiplication
461 Rational r = mul[0].getRational();
462
463 // Make a new multiplication term with a 1 instead of the rational r
464 vector<Expr> newKids;
465 // Copy the children to the newKids vector (including the rational)
466 for(Expr::iterator m = mul.begin(); m != mul.end(); m ++) newKids.push_back(*m);
467 // Change the rational to 1
468 newKids[0] = rat(1);
469 // Make the newMul expression
470 Expr newMul = multExpr(newKids);
471
472 // Find the term in the hashmap, so that we can add the coefficient (a*t + b*t = (a+b)*t)
473 MonomMap::iterator i = sumHashMap.find(newMul);
474
475 // If not found, just add the rational to the hash map
476 if (i == sumHashMap.end()) sumHashMap[newMul] = r;
477 // Otherwise, add it to the existing coefficient
478 else (*i).second += r;
479
480 // MULT case break
481 break;
482 }
483
484 default: {
485
486 // Find the term in the hashmap (add the 1*mul for being canonical)
487 MonomMap::iterator i = sumHashMap.find(multExpr(rat(1), mul));
488
489 // covers the case of POW, leaf
490 if (i == sumHashMap.end()) sumHashMap[multExpr(rat(1), mul)] = 1;
491 else (*i).second += 1;
492
493 // Default break
494 break;
495 }
496 }
497 }
498 }
499
500 // Now transfer to sumKids, first adding the rational constant if different from 0 (b + a_1*x_1 + a_2*x_2 + ... + a_n*x_n)
501 if (constant != 0) sumKids.push_back(rat(constant));
502
503 // After the constant, add all the other summands, in the right order (the hashmap order)
504 MonomMap::iterator j = sumHashMap.begin(), jend=sumHashMap.end();
505 for(; j != jend; j++) {
506 // If the corresponding coefficient is non-zero, add the term to the sum
507 if ((*j).second != 0) {
508 // Again, make a new multiplication term with a the coefficient instead of the rational one (1)
509 vector<Expr> newKids;
510 // Copy the children to the newKids vector (including the rational)
511 for(Expr::iterator m = (*j).first.begin(); m != (*j).first.end(); m ++) newKids.push_back(*m);
512 // Change the rational to the summed rationals for this term
513 newKids[0] = rat((*j).second);
514 // Make the newMul expression and add it to the sum
515 sumKids.push_back(multExpr(newKids));
516 }
517 }
518
519 // If the whole sum is only the constant, the whole sum is only the constant (TODO: CLEAN THIS UP, ITS HORRIBLE)
520 if (constant != 0 && sumKids.size() == 1) return sumKids[0];
521
522 // If the constant is 0 and there is only one more summand, return only the summand
523 if (constant == 0 && sumKids.size() == 1) return sumKids[0];
524
525 // If the constant is 0 and there are no summands, return 0
526 if (constant == 0 && sumKids.size() == 0) return rat(0);
527
528 // Otherwise return the sum of the sumkids
529 return plusExpr(sumKids);
530 }
531
canonMultLeafOrPowOrMultPlus(const Expr & e1,const Expr & e2)532 Expr ArithTheoremProducer::canonMultLeafOrPowOrMultPlus(const Expr & e1,
533 const Expr & e2)
534 {
535 DebugAssert(e2.getKind() == PLUS, "");
536 // Leaf * (PLUS rational sterm1 ...)
537 // or
538 // (POW n1 x1) * (PLUS rational sterm1 ...)
539 // or
540 // (MULT r1 m1 m2 ...) * (PLUS rational sterm1 ...)
541 // assume that e1 and e2 are themselves canonized
542 std::vector<Expr> sumExprs;
543 // Multiply each term in turn.
544 Expr::iterator i = e2.begin();
545 for (; i != e2.end(); ++i) {
546 sumExprs.push_back(canonMultMtermMterm(e1 * (*i)).getRHS());
547 }
548 return canonCombineLikeTerms(sumExprs);
549 }
550
canonMultPlusPlus(const Expr & e1,const Expr & e2)551 Expr ArithTheoremProducer::canonMultPlusPlus(const Expr & e1,
552 const Expr & e2)
553 {
554 DebugAssert(e1.getKind() == PLUS && e2.getKind() == PLUS, "");
555 // (PLUS r1 .... ) * (PLUS r1' ...)
556 // assume that e1 and e2 are themselves canonized
557
558 std::vector<Expr> sumExprs;
559 // Multiply each term in turn.
560 Expr::iterator i = e1.begin();
561 for (; i != e1.end(); ++i) {
562 Expr::iterator j = e2.begin();
563 for (; j != e2.end(); ++j) {
564 sumExprs.push_back(canonMultMtermMterm((*i) * (*j)).getRHS());
565 }
566 }
567 return canonCombineLikeTerms(sumExprs);
568 }
569
570
571
572 // The following produces a Theorem which is the result of multiplication
573 // of two canonized mterms. e = e1*e2
canonMultMtermMterm(const Expr & e)574 Theorem ArithTheoremProducer::canonMultMtermMterm(const Expr& e) {
575
576 // Check if the rule is sound
577 if(CHECK_PROOFS) {
578 CHECK_SOUND(isMult(e) && e.arity() == 2, "canonMultMtermMterm: e = " + e.toString());
579 }
580
581 // The proof we are using
582 Proof pf;
583
584 // The resulting expression
585 Expr rhs;
586
587 // Get the parts of the multiplication
588 const Expr& e1 = e[0];
589 const Expr& e2 = e[1];
590
591 // The name of the proof
592 string cmmm = "canon_mult_mterm_mterm";
593
594 if (e1.isRational()) {
595 // e1 is a Rational
596 const Rational& c = e1.getRational();
597 if (c == 0)
598 return canonMultZero(e2);
599 else if (c == 1)
600 return canonMultOne(e2);
601 else {
602 switch (e2.getKind()) {
603 case RATIONAL_EXPR :
604 // rat * rat
605 return canonMultConstConst(e1,e2);
606 break;
607 // TODO case of leaf
608 case POW:
609 // rat * (POW rat leaf)
610 // nothing to simplify
611 return d_theoryArith->reflexivityRule (e);
612
613 break;
614 case MULT:
615 rhs = canonMultConstMult(e1,e2);
616 if(withProof()) pf = newPf(cmmm,e,rhs);
617 return newRWTheorem(e, rhs, Assumptions::emptyAssump(), pf);
618 break;
619 case PLUS:
620 rhs = canonMultConstPlus(e1,e2);
621 if(withProof()) pf = newPf(cmmm,e,rhs);
622 return newRWTheorem(e, rhs, Assumptions::emptyAssump(), pf);
623 break;
624 default:
625 // TODO: I am going to assume that this is just a leaf
626 // i.e., a variable or term from another theory
627 return d_theoryArith->reflexivityRule(e);
628 break;
629 }
630 }
631 }
632 else if (e1.getKind() == POW) {
633 switch (e2.getKind()) {
634 case RATIONAL_EXPR:
635 // switch the order of the two arguments
636 return canonMultMtermMterm(e2 * e1);
637 break;
638 case POW:
639 rhs = canonMultPowPow(e1,e2);
640 if(withProof()) pf = newPf(cmmm,e,rhs);
641 return newRWTheorem(e,rhs, Assumptions::emptyAssump(), pf);
642 break;
643 case MULT:
644 rhs = canonMultLeafOrPowMult(e1,e2);
645 if(withProof()) pf = newPf(cmmm,e,rhs);
646 return newRWTheorem(e, rhs, Assumptions::emptyAssump(), pf);
647 break;
648 case PLUS:
649 rhs = canonMultLeafOrPowOrMultPlus(e1,e2);
650 if(withProof()) pf = newPf(cmmm,e,rhs);
651 return newRWTheorem(e, rhs, Assumptions::emptyAssump(), pf);
652 break;
653 default:
654 rhs = canonMultPowLeaf(e1,e2);
655 if(withProof()) pf = newPf(cmmm,e,rhs);
656 return newRWTheorem(e,rhs, Assumptions::emptyAssump(), pf);
657 break;
658 }
659 }
660 else if (e1.getKind() == MULT) {
661 switch (e2.getKind()) {
662 case RATIONAL_EXPR:
663 case POW:
664 // switch the order of the two arguments
665 return canonMultMtermMterm(e2 * e1);
666 break;
667 case MULT:
668 {
669 // (Mult r m1 m2 ...) (Mult r' m1' m2' ...)
670 Expr result = e2;
671 Expr::iterator i = e1.begin();
672 for (; i != e1.end(); ++i) {
673 result = canonMultMtermMterm((*i) * result).getRHS();
674 }
675 if(withProof()) pf = newPf(cmmm,e,result);
676 return newRWTheorem(e, result, Assumptions::emptyAssump(), pf);
677 }
678 break;
679 case PLUS:
680 rhs = canonMultLeafOrPowOrMultPlus(e1,e2);
681 if(withProof()) pf = newPf(cmmm,e,rhs);
682 return newRWTheorem(e,rhs, Assumptions::emptyAssump(), pf);
683 break;
684 default:
685 // leaf
686 // switch the order of the two arguments
687 return canonMultMtermMterm(e2 * e1);
688 break;
689 }
690 }
691 else if (e1.getKind() == PLUS) {
692 switch (e2.getKind()) {
693 case RATIONAL_EXPR:
694 case POW:
695 case MULT:
696 // switch the order of the two arguments
697 return canonMultMtermMterm(e2 * e1);
698 break;
699 case PLUS:
700 rhs = canonMultPlusPlus(e1,e2);
701 if(withProof()) pf = newPf(cmmm,e,rhs);
702 return newRWTheorem(e, rhs, Assumptions::emptyAssump(), pf);
703 break;
704 default:
705 // leaf
706 // switch the order of the two arguments
707 return canonMultMtermMterm(e2 * e1);
708 break;
709 }
710 }
711 else {
712 // leaf
713 switch (e2.getKind()) {
714 case RATIONAL_EXPR:
715 // switch the order of the two arguments
716 return canonMultMtermMterm(e2 * e1);
717 break;
718 case POW:
719 rhs = canonMultPowLeaf(e2,e1);
720 if(withProof()) pf = newPf(cmmm,e,rhs);
721 return newRWTheorem(e, rhs, Assumptions::emptyAssump(), pf);
722 break;
723 case MULT:
724 rhs = canonMultLeafOrPowMult(e1,e2);;
725 if(withProof()) pf = newPf(cmmm,e,rhs);
726 return newRWTheorem(e, rhs, Assumptions::emptyAssump(), pf);
727 break;
728 case PLUS:
729 rhs = canonMultLeafOrPowOrMultPlus(e1,e2);
730 if(withProof()) pf = newPf(cmmm,e,rhs);
731 return newRWTheorem(e, rhs, Assumptions::emptyAssump(), pf);
732 break;
733 default:
734 // leaf * leaf
735 rhs = canonMultLeafLeaf(e1,e2);
736 if(withProof()) pf = newPf(cmmm,e,rhs);
737 return newRWTheorem(e, rhs, Assumptions::emptyAssump(), pf);
738 break;
739 }
740 }
741 FatalAssert(false, "Unreachable");
742 return newRWTheorem(e, rhs, Assumptions::emptyAssump(), pf);
743 }
744
745 // (PLUS expr1 expr2 ...) where each expr is itself in canonic form
canonPlus(const Expr & e)746 Theorem ArithTheoremProducer::canonPlus(const Expr& e)
747 {
748 // Create the proof object in case we need it
749 Proof pf;
750
751 // The operation must be PLUS
752 DebugAssert(e.getKind() == PLUS, "");
753
754 // Add all the summands to the sumKids vector
755 std::vector<Expr> sumKids;
756 Expr::iterator i = e.begin();
757 for(; i != e.end(); ++i) {
758 if ((*i).getKind() != PLUS)
759 sumKids.push_back(*i);
760 else {
761 // If the kid is also a sum, add it to the sumKids vector (no need for recursion, kids are already canonized)
762 Expr::iterator j = (*i).begin();
763 for(; j != (*i).end(); ++j)
764 sumKids.push_back(*j);
765 }
766 }
767
768 // Combine all the kids to sum (gather the same variables and stuff)
769 Expr val = canonCombineLikeTerms(sumKids);
770
771 // If proofs needed set it up with starting expression and the value
772 if (withProof()) {
773 pf = newPf("canon_plus", e, val);
774 }
775
776 // Return the explaining rewrite theorem
777 return newRWTheorem(e, val, Assumptions::emptyAssump(), pf);
778 }
779
780 // (MULT expr1 expr2 ...) where each expr is itself in canonic form
canonMult(const Expr & e)781 Theorem ArithTheoremProducer::canonMult(const Expr& e)
782 {
783 // The proof we might need
784 Proof pf;
785
786 // Expression must be of kind MULT
787 DebugAssert(e.getKind() == MULT && e.arity() > 1, "");
788
789 // Get the first operand of the multiplication
790 Expr::iterator i = e.begin();
791
792 // Set the result to the first element
793 Expr result = *i;
794
795 // Skip to the next one
796 ++i;
797
798 // For all the other elements
799 for (; i != e.end(); ++i) {
800 // Multiply each element into the result
801 result = canonMultMtermMterm(result * (*i)).getRHS();
802 }
803
804 // If the proof is needed, create one
805 if (withProof()) {
806 pf = newPf("canon_mult", e,result);
807 }
808
809 // Return a new rewrite theorem with the result
810 return newRWTheorem(e, result, Assumptions::emptyAssump(), pf);
811 }
812
813
814 Theorem
canonInvertConst(const Expr & e)815 ArithTheoremProducer::canonInvertConst(const Expr& e)
816 {
817 if(CHECK_PROOFS)
818 CHECK_SOUND(isRational(e), "expecting a rational: e = "+e.toString());
819
820 Proof pf;
821
822 if (withProof()) {
823 pf = newPf("canon_invert_const", e);
824 }
825 const Rational& er = e.getRational();
826 return newRWTheorem((rat(1)/e), rat(er==0? 0 : (1/er)), Assumptions::emptyAssump(), pf);
827 }
828
829
830 Theorem
canonInvertLeaf(const Expr & e)831 ArithTheoremProducer::canonInvertLeaf(const Expr& e)
832 {
833 Proof pf;
834
835 if (withProof()) {
836 pf = newPf("canon_invert_leaf", e);
837 }
838 return newRWTheorem((rat(1)/e), powExpr(rat(-1), e), Assumptions::emptyAssump(), pf);
839 }
840
841
842 Theorem
canonInvertPow(const Expr & e)843 ArithTheoremProducer::canonInvertPow(const Expr& e)
844 {
845 DebugAssert(e.getKind() == POW, "expecting a rational"+e[0].toString());
846
847 Proof pf;
848
849 if (withProof()) {
850 pf = newPf("canon_invert_pow", e);
851 }
852 if (e[0].getRational() == -1)
853 return newRWTheorem((rat(1)/e), e[1], Assumptions::emptyAssump(), pf);
854 else
855 return newRWTheorem((rat(1)/e),
856 powExpr(rat(-e[0].getRational()), e),
857 Assumptions::emptyAssump(),
858 pf);
859 }
860
861 Theorem
canonInvertMult(const Expr & e)862 ArithTheoremProducer::canonInvertMult(const Expr& e)
863 {
864 DebugAssert(e.getKind() == MULT, "expecting a rational"+e[0].toString());
865
866 Proof pf;
867
868 if (withProof()) {
869 pf = newPf("canon_invert_mult", e);
870 }
871
872 DebugAssert(e.arity() > 1, "MULT should have arity > 1"+e.toString());
873 Expr result = canonInvert(e[0]).getRHS();
874 for (int i = 1; i < e.arity(); ++i) {
875 result =
876 canonMultMtermMterm(result * canonInvert(e[i]).getRHS()).getRHS();
877 }
878 return newRWTheorem((rat(1)/e), result, Assumptions::emptyAssump(), pf);
879 }
880
881
882 // Given an expression e in Canonic form generate 1/e in canonic form
883 // This function assumes that e is not a PLUS expression
884 Theorem
canonInvert(const Expr & e)885 ArithTheoremProducer::canonInvert(const Expr& e)
886 {
887 DebugAssert(e.getKind() != PLUS,
888 "Cannot do inverse on a PLUS"+e.toString());
889 switch (e.getKind()) {
890 case RATIONAL_EXPR:
891 return canonInvertConst(e);
892 break;
893 case POW:
894 return canonInvertPow(e);
895 break;
896 case MULT:
897 return canonInvertMult(e);
898 break;
899 default:
900 // leaf
901 return canonInvertLeaf(e);
902 break;
903 }
904 }
905
906
canonDivide(const Expr & e)907 Theorem ArithTheoremProducer::canonDivide(const Expr& e)
908 {
909 // The expression should be of type DIVIDE
910 DebugAssert(e.getKind() == DIVIDE, "Expecting Divide"+e.toString());
911
912 // The proof if we need one
913 Proof pf;
914
915 // If the proof is needed make it
916 if (withProof()) {
917 pf = newPf("canon_invert_divide", e);
918 }
919
920 // Rewrite e[0] / e[1] as e[0]*(e[1])^-1
921 Theorem thm = newRWTheorem(e, e[0]*(canonInvert(e[1]).getRHS()), Assumptions::emptyAssump(), pf);
922
923 // Return the proof with canonizing the above multiplication
924 return d_theoryArith->transitivityRule(thm, canonMult(thm.getRHS()));
925 }
926
927
928 // Rules for multiplication
929 // t*c ==> c*t, takes constant c and term t
930 Theorem
canonMultTermConst(const Expr & c,const Expr & t)931 ArithTheoremProducer::canonMultTermConst(const Expr& c, const Expr& t) {
932 Proof pf;
933 if(CHECK_PROOFS) {
934 CHECK_SOUND(isRational(c),
935 CLASS_NAME "::canonMultTermConst:\n "
936 "c is not a constant: " + c.toString());
937 }
938 if(withProof()) pf = newPf("canon_mult_term_const", c, t);
939 return newRWTheorem((t*c), (c*t), Assumptions::emptyAssump(), pf);
940 }
941
942 // Rules for multiplication
943 // t1*t2 ==> Error, takes t1 and t2 where both are non-constants
944 Theorem
canonMultTerm1Term2(const Expr & t1,const Expr & t2)945 ArithTheoremProducer::canonMultTerm1Term2(const Expr& t1, const Expr& t2) {
946 // Proof pf;
947 // if(withProof()) pf = newPf("canon_mult_term1_term2", t1, t2);
948 if(CHECK_PROOFS) {
949 CHECK_SOUND(false, "Fatal Error: We don't support multiplication"
950 "of two non constant terms at this time "
951 + t1.toString() + " and " + t2.toString());
952 }
953 return Theorem();
954 }
955
956 // Rules for multiplication
957 // 0*x = 0, takes x
canonMultZero(const Expr & e)958 Theorem ArithTheoremProducer::canonMultZero(const Expr& e) {
959 Proof pf;
960 if(withProof()) pf = newPf("canon_mult_zero", e);
961 return newRWTheorem((rat(0)*e), rat(0), Assumptions::emptyAssump(), pf);
962 }
963
964 // Rules for multiplication
965 // 1*x ==> x, takes x (if x is other than a leaf)
966 // otherwise 1*x ==> 1*x
canonMultOne(const Expr & e)967 Theorem ArithTheoremProducer::canonMultOne(const Expr& e) {
968
969 // Setup the proof object
970 Proof pf;
971 if(withProof()) pf = newPf("canon_mult_one", e);
972
973 // If it is a leaf multiply it by one
974 if (d_theoryArith->isLeaf(e)) return d_theoryArith->reflexivityRule (rat(1)*e);
975
976 // Otherwise, just return the expression itself
977 return newRWTheorem((rat(1)*e), e, Assumptions::emptyAssump(), pf);
978 }
979
980 // Rules for multiplication
981 // c1*c2 ==> c', takes constant c1*c2
982 Theorem
canonMultConstConst(const Expr & c1,const Expr & c2)983 ArithTheoremProducer::canonMultConstConst(const Expr& c1, const Expr& c2) {
984 Proof pf;
985 if(CHECK_PROOFS) {
986 CHECK_SOUND(isRational(c1),
987 CLASS_NAME "::canonMultConstConst:\n "
988 "c1 is not a constant: " + c1.toString());
989 CHECK_SOUND(isRational(c2),
990 CLASS_NAME "::canonMultConstConst:\n "
991 "c2 is not a constant: " + c2.toString());
992 }
993 if(withProof()) pf = newPf("canon_mult_const_const", c1, c2);
994 return
995 newRWTheorem((c1*c2), rat(c1.getRational()*c2.getRational()), Assumptions::emptyAssump(), pf);
996 }
997
998 // Rules for multiplication
999 // c1*(c2*t) ==> c'*t, takes c1 and c2 and t
1000 Theorem
canonMultConstTerm(const Expr & c1,const Expr & c2,const Expr & t)1001 ArithTheoremProducer::canonMultConstTerm(const Expr& c1,
1002 const Expr& c2,const Expr& t) {
1003 Proof pf;
1004 if(CHECK_PROOFS) {
1005 CHECK_SOUND(isRational(c1),
1006 CLASS_NAME "::canonMultConstTerm:\n "
1007 "c1 is not a constant: " + c1.toString());
1008 CHECK_SOUND(isRational(c2),
1009 CLASS_NAME "::canonMultConstTerm:\n "
1010 "c2 is not a constant: " + c2.toString());
1011 }
1012
1013 if(withProof()) pf = newPf("canon_mult_const_term", c1, c2, t);
1014 return
1015 newRWTheorem(c1*(c2*t), rat(c1.getRational()*c2.getRational())*t, Assumptions::emptyAssump(), pf);
1016 }
1017
1018 // Rules for multiplication
1019 // c1*(+ c2 v1 ...) ==> (+ c1c2 c1v1 ...), takes c1 and the sum
1020 Theorem
canonMultConstSum(const Expr & c1,const Expr & sum)1021 ArithTheoremProducer::canonMultConstSum(const Expr& c1, const Expr& sum) {
1022 Proof pf;
1023 std::vector<Expr> sumKids;
1024
1025 if(CHECK_PROOFS) {
1026 CHECK_SOUND(isRational(c1),
1027 CLASS_NAME "::canonMultConstTerm:\n "
1028 "c1 is not a constant: " + c1.toString());
1029 CHECK_SOUND(PLUS == sum.getKind(),
1030 CLASS_NAME "::canonMultConstTerm:\n "
1031 "the kind must be a PLUS: " + sum.toString());
1032 }
1033 Expr::iterator i = sum.begin();
1034 for(; i != sum.end(); ++i)
1035 sumKids.push_back(c1*(*i));
1036 Expr ret = plusExpr(sumKids);
1037 if(withProof()) pf = newPf("canon_mult_const_sum", c1, sum, ret);
1038 return newRWTheorem((c1*sum),ret , Assumptions::emptyAssump(), pf);
1039 }
1040
1041
1042 // c^n = c' (compute the constant power expression)
canonPowConst(const Expr & e)1043 Theorem ArithTheoremProducer::canonPowConst(const Expr& e) {
1044 if(CHECK_PROOFS) {
1045 CHECK_SOUND(e.getKind() == POW && e.arity() == 2
1046 && e[0].isRational() && e[1].isRational(),
1047 "ArithTheoremProducer::canonPowConst("+e.toString()+")");
1048 }
1049 const Rational& p = e[0].getRational();
1050 const Rational& base = e[1].getRational();
1051 if(CHECK_PROOFS) {
1052 CHECK_SOUND(p.isInteger(),
1053 "ArithTheoremProducer::canonPowConst("+e.toString()+")");
1054 }
1055 Expr res;
1056 if (base == 0 && p < 0) {
1057 res = rat(0);
1058 }
1059 else res = rat(pow(p, base));
1060 Proof pf;
1061 if(withProof())
1062 pf = newPf("canon_pow_const", e);
1063 return newRWTheorem(e, res, Assumptions::emptyAssump(), pf);
1064 }
1065
1066
1067 // Rules for addition
1068 // flattens the input. accepts a PLUS expr
1069 Theorem
canonFlattenSum(const Expr & e)1070 ArithTheoremProducer::canonFlattenSum(const Expr& e) {
1071 Proof pf;
1072 std::vector<Expr> sumKids;
1073 if(CHECK_PROOFS) {
1074 CHECK_SOUND(PLUS == e.getKind(),
1075 CLASS_NAME "::canonFlattenSum:\n"
1076 "input must be a PLUS:" + e.toString());
1077 }
1078
1079 Expr::iterator i = e.begin();
1080 for(; i != e.end(); ++i){
1081 if (PLUS != (*i).getKind())
1082 sumKids.push_back(*i);
1083 else {
1084 Expr::iterator j = (*i).begin();
1085 for(; j != (*i).end(); ++j)
1086 sumKids.push_back(*j);
1087 }
1088 }
1089 Expr ret = plusExpr(sumKids);
1090 if(withProof()) pf = newPf("canon_flatten_sum", e,ret);
1091 return newRWTheorem(e,ret, Assumptions::emptyAssump(), pf);
1092 }
1093
1094 // Rules for addition
1095 // combine like terms. accepts a flattened PLUS expr
1096 Theorem
canonComboLikeTerms(const Expr & e)1097 ArithTheoremProducer::canonComboLikeTerms(const Expr& e) {
1098 Proof pf;
1099 std::vector<Expr> sumKids;
1100 ExprMap<Rational> sumHashMap;
1101 Rational constant = 0;
1102
1103 if(CHECK_PROOFS) {
1104 Expr::iterator k = e.begin();
1105 for(; k != e.end(); ++k)
1106 CHECK_SOUND(!isPlus(*k),
1107 CLASS_NAME "::canonComboLikeTerms:\n"
1108 "input must be a flattened PLUS:" + k->toString());
1109 }
1110 Expr::iterator i = e.begin();
1111 for(; i != e.end(); ++i){
1112 if(i->isRational())
1113 constant = constant + i->getRational();
1114 else {
1115 if (!isMult(*i)) {
1116 if(0 == sumHashMap.count((*i)))
1117 sumHashMap[*i] = 1;
1118 else
1119 sumHashMap[*i] += 1;
1120 }
1121 else {
1122 if(0 == sumHashMap.count((*i)[1]))
1123 sumHashMap[(*i)[1]] = (*i)[0].getRational();
1124 else
1125 sumHashMap[(*i)[1]] = sumHashMap[(*i)[1]] + (*i)[0].getRational();
1126 }
1127 }
1128 }
1129
1130 sumKids.push_back(rat(constant));
1131 ExprMap<Rational>::iterator j = sumHashMap.begin();
1132 for(; j != sumHashMap.end(); ++j) {
1133 if(0 == (*j).second)
1134 ;//do nothing
1135 else if (1 == (*j).second)
1136 sumKids.push_back((*j).first);
1137 else
1138 sumKids.push_back(rat((*j).second) * (*j).first);
1139 }
1140
1141 //constant is same as sumKids[0].
1142 //corner cases: "0 + monomial" and "constant"(no monomials)
1143
1144 Expr ret;
1145 if(2 == sumKids.size() && 0 == constant) ret = sumKids[1];
1146 else if (1 == sumKids.size()) ret = sumKids[0];
1147 else ret = plusExpr(sumKids);
1148
1149 if(withProof()) pf = newPf("canon_combo_like_terms",e,ret);
1150 return newRWTheorem(e, ret, Assumptions::emptyAssump(), pf);
1151 }
1152
1153
1154 // 0 = (* e1 e2 ...) <=> 0 = e1 OR 0 = e2 OR ...
multEqZero(const Expr & expr)1155 Theorem ArithTheoremProducer::multEqZero(const Expr& expr)
1156 {
1157 if (CHECK_PROOFS) {
1158 CHECK_SOUND(expr.isEq() && expr[0].isRational() &&
1159 expr[0].getRational() == 0 &&
1160 isMult(expr[1]) && expr[1].arity() > 1,
1161 "multEqZero invariant violated"+expr.toString());
1162 }
1163 Proof pf;
1164 vector<Expr> kids;
1165 Expr::iterator i = expr[1].begin(), iend = expr[1].end();
1166 for (; i != iend; ++i) {
1167 kids.push_back(rat(0).eqExpr(*i));
1168 }
1169 if (withProof()) {
1170 pf = newPf("multEqZero", expr);
1171 }
1172 return newRWTheorem(expr, Expr(OR, kids), Assumptions::emptyAssump(), pf);
1173 }
1174
1175
1176 // 0 = (^ c x) <=> false if c <=0
1177 // <=> 0 = x if c > 0
powEqZero(const Expr & expr)1178 Theorem ArithTheoremProducer::powEqZero(const Expr& expr)
1179 {
1180 if (CHECK_PROOFS) {
1181 CHECK_SOUND(expr.isEq() && expr[0].isRational() &&
1182 expr[0].getRational() == 0 &&
1183 isPow(expr[1]) && expr[1].arity() == 2 &&
1184 expr[1][0].isRational(),
1185 "powEqZero invariant violated"+expr.toString());
1186 }
1187 Proof pf;
1188 if (withProof()) {
1189 pf = newPf("powEqZero", expr);
1190 }
1191 Rational r = expr[1][0].getRational();
1192 Expr res;
1193 if (r <= 0) {
1194 res = d_em->falseExpr();
1195 }
1196 else {
1197 res = rat(0).eqExpr(expr[1][1]);
1198 }
1199 return newRWTheorem(expr, res, Assumptions::emptyAssump(), pf);
1200 }
1201
1202
1203 // x^n = y^n <=> x = y (if n is odd)
1204 // x^n = y^n <=> x = y OR x = -y (if n is even)
elimPower(const Expr & expr)1205 Theorem ArithTheoremProducer::elimPower(const Expr& expr)
1206 {
1207 if (CHECK_PROOFS) {
1208 CHECK_SOUND(expr.isEq() && isPow(expr[0]) &&
1209 isPow(expr[1]) &&
1210 isIntegerConst(expr[0][0]) &&
1211 expr[0][0].getRational() > 0 &&
1212 expr[0][0] == expr[1][0],
1213 "elimPower invariant violated"+expr.toString());
1214 }
1215 Proof pf;
1216 if (withProof()) {
1217 pf = newPf("elimPower", expr);
1218 }
1219 Rational r = expr[0][0].getRational();
1220 Expr res = expr[0][1].eqExpr(expr[1][1]);
1221 if (r % 2 == 0) {
1222 res = res.orExpr(expr[0][1].eqExpr(-expr[1][1]));
1223 }
1224 return newRWTheorem(expr, res, Assumptions::emptyAssump(), pf);
1225 }
1226
1227
1228 // x^n = c <=> x = root (if n is odd and root^n = c)
1229 // x^n = c <=> x = root OR x = -root (if n is even and root^n = c)
elimPowerConst(const Expr & expr,const Rational & root)1230 Theorem ArithTheoremProducer::elimPowerConst(const Expr& expr, const Rational& root)
1231 {
1232 if (CHECK_PROOFS) {
1233 CHECK_SOUND(expr.isEq() && isPow(expr[0]) &&
1234 isIntegerConst(expr[0][0]) &&
1235 expr[0][0].getRational() > 0 &&
1236 expr[1].isRational() &&
1237 pow(expr[0][0].getRational(), root) == expr[1].getRational(),
1238 "elimPowerConst invariant violated"+expr.toString());
1239 }
1240 Proof pf;
1241 if (withProof()) {
1242 pf = newPf("elimPowerConst", expr, rat(root));
1243 }
1244 Rational r = expr[0][0].getRational();
1245 Expr res = expr[0][1].eqExpr(rat(root));
1246 if (r % 2 == 0) {
1247 res = res.orExpr(expr[0][1].eqExpr(rat(-root)));
1248 }
1249 return newRWTheorem(expr, res, Assumptions::emptyAssump(), pf);
1250 }
1251
1252
1253 // x^n = c <=> false (if n is even and c is negative)
evenPowerEqNegConst(const Expr & expr)1254 Theorem ArithTheoremProducer::evenPowerEqNegConst(const Expr& expr)
1255 {
1256 if (CHECK_PROOFS) {
1257 CHECK_SOUND(expr.isEq() && isPow(expr[0]) &&
1258 expr[1].isRational() &&
1259 isIntegerConst(expr[0][0]) &&
1260 expr[0][0].getRational() % 2 == 0 &&
1261 expr[1].getRational() < 0,
1262 "evenPowerEqNegConst invariant violated"+expr.toString());
1263 }
1264 Proof pf;
1265 if (withProof()) {
1266 pf = newPf("evenPowerEqNegConst", expr);
1267 }
1268 return newRWTheorem(expr, d_em->falseExpr(), Assumptions::emptyAssump(), pf);
1269 }
1270
1271
1272 // x^n = c <=> false (if x is an integer and c is not a perfect n power)
intEqIrrational(const Expr & expr,const Theorem & isIntx)1273 Theorem ArithTheoremProducer::intEqIrrational(const Expr& expr, const Theorem& isIntx)
1274 {
1275 if (CHECK_PROOFS) {
1276 CHECK_SOUND(expr.isEq() && isPow(expr[0]) &&
1277 expr[1].isRational() &&
1278 expr[1].getRational() != 0 &&
1279 isIntegerConst(expr[0][0]) &&
1280 expr[0][0].getRational() > 0 &&
1281 ratRoot(expr[1].getRational(), expr[0][0].getRational().getUnsigned()) == 0,
1282 "intEqIrrational invariant violated"+expr.toString());
1283 CHECK_SOUND(isIntPred(isIntx.getExpr()) && isIntx.getExpr()[0] == expr[0][1],
1284 "ArithTheoremProducerOld::intEqIrrational:\n "
1285 "wrong integrality constraint:\n expr = "
1286 +expr.toString()+"\n isIntx = "
1287 +isIntx.getExpr().toString());
1288 }
1289 const Assumptions& assump(isIntx.getAssumptionsRef());
1290 Proof pf;
1291 if (withProof()) {
1292 pf = newPf("int_eq_irr", expr, isIntx.getProof());
1293 }
1294 return newRWTheorem(expr, d_em->falseExpr(), assump, pf);
1295 }
1296
1297
1298 // e[0] kind e[1] <==> true when e[0] kind e[1],
1299 // false when e[0] !kind e[1], for constants only
constPredicate(const Expr & e)1300 Theorem ArithTheoremProducer::constPredicate(const Expr& e) {
1301 if(CHECK_PROOFS) {
1302 CHECK_SOUND(e.arity() == 2 && isRational(e[0]) && isRational(e[1]),
1303 CLASS_NAME "::constPredicate:\n "
1304 "non-const parameters: " + e.toString());
1305 }
1306 Proof pf;
1307 bool result(false);
1308 int kind = e.getKind();
1309 Rational r1 = e[0].getRational(), r2 = e[1].getRational();
1310 switch(kind) {
1311 case EQ:
1312 result = (r1 == r2)?true : false;
1313 break;
1314 case LT:
1315 result = (r1 < r2)?true : false;
1316 break;
1317 case LE:
1318 result = (r1 <= r2)?true : false;
1319 break;
1320 case GT:
1321 result = (r1 > r2)?true : false;
1322 break;
1323 case GE:
1324 result = (r1 >= r2)?true : false;
1325 break;
1326 default:
1327 if(CHECK_PROOFS) {
1328 CHECK_SOUND(false,
1329 "ArithTheoremProducer::constPredicate: wrong kind");
1330 }
1331 break;
1332 }
1333 Expr ret = (result) ? d_em->trueExpr() : d_em->falseExpr();
1334 if(withProof()) pf = newPf("const_predicate", e,ret);
1335 return newRWTheorem(e, ret, Assumptions::emptyAssump(), pf);
1336 }
1337
1338
1339 // e[0] kind e[1] <==> 0 kind e[1] - e[0]
rightMinusLeft(const Expr & e)1340 Theorem ArithTheoremProducer::rightMinusLeft(const Expr& e)
1341 {
1342 Proof pf;
1343 int kind = e.getKind();
1344 if(CHECK_PROOFS) {
1345 CHECK_SOUND((EQ==kind) ||
1346 (LT==kind) ||
1347 (LE==kind) ||
1348 (GE==kind) ||
1349 (GT==kind),
1350 "ArithTheoremProduder::rightMinusLeft: wrong kind");
1351 }
1352 if(withProof()) pf = newPf("right_minus_left",e);
1353 return newRWTheorem(e, Expr(e.getOp(), rat(0), e[1] - e[0]), Assumptions::emptyAssump(), pf);
1354 }
1355
1356 // e[0] kind e[1] <==> 0 kind e[1] - e[0]
leftMinusRight(const Expr & e)1357 Theorem ArithTheoremProducer::leftMinusRight(const Expr& e)
1358 {
1359 Proof pf;
1360 int kind = e.getKind();
1361 if(CHECK_PROOFS) {
1362 CHECK_SOUND((EQ==kind) ||
1363 (LT==kind) ||
1364 (LE==kind) ||
1365 (GE==kind) ||
1366 (GT==kind),
1367 "ArithTheoremProduder::rightMinusLeft: wrong kind");
1368 }
1369 if(withProof()) pf = newPf("left_minus_right",e);
1370 return newRWTheorem(e, Expr(e.getOp(), e[0] - e[1], rat(0)), Assumptions::emptyAssump(), pf);
1371 }
1372
1373
1374
1375 // x kind y <==> x + z kind y + z
plusPredicate(const Expr & x,const Expr & y,const Expr & z,int kind)1376 Theorem ArithTheoremProducer::plusPredicate(const Expr& x,
1377 const Expr& y,
1378 const Expr& z, int kind) {
1379 if(CHECK_PROOFS) {
1380 CHECK_SOUND((EQ==kind) ||
1381 (LT==kind) ||
1382 (LE==kind) ||
1383 (GE==kind) ||
1384 (GT==kind),
1385 "ArithTheoremProduder::plusPredicate: wrong kind");
1386 }
1387 Proof pf;
1388 Expr left = Expr(kind, x, y);
1389 Expr right = Expr(kind, x + z, y + z);
1390 if(withProof()) pf = newPf("plus_predicate",left,right);
1391 return newRWTheorem(left, right, Assumptions::emptyAssump(), pf);
1392 }
1393
1394 // x = y <==> x * z = y * z
multEqn(const Expr & x,const Expr & y,const Expr & z)1395 Theorem ArithTheoremProducer::multEqn(const Expr& x,
1396 const Expr& y,
1397 const Expr& z) {
1398 Proof pf;
1399 if(CHECK_PROOFS)
1400 CHECK_SOUND(z.isRational() && z.getRational() != 0,
1401 "ArithTheoremProducer::multEqn(): multiplying equation by 0");
1402 if(withProof()) pf = newPf("mult_eqn", x, y, z);
1403 return newRWTheorem(x.eqExpr(y), (x * z).eqExpr(y * z), Assumptions::emptyAssump(), pf);
1404 }
1405
1406
1407 // x = y <==> z=0 OR x * 1/z = y * 1/z
divideEqnNonConst(const Expr & x,const Expr & y,const Expr & z)1408 Theorem ArithTheoremProducer::divideEqnNonConst(const Expr& x,
1409 const Expr& y,
1410 const Expr& z) {
1411 Proof pf;
1412 if(withProof()) pf = newPf("mult_eqn_nonconst", x, y, z);
1413 return newRWTheorem(x.eqExpr(y), (z.eqExpr(rat(0))).orExpr((x / z).eqExpr(y / z)),
1414 Assumptions::emptyAssump(), pf);
1415 }
1416
1417
1418 // if z is +ve, return e[0] LT|LE|GT|GE e[1] <==> e[0]*z LT|LE|GT|GE e[1]*z
1419 // if z is -ve, return e[0] LT|LE|GT|GE e[1] <==> e[1]*z LT|LE|GT|GE e[0]*z
multIneqn(const Expr & e,const Expr & z)1420 Theorem ArithTheoremProducer::multIneqn(const Expr& e, const Expr& z) {
1421
1422 // Check the proofs in necessary
1423 if(CHECK_PROOFS) {
1424 CHECK_SOUND(isIneq(e), "ArithTheoremProduder::multIneqn: wrong kind");
1425 CHECK_SOUND(z.isRational() && z.getRational() != 0, "ArithTheoremProduder::multIneqn: z must be non-zero rational: " + z.toString());
1426 }
1427
1428 // Operation of the expression
1429 Op op(e.getOp());
1430
1431 // Calculate the returning expression
1432 Expr ret;
1433 // If constant is positive, just multiply both sides
1434 if(0 < z.getRational())
1435 ret = Expr(op, e[0]*z, e[1]*z);
1436 else
1437 // The constant is negative, reverse the relation
1438 switch (e.getKind()) {
1439 case LE: ret = geExpr(e[0]*z, e[1]*z); break;
1440 case LT: ret = gtExpr(e[0]*z, e[1]*z); break;
1441 case GE: ret = leExpr(e[0]*z, e[1]*z); break;
1442 case GT: ret = ltExpr(e[0]*z, e[1]*z); break;
1443 default:
1444 //TODO: exception, we shouldn't be here
1445 break;
1446 }
1447
1448 // If we need the proof, set it up
1449 Proof pf;
1450 if(withProof()) pf = newPf("mult_ineqn", e, ret);
1451
1452 // Return the explaining rewrite theorem
1453 return newRWTheorem(e, ret, Assumptions::emptyAssump(), pf);
1454 }
1455
1456 //// multiply a canonised expression e = e[0] @ 0 with a constant c
1457 //Theorem ArithTheoremProducer::multConst(const Expr& e, const Rational c)
1458 //{
1459 // // The proof object
1460 // Proof pf;
1461 //
1462 // // The resulting expression
1463 // Expr ret;
1464 //
1465 // // If expression is just a rational multiply it and thats it
1466 // if (e[0].isRational())
1467 // ret = rat(e[0].getRational() * c);
1468 // // The expression is a canonised sum, multiply each one
1469 // else {
1470 // // Vector to hold all the sum children
1471 // vector<Expr> sumKids;
1472 //
1473 // // Put all the sum children to the sumKids vector
1474 // for(Expression::iterator m = e[0].begin(); m != e[0].end(); m ++) {
1475 // // The current term in the sum
1476 // const Expr& sumTerm = (*m);
1477 //
1478 // // If the child is rational, just multiply it
1479 // if (sumTerm.isRational()) sumKids.push_back(rat(sumTerm.getRational() * c));
1480 // // Otherwise multiply the coefficient with c and add it to the sumKids (TODO: Is the multiplication binary???)
1481 // else sumKids.pushBack(multExpr(rat(c * sumTerm[0].getRational()), sumTerm[1]));
1482 // }
1483 //
1484 // // The resulting expression is the sum of the sumKids
1485 // ret = plusExpr(sumKids);
1486 // }
1487 //
1488 // // If proof is needed set it up
1489 // if(withProof()) pf = newPf("arith_mult_const", e, ret);
1490 //
1491 // // Return the theorem explaining the multiplication
1492 // return newRWTheorem(e, ret, Assumptions::emptyAssump(), pf);
1493 //}
1494
1495
1496
1497 // "op1 GE|GT op2" <==> op2 LE|LT op1
flipInequality(const Expr & e)1498 Theorem ArithTheoremProducer::flipInequality(const Expr& e)
1499 {
1500 Proof pf;
1501 if(CHECK_PROOFS) {
1502 CHECK_SOUND(isGT(e) || isGE(e),
1503 "ArithTheoremProducer::flipInequality: wrong kind: " +
1504 e.toString());
1505 }
1506
1507 int kind = isGE(e) ? LE : LT;
1508 Expr ret = Expr(kind, e[1], e[0]);
1509 if(withProof()) pf = newPf("flip_inequality", e,ret);
1510 return newRWTheorem(e,ret, Assumptions::emptyAssump(), pf);
1511 }
1512
1513
1514 // NOT (op1 LT op2) <==> (op1 GE op2)
1515 // NOT (op1 LE op2) <==> (op1 GT op2)
1516 // NOT (op1 GT op2) <==> (op1 LE op2)
1517 // NOT (op1 GE op2) <==> (op1 LT op2)
negatedInequality(const Expr & e)1518 Theorem ArithTheoremProducer::negatedInequality(const Expr& e)
1519 {
1520 const Expr& ineq = e[0];
1521 if(CHECK_PROOFS) {
1522 CHECK_SOUND(e.isNot(),
1523 "ArithTheoremProducer::negatedInequality: wrong kind: " +
1524 e.toString());
1525 CHECK_SOUND(isIneq(ineq),
1526 "ArithTheoremProducer::negatedInequality: wrong kind: " +
1527 (ineq).toString());
1528 }
1529 Proof pf;
1530 if(withProof()) pf = newPf("negated_inequality", e);
1531
1532 int kind;
1533 // NOT (op1 LT op2) <==> (op1 GE op2)
1534 // NOT (op1 LE op2) <==> (op1 GT op2)
1535 // NOT (op1 GT op2) <==> (op1 LE op2)
1536 // NOT (op1 GE op2) <==> (op1 LT op2)
1537 kind =
1538 isLT(ineq) ? GE :
1539 isLE(ineq) ? GT :
1540 isGT(ineq) ? LE :
1541 LT;
1542 return newRWTheorem(e, Expr(kind, ineq[0], ineq[1]), Assumptions::emptyAssump(), pf);
1543 }
1544
1545 //takes two ineqs "|- alpha LT|LE t" and "|- t LT|LE beta"
1546 //and returns "|- alpha LT|LE beta"
realShadow(const Theorem & alphaLTt,const Theorem & tLTbeta)1547 Theorem ArithTheoremProducer::realShadow(const Theorem& alphaLTt,
1548 const Theorem& tLTbeta)
1549 {
1550 const Expr& expr1 = alphaLTt.getExpr();
1551 const Expr& expr2 = tLTbeta.getExpr();
1552 if(CHECK_PROOFS) {
1553 CHECK_SOUND((isLE(expr1) || isLT(expr1)) &&
1554 (isLE(expr2) || isLT(expr2)),
1555 "ArithTheoremProducer::realShadow: Wrong Kind: " +
1556 alphaLTt.toString() + tLTbeta.toString());
1557
1558 CHECK_SOUND(expr1[1] == expr2[0],
1559 "ArithTheoremProducer::realShadow:"
1560 " t must be same for both inputs: " +
1561 expr1[1].toString() + " , " + expr2[0].toString());
1562 }
1563 Assumptions a(alphaLTt, tLTbeta);
1564 int firstKind = expr1.getKind();
1565 int secondKind = expr2.getKind();
1566 int kind = (firstKind == secondKind) ? firstKind : LT;
1567 Proof pf;
1568 if(withProof()) {
1569 vector<Proof> pfs;
1570 pfs.push_back(alphaLTt.getProof());
1571 pfs.push_back(tLTbeta.getProof());
1572 pf = newPf("real_shadow",expr1, expr2, pfs);
1573 }
1574 return newTheorem(Expr(kind, expr1[0], expr2[1]), a, pf);
1575 }
1576
1577 //! alpha <= t <= alpha ==> t = alpha
1578
1579 /*! takes two ineqs "|- alpha LE t" and "|- t LE alpha"
1580 and returns "|- t = alpha"
1581 */
realShadowEq(const Theorem & alphaLEt,const Theorem & tLEalpha)1582 Theorem ArithTheoremProducer::realShadowEq(const Theorem& alphaLEt,
1583 const Theorem& tLEalpha)
1584 {
1585 const Expr& expr1 = alphaLEt.getExpr();
1586 const Expr& expr2 = tLEalpha.getExpr();
1587 if(CHECK_PROOFS) {
1588 CHECK_SOUND(isLE(expr1) && isLE(expr2),
1589 "ArithTheoremProducer::realShadowLTLE: Wrong Kind: " +
1590 alphaLEt.toString() + tLEalpha.toString());
1591
1592 CHECK_SOUND(expr1[1] == expr2[0],
1593 "ArithTheoremProducer::realShadowLTLE:"
1594 " t must be same for both inputs: " +
1595 alphaLEt.toString() + " , " + tLEalpha.toString());
1596
1597 CHECK_SOUND(expr1[0] == expr2[1],
1598 "ArithTheoremProducer::realShadowLTLE:"
1599 " alpha must be same for both inputs: " +
1600 alphaLEt.toString() + " , " + tLEalpha.toString());
1601 }
1602 Assumptions a(alphaLEt, tLEalpha);
1603 Proof pf;
1604 if(withProof()) {
1605 vector<Proof> pfs;
1606 pfs.push_back(alphaLEt.getProof());
1607 pfs.push_back(tLEalpha.getProof());
1608 pf = newPf("real_shadow_eq", alphaLEt.getExpr(), tLEalpha.getExpr(), pfs);
1609 }
1610 return newRWTheorem(expr1[0], expr1[1], a, pf);
1611 }
1612
1613 Theorem
finiteInterval(const Theorem & aLEt,const Theorem & tLEac,const Theorem & isInta,const Theorem & isIntt)1614 ArithTheoremProducer::finiteInterval(const Theorem& aLEt,
1615 const Theorem& tLEac,
1616 const Theorem& isInta,
1617 const Theorem& isIntt) {
1618 const Expr& e1 = aLEt.getExpr();
1619 const Expr& e2 = tLEac.getExpr();
1620 if(CHECK_PROOFS) {
1621 CHECK_SOUND(isLE(e1) && isLE(e2),
1622 "ArithTheoremProducer::finiteInterval:\n e1 = "
1623 +e1.toString()+"\n e2 = "+e2.toString());
1624 // term 't' is the same in both inequalities
1625 CHECK_SOUND(e1[1] == e2[0],
1626 "ArithTheoremProducer::finiteInterval:\n e1 = "
1627 +e1.toString()+"\n e2 = "+e2.toString());
1628 // RHS in e2 is (a+c)
1629 CHECK_SOUND(isPlus(e2[1]) && e2[1].arity() == 2,
1630 "ArithTheoremProducer::finiteInterval:\n e1 = "
1631 +e1.toString()+"\n e2 = "+e2.toString());
1632 // term 'a' in LHS of e1 and RHS of e2 is the same
1633 CHECK_SOUND(e1[0] == e2[1][0],
1634 "ArithTheoremProducer::finiteInterval:\n e1 = "
1635 +e1.toString()+"\n e2 = "+e2.toString());
1636 // 'c' in the RHS of e2 is a positive integer constant
1637 CHECK_SOUND(e2[1][1].isRational() && e2[1][1].getRational().isInteger()
1638 && e2[1][1].getRational() >= 1,
1639 "ArithTheoremProducer::finiteInterval:\n e1 = "
1640 +e1.toString()+"\n e2 = "+e2.toString());
1641 // Integrality constraints
1642 const Expr& isIntaExpr = isInta.getExpr();
1643 const Expr& isInttExpr = isIntt.getExpr();
1644 CHECK_SOUND(isIntPred(isIntaExpr) && isIntaExpr[0] == e1[0],
1645 "Wrong integrality constraint:\n e1 = "
1646 +e1.toString()+"\n isInta = "+isIntaExpr.toString());
1647 CHECK_SOUND(isIntPred(isInttExpr) && isInttExpr[0] == e1[1],
1648 "Wrong integrality constraint:\n e1 = "
1649 +e1.toString()+"\n isIntt = "+isInttExpr.toString());
1650 }
1651 vector<Theorem> thms;
1652 thms.push_back(aLEt);
1653 thms.push_back(tLEac);
1654 thms.push_back(isInta);
1655 thms.push_back(isIntt);
1656 Assumptions a(thms);
1657 Proof pf;
1658 if(withProof()) {
1659 vector<Expr> es;
1660 vector<Proof> pfs;
1661 es.push_back(e1);
1662 es.push_back(e2);
1663 es.push_back(isInta.getExpr());
1664 es.push_back(isIntt.getExpr());
1665 pfs.push_back(aLEt.getProof());
1666 pfs.push_back(tLEac.getProof());
1667 pfs.push_back(isInta.getProof());
1668 pfs.push_back(isIntt.getProof());
1669 pf = newPf("finite_interval", es, pfs);
1670 }
1671 // Construct GRAY_SHADOW(t, a, 0, c)
1672 Expr g(grayShadow(e1[1], e1[0], 0, e2[1][1].getRational()));
1673 return newTheorem(g, a, pf);
1674 }
1675
1676
1677 // Dark & Gray shadows when a <= b
darkGrayShadow2ab(const Theorem & betaLEbx,const Theorem & axLEalpha,const Theorem & isIntAlpha,const Theorem & isIntBeta,const Theorem & isIntx)1678 Theorem ArithTheoremProducer::darkGrayShadow2ab(const Theorem& betaLEbx,
1679 const Theorem& axLEalpha,
1680 const Theorem& isIntAlpha,
1681 const Theorem& isIntBeta,
1682 const Theorem& isIntx) {
1683 const Expr& expr1 = betaLEbx.getExpr();
1684 const Expr& expr2 = axLEalpha.getExpr();
1685 const Expr& isIntAlphaExpr = isIntAlpha.getExpr();
1686 const Expr& isIntBetaExpr = isIntBeta.getExpr();
1687 const Expr& isIntxExpr = isIntx.getExpr();
1688
1689 if(CHECK_PROOFS) {
1690 CHECK_SOUND(isLE(expr1) && isLE(expr2),
1691 "ArithTheoremProducer::darkGrayShadow2ab: Wrong Kind: " +
1692 betaLEbx.toString() + axLEalpha.toString());
1693 }
1694
1695 const Expr& beta = expr1[0];
1696 const Expr& bx = expr1[1];
1697 const Expr& ax = expr2[0];
1698 const Expr& alpha = expr2[1];
1699 Rational a = isMult(ax)? ax[0].getRational() : 1;
1700 Rational b = isMult(bx)? bx[0].getRational() : 1;
1701 const Expr& x = isMult(ax)? ax[1] : ax;
1702
1703 if(CHECK_PROOFS) {
1704 // Integrality constraints
1705 CHECK_SOUND(isIntPred(isIntAlphaExpr) && isIntAlphaExpr[0] == alpha,
1706 "ArithTheoremProducer::darkGrayShadow2ab:\n "
1707 "wrong integrality constraint:\n alpha = "
1708 +alpha.toString()+"\n isIntAlpha = "
1709 +isIntAlphaExpr.toString());
1710 CHECK_SOUND(isIntPred(isIntBetaExpr) && isIntBetaExpr[0] == beta,
1711 "ArithTheoremProducer::darkGrayShadow2ab:\n "
1712 "wrong integrality constraint:\n beta = "
1713 +beta.toString()+"\n isIntBeta = "
1714 +isIntBetaExpr.toString());
1715 CHECK_SOUND(isIntPred(isIntxExpr) && isIntxExpr[0] == x,
1716 "ArithTheoremProducer::darkGrayShadow2ab:\n "
1717 "wrong integrality constraint:\n x = "
1718 +x.toString()+"\n isIntx = "
1719 +isIntxExpr.toString());
1720 // Expressions ax and bx should match on x
1721 CHECK_SOUND(!isMult(ax) || ax.arity() == 2,
1722 "ArithTheoremProducer::darkGrayShadow2ab:\n ax<=alpha: " +
1723 axLEalpha.toString());
1724 CHECK_SOUND(!isMult(bx) || (bx.arity() == 2 && bx[1] == x),
1725 "ArithTheoremProducer::darkGrayShadow2ab:\n beta<=bx: "
1726 +betaLEbx.toString()
1727 +"\n ax<=alpha: "+ axLEalpha.toString());
1728 CHECK_SOUND(1 <= a && a <= b && 2 <= b,
1729 "ArithTheoremProducer::darkGrayShadow2ab:\n beta<=bx: "
1730 +betaLEbx.toString()
1731 +"\n ax<=alpha: "+ axLEalpha.toString());
1732 }
1733 vector<Theorem> thms;
1734 thms.push_back(betaLEbx);
1735 thms.push_back(axLEalpha);
1736 thms.push_back(isIntAlpha);
1737 thms.push_back(isIntBeta);
1738 thms.push_back(isIntx);
1739 Assumptions A(thms);
1740
1741 Expr bAlpha = multExpr(rat(b), alpha);
1742 Expr aBeta = multExpr(rat(a), beta);
1743 Expr t = minusExpr(bAlpha, aBeta);
1744 Expr d = darkShadow(rat(a*b-1), t);
1745 Expr g = grayShadow(ax, alpha, -a+1, 0);
1746
1747 Proof pf;
1748 if(withProof()) {
1749 vector<Expr> exprs;
1750 exprs.push_back(expr1);
1751 exprs.push_back(expr2);
1752 exprs.push_back(d);
1753 exprs.push_back(g);
1754
1755 vector<Proof> pfs;
1756 pfs.push_back(betaLEbx.getProof());
1757 pfs.push_back(axLEalpha.getProof());
1758 pfs.push_back(isIntAlpha.getProof());
1759 pfs.push_back(isIntBeta.getProof());
1760 pfs.push_back(isIntx.getProof());
1761
1762 pf = newPf("dark_grayshadow_2ab", exprs, pfs);
1763 }
1764
1765 return newTheorem((d || g) && (!d || !g), A, pf);
1766 }
1767
1768 // Dark & Gray shadows when b <= a
darkGrayShadow2ba(const Theorem & betaLEbx,const Theorem & axLEalpha,const Theorem & isIntAlpha,const Theorem & isIntBeta,const Theorem & isIntx)1769 Theorem ArithTheoremProducer::darkGrayShadow2ba(const Theorem& betaLEbx,
1770 const Theorem& axLEalpha,
1771 const Theorem& isIntAlpha,
1772 const Theorem& isIntBeta,
1773 const Theorem& isIntx) {
1774 const Expr& expr1 = betaLEbx.getExpr();
1775 const Expr& expr2 = axLEalpha.getExpr();
1776 const Expr& isIntAlphaExpr = isIntAlpha.getExpr();
1777 const Expr& isIntBetaExpr = isIntBeta.getExpr();
1778 const Expr& isIntxExpr = isIntx.getExpr();
1779
1780 if(CHECK_PROOFS) {
1781 CHECK_SOUND(isLE(expr1) && isLE(expr2),
1782 "ArithTheoremProducer::darkGrayShadow2ba: Wrong Kind: " +
1783 betaLEbx.toString() + axLEalpha.toString());
1784 }
1785
1786 const Expr& beta = expr1[0];
1787 const Expr& bx = expr1[1];
1788 const Expr& ax = expr2[0];
1789 const Expr& alpha = expr2[1];
1790 Rational a = isMult(ax)? ax[0].getRational() : 1;
1791 Rational b = isMult(bx)? bx[0].getRational() : 1;
1792 const Expr& x = isMult(ax)? ax[1] : ax;
1793
1794 if(CHECK_PROOFS) {
1795 // Integrality constraints
1796 CHECK_SOUND(isIntPred(isIntAlphaExpr) && isIntAlphaExpr[0] == alpha,
1797 "ArithTheoremProducer::darkGrayShadow2ab:\n "
1798 "wrong integrality constraint:\n alpha = "
1799 +alpha.toString()+"\n isIntAlpha = "
1800 +isIntAlphaExpr.toString());
1801 CHECK_SOUND(isIntPred(isIntBetaExpr) && isIntBetaExpr[0] == beta,
1802 "ArithTheoremProducer::darkGrayShadow2ab:\n "
1803 "wrong integrality constraint:\n beta = "
1804 +beta.toString()+"\n isIntBeta = "
1805 +isIntBetaExpr.toString());
1806 CHECK_SOUND(isIntPred(isIntxExpr) && isIntxExpr[0] == x,
1807 "ArithTheoremProducer::darkGrayShadow2ab:\n "
1808 "wrong integrality constraint:\n x = "
1809 +x.toString()+"\n isIntx = "
1810 +isIntxExpr.toString());
1811 // Expressions ax and bx should match on x
1812 CHECK_SOUND(!isMult(ax) || ax.arity() == 2,
1813 "ArithTheoremProducer::darkGrayShadow2ba:\n ax<=alpha: " +
1814 axLEalpha.toString());
1815 CHECK_SOUND(!isMult(bx) || (bx.arity() == 2 && bx[1] == x),
1816 "ArithTheoremProducer::darkGrayShadow2ba:\n beta<=bx: "
1817 +betaLEbx.toString()
1818 +"\n ax<=alpha: "+ axLEalpha.toString());
1819 CHECK_SOUND(1 <= b && b <= a && 2 <= a,
1820 "ArithTheoremProducer::darkGrayShadow2ba:\n beta<=bx: "
1821 +betaLEbx.toString()
1822 +"\n ax<=alpha: "+ axLEalpha.toString());
1823 }
1824 vector<Theorem> thms;
1825 thms.push_back(betaLEbx);
1826 thms.push_back(axLEalpha);
1827 thms.push_back(isIntAlpha);
1828 thms.push_back(isIntBeta);
1829 thms.push_back(isIntx);
1830 Assumptions A(thms);
1831 Proof pf;
1832 if(withProof()) {
1833 vector<Proof> pfs;
1834 pfs.push_back(betaLEbx.getProof());
1835 pfs.push_back(axLEalpha.getProof());
1836 pfs.push_back(isIntAlpha.getProof());
1837 pfs.push_back(isIntBeta.getProof());
1838 pfs.push_back(isIntx.getProof());
1839
1840 pf = newPf("dark_grayshadow_2ba", betaLEbx.getExpr(),
1841 axLEalpha.getExpr(), pfs);
1842 }
1843
1844 Expr bAlpha = multExpr(rat(b), alpha);
1845 Expr aBeta = multExpr(rat(a), beta);
1846 Expr t = minusExpr(bAlpha, aBeta);
1847 Expr d = darkShadow(rat(a*b-1), t);
1848 Expr g = grayShadow(bx, beta, 0, b-1);
1849 return newTheorem((d || g) && (!d || !g), A, pf);
1850 }
1851
1852 /*! takes a dark shadow and expands it into an inequality.
1853 */
expandDarkShadow(const Theorem & darkShadow)1854 Theorem ArithTheoremProducer::expandDarkShadow(const Theorem& darkShadow) {
1855 const Expr& theShadow = darkShadow.getExpr();
1856 if(CHECK_PROOFS){
1857 CHECK_SOUND(isDarkShadow(theShadow),
1858 "ArithTheoremProducer::expandDarkShadow: not DARK_SHADOW: " +
1859 theShadow.toString());
1860 }
1861 Proof pf;
1862 if(withProof())
1863 pf = newPf("expand_dark_shadow", theShadow, darkShadow.getProof());
1864 return newTheorem(leExpr(theShadow[0], theShadow[1]), darkShadow.getAssumptionsRef(), pf);
1865 }
1866
1867
1868 // takes a grayShadow (c1==c2) and expands it into an equality
expandGrayShadow0(const Theorem & grayShadow)1869 Theorem ArithTheoremProducer::expandGrayShadow0(const Theorem& grayShadow) {
1870 const Expr& theShadow = grayShadow.getExpr();
1871 if(CHECK_PROOFS) {
1872 CHECK_SOUND(isGrayShadow(theShadow),
1873 "ArithTheoremProducer::expandGrayShadowConst0:"
1874 " not GRAY_SHADOW: " +
1875 theShadow.toString());
1876 CHECK_SOUND(theShadow[2] == theShadow[3],
1877 "ArithTheoremProducer::expandGrayShadow0: c1!=c2: " +
1878 theShadow.toString());
1879 }
1880 Proof pf;
1881 if(withProof()) pf = newPf("expand_gray_shadowconst0", theShadow,
1882 grayShadow.getProof());
1883 const Expr& v = theShadow[0];
1884 const Expr& e = theShadow[1];
1885 return newRWTheorem(v, e + theShadow[2], grayShadow.getAssumptionsRef(), pf);
1886 }
1887
1888
1889 // G ==> (G1 or G2) and (!G1 or !G2),
1890 // where G = G(x, e, c1, c2),
1891 // G1 = G(x,e,c1,c)
1892 // G2 = G(x,e,c+1,c2),
1893 // and c = floor((c1+c2)/2)
splitGrayShadow(const Theorem & gThm)1894 Theorem ArithTheoremProducer::splitGrayShadow(const Theorem& gThm) {
1895 const Expr& theShadow = gThm.getExpr();
1896 if(CHECK_PROOFS) {
1897 CHECK_SOUND(isGrayShadow(theShadow),
1898 "ArithTheoremProducer::expandGrayShadowConst: not a shadow" +
1899 theShadow.toString());
1900 }
1901
1902 const Rational& c1 = theShadow[2].getRational();
1903 const Rational& c2 = theShadow[3].getRational();
1904
1905 if(CHECK_PROOFS) {
1906 CHECK_SOUND(c1.isInteger() && c2.isInteger() && c1 < c2,
1907 "ArithTheoremProducer::expandGrayShadow: " +
1908 theShadow.toString());
1909 }
1910
1911 const Expr& v = theShadow[0];
1912 const Expr& e = theShadow[1];
1913
1914 Proof pf;
1915 Rational c(floor((c1+c2) / 2));
1916 Expr g1(grayShadow(v, e, c1, c));
1917 Expr g2(grayShadow(v, e, c+1, c2));
1918
1919 if(withProof()){
1920 vector<Expr> exprs;
1921 exprs.push_back(theShadow);
1922 exprs.push_back(g1);
1923 exprs.push_back(g2);
1924 pf = newPf("split_gray_shadow", exprs, gThm.getProof());
1925 }
1926
1927 return newTheorem((g1 || g2) && (!g1 || !g2), gThm.getAssumptionsRef(), pf);
1928 }
1929
1930
expandGrayShadow(const Theorem & gThm)1931 Theorem ArithTheoremProducer::expandGrayShadow(const Theorem& gThm) {
1932 const Expr& theShadow = gThm.getExpr();
1933 if(CHECK_PROOFS) {
1934 CHECK_SOUND(isGrayShadow(theShadow),
1935 "ArithTheoremProducer::expandGrayShadowConst: not a shadow" +
1936 theShadow.toString());
1937 }
1938
1939 const Rational& c1 = theShadow[2].getRational();
1940 const Rational& c2 = theShadow[3].getRational();
1941
1942 if(CHECK_PROOFS) {
1943 CHECK_SOUND(c1.isInteger() && c2.isInteger() && c1 < c2,
1944 "ArithTheoremProducer::expandGrayShadow: " +
1945 theShadow.toString());
1946 }
1947
1948 const Expr& v = theShadow[0];
1949 const Expr& e = theShadow[1];
1950
1951 Proof pf;
1952 if(withProof())
1953 pf = newPf("expand_gray_shadow", theShadow, gThm.getProof());
1954 Expr ineq1(leExpr(e+rat(c1), v));
1955 Expr ineq2(leExpr(v, e+rat(c2)));
1956 return newTheorem(ineq1 && ineq2, gThm.getAssumptionsRef(), pf);
1957 }
1958
1959
1960 // Expanding GRAY_SHADOW(a*x, c, b), where c is a constant
1961 Theorem
expandGrayShadowConst(const Theorem & gThm)1962 ArithTheoremProducer::expandGrayShadowConst(const Theorem& gThm) {
1963 const Expr& theShadow = gThm.getExpr();
1964 const Expr& ax = theShadow[0];
1965 const Expr& cExpr = theShadow[1];
1966 const Expr& bExpr = theShadow[2];
1967
1968 if(CHECK_PROOFS) {
1969 CHECK_SOUND(!isMult(ax) || ax[0].isRational(),
1970 "ArithTheoremProducer::expandGrayShadowConst: "
1971 "'a' in a*x is not a const: " +theShadow.toString());
1972 }
1973
1974 Rational a = isMult(ax)? ax[0].getRational() : 1;
1975
1976 if(CHECK_PROOFS) {
1977 CHECK_SOUND(isGrayShadow(theShadow),
1978 "ArithTheoremProducer::expandGrayShadowConst: "
1979 "not a GRAY_SHADOW: " +theShadow.toString());
1980 CHECK_SOUND(a.isInteger() && a >= 1,
1981 "ArithTheoremProducer::expandGrayShadowConst: "
1982 "'a' is not integer: " +theShadow.toString());
1983 CHECK_SOUND(cExpr.isRational(),
1984 "ArithTheoremProducer::expandGrayShadowConst: "
1985 "'c' is not rational" +theShadow.toString());
1986 CHECK_SOUND(bExpr.isRational() && bExpr.getRational().isInteger(),
1987 "ArithTheoremProducer::expandGrayShadowConst: b not integer: "
1988 +theShadow.toString());
1989 }
1990
1991 const Rational& b = bExpr.getRational();
1992 const Rational& c = cExpr.getRational();
1993 Rational j = constRHSGrayShadow(c,b,a);
1994 // Compute sign(b)*j(c,b,a)
1995 Rational signB = (b>0)? 1 : -1;
1996 // |b| (absolute value of b)
1997 Rational bAbs = abs(b);
1998
1999 const Assumptions& assump(gThm.getAssumptionsRef());
2000 Proof pf;
2001 Theorem conc; // Conclusion of the rule
2002
2003 if(bAbs < j) {
2004 if(withProof())
2005 pf = newPf("expand_gray_shadow_const_0", theShadow,
2006 gThm.getProof());
2007 conc = newTheorem(d_em->falseExpr(), assump, pf);
2008 } else if(bAbs < a+j) {
2009 if(withProof())
2010 pf = newPf("expand_gray_shadow_const_1", theShadow,
2011 gThm.getProof());
2012 conc = newRWTheorem(ax, rat(c+b-signB*j), assump, pf);
2013 } else {
2014 if(withProof())
2015 pf = newPf("expand_gray_shadow_const", theShadow,
2016 gThm.getProof());
2017 Expr newGrayShadow(Expr(GRAY_SHADOW, ax, cExpr, rat(b-signB*(a+j))));
2018 conc = newTheorem(ax.eqExpr(rat(c+b-signB*j)).orExpr(newGrayShadow),
2019 assump, pf);
2020 }
2021
2022 return conc;
2023 }
2024
2025
2026 Theorem
grayShadowConst(const Theorem & gThm)2027 ArithTheoremProducer::grayShadowConst(const Theorem& gThm) {
2028 const Expr& g = gThm.getExpr();
2029 bool checkProofs(CHECK_PROOFS);
2030 if(checkProofs) {
2031 CHECK_SOUND(isGrayShadow(g), "ArithTheoremProducer::grayShadowConst("
2032 +g.toString()+")");
2033 }
2034
2035 const Expr& ax = g[0];
2036 const Expr& e = g[1];
2037 const Rational& c1 = g[2].getRational();
2038 const Rational& c2 = g[3].getRational();
2039 Expr aExpr, x;
2040 d_theoryArith->separateMonomial(ax, aExpr, x);
2041
2042 if(checkProofs) {
2043 CHECK_SOUND(e.isRational() && e.getRational().isInteger(),
2044 "ArithTheoremProducer::grayShadowConst("+g.toString()+")");
2045 CHECK_SOUND(aExpr.isRational(),
2046 "ArithTheoremProducer::grayShadowConst("+g.toString()+")");
2047 }
2048
2049 const Rational& a = aExpr.getRational();
2050 const Rational& c = e.getRational();
2051
2052 if(checkProofs) {
2053 CHECK_SOUND(a.isInteger() && a >= 2,
2054 "ArithTheoremProducer::grayShadowConst("+g.toString()+")");
2055 }
2056
2057 Rational newC1 = ceil((c1+c)/a), newC2 = floor((c2+c)/a);
2058 Expr newG((newC1 > newC2)? d_em->falseExpr()
2059 : grayShadow(x, rat(0), newC1, newC2));
2060 Proof pf;
2061 if(withProof())
2062 pf = newPf("gray_shadow_const", g, newG, gThm.getProof());
2063 return newTheorem(newG, gThm.getAssumptionsRef(), pf);
2064 }
2065
2066
constRHSGrayShadow(const Rational & c,const Rational & b,const Rational & a)2067 Rational ArithTheoremProducer::constRHSGrayShadow(const Rational& c,
2068 const Rational& b,
2069 const Rational& a) {
2070 DebugAssert(c.isInteger() &&
2071 b.isInteger() &&
2072 a.isInteger() &&
2073 b != 0,
2074 "ArithTheoremProducer::constRHSGrayShadow: a, b, c must be ints");
2075 if (b > 0)
2076 return mod(c+b, a);
2077 else
2078 return mod(a-(c+b), a);
2079 }
2080
2081 /*! Takes a Theorem(\\alpha < \\beta) and returns
2082 * Theorem(\\alpha < \\beta <==> \\alpha <= \\beta -1)
2083 * where \\alpha and \\beta are integer expressions
2084 */
lessThanToLE(const Theorem & less,const Theorem & isIntLHS,const Theorem & isIntRHS,bool changeRight)2085 Theorem ArithTheoremProducer::lessThanToLE(const Theorem& less,
2086 const Theorem& isIntLHS,
2087 const Theorem& isIntRHS,
2088 bool changeRight) {
2089 const Expr& ineq = less.getExpr();
2090 const Expr& isIntLHSexpr = isIntLHS.getExpr();
2091 const Expr& isIntRHSexpr = isIntRHS.getExpr();
2092
2093 if(CHECK_PROOFS) {
2094 CHECK_SOUND(isLT(ineq),
2095 "ArithTheoremProducer::LTtoLE: ineq must be <");
2096 // Integrality check
2097 CHECK_SOUND(isIntPred(isIntLHSexpr) && isIntLHSexpr[0] == ineq[0],
2098 "ArithTheoremProducer::lessThanToLE: bad integrality check:\n"
2099 " ineq = "+ineq.toString()+"\n isIntLHS = "
2100 +isIntLHSexpr.toString());
2101 CHECK_SOUND(isIntPred(isIntRHSexpr) && isIntRHSexpr[0] == ineq[1],
2102 "ArithTheoremProducer::lessThanToLE: bad integrality check:\n"
2103 " ineq = "+ineq.toString()+"\n isIntRHS = "
2104 +isIntRHSexpr.toString());
2105 }
2106 vector<Theorem> thms;
2107 thms.push_back(less);
2108 thms.push_back(isIntLHS);
2109 thms.push_back(isIntRHS);
2110 Assumptions a(thms);
2111 Proof pf;
2112 Expr le = changeRight?
2113 leExpr(ineq[0], ineq[1] + rat(-1))
2114 : leExpr(ineq[0] + rat(1), ineq[1]);
2115
2116 if(withProof()) {
2117 vector<Proof> pfs;
2118 pfs.push_back(less.getProof());
2119 pfs.push_back(isIntLHS.getProof());
2120 pfs.push_back(isIntRHS.getProof());
2121 pf = newPf(changeRight? "lessThan_To_LE_rhs" : "lessThan_To_LE_lhs",
2122 ineq, le, pfs);
2123 }
2124
2125 return newRWTheorem(ineq, le, a, pf);
2126 }
2127
2128
2129 /*! \param eqn is an equation 0 = a.x or 0 = c + a.x
2130 * \param isIntx is a proof of IS_INTEGER(x)
2131 *
2132 * \return the theorem 0 = c + a.x <==> x=-c/a if -c/a is int else
2133 * return the theorem 0 = c + a.x <==> false.
2134 *
2135 * It also handles the special case of 0 = a.x <==> x = 0
2136 */
2137 Theorem
intVarEqnConst(const Expr & eqn,const Theorem & isIntx)2138 ArithTheoremProducer::intVarEqnConst(const Expr& eqn,
2139 const Theorem& isIntx) {
2140 const Expr& left(eqn[0]);
2141 const Expr& right(eqn[1]);
2142 const Expr& isIntxexpr(isIntx.getExpr());
2143
2144 if(CHECK_PROOFS) {
2145 CHECK_SOUND((isMult(right) && right[0].isRational())
2146 || (right.arity() == 2 && isPlus(right)
2147 && right[0].isRational()
2148 && ((!isMult(right[1]) || right[1][0].isRational()))),
2149 "ArithTheoremProducer::intVarEqnConst: "
2150 "rhs has a wrong format: " + right.toString());
2151 CHECK_SOUND(left.isRational() && 0 == left.getRational(),
2152 "ArithTheoremProducer:intVarEqnConst:left is not a zero: " +
2153 left.toString());
2154 }
2155 // Integrality constraint
2156 Expr x(right);
2157 Rational a(1), c(0);
2158 if(isMult(right)) {
2159 Expr aExpr;
2160 d_theoryArith->separateMonomial(right, aExpr, x);
2161 a = aExpr.getRational();
2162 } else { // right is a PLUS
2163 c = right[0].getRational();
2164 Expr aExpr;
2165 d_theoryArith->separateMonomial(right[1], aExpr, x);
2166 a = aExpr.getRational();
2167 }
2168 if(CHECK_PROOFS) {
2169 CHECK_SOUND(isIntPred(isIntxexpr) && isIntxexpr[0] == x,
2170 "ArithTheoremProducer:intVarEqnConst: "
2171 "bad integrality constraint:\n right = " +
2172 right.toString()+"\n isIntx = "+isIntxexpr.toString());
2173 CHECK_SOUND(a!=0, "ArithTheoremProducer:intVarEqnConst: eqn = "
2174 +eqn.toString());
2175 }
2176 const Assumptions& assump(isIntx.getAssumptionsRef());
2177 Proof pf;
2178 if(withProof())
2179 pf = newPf("int_const_eq", eqn, isIntx.getProof());
2180
2181 // Solve for x: x = r = -c/a
2182 Rational r(-c/a);
2183
2184 if(r.isInteger())
2185 return newRWTheorem(eqn, x.eqExpr(rat(r)), assump, pf);
2186 else
2187 return newRWTheorem(eqn, d_em->falseExpr(), assump, pf);
2188 }
2189
2190
2191 Expr
create_t(const Expr & eqn)2192 ArithTheoremProducer::create_t(const Expr& eqn) {
2193 const Expr& lhs = eqn[0];
2194 DebugAssert(isMult(lhs),
2195 CLASS_NAME "create_t : lhs must be a MULT"
2196 + lhs.toString());
2197 const Expr& x = lhs[1];
2198 Rational m = lhs[0].getRational()+1;
2199 DebugAssert(m > 0, "ArithTheoremProducer::create_t: m = "+m.toString());
2200 vector<Expr> kids;
2201 if(isPlus(eqn[1]))
2202 sumModM(kids, eqn[1], m, m);
2203 else
2204 kids.push_back(monomialModM(eqn[1], m, m));
2205
2206 kids.push_back(multExpr(rat(1/m), x));
2207 return plusExpr(kids);
2208 }
2209
2210 Expr
create_t2(const Expr & lhs,const Expr & rhs,const Expr & sigma)2211 ArithTheoremProducer::create_t2(const Expr& lhs, const Expr& rhs,
2212 const Expr& sigma) {
2213 Rational m = lhs[0].getRational()+1;
2214 DebugAssert(m > 0, "ArithTheoremProducer::create_t2: m = "+m.toString());
2215 vector<Expr> kids;
2216 if(isPlus(rhs))
2217 sumModM(kids, rhs, m, -1);
2218 else {
2219 kids.push_back(rat(0)); // For canonical form
2220 Expr monom = monomialModM(rhs, m, -1);
2221 if(!monom.isRational())
2222 kids.push_back(monom);
2223 else
2224 DebugAssert(monom.getRational() == 0, "");
2225 }
2226 kids.push_back(rat(m)*sigma);
2227 return plusExpr(kids);
2228 }
2229
2230 Expr
create_t3(const Expr & lhs,const Expr & rhs,const Expr & sigma)2231 ArithTheoremProducer::create_t3(const Expr& lhs, const Expr& rhs,
2232 const Expr& sigma) {
2233 const Rational& a = lhs[0].getRational();
2234 Rational m = a+1;
2235 DebugAssert(m > 0, "ArithTheoremProducer::create_t3: m = "+m.toString());
2236 vector<Expr> kids;
2237 if(isPlus(rhs))
2238 sumMulF(kids, rhs, m, 1);
2239 else {
2240 kids.push_back(rat(0)); // For canonical form
2241 Expr monom = monomialMulF(rhs, m, 1);
2242 if(!monom.isRational())
2243 kids.push_back(monom);
2244 else
2245 DebugAssert(monom.getRational() == 0, "");
2246 }
2247 kids.push_back(rat(-a)*sigma);
2248 return plusExpr(kids);
2249 }
2250
2251 Rational
modEq(const Rational & i,const Rational & m)2252 ArithTheoremProducer::modEq(const Rational& i, const Rational& m) {
2253 DebugAssert(m > 0, "ArithTheoremProducer::modEq: m = "+m.toString());
2254 Rational half(1,2);
2255 Rational res((i - m*(floor((i/m) + half))));
2256 TRACE("arith eq", "modEq("+i.toString()+", "+m.toString()+") = ", res, "");
2257 return res;
2258 }
2259
2260 Rational
f(const Rational & i,const Rational & m)2261 ArithTheoremProducer::f(const Rational& i, const Rational& m) {
2262 DebugAssert(m > 0, "ArithTheoremProducer::f: m = "+m.toString());
2263 Rational half(1,2);
2264 return (floor(i/m + half)+modEq(i,m));
2265 }
2266
2267 void
sumModM(vector<Expr> & summands,const Expr & sum,const Rational & m,const Rational & divisor)2268 ArithTheoremProducer::sumModM(vector<Expr>& summands, const Expr& sum,
2269 const Rational& m, const Rational& divisor) {
2270 DebugAssert(divisor != 0, "ArithTheoremProducer::sumModM: divisor = "
2271 +divisor.toString());
2272 Expr::iterator i = sum.begin();
2273 DebugAssert(i != sum.end(), CLASS_NAME "::sumModM");
2274 Rational C = i->getRational();
2275 C = modEq(C,m)/divisor;
2276 summands.push_back(rat(C));
2277 i++;
2278 for(Expr::iterator iend=sum.end(); i!=iend; ++i) {
2279 Expr monom = monomialModM(*i, m, divisor);
2280 if(!monom.isRational())
2281 summands.push_back(monom);
2282 else
2283 DebugAssert(monom.getRational() == 0, "");
2284 }
2285 }
2286
2287 Expr
monomialModM(const Expr & i,const Rational & m,const Rational & divisor)2288 ArithTheoremProducer::monomialModM(const Expr& i,
2289 const Rational& m, const Rational& divisor)
2290 {
2291 DebugAssert(divisor != 0, "ArithTheoremProducer::monomialModM: divisor = "
2292 +divisor.toString());
2293 Expr res;
2294 if(isMult(i)) {
2295 Rational ai = i[0].getRational();
2296 ai = modEq(ai,m)/divisor;
2297 if(0 == ai) res = rat(0);
2298 else if(1 == ai && i.arity() == 2) res = i[1];
2299 else {
2300 vector<Expr> kids = i.getKids();
2301 kids[0] = rat(ai);
2302 res = multExpr(kids);
2303 }
2304 } else { // It's a single variable
2305 Rational ai = modEq(1,m)/divisor;
2306 if(1 == ai) res = i;
2307 else res = rat(ai)*i;
2308 }
2309 DebugAssert(!res.isNull(), "ArithTheoremProducer::monomialModM()");
2310 TRACE("arith eq", "monomialModM(i="+i.toString()+", m="+m.toString()
2311 +", div="+divisor.toString()+") = ", res, "");
2312 return res;
2313 }
2314
2315 void
sumMulF(vector<Expr> & summands,const Expr & sum,const Rational & m,const Rational & divisor)2316 ArithTheoremProducer::sumMulF(vector<Expr>& summands, const Expr& sum,
2317 const Rational& m, const Rational& divisor) {
2318 DebugAssert(divisor != 0, "ArithTheoremProducer::sumMulF: divisor = "
2319 +divisor.toString());
2320 Expr::iterator i = sum.begin();
2321 DebugAssert(i != sum.end(), CLASS_NAME "::sumModM");
2322 Rational C = i->getRational();
2323 C = f(C,m)/divisor;
2324 summands.push_back(rat(C));
2325 i++;
2326 for(Expr::iterator iend=sum.end(); i!=iend; ++i) {
2327 Expr monom = monomialMulF(*i, m, divisor);
2328 if(!monom.isRational())
2329 summands.push_back(monom);
2330 else
2331 DebugAssert(monom.getRational() == 0, "");
2332 }
2333 }
2334
2335 Expr
monomialMulF(const Expr & i,const Rational & m,const Rational & divisor)2336 ArithTheoremProducer::monomialMulF(const Expr& i,
2337 const Rational& m, const Rational& divisor)
2338 {
2339 DebugAssert(divisor != 0, "ArithTheoremProducer::monomialMulF: divisor = "
2340 +divisor.toString());
2341 Rational ai = isMult(i) ? (i)[0].getRational() : 1;
2342 Expr xi = isMult(i) ? (i)[1] : (i);
2343 ai = f(ai,m)/divisor;
2344 if(0 == ai) return rat(0);
2345 if(1 == ai) return xi;
2346 return multExpr(rat(ai), xi);
2347 }
2348
2349 // This recursive function accepts a term, t, and a 'map' of
2350 // substitutions [x1/t1, x2/t2,...,xn/tn]. it returns a t' which is
2351 // basically t[x1/t1,x2/t2...xn/tn]
2352 Expr
substitute(const Expr & term,ExprMap<Expr> & eMap)2353 ArithTheoremProducer::substitute(const Expr& term, ExprMap<Expr>& eMap)
2354 {
2355 ExprMap<Expr>::iterator i, iend = eMap.end();
2356
2357 i = eMap.find(term);
2358 if(iend != i)
2359 return (*i).second;
2360
2361 if (isMult(term)) {
2362 //in this case term is of the form c.x
2363 i = eMap.find(term[1]);
2364 if(iend != i)
2365 return term[0]*(*i).second;
2366 else
2367 return term;
2368 }
2369
2370 if(isPlus(term)) {
2371 vector<Expr> output;
2372 for(Expr::iterator j = term.begin(), jend = term.end(); j != jend; ++j)
2373 output.push_back(substitute(*j, eMap));
2374 return plusExpr(output);
2375 }
2376 return term;
2377 }
2378
greaterthan(const Expr & l,const Expr & r)2379 bool ArithTheoremProducer::greaterthan(const Expr & l, const Expr & r)
2380 {
2381 // DebugAssert(l != r, "");
2382 if (l==r) return false;
2383
2384 switch(l.getKind()) {
2385 case RATIONAL_EXPR:
2386 DebugAssert(!r.isRational(), "");
2387 return true;
2388 break;
2389 case POW:
2390 switch (r.getKind()) {
2391 case RATIONAL_EXPR:
2392 // TODO:
2393 // alternately I could return (not greaterthan(r,l))
2394 return false;
2395 break;
2396 case POW:
2397 // x^n > y^n if x > y
2398 // x^n1 > x^n2 if n1 > n2
2399 return
2400 ((r[1] < l[1]) ||
2401 ((r[1]==l[1]) && (r[0].getRational() < l[0].getRational())));
2402 break;
2403
2404 case MULT:
2405 DebugAssert(r.arity() > 1, "");
2406 DebugAssert((r.arity() > 2) || (r[1] != l), "");
2407 if (r[1] == l) return false;
2408 return greaterthan(l, r[1]);
2409 break;
2410 case PLUS:
2411 DebugAssert(false, "");
2412 return true;
2413 break;
2414 default:
2415 // leaf
2416 return ((r < l[1]) || ((r == l[1]) && l[0].getRational() > 1));
2417 break;
2418 }
2419 break;
2420 case MULT:
2421 DebugAssert(l.arity() > 1, "");
2422 switch (r.getKind()) {
2423 case RATIONAL_EXPR:
2424 return false;
2425 break;
2426 case POW:
2427 DebugAssert(l.arity() > 1, "");
2428 DebugAssert((l.arity() > 2) || (l[1] != r), "");
2429 // TODO:
2430 // alternately return (not greaterthan(r,l)
2431 return ((l[1] == r) || greaterthan(l[1], r));
2432 break;
2433 case MULT:
2434 {
2435
2436 DebugAssert(r.arity() > 1, "");
2437 Expr::iterator i = l.begin();
2438 Expr::iterator j = r.begin();
2439 ++i;
2440 ++j;
2441 for (; i != l.end() && j != r.end(); ++i, ++j) {
2442 if (*i == *j)
2443 continue;
2444 return greaterthan(*i,*j);
2445 }
2446 DebugAssert(i != l.end() || j != r.end(), "");
2447 if (i == l.end()) {
2448 // r is bigger
2449 return false;
2450 }
2451 else
2452 {
2453 // l is bigger
2454 return true;
2455 }
2456 }
2457 break;
2458 case PLUS:
2459 DebugAssert(false, "");
2460 return true;
2461 break;
2462 default:
2463 // leaf
2464 DebugAssert((l.arity() > 2) || (l[1] != r), "");
2465 return ((l[1] == r) || greaterthan(l[1], r));
2466 break;
2467 }
2468 break;
2469 case PLUS:
2470 DebugAssert(false, "");
2471 return true;
2472 break;
2473 default:
2474 // leaf
2475 switch (r.getKind()) {
2476 case RATIONAL_EXPR:
2477 return false;
2478 break;
2479 case POW:
2480 return ((r[1] < l) || ((r[1] == l) && (r[0].getRational() < 1)));
2481 break;
2482 case MULT:
2483 DebugAssert(r.arity() > 1, "");
2484 DebugAssert((r.arity() > 2) || (r[1] != l), "");
2485 if (l == r[1]) return false;
2486 return greaterthan(l,r[1]);
2487 break;
2488 case PLUS:
2489 DebugAssert(false, "");
2490 return true;
2491 break;
2492 default:
2493 // leaf
2494 return (r < l);
2495 break;
2496 }
2497 break;
2498 }
2499 }
2500
2501
2502 /*! IS_INTEGER(x) |= EXISTS (y : INT) y = x
2503 * where x is not already known to be an integer.
2504 */
IsIntegerElim(const Theorem & isIntx)2505 Theorem ArithTheoremProducer::IsIntegerElim(const Theorem& isIntx)
2506 {
2507 Expr expr = isIntx.getExpr();
2508 if (CHECK_PROOFS) {
2509 CHECK_SOUND(expr.getKind() == IS_INTEGER,
2510 "Expected IS_INTEGER predicate");
2511 }
2512 expr = expr[0];
2513 DebugAssert(!d_theoryArith->isInteger(expr), "Expected non-integer");
2514
2515 Assumptions a(isIntx);
2516 Proof pf;
2517
2518 if (withProof())
2519 {
2520 pf = newPf("isIntElim", isIntx.getProof());
2521 }
2522
2523 Expr newVar = d_em->newBoundVarExpr(d_theoryArith->intType());
2524 Expr res = d_em->newClosureExpr(EXISTS, newVar, newVar.eqExpr(expr));
2525
2526 return newTheorem(res, a, pf);
2527 }
2528
2529
2530 Theorem
eqElimIntRule(const Theorem & eqn,const Theorem & isIntx,const vector<Theorem> & isIntVars)2531 ArithTheoremProducer::eqElimIntRule(const Theorem& eqn, const Theorem& isIntx,
2532 const vector<Theorem>& isIntVars) {
2533 TRACE("arith eq", "eqElimIntRule(", eqn.getExpr(), ") {");
2534 Proof pf;
2535
2536 if(CHECK_PROOFS)
2537 CHECK_SOUND(eqn.isRewrite(),
2538 "ArithTheoremProducer::eqElimInt: input must be an equation" +
2539 eqn.toString());
2540
2541 const Expr& lhs = eqn.getLHS();
2542 const Expr& rhs = eqn.getRHS();
2543 Expr a, x;
2544 d_theoryArith->separateMonomial(lhs, a, x);
2545
2546 if(CHECK_PROOFS) {
2547 // Checking LHS
2548 const Expr& isIntxe = isIntx.getExpr();
2549 CHECK_SOUND(isIntPred(isIntxe) && isIntxe[0] == x,
2550 "ArithTheoremProducer::eqElimInt\n eqn = "
2551 +eqn.getExpr().toString()
2552 +"\n isIntx = "+isIntxe.toString());
2553 CHECK_SOUND(isRational(a) && a.getRational().isInteger()
2554 && a.getRational() >= 2,
2555 "ArithTheoremProducer::eqElimInt:\n lhs = "+lhs.toString());
2556 // Checking RHS
2557 // It cannot be a division (we don't handle it)
2558 CHECK_SOUND(!isDivide(rhs),
2559 "ArithTheoremProducer::eqElimInt:\n rhs = "+rhs.toString());
2560 // If it's a single monomial, then it's the only "variable"
2561 if(!isPlus(rhs)) {
2562 Expr c, v;
2563 d_theoryArith->separateMonomial(rhs, c, v);
2564 CHECK_SOUND(isIntVars.size() == 1
2565 && isIntPred(isIntVars[0].getExpr())
2566 && isIntVars[0].getExpr()[0] == v
2567 && isRational(c) && c.getRational().isInteger(),
2568 "ArithTheoremProducer::eqElimInt:\n rhs = "+rhs.toString()
2569 +"isIntVars.size = "+int2string(isIntVars.size()));
2570 } else { // RHS is a plus
2571 CHECK_SOUND(isIntVars.size() + 1 == (size_t)rhs.arity(),
2572 "ArithTheoremProducer::eqElimInt: rhs = "+rhs.toString());
2573 // Check the free constant
2574 CHECK_SOUND(isRational(rhs[0]) && rhs[0].getRational().isInteger(),
2575 "ArithTheoremProducer::eqElimInt: rhs = "+rhs.toString());
2576 // Check the vars
2577 for(size_t i=0, iend=isIntVars.size(); i<iend; ++i) {
2578 Expr c, v;
2579 d_theoryArith->separateMonomial(rhs[i+1], c, v);
2580 const Expr& isInt(isIntVars[i].getExpr());
2581 CHECK_SOUND(isIntPred(isInt) && isInt[0] == v
2582 && isRational(c) && c.getRational().isInteger(),
2583 "ArithTheoremProducer::eqElimInt:\n rhs["+int2string(i+1)
2584 +"] = "+rhs[i+1].toString()
2585 +"\n isInt = "+isInt.toString());
2586 }
2587 }
2588 }
2589
2590 // Creating a fresh bound variable
2591 static int varCount(0);
2592 Expr newVar = d_em->newBoundVarExpr("_int_var", int2string(varCount++));
2593 newVar.setType(intType());
2594 Expr t2 = create_t2(lhs, rhs, newVar);
2595 Expr t3 = create_t3(lhs, rhs, newVar);
2596 vector<Expr> vars;
2597 vars.push_back(newVar);
2598 Expr res = d_em->newClosureExpr(EXISTS, vars,
2599 x.eqExpr(t2) && rat(0).eqExpr(t3));
2600
2601 vector<Theorem> thms(isIntVars);
2602 thms.push_back(isIntx);
2603 thms.push_back(eqn);
2604 Assumptions assump(thms);
2605
2606 if(withProof()) {
2607 vector<Proof> pfs;
2608 pfs.push_back(eqn.getProof());
2609 pfs.push_back(isIntx.getProof());
2610 vector<Theorem>::const_iterator i=isIntVars.begin(), iend=isIntVars.end();
2611 for(; i!=iend; ++i)
2612 pfs.push_back(i->getProof());
2613 pf = newPf("eq_elim_int", eqn.getExpr(), res , pfs);
2614 }
2615
2616 Theorem thm(newTheorem(res, assump, pf));
2617 TRACE("arith eq", "eqElimIntRule => ", thm.getExpr(), " }");
2618 return thm;
2619 }
2620
2621
2622 Theorem
isIntConst(const Expr & e)2623 ArithTheoremProducer::isIntConst(const Expr& e) {
2624 Proof pf;
2625
2626 if(CHECK_PROOFS) {
2627 CHECK_SOUND(isIntPred(e) && e[0].isRational(),
2628 "ArithTheoremProducer::isIntConst(e = "
2629 +e.toString()+")");
2630 }
2631 if(withProof())
2632 pf = newPf("is_int_const", e);
2633 bool isInt = e[0].getRational().isInteger();
2634 return newRWTheorem(e, isInt? d_em->trueExpr() : d_em->falseExpr(), Assumptions::emptyAssump(), pf);
2635 }
2636
2637
2638 Theorem
equalLeaves1(const Theorem & thm)2639 ArithTheoremProducer::equalLeaves1(const Theorem& thm)
2640 {
2641 Proof pf;
2642 const Expr& e = thm.getRHS();
2643
2644 if (CHECK_PROOFS) {
2645 CHECK_SOUND(e[1].getKind() == RATIONAL_EXPR &&
2646 e[1].getRational() == Rational(0) &&
2647 e[0].getKind() == PLUS &&
2648 e[0].arity() == 3 &&
2649 e[0][0].getKind() == RATIONAL_EXPR &&
2650 e[0][0].getRational() == Rational(0) &&
2651 e[0][1].getKind() == MULT &&
2652 e[0][1].arity() == 2 &&
2653 e[0][1][0].getKind() == RATIONAL_EXPR &&
2654 e[0][1][0].getRational() == Rational(-1),
2655 "equalLeaves1");
2656 }
2657 if (withProof())
2658 {
2659 vector<Proof> pfs;
2660 pfs.push_back(thm.getProof());
2661 pf = newPf("equalLeaves1", e, pfs);
2662 }
2663 return newRWTheorem(e, e[0][1][1].eqExpr(e[0][2]), thm.getAssumptionsRef(), pf);
2664 }
2665
2666
2667 Theorem
equalLeaves2(const Theorem & thm)2668 ArithTheoremProducer::equalLeaves2(const Theorem& thm)
2669 {
2670 Proof pf;
2671 const Expr& e = thm.getRHS();
2672
2673 if (CHECK_PROOFS) {
2674 CHECK_SOUND(e[0].getKind() == RATIONAL_EXPR &&
2675 e[0].getRational() == Rational(0) &&
2676 e[1].getKind() == PLUS &&
2677 e[1].arity() == 3 &&
2678 e[1][0].getKind() == RATIONAL_EXPR &&
2679 e[1][0].getRational() == Rational(0) &&
2680 e[1][1].getKind() == MULT &&
2681 e[1][1].arity() == 2 &&
2682 e[1][1][0].getKind() == RATIONAL_EXPR &&
2683 e[1][1][0].getRational() == Rational(-1),
2684 "equalLeaves2");
2685 }
2686 if (withProof())
2687 {
2688 vector<Proof> pfs;
2689 pfs.push_back(thm.getProof());
2690 pf = newPf("equalLeaves2", e, pfs);
2691 }
2692 return newRWTheorem(e, e[1][1][1].eqExpr(e[1][2]), thm.getAssumptionsRef(), pf);
2693 }
2694
2695
2696 Theorem
equalLeaves3(const Theorem & thm)2697 ArithTheoremProducer::equalLeaves3(const Theorem& thm)
2698 {
2699 Proof pf;
2700 const Expr& e = thm.getRHS();
2701
2702 if (CHECK_PROOFS) {
2703 CHECK_SOUND(e[1].getKind() == RATIONAL_EXPR &&
2704 e[1].getRational() == Rational(0) &&
2705 e[0].getKind() == PLUS &&
2706 e[0].arity() == 3 &&
2707 e[0][0].getKind() == RATIONAL_EXPR &&
2708 e[0][0].getRational() == Rational(0) &&
2709 e[0][2].getKind() == MULT &&
2710 e[0][2].arity() == 2 &&
2711 e[0][2][0].getKind() == RATIONAL_EXPR &&
2712 e[0][2][0].getRational() == Rational(-1),
2713 "equalLeaves3");
2714 }
2715 if (withProof())
2716 {
2717 vector<Proof> pfs;
2718 pfs.push_back(thm.getProof());
2719 pf = newPf("equalLeaves3", e, pfs);
2720 }
2721 return newRWTheorem(e, e[0][2][1].eqExpr(e[0][1]), thm.getAssumptionsRef(), pf);
2722 }
2723
2724
2725 Theorem
equalLeaves4(const Theorem & thm)2726 ArithTheoremProducer::equalLeaves4(const Theorem& thm)
2727 {
2728 Proof pf;
2729 const Expr& e = thm.getRHS();
2730
2731 if (CHECK_PROOFS) {
2732 CHECK_SOUND(e[0].getKind() == RATIONAL_EXPR &&
2733 e[0].getRational() == Rational(0) &&
2734 e[1].getKind() == PLUS &&
2735 e[1].arity() == 3 &&
2736 e[1][0].getKind() == RATIONAL_EXPR &&
2737 e[1][0].getRational() == Rational(0) &&
2738 e[1][2].getKind() == MULT &&
2739 e[1][2].arity() == 2 &&
2740 e[1][2][0].getKind() == RATIONAL_EXPR &&
2741 e[1][2][0].getRational() == Rational(-1),
2742 "equalLeaves4");
2743 }
2744 if (withProof())
2745 {
2746 vector<Proof> pfs;
2747 pfs.push_back(thm.getProof());
2748 pf = newPf("equalLeaves4", e, pfs);
2749 }
2750 return newRWTheorem(e, e[1][2][1].eqExpr(e[1][1]), thm.getAssumptionsRef(), pf);
2751 }
2752
2753 Theorem
diseqToIneq(const Theorem & diseq)2754 ArithTheoremProducer::diseqToIneq(const Theorem& diseq) {
2755 Proof pf;
2756
2757 const Expr& e = diseq.getExpr();
2758
2759 if(CHECK_PROOFS) {
2760 CHECK_SOUND(e.isNot() && e[0].isEq(),
2761 "ArithTheoremProducer::diseqToIneq: expected disequality:\n"
2762 " e = "+e.toString());
2763 }
2764
2765 const Expr& x = e[0][0];
2766 const Expr& y = e[0][1];
2767
2768 if(withProof())
2769 pf = newPf(e, diseq.getProof());
2770 return newTheorem(ltExpr(x,y).orExpr(gtExpr(x,y)), diseq.getAssumptionsRef(), pf);
2771 }
2772
moveSumConstantRight(const Expr & e)2773 Theorem ArithTheoremProducer::moveSumConstantRight(const Expr& e) {
2774
2775 // Check soundness of the rule if necessary
2776 if (CHECK_PROOFS) {
2777 CHECK_SOUND(isIneq(e) || e.isEq(), "moveSumConstantRight: input must be Eq or Ineq: " + e.toString());
2778 CHECK_SOUND(isRational(e[0]) || isPlus(e[0]), "moveSumConstantRight: left side must be a canonised sum: " + e.toString());
2779 CHECK_SOUND(isRational(e[1]) && e[1].getRational() == 0, "moveSumConstantRight: right side must be 0: " + e.toString());
2780 }
2781
2782 // The rational constant of the sum
2783 Rational r = 0;
2784
2785 // The right hand side of the expression
2786 Expr right = e[0];
2787
2788 // The vector of sum terms
2789 vector<Expr> sumTerms;
2790
2791 // Get all the non rational children and
2792 if (!right.isRational())
2793 for(Expr::iterator it = right.begin(); it != right.end(); it ++) {
2794 // If the term is rational then add the rational number to r
2795 if ((*it).isRational()) r = r + (*it).getRational();
2796 // Otherwise just add the sumTerm to the sumTerms
2797 else sumTerms.push_back((*it));
2798 }
2799
2800 // Setup the new expression
2801 Expr transformed;
2802 if (sumTerms.size() > 1)
2803 // If the number of summands is > 1 return the sum of them
2804 transformed = Expr(e.getKind(), plusExpr(sumTerms), rat(-r));
2805 else
2806 // Otherwise return the one summand as itself
2807 transformed = Expr(e.getKind(), sumTerms[0], rat(-r));
2808
2809
2810 // If proof is needed set it up
2811 Proof pf;
2812 if (withProof()) pf = newPf("arithm_sum_constant_right", e);
2813
2814 // Retrun the theorem explaining the transformation
2815 return newRWTheorem(e, transformed, Assumptions::emptyAssump(), pf);
2816 }
2817
eqToIneq(const Expr & e)2818 Theorem ArithTheoremProducer::eqToIneq(const Expr& e) {
2819
2820 // Check soundness of the rule if necessary
2821 if (CHECK_PROOFS)
2822 CHECK_SOUND(e.isEq(), "eqToIneq: input must be an equality: " + e.toString());
2823
2824 // The proof object we will use
2825 Proof pf;
2826
2827 // The parts of the equality x = y
2828 const Expr& x = e[0];
2829 const Expr& y = e[1];
2830
2831 // Setup the proof if needed
2832 if (withProof())
2833 pf = newPf("eqToIneq", e);
2834
2835 // Retrun the theorem explaining the transformation
2836 return newRWTheorem(e, leExpr(x,y).andExpr(geExpr(x,y)), Assumptions::emptyAssump(), pf);
2837 }
2838
dummyTheorem(const Expr & e)2839 Theorem ArithTheoremProducer::dummyTheorem(const Expr& e) {
2840 Proof pf;
2841 return newRWTheorem(e, d_em->trueExpr(), Assumptions::emptyAssump(), pf);
2842 }
2843
oneElimination(const Expr & e)2844 Theorem ArithTheoremProducer::oneElimination(const Expr& e) {
2845
2846 // Check soundness
2847 if (CHECK_PROOFS)
2848 CHECK_SOUND(isMult(e) &&
2849 e.arity() == 2 &&
2850 e[0].isRational() &&
2851 e[0].getRational() == 1,
2852 "oneElimination: input must be a multiplication by one" + e.toString());
2853
2854 // The proof object that we will us
2855 Proof pf;
2856
2857 // Setup the proof if needed
2858 if (withProof())
2859 pf = newPf("oneElimination", e);
2860
2861 // Return the rewrite theorem that explains the phenomenon
2862 return newRWTheorem(e, e[1], Assumptions::emptyAssump(), pf);
2863 }
2864
clashingBounds(const Theorem & lowerBound,const Theorem & upperBound)2865 Theorem ArithTheoremProducer::clashingBounds(const Theorem& lowerBound, const Theorem& upperBound) {
2866
2867 // Get the expressions
2868 const Expr& lowerBoundExpr = lowerBound.getExpr();
2869 const Expr& upperBoundExpr = upperBound.getExpr();
2870
2871 // Check soundness
2872 if (CHECK_PROOFS) {
2873 CHECK_SOUND(isLE(lowerBoundExpr) || isLT(lowerBoundExpr), "clashingBounds: lowerBound should be >= or > " + lowerBoundExpr.toString());
2874 CHECK_SOUND(isGE(upperBoundExpr) || isGT(upperBoundExpr), "clashingBounds: upperBound should be <= or < " + upperBoundExpr.toString());
2875 CHECK_SOUND(lowerBoundExpr[0].isRational(), "clashingBounds: lowerBound left side should be a rational " + lowerBoundExpr.toString());
2876 CHECK_SOUND(upperBoundExpr[0].isRational(), "clashingBounds: upperBound left side should be a rational " + upperBoundExpr.toString());
2877 CHECK_SOUND(lowerBoundExpr[1] == upperBoundExpr[1], "clashingBounds: bounds not on the same term " + lowerBoundExpr.toString() + ", " + upperBoundExpr.toString());
2878
2879 // Get the bounds
2880 Rational lowerBoundR = lowerBoundExpr[0].getRational();
2881 Rational upperBoundR = upperBoundExpr[0].getRational();
2882
2883 if (isLE(lowerBoundExpr) && isGE(upperBoundExpr)) {
2884 CHECK_SOUND(upperBoundR < lowerBoundR, "clashingBounds: bounds are satisfiable");
2885 } else {
2886 CHECK_SOUND(upperBoundR <= lowerBoundR, "clashingBounds: bounds are satisfiable");
2887 }
2888 }
2889
2890 // The proof object that we will use
2891 Proof pf;
2892 // Setup the proof if needed
2893 if (withProof())
2894 pf = newPf("clashingBounds", lowerBoundExpr, upperBoundExpr);
2895
2896 // Put the bounds expressions in the assumptions
2897 Assumptions assumptions;
2898 assumptions.add(lowerBound);
2899 assumptions.add(upperBound);
2900
2901 // Return the theorem
2902 return newTheorem(d_em->falseExpr(), assumptions, pf);
2903 }
2904
addInequalities(const Theorem & thm1,const Theorem & thm2)2905 Theorem ArithTheoremProducer::addInequalities(const Theorem& thm1, const Theorem& thm2) {
2906
2907 // Get the expressions of the theorem
2908 const Expr& expr1 = thm1.getExpr();
2909 const Expr& expr2 = thm2.getExpr();
2910
2911 // Check soundness
2912 if (CHECK_PROOFS) {
2913
2914 CHECK_SOUND(isIneq(expr1), "addInequalities: expecting an inequality for thm1, got " + expr1.toString());
2915 CHECK_SOUND(isIneq(expr2), "addInequalities: expecting an inequality for thm2, got " + expr2.toString());
2916
2917 if (isLE(expr1) || isLT(expr1))
2918 CHECK_SOUND(isLE(expr2) || isLT(expr2), "addInequalities: expr2 should be <(=) also " + expr2.toString());
2919 if (isGE(expr1) || isGT(expr1))
2920 CHECK_SOUND(isGE(expr2) || isGT(expr2), "addInequalities: expr2 should be >(=) also" + expr2.toString());
2921 }
2922
2923 // Create the assumptions
2924 Assumptions a(thm1, thm2);
2925
2926 // Get the kinds of the inequalitites
2927 int kind1 = expr1.getKind();
2928 int kind2 = expr2.getKind();
2929
2930 // Set-up the resulting inequality
2931 int kind = (kind1 == kind2) ? kind1 : ((kind1 == LT) || (kind2 == LT))? LT : GT;
2932
2933 // Create the proof object
2934 Proof pf;
2935 if(withProof()) {
2936 vector<Proof> pfs;
2937 pfs.push_back(thm1.getProof());
2938 pfs.push_back(thm2.getProof());
2939 pf = newPf("addInequalities", expr1, expr2, pfs);
2940 }
2941
2942 // Create the new expressions
2943 Expr leftSide = plusExpr(expr1[0], expr2[0]);
2944 Expr rightSide = plusExpr(expr1[1], expr2[1]);
2945
2946 // Return the theorem
2947 return newTheorem(Expr(kind, leftSide, rightSide), a, pf);
2948 }
2949
implyWeakerInequality(const Expr & expr1,const Expr & expr2)2950 Theorem ArithTheoremProducer::implyWeakerInequality(const Expr& expr1, const Expr& expr2) {
2951
2952 // Check soundness
2953 if (CHECK_PROOFS) {
2954
2955 // Both must be inequalitites
2956 CHECK_SOUND(isIneq(expr1), "implyWeakerInequality: expr1 should be an inequality" + expr1.toString());
2957 CHECK_SOUND(isIneq(expr2), "implyWeakerInequality: expr1 should be an inequality" + expr2.toString());
2958
2959 bool type_less_than = true;
2960
2961 // Should be of the same type
2962 if (isLE(expr1) || isLT(expr1))
2963 CHECK_SOUND(isLE(expr2) || isLT(expr2), "implyWeakerInequality: expr2 should be <(=) also " + expr2.toString());
2964 if (isGE(expr1) || isGT(expr1)) {
2965 CHECK_SOUND(isGE(expr2) || isGT(expr2), "implyWeakerInequality: expr2 should be >(=) also" + expr2.toString());
2966 type_less_than = false;
2967 }
2968
2969 // Left sides must be rational numbers
2970 CHECK_SOUND(expr1[0].isRational(), "implyWeakerInequality: expr1 should have a rational on the left side" + expr1.toString());
2971 CHECK_SOUND(expr2[0].isRational(), "implyWeakerInequality: expr2 should have a rational on the left side" + expr2.toString());
2972
2973 // Right sides must be identical
2974 CHECK_SOUND(expr1[1] == expr2[1], "implyWeakerInequality: the expression must be the same" + expr1.toString() + " and " + expr2.toString());
2975
2976 Rational expr1rat = expr1[0].getRational();
2977 Rational expr2rat = expr2[0].getRational();
2978
2979
2980 // Check the bounds
2981 if (type_less_than) {
2982 if (isLE(expr1) || isLT(expr2)) {
2983 CHECK_SOUND(expr2rat < expr1rat, "implyWeakerInequality: the implication doesn't apply" + expr1.toString() + " and " + expr2.toString());
2984 } else {
2985 CHECK_SOUND(expr2rat <= expr1rat, "implyWeakerInequality: the implication doesn't apply" + expr1.toString() + " and " + expr2.toString());
2986 }
2987 } else {
2988 if (isGE(expr1) || isGT(expr2)) {
2989 CHECK_SOUND(expr2rat > expr1rat, "implyWeakerInequality: the implication doesn't apply" + expr1.toString() + " and " + expr2.toString());
2990 } else {
2991 CHECK_SOUND(expr2rat >= expr1rat, "implyWeakerInequality: the implication doesn't apply" + expr1.toString() + " and " + expr2.toString());
2992 }
2993 }
2994 }
2995
2996 // Create the proof object
2997 Proof pf;
2998 if(withProof()) pf = newPf("implyWeakerInequality", expr1, expr2);
2999
3000 // Return the theorem
3001 return newTheorem(expr1.impExpr(expr2), Assumptions::emptyAssump(), pf);
3002 }
3003
implyNegatedInequality(const Expr & expr1,const Expr & expr2)3004 Theorem ArithTheoremProducer::implyNegatedInequality(const Expr& expr1, const Expr& expr2) {
3005
3006 // Check soundness
3007 if (CHECK_PROOFS) {
3008 CHECK_SOUND(isIneq(expr1), "implyNegatedInequality: lowerBound should be an inequality " + expr1.toString());
3009 CHECK_SOUND(isIneq(expr2), "implyNegatedInequality: upperBound should be be an inequality " + expr2.toString());
3010 CHECK_SOUND(expr1[0].isRational(), "implyNegatedInequality: lowerBound left side should be a rational " + expr1.toString());
3011 CHECK_SOUND(expr2[0].isRational(), "implyNegatedInequality: upperBound left side should be a rational " + expr2.toString());
3012 CHECK_SOUND(expr1[1] == expr2[1], "implyNegatedInequality: bounds not on the same term " + expr1.toString() + ", " + expr2.toString());
3013
3014 // Get the bounds
3015 Rational lowerBoundR = expr1[0].getRational();
3016 Rational upperBoundR = expr2[0].getRational();
3017
3018 if (isLE(expr1) && isGE(expr2))
3019 CHECK_SOUND(upperBoundR < lowerBoundR, "implyNegatedInequality: cant imply negation" + expr1.toString() + ", " + expr2.toString());
3020 if (isLT(expr1) || isGT(expr2))
3021 CHECK_SOUND(upperBoundR <= lowerBoundR, "implyNegatedInequality: cant imply negation" + expr1.toString() + ", " + expr2.toString());
3022 if (isGE(expr1) && isLE(expr2))
3023 CHECK_SOUND(upperBoundR > lowerBoundR, "implyNegatedInequality: cant imply negation" + expr1.toString() + ", " + expr2.toString());
3024 if (isGT(expr1) || isLT(expr2))
3025 CHECK_SOUND(upperBoundR >= lowerBoundR, "implyNegatedInequality: cant imply negation" + expr1.toString() + ", " + expr2.toString());
3026 }
3027
3028 // The proof object that we will use
3029 Proof pf;
3030 if (withProof()) pf = newPf("implyNegatedInequality", expr1, expr2);
3031
3032 // Return the theorem
3033 return newTheorem(expr1.impExpr(expr2.negate()), Assumptions::emptyAssump(), pf);
3034 }
3035
trustedRewrite(const Expr & expr1,const Expr & expr2)3036 Theorem ArithTheoremProducer::trustedRewrite(const Expr& expr1, const Expr& expr2) {
3037
3038 // The proof object that we will us
3039 Proof pf;
3040
3041 // Setup the proof if needed
3042 if (withProof()) pf = newPf("trustedRewrite", expr1, expr2);
3043
3044 // Return the rewrite theorem that explains the phenomenon
3045 return newRWTheorem(expr1, expr2, Assumptions::emptyAssump(), pf);
3046
3047 }
3048
integerSplit(const Expr & intVar,const Rational & intPoint)3049 Theorem ArithTheoremProducer::integerSplit(const Expr& intVar, const Rational& intPoint) {
3050
3051 // Check soundness
3052 if (CHECK_PROOFS) {
3053 CHECK_SOUND(intPoint.isInteger(), "integerSplit: we can only split on integer points, given" + intPoint.toString());
3054 }
3055
3056 // Create the expression
3057 const Expr& split = Expr(IS_INTEGER, intVar).impExpr(leExpr(intVar, rat(intPoint)).orExpr(geExpr(intVar, rat(intPoint + 1))));
3058
3059 // The proof object that we will use
3060 Proof pf;
3061 if (withProof()) pf = newPf("integerSplit", intVar, rat(intPoint));
3062
3063 // Return the theorem
3064 return newTheorem(split, Assumptions::emptyAssump(), pf);
3065 }
3066
3067
rafineStrictInteger(const Theorem & isIntConstrThm,const Expr & constr)3068 Theorem ArithTheoremProducer::rafineStrictInteger(const Theorem& isIntConstrThm, const Expr& constr) {
3069
3070
3071 // Check soundness
3072 if (CHECK_PROOFS) {
3073 // Right side of the constraint should correspond to the proved integer expression
3074 CHECK_SOUND(isIneq(constr), "rafineStrictInteger: expected a constraint got : " + constr.toString());
3075 CHECK_SOUND(isIntConstrThm.getExpr()[0] == constr[1], "rafineStrictInteger: proof of intger doesn't correspond to the constarint right side");
3076 CHECK_SOUND(constr[0].isRational(), "rafineStrictInteger: right side of the constraint muts be a rational");
3077 }
3078
3079 // Get the contraint bound
3080 Rational bound = constr[0].getRational();
3081
3082 // Get the kind of the constraint
3083 int kind = constr.getKind();
3084
3085 // If the bound is strict, make it non-strict
3086 switch (kind) {
3087 case LT:
3088 kind = LE;
3089 if (bound.isInteger()) bound ++; // 3 < x --> 4 <= x
3090 else bound = ceil(bound); // 3.4 < x --> 4 <= x
3091 break;
3092 case LE:
3093 kind = LE;
3094 if (!bound.isInteger()) bound = ceil(bound); // 3.5 <= x --> 4 <= x
3095 break;
3096 case GT:
3097 kind = GE;
3098 if (bound.isInteger()) bound --; // 3 > x --> 2 >= x
3099 else bound = floor(bound); // 3.4 > x --> 3 >= x
3100 break;
3101 case GE:
3102 kind = GE;
3103 if (!bound.isInteger()) bound = floor(bound); // 3.4 >= x --> 3 >= x
3104 break;
3105 }
3106
3107 // The new constraint
3108 Expr newConstr(kind, rat(bound), constr[1]);
3109
3110 // Pick up the assumptions from the integer proof
3111 const Assumptions& assump(isIntConstrThm.getAssumptionsRef());
3112
3113 // Construct the proof object if necessary
3114 Proof pf;
3115 if (withProof()) pf = newPf("rafineStrictInteger", constr, newConstr,isIntConstrThm.getProof());
3116
3117 // Return the rewrite theorem that explains the phenomenon
3118 return newRWTheorem(constr, newConstr, assump, pf);
3119 }
3120
3121 //
3122 // This one is here just to compile... the code is in old arithmetic
simpleIneqInt(const Expr & ineq,const Theorem & isIntRHS)3123 Theorem ArithTheoremProducer::simpleIneqInt(const Expr& ineq, const Theorem& isIntRHS)
3124 {
3125 DebugAssert(false, "Not implemented!!!");
3126 return Theorem();
3127 }
3128
3129 // Given:
3130 // 0 = c + t
3131 // where t is integer and c is not
3132 // deduce bot
intEqualityRationalConstant(const Theorem & isIntConstrThm,const Expr & constr)3133 Theorem ArithTheoremProducer::intEqualityRationalConstant(const Theorem& isIntConstrThm, const Expr& constr) {
3134 DebugAssert(false, "Not implemented!!!");
3135 return Theorem();
3136 }
3137
cycleConflict(const vector<Theorem> & inequalitites)3138 Theorem ArithTheoremProducer::cycleConflict(const vector<Theorem>& inequalitites) {
3139 DebugAssert(false, "Not implemented!!!");
3140 return Theorem();
3141 }
3142
implyEqualities(const vector<Theorem> & inequalitites)3143 Theorem ArithTheoremProducer::implyEqualities(const vector<Theorem>& inequalitites) {
3144 DebugAssert(false, "Not implemented!!!");
3145 return Theorem();
3146 }
3147
3148 /*! Takes a Theorem(\\alpha < \\beta) and returns
3149 * Theorem(\\alpha < \\beta <==> \\alpha <= \\beta -1)
3150 * where \\alpha and \\beta are integer expressions
3151 */
lessThanToLERewrite(const Expr & ineq,const Theorem & isIntLHS,const Theorem & isIntRHS,bool changeRight)3152 Theorem ArithTheoremProducer::lessThanToLERewrite(const Expr& ineq,
3153 const Theorem& isIntLHS,
3154 const Theorem& isIntRHS,
3155 bool changeRight) {
3156
3157 const Expr& isIntLHSexpr = isIntLHS.getExpr();
3158 const Expr& isIntRHSexpr = isIntRHS.getExpr();
3159
3160 if(CHECK_PROOFS) {
3161 CHECK_SOUND(isLT(ineq), "ArithTheoremProducerOld::LTtoLE: ineq must be <");
3162 // Integrality check
3163 CHECK_SOUND(isIntPred(isIntLHSexpr) && isIntLHSexpr[0] == ineq[0],
3164 "ArithTheoremProducerOld::lessThanToLE: bad integrality check:\n"
3165 " ineq = "+ineq.toString()+"\n isIntLHS = "
3166 +isIntLHSexpr.toString());
3167 CHECK_SOUND(isIntPred(isIntRHSexpr) && isIntRHSexpr[0] == ineq[1],
3168 "ArithTheoremProducerOld::lessThanToLE: bad integrality check:\n"
3169 " ineq = "+ineq.toString()+"\n isIntRHS = "
3170 +isIntRHSexpr.toString());
3171 }
3172
3173 vector<Theorem> thms;
3174 thms.push_back(isIntLHS);
3175 thms.push_back(isIntRHS);
3176 Assumptions a(thms);
3177 Proof pf;
3178 Expr le = changeRight? leExpr(ineq[0], ineq[1] + rat(-1)) : leExpr(ineq[0] + rat(1), ineq[1]);
3179 if(withProof()) {
3180 vector<Proof> pfs;
3181 pfs.push_back(isIntLHS.getProof());
3182 pfs.push_back(isIntRHS.getProof());
3183 pf = newPf(changeRight? "lessThan_To_LE_rhs_rwr" : "lessThan_To_LE_lhs_rwr", ineq, le, pfs);
3184 }
3185
3186 return newRWTheorem(ineq, le, a, pf);
3187 }
3188
3189
splitGrayShadowSmall(const Theorem & gThm)3190 Theorem ArithTheoremProducer::splitGrayShadowSmall(const Theorem& gThm) {
3191 DebugAssert(false, "Not implemented!!!");
3192 return Theorem();
3193 }
3194
implyWeakerInequalityDiffLogic(const std::vector<Theorem> & antecedentThms,const Expr & implied)3195 Theorem ArithTheoremProducer::implyWeakerInequalityDiffLogic(const std::vector<Theorem>& antecedentThms, const Expr& implied) {
3196 DebugAssert(false, "Not implemented!!!");
3197 return Theorem();
3198 }
3199
implyNegatedInequalityDiffLogic(const std::vector<Theorem> & antecedentThms,const Expr & implied)3200 Theorem ArithTheoremProducer::implyNegatedInequalityDiffLogic(const std::vector<Theorem>& antecedentThms, const Expr& implied) {
3201 DebugAssert(false, "Not implemented!!!");
3202 return Theorem();
3203 }
3204
expandGrayShadowRewrite(const Expr & theShadow)3205 Theorem ArithTheoremProducer::expandGrayShadowRewrite(const Expr& theShadow) {
3206 DebugAssert(false, "Not implemented!!!");
3207 return Theorem();
3208 }
3209
compactNonLinearTerm(const Expr & nonLinear)3210 Theorem ArithTheoremProducer::compactNonLinearTerm(const Expr& nonLinear) {
3211 DebugAssert(false, "Not implemented!!!");
3212 return Theorem();
3213 }
3214
nonLinearIneqSignSplit(const Theorem & ineqThm)3215 Theorem ArithTheoremProducer::nonLinearIneqSignSplit(const Theorem& ineqThm) {
3216 DebugAssert(false, "Not implemented!!!");
3217 return Theorem();
3218 }
3219
implyDiffLogicBothBounds(const Expr & x,std::vector<Theorem> & c1_le_x,Rational c1,std::vector<Theorem> & x_le_c2,Rational c2)3220 Theorem ArithTheoremProducer::implyDiffLogicBothBounds(const Expr& x,
3221 std::vector<Theorem>& c1_le_x, Rational c1,
3222 std::vector<Theorem>& x_le_c2, Rational c2) {
3223 DebugAssert(false, "Not implemented!!!");
3224 return Theorem();
3225 }
3226
addInequalities(const vector<Theorem> & thms)3227 Theorem ArithTheoremProducer::addInequalities(const vector<Theorem>& thms) {
3228 DebugAssert(false, "Not implemented!!!");
3229 return Theorem();
3230 }
3231
powerOfOne(const Expr & e)3232 Theorem ArithTheoremProducer::powerOfOne(const Expr& e) {
3233 DebugAssert(false, "Not implemented!!!");
3234 return Theorem();
3235 }
3236
3237
3238 ////////////////////////////////////////////////////////////////////
3239 // Stubs for ArithProofRules
3240 ////////////////////////////////////////////////////////////////////
3241
3242
rewriteLeavesConst(const Expr & e)3243 Theorem ArithProofRules::rewriteLeavesConst(const Expr& e) {
3244 DebugAssert(false, "Not implemented!!!");
3245 return Theorem();
3246 }
3247