KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > commons > math > linear > BigMatrixImpl


1 /*
2  * Copyright 2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package org.apache.commons.math.linear;
18 import java.io.Serializable JavaDoc;
19 import java.math.BigDecimal JavaDoc;
20
21 /**
22  * Implementation for {@link BigMatrix} using a BigDecimal[][] array to store entries
23  * and <a HREF="http://www.math.gatech.edu/~bourbaki/math2601/Web-notes/2num.pdf">
24  * LU decompostion</a> to support linear system
25  * solution and inverse.
26  * <p>
27  * The LU decompostion is performed as needed, to support the following operations: <ul>
28  * <li>solve</li>
29  * <li>isSingular</li>
30  * <li>getDeterminant</li>
31  * <li>inverse</li> </ul>
32  * <p>
33 * <strong>Usage notes</strong>:<br>
34  * <ul><li>
35  * The LU decomposition is stored and reused on subsequent calls. If matrix
36  * data are modified using any of the public setXxx methods, the saved
37  * decomposition is discarded. If data are modified via references to the
38  * underlying array obtained using <code>getDataRef()</code>, then the stored
39  * LU decomposition will not be discarded. In this case, you need to
40  * explicitly invoke <code>LUDecompose()</code> to recompute the decomposition
41  * before using any of the methods above.</li>
42  * <li>
43  * As specified in the {@link BigMatrix} interface, matrix element indexing
44  * is 0-based -- e.g., <code>getEntry(0, 0)</code>
45  * returns the element in the first row, first column of the matrix.</li></ul>
46  * @version $Revision$ $Date: 2005-07-04 15:16:48 -0700 (Mon, 04 Jul 2005) $
47  */

