package kodkod.examples.alloy;
import java.util.LinkedList;
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.Universe;
/**
* A kodkod encoding of ceilingsAndFloors.als
*
* <pre>
* In his 1973 song, Paul Simon said "One Man's Ceiling Is Another Man's Floor".
* Does it follow that "One Man's Floor Is Another Man's Ceiling"?
*
* To see why not, check the assertion BelowToo.
*
* Perhaps simply preventing man's own floor from being his ceiling is enough,
* as is done in the Geometry constraint. BelowToo' shows that there are still
* cases where Geometry holds but the implication does not, although now
* the smallest solution has 3 Men and 3 Platforms instead of just 2 of each.
*
* What if we instead prevent floors and ceilings from being shared,
* as is done in the NoSharing constraint? The assertion BelowToo''
* has no counterexamples, demonstrating that the implication now
* holds for all small examples.
*
* model author: Daniel Jackson (11/2001)
* modified by Robert Seater (11/2004)
*
* sig Platform {}
* sig Man {ceiling, floor: Platform}
* fact PaulSimon {all m: Man | some n: Man | Above (n,m)}
* pred Above(m, n: Man) {m.floor = n.ceiling}
*
* assert BelowToo {all m: Man | some n: Man | Above (m,n)}
* check BelowToo for 2 expect 1
*
* pred Geometry (){no m: Man | m.floor = m.ceiling}
* assert BelowToo' {Geometry() => all m: Man | some n: Man | Above (m,n)}
* check BelowToo' for 2 expect 0
* check BelowToo' for 3 expect 1
*
* pred NoSharing() {no disj m,n: Man | m.floor = n.floor || m.ceiling = n.ceiling}
* assert BelowToo'' {NoSharing() => all m: Man | some n: Man | Above (m,n)}
* check BelowToo'' for 5 expect 0
* check BelowToo'' for 10 expect 0
* </pre>
* @author Emina Torlak
*/
public final class CeilingsAndFloors {
private final Relation Platform, Man, ceiling, floor;
/**
* Creates an instance of the ceilings and floors class.
*/
public CeilingsAndFloors() {
Platform = Relation.unary("Platform");
Man = Relation.unary("Man");
ceiling = Relation.binary("ceiling");
floor = Relation.binary("floor");
}
/**
* Returns a formula that constrains the ceiling and floor
* relations to be functions from Man to Platform.
* @return FUNCTION(ceiling, Man, Platform) && FUNCTION(floor, Man, Platform)
*/
public Formula declarations() {
// ceiling and floor are functions from Man to Platform
return ceiling.function(Man,Platform).and(floor.function(Man,Platform));
}
/**
* Returns the belowToo constraint
* @return all m: Man | some n: Man | m.floor = n.ceiling
*/
public Formula belowToo() {
final Variable m = Variable.unary("m0"), n = Variable.unary("n0");
// all m: Man | some n: Man | m.floor = n.ceiling
return ((m.join(floor).eq(n.join(ceiling))).forSome(n.oneOf(Man)).forAll(m.oneOf(Man)));
}
/**
* Returns the noSharing constraint.
* @return all m, n: Man | !(m = n) => !(m.floor = n.floor || m.ceiling = n.ceiling)
*/
public Formula noSharing() {
final Variable m = Variable.unary("m1"), n = Variable.unary("n1");
// all m, n: Man | !(m = n) => !(m.floor = n.floor || m.ceiling = n.ceiling)
final Formula body = (m.join(floor).eq(n.join(floor))).or(m.join(ceiling).eq(n.join(ceiling)));
return (m.eq(n).not().implies(body.not())).forAll(m.oneOf(Man).and(n.oneOf(Man)));
}
/**
* Returns the paulSimon constraint.
* @return all m: Man | some n: Man | n.floor = m.ceiling
*/
public Formula paulSimon() {
final Variable m = Variable.unary("m2"), n = Variable.unary("n2");
// all m: Man | some n: Man | n.floor = m.ceiling
return ((n.join(floor).eq(m.join(ceiling))).forSome(n.oneOf(Man)).forAll(m.oneOf(Man)));
}
/**
* Returns the belowToo'' constraint.
* @return declarations() && paulSimon() && noSharing() && !belowToo()
*/
public Formula checkBelowTooDoublePrime() {
return declarations().and(paulSimon()).and(noSharing()).and(belowToo().not());
}
/**
* Returns the belowToo assertion.
* @return declarations() && paulSimon() && !belowToo()
*/
public Formula checkBelowTooAssertion() {
return declarations().and(paulSimon()).and(belowToo().not());
}
/**
* Creates bounds for the problem using the given number of platforms and men.
* @return bounds for the problem using the given number of platforms and men.
*/
public Bounds bounds(int scope) { return bounds(scope, scope); }
/**
* Creates bounds for the problem using the given number of platforms and men.
* @return bounds for the problem using the given number of platforms and men.
*/
public Bounds bounds(int platforms,int men) {
final List<String> atoms = new LinkedList<String>();
for (int i = 0; i < men; i++) {
atoms.add("Man" + i);
}
for (int i = 0; i < platforms; i++) {
atoms.add("Platform" + i);
}
final Universe universe = new Universe(atoms);
final TupleFactory factory = universe.factory();
final Bounds bounds = new Bounds(universe);
final String manMax = "Man" + (men - 1), platformMax = "Platform" + (platforms - 1);
bounds.bound(Platform, factory.range(factory.tuple("Platform0"), factory.tuple(platformMax)));
bounds.bound(Man, factory.range(factory.tuple("Man0"), factory.tuple(manMax)));
bounds.bound(ceiling, factory.area(factory.tuple("Man0", "Platform0"), factory.tuple(manMax, platformMax)));
bounds.bound(floor, factory.area(factory.tuple("Man0", "Platform0"), factory.tuple(manMax, platformMax)));
return bounds;
}
private static void usage() {
System.out.println("Usage: java examples.CeilingsAndFloors [# men] [# platforms]");
System.exit(1);
}
/**
* Usage: java examples.CeilingsAndFloors [# men] [# platforms]
*/
public static void main(String[] args) {
if (args.length < 2) usage();
final CeilingsAndFloors model = new CeilingsAndFloors();
final Solver solver = new Solver();
solver.options().setSolver(SATFactory.MiniSat);
try {
final int m = Integer.parseInt(args[0]);
final int p = Integer.parseInt(args[1]);
final Formula show = model.checkBelowTooDoublePrime();
final Solution sol = solver.solve(show, model.bounds(m,p));
System.out.println(show);
System.out.println(sol);
} catch (NumberFormatException nfe) {
usage();
}
}
}