#include "Lib/Environment.hpp"
#include "Lib/List.hpp"
#include "Kernel/Clause.hpp"
#include "Kernel/Formula.hpp"
#include "Kernel/FormulaUnit.hpp"
#include "Kernel/Inference.hpp"
#include "Kernel/InferenceStore.hpp"
#include "Kernel/Problem.hpp"
#include "Kernel/Signature.hpp"
#include "Kernel/SortHelper.hpp"
#include "Kernel/Term.hpp"
#include "Kernel/Unit.hpp"
#include "Kernel/SortHelper.hpp"
#include "Kernel/SubstHelper.hpp"
#include "EqualityProxy.hpp"
using namespace Shell;
using namespace std;
using namespace Lib;
using namespace Kernel;
EqualityProxy::EqualityProxy(Options::EqualityProxy opt)
: _opt(opt), _addedPred(0), _defUnit(0)
{
ASS(opt != Options::EqualityProxy::OFF);
}
void EqualityProxy::apply(Problem& prb)
{
bool hadEquality = prb.hasEquality();
apply(prb.units());
prb.invalidateByRemoval();
prb.reportEqualityEliminated();
if (hadEquality) {
switch(_opt) {
case Options::EqualityProxy::R:
case Options::EqualityProxy::RS:
case Options::EqualityProxy::RST:
prb.reportIncompleteTransformation();
break;
default:
break;
}
}
}
void EqualityProxy::apply(UnitList*& units)
{
UnitList::DelIterator uit(units);
while (uit.hasNext()) {
Unit* unit = uit.next();
ASS (unit->isClause());
Clause* cl = static_cast<Clause*>(unit);
Clause* cl2 = apply(cl);
if (cl != cl2) {
uit.replace(cl2);
}
}
addAxioms(units);
}
void EqualityProxy::addLocalAxioms(UnitList*& units)
{
Stack<Literal*> lits;
TermList sort = TermList(false, 0);
lits.push(makeProxyLiteral(true,TermList(1,false),TermList(1,false), sort));
UnitList::push(createEqProxyAxiom(lits),units);
if (_opt == Options::EqualityProxy::RS || _opt == Options::EqualityProxy::RST || _opt == Options::EqualityProxy::RSTC) {
lits.reset();
lits.push(makeProxyLiteral(false,TermList(1,false),TermList(2,false), sort));
lits.push(makeProxyLiteral(true,TermList(2,false),TermList(1,false), sort));
UnitList::push(createEqProxyAxiom(lits),units);
}
if (_opt == Options::EqualityProxy::RST || _opt == Options::EqualityProxy::RSTC) {
lits.reset();
lits.push(makeProxyLiteral(false,TermList(1,false),TermList(2,false), sort));
lits.push(makeProxyLiteral(false,TermList(2,false),TermList(3,false), sort));
lits.push(makeProxyLiteral(true,TermList(1,false),TermList(3,false), sort));
UnitList::push(createEqProxyAxiom(lits),units);
}
}
void EqualityProxy::addAxioms(UnitList*& units)
{
if (_opt == Options::EqualityProxy::RSTC) {
addCongruenceAxioms(units);
}
addLocalAxioms(units);
}
void EqualityProxy::getArgumentEqualityLiterals(unsigned cnt, LiteralStack& lits,
Stack<TermList>& vars1, Stack<TermList>& vars2, OperatorType* symbolType)
{
ASS_EQ(cnt, symbolType->arity());
lits.reset();
vars1.reset();
vars2.reset();
static Substitution localSubst;
localSubst.reset();
for (unsigned i=0; i<cnt; i++) {
TermList v1(2*i, false);
TermList v2(2*i+1, false);
TermList sort = symbolType->arg(i);
if(sort != AtomicSort::superSort()){
lits.push(makeProxyLiteral(false, v1, v2, SubstHelper::apply(sort, localSubst)));
vars1.push(v1);
vars2.push(v2);
} else {
TermList var = symbolType->quantifiedVar(i);
localSubst.bindUnbound(var.var(), v1);
vars1.push(v1);
vars2.push(v1);
}
}
}
void EqualityProxy::addCongruenceAxioms(UnitList*& units)
{
Stack<TermList> vars1;
Stack<TermList> vars2;
LiteralStack lits;
TermList srt;
unsigned funs = env.signature->functions();
for (unsigned i=0; i<funs; i++) {
Signature::Symbol* fnSym = env.signature->getFunction(i);
if(!fnSym->usageCnt() || fnSym->skipCongruence())
continue;
unsigned arity = fnSym->arity();
OperatorType* fnType = fnSym->fnType();
if (arity == 0) {
continue;
}
getArgumentEqualityLiterals(arity, lits, vars1, vars2, fnType);
Term* t1 = Term::create(i, arity, vars1.begin());
Term* t2 = Term::create(i, arity, vars2.begin());
SortHelper::tryGetResultSort(t1, srt);
lits.push(makeProxyLiteral(true, TermList(t1), TermList(t2), srt));
Clause* cl = createEqProxyAxiom(lits);
UnitList::push(cl,units);
}
unsigned preds = env.signature->predicates();
for (unsigned i = 1; i < preds; i++) {
Signature::Symbol* predSym = env.signature->getPredicate(i);
if(!predSym->usageCnt() || predSym->skipCongruence())
continue;
unsigned arity = predSym->arity();
if (arity == 0) {
continue;
}
getArgumentEqualityLiterals(arity, lits, vars1, vars2, predSym->predType());
lits.push(Literal::create(i, arity, false, vars1.begin()));
lits.push(Literal::create(i, arity, true, vars2.begin()));
Clause* cl = createEqProxyAxiom(lits);
UnitList::push(cl,units);
}
}
Clause* EqualityProxy::apply(Clause* cl)
{
unsigned clen = cl->length();
RStack<Literal*> resLits;
bool modified = false;
for (unsigned i = 0; i < clen ; i++) {
Literal* lit=(*cl)[i];
Literal* rlit=apply(lit);
resLits->push(rlit);
if (rlit != lit) {
ASS(lit->isEquality());
modified = true;
}
}
if (!modified) {
return cl;
}
ASS(_defUnit);
auto res = Clause::fromStack(*resLits,
NonspecificInference2(InferenceRule::EQUALITY_PROXY_REPLACEMENT, cl, _defUnit));
res->setAge(cl->age());
return res;
}
Literal* EqualityProxy::apply(Literal* lit)
{
if (!lit->isEquality()) {
return lit;
}
TermList sort = SortHelper::getEqualityArgumentSort(lit);
return makeProxyLiteral(lit->polarity(), *lit->nthArgument(0), *lit->nthArgument(1), sort);
}
unsigned EqualityProxy::getProxyPredicate()
{
if(_addedPred){ return _proxyPredicate; }
unsigned newPred = env.signature->addFreshPredicate(3,"sQ","eqProxy");
TermList sort = TermList(0,false);
TermList var1 = TermList(1,false);
TermList var2 = TermList(2,false);
Signature::Symbol* predSym = env.signature->getPredicate(newPred);
OperatorType* predType = OperatorType::getPredicateType({sort, sort}, 1);
predSym->setType(predType);
predSym->markEqualityProxy();
predSym->markSkipCongruence();
static TermStack args;
args.reset();
args.push(sort);
args.push(var1);
args.push(var2);
Literal* proxyLit = Literal::create(newPred, 3, true, args.begin());
Literal* eqLit = Literal::createEquality(true,var1,var2,sort);
Formula* defForm = new BinaryFormula(IFF, new AtomicFormula(proxyLit), new AtomicFormula(eqLit));
Formula* quantDefForm = Formula::quantify(defForm);
_defUnit = new FormulaUnit(quantDefForm,NonspecificInference0(UnitInputType::AXIOM,InferenceRule::EQUALITY_PROXY_AXIOM1));
InferenceStore::instance()->recordIntroducedSymbol(_defUnit, SymbolType::PRED, newPred);
_proxyPredicate = newPred;
_addedPred = true;
return newPred;
}
Clause* EqualityProxy::createEqProxyAxiom(const LiteralStack& literalStack)
{
ASS(_defUnit);
Clause* res = Clause::fromStack(literalStack, NonspecificInference1(InferenceRule::EQUALITY_PROXY_AXIOM2,_defUnit));
return res;
}
Literal* EqualityProxy::makeProxyLiteral(bool polarity, TermList arg0, TermList arg1, TermList sort)
{
unsigned pred = getProxyPredicate();
TermList args[] = {sort, arg0, arg1};
return Literal::create(pred, 3, polarity, args);
}