~ubuntu-branches/ubuntu/maverick/commons-math/maverick

« back to all changes in this revision

Viewing changes to src/java/org/apache/commons/math/linear/BigMatrixImpl.java

  • Committer: Bazaar Package Importer
  • Author(s): Damien Raude-Morvan
  • Date: 2009-08-22 01:13:25 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20090822011325-hi4peq1ua5weguwn
Tags: 2.0-1
* New upstream release.
* Set Maintainer field to Debian Java Team
* Add myself as Uploaders
* Switch to Quilt patch system:
  - Refresh all patchs
  - Remove B-D on dpatch, Add B-D on quilt
  - Include patchsys-quilt.mk in debian/rules
* Bump Standards-Version to 3.8.3:
  - Add a README.source to describe patch system
* Maven POMs:
  - Add a Build-Depends-Indep dependency on maven-repo-helper
  - Use mh_installpom and mh_installjar to install the POM and the jar to the
    Maven repository
* Use default-jdk/jre:
  - Depends on java5-runtime-headless
  - Build-Depends on default-jdk
  - Use /usr/lib/jvm/default-java as JAVA_HOME
* Move api documentation to /usr/share/doc/libcommons-math-java/api
* Build-Depends on junit4 instead of junit

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Licensed to the Apache Software Foundation (ASF) under one or more
3
 
 * contributor license agreements.  See the NOTICE file distributed with
4
 
 * this work for additional information regarding copyright ownership.
5
 
 * The ASF licenses this file to You under the Apache License, Version 2.0
6
 
 * (the "License"); you may not use this file except in compliance with
7
 
 * the License.  You may obtain a copy of the License at
8
 
 *
9
 
 *      http://www.apache.org/licenses/LICENSE-2.0
10
 
 *
11
 
 * Unless required by applicable law or agreed to in writing, software
12
 
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 
 * See the License for the specific language governing permissions and
15
 
 * limitations under the License.
16
 
 */
17
 
 
18
 
package org.apache.commons.math.linear;
19
 
import java.io.Serializable;
20
 
import java.math.BigDecimal;
21
 
 
22
 
/**
23
 
 * Implementation of {@link BigMatrix} using a BigDecimal[][] array to store entries
24
 
 * and <a href="http://www.math.gatech.edu/~bourbaki/math2601/Web-notes/2num.pdf">
25
 
 * LU decompostion</a> to support linear system 
26
 
 * solution and inverse.
27
 
 * <p>
28
 
 * The LU decompostion is performed as needed, to support the following operations: <ul>
29
 
 * <li>solve</li>
30
 
 * <li>isSingular</li>
31
 
 * <li>getDeterminant</li>
32
 
 * <li>inverse</li> </ul></p>
33
 
 * <p>
34
 
* <strong>Usage notes</strong>:<br>
35
 
 * <ul><li>
36
 
 * The LU decomposition is stored and reused on subsequent calls.  If matrix
37
 
 * data are modified using any of the public setXxx methods, the saved
38
 
 * decomposition is discarded.  If data are modified via references to the
39
 
 * underlying array obtained using <code>getDataRef()</code>, then the stored
40
 
 * LU decomposition will not be discarded.  In this case, you need to
41
 
 * explicitly invoke <code>LUDecompose()</code> to recompute the decomposition
42
 
 * before using any of the methods above.</li>
43
 
 * <li>
44
 
 * As specified in the {@link BigMatrix} interface, matrix element indexing
45
 
 * is 0-based -- e.g., <code>getEntry(0, 0)</code>
46
 
 * returns the element in the first row, first column of the matrix.</li></ul></p>
47
 
 * 
48
 
 * @version $Revision: 617953 $ $Date: 2008-02-02 22:54:00 -0700 (Sat, 02 Feb 2008) $
49
 
 */
50
 
public class BigMatrixImpl implements BigMatrix, Serializable {
51
 
    
52
 
    /** Serialization id */
53
 
    private static final long serialVersionUID = -1011428905656140431L;
54
 
    
55
 
    /** Entries of the matrix */
56
 
    private BigDecimal data[][] = null;
57
 
    
58
 
    /** Entries of cached LU decomposition.
59
 
     *  All updates to data (other than luDecompose()) *must* set this to null
60
 
     */
61
 
    private BigDecimal lu[][] = null;
62
 
    
63
 
    /** Permutation associated with LU decomposition */
64
 
    private int[] permutation = null;
65
 
    
66
 
    /** Parity of the permutation associated with the LU decomposition */
67
 
    private int parity = 1;
68
 
    
69
 
    /** Rounding mode for divisions **/
70
 
    private int roundingMode = BigDecimal.ROUND_HALF_UP;
71
 
    
72
 
    /*** BigDecimal scale ***/
73
 
    private int scale = 64;
74
 
    
75
 
    /** Bound to determine effective singularity in LU decomposition */
76
 
    protected static BigDecimal TOO_SMALL = new BigDecimal(10E-12);
77
 
    
78
 
    /** BigDecimal 0 */
79
 
    static final BigDecimal ZERO = new BigDecimal(0);
80
 
    /** BigDecimal 1 */
81
 
    static final BigDecimal ONE = new BigDecimal(1);
82
 
    
83
 
    /** 
84
 
     * Creates a matrix with no data
85
 
     */
86
 
    public BigMatrixImpl() {
87
 
    }
88
 
    
89
 
    /**
90
 
     * Create a new BigMatrix with the supplied row and column dimensions.
91
 
     *
92
 
     * @param rowDimension      the number of rows in the new matrix
93
 
     * @param columnDimension   the number of columns in the new matrix
94
 
     * @throws IllegalArgumentException if row or column dimension is not
95
 
     *  positive
96
 
     */
97
 
    public BigMatrixImpl(int rowDimension, int columnDimension) {
98
 
        if (rowDimension <=0 || columnDimension <=0) {
99
 
            throw new IllegalArgumentException
100
 
            ("row and column dimensions must be positive");
101
 
        }
102
 
        data = new BigDecimal[rowDimension][columnDimension];
103
 
        lu = null;
104
 
    }
105
 
    
106
 
    /**
107
 
     * Create a new BigMatrix using the <code>data</code> as the underlying
108
 
     * data array.
109
 
     * <p>
110
 
     * The input array is copied, not referenced.</p>
111
 
     *
112
 
     * @param d data for new matrix
113
 
     * @throws IllegalArgumentException if <code>d</code> is not rectangular
114
 
     *  (not all rows have the same length) or empty
115
 
     * @throws NullPointerException if <code>d</code> is null
116
 
     */
117
 
    public BigMatrixImpl(BigDecimal[][] d) {
118
 
        this.copyIn(d);
119
 
        lu = null;
120
 
    }
121
 
    
122
 
    /**
123
 
     * Create a new BigMatrix using the <code>data</code> as the underlying
124
 
     * data array.
125
 
     * <p>
126
 
     * The input array is copied, not referenced.</p>
127
 
     *
128
 
     * @param d data for new matrix
129
 
     * @throws IllegalArgumentException if <code>d</code> is not rectangular
130
 
     *  (not all rows have the same length) or empty
131
 
     * @throws NullPointerException if <code>d</code> is null
132
 
     */
133
 
