001/* A token that contains a 2-D boolean matrix. 002 003 Copyright (c) 1998-2014 The Regents of the University of California. 004 All rights reserved. 005 Permission is hereby granted, without written agreement and without 006 license or royalty fees, to use, copy, modify, and distribute this 007 software and its documentation for any purpose, provided that the above 008 copyright notice and the following two paragraphs appear in all copies 009 of this software. 010 011 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY 012 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 013 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF 014 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF 015 SUCH DAMAGE. 016 017 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, 018 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 019 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE 020 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF 021 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, 022 ENHANCEMENTS, OR MODIFICATIONS. 023 024 PT_COPYRIGHT_VERSION_2 025 COPYRIGHTENDKEY 026 027 There are currently no interesting operations implemented. 028 */ 029package ptolemy.data; 030 031import ptolemy.data.expr.ASTPtRootNode; 032import ptolemy.data.expr.ParseTreeEvaluator; 033import ptolemy.data.expr.PtParser; 034import ptolemy.data.type.BaseType; 035import ptolemy.data.type.Type; 036import ptolemy.data.type.TypeLattice; 037import ptolemy.graph.CPO; 038import ptolemy.kernel.util.IllegalActionException; 039import ptolemy.kernel.util.InternalErrorException; 040 041/////////////////////////////////////////////////////////////////// 042//// BooleanMatrixToken 043 044/** 045 A token that contains a 2-D boolean matrix. 046 047 @author Yuhong Xiong, Steve Neuendorffer 048 @version $Id$ 049 @since Ptolemy II 0.2 050 @Pt.ProposedRating Green (neuendor) 051 @Pt.AcceptedRating Yellow (cxh) 052 */ 053public class BooleanMatrixToken extends MatrixToken { 054 /** Construct an BooleanMatrixToken with a one by one matrix. The 055 * only element in the matrix has value false. 056 */ 057 public BooleanMatrixToken() { 058 _rowCount = 1; 059 _columnCount = 1; 060 _value = new boolean[1][1]; 061 _value[0][0] = false; 062 } 063 064 /** Construct a BooleanMatrixToken with the specified 2-D matrix. 065 * This method makes a copy of the matrix and stores the copy, 066 * so changes on the specified matrix after this token is 067 * constructed will not affect the content of this token. 068 * @param value The 2-D boolean matrix. 069 * @exception IllegalActionException If the specified matrix 070 * is null. 071 */ 072 public BooleanMatrixToken(boolean[][] value) throws IllegalActionException { 073 if (value == null) { 074 throw new IllegalActionException( 075 "BooleanMatrixToken: The " + "specified matrix is null."); 076 } 077 078 _initialize(value); 079 } 080 081 /** Construct a BooleanMatrixToken from the specified string. 082 * @param init A string expression of a boolean matrix. 083 * @exception IllegalActionException If the string does 084 * not contain a parsable boolean matrix. 085 */ 086 public BooleanMatrixToken(String init) throws IllegalActionException { 087 PtParser parser = new PtParser(); 088 ASTPtRootNode tree = parser.generateParseTree(init); 089 Token token = new ParseTreeEvaluator().evaluateParseTree(tree); 090 091 if (token instanceof BooleanMatrixToken) { 092 boolean[][] value = ((BooleanMatrixToken) token).booleanMatrix(); 093 _initialize(value); 094 } else { 095 throw new IllegalActionException("A BooleanMatrixToken cannot be" 096 + " created from the expression '" + init + "'"); 097 } 098 } 099 100 /** Construct an BooleanMatrixToken from the specified array of 101 * tokens. The tokens in the array must be scalar tokens 102 * convertible into integers. 103 * @param tokens The array of tokens, which must contains 104 * rows*columns BooleanTokens. 105 * @param rows The number of rows in the matrix to be created. 106 * @param columns The number of columns in the matrix to be 107 * created. 108 * @exception IllegalActionException If the array of tokens is 109 * null, or the length of the array is not correct, or if one of 110 * the elements of the array is null, or if one of the elements 111 * of the array cannot be losslessly converted to a boolean. 112 */ 113 public BooleanMatrixToken(Token[] tokens, int rows, int columns) 114 throws IllegalActionException { 115 if (tokens == null) { 116 throw new IllegalActionException( 117 "BooleanMatrixToken: The specified" + " array is null."); 118 } 119 120 if (tokens.length != rows * columns) { 121 throw new IllegalActionException("BooleanMatrixToken: The specified" 122 + " array is not of the correct length"); 123 } 124 125 _rowCount = rows; 126 _columnCount = columns; 127 _value = new boolean[rows][columns]; 128 129 for (int i = 0; i < tokens.length; i++) { 130 Token token = tokens[i]; 131 132 if (token instanceof BooleanToken) { 133 _value[i / columns][i % columns] = ((BooleanToken) token) 134 .booleanValue(); 135 } else { 136 throw new IllegalActionException("BooleanMatrixToken: Element " 137 + i + " in the array with value " + token 138 + " is not a ScalarToken"); 139 } 140 } 141 } 142 143 /////////////////////////////////////////////////////////////////// 144 //// public methods //// 145 146 /** Return a copy of the contained 2-D matrix. 147 * It is safe for the caller to modify the returned matrix. 148 * @return A 2-D boolean matrix. 149 */ 150 @Override 151 public boolean[][] booleanMatrix() { 152 boolean[][] result = new boolean[_rowCount][_columnCount]; 153 154 for (int i = 0; i < _rowCount; i++) { 155 for (int j = 0; j < _columnCount; j++) { 156 result[i][j] = _value[i][j]; 157 } 158 } 159 160 return result; 161 } 162 163 /** Convert the specified token into an instance of BooleanMatrixToken. 164 * This method does lossless conversion. 165 * If the argument is already an instance of BooleanMatrixToken, 166 * it is returned without any change. Otherwise, if the argument 167 * is below BooleanMatrixToken in the type hierarchy, it is converted to 168 * an instance of BooleanMatrixToken or one of the subclasses of 169 * BooleanMatrixToken and returned. If none of the above conditions are 170 * met, an exception is thrown. 171 * @param token The token to be converted to a BooleanMatrixToken. 172 * @return A BooleanMatrixToken 173 * @exception IllegalActionException If the conversion cannot 174 * be carried out. 175 */ 176 public static BooleanMatrixToken convert(Token token) 177 throws IllegalActionException { 178 if (token instanceof BooleanMatrixToken) { 179 return (BooleanMatrixToken) token; 180 } 181 182 int compare = TypeLattice.compare(BaseType.BOOLEAN_MATRIX, token); 183 184 if (compare == CPO.LOWER || compare == CPO.INCOMPARABLE) { 185 throw new IllegalActionException( 186 notSupportedIncomparableConversionMessage(token, 187 "[boolean]")); 188 } 189 190 // try boolean 191 // compare = TypeLattice.compare(BaseType.BOOLEAN, token); 192 // if (compare == CPO.SAME || compare == CPO.HIGHER) { 193 // BooleanToken tem = (BooleanToken) 194 // BooleanToken.convert(token); 195 // boolean[][] result = new boolean[1][1]; 196 // result[0][0] = tem.booleanValue(); 197 // return new BooleanMatrixToken(result); 198 // } 199 // The argument is below BooleanMatrixToken in the type hierarchy, 200 // but I don't recognize it. 201 throw new IllegalActionException( 202 notSupportedConversionMessage(token, "[boolean]")); 203 } 204 205 /** Return a new matrix that is a sub-matrix of this matrix. 206 * @param rowStart The row to start on. 207 * @param colStart The column to start on. 208 * @param rowSpan The number of rows to copy. 209 * @param colSpan The number of columns to copy. 210 * @return a sub-matrix of this matrix. 211 * @exception IllegalActionException If the returned matrix is empty or if the specified 212 * parameters result in out of bounds accesses. 213 */ 214 @Override 215 public MatrixToken crop(int rowStart, int colStart, int rowSpan, 216 int colSpan) throws IllegalActionException { 217 boolean[][] value = this.booleanMatrix(); 218 try { 219 boolean[][] result = new boolean[rowSpan][colSpan]; 220 for (int i = 0; i < rowSpan; i++) { 221 System.arraycopy(value[rowStart + i], colStart, result[i], 0, 222 colSpan); 223 } 224 return new BooleanMatrixToken(result); 225 } catch (ArrayIndexOutOfBoundsException ex) { 226 throw new IllegalActionException( 227 "Matrix crop indices out of bounds (rowStart = " + rowStart 228 + ", colStart = " + colStart + ", rowSpan = " 229 + rowSpan + ", colSpan = " + colSpan + ")."); 230 } 231 } 232 233 /** Return true if the argument is an instance of BooleanMatrixToken 234 * of the same dimensions and the corresponding elements of the matrices 235 * are equal. 236 * @param object An instance of Object. 237 * @return True if the argument is an instance of BooleanMatrixToken 238 * of the same dimensions and the corresponding elements of the 239 * matrices are equal. 240 */ 241 @Override 242 public boolean equals(Object object) { 243 if (object == null) { 244 return false; 245 } 246 // This test rules out instances of a subclass. 247 if (object.getClass() != getClass()) { 248 return false; 249 } 250 251 BooleanMatrixToken matrixArgument = (BooleanMatrixToken) object; 252 253 if (_rowCount != matrixArgument.getRowCount()) { 254 return false; 255 } 256 257 if (_columnCount != matrixArgument.getColumnCount()) { 258 return false; 259 } 260 261 boolean[][] matrix = matrixArgument.booleanMatrix(); 262 263 for (int i = 0; i < _rowCount; i++) { 264 for (int j = 0; j < _columnCount; j++) { 265 if (_value[i][j] != matrix[i][j]) { 266 return false; 267 } 268 } 269 } 270 271 return true; 272 } 273 274 /** Return the number of columns in the matrix. 275 * @return The number of columns in the matrix. 276 */ 277 @Override 278 public int getColumnCount() { 279 return _columnCount; 280 } 281 282 /** Return the element of the matrix at the specified 283 * row and column in a BooleanToken. 284 * @param row The row index of the desired element. 285 * @param column The column index of the desired element. 286 * @return A BooleanToken containing the matrix element. 287 * @exception ArrayIndexOutOfBoundsException If the specified 288 * row or column number is outside the range of the matrix. 289 */ 290 @Override 291 public Token getElementAsToken(int row, int column) 292 throws ArrayIndexOutOfBoundsException { 293 return BooleanToken.getInstance(_value[row][column]); 294 } 295 296 /** Return the element of the contained matrix at the specified 297 * row and column. 298 * @param row The row index of the desired element. 299 * @param column The column index of the desired element. 300 * @return The boolean at the specified matrix entry. 301 * @exception ArrayIndexOutOfBoundsException If the specified 302 * row or column number is outside the range of the matrix. 303 */ 304 public boolean getElementAt(int row, int column) { 305 return _value[row][column]; 306 } 307 308 /** Return the Type of the tokens contained in this matrix token. 309 * @return BaseType.INT. 310 */ 311 @Override 312 public Type getElementType() { 313 return BaseType.INT; 314 } 315 316 /** Return the number of rows in the matrix. 317 * @return The number of rows in the matrix. 318 */ 319 @Override 320 public int getRowCount() { 321 return _rowCount; 322 } 323 324 /** Return the type of this token. 325 * @return BaseType.BOOLEAN_MATRIX 326 */ 327 @Override 328 public Type getType() { 329 return BaseType.BOOLEAN_MATRIX; 330 } 331 332 /** Return a hash code value for this token. This method returns the 333 * number of elements with value true in the contained matrix. 334 * @return A hash code value for this token. 335 */ 336 @Override 337 public int hashCode() { 338 int code = 0; 339 340 for (int i = 0; i < _rowCount; i++) { 341 for (int j = 0; j < _columnCount; j++) { 342 if (_value[i][j]) { 343 code++; 344 } 345 } 346 } 347 348 return code; 349 } 350 351 /** Join a matrix of matrices into a single matrix by tiling. 352 * All matrices in the matrix must be of the same type, 353 * the same type as this matrix. But none of them needs to 354 * actually be this matrix. This base class simply throws 355 * an exception. Derived classes provide the implementation. 356 * The number of columns in the resulting matrix is the sum 357 * of the number of columns in the first row of the argument. 358 * The number of rows in the resulting matrix is the sum 359 * of the number of rows in the first column of the argument. 360 * The matrices are copied into the result starting at the 361 * position determined by the first row or column. 362 * If the matrices overlap, then while copying left to right, 363 * top-to-bottom, data will be overwritten. If there are gaps, 364 * the resulting matrix will be filled with zeros. 365 * @param matrices A two-dimensional array of matrix tokens. 366 * @return A new matrix token of the same type as the elements 367 * in the input matrix of matrix tokens. 368 * @exception IllegalActionException If the types of the matrices 369 * in the input are not all the same, or if tiling fails due 370 * to size incompatibilities, or if the input matrix has no 371 * tokens. 372 */ 373 @Override 374 public MatrixToken join(MatrixToken[][] matrices) 375 throws IllegalActionException { 376 if (matrices == null || matrices.length == 0 377 || matrices[0].length == 0) { 378 throw new IllegalActionException("matrixJoin: No input matrices."); 379 } 380 // Calculate the size of the result. 381 // This assumes the matrices tile. 382 int rows = 0; 383 int columns = 0; 384 for (MatrixToken[] matrice : matrices) { 385 rows += matrice[0].getRowCount(); 386 } 387 for (int j = 0; j < matrices[0].length; j++) { 388 columns += matrices[0][j].getColumnCount(); 389 } 390 boolean[][] tiled = new boolean[rows][columns]; 391 int row = 0; 392 for (int i = 0; i < matrices.length; i++) { 393 int column = 0; 394 for (int j = 0; j < matrices[i].length; j++) { 395 if (!(matrices[i][j] instanceof BooleanMatrixToken)) { 396 throw new IllegalActionException( 397 "matrixJoin: matrices not all of the same type."); 398 } 399 int rowCount = matrices[i][j].getRowCount(); 400 if (row + rowCount > rows) { 401 rowCount = rows - row; 402 } 403 int columnCount = matrices[i][j].getColumnCount(); 404 if (column + columnCount > columns) { 405 columnCount = columns - column; 406 } 407 // There is no BooleanMatrixMath class, so we need 408 // to implement the matrix copy here. 409 for (int ii = 0; ii < rowCount; ii++) { 410 System.arraycopy(matrices[i][j].booleanMatrix()[ii], 0, 411 tiled[row + ii], column, columnCount); 412 } 413 // Starting position for the next column. 414 column += matrices[0][j].getColumnCount(); 415 } 416 // Starting position for the next column. 417 row += matrices[i][0].getRowCount(); 418 } 419 return new BooleanMatrixToken(tiled); 420 } 421 422 /** Split this matrix into multiple matrices. See the base 423 * class for documentation. 424 * @param rows The number of rows per submatrix. 425 * @param columns The number of columns per submatrix. 426 * @return An array of matrix tokens. 427 */ 428 @Override 429 public MatrixToken[][] split(int[] rows, int[] columns) { 430 MatrixToken[][] result = new MatrixToken[rows.length][columns.length]; 431 boolean[][] source = booleanMatrix(); 432 int row = 0; 433 for (int i = 0; i < rows.length; i++) { 434 int column = 0; 435 for (int j = 0; j < columns.length; j++) { 436 boolean[][] contents = new boolean[rows[i]][columns[j]]; 437 int rowspan = rows[i]; 438 if (row + rowspan > source.length) { 439 rowspan = source.length - row; 440 } 441 int columnspan = columns[j]; 442 if (column + columnspan > source[0].length) { 443 columnspan = source[0].length - column; 444 } 445 if (columnspan > 0 && rowspan > 0) { 446 // There is no BooleanMatrixMath class, so we need 447 // to implement the matrix copy here. 448 for (int ii = 0; ii < rowspan; ii++) { 449 System.arraycopy(source[row + ii], column, contents[ii], 450 0, columnspan); 451 } 452 } 453 column += columns[j]; 454 try { 455 result[i][j] = new BooleanMatrixToken(contents); 456 } catch (IllegalActionException e) { 457 throw new InternalErrorException(e); 458 } 459 } 460 row += rows[i]; 461 } 462 return result; 463 } 464 465 /** Return a new Token representing the left multiplicative 466 * identity. The returned token contains an identity matrix 467 * whose dimensions are the same as the number of rows of 468 * the matrix contained in this token. 469 * @return A new BooleanMatrixToken containing the left multiplicative 470 * identity. 471 */ 472 @Override 473 public Token one() { 474 try { 475 return new BooleanMatrixToken(_createIdentity(_rowCount)); 476 } catch (IllegalActionException illegalAction) { 477 // should not happen 478 throw new InternalErrorException("BooleanMatrixToken.one: " 479 + "Cannot create identity matrix."); 480 } 481 } 482 483 /** Return a new Token representing the right multiplicative 484 * identity. The returned token contains an identity matrix 485 * whose dimensions are the same as the number of columns of 486 * the matrix contained in this token. 487 * @return A new BooleanMatrixToken containing the right multiplicative 488 * identity. 489 */ 490 @Override 491 public Token oneRight() { 492 try { 493 return new BooleanMatrixToken(_createIdentity(_columnCount)); 494 } catch (IllegalActionException illegalAction) { 495 // should not happen 496 throw new InternalErrorException("BooleanMatrixToken.oneRight: " 497 + "Cannot create identity matrix."); 498 } 499 } 500 501 /** Return a new Token representing the additive identity. 502 * The returned token contains a matrix whose elements are 503 * all zero, and the size of the matrix is the same as the 504 * matrix contained in this token. 505 * @return A new IntMatrixToken containing the additive identity. 506 */ 507 @Override 508 public Token zero() { 509 try { 510 return new BooleanMatrixToken(new boolean[_rowCount][_columnCount]); 511 } catch (IllegalActionException illegalAction) { 512 // should not happen 513 throw new InternalErrorException( 514 "BooleanMatrixToken.zero: " + "Cannot create zero matrix."); 515 } 516 } 517 518 /////////////////////////////////////////////////////////////////// 519 //// protected methods //// 520 521 /** Return an new identity matrix with the specified dimension. The 522 * matrix is square, so only one dimension specifier is needed. 523 * @param dim The dimension 524 * @return the identity matrix. 525 */ 526 protected boolean[][] _createIdentity(int dim) { 527 boolean[][] a = new boolean[dim][dim]; 528 529 // we rely on the fact Java fills the allocated matrix with false. 530 for (int i = 0; i < dim; i++) { 531 a[i][i] = true; 532 } 533 534 return a; 535 } 536 537 /////////////////////////////////////////////////////////////////// 538 //// private methods //// 539 // Initialize the row and column count and copy the specified 540 // matrix. This method is used by the constructors. 541 private void _initialize(boolean[][] value) { 542 _rowCount = value.length; 543 _columnCount = value[0].length; 544 _value = new boolean[_rowCount][_columnCount]; 545 546 for (int i = 0; i < _rowCount; i++) { 547 for (int j = 0; j < _columnCount; j++) { 548 _value[i][j] = value[i][j]; 549 } 550 } 551 } 552 553 /////////////////////////////////////////////////////////////////// 554 //// private variables //// 555 private boolean[][] _value = null; 556 557 private int _rowCount = 0; 558 559 private int _columnCount = 0; 560}