/* * 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.smtinterpol.convert; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.Set; 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.Logics; import de.uni_freiburg.informatik.ultimate.logic.NoopScript; import de.uni_freiburg.informatik.ultimate.logic.QuantifiedFormula; import de.uni_freiburg.informatik.ultimate.logic.SMTLIBException; import de.uni_freiburg.informatik.ultimate.logic.Script; import de.uni_freiburg.informatik.ultimate.logic.Sort; import de.uni_freiburg.informatik.ultimate.logic.Term; import de.uni_freiburg.informatik.ultimate.logic.TermVariable; import de.uni_freiburg.informatik.ultimate.smtinterpol.Config; import de.uni_freiburg.informatik.ultimate.smtinterpol.DefaultLogger; import de.uni_freiburg.informatik.ultimate.smtinterpol.LogProxy; @RunWith(JUnit4.class) public class InferenceTest { private final Script mScript; private final Set<TermVariable> mTvs; // (g (ite (P&Q) x y)) private final Term mTopLevel; // P&(g (ite (P&Q) x y)) private final Term mSubLevel; // (g (f (ite (P&Q) x y) (ite (P||Q) y x))) private final Term mDouble; // (g (ite (P&Q) x (ite (P||Q) y x))) private final Term mNested; public InferenceTest() throws SMTLIBException { mScript = new NoopScript(); mScript.setLogic(Logics.AUFLIA); // ITE-Lifting mScript.declareSort("U", 0); final Sort u = mScript.sort("U"); final Sort[] binU = new Sort[] { u,u }; final Sort[] singU = new Sort[] { u }; final Sort[] emptysorts = new Sort[0]; final Sort bool = mScript.sort("Bool"); mScript.declareFun("f", binU, u); mScript.declareFun("g", singU, bool); final TermVariable x = mScript.variable("x", u); final TermVariable y = mScript.variable("y", u); mScript.declareFun("P", emptysorts, bool); mScript.declareFun("Q", emptysorts, bool); final Term pandq = mScript.term("and", mScript.term("P"), mScript.term("Q")); final Term porq = mScript.term("or", mScript.term("P"), mScript.term("Q")); final Term ite1 = mScript.term("ite", pandq, x, y); final Term ite2 = mScript.term("ite", porq, y, x); mTopLevel = mScript.term("g",ite1); mSubLevel = mScript.term("and", mScript.term("P"),mTopLevel); mDouble = mScript.term("g",mScript.term("f",ite1,ite2)); mNested = mScript.term("g",mScript.term("ite", pandq, x, ite2)); mTvs = new HashSet<TermVariable>(); mTvs.add(x); mTvs.add(y); } @Test public void testITELifting() { final InferencePreparation ip = new InferencePreparation(mTopLevel.getTheory(),mTvs); Assert.assertEquals("(ite (and P Q) (g x) (g y))", ip.prepare(mTopLevel).toStringDirect()); Assert.assertEquals("(and P (ite (and P Q) (g x) (g y)))", ip.prepare(mSubLevel).toStringDirect()); Assert.assertEquals("(ite (and P Q) (ite (or P Q) (g (f x y)) (g (f x x))) (ite (or P Q) (g (f y y)) (g (f y x))))",// NOCHECKSTYLE ip.prepare(mDouble).toStringDirect()); Assert.assertEquals("(ite (and P Q) (g x) (ite (or P Q) (g y) (g x)))", ip.prepare(mNested).toStringDirect()); } @Test public void testPatternInference() { // Pattern inference final Sort bool = mScript.sort("Bool"); final Sort u = mScript.sort("U"); final Sort[] binU = new Sort[] { u,u }; final Sort[] singU = new Sort[] { u }; final TermVariable x = mScript.variable("x", u); final TermVariable y = mScript.variable("y", u); final TermVariable z = mScript.variable("z", u); mScript.declareFun("T", binU, bool); mScript.declareFun("h", singU, u); mScript.declareFun("k", singU, u); Term loopingtrig, nonloopingtrig; // (forall ((x U)) (T (h x) (h (k x)))) Simplify tech report page 44 final Term looping = mScript.quantifier(Script.FORALL, new TermVariable[]{x}, mScript.term("T", loopingtrig = mScript.term("h",x), mScript.term("h", nonloopingtrig = mScript.term("k",x)))); final Set<TermVariable> singleX = Collections.singleton(x); Term c, p1, p2; // (forall ((x U) (y U) (z U)) (implies (and (T x y) (T y z)) (T x z))) final Term transitivity = mScript.quantifier(Script.FORALL, new TermVariable[]{x,y,z}, mScript.term("=>", mScript.term("and", p1 = mScript.term("T",x,y), p2 = mScript.term("T",y,z)), c = mScript.term("T",x,z))); final Set<TermVariable> transitivityVars = new HashSet<TermVariable>(); transitivityVars.add(x); transitivityVars.add(y); transitivityVars.add(z); mScript.declareFun("a", new Sort[0], u); final Term fa = mScript.term("a"); // (forall ((x U)) (and (T a a) (T a x))) Term constTrig; final Term partiallyConstant = mScript.quantifier(Script.FORALL, new TermVariable[]{x}, mScript.term("and", mScript.term("T",fa,fa), constTrig = mScript.term("T",fa,x))); // (forall ((i1 Int) (i2 Int)) (= (+ (* 3 i1) (* 5 i2)) 0)) final Sort intSort = mScript.sort("Int"); final TermVariable i1 = mScript.variable("i1", intSort); final TermVariable i2 = mScript.variable("i2", intSort); // (forall ((i1 Int) (i2 Int)) (= (+ (* 3 i1) (* 5 i2)) 0)) final Term notrig = mScript.quantifier(Script.FORALL, new TermVariable[]{i1,i2}, mScript.term("=", mScript.term("+", mScript.term("*", mScript.numeral("3"), i1), mScript.term("*", mScript.numeral("5"), i2)), mScript.numeral("0"))); final Set<TermVariable> intvars = new HashSet<TermVariable>(); intvars.add(i1); intvars.add(i2); mScript.declareFun("fi", new Sort[]{intSort}, intSort); // (forall ((i1 Int)) (= (fi (+ (* 3 i1) 7)) 5)) final Term notrigcomb = mScript.quantifier(Script.FORALL, new TermVariable[]{i1}, mScript.term("=", mScript.term("fi", mScript.term("+", mScript.term("*", mScript.numeral("3"), i1), mScript.numeral("7"))), mScript.numeral("10"))); final Set<TermVariable> int1 = Collections.singleton(i1); final LogProxy logger = new DefaultLogger(); final TriggerCandidateMap candidates = new TriggerCandidateMap( logger,mTopLevel.getTheory(),singleX); candidates.insert(((QuantifiedFormula)looping).getSubformula()); Term[] units = candidates.getAllUnitTriggers(); // This formula has at least one unit-trigger Assert.assertNotNull(units); logger.info("For " + looping + " I inferred unit triggers " + Arrays.toString(units)); final int expectedLength = Config.FEATURE_BLOCK_LOOPING_PATTERN ? 1 : 2; final Set<Term> unitSet = new HashSet<Term>(expectedLength,1.0f); for (final Term t : units) { unitSet.add(t); } Assert.assertEquals(expectedLength,unitSet.size()); Assert.assertTrue("Did not infer nonlooping trigger (k x)", unitSet.contains(nonloopingtrig)); if (!Config.FEATURE_BLOCK_LOOPING_PATTERN) { Assert.assertTrue("Did not infer looping trigger (h x) although I should", unitSet.contains(loopingtrig)); } candidates.reinit(transitivityVars); candidates.insert(((QuantifiedFormula)transitivity).getSubformula()); units = candidates.getAllUnitTriggers(); // This formula only has multi-triggers Assert.assertNull(units); Term[] multi = candidates.getMultiTrigger(); Assert.assertNotNull(multi); logger.info("For " + transitivity + " I inferred multi trigger " + Arrays.toString(multi)); final Set<Term> multiSet = new HashSet<Term>(2,1.0f); for (final Term t : multi) { multiSet.add(t); } Assert.assertEquals(2, multiSet.size()); final Iterator<Term> it = multiSet.iterator(); final Term first = it.next(); final Term second = it.next(); if (first == p1) { Assert.assertTrue("Wrong multi trigger", second == p2 || second == c); } else if (first == p2) { Assert.assertTrue("Wrong multi trigger", second == p1 || second == c); } else if (first == c) { Assert.assertTrue("Wrong multi trigger", second == p1 || second == p2); } candidates.reinit(singleX); candidates.insert( ((QuantifiedFormula)partiallyConstant).getSubformula()); units = candidates.getAllUnitTriggers(); Assert.assertNotNull(units); logger.info("For " + partiallyConstant + " I inferred unit triggers " + Arrays.toString(units)); Assert.assertEquals(1, units.length); Assert.assertEquals(constTrig, units[0]); candidates.reinit(intvars); candidates.insert(((QuantifiedFormula)notrig).getSubformula()); units = candidates.getAllUnitTriggers(); Assert.assertNull("Did infer unit-triggers where none exists: " + Arrays.toString(units), units); multi = candidates.getMultiTrigger(); Assert.assertNull("Did infer a multi trigger where none exists: " + Arrays.toString(multi), multi); candidates.reinit(int1); candidates.insert(((QuantifiedFormula)notrigcomb).getSubformula()); units = candidates.getAllUnitTriggers(); Assert.assertNull("Did infer unit-triggers where none exists: " + Arrays.toString(units), units); multi = candidates.getMultiTrigger(); Assert.assertNull("Did infer a multi trigger where none exists: " + Arrays.toString(multi),multi); } }