    public BigMatrixImpl(double[][] d) {
134
 
        int nRows = d.length;
135
 
        if (nRows == 0) {
136
 
            throw new IllegalArgumentException(
137
 
            "Matrix must have at least one row."); 
138
 
        }
139
 
        int nCols = d[0].length;
140
 
        if (nCols == 0) {
141
 
            throw new IllegalArgumentException(
142
 
            "Matrix must have at least one column."); 
143
 
        }
144
 
        for (int row = 1; row < nRows; row++) {
145
 
            if (d[row].length != nCols) {
146
 
                throw new IllegalArgumentException(
147
 
                "All input rows must have the same length.");
148
 
            }
149
 
        }
150
 
        this.copyIn(d);
151
 
        lu = null;
152
 
    }
153
 
    
154
 
    /**
155
 
     * Create a new BigMatrix using the values represented by the strings in 
156
 
     * <code>data</code> as the underlying data array.
157
 
     *
158
 
     * @param d data for new matrix
159
 
     * @throws IllegalArgumentException if <code>d</code> is not rectangular
160
 
     *  (not all rows have the same length) or empty
161
 
     * @throws NullPointerException if <code>d</code> is null
162
 
     */
163
 
    public BigMatrixImpl(String[][] d) {
164
 
        int nRows = d.length;
165
 
        if (nRows == 0) {
166
 
            throw new IllegalArgumentException(
167
 
            "Matrix must have at least one row."); 
168
 
        }
169
 
        int nCols = d[0].length;
170
 
        if (nCols == 0) {
171
 
            throw new IllegalArgumentException(
172
 
            "Matrix must have at least one column."); 
173
 
        }
174
 
        for (int row = 1; row < nRows; row++) {
175
 
            if (d[row].length != nCols) {
176
 
                throw new IllegalArgumentException(
177
 
                "All input rows must have the same length.");
178
 
            }
179
 
        }
180
 
        this.copyIn(d);
181
 
        lu = null;
182
 
    }
183
 
    
184
 
    /**
185
 
     * Create a new (column) BigMatrix using <code>v</code> as the
186
 
     * data for the unique column of the <code>v.length x 1</code> matrix 
187
 
     * created.
188
 
     * <p>
189
 
     * The input array is copied, not referenced.</p>
190
 
     *
191
 
     * @param v column vector holding data for new matrix
192
 
     */
193
 
    public BigMatrixImpl(BigDecimal[] v) {
194
 
        int nRows = v.length;
195
 
        data = new BigDecimal[nRows][1];
196
 
        for (int row = 0; row < nRows; row++) {
197
 
            data[row][0] = v[row];
198
 
        }
199
 
    }
200
 
    
201
 
    /**
202
 
     * Create a new BigMatrix which is a copy of this.
203
 
     *
204
 
     * @return  the cloned matrix
205
 
     */
206
 
    public BigMatrix copy() {
207
 
        return new BigMatrixImpl(this.copyOut());
208
 
    }
209
 
    
210
 
    /**
211
 
     * Compute the sum of this and <code>m</code>.
212
 
     *
213
 
     * @param m    matrix to be added
214
 
     * @return     this + m
215
 
     * @exception  IllegalArgumentException if m is not the same size as this
216
 
     */
217
 
    public BigMatrix add(BigMatrix m) throws IllegalArgumentException {
218
 
        if (this.getColumnDimension() != m.getColumnDimension() ||
219
 
                this.getRowDimension() != m.getRowDimension()) {
220
 
            throw new IllegalArgumentException("matrix dimension mismatch");
221
 
        }
222
 
        int rowCount = this.getRowDimension();
223
 
        int columnCount = this.getColumnDimension();
224
 
        BigDecimal[][] outData = new BigDecimal[rowCount][columnCount];
225
 
        for (int row = 0; row < rowCount; row++) {
226
 
            for (int col = 0; col < columnCount; col++) {
227
 
                outData[row][col] = data[row][col].add(m.getEntry(row, col));
228
 
            }
229
 
        }
230
 
        return new BigMatrixImpl(outData);
231
 
    }
232
 
    
233
 
    /**
234
 
     * Compute  this minus <code>m</code>.
235
 
     *
236
 
     * @param m    matrix to be subtracted
237
 
     * @return     this + m
238
 
     * @exception  IllegalArgumentException if m is not the same size as *this
239
 
     */
240
 
    public BigMatrix subtract(BigMatrix m) throws IllegalArgumentException {
241
 
        if (this.getColumnDimension() != m.getColumnDimension() ||
242
 
                this.getRowDimension() != m.getRowDimension()) {
243
 
            throw new IllegalArgumentException("matrix dimension mismatch");
244
 
        }
245
 
        int rowCount = this.getRowDimension();
246
 
        int columnCount = this.getColumnDimension();
247
 
        BigDecimal[][] outData = new BigDecimal[rowCount][columnCount];
248
 
        for (int row = 0; row < rowCount; row++) {
249
 
            for (int col = 0; col < columnCount; col++) {
250
 
                outData[row][col] = data[row][col].subtract(m.getEntry(row, col));
251
 
            }
252
 
        }
253
 
        return new BigMatrixImpl(outData);
254
 
    }
255
 
    
256
 
    /**
257
 
     * Returns the result of adding d to each entry of this.
258
 
     *
259
 
     * @param d    value to be added to each entry
260
 
     * @return     d + this
261
 
     */
262
 
    public BigMatrix scalarAdd(BigDecimal d) {
263
 
        int rowCount = this.getRowDimension();
264
 
        int columnCount = this.getColumnDimension();
265
 
        BigDecimal[][] outData = new BigDecimal[rowCount][columnCount];
266
 
        for (int row = 0; row < rowCount; row++) {
267
 
            for (int col = 0; col < columnCount; col++) {
268
 
                outData[row][col] = data[row][col].add(d);
269
 
            }
270
 
        }
271
 
        return new BigMatrixImpl(outData);
272
 
    }
273
 
    
274
 
    /**
275
 
     * Returns the result multiplying each entry of this by <code>d</code>
276
 
     * @param d  value to multiply all entries by
277
 
     * @return d * this
278
 
     */
279
 
    public BigMatrix scalarMultiply(BigDecimal d) {
280
 
        int rowCount = this.getRowDimension();
281
 
        int columnCount = this.getColumnDimension();
282
 
        BigDecimal[][] outData = new BigDecimal[rowCount][columnCount];
283
 
        for (int row = 0; row < rowCount; row++) {
284
 
            for (int col = 0; col < columnCount; col++) {
285
 
                outData[row][col] = data[row][col].multiply(d);
286
 
            }
287
 
        }
288
 
        return new BigMatrixImpl(outData);
289
 
    }
290
 
    
291
 
    /**
292
 
     * Returns the result of postmultiplying this by <code>m</code>.
293
 
     * @param m    matrix to postmultiply by
294
 
     * @return     this*m
295
 
     * @throws     IllegalArgumentException
296
 
     *             if columnDimension(this) != rowDimension(m)
297
 
     */
298
 
