I am trying to solve the N Queen problem using multiple threads. However, the single threaded version of it runs either faster or roughly the same as the multithreaded one.
In essence, I use a queue which all the threads share. They pop states from the queue and expand them and add then them to the queue. I have tried playing around with the number of threads but to no avail, the more threads I add after around 8 the performance degenerates. The algorithm is correct in that the output is the same in both versions.
Any ideas?
Here's the code:
public class Queens {
//Thread
static class Runner implements Runnable {
private BlockingQueue<Configuration> queue;
private final AtomicInteger total;
public Runner(BlockingQueue<Configuration> q, AtomicInteger total) {
this.queue = q;
this.total = total;
}
public void run() {
while(!queue.isEmpty()) {
Configuration currentConfiguration = null;
try {
currentConfiguration = queue.take();
}
catch(InterruptedException e) {
}
if(currentConfiguration.done()) {
//currentConfiguration.printConfiguration();
total.incrementAndGet();
System.out.println("Solution");
continue;
}
for(int i = 0; i < currentConfiguration.getSize(); i++) {
if(safe(currentConfiguration, i, currentConfiguration.getColumn())) {
Configuration childConfig = new Configuration(currentConfiguration.getColumn() + 1,
currentConfiguration.getBoard());
childConfig.place(i, currentConfiguration.getColumn());
queue.add(childConfig);
}
}
}
}
//Returns true if we can place a queen on that row and column.
private boolean safe(Configuration current, int row, int col) {
for (int i = 0; i < col; i++)
if (current.getBoard()[row][i] == 1)
return false;
for (int i = row, j = col; i >= 0 && j >= 0; i--, j--)
if (current.getBoard()[i][j] == 1)
return false;
for (int i = row, j = col; j >= 0 && i < current.getSize(); i++, j--)
if (current.getBoard()[i][j] == 1)
return false;
return true;
}
}
//Board configuration class.
static class Configuration {
private int column;
private int[][] board;
private int size;
public Configuration(int column, int[][] b) {
this.column = column;
this.board = new int[b.length][b.length];
this.size = b.length;
for(int i = 0; i < size; i++) {
for(int j = 0; j < size; j++) {
board[i][j] = b[i][j];
}
}
}
public int getSize() {
return size;
}
public int getColumn() {
return column;
}
public int[][] getBoard() {
return board;
}
public boolean done() {
if(column == size)
return true;
return false;
}
public void place(int row, int column) {
board[row][column] = 1;
}
//Method prints the current configuration.
public synchronized void printConfiguration() {
synchronized(Configuration.class) {
System.out.println(Thread.currentThread().getName());
for(int i = 0; i < size; i++) {
for(int j = 0; j < size; j++) {
System.out.print(board[i][j] + " ");
}
System.out.println();
}
}
}
}
public static void main(String[] args) throws InterruptedException {
Configuration x = new Configuration(0, new int[13][13]);
int threads = 10;
AtomicInteger totalSolutions = new AtomicInteger(0);
List<Thread> mythreads = new ArrayList<Thread>();
BlockingQueue<Configuration> q = new LinkedBlockingDeque<>();
//Initially the board is empty
q.put(x);
long startTime = System.currentTimeMillis();
//Run 10 threads
for(int i = 0; i < threads; i++) {
Thread newthread = new Thread(new Runner(q, totalSolutions));
newthread.start();
mythreads.add(newthread);
}
for(Thread t : mythreads) {
try {
t.join();
}
catch(Exception e) {};
}
System.out.println(totalSolutions.get());
long endTime = System.currentTimeMillis();
System.out.println("Time: " + (endTime - startTime));
}
}
This was too long for a comment so I have to write it as an answer, apology on that.
In run method I've added the following like:
System.out.println(Thread.currentThread().getName() + " taking " + currentConfiguration.toString() + " out of " + queue.size() + " elem");
When running a single thread program it looks like this:
Thread-0 taking jobs.DeleteMe$Configuration#279b9032 out of 925326 elem
Thread-0 taking jobs.DeleteMe$Configuration#15ced747 out of 925327 elem
Thread-0 taking jobs.DeleteMe$Configuration#42689f59 out of 925328 elem
Thread-0 taking jobs.DeleteMe$Configuration#29aeeda2 out of 925329 elem
When running 10 threads the log looks like:
Thread-6 taking jobs.DeleteMe$Configuration#2775c7e7 out of 39393 elem
Thread-7 taking jobs.DeleteMe$Configuration#4e0ae08b out of 39308 elem
Thread-6 taking jobs.DeleteMe$Configuration#5eb0ba9 out of 39404 elem
Thread-9 taking jobs.DeleteMe$Configuration#12321211 out of 39401 elem
Thread-0 taking jobs.DeleteMe$Configuration#13a07923 out of 39383 elem
Thread-9 taking jobs.DeleteMe$Configuration#442cf86a out of 39415 elem
Thread-0 taking jobs.DeleteMe$Configuration#49366e2a out of 39420 elem
Thread-8 taking jobs.DeleteMe$Configuration#1c4bcfa5 out of 39378 elem
So it seems there is nothing preventing multiple threads to work.
Since your code uses one resource intensively, which is memory.
So I guess the reason is that memory cache is used more efficiently when there is a single thread running instead of multiple threads. It means that single thread access usually Configuration which is already in CPU cache, while when running multithreaded there are more misses.
See:
Is multi-thread memory access faster than single threaded memory access?
On the sidenote, it would probably be efficient to take a configuration which was the most recently added, BlockingQueue takes the first configuration, it would probably be more efficient to use LinkedBlockingDeque.
So I tried with LinkedBlockingDeque, with 10 threads, it runs for
Time: 3753
with 1 thread:
Time: 3352
(it's 3x speedup for me than the version with LinkedBlockingQueue).
Source:
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.BlockingDeque;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.atomic.AtomicInteger;
/**
*
* #author mladen
*/
public class DeleteMe {
//Thread
static class Runner implements Runnable {
private LinkedBlockingDeque<Configuration> queue;
private final AtomicInteger total;
public Runner(LinkedBlockingDeque<Configuration> q, AtomicInteger total) {
this.queue = q;
this.total = total;
}
public void run() {
while (!queue.isEmpty()) {
Configuration currentConfiguration = null;
//try {
currentConfiguration = queue.removeLast();
//System.out.println(Thread.currentThread().getName() + " taking " + currentConfiguration.toString() + " out of " + queue.size() + " elem");
// } catch (InterruptedException e) {
//
// }
if (currentConfiguration.done()) {
//currentConfiguration.printConfiguration();
total.incrementAndGet();
System.out.println("Solution");
continue;
}
for (int i = 0; i < currentConfiguration.getSize(); i++) {
if (safe(currentConfiguration, i, currentConfiguration.getColumn())) {
Configuration childConfig = new Configuration(currentConfiguration.getColumn() + 1,
currentConfiguration.getBoard());
childConfig.place(i, currentConfiguration.getColumn());
queue.add(childConfig);
}
}
}
}
//Returns true if we can place a queen on that row and column.
private boolean safe(Configuration current, int row, int col) {
for (int i = 0; i < col; i++) {
if (current.getBoard()[row][i] == 1) {
return false;
}
}
for (int i = row, j = col; i >= 0 && j >= 0; i--, j--) {
if (current.getBoard()[i][j] == 1) {
return false;
}
}
for (int i = row, j = col; j >= 0 && i < current.getSize(); i++, j--) {
if (current.getBoard()[i][j] == 1) {
return false;
}
}
return true;
}
}
//Board configuration class.
static class Configuration {
private int column;
private int[][] board;
private int size;
public Configuration(int column, int[][] b) {
this.column = column;
this.board = new int[b.length][b.length];
this.size = b.length;
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
board[i][j] = b[i][j];
}
}
}
public int getSize() {
return size;
}
public int getColumn() {
return column;
}
public int[][] getBoard() {
return board;
}
public boolean done() {
if (column == size) {
return true;
}
return false;
}
public void place(int row, int column) {
board[row][column] = 1;
}
//Method prints the current configuration.
public synchronized void printConfiguration() {
synchronized (Configuration.class) {
System.out.println(Thread.currentThread().getName());
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
System.out.print(board[i][j] + " ");
}
System.out.println();
}
}
}
}
public static void main(String[] args) throws InterruptedException {
Configuration x = new Configuration(0, new int[13][13]);
int threads = 1;
AtomicInteger totalSolutions = new AtomicInteger(0);
List<Thread> mythreads = new ArrayList<Thread>();
LinkedBlockingDeque<Configuration> q = new LinkedBlockingDeque<>();
//Initially the board is empty
q.put(x);
long startTime = System.currentTimeMillis();
//Run 10 threads
for (int i = 0; i < threads; i++) {
Thread newthread = new Thread(new Runner(q, totalSolutions));
newthread.start();
mythreads.add(newthread);
}
for (Thread t : mythreads) {
try {
t.join();
} catch (Exception e) {
};
}
System.out.println(totalSolutions.get());
long endTime = System.currentTimeMillis();
System.out.println("Time: " + (endTime - startTime));
}
}
The synchronization overhead is massive here. Try doing more work without fetching from the queue all the time.
Also, between the isEmpty call and the take call the queue can become empty. Avoid this race condition by using poll and checking for null result.
The memory overhead can be mitigated by going depth-first instead of breadth-first.
Code follows:
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
public class Queens {
//Thread
static class Runner implements Runnable {
private BlockingQueue<Configuration> queue;
private final AtomicInteger total;
private boolean local;
public Runner(BlockingQueue<Configuration> q, AtomicInteger total) {
this.queue = q;
this.total = total;
}
public void run() {
while(true) {
Configuration currentConfiguration = null;
try {
currentConfiguration = queue.poll(50, TimeUnit.MILLISECONDS);
}
catch(InterruptedException e) {
}
if(!local && queue.size() > 1000) local = true;
if(currentConfiguration == null){
break;
}
recurse(currentConfiguration);
}
System.out.println("DONE");
}
public void recurse(Configuration c){
if(c.done()){
total.incrementAndGet();
return;
}
for(int i = 0; i < c.getSize(); i++) {
if(safe(c, i, c.getColumn())) {
c.place(i, c.getColumn());
c.setColumn(c.getColumn() + 1);
if(local){
recurse(c);
}else{
queue.add(c.clone());
}
c.setColumn(c.getColumn() - 1);
c.clear(i, c.getColumn());
}
}
}
//Returns true if we can place a queen on that row and column.
private boolean safe(Configuration current, int row, int col) {
for (int i = 0; i < col; i++)
if (current.getBoard()[row][i] == 1)
return false;
for (int i = row, j = col; i >= 0 && j >= 0; i--, j--)
if (current.getBoard()[i][j] == 1)
return false;
for (int i = row, j = col; j >= 0 && i < current.getSize(); i++, j--)
if (current.getBoard()[i][j] == 1)
return false;
return true;
}
}
//Board configuration class.
static class Configuration {
private int column;
private int[][] board;
private int size;
public Configuration(int column, int[][] b) {
this.column = column;
this.board = new int[b.length][b.length];
this.size = b.length;
for(int i = 0; i < size; i++) {
for(int j = 0; j < size; j++) {
board[i][j] = b[i][j];
}
}
}
public Configuration clone(){
return new Configuration(column, board);
}
public int getSize() {
return size;
}
public int getColumn() {
return column;
}
public void setColumn( int v) {
column = v;
}
public int[][] getBoard() {
return board;
}
public boolean done() {
if(column == size)
return true;
return false;
}
public void place(int row, int column) {
board[row][column] = 1;
}
public void clear(int row, int column){
board[row][column] = 0;
}
//Method prints the current configuration.
public synchronized void printConfiguration() {
synchronized(Configuration.class) {
System.out.println(Thread.currentThread().getName());
for(int i = 0; i < size; i++) {
for(int j = 0; j < size; j++) {
System.out.print(board[i][j] + " ");
}
System.out.println();
}
}
}
}
public static void main(String[] args) throws InterruptedException {
final int size = 14;
Configuration x = new Configuration(0, new int[size][size]);
int threads = 8;
AtomicInteger totalSolutions = new AtomicInteger(0);
List<Thread> mythreads = new ArrayList<Thread>();
BlockingQueue<Configuration> q = new LinkedBlockingDeque<>();
//Initially the board is empty
q.put(x);
long startTime = System.currentTimeMillis();
//Run 10 threads
for(int i = 0; i < threads; i++) {
Thread newthread = new Thread(new Runner(q, totalSolutions));
newthread.start();
mythreads.add(newthread);
}
for(Thread t : mythreads) {
try {
t.join();
}
catch(Exception e) {};
}
System.out.println(totalSolutions.get());
long endTime = System.currentTimeMillis();
System.out.println("Time: " + (endTime - startTime));
}
}
Related
How can I make the second iteration use the first array "poqet" to switch their positions from true to false, but without changing their state when the first iteration made them all true?
public class Dhoma {
public static void main(String[] args) {
boolean poqet[] = new boolean[100];
int njerezit[] = new int[100];
int count = 0;
int nrRendorP = 0;
int nrRendorN = 0;
for (int i = 0; i < njerezit.length; i++) {
nrRendorN++;
for (int k = 0; k < poqet.length; k++) {
nrRendorP++;
if (nrRendorP == 100) {
nrRendorP = 0;
}
poqet[i] = Switch(nrRendorN, nrRendorP);
System.out.println(k + " " + poqet[i]);
}
}
// System.out.println("Jane te ndezura "+ count);
}
private static boolean Switch(int nr, int n) {
if (n % nr == 0) {
return true;
}
return false;
}
}
I have a 2D array that represents Game of Life board. N threads work on their own part of the array, creating the next generation.
When all N locks are done with their part, I print the current generation and sleep some time before going to the next generation. It is achieved by using CyclicBarrier.
Although the program works, I think the printing thread might see stale array cells because writes to the array are not synchronized. Internally CyclicBarrier uses lock, so it might trigger happens-before, but I'm not sure about it.
The only solution I see is to lock on Board methods. But I don't want to use locks because each thread has its own dedicated part of the array and it would create unnecessary contention on the lock.
public class GameOfLife {
private final Worker[] workers;
private final long duration;
private final AtomicBoolean done;
private Board current;
public GameOfLife(Board initialBoard, long duration) throws InterruptedException {
initialBoard.print();
this.current = new Board(initialBoard);
this.duration = duration;
this.done = new AtomicBoolean(false);
int cores = Runtime.getRuntime().availableProcessors();
this.workers = new Worker[cores];
CyclicBarrier barrier = new CyclicBarrier(cores, () -> {
current.print();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
GameOfLife.this.done.set(true);
return;
}
Board oldBoard = current;
current = new Board(current);
for (Worker worker : this.workers) {
worker.setOldBoard(oldBoard);
worker.setNewBoard(current);
}
});
int partitionSize = (initialBoard.getRows() / cores) + 1;
for (int core = 0; core < cores; core++) {
workers[core] = new Worker(barrier, initialBoard, current, done, core * partitionSize, Math.min(initialBoard.getRows(), (core + 1) * partitionSize));
}
}
public void start() {
for (Worker worker : this.workers) {
new Thread(worker).start();
}
new Timer(true).schedule(new TimerTask() {
#Override
public void run() {
GameOfLife.this.done.set(true);
}
}, this.duration);
}
public static void main(String[] args) throws InterruptedException {
boolean[][] initialBoard = new boolean[27][27];
for (int row = 10; row < 20; row++) {
initialBoard[row][15] = true;
}
GameOfLife e = new GameOfLife(new Board(initialBoard), 40000);
e.start();
}
}
class Worker implements Runnable {
private final CyclicBarrier barrier;
private final AtomicBoolean done;
private volatile Board oldBoard;
private volatile Board newBoard;
private final int rowStart;
private final int rowEnd;
public Worker(CyclicBarrier barrier, Board oldBoard, Board newBoard, AtomicBoolean done, int rowStart, int rowEnd) {
this.oldBoard = oldBoard;
this.newBoard = newBoard;
this.done = done;
this.rowStart = rowStart;
this.rowEnd = rowEnd;
this.barrier = barrier;
}
#Override
public void run() {
while (!done.get()) {
for (int row = rowStart; row < rowEnd; row++) {
for (int col = 0; col < this.oldBoard.getCols(); col++) {
int neighbors = this.oldBoard.countNeighbors(row, col);
if (this.oldBoard.isAlive(row, col)) {
if (neighbors < 2 || neighbors > 3) {
this.newBoard.kill(row, col);
}
} else {
if (neighbors == 3) {
this.newBoard.create(row, col);
}
}
}
}
try {
barrier.await();
} catch (Exception e) {
System.out.println(e);
return;
}
}
}
public void setOldBoard(Board oldBoard) {
this.oldBoard = oldBoard;
}
public void setNewBoard(Board newBoard) {
this.newBoard = newBoard;
}
}
class Board {
private final boolean[][] board;
Board(Board another) {
this(another.board);
}
Board(boolean[][] aBoard) {
this.board = new boolean[aBoard.length][aBoard[0].length];
for (int row = 0; row < aBoard.length; row++) {
this.board[row] = Arrays.copyOf(aBoard[row], aBoard[row].length);
}
}
public int countNeighbors(int row, int col) {
int counter = 0;
int[][] possibleNeighbors = {{row - 1, col - 1}, {row, col - 1}, {row + 1, col - 1}, {row - 1, col},
{row + 1, col}, {row - 1, col + 1}, {row, col + 1}, {row + 1, col + 1}};
for (int[] possibleNeighbor : possibleNeighbors) {
final int r = possibleNeighbor[0];
final int c = possibleNeighbor[1];
if (insideBoard(r, c) && this.board[r][c]) {
counter++;
}
}
return counter;
}
private boolean insideBoard(int row, int col) {
return row >= 0 && row < this.board.length && col >= 0 && col < this.board[row].length;
}
public int getRows() {
return this.board.length;
}
public int getCols() {
return this.board[0].length;
}
public boolean isAlive(int row, int col) {
return this.board[row][col];
}
public void kill(int row, int col) {
this.board[row][col] = false;
}
public void create(int row, int col) {
this.board[row][col] = true;
}
public void print() {
for (int row = 0; row < this.board.length; row++) {
for (int col = 0; col < this.board[row].length; col++) {
System.out.print(this.board[row][col] ? "*" : " ");
}
System.out.println();
}
}
}
So I got this assignment where I had to split an array into two, split those split arrays in 2, etc... up to a certain threshold.
So if my threshold was lets say 1000 it would be like:
10k>2x 5k>4x 2500>8x 1250>16x 625 (numbers in array).
Then I'd have to sort those arrays and merge them:
16x 625 (merged)>8x 1250 (merged)>4x 2500 (merged)>2x 5000 (merged)>1x 10k.
All of them must remain sorted.
So I think I got pretty far but it seems like it does not work the way I want it to. I tried multiple things to figure what is going wrong but I haven#t figured it out which is why I am here.
Can someone help me understand what I am doing wrong and give me a solution?
Bubblesort.java:
package PartThree;
import java.util.ArrayList;
import java.util.List;
public class Bubblesort implements Runnable {
public List<Integer> arrayList;
private int threshold;
private int middle;
public Bubblesort(List<Integer> arrayList, int threshold) {
this.arrayList = arrayList;
this.threshold = threshold;
this.middle = arrayList.size() / 2;
System.out.println(arrayList.size() + " ha");
}
#Override
public void run() {
if (arrayList.size() <= treshold) {
sort();
}else if(threshold<arrayList.size()){
Bubblesort rLeft = new Bubblesort(arrayList.subList(0, middle), threshold);
Bubblesort rRight = new Bubblesort(arrayList.subList(middle, arrayList.size()), threshold);
Thread tLeft = new Thread(rLeft);
Thread tRight = new Thread((rRight));
tRight.start();
tLeft.start();
try {
tLeft.join();
tRight.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
merge(rLeft.arrayList, rRight.arrayList);
System.out.println(arrayList.size() + ":size");
}
}
private void merge(List<Integer> left, List<Integer> right) {
int i = 0, j = 0, k = 0;
List<Integer> temp = new ArrayList<>();
while (i < left.size() && j < right.size()) {
if (left.get(i) < right.get(j)) {
temp.add(k, left.get(i));
i++;
} else {
temp.add(k, right.get(j));
j++;
}
k++;
}
while (i < left.size()) {
temp.add(k, left.get(i));
i++;
k++;
}
while (j < right.size()) {
temp.add(k, right.get(j));
j++;
k++;
}
arrayList = temp;
temp.clear();
}
private void sort() {
int i, j, tijdelijk;
for (j = 0; j < arrayList.size(); j++) {
for (i = 1; i < arrayList.size() - j; i++) {
if (arrayList.get(i - 1) > arrayList.get(i)) {
tijdelijk = arrayList.get(i);
arrayList.set(i, arrayList.get(i - 1));
arrayList.set(i - 1, tijdelijk);
}
}
}
}
}
Implementation:
package PartThree;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class API {
private Random random = new Random();
private List<Integer> array_unsorted_main = new ArrayList<>();
private int maxSize;
private Thread t1;
private void run(){
this.maxSize = 10000;
for (int i = 0; i < maxSize; i++) {
array_unsorted_main.add(random.nextInt(10000));
}
t1 = new Thread(new Bubblesort(array_unsorted_main,1000));
t1.start();
try {
t1.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String args[]){
new PartThree.API().run();
}
}
Please help me out, thank you for your time.
One of your problems is in your merge method you do arrayList = temp; and then do temp.clear() thereby clearing arrayList since it now points to temp.
Remove the temp.clear() statement so arrayList will retain the sorted values.
I'm not sure what this error is or why it is happening. verything I've found online has nothing to do with TableViews. But when this method in my prisoner Class is accessed by my TableView it throws a InvocationTargetException. This is my first time using a TableView.
public int getCellBlock() {
for (int i = 0; i < Main.getCellBlocks().size(); i++) //for each cellblock
for (int j = 0; j < Main.getCellBlocks().get(i).getCells().size(); j++) //for each cell
for (int k = 0; k < Main.getCellBlocks().get(i).getCells().get(j).getInmates().size(); k++)
if (Main.getCellBlocks().get(i).getCells().get(j).getInmates().get(k).equals(this.idNum)) {
return i;
}
return -1;
}
Cell (has two subclasses but im not accessing data in them with the above method):
import java.io.Serializable;
import java.util.ArrayList;
public class Cell implements Serializable {
private ArrayList<Integer> inmateIdNums;
private int capacity = 0;
Cell(int cap){
capacity = cap;
inmateIdNums = new ArrayList<>();
for (int i = 0; i < capacity; i++)
inmateIdNums.add(null);
}
public void add (int idNum){
for (int i = 0; i < capacity; i++){
if (inmateIdNums.get(i) == null) {
inmateIdNums.set(i, idNum);
break;
}
}
}
public void add (int idNum, int dur){}
public void add (int idNum, String reason){}
public ArrayList<Integer> getInmates(){ return inmateIdNums; }
public int getEmptyBunks(){
int emptyBunks = 0;
for (int i = 0; i < inmateIdNums.size(); i++){
if (inmateIdNums.get(i) == null)
emptyBunks++;
}
return emptyBunks;
}
}
CellBlock:
import java.io.Serializable;
import java.util.ArrayList;
public class CellBlock implements Serializable{
private String name;
private String type;
private int capacity;
private int occupancy = 0;
private ArrayList<Cell> cells;
CellBlock(int cap, String nName, String nType, int cellCapacity){
name = nName;
type = nType;
capacity = cap;
cells = new ArrayList<>(capacity);
if (type == "Maximum Security" || type == "Minimum Security") {
for (int i = 0; i < capacity; i++)
cells.add(new Cell(cellCapacity));
}
else if(type == "Infirmary"){
for (int i = 0; i < capacity; i++)
cells.add(new InfirmaryCell(cellCapacity));
}
else if(type == "Isolation"){
for (int i = 0; i < capacity; i++)
cells.add(new IsolationCell(cellCapacity));
}
}
public void addInmate(int cell, int inmateIdNum){
cells.get(cell-1).add(inmateIdNum);
occupancy++;
}
public void addInmate(int cell, int inmateIdNum, String reason){
cells.get(cell-1).add(inmateIdNum, reason);
occupancy++;
}
public void addInmate(int cell, int inmateIdNum, int duration){
cells.get(cell-1).add(inmateIdNum, duration);
occupancy++;
}
public void removeInmate(int inmateIdNum){
//search for inmate and remove from list
}
public ArrayList<Cell> getInmates(){ return cells; }
public boolean checkCapacity(){
if (capacity > occupancy)
return true;
return false;
}
public ArrayList<Cell> getCells(){ return cells; }
public ArrayList<String> getOpenCells(){
ArrayList<String> openCells = new ArrayList<>();
for (int i = 0; i < cells.size();i++){
if (cells.get(i).getEmptyBunks() > 0)
openCells.add(Integer.toString(i+1));
}
return openCells;
}
}
The Error:
I'm not sure which did it, but I fixed this myself. The loops were fine.
The problem was one of two things - the comparison, or the files where I had written the information (I am using binary files and ObjectInputStream/ObjectOutputStream).
In the Cell constructor I had:
for (int i = 0; i < capacity; i++)
inmateIdNums.add(null);
And to avoid comparing Integer to null I changed it to:
for (int i = 0; i < capacity; i++)
inmateIdNums.add(0);
This did not fix my issue. So I could only assume that someone where along the way something went wrong with one of my files being written while this crappy comparison was going on. As a last ditch effort I deleted the files I had been working with and ran my program fresh to create new files and add new entries.
Problem solved.
The purpose of the below code snippet is to create an instance of a matrix and then calculate the determinant of an nxn matrix. However, method computeDet won't return because the following error occurs: value cannot be resolved to a variable. Why is that?
** determinant code edited from here (this code does work - no error)
public class MatrixArrayCR {
long[][] matrix;
public MatrixArrayCR(long[] arr) {
double len = Math.sqrt(arr.length);
int counter = 0;
for (int i=0; i==len; i++) {
for (int j=0; j==len; j++) {
matrix[i][j] = arr[counter];
counter++;
}
}
}
// determinant method edited from code off http://www.coderanch.com/t/446179/java/java/Learning-Project
public long determinant() {
return computeDet(matrix);
}
public long computeDet(long[][] matrix) {
int matrixSize = matrix.length;
if (matrixSize==2) {
return matrix[0][0]*matrix[1][1]-matrix[0][1]*matrix[1][0];
} else {
long value = 0;
for (int i=0; i<matrixSize; i++) {
long[][] minor=generateMinor(matrix,0,i);
value += (sgn(i)*matrix[0][i]*computeDet(minor));
}
} return value; //ERROR HERE
}
private int sgn(int n) {
if (n%2==0) {
return 1;
} else {
return -1;
}
}
private long[][] generateMinor(long[][] matrix, int row, int column) {
int matrixSize = matrix.length;
int minorSize = matrixSize -1;
int counterOne = 0;
int counterTwo = 0;
long[][] minor = new long[minorSize][minorSize];
for (int i=0; i<matrixSize; i++) {
if (i==row) {
continue;
} for (int j=0; j<matrixSize; j++) {
if (j==column) {
continue;
} minor[counterOne][counterTwo] = matrix[i][j];
++ counterTwo;
} ++counterOne;
counterTwo = 0;
} return minor;
}
}
value is a local variable, i.e it's only visible in the block it has been declared. Since you declared value in the else block and try to return it outside this block, you get this error.
The return statement should be in the else block. I.e :
public long computeDet(long[][] matrix) {
int matrixSize = matrix.length;
if (matrixSize==2) {
return matrix[0][0]*matrix[1][1]-matrix[0][1]*matrix[1][0];
} else {
long value = 0;
for (int i=0; i<matrixSize; i++) {
long[][] minor=generateMinor(matrix,0,i);
value += (sgn(i)*matrix[0][i]*computeDet(minor));
}
return value;
}
}
The value variable is declared inside of an if or else block and is only visible within the block it was declared. If you want it visible at the end of the method, declare it at the start of the method, before the if/else blocks.
public long computeDet(long[][] matrix) {
long value = 0L;
int matrixSize = matrix.length;
if (matrixSize==2) {
value = matrix[0][0]*matrix[1][1]-matrix[0][1]*matrix[1][0];
} else {
for (int i=0; i<matrixSize; i++) {
long[][] minor=generateMinor(matrix,0,i);
value += (sgn(i)*matrix[0][i]*computeDet(minor));
}
}
return value;
}
Either that or return it from inside of the else block:
public long computeDet(long[][] matrix) {
int matrixSize = matrix.length;
if (matrixSize==2) {
return matrix[0][0]*matrix[1][1]-matrix[0][1]*matrix[1][0];
} else {
long value = 0;
for (int i=0; i<matrixSize; i++) {
long[][] minor=generateMinor(matrix,0,i);
value += (sgn(i)*matrix[0][i]*computeDet(minor));
}
return value; //ERROR HERE
} // this guy moved
}