001/* A library for mathematical operations on matrices of longs.
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//// LongMatrixMath
038
039/**
040 This class provides a library for mathematical operations on
041 matrices of longs.
042
043 Rows and column numbers of matrices are specified with zero-based indices.
044
045 All calls expect matrix arguments to be non-null. In addition, all
046 rows of the matrix are expected to have the same number of columns.
047 @author Jeff Tsay
048 @version $Id$
049 @since Ptolemy II 1.0
050 @Pt.ProposedRating Yellow (ctsay)
051 @Pt.AcceptedRating Yellow (ctsay)
052 */
053public class LongMatrixMath {
054    // private constructor prevents construction of this class.
055    private LongMatrixMath() {
056    }
057
058    /** Return a new matrix that is constructed from the argument by
059     *  adding the second argument to every element.
060     *  @param matrix A matrix of longs.
061     *  @param z The long number to add.
062     *  @return A new matrix of longs.
063     */
064    public static final long[][] add(long[][] matrix, long z) {
065        long[][] returnValue = new long[_rows(matrix)][_columns(matrix)];
066
067        for (int i = 0; i < _rows(matrix); i++) {
068            for (int j = 0; j < _columns(matrix); j++) {
069                returnValue[i][j] = matrix[i][j] + z;
070            }
071        }
072
073        return returnValue;
074    }
075
076    /** Return a new matrix that is constructed from the argument by
077     *  adding the second matrix to the first one.  If the two
078     *  matrices are not the same size, throw an
079     *  IllegalArgumentException.
080     *  @param matrix1 The first matrix of longs.
081     *  @param matrix2 The second matrix of longs.
082     *  @return A new matrix of longs.  */
083    public static final long[][] add(final long[][] matrix1,
084            final long[][] matrix2) {
085        _checkSameDimension("add", matrix1, matrix2);
086
087        long[][] returnValue = new long[_rows(matrix1)][_columns(matrix1)];
088
089        for (int i = 0; i < _rows(matrix1); i++) {
090            for (int j = 0; j < _columns(matrix1); j++) {
091                returnValue[i][j] = matrix1[i][j] + matrix2[i][j];
092            }
093        }
094
095        return returnValue;
096    }
097
098    /** Return a new matrix that is a copy of the matrix argument.
099     *  @param matrix A matrix of longs.
100     *  @return A new matrix of longs.
101     */
102    public static final long[][] allocCopy(final long[][] matrix) {
103        return crop(matrix, 0, 0, _rows(matrix), _columns(matrix));
104    }
105
106    /** Return a new array that is formed by applying an instance of a
107     *  LongBinaryOperation to each element in the input matrix,
108     *  using z as the left operand in all cases and the matrix elements
109     *  as the right operands (op.operate(z, matrix[i][j])).
110     */
111    public static final long[][] applyBinaryOperation(LongBinaryOperation op,
112            final long z, final long[][] matrix) {
113        int rows = _rows(matrix);
114        int columns = _columns(matrix);
115
116        long[][] returnValue = new long[rows][columns];
117
118        for (int i = 0; i < rows; i++) {
119            for (int j = 0; j < columns; j++) {
120                returnValue[i][j] = op.operate(z, matrix[i][j]);
121            }
122        }
123
124        return returnValue;
125    }
126
127    /** Return a new array that is formed by applying an instance of a
128     *  LongBinaryOperation to each element in the input matrix,
129     *  using the matrix elements as the left operands and z as the right
130     *  operand in all cases (op.operate(matrix[i][j], z)).
131     */
132    public static final long[][] applyBinaryOperation(LongBinaryOperation op,
133            final long[][] matrix, final long z) {
134        int rows = _rows(matrix);
135        int columns = _columns(matrix);
136
137        long[][] returnValue = new long[rows][columns];
138
139        for (int i = 0; i < rows; i++) {
140            for (int j = 0; j < columns; j++) {
141                returnValue[i][j] = op.operate(matrix[i][j], z);
142            }
143        }
144
145        return returnValue;
146    }
147
148    /** Return a new array that is formed by applying an instance of a
149     *  LongBinaryOperation to the two matrices, element by element,
150     *  using the elements of the first matrix as the left operands
151     *  and the elements of the second matrix as the right operands.
152     *  (op.operate(matrix1[i][j], matrix2[i][j])).  If the matrices
153     *  are not the same size, throw an IllegalArgumentException.
154     */
155    public static final long[][] applyBinaryOperation(LongBinaryOperation op,
156            final long[][] matrix1, final long[][] matrix2) {
157        int rows = _rows(matrix1);
158        int columns = _columns(matrix1);
159
160        _checkSameDimension("applyBinaryOperation", matrix1, matrix2);
161
162        long[][] returnValue = new long[rows][columns];
163
164        for (int i = 0; i < rows; i++) {
165            for (int j = 0; j < columns; j++) {
166                returnValue[i][j] = op.operate(matrix1[i][j], matrix2[i][j]);
167            }
168        }
169
170        return returnValue;
171    }
172
173    /** Return a new array that is formed by applying an instance of a
174     *  LongUnaryOperation to each element in the input matrix
175     *  (op.operate(matrix[i][j])).
176     */
177    public static final long[][] applyUnaryOperation(
178            final LongUnaryOperation op, final long[][] matrix) {
179        int rows = _rows(matrix);
180        int columns = _columns(matrix);
181
182        long[][] returnValue = new long[rows][columns];
183
184        for (int i = 0; i < rows; i++) {
185            for (int j = 0; j < columns; j++) {
186                returnValue[i][j] = op.operate(matrix[i][j]);
187            }
188        }
189
190        return returnValue;
191    }
192
193    /** Return a new matrix that is the formed by bitwise ANDing z
194     *  with each element of the input matrix (matrix[i][j] &amp; z).
195     */
196    public static final long[][] bitwiseAnd(final long[][] matrix,
197            final long z) {
198        int rows = _rows(matrix);
199        int columns = _columns(matrix);
200
201        long[][] returnValue = new long[rows][columns];
202
203        for (int i = 0; i < rows; i++) {
204            for (int j = 0; j < columns; j++) {
205                returnValue[i][j] = matrix[i][j] & z;
206            }
207        }
208
209        return returnValue;
210    }
211
212    /** Return a new array that is the element-by-element bitwise AND
213     *  of the two input matrices (matrix1[i][j] &amp; matrix2[i][j]).  If
214     *  the two matrices are not the same size, throw an
215     *  IllegalArgumentException.
216     */
217    public static final long[][] bitwiseAnd(final long[][] matrix1,
218            final long[][] matrix2) {
219        int rows = _rows(matrix1);
220        int columns = _columns(matrix1);
221
222        _checkSameDimension("bitwiseAnd", matrix1, matrix2);
223
224        long[][] returnValue = new long[rows][columns];
225
226        for (int i = 0; i < rows; i++) {
227            for (int j = 0; j < columns; j++) {
228                returnValue[i][j] = matrix1[i][j] & matrix2[i][j];
229            }
230        }
231
232        return returnValue;
233    }
234
235    /** Return a new array that formed by the bitwise complement of
236     *  each element in the input matrix (~matrix[i][j]).
237     */
238    public static final long[][] bitwiseComplement(final long[][] matrix) {
239        int rows = _rows(matrix);
240        int columns = _columns(matrix);
241
242        long[][] returnValue = new long[rows][columns];
243
244        for (int i = 0; i < rows; i++) {
245            for (int j = 0; j < columns; j++) {
246                returnValue[i][j] = ~matrix[i][j];
247            }
248        }
249
250        return returnValue;
251    }
252
253    /** Return a new matrix that is the formed by bitwise ORing z with
254     *  each element of the input matrix (matrix[i][j] | z).
255     */
256    public static final long[][] bitwiseOr(final long[][] matrix,
257            final long z) {
258        int rows = _rows(matrix);
259        int columns = _columns(matrix);
260
261        long[][] returnValue = new long[rows][columns];
262
263        for (int i = 0; i < rows; i++) {
264            for (int j = 0; j < columns; j++) {
265                returnValue[i][j] = matrix[i][j] | z;
266            }
267        }
268
269        return returnValue;
270    }
271
272    /** Return a new array that is the element-by-element bitwise OR
273     *  of the two input matrices (matrix1[i][j] | matrix2[i][j]).  If
274     *  the two matrices are not the same size, throw an
275     *  IllegalArgumentException.
276     */
277    public static final long[][] bitwiseOr(final long[][] matrix1,
278            final long[][] matrix2) {
279        int rows = _rows(matrix1);
280        int columns = _columns(matrix1);
281
282        _checkSameDimension("bitwiseOr", matrix1, matrix2);
283
284        long[][] returnValue = new long[rows][columns];
285
286        for (int i = 0; i < rows; i++) {
287            for (int j = 0; j < columns; j++) {
288                returnValue[i][j] = matrix1[i][j] | matrix2[i][j];
289            }
290        }
291
292        return returnValue;
293    }
294
295    /** Return a new matrix that is the formed by bitwise XORing z
296     *  with each element of the input matrix (matrix[i][j] ^ z).
297     */
298    public static final long[][] bitwiseXor(final long[][] matrix,
299            final long z) {
300        int rows = _rows(matrix);
301        int columns = _columns(matrix);
302
303        long[][] returnValue = new long[rows][columns];
304
305        for (int i = 0; i < rows; i++) {
306            for (int j = 0; j < columns; j++) {
307                returnValue[i][j] = matrix[i][j] ^ z;
308            }
309        }
310
311        return returnValue;
312    }
313
314    /** Return a new array that is the element-by-element bitwise XOR
315     *  of the two input matrices (matrix1[i][j] &amp; matrix2[i][j]).  If
316     *  the two matrices are not the same size, throw an
317     *  IllegalArgumentException.
318     */
319    public static final long[][] bitwiseXor(final long[][] matrix1,
320            final long[][] matrix2) {
321        int rows = _rows(matrix1);
322        int columns = _columns(matrix1);
323
324        _checkSameDimension("bitwiseXor", matrix1, matrix2);
325
326        long[][] returnValue = new long[rows][columns];
327
328        for (int i = 0; i < rows; i++) {
329            for (int j = 0; j < columns; j++) {
330                returnValue[i][j] = matrix1[i][j] ^ matrix2[i][j];
331            }
332        }
333
334        return returnValue;
335    }
336
337    /** Return a new matrix that is a sub-matrix of the input
338     *  matrix argument. The row and column from which to start
339     *  and the number of rows and columns to span are specified.
340     *  @param matrix A matrix of longs.
341     *  @param rowStart An int specifying which row to start on.
342     *  @param colStart An int specifying which column to start on.
343     *  @param rowSpan An int specifying how many rows to copy.
344     *  @param colSpan An int specifying how many columns to copy.
345     */
346    public static final long[][] crop(final long[][] matrix, final int rowStart,
347            final int colStart, final int rowSpan, final int colSpan) {
348        long[][] returnValue = new long[rowSpan][colSpan];
349
350        for (int i = 0; i < rowSpan; i++) {
351            System.arraycopy(matrix[rowStart + i], colStart, returnValue[i], 0,
352                    colSpan);
353        }
354
355        return returnValue;
356    }
357
358    /** Return a new matrix that is constructed by placing the
359     *  elements of the input array on the diagonal of the square
360     *  matrix, starting from the top left corner down to the bottom
361     *  right corner. All other elements are zero. The size of of the
362     *  matrix is n x n, where n is the length of the input array.
363     */
364    public static final long[][] diag(final long[] array) {
365        int n = array.length;
366
367        long[][] returnValue = new long[n][n];
368
369        // Assume the matrix is zero-filled.
370        for (int i = 0; i < n; i++) {
371            returnValue[i][i] = array[i];
372        }
373
374        return returnValue;
375    }
376
377    /** Return a new matrix that is constructed from the argument by
378     *  dividing the second argument to every element.
379     *  @param matrix A matrix of longs.
380     *  @param z The long number to divide.
381     *  @return A new matrix of longs.
382     */
383    public static final long[][] divide(long[][] matrix, long z) {
384        long[][] returnValue = new long[_rows(matrix)][_columns(matrix)];
385
386        for (int i = 0; i < _rows(matrix); i++) {
387            for (int j = 0; j < _columns(matrix); j++) {
388                returnValue[i][j] = matrix[i][j] / z;
389            }
390        }
391
392        return returnValue;
393    }
394
395    /** Return a new matrix that is constructed by element by element
396     *  division of the two matrix arguments. Each element of the
397     *  first matrix is divided by the corresponding element of the
398     *  second matrix.  If the two matrices are not the same size,
399     *  throw an IllegalArgumentException.
400     */
401    public static final long[][] divideElements(final long[][] matrix1,
402            final long[][] matrix2) {
403        int rows = _rows(matrix1);
404        int columns = _columns(matrix1);
405
406        _checkSameDimension("divideElements", matrix1, matrix2);
407
408        long[][] returnValue = new long[rows][columns];
409
410        for (int i = 0; i < rows; i++) {
411            for (int j = 0; j < columns; j++) {
412                returnValue[i][j] = matrix1[i][j] / matrix2[i][j];
413            }
414        }
415
416        return returnValue;
417    }
418
419    /** Return a new array that is filled with the contents of the matrix.
420     *  The longs are stored row by row, i.e. using the notation
421     *  (row, column), the entries of the array are in the following order
422     *  for a (m, n) matrix :
423     *  (0, 0), (0, 1), (0, 2), ... , (0, n-1), (1, 0), (1, 1), ..., (m-1)(n-1)
424     *  @param matrix A matrix of longs.
425     *  @return A new array of longs.
426     */
427    public static final long[] fromMatrixToArray(final long[][] matrix) {
428        return fromMatrixToArray(matrix, _rows(matrix), _columns(matrix));
429    }
430
431    /** Return a new array that is filled with the contents of the matrix.
432     *  The maximum numbers of rows and columns to copy are specified so
433     *  that entries lying outside of this range can be ignored. The
434     *  maximum rows to copy cannot exceed the number of rows in the matrix,
435     *  and the maximum columns to copy cannot exceed the number of columns
436     *  in the matrix.
437     *  The longs are stored row by row, i.e. using the notation
438     *  (row, column), the entries of the array are in the following order
439     *  for a matrix, limited to m rows and n columns :
440     *  (0, 0), (0, 1), (0, 2), ... , (0, n-1), (1, 0), (1, 1), ..., (m-1)(n-1)
441     *  @param matrix A matrix of longs.
442     *  @return A new array of longs.
443     */
444    public static final long[] fromMatrixToArray(final long[][] matrix,
445            int maxRow, int maxCol) {
446        long[] returnValue = new long[maxRow * maxCol];
447
448        for (int i = 0; i < maxRow; i++) {
449            System.arraycopy(matrix[i], 0, returnValue, i * maxCol, maxCol);
450        }
451
452        return returnValue;
453    }
454
455    /** Return an new identity matrix with the specified dimension. The
456     *  matrix is square, so only one dimension specifier is needed.
457     */
458    public static final long[][] identity(final int dim) {
459        long[][] returnValue = new long[dim][dim];
460
461        // we rely on the fact Java fills the allocated matrix with 0's
462        for (int i = 0; i < dim; i++) {
463            returnValue[i][i] = 1L;
464        }
465
466        return returnValue;
467    }
468
469    /** Return an new identity matrix with the specified dimension. The
470     *  matrix is square, so only one dimension specifier is needed.
471     */
472    public static final long[][] identityMatrixLong(final int dim) {
473        return identity(dim);
474    }
475
476    /** Replace the first matrix argument elements with the values of
477     *  the second matrix argument. The second matrix argument must be
478     *  large enough to hold all the values of second matrix argument.
479     *  @param destMatrix A matrix of longs, used as the destination.
480     *  @param srcMatrix A matrix of longs, used as the source.
481     */
482    public static final void matrixCopy(final long[][] srcMatrix,
483            final long[][] destMatrix) {
484        matrixCopy(srcMatrix, 0, 0, destMatrix, 0, 0, _rows(srcMatrix),
485                _columns(srcMatrix));
486    }
487
488    /** Replace the first matrix argument's values, in the specified row
489     *  and column range, with the second matrix argument's values, starting
490     *  from specified row and column of the second matrix.
491     *  @param srcMatrix A matrix of longs, used as the destination.
492     *  @param srcRowStart An int specifying the starting row of the source.
493     *  @param srcColStart An int specifying the starting column of the
494     *  source.
495     *  @param destMatrix A matrix of longs, used as the destination.
496     *  @param destRowStart An int specifying the starting row of the dest.
497     *  @param destColStart An int specifying the starting column of the
498     *         dest.
499     *  @param rowSpan An int specifying how many rows to copy.
500     *  @param colSpan An int specifying how many columns to copy.
501     */
502    public static final void matrixCopy(final long[][] srcMatrix,
503            final int srcRowStart, final int srcColStart,
504            final long[][] destMatrix, final int destRowStart,
505            final int destColStart, final int rowSpan, final int colSpan) {
506        // We should verify the parameters here
507        for (int i = 0; i < rowSpan; i++) {
508            System.arraycopy(srcMatrix[srcRowStart + i], srcColStart,
509                    destMatrix[destRowStart + i], destColStart, colSpan);
510        }
511    }
512
513    /** Return a new matrix that is constructed by computing the
514     *  remainders between each element in the matrix and z.
515     */
516    public static final long[][] modulo(final long[][] matrix, final long z) {
517        long[][] returnValue = new long[_rows(matrix)][_columns(matrix)];
518
519        for (int i = 0; i < _rows(matrix); i++) {
520            for (int j = 0; j < _columns(matrix); j++) {
521                returnValue[i][j] = matrix[i][j] % z;
522            }
523        }
524
525        return returnValue;
526    }
527
528    /** Return a new matrix that is constructed by computing the
529     *  remainders between each element in the first matrix argument
530     *  and the corresponding element in the second matrix argument.
531     *  If the two matrices are not the same size, throw an
532     *  IllegalArgumentException.
533     */
534    public static final long[][] modulo(final long[][] matrix1,
535            final long[][] matrix2) {
536        int rows = _rows(matrix1);
537        int columns = _columns(matrix1);
538
539        _checkSameDimension("modulo", matrix1, matrix2);
540
541        long[][] returnValue = new long[rows][columns];
542
543        for (int i = 0; i < rows; i++) {
544            for (int j = 0; j < columns; j++) {
545                returnValue[i][j] = matrix1[i][j] % matrix2[i][j];
546            }
547        }
548
549        return returnValue;
550    }
551
552    /** Return a new matrix that is constructed by multiplying the matrix
553     *  by a scaleFactor.
554     */
555    public static final long[][] multiply(final long[][] matrix,
556            final long scaleFactor) {
557        int rows = _rows(matrix);
558        int columns = _columns(matrix);
559
560        long[][] returnValue = new long[rows][columns];
561
562        for (int i = 0; i < rows; i++) {
563            for (int j = 0; j < columns; j++) {
564                returnValue[i][j] = matrix[i][j] * scaleFactor;
565            }
566        }
567
568        return returnValue;
569    }
570
571    /** Return a new array that is constructed from the argument by
572     *  pre-multiplying the array (treated as a row vector) by a matrix.
573     *  The number of rows of the matrix must equal the number of elements
574     *  in the array. The returned array will have a length equal to the number
575     *  of columns of the matrix.
576     */
577    public static final long[] multiply(final long[][] matrix,
578            final long[] array) {
579        int rows = _rows(matrix);
580        int columns = _columns(matrix);
581
582        if (rows != array.length) {
583            throw new IllegalArgumentException(
584                    "preMultiply : array does not have the same number of "
585                            + "elements (" + array.length
586                            + ") as the number of rows " + "of the matrix ("
587                            + rows + ")");
588        }
589
590        long[] returnValue = new long[columns];
591
592        for (int i = 0; i < columns; i++) {
593            long sum = 0L;
594
595            for (int j = 0; j < rows; j++) {
596                sum += matrix[j][i] * array[j];
597            }
598
599            returnValue[i] = sum;
600        }
601
602        return returnValue;
603    }
604
605    /** Return a new array that is constructed from the argument by
606     *  post-multiplying the matrix by an array (treated as a row vector).
607     *  The number of columns of the matrix must equal the number of elements
608     *  in the array. The returned array will have a length equal to the number
609     *  of rows of the matrix.
610     */
611    public static final long[] multiply(final long[] array,
612            final long[][] matrix) {
613        int rows = _rows(matrix);
614        int columns = _columns(matrix);
615
616        if (columns != array.length) {
617            throw new IllegalArgumentException(
618                    "postMultiply() : array does not have the same number "
619                            + "of elements (" + array.length
620                            + ") as the number of " + "columns of the matrix ("
621                            + columns + ")");
622        }
623
624        long[] returnValue = new long[rows];
625
626        for (int i = 0; i < rows; i++) {
627            long sum = 0L;
628
629            for (int j = 0; j < columns; j++) {
630                sum += matrix[i][j] * array[j];
631            }
632
633            returnValue[i] = sum;
634        }
635
636        return returnValue;
637    }
638
639    /** Return a new matrix that is constructed from the argument by
640     *  multiplying the first matrix by the second one.
641     *  Note this operation is not commutative,
642     *  so care must be taken in the ordering of the arguments.
643     *  The number of columns of matrix1
644     *  must equal the number of rows of matrix2. If matrix1 is of
645     *  size m x n, and matrix2 is of size n x p, the returned matrix
646     *  will have size m x p.
647     *
648     *  <p>Note that this method is different from the other multiply()
649     *  methods in that this method does not do pointwise multiplication.
650     *
651     *  @see #multiplyElements(long[][], long[][])
652     *  @param matrix1 The first matrix of longs.
653     *  @param matrix2 The second matrix of longs.
654     *  @return A new matrix of longs.
655     */
656    public static final long[][] multiply(long[][] matrix1, long[][] matrix2) {
657        long[][] returnValue = new long[_rows(matrix1)][matrix2[0].length];
658
659        for (int i = 0; i < _rows(matrix1); i++) {
660            for (int j = 0; j < matrix2[0].length; j++) {
661                long sum = 0L;
662
663                for (int k = 0; k < matrix2.length; k++) {
664                    sum += matrix1[i][k] * matrix2[k][j];
665                }
666
667                returnValue[i][j] = sum;
668            }
669        }
670
671        return returnValue;
672    }
673
674    /** Return a new matrix that is constructed by element by element
675     *  multiplication of the two matrix arguments.  If the two
676     *  matrices are not the same size, throw an
677     *  IllegalArgumentException.
678     *  <p>Note that this method does pointwise matrix multiplication.
679     *  See {@link #multiply(long[][], long[][])} for standard
680     *  matrix multiplication.
681     */
682    public static final long[][] multiplyElements(final long[][] matrix1,
683            final long[][] matrix2) {
684        int rows = _rows(matrix1);
685        int columns = _columns(matrix1);
686
687        _checkSameDimension("multiplyElements", matrix1, matrix2);
688
689        long[][] returnValue = new long[rows][columns];
690
691        for (int i = 0; i < rows; i++) {
692            for (int j = 0; j < columns; j++) {
693                returnValue[i][j] = matrix1[i][j] * matrix2[i][j];
694            }
695        }
696
697        return returnValue;
698    }
699
700    /** Return a new matrix that is the additive inverse of the
701     *  argument matrix.
702     */
703    public static final long[][] negative(final long[][] matrix) {
704        int rows = _rows(matrix);
705        int columns = _columns(matrix);
706
707        long[][] returnValue = new long[rows][columns];
708
709        for (int i = 0; i < rows; i++) {
710            for (int j = 0; j < columns; j++) {
711                returnValue[i][j] = -matrix[i][j];
712            }
713        }
714
715        return returnValue;
716    }
717
718    /** Return a new matrix that is constructed from the argument by
719     *  arithmetically shifting the elements in the matrix by the
720     *  second argument.  If the second argument is positive, the
721     *  elements are shifted left by the second argument. If the
722     *  second argument is negative, the elements are shifted right
723     *  (arithmetically, with the &gt;&gt;&gt; operator) by the absolute value
724     *  of the second argument. If the second argument is 0, no
725     *  operation is performed (the matrix is just copied).
726     *  @param matrix A first matrix of longs.
727     *  @param shiftAmount The amount to shift by, positive for left shift,
728     *  negative for right shift.
729     *  @return A new matrix of longs.  */
730    public static final long[][] shiftArithmetic(final long[][] matrix,
731            final int shiftAmount) {
732        int rows = _rows(matrix);
733        int columns = _columns(matrix);
734
735        long[][] returnValue = new long[rows][columns];
736
737        if (shiftAmount >= 0) {
738            for (int i = 0; i < rows; i++) {
739                for (int j = 0; j < columns; j++) {
740                    returnValue[i][j] = matrix[i][j] << shiftAmount;
741                }
742            }
743        } else if (shiftAmount < 0) {
744            for (int i = 0; i < rows; i++) {
745                for (int j = 0; j < columns; j++) {
746                    returnValue[i][j] = matrix[i][j] >>> -shiftAmount;
747                }
748            }
749        }
750
751        return returnValue;
752    }
753
754    /** Return a new matrix that is constructed from the argument by
755     *  logically shifting the elements in the matrix by the second
756     *  argument.  If the second argument is positive, the elements
757     *  are shifted left by the second argument. If the second
758     *  argument is negative, the elements are shifted right
759     *  (logically, with the &gt;&gt; operator) by the absolute value of the
760     *  second argument. If the second argument is 0, no operation is
761     *  performed (the matrix is just copied).
762     *  @param matrix A first matrix of longs.
763     *  @param shiftAmount The amount to shift by, positive for left shift,
764     *  negative for right shift.
765     *  @return A new matrix of longs.  */
766    public static final long[][] shiftLogical(final long[][] matrix,
767            final int shiftAmount) {
768        int rows = _rows(matrix);
769        int columns = _columns(matrix);
770
771        long[][] returnValue = new long[rows][columns];
772
773        if (shiftAmount >= 0) {
774            for (int i = 0; i < rows; i++) {
775                for (int j = 0; j < columns; j++) {
776                    returnValue[i][j] = matrix[i][j] << shiftAmount;
777                }
778            }
779        } else if (shiftAmount < 0) {
780            for (int i = 0; i < rows; i++) {
781                for (int j = 0; j < columns; j++) {
782                    returnValue[i][j] = matrix[i][j] >> -shiftAmount;
783                }
784            }
785        }
786
787        return returnValue;
788    }
789
790    /** Return a new matrix that is constructed from the argument by
791     *  subtracting the second matrix from the first one.  If the two
792     *  matrices are not the same size, throw an
793     *  IllegalArgumentException.
794     */
795    public static final long[][] subtract(final long[][] matrix1,
796            final long[][] matrix2) {
797        _checkSameDimension("subtract", matrix1, matrix2);
798
799        int rows = _rows(matrix1);
800        int columns = _columns(matrix1);
801
802        long[][] returnValue = new long[rows][columns];
803
804        for (int i = 0; i < rows; i++) {
805            for (int j = 0; j < columns; j++) {
806                returnValue[i][j] = matrix1[i][j] - matrix2[i][j];
807            }
808        }
809
810        return returnValue;
811    }
812
813    /** Return the sum of the elements of a matrix.
814     *  @return The sum of the elements of the matrix.
815     */
816    public static final long sum(final long[][] matrix) {
817        long sum = 0L;
818
819        for (long[] element : matrix) {
820            for (int j = 0; j < element.length; j++) {
821                sum += element[j];
822            }
823        }
824
825        return sum;
826    }
827
828    /** Return a new matrix that is formed by converting the long values
829     *  in the argument matrix to complex numbers. Each complex number
830     *  has a real part equal to the value in the argument matrix and a
831     *  zero imaginary part.
832     *
833     *  @param matrix A matrix of long values.
834     *  @return A new matrix of complex numbers.
835     */
836    public static final Complex[][] toComplexMatrix(final long[][] matrix) {
837        int rows = _rows(matrix);
838        int columns = _columns(matrix);
839
840        Complex[][] returnValue = new Complex[rows][columns];
841
842        for (int i = 0; i < rows; i++) {
843            for (int j = 0; j < columns; j++) {
844                returnValue[i][j] = new Complex(matrix[i][j], 0.0);
845            }
846        }
847
848        return returnValue;
849    }
850
851    /** Return a new matrix that is formed by converting the longs in
852     *  the argument matrix to doubles.
853     *  @param matrix An matrix of long.
854     *  @return A new matrix of doubles.
855     */
856    public static final double[][] toDoubleMatrix(final long[][] matrix) {
857        int rows = _rows(matrix);
858        int columns = _columns(matrix);
859
860        double[][] returnValue = new double[rows][columns];
861
862        for (int i = 0; i < rows; i++) {
863            for (int j = 0; j < columns; j++) {
864                returnValue[i][j] = matrix[i][j];
865            }
866        }
867
868        return returnValue;
869    }
870
871    /** Return a new matrix that is formed by converting the longs in
872     *  the argument matrix to floats.
873     *  @param matrix An matrix of long.
874     *  @return A new matrix of floats.
875     */
876    public static final float[][] toFloatMatrix(final long[][] matrix) {
877        int rows = _rows(matrix);
878        int columns = _columns(matrix);
879
880        float[][] returnValue = new float[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];
885            }
886        }
887
888        return returnValue;
889    }
890
891    /** Return a new matrix that is formed by converting the longs in
892     *  the argument matrix to integers.
893     *  @param matrix An matrix of long.
894     *  @return A new matrix of integers.
895     */
896    public static final int[][] toIntegerMatrix(final long[][] matrix) {
897        int rows = _rows(matrix);
898        int columns = _columns(matrix);
899
900        int[][] returnValue = new int[rows][columns];
901
902        for (int i = 0; i < rows; i++) {
903            for (int j = 0; j < columns; j++) {
904                returnValue[i][j] = (int) matrix[i][j];
905            }
906        }
907
908        return returnValue;
909    }
910
911    /** Return a new matrix of longs that is initialized from a 1-D array.
912     *  The format of the array must be (0, 0), (0, 1), ..., (0, n-1), (1, 0),
913     *  (1, 1), ..., (m-1, n-1) where the output matrix is to be m x n and
914     *  entries are denoted by (row, column).
915     *  @param array An array of longs.
916     *  @param rows An integer representing the number of rows of the new
917     *  matrix.
918     *  @param cols An integer representing the number of columns of the new
919     *  matrix.
920     *  @return A new matrix of longs.
921     */
922    public static final long[][] toMatrixFromArray(long[] array, int rows,
923            int cols) {
924        long[][] returnValue = new long[rows][cols];
925
926        for (int i = 0; i < rows; i++) {
927            System.arraycopy(array, i * cols, returnValue[i], 0, cols);
928        }
929
930        return returnValue;
931    }
932
933    /** Return a new String representing the matrix, formatted as
934     *  in Java array initializers.
935     */
936    public static final String toString(final long[][] matrix) {
937        return toString(matrix, ", ", "{", "}", "{", ", ", "}");
938    }
939
940    /** Return a new String representing the matrix, formatted as
941     *  specified by the ArrayStringFormat argument.
942     *  To get a String in the Ptolemy expression language format,
943     *  call this method with ArrayStringFormat.exprASFormat as the
944     *  format argument.
945     */
946    public static final String toString(final long[][] matrix,
947            String elementDelimiter, String matrixBegin, String matrixEnd,
948            String vectorBegin, String vectorDelimiter, String vectorEnd) {
949        StringBuffer sb = new StringBuffer();
950        sb.append(matrixBegin);
951
952        for (int i = 0; i < _rows(matrix); i++) {
953            sb.append(vectorBegin);
954
955            for (int j = 0; j < _columns(matrix); j++) {
956                sb.append(Long.toString(matrix[i][j]));
957
958                if (j < _columns(matrix) - 1) {
959                    sb.append(elementDelimiter);
960                }
961            }
962
963            sb.append(vectorEnd);
964
965            if (i < _rows(matrix) - 1) {
966                sb.append(vectorDelimiter);
967            }
968        }
969
970        sb.append(matrixEnd);
971
972        return new String(sb);
973    }
974
975    /** Return the trace of a square matrix, which is the sum of the
976     *  diagonal entries A<sub>11</sub> + A<sub>22</sub> + ... + A<sub>nn</sub>
977     *  Throw an IllegalArgumentException if the matrix is not square.
978     *  Note that the trace of a matrix is equal to the sum of its eigenvalues.
979     */
980    public static final long trace(final long[][] matrix) {
981        int dim = _checkSquare("trace", matrix);
982        long sum = 0L;
983
984        for (int i = 0; i < dim; i++) {
985            sum += matrix[i][i];
986        }
987
988        return sum;
989    }
990
991    /** Return a new matrix that is constructed by transposing the input
992     *  matrix. If the input matrix is m x n, the output matrix will be
993     *  n x m.
994     */
995    public static final long[][] transpose(final long[][] matrix) {
996        int rows = _rows(matrix);
997        int columns = _columns(matrix);
998
999        long[][] returnValue = new long[columns][rows];
1000
1001        for (int i = 0; i < rows; i++) {
1002            for (int j = 0; j < columns; j++) {
1003                returnValue[j][i] = matrix[i][j];
1004            }
1005        }
1006
1007        return returnValue;
1008    }
1009
1010    /** Return true if the elements of the two matrices differ by no more
1011     *  than the specified distance. If <i>distance</i> is negative, return
1012     *  false.
1013     *  @param matrix1 The first matrix.
1014     *  @param matrix2 The second matrix.
1015     *  @param distance The distance to use for comparison.
1016     *  @return True if the elements of the two matrices are within the
1017     *   specified distance.
1018     *  @exception IllegalArgumentException If the matrices do not have the same dimension.
1019     *          This is a run-time exception, so it need not be declared explicitly.
1020     */
1021    public static final boolean within(final long[][] matrix1,
1022            final long[][] matrix2, long distance) {
1023        int rows = _rows(matrix1);
1024        int columns = _columns(matrix1);
1025
1026        _checkSameDimension("within", matrix1, matrix2);
1027
1028        for (int i = 0; i < rows; i++) {
1029            for (int j = 0; j < columns; j++) {
1030                if (matrix1[i][j] > matrix2[i][j] + distance
1031                        || matrix1[i][j] < matrix2[i][j] - distance) {
1032                    return false;
1033                }
1034            }
1035        }
1036
1037        return true;
1038    }
1039
1040    /** Return true if the elements of the two matrices differ by no more
1041     *  than the specified distances. If any element of <i>errorMatrix</i> is
1042     *  negative, return false.
1043     *  @param matrix1 The first matrix.
1044     *  @param matrix2 The second matrix.
1045     *  @param errorMatrix The distance to use for comparison.
1046     *  @return True if the elements of the two matrices are within the
1047     *   specified distance.
1048     *  @exception IllegalArgumentException If the matrices do not have the same dimension.
1049     *          This is a run-time exception, so it need not be declared explicitly.
1050     */
1051    public static final boolean within(final long[][] matrix1,
1052            final long[][] matrix2, final long[][] errorMatrix) {
1053        int rows = _rows(matrix1);
1054        int columns = _columns(matrix1);
1055
1056        _checkSameDimension("within", matrix1, matrix2);
1057        _checkSameDimension("within", matrix1, errorMatrix);
1058
1059        for (int i = 0; i < rows; i++) {
1060            for (int j = 0; j < columns; j++) {
1061                if (matrix1[i][j] > matrix2[i][j] + errorMatrix[i][j]
1062                        || matrix1[i][j] < matrix2[i][j] - errorMatrix[i][j]) {
1063                    return false;
1064                }
1065            }
1066        }
1067
1068        return true;
1069    }
1070
1071    /** Check that the two matrix arguments are of the same dimension.
1072     *  If they are not, an IllegalArgumentException is thrown.
1073     *  @param caller A string representing the caller method name.
1074     *  @param matrix1 A matrix of longs.
1075     *  @param matrix2 A matrix of longs.
1076     */
1077    protected static final void _checkSameDimension(final String caller,
1078            final long[][] matrix1, final long[][] matrix2) {
1079        int rows = _rows(matrix1);
1080        int columns = _columns(matrix1);
1081
1082        if (rows != _rows(matrix2) || columns != _columns(matrix2)) {
1083            throw new IllegalArgumentException("ptolemy.math.LongMatrixMath."
1084                    + caller + "() : one matrix " + _dimensionString(matrix1)
1085                    + " is not the same size as another matrix "
1086                    + _dimensionString(matrix2) + ".");
1087        }
1088    }
1089
1090    /** Check that the argument matrix is a square matrix. If the matrix is not
1091     *  square, an IllegalArgumentException is thrown.
1092     *  @param caller A string representing the caller method name.
1093     *  @param matrix A matrix of longs.
1094     *  @return The dimension of the square matrix.
1095     */
1096    protected static final int _checkSquare(final String caller,
1097            final long[][] matrix) {
1098        if (_rows(matrix) != _columns(matrix)) {
1099            throw new IllegalArgumentException("ptolemy.math.LongMatrixMath."
1100                    + caller + "() : matrix argument "
1101                    + _dimensionString(matrix) + " is not a square matrix.");
1102        }
1103
1104        return _rows(matrix);
1105    }
1106
1107    /** Return the number of columns of a matrix.
1108     *  @param matrix The matrix.
1109     *  @return The number of columns.
1110     */
1111    protected static final int _columns(final long[][] matrix) {
1112        return matrix[0].length;
1113    }
1114
1115    /** Return a string that describes the number of rows and columns.
1116     *  @param matrix The matrix that is to be described.
1117     *  @return a string describing the dimensions of this matrix.
1118     */
1119    protected static final String _dimensionString(final long[][] matrix) {
1120        return "[" + _rows(matrix) + " x " + _columns(matrix) + "]";
1121    }
1122
1123    /** Return the number of rows of a matrix. */
1124    protected static final int _rows(final long[][] matrix) {
1125        return matrix.length;
1126    }
1127}