recursion count of groups - java

so I got a little stuck in the code and if possible help
so the matrix is
{1,1,0,0,0},
{0,1,0,0,1},
{1,0,0,1,1},
{0,0,0,0,0},
{1,0,1,1,0}};
so i need to to return how much islands of 1 i have .Here in the example there are 4
I tried to do a double loop and any repetition of it would be added to my count 1 but I got into trouble with an edge case etc. this is some of my code.
There are probably duplicates because I tried something different every time
help
if(A[i][j]==1&& A[i-1][j]==1&&i>=1 && j>=0 && j<=A[i].length-1 &&i<=A.length-1 ) {
A[i][j]=0;
count++;
printPath1(A, i - 1, j); } // up
if(A[i][j]==1&&A[i][j+1]==1&& i>=0 && j>=0 && j<=A[i].length-1 &&i<=A.length-1 ) {
A[i][j]=0;
count++;
printPath1(A, i, j + 1); } // right
if(A[i][j]==1&& A[i][j-1]==1 && i>=0 && j>=1 && j<=A[i].length-1 &&i<=A.length-1 ) {
A[i][j]=0;
count++;
printPath1(A, i, j - 1);} // left
if(A[i][j]==1&&A[i-1][j-1]==1&& i>=1 && j>=1 && j<=A[i].length-1 &&i<=A.length-1 ) {
A[i][j]=0;
count++;
printPath1(A, i-1, j - 1); }
if(A[i][j]==1&&A[i-1][j+1]==1&& i>=1 && j>=0 && j<=A[i].length-1 &&i<=A.length-1 ) {
A[i][j]=0;
count++;
printPath1(A, i-1, j + 1); }
if(A[i][j]==1&&A[i+1][j+1]==1&& i>=0 && j>=0 && j<=A[i].length-1 &&i<=A.length-1 ) {
A[i][j]=0;
count++;
printPath1(A, i+1, j + 1); }
if(A[i][j]==1&& A[i+1][j+1]==1&&i>=0 && j>=1 && j<=A[i].length-1 &&i<=A.length-1 ) {
A[i][j]=0;
count++;
printPath1(A, i, j - 1); }
if(A[i][j]==1&& A[i+1][j]==1&& i>=0 && j>=0 && j<=A[i].length-1 &&i<=A.length-1 ) {
count++;
A[i][j]=0;
printPath1(A, i + 1, j);} // down

