@Test
  public final void testAcyclic() {
    bounds.bound(ac1, factory.area(factory.tuple("0", "0"), factory.tuple("4", "4")));
    assertNotNull(solve(ac1.some().and(ac1.acyclic())));
    assertPrimVarNum(10);

    bounds.bound(r1, factory.range(factory.tuple("0"), factory.tuple("4")));
    assertNotNull(solve(ac1.join(r1).some().and(ac1.acyclic())));
    assertPrimVarNum(10 + bounds.upperBound(r1).size());

    TupleSet ac2b = factory.setOf("5", "6", "7", "8");
    ac2b = ac2b.product(ac2b);
    bounds.bound(ac2, ac2b);
    assertNotNull(solve(ac1.difference(ac2).some().and(ac1.acyclic()).and(ac2.acyclic())));
    assertPrimVarNum(10 + 6);

    bounds.boundExactly(r2, factory.setOf(factory.tuple("5", "6")));
    assertNotNull(solve(ac2.join(r2).some().and(ac2.acyclic())));

    final TupleSet ac3Bound = factory.allOf(2);
    ac3Bound.remove(factory.tuple("9", "9"));
    bounds.bound(ac3, ac3Bound);

    assertNotNull(
        solve(ac1.difference(ac2).union(ac3).some().and(ac1.acyclic()).and(ac2.acyclic())));
    assertPrimVarNum(ac3Bound.size() + 10 + 6);

    bounds.bound(to3, factory.allOf(2));
    bounds.bound(ord3, factory.setOf("0", "1", "2"));
    bounds.bound(first3, bounds.upperBound(ord3));
    bounds.bound(last3, bounds.upperBound(ord3));
    assertNotNull(
        solve(to3.product(ac1).some().and(ac1.acyclic()).and(to3.totalOrder(ord3, first3, last3))));
    assertPrimVarNum(bounds.upperBound(ac1).size());
  }
  @Test
  public final void testTotalOrdering() {
    bounds.bound(to1, factory.area(factory.tuple("0", "0"), factory.tuple("4", "4")));
    bounds.bound(ord1, factory.setOf("0", "1", "2", "3", "4"));
    bounds.bound(first1, bounds.upperBound(ord1));
    bounds.bound(last1, bounds.upperBound(ord1));
    final Formula ordered1 = to1.totalOrder(ord1, first1, last1);
    assertNotNull(solve(to1.some().and(ordered1)));
    assertPrimVarNum(0);
    assertAuxVarNum(0);
    assertClauseNum(0);

    bounds.bound(r1, factory.range(factory.tuple("0"), factory.tuple("4")));
    assertNotNull(solve(to1.join(r1).some().and(ordered1)));
    assertPrimVarNum(bounds.upperBound(r1).size());

    bounds.boundExactly(r1, bounds.upperBound(r1));
    assertNotNull(solve(to1.join(r1).some().and(ordered1)));
    assertPrimVarNum(0);

    bounds.bound(to2, factory.setOf("5", "6", "7", "8", "9").product(factory.setOf("5", "7", "8")));
    bounds.bound(ord2, factory.setOf("5", "7", "8"));
    bounds.bound(first2, bounds.upperBound(ord2));
    bounds.bound(last2, bounds.upperBound(ord2));
    final Formula ordered2 = to2.totalOrder(ord2, first2, last2);
    assertNotNull(solve(to1.difference(to2).some().and(ordered2).and(ordered1)));
    assertPrimVarNum(0);
    assertAuxVarNum(0);
    assertClauseNum(0);

    bounds.bound(to3, factory.allOf(2));
    bounds.bound(ord3, factory.allOf(1));
    bounds.bound(first3, factory.setOf("9"));
    bounds.bound(last3, factory.setOf("8"));
    final Formula ordered3 = to3.totalOrder(ord3, first3, last3);
    assertNotNull(solve(to3.product(to1).some().and(ordered1).and(ordered3)));
    assertPrimVarNum(bounds.upperBound(to3).size() + bounds.upperBound(ord3).size() + 2);

    // SAT solver takes a while
    //		bounds.boundExactly(r2, factory.setOf(factory.tuple("9","8")));
    //		assertNotNull(solve(r2.in(to3).and(ordered3)));
    bounds.bound(to3, factory.allOf(2));
    bounds.bound(ord3, factory.setOf("3"));
    bounds.bound(first3, factory.allOf(1));
    bounds.bound(last3, factory.allOf(1));

    Instance instance = solve(ordered3);
    assertNotNull(instance);
    assertTrue(instance.tuples(to3).isEmpty());
    assertTrue(instance.tuples(ord3).equals(bounds.upperBound(ord3)));
    assertTrue(instance.tuples(first3).equals(bounds.upperBound(ord3)));
    assertTrue(instance.tuples(last3).equals(bounds.upperBound(ord3)));
  }
