| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package org.apache.commons.math.linear; |
| import java.io.Serializable; |
| import java.math.BigDecimal; |
| |
| import org.apache.commons.math.MathRuntimeException; |
| import org.apache.commons.math.exception.util.LocalizedFormats; |
| |
| /** |
| * Implementation of {@link BigMatrix} using a BigDecimal[][] array to store entries |
| * and <a href="http://www.math.gatech.edu/~bourbaki/math2601/Web-notes/2num.pdf"> |
| * LU decompostion</a> to support linear system |
| * solution and inverse. |
| * <p> |
| * The LU decompostion is performed as needed, to support the following operations: <ul> |
| * <li>solve</li> |
| * <li>isSingular</li> |
| * <li>getDeterminant</li> |
| * <li>inverse</li> </ul></p> |
| * <p> |
| * <strong>Usage notes</strong>:<br> |
| * <ul><li> |
| * The LU decomposition is stored and reused on subsequent calls. If matrix |
| * data are modified using any of the public setXxx methods, the saved |
| * decomposition is discarded. If data are modified via references to the |
| * underlying array obtained using <code>getDataRef()</code>, then the stored |
| * LU decomposition will not be discarded. In this case, you need to |
| * explicitly invoke <code>LUDecompose()</code> to recompute the decomposition |
| * before using any of the methods above.</li> |
| * <li> |
| * As specified in the {@link BigMatrix} interface, matrix element indexing |
| * is 0-based -- e.g., <code>getEntry(0, 0)</code> |
| * returns the element in the first row, first column of the matrix.</li></ul></p> |
| * |
| * @deprecated as of 2.0, replaced by {@link Array2DRowFieldMatrix} with a {@link |
| * org.apache.commons.math.util.BigReal} parameter |
| * @version $Revision: 1042376 $ $Date: 2010-12-05 16:54:55 +0100 (dim. 05 déc. 2010) $ |
| */ |
| @Deprecated |
| public class BigMatrixImpl implements BigMatrix, Serializable { |
| |
| /** BigDecimal 0 */ |
| static final BigDecimal ZERO = new BigDecimal(0); |
| |
| /** BigDecimal 1 */ |
| static final BigDecimal ONE = new BigDecimal(1); |
| |
| /** Bound to determine effective singularity in LU decomposition */ |
| private static final BigDecimal TOO_SMALL = new BigDecimal(10E-12); |
| |
| /** Serialization id */ |
| private static final long serialVersionUID = -1011428905656140431L; |
| |
| /** Entries of the matrix */ |
| protected BigDecimal data[][] = null; |
| |
| /** Entries of cached LU decomposition. |
| * All updates to data (other than luDecompose()) *must* set this to null |
| */ |
| protected BigDecimal lu[][] = null; |
| |
| /** Permutation associated with LU decomposition */ |
| protected int[] permutation = null; |
| |
| /** Parity of the permutation associated with the LU decomposition */ |
| protected int parity = 1; |
| |
| /** Rounding mode for divisions **/ |
| private int roundingMode = BigDecimal.ROUND_HALF_UP; |
| |
| /*** BigDecimal scale ***/ |
| private int scale = 64; |
| |
| /** |
| * Creates a matrix with no data |
| */ |
| public BigMatrixImpl() { |
| } |
| |
| /** |
| * Create a new BigMatrix with the supplied row and column dimensions. |
| * |
| * @param rowDimension the number of rows in the new matrix |
| * @param columnDimension the number of columns in the new matrix |
| * @throws IllegalArgumentException if row or column dimension is not |
| * positive |
| */ |
| public BigMatrixImpl(int rowDimension, int columnDimension) { |
| if (rowDimension < 1 ) { |
| throw MathRuntimeException.createIllegalArgumentException( |
| LocalizedFormats.INSUFFICIENT_DIMENSION, rowDimension, 1); |
| } |
| if (columnDimension < 1) { |
| throw MathRuntimeException.createIllegalArgumentException( |
| LocalizedFormats.INSUFFICIENT_DIMENSION, columnDimension, 1); |
| } |
| data = new BigDecimal[rowDimension][columnDimension]; |
| lu = null; |
| } |
| |
| /** |
| * Create a new BigMatrix using <code>d</code> as the underlying |
| * data array. |
| * <p>The input array is copied, not referenced. This constructor has |
| * the same effect as calling {@link #BigMatrixImpl(BigDecimal[][], boolean)} |
| * with the second argument set to <code>true</code>.</p> |
| * |
| * @param d data for new matrix |
| * @throws IllegalArgumentException if <code>d</code> is not rectangular |
| * (not all rows have the same length) or empty |
| * @throws NullPointerException if <code>d</code> is null |
| */ |
| public BigMatrixImpl(BigDecimal[][] d) { |
| this.copyIn(d); |
| lu = null; |
| } |
| |
| /** |
| * Create a new BigMatrix using the input array as the underlying |
| * data array. |
| * <p>If an array is built specially in order to be embedded in a |
| * BigMatrix and not used directly, the <code>copyArray</code> may be |
| * set to <code>false</code. This will prevent the copying and improve |
| * performance as no new array will be built and no data will be copied.</p> |
| * @param d data for new matrix |
| * @param copyArray if true, the input array will be copied, otherwise |
| * it will be referenced |
| * @throws IllegalArgumentException if <code>d</code> is not rectangular |
| * (not all rows have the same length) or empty |
| * @throws NullPointerException if <code>d</code> is null |
| * @see #BigMatrixImpl(BigDecimal[][]) |
| */ |
| public BigMatrixImpl(BigDecimal[][] d, boolean copyArray) { |
| if (copyArray) { |
| copyIn(d); |
| } else { |
| if (d == null) { |
| throw new NullPointerException(); |
| } |
| final int nRows = d.length; |
| if (nRows == 0) { |
| throw MathRuntimeException.createIllegalArgumentException(LocalizedFormats.AT_LEAST_ONE_ROW); |
| } |
| |
| final int nCols = d[0].length; |
| if (nCols == 0) { |
| throw MathRuntimeException.createIllegalArgumentException(LocalizedFormats.AT_LEAST_ONE_COLUMN); |
| } |
| for (int r = 1; r < nRows; r++) { |
| if (d[r].length != nCols) { |
| throw MathRuntimeException.createIllegalArgumentException( |
| LocalizedFormats.DIFFERENT_ROWS_LENGTHS, |
| nCols, d[r].length); |
| } |
| } |
| data = d; |
| } |
| lu = null; |
| } |
| |
| /** |
| * Create a new BigMatrix using <code>d</code> as the underlying |
| * data array. |
| * <p>Since the underlying array will hold <code>BigDecimal</code> |
| * instances, it will be created.</p> |
| * |
| * @param d data for new matrix |
| * @throws IllegalArgumentException if <code>d</code> is not rectangular |
| * (not all rows have the same length) or empty |
| * @throws NullPointerException if <code>d</code> is null |
| */ |
| public BigMatrixImpl(double[][] d) { |
| final int nRows = d.length; |
| if (nRows == 0) { |
| throw MathRuntimeException.createIllegalArgumentException(LocalizedFormats.AT_LEAST_ONE_ROW); |
| } |
| |
| final int nCols = d[0].length; |
| if (nCols == 0) { |
| throw MathRuntimeException.createIllegalArgumentException(LocalizedFormats.AT_LEAST_ONE_COLUMN); |
| } |
| for (int row = 1; row < nRows; row++) { |
| if (d[row].length != nCols) { |
| throw MathRuntimeException.createIllegalArgumentException( |
| LocalizedFormats.DIFFERENT_ROWS_LENGTHS, |
| nCols, d[row].length); |
| } |
| } |
| this.copyIn(d); |
| lu = null; |
| } |
| |
| /** |
| * Create a new BigMatrix using the values represented by the strings in |
| * <code>d</code> as the underlying data array. |
| * |
| * @param d data for new matrix |
| * @throws IllegalArgumentException if <code>d</code> is not rectangular |
| * (not all rows have the same length) or empty |
| * @throws NullPointerException if <code>d</code> is null |
| */ |
| public BigMatrixImpl(String[][] d) { |
| final int nRows = d.length; |
| if (nRows == 0) { |
| throw MathRuntimeException.createIllegalArgumentException(LocalizedFormats.AT_LEAST_ONE_ROW); |
| } |
| |
| final int nCols = d[0].length; |
| if (nCols == 0) { |
| throw MathRuntimeException.createIllegalArgumentException(LocalizedFormats.AT_LEAST_ONE_COLUMN); |
| } |
| for (int row = 1; row < nRows; row++) { |
| if (d[row].length != nCols) { |
| throw MathRuntimeException.createIllegalArgumentException( |
| LocalizedFormats.DIFFERENT_ROWS_LENGTHS, |
| nCols, d[row].length); |
| } |
| } |
| this.copyIn(d); |
| lu = null; |
| } |
| |
| /** |
| * Create a new (column) BigMatrix using <code>v</code> as the |
| * data for the unique column of the <code>v.length x 1</code> matrix |
| * created. |
| * <p> |
| * The input array is copied, not referenced.</p> |
| * |
| * @param v column vector holding data for new matrix |
| */ |
| public BigMatrixImpl(BigDecimal[] v) { |
| final int nRows = v.length; |
| data = new BigDecimal[nRows][1]; |
| for (int row = 0; row < nRows; row++) { |
| data[row][0] = v[row]; |
| } |
| } |
| |
| /** |
| * Create a new BigMatrix which is a copy of this. |
| * |
| * @return the cloned matrix |
| */ |
| public BigMatrix copy() { |
| return new BigMatrixImpl(this.copyOut(), false); |
| } |
| |
| /** |
| * Compute the sum of this and <code>m</code>. |
| * |
| * @param m matrix to be added |
| * @return this + m |
| * @throws IllegalArgumentException if m is not the same size as this |
| */ |
| public BigMatrix add(BigMatrix m) throws IllegalArgumentException { |
| try { |
| return add((BigMatrixImpl) m); |
| } catch (ClassCastException cce) { |
| |
| // safety check |
| MatrixUtils.checkAdditionCompatible(this, m); |
| |
| final int rowCount = getRowDimension(); |
| final int columnCount = getColumnDimension(); |
| final BigDecimal[][] outData = new BigDecimal[rowCount][columnCount]; |
| for (int row = 0; row < rowCount; row++) { |
| final BigDecimal[] dataRow = data[row]; |
| final BigDecimal[] outDataRow = outData[row]; |
| for (int col = 0; col < columnCount; col++) { |
| outDataRow[col] = dataRow[col].add(m.getEntry(row, col)); |
| } |
| } |
| return new BigMatrixImpl(outData, false); |
| } |
| } |
| |
| /** |
| * Compute the sum of this and <code>m</code>. |
| * |
| * @param m matrix to be added |
| * @return this + m |
| * @throws IllegalArgumentException if m is not the same size as this |
| */ |
| public BigMatrixImpl add(BigMatrixImpl m) throws IllegalArgumentException { |
| |
| // safety check |
| MatrixUtils.checkAdditionCompatible(this, m); |
| |
| final int rowCount = getRowDimension(); |
| final int columnCount = getColumnDimension(); |
| final BigDecimal[][] outData = new BigDecimal[rowCount][columnCount]; |
| for (int row = 0; row < rowCount; row++) { |
| final BigDecimal[] dataRow = data[row]; |
| final BigDecimal[] mRow = m.data[row]; |
| final BigDecimal[] outDataRow = outData[row]; |
| for (int col = 0; col < columnCount; col++) { |
| outDataRow[col] = dataRow[col].add(mRow[col]); |
| } |
| } |
| return new BigMatrixImpl(outData, false); |
| } |
| |
| /** |
| * Compute this minus <code>m</code>. |
| * |
| * @param m matrix to be subtracted |
| * @return this + m |
| * @throws IllegalArgumentException if m is not the same size as this |
| */ |
| public BigMatrix subtract(BigMatrix m) throws IllegalArgumentException { |
| try { |
| return subtract((BigMatrixImpl) m); |
| } catch (ClassCastException cce) { |
| |
| // safety check |
| MatrixUtils.checkSubtractionCompatible(this, m); |
| |
| final int rowCount = getRowDimension(); |
| final int columnCount = getColumnDimension(); |
| final BigDecimal[][] outData = new BigDecimal[rowCount][columnCount]; |
| for (int row = 0; row < rowCount; row++) { |
| final BigDecimal[] dataRow = data[row]; |
| final BigDecimal[] outDataRow = outData[row]; |
| for (int col = 0; col < columnCount; col++) { |
| outDataRow[col] = dataRow[col].subtract(getEntry(row, col)); |
| } |
| } |
| return new BigMatrixImpl(outData, false); |
| } |
| } |
| |
| /** |
| * Compute this minus <code>m</code>. |
| * |
| * @param m matrix to be subtracted |
| * @return this + m |
| * @throws IllegalArgumentException if m is not the same size as this |
| */ |
| public BigMatrixImpl subtract(BigMatrixImpl m) throws IllegalArgumentException { |
| |
| // safety check |
| MatrixUtils.checkSubtractionCompatible(this, m); |
| |
| final int rowCount = getRowDimension(); |
| final int columnCount = getColumnDimension(); |
| final BigDecimal[][] outData = new BigDecimal[rowCount][columnCount]; |
| for (int row = 0; row < rowCount; row++) { |
| final BigDecimal[] dataRow = data[row]; |
| final BigDecimal[] mRow = m.data[row]; |
| final BigDecimal[] outDataRow = outData[row]; |
| for (int col = 0; col < columnCount; col++) { |
| outDataRow[col] = dataRow[col].subtract(mRow[col]); |
| } |
| } |
| return new BigMatrixImpl(outData, false); |
| } |
| |
| /** |
| * Returns the result of adding d to each entry of this. |
| * |
| * @param d value to be added to each entry |
| * @return d + this |
| */ |
| public BigMatrix scalarAdd(BigDecimal d) { |
| final int rowCount = getRowDimension(); |
| final int columnCount = getColumnDimension(); |
| final BigDecimal[][] outData = new BigDecimal[rowCount][columnCount]; |
| for (int row = 0; row < rowCount; row++) { |
| final BigDecimal[] dataRow = data[row]; |
| final BigDecimal[] outDataRow = outData[row]; |
| for (int col = 0; col < columnCount; col++) { |
| outDataRow[col] = dataRow[col].add(d); |
| } |
| } |
| return new BigMatrixImpl(outData, false); |
| } |
| |
| /** |
| * Returns the result of multiplying each entry of this by <code>d</code> |
| * @param d value to multiply all entries by |
| * @return d * this |
| */ |
| public BigMatrix scalarMultiply(BigDecimal d) { |
| final int rowCount = getRowDimension(); |
| final int columnCount = getColumnDimension(); |
| final BigDecimal[][] outData = new BigDecimal[rowCount][columnCount]; |
| for (int row = 0; row < rowCount; row++) { |
| final BigDecimal[] dataRow = data[row]; |
| final BigDecimal[] outDataRow = outData[row]; |
| for (int col = 0; col < columnCount; col++) { |
| outDataRow[col] = dataRow[col].multiply(d); |
| } |
| } |
| return new BigMatrixImpl(outData, false); |
| } |
| |
| /** |
| * Returns the result of postmultiplying this by <code>m</code>. |
| * @param m matrix to postmultiply by |
| * @return this*m |
| * @throws IllegalArgumentException |
| * if columnDimension(this) != rowDimension(m) |
| */ |
| public BigMatrix multiply(BigMatrix m) throws IllegalArgumentException { |
| try { |
| return multiply((BigMatrixImpl) m); |
| } catch (ClassCastException cce) { |
| |
| // safety check |
| MatrixUtils.checkMultiplicationCompatible(this, m); |
| |
| final int nRows = this.getRowDimension(); |
| final int nCols = m.getColumnDimension(); |
| final int nSum = this.getColumnDimension(); |
| final BigDecimal[][] outData = new BigDecimal[nRows][nCols]; |
| for (int row = 0; row < nRows; row++) { |
| final BigDecimal[] dataRow = data[row]; |
| final BigDecimal[] outDataRow = outData[row]; |
| for (int col = 0; col < nCols; col++) { |
| BigDecimal sum = ZERO; |
| for (int i = 0; i < nSum; i++) { |
| sum = sum.add(dataRow[i].multiply(m.getEntry(i, col))); |
| } |
| outDataRow[col] = sum; |
| } |
| } |
| return new BigMatrixImpl(outData, false); |
| } |
| } |
| |
| /** |
| * Returns the result of postmultiplying this by <code>m</code>. |
| * @param m matrix to postmultiply by |
| * @return this*m |
| * @throws IllegalArgumentException |
| * if columnDimension(this) != rowDimension(m) |
| */ |
| public BigMatrixImpl multiply(BigMatrixImpl m) throws IllegalArgumentException { |
| |
| // safety check |
| MatrixUtils.checkMultiplicationCompatible(this, m); |
| |
| final int nRows = this.getRowDimension(); |
| final int nCols = m.getColumnDimension(); |
| final int nSum = this.getColumnDimension(); |
| final BigDecimal[][] outData = new BigDecimal[nRows][nCols]; |
| for (int row = 0; row < nRows; row++) { |
| final BigDecimal[] dataRow = data[row]; |
| final BigDecimal[] outDataRow = outData[row]; |
| for (int col = 0; col < nCols; col++) { |
| BigDecimal sum = ZERO; |
| for (int i = 0; i < nSum; i++) { |
| sum = sum.add(dataRow[i].multiply(m.data[i][col])); |
| } |
| outDataRow[col] = sum; |
| } |
| } |
| return new BigMatrixImpl(outData, false); |
| } |
| |
| /** |
| * Returns the result premultiplying this by <code>m</code>. |
| * @param m matrix to premultiply by |
| * @return m * this |
| * @throws IllegalArgumentException |
| * if rowDimension(this) != columnDimension(m) |
| */ |
| public BigMatrix preMultiply(BigMatrix m) throws IllegalArgumentException { |
| return m.multiply(this); |
| } |
| |
| /** |
| * Returns matrix entries as a two-dimensional array. |
| * <p> |
| * Makes a fresh copy of the underlying data.</p> |
| * |
| * @return 2-dimensional array of entries |
| */ |
| public BigDecimal[][] getData() { |
| return copyOut(); |
| } |
| |
| /** |
| * Returns matrix entries as a two-dimensional array. |
| * <p> |
| * Makes a fresh copy of the underlying data converted to |
| * <code>double</code> values.</p> |
| * |
| * @return 2-dimensional array of entries |
| */ |
| public double[][] getDataAsDoubleArray() { |
| final int nRows = getRowDimension(); |
| final int nCols = getColumnDimension(); |
| final double d[][] = new double[nRows][nCols]; |
| for (int i = 0; i < nRows; i++) { |
| for (int j = 0; j < nCols; j++) { |
| d[i][j] = data[i][j].doubleValue(); |
| } |
| } |
| return d; |
| } |
| |
| /** |
| * Returns a reference to the underlying data array. |
| * <p> |
| * Does not make a fresh copy of the underlying data.</p> |
| * |
| * @return 2-dimensional array of entries |
| */ |
| public BigDecimal[][] getDataRef() { |
| return data; |
| } |
| |
| /*** |
| * Gets the rounding mode for division operations |
| * The default is {@link java.math.BigDecimal#ROUND_HALF_UP} |
| * @see BigDecimal |
| * @return the rounding mode. |
| */ |
| public int getRoundingMode() { |
| return roundingMode; |
| } |
| |
| /*** |
| * Sets the rounding mode for decimal divisions. |
| * @see BigDecimal |
| * @param roundingMode rounding mode for decimal divisions |
| */ |
| public void setRoundingMode(int roundingMode) { |
| this.roundingMode = roundingMode; |
| } |
| |
| /*** |
| * Sets the scale for division operations. |
| * The default is 64 |
| * @see BigDecimal |
| * @return the scale |
| */ |
| public int getScale() { |
| return scale; |
| } |
| |
| /*** |
| * Sets the scale for division operations. |
| * @see BigDecimal |
| * @param scale scale for division operations |
| */ |
| public void setScale(int scale) { |
| this.scale = scale; |
| } |
| |
| /** |
| * Returns the <a href="http://mathworld.wolfram.com/MaximumAbsoluteRowSumNorm.html"> |
| * maximum absolute row sum norm</a> of the matrix. |
| * |
| * @return norm |
| */ |
| public BigDecimal getNorm() { |
| BigDecimal maxColSum = ZERO; |
| for (int col = 0; col < this.getColumnDimension(); col++) { |
| BigDecimal sum = ZERO; |
| for (int row = 0; row < this.getRowDimension(); row++) { |
| sum = sum.add(data[row][col].abs()); |
| } |
| maxColSum = maxColSum.max(sum); |
| } |
| return maxColSum; |
| } |
| |
| /** |
| * Gets a submatrix. Rows and columns are indicated |
| * counting from 0 to n-1. |
| * |
| * @param startRow Initial row index |
| * @param endRow Final row index |
| * @param startColumn Initial column index |
| * @param endColumn Final column index |
| * @return The subMatrix containing the data of the |
| * specified rows and columns |
| * @exception MatrixIndexException if row or column selections are not valid |
| */ |
| public BigMatrix getSubMatrix(int startRow, int endRow, |
| int startColumn, int endColumn) |
| throws MatrixIndexException { |
| |
| MatrixUtils.checkRowIndex(this, startRow); |
| MatrixUtils.checkRowIndex(this, endRow); |
| if (startRow > endRow) { |
| throw new MatrixIndexException(LocalizedFormats.INITIAL_ROW_AFTER_FINAL_ROW, |
| startRow, endRow); |
| } |
| |
| MatrixUtils.checkColumnIndex(this, startColumn); |
| MatrixUtils.checkColumnIndex(this, endColumn); |
| if (startColumn > endColumn) { |
| throw new MatrixIndexException(LocalizedFormats.INITIAL_COLUMN_AFTER_FINAL_COLUMN, |
| startColumn, endColumn); |
| } |
| |
| final BigDecimal[][] subMatrixData = |
| new BigDecimal[endRow - startRow + 1][endColumn - startColumn + 1]; |
| for (int i = startRow; i <= endRow; i++) { |
| System.arraycopy(data[i], startColumn, |
| subMatrixData[i - startRow], 0, |
| endColumn - startColumn + 1); |
| } |
| |
| return new BigMatrixImpl(subMatrixData, false); |
| |
| } |
| |
| /** |
| * Gets a submatrix. Rows and columns are indicated |
| * counting from 0 to n-1. |
| * |
| * @param selectedRows Array of row indices must be non-empty |
| * @param selectedColumns Array of column indices must be non-empty |
| * @return The subMatrix containing the data in the |
| * specified rows and columns |
| * @exception MatrixIndexException if supplied row or column index arrays |
| * are not valid |
| */ |
| public BigMatrix getSubMatrix(int[] selectedRows, int[] selectedColumns) |
| throws MatrixIndexException { |
| |
| if (selectedRows.length * selectedColumns.length == 0) { |
| if (selectedRows.length == 0) { |
| throw new MatrixIndexException(LocalizedFormats.EMPTY_SELECTED_ROW_INDEX_ARRAY); |
| } |
| throw new MatrixIndexException(LocalizedFormats.EMPTY_SELECTED_COLUMN_INDEX_ARRAY); |
| } |
| |
| final BigDecimal[][] subMatrixData = |
| new BigDecimal[selectedRows.length][selectedColumns.length]; |
| try { |
| for (int i = 0; i < selectedRows.length; i++) { |
| final BigDecimal[] subI = subMatrixData[i]; |
| final BigDecimal[] dataSelectedI = data[selectedRows[i]]; |
| for (int j = 0; j < selectedColumns.length; j++) { |
| subI[j] = dataSelectedI[selectedColumns[j]]; |
| } |
| } |
| } catch (ArrayIndexOutOfBoundsException e) { |
| // we redo the loop with checks enabled |
| // in order to generate an appropriate message |
| for (final int row : selectedRows) { |
| MatrixUtils.checkRowIndex(this, row); |
| } |
| for (final int column : selectedColumns) { |
| MatrixUtils.checkColumnIndex(this, column); |
| } |
| } |
| return new BigMatrixImpl(subMatrixData, false); |
| } |
| |
| /** |
| * Replace the submatrix starting at <code>row, column</code> using data in |
| * the input <code>subMatrix</code> array. Indexes are 0-based. |
| * <p> |
| * Example:<br> |
| * Starting with <pre> |
| * 1 2 3 4 |
| * 5 6 7 8 |
| * 9 0 1 2 |
| * </pre> |
| * and <code>subMatrix = {{3, 4} {5,6}}</code>, invoking |
| * <code>setSubMatrix(subMatrix,1,1))</code> will result in <pre> |
| * 1 2 3 4 |
| * 5 3 4 8 |
| * 9 5 6 2 |
| * </pre></p> |
| * |
| * @param subMatrix array containing the submatrix replacement data |
| * @param row row coordinate of the top, left element to be replaced |
| * @param column column coordinate of the top, left element to be replaced |
| * @throws MatrixIndexException if subMatrix does not fit into this |
| * matrix from element in (row, column) |
| * @throws IllegalArgumentException if <code>subMatrix</code> is not rectangular |
| * (not all rows have the same length) or empty |
| * @throws NullPointerException if <code>subMatrix</code> is null |
| * @since 1.1 |
| */ |
| public void setSubMatrix(BigDecimal[][] subMatrix, int row, int column) |
| throws MatrixIndexException { |
| |
| final int nRows = subMatrix.length; |
| if (nRows == 0) { |
| throw MathRuntimeException.createIllegalArgumentException(LocalizedFormats.AT_LEAST_ONE_ROW); |
| } |
| |
| final int nCols = subMatrix[0].length; |
| if (nCols == 0) { |
| throw MathRuntimeException.createIllegalArgumentException(LocalizedFormats.AT_LEAST_ONE_COLUMN); |
| } |
| |
| for (int r = 1; r < nRows; r++) { |
| if (subMatrix[r].length != nCols) { |
| throw MathRuntimeException.createIllegalArgumentException( |
| LocalizedFormats.DIFFERENT_ROWS_LENGTHS, |
| nCols, subMatrix[r].length); |
| } |
| } |
| |
| if (data == null) { |
| if (row > 0) { |
| throw MathRuntimeException.createIllegalStateException( |
| LocalizedFormats.FIRST_ROWS_NOT_INITIALIZED_YET, |
| row); |
| } |
| if (column > 0) { |
| throw MathRuntimeException.createIllegalStateException( |
| LocalizedFormats.FIRST_COLUMNS_NOT_INITIALIZED_YET, |
| column); |
| } |
| data = new BigDecimal[nRows][nCols]; |
| System.arraycopy(subMatrix, 0, data, 0, subMatrix.length); |
| } else { |
| MatrixUtils.checkRowIndex(this, row); |
| MatrixUtils.checkColumnIndex(this, column); |
| MatrixUtils.checkRowIndex(this, nRows + row - 1); |
| MatrixUtils.checkColumnIndex(this, nCols + column - 1); |
| } |
| for (int i = 0; i < nRows; i++) { |
| System.arraycopy(subMatrix[i], 0, data[row + i], column, nCols); |
| } |
| |
| lu = null; |
| |
| } |
| |
| /** |
| * Returns the entries in row number <code>row</code> |
| * as a row matrix. Row indices start at 0. |
| * |
| * @param row the row to be fetched |
| * @return row matrix |
| * @throws MatrixIndexException if the specified row index is invalid |
| */ |
| public BigMatrix getRowMatrix(int row) throws MatrixIndexException { |
| MatrixUtils.checkRowIndex(this, row); |
| final int ncols = this.getColumnDimension(); |
| final BigDecimal[][] out = new BigDecimal[1][ncols]; |
| System.arraycopy(data[row], 0, out[0], 0, ncols); |
| return new BigMatrixImpl(out, false); |
| } |
| |
| /** |
| * Returns the entries in column number <code>column</code> |
| * as a column matrix. Column indices start at 0. |
| * |
| * @param column the column to be fetched |
| * @return column matrix |
| * @throws MatrixIndexException if the specified column index is invalid |
| */ |
| public BigMatrix getColumnMatrix(int column) throws MatrixIndexException { |
| MatrixUtils.checkColumnIndex(this, column); |
| final int nRows = this.getRowDimension(); |
| final BigDecimal[][] out = new BigDecimal[nRows][1]; |
| for (int row = 0; row < nRows; row++) { |
| out[row][0] = data[row][column]; |
| } |
| return new BigMatrixImpl(out, false); |
| } |
| |
| /** |
| * Returns the entries in row number <code>row</code> as an array. |
| * <p> |
| * Row indices start at 0. A <code>MatrixIndexException</code> is thrown |
| * unless <code>0 <= row < rowDimension.</code></p> |
| * |
| * @param row the row to be fetched |
| * @return array of entries in the row |
| * @throws MatrixIndexException if the specified row index is not valid |
| */ |
| public BigDecimal[] getRow(int row) throws MatrixIndexException { |
| MatrixUtils.checkRowIndex(this, row); |
| final int ncols = this.getColumnDimension(); |
| final BigDecimal[] out = new BigDecimal[ncols]; |
| System.arraycopy(data[row], 0, out, 0, ncols); |
| return out; |
| } |
| |
| /** |
| * Returns the entries in row number <code>row</code> as an array |
| * of double values. |
| * <p> |
| * Row indices start at 0. A <code>MatrixIndexException</code> is thrown |
| * unless <code>0 <= row < rowDimension.</code></p> |
| * |
| * @param row the row to be fetched |
| * @return array of entries in the row |
| * @throws MatrixIndexException if the specified row index is not valid |
| */ |
| public double[] getRowAsDoubleArray(int row) throws MatrixIndexException { |
| MatrixUtils.checkRowIndex(this, row); |
| final int ncols = this.getColumnDimension(); |
| final double[] out = new double[ncols]; |
| for (int i=0;i<ncols;i++) { |
| out[i] = data[row][i].doubleValue(); |
| } |
| return out; |
| } |
| |
| /** |
| * Returns the entries in column number <code>col</code> as an array. |
| * <p> |
| * Column indices start at 0. A <code>MatrixIndexException</code> is thrown |
| * unless <code>0 <= column < columnDimension.</code></p> |
| * |
| * @param col the column to be fetched |
| * @return array of entries in the column |
| * @throws MatrixIndexException if the specified column index is not valid |
| */ |
| public BigDecimal[] getColumn(int col) throws MatrixIndexException { |
| MatrixUtils.checkColumnIndex(this, col); |
| final int nRows = this.getRowDimension(); |
| final BigDecimal[] out = new BigDecimal[nRows]; |
| for (int i = 0; i < nRows; i++) { |
| out[i] = data[i][col]; |
| } |
| return out; |
| } |
| |
| /** |
| * Returns the entries in column number <code>col</code> as an array |
| * of double values. |
| * <p> |
| * Column indices start at 0. A <code>MatrixIndexException</code> is thrown |
| * unless <code>0 <= column < columnDimension.</code></p> |
| * |
| * @param col the column to be fetched |
| * @return array of entries in the column |
| * @throws MatrixIndexException if the specified column index is not valid |
| */ |
| public double[] getColumnAsDoubleArray(int col) throws MatrixIndexException { |
| MatrixUtils.checkColumnIndex(this, col); |
| final int nrows = this.getRowDimension(); |
| final double[] out = new double[nrows]; |
| for (int i=0;i<nrows;i++) { |
| out[i] = data[i][col].doubleValue(); |
| } |
| return out; |
| } |
| |
| /** |
| * Returns the entry in the specified row and column. |
| * <p> |
| * Row and column indices start at 0 and must satisfy |
| * <ul> |
| * <li><code>0 <= row < rowDimension</code></li> |
| * <li><code> 0 <= column < columnDimension</code></li> |
| * </ul> |
| * otherwise a <code>MatrixIndexException</code> is thrown.</p> |
| * |
| * @param row row location of entry to be fetched |
| * @param column column location of entry to be fetched |
| * @return matrix entry in row,column |
| * @throws MatrixIndexException if the row or column index is not valid |
| */ |
| public BigDecimal getEntry(int row, int column) |
| throws MatrixIndexException { |
| try { |
| return data[row][column]; |
| } catch (ArrayIndexOutOfBoundsException e) { |
| throw new MatrixIndexException( |
| LocalizedFormats.NO_SUCH_MATRIX_ENTRY, |
| row, column, getRowDimension(), getColumnDimension()); |
| } |
| } |
| |
| /** |
| * Returns the entry in the specified row and column as a double. |
| * <p> |
| * Row and column indices start at 0 and must satisfy |
| * <ul> |
| * <li><code>0 <= row < rowDimension</code></li> |
| * <li><code> 0 <= column < columnDimension</code></li> |
| * </ul> |
| * otherwise a <code>MatrixIndexException</code> is thrown.</p> |
| * |
| * @param row row location of entry to be fetched |
| * @param column column location of entry to be fetched |
| * @return matrix entry in row,column |
| * @throws MatrixIndexException if the row |
| * or column index is not valid |
| */ |
| public double getEntryAsDouble(int row, int column) throws MatrixIndexException { |
| return getEntry(row,column).doubleValue(); |
| } |
| |
| /** |
| * Returns the transpose matrix. |
| * |
| * @return transpose matrix |
| */ |
| public BigMatrix transpose() { |
| final int nRows = this.getRowDimension(); |
| final int nCols = this.getColumnDimension(); |
| final BigDecimal[][] outData = new BigDecimal[nCols][nRows]; |
| for (int row = 0; row < nRows; row++) { |
| final BigDecimal[] dataRow = data[row]; |
| for (int col = 0; col < nCols; col++) { |
| outData[col][row] = dataRow[col]; |
| } |
| } |
| return new BigMatrixImpl(outData, false); |
| } |
| |
| /** |
| * Returns the inverse matrix if this matrix is invertible. |
| * |
| * @return inverse matrix |
| * @throws InvalidMatrixException if this is not invertible |
| */ |
| public BigMatrix inverse() throws InvalidMatrixException { |
| return solve(MatrixUtils.createBigIdentityMatrix(getRowDimension())); |
| } |
| |
| /** |
| * Returns the determinant of this matrix. |
| * |
| * @return determinant |
| * @throws InvalidMatrixException if matrix is not square |
| */ |
| public BigDecimal getDeterminant() throws InvalidMatrixException { |
| if (!isSquare()) { |
| throw new NonSquareMatrixException(getRowDimension(), getColumnDimension()); |
| } |
| if (isSingular()) { // note: this has side effect of attempting LU decomp if lu == null |
| return ZERO; |
| } else { |
| BigDecimal det = (parity == 1) ? ONE : ONE.negate(); |
| for (int i = 0; i < getRowDimension(); i++) { |
| det = det.multiply(lu[i][i]); |
| } |
| return det; |
| } |
| } |
| |
| /** |
| * Is this a square matrix? |
| * @return true if the matrix is square (rowDimension = columnDimension) |
| */ |
| public boolean isSquare() { |
| return getColumnDimension() == getRowDimension(); |
| } |
| |
| /** |
| * Is this a singular matrix? |
| * @return true if the matrix is singular |
| */ |
| public boolean isSingular() { |
| if (lu == null) { |
| try { |
| luDecompose(); |
| return false; |
| } catch (InvalidMatrixException ex) { |
| return true; |
| } |
| } else { // LU decomp must have been successfully performed |
| return false; // so the matrix is not singular |
| } |
| } |
| |
| /** |
| * Returns the number of rows in the matrix. |
| * |
| * @return rowDimension |
| */ |
| public int getRowDimension() { |
| return data.length; |
| } |
| |
| /** |
| * Returns the number of columns in the matrix. |
| * |
| * @return columnDimension |
| */ |
| public int getColumnDimension() { |
| return data[0].length; |
| } |
| |
| /** |
| * Returns the <a href="http://mathworld.wolfram.com/MatrixTrace.html"> |
| * trace</a> of the matrix (the sum of the elements on the main diagonal). |
| * |
| * @return trace |
| * |
| * @throws IllegalArgumentException if this matrix is not square. |
| */ |
| public BigDecimal getTrace() throws IllegalArgumentException { |
| if (!isSquare()) { |
| throw new NonSquareMatrixException(getRowDimension(), getColumnDimension()); |
| } |
| BigDecimal trace = data[0][0]; |
| for (int i = 1; i < this.getRowDimension(); i++) { |
| trace = trace.add(data[i][i]); |
| } |
| return trace; |
| } |
| |
| /** |
| * Returns the result of multiplying this by the vector <code>v</code>. |
| * |
| * @param v the vector to operate on |
| * @return this*v |
| * @throws IllegalArgumentException if columnDimension != v.size() |
| */ |
| public BigDecimal[] operate(BigDecimal[] v) throws IllegalArgumentException { |
| if (v.length != getColumnDimension()) { |
| throw MathRuntimeException.createIllegalArgumentException( |
| LocalizedFormats.VECTOR_LENGTH_MISMATCH, |
| v.length, getColumnDimension() ); |
| } |
| final int nRows = this.getRowDimension(); |
| final int nCols = this.getColumnDimension(); |
| final BigDecimal[] out = new BigDecimal[nRows]; |
| for (int row = 0; row < nRows; row++) { |
| BigDecimal sum = ZERO; |
| for (int i = 0; i < nCols; i++) { |
| sum = sum.add(data[row][i].multiply(v[i])); |
| } |
| out[row] = sum; |
| } |
| return out; |
| } |
| |
| /** |
| * Returns the result of multiplying this by the vector <code>v</code>. |
| * |
| * @param v the vector to operate on |
| * @return this*v |
| * @throws IllegalArgumentException if columnDimension != v.size() |
| */ |
| public BigDecimal[] operate(double[] v) throws IllegalArgumentException { |
| final BigDecimal bd[] = new BigDecimal[v.length]; |
| for (int i = 0; i < bd.length; i++) { |
| bd[i] = new BigDecimal(v[i]); |
| } |
| return operate(bd); |
| } |
| |
| /** |
| * Returns the (row) vector result of premultiplying this by the vector <code>v</code>. |
| * |
| * @param v the row vector to premultiply by |
| * @return v*this |
| * @throws IllegalArgumentException if rowDimension != v.size() |
| */ |
| public BigDecimal[] preMultiply(BigDecimal[] v) throws IllegalArgumentException { |
| final int nRows = this.getRowDimension(); |
| if (v.length != nRows) { |
| throw MathRuntimeException.createIllegalArgumentException( |
| LocalizedFormats.VECTOR_LENGTH_MISMATCH, |
| v.length, nRows ); |
| } |
| final int nCols = this.getColumnDimension(); |
| final BigDecimal[] out = new BigDecimal[nCols]; |
| for (int col = 0; col < nCols; col++) { |
| BigDecimal sum = ZERO; |
| for (int i = 0; i < nRows; i++) { |
| sum = sum.add(data[i][col].multiply(v[i])); |
| } |
| out[col] = sum; |
| } |
| return out; |
| } |
| |
| /** |
| * Returns a matrix of (column) solution vectors for linear systems with |
| * coefficient matrix = this and constant vectors = columns of |
| * <code>b</code>. |
| * |
| * @param b array of constants forming RHS of linear systems to |
| * to solve |
| * @return solution array |
| * @throws IllegalArgumentException if this.rowDimension != row dimension |
| * @throws InvalidMatrixException if this matrix is not square or is singular |
| */ |
| public BigDecimal[] solve(BigDecimal[] b) throws IllegalArgumentException, InvalidMatrixException { |
| final int nRows = this.getRowDimension(); |
| if (b.length != nRows) { |
| throw MathRuntimeException.createIllegalArgumentException( |
| LocalizedFormats.VECTOR_LENGTH_MISMATCH, |
| b.length, nRows); |
| } |
| final BigMatrix bMatrix = new BigMatrixImpl(b); |
| final BigDecimal[][] solution = ((BigMatrixImpl) (solve(bMatrix))).getDataRef(); |
| final BigDecimal[] out = new BigDecimal[nRows]; |
| for (int row = 0; row < nRows; row++) { |
| out[row] = solution[row][0]; |
| } |
| return out; |
| } |
| |
| /** |
| * Returns a matrix of (column) solution vectors for linear systems with |
| * coefficient matrix = this and constant vectors = columns of |
| * <code>b</code>. |
| * |
| * @param b array of constants forming RHS of linear systems to |
| * to solve |
| * @return solution array |
| * @throws IllegalArgumentException if this.rowDimension != row dimension |
| * @throws InvalidMatrixException if this matrix is not square or is singular |
| */ |
| public BigDecimal[] solve(double[] b) throws IllegalArgumentException, InvalidMatrixException { |
| final BigDecimal bd[] = new BigDecimal[b.length]; |
| for (int i = 0; i < bd.length; i++) { |
| bd[i] = new BigDecimal(b[i]); |
| } |
| return solve(bd); |
| } |
| |
| /** |
| * Returns a matrix of (column) solution vectors for linear systems with |
| * coefficient matrix = this and constant vectors = columns of |
| * <code>b</code>. |
| * |
| * @param b matrix of constant vectors forming RHS of linear systems to |
| * to solve |
| * @return matrix of solution vectors |
| * @throws IllegalArgumentException if this.rowDimension != row dimension |
| * @throws InvalidMatrixException if this matrix is not square or is singular |
| */ |
| public BigMatrix solve(BigMatrix b) throws IllegalArgumentException, InvalidMatrixException { |
| if (b.getRowDimension() != getRowDimension()) { |
| throw MathRuntimeException.createIllegalArgumentException( |
| LocalizedFormats.DIMENSIONS_MISMATCH_2x2, |
| b.getRowDimension(), b.getColumnDimension(), getRowDimension(), "n"); |
| } |
| if (!isSquare()) { |
| throw new NonSquareMatrixException(getRowDimension(), getColumnDimension()); |
| } |
| if (this.isSingular()) { // side effect: compute LU decomp |
| throw new SingularMatrixException(); |
| } |
| |
| final int nCol = this.getColumnDimension(); |
| final int nColB = b.getColumnDimension(); |
| final int nRowB = b.getRowDimension(); |
| |
| // Apply permutations to b |
| final BigDecimal[][] bp = new BigDecimal[nRowB][nColB]; |
| for (int row = 0; row < nRowB; row++) { |
| final BigDecimal[] bpRow = bp[row]; |
| for (int col = 0; col < nColB; col++) { |
| bpRow[col] = b.getEntry(permutation[row], col); |
| } |
| } |
| |
| // Solve LY = b |
| for (int col = 0; col < nCol; col++) { |
| for (int i = col + 1; i < nCol; i++) { |
| final BigDecimal[] bpI = bp[i]; |
| final BigDecimal[] luI = lu[i]; |
| for (int j = 0; j < nColB; j++) { |
| bpI[j] = bpI[j].subtract(bp[col][j].multiply(luI[col])); |
| } |
| } |
| } |
| |
| // Solve UX = Y |
| for (int col = nCol - 1; col >= 0; col--) { |
| final BigDecimal[] bpCol = bp[col]; |
| final BigDecimal luDiag = lu[col][col]; |
| for (int j = 0; j < nColB; j++) { |
| bpCol[j] = bpCol[j].divide(luDiag, scale, roundingMode); |
| } |
| for (int i = 0; i < col; i++) { |
| final BigDecimal[] bpI = bp[i]; |
| final BigDecimal[] luI = lu[i]; |
| for (int j = 0; j < nColB; j++) { |
| bpI[j] = bpI[j].subtract(bp[col][j].multiply(luI[col])); |
| } |
| } |
| } |
| |
| return new BigMatrixImpl(bp, false); |
| |
| } |
| |
| /** |
| * Computes a new |
| * <a href="http://www.math.gatech.edu/~bourbaki/math2601/Web-notes/2num.pdf"> |
| * LU decompostion</a> for this matrix, storing the result for use by other methods. |
| * <p> |
| * <strong>Implementation Note</strong>:<br> |
| * Uses <a href="http://www.damtp.cam.ac.uk/user/fdl/people/sd/lectures/nummeth98/linear.htm"> |
| * Crout's algortithm</a>, with partial pivoting.</p> |
| * <p> |
| * <strong>Usage Note</strong>:<br> |
| * This method should rarely be invoked directly. Its only use is |
| * to force recomputation of the LU decomposition when changes have been |
| * made to the underlying data using direct array references. Changes |
| * made using setXxx methods will trigger recomputation when needed |
| * automatically.</p> |
| * |
| * @throws InvalidMatrixException if the matrix is non-square or singular. |
| */ |
| public void luDecompose() throws InvalidMatrixException { |
| |
| final int nRows = this.getRowDimension(); |
| final int nCols = this.getColumnDimension(); |
| if (nRows != nCols) { |
| throw new NonSquareMatrixException(getRowDimension(), getColumnDimension()); |
| } |
| lu = this.getData(); |
| |
| // Initialize permutation array and parity |
| permutation = new int[nRows]; |
| for (int row = 0; row < nRows; row++) { |
| permutation[row] = row; |
| } |
| parity = 1; |
| |
| // Loop over columns |
| for (int col = 0; col < nCols; col++) { |
| |
| BigDecimal sum = ZERO; |
| |
| // upper |
| for (int row = 0; row < col; row++) { |
| final BigDecimal[] luRow = lu[row]; |
| sum = luRow[col]; |
| for (int i = 0; i < row; i++) { |
| sum = sum.subtract(luRow[i].multiply(lu[i][col])); |
| } |
| luRow[col] = sum; |
| } |
| |
| // lower |
| int max = col; // permutation row |
| BigDecimal largest = ZERO; |
| for (int row = col; row < nRows; row++) { |
| final BigDecimal[] luRow = lu[row]; |
| sum = luRow[col]; |
| for (int i = 0; i < col; i++) { |
| sum = sum.subtract(luRow[i].multiply(lu[i][col])); |
| } |
| luRow[col] = sum; |
| |
| // maintain best permutation choice |
| if (sum.abs().compareTo(largest) == 1) { |
| largest = sum.abs(); |
| max = row; |
| } |
| } |
| |
| // Singularity check |
| if (lu[max][col].abs().compareTo(TOO_SMALL) <= 0) { |
| lu = null; |
| throw new SingularMatrixException(); |
| } |
| |
| // Pivot if necessary |
| if (max != col) { |
| BigDecimal tmp = ZERO; |
| for (int i = 0; i < nCols; i++) { |
| tmp = lu[max][i]; |
| lu[max][i] = lu[col][i]; |
| lu[col][i] = tmp; |
| } |
| int temp = permutation[max]; |
| permutation[max] = permutation[col]; |
| permutation[col] = temp; |
| parity = -parity; |
| } |
| |
| // Divide the lower elements by the "winning" diagonal elt. |
| final BigDecimal luDiag = lu[col][col]; |
| for (int row = col + 1; row < nRows; row++) { |
| final BigDecimal[] luRow = lu[row]; |
| luRow[col] = luRow[col].divide(luDiag, scale, roundingMode); |
| } |
| |
| } |
| |
| } |
| |
| /** |
| * Get a string representation for this matrix. |
| * @return a string representation for this matrix |
| */ |
| @Override |
| public String toString() { |
| StringBuilder res = new StringBuilder(); |
| res.append("BigMatrixImpl{"); |
| if (data != null) { |
| for (int i = 0; i < data.length; i++) { |
| if (i > 0) { |
| res.append(","); |
| } |
| res.append("{"); |
| for (int j = 0; j < data[0].length; j++) { |
| if (j > 0) { |
| res.append(","); |
| } |
| res.append(data[i][j]); |
| } |
| res.append("}"); |
| } |
| } |
| res.append("}"); |
| return res.toString(); |
| } |
| |
| /** |
| * Returns true iff <code>object</code> is a |
| * <code>BigMatrixImpl</code> instance with the same dimensions as this |
| * and all corresponding matrix entries are equal. BigDecimal.equals |
| * is used to compare corresponding entries. |
| * |
| * @param object the object to test equality against. |
| * @return true if object equals this |
| */ |
| @Override |
| public boolean equals(Object object) { |
| if (object == this ) { |
| return true; |
| } |
| if (object instanceof BigMatrixImpl == false) { |
| return false; |
| } |
| final BigMatrix m = (BigMatrix) object; |
| final int nRows = getRowDimension(); |
| final int nCols = getColumnDimension(); |
| if (m.getColumnDimension() != nCols || m.getRowDimension() != nRows) { |
| return false; |
| } |
| for (int row = 0; row < nRows; row++) { |
| final BigDecimal[] dataRow = data[row]; |
| for (int col = 0; col < nCols; col++) { |
| if (!dataRow[col].equals(m.getEntry(row, col))) { |
| return false; |
| } |
| } |
| } |
| return true; |
| } |
| |
| /** |
| * Computes a hashcode for the matrix. |
| * |
| * @return hashcode for matrix |
| */ |
| @Override |
| public int hashCode() { |
| int ret = 7; |
| final int nRows = getRowDimension(); |
| final int nCols = getColumnDimension(); |
| ret = ret * 31 + nRows; |
| ret = ret * 31 + nCols; |
| for (int row = 0; row < nRows; row++) { |
| final BigDecimal[] dataRow = data[row]; |
| for (int col = 0; col < nCols; col++) { |
| ret = ret * 31 + (11 * (row+1) + 17 * (col+1)) * |
| dataRow[col].hashCode(); |
| } |
| } |
| return ret; |
| } |
| |
| //------------------------ Protected methods |
| |
| /** |
| * Returns the LU decomposition as a BigMatrix. |
| * Returns a fresh copy of the cached LU matrix if this has been computed; |
| * otherwise the composition is computed and cached for use by other methods. |
| * Since a copy is returned in either case, changes to the returned matrix do not |
| * affect the LU decomposition property. |
| * <p> |
| * The matrix returned is a compact representation of the LU decomposition. |
| * Elements below the main diagonal correspond to entries of the "L" matrix; |
| * elements on and above the main diagonal correspond to entries of the "U" |
| * matrix.</p> |
| * <p> |
| * Example: <pre> |
| * |
| * Returned matrix L U |
| * 2 3 1 1 0 0 2 3 1 |
| * 5 4 6 5 1 0 0 4 6 |
| * 1 7 8 1 7 1 0 0 8 |
| * </pre> |
| * |
| * The L and U matrices satisfy the matrix equation LU = permuteRows(this), <br> |
| * where permuteRows reorders the rows of the matrix to follow the order determined |
| * by the <a href=#getPermutation()>permutation</a> property.</p> |
| * |
| * @return LU decomposition matrix |
| * @throws InvalidMatrixException if the matrix is non-square or singular. |
| */ |
| protected BigMatrix getLUMatrix() throws InvalidMatrixException { |
| if (lu == null) { |
| luDecompose(); |
| } |
| return new BigMatrixImpl(lu); |
| } |
| |
| /** |
| * Returns the permutation associated with the lu decomposition. |
| * The entries of the array represent a permutation of the numbers 0, ... , nRows - 1. |
| * <p> |
| * Example: |
| * permutation = [1, 2, 0] means current 2nd row is first, current third row is second |
| * and current first row is last.</p> |
| * <p> |
| * Returns a fresh copy of the array.</p> |
| * |
| * @return the permutation |
| */ |
| protected int[] getPermutation() { |
| final int[] out = new int[permutation.length]; |
| System.arraycopy(permutation, 0, out, 0, permutation.length); |
| return out; |
| } |
| |
| //------------------------ Private methods |
| |
| /** |
| * Returns a fresh copy of the underlying data array. |
| * |
| * @return a copy of the underlying data array. |
| */ |
| private BigDecimal[][] copyOut() { |
| final int nRows = this.getRowDimension(); |
| final BigDecimal[][] out = new BigDecimal[nRows][this.getColumnDimension()]; |
| // can't copy 2-d array in one shot, otherwise get row references |
| for (int i = 0; i < nRows; i++) { |
| System.arraycopy(data[i], 0, out[i], 0, data[i].length); |
| } |
| return out; |
| } |
| |
| /** |
| * Replaces data with a fresh copy of the input array. |
| * <p> |
| * Verifies that the input array is rectangular and non-empty.</p> |
| * |
| * @param in data to copy in |
| * @throws IllegalArgumentException if input array is emtpy or not |
| * rectangular |
| * @throws NullPointerException if input array is null |
| */ |
| private void copyIn(BigDecimal[][] in) { |
| setSubMatrix(in,0,0); |
| } |
| |
| /** |
| * Replaces data with a fresh copy of the input array. |
| * |
| * @param in data to copy in |
| */ |
| private void copyIn(double[][] in) { |
| final int nRows = in.length; |
| final int nCols = in[0].length; |
| data = new BigDecimal[nRows][nCols]; |
| for (int i = 0; i < nRows; i++) { |
| final BigDecimal[] dataI = data[i]; |
| final double[] inI = in[i]; |
| for (int j = 0; j < nCols; j++) { |
| dataI[j] = new BigDecimal(inI[j]); |
| } |
| } |
| lu = null; |
| } |
| |
| /** |
| * Replaces data with BigDecimals represented by the strings in the input |
| * array. |
| * |
| * @param in data to copy in |
| */ |
| private void copyIn(String[][] in) { |
| final int nRows = in.length; |
| final int nCols = in[0].length; |
| data = new BigDecimal[nRows][nCols]; |
| for (int i = 0; i < nRows; i++) { |
| final BigDecimal[] dataI = data[i]; |
| final String[] inI = in[i]; |
| for (int j = 0; j < nCols; j++) { |
| dataI[j] = new BigDecimal(inI[j]); |
| } |
| } |
| lu = null; |
| } |
| |
| } |