Not only do you not need recursion but it is better not to use it.
Keep a list of unvisited cells. Scroll through the matrix looking for unvisited cells, when you find one, you have a new group. Mark all the cells in that group as already visited (so they don't count another group).
A simple way to do it is:
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Set;
public class Program {
public static void main(String... args) {
int[][] mx = {
{1, 1, 0, 0, 0},
{0, 1, 0, 0, 1},
{1, 0, 0, 1, 1},
{0, 0, 0, 0, 0},
{1, 0, 1, 1, 0}};
N2[] cross = new N2[]{new N2(0, -1), new N2(0, 1), new N2(-1, 0), new N2(1, 0)};
N2[] diagonal = new N2[]{new N2(0, -1), new N2(0, 1), new N2(-1, 0), new N2(1, 0), new N2(-1,-1), new N2(1,-1), new N2(-1,1), new N2(1,1)};
System.out.printf("%d%n", countGroupsOf(1, mx, cross));
System.out.printf("%d%n", countGroupsOf(1, mx, diagonal));
System.out.printf("%d%n", countGroupsOf(0, mx, cross));
System.out.printf("%d%n", countGroupsOf(0, mx, diagonal));
}
private static int countGroupsOf(int value, int[][] mx, N2[] adjacentDeltas) {
int groups = 0;
// visited cells with `value` must not be revisited
Set<N2> visited = new HashSet<>();
// check all `value` cells
for (int i = 0; i < mx.length; i++)
for (int j = 0; j < mx[i].length; j++) {
N2 p = new N2(i, j);
if (mx[i][j] == value && !visited.contains(p)) {
// new group encountered
groups += 1;
// visit all `value` cells in this group
Queue<N2> expand = new LinkedList<>();
expand.add(p);
visited.add(p);
while (!expand.isEmpty()) {
N2 q = expand.poll();
// arbitrary adjacency
for (N2 d : adjacentDeltas) {
N2 r = q.add(d);
// adjacent, valid, not visited, `value` cells must be expanded
if (r.x >= 0 && r.y >= 0 && r.x < mx.length && r.y < mx[r.x].length && mx[r.x][r.y] == value && !visited.contains(r)) {
expand.add(r);
visited.add(r);
}
}
}
}
}
return groups;
}
static class N2 {
int x;
int y;
N2 add(N2 p) {
return new N2(x + p.x, y + p.y);
}
N2(int x, int y) {
this.x = x;
this.y = y;
}
#Override
public int hashCode() {
return x + 7 * y;
}
#Override
public boolean equals(Object z) {
if(!(z instanceof N2))
return false;
N2 w = (N2) z;
return w.x == x && w.y == y;
}
}
}
With result:
5
4
2
1
This algorithm works for any adjacency relationship you want to define.
The time and memory complexity is O(n) (where n is the total cells number).

Here is a solution.
public class IslandsMentallurg {
private static class Cell {
int col;
int row;
Cell(int row, int col) {
this.row = row;
this.col = col;
}
#Override
public String toString() {
return "(" + row + "," + col + ")";
}
}
private static int[][] matrix = { //
{ 1, 1, 0, 0, 0 }, //
{ 0, 1, 0, 0, 1 }, //
{ 1, 0, 0, 1, 1 }, //
{ 0, 0, 0, 0, 0 }, //
{ 1, 0, 1, 1, 0 } //
};
private static boolean[][] visited;
private static Cell findNewCell(Cell currentCell) {
for (int i = -1; i <= 1; i++) {
int row = currentCell.row + i;
if (row < 0 || row >= matrix.length) {
continue;
}
for (int j = -1; j <= 1; j++) {
int col = currentCell.col + j;
if (col < 0 || col >= matrix[row].length) {
continue;
}
if (!visited[row][col] && matrix[row][col] == 1) {
return new Cell(row, col);
}
}
}
return null;
}
public static void main(String[] args) {
visited = new boolean[matrix.length][matrix.length];
for (int i = 0; i < visited.length; i++) {
for (int j = 0; j < visited[i].length; j++) {
visited[i][j] = false;
}
}
List<List<Cell>> islands = new ArrayList<>();
for (int i = 0; i < visited.length; i++) {
for (int j = 0; j < visited[i].length; j++) {
if (!visited[i][j] && matrix[i][j] == 1) {
List<Cell> island = new ArrayList<>();
islands.add(island);
island.add(new Cell(i, j));
visited[i][j] = true;
int currentCellIndex = 0;
do {
Cell currentCell = island.get(currentCellIndex);
Cell newCell = findNewCell(currentCell);
if (newCell != null) {
island.add(newCell);
visited[newCell.row][newCell.col] = true;
currentCellIndex = island.size() - 1;
continue;
}
currentCellIndex--;
} while (currentCellIndex >= 0);
}
}
}
System.out.printf("Number of 1-islands: %d\n", islands.size());
for (int i = 0; i < islands.size(); i++) {
System.out.printf("Island %d: ", i + 1);
List<Cell> island = islands.get(i);
for (Cell cell : island) {
System.out.printf("%s, ", cell);
}
System.out.printf("\n");
}
}
}

Related

How to create shorter if-statements, or make them look better?

I have this code, where the conditions are very similar and the methods being called are the same. I was wondering if there's a way to make this look better, or at least make it smaller and thus easier to read.
public void open(int i, int j){
if (i > n - 1 || i < 0 || j > n - 1 || j < 0) {
throw new IndexOutOfBoundsException
("Index out of bounds.");
}
grid[i][j] = true;
if (i - 1 >= 0 && grid[i - 1][j]) {
unionFind.union(location(i - 1, j), location(i, j));
unionFind2.union(location(i - 1, j), location(i, j));
}
if (i + 1 < n && grid[i + 1][j]) {
unionFind.union(location(i + 1, j), location(i, j));
unionFind2.union(location(i + 1, j), location(i, j));
}
if (j - 1 >= 0 && grid[i][j - 1]) {
unionFind.union(location(i, j - 1), location(i, j));
unionFind2.union(location(i, j - 1), location(i, j));
}
if (j + 1 < n && grid[i][j + 1]) {
unionFind.union(location(i, j + 1), location(i, j));
unionFind2.union(location(i, j + 1), location(i, j));
}
numberOpen++;
}
Well, you could easily write a method which conditionally calls the union method, then call that unconditionally from open:
public void open(int i, int j) {
if (i > n - 1 || i < 0 || j > n - 1 || j < 0) {
throw new IndexOutOfBoundsException("Index out of bounds.");
}
grid[i][j] = true;
// I'm assuming the result of this doesn't change between calls?
// (We don't know the type, either.)
Location thisLocation = location(i, j);
maybeUnion(i - 1, j, thisLocation);
maybeUnion(i + 1, j, thisLocation);
maybeUnion(i, j + 1, thisLocation);
maybeUnion(i, j - 1, thisLocation);
numberOpen++;
}
private void maybeUnion(int x, int y, Location unionWith) {
if (x < 0 || y < 0 || x >= n || y >= n || !grid[x][y]) {
return;
}
unionFind.union(location(x, y), unionWith);
unionFind2.union(location(x, y), unionWith);
}
Try this.
static final int[][] DIRECTIONS = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
boolean inRange(int i, int j) {
return i >= 0 && i < n && j >= 0 && j < n;
}
public void open(int i, int j) {
if (!inRange(i, j))
throw new IndexOutOfBoundsException("Index out of bounds.");
grid[i][j] = true;
for (int[] dir : DIRECTIONS) {
int ii = i + dir[0], jj = j + dir[1];
if (inRange(ii, jj) && grid[ii][jj]) {
unionFind.union(location(ii, jj), location(i, j));
unionFind2.union(location(ii, jj), location(i, j));
}
}
numberOpen++;
}
private int[] dr = new int[] {-1, 1, 0, 0};
private int[] dc = new int[] { 0, 0, -1, 1};
public void open(int i, int j) {
if (i > n - 1 || i < 0 || j > n - 1 || j < 0) {
throw new IndexOutOfBoundsException("Index out of bounds.");
}
grid[i][j] = true;
Location thisLocation = new location(i, j);
for (int k = 0; k < 4; i++) {
int newI = dr[k] + i;
int newJ = dc[k] + j;
performUnion(new Location(newI, newJ), thisLocation);
}
numberOpen++;
}
private void performUnion(Location loc, Location unionWith) {
if (loc.x < 0 || loc.y < 0 || loc.x >= n || loc.y >= n && !grid[loc.x][loc.y]) {
return;
}
unionFind.union(loc, unionWith);
unionFind2.union(loc, unionWith);
}

Better way to check for equal consecutive elements of size x in an array?

public static void main(String[] args) {
int[] a = { 0, 0, 1, 1, 1, 1, 1, 0, 0 };
int[] b = { 0, 0, 1, 0, 1, 1, 1, 0, 0 };
System.out.println(consecutiveEqualofSize(a, 5));
System.out.println(consecutiveEqualofSize(b, 5));
System.out.println(consecutiveEqualofSize(b, 3));
}
public static boolean consecutiveEqualofSize(int[] a, int size) {
int count = 0;
boolean flag = false;
for (int i = 0; i < a.length; i++) {
if (flag) {
break;
}
if (a[i] == 1) {
for (int j = i; j < i + size; j++) {
if (j == a.length - 1)
break;
if (a[j] == 1) {
count++;
} else {
count = 0;
break;
}
if (count == size)
flag = true;
}
}
}
return flag;
}
The code in the main method print "True, False, True". Im a new student within programming and would like some tips
Start your loop with the second element. You only need to compare the current element and the previous element to count the duplicates. If you get the desired count return immediately. Something like
public static boolean consecutiveEqualofSize(int[] a, int size) {
int count = 0;
for (int i = 1; i < a.length; i++) {
if (a[i] == a[i - 1]) {
count++;
if (count >= size - 1) {
return true;
}
} else {
count = 0;
}
}
return false;
}
You can simplify the code by comparing the current element with the previous one. If they match, increase the counter. If not, return true if the counter matches the passed value, otherwise carry on.
public static boolean consecutiveEqualofSize(int[] a, int size) {
if (a == null) return false;
int matched = 1;
for (int i = 1; i < a.length; i++) {
if (a[i] != a[i - 1]) {
if (matched == size) return true;
matched = 1;
} else {
matched++;
}
}
return matched == size;
}

8 Puzzle A* java Implemenation [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
I am told that A* implementation on following 8 puzzle Solver is wrong, can anybody please tell me where it's wrong and how to correct it?
Also: this throws Exception in thread "main" java.lang.OutOfMemoryError: Java heap space even though Build Process Heap size is set to 2048.
Here is Solver.java
import java.util.HashSet;
import java.util.Set;
import java.util.Stack;
import java.util.PriorityQueue;
public class Solver {
private int moves = 0;
private SearchNode finalNode;
private Stack<Board> boards;
public Solver(Board initial) {
if (!initial.isSolvable()) throw new IllegalArgumentException("Unsolvable puzzle");
// this.initial = initial;
PriorityQueue<SearchNode> minPQ = new PriorityQueue<SearchNode>(initial.size() + 10);
Set<Board> previouses = new HashSet<Board>(50);
Board dequeuedBoard = initial;
Board previous = null;
SearchNode dequeuedNode = new SearchNode(initial, 0, null);
Iterable<Board> boards;
while (!dequeuedBoard.isGoal()) {
boards = dequeuedBoard.neighbors();
moves++;
for (Board board : boards) {
if (!board.equals(previous) && !previouses.contains(board)) {
minPQ.add(new SearchNode(board, moves, dequeuedNode));
}
}
previouses.add(previous);
previous = dequeuedBoard;
dequeuedNode = minPQ.poll();
dequeuedBoard = dequeuedNode.current;
}
finalNode = dequeuedNode;
}
// min number of moves to solve initial board
public int moves() {
if (boards != null) return boards.size()-1;
solution();
return boards.size() - 1;
}
public Iterable<Board> solution() {
if (boards != null) return boards;
boards = new Stack<Board>();
SearchNode pointer = finalNode;
while (pointer != null) {
boards.push(pointer.current);
pointer = pointer.previous;
}
return boards;
}
private class SearchNode implements Comparable<SearchNode> {
private final int priority;
private final SearchNode previous;
private final Board current;
public SearchNode(Board current, int moves, SearchNode previous) {
this.current = current;
this.previous = previous;
this.priority = moves + current.manhattan();
}
#Override
public int compareTo(SearchNode that) {
int cmp = this.priority - that.priority;
return Integer.compare(cmp, 0);
}
}
public static void main(String[] args) {
int[][] tiles = {{4, 1, 3},
{0, 2, 6},
{7, 5, 8}};
double start = System.currentTimeMillis();
Board board = new Board(tiles);
Solver solve = new Solver(board);
System.out.printf("# of moves = %d && # of actual moves %d & time passed %f\n, ", solve.moves(), solve.moves, (System.currentTimeMillis() - start) / 1000);
}
}
And Board.java, just in case:
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
public final class Board {
private final int[][] tilesCopy;
private final int N;
// cache
private int hashCode = -1;
private int zeroRow = -1;
private int zeroCol = -1;
private Collection<Board> neighbors;
/*
* Rep Invariant
* tilesCopy.length > 0
* Abstraction Function
* represent single board of 8 puzzle game
* Safety Exposure
* all fields are private and final (except cache variables). In the constructor,
* defensive copy of tiles[][] (array that is received from the client)
* is done.
*/
public Board(int[][] tiles) {
//this.N = tiles.length;
this.N = 3;
this.tilesCopy = new int[N][N];
// defensive copy
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
if (tiles[i][j] >= 0 && tiles[i][j] < N*N) tilesCopy[i][j] = tiles[i][j];
else {
System.out.printf("Illegal tile value at (%d, %d): "
+ "should be between 0 and N^2 - 1.", i, j);
System.exit(1);
}
}
}
checkRep();
}
public int tileAt(int row, int col) {
if (row < 0 || row > N - 1) throw new IndexOutOfBoundsException
("row should be between 0 and N - 1");
if (col < 0 || col > N - 1) throw new IndexOutOfBoundsException
("col should be between 0 and N - 1");
return tilesCopy[row][col];
}
public int size() {
return N;
}
public int hamming() {
int hamming = 0;
for (int row = 0; row < this.size(); row++) {
for (int col = 0; col < this.size(); col++) {
if (tileAt(row, col) != 0 && tileAt(row, col) != (row*N + col + 1)) hamming++;
}
}
return hamming;
}
// sum of Manhattan distances between tiles and goal
public int manhattan() {
int manhattan = 0;
int expectedRow = 0, expectedCol = 0;
for (int row = 0; row < this.size(); row++) {
for (int col = 0; col < this.size(); col++) {
if (tileAt(row, col) != 0 && tileAt(row, col) != (row*N + col + 1)) {
expectedRow = (tileAt(row, col) - 1) / N;
expectedCol = (tileAt(row, col) - 1) % N;
manhattan += Math.abs(expectedRow - row) + Math.abs(expectedCol - col);
}
}
}
return manhattan;
}
public boolean isGoal() {
if (tileAt(N-1, N-1) != 0) return false; // prune
for (int i = 0; i < this.size(); i++) {
for (int j = 0; j < this.size(); j++) {
if (tileAt(i, j) != 0 && tileAt(i, j) != (i*N + j + 1)) return false;
}
}
return true;
}
// change i && j' s name
public boolean isSolvable() {
int inversions = 0;
for (int i = 0; i < this.size() * this.size(); i++) {
int currentRow = i / this.size();
int currentCol = i % this.size();
if (tileAt(currentRow, currentCol) == 0) {
this.zeroRow = currentRow;
this.zeroCol = currentCol;
}
for (int j = i; j < this.size() * this.size(); j++) {
int row = j / this.size();
int col = j % this.size();
if (tileAt(row, col) != 0 && tileAt(row, col) < tileAt(currentRow, currentCol)) {
inversions++;
}
}
}
if (tilesCopy.length % 2 != 0 && inversions % 2 != 0) return false;
if (tilesCopy.length % 2 == 0 && (inversions + this.zeroRow) % 2 == 0) return false;
return true;
}
#Override
public boolean equals(Object y) {
if (!(y instanceof Board)) return false;
Board that = (Board) y;
// why bother checking whole array, if last elements aren't equals
return this.tileAt(N - 1, N - 1) == that.tileAt(N - 1, N - 1) && this.size() == that.size() && Arrays.deepEquals(this.tilesCopy, that.tilesCopy);
}
#Override
public int hashCode() {
if (this.hashCode != -1) return hashCode;
// more optimized version(Arrays.hashCode is too slow)?
this.hashCode = Arrays.deepHashCode(tilesCopy);
return this.hashCode;
}
public Collection<Board> neighbors() {
if (neighbors != null) return neighbors;
if (this.zeroRow == -1 && this.zeroCol == -1) findZeroTile();
neighbors = new HashSet<>();
if (zeroRow - 1 >= 0) generateNeighbor(zeroRow - 1, true);
if (zeroCol - 1 >= 0) generateNeighbor(zeroCol - 1, false);
if (zeroRow + 1 < this.size()) generateNeighbor(zeroRow + 1, true);
if (zeroCol + 1 < this.size()) generateNeighbor(zeroCol + 1, false);
return neighbors;
}
private void findZeroTile() {
outerloop:
for (int i = 0; i < this.size(); i++) {
for (int j = 0; j < this.size(); j++) {
if (tileAt(i, j) == 0) {
this.zeroRow = i; // index starting from 0
this.zeroCol = j;
break outerloop;
}
}
}
}
private void generateNeighbor(int toPosition, boolean isRow) {
int[][] copy = Arrays.copyOf(this.tilesCopy, tilesCopy.length);
if (isRow) swapEntries(copy, zeroRow, zeroCol, toPosition, zeroCol);
else swapEntries(copy, zeroRow, zeroCol, zeroRow, toPosition);
neighbors.add(new Board(copy));
}
private void swapEntries(int[][] array, int fromRow, int fromCol, int toRow, int toCol) {
int i = array[fromRow][fromCol];
array[fromRow][fromCol] = array[toRow][toCol];
array[toRow][toCol] = i;
}
public String toString() {
StringBuilder s = new StringBuilder(4 * N * N); // optimization?
// s.append(N + "\n");
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
s.append(String.format("%2d ", tileAt(i, j)));
}
s.append("\n");
}
return s.toString();
}
private void checkRep() {
assert tilesCopy.length > 0;
}
}
The problem you have is at line
int[][] copy = Arrays.copyOf(this.tilesCopy, tilesCopy.length);
You assume here to have copied the matrix. But actually you've copied the array with references to arrays in the 2nd dimension.
In other words
copy == this.tolesCopy // false
copy[0] == this.tilesCopy[0] // true
copy[1] == this.tilesCopy[1] // true
copy[2] == this.tilesCopy[2] // true
what leads to have the same matrix changed multiple times, and even to an invalid/unsolvable state.
The easiest fix I see in your code would be to change the generateNeighbor method
private void generateNeighbor(int toPosition, boolean isRow) {
Board board = new Board(this.tilesCopy);
if (isRow) swapEntries(board.tilesCopy, zeroRow, zeroCol, toPosition, zeroCol);
else swapEntries(board.tilesCopy, zeroRow, zeroCol, zeroRow, toPosition);
neighbors.add(board);
}
Although the overal idea looks good. There are multiple other things that can be improved. I suggest you to have a look at this implementation

Java arrays: 4-point in a matrix

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();
}

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