All Downloads are FREE. Search and download functionalities are using the official Maven repository.

javajs.util.Matrix Maven / Gradle / Ivy

There is a newer version: 14.31.10
Show newest version
package javajs.util;

/**
 * 
 * streamlined and refined for Jmol by Bob Hanson
 * 
 * from http://math.nist.gov/javanumerics/jama/
 * 
 * Jama = Java Matrix class.
 * 
 * @author The MathWorks, Inc. and the National Institute of Standards and
 *         Technology.
 * @version 5 August 1998
 */

public class Matrix implements Cloneable {

  public double[][] a;
  protected int m, n;

  /**
   * Construct a matrix quickly without checking arguments.
   * 
   * @param a
   *        Two-dimensional array of doubles or null
   * @param m
   *        Number of rows.
   * @param n
   *        Number of colums.
   */

  public Matrix(double[][] a, int m, int n) {
    this.a = (a == null ? new double[m][n] : a);
    this.m = m;
    this.n = n;
  }

  /**
   * Get row dimension.
   * 
   * @return m, the number of rows.
   */

  public int getRowDimension() {
    return m;
  }

  /**
   * Get column dimension.
   * 
   * @return n, the number of columns.
   */

  public int getColumnDimension() {
    return n;
  }

  /**
   * Access the internal two-dimensional array.
   * 
   * @return Pointer to the two-dimensional array of matrix elements.
   */

  public double[][] getArray() {
    return a;
  }

  /**
   * Copy the internal two-dimensional array.
   * 
   * @return Two-dimensional array copy of matrix elements.
   */

  public double[][] getArrayCopy() {
    double[][] x = new double[m][n];
    for (int i = m; --i >= 0;)
      for (int j = n; --j >= 0;)
        x[i][j] = a[i][j];
    return x;
  }

  /**
   * Make a deep copy of a matrix
   * 
   * @return copy
   */

  public Matrix copy() {
    Matrix x = new Matrix(null, m, n);
    double[][] c = x.a;
    for (int i = m; --i >= 0;)
      for (int j = n; --j >= 0;)
        c[i][j] = a[i][j];
    return x;
  }

  /**
   * Clone the Matrix object.
   */

  @Override
  public Object clone() {
    return copy();
  }

  /**
   * Get a submatrix.
   * 
   * @param i0
   *        Initial row index
   * @param j0
   *        Initial column index
   * @param nrows
   *        Number of rows
   * @param ncols
   *        Number of columns
   * @return submatrix
   * 
   */

  public Matrix getSubmatrix(int i0, int j0, int nrows, int ncols) {
    Matrix x = new Matrix(null, nrows, ncols);
    double[][] xa = x.a;
    for (int i = nrows; --i >= 0;)
      for (int j = ncols; --j >= 0;)
        xa[i][j] = a[i0 + i][j0 + j];
    return x;
  }

  /**
   * Get a submatrix for a give number of columns and selected row set.
   * 
   * @param r
   *        Array of row indices.
   * @param n
   *        number of rows 
   * @return submatrix
   */

  public Matrix getMatrixSelected(int[] r, int n) {
    Matrix x = new Matrix(null, r.length, n);
    double[][] xa = x.a;
    for (int i = r.length; --i >= 0;) {
      double[] b = a[r[i]];
      for (int j = n; --j >= 0;)
        xa[i][j] = b[j];
    }
    return x;
  }

  /**
   * Matrix transpose.
   * 
   * @return A'
   */

  public Matrix transpose() {
    Matrix x = new Matrix(null, n, m);
    double[][] c = x.a;
    for (int i = m; --i >= 0;)
      for (int j = n; --j >= 0;)
        c[j][i] = a[i][j];
    return x;
  }

  /**
   * add two matrices
   * @param b
   * @return new Matrix this + b
   */
  public Matrix add(Matrix b) {
    return scaleAdd(b, 1);
  }

  /**
   * subtract two matrices
   * @param b
   * @return new Matrix this - b
   */
  public Matrix sub(Matrix b) {
    return scaleAdd(b, -1);
  }
  
  /**
   * X = A + B*scale
   * @param b 
   * @param scale 
   * @return X
   * 
   */
  public Matrix scaleAdd(Matrix b, double scale) {
    Matrix x = new Matrix(null, m, n);
    double[][] xa = x.a;
    double[][] ba = b.a;
    for (int i = m; --i >= 0;)
      for (int j = n; --j >= 0;)
        xa[i][j] = ba[i][j] * scale + a[i][j];
    return x;
  }

  /**
   * Linear algebraic matrix multiplication, A * B
   * 
   * @param b
   *        another matrix
   * @return Matrix product, A * B or null for wrong dimension
   */

  public Matrix mul(Matrix b) {
    if (b.m != n)
      return null;
    Matrix x = new Matrix(null, m, b.n);
    double[][] xa = x.a;
    double[][] ba = b.a;
    for (int j = b.n; --j >= 0;)
      for (int i = m; --i >= 0;) {
        double[] arowi = a[i];
        double s = 0;
        for (int k = n; --k >= 0;)
          s += arowi[k] * ba[k][j];
        xa[i][j] = s;
      }
    return x;
  }

  /**
   * Matrix inverse or pseudoinverse
   * 
   * @return inverse (m == n) or pseudoinverse (m != n)
   */

