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}