Skip to content

Commit

Permalink
Solver class without generics, callbacks are just runnables
Browse files Browse the repository at this point in the history
  • Loading branch information
[email protected] committed Feb 26, 2024
1 parent c5d6fd5 commit 9eccca9
Show file tree
Hide file tree
Showing 6 changed files with 61 additions and 90 deletions.
36 changes: 18 additions & 18 deletions src/main/java/de/nqueensfaf/Demo.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,26 +13,26 @@ public static void main(String[] args) {
}

static void cpu() {
new CpuSolver()
.setPresetQueens(5)
.setThreadCount(1)
.setUpdateInterval(800)
.onInit(self -> System.out.println("Starting Solver for board size " + self.getN() + "..."))
.onUpdate((self, progress, solutions, duration) -> System.out.println("progress: " + progress + " solutions: " + solutions + " duration: " + duration))
.onFinish(self -> System.out.println("Found " + self.getSolutions() + " solutions in " + self.getDuration() + " ms"))
.setN(16)
.solve();
var cs = new CpuSolver();
cs.setPresetQueens(5);
cs.setThreadCount(1);
cs.setUpdateInterval(800);
cs.onInit(() -> System.out.println("Starting Solver for board size " + cs.getN() + "..."));
cs.onUpdate((progress, solutions, duration) -> System.out.println("progress: " + progress + " solutions: " + solutions + " duration: " + duration));
cs.onFinish(() -> System.out.println("Found " + cs.getSolutions() + " solutions in " + cs.getDuration() + " ms"));
cs.setN(16);
cs.solve();
}

static void gpu() {
GpuSolver g = new GpuSolver();
List<GpuInfo> availableGpus = g.getAvailableGpus();
g.gpuSelection().choose(availableGpus.get(0).id());
g.setUpdateInterval(400);
g.onInit(self -> System.out.println("Starting Solver for board size " + self.getN() + "..."))
.onUpdate((self, progress, solutions, duration) -> System.out.println("progress: " + progress + " solutions: " + solutions + " duration: " + duration))
.onFinish(self -> System.out.println("Found " + self.getSolutions() + " solutions in " + self.getDuration() + " ms"))
.setN(18)
.solve();
GpuSolver gs = new GpuSolver();
List<GpuInfo> availableGpus = gs.getAvailableGpus();
gs.gpuSelection().choose(availableGpus.get(0).id());
gs.setUpdateInterval(400);
gs.onInit(() -> System.out.println("Starting Solver for board size " + gs.getN() + "..."));
gs.onUpdate((progress, solutions, duration) -> System.out.println("progress: " + progress + " solutions: " + solutions + " duration: " + duration));
gs.onFinish(() -> System.out.println("Found " + gs.getSolutions() + " solutions in " + gs.getDuration() + " ms"));
gs.setN(18);
gs.solve();
}
}
69 changes: 25 additions & 44 deletions src/main/java/de/nqueensfaf/Solver.java
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
package de.nqueensfaf;

import java.util.function.Consumer;