  public Matrix inverse() {
    return new LUDecomp(m, n).solve(identity(m, m), n);
  }

  /**
   * Matrix trace.
   * 
   * @return sum of the diagonal elements.
   */

  public double trace() {
    double t = 0;
    for (int i = Math.min(m, n); --i >= 0;)
      t += a[i][i];
    return t;
  }

  /**
   * Generate identity matrix
   * 
   * @param m
   *        Number of rows.
   * @param n
   *        Number of columns.
   * @return An m-by-n matrix with ones on the diagonal and zeros elsewhere.
   */

  public static Matrix identity(int m, int n) {
    Matrix x = new Matrix(null, m, n);
    double[][] xa = x.a;
    for (int i = Math.min(m, n); --i >= 0;)
      xa[i][i] = 1;
    return x;
  }

  /**
   * similarly to M3/M4 standard rotation/translation matrix
   * we set a rotationTranslation matrix to be:
   * 
   * [   nxn rot    nx1 trans
   * 
   *     1xn  0     1x1 1      ]
   * 
   * 
   * @return rotation matrix
   */
  public Matrix getRotation() {
    return getSubmatrix(0, 0, m - 1, n - 1);
  }

  public Matrix getTranslation() {
    return getSubmatrix(0, n - 1, m - 1, 1);
  }

  public static Matrix newT(T3 r, boolean asColumn) {
    return (asColumn ? new Matrix(new double[][] { new double[] { r.x },
        new double[] { r.y }, new double[] { r.z } }, 3, 1) : new Matrix(
        new double[][] { new double[] { r.x, r.y, r.z } }, 1, 3));
  }

  @Override
  public String toString() {
    String s = "[\n";
    for (int i = 0; i < m; i++) {
      s += "  [";
      for (int j = 0; j < n; j++)
        s += " " + a[i][j];
      s += "]\n";
    }
    s += "]";
    return s;
  }

  /**
   * 
   * Edited down by Bob Hanson for minimum needed by Jmol -- just constructor
   * and solve
   * 
   * LU Decomposition.
   * 

* For an m-by-n matrix A with m >= n, the LU decomposition is an m-by-n unit * lower triangular matrix L, an n-by-n upper triangular matrix U, and a * permutation vector piv of length m so that A(piv,:) = L*U. If m < n, then L * is m-by-m and U is m-by-n. *

* The LU decompostion with pivoting always exists, even if the matrix is * singular, so the constructor will never fail. The primary use of the LU * decomposition is in the solution of square systems of simultaneous linear * equations. This will fail if isNonsingular() returns false. */ private class LUDecomp { /* ------------------------ Class variables * ------------------------ */ /** * Array for internal storage of decomposition. * */ private double[][] LU; /** * Internal storage of pivot vector. * */ private int[] piv; private int pivsign; /* ------------------------ Constructor * ------------------------ */ /** * LU Decomposition Structure to access L, U and piv. * @param m * @param n * */ protected LUDecomp(int m, int n) { // Use a "left-looking", dot-product, Crout/Doolittle algorithm. LU = getArrayCopy(); piv = new int[m]; for (int i = m; --i >= 0;) piv[i] = i; pivsign = 1; double[] LUrowi; double[] LUcolj = new double[m]; // Outer loop. for (int j = 0; j < n; j++) { // Make a copy of the j-th column to localize references. for (int i = m; --i >= 0;) LUcolj[i] = LU[i][j]; // Apply previous transformations. for (int i = m; --i >= 0;) { LUrowi = LU[i]; // Most of the time is spent in the following dot product. int kmax = Math.min(i, j); double s = 0.0; for (int k = kmax; --k >= 0;) s += LUrowi[k] * LUcolj[k]; LUrowi[j] = LUcolj[i] -= s; } // Find pivot and exchange if necessary. int p = j; for (int i = m; --i > j;) if (Math.abs(LUcolj[i]) > Math.abs(LUcolj[p])) p = i; if (p != j) { for (int k = n; --k >= 0;) { double t = LU[p][k]; LU[p][k] = LU[j][k]; LU[j][k] = t; } int k = piv[p]; piv[p] = piv[j]; piv[j] = k; pivsign = -pivsign; } // Compute multipliers. if (j < m & LU[j][j] != 0.0) for (int i = m; --i > j;) LU[i][j] /= LU[j][j]; } } /* ------------------------ default Methods * ------------------------ */ /** * Solve A*X = B * * @param b * A Matrix with as many rows as A and any number of columns. * @param n * @return X so that L*U*X = B(piv,:) or null for wrong size or singular matrix */ protected Matrix solve(Matrix b, int n) { for (int j = 0; j < n; j++) if (LU[j][j] == 0) return null; // matrix is singular // Copy right hand side with pivoting int nx = b.n; Matrix x = b.getMatrixSelected(piv, nx); double[][] a = x.a; // Solve L*Y = B(piv,:) for (int k = 0; k < n; k++) for (int i = k + 1; i < n; i++) for (int j = 0; j < nx; j++) a[i][j] -= a[k][j] * LU[i][k]; // Solve U*X = Y; for (int k = n; --k >= 0;) { for (int j = nx; --j >= 0;) a[k][j] /= LU[k][k]; for (int i = k; --i >= 0;) for (int j = nx; --j >= 0;) a[i][j] -= a[k][j] * LU[i][k]; } return x; } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy