Skip to content

Commit

Permalink
preperation for distributed
Browse files Browse the repository at this point in the history
change variables in solvers from ijkl to ld rd col and startQueensIjklList
  • Loading branch information
timmitohnetim committed Jan 6, 2022
1 parent 1bd8a77 commit 2fec7d9
Show file tree
Hide file tree
Showing 4 changed files with 175 additions and 91 deletions.
5 changes: 3 additions & 2 deletions src/de/nqueensfaf/SolverTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ void tearDown() throws Exception {
// @Test
// void testCpuSolver() {
// CpuSolver s = new CpuSolver();
// s.setN(6);
// s.setN(17);
// s.setThreadcount(4);
// s.addTerminationCallback(() -> {
// System.out.println(s.getSolutions() + " solutions found in " + s.getDuration() + " ms");
// });
Expand All @@ -52,7 +53,7 @@ void testGpuSolver() {
GpuSolver s = new GpuSolver();
s.setDevice(0);
s.setProgressUpdatesEnabled(false);
s.setN(17);
s.setN(18);
new Thread(() -> {
while(true) {
if(s.getGlobalWorkSize() == 0) {
Expand Down
180 changes: 157 additions & 23 deletions src/de/nqueensfaf/compute/CpuSolver.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,24 +19,26 @@ public class CpuSolver extends Solver {

private final int smallestN = 6;
private int threadcount = 1;
private int kbit, lbit, preQueens = 4, L, mask, LD, RD, counter;
private long start, end;
private HashSet<Integer>
startConstellations = new HashSet<Integer>();
private HashSet<Integer> startConstellations = new HashSet<Integer>();
private ArrayList<Integer> ldList = new ArrayList<Integer>(), rdList = new ArrayList<Integer>(), colList = new ArrayList<Integer>();
private ArrayList<Integer> startQueensIjklList = new ArrayList<Integer>();
private ArrayList<CpuSolverThread> threads = new ArrayList<CpuSolverThread>();
private int startConstCount, solvedConstellations;
private long timePassed = 0, pauseStart = 0;
private long solutions;
private boolean restored = false;
private ArrayList<Runnable> pausing = new ArrayList<Runnable>();

// inherited functions
@Override
protected void run() {
// check if run is called without calling reset after a run call had finished
if(start != 0) {
throw new IllegalStateException("You first have to call reset() when calling solve() multiple times on the same object");
}

start = System.currentTimeMillis();
if(N <= smallestN) { // if N is very small, use the simple Solver from the parent class
solutions = solveSmallBoard();
Expand All @@ -50,7 +52,7 @@ protected void run() {
genConstellations();
startConstCount = startConstellations.size();
}

// split starting constellations in [cpu] many lists (splitting the work for the threads)
ArrayList<ArrayDeque<Integer>> threadConstellations = new ArrayList<ArrayDeque<Integer>>(threadcount);
for(int i = 0; i < threadcount; i++) {
Expand All @@ -64,11 +66,11 @@ protected void run() {
// start the threads and wait until they are all finished
ExecutorService executor = Executors.newFixedThreadPool(threadcount);
for(i = 0; i < threadcount; i++) {
CpuSolverThread cpuSolverThread = new CpuSolverThread(N, threadConstellations.get(i), this);
CpuSolverThread cpuSolverThread = new CpuSolverThread(N, threadConstellations.get(i), this, ldList, rdList, colList, startQueensIjklList);
threads.add(cpuSolverThread);
executor.submit(cpuSolverThread);
}

// wait for the threads to finish
executor.shutdown();
try {
Expand All @@ -84,7 +86,7 @@ protected void run() {
}
restored = false;
}

@Override
public void store_(String filepath) throws IOException {
// if Solver was not even started yet, throw exception
Expand All @@ -102,7 +104,7 @@ public void store_(String filepath) throws IOException {
}
long timePassed = getDuration();
RestorationInformation resInfo = new RestorationInformation(N, startConstellations, timePassed, solutions, startConstCount);

FileOutputStream fos = new FileOutputStream(filepath);
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(resInfo);
Expand Down Expand Up @@ -132,12 +134,12 @@ public void restore_(String filepath) throws IOException, ClassNotFoundException
solvedConstellations = startConstCount - startConstellations.size();
restored = true;
}

@Override
public boolean isRestored() {
return restored;
}

@Override
public void reset() {
start = 0;
Expand Down Expand Up @@ -189,13 +191,15 @@ public long getSolutions() {
}
return solutions;
}

// own functions
private void genConstellations() {
startConstellations.clear();

// halfN half of N rounded up
final int halfN = (N + 1) / 2;
L = 1 << (N -1);
mask = (1 << N) - 1;

// calculating start constellations with the first Queen on square (0,0)
for(int j = 1; j < N-2; j++) { // j is idx of Queen in last row
Expand All @@ -221,8 +225,92 @@ private void genConstellations() {
}
}
}
HashSet<Integer> startConstellationsJasmin = new HashSet<Integer>();
// 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 : startConstellations) {
startConstellationsJasmin.add(jasmin(startConstellation));
}
startConstellations = startConstellationsJasmin;

int i, j, k, l, ld, rd, col, currentSize = 0;
for(int sc : startConstellations) {
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
ld = (L >>> (i-1)) | (1 << (N-k));
rd = (L >>> (i+1)) | (1 << (l-1));
col = 1 | L | (L >>> j) | (L >>> i);
// occupy diagonals of the queens j k l in the last row
// later we are going to shift them upwards the board
LD = (L >>> j) | (L >>> l);
RD = (L >>> j) | (1 << k);
// this is the queen in row k and l
// their diagonals have to be occupied later
// we can not do this right now, because in row k, the queen k has to be actually set
kbit = (1 << (N-k-1));
lbit = (1 << l);

// counts all subconstellations
counter = 0;
// generate all subconstellations
setPreQueens(ld, rd, col, k, l, 1, 4);
currentSize = startQueensIjklList.size();
// jkl and sym and start are the same for all subconstellations
for(int a = 0; a < counter; a++) {
startQueensIjklList.set(currentSize-a-1, startQueensIjklList.get(currentSize-a-1) | (preQueens << 20) | toijkl(i, j, k, l));
}
}
}


// generate subconstellations for each starting constellation with 3 or 4 queens
private void setPreQueens(int ld, int rd, int col, int k, int l, int row, int queens) {
// in row k and l just go further
if(row == k || row == l) {
setPreQueens(ld<<1, rd>>>1, col, k, l, row+1, queens);
return;
}
// add queens until we have preQueens queens
// this should be variable for the distributed version and different N
if(queens == preQueens) {
// occupy diagonals from queen k and l, that will end in the left or right border
// the following 2 lines are probably TRASH
ld &= ~(kbit << row);
rd &= ~(lbit >>> row);
// make left and right col free
col &= ~(1 | L);
// if k already came, then occupy it on the board
if(k < row) {
rd |= (L >> (row-k));
col |= L;
}
// same for l
if(l < row) {
ld |= (1 << (row-l));
col |= 1;
}
// add the subconstellations to the list
ldList.add(ld);
rdList.add(rd);
colList.add(col);
startQueensIjklList.add(row << 25);
counter++;
return;
}
// if not done or row k or l, just place queens and occupy the board and go further
else {
int free = ~(ld | rd | col | (LD >>> (N-1-row)) | (RD << (N-1-row))) & mask;
int bit;

while(free > 0) {
bit = free & (-free);
free -= bit;
setPreQueens((ld|bit) << 1, (rd|bit) >>> 1, col|bit, k, l, row+1, queens+1);
}
}
}



// true, if starting constellation rotated by any angle has already been found
private boolean checkRotations(int i, int j, int k, int l) {
// rot90
Expand All @@ -240,10 +328,56 @@ private boolean checkRotations(int i, int j, int k, int l) {
return false;
}

// wrap i, j, k and l to one integer using bitwise movement
// i, j, k, l to ijkl and functions to get specific entry
private int toijkl(int i, int j, int k, int l) {
return (i<<24) + (j<<16) + (k<<8) + l;
}
private int geti(int ijkl) {
return ijkl >> 24;
}
private int getj(int ijkl) {
return (ijkl >> 16) & 255;
}
private int getk(int ijkl) {
return (ijkl >> 8) & 255;
}
private int getl(int ijkl) {
return ijkl & 255;
}
// rotate and mirror board, so that the queen closest to a corner is on the right side of the last row
private int jasmin(int ijkl) {
int min = Math.min(getj(ijkl), N-1 - getj(ijkl)), arg = 0;

if(Math.min(geti(ijkl), N-1 - geti(ijkl)) < min) {
arg = 2;
min = Math.min(geti(ijkl), N-1 - geti(ijkl));
}
if(Math.min(getk(ijkl), N-1 - getk(ijkl)) < min) {
arg = 3;
min = Math.min(getk(ijkl), N-1 - getk(ijkl));
}
if(Math.min(getl(ijkl), N-1 - getl(ijkl)) < min) {
arg = 1;
min = Math.min(getl(ijkl), N-1 - getl(ijkl));
}

for(int i = 0; i < arg; i++) {
ijkl = rot90(ijkl);
}

if(getj(ijkl) < N-1 - getj(ijkl))
ijkl = mirvert(ijkl);

return ijkl;
}
// mirror left-right
private int mirvert(int ijkl) {
return toijkl(N-1-geti(ijkl), N-1-getj(ijkl), getl(ijkl), getk(ijkl));
}
// rotate 90 degrees clockwise
private int rot90(int ijkl) {
return ((N-1-getk(ijkl))<<24) + ((N-1-getl(ijkl))<<16) + (getj(ijkl)<<8) + geti(ijkl);
}

// for user interaction
public void pause() {
Expand All @@ -257,7 +391,7 @@ public void pause() {
t.pauseThread();
}
}

public void cancel() {
if(!isRunning()) {
throw new IllegalStateException("unable to cancel a CpuSolver when it is not running");
Expand All @@ -266,7 +400,7 @@ public void cancel() {
t.cancelThread();
}
}

public void resume() {
if(!isRunning()) {
throw new IllegalStateException("unable to resume a CpuSolver when it is not running");
Expand All @@ -280,7 +414,7 @@ public void resume() {
pauseStart = 0;
}
}

public boolean isPaused() {
if(threads.size() <= 0) {
return false;
Expand All @@ -291,7 +425,7 @@ public boolean isPaused() {
}
return true;
}

public boolean wasCanceled() {
if(isRunning() || N <= smallestN) {
return false;
Expand All @@ -302,14 +436,14 @@ public boolean wasCanceled() {
}
return true;
}

public void addOnPauseCallback(Runnable r) {
if(r == null) {
throw new IllegalArgumentException("pausing callback must not be null");
}
pausing.add(r);
}

// is called from the SolverThreads to measure correct time of the start of the pause
synchronized void onPauseStart() {
if(isPaused() && pauseStart == 0) {
Expand All @@ -321,19 +455,19 @@ synchronized void onPauseStart() {
}
}
}

// getters and setters
public void setThreadcount(int threadcount) {
if(threadcount < 1 || threadcount > Runtime.getRuntime().availableProcessors()) {
throw new IllegalArgumentException("threadcount must be a number between 1 and " + Runtime.getRuntime().availableProcessors() + " (=your CPU's number of logical cores) (inclusive)");
}
this.threadcount = threadcount;
}

public int getThreadcount() {
return threadcount;
}

// for saving and restoring
private record RestorationInformation(int N, HashSet<Integer> startConstellations, long timePassed, long solutions, int startConstCount) implements Serializable {
RestorationInformation(int N, HashSet<Integer> startConstellations, long timePassed, long solutions, int startConstCount) {
Expand Down
Loading

0 comments on commit 2fec7d9

Please sign in to comment.