1queuelive mc1
This file contains a simple liveness proof using model checking
include order
instance nat : unbounded_sequence
include mc_schemata
instantiate unbounded_sequence_schemata(nat)
module signal = {
action raise
specification {
relation now
after init { now := false; }
before raise {
now := true;
now := false;
}
invariant ~now
}
}
action send
action recv
var head : nat
var tail : nat
after init {
head := 0;
tail := 0;
}
instance receiving : signal
before send {
var baf := tail.next;
tail := baf;
}
before recv {
require head < tail;
call receiving.raise;
var bif := head.next;
head := bif;
}
This property is easy to prove because it is inductive over time. That is, it suffices to assume that the property 'tail = X -> eventually head = X' has always been true in the past fr all X. In particular if X = head at the current time, then we can assume 'tail = X - 1 -> eventually head = X - 1' has always been true in the past. This means that eventually 'head = X - 1' and thuse eventually 'head = X' (at the next time recv is called).
The nice thing about this inductive argument is that we only have to reason about X and X - 1. We can abstract away all the other values of X. To do this, we first skolemize so that the universal X becomes a fixed constant _X. Then we apply model checking tactic 'mc', adding a new constant Xm1 that stands for _X -1. The model checker uses these two symbolic constants in its finite abstraction. As we argued above, this finite abstraction is enough to prove the property.
temporal property
forall X.
(globally eventually receiving.now)
-> (globally tail = X -> eventually head = X)
proof {
tactic tempind;
tactic skolemize;
tactic mc proof {let Xm1 = _X - 1}
}
export send
export recv