Java arrays: 4-point in a matrix - java

Can anyone tell me why in the code below, for array points stands [k][1] and no [k][0]
It's about drawing a 5-point in a matrix.
int w = 20;
int h = 10;
int[][] points = { { 2, 4 }, { 1, 5 }, { 6, 6 }, { 3, 2 }, { 0, 0 } };
for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
boolean points_exsist = false;
for (int k = 0; k < points.length; k++) {
if (points[k][0] == i && points[k][1] == j) {
points_exsist = true;
}
}
System.out.print(points_exsist ? "B" : "O");
}
System.out.println();
}

Related

ERROR : java.lang.ArrayIndexOutOfBoundsException: Index 4 out of bounds for length 4

Can anyone please point out the mistake, the error its showing is:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 4 out of bounds for length 4
at com.company.Grid.pushZero(Grid.java:42)
at com.company.Main.main(Main.java:14)
My Code is
package com.company;
import java.util.Random;
public class Grid {
Random rand = new Random();
int newnumber() {
double rand1 = rand.nextDouble();
if (rand1 < 0.2) {
return 4;
} else {
return 2;
}
}
int[][] array = {{0, 0, 0, newnumber()}, {0, 0, 0, 2}, {0, 0, 0, 0}, {0, 0, 0, 0}};
void display() {
for (int i = 0; i < 4; i++) {
for (int j = 0; j < array[i].length; ++j) {
System.out.print(array[i][j] + "\t");
}
System.out.print("\n");
}
System.out.print("\n");
}
void pushZero(int[][] array, int n) {
int count1 = 0;
for (int i = 0; i < n; i++){
for (int j = 0; j < n; j++) {
if (array[i][j] != 1) {
array[count1++][j] = array[i][j];
while (count1 < n) {
array[count1++][j] = 1;
}
} else {
while (count1 < n)
array[count1++][j] = 1;
}
int lastNonOne = 0;
for (int a = n - 1; i >= 0; i--) {
if (array[a][j] == 1)
continue;
if (lastNonOne == 0) {
lastNonOne = a;
}
if (array[i][j] !=0)
array[lastNonOne--][j] = array[i][j];
}
while (lastNonOne >= 0)
array[lastNonOne--][j] = 0;
}
}
}
}
You forgot to reset count1. Or, rather, you've mis-scoped it. It shuold probably be declared 2 nest-levels deeper, right above if (array[i][j]...) - the first loop, count1 is upped to 4 (or rather, upped to whatever n is, but I assume that pushZero is called with n=4), and then next loop, it just carries on where it left off, trying array[4], in effect, and that causes an AIOOBEx exactly as you get it - there is no array[4], there's only array[0] through array[3].

Program counting adjacent elements in a 2D array gives inconsistent results

