/* * 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.Arrays; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; import de.uni_freiburg.informatik.ultimate.logic.FormulaUnLet.UnletType; @RunWith(JUnit4.class) public class UnfletTest { Theory mTheory = new Theory(Logics.AUFLIRA); Sort mIntSort = mTheory.getSort("Int"); Sort[] mInt2 = arr(mIntSort, mIntSort); TermVariable mX = mTheory.createTermVariable("x", mIntSort); TermVariable mY = mTheory.createTermVariable("y", mIntSort); TermVariable mZ = mTheory.createTermVariable("z", mIntSort); Term mNum1 = mTheory.numeral("1"); Term mNum2 = mTheory.numeral("2"); FunctionSymbol mPlus = mTheory.getFunction("+", mInt2); Term mSublet = mTheory.let(mX, mNum1, mX); FormulaUnLet mUnletter = new FormulaUnLet(); FormulaUnLet mUnletterLazy = new FormulaUnLet(UnletType.LAZY); FormulaUnLet mUnletterExpand = new FormulaUnLet(UnletType.EXPAND_DEFINITIONS); @SafeVarargs private final <E> E[] arr(E... vals) { return vals; } // NOCHECKSTYLE @Test public void test() { final Term letTerm = mTheory.let(arr(mX, mY), arr(mNum1, mNum2), mTheory.term(mPlus, mX, mY)); Assert.assertEquals("(let ((x 1) (y 2)) (+ x y))", letTerm.toStringDirect()); Assert.assertEquals("(+ 1 2)", mUnletter.unlet(letTerm).toStringDirect()); } @Test public void testScope() { Term letTerm = mTheory.let(mX, mNum2, mTheory.term(mPlus, mTheory.let(mX, mNum1, mX), mX)); Assert.assertEquals("(let ((x 2)) (+ (let ((x 1)) x) x))", letTerm.toStringDirect()); Assert.assertEquals("(+ 1 2)", mUnletter.unlet(letTerm).toStringDirect()); Assert.assertEquals("(+ 1 x)", mUnletter.unlet(((LetTerm) letTerm).getSubTerm()). toStringDirect()); Assert.assertTrue(Arrays.equals(new TermVariable[] {mX}, mUnletter.unlet(((LetTerm) letTerm).getSubTerm()). getFreeVars())); letTerm = mTheory.let(arr(mX, mY), arr(mY, mX), mTheory.term(mPlus, mX, mY)); Assert.assertEquals("(let ((x y) (y x)) (+ x y))", letTerm.toStringDirect()); Assert.assertEquals("(+ y x)", mUnletter.unlet(letTerm).toStringDirect()); letTerm = mTheory.let(mX, mY, mTheory.let(mY, mX, mTheory.term(mPlus, mX, mY))); Assert.assertEquals("(let ((x y)) (let ((y x)) (+ x y)))", letTerm.toStringDirect()); Assert.assertEquals("(+ y y)", mUnletter.unlet(letTerm).toStringDirect()); // This test is broken: the lazy semantics would require non-termination //Assert.assertEquals("(+ x y)", unletterLazy.unlet(letTerm).toStringDirect()); } @Test public void testLazy() { final Term letTerm = mTheory.let(mX, mY, mTheory.let(mY, mNum1, mX)); Assert.assertEquals("(let ((x y)) (let ((y 1)) x))", letTerm.toStringDirect()); Assert.assertEquals("y", mUnletter.unlet(letTerm).toStringDirect()); Assert.assertEquals("1", mUnletterLazy.unlet(letTerm).toStringDirect()); } @Test public void testQuant() { Term letTerm = mTheory.let(mX, mY, mTheory.exists(arr(mX), mTheory.equals(mX, mY))); Assert.assertEquals("(let ((x y)) (exists ((x Int)) (= x y)))", letTerm.toStringDirect()); Assert.assertEquals("(exists ((x Int)) (= x y))", mUnletter.unlet(letTerm).toStringDirect()); letTerm = mTheory.let(arr(mX,mY), arr(mY,mZ), mTheory.exists(arr(mX), mTheory.equals(mX, mY))); Assert.assertEquals("(let ((x y) (y z)) (exists ((x Int)) (= x y)))", letTerm.toStringDirect()); Assert.assertEquals("(exists ((x Int)) (= x z))", mUnletter.unlet(letTerm).toStringDirect()); letTerm = mTheory.let(mY, mX, mTheory.exists(arr(mX), mTheory.equals(mX, mY))); Assert.assertEquals("(let ((y x)) (exists ((x Int)) (= x y)))", letTerm.toStringDirect()); Assert.assertEquals("(exists ((.unlet.0 Int)) (= .unlet.0 x))", mUnletter.unlet(letTerm).toStringDirect()); letTerm = mTheory.let(arr(mX,mY), arr(mY,mZ), mTheory.exists(arr(mY), mTheory.equals(mX, mY))); Assert.assertEquals("(let ((x y) (y z)) (exists ((y Int)) (= x y)))", letTerm.toStringDirect()); final Term unlet = mUnletter.unlet(letTerm); final String varname = ((QuantifiedFormula) unlet).getVariables()[0].toStringDirect(); Assert.assertEquals(".unlet.", varname.substring(0, 7));// NOCHECKSTYLE Assert.assertEquals("(exists ((" + varname + " Int)) (= y " + varname + "))", unlet.toStringDirect()); } @Test public void testAnnotation() { Term letTerm = mTheory.let(mX, mY, mTheory.annotatedTerm( arr(new Annotation(":named", "foo")), mX)); Assert.assertEquals("(let ((x y)) (! x :named foo))", letTerm.toStringDirect()); Assert.assertEquals("(! y :named foo)", mUnletter.unlet(letTerm).toStringDirect()); letTerm = mTheory.let(mX, mZ, mTheory.exists(arr(mY), mTheory.annotatedTerm( arr(new Annotation(":pattern", mTheory.term(mPlus, mX, mY))), mTheory.equals( mTheory.term(mPlus, mX, mY), mNum2)))); Assert.assertEquals("(let ((x z)) (exists ((y Int)) (! (= (+ x y) 2) :pattern (+ x y))))",// NOCHECKSTYLE letTerm.toStringDirect()); Assert.assertEquals("(exists ((y Int)) (! (= (+ z y) 2) :pattern (+ z y)))", mUnletter.unlet(letTerm).toStringDirect()); letTerm = mTheory.let(mX, mZ, mTheory.exists(arr(mY), mTheory.annotatedTerm(arr(new Annotation(":pattern", arr(mTheory.term(mPlus, mX, mY), mTheory.term(mPlus, mY, mX)))), mTheory.equals( mTheory.term(mPlus, mX, mY), mNum2)))); Assert.assertEquals("(let ((x z)) (exists ((y Int)) (! (= (+ x y) 2) :pattern ((+ x y) (+ y x)))))",// NOCHECKSTYLE letTerm.toStringDirect()); Assert.assertEquals("(exists ((y Int)) (! (= (+ z y) 2) :pattern ((+ z y) (+ y z))))", // NOCHECKSTYLE mUnletter.unlet(letTerm).toStringDirect()); } @Test public void testCache() { final Term[] deepTerm = new Term[100];// NOCHECKSTYLE deepTerm[0] = mX; for (int i = 1; i < 100; i++) { deepTerm[i] = mTheory.term(mPlus, deepTerm[i - 1], deepTerm[i - 1]); } int depth = 0; Term unlet = mUnletter.unlet(mTheory.let(mX, mY, deepTerm[99]));// NOCHECKSTYLE // do not even think of calling toStringDirect here... while ((unlet instanceof ApplicationTerm)) { final ApplicationTerm app = (ApplicationTerm) unlet; Assert.assertEquals(mPlus, app.getFunction()); Assert.assertEquals(app.getParameters()[0], app.getParameters()[1]); unlet = app.getParameters()[0]; depth++; } Assert.assertEquals(mY, unlet); Assert.assertEquals(99, depth);// NOCHECKSTYLE final Term plusxy = mTheory.term(mPlus, mX, mY); Term letTerm = mTheory.let(mX, mZ, mTheory.equals( plusxy, mTheory.let(mX, mY, plusxy))); Assert.assertEquals("(let ((x z)) (= (+ x y) (let ((x y)) (+ x y))))", letTerm.toStringDirect()); Assert.assertEquals("(= (+ z y) (+ y y))", mUnletter.unlet(letTerm).toStringDirect()); letTerm = mTheory.equals(mTheory.let(mX, mZ, plusxy), mTheory.let(mX, mY, plusxy)); Assert.assertEquals("(= (let ((x z)) (+ x y)) (let ((x y)) (+ x y)))", letTerm.toStringDirect()); Assert.assertEquals("(= (+ z y) (+ y y))", mUnletter.unlet(letTerm).toStringDirect()); letTerm = mTheory.equals(plusxy, mTheory.let(mX, mY, plusxy)); Assert.assertEquals("(= (+ x y) (let ((x y)) (+ x y)))", letTerm.toStringDirect()); Assert.assertEquals("(= (+ x y) (+ y y))", mUnletter.unlet(letTerm).toStringDirect()); } @Test public void testExpand() { final Term def = mTheory.term(mPlus, mX, mY); final FunctionSymbol plusdef = mTheory.defineFunction("plus", arr(mX, mY), def); final Term defed = mTheory.term(plusdef, mNum1, mNum2); Assert.assertEquals("(plus 1 2)", defed.toStringDirect()); Assert.assertEquals("(+ 1 2)", mUnletterExpand.unlet(defed).toStringDirect()); } }