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