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