X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fmath%2FMatrix.java;h=b22bf4e1d27558fc09c6e59e64a45733f12d75cf;hb=187269da0130408d24901c88acb10c217f6284f9;hp=0f93eb5a4a3d4f1bba87115983fcc530c2d532cd;hpb=ab7ccf4373a27d71bca31bd6356c1390d9a0054c;p=jalview.git diff --git a/src/jalview/math/Matrix.java b/src/jalview/math/Matrix.java index 0f93eb5..b22bf4e 100755 --- a/src/jalview/math/Matrix.java +++ b/src/jalview/math/Matrix.java @@ -24,53 +24,53 @@ import jalview.util.Format; import jalview.util.MessageManager; import java.io.PrintStream; +import java.util.Arrays; /** - * DOCUMENT ME! - * - * @author $author$ - * @version $Revision$ + * A class to model rectangular matrices of double values and operations on them */ public class Matrix implements MatrixI { /* - * the [row][column] values in the matrix + * maximum number of iterations for tqli */ - private double[][] value; + private static final int MAX_ITER = 45; + // fudge - add 15 iterations, just in case /* * the number of rows */ - protected int rows; + final protected int rows; /* * the number of columns */ - protected int cols; + final protected int cols; + + /* + * the cell values in row-major order + */ + private double[][] value; - /** DOCUMENT ME!! */ protected double[] d; // Diagonal - /** DOCUMENT ME!! */ protected double[] e; // off diagonal /** - * maximum number of iterations for tqli + * Constructor given number of rows and columns * + * @param colCount + * @param rowCount */ - private static final int maxIter = 45; // fudge - add 15 iterations, just in - // case - - /** - * Default constructor - */ - public Matrix() + protected Matrix(int rowCount, int colCount) { - + rows = rowCount; + cols = colCount; } - + /** - * Creates a new Matrix object. For example + * Creates a new Matrix object containing a copy of the supplied array values. + * For example * *
    *   new Matrix(new double[][] {{2, 3, 4}, {5, 6, 7})
@@ -89,18 +89,24 @@ public class Matrix implements MatrixI
   public Matrix(double[][] values)
   {
     this.rows = values.length;
-    if (rows > 0)
+    this.cols = this.rows == 0 ? 0 : values[0].length;
+
+    /*
+     * make a copy of the values array, for immutability
+     */
+    this.value = new double[rows][];
+    int i = 0;
+    for (double[] row : values)
     {
-      this.cols = values[0].length;
+      if (row != null)
+      {
+        value[i] = new double[row.length];
+        System.arraycopy(row, 0, value[i], 0, row.length);
+      }
+      i++;
     }
-    this.value = values;
   }
 
-  /**
-   * Returns a new matrix which is the transpose of this one
-   * 
-   * @return DOCUMENT ME!
-   */
   @Override
   public MatrixI transpose()
   {
@@ -138,18 +144,6 @@ public class Matrix implements MatrixI
     }
   }
 
-  /**
-   * Returns a new matrix which is the result of premultiplying this matrix by
-   * the supplied argument. If this of size AxB (A rows and B columns), and the
-   * argument is CxA (C rows and A columns), the result is of size CxB.
-   * 
-   * @param in
-   * 
-   * @return
-   * @throws IllegalArgumentException
-   *           if the number of columns in the pre-multiplier is not equal to
-   *           the number of rows in the multiplicand (this)
-   */
   @Override
   public MatrixI preMultiply(MatrixI in)
   {
@@ -201,21 +195,6 @@ public class Matrix implements MatrixI
     return out;
   }
 
-  /**
-   * Returns a new matrix which is the result of postmultiplying this matrix by
-   * the supplied argument. If this of size AxB (A rows and B columns), and the
-   * argument is BxC (B rows and C columns), the result is of size AxC.
-   * 

- * This method simply returns the result of in.preMultiply(this) - * - * @param in - * - * @return - * @throws IllegalArgumentException - * if the number of rows in the post-multiplier is not equal to the - * number of columns in the multiplicand (this) - * @see #preMultiply(Matrix) - */ @Override public MatrixI postMultiply(MatrixI in) { @@ -227,11 +206,6 @@ public class Matrix implements MatrixI return in.preMultiply(this); } - /** - * Answers a new matrix with a copy of the values in this one - * - * @return - */ @Override public MatrixI copy() { @@ -242,7 +216,17 @@ public class Matrix implements MatrixI System.arraycopy(value[i], 0, newmat[i], 0, value[i].length); } - return new Matrix(newmat); + Matrix m = new Matrix(newmat); + if (this.d != null) + { + m.d = Arrays.copyOf(this.d, this.d.length); + } + if (this.e != null) + { + m.e = Arrays.copyOf(this.e, this.e.length); + } + + return m; } /** @@ -275,27 +259,22 @@ public class Matrix implements MatrixI { for (k = 1; k <= l; k++) { - // double v = Math.abs(value[i - 1][k - 1]); double v = Math.abs(getValue(i - 1, k - 1)); scale += v; } if (scale == 0.0) { - // e[i - 1] = value[i - 1][l - 1]; e[i - 1] = getValue(i - 1, l - 1); } else { for (k = 1; k <= l; k++) { - // value[i - 1][k - 1] /= scale; - // h += (value[i - 1][k - 1] * value[i - 1][k - 1]); double v = divideValue(i - 1, k - 1, scale); h += v * v; } - // f = value[i - 1][l - 1]; f = getValue(i - 1, l - 1); if (f > 0) @@ -309,34 +288,26 @@ public class Matrix implements MatrixI e[i - 1] = scale * g; h -= (f * g); - // value[i - 1][l - 1] = f - g; setValue(i - 1, l - 1, f - g); - // System.out.println(String.format("%d %d %f %f %f %f %f %.5e", i, - // l, - // scale, f, g, h, getValue(i - 1, l - 1), checksum())); f = 0.0; for (j = 1; j <= l; j++) { - // value[j - 1][i - 1] = value[i - 1][j - 1] / h; double val = getValue(i - 1, j - 1) / h; setValue(j - 1, i - 1, val); g = 0.0; for (k = 1; k <= j; k++) { - // g += (value[j - 1][k - 1] * value[i - 1][k - 1]); g += (getValue(j - 1, k - 1) * getValue(i - 1, k - 1)); } for (k = j + 1; k <= l; k++) { - // g += (value[k - 1][j - 1] * value[i - 1][k - 1]); g += (getValue(k - 1, j - 1) * getValue(i - 1, k - 1)); } e[j - 1] = g / h; - // f += (e[j - 1] * value[i - 1][j - 1]); f += (e[j - 1] * getValue(i - 1, j - 1)); } @@ -344,15 +315,12 @@ public class Matrix implements MatrixI for (j = 1; j <= l; j++) { - // f = value[i - 1][j - 1]; f = getValue(i - 1, j - 1); g = e[j - 1] - (hh * f); e[j - 1] = g; for (k = 1; k <= j; k++) { - // value[j - 1][k - 1] -= ((f * e[k - 1]) + (g * value[i - 1][k - - // 1])); double val = (f * e[k - 1]) + (g * getValue(i - 1, k - 1)); addValue(j - 1, k - 1, -val); } @@ -361,7 +329,6 @@ public class Matrix implements MatrixI } else { - // e[i - 1] = value[i - 1][l - 1]; e[i - 1] = getValue(i - 1, l - 1); } @@ -383,27 +350,21 @@ public class Matrix implements MatrixI for (k = 1; k <= l; k++) { - // g += (value[i - 1][k - 1] * value[k - 1][j - 1]); g += (getValue(i - 1, k - 1) * getValue(k - 1, j - 1)); } for (k = 1; k <= l; k++) { - // value[k - 1][j - 1] -= (g * value[k - 1][i - 1]); addValue(k - 1, j - 1, -(g * getValue(k - 1, i - 1))); } } } - // d[i - 1] = value[i - 1][i - 1]; - // value[i - 1][i - 1] = 1.0; d[i - 1] = getValue(i - 1, i - 1); setValue(i - 1, i - 1, 1.0); for (j = 1; j <= l; j++) { - // value[j - 1][i - 1] = 0.0; - // value[i - 1][j - 1] = 0.0; setValue(j - 1, i - 1, 0.0); setValue(i - 1, j - 1, 0.0); } @@ -495,11 +456,11 @@ public class Matrix implements MatrixI { iter++; - if (iter == maxIter) + if (iter == MAX_ITER) { throw new Exception(MessageManager.formatMessage( - "exception.matrix_too_many_iteration", new String[] { - "tqli", Integer.valueOf(maxIter).toString() })); + "exception.matrix_too_many_iteration", new String[] + { "tqli", Integer.valueOf(MAX_ITER).toString() })); } else { @@ -543,12 +504,10 @@ public class Matrix implements MatrixI for (k = 1; k <= n; k++) { - // f = value[k - 1][i]; - // value[k - 1][i] = (s * value[k - 1][i - 1]) + (c * f); - // value[k - 1][i - 1] = (c * value[k - 1][i - 1]) - (s * f); f = getValue(k - 1, i); setValue(k - 1, i, (s * getValue(k - 1, i - 1)) + (c * f)); - setValue(k - 1, i - 1, (c * getValue(k - 1, i - 1)) - (s * f)); + setValue(k - 1, i - 1, + (c * getValue(k - 1, i - 1)) - (s * f)); } } @@ -566,6 +525,7 @@ public class Matrix implements MatrixI return value[i][j]; } + @Override public void setValue(int i, int j, double val) { value[i][j] = val; @@ -760,11 +720,11 @@ public class Matrix implements MatrixI { iter++; - if (iter == maxIter) + if (iter == MAX_ITER) { throw new Exception(MessageManager.formatMessage( - "exception.matrix_too_many_iteration", new String[] { - "tqli2", Integer.valueOf(maxIter).toString() })); + "exception.matrix_too_many_iteration", new String[] + { "tqli2", Integer.valueOf(MAX_ITER).toString() })); } else { @@ -882,7 +842,8 @@ public class Matrix implements MatrixI * * @param ps * DOCUMENT ME! - * @param format TODO + * @param format + * TODO */ @Override public void printE(PrintStream ps, String format) @@ -904,9 +865,10 @@ public class Matrix implements MatrixI { return e; } - + @Override - public int height() { + public int height() + { return rows; } @@ -923,4 +885,141 @@ public class Matrix implements MatrixI System.arraycopy(value[i], 0, row, 0, cols); return row; } + + /** + * Returns a length 2 array of {minValue, maxValue} of all values in the + * matrix. Returns null if the matrix is null or empty. + * + * @return + */ + double[] findMinMax() + { + if (value == null) + { + return null; + } + double min = Double.MAX_VALUE; + double max = -Double.MAX_VALUE; + boolean empty = true; + for (double[] row : value) + { + if (row != null) + { + for (double x : row) + { + empty = false; + if (x > max) + { + max = x; + } + if (x < min) + { + min = x; + } + } + } + } + return empty ? null : new double[] { min, max }; + } + + /** + * {@inheritDoc} + */ + @Override + public void reverseRange(boolean maxToZero) + { + if (value == null) + { + return; + } + double[] minMax = findMinMax(); + if (minMax == null) + { + return; // empty matrix + } + double subtractFrom = maxToZero ? minMax[1] : minMax[0] + minMax[1]; + + for (double[] row : value) + { + if (row != null) + { + int j = 0; + for (double x : row) + { + row[j] = subtractFrom - x; + j++; + } + } + } + } + + /** + * Multiplies every entry in the matrix by the given value. + * + * @param + */ + @Override + public void multiply(double by) + { + for (double[] row : value) + { + if (row != null) + { + for (int i = 0; i < row.length; i++) + { + row[i] *= by; + } + } + } + } + + @Override + public void setD(double[] v) + { + d = v; + } + + @Override + public void setE(double[] v) + { + e = v; + } + + public double getTotal() + { + double d = 0d; + for (int i = 0; i < this.height(); i++) + { + for (int j = 0; j < this.width(); j++) + { + d += value[i][j]; + } + } + return d; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(MatrixI m2, double delta) + { + if (m2 == null || this.height() != m2.height() + || this.width() != m2.width()) + { + return false; + } + for (int i = 0; i < this.height(); i++) + { + for (int j = 0; j < this.width(); j++) + { + double diff = this.getValue(i, j) - m2.getValue(i, j); + if (Math.abs(diff) > delta) + { + return false; + } + } + } + return true; + } }