//
// JamaMatrix.java
//

/*
VisAD system for interactive analysis and visualization of numerical
data.  Copyright (C) 1996 - 2017 Bill Hibbard, Curtis Rueden, Tom
Rink, Dave Glowacki, Steve Emmerson, Tom Whittaker, Don Murray, and
Tommy Jasmin.

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Library General Public License for more details.

You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
MA 02111-1307, USA
*/

package visad.matrix;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.rmi.RemoteException;
import java.text.NumberFormat;

import visad.CoordinateSystem;
import visad.FlatField;
import visad.FunctionType;
import visad.Gridded1DSet;
import visad.Gridded2DSet;
import visad.GriddedSet;
import visad.Integer2DSet;
import visad.RealTupleType;
import visad.RealType;
import visad.Set;
import visad.SetType;
import visad.TupleType;
import visad.Unit;
import visad.VisADException;

/**
 * JamaMatrix is a VisAD wrapper for JAMA matrices. This class requires the
 * JAMA package.
 */
public class JamaMatrix extends FlatField {

  private static final RealType matrix_row =
    RealType.getRealType("matrix_row");

  private static final RealType matrix_column =
    RealType.getRealType("matrix_column");

  private static final RealType matrix_value =
    RealType.getRealType("matrix_value");

  private static final FunctionType matrixType = constructFunction();

  private static FunctionType constructFunction() {
    try {
      RealTupleType tuple = new RealTupleType(matrix_row, matrix_column);
      FunctionType function = new FunctionType(tuple, matrix_value);
      return function;
    }
    catch (VisADException exc) {
      exc.printStackTrace();
      return null;
    }
  }

  private static final Class[] classes = constructClasses();

  private static Class[] constructClasses() {
    Class[] cs = new Class[6];
    try {
      cs[0] = Class.forName("Jama.Matrix");
      cs[1] = Class.forName("Jama.CholeskyDecomposition");
      cs[2] = Class.forName("Jama.EigenvalueDecomposition");
      cs[3] = Class.forName("Jama.LUDecomposition");
      cs[4] = Class.forName("Jama.QRDecomposition");
      cs[5] = Class.forName("Jama.SingularValueDecomposition");
    }
    catch (ClassNotFoundException e) {
      throw new RuntimeException("you need to install Jama from " +
                                 "http://math.nist.gov/javanumerics/jama/");
    }
    return cs;
  }

  private static final Class classMatrix = classes[0];
  private static final Class classCholeskyDecomposition = classes[1];
  private static final Class classEigenvalueDecomposition = classes[2];
  private static final Class classLUDecomposition = classes[3];
  private static final Class classQRDecomposition = classes[4];
  private static final Class classSingularValueDecomposition = classes[5];

  private static Class constructMatrixClass() {
    try {
      Class c = Class.forName("Jama.Matrix");
      return c;
    }
    catch (ClassNotFoundException e) {
      throw new RuntimeException("you need to install Jama from " +
                                 "http://math.nist.gov/javanumerics/jama/");
    }
  }

  /** This matrix's associated JAMA Matrix object */
  private Object matrix;

  /** useful methods from Jama.Matrix class */
  private static final Method[] methods =
    constructMethods();

