#include "Lib/Environment.hpp"
#include "Lib/Int.hpp"
#include "Signature.hpp"
#include "Term.hpp"
#include "Theory.hpp"
#include "NumTraits.hpp"
#include "InterpretedLiteralEvaluator.hpp"
#if VDEBUG
#define _DEBUG(...)
#define DEBUG(...)
#else
#define DEBUG(...)
#define _DEBUG(...)
#endif
namespace Kernel
{
using namespace std;
using namespace Lib;
struct PredEvalResult {
enum status_t {
Simplified,
Trivial,
Nop,
} status;
union {
bool trivial_val;
Literal* simplified_val;
};
static PredEvalResult nop() {return PredEvalResult(Nop); }
static PredEvalResult trivial(bool value) {return PredEvalResult (value); }
static PredEvalResult simplified(Literal* value) {return PredEvalResult (value); }
private:
explicit PredEvalResult(bool value) : status(Trivial), trivial_val(value) {}
explicit PredEvalResult(Literal* value) : status(Simplified), simplified_val(value) {}
explicit PredEvalResult(status_t stat) : status(stat) {}
};
class InterpretedLiteralEvaluator::Evaluator
{
public:
virtual ~Evaluator() {}
virtual bool canEvaluateFunc(unsigned func) { return false; }
virtual bool canEvaluatePred(unsigned pred) { return false; }
virtual bool tryEvaluateFunc(Term* trm, TermList& res) { return false; }
virtual PredEvalResult tryEvaluatePred(Literal* trm) { return PredEvalResult::nop(); }
};
template<class Fn, class Predicate>
void stackTraverseIf(TermList term, Predicate pred, Fn action) {
Stack<TermList> todo;
todo.push(term);
while(!todo.isEmpty()){
TermList t = todo.pop();
if(t.isTerm()) {
auto& trm = *t.term();
if (pred(trm)) {
for (unsigned i = 0; i < trm.numTermArguments(); i++) {
todo.push(trm[i]);
}
} else {
action(t);
}
} else {
action(t);
}
}
}
template<class AbelianGroup>
class InterpretedLiteralEvaluator::ACFunEvaluator
: public Evaluator
{
public:
using ConstantType = typename AbelianGroup::ConstantType;
ACFunEvaluator() : _fun(env.signature->getInterpretingSymbol(AbelianGroup::interpretation)) { }
const unsigned _fun;
bool canEvaluateFunc(unsigned func) override { return func == _fun; }
bool tryEvaluateFunc(Term* trm, TermList& res) override {
ASS_EQ(trm->functor(), _fun);
ASS_EQ(trm->numTermArguments(),2);
unsigned nums = 0;
ConstantType acc = AbelianGroup::IDENTITY;
Stack<TermList> keep;
stackTraverseIf(TermList(trm),
[&](Term& t){ return t.functor() == _fun; },
[&](TermList t) {
ConstantType c;
if (t.isTerm() && theory->tryInterpretConstant(t.term(), c)) {
acc = AbelianGroup::groundEval(acc, c);
nums++;
} else {
keep.push(t);
}
});
if (nums == 0 || (nums == 1 && acc != AbelianGroup::IDENTITY)) {
return false;
}
if (acc != AbelianGroup::IDENTITY) {
keep.push(TermList(theory->representConstant(acc)));
}
auto iter = Stack<TermList>::BottomFirstIterator(keep);
if (!iter.hasNext()) {
res = TermList(theory->representConstant(AbelianGroup::IDENTITY));
return TermList(trm) != res;
} else {
TermList out = iter.next();
while (iter.hasNext()) {
auto t = iter.next();
out = TermList(Term::create2(_fun, t, out));
}
res = out;
return TermList(trm) != res;
}
}
};
template<class Inequality>
class InequalityNormalizer {
public:
static Literal* normalize(Literal* in) {
ASS(in->functor() == Inequality::functor());
if (Inequality::isNormalized(in)) {
return in;
} else {
return Inequality::normalizedLit(
in->polarity(),
in->termArg(0),
in->termArg(1));
}
}
};
template<class ConstantType>
class FracLess {
template<class Inequality> friend class InequalityNormalizer;
using number = NumTraits<ConstantType>;
inline static unsigned functor() { return number::lessF(); }
static Literal* normalizedLit(bool polarity, TermList lhs, TermList rhs) {
static auto zero = TermList(number::zeroT());
return number::less(
polarity,
zero,
number::add(rhs, number::minus(lhs)));
}
inline static bool isNormalized(Literal* in) {
return number::isZero(in->termArg(0));
}
};
class IntLess {
template<class Inequality> friend class InequalityNormalizer;
using number = NumTraits<IntegerConstantType>;
inline static unsigned functor() { return number::lessF(); }
static Literal* normalizedLit(bool polarity, TermList lhs, TermList rhs) {
static auto one = TermList(number::oneT());
static auto zero = TermList(number::zeroT());
if (polarity) {
return number::less(
true,
zero,
number::add(rhs, number::minus(lhs)));
} else {
return number::less(
true,
zero,
number::add(number::add(lhs, one), number::minus(rhs)));
}
}
inline static bool isNormalized(Literal* in) {
return number::isZero(in->termArg(0)) && in->polarity();
}
};
class InterpretedLiteralEvaluator::EqualityEvaluator
: public Evaluator
{
bool canEvaluatePred(unsigned pred) override {
return Signature::isEqualityPredicate(pred);
}
template<typename T>
bool checkEquality(Literal* lit, bool& res)
{
T arg1;
if(!theory->tryInterpretConstant(lit->termArg(0).term(),arg1)){
return false;
}
T arg2;
if(!theory->tryInterpretConstant(lit->termArg(1).term(),arg2)){
return false;
}
res = (arg1 == arg2);
return true;
}
PredEvalResult tryEvaluatePred(Literal* lit_) override
{
auto& lit = *lit_;
ASS(lit.isEquality());
TermList l = lit[0];
TermList r = lit[1];
if (l == r) {
return PredEvalResult::trivial(lit.polarity());
} else {
if (theory->isInterpretedNumber(l) && theory->isInterpretedNumber(r)) {
return PredEvalResult::trivial(!lit.polarity());
} else {
return PredEvalResult::nop();
}
}
}
};
class InterpretedLiteralEvaluator::ConversionEvaluator
: public Evaluator
{
public:
bool canEvaluateFunc(unsigned func) override
{
if (!theory->isInterpretedFunction(func)) {
return false;
}
return theory->isConversionOperation(theory->interpretFunction(func));
}
bool tryEvaluateFunc(Term* trm, TermList& res) override
{
ASS(theory->isInterpretedFunction(trm));
try {
Interpretation itp = theory->interpretFunction(trm);
ASS(theory->isFunction(itp));
ASS(theory->isConversionOperation(itp));
ASS_EQ(theory->getArity(itp), 1);
TermList argTrm = trm->termArg(0);
switch(itp) {
case Theory::INT_TO_RAT:
{
IntegerConstantType arg;
if (!theory->tryInterpretConstant(argTrm, arg)) {
return false;
}
RationalConstantType resNum(arg,IntegerConstantType(1));
res = TermList(theory->representConstant(resNum));
return true;
}
case Theory::INT_TO_REAL:
{
IntegerConstantType arg;
if (!theory->tryInterpretConstant(argTrm, arg)) {
return false;
}
RealConstantType resNum(RationalConstantType(arg,IntegerConstantType(1)));
res = TermList(theory->representConstant(resNum));
return true;
}
case Theory::RAT_TO_INT:
{
RationalConstantType arg;
if (!theory->tryInterpretConstant(argTrm, arg)) {
return false;
}
IntegerConstantType resNum = arg.floor();
res = TermList(theory->representConstant(resNum));
return true;
}
case Theory::RAT_TO_REAL:
{
RationalConstantType arg;
if (!theory->tryInterpretConstant(argTrm, arg)) {
return false;
}
RealConstantType resNum(arg);
res = TermList(theory->representConstant(resNum));
return true;
}
case Theory::REAL_TO_INT:
{
RealConstantType arg;
if (!theory->tryInterpretConstant(argTrm, arg)) {
return false;
}
auto resNum = arg.floor();
res = TermList(theory->representConstant(resNum));
return true;
}
case Theory::REAL_TO_RAT:
{
RealConstantType arg;
if (!theory->tryInterpretConstant(argTrm, arg)) {
return false;
}
RationalConstantType resNum(arg);
res = TermList(theory->representConstant(resNum));
return true;
}
default:
ASSERTION_VIOLATION;
}
}
catch(DivByZeroException&)
{
return false;
}
}
};
template<class T>
class InterpretedLiteralEvaluator::TypedEvaluator : public Evaluator
{
public:
using Value = T;
using number = NumTraits<Value>;
TypedEvaluator() {}
bool isZero(T arg) const { return T(0) == arg; }
TermList getZero() const {return number::zero(); }
bool isOne(T arg) const { return T(1) == arg; }
bool isMinusOne(T arg) const { return typename number::ConstantType(-1) == arg; }
TermList invert(TermList t) const { return number::minus(t); }
bool isAddition(Interpretation interp) const { return interp == number::addI; }
bool isProduct(Interpretation interp) const { return interp == number::mulI; }
virtual bool isDivision(Interpretation interp) const = 0;
virtual bool canEvaluate(Interpretation interp)
{
if (!theory->hasSingleSort(interp)) { return false; }
if (theory->isPolymorphic(interp)) { return false; }
TermList opSort = theory->getOperationSort(interp);
return opSort==T::getSort();
}
bool tryEvaluateFunc(Term* trm, TermList& res) override
{
ASS(theory->isInterpretedFunction(trm));
const auto num = NumTraits<Value>{};
_DEBUG( "try evaluate ", trm->toString() );
try {
Interpretation itp = theory->interpretFunction(trm);
ASS(theory->isFunction(itp));
unsigned arity = theory->getArity(itp);
if (arity!=1 && arity!=2) {
INVALID_OPERATION("unsupported arity of interpreted operation: "+Int::toString(arity));
}
T resNum;
TermList arg1Trm = trm->termArg(0);
T arg1;
if (arity==1) {
if (theory->tryInterpretConstant(arg1Trm, arg1)){
if (!tryEvaluateUnaryFunc(itp, arg1, resNum)) { return false;}
} else if (itp == num.minusI){
const unsigned umin = trm->functor();
return trySimplifyUnaryMinus(umin, arg1Trm, res);
} else{
return false;
}
}
else if(arity==2){
T arg2;
TermList arg2Trm = trm->termArg(1);
bool specialCase = true;
T conArg;
TermList nonConTerm;
if (theory->tryInterpretConstant(arg1Trm, arg1) && (isZero(arg1) || isOne(arg1) || isMinusOne(arg1)) &&
!theory->tryInterpretConstant(arg2Trm, arg2)) {
conArg = arg1;
nonConTerm = arg2Trm;
}
else if(theory->tryInterpretConstant(arg2Trm, arg2) && (isZero(arg2) || isOne(arg2) || isMinusOne(arg2)) &&
!theory->tryInterpretConstant(arg1Trm, arg1)) {
conArg = arg2;
nonConTerm = arg1Trm;
}
else{
specialCase = false;
}
if(specialCase){
_DEBUG( "special case" );
if(theory->tryInterpretConstant(arg2Trm, arg2) && isOne(arg2) && isDivision(itp)){
res = arg1Trm;
return true;
}
if(isZero(conArg) && isAddition(itp)){
res = nonConTerm;
return true;
}
if(isOne(conArg) && isProduct(itp)){
res = nonConTerm;
return true;
}
if(isMinusOne(conArg) && isProduct(itp)){
res = invert(nonConTerm);
return true;
}
if(isZero(conArg) && isProduct(itp)){
res = getZero();
return true;
}
}
if(theory->tryInterpretConstant(arg1Trm, arg1) && theory->tryInterpretConstant(arg2Trm, arg2)){
if (!tryEvaluateBinaryFunc(itp, arg1, arg2, resNum)) { return false;}
}
else{ return false;}
}
res = TermList(theory->representConstant(resNum));
return true;
}
catch(DivByZeroException&)
{
return false;
}
}
PredEvalResult tryEvaluatePred(Literal* lit) override
{
ASS(theory->isInterpretedPredicate(lit->functor()));
bool res;
try {
Interpretation itp = theory->interpretPredicate(lit);
ASS(!theory->isFunction(itp));
unsigned arity = theory->getArity(itp);
if (arity!=1 && arity!=2) {
INVALID_OPERATION("unsupported arity of interpreted operation: "+Int::toString(arity));
}
TermList arg1Trm = lit->termArg(0);
T arg1;
if (!theory->tryInterpretConstant(arg1Trm, arg1)) { return PredEvalResult::nop(); }
if (arity==1) {
if (!tryEvaluateUnaryPred(itp, arg1, res)) { return PredEvalResult::nop();}
}
else {
TermList arg2Trm = lit->termArg(1);
T arg2;
if (!theory->tryInterpretConstant(arg2Trm, arg2)) { return PredEvalResult::nop(); }
if (!tryEvaluateBinaryPred(itp, arg1, arg2, res)) { return PredEvalResult::nop();}
}
if (lit->isNegative()) {
res = !res;
}
return PredEvalResult::trivial(res);
}
catch(DivByZeroException&)
{
return PredEvalResult::nop();
}
}
bool canEvaluateFunc(unsigned func) override
{
if (!theory->isInterpretedFunction(func)) {
return false;
}
Interpretation interp = theory->interpretFunction(func);
return canEvaluate(interp);
}
bool canEvaluatePred(unsigned pred) override
{
if (!theory->isInterpretedPredicate(pred)) {
return false;
}
Interpretation interp = theory->interpretPredicate(pred);
return canEvaluate(interp);
}
protected:
bool trySimplifyUnaryMinus(const unsigned& uminus_functor, const TermList& inner, TermList& result)
{
DEBUG("trySimplifyUnaryMinus(uminus(", inner, "))")
ASS_EQ(uminus_functor, env.signature->getInterpretingSymbol(number::minusI));
if (inner.isTerm()) {
auto& t = *inner.term();
if (theory->isInterpretedFunction(t.functor())) {
auto itp = theory->interpretFunction(t.functor());
switch (itp) {
case number::minusI:
ASS_EQ(t.numTermArguments(), 1);
result = t[0];
return true;
default:
return false;
}
} else {
Value cons;
if (theory->tryInterpretConstant(&t, cons)) {
result = TermList(theory->representConstant(-cons));
return true;
} else {
return false;
}
}
} else {
return false;
}
}
TermList simplifyUnaryMinus(const unsigned& uminus_functor, const TermList& inner)
{
TermList out;
if (trySimplifyUnaryMinus(uminus_functor, inner, out)) {
return out;
} else {
return TermList(Term::create1(uminus_functor, inner));
}
}
virtual bool tryEvaluateUnaryFunc(Interpretation op, const T& arg, T& res)
{ return false; }
virtual bool tryEvaluateBinaryFunc(Interpretation op, const T& arg1, const T& arg2, T& res)
{ return false; }
virtual bool tryEvaluateUnaryPred(Interpretation op, const T& arg1, bool& res)
{ return false; }
virtual bool tryEvaluateBinaryPred(Interpretation op, const T& arg1, const T& arg2, bool& res)
{ return false; }
};
class InterpretedLiteralEvaluator::IntEvaluator : public TypedEvaluator<IntegerConstantType>
{
protected:
bool isDivision(Interpretation interp) const override {
return interp==Theory::INT_QUOTIENT_E || interp==Theory::INT_QUOTIENT_T ||
interp==Theory::INT_QUOTIENT_F;
}
bool tryEvaluateUnaryFunc(Interpretation op, const Value& arg, Value& res) override
{
switch(op) {
case Theory::INT_UNARY_MINUS:
res = -arg;
return true;
case Theory::INT_ABS:
if (arg < IntegerConstantType(0)) {
res = -arg;
} else {
res = arg;
}
return true;
case Theory::INT_SUCCESSOR:
res = arg+ IntegerConstantType(1);
return true;
case Theory::INT_FLOOR:
case Theory::INT_CEILING:
case Theory::INT_TRUNCATE:
case Theory::INT_ROUND:
res = arg;
return true;
default:
return false;
}
}
bool tryEvaluateBinaryFunc(Interpretation op, const Value& arg1,
const Value& arg2, Value& res) override
{
switch(op) {
case Theory::INT_PLUS:
res = arg1+arg2;
return true;
case Theory::INT_MINUS:
res = arg1-arg2;
return true;
case Theory::INT_MULTIPLY:
res = arg1*arg2;
return true;
case Theory::INT_QUOTIENT_E:
if (arg2 == 0) return false;
res = arg1.quotientE(arg2); return true;
case Theory::INT_QUOTIENT_T:
if (arg2 == 0) return false;
res = arg1.quotientT(arg2);
return true;
case Theory::INT_QUOTIENT_F:
if (arg2 == 0) return false;
res = arg1.quotientF(arg2);
return true;
case Theory::INT_REMAINDER_E:
if (arg2 == 0) return false;
res = arg1.remainderE(arg2);
return true;
case Theory::INT_REMAINDER_T:
if (arg2 == 0) return false;
res = arg1 - (arg1.quotientT(arg2)*arg2);
return true;
case Theory::INT_REMAINDER_F:
if (arg2 == 0) return false;
res = arg1 - (arg1.quotientF(arg2)*arg2);
return true;
default:
return false;
}
}
bool tryEvaluateBinaryPred(Interpretation op, const Value& arg1,
const Value& arg2, bool& res) override
{
switch(op) {
case Theory::INT_GREATER:
res = arg1>arg2;
return true;
case Theory::INT_GREATER_EQUAL:
res = arg1>=arg2;
return true;
case Theory::INT_LESS:
res = arg1<arg2;
return true;
case Theory::INT_LESS_EQUAL:
res = arg1<=arg2;
return true;
case Theory::INT_DIVIDES:
res = arg1.divides(arg2);
return true;
default:
return false;
}
}
};
class InterpretedLiteralEvaluator::RatEvaluator : public TypedEvaluator<RationalConstantType>
{
protected:
bool isDivision(Interpretation interp) const override {
return interp==Theory::RAT_QUOTIENT || interp==Theory::RAT_QUOTIENT_E ||
interp==Theory::RAT_QUOTIENT_T || interp==Theory::RAT_QUOTIENT_F;
}
bool tryEvaluateUnaryFunc(Interpretation op, const Value& arg, Value& res) override
{
switch(op) {
case Theory::RAT_UNARY_MINUS:
res = -arg;
return true;
case Theory::RAT_FLOOR:
res = RationalConstantType(arg.floor());
return true;
case Theory::RAT_CEILING:
res = RationalConstantType(arg.ceiling());
return true;
case Theory::RAT_TRUNCATE:
res = RationalConstantType(arg.truncate());
return true;
default:
return false;
}
}
bool tryEvaluateBinaryFunc(Interpretation op, const Value& arg1,
const Value& arg2, Value& res) override
{
switch(op) {
case Theory::RAT_PLUS:
res = arg1+arg2;
return true;
case Theory::RAT_MINUS:
res = arg1-arg2;
return true;
case Theory::RAT_MULTIPLY:
res = arg1*arg2;
return true;
case Theory::RAT_QUOTIENT:
if (arg2 == 0) return false;
res = arg1/arg2;
return true;
default:
return false;
}
}
bool tryEvaluateBinaryPred(Interpretation op, const Value& arg1,
const Value& arg2, bool& res) override
{
switch(op) {
case Theory::RAT_GREATER:
res = arg1>arg2;
return true;
case Theory::RAT_GREATER_EQUAL:
res = arg1>=arg2;
return true;
case Theory::RAT_LESS:
res = arg1<arg2;
return true;
case Theory::RAT_LESS_EQUAL:
res = arg1<=arg2;
return true;
default:
return false;
}
}
bool tryEvaluateUnaryPred(Interpretation op, const Value& arg1,
bool& res) override
{
switch(op) {
case Theory::RAT_IS_INT:
res = arg1.isInt();
return true;
default:
return false;
}
}
};
class InterpretedLiteralEvaluator::RealEvaluator : public TypedEvaluator<RealConstantType>
{
protected:
bool isDivision(Interpretation interp) const override {
return interp==Theory::REAL_QUOTIENT || interp==Theory::REAL_QUOTIENT_E ||
interp==Theory::REAL_QUOTIENT_T || interp==Theory::REAL_QUOTIENT_F;
}
bool tryEvaluateUnaryFunc(Interpretation op, const Value& arg, Value& res) override
{
switch(op) {
case Theory::REAL_UNARY_MINUS:
res = -arg;
return true;
case Theory::REAL_FLOOR:
res = RealConstantType(arg.floor());
return true;
case Theory::REAL_CEILING:
res = RealConstantType(arg.ceiling());
return true;
case Theory::REAL_TRUNCATE:
res = arg.truncate();
return true;
default:
return false;
}
}
bool tryEvaluateBinaryFunc(Interpretation op, const Value& arg1,
const Value& arg2, Value& res) override
{
switch(op) {
case Theory::REAL_PLUS:
res = arg1+arg2;
return true;
case Theory::REAL_MINUS:
res = arg1-arg2;
return true;
case Theory::REAL_MULTIPLY:
res = arg1*arg2;
return true;
case Theory::REAL_QUOTIENT:
if (arg2 == 0) return false;
res = arg1/arg2;
return true;
default:
return false;
}
}
bool tryEvaluateBinaryPred(Interpretation op, const Value& arg1,
const Value& arg2, bool& res) override
{
switch(op) {
case Theory::REAL_GREATER:
res = arg1>arg2;
return true;
case Theory::REAL_GREATER_EQUAL:
res = arg1>=arg2;
return true;
case Theory::REAL_LESS:
res = arg1<arg2;
return true;
case Theory::REAL_LESS_EQUAL:
res = arg1<=arg2;
return true;
default:
return false;
}
}
bool tryEvaluateUnaryPred(Interpretation op, const Value& arg1,
bool& res) override
{
switch(op) {
case Theory::REAL_IS_INT:
res = arg1.isInt();
return true;
case Theory::REAL_IS_RAT:
res = true;
return true;
default:
return false;
}
}
};
template<Theory::Interpretation op>
struct AbelianGroup;
#define IMPL_OPERATOR(oper, type, identity, eval) \
template<> struct AbelianGroup<oper> { \
const static Theory::Interpretation interpretation = oper; \
using ConstantType = type; \
const static type IDENTITY; \
static type groundEval(type l, type r) { return eval; } \
\
}; \
const type AbelianGroup<oper>::IDENTITY = identity; \
IMPL_OPERATOR(Theory::INT_MULTIPLY, IntegerConstantType, IntegerConstantType(1), l * r)
IMPL_OPERATOR(Theory::INT_PLUS, IntegerConstantType, IntegerConstantType(0), l + r)
IMPL_OPERATOR(Theory::RAT_MULTIPLY, RationalConstantType, RationalConstantType(1), l * r)
IMPL_OPERATOR(Theory::RAT_PLUS, RationalConstantType, RationalConstantType(0), l + r)
IMPL_OPERATOR(Theory::REAL_MULTIPLY, RealConstantType, RealConstantType(RationalConstantType(1)), l * r)
IMPL_OPERATOR(Theory::REAL_PLUS, RealConstantType, RealConstantType(RationalConstantType(0)), l + r)
InterpretedLiteralEvaluator::InterpretedLiteralEvaluator(bool doNormalize) : _normalize(doNormalize)
{
_evals.push(new IntEvaluator());
_evals.push(new RatEvaluator());
_evals.push(new RealEvaluator());
_evals.push(new ConversionEvaluator());
_evals.push(new EqualityEvaluator());
if(env.options->useACeval() && !env.options->alasca()){
_evals.push(new ACFunEvaluator<AbelianGroup<Theory::INT_PLUS>>());
_evals.push(new ACFunEvaluator<AbelianGroup<Theory::INT_MULTIPLY>>());
_evals.push(new ACFunEvaluator<AbelianGroup<Theory::RAT_PLUS>>());
_evals.push(new ACFunEvaluator<AbelianGroup<Theory::RAT_MULTIPLY>> ());
_evals.push(new ACFunEvaluator<AbelianGroup<Theory::REAL_PLUS>> ());
_evals.push(new ACFunEvaluator<AbelianGroup<Theory::REAL_MULTIPLY>> ());
}
_funEvaluators.ensure(0);
_predEvaluators.ensure(0);
}
InterpretedLiteralEvaluator::~InterpretedLiteralEvaluator()
{
while (_evals.isNonEmpty()) {
delete _evals.pop();
}
}
bool InterpretedLiteralEvaluator::balancable(Literal* lit)
{
if (!lit->isEquality()) return false;
ASS_EQ(lit->numTermArguments(), 2)
TermList t1 = lit->termArg(0);
TermList t2 = lit->termArg(1);
bool t1Number = theory->isInterpretedNumber(t1);
bool t2Number = theory->isInterpretedNumber(t2);
if(!t1Number && !t2Number){ return false; } if(t1Number && t2Number){ return true; }
if(t1Number){
if(t2.isVar()){ return false;} if(!theory->isInterpretedFunction(t2)){ return false;} }
if(t2Number){
if(t1.isVar()){ return false;} if(!theory->isInterpretedFunction(t1)){ return false;} }
return true;
}
bool InterpretedLiteralEvaluator::balance(Literal* lit,Literal*& resLit)
{
ASS(balancable(lit));
_DEBUG( "try balance ", lit->toString() );
ASS(theory->isInterpretedPredicate(lit->functor()));
bool swap = false;
if(lit->numTermArguments()!=2) return false;
TermList t1;
TermList t2;
if(theory->isInterpretedNumber(lit->termArg(0))){
t1 = lit->termArg(0); t2 = lit->termArg(1);
}else{
t1 = lit->termArg(1); t2 = lit->termArg(0);
swap=true;
}
Signature::Symbol* conSym = env.signature->getFunction(t1.term()->functor());
TermList srt;
if(conSym->integerConstant()) srt = AtomicSort::intSort();
else if(conSym->rationalConstant()) srt = AtomicSort::rationalSort();
else if(conSym->realConstant()) srt = AtomicSort::realSort();
else{
ASSERTION_VIOLATION_REP(t1);
return false; }
bool modified = false;
while(theory->isInterpretedFunction(t2)){
TermList* args = t2.term()->args();
TermList to_unwrap = TermList::empty();
while(args->isNonEmpty()){
if(!theory->isInterpretedNumber(*args)){
if(!to_unwrap.isEmpty()){
return false; }
to_unwrap=*args;
}
args= args->next();
}
if(to_unwrap.isEmpty()){ return false;}
Term* t2term = t2.term();
Interpretation t2interp = theory->interpretFunction(t2term->functor());
TermList result;
bool okay=true;
switch(t2interp){
case Theory::INT_PLUS:
okay=balancePlus(Theory::INT_PLUS,Theory::INT_UNARY_MINUS,t2term,to_unwrap,t1,result);
break;
case Theory::RAT_PLUS:
okay=balancePlus(Theory::RAT_PLUS,Theory::RAT_UNARY_MINUS,t2term,to_unwrap,t1,result);
break;
case Theory::REAL_PLUS:
okay=balancePlus(Theory::REAL_PLUS,Theory::REAL_UNARY_MINUS,t2term,to_unwrap,t1,result);
break;
case Theory::INT_MULTIPLY:
{
okay=balanceIntegerMultiply(t2term,to_unwrap,t1,result,swap);
break;
}
case Theory::RAT_MULTIPLY:
{
RationalConstantType zero(0,1);
okay=balanceMultiply(Theory::RAT_QUOTIENT,zero,t2term,to_unwrap,t1,result,swap);
break;
}
case Theory::REAL_MULTIPLY:
{
RealConstantType zero(RationalConstantType(0, 1));
okay=balanceMultiply(Theory::REAL_QUOTIENT,zero,t2term,to_unwrap,t1,result,swap);
break;
}
case Theory::RAT_QUOTIENT:
okay=balanceDivide(Theory::RAT_MULTIPLY,t2term,to_unwrap,t1,result,swap);
break;
case Theory::REAL_QUOTIENT:
okay=balanceDivide(Theory::REAL_MULTIPLY,t2term,to_unwrap,t1,result,swap);
break;
default:
okay=false;
break;
}
if(!okay){
if(!modified) return false;
goto endOfUnwrapping;
}
t1=result;
t2 = to_unwrap;
modified = true;
}
endOfUnwrapping:
if(lit->functor()==0){
resLit = BottomUpTermTransformer::transformLiteral(Literal::createEquality(lit->polarity(),t2,t1,srt));
}
else{
if(swap){
resLit = BottomUpTermTransformer::transformLiteral(Literal::create2(lit->functor(),lit->polarity(),t2,t1));
}else{
resLit = BottomUpTermTransformer::transformLiteral(Literal::create2(lit->functor(),lit->polarity(),t1,t2));
}
}
return true;
}
bool InterpretedLiteralEvaluator::balancePlus(Interpretation plus, Interpretation unaryMinus,
Term* AplusB, TermList A, TermList C, TermList& result)
{
unsigned um = env.signature->getInterpretingSymbol(unaryMinus);
unsigned ip = env.signature->getInterpretingSymbol(plus);
TermList B;
if(AplusB->termArg(0)==A){
B = AplusB->termArg(1);
}
else{
ASS(AplusB->termArg(1)==A);
B = AplusB->termArg(0);
}
TermList mB(Term::create1(um,B));
result = TermList(Term::create2(ip,C,mB));
return true;
}
template<typename ConstantType>
bool InterpretedLiteralEvaluator::balanceMultiply(Interpretation divide,ConstantType zero,
Term* AmultiplyB, TermList A, TermList C, TermList& result,
bool& swap)
{
#if VDEBUG
TermList srt = theory->getOperationSort(divide);
ASS(srt == AtomicSort::realSort() || srt == AtomicSort::rationalSort());
#endif
unsigned div = env.signature->getInterpretingSymbol(divide);
TermList B;
if(AmultiplyB->termArg(0)==A){
B = AmultiplyB->termArg(1);
}
else{
ASS(AmultiplyB->termArg(1)==A);
B = AmultiplyB->termArg(0);
}
result = TermList(Term::create2(div,C,B));
ConstantType bcon;
if(theory->tryInterpretConstant(B,bcon)){
if(bcon.isZero()) return false;
if(bcon.isNegative()){ swap=!swap; } return true;
}
return false;
}
bool InterpretedLiteralEvaluator::balanceIntegerMultiply(
Term* AmultiplyB, TermList A, TermList C, TermList& result,
bool& swap)
{
IntegerConstantType ccon;
if(!theory->tryInterpretConstant(C,ccon)){ return false; }
unsigned div = env.signature->getInterpretingSymbol(Theory::INT_QUOTIENT_E);
TermList B;
if(AmultiplyB->termArg(0)==A){
B = AmultiplyB->termArg(1);
}
else{
ASS(AmultiplyB->termArg(1)==A);
B = AmultiplyB->termArg(0);
}
result = TermList(Term::create2(div,C,B));
IntegerConstantType bcon;
if(theory->tryInterpretConstant(B,bcon)){
if(bcon.isZero()){ return false; }
if(!bcon.divides(ccon)){ return false;}
if(bcon.isNegative()){ swap=!swap; } return true;
}
return false;
}
bool InterpretedLiteralEvaluator::balanceDivide(Interpretation multiply,
Term* AoverB, TermList A, TermList C, TermList& result, bool& swap)
{
#if VDEBUG
TermList srt = theory->getOperationSort(multiply);
ASS(srt == AtomicSort::realSort() || srt == AtomicSort::rationalSort());
#endif
unsigned mul = env.signature->getInterpretingSymbol(multiply);
if(AoverB->termArg(0)!=A)return false;
auto B = AoverB->termArg(1);
result = TermList(Term::create2(mul,C,B));
RationalConstantType bcon;
if(theory->tryInterpretConstant(B,bcon)){
ASS(!bcon.isZero());
if(bcon.isNegative()){ swap=!swap; } return true;
}
return false;
}
class LiteralNormalizer
{
public:
static Literal* normalize(Literal* in) {
auto functor = in->functor();
if (theory->isInterpretedPredicate(functor)) {
auto i = theory->interpretPredicate(functor);
switch (i) {
case Interpretation::INT_LESS:
return InequalityNormalizer<IntLess>::normalize(in);
case Interpretation::RAT_LESS:
return InequalityNormalizer<FracLess<RationalConstantType>>::normalize(in);
case Interpretation::REAL_LESS:
return InequalityNormalizer<FracLess<RealConstantType>>::normalize(in);
default:
return in;
}
} else {
return in;
}
}
};
TermList InterpretedLiteralEvaluator::evaluate(TermList t) {
if (t.isTerm())
t = TermList(BottomUpTermTransformer::transform(t.term()));
return InterpretedLiteralEvaluator::transformSubterm(t);
}
bool InterpretedLiteralEvaluator::evaluate(Literal* lit, bool& isConstant, Literal*& resLit, bool& resConst)
{
DEBUG( "evaluate ", lit->toString() );
resLit = _normalize ? LiteralNormalizer::normalize(lit)
: lit;
DEBUG( "\t0 ==> ", resLit->toString() );
resLit = BottomUpTermTransformer::transformLiteral( resLit);
DEBUG( "\t1 ==> ", resLit->toString() );
unsigned pred = resLit->functor();
Evaluator* predEv = getPredEvaluator(pred);
if (predEv) {
auto r = predEv->tryEvaluatePred(resLit);
switch (r.status) {
case PredEvalResult::Nop:
break;
case PredEvalResult::Simplified:
resLit = BottomUpTermTransformer::transformLiteral(r.simplified_val);
break;
case PredEvalResult::Trivial:
isConstant = true;
resConst = r.trivial_val;
DEBUG( "\t3 ==> ", resConst );
return true;
}
}
isConstant = false;
auto out = resLit != lit;
DEBUG( "\t3 ==> ", resLit->toString(), "(did evaluate: ", out, ")" );
return out;
}
TermList InterpretedLiteralEvaluator::transformSubterm(TermList trm)
{
if (!trm.isTerm() || trm.term()->isSort()) { return trm; }
Term* t = trm.term();
unsigned func = t->functor();
Evaluator* funcEv = getFuncEvaluator(func);
if (funcEv) {
TermList res;
if (funcEv->tryEvaluateFunc(t, res)) {
return res;
}
} else {
DEBUG("no transformer")
}
return trm;
}
template<class Fn>
InterpretedLiteralEvaluator::Evaluator* InterpretedLiteralEvaluator::getEvaluator(unsigned functor, DArray<Evaluator*>& evaluators, Fn canEval)
{
if (functor >= evaluators.size()) {
unsigned oldSz = evaluators.size();
unsigned newSz = functor + 1 ;
evaluators.expand(newSz);
for (unsigned i=oldSz; i<newSz; i++) {
EvalStack::Iterator evit(_evals);
while (evit.hasNext()) {
Evaluator* ev = evit.next();
if (canEval(ev, i)) {
evaluators[i] = ev;
goto break_inner;
}
}
break_inner:;
}
}
return evaluators[functor];
}
InterpretedLiteralEvaluator::Evaluator* InterpretedLiteralEvaluator::getFuncEvaluator(unsigned func)
{
return getEvaluator(func,
this->_funEvaluators,
[] (Evaluator* ev, unsigned i) {return ev->canEvaluateFunc(i); });
}
InterpretedLiteralEvaluator::Evaluator* InterpretedLiteralEvaluator::getPredEvaluator(unsigned pred)
{
return getEvaluator(pred, this->_predEvaluators,
[] (Evaluator* ev, unsigned i) {return ev->canEvaluatePred(i); });
}
}