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