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