Está en la página 1de 50

1

The B-method: an Introduction


Sample solutions to exercises

This document contains sample solutions to the exercises in the book The B-Method: an Introduction by Steve Schneider. Steve Schneider S.Schneider@rhul.ac.uk June 2001

The B-Method: an Introduction Sample solutions to exercises from Chapter 1


Exercise 1.1 reset = PRE true THEN serve , next := 0 , 0
END

Exercise 1.2 MACHINE Ticket VARIABLES serve , next INVARIANT serve next serve next next 501 INITIALISATION serve , next := 0 , 0 OPERATIONS ss serve next = PRE serve < next THEN ss , serve := serve + 1 , serve + 1
END

tt

take ticket = PRE next 500 THEN tt , next := next , next + 1


END

END Exercise 1.3 nn query = true THEN nn := next serve


PRE END

Exercise 1.4 MACHINE Ticket14 VARIABLES serve , next , record INVARIANT serve next record serve next INITIALISATION serve , next , record := 0 , 0 , 0 OPERATIONS ss serve next = PRE serve < next THEN ss , serve , record := serve + 1 , serve + 1 , 0
END

tt

take ticket = PRE true THEN tt , next , record := next , next + 1 , record + 1
END

rr

query record = true THEN rr := record


PRE END

END

Exercise 1.5 MACHINE Ticket VARIABLES serve , next , lim INVARIANT serve next lim serve next next lim INITIALISATION serve , next , lim := 0 , 0 , 500 OPERATIONS ss serve next = PRE serve < next THEN ss , serve := serve + 1 , serve + 1
END

tt

take ticket = PRE next < lim THEN tt , next := next , next + 1
END

limit ( nn ) = PRE nn next nn THEN lim := nn


END

END Exercise 1.6 No, this operation is not consistent with the invariant of the Ticket machine, since it may be called in the state in which serve and next are both 0. It can be made consistent by strengthening the precondition to serve > 0.

Exercise 1.7 MACHINE CarPark VARIABLES contents INVARIANT contents contents 640 INITIALISATION contents := 0 OPERATIONS

enter = PRE contents < 640 THEN contents := contents + 1


END

leave = PRE contents > 0 THEN contents := contents 1


END

nn

query = PRE true THEN nn := contents


END

END

The B-Method: an Introduction Sample solutions to exercises from Chapter 2


Exercise 2.1 1. { {}, {fred}, {ginger }, {fred, ginger }, {harold}, {fred, harold}, {ginger , harold}, {fred, ginger , harold}} 2. { (fred, fred), (fred, ginger ), (fred, harold), (ginger , fred), (ginger , ginger ), (ginger , harold), (harold, fred), (harold, ginger ), (harold, harold)} 3. 512(= 29 ) 4. 256(= 2( 23 ))

MEMBER.

Yes to both questions: {{fred}, {ginger }} MEMBER, and {{fred, ginger }}

Exercise 2.2 {} {home, work} = {}. S T = T S if S = {} or T = {} or S = T . Exercise 2.3 This is the set of cubes of size less than 100, which is { 0, 1, 8, 27, 64 } Exercise 2.4 1. always true 2. not always true 3. always true 4. always true 5. not always true 6. always true 7. always true

The B-Method: an Introduction Sample solutions to exercises from Chapter 3

Exercise 3.1

0, {} 0, {olly} 0, {pat } 0, {olly, pat } 1, {} 1, {olly} 1, {pat } 1, {olly, pat } 2, {olly, pat } 2, {olly} 2, {pat } 2, {}

0, {} 0, {olly} 0, {pat } 0, {olly, pat } 1, {} 1, {olly} 1, {pat } 1, {olly, pat } 2, {olly, pat } 2, {olly} 2, {pat } 2, {}

0, {} 0, {olly} 0, {pat } 0, {olly, pat } 1, {} 1, {olly} 1, {pat } 1, {olly, pat } 2, {olly, pat } 2, {olly} 2, {pat } 2, {}

Exercise 3.2

0, 0 0, 1 0, 2 1, 0 1, 1 1, 2 2, 0 2, 1 2, 2

0, 0 0, 1 0, 2 1, 0 1, 1 1, 2 2, 0 2, 1 2, 2

The states which reach a state in which x+y = 2 are (0, 2), (2, 2), (1, 2), (2, 1), (2, 0). By calculation, we obtain: [ IF x < y THEN y := y x ELSE x := x y END ](x + y = 2) = = = = (x < y [y := y x](x + y = 2)) (x (x 2 [x := x y](x + y = 2)) y x y + y = 2) y x = 2) (x < y x + y x = 2) (x < y y = 2) (x max(x, y) = 2

which yields the same states as obtained directly from the relation.

Exercise 3.3

IF E1 THEN S1

ELSIF E 2 THEN S2 ELSIF ... P ELSIF En THEN Sn ELSE Sn+1 END

E1 [S1 ]P (E1 E2 ) [S2 ]P = ... (E1 ... En1 En ) [Sn ]P (E1 E2 ... En ) [Sn+1 ]P

Exercise 3.4 1. serve + new 2. serve + new next next + 1

3. z.(z 7 < z 2 ) (= false) 4. house set {x, y} (x 1)..(y + 1) = house set x 1..y + 1 5. num = card(house set ) 6. house set old set {new} Exercise 3.5 If i is even then it sets ans to even, otherwise it sets it to odd. The weakest precondition for it to establish that ans = even is that i mod 2 = 0. Exercise 3.6 That (i + 2)/3 is not 2 or 3; i.e. that i < 4 or that i > 9.

The B-Method: an Introduction Sample solutions to exercises from Chapter 4


Exercise 4.1 allmags = PRE true THEN magazines := papers
END

This operation is consistent with the invariant of Paperround. Exercise 4.2 removehouse(hh) = PRE hh papers THEN papers := papers {hh} || magazines := magazines {hh}
END

The proof obligations for this operation are given by instantiating I P [S ]I : in this case, that (papers 1..163 magazines papers card(papers) 60) hh papers 60)

[papers := papers {hh} || magazines := magazines {hh}] (papers 1..163 magazines papers card(papers)

or, using the weakest precondition rule for assignment, that (papers 1..163 magazines papers card(papers) card(papers {hh}) 60) 60) hh papers

