How to transpose a matrix in java (parallel/multithreaded) - java

We all know how useful matrix transposition is, and writing a general algorithm for sequential use is no problem. However, I am having some trouble doing the same for multithreaded purposes, and have only gotten this small case for 4 x 4 to work properly.
My approach is to assign equal parts of a double[][] structure, in this case 2 x 2, to each out of four threads. In this case, that means starting positions of 0,0 & 0,2 & 2,0 & 2,2. This is passed in with "kol" and "rad".
However, I cannot get this to work on larger matrices, so any help would be appreciated. The closest answer to this problem I've found is here: How to to parallelize the matrix transpose?
This is also my inspiration for splitting the double[][] structure into four parts. My (working) 4 x 4 code can be found below, so how can I modify it to work for four threads?
Cheers!
public double[][] transponerMatrise(double[][] matrise, int rad, int
kol, int id)
{
if((id != 2))
{
for (int i = rad; i < n/2 + rad; i++)
{
for (int j = kol+1; j < n/2 + kol; j++)
{
System.out.println("Traad " + id + " bytter " + i + "," + j + " med " + j + "," + i);
System.out.println("Value is " + matrise[i][j] + ", " + matrise[j][i]);
element = matrise[i][j];
matrise[i][j] = matrise[j][i];
matrise[j][i] = element;
}
}
}
else
{
for (int i = rad; i < n/2 + rad-1; i++)
{
for (int j = kol; j < n/2 + kol; j++)
{
System.out.println("Traad " + id + " bytter " + i + "," + j + " med " + j + "," + i);
System.out.println("Value is " + matrise[i][j] + ", " + matrise[j][i]);
element = matrise[i][j];
matrise[i][j] = matrise[j][i];
matrise[j][i] = element;
}
}
}
return matrise;
}
PS: I know the code works properly, because I have a checking method against a working sequential variant.

