/* This file is part of JOP, the Java Optimized Processor see <http://www.jopdesign.com/> Copyright (C) Martin Schoeberl <martin@jopdesign.com> Thomas B. Preusser <thomas.preusser@tu-dresden.de> This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ package jembench.parallel; import jembench.ParallelBenchmark; /** * Benchmark based on the N-Queens Puzzle. It calculates the number of valid * solutions for the given problem size N. The search space is explored entirely * - without exploiting any optimizations due to symmetries. The parallel * implementation partitions the search space by the pre-placement of the L * initial columns. * * The check value returned by execute() is the determined solution count. It * may be verified by sequence A000170 of Sloane's On-Line Encyclopedia of * Integer Sequences: * * http://www.research.att.com/~njas/sequences/A000170 * * Be aware of the computational complexity as you increase N! * * @author Thomas B. Preusser <thomas.preusser@tu-dresden.de> */ public class NQueens extends ParallelBenchmark implements Runnable { // Problem Size private final int N; private final int L; // Preplacement Calculation private final int[] bh; private final int[] bu; private final int[] bd; private final int[] sl; private int col; // Work Collection private long total; /** Create Benchmark for Standard Size. */ public NQueens() { this(9, 3); } public NQueens(final int N, final int L) { // Check Problem Spec if ((L <= 0) || (L > N) || (N > 32)) throw new IllegalArgumentException(); this.N = N; this.L = L; // Memory for Calculation of Pre-Placement bh = new int[L]; if (N < 32) bh[0] = -1 << N; bu = new int[L]; bd = new int[L]; sl = new int[L]; } public String toString() { return "NQueens(N=" + N + ";L=" + L + ")"; } public Runnable getWorker() { // Reset State sl[0] = ~bh[0]; col = 0; total = 0; return this; // use myself as worker Thread } public void run() { final int[] cs = new int[3]; while (true) { if (get(cs) == null) break; add(q(cs[0], cs[1], cs[2])); } } // Calculate & Fetch next Pre-Placement private synchronized int[] get(final int[] store) { final int[] bh = this.bh; final int[] bu = this.bu; final int[] bd = this.bd; int col; if ((col = this.col) < 0) return null; while (true) { int slot; if ((slot = sl[col]) == 0) { // Retreat one Column if (--col < 0) { this.col = -1; return null; } } else { // Explore next free Position of Column sl[col] ^= (slot = slot & -slot); if (col < L - 1) { // Calculate Blocking for Next Column final int p = col++; sl[col] = ~((bh[col] = bh[p] | slot) | (bu[col] = (bu[p] | slot) << 1) | (bd[col] = (bd[p] | slot) >>> 1)); } else { this.col = col; store[0] = bh[col] | slot; store[1] = (bu[col] | slot) << 1; store[2] = (bd[col] | slot) >>> 1; return store; } } } } // Add a Subtotal private synchronized void add(final long subtotal) { total += subtotal; } // Recursively count the Completions of a Subboard private static long q(final int bh, final int bu, final int bd) { int slots = ~(bh | bu | bd); if (slots == 0) return (bh == -1) ? 1 : 0; long cnt = 0; while (slots != 0) { final int slot; slots ^= (slot = slots & -slots); cnt += q(bh | slot, (bu | slot) << 1, (bd | slot) >>> 1); } return cnt; } }