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