This is an a priori lost fight against O(N^2) costs-function
If I may turn your attention to a smarter approach, having an almost O(1) ( constant ) cost, the trick would help you start working in a way more promising direction.
May try to add one thin abstraction layer above the high-performance tuned ( cache-lines friendly "raw"-storage of the matrix elements. This abstracted layer will help to access the "raw"-storage ( using indexing-axes, index-striding and slicing tricks - the very same way as HPC FORTRAN libraries have inspired the well-known numpy and it's striding tricks) and this way the .T-method will do nothing expensive ( alike bulldozing N^2 memory locations, swapping there and back ) but simply swap axes-parameters in the abstract layer, responsible for the indirection mapper, taking a few tens of nanoseconds for whatever large matrise[N,N]; where N = 10, 100, 1000, 10000, 100000, 1000000, 10000000+ still a few [ns].
There is nothing faster in doing this or other, more complex, matrix operations and both the FORTRAN and numpy, performance polished, methods are a proof per-se of such observation.

Maybe it could be an simple idea to use a thread to swap a row to col but therefore you need twice the memory for you matrix which could be a problem on huge matrices. also if you have a 6 Core CPU i think there is not much benefit from using 100 thread so my thread pool is very small. And as #user3666197 mentioned its a still a expensive solution - but paralell ;-)
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class MatrixTransposition {
public static void main(final String[] args) throws InterruptedException {
final MatrixTransposition transposition = new MatrixTransposition();
final int[][] source = transposition.create(32);
final int[][] transposed = transposition.solve(source);
System.out.println("Compare source and transpositon = " + transposition.compare(source, transposed));
final int[][] result = transposition.solve(transposed);
System.out.println("Compare source and double transpositon = " + transposition.compare(source, result));
transposition.print(source);
transposition.print(transposed);
}
public boolean compare(final int[][] a, final int[][] b) {
for (int r = 0; r < a.length; r++) {
for (int c = 0; c < a[0].length; c++) {
if (a[r][c] != b[r][c]) return false;
}
}
return true;
}
public int[][] create(final int size) {
final int[][] result = new int[size][size];
for (int r = 0; r < size; r++) {
for (int c = 0; c < size; c++) {
result[r][c] = r * size + c;
}
}
return result;
}
public void print(final int[][] input) {
final int size = input.length;
final int maxNr = size * size;
final int digits = new String(maxNr + "").length();
final String cellFormat = "%0" + digits + "d ";
for (int r = 0; r < input.length; r++) {
final int[] row = input[r];
for (final int c : row) {
System.out.print(String.format(cellFormat, c));
}
System.out.println("");
}
System.out.println("");
}
public int[][] solve(final int[][] input) throws InterruptedException {
final int width = input.length;
final int height = input[0].length;
final int[][] result = new int[width][height];
final CountDownLatch latch = new CountDownLatch(width);
for (int r = 0; r < width; r++) {
final int row = r;
threadPool.execute(() -> {
solvePart(result, input, row);
latch.countDown();
});
}
latch.await();
return result;
}
private void solvePart(final int[][] result, final int[][] input, final int r) {
System.out.println("Solve row " + String.format("%02d", r) + " in thread " + Thread.currentThread().getName());
final int[] row = input[r];
for (int c = 0; c < row.length; c++) {
result[c][r] = row[c];
}
}
private final ExecutorService threadPool = Executors.newFixedThreadPool(6);
}

based on the aproach of user3666197 you could do something like that:
public class Matrix {
private class Index {
Index(final int row, final int col) {
super();
this.row = row;
this.col = col;
}
int col;
int row;
}
public Matrix(final int rows, final int cols) {
this.rows = rows;
this.cols = cols;
data = new int[rows][cols];
}
public int get(final int row, final int col) {
return get(getIndex(row, col));
}
public void set(final int row, final int col, final int value) {
set(getIndex(row, col), value);
}
public void transpose() {
transpositioned = !transpositioned;
}
private int get(final Index index) {
return data[index.row][index.col];
}
private Index getIndex(final int row, final int col) {
return transpositioned ? new Index(col, row) : new Index(row, col);
}
private void set(final Index index, final int value) {
data[index.row][index.col] = value;
}
private final int cols;
private final int[][] data;
private final int rows;
private boolean transpositioned;
}

Related

Running multiple threads for row matrix multiplication

I have a program that takes a text file that has ints in it to look like a matrix. It has 2 of these here is an example.
1 1 1 1
1 1 1 1
1 1 1 1.
I have to use one single thread for each row dot matrix multiplication and then put it into the new matrix. The error I keep getting it that I get a repeat of the same thread number even though once its done the row matrix multiplication the thread should not be used again. The first part of the code is creating the new 2D array for the products of the row dot multiplication. The next set of code is the run() method doing the actual math. I do not know how to not get repeating threads to keep going. Any help is appreciated. enter code here
P = new int[x][z];
for(int i = 0; i < x; i++) {
for(int j = 0; j < z; j++) {
Thread t = new Thread(new MatrixThread(A,B,P,i,j,y));
t.setName( "[" + i + "] [" + j + "]");
t.start();
}
}
private static class MatrixThread implements Runnable {
private int[][] A,B,P;
private int row,col,y;
public MatrixThread(int[][] A, int[][] B, int[][] P, int i, int j,int y) {
this.A = A;
this.B = B;
this.P = P;
this.row = i;
this.col = j;
this.y = y;
}
public void run() {
System.out.println("Thread " + Thread.currentThread().getName() + " starts calculating");
for(int i = 0; i < y; i++) {
P[row][col] += A[row][i]* B[col][i];
}
System.out.println("Thread " + Thread.currentThread().getName() + " returns cell value " + P[row][col]);
}
}

Java 10 * 10 grid

First post here, thanks in advance for any help.
I have made a 10*10 grid in Java and am trying to get the row numbers to appear on the left side of the grid, after many attempts at different print formats and options I am now here for a little help. Any pointers will be greatly appreciated.
public class ArrayTest {
public final static int SIZE =10;
final static char[][] GRID = new char[SIZE][SIZE];
public static void main(String[] args){
setGrid();
printGrid();
}
public static void setGrid(){
for( int row = 0; row< SIZE;row++){
for(int column = 0; column<SIZE; column++){
GRID[row][column]= ' ';
}
}
}
public static void printGrid(){
System.out.println(" 10 x 10 Grid");
System.out.println(" 0 1 2 3 4 5 6 7 8 9");
System.out.println(" +---+---+---+---+---+---+---+---+---+---+");
for(int row = 0; row< SIZE; row++){
for(int column = 0; column<SIZE; column++){
System.out.print(" |" + GRID[row][column] + "");
}
System.out.println(" | " + row );
System.out.println(" +---+---+---+---+---+---+---+---+---+---+");
}
}
}
for(int row = 0; row< SIZE; row++){
System.out.print( " " + row + " | ");
for ( int column = 0; column<SIZE; column++){
... <print column values for this row here>
}
System.out.println("");
}
Don't forget to add extra spaces when you print out the column numbers at the top, to account for the space used up by the row number indicators.
Your algorithm is a good point to start. Anyway I would like to broaden your perspective on extended use-cases and the usage of existing (reliable and customizable) text-based tabular-formatting libraries.
Use this extended solution and optimize
It is based on your approach. I added following features:
customizable grid-size (width, height as parameters)
utility functions: padRight, padLeft, repeatChar
You can further optimize that, for example:
left or right alignment of headers/data
calculation of the maximum cell-space need (max length of grid-data)
Source (minimal Java 8 streaming used)
Find source below or online where you can test & download on Ideone.
import java.util.stream.Collectors;
import java.util.stream.IntStream;
class GridDataToTextTable {
public static final int WIDTH = 10;
public static final int HEIGHT = 10;
public static void main(String[] args) {
System.out.printf("%d x %d Grid%n", WIDTH, HEIGHT);
String[][] generateGrid = generateGrid(WIDTH, HEIGHT);
printGrid(WIDTH, HEIGHT, generateGrid);
}
public static String[][] generateGrid(int width, int height) {
String[][] gridData = new String[height][width];
for (int row = 0; row < height; row++) {
for (int column = 0; column < width; column++) {
gridData[row][column] = " ";
}
}
return gridData;
}
public static String padRight(String s, int n) {
return String.format("%-" + n + "s", s);
}
public static String padLeft(String s, int n) {
return String.format("%" + n + "s", s);
}
public static String repeatChar(char c, int n) {
return IntStream.range(0, n).mapToObj(i -> String.valueOf(c)).collect(Collectors.joining(""));
}
public static void printGrid(int width, int height, String[][] gridData) {
int lengthOfMaxRowNum = String.valueOf(height - 1).length();
// TODO: can be calculated as max length over Strings in gridData
int maxCellWidth = 4;
System.out.print(padRight(" ", lengthOfMaxRowNum));
for (int column = 0; column < width; column++) {
System.out.print(padLeft(String.valueOf(column), maxCellWidth + 1));
}
System.out.println();
printHorizontalLine(width, lengthOfMaxRowNum, maxCellWidth);
System.out.println();
for (int row = 0; row < height; row++) {
// TODO: alignment of headers (col-numbers) could be customizable
System.out.print(padLeft(String.valueOf(row), lengthOfMaxRowNum));
for (int column = 0; column < width; column++) {
// TODO: alignment of cell-data could be customizable
System.out.print("|" + padLeft(gridData[row][column], maxCellWidth));
}
System.out.println("|");
printHorizontalLine(width, lengthOfMaxRowNum, maxCellWidth);
System.out.println();
}
}
private static void printHorizontalLine(int width, int lengthOfMaxRowNum, int maxCellWidth) {
String line = repeatChar('-', maxCellWidth);
System.out.print(padLeft(" ", lengthOfMaxRowNum));
for (int column = 0; column < width; column++) {
System.out.printf("+" + line);
}
System.out.printf("+");
}
}
Use Text-Formatting libraries
To print out data text-based in tabular or grid format see this answer.
Maybe you can use one of following libraries:
Java Text Tables library from iNamik's GitHub project
WAGU data-in-table-view library from thedathoudarya's GitHub project

How to compare integer elements within ArrayList?

I am trying to solve a problem by fetching the maximum number from each row in a triangle. So far am able to generate a triangle but how do I fetch the max number from each row?
Here is my code
private static Integer solve(Triangle triangle)
{
//triangle is extending an ArrayList
System.out.println(triangle);
return 0;
}
This is what am producing so far:
6
3 5
9 7 1
4 6 8 4
but now I want to get the result which says:
"In this triangle the maximum total is: 6 + 5 + 9 + 8 = 26"
Here is the complete code:
public class HellTriangle {
private static final int TRIANGLE_HEIGHT = 10;
public static void start() {
Triangle triangle = generateTriangle();
//System.out.println(triangle);
long start = System.currentTimeMillis();
Integer result = solve(triangle);
long end = System.currentTimeMillis();
System.out.println("Result:" + result);
System.out.println("Resolution time: " + (end - start) + "ms");
}
private static Triangle generateTriangle() {
Triangle triangle = new Triangle();
Random random = new Random();
for (int i = 0; i < TRIANGLE_HEIGHT; i++) {
Row row = new Row();
for (int j = 0; j <= i; j++) {
row.add(random.nextInt(100));
}
triangle.add(row);
}
return triangle;
}
private static class Row extends ArrayList<Integer> {
public String toString() {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < size(); i++) {
sb.append(String.format("%02d", get(i)));
//rows.add(get(i));
if (i < (size() - 1)) {
sb.append(" ");
}
}
return sb.toString();
}
}
private static class Triangle extends ArrayList<Row> {
public String toString() {
// sb is used to make modification to the String
StringBuilder sb = new StringBuilder();
for (int i = 0; i < size(); i++) {
for (int j = 0; j < (TRIANGLE_HEIGHT - 1 - i); j++) {
sb.append(" ");
}
sb.append(get(i));
if (i < (size() - 1)) {
sb.append("\n");
}
}
return sb.toString();
}
}
private static Integer solve(Triangle triangle) {
System.out.println(triangle);
return 0;
}
public static void main(String[] args) {
start();
}
}
Any help would be appreciated!
Here, just change with your solve()
private static void solve(Triangle triangle) {
System.out.println(triangle);
ArrayList<Integer> result = new ArrayList<Integer>();
int total = 0;
for(Row row : triangle){
Collections.sort(row);
total += row.get(row.size()-1);
result.add(row.get(row.size()-1));
}
for(Integer intr : result)
System.out.println("Largest elements of the rows: " + intr);
System.out.println("Total: " + total);
}
As there is no ordering in your rows and this would lead to O(n) to get the maximum value per row i would look up the maximum value during insertion. Something like that (not tested and you probably have to override the other add methods also, depending on your use case):
public class Row extends ArrayList<Integer> {
public String toString() {
...
}
private Integer max = null;
#Override
public boolean add(Integer elem) {
if (elem != null && (max == null || max < elem)) {
max = elem;
}
return super.add(elem);
}
public Integer getMax() {
return max;
}
}
Try
private static int getTriangleMax(final Triangle rows)
{
int max = 0;
for (final Row row : rows)
{
final int rowMax = getRowMax(row);
max += rowMax;
}
return max;
}
private static int getRowMax(final Row row)
{
int rowMax = Integer.MIN_VALUE;
for (final Integer integer : row)
{
if (rowMax < integer)
{
rowMax = integer;
}
}
return rowMax;
}
Simple-Solution:
1.Add the static list as here:
private static List maxRowVal=new ArrayList();
2.Replace your generateTriangle() function with this:
private static Triangle generateTriangle()
{
Triangle triangle = new Triangle();
Random random = new Random();
for (int i = 0; i < TRIANGLE_HEIGHT; i++) {
Row row = new Row();
int maxTemp=0;
for (int j = 0; j <= i; j++) {
int rand=random.nextInt(100);
row.add(rand);
if(rand>maxTemp)
maxTemp=rand; //will get max value for the row
}
maxRowVal.add(maxTemp);
triangle.add(row);
}
return triangle;
}
Simple indeed!!
This is not exactly what you asked for, but I would like to show you a different way to go about this problem. People have done this for me before, and I really appreciated seeing different ways to solve a problems. Good luck with your coding!
Below is the code in its entirety, so you can just copy, paste and run it.
public class SSCCE {
public static void main(String[] args) {
// Here you specify the size of your triangle. Change the number dim to
// whatever you want. The triangle will be represented by a 2d-array.
final int dim = 5;
int[][] triangle = new int[dim][dim];
// Walks through the triangle and fills it with random numbers from 1-9.
for (int r = 0; r < dim; r++) {
for (int c = 0; c < r + 1; c++) {
triangle[r][c] = (int) (9 * Math.random()) + 1;
}
}
// This piece just prints the triangle so you can see what's in it.
for (int r = 0; r < dim; r++) {
for (int c = 0; c < r + 1; c++) {
System.out.print(triangle[r][c] + " ");
}
System.out.println();
}
// This part finds the maximum of each row. It prints each rows maximum
// as well as the sum of all the maximums at the end.
int sum = 0;
System.out.print("\nIn this triangle the maximum total is: ");
for (int r = 0; r < dim; r++) {
int currentMax = 0;
for (int c = 0; c < r + 1; c++) {
if (triangle[r][c] > currentMax) {
currentMax = triangle[r][c];
}
}
sum += currentMax;
if (r != 0) {
System.out.print(" + ");
}
System.out.print(currentMax);
}
System.out.println(" = " + sum + ".");
}
}
Output:
9
9 2
1 7 3
1 7 3 3
5 7 5 1 9
In this triangle the maximum total is: 9 + 9 + 7 + 7 + 9 = 41.

Algorithm comparison in java: test program does not work

I'm trying to compare the execution of the java implementation of QuickSort and its hybrid version (using InsertionSort for those partitions which are smaller than an integer k). I wrote a test class to analyze the behaviour of the algorithms for some values ok k (1 <= k <= 25). For each value of k the class compares for different sizes of the input array the two algorithms.
I can't run the program for some values of the size of the array, for instance for values greater than 4000. The execution reach some different values and then freeze, after a while it will finish but I have no output of the computation. (I'm using eclipse).
What could be the problem? I wish to perform the comparation of the two algoritms for an array size from 10 to 10000 (at least). The code is listed below:
public class Main {
private static final int MAX_K = 25;
private static final int MAX_SIZE = 4500;
private static final int ADD_SIZE = 100;
private static int size = 10;
private static QuickSort qSort;
private static HybridSort hSort;
private static void initArray(int[] A) {
Random rand = new Random();
for (int i = 0; i < A.length; i++) {
// A[i] = (int)(Math.random()*100000);
A[i] = rand.nextInt();
}
}
private static int[] A = new int[10];
private static int[] B = new int[10];
public static void main(String[] args) {
try {
FileWriter fstream = new FileWriter("out.txt");
BufferedWriter out = new BufferedWriter(fstream);
out.write("Init file");
qSort = new QuickSort();
hSort = new HybridSort();
/************************************************/
/* Comparison */
/************************************************/
for (int i = 1; i <= MAX_K; i++) {
hSort.setK(i);
int p = 0;
for (int j = size; j <= MAX_SIZE; j = j + ADD_SIZE) {
A = new int[j];
B = new int[j];
initArray(A);
initArray(B);
long sTime = System.nanoTime();
qSort.quickSort(A, 0, A.length - 1);
long qDuration = System.nanoTime() - sTime;
sTime = System.nanoTime();
hSort.hybridSort(B, 0, B.length - 1);
long hDuration = System.nanoTime() - sTime;
out.append(/* "\nA: " +printArray(A)+ */"K: " + i + " A["
+ j + "]\tQ = " + qDuration + " H = " + hDuration
+ "\n");
String h = Long.toString(hDuration);
String q = Long.toString(qDuration);
if (h.length() < q.length()) {
p++;
out.append("\t#OUTPERM for K: "
+ i
+ "\t\t"
+ hDuration
+ "\t\t < \t\t "
+ qDuration
+ "\t\t\t\t| A[]\t\t"
+ A.length
+ ((q.length() - h.length()) == 2 ? "\t Magn. 2"
: "") + "\n");
}
}
if (p > 0)
out.append("#P= " + p + " for K= " + i + "\n\n");
}
out.append("Close file");
out.close();
} catch (IOException e) {
}
}
}
The algorithm classes:
public class QuickSort {
public void quickSort(int[] A, int left, int right){
if (left < right) {
int m = Partition(A, left, right);
quickSort(A, left, m-1);
quickSort(A, m, right);
}
}
private int Partition(int[] A, int left, int right){
int pivot = A[right];
int i = left;
int j = right;
while (true) {
while ( (A[j] > pivot)) {
j--;
}
while ((A[i] < pivot)) {
i++;
}
if (i < j){
int swap = A[j];
A[j] = A[i];
A[i] = swap;
}else{
return i;
}
}
}
}
public class HybridSort {
int k;
int m;
InsertionSort iSort;
public HybridSort() {
k = 3;
iSort = new InsertionSort();
}
public void hybridSort(int[] A, int left, int right) {
if (left < right) {
if ((right - left) < k) {
iSort.sort(A,left,right);
} else {
m = Partition(A, left, right);
hybridSort(A, left, m - 1);
hybridSort(A, m, right);
}
}
}
private int Partition(int[] A, int left, int right) {
int pivot = A[right];
int i = left;
int j = right;
while (true) {
while ((A[j] > pivot) && (j >= 0)) {
j--;
}
while ((A[i] < pivot) && (i < A.length)) {
i++;
}
if (i < j) {
int swap = A[j];
A[j] = A[i];
A[i] = swap;
} else {
return i;
}
}
}
public void setK(int k) {
this.k = k;
}
}
Your implementation of Partition is not correct. Consider the small test below (I made Partition static for my convenience).
Both while loops won't be executed, because A[i] == A[j] == pivot. Moreover, i<j, so the two elements will be swapped, resulting in exactly the same array. Therefore, the outer while loop becomes infinite.
The same problem occurs for any array for which the first and last element are the same.
public class Test {
public static void main(String[] args) {
int[] A = {1, 1};
Partition(A, 0, 1);
}
private static int Partition(int[] A, int left, int right){
int pivot = A[right];
int i = left;
int j = right;
while (true) {
while ( (A[j] > pivot)) {
j--;
}
while ((A[i] < pivot)) {
i++;
}
if (i < j){
int swap = A[j];
A[j] = A[i];
A[i] = swap;
}else{
return i;
}
}
}
}
Have you tried increasing memory settings for your code to run in eclipse.
You may find this Setting memory of Java programs that runs from Eclipse helpful.
Some tips / possible solution?:
I haven't read your implementation of QuickSort or HybridSort but I am assuming they are correct.
If you are comparing the performance of two algorithms you should most definitely compare their performance to indentical inputs. Currently you are generating two random arrys (albeit of the same size). This isn't necessarily going to be an accurate test as I can easily find a test case where one algorithm will outperform the other if the random generator is out to troll you.
Your logic for comparing the two algorithms is a bit weird and incorrect according to me. Why do you compare the lengths of the strings of the times? according to your logic 1 is the same as 9 and 1,000,000,000 is the same as 9,999,999,999 which is clearly incorrect. One algorithm is almost 10 times faster than the other.
Moreover, one reason for no output might be the reason that you are only outputing when hybridsort is better than quicksort and not the other way around. I am sure there are other reasons as well but this could be one easily noticable reason (if your implementations are incorrect).
I do notice that you close your outputstream which is good as that is a very common reason why there is no output. You should however, close steams in the finally section of the try-catch as then they are guaranteed to close. You could be getting an IOException and in your case this would also not close the outputsteam and consequently lead to no ouput in your file.
Here is a sample structure that I would follow for doing any comparitive testing. It is easy to read and easy to debug with enough output for you to figure out which algorithm performs better. This is merely a suggestion.
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintWriter;
import java.util.Random;
public class Tester {
private static int[] initArray(int size) {
Random rand = new Random();
int[] arr = new int[size];
for (int i = 0; i < arr.length; i++) {
arr[i] = rand.nextInt();
}
return arr;
}
public static void main(String[] args) {
final int MAX_ITERATIONS = 25;
final int INITIAL_ARRAY_SIZE = 10;
final int MAX_ARRAY_SIZE = 4500;
final int ARRAY_SIZE_INCREMENT = 100;
long start;
int[] score = null;
PrintWriter out = null;
try {
out = new PrintWriter(new FileOutputStream("out.txt"));
for (int arraySize = INITIAL_ARRAY_SIZE; arraySize <= MAX_ARRAY_SIZE; arraySize += ARRAY_SIZE_INCREMENT) {
// score[0] is for quickSort and score[1] is for hybridSort
score = new int[2];
for (int iteration = 0; iteration < MAX_ITERATIONS; iteration++) {
int[] testArray = initArray(arraySize);
int[] testArrayCopy = new int[arraySize];
System.arraycopy(testArray, 0, testArrayCopy, 0, arraySize);
start = System.nanoTime();
// Do quicksort here using testArray
long qSortfinish = System.nanoTime() - start;
System.arraycopy(testArray, 0, testArrayCopy, 0, arraySize);
start = System.nanoTime();
// Do hybridsort here using testArrayCopy
long hybridSortfinish = System.nanoTime() - start;
// Keep score
if (qSortfinish < hybridSortfinish)
score[0]++;
else if (qSortfinish > hybridSortfinish) {
score[1]++;
} else {
score[0]++;
score[1]++;
}
}
out.println("Array Size: " + arraySize + " QuickSort: " + score[0] + " HybridSort: " + score[1]);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
if (out != null)
out.close();
}
}
}

Optimizing N queens puzzle

I'm trying to solve the problem of positioning N queens on NxN board without row, column and diagonal conflicts. I use an algorithm with minimizing the conflicts. Firstly, on each column randomly a queen is positioned. After that, of all conflict queens randomly one is chosen and for her column are calculated the conflicts of each possible position. Then, the queen moves to the best position with min number of conflicts. It works, but it runs extremely slow. My goal is to make it run fast for 10000 queens. Would you, please, suggest me some improvements or maybe notice some mistakes in my logic?
Here is my code:
public class Queen {
int column;
int row;
int d1;
int d2;
public Queen(int column, int row, int d1, int d2) {
super();
this.column = column;
this.row = row;
this.d1 = d1;
this.d2 = d2;
}
#Override
public String toString() {
return "Queen [column=" + column + ", row=" + row + ", d1=" + d1
+ ", d2=" + d2 + "]";
}
#Override
public boolean equals(Object obj) {
return ((Queen)obj).column == this.column && ((Queen)obj).row == this.row;
}
}
And:
import java.util.HashSet;
import java.util.Random;
public class SolveQueens {
public static boolean printBoard = false;
public static int N = 100;
public static int maxSteps = 2000000;
public static int[] queens = new int[N];
public static Random random = new Random();
public static HashSet<Queen> q = new HashSet<Queen>();
public static HashSet rowConfl[] = new HashSet[N];
public static HashSet d1Confl[] = new HashSet[2*N - 1];
public static HashSet d2Confl[] = new HashSet[2*N - 1];
public static void init () {
int r;
rowConfl = new HashSet[N];
d1Confl = new HashSet[2*N - 1];
d2Confl = new HashSet[2*N - 1];
for (int i = 0; i < N; i++) {
r = random.nextInt(N);
queens[i] = r;
Queen k = new Queen(i, r, i + r, N - 1 + i - r);
q.add(k);
if (rowConfl[k.row] == null) {
rowConfl[k.row] = new HashSet<Queen>();
}
if (d1Confl[k.d1] == null) {
d1Confl[k.d1] = new HashSet<Queen>();
}
if (d2Confl[k.d2] == null) {
d2Confl[k.d2] = new HashSet<Queen>();
}
((HashSet<Queen>)rowConfl[k.row]).add(k);
((HashSet<Queen>)d1Confl[k.d1]).add(k);
((HashSet<Queen>)d2Confl[k.d2]).add(k);
}
}
public static void print () {
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
System.out.print(queens[i] == j ? "♕ " : "◻◻◻ ");
}
System.out.println();
}
System.out.println();
}
public static boolean checkItLinear() {
Queen r = choseConflictQueen();
if (r == null) {
return true;
}
Queen newQ = findNewBestPosition(r);
q.remove(r);
q.add(newQ);
rowConfl[r.row].remove(r);
d1Confl[r.d1].remove(r);
d2Confl[r.d2].remove(r);
if (rowConfl[newQ.row] == null) {
rowConfl[newQ.row] = new HashSet<Queen>();
}
if (d1Confl[newQ.d1] == null) {
d1Confl[newQ.d1] = new HashSet<Queen>();
}
if (d2Confl[newQ.d2] == null) {
d2Confl[newQ.d2] = new HashSet<Queen>();
}
((HashSet<Queen>)rowConfl[newQ.row]).add(newQ);
((HashSet<Queen>)d1Confl[newQ.d1]).add(newQ);
((HashSet<Queen>)d2Confl[newQ.d2]).add(newQ);
queens[r.column] = newQ.row;
return false;
}
public static Queen choseConflictQueen () {
HashSet<Queen> conflictSet = new HashSet<Queen>();
boolean hasConflicts = false;
for (int i = 0; i < 2*N - 1; i++) {
if (i < N && rowConfl[i] != null) {
hasConflicts = hasConflicts || rowConfl[i].size() > 1;
conflictSet.addAll(rowConfl[i]);
}
if (d1Confl[i] != null) {
hasConflicts = hasConflicts || d1Confl[i].size() > 1;
conflictSet.addAll(d1Confl[i]);
}
if (d2Confl[i] != null) {
hasConflicts = hasConflicts || d2Confl[i].size() > 1;
conflictSet.addAll(d2Confl[i]);
}
}
if (hasConflicts) {
int c = random.nextInt(conflictSet.size());
return (Queen) conflictSet.toArray()[c];
}
return null;
}
public static Queen findNewBestPosition(Queen old) {
int[] row = new int[N];
int min = Integer.MAX_VALUE;
int minInd = old.row;
for (int i = 0; i < N; i++) {
if (rowConfl[i] != null) {
row[i] = rowConfl[i].size();
}
if (d1Confl[old.column + i] != null) {
row[i] += d1Confl[old.column + i].size();
}
if (d2Confl[N - 1 + old.column - i] != null) {
row[i] += d2Confl[N - 1 + old.column - i].size();
}
if (i == old.row) {
row[i] = row[i] - 3;
}
if (row[i] <= min && i != minInd) {
min = row[i];
minInd = i;
}
}
return new Queen(old.column, minInd, old.column + minInd, N - 1 + old.column - minInd);
}
public static void main(String[] args) {
long startTime = System.currentTimeMillis();
init();
int steps = 0;
while(!checkItLinear()) {
if (++steps > maxSteps) {
init();
steps = 0;
}
}
long endTime = System.currentTimeMillis();
System.out.println("Done for " + (endTime - startTime) + "ms\n");
if(printBoard){
print();
}
}
}
Edit:
Here is my a-little-bit-optimized solution with removing some unused objects and putting the queens on diagonal positions when initializing.
import java.util.Random;
import java.util.Vector;
public class SolveQueens {
public static boolean PRINT_BOARD = true;
public static int N = 10;
public static int MAX_STEPS = 5000;
public static int[] queens = new int[N];
public static Random random = new Random();
public static int[] rowConfl = new int[N];
public static int[] d1Confl = new int[2*N - 1];
public static int[] d2Confl = new int[2*N - 1];
public static Vector<Integer> conflicts = new Vector<Integer>();
public static void init () {
random = new Random();
for (int i = 0; i < N; i++) {
queens[i] = i;
}
}
public static int getD1Pos (int col, int row) {
return col + row;
}
public static int getD2Pos (int col, int row) {
return N - 1 + col - row;
}
public static void print () {
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
System.out.print(queens[i] == j ? "Q " : "* ");
}
System.out.println();
}
System.out.println();
}
public static boolean hasConflicts() {
generateConflicts();
if (conflicts.isEmpty()) {
return false;
}
int r = random.nextInt(conflicts.size());
int conflQueenCol = conflicts.get(r);
int currentRow = queens[conflQueenCol];
int bestRow = currentRow;
int minConfl = getConflicts(conflQueenCol, queens[conflQueenCol]) - 3;
int tempConflCount;
for (int i = 0; i < N ; i++) {
tempConflCount = getConflicts(conflQueenCol, i);
if (i != currentRow && tempConflCount <= minConfl) {
minConfl = tempConflCount;
bestRow = i;
}
}
queens[conflQueenCol] = bestRow;
return true;
}
public static void generateConflicts () {
conflicts = new Vector<Integer>();
rowConfl = new int[N];
d1Confl = new int[2*N - 1];
d2Confl = new int[2*N - 1];
for (int i = 0; i < N; i++) {
int r = queens[i];
rowConfl[r]++;
d1Confl[getD1Pos(i, r)]++;
d2Confl[getD2Pos(i, r)]++;
}
for (int i = 0; i < N; i++) {
int conflictsCount = getConflicts(i, queens[i]) - 3;
if (conflictsCount > 0) {
conflicts.add(i);
}
}
}
public static int getConflicts(int col, int row) {
return rowConfl[row] + d1Confl[getD1Pos(col, row)] + d2Confl[getD2Pos(col, row)];
}
public static void main(String[] args) {
long startTime = System.currentTimeMillis();
init();
int steps = 0;
while(hasConflicts()) {
if (++steps > MAX_STEPS) {
init();
steps = 0;
}
}
long endTime = System.currentTimeMillis();
System.out.println("Done for " + (endTime - startTime) + "ms\n");
if(PRINT_BOARD){
print();
}
}
}
Comments would have been helpful :)
Rather than recreating your conflict set and your "worst conflict" queen everything, could you create it once, and then just update the changed rows/columns?
EDIT 0:
I tried playing around with your code a bit. Since the code is randomized, it's hard to find out if a change is good or not, since you might start with a good initial state or a crappy one. I tried making 10 runs with 10 queens, and got wildly different answers, but results are below.
I psuedo-profiled to see which statements were being executed the most, and it turns out the inner loop statements in chooseConflictQueen are executed the most. I tried inserting a break to pull the first conflict queen if found, but it didn't seem to help much.
Grouping only runs that took more than a second:
I realize I only have 10 runs, which is not really enough to be statistically valid, but hey.
So adding breaks didn't seem to help. I think a constructive solution will likely be faster, but randomness will again make it harder to check.
Your approach is good : Local search algorithm with minimum-conflicts constraint. I would suggest try improving your initial state. Instead of randomly placing all queens, 1 per column, try to place them so that you minimize the number of conflicts. An example would be to try placing you next queen based on the position of the previous one ... or maybe position of previous two ... Then you local search will have less problematic columns to deal with.
If you randomly select, you could be selecting the same state as a previous state. Theoretically, you might never find a solution even if there is one.
I think you woud be better to iterate normally through the states.
Also, are you sure boards other than 8x8 are solvable?
By inspection, 2x2 is not, 3x3 is not, 4x4 is not.

Categories

Resources