/* * 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 * LU decompostion to support linear system * solution and inverse. *
* The LU decompostion is performed as needed, to support the following operations:
* Usage notes:
*
getDataRef()
, then the stored
* LU decomposition will not be discarded. In this case, you need to
* explicitly invoke LUDecompose()
to recompute the decomposition
* before using any of the methods above.getEntry(0, 0)
* returns the element in the first row, first column of the matrix.d
as the underlying
* data array.
* 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 true
.
d
is not rectangular
* (not all rows have the same length) or empty
* @throws NullPointerException if d
is null
*/
public BigMatrixImpl(BigDecimal[][] d) {
this.copyIn(d);
lu = null;
}
/**
* Create a new BigMatrix using the input array as the underlying
* data array.
* If an array is built specially in order to be embedded in a
* BigMatrix and not used directly, the Since the underlying array will hold
* The input array is copied, not referenced.
* Makes a fresh copy of the underlying data.
* Makes a fresh copy of the underlying data converted to
*
* Does not make a fresh copy of the underlying data.
* Example:copyArray
may be
* set to false
* @param d data for new matrix
* @param copyArray if true, the input array will be copied, otherwise
* it will be referenced
* @throws IllegalArgumentException if
d
is not rectangular
* (not all rows have the same length) or empty
* @throws NullPointerException if d
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 d
as the underlying
* data array.
* BigDecimal
* instances, it will be created.d
is not rectangular
* (not all rows have the same length) or empty
* @throws NullPointerException if d
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
* d
as the underlying data array.
*
* @param d data for new matrix
* @throws IllegalArgumentException if d
is not rectangular
* (not all rows have the same length) or empty
* @throws NullPointerException if d
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 v
as the
* data for the unique column of the v.length x 1
matrix
* created.
* m
.
*
* @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 m
.
*
* @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 m
.
*
* @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 m
.
*
* @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 d
* @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 m
.
* @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 m
.
* @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 m
.
* @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.
* double
values.row, column
using data in
* the input subMatrix
array. Indexes are 0-based.
*
* Starting with
* 1 2 3 4
* 5 6 7 8
* 9 0 1 2
*
* and subMatrix = {{3, 4} {5,6}}
, invoking
* setSubMatrix(subMatrix,1,1))
will result in
* 1 2 3 4
* 5 3 4 8
* 9 5 6 2
*
subMatrix
is not rectangular
* (not all rows have the same length) or empty
* @throws NullPointerException if subMatrix
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 row
* 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 column
* 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 row
as an array.
*
* Row indices start at 0. A MatrixIndexException
is thrown
* unless 0 <= row < rowDimension.
row
as an array
* of double values.
*
* Row indices start at 0. A MatrixIndexException
is thrown
* unless 0 <= row < rowDimension.
* Column indices start at 0. A MatrixIndexException
is thrown
* unless 0 <= column < columnDimension.
col
as an array
* of double values.
*
* Column indices start at 0. A MatrixIndexException
is thrown
* unless 0 <= column < columnDimension.
0 <= row < rowDimension
0 <= column < columnDimension
MatrixIndexException
is thrown.
*
* @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.
* * Row and column indices start at 0 and must satisfy *
0 <= row < rowDimension
0 <= column < columnDimension
MatrixIndexException
is thrown.
*
* @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
* trace 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 v
.
*
* @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 v
.
*
* @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 v
.
*
* @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
* b
.
*
* @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
* b
.
*
* @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
* b
.
*
* @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
*
* LU decompostion for this matrix, storing the result for use by other methods.
*
* Implementation Note:
* Uses
* Crout's algortithm, with partial pivoting.
* Usage Note:
* 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.
object
is a
* BigMatrixImpl
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.
* * 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.
** Example:
* * 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 ** * The L and U matrices satisfy the matrix equation LU = permuteRows(this),
* Example: * permutation = [1, 2, 0] means current 2nd row is first, current third row is second * and current first row is last.
** Returns a fresh copy of the array.
* * @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. ** Verifies that the input array is rectangular and non-empty.
* * @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; } }