    public BigMatrix multiply(BigMatrix m) throws IllegalArgumentException {
299
 
        if (this.getColumnDimension() != m.getRowDimension()) {
300
 
            throw new IllegalArgumentException("Matrices are not multiplication compatible.");
301
 
        }
302
 
        int nRows = this.getRowDimension();
303
 
        int nCols = m.getColumnDimension();
304
 
        int nSum = this.getColumnDimension();
305
 
        BigDecimal[][] outData = new BigDecimal[nRows][nCols];
306
 
        BigDecimal sum = ZERO;
307
 
        for (int row = 0; row < nRows; row++) {
308
 
            for (int col = 0; col < nCols; col++) {
309
 
                sum = ZERO;
310
 
                for (int i = 0; i < nSum; i++) {
311
 
                    sum = sum.add(data[row][i].multiply(m.getEntry(i, col)));
312
 
                }
313
 
                outData[row][col] = sum;
314
 
            }
315
 
        }
316
 
        return new BigMatrixImpl(outData);
317
 
    }
318
 
    
319
 
    /**
320
 
     * Returns the result premultiplying this by <code>m</code>.
321
 
     * @param m    matrix to premultiply by
322
 
     * @return     m * this
323
 
     * @throws     IllegalArgumentException
324
 
     *             if rowDimension(this) != columnDimension(m)
325
 
     */
326
 
    public BigMatrix preMultiply(BigMatrix m) throws IllegalArgumentException {
327
 
        return m.multiply(this);
328
 
    }
329
 
    
330
 
    /**
331
 
     * Returns matrix entries as a two-dimensional array.
332
 
     * <p>
333
 
     * Makes a fresh copy of the underlying data.</p>
334
 
     *
335
 
     * @return    2-dimensional array of entries
336
 
     */
337
 
    public BigDecimal[][] getData() {
338
 
        return copyOut();
339
 
    }
340
 
    
341
 
    /**
342
 
     * Returns matrix entries as a two-dimensional array.
343
 
     * <p>
344
 
     * Makes a fresh copy of the underlying data converted to
345
 
     * <code>double</code> values.</p>
346
 
     *
347
 
     * @return    2-dimensional array of entries
348
 
     */
349
 
    public double[][] getDataAsDoubleArray() {
350
 
        int nRows = getRowDimension();
351
 
        int nCols = getColumnDimension();
352
 
        double d[][] = new double[nRows][nCols];
353
 
        for (int i = 0; i < nRows; i++) {
354
 
            for (int j=0; j<nCols;j++) {
355
 
                d[i][j] = data[i][j].doubleValue();
356
 
            }
357
 
        }
358
 
        return d;
359
 
    }
360
 
    
361
 
    /**
362
 
     * Returns a reference to the underlying data array.
363
 
     * <p>
364
 
     * Does not make a fresh copy of the underlying data.</p>
365
 
     *
366
 
     * @return 2-dimensional array of entries
367
 
     */
368
 
    public BigDecimal[][] getDataRef() {
369
 
        return data;
370
 
    }
371
 
    
372
 
    /***
373
 
     * Gets the rounding mode for division operations
374
 
     * The default is {@link java.math.BigDecimal#ROUND_HALF_UP}
375
 
     * @see BigDecimal
376
 
     * @return the rounding mode.
377
 
     */ 
378
 
    public int getRoundingMode() {
379
 
        return roundingMode;
380
 
    }
381
 
    
382
 
    /***
383
 
     * Sets the rounding mode for decimal divisions.
384
 
     * @see BigDecimal
385
 
     * @param roundingMode rounding mode for decimal divisions
386
 
     */
387
 
    public void setRoundingMode(int roundingMode) {
388
 
        this.roundingMode = roundingMode;
389
 
    }
390
 
    
391
 
    /***
392
 
     * Sets the scale for division operations.
393
 
     * The default is 64
394
 
     * @see BigDecimal
395
 
     * @return the scale
396
 
     */
397
 
    public int getScale() {
398
 
        return scale;
399
 
    }
400
 
    
401
 
    /***
402
 
     * Sets the scale for division operations.
403
 
     * @see BigDecimal
404
 
     * @param scale scale for division operations
405
 
     */
406
 
    public void setScale(int scale) {
407
 
        this.scale = scale;
408
 
    }
409
 
    
410
 
    /**
411
 
     * Returns the <a href="http://mathworld.wolfram.com/MaximumAbsoluteRowSumNorm.html">
412
 
     * maximum absolute row sum norm</a> of the matrix.
413
 
     *
414
 
     * @return norm
415
 
     */
416
 
    public BigDecimal getNorm() {
417
 
        BigDecimal maxColSum = ZERO;
418
 
        for (int col = 0; col < this.getColumnDimension(); col++) {
419
 
            BigDecimal sum = ZERO;
420
 
            for (int row = 0; row < this.getRowDimension(); row++) {
421
 
                sum = sum.add(data[row][col].abs());
422
 
            }
423
 
            maxColSum = maxColSum.max(sum);
424
 
        }
425
 
        return maxColSum;
426
 
    }
427
 
    
428
 
    /**
429
 
     * Gets a submatrix. Rows and columns are indicated
430
 
     * counting from 0 to n-1.
431
 
     *
432
 
     * @param startRow Initial row index
433
 
     * @param endRow Final row index
434
 
     * @param startColumn Initial column index
435
 
     * @param endColumn Final column index
436
 
     * @return The subMatrix containing the data of the
437
 
     *         specified rows and columns
438
 
     * @exception MatrixIndexException if row or column selections are not valid
439
 
     */
440
 
    public BigMatrix getSubMatrix(int startRow, int endRow, int startColumn,
441
 
            int endColumn) throws MatrixIndexException {
442
 
        if (startRow < 0 || startRow > endRow || endRow > data.length ||
443
 
                startColumn < 0 || startColumn > endColumn ||
444
 
                endColumn > data[0].length ) {
445
 
            throw new MatrixIndexException(
446
 
            "invalid row or column index selection");
447
 
        }
448
 
        BigMatrixImpl subMatrix = new BigMatrixImpl(endRow - startRow+1,
449
 
                endColumn - startColumn+1);
450
 
        BigDecimal[][] subMatrixData = subMatrix.getDataRef();
451
 
        for (int i = startRow; i <= endRow; i++) {
452
 
            for (int j = startColumn; j <= endColumn; j++) {
453
 
                subMatrixData[i - startRow][j - startColumn] = data[i][j];
454
 
            }
455
 
        }
456
 
        return subMatrix;
457
 
    }
458
 
    
459
 
    /**
460
 
     * Gets a submatrix. Rows and columns are indicated
461
 
     * counting from 0 to n-1.
462
 
     *
463
 
     * @param selectedRows Array of row indices must be non-empty
464
 
     * @param selectedColumns Array of column indices must be non-empty
465
 
     * @return The subMatrix containing the data in the
466
 
     *     specified rows and columns
467
 
     * @exception MatrixIndexException  if supplied row or column index arrays
468
 
     *     are not valid
469
 
     */
470
 
    public BigMatrix getSubMatrix(int[] selectedRows, int[] selectedColumns)
471
 
    throws MatrixIndexException {
472
 
        if (selectedRows.length * selectedColumns.length == 0) {
473
 
            throw new MatrixIndexException(
474
 
            "selected row and column index arrays must be non-empty");
475
 
        }
476
 
        BigMatrixImpl subMatrix = new BigMatrixImpl(selectedRows.length,
477
 
                selectedColumns.length);
478
 
        BigDecimal[][] subMatrixData = subMatrix.getDataRef();
479
 
        try  {
480
 
            for (int i = 0; i < selectedRows.length; i++) {
481
 
                for (int j = 0; j < selectedColumns.length; j++) {
482
 
                    subMatrixData[i][j] = data[selectedRows[i]][selectedColumns[j]];
483
 
                }
484
 
            }
485
 
        }
486
 
        catch (ArrayIndexOutOfBoundsException e) {
487
 
            throw new MatrixIndexException("matrix dimension mismatch");
488
 
        }
489
 
        return subMatrix;
490
 
    } 
491
 
    
492
 
