package kodkod.test.unit; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import java.util.ArrayList; import java.util.List; import java.util.Set; import kodkod.ast.Expression; import kodkod.ast.Formula; import kodkod.ast.Node; import kodkod.ast.Relation; import kodkod.ast.Variable; import kodkod.engine.Solution; import kodkod.engine.Solver; import kodkod.engine.satlab.SATFactory; import kodkod.engine.ucore.ECFPStrategy; import kodkod.engine.ucore.NCEStrategy; import kodkod.instance.Bounds; import kodkod.instance.TupleFactory; import kodkod.instance.Universe; import kodkod.util.collections.IdentityHashSet; import kodkod.util.nodes.Nodes; import org.junit.Before; import org.junit.Test; /** * Tests the reduction algorithm for trivially * (un)satisfiable formulas, and does limited * testing of core extraction. * * @author Emina Torlak */ public class ReductionAndProofTest { private final int USIZE = 10; private final TupleFactory factory; private final Solver solver; private final Relation a, b, a2b, b2a; private final Relation first, last, ordered, total; private final Bounds bounds; public ReductionAndProofTest() { this.solver = new Solver(); solver.options().setLogTranslation(2); solver.options().setSolver(SATFactory.MiniSatProver); List<String> atoms = new ArrayList<String>(USIZE); for (int i = 0; i < USIZE; i++) { atoms.add(""+i); } final Universe universe = new Universe(atoms); this.factory = universe.factory(); this.a = Relation.unary("a"); this.b = Relation.unary("b"); this.a2b = Relation.binary("a2b"); this.b2a = Relation.binary("b2a"); this.first = Relation.unary("first"); this.last = Relation.unary("last"); this.ordered = Relation.unary("ordered"); this.total = Relation.binary("total"); this.bounds = new Bounds(universe); } @Before public void setUp() throws Exception { bounds.bound(a, factory.setOf("0","1","2","3","4")); bounds.bound(b, factory.setOf("5","6","7","8","9")); bounds.bound(a2b, bounds.upperBound(a).product(bounds.upperBound(b))); bounds.bound(b2a, bounds.upperBound(b).product(bounds.upperBound(a))); bounds.boundExactly(first, factory.setOf("0")); bounds.boundExactly(last, factory.setOf("4")); bounds.boundExactly(ordered, bounds.upperBound(a)); bounds.boundExactly(total, factory.setOf(factory.tuple("0","1"), factory.tuple("1","2"), factory.tuple("2","3"), factory.tuple("3","4"))); } private Set<Formula> reduce(Formula formula) { final Solution sol = solver.solve(formula, bounds); assertEquals(Solution.Outcome.TRIVIALLY_UNSATISFIABLE, sol.outcome()); sol.proof().minimize(null); return Nodes.minRoots(formula, sol.proof().highLevelCore().values()); } @Test public final void testReduction() { Formula f0, f1, f2, f3, f4, f5, f6; f0 = a.difference(b).eq(a); // T assertEquals(Solution.Outcome.TRIVIALLY_SATISFIABLE, solver.solve(f0, bounds).outcome()); f1 = a2b.join(b2a).some(); assertEquals(Solution.Outcome.TRIVIALLY_SATISFIABLE, solver.solve(f0.or(f1), bounds).outcome()); f2 = total.totalOrder(ordered, first, last); f3 = first.join(total).no(); // F Set<Formula> reduction = reduce(f3.and(f0).and(f1).and(f2)); assertEquals(1, reduction.size()); assertTrue(reduction.contains(f3)); f4 = total.acyclic(); f5 = total.closure().intersection(Expression.IDEN).some(); // F reduction = reduce(f4.and(f1).and(f0).and(f5)); assertEquals(1, reduction.size()); assertTrue(reduction.contains(f5)); bounds.boundExactly(a2b, bounds.upperBound(a2b)); bounds.boundExactly(a, bounds.upperBound(a)); bounds.boundExactly(b, bounds.upperBound(b)); f6 = a2b.function(a, b); // F reduction = reduce(f1.and(f2).and(f6)); assertEquals(1, reduction.size()); assertTrue(reduction.contains(f6)); } @Test public final void testProof() { Variable v0 = Variable.unary("v0"), v1 = Variable.unary("v1"), v2 = Variable.unary("v2"); Formula f0 = v0.join(a2b).eq(v1.union(v2)).and(v1.eq(v2).not()); Formula f1 = f0.forSome(v0.oneOf(a).and(v1.oneOf(b)).and(v2.oneOf(b))); Formula f2 = a2b.function(a, b); Formula f3 = f1.and(f2).and(total.totalOrder(ordered, first, last)); Solution sol = null; solver.options().setLogTranslation(0); solver.options().setSolver(SATFactory.MiniSat); sol = solver.solve(f3, bounds); assertEquals(Solution.Outcome.UNSATISFIABLE, sol.outcome()); assertNull(sol.proof()); solver.options().setLogTranslation(1); sol = solver.solve(f3, bounds); assertNull(sol.proof()); solver.options().setSolver(SATFactory.MiniSatProver); sol = solver.solve(f3, bounds); //System.out.println(f3 + ", " + bounds); sol.proof().minimize(new ECFPStrategy()); final Set<Formula> top = Nodes.minRoots(f3, sol.proof().highLevelCore().values()); assertEquals(2, top.size()); assertTrue(top.contains(f1)); assertTrue(top.contains(f2)); // for(Iterator<TranslationLog.Record> itr = sol.proof().core(); itr.hasNext(); ) { // System.out.println(itr.next()); // } } private Set<Node> reduce(Formula formula, int granularity) { solver.options().setCoreGranularity(granularity); final Solution sol = solver.solve(formula, bounds); assertEquals(Solution.Outcome.TRIVIALLY_UNSATISFIABLE, sol.outcome()); sol.proof().minimize(null); return new IdentityHashSet<Node>(sol.proof().highLevelCore().values()); } private Set<Node> core(Formula formula, int granularity) { solver.options().setCoreGranularity(granularity); final Solution sol = solver.solve(formula, bounds); assertEquals(Solution.Outcome.UNSATISFIABLE, sol.outcome()); sol.proof().minimize(new NCEStrategy(sol.proof().log())); return new IdentityHashSet<Node>(sol.proof().highLevelCore().values()); } @Test public final void testGranularity() { final Variable x = Variable.unary("x"); final Variable y = Variable.unary("y"); final Formula f0 = a.some(); final Formula f1 = b.some(); final Formula f2 = a.eq(b); final Formula f3 = x.product(y).in(Expression.UNIV.product(Expression.UNIV)); final Formula f4 = x.eq(y); final Formula f5 = f3.or(f4).forSome(y.oneOf(b)); final Formula f6 = f5.forAll(x.oneOf(a)); final Formula f7 = f2.or(f6).not(); final Formula f8 = b.intersection(Expression.UNIV).some(); final Formula f9 = Formula.and(f0, f1, f7, f8); Set<Node> core = core(f9,0); assertEquals(2, core.size()); assertTrue(core.contains(f1)); assertTrue(core.contains(f7)); core = core(f9,1); assertEquals(2, core.size()); assertTrue(core.contains(f1)); assertTrue(core.contains(f6)); core = reduce(f9,2); assertEquals(2, core.size()); assertTrue(core.contains(f1)); assertTrue(core.contains(f5)); core = core(f9,3); assertEquals(2, core.size()); assertTrue(core.contains(f1)); assertTrue(core.contains(f3)); } }