Skip to content

Commit

Permalink
Merge pull request #74 from olepoeschl/generator-for-distributed
Browse files Browse the repository at this point in the history
Unified Constellations Generator for CPUSolver and GPUSolver
  • Loading branch information
olepoeschl authored Jan 6, 2024
2 parents 072d2fb + 75cc0c1 commit 1c29f74
Show file tree
Hide file tree
Showing 4 changed files with 162 additions and 289 deletions.
108 changes: 1 addition & 107 deletions src/main/java/de/nqueensfaf/impl/CPUSolver.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
Expand All @@ -22,8 +21,6 @@
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
Expand All @@ -32,9 +29,7 @@ public class CPUSolver extends Solver {
// smallestN marks the border, when to use this simpler solver
private static final int smallestN = 6;

private int L, mask, LD, RD, counter;
private long start, end;
private HashSet<Integer> ijklList;
private ArrayList<Constellation> constellations;
private ArrayList<CPUSolverThread> threads;
private ArrayList<ArrayList<Constellation>> threadConstellations;
Expand All @@ -46,7 +41,6 @@ public class CPUSolver extends Solver {

public CPUSolver() {
config = new CPUSolverConfig();
ijklList = new HashSet<Integer>();
constellations = new ArrayList<Constellation>();
threads = new ArrayList<CPUSolverThread>();
loaded = false;
Expand All @@ -63,7 +57,7 @@ protected void run() {
}

if (!loaded) {
genConstellations();
constellations = new ConstellationsGenerator(n, config.presetQueens).generate();
}

// split starting constellations in [threadcount] lists (splitting the work for
Expand Down Expand Up @@ -178,106 +172,6 @@ public long getSolutions() {
}
return solutions;
}

private void genConstellations() {
// halfN half of n rounded up
final int halfN = (n + 1) / 2;
L = 1 << (n - 1);
mask = (1 << n) - 1;

// calculate starting constellations for no Queens in corners
for (int k = 1; k < halfN; k++) { // go through first col
for (int l = k + 1; l < n - 1; l++) { // go through last col
for (int i = k + 1; i < n - 1; i++) { // go through first row
if (i == n - 1 - l) // skip if occupied
continue;
for (int j = n - k - 2; j > 0; j--) { // go through last row
if (j == i || l == j)
continue;

if (!checkRotations(n, ijklList, i, j, k, l)) { // if no rotation-symmetric starting
// constellation already
// found
ijklList.add(toIjkl(i, j, k, l));
}
}
}
}
}
// calculating start constellations with the first Queen on the corner square
// (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(toIjkl(0, j, 0, l));
}
}

HashSet<Integer> ijklListJasmin = 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 : ijklList) {
ijklListJasmin.add(jAsMin(n, startConstellation));
}
ijklList = ijklListJasmin;

int i, j, k, l, ld, rd, col, currentSize = 0;
for (int sc : ijklList) {
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
// we are starting in the first row that can be free, namely row 1
ld = (L >>> (i - 1)) | (1 << (n - k));
rd = (L >>> (i + 1)) | (1 << (l - 1));
col = 1 | L | (L >>> i) | (L >>> j);
// 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);

// counts all subconstellations
counter = 0;
// generate all subconstellations
setPreQueens(ld, rd, col, k, l, 1, j == n - 1 ? 3 : 4);
currentSize = constellations.size();
// 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() | 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
if (queens == config.presetQueens) {
// add the subconstellations to the list
constellations.add(new Constellation(-1, ld, rd, col, row << 20, -1));
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);
}
}
}