    /**
493
 
     * Replace the submatrix starting at <code>row, column</code> using data in
494
 
     * the input <code>subMatrix</code> array. Indexes are 0-based.
495
 
     * <p> 
496
 
     * Example:<br>
497
 
     * Starting with <pre>
498
 
     * 1  2  3  4
499
 
     * 5  6  7  8
500
 
     * 9  0  1  2
501
 
     * </pre>
502
 
     * and <code>subMatrix = {{3, 4} {5,6}}</code>, invoking 
503
 
     * <code>setSubMatrix(subMatrix,1,1))</code> will result in <pre>
504
 
     * 1  2  3  4
505
 
     * 5  3  4  8
506
 
     * 9  5  6  2
507
 
     * </pre></p>
508
 
     * 
509
 
     * @param subMatrix  array containing the submatrix replacement data
510
 
     * @param row  row coordinate of the top, left element to be replaced
511
 
     * @param column  column coordinate of the top, left element to be replaced
512
 
     * @throws MatrixIndexException  if subMatrix does not fit into this 
513
 
     *    matrix from element in (row, column) 
514
 
     * @throws IllegalArgumentException if <code>subMatrix</code> is not rectangular
515
 
     *  (not all rows have the same length) or empty
516
 
     * @throws NullPointerException if <code>subMatrix</code> is null
517
 
     * @since 1.1
518
 
     */
519
 
    public void setSubMatrix(BigDecimal[][] subMatrix, int row, int column) 
520
 
    throws MatrixIndexException {
521
 
        if ((row < 0) || (column < 0)){
522
 
            throw new MatrixIndexException
523
 
            ("invalid row or column index selection");          
524
 
        }
525
 
        int nRows = subMatrix.length;
526
 
        if (nRows == 0) {
527
 
            throw new IllegalArgumentException(
528
 
            "Matrix must have at least one row."); 
529
 
        }
530
 
        int nCols = subMatrix[0].length;
531
 
        if (nCols == 0) {
532
 
            throw new IllegalArgumentException(
533
 
            "Matrix must have at least one column."); 
534
 
        }
535
 
        for (int r = 1; r < nRows; r++) {
536
 
            if (subMatrix[r].length != nCols) {
537
 
                throw new IllegalArgumentException(
538
 
                "All input rows must have the same length.");
539
 
            }
540
 
        }       
541
 
        if (data == null) {
542
 
            if ((row > 0)||(column > 0)) throw new MatrixIndexException
543
 
            ("matrix must be initialized to perfom this method");
544
 
            data = new BigDecimal[nRows][nCols];
545
 
            System.arraycopy(subMatrix, 0, data, 0, subMatrix.length);          
546
 
        }   
547
 
        if (((nRows + row) > this.getRowDimension()) ||
548
 
            (nCols + column > this.getColumnDimension()))
549
 
            throw new MatrixIndexException(
550
 
            "invalid row or column index selection");                   
551
 
        for (int i = 0; i < nRows; i++) {
552
 
            System.arraycopy(subMatrix[i], 0, data[row + i], column, nCols);
553
 
        } 
554
 
        lu = null;
555
 
    }
556
 
    
557
 
    /**
558
 
     * Returns the entries in row number <code>row</code>
559
 
     * as a row matrix.  Row indices start at 0.
560
 
     *
561
 
     * @param row the row to be fetched
562
 
     * @return row matrix
563
 
     * @throws MatrixIndexException if the specified row index is invalid
564
 
     */
565
 
    public BigMatrix getRowMatrix(int row) throws MatrixIndexException {
566
 
        if ( !isValidCoordinate( row, 0)) {
567
 
            throw new MatrixIndexException("illegal row argument");
568
 
        }
569
 
        int ncols = this.getColumnDimension();
570
 
        BigDecimal[][] out = new BigDecimal[1][ncols]; 
571
 
        System.arraycopy(data[row], 0, out[0], 0, ncols);
572
 
        return new BigMatrixImpl(out);
573
 
    } 
574
 
    
575
 
    /**
576
 
     * Returns the entries in column number <code>column</code>
577
 
     * as a column matrix.  Column indices start at 0.
578
 
     *
579
 
     * @param column the column to be fetched
580
 
     * @return column matrix
581
 
     * @throws MatrixIndexException if the specified column index is invalid
582
 
     */
583
 
    public BigMatrix getColumnMatrix(int column) throws MatrixIndexException {
584
 
        if ( !isValidCoordinate( 0, column)) {
585
 
            throw new MatrixIndexException("illegal column argument");
586
 
        }
587
 
        int nRows = this.getRowDimension();
588
 
        BigDecimal[][] out = new BigDecimal[nRows][1]; 
589
 
        for (int row = 0; row < nRows; row++) {
590
 
            out[row][0] = data[row][column];
591
 
        }
592
 
        return new BigMatrixImpl(out);
593
 
    }
594
 
    
595
 
    /**
596
 
     * Returns the entries in row number <code>row</code> as an array.
597
 
     * <p>
598
 
     * Row indices start at 0.  A <code>MatrixIndexException</code> is thrown
599
 
     * unless <code>0 <= row < rowDimension.</code></p>
600
 
     *
601
 
     * @param row the row to be fetched
602
 
     * @return array of entries in the row
603
 
     * @throws MatrixIndexException if the specified row index is not valid
604
 
     */
605
 
    public BigDecimal[] getRow(int row) throws MatrixIndexException {
606
 
        if ( !isValidCoordinate( row, 0 ) ) {
607
 
            throw new MatrixIndexException("illegal row argument");
608
 
        }
609
 
        int ncols = this.getColumnDimension();
610
 
        BigDecimal[] out = new BigDecimal[ncols];
611
 
        System.arraycopy(data[row], 0, out, 0, ncols);
612
 
        return out;
613
 
    }
614
 
    
615
 
     /**
616
 
     * Returns the entries in row number <code>row</code> as an array
617
 
     * of double values.
618
 
     * <p>
619
 
     * Row indices start at 0.  A <code>MatrixIndexException</code> is thrown
620
 
     * unless <code>0 <= row < rowDimension.</code></p>
621
 
     *
622
 
     * @param row the row to be fetched
623
 
     * @return array of entries in the row
624
 
     * @throws MatrixIndexException if the specified row index is not valid
625
 
     */
626
 
    public double[] getRowAsDoubleArray(int row) throws MatrixIndexException {
627
 
        if ( !isValidCoordinate( row, 0 ) ) {
628
 
            throw new MatrixIndexException("illegal row argument");
629
 
        }
630
 
        int ncols = this.getColumnDimension();
631
 
        double[] out = new double[ncols];
632
 
        for (int i=0;i<ncols;i++) {
633
 
            out[i] = data[row][i].doubleValue();
634
 
        }
635
 
        return out;
636
 
    }
637
 
    
638
 
