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