// debug info
public int getNumberOfConstellations() {
Expand Down
160 changes: 160 additions & 0 deletions src/main/java/de/nqueensfaf/impl/ConstellationsGenerator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
package de.nqueensfaf.impl;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.function.Consumer;

import static de.nqueensfaf.impl.SolverUtils.*;

public class ConstellationsGenerator {

private ArrayList<Constellation> constellations;
private int n, presetQueens;
private int L, mask, LD, RD, subConstellationsCounter;
private HashSet<Integer> ijklList;

public ConstellationsGenerator(int n, int presetQueens) {
this.n = n;
this.presetQueens = presetQueens;

L = (1 << (n - 1));
mask = (L << 1) - 1;
}

public ArrayList<Constellation> generate(){
return generate(null);
}

public ArrayList<Constellation> generate(Consumer<Constellation> constellationConsumer){
generateIjkls();

constellations = new ArrayList<Constellation>();

int i, j, k, l, ld, rd, col, currentSize = 0;
for (int ijkl : ijklList) {
ijkl = jAsMin(n, ijkl);
i = geti(ijkl);
j = getj(ijkl);
k = getk(ijkl);
l = getl(ijkl);

// counts all subconstellations
subConstellationsCounter = 0;

// 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
// we are starting in the first row that can be free, namely row 1
ld = (L >>> (i - 1)) | (1 << (n - k));
rd = (L >>> (i + 1)) | (1 << (l - 1));
col = 1 | L | (L >>> i) | (L >>> j);
// 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);

// generate all subconstellations
placePresetQueens(ld, rd, col, k, l, 1, j == n - 1 ? 3 : 4);
currentSize = constellations.size();

// jkl and sym and start are the same for all subconstellations
for (int a = 0; a < subConstellationsCounter; a++) {
var c = constellations.get(currentSize - a - 1);
c.setStartIjkl(c.getStartIjkl() | ijkl);
c.setId(currentSize - a - 1);

if(constellationConsumer != null)
constellationConsumer.accept(constellations.get(currentSize - a - 1));
}
}

return constellations;
}

public ArrayList<Constellation> generateSubConstellations(ArrayList<Constellation> baseConstellations){
constellations = new ArrayList<Constellation>();

int currentSize;

for(var bc : baseConstellations) {
// counts all subconstellations
subConstellationsCounter = 0;

placePresetQueens(bc.getLd(), bc.getRd(), bc.getCol(), getk(bc.getIjkl()), getl(bc.getIjkl()),
bc.getStartIjkl() >> 20, bc.getStartIjkl() >> 20); // from row start to row presetQueens
currentSize = constellations.size();

// jkl and sym and start are the same for all subconstellations
for (int a = 0; a < subConstellationsCounter; a++) {
var c = constellations.get(currentSize - a - 1);
c.setStartIjkl(c.getStartIjkl() | bc.getIjkl());
c.setId(bc.getId());
}
}

return constellations;
}

private void generateIjkls() {
ijklList = new HashSet<Integer>();

// half of n rounded up
final int halfN = (n + 1) / 2;

// calculate starting constellations for no Queens in corners
for (int j = 1; j < halfN; j++) { // go through last row
for (int l = j + 1; l < n - 1; l++) { // go through last col
for (int k = n - j - 2; k > 0; k--) { // go through first col
if (k == l) // skip if occupied
continue;
for (int i = j + 1; i < n - 1; i++) { // go through first row
if (i == n - 1 - l || i == k) // skip if occupied
continue;

if (!checkRotations(n, ijklList, i, j, k, l)) {
// if no rotation-symmetric starting constellation is found
ijklList.add(toIjkl(i, j, k, l));
}
}
}
}
}

// calculating start constellations with the first Queen on the corner square
// (0,0)
for (int k = 1; k < n - 2; k++) { // j is idx of Queen in last row
for (int i = k + 1; i < n - 1; i++) { // l is idx of Queen in last col
// always add the constellation, we can not accidently get symmetric ones
ijklList.add(toIjkl(i, n - 1, k, n - 1));
}
}
}

// generate sub constellations for each starting constellation
private void placePresetQueens(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) {
placePresetQueens(ld << 1, rd >>> 1, col, k, l, row + 1, queens);
return;
}
// add queens until we have preQueens queens
if (queens == presetQueens) {
// add the subconstellations to the list
constellations.add(new Constellation(0, ld, rd, col, row << 20, -1));
subConstellationsCounter++;
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;
placePresetQueens((ld | bit) << 1, (rd | bit) >>> 1, col | bit, k, l, row + 1, queens + 1);
}
}
}
}
Loading

0 comments on commit 1c29f74

Please sign in to comment.