     /**
639
 
     * Returns the entries in column number <code>col</code> as an array.
640
 
     * <p>
641
 
     * Column indices start at 0.  A <code>MatrixIndexException</code> is thrown
642
 
     * unless <code>0 <= column < columnDimension.</code></p>
643
 
     *
644
 
     * @param col the column to be fetched
645
 
     * @return array of entries in the column
646
 
     * @throws MatrixIndexException if the specified column index is not valid
647
 
     */
648
 
    public BigDecimal[] getColumn(int col) throws MatrixIndexException {
649
 
        if ( !isValidCoordinate(0, col) ) {
650
 
            throw new MatrixIndexException("illegal column argument");
651
 
        }
652
 
        int nRows = this.getRowDimension();
653
 
        BigDecimal[] out = new BigDecimal[nRows];
654
 
        for (int i = 0; i < nRows; i++) {
655
 
            out[i] = data[i][col];
656
 
        }
657
 
        return out;
658
 
    }
659
 
    
660
 
    /**
661
 
     * Returns the entries in column number <code>col</code> as an array
662
 
     * of double values.
663
 
     * <p>
664
 
     * Column indices start at 0.  A <code>MatrixIndexException</code> is thrown
665
 
     * unless <code>0 <= column < columnDimension.</code></p>
666
 
     *
667
 
     * @param col the column to be fetched
668
 
     * @return array of entries in the column
669
 
     * @throws MatrixIndexException if the specified column index is not valid
670
 
     */
671
 
    public double[] getColumnAsDoubleArray(int col) throws MatrixIndexException {
672
 
        if ( !isValidCoordinate( 0, col ) ) {
673
 
            throw new MatrixIndexException("illegal column argument");
674
 
        }
675
 
        int nrows = this.getRowDimension();
676
 
        double[] out = new double[nrows];
677
 
        for (int i=0;i<nrows;i++) {
678
 
            out[i] = data[i][col].doubleValue();
679
 
        }
680
 
        return out;
681
 
    }
682
 
    
683
 
     /**
684
 
     * Returns the entry in the specified row and column.
685
 
     * <p>
686
 
     * Row and column indices start at 0 and must satisfy 
687
 
     * <ul>
688
 
     * <li><code>0 <= row < rowDimension</code></li>
689
 
     * <li><code> 0 <= column < columnDimension</code></li>
690
 
     * </ul>
691
 
     * otherwise a <code>MatrixIndexException</code> is thrown.</p>
692
 
     *
693
 
     * @param row  row location of entry to be fetched  
694
 
     * @param column  column location of entry to be fetched
695
 
     * @return matrix entry in row,column
696
 
     * @throws MatrixIndexException if the row or column index is not valid
697
 
     */
698
 
    public BigDecimal getEntry(int row, int column)
699
 
    throws MatrixIndexException {
700
 
        if (!isValidCoordinate(row,column)) {
701
 
            throw new MatrixIndexException("matrix entry does not exist");
702
 
        }
703
 
        return data[row][column];
704
 
    }
705
 
    
706
 
    /**
707
 
     * Returns the entry in the specified row and column as a double.
708
 
     * <p>
709
 
     * Row and column indices start at 0 and must satisfy 
710
 
     * <ul>
711
 
     * <li><code>0 <= row < rowDimension</code></li>
712
 
     * <li><code> 0 <= column < columnDimension</code></li>
713
 
     * </ul>
714
 
     * otherwise a <code>MatrixIndexException</code> is thrown.</p>
715
 
     *
716
 
     * @param row  row location of entry to be fetched
717
 
     * @param column  column location of entry to be fetched
718
 
     * @return matrix entry in row,column
719
 
     * @throws MatrixIndexException if the row
720
 
     * or column index is not valid
721
 
     */
722
 
    public double getEntryAsDouble(int row, int column) throws MatrixIndexException {
723
 
        return getEntry(row,column).doubleValue();
724
 
    }
725
 
    
726
 
    /**
727
 
     * Returns the transpose matrix.
728
 
     *
729
 
     * @return transpose matrix
730
 
     */
731
 
    public BigMatrix transpose() {
732
 
        int nRows = this.getRowDimension();
733
 
        int nCols = this.getColumnDimension();
734
 
        BigMatrixImpl out = new BigMatrixImpl(nCols, nRows);
735
 
        BigDecimal[][] outData = out.getDataRef();
736
 
        for (int row = 0; row < nRows; row++) {
737
 
            for (int col = 0; col < nCols; col++) {
738
 
                outData[col][row] = data[row][col];
739
 
            }
740
 
        }
741
 
        return out;
742
 
    }
743
 
    
744
 
    /**
745
 
     * Returns the inverse matrix if this matrix is invertible.
746
 
     * 
747
 
     * @return inverse matrix
748
 
     * @throws InvalidMatrixException if this is not invertible
749
 
     */
750
 
    public BigMatrix inverse() throws InvalidMatrixException {
751
 
        return solve(MatrixUtils.createBigIdentityMatrix
752
 
                (this.getRowDimension()));
753
 
    }
754
 
    
755
 
    /**
756
 
     * Returns the determinant of this matrix.
757
 
     *
758
 
     * @return determinant
759
 
     * @throws InvalidMatrixException if matrix is not square
760
 
     */
761
 
    public BigDecimal getDeterminant() throws InvalidMatrixException {
762
 
        if (!isSquare()) {
763
 
            throw new InvalidMatrixException("matrix is not square");
764
 
        }
765
 
        if (isSingular()) {   // note: this has side effect of attempting LU decomp if lu == null
766
 
            return ZERO;
767
 
        } else {
768
 
            BigDecimal det = (parity == 1) ? ONE : ONE.negate();
769
 
            for (int i = 0; i < this.getRowDimension(); i++) {
770
 
                det = det.multiply(lu[i][i]);
771
 
            }
772
 
            return det;
773
 
        }
774
 
    }
775
 
    
776
 
     /**
777
 
     * Is this a square matrix?
778
 
     * @return true if the matrix is square (rowDimension = columnDimension)
779
 
     */
780
 
    public boolean isSquare() {
781
 
        return (this.getColumnDimension() == this.getRowDimension());
782
 
    }
783
 
    
784
 
    /**
785
 
     * Is this a singular matrix?
786
 
     * @return true if the matrix is singular
787
 
     */
788
 
    public boolean isSingular() {
789
 
        if (lu == null) {
790
 
            try {
791
 
                luDecompose();
792
 
                return false;
793
 
            } catch (InvalidMatrixException ex) {
794
 
                return true;
795
 
            }
796
 
        } else { // LU decomp must have been successfully performed
797
 
            return false; // so the matrix is not singular
798
 
        }
799
 
    }
800
 
    
801
 
    /**
802
 
     * Returns the number of rows in the matrix.
803
 
     *
804
 
     * @return rowDimension
805
 
     */
806
 
    public int getRowDimension() {
807
 
        return data.length;
808
 
    }
809
 
    
810
 
    /**
811
 
     * Returns the number of columns in the matrix.
812
 
     *
813
 
     * @return columnDimension
814
 
     */
815
 
    public int getColumnDimension() {
816
 
        return data[0].length;
817
 
    }
818
 
    
819
 
     /**
820
 
     * Returns the <a href="http://mathworld.wolfram.com/MatrixTrace.html">
821
 
     * trace</a> of the matrix (the sum of the elements on the main diagonal).
822
 
     *
823
 
     * @return trace
824
 
     * 
825
 
     * @throws IllegalArgumentException if this matrix is not square.
826
 
     */
827
 
