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.math3.linear; 019 020 import java.io.Serializable; 021 022 import org.apache.commons.math3.exception.DimensionMismatchException; 023 import org.apache.commons.math3.exception.MathIllegalStateException; 024 import org.apache.commons.math3.exception.NoDataException; 025 import org.apache.commons.math3.exception.NotStrictlyPositiveException; 026 import org.apache.commons.math3.exception.NullArgumentException; 027 import org.apache.commons.math3.exception.NumberIsTooSmallException; 028 import org.apache.commons.math3.exception.OutOfRangeException; 029 import org.apache.commons.math3.exception.util.LocalizedFormats; 030 import org.apache.commons.math3.util.MathUtils; 031 032 /** 033 * Implementation of {@link RealMatrix} using a {@code double[][]} array to 034 * store entries. 035 * 036 * @version $Id: Array2DRowRealMatrix.java 1416643 2012-12-03 19:37:14Z tn $ 037 */ 038 public class Array2DRowRealMatrix extends AbstractRealMatrix implements Serializable { 039 /** Serializable version identifier. */ 040 private static final long serialVersionUID = -1067294169172445528L; 041 042 /** Entries of the matrix. */ 043 private double data[][]; 044 045 /** 046 * Creates a matrix with no data 047 */ 048 public Array2DRowRealMatrix() {} 049 050 /** 051 * Create a new RealMatrix with the supplied row and column dimensions. 052 * 053 * @param rowDimension Number of rows in the new matrix. 054 * @param columnDimension Number of columns in the new matrix. 055 * @throws NotStrictlyPositiveException if the row or column dimension is 056 * not positive. 057 */ 058 public Array2DRowRealMatrix(final int rowDimension, 059 final int columnDimension) 060 throws NotStrictlyPositiveException { 061 super(rowDimension, columnDimension); 062 data = new double[rowDimension][columnDimension]; 063 } 064 065 /** 066 * Create a new {@code RealMatrix} using the input array as the underlying 067 * data array. 068 * <p>The input array is copied, not referenced. This constructor has 069 * the same effect as calling {@link #Array2DRowRealMatrix(double[][], boolean)} 070 * with the second argument set to {@code true}.</p> 071 * 072 * @param d Data for the new matrix. 073 * @throws DimensionMismatchException if {@code d} is not rectangular. 074 * @throws NoDataException if {@code d} row or colum dimension is zero. 075 * @throws NullArgumentException if {@code d} is {@code null}. 076 * @see #Array2DRowRealMatrix(double[][], boolean) 077 */ 078 public Array2DRowRealMatrix(final double[][] d) 079 throws DimensionMismatchException, NoDataException, NullArgumentException { 080 copyIn(d); 081 } 082 083 /** 084 * Create a new RealMatrix using the input array as the underlying 085 * data array. 086 * If an array is built specially in order to be embedded in a 087 * RealMatrix and not used directly, the {@code copyArray} may be 088 * set to {@code false}. This will prevent the copying and improve 089 * performance as no new array will be built and no data will be copied. 090 * 091 * @param d Data for new matrix. 092 * @param copyArray if {@code true}, the input array will be copied, 093 * otherwise it will be referenced. 094 * @throws DimensionMismatchException if {@code d} is not rectangular. 095 * @throws NoDataException if {@code d} row or colum dimension is zero. 096 * @throws NullArgumentException if {@code d} is {@code null}. 097 * @see #Array2DRowRealMatrix(double[][]) 098 */ 099 public Array2DRowRealMatrix(final double[][] d, final boolean copyArray) 100 throws DimensionMismatchException, NoDataException, 101 NullArgumentException { 102 if (copyArray) { 103 copyIn(d); 104 } else { 105 if (d == null) { 106 throw new NullArgumentException(); 107 } 108 final int nRows = d.length; 109 if (nRows == 0) { 110 throw new NoDataException(LocalizedFormats.AT_LEAST_ONE_ROW); 111 } 112 final int nCols = d[0].length; 113 if (nCols == 0) { 114 throw new NoDataException(LocalizedFormats.AT_LEAST_ONE_COLUMN); 115 } 116 for (int r = 1; r < nRows; r++) { 117 if (d[r].length != nCols) { 118 throw new DimensionMismatchException(d[r].length, nCols); 119 } 120 } 121 data = d; 122 } 123 } 124 125 /** 126 * Create a new (column) RealMatrix using {@code v} as the 127 * data for the unique column of the created matrix. 128 * The input array is copied. 129 * 130 * @param v Column vector holding data for new matrix. 131 */ 132 public Array2DRowRealMatrix(final double[] v) { 133 final int nRows = v.length; 134 data = new double[nRows][1]; 135 for (int row = 0; row < nRows; row++) { 136 data[row][0] = v[row]; 137 } 138 } 139 140 /** {@inheritDoc} */ 141 @Override 142 public RealMatrix createMatrix(final int rowDimension, 143 final int columnDimension) 144 throws NotStrictlyPositiveException { 145 return new Array2DRowRealMatrix(rowDimension, columnDimension); 146 } 147 148 /** {@inheritDoc} */ 149 @Override 150 public RealMatrix copy() { 151 return new Array2DRowRealMatrix(copyOut(), false); 152 } 153 154 /** 155 * Compute the sum of {@code this} and {@code m}. 156 * 157 * @param m Matrix to be added. 158 * @return {@code this + m}. 159 * @throws MatrixDimensionMismatchException if {@code m} is not the same 160 * size as {@code this}. 161 */ 162 public Array2DRowRealMatrix add(final Array2DRowRealMatrix m) 163 throws MatrixDimensionMismatchException { 164 // Safety check. 165 MatrixUtils.checkAdditionCompatible(this, m); 166 167 final int rowCount = getRowDimension(); 168 final int columnCount = getColumnDimension(); 169 final double[][] outData = new double[rowCount][columnCount]; 170 for (int row = 0; row < rowCount; row++) { 171 final double[] dataRow = data[row]; 172 final double[] mRow = m.data[row]; 173 final double[] outDataRow = outData[row]; 174 for (int col = 0; col < columnCount; col++) { 175 outDataRow[col] = dataRow[col] + mRow[col]; 176 } 177 } 178 179 return new Array2DRowRealMatrix(outData, false); 180 } 181 182 /** 183 * Returns {@code this} minus {@code m}. 184 * 185 * @param m Matrix to be subtracted. 186 * @return {@code this - m} 187 * @throws MatrixDimensionMismatchException if {@code m} is not the same 188 * size as {@code this}. 189 */ 190 public Array2DRowRealMatrix subtract(final Array2DRowRealMatrix m) 191 throws MatrixDimensionMismatchException { 192 MatrixUtils.checkSubtractionCompatible(this, m); 193 194 final int rowCount = getRowDimension(); 195 final int columnCount = getColumnDimension(); 196 final double[][] outData = new double[rowCount][columnCount]; 197 for (int row = 0; row < rowCount; row++) { 198 final double[] dataRow = data[row]; 199 final double[] mRow = m.data[row]; 200 final double[] outDataRow = outData[row]; 201 for (int col = 0; col < columnCount; col++) { 202 outDataRow[col] = dataRow[col] - mRow[col]; 203 } 204 } 205 206 return new Array2DRowRealMatrix(outData, false); 207 } 208 209 /** 210 * Returns the result of postmultiplying {@code this} by {@code m}. 211 * 212 * @param m matrix to postmultiply by 213 * @return {@code this * m} 214 * @throws DimensionMismatchException if 215 * {@code columnDimension(this) != rowDimension(m)} 216 */ 217 public Array2DRowRealMatrix multiply(final Array2DRowRealMatrix m) 218 throws DimensionMismatchException { 219 MatrixUtils.checkMultiplicationCompatible(this, m); 220 221 final int nRows = this.getRowDimension(); 222 final int nCols = m.getColumnDimension(); 223 final int nSum = this.getColumnDimension(); 224 225 final double[][] outData = new double[nRows][nCols]; 226 // Will hold a column of "m". 227 final double[] mCol = new double[nSum]; 228 final double[][] mData = m.data; 229 230 // Multiply. 231 for (int col = 0; col < nCols; col++) { 232 // Copy all elements of column "col" of "m" so that 233 // will be in contiguous memory. 234 for (int mRow = 0; mRow < nSum; mRow++) { 235 mCol[mRow] = mData[mRow][col]; 236 } 237 238 for (int row = 0; row < nRows; row++) { 239 final double[] dataRow = data[row]; 240 double sum = 0; 241 for (int i = 0; i < nSum; i++) { 242 sum += dataRow[i] * mCol[i]; 243 } 244 outData[row][col] = sum; 245 } 246 } 247 248 return new Array2DRowRealMatrix(outData, false); 249 } 250 251 /** {@inheritDoc} */ 252 @Override 253 public double[][] getData() { 254 return copyOut(); 255 } 256 257 /** 258 * Get a reference to the underlying data array. 259 * 260 * @return 2-dimensional array of entries. 261 */ 262 public double[][] getDataRef() { 263 return data; 264 } 265 266 /** {@inheritDoc} */ 267 @Override 268 public void setSubMatrix(final double[][] subMatrix, final int row, 269 final int column) 270 throws NoDataException, OutOfRangeException, 271 DimensionMismatchException, NullArgumentException { 272 if (data == null) { 273 if (row > 0) { 274 throw new MathIllegalStateException(LocalizedFormats.FIRST_ROWS_NOT_INITIALIZED_YET, row); 275 } 276 if (column > 0) { 277 throw new MathIllegalStateException(LocalizedFormats.FIRST_COLUMNS_NOT_INITIALIZED_YET, column); 278 } 279 MathUtils.checkNotNull(subMatrix); 280 final int nRows = subMatrix.length; 281 if (nRows == 0) { 282 throw new NoDataException(LocalizedFormats.AT_LEAST_ONE_ROW); 283 } 284 285 final int nCols = subMatrix[0].length; 286 if (nCols == 0) { 287 throw new NoDataException(LocalizedFormats.AT_LEAST_ONE_COLUMN); 288 } 289 data = new double[subMatrix.length][nCols]; 290 for (int i = 0; i < data.length; ++i) { 291 if (subMatrix[i].length != nCols) { 292 throw new DimensionMismatchException(subMatrix[i].length, nCols); 293 } 294 System.arraycopy(subMatrix[i], 0, data[i + row], column, nCols); 295 } 296 } else { 297 super.setSubMatrix(subMatrix, row, column); 298 } 299 300 } 301 302 /** {@inheritDoc} */ 303 @Override 304 public double getEntry(final int row, final int column) 305 throws OutOfRangeException { 306 MatrixUtils.checkMatrixIndex(this, row, column); 307 return data[row][column]; 308 } 309 310 /** {@inheritDoc} */ 311 @Override 312 public void setEntry(final int row, final int column, final double value) 313 throws OutOfRangeException { 314 MatrixUtils.checkMatrixIndex(this, row, column); 315 data[row][column] = value; 316 } 317 318 /** {@inheritDoc} */ 319 @Override 320 public void addToEntry(final int row, final int column, 321 final double increment) 322 throws OutOfRangeException { 323 MatrixUtils.checkMatrixIndex(this, row, column); 324 data[row][column] += increment; 325 } 326 327 /** {@inheritDoc} */ 328 @Override 329 public void multiplyEntry(final int row, final int column, 330 final double factor) 331 throws OutOfRangeException { 332 MatrixUtils.checkMatrixIndex(this, row, column); 333 data[row][column] *= factor; 334 } 335 336 /** {@inheritDoc} */ 337 @Override 338 public int getRowDimension() { 339 return (data == null) ? 0 : data.length; 340 } 341 342 /** {@inheritDoc} */ 343 @Override 344 public int getColumnDimension() { 345 return ((data == null) || (data[0] == null)) ? 0 : data[0].length; 346 } 347 348 /** {@inheritDoc} */ 349 @Override 350 public double[] operate(final double[] v) 351 throws DimensionMismatchException { 352 final int nRows = this.getRowDimension(); 353 final int nCols = this.getColumnDimension(); 354 if (v.length != nCols) { 355 throw new DimensionMismatchException(v.length, nCols); 356 } 357 final double[] out = new double[nRows]; 358 for (int row = 0; row < nRows; row++) { 359 final double[] dataRow = data[row]; 360 double sum = 0; 361 for (int i = 0; i < nCols; i++) { 362 sum += dataRow[i] * v[i]; 363 } 364 out[row] = sum; 365 } 366 return out; 367 } 368 369 /** {@inheritDoc} */ 370 @Override 371 public double[] preMultiply(final double[] v) 372 throws DimensionMismatchException { 373 final int nRows = getRowDimension(); 374 final int nCols = getColumnDimension(); 375 if (v.length != nRows) { 376 throw new DimensionMismatchException(v.length, nRows); 377 } 378 379 final double[] out = new double[nCols]; 380 for (int col = 0; col < nCols; ++col) { 381 double sum = 0; 382 for (int i = 0; i < nRows; ++i) { 383 sum += data[i][col] * v[i]; 384 } 385 out[col] = sum; 386 } 387 388 return out; 389 390 } 391 392 /** {@inheritDoc} */ 393 @Override 394 public double walkInRowOrder(final RealMatrixChangingVisitor visitor) { 395 final int rows = getRowDimension(); 396 final int columns = getColumnDimension(); 397 visitor.start(rows, columns, 0, rows - 1, 0, columns - 1); 398 for (int i = 0; i < rows; ++i) { 399 final double[] rowI = data[i]; 400 for (int j = 0; j < columns; ++j) { 401 rowI[j] = visitor.visit(i, j, rowI[j]); 402 } 403 } 404 return visitor.end(); 405 } 406 407 /** {@inheritDoc} */ 408 @Override 409 public double walkInRowOrder(final RealMatrixPreservingVisitor visitor) { 410 final int rows = getRowDimension(); 411 final int columns = getColumnDimension(); 412 visitor.start(rows, columns, 0, rows - 1, 0, columns - 1); 413 for (int i = 0; i < rows; ++i) { 414 final double[] rowI = data[i]; 415 for (int j = 0; j < columns; ++j) { 416 visitor.visit(i, j, rowI[j]); 417 } 418 } 419 return visitor.end(); 420 } 421 422 /** {@inheritDoc} */ 423 @Override 424 public double walkInRowOrder(final RealMatrixChangingVisitor visitor, 425 final int startRow, final int endRow, 426 final int startColumn, final int endColumn) 427 throws OutOfRangeException, NumberIsTooSmallException { 428 MatrixUtils.checkSubMatrixIndex(this, startRow, endRow, startColumn, endColumn); 429 visitor.start(getRowDimension(), getColumnDimension(), 430 startRow, endRow, startColumn, endColumn); 431 for (int i = startRow; i <= endRow; ++i) { 432 final double[] rowI = data[i]; 433 for (int j = startColumn; j <= endColumn; ++j) { 434 rowI[j] = visitor.visit(i, j, rowI[j]); 435 } 436 } 437 return visitor.end(); 438 } 439 440 /** {@inheritDoc} */ 441 @Override 442 public double walkInRowOrder(final RealMatrixPreservingVisitor visitor, 443 final int startRow, final int endRow, 444 final int startColumn, final int endColumn) 445 throws OutOfRangeException, NumberIsTooSmallException { 446 MatrixUtils.checkSubMatrixIndex(this, startRow, endRow, startColumn, endColumn); 447 visitor.start(getRowDimension(), getColumnDimension(), 448 startRow, endRow, startColumn, endColumn); 449 for (int i = startRow; i <= endRow; ++i) { 450 final double[] rowI = data[i]; 451 for (int j = startColumn; j <= endColumn; ++j) { 452 visitor.visit(i, j, rowI[j]); 453 } 454 } 455 return visitor.end(); 456 } 457 458 /** {@inheritDoc} */ 459 @Override 460 public double walkInColumnOrder(final RealMatrixChangingVisitor visitor) { 461 final int rows = getRowDimension(); 462 final int columns = getColumnDimension(); 463 visitor.start(rows, columns, 0, rows - 1, 0, columns - 1); 464 for (int j = 0; j < columns; ++j) { 465 for (int i = 0; i < rows; ++i) { 466 final double[] rowI = data[i]; 467 rowI[j] = visitor.visit(i, j, rowI[j]); 468 } 469 } 470 return visitor.end(); 471 } 472 473 /** {@inheritDoc} */ 474 @Override 475 public double walkInColumnOrder(final RealMatrixPreservingVisitor visitor) { 476 final int rows = getRowDimension(); 477 final int columns = getColumnDimension(); 478 visitor.start(rows, columns, 0, rows - 1, 0, columns - 1); 479 for (int j = 0; j < columns; ++j) { 480 for (int i = 0; i < rows; ++i) { 481 visitor.visit(i, j, data[i][j]); 482 } 483 } 484 return visitor.end(); 485 } 486 487 /** {@inheritDoc} */ 488 @Override 489 public double walkInColumnOrder(final RealMatrixChangingVisitor visitor, 490 final int startRow, final int endRow, 491 final int startColumn, final int endColumn) 492 throws OutOfRangeException, NumberIsTooSmallException { 493 MatrixUtils.checkSubMatrixIndex(this, startRow, endRow, startColumn, endColumn); 494 visitor.start(getRowDimension(), getColumnDimension(), 495 startRow, endRow, startColumn, endColumn); 496 for (int j = startColumn; j <= endColumn; ++j) { 497 for (int i = startRow; i <= endRow; ++i) { 498 final double[] rowI = data[i]; 499 rowI[j] = visitor.visit(i, j, rowI[j]); 500 } 501 } 502 return visitor.end(); 503 } 504 505 /** {@inheritDoc} */ 506 @Override 507 public double walkInColumnOrder(final RealMatrixPreservingVisitor visitor, 508 final int startRow, final int endRow, 509 final int startColumn, final int endColumn) 510 throws OutOfRangeException, NumberIsTooSmallException { 511 MatrixUtils.checkSubMatrixIndex(this, startRow, endRow, startColumn, endColumn); 512 visitor.start(getRowDimension(), getColumnDimension(), 513 startRow, endRow, startColumn, endColumn); 514 for (int j = startColumn; j <= endColumn; ++j) { 515 for (int i = startRow; i <= endRow; ++i) { 516 visitor.visit(i, j, data[i][j]); 517 } 518 } 519 return visitor.end(); 520 } 521 522 /** 523 * Get a fresh copy of the underlying data array. 524 * 525 * @return a copy of the underlying data array. 526 */ 527 private double[][] copyOut() { 528 final int nRows = this.getRowDimension(); 529 final double[][] out = new double[nRows][this.getColumnDimension()]; 530 // can't copy 2-d array in one shot, otherwise get row references 531 for (int i = 0; i < nRows; i++) { 532 System.arraycopy(data[i], 0, out[i], 0, data[i].length); 533 } 534 return out; 535 } 536 537 /** 538 * Replace data with a fresh copy of the input array. 539 * 540 * @param in Data to copy. 541 * @throws NoDataException if the input array is empty. 542 * @throws DimensionMismatchException if the input array is not rectangular. 543 * @throws NullArgumentException if the input array is {@code null}. 544 */ 545 private void copyIn(final double[][] in) 546 throws DimensionMismatchException, NoDataException, NullArgumentException { 547 setSubMatrix(in, 0, 0); 548 } 549 }