/** * 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); }
/** Allocate relations for nonbuiltin PrimSigs bottom-up. */ private Expression allocatePrimSig(PrimSig sig) throws Err { // Recursively allocate all children expressions, and form the union of them Expression sum = null; for (PrimSig child : sig.children()) { Expression childexpr = allocatePrimSig(child); if (sum == null) { sum = childexpr; continue; } // subsigs are disjoint sol.addFormula(sum.intersection(childexpr).no(), child.isSubsig); sum = sum.union(childexpr); } TupleSet lower = lb.get(sig).clone(), upper = ub.get(sig).clone(); if (sum == null) { // If sig doesn't have children, then sig should make a fresh relation for itself sum = sol.addRel(sig.label, lower, upper); } else if (sig.isAbstract == null) { // If sig has children, and sig is not abstract, then create a new relation to act as the // remainder. for (PrimSig child : sig.children()) { // Remove atoms that are KNOWN to be in a subsig; // it's okay to mistakenly leave some atoms in, since we will never solve for the // "remainder" relation directly; // instead, we union the remainder with the children, then solve for the combined solution. // (Thus, the more we can remove, the more efficient it gets, but it is not crucial for // correctness) TupleSet childTS = sol.query(false, sol.a2k(child), false); lower.removeAll(childTS); upper.removeAll(childTS); } sum = sum.union(sol.addRel(sig.label + " remainder", lower, upper)); } sol.addSig(sig, sum); return sum; }