    public BigDecimal getTrace() throws IllegalArgumentException {
828
 
        if (!isSquare()) {
829
 
            throw new IllegalArgumentException("matrix is not square");
830
 
        }
831
 
        BigDecimal trace = data[0][0];
832
 
        for (int i = 1; i < this.getRowDimension(); i++) {
833
 
            trace = trace.add(data[i][i]);
834
 
        }
835
 
        return trace;
836
 
    }
837
 
    
838
 
    /**
839
 
     * Returns the result of multiplying this by the vector <code>v</code>.
840
 
     *
841
 
     * @param v the vector to operate on
842
 
     * @return this*v
843
 
     * @throws IllegalArgumentException if columnDimension != v.size()
844
 
     */
845
 
    public BigDecimal[] operate(BigDecimal[] v) throws IllegalArgumentException {
846
 
        if (v.length != this.getColumnDimension()) {
847
 
            throw new IllegalArgumentException("vector has wrong length");
848
 
        }
849
 
        int nRows = this.getRowDimension();
850
 
        int nCols = this.getColumnDimension();
851
 
        BigDecimal[] out = new BigDecimal[v.length];
852
 
        for (int row = 0; row < nRows; row++) {
853
 
            BigDecimal sum = ZERO;
854
 
            for (int i = 0; i < nCols; i++) {
855
 
                sum = sum.add(data[row][i].multiply(v[i]));
856
 
            }
857
 
            out[row] = sum;
858
 
        }
859
 
        return out;
860
 
    }
861
 
    
862
 
    /**
863
 
     * Returns the result of multiplying this by the vector <code>v</code>.
864
 
     *
865
 
     * @param v the vector to operate on
866
 
     * @return this*v
867
 
     * @throws IllegalArgumentException if columnDimension != v.size()
868
 
     */
869
 
    public BigDecimal[] operate(double[] v) throws IllegalArgumentException {
870
 
        BigDecimal bd[] = new BigDecimal[v.length];
871
 
        for (int i=0;i<bd.length;i++) {
872
 
            bd[i] = new BigDecimal(v[i]);
873
 
        }
874
 
        return operate(bd);
875
 
    }
876
 
    
877
 
    /**
878
 
     * Returns the (row) vector result of premultiplying this by the vector <code>v</code>.
879
 
     *
880
 
     * @param v the row vector to premultiply by
881
 
     * @return v*this
882
 
     * @throws IllegalArgumentException if rowDimension != v.size()
883
 
     */
884
 
    public BigDecimal[] preMultiply(BigDecimal[] v) throws IllegalArgumentException {
885
 
        int nRows = this.getRowDimension();
886
 
        if (v.length != nRows) {
887
 
            throw new IllegalArgumentException("vector has wrong length");
888
 
        }
889
 
        int nCols = this.getColumnDimension();
890
 
        BigDecimal[] out = new BigDecimal[nCols];
891
 
        for (int col = 0; col < nCols; col++) {
892
 
            BigDecimal sum = ZERO;
893
 
            for (int i = 0; i < nRows; i++) {
894
 
                sum = sum.add(data[i][col].multiply(v[i]));
895
 
            }
896
 
            out[col] = sum;
897
 
        }
898
 
        return out;
899
 
    }
900
 
    
901
 
    /**
902
 
     * Returns a matrix of (column) solution vectors for linear systems with
903
 
     * coefficient matrix = this and constant vectors = columns of
904
 
     * <code>b</code>. 
905
 
     *
906
 
     * @param b  array of constants forming RHS of linear systems to
907
 
     * to solve
908
 
     * @return solution array
909
 
     * @throws IllegalArgumentException if this.rowDimension != row dimension
910
 
     * @throws InvalidMatrixException if this matrix is not square or is singular
911
 
     */
912
 
    public BigDecimal[] solve(BigDecimal[] b) throws IllegalArgumentException, InvalidMatrixException {
913
 
        int nRows = this.getRowDimension();
914
 
        if (b.length != nRows) {
915
 
            throw new IllegalArgumentException("constant vector has wrong length");
916
 
        }
917
 
        BigMatrix bMatrix = new BigMatrixImpl(b);
918
 
        BigDecimal[][] solution = ((BigMatrixImpl) (solve(bMatrix))).getDataRef();
919
 
        BigDecimal[] out = new BigDecimal[nRows];
920
 
        for (int row = 0; row < nRows; row++) {
921
 
            out[row] = solution[row][0];
922
 
        }
923
 
        return out;
924
 
    }
925
 
    
926
 
    /**
927
 
     * Returns a matrix of (column) solution vectors for linear systems with
928
 
     * coefficient matrix = this and constant vectors = columns of
929
 
     * <code>b</code>. 
930
 
     *
931
 
     * @param b  array of constants forming RHS of linear systems to
932
 
     * to solve
933
 
     * @return solution array
934
 
     * @throws IllegalArgumentException if this.rowDimension != row dimension
935
 
     * @throws InvalidMatrixException if this matrix is not square or is singular
936
 
     */
937
 
    public BigDecimal[] solve(double[] b) throws IllegalArgumentException, InvalidMatrixException {
938
 
        BigDecimal bd[] = new BigDecimal[b.length];
939
 
        for (int i=0;i<bd.length;i++) {
940
 
            bd[i] = new BigDecimal(b[i]);
941
 
        }
942
 
        return solve(bd);
943
 
    }
944
 
    
945
 
    /**
946
 
     * Returns a matrix of (column) solution vectors for linear systems with
947
 
     * coefficient matrix = this and constant vectors = columns of
948
 
     * <code>b</code>. 
949
 
     *
950
 
     * @param b  matrix of constant vectors forming RHS of linear systems to
951
 
     * to solve
952
 
     * @return matrix of solution vectors
953
 
     * @throws IllegalArgumentException if this.rowDimension != row dimension
954
 
     * @throws InvalidMatrixException if this matrix is not square or is singular
955
 
     */
956
 
    public BigMatrix solve(BigMatrix b) throws IllegalArgumentException, InvalidMatrixException  {
957
 
        if (b.getRowDimension() != this.getRowDimension()) {
958
 
            throw new IllegalArgumentException("Incorrect row dimension");
959
 
        }
960
 
        if (!this.isSquare()) {
961
 
            throw new InvalidMatrixException("coefficient matrix is not square");
962
 
        }
963
 
        if (this.isSingular()) { // side effect: compute LU decomp
964
 
            throw new InvalidMatrixException("Matrix is singular.");
965
 
        }
966
 
        
967
 
        int nCol = this.getColumnDimension();
968
 
        int nColB = b.getColumnDimension();
969
 
        int nRowB = b.getRowDimension();
970
 
        
971
 
        // Apply permutations to b
972
 
        BigDecimal[][] bp = new BigDecimal[nRowB][nColB];
973
 
        for (int row = 0; row < nRowB; row++) {
974
 
            for (int col = 0; col < nColB; col++) {
975
 
                bp[row][col] = b.getEntry(permutation[row], col);
976
 
            }
977
 
        }
978
 
        
979
 
        // Solve LY = b
980
 
        for (int col = 0; col < nCol; col++) {
981
 
            for (int i = col + 1; i < nCol; i++) {
982
 
                for (int j = 0; j < nColB; j++) {
983
 
                    bp[i][j] = bp[i][j].subtract(bp[col][j].multiply(lu[i][col]));
984
 
                }
985
 
            }
986
 
        }
987
 
        
988
 
        // Solve UX = Y
989
 
        for (int col = nCol - 1; col >= 0; col--) {
990
 
            for (int j = 0; j < nColB; j++) {
991
 
                bp[col][j] = bp[col][j].divide(lu[col][col], scale, roundingMode);
992
 
            }
993
 
            for (int i = 0; i < col; i++) {
994
 
                for (int j = 0; j < nColB; j++) {
995
 
                    bp[i][j] = bp[i][j].subtract(bp[col][j].multiply(lu[i][col]));
996
 
                }
997
 
            }
998
 
        }
999
 
        
1000
 
        BigMatrixImpl outMat = new BigMatrixImpl(bp);
1001
 
        return outMat;
1002
 
    }
1003
 
    
1004
 