  private static Method[] constructMethods() {
    Method[] ms = new Method[51];
    try {
      Class[] param = new Class[] {};
      ms[0] = classMatrix.getMethod("getColumnDimension", param);
      ms[1] = classMatrix.getMethod("getRowDimension", param);
      ms[2] = classMatrix.getMethod("getArray", param);
      param = new Class[] {int.class, int.class};
      ms[3] = classMatrix.getMethod("get", param);
      param = new Class[] {int.class, int.class, int.class, int.class};
      ms[4] = classMatrix.getMethod("getMatrix", param);
      param = new Class[] {int[].class, int[].class};
      ms[5] = classMatrix.getMethod("getMatrix", param);
      param = new Class[] {int.class, int.class, int[].class};
      ms[6] = classMatrix.getMethod("getMatrix", param);
      param = new Class[] {int[].class, int.class, int.class};
      ms[7] = classMatrix.getMethod("getMatrix", param);
      param = new Class[] {int.class, int.class, double.class};
      ms[8] = classMatrix.getMethod("set", param);
      param = new Class[] {int.class, int.class, int.class, int.class,
                           classMatrix};
      ms[9] = classMatrix.getMethod("setMatrix", param);
      param = new Class[] {int[].class, int[].class, classMatrix};
      ms[10] = classMatrix.getMethod("setMatrix", param);
      param = new Class[] {int.class, int.class, int[].class, classMatrix};
      ms[11] = classMatrix.getMethod("setMatrix", param);
      param = new Class[] {int[].class, int.class, int.class, classMatrix};
      ms[12] = classMatrix.getMethod("setMatrix", param);
      param = new Class[] {};
      ms[13] = classMatrix.getMethod("transpose", param);
      ms[14] = classMatrix.getMethod("norm1", param);
      ms[15] = classMatrix.getMethod("norm2", param);
      ms[16] = classMatrix.getMethod("normInf", param);
      ms[17] = classMatrix.getMethod("normF", param);
      ms[18] = classMatrix.getMethod("uminus", param);
      param = new Class[] {classMatrix};
      ms[19] = classMatrix.getMethod("plus", param);
      ms[20] = classMatrix.getMethod("plusEquals", param);
      ms[21] = classMatrix.getMethod("minus", param);
      ms[22] = classMatrix.getMethod("minusEquals", param);
      ms[23] = classMatrix.getMethod("arrayTimes", param);
      ms[24] = classMatrix.getMethod("arrayTimesEquals", param);
      ms[25] = classMatrix.getMethod("arrayRightDivide", param);
      ms[26] = classMatrix.getMethod("arrayRightDivideEquals", param);
      ms[27] = classMatrix.getMethod("arrayLeftDivide", param);
      ms[28] = classMatrix.getMethod("arrayLeftDivideEquals", param);
      param = new Class[] {double.class};
      ms[29] = classMatrix.getMethod("times", param);
      ms[30] = classMatrix.getMethod("timesEquals", param);
      param = new Class[] {classMatrix};
      ms[31] = classMatrix.getMethod("times", param);
      ms[32] = classMatrix.getMethod("solve", param);
      ms[33] = classMatrix.getMethod("solveTranspose", param);
      param = new Class[] {};
      ms[34] = classMatrix.getMethod("inverse", param);
      ms[35] = classMatrix.getMethod("det", param);
      ms[36] = classMatrix.getMethod("rank", param);
      ms[37] = classMatrix.getMethod("cond", param);
      ms[38] = classMatrix.getMethod("trace", param);
      param = new Class[] {int.class, int.class};
      ms[39] = classMatrix.getMethod("random", param);
      ms[40] = classMatrix.getMethod("identity", param);
      ms[41] = classMatrix.getMethod("print", param);
      param = new Class[] {PrintWriter.class, int.class, int.class};
      ms[42] = classMatrix.getMethod("print", param);
      param = new Class[] {NumberFormat.class, int.class};
      ms[43] = classMatrix.getMethod("print", param);
      param = new Class[] {PrintWriter.class, NumberFormat.class, int.class};
      ms[44] = classMatrix.getMethod("print", param);
      param = new Class[] {BufferedReader.class};
      ms[45] = classMatrix.getMethod("read", param);
      param = new Class[] {};
      ms[46] = classMatrix.getMethod("chol", param);
      ms[47] = classMatrix.getMethod("eig", param);
      ms[48] = classMatrix.getMethod("lu", param);
      ms[49] = classMatrix.getMethod("qr", param);
      ms[50] = classMatrix.getMethod("svd", param);
    }
    catch (NoSuchMethodException e) {
      e.printStackTrace();
    }
    return ms;
  }

  private static final Method getColumnDimension = methods[0];
  private static final Method getRowDimension = methods[1];
  private static final Method getArray = methods[2];
  private static final Method get = methods[3];
  private static final Method getMatrix1 = methods[4];
  private static final Method getMatrix2 = methods[5];
  private static final Method getMatrix3 = methods[6];
  private static final Method getMatrix4 = methods[7];
  private static final Method set = methods[8];
  private static final Method setMatrix1 = methods[9];
  private static final Method setMatrix2 = methods[10];
  private static final Method setMatrix3 = methods[11];
  private static final Method setMatrix4 = methods[12];
  private static final Method transpose = methods[13];
  private static final Method norm1 = methods[14];
  private static final Method norm2 = methods[15];
  private static final Method normInf = methods[16];
  private static final Method normF = methods[17];
  private static final Method uminus = methods[18];
  private static final Method plus = methods[19];
  private static final Method plusEquals = methods[20];
  private static final Method minus = methods[21];
  private static final Method minusEquals = methods[22];
  private static final Method arrayTimes = methods[23];
  private static final Method arrayTimesEquals = methods[24];
  private static final Method arrayRightDivide = methods[25];
  private static final Method arrayRightDivideEquals = methods[26];
  private static final Method arrayLeftDivide = methods[27];
  private static final Method arrayLeftDivideEquals = methods[28];
  private static final Method times1 = methods[29];
  private static final Method timesEquals = methods[30];
  private static final Method times2 = methods[31];
  private static final Method solve = methods[32];
  private static final Method solveTranspose = methods[33];
  private static final Method inverse = methods[34];
  private static final Method det = methods[35];
  private static final Method rank = methods[36];
  private static final Method cond = methods[37];
  private static final Method trace = methods[38];
  private static final Method random = methods[39];
  private static final Method identity = methods[40];
  private static final Method print1 = methods[41];
  private static final Method print2 = methods[42];
  private static final Method print3 = methods[43];
  private static final Method print4 = methods[44];
  private static final Method read = methods[45];
  private static final Method chol = methods[46];
  private static final Method eig = methods[47];
  private static final Method lu = methods[48];
  private static final Method qr = methods[49];
  private static final Method svd = methods[50];