public abstract class Solver<T extends Solver<T>> {
public abstract class Solver {

private int n;
private int updateInterval = 128;
private volatile Status status = Status.IDLE;
private OnUpdateConsumer<T> onUpdateConsumer;
private Runnable onInit, onFinish;
private OnUpdateConsumer onUpdate;
private Thread asyncSolverThread, bgThread;
private Consumer<T> initCb, finishCb;
private int solutionsSmallN = 0;

public abstract long getDuration();
Expand All @@ -18,26 +16,25 @@ public abstract class Solver<T extends Solver<T>> {

protected abstract void run();

@SuppressWarnings("unchecked")
public final T solve() {
public final void solve() {
preconditions();

status = Status.INITIALIZING;

if (initCb != null)
initCb.accept((T) this);
if (onInit != null)
onInit.run();

if(updateInterval > 0 && onUpdateConsumer != null) { // if updateInterval is 0, it means disable progress updates
if(updateInterval > 0 && onUpdate != null) { // if updateInterval is 0, it means disable progress updates
bgThread = new Thread(() -> {
while (isRunning() && getProgress() < 1f) {
onUpdateConsumer.accept((T) this, getProgress(), getSolutions(), getDuration());
onUpdate.accept(getProgress(), getSolutions(), getDuration());
try {
Thread.sleep(updateInterval);
} catch (InterruptedException e) {
// ignore
}
}
onUpdateConsumer.accept((T) this, getProgress(), getSolutions(), getDuration());
onUpdate.accept(getProgress(), getSolutions(), getDuration());
});
bgThread.start();
}
Expand All @@ -59,31 +56,25 @@ public final T solve() {
throw new RuntimeException("could not wait for background thread to terminate: " + e.getMessage(), e);
}
}
if (finishCb != null)
finishCb.accept((T) this);
if (onFinish != null)
onFinish.run();

status = Status.FINISHED;

return (T) this;
}

@SuppressWarnings("unchecked")
public final T solveAsync() {
public final void solveAsync() {
asyncSolverThread = new Thread(() -> solve());
asyncSolverThread.start();
return (T) this;
}

@SuppressWarnings("unchecked")
public final T waitFor() throws InterruptedException {
public final void waitFor() throws InterruptedException {
if(asyncSolverThread == null || !asyncSolverThread.isAlive())
throw new IllegalStateException("could not wait for solver thread to terminate: solver thread is not running");
try {
asyncSolverThread.join();
} catch (InterruptedException e) {
throw new InterruptedException("could not wait for solver thread to terminate: " + e.getMessage());
}
return (T) this;
}

private void preconditions() {
Expand Down Expand Up @@ -123,56 +114,46 @@ private void smallBoardNQ(int ld, int rd, int col, int row, int free, int mask)
}
}

@SuppressWarnings("unchecked")
public final T onInit(Consumer<T> c) {
public final void onInit(Runnable c) {
if (c == null) {
throw new IllegalArgumentException("could not set initialization callback: callback must not be null");
}
initCb = c;
return (T) this;
onInit = c;
}

@SuppressWarnings("unchecked")
public final T onFinish(Consumer<T> c) {
public final void onFinish(Runnable c) {
if (c == null) {
throw new IllegalArgumentException("could not set finish callback: callback must not be null");
}
finishCb = c;
return (T) this;
onFinish = c;
}

@SuppressWarnings("unchecked")
public final T onUpdate(OnUpdateConsumer<T> onUpdateConsumer) {
if (onUpdateConsumer == null) {
this.onUpdateConsumer = (self, progress, solutions, duration) -> {};
public final void onUpdate(OnUpdateConsumer onUpdate) {
if (onUpdate == null) {
this.onUpdate = (progress, solutions, duration) -> {};
} else {
this.onUpdateConsumer = onUpdateConsumer;
this.onUpdate = onUpdate;
}
return (T) this;
}

@SuppressWarnings("unchecked")
public final T setN(int n) {
public final void setN(int n) {
if (isInitializing() || isRunning() || isTerminating()) {
throw new IllegalStateException("could not set board size: solver already running");
}
if (n <= 0 || n > 31) {
throw new IllegalArgumentException("could not set board size: must be a number between >0 and <32");
}
this.n = n;
return (T) this;
}

public final int getN() {
return n;
}

@SuppressWarnings("unchecked")
public final T setUpdateInterval(int updateInterval) {
public final void setUpdateInterval(int updateInterval) {
if (updateInterval < 0)
throw new IllegalArgumentException("invalid value for updateInterval: must be a number >=0 (0 means disabling updates)");
this.updateInterval = updateInterval;
return (T) this;
}

public final int getUpdateInterval() {
Expand Down Expand Up @@ -207,7 +188,7 @@ private static enum Status {
IDLE, INITIALIZING, RUNNING, TERMINATING, FINISHED, CANCELED;
}

public interface OnUpdateConsumer<T extends Solver<T>> {
void accept(T self, float progress, long solutions, long duration);
public interface OnUpdateConsumer {
void accept(float progress, long solutions, long duration);
}
}
31 changes: 15 additions & 16 deletions src/main/java/de/nqueensfaf/cli/BaseCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;

import de.nqueensfaf.Solver;
import de.nqueensfaf.Solver.OnUpdateConsumer;
Expand Down Expand Up @@ -71,7 +70,7 @@ public void pathToSolverStateFile(String input) {

public BaseCommand() {}

private <T extends Solver<T>> OnUpdateConsumer<T> onUpdate(T solver) {
private OnUpdateConsumer onUpdate(Solver solver) {
if(solver instanceof Stateful && autoSaveProgressStep > 0) {
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
try {
Expand All @@ -82,7 +81,7 @@ private <T extends Solver<T>> OnUpdateConsumer<T> onUpdate(T solver) {
}
}));

return (self, progress, solutions, duration) -> {
return (progress, solutions, duration) -> {
if (loadingCharIdx == BaseCommand.loadingChars.length)
loadingCharIdx = 0;
System.out.format(BaseCommand.progressStringFormat, BaseCommand.loadingChars[loadingCharIdx++], progress, solutions,
Expand All @@ -100,7 +99,7 @@ private <T extends Solver<T>> OnUpdateConsumer<T> onUpdate(T solver) {
}
};
} else {
return (self, progress, solutions, duration) -> {
return (progress, solutions, duration) -> {
if (loadingCharIdx == BaseCommand.loadingChars.length)
loadingCharIdx = 0;
System.out.format(BaseCommand.progressStringFormat, BaseCommand.loadingChars[loadingCharIdx++], progress, solutions,
Expand All @@ -111,13 +110,13 @@ private <T extends Solver<T>> OnUpdateConsumer<T> onUpdate(T solver) {

}

private <T extends Solver<T>> Consumer<T> onFinish(T solver){
private Runnable onFinish(Solver solver){
if(solver instanceof Stateful && autoSaveProgressStep > 0) {
return (s) -> {
if(s.getUpdateInterval() > 0)
return () -> {
if(solver.getUpdateInterval() > 0)
System.out.println();
System.out.println("found " + s.getSolutions() + " solutions in "
+ getDurationPrettyString(s.getDuration()));
System.out.println("found " + solver.getSolutions() + " solutions in "
+ getDurationPrettyString(solver.getDuration()));

autoSaveExecutorService.shutdown();
try {
Expand All @@ -127,17 +126,17 @@ private <T extends Solver<T>> Consumer<T> onFinish(T solver){
}
};
} else {
return (s) -> {
if(s.getUpdateInterval() > 0)
return () -> {
if(solver.getUpdateInterval() > 0)
System.out.println();
System.out.println("found " + s.getSolutions() + " solutions in "
+ getDurationPrettyString(s.getDuration()));
System.out.println("found " + solver.getSolutions() + " solutions in "
+ getDurationPrettyString(solver.getDuration()));
};
}
}

<T extends Solver<T>> void applySolverConfig(T solver){
solver.onInit(s -> System.out.println("starting solver for board size " + s.getN() + "..."));
void applySolverConfig(Solver solver){
solver.onInit(() -> System.out.println("starting solver for board size " + solver.getN() + "..."));
solver.onFinish(onFinish(solver));
solver.onUpdate(onUpdate(solver));

Expand All @@ -152,7 +151,7 @@ <T extends Solver<T>> void applySolverConfig(T solver){
}
}

<T extends Solver<T>> long getUniqueSolutions(T solver) {
long getUniqueSolutions(Solver solver) {
SymSolver symSolver = new SymSolver();
symSolver.setN(solver.getN());
symSolver.solve();
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/de/nqueensfaf/impl/CpuSolver.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

import de.nqueensfaf.Solver;

public class CpuSolver extends Solver<CpuSolver> implements Stateful {
public class CpuSolver extends Solver implements Stateful {

private ArrayList<Constellation> constellations = new ArrayList<Constellation>();
private ArrayList<ArrayList<Constellation>> threadConstellations = new ArrayList<ArrayList<Constellation>>();
Expand Down
11 changes: 1 addition & 10 deletions src/main/java/de/nqueensfaf/impl/GpuSolver.java
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@

import de.nqueensfaf.Solver;

public class GpuSolver extends Solver<GpuSolver> implements Stateful {
public class GpuSolver extends Solver implements Stateful {

private ArrayList<Gpu> availableGpus = new ArrayList<Gpu>();
private GpuSelection gpuSelection = new GpuSelection();
Expand Down Expand Up @@ -393,15 +393,6 @@ private String readKernelSource(String filepath) throws IOException {
return resultString;
}

private int findNextJklChangeIndex(List<Constellation> constellations, int fromIndex) {
int currentJkl = getJkl(constellations.get(fromIndex).extractIjkl());
for (int i = fromIndex; i < constellations.size(); i++) {
if (getJkl(constellations.get(i).extractIjkl()) != currentJkl)
return i;
}
return constellations.size();
}

private void sortConstellationsByJkl(List<Constellation> constellations) {
Collections.sort(constellations, new Comparator<Constellation>() {
@Override
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/de/nqueensfaf/impl/SymSolver.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import de.nqueensfaf.Solver;

public class SymSolver extends Solver<SymSolver> {
public class SymSolver extends Solver {

private long start, end;
private long solutions90, solutions180;
Expand Down

0 comments on commit 9eccca9

Please sign in to comment.