    /**
1005
 
     * Computes a new 
1006
 
     * <a href="http://www.math.gatech.edu/~bourbaki/math2601/Web-notes/2num.pdf">
1007
 
     * LU decompostion</a> for this matrix, storing the result for use by other methods. 
1008
 
     * <p>
1009
 
     * <strong>Implementation Note</strong>:<br>
1010
 
     * Uses <a href="http://www.damtp.cam.ac.uk/user/fdl/people/sd/lectures/nummeth98/linear.htm">
1011
 
     * Crout's algortithm</a>, with partial pivoting.</p>
1012
 
     * <p>
1013
 
     * <strong>Usage Note</strong>:<br>
1014
 
     * This method should rarely be invoked directly. Its only use is
1015
 
     * to force recomputation of the LU decomposition when changes have been
1016
 
     * made to the underlying data using direct array references. Changes
1017
 
     * made using setXxx methods will trigger recomputation when needed
1018
 
     * automatically.</p>
1019
 
     *
1020
 
     * @throws InvalidMatrixException if the matrix is non-square or singular.
1021
 
     */
1022
 
    public void luDecompose() throws InvalidMatrixException {
1023
 
        
1024
 
        int nRows = this.getRowDimension();
1025
 
        int nCols = this.getColumnDimension();
1026
 
        if (nRows != nCols) {
1027
 
            throw new InvalidMatrixException("LU decomposition requires that the matrix be square.");
1028
 
        }
1029
 
        lu = this.getData();
1030
 
        
1031
 
        // Initialize permutation array and parity
1032
 
        permutation = new int[nRows];
1033
 
        for (int row = 0; row < nRows; row++) {
1034
 
            permutation[row] = row;
1035
 
        }
1036
 
        parity = 1;
1037
 
        
1038
 
        // Loop over columns
1039
 
        for (int col = 0; col < nCols; col++) {
1040
 
            
1041
 
            BigDecimal sum = ZERO;
1042
 
            
1043
 
            // upper
1044
 
            for (int row = 0; row < col; row++) {
1045
 
                sum = lu[row][col];
1046
 
                for (int i = 0; i < row; i++) {
1047
 
                    sum = sum.subtract(lu[row][i].multiply(lu[i][col]));
1048
 
                }
1049
 
                lu[row][col] = sum;
1050
 
            }
1051
 
            
1052
 
            // lower
1053
 
            int max = col; // permutation row
1054
 
            BigDecimal largest = ZERO;
1055
 
            for (int row = col; row < nRows; row++) {
1056
 
                sum = lu[row][col];
1057
 
                for (int i = 0; i < col; i++) {
1058
 
                    sum = sum.subtract(lu[row][i].multiply(lu[i][col]));
1059
 
                }
1060
 
                lu[row][col] = sum;
1061
 
                
1062
 
                // maintain best permutation choice
1063
 
                if (sum.abs().compareTo(largest) == 1) {
1064
 
                    largest = sum.abs();
1065
 
                    max = row;
1066
 
                }
1067
 
            }
1068
 
            
1069
 
            // Singularity check
1070
 
            if (lu[max][col].abs().compareTo(TOO_SMALL) <= 0) {
1071
 
                lu = null;
1072
 
                throw new InvalidMatrixException("matrix is singular");
1073
 
            }
1074
 
            
1075
 
            // Pivot if necessary
1076
 
            if (max != col) {
1077
 
                BigDecimal tmp = ZERO;
1078
 
                for (int i = 0; i < nCols; i++) {
1079
 
                    tmp = lu[max][i];
1080
 
                    lu[max][i] = lu[col][i];
1081
 
                    lu[col][i] = tmp;
1082
 
                }
1083
 
                int temp = permutation[max];
1084
 
                permutation[max] = permutation[col];
1085
 
                permutation[col] = temp;
1086
 
                parity = -parity;
1087
 
            }
1088
 
            
1089
 
            //Divide the lower elements by the "winning" diagonal elt.
1090
 
            for (int row = col + 1; row < nRows; row++) {
1091
 
                lu[row][col] = lu[row][col].divide(lu[col][col], scale, roundingMode);
1092
 
            }
1093
 
            
1094
 
        }
1095
 
        
1096
 
    }
1097
 
    
1098
 
    /**
1099
 
     * Get a string representation for this matrix.
1100
 
     * @return a string representation for this matrix
1101
 
     */
1102
 
    public String toString() {
1103
 
        StringBuffer res = new StringBuffer();
1104
 
        res.append("BigMatrixImpl{");
1105
 
        if (data != null) {
1106
 
            for (int i = 0; i < data.length; i++) {
1107
 
                if (i > 0)
1108
 
                    res.append(",");
1109
 
                res.append("{");
1110
 
                for (int j = 0; j < data[0].length; j++) {
1111
 
                    if (j > 0)
1112
 
                        res.append(",");
1113
 
                    res.append(data[i][j]);
1114
 
                } 
1115
 
                res.append("}");
1116
 
            } 
1117
 
        }
1118
 
        res.append("}");
1119
 
        return res.toString();
1120
 
    } 
1121
 
    
1122
 
    /**
1123
 
     * Returns true iff <code>object</code> is a 
1124
 
     * <code>BigMatrixImpl</code> instance with the same dimensions as this
1125
 
     * and all corresponding matrix entries are equal.  BigDecimal.equals
1126
 
     * is used to compare corresponding entries.
1127
 
     * 
1128
 
     * @param object the object to test equality against.
1129
 
     * @return true if object equals this
1130
 
     */
1131
 
    public boolean equals(Object object) {
1132
 
        if (object == this ) {
1133
 
            return true;
1134
 
        }
1135
 
        if (object instanceof BigMatrixImpl == false) {
1136
 
            return false;
1137
 
        }
1138
 
        BigMatrix m = (BigMatrix) object;
1139
 
        int nRows = getRowDimension();
1140
 
        int nCols = getColumnDimension();
1141
 
        if (m.getColumnDimension() != nCols || m.getRowDimension() != nRows) {
1142
 
            return false;
1143
 
        }
1144
 
        for (int row = 0; row < nRows; row++) {
1145
 
            for (int col = 0; col < nCols; col++) {
1146
 
                if (!data[row][col].equals(m.getEntry(row, col))) {
1147
 
                    return false;
1148
 
                }
1149
 
            }
1150
 
        }
1151
 
        return true;
1152
 
    }
1153
 
    
1154
 
