diff --git a/src/main/java/de/nqueensfaf/impl/CPUSolver.java b/src/main/java/de/nqueensfaf/impl/CPUSolver.java index 144f6f45..399cd40b 100644 --- a/src/main/java/de/nqueensfaf/impl/CPUSolver.java +++ b/src/main/java/de/nqueensfaf/impl/CPUSolver.java @@ -22,6 +22,8 @@ import de.nqueensfaf.Solver; import de.nqueensfaf.persistence.SolverState; +import static de.nqueensfaf.impl.SolverUtils.*; + public class CPUSolver extends Solver { // for very small n it is overkill to use this method @@ -41,11 +43,9 @@ public class CPUSolver extends Solver { private boolean loaded; private CPUSolverConfig config; - private SolverUtils utils; public CPUSolver() { config = new CPUSolverConfig(); - utils = new SolverUtils(); ijklList = new HashSet(); constellations = new ArrayList(); threads = new ArrayList(); @@ -62,7 +62,6 @@ protected void run() { return; } - utils.setN(n); if (!loaded) { genConstellations(); } @@ -83,7 +82,7 @@ protected void run() { // start the threads and wait until they are all finished ExecutorService executor = Executors.newFixedThreadPool(config.threadcount); for (i = 0; i < config.threadcount; i++) { - CPUSolverThread cpuSolverThread = new CPUSolverThread(utils, n, threadConstellations.get(i)); + CPUSolverThread cpuSolverThread = new CPUSolverThread(n, threadConstellations.get(i)); threads.add(cpuSolverThread); executor.submit(cpuSolverThread); } @@ -196,10 +195,10 @@ private void genConstellations() { if (j == i || l == j) continue; - if (!utils.checkRotations(ijklList, i, j, k, l)) { // if no rotation-symmetric starting + if (!checkRotations(n, ijklList, i, j, k, l)) { // if no rotation-symmetric starting // constellation already // found - ijklList.add(utils.toijkl(i, j, k, l)); + ijklList.add(toIjkl(i, j, k, l)); } } } @@ -209,7 +208,7 @@ private void genConstellations() { // (0,0) for (int j = 1; j < n - 2; j++) { // j is idx of Queen in last row for (int l = j + 1; l < n - 1; l++) { // l is idx of Queen in last col - ijklList.add(utils.toijkl(0, j, 0, l)); + ijklList.add(toIjkl(0, j, 0, l)); } } @@ -217,16 +216,16 @@ private void genConstellations() { // rotate and mirror all start constellations, such that the queen in the last // row is as close to the right border as possible for (int startConstellation : ijklList) { - ijklListJasmin.add(utils.jasmin(startConstellation)); + ijklListJasmin.add(jasmin(n, startConstellation)); } ijklList = ijklListJasmin; int i, j, k, l, ld, rd, col, currentSize = 0; for (int sc : ijklList) { - i = utils.geti(sc); - j = utils.getj(sc); - k = utils.getk(sc); - l = utils.getl(sc); + i = geti(sc); + j = getj(sc); + k = getk(sc); + l = getl(sc); // fill up the board with preQueens queens and generate corresponding variables // ld, rd, col, start_queens_ijkl for each constellation // occupy the board corresponding to the queens on the borders of the board @@ -247,7 +246,7 @@ private void genConstellations() { // jkl and sym and start are the same for all subconstellations for (int a = 0; a < counter; a++) { constellations.get(currentSize - a - 1) - .setStartIjkl(constellations.get(currentSize - a - 1).getStartIjkl() | utils.toijkl(i, j, k, l)); + .setStartIjkl(constellations.get(currentSize - a - 1).getStartIjkl() | toIjkl(i, j, k, l)); } } } diff --git a/src/main/java/de/nqueensfaf/impl/CPUSolverThread.java b/src/main/java/de/nqueensfaf/impl/CPUSolverThread.java index 07f1b967..7673a21d 100644 --- a/src/main/java/de/nqueensfaf/impl/CPUSolverThread.java +++ b/src/main/java/de/nqueensfaf/impl/CPUSolverThread.java @@ -2,6 +2,8 @@ import java.util.ArrayList; +import static de.nqueensfaf.impl.SolverUtils.*; + class CPUSolverThread extends Thread { private final int n, n3, n4, L, L3, L4; // boardsize @@ -16,10 +18,8 @@ class CPUSolverThread extends Thread { // list of uncalculated starting positions, their indices private ArrayList constellations; - - private SolverUtils utils; - CPUSolverThread(SolverUtils utils, int n, ArrayList constellations) { + CPUSolverThread(int n, ArrayList constellations) { this.n = n; n3 = n - 3; n4 = n - 4; @@ -27,7 +27,6 @@ class CPUSolverThread extends Thread { L3 = 1 << n3; L4 = 1 << n4; this.constellations = constellations; - this.utils = utils; } // Recursive functions for Placing the Queens @@ -775,9 +774,9 @@ public void run() { startIjkl = constellation.getStartIjkl(); start = startIjkl >> 20; ijkl = startIjkl & ((1 << 20) - 1); - j = utils.getj(ijkl); - k = utils.getk(ijkl); - l = utils.getl(ijkl); + j = getj(ijkl); + k = getk(ijkl); + l = getl(ijkl); // IMPORTANT NOTE: we shift ld and rd one to the right, because the right // column does not matter (always occupied by queen l) @@ -1059,7 +1058,7 @@ else if (j == n - 2) { } // for saving and loading progress remove the finished starting constellation - constellation.setSolutions(tempcounter * utils.symmetry(ijkl)); + constellation.setSolutions(tempcounter * symmetry(n, ijkl)); tempcounter = 0; } } diff --git a/src/main/java/de/nqueensfaf/impl/GPUSolver.java b/src/main/java/de/nqueensfaf/impl/GPUSolver.java index ad225096..9717e97f 100644 --- a/src/main/java/de/nqueensfaf/impl/GPUSolver.java +++ b/src/main/java/de/nqueensfaf/impl/GPUSolver.java @@ -31,6 +31,7 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; +import static de.nqueensfaf.impl.SolverUtils.*; import static de.nqueensfaf.impl.InfoUtil.*; import static org.lwjgl.opencl.CL12.*; import static org.lwjgl.system.MemoryStack.*; @@ -55,11 +56,9 @@ public class GPUSolver extends Solver { private boolean loaded; private GPUSolverConfig config; - private SolverUtils utils; public GPUSolver() { config = new GPUSolverConfig(); - utils = new SolverUtils(); devices = new ArrayList(); availableDevices = new ArrayList(); constellations = new ArrayList(); @@ -87,7 +86,6 @@ protected void run() { throw new IllegalStateException("no devices selected"); try (MemoryStack stack = stackPush()) { - utils.setN(n); if (!loaded) genConstellations(); // generate constellations var remainingConstellations = constellations.stream().filter(c -> c.getSolutions() < 0) @@ -203,7 +201,7 @@ void sortConstellations(List constellations) { public int compare(Constellation o1, Constellation o2) { int o1ijkl = o1.getStartIjkl() & ((1 << 20) - 1); int o2ijkl = o2.getStartIjkl() & ((1 << 20) - 1); - return Integer.compare(utils.getjkl(o1ijkl), utils.getjkl(o2ijkl)); + return Integer.compare(getJkl(o1ijkl), getJkl(o2ijkl)); } }); } @@ -441,7 +439,7 @@ private void readResults(Device device) { if (device.workloadConstellations.get(i).getStartIjkl() >> 20 == 69) // start=69 is for trash constellations continue; long solutionsForConstellation = device.resPtr.getLong(i * 8) - * utils.symmetry(device.workloadConstellations.get(i).getStartIjkl() & 0b11111111111111111111); + * symmetry(n, device.workloadConstellations.get(i).getStartIjkl() & 0b11111111111111111111); if (solutionsForConstellation >= 0) // synchronize with the list of constellations on the RAM device.workloadConstellations.get(i).setSolutions(solutionsForConstellation); diff --git a/src/main/java/de/nqueensfaf/impl/SolverUtils.java b/src/main/java/de/nqueensfaf/impl/SolverUtils.java index 22e2b23a..cb8d54cd 100644 --- a/src/main/java/de/nqueensfaf/impl/SolverUtils.java +++ b/src/main/java/de/nqueensfaf/impl/SolverUtils.java @@ -3,18 +3,38 @@ import java.util.HashSet; class SolverUtils { - - private int n; - SolverUtils() { + // functions for ijkl manipulation + static int toIjkl(int i, int j, int k, int l) { + return (i << 15) + (j << 10) + (k << 5) + l; + } + + static int geti(int ijkl) { + return ijkl >> 15; + } + + static int getj(int ijkl) { + return (ijkl >> 10) & 31; + } + + static int getk(int ijkl) { + return (ijkl >> 5) & 31; + } + + static int getl(int ijkl) { + return ijkl & 31; } - void setN(int n) { - this.n = n; + static int getJkl(int ijkl) { + return ijkl & 0b111111111111111; + } + + static boolean oneQueenInCorner(int n, int ijkl) { + return getj(ijkl) == n-1 && getl(ijkl) == n-1; } // true, if starting constellation rotated by any angle has already been found - boolean checkRotations(HashSet ijklList, int i, int j, int k, int l) { + static boolean checkRotations(int n, HashSet ijklList, int i, int j, int k, int l) { // rot90 if (ijklList.contains(((n - 1 - k) << 15) + ((n - 1 - l) << 10) + (j << 5) + i)) return true; @@ -30,34 +50,9 @@ boolean checkRotations(HashSet ijklList, int i, int j, int k, int l) { return false; } - // i, j, k, l to ijkl and functions to get specific entry - int toijkl(int i, int j, int k, int l) { - return (i << 15) + (j << 10) + (k << 5) + l; - } - - int geti(int ijkl) { - return ijkl >> 15; - } - - int getj(int ijkl) { - return (ijkl >> 10) & 31; - } - - int getk(int ijkl) { - return (ijkl >> 5) & 31; - } - - int getl(int ijkl) { - return ijkl & 31; - } - - int getjkl(int ijkl) { - return ijkl & 0b111111111111111; - } - // rotate and mirror board, so that the queen closest to a corner is on the // right side of the last row - int jasmin(int ijkl) { + static int jasmin(int n, int ijkl) { int min = Math.min(getj(ijkl), n - 1 - getj(ijkl)), arg = 0; if (Math.min(geti(ijkl), n - 1 - geti(ijkl)) < min) { @@ -74,43 +69,43 @@ int jasmin(int ijkl) { } for (int i = 0; i < arg; i++) { - ijkl = rot90(ijkl); + ijkl = rot90(n, ijkl); } if (getj(ijkl) < n - 1 - getj(ijkl)) - ijkl = mirvert(ijkl); + ijkl = mirvert(n, ijkl); return ijkl; } // mirror left-right - int mirvert(int ijkl) { - return toijkl(n - 1 - geti(ijkl), n - 1 - getj(ijkl), getl(ijkl), getk(ijkl)); + private static int mirvert(int n, int ijkl) { + return toIjkl(n - 1 - geti(ijkl), n - 1 - getj(ijkl), getl(ijkl), getk(ijkl)); } // rotate 90 degrees clockwise - int rot90(int ijkl) { + private static int rot90(int n, int ijkl) { return ((n - 1 - getk(ijkl)) << 15) + ((n - 1 - getl(ijkl)) << 10) + (getj(ijkl) << 5) + geti(ijkl); } - // helper functions for doing the math - // for symmetry stuff and working with ijkl - // true, if starting constellation is symmetric for rot90 - boolean symmetry90(int ijkl) { - if (((geti(ijkl) << 15) + (getj(ijkl) << 10) + (getk(ijkl) << 5) + getl(ijkl)) == (((n - 1 - getk(ijkl)) << 15) - + ((n - 1 - getl(ijkl)) << 10) + (getj(ijkl) << 5) + geti(ijkl))) - return true; - return false; - } - // how often does a found solution count for this start constellation - int symmetry(int ijkl) { + static int symmetry(int n, int ijkl) { if (geti(ijkl) == n - 1 - getj(ijkl) && getk(ijkl) == n - 1 - getl(ijkl)) // starting constellation symmetric by rot180? - if (symmetry90(ijkl)) // even by rot90? + if (symmetry90(n, ijkl)) // even by rot90? return 2; else return 4; else return 8; // none of the above? } + + // helper functions for doing the math + // for symmetry stuff and working with ijkl + // true, if starting constellation is symmetric for rot90 + private static boolean symmetry90(int n, int ijkl) { + if (((geti(ijkl) << 15) + (getj(ijkl) << 10) + (getk(ijkl) << 5) + getl(ijkl)) == (((n - 1 - getk(ijkl)) << 15) + + ((n - 1 - getl(ijkl)) << 10) + (getj(ijkl) << 5) + geti(ijkl))) + return true; + return false; + } }