/*****************************************************************************/
/*!
* \file theory_arith.cpp
*
* Author: Clark Barrett, Vijay Ganesh.
*
* Created: Fri Jan 17 18:39:18 2003
*
*
*
* License to use, copy, modify, sell and/or distribute this software
* and its documentation for any purpose is hereby granted without
* royalty, subject to the terms and conditions defined in the \ref
* LICENSE file provided with this distribution.
*
*
*
*/
/*****************************************************************************/
#include "theory_arith.h"
#include "theory_core.h"
#include "translator.h"
using namespace std;
using namespace CVC3;
Theorem TheoryArith::canonRec(const Expr& e)
{
if (isLeaf(e)) return reflexivityRule(e);
int ar = e.arity();
if (ar > 0) {
vector newChildrenThm;
vector changed;
for(int k = 0; k < ar; ++k) {
// Recursively canonize the kids
Theorem thm = canonRec(e[k]);
if (thm.getLHS() != thm.getRHS()) {
newChildrenThm.push_back(thm);
changed.push_back(k);
}
}
if(changed.size() > 0) {
return canonThm(substitutivityRule(e, changed, newChildrenThm));
}
}
return canon(e);
}
void TheoryArith::printRational(ExprStream& os, const Rational& r,
bool printAsReal)
{
// Print rational
if (r.isInteger()) {
if (r < 0) {
os << "(" << push << "-" << space << (-r).toString();
if (printAsReal) os << ".0";
os << push << ")";
}
else {
os << r.toString();
if (printAsReal) os << ".0";
}
}
else {
os << "(" << push << "/ ";
Rational tmp = r.getNumerator();
if (tmp < 0) {
os << "(" << push << "-" << space << (-tmp).toString();
if (printAsReal) os << ".0";
os << push << ")";
}
else {
os << tmp.toString();
if (printAsReal) os << ".0";
}
os << space;
tmp = r.getDenominator();
DebugAssert(tmp > 0 && tmp.isInteger(), "Unexpected rational denominator");
os << tmp.toString();
if (printAsReal) os << ".0";
os << push << ")";
}
}
bool TheoryArith::isAtomicArithTerm(const Expr& e)
{
switch (e.getKind()) {
case RATIONAL_EXPR:
return true;
case ITE:
return false;
case UMINUS:
case PLUS:
case MINUS:
case MULT:
case DIVIDE:
case POW:
case INTDIV:
case MOD: {
int i=0, iend=e.arity();
for(; i!=iend; ++i) {
if (!isAtomicArithTerm(e[i])) return false;
}
break;
}
default:
break;
}
return true;
}
bool TheoryArith::isAtomicArithFormula(const Expr& e)
{
switch (e.getKind()) {
case LT:
case GT:
case LE:
case GE:
case EQ:
return isAtomicArithTerm(e[0]) && isAtomicArithTerm(e[1]);
}
return false;
}
bool TheoryArith::isSyntacticRational(const Expr& e, Rational& r)
{
if (e.getKind() == REAL_CONST) {
r = e[0].getRational();
return true;
}
else if (e.isRational()) {
r = e.getRational();
return true;
}
else if (isUMinus(e)) {
if (isSyntacticRational(e[0], r)) {
r = -r;
return true;
}
}
else if (isDivide(e)) {
Rational num;
if (isSyntacticRational(e[0], num)) {
Rational den;
if (isSyntacticRational(e[1], den)) {
if (den != 0) {
r = num / den;
return true;
}
}
}
}
return false;
}
Expr TheoryArith::rewriteToDiff(const Expr& e)
{
Expr tmp = e[0] - e[1];
tmp = canonRec(tmp).getRHS();
switch (tmp.getKind()) {
case RATIONAL_EXPR: {
Rational r = tmp.getRational();
switch (e.getKind()) {
case LT:
if (r < 0) return trueExpr();
else return falseExpr();
case LE:
if (r <= 0) return trueExpr();
else return falseExpr();
case GT:
if (r > 0) return trueExpr();
else return falseExpr();
case GE:
if (r >= 0) return trueExpr();
else return falseExpr();
case EQ:
if (r == 0) return trueExpr();
else return falseExpr();
}
}
case MULT:
DebugAssert(tmp[0].isRational(), "Unexpected term structure from canon");
if (tmp[0].getRational() != -1) return e;
return Expr(e.getOp(), theoryCore()->getTranslator()->zeroVar() - tmp[1], rat(0));
case PLUS: {
DebugAssert(tmp[0].isRational(), "Unexpected term structure from canon");
Rational c = tmp[0].getRational();
Expr x, y;
if (tmp.arity() == 2) {
if (tmp[1].getKind() == MULT) {
x = theoryCore()->getTranslator()->zeroVar();
y = tmp[1];
}
else {
x = tmp[1];
y = rat(-1) * theoryCore()->getTranslator()->zeroVar();
}
}
else if (tmp.arity() == 3) {
if (tmp[1].getKind() == MULT) {
x = tmp[2];
y = tmp[1];
}
else if (tmp[2].getKind() == MULT) {
x = tmp[1];
y = tmp[2];
}
else return e;
}
else return e;
if (x.getKind() == MULT) return e;
DebugAssert(y[0].isRational(), "Unexpected term structure from canon");
if (y[0].getRational() != -1) return e;
return Expr(e.getOp(), x - y[1], getEM()->newRatExpr(-c));
}
default:
return Expr(e.getOp(), tmp - theoryCore()->getTranslator()->zeroVar(), rat(0));
break;
}
return e;
}
Theorem TheoryArith::canonSimp(const Expr& e)
{
DebugAssert(canonRec(e).getRHS() == e, "canonSimp expects input to be canonized");
int ar = e.arity();
if (isLeaf(e)) return find(e);
if (ar > 0) {
vector newChildrenThm;
vector changed;
Theorem thm;
for (int k = 0; k < ar; ++k) {
thm = canonSimp(e[k]);
if (thm.getLHS() != thm.getRHS()) {
newChildrenThm.push_back(thm);
changed.push_back(k);
}
}
if(changed.size() > 0)
return canonThm(substitutivityRule(e, changed, newChildrenThm));
}
return reflexivityRule(e);
}
bool TheoryArith::recursiveCanonSimpCheck(const Expr& e)
{
if (e.hasFind()) return true;
if (e != canonSimp(e).getRHS()) return false;
Expr::iterator i = e.begin(), iend = e.end();
for (; i != iend; ++i)
if (!recursiveCanonSimpCheck(*i)) return false;
return true;
}