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