/* * Copyright (C) 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.smtinterpol.convert; import java.util.HashMap; import java.util.Map; import de.uni_freiburg.informatik.ultimate.logic.ApplicationTerm; import de.uni_freiburg.informatik.ultimate.logic.NonRecursive; import de.uni_freiburg.informatik.ultimate.logic.Term; import de.uni_freiburg.informatik.ultimate.logic.TermVariable; import de.uni_freiburg.informatik.ultimate.logic.Theory; import de.uni_freiburg.informatik.ultimate.smtinterpol.proof.NoopProofTracker; /** * Destructs equalities over quantified variables. This class assumes that the * body of the quantifier is already in or-not-form. Furthermore, it can only * be used to destruct equalities for existentially quantified variables. It * folds equalities into the formula, i.e., it transforms * (exists ((x)(Y)) (not (or (not (= x c)) (not F[x,Y]))) into * (exists ((Y)) F[Y]). * @author Juergen Christ */ public class EqualityDestructor extends NonRecursive { private static final class SearchEqualities implements NonRecursive.Walker { private final Term mTerm; private final boolean mPositive; public SearchEqualities(Term term) { this(term, true); } public SearchEqualities(Term term, boolean positive) { mTerm = term; mPositive = positive; } @Override public void walk(NonRecursive engine) { if (mTerm instanceof ApplicationTerm) { final ApplicationTerm at = (ApplicationTerm) mTerm; if (at.getFunction() == at.getTheory().mNot) { engine.enqueueWalker(new SearchEqualities( at.getParameters()[0], !mPositive)); } else if (!mPositive && at.getFunction() == at.getTheory().mOr) { for (final Term t : at.getParameters()) { engine.enqueueWalker(new SearchEqualities(t, false)); } } else if (at.getFunction().getName().equals("=")) { // An interesting equality? final Term[] args = at.getParameters(); assert args.length == 2; final EqualityDestructor ed = (EqualityDestructor) engine; if (args[0] instanceof TermVariable) { final TermVariable v0 = (TermVariable) args[0]; if (args[1] instanceof TermVariable) { final TermVariable v1 = (TermVariable) args[1]; // This cannot happen due to simplification // if (v0 == v1) // return; if (ed.mEqs.containsKey(v0)) { if (ed.mEqs.containsKey(v1)) { // We are already rewriting v0, v1 // Skip this equality. return; } // Rewrite v1 to the same value we are // rewriting v0 ed.mEqs.put(v1, ed.mEqs.get(v0)); } else if (ed.mEqs.containsKey(v1)) { // See above ed.mEqs.put(v0, ed.mEqs.get(v1)); } else { // Use one variable from now on ed.mEqs.put(v1, v0); } } else { // (= x c) checkVariable(ed, v0, args[1]); } } else if (args[1] instanceof TermVariable) { // (= c x) final TermVariable v1 = (TermVariable) args[1]; checkVariable(ed, v1, args[0]); } } // Not interesting... } } private void checkVariable(EqualityDestructor ed, TermVariable var, Term val) { // rewrite loop check // FIXME: This is ugly final TermVariable[] freeVars = SMTAffineTerm.cleanup(val).getFreeVars(); for (final TermVariable v : freeVars) { if (v == var) { return; } } if (!ed.mEqs.containsKey(var)) { ed.mEqs.put(var, val); } } } private final Map<TermVariable, Term> mEqs = new HashMap<TermVariable, Term>(); public Term destruct(Term qbody) { run(new SearchEqualities(qbody)); return new InternTermTransformer() { Utils mUtils = new Utils(new NoopProofTracker()); @Override protected void convert(Term term) { if (term instanceof TermVariable) { final Term replacement = mEqs.get(term); if (replacement != null) { setResult(replacement); return; } } super.convert(term); } @Override public void convertApplicationTerm(ApplicationTerm appTerm, Term[] newArgs) { if (newArgs == appTerm.getParameters()) { setResult(appTerm); } else { final Theory t = appTerm.getTheory(); if (appTerm.getFunction() == t.mNot) { setResult(mUtils.createNot(newArgs[0])); } else if (appTerm.getFunction() == t.mOr) { setResult(mUtils.createOr(newArgs)); } else if (appTerm.getFunction().getName().equals("=")) { setResult(mUtils.createEq(newArgs)); } else if (appTerm.getFunction().getName().equals("<=")) { setResult(mUtils.createLeq0(newArgs[0])); } else if (appTerm.getFunction().getName().equals("ite")) { setResult(mUtils.createIte( newArgs[0], newArgs[1], newArgs[2])); } else { assert !appTerm.getFunction().isIntern(); setResult(t.term(appTerm.getFunction(), newArgs)); } } } }.transform(qbody); } }