I have a piece of program that i have to fill. It is supposed to count adjacent numbers in a 5 by 5 binary matrix. For example a matrix like this:
0 1 1 1 0
1 0 0 0 1
1 0 0 0 0
1 0 0 1 0
0 1 0 1 0
Should return 8, you can only move horizontally or vertically.
Here is the code that generates these said matrices and it can't have any modifications after i'm done.
import java.util.Random;
public class Test {
public static void main(String[] args) {
final Random r = new Random();
for (int kerrat = 0; kerrat < 10; kerrat++) {
int[][] alkioTaulukko = new int[5][5];
System.out.println("Matriisin");
for (int i = 0; i < alkioTaulukko.length; i++) {
System.out.print("");
for (int j = 0; j < alkioTaulukko[i].length; j++) {
alkioTaulukko[i][j] = r.nextInt(2);
System.out.print("" + alkioTaulukko[i][j] + " ");
}
System.out.println("");
}
System.out.print("suurimman yhtenäisen alueen koko on ");
System.out.println(laskeSuurinAlue(alkioTaulukko));
System.out.println("");
}
}
}
And finally here is my solution to the problem.
static int laskeSuurinAlue(int[][] matriisi) {
int vierekkaiset = 0;
int rivi = matriisi.length;
int palkki = matriisi[0].length;
for (int r = 0; r < rivi; r++)
{
for (int p = 0; p < palkki; p++)
{
if ((p+1 < palkki) && (matriisi[r][p] == matriisi[r][p+1]))//loops through the rows
vierekkaiset++;
if ((r+1 < rivi) && (matriisi[r][p] == matriisi[r+1][p]))//loops through the columns
vierekkaiset++;
}
}
return vierekkaiset;
}
What happens is that my solution always brings up too big results and i'm failing to see any pattern between each run. However if i use a smaller matrix like this:
int[][] array = {{1, 0, 1}, {0, 1, 1}, {0, 1, 0}};
The result is correctly 4.
And if i use a bigger one like this:
int[][] arr = {{1,0,1,1,0},
{0,0,1,0,0},
{0,0,1,0,1},
{1,1,1,0,1},
{0,0,1,0,0}
};
The result is always 20.
Finally here is my code at its current state:
import java.util.Random;
import static java.util.Arrays.deepToString;
public class Test {
public static void main(String[] args) {
final Random r = new Random();
int[][] array = {{1, 0, 1}, {0, 1, 1}, {0, 1, 0}};
int[][] arr = {{1,0,1,1,0},
{0,0,1,0,0},
{0,0,1,0,1},
{1,1,1,0,1},
{0,0,1,0,0}
};
for (int kerrat = 0; kerrat < 10; kerrat++) {
int[][] alkioTaulukko = new int[5][5];
System.out.println("Matriisin");
for (int i = 0; i < alkioTaulukko.length; i++) {
System.out.print("");
for (int j = 0; j < alkioTaulukko[i].length; j++) {
alkioTaulukko[i][j] = r.nextInt(2);
System.out.print("" + alkioTaulukko[i][j] + " ");
}
System.out.println("");
}
System.out.print("suurimman yhtenäisen alueen koko on ");
System.out.println(laskeSuurinAlue(arr));//Change to arr,array or alkioTaulukko to run the code with different matrices
System.out.println(deepToString(arr));
System.out.println("");
}
}
static int laskeSuurinAlue(int[][] array) {
int counter = 0;
int rowLimit = array.length;
int colLimit = array[0].length;
for (int r = 0; r < rowLimit; r++)
{
for (int c = 0; c < colLimit; c++)
{
if ((c+1 < colLimit) && (array[r][c] == array[r][c+1]))
counter++;
if ((r+1 < rowLimit) && (array[r][c] == array[r+1][c]))
counter++;
}
}
return counter;
}
}
You're couting the same entry more than once.
Use this code
static int laskeSuurinAlue(int[][] array) {
int counter = 0;
int rowLimit = array.length;
int colLimit = array[0].length;
for (int r = 0; r < rowLimit; r++)
{
for (int c = 0; c < colLimit; c++)
{
if (array[r][c] == 0) {
continue;
}
int sum = array[r][c];
sum += (r + 1 < rowLimit) ? array[r+1][c] : 0;
sum += (c + 1 < colLimit) ? array[r][c+1] : 0;
sum += (r - 1 >= 0 ) ? array[r-1][c] : 0;
sum += (c - 1 >= 0) ? array[r][c-1] : 0;
if (sum > 1) {
counter++;
}
}
}
return counter;
}

How to shift elements to left after removing array element?

