/* * 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.proof; import java.util.ArrayDeque; import java.util.HashSet; import java.util.Queue; 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.Term; import de.uni_freiburg.informatik.ultimate.logic.Theory; import de.uni_freiburg.informatik.ultimate.smtinterpol.dpll.Clause; import de.uni_freiburg.informatik.ultimate.smtinterpol.dpll.DPLLAtom; import de.uni_freiburg.informatik.ultimate.smtinterpol.dpll.Literal; import de.uni_freiburg.informatik.ultimate.smtinterpol.proof.ResolutionNode.Antecedent; import de.uni_freiburg.informatik.ultimate.smtinterpol.proof.Transformations.AvailableTransformations; @RunWith(JUnit4.class) public class RPITest { private static class ProofDAGCheck { private final ArrayDeque<Clause> mTodo = new ArrayDeque<Clause>(); private HashSet<Clause> mSeen; public boolean check(Queue<Clause> expected, Clause proof) { mSeen = new HashSet<Clause>(); mTodo.add(proof); while (!mTodo.isEmpty()) { final Clause tmp = mTodo.pop(); final Clause exp = expected.poll(); if (!clauseEqual(tmp, exp)) { System.err.println("Expected " + exp); System.err.println("Got " + tmp); return false; } if (mSeen.add(tmp)) { final ProofNode pn = tmp.getProof(); if (!pn.isLeaf()) { final ResolutionNode rn = (ResolutionNode) pn; mTodo.push(rn.getPrimary()); for (final Antecedent a : rn.getAntecedents()) { mTodo.push(a.mAntecedent); } } } } return true; } private static final boolean clauseEqual(Clause c1, Clause c2) { if (c1.getSize() != c2.getSize()) { return false; } final HashSet<Literal> l1 = new HashSet<Literal>(); for (int i = 0; i < c1.getSize(); ++i) { l1.add(c1.getLiteral(i)); } for (int i = 0; i < c2.getSize(); ++i) { if (!l1.remove(c2.getLiteral(i))) { return false; } } return l1.isEmpty(); } } private static class DummyAtom extends DPLLAtom { private final String mName; public DummyAtom(String name) { super(name.hashCode(), 0); mName = name; } @Override public Term getSMTFormula(Theory smtTheory, boolean quoted) { throw new InternalError("Bug in testcase"); } @Override public String toString() { return mName; } } DPLLAtom mA,mB,mC,mD; Clause[] mEtas; public RPITest() { mA = new DummyAtom("a"); mB = new DummyAtom("b"); mC = new DummyAtom("c"); mD = new DummyAtom("d"); mEtas = new Clause[] { new Clause(new Literal[] {mA.negate()}), new Clause(new Literal[] {mA,mC,mB.negate()}), new Clause(new Literal[] {mA,mB}), new Clause(new Literal[] {mB}), new Clause(new Literal[] {mA,mC}), new Clause(new Literal[] {mC}), new Clause(new Literal[] {mA,mB.negate(),mC.negate()}), new Clause(new Literal[] {mA,mC.negate()}), new Clause(new Literal[] {mC.negate()}) }; } @Test public void testRPIPaperExample() { // Build proof mEtas[0].setProof(new LeafNode(LeafNode.NO_THEORY, new SourceAnnotation("eta1", null))); mEtas[1].setProof(new LeafNode(LeafNode.NO_THEORY, new SourceAnnotation("eta2", null))); mEtas[2].setProof(new LeafNode(LeafNode.NO_THEORY, new SourceAnnotation("eta3", null))); mEtas[6].setProof(new LeafNode(LeafNode.NO_THEORY,// NOCHECKSTYLE new SourceAnnotation("eta7", null))); mEtas[3].setProof(new ResolutionNode(// NOCHECKSTYLE mEtas[0], new Antecedent[] {new Antecedent(mA, mEtas[2])}));// NOCHECKSTYLE mEtas[4].setProof(new ResolutionNode(// NOCHECKSTYLE mEtas[1], new Antecedent[] {new Antecedent(mB, mEtas[3])}));// NOCHECKSTYLE mEtas[5].setProof(new ResolutionNode(// NOCHECKSTYLE mEtas[0], new Antecedent[] {new Antecedent(mA, mEtas[4])}));// NOCHECKSTYLE // Spare etas[7] by proof compression mEtas[8].setProof(new ResolutionNode(// NOCHECKSTYLE mEtas[3], new Antecedent[] {// NOCHECKSTYLE new Antecedent(mB.negate(), mEtas[6]),// NOCHECKSTYLE new Antecedent(mA.negate(), mEtas[0])})); final Clause empty = new Clause(new Literal[0], new ResolutionNode(mEtas[5],// NOCHECKSTYLE new Antecedent[] { new Antecedent(mC.negate(), mEtas[8])}));// NOCHECKSTYLE final Clause transformed = AvailableTransformations.RPI.transform(empty); final ProofDAGCheck pdc = new ProofDAGCheck(); // Sanity check final Queue<Clause> input = new ArrayDeque<Clause>(); input.add(empty); input.add(mEtas[8]);// NOCHECKSTYLE input.add(mEtas[0]); input.add(mEtas[6]);// NOCHECKSTYLE input.add(mEtas[3]);// NOCHECKSTYLE input.add(mEtas[2]); input.add(mEtas[0]); input.add(mEtas[5]);// NOCHECKSTYLE input.add(mEtas[4]);// NOCHECKSTYLE input.add(mEtas[3]);// NOCHECKSTYLE input.add(mEtas[1]); input.add(mEtas[0]); final boolean checkDAGCheck = pdc.check(input, empty); Assert.assertTrue(checkDAGCheck); input.clear(); input.add(empty); input.add(mEtas[8]);// NOCHECKSTYLE input.add(mEtas[0]); input.add(mEtas[6]);// NOCHECKSTYLE input.add(mEtas[2]); input.add(mEtas[5]);// NOCHECKSTYLE input.add(mEtas[4]);// NOCHECKSTYLE input.add(mEtas[2]); input.add(mEtas[1]); input.add(mEtas[0]); final boolean check = new ProofDAGCheck().check(input, transformed); Assert.assertTrue(check); } @Test public void testRPIPaperMod() { // Build proof mEtas[0].setProof(new LeafNode(LeafNode.NO_THEORY, new SourceAnnotation("eta1", null))); mEtas[1].setProof(new LeafNode(LeafNode.NO_THEORY, new SourceAnnotation("eta2", null))); mEtas[2].setProof(new LeafNode(LeafNode.NO_THEORY, new SourceAnnotation("eta3", null))); mEtas[6].setProof(new LeafNode(LeafNode.NO_THEORY,// NOCHECKSTYLE new SourceAnnotation("eta7", null))); mEtas[3].setProof(new ResolutionNode(// NOCHECKSTYLE mEtas[0], new Antecedent[] {new Antecedent(mA, mEtas[2])})); mEtas[4].setProof(new ResolutionNode(// NOCHECKSTYLE mEtas[0], new Antecedent[] {new Antecedent(mA, mEtas[2]), new Antecedent(mB.negate(), mEtas[1])})); // etas[5].setProof(new ResolutionNode( // etas[0], new Antecedent[] {new Antecedent(a, etas[4])})); // Spare etas[7] by proof compression mEtas[8].setProof(new ResolutionNode(// NOCHECKSTYLE mEtas[3], new Antecedent[] {// NOCHECKSTYLE new Antecedent(mB.negate(), mEtas[6]),// NOCHECKSTYLE new Antecedent(mA.negate(), mEtas[0])})); final Antecedent[] antes = new Antecedent[] { new Antecedent(mA.negate(), mEtas[0]), new Antecedent(mC.negate(), mEtas[8])// NOCHECKSTYLE }; final Clause empty = new Clause(new Literal[0], new ResolutionNode(mEtas[4],// NOCHECKSTYLE antes)); final Clause transformed = AvailableTransformations.RPI.transform(empty); final ProofDAGCheck pdc = new ProofDAGCheck(); // Sanity check final Queue<Clause> input = new ArrayDeque<Clause>(); input.add(empty); input.add(mEtas[8]);// NOCHECKSTYLE input.add(mEtas[0]); input.add(mEtas[6]);// NOCHECKSTYLE input.add(mEtas[3]);// NOCHECKSTYLE input.add(mEtas[2]); input.add(mEtas[0]); input.add(mEtas[0]); input.add(mEtas[4]);// NOCHECKSTYLE input.add(mEtas[1]); input.add(mEtas[2]); input.add(mEtas[0]); final boolean checkDAGCheck = pdc.check(input, empty); Assert.assertTrue(checkDAGCheck); input.clear(); input.add(empty); input.add(mEtas[8]);// NOCHECKSTYLE input.add(mEtas[0]); input.add(mEtas[6]);// NOCHECKSTYLE input.add(mEtas[2]); input.add(mEtas[0]); input.add(mEtas[4]);// NOCHECKSTYLE input.add(mEtas[1]); input.add(mEtas[2]); final boolean check = new ProofDAGCheck().check(input, transformed); Assert.assertTrue(check); } @Test public void testRPIPaperModElimEta4() { // Build proof mEtas[0].setProof(new LeafNode(LeafNode.NO_THEORY, new SourceAnnotation("eta1", null))); mEtas[1].setProof(new LeafNode(LeafNode.NO_THEORY, new SourceAnnotation("eta2", null))); mEtas[2].setProof(new LeafNode(LeafNode.NO_THEORY, new SourceAnnotation("eta3", null))); mEtas[6].setProof(new LeafNode(LeafNode.NO_THEORY,// NOCHECKSTYLE new SourceAnnotation("eta7", null))); // etas[3].setProof(new ResolutionNode( // etas[0], new Antecedent[] {new Antecedent(a, etas[2])})); mEtas[4].setProof(new ResolutionNode(// NOCHECKSTYLE mEtas[0], new Antecedent[] {new Antecedent(mA, mEtas[2]), new Antecedent(mB.negate(), mEtas[1])})); // etas[5].setProof(new ResolutionNode( // etas[0], new Antecedent[] {new Antecedent(a, etas[4])})); mEtas[7].setProof(new ResolutionNode(mEtas[0], new Antecedent[] {// NOCHECKSTYLE new Antecedent(mA, mEtas[2]), new Antecedent(mB.negate(), mEtas[6])// NOCHECKSTYLE })); mEtas[8].setProof(new ResolutionNode(// NOCHECKSTYLE mEtas[7], new Antecedent[] {// NOCHECKSTYLE new Antecedent(mA.negate(), mEtas[0]) })); final Antecedent[] antes = new Antecedent[] { new Antecedent(mA.negate(), mEtas[0]), new Antecedent(mC.negate(), mEtas[8])// NOCHECKSTYLE }; final Clause empty = new Clause(new Literal[0], new ResolutionNode(mEtas[4],// NOCHECKSTYLE antes)); final Clause transformed = AvailableTransformations.RPI.transform(empty); final ProofDAGCheck pdc = new ProofDAGCheck(); // Sanity check final Queue<Clause> input = new ArrayDeque<Clause>(); input.add(empty); input.add(mEtas[8]);// NOCHECKSTYLE input.add(mEtas[0]); input.add(mEtas[7]);// NOCHECKSTYLE input.add(mEtas[6]);// NOCHECKSTYLE input.add(mEtas[2]); input.add(mEtas[0]); input.add(mEtas[0]); input.add(mEtas[4]);// NOCHECKSTYLE input.add(mEtas[1]); input.add(mEtas[2]); input.add(mEtas[0]); final boolean checkDAGCheck = pdc.check(input, empty); Assert.assertTrue(checkDAGCheck); input.clear(); input.add(empty); input.add(mEtas[8]);// NOCHECKSTYLE input.add(mEtas[0]); input.add(mEtas[7]);// NOCHECKSTYLE input.add(mEtas[6]);// NOCHECKSTYLE input.add(mEtas[2]); input.add(mEtas[0]); input.add(mEtas[4]);// NOCHECKSTYLE input.add(mEtas[1]); input.add(mEtas[2]); final boolean check = new ProofDAGCheck().check(input, transformed); Assert.assertTrue(check); } @Test public void testNewExample() { final Clause nega = new Clause(new Literal[]{mA.negate()}, new LeafNode(LeafNode.NO_THEORY, new SourceAnnotation("nega", null))); final Clause negb = new Clause(new Literal[]{mB.negate()}, new LeafNode(LeafNode.NO_THEORY, new SourceAnnotation("negb", null))); final Clause ab = new Clause(new Literal[]{mA, mB}, new LeafNode(LeafNode.NO_THEORY, new SourceAnnotation("ab", null))); final Clause negbc = new Clause(new Literal[]{mB.negate(), mC}, new LeafNode(LeafNode.NO_THEORY, new SourceAnnotation("negbc", null))); final Clause bnegc = new Clause(new Literal[]{mB, mC.negate()}, new LeafNode(LeafNode.NO_THEORY, new SourceAnnotation("bnegc", null))); final Clause ac = new Clause(new Literal[]{mA, mC}, new ResolutionNode(ab, new Antecedent[] { new Antecedent(mB.negate(), negbc) })); final Clause empty = new Clause(new Literal[0], new ResolutionNode(bnegc, new Antecedent[] { new Antecedent(mC, ac), new Antecedent(mB.negate(), negb), new Antecedent(mA.negate(), nega) })); final Clause transformed = AvailableTransformations.RPI.transform(empty); final ProofDAGCheck pdc = new ProofDAGCheck(); // Sanity check final Queue<Clause> input = new ArrayDeque<Clause>(); input.add(empty); input.add(nega); input.add(negb); input.add(ac); input.add(negbc); input.add(ab); input.add(bnegc); final boolean checkDAGCheck = pdc.check(input, empty); Assert.assertTrue(checkDAGCheck); input.clear(); input.add(empty); input.add(nega); input.add(negb); input.add(ab); final boolean check = new ProofDAGCheck().check(input, transformed); Assert.assertTrue(check); } @Test public void testNewExample2() { final Clause nega = new Clause(new Literal[]{mA.negate()}, new LeafNode(LeafNode.NO_THEORY, new SourceAnnotation("nega", null))); final Clause negb = new Clause(new Literal[]{mB.negate()}, new LeafNode(LeafNode.NO_THEORY, new SourceAnnotation("negb", null))); final Clause ab = new Clause(new Literal[]{mA, mB}, new LeafNode(LeafNode.NO_THEORY, new SourceAnnotation("ab", null))); final Clause negbc = new Clause(new Literal[]{mB.negate(), mC}, new LeafNode(LeafNode.NO_THEORY, new SourceAnnotation("negbc", null))); final Clause bnegc = new Clause(new Literal[]{mB, mC.negate()}, new LeafNode(LeafNode.NO_THEORY, new SourceAnnotation("bnegc", null))); final Clause ac = new Clause(new Literal[]{mA, mC}, new ResolutionNode(ab, new Antecedent[] { new Antecedent(mB.negate(), negbc) })); final Clause empty = new Clause(new Literal[0], new ResolutionNode(ac, new Antecedent[] { new Antecedent(mC.negate(), bnegc), new Antecedent(mB.negate(), negb), new Antecedent(mA.negate(), nega) })); final Clause transformed = AvailableTransformations.RPI.transform(empty); final ProofDAGCheck pdc = new ProofDAGCheck(); // Sanity check final Queue<Clause> input = new ArrayDeque<Clause>(); input.add(empty); input.add(nega); input.add(negb); input.add(bnegc); input.add(ac); input.add(negbc); input.add(ab); final boolean checkDAGCheck = pdc.check(input, empty); Assert.assertTrue(checkDAGCheck); input.clear(); input.add(empty); input.add(nega); input.add(negb); input.add(ab); final boolean check = new ProofDAGCheck().check(input, transformed); Assert.assertTrue(check); } }