Relating a Simulation Model to an Applicative Specification Ole-Johan Dahl Department of Informatics University of Oslo PO box 1080 Blindern N-0316 Oslo, Norway E-mail: [email protected] ABSTRACT We consider a “package router”, a system adapted from one proposed in (Balzer et al. 1981) and used for specification case studies. Here we give two specifications: a discrete event simulation model in traditional style useful for studying the dynamic behaviour of the system, and an applicative, more “abstract” specification useful for proving properties of the system. We demonstrate how the two specifications can be proved equivalent in a certain sense, using techniques of program verification, more precisely a suitably extended Hoare logic. We introduce additional proof rules to cater for special scheduling statements and the concept of system time. An important part of the verification is to identify a correct and sufficiently strong system invariant. INTRODUCTION The purpose of the present paper is to compare a simulation model in the style of Simula 67 and an applicative model of the same system. The latter might be seen as an “abstract” specification of the simulated system, and a proof of equivalence in some sense between the two can be seen as a proof of “correctness” of the traditional model. We indicate how a formal proof may be produced, identifying useful techniques in so doing. The system considered is an adaptation of a simple “package routing” device described in (Balzer et al. 1981) for the purpose of specification case studies. The system was presented and discussed at a meeting of the IFIP Working Group 2.3 (on Programming Methodology) in 1981. The purpose of the discussion was to consider different specification techniques. A resulting applicative specification formulated by the author was subsequently presented at the IMACS World Congress on System Simulation and Scientific Computation, Oslo 1985 (Dahl 1985). The specification is constructive, and can thus be seen as an applicative simulation program, though not a very practical one. It is, however, well suited for proving properties of the system. The more standard imperative program, on the other hand, could render a complete time sequence of events occurring during the routing of packages, and is therefore a good vehicle for performing lifelike simulation experiments, but not for proving system properties. An equivalence proof of the two models will provide the user with both options. The paper is organized as follows. We first give an informal description of the device to be simulated, and then present the applicative specification, together with a few provable properties. In the next main section the essential parts of a discrete event simulation model in the style of Simula 67 is presented, and we finally indicate how a formal equivalence proof may be constructed. THE SYSTEM A stream of packages, called boxes, with machine readable address labels are routed to appropriate bins, one for each address. The boxes slide through a pyramid of mechanical binary switches. Addresses are assumed to be bit sequences of length N > , and each switch on level i in the pyramid, i N , should react to the address bit number i of each box passing through the switch by routing it in the left or right direction, respectively. For a switch to react properly, there must be a certain minimum time interval between box arrivals; otherwise the switch remains in the former position, which may result in misrouting. Boxes may have different sliding speeds, so it is possible for one box to overtake another. In that case these boxes remain together, the former taking on the slower sliding speed. As a consequence all boxes of such a train will be routed to the bin appropriate for the front box, which may or may not be the correct one for the succeeding boxes in the train. The natural sliding speed of a box is defined by a constant natural transfer time from one pyramid level to the next. In addition there is a constant switching interval, the same for all switches, representing the time for an arbitrary box to pass through the switch. If a box arrives at a time when a box is passing through, the switch is unable to react to the address of the arriving one. Boxes are fed in at the top of the pyramid at fixed time intervals. An objective of a simulation study could be to adjust the feeding interval so as to maximize the throughput of boxes, while keeping the probability of misrouting below a given limit for a given distribution of sliding speeds, and box addresses being selected, say independently with equal probabilities. 0 1 THE APPLICATIVE SPECIFICATION We specify the routing device using the idiom of the specification language ABEL (Dahl and Owe 1992). The specification is in terms of at list of types, representing sets of values, and a list of typed functions operating on typed values. Type definition A type, say T , is defined by identifying its generator basis, a list of functions, the generators, producing T values and spanning the intended value set. Consequently all values will be represented by expressions consisting entirely of generator applications. The following types are needed in the model: Bool (predefined). Generator basis: f; t ,! Bool. TimeIntv and TimePoint are arithmetic types left unspecified here. It is assumed, however, that arithmetic operators satisfy usual arithmetic laws. Bit. Generator basis: 0; 1 ,! Bit. Box. Left unspecified. It is assumed, however, that the set of Box values is countably infinite. SeqfTg, sequences of T values for arbitrary type T . Generator basis: " ,! SeqfT g; ˆ ` ˆ SeqfT g T ,! SeqfT g, where the symbol ˆ indicates an operand position. The operator ˆ computes the length of a sequence. : : : # : The following sequence types and subtypes occur (for some given integer N > ): BoxFlow SeqfBoxg SwPos fq SeqfBitg q N g Addr fq SeqfBitg q N g 0 = = : = : # #= Function definition Each occurring function must be specified syntactically by providing its domain and codomain types. Functions, other than generators, are specified semantically by defining equations, possibly using induction with respect to the structure of some argument. Since an argument stands for a typed value, i.e. an expression in generators, there will be one definition for each generator of the argument type, either separate axioms or branches of a special “case construct”. The use of recursion may be controlled by effective syntactic termination checks. This style of function definition is therefore called terminating generator induction, TGI (Dahl 1992). TGI axioms form convergent rewrite rules. For that reason they are well suited for (semi-)mechanical reasoning. Example: We specify the sequence length function semantically. Either: Or: #q == case q of " ! 0 j q 0 ` x ! #q 0 +1 fo #" == 0; #(q ` x) == #q + 1. Termination of recursion follows from the fact that the recursive application of ˆ has a syntactically simpler argument than that of the left hand side. All generator induction occurring below is with respect to sequence arguments. We use the style of separate, named axioms. # The model : : func fi ,! TimeIntv - - feeding interval, unspecified - - switching interval, unspecified func si ,! TimeIntv - - address label, unspecified func ˆ:ad Box ,! Addr - - transfer time, unspec. func ˆ:tt Box ,! TimeIntv func bf BoxFlow SwPos ,! BoxFlow - - total flow at switch for given input A1: bf "; p "; A2: bf q ` b; p if op b; q; p then bf q; p ` b else bf q; p fi func op Box BoxFlow SwPos ,! Bool - - switch is on path of box, after given input A3: op b; q; " t A4: op b; q; p ` x op b; q; p ^ ss q ` b; p x func ss BoxFlow SwPos ,! Bit - - final status of switch for given input A5: ss "; p 0 A6: ss q ` b; p ifop b; q; p ^:ha b; q; p then b:ad p else ss q; p fi func ha Box BoxFlow SwPos ,! Bool - - box, after given input, hindered at switch A7: ha b; q; p op b; q; p ^ at q ` b; p at q; p si func at BoxFlow SwPos ,! TimePt - - last arrival time at switch for given input A8: at "; p ,si A9: at q ` b; " fi q A10: at q ` b; p ` x if op b; q; p `x then max at q ` b; p b:tt; at q; p ` x si else at q; p ` x fi func uhb Box BoxFlow SwPos ,! Bool - - box, after given input, unhindered before switch A11: uhb b; q; " t A12: uhb b; q; p ` x uhb b; q; p ^ :ha b; q; p : : : ( ( : ( ( : ( ( : ( : ( ( ( : ( ( ) == ) == ( ) ) == ) == ( ) ) == ) == ( ) ( ) == ( ( ) ( )= ) ) ( ) [# ] ( ) ( ) ( )+ ) == ) == # ) == ( ) ( ( )+ ( ))+ ) == ) == ( ) ( ( ) ) It is assumed that the feeding interval is longer than the switching interval, see A9 and A11. Based on the above definitions several theorems expressing properties of the specified model may be formulated and proved, such as: : : T1 (correct routing): 8b Box; q BoxFlow uhb b; q; b:ad ) bf q `b; b:ad bf q; b:ad ` b T2 (bad routing): 8b; b0 Box ; 0q; q0 ;00q 00 BoxFlow; p SwPos; bin Addr 0 q q ` b `a q 0 ^ p hd0 b:ad ^ uhb b; q; p ^ ha b; q; p ^ bf q; p bf q ; p ` b ^ bf q ` b0 ; bin bf q0 bin ` b0 ) bf q ` b; bin bf q0 ; bin ` b0 `b. ( ) ( : : : =( ) ( )= ( ) ( ( )= ( ) )= ( ) : ( ) ( ) )= ( ) T2 uses the relation ˆhdˆ which expresses that the left sequence argument is an initial part of the second sequence. The operator ˆ `a ˆ concatenates two sequences. The premise of T2 thus establishes the fact that the box b is hindered by b0 for the first time at some position p in the pyramid. As a consequence both boxes will thereafter follow the same path and end up in the same bin. Remark. Our choice of defining the right append operator as a sequence generator rather than the left append operator, is motivated by the fact that expressions of the form q ` x will occur in the conditions for the verification of the imperative model. Notice that the algorithm for evaluating an expression containing inductively defined sequence functions will then in fact process sequence arguments backwards. This, however, has the side benefit that the evaluation algorithm is essentially different from that of the imperative model which works “forward” in time. Consequently a comparison of the two models is non-trivial. It should be mentioned that our approach is simplified by the fact that the model considered is “historically monotonic”, in the sense that the results caused by an initial part of the input sequence cannot be influenced by later input. Thus, for instance: 8q; q 0 : BoxFlow q hd q0 ) 8p : SwPos bf (q; p) hd bf (q 0 ; p) This property would not obtain in a more realistic model where the sliding speed of a box would increase as the result of being overtaken by a faster one. In that case extending the input by fast sliding boxes might cause misrouting of preceding ones that would otherwise be routed correctly. THE IMPERATIVE PROGRAM The program is expressed in a suitably adapted version of SIMULA 67. Thus, a statement hold t represents the passage of t units of system time, the operating process object being in a state of suspension; the statement passivate represents the passage of an indefinite amount of system time, the object being in the idle state; and activate X calls for the immediate activation of the designated process object, provided it is in the idle state. Control returns to the activator upon the end of the active phase of X , system time remaining unchanged. Types defined for the applicative model are used in the program. It is understood that operations on Box objects are through pointers; in particular, Box sequences would be implemented as sequences of pointers. The operators lt and rr take the left term, respectively the right rest of a nonempty sequence. Similarly, rt and lr take the right term, respectively the left rest. The program is embellished with a few key assertions, as well as certain “mythical” sections enclosed in quotes. Both are understood to be ignored during program execution. They do, however, () : =?? ??; ) == ; SIMULATION begin constfi; si TimeIntv ; assert fi > si; process class Box ad Addr; tt TimeIntv begin var P SwPos " “const Q INP”; const B this Box INP INP `B loop inspect SW P do TL TL ` B if P 6 " then hold tt fi assert B 2 TL if B 6 lt TL then passivate else if P <N then SS ad P fi fi assert TL 6 e ^ B lt TL ^ time AT si; “AT time” hold si assert TL 6 " ^ B lt TL ^ time AT si “BF TL rr TL if TL 6 " ^ lt TL :idle then activate lt TL fi while P <N : := ( : = ; : := - - feeding and switching times - - box with address label and transfer time - - position in pyramid - - preceding input sequence, self reference - - update input sequence := ; ( ) := ; = () ; ; =( ) # := [# +1] ; = =( ) + := ; ( ); = = ( ) = + ; := BF ` B ”; := ( ); = ( ) ( ) ; # ; P := P ` SS od repeat end; class Switch(pos : SwPos) == begin var L; R : Switch; var TL : BoxFlow = "; SS : Bit = 0; “var BF : Boxflow = "; AT : TimePt = ,si”; if #pos<N then L := new Switch(pos `0); R := new Switch(pos ` 1) fi end; var TOP := new Switch("); INP : BoxFlow = "; func SW (p : SwPos) == case p of " ! TOP j p0 `x ! case x of 0 ! SW (p0 ):L j 1 ! SW (p0 ):R fo fo; while ?? do activate new Box(??; ??); hold(fi) od; hold(:::); assert 8bin : Addr SW (bin):BF = bf (INP; bin) - - switch at given position - - left and right successors - - transfer line, switching state - - local box flow, last arrival time - - the pyramid, box input - - locate switch at given position - - generate input of boxes - - all model activity has terminated end provide information important for understanding the program and reasoning about it. PROOF OF EQUIVALENCE General rules Comments Each box enters the transit line TL in front of the next switch (or bin) immediately after leaving the preceding switch, if any. Since TL is operated as a FIFO queue, the boxes enter the switch in the right order. During the switching interval a box remains at the front of TL. Thus, a box whose arrival at the switch entry would be at a time when it is not at the front of TL, must await its turn, going idle. Before leaving the switch the current box removes itself from the TL. If there is then a box at the front of TL waiting idlely, its time has come to enter the switch. Otherwise the next box, if any, will arrive at the switch entry at an acceptable time, being at the front of TL. In the latter case the switching status SS is set according to the relevant address bit. In the former case the SS must remain unchanged. The switches at N -bit pyramid positions play the roles of bins. The box flow BF through each switch is accumulated (including the arrivals at the bins). The arrival time of the currently last box is recorded in AT. Since these variables and operations do not contribute to the actual routing algorithm, they are defined as mythical. We shall reason as if all mythical sections were executed. The function SW locating a switch, given its address in the pyramid, is defined inductively in the specification style of ABEL. The actual input to the model is left unspecified, as well as the feeding and switching intervals. The final hold statement should have a duration large enough to allow all model activity to terminate. The final assertion then expresses the correctness of the imperative model relative to the applicative specification. The most important basis for reasoning about a discrete event simulation model is a sufficiently strong system invariant, i.e. a formula in program variables accessible from the main program (possibly through remote accessing), including the system time, that holds between events. Given a system invariant, say I , we can reason about hold statements as indicated by the following Hoare triple: fI ghold(t)fI g 0 (for t> ) It is sometimes necessary to distinguish between system times “immediately before” or “immediately after” that of an event (i.e. of an active process phase). In such cases we permit I to be time time replaced by Itime + in the precondition or by Itime , in the postcondition, where the sub- and superscripts indicate syntactic substitutions, and where is a “small” amount of time. (This raises certain logical difficulties with respect to events taking place at the same system time. Suffice it to say that we postulate a sufficiently fine-grained system time, and that we may for most purposes reason as if the system times of consecutive events are in fact different.) The system invariant also plays a role in the reasoning about passivate and activate statements’. However, we define the active phase of the activator, followed by that of the activated process, followed in turn by another active phase of the activator (to be understood recursively) as constituting a single event. Thus, we may choose some predicate different from the system invariant to hold before activate X and after a passivate, where X refers to an object of process class C and for a passivate occurring in the body of C : C;idle fX:idle ^ [BC ]this X; falsegactivate X fI g fI gpassivatefBC g The substitution indicates a change of perspective as regards the access to attributes of X . Thus, a reference A to an attribute in X is shorthand for this C:A, and seen from the activator that same attribute is X:A. Notice that X is not idle after the activation. The Hoare triples above play the roles of assumptions in the formal logic, available for the reasoning about these special statements, and to be thrown off in the final reasoning step about the complete model. We refer to them as the scheduling assumptions. The predicate I and the BC ’s are chosen to fit the particular model at hand. The system invariant must occur as pre- and postconditions for each process class body. The following somewhat simplified proof rule expresses these requirements: ; =1 ; ASS j- fBC gSi fI g i ::n ASS j- fP j- fP gmodelfQg ^ I gS fQg where ASS is the list of scheduling assumptions, and the precondition of process class bodies reflects the fact that a process object is idle upon generation. The model is a program with n process class declarations and the main program S : SIMULATION begin hnonlocal variables and proceduresi process class Ci Si i ::n S end == ; =1 ; In addition to the scheduling assumptions there are axiom schemas expressing the constancy of local variables, as well as the passage of system time over hold and passivate statements and the constancy of system time over activate statements: fRtime (for t> 0) time+t ghold (t)fR g f8 > time ) Rtime ^gpassivatefRg fRgactivate X fRg where R is an arbitrary formula in local variables, time and self references. In actual cases it is useful to conjoin the pre- and postconditions of one of the assumptions with those of a corresponding axiom. The fact that only one pair of assumptions for passivate and activate statements for each process class is allowed, may cause some complication for the reasoning if a class contains several such statements. It is sometimes useful to introduce explicit references to the program control of process objects in the predicates B and I in order to distinguish between different situations. Any simulation model satisfies the general principle that system time can never decrease. This can be expressed by the following axiom: 9q 0: BoxFlow q0 ` b hdTL0 ^ bf (q `b; p)= BF `a q 0` b ^ at(q ` b; p)= At(q ` b; AT ) ^ ss0(q `b; p)= Ss(q 0 ` b; AT ; SS; p) ^(q = " ^ :b:idle ) b:evtime AT +si)] ^ [at(q ` b; p) time < at(q ` b; p)+si ) " `b hd TL ^ bf (q ` b; p)= BF `b ^ at(q ` b; p)= AT ^ ss(q `b; p)= SS] ^ [time at(q ` b; p)+si ) bf (q ` b; p) hd BF] else if q = 6 " then J (lr(q); rt(q )) else TL = BF = " ^ AT = ,si ^ SS = 0 fi fi The invariant talks about an arbitrary switch in the pyramid. The first conjunct states that the sequence of boxes so far routed toward the switch, BF `a TL, is an initial part of the final value of the local box flow for the current input. This is a consequence of the monotonicity property mentioned earlier. For an arbitrary initial part q`b of the current input, such that the switch is on the path of the box b, the J predicate states how the arrival time of b, as well as the resulting local box flow and switching state can be computed from the state of the Switch object at relevant system times. The last conjunct of the first implication of J is a consequence of the general system time principle. If the switch is not on the path of b, its state remains unchanged. The prediction functions for the arrival time and the switching state are defined inductively: (";0 AT ) == AT (q ` b; AT ) == if b:idle then At(q0 ; AT )+si 0 else max(b:evtime; At(q ; AT )+si) fi Ss("; AT ; SS; p) == SS Ss(q0 ` b; AT ; SS; p) == if b:idle _ b:evtime < At (q0 ; AT ) _ #p = N then Ss(q0 ; AT ; SS; p) else b:ad[#p +1] fi Notice that for any Switch object SW (p), total input INP, and a sufficiently large system time, the system invariant gives, by its first conjunct and the last conjunct of J for q = INP: with SW (p) BF `a TL hd bf (INP; p) ^ bf (INP; p) hd BF which, for p : Addr implies the desired final result. At At Proofs 8X : process :X:idle ) X:evtime time We show the process class Box embellished with state assertions sufficient to carry out a formal verification. It is worth noticing that these assertions imply those provided for the complete program shown earlier. For instance, = = " ^ B = lt(TL) ^ time = AT +si follows from the second conjunct of J for p = P , q = Q, and b = B , which asserts " ` B hd TL and at(Q ` B; P )= AT. where X:evtime is the system time scheduled for the present or next active phase of X , provided X is not idle. Thus, if X is currently active, then X:evtime time. The system invariant The system invariant is fairly complicated. This is partly due to the fact that the functions bf, at and ss of the applicative specification compute the final results for given input, whereas the corresponding program variables BF, AT and SS of a Switch object refer to the current state, as it evolves. I == 8p : SwPos with SW (p) BF `aTL hd bf (INP; p) ^ [TL =6 " ) : lt(TL):idle] ^ 8q : BoxFlow; b : Box q ` b hd INP ) b = b:B ^ q = b:Q ^ J (q; b) where J (q; b) == if op(b; q; p) then [if p = " then #q fi else at(q ` b; lr(p)) fi+si < time < at(q ` b; p) ) time Itime , ^ P4 ) TL 6 The predicates R; P1; : : : ; P4 formally violate the constancy axioms for scheduling statements in referring to Box attributes. They are not local in the sense of being inaccessible to other process objects, however, a syntactic check on the program shows that Box attributes are not changed nonlocally, thus providing a sufficient guarantee for constancy. Fortunately, references to Switch attributes are not needed in the constancy predicates. Technically, the predicate BBox occurring in the scheduling assumptions should be: with SW (P ) if B 6= lt(TL) then I ^time = fi#INPelse I ^P3 fi AT time We mention below a few of the less obvious verification conditions. Notice that in proving that the system invariant holds after modifications, not only the instance corresponding to p P , = ( : : ) == = ; := ; := ; = # = = = ; := ; = # =; ( ) : := ; ; = ( ) ; ( )= ( ) ; ; := ; ( ); := := ( ); = ( ) [ ] # ; := ; 1. process class Box ad Addr ; tt TimeIntv 2. begin var P SwPos " ”const Q INP” const B this Box 3. assert I ^ time fi INP ^ P " ^ B this Box ^ Q INP 4. INP INP ` B assert I ^ R ^ time fi INP ^ P " 5. loop inspect SW P do assert I ^ R time time 6. TL TL ` B assert Itime + ^ P1 if P 6 " then hold tt fi assert Itime , ^ P2 7. if lt TL 6 B then assert I ^ R ^ time lt TL :evtime passivate else if P <N then SS ad AT time 8. assert Itime ^ P3 “AT time”; assert I ^ P3 hold si assert Itime ^ P4 , 9. “BF BF `B ”; TL rr TL this Box; idle AT 10. if TL 6 " then if lt TL :idle then assert Itime ^ P3 lt(TL); false ^ P4 activate lt TL assert I ^ P4 11. else assert I ^ P4 ^ TL:evtime time fi fi 12. while P <N 13. P P ` SS assert I ^ R 14. od repeat end : # where and and and and # ; ; ; := [#P +1] fi fi; ( ); R == #P N ^ B = this Box ^ Q ` B hd INP ^ op(Q ` B; P ) == R ^ time = if P = " then fi #Q else at(Q ` B; lr(P ))+si fi == R ^ time = if P = " then fi #Q else at(Q ` B; lr(P ))+si+tt fi == R ^ time = at(Q ` B; P ) == R ^ time = at(Q ` B; P )+si: P1 P2 P3 P4 b = B , and q = Q, but also the (other) objects contained in SW (P ):TL must be considered. This makes the proofs of some or the verification conditions quite lengthy. SS; AT time L7: Itime , ^ P2 ^ lt TL B ^ P <N ) Iad[#P+1];time ^ P3. P2 and the axiom A10 show that the first implication of J applies for time , . Then lt TL B gives q 0 " and thus at Q ` B; P At " ` B; AT max B:evtime; AT si time, where the last equality is a consequence of the last conjunct of the present J case and the fact that B is active. It follows that the second J case applies to the consequent, which holds, as well as P3. It is easy to see that the predictions for any successor in TL remains unchanged. In the case of ltTL 6 B we conclude at Q ` B; P > time, using the fact that time lt TL :evtime. (I gives : lt TL :idle.) Then the predictions of all members of TL remain unchanged when B goes idle. L10: For the precondition of the activate statement we have to prove (since P4 is not affected by the assignments to TL and BF): time Itime , ^ P4 ^ rr TL 6 " ^ lt rr TL :idle ) ; idle; TL; BF AT ^ P3 ltthisBox Itime (rr(TL)); false;rr(TL);BF`B According to the premise the second J alternative applies, which shows that at Q`B; P AT and time AT si. For the modified I of the consequent the third J case applies, which holds in view of the substitution on BF. We instantiate q;0b in J0 of the premise to Q0 ; B 0 , where B 0 lt rr TL and Q B :Q. We have time , 0 at Q `B; P si , at Q ; P si , < at Q0 ` B 0 ; P where the second equality is a consequence of the first conjunct of I and monotonicity, which shows that Q `B hd Q0 , and that no box of the extension has P on its path. The inequality is a consequence of A10 and shows that the first J case applies here. Therefore the premise implies: at Q0`B 0 ; P At " `B`B 0 ; AT At " `B; AT si AT si Instantiating q; b of the modified I of the consequent to Q0 ; B 0 , the above results show that the second J case applies, which implies: at Q0 ` B0 ; P time AT si (QED) Similar reasoning applies to the value of SS. The modified P3 is easily verified. The case that lt rr TL is not idle may be verified using similar techniques. Here the general system time principle ( )= ( # ( )= )= ( )= ( = ( ) )+ ( = ( )= ( ( + )= ( ) ( ) = ( ( )) ] ( )= = + [ = ( ( ) = = )+ )= ( )= ( ( )) = + = ( ( )) ( ) )+ = + must be used in order to prove the last conjunct of the first J case. The case that rr(TL) is empty is trivial, since there exist no Q0 ; B 0 as above to consider.. CONCLUSIONS We have presented a non-trivial simulation program in imperative style, as well as an applicative specification. Using program verification techniques we have shown how a formal proof of equivalence may be constructed. The whole venture was meant as an experiment to see whether such a proof would be feasible at all. In that sense the experiment was successful. However, the proof was surprisingly difficult, in fact so difficult that the feasibility of the approach for more realistic models seems doubtful. One conclusion is inescapable: this is not the way a programmer’s mind works when constructing imperative simulation programs. REFERENCES Balzer, R., N. Goldman, D. Wile. 1981. “Operational Specification as the Basis for Rapid Prototyping.” ACM SIGSOFT Software Engineering Symposium on Rapid Prototyping, (Oct.) 1981. Dahl, O.-J. 1985. “Specification and Reasoning about Discrete Simulation Models: A Case Study.” Research Report no. 94, Dept. of Informatics, University of Oslo, (Aug.) 1985. Dahl, O.-J., O. Owe. 1992. “Formal Development with ABEL.” In VDM’91, Formal Software Development Methods, Volume 2, S. Prehn and W.J. Toetenel, eds. LNCS 552, Springer, 330–362. Dahl, O.-J. 1992. Verifiable Programming. Prentice Hall.
© Copyright 2024