summaryrefslogtreecommitdiffstats
path: root/src/org/jogamp/vecmath/GMatrix.java
diff options
context:
space:
mode:
authorJulien Gouesse <[email protected]>2015-11-28 14:20:15 +0100
committerJulien Gouesse <[email protected]>2015-11-28 14:20:15 +0100
commit245ee0238c841e60da215db9a40ccd04c65e40eb (patch)
tree92cb5c4bc2ef7440ea2daccecc490092a7bf12f8 /src/org/jogamp/vecmath/GMatrix.java
parent89caa5181fae34eaaec6d4e0a40c08ea5d38844e (diff)
parent0bc630ab20ae013225c0c93ff13733457724f143 (diff)
Merge pull request #2 from scijava/package-prefix
Relocate package prefix to org.jogamp.vecmath
Diffstat (limited to 'src/org/jogamp/vecmath/GMatrix.java')
-rw-r--r--src/org/jogamp/vecmath/GMatrix.java3006
1 files changed, 3006 insertions, 0 deletions
diff --git a/src/org/jogamp/vecmath/GMatrix.java b/src/org/jogamp/vecmath/GMatrix.java
new file mode 100644
index 0000000..2c7a6ae
--- /dev/null
+++ b/src/org/jogamp/vecmath/GMatrix.java
@@ -0,0 +1,3006 @@
+/*
+ * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+package org.jogamp.vecmath;
+
+
+/**
+ * A double precision, general, dynamically-resizable,
+ * two-dimensional matrix class. Row and column numbering begins with
+ * zero. The representation is row major.
+ */
+
+public class GMatrix implements java.io.Serializable, Cloneable {
+
+ // Compatible with 1.1
+ static final long serialVersionUID = 2777097312029690941L;
+ private static final boolean debug = false;
+
+ int nRow;
+ int nCol;
+
+ // double dereference is slow
+ double[][] values;
+
+ private static final double EPS = 1.0E-10;
+
+ /**
+ * Constructs an nRow by NCol identity matrix.
+ * Note that because row and column numbering begins with
+ * zero, nRow and nCol will be one larger than the maximum
+ * possible matrix index values.
+ * @param nRow number of rows in this matrix.
+ * @param nCol number of columns in this matrix.
+ */
+ public GMatrix(int nRow, int nCol)
+ {
+ values = new double[nRow][nCol];
+ this.nRow = nRow;
+ this.nCol = nCol;
+
+ int i, j;
+ for (i = 0; i < nRow; i++) {
+ for (j = 0; j < nCol; j++) {
+ values[i][j] = 0.0;
+ }
+ }
+
+ int l;
+ if (nRow < nCol)
+ l = nRow;
+ else
+ l = nCol;
+
+ for (i = 0; i < l; i++) {
+ values[i][i] = 1.0;
+ }
+ }
+
+ /**
+ * Constructs an nRow by nCol matrix initialized to the values
+ * in the matrix array. The array values are copied in one row at
+ * a time in row major fashion. The array should be at least
+ * nRow*nCol in length.
+ * Note that because row and column numbering begins with
+ * zero, nRow and nCol will be one larger than the maximum
+ * possible matrix index values.
+ * @param nRow number of rows in this matrix.
+ * @param nCol number of columns in this matrix.
+ * @param matrix a 1D array that specifies a matrix in row major fashion
+ */
+ public GMatrix(int nRow, int nCol, double[] matrix)
+ {
+ values = new double[nRow][nCol];
+ this.nRow = nRow;
+ this.nCol = nCol;
+
+ int i, j;
+ for (i = 0; i < nRow; i++) {
+ for (j = 0; j < nCol; j++) {
+ values[i][j] = matrix[i*nCol+j];
+ }
+ }
+ }
+
+ /**
+ * Constructs a new GMatrix and copies the initial values
+ * from the parameter matrix.
+ * @param matrix the source of the initial values of the new GMatrix
+ */
+ public GMatrix(GMatrix matrix)
+ {
+ nRow = matrix.nRow;
+ nCol = matrix.nCol;
+ values = new double[nRow][nCol];
+
+ int i, j;
+ for (i = 0; i < nRow; i++) {
+ for (j = 0; j < nCol; j++) {
+ values[i][j] = matrix.values[i][j];
+ }
+ }
+ }
+
+ /**
+ * Sets the value of this matrix to the result of multiplying itself
+ * with matrix m1 (this = this * m1).
+ * @param m1 the other matrix
+ */
+ public final void mul(GMatrix m1)
+ {
+ int i, j, k;
+
+ if (nCol != m1.nRow || nCol != m1.nCol)
+ throw new MismatchedSizeException
+ (VecMathI18N.getString("GMatrix0"));
+
+ double [][] tmp = new double[nRow][nCol];
+
+ for (i = 0; i < nRow; i++) {
+ for (j = 0; j < nCol; j++) {
+ tmp[i][j] = 0.0;
+ for (k = 0; k < nCol; k++) {
+ tmp[i][j] += values[i][k]*m1.values[k][j];
+ }
+ }
+ }
+
+ values = tmp;
+ }
+
+ /**
+ * Sets the value of this matrix to the result of multiplying
+ * the two argument matrices together (this = m1 * m2).
+ * @param m1 the first matrix
+ * @param m2 the second matrix
+ */
+ public final void mul(GMatrix m1, GMatrix m2)
+ {
+ int i, j, k;
+
+ if (m1.nCol != m2.nRow || nRow != m1.nRow || nCol != m2.nCol)
+ throw new MismatchedSizeException
+ (VecMathI18N.getString("GMatrix1"));
+
+ double[][] tmp = new double[nRow][nCol];
+
+ for (i = 0; i < m1.nRow; i++) {
+ for (j = 0; j < m2.nCol; j++) {
+ tmp[i][j] = 0.0;
+ for (k = 0; k < m1.nCol; k++) {
+ tmp[i][j] += m1.values[i][k]*m2.values[k][j];
+ }
+ }
+ }
+
+ values = tmp;
+ }
+
+ /**
+ * Computes the outer product of the two vectors; multiplies the
+ * the first vector by the transpose of the second vector and places
+ * the matrix result into this matrix. This matrix must be
+ * be as big or bigger than getSize(v1)xgetSize(v2).
+ * @param v1 the first vector, treated as a row vector
+ * @param v2 the second vector, treated as a column vector
+ */
+ public final void mul(GVector v1, GVector v2)
+ {
+ int i, j;
+
+ if (nRow < v1.getSize())
+ throw new MismatchedSizeException
+ (VecMathI18N.getString("GMatrix2"));
+
+ if (nCol < v2.getSize())
+ throw new MismatchedSizeException
+ (VecMathI18N.getString("GMatrix3"));
+
+ for (i = 0; i < v1.getSize(); i++ ) {
+ for (j = 0; j < v2.getSize(); j++ ) {
+ values[i][j] = v1.values[i]*v2.values[j];
+ }
+ }
+ }
+
+ /**
+ * Sets the value of this matrix to sum of itself and matrix m1.
+ * @param m1 the other matrix
+ */
+ public final void add(GMatrix m1)
+ {
+ int i, j;
+
+ if (nRow != m1.nRow)
+ throw new MismatchedSizeException
+ (VecMathI18N.getString("GMatrix4"));
+
+ if (nCol != m1.nCol)
+ throw new MismatchedSizeException
+ (VecMathI18N.getString("GMatrix5"));
+
+ for (i = 0; i < nRow; i++) {
+ for (j = 0; j < nCol; j++) {
+ values[i][j] = values[i][j] + m1.values[i][j];
+ }
+ }
+ }
+
+ /**
+ * Sets the value of this matrix to the matrix sum of matrices m1 and m2.
+ * @param m1 the first matrix
+ * @param m2 the second matrix
+ */
+ public final void add(GMatrix m1, GMatrix m2)
+ {
+ int i, j;
+
+ if (m2.nRow != m1.nRow)
+ throw new MismatchedSizeException
+ (VecMathI18N.getString("GMatrix6"));
+
+ if (m2.nCol != m1.nCol)
+ throw new MismatchedSizeException
+ (VecMathI18N.getString("GMatrix7"));
+
+ if (nCol != m1.nCol || nRow != m1.nRow)
+ throw new MismatchedSizeException
+ (VecMathI18N.getString("GMatrix8"));
+
+ for (i = 0; i < nRow; i++) {
+ for (j = 0; j < nCol; j++) {
+ values[i][j] = m1.values[i][j] + m2.values[i][j];
+ }
+ }
+ }
+
+ /**
+ * Sets the value of this matrix to the matrix difference of itself
+ * and matrix m1 (this = this - m1).
+ * @param m1 the other matrix
+ */
+ public final void sub(GMatrix m1)
+ {
+ int i, j;
+ if (nRow != m1.nRow)
+ throw new MismatchedSizeException
+ (VecMathI18N.getString("GMatrix9"));
+
+ if (nCol != m1.nCol)
+ throw new MismatchedSizeException
+ (VecMathI18N.getString("GMatrix28"));
+
+ for (i = 0; i < nRow; i++) {
+ for (j = 0; j < nCol; j++) {
+ values[i][j] = values[i][j] - m1.values[i][j];
+ }
+ }
+ }
+
+ /**
+ * Sets the value of this matrix to the matrix difference
+ * of matrices m1 and m2 (this = m1 - m2).
+ * @param m1 the first matrix
+ * @param m2 the second matrix
+ */
+ public final void sub(GMatrix m1, GMatrix m2)
+ {
+ int i, j;
+ if (m2.nRow != m1.nRow)
+ throw new MismatchedSizeException
+ (VecMathI18N.getString("GMatrix10"));
+
+ if (m2.nCol != m1.nCol)
+ throw new MismatchedSizeException
+ (VecMathI18N.getString("GMatrix11"));
+
+ if (nRow != m1.nRow || nCol != m1.nCol)
+ throw new MismatchedSizeException
+ (VecMathI18N.getString("GMatrix12"));
+
+ for (i = 0; i < nRow; i++) {
+ for (j = 0; j < nCol; j++) {
+ values[i][j] = m1.values[i][j] - m2.values[i][j];
+ }
+ }
+ }
+
+ /**
+ * Negates the value of this matrix: this = -this.
+ */
+ public final void negate()
+ {
+ int i, j;
+ for (i = 0; i < nRow; i++) {
+ for (j = 0;j < nCol; j++) {
+ values[i][j] = -values[i][j];
+ }
+ }
+ }
+
+ /**
+ * Sets the value of this matrix equal to the negation of
+ * of the GMatrix parameter.
+ * @param m1 The source matrix
+ */
+ public final void negate(GMatrix m1)
+ {
+ int i, j;
+ if (nRow != m1.nRow || nCol != m1.nCol)
+ throw new MismatchedSizeException
+ (VecMathI18N.getString("GMatrix13"));
+
+ for (i = 0; i < nRow; i++) {
+ for (j = 0; j < nCol; j++) {
+ values[i][j] = -m1.values[i][j];
+ }
+ }
+ }
+
+ /**
+ * Sets this GMatrix to the identity matrix.
+ */
+ public final void setIdentity()
+ {
+ int i, j;
+ for (i = 0; i < nRow; i++) {
+ for (j = 0; j < nCol; j++) {
+ values[i][j] = 0.0;
+ }
+ }
+
+ int l;
+ if (nRow < nCol)
+ l = nRow;
+ else
+ l = nCol;
+
+ for (i = 0; i < l; i++) {
+ values[i][i] = 1.0;
+ }
+ }
+
+ /**
+ * Sets all the values in this matrix to zero.
+ */
+ public final void setZero()
+ {
+ int i, j;
+ for (i = 0; i < nRow; i++) {
+ for (j = 0; j < nCol; j++) {
+ values[i][j] = 0.0;
+ }
+ }
+ }
+
+ /**
+ * Subtracts this matrix from the identity matrix and puts the values
+ * back into this (this = I - this).
+ */
+ public final void identityMinus()
+ {
+ int i, j;
+
+ for(i = 0; i < nRow; i++) {
+ for(j = 0; j < nCol; j++) {
+ values[i][j] = -values[i][j];
+ }
+ }
+
+ int l;
+ if( nRow < nCol)
+ l = nRow;
+ else
+ l = nCol;
+
+ for(i = 0; i < l; i++) {
+ values[i][i] += 1.0;
+ }
+ }
+
+
+ /**
+ * Inverts this matrix in place.
+ */
+ public final void invert()
+ {
+ invertGeneral(this);
+ }
+
+ /**
+ * Inverts matrix m1 and places the new values into this matrix. Matrix
+ * m1 is not modified.
+ * @param m1 the matrix to be inverted
+ */
+ public final void invert(GMatrix m1)
+ {
+ invertGeneral(m1);
+ }
+
+ /**
+ * Copies a sub-matrix derived from this matrix into the target matrix.
+ * The upper left of the sub-matrix is located at (rowSource, colSource);
+ * the lower right of the sub-matrix is located at
+ * (lastRowSource,lastColSource). The sub-matrix is copied into the
+ * the target matrix starting at (rowDest, colDest).
+ * @param rowSource the top-most row of the sub-matrix
+ * @param colSource the left-most column of the sub-matrix
+ * @param numRow the number of rows in the sub-matrix
+ * @param numCol the number of columns in the sub-matrix
+ * @param rowDest the top-most row of the position of the copied
+ * sub-matrix within the target matrix
+ * @param colDest the left-most column of the position of the copied
+ * sub-matrix within the target matrix
+ * @param target the matrix into which the sub-matrix will be copied
+ */
+ public final void copySubMatrix(int rowSource, int colSource,
+ int numRow, int numCol, int rowDest,
+ int colDest, GMatrix target)
+ {
+ int i, j;
+
+ if (this != target) {
+ for (i = 0; i < numRow; i++) {
+ for (j = 0; j < numCol; j++) {
+ target.values[rowDest+i][colDest+j] =
+ values[rowSource+i][colSource+j];
+ }
+ }
+ } else {
+ double[][] tmp = new double[numRow][numCol];
+ for (i = 0; i < numRow; i++) {
+ for (j = 0; j < numCol; j++) {
+ tmp[i][j] = values[rowSource+i][colSource+j];
+ }
+ }
+ for (i = 0; i < numRow; i++) {
+ for (j = 0; j < numCol; j++) {
+ target.values[rowDest+i][colDest+j] = tmp[i][j];
+ }
+ }
+ }
+ }
+
+ /**
+ * Changes the size of this matrix dynamically. If the size is increased
+ * no data values will be lost. If the size is decreased, only those data
+ * values whose matrix positions were eliminated will be lost.
+ * @param nRow number of desired rows in this matrix
+ * @param nCol number of desired columns in this matrix
+ */
+ public final void setSize(int nRow, int nCol)
+ {
+ double[][] tmp = new double[nRow][nCol];
+ int i, j, maxRow, maxCol;
+
+ if (this.nRow < nRow)
+ maxRow = this.nRow;
+ else
+ maxRow = nRow;
+
+ if (this.nCol < nCol)
+ maxCol = this.nCol;
+ else
+ maxCol = nCol;
+
+ for (i = 0; i < maxRow; i++) {
+ for (j = 0; j < maxCol; j++) {
+ tmp[i][j] = values[i][j];
+ }
+ }
+
+ this.nRow = nRow;
+ this.nCol = nCol;
+
+ values = tmp;
+ }
+
+ /**
+ * Sets the value of this matrix to the values found in the array parameter.
+ * The values are copied in one row at a time, in row major
+ * fashion. The array should be at least equal in length to
+ * the number of matrix rows times the number of matrix columns
+ * in this matrix.
+ * @param matrix the row major source array
+ */
+ public final void set(double[] matrix)
+ {
+ int i, j;
+
+ for (i = 0; i < nRow; i++) {
+ for (j = 0; j < nCol; j++) {
+ values[i][j] = matrix[nCol*i+j];
+ }
+ }
+ }
+
+ /**
+ * Sets the value of this matrix to that of the Matrix3f provided.
+ * @param m1 the matrix
+ */
+ public final void set(Matrix3f m1)
+ {
+ int i, j;
+
+ if (nCol < 3 || nRow < 3) { // expand matrix if too small
+ nCol = 3;
+ nRow = 3;
+ values = new double[nRow][nCol];
+ }
+
+ values[0][0] = m1.m00;
+ values[0][1] = m1.m01;
+ values[0][2] = m1.m02;
+
+ values[1][0] = m1.m10;
+ values[1][1] = m1.m11;
+ values[1][2] = m1.m12;
+
+ values[2][0] = m1.m20;
+ values[2][1] = m1.m21;
+ values[2][2] = m1.m22;
+
+ for (i = 3; i < nRow; i++) { // pad rest or matrix with zeros
+ for (j = 3; j < nCol; j++) {
+ values[i][j] = 0.0;
+ }
+ }
+ }
+
+ /**
+ * Sets the value of this matrix to that of the Matrix3d provided.
+ * @param m1 the matrix
+ */
+ public final void set(Matrix3d m1)
+ {
+ if (nRow < 3 || nCol < 3) {
+ values = new double[3][3];
+ nRow = 3;
+ nCol = 3;
+ }
+
+ values[0][0] = m1.m00;
+ values[0][1] = m1.m01;
+ values[0][2] = m1.m02;
+
+ values[1][0] = m1.m10;
+ values[1][1] = m1.m11;
+ values[1][2] = m1.m12;
+
+ values[2][0] = m1.m20;
+ values[2][1] = m1.m21;
+ values[2][2] = m1.m22;
+
+ for (int i = 3; i < nRow; i++) { // pad rest or matrix with zeros
+ for(int j = 3; j < nCol; j++) {
+ values[i][j] = 0.0;
+ }
+ }
+
+ }
+
+ /**
+ * Sets the value of this matrix to that of the Matrix4f provided.
+ * @param m1 the matrix
+ */
+ public final void set(Matrix4f m1)
+ {
+ if (nRow < 4 || nCol < 4) {
+ values = new double[4][4];
+ nRow = 4;
+ nCol = 4;
+ }
+
+ values[0][0] = m1.m00;
+ values[0][1] = m1.m01;
+ values[0][2] = m1.m02;
+ values[0][3] = m1.m03;
+
+ values[1][0] = m1.m10;
+ values[1][1] = m1.m11;
+ values[1][2] = m1.m12;
+ values[1][3] = m1.m13;
+
+ values[2][0] = m1.m20;
+ values[2][1] = m1.m21;
+ values[2][2] = m1.m22;
+ values[2][3] = m1.m23;
+
+ values[3][0] = m1.m30;
+ values[3][1] = m1.m31;
+ values[3][2] = m1.m32;
+ values[3][3] = m1.m33;
+
+ for (int i = 4 ; i < nRow; i++) { // pad rest or matrix with zeros
+ for (int j = 4; j < nCol; j++) {
+ values[i][j] = 0.0;
+ }
+ }
+ }
+
+ /**
+ * Sets the value of this matrix to that of the Matrix4d provided.
+ * @param m1 the matrix
+ */
+ public final void set(Matrix4d m1)
+ {
+ if (nRow < 4 || nCol < 4) {
+ values = new double[4][4];
+ nRow = 4;
+ nCol = 4;
+ }
+
+ values[0][0] = m1.m00;
+ values[0][1] = m1.m01;
+ values[0][2] = m1.m02;
+ values[0][3] = m1.m03;
+
+ values[1][0] = m1.m10;
+ values[1][1] = m1.m11;
+ values[1][2] = m1.m12;
+ values[1][3] = m1.m13;
+
+ values[2][0] = m1.m20;
+ values[2][1] = m1.m21;
+ values[2][2] = m1.m22;
+ values[2][3] = m1.m23;
+
+ values[3][0] = m1.m30;
+ values[3][1] = m1.m31;
+ values[3][2] = m1.m32;
+ values[3][3] = m1.m33;
+
+ for (int i = 4; i < nRow; i++) { // pad rest or matrix with zeros
+ for (int j = 4; j < nCol; j++) {
+ values[i][j] = 0.0;
+ }
+ }
+ }
+
+ /**
+ * Sets the value of this matrix to the values found in matrix m1.
+ * @param m1 the source matrix
+ */
+ public final void set(GMatrix m1)
+ {
+ int i, j;
+
+ if (nRow < m1.nRow || nCol < m1.nCol) {
+ nRow = m1.nRow;
+ nCol = m1.nCol;
+ values = new double[nRow][nCol];
+ }
+
+ for (i = 0; i < Math.min(nRow, m1.nRow); i++) {
+ for (j = 0; j < Math.min(nCol, m1.nCol); j++) {
+ values[i][j] = m1.values[i][j];
+ }
+ }
+
+ for (i = m1.nRow; i < nRow; i++) { // pad rest or matrix with zeros
+ for (j = m1.nCol; j < nCol; j++) {
+ values[i][j] = 0.0;
+ }
+ }
+ }
+
+ /**
+ * Returns the number of rows in this matrix.
+ * @return number of rows in this matrix
+ */
+ public final int getNumRow()
+ {
+ return(nRow);
+ }
+
+ /**
+ * Returns the number of colmuns in this matrix.
+ * @return number of columns in this matrix
+ */
+ public final int getNumCol()
+ {
+ return(nCol);
+ }
+
+ /**
+ * Retrieves the value at the specified row and column of this matrix.
+ * @param row the row number to be retrieved (zero indexed)
+ * @param column the column number to be retrieved (zero indexed)
+ * @return the value at the indexed element
+ */
+ public final double getElement(int row, int column)
+ {
+ return(values[row][column]);
+ }
+
+
+ /**
+ * Modifies the value at the specified row and column of this matrix.
+ * @param row the row number to be modified (zero indexed)
+ * @param column the column number to be modified (zero indexed)
+ * @param value the new matrix element value
+ */
+ public final void setElement(int row, int column, double value)
+ {
+ values[row][column] = value;
+ }
+
+ /**
+ * Places the values of the specified row into the array parameter.
+ * @param row the target row number
+ * @param array the array into which the row values will be placed
+ */
+ public final void getRow(int row, double[] array)
+ {
+ for (int i = 0; i < nCol; i++) {
+ array[i] = values[row][i];
+ }
+ }
+
+ /**
+ * Places the values of the specified row into the vector parameter.
+ * @param row the target row number
+ * @param vector the vector into which the row values will be placed
+ */
+ public final void getRow(int row, GVector vector)
+ {
+ if (vector.getSize() < nCol)
+ vector.setSize(nCol);
+
+ for (int i = 0; i < nCol; i++) {
+ vector.values[i] = values[row][i];
+ }
+ }
+
+ /**
+ * Places the values of the specified column into the array parameter.
+ * @param col the target column number
+ * @param array the array into which the column values will be placed
+ */
+ public final void getColumn(int col, double[] array)
+ {
+ for (int i = 0; i < nRow; i++) {
+ array[i] = values[i][col];
+ }
+
+ }
+
+ /**
+ * Places the values of the specified column into the vector parameter.
+ * @param col the target column number
+ * @param vector the vector into which the column values will be placed
+ */
+ public final void getColumn(int col, GVector vector)
+ {
+ if (vector.getSize() < nRow)
+ vector.setSize(nRow);
+
+ for (int i = 0; i < nRow; i++) {
+ vector.values[i] = values[i][col];
+ }
+ }
+
+ /**
+ * Places the values in the upper 3x3 of this GMatrix into
+ * the matrix m1.
+ * @param m1 The matrix that will hold the new values
+ */
+ public final void get(Matrix3d m1)
+ {
+ if (nRow < 3 || nCol < 3) {
+ m1.setZero();
+ if (nCol > 0) {
+ if (nRow > 0){
+ m1.m00 = values[0][0];
+ if (nRow > 1){
+ m1.m10 = values[1][0];
+ if( nRow > 2 ){
+ m1.m20= values[2][0];
+ }
+ }
+ }
+ if (nCol > 1) {
+ if (nRow > 0) {
+ m1.m01 = values[0][1];
+ if (nRow > 1){
+ m1.m11 = values[1][1];
+ if (nRow > 2){
+ m1.m21 = values[2][1];
+ }
+ }
+ }
+ if (nCol > 2) {
+ if (nRow > 0) {
+ m1.m02 = values[0][2];
+ if (nRow > 1) {
+ m1.m12 = values[1][2];
+ if (nRow > 2) {
+ m1.m22 = values[2][2];
+ }
+ }
+ }
+ }
+ }
+ }
+ } else {
+ m1.m00 = values[0][0];
+ m1.m01 = values[0][1];
+ m1.m02 = values[0][2];
+
+ m1.m10 = values[1][0];
+ m1.m11 = values[1][1];
+ m1.m12 = values[1][2];
+
+ m1.m20 = values[2][0];
+ m1.m21 = values[2][1];
+ m1.m22 = values[2][2];
+ }
+ }
+
+ /**
+ * Places the values in the upper 3x3 of this GMatrix into
+ * the matrix m1.
+ * @param m1 The matrix that will hold the new values
+ */
+ public final void get(Matrix3f m1)
+ {
+
+ if (nRow < 3 || nCol < 3) {
+ m1.setZero();
+ if (nCol > 0) {
+ if (nRow > 0) {
+ m1.m00 = (float)values[0][0];
+ if (nRow > 1) {
+ m1.m10 = (float)values[1][0];
+ if (nRow > 2) {
+ m1.m20 = (float)values[2][0];
+ }
+ }
+ }
+ if (nCol > 1) {
+ if (nRow > 0) {
+ m1.m01 = (float)values[0][1];
+ if (nRow > 1){
+ m1.m11 = (float)values[1][1];
+ if (nRow > 2){
+ m1.m21 = (float)values[2][1];
+ }
+ }
+ }
+ if (nCol > 2) {
+ if (nRow > 0) {
+ m1.m02 = (float)values[0][2];
+ if (nRow > 1) {
+ m1.m12 = (float)values[1][2];
+ if (nRow > 2) {
+ m1.m22 = (float)values[2][2];
+ }
+ }
+ }
+ }
+ }
+ }
+ } else {
+ m1.m00 = (float)values[0][0];
+ m1.m01 = (float)values[0][1];
+ m1.m02 = (float)values[0][2];
+
+ m1.m10 = (float)values[1][0];
+ m1.m11 = (float)values[1][1];
+ m1.m12 = (float)values[1][2];
+
+ m1.m20 = (float)values[2][0];
+ m1.m21 = (float)values[2][1];
+ m1.m22 = (float)values[2][2];
+ }
+ }
+
+ /**
+ * Places the values in the upper 4x4 of this GMatrix into
+ * the matrix m1.
+ * @param m1 The matrix that will hold the new values
+ */
+ public final void get(Matrix4d m1)
+ {
+ if (nRow < 4 || nCol < 4) {
+ m1.setZero();
+ if (nCol > 0) {
+ if (nRow > 0) {
+ m1.m00 = values[0][0];
+ if (nRow > 1) {
+ m1.m10 = values[1][0];
+ if (nRow > 2) {
+ m1.m20 = values[2][0];
+ if (nRow > 3) {
+ m1.m30 = values[3][0];
+ }
+ }
+ }
+ }
+ if (nCol > 1) {
+ if (nRow > 0) {
+ m1.m01 = values[0][1];
+ if (nRow > 1) {
+ m1.m11 = values[1][1];
+ if (nRow > 2) {
+ m1.m21 = values[2][1];
+ if (nRow > 3) {
+ m1.m31 = values[3][1];
+ }
+ }
+ }
+ }
+ if (nCol > 2) {
+ if (nRow > 0) {
+ m1.m02 = values[0][2];
+ if (nRow > 1) {
+ m1.m12 = values[1][2];
+ if (nRow > 2) {
+ m1.m22 = values[2][2];
+ if (nRow > 3) {
+ m1.m32 = values[3][2];
+ }
+ }
+ }
+ }
+ if (nCol > 3) {
+ if (nRow > 0) {
+ m1.m03 = values[0][3];
+ if (nRow > 1) {
+ m1.m13 = values[1][3];
+ if (nRow > 2) {
+ m1.m23 = values[2][3];
+ if (nRow > 3) {
+ m1.m33 = values[3][3];
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ } else {
+ m1.m00 = values[0][0];
+ m1.m01 = values[0][1];
+ m1.m02 = values[0][2];
+ m1.m03 = values[0][3];
+
+ m1.m10 = values[1][0];
+ m1.m11 = values[1][1];
+ m1.m12 = values[1][2];
+ m1.m13 = values[1][3];
+
+ m1.m20 = values[2][0];
+ m1.m21 = values[2][1];
+ m1.m22 = values[2][2];
+ m1.m23 = values[2][3];
+
+ m1.m30 = values[3][0];
+ m1.m31 = values[3][1];
+ m1.m32 = values[3][2];
+ m1.m33 = values[3][3];
+ }
+
+ }
+
+ /**
+ * Places the values in the upper 4x4 of this GMatrix into
+ * the matrix m1.
+ * @param m1 The matrix that will hold the new values
+ */
+ public final void get(Matrix4f m1)
+ {
+
+ if (nRow < 4 || nCol < 4) {
+ m1.setZero();
+ if (nCol > 0) {
+ if (nRow > 0) {
+ m1.m00 = (float)values[0][0];
+ if (nRow > 1) {
+ m1.m10 = (float)values[1][0];
+ if (nRow > 2) {
+ m1.m20 = (float)values[2][0];
+ if (nRow > 3) {
+ m1.m30 = (float)values[3][0];
+ }
+ }
+ }
+ }
+ if (nCol > 1) {
+ if (nRow > 0) {
+ m1.m01 = (float)values[0][1];
+ if (nRow > 1) {
+ m1.m11 = (float)values[1][1];
+ if (nRow > 2) {
+ m1.m21 = (float)values[2][1];
+ if (nRow > 3) {
+ m1.m31 = (float)values[3][1];
+ }
+ }
+ }
+ }
+ if (nCol > 2) {
+ if (nRow > 0) {
+ m1.m02 = (float)values[0][2];
+ if (nRow > 1) {
+ m1.m12 = (float)values[1][2];
+ if (nRow > 2) {
+ m1.m22 = (float)values[2][2];
+ if (nRow > 3) {
+ m1.m32 = (float)values[3][2];
+ }
+ }
+ }
+ }
+ if (nCol > 3) {
+ if (nRow > 0) {
+ m1.m03 = (float)values[0][3];
+ if (nRow > 1) {
+ m1.m13 = (float)values[1][3];
+ if (nRow > 2) {
+ m1.m23 = (float)values[2][3];
+ if (nRow > 3) {
+ m1.m33 = (float)values[3][3];
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ } else {
+ m1.m00 = (float)values[0][0];
+ m1.m01 = (float)values[0][1];
+ m1.m02 = (float)values[0][2];
+ m1.m03 = (float)values[0][3];
+
+ m1.m10 = (float)values[1][0];
+ m1.m11 = (float)values[1][1];
+ m1.m12 = (float)values[1][2];
+ m1.m13 = (float)values[1][3];
+
+ m1.m20 = (float)values[2][0];
+ m1.m21 = (float)values[2][1];
+ m1.m22 = (float)values[2][2];
+ m1.m23 = (float)values[2][3];
+
+ m1.m30 = (float)values[3][0];
+ m1.m31 = (float)values[3][1];
+ m1.m32 = (float)values[3][2];
+ m1.m33 = (float)values[3][3];
+ }
+ }
+
+ /**
+ * Places the values in the this GMatrix into the matrix m1;
+ * m1 should be at least as large as this GMatrix.
+ * @param m1 The matrix that will hold the new values
+ */
+ public final void get(GMatrix m1)
+ {
+ int i, j, nc, nr;
+
+ if (nCol < m1.nCol)
+ nc = nCol;
+ else
+ nc = m1.nCol;
+
+ if (nRow < m1.nRow)
+ nr = nRow;
+ else
+ nr = m1.nRow;
+
+ for (i = 0; i < nr; i++) {
+ for (j = 0; j < nc; j++) {
+ m1.values[i][j] = values[i][j];
+ }
+ }
+ for (i = nr; i < m1.nRow; i++) {
+ for (j = 0; j < m1.nCol; j++) {
+ m1.values[i][j] = 0.0;
+ }
+ }
+ for (j = nc; j < m1.nCol; j++) {
+ for (i = 0; i < nr; i++) {
+ m1.values[i][j] = 0.0;
+ }
+ }
+ }
+
+ /**
+ * Copy the values from the array into the specified row of this
+ * matrix.
+ * @param row the row of this matrix into which the array values
+ * will be copied.
+ * @param array the source array
+ */
+ public final void setRow(int row, double[] array)
+ {
+ for (int i = 0; i < nCol; i++) {
+ values[row][i] = array[i];
+ }
+ }
+
+ /**
+ * Copy the values from the vector into the specified row of this
+ * matrix.
+ * @param row the row of this matrix into which the array values
+ * will be copied
+ * @param vector the source vector
+ */
+ public final void setRow(int row, GVector vector)
+ {
+ for(int i = 0; i < nCol; i++) {
+ values[row][i] = vector.values[i];
+ }
+ }
+
+ /**
+ * Copy the values from the array into the specified column of this
+ * matrix.
+ * @param col the column of this matrix into which the array values
+ * will be copied
+ * @param array the source array
+ */
+ public final void setColumn(int col, double[] array)
+ {
+ for(int i = 0; i < nRow; i++) {
+ values[i][col] = array[i];
+ }
+ }
+
+ /**
+ * Copy the values from the vector into the specified column of this
+ * matrix.
+ * @param col the column of this matrix into which the array values
+ * will be copied
+ * @param vector the source vector
+ */
+ public final void setColumn(int col, GVector vector)
+ {
+ for(int i = 0; i < nRow; i++) {
+ values[i][col] = vector.values[i];
+ }
+
+ }
+
+ /**
+ * Multiplies the transpose of matrix m1 times the transpose of matrix
+ * m2, and places the result into this.
+ * @param m1 The matrix on the left hand side of the multiplication
+ * @param m2 The matrix on the right hand side of the multiplication
+ */
+ public final void mulTransposeBoth(GMatrix m1, GMatrix m2)
+ {
+ int i, j, k;
+
+ if (m1.nRow != m2.nCol || nRow != m1.nCol || nCol != m2.nRow)
+ throw new MismatchedSizeException
+ (VecMathI18N.getString("GMatrix14"));
+
+ if (m1 == this || m2 == this) {
+ double[][] tmp = new double[nRow][nCol];
+ for (i = 0; i < nRow; i++) {
+ for (j = 0; j < nCol; j++) {
+ tmp[i][j] = 0.0;
+ for (k = 0; k < m1.nRow; k++) {
+ tmp[i][j] += m1.values[k][i]*m2.values[j][k];
+ }
+ }
+ }
+ values = tmp;
+ } else {
+ for (i = 0; i < nRow; i++) {
+ for (j = 0; j < nCol; j++) {
+ values[i][j] = 0.0;
+ for (k = 0; k < m1.nRow; k++) {
+ values[i][j] += m1.values[k][i]*m2.values[j][k];
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Multiplies matrix m1 times the transpose of matrix m2, and
+ * places the result into this.
+ * @param m1 The matrix on the left hand side of the multiplication
+ * @param m2 The matrix on the right hand side of the multiplication
+ */
+ public final void mulTransposeRight(GMatrix m1, GMatrix m2)
+ {
+ int i, j, k;
+
+ if (m1.nCol != m2.nCol || nCol != m2.nRow || nRow != m1.nRow)
+ throw new MismatchedSizeException
+ (VecMathI18N.getString("GMatrix15"));
+
+ if (m1 == this || m2 == this) {
+ double[][] tmp = new double[nRow][nCol];
+ for (i = 0; i < nRow; i++) {
+ for (j = 0; j < nCol; j++) {
+ tmp[i][j] = 0.0;
+ for (k = 0; k < m1.nCol; k++) {
+ tmp[i][j] += m1.values[i][k]*m2.values[j][k];
+ }
+ }
+ }
+ values = tmp;
+ } else {
+ for (i = 0; i < nRow; i++) {
+ for (j = 0;j < nCol; j++) {
+ values[i][j] = 0.0;
+ for (k = 0; k < m1.nCol; k++) {
+ values[i][j] += m1.values[i][k]*m2.values[j][k];
+ }
+ }
+ }
+ }
+
+ }
+
+
+ /**
+ * Multiplies the transpose of matrix m1 times matrix m2, and
+ * places the result into this.
+ * @param m1 The matrix on the left hand side of the multiplication
+ * @param m2 The matrix on the right hand side of the multiplication
+ */
+ public final void mulTransposeLeft(GMatrix m1, GMatrix m2)
+ {
+ int i, j, k;
+
+ if (m1.nRow != m2.nRow || nCol != m2.nCol || nRow != m1.nCol)
+ throw new MismatchedSizeException
+ (VecMathI18N.getString("GMatrix16"));
+
+ if (m1 == this || m2 == this) {
+ double[][] tmp = new double[nRow][nCol];
+ for (i = 0; i < nRow; i++) {
+ for (j = 0; j < nCol; j++) {
+ tmp[i][j] = 0.0;
+ for (k = 0; k < m1.nRow; k++) {
+ tmp[i][j] += m1.values[k][i]*m2.values[k][j];
+ }
+ }
+ }
+ values = tmp;
+ } else {
+ for (i = 0; i < nRow; i++) {
+ for (j = 0; j < nCol; j++) {
+ values[i][j] = 0.0;
+ for (k = 0; k < m1.nRow; k++) {
+ values[i][j] += m1.values[k][i]*m2.values[k][j];
+ }
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Transposes this matrix in place.
+ */
+ public final void transpose()
+ {
+ int i, j;
+
+ if (nRow != nCol) {
+ double[][] tmp;
+ i=nRow;
+ nRow = nCol;
+ nCol = i;
+ tmp = new double[nRow][nCol];
+ for (i = 0; i < nRow; i++) {
+ for (j = 0; j < nCol; j++) {
+ tmp[i][j] = values[j][i];
+ }
+ }
+ values = tmp;
+ } else {
+ double swap;
+ for (i = 0; i < nRow; i++) {
+ for (j = 0; j < i; j++) {
+ swap = values[i][j];
+ values[i][j] = values[j][i];
+ values[j][i] = swap;
+ }
+ }
+ }
+ }
+
+ /**
+ * Places the matrix values of the transpose of matrix m1 into this matrix.
+ * @param m1 the matrix to be transposed (but not modified)
+ */
+ public final void transpose(GMatrix m1)
+ {
+ int i, j;
+
+ if (nRow != m1.nCol || nCol != m1.nRow)
+ throw new MismatchedSizeException
+ (VecMathI18N.getString("GMatrix17"));
+
+ if (m1 != this) {
+ for (i = 0; i < nRow; i++) {
+ for (j = 0;j < nCol; j++) {
+ values[i][j] = m1.values[j][i];
+ }
+ }
+ } else {
+ transpose();
+ }
+ }
+
+ /**
+ * Returns a string that contains the values of this GMatrix.
+ * @return the String representation
+ */
+ @Override
+ public String toString()
+ {
+ StringBuffer buffer = new StringBuffer(nRow*nCol*8);
+
+ int i, j;
+
+ for (i = 0; i < nRow; i++) {
+ for (j = 0; j < nCol; j++) {
+ buffer.append(values[i][j]).append(" ");
+ }
+ buffer.append("\n");
+ }
+
+ return buffer.toString();
+ }
+
+ private static void checkMatrix( GMatrix m)
+ {
+ int i, j;
+
+ for (i = 0; i < m.nRow; i++) {
+ for (j = 0; j < m.nCol; j++) {
+ if (Math.abs(m.values[i][j]) < 0.0000000001) {
+ System.out.print(" 0.0 ");
+ } else {
+ System.out.print(" " + m.values[i][j]);
+ }
+ }
+ System.out.print("\n");
+ }
+ }
+
+
+ /**
+ * Returns a hash code value based on the data values in this
+ * object. Two different GMatrix objects with identical data
+ * values (i.e., GMatrix.equals returns true) will return the
+ * same hash number. Two GMatrix objects with different data
+ * members may return the same hash value, although this is not
+ * likely.
+ * @return the integer hash code value
+ */
+ @Override
+ public int hashCode() {
+ long bits = 1L;
+
+ bits = VecMathUtil.hashLongBits(bits, nRow);
+ bits = VecMathUtil.hashLongBits(bits, nCol);
+
+ for (int i = 0; i < nRow; i++) {
+ for (int j = 0; j < nCol; j++) {
+ bits = VecMathUtil.hashDoubleBits(bits, values[i][j]);
+ }
+ }
+
+ return VecMathUtil.hashFinish(bits);
+ }
+
+
+ /**
+ * Returns true if all of the data members of GMatrix m1 are
+ * equal to the corresponding data members in this GMatrix.
+ * @param m1 The matrix with which the comparison is made.
+ * @return true or false
+ */
+ public boolean equals(GMatrix m1)
+ {
+ try {
+ int i, j;
+
+ if (nRow != m1.nRow || nCol != m1.nCol)
+ return false;
+
+ for (i = 0;i < nRow; i++) {
+ for (j = 0; j < nCol; j++) {
+ if (values[i][j] != m1.values[i][j])
+ return false;
+ }
+ }
+ return true;
+ }
+ catch (NullPointerException e2) {
+ return false;
+ }
+ }
+
+ /**
+ * Returns true if the Object o1 is of type GMatrix and all of the
+ * data members of o1 are equal to the corresponding data members in
+ * this GMatrix.
+ * @param o1 The object with which the comparison is made.
+ * @return true or false
+ */
+ @Override
+ public boolean equals(Object o1)
+ {
+ try {
+ GMatrix m2 = (GMatrix) o1;
+ int i, j;
+ if (nRow != m2.nRow || nCol != m2.nCol)
+ return false;
+
+ for (i = 0; i < nRow; i++) {
+ for (j = 0; j < nCol; j++) {
+ if (values[i][j] != m2.values[i][j])
+ return false;
+ }
+ }
+ return true;
+ }
+ catch (ClassCastException e1) {
+ return false;
+ }
+ catch (NullPointerException e2) {
+ return false;
+ }
+ }
+
+ /**
+ * @deprecated Use epsilonEquals(GMatrix, double) instead
+ */
+ public boolean epsilonEquals(GMatrix m1, float epsilon) {
+ return epsilonEquals(m1, (double)epsilon);
+ }
+
+ /**
+ * Returns true if the L-infinite distance between this matrix
+ * and matrix m1 is less than or equal to the epsilon parameter,
+ * otherwise returns false. The L-infinite
+ * distance is equal to
+ * MAX[i=0,1,2, . . .n ; j=0,1,2, . . .n ; abs(this.m(i,j) - m1.m(i,j)]
+ * @param m1 The matrix to be compared to this matrix
+ * @param epsilon the threshold value
+ */
+ public boolean epsilonEquals(GMatrix m1, double epsilon)
+ {
+ int i, j;
+ double diff;
+ if (nRow != m1.nRow || nCol != m1.nCol)
+ return false;
+
+ for (i = 0; i < nRow; i++) {
+ for (j = 0; j < nCol; j++) {
+ diff = values[i][j] - m1.values[i][j];
+ if ((diff < 0 ? -diff : diff) > epsilon)
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Returns the trace of this matrix.
+ * @return the trace of this matrix
+ */
+ public final double trace()
+ {
+ int i, l;
+ double t;
+
+ if (nRow < nCol)
+ l = nRow;
+ else
+ l = nCol;
+
+ t = 0.0;
+ for (i = 0; i < l; i++) {
+ t += values[i][i];
+ }
+ return t;
+ }
+
+ /**
+ * Finds the singular value decomposition (SVD) of this matrix
+ * such that this = U*W*transpose(V); and returns the rank of
+ * this matrix; the values of U,W,V are all overwritten. Note
+ * that the matrix V is output as V, and
+ * not transpose(V). If this matrix is mxn, then U is mxm, W
+ * is a diagonal matrix that is mxn, and V is nxn. Using the
+ * notation W = diag(w), then the inverse of this matrix is:
+ * inverse(this) = V*diag(1/w)*tranpose(U), where diag(1/w)
+ * is the same matrix as W except that the reciprocal of each
+ * of the diagonal components is used.
+ * @param U The computed U matrix in the equation this = U*W*transpose(V)
+ * @param W The computed W matrix in the equation this = U*W*transpose(V)
+ * @param V The computed V matrix in the equation this = U*W*transpose(V)
+ * @return The rank of this matrix.
+ */
+ public final int SVD(GMatrix U, GMatrix W, GMatrix V)
+ {
+ // check for consistancy in dimensions
+ if (nCol != V.nCol || nCol != V.nRow) {
+ throw new MismatchedSizeException
+ (VecMathI18N.getString("GMatrix18"));
+ }
+
+ if (nRow != U.nRow || nRow != U.nCol) {
+ throw new MismatchedSizeException
+ (VecMathI18N.getString("GMatrix25"));
+ }
+
+ if (nRow != W.nRow || nCol != W.nCol) {
+ throw new MismatchedSizeException
+ (VecMathI18N.getString("GMatrix26"));
+ }
+
+ // Fix ArrayIndexOutOfBounds for 2x2 matrices, which partially
+ // addresses bug 4348562 for J3D 1.2.1.
+ //
+ // Does *not* fix the following problems reported in 4348562,
+ // which will wait for J3D 1.3:
+ //
+ // 1) no output of W
+ // 2) wrong transposition of U
+ // 3) wrong results for 4x4 matrices
+ // 4) slow performance
+ if (nRow == 2 && nCol == 2) {
+ if (values[1][0] == 0.0) {
+ U.setIdentity();
+ V.setIdentity();
+
+ if (values[0][1] == 0.0) {
+ return 2;
+ }
+
+ double[] sinl = new double[1];
+ double[] sinr = new double[1];
+ double[] cosl = new double[1];
+ double[] cosr = new double[1];
+ double[] single_values = new double[2];
+
+ single_values[0] = values[0][0];
+ single_values[1] = values[1][1];
+
+ compute_2X2(values[0][0], values[0][1], values[1][1],
+ single_values, sinl, cosl, sinr, cosr, 0);
+
+ update_u(0, U, cosl, sinl);
+ update_v(0, V, cosr, sinr);
+
+ return 2;
+ }
+ // else call computeSVD() and check for 2x2 there
+ }
+
+ return computeSVD(this, U, W, V);
+ }
+
+ /**
+ * LU Decomposition: this matrix must be a square matrix and the
+ * LU GMatrix parameter must be the same size as this matrix.
+ * The matrix LU will be overwritten as the combination of a
+ * lower diagonal and upper diagonal matrix decompostion of this
+ * matrix; the diagonal
+ * elements of L (unity) are not stored. The GVector parameter
+ * records the row permutation effected by the partial pivoting,
+ * and is used as a parameter to the GVector method LUDBackSolve
+ * to solve sets of linear equations.
+ * This method returns +/- 1 depending on whether the number
+ * of row interchanges was even or odd, respectively.
+ * @param LU The matrix into which the lower and upper decompositions
+ * will be placed.
+ * @param permutation The row permutation effected by the partial
+ * pivoting
+ * @return +-1 depending on whether the number of row interchanges
+ * was even or odd respectively
+ */
+ public final int LUD(GMatrix LU, GVector permutation)
+ {
+ int size = LU.nRow*LU.nCol;
+ double[] temp = new double[size];
+ int[] even_row_exchange = new int[1];
+ int[] row_perm = new int[LU.nRow];
+ int i, j;
+
+ if (nRow != nCol) {
+ throw new MismatchedSizeException
+ (VecMathI18N.getString("GMatrix19"));
+ }
+
+ if (nRow != LU.nRow) {
+ throw new MismatchedSizeException
+ (VecMathI18N.getString("GMatrix27"));
+ }
+
+ if (nCol != LU.nCol) {
+ throw new MismatchedSizeException
+ (VecMathI18N.getString("GMatrix27"));
+ }
+
+ if (LU.nRow != permutation.getSize()) {
+ throw new MismatchedSizeException
+ (VecMathI18N.getString("GMatrix20"));
+ }
+
+ for (i = 0; i < nRow; i++) {
+ for (j = 0; j < nCol; j++) {
+ temp[i*nCol+j] = values[i][j];
+ }
+ }
+
+ // Calculate LU decomposition: Is the matrix singular?
+ if (!luDecomposition(LU.nRow, temp, row_perm, even_row_exchange)) {
+ // Matrix has no inverse
+ throw new SingularMatrixException
+ (VecMathI18N.getString("GMatrix21"));
+ }
+
+ for (i = 0; i < nRow; i++) {
+ for (j = 0; j < nCol; j++) {
+ LU.values[i][j] = temp[i*nCol+j];
+ }
+ }
+
+ for (i = 0; i < LU.nRow; i++){
+ permutation.values[i] = (double)row_perm[i];
+ }
+
+ return even_row_exchange[0];
+ }
+
+ /**
+ * Sets this matrix to a uniform scale matrix; all of the
+ * values are reset.
+ * @param scale The new scale value
+ */
+ public final void setScale(double scale)
+ {
+ int i, j, l;
+
+ if (nRow < nCol)
+ l = nRow;
+ else
+ l = nCol;
+
+ for (i = 0; i < nRow; i++) {
+ for (j = 0; j < nCol; j++) {
+ values[i][j] = 0.0;
+ }
+ }
+
+ for (i = 0; i < l; i++) {
+ values[i][i] = scale;
+ }
+ }
+
+ /**
+ * General invert routine. Inverts m1 and places the result in "this".
+ * Note that this routine handles both the "this" version and the
+ * non-"this" version.
+ *
+ * Also note that since this routine is slow anyway, we won't worry
+ * about allocating a little bit of garbage.
+ */
+ final void invertGeneral(GMatrix m1) {
+ int size = m1.nRow*m1.nCol;
+ double temp[] = new double[size];
+ double result[] = new double[size];
+ int row_perm[] = new int[m1.nRow];
+ int[] even_row_exchange = new int[1];
+ int i, j;
+
+ // Use LU decomposition and backsubstitution code specifically
+ // for floating-point nxn matrices.
+ if (m1.nRow != m1.nCol) {
+ // Matrix is either under or over determined
+ throw new MismatchedSizeException
+ (VecMathI18N.getString("GMatrix22"));
+ }
+
+ // Copy source matrix to temp
+ for (i = 0; i < nRow; i++) {
+ for (j = 0; j < nCol; j++) {
+ temp[i*nCol+j] = m1.values[i][j];
+ }
+ }
+
+ // Calculate LU decomposition: Is the matrix singular?
+ if (!luDecomposition(m1.nRow, temp, row_perm, even_row_exchange)) {
+ // Matrix has no inverse
+ throw new SingularMatrixException
+ (VecMathI18N.getString("GMatrix21"));
+ }
+
+ // Perform back substitution on the identity matrix
+ for (i = 0; i < size; i++)
+ result[i] = 0.0;
+
+ for (i = 0; i < nCol; i++)
+ result[i+i*nCol] = 1.0;
+
+ luBacksubstitution(m1.nRow, temp, row_perm, result);
+
+ for (i = 0; i < nRow; i++) {
+ for (j = 0; j < nCol; j++) {
+ values[i][j] = result[i*nCol+j];
+ }
+ }
+ }
+
+ /**
+ * Given a nxn array "matrix0", this function replaces it with the
+ * LU decomposition of a row-wise permutation of itself. The input
+ * parameters are "matrix0" and "dim". The array "matrix0" is also
+ * an output parameter. The vector "row_perm[]" is an output
+ * parameter that contains the row permutations resulting from partial
+ * pivoting. The output parameter "even_row_xchg" is 1 when the
+ * number of row exchanges is even, or -1 otherwise. Assumes data
+ * type is always double.
+ *
+ * @return true if the matrix is nonsingular, or false otherwise.
+ */
+ //
+ // Reference: Press, Flannery, Teukolsky, Vetterling,
+ // _Numerical_Recipes_in_C_, Cambridge University Press,
+ // 1988, pp 40-45.
+ //
+ static boolean luDecomposition(int dim, double[] matrix0,
+ int[] row_perm, int[] even_row_xchg) {
+
+ double row_scale[] = new double[dim];
+
+ // Determine implicit scaling information by looping over rows
+ int i, j;
+ int ptr, rs, mtx;
+ double big, temp;
+
+ ptr = 0;
+ rs = 0;
+ even_row_xchg[0] = 1;
+
+ // For each row ...
+ i = dim;
+ while (i-- != 0) {
+ big = 0.0;
+
+ // For each column, find the largest element in the row
+ j = dim;
+ while (j-- != 0) {
+ temp = matrix0[ptr++];
+ temp = Math.abs(temp);
+ if (temp > big) {
+ big = temp;
+ }
+ }
+
+ // Is the matrix singular?
+ if (big == 0.0) {
+ return false;
+ }
+ row_scale[rs++] = 1.0 / big;
+ }
+
+ // For all columns, execute Crout's method
+ mtx = 0;
+ for (j = 0; j < dim; j++) {
+ int imax, k;
+ int target, p1, p2;
+ double sum;
+
+ // Determine elements of upper diagonal matrix U
+ for (i = 0; i < j; i++) {
+ target = mtx + (dim*i) + j;
+ sum = matrix0[target];
+ k = i;
+ p1 = mtx + (dim*i);
+ p2 = mtx + j;
+ while (k-- != 0) {
+ sum -= matrix0[p1] * matrix0[p2];
+ p1++;
+ p2 += dim;
+ }
+ matrix0[target] = sum;
+ }
+
+ // Search for largest pivot element and calculate
+ // intermediate elements of lower diagonal matrix L.
+ big = 0.0;
+ imax = -1;
+ for (i = j; i < dim; i++) {
+ target = mtx + (dim*i) + j;
+ sum = matrix0[target];
+ k = j;
+ p1 = mtx + (dim*i);
+ p2 = mtx + j;
+ while (k-- != 0) {
+ sum -= matrix0[p1] * matrix0[p2];
+ p1++;
+ p2 += dim;
+ }
+ matrix0[target] = sum;
+
+ // Is this the best pivot so far?
+ if ((temp = row_scale[i] * Math.abs(sum)) >= big) {
+ big = temp;
+ imax = i;
+ }
+ }
+
+ if (imax < 0) {
+ throw new RuntimeException(VecMathI18N.getString("GMatrix24"));
+ }
+
+ // Is a row exchange necessary?
+ if (j != imax) {
+ // Yes: exchange rows
+ k = dim;
+ p1 = mtx + (dim*imax);
+ p2 = mtx + (dim*j);
+ while (k-- != 0) {
+ temp = matrix0[p1];
+ matrix0[p1++] = matrix0[p2];
+ matrix0[p2++] = temp;
+ }
+
+ // Record change in scale factor
+ row_scale[imax] = row_scale[j];
+ even_row_xchg[0] = -even_row_xchg[0]; // change exchange parity
+ }
+
+ // Record row permutation
+ row_perm[j] = imax;
+
+ // Is the matrix singular
+ if (matrix0[(mtx + (dim*j) + j)] == 0.0) {
+ return false;
+ }
+
+ // Divide elements of lower diagonal matrix L by pivot
+ if (j != (dim-1)) {
+ temp = 1.0 / (matrix0[(mtx + (dim*j) + j)]);
+ target = mtx + (dim*(j+1)) + j;
+ i = (dim-1) - j;
+ while (i-- != 0) {
+ matrix0[target] *= temp;
+ target += dim;
+ }
+ }
+
+ }
+
+ return true;
+ }
+
+ /**
+ * Solves a set of linear equations. The input parameters "matrix1",
+ * and "row_perm" come from luDecompostion and do not change
+ * here. The parameter "matrix2" is a set of column vectors assembled
+ * into a nxn matrix of floating-point values. The procedure takes each
+ * column of "matrix2" in turn and treats it as the right-hand side of the
+ * matrix equation Ax = LUx = b. The solution vector replaces the
+ * original column of the matrix.
+ *
+ * If "matrix2" is the identity matrix, the procedure replaces its contents
+ * with the inverse of the matrix from which "matrix1" was originally
+ * derived.
+ */
+ //
+ // Reference: Press, Flannery, Teukolsky, Vetterling,
+ // _Numerical_Recipes_in_C_, Cambridge University Press,
+ // 1988, pp 44-45.
+ //
+ static void luBacksubstitution(int dim, double[] matrix1,
+ int[] row_perm,
+ double[] matrix2) {
+
+ int i, ii, ip, j, k;
+ int rp;
+ int cv, rv, ri;
+ double tt;
+
+ // rp = row_perm;
+ rp = 0;
+
+ // For each column vector of matrix2 ...
+ for (k = 0; k < dim; k++) {
+ // cv = &(matrix2[0][k]);
+ cv = k;
+ ii = -1;
+
+ // Forward substitution
+ for (i = 0; i < dim; i++) {
+ double sum;
+
+ ip = row_perm[rp+i];
+ sum = matrix2[cv+dim*ip];
+ matrix2[cv+dim*ip] = matrix2[cv+dim*i];
+ if (ii >= 0) {
+ // rv = &(matrix1[i][0]);
+ rv = i*dim;
+ for (j = ii; j <= i-1; j++) {
+ sum -= matrix1[rv+j] * matrix2[cv+dim*j];
+ }
+ }
+ else if (sum != 0.0) {
+ ii = i;
+ }
+ matrix2[cv+dim*i] = sum;
+ }
+
+ // Backsubstitution
+ for (i = 0; i < dim; i++) {
+ ri = (dim-1-i);
+ rv = dim*(ri);
+ tt = 0.0;
+ for(j=1;j<=i;j++) {
+ tt += matrix1[rv+dim-j] * matrix2[cv+dim*(dim-j)];
+ }
+ matrix2[cv+dim*ri]= (matrix2[cv+dim*ri] - tt) / matrix1[rv+ri];
+ }
+ }
+ }
+
+ static int computeSVD(GMatrix mat, GMatrix U, GMatrix W, GMatrix V) {
+ int i, j, k;
+ int nr, nc, si;
+
+ int converged, rank;
+ double cs, sn, r, mag,scale, t;
+ int eLength, sLength, vecLength;
+
+ GMatrix tmp = new GMatrix(mat.nRow, mat.nCol);
+ GMatrix u = new GMatrix(mat.nRow, mat.nCol);
+ GMatrix v = new GMatrix(mat.nRow, mat.nCol);
+ GMatrix m = new GMatrix(mat);
+
+ // compute the number of singular values
+ if (m.nRow >= m.nCol) {
+ sLength = m.nCol;
+ eLength = m.nCol-1;
+ }else {
+ sLength = m.nRow;
+ eLength = m.nRow;
+ }
+
+ if (m.nRow > m.nCol)
+ vecLength = m.nRow;
+ else
+ vecLength = m.nCol;
+
+ double[] vec = new double[vecLength];
+ double[] single_values = new double[sLength];
+ double[] e = new double[eLength];
+
+ if(debug) {
+ System.out.println("input to compute_svd = \n"+m.toString());
+ }
+
+ rank = 0;
+
+ U.setIdentity();
+ V.setIdentity();
+
+ nr = m.nRow;
+ nc = m.nCol;
+
+ // householder reduction
+ for (si = 0; si < sLength; si++) {
+ // for each singular value
+
+ if (nr > 1) {
+ // zero out column
+ if (debug)
+ System.out.println
+ ("*********************** U ***********************\n");
+
+ // compute reflector
+ mag = 0.0;
+ for (i = 0; i < nr; i++) {
+ mag += m.values[i+si][si] * m.values[i+si][si];
+ if (debug)
+ System.out.println
+ ("mag = " + mag + " matrix.dot = " +
+ m.values[i+si][si] * m.values[i+si][si]);
+ }
+
+ mag = Math.sqrt(mag);
+ if (m.values[si][si] == 0.0) {
+ vec[0] = mag;
+ } else {
+ vec[0] = m.values[si][si] + d_sign(mag, m.values[si][si]);
+ }
+
+ for (i = 1; i < nr; i++) {
+ vec[i] = m.values[si+i][si];
+ }
+
+ scale = 0.0;
+ for (i = 0; i < nr; i++) {
+ if (debug)
+ System.out.println("vec["+i+"]="+vec[i]);
+
+ scale += vec[i]*vec[i];
+ }
+
+ scale = 2.0/scale;
+ if (debug)
+ System.out.println("scale = "+scale);
+
+ for (j = si; j < m.nRow; j++) {
+ for (k = si; k < m.nRow; k++) {
+ u.values[j][k] = -scale * vec[j-si]*vec[k-si];
+ }
+ }
+
+ for (i = si; i < m.nRow; i++){
+ u.values[i][i] += 1.0;
+ }
+
+ // compute s
+ t = 0.0;
+ for (i = si; i < m.nRow; i++){
+ t += u.values[si][i] * m.values[i][si];
+ }
+ m.values[si][si] = t;
+
+ // apply reflector
+ for (j = si; j < m.nRow; j++) {
+ for (k = si+1; k < m.nCol; k++) {
+ tmp.values[j][k] = 0.0;
+ for (i = si; i < m.nCol; i++) {
+ tmp.values[j][k] += u.values[j][i] * m.values[i][k];
+ }
+ }
+ }
+
+ for (j = si; j < m.nRow; j++) {
+ for (k = si+1; k < m.nCol; k++) {
+ m.values[j][k] = tmp.values[j][k];
+ }
+ }
+
+ if (debug) {
+ System.out.println("U =\n" + U.toString());
+ System.out.println("u =\n" + u.toString());
+ }
+
+ // update U matrix
+ for (j = si; j < m.nRow; j++) {
+ for (k = 0; k < m.nCol; k++) {
+ tmp.values[j][k] = 0.0;
+ for (i = si; i < m.nCol; i++) {
+ tmp.values[j][k] += u.values[j][i] * U.values[i][k];
+ }
+ }
+ }
+
+ for (j = si; j < m.nRow; j++) {
+ for (k = 0; k < m.nCol; k++) {
+ U.values[j][k] = tmp.values[j][k];
+ }
+ }
+
+ if (debug) {
+ System.out.println("single_values["+si+"] =\n" +
+ single_values[si]);
+ System.out.println("m =\n" + m.toString());
+ System.out.println("U =\n" + U.toString());
+ }
+
+ nr--;
+ }
+
+ if( nc > 2 ) {
+ // zero out row
+ if (debug)
+ System.out.println
+ ("*********************** V ***********************\n");
+
+ mag = 0.0;
+ for (i = 1; i < nc; i++){
+ mag += m.values[si][si+i] * m.values[si][si+i];
+ }
+
+ if (debug)
+ System.out.println("mag = " + mag);
+
+ // generate the reflection vector, compute the first entry and
+ // copy the rest from the row to be zeroed
+ mag = Math.sqrt(mag);
+ if (m.values[si][si+1] == 0.0) {
+ vec[0] = mag;
+ } else {
+ vec[0] = m.values[si][si+1] +
+ d_sign(mag, m.values[si][si+1]);
+ }
+
+ for (i = 1; i < nc - 1; i++){
+ vec[i] = m.values[si][si+i+1];
+ }
+
+ // use reflection vector to compute v matrix
+ scale = 0.0;
+ for (i = 0; i < nc - 1; i++){
+ if( debug )System.out.println("vec["+i+"]="+vec[i]);
+ scale += vec[i]*vec[i];
+ }
+
+ scale = 2.0/scale;
+ if (debug)
+ System.out.println("scale = "+scale);
+
+ for (j = si + 1; j < nc; j++) {
+ for (k = si+1; k < m.nCol; k++) {
+ v.values[j][k] = -scale * vec[j-si-1]*vec[k-si-1];
+ }
+ }
+
+ for (i = si + 1; i < m.nCol; i++){
+ v.values[i][i] += 1.0;
+ }
+
+ t=0.0;
+ for (i = si; i < m.nCol; i++){
+ t += v.values[i][si+1] * m.values[si][i];
+ }
+ m.values[si][si+1]=t;
+
+ // apply reflector
+ for (j = si + 1; j < m.nRow; j++) {
+ for (k = si + 1; k < m.nCol; k++) {
+ tmp.values[j][k] = 0.0;
+ for (i = si + 1; i < m.nCol; i++) {
+ tmp.values[j][k] += v.values[i][k] * m.values[j][i];
+ }
+ }
+ }
+
+ for (j = si + 1; j < m.nRow; j++) {
+ for (k = si + 1; k < m.nCol; k++) {
+ m.values[j][k] = tmp.values[j][k];
+ }
+ }
+
+ if (debug) {
+ System.out.println("V =\n" + V.toString());
+ System.out.println("v =\n" + v.toString());
+ System.out.println("tmp =\n" + tmp.toString());
+ }
+
+ // update V matrix
+ for (j = 0; j < m.nRow; j++) {
+ for (k = si + 1; k < m.nCol; k++) {
+ tmp.values[j][k] = 0.0;
+ for (i = si + 1; i < m.nCol; i++) {
+ tmp.values[j][k] += v.values[i][k] * V.values[j][i];
+ }
+ }
+ }
+
+ if (debug)
+ System.out.println("tmp =\n" + tmp.toString());
+
+ for (j = 0;j < m.nRow; j++) {
+ for (k = si + 1; k < m.nCol; k++) {
+ V.values[j][k] = tmp.values[j][k];
+ }
+ }
+
+ if (debug) {
+ System.out.println("m =\n" + m.toString());
+ System.out.println("V =\n" + V.toString());
+ }
+
+ nc--;
+ }
+ }
+
+ for (i = 0; i < sLength; i++){
+ single_values[i] = m.values[i][i];
+ }
+
+ for (i = 0; i < eLength; i++){
+ e[i] = m.values[i][i+1];
+ }
+
+ // Fix ArrayIndexOutOfBounds for 2x2 matrices, which partially
+ // addresses bug 4348562 for J3D 1.2.1.
+ //
+ // Does *not* fix the following problems reported in 4348562,
+ // which will wait for J3D 1.3:
+ //
+ // 1) no output of W
+ // 2) wrong transposition of U
+ // 3) wrong results for 4x4 matrices
+ // 4) slow performance
+ if (m.nRow == 2 && m.nCol == 2) {
+ double[] cosl = new double[1];
+ double[] cosr = new double[1];
+ double[] sinl = new double[1];
+ double[] sinr = new double[1];
+
+ compute_2X2(single_values[0], e[0], single_values[1],
+ single_values, sinl, cosl, sinr, cosr, 0);
+
+ update_u(0, U, cosl, sinl);
+ update_v(0, V, cosr, sinr);
+
+ return 2;
+ }
+
+ // compute_qr causes ArrayIndexOutOfBounds for 2x2 matrices
+ compute_qr (0, e.length-1, single_values, e, U, V);
+
+ // compute rank = number of non zero singular values
+ rank = single_values.length;
+
+ // sort by order of size of single values
+ // and check for zero's
+ return rank;
+ }
+
+ static void compute_qr(int start, int end, double[] s, double[] e,
+ GMatrix u, GMatrix v) {
+
+ int i, j, k, n, sl;
+ boolean converged;
+ double shift, r, utemp, vtemp, f, g;
+ double[] cosl = new double[1];
+ double[] cosr = new double[1];
+ double[] sinl = new double[1];
+ double[] sinr = new double[1];
+ GMatrix m = new GMatrix(u.nCol, v.nRow);
+
+ final int MAX_INTERATIONS = 2;
+ final double CONVERGE_TOL = 4.89E-15;
+
+ if (debug) {
+ System.out.println("start =" + start);
+ System.out.println("s =\n");
+ for(i=0;i<s.length;i++) {
+ System.out.println(s[i]);
+ }
+
+ System.out.println("\nes =\n");
+ for (i = 0; i < e.length; i++) {
+ System.out.println(e[i]);
+ }
+
+ for (i = 0; i < s.length; i++) {
+ m.values[i][i] = s[i];
+ }
+
+ for (i = 0; i < e.length; i++) {
+ m.values[i][i+1] = e[i];
+ }
+ System.out.println("\nm =\n" + m.toString());
+ }
+
+ double c_b48 = 1.0;
+ double c_b71 = -1.0;
+ converged = false;
+
+ if (debug)
+ print_svd(s, e, u, v);
+
+ f = 0.0;
+ g = 0.0;
+
+ for (k = 0; k < MAX_INTERATIONS && !converged;k++) {
+ for (i = start; i <= end; i++) {
+
+ // if at start of iterfaction compute shift
+ if (i == start) {
+ if (e.length == s.length)
+ sl = end;
+ else
+ sl = end + 1;
+
+ shift = compute_shift(s[sl-1], e[end], s[sl]);
+
+ f = (Math.abs(s[i]) - shift) *
+ (d_sign(c_b48, s[i]) + shift/s[i]);
+ g = e[i];
+ }
+
+ r = compute_rot(f, g, sinr, cosr);
+ if (i != start)
+ e[i-1] = r;
+
+ f = cosr[0] * s[i] + sinr[0] * e[i];
+ e[i] = cosr[0] * e[i] - sinr[0] * s[i];
+ g = sinr[0] * s[i+1];
+ s[i+1] = cosr[0] * s[i+1];
+
+ // if (debug) print_se(s,e);
+ update_v (i, v, cosr, sinr);
+ if (debug)
+ print_m(m,u,v);
+
+ r = compute_rot(f, g, sinl, cosl);
+ s[i] = r;
+ f = cosl[0] * e[i] + sinl[0] * s[i+1];
+ s[i+1] = cosl[0] * s[i+1] - sinl[0] * e[i];
+
+ if( i < end) {
+ // if not last
+ g = sinl[0] * e[i+1];
+ e[i+1] = cosl[0] * e[i+1];
+ }
+ //if (debug) print_se(s,e);
+
+ update_u(i, u, cosl, sinl);
+ if (debug)
+ print_m(m,u,v);
+ }
+
+ // if extra off diagonal perform one more right side rotation
+ if (s.length == e.length) {
+ r = compute_rot(f, g, sinr, cosr);
+ f = cosr[0] * s[i] + sinr[0] * e[i];
+ e[i] = cosr[0] * e[i] - sinr[0] * s[i];
+ s[i+1] = cosr[0] * s[i+1];
+
+ update_v(i, v, cosr, sinr);
+ if (debug)
+ print_m(m,u,v);
+ }
+
+ if (debug) {
+ System.out.println
+ ("\n*********************** iteration #" + k +
+ " ***********************\n");
+ print_svd(s, e, u, v);
+ }
+
+ // check for convergence on off diagonals and reduce
+ while ((end-start > 1) && (Math.abs(e[end]) < CONVERGE_TOL)) {
+ end--;
+ }
+
+ // check if need to split
+ for (n = end - 2; n > start; n--) {
+ if (Math.abs(e[n]) < CONVERGE_TOL) { // split
+ compute_qr(n + 1, end, s, e, u, v); // do lower matrix
+ end = n - 1; // do upper matrix
+
+ // check for convergence on off diagonals and reduce
+ while ((end - start > 1) &&
+ (Math.abs(e[end]) < CONVERGE_TOL)) {
+ end--;
+ }
+ }
+ }
+
+ if (debug)
+ System.out.println("start = " + start);
+
+ if ((end - start <= 1) && (Math.abs(e[start+1]) < CONVERGE_TOL)) {
+ converged = true;
+ } else {
+ // check if zero on the diagonal
+ }
+
+ }
+
+ if (debug)
+ System.out.println("\n****call compute_2X2 ********************\n");
+
+ if (Math.abs(e[1]) < CONVERGE_TOL) {
+ compute_2X2(s[start], e[start], s[start+1], s,
+ sinl, cosl, sinr, cosr, 0);
+ e[start] = 0.0;
+ e[start+1] = 0.0;
+ } else {
+ }
+
+ i = start;
+ update_u(i, u, cosl, sinl);
+ update_v(i, v, cosr, sinr);
+
+ if(debug) {
+ System.out.println
+ ("\n*******after call compute_2X2 **********************\n");
+ print_svd(s, e, u, v);
+ }
+
+ return;
+ }
+
+ private static void print_se(double[] s, double[] e) {
+ System.out.println("\ns =" + s[0] + " " + s[1] + " " + s[2]);
+ System.out.println("e =" + e[0] + " " + e[1]);
+ }
+
+ private static void update_v(int index, GMatrix v,
+ double[] cosr, double[] sinr) {
+ int j;
+ double vtemp;
+
+ for (j = 0; j < v.nRow; j++) {
+ vtemp = v.values[j][index];
+ v.values[j][index] =
+ cosr[0]*vtemp + sinr[0]*v.values[j][index+1];
+ v.values[j][index+1] =
+ -sinr[0]*vtemp + cosr[0]*v.values[j][index+1];
+ }
+ }
+
+ private static void chase_up(double[] s, double[] e, int k, GMatrix v) {
+ double f, g, r;
+ double[] cosr = new double[1];
+ double[] sinr = new double[1];
+ int i;
+ GMatrix t = new GMatrix(v.nRow, v.nCol);
+ GMatrix m = new GMatrix(v.nRow, v.nCol);
+
+ if (debug) {
+ m.setIdentity();
+ for (i = 0; i < s.length; i++) {
+ m.values[i][i] = s[i];
+ }
+ for (i = 0; i < e.length; i++) {
+ m.values[i][i+1] = e[i];
+ }
+ }
+
+ f = e[k];
+ g = s[k];
+
+ for (i = k; i > 0; i--) {
+ r = compute_rot(f, g, sinr, cosr);
+ f = -e[i-1] * sinr[0];
+ g = s[i-1];
+ s[i] = r;
+ e[i-1] = e[i-1] * cosr[0];
+ update_v_split(i, k+1, v, cosr, sinr, t, m);
+ }
+
+ s[i+1] = compute_rot(f, g, sinr, cosr);
+ update_v_split(i, k+1, v, cosr, sinr, t, m);
+ }
+
+ private static void chase_across(double[] s, double[] e, int k, GMatrix u) {
+ double f, g, r;
+ double[] cosl = new double[1];
+ double[] sinl = new double[1];
+ int i;
+ GMatrix t = new GMatrix(u.nRow, u.nCol);
+ GMatrix m = new GMatrix(u.nRow, u.nCol);
+
+ if (debug) {
+ m.setIdentity();
+ for (i = 0; i < s.length; i++) {
+ m.values[i][i] = s[i];
+ }
+ for (i = 0; i < e.length; i++) {
+ m.values[i][i+1] = e[i];
+ }
+ }
+
+ g = e[k];
+ f = s[k+1];
+
+ for (i = k; i < u.nCol-2; i++){
+ r = compute_rot(f, g, sinl, cosl);
+ g = -e[i+1] * sinl[0];
+ f = s[i+2];
+ s[i+1] = r;
+ e[i+1] = e[i+1] * cosl[0];
+ update_u_split(k, i + 1, u, cosl, sinl, t, m);
+ }
+
+ s[i+1] = compute_rot(f, g, sinl, cosl);
+ update_u_split(k, i + 1, u, cosl, sinl, t, m);
+ }
+
+ private static void update_v_split(int topr, int bottomr, GMatrix v,
+ double[] cosr, double[] sinr,
+ GMatrix t, GMatrix m) {
+ int j;
+ double vtemp;
+
+ for (j = 0; j < v.nRow; j++) {
+ vtemp = v.values[j][topr];
+ v.values[j][topr] = cosr[0]*vtemp - sinr[0]*v.values[j][bottomr];
+ v.values[j][bottomr] = sinr[0]*vtemp + cosr[0]*v.values[j][bottomr];
+ }
+
+ if (debug) {
+ t.setIdentity();
+ for (j = 0; j < v.nRow; j++) {
+ vtemp = t.values[j][topr];
+ t.values[j][topr] =
+ cosr[0]*vtemp - sinr[0]*t.values[j][bottomr];
+ t.values[j][bottomr] =
+ sinr[0]*vtemp + cosr[0]*t.values[j][bottomr];
+ }
+ }
+
+ System.out.println("topr =" + topr);
+ System.out.println("bottomr =" + bottomr);
+ System.out.println("cosr =" + cosr[0]);
+ System.out.println("sinr =" + sinr[0]);
+ System.out.println("\nm =");
+ checkMatrix(m);
+ System.out.println("\nv =");
+ checkMatrix(t);
+ m.mul(m,t);
+ System.out.println("\nt*m =");
+ checkMatrix(m);
+ }
+
+ private static void update_u_split(int topr, int bottomr, GMatrix u,
+ double[] cosl, double[] sinl,
+ GMatrix t, GMatrix m) {
+ int j;
+ double utemp;
+
+ for (j = 0; j < u.nCol; j++) {
+ utemp = u.values[topr][j];
+ u.values[topr][j] = cosl[0]*utemp - sinl[0]*u.values[bottomr][j];
+ u.values[bottomr][j] = sinl[0]*utemp + cosl[0]*u.values[bottomr][j];
+ }
+
+ if(debug) {
+ t.setIdentity();
+ for (j = 0;j < u.nCol; j++) {
+ utemp = t.values[topr][j];
+ t.values[topr][j] =
+ cosl[0]*utemp - sinl[0]*t.values[bottomr][j];
+ t.values[bottomr][j] =
+ sinl[0]*utemp + cosl[0]*t.values[bottomr][j];
+ }
+ }
+ System.out.println("\nm=");
+ checkMatrix(m);
+ System.out.println("\nu=");
+ checkMatrix(t);
+ m.mul(t,m);
+ System.out.println("\nt*m=");
+ checkMatrix(m);
+ }
+
+ private static void update_u(int index, GMatrix u,
+ double[] cosl, double[] sinl) {
+ int j;
+ double utemp;
+
+ for (j = 0; j < u.nCol; j++) {
+ utemp = u.values[index][j];
+ u.values[index][j] =
+ cosl[0]*utemp + sinl[0]*u.values[index+1][j];
+ u.values[index+1][j] =
+ -sinl[0]*utemp + cosl[0]*u.values[index+1][j];
+ }
+ }
+
+ private static void print_m(GMatrix m, GMatrix u, GMatrix v) {
+ GMatrix mtmp = new GMatrix(m.nCol, m.nRow);
+
+ mtmp.mul(u, mtmp);
+ mtmp.mul(mtmp, v);
+ System.out.println("\n m = \n" + mtmp.toString(mtmp));
+
+ }
+
+ private static String toString(GMatrix m)
+ {
+ StringBuffer buffer = new StringBuffer(m.nRow * m.nCol * 8);
+ int i, j;
+
+ for (i = 0; i < m.nRow; i++) {
+ for(j = 0; j < m.nCol; j++) {
+ if (Math.abs(m.values[i][j]) < .000000001) {
+ buffer.append("0.0000 ");
+ } else {
+ buffer.append(m.values[i][j]).append(" ");
+ }
+ }
+ buffer.append("\n");
+ }
+ return buffer.toString();
+ }
+
+ private static void print_svd(double[] s, double[] e,
+ GMatrix u, GMatrix v) {
+ int i;
+ GMatrix mtmp = new GMatrix(u.nCol, v.nRow);
+
+ System.out.println(" \ns = ");
+ for (i = 0; i < s.length; i++) {
+ System.out.println(" " + s[i]);
+ }
+
+ System.out.println(" \ne = ");
+ for (i = 0; i < e.length; i++) {
+ System.out.println(" " + e[i]);
+ }
+
+ System.out.println(" \nu = \n" + u.toString());
+ System.out.println(" \nv = \n" + v.toString());
+
+ mtmp.setIdentity();
+ for (i = 0; i < s.length; i++) {
+ mtmp.values[i][i] = s[i];
+ }
+ for (i = 0; i < e.length; i++) {
+ mtmp.values[i][i+1] = e[i];
+ }
+ System.out.println(" \nm = \n"+mtmp.toString());
+
+ mtmp.mulTransposeLeft(u, mtmp);
+ mtmp.mulTransposeRight(mtmp, v);
+
+ System.out.println(" \n u.transpose*m*v.transpose = \n" +
+ mtmp.toString());
+ }
+
+ static double max(double a, double b) {
+ if (a > b)
+ return a;
+ else
+ return b;
+ }
+
+ static double min(double a, double b) {
+ if (a < b)
+ return a;
+ else
+ return b;
+ }
+
+ static double compute_shift(double f, double g, double h) {
+ double d__1, d__2;
+ double fhmn, fhmx, c, fa, ga, ha, as, at, au;
+ double ssmin;
+
+ fa = Math.abs(f);
+ ga = Math.abs(g);
+ ha = Math.abs(h);
+ fhmn = min(fa,ha);
+ fhmx = max(fa,ha);
+
+ if (fhmn == 0.0) {
+ ssmin = 0.0;
+ if (fhmx == 0.0) {
+ } else {
+ d__1 = min(fhmx,ga) / max(fhmx,ga);
+ }
+ } else {
+ if (ga < fhmx) {
+ as = fhmn / fhmx + 1.0;
+ at = (fhmx - fhmn) / fhmx;
+ d__1 = ga / fhmx;
+ au = d__1 * d__1;
+ c = 2.0 / (Math.sqrt(as * as + au) + Math.sqrt(at * at + au));
+ ssmin = fhmn * c;
+ } else {
+ au = fhmx / ga;
+ if (au == 0.0) {
+ ssmin = fhmn * fhmx / ga;
+ } else {
+ as = fhmn / fhmx + 1.0;
+ at = (fhmx - fhmn) / fhmx;
+ d__1 = as * au;
+ d__2 = at * au;
+ c = 1.0 / (Math.sqrt(d__1 * d__1 + 1.0) +
+ Math.sqrt(d__2 * d__2 + 1.0));
+ ssmin = fhmn * c * au;
+ ssmin += ssmin;
+ }
+ }
+ }
+
+ return ssmin;
+ }
+
+ static int compute_2X2(double f, double g, double h,
+ double[] single_values, double[] snl, double[] csl,
+ double[] snr, double[] csr, int index) {
+
+ double c_b3 = 2.0;
+ double c_b4 = 1.0;
+
+ double d__1;
+ int pmax;
+ double temp;
+ boolean swap;
+ double a, d, l, m, r, s, t, tsign, fa, ga, ha;
+ double ft, gt, ht, mm;
+ boolean gasmal;
+ double tt, clt, crt, slt, srt;
+ double ssmin,ssmax;
+
+ ssmax = single_values[0];
+ ssmin = single_values[1];
+ clt = 0.0;
+ crt = 0.0;
+ slt = 0.0;
+ srt = 0.0;
+ tsign = 0.0;
+
+ ft = f;
+ fa = Math.abs(ft);
+ ht = h;
+ ha = Math.abs(h);
+
+ pmax = 1;
+ if (ha > fa)
+ swap = true;
+ else
+ swap = false;
+
+ if (swap) {
+ pmax = 3;
+ temp = ft;
+ ft = ht;
+ ht = temp;
+ temp = fa;
+ fa = ha;
+ ha = temp;
+
+ }
+
+ gt = g;
+ ga = Math.abs(gt);
+ if (ga == 0.0) {
+ single_values[1] = ha;
+ single_values[0] = fa;
+ clt = 1.0;
+ crt = 1.0;
+ slt = 0.0;
+ srt = 0.0;
+ } else {
+ gasmal = true;
+ if (ga > fa) {
+ pmax = 2;
+ if (fa / ga < EPS) {
+ gasmal = false;
+ ssmax = ga;
+
+ if (ha > 1.0) {
+ ssmin = fa / (ga / ha);
+ } else {
+ ssmin = fa / ga * ha;
+ }
+ clt = 1.0;
+ slt = ht / gt;
+ srt = 1.0;
+ crt = ft / gt;
+ }
+ }
+ if (gasmal) {
+ d = fa - ha;
+ if (d == fa) {
+
+ l = 1.0;
+ } else {
+ l = d / fa;
+ }
+
+ m = gt / ft;
+ t = 2.0 - l;
+ mm = m * m;
+ tt = t * t;
+ s = Math.sqrt(tt + mm);
+
+ if (l == 0.0) {
+ r = Math.abs(m);
+ } else {
+ r = Math.sqrt(l * l + mm);
+ }
+
+ a = (s + r) * 0.5;
+ if (ga > fa) {
+ pmax = 2;
+ if (fa / ga < EPS) {
+ gasmal = false;
+ ssmax = ga;
+ if (ha > 1.0) {
+ ssmin = fa / (ga / ha);
+ } else {
+ ssmin = fa / ga * ha;
+ }
+ clt = 1.0;
+ slt = ht / gt;
+ srt = 1.0;
+ crt = ft / gt;
+ }
+ }
+ if (gasmal) {
+ d = fa - ha;
+ if (d == fa) {
+ l = 1.0;
+ } else {
+ l = d / fa;
+ }
+
+ m = gt / ft;
+ t = 2.0 - l;
+
+ mm = m * m;
+ tt = t * t;
+ s = Math.sqrt(tt + mm);
+
+ if (l == 0.) {
+ r = Math.abs(m);
+ } else {
+ r = Math.sqrt(l * l + mm);
+ }
+
+ a = (s + r) * 0.5;
+ ssmin = ha / a;
+ ssmax = fa * a;
+
+ if (mm == 0.0) {
+ if (l == 0.0) {
+ t = d_sign(c_b3, ft) * d_sign(c_b4, gt);
+ } else {
+ t = gt / d_sign(d, ft) + m / t;
+ }
+ } else {
+ t = (m / (s + t) + m / (r + l)) * (a + 1.0);
+ }
+
+ l = Math.sqrt(t * t + 4.0);
+ crt = 2.0 / l;
+ srt = t / l;
+ clt = (crt + srt * m) / a;
+ slt = ht / ft * srt / a;
+ }
+ }
+ if (swap) {
+ csl[0] = srt;
+ snl[0] = crt;
+ csr[0] = slt;
+ snr[0] = clt;
+ } else {
+ csl[0] = clt;
+ snl[0] = slt;
+ csr[0] = crt;
+ snr[0] = srt;
+ }
+
+ if (pmax == 1) {
+ tsign = d_sign(c_b4, csr[0]) *
+ d_sign(c_b4, csl[0]) * d_sign(c_b4, f);
+ }
+ if (pmax == 2) {
+ tsign = d_sign(c_b4, snr[0]) *
+ d_sign(c_b4, csl[0]) * d_sign(c_b4, g);
+ }
+ if (pmax == 3) {
+ tsign = d_sign(c_b4, snr[0]) *
+ d_sign(c_b4, snl[0]) * d_sign(c_b4, h);
+ }
+
+ single_values[index] = d_sign(ssmax, tsign);
+ d__1 = tsign * d_sign(c_b4, f) * d_sign(c_b4, h);
+ single_values[index+1] = d_sign(ssmin, d__1);
+ }
+
+ return 0;
+ }
+
+ static double compute_rot(double f, double g, double[] sin, double[] cos) {
+ int i__1;
+ double d__1, d__2;
+ double cs, sn;
+ int i;
+ double scale;
+ int count;
+ double f1, g1;
+ double r;
+ final double safmn2 = 2.002083095183101E-146;
+ final double safmx2 = 4.994797680505588E+145;
+
+ if (g == 0.0) {
+ cs = 1.0;
+ sn = 0.0;
+ r = f;
+ } else if (f == 0.0) {
+ cs = 0.0;
+ sn = 1.0;
+ r = g;
+ } else {
+ f1 = f;
+ g1 = g;
+ scale = max(Math.abs(f1),Math.abs(g1));
+ if (scale >= safmx2) {
+ count = 0;
+ while(scale >= safmx2) {
+ ++count;
+ f1 *= safmn2;
+ g1 *= safmn2;
+ scale = max(Math.abs(f1), Math.abs(g1));
+ }
+ r = Math.sqrt(f1*f1 + g1*g1);
+ cs = f1 / r;
+ sn = g1 / r;
+ i__1 = count;
+ for (i = 1; i <= count; ++i) {
+ r *= safmx2;
+ }
+ } else if (scale <= safmn2) {
+ count = 0;
+ while(scale <= safmn2) {
+ ++count;
+ f1 *= safmx2;
+ g1 *= safmx2;
+ scale = max(Math.abs(f1), Math.abs(g1));
+ }
+ r = Math.sqrt(f1*f1 + g1*g1);
+ cs = f1 / r;
+ sn = g1 / r;
+ i__1 = count;
+ for (i = 1; i <= count; ++i) {
+ r *= safmn2;
+ }
+ } else {
+ r = Math.sqrt(f1*f1 + g1*g1);
+ cs = f1 / r;
+ sn = g1 / r;
+ }
+ if (Math.abs(f) > Math.abs(g) && cs < 0.0) {
+ cs = -cs;
+ sn = -sn;
+ r = -r;
+ }
+ }
+ sin[0] = sn;
+ cos[0] = cs;
+ return r;
+ }
+
+ static double d_sign(double a, double b) {
+ double x;
+ x = (a >= 0 ? a : - a);
+ return (b >= 0 ? x : -x);
+ }
+
+ /**
+ * Creates a new object of the same class as this object.
+ *
+ * @return a clone of this instance.
+ * @exception OutOfMemoryError if there is not enough memory.
+ * @see java.lang.Cloneable
+ * @since vecmath 1.3
+ */
+ @Override
+ public Object clone() {
+ GMatrix m1 = null;
+ try {
+ m1 = (GMatrix)super.clone();
+ } catch (CloneNotSupportedException e) {
+ // this shouldn't happen, since we are Cloneable
+ throw new InternalError();
+ }
+
+ // Also need to clone array of values
+ m1.values = new double[nRow][nCol];
+ for (int i = 0; i < nRow; i++) {
+ for(int j = 0; j < nCol; j++) {
+ m1.values[i][j] = values[i][j];
+ }
+ }
+
+ return m1;
+ }
+
+}