I was asked to write, to remove the element (lets say k=30) from the array and shift the other elements to its left without using inbuilt methods.
I have tried the below approach.
public static void main(String[] args) {
// TODO Auto-generated method stub
int[] arr = new int[] { 1, 2, 30, 4, 5, 30, 6 };
int k = 30;
int count = 0;
System.out.println("---Original Array------");
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
for (int i = 0; i < arr.length; i++) {
if (arr[i] == k)
count++;
}
for (int j = 0; j < count; j++) {
for (int i = 0; i < arr.length; i++) {
if (arr[i] == k) {
for (int l = i; l < arr.length - 1; l++) {
arr[l] = arr[l + 1];
}
}
}
}
System.out.println("---Modified Array------");
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
}
I need output like this: [1 2 4 5 6 0 0]
But the output from the above logic is: [1 2 4 5 6 6 6]
Also, I'm worried about using nested for loops here. Is there any way that we can reduce the time complexity with out using any inbuilt methods?
Here is another variant:
int[] arr = new int[] { 1, 2, 30, 4, 5, 30, 6 };
int k = 30;
int j = 0;
for (int i = 0; i < arr.length; i++) {
if (arr[i] != k) {
arr[j++] = arr[i];
}
}
while (j < arr.length) {
arr[j++] = 0;
}
In order to not change your approach drastically, I would suggest adding another iteration of the array at the end, to insert 0s to count-many indices from the end of your array.
This would be as simple as adding the following snippet:
// nested for loop
// ...
// set trailing elements to 0s
for (int i = 0; i < count ; i++)
arr[arr.length-1-i] = 0;
System.out.println("\n---Modified Array------");
// ...
There are some cleaner/more-efficient ways of solving this problem.
Based exactly on your approach, I went ahead and made a modification to your nested loop to not require another iteration.
for (int j = 0; j < count; j++) {
for (int i = 0; i < arr.length; i++) {
if (arr[i] == k) {
for (int l = i; l < arr.length - 1; l++)
arr[l] = arr[l + 1];
// since we have performed the shifting, we can safely set the last element to 0
arr[arr.length-1] = 0; // <----- this was missing!!
}
}
}
The following code gives the desired result:
int [] arr = { 1, 2, 30, 4, 5, 30, 6 };
int k = 30;
int elementCount = 0;
for (int i = 0; i < arr.length; i++) {
if (arr[i] == k) {
++elementCount;
}
}
int count = 0;
for (int i = 0; i < arr.length; i++) {
if (arr[i] == k) {
count++;
for (int j = i; j < arr.length-1; j++) {
arr[j] = arr[j+1];
}
arr[arr.length-1] = 0;
}
if (count == elementCount) {
break;
}
}
I don't know if it helps. This is a simplified aproach, that is easier to read and understand(at least for people that learned C), that does removal as required....
public static void main(String[] args) {
int[] arr = new int[] { 1, 2, 30, 4, 5, 30, 6 };
int k = 30;
int i=0;
int j=0;
for(;j<arr.length;i++,j++){
if((arr[i]=arr[j])==k) i--;
}
while(i<j)arr[i++]=0;
System.err.println(Arrays.toString(arr));
}
output:[1, 2, 4, 5, 6, 0, 0]
First version with a small fix on your code. You issue is that the shifted elements need to be replaced by zero. Which require basically an if statement with the arr.length - count
public static void main(String[] args) {
// TODO Auto-generated method stub
int[] arr = new int[] { 1, 2, 30, 4, 5, 30, 6 };
int k = 30;
int count = 0;
System.out.println("---Original Array------");
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
System.out.println("");
for (int i = 0; i < arr.length; i++) {
if (arr[i] == k)
count++;
}
for (int j = 0; j < count; j++) {
for (int i = 0; i < arr.length; i++) {
if(i >= arr.length - count){
arr[i] = 0;
}else {
if (arr[i] == k) {
for (int l = i; l < arr.length - 1; l++) {
arr[l] = arr[l + 1];
}
}
}
}
}
System.out.println("---Modified Array------");
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
System.out.println("");
}
Which gives output
---Original Array------
1 2 30 4 5 30 6
---Modified Array------
1 2 4 5 6 0 0
Now, we can simplify the code also
public static void main(String[] args) {
int[] arr = new int[] { 1, 2, 30, 4, 5, 30, 6 };
int k = 30;
int count = 0;
System.out.println("---Original Array------");
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
System.out.println("");
for(int i = 0; i < arr.length; i++){
if(arr[i]==k){
count++;
}else{
arr[i-count] = arr[i];
}
}
for(int i = 1; i <= count; i++){
arr[arr.length - i] = 0;
}
System.out.println("---Modified Array------");
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
System.out.println("");
}
which give the same output

Finding the Minor Matrix

