package kodkod.examples.alloy;
import java.util.ArrayList;
import java.util.List;
import kodkod.ast.Formula;
import kodkod.ast.Relation;
import kodkod.ast.Variable;
import kodkod.engine.Solution;
import kodkod.engine.Solver;
import kodkod.engine.satlab.SATFactory;
import kodkod.instance.Bounds;
import kodkod.instance.TupleFactory;
import kodkod.instance.TupleSet;
import kodkod.instance.Universe;
/**
* A KodKod encoding of the pigeonhole problem: module internal/pigeonhole
* <pre>
* sig Pigeon { hole: Hole }
*
* sig Hole {}
*
* pred aPigeonPerHole() {
* // holes are not shared
* no disj p1, p2: Pigeon |
* p1.hole = p2.hole }
*
* run aPigeonPerHole for exactly 30 Pigeon, exactly 29 Hole
* </pre>
* @author Emina Torlak
*/
public final class Pigeonhole {
// sigs
private final Relation Pigeon, Hole;
// fields
private final Relation hole;
/**
* Creates an instance of the pigeonhole example.
*/
public Pigeonhole() {
this.Pigeon = Relation.unary("Pigeon");
this.Hole = Relation.unary("Hole");
this.hole = Relation.binary("hole");
}
/**
* Returns the declaration constraints.
* @return declarations
*/
public Formula declarations() {
return hole.function(Pigeon, Hole);
}
/**
* Returns the aPigeonPerHole constraints.
* @return aPigeonPerHole
*/
public Formula pigeonPerHole() {
final Variable p1 = Variable.unary("p1");
final Variable p2 = Variable.unary("p2");
return (p1.eq(p2).not().
implies(p1.join(hole).intersection(p2.join(hole)).no())).
forAll(p1.oneOf(Pigeon).and(p2.oneOf(Pigeon)));
}
/**
* Returns the bounds for the given number of pigeons and holes.
* @return bounds
*/
public Bounds bounds(int pigeons, int holes) {
final List<String> atoms = new ArrayList<String>(pigeons + holes);
for(int i = 0; i < pigeons; i++) {
atoms.add("Pigeon"+i);
}
for(int i = 0; i < holes; i++) {
atoms.add("Hole"+i);
}
final Universe u = new Universe(atoms);
final TupleFactory f = u.factory();
final Bounds b = new Bounds(u);
final TupleSet pbound = f.range(f.tuple("Pigeon0"), f.tuple("Pigeon" + (pigeons-1)));
final TupleSet hbound = f.range(f.tuple("Hole0"), f.tuple("Hole" + (holes-1)));
b.boundExactly(Pigeon, pbound);
b.boundExactly(Hole, hbound);
b.bound(hole, pbound.product(hbound));
return b;
}
private static void usage() {
System.out.println("Usage: java tests.Pigeonhole [# pigeons] [# holes]");
System.exit(1);
}
/**
* Usage: java tests.Pigeonhole [# pigeons] [# holes]
*/
public static void main(String[] args) {
if (args.length < 2)
usage();
final Pigeonhole model = new Pigeonhole();
final Solver solver = new Solver();
try {
final int p = Integer.parseInt(args[0]);
final int h = Integer.parseInt(args[1]);
solver.options().setSolver(SATFactory.MiniSat);
solver.options().setSymmetryBreaking(p);
final Formula show = model.declarations().and(model.pigeonPerHole());
final Solution sol = solver.solve(show, model.bounds(p,h));
//System.out.println(show);
System.out.println(sol);
} catch (NumberFormatException nfe) {
usage();
}
}
}