/* * 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.List; import de.uni_freiburg.informatik.ultimate.logic.AnnotatedTerm; import de.uni_freiburg.informatik.ultimate.logic.Annotation; import de.uni_freiburg.informatik.ultimate.logic.ApplicationTerm; import de.uni_freiburg.informatik.ultimate.logic.Term; import de.uni_freiburg.informatik.ultimate.logic.Theory; public class SubstitutionManager { private int mDepth = -1; private List<Substitution> mSubsts; private final AbstractOneTermCmd mCmd; private final boolean mUnletRelet; public SubstitutionManager(AbstractOneTermCmd cmd, boolean unletRelet) { mCmd = cmd; mUnletRelet = unletRelet; } public boolean deepen() { ++mDepth; return computeSubsts(); } /** * Notification of a test failure. Steps all substitutions one step further * and, hence, misses some of the potentially exponentially many * substitutions. * @return Does this depth still has some substitutions? */ public boolean failed() { stepSubsts(); return !mSubsts.isEmpty(); } private Substitution getSubstition(Term t) { if (t instanceof AnnotatedTerm) { final AnnotatedTerm at = (AnnotatedTerm) t; for (final Annotation a : at.getAnnotations()) { if (a.getKey().equals(":named")) { // Cannot substitute at this level return null; } } // No names => Ignore annotations return new ReplaceByTerm(t, at.getSubterm(), true); } else if (t.getSort() == t.getTheory().getBooleanSort()) { // Try to replace by true return new ReplaceByTerm(t, t.getTheory().mTrue, true); } else if (t.getSort().isNumericSort()) { return new ReplaceByTerm(t, t.getSort().getName().equals("Int") ? t.getTheory().numeral(BigInteger.ZERO) : t.getTheory().decimal(BigDecimal.ZERO), true); } else if (t instanceof ApplicationTerm) { // I guess this is always the case... final ApplicationTerm at = (ApplicationTerm) t; if (at.getParameters().length > 0) { if (at.getFunction().getName().equals("store")) { return new ReplaceByTerm(t, at.getParameters()[0], true); } return ReplaceByFreshTerm.isFreshTerm(at) ? null : new ReplaceByFreshTerm(t); } } // Cannot replace TermVariables or ConstantTerms return null; } private Substitution getNextSubstitution(Substitution subst) { final Term t = subst.getMatch(); if (subst instanceof ReplaceByFreshTerm) { final ApplicationTerm at = (ApplicationTerm) t; if (at.getFunction().getName().equals("ite")) { return new ReplaceByTerm(t, at.getParameters()[1], true, false); } return null; } final ReplaceByTerm r = (ReplaceByTerm) subst; if (t instanceof AnnotatedTerm) { assert r.getReplacement() == ((AnnotatedTerm) t).getSubterm(); return null; } final Theory theory = t.getTheory(); if (r.getReplacement() == theory.mTrue && r.isNeutralReplacement()) { return new ReplaceByTerm(t, theory.mFalse, true); } if (r.getReplacement() == theory.mFalse && r.isNeutralReplacement()) { if (t instanceof ApplicationTerm) { final ApplicationTerm at = (ApplicationTerm) t; // replace f-app if (at.getParameters().length > 0) { return new ReplaceByFreshTerm(t); } } // application term // give up return null; } else if (t instanceof ApplicationTerm) { // Can be either neutrals or ite or store final ApplicationTerm at = (ApplicationTerm) t; if (at.getFunction().getName().equals("ite")) { if (r.getReplacement() == at.getParameters()[1]) { return new ReplaceByTerm(t, at.getParameters()[2], true, false); } else if (!r.isNeutralReplacement() || r.getReplacement() == at.getParameters()[2]) { return null; } } else if (at.getFunction().getName().equals("store") && r.getReplacement() == at.getParameters()[0]) { return new ReplaceByFreshTerm(t); } if (at.getParameters().length > 0) { return new ReplaceByFreshTerm(t); } } return null; } private boolean computeSubsts() { final TermCollector tc = new TermCollector(mDepth); tc.add(mCmd.getTerm(mUnletRelet)); final List<Term> found = tc.getTerms(); mSubsts = new ArrayList<Substitution>(found.size()); for (final Term t : found) { final Substitution subst = getSubstition(t); if (subst != null) { mSubsts.add(subst); } } return !found.isEmpty(); } private void stepSubsts() { final List<Substitution> old = mSubsts; mSubsts = new ArrayList<Substitution>(old.size()); for (final Substitution cur : old) { if (cur.isActive()) { if (cur.isRecurse()) { final Substitution rec = getSubstition( ((ReplaceByTerm) cur).getReplacement()); if (rec != null) { mSubsts.add(rec); } } continue; } final Substitution next = getNextSubstitution(cur); if (next != null) { mSubsts.add(next); } } } public List<Substitution> getSubstitutions() { return mSubsts; } public int getDepth() { return mDepth; } }