use sectors
This commit is contained in:
parent
344aa4af18
commit
e2acf6899e
|
@ -20,6 +20,7 @@ import javax.swing.JScrollPane;
|
||||||
|
|
||||||
import java.util.concurrent.*;
|
import java.util.concurrent.*;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
final public class Solver extends JPanel {
|
final public class Solver extends JPanel {
|
||||||
|
|
||||||
|
@ -37,6 +38,10 @@ final public class Solver extends JPanel {
|
||||||
// For each cell in the labyrinth: Has solve() visited it yet?
|
// For each cell in the labyrinth: Has solve() visited it yet?
|
||||||
private boolean[][] visited; // initialized in solve()
|
private boolean[][] visited; // initialized in solve()
|
||||||
private AtomicBoolean[][] visitedAtomic;
|
private AtomicBoolean[][] visitedAtomic;
|
||||||
|
private AtomicInteger numTasks = new AtomicInteger(0);
|
||||||
|
|
||||||
|
private Semaphore[] sectors;
|
||||||
|
private static final int SECTOR_SIZE = (int) Math.sqrt(DEFAULT_WIDTH_IN_CELLS * DEFAULT_HEIGHT_IN_CELLS) / 50;
|
||||||
|
|
||||||
// determined by trial and error
|
// determined by trial and error
|
||||||
private static final int DISTANCE_PER_TASK = DEFAULT_WIDTH_IN_CELLS * DEFAULT_HEIGHT_IN_CELLS / 128;
|
private static final int DISTANCE_PER_TASK = DEFAULT_WIDTH_IN_CELLS * DEFAULT_HEIGHT_IN_CELLS / 128;
|
||||||
|
@ -123,15 +128,32 @@ final public class Solver extends JPanel {
|
||||||
return pathSoFar.toArray(new Point[0]);
|
return pathSoFar.toArray(new Point[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int getSectorsX() {
|
||||||
|
return (int)Math.ceil((double)labyrinth.getWidth() / SECTOR_SIZE);
|
||||||
|
}
|
||||||
|
private int getSectorsY() {
|
||||||
|
return (int)Math.ceil((double)labyrinth.getHeight() / SECTOR_SIZE);
|
||||||
|
}
|
||||||
|
private int getSectorId(Point p) {
|
||||||
|
return (p.getX() / SECTOR_SIZE) + (p.getY() / SECTOR_SIZE) * getSectorsX();
|
||||||
|
}
|
||||||
|
|
||||||
public Point[] solveConcurrently() {
|
public Point[] solveConcurrently() {
|
||||||
// dummy origin direction for start
|
// dummy origin direction for start
|
||||||
PointAndDirection start = new PointAndDirection(labyrinth.getStart(), null);
|
PointAndDirection start = new PointAndDirection(labyrinth.getStart(), null);
|
||||||
|
|
||||||
visitedAtomic = new AtomicBoolean[labyrinth.getWidth()][labyrinth.getHeight()];
|
// visitedAtomic = new AtomicBoolean[labyrinth.getWidth()][labyrinth.getHeight()];
|
||||||
for (int i = 0; i < visitedAtomic.length; i++) {
|
// for (int i = 0; i < visitedAtomic.length; i++) {
|
||||||
for (int j = 0; j < visitedAtomic[i].length; j++) {
|
// for (int j = 0; j < visitedAtomic[i].length; j++) {
|
||||||
visitedAtomic[i][j] = new AtomicBoolean(false);
|
// visitedAtomic[i][j] = new AtomicBoolean(false);
|
||||||
}
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
visited = new boolean[labyrinth.getWidth()][labyrinth.getHeight()];
|
||||||
|
|
||||||
|
sectors = new Semaphore[getSectorsX() * getSectorsY()];
|
||||||
|
for (int i = 0; i < sectors.length; i++) {
|
||||||
|
sectors[i] = new Semaphore(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
ForkJoinPool pool = ForkJoinPool.commonPool();
|
ForkJoinPool pool = ForkJoinPool.commonPool();
|
||||||
|
@ -140,6 +162,9 @@ final public class Solver extends JPanel {
|
||||||
ConcurrentSolverTask t = new ConcurrentSolverTask(start, pathSoFar, pool);
|
ConcurrentSolverTask t = new ConcurrentSolverTask(start, pathSoFar, pool);
|
||||||
Point[] result = pool.invoke(t);
|
Point[] result = pool.invoke(t);
|
||||||
|
|
||||||
|
System.out.println("Used tasks: " + numTasks.get());
|
||||||
|
System.out.println("Task to Solution Length Ratio: " + (double)result.length / numTasks.get());
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -149,6 +174,7 @@ final public class Solver extends JPanel {
|
||||||
private ArrayDeque<Point> pathSoFar;
|
private ArrayDeque<Point> pathSoFar;
|
||||||
private ForkJoinPool pool;
|
private ForkJoinPool pool;
|
||||||
private ArrayList<ConcurrentSolverTask> subtasks;
|
private ArrayList<ConcurrentSolverTask> subtasks;
|
||||||
|
private int currentSector;
|
||||||
public ConcurrentSolverTask(PointAndDirection start, ArrayDeque<Point> pathSoFar, ForkJoinPool pool) {
|
public ConcurrentSolverTask(PointAndDirection start, ArrayDeque<Point> pathSoFar, ForkJoinPool pool) {
|
||||||
this.start = start;
|
this.start = start;
|
||||||
this.pathSoFar = pathSoFar;
|
this.pathSoFar = pathSoFar;
|
||||||
|
@ -156,9 +182,33 @@ final public class Solver extends JPanel {
|
||||||
|
|
||||||
this.backtrackStack = new ArrayDeque<>();
|
this.backtrackStack = new ArrayDeque<>();
|
||||||
this.subtasks = new ArrayList<>();
|
this.subtasks = new ArrayList<>();
|
||||||
|
this.currentSector = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void acquireSector(Point p) {
|
||||||
|
if (getSectorId(p) == this.currentSector) return;
|
||||||
|
if (this.currentSector >= 0) {
|
||||||
|
// release previous sector
|
||||||
|
sectors[this.currentSector].release();
|
||||||
|
}
|
||||||
|
this.currentSector = getSectorId(p);
|
||||||
|
try {
|
||||||
|
// acquire new sector
|
||||||
|
sectors[this.currentSector].acquire();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
System.out.println(e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void releaseSector() {
|
||||||
|
if (this.currentSector >= 0) {
|
||||||
|
sectors[this.currentSector].release();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Point[] compute() {
|
public Point[] compute() {
|
||||||
|
numTasks.incrementAndGet();
|
||||||
int currentLength = 0;
|
int currentLength = 0;
|
||||||
Point current = this.start.getPoint();
|
Point current = this.start.getPoint();
|
||||||
|
|
||||||
|
@ -197,11 +247,19 @@ final public class Solver extends JPanel {
|
||||||
|
|
||||||
// check if that cell has been visited
|
// check if that cell has been visited
|
||||||
// set visitedAtomic to true if it has not been visited
|
// set visitedAtomic to true if it has not been visited
|
||||||
if (!visitedAtomic[neighbour.x][neighbour.y].compareAndSet(false, true)) {
|
// if (!visitedAtomic[neighbour.x][neighbour.y].compareAndSet(false, true)) {
|
||||||
continue;
|
// continue;
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
acquireSector(neighbour);
|
||||||
|
if (visited[neighbour.x][neighbour.y]) continue;
|
||||||
|
visited[neighbour.x][neighbour.y] = true;
|
||||||
|
releaseSector();
|
||||||
|
|
||||||
|
|
||||||
// System.out.println("Found unvisited neighbour: " + neighbour);
|
// System.out.println("Found unvisited neighbour: " + neighbour);
|
||||||
if (currentLength >= DISTANCE_PER_TASK) {
|
if (currentLength >= DISTANCE_PER_TASK) {
|
||||||
|
releaseSector();
|
||||||
// if we have reached the distance limit, create a subtask
|
// if we have reached the distance limit, create a subtask
|
||||||
ArrayDeque<Point> subPath = this.pathSoFar.clone();
|
ArrayDeque<Point> subPath = this.pathSoFar.clone();
|
||||||
subPath.addLast(current);
|
subPath.addLast(current);
|
||||||
|
@ -210,8 +268,9 @@ final public class Solver extends JPanel {
|
||||||
subPath,
|
subPath,
|
||||||
this.pool
|
this.pool
|
||||||
);
|
);
|
||||||
subtask.fork();
|
|
||||||
subtasks.add(subtask);
|
subtasks.add(subtask);
|
||||||
|
|
||||||
|
subtask.fork();
|
||||||
} else {
|
} else {
|
||||||
if (next == null) {
|
if (next == null) {
|
||||||
// visit first unvisited neighbour next
|
// visit first unvisited neighbour next
|
||||||
|
@ -224,7 +283,6 @@ final public class Solver extends JPanel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// at least one unvisited neighbour found
|
// at least one unvisited neighbour found
|
||||||
if (next != null) {
|
if (next != null) {
|
||||||
pathSoFar.addLast(current);
|
pathSoFar.addLast(current);
|
||||||
|
@ -232,6 +290,7 @@ final public class Solver extends JPanel {
|
||||||
currentLength++;
|
currentLength++;
|
||||||
}
|
}
|
||||||
if (next == null) {
|
if (next == null) {
|
||||||
|
releaseSector();
|
||||||
// no unvisited neighbour found
|
// no unvisited neighbour found
|
||||||
// backtrack if possible
|
// backtrack if possible
|
||||||
if (this.backtrackStack.isEmpty()) {
|
if (this.backtrackStack.isEmpty()) {
|
||||||
|
|
Loading…
Reference in New Issue