001/* A token that contains a 2-D int matrix.
002
003 Copyright (c) 1998-2018 The Regents of the University of California.
004 All rights reserved.
005 Permission is hereby granted, without written agreement and without
006 license or royalty fees, to use, copy, modify, and distribute this
007 software and its documentation for any purpose, provided that the above
008 copyright notice and the following two paragraphs appear in all copies
009 of this software.
010
011 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
012 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
013 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
014 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
015 SUCH DAMAGE.
016
017 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
018 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
019 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
020 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
021 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
022 ENHANCEMENTS, OR MODIFICATIONS.
023
024 PT_COPYRIGHT_VERSION_2
025 COPYRIGHTENDKEY
026
027
028 */
029package ptolemy.data;
030
031import ptolemy.data.expr.ASTPtRootNode;
032import ptolemy.data.expr.ParseTreeEvaluator;
033import ptolemy.data.expr.PtParser;
034import ptolemy.data.type.BaseType;
035import ptolemy.data.type.Type;
036import ptolemy.data.type.TypeLattice;
037import ptolemy.graph.CPO;
038import ptolemy.kernel.util.IllegalActionException;
039import ptolemy.kernel.util.InternalErrorException;
040import ptolemy.math.Complex;
041import ptolemy.math.ComplexMatrixMath;
042import ptolemy.math.DoubleMatrixMath;
043import ptolemy.math.IntegerArrayMath;
044import ptolemy.math.IntegerMatrixMath;
045import ptolemy.math.LongMatrixMath;
046
047///////////////////////////////////////////////////////////////////
048//// IntMatrixToken
049
050/**
051 A token that contains a 2-D int matrix.
052
053 @author Yuhong Xiong, Jeff Tsay, Steve Neuendorffer
054 @version $Id$
055 @since Ptolemy II 0.2
056 @Pt.ProposedRating Green (neuendor)
057 @Pt.AcceptedRating Yellow (wbwu)
058 */
059public class IntMatrixToken extends MatrixToken {
060    /** Construct an IntMatrixToken with a one by one matrix. The
061     *  only element in the matrix has value 0.0
062     */
063    public IntMatrixToken() {
064        _value = new int[1];
065        _value[0] = 0;
066        _rowCount = 1;
067        _columnCount = 1;
068    }
069
070    /** Construct a IntMatrixToken with the specified 1-D matrix.
071     *  Make a copy of the matrix and store the copy,
072     *  so that changes on the specified matrix after this token is
073     *  constructed will not affect the content of this token.
074     *  @param value The 1-D matrix.
075     *  @param rows The number of rows.
076     *  @param columns The number of columns.
077     *  @exception IllegalActionException If the specified matrix
078     *   is null.
079     */
080    public IntMatrixToken(int[] value, int rows, int columns)
081            throws IllegalActionException {
082        this(value, rows, columns, DO_COPY);
083    }
084
085    /** Construct a IntMatrixToken with the specified 1-D matrix.
086     *  If copy is DO_COPY, make a copy of the matrix and store the copy,
087     *  so that changes on the specified matrix after this token is
088     *  constructed will not affect the content of this token.
089     *  If copy is DO_NOT_COPY, just reference the matrix (do not copy
090     *  its contents). This saves some time and memory.
091     *  The argument matrix should NOT be modified after this constructor
092     *  is called to preserve immutability.
093     *  @param value The 1-D matrix.
094     *  @param rows The number of rows.
095     *  @param columns The number of columns.
096     *  @param copy If this parameter is
097     *  {@link ptolemy.data.MatrixToken#DO_COPY}, then the value matrix
098     *  is copied.  If this parameter is
099     *  {@link ptolemy.data.MatrixToken#DO_NOT_COPY}, then the value matrix
100     *  is NOT copied and should not be modified after construction of this
101     *  object.
102     *  @exception IllegalActionException If the specified matrix
103     *   is null.
104     */
105    public IntMatrixToken(int[] value, int rows, int columns, int copy)
106            throws IllegalActionException {
107        if (value == null) {
108            throw new IllegalActionException(
109                    "IntMatrixToken: The specified " + "matrix is null.");
110        }
111
112        _rowCount = rows;
113        _columnCount = columns;
114
115        if (copy == DO_COPY) {
116            _value = IntegerArrayMath.allocCopy(value);
117        } else {
118            _value = value;
119        }
120    }
121
122    /** Construct a IntMatrixToken with the specified 2-D matrix.
123     *  Make a copy of the matrix and store the copy,
124     *  so that changes on the specified matrix after this token is
125     *  constructed will not affect the content of this token.
126     *  @param value The 2-D matrix used to initialize this object.
127     *  @exception IllegalActionException If the specified matrix
128     *   is null.
129     */
130    public IntMatrixToken(int[][] value) throws IllegalActionException {
131        this(value, DO_COPY);
132    }
133
134    /** Construct a IntMatrixToken with the specified 2-D matrix.
135     *  If copy is DO_COPY, make a copy of the matrix and store the copy,
136     *  so that changes on the specified matrix after this token is
137     *  constructed will not affect the content of this token.
138     *  If copy is DO_NOT_COPY, just reference the matrix (do not copy
139     *  its contents). This saves some time and memory.
140     *  The argument matrix should NOT be modified after this constructor
141     *  is called to preserve immutability.
142     *  <p>
143     *  Since the DO_NOT_COPY option requires some care, this constructor
144     *  should  be protected, but is not.
145     *  @param value The 2-D matrix used to initialize this object.
146     *  @param copy If this parameter is
147     *  {@link ptolemy.data.MatrixToken#DO_COPY}, then the value matrix
148     *  is copied.  If this parameter is
149     *  {@link ptolemy.data.MatrixToken#DO_NOT_COPY}, then the value matrix
150     *  is NOT copied and should not be modified after construction of this
151     *  object.
152
153     *  @exception IllegalActionException If the specified matrix
154     *   is null.
155     */
156    public IntMatrixToken(int[][] value, int copy)
157            throws IllegalActionException {
158        if (value == null) {
159            throw new IllegalActionException(
160                    "IntMatrixToken: The specified " + "matrix is null.");
161        }
162
163        _initialize(value);
164    }
165
166    /** Construct an IntMatrixToken from the specified string.
167     *  @param init A string expression of a 2-D int matrix.
168     *  @exception IllegalActionException If the string does
169     *   not contain a parsable 2-D int matrix.
170     */
171    public IntMatrixToken(String init) throws IllegalActionException {
172        PtParser parser = new PtParser();
173        ASTPtRootNode tree = parser.generateParseTree(init);
174        Token token = new ParseTreeEvaluator().evaluateParseTree(tree);
175
176        if (token instanceof IntMatrixToken) {
177            int[][] value = ((IntMatrixToken) token).intMatrix();
178            _initialize(value);
179        } else {
180            throw new IllegalActionException("A matrix token cannot be"
181                    + " created from the expression '" + init + "'");
182        }
183    }
184
185    /** Construct an IntMatrixToken from the specified array of
186     *  tokens.  The tokens in the array must be scalar tokens
187     *  convertible into integers.
188     *  @param tokens The array of tokens, which must contains
189     *  rows * columns ScalarTokens.
190     *  @param rows The number of rows in the matrix to be created.
191     *  @param columns The number of columns in the matrix to be
192     *  created.
193     *  @exception IllegalActionException If the array of tokens is
194     *  null, or the length of the array is not correct, or if one of
195     *  the elements of the array is null, or if one of the elements
196     *  of the array cannot be losslessly converted to an integer.
197     */
198    public IntMatrixToken(Token[] tokens, int rows, int columns)
199            throws IllegalActionException {
200        int elements = rows * columns;
201
202        if (tokens == null) {
203            throw new IllegalActionException(
204                    "IntMatrixToken: The specified" + " array is null.");
205        }
206
207        if (tokens.length != elements) {
208            throw new IllegalActionException("IntMatrixToken: The specified"
209                    + " array is not of the correct length");
210        }
211
212        _rowCount = rows;
213        _columnCount = columns;
214        _value = new int[elements];
215
216        for (int i = 0; i < elements; i++) {
217            Token token = tokens[i];
218
219            if (token instanceof ScalarToken) {
220                _value[i] = ((ScalarToken) token).intValue();
221            } else {
222                throw new IllegalActionException("IntMatrixToken: Element " + i
223                        + " in the array with value " + token
224                        + " is not a ScalarToken");
225            }
226        }
227    }
228
229    ///////////////////////////////////////////////////////////////////
230    ////                         public methods                    ////
231
232    /** Return the content of this token as a 2-D Complex matrix.
233     *  @return A 2-D Complex matrix
234     */
235    @Override
236    public Complex[][] complexMatrix() {
237        return ComplexMatrixMath.toMatrixFromArray(
238                IntegerArrayMath.toComplexArray(_value), _rowCount,
239                _columnCount);
240    }
241
242    /** Convert the specified token into an instance of IntMatrixToken.
243     *  This method does lossless conversion.
244     *  If the argument is already an instance of IntMatrixToken,
245     *  it is returned without any change. Otherwise, if the argument
246     *  is below IntMatrixToken in the type hierarchy, it is converted to
247     *  an instance of IntMatrixToken or one of the subclasses of
248     *  IntMatrixToken and returned. If none of the above condition is
249     *  met, an exception is thrown.
250     *  @param token The token to be converted to a IntMatrixToken.
251     *  @return A IntMatrixToken
252     *  @exception IllegalActionException If the conversion cannot
253     *   be carried out.
254     */
255    public static IntMatrixToken convert(Token token)
256            throws IllegalActionException {
257        if (token instanceof IntMatrixToken) {
258            return (IntMatrixToken) token;
259        }
260
261        int compare = TypeLattice.compare(BaseType.INT_MATRIX, token);
262
263        if (compare == CPO.LOWER || compare == CPO.INCOMPARABLE) {
264            throw new IllegalActionException(
265                    notSupportedIncomparableConversionMessage(token, "[int]"));
266        }
267
268        // try int
269        //   compare = TypeLattice.compare(BaseType.INT, token);
270        //         if (compare == CPO.SAME || compare == CPO.HIGHER) {
271        //             IntToken tem = IntToken.convert(token);
272        //             int[][] result = new int[1][1];
273        //             result[0][0] = tem.intValue();
274        //             return new IntMatrixToken(result);
275        //         }
276        // try ByteMatrix?
277        //       compare = TypeLattice.compare(BaseType.INT_MATRIX, token);
278        //         if (compare == CPO.SAME || compare == CPO.HIGHER) {
279        //             IntMatrixToken tem = convert(token);
280        //             int[][] result = tem.intMatrix();
281        //             return new IntMatrixToken(result);
282        //         }
283        // The argument is below IntMatrixToken in the type hierarchy,
284        // but I don't recognize it.
285        throw new IllegalActionException(
286                notSupportedConversionMessage(token, "[int]"));
287    }
288
289    /** Convert the specified scalar token into an instance of
290     *  IntMatrixToken.  The resulting matrix will be square, with
291     *  the number of rows and columns equal to the given size.
292     *  This method does lossless conversion.
293     *  @param token The token to be converted to a IntMatrixToken.
294     *  @param size The number of rows and columns of the resulting matrix.
295     *  @return A IntMatrixToken
296     *  @exception IllegalActionException If the conversion cannot
297     *  be carried out.
298     */
299    public static Token convert(ScalarToken token, int size)
300            throws IllegalActionException {
301        // Check to make sure that the token is convertible to INT.
302        int compare = TypeLattice.compare(BaseType.INT, token);
303
304        if (compare == CPO.SAME || compare == CPO.HIGHER) {
305            if (token.isNil()) {
306                throw new IllegalActionException(
307                        Token.notSupportedConversionMessage(token, "[int]"));
308            }
309            IntToken intToken = IntToken.convert(token);
310            int intValue = intToken.intValue();
311            int[] result = new int[size * size];
312
313            for (int i = 0; i < size; i++) {
314                result[i] = intValue;
315            }
316
317            return new IntMatrixToken(result, size, size, DO_NOT_COPY);
318        }
319
320        throw new IllegalActionException(
321                notSupportedConversionMessage(token, "[int]"));
322    }
323
324    /** Return a new matrix that is a sub-matrix of this matrix.
325     *  @param rowStart The row to start on.
326     *  @param colStart The column to start on.
327     *  @param rowSpan The number of rows to copy.
328     *  @param colSpan The number of columns to copy.
329     *  @return a sub-matrix of this matrix.
330     *  @exception IllegalActionException If the returned matrix is empty or if the specified
331     *   parameters result in out of bounds accesses.
332     */
333    @Override
334    public MatrixToken crop(int rowStart, int colStart, int rowSpan,
335            int colSpan) throws IllegalActionException {
336        int[][] value = this.intMatrix();
337        try {
338            int[][] result = IntegerMatrixMath.crop(value, rowStart, colStart,
339                    rowSpan, colSpan);
340            return new IntMatrixToken(result);
341        } catch (ArrayIndexOutOfBoundsException ex) {
342            throw new IllegalActionException(
343                    "Matrix crop indices out of bounds (rowStart = " + rowStart
344                            + ", colStart = " + colStart + ", rowSpan = "
345                            + rowSpan + ", colSpan = " + colSpan + ").");
346        }
347    }
348
349    /** Return the content of this token as a 2-D double matrix.
350     *  @return A 2-D double matrix.
351     */
352    @Override
353    public double[][] doubleMatrix() {
354        return DoubleMatrixMath.toMatrixFromArray(
355                IntegerArrayMath.toDoubleArray(_value), _rowCount,
356                _columnCount);
357    }
358
359    /** Return true if the argument is an instance of IntMatrixToken
360     *  of the same dimensions and the corresponding elements of the matrices
361     *  are equal.
362     *  @param object An instance of Object.
363     *  @return True if the argument is an instance of IntMatrixToken
364     *   of the same dimensions and the corresponding elements of the
365     *   matrices are equal.
366     */
367    @Override
368    public boolean equals(Object object) {
369        if (object == null) {
370            return false;
371        }
372        // This test rules out instances of a subclass.
373        if (object.getClass() != getClass()) {
374            return false;
375        }
376
377        IntMatrixToken matrixArgument = (IntMatrixToken) object;
378
379        if (_rowCount != matrixArgument.getRowCount()) {
380            return false;
381        }
382
383        if (_columnCount != matrixArgument.getColumnCount()) {
384            return false;
385        }
386
387        int[] value = matrixArgument._value;
388        int elements = _rowCount * _columnCount;
389
390        for (int i = 0; i < elements; i++) {
391            if (_value[i] != value[i]) {
392                return false;
393            }
394        }
395
396        return true;
397    }
398
399    /** Return the number of columns in the matrix.
400     *  @return The number of columns in the matrix.
401     */
402    @Override
403    public int getColumnCount() {
404        return _columnCount;
405    }
406
407    /** Return the element of the matrix at the specified
408     *  row and column in a IntToken.
409     *  @param row The row index of the desired element.
410     *  @param column The column index of the desired element.
411     *  @return A IntToken containing the matrix element.
412     *  @exception ArrayIndexOutOfBoundsException If the specified
413     *   row or column number is outside the range of the matrix.
414     */
415    @Override
416    public Token getElementAsToken(int row, int column)
417            throws ArrayIndexOutOfBoundsException {
418        return new IntToken(_value[row * _columnCount + column]);
419    }
420
421    /** Return the element of the contained matrix at the specified
422     *  row and column.
423     *  @param row The row index of the desired element.
424     *  @param column The column index of the desired element.
425     *  @return The int at the specified matrix entry.
426     *  @exception ArrayIndexOutOfBoundsException If the specified
427     *   row or column number is outside the range of the matrix.
428     */
429    public int getElementAt(int row, int column) {
430        return _value[row * _columnCount + column];
431    }
432
433    /** Return the Type of the tokens contained in this matrix token.
434     *  This must be a type representing a scalar token.
435     *  @return BaseType.INT.
436     */
437    @Override
438    public Type getElementType() {
439        return BaseType.INT;
440    }
441
442    /** Return the number of rows in the matrix.
443     *  @return The number of rows in the matrix.
444     */
445    @Override
446    public int getRowCount() {
447        return _rowCount;
448    }
449
450    /** Return the type of this token.
451     *  @return BaseType.INT_MATRIX
452     */
453    @Override
454    public Type getType() {
455        return BaseType.INT_MATRIX;
456    }
457
458    /** Return a hash code value for this token. This method returns the
459     *  sum of the elements.
460     *  @return A hash code value for this token.
461     */
462    @Override
463    public int hashCode() {
464        int code = 0;
465        int elements = _rowCount * _columnCount;
466
467        for (int i = 0; i < elements; i++) {
468            code += _value[i];
469        }
470
471        return code;
472    }
473
474    /** Return the content in the token as a 2-D int matrix.
475     *  The returned matrix is a copy so the caller is free to
476     *  modify it.
477     *  @return A 2-D int matrix.
478     */
479    @Override
480    public int[][] intMatrix() {
481        return IntegerMatrixMath.toMatrixFromArray(_value, _rowCount,
482                _columnCount);
483    }
484
485    /** Join a matrix of matrices into a single matrix by tiling.
486     *  All matrices in the matrix must be of the same type,
487     *  the same type as this matrix. But none of them needs to
488     *  actually be this matrix. This base class simply throws
489     *  an exception. Derived classes provide the implementation.
490     *  The number of columns in the resulting matrix is the sum
491     *  of the number of columns in the first row of the argument.
492     *  The number of rows in the resulting matrix is the sum
493     *  of the number of rows in the first column of the argument.
494     *  The matrices are copied into the result starting at the
495     *  position determined by the first row or column.
496     *  If the matrices overlap, then while copying left to right,
497     *  top-to-bottom, data will be overwritten. If there are gaps,
498     *  the resulting matrix will be filled with zeros.
499     *  @param matrices A two-dimensional array of matrix tokens.
500     *  @return A new matrix token of the same type as the elements
501     *   in the input matrix of matrix tokens.
502     *  @exception IllegalActionException If the types of the matrices
503     *   in the input are not all the same, or if tiling fails due
504     *   to size incompatibilities, or if the input matrix has no
505     *   tokens.
506     */
507    @Override
508    public MatrixToken join(MatrixToken[][] matrices)
509            throws IllegalActionException {
510        if (matrices == null || matrices.length == 0
511                || matrices[0].length == 0) {
512            throw new IllegalActionException("matrixJoin: No input matrices.");
513        }
514        // Calculate the size of the result.
515        // This assumes the matrices tile.
516        int rows = 0;
517        int columns = 0;
518        for (MatrixToken[] matrice : matrices) {
519            rows += matrice[0].getRowCount();
520        }
521        for (int j = 0; j < matrices[0].length; j++) {
522            columns += matrices[0][j].getColumnCount();
523        }
524        int[][] tiled = new int[rows][columns];
525        int row = 0;
526        for (int i = 0; i < matrices.length; i++) {
527            int column = 0;
528            for (int j = 0; j < matrices[i].length; j++) {
529                if (!(matrices[i][j] instanceof IntMatrixToken)) {
530                    throw new IllegalActionException(
531                            "matrixJoin: matrices not all of the same type.");
532                }
533                int rowCount = matrices[i][j].getRowCount();
534                if (row + rowCount > rows) {
535                    rowCount = rows - row;
536                }
537                int columnCount = matrices[i][j].getColumnCount();
538                if (column + columnCount > columns) {
539                    columnCount = columns - column;
540                }
541                IntegerMatrixMath.matrixCopy(matrices[i][j].intMatrix(), 0, 0,
542                        tiled, row, column, rowCount, columnCount);
543                // Starting position for the next column.
544                column += matrices[0][j].getColumnCount();
545            }
546            // Starting position for the next column.
547            row += matrices[i][0].getRowCount();
548        }
549        return new IntMatrixToken(tiled);
550    }
551
552    /** Return the content of this token as a 2-D long matrix.
553     *  @return A 2-D long matrix.
554     */
555    @Override
556    public long[][] longMatrix() {
557        return LongMatrixMath.toMatrixFromArray(
558                IntegerArrayMath.toLongArray(_value), _rowCount, _columnCount);
559    }
560
561    /** Return a new Token representing the left multiplicative
562     *  identity. The returned token contains an identity matrix
563     *  whose dimensions are the same as the number of rows of
564     *  the matrix contained in this token.
565     *  @return A new IntMatrixToken containing the left multiplicative
566     *   identity.
567     */
568    @Override
569    public Token one() {
570        try {
571            return new IntMatrixToken(IntegerMatrixMath.identity(_rowCount),
572                    DO_NOT_COPY);
573        } catch (IllegalActionException illegalAction) {
574            // should not happen
575            throw new InternalErrorException(
576                    "IntMatrixToken.one: " + "Cannot create identity matrix.");
577        }
578    }
579
580    /** Return a new Token representing the right multiplicative
581     *  identity. The returned token contains an identity matrix
582     *  whose dimensions are the same as the number of columns of
583     *  the matrix contained in this token.
584     *  @return A new IntMatrixToken containing the right multiplicative
585     *   identity.
586     */
587    @Override
588    public Token oneRight() {
589        try {
590            return new IntMatrixToken(IntegerMatrixMath.identity(_columnCount),
591                    DO_NOT_COPY);
592        } catch (IllegalActionException illegalAction) {
593            // should not happen
594            throw new InternalErrorException("IntMatrixToken.oneRight: "
595                    + "Cannot create identity matrix.");
596        }
597    }
598
599    /** Split this matrix into multiple matrices. See the base
600     *  class for documentation.
601     *  @param rows The number of rows per submatrix.
602     *  @param columns The number of columns per submatrix.
603     *  @return An array of matrix tokens.
604     */
605    @Override
606    public MatrixToken[][] split(int[] rows, int[] columns) {
607        MatrixToken[][] result = new MatrixToken[rows.length][columns.length];
608        int[][] source = intMatrix();
609        int row = 0;
610        for (int i = 0; i < rows.length; i++) {
611            int column = 0;
612            for (int j = 0; j < columns.length; j++) {
613                int[][] contents = new int[rows[i]][columns[j]];
614                int rowspan = rows[i];
615                if (row + rowspan > source.length) {
616                    rowspan = source.length - row;
617                }
618                int columnspan = columns[j];
619                if (column + columnspan > source[0].length) {
620                    columnspan = source[0].length - column;
621                }
622                if (columnspan > 0 && rowspan > 0) {
623                    IntegerMatrixMath.matrixCopy(source, row, column, contents,
624                            0, 0, rowspan, columnspan);
625                }
626                column += columns[j];
627                try {
628                    result[i][j] = new IntMatrixToken(contents);
629                } catch (IllegalActionException e) {
630                    throw new InternalErrorException(e);
631                }
632            }
633            row += rows[i];
634        }
635        return result;
636    }
637
638    /** Return a new Token representing the additive identity.
639     *  The returned token contains a matrix whose elements are
640     *  all zero, and the size of the matrix is the same as the
641     *  matrix contained in this token.
642     *  @return A new IntMatrixToken containing the additive identity.
643     */
644    @Override
645    public Token zero() {
646        try {
647            return new IntMatrixToken(new int[_rowCount * _columnCount],
648                    _rowCount, _columnCount, DO_NOT_COPY);
649        } catch (IllegalActionException illegalAction) {
650            // should not happen
651            throw new InternalErrorException(
652                    "IntMatrixToken.zero: " + "Cannot create zero matrix.");
653        }
654    }
655
656    ///////////////////////////////////////////////////////////////////
657    ////                         protected methods                 ////
658
659    /** Return a new token whose value is the value of the argument
660     *  Token added to the value of this Token.  It is assumed that
661     *  the type of the argument is IntMatrixToken.
662     *  @param rightArgument The token to add to this token.
663     *  @exception IllegalActionException If the units are not
664     *  compatible, or this operation is not supported by the derived
665     *  class.
666     *  @return A new IntMatrixToken containing the result.
667     */
668    @Override
669    protected MatrixToken _add(MatrixToken rightArgument)
670            throws IllegalActionException {
671        IntMatrixToken convertedArgument = (IntMatrixToken) rightArgument;
672        int[] result = IntegerArrayMath
673                .add(convertedArgument._getInternalIntArray(), _value);
674        return new IntMatrixToken(result, _rowCount, _columnCount, DO_NOT_COPY);
675    }
676
677    /** Return a new token whose value is the value of the argument
678     *  Token added to the value of each element of this Token. It is
679     *  assumed that the type of the argument is the same as the type
680     *  of each element of this class or is a matrix with one element.
681     *  @param rightArgument The token to add to this token.
682     *  @exception IllegalActionException If this operation is not
683     *  supported by the derived class.
684     *  @return A new Token containing the result.
685     */
686    @Override
687    protected MatrixToken _addElement(Token rightArgument)
688            throws IllegalActionException {
689        int scalar;
690        if (rightArgument instanceof IntMatrixToken) {
691            if (((IntMatrixToken) rightArgument).getRowCount() != 1
692                    || ((IntMatrixToken) rightArgument).getColumnCount() != 1) {
693                // Throw an exception.
694                return super._moduloElement(rightArgument);
695            }
696            scalar = ((IntMatrixToken) rightArgument).getElementAt(0, 0);
697        } else {
698            scalar = ((IntToken) rightArgument).intValue();
699        }
700        int[] result = IntegerArrayMath.add(_value, scalar);
701        return new IntMatrixToken(result, _rowCount, _columnCount, DO_NOT_COPY);
702    }
703
704    /** Return a new token whose elements are the result of dividing
705     *  the elements of this token by the argument. It is
706     *  assumed that the type of the argument is the same as the type
707     *  of each element of this class, or is an integer matrix
708     *  with one element that is of the same type.
709     *  @param rightArgument The token that divides this token.
710     *  @exception IllegalActionException If this operation is not
711     *  supported by the derived class.
712     *  @return A new Token containing the result.
713     */
714    @Override
715    protected MatrixToken _divideElement(Token rightArgument)
716            throws IllegalActionException {
717        int scalar;
718        if (rightArgument instanceof IntMatrixToken) {
719            if (((IntMatrixToken) rightArgument).getRowCount() != 1
720                    || ((IntMatrixToken) rightArgument).getColumnCount() != 1) {
721                // Throw an exception.
722                return super._moduloElement(rightArgument);
723            }
724            scalar = ((IntMatrixToken) rightArgument).getElementAt(0, 0);
725        } else {
726            scalar = ((IntToken) rightArgument).intValue();
727        }
728        int[] result = IntegerArrayMath.divide(_value, scalar);
729        return new IntMatrixToken(result, _rowCount, _columnCount, DO_NOT_COPY);
730    }
731
732    /** Return a reference to the internal 2-D matrix of ints that represents
733     *  this Token. Because no copying is done, the contents must NOT be
734     *  modified to preserve the immutability of Token.
735     *  @return An int matrix.
736     */
737    protected int[] _getInternalIntArray() {
738        return _value;
739    }
740
741    /** Return a new token whose elements are the remainders of
742     *  the elements of this token when divided by the argument.
743     *  It is guaranteed by the caller that the type of the argument
744     *  is the same as the type of each element of this class
745     *  or is a matrix with one element.
746     *  @param rightArgument The token that performs modulo on this token.
747     *  @exception IllegalActionException If this operation is not
748     *  supported by the derived class.
749     *  @return A new Token containing the result.
750     */
751    @Override
752    protected MatrixToken _moduloElement(Token rightArgument)
753            throws IllegalActionException {
754        int scalar;
755        if (rightArgument instanceof IntMatrixToken) {
756            if (((IntMatrixToken) rightArgument).getRowCount() != 1
757                    || ((IntMatrixToken) rightArgument).getColumnCount() != 1) {
758                // Throw an exception.
759                return super._moduloElement(rightArgument);
760            }
761            scalar = ((IntMatrixToken) rightArgument).getElementAt(0, 0);
762        } else {
763            scalar = ((IntToken) rightArgument).intValue();
764        }
765        int[] result = IntegerArrayMath.modulo(_value, scalar);
766        return new IntMatrixToken(result, _rowCount, _columnCount, DO_NOT_COPY);
767    }
768
769    /** Return a new token whose value is the value of this token
770     *  multiplied by the value of the argument token.  It is assumed
771     *  that the type of the argument is IntMatrixToken.
772     *  @param rightArgument The token to multiply this token by.
773     *  @exception IllegalActionException If the units are not
774     *  compatible, or this operation is not supported by the derived
775     *  class.
776     *  @return A new IntMatrixToken containing the result.
777     */
778    @Override
779    protected MatrixToken _multiply(MatrixToken rightArgument)
780            throws IllegalActionException {
781        IntMatrixToken convertedArgument = (IntMatrixToken) rightArgument;
782        int[] A = _value;
783        int[] B = convertedArgument._getInternalIntArray();
784        int m = _rowCount;
785        int n = _columnCount;
786        int p = convertedArgument.getColumnCount();
787        int[] newMatrix = new int[m * p];
788        int in = 0;
789        int ta = 0;
790
791        for (int i = 0; i < m; i++) {
792            ta += n;
793
794            for (int j = 0; j < p; j++) {
795                int sum = 0;
796                int ib = j;
797
798                for (int ia = i * n; ia < ta; ia++, ib += p) {
799                    sum += A[ia] * B[ib];
800                }
801
802                newMatrix[in++] = sum;
803            }
804        }
805
806        return new IntMatrixToken(newMatrix, m, p, DO_NOT_COPY);
807    }
808
809    /** Return a new token whose value is the value of this token
810     *  multiplied by the value of the argument scalar token.
811     *  @param rightArgument The token to multiply this token by.
812     *  @exception IllegalActionException If this method is not
813     *   supported by the derived class.
814     *  @return A new IntMatrixToken containing the result.
815     */
816    @Override
817    protected MatrixToken _multiplyElement(Token rightArgument)
818            throws IllegalActionException {
819        int scalar;
820        if (rightArgument instanceof IntMatrixToken) {
821            if (((IntMatrixToken) rightArgument).getRowCount() != 1
822                    || ((IntMatrixToken) rightArgument).getColumnCount() != 1) {
823                // Throw an exception.
824                return super._moduloElement(rightArgument);
825            }
826            scalar = ((IntMatrixToken) rightArgument).getElementAt(0, 0);
827        } else {
828            scalar = ((IntToken) rightArgument).intValue();
829        }
830        int[] result = IntegerArrayMath.multiply(_value, scalar);
831        return new IntMatrixToken(result, _rowCount, _columnCount, DO_NOT_COPY);
832    }
833
834    /** Return a new token whose value is the value of the argument token
835     *  subtracted from the value of this token.  It is assumed that the
836     *  type of the argument is IntMatrixToken.
837     *  @param rightArgument The token to subtract from this token.
838     *  @exception IllegalActionException If the units are not
839     *  compatible, or this operation is not supported by the derived
840     *  class.
841     *  @return A new IntMatrixToken containing the result.
842     */
843    @Override
844    protected MatrixToken _subtract(MatrixToken rightArgument)
845            throws IllegalActionException {
846        IntMatrixToken convertedArgument = (IntMatrixToken) rightArgument;
847        int[] result = IntegerArrayMath.subtract(_value,
848                convertedArgument._getInternalIntArray());
849        return new IntMatrixToken(result, _rowCount, _columnCount, DO_NOT_COPY);
850    }
851
852    /** Return a new token whose value is the value of the argument
853     *  Token subtracted from the value of each element of this Token. It is
854     *  assumed that the type of the argument is the same as the type
855     *  of each element of this class or is a matrix with one element.
856     *  @param rightArgument The token to subtract from this token.
857     *  @exception IllegalActionException If this operation is not
858     *  supported by the derived class.
859     *  @return A new Token containing the result.
860     */
861    @Override
862    protected MatrixToken _subtractElement(Token rightArgument)
863            throws IllegalActionException {
864        int scalar;
865        if (rightArgument instanceof IntMatrixToken) {
866            if (((IntMatrixToken) rightArgument).getRowCount() != 1
867                    || ((IntMatrixToken) rightArgument).getColumnCount() != 1) {
868                // Throw an exception.
869                return super._moduloElement(rightArgument);
870            }
871            scalar = ((IntMatrixToken) rightArgument).getElementAt(0, 0);
872        } else {
873            scalar = ((IntToken) rightArgument).intValue();
874        }
875        int[] result = IntegerArrayMath.add(_value, -scalar);
876        return new IntMatrixToken(result, _rowCount, _columnCount, DO_NOT_COPY);
877    }
878
879    /** Return a new token whose value is the value of the argument
880     *  Token subtracted from the value of each element of this Token. It is
881     *  assumed that the type of the argument is the same as the type
882     *  of each element of this class or is a matrix with one element.
883     *  @param rightArgument The token to subtract from this token.
884     *  @exception IllegalActionException If this operation is not
885     *  supported by the derived class.
886     *  @return A new Token containing the result.
887     */
888    @Override
889    protected MatrixToken _subtractElementReverse(Token rightArgument)
890            throws IllegalActionException {
891        int scalar;
892        if (rightArgument instanceof IntMatrixToken) {
893            if (((IntMatrixToken) rightArgument).getRowCount() != 1
894                    || ((IntMatrixToken) rightArgument).getColumnCount() != 1) {
895                // Throw an exception.
896                return super._moduloElement(rightArgument);
897            }
898            scalar = ((IntMatrixToken) rightArgument).getElementAt(0, 0);
899        } else {
900            scalar = ((IntToken) rightArgument).intValue();
901        }
902        int[] result = IntegerArrayMath
903                .negative(IntegerArrayMath.add(_value, -scalar));
904        return new IntMatrixToken(result, _rowCount, _columnCount, DO_NOT_COPY);
905    }
906
907    ///////////////////////////////////////////////////////////////////
908    ////                         private methods                   ////
909    // Initialize the row and column count and copy the specified
910    // matrix.  This method is used by the constructors.
911    private void _initialize(int[][] value) {
912        _rowCount = value.length;
913        _columnCount = value[0].length;
914        _value = IntegerMatrixMath.fromMatrixToArray(value);
915    }
916
917    ///////////////////////////////////////////////////////////////////
918    ////                         private variables                 ////
919    private int[] _value;
920
921    private int _rowCount;
922
923    private int _columnCount;
924}