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