package kodkod.examples.alloy; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.LinkedList; import java.util.List; import kodkod.ast.Expression; import kodkod.ast.Formula; import kodkod.ast.Relation; import kodkod.ast.Variable; import kodkod.engine.Solution; import kodkod.engine.Solver; import kodkod.engine.config.ConsoleReporter; import kodkod.engine.satlab.SATFactory; import kodkod.instance.Bounds; import kodkod.instance.TupleFactory; import kodkod.instance.Universe; /** * KK encoding of mondex/a.als together with mondex/common.als. * * @author Emina Torlak */ public final class AbstractWorldDefinitions { // relations declared in common.als private final Relation Coin, Purse, TransferDetails; private final Relation from, to, value; // relations declared in a.als private final Relation AbWorld, AbPurse, aNullIn, AIN, AOUT, aNullOut; private final Relation abAuthPurse, abBalance, abLost; /** * Constructs an instance of AbstractWorldDefinitions. */ public AbstractWorldDefinitions() { Coin = Relation.unary("Coin"); Purse = Relation.unary("Purse"); TransferDetails = Relation.unary("TransferDetails"); from = Relation.binary("from"); to = Relation.binary("to"); value = Relation.binary("value"); AbWorld = Relation.unary("AbWorld"); AbPurse = Relation.unary("AbPurse"); aNullIn = Relation.unary("aNullIn"); AIN = Relation.unary("AIN"); AOUT = Relation.unary("AOUT"); aNullOut = Relation.unary("aNullOut"); abAuthPurse = Relation.binary("abAuthPurse"); abBalance = Relation.ternary("abBalance"); abLost = Relation.ternary("abLost"); } /** * Returns the declaration constraints for mondex/common.als * @return declaration constraints for mondex/common.als */ public Formula decls() { final Formula f0 = from.function(TransferDetails, Purse); final Formula f1 = to.function(TransferDetails, Purse); final Formula f2 = value.in(TransferDetails.product(Coin)); final Formula f3 = AbPurse.in(Purse); final Formula f4 = abAuthPurse.in(AbWorld.product(AbPurse)); final Formula f5 = abBalance.in(AbPurse.product(Coin).product(AbWorld)); final Formula f6 = abLost.in(AbPurse.product(Coin).product(AbWorld)); final Formula f7 = AIN.in(aNullIn.union(TransferDetails)); final Formula f8 = aNullOut.in(AOUT); // final List<Formula> fs = Arrays.asList(f0, f1, f2, f3, f4, f5, f6, f7, f8); // Collections.shuffle(fs); return Formula.and(f0, f1, f2, f3, f4, f5, f6, f7, f8);//Formula.and(fs); } /** * Applies the XiTransfer predicate to the arguments. * @return application of the XiTransfer predicate to the arguments. */ public final Formula XiTransfer(Expression p, Expression pprime) { final Formula f0 = p.join(from).eq(pprime.join(from)); final Formula f1 = p.join(to).eq(pprime.join(to)); final Formula f2 = p.join(value).eq(pprime.join(value)); return Formula.and(f0, f1, f2); } /** * Returns the application of the Abstract predicate. * @return application of the Abstract predicate. */ public Formula Abstract(Expression s) { final Expression e0 = s.join(abAuthPurse).join(abBalance).join(s).intersection(s.join(abAuthPurse).join(abLost).join(s)); final Formula f0 = e0.no(); final Expression e1 = s.join(abAuthPurse).product(Expression.UNIV); final Expression e2 = e1.intersection((abBalance.union(abLost)).join(s)); final Formula f1 = e2.in(AbPurse.product(Coin)); final Variable c = Variable.unary("c"); final Formula f2 = e2.join(c).lone().forAll(c.oneOf(Coin)); return Formula.and(f0, f1, f2); } /** * Returns the application of the XiAbPurse predicate. * @return application of the XiAbPurse predicate. */ public Formula XiAbPurse(Expression s, Expression sprime, Expression a) { final Expression aRestrict = a.product(Expression.UNIV); final Formula f0 = aRestrict.intersection(abBalance.join(s)).eq(aRestrict.intersection(abBalance.join(sprime))); final Formula f1 = aRestrict.intersection(abLost.join(s)).eq(aRestrict.intersection(abLost.join(sprime))); return f0.and(f1); } /** * Returns the application of the totalBalance function. * @return application of the totalBalance function. */ public Expression totalBalance(Expression s) { return s.join(abAuthPurse).join(abBalance).join(s); } /** * Returns the application of the totalLost function. * @return application of the totalLost function. */ public Expression totalLost(Expression s) { return s.join(abAuthPurse).join(abLost).join(s); } /** * Returns the application of the NoValueCreation predicate. * @return application of the NoValueCreation predicate. */ public Formula NoValueCreation(Expression s, Expression sprime) { return totalBalance(sprime).in(totalBalance(s)); } /** * Returns the application of the AllValueAccounted predicate. * @return application of the AllValueAccounted predicate. */ public Formula AllValueAccounted(Expression s, Expression sprime) { return totalBalance(sprime).union(totalLost(sprime)).in(totalBalance(s).union(totalLost(s))); } /** * Returns the application of the Authentic predicate. * @return application of the Authentic predicate. */ public Formula Authentic(Expression s, Expression p) { return p.in(s.join(abAuthPurse)); } /** * Returns the application of the Authentic predicate. * @return application of the Authentic predicate. */ public Formula SufficientFundsProperty(Expression s, Expression t) { return t.join(value).in(t.join(from).join(abBalance).join(s)); } /** * Returns the application of the AbOp predicate. * @return application of the AbOp predicate. */ public Formula AbOp(Expression a_out) { return a_out.eq(aNullOut); } /** * Returns the application of the AbIgnore predicate. * @return application of the AbIgnore predicate. */ public Formula AbIgnore(Expression s, Expression sprime, Expression a_out) { final Formula f0 = AbOp(a_out); final Formula f1 = s.join(abAuthPurse).eq(sprime.join(abAuthPurse)); final Formula f2 = XiAbPurse(s, sprime, s.join(abAuthPurse)); return f0.and(f1).and(f2); } /** * Returns the application of the AbWorldSecureOp predicate. * @return application of the AbWorldSecureOp predicate. */ public Formula AbWorldSecureOp(Expression s, Expression sprime, Expression a_in, Expression a_out) { final Formula f0 = AbOp(a_out); final Formula f1 = a_in.in(TransferDetails); final Expression e0 = a_in.join(from); final Expression e1 = a_in.join(to); final Expression e2 = s.join(abAuthPurse).difference(e0).difference(e1); final Expression e3 = sprime.join(abAuthPurse).difference(e0).difference(e1); final Formula f2 = e2.eq(e3); final Formula f3 = XiAbPurse(s, sprime, e2); return Formula.and(f0, f1, f2, f3); } /** * Returns the application of the AbTransferOkay predicate. * @return application of the AbTransferOkay predicate. */ public Formula AbTransferOkay(Expression s, Expression sprime, Expression a_in, Expression a_out) { final Expression e0 = a_in.join(from); final Expression e1 = a_in.join(to); final Formula f0 = AbWorldSecureOp(s, sprime, a_in, a_out); final Formula f1 = Authentic(s, e0); final Formula f2 = Authentic(s, e1); final Formula f3 = SufficientFundsProperty(s, a_in); final Formula f4 = e0.intersection(e1).no(); final Formula f5 = e0.join(abBalance).join(sprime).eq(e0.join(abBalance).join(s).difference(a_in.join(value))); final Formula f6 = e0.join(abLost).join(sprime).eq(e0.join(abLost).join(s)); final Formula f7 = e1.join(abBalance).join(sprime).eq(e1.join(abBalance).join(s).union(a_in.join(value))); final Formula f8 = e1.join(abLost).join(sprime).eq(e1.join(abLost).join(s)); final Formula f9 = Authentic(sprime, e0); final Formula f10 = Authentic(sprime, e1); return Formula.and(f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10); } /** * Returns the application of the AbTransferLost predicate. * @return application of the AbTransferOkay predicate. */ public Formula AbTransferLost(Expression s, Expression sprime, Expression a_in, Expression a_out) { final Expression e0 = a_in.join(from); final Expression e1 = a_in.join(to); final Formula f0 = AbWorldSecureOp(s, sprime, a_in, a_out); final Formula f1 = Authentic(s, e0); final Formula f2 = Authentic(s, e1); final Formula f3 = SufficientFundsProperty(s, a_in); final Formula f4 = e0.intersection(e1).no(); final Formula f5 = e0.join(abBalance).join(sprime).eq(e0.join(abBalance).join(s).difference(a_in.join(value))); final Formula f6 = e0.join(abLost).join(sprime).eq(e0.join(abLost).join(s).union(a_in.join(value))); final Formula f7 = XiAbPurse(s, sprime, e1); final Formula f8 = Authentic(sprime, e0); final Formula f9 = Authentic(sprime, e1); return Formula.and(f0, f1, f2, f3, f4, f5, f6, f7, f8, f9); } /** * Returns the application of the AbTransfer predicate. * @return application of the AbTransfer predicate. */ public Formula AbTransfer(Expression s, Expression sprime, Expression a_in, Expression a_out) { return AbTransferOkay(s, sprime, a_in, a_out).or(AbTransferLost(s, sprime, a_in, a_out)). or(AbIgnore(s, sprime, a_out)); } /** * Returns decls() && !A241() * @return decls() && !A241() */ public Formula checkA241() { return decls().and(A241().not()); } /** * Returns decls() && !AbOp_total() * @return decls() && !AbOp_total() */ public Formula checkAbOp_total() { return decls().and(AbOp_total().not()); } /** * Returns decls() && !AbIgnore_inv() * @return decls() && !AbIgnore_inv() */ public Formula checkAbIgnore_inv() { return decls().and(AbIgnore_inv().not()); } /** * Returns decls() && !AbTransfer_inv() * @return decls() && !AbTransfer_inv() */ public Formula checkAbTransfer_inv() { return decls().and(AbTransfer_inv().not()); } /** * Returns the A241 assertion. * @return A241 assertion */ public Formula A241() { final Variable s = Variable.unary("s"); final Variable sprime = Variable.unary("s'"); final Variable a_in = Variable.unary("a_in"); final Variable a_out = Variable.unary("a_out"); final Formula f0 = Abstract(s).and(Abstract(sprime)).and(AbTransfer(s, sprime, a_in, a_out)); final Formula f1 = NoValueCreation(s, sprime).and(AllValueAccounted(s, sprime)); final Formula f2 = f0.implies(f1). forAll(s.oneOf(AbWorld).and(sprime.oneOf(AbWorld)).and(a_in.oneOf(AIN)).and(a_out.oneOf(AOUT))); return f2; } /** * Returns the AbOp_total assertion. * @return AbOp_total assertion */ public Formula AbOp_total() { final Variable a = Variable.unary("a"); final Variable a_in = Variable.unary("a_in"); final Formula f0 = Abstract(a).implies(AbIgnore(a, a, aNullOut).and(AbTransfer(a, a, a_in, aNullOut))); final Formula f1 = f0.forAll(a.oneOf(AbWorld).and(a_in.oneOf(AIN))); return f1; } /** * Returns the AbIgnore_inv assertion. * @return AbIgnore_inv assertion */ public Formula AbIgnore_inv() { final Variable a = Variable.unary("a"); final Variable aprime = Variable.unary("a'"); final Variable a_out = Variable.unary("a_out"); final Formula f0 = (Abstract(a).and(AbIgnore(a, aprime, a_out))).implies(Abstract(aprime)); final Formula f1 = f0.forAll(a.oneOf(AbWorld).and(aprime.oneOf(AbWorld)).and(a_out.oneOf(AOUT))); return f1; } /** * Returns the AbTransfer_inv assertion. * @return AbTransfer_inv assertion */ public Formula AbTransfer_inv() { final Variable a = Variable.unary("a"); final Variable aprime = Variable.unary("a'"); final Variable a_in = Variable.unary("a_in"); final Variable a_out = Variable.unary("a_out"); final Formula f0 = (Abstract(a).and(AbTransfer(a, aprime, a_in, a_out))).implies(Abstract(aprime)); final Formula f1 = f0. forAll(a.oneOf(AbWorld).and(aprime.oneOf(AbWorld)).and(a_in.oneOf(AIN)).and(a_out.oneOf(AOUT))); return f1; } /** * Returns the bounds for the given scope. * @return bounds for the given scope */ public final Bounds bounds(int scope) { final List<String> atoms = new LinkedList<String>(); final int max = scope-1; for(int i = 0; i < scope; i++) { atoms.add("Coin"+i); } for(int i = 0; i < scope; i++) { atoms.add("Purse"+i);} for(int i = 0; i < scope; i++) { atoms.add("TransferDetails"+i);} atoms.add("aNullIn"); for(int i = 0; i < scope; i++) { atoms.add("AbWorld"+i);} for(int i = 0; i < max; i++) { atoms.add("AOUT"+i);} atoms.add("aNullOut"); final Universe u = new Universe(atoms); final TupleFactory f = u.factory(); final Bounds b = new Bounds(u); b.bound(Coin, f.range(f.tuple("Coin0"), f.tuple("Coin"+max))); b.bound(Purse, f.range(f.tuple("Purse0"), f.tuple("Purse"+max))); b.bound(TransferDetails, f.range(f.tuple("TransferDetails0"), f.tuple("TransferDetails"+max))); b.bound(AbWorld, f.range(f.tuple("AbWorld0"), f.tuple("AbWorld"+max))); b.bound(AbPurse, b.upperBound(Purse)); b.bound(AOUT, f.range(f.tuple("AOUT0"), f.tuple("aNullOut"))); b.bound(AIN, f.range(f.tuple("TransferDetails0"), f.tuple("aNullIn"))); b.boundExactly(aNullIn, f.setOf("aNullIn")); b.boundExactly(aNullOut, f.setOf("aNullOut")); b.bound(from, b.upperBound(TransferDetails).product(b.upperBound(Purse))); b.bound(to, b.upperBound(TransferDetails).product(b.upperBound(Purse))); b.bound(value, b.upperBound(TransferDetails).product(b.upperBound(Coin))); b.bound(abAuthPurse, b.upperBound(AbWorld).product(b.upperBound(AbPurse))); b.bound(abBalance, b.upperBound(AbPurse).product(b.upperBound(Coin)).product(b.upperBound(AbWorld))); b.bound(abLost, b.upperBound(AbPurse).product(b.upperBound(Coin)).product(b.upperBound(AbWorld))); return b; } private static void usage() { System.out.println("java examples.AbstractWorldDefinitions [A241 | AbOp_total | AbIgnore_inv | AbTransfer_inv] [univ size]"); System.exit(1); } /** * Usage: java examples.AbstractWorldDefinitions [A241 | AbOp_total | AbIgnore_inv | AbTransfer_inv] [univ size] */ public static void main(String[] args) { if (args.length < 2) usage(); try { final String assertion = args[0]; final int n = Integer.parseInt(args[1]); if (n < 1) usage(); final AbstractWorldDefinitions model = new AbstractWorldDefinitions(); final Solver solver = new Solver(); solver.options().setSolver(SATFactory.MiniSat); solver.options().setReporter(new ConsoleReporter()); // solver.options().setFlatten(true); final Method method = model.getClass().getMethod(assertion); final Formula f = model.decls().and(((Formula)method.invoke(model)).not()); final Bounds b = model.bounds(n); System.out.println(f); final Solution sol = solver.solve(f, b); System.out.println(sol); } catch (NumberFormatException nfe) { usage(); } catch (SecurityException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (NoSuchMethodException e) { usage(); } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InvocationTargetException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }