You are on page 1of 110

micromodels of software declarative modelling and analysis with Alloy

lecture 4: a case study

Daniel Jackson MIT Lab for Computer Science Marktoberdorf, August 2002

why looseness?

why looseness?
risk-driven modelling give only crucial properties

why looseness?
risk-driven modelling give only crucial properties implementation freedom allow concurrency representation independence

why looseness?
risk-driven modelling give only crucial properties implementation freedom allow concurrency representation independence account for environment fewer assumptions better

why looseness?
risk-driven modelling give only crucial properties implementation freedom allow concurrency representation independence account for environment fewer assumptions better specify a family of systems every program is a family? [Parnas]

example: elevator policy

example: elevator policy


challenge specify a policy for scheduling lifts keep concerns separated

example: elevator policy


challenge specify a policy for scheduling lifts keep concerns separated tight enough all requests eventually served dont skip request from inside lift

example: elevator policy


challenge specify a policy for scheduling lifts keep concerns separated tight enough all requests eventually served dont skip request from inside lift loose enough no fixed configuration of floors, lifts, buttons not one algorithm but a family

complications

complications
multiple lifts dont send all to service one request

complications
multiple lifts dont send all to service one request top and bottom lift going in wrong direction may be nearer

complications
multiple lifts dont send all to service one request top and bottom lift going in wrong direction may be nearer load balancing accommodate strategies based on occupancy, eg dont force nearest lift to serve

approach: promises

approach: promises
ways to deny a request skipping: going past floor bouncing: doubling back before floor

approach: promises
ways to deny a request skipping: going past floor bouncing: doubling back before floor

approach: promises
ways to deny a request skipping: going past floor bouncing: doubling back before floor

approach: promises
ways to deny a request skipping: going past floor bouncing: doubling back before floor policy a lift cant deny a request from inside if a lift denies a floor request some lifts promise to serve it later a lift cant deny the last promise

approach: promises
ways to deny a request skipping: going past floor bouncing: doubling back before floor policy a lift cant deny a request from inside if a lift denies a floor request some lifts promise to serve it later a lift cant deny the last promise

approach: promises
ways to deny a request skipping: going past floor bouncing: doubling back before floor policy a lift cant deny a request from inside if a lift denies a floor request some lifts promise to serve it later a lift cant deny the last promise

approach: promises
ways to deny a request skipping: going past floor bouncing: doubling back before floor policy a lift cant deny a request from inside if a lift denies a floor request some lifts promise to serve it later a lift cant deny the last promise freedoms divide requests amongst lifts postpone allocation decision

basic abstractions

basic abstractions
floor layout orderings above and below top and bottom floors

basic abstractions
floor layout orderings above and below top and bottom floors buttons inside lift and at floors each has an associated floor in a given state, some lit

basic abstractions
floor layout orderings above and below top and bottom floors buttons inside lift and at floors each has an associated floor in a given state, some lit elevator state at or approaching a floor rising or falling promises to serve some buttons

basic abstractions
floor layout orderings above and below top and bottom floors buttons inside lift and at floors each has an associated floor in a given state, some lit elevator state at or approaching a floor rising or falling promises to serve some buttons

basic abstractions
floor layout orderings above and below top and bottom floors buttons inside lift and at floors each has an associated floor in a given state, some lit elevator state at or approaching a floor rising or falling promises to serve some buttons

at floor 2, falling

basic abstractions
floor layout orderings above and below top and bottom floors buttons inside lift and at floors each has an associated floor in a given state, some lit elevator state at or approaching a floor rising or falling promises to serve some buttons

at floor 2, falling

at floor 1, rising

basic abstractions
floor layout orderings above and below top and bottom floors buttons inside lift and at floors each has an associated floor in a given state, some lit elevator state at or approaching a floor rising or falling promises to serve some buttons

at floor 2, falling

approaching floor 2, rising

at floor 1, rising

floor layout

floor layout
open std/orders

