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