001/* An actor containing a finite state machine (FSM).
002
003 Copyright (c) 1999-2018 The Regents of the University of California.
004 All rights reserved.
005 Permission is hereby granted, without written agreement and without
006 license or royalty fees, to use, copy, modify, and distribute this
007 software and its documentation for any purpose, provided that the above
008 copyright notice and the following two paragraphs appear in all copies
009 of this software.
010
011 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
012 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
013 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
014 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
015 SUCH DAMAGE.
016
017 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
018 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
019 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
020 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
021 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
022 ENHANCEMENTS, OR MODIFICATIONS.
023
024 PT_COPYRIGHT_VERSION_2
025 COPYRIGHTENDKEY
026 */
027package ptolemy.domains.modal.kernel;
028
029import java.io.IOException;
030import java.io.Writer;
031import java.util.HashMap;
032import java.util.HashSet;
033import java.util.Hashtable;
034import java.util.Iterator;
035import java.util.LinkedList;
036import java.util.List;
037import java.util.Map;
038import java.util.Random;
039import java.util.Set;
040
041import ptolemy.actor.Actor;
042import ptolemy.actor.ActorExecutionAspect;
043import ptolemy.actor.CompositeActor;
044import ptolemy.actor.Director;
045import ptolemy.actor.Executable;
046import ptolemy.actor.ExecutionAspectHelper;
047import ptolemy.actor.IOPort;
048import ptolemy.actor.IORelation;
049import ptolemy.actor.Initializable;
050import ptolemy.actor.Manager;
051import ptolemy.actor.Receiver;
052import ptolemy.actor.SuperdenseTimeDirector;
053import ptolemy.actor.TypedActor;
054import ptolemy.actor.TypedIOPort;
055import ptolemy.actor.lib.RandomSource;
056import ptolemy.actor.parameters.SharedParameter;
057import ptolemy.actor.util.BooleanDependency;
058import ptolemy.actor.util.CausalityInterface;
059import ptolemy.actor.util.DFUtilities;
060import ptolemy.actor.util.DefaultCausalityInterface;
061import ptolemy.actor.util.Dependency;
062import ptolemy.actor.util.ExplicitChangeContext;
063import ptolemy.actor.util.Time;
064import ptolemy.data.ArrayToken;
065import ptolemy.data.BooleanToken;
066import ptolemy.data.DoubleToken;
067import ptolemy.data.Function;
068import ptolemy.data.FunctionToken;
069import ptolemy.data.IntToken;
070import ptolemy.data.LongToken;
071import ptolemy.data.ObjectToken;
072import ptolemy.data.Token;
073import ptolemy.data.expr.ASTPtAssignmentNode;
074import ptolemy.data.expr.ASTPtRootNode;
075import ptolemy.data.expr.ModelScope;
076import ptolemy.data.expr.Parameter;
077import ptolemy.data.expr.ParseTreeFreeVariableCollector;
078import ptolemy.data.expr.ParserScope;
079import ptolemy.data.expr.PtParser;
080import ptolemy.data.expr.StringParameter;
081import ptolemy.data.expr.UndefinedConstantOrIdentifierException;
082import ptolemy.data.expr.Variable;
083import ptolemy.data.type.ArrayType;
084import ptolemy.data.type.BaseType;
085import ptolemy.data.type.FunctionType;
086import ptolemy.data.type.HasTypeConstraints;
087import ptolemy.data.type.ObjectType;
088import ptolemy.data.type.Type;
089import ptolemy.data.type.Typeable;
090import ptolemy.domains.modal.modal.ModalModel;
091import ptolemy.domains.modal.modal.ModalRefinement;
092import ptolemy.graph.Inequality;
093import ptolemy.graph.InequalityTerm;
094import ptolemy.kernel.ComponentEntity;
095import ptolemy.kernel.ComponentRelation;
096import ptolemy.kernel.CompositeEntity;
097import ptolemy.kernel.Entity;
098import ptolemy.kernel.Port;
099import ptolemy.kernel.Relation;
100import ptolemy.kernel.util.Attribute;
101import ptolemy.kernel.util.ChangeRequest;
102import ptolemy.kernel.util.IllegalActionException;
103import ptolemy.kernel.util.InternalErrorException;
104import ptolemy.kernel.util.KernelException;
105import ptolemy.kernel.util.NameDuplicationException;
106import ptolemy.kernel.util.Nameable;
107import ptolemy.kernel.util.NamedObj;
108import ptolemy.kernel.util.Settable;
109import ptolemy.kernel.util.StreamListener;
110import ptolemy.kernel.util.StringAttribute;
111import ptolemy.kernel.util.Workspace;
112
113///////////////////////////////////////////////////////////////////
114//// FSMActor
115
116/**
117 An FSMActor contains a set of states and transitions. A transition has
118 a <i>guard expression</i>, any number of <i>output actions</i>, and any
119 number of <i>set actions</i>. It has an <i>initial state</i>, which is
120 the unique state whose <i>isInitialState</i> parameter is true.
121 In outline, a firing of this actor is a sequence of steps as
122 follows. In the fire() method:
123 <ol>
124 <li> Read inputs.
125 <li> Evaluate guards on outgoing transitions of the current state.
126 <li> Choose a transitions whose guard is true.
127 <li> Execute the output actions.
128 </ol>
129 In the postfire() method:
130 <ol>
131 <li> Execute the set actions of the chosen transition.
132 <li> Change the current state to the destination of the chosen transition.
133 </ol>
134 The fire() method may be invoked more than once
135 in an iteration, for example in a fixedpoint iteration.
136 This actor makes no persistent state changes in
137 its fire()  method, so actor conforms
138 with the <i>actor abstract semantics</i>, and hence can be used in any
139 Ptolemy II domain.
140 <p>
141 After reading the inputs, this actor examines
142 the outgoing transitions of the current state, evaluating their
143 guard expressions. A transition is <i>enabled</i> if its guard
144 expression evaluates to true. A blank guard expression is
145 interpreted to be always true. The guard expression may refer to any
146 input port and any variable in scope.
147 <p>
148 If an input port name <i>portName</i> is used in a guard expression,
149 it refers to the current input on that port on channel zero.
150 If the input port status is not known, or if the input is absent,
151 then a guard expression referring to <i>portName</i> will not be evaluated.
152 The guard expression may alternatively refer to <i>portName</i>_<i>isPresent</i>,
153 which is a boolean that is true if an input is present on the specified
154 port. Again, if the input port status is not known, such a guard
155 would not be evaluated. The status of an input port may not be
156 known during firings under a director with fixed-point semantics,
157 such as SR or Continuous.
158 <p>
159 To refer to a channel specifically, a guard expression may use
160 <i>portName</i>_<i>channelIndex</i>, which has value equal to the token
161 received on the port on the given channel. Similarly, it may refer
162 to <i>portName</i>_<i>channelIndex</i>_<i>isPresent</i>.
163 <p>
164 FIXME: Document multirate behavior.
165 <p>
166 The identifier <i>portName</i>Array or
167 <i>portName</i>_<i>channelIndex</i>Array refers the
168 array of all tokens consumed from the port in the last firing.  This
169 identifier has an array type whose element type is the type of the
170 corresponding input port.
171 <p>
172 Nondeterministic transitions are allowed if all enabled transitions
173 are marked <i>nondeterministic</i>. If more than one transition is
174 enabled and they are all marked nondeterministic, then one is chosen
175 at random in the fire() method. Note that this class provides no
176 guarantees about the probability of selecting a particular
177 nondeterministic transition. It is perfectly valid to always
178 choose the same one, for example. To provide such a guarantee,
179 we would have to impose the constraint that no nondeterministic
180 transition can be chosen until the guards of all nondeterministic
181 transitions can be evaluated. This would rule out certain models,
182 in particular those that illustrate the celebrated Brock-Ackerman
183 anomaly.  Hence, in this implementation,
184 if the fire() method is invoked more
185 than once in an iteration, then subsequent invocations in the same
186 iteration will always choose the same transition, if it is still
187 enabled. If more transitions become enabled in subsequent firings and
188 they are not all marked nondeterminate, then an
189 exception will thrown. All of this means that
190 if some input is unknown on the first invocation
191 of fire(), and a guard refers to that input, then that transition
192 will not be chosen. As a consequence, for nondeterministic state
193 machines, the behavior may depend on the order of firings in
194 a fixed-point iteration. This is in fact unavoidable (it is
195 related to the celebrated Brock-Ackerman anomaly, which demonstrates
196 that the input/output relations of a nondeterministic system do
197 not completely determine its behavior; the context in which it
198 is used can also affect the behavior; specifically, the context
199 may make it impossible to know the value of input on the first
200 invocation of fire() because of a feedback loop). Thus, to
201 correctly realize all nondeterministic systems, we cannot provide
202 probabilistic execution of nondeterministic transitions.
203 <p>
204 If no transition is
205 enabled and all their guard expressions have been evaluated (all relevant
206 inputs are known), then if there is a transition marked as a
207 <i>default transition</i>, then that transition is chosen. If
208 there is more than one default transition and they are all marked
209 nondeterministic, then one is chosen at random.
210 <p>
211 Once a transition is chosen, its output actions are executed.
212 Typically, these will write values to output ports. The form of an output
213 action is typically <i>y</i> = <i>expression</i>, where expression may
214 refer to any variable defined as above or any parameter in scope
215 (and also to outputs of state refinements, see below).
216 This gives the behavior of a Mealy machine, where
217 outputs are produced by transitions rather than by states. Moore machine
218 behavior is also achievable using state refinements that produce
219 outputs (see FSMDirector documentation).
220 Multiple output actions may be given by separating them with semicolons.
221 Also, output actions may take the form of <i>d.p</i> = <i>expression</i>,
222 where <i>d</i> is the name of the destination state and <i>p</i> is a
223 parameter of the destination refinement.
224  <p>
225 After a transition is taken, this actor calls fireAtCurrentTime()
226 on its enclosing director. This ensures that if the destination
227 state has an enabled transition, that transition will be taken
228 at the same time (in the next superdense time index). It also
229 supports continuous-time models, where the destination state
230 refinement, if any, should produce an output at the next superdense
231 time index.
232 <p>
233 A final state is a state that has its <i>isFinalState</i> parameter
234 set to true. When the actor reaches a final state, then the
235 postfire method will return false, indicating that the actor does not
236 wish to be fired again.
237 <p>
238 An FSMActor can be used in a modal model to represent the mode
239 control logic.  In this case, the states and transitions have
240 refinements, and this actor works in concert with the FSMDirector
241 to execute those refinements. See the documentation for
242 FSMDirector for details on how that works.
243 <p>
244 By default, this actor has a conservative causality interface,
245 implemented by the {@link DefaultCausalityInterface}, which declares
246 that all outputs depend on all inputs. If, however, the enclosing
247 director and all state refinement directors implement the
248 strict actor semantics (as indicated by their
249 implementsStrictActorSemantics() method), then the returned
250 causality interface is
251 implemented by the {@link FSMCausalityInterface} class. If
252 the <i>stateDependentCausality</i> is false (the default),
253 then this causality interface in conservative and valid in all
254 states. If it is true, then the causality interface will show
255 different input/output dependencies depending on the state.
256 See {@link FSMCausalityInterface} for details.
257
258 @author Edward A. Lee, Xiaojun Liu, Haiyang Zheng, Ye Zhou, Christian Motika
259 @version $Id$
260 @since Ptolemy II 8.0
261 @Pt.ProposedRating Yellow (liuxj)
262 @Pt.AcceptedRating Yellow (kienhuis)
263 @see State
264 @see Transition
265 @see Action
266 @see FSMDirector
267 */
268public class FSMActor extends CompositeEntity
269        implements TypedActor, ExplicitChangeContext {
270    /** Construct an FSMActor in the default workspace with an empty string
271     *  as its name. Add the actor to the workspace directory.
272     *  Increment the version number of the workspace.
273     */
274    public FSMActor() {
275        super();
276        _init();
277    }
278
279    /** Create an FSMActor in the specified container with the specified
280     *  name. The name must be unique within the container or an exception
281     *  is thrown. The container argument must not be null, or a
282     *  NullPointerException will be thrown.
283     *  @param container The container.
284     *  @param name The name of this actor within the container.
285     *  @exception IllegalActionException If the entity cannot be contained
286     *   by the proposed container.
287     *  @exception NameDuplicationException If the name coincides with
288     *   an entity already in the container.
289     */
290    public FSMActor(CompositeEntity container, String name)
291            throws IllegalActionException, NameDuplicationException {
292        super(container, name);
293        _init();
294    }
295
296    /** Construct an FSMActor in the specified workspace with an empty
297     *  string as its name. You can then change the name with setName().
298     *  If the workspace argument is null, then use the default workspace.
299     *  Add the actor to the workspace directory.
300     *  Increment the version number of the workspace.
301     *  @param workspace The workspace that will list the actor.
302     */
303    public FSMActor(Workspace workspace) {
304        super(workspace);
305        _init();
306    }
307
308    ///////////////////////////////////////////////////////////////////
309    ////                         parameters                        ////
310
311    /** Parameter containing the cause of an exception thrown
312     *  while executing a refinement if the exception is a
313     *  KernelException that specified a Nameable.
314     *  This parameter may be used in a guard
315     *  expression or output or set action to access the object
316     *  that originated an exception on an error transition.
317     *  This is an object token that defaults to null.
318     *  This parameter is not persistent. It will not be exported to MoML.
319     */
320    public Parameter errorCause;
321
322    /** Parameter containing the name of the class of exception thrown
323     *  while executing a refinement. This parameter may be used in a guard
324     *  expression or output or set action to access the class of an
325     *  exception on an error transition.
326     *  This is a string that defaults to the empty string.
327     *  This parameter is not persistent. It will not be exported to MoML.
328     */
329    public StringParameter errorClass;
330
331    /** Parameter containing the message of exception thrown
332     *  while executing a refinement. This parameter may be used in a guard
333     *  expression or output or set action to access the message of an
334     *  exception on an error transition.
335     *  This is a string that defaults to the empty string.
336     *  This parameter is not persistent. It will not be exported to MoML.
337     */
338    public StringParameter errorMessage;
339
340    /** Parameter that is a function which evaluates to true
341     * when the randomly generated token value is within the probability
342     * range expressed by a transition.
343     */
344    public Parameter probability;
345
346    /** Boolean parameter to determine whether seeds are reset on each run.
347     */
348    public SharedParameter resetOnEachRun;
349
350    /** The seed to be used for random token generation, to evaluate
351     * probabilistic transitions between states.
352     */
353    public SharedParameter seed;
354
355    /** Parameter that is a function that evaluates to true when the
356     *  time elapsed in the current state equals the argument to the
357     *  function. This can be used in a guard to trigger a transition.
358     */
359    public Parameter timeout;
360
361    ///////////////////////////////////////////////////////////////////
362    ////                         public methods                    ////
363
364    /** Add a chosen transition to the set of chosen transitions.
365     *  There may be more than one chosen transition because the destination
366     *  state of a chosen transition may have immediate transitions emerging
367     *  from it.
368     *  @param state The state that has the last chosen transition.
369     *  @param transition The last chosen transition.
370     *  @see #getLastChosenTransitions()
371     *  @exception IllegalActionException If there is already a chosen
372     *   transition associated with the specified state and it is not
373     *   the same transition.
374     */
375    public void addChosenTransition(State state, Transition transition)
376            throws IllegalActionException {
377        Transition previouslyChosenTransition = _lastChosenTransitions
378                .get(state);
379        if (previouslyChosenTransition != null
380                && previouslyChosenTransition != transition) {
381            throw new IllegalActionException(this, transition,
382                    "Cannot change chosen transition within a firing.");
383        }
384        if (previouslyChosenTransition != transition) {
385            _lastChosenTransitions.put(state, transition);
386        }
387    }
388
389    /** Add the specified object to the list of objects whose
390     *  preinitialize(), initialize(), and wrapup()
391     *  methods should be invoked upon invocation of the corresponding
392     *  methods of this object.
393     *  @param initializable The object whose methods should be invoked.
394     *  @see #removeInitializable(Initializable)
395     *  @see ptolemy.actor.CompositeActor#addPiggyback(Executable)
396     */
397    @Override
398    public void addInitializable(Initializable initializable) {
399        if (_initializables == null) {
400            _initializables = new LinkedList<Initializable>();
401        }
402        _initializables.add(initializable);
403    }
404
405    /** If the attribute is <i>seed</i>
406     *  then create the base random number generator.
407     *  @param attribute The attribute that changed.
408     *  @exception IllegalActionException If the change is not acceptable
409     *   to this container (not thrown in this base class).
410     */
411    @Override
412    public void attributeChanged(Attribute attribute)
413            throws IllegalActionException {
414        if (attribute == seed) {
415            long seedValue;
416            if (seed != null) {
417                seedValue = ((LongToken) seed.getToken()).longValue();
418                _seed = seedValue;
419                _createRandomGenerator();
420            }
421
422        } else {
423            super.attributeChanged(attribute);
424        }
425    }
426
427    /** Return false because backward type inference is not implemented
428     *  for this actor.
429     *  @return false
430     */
431    @Override
432    public boolean isBackwardTypeInferenceEnabled() {
433        return false;
434    }
435
436    /** Clone the actor into the specified workspace. This calls the
437     *  base class and then sets the attribute public members to refer
438     *  to the attributes of the new actor.
439     *  @param workspace The workspace for the new actor.
440     *  @return A new FSMActor.
441     *  @exception CloneNotSupportedException If a derived class contains
442     *   an attribute that cannot be cloned.
443     */
444    @Override
445    public Object clone(Workspace workspace) throws CloneNotSupportedException {
446
447        // Thomas Feng writes: "Set the _instantiables in
448        // super.clone() so that it contains the instantiables newly
449        // added, whose setContainer() is called with the cloned
450        // object as its container."
451        // See $PTII/ptolemy/actor/gt/test/auto/InitializationBug.xml
452        List<Initializable> oldInitializables = _initializables;
453        _initializables = null;
454        FSMActor newObject = (FSMActor) super.clone(workspace);
455        _initializables = oldInitializables;
456        // If the next line is uncommented, the InitializationBug.xml fails.
457        // newObject._initializables = null;
458
459        newObject._currentState = null;
460        newObject._disabledRefinements = new HashSet<Actor>();
461        newObject._inputTokenMap = new HashMap();
462        newObject._lastChosenTransitions = new HashMap<State, Transition>();
463        newObject._lastChosenTransition = null;
464        newObject._lastTakenTransitions = new LinkedList<Transition>();
465        newObject._stateRefinementsToPostfire = new LinkedList<Actor>();
466
467        if (_initialState != null) {
468            newObject._initialState = (State) newObject
469                    .getEntity(_initialState.getName());
470        }
471
472        newObject._cachedInputPorts = null;
473        newObject._cachedOutputPorts = null;
474        newObject._causalityInterface = null;
475        newObject._causalityInterfaces = null;
476        newObject._causalityInterfacesVersions = null;
477        newObject._causalityInterfaceDirector = null;
478        newObject._connectionMaps = null;
479        newObject._connectionMapsVersion = -1;
480        newObject._currentConnectionMap = null;
481        newObject._identifierToPort = new HashMap<String, IOPort>();
482        newObject._identifierToPortVersion = -1;
483        newObject._inputPortsVersion = -1;
484        newObject._outputPortsVersion = -1;
485        newObject._receiversVersion = -1;
486        newObject._tokenListArrays = null;
487        newObject._transitionsPreviouslyChosenInIteration = new HashSet<Transition>();
488        newObject._transitionRefinementsToPostfire = new LinkedList<Actor>();
489
490        try {
491            newObject.probability
492                    .setToken(newObject.new ProbabilityFunctionToken());
493            newObject.timeout.setToken(newObject.new TimeoutFunctionToken());
494        } catch (IllegalActionException e) {
495            // Should not occur, because it didn't occur in the object being cloned.
496            throw new CloneNotSupportedException(e.getMessage());
497        }
498        newObject._transitionEvaluatedTo = new HashMap<Transition, BooleanToken>();
499        newObject._oldThreshold = 0.0;
500        newObject._randomToken = null;
501
502        return newObject;
503    }
504
505    /** Create receivers for each input port. In case the receivers
506     *  don't need to be created they are reset
507     *  @exception IllegalActionException If any port throws it.
508     */
509    @Override
510    public void createReceivers() throws IllegalActionException {
511        if (_receiversVersion != workspace().getVersion()) {
512            _createReceivers();
513            _receiversVersion = workspace().getVersion();
514        } else {
515            _resetReceivers();
516        }
517
518        _receiversVersion = workspace().getVersion();
519    }
520
521    /** Return the current state of this actor.
522     *  @return The current state of this actor.
523     */
524    public State currentState() {
525        return _currentState;
526    }
527
528    /** Return a list of enabled transitions among the given list of
529     *  transitions. This includes all transitions whose guards can
530     *  can be evaluated and evaluate to true, plus, if all guards can
531     *  be evaluated and evaluate to false, all default transitions.
532     *  <p>
533     *  After calling this method, you can call foundUnknown()
534     *  to determine whether any guard expressions
535     *  were found in the specified transition list that
536     *  referred to input ports that are not currently known.
537     *  @param transitionList A list of transitions.
538     *  @param preemptive True to consider only preemptive transitions,
539     *   false to consider only non-preemptive transitions.
540     *  @param immediateOnly True to consider only immediate transitions,
541     *   false to consider both immediate and non-immediate transitions.
542     *  @return A list of enabled transition.
543     *  @exception IllegalActionException If the guard expression of any
544     *  transition can not be evaluated.
545     */
546    public List enabledTransitions(List transitionList, boolean preemptive,
547            boolean immediateOnly) throws IllegalActionException {
548        LinkedList enabledTransitions = new LinkedList();
549        LinkedList defaultTransitions = new LinkedList();
550
551        Iterator transitionRelations = transitionList.iterator();
552
553        _foundUnknown = false;
554        while (transitionRelations.hasNext() && !_stopRequested) {
555            Transition transition = (Transition) transitionRelations.next();
556            if (immediateOnly) {
557                boolean isImmediate = transition.isImmediate();
558                if (!isImmediate) {
559                    continue;
560                }
561            }
562            if (preemptive && !transition.isPreemptive()
563                    || !preemptive && transition.isPreemptive()) {
564                continue;
565            }
566            boolean transitionRefersToUnknownInputs = !_referencedInputPortsByGuardKnown(
567                    transition);
568            _foundUnknown = _foundUnknown || transitionRefersToUnknownInputs;
569            if (transition.isDefault()) {
570                if (_isTransitionEnabled(transition)) {
571                    defaultTransitions.add(transition);
572                }
573            } else {
574                if (_isTransitionEnabled(transition)) {
575                    enabledTransitions.add(transition);
576                }
577            }
578        }
579
580        // NOTE: It is the chooseTransition method that decides which
581        // enabled transition is actually taken. This method simply returns
582        // all enabled transitions.
583        if (enabledTransitions.size() > 0) {
584            if (_debugging) {
585                _debug("Enabled transitions: " + enabledTransitions);
586            }
587            return enabledTransitions;
588        } else {
589            // No enabled regular transitions. Check for default transitions.
590            // Default transitions cannot become enabled until all
591            // guard expressions can be evaluated.
592            if (!_foundUnknown) {
593                if (_debugging) {
594                    if (defaultTransitions.size() > 0) {
595                        _debug("Enabled default transitions: "
596                                + defaultTransitions);
597                    } else {
598                        _debug("No enabled transitions.");
599                    }
600                }
601                return defaultTransitions;
602            }
603        }
604        // No enabled transitions were found, but some are not yet
605        // known to disabled, so we cannot return a transition (even the
606        // default transition).
607        if (_debugging) {
608            _debug("No enabled transitions.");
609            if (_foundUnknown) {
610                _debug("(some are not known to be disabled).");
611            }
612        }
613        return new LinkedList();
614    }
615
616    /** Write this FSMActor into the output writer as a submodel. All
617     *  refinements of the events in this FSMActor will be exported as
618     *  configurations of those events, not as composite entities belonging to
619     *  the closest modal model.
620     *
621     *  @param output The output stream to write to.
622     *  @param depth The depth in the hierarchy, to determine indenting.
623     *  @param name The name to use in the exported MoML.
624     *  @exception IOException If an I/O error occurs.
625     */
626    public void exportSubmodel(Writer output, int depth, String name)
627            throws IOException {
628        try {
629            List<State> stateList = deepEntityList();
630            for (State state : stateList) {
631                state.saveRefinementsInConfigurer.setToken(BooleanToken.TRUE);
632            }
633            if (depth == 0 && getContainer() != null) {
634                output.write("<?xml version=\"1.0\" standalone=\"no\"?>\n"
635                        + "<!DOCTYPE " + _elementName + " PUBLIC "
636                        + "\"-//UC Berkeley//DTD MoML 1//EN\"\n"
637                        + "    \"http://ptolemy.eecs.berkeley.edu"
638                        + "/xml/dtd/MoML_1.dtd\">\n");
639            }
640            super.exportMoML(output, depth, name);
641        } catch (IllegalActionException ex) {
642            throw new InternalErrorException(this, ex,
643                    "Unable to set " + "attributes for the states.");
644        } finally {
645            List<State> stateList = deepEntityList();
646            for (State state : stateList) {
647                try {
648                    state.saveRefinementsInConfigurer
649                            .setToken(BooleanToken.FALSE);
650                } catch (IllegalActionException e) {
651                    // Ignore.
652                }
653            }
654        }
655    }
656
657    /** Set the values of input variables. Choose the enabled transition
658     *  among the outgoing transitions of the current state. Throw an
659     *  exception if there is more than one transition enabled.
660     *  Otherwise, execute the output actions contained by the chosen
661     *  transition.
662     *  @exception IllegalActionException If there is more than one
663     *   transition enabled.
664     */
665    @Override
666    public void fire() throws IllegalActionException {
667        if (_debugging) {
668            _debug("************ Firing FSM. Current state: "
669                    + _currentState.getName());
670        }
671        if (_firstFire) {
672            _schedule(_currentState, getDirector().getModelTime());
673            _firstFire = false;
674        }
675
676        Time environmentTime = _getEnvironmentTime();
677        Director director = getDirector();
678        boolean inModalModel = false;
679        if (director instanceof FSMDirector) {
680            inModalModel = true;
681            director.setModelTime(environmentTime);
682        }
683
684        readInputs();
685
686        // To support continuous-time models, we need to clear
687        // the list of chosen transitions because, during an
688        // iteration, the solver may backtrack, and transitions
689        // that were previously enabled in the iteration will
690        // no longer be enabled. Presumably, if the guards are
691        // still enabled, then the same transitions will be
692        // chosen again.
693        _lastChosenTransitions.clear();
694        _lastChosenTransition = null;
695
696        // Some outputs may have to be forced to be unknown
697        // if they are set on transitions that are not known
698        // to be enabled.
699        _outputsThatMustBeUnknown.clear();
700
701        // Keep track during firing of all refinements
702        // that are fired so that they can later be postfired.
703        _transitionRefinementsToPostfire.clear();
704        _stateRefinementsToPostfire.clear();
705
706        if (_debugging) {
707            _debug("** Checking preemptive transitions.");
708        }
709
710        // Choose transitions from the preemptive transitions,
711        // including any immediate transitions that these lead to.
712        List<Transition> transitionList = _currentState
713                .nonErrorNonTerminationTransitionList();
714
715        // The last argument ensures that we look at all transitions
716        // not just those that are marked immediate.
717        // Third to last argument ensures that we look only at preemptive transitions.
718        // The following has the side effect of putting the chosen
719        // transitions into the _lastChosenTransitions map of the controller.
720        _chooseTransitions(transitionList, true, false, false, false);
721
722        // If there is an enabled preemptive transition, then we know
723        // that the current refinements cannot generate outputs, so we
724        // may be able to assert that some outputs are absent.
725        if (_lastChosenTransitions.size() > 0) {
726            // In case the refinement port somehow accesses time, set it.
727            if (inModalModel) {
728                director.setModelTime(environmentTime);
729            }
730
731            // If the current (preempted) state has refinements, then
732            // we know they cannot produce any outputs. All outputs of
733            // this state must be cleared so that at least they do not
734            // remain unknown at the end of the fixed point iteration.
735            // If an output port is known because these preemptive
736            // transitions already set it we do not send a clear.
737            TypedActor[] refinements = _currentState.getRefinement();
738            if (refinements != null) {
739                for (Actor refinementActor : refinements) {
740                    if (refinementActor instanceof CompositeActor) {
741                        CompositeActor refinement = (CompositeActor) refinementActor;
742                        for (IOPort refinementPort : (List<IOPort>) refinement
743                                .outputPortList()) {
744                            for (int i = 0; i < refinementPort
745                                    .getWidth(); i++) {
746                                if (!refinementPort.isKnown(i)) {
747                                    if (_debugging) {
748                                        _debug("--- Asserting absent output on "
749                                                + refinementPort.getName()
750                                                + ", channel " + i);
751                                    }
752                                    refinementPort.sendClear(i);
753                                }
754                            }
755                        } // end for all ports
756                    } // end if CompositeActor
757                } // end for all refinements
758            } // end if has refinement
759        } else {
760            // ASSERT: At this point, there are no enabled preemptive transitions.
761            // It may be that some preemptive transition guards cannot be evaluated yet.
762            if (!foundUnknown()) {
763                // ASSERT: At this point, there are no enabled preemptive transitions,
764                // and all preemptive transition guards, if any, have evaluated to false.
765                // We can now fire the refinements.
766                Actor[] stateRefinements = _currentState.getRefinement();
767
768                if (stateRefinements != null) {
769                    try {
770                        for (int i = 0; i < stateRefinements.length; ++i) {
771                            if (_stopRequested || _disabledRefinements
772                                    .contains(stateRefinements[i])) {
773                                continue;
774                            }
775                            _setTimeForRefinement(stateRefinements[i]);
776                            if (stateRefinements[i].prefire()) {
777                                if (_debugging) {
778                                    _debug("Fire state refinement:",
779                                            stateRefinements[i].getName());
780                                }
781                                // NOTE: If the state refinement is an FSMActor, then the following
782                                // fire() method doesn't do the right thing. That fire() method does
783                                // much less than this fire() method, and in particular, does not
784                                // invoke refinements! This is fixed by using ModalModel in a
785                                // hierarchical state.
786                                if (_modelErrorHandled == null) {
787                                    stateRefinements[i].fire();
788                                    if (_modelErrorHandled == null) {
789                                        _stateRefinementsToPostfire
790                                                .add(stateRefinements[i]);
791                                    }
792                                }
793                            }
794                        }
795                    } catch (Throwable ex) {
796                        // Handle exceptions if there are error transitions.
797                        _chooseErrorTransition(ex);
798                        if (_lastChosenTransitions.size() > 0) {
799                            // An error transition was chosen. We are done.
800                            // Restore time before returning.
801                            if (inModalModel) {
802                                director.setModelTime(environmentTime);
803                            }
804                            return;
805                        }
806                        throw new IllegalActionException(this, ex,
807                                "Exception occurred executing refinement.");
808                    }
809                    if (_modelErrorHandled != null) {
810                        // A model error was thrown.
811                        // Note that if it was a model errors, then the transition
812                        // to take has already been identified in handleModelError().
813                        // However, we need to choose again so that the output actions
814                        // overwrite any outputs produced by the refinement.
815                        _chooseErrorTransition(_modelErrorHandled);
816                        // Restore time before returning.
817                        if (inModalModel) {
818                            director.setModelTime(environmentTime);
819                        }
820                        return;
821                    }
822                }
823                if (inModalModel) {
824                    director.setModelTime(environmentTime);
825                }
826                readOutputsFromRefinement();
827
828                // Choose transitions from the nonpreemptive transitions,
829                // including any immediate transitions that these lead to.
830                if (_debugging) {
831                    _debug("** Checking nonpreemptive transitions.");
832                }
833                // As a special case, if there are termination transitions
834                // and all refinements of the current state are FSM refinements,
835                // then we allow an termination transition to be chosen now if
836                // all refinements have reached a final state. Allowing this now
837                // means that the termination transition can produce outputs before
838                // postfire, which is essential in SR and Continuous domains.
839                List<Transition> terminationTransitions = _currentState
840                        .terminationTransitionList();
841                // Assume until proven otherwise that termination transitions should
842                // not be checked.
843                boolean checkTerminationTransitions = false;
844                if (terminationTransitions.size() > 0) {
845                    // There are termination transitions. Check the refinements.
846                    TypedActor[] refinements = _currentState.getRefinement();
847                    if (refinements != null && refinements.length > 0) {
848                        // There are refinements. Assume until proven
849                        // otherwise that termination transitions should be
850                        // checked.
851                        checkTerminationTransitions = true;
852                        for (Actor refinementActor : refinements) {
853                            if (refinementActor instanceof ModalRefinement) {
854                                // We will check the guards of termination transitions only
855                                // if all refinements are transitioning to a final state
856                                // or are already in a final state.
857                                ModalRefinement refinement = (ModalRefinement) refinementActor;
858                                FSMActor refinementController = refinement
859                                        .getController();
860                                State destinationState = refinementController
861                                        ._destinationState();
862                                // If the current state is not a final state and we are not transitioning
863                                // to a final state, then no termination transition can be enabled.
864                                if (!((BooleanToken) refinementController
865                                        .currentState().isFinalState.getToken())
866                                                .booleanValue()
867                                        && (destinationState == null
868                                                || !((BooleanToken) destinationState.isFinalState
869                                                        .getToken())
870                                                                .booleanValue())) {
871                                    // No chosen transition, or the destination
872                                    // state is not final.
873                                    // Cannot take termination transition.
874                                    checkTerminationTransitions = false;
875                                    break;
876                                }
877                            } else {
878                                checkTerminationTransitions = false;
879                                break;
880                            }
881                        }
882                    }
883                }
884
885                if (checkTerminationTransitions) {
886                    // The second to last argument ensures that we look at all transitions
887                    // not just those that are marked immediate.
888                    // The third from the last ensures that we look only at
889                    // non-preemptive transitions.
890                    _chooseTransitions(
891                            _currentState.nonpreemptiveTransitionList(), false,
892                            false, false, false);
893                } else {
894                    // The second to last argument ensures that we look at all transitions
895                    // not just those that are marked immediate.
896                    // The third from last ensures that we look only at
897                    // non-preemptive transitions.
898                    _chooseTransitions(transitionList, false, false, false,
899                            false);
900                }
901            }
902        }
903        // Finally, assert any absent outputs that can be asserted absent.
904        _assertAbsentOutputs(this);
905    }
906
907    /** Return true if the most recent call to enabledTransition()
908     *  or chooseTransition() found guard expressions or output value
909     *  expressions that could not be evaluated due to unknown inputs.
910     *  Specifically, after calling {@link #enabledTransitions(List, boolean, boolean)},
911     *  call this method to see whether there were guard expressions
912     *  in the specified list that could not be evaluated. After
913     *  calling
914     *  {@link #_chooseTransitions(List, boolean, boolean, boolean, boolean)},
915     *  call this to determine whether any guard expressions or output
916     *  value expressions on a transition whose guard evaluates to
917     *  true were found in the specified transition list that referred
918     *  to input ports that are not currently known.
919     *  @return True If guards or output value expressions could
920     *   not be evaluated.
921     */
922    public boolean foundUnknown() {
923        return _foundUnknown;
924    }
925
926    /** Return a causality interface for this actor. This
927     *  method returns an instance of class
928     *  {@link FSMCausalityInterface} if the enclosing director
929     *  returns true in its implementsStrictActorSemantics() method.
930     *  Otherwise, it returns an interface of class
931     *  {@link DefaultCausalityInterface}.
932     *  @return A representation of the dependencies between input ports
933     *   and output ports.
934     */
935    @Override
936    public CausalityInterface getCausalityInterface() {
937        Director director = getDirector();
938        Dependency defaultDependency = BooleanDependency.OTIMES_IDENTITY;
939        if (director != null) {
940            defaultDependency = director.defaultDependency();
941            if (!director.implementsStrictActorSemantics()) {
942                if (_causalityInterface != null
943                        && _causalityInterfaceDirector == director) {
944                    return _causalityInterface;
945                }
946                _causalityInterface = new DefaultCausalityInterface(this,
947                        defaultDependency);
948                _causalityInterfaceDirector = director;
949                return _causalityInterface;
950            }
951        }
952        boolean stateDependent = false;
953        try {
954            stateDependent = ((BooleanToken) stateDependentCausality.getToken())
955                    .booleanValue();
956        } catch (IllegalActionException ex) {
957            throw new InternalErrorException(this, ex,
958                    "Failed to get the value of the stateDependentCausality parameter.");
959        }
960        if (!stateDependent) {
961            if (_causalityInterface != null
962                    && _causalityInterfaceDirector == director) {
963                return _causalityInterface;
964            }
965            _causalityInterface = new FSMCausalityInterface(this,
966                    defaultDependency);
967            _causalityInterfaceDirector = director;
968            return _causalityInterface;
969        }
970        // We need to return a different causality interface for each state.
971        // Construct one for the current state if necessary.
972        if (_causalityInterfacesVersions == null) {
973            _causalityInterfacesVersions = new HashMap<State, Long>();
974            _causalityInterfaces = new HashMap<State, FSMCausalityInterface>();
975        }
976        Long version = _causalityInterfacesVersions.get(_currentState);
977        FSMCausalityInterface causality = _causalityInterfaces
978                .get(_currentState);
979        if (version == null || causality == null
980                || version.longValue() != workspace().getVersion()) {
981            // Need to create or update a causality interface for the current state.
982            causality = new FSMCausalityInterface(this, defaultDependency);
983            _causalityInterfaces.put(_currentState, causality);
984            _causalityInterfacesVersions.put(_currentState,
985                    Long.valueOf(workspace().getVersion()));
986        }
987        return causality;
988    }
989
990    /**
991     * Return the change context being made explicit.  This class returns
992     * this.
993     * @return The change context being made explicit
994     */
995    @Override
996    public Entity getContext() {
997        return this;
998    }
999
1000    /** Return the director responsible for the execution of this actor.
1001     *  In this class, this is always the executive director.
1002     *  Return null if either there is no container or the container has no
1003     *  director.
1004     *  @return The director that invokes this actor.
1005     */
1006    @Override
1007    public Director getDirector() {
1008        CompositeEntity container = (CompositeEntity) getContainer();
1009
1010        if (container instanceof CompositeActor) {
1011            return ((CompositeActor) container).getDirector();
1012        }
1013
1014        return null;
1015    }
1016
1017    /** Return the executive director (same as getDirector()).
1018     *  @return The executive director.
1019     */
1020    @Override
1021    public Director getExecutiveDirector() {
1022        return getDirector();
1023    }
1024
1025    /** Return the initial state of this actor. The initial state is
1026     *  the unique state with its <i>isInitialState</i> parameter set
1027     *  to true. An exception is thrown if this actor does not contain
1028     *  an initial state.
1029     *  This method is read-synchronized on the workspace.
1030     *  @return The initial state of this actor.
1031     *  @exception IllegalActionException If this actor does not contain
1032     *   a state with the specified name.
1033     */
1034    public State getInitialState() throws IllegalActionException {
1035        // For backward compatibility, if the initialStateName
1036        // parameter and has been given, then use it to determine
1037        // the initial state.
1038        String name = initialStateName.getExpression();
1039        if (!name.equals("")) {
1040            try {
1041                workspace().getReadAccess();
1042                State state = (State) getEntity(name);
1043                if (state == null) {
1044                    throw new IllegalActionException(this, "Cannot find "
1045                            + "initial state with name \"" + name + "\".");
1046                }
1047                state.isInitialState.setToken("true");
1048                state.isInitialState.setPersistent(true);
1049                _initialState = state;
1050                return _initialState;
1051            } finally {
1052                workspace().doneReading();
1053            }
1054        }
1055        if (_initialState == null) {
1056            throw new IllegalActionException(this,
1057                    "No initial state has been specified.");
1058        }
1059        return _initialState;
1060    }
1061
1062    /** Get the last chosen transition from the current state.
1063     *  Note that this does not include chosen immediate transitions
1064     *  from the destination of the returned transition.
1065     *  @return The last chosen transition from the current state.
1066     *  @deprecated Use {@link #getLastChosenTransitions()} instead.
1067     *  @see #setLastChosenTransition(Transition)
1068     */
1069    @Deprecated
1070    public Transition getLastChosenTransition() {
1071        return _lastChosenTransitions.get(currentState());
1072    }
1073
1074    /** Get the last chosen transitions.
1075     *  @return A map of last chosen transitions.
1076     *  @see #addChosenTransition(State,Transition)
1077     */
1078    public Map<State, Transition> getLastChosenTransitions() {
1079        return _lastChosenTransitions;
1080    }
1081
1082    /** Get the last taken transitions.
1083     *  @return A list of last taken transition.
1084     *  @see #setLastChosenTransition(Transition)
1085     */
1086    public List<Transition> getLastTakenTransitions() {
1087        return _lastTakenTransitions;
1088    }
1089
1090    /** Return the Manager responsible for execution of this actor,
1091     *  if there is one. Otherwise, return null.
1092     *  @return The manager.
1093     */
1094    @Override
1095    public Manager getManager() {
1096        try {
1097            _workspace.getReadAccess();
1098
1099            CompositeEntity container = (CompositeEntity) getContainer();
1100
1101            if (container instanceof CompositeActor) {
1102                return ((CompositeActor) container).getManager();
1103            }
1104
1105            return null;
1106        } finally {
1107            _workspace.doneReading();
1108        }
1109    }
1110
1111    /** Return a list of variables that this entity modifies.  The
1112     * variables are assumed to have a change context of the given
1113     * entity.  This method returns the destinations of all choice and
1114     * commit identifiers that are deeply contained by this actor.
1115     * Note that this actor is also used as the controller of modal
1116     * models and FSMDirector reports destinations of all choice and
1117     * commit identifiers, even those not contained by the finite
1118     * state machine.
1119     * @return A list of variables.
1120     * @exception IllegalActionException If a valid destination object can not
1121     * be found.
1122     * @see FSMDirector#getModifiedVariables()
1123     */
1124    @Override
1125    public List getModifiedVariables() throws IllegalActionException {
1126        List list = new LinkedList();
1127
1128        // Collect assignments from FSM transitions
1129        for (Iterator states = entityList().iterator(); states.hasNext();) {
1130            State state = (State) states.next();
1131
1132            for (Iterator transitions = state.outgoingPort.linkedRelationList()
1133                    .iterator(); transitions.hasNext();) {
1134                Transition transition = (Transition) transitions.next();
1135
1136                for (Iterator actions = transition.choiceActionList()
1137                        .iterator(); actions.hasNext();) {
1138                    AbstractActionsAttribute action = (AbstractActionsAttribute) actions
1139                            .next();
1140
1141                    for (Iterator names = action.getDestinationNameList()
1142                            .iterator(); names.hasNext();) {
1143                        String name = (String) names.next();
1144                        NamedObj object = action.getDestination(name);
1145
1146                        if (object instanceof Variable
1147                                && deepContains(object)) {
1148                            list.add(object);
1149                        }
1150                    }
1151                }
1152
1153                for (Iterator actions = transition.commitActionList()
1154                        .iterator(); actions.hasNext();) {
1155                    AbstractActionsAttribute action = (AbstractActionsAttribute) actions
1156                            .next();
1157
1158                    for (Iterator names = action.getDestinationNameList()
1159                            .iterator(); names.hasNext();) {
1160                        String name = (String) names.next();
1161                        NamedObj object = action.getDestination(name);
1162
1163                        if (object instanceof Variable
1164                                && deepContains(object)) {
1165                            list.add(object);
1166                        }
1167                    }
1168                }
1169            }
1170        }
1171
1172        return list;
1173    }
1174
1175    /** Return a scope object that has current values from input ports
1176     *  of this FSMActor in scope.  This scope is used to evaluate
1177     *  guard expressions and set and output actions.
1178     *  @return A scope object that has current values from input ports of
1179     *  this FSMActor in scope.
1180     */
1181    public ParserScope getPortScope() {
1182        // FIXME: this could be cached.
1183        return new PortScope();
1184    }
1185
1186    /** Handle a model error.
1187     *  @param context The object in which the error occurred.
1188     *  @param exception An exception that represents the error.
1189     *  @return True if the error has been handled, or false if the
1190     *   error is not handled.
1191     *  @exception IllegalActionException If the handler handles the
1192     *   error by throwing an exception.
1193     */
1194    @Override
1195    public boolean handleModelError(NamedObj context,
1196            IllegalActionException exception) throws IllegalActionException {
1197        _chooseErrorTransition(exception);
1198        if (_lastChosenTransitions.size() > 0) {
1199            // An error transition is enabled.
1200            // To prevent the model error from being passed up the hierarchy,
1201            // we have to return true. Set a flag so that the fire() method
1202            // knows about this.
1203            _modelErrorHandled = exception;
1204            return true;
1205        }
1206        // There is no error transition enabled.
1207        // Pass the model up the hierarchy.
1208        return false;
1209    }
1210
1211    /** Test whether new input tokens have been received at the input ports.
1212     *
1213     *  @return true if new input tokens have been received.
1214     */
1215    public boolean hasInput() {
1216        Iterator<?> inPorts = ((CompositeActor) getContainer()).inputPortList()
1217                .iterator();
1218        while (inPorts.hasNext() && !_stopRequested) {
1219            Port port = (Port) inPorts.next();
1220            if (hasInput(port)) {
1221                return true;
1222            }
1223        }
1224        return false;
1225    }
1226
1227    /** Test whether new input tokens have been received at the given input
1228     *  port.
1229     *
1230     *  @param port The input port.
1231     *  @return true if new input tokens have been received.
1232     */
1233    public boolean hasInput(Port port) {
1234        Token token = (Token) _inputTokenMap.get(port.getName() + "_isPresent");
1235        return token != null && BooleanToken.TRUE.equals(token);
1236    }
1237
1238    /** Initialize this actor by setting the current state to the
1239     *  initial state.
1240     *  @exception IllegalActionException If a derived class throws it.
1241     */
1242    @Override
1243    public void initialize() throws IllegalActionException {
1244
1245        if (_debugging) {
1246            _debug("************ Initializing FSM.");
1247        }
1248        // Ensure previous input values are not available.
1249        _inputTokenMap.clear();
1250        errorMessage.setExpression("");
1251        errorClass.setExpression("");
1252        errorCause.setToken((Token) null);
1253        _modelErrorHandled = null;
1254
1255        _transitionTaken = false;
1256
1257        _transitionEvaluatedTo.clear();
1258        _oldThreshold = 0.0;
1259
1260        // create generator
1261        if (_randomToken == null
1262                || ((BooleanToken) resetOnEachRun.getToken()).booleanValue()) {
1263            _createRandomGenerator();
1264        }
1265        _randomValue = _randomToken.nextDouble();
1266
1267        // First invoke initializable methods.
1268        if (_initializables != null) {
1269            for (Initializable initializable : _initializables) {
1270                initializable.initialize();
1271            }
1272        }
1273
1274        // Even though reset() is called in preinitialize(),
1275        // we have to call it again because if a reset transition is
1276        // taken, preinitialize() is not called.
1277        reset();
1278
1279        _timeOfNextTimeoutExpiration = null;
1280        _timeEnteredCurrentState = getDirector().getModelTime();
1281
1282        // Check for immediate transitions out of the initial state,
1283        // and also for any enabled transition (to request a refiring
1284        // at the current time.
1285        // NOTE: There is no current state when the FSMActor is in fact a Ptera
1286        // controller. (tfeng 05/12/2009)
1287        if (_currentState != null) {
1288            List transitionList = _currentState.outgoingPort
1289                    .linkedRelationList();
1290            if (_debugging) {
1291                _debug("** Checking immediate preemptive transitions.");
1292            }
1293            _chooseTransitions(transitionList, true, true, true, false);
1294            if (_lastChosenTransitions.size() > 0) {
1295                _transitionTaken = true;
1296            } else {
1297                if (_debugging) {
1298                    _debug("** Checking immediate non-preemptive transitions.");
1299                }
1300                _chooseTransitions(transitionList, false, true, true, false);
1301                if (_lastChosenTransitions.size() > 0) {
1302                    _transitionTaken = true;
1303                } else {
1304                    _transitionTaken = false;
1305                }
1306            }
1307            _commitLastChosenTransition(false, true);
1308            // Need to clear this again.
1309            _transitionsPreviouslyChosenInIteration.clear();
1310
1311            // If there is a non-immediate transition enabled in the initial state,
1312            // then request a refiring at the current time.
1313            try {
1314                // State may have changed. Get new transition list.
1315                transitionList = _currentState.outgoingPort
1316                        .linkedRelationList();
1317                // Check both preemptive and non-preemptive transitions.
1318                if (_debugging) {
1319                    _debug("** Checking preemptive transitions to see whether to request a firing at the current time.");
1320                }
1321                List enabledTransitions = enabledTransitions(transitionList,
1322                        true, false);
1323                if (_debugging) {
1324                    _debug("** Checking non-preemptive transitions to see whether to request a firing at the current time.");
1325                }
1326                enabledTransitions.addAll(
1327                        enabledTransitions(transitionList, false, false));
1328                if (enabledTransitions.size() > 0) {
1329                    if (_debugging) {
1330                        _debug("A transition from the initial state is enabled. FSMActor requesting refiring by at "
1331                                + getDirector().getModelTime());
1332                    }
1333                    getDirector().fireAtCurrentTime(this);
1334                }
1335            } catch (IllegalActionException ex) {
1336                // Guards cannot yet be evaluated. Ignore.
1337            }
1338        }
1339        _firstFire = true;
1340    }
1341
1342    /** Return a list of the input ports.
1343     *  This method is read-synchronized on the workspace.
1344     *  @return A list of input IOPort objects.
1345     */
1346    @Override
1347    public List inputPortList() {
1348        if (_inputPortsVersion != _workspace.getVersion()) {
1349            try {
1350                _workspace.getReadAccess();
1351
1352                // Update the cache.
1353                LinkedList inPorts = new LinkedList();
1354                Iterator ports = portList().iterator();
1355
1356                while (ports.hasNext()) {
1357                    IOPort p = (IOPort) ports.next();
1358
1359                    if (p.isInput()) {
1360                        inPorts.add(p);
1361                    }
1362                }
1363
1364                _cachedInputPorts = inPorts;
1365                _inputPortsVersion = _workspace.getVersion();
1366            } finally {
1367                _workspace.doneReading();
1368            }
1369        }
1370
1371        return _cachedInputPorts;
1372    }
1373
1374    /** Return false. During the fire() method, if a transition is enabled,
1375     *  it will be taken and the actions associated with this transition are
1376     *  executed. We assume the actions will change states of this actor.
1377     *
1378     *  @return False.
1379     */
1380    @Override
1381    public boolean isFireFunctional() {
1382        return false;
1383    }
1384
1385    /** Return true.
1386     *  @return True.
1387     */
1388    @Override
1389    public boolean isOpaque() {
1390        return true;
1391    }
1392
1393    /** Return false. This actor checks inputs to see whether
1394     *  they are known before evaluating guards, so it can fired
1395     *  even if it has unknown inputs.
1396     *  @return False.
1397     *  @exception IllegalActionException Not thrown in this base class.
1398     */
1399    @Override
1400    public boolean isStrict() throws IllegalActionException {
1401        return false;
1402        /* NOTE: This used to return a value as follows based
1403         * on the causality interface. But this is conservative
1404         * and prevents using the actor in some models.
1405        CausalityInterface causality = getCausalityInterface();
1406        int numberOfOutputs = outputPortList().size();
1407        Collection<IOPort> inputs = inputPortList();
1408        for (IOPort input : inputs) {
1409            // If the input is also output, skip it.
1410            // This is the output of a refinement.
1411            if (input.isOutput()) {
1412                continue;
1413            }
1414            try {
1415                if (causality.dependentPorts(input).size() < numberOfOutputs) {
1416                    return false;
1417                }
1418            } catch (IllegalActionException ex) {
1419                throw new InternalErrorException(this, ex,
1420                "Failed to get the dependent ports.");
1421            }
1422        }
1423        return true;
1424         */
1425    }
1426
1427    /** Invoke a specified number of iterations of the actor. An
1428     *  iteration is equivalent to invoking prefire(), fire(), and
1429     *  postfire(), in that order. In an iteration, if prefire()
1430     *  returns true, then fire() will be called once, followed by
1431     *  postfire(). Otherwise, if prefire() returns false, fire()
1432     *  and postfire() are not invoked, and this method returns
1433     *  NOT_READY. If postfire() returns false, then no more
1434     *  iterations are invoked, and this method returns STOP_ITERATING.
1435     *  Otherwise, it returns COMPLETED. If stop() is called while
1436     *  this is executing, then cease executing and return STOP_ITERATING.
1437     *
1438     *  @param count The number of iterations to perform.
1439     *  @return NOT_READY, STOP_ITERATING, or COMPLETED.
1440     *  @exception IllegalActionException If iterating is not
1441     *   permitted, or if prefire(), fire(), or postfire() throw it.
1442     */
1443    @Override
1444    public int iterate(int count) throws IllegalActionException {
1445        int n = 0;
1446
1447        while (n++ < count && !_stopRequested) {
1448            if (prefire()) {
1449                fire();
1450
1451                if (!postfire()) {
1452                    return STOP_ITERATING;
1453                }
1454            } else {
1455                return NOT_READY;
1456            }
1457        }
1458
1459        if (_stopRequested) {
1460            return Executable.STOP_ITERATING;
1461        } else {
1462            return Executable.COMPLETED;
1463        }
1464    }
1465
1466    /** Create a new TypedIOPort with the specified name.
1467     *  The container of the port is set to this actor.
1468     *  This method is write-synchronized on the workspace.
1469     *
1470     *  @param name The name for the new port.
1471     *  @return The new port.
1472     *  @exception NameDuplicationException If the actor already has a port
1473     *   with the specified name.
1474     */
1475    @Override
1476    public Port newPort(String name) throws NameDuplicationException {
1477        try {
1478            _workspace.getWriteAccess();
1479
1480            //TypedIOPort p = new TypedIOPort(this, name);
1481            //return p;
1482            return new TypedIOPort(this, name);
1483        } catch (IllegalActionException ex) {
1484            // This exception should not occur.
1485            throw new InternalErrorException(this, ex,
1486                    "Failed to create a port named \"" + name + "\"");
1487        } finally {
1488            _workspace.doneWriting();
1489        }
1490    }
1491
1492    /** Return a new receiver obtained from the director.
1493     *  @exception IllegalActionException If there is no director.
1494     *  @return A new object implementing the Receiver interface.
1495     */
1496    @Override
1497    public Receiver newReceiver() throws IllegalActionException {
1498        Director director = getDirector();
1499
1500        if (director == null) {
1501            throw new IllegalActionException(this,
1502                    "Cannot create a receiver without a director.");
1503        }
1504
1505        return director.newReceiver();
1506    }
1507
1508    /** Create a new instance of Transition with the specified name in
1509     *  this actor, and return it.
1510     *  This method is write-synchronized on the workspace.
1511     *  @param name The name of the new transition.
1512     *  @return A transition with the given name.
1513     *  @exception IllegalActionException If the name argument is null.
1514     *  @exception NameDuplicationException If name collides with that
1515     *   of a transition already in this actor.
1516     */
1517    @Override
1518    public ComponentRelation newRelation(String name)
1519            throws IllegalActionException, NameDuplicationException {
1520        try {
1521            workspace().getWriteAccess();
1522
1523            //Director director = getDirector();
1524            Transition tr = new Transition(this, name);
1525            return tr;
1526        } finally {
1527            workspace().doneWriting();
1528        }
1529    }
1530
1531    /** Return a list of the output ports.
1532     *  This method is read-synchronized on the workspace.
1533     *  @return A list of output IOPort objects.
1534     */
1535    @Override
1536    public List outputPortList() {
1537        if (_outputPortsVersion != _workspace.getVersion()) {
1538            try {
1539                _workspace.getReadAccess();
1540                _cachedOutputPorts = new LinkedList();
1541
1542                Iterator ports = portList().iterator();
1543
1544                while (ports.hasNext()) {
1545                    IOPort p = (IOPort) ports.next();
1546
1547                    if (p.isOutput()) {
1548                        _cachedOutputPorts.add(p);
1549                    }
1550                }
1551
1552                _outputPortsVersion = _workspace.getVersion();
1553            } finally {
1554                _workspace.doneReading();
1555            }
1556        }
1557
1558        return _cachedOutputPorts;
1559    }
1560
1561    /** Execute actions on the last chosen transition. Change state
1562     *  to the destination state of the last chosen transition.
1563     *  @return True, unless stop() has been called, in which case, false.
1564     *  @exception IllegalActionException If any action throws it.
1565     */
1566    @Override
1567    public boolean postfire() throws IllegalActionException {
1568        if (_debugging) {
1569            _debug("************ Postfiring FSM.");
1570        }
1571
1572        Director director = getDirector();
1573        boolean inModalModel = false;
1574        if (director instanceof FSMDirector) {
1575            inModalModel = true;
1576        }
1577
1578        // First, postfire any state refinements that were fired.
1579        Time environmentTime = _getEnvironmentTime();
1580        for (Actor stateRefinement : _stateRefinementsToPostfire) {
1581            if (_debugging) {
1582                _debug("Postfiring state refinment:",
1583                        stateRefinement.getName());
1584            }
1585            _setTimeForRefinement(stateRefinement);
1586            if (!stateRefinement.postfire()) {
1587                _disabledRefinements.add(stateRefinement);
1588                // It is not correct for the modal model to return false
1589                // just because the refinement doesn't want to be fired anymore.
1590                // result = false;
1591            }
1592            if (inModalModel) {
1593                director.setModelTime(environmentTime);
1594            }
1595        }
1596        // Suspend all refinements of the current state, whether they were fired
1597        // or not. This is important because if a preemptive transition was taken,
1598        // then the refinement was not fired, but it should still be suspended.
1599        Actor[] refinements = _currentState.getRefinement();
1600        if (refinements != null) {
1601            for (Actor stateRefinement : refinements) {
1602                Director refinementDirector = stateRefinement.getDirector();
1603                if (_lastChosenTransitions.size() != 0
1604                        && refinementDirector != director) {
1605                    refinementDirector.suspend();
1606                }
1607            }
1608        }
1609
1610        // Check for termination transitions.
1611        if (refinements != null && refinements.length > 0
1612                && _disabledRefinements.size() == refinements.length) {
1613            // All refinements have terminated. If no other
1614            // transition is enabled, see whether there is a termination transition.
1615            if (_lastChosenTransitions.size() == 0) {
1616                // Choose transitions from the termination transitions,
1617                // including any immediate transitions that these lead to.
1618                List<Transition> transitionList = _currentState
1619                        .terminationTransitionList();
1620                // The second last argument ensures that we look at all transitions
1621                // not just those that are marked immediate.
1622                // Third from last argument ensures that we look only at non-preemptive transitions.
1623                // The following has the side effect of putting the chosen
1624                // transitions into the _lastChosenTransitions map of the controller.
1625                _chooseTransitions(transitionList, false, false, false, false);
1626            }
1627        }
1628
1629        // Notify all the refinements of the destination state that they are being
1630        // resumed.
1631        if (_lastChosenTransitions.size() != 0) {
1632            _transitionTaken = true;
1633            State destinationState = _destinationState();
1634            if (destinationState != null) {
1635                TypedActor[] destinationRefinements = destinationState
1636                        .getRefinement();
1637                if (destinationRefinements != null) {
1638                    for (TypedActor destinationRefinement : destinationRefinements) {
1639                        Director refinementDirector = destinationRefinement
1640                                .getDirector();
1641                        if (refinementDirector != director) {
1642                            refinementDirector.resume();
1643                        }
1644                    }
1645                }
1646            }
1647        } else {
1648            _transitionTaken = false;
1649        }
1650
1651        // To ensure that nondeterministic transitions result in the
1652        // same choice anytime during an iteration, but that different
1653        // choices can be made in subsequent transitions, clear the
1654        // set of previously chosen transitions.
1655        _transitionsPreviouslyChosenInIteration.clear();
1656
1657        // Commit transitions on the _lastChosenTransitions map.
1658        _commitLastChosenTransition(false, false);
1659
1660        // Postfire any transition refinements that were fired in fire().
1661        for (Actor transitionRefinement : _transitionRefinementsToPostfire) {
1662            if (_debugging) {
1663                _debug("Postfiring transition refinment:",
1664                        transitionRefinement.getName());
1665            }
1666            if (!transitionRefinement.postfire()) {
1667                _disabledRefinements.add(transitionRefinement);
1668                // It is not correct for the modal model to return false
1669                // just because the refinement doesn't want to be fired anymore.
1670                // result = false;
1671            }
1672        }
1673
1674        // Ensure previous input values are not available.
1675        _inputTokenMap.clear();
1676        errorMessage.setExpression("");
1677        errorClass.setExpression("");
1678        errorCause.setToken((Token) null);
1679        _modelErrorHandled = null;
1680
1681        // generate a new random token for the next transition to be taken
1682
1683        _transitionEvaluatedTo.clear();
1684        _oldThreshold = 0.0;
1685        _randomValue = _randomToken.nextDouble();
1686
1687        if (_debugging) {
1688            _debug("** Finished postfire. New random number is :"
1689                    + _randomValue);
1690        }
1691
1692        return !_reachedFinalState && !_stopRequested;
1693    }
1694
1695    /** Return true.
1696     *  @return True.
1697     *  @exception IllegalActionException Not thrown in this base class.
1698     */
1699    @Override
1700    public boolean prefire() throws IllegalActionException {
1701        return true;
1702    }
1703
1704    /** Create receivers and input variables for the input ports of
1705     *  this actor, and validate attributes of this actor, and
1706     *  attributes of the ports of this actor. Set current state to
1707     *  the initial state.
1708     *  @exception IllegalActionException If this actor does not contain an
1709     *   initial state.
1710     */
1711    @Override
1712    public void preinitialize() throws IllegalActionException {
1713        // First invoke initializable methods.
1714        if (_initializables != null) {
1715            for (Initializable initializable : _initializables) {
1716                initializable.preinitialize();
1717            }
1718        }
1719
1720        _stopRequested = false;
1721        _reachedFinalState = false;
1722
1723        _newIteration = true;
1724        _tokenListArrays = new Hashtable();
1725
1726        _inputTokenMap.clear();
1727        errorMessage.setExpression("");
1728        errorClass.setExpression("");
1729        errorCause.setToken((Token) null);
1730        _modelErrorHandled = null;
1731
1732        // In case any further static analysis depends on the initial
1733        // state, reset to that state here. For example, HDF sets
1734        // the production/consumption rates based on the refinement
1735        // of the initial state.
1736        reset();
1737
1738        // The actual initial state may depend on immediate transitions
1739        // out of the initial state, and those transitions may set
1740        // relevant variables, so we have to traverse them here.
1741        // NOTE: There is no current state when the FSMActor is in fact a Ptera
1742        // controller. (tfeng 05/12/2009)
1743        if (_currentState != null) {
1744            List transitionList = _currentState.outgoingPort
1745                    .linkedRelationList();
1746            if (_debugging) {
1747                _debug("** Checking immediate preemptive transitions.");
1748            }
1749            _chooseTransitions(transitionList, true, true, true, true);
1750            if (_lastChosenTransitions.size() == 0) {
1751                if (_debugging) {
1752                    _debug("** Checking immediate non-preemptive transitions.");
1753                }
1754                _chooseTransitions(transitionList, false, true, true, true);
1755            }
1756            // NOTE: Have to be very careful here. This needs
1757            // to be an incomplete commit in that it cannot
1758            // initialize the destination refinement nor produce
1759            // outputs, because we are in preinitialize().
1760            // The destination refinement hasn't been preinitialized
1761            // yet.  See HDF Fibonnaci demo.
1762            _commitLastChosenTransition(true, true);
1763            // Need to clear this again.
1764            _transitionsPreviouslyChosenInIteration.clear();
1765        }
1766    }
1767
1768    /** Set the value of the shadow variables for input ports of this actor.
1769     *  This method skips over ports that connected to outputs of a refinement.
1770     *  @exception IllegalActionException If a shadow variable cannot take
1771     *   the token read from its corresponding channel (should not occur).
1772     */
1773    public void readInputs() throws IllegalActionException {
1774        Iterator inPorts = inputPortList().iterator();
1775
1776        while (inPorts.hasNext() && !_stopRequested) {
1777            IOPort p = (IOPort) inPorts.next();
1778            int width = p.getWidth();
1779
1780            for (int channel = 0; channel < width; ++channel) {
1781                if (!_isRefinementOutput(p, channel)) {
1782                    _readInputs(p, channel);
1783                }
1784            }
1785        }
1786    }
1787
1788    /** Set the input variables for channels that are connected to an
1789     *  output port of the refinement of current state.
1790     *  @exception IllegalActionException If a value variable cannot take
1791     *   the token read from its corresponding channel.
1792     */
1793    public void readOutputsFromRefinement() throws IllegalActionException {
1794        Iterator inPorts = inputPortList().iterator();
1795
1796        while (inPorts.hasNext() && !_stopRequested) {
1797            IOPort p = (IOPort) inPorts.next();
1798            int width = p.getWidth();
1799
1800            for (int channel = 0; channel < width; ++channel) {
1801                if (_isRefinementOutput(p, channel)) {
1802                    _readInputs(p, channel);
1803                }
1804            }
1805        }
1806    }
1807
1808    /** Remove the specified object from the list of objects whose
1809     *  preinitialize(), initialize(), and wrapup()
1810     *  methods should be invoked upon invocation of the corresponding
1811     *  methods of this object. If the specified object is not
1812     *  on the list, do nothing.
1813     *  @param initializable The object whose methods should no longer be invoked.
1814     *  @see #addInitializable(Initializable)
1815     *  @see ptolemy.actor.CompositeActor#removePiggyback(Executable)
1816     */
1817    @Override
1818    public void removeInitializable(Initializable initializable) {
1819        if (_initializables != null) {
1820            _initializables.remove(initializable);
1821            if (_initializables.size() == 0) {
1822                _initializables = null;
1823            }
1824        }
1825    }
1826
1827    /** Reset current state to the initial state.
1828     *  @exception IllegalActionException If thrown while
1829     *  getting the initial state or setting the current connection map.
1830     */
1831    public void reset() throws IllegalActionException {
1832        _reachedFinalState = false;
1833        _newIteration = true;
1834        _currentState = getInitialState();
1835        if (_debugging && _currentState != null) {
1836            _debug("Resetting to initial state: " + _currentState.getName());
1837        }
1838        _setCurrentConnectionMap();
1839
1840        // To ensure that nondeterministic transitions result in the
1841        // same choice anytime during an iteration, but that different
1842        // choices can be made in subsequent transitions, clear the
1843        // set of previously chosen transitions.
1844        _transitionsPreviouslyChosenInIteration.clear();
1845
1846        // Although this will be cleared at the start of fire(),
1847        // we need to clear it here as well before we potentially
1848        // choose immediate transitions.
1849        _lastChosenTransitions.clear();
1850        _lastChosenTransition = null;
1851
1852        // Clear the list of refinements whose postfire() methods
1853        // have returned false.
1854        _disabledRefinements.clear();
1855
1856        _transitionEvaluatedTo.clear();
1857        _oldThreshold = 0.0;
1858
1859    }
1860
1861    /** Set the last chosen transition. Note that this erases
1862     *  any previously set chosen transitions and makes the specified
1863     *  transition the only chosen transition, ignoring immediate
1864     *  transitions that this might lead to.
1865     *  @param transition The last chosen transition.
1866     *  @deprecated Use addChosenTransition(State, Transition)
1867     *  @see #getLastChosenTransition()
1868     */
1869    @Deprecated
1870    public void setLastChosenTransition(Transition transition) {
1871        _lastChosenTransitions.clear();
1872        _lastChosenTransition = null;
1873        if (transition != null) {
1874            _lastChosenTransitions.put(currentState(), transition);
1875            _lastChosenTransition = transition;
1876        }
1877    }
1878
1879    /** Set the flag indicating whether we are at the start of
1880     *  a new iteration (firing).  Normally, the flag is set to true.
1881     *  It is only set to false in HDF.
1882     *  @param newIteration A boolean variable indicating whether this is
1883     *  a new iteration.
1884     */
1885    public void setNewIteration(boolean newIteration) {
1886        _newIteration = newIteration;
1887    }
1888
1889    /** Set true indicating that this actor supports multirate firing.
1890     *  @param supportMultirate A boolean variable indicating whether this
1891     *  actor supports multirate firing.
1892     */
1893    public void setSupportMultirate(boolean supportMultirate) {
1894        _supportMultirate = supportMultirate;
1895    }
1896
1897    /** Request that execution of the current iteration stop as soon
1898     *  as possible.  In this class, we set a flag indicating that
1899     *  this request has been made (the protected variable _stopRequested).
1900     *  This will result in postfire() returning false.
1901     */
1902    @Override
1903    public void stop() {
1904        _stopRequested = true;
1905    }
1906
1907    /** Do nothing.
1908     */
1909    @Override
1910    public void stopFire() {
1911    }
1912
1913    /** Call stop().
1914     */
1915    @Override
1916    public void terminate() {
1917        stop();
1918    }
1919
1920    /** Return the type constraints of this actor. The constraints
1921     *  have the form of a set of inequalities. This method first
1922     *  creates constraints such that the type of any input port that
1923     *  does not have its type declared must be less than or equal to
1924     *  the type of any output port that does not have its type
1925     *  declared. Type constraints from the contained Typeables
1926     *  (ports, variables, and parameters) are collected. In addition,
1927     *  type constraints from all the transitions are added. These
1928     *  constraints are determined by the guard and trigger expressions
1929     *  of transitions, and actions contained by the transitions.
1930     *  This method is read-synchronized on the workspace.
1931     *  @return A list of inequalities.
1932     *  @see ptolemy.graph.Inequality
1933     */
1934    @Override
1935    public Set<Inequality> typeConstraints() {
1936        try {
1937            _workspace.getReadAccess();
1938
1939            Set<Inequality> result = new HashSet<Inequality>();
1940
1941            // Collect constraints from contained Typeables.
1942            Iterator ports = portList().iterator();
1943
1944            while (ports.hasNext()) {
1945                Typeable port = (Typeable) ports.next();
1946                result.addAll(port.typeConstraints());
1947            }
1948
1949            // Collect constraints from contained HasTypeConstraints
1950            // attributes.
1951            Iterator attributes = attributeList(HasTypeConstraints.class)
1952                    .iterator();
1953
1954            while (attributes.hasNext()) {
1955                HasTypeConstraints typeableAttribute = (HasTypeConstraints) attributes
1956                        .next();
1957                result.addAll(typeableAttribute.typeConstraints());
1958            }
1959
1960            // Collect constraints from all transitions.
1961            Iterator transitionRelations = relationList().iterator();
1962
1963            while (transitionRelations.hasNext()) {
1964                Relation tr = (Relation) transitionRelations.next();
1965                attributes = tr.attributeList(HasTypeConstraints.class)
1966                        .iterator();
1967
1968                while (attributes.hasNext()) {
1969                    HasTypeConstraints typeableAttribute = (HasTypeConstraints) attributes
1970                            .next();
1971                    result.addAll(typeableAttribute.typeConstraints());
1972                }
1973            }
1974
1975            return result;
1976        } finally {
1977            _workspace.doneReading();
1978        }
1979    }
1980
1981    /** Return true if a transition was taken in the previous
1982     *  iteration, or if this is before the first iteration concludes,
1983     *  true if during initialize an immediate transition was taken.
1984     *  @return True if a transition was taken.
1985     */
1986    public boolean wasTransitionTaken() {
1987        return _transitionTaken;
1988    }
1989
1990    /** Do nothing except invoke the wrapup method of any objects
1991     *  that have been added using addInitializable().
1992     *  Derived classes override this method to define
1993     *  operations to be performed exactly once at the end of a complete
1994     *  execution of an application.  It typically closes
1995     *  files, displays final results, etc.
1996     *
1997     *  @exception IllegalActionException Not thrown in this base class.
1998     */
1999    @Override
2000    public void wrapup() throws IllegalActionException {
2001        // First invoke initializable methods.
2002        if (_initializables != null) {
2003            for (Initializable initializable : _initializables) {
2004                initializable.wrapup();
2005            }
2006        }
2007    }
2008
2009    ///////////////////////////////////////////////////////////////////
2010    ////                         public variables                  ////
2011
2012    /** Attribute specifying the names of the final states of this
2013     *  actor. This attribute is kept for backward compatibility only,
2014     *  and is set to expert visibility. To set the final states,
2015     *  set the <i>isFinalState</i> parameter of a States.
2016     */
2017    public StringAttribute finalStateNames = null;
2018
2019    /** Attribute specifying the name of the initial state of this
2020     *  actor. This attribute is kept for backward compatibility only,
2021     *  and is set to expert visibility. To set the initial state,
2022     *  set the <i>isInitialState</i> parameter of a State.
2023     */
2024    public StringAttribute initialStateName = null;
2025
2026    /** Indicate whether input/output dependencies can depend on the
2027     *  state. By default, this is false (the default), indicating that a conservative
2028     *  dependency is provided by the causality interface. Specifically,
2029     *  if there is a dependency in any state, then the causality interface
2030     *  indicates that there is a dependency. If this is true, then a less
2031     *  conservative dependency is provided, indicating a dependency only
2032     *  if there can be one in the current state.  If this is true, then
2033     *  upon any state transition, this actor issues a change request, which
2034     *  forces causality analysis to be redone. Note that this can be expensive.
2035     */
2036    public Parameter stateDependentCausality;
2037
2038    ///////////////////////////////////////////////////////////////////
2039    ////                         protected methods                 ////
2040
2041    /** Add a state to this FSMActor. This overrides the base-class
2042     *  method to make sure the argument is an instance of State.
2043     *  This method is <i>not</i> synchronized on the workspace, so the
2044     *  caller should be.
2045     *
2046     *  @param entity State to contain.
2047     *  @exception IllegalActionException If the state has no name, or the
2048     *   action would result in a recursive containment structure, or the
2049     *   argument is not an instance of State.
2050     *  @exception NameDuplicationException If the name collides with a name
2051     *   already on the state list.
2052     */
2053    @Override
2054    protected void _addEntity(ComponentEntity entity)
2055            throws IllegalActionException, NameDuplicationException {
2056        if (!(entity instanceof State)) {
2057            throw new IllegalActionException(this, entity,
2058                    "FSMActor can only contain entities that "
2059                            + "are instances of State or Mode.");
2060        }
2061
2062        super._addEntity(entity);
2063    }
2064
2065    /** Add a transition to this FSMActor. This method should not be used
2066     *  directly.  Call the setContainer() method of the transition instead.
2067     *  This method does not set the container of the transition to refer
2068     *  to this container. This method is <i>not</i> synchronized on the
2069     *  workspace, so the caller should be.
2070     *
2071     *  @param relation Transition to contain.
2072     *  @exception IllegalActionException If the transition has no name, or
2073     *   is not an instance of Transition.
2074     *  @exception NameDuplicationException If the name collides with a name
2075     *   already on the contained transitions list.
2076     */
2077    @Override
2078    protected void _addRelation(ComponentRelation relation)
2079            throws IllegalActionException, NameDuplicationException {
2080        if (!(relation instanceof Transition)) {
2081            throw new IllegalActionException(this, relation,
2082                    "FSMActor can only contain instances of Transition.");
2083        }
2084
2085        super._addRelation(relation);
2086
2087        if (_debugging) {
2088            relation.addDebugListener(new StreamListener());
2089        }
2090    }
2091
2092    /** Return true if all immediate transitions from
2093     *  the specified state have guards that can be evaluated
2094     *  and that evaluate to false. Note that this will return
2095     *  true if there are no immediate transitions.
2096     *  @param state The state to check for immediate transitions.
2097     *  @return true If there are no immediate transitions or if
2098     *   they are all disabled.
2099     * @exception IllegalActionException If the guard expression cannot be parsed
2100     *  or if it cannot yet be evaluated.
2101     */
2102    protected boolean _areAllImmediateTransitionsDisabled(State state)
2103            throws IllegalActionException {
2104        List<Transition> transitionList = state.outgoingPort
2105                .linkedRelationList();
2106        for (Transition transition : transitionList) {
2107            if (transition.isImmediate()) {
2108                if (!_referencedInputPortsByGuardKnown(transition)) {
2109                    return false;
2110                }
2111                if (_isTransitionEnabled(transition)) {
2112                    return false;
2113                }
2114            }
2115        }
2116        return true;
2117    }
2118
2119    /** Choose zero or more transitions enabled in the current
2120     *  state from the list of specified transitions. This method
2121     *  follows chains of immediate transitions, if there are any.
2122     *  As a side effect, the controller's _lastChosenTransitions
2123     *  protected variable will contain the chosen transitions.
2124     *  @param transitionList The candidate transitions.
2125     *  @param preemptive True to consider only preemptive transitions,
2126     *   and false to consider only non-preemptive transitions.
2127     *  @param immediateOnly If true, look only at immediate
2128     *   transitions from the current state. Otherwise, look
2129     *   at both immediate and non-immediate transitions.
2130     *  @param inInitialize True when this method is called
2131     *   from initialize or preinitialize, in which case, firing and initializing
2132     *   refinements is not allowed; note that the refinements
2133     *   will be initialized by the initialize method, but this
2134     *   prevents them from being initialized more than once.
2135     *   This could be important if, for example, the refinement
2136     *   produces an output during initialize in a domain where
2137     *   outputs are consumed, such as SDF.
2138     *  @param inPreinitialize True if this is being called in
2139     *   preinitialize. Outputs must not be produced in preinitialize,
2140     *   so we don't execute output actions if this argument is true.
2141     *  @exception IllegalActionException If something goes wrong.
2142     */
2143    protected void _chooseTransitions(List<Transition> transitionList,
2144            boolean preemptive, boolean immediateOnly, boolean inInitialize,
2145            boolean inPreinitialize) throws IllegalActionException {
2146        Transition chosenTransition = _chooseTransition(_currentState,
2147                transitionList, preemptive, immediateOnly, inInitialize,
2148                inPreinitialize);
2149
2150        // A self-loop that is immediate is not allowed, because if it is enabled,
2151        // it implied an infinite number of traversals.
2152        if (chosenTransition != null && chosenTransition.isImmediate()
2153                && chosenTransition.destinationState() == _currentState) {
2154            throw new IllegalActionException(_currentState, this,
2155                    "Self loop cannot be an immediate transition.");
2156        }
2157
2158        // The destination of the chosen transition may be transient,
2159        // so we should also choose transitions on the destination state.
2160        // The following set is used
2161        // to detect cycles of immediate transitions.
2162        // NOTE: cmot, should the visitedStates not be part of the fire function and reset
2163        // once a normal transition is taken? Maybe a fire method is called twice and that
2164        // would hide an immediate cycle (because visitedStates is reset for the second call). Both
2165        // calls and consecutive ones may happen in the same fixed point iteration.
2166        // NOTE: eal, No, this seems OK to me. A repeated firing will choose at least
2167        // the same transitions. The repeated firing also starts from the same _currentState.
2168        HashSet<State> visitedStates = new HashSet<State>();
2169        while (chosenTransition != null) {
2170            State nextState = chosenTransition.destinationState();
2171            if (visitedStates.contains(nextState)) {
2172                throw new IllegalActionException(nextState, this,
2173                        "Cycle of immediate transitions found.");
2174            }
2175            visitedStates.add(nextState);
2176
2177            transitionList = nextState.outgoingPort.linkedRelationList();
2178            // The last argument ensures that we look only at transitions
2179            // that are marked immediate.
2180            if (_debugging) {
2181                _debug("** Checking for immediate transitions out of the next state: "
2182                        + nextState.getName());
2183            }
2184
2185            // Try preemptive transitions first, then non-preemptive.
2186            chosenTransition = _chooseTransition(nextState, transitionList,
2187                    true, true, inInitialize, inPreinitialize);
2188            if (chosenTransition == null) {
2189                // Only try non-preemptive transitions if no preemptive transition
2190                // is enabled.
2191                chosenTransition = _chooseTransition(nextState, transitionList,
2192                        false, true, inInitialize, inPreinitialize);
2193            }
2194        }
2195    }
2196
2197    /** Fire all refinements of the state if it has any refinements.
2198     *  @exception IllegalActionException If any commit action throws it,
2199     *   or the last chosen transition does not have a destination state.
2200     */
2201    private void _fireStateRefinements(State state)
2202            throws IllegalActionException {
2203        // Execute state refinement here: If the chosenTransition is not null and weak,
2204        // and the current state has a refinement, we need to fire it
2205        Actor[] stateRefinements = state.getRefinement();
2206        if (stateRefinements != null && stateRefinements.length > 0) {
2207            // ASSERT: At this point, there are no enabled preemptive transitions,
2208            // and all preemptive transition guards, if any, have evaluated to false.
2209            // We can now fire the refinements.
2210            for (int i = 0; i < stateRefinements.length; ++i) {
2211                if (_stopRequested
2212                        || _disabledRefinements.contains(stateRefinements[i])) {
2213                    break;
2214                }
2215                _setTimeForRefinement(stateRefinements[i]);
2216                if (stateRefinements[i].prefire()) {
2217                    if (_debugging) {
2218                        _debug("Fire transient state refinement:",
2219                                stateRefinements[i].getName());
2220                    }
2221                    // NOTE: If the state refinement is an FSMActor, then the following
2222                    // fire() method doesn't do the right thing. That fire() method does
2223                    // much less than this fire() method, and in particular, does not
2224                    // invoke refinements! This is fixed by using ModalModel in a
2225                    // hierarchical state.
2226                    stateRefinements[i].fire();
2227                    _stateRefinementsToPostfire.add(stateRefinements[i]);
2228                }
2229            }
2230        }
2231    }
2232
2233    /** Return the chosen destination state. This method follows
2234     *  the chain of chosen transitions from the current state
2235     *  to the new state, possibly traversing several immediate
2236     *  transitions.
2237     *  @return The state that will be the current state after
2238     *   all chosen transitions are taken, or null if there are no
2239     *   chosen transitions.
2240     * @exception IllegalActionException If no controller is found.
2241     */
2242    protected State _destinationState() throws IllegalActionException {
2243        Transition chosenTransition = _lastChosenTransitions.get(_currentState);
2244        if (chosenTransition == null) {
2245            return null;
2246        }
2247        State destinationState = chosenTransition.destinationState();
2248        Transition nextTransition = _lastChosenTransitions
2249                .get(destinationState);
2250        while (nextTransition != null) {
2251            State newDestinationState = nextTransition.destinationState();
2252            if (newDestinationState == destinationState) {
2253                // Found a self loop.
2254                return destinationState;
2255            }
2256            nextTransition = _lastChosenTransitions.get(newDestinationState);
2257
2258        }
2259        return destinationState;
2260    }
2261
2262    /** Given an identifier, return a channel number i if the identifier is of
2263     *  the form portName_i, portName_i_isPresent, portName_iArray.
2264     *  Otherwise, return -1.
2265     *  @param identifier An identifier.
2266     *  @return A channel index, if the identifier refers to one.
2267     *  @exception IllegalActionException If getting the width of the port fails.
2268     */
2269    protected int _getChannelForIdentifier(String identifier)
2270            throws IllegalActionException {
2271        Port port = _getPortForIdentifier(identifier);
2272        if (port != null) {
2273            String portName = port.getName();
2274            if (identifier.startsWith(portName + "_")) {
2275                String channel = identifier.substring(portName.length() + 1);
2276                if (channel.endsWith("Array")) {
2277                    channel = channel.substring(0, channel.length() - 5);
2278                }
2279                if (channel.endsWith("isPresent")) {
2280                    channel = channel.substring(0, channel.length() - 9);
2281                }
2282                // Apparently, the syntax has been variably name_index_isPresent
2283                // and name_indexisPresent (without the second underscore).
2284                // Tolerate both syntaxes.
2285                if (channel.endsWith("_")) {
2286                    channel = channel.substring(0, channel.length() - 1);
2287                }
2288                if (channel.length() > 0) {
2289                    return Integer.decode(channel);
2290                }
2291            }
2292        }
2293        return -1;
2294    }
2295
2296    /** Get the port for the specified identifier, which may be of
2297     *  form portName, portName_isPresent, portName_i, portName_i_isPresent,
2298     *  etc.
2299     *  @param identifier The specified identifier.
2300     *  @return The port that corresponds with the specified identifier.
2301     *  @exception IllegalActionException If getting the width of the port fails.
2302     */
2303    protected IOPort _getPortForIdentifier(String identifier)
2304            throws IllegalActionException {
2305        if (workspace().getVersion() != _identifierToPortVersion) {
2306            _setIdentifierToPort();
2307            _identifierToPortVersion = workspace().getVersion();
2308        }
2309        return _identifierToPort.get(identifier);
2310    }
2311
2312    /** Return the list used to keep track of refinements that have been
2313     *  fired. This is protected so that FSMDirector can mirror it with
2314     *  its own protected method so that subclasses of FSMDirector can
2315     *  access it.
2316     *  @return A list of actors to postfire.
2317     */
2318    protected List<Actor> _getStateRefinementsToPostfire() {
2319        return _stateRefinementsToPostfire;
2320    }
2321
2322    /** Return the list used to keep track of refinements that have been
2323     *  fired. This is protected so that FSMDirector can mirror it with
2324     *  its own protected method so that subclasses of FSMDirector can
2325     *  access it.
2326     *  @return A list of actors to postfire.
2327     */
2328    protected List<Actor> _getTransitionRefinementsToPostfire() {
2329        return _transitionRefinementsToPostfire;
2330    }
2331
2332    /** Initialize the refinements of the specified state.
2333     *  @param state The state.
2334     *  @exception IllegalActionException If initialization fails.
2335     */
2336    protected void _initializeRefinements(State state)
2337            throws IllegalActionException {
2338        Actor[] actors = state.getRefinement();
2339        if (actors != null) {
2340            Director executiveDirector = getExecutiveDirector();
2341            for (int i = 0; i < actors.length; ++i) {
2342                if (_debugging) {
2343                    _debug(getFullName() + " initialize refinement: "
2344                            + ((NamedObj) actors[i]).getName());
2345                }
2346                // NOTE: For a modal model, the executive director will normally
2347                // be an FSMDirector. Here we communicate with that director
2348                // to ensure that it reports the correct superdense time index
2349                // during initialization, which is one greater than the current
2350                // superdense index of its context. If the enclosing director
2351                // is not an FSMDirector, then the initialize() method below
2352                // will likely set the index to one less than it should be.
2353                // I don't have a solution for this, but this situation is
2354                // unlikely to arise except in very weird models, since the
2355                // standard pattern is for FSMDirector and FSMActor to work
2356                // together.
2357                if (executiveDirector instanceof FSMDirector) {
2358                    try {
2359                        ((FSMDirector) executiveDirector)._indexOffset = 1;
2360                        actors[i].initialize();
2361                    } finally {
2362                        ((FSMDirector) executiveDirector)._indexOffset = 0;
2363                    }
2364                    _disabledRefinements.remove(actors[i]);
2365                } else {
2366                    actors[i].initialize();
2367                }
2368            }
2369        }
2370    }
2371
2372    /** Return true if the channel of the port is connected to an output
2373     *  port of the refinement of current state. If the current state
2374     *  does not have refinement, return false.
2375     *  @param port An input port of this actor.
2376     *  @param channel A channel of the input port.
2377     *  @return True if the channel of the port is connected to an output
2378     *   port of the refinement of current state.
2379     *  @exception IllegalActionException If the refinement specified for
2380     *   one of the states is not valid.
2381     */
2382    protected boolean _isRefinementOutput(IOPort port, int channel)
2383            throws IllegalActionException {
2384        // Ptera may not have a _currentState.
2385        if (_currentState == null) {
2386            return false;
2387        }
2388        TypedActor[] refinements = _currentState.getRefinement();
2389
2390        if (refinements == null || refinements.length == 0) {
2391            return false;
2392        }
2393
2394        if (_connectionMapsVersion != workspace().getVersion()) {
2395            _setCurrentConnectionMap();
2396        }
2397
2398        boolean[] flags = (boolean[]) _currentConnectionMap.get(port);
2399        return flags[channel];
2400    }
2401
2402    /** Given an output port and channel, determine whether the
2403     *  output port must be absent on the specified channel, given whatever
2404     *  current information about the inputs is available (the inputs
2405     *  may be known or unknown).
2406     *  <p>
2407     *  The way this works is that it examines all the outgoing
2408     *  transitions of the current state. If the guard on the transition
2409     *  can be evaluated to false, then as far as this transition is
2410     *  concerned, the output port can be absent.
2411     *  Otherwise, two things happen. First, we check to see whether
2412     *  the output actions of a transition writes to the specified
2413     *  port. Second, we look at the destination state of the
2414     *  transition and examine all immediate transition emanating
2415     *  from that state. If none of the transitions makes an assignment
2416     *  to the output port, then we can safely
2417     *  assert that the output is absent, with one exception.
2418     *  If the output port already has a value, that value was probably
2419     *  set by another refinement. Thus, we should leave it alone.
2420     *  <p>
2421     *  This method ignores any state refinements, and consequently
2422     *  its analysis is valid only if all state refinements also assert
2423     *  that the output is absent.
2424     *
2425     *  @param port The IOPort in question.
2426     *  @param channel The channel in question.
2427     *  @param state The state whose transitions are examined.
2428     *  @param immediateOnly True to examine only immediate transitions.
2429     *  @param visitedStates The set of states already visited, or null
2430     *   if none have yet been visited.
2431     *  @return True, if successful.
2432     *  @exception IllegalActionException If we cannot determine whether
2433     *   the port is known and absent.
2434     */
2435    protected boolean _isSafeToClear(IOPort port, int channel, State state,
2436            boolean immediateOnly, HashSet<State> visitedStates)
2437            throws IllegalActionException {
2438        if (_debugging) {
2439            _debug("Calling _isSafeToClear() on port: " + port.getFullName());
2440        }
2441
2442        // If this FSMActor is inside a refinement, then it's possible
2443        // that another refinement wants to set the value of an output port.
2444        // We need to allow it to.
2445        if (getContainer() instanceof RefinementActor) {
2446            // Check to see whether the output port destinations are known.
2447            if (port.isKnown(channel)) {
2448                // Check to see whether the destinations are present.
2449                // Can't use port.hasToken(channel) to determine whether the
2450                // know value is absent because this is not an input port.
2451                // Have to traverse to the destinations to find out.
2452                Receiver[][] receivers = port.getRemoteReceivers();
2453
2454                if (receivers.length <= channel) {
2455                    throw new IllegalActionException(this,
2456                            "Channel index is out of range: " + channel);
2457                }
2458
2459                // Presumably, if one destination has a token, then they all
2460                // should. This assumes we are inside modal model
2461                if (receivers[channel] != null) {
2462                    for (int j = 0; j < receivers[channel].length; j++) {
2463                        if (!receivers[channel][j].hasToken()) {
2464                            return false;
2465                        }
2466                    }
2467                }
2468            }
2469        }
2470
2471        List<Transition> transitionList = state.outgoingPort
2472                .linkedRelationList();
2473        for (Transition transition : transitionList) {
2474
2475            _transitionBeingTested = transition;
2476            if (immediateOnly && !transition.isImmediate()) {
2477                // Skip the transition.
2478                continue;
2479            }
2480            // Next check to see whether the transition can be
2481            // evaluated to false. This will throw an exception
2482            // if there is not enough information to evaluate
2483            // the guard.
2484            try {
2485                if (!transition.isEnabled()) {
2486                    // Transition is assured of not being
2487                    // enabled, so we can ignore it.
2488                    continue;
2489                }
2490            } catch (IllegalActionException ex) {
2491                // Guard cannot be evaluated. Therefore,
2492                // we have to check it.
2493            }
2494            // ASSERT: Either the guard cannot be evaluated
2495            // or it evaluates to true at this point.
2496
2497            // First, recursively check immediate transitions
2498            // emanating from the destination state.
2499            State destinationState = transition.destinationState();
2500            // Guard against cycles!!
2501            if (visitedStates == null) {
2502                visitedStates = new HashSet<State>();
2503                visitedStates.add(state);
2504            }
2505            if (!visitedStates.contains(destinationState)) {
2506                visitedStates.add(destinationState);
2507                // Have not checked the destination state. Check it now.
2508                // The "true" argument asks for only immediate transitions to be checked.
2509                if (!_isSafeToClear(port, channel, destinationState, true,
2510                        visitedStates)) {
2511                    // An immediate transition somewhere downstream may
2512                    // assign a value to the port, so it is not safe
2513                    // to clear the port.
2514                    return false;
2515                }
2516            }
2517            // ASSERT: At this point, the transition may be
2518            // enabled (now or later), and all downstream immediate
2519            // transitions assert that as far as they are concerned,
2520            // the port is safe to clear. So now, we should check
2521            // to see whether this transition assigns a value to the
2522            // port.
2523
2524            // FIXME: The implementation should not re-parse the output
2525            // actions and get the information from the parsed AST.
2526            // This code already exists somewhere... Where?
2527            String outputActionsExpression = transition.outputActions
2528                    .getExpression();
2529            String regexp = "(^|((.|\\s)*\\W))" + port.getName()
2530                    + "\\s*=[^=](.|\\s)*";
2531            boolean transitionWritesToThePort = outputActionsExpression.trim()
2532                    .matches(regexp);
2533
2534            if (transitionWritesToThePort) {
2535                // The transition does include an assignement to the port, so
2536                // it is not safe to clear the port.
2537                return false;
2538            }
2539        } // Continue to the next transition.
2540
2541        // ASSERT: At this point, no transition can possibly write
2542        // to the output, so it is safe to clear.
2543        return true;
2544    }
2545
2546    /** Read tokens from the given channel of the given input port and
2547     *  make them accessible to the expressions of guards and
2548     *  transitions through the port scope.  If the specified port is
2549     *  not an input port, then do nothing.
2550     *  @param port An input port of this actor.
2551     *  @param channel A channel of the input port.
2552     *  @exception IllegalActionException If the port is not contained by
2553     *   this actor.
2554     */
2555    protected void _readInputs(IOPort port, int channel)
2556            throws IllegalActionException {
2557        String portName = port.getName();
2558
2559        if (port.getContainer() != this) {
2560            throw new IllegalActionException(this, port,
2561                    "Cannot read inputs from port "
2562                            + "not contained by this FSMActor.");
2563        }
2564
2565        if (!port.isInput()) {
2566            return;
2567        }
2568
2569        // Do not overwrite the port if it already has a token.
2570        // This is essential for he imperative behavior of multiple
2571        // refinements.
2572        if (port.isKnown(channel)) {
2573            if (_supportMultirate) {
2574                // FIXME: The following implementation to support multirate is
2575                // rather expensive. Try to optimize it.
2576
2577                // FIXME: This does not look right. It reads all available tokens.
2578                // Shouldn't it read exactly the number to consume?
2579                // It could end up consuming tokens that will be needed on a
2580                // subsequent firing!
2581                int width = port.getWidth();
2582
2583                // If we're in a new iteration, reallocate arrays to keep
2584                // track of HDF data.
2585                if (_newIteration && channel == 0) {
2586                    List[] tokenListArray = new LinkedList[width];
2587
2588                    for (int i = 0; i < width; i++) {
2589                        tokenListArray[i] = new LinkedList();
2590                    }
2591
2592                    _tokenListArrays.put(port, tokenListArray);
2593                }
2594
2595                // Get the list of tokens for the given port.
2596                List[] tokenListArray = (LinkedList[]) _tokenListArrays
2597                        .get(port);
2598
2599                // Update the value variable if there is/are token(s) in
2600                // the channel. The HDF(SDF) schedule will guarantee there
2601                // are always enough tokens.
2602                // Limit the number of tokens read to the consumption rate
2603                // of the port, which by default is 1. If the MultirateFSMDirector
2604                // is used, however, it may set the consumption rate other than one.
2605                int numberOfTokensToRead = DFUtilities
2606                        .getTokenConsumptionRate(port);
2607                int count = 0;
2608                while (port.hasNewToken(channel)
2609                        && count < numberOfTokensToRead) {
2610                    Token token = port.get(channel);
2611                    count++;
2612
2613                    if (_debugging) {
2614                        _debug("---", port.getName(), "(" + channel + ") has ",
2615                                token.toString() + " at time "
2616                                        + getDirector().getModelTime());
2617                    }
2618
2619                    tokenListArray[channel].add(0, token);
2620                }
2621
2622                int length = tokenListArray[channel].size();
2623                if (_debugging) {
2624                    _debug("Total tokens available at port: "
2625                            + port.getFullName() + " is  " + length);
2626                }
2627
2628                if (length > 0) {
2629                    Token[] tokens = new Token[length];
2630                    tokenListArray[channel].toArray(tokens);
2631                    _setInputTokenMap(port, channel, tokens[0], tokens);
2632                } else {
2633                    // There is no data. Just set the _isPresent variables to false.
2634                    _setInputTokenMap(port, channel, null, null);
2635                }
2636            } else {
2637                // If not supporting multirate firing,
2638                // Update the value variable if there is a token in the channel.
2639                if (port.hasToken(channel)) {
2640                    Token token = port.get(channel);
2641
2642                    if (_debugging) {
2643                        _debug("---", port.getName(), "(" + channel + ") has ",
2644                                token.toString() + " at time "
2645                                        + getDirector().getModelTime());
2646                    }
2647                    _setInputTokenMap(port, channel, token, null);
2648                } else {
2649                    // There is no data. Check to see whether the token
2650                    // map has been previously set, and if not,
2651                    // set the _isPresent variables to false.
2652                    // NOTE: The test will only work if the _inputTokenMap is reset
2653                    // between iterations. Ptera does not do this!!!
2654                    // if (_inputTokenMap.get(portName + "_isPresent") == null) {
2655                    if (_debugging) {
2656                        _debug("---", port.getName(), "(" + channel + ") has ",
2657                                "no tokens at time "
2658                                        + getDirector().getModelTime());
2659                    }
2660                    _setInputTokenMap(port, channel, null, null);
2661                    // }
2662                }
2663            }
2664        } else {
2665            // Remove identifiers so that previous values are not erroneously
2666            // read.
2667            _removePortVariables(portName, channel);
2668        }
2669    }
2670
2671    /** Set the map from input ports to boolean flags indicating whether a
2672     *  channel is connected to an output port of the refinement of the
2673     *  current state.
2674     *  @exception IllegalActionException If the refinement specified
2675     *   for one of the states is not valid.
2676     */
2677    protected void _setCurrentConnectionMap() throws IllegalActionException {
2678        if (_connectionMapsVersion != workspace().getVersion()) {
2679            _buildConnectionMaps();
2680        }
2681
2682        _currentConnectionMap = (Map) _connectionMaps.get(_currentState);
2683    }
2684
2685    /** Set the refinements current time equal to the matching environment,
2686     *  or if there is no environment, do nothing.
2687     *  @param refinement The refinement.
2688     *  @exception IllegalActionException If setModelTime() throws it.
2689     */
2690    protected void _setTimeForRefinement(Actor refinement)
2691            throws IllegalActionException {
2692        Actor container = (Actor) getContainer();
2693        Director director = getDirector();
2694        if (!(director instanceof FSMDirector)) {
2695            throw new IllegalActionException(this,
2696                    "State refinements are only supported within ModalModel.");
2697        }
2698        Director executiveDirector = container.getExecutiveDirector();
2699        if (executiveDirector != null) {
2700            Time environmentTime = executiveDirector.getModelTime();
2701            /* FIXME: This is now handled by the director.
2702            Director refinementDirector = refinement.getDirector();
2703            if (refinementDirector instanceof Suspendable && refinementDirector != director) {
2704                // Adjust current time to be the environment time minus
2705                // the accumulated suspended time of the refinement.
2706                Time suspendedTime = ((Suspendable) refinementDirector)
2707                        .accumulatedSuspendTime();
2708                if (suspendedTime != null) {
2709                    director.setModelTime(environmentTime.subtract(suspendedTime));
2710                    ((FSMDirector)director)._currentOffset = suspendedTime;
2711                    return;
2712                }
2713            }
2714             */
2715            director.setModelTime(environmentTime);
2716        }
2717    }
2718
2719    ///////////////////////////////////////////////////////////////////
2720    ////                         protected fields                  ////
2721
2722    /** Current state. */
2723    protected State _currentState = null;
2724
2725    /** State and transition refinements that have returned false in postfire(). */
2726    protected Set<Actor> _disabledRefinements = new HashSet<Actor>();
2727
2728    /** List of objects whose (pre)initialize() and wrapup() methods
2729     *  should be slaved to these.
2730     */
2731    protected transient List<Initializable> _initializables;
2732
2733    /** A map from ports to corresponding input variables. */
2734    protected Map _inputTokenMap = new HashMap();
2735
2736    /** The most recently chosen transition within the fire() method. */
2737    protected Transition _lastChosenTransition;
2738
2739    /** The last chosen transitions, by state from which these transitions emerge. */
2740    protected HashMap<State, Transition> _lastChosenTransitions = new HashMap<State, Transition>();
2741
2742    /** The last taken transitions, by state from which these transitions emerge. */
2743    protected List<Transition> _lastTakenTransitions = new LinkedList<Transition>();
2744
2745    /** State refinements to postfire(), as determined by the fire() method. */
2746    protected List<Actor> _stateRefinementsToPostfire = new LinkedList<Actor>();
2747
2748    /** Indicator that a stop has been requested by a call to stop(). */
2749    protected boolean _stopRequested = false;
2750
2751    ///////////////////////////////////////////////////////////////////
2752    ////                package friendly variables                 ////
2753
2754    /** The initial state. This is package friendly so that State can
2755     *  access it.
2756     */
2757    State _initialState = null;
2758
2759    ///////////////////////////////////////////////////////////////////
2760    ////                         private methods                   ////
2761
2762    /**
2763     * For the given controller FSM, set all outputs that are
2764     * currently unknown to absent if it
2765     * can be determined to be absent given the current state and possibly
2766     * partial information about the inputs (some of the inputs may be
2767     * unknown). If the current state has any refinements that are not
2768     * FSMs, then return false. It is not safe to assert absent outputs
2769     * because we have no visibility into what those refinements do with
2770     * the outputs.
2771     * <p>
2772     * This method first explores any FSM refinements of the current
2773     * state. If those refinements are all FSMs and they are all able
2774     * to assert that an output is absent, then explore this FSM
2775     * to determine whether it also can assert that the output is absent.
2776     * If all the refinements and the specified FSM agree that an
2777     * output is absent, then this method sets it to absent.
2778     * Otherwise, it leaves it unknown.
2779     * <p>
2780     * In addition, if any port is listed in _outputsThatMustBeUnknown,
2781     * then that output is forced to be unkown, regardless of its
2782     * previous state.
2783     *
2784     * @param controller The controller FSM.
2785     * @return True if after this method is called, any output port is absent.
2786     * @exception IllegalActionException If something goes wrong.
2787     */
2788    private boolean _assertAbsentOutputs(FSMActor controller)
2789            throws IllegalActionException {
2790        // First, if any output port must be forced to be unknown,
2791        // do so here. We have to be careful to not make these same
2792        // ports known later.
2793        for (IOPort port : controller._outputsThatMustBeUnknown.keySet()) {
2794            // Get the channel number.
2795            int i = controller._outputsThatMustBeUnknown.get(port).intValue();
2796            _forceUnknownOutput(port, i);
2797        }
2798
2799        // First check the refinements.
2800        TypedActor[] refinements = controller._currentState.getRefinement();
2801        if (refinements != null) {
2802            for (Actor refinementActor : refinements) {
2803                Director refinementDirector = refinementActor.getDirector();
2804
2805                // The second check below guards against a refinement with no director.
2806                if (refinementDirector instanceof FSMDirector
2807                        && refinementDirector != getDirector()) {
2808                    // The refinement is an FSM, so we perform must/may analysis
2809                    // to identify outputs that can be determined to be absent.
2810                    FSMActor refinementController = ((FSMDirector) refinementDirector)
2811                            .getController();
2812                    if (!_assertAbsentOutputs(refinementController)) {
2813                        // The refinement has no absent outputs (they are all either
2814                        // unknown or present), therefore we cannot assert any outputs
2815                        // to be absent at this level either.
2816                        return false;
2817                    }
2818                } else {
2819                    // Refinement is not an FSM. We can't say anything about
2820                    // outputs.
2821                    return false;
2822                }
2823            }
2824        }
2825        // At this point, either there are no refinements, or all refinements
2826        // are FSMs, those refinements have asserted at least one output
2827        // to be absent.
2828
2829        boolean foundAbsentOutputs = false;
2830        if (getContainer() instanceof ModalModel) {
2831            // Inside a modal model.
2832            // We now iterate over all output ports of the container
2833            // of this director, and for each such output port p,
2834            // on each channel c,
2835            // if all the refinements and the controller FSM agree that
2836            // p on c is absent, then we assert it to be absent.
2837            Actor container = (Actor) getContainer();
2838            List<IOPort> outputs = container.outputPortList();
2839            if (outputs.size() == 0) {
2840                // There are no outputs, so in effect, all outputs
2841                // are absent !!
2842                return true;
2843            }
2844            for (IOPort port : outputs) {
2845                IOPort[] refinementPorts = null;
2846                if (refinements != null) {
2847                    refinementPorts = new IOPort[refinements.length];
2848                    int i = 0;
2849                    for (TypedActor refinement : refinements) {
2850                        refinementPorts[i++] = (IOPort) ((Entity) refinement)
2851                                .getPort(port.getName());
2852                    }
2853                }
2854                for (int channel = 0; channel < port
2855                        .getWidthInside(); channel++) {
2856                    // If the channel is known, we don't need to do any
2857                    // further checks.
2858                    if (!port.isKnownInside(channel)) {
2859                        // First check whether all refinements agree that the channel is
2860                        // absent.
2861                        boolean channelIsAbsent = true;
2862                        if (refinementPorts != null) {
2863                            for (int i = 0; i < refinementPorts.length; i++) {
2864                                // Note that _transferOutputs(refinementPorts[i]
2865                                // has not been called, or the inside of port would
2866                                // be known and we would not be here. Hence, we
2867                                // have to check the inside of this refinement port.
2868                                if (refinementPorts[i] != null
2869                                        && channel < refinementPorts[i]
2870                                                .getWidthInside()
2871                                        && (!refinementPorts[i]
2872                                                .isKnownInside(channel)
2873                                                || refinementPorts[i]
2874                                                        .hasTokenInside(
2875                                                                channel))) {
2876                                    // A refinement has either unknown or non-absent
2877                                    // output. Give up on this channel. It cannot be
2878                                    // asserted absent.
2879                                    channelIsAbsent = false;
2880                                    break;
2881                                }
2882                            }
2883                        }
2884                        if (!channelIsAbsent) {
2885                            // A refinement has either unknown or non-absent
2886                            // output. Give up on this channel. It cannot be
2887                            // asserted absent.
2888                            break;
2889                        }
2890                        // If we get here, all refinements (if any) agree that
2891                        // the current channel of the current port is absent. See
2892                        // whether this controller FSM also agrees.
2893                        IOPort controllerPort = (IOPort) controller
2894                                .getPort(port.getName());
2895                        // NOTE: If controllerPort is null, then presumably we should
2896                        // be able to set the output port to absent, but how to do that?
2897                        // We can't do it by sending null from controllerPort, because
2898                        // there is no controllerPort!
2899                        if (controllerPort != null) {
2900                            channelIsAbsent = controller._isSafeToClear(
2901                                    controllerPort, channel,
2902                                    controller._currentState, false, null);
2903                            if (channelIsAbsent) {
2904                                Integer channelThatMustBeUnknown = controller._outputsThatMustBeUnknown
2905                                        .get(controllerPort);
2906                                if (channelThatMustBeUnknown == null
2907                                        || channelThatMustBeUnknown
2908                                                .intValue() != channel) {
2909                                    foundAbsentOutputs = true;
2910                                    controllerPort.send(channel, null);
2911                                    if (_debugging) {
2912                                        _debug("Asserting absent output: "
2913                                                + port.getName()
2914                                                + ", on channel " + channel);
2915                                    }
2916                                }
2917                            }
2918                        }
2919                    } else {
2920                        if (!port.hasTokenInside(channel)) {
2921                            foundAbsentOutputs = true;
2922                        }
2923                    }
2924                }
2925            }
2926        } else {
2927            // Not inside a modal model.
2928            List<IOPort> outputs = outputPortList();
2929            for (IOPort port : outputs) {
2930                for (int channel = 0; channel < port.getWidth(); channel++) {
2931                    if (_isSafeToClear(port, channel, _currentState, false,
2932                            null)) {
2933                        if (_debugging) {
2934                            _debug("Asserting absent output: " + port.getName()
2935                                    + ", on channel " + channel);
2936                        }
2937                        Integer channelThatMustBeUnknown = controller._outputsThatMustBeUnknown
2938                                .get(port);
2939                        if (channelThatMustBeUnknown == null
2940                                || channelThatMustBeUnknown
2941                                        .intValue() != channel) {
2942                            // Send absent.
2943                            port.send(channel, null);
2944                            foundAbsentOutputs = true;
2945                            if (_debugging) {
2946                                _debug("Asserting absent output: "
2947                                        + port.getName() + ", on channel "
2948                                        + channel);
2949                            }
2950                        }
2951                    }
2952                }
2953            }
2954        }
2955
2956        // Return true if any output channel is absent.
2957        return foundAbsentOutputs;
2958    }
2959
2960    /*  Build for each state a map from input ports to boolean flags
2961     *  indicating whether a channel is connected to an output port
2962     *  of the refinement of the state.
2963     *  This method is read-synchronized on the workspace.
2964     *  @exception IllegalActionException If the refinement specified
2965     *   for one of the states is not valid.
2966     */
2967    private void _buildConnectionMaps() throws IllegalActionException {
2968        try {
2969            workspace().getReadAccess();
2970
2971            if (_connectionMaps == null) {
2972                _connectionMaps = new HashMap();
2973            } else {
2974                // Remove any existing maps.
2975                _connectionMaps.clear();
2976            }
2977
2978            // Create a map for each state.
2979            Iterator states = entityList().iterator();
2980            State state = null;
2981
2982            while (states.hasNext()) {
2983                state = (State) states.next();
2984
2985                Map stateMap = new HashMap();
2986                TypedActor[] actors = state.getRefinement();
2987
2988                // Determine the boolean flags for each input port.
2989                Iterator inPorts = inputPortList().iterator();
2990
2991                while (inPorts.hasNext()) {
2992                    IOPort inPort = (IOPort) inPorts.next();
2993                    boolean[] flags = new boolean[inPort.getWidth()];
2994
2995                    if (actors == null || actors.length == 0) {
2996                        java.util.Arrays.fill(flags, false);
2997                        stateMap.put(inPort, flags);
2998                        continue;
2999                    }
3000
3001                    Iterator relations = inPort.linkedRelationList().iterator();
3002                    int channelIndex = 0;
3003
3004                    while (relations.hasNext()) {
3005                        IORelation relation = (IORelation) relations.next();
3006                        boolean linked = false;
3007
3008                        for (int i = 0; i < actors.length; ++i) {
3009                            Iterator outports = actors[i].outputPortList()
3010                                    .iterator();
3011
3012                            while (outports.hasNext()) {
3013                                IOPort outport = (IOPort) outports.next();
3014                                linked = linked | outport.isLinked(relation);
3015                            }
3016                        }
3017
3018                        for (int j = 0; j < relation.getWidth(); ++j) {
3019                            flags[channelIndex + j] = linked;
3020                        }
3021
3022                        channelIndex += relation.getWidth();
3023                    }
3024
3025                    stateMap.put(inPort, flags);
3026                }
3027
3028                _connectionMaps.put(state, stateMap);
3029            }
3030
3031            _connectionMapsVersion = workspace().getVersion();
3032        } finally {
3033            workspace().doneReading();
3034        }
3035    }
3036
3037    /** Choose an error transition to handle the specified exception,
3038     *  if there is one. As a side effect, this will set
3039     *  _lastChosenTransitions.
3040     *  @param ex The exception.
3041     *  @exception IllegalActionException If something goes wrong.
3042     */
3043    private void _chooseErrorTransition(Throwable ex)
3044            throws IllegalActionException {
3045        if (_currentState != null) {
3046            List<Transition> errorTransitionList = _currentState
3047                    .errorTransitionList();
3048            if (errorTransitionList.size() > 0) {
3049                if (_debugging) {
3050                    _debug("** Exception occurred executing refinement. Checking error transitions.");
3051                }
3052                // Set variables exposing the exception.
3053                // Escape any $ in the error message.
3054                String message = (ex.getMessage().replaceAll("\\$", "\\$\\$"));
3055                errorMessage.setExpression(message);
3056                errorClass.setExpression(ex.getClass().getName());
3057                if (ex instanceof KernelException) {
3058                    Nameable cause = ((KernelException) ex).getNameable1();
3059                    if (cause != null) {
3060                        errorCause.setToken(
3061                                new ObjectToken(cause, cause.getClass()));
3062                    }
3063                }
3064
3065                // It makes no sense for error transitions to be preemptive,
3066                // so we look only at non-preemptive error transitions.
3067                _chooseTransitions(errorTransitionList, false, false, false,
3068                        false);
3069            }
3070        }
3071    }
3072
3073    /** Return an enabled transition among the given list of transitions
3074     *  for which both the guard expression and the output actions can
3075     *  be evaluated (the inputs referred by these are known).
3076     *  If there is only one transition enabled, return that transition.
3077     *  In case there are multiple enabled transitions, if any of
3078     *  them is not marked nondeterministic, throw an exception.
3079     *  Otherwise, randomly choose one from the enabled transitions
3080     *  and return it if the output actions can be evaluated.
3081     *  Execute the output actions contained by the returned
3082     *  transition before returning. Also, fire the transition
3083     *  refinements, if any, and the refinements of any transient
3084     *  states.
3085     *  <p>
3086     *  After calling this method, you can call foundUnknown()
3087     *  to determine whether any guard expressions or output value
3088     *  expressions on a transition whose guard evaluates to true
3089     *  were found in the specified transition list that
3090     *  referred to input ports that are not currently known.
3091     *  @param currentState The state from which transitions are examined.
3092     *  @param transitionList A list of transitions.
3093     *  @param preemptive True to consider only preemptive transitions,
3094     *   false to consider only non-preemptive transitions.
3095     *  @param immediateOnly True to consider only immediate transitions,
3096     *   false to consider both immediate and non-immediate transitions.
3097     *  @param inInitialize True when this method is called
3098     *   from initialize or preinitialize, in which case, firing and initializing
3099     *   refinements is not allowed; note that the refinements
3100     *   will be initialized by the initialize method, but this
3101     *   prevents them from being initialized more than once.
3102     *   This could be important if, for example, the refinement
3103     *   produces an output during initialize in a domain where
3104     *   outputs are consumed, such as SDF.
3105     *  @param inPreinitialize True if this is being called in
3106     *   preinitialize. Outputs must not be produced in preinitialize,
3107     *   so we don't execute output actions if this argument is true.
3108     *  @return An enabled transition, or null if none is enabled.
3109     *  @exception IllegalActionException If there is more than one
3110     *   transition enabled and not all of them are nondeterministic.
3111     */
3112    private Transition _chooseTransition(State currentState,
3113            List transitionList, boolean preemptive, boolean immediateOnly,
3114            boolean inInitialize, boolean inPreinitialize)
3115            throws IllegalActionException {
3116
3117        // Get the transitions enabled from the current state.
3118        List<Transition> enabledTransitions = enabledTransitions(transitionList,
3119                preemptive, immediateOnly);
3120        int numberOfEnabledTransitions = enabledTransitions.size();
3121
3122        Transition chosenTransition = null;
3123
3124        if (numberOfEnabledTransitions == 1) {
3125            chosenTransition = enabledTransitions.get(0);
3126            // Record the chosen transition.
3127            _transitionsPreviouslyChosenInIteration.add(chosenTransition);
3128        } else if (numberOfEnabledTransitions > 1) {
3129            // Ensure that if there are multiple enabled transitions, all of them
3130            // are nondeterministic.
3131            for (Transition enabledTransition : enabledTransitions) {
3132                if (!enabledTransition.isNondeterministic()) {
3133                    // Construct an informative error message.
3134                    StringBuffer enabled = new StringBuffer();
3135                    for (Transition transition : enabledTransitions) {
3136                        if (enabled.length() == 0) {
3137                            enabled.append("{");
3138                        } else {
3139                            enabled.append(", ");
3140                        }
3141                        enabled.append(transition.getName());
3142                    }
3143                    enabled.append("}");
3144                    throw new MultipleEnabledTransitionsException(currentState,
3145                            "Nondeterministic FSM error: "
3146                                    + "Multiple enabled transitions found but not all"
3147                                    + " of them are nondeterministic. Transition "
3148                                    + enabledTransition.getName()
3149                                    + " is deterministic. "
3150                                    + "The following transitions are all enabled: "
3151                                    + enabled);
3152                }
3153            }
3154            // If one of these transitions has been previously chosen in
3155            // this iteration, then choose it again. This ensures the same
3156            // results for nondeterministic choices.
3157            if (_transitionsPreviouslyChosenInIteration.size() > 0) {
3158                for (Transition previouslyChosenTransition : _transitionsPreviouslyChosenInIteration) {
3159                    if (enabledTransitions
3160                            .contains(previouslyChosenTransition)) {
3161                        chosenTransition = previouslyChosenTransition;
3162                    }
3163                }
3164            }
3165            if (chosenTransition == null) {
3166                // No previously chosen transition.
3167                // Randomly choose one transition from the list of the
3168                // enabled transitions. Note that it is possible that the
3169                // chosen transition cannot be executed because inputs needed
3170                // by its output actions are not known.
3171                // In that case, we have to choose a different transition.
3172                while (enabledTransitions.size() > 0) {
3173                    // Since the size of the list of enabled transitions usually (almost
3174                    // always) is less than the maximum value of integer. We can safely
3175                    // do the cast from long to int in the following statement.
3176                    int randomChoice = (int) Math
3177                            .floor(Math.random() * numberOfEnabledTransitions);
3178
3179                    // There is a tiny chance that randomChoice equals length.
3180                    // When this happens, we deduct 1 from the randomChoice.
3181                    if (randomChoice == numberOfEnabledTransitions) {
3182                        randomChoice--;
3183                    }
3184
3185                    chosenTransition = enabledTransitions.get(randomChoice);
3186                    if (_referencedInputPortsByOutputKnown(chosenTransition)) {
3187                        // The chosen transition has an output action that
3188                        // references an unknown input.
3189                        _foundUnknown = true;
3190                        break;
3191                    } else {
3192                        // Cannot make this choice.
3193                        enabledTransitions.remove(chosenTransition);
3194                        chosenTransition = null;
3195                    }
3196                }
3197                // Record the chosen transition.
3198                _transitionsPreviouslyChosenInIteration.add(chosenTransition);
3199            }
3200        }
3201
3202        if (chosenTransition != null) {
3203            if (_debugging) {
3204                _debug("Choose transition: ", chosenTransition.getFullName());
3205            }
3206
3207            // cmot:
3208            // If non-preemptive and immediate transition, fire destination
3209            // state refinement.
3210            if (!chosenTransition.isPreemptive()
3211                    && chosenTransition.isImmediate()) {
3212                if (chosenTransition.destinationState() != _currentState) {
3213                    // reset probability threshold and generate new random
3214                    // in case there is an immediate transition.
3215                    _oldThreshold = 0.0;
3216                    _randomValue = _randomToken.nextDouble();
3217                }
3218                // Check for initial state with a refinement and an immediate transition,
3219                // which is not allowed because we can't fire the refinement in initialize.
3220                if (inInitialize) {
3221                    Actor[] stateRefinements = currentState.getRefinement();
3222                    if (stateRefinements != null
3223                            && stateRefinements.length > 0) {
3224                        throw new IllegalActionException(this,
3225                                "Initial state with a refinement and an enabled "
3226                                        + "immediate transition is not allowed, "
3227                                        + "because the refinement would have to execute during the initialize phase.");
3228                    }
3229                }
3230                // If the transition into the current state is a reset transition,
3231                // then initialize the source state refinements. Note that this is safe to do
3232                // in the fire() method because a transition cannot be unchosen later.
3233                //
3234                // FIXME: The above statement is not true in the Continuous domain!!!
3235                // The ContinuousDirector may later refine the step size.
3236                //
3237                // Note that at this point, _lastChosenTransition is the transition _into_
3238                // the current state, if there is one.
3239                if (!inInitialize && _lastChosenTransition != null
3240                        && !_lastChosenTransition.isHistory()) {
3241                    _initializeRefinements(currentState);
3242                }
3243
3244                // Fire the state refinements.
3245                _fireStateRefinements(currentState);
3246            }
3247
3248            // Execute the choice actions.
3249            Iterator actions = chosenTransition.choiceActionList().iterator();
3250            while (actions.hasNext()) {
3251                Action action = (Action) actions.next();
3252                if (!inPreinitialize) {
3253                    // Produce output tokens here.
3254                    // This should not be done in preinitialize, but is OK in initialize.
3255                    // Outputs cannot be produced in preinitialize because type resolution has not occurred
3256                    // and receivers have not been created.
3257                    action.execute();
3258                    if (_debugging) {
3259                        _debug("--- Transition action executed: " + action);
3260                    }
3261                } else {
3262                    // For the benefit of SDF, if there is an output action writing to an
3263                    // output port, then set the tokenInitProduction parameter of that port.
3264                    List<NamedObj> destinations = action.getDestinations();
3265                    for (NamedObj destination : destinations) {
3266                        if (destination instanceof IOPort) {
3267                            // This sets the parameter only for this FSMActor. If this actor
3268                            // is contained by a ModalModel, we need to set it for that port too.
3269                            DFUtilities.setTokenInitProduction(
3270                                    (IOPort) destination, 1);
3271                            if (getContainer() instanceof ModalModel) {
3272                                IOPort port = (IOPort) ((ModalModel) getContainer())
3273                                        .getPort(destination.getName());
3274                                if (port != null) {
3275                                    DFUtilities.setTokenInitProduction(port, 1);
3276                                }
3277                            }
3278                        }
3279                    }
3280                }
3281            }
3282
3283            // Execute the refinements of the transition.
3284            // This is kept for backward compatibility.
3285            Actor[] transitionRefinements = chosenTransition.getRefinement();
3286            if (transitionRefinements != null) {
3287                for (int i = 0; i < transitionRefinements.length; ++i) {
3288                    if (_stopRequested || _disabledRefinements
3289                            .contains(transitionRefinements[i])) {
3290                        break;
3291                    }
3292                    if (_debugging) {
3293                        _debug("Fire transition refinement:",
3294                                transitionRefinements[i].getName());
3295                    }
3296                    // NOTE: What should model time be for transition refinements?
3297                    // It is not reasonable for it to be the time of the originating
3298                    // refinement because multiple transitions may share a refinement
3299                    // and time will end up bouncing around...
3300                    // Transition refinements are deprecated anyway, so let's not
3301                    // worry about that.
3302                    if (transitionRefinements[i].prefire()) {
3303                        transitionRefinements[i].fire();
3304                        _transitionRefinementsToPostfire
3305                                .add(transitionRefinements[i]);
3306                    }
3307                }
3308            }
3309
3310            // If the current state has no refinement and there are
3311            // outputs that remain unknown, make them absent.
3312            // NOTE: Even if there is a refinement, it might be
3313            // reasonable to assert that outputs are absent.
3314            // We can't do that here, however, because the outputs
3315            // from the refinement have not been transferred.
3316            // This case has to be handled by the fire method.
3317            if (_areAllImmediateTransitionsDisabled(
3318                    chosenTransition.destinationState())
3319                    && currentState.getRefinement() == null) {
3320                List<IOPort> outputs = outputPortList();
3321                for (IOPort port : outputs) {
3322                    for (int channel = 0; channel < port
3323                            .getWidth(); channel++) {
3324                        if (!port.isKnown(channel)) {
3325                            port.send(channel, null);
3326                            if (_debugging) {
3327                                _debug("--- Asserting that output "
3328                                        + port.getName() + " is absent.");
3329                            }
3330                        }
3331                    }
3332                }
3333            }
3334
3335            // Commit to this transition, if it is != null.
3336            _lastChosenTransitions.put(currentState, chosenTransition);
3337            // Set this only if there is a non-null chosen transition, since
3338            // we want to remember the last chosen transition even if there
3339            // no preemptive immediate transition.
3340            _lastChosenTransition = chosenTransition;
3341        }
3342        return chosenTransition;
3343    }
3344
3345    /** Schedule an actor for execution on a ExecutionAspect. If the actor can
3346     *  execute this method returns true. If resources are not available this
3347     *  method returns false.
3348     *  @param actor The actor.
3349     *  @param timestamp The time the actor requests to be scheduled.
3350     *  @return True if actor was scheduled and can be fired.
3351     *  @exception IllegalActionException Thrown if parameters cannot be read, actor cannot be
3352     *   scheduled or container cannot be fired at future time.
3353     */
3354    protected boolean _schedule(NamedObj actor, Time timestamp)
3355            throws IllegalActionException {
3356        ActorExecutionAspect aspect = getDirector().getExecutionAspect(actor);
3357        Time time = null;
3358        Boolean finished = true;
3359        if (timestamp == null) {
3360            timestamp = getDirector().getModelTime();
3361        }
3362        if (aspect != null) {
3363            Time environmentTime = ((CompositeActor) aspect.getContainer())
3364                    .getDirector().getEnvironmentTime();
3365            time = ExecutionAspectHelper.schedule(aspect, actor,
3366                    environmentTime,
3367                    getDirector().getDeadline(actor, timestamp));
3368            //            if (_nextScheduleTime == null) {
3369            //                _nextScheduleTime = new HashMap<ActorExecutionAspect, Time>();
3370            //            }
3371            //            _nextScheduleTime.put(aspect, time);
3372            //            finished = _actorFinished(actor);
3373            if (time != null && time.getDoubleValue() > 0.0) {
3374                CompositeActor container = (CompositeActor) aspect
3375                        .getContainer();
3376                Time fireAtTime = environmentTime;
3377                if (!time.equals(Time.POSITIVE_INFINITY)) {
3378                    fireAtTime = fireAtTime.add(time);
3379                    container.getDirector().fireContainerAt(fireAtTime);
3380                }
3381            }
3382        }
3383        boolean schedule = time == null || finished;
3384        //        if (!schedule) {
3385        //            ActorExecutionAspect scheduler = getExecutionAspect(actor);
3386        //            if (scheduler != null) {
3387        //                ((CompositeActor) scheduler.getContainer()).getDirector().fireAt(
3388        //                        (Actor) scheduler,
3389        //                        getModelTime().add(_nextScheduleTime.get(scheduler)));
3390        //            } else {
3391        //                throw new InternalErrorException(this, null,
3392        //                        "_getExecutionAspect(" + actor.getFullName()
3393        //                        + ") returned null?");
3394        //            }
3395        //        }
3396        return schedule;
3397    }
3398
3399    /** Execute all set actions contained by the transition chosen
3400     *  from the current state. Change current state
3401     *  to the destination state of the last of these
3402     *  chosen transitions. If the new current state is a transient
3403     *  state that has a chosen transition emanating from it, then
3404     *  also execute the set actions on that transition.
3405     *  Reset the refinement
3406     *  of the destination state if the <i>reset</i> parameter of the
3407     *  chosen transition is true.
3408     *  @param inPreinitialize If true, then only set the current
3409     *   state after following immediate transitions. Note that the
3410     *   guards on the immediate transitions need to be evaluatable.
3411     *  @param inInitialize True when this method is called
3412     *   from initialize or preinitialize, in which case, firing and initializing
3413     *   refinements is not allowed; note that the refinements
3414     *   will be initialized by the initialize method, but this
3415     *   prevents them from being initialized more than once.
3416     *   This could be important if, for example, the refinement
3417     *   produces an output during initialize in a domain where
3418     *   outputs are consumed, such as SDF.
3419     *  @exception IllegalActionException If any commit action throws it,
3420     *   or the last chosen transition does not have a destination state.
3421     */
3422    private void _commitLastChosenTransition(boolean inPreinitialize,
3423            boolean inInitialize) throws IllegalActionException {
3424        Transition currentTransition = _lastChosenTransitions
3425                .get(_currentState);
3426        if (currentTransition == null) {
3427            return;
3428        }
3429
3430        // Add this transition to the last taken transitions
3431        _lastTakenTransitions.add(currentTransition);
3432
3433        // Remove the entry from the map of chosen transitions to prevent
3434        // a stack overflow from cycling forever around a directed cycle.
3435        _lastChosenTransitions.remove(_currentState);
3436
3437        if (_debugging) {
3438            _debug("Commit transition ", currentTransition.getFullName()
3439                    + " at time " + getDirector().getModelTime());
3440            _debug("  Guard evaluating to true: "
3441                    + currentTransition.guardExpression.getExpression());
3442        }
3443        if (currentTransition.destinationState() == null) {
3444            throw new IllegalActionException(this, currentTransition,
3445                    "The transition is enabled but does not have a "
3446                            + "destination state.");
3447        }
3448
3449        // Next execute the commit actions.
3450        // This needs to occur before resetting the destination
3451        // refinement because the commit actions may initialize
3452        // the destination refinement.
3453        Iterator actions = currentTransition.commitActionList().iterator();
3454        while (actions.hasNext() && !_stopRequested) {
3455            Action action = (Action) actions.next();
3456            action.execute();
3457        }
3458
3459        // If the chosen transition is not a history transition, initialize the destination
3460        // refinement. Note that initializing the director will normally also have
3461        // the side effect of setting its time and time to match the enclosing
3462        // director. This is done before invoking the set actions because (1)
3463        // the initialization may reverse the set actions or, (2)
3464        // the set actions may trigger attributeChanged() calls that depend on
3465        // the current time or index.
3466        // If the currentTransition is the last in the chain of chosen
3467        // transitions and the transition is a reset transition, then
3468        // initialize the destination refinement.
3469        State nextState = currentTransition.destinationState();
3470        // NOTE: This is too late to initialize refinements
3471        // of transient states, as those have already executed!!
3472        // So we only initialize if this is the last transition.
3473        if (_lastChosenTransitions.get(nextState) == null) {
3474            // If this is a reset transition, then we also need to initialize
3475            // the destination refinement.
3476            // Do not do this if we are in preinitialize(), as the refinement
3477            // has not been preinitialized yet.
3478            if (!currentTransition.isHistory() && !inPreinitialize
3479                    && !inInitialize) {
3480                _initializeRefinements(nextState);
3481            }
3482        }
3483
3484        // Commit to the new state.
3485        // Before committing the new state, record whether it changed.
3486        boolean stateChanged = _currentState != currentTransition
3487                .destinationState();
3488        _schedule(nextState, getExecutiveDirector().getModelTime());
3489        _currentState = nextState;
3490        if (stateChanged) {
3491            // reset threshold for probabilistic transitions
3492            _oldThreshold = 0.0;
3493        }
3494
3495        if (_debugging) {
3496            _debug(new StateEvent(this, _currentState));
3497        }
3498
3499        _timeOfNextTimeoutExpiration = null;
3500        _timeEnteredCurrentState = getDirector().getModelTime();
3501
3502        // If we have reached a final state, make a record of that fact
3503        // for the postfire() method.
3504        if (((BooleanToken) _currentState.isFinalState.getToken())
3505                .booleanValue()) {
3506            _reachedFinalState = true;
3507        }
3508
3509        _setCurrentConnectionMap();
3510
3511        // If the causality interface is state-dependent and the state
3512        // has changed, invalidate the schedule. This is done in a ChangeRequest
3513        // because the current iteration (processing all events with the same
3514        // time stamp and microstep) has to be allowed to complete. Otherwise,
3515        // the analysis for causality loops will be redone before other state
3516        // machines have been given a chance to switch states.
3517        boolean stateDependent = ((BooleanToken) stateDependentCausality
3518                .getToken()).booleanValue();
3519        if (stateDependent && stateChanged) {
3520            // The third argument indicates that this is not a structural
3521            // change, and therefore should not trigger a prompt to save
3522            // on closing the model.
3523            ChangeRequest request = new ChangeRequest(this,
3524                    "Invalidate schedule", false) {
3525                @Override
3526                protected void _execute() {
3527                    // Indicate to the director that the current schedule is invalid.
3528                    getDirector().invalidateSchedule();
3529                }
3530            };
3531            // This is also required to prevent a prompt to save on close.
3532            request.setPersistent(false);
3533            requestChange(request);
3534        }
3535
3536        // Finally, request a refiring at the current time. This ensures that
3537        // if the new state is transient, zero time is spent in it.
3538        // If the new state has a refinement, it is up to that refinement
3539        // to examine the superdense time index if appropriate and not produce
3540        // output if it should not produce output. This has implications on
3541        // the design of actors like DiscreteClock.
3542        // Do not do this in preinitialize.
3543        if (!inPreinitialize) {
3544            Director director = getDirector();
3545            director.fireAt(this, director.getModelTime());
3546        }
3547
3548        // If we have not reached a final state, and the state
3549        // changed, then recursively call this
3550        // same method in case the destination state is transient. If it is,
3551        // then there will be another chosen transition emerging from the
3552        // new _currentState, and we have to execute set actions on that
3553        // transition. If there is no chosen transition from the new
3554        // _currentState, then the recursive call will return immediately.
3555        if (!_reachedFinalState && stateChanged) {
3556            _commitLastChosenTransition(inPreinitialize, inInitialize);
3557        } else {
3558            _lastChosenTransitions.clear();
3559        }
3560    }
3561
3562    private void _createRandomGenerator() throws IllegalActionException {
3563
3564        _seed = ((LongToken) seed.getToken()).longValue();
3565        if (_seed == 0L) {
3566            _seed = System.currentTimeMillis() + hashCode();
3567        } else {
3568            _seed = _seed + getFullName().hashCode();
3569        }
3570        _randomToken = new Random(_seed);
3571    }
3572
3573    /** Create receivers for each input port.
3574     *  This method gets write permission on the workspace.
3575     *  @exception IllegalActionException If any port throws it.
3576     */
3577    private void _createReceivers() throws IllegalActionException {
3578        try {
3579            workspace().getWriteAccess();
3580            Iterator inputPorts = inputPortList().iterator();
3581            while (inputPorts.hasNext()) {
3582                IOPort inPort = (IOPort) inputPorts.next();
3583                inPort.createReceivers();
3584            }
3585        } finally {
3586            // Note that this does not increment the workspace version.
3587            // We have not changed the structure of the model.
3588            workspace().doneTemporaryWriting();
3589        }
3590    }
3591
3592    /** Force the output of the specified port on the specified channel
3593     *  to be unknown. This is done because there is a transition that
3594     *  may set the value of this output, possibly overwriting some
3595     *  previously set value, but the guard on that transition cannot
3596     *  be evaluated because some inputs are unknown. This method
3597     *  propagates the forcing of unknown outward through layers
3598     *  of ModalModels.
3599     *  @param port The port.
3600     *  @param channel The channel.
3601     *  @exception IllegalActionException If getting remove receivers or
3602     *   resetting them fails.
3603     */
3604    private void _forceUnknownOutput(IOPort port, int channel)
3605            throws IllegalActionException {
3606        Receiver[][] receivers = port.getRemoteReceivers();
3607        if (receivers != null) {
3608            if (receivers.length > channel && receivers[channel] != null) {
3609                for (int j = 0; j < receivers[channel].length; j++) {
3610                    if (receivers[channel][j] instanceof FSMReceiver) {
3611                        receivers[channel][j].reset();
3612                        // Propagate outwards until there are no more FSMReceivers.
3613                        IOPort destinationPort = receivers[channel][j]
3614                                .getContainer();
3615                        if (_debugging) {
3616                            _debug("--- Setting inside of port "
3617                                    + destinationPort.getFullName()
3618                                    + " unknown on channel " + channel
3619                                    + ", because a guard cannot be evaluated due to unknown inputs.");
3620                        }
3621                        if (destinationPort != null) {
3622                            _forceUnknownOutput(destinationPort, channel);
3623                        }
3624                    }
3625                }
3626            }
3627        }
3628    }
3629
3630    /** Return the environment time.
3631     *  If this actor is the controller for a modal model,
3632     *  then return the model time of the modal model's executive director,
3633     *  if there is one. Otherwise, return the model of the director
3634     *  for this actor.
3635     *  @return The current environment time.
3636     */
3637    private Time _getEnvironmentTime() {
3638        Director director = getDirector();
3639        if (director instanceof FSMDirector) {
3640            // In a modal model.
3641            Actor container = (Actor) director.getContainer();
3642            Director executiveDirector = container.getExecutiveDirector();
3643            if (executiveDirector != null) {
3644                Time environmentTime = executiveDirector.getModelTime();
3645                return environmentTime;
3646            }
3647        }
3648        return director.getModelTime();
3649    }
3650
3651    /*  Initialize the actor.
3652     *  @exception IllegalActionException If any port throws it.
3653     */
3654    protected void _init() {
3655        // Create a more reasonable default icon.
3656        _attachText("_iconDescription",
3657                "<svg>\n" + "<rect x=\"-30\" y=\"-20\" width=\"60\" "
3658                        + "height=\"40\" style=\"fill:red\"/>\n"
3659                        + "<rect x=\"-28\" y=\"-18\" width=\"56\" "
3660                        + "height=\"36\" style=\"fill:lightgrey\"/>\n"
3661                        + "<ellipse cx=\"0\" cy=\"0\""
3662                        + " rx=\"15\" ry=\"10\"/>\n"
3663                        + "<circle cx=\"-15\" cy=\"0\""
3664                        + " r=\"5\" style=\"fill:white\"/>\n"
3665                        + "<circle cx=\"15\" cy=\"0\""
3666                        + " r=\"5\" style=\"fill:white\"/>\n" + "</svg>\n");
3667
3668        try {
3669            stateDependentCausality = new Parameter(this,
3670                    "stateDependentCausality");
3671            stateDependentCausality.setTypeEquals(BaseType.BOOLEAN);
3672            stateDependentCausality.setExpression("false");
3673
3674            errorClass = new StringParameter(this, "errorClass");
3675            errorClass.setVisibility(Settable.EXPERT);
3676            errorClass.setPersistent(false);
3677            errorMessage = new StringParameter(this, "errorMessage");
3678            errorMessage.setVisibility(Settable.EXPERT);
3679            errorMessage.setPersistent(false);
3680            errorCause = new Parameter(this, "errorCause");
3681            errorCause.setVisibility(Settable.EXPERT);
3682            errorCause.setPersistent(false);
3683
3684            initialStateName = new StringAttribute(this, "initialStateName");
3685            initialStateName.setExpression("");
3686            initialStateName.setVisibility(Settable.EXPERT);
3687
3688            finalStateNames = new StringAttribute(this, "finalStateNames");
3689            finalStateNames.setExpression("");
3690            finalStateNames.setVisibility(Settable.EXPERT);
3691
3692            timeout = new Parameter(this, "timeout");
3693            timeout.setToken(new TimeoutFunctionToken());
3694            timeout.setVisibility(Settable.EXPERT);
3695            timeout.setPersistent(false);
3696
3697            probability = new Parameter(this, "probability");
3698            probability.setToken(new ProbabilityFunctionToken());
3699            probability.setVisibility(Settable.EXPERT);
3700            probability.setPersistent(false);
3701
3702            seed = new SharedParameter(this, "seed", RandomSource.class, "0L");
3703            seed.setTypeEquals(BaseType.LONG);
3704
3705            resetOnEachRun = new SharedParameter(this, "resetSeedOnEachRun",
3706                    RandomSource.class, "false");
3707            resetOnEachRun.setTypeEquals(BaseType.BOOLEAN);
3708
3709        } catch (KernelException ex) {
3710            // This should never happen.
3711            throw new InternalErrorException(this, ex, "Constructor error.");
3712        }
3713
3714        _identifierToPort = new HashMap<String, IOPort>();
3715        _transitionEvaluatedTo = new HashMap<Transition, BooleanToken>();
3716
3717    }
3718
3719    /** Check to see whether the specified transition is enabled.
3720     *  This method attempts to evaluate the guard of a transition.
3721     *  If an exception occurs, then it checks to see whether the
3722     *  guard expression referenced any unknown inputs, and if so,
3723     *  it returns false (the transition is not (yet) enabled).
3724     *  @param transition The transition to check.
3725     *  @return True if the transition is enabled.
3726     *  @exception IllegalActionException If the guard expression cannot be parsed.
3727     */
3728    private boolean _isTransitionEnabled(Transition transition)
3729            throws IllegalActionException {
3730        try {
3731            _transitionBeingTested = transition;
3732            return transition.isEnabled();
3733        } catch (UndefinedConstantOrIdentifierException ex) {
3734            // If the node refers to a port, then it may be that the
3735            // port is absent.  Check that it matches a port name.
3736            String name = ex.nodeName();
3737            IOPort portForIdentifier = _getPortForIdentifier(name);
3738            if (portForIdentifier != null) {
3739                // NOTE: We would like to make sure at this point that the
3740                // expression is well formed, but the issue simply that
3741                // port has absent, and hence the port name is undefined.
3742                // This is pretty tricky. How can we check that the
3743                // expression could be evaluated if the input were present?
3744
3745                // If the referenced port is now known, and
3746                // the transition includes any output actions,
3747                // then we need to make sure that those outputs are
3748                // unknown in this firing, even if they have been
3749                // previously set to known in this firing.
3750                // See $PTII/ptolemy/domains/modal/test/auto/SeeminglyNondeterminate2.xml
3751
3752                Integer channelForIdentifier = _getChannelForIdentifier(name);
3753                if (channelForIdentifier < 0) {
3754                    channelForIdentifier = 0;
3755                }
3756                if (channelForIdentifier != null
3757                        && !portForIdentifier.isKnown(channelForIdentifier)) {
3758                    List<IOPort> portsAssigned = transition.outputActions
3759                            .getDestinations();
3760                    List<Integer> channelsAssigned = transition.outputActions
3761                            .getChannelNumberList();
3762                    int i = 0;
3763                    if (portsAssigned != null) {
3764                        for (IOPort port : portsAssigned) {
3765                            // The channelsAssigned list had better have the same length.
3766                            Integer channel = channelsAssigned.get(i);
3767                            if (channel == null) {
3768                                // Interpret this to mean all channels.
3769                                for (int j = 0; j < port.getWidth(); j++) {
3770                                    _outputsThatMustBeUnknown.put(port,
3771                                            Integer.valueOf(j));
3772                                }
3773                            } else {
3774                                _outputsThatMustBeUnknown.put(port, channel);
3775                            }
3776                        }
3777                    }
3778                }
3779                return false;
3780            }
3781            throw ex;
3782        }
3783    }
3784
3785    /** Remove all variable definitions associated with the specified
3786     *  port name and channel number.
3787     *  @param portName The name of the port
3788     *  @param channel The channel number
3789     */
3790    private void _removePortVariables(String portName, int channel) {
3791        String portChannelName = portName + "_" + channel;
3792        _inputTokenMap.remove(portName);
3793        _inputTokenMap.remove(portChannelName);
3794        _inputTokenMap.remove(portName + "_isPresent");
3795        _inputTokenMap.remove(portName + "Array");
3796        _inputTokenMap.remove(portChannelName + "Array");
3797    }
3798
3799    /** Reset receivers for each input port.
3800     *  @exception IllegalActionException If any port throws it.
3801     */
3802    private void _resetReceivers() throws IllegalActionException {
3803        Iterator inputPorts = inputPortList().iterator();
3804        while (inputPorts.hasNext()) {
3805            IOPort inPort = (IOPort) inputPorts.next();
3806            Receiver[][] receivers = inPort.getReceivers();
3807            for (Receiver[] receiver : receivers) {
3808                if (receiver != null) {
3809                    for (int j = 0; j < receiver.length; j++) {
3810                        if (receiver[j] != null) {
3811                            receiver[j].reset();
3812                        }
3813                    }
3814                }
3815            }
3816        }
3817    }
3818
3819    /** Given a transition, return false if the guard includes any
3820     *  reference to an input port value and that input port is known
3821     *  to be absent, or any reference to an input port whose status
3822     *  is unknown. Otherwise, return true.  A reference to
3823     *  an input port with "_isPresent" appended is not considered.
3824     *  Note that you have to be very careful using this.
3825     *  E.g., if the guard expression is (!in_isPresent || in == 1)
3826     *  then this method would return false when in is absent, even
3827     *  though the guard can be evaluated and evaluates to true.
3828     *  Thus, the correct usage is to attempt first to evaluate the
3829     *  guard, and only if the evaluation fails, then use this method
3830     *  to determine whether the cause is the absence of input.
3831     *  @param transition A transition
3832     *  @return False if the guard includes references to values of input
3833     *   ports that are absent.
3834     *  @exception IllegalActionException If the guard expression cannot
3835     *   be parsed.
3836     */
3837    /*
3838     * NOTE: This method is no longer used, but might prove
3839     * useful in the future.
3840    private boolean _referencedInputPortValuesByGuardPresent(
3841            Transition transition) throws IllegalActionException {
3842
3843
3844        // If the port identifier does
3845        // not end with "_isPresent", then return false if port
3846        // identifier with "_isPresent" appended is false. There is no data on
3847        // the port "in" then the identifier "in" will be undefined, or worse,
3848        //  will resolve to the port object itself.
3849
3850        String string = transition.getGuardExpression();
3851        if (string.trim().equals("")) {
3852            return true;
3853        }
3854        PtParser parser = new PtParser();
3855        ASTPtRootNode parseTree = parser.generateParseTree(string);
3856        ParseTreeFreeVariableCollector variableCollector = new ParseTreeFreeVariableCollector();
3857        ParserScope scope = getPortScope();
3858        // Get a set of free variable names.
3859        Set<String> nameSet = variableCollector.collectFreeVariables(parseTree,
3860                scope);
3861
3862        for (String name : nameSet) {
3863            Port port = _getPortForIdentifier(name);
3864            if (port instanceof IOPort) {
3865                int channel = _getChannelForIdentifier(name);
3866                if (channel >= 0) {
3867                    if (!((IOPort) port).isKnown(channel)) {
3868                        return false;
3869                    }
3870                    if (!name.endsWith("_isPresent")) {
3871                        Token token = scope.get(port.getName() + "_" + channel
3872                                + "_isPresent");
3873                        if (!(token instanceof BooleanToken)
3874                                || !((BooleanToken) token).booleanValue()) {
3875                            // isPresent symbol is either undefined or false..
3876                            return false;
3877                        }
3878                    }
3879                } else {
3880                    // No specified channel.
3881                    if (!((IOPort) port).isKnown()) {
3882                        return false;
3883                    }
3884                    if (!name.endsWith("_isPresent")) {
3885                        Token token = scope.get(port.getName() + "_isPresent");
3886                        if (!(token instanceof BooleanToken)
3887                                || !((BooleanToken) token).booleanValue()) {
3888                            return false;
3889                        }
3890                    }
3891                }
3892            }
3893        }
3894        return true;
3895    }
3896     */
3897
3898    /** Given a transition, find any input ports
3899     *  referenced in the guard expressions of the
3900     *  transition, and if any of those input ports has status
3901     *  unknown, return false.
3902     *  Otherwise, return true.
3903     *  These are the input ports whose status must be known
3904     *  for this transition to be enabled.
3905     *  @param transition A transition
3906     *  @return True if all input ports referenced by the guard on
3907     *   the transition have known status.
3908     *  @exception IllegalActionException If the guard expression cannot
3909     *   be parsed.
3910     */
3911    private boolean _referencedInputPortsByGuardKnown(Transition transition)
3912            throws IllegalActionException {
3913
3914        String string = transition.getGuardExpression();
3915        if (string.trim().equals("")) {
3916            return true;
3917        }
3918        PtParser parser = new PtParser();
3919        ASTPtRootNode parseTree = parser.generateParseTree(string);
3920        ParseTreeFreeVariableCollector variableCollector = new ParseTreeFreeVariableCollector();
3921        ParserScope scope = getPortScope();
3922        // Get a set of free variable names.
3923        Set<String> nameSet = variableCollector.collectFreeVariables(parseTree,
3924                scope);
3925
3926        for (String name : nameSet) {
3927            Port port = _getPortForIdentifier(name);
3928            if (port instanceof IOPort) {
3929                int channel = _getChannelForIdentifier(name);
3930                if (channel >= 0) {
3931                    if (!((IOPort) port).isKnown(channel)) {
3932                        return false;
3933                    }
3934                } else {
3935                    // No specified channel.
3936                    if (!((IOPort) port).isKnown()) {
3937                        return false;
3938                    }
3939                }
3940            }
3941        }
3942        return true;
3943    }
3944
3945    /** Given a transition, find any input ports
3946     *  referenced in the output actions of the
3947     *  transitions, and if any of those input ports has status
3948     *  unknown, return false. Otherwise, return true.
3949     *  These are the input ports whose status must be known
3950     *  to choose this transition.
3951     *  @param transition A transition
3952     *  @return A set of input ports.
3953     *  @exception IllegalActionException If the guard expression cannot
3954     *   be parsed.
3955     */
3956    private boolean _referencedInputPortsByOutputKnown(Transition transition)
3957            throws IllegalActionException {
3958        String outputActionsExpression = transition.outputActions
3959                .getExpression();
3960        PtParser parser = new PtParser();
3961        ParseTreeFreeVariableCollector variableCollector = new ParseTreeFreeVariableCollector();
3962        ParserScope scope = getPortScope();
3963        if (!outputActionsExpression.trim().equals("")) {
3964            Map map = parser.generateAssignmentMap(outputActionsExpression);
3965            for (Iterator names = map.entrySet().iterator(); names.hasNext();) {
3966                Map.Entry entry = (Map.Entry) names.next();
3967                ASTPtAssignmentNode node = (ASTPtAssignmentNode) entry
3968                        .getValue();
3969                ASTPtRootNode parseTree = node.getExpressionTree();
3970                Set<String> nameSet = variableCollector
3971                        .collectFreeVariables(parseTree, scope);
3972
3973                for (String name : nameSet) {
3974                    Port port = _getPortForIdentifier(name);
3975                    if (port instanceof IOPort) {
3976                        int channel = _getChannelForIdentifier(name);
3977                        if (channel >= 0) {
3978                            if (!((IOPort) port).isKnown(channel)) {
3979                                return false;
3980                            }
3981                        } else {
3982                            if (!((IOPort) port).isKnown()) {
3983                                return false;
3984                            }
3985                        }
3986                        // Port status is known, but the referenced
3987                        // identifier may be undefined (e.g. "in" when
3988                        // in is absent).
3989                        /* NOTE: Bogus. Could be in a part of the
3990                         * output that will not be evaluated.
3991                        if (scope.get(name) == null) {
3992                            return false;
3993                        }
3994                         */
3995                    }
3996                }
3997            }
3998        }
3999        return true;
4000    }
4001
4002    /** For each input port of this actor, associate all identifiers
4003     *  with that port.
4004     *  @exception IllegalActionException If getting the width of the port fails.
4005     */
4006    private void _setIdentifierToPort() throws IllegalActionException {
4007        _identifierToPort.clear();
4008
4009        for (Iterator inputPorts = inputPortList().iterator(); inputPorts
4010                .hasNext();) {
4011            IOPort inPort = (IOPort) inputPorts.next();
4012            String portName = inPort.getName();
4013            _identifierToPort.put(portName, inPort);
4014            _identifierToPort.put(portName, inPort);
4015            _identifierToPort.put(portName + "_isPresent", inPort);
4016            _identifierToPort.put(portName + "Array", inPort);
4017
4018            for (int i = 0; i < inPort.getWidth(); i++) {
4019                _identifierToPort.put(portName + "_" + i, inPort);
4020                _identifierToPort.put(portName + "_" + i + "_isPresent",
4021                        inPort);
4022                _identifierToPort.put(portName + "_" + i + "Array", inPort);
4023            }
4024        }
4025    }
4026
4027    /** Set the port variables for the specified port as follows:
4028     *  The portName_isPresent variable is set to true if the token
4029     *  argument is non-null, and false otherwise.
4030     *  If the token argument is non-null, then the portName variable
4031     *  is set to have the value of the token.
4032     *  If the tokenArray variable is non-null, then the portNameArray
4033     *  variable is set to have its value.  In addition, for each
4034     *  of these cases, another (up to) three variables are set
4035     *  with portName replaced by portName_i, where i is the channel
4036     *  number. If token is null, then the variable portName
4037     *  is unset, so that an access to it results in the name
4038     *  resolving to the port itself, which can be very confusing.
4039     *  @param port The port.
4040     *  @param channel The channel.
4041     *  @param token If not null, the data token at the port.
4042     *  @param tokenArray If not null, an array of tokens at the port.
4043     *  @exception IllegalActionException If the identifier is
4044     *   already associated with another port.
4045     */
4046    private void _setInputTokenMap(Port port, int channel, Token token,
4047            Token[] tokenArray) throws IllegalActionException {
4048        String portName = port.getName();
4049
4050        String portChannelName = portName + "_" + channel;
4051
4052        String name = portName + "_isPresent";
4053        if (token != null) {
4054            _inputTokenMap.put(name, BooleanToken.TRUE);
4055            if (_debugging) {
4056                _debug("--- Setting variable ", name, " to true.");
4057            }
4058        } else {
4059            _inputTokenMap.put(name, BooleanToken.FALSE);
4060            if (_debugging) {
4061                _debug("--- Setting variable ", name, " to false.");
4062            }
4063        }
4064
4065        name = portChannelName + "_isPresent";
4066        if (token != null) {
4067            _inputTokenMap.put(name, BooleanToken.TRUE);
4068            if (_debugging) {
4069                _debug("--- Setting variable ", name, " to true.");
4070            }
4071        } else {
4072            _inputTokenMap.put(name, BooleanToken.FALSE);
4073            if (_debugging) {
4074                _debug("--- Setting variable ", name, " to false.");
4075            }
4076        }
4077
4078        name = portName;
4079        if (token != null) {
4080            _inputTokenMap.put(name, token);
4081            if (_debugging) {
4082                _debug("--- Setting variable ", name, " to " + token);
4083            }
4084        } else {
4085            // Remove the identifier.
4086            _inputTokenMap.remove(name);
4087        }
4088
4089        name = portChannelName;
4090        if (token != null) {
4091            _inputTokenMap.put(name, token);
4092            if (_debugging) {
4093                _debug("--- Setting variable ", name, " to " + token);
4094            }
4095        } else {
4096            // Remove the identifier.
4097            // FIXME: Should we set this to null instead???
4098            _inputTokenMap.remove(name);
4099        }
4100
4101        name = portName + "Array";
4102        if (tokenArray != null) {
4103            ArrayToken arrayToken = new ArrayToken(tokenArray);
4104            _inputTokenMap.put(name, arrayToken);
4105            if (_debugging) {
4106                _debug("--- Setting variable ", name, " to " + arrayToken);
4107            }
4108        } else {
4109            // Remove the identifier.
4110            // FIXME: Should we set this to null instead???
4111            _inputTokenMap.remove(name);
4112        }
4113
4114        name = portChannelName + "Array";
4115        if (tokenArray != null) {
4116            ArrayToken arrayToken = new ArrayToken(tokenArray);
4117            _inputTokenMap.put(name, arrayToken);
4118            if (_debugging) {
4119                _debug("--- Setting variable ", name, " to " + arrayToken);
4120            }
4121        } else {
4122            // Remove the identifier.
4123            // FIXME: Should we set this to null instead???
4124            _inputTokenMap.remove(name);
4125        }
4126    }
4127
4128    ///////////////////////////////////////////////////////////////////
4129    ////                         private variables                 ////
4130
4131    private transient LinkedList _cachedInputPorts;
4132
4133    private transient LinkedList _cachedOutputPorts;
4134
4135    /** The causality interface, if it has been created,
4136     *  for the case where the causality interface is not state
4137     *  dependent.
4138     */
4139    private CausalityInterface _causalityInterface;
4140
4141    /** The director for which the causality interface was created. */
4142    private Director _causalityInterfaceDirector;
4143
4144    /** The causality interfaces by state, for the case
4145     *  where the causality interface is state dependent.
4146     */
4147    private Map<State, FSMCausalityInterface> _causalityInterfaces;
4148
4149    /** The workspace version for causality interfaces by state, for the case
4150     *  where the causality interface is state dependent.
4151     */
4152    private Map<State, Long> _causalityInterfacesVersions;
4153
4154    // Stores for each state a map from input ports to boolean flags
4155    // indicating whether a channel is connected to an output port
4156    // of the refinement of the state.
4157    private Map _connectionMaps = null;
4158
4159    /** Version of the connection maps. */
4160    private long _connectionMapsVersion = -1;
4161
4162    /** The map from input ports to boolean flags indicating whether a
4163     *  channel is connected to an output port of the refinement of the
4164     *  current state.
4165     */
4166    private Map _currentConnectionMap = null;
4167
4168    /** True before the first fire, then false. Used to communicate
4169     *  with resource schedulers.
4170     */
4171    private boolean _firstFire = false;
4172
4173    /** A flag indicating that unknown inputs were referenced in guards
4174     *  and/or output value expressions (when guards evaluate to true)
4175     *  in the most recently called enabledTransition() or
4176     *  chooseTransition().
4177     */
4178    private boolean _foundUnknown = false;
4179
4180    /** A map that associates each identifier with the unique port that the
4181     *  identifier describes.  This map is used to detect port names that result
4182     *  in ambiguous identifier bindings.
4183     */
4184    private HashMap<String, IOPort> _identifierToPort;
4185
4186    /** Version number for _identifierToPort. */
4187    private long _identifierToPortVersion = -1;
4188
4189    // Cached lists of input and output ports.
4190    private transient long _inputPortsVersion = -1;
4191
4192    // Flag indicating that a model error occurred
4193    // and was handled.
4194    private Exception _modelErrorHandled = null;
4195
4196    // A flag indicating whether this is at the beginning
4197    // of one iteration (firing). Normally it is set to true.
4198    // It is only set to false in HDF.
4199    private boolean _newIteration = true;
4200
4201    /** Memory for the probabilistic threshold to be used in evaluating probabilistic transitions **/
4202    private double _oldThreshold;
4203
4204    private transient long _outputPortsVersion = -1;
4205
4206    /** Set of outputs that must be made unknown at the end
4207     *  of a firing because they are set on transitions that
4208     *  are not known to be enabled or disabled.
4209     */
4210    private Map<IOPort, Integer> _outputsThatMustBeUnknown = new HashMap<IOPort, Integer>();
4211
4212    /** Random Object to govern generated random numbers **/
4213    private Random _randomToken;
4214
4215    /** Random number to decide on the transition to be taken **/
4216    private double _randomValue;
4217
4218    // True if the current state is a final state.
4219    private boolean _reachedFinalState;
4220
4221    // Indicator of when the receivers were last updated.
4222    private long _receiversVersion = -1;
4223
4224    // Seed value to generate random tokens internally, for probabilistic transitions.
4225    private long _seed = 0L;
4226
4227    // A flag indicating whether this actor supports multirate firing.
4228    private boolean _supportMultirate = false;
4229
4230    // Time at which the current state was entered.
4231    private Time _timeEnteredCurrentState;
4232
4233    // Time of next experation of a timeout.
4234    private Time _timeOfNextTimeoutExpiration;
4235
4236    // Argument type for the timeout function.
4237    private static Type[] _TIMEOUT_FUNCTION_ARGUMENT_TYPE = { BaseType.DOUBLE };
4238
4239    // Hashtable to save an array of tokens for each port.
4240    // This is used in HDF when multiple tokens are consumed
4241    // by the FSMActor in one iteration.
4242    private Hashtable _tokenListArrays;
4243
4244    /** Indicator that a transition was taken in the last iteration.
4245     *  This gets set to true in initialize if immediate transitions are
4246     *  taken, and to true in postfire if any transition is taken.
4247     */
4248    private boolean _transitionTaken;
4249
4250    /** Set of nondeterministic transitions previously chosen
4251     *  in an iteration. There may be more than one because of
4252     *  immediate transitions.
4253     */
4254    private Set<Transition> _transitionsPreviouslyChosenInIteration = new HashSet<Transition>();
4255
4256    /** Transition refinements to postfire(), as determined by the fire() method. */
4257    private List<Actor> _transitionRefinementsToPostfire = new LinkedList<Actor>();
4258
4259    /** the current transition  tested for being enabled or not **/
4260    private Transition _transitionBeingTested;
4261
4262    /** values of the already-evaluated probabilistic transitions within a single firing.
4263     * Used to keep probabilistic transitions invariant within the firing **/
4264    private HashMap<Transition, BooleanToken> _transitionEvaluatedTo;
4265
4266    ///////////////////////////////////////////////////////////////////
4267    ////                         inner classes                     ////
4268
4269    /** This class implements a scope, which is used to evaluate the
4270     *  parsed expressions.  This class is currently rather simple,
4271     *  but in the future should allow the values of input ports to
4272     *  be referenced without having shadow variables.
4273     */
4274    public class PortScope extends ModelScope {
4275        /** Look up and return the attribute with the specified name in the
4276         *  scope. Return null if such an attribute does not exist.
4277         *  @param name The name of the variable to be looked up.
4278         *  @return The attribute with the specified name in the scope.
4279         *  @exception IllegalActionException If a value in the scope
4280         *  exists with the given name, but cannot be evaluated.
4281         */
4282        @Override
4283        public ptolemy.data.Token get(String name)
4284                throws IllegalActionException {
4285            // Check to see if it is something we refer to.
4286            Token token = (Token) _inputTokenMap.get(name);
4287
4288            if (token != null) {
4289                return token;
4290            }
4291
4292            Variable result = getScopedVariable(null, FSMActor.this, name);
4293
4294            if (result != null) {
4295                return result.getToken();
4296            } else {
4297                // If we still can't find a name, try to resolve it with
4298                // ModelScope. This will look up the names of all states, as
4299                // well as the names in refinements and those at higher levels
4300                // of the model hierarchy.
4301                // -- tfeng (09/26/2008)
4302                NamedObj object = ModelScope.getScopedObject(FSMActor.this,
4303                        name);
4304                if (object instanceof Variable) {
4305                    token = ((Variable) object).getToken();
4306                } else if (object != null) {
4307                    // If the object is an IOPort contained by this actor,
4308                    // then do not return it. IOPort names refer to the shadow
4309                    // variables.
4310                    // -- eal (10/8/2011)
4311                    if (object instanceof IOPort) {
4312                        if (object.getContainer() == FSMActor.this) {
4313                            return null;
4314                        }
4315                    }
4316                    token = new ObjectToken(object, object.getClass());
4317                }
4318                return token;
4319            }
4320        }
4321
4322        /** Look up and return the type of the attribute with the
4323         *  specified name in the scope. Return null if such an
4324         *  attribute does not exist.
4325         *  @param name The name of the variable to be looked up.
4326         *  @return The attribute with the specified name in the scope.
4327         *  @exception IllegalActionException If a value in the scope
4328         *  exists with the given name, but cannot be evaluated.
4329         */
4330        @Override
4331        public Type getType(String name) throws IllegalActionException {
4332            // Check to see if this is something we refer to.
4333            Port port = _getPortForIdentifier(name);
4334
4335            if (port != null && port instanceof Typeable) {
4336                if (name.endsWith("_isPresent")) {
4337                    return BaseType.BOOLEAN;
4338
4339                } else if (name.endsWith("Array")) {
4340
4341                    // We need to explicit return an ArrayType here
4342                    // because the port type may not be an ArrayType.
4343                    String portName = name.substring(0, name.length() - 5);
4344                    if (port == _getPortForIdentifier(portName)) {
4345                        Type portType = ((Typeable) port).getType();
4346                        return new ArrayType(portType);
4347                    }
4348                }
4349                return ((Typeable) port).getType();
4350            }
4351
4352            Variable result = getScopedVariable(null, FSMActor.this, name);
4353
4354            if (result != null) {
4355                return result.getType();
4356            } else {
4357                // If we still can't find a name, try to resolve it with
4358                // ModelScope. This will look up the names of all states, as
4359                // well as the names in refinements and those at higher levels
4360                // of the model hierarchy.
4361                // -- tfeng (09/26/2008)
4362                Type type = null;
4363                NamedObj object = ModelScope.getScopedObject(FSMActor.this,
4364                        name);
4365                if (object instanceof Variable) {
4366                    type = ((Variable) object).getType();
4367                } else if (object != null) {
4368                    type = new ObjectType(object, object.getClass());
4369                }
4370                return type;
4371            }
4372        }
4373
4374        /** Look up and return the type term for the specified name
4375         *  in the scope. Return null if the name is not defined in this
4376         *  scope, or is a constant type.
4377         *  @param name The name of the variable to be looked up.
4378         *  @return The InequalityTerm associated with the given name in
4379         *  the scope.
4380         *  @exception IllegalActionException If a value in the scope
4381         *  exists with the given name, but cannot be evaluated.
4382         */
4383        @Override
4384        public InequalityTerm getTypeTerm(String name)
4385                throws IllegalActionException {
4386            // Check to see if this is something we refer to.
4387            Port port = _getPortForIdentifier(name);
4388
4389            if (port != null && port instanceof Typeable) {
4390                return ((Typeable) port).getTypeTerm();
4391            }
4392
4393            Variable result = getScopedVariable(null, FSMActor.this, name);
4394
4395            if (result != null) {
4396                return result.getTypeTerm();
4397            } else {
4398                return null;
4399            }
4400        }
4401
4402        /** Return the list of identifiers within the scope.
4403         *  @return The list of identifiers within the scope.
4404         *  @exception IllegalActionException If getting the width of
4405         *   some port fails.
4406         */
4407        @Override
4408        public Set identifierSet() throws IllegalActionException {
4409            Set set = getAllScopedVariableNames(null, FSMActor.this);
4410
4411            // Make sure the identifier set is up to date.
4412            if (workspace().getVersion() != _identifierToPortVersion) {
4413                _setIdentifierToPort();
4414                _identifierToPortVersion = workspace().getVersion();
4415            }
4416
4417            set.addAll(_identifierToPort.keySet());
4418            // If we still can't find a name, try to resolve it with
4419            // ModelScope. This will look up the names of all states, as
4420            // well as the names in refinements and those at higher levels
4421            // of the model hierarchy.
4422            // -- tfeng (09/26/2008)
4423            set.addAll(ModelScope.getAllScopedObjectNames(FSMActor.this));
4424            return set;
4425        }
4426    }
4427
4428    /** The implementation of probabilistic transitions */
4429    private class ProbabilityFunction implements Function {
4430        @Override
4431        public Token apply(Token[] arguments) throws IllegalActionException {
4432
4433            if (arguments[0] instanceof DoubleToken
4434                    || arguments[0] instanceof IntToken) {
4435                if (arguments[0] instanceof IntToken) {
4436                    // to allow expresions 0 and 1 (instead of 0.0 and 1.0)
4437                    _guardProbability = ((IntToken) arguments[0]).intValue();
4438                } else {
4439                    _guardProbability = ((DoubleToken) arguments[0])
4440                            .doubleValue();
4441                }
4442
4443                if (_transitionBeingTested == null) {
4444                    return BooleanToken.FALSE;
4445                }
4446
4447                // First, check if the transition has already been evaluated. If so, return the result. If not,
4448                // change threshold and evaluate.
4449
4450                if (_transitionEvaluatedTo
4451                        .get(_transitionBeingTested) != null) {
4452                    // means we have already evaluated this transition,
4453                    return _transitionEvaluatedTo.get(_transitionBeingTested);
4454                } else {
4455                    // no record has been found; evaluate.
4456                    if (_guardProbability + _oldThreshold > 1.0
4457                            || (_guardProbability > 1.0)) {
4458                        System.err
4459                                .println("Probability range exceeds [0.0,1.0]");
4460                    } else if ((_oldThreshold <= _randomValue)
4461                            && _randomValue <= (_oldThreshold
4462                                    + _guardProbability)) {
4463                        _oldThreshold += _guardProbability;
4464                        _transitionEvaluatedTo.put(_transitionBeingTested,
4465                                BooleanToken.TRUE);
4466                        return BooleanToken.TRUE;
4467                    } else {
4468                        _oldThreshold += _guardProbability;
4469                        _transitionEvaluatedTo.put(_transitionBeingTested,
4470                                BooleanToken.FALSE);
4471                        return BooleanToken.FALSE;
4472                    }
4473                }
4474            }
4475            return BooleanToken.FALSE;
4476        }
4477
4478        @Override
4479        public int getNumberOfArguments() {
4480            // TODO Auto-generated method stub
4481            return 1;
4482        }
4483
4484        @Override
4485        public boolean isCongruent(Function function) {
4486            // TODO Auto-generated method stub
4487            return function instanceof ProbabilityFunction;
4488        }
4489
4490        @Override
4491        public String toString() {
4492            return "function(p:double):boolean";
4493        }
4494
4495        private double _guardProbability;
4496
4497    }
4498
4499    /** The implementation of the probability function as a token. */
4500    private class ProbabilityFunctionToken extends FunctionToken {
4501        public ProbabilityFunctionToken() {
4502            super(new ProbabilityFunction(), new FunctionType(
4503                    _TIMEOUT_FUNCTION_ARGUMENT_TYPE, BaseType.BOOLEAN));
4504        }
4505    }
4506
4507    /** The implementation of the timeout function as a function. */
4508    private class TimeoutFunction implements Function {
4509        @Override
4510        public ptolemy.data.Token apply(ptolemy.data.Token[] arguments)
4511                throws IllegalActionException {
4512            if (!(arguments[0] instanceof DoubleToken)) {
4513                // Try to convert to a double.
4514                arguments[0] = DoubleToken.convert(arguments[0]);
4515            }
4516            Time targetTime = _timeEnteredCurrentState
4517                    .add(((DoubleToken) arguments[0]).doubleValue());
4518            Director director = getDirector();
4519            Time currentTime = director.getModelTime();
4520
4521            if (targetTime.compareTo(currentTime) <= 0) {
4522                // Note that current time may have passed the target time if
4523                // the director was unable to honor the exact timing request.
4524                // Presumably we are going to take a transition in this
4525                // firing, so there should be no time for next expiration.
4526
4527                // If the director supports superdense time, then we need to
4528                // ensure that we are not at microstep zero.
4529                if (director instanceof SuperdenseTimeDirector) {
4530                    int microstep = ((SuperdenseTimeDirector) director)
4531                            .getIndex();
4532                    if (microstep == 0) {
4533                        // Request a refiring at the current time.
4534                        director.fireAtCurrentTime(FSMActor.this);
4535                        return BooleanToken.FALSE;
4536                    }
4537                }
4538                _timeOfNextTimeoutExpiration = null;
4539                return BooleanToken.TRUE;
4540            }
4541
4542            // If the time of next expiration doesn't exist or is greater
4543            // than this target time, the request a firing.
4544            if (_timeOfNextTimeoutExpiration == null
4545                    || _timeOfNextTimeoutExpiration.compareTo(targetTime) > 0) {
4546                director.fireAt(FSMActor.this, targetTime);
4547                _timeOfNextTimeoutExpiration = targetTime;
4548            }
4549            return BooleanToken.FALSE;
4550        }
4551
4552        @Override
4553        public int getNumberOfArguments() {
4554            return 1;
4555        }
4556
4557        @Override
4558        public boolean isCongruent(Function function) {
4559            return function instanceof TimeoutFunction;
4560        }
4561
4562        @Override
4563        public String toString() {
4564            return "function(t:double):boolean";
4565        }
4566    }
4567
4568    /** The implementation of the timeout function as a token. */
4569    private class TimeoutFunctionToken extends FunctionToken {
4570        public TimeoutFunctionToken() {
4571            super(new TimeoutFunction(), new FunctionType(
4572                    _TIMEOUT_FUNCTION_ARGUMENT_TYPE, BaseType.BOOLEAN));
4573        }
4574    }
4575}