/** * Internal function call that stores the result of a matrix multiply into the given * destinationMatrix. * * @param multiplicationMatrix matrix to postmultiply this by * @param destinationMatrix matrix to store the matrix multiplication result, must have rows == * this.getNumRows and columns == multiplicationMatrix.getNumColumns */ protected void timesInto( final AbstractMTJMatrix multiplicationMatrix, AbstractMTJMatrix destinationMatrix) { int M = this.getNumRows(); int N = multiplicationMatrix.getNumColumns(); if ((M != destinationMatrix.getNumRows()) || (N != destinationMatrix.getNumColumns())) { throw new DimensionalityMismatchException("Multiplication dimensions do not agree."); } this.internalMatrix.mult(multiplicationMatrix.internalMatrix, destinationMatrix.internalMatrix); }
/** * Solves for "X" in the equation this * X = B, where X is a DenseMatrix, "this" and "B" will be * converted to a DenseMatrix (if not already) * * @param B AbstractMTJMatrix, will be converted to a DenseMatrix * @return DenseMatrix of "X" in this * X = B */ public final Matrix solve(AbstractMTJMatrix B) { DenseMatrix X = new DenseMatrix(this.getNumColumns(), B.getNumColumns()); DenseMatrix Bdense; if (B instanceof DenseMatrix) { Bdense = (DenseMatrix) B; } else { Bdense = new DenseMatrix(B); } DenseMatrix Adense; if (this instanceof DenseMatrix) { Adense = (DenseMatrix) this; } else { Adense = new DenseMatrix(this); } boolean usePseudoInverse = false; try { Adense.solveInto(Bdense, X); usePseudoInverse = false; } catch (MatrixSingularException e) { Logger.getLogger(AbstractMTJMatrix.class.getName()) .log(Level.WARNING, "AbstractMTJMatrix.solve(): Matrix is singular."); usePseudoInverse = true; } // Sometimes LAPACK will return NaNs or infs as the solutions, but MTJ // won't throw the exception, so we need to check for this. // If we detect this, then we'll use a pseudoinverse if (!usePseudoInverse) { for (int i = 0; i < X.getNumRows(); i++) { for (int j = 0; j < X.getNumColumns(); j++) { double v = X.getElement(i, j); if (Double.isNaN(v) || Double.isInfinite(v)) { Logger.getLogger(AbstractMTJMatrix.class.getName()) .log(Level.WARNING, "AbstractMTJMatrix.solve(): Solver produced invalid results."); usePseudoInverse = true; break; } } if (usePseudoInverse) { break; } } } if (usePseudoInverse) { // The original LU solver produced a sucky answer, so let's use // the absurdly expensive SVD least-squares solution return Adense.pseudoInverse().times(Bdense); } return X; }
/** * Internal routine for storing a submatrix into and AbstractMTJMatrix. Gets the embedded * submatrix inside of the Matrix, specified by the inclusive, zero-based indices such that the * result matrix will have size (maxRow-minRow+1) x (maxColum-minCcolumn+1) * * @param minRow Zero-based index into the rows of the Matrix, must be less than or equal to * maxRow * @param maxRow Zero-based index into the rows of the Matrix, must be greater than or equal to * minRow * @param minColumn Zero-based index into the rows of the Matrix, must be less than or equal to * maxColumn * @param maxColumn Zero-based index into the rows of the Matrix, must be greater than or equal to * minColumn * @param destinationMatrix the destination submatrix of dimension * (maxRow-minRow+1)x(maxColumn-minColumn+1) */ protected void getSubMatrixInto( int minRow, int maxRow, int minColumn, int maxColumn, AbstractMTJMatrix destinationMatrix) { if ((destinationMatrix.getNumRows() != (maxRow - minRow + 1)) || (destinationMatrix.getNumColumns() != (maxColumn - minColumn + 1))) { throw new DimensionalityMismatchException("Submatrix is incorrect size."); } for (int i = minRow; i <= maxRow; i++) { for (int j = minColumn; j <= maxColumn; j++) { destinationMatrix.setElement(i - minRow, j - minColumn, this.getElement(i, j)); } } }