floor layout
open std/orders sig Floor { disj up, down: option FloorButton, above, below: option Floor }

floor layout
open std/orders sig Floor { disj up, down: option FloorButton, above, below: option Floor } sig Top extends Floor {} {no up}

floor layout
open std/orders sig Floor { disj up, down: option FloorButton, above, below: option Floor } sig Top extends Floor {} {no up} sig Bottom extends Floor {} {no down}

floor layout
open std/orders sig Floor { disj up, down: option FloorButton, above, below: option Floor } sig Top extends Floor {} {no up} sig Bottom extends Floor {} {no down} fact Layout { Ord[Floor].next = above Ord[Floor].prev = below Ord[Floor].last = Top Ord[Floor].first = Bottom }

floor layout
open std/orders sig Floor { disj up, down: option FloorButton, above, below: option Floor } sig Top extends Floor {} {no up} sig Bottom extends Floor {} {no down} fact Layout { Ord[Floor].next = above Ord[Floor].prev = below Ord[Floor].last = Top Ord[Floor].first = Bottom }

use ordering axioms from standard library

floor layout
open std/orders sig Floor { disj up, down: option FloorButton, above, below: option Floor } sig Top extends Floor {} {no up} sig Bottom extends Floor {} {no down} fact Layout { Ord[Floor].next = above Ord[Floor].prev = below Ord[Floor].last = Top Ord[Floor].first = Bottom }

dont require buttons on all floors allow small scope analysis will place buttons demonically

use ordering axioms from standard library

lifts

lifts
sig Lift { button: Floor ?->? LiftButton, buttons: set LiftButton }

lifts
sig Lift { button: Floor ?->? LiftButton, buttons: set LiftButton }

button panel: allows different lifts to cover different sets of floors

buttons

buttons
sig Button {floor: Floor}

buttons
sig Button {floor: Floor} disj sig LiftButton extends Button {lift: Lift}

buttons
sig Button {floor: Floor} disj sig LiftButton extends Button {lift: Lift} disj sig FloorButton extends Button {}

buttons
sig Button {floor: Floor} disj sig LiftButton extends Button {lift: Lift} disj sig FloorButton extends Button {}

part sig UpButton, DownButton extends FloorButton {}

buttons
sig Button {floor: Floor} disj sig LiftButton extends Button {lift: Lift} disj sig FloorButton extends Button {}

part sig UpButton, DownButton extends FloorButton {}

fact ButtonDefinitions { ~floor = Lift.button + up + down lift = {b: Button, p: Lift | some f: Floor | f->b in p.button} all p: Lift | p.buttons = p.button [Floor] UpButton = Floor.up }

buttons
sig Button {floor: Floor}

define classes of button; redundant but convenient

disj sig LiftButton extends Button {lift: Lift} disj sig FloorButton extends Button {}

part sig UpButton, DownButton extends FloorButton {}

fact ButtonDefinitions { ~floor = Lift.button + up + down lift = {b: Button, p: Lift | some f: Floor | f->b in p.button} all p: Lift | p.buttons = p.button [Floor] UpButton = Floor.up }

sample layout

10

sample layout
fun showLayout () {some Lift.buttons} run showLayout

10

sample layout
fun showLayout () {some Lift.buttons} run showLayout

10

system state

11

system state
declaring state collect together relations that change
sig State { lit: set Button, part rising, falling: set Lift, at, approaching: Lift ->? Floor, promises: Lift -> FloorButton }

11

system state
declaring state collect together relations that change
sig State { lit: set Button, part rising, falling: set Lift, at, approaching: Lift ->? Floor, promises: Lift -> FloorButton }

outstanding requests

11

system state
declaring state collect together relations that change
sig State { lit: set Button, part rising, falling: set Lift, at, approaching: Lift ->? Floor, promises: Lift -> FloorButton }

outstanding requests

lift directions

11

