| Modelling Systems
Mock Exam Questions Specimen Answers |
types
VehicleDetails :: model : token
colour : token;
RegNo = seq of char
inv r == len r = 6 and
(forall
i in set {1,...,3} & r(i) in set {'a',...,'Z'}) and
(forall
i in set {4,...,6} & r(i) in set {'0',...,'9'})
state Database of
vhs : map RegNo to VehicleDetails
end
operations
LookUp(r:RegNo)d:[VehicleDetails]
ext rd vhs : map RegNo to VehicleDetails
...
AddCar(r:RegNo, d:VehicleDetails)
ext wr vhs : map RegNo to VehicleDetails
...
DelCar(r:RegNo)
ext wr vhs : map RegNo to VehicleDetails
...
Match(m:token,c:token) ms:set of RegNo
ext rd vhs : map RegNo to VehicleDetails
...
f : T1 * T2 * ... * Tn -> R
is explicitly specified if it is defined in terms of an expression over
the inputs which, given any input satisfying the function's
precondition (if any), evaluates to a single result of the result type
R. An implicit specification of the same function would be defined
by means of a post-condition characterising the result in terms of the
inputs, and not necessarily defining a unique output. Implicit specifications,
in general, admit more implementations than explicit specifications unless
let-be expressions are used.
Position = <AISLE> | <WINDOW> | <MIDDLE>;
Seat :: num : nat
pos
: Position
pass:
seq of char
If a seat is not allocated to a passenger, the pass field will be the empty string [] (also written as "").
[You could also choose to make the pass field optional and represent the absence of a passenger by the value nil.]
Flight = set of Seat
inv f == not exists s1, s2 in set f & s1 <>
s2 and s1.num = s2.num
functions
free_seats : Flight -> set of Seat
free_seats(f) == {s | s in set f & s.pass = []};
good_seat(f:Flight, p:Position)r:Seat
pre exists s in set f & s.pass = [] and
s.pos = p
post r in set f and r.pass = [] and r.pos = p
This definition of good-seat has a precondition recording an assumption that there exists a free seat in f which has the desired position. The function may not be called when such a seat does not exist.
[An alternative is to return an error value or nil in the case where no suitable seat can be found:
good_seat(f:Flight, p:Position)r:[Seat]
post if exists s in set f & s.pass = [] and s.pos
= p
then r in set f and
r.pass = [] and r.pos = p
else r = nil
]
f : T1 * T2 * ... -> T
f is said to be explicitly specified if it is defined by means
of a value expression of type T such that for any
input satisfying the precondition of f (if present), the value expression
denotes a unique value. f is said to be implicitly
specified if it is defined by means of a logical expression (a post-condition)
such that for any input satisfying the precondition of f (if present),
the logical expression evaluates to true for those values which are acceptable
results. Unlike an explicitly defined function, an implicitly defined one
may leave a wide range of implementations open. For example, an implicit
specification of a function to calculate the square root of a number may
leave it unspecified whether the result is to be the positive root or the
negative.
Request :: description : seq of char
urgency : <non_urgent> | <urgent> | <emergency>;
List = seq of Request
functions
add_request : List * Request -> List
add_request(l,r) == l ^ [r];
exists i in set inds l & l(i).urgency = <emergency>
Then to say that the result is the earliest such request:
exists i in set inds l &
l(i).urgency = <emergency> and
l(i) = r and
forall j in set inds l & j<i => l(j).urgency <> <emergency>
Putting these together:
first_emergency(l:List)r : [Request]
post If exists i in set inds l & l(i).urgency =
<emergency>
then exists i in set
inds l &
l(i).urgency = <emergency> and
l(i) = r and
forall j in set inds l & j<i => l(j).urgency <> <emergency>
else r = nil
[ I put all the text at the start of the answer to this last part to
emphasise that you can still get marks for writing about the specification,
even if you haven't got time to work out all the details. Of course, you
don't have to write all the text, but you have a better chance of
being understood than if you just submit a page of (possibly wrong) maths.
Notice that the last part, although hard, doesn't add many marks to your
total.
]
op : A1 * A2 * ... * An -> B
is said to be partial if there is some a in A1 * A2 * ... * An such that op(a) is undefined.
For example, the head operator on sequences has the following signature:
hd : seq of A -> A
where A is some type. This operator is partial because it is undefined when applied to the empty sequence [].
The sequence concatenation operator, which has the following signature:
_^_ : seq of A * seq of A -> seq of A
where A is some type, is total, i.e. is defined for all possible sequences.
Stream = seq of Reactor;
Reactor :: batches : set of Batch
limit : nat;
BatchId = token;
Batch :: batch_id : BatchId
contents_type : token
batches_in_stream : Stream -> set of Batch
batches_in_stream(s) ==
dunion {r.batches | r : Reactor
& r in set elems s }
[Alternative: use inds rather than elems:
batches_in_stream : Stream -> set of Batch
batches_in_stream(s) ==
dunion {s(i).batches | i in set
inds s }
Another alternative: don't use distributed union, just forming the set directly:
batches_in_stream : Stream -> set of Batch
batches_in_stream(s) ==
{ b | b:Batch & exists i in
set inds s & b in set s(i).batches }
]
Stream = seq of Reactor;
inv b == not (exists b1,b2 in set batches_in_stream(s) &
b1 <> b2 and b1.batch_id = b2.batch_id) and
not
(exists i,j in set inds s &
i <> j and
s(i).batches inter s(j).batches <> {}) and
forall i in set inds s & card s(i).batches <= s(i)
f : T1 * T2 * ... -> T
f is said to be explicitly specified if it is defined by means
of a value expression of type T such that for any
input satisfying the precondition of f (if present), the value expression
denotes a unique value. f is said to be implicitly
specified if it is defined by means of a logical expression (a post-condition)
such that for any input satisfying the precondition of f (if present),
the logical expression evaluates to true for those values which are acceptable
results. Unlike an explicitly defined function, an implicitly defined one
may leave a wide range of implementations open. For example, an implicit
specification of a function to calculate the square root of a number may
leave it unspecified whether the result is to be the positive root or the
negative.
Store = map Location to [Container]
inv s == not (exists c1,c2 in set rng s &
c1 <> nil and c2 <> nil and
c1<>c2 and c1.cid = c2.cid)
and
not (exists l1, l2 in set dom s &
s(l1) <> nil and s(l2) <> nil and
l1 <> l2 and s(l1) = s(l2))
safe_store : Store -> bool
safe_store(s) == (not exists l in set dom s &
(l.x = 0 or l.x = 10 or
l.y = 0 or l.y = 10 or
l.z = 0 or l.z = 5) and
s(l) <> nil and s(l).class = <HIGH>)
and
(not exists l1, l2 in set dom s &
adjacent(l1,l2,s) and l1 <> l2 and
s(l1) <> nil and s(l2) <> nil and
and s(l1).class = <HIGH> and s(l2).class = <HIGH>
and adjacent(l1,l2,s);
The addition to the invariant is just
... and safe-store(s)
The absence of an input location means that the postcondition should assert simply that there exists such a location, e.g.
post exists loc in set dom s & r = s ++ { loc |-> c }
However, the postcondition might now allow the invariant to be broken, because it does not constrain the choice of loc to one which respects the invariant, so additional conjuncts would have to be added here. The pre-condition would change similarly:
pre not exists c1 in set rng s & c1.cid = c.cid
and
exists loc in set dom s &
safe-store(s ++ { loc |-> c })
Not yet available
| John.Fitzgerald@ncl.ac.uk | 6 June 1999 ... |