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}