package kodkod.examples.alloy; import java.util.ArrayList; import java.util.List; import kodkod.ast.Decls; 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.instance.Bounds; import kodkod.instance.TupleFactory; import kodkod.instance.TupleSet; import kodkod.instance.Universe; /** * A kodkod encoding of John McCarthy's thoughnut problem * <pre> * module internal/tougnut * * open util/ordering[Cell] * * sig Cell { covered: Cell -> Cell -> Cell } * * pred covering() { * // opposite corners not on the board * let board = Cell->Cell - (first()->first() + last()->last()) | * covered in board->board * * // covering relation is symmetric * all x,y: Cell | y.(x.covered)->x->y in covered * * // each pair of cells on the board should be covered * // by a domino, which also covers ONE of its neighbors * all x,y: Cell | one y.(x.covered) && * y.(x.covered) in (prev(x)+next(x))->y + x->(prev(y) + next(y)) * } * </pre> * * @author Emina * */ public final class Toughnut { private final Relation Cell, covered, ord; /** * Creates an instance of Toughnut. */ public Toughnut() { this.Cell = Relation.unary("Cell"); this.covered = Relation.nary("covered", 4); this.ord = Relation.binary("ord"); } private Expression next(Expression e) { return e.join(ord); } private Expression prev(Expression e) { return ord.join(e); } /** * Returns the covering predicate. Note that we don't * need to specify the first two lines of the predicate, * since they can be expressed as bounds constraints. * @return the covering predicate */ public Formula checkBelowTooDoublePrime() { final Variable x = Variable.unary("x"); final Variable y = Variable.unary("y"); final Decls d = x.oneOf(Cell).and(y.oneOf(Cell)); final Expression xy = y.join(x.join(covered)); // covering relation is symmetric Formula symm = xy.product(x.product(y)).in(covered).forAll(d); // each pair of cells on the board should be covered // by a domino, which also covers ONE of its neighbors Expression xNeighbors = (prev(x).union(next(x))).product(y); Expression yNeighbors = x.product(prev(y).union(next(y))); Formula covering = (xy.one().and(xy.in(xNeighbors.union(yNeighbors)))).forAll(d); return symm.and(covering); } /** * Returns bounds for an nxn board. * @return bounds for an nxn board. */ public Bounds bounds(int n) { assert n > 0; final List<String> atoms = new ArrayList<String>(n); for(int i = 0; i < n; i++) { atoms.add(String.valueOf(i)); } final Universe u = new Universe(atoms); final Bounds b = new Bounds(u); final TupleFactory f = u.factory(); b.boundExactly(Cell, f.allOf(1)); final TupleSet ordBound = f.noneOf(2); for(int i = 0; i < n-1; i++) { ordBound.add(f.tuple(String.valueOf(i), String.valueOf(i+1))); } b.boundExactly(ord, ordBound); final TupleSet board = f.allOf(2); board.remove(f.tuple(String.valueOf(0), String.valueOf(0))); board.remove(f.tuple(String.valueOf(n-1), String.valueOf(n-1))); b.bound(covered, board.product(board)); return b; } /** * Usage: java examples.Toughnut [size of one side of the board; optional] */ public static void main(String[] args) { try { int n = args.length==0 ? 4 : Integer.parseInt(args[0]); final Toughnut nut = new Toughnut(); final Solver solver = new Solver(); final Formula covering = nut.checkBelowTooDoublePrime(); final Bounds bounds = nut.bounds(n); //System.out.println(covering); //System.out.println(bounds); final Solution sol = solver.solve(covering, bounds); System.out.println(sol); } catch (NumberFormatException nfe) { System.out.println("Usage: java examples.Toughnut [size of one side of the board; optional]"); } } }