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