Beispiel #3
0
  /**
   * Returns all facts in the model.
   *
   * @return the facts.
   */
  public final Formula facts() {
    // sig File extends Object {} { some d: Dir | this in d.entries.contents }
    final Variable file = Variable.unary("this");
    final Variable d = Variable.unary("d");
    final Formula f0 =
        file.in(d.join(entries).join(contents)).forSome(d.oneOf(Dir)).forAll(file.oneOf(File));

    //		sig Dir extends Object {
    //			  entries: set DirEntry,
    //			  parent: lone Dir
    //			} {
    //			  parent = this.~@contents.~@entries
    //			  all e1, e2 : entries | e1.name = e2.name => e1 = e2
    //			  this !in this.^@parent
    //			  this != Root => Root in this.^@parent
    //			}

    final Variable dir = Variable.unary("this");
    final Variable e1 = Variable.unary("e1"), e2 = Variable.unary("e2");

    final Formula f1 =
        (dir.join(parent)).eq(dir.join(contents.transpose()).join(entries.transpose()));
    final Expression e0 = dir.join(entries);
    final Formula f2 =
        e1.join(name).eq(e2.join(name)).implies(e1.eq(e2)).forAll(e1.oneOf(e0).and(e2.oneOf(e0)));
    final Formula f3 = dir.in(dir.join(parent.closure())).not();
    final Formula f4 = dir.eq(Root).not().implies(Root.in(dir.join(parent.closure())));
    final Formula f5 = f1.and(f2).and(f3).and(f4).forAll(dir.oneOf(Dir));

    //		one sig Root extends Dir {} { no parent }
    final Formula f6 = Root.join(parent).no();

    //		sig DirEntry {
    //			  name: Name,
    //			  contents: Object
    //			} { one this.~entries }

    final Variable entry = Variable.unary("this");
    final Formula f7 = entry.join(entries.transpose()).one().forAll(entry.oneOf(DirEntry));

    //		fact OneParent {
    //		    // all directories besides root xhave one parent
    //		    all d: Dir - Root | one d.parent
    //		}

    final Formula f8 = d.join(parent).one().forAll(d.oneOf(Dir.difference(Root)));

    return f0.and(f5).and(f6).and(f7).and(f8);
  }
  /**
   * Returns a relational encoding of the problem.
   *
   * @return a relational encoding of the problem.
   */
  public Formula rules() {
    final List<Formula> rules = new ArrayList<Formula>();

    rules.add(x.function(queen, num));
    rules.add(y.function(queen, num));

    final Variable i = Variable.unary("n");
    final Variable q1 = Variable.unary("q1"), q2 = Variable.unary("q2");

    // at most one queen in each row: all i: num | lone x.i

    rules.add(x.join(i).lone().forAll(i.oneOf(num)));

    // at most one queen in each column: all i: num | lone y.i
    rules.add(y.join(i).lone().forAll(i.oneOf(num)));

    // no queen in a blocked position:  all q: Queen | q.x->q.y !in blocked
    rules.add(q1.join(x).product(q1.join(y)).intersection(blocked).no().forAll(q1.oneOf(queen)));

    // at most one queen on each diagonal
    //		all q1: Queen, q2: Queen - q1 |
    //		let xu = prevs[q2.x] + prevs[q1.x],
    //		     xi =  prevs[q2.x] & prevs[q1.x],
    //                yu = prevs[q2.y] + prevs[q1.y],
    //                yi = prevs[q2.y] & prevs[q1.y] |
    //		#(xu - xi) != #(yu - yi)
    final Expression ordClosure = ord.closure();
    final Expression q2xPrevs = ordClosure.join(q2.join(x)), q1xPrevs = ordClosure.join(q1.join(x));
    final Expression q2yPrevs = ordClosure.join(q2.join(y)), q1yPrevs = ordClosure.join(q1.join(y));

    final IntExpression xDiff =
        (q2xPrevs.union(q1xPrevs)).difference(q2xPrevs.intersection(q1xPrevs)).count();
    final IntExpression yDiff =
        (q2yPrevs.union(q1yPrevs)).difference(q2yPrevs.intersection(q1yPrevs)).count();

    rules.add(xDiff.eq(yDiff).not().forAll(q1.oneOf(queen).and(q2.oneOf(queen.difference(q1)))));

    return Formula.and(rules);
  }