diff options
Diffstat (limited to 'src/de/lmu/ifi/dbs/elki/math/linearalgebra/Matrix.java')
-rw-r--r-- | src/de/lmu/ifi/dbs/elki/math/linearalgebra/Matrix.java | 526 |
1 files changed, 239 insertions, 287 deletions
diff --git a/src/de/lmu/ifi/dbs/elki/math/linearalgebra/Matrix.java b/src/de/lmu/ifi/dbs/elki/math/linearalgebra/Matrix.java index 3f513720..6826f67d 100644 --- a/src/de/lmu/ifi/dbs/elki/math/linearalgebra/Matrix.java +++ b/src/de/lmu/ifi/dbs/elki/math/linearalgebra/Matrix.java @@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.math.linearalgebra; This file is part of ELKI: Environment for Developing KDD-Applications Supported by Index-Structures - Copyright (C) 2013 + Copyright (C) 2014 Ludwig-Maximilians-Universität München Lehr- und Forschungseinheit für Datenbanksysteme ELKI Development Team @@ -31,7 +31,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.logging.Logger; -import de.lmu.ifi.dbs.elki.data.RationalNumber; import de.lmu.ifi.dbs.elki.logging.LoggingConfiguration; import de.lmu.ifi.dbs.elki.math.MathUtil; import de.lmu.ifi.dbs.elki.utilities.FormatUtil; @@ -58,9 +57,15 @@ public class Matrix { public static final double DELTA = 1E-3; /** - * Error: matrix not square. + * Small value to increment diagonally of a matrix in order to avoid + * singularity before building the inverse. */ - public static final String ERR_NOTSQUARE = "All rows must have the same length."; + public static final double SINGULARITY_CHEAT = 1E-9; + + /** + * Error: matrix not rectangular. + */ + public static final String ERR_NOTRECTANGULAR = "All rows must have the same length."; /** * Error: matrix indexes incorrect @@ -112,8 +117,8 @@ public class Matrix { public Matrix(final int m, final int n, final double s) { this.columndimension = n; elements = new double[m][n]; - for (int i = 0; i < m; i++) { - for (int j = 0; j < n; j++) { + for(int i = 0; i < m; i++) { + for(int j = 0; j < n; j++) { elements[i][j] = s; } } @@ -128,31 +133,15 @@ public class Matrix { */ public Matrix(final double[][] elements) { columndimension = elements[0].length; - for (int i = 0; i < elements.length; i++) { - if (elements[i].length != columndimension) { - throw new IllegalArgumentException(ERR_NOTSQUARE); + for(int i = 0; i < elements.length; i++) { + if(elements[i].length != columndimension) { + throw new IllegalArgumentException(ERR_NOTRECTANGULAR); } } this.elements = elements; } /** - * Constructs a Matrix for a given array of arrays of {@link RationalNumber}s. - * - * @param q an array of arrays of RationalNumbers. q is not checked for - * consistency (i.e. whether all rows are of equal length) - */ - public Matrix(final RationalNumber[][] q) { - columndimension = q[0].length; - elements = new double[q.length][columndimension]; - for (int row = 0; row < q.length; row++) { - for (int col = 0; col < q[row].length; col++) { - elements[row][col] = q[row][col].doubleValue(); - } - } - } - - /** * Construct a matrix from a one-dimensional packed array * * @param values One-dimensional array of doubles, packed by columns (ala @@ -162,12 +151,12 @@ public class Matrix { */ public Matrix(final double values[], final int m) { columndimension = (m != 0 ? values.length / m : 0); - if (m * columndimension != values.length) { + if(m * columndimension != values.length) { throw new IllegalArgumentException("Array length must be a multiple of m."); } elements = new double[m][columndimension]; - for (int i = 0; i < m; i++) { - for (int j = 0; j < columndimension; j++) { + for(int i = 0; i < m; i++) { + for(int j = 0; j < columndimension; j++) { elements[i][j] = values[i + j * m]; } } @@ -193,9 +182,9 @@ public class Matrix { final int m = A.length; final int n = A[0].length; final Matrix X = new Matrix(m, n); - for (int i = 0; i < m; i++) { - if (A[i].length != n) { - throw new IllegalArgumentException(ERR_NOTSQUARE); + for(int i = 0; i < m; i++) { + if(A[i].length != n) { + throw new IllegalArgumentException(ERR_NOTRECTANGULAR); } System.arraycopy(A[i], 0, X.elements[i], 0, n); } @@ -210,7 +199,7 @@ public class Matrix { */ public static final Matrix unitMatrix(final int dim) { final double[][] e = new double[dim][dim]; - for (int i = 0; i < dim; i++) { + for(int i = 0; i < dim; i++) { e[i][i] = 1; } return new Matrix(e); @@ -236,8 +225,8 @@ public class Matrix { */ public static final Matrix random(final int m, final int n) { final Matrix A = new Matrix(m, n); - for (int i = 0; i < m; i++) { - for (int j = 0; j < n; j++) { + for(int i = 0; i < m; i++) { + for(int j = 0; j < n; j++) { A.elements[i][j] = Math.random(); } } @@ -253,7 +242,7 @@ public class Matrix { */ public static final Matrix identity(final int m, final int n) { final Matrix A = new Matrix(m, n); - for (int i = 0; i < Math.min(m, n); i++) { + for(int i = 0; i < Math.min(m, n); i++) { A.elements[i][i] = 1.0; } return A; @@ -268,7 +257,7 @@ public class Matrix { */ public static final Matrix diagonal(final double[] diagonal) { final Matrix result = new Matrix(diagonal.length, diagonal.length); - for (int i = 0; i < diagonal.length; i++) { + for(int i = 0; i < diagonal.length; i++) { result.elements[i][i] = diagonal[i]; } return result; @@ -283,7 +272,7 @@ public class Matrix { */ public static final Matrix diagonal(final Vector diagonal) { final Matrix result = new Matrix(diagonal.elements.length, diagonal.elements.length); - for (int i = 0; i < diagonal.elements.length; i++) { + for(int i = 0; i < diagonal.elements.length; i++) { result.elements[i][i] = diagonal.elements[i]; } return result; @@ -296,7 +285,7 @@ public class Matrix { */ public final Matrix copy() { final Matrix X = new Matrix(elements.length, columndimension); - for (int i = 0; i < elements.length; i++) { + for(int i = 0; i < elements.length; i++) { System.arraycopy(elements[i], 0, X.elements[i], 0, columndimension); } return X; @@ -326,7 +315,7 @@ public class Matrix { */ public final double[][] getArrayCopy() { final double[][] C = new double[elements.length][]; - for (int i = 0; i < elements.length; i++) { + for(int i = 0; i < elements.length; i++) { C[i] = elements[i].clone(); } return C; @@ -397,7 +386,7 @@ public class Matrix { */ public final double[] getRowPackedCopy() { double[] vals = new double[elements.length * columndimension]; - for (int i = 0; i < elements.length; i++) { + for(int i = 0; i < elements.length; i++) { System.arraycopy(elements[i], 0, vals, i * columndimension, columndimension); } return vals; @@ -410,8 +399,8 @@ public class Matrix { */ public final double[] getColumnPackedCopy() { final double[] vals = new double[elements.length * columndimension]; - for (int i = 0; i < elements.length; i++) { - for (int j = 0; j < columndimension; j++) { + for(int i = 0; i < elements.length; i++) { + for(int j = 0; j < columndimension; j++) { vals[i + j * elements.length] = elements[i][j]; } } @@ -431,10 +420,11 @@ public class Matrix { public final Matrix getMatrix(final int i0, final int i1, final int j0, final int j1) { final Matrix X = new Matrix(i1 - i0 + 1, j1 - j0 + 1); try { - for (int i = i0; i <= i1; i++) { + for(int i = i0; i <= i1; i++) { System.arraycopy(elements[i], j0, X.elements[i - i0], 0, j1 - j0 + 1); } - } catch (ArrayIndexOutOfBoundsException e) { + } + catch(ArrayIndexOutOfBoundsException e) { throw new ArrayIndexOutOfBoundsException(ERR_REINDEX); } return X; @@ -451,12 +441,13 @@ public class Matrix { public final Matrix getMatrix(final int[] r, final int[] c) { final Matrix X = new Matrix(r.length, c.length); try { - for (int i = 0; i < r.length; i++) { - for (int j = 0; j < c.length; j++) { + for(int i = 0; i < r.length; i++) { + for(int j = 0; j < c.length; j++) { X.elements[i][j] = elements[r[i]][c[j]]; } } - } catch (ArrayIndexOutOfBoundsException e) { + } + catch(ArrayIndexOutOfBoundsException e) { throw new ArrayIndexOutOfBoundsException(ERR_REINDEX); } return X; @@ -474,10 +465,11 @@ public class Matrix { public final Matrix getMatrix(final int[] r, final int j0, final int j1) { final Matrix X = new Matrix(r.length, j1 - j0 + 1); try { - for (int i = 0; i < r.length; i++) { + for(int i = 0; i < r.length; i++) { System.arraycopy(elements[r[i]], j0, X.elements[i], 0, j1 - j0 + 1); } - } catch (ArrayIndexOutOfBoundsException e) { + } + catch(ArrayIndexOutOfBoundsException e) { throw new ArrayIndexOutOfBoundsException(ERR_REINDEX); } return X; @@ -495,12 +487,13 @@ public class Matrix { public final Matrix getMatrix(final int i0, final int i1, final int[] c) { final Matrix X = new Matrix(i1 - i0 + 1, c.length); try { - for (int i = i0; i <= i1; i++) { - for (int j = 0; j < c.length; j++) { + for(int i = i0; i <= i1; i++) { + for(int j = 0; j < c.length; j++) { X.elements[i - i0][j] = elements[i][c[j]]; } } - } catch (ArrayIndexOutOfBoundsException e) { + } + catch(ArrayIndexOutOfBoundsException e) { throw new ArrayIndexOutOfBoundsException(ERR_REINDEX); } return X; @@ -518,10 +511,11 @@ public class Matrix { */ public final void setMatrix(final int i0, final int i1, final int j0, final int j1, final Matrix X) { try { - for (int i = i0; i <= i1; i++) { + for(int i = i0; i <= i1; i++) { System.arraycopy(X.elements[i - i0], 0, elements[i], j0, j1 - j0 + 1); } - } catch (ArrayIndexOutOfBoundsException e) { + } + catch(ArrayIndexOutOfBoundsException e) { throw new ArrayIndexOutOfBoundsException(ERR_REINDEX); } } @@ -536,12 +530,13 @@ public class Matrix { */ public final void setMatrix(final int[] r, final int[] c, final Matrix X) { try { - for (int i = 0; i < r.length; i++) { - for (int j = 0; j < c.length; j++) { + for(int i = 0; i < r.length; i++) { + for(int j = 0; j < c.length; j++) { elements[r[i]][c[j]] = X.elements[i][j]; } } - } catch (ArrayIndexOutOfBoundsException e) { + } + catch(ArrayIndexOutOfBoundsException e) { throw new ArrayIndexOutOfBoundsException(ERR_REINDEX); } } @@ -557,10 +552,11 @@ public class Matrix { */ public final void setMatrix(final int[] r, final int j0, final int j1, final Matrix X) { try { - for (int i = 0; i < r.length; i++) { + for(int i = 0; i < r.length; i++) { System.arraycopy(X.elements[i], 0, elements[r[i]], j0, j1 - j0 + 1); } - } catch (ArrayIndexOutOfBoundsException e) { + } + catch(ArrayIndexOutOfBoundsException e) { throw new ArrayIndexOutOfBoundsException(ERR_REINDEX); } } @@ -576,12 +572,13 @@ public class Matrix { */ public final void setMatrix(final int i0, final int i1, final int[] c, final Matrix X) { try { - for (int i = i0; i <= i1; i++) { - for (int j = 0; j < c.length; j++) { + for(int i = i0; i <= i1; i++) { + for(int j = 0; j < c.length; j++) { elements[i][c[j]] = X.elements[i - i0][j]; } } - } catch (ArrayIndexOutOfBoundsException e) { + } + catch(ArrayIndexOutOfBoundsException e) { throw new ArrayIndexOutOfBoundsException(ERR_REINDEX); } } @@ -604,7 +601,7 @@ public class Matrix { * @param row the value of the column to be set */ public final void setRow(final int j, final Vector row) { - if (row.elements.length != columndimension) { + if(row.elements.length != columndimension) { throw new IllegalArgumentException(ERR_MATRIX_DIMENSIONS); } System.arraycopy(row.elements, 0, elements[j], 0, columndimension); @@ -618,7 +615,7 @@ public class Matrix { */ public final Vector getCol(final int j) { final Vector v = new Vector(elements.length); - for (int i = 0; i < elements.length; i++) { + for(int i = 0; i < elements.length; i++) { v.elements[i] = elements[i][j]; } return v; @@ -631,10 +628,10 @@ public class Matrix { * @param column the value of the column to be set */ public final void setCol(final int j, final Vector column) { - if (column.elements.length != elements.length) { + if(column.elements.length != elements.length) { throw new IllegalArgumentException(ERR_MATRIX_DIMENSIONS); } - for (int i = 0; i < elements.length; i++) { + for(int i = 0; i < elements.length; i++) { elements[i][j] = column.elements[i]; } } @@ -646,8 +643,8 @@ public class Matrix { */ public final Matrix transpose() { final Matrix X = new Matrix(columndimension, elements.length); - for (int i = 0; i < elements.length; i++) { - for (int j = 0; j < columndimension; j++) { + for(int i = 0; i < elements.length; i++) { + for(int j = 0; j < columndimension; j++) { X.elements[j][i] = elements[i][j]; } } @@ -665,6 +662,26 @@ public class Matrix { } /** + * C = A + s + * + * @param s scalar value + * @return A + s in a new Matrix + */ + public final Matrix plus(final double s) { + return copy().plusEquals(s); + } + + /** + * C = A + s + * + * @param s scalar value + * @return A + s * E in a new Matrix + */ + public final Matrix plusDiagonal(final double s) { + return copy().plusDiagonalEquals(s); + } + + /** * C = A + s * B * * @param B another matrix @@ -683,8 +700,8 @@ public class Matrix { */ public final Matrix plusEquals(final Matrix B) { checkMatrixDimensions(B); - for (int i = 0; i < elements.length; i++) { - for (int j = 0; j < columndimension; j++) { + for(int i = 0; i < elements.length; i++) { + for(int j = 0; j < columndimension; j++) { elements[i][j] += B.elements[i][j]; } } @@ -692,6 +709,34 @@ public class Matrix { } /** + * A = A + s + * + * @param s constant to add to every cell + * @return A + s in this Matrix + */ + public final Matrix plusEquals(final double s) { + for(int i = 0; i < elements.length; i++) { + for(int j = 0; j < columndimension; j++) { + elements[i][j] += s; + } + } + return this; + } + + /** + * A = A + s + * + * @param s constant to add to the diagonal + * @return A + s in this Matrix + */ + public final Matrix plusDiagonalEquals(final double s) { + for(int i = 0; i < elements.length && i < columndimension; i++) { + elements[i][i] += s; + } + return this; + } + + /** * A = A + s * B * * @param B another matrix @@ -700,8 +745,8 @@ public class Matrix { */ public final Matrix plusTimesEquals(final Matrix B, final double s) { checkMatrixDimensions(B); - for (int i = 0; i < elements.length; i++) { - for (int j = 0; j < columndimension; j++) { + for(int i = 0; i < elements.length; i++) { + for(int j = 0; j < columndimension; j++) { elements[i][j] += s * B.elements[i][j]; } } @@ -737,8 +782,8 @@ public class Matrix { */ public final Matrix minusEquals(final Matrix B) { checkMatrixDimensions(B); - for (int i = 0; i < elements.length; i++) { - for (int j = 0; j < columndimension; j++) { + for(int i = 0; i < elements.length; i++) { + for(int j = 0; j < columndimension; j++) { elements[i][j] -= B.elements[i][j]; } } @@ -754,8 +799,8 @@ public class Matrix { */ public final Matrix minusTimesEquals(final Matrix B, final double s) { checkMatrixDimensions(B); - for (int i = 0; i < elements.length; i++) { - for (int j = 0; j < columndimension; j++) { + for(int i = 0; i < elements.length; i++) { + for(int j = 0; j < columndimension; j++) { elements[i][j] -= s * B.elements[i][j]; } } @@ -779,8 +824,8 @@ public class Matrix { * @return replace A by s*A */ public final Matrix timesEquals(final double s) { - for (int i = 0; i < elements.length; i++) { - for (int j = 0; j < columndimension; j++) { + for(int i = 0; i < elements.length; i++) { + for(int j = 0; j < columndimension; j++) { elements[i][j] *= s; } } @@ -796,22 +841,22 @@ public class Matrix { */ public final Matrix times(final Matrix B) { // Optimized implementation, exploiting the storage layout - if (B.elements.length != this.columndimension) { + if(B.elements.length != this.columndimension) { throw new IllegalArgumentException(ERR_MATRIX_INNERDIM); } final Matrix X = new Matrix(this.elements.length, B.columndimension); // Optimized ala Jama. jik order. final double[] Bcolj = new double[this.columndimension]; - for (int j = 0; j < X.columndimension; j++) { + for(int j = 0; j < X.columndimension; j++) { // Make a linear copy of column j from B - for (int k = 0; k < this.columndimension; k++) { + for(int k = 0; k < this.columndimension; k++) { Bcolj[k] = B.elements[k][j]; } // multiply it with each row from A - for (int i = 0; i < this.elements.length; i++) { + for(int i = 0; i < this.elements.length; i++) { final double[] Arowi = this.elements[i]; double s = 0; - for (int k = 0; k < this.columndimension; k++) { + for(int k = 0; k < this.columndimension; k++) { s += Arowi[k] * Bcolj[k]; } X.elements[i][j] = s; @@ -828,15 +873,15 @@ public class Matrix { * @throws IllegalArgumentException Matrix inner dimensions must agree. */ public final Vector times(final Vector B) { - if (B.elements.length != this.columndimension) { + if(B.elements.length != this.columndimension) { throw new IllegalArgumentException(ERR_MATRIX_INNERDIM); } final Vector X = new Vector(this.elements.length); // multiply it with each row from A - for (int i = 0; i < this.elements.length; i++) { + for(int i = 0; i < this.elements.length; i++) { final double[] Arowi = this.elements[i]; double s = 0; - for (int k = 0; k < this.columndimension; k++) { + for(int k = 0; k < this.columndimension; k++) { s += Arowi[k] * B.elements[k]; } X.elements[i] = s; @@ -852,14 +897,14 @@ public class Matrix { * @throws IllegalArgumentException Matrix inner dimensions must agree. */ public final Vector transposeTimes(final Vector B) { - if (B.elements.length != elements.length) { + if(B.elements.length != elements.length) { throw new IllegalArgumentException(ERR_MATRIX_INNERDIM); } final Vector X = new Vector(this.columndimension); // multiply it with each row from A - for (int i = 0; i < this.columndimension; i++) { + for(int i = 0; i < this.columndimension; i++) { double s = 0; - for (int k = 0; k < elements.length; k++) { + for(int k = 0; k < elements.length; k++) { s += elements[k][i] * B.elements[k]; } X.elements[i] = s; @@ -875,20 +920,20 @@ public class Matrix { * @throws IllegalArgumentException Matrix inner dimensions must agree. */ public final Matrix transposeTimes(final Matrix B) { - if (B.elements.length != elements.length) { + if(B.elements.length != elements.length) { throw new IllegalArgumentException(ERR_MATRIX_INNERDIM); } final Matrix X = new Matrix(this.columndimension, B.columndimension); final double[] Bcolj = new double[elements.length]; - for (int j = 0; j < X.columndimension; j++) { + for(int j = 0; j < X.columndimension; j++) { // Make a linear copy of column j from B - for (int k = 0; k < elements.length; k++) { + for(int k = 0; k < elements.length; k++) { Bcolj[k] = B.elements[k][j]; } // multiply it with each row from A - for (int i = 0; i < this.columndimension; i++) { + for(int i = 0; i < this.columndimension; i++) { double s = 0; - for (int k = 0; k < elements.length; k++) { + for(int k = 0; k < elements.length; k++) { s += elements[k][i] * Bcolj[k]; } X.elements[i][j] = s; @@ -905,17 +950,17 @@ public class Matrix { * @throws IllegalArgumentException Matrix inner dimensions must agree. */ public final Matrix timesTranspose(final Matrix B) { - if (B.columndimension != this.columndimension) { + if(B.columndimension != this.columndimension) { throw new IllegalArgumentException(ERR_MATRIX_INNERDIM); } final Matrix X = new Matrix(this.elements.length, B.elements.length); - for (int j = 0; j < X.elements.length; j++) { + for(int j = 0; j < X.elements.length; j++) { final double[] Browj = B.elements[j]; // multiply it with each row from A - for (int i = 0; i < this.elements.length; i++) { + for(int i = 0; i < this.elements.length; i++) { final double[] Arowi = this.elements[i]; double s = 0; - for (int k = 0; k < this.columndimension; k++) { + for(int k = 0; k < this.columndimension; k++) { s += Arowi[k] * Browj[k]; } X.elements[i][j] = s; @@ -933,23 +978,23 @@ public class Matrix { */ public final Matrix transposeTimesTranspose(Matrix B) { // Optimized implementation, exploiting the storage layout - if (this.elements.length != B.columndimension) { + if(this.elements.length != B.columndimension) { throw new IllegalArgumentException("Matrix inner dimensions must agree: " + getRowDimensionality() + "," + getColumnDimensionality() + " * " + B.getRowDimensionality() + "," + B.getColumnDimensionality()); } final Matrix X = new Matrix(this.columndimension, B.elements.length); // Optimized ala Jama. jik order. final double[] Acolj = new double[this.elements.length]; - for (int j = 0; j < X.elements.length; j++) { + for(int j = 0; j < X.elements.length; j++) { // Make a linear copy of column j from B - for (int k = 0; k < this.elements.length; k++) { + for(int k = 0; k < this.elements.length; k++) { Acolj[k] = this.elements[k][j]; } final double[] Xrow = X.elements[j]; // multiply it with each row from A - for (int i = 0; i < B.elements.length; i++) { + for(int i = 0; i < B.elements.length; i++) { final double[] Browi = B.elements[i]; double s = 0; - for (int k = 0; k < B.columndimension; k++) { + for(int k = 0; k < B.columndimension; k++) { s += Browi[k] * Acolj[k]; } Xrow[i] = s; @@ -978,6 +1023,19 @@ public class Matrix { } /** + * Matrix inverse for square matrixes. + * + * @return inverse(A), or inverse(A + epsilon E) if singular. + */ + public final Matrix robustInverse() { + LUDecomposition d = new LUDecomposition(this); + if(!d.isNonsingular()) { + d = new LUDecomposition(plusDiagonal(SINGULARITY_CHEAT).getArrayRef(), elements.length, columndimension); + } + return d.solve(identity(elements.length, elements.length)); + } + + /** * Matrix determinant * * @return determinant @@ -1011,7 +1069,7 @@ public class Matrix { */ public final double trace() { double t = 0; - for (int i = 0; i < Math.min(elements.length, columndimension); i++) { + for(int i = 0; i < Math.min(elements.length, columndimension); i++) { t += elements[i][i]; } return t; @@ -1024,9 +1082,9 @@ public class Matrix { */ public final double norm1() { double f = 0; - for (int j = 0; j < columndimension; j++) { + for(int j = 0; j < columndimension; j++) { double s = 0; - for (int i = 0; i < elements.length; i++) { + for(int i = 0; i < elements.length; i++) { s += Math.abs(elements[i][j]); } f = Math.max(f, s); @@ -1050,9 +1108,9 @@ public class Matrix { */ public final double normInf() { double f = 0; - for (int i = 0; i < elements.length; i++) { + for(int i = 0; i < elements.length; i++) { double s = 0; - for (int j = 0; j < columndimension; j++) { + for(int j = 0; j < columndimension; j++) { s += Math.abs(elements[i][j]); } f = Math.max(f, s); @@ -1067,8 +1125,8 @@ public class Matrix { */ public final double normF() { double f = 0; - for (int i = 0; i < elements.length; i++) { - for (int j = 0; j < columndimension; j++) { + for(int i = 0; i < elements.length; i++) { + for(int j = 0; j < columndimension; j++) { f = MathUtil.fastHypot(f, elements[i][j]); } } @@ -1079,14 +1137,14 @@ public class Matrix { * Normalizes the columns of this matrix to length of 1.0. */ public final void normalizeColumns() { - for (int col = 0; col < columndimension; col++) { + for(int col = 0; col < columndimension; col++) { double norm = 0.0; - for (int row = 0; row < elements.length; row++) { + for(int row = 0; row < elements.length; row++) { norm = norm + (elements[row][col] * elements[row][col]); } norm = Math.sqrt(norm); - if (norm != 0) { - for (int row = 0; row < elements.length; row++) { + if(norm != 0) { + for(int row = 0; row < elements.length; row++) { elements[row][col] /= norm; } } @@ -1105,13 +1163,13 @@ public class Matrix { * columns of this matrix */ public final boolean linearlyIndependent(final Matrix columnMatrix) { - if (columnMatrix.columndimension != 1) { + if(columnMatrix.columndimension != 1) { throw new IllegalArgumentException("a.getColumnDimension() != 1"); } - if (this.elements.length != columnMatrix.elements.length) { + if(this.elements.length != columnMatrix.elements.length) { throw new IllegalArgumentException(ERR_MATRIX_DIMENSIONS); } - if (this.columndimension + columnMatrix.columndimension > this.elements.length) { + if(this.columndimension + columnMatrix.columndimension > this.elements.length) { return false; } final StringBuilder msg = LoggingConfiguration.DEBUG ? new StringBuilder() : null; @@ -1119,20 +1177,22 @@ public class Matrix { final double[][] a = new double[columndimension + 1][elements.length - 1]; final double[] b = new double[columndimension + 1]; - for (int i = 0; i < a.length; i++) { - for (int j = 0; j < a[i].length; j++) { - if (i < columndimension) { + for(int i = 0; i < a.length; i++) { + for(int j = 0; j < a[i].length; j++) { + if(i < columndimension) { a[i][j] = elements[j][i]; - } else { + } + else { a[i][j] = columnMatrix.elements[j][0]; } } } - for (int i = 0; i < b.length; i++) { - if (i < columndimension) { + for(int i = 0; i < b.length; i++) { + if(i < columndimension) { b[i] = elements[elements.length - 1][i]; - } else { + } + else { b[i] = columnMatrix.elements[i][0]; } } @@ -1143,7 +1203,7 @@ public class Matrix { final double[][] coefficients = les.getCoefficents(); final double[] rhs = les.getRHS(); - if (msg != null) { + if(msg != null) { msg.append("\na' ").append(FormatUtil.format(this.getArrayRef())); msg.append("\nb' ").append(FormatUtil.format(columnMatrix.getColumnPackedCopy())); @@ -1152,20 +1212,20 @@ public class Matrix { msg.append("\nleq ").append(les.equationsToString(4)); } - for (int i = 0; i < coefficients.length; i++) { + for(int i = 0; i < coefficients.length; i++) { boolean allCoefficientsZero = true; - for (int j = 0; j < coefficients[i].length; j++) { + for(int j = 0; j < coefficients[i].length; j++) { final double value = coefficients[i][j]; - if (Math.abs(value) > DELTA) { + if(Math.abs(value) > DELTA) { allCoefficientsZero = false; break; } } // allCoefficients=0 && rhs=0 -> linearly dependent - if (allCoefficientsZero) { + if(allCoefficientsZero) { final double value = rhs[i]; - if (Math.abs(value) < DELTA) { - if (msg != null) { + if(Math.abs(value) < DELTA) { + if(msg != null) { msg.append("\nvalue ").append(value).append('[').append(i).append(']'); msg.append("\nlinearly independent ").append(false); Logger.getLogger(this.getClass().getName()).fine(msg.toString()); @@ -1175,7 +1235,7 @@ public class Matrix { } } - if (msg != null) { + if(msg != null) { msg.append("\nlinearly independent ").append(true); Logger.getLogger(this.getClass().getName()).fine(msg.toString()); } @@ -1183,128 +1243,17 @@ public class Matrix { } /** - * Returns a matrix derived by Gauss-Jordan-elimination using RationalNumbers - * for the transformations. - * - * @return a matrix derived by Gauss-Jordan-elimination using RationalNumbers - * for the transformations - */ - public final Matrix exactGaussJordanElimination() { - final RationalNumber[][] gauss = exactGaussElimination(); - - // reduced form - for (int row = gauss.length - 1; row > 0; row--) { - int firstCol = -1; - for (int col = 0; col < gauss[row].length && firstCol == -1; col++) { - // if(gauss.get(row, col) != 0.0) // i.e. == 1 - if (gauss[row][col].equals(RationalNumber.ONE)) { - firstCol = col; - } - } - if (firstCol > -1) { - for (int currentRow = row - 1; currentRow >= 0; currentRow--) { - RationalNumber multiplier = gauss[currentRow][firstCol].copy(); - for (int col = firstCol; col < gauss[currentRow].length; col++) { - RationalNumber subtrahent = gauss[row][col].times(multiplier); - gauss[currentRow][col] = gauss[currentRow][col].minus(subtrahent); - } - } - } - } - return new Matrix(gauss); - } - - /** - * Perform an exact Gauss-elimination of this Matrix using RationalNumbers to - * yield highest possible accuracy. - * - * @return an array of arrays of RationalNumbers representing the - * Gauss-eliminated form of this Matrix - */ - private final RationalNumber[][] exactGaussElimination() { - final RationalNumber[][] gauss = new RationalNumber[elements.length][this.columndimension]; - for (int row = 0; row < elements.length; row++) { - for (int col = 0; col < this.columndimension; col++) { - gauss[row][col] = new RationalNumber(elements[row][col]); - } - } - return exactGaussElimination(gauss); - } - - /** - * Perform recursive Gauss-elimination on the given matrix of RationalNumbers. - * - * @param gauss an array of arrays of RationalNumber - * @return recursive derived Gauss-elimination-form of the given matrix of - * RationalNumbers - */ - private static final RationalNumber[][] exactGaussElimination(final RationalNumber[][] gauss) { - int firstCol = -1; - int firstRow = -1; - - // 1. find first column unequal to zero - for (int col = 0; col < gauss[0].length && firstCol == -1; col++) { - for (int row = 0; row < gauss.length && firstCol == -1; row++) { - // if(gauss.get(row, col) != 0.0) - if (!gauss[row][col].equals(RationalNumber.ZERO)) { - firstCol = col; - firstRow = row; - } - } - } - - // 2. set row as first row - if (firstCol != -1) { - if (firstRow != 0) { - final RationalNumber[] row = new RationalNumber[gauss[firstRow].length]; - System.arraycopy(gauss[firstRow], 0, row, 0, gauss[firstRow].length); - System.arraycopy(gauss[0], 0, gauss[firstRow], 0, gauss[firstRow].length); - System.arraycopy(row, 0, gauss[0], 0, row.length); - } - - // 3. create leading 1 - if (!gauss[0][firstCol].equals(RationalNumber.ONE)) { - final RationalNumber inverse = gauss[0][firstCol].multiplicativeInverse(); - for (int col = 0; col < gauss[0].length; col++) { - gauss[0][col] = gauss[0][col].times(inverse); - } - } - - // 4. eliminate values unequal to zero below leading 1 - for (int row = 1; row < gauss.length; row++) { - final RationalNumber multiplier = gauss[row][firstCol].copy(); - // if(multiplier != 0.0) - if (!multiplier.equals(RationalNumber.ZERO)) { - for (int col = firstCol; col < gauss[row].length; col++) { - final RationalNumber subtrahent = gauss[0][col].times(multiplier); - gauss[row][col] = gauss[row][col].minus(subtrahent); - } - } - } - - // 5. recursion - if (gauss.length > 1) { - final RationalNumber[][] subMatrix = new RationalNumber[gauss.length - 1][gauss[1].length]; - System.arraycopy(gauss, 1, subMatrix, 0, gauss.length - 1); - final RationalNumber[][] eliminatedSubMatrix = exactGaussElimination(subMatrix); - System.arraycopy(eliminatedSubMatrix, 0, gauss, 1, eliminatedSubMatrix.length); - } - } - return gauss; - } - - /** * Returns true, if this matrix is symmetric, false otherwise. * * @return true, if this matrix is symmetric, false otherwise */ public final boolean isSymmetric() { - if (elements.length != columndimension) { + if(elements.length != columndimension) { return false; } - for (int i = 0; i < elements.length; i++) { - for (int j = i + 1; j < columndimension; j++) { - if (elements[i][j] != elements[j][i]) { + for(int i = 0; i < elements.length; i++) { + for(int j = i + 1; j < columndimension; j++) { + if(elements[i][j] != elements[j][i]) { return false; } } @@ -1321,16 +1270,17 @@ public class Matrix { public final Matrix completeBasis() { Matrix basis = copy(); Matrix result = null; - for (int i = 0; i < elements.length; i++) { + for(int i = 0; i < elements.length; i++) { final Matrix e_i = new Matrix(elements.length, 1); e_i.elements[0][i] = 1.0; final boolean li = basis.linearlyIndependent(e_i); // TODO: efficiency - appendColumns is expensive. - if (li) { - if (result == null) { + if(li) { + if(result == null) { result = e_i.copy(); - } else { + } + else { result = result.appendColumns(e_i); } basis = basis.appendColumns(e_i); @@ -1348,16 +1298,17 @@ public class Matrix { public final Matrix completeToOrthonormalBasis() { Matrix basis = copy(); Matrix result = null; - for (int i = 0; i < elements.length; i++) { + for(int i = 0; i < elements.length; i++) { final Matrix e_i = new Matrix(elements.length, 1); e_i.elements[i][0] = 1.0; final boolean li = basis.linearlyIndependent(e_i); // TODO: efficiency - appendColumns is expensive. - if (li) { - if (result == null) { + if(li) { + if(result == null) { result = e_i.copy(); - } else { + } + else { result = result.appendColumns(e_i); } basis = basis.appendColumns(e_i); @@ -1374,16 +1325,17 @@ public class Matrix { * @return the new matrix with the appended columns */ public final Matrix appendColumns(final Matrix columns) { - if (elements.length != columns.elements.length) { + if(elements.length != columns.elements.length) { throw new IllegalArgumentException(ERR_MATRIX_DIMENSIONS); } final Matrix result = new Matrix(elements.length, columndimension + columns.columndimension); - for (int i = 0; i < result.columndimension; i++) { + for(int i = 0; i < result.columndimension; i++) { // FIXME: optimize - excess copying! - if (i < columndimension) { + if(i < columndimension) { result.setCol(i, getCol(i)); - } else { + } + else { result.setCol(i, columns.getCol(i - columndimension)); } } @@ -1399,10 +1351,10 @@ public class Matrix { Matrix v = copy(); // FIXME: optimize - excess copying! - for (int i = 1; i < columndimension; i++) { + for(int i = 1; i < columndimension; i++) { final Vector u_i = getCol(i); final Vector sum = new Vector(elements.length); - for (int j = 0; j < i; j++) { + for(int j = 0; j < i; j++) { final Vector v_j = v.getCol(j); double scalar = u_i.transposeTimes(v_j) / v_j.transposeTimes(v_j); sum.plusTimesEquals(v_j, scalar); @@ -1425,7 +1377,7 @@ public class Matrix { */ public final Matrix cheatToAvoidSingularity(final double constant) { final Matrix a = this.copy(); - for (int i = 0; i < a.columndimension && i < a.elements.length; i++) { + for(int i = 0; i < a.columndimension && i < a.elements.length; i++) { // if(a.get(i, i) < constant) { a.elements[i][i] += constant; @@ -1460,40 +1412,40 @@ public class Matrix { TDoubleArrayList v = new TDoubleArrayList(); // Ignore initial empty lines - while (tokenizer.nextToken() == StreamTokenizer.TT_EOL) { + while(tokenizer.nextToken() == StreamTokenizer.TT_EOL) { // ignore initial empty lines } - if (tokenizer.ttype == StreamTokenizer.TT_EOF) { + if(tokenizer.ttype == StreamTokenizer.TT_EOF) { throw new java.io.IOException("Unexpected EOF on matrix read."); } do { v.add(FormatUtil.parseDouble(tokenizer.sval)); // Read & store 1st // row. } - while (tokenizer.nextToken() == StreamTokenizer.TT_WORD); + while(tokenizer.nextToken() == StreamTokenizer.TT_WORD); int n = v.size(); // Now we've got the number of columns! double row[] = v.toArray(); ArrayList<double[]> rowV = new ArrayList<>(); rowV.add(row); // Start storing rows instead of columns. - while (tokenizer.nextToken() == StreamTokenizer.TT_WORD) { + while(tokenizer.nextToken() == StreamTokenizer.TT_WORD) { // While non-empty lines rowV.add(row = new double[n]); int j = 0; do { - if (j >= n) { + if(j >= n) { throw new java.io.IOException("Row " + v.size() + " is too long."); } row[j++] = FormatUtil.parseDouble(tokenizer.sval); } - while (tokenizer.nextToken() == StreamTokenizer.TT_WORD); - if (j < n) { + while(tokenizer.nextToken() == StreamTokenizer.TT_WORD); + if(j < n) { throw new java.io.IOException("Row " + v.size() + " is too short."); } } int m = rowV.size(); // Now we've got the number of rows. double[][] A = new double[m][]; - for (int i = 0; i < m; i++) { + for(int i = 0; i < m; i++) { A[i] = rowV.get(i); } return new Matrix(A); @@ -1503,7 +1455,7 @@ public class Matrix { * Check if size(A) == size(B) */ protected void checkMatrixDimensions(Matrix B) { - if (B.getRowDimensionality() != getRowDimensionality() || B.getColumnDimensionality() != getColumnDimensionality()) { + if(B.getRowDimensionality() != getRowDimensionality() || B.getColumnDimensionality() != getColumnDimensionality()) { throw new IllegalArgumentException("Matrix dimensions must agree."); } } @@ -1520,25 +1472,25 @@ public class Matrix { @Override public boolean equals(Object obj) { - if (this == obj) { + if(this == obj) { return true; } - if (obj == null) { + if(obj == null) { return false; } - if (getClass() != obj.getClass()) { + if(getClass() != obj.getClass()) { return false; } final Matrix other = (Matrix) obj; - if (this.elements.length != other.elements.length) { + if(this.elements.length != other.elements.length) { return false; } - if (this.columndimension != other.columndimension) { + if(this.columndimension != other.columndimension) { return false; } - for (int i = 0; i < this.elements.length; i++) { - for (int j = 0; j < this.columndimension; j++) { - if (this.elements[i][j] != other.elements[i][j]) { + for(int i = 0; i < this.elements.length; i++) { + for(int j = 0; j < this.columndimension; j++) { + if(this.elements[i][j] != other.elements[i][j]) { return false; } } @@ -1555,25 +1507,25 @@ public class Matrix { * @return true if delta smaller than maximum */ public boolean almostEquals(Object obj, double maxdelta) { - if (this == obj) { + if(this == obj) { return true; } - if (obj == null) { + if(obj == null) { return false; } - if (getClass() != obj.getClass()) { + if(getClass() != obj.getClass()) { return false; } final Matrix other = (Matrix) obj; - if (this.elements.length != other.elements.length) { + if(this.elements.length != other.elements.length) { return false; } - if (this.columndimension != other.columndimension) { + if(this.columndimension != other.columndimension) { return false; } - for (int i = 0; i < this.elements.length; i++) { - for (int j = 0; j < this.columndimension; j++) { - if (Math.abs(this.elements[i][j] - other.elements[i][j]) > maxdelta) { + for(int i = 0; i < this.elements.length; i++) { + for(int j = 0; j < this.columndimension; j++) { + if(Math.abs(this.elements[i][j] - other.elements[i][j]) > maxdelta) { return false; } } |