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.util.ArrayList; 021 022import org.apache.commons.math4.legacy.core.Field; 023import org.apache.commons.math4.legacy.core.FieldElement; 024import org.apache.commons.math4.legacy.exception.DimensionMismatchException; 025import org.apache.commons.math4.legacy.exception.NoDataException; 026import org.apache.commons.math4.legacy.exception.NotPositiveException; 027import org.apache.commons.math4.legacy.exception.NotStrictlyPositiveException; 028import org.apache.commons.math4.legacy.exception.NullArgumentException; 029import org.apache.commons.math4.legacy.exception.NumberIsTooSmallException; 030import org.apache.commons.math4.legacy.exception.OutOfRangeException; 031import org.apache.commons.math4.legacy.exception.util.LocalizedFormats; 032import org.apache.commons.math4.legacy.core.MathArrays; 033 034/** 035 * Basic implementation of {@link FieldMatrix} methods regardless of the underlying storage. 036 * <p>All the methods implemented here use {@link #getEntry(int, int)} to access 037 * matrix elements. Derived class can provide faster implementations. </p> 038 * 039 * @param <T> Type of the field elements. 040 * 041 * @since 2.0 042 */ 043public abstract class AbstractFieldMatrix<T extends FieldElement<T>> 044 implements FieldMatrix<T> { 045 /** Field to which the elements belong. */ 046 private final Field<T> field; 047 048 /** 049 * Constructor for use with Serializable. 050 */ 051 protected AbstractFieldMatrix() { 052 field = null; 053 } 054 055 /** 056 * Creates a matrix with no data. 057 * @param field field to which the elements belong 058 */ 059 protected AbstractFieldMatrix(final Field<T> field) { 060 this.field = field; 061 } 062 063 /** 064 * Create a new {@code FieldMatrix<T>} with the supplied row and column dimensions. 065 * 066 * @param field Field to which the elements belong. 067 * @param rowDimension Number of rows in the new matrix. 068 * @param columnDimension Number of columns in the new matrix. 069 * @throws NotStrictlyPositiveException if row or column dimension is not 070 * positive. 071 */ 072 protected AbstractFieldMatrix(final Field<T> field, 073 final int rowDimension, 074 final int columnDimension) 075 throws NotStrictlyPositiveException { 076 if (rowDimension <= 0) { 077 throw new NotStrictlyPositiveException(LocalizedFormats.DIMENSION, 078 rowDimension); 079 } 080 if (columnDimension <= 0) { 081 throw new NotStrictlyPositiveException(LocalizedFormats.DIMENSION, 082 columnDimension); 083 } 084 this.field = field; 085 } 086 087 /** 088 * Get the elements type from an array. 089 * 090 * @param <T> Type of the field elements. 091 * @param d Data array. 092 * @return the field to which the array elements belong. 093 * @throws NullArgumentException if the array is {@code null}. 094 * @throws NoDataException if the array is empty. 095 */ 096 protected static <T extends FieldElement<T>> Field<T> extractField(final T[][] d) 097 throws NoDataException, NullArgumentException { 098 if (d == null) { 099 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 */ 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 /** {@inheritDoc} */ 127 @Override 128 public Field<T> getField() { 129 return field; 130 } 131 132 /** {@inheritDoc} */ 133 @Override 134 public abstract FieldMatrix<T> createMatrix(int rowDimension, 135 int columnDimension) 136 throws NotStrictlyPositiveException; 137 138 /** {@inheritDoc} */ 139 @Override 140 public abstract FieldMatrix<T> copy(); 141 142 /** {@inheritDoc} */ 143 @Override 144 public FieldMatrix<T> add(FieldMatrix<T> m) 145 throws MatrixDimensionMismatchException { 146 // safety check 147 checkAdd(m); 148 149 final int rowCount = getRowDimension(); 150 final int columnCount = getColumnDimension(); 151 final FieldMatrix<T> out = createMatrix(rowCount, columnCount); 152 for (int row = 0; row < rowCount; ++row) { 153 for (int col = 0; col < columnCount; ++col) { 154 out.setEntry(row, col, getEntry(row, col).add(m.getEntry(row, col))); 155 } 156 } 157 158 return out; 159 } 160 161 /** {@inheritDoc} */ 162 @Override 163 public FieldMatrix<T> subtract(final FieldMatrix<T> m) 164 throws MatrixDimensionMismatchException { 165 // safety check 166 checkAdd(m); 167 168 final int rowCount = getRowDimension(); 169 final int columnCount = getColumnDimension(); 170 final FieldMatrix<T> out = createMatrix(rowCount, columnCount); 171 for (int row = 0; row < rowCount; ++row) { 172 for (int col = 0; col < columnCount; ++col) { 173 out.setEntry(row, col, getEntry(row, col).subtract(m.getEntry(row, col))); 174 } 175 } 176 177 return out; 178 } 179 180 /** {@inheritDoc} */ 181 @Override 182 public FieldMatrix<T> scalarAdd(final T d) { 183 184 final int rowCount = getRowDimension(); 185 final int columnCount = getColumnDimension(); 186 final FieldMatrix<T> out = createMatrix(rowCount, columnCount); 187 for (int row = 0; row < rowCount; ++row) { 188 for (int col = 0; col < columnCount; ++col) { 189 out.setEntry(row, col, getEntry(row, col).add(d)); 190 } 191 } 192 193 return out; 194 } 195 196 /** {@inheritDoc} */ 197 @Override 198 public FieldMatrix<T> scalarMultiply(final T d) { 199 final int rowCount = getRowDimension(); 200 final int columnCount = getColumnDimension(); 201 final FieldMatrix<T> out = createMatrix(rowCount, columnCount); 202 for (int row = 0; row < rowCount; ++row) { 203 for (int col = 0; col < columnCount; ++col) { 204 out.setEntry(row, col, getEntry(row, col).multiply(d)); 205 } 206 } 207 208 return out; 209 } 210 211 /** {@inheritDoc} */ 212 @Override 213 public FieldMatrix<T> multiply(final FieldMatrix<T> m) 214 throws DimensionMismatchException { 215 // safety check 216 checkMultiply(m); 217 218 final int nRows = getRowDimension(); 219 final int nCols = m.getColumnDimension(); 220 final int nSum = getColumnDimension(); 221 final FieldMatrix<T> out = createMatrix(nRows, nCols); 222 for (int row = 0; row < nRows; ++row) { 223 for (int col = 0; col < nCols; ++col) { 224 T sum = field.getZero(); 225 for (int i = 0; i < nSum; ++i) { 226 sum = sum.add(getEntry(row, i).multiply(m.getEntry(i, col))); 227 } 228 out.setEntry(row, col, sum); 229 } 230 } 231 232 return out; 233 } 234 235 /** {@inheritDoc} */ 236 @Override 237 public FieldMatrix<T> preMultiply(final FieldMatrix<T> m) 238 throws DimensionMismatchException { 239 return m.multiply(this); 240 } 241 242 /** {@inheritDoc} */ 243 @Override 244 public FieldMatrix<T> power(final int p) throws NonSquareMatrixException, 245 NotPositiveException { 246 if (p < 0) { 247 throw new NotPositiveException(p); 248 } 249 250 if (!isSquare()) { 251 throw new NonSquareMatrixException(getRowDimension(), getColumnDimension()); 252 } 253 254 if (p == 0) { 255 return MatrixUtils.createFieldIdentityMatrix(this.getField(), this.getRowDimension()); 256 } 257 258 if (p == 1) { 259 return this.copy(); 260 } 261 262 final int power = p - 1; 263 264 /* 265 * Only log_2(p) operations is used by doing as follows: 266 * 5^214 = 5^128 * 5^64 * 5^16 * 5^4 * 5^2 267 * 268 * In general, the same approach is used for A^p. 269 */ 270 271 final char[] binaryRepresentation = Integer.toBinaryString(power) 272 .toCharArray(); 273 final ArrayList<Integer> nonZeroPositions = new ArrayList<>(); 274 275 for (int i = 0; i < binaryRepresentation.length; ++i) { 276 if (binaryRepresentation[i] == '1') { 277 final int pos = binaryRepresentation.length - i - 1; 278 nonZeroPositions.add(pos); 279 } 280 } 281 282 ArrayList<FieldMatrix<T>> results = new ArrayList<>( 283 binaryRepresentation.length); 284 285 results.add(0, this.copy()); 286 287 for (int i = 1; i < binaryRepresentation.length; ++i) { 288 final FieldMatrix<T> s = results.get(i - 1); 289 final FieldMatrix<T> r = s.multiply(s); 290 results.add(i, r); 291 } 292 293 FieldMatrix<T> result = this.copy(); 294 295 for (Integer i : nonZeroPositions) { 296 result = result.multiply(results.get(i)); 297 } 298 299 return result; 300 } 301 302 /** {@inheritDoc} */ 303 @Override 304 public T[][] getData() { 305 final T[][] data = MathArrays.buildArray(field, getRowDimension(), getColumnDimension()); 306 307 for (int i = 0; i < data.length; ++i) { 308 final T[] dataI = data[i]; 309 for (int j = 0; j < dataI.length; ++j) { 310 dataI[j] = getEntry(i, j); 311 } 312 } 313 314 return data; 315 } 316 317 /** {@inheritDoc} */ 318 @Override 319 public FieldMatrix<T> getSubMatrix(final int startRow, final int endRow, 320 final int startColumn, final int endColumn) 321 throws NumberIsTooSmallException, OutOfRangeException { 322 checkSubMatrixIndex(startRow, endRow, startColumn, endColumn); 323 324 final FieldMatrix<T> subMatrix = 325 createMatrix(endRow - startRow + 1, endColumn - startColumn + 1); 326 for (int i = startRow; i <= endRow; ++i) { 327 for (int j = startColumn; j <= endColumn; ++j) { 328 subMatrix.setEntry(i - startRow, j - startColumn, getEntry(i, j)); 329 } 330 } 331 332 return subMatrix; 333 } 334 335 /** {@inheritDoc} */ 336 @Override 337 public FieldMatrix<T> getSubMatrix(final int[] selectedRows, 338 final int[] selectedColumns) 339 throws NoDataException, NullArgumentException, OutOfRangeException { 340 341 // safety checks 342 checkSubMatrixIndex(selectedRows, selectedColumns); 343 344 // copy entries 345 final FieldMatrix<T> subMatrix = 346 createMatrix(selectedRows.length, selectedColumns.length); 347 subMatrix.walkInOptimizedOrder(new DefaultFieldMatrixChangingVisitor<T>(field.getZero()) { 348 349 /** {@inheritDoc} */ 350 @Override 351 public T visit(final int row, final int column, final T value) { 352 return getEntry(selectedRows[row], selectedColumns[column]); 353 } 354 }); 355 356 return subMatrix; 357 } 358 359 /** {@inheritDoc} */ 360 @Override 361 public void copySubMatrix(final int startRow, final int endRow, 362 final int startColumn, final int endColumn, 363 final T[][] destination) 364 throws MatrixDimensionMismatchException, NumberIsTooSmallException, 365 OutOfRangeException{ 366 // safety checks 367 checkSubMatrixIndex(startRow, endRow, startColumn, endColumn); 368 final int rowsCount = endRow + 1 - startRow; 369 final int columnsCount = endColumn + 1 - startColumn; 370 if (destination.length < rowsCount || destination[0].length < columnsCount) { 371 throw new MatrixDimensionMismatchException(destination.length, 372 destination[0].length, 373 rowsCount, 374 columnsCount); 375 } 376 377 // copy entries 378 walkInOptimizedOrder(new DefaultFieldMatrixPreservingVisitor<T>(field.getZero()) { 379 380 /** Initial row index. */ 381 private int startRow; 382 383 /** Initial column index. */ 384 private int startColumn; 385 386 /** {@inheritDoc} */ 387 @Override 388 public void start(final int rows, final int columns, 389 final int startRow, final int endRow, 390 final int startColumn, final int endColumn) { 391 this.startRow = startRow; 392 this.startColumn = startColumn; 393 } 394 395 /** {@inheritDoc} */ 396 @Override 397 public void visit(final int row, final int column, final T value) { 398 destination[row - startRow][column - startColumn] = value; 399 } 400 }, startRow, endRow, startColumn, endColumn); 401 } 402 403 /** {@inheritDoc} */ 404 @Override 405 public void copySubMatrix(int[] selectedRows, int[] selectedColumns, T[][] destination) 406 throws MatrixDimensionMismatchException, NoDataException, 407 NullArgumentException, OutOfRangeException { 408 // safety checks 409 checkSubMatrixIndex(selectedRows, selectedColumns); 410 if (destination.length < selectedRows.length || 411 destination[0].length < selectedColumns.length) { 412 throw new MatrixDimensionMismatchException(destination.length, 413 destination[0].length, 414 selectedRows.length, 415 selectedColumns.length); 416 } 417 418 // copy entries 419 for (int i = 0; i < selectedRows.length; i++) { 420 final T[] destinationI = destination[i]; 421 for (int j = 0; j < selectedColumns.length; j++) { 422 destinationI[j] = getEntry(selectedRows[i], selectedColumns[j]); 423 } 424 } 425 } 426 427 /** {@inheritDoc} */ 428 @Override 429 public void setSubMatrix(final T[][] subMatrix, final int row, 430 final int column) 431 throws DimensionMismatchException, OutOfRangeException, 432 NoDataException, NullArgumentException { 433 if (subMatrix == null) { 434 throw new NullArgumentException(); 435 } 436 final int nRows = subMatrix.length; 437 if (nRows == 0) { 438 throw new NoDataException(LocalizedFormats.AT_LEAST_ONE_ROW); 439 } 440 441 final int nCols = subMatrix[0].length; 442 if (nCols == 0) { 443 throw new NoDataException(LocalizedFormats.AT_LEAST_ONE_COLUMN); 444 } 445 446 for (int r = 1; r < nRows; ++r) { 447 if (subMatrix[r].length != nCols) { 448 throw new DimensionMismatchException(nCols, subMatrix[r].length); 449 } 450 } 451 452 checkRowIndex(row); 453 checkColumnIndex(column); 454 checkRowIndex(nRows + row - 1); 455 checkColumnIndex(nCols + column - 1); 456 457 for (int i = 0; i < nRows; ++i) { 458 for (int j = 0; j < nCols; ++j) { 459 setEntry(row + i, column + j, subMatrix[i][j]); 460 } 461 } 462 } 463 464 /** {@inheritDoc} */ 465 @Override 466 public FieldMatrix<T> getRowMatrix(final int row) throws OutOfRangeException { 467 checkRowIndex(row); 468 final int nCols = getColumnDimension(); 469 final FieldMatrix<T> out = createMatrix(1, nCols); 470 for (int i = 0; i < nCols; ++i) { 471 out.setEntry(0, i, getEntry(row, i)); 472 } 473 474 return out; 475 } 476 477 /** {@inheritDoc} */ 478 @Override 479 public void setRowMatrix(final int row, final FieldMatrix<T> matrix) 480 throws OutOfRangeException, MatrixDimensionMismatchException { 481 checkRowIndex(row); 482 final int nCols = getColumnDimension(); 483 if (matrix.getRowDimension() != 1 || 484 matrix.getColumnDimension() != nCols) { 485 throw new MatrixDimensionMismatchException(matrix.getRowDimension(), 486 matrix.getColumnDimension(), 487 1, nCols); 488 } 489 for (int i = 0; i < nCols; ++i) { 490 setEntry(row, i, matrix.getEntry(0, i)); 491 } 492 } 493 494 /** {@inheritDoc} */ 495 @Override 496 public FieldMatrix<T> getColumnMatrix(final int column) 497 throws OutOfRangeException { 498 499 checkColumnIndex(column); 500 final int nRows = getRowDimension(); 501 final FieldMatrix<T> out = createMatrix(nRows, 1); 502 for (int i = 0; i < nRows; ++i) { 503 out.setEntry(i, 0, getEntry(i, column)); 504 } 505 506 return out; 507 } 508 509 /** {@inheritDoc} */ 510 @Override 511 public void setColumnMatrix(final int column, final FieldMatrix<T> matrix) 512 throws OutOfRangeException, MatrixDimensionMismatchException { 513 checkColumnIndex(column); 514 final int nRows = getRowDimension(); 515 if (matrix.getRowDimension() != nRows || 516 matrix.getColumnDimension() != 1) { 517 throw new MatrixDimensionMismatchException(matrix.getRowDimension(), 518 matrix.getColumnDimension(), 519 nRows, 1); 520 } 521 for (int i = 0; i < nRows; ++i) { 522 setEntry(i, column, matrix.getEntry(i, 0)); 523 } 524 } 525 526 /** {@inheritDoc} */ 527 @Override 528 public FieldVector<T> getRowVector(final int row) 529 throws OutOfRangeException { 530 return new ArrayFieldVector<>(field, getRow(row), false); 531 } 532 533 /** {@inheritDoc} */ 534 @Override 535 public void setRowVector(final int row, final FieldVector<T> vector) 536 throws OutOfRangeException, MatrixDimensionMismatchException { 537 checkRowIndex(row); 538 final int nCols = getColumnDimension(); 539 if (vector.getDimension() != nCols) { 540 throw new MatrixDimensionMismatchException(1, vector.getDimension(), 541 1, nCols); 542 } 543 for (int i = 0; i < nCols; ++i) { 544 setEntry(row, i, vector.getEntry(i)); 545 } 546 } 547 548 /** {@inheritDoc} */ 549 @Override 550 public FieldVector<T> getColumnVector(final int column) 551 throws OutOfRangeException { 552 return new ArrayFieldVector<>(field, getColumn(column), false); 553 } 554 555 /** {@inheritDoc} */ 556 @Override 557 public void setColumnVector(final int column, final FieldVector<T> vector) 558 throws OutOfRangeException, MatrixDimensionMismatchException { 559 560 checkColumnIndex(column); 561 final int nRows = getRowDimension(); 562 if (vector.getDimension() != nRows) { 563 throw new MatrixDimensionMismatchException(vector.getDimension(), 1, 564 nRows, 1); 565 } 566 for (int i = 0; i < nRows; ++i) { 567 setEntry(i, column, vector.getEntry(i)); 568 } 569 } 570 571 /** {@inheritDoc} */ 572 @Override 573 public T[] getRow(final int row) throws OutOfRangeException { 574 checkRowIndex(row); 575 final int nCols = getColumnDimension(); 576 final T[] out = MathArrays.buildArray(field, nCols); 577 for (int i = 0; i < nCols; ++i) { 578 out[i] = getEntry(row, i); 579 } 580 581 return out; 582 } 583 584 /** {@inheritDoc} */ 585 @Override 586 public void setRow(final int row, final T[] array) 587 throws OutOfRangeException, MatrixDimensionMismatchException { 588 checkRowIndex(row); 589 final int nCols = getColumnDimension(); 590 if (array.length != nCols) { 591 throw new MatrixDimensionMismatchException(1, array.length, 1, nCols); 592 } 593 for (int i = 0; i < nCols; ++i) { 594 setEntry(row, i, array[i]); 595 } 596 } 597 598 /** {@inheritDoc} */ 599 @Override 600 public T[] getColumn(final int column) throws OutOfRangeException { 601 checkColumnIndex(column); 602 final int nRows = getRowDimension(); 603 final T[] out = MathArrays.buildArray(field, nRows); 604 for (int i = 0; i < nRows; ++i) { 605 out[i] = getEntry(i, column); 606 } 607 608 return out; 609 } 610 611 /** {@inheritDoc} */ 612 @Override 613 public void setColumn(final int column, final T[] array) 614 throws OutOfRangeException, MatrixDimensionMismatchException { 615 checkColumnIndex(column); 616 final int nRows = getRowDimension(); 617 if (array.length != nRows) { 618 throw new MatrixDimensionMismatchException(array.length, 1, nRows, 1); 619 } 620 for (int i = 0; i < nRows; ++i) { 621 setEntry(i, column, array[i]); 622 } 623 } 624 625 /** {@inheritDoc} */ 626 @Override 627 public abstract T getEntry(int row, int column) throws OutOfRangeException; 628 629 /** {@inheritDoc} */ 630 @Override 631 public abstract void setEntry(int row, int column, T value) throws OutOfRangeException; 632 633 /** {@inheritDoc} */ 634 @Override 635 public abstract void addToEntry(int row, int column, T increment) throws OutOfRangeException; 636 637 /** {@inheritDoc} */ 638 @Override 639 public abstract void multiplyEntry(int row, int column, T factor) throws OutOfRangeException; 640 641 /** {@inheritDoc} */ 642 @Override 643 public FieldMatrix<T> transpose() { 644 final int nRows = getRowDimension(); 645 final int nCols = getColumnDimension(); 646 final FieldMatrix<T> out = createMatrix(nCols, nRows); 647 walkInOptimizedOrder(new DefaultFieldMatrixPreservingVisitor<T>(field.getZero()) { 648 /** {@inheritDoc} */ 649 @Override 650 public void visit(final int row, final int column, final T value) { 651 out.setEntry(column, row, value); 652 } 653 }); 654 655 return out; 656 } 657 658 /** {@inheritDoc} */ 659 @Override 660 public T getTrace() throws NonSquareMatrixException { 661 final int nRows = getRowDimension(); 662 final int nCols = getColumnDimension(); 663 if (nRows != nCols) { 664 throw new NonSquareMatrixException(nRows, nCols); 665 } 666 T trace = field.getZero(); 667 for (int i = 0; i < nRows; ++i) { 668 trace = trace.add(getEntry(i, i)); 669 } 670 return trace; 671 } 672 673 /** {@inheritDoc} */ 674 @Override 675 public T[] operate(final T[] v) throws DimensionMismatchException { 676 677 final int nRows = getRowDimension(); 678 final int nCols = getColumnDimension(); 679 if (v.length != nCols) { 680 throw new DimensionMismatchException(v.length, nCols); 681 } 682 683 final T[] out = MathArrays.buildArray(field, nRows); 684 for (int row = 0; row < nRows; ++row) { 685 T sum = field.getZero(); 686 for (int i = 0; i < nCols; ++i) { 687 sum = sum.add(getEntry(row, i).multiply(v[i])); 688 } 689 out[row] = sum; 690 } 691 692 return out; 693 } 694 695 /** {@inheritDoc} */ 696 @Override 697 public FieldVector<T> operate(final FieldVector<T> v) 698 throws DimensionMismatchException { 699 if (v instanceof ArrayFieldVector) { 700 return new ArrayFieldVector<>(field, operate(((ArrayFieldVector<T>) v).getDataRef()), false); 701 } 702 703 final int nRows = getRowDimension(); 704 final int nCols = getColumnDimension(); 705 if (v.getDimension() != nCols) { 706 throw new DimensionMismatchException(v.getDimension(), 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.getEntry(i))); 714 } 715 out[row] = sum; 716 } 717 718 return new ArrayFieldVector<>(field, out, false); 719 } 720 721 /** {@inheritDoc} */ 722 @Override 723 public T[] preMultiply(final T[] v) throws DimensionMismatchException { 724 725 final int nRows = getRowDimension(); 726 final int nCols = getColumnDimension(); 727 if (v.length != nRows) { 728 throw new DimensionMismatchException(v.length, nRows); 729 } 730 731 final T[] out = MathArrays.buildArray(field, nCols); 732 for (int col = 0; col < nCols; ++col) { 733 T sum = field.getZero(); 734 for (int i = 0; i < nRows; ++i) { 735 sum = sum.add(getEntry(i, col).multiply(v[i])); 736 } 737 out[col] = sum; 738 } 739 740 return out; 741 } 742 743 /** {@inheritDoc} */ 744 @Override 745 public FieldVector<T> preMultiply(final FieldVector<T> v) 746 throws DimensionMismatchException { 747 if (v instanceof ArrayFieldVector) { 748 return new ArrayFieldVector<>(field, preMultiply(((ArrayFieldVector<T>) v).getDataRef()), false); 749 } 750 751 final int nRows = getRowDimension(); 752 final int nCols = getColumnDimension(); 753 if (v.getDimension() != nRows) { 754 throw new DimensionMismatchException(v.getDimension(), nRows); 755 } 756 757 final T[] out = MathArrays.buildArray(field, nCols); 758 for (int col = 0; col < nCols; ++col) { 759 T sum = field.getZero(); 760 for (int i = 0; i < nRows; ++i) { 761 sum = sum.add(getEntry(i, col).multiply(v.getEntry(i))); 762 } 763 out[col] = sum; 764 } 765 766 return new ArrayFieldVector<>(field, out, false); 767 } 768 769 /** {@inheritDoc} */ 770 @Override 771 public T walkInRowOrder(final FieldMatrixChangingVisitor<T> visitor) { 772 final int rows = getRowDimension(); 773 final int columns = getColumnDimension(); 774 visitor.start(rows, columns, 0, rows - 1, 0, columns - 1); 775 for (int row = 0; row < rows; ++row) { 776 for (int column = 0; column < columns; ++column) { 777 final T oldValue = getEntry(row, column); 778 final T newValue = visitor.visit(row, column, oldValue); 779 setEntry(row, column, newValue); 780 } 781 } 782 return visitor.end(); 783 } 784 785 /** {@inheritDoc} */ 786 @Override 787 public T walkInRowOrder(final FieldMatrixPreservingVisitor<T> visitor) { 788 final int rows = getRowDimension(); 789 final int columns = getColumnDimension(); 790 visitor.start(rows, columns, 0, rows - 1, 0, columns - 1); 791 for (int row = 0; row < rows; ++row) { 792 for (int column = 0; column < columns; ++column) { 793 visitor.visit(row, column, getEntry(row, column)); 794 } 795 } 796 return visitor.end(); 797 } 798 799 /** {@inheritDoc} */ 800 @Override 801 public T walkInRowOrder(final FieldMatrixChangingVisitor<T> visitor, 802 final int startRow, final int endRow, 803 final int startColumn, final int endColumn) 804 throws NumberIsTooSmallException, OutOfRangeException { 805 checkSubMatrixIndex(startRow, endRow, startColumn, endColumn); 806 visitor.start(getRowDimension(), getColumnDimension(), 807 startRow, endRow, startColumn, endColumn); 808 for (int row = startRow; row <= endRow; ++row) { 809 for (int column = startColumn; column <= endColumn; ++column) { 810 final T oldValue = getEntry(row, column); 811 final T newValue = visitor.visit(row, column, oldValue); 812 setEntry(row, column, newValue); 813 } 814 } 815 return visitor.end(); 816 } 817 818 /** {@inheritDoc} */ 819 @Override 820 public T walkInRowOrder(final FieldMatrixPreservingVisitor<T> visitor, 821 final int startRow, final int endRow, 822 final int startColumn, final int endColumn) 823 throws NumberIsTooSmallException, OutOfRangeException { 824 checkSubMatrixIndex(startRow, endRow, startColumn, endColumn); 825 visitor.start(getRowDimension(), getColumnDimension(), 826 startRow, endRow, startColumn, endColumn); 827 for (int row = startRow; row <= endRow; ++row) { 828 for (int column = startColumn; column <= endColumn; ++column) { 829 visitor.visit(row, column, getEntry(row, column)); 830 } 831 } 832 return visitor.end(); 833 } 834 835 /** {@inheritDoc} */ 836 @Override 837 public T walkInColumnOrder(final FieldMatrixChangingVisitor<T> visitor) { 838 final int rows = getRowDimension(); 839 final int columns = getColumnDimension(); 840 visitor.start(rows, columns, 0, rows - 1, 0, columns - 1); 841 for (int column = 0; column < columns; ++column) { 842 for (int row = 0; row < rows; ++row) { 843 final T oldValue = getEntry(row, column); 844 final T newValue = visitor.visit(row, column, oldValue); 845 setEntry(row, column, newValue); 846 } 847 } 848 return visitor.end(); 849 } 850 851 /** {@inheritDoc} */ 852 @Override 853 public T walkInColumnOrder(final FieldMatrixPreservingVisitor<T> visitor) { 854 final int rows = getRowDimension(); 855 final int columns = getColumnDimension(); 856 visitor.start(rows, columns, 0, rows - 1, 0, columns - 1); 857 for (int column = 0; column < columns; ++column) { 858 for (int row = 0; row < rows; ++row) { 859 visitor.visit(row, column, getEntry(row, column)); 860 } 861 } 862 return visitor.end(); 863 } 864 865 /** {@inheritDoc} */ 866 @Override 867 public T walkInColumnOrder(final FieldMatrixChangingVisitor<T> visitor, 868 final int startRow, final int endRow, 869 final int startColumn, final int endColumn) 870 throws NumberIsTooSmallException, OutOfRangeException { 871 checkSubMatrixIndex(startRow, endRow, startColumn, endColumn); 872 visitor.start(getRowDimension(), getColumnDimension(), 873 startRow, endRow, startColumn, endColumn); 874 for (int column = startColumn; column <= endColumn; ++column) { 875 for (int row = startRow; row <= endRow; ++row) { 876 final T oldValue = getEntry(row, column); 877 final T newValue = visitor.visit(row, column, oldValue); 878 setEntry(row, column, newValue); 879 } 880 } 881 return visitor.end(); 882 } 883 884 /** {@inheritDoc} */ 885 @Override 886 public T walkInColumnOrder(final FieldMatrixPreservingVisitor<T> visitor, 887 final int startRow, final int endRow, 888 final int startColumn, final int endColumn) 889 throws NumberIsTooSmallException, OutOfRangeException{ 890 checkSubMatrixIndex(startRow, endRow, startColumn, endColumn); 891 visitor.start(getRowDimension(), getColumnDimension(), 892 startRow, endRow, startColumn, endColumn); 893 for (int column = startColumn; column <= endColumn; ++column) { 894 for (int row = startRow; row <= endRow; ++row) { 895 visitor.visit(row, column, getEntry(row, column)); 896 } 897 } 898 return visitor.end(); 899 } 900 901 /** {@inheritDoc} */ 902 @Override 903 public T walkInOptimizedOrder(final FieldMatrixChangingVisitor<T> visitor) { 904 return walkInRowOrder(visitor); 905 } 906 907 /** {@inheritDoc} */ 908 @Override 909 public T walkInOptimizedOrder(final FieldMatrixPreservingVisitor<T> visitor) { 910 return walkInRowOrder(visitor); 911 } 912 913 /** {@inheritDoc} */ 914 @Override 915 public T walkInOptimizedOrder(final FieldMatrixChangingVisitor<T> visitor, 916 final int startRow, final int endRow, 917 final int startColumn, final int endColumn) 918 throws NumberIsTooSmallException, OutOfRangeException { 919 return walkInRowOrder(visitor, startRow, endRow, startColumn, endColumn); 920 } 921 922 /** {@inheritDoc} */ 923 @Override 924 public T walkInOptimizedOrder(final FieldMatrixPreservingVisitor<T> visitor, 925 final int startRow, final int endRow, 926 final int startColumn, final int endColumn) 927 throws NumberIsTooSmallException, OutOfRangeException { 928 return walkInRowOrder(visitor, startRow, endRow, startColumn, endColumn); 929 } 930 931 /** 932 * Get a string representation for this matrix. 933 * @return a string representation for this matrix 934 */ 935 @Override 936 public String toString() { 937 final int nRows = getRowDimension(); 938 final int nCols = getColumnDimension(); 939 final StringBuffer res = new StringBuffer(); 940 String fullClassName = getClass().getName(); 941 String shortClassName = fullClassName.substring(fullClassName.lastIndexOf('.') + 1); 942 res.append(shortClassName).append("{"); 943 944 for (int i = 0; i < nRows; ++i) { 945 if (i > 0) { 946 res.append(","); 947 } 948 res.append("{"); 949 for (int j = 0; j < nCols; ++j) { 950 if (j > 0) { 951 res.append(","); 952 } 953 res.append(getEntry(i, j)); 954 } 955 res.append("}"); 956 } 957 958 res.append("}"); 959 return res.toString(); 960 } 961 962 /** 963 * Returns true iff <code>object</code> is a 964 * <code>FieldMatrix</code> instance with the same dimensions as this 965 * and all corresponding matrix entries are equal. 966 * 967 * @param object the object to test equality against. 968 * @return true if object equals this 969 */ 970 @Override 971 public boolean equals(final Object object) { 972 if (object == this ) { 973 return true; 974 } 975 if (!(object instanceof FieldMatrix<?>)) { 976 return false; 977 } 978 FieldMatrix<?> m = (FieldMatrix<?>) object; 979 final int nRows = getRowDimension(); 980 final int nCols = getColumnDimension(); 981 if (m.getColumnDimension() != nCols || m.getRowDimension() != nRows) { 982 return false; 983 } 984 for (int row = 0; row < nRows; ++row) { 985 for (int col = 0; col < nCols; ++col) { 986 if (!getEntry(row, col).equals(m.getEntry(row, col))) { 987 return false; 988 } 989 } 990 } 991 return true; 992 } 993 994 /** 995 * Computes a hash code for the matrix. 996 * 997 * @return hash code for matrix 998 */ 999 @Override 1000 public int hashCode() { 1001 int ret = 322562; 1002 final int nRows = getRowDimension(); 1003 final int nCols = getColumnDimension(); 1004 ret = ret * 31 + nRows; 1005 ret = ret * 31 + nCols; 1006 for (int row = 0; row < nRows; ++row) { 1007 for (int col = 0; col < nCols; ++col) { 1008 ret = ret * 31 + (11 * (row+1) + 17 * (col+1)) * getEntry(row, col).hashCode(); 1009 } 1010 } 1011 return ret; 1012 } 1013 1014 /** 1015 * Check if a row index is valid. 1016 * 1017 * @param row Row index to check. 1018 * @throws OutOfRangeException if {@code index} is not valid. 1019 */ 1020 protected void checkRowIndex(final int row) throws OutOfRangeException { 1021 if (row < 0 || row >= getRowDimension()) { 1022 throw new OutOfRangeException(LocalizedFormats.ROW_INDEX, 1023 row, 0, getRowDimension() - 1); 1024 } 1025 } 1026 1027 /** 1028 * Check if a column index is valid. 1029 * 1030 * @param column Column index to check. 1031 * @throws OutOfRangeException if {@code index} is not valid. 1032 */ 1033 protected void checkColumnIndex(final int column) 1034 throws OutOfRangeException { 1035 if (column < 0 || column >= getColumnDimension()) { 1036 throw new OutOfRangeException(LocalizedFormats.COLUMN_INDEX, 1037 column, 0, getColumnDimension() - 1); 1038 } 1039 } 1040 1041 /** 1042 * Check if submatrix ranges indices are valid. 1043 * Rows and columns are indicated counting from 0 to n-1. 1044 * 1045 * @param startRow Initial row index. 1046 * @param endRow Final row index. 1047 * @param startColumn Initial column index. 1048 * @param endColumn Final column index. 1049 * @throws OutOfRangeException if the indices are not valid. 1050 * @throws NumberIsTooSmallException if {@code endRow < startRow} or 1051 * {@code endColumn < startColumn}. 1052 */ 1053 protected void checkSubMatrixIndex(final int startRow, final int endRow, 1054 final int startColumn, final int endColumn) 1055 throws NumberIsTooSmallException, OutOfRangeException { 1056 checkRowIndex(startRow); 1057 checkRowIndex(endRow); 1058 if (endRow < startRow) { 1059 throw new NumberIsTooSmallException(LocalizedFormats.INITIAL_ROW_AFTER_FINAL_ROW, 1060 endRow, startRow, true); 1061 } 1062 1063 checkColumnIndex(startColumn); 1064 checkColumnIndex(endColumn); 1065 if (endColumn < startColumn) { 1066 throw new NumberIsTooSmallException(LocalizedFormats.INITIAL_COLUMN_AFTER_FINAL_COLUMN, 1067 endColumn, startColumn, true); 1068 } 1069 } 1070 1071 /** 1072 * Check if submatrix ranges indices are valid. 1073 * Rows and columns are indicated counting from 0 to n-1. 1074 * 1075 * @param selectedRows Array of row indices. 1076 * @param selectedColumns Array of column indices. 1077 * @throws NullArgumentException if the arrays are {@code null}. 1078 * @throws NoDataException if the arrays have zero length. 1079 * @throws OutOfRangeException if row or column selections are not valid. 1080 */ 1081 protected void checkSubMatrixIndex(final int[] selectedRows, final int[] selectedColumns) 1082 throws NoDataException, NullArgumentException, OutOfRangeException { 1083 if (selectedRows == null || 1084 selectedColumns == null) { 1085 throw new NullArgumentException(); 1086 } 1087 if (selectedRows.length == 0 || 1088 selectedColumns.length == 0) { 1089 throw new NoDataException(); 1090 } 1091 1092 for (final int row : selectedRows) { 1093 checkRowIndex(row); 1094 } 1095 for (final int column : selectedColumns) { 1096 checkColumnIndex(column); 1097 } 1098 } 1099}