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