(papers {hh} 1..163 magazines {hh} papers {hh}

which is true by elementary logic and set theory. Exercise 4.3 The operations addmagazine and remove are not consistent with the new invariant. Their preconditions require strengthening, for example as follows: addmagazine ( hh ) = PRE hh papers card ( magazines ) < card ( papers ) / 2 THEN magazines := magazines { hh }
END

remove ( hh ) = PRE hh 1 . . 163 card ( magazines { hh } ) card ( papers { hh } ) / 2

10 THEN END

papers := papers { hh }

magazines := magazines { hh }

Exercise 4.4 The operation board is consistent with the invariant of Bus. The other two operations, buy and double are not consistent. The machine can be amended by strengthening the invariant so that tickets passengers is a clause; and by altering the precondition of buy to ensure the (new) invariant is met, resulting in the following machine: MACHINE Bus VARIABLES tickets , passengers INVARIANT tickets passengers tickets passengers INITIALISATION tickets , passengers := 0 , 0 OPERATIONS buy ( mm ) = PRE mm tickets + mm passengers THEN tickets := tickets + mm
END

board ( nn ) = PRE nn THEN passengers := passengers + nn


END

double = PRE true THEN tickets , passengers := 2 tickets , 2 passengers


END

END With the additional clause passengers tickets + 45 in the invariant, the operations board and double which increase the number of passengers require stronger preconditions to prevent violation of this new clause. The new precondition for board is nn passengers + nn tickets + 45

The new precondition for double is passengers tickets + 22

11

The B-Method: an Introduction Sample solutions to exercises from Chapter 5


Exercise 5.1 The proof obligations are: 1. ITEM , sample, num.ITEM {} sample ITEM num num > card(ITEM ). This proof obligation is true. Observe that the set ITEM must be non-empty, and is an implicit clause of the constraint. 2. (ITEM {} sample ITEM num num > card(ITEM )) storage.storage 1 storage num. This proof obligation is also true. 3. (ITEM {} sample ITEM num num > card(ITEM ) storage 1 storage num) existscurrent , nextprevious.current ITEM next ITEM previous ITEM next previous. This proof obligation is not true in the case where ITEM is a singleton set. Thus it is not universally true, and hence the machine clauses are not all consistent. Exercise 5.2 The initialisation is consistent with the invariant, constraints and properties, since num 2 follows from them. input is not consistent, since nn = next is a permitted input, resulting in a state which violates the invariant. output is not consistent, since it also reaches a state in which next current , violating the invariant. increment is consistent.

12

The B-Method: an Introduction Sample solutions to exercises from Chapter 6


Exercise 6.1 1.

ian jim ken lisa eats 2. {ian}

eggs cheese salad pizza

eats = {ian eggs, ian cheese, ian pizza} ken pizza, lisa cheese, lisa salad, lisa pizza}

