001/* The type of fixed point token classes.
002
003 Copyright (c) 1997-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.type;
029
030import ptolemy.data.FixToken;
031import ptolemy.data.Token;
032import ptolemy.graph.CPO;
033import ptolemy.kernel.util.IllegalActionException;
034import ptolemy.kernel.util.InternalErrorException;
035import ptolemy.math.FixPoint;
036import ptolemy.math.FixPointQuantization;
037import ptolemy.math.Overflow;
038import ptolemy.math.Precision;
039import ptolemy.math.Rounding;
040
041///////////////////////////////////////////////////////////////////
042//// FixType
043
044/**
045 This class represents the type of fix point token objects.  Generally the
046 type of a fix point token includes the precision of the token, along with
047 the rounding and quantization techniques that are being applied.
048
049 @author Steve Neuendorffer
050 @version $Id$
051 @since Ptolemy II 2.1
052 @Pt.ProposedRating Red (neuendor)
053 @Pt.AcceptedRating Red
054 */
055public class FixType extends StructuredType implements Cloneable {
056    /** Construct a new fix type, with no integer bits and no
057     * fractional bits.  This (rather useless) type represents the
058     * bottom of the FixPoint type lattice.
059     */
060    public FixType() {
061        _precision = new Precision(0, 0);
062    }
063
064    /** Construct a new fix type.
065     *  @param precision The precision.
066     */
067    public FixType(Precision precision) {
068        _precision = precision;
069    }
070
071    ///////////////////////////////////////////////////////////////////
072    ////                         public methods                    ////
073
074    /** Return a new type which represents the type that results from
075     *  adding a token of this type and a token of the given argument
076     *  type.
077     *
078     *  @param rightArgumentType The type to add to this type.
079     *  @return A new type, or BaseType.GENERAL, if the operation does
080     *  not make sense for the given types.
081     */
082    @Override
083    public Type add(Type rightArgumentType) {
084        if (rightArgumentType instanceof FixType) {
085            Precision rPrecision = ((FixType) rightArgumentType).getPrecision();
086            Precision newPrecision = FixPoint.addPrecision(rPrecision,
087                    _precision);
088            FixType returnType = new FixType(newPrecision);
089            return returnType;
090        } else {
091            return TypeLattice.leastUpperBound(this, rightArgumentType);
092        }
093    }
094
095    /** Return this, that is, return the reference to this object.
096     *  @return A FixType.
097     */
098    @Override
099    public Object clone() {
100        // FIXME: Note that we do not call super.clone() here.  Is that right?
101        return this;
102    }
103
104    /** Convert the specified token to a token having the type
105     *  represented by this object.
106     *  @param token A token.
107     *  @return A token.
108     *  @exception IllegalActionException If lossless conversion cannot
109     *   be done.
110     */
111    @Override
112    public Token convert(Token token) throws IllegalActionException {
113        if (token.getType() instanceof FixType
114                && (_compare((FixType) token.getType()) == CPO.SAME
115                        || _compare((FixType) token.getType()) == CPO.HIGHER)) {
116
117            // The overflow and rounding modes could be anything here,
118            // since the above check should ensure that rounding and
119            // overflow will never occur.
120            return ((FixToken) token).quantize(new FixPointQuantization(
121                    getPrecision(), Overflow.GROW, Rounding.HALF_EVEN));
122        }
123
124        throw new IllegalActionException(
125                Token.notSupportedConversionMessage(token, toString()));
126    }
127
128    /** Return a new type which represents the type that results from
129     *  dividing a token of this type and a token of the given
130     *  argument type.
131     *  @param rightArgumentType The type to add to this type.
132     *  @return A new type, or BaseType.GENERAL, if the operation does
133     *  not make sense for the given types.
134     */
135    @Override
136    public Type divide(Type rightArgumentType) {
137        if (rightArgumentType instanceof FixType) {
138            Precision rPrecision = ((FixType) rightArgumentType).getPrecision();
139            Precision newPrecision = FixPoint.dividePrecision(rPrecision,
140                    _precision);
141            FixType returnType = new FixType(newPrecision);
142            return returnType;
143        } else {
144            return TypeLattice.leastUpperBound(this, rightArgumentType);
145        }
146    }
147
148    /** Determine if the argument represents the same FixType as this
149     *  object.
150     *  @param object A Type.
151     *  @return Always return true
152     */
153    @Override
154    public boolean equals(Object object) {
155        if (!(object instanceof FixType)) {
156            return false;
157        }
158        Precision precision = ((FixType) object).getPrecision();
159        if (!precision.equals(_precision)) {
160            return false;
161        }
162
163        return true;
164    }
165
166    /** Return the precision associated with this FixType.
167     *  @return A Precision.
168     */
169    public Precision getPrecision() {
170        return _precision;
171    }
172
173    /** Return the class for tokens that this type represents.
174     *  @return The class representing ptolemy.data.token.FixToken.
175     */
176    @Override
177    public Class getTokenClass() {
178        return FixToken.class;
179    }
180
181    /** Return a hash code value for this object.
182     *  @return The hash code for the token class of this type.
183     */
184    @Override
185    public int hashCode() {
186        return getTokenClass().hashCode();
187    }
188
189    /** Set the elements that have declared type BaseType.UNKNOWN to the
190     *  specified type.
191     *  @param type A Type.
192     */
193    @Override
194    public void initialize(Type type) {
195        // Ignore... This type has no components that are unknown.
196    }
197
198    /** Return true if this type does not correspond to a single token
199     *  class.  This occurs if the type is not instantiable, or it
200     *  represents either an abstract base class or an interface.
201     *  This method should be overridden in derived classes to return
202     *  true only for types which are not abstract.
203     *  @return true.
204     */
205    @Override
206    public boolean isAbstract() {
207        return !isInstantiable();
208    }
209
210    /** Test if the argument type is compatible with this type. The method
211     *  returns true if this type is UNKNOWN, since any type is a substitution
212     *  instance of it. If this type is not UNKNOWN, this method returns true
213     *  if the argument type is less than or equal to this type in the type
214     *  lattice, and false otherwise.
215     *  @param type An instance of Type.
216     *  @return True if the argument is compatible with this type.
217     */
218    @Override
219    public boolean isCompatible(Type type) {
220        int typeInfo = TypeLattice.compare(this, type);
221        return typeInfo == CPO.SAME || typeInfo == CPO.HIGHER;
222    }
223
224    /** Test if this Type is a constant. A Type is a constant if it
225     *  does not contain BaseType.UNKNOWN in any level within it.
226     *  @return False.
227     */
228    @Override
229    public boolean isConstant() {
230        return true;
231    }
232
233    /** Test if this type corresponds to an instantiable token
234     *  classes.
235     *  @return True if the precision of this fix type has any bits.
236     */
237    @Override
238    public boolean isInstantiable() {
239        if (_precision.getNumberOfBits() == 0) {
240            return false;
241        } else {
242            return true;
243        }
244    }
245
246    /** Test if the argument is a substitution instance of this type.
247     *  @param type A Type.
248     *  @return False.
249     */
250    @Override
251    public boolean isSubstitutionInstance(Type type) {
252        if (type instanceof StructuredType) {
253            return ((StructuredType) type)
254                    ._getRepresentative() == _getRepresentative();
255        } else {
256            return false;
257        }
258    }
259
260    /** Return a new type which represents the type that results from
261     *  moduloing a token of this type and a token of the given
262     *  argument type.
263     *  @param rightArgumentType The type to add to this type.
264     *  @return A new type, or BaseType.GENERAL, if the operation does
265     *  not make sense for the given types.
266     */
267    @Override
268    public Type modulo(Type rightArgumentType) {
269        // FIXME...  deal with precisions correctly.
270        return TypeLattice.leastUpperBound(this, rightArgumentType);
271    }
272
273    /** Return a new type which represents the type that results from
274     *  multiplying a token of this type and a token of the given
275     *  argument type.
276     *  The resulting Precision of a multiply between two FixType
277     *  arguments is as follows: the integer location is the sum
278     *  of the integer locations of the two arguments and the
279     *  fractional location is the sum of the fractional locations
280     *  of the two arguments.
281     *
282     *  @param rightArgumentType The type to add to this type.
283     *  @return A new type, or BaseType.GENERAL, if the operation does
284     *  not make sense for the given types.
285     */
286    @Override
287    public Type multiply(Type rightArgumentType) {
288        if (rightArgumentType instanceof FixType) {
289            Precision rPrecision = ((FixType) rightArgumentType).getPrecision();
290            Precision newPrecision = FixPoint.multiplyPrecision(rPrecision,
291                    _precision);
292            FixType returnType = new FixType(newPrecision);
293            return returnType;
294        } else {
295            return TypeLattice.leastUpperBound(this, rightArgumentType);
296        }
297    }
298
299    /** Return the type of the multiplicative identity for elements of
300     *  this type.
301     *  @return A new type, or BaseType.GENERAL, if the operation does
302     *  not make sense for the given types.
303     */
304    @Override
305    public Type one() {
306        // FIXME...  deal with precisions correctly.
307        return this;
308    }
309
310    /** Return a new type which represents the type that results from
311     *  subtracting a token of this type and a token of the given
312     *  argument type.
313     *  @param rightArgumentType The type to add to this type.
314     *  @return A new type, or BaseType.GENERAL, if the operation does
315     *  not make sense for the given types.
316     */
317    @Override
318    public Type subtract(Type rightArgumentType) {
319        if (rightArgumentType instanceof FixType) {
320            Precision rPrecision = ((FixType) rightArgumentType).getPrecision();
321            Precision newPrecision = FixPoint.subtractPrecision(rPrecision,
322                    _precision);
323            FixType returnType = new FixType(newPrecision);
324            return returnType;
325        } else {
326            return TypeLattice.leastUpperBound(this, rightArgumentType);
327        }
328    }
329
330    /** Return the string representation of this type.
331     *  @return A String.
332     */
333    @Override
334    public String toString() {
335        return "fixedpoint"
336                + _precision.toString(Precision.EXPRESSION_LANGUAGE);
337    }
338
339    /** Update this StructuredType to the specified Structured Type.
340     *  The specified type must have the same structure as this type.
341     *  This method will only update the component type that is
342     *  BaseType.UNKNOWN, and leave the constant part of this type intact.
343     *  @param newType A StructuredType.
344     *  @exception IllegalActionException If the specified type has a
345     *   different structure.
346     */
347    @Override
348    public void updateType(StructuredType newType)
349            throws IllegalActionException {
350        super.updateType(newType);
351        if (newType._getRepresentative() != _getRepresentative()) {
352            throw new InternalErrorException("FixType.updateType: Cannot "
353                    + "updateType the element type to " + newType + ".");
354        }
355    }
356
357    /** Return the type of the additive identity for elements of
358     *  this type.
359     *  @return A new type, or BaseType.GENERAL, if the operation does
360     *  not make sense for the given types.
361     */
362    @Override
363    public Type zero() {
364        // FIXME...  deal with precisions correctly.
365        return this;
366    }
367
368    ///////////////////////////////////////////////////////////////////
369    ////                           public fields                   ////
370
371    /** The bottom fix type. */
372    public static final FixType BOTTOM = new FixType();
373
374    ///////////////////////////////////////////////////////////////////
375    ////                         protected methods                 ////
376
377    /** Compare this type with the specified type. The specified type
378     *  must be of the same structured type, otherwise an exception will
379     *  be thrown.
380     *  This method returns one of ptolemy.graph.CPO.LOWER,
381     *  ptolemy.graph.CPO.SAME, ptolemy.graph.CPO.HIGHER,
382     *  ptolemy.graph.CPO.INCOMPARABLE, indicating this type is lower
383     *  than, equal to, higher than, or incomparable with the
384     *  specified type in the type hierarchy, respectively.
385     *  @param type a StructuredType.
386     *  @return An integer.
387     *  @exception IllegalArgumentException If the specified type is
388     *   not the same structured type as this one.
389     */
390    @Override
391    protected int _compare(StructuredType type) {
392        if (!(type instanceof FixType)) {
393            throw new IllegalArgumentException(
394                    "FixType._compare: " + "The argument is not a FixType.");
395        }
396
397        Precision precision = ((FixType) type).getPrecision();
398
399        int fractionBits1 = _precision.getFractionBitLength();
400        int fractionBits2 = precision.getFractionBitLength();
401        int integerBits1 = _precision.getFractionBitLength();
402        int integerBits2 = precision.getFractionBitLength();
403        boolean signBit1 = _precision.isSigned();
404        boolean signBit2 = precision.isSigned();
405        int compareBits1, compareBits2;
406
407        if (_precision.equals(precision)) {
408            return CPO.SAME;
409        } else if (signBit1 == signBit2) {
410            if (fractionBits1 < fractionBits2 && integerBits1 < integerBits2) {
411                return CPO.LOWER;
412
413            } else if (fractionBits1 > fractionBits2
414                    && integerBits1 > integerBits2) {
415                return CPO.HIGHER;
416
417            } else if (integerBits1 == integerBits2) {
418                compareBits1 = fractionBits1;
419                compareBits2 = fractionBits2;
420            } else {
421                compareBits1 = integerBits1;
422                compareBits2 = integerBits2;
423            }
424
425            if (compareBits1 < compareBits2) {
426                return CPO.LOWER;
427            } else if (compareBits1 > compareBits2) {
428                return CPO.HIGHER;
429            } else { // (signBit1 == signBit2)
430                return CPO.SAME;
431            }
432        } else if (signBit1 && !signBit2) {
433            if (fractionBits1 >= fractionBits2
434                    && integerBits1 >= integerBits2) {
435                return CPO.HIGHER;
436            }
437        } else {
438            if (fractionBits1 <= fractionBits2
439                    && integerBits1 <= integerBits2) {
440                return CPO.LOWER;
441            }
442        }
443        return CPO.INCOMPARABLE;
444    }
445
446    /** Return a static instance of this structured type. The return
447     *  value is used by TypeLattice to represent this type.
448     *  @return a StructuredType.
449     */
450    @Override
451    protected StructuredType _getRepresentative() {
452        return FixType.BOTTOM;
453    }
454
455    /** Return the greatest lower bound of this type with the specified
456     *  type. The specified type must be of the same structured type,
457     *  otherwise an exception will be thrown.
458     *  @param type a StructuredType.
459     *  @return a StructuredType.
460     *  @exception IllegalArgumentException If the specified type is
461     *   not the same structured type as this one.
462     */
463    @Override
464    protected StructuredType _greatestLowerBound(StructuredType type) {
465        if (!(type instanceof FixType)) {
466            throw new IllegalArgumentException("FixType._greatestLowerBound: "
467                    + "The argument is not a FixType.");
468        }
469        Precision precision = ((FixType) type).getPrecision();
470        int fractionBits = Math.min(precision.getFractionBitLength(),
471                _precision.getFractionBitLength());
472        int integerBits = Math.min(precision.getIntegerBitLength(),
473                _precision.getIntegerBitLength());
474        return new FixType(
475                new Precision(fractionBits + integerBits, integerBits));
476    }
477
478    /** Return the least upper bound of this type with the specified
479     *  type. The specified type must be of the same structured type,
480     *  otherwise an exception will be thrown.
481     *  @param type a StructuredType.
482     *  @return a StructuredType.
483     *  @exception IllegalArgumentException If the specified type is
484     *   not the same structured type as this one.
485     */
486    @Override
487    protected StructuredType _leastUpperBound(StructuredType type) {
488        if (!(type instanceof FixType)) {
489            throw new IllegalArgumentException("FixType._greatestLowerBound: "
490                    + "The argument is not a FixType.");
491        }
492        Precision precision = ((FixType) type).getPrecision();
493        int fractionBits = Math.max(precision.getFractionBitLength(),
494                _precision.getFractionBitLength());
495        int integerBits = Math.max(precision.getIntegerBitLength(),
496                _precision.getIntegerBitLength());
497        FixType returnType = new FixType(
498                new Precision(fractionBits + integerBits, integerBits));
499        returnType._checkPrecision();
500        return returnType;
501    }
502
503    /** Check the precision.
504     *  If the number of bits is greater than 128, throw an exception.
505     */
506    protected void _checkPrecision() {
507        if (_precision.getNumberOfBits() > 128) {
508            throw new RuntimeException(
509                    "Large fixed point type detected during type resolution."
510                            + "  The structured type " + this
511                            + " has depth larger than the bound " + 128
512                            + ".  This may be an indicator of type constraints "
513                            + "in a model with no finite solution, which may occur "
514                            + "if there is a feedback loop that requires an "
515                            + "explicit FixToFix conversion actor.");
516        }
517    }
518
519    ///////////////////////////////////////////////////////////////////
520    ////                         private variables                 ////
521    private Precision _precision;
522    //  private Quantization _quantization;
523    //  private Rounding _rounding;
524}