/*
* Copyright (C) 2009-2012 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.logic;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
/**
* Helper to compute the free variables contained in a term. This class uses
* memoization in the terms to compute the free variables efficiently on DAGs.
* @author hoenicke
*/
public class ComputeFreeVariables extends NonRecursive.TermWalker {
static final TermVariable[] NOFREEVARS = new TermVariable[0];
public ComputeFreeVariables(Term term) {
super(term);
}
@Override
public void walk(NonRecursive walker) {
if (mTerm.mFreeVars != null) {
return;
}
super.walk(walker);
}
@Override
public void walk(NonRecursive walker, final AnnotatedTerm annot) {
walker.enqueueWalker(new NonRecursive.Walker() {
@Override
public void walk(NonRecursive walker) {
annot.mFreeVars = annot.getSubterm().mFreeVars;
}
});
walker.enqueueWalker(new ComputeFreeVariables(annot.getSubterm()));
}
static class AppTermWorker implements NonRecursive.Walker {
final ApplicationTerm mTerm;
public AppTermWorker(ApplicationTerm term) {
mTerm = term;
}
@Override
public void walk(NonRecursive walker) {
final Term[] params = mTerm.getParameters();
if (params.length <= 1) {
if (params.length == 1) {
mTerm.mFreeVars = params[0].mFreeVars;
} else {
mTerm.mFreeVars = ComputeFreeVariables.NOFREEVARS;
}
} else {
int biggestlen = 0;
int biggestidx = -1;
for (int i = 0; i < params.length; i++) {
final TermVariable[] free = params[i].mFreeVars;
if (free.length > biggestlen) {
biggestlen = free.length;
biggestidx = i;
}
}
/* return if term is closed */
if (biggestidx < 0) {
mTerm.mFreeVars = ComputeFreeVariables.NOFREEVARS;
return;
}
List<TermVariable> result = null;
final List<TermVariable> biggestAsList =
Arrays.asList(params[biggestidx].getFreeVars());
for (int i = 0; i < params.length; i++) {
if (i == biggestidx) {
continue;
}
final TermVariable[] free = params[i].getFreeVars();
for (final TermVariable tv : free) {
if (!biggestAsList.contains(tv)) {
if (result == null) {
result = new ArrayList<TermVariable>();
result.addAll(biggestAsList);
}
if (!result.contains(tv)) {
result.add(tv);
}
}
}
}
if (result == null) {
mTerm.mFreeVars = params[biggestidx].getFreeVars();
} else {
mTerm.mFreeVars =
result.toArray(new TermVariable[result.size()]);
}
}
}
@Override
public String toString() {
return "AppTermWalker:" + mTerm.toStringDirect();
}
}
@Override
public void walk(NonRecursive walker,
final ApplicationTerm term) {
walker.enqueueWalker(new AppTermWorker(term));
for (final Term param : ((ApplicationTerm) mTerm).getParameters()) {
walker.enqueueWalker(new ComputeFreeVariables(param));
}
}
@Override
public void walk(NonRecursive walker, ConstantTerm term) {
term.mFreeVars = NOFREEVARS;
}
@Override
public void walk(NonRecursive walker, final LetTerm letTerm) {
walker.enqueueWalker(new NonRecursive.Walker() {
@Override
public void walk(NonRecursive walker) {
final TermVariable[] vars = letTerm.getVariables();
final Term[] vals = letTerm.getValues();
final HashSet<TermVariable> free = new HashSet<TermVariable>();
free.addAll(Arrays.asList(letTerm.getSubTerm().getFreeVars()));
free.removeAll(Arrays.asList(vars));
for (final Term v : vals) {
free.addAll(Arrays.asList(v.getFreeVars()));
}
if (free.isEmpty()) {
letTerm.mFreeVars = NOFREEVARS;
} else {
letTerm.mFreeVars =
free.toArray(new TermVariable[free.size()]);
}
}
});
walker.enqueueWalker(new ComputeFreeVariables(letTerm.getSubTerm()));
for (final Term value : letTerm.getValues()) {
walker.enqueueWalker(new ComputeFreeVariables(value));
}
}
@Override
public void walk(NonRecursive walker, final QuantifiedFormula quant) {
walker.enqueueWalker(new NonRecursive.Walker() {
@Override
public void walk(NonRecursive walker) {
final HashSet<TermVariable> free = new HashSet<TermVariable>();
free.addAll(Arrays.asList(quant.getSubformula().getFreeVars()));
free.removeAll(Arrays.asList(quant.getVariables()));
if (free.isEmpty()) {
quant.mFreeVars = NOFREEVARS;
} else {
quant.mFreeVars =
free.toArray(new TermVariable[free.size()]);
}
}
});
walker.enqueueWalker(new ComputeFreeVariables(quant.getSubformula()));
}
@Override
public void walk(NonRecursive walker, TermVariable term) {
term.mFreeVars = new TermVariable[] {term};
}
}