/*
* Copyright (C) 2012-2013 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.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;
import de.uni_freiburg.informatik.ultimate.logic.ApplicationTerm;
import de.uni_freiburg.informatik.ultimate.logic.ConstantTerm;
import de.uni_freiburg.informatik.ultimate.logic.FunctionSymbol;
import de.uni_freiburg.informatik.ultimate.logic.LetTerm;
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.TermTransformer;
import de.uni_freiburg.informatik.ultimate.logic.TermVariable;
import de.uni_freiburg.informatik.ultimate.logic.Theory;
public class TermSimplifier extends TermTransformer {
public enum Mode {
NEUTRALS,
BINDINGS
}
private final Mode mMode;
public TermSimplifier(Mode mode) {
mMode = mode;
}
private boolean isZero(Term t) {
if (t instanceof ConstantTerm) {
final ConstantTerm ct = (ConstantTerm) t;
final Object val = ct.getValue();
if (val instanceof BigInteger) {
return BigInteger.ZERO.equals(val);
}
if (val instanceof BigDecimal) {
return BigDecimal.ZERO.equals(val);
}
if (val instanceof Rational) {
return Rational.ZERO.equals(val);
}
}
return false;
}
@Override
public void convertApplicationTerm(
ApplicationTerm appTerm, Term[] newArgs) {
if (mMode != Mode.NEUTRALS) {
super.convertApplicationTerm(appTerm, newArgs);
return;
}
final Theory t = appTerm.getTheory();
final FunctionSymbol fs = appTerm.getFunction();
if (appTerm.getSort() == t.getBooleanSort()) {
if (appTerm.getFunction() == t.mAnd
|| appTerm.getFunction() == t.mOr) {
final Term neutral = fs == t.mAnd ? t.mTrue : t.mFalse;
final LinkedHashSet<Term> newParams = new LinkedHashSet<Term>();
for (final Term p : newArgs) {
if (p != neutral) {
newParams.add(p);
}
}
if (newParams.size() != newArgs.length) {
if (newParams.size() == 1) {
setResult(newParams.iterator().next());
} else if (newParams.isEmpty()) {
setResult(t.term(fs, new Term[] {neutral, neutral}));
} else {
setResult(t.term(fs,
newParams.toArray(new Term[newParams.size()])));
}
return;
}
}
setResult(t.term(appTerm.getFunction(), newArgs));
} else if (appTerm.getSort().isNumericSort()) {
int start = 0;
if (fs.getName().equals("-")) {
start = 1;
} else if (!fs.getName().equals("+")) {
super.convertApplicationTerm(appTerm, newArgs);
return;
}
final ArrayList<Term> simp = new ArrayList<Term>();
for (int i = 0; i < start; ++i)
{
simp.add(newArgs[i]);// NOPMD
}
for ( ; start < newArgs.length; ++start) {
if (!isZero(newArgs[start])) {
simp.add(newArgs[start]);
}
}
if (simp.isEmpty()) {
setResult(t.term(appTerm.getFunction(),
newArgs[0], newArgs[0]));
} else if (simp.size() == 1) {
setResult(simp.iterator().next());
} else if (newArgs.length == simp.size()) {
setResult(appTerm.getTheory().term(fs, newArgs));
} else {
setResult(appTerm.getTheory().term(fs,
simp.toArray(new Term[simp.size()])));
}
} else {
super.convertApplicationTerm(appTerm, newArgs);
}
}
@Override
public void postConvertLet(LetTerm oldLet, Term[] newValues, Term newBody) {
if (mMode != Mode.BINDINGS) {
super.postConvertLet(oldLet, newValues, newBody);
return;
}
final Set<TermVariable> freeVars = new HashSet<TermVariable>(
Arrays.asList(newBody.getFreeVars()));
final ArrayList<TermVariable> tvs = new ArrayList<TermVariable>();
final ArrayList<Term> vals = new ArrayList<Term>();
for (int i = 0; i < newValues.length; ++i) {
final TermVariable var = oldLet.getVariables()[i];
if (freeVars.contains(var)) {
tvs.add(var);
vals.add(newValues[i]);
}
}
if (tvs.isEmpty()) {
setResult(newBody);
} else if (tvs.size() == newValues.length
&& newBody == oldLet.getSubTerm()) {
setResult(oldLet);
} else {
setResult(newBody.getTheory().let(
tvs.toArray(new TermVariable[tvs.size()]),
vals.toArray(new Term[vals.size()]), newBody));
}
}
@Override
public void postConvertQuantifier(QuantifiedFormula old, Term newBody) {
if (mMode != Mode.BINDINGS) {
super.postConvertQuantifier(old, newBody);
return;
}
final Set<TermVariable> freeVars = new HashSet<TermVariable>(
Arrays.asList(newBody.getFreeVars()));
final ArrayList<TermVariable> tvs = new ArrayList<TermVariable>();
for (final TermVariable tv : old.getVariables()) {
if (freeVars.contains(tv)) {
tvs.add(tv);
}
}
if (tvs.isEmpty()) {
setResult(newBody);
} else if (tvs.size() == old.getVariables().length
&& newBody == old.getSubformula()) {
setResult(old);
} else {
final Theory t = old.getTheory();
setResult(old.getQuantifier() == QuantifiedFormula.EXISTS
? t.exists(tvs.toArray(
new TermVariable[tvs.size()]), newBody)
: t.forall(tvs.toArray(
new TermVariable[tvs.size()]), newBody));
}
}
}