001/* The base type of matrix token classes.
002
003 Copyright (c) 2006-2018 The Regents of the University of California.
004 All rights reserved.
005 Permission is hereby granted, without written agreement and without
006 license or royalty fees, to use, copy, modify, and distribute this
007 software and its documentation for any purpose, provided that the above
008 copyright notice and the following two paragraphs appear in all copies
009 of this software.
010
011 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
012 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
013 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
014 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
015 SUCH DAMAGE.
016
017 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
018 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
019 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
020 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
021 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
022 ENHANCEMENTS, OR MODIFICATIONS.
023
024 PT_COPYRIGHT_VERSION_2
025 COPYRIGHTENDKEY
026
027 */
028package ptolemy.data.type;
029
030import ptolemy.data.BooleanMatrixToken;
031import ptolemy.data.ComplexMatrixToken;
032import ptolemy.data.ComplexToken;
033import ptolemy.data.DoubleMatrixToken;
034import ptolemy.data.DoubleToken;
035import ptolemy.data.FixMatrixToken;
036import ptolemy.data.FixToken;
037import ptolemy.data.IntMatrixToken;
038import ptolemy.data.IntToken;
039import ptolemy.data.LongMatrixToken;
040import ptolemy.data.LongToken;
041import ptolemy.data.MatrixToken;
042import ptolemy.data.Token;
043import ptolemy.graph.CPO;
044import ptolemy.kernel.util.IllegalActionException;
045import ptolemy.kernel.util.InternalErrorException;
046import ptolemy.math.Complex;
047import ptolemy.math.FixPoint;
048
049///////////////////////////////////////////////////////////////////
050//// MatrixType
051
052/**
053 The base type of matrix token classes. This type functions as a union
054 of the various matrix types. It allows for the creation of arrays
055 that consist of diverse matrix types, because the array type will
056 be {matrix}.
057
058 @author Steve Neuendorffer and Edward A. Lee
059 @version $Id$
060 @since Ptolemy II 5.2
061 @Pt.ProposedRating Red (yuhong)
062 @Pt.AcceptedRating Red
063 */
064public class MatrixType extends StructuredType implements Cloneable {
065
066    /** Construct a new matrix type that represents matrix tokens of the
067     *  given class with the given number of rows and columns.
068     *  @param c The token class.
069     *  @param type The element type.
070     *  @param name The name.
071     */
072    public MatrixType(Class c, Type type, String name) {
073        _tokenClass = c;
074        _elementType = type;
075        _name = name;
076        BaseType._addType(this, name, c);
077    }
078
079    ///////////////////////////////////////////////////////////////////
080    ////                         public methods                    ////
081
082    /** Return this, that is, return the reference to this object.
083     *  @return A MatrixType.
084     */
085    @Override
086    public Object clone() {
087        return this;
088    }
089
090    /** If the argument is an instance of this class or a subclass,
091     *  then return the token. Otherwise, throw an exception.
092     *  @param token A token.
093     *  @return An instance of this class.
094     *  @exception IllegalActionException If the argument is not
095     *   an instance of this class.
096     */
097    @Override
098    public Token convert(Token token) throws IllegalActionException {
099        if (token instanceof MatrixToken) {
100            return token;
101        }
102        throw new IllegalActionException(Token
103                .notSupportedIncomparableConversionMessage(token, "matrix"));
104    }
105
106    /** Determine if the argument represents the same MatrixType as this
107     *  object.
108     *  @param object A Type.
109     *  @return True if the argument type is a matrix type representing the
110     *  same class, with the same number of rows and columns.
111     */
112    @Override
113    public boolean equals(Object object) {
114        if (!(object instanceof MatrixType)) {
115            return false;
116        }
117
118        MatrixType matrixType = (MatrixType) object;
119
120        if (matrixType.getTokenClass() != _tokenClass) {
121            return false;
122        }
123
124        return true;
125    }
126
127    /** Return the type of the elements contained in an instance of
128     *  this matrix type.  Tokens of the type returned by this method
129     *  will be returned by the getElementAsToken of matrices that
130     *  have this type. If this is an instance of this base class
131     *  rather than the specific matrix types, then return null.
132     *  @return The type of the elements.
133     */
134    public Type getElementType() {
135        return _elementType;
136    }
137
138    /** Return a matrix type whose element type is the given element
139     *  type.
140     *  @param elementType The type of the element.
141     *  @return The matrix type.
142     *  @exception IllegalActionException If the elementType is not a
143     *  type that has a corresponding matrix type.
144     */
145    public static MatrixType getMatrixTypeForElementType(Type elementType)
146            throws IllegalActionException {
147        MatrixType matrixType;
148
149        if (elementType.equals(BaseType.UNKNOWN)) {
150            throw new IllegalActionException(
151                    "Cannot resolve type for " + "matrix construction.");
152        } else if (elementType.equals(BaseType.BOOLEAN)) {
153            matrixType = BaseType.BOOLEAN_MATRIX;
154        } else if (elementType.equals(BaseType.INT)) {
155            matrixType = BaseType.INT_MATRIX;
156        } else if (elementType.equals(BaseType.LONG)) {
157            matrixType = BaseType.LONG_MATRIX;
158        } else if (elementType.equals(BaseType.DOUBLE)) {
159            matrixType = BaseType.DOUBLE_MATRIX;
160        } else if (elementType.equals(BaseType.COMPLEX)) {
161            matrixType = BaseType.COMPLEX_MATRIX;
162        } else if (elementType instanceof FixType) {
163            matrixType = BaseType.FIX_MATRIX;
164        } else if (elementType.equals(BaseType.UNSIZED_FIX)) {
165            matrixType = BaseType.FIX_MATRIX;
166        } else {
167            throw new IllegalActionException("Type " + elementType
168                    + " does not have a corresponding matrix type.");
169        }
170
171        return matrixType;
172    }
173
174    /** Return the class for tokens that this type represents.
175     *  @return A class that represents a matrix token.
176     */
177    @Override
178    public Class getTokenClass() {
179        return _tokenClass;
180    }
181
182    /** Return a hash code value for this object.
183     *  @return The hash code for the token class of this type.
184     */
185    @Override
186    public int hashCode() {
187        return getTokenClass().hashCode();
188    }
189
190    /** Set the elements that have declared type BaseType.UNKNOWN to the
191     *  specified type.
192     *  @param type A Type.
193     */
194    @Override
195    public void initialize(Type type) {
196        // Ignore... This type has no components that are unknown.
197    }
198
199    /** Return true if the element type is abstract.
200     *  @return True.
201     */
202    @Override
203    public boolean isAbstract() {
204        return _elementType.isAbstract();
205    }
206
207    /** Test if the argument type is compatible with this type. The method
208     *  returns true if this type is UNKNOWN, since any type is a substitution
209     *  instance of it. If this type is not UNKNOWN, this method returns true
210     *  if the argument type is less than or equal to this type in the type
211     *  lattice, and false otherwise.
212     *  @param type An instance of Type.
213     *  @return True if the argument is compatible with this type.
214     */
215    @Override
216    public boolean isCompatible(Type type) {
217        int typeInfo = TypeLattice.compare(this, type);
218        return typeInfo == CPO.SAME || typeInfo == CPO.HIGHER;
219    }
220
221    /** Test if this Type is a constant. A Type is a constant if it
222     *  does not contain BaseType.UNKNOWN in any level within it.
223     *  @return False.
224     */
225    @Override
226    public boolean isConstant() {
227        return true;
228    }
229
230    /** Return true, indicating that instances of this type can
231     *  exist.
232     *  @return True.
233     */
234    @Override
235    public boolean isInstantiable() {
236        return _elementType.isInstantiable();
237    }
238
239    /** Test if the argument is a substitution instance of this type.
240     *  @param type A Type.
241     *  @return False.
242     */
243    @Override
244    public boolean isSubstitutionInstance(Type type) {
245        if (type instanceof StructuredType) {
246            return ((StructuredType) type)
247                    ._getRepresentative() == _getRepresentative();
248        } else {
249            return false;
250        }
251    }
252
253    /** Return the string representation of this type.
254     *  @return A String.
255     */
256    @Override
257    public String toString() {
258        return _name;
259    }
260
261    /** Update this StructuredType to the specified Structured Type.
262     ** The specified type must have the same structure as this type.
263     *  This method will only update the component type that is
264     *  BaseType.UNKNOWN, and leave the constant part of this type intact.
265     *  @param newType A StructuredType.
266     *  @exception IllegalActionException If the specified type has a
267     *   different structure.
268     */
269    @Override
270    public void updateType(StructuredType newType)
271            throws IllegalActionException {
272        if (newType._getRepresentative() != _getRepresentative()) {
273            throw new InternalErrorException("MatrixType.updateType: Cannot "
274                    + "updateType the element type to " + newType + ".");
275        }
276    }
277
278    /** The boolean matrix data type. */
279    public static class BooleanMatrixType extends MatrixType {
280        public BooleanMatrixType() {
281            super(BooleanMatrixToken.class, BaseType.BOOLEAN, "[boolean]");
282        }
283
284        @Override
285        public Token convert(Token token) throws IllegalActionException {
286            if (token instanceof MatrixToken) {
287                return BooleanMatrixToken.convert(token);
288            } else {
289                // NOTE: No point in converting to a boolean matrix,
290                // since you can't do anything with it.
291                throw new IllegalActionException(
292                        Token.notSupportedConversionMessage(token, toString()));
293            }
294        }
295    }
296
297    /** The complex matrix data type. */
298    public static class ComplexMatrixType extends MatrixType {
299        public ComplexMatrixType() {
300            super(ComplexMatrixToken.class, BaseType.COMPLEX, "[complex]");
301        }
302
303        @Override
304        public Token convert(Token token) throws IllegalActionException {
305            if (token instanceof MatrixToken) {
306                return ComplexMatrixToken.convert(token);
307            } else {
308                if (token.isNil()) {
309                    throw new IllegalActionException(Token
310                            .notSupportedConversionMessage(token, toString()));
311                }
312                // Try to create a new [complex] type with just one member.
313                // The following conversion will fail if the member cannot
314                // be converted to an int.
315                ComplexToken singleMember = ComplexToken.convert(token);
316                Complex[][] matrix = new Complex[1][1];
317                matrix[0][0] = singleMember.complexValue();
318                return new ComplexMatrixToken(matrix);
319            }
320
321        }
322    }
323
324    /** The double matrix data type. */
325    public static class DoubleMatrixType extends MatrixType {
326        public DoubleMatrixType() {
327            super(DoubleMatrixToken.class, BaseType.DOUBLE, "[double]");
328        }
329
330        @Override
331        public Token convert(Token token) throws IllegalActionException {
332            if (token instanceof MatrixToken) {
333                return DoubleMatrixToken.convert(token);
334            } else {
335                if (token.isNil()) {
336                    // MatrixTokens do not support nil because there is no
337                    // way to represent a nil double as a Java.lang.Double.
338                    // Double.NaN is a possibility, but NaN is a value, whereas
339                    // nil is the absent value.  Other types, like int do
340                    // not have NaN, so we catch this problem here.
341                    // Note that this code is called by the "cast" expression
342                    // language method from data.expr.UtilityFunctions
343                    throw new IllegalActionException(Token
344                            .notSupportedConversionMessage(token, toString()));
345                }
346                // Try to create a new [double] type with just one member.
347                // The following conversion will fail if the member cannot
348                // be converted to an int.
349                DoubleToken singleMember = DoubleToken.convert(token);
350                double[] matrix = new double[1];
351                matrix[0] = singleMember.doubleValue();
352                return new DoubleMatrixToken(matrix, 1, 1);
353            }
354        }
355    }
356
357    /** The integer matrix data type. */
358    public static class IntMatrixType extends MatrixType {
359        public IntMatrixType() {
360            super(IntMatrixToken.class, BaseType.INT, "[int]");
361        }
362
363        @Override
364        public Token convert(Token token) throws IllegalActionException {
365            if (token instanceof MatrixToken) {
366                return IntMatrixToken.convert(token);
367            } else {
368                if (token.isNil()) {
369                    throw new IllegalActionException(Token
370                            .notSupportedConversionMessage(token, toString()));
371                }
372
373                // Try to create a new [int] type with just one member.
374                // The following conversion will fail if the member cannot
375                // be converted to an int.
376                IntToken singleMember = IntToken.convert(token);
377                int[] matrix = new int[1];
378                matrix[0] = singleMember.intValue();
379                return new IntMatrixToken(matrix, 1, 1);
380            }
381        }
382    }
383
384    /** The fix matrix data type. */
385    public static class FixMatrixType extends MatrixType {
386        public FixMatrixType() {
387            super(FixMatrixToken.class, BaseType.UNSIZED_FIX, "[fixedpoint]");
388        }
389
390        @Override
391        public Token convert(Token token) throws IllegalActionException {
392            if (token instanceof MatrixToken) {
393                return FixMatrixToken.convert(token);
394            } else {
395                if (token.isNil()) {
396                    throw new IllegalActionException(Token
397                            .notSupportedConversionMessage(token, toString()));
398                }
399                // Try to create a new [fix] type with just one member.
400                // The following conversion will fail if the member cannot
401                // be converted to an int.
402                FixToken singleMember = FixToken.convert(token);
403                FixPoint[][] matrix = new FixPoint[1][1];
404                matrix[0][0] = singleMember.fixValue();
405                return new FixMatrixToken(matrix);
406            }
407        }
408    }
409
410    /** The long matrix data type. */
411    public static class LongMatrixType extends MatrixType {
412        public LongMatrixType() {
413            super(LongMatrixToken.class, BaseType.LONG, "[long]");
414        }
415
416        @Override
417        public Token convert(Token token) throws IllegalActionException {
418            if (token instanceof MatrixToken) {
419                return LongMatrixToken.convert(token);
420            } else {
421                if (token.isNil()) {
422                    throw new IllegalActionException(Token
423                            .notSupportedConversionMessage(token, toString()));
424                }
425                // Try to create a new [long] type with just one member.
426                // The following conversion will fail if the member cannot
427                // be converted to an int.
428                LongToken singleMember = LongToken.convert(token);
429                long[] matrix = new long[1];
430                matrix[0] = singleMember.longValue();
431                return new LongMatrixToken(matrix, 1, 1);
432            }
433        }
434    }
435
436    ///////////////////////////////////////////////////////////////////
437    ////                         protected methods                 ////
438
439    /** Compare this type with the specified type. The specified type
440     *  must be of the same structured type, otherwise an exception will
441     *  be thrown.
442     *  This method returns one of ptolemy.graph.CPO.LOWER,
443     *  ptolemy.graph.CPO.SAME, ptolemy.graph.CPO.HIGHER,
444     *  ptolemy.graph.CPO.INCOMPARABLE, indicating this type is lower
445     *  than, equal to, higher than, or incomparable with the
446     *  specified type in the type hierarchy, respectively.
447     *  @param type a StructuredType.
448     *  @return An integer.
449     *  @exception IllegalArgumentException If the specified type is
450     *   not the same structured type as this one.
451     */
452    @Override
453    protected int _compare(StructuredType type) {
454        return CPO.SAME;
455
456        //         if (equals(type)) {
457        //             return CPO.SAME;
458        //         } else {
459        //             return CPO.LOWER;
460        //         }
461    }
462
463    /** Return a static instance of this structured type. The return
464     *  value is used by TypeLattice to represent this type.
465     *  @return a StructuredType.
466     */
467    @Override
468    protected StructuredType _getRepresentative() {
469        return this;
470    }
471
472    /** Return the greatest lower bound of this type with the specified
473     *  type. The specified type must be of the same structured type,
474     *  otherwise an exception will be thrown.
475     *  @param type a StructuredType.
476     *  @return a StructuredType.
477     *  @exception IllegalArgumentException If the specified type is
478     *   not the same structured type as this one.
479     */
480    @Override
481    protected StructuredType _greatestLowerBound(StructuredType type) {
482        return this;
483    }
484
485    /** Return the least upper bound of this type with the specified
486     *  type. The specified type must be of the same structured type,
487     *  otherwise an exception will be thrown.
488     *  @param type a StructuredType.
489     *  @return a StructuredType.
490     *  @exception IllegalArgumentException If the specified type is
491     *   not the same structured type as this one.
492     */
493    @Override
494    protected StructuredType _leastUpperBound(StructuredType type) {
495        return this;
496
497        //         if (equals(type)) {
498        //             return this;
499        //         } else {
500        //             return type;
501        //         }
502    }
503
504    ///////////////////////////////////////////////////////////////////
505    ////                         private variables                 ////
506
507    /** The type of MatrixToken that this class represents. */
508    private Class _tokenClass;
509
510    /** The type of the elements of the matrix, or ScalarType for this base class. */
511    private Type _elementType;
512
513    /** The name of this instance. */
514    private String _name;
515}