Verifying Ptolemy II Discrete-Event Models using Real ... - CiteSeerX

5 downloads 17752 Views 733KB Size Report
models, and explain how the code generation infrastructure of Ptolemy II ..... of the generated output of a timer is not the same as the input, but is instead.
Verifying Ptolemy II Discrete-Event Models using Real-Time Maude 2 ¨ Kyungmin Bae1 , Peter Csaba Olveczky , Thomas Huining Feng3 , and Stavros Tripakis3 1

University of Illinois at Urbana-Champaign 2 University of Oslo 3 University of California, Berkeley

Abstract This paper shows how Ptolemy II discrete-event (DE) models can be formally analyzed using Real-Time Maude. We formalize in RealTime Maude the semantics of a subset of hierarchical Ptolemy II DE models, and explain how the code generation infrastructure of Ptolemy II has been used to automatically synthesize a Real-Time Maude verification model from a Ptolemy II design model. This enables a model-engineering process that combines the convenience of Ptolemy II DE modeling and simulation with formal verification in Real-Time Maude.

1

Introduction

Model-based design principles put the construction of models at the center of embedded system design processes [1,2]. Useful models are executable, providing simulations of system functionality, performance, power consumption, or other properties. Ideally, models are translated (code generated) automatically to produce deployable embedded software. Commercial examples of such modeling and code generation frameworks include Real-Time Workshop (from The MathWorks) and TargetLink (from dSpace), which generate code from Simulink models, and LabVIEW Embedded, from National Instruments. Models can also be used to guide formal verification, which can provide proofs of safety properties or identification of security vulnerabilities. Ptolemy II is a well-established modeling and simulation tool, developed at UC Berkeley, that provides a powerful and intuitive graphical modeling language to allow a user to build hierarchical models that combine different models of computations [3]. In this paper, we focus on discrete-event (DE) models, which are explicit about timing behavior of systems. Discrete-event modeling is a time honored and widely used approach for system simulation [4,5]. More recently, it has been proposed as basis for synthesis of embedded real-time software [6]. The Ptolemy II realization of DE has a rigorous formal semantics rooted in the fixed-point semantics of synchronous languages [7]. This paper describes our work on enriching a significant subset of hierarchical Ptolemy II DE models with formal verification capabilities using Real-Time

Maude [8,9] as back-end. Real-Time Maude is a high-performance tool that extends the rewriting-logic-based Maude [10] system to support the formal specification and analysis of object-based real-time systems. Real-Time Maude provides a spectrum of formal analysis methods, including rewriting for simulation purposes, reachability analysis, and linear temporal logic (LTL) model checking. In particular, we explain how we have enriched Ptolemy II DE models with formal verification capabilities by: 1. Formalizing the semantics of transparent hierarchical Ptolemy II DE models in Real-Time Maude. 2. Defining useful atomic state propositions, so that the Ptolemy user can specify temporal logic properties to be verified without understanding how Ptolemy models are represented in Real-Time Maude. 3. Using Ptolemy II’s code generation infrastructure [11] to automatically synthesize a Real-Time Maude verification model from a Ptolemy design model, and by explaining how both code generation and verification have been integrated into Ptolemy, so that a Ptolemy model can be verified within Ptolemy. This integration of Ptolemy II and Real-Time Maude enables a model-engineering process that combines the convenience of Ptolemy II modeling with formal verification in Real-Time Maude. The main contributions of our work are: – Enriching Ptolemy with formal verification capabilities to verify properties, such as the liveness property in Section 6, that cannot be checked using Ptolemy simulations. Furthermore, the synthesized verification model can be formally analyzed w.r.t. other properties (e.g., determinism, etc.). – We show how Real-Time Maude can define the semantics of synchronous languages with fixed-point semantics. These techniques should be useful for defining the formal semantics of other synchronous languages. Our semantics also provides a basis for extensions to, e.g., probabilistic Ptolemy models, that can then be subjected to statistical model checking using tools like VeStA [12]. Our work is conducted in the context of the NAOMI project [13], where LM ATL (Lockheed Martin Advanced Technology Laboratories), UC Berkeley, UIUC, and Vanderbilt University work together to develop a multimodeling design methodology. A key part of this project is the systematic use of model transformations and code generation to maintain consistency across models. Section 2 introduces Ptolemy II and Real-Time Maude. The Real-Time Maude semantics of Ptolemy II DE models is described in Section ??. Section ?? presents the atomic propositions that allow the user to specify his/her LTL properties without having the understand the Real-Time Maude translation of a Ptolemy model. Section ?? explains the Real-Time Maude code generation and integration into Ptolemy. Section 6 illustrates the use of our techniques to verify three Ptolemy DE models. Finally, Section 7 presents some related work and Section 8 gives some concluding remarks.

2

Preliminaries

This section presents some preliminaries on rewriting logic and Real-Time Maude (Section 2.1) and the selected discrete event subset of Ptolemy (Section 2.2). 2.1

Rewriting Logic and Real-Time Maude

Modeling. A Real-Time Maude timed module specifies a real-time rewrite theory [14] of the form (Σ, E, IR, TR), where: – (Σ, E) is a membership equational logic [10] theory with Σ a signature4 and E a set of confluent and terminating conditional equations. (Σ, E) specifies the system’s state space as an algebraic data type, and must contain a specification of a sort Time modeling the (discrete or dense) time domain. – IR is a set of (possibly conditional) labeled instantaneous rewrite rules specifying the system’s instantaneous (i.e., zero-time) local transitions, written rl [l] : t => t0 , where l is a label. Such a rule specifies a one-step transition from an instance of t to the corresponding instance of t0 . The rules are applied modulo the equations E.5 – TR is a set of tick (rewrite) rules, written with syntax rl [l] : {t} => {t0 } in time τ . that model time elapse. {_} is a built-in constructor of sort GlobalSystem, and τ is a term of sort Time that denotes the duration of the rewrite. The initial state must be a ground term of sort GlobalSystem and must be reducible to a term of the form {t} using the equations in the specifications. The Real-Time Maude syntax is fairly intuitive. For example, function symbols, or operators, are declared with the syntax op f : s1 . . . sn -> s. f is the name of the operator; s1 . . . sn are the sorts of the arguments of f ; and s is its (value) sort. Equations are written with syntax eq t = t0 , and ceq t = t0 if cond for conditional equations. The mathematical variables in such statements are declared with the keywords var and vars. We refer to [10] for more details on the syntax of Real-Time Maude. We make extensive use of the fact that an equation f (t1 , . . . , tn ) = t with the owise (for “otherwise”) attribute can be applied to a subterm f (. . .) only if no other equation with left-hand side f (u1 , . . . , un ) can be applied.6 In object-oriented Real-Time Maude modules, a class declaration class C | att1 : s1 , ... , attn : sn . 4 5

6

i.e., Σ is a set of declarations of sorts, subsorts, and function symbols E is a union E 0 ∪ A, where A is a set of equational axioms such as associativity, commutativity, and identity, so that deduction is performed modulo A. Operationally, a term is reduced to its E 0 -normal form modulo A before any rewrite rule is applied. A specification with owise equations can be transformed to an equivalent system without such equations [10].

declares a class C with attributes att1 to attn of sorts s1 to sn . An object of class C in a given state is represented as a term < O : C | att1 : val1 , ..., attn : valn > of sort Object, where O, of sort Oid, is the object’s identifier, and where val1 to valn are the current values of the attributes att1 to attn . In a concurrent object-oriented system, the state is a term of the sort Configuration. It has the structure of a multiset made up of objects and messages. Multiset union for configurations is denoted by a juxtaposition operator (empty syntax) that is declared associative and commutative, so that rewriting is multiset rewriting supported directly in Real-Time Maude. The dynamic behavior of concurrent object systems is axiomatized by specifying each of its transition patterns by a rewrite rule. For example, the rule rl [l] :

< O : C | a1 : 0, a2 : y, a3 : w, a4 : z > => < O : C | a1 : T, a2 : y, a3 : y + w, a4 : z >

defines a parameterized family of transitions (one for each substitution instance) which can be applied whenever the attribute a1 of an object O of class C has the value 0, with the effect of altering the attributes a1 and a3 of the object. “Irrelevant” attributes (such as a4, and the right-hand side occurrence of a2) need not be mentioned in a rule (or equation). A subclass inherits all the attributes and rules of its superclasses.

