/* * This file is part of the X10 project (http://x10-lang.org). * * This file is licensed to You under the Eclipse Public License (EPL); * You may not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.opensource.org/licenses/eclipse-1.0.php * * (C) Copyright IBM Corporation 2006-2014. * (C) Copyright Australian National University 2011. */ import x10.array.DistArray_Unique; /** * A distributed version of NQueens. Runs over NUM_PLACES. * Identical to NQueensPar, except that work is distributed * over multiple places rather than shared between threads. */ public class NQueensDist { public static val EXPECTED_SOLUTIONS = [0, 1, 0, 0, 2, 10, 4, 40, 92, 352, 724, 2680, 14200, 73712, 365596, 2279184, 14772512]; val N:Long; val P:Long; val results:DistArray_Unique[Long]; val R:LongRange; def this(N:Long, P:Long) { this.N=N; this.P=P; this.results = new DistArray_Unique[Long](); this.R = 0..(N-1); } def start() { new Board().distSearch(); } def run():Long { finish start(); val result = results.reduce(((x:Long,y:Long) => x+y),0); return result; } class Board { val q: Rail[Long]; /** The number of low-rank positions that are fixed in this board for the purposes of search. */ var fixed:Long; def this() { q = new Rail[Long](N); fixed = 0; } /** * @return true if it is safe to put a queen in file j * on the next rank after the last fixed position. */ def safe(j:Long) { for (k in 0..(fixed-1)) { if (j == q(k) || Math.abs(fixed-k) == Math.abs(j-q(k))) return false; } return true; } /** Search all positions for the current board. */ def search() { for (k in R) searchOne(k); } /** * Modify the current board by adding a new queen * in file k on rank fixed, * and search for all safe positions with this prefix. */ def searchOne(k:Long) { if (safe(k)) { if (fixed==(N-1)) { // all ranks safely filled atomic NQueensDist.this.results(here.id)++; } else { q(fixed++) = k; search(); fixed--; } } } /** * Search this board, dividing the work between all places * using a block distribution of the current free rank. */ def distSearch() { val work = R.split(Place.numPlaces()); finish for (p in Place.places()) { val myPiece = work(p.id); at (p) async { // implicit copy of 'this' made across the at divide for (k in myPiece) { searchOne(k); } } } } } public static def main(args:Rail[String]) { val n = args.size > 0 ? Long.parse(args(0)) : 8; Console.OUT.println("N=" + n); //warmup //finish new NQueensPar(12, 1).start(); val P = Place.numPlaces(); val nq = new NQueensDist(n,P); var start:Long = -System.nanoTime(); val answer = nq.run(); val result = answer==EXPECTED_SOLUTIONS(n); start += System.nanoTime(); start /= 1000000; Console.OUT.println("NQueensDist " + nq.N + "(P=" + P + ") has " + answer + " solutions" + (result? " (ok)." : " (wrong).") + "time=" + start + "ms"); } }