001/* Abstract base class for tokens that contain a 2-D matrix. 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 028 */ 029package ptolemy.data; 030 031import java.util.HashSet; 032import java.util.Set; 033 034import ptolemy.data.type.ArrayType; 035import ptolemy.data.type.BaseType; 036import ptolemy.data.type.FixType; 037import ptolemy.data.type.MatrixType; 038import ptolemy.data.type.Type; 039import ptolemy.data.type.TypeLattice; 040import ptolemy.graph.CPO; 041import ptolemy.kernel.util.IllegalActionException; 042import ptolemy.kernel.util.InternalErrorException; 043import ptolemy.math.Complex; 044import ptolemy.math.FixPoint; 045 046/////////////////////////////////////////////////////////////////// 047//// MatrixToken 048 049/** 050 Abstract base class for tokens that contain a 2-D matrix. 051 This class defines methods for type conversion among different matrix 052 tokens. The implementation in this base class just throws an exception. 053 Derived classes should override those methods where the corresponding 054 conversion can be achieved without loss of information. 055 Derived classes should call _elementIsNil() when they encounter a nil 056 token during construction. 057 058 @author Yuhong Xiong, Steve Neuendorffer, contributor: Christopher Brooks 059 @version $Id$ 060 @since Ptolemy II 0.2 061 @Pt.ProposedRating Yellow (cxh) 062 @Pt.AcceptedRating Red (cxh) nil token code 063 */ 064public abstract class MatrixToken extends Token { 065 /////////////////////////////////////////////////////////////////// 066 //// public methods //// 067 068 /** Return a new token whose value is the sum of this token and 069 * the argument. Type conversion also occurs here, so that the 070 * operation is performed at the least type necessary to ensure 071 * precision. The returned type is the same as the type chosen 072 * for the operation. Generally, this is higher of the type of 073 * this token and the argument type. Subclasses should not 074 * generally override this method, but override the protected 075 * _add() method to ensure that type conversion is performed 076 * consistently. 077 * @param rightArgument The token to add to this token. 078 * @return A new token containing the result. 079 * @exception IllegalActionException If the argument token 080 * and this token are of incomparable types, or the operation 081 * does not make sense for the given types. 082 */ 083 @Override 084 public Token add(Token rightArgument) throws IllegalActionException { 085 // Get the corresponding element type for this matrix type, 086 // and try a scalar operation. 087 Type elementType = getElementType(); 088 int typeInfo = TypeLattice.compare(elementType, rightArgument); 089 090 if (typeInfo == CPO.SAME) { 091 Token result = _addElement(rightArgument); 092 return result; 093 } else if (typeInfo == CPO.HIGHER) { 094 Token convertedArgument = elementType.convert(rightArgument); 095 096 try { 097 Token result = _addElement(convertedArgument); 098 return result; 099 } catch (IllegalActionException ex) { 100 // If the type-specific operation fails, then create a better 101 // error message that has the types of the arguments that were 102 // passed in. 103 throw new IllegalActionException(null, ex, 104 notSupportedMessage("add", this, rightArgument)); 105 } 106 } 107 108 // If we get here, then either our element type is lower than 109 // the rightArgument or incomparable to it. 110 typeInfo = TypeLattice.compare(getType(), rightArgument); 111 112 if (typeInfo == CPO.SAME) { 113 Token result = _doAdd(rightArgument); 114 return result; 115 } else if (typeInfo == CPO.HIGHER) { 116 MatrixToken convertedArgument = (MatrixToken) getType() 117 .convert(rightArgument); 118 119 try { 120 Token result = _doAdd(convertedArgument); 121 return result; 122 } catch (IllegalActionException ex) { 123 // If the type-specific operation fails, then create a 124 // better error message that has the types of the 125 // arguments that were passed in. 126 throw new IllegalActionException(null, ex, 127 notSupportedMessage("add", this, rightArgument)); 128 } 129 } else if (typeInfo == CPO.LOWER) { 130 Token result = rightArgument.addReverse(this); 131 return result; 132 } else { 133 // Items being added are incomparable. 134 // However, addition may still be possible because 135 // the LUB of the types might support it. E.g., [double]+complex, 136 // where the LUB is [complex]. 137 Type lubType = (Type) TypeLattice.lattice() 138 .leastUpperBound(getType(), rightArgument.getType()); 139 140 // If the LUB is a new type, try it. 141 if (!lubType.equals(getType())) { 142 Token lub = lubType.convert(this); 143 144 // Caution: convert() might return this again, e.g. 145 // if lubType is general. Only proceed if the conversion 146 // returned a new type. 147 if (!lub.getType().equals(getType())) { 148 return lub.add(rightArgument); 149 } 150 } 151 152 throw new IllegalActionException(notSupportedIncomparableMessage( 153 "add", this, rightArgument)); 154 } 155 } 156 157 /** Return a new token whose value is the sum of this token 158 * and the argument. Type resolution also occurs here, with 159 * the returned token type chosen to achieve 160 * a lossless conversion. 161 * @param leftArgument The token to add this token to. 162 * @return A new token containing the result. 163 * @exception IllegalActionException If the argument token 164 * is not of a type that can be added to this token, or 165 * the units of this token and the argument token are not the same. 166 */ 167 @Override 168 public Token addReverse(ptolemy.data.Token leftArgument) 169 throws IllegalActionException { 170 // Get the corresponding element type for this matrix type, 171 // and try a scalar operation. 172 Type elementType = getElementType(); 173 int typeInfo = TypeLattice.compare(leftArgument, elementType); 174 175 if (typeInfo == CPO.LOWER) { 176 Token convertedArgument = elementType.convert(leftArgument); 177 178 try { 179 Token result = _addElement(convertedArgument); 180 return result; 181 } catch (IllegalActionException ex) { 182 // If the type-specific operation fails, then create a 183 // better error message that has the types of the 184 // arguments that were passed in. 185 throw new IllegalActionException(null, ex, 186 notSupportedMessage("add", this, leftArgument)); 187 } 188 } else if (typeInfo == CPO.SAME) { 189 Token result = _addElement(leftArgument); 190 return result; 191 } 192 193 // If we get here, then either our element type is lower than 194 // the leftArgument or incomparable to it. 195 typeInfo = TypeLattice.compare(leftArgument, getType()); 196 197 // We would normally expect this to be LOWER, since this will almost 198 // always be called by subtract, so put that case first. 199 if (typeInfo == CPO.LOWER) { 200 MatrixToken convertedArgument = (MatrixToken) getType() 201 .convert(leftArgument); 202 203 try { 204 Token result = convertedArgument._doAdd(this); 205 return result; 206 } catch (IllegalActionException ex) { 207 // If the type-specific operation fails, then create a 208 // better error message that has the types of the 209 // arguments that were passed in. 210 throw new IllegalActionException(null, ex, 211 notSupportedMessage("addReverse", this, leftArgument)); 212 } 213 } else if (typeInfo == CPO.SAME) { 214 Token result = ((MatrixToken) leftArgument)._doAdd(this); 215 return result; 216 } else if (typeInfo == CPO.HIGHER) { 217 Token result = leftArgument.add(this); 218 return result; 219 } else { 220 // Items being added are incomparable. 221 // However, addition may still be possible because 222 // the LUB of the types might support it. E.g., complex+[double], 223 // where the LUB is [complex]. 224 Type lubType = (Type) TypeLattice.lattice() 225 .leastUpperBound(getType(), leftArgument.getType()); 226 227 // If the LUB is a new type, try it. 228 if (!lubType.equals(getType())) { 229 Token lub = lubType.convert(this); 230 231 // Caution: convert() might return this again, e.g. 232 // if lubType is general. Only proceed if the conversion 233 // returned a new type. 234 if (!lub.getType().equals(getType())) { 235 return lub.addReverse(leftArgument); 236 } 237 } 238 239 throw new IllegalActionException(notSupportedIncomparableMessage( 240 "addReverse", this, leftArgument)); 241 } 242 } 243 244 /** Create a new instance of a MatrixToken subclass with the 245 * given number of rows and columns. The token will contain 246 * all of the elements of the given array. The element type 247 * of the matrix token will be the least upper bound of the 248 * types of all of the tokens in the given array. The size 249 * of the array must be (rows*columns). 250 * @param tokens an array of Token objects 251 * @param rows The number of rows. 252 * @param columns The number of columns. 253 * @return An instance of a subclass of MatrixToken. 254 * @exception IllegalActionException If no type exists for the 255 * matrix token, or the array of tokens is not the right size, or 256 * the array is null. 257 */ 258 public static MatrixToken arrayToMatrix(Token[] tokens, int rows, 259 int columns) throws IllegalActionException { 260 Set<Type> typeTerms = new HashSet<Type>(); 261 262 // Find the first non-nil element and get its type 263 Type baseType = BaseType.GENERAL; 264 for (int i = 0; i < tokens.length; i++) { 265 if (!tokens[i].isNil()) { 266 baseType = tokens[i].getType(); 267 break; 268 } 269 } 270 271 // If a token is nil, then default to the first type that we 272 // found. 273 for (Token token : tokens) { 274 if (token.isNil()) { 275 typeTerms.add(baseType); 276 } else { 277 typeTerms.add(token.getType()); 278 } 279 } 280 281 Type type = (Type) TypeLattice.lattice().leastUpperBound(typeTerms); 282 283 return arrayToMatrix(type, tokens, rows, columns); 284 } 285 286 /** Create a new instance of a MatrixToken subclass with the given 287 * element type and number of rows and columns. The token will 288 * contain all of the elements of the given array. The size of 289 * the array must be (rows*columns). 290 * @param type The type of the MatrixToken. 291 * @param tokens an array of Token objects 292 * @param rows The number of rows. 293 * @param columns The number of columns. 294 * @return An instance of a subclass of MatrixToken. 295 * @exception IllegalActionException If the type is not possible, 296 * or the array of tokens is not the right size, or the array is 297 * null. 298 */ 299 public static MatrixToken arrayToMatrix(Type type, Token[] tokens, int rows, 300 int columns) throws IllegalActionException { 301 MatrixToken token; 302 303 if (type.equals(BaseType.UNKNOWN)) { 304 throw new IllegalActionException( 305 "Cannot resolve type for " + "matrix construction."); 306 } else if (type.equals(BaseType.BOOLEAN)) { 307 token = new BooleanMatrixToken(tokens, rows, columns); 308 } else if (type.equals(BaseType.INT)) { 309 token = new IntMatrixToken(tokens, rows, columns); 310 } else if (type.equals(BaseType.LONG)) { 311 token = new LongMatrixToken(tokens, rows, columns); 312 } else if (type.equals(BaseType.DOUBLE)) { 313 token = new DoubleMatrixToken(tokens, rows, columns); 314 } else if (type.equals(BaseType.COMPLEX)) { 315 token = new ComplexMatrixToken(tokens, rows, columns); 316 } else if (type.equals(BaseType.UNSIZED_FIX) 317 || type instanceof FixType) { 318 token = new FixMatrixToken(tokens, rows, columns); 319 } else { 320 throw new IllegalActionException( 321 "Unrecognized type " + type + " for matrix creation."); 322 } 323 324 return token; 325 } 326 327 /** Return the (exact) return type of the arrayToMatrix function 328 * above. If the first argument type is an array type, then 329 * return a matrix type of the same element type, otherwise return 330 * BaseType.UNKNOWN. 331 * @param type1 The type of the first argument to the 332 * corresponding function. 333 * @param type2 The type of the second argument to the 334 * corresponding function. 335 * @param type3 The type of the third argument to the 336 * corresponding function. 337 * @return The type of the value returned from the corresponding 338 * function. 339 * @exception IllegalActionException If thrown while getting the matrix 340 * type for type1. 341 */ 342 public static Type arrayToMatrixReturnType(Type type1, Type type2, 343 Type type3) throws IllegalActionException { 344 // FIXME: why are type2 and type3 isgnored here? 345 if (type1 instanceof ArrayType) { 346 Type elementType = ((ArrayType) type1).getElementType(); 347 return MatrixType.getMatrixTypeForElementType(elementType); 348 } else { 349 return BaseType.UNKNOWN; 350 } 351 } 352 353 /** Return the content of this token as a 2-D boolean matrix. 354 * In this base class, just throw an exception. 355 * @return A 2-D boolean matrix. 356 * @exception IllegalActionException If the token cannot be represented 357 * as requested (always thrown in this base class). 358 */ 359 public boolean[][] booleanMatrix() throws IllegalActionException { 360 throw new IllegalActionException( 361 notSupportedConversionMessage(this, "boolean matrix")); 362 } 363 364 /** Return a copy of the content of this token as a 2-D Complex matrix. 365 * In this base class, just throw an exception. 366 * @return A 2-D Complex matrix. 367 * @exception IllegalActionException If the token cannot be represented 368 * as requested (always thrown in this base class). 369 */ 370 public Complex[][] complexMatrix() throws IllegalActionException { 371 throw new IllegalActionException( 372 notSupportedConversionMessage(this, "complex matrix")); 373 } 374 375 /** Create a new instance of a MatrixToken subclass with the given 376 * number of rows and columns. The token will contain all of the 377 * elements of the given array. The element type of the matrix 378 * token will be the least upper bound of the types of all of the 379 * tokens in the given array. The size of the array must be 380 * (rows*columns). 381 * @param tokens an array of Token objects. 382 * @param rows The number of rows. 383 * @param columns The number of columns. 384 * @return An instance of a subclass of MatrixToken. 385 * @exception IllegalActionException If no type exists for the 386 * matrix token, or the array of tokens is not the right size, or 387 * the array is null. 388 * @deprecated Use arrayToMatrix() instead. 389 */ 390 @Deprecated 391 public static MatrixToken create(Token[] tokens, int rows, int columns) 392 throws IllegalActionException { 393 return arrayToMatrix(tokens, rows, columns); 394 } 395 396 /** Create an array of tokens of the given length. The first 397 * token in the sequence will have value start and each succeeding 398 * token will have the value created by adding the given increment 399 * to the preceding token. 400 * @param start The value of the first element of the returned array. 401 * @param increment The difference between elements in the array. 402 * @param length The size of the array to create, which must not be 403 * negative. 404 * @return An array of tokens of the given length. 405 * @exception IllegalActionException If the length is negative, or 406 * tokens of the given type cannot be added together. 407 */ 408 public static Token[] createSequence(Token start, Token increment, 409 int length) throws IllegalActionException { 410 Token[] result = new Token[length]; 411 Token value = start; 412 413 if (length > 0) { 414 result[0] = start; 415 416 for (int i = 1; i < length; i++) { 417 value = value.add(increment); 418 result[i] = value; 419 } 420 } 421 422 return result; 423 } 424 425 /** Return the (exact) return type of the createSequence function 426 * above. The return type is an array type whose element type is 427 * the least upper bound of the first two types. 428 * @param type1 The type of the first argument to the 429 * corresponding function. 430 * @param type2 The type of the second argument to the 431 * corresponding function. 432 * @param type3 The type of the third argument to the 433 * corresponding function. 434 * @return The type of the value returned from the corresponding 435 * function. 436 * @exception IllegalActionException If thrown while creating a 437 * new ArrayType object. 438 */ 439 public static Type createSequenceReturnType(Type type1, Type type2, 440 Type type3) throws IllegalActionException { 441 return new ArrayType(TypeLattice.leastUpperBound(type1, type2)); 442 } 443 444 /** Create an array of tokens of the given length. The first 445 * token in the sequence will have value start and each succeeding 446 * token will have the value created by adding the given increment 447 * to the preceding token. 448 * @param start The value of the first element of the returned array. 449 * @param increment The difference between elements in the array. 450 * @param length The size of the array to create, which must not be 451 * negative. 452 * @return an array of tokens. 453 * @exception IllegalActionException If the length is negative, or 454 * tokens of the given type cannot be added together. 455 * @deprecated Use createSequence() instead. 456 */ 457 @Deprecated 458 public static Token[] createTokenSequence(Token start, Token increment, 459 int length) throws IllegalActionException { 460 return createSequence(start, increment, length); 461 } 462 463 /** Return a new matrix that is a sub-matrix of this matrix. 464 * @param rowStart The row to start on. 465 * @param colStart The column to start on. 466 * @param rowSpan The number of rows to copy. 467 * @param colSpan The number of columns to copy. 468 * @return subclasses return a sub-matrix of this matrix. This 469 * base class does not return, it always throws an exception. 470 * @exception IllegalActionException If the operation is not 471 * supported. Always thrown in this base class. 472 */ 473 public MatrixToken crop(int rowStart, int colStart, int rowSpan, 474 int colSpan) throws IllegalActionException { 475 throw new IllegalActionException( 476 "crop: Operation not supported on class " + getClass() + "."); 477 } 478 479 /** Count the number of tokens differing by the given increment 480 * that fit in a range between the given start token and the 481 * given end token. This computes, type polymorphically, the 482 * value floor(((end-start)/increment) + 1). If the size of the 483 * sequence cannot be determined, because the increment is zero, 484 * or the increment is positive and end is greater than start, or 485 * the increment is negative and start is greater than end, 486 * then an exception will be thrown. 487 * @param start The given start token. 488 * @param increment The increment. 489 * @param end The given end token 490 * @return The size of the sequence, which will be greater than zero. 491 * @exception IllegalActionException If the length of the 492 * sequence cannot be determined, or the tokens provided do not 493 * support the zero, isEqualTo, isLessThan, add, divide, or 494 * subtract operations, or is not convertible to a double token. 495 */ 496 public static int determineSequenceLength(ScalarToken start, 497 ScalarToken increment, ScalarToken end) 498 throws IllegalActionException { 499 ScalarToken zero = (ScalarToken) increment.zero(); 500 501 if (increment.isEqualTo(increment.zero()).booleanValue()) { 502 throw new IllegalActionException("Sequence length cannot " 503 + "be determined because the increment is zero."); 504 } else if (increment.isLessThan(zero).booleanValue() 505 && start.isLessThan(end).booleanValue()) { 506 throw new IllegalActionException("Sequence length cannot " 507 + "be determined because the increment has the wrong sign."); 508 } else if (zero.isLessThan(increment).booleanValue() 509 && end.isLessThan(start).booleanValue()) { 510 throw new IllegalActionException("Sequence length cannot " 511 + "be determined because the increment has the wrong sign."); 512 } else { 513 ScalarToken diff = (ScalarToken) end.subtract(start) 514 .divide(increment); 515 int count; 516 517 // UGH... I don't see how to abstract this nicely... 518 if (diff instanceof LongToken) { 519 count = (int) diff.longValue() + 1; 520 } else if (diff instanceof DoubleToken) { 521 count = (int) diff.doubleValue() + 1; 522 } else { 523 count = diff.intValue() + 1; 524 } 525 526 if (count < 1) { 527 throw new InternalErrorException( 528 "The determined count does not make sense."); 529 } 530 531 return count; 532 } 533 } 534 535 /** Return a new token whose value is the value of this token 536 * divided by the value of the argument token. Division is not 537 * supported for matrices, so this throws an exception if the 538 * argument is a matrix. However, if it is a scalar, then division 539 * is performed elementwise. 540 * @param rightArgument The token that divides this token. 541 * @return A new token containing the result. 542 * @exception IllegalActionException If the operation 543 * does not make sense for the given types. 544 */ 545 @Override 546 public final Token divide(Token rightArgument) 547 throws IllegalActionException { 548 // Get the corresponding element type for this matrix type, 549 // and try a scalar operation. 550 Type elementType = getElementType(); 551 int typeInfo = TypeLattice.compare(elementType, rightArgument); 552 553 if (typeInfo == CPO.SAME) { 554 Token result = _divideElement(rightArgument); 555 return result; 556 } else if (typeInfo == CPO.HIGHER) { 557 Token convertedArgument = elementType.convert(rightArgument); 558 559 try { 560 Token result = _divideElement(convertedArgument); 561 return result; 562 } catch (IllegalActionException ex) { 563 // If the type-specific operation fails, then create a better 564 // error message that has the types of the arguments that were 565 // passed in. 566 throw new IllegalActionException(null, ex, 567 notSupportedMessage("divide", this, rightArgument)); 568 } 569 } 570 571 // If we get here, then either our element type is lower than 572 // the rightArgument or incomparable to it. 573 typeInfo = TypeLattice.compare(getType(), rightArgument); 574 575 if (typeInfo == CPO.SAME 576 && ((MatrixToken) rightArgument).getRowCount() == 1 577 && ((MatrixToken) rightArgument).getColumnCount() == 1) { 578 // Dividing a matrix by a matrix. If the divisor has 579 // only one element, then this is OK. 580 return _divideElement(rightArgument); 581 } else if (typeInfo == CPO.HIGHER 582 && ((MatrixToken) rightArgument).getRowCount() == 1 583 && ((MatrixToken) rightArgument).getColumnCount() == 1) { 584 // Dividing a matrix by something that can be converted 585 // to a matrix, which if it has one element is OK. 586 Token convertedArgument = getType().convert(rightArgument); 587 588 try { 589 return _divideElement(convertedArgument); 590 } catch (IllegalActionException ex) { 591 // If the type-specific operation fails, then create a better 592 // error message that has the types of the arguments that were 593 // passed in. 594 throw new IllegalActionException(null, ex, 595 notSupportedMessage("divide", this, rightArgument)); 596 } 597 } else if (typeInfo == CPO.INCOMPARABLE) { 598 // Items being divided are incomparable. 599 // However, division may still be possible because 600 // the LUB of the types might support it. E.g., [double]/complex, 601 // where the LUB is [complex]. 602 Type lubType = (Type) TypeLattice.lattice() 603 .leastUpperBound(getType(), rightArgument.getType()); 604 605 // If the LUB is a new type, try it. 606 if (!lubType.equals(getType())) { 607 Token lub = lubType.convert(this); 608 609 // Caution: convert() might return this again, e.g. 610 // if lubType is general. Only proceed if the conversion 611 // returned a new type. 612 if (!lub.getType().equals(getType())) { 613 return lub.divide(rightArgument); 614 } 615 } 616 } 617 618 throw new IllegalActionException( 619 notSupportedMessage("divide", this, rightArgument)); 620 } 621 622 /** Return a new token whose value is the value of the argument 623 * token divided by the value of this token. Division is not 624 * supported for matrices, so this always throws an exception. 625 * @param leftArgument The token to be divided by the value of this token. 626 * @return A new token containing the result. 627 * @exception IllegalActionException If the argument token and 628 * this token are of incomparable types, or the operation does 629 * not make sense for the given types. 630 */ 631 @Override 632 public Token divideReverse(Token leftArgument) 633 throws IllegalActionException { 634 throw new IllegalActionException( 635 notSupportedMessage("divideReverse", this, leftArgument)); 636 } 637 638 /** Return the content of this token as a 2-D double matrix. 639 * In this base class, just throw an exception. 640 * @return A 2-D double matrix. 641 * @exception IllegalActionException If the token cannot be represented 642 * as requested (always thrown in this base class). 643 */ 644 public double[][] doubleMatrix() throws IllegalActionException { 645 throw new IllegalActionException( 646 notSupportedConversionMessage(this, "double matrix")); 647 } 648 649 /** Return the content of this token as a 2-D fixed point matrix. 650 * In this base class, just throw an exception. 651 * @return A 2-D fix matrix. 652 * @exception IllegalActionException If the token cannot be represented 653 * as requested (always thrown in this base class). 654 */ 655 public FixPoint[][] fixMatrix() throws IllegalActionException { 656 throw new IllegalActionException( 657 notSupportedConversionMessage(this, "FixPoint matrix")); 658 } 659 660 /** Return the number of columns of the matrix. 661 * @return The number of columns of the matrix. 662 */ 663 public abstract int getColumnCount(); 664 665 /** Return the element of the matrix at the specified 666 * row and column wrapped in a token. 667 * @param row The row index of the desired element. 668 * @param column The column index of the desired element. 669 * @return A token containing the matrix element. 670 * @exception ArrayIndexOutOfBoundsException If the specified 671 * row or column number is outside the range of the matrix. 672 */ 673 public abstract Token getElementAsToken(int row, int column) 674 throws ArrayIndexOutOfBoundsException; 675 676 /** Return the Type of the tokens contained in this matrix token. 677 * @return A Type. 678 */ 679 public abstract Type getElementType(); 680 681 /** Return the number of rows of the matrix. 682 * @return The number of rows of the matrix. 683 */ 684 public abstract int getRowCount(); 685 686 /** Return the content of this token as a 2-D integer matrix. 687 * In this base class, just throw an exception. 688 * @return A 2-D integer matrix. 689 * @exception IllegalActionException If the token cannot be represented 690 * as requested (always thrown in this base class). 691 */ 692 public int[][] intMatrix() throws IllegalActionException { 693 throw new IllegalActionException( 694 notSupportedConversionMessage(this, "int matrix")); 695 } 696 697 /** Test whether the value of this Token is close to the argument 698 * Token. In this base class, we call isEqualTo() and the 699 * epsilon argument is ignored. This method should be overridden 700 * in derived classes such as DoubleToken and ComplexToken to 701 * provide type specific actions for equality testing using the 702 * epsilon argument 703 * 704 * @see #isEqualTo 705 * @param rightArgument The token to test closeness of this token with. 706 * @param epsilon The value that we use to determine whether two 707 * tokens are close. In this base class, the epsilon argument is 708 * ignored. 709 * @return a boolean token that contains the value true if the 710 * value and units of this token are close to those of the argument 711 * token. 712 * @exception IllegalActionException If the argument token is 713 * not of a type that can be compared with this token. 714 */ 715 @Override 716 public final BooleanToken isCloseTo(Token rightArgument, double epsilon) 717 throws IllegalActionException { 718 // Note that if we had absolute(), subtraction() and islessThan() 719 // we could perhaps define this method for all tokens. However, 720 // Precise classes like IntToken not bother doing the absolute(), 721 // subtraction(), and isLessThan() method calls and should go 722 // straight to isEqualTo(). Also, these methods might introduce 723 // exceptions because of type conversion issues. 724 int typeInfo = TypeLattice.compare(getType(), rightArgument); 725 726 if (typeInfo == CPO.SAME) { 727 return _doIsCloseTo(rightArgument, epsilon); 728 } else if (typeInfo == CPO.HIGHER) { 729 MatrixToken convertedArgument = (MatrixToken) getType() 730 .convert(rightArgument); 731 732 try { 733 return _doIsCloseTo(convertedArgument, epsilon); 734 } catch (IllegalActionException ex) { 735 // If the type-specific operation fails, then create a better 736 // error message that has the types of the arguments that were 737 // passed in. 738 throw new IllegalActionException(null, null, ex, 739 notSupportedMessage("isCloseTo", this, rightArgument)); 740 } 741 } else if (typeInfo == CPO.LOWER) { 742 return rightArgument.isCloseTo(this, epsilon); 743 } else { 744 throw new IllegalActionException(notSupportedIncomparableMessage( 745 "isCloseTo", this, rightArgument)); 746 } 747 } 748 749 /** Test for equality of the values of this Token and the argument 750 * Token. The argument and this token are converted to 751 * equivalent types, and then compared. Generally, this is the 752 * higher of the type of this token and the argument type. This 753 * method defers to the _isEqualTo method to perform a 754 * type-specific equality check. Derived classes should override 755 * that method to provide type specific actions for equality 756 * testing. 757 * 758 * @see #isCloseTo 759 * @param rightArgument The token with which to test equality. 760 * @exception IllegalActionException If this method is not 761 * supported by the derived class. 762 * @return A BooleanToken which contains the result of the test. 763 */ 764 @Override 765 public final BooleanToken isEqualTo(Token rightArgument) 766 throws IllegalActionException { 767 int typeInfo = TypeLattice.compare(getType(), rightArgument); 768 769 if (typeInfo == CPO.SAME) { 770 return _doIsEqualTo(rightArgument); 771 } else if (typeInfo == CPO.HIGHER) { 772 MatrixToken convertedArgument = (MatrixToken) getType() 773 .convert(rightArgument); 774 775 try { 776 return _doIsEqualTo(convertedArgument); 777 } catch (IllegalActionException ex) { 778 // If the type-specific operation fails, then create a better 779 // error message that has the types of the arguments that were 780 // passed in. 781 throw new IllegalActionException(null, ex, 782 notSupportedMessage("isEqualTo", this, rightArgument)); 783 } 784 } else if (typeInfo == CPO.LOWER) { 785 return rightArgument.isEqualTo(this); 786 } else { 787 throw new IllegalActionException(notSupportedIncomparableMessage( 788 "isEqualTo", this, rightArgument)); 789 } 790 } 791 792 /** Join a matrix of matrices into a single matrix by tiling. 793 * All matrices in the matrix must be of the same type, 794 * the same type as this matrix. But none of them needs to 795 * actually be this matrix. This base class simply throws 796 * an exception. Derived classes provide the implementation. 797 * The number of columns in the resulting matrix is the sum 798 * of the number of columns in the first row of the argument. 799 * The number of rows in the resulting matrix is the sum 800 * of the number of rows in the first column of the argument. 801 * The matrices are copied into the result starting at the 802 * position determined by the first row or column. 803 * If the matrices overlap, then while copying left to right, 804 * top-to-bottom, data will be overwritten. If there are gaps, 805 * the resulting matrix will be filled with zeros. 806 * @param matrices A two-dimensional array of matrix tokens. 807 * @return A new matrix token of the same type as the elements 808 * in the input matrix of matrix tokens. 809 * @exception IllegalActionException If the types of the matrices 810 * in the input are not all the same, or if tiling fails due 811 * to size incompatibilities, or if the input matrix has no 812 * tokens, or the operation is not supported by this matrix class. 813 */ 814 public MatrixToken join(MatrixToken[][] matrices) 815 throws IllegalActionException { 816 throw new IllegalActionException( 817 "join: Operation not supported on class " + getClass() + "."); 818 } 819 820 /** Return the content of this matrix as a 2-D long matrix. 821 * In this base class, just throw an exception. 822 * @return A 2-D long matrix. 823 * @exception IllegalActionException If the token cannot be represented 824 * as requested (always thrown in this base class). 825 */ 826 public long[][] longMatrix() throws IllegalActionException { 827 throw new IllegalActionException( 828 notSupportedConversionMessage(this, "long matrix")); 829 } 830 831 /** Create a new instance of ArrayToken that contains the values 832 * in the specified matrix. 833 * @param matrix The given matrix. 834 * @return An array. 835 */ 836 public static ArrayToken matrixToArray(MatrixToken matrix) { 837 return matrix.toArray(); 838 } 839 840 /** Return the (exact) return type of the toArray function above. If the 841 * argument is a matrix type, then return an array type of its 842 * element type, otherwise return BaseType.UNKNOWN. 843 * @param type The type of the argument to the corresponding function. 844 * @return The type of the value returned from the corresponding function. 845 */ 846 public static Type matrixToArrayReturnType(Type type) { 847 return toArrayReturnType(type); 848 } 849 850 /** Return a new token whose value is this token 851 * modulo the value of the argument token. 852 * @param rightArgument The token that performs modulo on this token. 853 * @return A new token containing the result. 854 * @exception IllegalActionException If the operation 855 * does not make sense for the given types. 856 */ 857 @Override 858 public final Token modulo(Token rightArgument) 859 throws IllegalActionException { 860 /* 861 // If the rightArgument is a complex token, throw an error 862 // message as modulo can't be operated. 863 if (rightArgument instanceof ComplexToken) 864 throw new IllegalActionException( 865 notSupportedMessage("modulo", this, rightArgument)); 866 */ 867 868 // Get the corresponding element type for this matrix type, 869 // and try a scalar operation. 870 Type elementType = getElementType(); 871 872 /* 873 // If this is a complex array, throw an error message as modulo 874 // can't be performed on it 875 if (elementType == BaseType.COMPLEX) 876 throw new IllegalActionException( 877 notSupportedMessage("modulo", this, rightArgument)); 878 */ 879 int typeInfo = TypeLattice.compare(elementType, rightArgument); 880 881 if (typeInfo == CPO.SAME) { 882 Token result = _moduloElement(rightArgument); 883 return result; 884 } else if (typeInfo == CPO.HIGHER) { 885 Token convertedArgument = elementType.convert(rightArgument); 886 887 try { 888 Token result = _moduloElement(convertedArgument); 889 return result; 890 } catch (IllegalActionException ex) { 891 // If the type-specific operation fails, then create a better 892 // error message that has the types of the arguments that were 893 // passed in. 894 throw new IllegalActionException(null, ex, 895 notSupportedMessage("modulo", this, rightArgument)); 896 } 897 } 898 899 // If we get here, then either our element type is lower than 900 // the rightArgument or incomparable to it. 901 typeInfo = TypeLattice.compare(getType(), rightArgument); 902 903 if (typeInfo == CPO.SAME) { 904 // Dividing a matrix by a matrix. If the divisor has 905 // only one element, then this is OK. 906 return _moduloElement(rightArgument); 907 } else if (typeInfo == CPO.HIGHER) { 908 // Dividing a matrix by something that can be converted 909 // to a matrix, which if it has one element is OK. 910 Token convertedArgument = getType().convert(rightArgument); 911 912 try { 913 return _moduloElement(convertedArgument); 914 } catch (IllegalActionException ex) { 915 // If the type-specific operation fails, then create a better 916 // error message that has the types of the arguments that were 917 // passed in. 918 throw new IllegalActionException(null, ex, 919 notSupportedMessage("modulo", this, rightArgument)); 920 } 921 } else if (typeInfo == CPO.INCOMPARABLE) { 922 // Items being added are incomparable. 923 // However, division may still be possible because 924 // the LUB of the types might support it. E.g., [double]/complex, 925 // where the LUB is [complex]. 926 Type lubType = (Type) TypeLattice.lattice() 927 .leastUpperBound(getType(), rightArgument.getType()); 928 929 // If the LUB is a new type, try it. 930 if (!lubType.equals(getType())) { 931 Token lub = lubType.convert(this); 932 933 // Caution: convert() might return this again, e.g. 934 // if lubType is general. Only proceed if the conversion 935 // returned a new type. 936 if (!lub.getType().equals(getType())) { 937 return lub.modulo(rightArgument); 938 } 939 } 940 } 941 942 throw new IllegalActionException( 943 notSupportedMessage("modulo", this, rightArgument)); 944 } 945 946 /** Return a new token whose value is the value of the argument token 947 * modulo the value of this token. Since modulo is not 948 * supported for matrices, this always throws an exception. 949 * @param leftArgument The token to apply modulo to by the value 950 * of this token. 951 * @return A new token containing the result. 952 * @exception IllegalActionException If the the operation does 953 * not make sense for the given types. 954 */ 955 @Override 956 public final Token moduloReverse(Token leftArgument) 957 throws IllegalActionException { 958 throw new IllegalActionException( 959 notSupportedMessage("moduloReverse", this, leftArgument)); 960 } 961 962 /** Return a new token whose value is the value of this token 963 * multiplied by the value of the argument token. Type 964 * conversion also occurs here, so that the operation is 965 * performed at the least type necessary to ensure precision. 966 * The returned type is the same as the type chosen for the 967 * operation. Generally, this is higher of the type of this 968 * token and the argument type. This class overrides the base 969 * class to perform conversion from scalars to matrices 970 * appropriately for matrix multiplication. Subclasses should 971 * not generally override this method, but override the protected 972 * _multiply() method to ensure that type conversion is performed 973 * consistently. 974 * @param rightArgument The token to multiply this token by. 975 * @return A new token containing the result. 976 * @exception IllegalActionException If the argument token 977 * and this token are of incomparable types, or the operation 978 * does not make sense for the given types. 979 */ 980 @Override 981 public final Token multiply(Token rightArgument) 982 throws IllegalActionException { 983 // MatrixType type = (MatrixType)getType(); 984 // Get the corresponding element type for this matrix type, 985 // and try a scalar operation. 986 Type elementType = getElementType(); 987 int typeInfo = TypeLattice.compare(elementType, rightArgument); 988 989 if (typeInfo == CPO.SAME) { 990 Token result = _multiplyElement(rightArgument); 991 return result; 992 } else if (typeInfo == CPO.HIGHER) { 993 Token convertedArgument = elementType.convert(rightArgument); 994 995 try { 996 Token result = _multiplyElement(convertedArgument); 997 return result; 998 } catch (IllegalActionException ex) { 999 // If the type-specific operation fails, then create a better 1000 // error message that has the types of the arguments that were 1001 // passed in. 1002 throw new IllegalActionException(null, ex, 1003 notSupportedMessage("multiply", this, rightArgument)); 1004 } 1005 } 1006 1007 // Argument must be a matrix or incomparable. 1008 typeInfo = TypeLattice.compare(getType(), rightArgument); 1009 1010 if (typeInfo == CPO.SAME) { 1011 Token result = _doMultiply(rightArgument); 1012 return result; 1013 } else if (typeInfo == CPO.HIGHER) { 1014 MatrixToken convertedArgument = (MatrixToken) getType() 1015 .convert(rightArgument); 1016 1017 try { 1018 Token result = _doMultiply(convertedArgument); 1019 return result; 1020 } catch (IllegalActionException ex) { 1021 // If the type-specific operation fails, then create a 1022 // better error message that has the types of the 1023 // arguments that were passed in. 1024 throw new IllegalActionException(null, ex, 1025 notSupportedMessage("multiply", this, rightArgument)); 1026 } 1027 } else if (typeInfo == CPO.LOWER) { 1028 Token result = rightArgument.multiplyReverse(this); 1029 return result; 1030 } else { 1031 // Items being multiplied are incomparable. 1032 // However, multiplication may still be possible because 1033 // the LUB of the types might support it. E.g., [double]*complex, 1034 // where the LUB is [complex]. 1035 Type lubType = (Type) TypeLattice.lattice() 1036 .leastUpperBound(getType(), rightArgument.getType()); 1037 1038 // If the LUB is a new type, try it. 1039 if (!lubType.equals(getType())) { 1040 Token lub = lubType.convert(this); 1041 1042 // Caution: convert() might return this again, e.g. 1043 // if lubType is general. Only proceed if the conversion 1044 // returned a new type. 1045 if (!lub.getType().equals(getType())) { 1046 return lub.multiply(rightArgument); 1047 } 1048 } 1049 1050 throw new IllegalActionException(notSupportedIncomparableMessage( 1051 "multiply", this, rightArgument)); 1052 } 1053 } 1054 1055 /** Return a new token whose value is the value of the argument token 1056 * multiplied by the value of this token. 1057 * Type resolution also occurs here, with the returned token 1058 * type chosen to achieve a lossless conversion. 1059 * @param leftArgument The token to be multiplied by the value of 1060 * this token. 1061 * @return A new token containing the result. 1062 * @exception IllegalActionException If the argument token 1063 * is not of a type that can be multiplied by this token. 1064 */ 1065 @Override 1066 public final Token multiplyReverse(Token leftArgument) 1067 throws IllegalActionException { 1068 // Get the corresponding element type for this matrix type, 1069 // and try a scalar operation. 1070 Type elementType = getElementType(); 1071 int typeInfo = TypeLattice.compare(leftArgument, elementType); 1072 1073 if (typeInfo == CPO.LOWER) { 1074 Token convertedArgument = elementType.convert(leftArgument); 1075 1076 try { 1077 Token result = _multiplyElement(convertedArgument); 1078 return result; 1079 } catch (IllegalActionException ex) { 1080 // If the type-specific operation fails, then create a 1081 // better error message that has the types of the 1082 // arguments that were passed in. 1083 throw new IllegalActionException(null, ex, 1084 notSupportedMessage("multiply", this, leftArgument)); 1085 } 1086 } else if (typeInfo == CPO.SAME) { 1087 Token result = _multiplyElement(leftArgument); 1088 return result; 1089 } 1090 1091 // Must be a matrix or incomparable. 1092 typeInfo = TypeLattice.compare(leftArgument, getType()); 1093 1094 // We would normally expect this to be LOWER, since this will almost 1095 // always be called by subtract, so put that case first. 1096 if (typeInfo == CPO.LOWER) { 1097 MatrixToken convertedArgument = (MatrixToken) getType() 1098 .convert(leftArgument); 1099 1100 try { 1101 Token result = convertedArgument._doMultiply(this); 1102 return result; 1103 } catch (IllegalActionException ex) { 1104 // If the type-specific operation fails, then create a 1105 // better error message that has the types of the 1106 // arguments that were passed in. 1107 throw new IllegalActionException(null, ex, notSupportedMessage( 1108 "multiplyReverse", this, leftArgument)); 1109 } 1110 } else if (typeInfo == CPO.SAME) { 1111 Token result = ((MatrixToken) leftArgument)._doMultiply(this); 1112 return result; 1113 } else if (typeInfo == CPO.HIGHER) { 1114 Token result = leftArgument.multiply(this); 1115 return result; 1116 } else { 1117 // Items being multiplied are incomparable. 1118 // However, multiplication may still be possible because 1119 // the LUB of the types might support it. E.g., [double]*complex, 1120 // where the LUB is [complex]. 1121 Type lubType = (Type) TypeLattice.lattice() 1122 .leastUpperBound(getType(), leftArgument.getType()); 1123 1124 // If the LUB is a new type, try it. 1125 if (!lubType.equals(getType())) { 1126 Token lub = lubType.convert(this); 1127 1128 // Caution: convert() might return this again, e.g. 1129 // if lubType is general. Only proceed if the conversion 1130 // returned a new type. 1131 if (!lub.getType().equals(getType())) { 1132 return lub.multiplyReverse(leftArgument); 1133 } 1134 } 1135 1136 throw new IllegalActionException(notSupportedIncomparableMessage( 1137 "multiplyReverse", leftArgument, this)); 1138 } 1139 } 1140 1141 /** Return a new Token representing the right multiplicative 1142 * identity. The returned token contains an identity matrix 1143 * whose dimensions are the same as the number of columns of 1144 * the matrix contained in this token. 1145 * The implementation in this base class just throws an 1146 * exception. This method should be overridden in the subclass 1147 * when the right multiplicative identity exists. 1148 * @return A new MatrixToken containing the right multiplicative 1149 * identity. 1150 * @exception IllegalActionException If this method is not 1151 * supported by the derived class. 1152 */ 1153 public Token oneRight() throws IllegalActionException { 1154 throw new IllegalActionException("Right multiplicative identity " 1155 + "not supported on " + getClass().getName() + " objects."); 1156 } 1157 1158 /** Split this matrix into multiple matrices. In this base 1159 * class, this method simply throws an exception. Derived 1160 * classes provide the implementation. 1161 * <p> 1162 * The matrices are produced from submatrices extracted 1163 * left-to-right, top-to-bottom, in a raster scan pattern. 1164 * For example, if <i>rowSplit</i> = {1, 2}, 1165 * <i>columnSplit</i> = {2, 1}, and the input matrix is 1166 * as follows: 1167 * <pre> 1168 * 1 2 3 1169 * 4 5 6 1170 * 7 8 9 1171 * </pre> 1172 * then the first matrix out is a column vector: 1173 * <pre> 1174 * 1 1175 * 4 1176 * </pre> 1177 * The second matrix out is 1178 * <pre> 1179 * 2 3 1180 * 5 6 1181 * </pre> 1182 * The third is 1183 * <pre> 1184 * 7 1185 * </pre> 1186 * (a 1x1 matrix) and the fourth is 1187 * <pre> 1188 * 8 9 1189 * </pre> 1190 * a row vector. 1191 * If the input does not have enough elements to fill the specified 1192 * output matrices, then zeros (of the same type as the input elements) 1193 * are used. If the input is larger than is required to fill the specified 1194 * output, then the additional values are discarded. 1195 * @param rows The number of rows per submatrix. 1196 * @param columns The number of columns per submatrix. 1197 * @return An array of matrix tokens. 1198 * @exception IllegalActionException If the operation is not supported. 1199 */ 1200 public MatrixToken[][] split(int[] rows, int[] columns) 1201 throws IllegalActionException { 1202 throw new IllegalActionException( 1203 "split: Operation not supported on class " + getClass() + "."); 1204 } 1205 1206 /** Return a new token whose value is the value of the argument token 1207 * subtracted from the value of this token. Type conversion 1208 * also occurs here, so that the operation is performed at the 1209 * least type necessary to ensure precision. The returned type 1210 * is the same as the type chosen for the operation. Generally, 1211 * this is higher of the type of this token and the argument 1212 * type. Subclasses should not override this method, 1213 * but override the protected _subtract() method to ensure that type 1214 * conversion is performed consistently. 1215 * @param rightArgument The token to subtract from this token. 1216 * @return A new token containing the result. 1217 * @exception IllegalActionException If the argument token 1218 * and this token are of incomparable types, or the operation 1219 * does not make sense for the given types. 1220 */ 1221 @Override 1222 public final Token subtract(Token rightArgument) 1223 throws IllegalActionException { 1224 // Get the corresponding element type for this matrix type, 1225 // and try a scalar operation. 1226 Type elementType = getElementType(); 1227 int typeInfo = TypeLattice.compare(elementType, rightArgument); 1228 1229 if (typeInfo == CPO.SAME) { 1230 Token result = _subtractElement(rightArgument); 1231 return result; 1232 } else if (typeInfo == CPO.HIGHER) { 1233 Token convertedArgument = elementType.convert(rightArgument); 1234 1235 try { 1236 Token result = _subtractElement(convertedArgument); 1237 return result; 1238 } catch (IllegalActionException ex) { 1239 // If the type-specific operation fails, then create a better 1240 // error message that has the types of the arguments that were 1241 // passed in. 1242 throw new IllegalActionException(null, ex, 1243 notSupportedMessage("subtract", this, rightArgument)); 1244 } 1245 } 1246 1247 // If we get here, then either our element type is lower than 1248 // the rightArgument or incomparable to it. 1249 typeInfo = TypeLattice.compare(getType(), rightArgument); 1250 1251 if (typeInfo == CPO.SAME) { 1252 Token result = _doSubtract(rightArgument); 1253 return result; 1254 } else if (typeInfo == CPO.HIGHER) { 1255 MatrixToken convertedArgument = (MatrixToken) getType() 1256 .convert(rightArgument); 1257 1258 try { 1259 Token result = _doSubtract(convertedArgument); 1260 return result; 1261 } catch (IllegalActionException ex) { 1262 // If the type-specific operation fails, then create a 1263 // better error message that has the types of the 1264 // arguments that were passed in. 1265 throw new IllegalActionException(null, ex, 1266 notSupportedMessage("subtract", this, rightArgument)); 1267 } 1268 } else if (typeInfo == CPO.LOWER) { 1269 Token result = rightArgument.subtractReverse(this); 1270 return result; 1271 } else { 1272 // Items being subracted are incomparable. 1273 // However, subtraction may still be possible because 1274 // the LUB of the types might support it. E.g., [double]-complex, 1275 // where the LUB is [complex]. 1276 Type lubType = (Type) TypeLattice.lattice() 1277 .leastUpperBound(getType(), rightArgument.getType()); 1278 1279 // If the LUB is a new type, try it. 1280 if (!lubType.equals(getType())) { 1281 Token lub = lubType.convert(this); 1282 1283 // Caution: convert() might return this again, e.g. 1284 // if lubType is general. Only proceed if the conversion 1285 // returned a new type. 1286 if (!lub.getType().equals(getType())) { 1287 return lub.subtract(rightArgument); 1288 } 1289 } 1290 1291 throw new IllegalActionException(notSupportedIncomparableMessage( 1292 "subtract", this, rightArgument)); 1293 } 1294 } 1295 1296 /** Return a new token whose value is the value of this token 1297 * subtracted from the value of the argument token. 1298 * Type resolution also occurs here, with the returned token type 1299 * chosen to achieve a lossless conversion. 1300 * @param leftArgument The token to subtract this token from. 1301 * @return A new token containing the result. 1302 * @exception IllegalActionException If the argument token is not 1303 * of a type that can be subtracted to this token, or the units 1304 * of this token and the argument token are not the same. 1305 */ 1306 @Override 1307 public final Token subtractReverse(Token leftArgument) 1308 throws IllegalActionException { 1309 // Get the corresponding element type for this matrix type, 1310 // and try a scalar operation. 1311 Type elementType = getElementType(); 1312 int typeInfo = TypeLattice.compare(leftArgument, elementType); 1313 1314 if (typeInfo == CPO.LOWER) { 1315 Token convertedArgument = elementType.convert(leftArgument); 1316 1317 try { 1318 Token result = _subtractElementReverse(convertedArgument); 1319 return result; 1320 } catch (IllegalActionException ex) { 1321 // If the type-specific operation fails, then create a 1322 // better error message that has the types of the 1323 // arguments that were passed in. 1324 throw new IllegalActionException(null, ex, 1325 notSupportedMessage("subtract", this, leftArgument)); 1326 } 1327 } else if (typeInfo == CPO.SAME) { 1328 Token result = _subtractElementReverse(leftArgument); 1329 return result; 1330 } 1331 1332 // If we get here, then either our element type is lower than 1333 // the rightArgument or incomparable to it. 1334 typeInfo = TypeLattice.compare(leftArgument, getType()); 1335 1336 // We would normally expect this to be LOWER, since this will almost 1337 // always be called by subtract, so put that case first. 1338 if (typeInfo == CPO.LOWER) { 1339 MatrixToken convertedArgument = (MatrixToken) getType() 1340 .convert(leftArgument); 1341 1342 try { 1343 Token result = convertedArgument._doSubtract(this); 1344 return result; 1345 } catch (IllegalActionException ex) { 1346 // If the type-specific operation fails, then create a 1347 // better error message that has the types of the 1348 // arguments that were passed in. 1349 throw new IllegalActionException(null, ex, notSupportedMessage( 1350 "subtractReverse", this, leftArgument)); 1351 } 1352 } else if (typeInfo == CPO.SAME) { 1353 Token result = ((MatrixToken) leftArgument)._doSubtract(this); 1354 return result; 1355 } else if (typeInfo == CPO.HIGHER) { 1356 Token result = leftArgument.subtract(this); 1357 return result; 1358 } else { 1359 // Items being subtracted are incomparable. 1360 // However, subtraction may still be possible because 1361 // the LUB of the types might support it. E.g., complex-[double], 1362 // where the LUB is [complex]. 1363 Type lubType = (Type) TypeLattice.lattice() 1364 .leastUpperBound(getType(), leftArgument.getType()); 1365 1366 // If the LUB is a new type, try it. 1367 if (!lubType.equals(getType())) { 1368 Token lub = lubType.convert(this); 1369 1370 // Caution: convert() might return this again, e.g. 1371 // if lubType is general. Only proceed if the conversion 1372 // returned a new type. 1373 if (!lub.getType().equals(getType())) { 1374 return lub.subtractReverse(leftArgument); 1375 } 1376 } 1377 1378 throw new IllegalActionException(notSupportedIncomparableMessage( 1379 "subtractReverse", this, leftArgument)); 1380 } 1381 } 1382 1383 /** Return an ArrayToken containing the all the values of this 1384 * matrix token. The type of the tokens in the array is consistent 1385 * with the type of this token. 1386 * 1387 * @return An ArrayToken containing the elements of this matrix in 1388 * row-scanned order. 1389 */ 1390 public ArrayToken toArray() { 1391 int rowCount = getRowCount(); 1392 int columnCount = getColumnCount(); 1393 Token[] output = new Token[rowCount * columnCount]; 1394 1395 for (int i = 0, n = 0; i < rowCount; i++) { 1396 for (int j = 0; j < columnCount; j++) { 1397 output[n++] = getElementAsToken(i, j); 1398 } 1399 } 1400 1401 ArrayToken result; 1402 1403 try { 1404 result = new ArrayToken(output); 1405 } catch (IllegalActionException illegalAction) { 1406 // Cannot happen, since the elements of MatrixToken always 1407 // have the same type. 1408 throw new InternalErrorException("MatrixToken.toArray: Cannot " 1409 + "construct ArrayToken. " + illegalAction.getMessage()); 1410 } 1411 1412 return result; 1413 } 1414 1415 /** Return an ArrayToken containing the all the values of this 1416 * matrix token. The type of the tokens in the array is consistent 1417 * with the type of this token. 1418 * 1419 * @return An ArrayToken containing the elements of this matrix in 1420 * column-scanned order. 1421 */ 1422 public ArrayToken toArrayColumnMajor() { 1423 int rowCount = getRowCount(); 1424 int columnCount = getColumnCount(); 1425 Token[] output = new Token[rowCount * columnCount]; 1426 1427 for (int i = 0, n = 0; i < columnCount; i++) { 1428 for (int j = 0; j < rowCount; j++) { 1429 output[n++] = getElementAsToken(j, i); 1430 } 1431 } 1432 1433 ArrayToken result; 1434 1435 try { 1436 result = new ArrayToken(output); 1437 } catch (IllegalActionException illegalAction) { 1438 // Cannot happen, since the elements of MatrixToken always 1439 // have the same type. 1440 throw new InternalErrorException("MatrixToken.toArray: Cannot " 1441 + "construct ArrayToken. " + illegalAction.getMessage()); 1442 } 1443 1444 return result; 1445 } 1446 1447 /** Return the (exact) return type of the toArray function above. If the 1448 * argument is a matrix type, then return an array type of its 1449 * element type, otherwise return BaseType.UNKNOWN. 1450 * @param type The type of the argument to the corresponding function. 1451 * @return The type of the value returned from the corresponding function. 1452 */ 1453 public static Type toArrayReturnType(Type type) { 1454 if (type instanceof MatrixType) { 1455 Type elementType = ((MatrixType) type).getElementType(); 1456 return new ArrayType(elementType); 1457 } else { 1458 return BaseType.UNKNOWN; 1459 } 1460 } 1461 1462 /** Return the value of this token as a string that can be parsed 1463 * by the expression language to recover a token with the same value. 1464 * The expression starts and ends with a square bracket. The matrix is 1465 * scanned starting from the upper left and proceeding across each row. 1466 * Each element in the row is separated by a comma, and the end of a row 1467 * is represented by a semicolon. The value of each element is obtained 1468 * using its toString method. 1469 * @return A String representing a matrix similar to Matlab. 1470 */ 1471 @Override 1472 public String toString() { 1473 int rowCount = getRowCount(); 1474 int columnCount = getColumnCount(); 1475 StringBuffer sb = new StringBuffer(); 1476 sb.append("["); 1477 1478 for (int i = 0; i < rowCount; i++) { 1479 for (int j = 0; j < columnCount; j++) { 1480 // Handle nil token 1481 if (_nils != null && _nils 1482 .contains(Integer.valueOf(i * columnCount + j))) { 1483 sb.append("nil"); 1484 } else { 1485 sb.append(getElementAsToken(i, j).toString()); 1486 } 1487 1488 if (j < columnCount - 1) { 1489 sb.append(", "); 1490 } 1491 } 1492 1493 if (i < rowCount - 1) { 1494 sb.append("; "); 1495 } 1496 } 1497 1498 sb.append("]"); 1499 return sb.toString(); 1500 } 1501 1502 /////////////////////////////////////////////////////////////////// 1503 //// public variables //// 1504 1505 /** A constant indicating to constructors that contents of an argument 2-D 1506 * matrix should be copied. The contents of the input 2-D matrix may be 1507 * modified after construction without violating the immutability of 1508 * MatrixTokens. 1509 */ 1510 public static final int DO_COPY = 0; 1511 1512 /** A constant indicating to constructors not to copy the contents 1513 * of an argument 2-D matrix, but instead to just copy the 1514 * pointer to the matrix. The contents of the input 2-D matrix 1515 * should NOT be modified after construction of an 1516 * instance of MatrixToken, if the property of immutability is 1517 * to be preserved. 1518 */ 1519 public static final int DO_NOT_COPY = 1; 1520 1521 /////////////////////////////////////////////////////////////////// 1522 //// protected methods //// 1523 1524 /** Return a new token whose value is the value of the argument 1525 * Token added to the value of this Token. It is guaranteed by 1526 * the caller that the type of the argument is the same as the 1527 * type of this class, and that the matrices have appropriate 1528 * dimensions. This method should be overridden in derived 1529 * classes to provide type-specific operation and return a token 1530 * of the appropriate subclass. 1531 * @param rightArgument The token to add to this token. 1532 * @exception IllegalActionException If this method is not 1533 * supported by the derived class. 1534 * @return A new Token containing the result. 1535 */ 1536 protected MatrixToken _add(MatrixToken rightArgument) 1537 throws IllegalActionException { 1538 throw new IllegalActionException( 1539 notSupportedMessage("add", this, rightArgument)); 1540 } 1541 1542 /** Return a new token whose value is the value of the argument 1543 * Token added to the value of each element of this Token. It is 1544 * guaranteed by the caller that the type of the argument 1545 * is the same as the type of each element of this class. 1546 * @param rightArgument The token to add to this token. 1547 * @exception IllegalActionException If this operation is not 1548 * supported by the derived class. 1549 * @return A new Token containing the result. 1550 */ 1551 protected MatrixToken _addElement(Token rightArgument) 1552 throws IllegalActionException { 1553 throw new IllegalActionException( 1554 notSupportedMessage("add", this, rightArgument)); 1555 } 1556 1557 /** Return a new token whose elements are the result of dividing 1558 * the elements of this token by the argument. It is 1559 * guaranteed by the caller that the type of the argument 1560 * is the same as the type of each element of this class. 1561 * @param rightArgument The token that divides this token. 1562 * @exception IllegalActionException If this operation is not 1563 * supported by the derived class. 1564 * @return A new Token containing the result. 1565 */ 1566 protected MatrixToken _divideElement(Token rightArgument) 1567 throws IllegalActionException { 1568 throw new IllegalActionException( 1569 notSupportedMessage("divide", this, rightArgument)); 1570 } 1571 1572 /** Test whether the value of this token is close to the first 1573 * argument, where "close" means that the distance between their 1574 * elements is less than or equal to the second argument. This 1575 * base class delegates to the token class corresponding to the 1576 * matrix elements, using its isCloseTo() method. If the two 1577 * matrices do have the same dimension, then this method returns 1578 * false. 1579 * 1580 * @param token The matrix token to compare to this token. 1581 * @param distance The specified distance. 1582 * @return True if every element of the specified matrix is within 1583 * the specified distance of the corresponding element of this matrix. 1584 * @exception IllegalActionException If a derived class throws it. 1585 */ 1586 protected BooleanToken _isCloseTo(MatrixToken token, double distance) 1587 throws IllegalActionException { 1588 int rows = getRowCount(); 1589 int columns = getColumnCount(); 1590 1591 if (token.getRowCount() != rows || token.getColumnCount() != columns) { 1592 return BooleanToken.FALSE; 1593 } 1594 1595 for (int i = 0; i < rows; i++) { 1596 for (int j = 0; j < columns; j++) { 1597 Token element = getElementAsToken(i, j); 1598 Token other = token.getElementAsToken(i, j); 1599 1600 if (!element.isCloseTo(other, distance).booleanValue()) { 1601 return BooleanToken.FALSE; 1602 } 1603 } 1604 } 1605 1606 return BooleanToken.TRUE; 1607 } 1608 1609 /** Test for equality of the values of this Token and the argument 1610 * Token. It is guaranteed by the caller that the type and 1611 * dimensions of the argument is the same as the type of this 1612 * class. This method can be overridden in derived classes to 1613 * provide type-specific operation and return a token of the 1614 * appropriate subclass. In this base class, this method 1615 * delegates to equals(). 1616 * @param rightArgument The token to compare to this token. 1617 * @exception IllegalActionException If this method is not 1618 * supported by a derived class. 1619 * @return A true-valued token if the argument is equal to this 1620 * matrix. 1621 */ 1622 protected BooleanToken _isEqualTo(MatrixToken rightArgument) 1623 throws IllegalActionException { 1624 return BooleanToken.getInstance(equals(rightArgument)); 1625 } 1626 1627 /** Add the element to the _nils Set. Subclasses should call this 1628 * when they encounter a nil token during construction. If _nils 1629 * is null, this method constructs _nils as a new HashSet. 1630 * @param element The element index. The format is rows * columnCount 1631 * + column. 1632 */ 1633 protected void _elementIsNil(int element) { 1634 if (_nils == null) { 1635 _nils = new HashSet(); 1636 } 1637 _nils.add(Integer.valueOf(element)); 1638 } 1639 1640 /** Return a new token whose elements are the modulo of 1641 * the elements of this token by the argument. It is 1642 * guaranteed by the caller that the type of the argument 1643 * is the same as the type of each element of this class. 1644 * @param rightArgument The token that performs modulo on this token. 1645 * @exception IllegalActionException If this operation is not 1646 * supported by the derived class. 1647 * @return A new Token containing the result. 1648 */ 1649 protected MatrixToken _moduloElement(Token rightArgument) 1650 throws IllegalActionException { 1651 throw new IllegalActionException( 1652 notSupportedMessage("modulo", this, rightArgument)); 1653 } 1654 1655 /** Return a new token whose value is the value of this token 1656 * multiplied by the value of the argument token. It is 1657 * guaranteed by the caller that the type of the argument is the 1658 * same as the type of this class, and that the matrices have 1659 * appropriate dimensions. This method should be overridden in 1660 * derived classes to provide type-specific operation and return 1661 * a token of the appropriate subclass. 1662 * @param rightArgument The token to multiply this token by. 1663 * @exception IllegalActionException If this method is not 1664 * supported by the derived class. 1665 * @return A new Token containing the result. 1666 */ 1667 protected MatrixToken _multiply(MatrixToken rightArgument) 1668 throws IllegalActionException { 1669 throw new IllegalActionException( 1670 notSupportedMessage("multiply", this, rightArgument)); 1671 } 1672 1673 /** Return a new token whose value is the value of this token 1674 * multiplied by the value of the argument scalar token. 1675 * This method should be overridden in derived 1676 * classes to provide type specific actions for multiply. 1677 * @param rightArgument The token to multiply this token by. 1678 * @exception IllegalActionException If this method is not 1679 * supported by the derived class. 1680 * @return A new Token containing the result that is of the same class 1681 * as this token. 1682 */ 1683 protected MatrixToken _multiplyElement(Token rightArgument) 1684 throws IllegalActionException { 1685 throw new IllegalActionException( 1686 notSupportedMessage("multiply", this, rightArgument)); 1687 } 1688 1689 /** Return a new token whose value is the value of the argument 1690 * token subtracted from the value of this token. It is 1691 * guaranteed by the caller that the type of the argument is the 1692 * same as the type of this class, and that the matrices have 1693 * appropriate dimensions. This method should be overridden in 1694 * derived classes to provide type-specific operation and return 1695 * a token of the appropriate subclass. 1696 * @param rightArgument The token to subtract from this token. 1697 * @exception IllegalActionException If this method is not 1698 * supported by the derived class. 1699 * @return A new Token containing the result. 1700 */ 1701 protected MatrixToken _subtract(MatrixToken rightArgument) 1702 throws IllegalActionException { 1703 throw new IllegalActionException( 1704 notSupportedMessage("subtract", this, rightArgument)); 1705 } 1706 1707 /** Return a new token whose value is the value of the argument 1708 * Token subtracted from the value of each element of this 1709 * Token. It is guaranteed by the caller that the type of the 1710 * argument is the same as the type of each element of this 1711 * class. 1712 * @param rightArgument The token to subtract from this token. 1713 * @exception IllegalActionException If this operation is not 1714 * supported by the derived class. 1715 * @return A new Token containing the result. 1716 */ 1717 protected MatrixToken _subtractElement(Token rightArgument) 1718 throws IllegalActionException { 1719 throw new IllegalActionException( 1720 notSupportedMessage("subtract", this, rightArgument)); 1721 } 1722 1723 /** Return a new token whose value is the value of each element of 1724 * this Token subtracted from the value the argument Token. It is 1725 * guaranteed by the caller that the type of the argument is the 1726 * same as the type of each element of this class. 1727 * @param rightArgument The token to subtract this token from. 1728 * @exception IllegalActionException If this operation is not 1729 * supported by the derived class. 1730 * @return A new Token containing the result. 1731 */ 1732 protected MatrixToken _subtractElementReverse(Token rightArgument) 1733 throws IllegalActionException { 1734 throw new IllegalActionException( 1735 notSupportedMessage("subtract", this, rightArgument)); 1736 } 1737 1738 /////////////////////////////////////////////////////////////////// 1739 //// protected variables //// 1740 1741 /** HashSet of nil elements, where each element is the index of the 1742 * element in _value[] that should be nil. 1743 */ 1744 protected Set _nils; 1745 1746 /////////////////////////////////////////////////////////////////// 1747 //// private methods //// 1748 1749 /** Return a new token whose value is the value of the argument 1750 * Token added to the value of this Token. It is guaranteed by 1751 * the caller that the type of the argument is the same as the 1752 * type of this class. This method defers to the _add method 1753 * that takes a MatrixToken. Derived classes should override 1754 * that method instead to provide type-specific operation. 1755 * @param rightArgument The token to add to this token. 1756 * @exception IllegalActionException If the matrix dimensions are 1757 * not compatible, or this operation is not supported by the 1758 * derived class. 1759 * @return A new Token containing the result. 1760 */ 1761 private Token _doAdd(Token rightArgument) throws IllegalActionException { 1762 MatrixToken convertedArgument = (MatrixToken) rightArgument; 1763 1764 if (convertedArgument.getRowCount() != getRowCount() 1765 || convertedArgument.getColumnCount() != getColumnCount()) { 1766 // Either this matrix or the argument might be a size one matrix 1767 // converted automatically from a scalar. Support this by 1768 // scalar addition. 1769 if (getRowCount() == 1 && getColumnCount() == 1) { 1770 // This matrix should be treated as a scalar. 1771 return convertedArgument._addElement(getElementAsToken(0, 0)); 1772 } else if (convertedArgument.getRowCount() == 1 1773 && convertedArgument.getColumnCount() == 1) { 1774 // The argument matrix should be treated as a scalar. 1775 return _addElement(convertedArgument.getElementAsToken(0, 0)); 1776 } else { 1777 throw new IllegalActionException(Token 1778 .notSupportedMessage("add", this, rightArgument) 1779 + " because the matrices have different dimensions."); 1780 } 1781 } 1782 1783 MatrixToken result = _add(convertedArgument); 1784 return result; 1785 } 1786 1787 /** Test for closeness of the values of this Token and the 1788 * argument Token. It is guaranteed by the caller that the type 1789 * of the argument is the same as the type of this class. This 1790 * class overrides the base class to return BooleanToken.FALSE if 1791 * the dimensions of this token and the given token are not 1792 * identical. This method may defer to the _isEqualTo method 1793 * that takes a MatrixToken. Derived classes should override 1794 * that method instead to provide type-specific operation. 1795 * @param rightArgument The token with which to test equality. 1796 * @exception IllegalActionException If this method is not 1797 * supported by the derived class. 1798 * @return A BooleanToken which contains the result of the test. 1799 */ 1800 private BooleanToken _doIsCloseTo(Token rightArgument, double epsilon) 1801 throws IllegalActionException { 1802 MatrixToken convertedArgument = (MatrixToken) rightArgument; 1803 1804 if (convertedArgument.getRowCount() != getRowCount() 1805 || convertedArgument.getColumnCount() != getColumnCount()) { 1806 return BooleanToken.FALSE; 1807 } 1808 1809 return _isCloseTo(convertedArgument, epsilon); 1810 } 1811 1812 /** Test for equality of the values of this Token and the argument 1813 * Token. It is guaranteed by the caller that the type of the 1814 * argument is the same as the type of this class. This class 1815 * overrides the base class to return BooleanToken.FALSE if the 1816 * dimensions of this token and the given token are not 1817 * identical. This method may defer to the _isEqualTo method 1818 * that takes a MatrixToken. Derived classes should override 1819 * that method instead to provide type-specific operation. 1820 * @param rightArgument The token with which to test equality. 1821 * @exception IllegalActionException If this method is not 1822 * supported by the derived class. 1823 * @return A BooleanToken which contains the result of the test. 1824 */ 1825 private BooleanToken _doIsEqualTo(Token rightArgument) 1826 throws IllegalActionException { 1827 MatrixToken convertedArgument = (MatrixToken) rightArgument; 1828 1829 if (convertedArgument.getRowCount() != getRowCount() 1830 || convertedArgument.getColumnCount() != getColumnCount()) { 1831 return BooleanToken.FALSE; 1832 } 1833 1834 return _isEqualTo(convertedArgument); 1835 } 1836 1837 /** Return a new token whose value is the value of this token 1838 * multiplied by the value of the argument token. It is 1839 * guaranteed by the caller that the type of the argument is the 1840 * same as the type of this class. This method defers to the 1841 * _multiply method that takes a MatrixToken. Derived classes 1842 * should override that method instead to provide type-specific 1843 * operation. 1844 * @param rightArgument The token to multiply this token by. 1845 * @exception IllegalActionException If the matrix dimensions are 1846 * not compatible, or this operation is not supported by the 1847 * derived class. 1848 * @return A new Token containing the result. 1849 */ 1850 private Token _doMultiply(Token rightArgument) 1851 throws IllegalActionException { 1852 MatrixToken convertedArgument = (MatrixToken) rightArgument; 1853 1854 if (convertedArgument.getRowCount() != getColumnCount()) { 1855 // Either this matrix or the argument might be a size one matrix 1856 // converted automatically from a scalar. Support this by 1857 // scalar multiplication. 1858 if (getRowCount() == 1 && getColumnCount() == 1) { 1859 // This matrix should be treated as a scalar. 1860 return convertedArgument 1861 ._multiplyElement(getElementAsToken(0, 0)); 1862 } else if (convertedArgument.getRowCount() == 1 1863 && convertedArgument.getColumnCount() == 1) { 1864 // The argument matrix should be treated as a scalar. 1865 return _multiplyElement( 1866 convertedArgument.getElementAsToken(0, 0)); 1867 } else { 1868 throw new IllegalActionException(Token 1869 .notSupportedMessage("multiply", this, rightArgument) 1870 + " because the matrices have incompatible dimensions."); 1871 } 1872 } 1873 MatrixToken result = _multiply(convertedArgument); 1874 return result; 1875 } 1876 1877 /** Return a new token whose value is the value of the argument 1878 * token subtracted from the value of this token. It is 1879 * guaranteed by the caller that the type of the argument is the 1880 * same as the type of this class and has the same units as this 1881 * token. This method defers to the _subtract method that takes 1882 * a MatrixToken. Derived classes should override that method 1883 * instead to provide type-specific operation. 1884 * @param rightArgument The token to subtract from this token. 1885 * @exception IllegalActionException If the matrix dimensions are 1886 * not compatible, or this operation is not supported by the 1887 * derived class. 1888 * @return A new Token containing the result. 1889 */ 1890 private Token _doSubtract(Token rightArgument) 1891 throws IllegalActionException { 1892 MatrixToken convertedArgument = (MatrixToken) rightArgument; 1893 1894 if (convertedArgument.getRowCount() != getRowCount() 1895 || convertedArgument.getColumnCount() != getColumnCount()) { 1896 // Either this matrix or the argument might be a size one matrix 1897 // converted automatically from a scalar. Support this by 1898 // scalar multiplication. 1899 if (getRowCount() == 1 && getColumnCount() == 1) { 1900 // This matrix should be treated as a scalar. 1901 // Need to reverse the subtraction. 1902 return convertedArgument 1903 ._subtractElementReverse(getElementAsToken(0, 0)); 1904 } else if (convertedArgument.getRowCount() == 1 1905 && convertedArgument.getColumnCount() == 1) { 1906 // The argument matrix should be treated as a scalar. 1907 return _subtractElement( 1908 convertedArgument.getElementAsToken(0, 0)); 1909 } else { 1910 throw new IllegalActionException(Token 1911 .notSupportedMessage("subtract", this, rightArgument) 1912 + " because the matrices have different dimensions."); 1913 } 1914 } 1915 1916 MatrixToken result = _subtract(convertedArgument); 1917 return result; 1918 } 1919}