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