001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018 package org.apache.commons.math.linear;
019
020 import java.io.Serializable;
021
022 import org.apache.commons.math.MathRuntimeException;
023 import org.apache.commons.math.linear.MatrixVisitorException;
024 import org.apache.commons.math.exception.util.LocalizedFormats;
025
026 /**
027 * Implementation of RealMatrix using a double[][] array to store entries and
028 * <a href="http://www.math.gatech.edu/~bourbaki/math2601/Web-notes/2num.pdf">
029 * LU decomposition</a> to support linear system
030 * solution and inverse.
031 * <p>
032 * The LU decomposition is performed as needed, to support the following operations: <ul>
033 * <li>solve</li>
034 * <li>isSingular</li>
035 * <li>getDeterminant</li>
036 * <li>inverse</li> </ul></p>
037 * <p>
038 * <strong>Usage notes</strong>:<br>
039 * <ul><li>
040 * The LU decomposition is cached and reused on subsequent calls.
041 * If data are modified via references to the underlying array obtained using
042 * <code>getDataRef()</code>, then the stored LU decomposition will not be
043 * discarded. In this case, you need to explicitly invoke
044 * <code>LUDecompose()</code> to recompute the decomposition
045 * before using any of the methods above.</li>
046 * <li>
047 * As specified in the {@link RealMatrix} interface, matrix element indexing
048 * is 0-based -- e.g., <code>getEntry(0, 0)</code>
049 * returns the element in the first row, first column of the matrix.</li></ul>
050 * </p>
051 *
052 * @version $Revision: 1073158 $ $Date: 2011-02-21 22:46:52 +0100 (lun. 21 f??vr. 2011) $
053 * @deprecated as of 2.0 replaced by {@link Array2DRowRealMatrix}
054 */
055 @Deprecated
056 public class RealMatrixImpl extends AbstractRealMatrix implements Serializable {
057
058 /** Serializable version identifier */
059 private static final long serialVersionUID = -1067294169172445528L;
060
061 /** Entries of the matrix */
062 protected double data[][];
063
064 /**
065 * Creates a matrix with no data
066 */
067 public RealMatrixImpl() {
068 }
069
070 /**
071 * Create a new RealMatrix with the supplied row and column dimensions.
072 *
073 * @param rowDimension the number of rows in the new matrix
074 * @param columnDimension the number of columns in the new matrix
075 * @throws IllegalArgumentException if row or column dimension is not
076 * positive
077 */
078 public RealMatrixImpl(final int rowDimension, final int columnDimension)
079 throws IllegalArgumentException {
080 super(rowDimension, columnDimension);
081 data = new double[rowDimension][columnDimension];
082 }
083
084 /**
085 * Create a new RealMatrix using the input array as the underlying
086 * data array.
087 * <p>The input array is copied, not referenced. This constructor has
088 * the same effect as calling {@link #RealMatrixImpl(double[][], boolean)}
089 * with the second argument set to <code>true</code>.</p>
090 *
091 * @param d data for new matrix
092 * @throws IllegalArgumentException if <code>d</code> is not rectangular
093 * (not all rows have the same length) or empty
094 * @throws NullPointerException if <code>d</code> is null
095 * @see #RealMatrixImpl(double[][], boolean)
096 */
097 public RealMatrixImpl(final double[][] d)
098 throws IllegalArgumentException, NullPointerException {
099 copyIn(d);
100 }
101
102 /**
103 * Create a new RealMatrix using the input array as the underlying
104 * data array.
105 * <p>If an array is built specially in order to be embedded in a
106 * RealMatrix and not used directly, the <code>copyArray</code> may be
107 * set to <code>false</code. This will prevent the copying and improve
108 * performance as no new array will be built and no data will be copied.</p>
109 * @param d data for new matrix
110 * @param copyArray if true, the input array will be copied, otherwise
111 * it will be referenced
112 * @throws IllegalArgumentException if <code>d</code> is not rectangular
113 * (not all rows have the same length) or empty
114 * @throws NullPointerException if <code>d</code> is null
115 * @see #RealMatrixImpl(double[][])
116 */
117 public RealMatrixImpl(final double[][] d, final boolean copyArray)
118 throws IllegalArgumentException, NullPointerException {
119 if (copyArray) {
120 copyIn(d);
121 } else {
122 if (d == null) {
123 throw new NullPointerException();
124 }
125 final int nRows = d.length;
126 if (nRows == 0) {
127 throw MathRuntimeException.createIllegalArgumentException(LocalizedFormats.AT_LEAST_ONE_ROW);
128 }
129 final int nCols = d[0].length;
130 if (nCols == 0) {
131 throw MathRuntimeException.createIllegalArgumentException(LocalizedFormats.AT_LEAST_ONE_COLUMN);
132 }
133 for (int r = 1; r < nRows; r++) {
134 if (d[r].length != nCols) {
135 throw MathRuntimeException.createIllegalArgumentException(
136 LocalizedFormats.DIFFERENT_ROWS_LENGTHS,
137 nCols, d[r].length);
138 }
139 }
140 data = d;
141 }
142 }
143
144 /**
145 * Create a new (column) RealMatrix using <code>v</code> as the
146 * data for the unique column of the <code>v.length x 1</code> matrix
147 * created.
148 * <p>The input array is copied, not referenced.</p>
149 *
150 * @param v column vector holding data for new matrix
151 */
152 public RealMatrixImpl(final double[] v) {
153 final int nRows = v.length;
154 data = new double[nRows][1];
155 for (int row = 0; row < nRows; row++) {
156 data[row][0] = v[row];
157 }
158 }
159
160 /** {@inheritDoc} */
161 @Override
162 public RealMatrix createMatrix(final int rowDimension, final int columnDimension)
163 throws IllegalArgumentException {
164 return new RealMatrixImpl(rowDimension, columnDimension);
165 }
166
167 /** {@inheritDoc} */
168 @Override
169 public RealMatrix copy() {
170 return new RealMatrixImpl(copyOut(), false);
171 }
172
173 /** {@inheritDoc} */
174 @Override
175 public RealMatrix add(final RealMatrix m)
176 throws IllegalArgumentException {
177 try {
178 return add((RealMatrixImpl) m);
179 } catch (ClassCastException cce) {
180 return super.add(m);
181 }
182 }
183
184 /**
185 * Compute the sum of this and <code>m</code>.
186 *
187 * @param m matrix to be added
188 * @return this + m
189 * @throws IllegalArgumentException if m is not the same size as this
190 */
191 public RealMatrixImpl add(final RealMatrixImpl m)
192 throws IllegalArgumentException {
193
194 // safety check
195 MatrixUtils.checkAdditionCompatible(this, m);
196
197 final int rowCount = getRowDimension();
198 final int columnCount = getColumnDimension();
199 final double[][] outData = new double[rowCount][columnCount];
200 for (int row = 0; row < rowCount; row++) {
201 final double[] dataRow = data[row];
202 final double[] mRow = m.data[row];
203 final double[] outDataRow = outData[row];
204 for (int col = 0; col < columnCount; col++) {
205 outDataRow[col] = dataRow[col] + mRow[col];
206 }
207 }
208
209 return new RealMatrixImpl(outData, false);
210
211 }
212
213 /** {@inheritDoc} */
214 @Override
215 public RealMatrix subtract(final RealMatrix m)
216 throws IllegalArgumentException {
217 try {
218 return subtract((RealMatrixImpl) m);
219 } catch (ClassCastException cce) {
220 return super.subtract(m);
221 }
222 }
223
224 /**
225 * Compute this minus <code>m</code>.
226 *
227 * @param m matrix to be subtracted
228 * @return this + m
229 * @throws IllegalArgumentException if m is not the same size as this
230 */
231 public RealMatrixImpl subtract(final RealMatrixImpl m)
232 throws IllegalArgumentException {
233
234 // safety check
235 MatrixUtils.checkSubtractionCompatible(this, m);
236
237 final int rowCount = getRowDimension();
238 final int columnCount = getColumnDimension();
239 final double[][] outData = new double[rowCount][columnCount];
240 for (int row = 0; row < rowCount; row++) {
241 final double[] dataRow = data[row];
242 final double[] mRow = m.data[row];
243 final double[] outDataRow = outData[row];
244 for (int col = 0; col < columnCount; col++) {
245 outDataRow[col] = dataRow[col] - mRow[col];
246 }
247 }
248
249 return new RealMatrixImpl(outData, false);
250
251 }
252
253 /** {@inheritDoc} */
254 @Override
255 public RealMatrix multiply(final RealMatrix m)
256 throws IllegalArgumentException {
257 try {
258 return multiply((RealMatrixImpl) m);
259 } catch (ClassCastException cce) {
260 return super.multiply(m);
261 }
262 }
263
264 /**
265 * Returns the result of postmultiplying this by <code>m</code>.
266 * @param m matrix to postmultiply by
267 * @return this*m
268 * @throws IllegalArgumentException
269 * if columnDimension(this) != rowDimension(m)
270 */
271 public RealMatrixImpl multiply(final RealMatrixImpl m)
272 throws IllegalArgumentException {
273
274 // safety check
275 MatrixUtils.checkMultiplicationCompatible(this, m);
276
277 final int nRows = this.getRowDimension();
278 final int nCols = m.getColumnDimension();
279 final int nSum = this.getColumnDimension();
280 final double[][] outData = new double[nRows][nCols];
281 for (int row = 0; row < nRows; row++) {
282 final double[] dataRow = data[row];
283 final double[] outDataRow = outData[row];
284 for (int col = 0; col < nCols; col++) {
285 double sum = 0;
286 for (int i = 0; i < nSum; i++) {
287 sum += dataRow[i] * m.data[i][col];
288 }
289 outDataRow[col] = sum;
290 }
291 }
292
293 return new RealMatrixImpl(outData, false);
294
295 }
296
297 /** {@inheritDoc} */
298 @Override
299 public double[][] getData() {
300 return copyOut();
301 }
302
303 /**
304 * Returns a reference to the underlying data array.
305 * <p>
306 * Does <strong>not</strong> make a fresh copy of the underlying data.</p>
307 *
308 * @return 2-dimensional array of entries
309 */
310 public double[][] getDataRef() {
311 return data;
312 }
313
314 /** {@inheritDoc} */
315 @Override
316 public void setSubMatrix(final double[][] subMatrix, final int row, final int column)
317 throws MatrixIndexException {
318 if (data == null) {
319 if (row > 0) {
320 throw MathRuntimeException.createIllegalStateException(
321 LocalizedFormats.FIRST_ROWS_NOT_INITIALIZED_YET,
322 row);
323 }
324 if (column > 0) {
325 throw MathRuntimeException.createIllegalStateException(
326 LocalizedFormats.FIRST_COLUMNS_NOT_INITIALIZED_YET,
327 column);
328 }
329 final int nRows = subMatrix.length;
330 if (nRows == 0) {
331 throw MathRuntimeException.createIllegalArgumentException(LocalizedFormats.AT_LEAST_ONE_ROW);
332 }
333
334 final int nCols = subMatrix[0].length;
335 if (nCols == 0) {
336 throw MathRuntimeException.createIllegalArgumentException(LocalizedFormats.AT_LEAST_ONE_COLUMN);
337 }
338 data = new double[subMatrix.length][nCols];
339 for (int i = 0; i < data.length; ++i) {
340 if (subMatrix[i].length != nCols) {
341 throw MathRuntimeException.createIllegalArgumentException(
342 LocalizedFormats.DIFFERENT_ROWS_LENGTHS,
343 nCols, subMatrix[i].length);
344 }
345 System.arraycopy(subMatrix[i], 0, data[i + row], column, nCols);
346 }
347 } else {
348 super.setSubMatrix(subMatrix, row, column);
349 }
350
351 }
352
353 /** {@inheritDoc} */
354 @Override
355 public double getEntry(final int row, final int column)
356 throws MatrixIndexException {
357 try {
358 return data[row][column];
359 } catch (ArrayIndexOutOfBoundsException e) {
360 throw new MatrixIndexException(
361 LocalizedFormats.NO_SUCH_MATRIX_ENTRY,
362 row, column, getRowDimension(), getColumnDimension());
363 }
364 }
365
366 /** {@inheritDoc} */
367 @Override
368 public void setEntry(final int row, final int column, final double value)
369 throws MatrixIndexException {
370 try {
371 data[row][column] = value;
372 } catch (ArrayIndexOutOfBoundsException e) {
373 throw new MatrixIndexException(
374 LocalizedFormats.NO_SUCH_MATRIX_ENTRY,
375 row, column, getRowDimension(), getColumnDimension());
376 }
377 }
378
379 /** {@inheritDoc} */
380 @Override
381 public void addToEntry(final int row, final int column, final double increment)
382 throws MatrixIndexException {
383 try {
384 data[row][column] += increment;
385 } catch (ArrayIndexOutOfBoundsException e) {
386 throw new MatrixIndexException(
387 LocalizedFormats.NO_SUCH_MATRIX_ENTRY,
388 row, column, getRowDimension(), getColumnDimension());
389 }
390 }
391
392 /** {@inheritDoc} */
393 @Override
394 public void multiplyEntry(final int row, final int column, final double factor)
395 throws MatrixIndexException {
396 try {
397 data[row][column] *= factor;
398 } catch (ArrayIndexOutOfBoundsException e) {
399 throw new MatrixIndexException(
400 LocalizedFormats.NO_SUCH_MATRIX_ENTRY,
401 row, column, getRowDimension(), getColumnDimension());
402 }
403 }
404
405 /** {@inheritDoc} */
406 @Override
407 public int getRowDimension() {
408 return (data == null) ? 0 : data.length;
409 }
410
411 /** {@inheritDoc} */
412 @Override
413 public int getColumnDimension() {
414 return ((data == null) || (data[0] == null)) ? 0 : data[0].length;
415 }
416
417 /** {@inheritDoc} */
418 @Override
419 public double[] operate(final double[] v)
420 throws IllegalArgumentException {
421 final int nRows = this.getRowDimension();
422 final int nCols = this.getColumnDimension();
423 if (v.length != nCols) {
424 throw MathRuntimeException.createIllegalArgumentException(
425 LocalizedFormats.VECTOR_LENGTH_MISMATCH,
426 v.length, nCols);
427 }
428 final double[] out = new double[nRows];
429 for (int row = 0; row < nRows; row++) {
430 final double[] dataRow = data[row];
431 double sum = 0;
432 for (int i = 0; i < nCols; i++) {
433 sum += dataRow[i] * v[i];
434 }
435 out[row] = sum;
436 }
437 return out;
438 }
439
440 /** {@inheritDoc} */
441 @Override
442 public double[] preMultiply(final double[] v)
443 throws IllegalArgumentException {
444
445 final int nRows = getRowDimension();
446 final int nCols = getColumnDimension();
447 if (v.length != nRows) {
448 throw MathRuntimeException.createIllegalArgumentException(
449 LocalizedFormats.VECTOR_LENGTH_MISMATCH,
450 v.length, nRows);
451 }
452
453 final double[] out = new double[nCols];
454 for (int col = 0; col < nCols; ++col) {
455 double sum = 0;
456 for (int i = 0; i < nRows; ++i) {
457 sum += data[i][col] * v[i];
458 }
459 out[col] = sum;
460 }
461
462 return out;
463
464 }
465
466 /** {@inheritDoc} */
467 @Override
468 public double walkInRowOrder(final RealMatrixChangingVisitor visitor)
469 throws MatrixVisitorException {
470 final int rows = getRowDimension();
471 final int columns = getColumnDimension();
472 visitor.start(rows, columns, 0, rows - 1, 0, columns - 1);
473 for (int i = 0; i < rows; ++i) {
474 final double[] rowI = data[i];
475 for (int j = 0; j < columns; ++j) {
476 rowI[j] = visitor.visit(i, j, rowI[j]);
477 }
478 }
479 return visitor.end();
480 }
481
482 /** {@inheritDoc} */
483 @Override
484 public double walkInRowOrder(final RealMatrixPreservingVisitor visitor)
485 throws MatrixVisitorException {
486 final int rows = getRowDimension();
487 final int columns = getColumnDimension();
488 visitor.start(rows, columns, 0, rows - 1, 0, columns - 1);
489 for (int i = 0; i < rows; ++i) {
490 final double[] rowI = data[i];
491 for (int j = 0; j < columns; ++j) {
492 visitor.visit(i, j, rowI[j]);
493 }
494 }
495 return visitor.end();
496 }
497
498 /** {@inheritDoc} */
499 @Override
500 public double walkInRowOrder(final RealMatrixChangingVisitor visitor,
501 final int startRow, final int endRow,
502 final int startColumn, final int endColumn)
503 throws MatrixIndexException, MatrixVisitorException {
504 MatrixUtils.checkSubMatrixIndex(this, startRow, endRow, startColumn, endColumn);
505 visitor.start(getRowDimension(), getColumnDimension(),
506 startRow, endRow, startColumn, endColumn);
507 for (int i = startRow; i <= endRow; ++i) {
508 final double[] rowI = data[i];
509 for (int j = startColumn; j <= endColumn; ++j) {
510 rowI[j] = visitor.visit(i, j, rowI[j]);
511 }
512 }
513 return visitor.end();
514 }
515
516 /** {@inheritDoc} */
517 @Override
518 public double walkInRowOrder(final RealMatrixPreservingVisitor visitor,
519 final int startRow, final int endRow,
520 final int startColumn, final int endColumn)
521 throws MatrixIndexException, MatrixVisitorException {
522 MatrixUtils.checkSubMatrixIndex(this, startRow, endRow, startColumn, endColumn);
523 visitor.start(getRowDimension(), getColumnDimension(),
524 startRow, endRow, startColumn, endColumn);
525 for (int i = startRow; i <= endRow; ++i) {
526 final double[] rowI = data[i];
527 for (int j = startColumn; j <= endColumn; ++j) {
528 visitor.visit(i, j, rowI[j]);
529 }
530 }
531 return visitor.end();
532 }
533
534 /** {@inheritDoc} */
535 @Override
536 public double walkInColumnOrder(final RealMatrixChangingVisitor visitor)
537 throws MatrixVisitorException {
538 final int rows = getRowDimension();
539 final int columns = getColumnDimension();
540 visitor.start(rows, columns, 0, rows - 1, 0, columns - 1);
541 for (int j = 0; j < columns; ++j) {
542 for (int i = 0; i < rows; ++i) {
543 final double[] rowI = data[i];
544 rowI[j] = visitor.visit(i, j, rowI[j]);
545 }
546 }
547 return visitor.end();
548 }
549
550 /** {@inheritDoc} */
551 @Override
552 public double walkInColumnOrder(final RealMatrixPreservingVisitor visitor)
553 throws MatrixVisitorException {
554 final int rows = getRowDimension();
555 final int columns = getColumnDimension();
556 visitor.start(rows, columns, 0, rows - 1, 0, columns - 1);
557 for (int j = 0; j < columns; ++j) {
558 for (int i = 0; i < rows; ++i) {
559 visitor.visit(i, j, data[i][j]);
560 }
561 }
562 return visitor.end();
563 }
564
565 /** {@inheritDoc} */
566 @Override
567 public double walkInColumnOrder(final RealMatrixChangingVisitor visitor,
568 final int startRow, final int endRow,
569 final int startColumn, final int endColumn)
570 throws MatrixIndexException, MatrixVisitorException {
571 MatrixUtils.checkSubMatrixIndex(this, startRow, endRow, startColumn, endColumn);
572 visitor.start(getRowDimension(), getColumnDimension(),
573 startRow, endRow, startColumn, endColumn);
574 for (int j = startColumn; j <= endColumn; ++j) {
575 for (int i = startRow; i <= endRow; ++i) {
576 final double[] rowI = data[i];
577 rowI[j] = visitor.visit(i, j, rowI[j]);
578 }
579 }
580 return visitor.end();
581 }
582
583 /** {@inheritDoc} */
584 @Override
585 public double walkInColumnOrder(final RealMatrixPreservingVisitor visitor,
586 final int startRow, final int endRow,
587 final int startColumn, final int endColumn)
588 throws MatrixIndexException, MatrixVisitorException {
589 MatrixUtils.checkSubMatrixIndex(this, startRow, endRow, startColumn, endColumn);
590 visitor.start(getRowDimension(), getColumnDimension(),
591 startRow, endRow, startColumn, endColumn);
592 for (int j = startColumn; j <= endColumn; ++j) {
593 for (int i = startRow; i <= endRow; ++i) {
594 visitor.visit(i, j, data[i][j]);
595 }
596 }
597 return visitor.end();
598 }
599
600 /**
601 * Returns a fresh copy of the underlying data array.
602 *
603 * @return a copy of the underlying data array.
604 */
605 private double[][] copyOut() {
606 final int nRows = this.getRowDimension();
607 final double[][] out = new double[nRows][this.getColumnDimension()];
608 // can't copy 2-d array in one shot, otherwise get row references
609 for (int i = 0; i < nRows; i++) {
610 System.arraycopy(data[i], 0, out[i], 0, data[i].length);
611 }
612 return out;
613 }
614
615 /**
616 * Replaces data with a fresh copy of the input array.
617 * <p>
618 * Verifies that the input array is rectangular and non-empty.</p>
619 *
620 * @param in data to copy in
621 * @throws IllegalArgumentException if input array is empty or not
622 * rectangular
623 * @throws NullPointerException if input array is null
624 */
625 private void copyIn(final double[][] in) {
626 setSubMatrix(in, 0, 0);
627 }
628
629 }