#include "Lib/Metaiterators.hpp"
#include "Lib/Recycled.hpp"
#include "Kernel/Formula.hpp"
#include "Kernel/FormulaUnit.hpp"
#include "Kernel/Inference.hpp"
#include "Kernel/SortHelper.hpp"
#include "Kernel/Term.hpp"
#include "Kernel/TermIterators.hpp"
#include "Kernel/Unit.hpp"
#include "Rectify.hpp"
using namespace std;
using namespace Shell;
bool Rectify::Renaming::tryGetBoundAndMarkUsed (int var,int& boundTo) const
{
if ((unsigned)var >= _capacity) {
return false;
}
VarUsageTrackingList* vs = _array[var];
if (VarUsageTrackingList::isEmpty(vs)) {
return false;
}
boundTo = vs->head().first;
vs->headPtr()->second = true;
return true;
}
Rectify::VarWithUsageInfo Rectify::Renaming::getBoundAndUsage(int var) const
{
ASS_L((unsigned)var,_capacity);
VarUsageTrackingList* vs = _array[var];
ASS(VarUsageTrackingList::isNonEmpty(vs));
return vs->head();
}
FormulaUnit* Rectify::rectify (FormulaUnit* unit0, bool removeUnusedVars)
{
ASS(!unit0->isClause());
FormulaUnit* unit = unit0;
Formula* f = unit->formula();
Rectify rect;
rect._removeUnusedVars = removeUnusedVars;
Formula* g = rect.rectify(f);
VList* vars = rect._free;
if (f != g) {
unit = new FormulaUnit(g,FormulaClauseTransformation(InferenceRule::RECTIFY,unit));
}
if (VList::isNonEmpty(vars)) {
unit = new FormulaUnit(new QuantifiedFormula(FORALL,vars,0,g),FormulaClauseTransformation(InferenceRule::CLOSURE,unit));
}
return unit;
}
void Rectify::rectify(UnitList*& units)
{
UnitList::DelIterator us(units);
while (us.hasNext()) {
Unit* u = us.next();
if(u->isClause()) {
continue;
}
FormulaUnit* fu = static_cast<FormulaUnit*>(u);
FormulaUnit* v = rectify(fu);
if (v != fu) {
us.replace(v);
}
}
}
Rectify::Renaming::~Renaming ()
{
for (int i = _capacity-1;i >= 0;i--) {
VarUsageTrackingList::destroy(_array[i]);
_array[i] = 0;
}
}
Term* Rectify::rectifySpecialTerm(Term* t)
{
Term::SpecialTermData* sd = t->getSpecialData();
switch(t->specialFunctor()) {
case SpecialFunctor::ITE:
{
ASS_EQ(t->arity(),2);
Formula* c = rectify(sd->getITECondition());
TermList th = rectify(*t->nthArgument(0));
TermList el = rectify(*t->nthArgument(1));
TermList sort = rectify(sd->getSort());
if(c==sd->getITECondition() && th==*t->nthArgument(0) && el==*t->nthArgument(1) && sort==sd->getSort()) {
return t;
}
return Term::createITE(c, th, el, sort);
}
case SpecialFunctor::LET:
{
ASS_EQ(t->arity(),1);
Formula* binding = rectify(sd->getLetBinding());
TermList body = rectify(*t->nthArgument(0));
TermList sort = rectify(sd->getSort());
if (binding == sd->getLetBinding() && body == *t->nthArgument(0) && sort == sd->getSort()) {
return t;
}
return Term::createLet(binding, body, sort);
}
case SpecialFunctor::FORMULA:
{
ASS_EQ(t->arity(),0);
Formula* orig = rectify(sd->getFormula());
if(orig==sd->getFormula()) {
return t;
}
return Term::createFormula(orig);
}
case SpecialFunctor::LAMBDA:
{
ASS_EQ(t->arity(),0);
bindVars(sd->getLambdaVars());
bool modified = false;
TermList lambdaTerm = rectify(sd->getLambdaExp());
TermList lambdaTermS = rectify(sd->getLambdaExpSort());
if(lambdaTerm != sd->getLambdaExp() || lambdaTermS != sd->getLambdaExpSort())
{ modified = true; }
bool removeUnusedVars = _removeUnusedVars;
_removeUnusedVars = false;
VList* vs = rectifyBoundVars(sd->getLambdaVars());
SList* sorts = sd->getLambdaVarSorts();
SList* rectifiedSorts = SList::empty();
SList::Iterator slit(sorts);
while(slit.hasNext()){
TermList sort = slit.next();
TermList rectifiedSort = rectify(sort);
if(sort != rectifiedSort){
modified = true;
}
rectifiedSorts = SList::addLast(rectifiedSorts, rectifiedSort); }
_removeUnusedVars = removeUnusedVars; unbindVars(sd->getLambdaVars());
if (vs == sd->getLambdaVars() && !modified) {
return t;
}
return Term::createLambda(lambdaTerm, vs, rectifiedSorts, lambdaTermS);
}
case SpecialFunctor::MATCH: {
DArray<TermList> terms(t->arity());
bool unchanged = true;
for (unsigned i = 0; i < t->arity(); i++) {
terms[i] = rectify(*t->nthArgument(i));
unchanged = unchanged && (terms[i] == *t->nthArgument(i));
}
auto sort = rectify(sd->getSort());
auto matchedSort = rectify(sd->getMatchedSort());
if (unchanged && sort == sd->getSort() && matchedSort == sd->getMatchedSort()) {
return t;
}
return Term::createMatch(sort, matchedSort, t->arity(), terms.begin());
}
}
ASSERTION_VIOLATION;
}
Term* Rectify::rectify (Term* t)
{
if (t->shared() && t->ground()) {
return t;
}
if(t->isSpecial()) {
return rectifySpecialTerm(t);
}
Recycled<Stack<TermList>> args;
for (auto a : anyArgIter(t)) {
args->push(rectify(a));
}
if (t->isSort()) {
return AtomicSort::create(static_cast<AtomicSort*>(t), args->begin());
} else if (t->isLiteral()) {
return Literal::create(static_cast<Literal*>(t), args->begin());
} else {
return Term::create(t, args->begin());
}
}
SList* Rectify::rectifySortList(SList* from, bool& modified)
{
modified = false;
SList* to = SList::empty();
SList::Iterator slit(from);
while(slit.hasNext()){
TermList sort = slit.next();
TermList rectifiedSort = rectify(sort);
if(sort != rectifiedSort){
modified = true;
}
SList::addLast(to, rectifiedSort); }
return to;
}
Literal* Rectify::rectifyShared(Literal* lit)
{
ASS(lit->shared());
return SubstHelper::apply(lit, *this);
}
Literal* Rectify::rectify (Literal* l)
{
if (l->shared()) {
if(l->ground()) {
return l;
}
}
if (l->isTwoVarEquality()) {
constexpr unsigned arity = 3;
TermList args[arity];
bool changed = Rectify::rectify(
[&](auto i) { return i == 0 ? SortHelper::getEqualityArgumentSort(l)
: *l->nthArgument(i - 1); },
[&](auto i) -> TermList& { return args[i]; },
arity);
return changed ? Literal::createEquality(l->polarity(), args[1], args[2], args[0]) : l;
} else {
Recycled<DArray<TermList>> args;
args->ensure(l->arity());
bool changed = Rectify::rectify(
[&](auto i) { return *l->nthArgument(i); },
[&](auto i) -> TermList& { return (*args)[i]; },
l->arity());
return !changed ? l : Literal::create(l->functor(), l->arity(), l->polarity(), args->begin());
}
}
template<class From, class To>
bool Rectify::rectify(From from, To to, unsigned cnt)
{
bool changed = false;
for (auto i : range(0, cnt)) {
if (from(i).isVar()) {
int v = from(i).var();
int newV = rectifyVar(v);
to(i) = TermList::var(newV);
if (v != newV) { changed = true;
}
}
else { Term* f = from(i).term();
Term* t = rectify(f);
to(i) = TermList(t);
if (f != t) {
changed = true;
}
}
}
return changed;
}
unsigned Rectify::rectifyVar(unsigned v)
{
int newV;
if (! _renaming.tryGetBoundAndMarkUsed(v,newV)) {
newV = _renaming.bind(v);
VList::push(newV,_free);
}
return newV;
}
TermList Rectify::rectify(TermList t)
{
if(t.isTerm()) {
return TermList(rectify(t.term()));
}
ASS(t.isOrdinaryVar());
return TermList(rectifyVar(t.var()), false);
}
Formula* Rectify::rectify (Formula* f)
{
switch (f->connective()) {
case LITERAL:
{
Literal* lit = rectify(f->literal());
return lit == f->literal() ? f : new AtomicFormula(lit);
}
case AND:
case OR:
{
FormulaList* newArgs = rectify(f->args());
if (newArgs == f->args()) {
return f;
}
return new JunctionFormula(f->connective(), newArgs);
}
case IMP:
case IFF:
case XOR:
{
Formula* l = rectify(f->left());
Formula* r = rectify(f->right());
if (l == f->left() && r == f->right()) {
return f;
}
return new BinaryFormula(f->connective(), l, r);
}
case NOT:
{
Formula* arg = rectify(f->uarg());
if (f->uarg() == arg) {
return f;
}
return new NegatedFormula(arg);
}
case FORALL:
case EXISTS:
{
bindVars(f->vars());
Formula* arg = rectify(f->qarg());
VList* vs = rectifyBoundVars(f->vars());
unbindVars(f->vars());
if (vs == f->vars() && arg == f->qarg()) {
return f;
}
if(VList::isEmpty(vs)) {
return arg;
}
return new QuantifiedFormula(f->connective(),vs,0,arg);
}
case TRUE:
case FALSE:
return f;
case BOOL_TERM:
return new BoolTermFormula(rectify(f->getBooleanTerm()));
case NAME:
case NOCONN:
ASSERTION_VIOLATION;
}
ASSERTION_VIOLATION;
}
void Rectify::Renaming::undoBinding (unsigned var)
{
ASS(var < _capacity);
VarUsageTrackingList::pop(_array[var]);
}
unsigned Rectify::Renaming::bind (unsigned var)
{
unsigned result = _nextVar++;
VarUsageTrackingList::push(make_pair(result,false), get(var));
return result;
}
void Rectify::bindVars(VList* vs)
{
VList::Iterator vit(vs);
while(vit.hasNext()) {
unsigned v = vit.next();
_renaming.bind(v);
}
}
void Rectify::unbindVars(VList* vs)
{
VList::Iterator vit(vs);
while(vit.hasNext()) {
unsigned v = vit.next();
_renaming.undoBinding(v);
}
}
VList* Rectify::rectifyBoundVars (VList* vs)
{
if (VList::isEmpty(vs)) {
return vs;
}
Stack<VList*> args;
while (VList::isNonEmpty(vs)) {
args.push(vs);
vs = vs->tail();
}
VList* res = VList::empty();
DHSet<int> seen;
while (args.isNonEmpty()) {
vs = args.pop();
VList* vtail = vs->tail();
VList* ws = res;
int v = vs->head();
if (!seen.insert(v)) {
continue;
}
int w;
VarWithUsageInfo wWithUsg = _renaming.getBoundAndUsage(v);
if (wWithUsg.second || !_removeUnusedVars) {
w = wWithUsg.first;
if (v == w && vtail == ws) {
res = vs;
} else {
res = VList::cons(w,ws);
}
}
}
return res;
}
FormulaList* Rectify::rectify (FormulaList* fs)
{
Recycled<Stack<FormulaList*>> els;
FormulaList* el = fs;
while(el) {
els->push(el);
el = el->tail();
}
FormulaList* res = 0;
bool modified = false;
while(els->isNonEmpty()) {
FormulaList* el = els->pop();
Formula* f = el->head();
Formula* g = rectify(f);
if(!modified && f!=g) {
modified = true;
}
if(modified) {
FormulaList::push(g, res);
}
else {
res = el;
}
}
return res;
}
void Rectify::Renaming::fillInterval (size_t start,size_t end)
{
for (unsigned i = start;i < end;i++) {
_array[i] = 0;
}
}