You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by bu...@apache.org on 2004/08/27 16:50:00 UTC
DO NOT REPLY [Bug 30897] New: -
New methods in RealMatrixImpl and changing indexing
DO NOT REPLY TO THIS EMAIL, BUT PLEASE POST YOUR BUG
RELATED COMMENTS THROUGH THE WEB INTERFACE AVAILABLE AT
<http://issues.apache.org/bugzilla/show_bug.cgi?id=30897>.
ANY REPLY MADE TO THIS MESSAGE WILL NOT BE COLLECTED AND
INSERTED IN THE BUG DATABASE.
http://issues.apache.org/bugzilla/show_bug.cgi?id=30897
New methods in RealMatrixImpl and changing indexing
Summary: New methods in RealMatrixImpl and changing indexing
Product: Commons
Version: 1.0 Alpha
Platform: All
OS/Version: All
Status: NEW
Severity: Enhancement
Priority: Other
Component: Math
AssignedTo: commons-dev@jakarta.apache.org
ReportedBy: kim@kimvdlinde.com
Numbering of the rows and columns is as default for an JAVA array, starting with
0 with the higest value for either row-1 or column-1. This facilitates
programming of modules which give back an array to construct subMatrices from
the original matrix.
This change affects the folowing old methods:
getRow(int row)
getColumn(int column)
isValidCoordinate(int row, int col)
setEntry(...)
getEntry(...)
/*
* Copyright 2003-2004 The Apache Software Foundation.
*
* Licensed 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;
/**
* Implementation for RealMatrix using a double[][] 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>
* <strong>Usage note</strong>:<br>
* 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.
*
* <p> Numbering of the rows and columns is as default for an JAVA array,
starting with 0
* with the higest value for either row-1 or column-1. This facilitates
programming of
* modules which give back an array to construct subMatrices from the original
matrix.
*
* @version $Revision: 1.26 $ $Date: 2004/08/22 01:42:58 $
*/
public class RealMatrixImpl implements RealMatrix, Serializable {
/** Serializable version identifier */
static final long serialVersionUID = 4237564493130426188L;
/** Entries of the matrix */
private double data[][] = null;
/** Entries of cached LU decomposition.
* All updates to data (other than luDecompose()) *must* set this to null
*/
private double lu[][] = null;
/** Permutation associated with LU decompostion */
private int[] permutation = null;
/** Parity of the permutation associated with the LU decomposition */
private int parity = 1;
/** Bound to determine effective singularity in LU decomposition */
protected static double TOO_SMALL = 10E-12;
/**
* Creates a matrix with no data
*/
public RealMatrixImpl() {
}
/**
* Create a new RealMatrix 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
*/
public RealMatrixImpl(int rowDimension, int columnDimension) {
data = new double[rowDimension][columnDimension];
lu = null;
}
/**
* Create a new RealMatrix using the <code>data</code> as the underlying
* data array.
* <p>
* The input array is copied, not referenced.
*
* @param d data for new matrix
*/
public RealMatrixImpl(double[][] d) {
this.copyIn(d);
lu = null;
}
/**
* Create a new (column) RealMatrix 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.
*
* @param v column vector holding data for new matrix
*/
public RealMatrixImpl(double[] v) {
int nRows = v.length;
data = new double[nRows][1];
for (int row = 0; row < nRows; row++) {
data[row][0] = v[row];
}
}
/**
* Create a new RealMatrix which is a copy of this.
*
* @return the cloned matrix
*/
public RealMatrix copy() {
return new RealMatrixImpl(this.copyOut());
}
/**
* 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 RealMatrix add(RealMatrix m) throws IllegalArgumentException {
if (this.getColumnDimension() != m.getColumnDimension() ||
this.getRowDimension() != m.getRowDimension()) {
throw new IllegalArgumentException("matrix dimension mismatch");
}
int rowCount = this.getRowDimension();
int columnCount = this.getColumnDimension();
double[][] outData = new double[rowCount][columnCount];
double[][] mData = m.getData();
for (int row = 0; row < rowCount; row++) {
for (int col = 0; col < columnCount; col++) {
outData[row][col] = data[row][col] + mData[row][col];
}
}
return new RealMatrixImpl(outData);
}
/**
* 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 RealMatrix subtract(RealMatrix m) throws IllegalArgumentException {
if (this.getColumnDimension() != m.getColumnDimension() ||
this.getRowDimension() != m.getRowDimension()) {
throw new IllegalArgumentException("matrix dimension mismatch");
}
int rowCount = this.getRowDimension();
int columnCount = this.getColumnDimension();
double[][] outData = new double[rowCount][columnCount];
double[][] mData = m.getData();
for (int row = 0; row < rowCount; row++) {
for (int col = 0; col < columnCount; col++) {
outData[row][col] = data[row][col] - mData[row][col];
}
}
return new RealMatrixImpl(outData);
}
/**
* Returns the result of adding d to each entry of this.
*
* @param d value to be added to each entry
* @return d + this
*/
public RealMatrix scalarAdd(double d) {
int rowCount = this.getRowDimension();
int columnCount = this.getColumnDimension();
double[][] outData = new double[rowCount][columnCount];
for (int row = 0; row < rowCount; row++) {
for (int col = 0; col < columnCount; col++) {
outData[row][col] = data[row][col] + d;
}
}
return new RealMatrixImpl(outData);
}
/**
* Returns the result multiplying each entry of this by <code>d</code>
* @param d value to multiply all entries by
* @return d * this
*/
public RealMatrix scalarMultiply(double d) {
int rowCount = this.getRowDimension();
int columnCount = this.getColumnDimension();
double[][] outData = new double[rowCount][columnCount];
for (int row = 0; row < rowCount; row++) {
for (int col = 0; col < columnCount; col++) {
outData[row][col] = data[row][col] * d;
}
}
return new RealMatrixImpl(outData);
}
/**
* 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 RealMatrix multiply(RealMatrix m) throws IllegalArgumentException {
if (this.getColumnDimension() != m.getRowDimension()) {
throw new IllegalArgumentException("Matrices are not multiplication
compatible.");
}
int nRows = this.getRowDimension();
int nCols = m.getColumnDimension();
int nSum = this.getColumnDimension();
double[][] mData = m.getData();
double[][] outData = new double[nRows][nCols];
double sum = 0;
for (int row = 0; row < nRows; row++) {
for (int col = 0; col < nCols; col++) {
sum = 0;
for (int i = 0; i < nSum; i++) {
sum += data[row][i] * mData[i][col];
}
outData[row][col] = sum;
}
}
return new RealMatrixImpl(outData);
}
/**
* 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 RealMatrix preMultiply(RealMatrix m) throws IllegalArgumentException {
return m.multiply(this);
}
/**
* Returns matrix entries as a two-dimensional array.
* <p>
* Makes a fresh copy of the underlying data.
*
* @return 2-dimensional array of entries
*/
public double[][] getData() {
return copyOut();
}
/**
* Overwrites the underlying data for the matrix
* with a fresh copy of <code>inData</code>.
*
* @param inData 2-dimensional array of entries
*/
public void setData(double[][] inData) {
copyIn(inData);
lu = null;
}
/**
* Returns a reference to the underlying data array.
* <p>
* Does not make a fresh copy of the underlying data.
*
* @return 2-dimensional array of entries
*/
public double[][] getDataRef() {
return data;
}
/**
* Overwrites the underlying data for the matrix
* with a reference to <code>inData</code>.
* <p>
* Does not make a fresh copy of <code>data</code>.
*
* @param inData 2-dimensional array of entries
*/
public void setDataRef(double[][] inData) {
this.data = inData;
lu = null;
}
/**
*
* @return norm
*/
public double getNorm() {
double maxColSum = 0;
for (int col = 0; col < this.getColumnDimension(); col++) {
double sum = 0;
for (int row = 0; row < this.getRowDimension(); row++) {
sum += Math.abs(data[row][col]);
}
maxColSum = Math.max(maxColSum, sum);
}
return maxColSum;
}
/**
* Returns the entries in row number <code>row</code> as an array.
*
* @param row the row to be fetched
* @return array of entries in the row
* @throws MatrixIndexException if the specified row is greater
* than the number of rows in this matrix
*/
public double[] getRow(int row) throws MatrixIndexException {
if ( !isValidCoordinate( row, 0 ) ) {
throw new MatrixIndexException("illegal row argument");
}
int ncols = this.getColumnDimension();
double[] out = new double[ncols];
System.arraycopy(data[row], 0, out, 0, ncols);
return out;
}
/**
* Returns the entries in row number <code>row</code> as a RealMatrix object.
*
* @param row the row to be fetched
* @return RealMatrix with only one row
* @throws MatrixIndexException if the specified row is greater
* than the number of rows in this matrix
*/
public RealMatrix getRowMatrix(int row) throws MatrixIndexException {
if ( !isValidCoordinate( row, 0 ) ) {
throw new MatrixIndexException("illegal row argument");
}
int ncols = this.getColumnDimension();
double[][] out = new double[1][ncols];
for (int y = 0; y<ncols; y++)
{
out[0][y] = data[row][y];
}
return new RealMatrixImpl(out);
}
/**
* Returns the entries in column number <code>col</code> as an array.
*
* @param col column to fetch
* @return array of entries in the column
* @throws MatrixIndexException if the specified column is greater
* than the number of columns in this matrix
*/
public double[] getColumn(int col) throws MatrixIndexException {
if ( !isValidCoordinate(0, col) ) {
throw new MatrixIndexException("illegal column argument");
}
int nRows = this.getRowDimension();
double[] out = new double[nRows];
for (int row = 0; row < nRows; row++) {
out[row] = data[row][col];
}
return out;
}
/**
* Returns the entries in column number <code>col</code> as a RealMatrix object.
*
* @param col column to fetch
* @return RealMatrix with only one column
* @throws MatrixIndexException if the specified column is greater
* than the number of columns in this matrix
*/
public RealMatrix getColumnMatrix(int col) throws MatrixIndexException {
if ( !isValidCoordinate(0, col) ) {
throw new MatrixIndexException("illegal row argument");
}
int nRows = this.getRowDimension();
double[][] out = new double[nRows][1];
for (int y = 0; y<nRows ; y++)
{
out[y][0] = data[y][col];
}
return new RealMatrixImpl(out);
}
/**
* Returns the entry in the specified row and column.
*
* @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 specified coordinate is outside
* the dimensions of this matrix
*/
public double getEntry(int row, int column)
throws MatrixIndexException {
if (!isValidCoordinate(row,column)) {
throw new MatrixIndexException("matrix entry does not exist");
}
return data[row][column];
}
/**
* Sets the entry in the specified row and column to the specified value.
*
* @param row row location of entry to be set
* @param column column location of entry to be set
* @param value value to set
* @throws MatrixIndexException if the specified coordinate is outside
* he dimensions of this matrix
*/
public void setEntry(int row, int column, double value)
throws MatrixIndexException {
if (!isValidCoordinate(row,column)) {
throw new MatrixIndexException("matrix entry does not exist");
}
data[row][column] = value;
lu = null;
}
/**
* Returns the transpose matrix.
*
* @return transpose matrix
*/
public RealMatrix transpose() {
int nRows = this.getRowDimension();
int nCols = this.getColumnDimension();
RealMatrixImpl out = new RealMatrixImpl(nCols, nRows);
double[][] outData = out.getDataRef();
for (int row = 0; row < nRows; row++) {
for (int col = 0; col < nCols; col++) {
outData[col][row] = data[row][col];
}
}
return out;
}
/**
* Returns the inverse matrix if this matrix is invertible.
*
* @return inverse matrix
* @throws InvalidMatrixException if this is not invertible
*/
public RealMatrix inverse() throws InvalidMatrixException {
return solve(getIdentity(this.getRowDimension()));
}
/**
* @return determinant
* @throws InvalidMatrixException if matrix is not square
*/
public double getDeterminant() throws InvalidMatrixException {
if (!isSquare()) {
throw new InvalidMatrixException("matrix is not square");
}
if (isSingular()) { // note: this has side effect of attempting LU
decomp if lu == null
return 0d;
} else {
double det = parity;
for (int i = 0; i < this.getRowDimension(); i++) {
det *= lu[i][i];
}
return det;
}
}
/**
* @return true if the matrix is square (rowDimension = columnDimension)
*/
public boolean isSquare() {
return (this.getColumnDimension() == this.getRowDimension());
}
/**
* @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
}
}
/**
* @return rowDimension
*/
public int getRowDimension() {
return data.length;
}
/**
* @return columnDimension
*/
public int getColumnDimension() {
return data[0].length;
}
/**
* @return trace
* @throws IllegalArgumentException if the matrix is not square
*/
public double getTrace() throws IllegalArgumentException {
if (!isSquare()) {
throw new IllegalArgumentException("matrix is not square");
}
double trace = data[0][0];
for (int i = 1; i < this.getRowDimension(); i++) {
trace += data[i][i];
}
return trace;
}
/**
* @param v vector to operate on
* @throws IllegalArgumentException if columnDimension != v.length
* @return resulting vector
*/
public double[] operate(double[] v) throws IllegalArgumentException {
if (v.length != this.getColumnDimension()) {
throw new IllegalArgumentException("vector has wrong length");
}
int nRows = this.getRowDimension();
int nCols = this.getColumnDimension();
double[] out = new double[v.length];
for (int row = 0; row < nRows; row++) {
double sum = 0;
for (int i = 0; i < nCols; i++) {
sum += data[row][i] * v[i];
}
out[row] = sum;
}
return out;
}
/**
* @param v vector to premultiply by
* @throws IllegalArgumentException if rowDimension != v.length
* @return resulting matrix
*/
public double[] preMultiply(double[] v) throws IllegalArgumentException {
int nRows = this.getRowDimension();
if (v.length != nRows) {
throw new IllegalArgumentException("vector has wrong length");
}
int nCols = this.getColumnDimension();
double[] out = new double[nCols];
for (int col = 0; col < nCols; col++) {
double sum = 0;
for (int i = 0; i < nRows; i++) {
sum += data[i][col] * 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 constant 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 double[] solve(double[] b) throws IllegalArgumentException,
InvalidMatrixException {
int nRows = this.getRowDimension();
if (b.length != nRows) {
throw new IllegalArgumentException("constant vector has wrong length");
}
RealMatrix bMatrix = new RealMatrixImpl(b);
double[][] solution = ((RealMatrixImpl) (solve(bMatrix))).getDataRef();
double[] out = new double[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 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 RealMatrix solve(RealMatrix b) throws IllegalArgumentException,
InvalidMatrixException {
if (b.getRowDimension() != this.getRowDimension()) {
throw new IllegalArgumentException("Incorrect row dimension");
}
if (!this.isSquare()) {
throw new InvalidMatrixException("coefficient matrix is not square");
}
if (this.isSingular()) { // side effect: compute LU decomp
throw new InvalidMatrixException("Matrix is singular.");
}
int nCol = this.getColumnDimension();
int nColB = b.getColumnDimension();
int nRowB = b.getRowDimension();
// Apply permutations to b
double[][] bv = b.getData();
double[][] bp = new double[nRowB][nColB];
for (int row = 0; row < nRowB; row++) {
for (int col = 0; col < nColB; col++) {
bp[row][col] = bv[permutation[row]][col];
}
}
bv = null;
// Solve LY = b
for (int col = 0; col < nCol; col++) {
for (int i = col + 1; i < nCol; i++) {
for (int j = 0; j < nColB; j++) {
bp[i][j] -= bp[col][j] * lu[i][col];
}
}
}
// Solve UX = Y
for (int col = nCol - 1; col >= 0; col--) {
for (int j = 0; j < nColB; j++) {
bp[col][j] /= lu[col][col];
}
for (int i = 0; i < col; i++) {
for (int j = 0; j < nColB; j++) {
bp[i][j] -= bp[col][j] * lu[i][col];
}
}
}
RealMatrixImpl outMat = new RealMatrixImpl(bp);
return outMat;
}
/**
* 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>
* <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.
*
* @throws InvalidMatrixException if the matrix is non-square or singular.
*/
public void luDecompose() throws InvalidMatrixException {
int nRows = this.getRowDimension();
int nCols = this.getColumnDimension();
if (nRows != nCols) {
throw new InvalidMatrixException("LU decomposition requires that the
matrix be square.");
}
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++) {
double sum = 0;
// upper
for (int row = 0; row < col; row++) {
sum = lu[row][col];
for (int i = 0; i < row; i++) {
sum -= lu[row][i] * lu[i][col];
}
lu[row][col] = sum;
}
// lower
int max = col; // permutation row
double largest = 0d;
for (int row = col; row < nRows; row++) {
sum = lu[row][col];
for (int i = 0; i < col; i++) {
sum -= lu[row][i] * lu[i][col];
}
lu[row][col] = sum;
// maintain best permutation choice
if (Math.abs(sum) > largest) {
largest = Math.abs(sum);
max = row;
}
}
// Singularity check
if (Math.abs(lu[max][col]) < TOO_SMALL) {
lu = null;
throw new InvalidMatrixException("matrix is singular");
}
// Pivot if necessary
if (max != col) {
double tmp = 0;
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.
for (int row = col + 1; row < nRows; row++) {
lu[row][col] /= lu[col][col];
}
}
}
/**
* Gives the means of each row of the matrix.
* @return the row means
*/
public double[] rowMeans()
{
int rowCount = this.getRowDimension();
int columnCount = this.getColumnDimension();
double[] means = new double[rowCount];
for (int x = 0; x<rowCount; x++)
{
for (int y = 0; y<columnCount; y++)
{
means[x] += data[x][y]/columnCount;
}
}
return means;
}
/**
* Gives the means of each colums of the matrix.
* @return the column means
*/
public double[] columnMeans()
{
int rowCount = this.getRowDimension();
int columnCount = this.getColumnDimension();
double[] means = new double[columnCount];
for (int x = 0; x<rowCount; x++)
{
for (int y = 0; y<columnCount; y++)
{
means[y] += data[x][y]/rowCount;
}
}
return means;
}
/**
* Get a submatrix. Rows and columns are indicated counting from 1 to n, NOT
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 matrix dimension mismatch
*/
public RealMatrix getSubMatrix (int startRow, int endRow, int startColumn,
int endColumn)
throws MatrixIndexException {
RealMatrixImpl subMatrix = new
RealMatrixImpl(endRow-startRow+1,endColumn-startColumn+1);
double[][] subMatrixData = subMatrix.getDataRef();
try {
for (int i = startRow; i < endRow; i++) {
for (int j = startColumn; j < endColumn; j++) {
subMatrixData[i-startRow][j-startColumn] = data[i][j];
}
}
} catch(ArrayIndexOutOfBoundsException e) {
throw new MatrixIndexException("matrix dimension mismatch");
}
return subMatrix;
}
/**
* Get a submatrix. Rows and columns are indicated counting from 1 to n, NOT
from 0 to n-1.
* @param rows Array of row indices.
* @param columns Array of column indices.
* @return The subMatrix containing the data of the specified rows and
columns
* @exception MatrixIndexException matrix dimension mismatch
*/
public RealMatrix getSubMatrix (int[] rows, int[] columns)
throws MatrixIndexException {
RealMatrixImpl subMatrix = new RealMatrixImpl(rows.length,columns.length);
double[][] subMatrixData = subMatrix.getDataRef();
try {
for (int i = 0; i < rows.length; i++) {
for (int j = 0; j < columns.length; j++) {
subMatrixData[i][j] = data[rows[i]][columns[j]];
}
}
} catch(ArrayIndexOutOfBoundsException e) {
throw new MatrixIndexException("matrix dimension mismatch");
}
return subMatrix ;
}
/**
* Get a submatrix. Rows and columns are indicated counting from 1 to n, NOT
from 0 to n-1.
* @param startRow Initial row index
* @param endRow Final row index
* @param columns Array of column indices.
* @return The subMatrix containing the data of the specified rows and
columns
* @exception MatrixIndexException matrix dimension mismatch
*/
public RealMatrix getSubMatrix (int startRow, int endRow, int[] columns)
throws MatrixIndexException {
RealMatrixImpl subMatrix = new
RealMatrixImpl(endRow-startRow+1,columns.length);
double[][] subMatrixData = subMatrix.getDataRef();
try {
for (int i = startRow; i < endRow; i++) {
for (int j = 0; j < columns.length; j++) {
subMatrixData[i-startRow][j] = data[i][columns[j]];
}
}
} catch(ArrayIndexOutOfBoundsException e) {
throw new MatrixIndexException("matrix dimension mismatch");
}
return subMatrix;
}
/**
* Get a submatrix. Rows and columns are indicated counting from 1 to n, NOT
from 0 to n-1.
* @param rows Array of row indices.
* @param startColumn Initial column index
* @param endColumn Final column index
* @return The subMatrix containing the data of the specified rows and
columns
* @exception MatrixIndexException matrix dimension mismatch
*/
public RealMatrix getSubMatrix (int[] rows, int startColumn, int endColumn)
throws MatrixIndexException {
RealMatrixImpl subMatrix = new
RealMatrixImpl(rows.length,endColumn-startColumn+1);
double[][] subMatrixData = subMatrix.getDataRef();
try {
for (int i = 0; i < rows.length; i++) {
for (int j = startColumn; j <= endColumn; j++) {
subMatrixData[i][j-startColumn] = data[rows[i]][j];
//System.out.println(""+rows[i]+", "+j+": "+data[rows[i]][j]);
}
}
} catch(ArrayIndexOutOfBoundsException e) {
throw new MatrixIndexException("matrix dimension mismatch");
}
return subMatrix;
}
/**
*
* @see java.lang.Object#toString()
*/
public String toString() {
StringBuffer res = new StringBuffer();
res.append("RealMatrixImpl{");
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]);
} //for
res.append("}");
} //for
res.append("}");
return res.toString();
} //toString
//------------------------ Protected methods
/**
* Returns <code>dimension x dimension</code> identity matrix.
*
* @param dimension dimension of identity matrix to generate
* @return identity matrix
*/
protected RealMatrix getIdentity(int dimension) {
RealMatrixImpl out = new RealMatrixImpl(dimension, dimension);
double[][] d = out.getDataRef();
for (int row = 0; row < dimension; row++) {
for (int col = 0; col < dimension; col++) {
d[row][col] = row == col ? 1d : 0d;
}
}
return out;
}
/**
* Returns the LU decomposition as a RealMatrix.
* 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>
* 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.
*
* @return LU decomposition matrix
* @throws InvalidMatrixException if the matrix is non-square or singular.
*/
protected RealMatrix getLUMatrix() throws InvalidMatrixException {
if (lu == null) {
luDecompose();
}
return new RealMatrixImpl(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>
* Returns a fresh copy of the array.
*
* @return the permutation
*/
protected int[] getPermutation() {
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 double[][] copyOut() {
int nRows = this.getRowDimension();
double[][] out = new double[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.
*
* @param in data to copy in
*/
private void copyIn(double[][] in) {
int nRows = in.length;
int nCols = in[0].length;
data = new double[nRows][nCols];
System.arraycopy(in, 0, data, 0, in.length);
for (int i = 0; i < nRows; i++) {
System.arraycopy(in[i], 0, data[i], 0, nCols);
}
lu = null;
}
/**
* Tests a given coordinate as being valid or invalid
*
* @param row the row index.
* @param col the column index.
* @return true if the coordinate is with the current dimensions
*/
private boolean isValidCoordinate(int row, int col) {
int nRows = this.getRowDimension();
int nCols = this.getColumnDimension();
return !(row < 0 || row > (nRows-1) || col < 0 || col > (nCols-1));
}
}
---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org