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] = &lt;rowArray[i], outArray[j]&gt;.  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}