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]");
}
}
}