1queuelive mc2
This file contains a simple liveness proof using model checking, where the property is not inductive over time.
include order
instance nat : unbounded_sequence
include mc_schemata
instantiate unbounded_sequence_schemata(nat)
module signal(data) = {
action raise(val:data)
specification {
relation now
var value : data
after init { now := false; }
before raise {
value := val;
now := true;
now := false;
}
invariant ~now
}
}
type id
isolate bar = {
action send(x:id)
action recv
specification {
var head : nat
var tail : nat
var queue(X:nat) : id
after init {
head := 0;
tail := 0;
}
instance sending : signal(id)
instance receiving : signal(id)
before send {
sending.raise(x);
queue(tail) := x;
tail := tail.next;
}
before recv {
require head < tail;
call receiving.raise(queue(head));
head := head.next;
}
This, we first prove 'lemma1', stating the if the tail pointer is X, then eventually the head pointer is X. This is done by induction on X, as described in '1queuelive_mc1.ivy'.
temporal property [lemma1]
forall X.
(globally eventually receiving.now)
-> (globally tail = X -> eventually head = X)
proof {
tactic tempind;
tactic skolemize;
tactic mc proof {let Xm1 = _X - 1}
}
Model checking is able to verify the liveness property using just these two constants in its abstraction.
temporal property
forall X.
(globally eventually receiving.now) ->
globally (sending.now & sending.value = X) ->
(eventually receiving.now & receiving.value = X)
proof {
tactic tempind with Y = tail;
tactic skolemize;
tactic mc
}
}
} with nat
export bar.send
export bar.recv