system state
declaring state collect together relations that change
sig State { lit: set Button, part rising, falling: set Lift, at, approaching: Lift ->? Floor, promises: Lift -> FloorButton }

outstanding requests

lift directions

lift positions

11

system state
declaring state collect together relations that change
sig State { lit: set Button, part rising, falling: set Lift, at, approaching: Lift ->? Floor, promises: Lift -> FloorButton }

outstanding requests

lift directions

lift positions

promises: many to many

11

physical constraints on lift state

12

physical constraints on lift state


fun LiftPosition (s: State) { all p: Lift | with s { one (at + approaching)[p] no (at & approaching)[p] p in rising => no approaching[p] & Bottom, no approaching[p] & Top p in rising => no at[p] & Top, no at[p] & Bottom } }

12

physical constraints on lift state


fun LiftPosition (s: State) { all p: Lift | with s { one (at + approaching)[p] no (at & approaching)[p] p in rising => no approaching[p] & Bottom, no approaching[p] & Top p in rising => no at[p] & Top, no at[p] & Bottom } }

sig State { at, approaching: Lift ->? Floor, part rising, falling: set Lift }

rising short for s.rising

12

physical constraints on lift state


fun LiftPosition (s: State) { all p: Lift | with s { one (at + approaching)[p] no (at & approaching)[p] p in rising => no approaching[p] & Bottom, no approaching[p] & Top p in rising => no at[p] & Top, no at[p] & Bottom } }

lift is at or approaching one floor

sig State { at, approaching: Lift ->? Floor, part rising, falling: set Lift }

rising short for s.rising

12

physical constraints on lift state


fun LiftPosition (s: State) { all p: Lift | with s { one (at + approaching)[p] no (at & approaching)[p] p in rising => no approaching[p] & Bottom, no approaching[p] & Top p in rising => no at[p] & Top, no at[p] & Bottom } }

lift is at or approaching one floor

lift is not at and approaching

sig State { at, approaching: Lift ->? Floor, part rising, falling: set Lift }

rising short for s.rising

12

physical constraints on lift state


fun LiftPosition (s: State) { all p: Lift | with s { one (at + approaching)[p] no (at & approaching)[p] p in rising => no approaching[p] & Bottom, no approaching[p] & Top p in rising => no at[p] & Top, no at[p] & Bottom } }

lift is at or approaching one floor

lift is not at and approaching

no rising on approach to bottom

sig State { at, approaching: Lift ->? Floor, part rising, falling: set Lift }

rising short for s.rising

12

physical constraints on lift state


fun LiftPosition (s: State) { all p: Lift | with s { one (at + approaching)[p] no (at & approaching)[p] p in rising => no approaching[p] & Bottom, no approaching[p] & Top p in rising => no at[p] & Top, no at[p] & Bottom } }

lift is at or approaching one floor

lift is not at and approaching

no rising on approach to bottom

no rising at top floor

sig State { at, approaching: Lift ->? Floor, part rising, falling: set Lift }

rising short for s.rising

12

sample state

13

sample state
run LiftPosition

13

sample state
run LiftPosition

13

physical constraints on lift motion

14

physical constraints on lift motion


fun nextFloor (s: State, p: Lift): Floor -> Floor { result = if p in s.rising then above else below }

14

physical constraints on lift motion


