001/* A library for mathematical operations on matrices of doubles. 002 003 This file was automatically generated with a preprocessor, so that 004 similar matrix operations are supported on ints, longs, floats, and doubles. 005 006 Copyright (c) 1998-2014 The Regents of the University of California. 007 All rights reserved. 008 009 Permission is hereby granted, without written agreement and without 010 license or royalty fees, to use, copy, modify, and distribute this 011 software and its documentation for any purpose, provided that the above 012 copyright notice and the following two paragraphs appear in all copies 013 of this software. 014 015 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY 016 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 017 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF 018 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF 019 SUCH DAMAGE. 020 021 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, 022 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 023 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE 024 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF 025 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, 026 ENHANCEMENTS, OR MODIFICATIONS. 027 028 PT_COPYRIGHT_VERSION_2 029 COPYRIGHTENDKEY 030 031 */ 032package ptolemy.math; 033 034/////////////////////////////////////////////////////////////////// 035//// DoubleMatrixMath 036 037/** 038 This class provides a library for mathematical operations on 039 matrices of doubles. 040 All calls expect matrix arguments to be non-null. In addition, all 041 rows of the matrix are expected to have the same number of columns. 042 <p> 043 Some algorithms are from: 044 <p> 045 [1] Embree, Paul M. and Bruce Kimble. "C Language Algorithms for Digital 046 Signal Processing," Prentice Hall, Englewood Cliffs, NJ, 1991. 047 048 @author Jeff Tsay 049 @version $Id$ 050 @since Ptolemy II 1.0 051 @Pt.ProposedRating Yellow (ctsay) 052 @Pt.AcceptedRating Yellow (ctsay) 053 */ 054public class DoubleMatrixMath { 055 // private constructor prevents construction of this class. 056 private DoubleMatrixMath() { 057 } 058 059 /////////////////////////////////////////////////////////////////// 060 //// public methods //// 061 062 /** Return a new matrix that is constructed from the argument by 063 * adding the second argument to every element. 064 * @param matrix A matrix of doubles. 065 * @param z The double number to add. 066 * @return A new matrix of doubles. 067 */ 068 public static final double[][] add(double[][] matrix, double z) { 069 double[][] returnValue = new double[_rows(matrix)][_columns(matrix)]; 070 071 for (int i = 0; i < _rows(matrix); i++) { 072 for (int j = 0; j < _columns(matrix); j++) { 073 returnValue[i][j] = matrix[i][j] + z; 074 } 075 } 076 077 return returnValue; 078 } 079 080 /** Return a new matrix that is constructed from the argument by 081 * adding the second matrix to the first one. If the two 082 * matrices are not the same size, throw an 083 * IllegalArgumentException. 084 * 085 * @param matrix1 The first matrix of doubles. 086 * @param matrix2 The second matrix of doubles. 087 * @return A new matrix of doubles. 088 */ 089 public static final double[][] add(final double[][] matrix1, 090 final double[][] matrix2) { 091 _checkSameDimension("add", matrix1, matrix2); 092 093 double[][] returnValue = new double[_rows(matrix1)][_columns(matrix1)]; 094 095 for (int i = 0; i < _rows(matrix1); i++) { 096 for (int j = 0; j < _columns(matrix1); j++) { 097 returnValue[i][j] = matrix1[i][j] + matrix2[i][j]; 098 } 099 } 100 101 return returnValue; 102 } 103 104 /** Return a new matrix that is a copy of the matrix argument. 105 * @param matrix A matrix of doubles. 106 * @return A new matrix of doubles. 107 */ 108 public static final double[][] allocCopy(final double[][] matrix) { 109 return crop(matrix, 0, 0, _rows(matrix), _columns(matrix)); 110 } 111 112 /** Return a new array that is formed by applying an instance of a 113 * DoubleBinaryOperation to each element in the input matrix, 114 * using z as the left operand in all cases and the matrix elements 115 * as the right operands (op.operate(z, matrix[i][j])). 116 */ 117 public static final double[][] applyBinaryOperation( 118 DoubleBinaryOperation op, final double z, final double[][] matrix) { 119 int rows = _rows(matrix); 120 int columns = _columns(matrix); 121 122 double[][] returnValue = new double[rows][columns]; 123 124 for (int i = 0; i < rows; i++) { 125 for (int j = 0; j < columns; j++) { 126 returnValue[i][j] = op.operate(z, matrix[i][j]); 127 } 128 } 129 130 return returnValue; 131 } 132 133 /** Return a new array that is formed by applying an instance of a 134 * DoubleBinaryOperation to each element in the input matrix, 135 * using the matrix elements as the left operands and z as the right 136 * operand in all cases (op.operate(matrix[i][j], z)). 137 */ 138 public static final double[][] applyBinaryOperation( 139 DoubleBinaryOperation op, final double[][] matrix, final double z) { 140 int rows = _rows(matrix); 141 int columns = _columns(matrix); 142 143 double[][] returnValue = new double[rows][columns]; 144 145 for (int i = 0; i < rows; i++) { 146 for (int j = 0; j < columns; j++) { 147 returnValue[i][j] = op.operate(matrix[i][j], z); 148 } 149 } 150 151 return returnValue; 152 } 153 154 /** Return a new array that is formed by applying an instance of a 155 * DoubleBinaryOperation to the two matrices, element by element, 156 * using the elements of the first matrix as the left operands 157 * and the elements of the second matrix as the right operands. 158 * (op.operate(matrix1[i][j], matrix2[i][j])). If the matrices 159 * are not the same size, throw an IllegalArgumentException. 160 */ 161 public static final double[][] applyBinaryOperation( 162 DoubleBinaryOperation op, final double[][] matrix1, 163 final double[][] matrix2) { 164 int rows = _rows(matrix1); 165 int columns = _columns(matrix1); 166 167 _checkSameDimension("applyBinaryOperation", matrix1, matrix2); 168 169 double[][] returnValue = new double[rows][columns]; 170 171 for (int i = 0; i < rows; i++) { 172 for (int j = 0; j < columns; j++) { 173 returnValue[i][j] = op.operate(matrix1[i][j], matrix2[i][j]); 174 } 175 } 176 177 return returnValue; 178 } 179 180 /** Return a new array that is formed by applying an instance of a 181 * DoubleUnaryOperation to each element in the input matrix 182 * (op.operate(matrix[i][j])). 183 */ 184 public static final double[][] applyUnaryOperation( 185 final DoubleUnaryOperation op, final double[][] matrix) { 186 int rows = _rows(matrix); 187 int columns = _columns(matrix); 188 189 double[][] returnValue = new double[rows][columns]; 190 191 for (int i = 0; i < rows; i++) { 192 for (int j = 0; j < columns; j++) { 193 returnValue[i][j] = op.operate(matrix[i][j]); 194 } 195 } 196 197 return returnValue; 198 } 199 200 /** Return a new matrix that is a sub-matrix of the input 201 * matrix argument. The row and column from which to start 202 * and the number of rows and columns to span are specified. 203 * @param matrix A matrix of doubles. 204 * @param rowStart An int specifying which row to start on. 205 * @param colStart An int specifying which column to start on. 206 * @param rowSpan An int specifying how many rows to copy. 207 * @param colSpan An int specifying how many columns to copy. 208 */ 209 public static final double[][] crop(final double[][] matrix, 210 final int rowStart, final int colStart, final int rowSpan, 211 final int colSpan) { 212 double[][] returnValue = new double[rowSpan][colSpan]; 213 214 for (int i = 0; i < rowSpan; i++) { 215 System.arraycopy(matrix[rowStart + i], colStart, returnValue[i], 0, 216 colSpan); 217 } 218 219 return returnValue; 220 } 221 222 /** Return the determinant of a square matrix. 223 * If the matrix is not square, throw an IllegalArgumentException. 224 * This algorithm uses LU decomposition, and is taken from [1] 225 */ 226 public static final double determinant(final double[][] matrix) { 227 _checkSquare("determinant", matrix); 228 229 double[][] a; 230 double det = 1.0; 231 int n = _rows(matrix); 232 233 a = allocCopy(matrix); 234 235 for (int pivot = 0; pivot < n - 1; pivot++) { 236 // find the biggest absolute pivot 237 double big = Math.abs(a[pivot][pivot]); 238 int swapRow = 0; // initialize for no swap 239 240 for (int row = pivot + 1; row < n; row++) { 241 double absElement = Math.abs(a[row][pivot]); 242 243 if (absElement > big) { 244 swapRow = row; 245 big = absElement; 246 } 247 } 248 249 // unless swapRow is still zero we must swap two rows 250 if (swapRow != 0) { 251 double[] aPtr = a[pivot]; 252 a[pivot] = a[swapRow]; 253 a[swapRow] = aPtr; 254 255 // change sign of determinant because of swap 256 det *= -a[pivot][pivot]; 257 } else { 258 // calculate the determinant by the product of the pivots 259 det *= a[pivot][pivot]; 260 } 261 262 // if almost singular matrix, give up now 263 // If almost singular matrix, give up now. 264 if (Math.abs(det) <= Complex.EPSILON) { 265 return det; 266 } 267 268 double pivotInverse = 1.0 / a[pivot][pivot]; 269 270 for (int col = pivot + 1; col < n; col++) { 271 a[pivot][col] *= pivotInverse; 272 } 273 274 for (int row = pivot + 1; row < n; row++) { 275 double temp = a[row][pivot]; 276 277 for (int col = pivot + 1; col < n; col++) { 278 a[row][col] -= a[pivot][col] * temp; 279 } 280 } 281 } 282 283 // Last pivot, no reduction required. 284 det *= a[n - 1][n - 1]; 285 286 return det; 287 } 288 289 /** Return a new matrix that is constructed by placing the 290 * elements of the input array on the diagonal of the square 291 * matrix, starting from the top left corner down to the bottom 292 * right corner. All other elements are zero. The size of of the 293 * matrix is n x n, where n is the length of the input array. 294 */ 295 public static final double[][] diag(final double[] array) { 296 int n = array.length; 297 298 double[][] returnValue = new double[n][n]; 299 300 // Assume the matrix is zero-filled. 301 for (int i = 0; i < n; i++) { 302 returnValue[i][i] = array[i]; 303 } 304 305 return returnValue; 306 } 307 308 /** Return a new matrix that is constructed from the argument by 309 * dividing the second argument to every element. 310 * @param matrix A matrix of doubles. 311 * @param z The double number to divide. 312 * @return A new matrix of doubles. 313 */ 314 public static final double[][] divide(double[][] matrix, double z) { 315 double[][] returnValue = new double[_rows(matrix)][_columns(matrix)]; 316 317 for (int i = 0; i < _rows(matrix); i++) { 318 for (int j = 0; j < _columns(matrix); j++) { 319 returnValue[i][j] = matrix[i][j] / z; 320 } 321 } 322 323 return returnValue; 324 } 325 326 /** Return a new matrix that is constructed by element by element 327 * division of the two matrix arguments. Each element of the 328 * first matrix is divided by the corresponding element of the 329 * second matrix. If the two matrices are not the same size, 330 * throw an IllegalArgumentException. 331 */ 332 public static final double[][] divideElements(final double[][] matrix1, 333 final double[][] matrix2) { 334 int rows = _rows(matrix1); 335 int columns = _columns(matrix1); 336 337 _checkSameDimension("divideElements", matrix1, matrix2); 338 339 double[][] returnValue = new double[rows][columns]; 340 341 for (int i = 0; i < rows; i++) { 342 for (int j = 0; j < columns; j++) { 343 returnValue[i][j] = matrix1[i][j] / matrix2[i][j]; 344 } 345 } 346 347 return returnValue; 348 } 349 350 /** Return a new array that is filled with the contents of the matrix. 351 * The doubles are stored row by row, i.e. using the notation 352 * (row, column), the entries of the array are in the following order 353 * for a (m, n) matrix : 354 * (0, 0), (0, 1), (0, 2), ... , (0, n-1), (1, 0), (1, 1), ..., (m-1)(n-1) 355 * @param matrix A matrix of doubles. 356 * @return A new array of doubles. 357 */ 358 public static final double[] fromMatrixToArray(final double[][] matrix) { 359 return fromMatrixToArray(matrix, _rows(matrix), _columns(matrix)); 360 } 361 362 /** Return a new array that is filled with the contents of the matrix. 363 * The maximum numbers of rows and columns to copy are specified so 364 * that entries lying outside of this range can be ignored. The 365 * maximum rows to copy cannot exceed the number of rows in the matrix, 366 * and the maximum columns to copy cannot exceed the number of columns 367 * in the matrix. 368 * The doubles are stored row by row, i.e. using the notation 369 * (row, column), the entries of the array are in the following order 370 * for a matrix, limited to m rows and n columns : 371 * (0, 0), (0, 1), (0, 2), ... , (0, n-1), (1, 0), (1, 1), ..., (m-1)(n-1) 372 * @param matrix A matrix of doubles. 373 * @return A new array of doubles. 374 */ 375 public static final double[] fromMatrixToArray(final double[][] matrix, 376 int maxRow, int maxCol) { 377 double[] returnValue = new double[maxRow * maxCol]; 378 379 for (int i = 0; i < maxRow; i++) { 380 System.arraycopy(matrix[i], 0, returnValue, i * maxCol, maxCol); 381 } 382 383 return returnValue; 384 } 385 386 /** Return a new matrix, which is defined by Aij = 1/(i+j+1), 387 * the Hilbert matrix. The matrix is square with one 388 * dimension specifier required. This matrix is useful because it always 389 * has an inverse. 390 */ 391 public static final double[][] hilbert(final int dim) { 392 double[][] returnValue = new double[dim][dim]; 393 394 for (int i = 0; i < dim; i++) { 395 for (int j = 0; j < dim; j++) { 396 returnValue[i][j] = 1.0 / (i + j + 1); 397 } 398 } 399 400 return returnValue; 401 } 402 403 /** Return an new identity matrix with the specified dimension. The 404 * matrix is square, so only one dimension specifier is needed. 405 * Note that this method does the same thing as identityDouble(), 406 * but the latter is more useful in the expression language. 407 */ 408 public static final double[][] identity(final int dim) { 409 double[][] returnValue = new double[dim][dim]; 410 411 // we rely on the fact Java fills the allocated matrix with 0's 412 for (int i = 0; i < dim; i++) { 413 returnValue[i][i] = 1.0; 414 } 415 416 return returnValue; 417 } 418 419 /** Return an new identity matrix with the specified dimension. The 420 * matrix is square, so only one dimension specifier is needed. 421 */ 422 public static final double[][] identityMatrixDouble(final int dim) { 423 return identity(dim); 424 } 425 426 /** Return a new matrix that is constructed by inverting the input 427 * matrix. If the input matrix is singular, throw an exception. 428 * This method is from [1]. 429 * @exception IllegalArgumentException If the matrix is singular. 430 */ 431 public static final double[][] inverse(final double[][] A) { 432 _checkSquare("inverse", A); 433 434 int n = _rows(A); 435 436 double[][] Ai = allocCopy(A); 437 438 // We depend on each of the elements being initialized to 0 439 int[] pivotFlag = new int[n]; 440 int[] swapCol = new int[n]; 441 int[] swapRow = new int[n]; 442 443 int irow = 0; 444 int icol = 0; 445 446 for (int i = 0; i < n; i++) { // n iterations of pivoting 447 448 // find the biggest pivot element 449 double big = 0.0; 450 451 for (int row = 0; row < n; row++) { 452 if (pivotFlag[row] == 0) { 453 for (int col = 0; col < n; col++) { 454 if (pivotFlag[col] == 0) { 455 double absElement = Math.abs(Ai[row][col]); 456 457 if (absElement >= big) { 458 big = absElement; 459 irow = row; 460 icol = col; 461 } 462 } 463 } 464 } 465 } 466 467 pivotFlag[icol]++; 468 469 // swap rows to make this diagonal the biggest absolute pivot 470 if (irow != icol) { 471 for (int col = 0; col < n; col++) { 472 double temp = Ai[irow][col]; 473 Ai[irow][col] = Ai[icol][col]; 474 Ai[icol][col] = temp; 475 } 476 } 477 478 // store what we swapped 479 swapRow[i] = irow; 480 swapCol[i] = icol; 481 482 // if the pivot is zero, the matrix is singular 483 if (Ai[icol][icol] == 0.0) { 484 throw new IllegalArgumentException( 485 "Attempt to invert a singular matrix."); 486 } 487 488 // divide the row by the pivot 489 double pivotInverse = 1.0 / Ai[icol][icol]; 490 Ai[icol][icol] = 1.0; // pivot = 1 to avoid round off 491 492 for (int col = 0; col < n; col++) { 493 Ai[icol][col] *= pivotInverse; 494 } 495 496 // fix the other rows by subtracting 497 for (int row = 0; row < n; row++) { 498 if (row != icol) { 499 double temp = Ai[row][icol]; 500 Ai[row][icol] = 0.0; 501 502 for (int col = 0; col < n; col++) { 503 Ai[row][col] -= Ai[icol][col] * temp; 504 } 505 } 506 } 507 } 508 509 // fix the effect of all the swaps for final answer 510 for (int swap = n - 1; swap >= 0; swap--) { 511 if (swapRow[swap] != swapCol[swap]) { 512 for (int row = 0; row < n; row++) { 513 double temp = Ai[row][swapRow[swap]]; 514 Ai[row][swapRow[swap]] = Ai[row][swapCol[swap]]; 515 Ai[row][swapCol[swap]] = temp; 516 } 517 } 518 } 519 520 return Ai; 521 } 522 523 /** Replace the destinationMatrix argument elements with the values of 524 * the sourceMatrix argument. The destinationMatrix argument must be 525 * large enough to hold all the values of sourceMatrix argument. 526 * @param destinationMatrix A matrix of doubles, used as the destination. 527 * @param sourceMatrix A matrix of doubles, used as the source. 528 */ 529 public static final void matrixCopy(final double[][] sourceMatrix, 530 final double[][] destinationMatrix) { 531 matrixCopy(sourceMatrix, 0, 0, destinationMatrix, 0, 0, 532 _rows(sourceMatrix), _columns(sourceMatrix)); 533 } 534 535 /** Replace the destinationMatrix argument's values, in the specified row 536 * and column range, with the sourceMatrix argument's values, starting 537 * from specified row and column of the second matrix. 538 * @param sourceMatrix A matrix of doubles, used as the destination. 539 * @param sourceRowStart An int specifying the starting row of the source. 540 * @param sourceColStart An int specifying the starting column of the 541 * source. 542 * @param destinationMatrix A matrix of doubles, used as the destination. 543 * @param destinationRowStart An int specifying the starting row of the 544 * destination. 545 * @param destinationColumnStart An int specifying the starting column 546 * of the destination. 547 * @param rowSpan An int specifying how many rows to copy. 548 * @param columnSpan An int specifying how many columns to copy. 549 */ 550 public static final void matrixCopy(final double[][] sourceMatrix, 551 final int sourceRowStart, final int sourceColStart, 552 final double[][] destinationMatrix, final int destinationRowStart, 553 final int destinationColumnStart, final int rowSpan, 554 final int columnSpan) { 555 // We should verify the parameters here 556 for (int i = 0; i < rowSpan; i++) { 557 System.arraycopy(sourceMatrix[sourceRowStart + i], sourceColStart, 558 destinationMatrix[destinationRowStart + i], 559 destinationColumnStart, columnSpan); 560 } 561 } 562 563 /** Return a new matrix that is constructed from the argument after 564 * performing modulo operation by the second argument to every element. 565 * @param matrix A matrix of doubles. 566 * @param z The double number to divide. 567 * @return A new matrix of doubles. 568 */ 569 public static final double[][] modulo(double[][] matrix, double z) { 570 double[][] returnValue = new double[_rows(matrix)][_columns(matrix)]; 571 572 for (int i = 0; i < _rows(matrix); i++) { 573 for (int j = 0; j < _columns(matrix); j++) { 574 returnValue[i][j] = matrix[i][j] % z; 575 } 576 } 577 578 return returnValue; 579 } 580 581 /** Return a new matrix that is constructed by multiplying the matrix 582 * by a scaleFactor. 583 */ 584 public static final double[][] multiply(final double[][] matrix, 585 final double scaleFactor) { 586 int rows = _rows(matrix); 587 int columns = _columns(matrix); 588 589 double[][] returnValue = new double[rows][columns]; 590 591 for (int i = 0; i < rows; i++) { 592 for (int j = 0; j < columns; j++) { 593 returnValue[i][j] = matrix[i][j] * scaleFactor; 594 } 595 } 596 597 return returnValue; 598 } 599 600 /** Return a new array that is constructed from the argument by 601 * pre-multiplying the array (treated as a row vector) by a matrix. 602 * The number of rows of the matrix must equal the number of elements 603 * in the array. The returned array will have a length equal to the number 604 * of columns of the matrix. 605 */ 606 public static final double[] multiply(final double[][] matrix, 607 final double[] array) { 608 int rows = _rows(matrix); 609 int columns = _columns(matrix); 610 611 if (rows != array.length) { 612 throw new IllegalArgumentException( 613 "preMultiply : array does not have the same number of " 614 + "elements (" + array.length 615 + ") as the number of rows " + "of the matrix (" 616 + rows + ")"); 617 } 618 619 double[] returnValue = new double[columns]; 620 621 for (int i = 0; i < columns; i++) { 622 double sum = 0.0; 623 624 for (int j = 0; j < rows; j++) { 625 sum += matrix[j][i] * array[j]; 626 } 627 628 returnValue[i] = sum; 629 } 630 631 return returnValue; 632 } 633 634 /** Return a new array that is constructed from the argument by 635 * post-multiplying the matrix by an array (treated as a row vector). 636 * The number of columns of the matrix must equal the number of elements 637 * in the array. The returned array will have a length equal to the number 638 * of rows of the matrix. 639 */ 640 public static final double[] multiply(final double[] array, 641 final double[][] matrix) { 642 int rows = _rows(matrix); 643 int columns = _columns(matrix); 644 645 if (columns != array.length) { 646 throw new IllegalArgumentException( 647 "postMultiply() : array does not have the same number " 648 + "of elements (" + array.length 649 + ") as the number of " + "columns of the matrix (" 650 + columns + ")"); 651 } 652 653 double[] returnValue = new double[rows]; 654 655 for (int i = 0; i < rows; i++) { 656 double sum = 0.0; 657 658 for (int j = 0; j < columns; j++) { 659 sum += matrix[i][j] * array[j]; 660 } 661 662 returnValue[i] = sum; 663 } 664 665 return returnValue; 666 } 667 668 /** Return a new matrix that is constructed from the argument by 669 * multiplying the first matrix by the second one. 670 * Note this operation is not commutative, 671 * so care must be taken in the ordering of the arguments. 672 * The number of columns of matrix1 673 * must equal the number of rows of matrix2. If matrix1 is of 674 * size m x n, and matrix2 is of size n x p, the returned matrix 675 * will have size m x p. 676 * <p>Note that this method is different from the other multiply() 677 * methods in that this method does not do pointwise multiplication. 678 * 679 * @see #multiplyElements(double[][], double[][]) 680 * @param matrix1 The first matrix of doubles. 681 * @param matrix2 The second matrix of doubles. 682 * @return A new matrix of doubles. 683 */ 684 public static final double[][] multiply(double[][] matrix1, 685 double[][] matrix2) { 686 double[][] returnValue = new double[_rows(matrix1)][matrix2[0].length]; 687 688 for (int i = 0; i < _rows(matrix1); i++) { 689 for (int j = 0; j < matrix2[0].length; j++) { 690 double sum = 0.0; 691 692 for (int k = 0; k < matrix2.length; k++) { 693 sum += matrix1[i][k] * matrix2[k][j]; 694 } 695 696 returnValue[i][j] = sum; 697 } 698 } 699 700 return returnValue; 701 } 702 703 /** Return a new matrix that is constructed by element by element 704 * multiplication of the two matrix arguments. If the two 705 * matrices are not the same size, throw an 706 * IllegalArgumentException. 707 * <p>Note that this method does pointwise matrix multiplication. 708 * See {@link #multiply(double[][], double[][])} for standard 709 * matrix multiplication. 710 */ 711 public static final double[][] multiplyElements(final double[][] matrix1, 712 final double[][] matrix2) { 713 int rows = _rows(matrix1); 714 int columns = _columns(matrix1); 715 716 _checkSameDimension("multiplyElements", matrix1, matrix2); 717 718 double[][] returnValue = new double[rows][columns]; 719 720 for (int i = 0; i < rows; i++) { 721 for (int j = 0; j < columns; j++) { 722 returnValue[i][j] = matrix1[i][j] * matrix2[i][j]; 723 } 724 } 725 726 return returnValue; 727 } 728 729 /** Return a new matrix that is the additive inverse of the 730 * argument matrix. 731 */ 732 public static final double[][] negative(final double[][] matrix) { 733 int rows = _rows(matrix); 734 int columns = _columns(matrix); 735 736 double[][] returnValue = new double[rows][columns]; 737 738 for (int i = 0; i < rows; i++) { 739 for (int j = 0; j < columns; j++) { 740 returnValue[i][j] = -matrix[i][j]; 741 } 742 } 743 744 return returnValue; 745 } 746 747 /** Return a new matrix that is formed by orthogonalizing the 748 * columns of the input matrix (the column vectors are 749 * orthogonal). If not all columns are linearly independent, the 750 * output matrix will contain a column of zeros for all redundant 751 * input columns. 752 */ 753 public static final double[][] orthogonalizeColumns( 754 final double[][] matrix) { 755 Object[] orthoInfo = _orthogonalizeRows(transpose(matrix)); 756 return transpose((double[][]) orthoInfo[0]); 757 } 758 759 /** Return a new matrix that is formed by orthogonalizing the rows of the 760 * input matrix (the row vectors are orthogonal). If not all rows are 761 * linearly independent, the output matrix will contain a row of zeros 762 * for all redundant input rows. 763 */ 764 public static final double[][] orthogonalizeRows(final double[][] matrix) { 765 Object[] orthoInfo = _orthogonalizeRows(matrix); 766 return (double[][]) orthoInfo[0]; 767 } 768 769 /** Return a new matrix that is formed by orthonormalizing the 770 * columns of the input matrix (the column vectors are orthogonal 771 * and have norm 1). If not all columns are linearly independent, 772 * the output matrix will contain a column of zeros for all 773 * redundant input columns. 774 */ 775 public static final double[][] orthonormalizeColumns( 776 final double[][] matrix) { 777 return transpose(orthogonalizeRows(transpose(matrix))); 778 } 779 780 /** Return a new matrix that is formed by orthonormalizing the 781 * rows of the input matrix (the row vectors are orthogonal and 782 * have norm 1). If not all rows are linearly independent, the 783 * output matrix will contain a row of zeros for all redundant 784 * input rows. 785 */ 786 public static final double[][] orthonormalizeRows(final double[][] matrix) { 787 int rows = _rows(matrix); 788 789 Object[] orthoInfo = _orthogonalizeRows(matrix); 790 double[][] orthogonalMatrix = (double[][]) orthoInfo[0]; 791 double[] oneOverNormSquaredArray = (double[]) orthoInfo[2]; 792 793 for (int i = 0; i < rows; i++) { 794 orthogonalMatrix[i] = DoubleArrayMath.scale(orthogonalMatrix[i], 795 Math.sqrt(oneOverNormSquaredArray[i])); 796 } 797 798 return orthogonalMatrix; 799 } 800 801 /** Return a pair of matrices that are the decomposition of the 802 * input matrix (which must have linearly independent column 803 * vectors), which is m x n, into the matrix product of Q, which 804 * is m x n with orthonormal column vectors, and R, which is an 805 * invertible n x n upper triangular matrix. 806 * 807 * @param matrix The input matrix of doubles. 808 * @return The pair of newly allocated matrices of doubles, 809 * out[0] = Q, out[1] = R. 810 * @exception IllegalArgumentException if the columns vectors of the input 811 * matrix are not linearly independent. 812 */ 813 public static final double[][][] qr(final double[][] matrix) { 814 int columns = _columns(matrix); 815 816 /* Find an orthogonal basis using _orthogonalizeRows(). Note 817 * that _orthogonalizeRows() orthogonalizes row vectors, so 818 * we have use the transpose of input matrix to orthogonalize 819 * its columns vectors. The output will be the transpose of 820 * Q. 821 */ 822 Object[] orthoRowInfo = _orthogonalizeRows(transpose(matrix)); 823 824 double[][] qT = (double[][]) orthoRowInfo[0]; 825 826 // get the dot product matrix, dp[j][i] = <inColumn[i], outColumn[j]> 827 double[][] dotProducts = (double[][]) orthoRowInfo[1]; 828 829 // Normalize the row vectors of qT (column vectors of Q) by 830 // dividing by the norm of each row vector. To compute R, 831 // normalize each row of dotProducts by dividing each row the 832 // norm of each column vector of Q. 833 double[] oneOverNormSquaredArray = (double[]) orthoRowInfo[2]; 834 835 // check that all columns were linearly independent 836 Integer nullity = (Integer) orthoRowInfo[3]; 837 838 if (nullity.intValue() > 0) { 839 throw new IllegalArgumentException("qr() : not all " 840 + "column vectors are linearly independent."); 841 } 842 843 for (int i = 0; i < columns; i++) { 844 double oneOverNorm = Math.sqrt(oneOverNormSquaredArray[i]); 845 qT[i] = DoubleArrayMath.scale(qT[i], oneOverNorm); 846 847 // R is upper triangular, so normalize only upper elements 848 for (int j = i; j < columns; j++) { 849 dotProducts[i][j] *= oneOverNorm; 850 } 851 } 852 853 return new double[][][] { transpose(qT), dotProducts }; 854 } 855 856 /** Return a new matrix that is constructed from the argument by 857 * subtracting the second matrix from the first one. If the two 858 * matrices are not the same size, throw an 859 * IllegalArgumentException. 860 */ 861 public static final double[][] subtract(final double[][] matrix1, 862 final double[][] matrix2) { 863 _checkSameDimension("subtract", matrix1, matrix2); 864 865 int rows = _rows(matrix1); 866 int columns = _columns(matrix1); 867 868 double[][] returnValue = new double[rows][columns]; 869 870 for (int i = 0; i < rows; i++) { 871 for (int j = 0; j < columns; j++) { 872 returnValue[i][j] = matrix1[i][j] - matrix2[i][j]; 873 } 874 } 875 876 return returnValue; 877 } 878 879 /** Return the sum of the elements of a matrix. 880 * @return The sum of the elements of the matrix. 881 */ 882 public static final double sum(final double[][] matrix) { 883 double sum = 0.0; 884 885 for (double[] element : matrix) { 886 for (int j = 0; j < element.length; j++) { 887 sum += element[j]; 888 } 889 } 890 891 return sum; 892 } 893 894 /** Return a new matrix that is formed by converting the doubles 895 * in the argument matrix to complex numbers. Each complex number 896 * has real part equal to the value in the argument matrix and a 897 * zero imaginary part. 898 * 899 * @param matrix An matrix of double. 900 * @return A new matrix of complex numbers. 901 */ 902 public static final Complex[][] toComplexMatrix(final double[][] matrix) { 903 int rows = _rows(matrix); 904 int columns = _columns(matrix); 905 906 Complex[][] returnValue = new Complex[rows][columns]; 907 908 for (int i = 0; i < rows; i++) { 909 for (int j = 0; j < columns; j++) { 910 returnValue[i][j] = new Complex(matrix[i][j], 0.0); 911 } 912 } 913 914 return returnValue; 915 } 916 917 /** Return a new matrix that is formed by converting the doubles in 918 * the argument matrix to floats. 919 * @param matrix An matrix of double. 920 * @return A new matrix of floats. 921 */ 922 public static final float[][] toFloatMatrix(final double[][] matrix) { 923 int rows = _rows(matrix); 924 int columns = _columns(matrix); 925 926 float[][] returnValue = new float[rows][columns]; 927 928 for (int i = 0; i < rows; i++) { 929 for (int j = 0; j < columns; j++) { 930 returnValue[i][j] = (float) matrix[i][j]; 931 } 932 } 933 934 return returnValue; 935 } 936 937 /** Return a new matrix that is formed by converting the doubles in 938 * the argument matrix to integers. 939 * @param matrix An matrix of double. 940 * @return A new matrix of integers. 941 */ 942 public static final int[][] toIntegerMatrix(final double[][] matrix) { 943 int rows = _rows(matrix); 944 int columns = _columns(matrix); 945 946 int[][] returnValue = new int[rows][columns]; 947 948 for (int i = 0; i < rows; i++) { 949 for (int j = 0; j < columns; j++) { 950 returnValue[i][j] = (int) matrix[i][j]; 951 } 952 } 953 954 return returnValue; 955 } 956 957 /** Return a new matrix that is formed by converting the doubles in 958 * the argument matrix to longs. 959 * @param matrix An matrix of double. 960 * @return A new matrix of longs. 961 */ 962 public static final long[][] toLongMatrix(final double[][] matrix) { 963 int rows = _rows(matrix); 964 int columns = _columns(matrix); 965 966 long[][] returnValue = new long[rows][columns]; 967 968 for (int i = 0; i < rows; i++) { 969 for (int j = 0; j < columns; j++) { 970 returnValue[i][j] = (long) matrix[i][j]; 971 } 972 } 973 974 return returnValue; 975 } 976 977 /** Return a new matrix of doubles that is initialized from a 1-D array. 978 * The format of the array must be (0, 0), (0, 1), ..., (0, n-1), (1, 0), 979 * (1, 1), ..., (m-1, n-1) where the output matrix is to be m x n and 980 * entries are denoted by (row, column). 981 * @param array An array of doubles. 982 * @param rows An integer representing the number of rows of the 983 * new matrix. 984 * @param cols An integer representing the number of columns of the 985 * new matrix. 986 * @return A new matrix of doubles. 987 */ 988 public static final double[][] toMatrixFromArray(double[] array, int rows, 989 int cols) { 990 double[][] returnValue = new double[rows][cols]; 991 992 for (int i = 0; i < rows; i++) { 993 System.arraycopy(array, i * cols, returnValue[i], 0, cols); 994 } 995 996 return returnValue; 997 } 998 999 /** Return a new String representing the matrix, formatted as 1000 * in Java array initializers. 1001 */ 1002 public static final String toString(final double[][] matrix) { 1003 return toString(matrix, ", ", "{", "}", "{", ", ", "}"); 1004 } 1005 1006 /** Return a new String representing the matrix, formatted as 1007 * specified by the ArrayStringFormat argument. 1008 * To get a String in the Ptolemy expression language format, 1009 * call this method with ArrayStringFormat.exprASFormat as the 1010 * format argument. 1011 */ 1012 public static final String toString(final double[][] matrix, 1013 String elementDelimiter, String matrixBegin, String matrixEnd, 1014 String vectorBegin, String vectorDelimiter, String vectorEnd) { 1015 StringBuffer sb = new StringBuffer(); 1016 sb.append(matrixBegin); 1017 1018 for (int i = 0; i < _rows(matrix); i++) { 1019 sb.append(vectorBegin); 1020 1021 for (int j = 0; j < _columns(matrix); j++) { 1022 sb.append(Double.toString(matrix[i][j])); 1023 1024 if (j < _columns(matrix) - 1) { 1025 sb.append(elementDelimiter); 1026 } 1027 } 1028 1029 sb.append(vectorEnd); 1030 1031 if (i < _rows(matrix) - 1) { 1032 sb.append(vectorDelimiter); 1033 } 1034 } 1035 1036 sb.append(matrixEnd); 1037 1038 return new String(sb); 1039 } 1040 1041 /** Return the trace of a square matrix, which is the sum of the 1042 * diagonal entries A<sub>11</sub> + A<sub>22</sub> + ... + A<sub>nn</sub> 1043 * Throw an IllegalArgumentException if the matrix is not square. 1044 * Note that the trace of a matrix is equal to the sum of its eigenvalues. 1045 */ 1046 public static final double trace(final double[][] matrix) { 1047 int dim = _checkSquare("trace", matrix); 1048 double sum = 0.0; 1049 1050 for (int i = 0; i < dim; i++) { 1051 sum += matrix[i][i]; 1052 } 1053 1054 return sum; 1055 } 1056 1057 /** Return a new matrix that is constructed by transposing the input 1058 * matrix. If the input matrix is m x n, the output matrix will be 1059 * n x m. 1060 */ 1061 public static final double[][] transpose(final double[][] matrix) { 1062 int rows = _rows(matrix); 1063 int columns = _columns(matrix); 1064 1065 double[][] returnValue = new double[columns][rows]; 1066 1067 for (int i = 0; i < rows; i++) { 1068 for (int j = 0; j < columns; j++) { 1069 returnValue[j][i] = matrix[i][j]; 1070 } 1071 } 1072 1073 return returnValue; 1074 } 1075 1076 /** Return true if the elements of the two matrices differ by no more 1077 * than the specified distance. The specified distance must be non-negative. 1078 * If <i>distance</i> is negative, return false. 1079 * @param matrix1 The first matrix. 1080 * @param matrix2 The second matrix. 1081 * @param distance The distance to use for comparison. 1082 * @return True if the elements of the two matrices are within the 1083 * specified distance. 1084 * @exception IllegalArgumentException If the matrices do not have the same dimension. 1085 * This is a run-time exception, so it need not be declared explicitly. 1086 */ 1087 public static final boolean within(final double[][] matrix1, 1088 final double[][] matrix2, double distance) { 1089 int rows = _rows(matrix1); 1090 int columns = _columns(matrix1); 1091 1092 _checkSameDimension("within", matrix1, matrix2); 1093 1094 for (int i = 0; i < rows; i++) { 1095 for (int j = 0; j < columns; j++) { 1096 if (matrix1[i][j] > matrix2[i][j] + distance 1097 || matrix1[i][j] < matrix2[i][j] - distance) { 1098 return false; 1099 } 1100 } 1101 } 1102 1103 return true; 1104 } 1105 1106 /** Return true if the elements of the two matrices differ by no more 1107 * than the specified distances. The specified distances must all 1108 * be non-negative. If any element of <i>errorMatrix</i> is negative, 1109 * return false. 1110 * @param matrix1 The first matrix. 1111 * @param matrix2 The second matrix. 1112 * @param errorMatrix The distance to use for comparison. 1113 * Note that if errorMatrix contains an element that is negative, 1114 * then this method will return false. 1115 * @return True if the elements of the two matrices are within the 1116 * specified distance. 1117 * @exception IllegalArgumentException If the matrices do not have the same dimension. 1118 * This is a run-time exception, so it need not be declared explicitly. 1119 */ 1120 public static final boolean within(final double[][] matrix1, 1121 final double[][] matrix2, final double[][] errorMatrix) { 1122 int rows = _rows(matrix1); 1123 int columns = _columns(matrix1); 1124 1125 _checkSameDimension("within", matrix1, matrix2); 1126 _checkSameDimension("within", matrix1, errorMatrix); 1127 1128 for (int i = 0; i < rows; i++) { 1129 for (int j = 0; j < columns; j++) { 1130 if (matrix1[i][j] > matrix2[i][j] + errorMatrix[i][j] 1131 || matrix1[i][j] < matrix2[i][j] - errorMatrix[i][j]) { 1132 return false; 1133 } 1134 } 1135 } 1136 1137 return true; 1138 } 1139 1140 /////////////////////////////////////////////////////////////////// 1141 //// protected methods //// 1142 1143 /** Check that the two matrix arguments are of the same dimension. 1144 * If they are not, an IllegalArgumentException is thrown. 1145 * @param caller A string representing the caller method name. 1146 * @param matrix1 A matrix of doubles. 1147 * @param matrix2 A matrix of doubles. 1148 * @exception IllegalArgumentException If the arguments do not 1149 * have the same dimension. This is a run-time exception, so it 1150 * need not be declared explicitly. 1151 */ 1152 protected static final void _checkSameDimension(final String caller, 1153 final double[][] matrix1, final double[][] matrix2) 1154 throws IllegalArgumentException { 1155 int rows = _rows(matrix1); 1156 int columns = _columns(matrix1); 1157 1158 if (rows != _rows(matrix2) || columns != _columns(matrix2)) { 1159 throw new IllegalArgumentException("ptolemy.math.DoubleMatrixMath." 1160 + caller + "() : one matrix " + _dimensionString(matrix1) 1161 + " is not the same size as another matrix " 1162 + _dimensionString(matrix2) + "."); 1163 } 1164 } 1165 1166 /** Check that the argument matrix is a square matrix. If the matrix is not 1167 * square, an IllegalArgumentException is thrown. 1168 * @param caller A string representing the caller method name. 1169 * @param matrix A matrix of doubles. 1170 * @return The dimension of the square matrix. 1171 * @exception IllegalArgumentException If the argument is not square. 1172 * This is a run-time exception, so it need not be declared explicitly. 1173 */ 1174 protected static final int _checkSquare(final String caller, 1175 final double[][] matrix) throws IllegalArgumentException { 1176 if (_rows(matrix) != _columns(matrix)) { 1177 throw new IllegalArgumentException("ptolemy.math.DoubleMatrixMath." 1178 + caller + "() : matrix argument " 1179 + _dimensionString(matrix) + " is not a square matrix."); 1180 } 1181 1182 return _rows(matrix); 1183 } 1184 1185 /** Return the number of columns of a matrix. 1186 * @param matrix The matrix. 1187 * @return The number of columns. 1188 */ 1189 protected static final int _columns(final double[][] matrix) { 1190 return matrix[0].length; 1191 } 1192 1193 /** Return a string that describes the number of rows and columns. 1194 * @param matrix The matrix that is to be described. 1195 * @return a string describing the dimensions of this matrix. 1196 */ 1197 protected static final String _dimensionString(final double[][] matrix) { 1198 return "[" + _rows(matrix) + " x " + _columns(matrix) + "]"; 1199 } 1200 1201 /** Given a set of row vectors rowArrays[0] ... rowArrays[n-1], compute : 1202 * <ol> 1203 * <li>A new set of row vectors out[0] ... out[n-1] which are the 1204 * orthogonalized versions of each input row vector. If a row 1205 * vector rowArray[i] is a linear combination of the last 0 .. i 1206 * - 1 row vectors, set array[i] to an array of 0's (array[i] 1207 * being the 0 vector is a special case of this). Put the result 1208 * in returnValue[0].<br> 1209 * 1210 * <li> An n x n matrix containing the dot products of the input 1211 * row vectors and the output row vectors, 1212 * dotProductMatrix[j][i] = <rowArray[i], outArray[j]>. Put 1213 * the result in returnValue[1].<br> 1214 * 1215 * <li> An array containing 1 / (norm(outArray[i])<sup>2</sup>), 1216 * with n entries. Put the result in returnValue[2].<br> 1217 * 1218 * <li> A count of the number of rows that were found to be linear 1219 * combinations of previous rows. Replace those rows with rows 1220 * of zeros. The count is equal to the nullity of the 1221 * transpose of the input matrix. Wrap the count with an 1222 * Integer, and put it in returnValue[3]. 1223 * </ol> 1224 * Orthogonalization is done with the Gram-Schmidt process. 1225 */ 1226 protected static final Object[] _orthogonalizeRows( 1227 final double[][] rowArrays) { 1228 int rows = rowArrays.length; 1229 int columns = rowArrays[0].length; 1230 int nullity = 0; 1231 1232 double[][] orthogonalMatrix = new double[rows][]; 1233 1234 double[] oneOverNormSquaredArray = new double[rows]; 1235 1236 // A matrix containing the dot products of the input row 1237 // vectors and output row vectors, dotProductMatrix[j][i] = 1238 // <rowArray[i], outArray[j]> 1239 double[][] dotProductMatrix = new double[rows][rows]; 1240 1241 for (int i = 0; i < rows; i++) { 1242 // Get a reference to the row vector. 1243 double[] refArray = rowArrays[i]; 1244 1245 // Initialize row vector. 1246 double[] rowArray = refArray; 1247 1248 // Subtract projections onto all previous vectors. 1249 for (int j = 0; j < i; j++) { 1250 // Save the dot product for future use for QR decomposition. 1251 double dotProduct = DoubleArrayMath.dotProduct(refArray, 1252 orthogonalMatrix[j]); 1253 1254 dotProductMatrix[j][i] = dotProduct; 1255 1256 rowArray = DoubleArrayMath.subtract(rowArray, 1257 DoubleArrayMath.scale(orthogonalMatrix[j], 1258 dotProduct * oneOverNormSquaredArray[j])); 1259 } 1260 1261 // Compute the dot product between the input and output vector 1262 // for the diagonal entry of dotProductMatrix. 1263 dotProductMatrix[i][i] = DoubleArrayMath.dotProduct(refArray, 1264 rowArray); 1265 1266 // Check the norm to find zero rows, and save the 1 / 1267 // norm^2 for later computation. 1268 double normSquared = DoubleArrayMath.sumOfSquares(rowArray); 1269 1270 if (normSquared == 0.0) { 1271 if (i == 0) { 1272 // The input row was the zero vector, we now have 1273 // a reference to it. Set the row to a new zero 1274 // vector to ensure the output memory is entirely 1275 // disjoint from the input memory. 1276 orthogonalMatrix[i] = new double[columns]; 1277 } else { 1278 // Reuse the memory allocated by the last 1279 // subtract() call -- the row is all zeros. 1280 orthogonalMatrix[i] = rowArray; 1281 } 1282 1283 // set the normalizing factor to 0.0 to avoid division by 0, 1284 // it works because the projection onto the zero vector yields 1285 // zero 1286 oneOverNormSquaredArray[i] = 0.0; 1287 1288 nullity++; 1289 } else { 1290 orthogonalMatrix[i] = rowArray; 1291 oneOverNormSquaredArray[i] = 1.0 / normSquared; 1292 } 1293 } 1294 1295 return new Object[] { orthogonalMatrix, dotProductMatrix, 1296 oneOverNormSquaredArray, Integer.valueOf(nullity) }; 1297 } 1298 1299 /** Return the number of rows of a matrix. 1300 * @param matrix The matrix. 1301 * @return The number of rows. 1302 */ 1303 protected static final int _rows(final double[][] matrix) { 1304 return matrix.length; 1305 } 1306}