/**
*
*/
package kodkod.examples.alloy;
import java.util.ArrayList;
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.fol2sat.HigherOrderDeclException;
import kodkod.engine.fol2sat.UnboundLeafException;
import kodkod.engine.satlab.SATFactory;
import kodkod.instance.Bounds;
import kodkod.instance.TupleFactory;
import kodkod.instance.Universe;
/**
* A KK encoding of lists.als
* @author Emina Torlak
*/
public final class Lists {
/* KK outperformed by the sequential analysis tool on the reflexive and symmetric assertions */
private final Relation Thing, List, NonEmptyList, EmptyList;
private final Relation car, cdr, equivTo, prefixes;
/**
* Constructs a new isntance of the Lists model.
*/
public Lists() {
Thing = Relation.unary("Thing");
List = Relation.unary("List");
NonEmptyList = Relation.unary("NonEmptyList");
EmptyList = Relation.unary("EmptyList");
car = Relation.binary("car");
cdr = Relation.binary("cdr");
equivTo = Relation.binary("equivTo");
prefixes = Relation.binary("prefixes");
}
/**
* Returns the declaration constraints.
* @return declaration constraints
*/
public final Formula decls() {
// abstract sig List {
// equivTo: set List,
// prefixes: set List
// }
// sig NonEmptyList extends List {
// car: one Thing,
// cdr: one List
// }
// sig EmptyList extends List {}
final Formula f0 = List.eq(EmptyList.union(NonEmptyList));
final Formula f1 = EmptyList.intersection(NonEmptyList).no();
final Formula f2 = equivTo.in(List.product(List));
final Formula f3 = prefixes.in(List.product(List));
final Formula f4 = car.function(NonEmptyList, Thing);
final Formula f5 = cdr.function(NonEmptyList, List);
return f0.and(f1).and(f2).and(f3).and(f4).and(f5);
}
/**
* Returns all facts in the model.
* @return the facts.
*/
public final Formula facts() {
// fact NoStrayThings {Thing in List.car}
final Formula f0 = Thing.in(List.join(car));
// fact finite {all L: List | isFinite(L)}
final Variable L = Variable.unary("L");
final Formula f1 = isFinite(L).forAll(L.oneOf(List));
// fact Equivalence {
// all a,b: List | (a in b.equivTo) <=> (a.car = b.car and b.cdr in a.cdr.equivTo)
// }
final Variable a = Variable.unary("a");
final Variable b = Variable.unary("b");
final Formula f2 = a.in(b.join(equivTo));
final Formula f3 = a.join(car).eq(b.join(car));
final Formula f4 = b.join(cdr).in(a.join(cdr).join(equivTo));
final Formula f6 = f2.iff(f3.and(f4)).forAll(a.oneOf(List).and(b.oneOf(List)));
// fact prefix { //a is a prefix of b
// List->EmptyList in prefixes
// all a,b: NonEmptyList | (a in b.prefixes) <=> (a.car = b.car
// and a.cdr in b.cdr.prefixes)
// }
final Formula f7 = List.product(EmptyList).in(prefixes);
final Formula f8 = a.in(b.join(prefixes));
final Formula f9 = a.join(cdr).in(b.join(cdr).join(prefixes));
final Formula f11 = f8.iff(f3.and(f9)).forAll(a.oneOf(NonEmptyList).and(b.oneOf(NonEmptyList)));
return f0.and(f1).and(f6).and(f7).and(f11);
}
/**
* Returns the isFinite predicate.
* @return isFinite
*/
public final Formula isFinite(Expression/*List*/ L) {
// pred isFinite (L:List) {some EmptyList & L.*cdr}
return EmptyList.intersection(L.join(cdr.reflexiveClosure())).some();
}
/**
* Returns the reflexive assertion.
* @return reflexive
*/
public final Formula reflexive() {
// assert reflexive {all L: List | L in L.equivTo}
final Variable L = Variable.unary("L");
return L.in(L.join(equivTo)).forAll(L.oneOf(List));
}
/**
* Returns the symmetric assertion.
* @return symmetric
*/
public final Formula symmetric() {
// assert symmetric { ~equivTo in equivTo }
return equivTo.transpose().in(equivTo);
}
/**
* Returns the empties assertion.
* @return empties
*/
public final Formula empties() {
// assert empties { EmptyList->EmptyList in equivTo}
return EmptyList.product(EmptyList).in(equivTo);
}
/**
* Returns the show predicate.
* @return show
*/
public final Formula show() {
// pred show() {
// some disj a, b: NonEmptyList | b in a.prefixes
// }
final Variable a = Variable.unary("a"), b = Variable.unary("b");
return a.eq(b).not().and(b.in(a.join(prefixes))).forSome(a.oneOf(NonEmptyList).and(b.oneOf(NonEmptyList)));
}
/**
* Returns the conjunction of declaration constraints and facts.
* @return decls() and facts()
*/
public final Formula invariants() {
return decls().and(facts());
}
/**
* Returns the conjunction of invariants and the show predicate.
* @return invariants() and show()
*/
public final Formula runShow() {
return invariants().and(show());
}
/**
* Returns the conjunction of invariants and the negation of the empty hypothesis.
* @return invariants() and !empties()
*/
public final Formula checkEmpties() {
return invariants().and(empties().not());
}
/**
* Returns the conjunction of invariants and the negation of the reflexive hypothesis.
* @return invariants() and !reflexive()
*/
public final Formula checkReflexive() {
return invariants().and(reflexive().not());
}
/**
* Returns the conjunction of invariants and the negation of the symmetric hypothesis.
* @return invariants() and !symmetric()
*/
public final Formula checkSymmetric() {
return invariants().and(symmetric().not());
}
/**
* Returns the bounds for the given scope.
* @return the bounds for the given scope.
*/
public final Bounds bounds(int scope) {
assert scope > 0;
final int n = scope*2;
final List<String> atoms = new ArrayList<String>(n);
for(int i = 0; i < scope; i++)
atoms.add("Thing"+i);
for(int i = 0; i < scope; i++)
atoms.add("List"+i);
//private final Relation Thing, List, NonEmptyList, EmptyList;
//private final Relation car, cdr, equivTo, prefixes;
final Universe u = new Universe(atoms);
final TupleFactory f = u.factory();
final Bounds b = new Bounds(u);
final int max = scope-1;
b.bound(Thing, f.range(f.tuple("Thing0"), f.tuple("Thing"+max)));
b.bound(List, f.range(f.tuple("List0"), f.tuple("List"+max)));
b.bound(EmptyList, b.upperBound(List));
b.bound(NonEmptyList, b.upperBound(List));
b.bound(car, b.upperBound(List).product(b.upperBound(Thing)));
b.bound(cdr, b.upperBound(List).product(b.upperBound(List)));
b.bound(equivTo, b.upperBound(cdr));
b.bound(prefixes, b.upperBound(cdr));
return b;
}
private static void usage() {
System.out.println("java examples.Lists [scope]");
System.exit(1);
}
/**
* Usage: java examples.Lists [scope]
*/
public static void main(String[] args) {
if (args.length < 1)
usage();
try {
final int n = Integer.parseInt(args[0]);
final Lists model = new Lists();
final Bounds b = model.bounds(n);
final Solver solver = new Solver();
solver.options().setSolver(SATFactory.MiniSat);
// solver.options().setFlatten(false);
// solver.options().setSkolemize(false);
Formula f = model.runShow();
System.out.println("running show");
Solution s = solver.solve(f, b);
System.out.println(s);
f = model.checkEmpties();
System.out.println("checking empties");
s = solver.solve(f, b);
System.out.println(s);
f = model.checkReflexive();
System.out.println("checking reflexive");
s = solver.solve(f, b);
System.out.println(s);
f = model.checkSymmetric();
System.out.println("checking symmetric");
s = solver.solve(f, b);
System.out.println(s);
} catch (NumberFormatException nfe) {
usage();
} catch (HigherOrderDeclException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (UnboundLeafException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}