fun nextFloor (s: State, p: Lift): Floor -> Floor { result = if p in s.rising then above else below } fun LiftMotion (s, s': State) { all p: Lift { p & s.rising != p & s'.rising => some s'.at[p]

14

physical constraints on lift motion


fun nextFloor (s: State, p: Lift): Floor -> Floor { result = if p in s.rising then above else below } fun LiftMotion (s, s': State) { all p: Lift { p & s.rising != p & s'.rising => some s'.at[p] s'.at[p] in s.(at + approaching)[p]

14

physical constraints on lift motion


fun nextFloor (s: State, p: Lift): Floor -> Floor { result = if p in s.rising then above else below } fun LiftMotion (s, s': State) { all p: Lift { p & s.rising != p & s'.rising => some s'.at[p] s'.at[p] in s.(at + approaching)[p]

s'.approaching[p] in s.approaching[p] + s.(at + approaching)[p].nextFloor(s,p) } }

14

physical constraints on lift motion


fun nextFloor (s: State, p: Lift): Floor -> Floor { result = if p in s.rising then above else below }

no dir change except at floor fun LiftMotion (s, s': State) { all p: Lift { p & s.rising != p & s'.rising => some s'.at[p]

s'.at[p] in s.(at + approaching)[p]

s'.approaching[p] in s.approaching[p] + s.(at + approaching)[p].nextFloor(s,p) } }

14

physical constraints on lift motion


fun nextFloor (s: State, p: Lift): Floor -> Floor { result = if p in s.rising then above else below }

no dir change except at floor fun LiftMotion (s, s': State) { all p: Lift { p & s.rising != p & s'.rising => some s'.at[p]

s'.at[p] in s.(at + approaching)[p]

floor at after is floor at or approaching before

s'.approaching[p] in s.approaching[p] + s.(at + approaching)[p].nextFloor(s,p) } }

14

physical constraints on lift motion


fun nextFloor (s: State, p: Lift): Floor -> Floor { result = if p in s.rising then above else below }

no dir change except at floor fun LiftMotion (s, s': State) { all p: Lift { p & s.rising != p & s'.rising => some s'.at[p]

s'.at[p] in s.(at + approaching)[p]

floor at after is floor at or approaching before

s'.approaching[p] in s.approaching[p] + s.(at + approaching)[p].nextFloor(s,p) } }

floor approaching after is floor approached before, or next floor

14

sample transition

15

sample transition
fun NiceMotion (s, s': State) { LiftMotion (s,s') && LiftPosition (s) && LiftPosition (s') s.at != s'.at} run NiceMotion for 3 but 2 State

15

sample transition
fun NiceMotion (s, s': State) { LiftMotion (s,s') && LiftPosition (s) && LiftPosition (s') s.at != s'.at} run NiceMotion for 3 but 2 State

15

sample transition
fun NiceMotion (s, s': State) { LiftMotion (s,s') && LiftPosition (s) && LiftPosition (s') s.at != s'.at} run NiceMotion for 3 but 2 State

15

button update

16

button update
fun ButtonUpdate (s, s': State, press: set Button) { s'.lit = s.lit {b: Button | some p: Lift | Serves (s,s',p,b)} + press no b: press & LiftButton | b.floor in (s+s').at[b.lift] no press & s.lit s.promises[Lift] - s'.promises[Lift] in s.lit - s'.lit }

16

denying service

17

denying service
fun Towards (s: State, p: Lift, f: Floor) { let next = nextFloor(s,p) | f in s.at[p].^next + s.approaching[p].*next }

17

denying service
fun Towards (s: State, p: Lift, f: Floor) { let next = nextFloor(s,p) | f in s.at[p].^next + s.approaching[p].*next } fun Denies (s, s': State, p: Lift, b: Button) { let f = b.floor { Towards (s,p,f) not Towards (s',p,f) not Serves (s,s',p,b) } }

17

a policy

18

a policy
fun Policy (s, s': State) { no p: Lift, b: p.buttons & s.lit | Denies (s,s',p,b)

all b: s.lit & FloorButton, p: Lift | Denies (s,s',p,b) => (some q: Lift | Serves(s,s',q,b)) or (b in s'.promises[Lift] and some b': s.lit | Towards (s',p,b'.floor)) NoStuckLift (s,s') AvoidStops (s,s') }

18

a policy
fun Policy (s, s': State) { no p: Lift, b: p.buttons & s.lit | Denies (s,s',p,b)

dont deny lift buttons

all b: s.lit & FloorButton, p: Lift | Denies (s,s',p,b) => (some q: Lift | Serves(s,s',q,b)) or (b in s'.promises[Lift] and some b': s.lit | Towards (s',p,b'.floor)) NoStuckLift (s,s') AvoidStops (s,s') }

18

a policy
fun Policy (s, s': State) { no p: Lift, b: p.buttons & s.lit | Denies (s,s',p,b)

dont deny lift buttons

all b: s.lit & FloorButton, p: Lift | Denies (s,s',p,b) => (some q: Lift | Serves(s,s',q,b)) or (b in s'.promises[Lift] and some b': s.lit | Towards (s',p,b'.floor)) NoStuckLift (s,s') AvoidStops (s,s') }

if deny floor button some lift serves it or some lift promises to

18

putting it all together

19

putting it all together


fun Trans (s, s': State) { LiftPosition (s) LiftPosition (s') LiftMotion (s,s') Policy (s,s') some press: set Button | ButtonUpdate (s, s', press) }

19

putting it all together


fun Trans (s, s': State) { LiftPosition (s) LiftPosition (s') LiftMotion (s,s') Policy (s,s') some press: set Button | ButtonUpdate (s, s', press) }

in a transition, some set of buttons is pressed and buttons are updated

19

sample denial

20

sample denial
fun ShowPolicy (s, s': State) { Trans (s, s') some b: s.lit & FloorButton, p: Lift | Denies (s,s',p,b) no s.promises && some s'.promises} run ShowPolicy for 3 but 2 State, 2 Lift, 2 Button

20

sample denial
fun ShowPolicy (s, s': State) { Trans (s, s') some b: s.lit & FloorButton, p: Lift | Denies (s,s',p,b) no s.promises && some s'.promises} run ShowPolicy for 3 but 2 State, 2 Lift, 2 Button

20

sample denial
fun ShowPolicy (s, s': State) { Trans (s, s') some b: s.lit & FloorButton, p: Lift | Denies (s,s',p,b) no s.promises && some s'.promises} run ShowPolicy for 3 but 2 State, 2 Lift, 2 Button

20

traces

21

traces
fun Init (s: State) { no s.lit.floor & s.at[Lift] no s.promises } fun Trace () { Init (Ord[State].first) all s: State - Ord[State].last | let s' = Ord[State].next[s] | Trans (s,s') }

21

traces
fun Init (s: State) { no s.lit.floor & s.at[Lift] no s.promises } fun Trace () { Init (Ord[State].first)

initial condition holds in first state

all s: State - Ord[State].last | let s' = Ord[State].next[s] | Trans (s,s') }

21

traces
fun Init (s: State) { no s.lit.floor & s.at[Lift] no s.promises } fun Trace () { Init (Ord[State].first)

initial condition holds in first state

all s: State - Ord[State].last | let s' = Ord[State].next[s] | Trans (s,s') }

transition relation relates each state except the last to the next state

21

asserting eventual service

22

asserting eventual service

assert EventuallyServed { Trace () => let start = Ord[State].first { all b: start.lit | some s': OrdNexts (start) | b !in s'.lit } }

22

counterexample!

23

counterexample!

23

counterexample!

assert EventuallyServed { Trace () and some Lift => let start = Ord[State].first { all b: start.lit | some s': OrdNexts (start) | b !in s'.lit } }

23

counterexample!

no service without lifts

assert EventuallyServed { Trace () and some Lift => let start = Ord[State].first { all b: start.lit | some s': OrdNexts (start) | b !in s'.lit } }

23

model structure

floor & button sigs & definitions

state signature

physical constraints on lift state

physical constraints on lift motion

behaviour definitions (eg, denying) button update rules

policy description

transition relation trace definition physics design eventuality assertion

24

incremental development
loosen model none generate instances write minimal model pick analysis check property some tighten model some

extend model or stop none

25

challenges for you

26

challenges for you


key properties of all lift systems what are they? are they just cultural?

26

challenges for you


key properties of all lift systems what are they? are they just cultural? replacing promises a better way to allow load balancing?

26

You might also like