    /**
1155
 
     * Computes a hashcode for the matrix.
1156
 
     * 
1157
 
     * @return hashcode for matrix
1158
 
     */
1159
 
    public int hashCode() {
1160
 
        int ret = 7;
1161
 
        int nRows = getRowDimension();
1162
 
        int nCols = getColumnDimension();
1163
 
        ret = ret * 31 + nRows;
1164
 
        ret = ret * 31 + nCols;
1165
 
        for (int row = 0; row < nRows; row++) {
1166
 
            for (int col = 0; col < nCols; col++) {
1167
 
                ret = ret * 31 + (11 * (row+1) + 17 * (col+1)) * 
1168
 
                data[row][col].hashCode();
1169
 
            }
1170
 
        }   
1171
 
        return ret;
1172
 
    }
1173
 
    
1174
 
    //------------------------ Protected methods
1175
 
    
1176
 
    /**
1177
 
     * Returns <code>dimension x dimension</code> identity matrix.
1178
 
     *
1179
 
     * @param dimension dimension of identity matrix to generate
1180
 
     * @return identity matrix
1181
 
     * @throws IllegalArgumentException if dimension is not positive
1182
 
     * @deprecated  use {@link MatrixUtils#createBigIdentityMatrix}
1183
 
     */
1184
 
    protected BigMatrix getIdentity(int dimension) {
1185
 
        return MatrixUtils.createBigIdentityMatrix(dimension);
1186
 
    }
1187
 
    
1188
 
    /**
1189
 
     *  Returns the LU decomposition as a BigMatrix.
1190
 
     *  Returns a fresh copy of the cached LU matrix if this has been computed; 
1191
 
     *  otherwise the composition is computed and cached for use by other methods.   
1192
 
     *  Since a copy is returned in either case, changes to the returned matrix do not 
1193
 
     *  affect the LU decomposition property. 
1194
 
     * <p>
1195
 
     * The matrix returned is a compact representation of the LU decomposition. 
1196
 
     * Elements below the main diagonal correspond to entries of the "L" matrix;   
1197
 
     * elements on and above the main diagonal correspond to entries of the "U"
1198
 
     * matrix.</p>
1199
 
     * <p>
1200
 
     * Example: <pre>
1201
 
     * 
1202
 
     *     Returned matrix                L                  U
1203
 
     *         2  3  1                   1  0  0            2  3  1          
1204
 
     *         5  4  6                   5  1  0            0  4  6
1205
 
     *         1  7  8                   1  7  1            0  0  8          
1206
 
     * </pre>
1207
 
     * 
1208
 
     * The L and U matrices satisfy the matrix equation LU = permuteRows(this), <br>
1209
 
     *  where permuteRows reorders the rows of the matrix to follow the order determined
1210
 
     *  by the <a href=#getPermutation()>permutation</a> property.</p>
1211
 
     * 
1212
 
     * @return LU decomposition matrix
1213
 
     * @throws InvalidMatrixException if the matrix is non-square or singular.
1214
 
     */
1215
 
    protected BigMatrix getLUMatrix() throws InvalidMatrixException {
1216
 
        if (lu == null) {
1217
 
            luDecompose();
1218
 
        }
1219
 
        return new BigMatrixImpl(lu);
1220
 
    }
1221
 
    
1222
 
    /**
1223
 
     * Returns the permutation associated with the lu decomposition.
1224
 
     * The entries of the array represent a permutation of the numbers 0, ... , nRows - 1.
1225
 
     * <p>
1226
 
     * Example:
1227
 
     * permutation = [1, 2, 0] means current 2nd row is first, current third row is second
1228
 
     * and current first row is last.</p>
1229
 
     * <p>
1230
 
     * Returns a fresh copy of the array.</p>
1231
 
     * 
1232
 
     * @return the permutation
1233
 
     */
1234
 
    protected int[] getPermutation() {
1235
 
        int[] out = new int[permutation.length];
1236
 
        System.arraycopy(permutation, 0, out, 0, permutation.length);
1237
 
        return out;
1238
 
    }
1239
 
    
1240
 
    //------------------------ Private methods
1241
 
    
1242
 
    /**
1243
 
     * Returns a fresh copy of the underlying data array.
1244
 
     *
1245
 
     * @return a copy of the underlying data array.
1246
 
     */
1247
 
    private BigDecimal[][] copyOut() {
1248
 
        int nRows = this.getRowDimension();
1249
 
        BigDecimal[][] out = new BigDecimal[nRows][this.getColumnDimension()];
1250
 
        // can't copy 2-d array in one shot, otherwise get row references
1251
 
        for (int i = 0; i < nRows; i++) {
1252
 
            System.arraycopy(data[i], 0, out[i], 0, data[i].length);
1253
 
        }
1254
 
        return out;
1255
 
    }
1256
 
    
1257
 
    /**
1258
 
     * Replaces data with a fresh copy of the input array.
1259
 
     * <p>
1260
 
     * Verifies that the input array is rectangular and non-empty.</p>
1261
 
     *
1262
 
     * @param in data to copy in
1263
 
     * @throws IllegalArgumentException if input array is emtpy or not
1264
 
     *    rectangular
1265
 
     * @throws NullPointerException if input array is null
1266
 
     */
1267
 
    private void copyIn(BigDecimal[][] in) {
1268
 
        setSubMatrix(in,0,0);
1269
 
    }
1270
 
    
1271
 
    /**
1272
 
     * Replaces data with a fresh copy of the input array.
1273
 
     *
1274
 
     * @param in data to copy in
1275
 
     */
1276
 
    private void copyIn(double[][] in) {
1277
 
        int nRows = in.length;
1278
 
        int nCols = in[0].length;
1279
 
        data = new BigDecimal[nRows][nCols];
1280
 
        for (int i = 0; i < nRows; i++) {
1281
 
            for (int j=0; j < nCols; j++) {
1282
 
                data[i][j] = new BigDecimal(in[i][j]);
1283
 
            }
1284
 
        }
1285
 
        lu = null;
1286
 
    }
1287
 
    
1288
 
    /**
1289
 
     * Replaces data with BigDecimals represented by the strings in the input
1290
 
     * array.
1291
 
     *
1292
 
     * @param in data to copy in
1293
 
     */
1294
 
    private void copyIn(String[][] in) {
1295
 
        int nRows = in.length;
1296
 
        int nCols = in[0].length;
1297
 
        data = new BigDecimal[nRows][nCols];
1298
 
        for (int i = 0; i < nRows; i++) {
1299
 
            for (int j=0; j < nCols; j++) {
1300
 
                data[i][j] = new BigDecimal(in[i][j]);
1301
 
            }
1302
 
        }
1303
 
        lu = null;
1304
 
    }
1305
 
    
1306
 
    /**
1307
 
     * Tests a given coordinate as being valid or invalid
1308
 
     *
1309
 
     * @param row the row index.
1310
 
     * @param col the column index.
1311
 
     * @return true if the coordinate is with the current dimensions
1312
 
     */
1313
 
    private boolean isValidCoordinate(int row, int col) {
1314
 
        int nRows = this.getRowDimension();
1315
 
        int nCols = this.getColumnDimension();
1316
 
        
1317
 
        return !(row < 0 || row >= nRows || col < 0 || col >= nCols);
1318
 
    }
1319
 
    
1320
 
}