001/* A utility class to infer the width of relations that don't specify the width 002 003Copyright (c) 2008-2015 The Regents of the University of California. 004All rights reserved. 005Permission is hereby granted, without written agreement and without 006license or royalty fees, to use, copy, modify, and distribute this 007software and its documentation for any purpose, provided that the above 008copyright notice and the following two paragraphs appear in all copies 009of this software. 010 011IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY 012FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 013ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF 014THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF 015SUCH DAMAGE. 016 017THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, 018INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 019MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE 020PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF 021CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, 022ENHANCEMENTS, OR MODIFICATIONS. 023 024PT_COPYRIGHT_VERSION_2 025COPYRIGHTENDKEY 026 027 */ 028 029package ptolemy.actor; 030 031import java.util.Date; 032import java.util.HashSet; 033import java.util.Iterator; 034import java.util.LinkedList; 035import java.util.List; 036import java.util.Set; 037 038import ptolemy.data.BooleanToken; 039import ptolemy.data.Token; 040import ptolemy.data.expr.ModelScope; 041import ptolemy.kernel.ComponentRelation; 042import ptolemy.kernel.util.IllegalActionException; 043import ptolemy.kernel.util.NamedObj; 044 045/////////////////////////////////////////////////////////////////// 046////RelationWidthInference 047 048/** 049A class that offers convenience utility methods to infer the widths of 050relations in a composite actor. 051 052 053@author Bert Rodiers 054@version $Id$ 055@since Ptolemy II 8.0 056@Pt.ProposedRating Red (rodiers) 057 */ 058 059public class RelationWidthInference { 060 061 /////////////////////////////////////////////////////////////////// 062 //// public methods //// 063 064 /** 065 * Create RelationWidthInference, the algorithm for width inference. 066 * Also set the top level to the value given as argument. 067 * @param topLevel The top level CompositeActor. 068 * @exception IllegalArgumentException If the specified actor is not the 069 * top level container. That is, its container is not null. 070 */ 071 public RelationWidthInference(CompositeActor topLevel) { 072 073 if (topLevel == null) { 074 throw new IllegalArgumentException( 075 "The toplevel should not be a null pointer."); 076 } 077 078 _topLevel = topLevel; 079 } 080 081 /** Determine whether widths are currently being inferred or not. 082 * @return True When widths are currently being inferred. 083 */ 084 public boolean inferringWidths() { 085 return _inferringWidths; 086 } 087 088 /** 089 * Infer the width of the relations for which no width has been 090 * specified yet. 091 * The specified actor must be the top level container of the model. 092 * @exception IllegalActionException If the widths of the relations at port are not consistent 093 * or if the width cannot be inferred for a relation. 094 */ 095 public void inferWidths() throws IllegalActionException { 096 if (_needsWidthInference) { 097 // Extra test for compositeActor != null since when the manager is changed 098 // the old manager gets a null pointer as compositeActor. 099 // Afterwards width inference should not be done anymore on this manager 100 // (this will throw a null pointer exception since _topLevel will be set to null). 101 if (_topLevel.getContainer() instanceof CompositeActor) { 102 throw new IllegalArgumentException( 103 "Width inference failed: The specified actor is " 104 + "not the top level container."); 105 } 106 final boolean logTimings = false; 107 boolean checkConsistencyAtMultiport = true; 108 109 { 110 Token checkConsistency = ModelScope.preferenceValue(_topLevel, 111 "_checkWidthConsistencyAtMultiports"); 112 if (checkConsistency instanceof BooleanToken) { 113 checkConsistencyAtMultiport = ((BooleanToken) checkConsistency) 114 .booleanValue(); 115 } 116 } 117 boolean checkWidthConstraints = true; 118 119 { 120 Token checkConstraints = ModelScope.preferenceValue(_topLevel, 121 "_checkWidthConstraints"); 122 if (checkConstraints instanceof BooleanToken) { 123 checkWidthConstraints = ((BooleanToken) checkConstraints) 124 .booleanValue(); 125 } 126 } 127 128 long startTime = 0L; 129 // FindBugs: avoid dead local store. 130 if (logTimings) { 131 startTime = new Date().getTime(); 132 } 133 134 try { 135 _topLevel.workspace().getWriteAccess(); 136 _inferringWidths = true; 137 138 Set<ComponentRelation> relationList = _topLevel 139 .deepRelationSet(); 140 Set<IORelation> workingRelationSet = new HashSet<IORelation>(); 141 Set<IOPort> workingPortSet = new HashSet<IOPort>(); 142 Set<IOPort> workingDefaultPortSet = new HashSet<IOPort>(); 143 HashSet<IORelation> unspecifiedSet = new HashSet<IORelation>(); 144 HashSet<IOPort> portsToCheckConsistency = new HashSet<IOPort>(); 145 HashSet<IOPort> portsThatCanBeIngnoredForConsistencyCheck = new HashSet<IOPort>(); 146 147 for (ComponentRelation componentRelation : relationList) { 148 if (componentRelation instanceof IORelation) { 149 IORelation relation = (IORelation) componentRelation; 150 if (!relation._skipWidthInference()) { 151 if (relation.needsWidthInference()) { 152 unspecifiedSet.add(relation); 153 } 154 if (!relation.isWidthFixed() 155 && relation.needsWidthInference()) { 156 // If connected to non-multiports => the relation should be 1 157 List<?> linkedObjects = relation 158 .linkedObjectsList(); 159 // If there is no port linked to the relation, we 160 // declare the width of the relation to be zero. 161 // FIXME: If there is only one port, the width should 162 // also be zero. But there seem to be many tests that 163 // depend on it being non-zero. 164 if (linkedObjects.isEmpty()) { 165 relation._setInferredWidth(0); 166 workingRelationSet.add(relation); 167 } else { 168 for (Object object : linkedObjects) { 169 if (object instanceof IOPort) { 170 IOPort port = (IOPort) object; 171 172 if (!port.isMultiport()) { 173 relation._setInferredWidth(1); 174 workingRelationSet 175 .add(relation); 176 break; //Break the for loop. 177 } else { 178 //Add known outside relations 179 for (Object connectedRelationObject : port 180 .linkedRelationList()) { 181 IORelation connectedRelation = (IORelation) connectedRelationObject; 182 if (connectedRelation != null 183 && connectedRelation 184 .isWidthFixed()) { 185 workingRelationSet.add( 186 connectedRelation); 187 } 188 } 189 //Add known inside relations 190 for (Object connectedRelationObject : port 191 .insideRelationList()) { 192 IORelation connectedRelation = (IORelation) connectedRelationObject; 193 if (connectedRelation != null 194 && connectedRelation 195 .isWidthFixed()) { 196 workingRelationSet.add( 197 connectedRelation); 198 } 199 } 200 if (port.hasWidthConstraints()) { 201 workingPortSet.add(port); 202 } 203 if (port.getDefaultWidth() >= 0) { 204 workingDefaultPortSet 205 .add(port); 206 } 207 } 208 } 209 } 210 } 211 } 212 } 213 } 214 } 215 216 LinkedList<IORelation> workingRelationList = new LinkedList<IORelation>( 217 workingRelationSet); 218 workingRelationSet = null; 219 220 if (logTimings) { 221 System.out.println("Width inference - initialization: " 222 + (System.currentTimeMillis() - startTime) 223 + " ms."); 224 } 225 226 long afterinit = 0L; 227 // FindBugs: avoid dead local store. 228 if (logTimings) { 229 afterinit = new Date().getTime(); 230 } 231 232 boolean continueInference = true; 233 234 while (continueInference && !unspecifiedSet.isEmpty() 235 && (!workingPortSet.isEmpty() 236 || !workingRelationList.isEmpty() 237 || !workingDefaultPortSet.isEmpty())) { 238 239 while (!workingRelationList.isEmpty() 240 && !unspecifiedSet.isEmpty()) { 241 242 //IORelation relation = workingSet2.pop(); 243 // pop has been added to LinkedList in Java 1.6 244 // (cfr. http://download.oracle.com/javase/6/docs/api/java/util/LinkedList.html#pop() ). 245 // Hence we use get an remove for the time being... 246 IORelation relation = workingRelationList.get(0); 247 workingRelationList.remove(0); 248 249 unspecifiedSet.remove(relation); 250 assert !relation.needsWidthInference(); 251 int width = relation.getWidth(); 252 assert width >= 0; 253 254 // All relations in the same relation group need to have the same width 255 for (Object otherRelationObject : relation 256 .relationGroupList()) { 257 IORelation otherRelation = (IORelation) otherRelationObject; 258 if (relation != otherRelation 259 && otherRelation.needsWidthInference()) { 260 otherRelation._setInferredWidth(width); 261 unspecifiedSet.remove(otherRelation); 262 // We don't need to add otherRelation to unspecifiedSet since 263 // we will process all ports linked to the complete relationGroup 264 // all at once. 265 } 266 } 267 268 // Now we see whether we can determine the widths of relations directly connected 269 // at the multiports linked to this relation. 270 271 // linkedPortList() can contain a port more than once. We only want 272 // them once. We will also only add multiports 273 HashSet<IOPort> multiports = new HashSet<IOPort>(); 274 for (Object port : relation.linkedPortList()) { 275 if (((IOPort) port).isMultiport()) { 276 multiports.add((IOPort) port); 277 } 278 } 279 for (IOPort port : multiports) { 280 List<IORelation> updatedRelations = new LinkedList<IORelation>(); 281 _updateRelationsFromMultiport(port, 282 updatedRelations); 283 if (checkConsistencyAtMultiport 284 && !updatedRelations.isEmpty()) { 285 // If we have updated relations for this port, it means that it is consistent 286 // and hence we don't need to check consistency anymore. 287 portsThatCanBeIngnoredForConsistencyCheck 288 .add(port); 289 for (IORelation updatedRelation : updatedRelations) { 290 portsToCheckConsistency 291 .addAll(updatedRelation 292 .linkedPortList(port)); 293 } 294 } 295 workingRelationList.addAll(updatedRelations); 296 } 297 } 298 299 // Use the width constraints on ports to infer the widths. 300 if (!workingPortSet.isEmpty() 301 && !unspecifiedSet.isEmpty()) { 302 continueInference = false; 303 LinkedList<IOPort> workingPortList = new LinkedList<IOPort>( 304 workingPortSet); 305 for (IOPort port : workingPortList) { 306 List<IORelation> updatedRelations = new LinkedList<IORelation>(); 307 boolean constraintStillUseful = _updateRelationsFromMultiport( 308 port, updatedRelations); 309 if (!updatedRelations.isEmpty()) { 310 workingPortSet.remove(port); 311 continueInference = true; 312 // We found new information, so we can try to infer 313 // new relations. 314 } else if (!constraintStillUseful) { 315 workingDefaultPortSet.remove(port); 316 } 317 if (checkConsistencyAtMultiport 318 && !updatedRelations.isEmpty()) { 319 // If we have updated relations for this port, it means that it is consistent 320 // and hence we don't need to check consistency anymore. 321 portsThatCanBeIngnoredForConsistencyCheck 322 .add(port); 323 for (IORelation updatedRelation : updatedRelations) { 324 portsToCheckConsistency 325 .addAll(updatedRelation 326 .linkedPortList(port)); 327 } 328 } 329 workingRelationList.addAll(updatedRelations); 330 } 331 } 332 333 // If we can't infer any widths anymore (workingRelationList.isEmpty()) 334 // we will look whether there are ports that have a default width. 335 if (!workingDefaultPortSet.isEmpty() 336 && workingRelationList.isEmpty()) { 337 LinkedList<IOPort> workingDefaultPortList = new LinkedList<IOPort>( 338 workingDefaultPortSet); 339 for (IOPort port : workingDefaultPortList) { 340 List<IORelation> updatedRelations = new LinkedList<IORelation>(); 341 boolean constraintStillUseful = _updateRelationsFromDefaultWidth( 342 port, updatedRelations); 343 if (!updatedRelations.isEmpty()) { 344 workingDefaultPortSet.remove(port); 345 continueInference = true; 346 // We found new information, so we can try to infer 347 // new relations. 348 } else if (!constraintStillUseful) { 349 workingDefaultPortSet.remove(port); 350 } 351 workingRelationList.addAll(updatedRelations); 352 } 353 } 354 } 355 356 if (logTimings) { 357 System.out.println("Actual algorithm: " 358 + (System.currentTimeMillis() - afterinit) 359 + " ms."); 360 } 361 362 //Consistency check 363 if (checkConsistencyAtMultiport) { 364 365 portsToCheckConsistency.removeAll( 366 portsThatCanBeIngnoredForConsistencyCheck); 367 for (IOPort port : portsToCheckConsistency) { 368 _checkConsistency(port); 369 } 370 } 371 if (checkWidthConstraints) { 372 for (IOPort port : workingPortSet) { 373 _checkConsistency(port); 374 port.checkWidthConstraints(); 375 } 376 } 377 378 while (!unspecifiedSet.isEmpty()) { 379 380 boolean defaultInferredWidthTo1 = false; 381 382 Token defaultTo1 = ModelScope.preferenceValue(_topLevel, 383 "_defaultInferredWidthTo1"); 384 if (defaultTo1 instanceof BooleanToken) { 385 defaultInferredWidthTo1 = ((BooleanToken) defaultTo1) 386 .booleanValue(); 387 } 388 389 if (defaultInferredWidthTo1) { 390 for (IORelation relation : unspecifiedSet) { 391 relation._setInferredWidth(1); 392 } 393 unspecifiedSet.clear(); 394 } else { 395 StringBuffer portDetails = new StringBuffer(); 396 IORelation relation = unspecifiedSet.iterator().next(); 397 List<IOPort> linkedPorts = relation 398 .deepLinkedPortList(); 399 400 // Look for a special case where a relation is linking a multiport 401 // inside a composite to the inside of one or more multiports that are 402 // not connected to anything on the outside. In this case, the width 403 // will be zero. The pattern we look for that no more than one port 404 // is linked on the outside. 405 boolean foundOutside = false; 406 boolean giveUp = false; 407 for (IOPort port : linkedPorts) { 408 if (port.isInsideGroupLinked(relation)) { 409 continue; 410 } else { 411 if (foundOutside) { 412 // relation links more than one port on the outside, 413 // so there is nothing more we can do. 414 giveUp = true; 415 break; 416 } 417 foundOutside = true; 418 } 419 } 420 if (giveUp) { 421 Iterator deepPorts = linkedPorts.iterator(); 422 while (deepPorts.hasNext()) { 423 if (portDetails.length() > 0) { 424 portDetails.append("\n"); 425 } 426 portDetails.append(((IOPort) deepPorts.next()) 427 .getFullName()); 428 } 429 430 String message1 = "The width of relation " 431 + relation.getFullName() 432 + " can not be uniquely inferred.\n"; 433 String message2 = "One possible solution is to create a toplevel parameter " 434 + "named \"_defaultInferredWidthTo1\" with the boolean " 435 + "value true.\n" 436 + "Please make the width inference deterministic by" 437 + " explicitly specifying the width of this relation." 438 + " In the user interface, right click on the " 439 + "relation, select Configure and change the width. " 440 + " Note that some actors may need to have their " 441 + " Java code updated to call setDefaultWidth(1) " 442 + "on the output port. " 443 + "The relation is deeply connected to these ports:\n" 444 + portDetails.toString(); 445 Manager manager = ((CompositeActor) relation 446 .toplevel()).getManager(); 447 if (manager != null 448 && manager.getState() != Manager.IDLE) { 449 throw new IllegalActionException( 450 relation, message1 451 + "The model is not idle, so stopping the model " 452 + "might help.\n" + message2); 453 } 454 throw new IllegalActionException(relation, 455 message1 + message2); 456 } else { 457 relation._setInferredWidth(0); 458 unspecifiedSet.remove(relation); 459 } 460 } 461 } 462 } finally { 463 _inferringWidths = false; 464 _topLevel.workspace().doneTemporaryWriting(); 465 if (logTimings) { 466 System.out.println("Time to do width inference: " 467 + (System.currentTimeMillis() - startTime) 468 + " ms."); 469 } 470 } 471 _needsWidthInference = false; 472 } 473 } 474 475 /** 476 * Return whether the current widths of the relation in the model 477 * are no longer valid anymore and the widths need to be inferred again. 478 * @return True when width inference needs to be executed again. 479 */ 480 public boolean needsWidthInference() { 481 return _needsWidthInference; 482 } 483 484 /** 485 * Notify the width inference algorithm that the connectivity in the model changed 486 * (width of relation changed, relations added, linked to different ports, ...). 487 * This will invalidate the current width inference. 488 */ 489 public void notifyConnectivityChange() { 490 if (!_inferringWidths) { 491 _needsWidthInference = true; 492 } 493 // If we are currently inferring widths we ignore connectivity changes, 494 // since evaluating expressions can cause a call of attributesChanged, 495 // which results in notifyConnectivityChange. In this case we aren't 496 // changing the model, but just getting all parameters. 497 // Notice that we use the boolean _inferringWidths without any locking 498 // This is to avoid deadlocks... In case we are inferring widths notifyConnectivityChange 499 // should only be called from the same thread as the one that is inferring 500 // widths and hence there is no issue. When the user is actually changing he model 501 // we shouldn't be doing width inference and hence the parameter should not be 502 // changing. 503 } 504 505 /////////////////////////////////////////////////////////////////// 506 //// protected methods //// 507 508 /** Filter the relations for which the width still has to be inferred. 509 * @param relationList The relations that need to be filtered. 510 * @return The relations for which the width still has to return. 511 * @exception IllegalActionException If the expression for the width cannot 512 * be parsed or cannot be evaluated, or if the result of evaluation 513 * violates type constraints, or if the result of evaluation is null 514 * and there are variables that depend on this one. 515 */ 516 static protected Set<IORelation> _relationsWithUnspecifiedWidths( 517 List<?> relationList) throws IllegalActionException { 518 Set<IORelation> result = new HashSet<IORelation>(); 519 for (Object relation : relationList) { 520 if (relation != null 521 && ((IORelation) relation).needsWidthInference()) { 522 result.add((IORelation) relation); 523 } 524 } 525 return result; 526 } 527 528 /////////////////////////////////////////////////////////////////// 529 //// private methods //// 530 531 /** 532 * Check whether the widths at a port are consistent. Consistent means that 533 * the input and output width is either zero or that the input width is equal 534 * to the output width. 535 * @param port The port which will be checked. 536 * @exception IllegalActionException If the widths of the relations at port 537 * are not consistent. 538 */ 539 static private void _checkConsistency(IOPort port) 540 throws IllegalActionException { 541 // We check whether the inside and outside widths are consistent. In case 542 // widths are inferred they should be inferred uniquely. We don't want to have 543 // different results depending on where we start in the graph. 544 int insideWidth = port._getInsideWidth(null); 545 int outsideWidth = port._getOutsideWidth(null); 546 547 // Special case. 548 if (port instanceof SubscriptionAggregatorPort) { 549 if (insideWidth != 1) { 550 throw new IllegalActionException(port, 551 "The inside width is required to be 1. Got " 552 + insideWidth); 553 } 554 return; 555 } 556 557 if (insideWidth != 0 && outsideWidth != 0 558 && insideWidth != outsideWidth) { 559 throw new IllegalActionException(port, "The inside width (" 560 + insideWidth + ") and the outside width (" + outsideWidth 561 + ") of port " + port.getFullName() 562 + " are not either equal to 0 or not equal to each other and are therefore" 563 + " inconsistent.\nCan't determine a uniquely defined width for" 564 + " the connected relations. A possible fix is to right clicking on either the" 565 + " inside or outside relation and set the width -1."); 566 } 567 } 568 569 /** 570 * Infer the width for the relations connected to the port. If the width can be 571 * inferred, update the width and add the relations for which the width has been 572 * updated. 573 * @param port The port for whose connected relations the width should be inferred. 574 * @param updatedRelations The relations for which the width has been updated. 575 * @return true When this constraint is still useful (can be used to extra more information). 576 * @exception IllegalActionException If the widths of the relations at port are not consistent. 577 */ 578 static private boolean _updateRelationsFromMultiport(IOPort port, 579 List<IORelation> updatedRelations) throws IllegalActionException { 580 boolean constraintStillUseful = true; 581 Set<IORelation> outsideUnspecifiedWidths = _relationsWithUnspecifiedWidths( 582 port.linkedRelationList()); 583 //port.linkedRelationList() returns the outside relations 584 585 int outsideUnspecifiedWidthsSize = outsideUnspecifiedWidths.size(); 586 587 NamedObj namedObject = port.getContainer(); 588 if (namedObject == null) { 589 assert false; // not expected 590 return false; 591 } 592 int difference = -1; 593 Set<IORelation> unspecifiedWidths = null; 594 if (namedObject instanceof AtomicActor) { 595 596 assert outsideUnspecifiedWidthsSize >= 0; 597 if (outsideUnspecifiedWidthsSize > 0 598 && port.hasWidthConstraints()) { 599 difference = port.getWidthFromConstraints(); 600 unspecifiedWidths = outsideUnspecifiedWidths; 601 if (difference < 0) { 602 return true; // Constraints still unknown 603 } 604 } else { 605 return false; 606 } 607 } else { 608 609 Set<IORelation> insideUnspecifiedWidths = _relationsWithUnspecifiedWidths( 610 port.insideRelationList()); 611 int insideUnspecifiedWidthsSize = insideUnspecifiedWidths.size(); 612 613 if (insideUnspecifiedWidthsSize > 0 614 && outsideUnspecifiedWidthsSize > 0) { 615 return true; 616 } 617 if (insideUnspecifiedWidthsSize == 0 618 && outsideUnspecifiedWidthsSize == 0) { 619 return false; 620 } 621 622 int insideWidth = port._getInsideWidth(null); 623 int outsideWidth = port._getOutsideWidth(null); 624 625 if (insideUnspecifiedWidthsSize > 0) { 626 unspecifiedWidths = insideUnspecifiedWidths; 627 difference = outsideWidth - insideWidth; 628 } else { 629 assert outsideUnspecifiedWidthsSize > 0; 630 unspecifiedWidths = outsideUnspecifiedWidths; 631 difference = insideWidth - outsideWidth; 632 } 633 634 // We expect that the following case does not exist anymore since atomic 635 // actors are handled separately. Hence the assert... 636 // For opaque ports we not always want the same behavior. 637 // For example at an add-subtract actor we only have information 638 // about the outside, and hence we can't infer any widths at this port. 639 // In this case difference < 0. 640 // However in the case of a multimodel, you often have relations on the 641 // inside and width inference needs to happen. In this case difference >=0 642 if (port.isOpaque() && difference < 0) { 643 assert false; // We don't expect to come in this case 644 assert insideWidth == 0; 645 return false; // No width inference possible and necessary at this port. 646 } 647 if (difference < 0) { 648 throw new IllegalActionException(port, 649 "The inside and outside widths of port " 650 + port.getFullName() 651 + " are not consistent.\nThe inferred width of relation " 652 + unspecifiedWidths.iterator().next() 653 .getFullName() 654 + " would be negative."); 655 } 656 } 657 658 assert unspecifiedWidths != null; 659 int unspecifiedWidthsSize = unspecifiedWidths.size(); 660 661 // Put the next test in comments since the condition 662 // difference >= unspecifiedWidthsSize only needs to be fulfilled 663 // in case we don't allow inferred widths to be zero. 664 // 665 // if (difference > 0 && difference < unspecifiedWidthsSize) { 666 // throw new IllegalActionException(port, 667 // "The inside and outside widths of port " + port.getFullName() 668 // + " are not consistent.\n Can't determine a uniquely defined width for relation" 669 // + unspecifiedWidths.iterator().next().getFullName()); 670 // } 671 672 if (unspecifiedWidthsSize == 1 || unspecifiedWidthsSize == difference 673 || difference == 0) { 674 int width = difference / unspecifiedWidthsSize; 675 assert width >= 0; 676 for (IORelation relation : unspecifiedWidths) { 677 relation._setInferredWidth(width); 678 updatedRelations.add(relation); 679 } 680 constraintStillUseful = false; 681 } 682 return constraintStillUseful; 683 } 684 685 /** Infer the width for the relations connected to the port (which should have a default width). 686 * If the width can be inferred, update the width and add the relations for which the width 687 * has been updated. 688 * @param port The port for whose connected relations the width should be inferred. 689 * @param updatedRelations The relations for which the width has been updated. 690 * @return true When this constraint is still useful (can be used to extra more information). 691 * @exception IllegalActionException If the expression for the width cannot 692 * be parsed or cannot be evaluated, or if the result of evaluation 693 * violates type constraints, or if the result of evaluation is null 694 * and there are variables that depend on this one. 695 */ 696 static private boolean _updateRelationsFromDefaultWidth(IOPort port, 697 List<IORelation> updatedRelations) throws IllegalActionException { 698 boolean constraintStillUseful = true; 699 700 Set<IORelation> outsideUnspecifiedWidths = _relationsWithUnspecifiedWidths( 701 port.linkedRelationList()); 702 //port.linkedRelationList() returns the outside relations 703 704 int outsideUnspecifiedWidthsSize = outsideUnspecifiedWidths.size(); 705 706 NamedObj namedObject = port.getContainer(); 707 if (namedObject == null) { 708 assert false; // not expected 709 return false; 710 } 711 assert outsideUnspecifiedWidthsSize >= 0; 712 if (outsideUnspecifiedWidthsSize > 0) { 713 int defaultWidth = port.getDefaultWidth(); 714 assert defaultWidth >= 0; 715 int unspecifiedWidthsSize = outsideUnspecifiedWidths.size(); 716 if (unspecifiedWidthsSize == 1 717 || unspecifiedWidthsSize % defaultWidth == 0 718 || defaultWidth == 0) { 719 int width = 0; 720 // Coverity: Avoid a divide by zero error. 721 if (defaultWidth != 0) { 722 width = unspecifiedWidthsSize / defaultWidth; 723 } 724 assert width >= 0; 725 for (IORelation relation : outsideUnspecifiedWidths) { 726 relation._setInferredWidth(width); 727 updatedRelations.add(relation); 728 } 729 constraintStillUseful = false; 730 } 731 } else { 732 constraintStillUseful = false; 733 } 734 return constraintStillUseful; 735 } 736 737 /////////////////////////////////////////////////////////////////// 738 //// private variables //// 739 740 //True when we are inferring widths 741 private boolean _inferringWidths = false; 742 743 //True when width inference needs to happen again 744 private boolean _needsWidthInference = true; 745 746 //The top level of the model. 747 private CompositeActor _topLevel = null; 748}