/* * 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.util.ArrayDeque; import java.util.ArrayList; 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.CheckClosedTerm; 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.Term; import de.uni_freiburg.informatik.ultimate.logic.TermVariable; import de.uni_freiburg.informatik.ultimate.logic.Theory; public class SubstitutionApplier extends NonRecursive { private final class AnnotationBuilder implements Walker { private final AnnotatedTerm mTerm; public AnnotationBuilder(AnnotatedTerm term) { mTerm = term; } @Override public void walk(NonRecursive engine) { final Term converted = mConverted.pop(); final Term res = converted.getTheory().annotatedTerm( mTerm.getAnnotations(), converted); mConverted.push(res); } } private final class ApplicationTermBuilder implements Walker { private final ApplicationTerm mTerm; public ApplicationTermBuilder(ApplicationTerm term) { mTerm = term; } @Override public void walk(NonRecursive engine) { final Term[] newArgs = new Term[mTerm.getParameters().length]; for (int i = 0; i < newArgs.length; ++i) { newArgs[i] = mConverted.pop(); } final Term res = mTerm.getTheory().term(mTerm.getFunction(), newArgs); mConverted.push(res); } } private final class LetBuilder implements Walker { private final LetTerm mTerm; public LetBuilder(LetTerm term) { mTerm = term; } @Override public void walk(NonRecursive engine) { final Term[] newVals = new Term[mTerm.getValues().length]; for (int i = 0; i < newVals.length; ++i) { newVals[i] = mConverted.pop(); } final Term subform = mConverted.pop(); final Term res = new CheckClosedTerm().isClosed(subform) ? subform : mTerm.getTheory().let( mTerm.getVariables(), newVals, subform); mConverted.push(res); } } private final class QuantifierBuilder implements Walker { private final QuantifiedFormula mTerm; public QuantifierBuilder(QuantifiedFormula term) { mTerm = term; } @Override public void walk(NonRecursive engine) { final Term subform = mConverted.pop(); final Theory t = mTerm.getTheory(); final Term res = new CheckClosedTerm().isClosed(subform) ? subform : mTerm.getQuantifier() == QuantifiedFormula.EXISTS ? t.exists(mTerm.getVariables(), subform) : t.forall(mTerm.getVariables(), subform); mConverted.push(res); } } private final class DepthDescender extends TermWalker { private final int mDepth; public DepthDescender(Term term, int depth) { super(term); mDepth = depth; } @Override public void walk(NonRecursive walker) { if (mDepth == SubstitutionApplier.this.mDepth) { // Apply substitution final boolean expectedTrue = mIt.hasNext(); assert expectedTrue; if (mSubst != null && mSubst.matches(getTerm())) { if (mSubst.isActive()) { mConverted.push(mSubst.apply(getTerm())); final Cmd add = mSubst.getAdditionalCmd(getTerm()); if (add != null) { mAdds.add(add); } } else { mConverted.push(getTerm()); } // We can step here since we found a (possibly deactivated) // match. If the term does not match, we should not step! stepSubst(); } else { // We don't need to descend since we will never change // anything at lower depths. mConverted.push(getTerm()); } } else { super.walk(walker); } } @Override public void walk(NonRecursive walker, ConstantTerm term) { mConverted.push(term); } @Override public void walk(NonRecursive walker, AnnotatedTerm term) { walker.enqueueWalker(new AnnotationBuilder(term)); walker.enqueueWalker( new DepthDescender(term.getSubterm(), mDepth + 1)); } @Override public void walk(NonRecursive walker, ApplicationTerm term) { walker.enqueueWalker(new ApplicationTermBuilder(term)); for (final Term p : term.getParameters()) { walker.enqueueWalker(new DepthDescender(p, mDepth + 1)); } } @Override public void walk(NonRecursive walker, LetTerm term) { walker.enqueueWalker(new LetBuilder(term)); for (final Term v : term.getValues()) { walker.enqueueWalker(new DepthDescender(v, mDepth + 1)); } walker.enqueueWalker( new DepthDescender(term.getSubTerm(), mDepth + 1)); } @Override public void walk(NonRecursive walker, QuantifiedFormula term) { walker.enqueueWalker(new QuantifierBuilder(term)); walker.enqueueWalker( new DepthDescender(term.getSubformula(), mDepth + 1)); } @Override public void walk(NonRecursive walker, TermVariable term) { mConverted.push(term); } } private int mDepth; private List<Substitution> mSubsts;// NOPMD private Iterator<Substitution> mIt; private Substitution mSubst; private final ArrayDeque<Term> mConverted = new ArrayDeque<Term>(); private List<Cmd> mAdds = new ArrayList<Cmd>(); void stepSubst() { while (mIt.hasNext()) { mSubst = mIt.next(); if (!mSubst.isSuccess()) { return; } } mSubst = null; } public void init(int depth, List<Substitution> substs) { mDepth = depth; mSubsts = substs; mIt = mSubsts.iterator(); stepSubst(); } public Term apply(Term term) { run(new DepthDescender(term, 0)); return mConverted.pop(); } public List<Cmd> getAdds() { final List<Cmd> res = mAdds; mAdds = new ArrayList<Cmd>(); return res; } }