/**
*
*/
package kodkod.examples.alloy;
import static kodkod.ast.Expression.INTS;
import java.util.ArrayList;
import java.util.List;
import kodkod.ast.Decls;
import kodkod.ast.Expression;
import kodkod.ast.Formula;
import kodkod.ast.IntConstant;
import kodkod.ast.IntExpression;
import kodkod.ast.Relation;
import kodkod.ast.Variable;
import kodkod.engine.Evaluator;
import kodkod.engine.Solution;
import kodkod.engine.Solver;
import kodkod.engine.config.ConsoleReporter;
import kodkod.engine.config.Options;
import kodkod.engine.satlab.SATFactory;
import kodkod.instance.Bounds;
import kodkod.instance.Instance;
import kodkod.instance.TupleFactory;
import kodkod.instance.TupleSet;
import kodkod.instance.Universe;
/**
* A KK encoding of the Kuncak hypothesis for n = 3.
* @author Emina Torlak
*/
public final class Viktor {
private final int rows, cols;
private final Relation[][] a;
private final Relation[] x;
private final IntExpression[] b;
/**
* Constructs an instance of Viktor for n = 3.
*/
public Viktor() {
rows = 3;
cols = 1<<rows;
a = new Relation[rows][cols];
x = new Relation[cols];
b = new IntExpression[rows];
for(int i = 0; i < rows; i++) {
for(int j = 0; j < cols; j++) {
a[i][j] = Relation.unary("a"+String.valueOf(i)+String.valueOf(j));
}
}
for(int j = 0; j < cols; j++) {
x[j] = Relation.unary("x"+j);
}
for(int i = 0; i < rows; i++) {
b[i] = conditionalSum(a[i], x, 0, cols-1);
}
}
/**
* Returns the sum of the elements in x (conditional on the non-emptiness of a
* given a[i]) located at indices [lo..hi]
* @return the sum of cardinalities of the elements in x (conditional on the non-emptiness of a
* given a[i]) located at indices [lo..hi]
*/
private static IntExpression conditionalSum(Expression[] a, Expression[] x, int lo, int hi) {
if (lo>hi)
return IntConstant.constant(0);
else if (lo==hi)
return a[lo].some().thenElse(x[lo].sum(), IntConstant.constant(0));
else {
final int mid = (lo + hi) / 2;
final IntExpression lsum = conditionalSum(a, x, lo, mid);
final IntExpression hsum = conditionalSum(a, x, mid+1, hi);
return lsum.plus(hsum);
}
}
/**
* Returns a formula constraining all x's to be singletons.
* @return a formula constraining all x's to be singletons
*/
public final Formula decls() {
Formula ret = Formula.TRUE;
for(Relation xj: x) {
ret =ret.and(xj.one());
}
return ret;
}
/**
* Returns the equations to be satisfied.
* @return equations to be satisfied.
*/
public final Formula equations() {
// each b <= cols-1
Formula f0 = Formula.TRUE;
final IntConstant colConst = IntConstant.constant(cols-1);
for(IntExpression bi: b) {
f0 = f0.and(bi.lte(colConst));
}
final Variable[] y = new Variable[rows];
for(int i = 0; i < rows; i++) {
y[i] = Variable.unary("y"+i);
}
Decls decls = y[0].oneOf(INTS);
for(int i = 1; i < rows; i++)
decls = decls.and(y[i].oneOf(INTS));
Formula f1 = Formula.TRUE;
final Expression[] combo = new Expression[rows];
for(int i = 0; i < cols; i++) {
for(int j = i+1; j < cols; j++) {
for(int k = j+1; k < cols; k++) {
Formula f2 = Formula.TRUE;
for(int m = 0; m < rows; m++) {
combo[0] = a[m][i];
combo[1] = a[m][j];
combo[2] = a[m][k];
f2 = f2.and(conditionalSum(combo, y, 0, rows-1).eq(b[m]));
}
f1 = f1.and(f2.not().forAll(decls));
}
}
}
return f0.and(f1);
}
/**
* Returns decls() && equations().
* @return decls() && equations()
*/
public final Formula checkEquations() {
return decls().and(equations());
}
/**
* Returns the bounds for the problem.
* @return bounds
*/
public final Bounds bounds() {
List<String> atoms = new ArrayList<String>(cols+1);
for(int i = 0; i < cols; i++) {
atoms.add(String.valueOf(i));
}
atoms.add("a");
final Universe u = new Universe(atoms);
final TupleFactory f = u.factory();
final Bounds b = new Bounds(u);
final TupleSet abound = f.setOf("a");
for(int i = 0; i < rows; i++) {
for(int j = 0; j < cols; j++) {
b.bound(a[i][j], abound);
}
}
final TupleSet xbound = f.range(f.tuple(String.valueOf(0)), f.tuple(String.valueOf(cols-1)));
for(int j = 0; j < cols; j++) {
b.bound(x[j], xbound);
b.boundExactly(j, f.setOf(String.valueOf(j)));
}
return b;
}
private final void display(Instance instance, Options options) {
final Evaluator eval = new Evaluator(instance, options);
for(int i = 0; i < 2; i++) {
System.out.print(" | ");
System.out.print(instance.tuples(x[i]).indexView().min());
System.out.println(" |");
}
for(int i = 0; i < rows; i++) {
System.out.print("| ");
for(int j = 0; j < cols; j++) {
System.out.print(instance.tuples(a[i][j]).isEmpty() ? 0 : 1);
System.out.print(" ");
}
System.out.print(i==1 ? "| * | " : "| | ");
System.out.print(instance.tuples(x[i+2]).indexView().min());
System.out.print(i==1 ? " | = | " : " | | ");
System.out.print(eval.evaluate(b[i]));
System.out.println(" |");
}
for(int i = 5; i < 8; i++) {
System.out.print(" | ");
System.out.print(instance.tuples(x[i]).indexView().min());
System.out.println(" |");
}
// for(int i = 0; i < 3; i++)
// System.out.println(b[i]);
//
// for(int i = 0; i < rows; i++) {
// for(int j = 0 ; j < 8; j++) {
// IntExpression e0 = x[j].sum();
// IntExpression e1 = a[i][j].some().thenElse(e0, IntConstant.constant(0));
// System.out.println(e0 + " : " + eval.evaluate(e0));
// System.out.println(e1 + " : " + eval.evaluate(e1));
// }
// }
}
/**
* Usage: java tests.Viktor
*/
public static void main(String[] args) {
final Viktor model = new Viktor();
final Solver solver = new Solver();
solver.options().setSolver(SATFactory.MiniSat);
solver.options().setReporter(new ConsoleReporter());
solver.options().setBitwidth(7);
final Formula f = model.checkEquations();
final Bounds b = model.bounds();
System.out.println(f);
System.out.println(b);
final Solution sol = solver.solve(f, b);
System.out.println(sol);
if (sol.instance()!=null)
model.display(sol.instance(), solver.options());
}
}