3. {jim} eats = { ian eggs, ian cheese, ian pizza 4. eats {cheese, pizza} = { ian cheese, ian pizza, ken pizza, lisa cheese, lisa pizza 5. dom(eats 6. dom(eats 7. dom(eats Exercise 6.2 1. eats[{ian, lisa}] = {eggs, cheese, pizza, salad} 2. eats 1 = { eggs ian, cheese ian, pizza ian, eggs jim, salad jim, pizza ken, cheese lisa, salad lisa, pizza lisa} 3. eats 1[{cheese, eggs}] = {ian, jim, lisa} 4. eats ; cost = { ian cheap, ian expensive, jim cheap, kenmapstoexpensive, lisa cheap, lisa expensive} 5. eats ; (cost {expensive}) = {ian cheap, jim cheap, lisa cheap} 6. eats 1[cost 1 [{expensive}]] = {ian, ken, lisa}
+ 7. eats < {lisa steak} = { ian eggs, ian cheese, ian pizza,

{eggs}) = {ian, jim} {eggs, pizza}) {cheese}) dom(eats {pizza})

jim eggs, jim salad, ken pizza, lisa steak}

13

Exercise 6.3 The invariant becomes access USER PRINTER uu . (uu USER card(access[{uu}]) 6)

Two operations are no longer consistent with this strengthened invariant: add, and unify. In order to regain consistency of the machine, the precondition of add can be strengthened to uu USER pp PRINTER card(access[{uu}]) < 6 and the precondition of unify can be strengthened to u1 USER u2 USER card(access[{u1}]) + card(access[{u2}]) . Exercise 6.4 exchange ( u1 , u2 ) = PRE u1 USER u2 USER + THEN access := access < ( { u1 } access [ { u2 } ] { u2 } access [ { u1 } ] )
END

Exercise 6.5 maintenance ( pp , alt ) = PRE pp PRINTER alt PRINTER THEN access := access { pp } access
END

[ { pp } ] { alt }

Exercise 6.6 The variable barred and associated conditions and operations are incorporated into the machine below. The operations which require strengthened preconditions are again add and unify. all other operations are consistent with the next invariant and remain unchanged from their description in the original Access machine. MACHINE Access SETS USER ; PRINTER ; OPTION ; PERMISSION = { ok , noaccess } CONSTANTS options PROPERTIES options PRINTER OPTION

14

dom ( options ) = PRINTER ran ( options ) = OPTION VARIABLES access , barred INVARIANT access USER PRINTER barred USER OPTION ( access ; options ) barred = {} INITIALISATION access , barred := {} , {} OPERATIONS addbar ( uu , oo ) = PRE uu USER oo OPTION THEN barred := barred { uu oo } access := access { uu } options
END

[ { oo } ]

removebar ( uu , oo ) = PRE uu USER oo OPTION uu oo barred THEN barred := barred { uu oo }


END

add ( uu , pp ) = PRE uu USER pp PRINTER options [ { pp } ] barred [ { uu } ] = {} THEN access := access { uu pp }


END

unify ( u1 , u2 ) = PRE u1 USER u2 USER access ; options [ { u1 , u2 } ] barred [ { u1 , u2 } ] = {} THEN access := access { u1 } access [ { u2 } ] { u2 } access [ { u1 } ]
END

END

15

The B-Method: an Introduction Sample solutions to exercises from Chapter 7


Exercise 7.1 MACHINE Reading SETS READER ; BOOK ; COPY ; RESPONSE = { yes , no } VARIABLES books , copies , copyof , hasread , reading INVARIANT copyof copies books books BOOK copies COPY hasread READER books reading READER copies ( reading ; copyof ) hasread = {} INITIALISATION copyof := {} books := {} copies := {} hasread := {} reading := {} OPERATIONS addcopy ( cc , bb ) = PRE cc COPY bb BOOK cc copies THEN copies := copies { cc } books := books { bb } copyof := copyof { cc bb }
END

start ( rr , cc ) = PRE rr READER cc copies copyof ( cc ) hasread [ { rr } ] rr dom ( reading ) cc ran ( reading ) THEN reading := reading { rr cc }
END

nished ( rr , cc ) = PRE rr READER cc copies cc = reading ( rr ) THEN hasread := hasread { rr copyof ( cc ) } reading := { rr } reading
END

;
precurrentquery ( rr ) = rr READER

resp
PRE THEN

IF rr dom ( reading ) THEN resp := yes ELSE resp := no END END

bb

currentquery ( rr ) = rr READER rr dom ( reading ) THEN bb := copyof ( reading ( rr ) )


PRE END

;
hasreadquery ( rr , bb ) = rr READER bb BOOK

resp
PRE

16 THEN IF bb hasread [ { rr } ] THEN resp := yes ELSE resp := no END END

END Exercise 7.2 pp position ( rr ) = rr ran ( nish ) THEN pp := nish 1 ( rr )


PRE END

remove ( rr ) = PRE rr ran ( nish )


THEN

pp BE pp = nish
LET IN END END

( rr ) ( nish pp )

nish := nish pp 1

17

The B-Method: an Introduction Sample solutions to exercises from Chapter 8


Exercise 8.1 [a(i) := 5](a(j ) = a(k) = =
+ + (a < {i 5})(j ) = (a < {i 5})(k)

i =j i =k i = j i k a(k) = 5 i j i = k a(j ) = 5 i j i k a(j ) = a(k)

Exercise 8.2 a := x . (x dom(a) | 2 x) Exercise 8.3 betterswap ( rr , ss ) =


PRE

rr ROOM ss ROOM ( rr small numbers ( ss ) 4 ) ( ss small numbers ( rr ) 4 ) + THEN numbers := numbers < { rr numbers ( ss ) , ss numbers ( rr ) }
END

Exercise 8.4 step = guests := xx . ( xx Exercise 8.5 MACHINE Hotelguests ( sze ) CONSTRAINTS sze 1 SETS NAME ; REPORT = { present , notpresent } CONSTANTS empty , ROOM PROPERTIES card ( ROOM ) = sze empty NAME ROOM VARIABLES pguests INVARIANT pguests ROOM NAME INITIALISATION pguests := {} OPERATIONS guestcheckin ( rr , nn ) =

xx + 1 ROOM

| guests ( xx + 1 ) )

18 PRE

rr ROOM nn NAME THEN pguests ( rr ) := nn


END

guestcheckout ( rr ) = PRE rr ROOM THEN pguests := { rr } pguests


END

nn

guestquery ( rr ) = rr ROOM THEN IF rr dom ( pguests ) THEN nn := pguests ( rr ) ELSE nn := empty


PRE END END

rr

presentquery ( nn ) = PRE nn NAME THEN IF nn ran ( pguests ) THEN rr := present ELSE rr := notpresent
END END

guestswap ( rr , ss ) = PRE rr ROOM ss ROOM


THEN IF rr dom ( pguests ) THEN IF

ss dom ( pguests ) + THEN pguests := pguests < { rr pguests ( ss ) , ss pguests ( rr ) } ELSE pguests := { rr } pguests { ss pguests ( rr ) }

END ELSE IF ss dom ( pguests ) THEN END END END

pguests := { ss } pguests { rr pguests ( ss ) }

step = pguests := xx . ( xx END

xx + 1 dom ( pguests )

| pguests ( xx + 1 ) )

19

The B-Method: an Introduction Sample solutions to exercises from Chapter 9


Exercise 9.1 ANY nn WHERE nn : THEN square := nn nn END Exercise 9.2 This operation adds some arbitrary value between 1 and 5 to total. [ ANY a WHERE a 1 a = = = a . (a 1 a a . (a 1 a 8 5 THEN total := total + 5 END ](total > 8)

5 [total := total + a](total > 8)) 5 total + a > 8)

total

Exercise 9.3 This statement picks an arbitrary set of up to three numbers between 1 and N . [ ANY s WHERE s 1..N card(s) = = = s . s 1..N card(s) s . s 1..N card(s) N 14 3 THEN myset := s END ](i.(i myset | i) < 40)

3 [myset := s](i.(i myset | i) < 40) 3 (i.(i s | i) < 40)

The statement is guaranteed to achieve the postcondition provided the numbers comprising the set are all no greater than 14. Exercise 9.4 ANY nn WHERE nn 1..49 card(nn) = 6 THEN ticket := nn END Exercise 9.5 ANY d WHERE d : order [{p}] THEN delivery := d END

[ ANY d WHERE d : order [{p}] THEN delivery := d END ](delivery fridge) = = = d.(d : order [{p}] [delivery := d](delivery fridge)) d.(d : order [{p}] d fridge)) fridge order [{p}]

20

Exercise 9.6 CHOICE salary := salary 1.03 OR salary := salary + 400 END

[ CHOICE salary := salary 1.03 OR salary := salary + 400 END ](salary > 14000) = = = = [salary := salary 1.03](salary > 14000) [salary := salary + 400](salary > 14000] (salary 1.03 > 14000) (salary > 13600) salary > 13592 salary > 13600 salary > 13600

Exercise 9.7 1. WHEN betty here THEN hh := betty WHEN clarissa here THEN hh := clarissa ELSE hh := do END = SELECT albert here THEN hh := albert (hh = clarissa)

albert here [hh := albert ](hh = clarissa) (betty here [hh := betty](hh = clarissa)) (clarissa here [hh := clarissa](hh = clarissa) (albert here betty here clarissa here [hh := do](hh = clarissa)

albert here false (betty here false (clarissa here true (albert here betty here clarissa here false

= 2.

albert here betty here clarissa here

WHEN betty here THEN hh := betty WHEN clarissa here THEN hh := clarissa ELSE hh := do END =

SELECT albert here THEN hh := albert

(hh albsert )

albert here [hh := albert ](hh albert ) (betty here [hh := betty](hh albert )) (clarissa here [hh := clarissa](hh albert ) (albert here betty here clarissa here [hh := do](hh albert )

albert here false (betty here true

21

(clarissa here true (albert here betty here clarissa here true = 3. SELECT albert here THEN hh := albert WHEN betty here THEN hh := betty WHEN clarissa here THEN hh := clarissa ELSE hh := do END = (hh do) albert here

albert here [hh := albert ](hh do) (betty here [hh := betty](hh do)) (clarissa here [hh := clarissa](hh do) (albert here betty here clarissa here [hh := do](hh do)

albert here true (betty here true (clarissa here true (albert here betty here clarissa here false

= Exercise 9.8

albert here betty here clarissa here

MACHINE Deliveries SETS ITEM ; ADDRESS VARIABLES van , nogo INVARIANT van ADDRESS INITIALISATION van := {} OPERATIONS load ( aa , ii ) = PRE aa ADDRESS ii THEN van := van { aa
END

ITEM nogo ADDRESS nogo : ( ADDRESS )

ITEM ii }

aa , ii drop = PRE van {}


THEN

ad , it ad ADDRESS it ITEM ad it van THEN aa := ad ii := it


ANY WHERE END END

warning ( aa ) = PRE aa ADDRESS THEN IF aa nogo

22 THEN CHOICE END ELSIF aa dom ( van ) THEN nogo := nogo { aa } END END

van := { aa } van OR nogo := nogo { aa }

END

23

The B-Method: an Introduction Sample solutions to exercises from Chapter 10


Exercise 10.1 The included machine Locks provides no single operation for closing a door and locking it, and Safes can only call one operation from Locks in any of its own operations. The new operation for Locks is quickclose ( dd ) = PRE dd DOOR position ( dd ) = open THEN closedoor ( dd ) status ( dd ) := locked
END

;
The new operation for Safes is

quickcloseandlock ( dd ) = PRE dd DOOR position ( dd ) = open THEN quickclose ( dd ) removekey ( unlocks


END

( dd ) )

Exercise 10.2 MACHINE Safes INCLUDES Locks , Keys PROMOTES opendoor , closedoor , lockdoor CONSTANTS unlocks PROPERTIES unlocks KEY DOOR VARIABLES masterkey INVARIANT status 1 [ { unlocked } ] unlocks [ keys ] masterkey DOOR card ( masterkey ) 1 status 1 [ { unlocked } ] masterkey INITIALISATION masterkey := {} OPERATIONS insertmaster ( dd ) = PRE dd DOOR masterkey = {} THEN masterkey := { dd }
END

removemaster = PRE status [ masterkey ] = { locked } THEN masterkey := {}


END

insert ( kk , dd ) = PRE kk KEY dd DOOR unlocks ( kk ) = dd

24 THEN END

insertkey ( kk )

extract ( kk , dd ) = PRE kk KEY dd DOOR unlocks ( kk ) = dd status ( dd ) = locked THEN removekey ( kk )


END

;
1

unlock ( dd ) = PRE dd DOOR unlocks THEN unlockdoor ( dd )


END

( dd ) keys dd masterkey

quicklock ( dd ) = PRE dd DOOR position ( dd ) = closed THEN lockdoor ( dd ) removekey ( unlocks


END

( dd ) )

END

Exercise 10.3 MACHINE Safes INCLUDES Locks , Keys PROMOTES opendoor , closedoor , lockdoor VARIABLES unlocks INVARIANT status 1 [ { unlocked } ] unlocks [ keys ] DOOR keys dom ( unlocks ) unlocks KEY INITIALISATION unlocks := {} OPERATIONS allocate ( kk , dd ) = PRE kk KEY kk dom ( unlocks ) dd DOOR dd ran ( unlocks ) THEN unlocks ( kk ) := dd
END

deallocate ( kk , dd ) = PRE kk KEY dd DOOR kk dd unlocks kk keys status ( dd ) = locked THEN unlocks := { kk } unlocks
END

insert ( kk , dd ) = PRE kk KEY dd DOOR unlocks ( kk ) = dd THEN insertkey ( kk )


END

extract ( kk , dd ) = PRE kk KEY dd DOOR unlocks ( kk ) = dd status ( dd ) = locked THEN removekey ( kk )


END

;
1

unlock ( dd ) = PRE dd DOOR unlocks

( dd ) keys

25 THEN END

unlockdoor ( dd )

quicklock ( dd ) = PRE dd DOOR position ( dd ) = closed dd ran ( unlocks ) THEN lockdoor ( dd ) removekey ( unlocks 1 ( dd ) )
END

END

Exercise 10.4 MACHINE RobustLocks INCLUDES Locks SETS REPORT = { ok , error } OPERATIONS rep robustopen ( dd ) = PRE dd DOOR THEN IF status ( dd ) = unlocked THEN opendoor ( dd ) rep := ok ELSE rep := error
END END

rep

robustclose ( dd ) = dd DOOR THEN closedoor ( dd ) rep := ok


PRE END

rep

robustunlock ( dd ) = PRE dd DOOR THEN unlockdoor ( dd ) rep := ok


END

rep

robustlock ( dd ) = PRE dd DOOR THEN IF position ( dd ) = closed THEN lockdoor ( dd ) rep := ok ELSE rep := error
END END

END

Exercise 10.5 MACHINE Hotelregister ( sze ) INCLUDES Hotel ( sze ) , Hotelguests ( sze ) PROMOTES guestquery , presentquery , roomquery , vacancies , totalguests INVARIANT guests 1 [ { empty } ] = numbers 1 [ { 0 } ]

26

OPERATIONS fullcheckin ( room , name , number ) = PRE name NAME number 1 . . 6 room ROOM guests ( room ) = empty name empty ( room small number 4 ) THEN checkin ( room , number ) guestcheckin ( room , name )
END

fullcheckout ( room ) = PRE room ROOM THEN checkout ( room )


END

guestcheckout ( room )

fullswap ( room1 , room2 ) = PRE room1 ROOM room2 ROOM room1 small ( room2 small ) THEN swap ( room1 , room2 ) guestswap ( room1 , room2 )
END

END

27

The B-Method: an Introduction Sample solutions to exercises from Chapter 11


Exercise 11.1 MACHINE Limit SEES Goods VARIABLES limit INVARIANT limit GOODS 1 INITIALISATION limit : GOODS OPERATIONS setlimit ( gg , pp ) = PRE gg GOODS pp 1 THEN limit ( gg ) := pp
END

;
limitquery ( gg ) = gg GOODS THEN pp := limit ( gg ) END

pp
PRE

END MACHINE Customer SEES Price , Goods , Limit VARIABLES purchases INVARIANT purchases GOODS INITIALISATION purchases := {} OPERATIONS pp buy ( gg ) = PRE gg GOODS price ( gg ) limit ( gg ) THEN purchases := purchases { gg } pp pricequery ( gg )
END

END

Exercise 11.2 change ( nn ) = PRE nn PERSON nn male female THEN IF nn male THEN female := female { nn } male := male { nn } ELSE male := male { nn } female := female { nn }
END END

The sexchange operation must take into account the possibility that the person nn is married. Here we simply include as a precondition that nn should not be married. Thus the function marriage will not change. An

28

alternative would be to accept married nn as well as unmarried, and update the function marriage by removing nn from it. sexchange ( nn ) = PRE nn male female nn dom ( marriage ) nn ran ( marriage ) THEN change ( nn )
END

Exercise 11.3 MACHINE Voters USES Life SETS RESPONSES = { listed , notlisted } VARIABLES voters INVARIANT voters male female INITIALISATION voters := {} OPERATIONS addvoter ( nn ) = PRE nn male female THEN voters := voters { nn }
END

removevoter ( nn ) = PRE nn male female THEN voters := voters { nn }


END

resp
PRE

voterquery ( nn ) = nn PERSON THEN IF nn voters THEN resp := listed ELSE resp := notlisted
END END

END In fact, Voters can be included in Registrar, and all its operations can be promoted, so the extends clause is used. The dies operation requires amendment: when a person dies then they should also be removed from the electoral roll. MACHINE Registrar EXTENDS Marriage , Voters INCLUDES Life PROMOTES born OPERATIONS dies ( nn ) =

29 PRE THEN

nn male female

die ( nn ) removevoter ( nn ) IF nn dom ( marriage ) THEN part ( nn , marriage ( nn ) ) ELSIF nn ran ( marriage ) THEN part ( marriage 1 ( nn ) , nn )
END END

END

Exercise 11.4 MACHINE Fullregistrar INCLUDES Registrar PROMOTES partner SETS STATUS = { bachelor , spinster , married , divorced , widow , widower } VARIABLES status INVARIANT status male female STATUS status 1 [ { married } ] = dom ( marriage ) ran ( marriage ) INITIALISATION status := {} OPERATIONS birth ( nn , ss ) = PRE nn PERSON nn ( male female ) ss SEX THEN born ( nn , ss ) IF ss = boy THEN status ( nn ) := bachelor ELSE status ( nn ) := spinster
END END

death ( nn ) = PRE nn PERSON nn male female THEN dies ( nn ) IF status ( nn ) married THEN status := { nn } status ELSE IF nn male + THEN status := { nn } status < { marriage ( nn ) widow } + ELSE status := { nn } status < { marriage 1 ( nn ) widower }
END END END

marry ( mm , ) = PRE mm male mm dom ( marriage ) female ran ( marriage ) THEN wed ( mm , )

30
+ status := status < { mm married , married }

END

divorce ( mm , ) = PRE mm male female mm marriage THEN part ( mm , ) + status := status < { mm divorced , divorced }
END

ss

PRE

maritalstatus ( nn ) = nn male female THEN ss := status ( nn )


END

END

31

The B-Method: an Introduction Sample solutions to exercises from Chapter 12


Exercise 12.1 1. aa 1..300 ran(aa) = orders 2. aa 1..300 3. ll seq() ran(ll) = orders

ran(aa) = orders

4. ll iseq() ran(ll) = orders 5.

ll seq() ran(ll) = orders ii, jj . (ii : dom(ll) jj dom(ll) (ii < jj ll(ii) < ll(jj )

Exercise 12.2 The rst renement uses an 11-place array.

REFINEMENT PlayerR REFINES Player VARIABLES teamr INVARIANT teamr 1 . . 11 PLAYER ran ( teamr ) = team PLAYER INITIALISATION teamr : 1 . . 11 OPERATIONS substitute ( pp , rr ) =
BEGIN

teamr ( teamr
END

( pp ) ) := rr

;
query ( pp ) =

aa

IF pp ran ( teamr )

aa := in ELSE aa := out
THEN END

END The second renement uses an array indexed by the players, recording for each whether he is in or out of the team.

REFINEMENT PlayerR2 REFINES Player VARIABLES teamr INVARIANT teamr PLAYER ANSWER team = teamr 1 [ { in } ] INITIALISATION ANY tr WHERE tr PLAYER ANSWER card ( tr THEN teamr := tr

[ { in } ] ) = 11

32 END

OPERATIONS substitute ( pp , rr ) =
BEGIN

teamr ( pp ) := out ; teamr ( rr ) := in


END

;
query ( pp ) = aa := teamr ( pp )

aa END

Exercise 12.3 In the abstract machine: jumpqueue ( ss , qq ) = PRE ss SHIP ss ran ( waiting ) ss ran ( docked ) qq QUAY qq dom ( docked ) THEN docked ( qq ) := ss
END

In the renement: jumpqueue ( ss , qq ) = insert ( ss , qq ) ;

33

The B-Method: an Introduction Sample solutions to exercises from Chapter 13


Exercise 13.1 First style of renement:

REFINEMENT JobshopR REFINES Jobshop VARIABLES jobarr INVARIANT jobarr 1 . . limit JOB ran ( jobarr ) = jobs INITIALISATION jobarr := {} OPERATIONS take ( jj ) = ANY tmp WHERE tmp 1 . . limit tmp dom ( jobarr ) THEN jobarr ( tmp ) := jj
END

jj

process = ANY tmp WHERE tmp dom ( jobarr ) THEN jj := jobarr ( tmp ) ; jobarr := { tmp } jobarr
END

prioritise ( jj ) = jobarr := jobarr { jj } END

REFINEMENT JobshopRR REFINES Jobshop VARIABLES jobarr , counter INVARIANT jobarr 1 . . limit JOB counter 0 . . limit jobarr [ 1 . . counter ] = jobs counter = card ( jobs ) INITIALISATION jobarr : 1 . . limit JOB ; counter := 0 OPERATIONS take ( jj ) =
BEGIN

counter := counter + 1 ; jobarr ( counter ) := jj


END

jj

process = jj := jobarr ( counter ) ; counter := counter 1

BEGIN

END

prioritise ( jj ) = ANY ii WHERE ii 1 . . counter jobarr ( ii ) = jj THEN

34

jobarr ( ii ) := jobarr ( counter ) ; counter := counter 1


END

END Exercise 13.2

REFINEMENT BoothR REFINES Booth VARIABLES reserved , ticketsr INVARIANT ticketsr SEAT CUSTOMER cc . ( cc CUSTOMER card ( ticketsr
1

[ { cc } ] ) [ { cc } ] ) + reserved ( cc ) ) ticketsr := {}

= card ( tickets

INITIALISATION reserved := CUSTOMER { 0 } OPERATIONS reserve ( cc , nn ) =


BEGIN

reserved ( cc ) := reserved ( cc ) + nn ANY ss WHERE ss SEAT card ( ss ) = nn ss dom ( ticketsr ) = {} THEN ticketsr := ticketsr ss { cc }
END END

collect ( cc ) = reserved ( cc ) := 0 END

35

The B-Method: an Introduction Sample solutions to exercises from Chapter 14


Exercise 14.1 There are no sets and constants of ColoursR2 so there are no proof obligations associated with sets and constants. ColoursR2 has no state, and hence no initialisation. However, it does have a non-trivial invariant J which requires that red cols, so it will have a proof obligations associated with initialisation. The initialisation of Colours2 is equivalent to skip, so the proof obligation that concrete initialisation renes abstract initialisation is: [skip][cols : (COLOUR {blue})](red cols) = = ( cols (COLOUR {blue}) . red cols) cols . (cols ({red, green}) red cols)

i.e. there is some subset of {red, green}) which contains redand this proof obligation is true. Each operation PRE P1 THEN S 1 END which renes PRE P THEN S END will have the proof obligation that I J P [S 1[out /out ]][S ](J out = out ), where I is the invariant of Colours. For each operation in turn we calculate [S 1[out /out ]][S ](J out = out ) and show that it is implied by I J P. add(cc): This operation does not have any outputs. [S 1][S ]J = = [skip][cols := cols {cc}](red cols) red (cols {cc}) red cols I J P (= J )

cc query: [S 1[out /out ]][S ]J = = = = [cc := red][cc : cols](red cols cc = cc) ( cc . cc cols (red cols red = cc)) cc . (cc cols (red cols red = cc)) red cols I J P (= J )

change: This operation has no outputs: [S 1][S ]J = [skip][cols : (COLOUR) {cols}](red cols)

36

= = =

( cs . (cs (COLOUR) {cols} (red cs))) cs . (cs (COLOUR) {cols} red cs) true I J P

The penultimate line follows from the fact that there will always be some subset of COLOUR other than cols which contains red (since there are 4 such subsets altogether). Thus all proof obligations are discharges, establishing that ColoursR2 is a renement of Colours. If the invariant is simply true then the query operations proof obligations will not discharge. This linking invariant is not strong enough to establish that ColoursR2 is a renement of Colours.

Exercise 14.2 There are no sets or constants introduced by TeamR, so there are no proof obligations generated there. The proof obligation for initialisation is as follows: [teamr := nn . (nn 1..11 | nn)] [team := 1..11] (teamr 1..11 = 1..22 ran(teamr = team)) 1..22) ( nn . (nn 1..11 | nn) 1..11

ran( nn . (nn 1..11 | nn) = 1..11 (which is true) The proof obligation for substitute is I J P [teamr (teamr 1(pp)) := rr ] [team := team {rr } {pp}] (teamr 1..11 = I J P
+ (teamr < {teamr 1 (pp) rr } 1..11 + ran(teamr < {teamr

1..22 ran(teamr = team)) 1..22

(pp) rr } = team {rr } {pp}))

(which is true) The proof obligation for query is I J [ IF pp ran(teamr ) THEN aa := in ELSE aa := out END ] [ IF pp team THEN aa := in ELSE aa := out END ] (J aa = aa)

37

I J [ IF pp ran(teamr ) THEN aa := in ELSE aa := out END ] J (pp team aa = in pp team aa = out )

I J J (pp ran(teamr ) pp team in = in pp ran(teamr ) pp team out = in pp ran(teamr ) pp team in = out pp ran(teamr ) pp team out = out )

(and this is true, since J implies ran(teamr ) = team.) Exercise 14.3 No, it is not possible. If ColoursR is in the state colour = blue, then this is related to four states of Colours, including {blue} and {blue, green}. In the rst case, alter will result in the state {blue, red} and in the second case {green}. Thus any possible resulting state of alter in the renement ColoursR must match both of these states, since it must rene alter called from either of them. But this is not possible, since there is no resulting value for colour which is in both sets. Exercise 14.4

REFINEMENT Colours2R REFINES Colours2 VARIABLES in , out INVARIANT in cols out COLOUR ( cols COLOUR out COLOUR cols ) in out INITIALISATION in := red out := blue OPERATIONS add ( cc ) = BEGIN IF cc = out THEN out : COLOUR { in , out } END cc inquery = cc := in ; cc outquery = cc := out ; change = skip ; invert = VAR tt IN tt := in ; in := out ; out := tt
END

END

END

38

The B-Method: an Introduction Sample solutions to exercises from Chapter 15


Exercise 15.1 e := 1; i := 0; WHILE i < b DO i := i + 1; e := e 2 INVARIANT i 0..b e = 2i VARIANT b i END establishes postcondition e = 2b . e := 1; i := 0; WHILE i < b DO i := i + 1; e := e a INVARIANT i 0..b e = a i VARIANT b i END establishes postcondition e = a b . Exercise 15.2 i := 0; WHILE i < N DO i := i + 1; arr (i) := i INVARIANT i 0..N dom(arr ) 1..N VARIANT N i ((1..i) END establishes postcondition arr = j .(j 1..i | j ), provided initially dom(arr ) 1..N . Exercise 15.3 The proof obligations are: 1. (r + (q a) = a r > b [q := q + 1; r := r a](r + (q a) = a) 2. (r + (q a) = a (r > b) (q = a div b r = a mod b) 3. r + (q b) = a r arr ) = j .(j 1..i | j )

39

4. (r + (q b) = a r > b r = ) [q := q + 1; r := r b](r < ) 5. [r := a; q := 0](r + (q b) = a) The rst and the fth are true. The second is false in the case where r = b or r < 0. The third is falser could be negative. The fourth is false when b 0, since then r b does not decrease r . The third and fourth indicate that the invariant requires strengthening to state that b > 0 and that r 0. The second proof obligations indicates that the guard of the loop should be r b rather than r > b. Thus the loop should be as follows: r := a; q := 0; WHILE r b DO q := q + 1; r := r b VARIANT r END Since the invariant must be true when the loop is started, it requires that a

INVARIANT r b 1 r + (q b) = a

b 1 .

Exercise 15.4 ans := TRUE j := 2 WHILE j < n DO IF n mod j = 0 THEN ans := FALSE END ; j := j + 1 INVARIANT ans = TRUE ( i.(i 2..j 1 n mod i 0)) j VARIANT n j END n

Exercise 15.5 i := 0; maximum := 0; WHILE i < N DO i := i + 1; IF arr (i) > maximum THEN maximum := arr (i) END INVARIANT maximum = max(arr [1..i] {0}) i 0..N VARIANT N i END

40

Exercise 15.6 We rst calculate [ IF i = 0 THEN rep := FALSE ELSE rep := TRUE END ](rep = TRUE p ran(a)) = = (= i = 0 (FALSE = TRUE p ran(a)) i 0 (TRUE = TRUE p ran(a)) (i = 0 p ran(a)) (i 0 p ran(a)) P)

This is the postcondition for the loop section of the program. The proof conditions for the loop are therefore: 1. (p a[(i + 1)..N ] i a[(i + 1)..N ] i )

i > 0 a(i) p) [i := i 1](p

3. (p a[(i + 1)..N ] i i

2. (p a[(i + 1)..N ] i (i > 0 a(i) p)) P

4. (p a[(i + 1)..N ] i i > 0 a(i) p i = [i := i 1](i < ) 5. [i := N ](p a[(i + 1)..N ] i )

These are all straightforward to establish, except the second, which bears closer examination: (p a[(i + 1)..N ] i (i > 0 a(i) p)) = = i = 0 p a[(i + 1)..N ] a(i) = p p a[(i + 1)..N ] i = 0 p ran(a) a(i) = p i 0 p ran(a) P (p a[(i + 1)..N ] i (i = 0 a(i) = p))

Thus the postcondition of the loop is established. Exercise 15.7 i := 1; j := 1; WHILE a(i) b(j ) DO IF a(i) < b(j )THEN i := i + 1ELSE j := j + 1END INVARIANT ran(a (i 1)) ran(b (j 1)) {} x . (x dom(a) x size(a) a(x) x . (x dom(b) x size(b) b(x) VARIANT size(a) + size(b) i j END a(x + 1)) b(x + 1))

41

Exercise 15.8 i := a; j := b; k := a; l := b; WHILE i j DO IF i < j THEN j := j i; l := l + k ELSE i := i j ; k := k + l END INVARIANT (i l) + (j k) = 2 a b VARIANT i + j END ; gcd := i; x := (k + l)/2 The value of x at the end of the loop is (k + l)/2, and i = j = gcd(a, b). Since the invariant il + jk = 2ab is true on termination, i.e. gcd(a, b) (l + k) = 2ab, we have that (k + l)/2 = ab/gcd(a, b) = lcm(a, b), i.e. x is the lowest common multiple of a and b: the smallest number that they both divide into.

42

The B-Method: an Introduction Sample solutions to exercises from Chapter 16

Exercise 16.1

We must establish that I J P [S 1[out /out ]][S 1]J , where S 1 and S are the bodies of the implementation and specication respectively of add.

[ VAR nn IN nn number ;

IF nn < cap THEN rr := ok; input (ee); inc ELSE rr := failed END

END ]

[ IF size(queue) < cap THEN rr := ok = [ VAR nn IN nn number ; IF nn < cap

queue := queue ee ELSE rr := failed END ] END ]

(counter = size(contents) contents = queue rr = rr )

THEN rr := ok; input (ee); inc ELSE rr := failed END (size(queue) < cap (counter = size(contents) contents = queue ee rr = ok) size(queue) = cap (counter = size(contents) contents = queue rr = failed) IF nn < cap THEN rr := ok; PRE ee ELEM size(contents < cap) THEN contents := contents ee END ; counter := counter + 1 ELSE rr := failed END END ] (size(queue) < cap ( counter = size(contents) contents = queue ee rr = ok) size(queue) cap ( counter = size(contents) contents = queue rr = failed) [ VAR nn IN nn := counter ;

43

counter < cap (size(queue) < cap ( counter + 1 = size(contents ee) contents ee = queue ee ok = ok) size(queue) cap ( counter + 1 = size(contents) contents ee = queue ok = failed)) counter cap (size(queue) < cap ( counter = size(contents) contents = queue ee failed = ok) size(queue) cap ( counter = size(contents) contents = queue failed = failed))

counter < cap size(queue) < cap (counter + 1 = size(contents ee) contents ee = queue ee) counter cap size(queue) cap (counter = size(contents) contents = queue)

counter = size(contents) contents = queue I J P

as required. Exercise 16.2 MACHINE RussianMult OPERATIONS rr mult ( aa , bb ) = PRE aa 1 bb 1 THEN rr := aa bb


END

END

IMPLEMENTATION RussianMultI REFINES RussianMult IMPORTS RussianBody OPERATIONS rr mult ( aa , bb ) = VAR xx , yy , total IN xx := aa ; yy := bb ; total := 0 ; WHILE xx > 0 DO xx , yy , total body ( xx , yy , total )

44 INVARIANT VARIANT END END

total + xx yy = aa bb xx

yy total

xx

rr := total END MACHINE RussianBody OPERATIONS dd , ee , tt body ( xx , yy , ss ) = PRE xx yy ss


THEN IF xx mod 2 = 1 THEN

tt := ss + yy END

dd := xx / 2 ee := yy 2
END

END Exercise 16.3

IMPLEMENTATION DateI REFINES Date SEES DateFields PROPERTIES DATE = { dd , mm , yy | dd DAY mm MONTH yy YEAR ( mm { April , June , September , November } dd 30 ) ( mm = February dd 29 ) ( mm = February ( yy YEAR yy mod 4 0 } ( yy mod 100 = 0 yy mod 400 0 ) ) dd 28 ) END MACHINE DateFields SETS DAY ; YEAR ; MONTH = { January , February , March , April , May , June , July , August , September , October , November , December } PROPERTIES DAY = 1 . . 31 YEAR = END

45

The B-Method: an Introduction Sample solutions to exercises from Chapter 17


Exercise 17.1 IMPLEMENTATION HeapI ... OPERATIONS insert ( nn ) =
BEGIN

inc ;
VAR ii , rep IN

ii number ; rep := TRUE ; append ( nn ) ; WHILE ii > 1 rep = TRUE DO rep siftup ( ii ) ; ii := ii / 2 INVARIANT ii 1 . . counter counter = size ( queue ) + 1 ( xx , yy ) . ( xx 2 . . counter 1 yy 1 . . counter 1 ( xx yy parent * ( rep = FALSE xx . ( xx
VARIANT END END END

xx ii ) heaparray ( yy ) heaparray ( xx ) ) ) card ( heaparray


1

[ { xx } ] )

= card ( ( queue nn) 1 [ { xx } ] ) ) ii

MACHINE Heaparray ... rr siftup ( ii ) = PRE ii 2 . . size ( heaparray ) THEN IF heaparray ( ii / 2 ) > heaparray ( ii ) + THEN heaparray := heaparray < { ii / 2 heaparray ( ii ) , ii heaparray ( ii / 2 ) } rr := TRUE ELSE rr := FALSE
END END

Exercise 17.2 sort ( ii , jj ) = PRE ii 1 . . cap jj 1 . . cap ii < jj

46 THEN ANY

pp

WHERE

pp ii . . jj ii . . jj nn . ( nn ii . . jj 1 pp ; aa ( nn ) pp ; aa ( nn + 1 ) ) + THEN aa := aa < ( pp ; aa )
END

END

IMPLEMENTATION SortarrayI ... sort ( ii , jj ) =


BEGIN VAR

cc , nn IN cc := ii 1 ; WHILE cc < jj DO cc := cc + 1 ; nn get ( cc ) ; insert ( nn ) INVARIANT cc ii 1 . . jj pp . ( pp ii . . cc 1 . . cc ( ii 1 ) ( pp ; queue ) = ii . . cc array = aa VARIANT jj cc


END

array )

END VAR

cc , nn IN cc := ii 1 ; WHILE cc < jj DO cc := cc + 1 ; nn extract ; set ( cc , nn ) INVARIANT cc cc cap pp . ( pp ii . . jj ii . . jj ( pp ; queue ( ii . . cc array ) ) = ii . . jj xx . ( xx ii . . cc 1 array ( xx ) array ( xx + 1 ) ) ( xx , yy ) . ( xx ran ( queue ) yy array [ ii . . cc ] yy xx ) VARIANT cap cc
END

aa )

END END

END

47

The B-Method: an Introduction Sample solutions to exercises from Chapter 18


Exercise 18.1 The constraints clause CONSTRAINTS maximum < 2146483646 must be added to SizeCounter, in order to make use of an Nvar machine.

IMPLEMENTATION SizeCounterI REFINES SizeCounter IMPORTS sze Nvar ( maximum ) INVARIANT sze Nvar = sze INITIALISATION sze STO NVAR ( 0 ) OPERATIONS szeinc = sze INC NVAR ; szedec = sze DEC NVAR ; ss szeget = ss sze VAL NVAR END

Exercise 18.2 MACHINE Checkouts ... OPERATIONS closeandmove ( co1 , co2 ) = PRE co1 COUNTER co2 COUNTER THEN opencounters := opencounters { co1 }
+ queues := { co1 } queues < { co2 ( queues ( co2 )

queues ( co1 ) ) }

END

... IMPLEMENTATION CheckoutsI ... closeandmove ( co1 , co2 ) = VAR tt1 , tt2 , bb IN tt1 get ( co1 ) ; tt2 get ( co2 ) ; bb queues APP SEQ OBJ ( tt2 , tt1 ) ; queues KIL SEQ OBJ ( tt1 ) ; remove ( co1 )
END

...

48

Exercise 18.3 Specication: jumpqueue ( co , cu ) =


PRE

co opencounters cu CUSTOMER cu cc . ( cc dom ( queues ) | ran ( queues ( cc ) ) ) THEN queues ( co ) := cu queues ( co )


END

;
Implementation:

jumpqueue ( co , cu ) = VAR pp , bb IN pp get ( co ) ; queues REV SEQ OBJ ( pp ) ; bb queues PSH SEQ OBJ ( pp , cu ) ; queues REV SEQ OBJ ( pp )
END

Exercise 18.4 rep present ( cu ) = PRE cu CUSTOMER


THEN

cc . ( cc dom ( queues ) | ran ( queues ( cc ) ) ) THEN rep := TRUE ELSE rep := FALSE
END END

IF cu

;
Implementation:

rep

VAR

present ( cu ) = nn , pp , bb , ii , ans IN nn , pp queues FIRST SEQ OBJ ; ans := FALSE ; WHILE nn > 0 DO bb , ii queues MBR SEQ OBJ ( pp , cu ) ; IF bb = TRUE THEN ans := TRUE END ; nn , pp queues NEXT SEQ OBJ ( nn , pp ) INVARIANT nn VARIANT nn
END

rep := ans
END

49

Exercise 18.5 mm maximum = vv , ii , msf IN msf := 0 ; ii marks CRD SET ; WHILE ii > 0 DO vv marks VAL SET ( ii ) ; IF vv > msf THEN msf := vv END ; ii := ii 1
INVARIANT

VAR

ii msf = max ( marks ordn [ ii + 1 . . card ( marks ) ] { 0 } ) marks sset = marks ii

VARIANT END END

mm := msf

Exercise 18.6

IMPLEMENTATION BasketsI REFINES Baskets IMPORTS Baskets set obj ( GOODS , 1000 , 1000 ) , Baskets set ctx , Pfun ( CUSTOMER , Baskets SETOBJ ) , Bool TYPE INVARIANT ( pfun ; Baskets setstruct ) = baskets ran ( pfun ) = Baskets settok OPERATIONS enter ( cu ) = VAR bb , pp IN bb , pp Baskets CRE SET OBJ ; set ( cu , pp )
END

add ( cu , gg ) = VAR pp , bb IN pp get ( cu ) ; bb Baskets ENT SET OBJ ( pp , gg )


END

nn

VAR

checkout ( cu ) = pp , ll , ii , total , vv IN pp get ( cu ) ;

50

ll Baskets CRD SET OBJ ( pp ) ; ii := 0 ; total := 0 ; WHILE ii < ll DO ii := ii + 1 ; vv Baskets VAL SET OBJ ( pp , ii ) ; total := total + price ( vv )
INVARIANT

ii 0 . . ll total = jj . ( jj Baskets setord ( pp ) [ 1 . . ii ] | price ( jj ) ) VARIANT ll ii


END

nn := total ; Baskets KIL SET OBJ ( pp )


END

END

También podría gustarte