The system class "simulation" may be considered an "application package" oriented towards simulation problems. It has the class "simset" as prefix, and set-handling facilities are thus immediately available.
The concepts defined in "simulation" are explained with respect to a prefixed block, whose prefix part is an instance of the body of "simulation" or of a subclass. The prefixed block instance acts as the head of a quasi-parallel system which may represent a "discrete event" simulation model.
simset class simulation; begin ref (head) SQS; link class EVENT_NOTICE (EVTIME, PROC); long real EVTIME; ref (process) PROC; begin ref (EVENT_NOTICE) procedure suc; suc:- if SUC is EVENT_NOTICE then SUC else none; ref (EVENT_NOTICE) procedure pred; pred:- PRED; procedure RANK_IN_SQS (afore); Boolean afore; begin ref (EVENT_NOTICE) evt; evt:- SQS.last; while evt.EVTIME > EVTIME do evt :- evt.pred; if afore then while evt.EVTIME = EVTIME do evt :- evt.pred; follow(evt) end RANK_IN_SQS; end EVENT_NOTICE; ref (MAIN_PROGRAM) main; ref (EVENT_NOTICE) procedure FIRSTEV; FIRSTEV :- SQS.first; ref (process) procedure current; current :- FIRSTEV.PROC; long real procedure time; time := FIRSTEV.EVTIME; link class process; .................... 12.1; procedure ACTIVAT .................. 12.3; procedure hold ..................... 12.4; procedure passivate ................ 12.4; procedure wait ..................... 12.4; procedure cancel ................... 12.4; process class MAIN_PROGRAM ................. 12.5; procedure accum .................... 12.6; SQS :- new head; main :- new MAIN_PROGRAM; main.EVENT :- new EVENT_NOTICE(0,main); main.EVENT.into(SQS) end simulation;
When used as a prefix to a block or a class, "simulation" introduces simulation-oriented features through the class "process" and associated procedures.
The variable SQS refers to a set which is called the "sequencing set", and serves to represent the system time axis. The members of the sequencing set are event notices ranked according to increasing value of the attribute "EVTIME". An event notice refers through its attribute PROC to a "process" object and represents an event which is the next active phase of that object, scheduled to take place at system time EVTIME. There may be at most one event notice referencing any given process object.
The event notice at the lower end of the sequencing set refers to the currently active process object. The object can be referenced through the procedure "current". The value of EVTIME for this event notice is identified as the current value of system time. It may be accessed through the procedure "time".
Note: Since the statements and procedures introduced by "simulation" make implicit use of the sequencing procedures (detach, call and resume) explicit sequencing by these procedures should be done with care.
link class process; begin ref (EVENT_NOTICE) EVENT; Boolean TERMINATED; Boolean procedure idle; idle := EVENT==none; Boolean procedure terminated; terminated := TERMINATED; long real procedure evtime; if idle then error("..." ! No Evtime for idle process) else evtime := EVENT.EVTIME; ref (process) procedure nextev; nextev :- if idle or else EVENT.suc == none then none else EVENT.suc.PROC; detach; inner; TERMINATED:= true; passivate; error("..." ! Terminated process;) end process;
An object of a class prefixed by "process" is called a process object. A process object has the properties of "link" and, in addition, the capability to be represented in the sequencing set and to be manipulated by certain sequencing statements which may modify its "process state". The possible process states are: active, suspended, passive and terminated.
When a process object is generated it immediately becomes detached and its reactivation point positioned in front of the first statement of its user- defined operation rule. The process object remains detached throughout its dynamic scope.
The procedure "idle" has the value true if the process object is not currently represented in the sequencing set. It is said to be in the passive or terminated state depending on the value of the procedure "terminated". An idle process object is passive if its reactivation point is at a user-defined prefix level. If and when the PSC passes through the final end of the user-defined part of the body, it proceeds to the final operations at the prefix level of the class "process", and the value of the procedure "terminated" becomes true. (Although the process state "terminated" is not strictly equivalent to the corresponding basic concept defined in chapter 7, an implementation may treat a terminated process object as terminated in the strict sense). A process object currently represented in the sequencing set is said to be "suspended", unless it is represented by the event notice at the lower end of the sequencing set. In the latter case it is active. A suspended process is scheduled to become active at the system time indicated by the attribute EVTIME of its event notice. This time value may be accessed through the procedure "evtime". The procedure "nextev" references the process object, if any, represented by the next event notice in the sequencing set.
activation-statement = activation-clause [ scheduling-clause ] activation-clause = activator object-expression activator = activate | reactivate scheduling-clause = timing-clause | ( before | after ) object-expression timing-clause = simple-timing-clause [ prior ] simple-timing-clause = ( at | delay ) arithmetic-expression
An activation statement is only valid within an object of a class included in "simulation", or within a prefixed block whose prefix part is such an object.
The effect of an activation statement is defined as being that of a call on the sequencing procedure ACTIVAT local to "simulation", see 12.3.
The actual parameter list is determined from the form of the activation statement, by the following rules:
scheduling clause actual text parameter ------------------------------------------------------- - absent - "direct" at arithmetic expression at delay arithmetic expression delay before object expression before after object expression after
procedure ACTIVAT(REAC, X, CODE, T, Y, PRIO); value CODE; ref (process) X, Y; Boolean REAC, PRIO; text CODE; long real T; inspect X do if not TERMINATED then begin ref (process) z; ref (EVENT_NOTICE) EV; if REAC then EV:- EVENT else if EVENT =/= none then goto exit; z:- current; if CODE = "direct" then direct: begin EVENT:- new EVENT_NOTICE(time,X); EVENT.precede(FIRSTEV) end direct else if CODE = delay then begin T:= T + time; goto at_ end delay else if CODE = at then at_: begin if T < time then T:= time; if T = time and PRIO then goto direct; EVENT:- new EVENT_NOTICE(T, X); EVENT.RANK_IN_SQS(PRIO) end at else if Y == none or else Y.EVENT == none then EVENT :- none else begin if X == Y then goto exit; comment reactivate X before/after X; EVENT:- new EVENT_NOTICE(Y.EVENT.EVTIME, X); if CODE = before then EVENT.precede(Y.EVENT) else EVENT.follow(Y.EVENT) end before or after; if EV =/= none then begin EV.out; if SQS.empty then error("...") end; if z =/= current then resume(current); exit: end ACTIVAT;
The procedure ACTIVAT represents an activation statement, as described in 12.2. The effects of a call on the procedure are described in terms of the corresponding activation statement. The purpose of an activation statement is to schedule an active phase of a process object.
Let X be the value of the object expression of the activation clause. If the activator is activate the statement has no effect (beyond that of evaluating its constituent expressions) unless the X is a passive process object. If the activator is reactivate and X is a suspended or active process object, the corresponding event notice is deleted (after the subsequent scheduling operation) and, in the latter case, the current active phase is terminated. The statement otherwise operates as an activate statement.
The scheduling takes place by generating an event notice for X and inserting it into the sequencing set. The type of scheduling is determined by the scheduling clause.
An empty scheduling clause indicates direct activation, whereby an active phase of X is initiated immediately. The event notice is inserted in front of the one currently at the lower end of the sequencing set and X becomes active.The system time remains unchanged. The formerly active process object becomes suspended.
A timing clause may be used to specify the system time of the scheduled active phase. The clause "delay T", where T is an arithmetic expression, is equivalent to "at time + T". The event notice is inserted into the sequencing set using the specified system time as the ranking criterion. It is normally inserted after any event notice with the same system time. The symbol "prior" may, however, be used to specify insertion in front of any event notice with the same system time.
Let Y be a reference to an active or suspended process object. Then the clause "before Y" or "after Y" may be used to insert the event notice in a position defined relation to (before or after) the event notice of Y. The generated event notice is given the same system time as that of Y. If Y is not an active or suspended process object, no scheduling takes place.
Example
The statements
activate X activate X before current activate X delay 0 prior activate X at time prior
are equivalent. They all specify direct activation.
The statement
reactivate current delay T
is equivalent to "hold(T)".
HOLD procedure hold(T); long real T; inspect FIRSTEV do begin if T > 0 then EVTIME:= EVTIME + T; if suc =/= none and then suc.EVTIME <= EVTIME then begin out; RANK_IN_SQS(false); resume(current) end if end hold; PASSIVATE procedure passivate; begin inspect current do begin EVENT.out; EVENT :- none end; if SQS.empty then error("...") else resume(current) end passivate; WAIT procedure wait(S); ref (head) S; begin current.into(S); passivate end wait; CANCEL procedure cancel(X); ref (process) X; if X == current then passivate else inspect X do if EVENT =/= none then begin EVENT.out; EVENT :- none end cancel;
The sequencing procedures serve to organize the quasi-parallel operation of process objects in a simulation model. Explicit use of the basic sequencing facilities (call, detach, resume) should be made only after thorough consideration of its effects.
The statement "hold(T)", where T is a long real number greater than or equal to zero, halts the active phase of the currently active process object, and schedules its next active phase at the system time "time + T". The statement thus represents an inactive period of duration T. During the inactive period the reactivation point is positioned within the "hold" statement. The process object becomes suspended.
The statement "passivate" stops the active phase of the currently active process object and deletes its event notice. The process object becomes passive. Its next active phase must be scheduled from outside the process object. The statement thus represents an inactive period of indefinite duration. The reactivation point of the process object is positioned within the "passivate" statement.
The procedure "wait" includes the currently active process object in a referenced set, and then calls the procedure "passivate".
The statement "cancel(X)", where X is a reference to a process object, deletes the corresponding event notice, if any. If the process object is currently active or suspended, it becomes passive. Otherwise, the statement has no effect. The statement "cancel(current)" is equivalent to "passivate".
process class MAIN_PROGRAM; begin while true do detach end MAIN PROGRAM;
It is desirable that the main component of a simulation model, i.e. the "simulation" block instance, should respond to the sequencing procedures of 12.4 as if it were itself a process object. This is accomplished by having a process object of the class MAIN_PROGRAM as a permanent component of the quasi-parallel system.
The process object represents the main component with respect to the sequencing procedures. Whenever it becomes operative, the PSC (and OSC) immediately enter the main component as a result of the "detach" statement (cf. 7.3.1). The procedure "current" references this process object whenever the main component is active.
A simulation model is initialized by generating the MAIN_PROGRAM object and scheduling an active phase for it at system time zero. Then the PSC proceeds to the first user-defined statement of the "simulation" block.
ACCUM procedure accum (a,b,c,d); name a,b,c; long real a,b,c,d; begin a:= a+c * (time-b); b:= time; c:= c + d end accum;
A statement of the form "accum (A,B,C,D)" may be used to accumulate the "system time integral" of the variable C, interpreted as a step function of system time. The integral is accumulated in the variable A. The variable B contains the system time at which the variables were last updated. The value of D is the current increment of the step function.