48 public class BigMatrixImpl implements BigMatrix, Serializable JavaDoc {
49     
50     /** Serialization id */
51     static final long serialVersionUID = -1011428905656140431L;
52     
53     /** Entries of the matrix */
54     private BigDecimal JavaDoc data[][] = null;
55     
56     /** Entries of cached LU decomposition.
57      * All updates to data (other than luDecompose()) *must* set this to null
58      */

59     private BigDecimal JavaDoc lu[][] = null;
60     
61     /** Permutation associated with LU decompostion */
62     private int[] permutation = null;
63     
64     /** Parity of the permutation associated with the LU decomposition */
65     private int parity = 1;
66     
67     /** Rounding mode for divisions **/
68     private int roundingMode = BigDecimal.ROUND_HALF_UP;
69     
70     /*** BigDecimal scale ***/
71     private int scale = 64;
72     
73     /** Bound to determine effective singularity in LU decomposition */
74     protected static BigDecimal JavaDoc TOO_SMALL = new BigDecimal JavaDoc(10E-12);
75     
76     /** BigDecimal 0 */
77     static final BigDecimal JavaDoc ZERO = new BigDecimal JavaDoc(0);
78     /** BigDecimal 1 */
79     static final BigDecimal JavaDoc ONE = new BigDecimal JavaDoc(1);
80     
81     /**
82      * Creates a matrix with no data
83      */

84     public BigMatrixImpl() {
85     }
86     
87     /**
88      * Create a new BigMatrix with the supplied row and column dimensions.
89      *
90      * @param rowDimension the number of rows in the new matrix
91      * @param columnDimension the number of columns in the new matrix
92      * @throws IllegalArgumentException if row or column dimension is not
93      * positive
94      */

95     public BigMatrixImpl(int rowDimension, int columnDimension) {
96         if (rowDimension <=0 || columnDimension <=0) {
97             throw new IllegalArgumentException JavaDoc
98             ("row and column dimensions must be positive");
99         }
100         data = new BigDecimal JavaDoc[rowDimension][columnDimension];
101         lu = null;
102     }
103     
104     /**
105      * Create a new BigMatrix using the <code>data</code> as the underlying
106      * data array.
107      * <p>
108      * The input array is copied, not referenced.
109      *
110      * @param d data for new matrix
111      * @throws IllegalArgumentException if <code>d</code> is not rectangular
112      * (not all rows have the same length) or empty
113      * @throws NullPointerException if <code>d</code> is null
114      */

115     public BigMatrixImpl(BigDecimal JavaDoc[][] d) {
116         this.copyIn(d);
117         lu = null;
118     }
119     
120     /**
121      * Create a new BigMatrix using the <code>data</code> as the underlying
122      * data array.
123      * <p>
124      * The input array is copied, not referenced.
125      *
126      * @param d data for new matrix
127      * @throws IllegalArgumentException if <code>d</code> is not rectangular
128      * (not all rows have the same length) or empty
129      * @throws NullPointerException if <code>d</code> is null
130      */

131     public BigMatrixImpl(double[][] d) {
132         int nRows = d.length;
133         if (nRows == 0) {
134             throw new IllegalArgumentException JavaDoc(
135             "Matrix must have at least one row.");
136         }
137         int nCols = d[0].length;
138         if (nCols == 0) {
139             throw new IllegalArgumentException JavaDoc(
140             "Matrix must have at least one column.");
141         }
142         for (int row = 1; row < nRows; row++) {
143             if (d[row].length != nCols) {
144                 throw new IllegalArgumentException JavaDoc(
145                 "All input rows must have the same length.");
146             }
147         }
148         this.copyIn(d);
149         lu = null;
150     }
151     
152     /**
153      * Create a new BigMatrix using the values represented by the strings in
154      * <code>data</code> as the underlying data array.
155      *
156      * @param d data for new matrix
157      * @throws IllegalArgumentException if <code>d</code> is not rectangular
158      * (not all rows have the same length) or empty
159      * @throws NullPointerException if <code>d</code> is null
160      */

161     public BigMatrixImpl(String JavaDoc[][] d) {
162         int nRows = d.length;
163         if (nRows == 0) {
164             throw new IllegalArgumentException JavaDoc(
165             "Matrix must have at least one row.");
166         }
167         int nCols = d[0].length;
168         if (nCols == 0) {
169             throw new IllegalArgumentException JavaDoc(
170             "Matrix must have at least one column.");
171         }
172         for (int row = 1; row < nRows; row++) {
173             if (d[row].length != nCols) {
174                 throw new IllegalArgumentException JavaDoc(
175                 "All input rows must have the same length.");
176             }
177         }
178         this.copyIn(d);
179         lu = null;
180     }
181     
182     /**
183      * Create a new (column) BigMatrix using <code>v</code> as the
184      * data for the unique column of the <code>v.length x 1</code> matrix
185      * created.
186      * <p>
187      * The input array is copied, not referenced.
188      *
189      * @param v column vector holding data for new matrix
190      */

191     public BigMatrixImpl(BigDecimal JavaDoc[] v) {
192         int nRows = v.length;
193         data = new BigDecimal JavaDoc[nRows][1];
194         for (int row = 0; row < nRows; row++) {
195             data[row][0] = v[row];
196         }
197     }
198     
199     /**
200      * Create a new BigMatrix which is a copy of this.
201      *
202      * @return the cloned matrix
203      */

204     public BigMatrix copy() {
205         return new BigMatrixImpl(this.copyOut());
206     }
207     
208     /**
209      * Compute the sum of this and <code>m</code>.
210      *
211      * @param m matrix to be added
212      * @return this + m
213      * @exception IllegalArgumentException if m is not the same size as this
214      */

215     public BigMatrix add(BigMatrix m) throws IllegalArgumentException JavaDoc {
216         if (this.getColumnDimension() != m.getColumnDimension() ||
217                 this.getRowDimension() != m.getRowDimension()) {
218             throw new IllegalArgumentException JavaDoc("matrix dimension mismatch");
219         }
220         int rowCount = this.getRowDimension();
221         int columnCount = this.getColumnDimension();
222         BigDecimal JavaDoc[][] outData = new BigDecimal JavaDoc[rowCount][columnCount];
223         for (int row = 0; row < rowCount; row++) {
224             for (int col = 0; col < columnCount; col++) {
225                 outData[row][col] = data[row][col].add(m.getEntry(row, col));
226             }
227         }
228         return new BigMatrixImpl(outData);
229     }
230     
231     /**
232      * Compute this minus <code>m</code>.
233      *
234      * @param m matrix to be subtracted
235      * @return this + m
236      * @exception IllegalArgumentException if m is not the same size as *this
237      */

238     public BigMatrix subtract(BigMatrix m) throws IllegalArgumentException JavaDoc {
239         if (this.getColumnDimension() != m.getColumnDimension() ||
240                 this.getRowDimension() != m.getRowDimension()) {
241             throw new IllegalArgumentException JavaDoc("matrix dimension mismatch");
242         }
243         int rowCount = this.getRowDimension();
244         int columnCount = this.getColumnDimension();
245         BigDecimal JavaDoc[][] outData = new BigDecimal JavaDoc[rowCount][columnCount];
246         for (int row = 0; row < rowCount; row++) {
247             for (int col = 0; col < columnCount; col++) {
248                 outData[row][col] = data[row][col].subtract(m.getEntry(row, col));
249             }
250         }
251         return new BigMatrixImpl(outData);
252     }
253     
254     /**
255      * Returns the result of adding d to each entry of this.
256      *
257      * @param d value to be added to each entry
258      * @return d + this
259      */

260     public BigMatrix scalarAdd(BigDecimal JavaDoc d) {
261         int rowCount = this.getRowDimension();
262         int columnCount = this.getColumnDimension();
263         BigDecimal JavaDoc[][] outData = new BigDecimal JavaDoc[rowCount][columnCount];
264         for (int row = 0; row < rowCount; row++) {
265             for (int col = 0; col < columnCount; col++) {
266                 outData[row][col] = data[row][col].add(d);
267             }
268         }
269         return new BigMatrixImpl(outData);
270     }
271     
272     /**
273      * Returns the result multiplying each entry of this by <code>d</code>
274      * @param d value to multiply all entries by
275      * @return d * this
276      */

277     public BigMatrix scalarMultiply(BigDecimal JavaDoc d) {
278         int rowCount = this.getRowDimension();
279         int columnCount = this.getColumnDimension();
280         BigDecimal JavaDoc[][] outData = new BigDecimal JavaDoc[rowCount][columnCount];
281         for (int row = 0; row < rowCount; row++) {
282             for (int col = 0; col < columnCount; col++) {
283                 outData[row][col] = data[row][col].multiply(d);
284             }
285         }
286         return new BigMatrixImpl(outData);
287     }
288     
289     /**
290      * Returns the result of postmultiplying this by <code>m</code>.
291      * @param m matrix to postmultiply by
292      * @return this*m
293      * @throws IllegalArgumentException
294      * if columnDimension(this) != rowDimension(m)
295      */

296     public BigMatrix multiply(BigMatrix m) throws IllegalArgumentException JavaDoc {
297         if (this.getColumnDimension() != m.getRowDimension()) {
298             throw new IllegalArgumentException JavaDoc("Matrices are not multiplication compatible.");
299         }
300         int nRows = this.getRowDimension();
301         int nCols = m.getColumnDimension();
302         int nSum = this.getColumnDimension();
303         BigDecimal JavaDoc[][] outData = new BigDecimal JavaDoc[nRows][nCols];
304         BigDecimal JavaDoc sum = ZERO;
305         for (int row = 0; row < nRows; row++) {
306             for (int col = 0; col < nCols; col++) {
307                 sum = ZERO;
308                 for (int i = 0; i < nSum; i++) {
309                     sum = sum.add(data[row][i].multiply(m.getEntry(i, col)));
310                 }
311                 outData[row][col] = sum;
312             }
313         }
314         return new BigMatrixImpl(outData);
315     }
316     
317     /**
318      * Returns the result premultiplying this by <code>m</code>.
319      * @param m matrix to premultiply by
320      * @return m * this
321      * @throws IllegalArgumentException
322      * if rowDimension(this) != columnDimension(m)
323      */

324     public BigMatrix preMultiply(BigMatrix m) throws IllegalArgumentException JavaDoc {
325         return m.multiply(this);
326     }
327     
328     /**
329      * Returns matrix entries as a two-dimensional array.
330      * <p>
331      * Makes a fresh copy of the underlying data.
332      *
333      * @return 2-dimensional array of entries
334      */

335     public BigDecimal JavaDoc[][] getData() {
336         return copyOut();
337     }
338     
339     /**
340      * Returns matrix entries as a two-dimensional array.
341      * <p>
342      * Makes a fresh copy of the underlying data converted to
343      * <code>double</code> values.
344      *
345      * @return 2-dimensional array of entries
346      */

347     public double[][] getDataAsDoubleArray() {
348         int nRows = getRowDimension();
349         int nCols = getColumnDimension();
350         double d[][] = new double[nRows][nCols];
351         for (int i = 0; i < nRows; i++) {
352             for (int j=0; j<nCols;j++) {
353                 d[i][j] = data[i][j].doubleValue();
354             }
355         }
356         return d;
357     }
358     
359     /**
360      * Returns a reference to the underlying data array.
361      * <p>
362      * Does not make a fresh copy of the underlying data.
363      *
364      * @return 2-dimensional array of entries
365      */

366     public BigDecimal JavaDoc[][] getDataRef() {
367         return data;
368     }
369     
370     /***
371      * Gets the rounding mode for division operations
372      * The default is {@link java.math.BigDecimal#ROUND_HALF_UP}
373      * @see BigDecimal
374      * @return the rounding mode.
375      */

376     public int getRoundingMode() {
377         return roundingMode;
378     }
379     
380     /***
381      * Sets the rounding mode for decimal divisions.
382      * @see BigDecimal
383      * @param roundingMode
384      */

385     public void setRoundingMode(int roundingMode) {
386         this.roundingMode = roundingMode;
387     }
388     
389     /***
390      * Sets the scale for division operations.
391      * The default is 64
392      * @see BigDecimal
393      * @return the scale
394      */

395     public int getScale() {
396         return scale;
397     }
398     
399     /***
400      * Sets the scale for division operations.
401      * @see BigDecimal
402      * @param scale
403      */

404     public void setScale(int scale) {
405         this.scale = scale;
406     }
407     
408     /**
409      * Returns the <a HREF="http://mathworld.wolfram.com/MaximumAbsoluteRowSumNorm.html">
410      * maximum absolute row sum norm</a> of the matrix.
411      *
412      * @return norm
413      */

414     public BigDecimal JavaDoc getNorm() {
415         BigDecimal JavaDoc maxColSum = ZERO;
416         for (int col = 0; col < this.getColumnDimension(); col++) {
417             BigDecimal JavaDoc sum = ZERO;
418             for (int row = 0; row < this.getRowDimension(); row++) {
419                 sum = sum.add(data[row][col].abs());
420             }
421             maxColSum = maxColSum.max(sum);
422         }
423         return maxColSum;
424     }
425     
426     /**
427      * Gets a submatrix. Rows and columns are indicated
428      * counting from 0 to n-1.
429      *
430      * @param startRow Initial row index
431      * @param endRow Final row index
432      * @param startColumn Initial column index
433      * @param endColumn Final column index
434      * @return The subMatrix containing the data of the
435      * specified rows and columns
436      * @exception MatrixIndexException if row or column selections are not valid
437      */

438     public BigMatrix getSubMatrix(int startRow, int endRow, int startColumn,
439             int endColumn) throws MatrixIndexException {
440         if (startRow < 0 || startRow > endRow || endRow > data.length ||
441                 startColumn < 0 || startColumn > endColumn ||
442                 endColumn > data[0].length ) {
443             throw new MatrixIndexException(
444             "invalid row or column index selection");
445         }
446         BigMatrixImpl subMatrix = new BigMatrixImpl(endRow - startRow+1,
447                 endColumn - startColumn+1);
448         BigDecimal JavaDoc[][] subMatrixData = subMatrix.getDataRef();
449         for (int i = startRow; i <= endRow; i++) {
450             for (int j = startColumn; j <= endColumn; j++) {
451                 subMatrixData[i - startRow][j - startColumn] = data[i][j];
452             }
453         }
454         return subMatrix;
455     }
456     
457     /**
458      * Gets a submatrix. Rows and columns are indicated
459      * counting from 0 to n-1.
460      *
461      * @param selectedRows Array of row indices must be non-empty
462      * @param selectedColumns Array of column indices must be non-empty
463      * @return The subMatrix containing the data in the
464      * specified rows and columns
465      * @exception MatrixIndexException if supplied row or column index arrays
466      * are not valid
467      */

468     public BigMatrix getSubMatrix(int[] selectedRows, int[] selectedColumns)
469     throws MatrixIndexException {
470         if (selectedRows.length * selectedColumns.length == 0) {
471             throw new MatrixIndexException(
472             "selected row and column index arrays must be non-empty");
473         }
474         BigMatrixImpl subMatrix = new BigMatrixImpl(selectedRows.length,
475                 selectedColumns.length);
476         BigDecimal JavaDoc[][] subMatrixData = subMatrix.getDataRef();
477         try {
478             for (int i = 0; i < selectedRows.length; i++) {
479                 for (int j = 0; j < selectedColumns.length; j++) {
480                     subMatrixData[i][j] = data[selectedRows[i]][selectedColumns[j]];
481                 }
482             }
483         }
484         catch (ArrayIndexOutOfBoundsException JavaDoc e) {
485             throw new MatrixIndexException("matrix dimension mismatch");
486         }
487         return subMatrix;
488     }
489     
490     /**
491      * Replace the submatrix starting at <code>row, column</code> using data in
492      * the input <code>subMatrix</code> array. Indexes are 0-based.
493      * <p>
494      * Example:<br>
495      * Starting with <pre>
496      * 1 2 3 4
497      * 5 6 7 8
498      * 9 0 1 2
499      * </pre>
500      * and <code>subMatrix = {{3, 4} {5,6}}</code>, invoking
501      * <code>setSubMatrix(subMatrix,1,1))</code> will result in <pre>
502      * 1 2 3 4
503      * 5 3 4 8
504      * 9 5 6 2
505      * </pre>
506      *
507      * @param subMatrix array containing the submatrix replacement data
508      * @param row row coordinate of the top, left element to be replaced
509      * @param column column coordinate of the top, left element to be replaced
510      * @throws MatrixIndexException if subMatrix does not fit into this
511      * matrix from element in (row, column)
512      * @throws IllegalArgumentException if <code>subMatrix</code> is not rectangular
513      * (not all rows have the same length) or empty
514      * @throws NullPointerException if <code>subMatrix</code> is null
515      * @since 1.1
516      */

517     public void setSubMatrix(BigDecimal JavaDoc[][] subMatrix, int row, int column)
518     throws MatrixIndexException {
519         if ((row < 0) || (column < 0)){
520             throw new MatrixIndexException
521             ("invalid row or column index selection");
522         }
523         int nRows = subMatrix.length;
524         if (nRows == 0) {
525             throw new IllegalArgumentException JavaDoc(
526             "Matrix must have at least one row.");
527         }
528         int nCols = subMatrix[0].length;
529         if (nCols == 0) {
530             throw new IllegalArgumentException JavaDoc(
531             "Matrix must have at least one column.");
532         }
533         for (int r = 1; r < nRows; r++) {
534             if (subMatrix[r].length != nCols) {
535                 throw new IllegalArgumentException JavaDoc(
536                 "All input rows must have the same length.");
537             }
538         }
539         if (data == null) {
540             if ((row > 0)||(column > 0)) throw new MatrixIndexException
541             ("matrix must be initialized to perfom this method");
542             data = new BigDecimal JavaDoc[nRows][nCols];
543             System.arraycopy(subMatrix, 0, data, 0, subMatrix.length);
544         }
545         if (((nRows + row) > this.getRowDimension()) ||
546             (nCols + column > this.getColumnDimension()))
547             throw new MatrixIndexException(
548             "invalid row or column index selection");
549         for (int i = 0; i < nRows; i++) {
550             System.arraycopy(subMatrix[i], 0, data[row + i], column, nCols);
551         }
552         lu = null;
553     }
554     
555     /**
556      * Returns the entries in row number <code>row</code>
557      * as a row matrix. Row indices start at 0.
558      *
559      * @param row the row to be fetched
560      * @return row matrix
561      * @throws MatrixIndexException if the specified row index is invalid
562      */

563     public BigMatrix getRowMatrix(int row) throws MatrixIndexException {
564         if ( !isValidCoordinate( row, 0)) {
565             throw new MatrixIndexException("illegal row argument");
566         }
567         int ncols = this.getColumnDimension();
568         BigDecimal JavaDoc[][] out = new BigDecimal JavaDoc[1][ncols];
569         System.arraycopy(data[row], 0, out[0], 0, ncols);
570         return new BigMatrixImpl(out);
571     }
572     
573     /**
574      * Returns the entries in column number <code>column</code>
575      * as a column matrix. Column indices start at 0.
576      *
577      * @param column the column to be fetched
578      * @return column matrix
579      * @throws MatrixIndexException if the specified column index is invalid
580      */

581     public BigMatrix getColumnMatrix(int column) throws MatrixIndexException {
582         if ( !isValidCoordinate( 0, column)) {
583             throw new MatrixIndexException("illegal column argument");
584         }
585         int nRows = this.getRowDimension();
586         BigDecimal JavaDoc[][] out = new BigDecimal JavaDoc[nRows][1];
587         for (int row = 0; row < nRows; row++) {
588             out[row][0] = data[row][column];
589         }
590         return new BigMatrixImpl(out);
591     }
592     
593     /**
594      * Returns the entries in row number <code>row</code> as an array.
595      * <p>
596      * Row indices start at 0. A <code>MatrixIndexException</code> is thrown
597      * unless <code>0 <= row < rowDimension.</code>
598      *
599      * @param row the row to be fetched
600      * @return array of entries in the row
601      * @throws MatrixIndexException if the specified row index is not valid
602      */

603     public BigDecimal JavaDoc[] getRow(int row) throws MatrixIndexException {
604         if ( !isValidCoordinate( row, 0 ) ) {
605             throw new MatrixIndexException("illegal row argument");
606         }
607         int ncols = this.getColumnDimension();
608         BigDecimal JavaDoc[] out = new BigDecimal JavaDoc[ncols];
609         System.arraycopy(data[row], 0, out, 0, ncols);
610         return out;
611     }
612     
613      /**
614      * Returns the entries in row number <code>row</code> as an array
615      * of double values.
616      * <p>
617      * Row indices start at 0. A <code>MatrixIndexException</code> is thrown
618      * unless <code>0 <= row < rowDimension.</code>
619      *
620      * @param row the row to be fetched
621      * @return array of entries in the row
622      * @throws MatrixIndexException if the specified row index is not valid
623      */

624     public double[] getRowAsDoubleArray(int row) throws MatrixIndexException {
625         if ( !isValidCoordinate( row, 0 ) ) {
626             throw new MatrixIndexException("illegal row argument");
627         }
628         int ncols = this.getColumnDimension();
629         double[] out = new double[ncols];
630         for (int i=0;i<ncols;i++) {
631             out[i] = data[row][i].doubleValue();
632         }
633         return out;
634     }
635     
636      /**
637      * Returns the entries in column number <code>col</code> as an array.
638      * <p>
639      * Column indices start at 0. A <code>MatrixIndexException</code> is thrown
640      * unless <code>0 <= column < columnDimension.</code>
641      *
642      * @param col the column to be fetched
643      * @return array of entries in the column
644      * @throws MatrixIndexException if the specified column index is not valid
645      */

646     public BigDecimal JavaDoc[] getColumn(int col) throws MatrixIndexException {
647         if ( !isValidCoordinate(0, col) ) {
648             throw new MatrixIndexException("illegal column argument");
649         }
650         int nRows = this.getRowDimension();
651         BigDecimal JavaDoc[] out = new BigDecimal JavaDoc[nRows];
652         for (int i = 0; i < nRows; i++) {
653             out[i] = data[i][col];
654         }
655         return out;
656     }
657     
658     /**
659      * Returns the entries in column number <code>col</code> as an array
660      * of double values.
661      * <p>
662      * Column indices start at 0. A <code>MatrixIndexException</code> is thrown
663      * unless <code>0 <= column < columnDimension.</code>
664      *
665      * @param col the column to be fetched
666      * @return array of entries in the column
667      * @throws MatrixIndexException if the specified column index is not valid
668      */

669     public double[] getColumnAsDoubleArray(int col) throws MatrixIndexException {
670         if ( !isValidCoordinate( 0, col ) ) {
671             throw new MatrixIndexException("illegal column argument");
672         }
673         int nrows = this.getRowDimension();
674         double[] out = new double[nrows];
675         for (int i=0;i<nrows;i++) {
676             out[i] = data[i][col].doubleValue();
677         }
678         return out;
679     }
680     
681      /**
682      * Returns the entry in the specified row and column.
683      * <p>
684      * Row and column indices start at 0 and must satisfy
685      * <ul>
686      * <li><code>0 <= row < rowDimension</code></li>
687      * <li><code> 0 <= column < columnDimension</code></li>
688      * </ul>
689      * otherwise a <code>MatrixIndexException</code> is thrown.
690      *
691      * @param row row location of entry to be fetched
692      * @param column column location of entry to be fetched
693      * @return matrix entry in row,column
694      * @throws MatrixIndexException if the row or column index is not valid
695      */

696     public BigDecimal JavaDoc getEntry(int row, int column)
697     throws MatrixIndexException {
698         if (!isValidCoordinate(row,column)) {
699             throw new MatrixIndexException("matrix entry does not exist");
700         }
701         return data[row][column];
702     }
703     
704     /**
705      * Returns the entry in the specified row and column as a double.
706      * <p>
707      * Row and column indices start at 0 and must satisfy
708      * <ul>
709      * <li><code>0 <= row < rowDimension</code></li>
710      * <li><code> 0 <= column < columnDimension</code></li>
711      * </ul>
712      * otherwise a <code>MatrixIndexException</code> is thrown.
713      *
714      * @param row row location of entry to be fetched
715      * @param column column location of entry to be fetched
716      * @return matrix entry in row,column
717      * @throws MatrixIndexException if the row
718      * or column index is not valid
719      */

720     public double getEntryAsDouble(int row, int column) throws MatrixIndexException {
721         return getEntry(row,column).doubleValue();
722     }
723     
724     /**
725      * Returns the transpose matrix.
726      *
727      * @return transpose matrix
728      */

729     public BigMatrix transpose() {
730         int nRows = this.getRowDimension();
731         int nCols = this.getColumnDimension();
732         BigMatrixImpl out = new BigMatrixImpl(nCols, nRows);
733         BigDecimal JavaDoc[][] outData = out.getDataRef();
734         for (int row = 0; row < nRows; row++) {
735             for (int col = 0; col < nCols; col++) {
736                 outData[col][row] = data[row][col];
737             }
738         }
739         return out;
740     }
741     
742     /**
743      * Returns the inverse matrix if this matrix is invertible.
744      *
745      * @return inverse matrix
746      * @throws InvalidMatrixException if this is not invertible
747      */

748     public BigMatrix inverse() throws InvalidMatrixException {
749         return solve(MatrixUtils.createBigIdentityMatrix
750                 (this.getRowDimension()));
751     }
752     
753     /**
754      * Returns the determinant of this matrix.
755      *
756      * @return determinant
757      * @throws InvalidMatrixException if matrix is not square
758      */

759     public BigDecimal JavaDoc getDeterminant() throws InvalidMatrixException {
760         if (!isSquare()) {
761             throw new InvalidMatrixException("matrix is not square");
762         }
763         if (isSingular()) { // note: this has side effect of attempting LU decomp if lu == null
764
return ZERO;
765         } else {
766             BigDecimal JavaDoc det = (parity == 1) ? ONE : ONE.negate();
767             for (int i = 0; i < this.getRowDimension(); i++) {
768                 det = det.multiply(lu[i][i]);
769             }
770             return det;
771         }
772     }
773     
774      /**
775      * Is this a square matrix?
776      * @return true if the matrix is square (rowDimension = columnDimension)
777      */

778     public boolean isSquare() {
779         return (this.getColumnDimension() == this.getRowDimension());
780     }
781     
782     /**
783      * Is this a singular matrix?
784      * @return true if the matrix is singular
785      */

786     public boolean isSingular() {
787         if (lu == null) {
788             try {
789                 luDecompose();
790                 return false;
791             } catch (InvalidMatrixException ex) {
792                 return true;
793             }
794         } else { // LU decomp must have been successfully performed
795
return false; // so the matrix is not singular
796
}
797     }
798     
799     /**
800      * Returns the number of rows in the matrix.
801      *
802      * @return rowDimension
803      */

804     public int getRowDimension() {
805         return data.length;
806     }
807     
808     /**
809      * Returns the number of columns in the matrix.
810      *
811      * @return columnDimension
812      */

813     public int getColumnDimension() {
814         return data[0].length;
815     }
816     
817      /**
818      * Returns the <a HREF="http://mathworld.wolfram.com/MatrixTrace.html">
819      * trace</a> of the matrix (the sum of the elements on the main diagonal).
820      *
821      * @return trace
822      *
823      * @throws IllegalArgumentException if this matrix is not square.
824      */

825     public BigDecimal JavaDoc getTrace() throws IllegalArgumentException JavaDoc {
826         if (!isSquare()) {
827             throw new IllegalArgumentException JavaDoc("matrix is not square");
828         }
829         BigDecimal