001/* Base class for directors that have fixed point semantics at each iteration. 002 003 Copyright (c) 2006-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 PT_COPYRIGHT_VERSION_2 024 COPYRIGHTENDKEY 025 026 */ 027package ptolemy.actor.sched; 028 029import java.util.HashSet; 030import java.util.Iterator; 031import java.util.LinkedList; 032import java.util.List; 033import java.util.Set; 034 035import ptolemy.actor.Actor; 036import ptolemy.actor.CompositeActor; 037import ptolemy.actor.IOPort; 038import ptolemy.actor.Receiver; 039import ptolemy.actor.SuperdenseTimeDirector; 040import ptolemy.actor.parameters.ParameterPort; 041import ptolemy.actor.util.Time; 042import ptolemy.data.BooleanToken; 043import ptolemy.data.IntToken; 044import ptolemy.data.expr.Parameter; 045import ptolemy.data.type.BaseType; 046import ptolemy.kernel.CompositeEntity; 047import ptolemy.kernel.util.IllegalActionException; 048import ptolemy.kernel.util.NameDuplicationException; 049import ptolemy.kernel.util.Nameable; 050import ptolemy.kernel.util.Workspace; 051 052/////////////////////////////////////////////////////////////////// 053//// FixedPointDirector 054 055/** 056 A base class for directors that have fixed point semantics at each 057 iteration. An iteration consists of repeated firings of the 058 actors controlled by this director until a fixed point is reached. 059 An iteration has converged if firing actors will not change signal 060 status any more. 061 <p> 062 At the beginning of each iteration, the status of 063 all inputs and outputs is unknown. Upon firing an actor, 064 the status of its output signals may become known. Once the status of 065 a signal becomes known, it cannot be changed back to unknown in the 066 iteration. This monotonicity constraint ensures the existence and 067 uniqueness of the fixed point. 068 During an iteration, the prefire() and fire() methods of the controlled 069 actors may be repeatedly invoked, but the postfire() method will be 070 invoked exactly once after the fixed point has been found. 071 The postfire() methods of the contained actors are invoked only 072 in the postfire() method of this director, and they are invoked 073 in arbitrary order. 074 </p><p> 075 If the prefire() method of an actor returns false, then this director 076 assumes that all the outputs of the actor are absent. The actor has 077 declined to fire. 078 </p><p> 079 Although this director does not require any specific ordering of actor 080 firings, a scheduler is used to choose an efficient ordering. 081 <p> 082 By default, actors are <i>strict</i>, which means that all their 083 input signals must be known before the actor can be fired. Here, 084 what we mean by "fired" is that prefire() is invoked, and if it 085 returns true, then fire() is invoked. Such actors 086 will be fired only once in an iteration. A non-strict actor can 087 be fired regardless of the status of its inputs, and may be fired 088 repeatedly in an iteration if some of the inputs are unknown. 089 Once an actor is fired with all its inputs known, it will not 090 be fired again in the same iteration. 091 A composite actor containing this director is a non-strict actor. 092 <p> 093 For an actor to be used under the control of this director, it must 094 either be strict, or if it is non-strict, it must be monotonic. 095 Montonicity implies two constraints on the actor. First, if prefire() 096 ever returns true during an iteration, then it will return true 097 on all subsequent invocations in the same iteration(). 098 Second, if either prefire() or fire() call clear() on an output port, 099 then no subsequent invocation in the same iteration can call 100 put() on the port. If prefire() or fire() call put() on an 101 output port with some token, then no subsequent invocation in 102 the same iteration can call clear() or put() with a token with 103 a different value. 104 These constraints ensure determinacy. 105 </p><p> 106 If <i>synchronizeToRealTime</i> is set to <code>true</code>, 107 then the postfire() method stalls until the real time elapsed 108 since the model started matches the current time. 109 This ensures that the director does not get ahead of real time. However, 110 of course, this does not ensure that the director keeps up with real time. 111 Note that this synchronization occurs <i>after</i> actors have been fired, 112 but before they have been postfired. 113 <p> 114 This class is based on the original SRDirector, written by Paul Whitaker. 115 116 @author Haiyang Zheng and Edward A. Lee 117 @version $Id$ 118 @since Ptolemy II 5.2 119 @Pt.ProposedRating Green (hyzheng) 120 @Pt.AcceptedRating Yellow (eal) 121 */ 122public class FixedPointDirector extends StaticSchedulingDirector 123 implements SuperdenseTimeDirector { 124 125 /** Construct a director in the default workspace with an empty string 126 * as its name. The director is added to the list of objects in 127 * the workspace. Increment the version number of the workspace. 128 * @exception IllegalActionException If the name has a period in it, or 129 * the director is not compatible with the specified container. 130 * @exception NameDuplicationException If the container already contains 131 * an entity with the specified name. 132 */ 133 public FixedPointDirector() 134 throws IllegalActionException, NameDuplicationException { 135 super(); 136 _init(); 137 } 138 139 /** Construct a director in the given workspace with an empty name. 140 * The director is added to the list of objects in the workspace. 141 * Increment the version number of the workspace. 142 * @param workspace The workspace for this object. 143 * @exception IllegalActionException If the name has a period in it, or 144 * the director is not compatible with the specified container. 145 * @exception NameDuplicationException If the container already contains 146 * an entity with the specified name. 147 */ 148 public FixedPointDirector(Workspace workspace) 149 throws IllegalActionException, NameDuplicationException { 150 super(workspace); 151 _init(); 152 } 153 154 /** Construct a director in the given container with the given name. 155 * The container argument must not be null, or a 156 * NullPointerException will be thrown. 157 * If the name argument is null, then the name is set to the 158 * empty string. Increment the version number of the workspace. 159 * @param container Container of the director. 160 * @param name Name of this director. 161 * @exception IllegalActionException If the director is not compatible 162 * with the specified container. 163 * @exception NameDuplicationException If the name collides with an 164 * attribute in the container. 165 */ 166 public FixedPointDirector(CompositeEntity container, String name) 167 throws IllegalActionException, NameDuplicationException { 168 super(container, name); 169 _init(); 170 } 171 172 /////////////////////////////////////////////////////////////////// 173 //// parameters //// 174 175 /** The number of times that postfire may be called before it 176 * returns false. The type must be int, and the value 177 * defaults to zero. If the value is less than or equal to zero, 178 * then the execution will never return false in postfire, and 179 * thus the execution can continue forever. 180 */ 181 public Parameter iterations; 182 183 /** Specify whether the execution should synchronize to the 184 * real time. This parameter has type boolean and defaults 185 * to false. If set to true, then this director stalls in the 186 * prefire() method until the elapsed real real time matches 187 * the current time. If the <i>period</i> parameter has value 188 * 0.0 (the default), then changing this parameter to true 189 * has no effect. Note that in this base class, there is 190 * no <i>period</i> parameter and time is never advanced, 191 * so this will have no effect. It has effect in derived 192 * classes. 193 */ 194 public Parameter synchronizeToRealTime; 195 196 /////////////////////////////////////////////////////////////////// 197 //// public methods //// 198 199 /** Clone the director into the specified workspace. This calls the 200 * base class and then sets the attribute public members to refer 201 * to the attributes of the new director. 202 * @param workspace The workspace for the new director. 203 * @return A new director. 204 * @exception CloneNotSupportedException If a derived class contains 205 * an attribute that cannot be cloned. 206 */ 207 @Override 208 public Object clone(Workspace workspace) throws CloneNotSupportedException { 209 FixedPointDirector newObject = (FixedPointDirector) super.clone( 210 workspace); 211 newObject._receivers = new LinkedList(); 212 213 newObject._actorsAllowedToFire = new HashSet(); 214 newObject._actorsFinishedFiring = new HashSet(); 215 newObject._actorsFired = new HashSet(); 216 newObject._cachedAllInputsKnown = new HashSet(); 217 return newObject; 218 } 219 220 /** Prefire and fire actors in the order given by the scheduler 221 * until the iteration converges. 222 * An iteration converges when a pass through the schedule does 223 * not change the status of any receiver. 224 * @exception IllegalActionException If an actor violates the 225 * monotonicity constraints, or the prefire() or fire() method 226 * of the actor throws it. 227 */ 228 @Override 229 public void fire() throws IllegalActionException { 230 if (_debugging) { 231 _debug("FixedPointDirector: invoking fire()."); 232 } 233 Schedule schedule = getScheduler().getSchedule(); 234 int iterationCount = 0; 235 do { 236 Iterator firingIterator = schedule.firingIterator(); 237 while (firingIterator.hasNext() && !_stopRequested) { 238 Actor actor = ((Firing) firingIterator.next()).getActor(); 239 // If the actor has previously returned false in postfire(), 240 // do not fire it. 241 if (!_actorsFinishedExecution.contains(actor)) { 242 // check if the actor is ready to fire. 243 if (_isReadyToFire(actor)) { 244 _fireActor(actor); 245 _actorsFired.add(actor); 246 } else { 247 if (_debugging) { 248 if (!_actorsFinishedFiring.contains(actor) 249 && actor.isStrict()) { 250 _debug("Strict actor has uknown inputs: " 251 + actor.getFullName()); 252 } 253 } 254 } 255 } else { 256 // The postfire() method of this actor returned false in 257 // some previous iteration, so here, for the benefit of 258 // connected actors, we need to explicitly call the 259 // send(index, null) method of all of its output ports, 260 // which indicates that a signal is known to be absent. 261 if (_debugging) { 262 _debug("FixedPointDirector: no longer enabled (return false in postfire): " 263 + actor.getFullName()); 264 } 265 _sendAbsentToAllUnknownOutputsOf(actor); 266 } 267 } 268 iterationCount++; 269 } while (!_hasIterationConverged() && !_stopRequested); 270 271 if (_debugging) { 272 _debug(this.getFullName() + ": Fixed point found after " 273 + iterationCount + " iterations."); 274 } 275 } 276 277 /** Return the current index of the director. 278 * The current index is a portion of the superdense time. 279 * Superdense time means that time is a real value and an index, 280 * allowing multiple sequential steps to occur at a fixed (real) time. 281 * @return the superdense time index 282 * @see #setIndex(int) 283 * @see ptolemy.actor.SuperdenseTimeDirector 284 */ 285 @Override 286 public int getIndex() { 287 return _index; 288 } 289 290 /** Return the next time of interest in the model being executed by 291 * this director or the director of any enclosing model up the 292 * hierarchy. If this director is at the top level, then this 293 * default implementation simply returns infinity, indicating 294 * that this director has no interest in any future time. 295 * If this director is not at the top level, then return 296 * whatever the enclosing director returns. 297 * <p> 298 * This method is useful for domains that perform 299 * speculative execution (such as Continuous itself). 300 * Such a domain in a hierarchical 301 * model (i.e. CT inside DE) uses this method to determine how far 302 * into the future to execute. This is simply an optimization that 303 * reduces the likelihood of having to roll back. 304 * <p> 305 * The base class implementation in Director is almost right, 306 * but not quite, because at the top level it returns current 307 * time. However, this director should not constrain any director 308 * below it from speculatively executing into the future. 309 * Instead, it assumes that any director below it implements 310 * a strict actor semantics. Note in particular that the 311 * implementation below would block time advancement in 312 * a Continuous in DE in Continuous model because the 313 * top-level model will usually only invoke the DE model 314 * during a zero-step execution, which means that the returned 315 * next iteration time will always be current time, which will 316 * force the inside Continuous director to have a zero step 317 * size always. 318 * @return The next time of interest. 319 * @exception IllegalActionException If creating a Time object fails. 320 * @see #getModelTime() 321 */ 322 @Override 323 public Time getModelNextIterationTime() throws IllegalActionException { 324 if (isEmbedded()) { 325 return super.getModelNextIterationTime(); 326 } 327 return Time.POSITIVE_INFINITY; 328 } 329 330 /** Return true, indicating that this director assumes and exports 331 * the strict actor semantics, as described in this paper: 332 * <p> 333 * A. Goderis, C. Brooks, I. Altintas, E. A. Lee, and C. Goble, 334 * "Heterogeneous Composition of Models of Computation," 335 * EECS Department, University of California, Berkeley, 336 * Tech. Rep. UCB/EECS-2007-139, Nov. 2007. 337 * http://www.eecs.berkeley.edu/Pubs/TechRpts/2007/EECS-2007-139.html 338 * <p> 339 * In particular, a director that implements this interface guarantees 340 * that it will not invoke the postfire() method of an actor until all 341 * its inputs are known at the current tag. Moreover, it it will only 342 * do so in its own postfire() method, and in its prefire() and fire() 343 * methods, it does not change its own state. Thus, such a director 344 * can be used within a model of computation that has a fixed-point 345 * semantics, such as SRDirector and ContinuousDirector. 346 * @return True. 347 */ 348 @Override 349 public boolean implementsStrictActorSemantics() { 350 return true; 351 } 352 353 /** Initialize the director and all deeply contained actors by calling 354 * the super.initialize() method. Reset all private variables. 355 * @exception IllegalActionException If the superclass throws it. 356 */ 357 @Override 358 public void initialize() throws IllegalActionException { 359 _currentIteration = 0; 360 // This variable has to be reset at the very beginning, because 361 // some actors may call fireAt method to register breakpoints in DE 362 // and Continuous domains, which depend on the value of _index. 363 _index = 0; 364 // This could be getting re-initialized during execution 365 // (e.g., if we are inside a modal model), in which case, 366 // if the enclosing director is a superdense time director, 367 // we should initialize to its microstep, not to our own. 368 // NOTE: Some (weird) directors pretend they are not embedded even 369 // if they are (e.g. in Ptides), so we call _isEmbedded() to give 370 // the subclass the option of pretending it is not embedded. 371 /* NOTE: No, this doesn't make sense. Initialization should 372 * reset the microstep to zero, otherwise actors like clocks 373 * and PeriodicSampler won't work properly. 374 if (isEmbedded()) { 375 Nameable container = getContainer(); 376 if (container instanceof CompositeActor) { 377 Director executiveDirector = ((CompositeActor) container) 378 .getExecutiveDirector(); 379 if (executiveDirector instanceof SuperdenseTimeDirector) { 380 _index = ((SuperdenseTimeDirector) executiveDirector) 381 .getIndex(); 382 } 383 } 384 } 385 */ 386 387 _cachedFunctionalProperty = true; 388 _functionalPropertyVersion = -1L; 389 390 super.initialize(); 391 392 _realStartTime = System.currentTimeMillis(); 393 394 // NOTE: The following used to be done in prefire(), which is wrong, 395 // because prefire() can be invoked multiple times in an iteration 396 // (particularly if this is inside another FixedPointDirector). 397 _resetAllReceivers(); 398 } 399 400 /** Return true if all the controlled actors' isFireFunctional() 401 * methods return true. Otherwise, return false. 402 * 403 * @return True if all controlled actors are functional. Return 404 * false if there is no container or no actors in the container. 405 */ 406 @Override 407 public boolean isFireFunctional() { 408 if (workspace().getVersion() == _functionalPropertyVersion) { 409 return _cachedFunctionalProperty; 410 } 411 412 boolean result = true; 413 boolean containsActors = false; 414 415 CompositeActor container = (CompositeActor) getContainer(); 416 if (container == null) { 417 return false; 418 } 419 Iterator actors = container.deepEntityList().iterator(); 420 421 while (result && actors.hasNext() && !_stopRequested) { 422 Actor actor = (Actor) actors.next(); 423 result = actor.isFireFunctional() && result; 424 containsActors = true; 425 } 426 427 if (!containsActors) { 428 result = false; 429 } 430 _cachedFunctionalProperty = result; 431 _functionalPropertyVersion = workspace().getVersion(); 432 433 return result; 434 } 435 436 /** Return false. The transferInputs() method checks whether 437 * the inputs are known before calling hasToken(). 438 * Thus this director tolerates unknown inputs. 439 * @return False. 440 */ 441 @Override 442 public boolean isStrict() { 443 return false; 444 } 445 446 /** Return a new FixedPointReceiver. If a subclass overrides this 447 * method, the receiver it creates must be a subclass of FixedPointReceiver, 448 * and it must add the receiver to the _receivers list (a protected 449 * member of this class). 450 * @return A new FixedPointReceiver. 451 */ 452 @Override 453 public Receiver newReceiver() { 454 Receiver receiver = new FixedPointReceiver(this); 455 _receivers.add(receiver); 456 return receiver; 457 } 458 459 /** Call postfire() on all contained actors that were fired in the current 460 * iteration. Return false if the model 461 * has finished executing, either by reaching the iteration limit, or if 462 * no actors in the model return true in postfire(), or if stop has 463 * been requested, or if no actors fired at all in the last iteration. 464 * This method is called only once for each iteration. 465 * Note that actors are postfired in arbitrary order. 466 * @return True if the execution is not finished. 467 * @exception IllegalActionException If the iterations parameter does 468 * not have a valid token, or if there still some unknown inputs (which 469 * indicates a causality loop). 470 */ 471 @Override 472 public boolean postfire() throws IllegalActionException { 473 if (_debugging) { 474 _debug("FixedPointDirector: Called postfire()."); 475 } 476 477 boolean needMoreIterations = true; 478 // If no actors were fired, this director used to return 479 // false in postfire. However, this is not correct because there 480 // may be actors that are using time to decide whether to fire 481 // and, in addition, this may be embedded, in which case future 482 // events will trigger firings. 483 /* 484 int numberOfActors = getScheduler().getSchedule().size(); 485 if ((numberOfActors > 0) && (_actorsFired.size() == 0)) { 486 needMoreIterations = false; 487 } 488 */ 489 490 // The following used to inexplicably iterate only over 491 // _actorsFired. Now we iterate over all actors in the order 492 // of the schedule. 493 Schedule schedule = getScheduler().getSchedule(); 494 Iterator firingIterator = schedule.firingIterator(); 495 while (firingIterator.hasNext() && !_stopRequested) { 496 Actor actor = ((Firing) firingIterator.next()).getActor(); 497 // Check for remaining unknown inputs. 498 // Don't care about actors that have previously returned false from postfire(). 499 if (!_areAllInputsKnown(actor) 500 && !_actorsFinishedExecution.contains(actor)) { 501 // Construct a list of the unknown inputs. 502 StringBuffer unknownInputs = new StringBuffer(); 503 Iterator inputPorts = actor.inputPortList().iterator(); 504 IOPort firstPort = null; 505 while (inputPorts.hasNext()) { 506 IOPort inputPort = (IOPort) inputPorts.next(); 507 if (!inputPort.isKnown()) { 508 unknownInputs.append(inputPort.getName()); 509 unknownInputs.append("\n"); 510 if (firstPort == null) { 511 firstPort = inputPort; 512 } 513 } 514 } 515 throw new IllegalActionException(actor, firstPort, 516 "Unknown inputs remain. Possible causality loop:\n" 517 + unknownInputs); 518 } 519 if (_actorsFired.contains(actor)) { 520 if (!_postfireActor(actor)) { 521 // postfire() returned false, so prevent the actor 522 // from iterating again. 523 _actorsFinishedExecution.add(actor); 524 } 525 } 526 } 527 if (_debugging) { 528 _debug(this.getFullName() + ": Iteration " + _currentIteration 529 + " is complete."); 530 } 531 532 // NOTE: The following used to be done in prefire(), which is wrong, 533 // because prefire() can be invoked multiple times in an iteration 534 // (particularly if this is inside another FixedPointDirector). 535 _resetAllReceivers(); 536 537 // In this base class, the superdense time index is the only advancement 538 // of time, and it advances on every iteration. Derived classes must set 539 // it to zero in their postfire method if they advance time. 540 _index++; 541 542 // Check whether the current execution has reached its iteration limit. 543 _currentIteration++; 544 int numberOfIterations = ((IntToken) iterations.getToken()).intValue(); 545 if (numberOfIterations > 0 && _currentIteration >= numberOfIterations) { 546 super.postfire(); 547 return false; 548 } 549 550 return super.postfire() && needMoreIterations; 551 } 552 553 /** Return true if the director is ready to fire. 554 * If <i>synchronizeToRealTime</i> is true, then 555 * wait for real time elapse to match or exceed model time. 556 * The return whatever the base class returns. 557 * @return True. 558 * @exception IllegalActionException Not thrown in this base class. 559 */ 560 @Override 561 public boolean prefire() throws IllegalActionException { 562 _synchronizeToRealTime(); 563 _postfireReturns = true; 564 565 boolean result = true; 566 List<IOPort> ports = ((CompositeEntity) getContainer()).portList(); 567 for (IOPort port : ports) { 568 if (port instanceof ParameterPort) { 569 if (!port.isKnown()) { 570 result = false; 571 break; 572 } 573 } 574 } 575 // The following synchronizes to environment time, making 576 // any necessary adjustments for drift or offset of the local clock. 577 return super.prefire() && result; 578 } 579 580 /** Set the superdense time index. This should only be 581 * called by an enclosing director. 582 * @exception IllegalActionException Not thrown in this base class. 583 * @see #getIndex() 584 * @see ptolemy.actor.SuperdenseTimeDirector 585 */ 586 @Override 587 public void setIndex(int index) throws IllegalActionException { 588 if (_debugging) { 589 _debug("Setting superdense time index to " + index); 590 } 591 _index = index; 592 } 593 594 /** Return an array of suggested directors to be used with 595 * ModalModel. Each director is specified by its full class 596 * name. The first director in the array will be the default 597 * director used by a modal model. 598 * @return An array of suggested directors to be used with ModalModel. 599 * @see ptolemy.actor.Director#suggestedModalModelDirectors() 600 */ 601 @Override 602 public String[] suggestedModalModelDirectors() { 603 String[] defaultSuggestions = new String[2]; 604 defaultSuggestions[1] = "ptolemy.domains.modal.kernel.NonStrictFSMDirector"; 605 defaultSuggestions[0] = "ptolemy.domains.modal.kernel.FSMDirector"; 606 return defaultSuggestions; 607 } 608 609 /** Transfer data from the specified input port of the 610 * container to the ports it is connected to on the inside. 611 * If there is no data on the specified input port, then 612 * set the ports on the inside to absent by calling sendInside(index, null). 613 * This method delegates the data transfer 614 * operation to the transferInputs method of the super class. 615 * 616 * @param port The port to transfer tokens from. 617 * @return True if at least one token is transferred. 618 * @exception IllegalActionException If the port is not an opaque 619 * input port. 620 */ 621 @Override 622 public boolean transferInputs(IOPort port) throws IllegalActionException { 623 boolean result = false; 624 int insideWidth = port.getWidthInside(); 625 for (int i = 0; i < port.getWidth(); i++) { 626 if (port.isKnown(i)) { 627 if (port.hasToken(i)) { 628 result = super.transferInputs(port) || result; 629 } else { 630 if (i < insideWidth) { 631 port.sendInside(i, null); 632 } 633 } 634 } 635 // we do not explicit reset the receivers receiving inputs 636 // from this port because the fixedpoint director resets the 637 // receivers in its prefire() method. 638 } 639 // If the inside is wider than the outside, send clear on the inside. 640 for (int i = port.getWidth(); i < insideWidth; i++) { 641 port.sendInside(i, null); 642 } 643 return result; 644 } 645 646 /** Transfer data from the specified output port of the 647 * container to the ports it is connected to on the outside. 648 * If there is no data on the specified output port, then 649 * set the ports on the outside to absent by calling send(index, null). 650 * This method delegates the data transfer 651 * operation to the transferOutputs method of the super class. 652 * 653 * @param port The port to transfer tokens from. 654 * @return True if at least one token is transferred. 655 * @exception IllegalActionException If the port is not an opaque 656 * input port, or if there are not enough input tokens available. 657 */ 658 @Override 659 public boolean transferOutputs(IOPort port) throws IllegalActionException { 660 boolean result = false; 661 int outsideWidth = port.getWidth(); 662 for (int i = 0; i < port.getWidthInside(); i++) { 663 if (port.isKnownInside(i)) { 664 if (port.hasTokenInside(i)) { 665 result = super.transferOutputs(port) || result; 666 } else { 667 // Mark the destination receivers absent, if the destination 668 // receiver has such a notion, and otherwise do nothing. 669 if (i < outsideWidth) { 670 port.send(i, null); 671 } 672 } 673 } else if (i < outsideWidth) { 674 // Output is not known. To ensure that this fact propagate 675 // outside, find the remote receivers and reset them. 676 // This was causing a monotonicity failure in certain 677 // modal models. 678 Receiver[][] remoteReceivers = port.getRemoteReceivers(); 679 for (Receiver remoteReceiver : remoteReceivers[i]) { 680 remoteReceiver.reset(); 681 } 682 } 683 } 684 // If the outside is wider than the inside, send clear on the outside. 685 /* NOTE: The following isn't right! Need to leave the output unknown in case 686 * we are in a modal model. A transition may be wanting to set it. 687 * it has to become known only if the environment sets it known 688 * by presuming that any unproduced outputs are absent. 689 * 690 for (int i = port.getWidthInside(); i < outsideWidth; i++) { 691 port.send(i, null); 692 } 693 */ 694 return result; 695 } 696 697 /////////////////////////////////////////////////////////////////// 698 //// protected methods //// 699 700 /** Return true if all the inputs of the specified actor are known. 701 * @param actor The specified actor. 702 * @return True if the all the inputs of the specified actor are known. 703 * @exception IllegalActionException If thrown while checking if an input 704 * port is known. 705 */ 706 protected boolean _areAllInputsKnown(Actor actor) 707 throws IllegalActionException { 708 709 if (_cachedAllInputsKnown.contains(actor)) { 710 return true; 711 } 712 713 Iterator inputPorts = actor.inputPortList().iterator(); 714 715 while (inputPorts.hasNext()) { 716 IOPort inputPort = (IOPort) inputPorts.next(); 717 718 if (!inputPort.isKnown()) { 719 return false; 720 } 721 } 722 723 _cachedAllInputsKnown.add(actor); 724 return true; 725 } 726 727 /** Fire an actor. Call its prefire() method, and 728 * if that returns true, call its fire() method. 729 * @param actor The actor to be fired. 730 * @exception IllegalActionException If the prefire() method 731 * returns false having previously returned true in the same 732 * iteration, or if the prefire() or fire() method of the actor 733 * throws it. 734 */ 735 protected void _fireActor(Actor actor) throws IllegalActionException { 736 // Prefire the actor. 737 boolean prefireReturns = actor.prefire(); 738 if (_debugging) { 739 _debug("FixedPointDirector: Prefiring: " 740 + ((Nameable) actor).getFullName() + ", which returns " 741 + prefireReturns); 742 } 743 // Check monotonicity constraint. 744 if (!prefireReturns && _actorsAllowedToFire.contains(actor)) { 745 throw new IllegalActionException(actor, 746 "prefire() method returns false, but it" 747 + " has previously returned true in this iteration."); 748 } 749 if (prefireReturns) { 750 _actorsAllowedToFire.add(actor); 751 752 // Whether all inputs are known must be checked before 753 // firing to handle cases with self-loops, because the 754 // current firing may change the status of some input 755 // receivers from unknown to known. 756 boolean allInputsKnownBeforeFiring = _areAllInputsKnown(actor); 757 758 if (_debugging) { 759 if (allInputsKnownBeforeFiring) { 760 _debug("Firing: " + ((Nameable) actor).getName() 761 + ", which has all inputs known."); 762 } else { 763 _debug("Firing: " + ((Nameable) actor).getName() 764 + ", which has some inputs unknown."); 765 } 766 } 767 768 actor.fire(); 769 // If all of the inputs of this actor were known before firing, firing 770 // the actor again in the current iteration is not necessary. 771 if (allInputsKnownBeforeFiring) { 772 _actorsFinishedFiring.add(actor); 773 _sendAbsentToAllUnknownOutputsOf(actor); 774 } 775 } else { 776 // prefire() returned false. The actor declines 777 // to fire. This could be because some inputs are 778 // not known. If all inputs are known, then we 779 // interpret this to mean that all outputs should be absent. 780 // Note that prefire() is executed only after all the inputs are 781 // known if the actor is strict. 782 if (actor.isStrict() || _areAllInputsKnown(actor)) { 783 _actorsFinishedFiring.add(actor); 784 _sendAbsentToAllUnknownOutputsOf(actor); 785 } 786 } 787 } 788 789 /** Return true if this iteration has converged. The iteration has 790 * converged if both the number of known receivers 791 * has not changed since the previous invocation of this method. 792 * @return true if this iteration has converged. 793 * @exception IllegalActionException Not thrown in this base class. 794 */ 795 protected boolean _hasIterationConverged() throws IllegalActionException { 796 if (_debugging) { 797 _debug(this.getFullName() 798 + ":\n Number of receivers known previously is " 799 + _lastNumberOfKnownReceivers 800 + ":\n Number of receivers known now is " 801 + _currentNumberOfKnownReceivers); 802 } 803 // Determine the number of known receivers has changed since the 804 // last iteration. If not, the current iteration has converged. 805 // Note that checking whether all receivers are known is not sufficient 806 // to conclude the convergence of the iteration because if some 807 // receivers just become known, their containers (actors) need to be 808 // fired to react these new inputs. 809 boolean converged = _lastNumberOfKnownReceivers == _currentNumberOfKnownReceivers; 810 _lastNumberOfKnownReceivers = _currentNumberOfKnownReceivers; 811 812 // One might try to optimize this method by also considering the 813 // _actorsFinishedFiring set. 814 // CompositeActor container = (CompositeActor) getContainer(); 815 // converged = 816 // _actorsFinishedFiring.size() == container.deepEntityList().size()); 817 return converged; 818 } 819 820 /** Return true if the specified actor is ready to fire. An actor is 821 * ready to fire if it has not previously finished firing in this iteration 822 * and either it is strict and all inputs are known or it is nonstrict. 823 * Note that this ignores whether the actor has previously returned 824 * false in postfire(). 825 * @param actor The actor that is checked for being ready to fire. 826 * @return true if the actor is ready to fire. 827 * @exception IllegalActionException If thrown while determining 828 * if actors are finished firing, or while determining if the actor is 829 * strict, or while determining if all the inputs are known. 830 */ 831 protected boolean _isReadyToFire(Actor actor) 832 throws IllegalActionException { 833 return !_actorsFinishedFiring.contains(actor) 834 && (!actor.isStrict() || _areAllInputsKnown(actor)); 835 } 836 837 /** React to the change in receiver status by incrementing the count of 838 * known receivers. 839 */ 840 protected void _receiverChanged() { 841 _currentNumberOfKnownReceivers++; 842 } 843 844 /** Reset all receivers to unknown status and clear out variables used 845 * to track which actors fired in the last iteration. 846 */ 847 protected void _resetAllReceivers() { 848 _actorsAllowedToFire.clear(); 849 _actorsFinishedFiring.clear(); 850 _actorsFired.clear(); 851 _cachedAllInputsKnown.clear(); 852 _lastNumberOfKnownReceivers = -1; 853 854 if (_debugging) { 855 _debug(" FixedPointDirector is resetting all receivers"); 856 } 857 _currentNumberOfKnownReceivers = 0; 858 859 Iterator receiverIterator = _receivers.iterator(); 860 while (receiverIterator.hasNext()) { 861 FixedPointReceiver receiver = (FixedPointReceiver) receiverIterator 862 .next(); 863 receiver.reset(); 864 } 865 } 866 867 /** Call the send(index, null) method of each output port with 868 * unknown status of the specified actor. 869 * @param actor The actor. 870 * @exception IllegalActionException If thrown while getting 871 * the width of a port, determining if a port is known 872 * or while sending data. 873 */ 874 protected void _sendAbsentToAllUnknownOutputsOf(Actor actor) 875 throws IllegalActionException { 876 // An actor, if its firing has finished but some of its 877 // outputs are still unknown, clear these outputs. 878 // However, there is nothing need to do if this actor has 879 // resolved all of its outputs. 880 Iterator outputPorts = actor.outputPortList().iterator(); 881 while (outputPorts.hasNext()) { 882 IOPort outputPort = (IOPort) outputPorts.next(); 883 // NOTE: The following assumes that if ANY destination 884 // receiver is known, then all are known. isKnown(j) 885 // will return false if ANY destination receiver on channel 886 // j is unknown, but send(j, null) will assert that ALL 887 // destination receivers are absent. 888 for (int j = 0; j < outputPort.getWidth(); j++) { 889 if (!outputPort.isKnown(j)) { 890 if (_debugging) { 891 _debug(" FixedPointDirector: Set output " 892 + outputPort.getFullName() + " to absent."); 893 } 894 outputPort.send(j, null); 895 } 896 } 897 } 898 } 899 900 /** Synchronize to real time, if appropriate. 901 * NOTE: This method is provided for backward compatibility. The preferred 902 * method for synchronizing to real time is now to use a 903 * {@link ptolemy.actor.lib.SynchronizeToRealTime} attribute, which implements the 904 * {@link ptolemy.actor.TimeRegulator} interface. 905 * @exception IllegalActionException If the <i>synchronizeToRealTime</i> 906 * parameter is ill formed. 907 */ 908 protected void _synchronizeToRealTime() throws IllegalActionException { 909 boolean synchronizeValue = ((BooleanToken) synchronizeToRealTime 910 .getToken()).booleanValue(); 911 912 if (synchronizeValue) { 913 int depth = 0; 914 try { 915 synchronized (this) { 916 while (true) { 917 long elapsedTime = System.currentTimeMillis() 918 - _realStartTime; 919 920 // NOTE: We assume that the elapsed time can be 921 // safely cast to a double. This means that 922 // the SR domain has an upper limit on running 923 // time of Double.MAX_VALUE milliseconds. 924 double elapsedTimeInSeconds = elapsedTime / 1000.0; 925 double currentTime = getModelTime().getDoubleValue(); 926 927 if (currentTime <= elapsedTimeInSeconds) { 928 break; 929 } 930 931 long timeToWait = (long) ((currentTime 932 - elapsedTimeInSeconds) * 1000.0); 933 934 if (_debugging) { 935 _debug("Waiting for real time to pass: " 936 + timeToWait); 937 } 938 939 try { 940 // NOTE: The built-in Java wait() method 941 // does not release the 942 // locks on the workspace, which would block 943 // UI interactions and may cause deadlocks. 944 // SOLUTION: explicitly release read permissions. 945 if (timeToWait > 0) { 946 // Bug fix from J. S. Senecal: 947 // 948 // The problem was that sometimes, the 949 // method Object.wait(timeout) was called 950 // with timeout = 0. According to java 951 // documentation: 952 // 953 // " If timeout is zero, however, then 954 // real time is not taken into 955 // consideration and the thread simply 956 // waits until notified." 957 depth = _workspace.releaseReadPermission(); 958 wait(timeToWait); 959 } 960 } catch (InterruptedException ex) { 961 // Continue executing. 962 } 963 } 964 } 965 } finally { 966 if (depth > 0) { 967 _workspace.reacquireReadPermission(depth); 968 } 969 } 970 } 971 } 972 973 /////////////////////////////////////////////////////////////////// 974 //// protected variables //// 975 976 /** The set of actors that have returned true in their prefire() methods 977 * in the current iteration. This is used only to check monotonicity 978 * constraints and to determine which actors should be postfired. 979 */ 980 protected Set _actorsAllowedToFire = new HashSet(); 981 982 /** Actors that were fired in the most recent invocation of the fire() method. */ 983 protected Set _actorsFired = new HashSet(); 984 985 /** The current index of the model. */ 986 protected int _index; 987 988 /** List of all receivers this director has created. */ 989 protected List _receivers = new LinkedList(); 990 991 /** The set of actors that have been fired in this iteration with 992 * all inputs known. 993 */ 994 protected Set _actorsFinishedFiring = new HashSet(); 995 996 /////////////////////////////////////////////////////////////////// 997 //// private methods //// 998 999 /** Initialize the director by creating the parameters and setting their 1000 * values and types. 1001 */ 1002 private void _init() 1003 throws IllegalActionException, NameDuplicationException { 1004 _zeroTime = new Time(this, 0.0); 1005 1006 iterations = new Parameter(this, "iterations", new IntToken(0)); 1007 iterations.setTypeEquals(BaseType.INT); 1008 1009 synchronizeToRealTime = new Parameter(this, "synchronizeToRealTime"); 1010 synchronizeToRealTime.setExpression("false"); 1011 synchronizeToRealTime.setTypeEquals(BaseType.BOOLEAN); 1012 1013 FixedPointScheduler scheduler = new FixedPointScheduler(this, 1014 uniqueName("Scheduler")); 1015 setScheduler(scheduler); 1016 } 1017 1018 /** Return the result of the postfire() method of the specified actor 1019 * if it is allowed to be fired in the current iteration. If this actor 1020 * is not to be fired in the current iteration, return true without 1021 * calling the postfire() method of the actor. 1022 */ 1023 private boolean _postfireActor(Actor actor) throws IllegalActionException { 1024 if (_actorsAllowedToFire.contains(actor)) { 1025 _debug(getFullName() + " is postfiring " 1026 + ((Nameable) actor).getFullName()); 1027 return actor.postfire(); 1028 } 1029 return true; 1030 } 1031 1032 /////////////////////////////////////////////////////////////////// 1033 //// private variables //// 1034 1035 /** The set of actors that have all inputs known in the given iteration. */ 1036 private Set _cachedAllInputsKnown = new HashSet(); 1037 1038 /** The cache of the functional property of the container of this director. */ 1039 private boolean _cachedFunctionalProperty; 1040 1041 /** The current number of receivers with known state. */ 1042 private int _currentNumberOfKnownReceivers; 1043 1044 /** The count of iterations executed. */ 1045 private int _currentIteration; 1046 1047 /** Version number for the cached functional property. */ 1048 private transient long _functionalPropertyVersion = -1L; 1049 1050 /** The number of receivers with known state on the last phase of 1051 * actor firings. 1052 */ 1053 private int _lastNumberOfKnownReceivers; 1054 1055 /** The real time at which the model begins executing. */ 1056 private long _realStartTime = 0L; 1057}