  /** constructors from Jama.Matrix class */
  private static final Constructor[] constructors =
    constructConstructors();

  private static Constructor[] constructConstructors() {
    Constructor[] cs = new Constructor[2];
    try {
      Class[] param = new Class[] {int.class, int.class};
      cs[0] = classMatrix.getConstructor(param);
      param = new Class[] {double[][].class};
      cs[1] = classMatrix.getConstructor(param);
    }
    catch (NoSuchMethodException e) {
      e.printStackTrace();
    }
    return cs;
  }

  private static final Constructor intintMatrix = constructors[0];
  private static final Constructor doubleMatrix = constructors[1];

  // Static methods

  /**
   * Attempt to convert the given VisAD FlatField to a VisAD JamaMatrix
   * Data object.
   * @return The converted object, or null if it could not be converted
   */
  public static JamaMatrix convertToMatrix(FlatField field)
         throws VisADException, IllegalAccessException,
                InstantiationException, InvocationTargetException {
    if (classMatrix == null) {
      throw new VisADException("you need to install Jama from " +
                               "http://math.nist.gov/javanumerics/jama/");
    }

    // if field is already a JamaMatrix the task is trivial
    if (field instanceof JamaMatrix) return (JamaMatrix) field;

    FunctionType ftype = (FunctionType) field.getType();

    // get domain set (must be 2-D ordered samples)
    Set set = field.getDomainSet();
    Gridded2DSet grid = null;
    if (set instanceof Gridded2DSet) {
      grid = (Gridded2DSet) set;
    }
    else if (set instanceof GriddedSet &&
             set.getDimension() == 2) {
      int[] lengths = ((GriddedSet) set).getLengths();
      float[][] samples = set.getSamples(false);
      grid = new Gridded2DSet(set.getType(), samples, lengths[0],
                              lengths[1], set.getCoordinateSystem(),
                              set.getSetUnits(), set.getSetErrors());
    }
    else if (set instanceof Gridded1DSet) {
      int[] lengths = ((Gridded1DSet) set).getLengths();
      float[][] samples = set.getSamples(false);
      float[] dummies = new float[lengths[0]];
      for (int i=0; i z)");
    }
    setMatrix(matrix);
  }

  // place for JamaCholeskyDecomposition, etc to store their
  // CholeskyDecomposition during construction
  private Object stash = null;

  void setStash(Object s) {
    stash = s;
  }

  Object getStash() {
    return stash;
  }

  // New methods

  /**
   * Return the associated JAMA Matrix object.
   */
  public Object getMatrix() {
    return matrix;
  }

  /**
   * Set this matrix's samples to correspond to those of the given
   * JAMA Matrix.
   */
  public void setMatrix(Object matrix)
         throws VisADException, IllegalAccessException,
                InstantiationException, InvocationTargetException {
    if (classMatrix == null) {
      throw new VisADException("you need to install Jama from " +
                               "http://math.nist.gov/javanumerics/jama/");
    }
    if (!classMatrix.isInstance(matrix)) {
      throw new VisADException("matrix must be an instance of Jama.Matrix");
    }
    // convert matrix entries into range sample values
    int rows = ((Integer)
      getRowDimension.invoke(matrix, new Object[] {})).intValue();
    int cols = ((Integer)
      getColumnDimension.invoke(matrix, new Object[] {})).intValue();
    double[][] entries =
      (double[][]) getArray.invoke(matrix, new Object[] {});
    double[][] range = new double[1][rows * cols];
    for (int i=0; i 

Ads help maintain this website.