Formal Analysis. A Real-Time Maude specification is executable, and the tool offers a variety of formal analysis methods. The rewrite command simulates one behavior of the system up to a certain duration. It is written with syntax (trew t in time (implication), [] (“always”), (“eventually”), and U (“until”). The time-bounded model checking command has syntax (mc t |=t formula in time 0 then τ 0 = τ + d and n0 = 0, otherwise, τ 0 = τ and n0 = n + 1. An essential feature of Ptolemy II is hierarchy. This helps hide internal details of parts of a model, and therefore is crucial for managing model complexity, and for achieving modularity and scalability. Hierarchical models can be created using composite actors, which are refined into new diagrams. If all composite actors in the hierarchy belong to the DE domain, then the semantics of the hierarchical model is equivalent to that of the corresponding flattened model, where composite actors are replaced by their internal diagrams, with hierarchy removed.

Ptolemy II also allows another mechanism for building hierarchical models, using finite state machines, where every state of the machine can be refined into an internal diagram. These are called modal models in Ptolemy II. To illustrate the semantics of such models, consider the example of a modal model with two states, s1 and s2 , refined into diagrams A1 and A2 . The latter diagrams can be viewed as composite actors, and they have the same sets of input and output ports. Then, the semantics of this modal model can be thought of as that of a diagram consisting of A1 , A2 and Ac , where Ac is an actor modeling the finite state machine, that controls the mode of the rest of the diagram. If Ac is in state s1 , then the external inputs are routed to the inputs of A1 and the outputs of A1 are routed to the external outputs. During that time, A2 remains “frozen” in the sense that its state does not evolve. When the automaton Ac changes state to s2 , A1 becomes “frozen” while A2 becomes active. And so on.

Ptolemy code gen adapter infrastructure. Ptolemy II is built in a highly modular manner, with flexible and extensible components that communicate through generic interfaces. This type of inter-component communication introduces overhead, however, which generally results in component models that are slower than custom-built code. To regain the lost efficiency, Ptolemy II offers a code generation capability where inter-component communication is reduced by generating “monolithic” code with highly specialized components. The idea is to use static analysis to discover data types, buffer sizes, parameter values, execution schedules, and so on, and then partial evaluation to propagate this information in order to synthesize an efficient implementation that preserves the original semantics. Our code generation framework uses a adapter-based mechanism. A codegen adapter is essentially a component that generates code for a Ptolemy II actor. Each actor may have multiple associated adapters, one for each target language (C, VHDL, etc.). A adapter essentially consists of a Java class file and a code template file. The latter contains code blocks written in the target language. The codegen kernel uses the Java class of the adapter to harvest code blocks from the code template file. The Java class of the adapter determines which code blocks to harvest based on the actor instance-specific information (e.g., port type, port width, and parameter values). The main advantages of this scheme are, first, that it decouples the writing of Java code and target code (otherwise the target code would be wrapped in strings and interspersed with Java code), and second, that it allows using a target language specific editor while working on the target language code blocks. For details on the adapter-based code generation scheme, the reader is referred to http://ptolemy.eecs.berkeley.edu/ptolemyII/ptII7. 0/ptII7.0.1/doc/codegen.htm.

3

Formalizing the Semantics of Ptolemy DE Models in Real-Time Maude

This section presents the Real-Time Maude semantics of the targeted subset of Ptolemy given in Section 3.1. In order to convey our ideas without introducing too much detail, we first explain our semantics for flat Ptolemy models; that is, models without hierarchical actors (Section 3.2). Section 3.4 shows how this semantics is extended to the hierarchical setting. The entire exutable Real-Time Maude semantics is available at http://www.ifi.uio.no/RealTimeMaude/Ptolemy. 3.1

Supported Subset of Ptolemy

We currently support Real-Time Maude analysis of transparent discrete event (DE) Ptolemy models; that is, DE models where subdiagrams are also executed under the DE director. We support composite actors, modal models (hierarchical finite state machines), and the following atomic actors: finite state machine (FSM), timed delay, variable delay, clock, current time, timer, noninterruptible timer, pulse, ramp, timed plotter, set variable, and single event actors. We also support connections with multiple destinations, split signals, and both single ports and multi-input ports. 3.2

Representing Flat Ptolemy DE Models in Real-Time Maude

This section defines our semantics for flat Ptolemy models. Our Real-Time Maude semantics is given in an object-oriented style, where the global state has the form of a multiset {actors

connections

< global : EventQUEUE | queue : event queue >}

where – actors are objects corresponding to the actors in the system, – connections are the connections between the ports of the different actors, and – < global : EventQUEUE | queue : event queue > is an object whose queue attribute denotes the global event queue. This section explains the representation of these entities in Real-Time Maude, and Section ?? defines the semantics of the behaviors of the Ptolemy models. Actors. Each Ptolemy actor is modeled in Real-Time Maude as an object instance of a subclass of the following class Actor: class Actor | ports : Configuration, parameters : AssignMap, store : Memory .

The ports attribute denotes the set of ports of the actor. In our model, a port is modeled as an object, as shown below. The parameters attribute represents the parameters of the corresponding Ptolemy actor, together with their user-defined values/expressions, as a semicolon-separated set of terms of the form ’parametername |-> expression. The sort AssignMap is declared as follows: sort VarAssignment ValueAssignment . subsort ValueAssignment < VarAssignment . op _|->_ : VarId Exp -> VarAssignment [ctor prec 80] . op _|->_ : VarId Value -> ValueAssignment [ditto] . sort AssignMap ValueMap . --- set of variable assignments subsorts ValueAssignment < VarAssignment ValueMap < AssignMap . op emptyMap : -> ValueMap [ctor] . op _;_ : AssignMap AssignMap -> AssignMap [ctor assoc comm id: emptyMap prec 90] . op _;_ : ValueMap ValueMap -> ValueMap [ditto] .

The parameters attribute is not modified during system execution. Instead, the store attribute computes the values of the needed parameters in each iteration using a continuation style computation (see [?] for details). Specific Actors. The actors are all modeled as objects of subclasses of the sort Actor. Some actors, such as clocks and timed plotters, have an internal clock measuring “model time.” Such actors are represented as object instances of subclasses of the following class TimeActor, where current-time denotes the current model time: class TimeActor | current-time : Time .

subclass TimeActor < Actor .

Clocks. Ptolemy’s Clock actors have as parameters a clock period, and samesized arrays values and offsets. In each period, a clock generates events with given values and offsets within the period. For example, if the period is 5, the values are {3, 8} and the offsets are {2, 4}, then an event with value 3 is generated at times 2, 7, 12, 17, 22, . . . , and an event with value 8 is generated at times 4, 9, 14, . . . . As explained above, the Ptolemy parameters of an actor (period, offsets, and values for clock actors) are represented in the parameters attribute. The only additional attribute needed for the Real-Time Maude representation of clock actors is the attribute index keeping track of the “index” of the offsets and values arrays for the next event to be generated: class Clock | index : Nat .

subclass Clock < Actor .

For instance, the initial state of the clock described above would be decribed by the object in state < ’Clock : Clock | index : 0, store : emptyMap, parameters : (’period |-> # 5 ;

’offsets |-> {# 2.0, # 4.0} ;

’values |-> {# 3, # 8}), ports : (< ’output : OutPort | value : # 0, status : absent > < ’trigger : InPort | value : # 0, status : absent > < ’period : PortParameter | value : # 0, status : absent, paramName : ’period >) >

Current Time. Ptolemy’s current time actor produces an output token on each firing with a value that is the current model time. Since the superclass TimeActor already contains the current time in the current-time attribute, the CurrentTime subclass does not add any new attributes: class CurrentTime .

subclass CurrentTime < TimeActor .

Timed Plotter. A timed plotter records its received data values and the times they were received. In our representation, these values are recorded as a list (source: s1 time: t1 value: v1 ) ++ ... ++ (source: sn time: tn value: vn ) of triples (source: si time: ti value: vi ), denoting, respectively, the port from which the data was received, the time it was received, and the received data value. Since such as actor must keep track of the current-time, the TimedPlotter class is declared as a subclass of TimeActor: class TimedPlotter | event-history : EventHistory . subclass TimedPlotter < TimeActor . sort EventTriple EventHistory . subsort EventTriple < EventHistory . op source:_time:_value:_ : EPortId Time Value -> EventTriple . op emptyHistory : -> EventHistory . op _++_ : EventHistory EventHistory -> EventHistory [ctor assoc id: emptyHistory] .

Timed Delay. A timed delayed actor propagates an incoming event after a given time delay. In particular, if the delay parameter is 0.0, then the this actor produces on its output port the event consumed in the previous iteration with the same time stamp, if there was one; that is, there is a ”microstep” delay on the generation of the output event. Since the delay parameter is represented in the parameters attribute of Actor, this subclass does not add any attributes: class Delay .

subclass Delay < Actor .

Variable Delay. The variable delay actor works in a similar way as the timed delay actor, except that the amount of time delayed is specified by an incoming token through the delay port (a parameter port): class VariableDelay .

subclass VariableDelay < Actor .

Timer. The difference between a timer actor and a delay actor is that the value of the generated output of a timer is not the same as the input, but is instead given by the output parameter of this actor. The length of the delay is specified by the input: class Timer .

subclass Timer < Actor .

Noninterruptible Timer. A noninterruptible timer is similar to a normal timer, but with the difference that the noninterruptible timer actor delays the processing of a new input if it has not finished processing a previous input, while the Timer actor begins processing inputs immediately upon their arrival. The Real-Time Maude declaration of this class is class NonInterruptibleTimer | processing : Bool, wait-queue : TimeList . subclass NonInterruptibleTimer < Actor .

For this class, we need some attributes that keeps track of the state: processing is true when the timer has not finished processing previous inputs. The wait-queue is a list that stores (the values of) the inputs received while the timer is “busy.” This list is therefore a list of time values declared in the usual Maude style as follows: sort TimeList . subsort Time < TimeList . op emptyList : -> TimeList . op __ : TimeList TimeList -> TimeList [ctor assoc id: emptyList] .

Ramps. Each time a ramp actor fires, it generates an event with a value that is incremented by the specified step each iteration. The first output is given by the init parameter. The corresponding class Ramp is declared in the expected way: class Ramp | firstStep : Bool, subclass Ramp < Actor .

output-value : Value .

The firstStep attribute is used to separate between the first and the other events generated by the ramp, and output-value denotes the value of the last event generated by the ramp. Pulse. A pulse actor produces pulses with values given by the values parameter; the parameter indexes specifies when those values should be produced. A zero is produced when the iteration count does not match an index. For example, if values is {4, 11, 8} and the indexes parameter is {0, 2, 3}, the sequence of outputs will be 4, 0, 11, 8, 0, 0, . . .. The current-index attribute keeps tracks of the iteration count: class Pulse | current-index : Nat .

subclass Pulse < Actor .

Set Variable. This actor contains a variable that is set by a signal. In principle, this has a delayed parameter, so that if delayed is true, then the change of the variable value is only effected at the end of current toplevel iteration. If delayed is false, then the change to the value of the variable is performed immediately. However, this can result in nondeterminism if the variable values are observed by any other actor in the system. (This nondeterminism can be overcome by using the output of the set variable.) In our model, we haven’t taken the delayed parameter into account, and assume it to be false. The setv message is sent to change the value of the variable:

class SetVariable | variableName : VarId . subclass SetVariable < Actor . --- message to change a variables of the container. msg setv : VarId Value -> Msg .

Single Event. This actor produces an event with the specified value at the specified time: class SingleEvent .

subclass SingleEvent < Actor .

Finite State Machine (FSM) Actors. An FSM actor is a transition system containing a finite set of states and a finite set of transitions. A transition has a guard expression, and can contain a set of output actions and variable assignments. When an FSMActor is fired, there is never more than one enabled transition. If there is exactly one enabled transition then it is chosen and the actions contained by the transition are executed. Under the DE director, only one transition step is performed in each iteration. An FSM-Actor is then characterized by its current state and its set transitions: class FSM-Actor | currState : Location, initState : Location, transitions : TransitionSet . subclass FSM-Actor < Actor .

A location is the sort of the local “states” of the transition system. In particular, quoted identifiers (Qids) are state names: sort Location .

subsorts Qid < Location .

In our fragment of Ptolemy, we model the set of transitions as a semi-colonseparated set of transitions of the form l : s1 --> s2 {guard: g output: pi1 |-> ei01 ;...; pik |-> ei0k set: vj1 |-> ej10 ;...; vil |-> ejl0 }

for state/locations s1 and s2 , port names pi , variables vi , and expressions ei . The guard, output, and/or set parts may be omitted. The transition label l is a unique label within the actor for each transition, and is added in our semantics.8 In Real-Time Maude, such sets of transitions are declared as follows:

sort Transition TransitionSet TransitionId . subsort Transition < TransitionSet . subsort Qid < TransitionId . op _:_-->_‘{_‘} : TransitionId Location Location TransBody -> Transition [ctor] . op emptyTransitionSet : -> TransitionSet [ctor] . op _;_ : TransitionSet TransitionSet -> TransitionSet [ctor assoc comm id: emptyTransitionSet] . sort TransBody . op guard:_output:_set:_ : Exp AssignMap AssignMap -> TransBody [ctor] . 8

In our code generation, this label is automatically generated for each transition.

Ports. A port is represented as an object, with a name (the identifier of the port object), a status (unknown, present, or absent), and a value. We also have subclasses for input, output, and input/output ports: sorts PortId . subsort Qid < PortId < Oid .

--- names for (local) ports

class Port | status : PortStatus, value : Value . class InPort . class OutPort . class InOutPort .

subclass InPort < Port . subclass OutPort < Port . subclass InOutPort < InPort OutPort .

sort PortStatus . ops unknown present absent : -> PortStatus [ctor] .

We also support multiple input ports. A Port parameter is an input port whose input value updates a given actor parameter: class PortParameter | paramName : VarId . subclass PortParameter < InPort .

Connections. A connection is just a term po ==> pi1 ; . . . ; pin of sort Connection, where the pj s are either local port names or have the form a!p for a a relative name of an actor. Such a connection connects the output port po to all the input ports pi1 , . . . , pin Since connections appear in configurations, we let them be subsorts of the sort Object: sort Connection . op _==>_ : EPortId EPortIdSet -> Connection [ctor] . subsort Connection < Object . sorts EPortId . op _!_ : ActorID PortId -> EPortId [ctor] . sort EPortIdSet . subsort EPortId < EPortIdSet . op noPort : -> EPortIdSet [ctor] . op _;_ : EPortIdSet EPortIdSet -> EPortIdSet [ctor assoc comm id: noPort] .

The Global Event Queue. The global event queue is represented by an object < global : EventQUEUE | eventQueue : event queue > where event queue is an ::-separated ordered list of terms of the form set of events ; time to fire ; microstep

where the set of events is a set of events, each event characterized by the “global port name” where the generated event should be output and the corresponding value, time to fire denotes the time until the events are supposed to fire, and microstep is the additional “microstep” until the event fires: sort Event . op event : EPortId Value -> Event [ctor] . sort Events . subsort Event < Events . op noEvent : -> Events [ctor] . op __ : Events Events -> Events [ctor assoc comm id: noEvent] . sort TimedEvent . op _;_;_ : Events Time Nat -> TimedEvent [ctor] . sort EventQueue . subsort TimedEvent < EventQueue . op nil : -> EventQueue . op _::_ : EventQueue EventQueue -> EventQueue [ctor assoc id: nil] .

3.3

Specifying the Behavior of Flat DE Models

The behavior of Ptolemy DE models can be summarized as repeatedly performing the following actions: – Time is advanced until the remaining time until the firing of the first events in the global event queue is (0, 0). – Then an iteration of the system is performed. That is, 1. (Prefire) The events that are supposed to fire are added to the corresponding output ports; the status of all other ports is set to unknown. 2. (Fire) Then the fixpoint of all ports is computed by gradually increasing the knowledge about the presence/absence of inputs to and output from ports until a fixpoint is reached. 3. (Postfire) Finally, the actors with inputs or scheduled events are executed; states are changed and new events are generated and inserted into the global event queue. Our semantics uses three rules to make the various steps explicit. The following tick rule advances time until the time when the first events in the event queue are scheduled: vars SYSTEM CF PORTS : Configuration . var O : Oid . var EVTS : Events . var NZT : NzTime . var N : Nat . var NZ : NzNat . var P : PortId . var EVENTQUEUE : EventQueue . vars T T’ : Time . var PS : PortStatus . rl [tick] : {SYSTEM < global : EventQUEUE | queue : (EVTS ; NZT ; N) :: EVENTQUEUE >} => {delta(SYSTEM, NZT) < global : EventQUEUE | queue : (EVTS ; 0 ; N) :: delta(EVENTQUEUE, NZT) >} in time NZT .

In this rule, the first element in the event queue has non-zero delay NZT. Time is advanced by this amount NZT, and as a consequence, the (first component of the) event timer goes to zero. In addition, the function delta is applied to all the other objects (denoted by SYSTEM) in the system. The function delta defines effect of time elapse on the objects. This function is also applied to the other elements in the event queue, where it decreases the remaining time of each event set by the elapsed time NZT (x monus y equals max(0, x − y)): op delta : EventQueue Time -> EventQueue . eq delta((EVTS ; T ; N) :: EVENTQUEUE, T’) = (EVTS ; T monus T’ ; N) :: delta(EVENTQUEUE, T’) . eq delta(nil, T) = nil .

The function delta on configurations distributes over the elements in the configuration: op delta : Configuration Time -> Configuration . eq delta(none, T) = none . eq delta(NCF NCF’, T) = delta(NCF, T) delta(NCF’, T) .

This function must then be defined on single objects, as shown later. The next rule is a “microstep tick rule” that advances “time” with some microsteps if needed to enable the first events in the event queue: rl [shortTick] : {SYSTEM < global : EventQUEUE | queue : (EVTS ; 0 ; NZ) :: EVENTQUEUE >} => {SYSTEM < global : EventQUEUE | queue : (EVTS ; 0 ; 0) :: EVENTQUEUE >} .

Finally, when the remaining time and microsteps of the first events in the event queue are both zero, an iteration of the system can be performed: rl [executeStep] : {SYSTEM < global : EventQUEUE | queue : (EVTS ; 0 ; 0) :: EVENTQUEUE >} => {< global : EventQUEUE | queue : EVENTQUEUE > postfireAll(portFixPoints(addEventsToPorts(EVTS, prefireAll(SYSTEM))))} .

The function prefireAll initializes each actor before execution. In particular, it computes the current values of the variables in the store, and sets the status of each port to unknown. The operator addEventsToPorts inserts the events scheduled to fire into the corresponding output ports. The portFixPoints function then finds the fixed points for all the port (fire), and postfire “executes” the steps on the computed port fixpoints (postfire). postfire also changes the states of the objects and generates new events and inputs them into the global event queue. Therefore, to completely define the behavior of the actors, we must define the functions prefireAll, portFixPoints, postfire, and delta on the different objects in the system.

Initialize Actors. The prefireAll function calls the prefire function for each actor object in the state. The prefire function takes an additonal argument: the (smallest) class of the object. In this way, the prefire function on a subclass may also call the prefire function defined on the superclass: op prefireAll : Configuration -> Configuration [frozen (1)] . op prefire : Cid Object -> Configuration [frozen (2)] . var REST : Configuration . var OBJ : Object . eq prefireAll(OBJ REST) = prefire(class(OBJ), OBJ) prefireAll(REST) .

For the main superclass Actor, the prefire function just clears all the ports, that is, sets their status to unknown: eq prefire(Actor, < O : Actor | ports : PORTS >) = < O : Actor | ports : clearPorts(PORTS) > . op clearPorts : Configuration -> Configuration . eq clearPorts(< P : Port | status : PS > PORTS) = < P : Port | status : unknown > clearPorts(PORTS) . eq clearPorts(none) = none .

The prefire function for the different actors is defined by first (re-)initializing the store to compute the current values of the expressions for the parameters, and then calling prefire for the superclass Actor. For example, the prefire function is defined on Clock actors as follows: eq prefire(Clock , < O : Clock | parameters : (’period |-> ’values |-> = prefire(Actor , < O : Clock | store : ’period |-> k(EP) ’values |-> k(EV)

EP ; ’offsets |-> EO ; EV ; AM) >) ; ’offsets |-> k(EO) ; >) .

For FSM actors, the prefire function initializes the store to contain a value @guard(li ) |-> k(guardi ) for each transition with label li (and corresponding guard expression guardi ) that starts in the location STATE: eq prefire(FSM-Actor , < O : FSM-Actor | store : MEM, currState : STATE, transitions : TRANSSET >) = prefire(Actor , < O : FSM-Actor | store : evalGuards(STATE, TRANSSET) ; MEM >) .

Computing the Fixpoint for Ports. The idea behind the definition of the function portFixPoints, that computes the fixpoint for the values of all the ports, is simple. The state has the form portFixPoints(objects and connections), where initially, the only port information are the events scheduled for this iteration. For each possible case when the status of an unknown port can be determined to be either present or absent, there is an equation

eq portFixPoints(< O : ... | ports : < P : Port | status : unknown > PORTS, ... > connections and other objects) = portFixPoints(< O : ... | ports : < P : Port | status : present, value : ... > PORTS, ... > connections and other objects) .

(and similarly for deciding that input/output will be absent). The fixpoint is reached when no such “information-increasing” equation can be applied. Then, the portFixPoints operator is removed by using the owise construct of RealTime Maude9 : var OC : ObjectConfiguration . eq portFixPoints(OC) = OC [owise] .

The following equation propagates port status from a “known” output port to a connecting unknown input port. The present/absent status (and possibly the value) of the output port PI of actor O is propagated to the input port PI’ of the actor O’ through the connection (O ! PI) ==> ((O’ ! PI’) ; EPIS): ceq portFixPoints( < O : Actor | ports : < PI : OutPort | status : PS , value : V > PORTS > ((O ! PI) ==> ((O’ ! PI’) ; EPIS)) < O’ : Actor | ports : < PI’ : InPort | status : unknown > PORTS’ > REST) = portFixPoints(< O : Actor | > ((O ! PI) ==> ((O’ ! PI’) ; EPIS)) < O’ : Actor | ports : < PI’ : InPort | status : PS, value : V > PORTS’ > REST) if PS =/= unknown .

When the status of port PI has been decided, the value of each subexpression isPresent(PI) in the store is replaced by # true (resp., # false for absent ports): eq portFixPoints( < O : Actor | ports : < PI : Port | status : present > PORTS, store : MI |-> k(isPresent(PI) -> K) ; MEM > REST) = portFixPoints( < O : Actor | store : MI |-> k(# true -> K) ; MEM > REST) . 9

The restriction to object configurations is crucial, as it ensures that all prefire and addEventsToPorts applications have been performed before the equation below is taken.

The portFixPoints function must then be defined for each kind of actor to decide whether the actor produces any output in a given port. For example, the timed delay actor does not produce any output in this iteration as a result of any input. Therefore, if its status is unknown (that is, the delay actor did not schedule an event for this iteration), its output port should be set to absent: eq portFixPoints( < O : Delay | ports : < PI : OutPort | status : unknown > PORTS > REST) = portFixPoints( < O : Delay | ports : < PI : OutPort | status : absent > PORTS > REST) .

We have run this with input only to the step port, and are somewhat surprised to find that output is generated even if the trigger port has no input!

Actors, such as variable delay, clock actors, timers, etc., that generate “delayed” events as a result of receiving input, have the same definition of portFixPoint. Other actors generate immediate output when receiving input. For example, a Ramp actor generates an output value which equals the previous value plus the current value of step if it gets input from either its port trigger or its step: eq portFixPoints( < O : Ramp | count : N, output-value : V, store : ’init |-> VI ; ’step |-> VS, ports : < PI : InPort | status : present > < ’output : OutPort | status : unknown > PORTS > REST) = portFixPoints( < O : Ramp | ports : < PI : InPort | > PORTS < ’output : OutPort | status : present, value : if N > 0 then V + VS else VI fi > > REST) . eq portFixPoints( < O : Ramp | ports : < < < REST) = portFixPoints( < O : Ramp | ports : < < REST) .

’trigger : InPort | status : absent > ’step : InPort | status : absent > ’output : OutPort | status : unknown > PORTS >

’trigger : InPort | > < ’step : InPort | > ’output : OutPort | status : absent > >

Likewise, when the current time actor gets an input, it outputs the current model time, given by its current-time attribute: ceq portFixPoints( < O : CurrentTime | current-time : T, ports : < PI : InPort | status : PS > < PI’ : OutPort | status : unknown > > REST) = portFixPoints( < O : CurrentTime | ports : < PI : InPort | >

< PI’ : OutPort | status : PS , value : # T > REST) if PS =/= unknown .

Likewise, the set variable actor generates output if and only if it receives input in its only input port: ceq portFixPoints( < O : SetVariable | ports : < < REST) = portFixPoints( < O : SetVariable | ports : < < REST) if PS =/= unknown .

PI : InPort | status : PS , value : V > PI’ : OutPort | status : unknown > >

PI : InPort | > PI’ : OutPort | status : PS, value : V > >

For the FSM actor, the portFixPoints function should check whether some of the guard expressions entered into the store by prefire evaluates to # true. If so, the corresponding transition should be applied. That is, for portFixPoints, the expressions in the output list of that transition must be computed. Hence, these expressions are added to the store for further evaluation. Furthermore, we must “remember” the transition taken, so that postFire can do the corresponding updates. Therefore, we add to the store the next location and the variable assignment expressions in the transition “taken”: eq portFixPoints( < O : FSM-Actor | ports : < PI : InPort | status : present > PORTS, store : @guard(TI) |-> # true ; MEM, transitions : ( (TI : STATE --> STATE’ {guard: TG output: OL set: AL}) ; TRANSSET) > REST) = portFixPoints( < O : FSM-Actor | ports : < PI : InPort | > PORTS, store : @next(STATE’) ; evalOut(OL) ; evalSet(AL) ; clearGuards(MEM) > REST) .

The other transition guards to be evaulated can be cleared from the store of values to be computed. The following equation updates the outgoing port PI for which the output value V has been computed. All other outgoing ports are set to absent at the last step, where no @out exists in the store. In the left-hand side, we make sure that there is some input to the FSM actor. eq portFixPoints( < O : FSM-Actor | ports : < PI’ : InPort | status : present > < PI : OutPort | > PORTS, store : @out(PI) |-> V ; MEM > REST)

= portFixPoints( < O : FSM-Actor | ports : < PI’ : InPort | > < PI : OutPort | status : present , value : V > if noOutValue(MEM) then setUnknownOutPortsAbsent(PORTS) else PORTS fi, store : MEM > REST) .

Other equations for portFixPoints on FSM actors specify the cases when all inputs are absent or when no transition can be enabled. In these cases, every output ports should be set to absent. The following equation does the process if every input ports are absent and any output port is unknown. ceq portFixPoints( < O : FSM-Actor | ports : < PI : InPort | status : absent > < PI : OutPort | status : unknown > PORTS > REST) = portFixPoints( < O : FSM-Actor | ports : < PI : InPort | > < PI : OutPort | status : absent > setUnknownOutPortsAbsent(PORTS) > REST) if allInputPortsAbsent(PORTS) .

The other case is not so trivial, since we need to consider undecidable situation so that a value of guard expression could not be decided. That is typically caused by unknown input ports. However, the solution is surprisingly simple. We can use that a guard expression is not reduced to a value if there exists an unknown component in the expression. Therefore, we only need to check if every guard expression is reduced to false; if a guard expression is not reduce to both true and false, it means undecidable situation. The following equation takes care this: ceq portFixPoints( < O : FSM-Actor | ports : < PI : InPort | status : present > PORTS, store : @guard(TI) |-> # false ; MEM > REST) = portFixPoints( < O : FSM-Actor | ports : < PI : InPort | > setUnknownOutPortsAbsent(PORTS), store : clearGuards(MEM) > REST) if allGuardsFalse(MEM) .

Postfire. Finally, the postfireAll function corresponds to “postfire” in Ptolemy. The internal states are updated, and new events are generated and entered into the event queue. The prefireAll function distributes over the actor objects in the configuration, and becomes the prefire function on such objects. Just like the prefire function, the postfire function takes as first argument the class name of the object, so that the prefire function of objects of a subclass can also call prefire for the superclass:

op eq eq eq

postfireAll : Configuration -> Configuration . postfireAll(CX:Connection CF) = CX:Connection postfireAll(CF) . postfireAll(OBJ CF) = postfire(class(OBJ), OBJ) postfireAll(CF) [owise] . postfireAll(none) = none .

op postfire : Cid Object -> Configuration .

The prefire function must then be defined for each class. Sometimes, postfire generates a new event with value v that should fire at time t and microstep n from the current time. In these cases, postfire puts the new event into the event queue and has the form eq postfire(C, < O : C | ports : < PI : OutPort | > PORTS, ... >) < global : EventQueue | queue : EQ > = < O : C | ... > < global : EventQueue | queue : addEvent(event(O . PI, v), t, n EQ) > .

where the function addEvent adds the new event into the correct place in the event queue: op addEvent : Event Time Nat EventQueue -> EventQueue . --- add event first: ceq addEvent(EVENT, T, N, (EVTS ; T’ ; N’) :: EQ) = ((EVENT ; T ; N) :: (EVTS ; T’ ; N’) :: EQ) if T < T’ or (T == T’ and N < N’) . --- add event to the first event: eq addEvent(EVENT, T, N, (EVTS ; T ; N) :: EQ) = (EVENT EVTS ; T ; N) :: EQ . --- add event to rest of queue: ceq addEvent(EVENT, T, N, (EVTS ; T’ ; N’) :: EQ) = ((EVTS ; T’ ; N’) :: addEvent(EVENT, T, N, EQ)) if (T’ < T) or (T’ == T and N’ < N) . eq addEvent(EVENT, T, nil) = (EVENT ; T ; 0) .

The postfire function is defined on the superclass Actor to update port variables, and to clear the store (so that the different stores do not add to the state space during model checking): eq postfire(Actor , < O : Actor | ports : PORTS, parameters : VAL, store : MEM >) = < O : Actor | parameters : updateParam(VAL, PORTS), store : emptyMap > .

Delay. If a time delay actor has input in its ’input port, then it generates an event with a delay equal to the current value of the ’delay parameter expression. If this delay is 0.0, the microstep is 1, otherwise the microstep is 0:

eq postfire(Delay , < O : Delay | ports : < ’input : InPort | status : present, value : V > < ’output : OutPort | >, store : ’delay |-> TV ; MEM >) < global : EventQueue | queue : EQ > = postfire(Actor , < O : Delay | >) . < global : EventQueue | queue : addEvent(event(O ! ’output, V), toTime(TV), if toTime(TV) == 0 then 1 else 0 fi, EQ) > .

Clock. When a clock actor is scheduled, that is, produces output, the postfire function should schedule the next event, and update the index variable: ceq postfire(Clock , < O : Clock | ports store index < global : EventQueue = postfire(Actor , < O : < global : EventQueue

: : : |

< PI : OutPort | status : present > PORTS, (’offsets |-> VO ; ’values |-> VV ; MEM), NI >) queue : EQ >

Clock | index : NI + 1 >) | queue : addEvent(event(O ! PI, VV(#(s NI))), TIME-TO-FIRE, if TIME-TO-FIRE == 0 then 1 else 0 fi, EQ) > if TIME-TO-FIRE := toTime((VO(#(s NI))) - (VO(# NI))) /\ ((# NI + # 1) lessThan (VO .. ’length(()) )) == # true .

ceq postfire(Clock, < O : Clock | ports store index < global : EventQueue = postfire(Actor , < O : < global : EventQueue

: : : |

< PI : OutPort | status : present > PORTS, (’period |-> VP ; ’offsets |-> VO ; ’values |-> VV ; MEM), NI >) queue : EQ >

Clock | index : 0 >) | queue : addEvent(event(O ! PI, VV(# 0)), TIME-TO-FIRE, if TIME-TO-FIRE == 0 then 1 else 0 fi, EQ) > if TIME-TO-FIRE := toTime((VP - (VO(# NI))) + (VO(# 0))) /\ ((# NI + # 1) equals (VO .. ’length(()) )) == # true /\ (VP lessThan Infinity) == # true .

Current time. The current time actor does not have a state that is changed, except by the passage of time, and does not schedule later events. Therefore, postfire does not affect CurrentTime objects: eq postfire(CurrentTime, < O : CurrentTime | >) = postfire(Actor, < O : CurrentTime | >) .

Ramp. The ramp actor updates its internal state by setting the output value to the previous output value plus the current evaluation of the expression defining

the value of the ’step parameter (unless this is the first round, in which case the output-value will be set to the current evaluation of the ’init expression). prefire only changes the state if the actor actually was fired during the iteration (one of the actor’s output ports have output a value): eq postfire(Ramp, < O : Ramp | store : ’init |-> VI ; ’step |-> VS, firstStep : B, output-value : V, ports : < PI : OutPort | status : present > PORTS >) = postfire(Actor, < O : Ramp | firstStep : false, output-value : if B then VI else V + VS fi >) .

If the ramp actor was not enabled, another equation just does not update the values. Timer. If a timer actor received input from its input port, it generates an event with value equal to the current value of the output parameter. The event is scheduled for a time from now given by the value of the input port: eq postfire(Timer, < O : Timer | store : ’output |-> V ; MEM, ports : < ’input : InPort | status : present, value : TV > PORTS >) < global : EventQueue | queue : EQ > = postfire(Actor, < O : Timer | >) < global : EventQueue | queue : addEvent(event(O ! ’output, V), toTime(TV), if toTime(TV) == 0 then 1 else 0 fi, EQ) > . eq postfire(Timer, < O : Timer | ports : < ’input : InPort | status : absent > = postfire(Actor, < O : Timer | >) .

PORTS >)

Timed Plotter. At the end of an iteration, the timed plotter records any input through its multi-input port by adding triple source: channel time: current time value: value of input for each such input to its event-history attribute. This job is done by the auxiliary function genEventHistory which traverses each channel in the multi-input port and generates a “history triple” for those channels where input were present: eq postfire(TimedPlotter, < O : TimedPlotter | current-time : T, event-history : EH, ports : < PI : MultiInPort | channels : CHS > >) = postfire(Actor, < O : TimedPlotter | event-history : EH ++ genEventHistory(T, CHS) >) . op genEventHistory : Time ChannelSet -> EventHistory . eq genEventHistory(T, [EPI,present,V] ; CHS) = (source: EPI time: T value: V) ++ genEventHistory(T, CHS) . eq genEventHistory(T, CHS) = emptyHistory [owise] .

FSM Actors. An FSM actor does not generate future events, but postfire updates the internal state (location and variables) of the actor if it has gotten input. eq postfire(FSM-Actor, < O : FSM-Actor | parameters : VAL, currState : STATE, store : MEM >) = postfire(Actor, < O : FSM-Actor | parameters : updateVars(VAL, MEM), currState : updateState(STATE, MEM) >) . op eq = eq

updateVars : AssignMap Memory -> AssignMap . updateVars((VI |-> E) ; AM, (@set(VI) |-> V) ; MEM) (VI |-> V) ; updateVars(AM, MEM) . updateVars(AM, MEM) = AM [owise] .

op updateState : Location Memory -> Location . eq updateState(STATE, @next(STATE’) ; MEM) = STATE’ . eq updateState(STATE, MEM) = STATE [owise] .

Note that if no input was present, then updateVars and updateState do nothing, since this @set and @next are only added to the store (in portFixPoints) when some transition is taken. Defining Timed Behavior. Finally, we must define the function delta, that specifies the effect of time elapse, on single actors. Time only affects the internal state of TimeActor objects (CurrentTime and TimedPlotter), that have an internal “clock” attribute current-time, by increasing the value of current-time according to the elapsed time: eq delta(< O : TimeActor | current-time : T >, T’) = < O : TimeActor | current-time : T + T’ > .

Time elapse does not affect other actors and connections: eq delta(O:Object, T) = O:Object [owise] .

Defining Initial Events. The initial state is defined as the term: {init(< global : EventQueue | queue : nil >

connections

actor objects }

where init adds the initial events of the system to the global event queue. In out flat subset, only Single and Clock actors generate such initial events: op init : Configuration -> Configuration . eq init(< O : SingleEvent | parameters : ’value |-> V1 ; ’time |-> V2 > < global : EventQueue | queue : EQ > REST) = < O : SingleEvent | > init(< global : EventQueue | queue : addEvent(event(O ! ’output, V1), toTime(V2), 0, EQ) > REST) .

eq init(< O : Clock | parameters : ’value |-> V1 ; ’offsets |-> V2 > < global : EventQueue | queue : EQ > REST) = < O : Clock | > init(< global : EventQueue | queue : addEvent(event(O ! ’output, V1(# 0)), toTime(V2(# 0)), 0, EQ) > REST) . eq init(CF) = CF [owise] .

3.4

Extending the Semantics to Hierachical Ptolemy DE Models

Ptolemy DE models can be hierarchial because 1. modal models are state machines where each “state” is (or “refines to”) a Ptolemy diagram, and 2. some actors are composite actors that are themselves Ptolemy diagrams. This section briefly outlines how the above Real-Time Maude semantics has been extended to hierarchical Ptolemy models. We refer to http://www.ifi. uio.no/RealTimeMaude/Ptolemy for details. Representing Hierarchical Models. Our Real-Time Maude representation of hierarchical actors preserve the hierarchical structure of Ptolemy models. Composite actors are modeled as object instances of the class CompositeActor, which is a subclass of the class Actor. This class adds only one attribute, innerActors, which denotes the inner actor objects and connections in the composite actor: class CompositeActor | innerActors : Configuration . subclass CompositeActor < Actor .

As mentioned in Section 2.2, Ptolemy II internally transforms a modal model to a composite actor, consisting of the refinement actors of the states, and a “controller” FSM corresponding to the “modal state machine”. We therefore represent modal models in this way, as a CompositeActor containing the controller FSM, the refined actors, and the connections in the innerActors attribute, and with an additional attribute controller pointing to the controller FSM in innerActors, and with the additional refinementSet attribute mapping each state in the modal model to its refinement: class ModalModel | controller : Oid, refinement : RefinementSet . subclass ModalModel < CompositeActor .

In addition, the definition of the basic Actor class adds an attribute status which can have the value enabled or disabled to reflect that any actor may be disabled as a result of being contained in a refinement of a state in a modal

model which is “frozen.” The equations for prefire, portFixPoints, etc., only apply to objects whose status is enabled. In the hierarchical setting, each actor can be uniquely identified by its global actor identifier, which is a list o1 . o2 . . . . . on of object names, where o1 is the name a toplevel actor, and oi+1 (for i ≥ 1) is the (local) identifier of an actor which is part of the innerActors : sort ActorID . subsort Oid < ActorID . op _._ : ActorID ActorID -> ActorID [ctor assoc] .

Extracting and Adding Event to the Event Queue. In the flat setting, each actor is at the same hierarchical level as the global EventQueue. Each actor therefore has direct access to the event queue, so that at the start of an iteration, the scheduled events could be directly inserted into the corresponding actor ports (by the function addEventsToPorts), and actors could add generated events directly into the global event queue (by postfire). In the hierarchical case, an actor that receives or generates an event from/to the global event queue can be located deep down in the actor hierarchy. Events communicated between the actors and the global event queue may therefore cross hierarchical boundaries. We have modeled this “traveling” of events by “method calls” or “messages”. For example, inserting an event into the output port p of some actor with global actor identifier g corresponds to generating the message active-evt(event(g ! p), v). Likewise, an event communicated from actor to the event queue has the form schedule-evt(event, time, microstep): msg schedule-evt : Event Time Nat -> Msg . msg active-evt : Event -> Msg .

For example, when an actor generates an event, it creates an schedule-evt “message”: eq postfire(Delay, < O : Delay | status : enabled, ports : < ’input : InPort | status : present, value : V > < ’output : OutPort | > PORTS, store : ’delay |-> TV ; MEM >) = schedule-evt(event(O ! ’output, V), toTime(TV), if toTime(TV) == 0 then 1 else 0 fi) postfire(Actor, < O : Delay | >) .

Such an event is propagated towards the top of the actor hierarchy by the following equation, in which a composite actor inside whose innerActors attribute the schedule-evt message resides moves the message one level out: eq < O : CompositeActor | innerActors : CF schedule-evt(event(AI ! PI, V), T, N) > = < O : CompositeActor | innerActors : CF > schedule-evt(event((O . AI) ! PI, V), T, N) .

Finally, when the schedule-evt request has been propagated to the top level in the hierarchy, it is entered into the event queue: eq < QUE : EventQUEUE | queue : EQ > schedule-evt(EVENT, T, N) = < QUE : EventQUEUE | queue : addEvent(EVENT, T, N, EQ) > .

The propagation of active-evts from the event queue to some inner actor is analoguous. It is worth remarking that careful use of sorts ensure that our equations remain confluent. Defining prefire, portFixPoints, and postfire for hierarchical models. The prefire function is unchanged in the hierarchical setting. For the new classes, the prefire function propagates to the inner actors. For modal models, prefire also sets the status attribute of the inner actors according to the current state of the controller: eq prefire(CompositeActor, < O : CompositeActor | innerActors : CF >) = prefire(Actor, < O : CompositeActor | innerActors : prefireAll(CF) >) . eq prefire(ModalModel, < O : ModalModel | controller : CO, refinement : REFS, innerActors : ACTS < CO : FSM-Actor | status : STAT, currState : STATE > >) = prefire(CompositeActor, < O : ModalModel | innerActors : < CO : FSM-Actor | status : disabled > setStateRefinement(STATE, REFS, ACTS) >) .

The controller is temporally disabled to allow the refinement actors to be executed first according to Ptolemy semantics. The controller is set to be enabled in portFixPoints. postfire is modified so that disabled actor do not change their state or generate new events. For a hierarchical actor, postfire just propagates to its inner actors: eq postfire(CompositeActor, < O : CompositeActor | status : enabled, innerActors : CF >) = postfire(Actor, < O : CompositeActor | innerActors : postfireAll(CF) >) .

Port fixpoints. The extension of the portFixPoints function to the hierarchical case is more subtle. The portFixPoints function should distribute to the subdiagrams of composite actors, to compute the fixpoint of these subsystems. However, an equation of the form eq portFixPoints(< O : CompositeActor | innerActors : IA, ... > REST) = portFixPoints(< O : CompositeActor | innerActors : portFixPoints(IA), ... > REST) .

would be applicable again when the inner portFixPoints function disappears, leading to nontermination (and non-applicability of the owise equation defining the end of the fixpoint computation). We therefore define the portFixPoints function in two stages: 1. In the “initializing” stage, the portFixPoints function is propagated to subdiagrams of composite actors. 2. In the second stage, portFixPoints works similarly to the flat setting. portFixPoints equations are applied to add information about the status of the ports. An owise equation is again used to end the fixpoint computation when no equation adding new information about the ports can be applied. However, to end the fixpoint computation of a (sub)system, the fixpoint computations of the subsystems of composite actors must have finished. Therefore, this owise equation should only be applied when there is no portFixPoints operator in the innerActors of the CompositeActors in the system. To separate the two stages, we add an additional parameter, which is either init or inited, to portFixPoints: op portFixPoints : InitStatus Configuration -> Configuration . sort InitStatus . ops init inited : -> InitStatus [ctor] .

When the first parameter of portFixPoints is init, the function should be applied to the subconfigurations of composite actors: eq portFixPoints(init , OBJECTS) = portFixPoints(inited , computeInnerFixPoints(OBJECTS)) .

The function computeInnerFixPoints calls portFixPoints for all innerActors in OBJECTS: op computeInnerFixPoints : Configuration -> Configuration . eq computeInnerFixPoints(< O : CompositeActors | innerActors : IA > < O : CompositeActors | innerActors : portFixPoints(init ,IA) > computeInnerFixPoints(REST) . eq computeInnerFixPoints(REST) = REST [owise] .

REST) =

The “ordinary” equations for portFixPoints for flat systems are inherited in the hierarchical case, with the modification that they only apply to inited portFixPointss, such as in, e.g.: eq portFixPoints(inited , < O : Delay | ports : < PI : OutPort | status : unknown > PORTS > REST) = portFixPoints(inited, < O : Delay | ports : < PI : OutPort | status : absent > PORTS > REST) .

We must then define the portFixPoints function for composite actors (including ModalModel actors). In particular, an input to the compsite actor will lead to an input in one of its subactors, and an output at a subactor will lead to

an output from the containing composite actor. (We use the special nale ’parent’ to denote the containing actor of an actor in port names.) It could happen that the inner fixpoint computation has finished when this information is added to the out input port. In that case, the portFixPoints must again be called to (re-) compute the fixpoint of the inner diagram:

ceq portFixPoints(inited , < O : CompositeActor | ports : < P : InPort | status : PS, value : V > PORTS, innerActors : (parent ! P) ==> (O’ ! P’) < O’ : Actor | ports : < P’ : InPort | status : unknown, value : V’ > PORTS2 > REST2 > REST) = portFixPoints(inited, < O : CompositeActor | ports : < P : InPort | > PORTS, innerActors : portFixPoints(inited, (parent ! P) ==> (O’ ! P’) < O’ : Actor | ports : < P’ : InPort | status : PS, value : if PS == absent then V’ else V f REST2) REST) if PS =/= unknown .

ceq portFixPoints(inited , < O : CompositeActor | ports : < P : InPort | status : PS, value : V > PORTS, innerActors : portFixPoints (inited, (parent ! P) ==> (O’ ! P’) < O’ : Actor | ports : < P’ : InPort | status : unknown, value : V’ > PORTS2 > REST2) > REST) = portFixPoints(inited, < O : CompositeActor | ports : < P : InPort | > PORTS, innerActors : portFixPoints(inited, (parent ! P) ==> (O’ ! P’) < O’ : Actor | ports : < P’ : InPort | status : PS, value : if PS == absent then V’ else V f REST2) > REST) if PS =/= unknown .

Likewise, an inner actor can generate output for the containing actor: ceq portFixPoints(inited ,

< O : CompositeActor | ports : < P : OutPort | status : unknown, value : V > PORTS, innerActors : (O’ ! P’) ==> (parent ! P) < O’ : Actor | ports : < P’ : OutPort | status : PS, value : V’ > PORTS2 > REST2 > REST) =

portFixPoints(inited, < O : CompositeActor | ports : < P : OutPort | status : PS, value : if PS == present then V’ else V fi > innerActors : (O’ ! P’) ==> (parent ! P) < O’ : Actor | ports : < P’ : OutPort | > PORTS2 > REST2 > REST) if PS =/= unknown .

Finally, the computation of a subsystem is finished when the fixpoint computation of its subsystems is finished, and no more equations adding information to the status of the ports can be performed: ceq portFixPoints(inited, OBJECTS) = OBJECTS if innerFixpointsComputed(OBJECTS) [owise] . op innerFixPointsComputed : Configuration -> Bool . eq innerFixPointsComputed( < O : CompositeActor | innerActors : portFixPoints(X, REST) > REST2) = false . eq innerFixPointsComputed(REST) = true [owise] .

4

Formal Analysis of Ptolemy Models

In this section, we show that how a property of a Ptolemy model can be expressed as user friendly way, and the property can be verified using Real-Time Maude semantics. 4.1

Model checking in Real-Time Maude

As mentioned in Section 2.1, Real-Time Maude supports linear temporal logic model checker. A general LTL formula is given by Real-Time Maude, and state propositions should be defined for each model by an equation. Then, model checking command with an initial state and a formula returns a verification result. For example, consider a safety condition of a traffic light system which means that both a car light and a pedestrian light will be never green at the same time. [] ~ (Car light is green /\ Pedestrian light is green )

In the above formula, Car light is green and Pedestrian light is green are atomic propositions. To tell a model checker whether a given state pattern S(x1 , . . . , xn ) satisfies a parametrized atomic proposition P (x1 , . . . , xk ), it

is enough to define an equation S(x1 , . . . , xn ) |= P (x1 , . . . , xk ) = true. Note that the operator |= is defined like the following: sorts State Prop . op _|=_ : State Prop -> Bool [frozen] .

For example, If the car light in the model are FSM-Actors, the state proposition could be defined like the following: var CF : Configuration . eq {< ’CarLight : FSM-Actor | currState : ’green > CF} |= Car light is green = true . eq {CF} |= Car light is green = false [owise] .

Pedestrian light is green can be defined by the same way, so that the model checking command will be like the following if init is a term describing the given ptolemy model: (mc {init} |=u [] ~ (Car light is green /\ Pedestrian light is green ) .)

4.2

Ptolemy property pattern in Real-Time Maude

This section defines a property specification pattern for supporting user-friendly way to describe a property of Ptolemy model. In general, to express a LTL property of a Ptolemy model, an user need to define equations for basic blocks of properties, i.e., atomic propositions. It makes a verification process much harder for usual Ptolemy users because users requires to know Real-Time Maude and details of translated representation of the given model. The above difficulties can be avoid for most of situation, by defining a property specification pattern for each class of actors. Since each actor can be uniquely determined by an actor id, the pattern consists of an actor id and a actor-specific patterns as follows. sort ActorPattern . op __ : ActorID ActorPattern -> Prop [ctor] .

Each interesting properties of Ptolemy models, such as parameters and states of FSM-Actors, could define ActorPattern, respectively, and OO hierarchy of actors enable to do it by minimal definition 10 . Parameters of an Actor. A parameter of an Actor can represent a state of specific point in most cases. A property pattern with an actor id O looks like O | var1 = value1 , var2 = value2 , . . . , varn = valuen which can be defined in Real-Time Maude like the following: 10

e.g., to define the pattern for parameters, we can consider only Actor class, since it has parameters attributes and every other actor class is a subclass of it.

op |_ : VarCheckSet -> ActorPattern [ctor] . sort VarCheck VarCheckSet . subsort VarCheck < VarCheckSet . op _=_ : VarId Exp -> VarCheck [ctor] . op ‘(‘) : -> VarCheckSet [ctor] . op _‘,_ : VarCheckSet VarCheckSet -> VarCheckSet [ctor assoc comm id: ()] .

A VarCheckSet expresses a comma-separated equation set, where an empty set is (). The equations for this pattern is defined by: var CF : Configuration . var O : Oid . var I : VarId . var E E’ : Exp . var VM : ValueMap . var VS : VarCheckSet . ceq {< O : Actor |= O | (I = = {< O : Actor if E equals E’ eq {< O : Actor eq {< O : Actor

| parameters E’, VS) | parameters == # true . | parameters | > CF} |= O

: (I |-> E) ; VM > CF} : VM > CF} |= O | VS : VM > CF} |= O | () = true . | VS = false [owise] .

The equations means that a given parameter pattern is true (i) if it is empty, or (ii) all the values in the pattern matches with the parameters in the actor. States of FSM-Actor. FSM-Actors have its own state, and it is denoted by current state attribute of FSM-Actor. A property pattern for a FSM-Actor F O looks like F O @ State The pattern is true only if the current state of a FSM-Actor F O is State : Exp, which is defined by: var CF : Configuration .

var O : Oid .

var L : Location .

op @_ : Location -> ActorPattern [ctor] . eq {< O : FSM-Actor | currState : L > CF} |= O @ L = true . eq {< O : FSM-Actor | > CF} |= O @ L = false [owise] .

Inner Actors. We also need to access inner actors of an actor for verifying hierarchical model of Ptolemy. It is sufficient to pass given atomic proposition to inner actors for a CompositeActor, which is defined by the following. var CF ACTS : Configuration . var O : Oid . var AI AI’ : ActorID . var AP : ActorPattern . eq < O : CompositeActor | innerActors : ACTS > CF |= (O . AI) AP = ACTS |= AI AP .

Modal modal state. A top level of a ModalModel actor is the same with FSM-Actor in the user-level, but the translation result is slightly different with that: the top level FSM-Actor is also one of inner actors, and a controller attribute denote that. Hence, a property pattern is exactly the same with the FSM-Actor case, but it should be transfered to the controller FSM actor, so that the equation for the pattern is defined by: var ACTS CF : Configuration .

vars O CO : Oid . var L : Location .

eq < O : ModalModel | controller : CO, innerActors : ACTS > CF |= O @ L = ACTS |= CO @ L .

Scope. A formula for inner actors is simplified with the actor scope feature. In the previous definition, to define a proposition for inner actors, we need to write identifies for every ancestor. It results very long formula if we want to verify a properties of inner actors. To avoid it, A scope operator is defined as follows: op _:_ : ActorID Formula -> Formula .

The formula restricted by a scope operator is just a syntactic sugar of existing formula. It will be automatically reduced to an usual formula by the following rewriting equations. var AI : ActorID . vars F1 F2 : Formula . eq eq eq eq

AI AI AI AI

4.3

: : : :

(~ F1) = ~ (AI : F1) . (F1 /\ F2) = (AI : F1) /\ (AI : F2) . (O F1) = O (AI : F1) . (F1 U F2) = (AI : F1) U (AI : F2) .

Example

Consider a simple traffic light model of Ptolemy in Figure 2. In the above model, each traffic light is represented by set of variables, e.g., Pred,Pgrn, Pred represents the pedestrian light, which are controlled by relating FSM-Actors. In this model, the safety condition we are interested in is that there is no case such that both a car light and a pedestrian light are green. It is represented like the following by our property language. (mc init |=u [] ~ (’DE_SimpleTrafficLight | (’Pgrn = # 1, ’Cgrn = # 1)) .)

To check states of FSM-Actors directly, we can write: (mc init |=u [] ~ (’DE_SimpleTrafficLight . ’CarLightNormal @ ’Cgrn /\ ’DE_SimpleTrafficLight . ’PedestrianLightNormal @ ’Pgreen) .)

Using an actor scope, the above safety property can be simplified by: (mc init |=u ’DE_SimpleTrafficLight : [] ~ (’CarLightNormal @ ’Cgrn /\ ’PedestrianLightNormal @ ’Pgreen) .)

Figure 2. Simple Traffic Light model of Ptolemy

5

Using Ptolemy’s Code Generation Infrastructure to Integrate Real-Time Maude Analysis into Ptolemy

This section shows how Ptolemy’s helper code generation infrastructure has been used to automatically generate Real-Time Maude code from a Ptolemy DE model, and to integrate Real-Time Maude analysis of DE models into Ptolemy. Section 5.1 gives a brief introduction to the code generation infrastructure of Ptolemy, Section 5.2 shows how a Real-Time Maude model is generated from a Ptolemy model, and Secton 5.3 briefly explains the Real-Time Maude interface in Ptolemy. 5.1

The Code Generation Infrastructure of Ptolemy

Ptolemy gives the user the possibility of adding a “code generation button” to a (top-level) Ptolemy model. When the user clicks on this button, Ptolemy opens a dialogue window which allows the user to start code generation and give commands to execute the code. Ptolemy provides a helper infrastructure to support the generation of code into any target language. In particular, Ptolemy provides a Java class CodeGeneratorHelper. This class contains utility methods, such as the function getComponent(), which returns a (Java) object containing all information about an actor, including its name, parameters, ports, inner actors, etc. The class CodeGeneratorHelper furthermore contains “skeleton” functions like String generateFireCode(), String generateInitializeCode(), String generatePostfireCode(), Set getSharedCode(), and so on. For example, the generateFireCode() function should generate the code exeucted when the actor is “fired.” The getSharedCode() function should generate code shared by multiple instances of the same actor. The point is that, for each kind of actor, we must define a helper class that extends the class CodeGeneratorHelper and defines the above

functions generateFireCode(), etc. Each director (DE, SR, SDF, etc.) also has an associated helper class, which uses the code generation infrastructure of each actor to generate the entire code of a Ptolemy model. Templates. A helper class may have a associated template file containing code blocks written in a target language. By using template file, target language code can be separated from a Java class file of a helper, so that readability and maintainability in the implementation of helper classes are increased. A code block in a template files is not just fixed text, but a sort of code pattern. It can be parameterized with several variables, and also have macro functions. Each code block has a header and ends with /**/. The header starts with /*** and ends with ***/, and contains a code block name and a comma-saperated parameter list. Each parameter is prefixed by the dollar sign $. Macros in a code block are prefixed with the dollar sign $symbol. The specific macro name follows immediately. The parameters to the macro are enclosed in parentheses. For example: /***exampleBlock ($name, $value)***/ ... if ($val($name) == $value) then doSomething() else reportError(); ... /**/ During execution, $name and $value are substituted by given parameter values, and $val($name) gives the current value of the parameter $name of an actor. 5.2

Implementing the Real-Time Maude Code Generator

The Real-Time Maude code generation is implemented by overriding two of the helper functions described in Section 5.1. The function getSharedCode() is used to generate the Real-Time Maude modules defining the semantics of those actors that appear in the Ptolemy model, as well as the modules defining the infrastructure for LTL model checking of Ptolemy models. The function generateFireCode() is used to generate the initial Real-Time Maude term corresponding to the given Ptolemy model. For each kind of actor, we therefore define a Java class extending CodeGeneratorHelper, and define the above two functions for that actor. To give idea about the implementation of the Real-Time Maude code generator, we show how getSharedCode() and generateFireCode() have been implemented for the CurrentTime actor. First of all, we have defined a Java class RTMaudeAdaptor that extends CodeGeneratorHelper, which is a base class for our code generator. The getSharedCode() function is defined in this class as follows: public Set getSharedCode() throws IllegalActionException { // Use LinkedHashSet to give order to the shared code. Set sharedCode = new LinkedHashSet();

semanticsIncludes = getModuleCode("semantics"); formalIncludes = getModuleCode("formal"); for (String m : semanticsIncludes) sharedCode.add(getRTMmodule().get(m)); for (String m : formalIncludes) sharedCode.add(getRTMmodule().get(m)); return sharedCode; }

The auxiliary function getModuleCode(header ) reads Real-Time Maude code blocks from the related templates to the helper class, whose code block name starts with header . The getModuleCode function uses templates of each super class of an actor. In Ptolemy, each actor class is a subclass of the class Entity. Therefore, we defined a helper class of Entity, extending RTMaudeAdaptor, that is a superclass of every actor helper class. The semantics_Entity code block in the template is: /***semantics_Entity***/ (tomod ACTOR is ... class Actor | ports : Configuration, parameters : AssignMap, status : ActorStatus, store : Memory . ... endtom) /**/

For the CurrentTime actor, the semantics_CurrentTime is: /***semantics_CurrentTime***/ (tomod CURRENT-TIME is inc ACTOR . inc OBJECT-WITH-TIMER . class CurrentTime . subclass CurrentTime < Actor TimeObj . vars PORTS : Configuration . vars PI PI’ : PortId . var DPS : DetPortStatus . var O : Oid . var REST : ObjectConfiguration . var T : Time . eq portFixPoints( < O : CurrentTime | status : enabled, current-time : T, ports :

< PI : InPort | < PI’ : OutPort PORTS > REST) = portFixPoints( < O : CurrentTime | ports : < PI : InPort | < PI’ : OutPort PORTS > REST) .

status : DPS > | status : unknown >

> | status : DPS, value : # T >

endtom) /**/

For the CurrentTime actor, getModuleCode("semantics") returns a set of above two code blocks. The template file for Entity also contains the following code blocks: /***fireBlock($attr_terms)***/ < ’$info(name) : $info(class) | $attr_terms > /**/ /***attr_Entity***/ store : emptyMap, status : enabled, ports : ($indent($info(ports))), parameters : ($indent($info(parameters))) /**/

The fireBlock code block used by generateFireCode() to generate the Real-Time Maude object corresponding to a Ptolemy actor instance. The parameter attr_terms will be replaced by set of attr Actor code blocks for each Actor of super classes of a given actor. $info is a macro that uses Ptolemy’s getComponent() to extract information, such as the name, the class, etc., about the actor instance. For CurrentTime, attr_CurrentTime is the following: /***attr_CurrentTime***/ current-time : 0 /**/

The definition of generateFireCode() is not given (since it calls a set of other auxiliary functions), but its effect is that it generates the object defined in the fireBlock code block. For example, given a Ptolemy CurrentTime actor with the name CT, the generateFireCode() function returns the term < ’CT : CurrentTime | status : enabled, current-time : 0, store : emptyMap, ports : < ’output : OutPort | value : # 0, status : absent > < ’trigger : InPort | value : # 0, status : absent >, parameters : emptyMap >

5.3

Verifying Ptolemy DE Models from within Ptolemy

We have integrated not only the code generation, but also the verification into Ptolemy, so that a Ptolemy DE model can be verified by pushing the RTMaudeCodeGenerator button in the Ptolemy model. The dialogue window that pops up when the above button is double-clicked allows the user to write his or her simulation or model checking command, as shown in Fig. 3. After clicking the Generate button of the dialogue window, the resulting Real-Time Maude code shows up in another window, and the result of executing the model checking commands is shown in the Code Generator Commands dialogue box.

Figure 3. Dialogue window for Real Time Maude code generation

The resulting Real-Time Maude code generated from a Ptolemy model illustrated in Figure 4. It consists of 1) semantics modules, 2) formal analysis modules, 3) an initial model module, 4) verification commands. Semantics modules and formal analysis modules 11 are generated by getSharedCode(). An initial model module contains an OO term of a Ptolemy model, which are generated by generateFireCode(). Each helper class for Real-Time Maude code generation overrides the both method from CodeGeneratorHelper class. In addition, LTL properties in a dialog window is used to generate verification commands. Real-Time Maude code blocks are defined in the associated template file of a helper class. getSharedCode() and generateFireCode() use the code blocks. If the name of an actor is Actor, a semantics module is defined in a code block semantics Actor , a formal analysis in a code block, formal Actor , the OO 11

described in Section 3.1 and Section 4, respectively.

******** include basic definitions ******** load ptolemy-base.maude ******** semantics modules ******** (tomod ACTOR is ... endtom) (tomod COMPOSITE-ACTOR is ... endtom) (tomod CLOCK is ... endtom) (tomod DELAY is ... endtom) (tomod FSM-ACTOR is ... endtom) (tomod SET-VARIABLE is ... endtom) ******** formal analysis modules ******** (tomod CHECK-ACTOR is ... endtom) (tomod CHECK-COMPOSITE-ACTOR is ... endtom) (tomod CHECK-FSM-ACTOR is ... endtom) ******** Initial model modules ******** (tomod INIT is including DE-DYNAMICS . including ACTOR + ... + CLOCK . ... op init : -> Configuration . eq init = initAll( *** OO term of a Ptolemy model *** < ’Model : CompositeActor | innerActors : ... > ) < global EventQUEUE | queue : nil > . .) (tomod PTOLEMY-MODELCHECK is including INIT + ... + CHECK-FSM-ACTOR . endtom) ******** verification commands ******** (mc init |=u [] ~ (’Model | (’Pgrn = # 1, ’Cgrn = # 1)) .) (mc init |=u (’Model | (’Pgrn = # 1, ’Cgrn = # 0)) .) quit

Figure 4. Structure of a resulting code

term of an actor in a parameterized code block fireBlock($attr terms), and attributes of the OO term in attr Class 12 . To illustrate more precisely, consider the helper class of Entity class, which generates code for a general Real-Time Maude Actor and other helpers of Ptolemy actors extend it. Figure 5 shows contents of Entity.rtmaude. Note that $info and $indent are template functions to be substituted to suitable Real-Time maude code during translation. Helper classes of actors extends Entity helper /***semantics_Entity***/ (tomod ACTOR is ... class Actor | ports : Configuration, parameters : AssignMap, status : ActorStatus, store : Memory . ... endtom) /**/ /***formal_Entity***/ (tomod CHECK-ACTOR is ... endtom) /**/ /***fireBlock($attr_terms)***/ < ’$info(name) : $block(className) | $attr_terms >/**/ /***attr_Actor***/ store : emptyMap, status : $block(statusBlock), ports : ($indent( $info(ports) )), parameters : ($indent( $info(parameters) ))/**/

Figure 5. Contents of the template file Entity.rtmaude

class. Since code blocks of super classes are automatically included for each helper class, the code of general actor is generated for any actor. 12

the suffix Class for a code block name is required since the current codegen infrastructure does not support call to superclass code blocks that have been overridden.

6

Examples

This section presents three Ptolemy II discrete-event models and shows how they can be analyzed in Real-Time Maude from within Ptolemy. Section ?? presents the benchmark railroad crossing example, Section ?? presents a hierarchical model of a fault-tolerant traffic light system, and Section ?? presents an assembly line due to Misra. 6.1

Railroad System

In the benchmark railroad crossing example, trains approach an intersection, and it is the goal of the system that the gates at the intersection are lowered (down??) when a train is in the intersection. Figure 6 shows a Ptolemy II DE model RailroadSystem of such a system. This model consists of two finite state machine (FSM) actors: a Train actor that models trains, and a Gate actor that controls the gate. In addition, the model has a set of “boolean” variables Tin (which is 1 when a train is in the intersection), Tleave (which is 1 when a train is leaving the environment), Tapproaching, and Gopen (which is 1 when the gate is open). State changes are triggered by a Clock actor. These variables are set by signals from the output ports of the train and the gate controller.

Figure 6. Ptolemy DE model of the railroad crossing.

Do we have/need a reference to Misra’s example??

Figure 7 shows the Train FSM actor modeling trains. This actor has five states, or locations, and a local variables distance, denoting the distance between the train and the beginning of the intersection. The Train has one input port, Sec, and three output ports (Tin, Tleave, and Tapproaching). Initially, the state is in location Tinit; in the first step, a new train is arriving, but is yet far away, at a distance −10. The FSM actor stays in location far as long as the distance < -3. The value of distance increases by 2 each time there is input in the Sec port (that is, each time unit in our case) as long as the train is state far. When distance has reached −3, and a new Sec signal arrives, the train takes a transition to location approaching, where it stays until the distance reaches 0. At the same time, it outputs a signal with value 1 through its Tapproaching output port. A train that is approaching the intersection slows down; therefore, the distance only increases by one for each time unit in location approaching (as well as in locations within and leaving). When the distance to the intersection is 0, the actor goes to state within, and emits a signal through its Tin port. When the distance is greater than or equal to 3, the train is leaving the intersection, and an output is emitted through the Tleave port. Finally, when the distance becomes greater than or equal to 10, the train disappears and a signal with value 0 is output through all three output ports. The actor goes to location far and the next train is seen in the horizon, and the distance is set to -10.

Figure 7. The FSM actor modeling trains.

Figure 8 shows the FSM actor controlling the gate. This actor responds to input from the Train actor through its Tapproaching, Tin, and Tleave input ports by the necessary signal through its Gopen output port.

Figure 8. The FSM actor modeling the gate controller.

Kyungmin, Real-Time Maude code corresponding to the initial state! Formal Analysis. The main property the system RailroadSystem must satisfy is the safety property that whenever a train is in the intersection, the gate must be closed. In our model, a train is in the intersection when the ’Train actor in the ’RailroadSystem main component is in location ’within, then the ’Gate actor is in location ’closed. Using the convenient propositions defined in Section ??, the atomic proposition (’RailroadSystem . ’Train @ ’within holds for states in which the ’Train actor is in location within, and the proposition (’RailroadSystem . ’Gate @ ’closed holds when the Gate is in location closed. We want to check whether it is always the case that the former implies the latter. In temporal logic, this can be given by the formula: [] ((’RailroadSystem . ’Train @ ’within) -> (’RailroadSystem . ’Gate @ ’closed))

Giving this command in the dialogue box that pops up when the user double clocks the “RTMaudeCodeGenerator” button gives the expected result true, proving that the desired property is satisfied in this Ptolemy model. Notice that the railroad system is finite state, hence we do need to perform time-bounded LTL model checking. The following model checking command checks whether it is always the case that the Train actor will reach the state within within 7 time units from the start of system execution: ( ’RailroadSystem . ’Train @ ’within) in time

Suggest Documents