1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package org.apache.commons.math3.linear; 19 20 import java.util.ArrayList; 21 22 import org.apache.commons.math3.Field; 23 import org.apache.commons.math3.FieldElement; 24 import org.apache.commons.math3.exception.DimensionMismatchException; 25 import org.apache.commons.math3.exception.NoDataException; 26 import org.apache.commons.math3.exception.NotPositiveException; 27 import org.apache.commons.math3.exception.NotStrictlyPositiveException; 28 import org.apache.commons.math3.exception.NullArgumentException; 29 import org.apache.commons.math3.exception.NumberIsTooSmallException; 30 import org.apache.commons.math3.exception.OutOfRangeException; 31 import org.apache.commons.math3.exception.util.LocalizedFormats; 32 import org.apache.commons.math3.util.MathArrays; 33 34 /** 35 * Basic implementation of {@link FieldMatrix} methods regardless of the underlying storage. 36 * <p>All the methods implemented here use {@link #getEntry(int, int)} to access 37 * matrix elements. Derived class can provide faster implementations. </p> 38 * 39 * @param <T> Type of the field elements. 40 * 41 * @since 2.0 42 */ 43 public abstract class AbstractFieldMatrix<T extends FieldElement<T>> 44 implements FieldMatrix<T> { 45 /** Field to which the elements belong. */ 46 private final Field<T> field; 47 48 /** 49 * Constructor for use with Serializable 50 */ AbstractFieldMatrix()51 protected AbstractFieldMatrix() { 52 field = null; 53 } 54 55 /** 56 * Creates a matrix with no data 57 * @param field field to which the elements belong 58 */ AbstractFieldMatrix(final Field<T> field)59 protected AbstractFieldMatrix(final Field<T> field) { 60 this.field = field; 61 } 62 63 /** 64 * Create a new FieldMatrix<T> with the supplied row and column dimensions. 65 * 66 * @param field Field to which the elements belong. 67 * @param rowDimension Number of rows in the new matrix. 68 * @param columnDimension Number of columns in the new matrix. 69 * @throws NotStrictlyPositiveException if row or column dimension is not 70 * positive. 71 */ AbstractFieldMatrix(final Field<T> field, final int rowDimension, final int columnDimension)72 protected AbstractFieldMatrix(final Field<T> field, 73 final int rowDimension, 74 final int columnDimension) 75 throws NotStrictlyPositiveException { 76 if (rowDimension <= 0) { 77 throw new NotStrictlyPositiveException(LocalizedFormats.DIMENSION, 78 rowDimension); 79 } 80 if (columnDimension <= 0) { 81 throw new NotStrictlyPositiveException(LocalizedFormats.DIMENSION, 82 columnDimension); 83 } 84 this.field = field; 85 } 86 87 /** 88 * Get the elements type from an array. 89 * 90 * @param <T> Type of the field elements. 91 * @param d Data array. 92 * @return the field to which the array elements belong. 93 * @throws NullArgumentException if the array is {@code null}. 94 * @throws NoDataException if the array is empty. 95 */ extractField(final T[][] d)96 protected static <T extends FieldElement<T>> Field<T> extractField(final T[][] d) 97 throws NoDataException, NullArgumentException { 98 if (d == null) { 99 throw new NullArgumentException(); 100 } 101 if (d.length == 0) { 102 throw new NoDataException(LocalizedFormats.AT_LEAST_ONE_ROW); 103 } 104 if (d[0].length == 0) { 105 throw new NoDataException(LocalizedFormats.AT_LEAST_ONE_COLUMN); 106 } 107 return d[0][0].getField(); 108 } 109 110 /** 111 * Get the elements type from an array. 112 * 113 * @param <T> Type of the field elements. 114 * @param d Data array. 115 * @return the field to which the array elements belong. 116 * @throws NoDataException if array is empty. 117 */ extractField(final T[] d)118 protected static <T extends FieldElement<T>> Field<T> extractField(final T[] d) 119 throws NoDataException { 120 if (d.length == 0) { 121 throw new NoDataException(LocalizedFormats.AT_LEAST_ONE_ROW); 122 } 123 return d[0].getField(); 124 } 125 126 /** Build an array of elements. 127 * <p> 128 * Complete arrays are filled with field.getZero() 129 * </p> 130 * @param <T> Type of the field elements 131 * @param field field to which array elements belong 132 * @param rows number of rows 133 * @param columns number of columns (may be negative to build partial 134 * arrays in the same way <code>new Field[rows][]</code> works) 135 * @return a new array 136 * @deprecated as of 3.2, replaced by {@link MathArrays#buildArray(Field, int, int)} 137 */ 138 @Deprecated buildArray(final Field<T> field, final int rows, final int columns)139 protected static <T extends FieldElement<T>> T[][] buildArray(final Field<T> field, 140 final int rows, 141 final int columns) { 142 return MathArrays.buildArray(field, rows, columns); 143 } 144 145 /** Build an array of elements. 146 * <p> 147 * Arrays are filled with field.getZero() 148 * </p> 149 * @param <T> the type of the field elements 150 * @param field field to which array elements belong 151 * @param length of the array 152 * @return a new array 153 * @deprecated as of 3.2, replaced by {@link MathArrays#buildArray(Field, int)} 154 */ 155 @Deprecated buildArray(final Field<T> field, final int length)156 protected static <T extends FieldElement<T>> T[] buildArray(final Field<T> field, 157 final int length) { 158 return MathArrays.buildArray(field, length); 159 } 160 161 /** {@inheritDoc} */ getField()162 public Field<T> getField() { 163 return field; 164 } 165 166 /** {@inheritDoc} */ createMatrix(final int rowDimension, final int columnDimension)167 public abstract FieldMatrix<T> createMatrix(final int rowDimension, 168 final int columnDimension) 169 throws NotStrictlyPositiveException; 170 171 /** {@inheritDoc} */ copy()172 public abstract FieldMatrix<T> copy(); 173 174 /** {@inheritDoc} */ add(FieldMatrix<T> m)175 public FieldMatrix<T> add(FieldMatrix<T> m) 176 throws MatrixDimensionMismatchException { 177 // safety check 178 checkAdditionCompatible(m); 179 180 final int rowCount = getRowDimension(); 181 final int columnCount = getColumnDimension(); 182 final FieldMatrix<T> out = createMatrix(rowCount, columnCount); 183 for (int row = 0; row < rowCount; ++row) { 184 for (int col = 0; col < columnCount; ++col) { 185 out.setEntry(row, col, getEntry(row, col).add(m.getEntry(row, col))); 186 } 187 } 188 189 return out; 190 } 191 192 /** {@inheritDoc} */ subtract(final FieldMatrix<T> m)193 public FieldMatrix<T> subtract(final FieldMatrix<T> m) 194 throws MatrixDimensionMismatchException { 195 // safety check 196 checkSubtractionCompatible(m); 197 198 final int rowCount = getRowDimension(); 199 final int columnCount = getColumnDimension(); 200 final FieldMatrix<T> out = createMatrix(rowCount, columnCount); 201 for (int row = 0; row < rowCount; ++row) { 202 for (int col = 0; col < columnCount; ++col) { 203 out.setEntry(row, col, getEntry(row, col).subtract(m.getEntry(row, col))); 204 } 205 } 206 207 return out; 208 } 209 210 /** {@inheritDoc} */ scalarAdd(final T d)211 public FieldMatrix<T> scalarAdd(final T d) { 212 213 final int rowCount = getRowDimension(); 214 final int columnCount = getColumnDimension(); 215 final FieldMatrix<T> out = createMatrix(rowCount, columnCount); 216 for (int row = 0; row < rowCount; ++row) { 217 for (int col = 0; col < columnCount; ++col) { 218 out.setEntry(row, col, getEntry(row, col).add(d)); 219 } 220 } 221 222 return out; 223 } 224 225 /** {@inheritDoc} */ scalarMultiply(final T d)226 public FieldMatrix<T> scalarMultiply(final T d) { 227 final int rowCount = getRowDimension(); 228 final int columnCount = getColumnDimension(); 229 final FieldMatrix<T> out = createMatrix(rowCount, columnCount); 230 for (int row = 0; row < rowCount; ++row) { 231 for (int col = 0; col < columnCount; ++col) { 232 out.setEntry(row, col, getEntry(row, col).multiply(d)); 233 } 234 } 235 236 return out; 237 } 238 239 /** {@inheritDoc} */ multiply(final FieldMatrix<T> m)240 public FieldMatrix<T> multiply(final FieldMatrix<T> m) 241 throws DimensionMismatchException { 242 // safety check 243 checkMultiplicationCompatible(m); 244 245 final int nRows = getRowDimension(); 246 final int nCols = m.getColumnDimension(); 247 final int nSum = getColumnDimension(); 248 final FieldMatrix<T> out = createMatrix(nRows, nCols); 249 for (int row = 0; row < nRows; ++row) { 250 for (int col = 0; col < nCols; ++col) { 251 T sum = field.getZero(); 252 for (int i = 0; i < nSum; ++i) { 253 sum = sum.add(getEntry(row, i).multiply(m.getEntry(i, col))); 254 } 255 out.setEntry(row, col, sum); 256 } 257 } 258 259 return out; 260 } 261 262 /** {@inheritDoc} */ preMultiply(final FieldMatrix<T> m)263 public FieldMatrix<T> preMultiply(final FieldMatrix<T> m) 264 throws DimensionMismatchException { 265 return m.multiply(this); 266 } 267 268 /** {@inheritDoc} */ power(final int p)269 public FieldMatrix<T> power(final int p) throws NonSquareMatrixException, 270 NotPositiveException { 271 if (p < 0) { 272 throw new NotPositiveException(p); 273 } 274 275 if (!isSquare()) { 276 throw new NonSquareMatrixException(getRowDimension(), getColumnDimension()); 277 } 278 279 if (p == 0) { 280 return MatrixUtils.createFieldIdentityMatrix(this.getField(), this.getRowDimension()); 281 } 282 283 if (p == 1) { 284 return this.copy(); 285 } 286 287 final int power = p - 1; 288 289 /* 290 * Only log_2(p) operations is used by doing as follows: 291 * 5^214 = 5^128 * 5^64 * 5^16 * 5^4 * 5^2 292 * 293 * In general, the same approach is used for A^p. 294 */ 295 296 final char[] binaryRepresentation = Integer.toBinaryString(power) 297 .toCharArray(); 298 final ArrayList<Integer> nonZeroPositions = new ArrayList<Integer>(); 299 300 for (int i = 0; i < binaryRepresentation.length; ++i) { 301 if (binaryRepresentation[i] == '1') { 302 final int pos = binaryRepresentation.length - i - 1; 303 nonZeroPositions.add(pos); 304 } 305 } 306 307 ArrayList<FieldMatrix<T>> results = new ArrayList<FieldMatrix<T>>( 308 binaryRepresentation.length); 309 310 results.add(0, this.copy()); 311 312 for (int i = 1; i < binaryRepresentation.length; ++i) { 313 final FieldMatrix<T> s = results.get(i - 1); 314 final FieldMatrix<T> r = s.multiply(s); 315 results.add(i, r); 316 } 317 318 FieldMatrix<T> result = this.copy(); 319 320 for (Integer i : nonZeroPositions) { 321 result = result.multiply(results.get(i)); 322 } 323 324 return result; 325 } 326 327 /** {@inheritDoc} */ getData()328 public T[][] getData() { 329 final T[][] data = MathArrays.buildArray(field, getRowDimension(), getColumnDimension()); 330 331 for (int i = 0; i < data.length; ++i) { 332 final T[] dataI = data[i]; 333 for (int j = 0; j < dataI.length; ++j) { 334 dataI[j] = getEntry(i, j); 335 } 336 } 337 338 return data; 339 } 340 341 /** {@inheritDoc} */ getSubMatrix(final int startRow, final int endRow, final int startColumn, final int endColumn)342 public FieldMatrix<T> getSubMatrix(final int startRow, final int endRow, 343 final int startColumn, final int endColumn) 344 throws NumberIsTooSmallException, OutOfRangeException { 345 checkSubMatrixIndex(startRow, endRow, startColumn, endColumn); 346 347 final FieldMatrix<T> subMatrix = 348 createMatrix(endRow - startRow + 1, endColumn - startColumn + 1); 349 for (int i = startRow; i <= endRow; ++i) { 350 for (int j = startColumn; j <= endColumn; ++j) { 351 subMatrix.setEntry(i - startRow, j - startColumn, getEntry(i, j)); 352 } 353 } 354 355 return subMatrix; 356 357 } 358 359 /** {@inheritDoc} */ getSubMatrix(final int[] selectedRows, final int[] selectedColumns)360 public FieldMatrix<T> getSubMatrix(final int[] selectedRows, 361 final int[] selectedColumns) 362 throws NoDataException, NullArgumentException, OutOfRangeException { 363 364 // safety checks 365 checkSubMatrixIndex(selectedRows, selectedColumns); 366 367 // copy entries 368 final FieldMatrix<T> subMatrix = 369 createMatrix(selectedRows.length, selectedColumns.length); 370 subMatrix.walkInOptimizedOrder(new DefaultFieldMatrixChangingVisitor<T>(field.getZero()) { 371 372 /** {@inheritDoc} */ 373 @Override 374 public T visit(final int row, final int column, final T value) { 375 return getEntry(selectedRows[row], selectedColumns[column]); 376 } 377 378 }); 379 380 return subMatrix; 381 382 } 383 384 /** {@inheritDoc} */ copySubMatrix(final int startRow, final int endRow, final int startColumn, final int endColumn, final T[][] destination)385 public void copySubMatrix(final int startRow, final int endRow, 386 final int startColumn, final int endColumn, 387 final T[][] destination) 388 throws MatrixDimensionMismatchException, NumberIsTooSmallException, 389 OutOfRangeException{ 390 // safety checks 391 checkSubMatrixIndex(startRow, endRow, startColumn, endColumn); 392 final int rowsCount = endRow + 1 - startRow; 393 final int columnsCount = endColumn + 1 - startColumn; 394 if ((destination.length < rowsCount) || (destination[0].length < columnsCount)) { 395 throw new MatrixDimensionMismatchException(destination.length, 396 destination[0].length, 397 rowsCount, 398 columnsCount); 399 } 400 401 // copy entries 402 walkInOptimizedOrder(new DefaultFieldMatrixPreservingVisitor<T>(field.getZero()) { 403 404 /** Initial row index. */ 405 private int startRow; 406 407 /** Initial column index. */ 408 private int startColumn; 409 410 /** {@inheritDoc} */ 411 @Override 412 public void start(final int rows, final int columns, 413 final int startRow, final int endRow, 414 final int startColumn, final int endColumn) { 415 this.startRow = startRow; 416 this.startColumn = startColumn; 417 } 418 419 /** {@inheritDoc} */ 420 @Override 421 public void visit(final int row, final int column, final T value) { 422 destination[row - startRow][column - startColumn] = value; 423 } 424 425 }, startRow, endRow, startColumn, endColumn); 426 427 } 428 429 /** {@inheritDoc} */ copySubMatrix(int[] selectedRows, int[] selectedColumns, T[][] destination)430 public void copySubMatrix(int[] selectedRows, int[] selectedColumns, T[][] destination) 431 throws MatrixDimensionMismatchException, NoDataException, 432 NullArgumentException, OutOfRangeException { 433 // safety checks 434 checkSubMatrixIndex(selectedRows, selectedColumns); 435 if ((destination.length < selectedRows.length) || 436 (destination[0].length < selectedColumns.length)) { 437 throw new MatrixDimensionMismatchException(destination.length, 438 destination[0].length, 439 selectedRows.length, 440 selectedColumns.length); 441 } 442 443 // copy entries 444 for (int i = 0; i < selectedRows.length; i++) { 445 final T[] destinationI = destination[i]; 446 for (int j = 0; j < selectedColumns.length; j++) { 447 destinationI[j] = getEntry(selectedRows[i], selectedColumns[j]); 448 } 449 } 450 451 } 452 453 /** {@inheritDoc} */ setSubMatrix(final T[][] subMatrix, final int row, final int column)454 public void setSubMatrix(final T[][] subMatrix, final int row, 455 final int column) 456 throws DimensionMismatchException, OutOfRangeException, 457 NoDataException, NullArgumentException { 458 if (subMatrix == null) { 459 throw new NullArgumentException(); 460 } 461 final int nRows = subMatrix.length; 462 if (nRows == 0) { 463 throw new NoDataException(LocalizedFormats.AT_LEAST_ONE_ROW); 464 } 465 466 final int nCols = subMatrix[0].length; 467 if (nCols == 0) { 468 throw new NoDataException(LocalizedFormats.AT_LEAST_ONE_COLUMN); 469 } 470 471 for (int r = 1; r < nRows; ++r) { 472 if (subMatrix[r].length != nCols) { 473 throw new DimensionMismatchException(nCols, subMatrix[r].length); 474 } 475 } 476 477 checkRowIndex(row); 478 checkColumnIndex(column); 479 checkRowIndex(nRows + row - 1); 480 checkColumnIndex(nCols + column - 1); 481 482 for (int i = 0; i < nRows; ++i) { 483 for (int j = 0; j < nCols; ++j) { 484 setEntry(row + i, column + j, subMatrix[i][j]); 485 } 486 } 487 } 488 489 /** {@inheritDoc} */ getRowMatrix(final int row)490 public FieldMatrix<T> getRowMatrix(final int row) throws OutOfRangeException { 491 checkRowIndex(row); 492 final int nCols = getColumnDimension(); 493 final FieldMatrix<T> out = createMatrix(1, nCols); 494 for (int i = 0; i < nCols; ++i) { 495 out.setEntry(0, i, getEntry(row, i)); 496 } 497 498 return out; 499 500 } 501 502 /** {@inheritDoc} */ setRowMatrix(final int row, final FieldMatrix<T> matrix)503 public void setRowMatrix(final int row, final FieldMatrix<T> matrix) 504 throws OutOfRangeException, MatrixDimensionMismatchException { 505 checkRowIndex(row); 506 final int nCols = getColumnDimension(); 507 if ((matrix.getRowDimension() != 1) || 508 (matrix.getColumnDimension() != nCols)) { 509 throw new MatrixDimensionMismatchException(matrix.getRowDimension(), 510 matrix.getColumnDimension(), 511 1, nCols); 512 } 513 for (int i = 0; i < nCols; ++i) { 514 setEntry(row, i, matrix.getEntry(0, i)); 515 } 516 517 } 518 519 /** {@inheritDoc} */ getColumnMatrix(final int column)520 public FieldMatrix<T> getColumnMatrix(final int column) 521 throws OutOfRangeException { 522 523 checkColumnIndex(column); 524 final int nRows = getRowDimension(); 525 final FieldMatrix<T> out = createMatrix(nRows, 1); 526 for (int i = 0; i < nRows; ++i) { 527 out.setEntry(i, 0, getEntry(i, column)); 528 } 529 530 return out; 531 532 } 533 534 /** {@inheritDoc} */ setColumnMatrix(final int column, final FieldMatrix<T> matrix)535 public void setColumnMatrix(final int column, final FieldMatrix<T> matrix) 536 throws OutOfRangeException, MatrixDimensionMismatchException { 537 checkColumnIndex(column); 538 final int nRows = getRowDimension(); 539 if ((matrix.getRowDimension() != nRows) || 540 (matrix.getColumnDimension() != 1)) { 541 throw new MatrixDimensionMismatchException(matrix.getRowDimension(), 542 matrix.getColumnDimension(), 543 nRows, 1); 544 } 545 for (int i = 0; i < nRows; ++i) { 546 setEntry(i, column, matrix.getEntry(i, 0)); 547 } 548 549 } 550 551 /** {@inheritDoc} */ getRowVector(final int row)552 public FieldVector<T> getRowVector(final int row) 553 throws OutOfRangeException { 554 return new ArrayFieldVector<T>(field, getRow(row), false); 555 } 556 557 /** {@inheritDoc} */ setRowVector(final int row, final FieldVector<T> vector)558 public void setRowVector(final int row, final FieldVector<T> vector) 559 throws OutOfRangeException, MatrixDimensionMismatchException { 560 checkRowIndex(row); 561 final int nCols = getColumnDimension(); 562 if (vector.getDimension() != nCols) { 563 throw new MatrixDimensionMismatchException(1, vector.getDimension(), 564 1, nCols); 565 } 566 for (int i = 0; i < nCols; ++i) { 567 setEntry(row, i, vector.getEntry(i)); 568 } 569 570 } 571 572 /** {@inheritDoc} */ getColumnVector(final int column)573 public FieldVector<T> getColumnVector(final int column) 574 throws OutOfRangeException { 575 return new ArrayFieldVector<T>(field, getColumn(column), false); 576 } 577 578 /** {@inheritDoc} */ setColumnVector(final int column, final FieldVector<T> vector)579 public void setColumnVector(final int column, final FieldVector<T> vector) 580 throws OutOfRangeException, MatrixDimensionMismatchException { 581 582 checkColumnIndex(column); 583 final int nRows = getRowDimension(); 584 if (vector.getDimension() != nRows) { 585 throw new MatrixDimensionMismatchException(vector.getDimension(), 1, 586 nRows, 1); 587 } 588 for (int i = 0; i < nRows; ++i) { 589 setEntry(i, column, vector.getEntry(i)); 590 } 591 592 } 593 594 /** {@inheritDoc} */ getRow(final int row)595 public T[] getRow(final int row) throws OutOfRangeException { 596 checkRowIndex(row); 597 final int nCols = getColumnDimension(); 598 final T[] out = MathArrays.buildArray(field, nCols); 599 for (int i = 0; i < nCols; ++i) { 600 out[i] = getEntry(row, i); 601 } 602 603 return out; 604 605 } 606 607 /** {@inheritDoc} */ setRow(final int row, final T[] array)608 public void setRow(final int row, final T[] array) 609 throws OutOfRangeException, MatrixDimensionMismatchException { 610 checkRowIndex(row); 611 final int nCols = getColumnDimension(); 612 if (array.length != nCols) { 613 throw new MatrixDimensionMismatchException(1, array.length, 1, nCols); 614 } 615 for (int i = 0; i < nCols; ++i) { 616 setEntry(row, i, array[i]); 617 } 618 619 } 620 621 /** {@inheritDoc} */ getColumn(final int column)622 public T[] getColumn(final int column) throws OutOfRangeException { 623 checkColumnIndex(column); 624 final int nRows = getRowDimension(); 625 final T[] out = MathArrays.buildArray(field, nRows); 626 for (int i = 0; i < nRows; ++i) { 627 out[i] = getEntry(i, column); 628 } 629 630 return out; 631 632 } 633 634 /** {@inheritDoc} */ setColumn(final int column, final T[] array)635 public void setColumn(final int column, final T[] array) 636 throws OutOfRangeException, MatrixDimensionMismatchException { 637 checkColumnIndex(column); 638 final int nRows = getRowDimension(); 639 if (array.length != nRows) { 640 throw new MatrixDimensionMismatchException(array.length, 1, nRows, 1); 641 } 642 for (int i = 0; i < nRows; ++i) { 643 setEntry(i, column, array[i]); 644 } 645 } 646 647 /** {@inheritDoc} */ getEntry(int row, int column)648 public abstract T getEntry(int row, int column) throws OutOfRangeException; 649 650 /** {@inheritDoc} */ setEntry(int row, int column, T value)651 public abstract void setEntry(int row, int column, T value) throws OutOfRangeException; 652 653 /** {@inheritDoc} */ addToEntry(int row, int column, T increment)654 public abstract void addToEntry(int row, int column, T increment) throws OutOfRangeException; 655 656 /** {@inheritDoc} */ multiplyEntry(int row, int column, T factor)657 public abstract void multiplyEntry(int row, int column, T factor) throws OutOfRangeException; 658 659 /** {@inheritDoc} */ transpose()660 public FieldMatrix<T> transpose() { 661 final int nRows = getRowDimension(); 662 final int nCols = getColumnDimension(); 663 final FieldMatrix<T> out = createMatrix(nCols, nRows); 664 walkInOptimizedOrder(new DefaultFieldMatrixPreservingVisitor<T>(field.getZero()) { 665 /** {@inheritDoc} */ 666 @Override 667 public void visit(final int row, final int column, final T value) { 668 out.setEntry(column, row, value); 669 } 670 }); 671 672 return out; 673 } 674 675 /** {@inheritDoc} */ isSquare()676 public boolean isSquare() { 677 return getColumnDimension() == getRowDimension(); 678 } 679 680 /** {@inheritDoc} */ getRowDimension()681 public abstract int getRowDimension(); 682 683 /** {@inheritDoc} */ getColumnDimension()684 public abstract int getColumnDimension(); 685 686 /** {@inheritDoc} */ getTrace()687 public T getTrace() throws NonSquareMatrixException { 688 final int nRows = getRowDimension(); 689 final int nCols = getColumnDimension(); 690 if (nRows != nCols) { 691 throw new NonSquareMatrixException(nRows, nCols); 692 } 693 T trace = field.getZero(); 694 for (int i = 0; i < nRows; ++i) { 695 trace = trace.add(getEntry(i, i)); 696 } 697 return trace; 698 } 699 700 /** {@inheritDoc} */ operate(final T[] v)701 public T[] operate(final T[] v) throws DimensionMismatchException { 702 703 final int nRows = getRowDimension(); 704 final int nCols = getColumnDimension(); 705 if (v.length != nCols) { 706 throw new DimensionMismatchException(v.length, nCols); 707 } 708 709 final T[] out = MathArrays.buildArray(field, nRows); 710 for (int row = 0; row < nRows; ++row) { 711 T sum = field.getZero(); 712 for (int i = 0; i < nCols; ++i) { 713 sum = sum.add(getEntry(row, i).multiply(v[i])); 714 } 715 out[row] = sum; 716 } 717 718 return out; 719 } 720 721 /** {@inheritDoc} */ operate(final FieldVector<T> v)722 public FieldVector<T> operate(final FieldVector<T> v) 723 throws DimensionMismatchException { 724 try { 725 return new ArrayFieldVector<T>(field, operate(((ArrayFieldVector<T>) v).getDataRef()), false); 726 } catch (ClassCastException cce) { 727 final int nRows = getRowDimension(); 728 final int nCols = getColumnDimension(); 729 if (v.getDimension() != nCols) { 730 throw new DimensionMismatchException(v.getDimension(), nCols); 731 } 732 733 final T[] out = MathArrays.buildArray(field, nRows); 734 for (int row = 0; row < nRows; ++row) { 735 T sum = field.getZero(); 736 for (int i = 0; i < nCols; ++i) { 737 sum = sum.add(getEntry(row, i).multiply(v.getEntry(i))); 738 } 739 out[row] = sum; 740 } 741 742 return new ArrayFieldVector<T>(field, out, false); 743 } 744 } 745 746 /** {@inheritDoc} */ preMultiply(final T[] v)747 public T[] preMultiply(final T[] v) throws DimensionMismatchException { 748 749 final int nRows = getRowDimension(); 750 final int nCols = getColumnDimension(); 751 if (v.length != nRows) { 752 throw new DimensionMismatchException(v.length, nRows); 753 } 754 755 final T[] out = MathArrays.buildArray(field, nCols); 756 for (int col = 0; col < nCols; ++col) { 757 T sum = field.getZero(); 758 for (int i = 0; i < nRows; ++i) { 759 sum = sum.add(getEntry(i, col).multiply(v[i])); 760 } 761 out[col] = sum; 762 } 763 764 return out; 765 } 766 767 /** {@inheritDoc} */ preMultiply(final FieldVector<T> v)768 public FieldVector<T> preMultiply(final FieldVector<T> v) 769 throws DimensionMismatchException { 770 try { 771 return new ArrayFieldVector<T>(field, preMultiply(((ArrayFieldVector<T>) v).getDataRef()), false); 772 } catch (ClassCastException cce) { 773 final int nRows = getRowDimension(); 774 final int nCols = getColumnDimension(); 775 if (v.getDimension() != nRows) { 776 throw new DimensionMismatchException(v.getDimension(), nRows); 777 } 778 779 final T[] out = MathArrays.buildArray(field, nCols); 780 for (int col = 0; col < nCols; ++col) { 781 T sum = field.getZero(); 782 for (int i = 0; i < nRows; ++i) { 783 sum = sum.add(getEntry(i, col).multiply(v.getEntry(i))); 784 } 785 out[col] = sum; 786 } 787 788 return new ArrayFieldVector<T>(field, out, false); 789 } 790 } 791 792 /** {@inheritDoc} */ walkInRowOrder(final FieldMatrixChangingVisitor<T> visitor)793 public T walkInRowOrder(final FieldMatrixChangingVisitor<T> visitor) { 794 final int rows = getRowDimension(); 795 final int columns = getColumnDimension(); 796 visitor.start(rows, columns, 0, rows - 1, 0, columns - 1); 797 for (int row = 0; row < rows; ++row) { 798 for (int column = 0; column < columns; ++column) { 799 final T oldValue = getEntry(row, column); 800 final T newValue = visitor.visit(row, column, oldValue); 801 setEntry(row, column, newValue); 802 } 803 } 804 return visitor.end(); 805 } 806 807 /** {@inheritDoc} */ walkInRowOrder(final FieldMatrixPreservingVisitor<T> visitor)808 public T walkInRowOrder(final FieldMatrixPreservingVisitor<T> visitor) { 809 final int rows = getRowDimension(); 810 final int columns = getColumnDimension(); 811 visitor.start(rows, columns, 0, rows - 1, 0, columns - 1); 812 for (int row = 0; row < rows; ++row) { 813 for (int column = 0; column < columns; ++column) { 814 visitor.visit(row, column, getEntry(row, column)); 815 } 816 } 817 return visitor.end(); 818 } 819 820 /** {@inheritDoc} */ walkInRowOrder(final FieldMatrixChangingVisitor<T> visitor, final int startRow, final int endRow, final int startColumn, final int endColumn)821 public T walkInRowOrder(final FieldMatrixChangingVisitor<T> visitor, 822 final int startRow, final int endRow, 823 final int startColumn, final int endColumn) 824 throws NumberIsTooSmallException, OutOfRangeException { 825 checkSubMatrixIndex(startRow, endRow, startColumn, endColumn); 826 visitor.start(getRowDimension(), getColumnDimension(), 827 startRow, endRow, startColumn, endColumn); 828 for (int row = startRow; row <= endRow; ++row) { 829 for (int column = startColumn; column <= endColumn; ++column) { 830 final T oldValue = getEntry(row, column); 831 final T newValue = visitor.visit(row, column, oldValue); 832 setEntry(row, column, newValue); 833 } 834 } 835 return visitor.end(); 836 } 837 838 /** {@inheritDoc} */ walkInRowOrder(final FieldMatrixPreservingVisitor<T> visitor, final int startRow, final int endRow, final int startColumn, final int endColumn)839 public T walkInRowOrder(final FieldMatrixPreservingVisitor<T> visitor, 840 final int startRow, final int endRow, 841 final int startColumn, final int endColumn) 842 throws NumberIsTooSmallException, OutOfRangeException { 843 checkSubMatrixIndex(startRow, endRow, startColumn, endColumn); 844 visitor.start(getRowDimension(), getColumnDimension(), 845 startRow, endRow, startColumn, endColumn); 846 for (int row = startRow; row <= endRow; ++row) { 847 for (int column = startColumn; column <= endColumn; ++column) { 848 visitor.visit(row, column, getEntry(row, column)); 849 } 850 } 851 return visitor.end(); 852 } 853 854 /** {@inheritDoc} */ walkInColumnOrder(final FieldMatrixChangingVisitor<T> visitor)855 public T walkInColumnOrder(final FieldMatrixChangingVisitor<T> visitor) { 856 final int rows = getRowDimension(); 857 final int columns = getColumnDimension(); 858 visitor.start(rows, columns, 0, rows - 1, 0, columns - 1); 859 for (int column = 0; column < columns; ++column) { 860 for (int row = 0; row < rows; ++row) { 861 final T oldValue = getEntry(row, column); 862 final T newValue = visitor.visit(row, column, oldValue); 863 setEntry(row, column, newValue); 864 } 865 } 866 return visitor.end(); 867 } 868 869 /** {@inheritDoc} */ walkInColumnOrder(final FieldMatrixPreservingVisitor<T> visitor)870 public T walkInColumnOrder(final FieldMatrixPreservingVisitor<T> visitor) { 871 final int rows = getRowDimension(); 872 final int columns = getColumnDimension(); 873 visitor.start(rows, columns, 0, rows - 1, 0, columns - 1); 874 for (int column = 0; column < columns; ++column) { 875 for (int row = 0; row < rows; ++row) { 876 visitor.visit(row, column, getEntry(row, column)); 877 } 878 } 879 return visitor.end(); 880 } 881 882 /** {@inheritDoc} */ walkInColumnOrder(final FieldMatrixChangingVisitor<T> visitor, final int startRow, final int endRow, final int startColumn, final int endColumn)883 public T walkInColumnOrder(final FieldMatrixChangingVisitor<T> visitor, 884 final int startRow, final int endRow, 885 final int startColumn, final int endColumn) 886 throws NumberIsTooSmallException, OutOfRangeException { 887 checkSubMatrixIndex(startRow, endRow, startColumn, endColumn); 888 visitor.start(getRowDimension(), getColumnDimension(), 889 startRow, endRow, startColumn, endColumn); 890 for (int column = startColumn; column <= endColumn; ++column) { 891 for (int row = startRow; row <= endRow; ++row) { 892 final T oldValue = getEntry(row, column); 893 final T newValue = visitor.visit(row, column, oldValue); 894 setEntry(row, column, newValue); 895 } 896 } 897 return visitor.end(); 898 } 899 900 /** {@inheritDoc} */ walkInColumnOrder(final FieldMatrixPreservingVisitor<T> visitor, final int startRow, final int endRow, final int startColumn, final int endColumn)901 public T walkInColumnOrder(final FieldMatrixPreservingVisitor<T> visitor, 902 final int startRow, final int endRow, 903 final int startColumn, final int endColumn) 904 throws NumberIsTooSmallException, OutOfRangeException{ 905 checkSubMatrixIndex(startRow, endRow, startColumn, endColumn); 906 visitor.start(getRowDimension(), getColumnDimension(), 907 startRow, endRow, startColumn, endColumn); 908 for (int column = startColumn; column <= endColumn; ++column) { 909 for (int row = startRow; row <= endRow; ++row) { 910 visitor.visit(row, column, getEntry(row, column)); 911 } 912 } 913 return visitor.end(); 914 } 915 916 /** {@inheritDoc} */ walkInOptimizedOrder(final FieldMatrixChangingVisitor<T> visitor)917 public T walkInOptimizedOrder(final FieldMatrixChangingVisitor<T> visitor) { 918 return walkInRowOrder(visitor); 919 } 920 921 /** {@inheritDoc} */ walkInOptimizedOrder(final FieldMatrixPreservingVisitor<T> visitor)922 public T walkInOptimizedOrder(final FieldMatrixPreservingVisitor<T> visitor) { 923 return walkInRowOrder(visitor); 924 } 925 926 /** {@inheritDoc} */ walkInOptimizedOrder(final FieldMatrixChangingVisitor<T> visitor, final int startRow, final int endRow, final int startColumn, final int endColumn)927 public T walkInOptimizedOrder(final FieldMatrixChangingVisitor<T> visitor, 928 final int startRow, final int endRow, 929 final int startColumn, final int endColumn) 930 throws NumberIsTooSmallException, OutOfRangeException { 931 return walkInRowOrder(visitor, startRow, endRow, startColumn, endColumn); 932 } 933 934 /** {@inheritDoc} */ walkInOptimizedOrder(final FieldMatrixPreservingVisitor<T> visitor, final int startRow, final int endRow, final int startColumn, final int endColumn)935 public T walkInOptimizedOrder(final FieldMatrixPreservingVisitor<T> visitor, 936 final int startRow, final int endRow, 937 final int startColumn, final int endColumn) 938 throws NumberIsTooSmallException, OutOfRangeException { 939 return walkInRowOrder(visitor, startRow, endRow, startColumn, endColumn); 940 } 941 942 /** 943 * Get a string representation for this matrix. 944 * @return a string representation for this matrix 945 */ 946 @Override toString()947 public String toString() { 948 final int nRows = getRowDimension(); 949 final int nCols = getColumnDimension(); 950 final StringBuffer res = new StringBuffer(); 951 String fullClassName = getClass().getName(); 952 String shortClassName = fullClassName.substring(fullClassName.lastIndexOf('.') + 1); 953 res.append(shortClassName).append("{"); 954 955 for (int i = 0; i < nRows; ++i) { 956 if (i > 0) { 957 res.append(","); 958 } 959 res.append("{"); 960 for (int j = 0; j < nCols; ++j) { 961 if (j > 0) { 962 res.append(","); 963 } 964 res.append(getEntry(i, j)); 965 } 966 res.append("}"); 967 } 968 969 res.append("}"); 970 return res.toString(); 971 } 972 973 /** 974 * Returns true iff <code>object</code> is a 975 * <code>FieldMatrix</code> instance with the same dimensions as this 976 * and all corresponding matrix entries are equal. 977 * 978 * @param object the object to test equality against. 979 * @return true if object equals this 980 */ 981 @Override equals(final Object object)982 public boolean equals(final Object object) { 983 if (object == this ) { 984 return true; 985 } 986 if (object instanceof FieldMatrix<?> == false) { 987 return false; 988 } 989 FieldMatrix<?> m = (FieldMatrix<?>) object; 990 final int nRows = getRowDimension(); 991 final int nCols = getColumnDimension(); 992 if (m.getColumnDimension() != nCols || m.getRowDimension() != nRows) { 993 return false; 994 } 995 for (int row = 0; row < nRows; ++row) { 996 for (int col = 0; col < nCols; ++col) { 997 if (!getEntry(row, col).equals(m.getEntry(row, col))) { 998 return false; 999 } 1000 } 1001 } 1002 return true; 1003 } 1004 1005 /** 1006 * Computes a hashcode for the matrix. 1007 * 1008 * @return hashcode for matrix 1009 */ 1010 @Override hashCode()1011 public int hashCode() { 1012 int ret = 322562; 1013 final int nRows = getRowDimension(); 1014 final int nCols = getColumnDimension(); 1015 ret = ret * 31 + nRows; 1016 ret = ret * 31 + nCols; 1017 for (int row = 0; row < nRows; ++row) { 1018 for (int col = 0; col < nCols; ++col) { 1019 ret = ret * 31 + (11 * (row+1) + 17 * (col+1)) * getEntry(row, col).hashCode(); 1020 } 1021 } 1022 return ret; 1023 } 1024 1025 /** 1026 * Check if a row index is valid. 1027 * 1028 * @param row Row index to check. 1029 * @throws OutOfRangeException if {@code index} is not valid. 1030 */ checkRowIndex(final int row)1031 protected void checkRowIndex(final int row) throws OutOfRangeException { 1032 if (row < 0 || row >= getRowDimension()) { 1033 throw new OutOfRangeException(LocalizedFormats.ROW_INDEX, 1034 row, 0, getRowDimension() - 1); 1035 } 1036 } 1037 1038 /** 1039 * Check if a column index is valid. 1040 * 1041 * @param column Column index to check. 1042 * @throws OutOfRangeException if {@code index} is not valid. 1043 */ checkColumnIndex(final int column)1044 protected void checkColumnIndex(final int column) 1045 throws OutOfRangeException { 1046 if (column < 0 || column >= getColumnDimension()) { 1047 throw new OutOfRangeException(LocalizedFormats.COLUMN_INDEX, 1048 column, 0, getColumnDimension() - 1); 1049 } 1050 } 1051 1052 /** 1053 * Check if submatrix ranges indices are valid. 1054 * Rows and columns are indicated counting from 0 to n-1. 1055 * 1056 * @param startRow Initial row index. 1057 * @param endRow Final row index. 1058 * @param startColumn Initial column index. 1059 * @param endColumn Final column index. 1060 * @throws OutOfRangeException if the indices are not valid. 1061 * @throws NumberIsTooSmallException if {@code endRow < startRow} or 1062 * {@code endColumn < startColumn}. 1063 */ checkSubMatrixIndex(final int startRow, final int endRow, final int startColumn, final int endColumn)1064 protected void checkSubMatrixIndex(final int startRow, final int endRow, 1065 final int startColumn, final int endColumn) 1066 throws NumberIsTooSmallException, OutOfRangeException { 1067 checkRowIndex(startRow); 1068 checkRowIndex(endRow); 1069 if (endRow < startRow) { 1070 throw new NumberIsTooSmallException(LocalizedFormats.INITIAL_ROW_AFTER_FINAL_ROW, 1071 endRow, startRow, true); 1072 } 1073 1074 checkColumnIndex(startColumn); 1075 checkColumnIndex(endColumn); 1076 if (endColumn < startColumn) { 1077 throw new NumberIsTooSmallException(LocalizedFormats.INITIAL_COLUMN_AFTER_FINAL_COLUMN, 1078 endColumn, startColumn, true); 1079 } 1080 } 1081 1082 /** 1083 * Check if submatrix ranges indices are valid. 1084 * Rows and columns are indicated counting from 0 to n-1. 1085 * 1086 * @param selectedRows Array of row indices. 1087 * @param selectedColumns Array of column indices. 1088 * @throws NullArgumentException if the arrays are {@code null}. 1089 * @throws NoDataException if the arrays have zero length. 1090 * @throws OutOfRangeException if row or column selections are not valid. 1091 */ checkSubMatrixIndex(final int[] selectedRows, final int[] selectedColumns)1092 protected void checkSubMatrixIndex(final int[] selectedRows, final int[] selectedColumns) 1093 throws NoDataException, NullArgumentException, OutOfRangeException { 1094 if (selectedRows == null || 1095 selectedColumns == null) { 1096 throw new NullArgumentException(); 1097 } 1098 if (selectedRows.length == 0 || 1099 selectedColumns.length == 0) { 1100 throw new NoDataException(); 1101 } 1102 1103 for (final int row : selectedRows) { 1104 checkRowIndex(row); 1105 } 1106 for (final int column : selectedColumns) { 1107 checkColumnIndex(column); 1108 } 1109 } 1110 1111 /** 1112 * Check if a matrix is addition compatible with the instance. 1113 * 1114 * @param m Matrix to check. 1115 * @throws MatrixDimensionMismatchException if the matrix is not 1116 * addition-compatible with instance. 1117 */ checkAdditionCompatible(final FieldMatrix<T> m)1118 protected void checkAdditionCompatible(final FieldMatrix<T> m) 1119 throws MatrixDimensionMismatchException { 1120 if ((getRowDimension() != m.getRowDimension()) || 1121 (getColumnDimension() != m.getColumnDimension())) { 1122 throw new MatrixDimensionMismatchException(m.getRowDimension(), m.getColumnDimension(), 1123 getRowDimension(), getColumnDimension()); 1124 } 1125 } 1126 1127 /** 1128 * Check if a matrix is subtraction compatible with the instance. 1129 * 1130 * @param m Matrix to check. 1131 * @throws MatrixDimensionMismatchException if the matrix is not 1132 * subtraction-compatible with instance. 1133 */ checkSubtractionCompatible(final FieldMatrix<T> m)1134 protected void checkSubtractionCompatible(final FieldMatrix<T> m) 1135 throws MatrixDimensionMismatchException { 1136 if ((getRowDimension() != m.getRowDimension()) || 1137 (getColumnDimension() != m.getColumnDimension())) { 1138 throw new MatrixDimensionMismatchException(m.getRowDimension(), m.getColumnDimension(), 1139 getRowDimension(), getColumnDimension()); 1140 } 1141 } 1142 1143 /** 1144 * Check if a matrix is multiplication compatible with the instance. 1145 * 1146 * @param m Matrix to check. 1147 * @throws DimensionMismatchException if the matrix is not 1148 * multiplication-compatible with instance. 1149 */ checkMultiplicationCompatible(final FieldMatrix<T> m)1150 protected void checkMultiplicationCompatible(final FieldMatrix<T> m) 1151 throws DimensionMismatchException { 1152 if (getColumnDimension() != m.getRowDimension()) { 1153 throw new DimensionMismatchException(m.getRowDimension(), getColumnDimension()); 1154 } 1155 } 1156 } 1157