#include "Inferences/PushUnaryMinus.hpp"
#include "Kernel/Clause.hpp"
#include "Kernel/TermIterators.hpp"
#define DEBUG(...)
namespace Inferences {
using namespace std;
enum class UMinus {
Int,
Rat,
Real,
None,
};
std::ostream& operator<<(std::ostream& out, UMinus const& self) {
switch(self) {
case UMinus::Int: return out << "UMinus::Int";
case UMinus::Rat: return out << "UMinus::Rat";
case UMinus::Real: return out << "UMinus::Real";
case UMinus::None: return out << "UMinus::None";
default:
return out << "UNKNOWN";
}
ASSERTION_VIOLATION
}
TermList pushUMinus(UMinus outerMinus, TermList t)
{
auto wrapMinus = [&](TermList t)
{
switch (outerMinus) {
case UMinus::Int : return IntTraits::minus(t);
case UMinus::Rat : return RatTraits::minus(t);
case UMinus::Real: return RealTraits::minus(t);
case UMinus::None: return t;
default:
ASSERTION_VIOLATION;
}
ASSERTION_VIOLATION
};
if (t.isVar()) {
return wrapMinus(t);
} else if(t.term()->isSort()){
return t;
} else {
auto term = t.term();
auto fun = term->functor();
if (theory->isInterpretedFunction(fun)) {
switch (theory->interpretFunction(fun)) {
#define CASE(Num) \
case Num##Traits::minusI: \
{ \
if(outerMinus == UMinus::None) { \
return pushUMinus(UMinus::Num, term->termArg(0)); \
} else { \
ASS_EQ(outerMinus, UMinus::Num) \
return term->termArg(0); \
} \
} \
case Num##Traits::addI: \
if (outerMinus != UMinus::None) { \
ASS_EQ(outerMinus, UMinus::Num); \
return Num##Traits::add( \
pushUMinus(UMinus::Num, term->termArg(0)), \
pushUMinus(UMinus::Num, term->termArg(1))); \
} else { break; }
CASE(Int)
CASE(Rat)
CASE(Real)
default: {}
}
}
auto args = concatIters(
typeArgIter(term),
termArgIter(term)
.map([&](auto t) { return pushUMinus(UMinus::None, t); }))
.template collect<Stack>();
return wrapMinus(TermList(Term::create(term, args.begin())));
}
}
PushUnaryMinus::~PushUnaryMinus() {}
Clause* PushUnaryMinus::simplify(Clause* cl_)
{
DEBUG("in: ", *cl_)
if (cl_->isTheoryAxiom())
return cl_;
auto& cl = *cl_;
Stack<Literal*> out(cl.size());
bool changed = false;
for (unsigned i = 0; i < cl.size(); i++) {
auto litIn = cl[i];
auto litStack = concatIters(
typeArgIter(litIn),
termArgIter(litIn)
.map([&](auto tIn) {
auto tOut = pushUMinus(UMinus::None, tIn);
changed = changed || tIn != tOut;
return tOut;
})
).template collect<Stack>();
if(changed){
auto litOut = Literal::create(litIn, litStack.begin());
out.push(litOut);
} else {
out.push(litIn);
}
}
if (!changed) {
return cl_;
} else {
auto result = Clause::fromStack(out, SimplifyingInference1(InferenceRule::EVALUATION, cl_));
DEBUG("out: ", *result)
return result;
}
}
}