package com.juliasoft.beedeedee.examples.queens; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import com.juliasoft.beedeedee.bdd.Assignment; import com.juliasoft.beedeedee.bdd.BDD; import com.juliasoft.beedeedee.bdd.UnsatException; import com.juliasoft.beedeedee.factories.Factory; import com.juliasoft.julia.checkers.nullness.Inner0NonNull; import com.juliasoft.julia.checkers.nullness.Inner1NonNull; public class QueenSolver extends Thread { private final Object lockForIndices = new Object(); private final Lock mergeSemaphore = new ReentrantLock(); private final int N; private final boolean parallel; private final Factory factory; private final @Inner0NonNull @Inner1NonNull BDD[][] X; /* BDD variable array */ private int i; private int j; public QueenSolver(int N, boolean parallel, Factory factory) { super("Queens solver for size " + N); this.N = N; this.parallel = parallel; this.factory = factory; this.X = new BDD[N][N]; } @Override public void run() { buildVariables(); BDD queen = oneQueenInEachRow(); Thread[] slaves = spawnSlaves(queen); processPairs(queen); awaitSlaves(slaves, queen); printSolution(queen); queen.free(); } private Thread[] spawnSlaves(final BDD queen) { class Processor extends Thread { @Override public void run() { processPairs(queen); } } if (parallel) { Thread[] slaves = new Thread[Runtime.getRuntime().availableProcessors()]; System.out.println("spawning " + slaves.length + " slaves"); for (int pos = 0; pos < slaves.length; pos++) (slaves[pos] = new Processor()).start(); return slaves; } else return null; } private void awaitSlaves(Thread[] slaves, BDD queen) { if (parallel) for (Thread slave: slaves) try { slave.join(); } catch (InterruptedException e) {} } private void processPairs(BDD queen) { BDD accumulator = factory.makeOne(); BDD constraintForPair; do { constraintForPair = constraintForNextPair(); if (constraintForPair != null) { accumulator.andWith(constraintForPair); int count = accumulator.nodeCount(); if (count > 7500) { if (parallel) mergeSemaphore.lock(); queen.andWith(accumulator); if (parallel) mergeSemaphore.unlock(); accumulator = factory.makeOne(); } } } while (constraintForPair != null); if (parallel) mergeSemaphore.lock(); queen.andWith(accumulator); if (parallel) mergeSemaphore.unlock(); } private BDD constraintForNextPair() { int myI, myJ; synchronized (lockForIndices) { myI = i; myJ = j; if (i == N) return null; else if (j < N - 1) j++; else { j = 0; ++i; } } BDD accumulator = factory.makeOne(); accumulator.andWith(noMoreThanOneInEachColumn(myI, myJ)); accumulator.andWith(noMoreThanOneInEachRow(myI, myJ)); accumulator.andWith(noMoreThanOneInEachUpRightDiagonal(myI, myJ)); accumulator.andWith(noMoreThanOneInEachDownRightDiagonal(myI, myJ)); return accumulator; } private BDD noMoreThanOneInEachDownRightDiagonal(int i, int j) { BDD d = factory.makeOne(); for (int k = 0; k < N; k++) if (k != i) { int ll = i + j - k; if (ll >= 0 && ll < N) d.andWith(X[i][j].nand(X[k][ll])); } return d; } private BDD noMoreThanOneInEachUpRightDiagonal(int i, int j) { BDD c = factory.makeOne(); for (int k = 0; k < N; k++) if (k != i) { int ll = k - i + j; if (ll >= 0 && ll < N) c.andWith(X[i][j].nand(X[k][ll])); } return c; } private BDD noMoreThanOneInEachRow(int i, int j) { BDD b = factory.makeOne(); for (int k = 0; k < N; k++) if (k != i) b.andWith(X[i][j].nand(X[k][j])); return b; } private BDD noMoreThanOneInEachColumn(int i, int j) { BDD a = factory.makeOne(); for (int l = 0; l < N; l++) if (l != j) a.andWith(X[i][l].nand(X[i][j])); return a; } private BDD oneQueenInEachRow() { BDD constraint = factory.makeOne(); for (int i = 0; i < N; i++) { BDD e = factory.makeZero(); for (int j = 0; j < N; j++) e.orWith(X[i][j].copy()); // 'or' with a copy constraint.andWith(e); } return constraint; } private void printSolution(BDD queen) { Assignment assignment; try { assignment = queen.anySat(); } catch (UnsatException e) { assignment = null; } StringBuilder sb = new StringBuilder(); sb.append("\n**************************************************\n\n"); sb.append("Built BDD for " + N + "-queens.\n"); sb.append("There are " + queen.satCount(N * N - 1) + " solutions.\n"); if (assignment != null) printAssignment(sb, assignment); else sb.append("Unsatisfiable"); sb.append("\n**************************************************\n"); System.out.println(sb); /* System.out.println("Finding all assignments...\n"); for (Assignment a : queen.allSat()) { printAssignment(a); System.out.println(); } */ } private void buildVariables() { for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) X[i][j] = factory.makeVar(i * N + j); } private void printAssignment(StringBuilder sb, Assignment assignment) { sb.append("Here is one:\n\n"); for (int i = 0; i < N; i++) { for (int j = 0; j < N; j++) sb.append(" " + (assignment.holds(X[i][j]) ? 'Q' : '-')); sb.append("\n"); } } }