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}