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 18package org.apache.commons.math.linear; 19 20import java.io.Serializable; 21 22import org.apache.commons.math.MathRuntimeException; 23import org.apache.commons.math.linear.MatrixVisitorException; 24import org.apache.commons.math.exception.util.LocalizedFormats; 25 26/** 27 * Implementation of RealMatrix using a double[][] array to store entries and 28 * <a href="http://www.math.gatech.edu/~bourbaki/math2601/Web-notes/2num.pdf"> 29 * LU decomposition</a> to support linear system 30 * solution and inverse. 31 * <p> 32 * The LU decomposition is performed as needed, to support the following operations: <ul> 33 * <li>solve</li> 34 * <li>isSingular</li> 35 * <li>getDeterminant</li> 36 * <li>inverse</li> </ul></p> 37 * <p> 38 * <strong>Usage notes</strong>:<br> 39 * <ul><li> 40 * The LU decomposition is cached and reused on subsequent calls. 41 * If data are modified via references to the underlying array obtained using 42 * <code>getDataRef()</code>, then the stored LU decomposition will not be 43 * discarded. In this case, you need to explicitly invoke 44 * <code>LUDecompose()</code> to recompute the decomposition 45 * before using any of the methods above.</li> 46 * <li> 47 * As specified in the {@link RealMatrix} interface, matrix element indexing 48 * is 0-based -- e.g., <code>getEntry(0, 0)</code> 49 * returns the element in the first row, first column of the matrix.</li></ul> 50 * </p> 51 * 52 * @version $Revision: 1073158 $ $Date: 2011-02-21 22:46:52 +0100 (lun. 21 févr. 2011) $ 53 * @deprecated as of 2.0 replaced by {@link Array2DRowRealMatrix} 54 */ 55@Deprecated 56public class RealMatrixImpl extends AbstractRealMatrix implements Serializable { 57 58 /** Serializable version identifier */ 59 private static final long serialVersionUID = -1067294169172445528L; 60 61 /** Entries of the matrix */ 62 protected double data[][]; 63 64 /** 65 * Creates a matrix with no data 66 */ 67 public RealMatrixImpl() { 68 } 69 70 /** 71 * Create a new RealMatrix with the supplied row and column dimensions. 72 * 73 * @param rowDimension the number of rows in the new matrix 74 * @param columnDimension the number of columns in the new matrix 75 * @throws IllegalArgumentException if row or column dimension is not 76 * positive 77 */ 78 public RealMatrixImpl(final int rowDimension, final int columnDimension) 79 throws IllegalArgumentException { 80 super(rowDimension, columnDimension); 81 data = new double[rowDimension][columnDimension]; 82 } 83 84 /** 85 * Create a new RealMatrix using the input array as the underlying 86 * data array. 87 * <p>The input array is copied, not referenced. This constructor has 88 * the same effect as calling {@link #RealMatrixImpl(double[][], boolean)} 89 * with the second argument set to <code>true</code>.</p> 90 * 91 * @param d data for new matrix 92 * @throws IllegalArgumentException if <code>d</code> is not rectangular 93 * (not all rows have the same length) or empty 94 * @throws NullPointerException if <code>d</code> is null 95 * @see #RealMatrixImpl(double[][], boolean) 96 */ 97 public RealMatrixImpl(final double[][] d) 98 throws IllegalArgumentException, NullPointerException { 99 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} 630