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