I have a Matrix class that has the following method
private Matrix matrixMinors()
{
double[][] matrixM = new double[matrix.length][matrix.length];
for(int i = 0; i < matrixM.length; i++)
for(int j = 0; j < matrixM.length; j++)
{
double[][] newone = new double[matrixM.length - 1][matrixM.length - 1];
for(int k = 0; k < newone.length; k++)
for(int h = 0; h < newone[0].length; h++)
if(k == i)
;
else if(h == j)
;
else
newone[k][h] = matrix[k][h];
test(newone, "little matrix"); //this just prints the matrix for debugging purposes
matrixM[i][j] = determinant(newone, newone.length);
}
test(matrixM, "minor matrix"); //this just prints the matrix for debugging purposes
return new Matrix(matrixM);
}
When printed the minor matrix has all zeros, any suggestions as to how to fix this.
Update:
My determinant method keeps printing only zeros, but I'm not sure if that's just because the data I'm giving it makes a zero determinant or my code is faulty.
private double determinant(double[][] mat, int size)
{
double det = 0;
if(size == 1)
det = mat[0][0];
else if (size == 2)
det = mat[0][0] * mat[1][1] - mat[1][0] * mat[0][1];
else
{
for(int j1 = 0; j1 < size; j1++)
{
double[][] m = new double[size-1][];
for(int k = 0; k < (size-1); k++)
m[k] = new double[size-1];
for(int i = 1; i < size; i++)
{
int j2 = 0;
for(int j = 0; j < size; j++)
{
if(j == j1)
continue;
m[i-1][j2] = mat[i][j];
j2++;
}
}
det += Math.pow(-1.0, 1.0 + j1 + 1.0) * mat[0][j1] * determinant(m, size - 1);
}
}
return det;
}
My first advice would be to replace the ugly if-else:
This one:
if(k == i)
;
else if(h == j)
;
else
newone[k][h] = matrix[k][h];
With:
if(k!=i && h!=j) {
System.out.println("test: "+matrix[k][h]);//to see if it enters here
newone[k][h] = matrix[k][h];
}
If the test is not printed, then the logic is wrong.
My second advice:
Write a UnitTest for your determinant method or at least check what it returns (a System.out could help). If it always returns 0, then the minor matrix is, of course, all zeros.
Edit:
You do not need to pass the size to determinant. You can simply use:
private double determinant(double[][] mat)
{
int size = mat.length;
I tested that method with a few matixes like this:
final double[][] mat = new double[][] { { 1, 0, 1 }, { 0, 1, 0 }, { 2, 0, 1 } };
final double det = determinant(mat, 3);
System.out.println("det: " + det);
The result was as expected.
Since newone is not as expected, here a Test class you can use:
public class TestMatrix
{
private static final double delta = 0.0001;
#Test
public void testDeterminant()
{
final double[][] mat = new double[][] { { 1.5, 2.7, 3.8 }, { -4.1, 5.4, -6.6 }, { 7.1, 8000, 9000 } };
final double det = Matrix.determinant(mat, 3);
assertEquals(126817.786, det, delta);
}
// TODO add other tests!
#Test
public void testNewOne() throws Exception
{
final double[][] matrix = { { 3, 0, 2 }, { 2, 0, -2 }, { 0, 1, 1 } };
final double[][] newOne = Matrix.newOne(matrix, 0, 0);
assertMatrix(new double[][] { { 0, -2 }, { 1, 1 } }, newOne);
}
private void assertMatrix(final double[][] ds, final double[][] newOne)
{
assertEquals(ds.length, newOne.length);
for (int i = 0; i < ds.length; i++)
{
assertEquals(ds[i].length, newOne[i].length);
for (int j = 0; j < ds[i].length; j++)
{
assertEquals(ds[i][j], newOne[i][j], delta);
}
}
}
}
I wrote a newOne method like this:
public static double[][] newOne(final double[][] matrix, final int i, final int j)
{
final double[][] newone = new double[matrix.length - 1][matrix.length - 1];
for(int k = 0; k < newone.length; k++)
{
for(int h = 0; h < newone[0].length; h++)
if (k != i && h != j)
{
newone[k][h] = matrix[k][h];
}
}
return newone;
}
Your matrixMinor would then be:
//...
for(int i = 0; i < matrixM.length; i++)
for(int j = 0; j < matrixM.length; j++)
{
double[][] newone = newOne(matrixM, i, j);
test(newone, "little matrix");
matrixM[i][j]=determinant(newone, newone.length);
}
//...
Then just change the method newOne until the UnitTest pass (a few more Tests wouldn't hurt, I just wrote one to show you how it can be done).

Matrix Computing is too slow

I am developing the game that named Lights Out. So for solving this, i have to compute the answer of AX = B in modules 2. So, for this reason i choose jscience library. In this game the size of A is 25x25 matrix, X and B are both 25x1 matrix. I wrote the code such below :
AllLightOut.java class :
public class AllLightOut {
public static final int SIZE = 5;
public static double[] Action(int i, int j) {
double[] change = new double[SIZE * SIZE];
int count = 0;
for (double[] d : Switch(new double[SIZE][SIZE], i, j))
for (double e : d)
change[count++] = e;
return change;
}
public static double[][] MatrixA() {
double[][] mat = new double[SIZE * SIZE][SIZE * SIZE];
for (int i = 0; i < SIZE; i++)
for (int j = 0; j < SIZE; j++)
mat[i * SIZE + j] = Action(i, j);
return mat;
}
public static SparseVector<ModuloInteger> ArrayToDenseVectorModule2(
double[] array) {
List<ModuloInteger> list = new ArrayList<ModuloInteger>();
for (int i = 0; i < array.length; i++) {
if (array[i] == 0)
list.add(ModuloInteger.ZERO);
else
list.add(ModuloInteger.ONE);
}
return SparseVector.valueOf(DenseVector.valueOf(list),
ModuloInteger.ZERO);
}
public static SparseMatrix<ModuloInteger> MatrixAModule2() {
double[][] mat = MatrixA();
List<DenseVector<ModuloInteger>> list = new ArrayList<DenseVector<ModuloInteger>>();
for (int i = 0; i < mat.length; i++) {
List<ModuloInteger> l = new ArrayList<ModuloInteger>();
for (int j = 0; j < mat[i].length; j++) {
if (mat[i][j] == 0)
l.add(ModuloInteger.ZERO);
else
l.add(ModuloInteger.ONE);
}
list.add(DenseVector.valueOf(l));
}
return SparseMatrix.valueOf(DenseMatrix.valueOf(list),
ModuloInteger.ZERO);
}
public static double[][] Switch(double[][] action, int i, int j) {
action[i][j] = action[i][j] == 1 ? 0 : 1;
if (i > 0)
action[i - 1][j] = action[i - 1][j] == 1 ? 0 : 1;
if (i < action.length - 1)
action[i + 1][j] = action[i + 1][j] == 1 ? 0 : 1;
if (j > 0)
action[i][j - 1] = action[i][j - 1] == 1 ? 0 : 1;
if (j < action.length - 1)
action[i][j + 1] = action[i][j + 1] == 1 ? 0 : 1;
return action;
}
}
And the main class is as follow :
public class Main {
public static void main(String[] args) {
double[] bVec = new double[] { 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0 };
SparseMatrix<ModuloInteger> matA = AllLightOut.MatrixAModule2();
SparseVector<ModuloInteger> matB = AllLightOut
.ArrayToDenseVectorModule2(bVec);
ModuloInteger.setModulus(LargeInteger.valueOf(2));
Vector<ModuloInteger> matX = matA.solve(matB);
System.out.println(matX);
}
}
I ran this program for about 30 minutes, but it had not result. Does my code include a fatal error or wrong ? Why it takes too long ?
Thanks for your attention :)
EDIT
The slowdown happening in this line Matrix<ModuloInteger> matX = matA.inverse();. Note that the JScience benchmark result, speed for this library is very high, but i don't know why my program ran too slow!
EDIT2
Please note that when i try to SIZE = 3, i get the answer truly. For example:
MatA :
{{1, 1, 0, 1, 0, 0, 0, 0, 0},
{1, 1, 1, 0, 1, 0, 0, 0, 0},
{0, 1, 1, 0, 0, 1, 0, 0, 0},
{1, 0, 0, 1, 1, 0, 1, 0, 0},
{0, 1, 0, 1, 1, 1, 0, 1, 0},
{0, 0, 1, 0, 1, 1, 0, 0, 1},
{0, 0, 0, 1, 0, 0, 1, 1, 0},
{0, 0, 0, 0, 1, 0, 1, 1, 1},
{0, 0, 0, 0, 0, 1, 0, 1, 1}}
MatB :
{1, 1, 1, 1, 1, 1, 1, 0, 0}
MatC :
{0, 0, 1, 1, 0, 0, 0, 0, 0}
But when i try SIZE = 5, slowdown occurred.
The slowdown happening in this line Matrix<ModuloInteger> matX = matA.inverse();
That would be because the coefficient matrix matA is not invertible for SIZE == 5 (or 4, 9, 11, 14, 16, ...?).
I'm a bit surprised the library didn't detect that and throw an exception. If the library tries to invert the matrix in solve(), that would have the same consequences.
A consequence of the singularity of the coefficient matrix for some sizes is that not all puzzles for these sizes are solvable, and the others have multiple solutions.
Since we're calculating modulo 2, we can use bits or booleans to model our states/toggles, using XOR for addition and & for multiplication. I have cooked up a simple solver using Gaussian elimination, maybe it helps you (I haven't spent much time thinking about the design, so it's not pretty):
public class Lights{
private static final int SIZE = 5;
private static boolean[] toggle(int i, int j) {
boolean[] action = new boolean[SIZE*SIZE];
int idx = i*SIZE+j;
action[idx] = true;
if (j > 0) action[idx-1] = true;
if (j < SIZE-1) action[idx+1] = true;
if (i > 0) action[idx-SIZE] = true;
if (i < SIZE-1) action[idx+SIZE] = true;
return action;
}
private static boolean[][] matrixA() {
boolean[][] mat = new boolean[SIZE*SIZE][];
for(int i = 0; i < SIZE; ++i) {
for(int j = 0; j < SIZE; ++j) {
mat[i*SIZE+j] = toggle(i,j);
}
}
return mat;
}
private static void rotateR(boolean[] a, int r) {
r %= a.length;
if (r < 0) r += a.length;
if (r == 0) return;
boolean[] tmp = new boolean[r];
for(int i = 0; i < r; ++i) {
tmp[i] = a[i];
}
for(int i = 0; i < a.length - r; ++i) {
a[i] = a[i+r];
}
for(int i = 0; i < r; ++i) {
a[i + a.length - r] = tmp[i];
}
}
private static void rotateR(boolean[][] a, int r) {
r %= a.length;
if (r < 0) r += a.length;
if (r == 0) return;
boolean[][] tmp = new boolean[r][];
for(int i = 0; i < r; ++i) {
tmp[i] = a[i];
}
for(int i = 0; i < a.length - r; ++i) {
a[i] = a[i+r];
}
for(int i = 0; i < r; ++i) {
a[i + a.length - r] = tmp[i];
}
}
private static int count(boolean[] a) {
int c = 0;
for(int i = 0; i < a.length; ++i) {
if (a[i]) ++c;
}
return c;
}
private static void swapBits(boolean[] a, int i, int j) {
boolean tmp = a[i];
a[i] = a[j];
a[j] = tmp;
}
private static void addBit(boolean[] a, int i, int j) {
a[j] ^= a[i];
}
private static void swapRows(boolean[][] a, int i, int j) {
boolean[] tmp = a[i];
a[i] = a[j];
a[j] = tmp;
}
private static void xorb(boolean[] a, boolean[] b) {
for(int i = 0; i < a.length; ++i) {
a[i] ^= b[i];
}
}
private static boolean[] boolBits(int bits, long param) {
boolean[] bitArr = new boolean[bits];
for(int i = 0; i < bits; ++i) {
if (((param >> i) & 1L) != 0) {
bitArr[i] = true;
}
}
return bitArr;
}
private static boolean[] solve(boolean[][] m, boolean[] b) {
// Move first SIZE rows to bottom, so that on the diagonal
// above the lowest SIZE rows, there are unit matrices
rotateR(m, SIZE);
// modify right hand side accordingly
rotateR(b,SIZE);
// clean first SIZE*(SIZE-1) columns
for(int i = 0; i < SIZE*(SIZE-1); ++i) {
for(int k = 0; k < SIZE*SIZE; ++k) {
if (k == i) continue;
if (m[k][i]) {
xorb(m[k], m[i]);
b[k] ^= b[i];
}
}
}
// Now we have a block matrix
/*
* E 0 0 ... 0 X
* 0 E 0 ... 0 X
* 0 0 E ... 0 X
* ...
* 0 0 ... E 0 X
* 0 0 ... 0 E X
* 0 0 ... 0 0 Y
*
*/
// Bring Y to row-echelon form
int i = SIZE*(SIZE-1), j, k, mi = i;
while(mi < SIZE*SIZE){
// Try to find a row with mi-th bit set
for(j = i; j < SIZE*SIZE; ++j) {
if (m[j][mi]) break;
}
if (j < SIZE*SIZE) {
// Found one
if (j > i) {
swapRows(m,i,j);
swapBits(b,i,j);
}
for(k = 0; k < SIZE*SIZE; ++k) {
if (k == i) continue;
if (m[k][mi]) {
xorb(m[k], m[i]);
b[k] ^= b[i];
}
}
// cleaned up column, good row, next
++i;
}
// Look at next column
++mi;
}
printMat(m,b);
boolean[] best = b;
if (i < SIZE*SIZE) {
// We have zero-rows in the matrix,
// check whether the puzzle is solvable at all,
// i.e. all corresponding bits in the rhs are 0
for(j = i; j < SIZE*SIZE; ++j) {
if (b[j]) {
System.out.println("Puzzle not solvable, some lights must remain lit.");
break;
// throw new IllegalArgumentException("Puzzle is not solvable!");
}
}
// Pretending it were solvable if not
if (j < SIZE*SIZE) {
System.out.println("Pretending the puzzle were solvable...");
for(; j < SIZE*SIZE; ++j) {
b[j] = false;
}
}
// Okay, puzzle is solvable, but there are several solutions
// Let's try to find the one with the least toggles.
// We have the canonical solution with last bits all zero
int toggles = count(b);
System.out.println(toggles + " toggles in canonical solution");
int freeBits = SIZE*SIZE - i;
long max = 1L << freeBits;
System.out.println(freeBits + " free bits");
// Check all combinations of free bits whether they produce
// something better
for(long param = 1; param < max; ++param) {
boolean[] base = boolBits(freeBits,param);
boolean[] c = new boolean[SIZE*SIZE];
for(k = 0; k < freeBits; ++k) {
c[i+k] = base[k];
}
for(k = 0; k < i; ++k) {
for(j = 0; j < freeBits; ++j) {
c[k] ^= base[j] && m[k][j+i];
}
}
xorb(c,b);
int t = count(c);
if (t < toggles) {
System.out.printf("Found new best for param %x, %d toggles\n",param,t);
printMat(m,c,b);
toggles = t;
best = c;
} else {
System.out.printf("%d toggles for parameter %x\n", t, param);
}
}
}
return best;
}
private static boolean[] parseLights(int[] lights) {
int lim = lights.length;
if (SIZE*SIZE < lim) lim = SIZE*SIZE;
boolean[] b = new boolean[SIZE*SIZE];
for(int i = 0; i < lim; ++i) {
b[i] = (lights[i] != 0);
}
return b;
}
private static void printToggles(boolean[] s) {
for(int i = 0; i < s.length; ++i) {
if (s[i]) {
System.out.print("(" + (i/SIZE + 1) + ", " + (i%SIZE + 1) + "); ");
}
}
System.out.println();
}
private static void printMat(boolean[][] a, boolean[] rhs) {
for(int i = 0; i < SIZE*SIZE; ++i) {
for(int j = 0; j < SIZE*SIZE; ++j) {
System.out.print((a[i][j] ? "1 " : "0 "));
}
System.out.println("| " + (rhs[i] ? "1" : "0"));
}
}
private static void printMat(boolean[][] a, boolean[] sol, boolean[] rhs) {
for(int i = 0; i < SIZE*SIZE; ++i) {
for(int j = 0; j < SIZE*SIZE; ++j) {
System.out.print((a[i][j] ? "1 " : "0 "));
}
System.out.println("| " + (sol[i] ? "1" : "0") + " | " + (rhs[i] ? "1" : "0"));
}
}
private static void printGrid(boolean[] g) {
for(int i = 0; i < SIZE; ++i) {
for(int j = 0; j < SIZE; ++j) {
System.out.print(g[i*SIZE+j] ? "1" : "0");
}
System.out.println();
}
}
public static void main(String[] args) {
int[] initialLights = new int[] { 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0 };
boolean[] b = parseLights(initialLights);
boolean[] b2 = b.clone();
boolean[][] coefficients = matrixA();
boolean[] toggles = solve(coefficients, b);
printGrid(b2);
System.out.println("--------");
boolean[][] check = matrixA();
boolean[] verify = new boolean[SIZE*SIZE];
for(int i = 0; i < SIZE*SIZE; ++i) {
if (toggles[i]) {
xorb(verify, check[i]);
}
}
printGrid(verify);
xorb(b2,verify);
if (count(b2) > 0) {
System.out.println("Aww, shuck, screwed up!");
printGrid(b2);
}
printToggles(toggles);
}
}
You almost never want to calculate the actual inverse of a matrix if it can be avoided. Such operations are problematic and highly time consuming. Looking at the docs for JScience have you considered using the solve method? Something along the lines of matX = matA.solve(matB) should give you what you're looking for and I doubt they're using an inverse to calculate that, although I haven't dug that far into JScience so it's not impossible.

Categories

Resources