/*
* Copyright (C) 2014 University of Freiburg
*
* This file is part of SMTInterpol.
*
* SMTInterpol is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SMTInterpol is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with SMTInterpol. If not, see <http://www.gnu.org/licenses/>.
*/
package de.uni_freiburg.informatik.ultimate.smtinterpol.delta;
import java.util.ArrayDeque;
import java.util.Iterator;
import java.util.List;
import de.uni_freiburg.informatik.ultimate.logic.AnnotatedTerm;
import de.uni_freiburg.informatik.ultimate.logic.ApplicationTerm;
import de.uni_freiburg.informatik.ultimate.logic.ConstantTerm;
import de.uni_freiburg.informatik.ultimate.logic.LetTerm;
import de.uni_freiburg.informatik.ultimate.logic.NonRecursive;
import de.uni_freiburg.informatik.ultimate.logic.QuantifiedFormula;
import de.uni_freiburg.informatik.ultimate.logic.Rational;
import de.uni_freiburg.informatik.ultimate.logic.Term;
import de.uni_freiburg.informatik.ultimate.logic.TermVariable;
import de.uni_freiburg.informatik.ultimate.logic.Theory;
public class NeutralRemover extends NonRecursive {
private static class BuildAnnotationTerm implements Walker {
private final AnnotatedTerm mAnnot;
public BuildAnnotationTerm(AnnotatedTerm annot) {
mAnnot = annot;
}
@Override
public void walk(NonRecursive engine) {
final NeutralRemover remover = (NeutralRemover) engine;
final Term sub = remover.getConverted();
remover.setResult(sub == mAnnot.getSubterm()
? mAnnot
: mAnnot.getTheory().annotatedTerm(
mAnnot.getAnnotations(), sub));
}
}
private static class BuildApplicationTerm implements Walker {
private final ApplicationTerm mApp;
private int mNumParams;
public BuildApplicationTerm(ApplicationTerm app) {
mApp = app;
}
public void setParamCount(int count) {
mNumParams = count;
}
@Override
public void walk(NonRecursive engine) {
final NeutralRemover remover = (NeutralRemover) engine;
if (mApp.getParameters().length == 0) {
remover.setResult(mApp);
} else if (mNumParams == 0) {
// Try to remove the whole term
if (mApp.getSort() == mApp.getTheory().getBooleanSort()) {
remover.setResult(mApp.getTheory().mTrue);
} else {
remover.setResult(Rational.ZERO.toTerm(mApp.getSort()));
}
} else if (mNumParams == 1 && mApp.getParameters().length != 1) {
// We removed some neutral elements. The result is already on
// the result stack. Thus, we don't do
// remover.setResult(remover.getConverted());
} else {
final Term[] params = remover.getConverted(mNumParams);
remover.setResult(mApp.getTheory().term(
mApp.getFunction(), params));
}
}
}
private static class BuildLetTerm implements Walker {
private final LetTerm mLet;
public BuildLetTerm(LetTerm let) {
mLet = let;
}
@Override
public void walk(NonRecursive engine) {
final NeutralRemover remover = (NeutralRemover) engine;
final Term[] values = remover.getConverted(mLet.getValues().length);
final Term sub = remover.getConverted();
remover.setResult(sub.getTheory().let(
mLet.getVariables(), values, sub));
}
}
private static class BuildQuantifiedFormula implements Walker {
private final QuantifiedFormula mQuant;
public BuildQuantifiedFormula(QuantifiedFormula quant) {
mQuant = quant;
}
@Override
public void walk(NonRecursive engine) {
final NeutralRemover remover = (NeutralRemover) engine;
final Term sub = remover.getConverted();
final Theory t = sub.getTheory();
if (sub == mQuant.getSubformula()) {
remover.setResult(mQuant);
} else if (mQuant.getQuantifier() == QuantifiedFormula.EXISTS) {
remover.setResult(t.exists(mQuant.getVariables(), sub));
} else {
remover.setResult(t.forall(mQuant.getVariables(), sub));
}
}
}
private static class NeutralWalker extends TermWalker {
public NeutralWalker(Term t) {
super(t);
}
@Override
public void walk(NonRecursive walker, ConstantTerm term) {
((NeutralRemover) walker).setResult(term);
}
@Override
public void walk(NonRecursive walker, AnnotatedTerm term) {
walker.enqueueWalker(new BuildAnnotationTerm(term));
walker.enqueueWalker(new NeutralWalker(term.getSubterm()));
}
@Override
public void walk(NonRecursive walker, ApplicationTerm term) {
final NeutralRemover remover = (NeutralRemover) walker;
final BuildApplicationTerm bat = new BuildApplicationTerm(term);
walker.enqueueWalker(bat);
int paramsPushed = 0;
final Term[] params = term.getParameters();
for (int i = 0; i < params.length; ++i) {
if (!remover.shouldRemove(term, i)) {
walker.enqueueWalker(new NeutralWalker(params[i]));
++paramsPushed;
}
}
bat.setParamCount(paramsPushed);
}
@Override
public void walk(NonRecursive walker, LetTerm term) {
walker.enqueueWalker(new BuildLetTerm(term));
for (final Term v : term.getValues()) {
walker.enqueueWalker(new NeutralWalker(v));
}
walker.enqueueWalker(new NeutralWalker(term.getSubTerm()));
}
@Override
public void walk(NonRecursive walker, QuantifiedFormula term) {
walker.enqueueWalker(new BuildQuantifiedFormula(term));
walker.enqueueWalker(new NeutralWalker(term.getSubformula()));
}
@Override
public void walk(NonRecursive walker, TermVariable term) {
((NeutralRemover) walker).setResult(term);
}
}
private final ArrayDeque<Term> mConverted = new ArrayDeque<Term>();
private final Iterator<Neutral> mNeutrals;
private Neutral mNext;
public NeutralRemover(List<Neutral> neutrals) {
mNeutrals = neutrals.iterator();
mNext = mNeutrals.hasNext() ? mNeutrals.next() : null;
}
boolean shouldRemove(Term t, int pos) {
if (mNext != null && mNext.matches(t, pos)) {
mNext = mNeutrals.hasNext() ? mNeutrals.next() : null;
return true;
}
return false;
}
void setResult(Term t) {
mConverted.push(t);
}
Term[] getConverted(int num) {
final Term[] res = new Term[num];
for (int i = 0; i < res.length; ++i) {
res[i] = mConverted.pop();
}
return res;
}
Term getConverted() {
return mConverted.pop();
}
public Term removeNeutrals(Term t) {
run(new NeutralWalker(t));
return mConverted.pop();
}
}