We define a simple state machine with a field x
that goes from A
to B
to C
, and separately a field happy
that remains constant.
The state machine has a safety property that says happy
is true, and a liveness property that says β βΞ» s, s.(x) = Cβ
.
This module contains the trusted (assume correct) definitions for the state machine itself, as well as the desired safety and liveness properties.
Module spec. Inductive abc := A | B | C. Record state := { x: abc; happy: bool; }. Definition ab : action state := Ξ» s s', (s.(x) = A β§ s'.(x) = B β§ s'.(happy) = s.(happy)). Definition bc : action state := Ξ» s s', (s.(x) = B β§ s'.(x) = C β§ s'.(happy) = s.(happy)). Definition init (s: state) := s.(x) = A β§ s.(happy) = true.
It is important to allow stuttering (s = s'
) in this predicate! Otherwise there would be no infinite sequences satisfying β‘ β¨nextβ©
, since after two transitions no steps would be possible.
Definition next s s' := ab s s' β¨ bc s s' β¨ s = s'.
The safety property for this example is that happy always remains true.
Definition safe : state β Prop := Ξ» s, s.(happy).
The statement that the state machine satisfies safety follows the very standard TLA formula here, βinitβ β§ β‘ β¨nextβ© β β‘ βsafeβ
. This says that if init
holds in the first state of an execution and every subsequent transition satisfies next
, then safe
holds of every state.
Definition safety : predicate state := βinitβ β§ β‘ β¨nextβ© β β‘ βsafeβ.
Intuitively the liveness property for this example is that eventually the field x
will be C
. Stating this formally is a bit more sophisticated than for safety. We still have βinitβ β§ β‘β¨nextβ© as an assumption (we only consider executions that follow the state machine semantics), but in order for this theorem to hold we need the ab
and bc
actions to run "often enough", expressed via weak fairness assumptions. Without these, the theorem would be false, because it would be valid for an execution to consist of infinitely many stuttering steps, starting from a state satisfying init
.
Definition liveness : predicate state := βinitβ β§ β‘ β¨nextβ© β§ weak_fairness ab β§ weak_fairness bc β β βΞ» s, s.(x) = Cβ. End spec.
The remainder of the code is untrusted proof (except for the fact that β’ safety and β’ liveness are stated and proven as theorems).
Import spec. Section example. Implicit Types (s: state).
A little automation will prove all the state-machine specific reasoning required for this example, essentially by brute force.
Hint Unfold init happy next ab bc : stm. Hint Unfold safe : stm. Hint Unfold enabled : stm. Ltac stm := autounfold with stm in *; intros; repeat match goal with | s: state |- _ => let x := fresh "x" in let happy := fresh "happy" in destruct s as [x happy] | H: (@eq state _ _) |- _ => invc H end; intuition idtac; try solve [ try match goal with | |- β (s: state), _ => eexists {| x := _; happy := _; |} end; intuition (subst; eauto; try congruence) ].
The safety property is pretty easy, using init_invariant
. In fact it's so simple it's already inductive and we don't need to go through a separate invariant.
β’ safetyβ’ safetyβ init β β§ β‘ β¨nextβ© β’ β‘ β safe ββ s, init s β safe sβ s s', safe s β next s s' β safe s'stm.β s, init s β safe sstm. Qed.β s s', safe s β next s s' β safe s'
Liveness is more interesting. The high-level strategy is to use the rule wf1
to prove A ~~> B
and that B ~~> C
; then we can chain them together and finally apply them by showing that init
implies A
.
Notice that the state-machine reasoning all happens here, and in the analogous b_leads_to_c
proof below. We only need to prove one- and two-state properties and the wf1 rules lifts them to a temporal property that uses the weak fairness assumption.
β‘ β¨nextβ© β§ weak_fairness ab β’ β Ξ» s, s.(x) = A β ~~> β Ξ» s, s.(x) = B ββ‘ β¨nextβ© β§ weak_fairness ab β’ β Ξ» s, s.(x) = A β ~~> β Ξ» s, s.(x) = B ββ s s', s.(x) = A β next s s' β s'.(x) = A β¨ s'.(x) = Bβ s s', s.(x) = A β next s s' β ab s s' β s'.(x) = Bβ s, s.(x) = A β enabled ab sstm.β s s', s.(x) = A β next s s' β s'.(x) = A β¨ s'.(x) = Bstm.β s s', s.(x) = A β next s s' β ab s s' β s'.(x) = Bstm. Qed.β s, s.(x) = A β enabled ab sβ init β β’ β Ξ» s, s.(x) = A ββ init β β’ β Ξ» s, s.(x) = A βstm. Qed.s: stateinit s β s.(x) = A
This theorem isn't directly needed; we carry out the same reasoning to derive β C from the leads_to proofs.
β init β β§ β‘ β¨nextβ© β§ weak_fairness ab β’ β β Ξ» s, s.(x) = B ββ init β β§ β‘ β¨nextβ© β§ weak_fairness ab β’ β β Ξ» s, s.(x) = B ββ init β β§ β‘ β¨nextβ© β§ weak_fairness ab β’ β Ξ» s, s.(x) = A ββ init β β§ β‘ β¨nextβ© β§ weak_fairness ab β’ β Ξ» s, s.(x) = A β ~~> β Ξ» s, s.(x) = B βrewrite init_a; tla_prop.β init β β§ β‘ β¨nextβ© β§ weak_fairness ab β’ β Ξ» s, s.(x) = A βtla_apply a_leads_to_b. Qed.β init β β§ β‘ β¨nextβ© β§ weak_fairness ab β’ β Ξ» s, s.(x) = A β ~~> β Ξ» s, s.(x) = B ββ‘ β¨nextβ© β§ weak_fairness bc β’ β Ξ» s, s.(x) = B β ~~> β Ξ» s, s.(x) = C ββ‘ β¨nextβ© β§ weak_fairness bc β’ β Ξ» s, s.(x) = B β ~~> β Ξ» s, s.(x) = C ββ s s', s.(x) = B β next s s' β s'.(x) = B β¨ s'.(x) = Cβ s s', s.(x) = B β next s s' β bc s s' β s'.(x) = Cβ s, s.(x) = B β enabled bc sstm.β s s', s.(x) = B β next s s' β s'.(x) = B β¨ s'.(x) = Cstm.β s s', s.(x) = B β next s s' β bc s s' β s'.(x) = Cstm. Qed.β s, s.(x) = B β enabled bc sβ‘ β¨nextβ© β§ weak_fairness ab β§ weak_fairness bc β’ β Ξ» s, s.(x) = A β ~~> β Ξ» s, s.(x) = C ββ‘ β¨nextβ© β§ weak_fairness ab β§ weak_fairness bc β’ β Ξ» s, s.(x) = A β ~~> β Ξ» s, s.(x) = C ββ‘ β¨nextβ© β§ weak_fairness ab β§ weak_fairness bc β’ β Ξ» s, s.(x) = A β ~~> β Ξ» s, s.(x) = B ββ‘ β¨nextβ© β§ weak_fairness ab β§ weak_fairness bc β’ β Ξ» s, s.(x) = B β ~~> β Ξ» s, s.(x) = C βtla_apply a_leads_to_b.β‘ β¨nextβ© β§ weak_fairness ab β§ weak_fairness bc β’ β Ξ» s, s.(x) = A β ~~> β Ξ» s, s.(x) = B βtla_apply b_leads_to_c. Qed.β‘ β¨nextβ© β§ weak_fairness ab β§ weak_fairness bc β’ β Ξ» s, s.(x) = B β ~~> β Ξ» s, s.(x) = C ββ’ livenessβ’ livenessβ init β β§ β‘ β¨nextβ© β§ weak_fairness ab β§ weak_fairness bc β’ β β Ξ» s, s.(x) = C β
leads_to_apply p
will switch from proving β q
to p
and p ~~> q
.
β init β β§ β‘ β¨nextβ© β§ weak_fairness ab β§ weak_fairness bc β’ β Ξ» s, s.(x) = A ββ init β β§ β‘ β¨nextβ© β§ weak_fairness ab β§ weak_fairness bc β’ β Ξ» s, s.(x) = A β ~~> β Ξ» s, s.(x) = C βrewrite init_a; tla_prop.β init β β§ β‘ β¨nextβ© β§ weak_fairness ab β§ weak_fairness bc β’ β Ξ» s, s.(x) = A βtla_apply a_leads_to_c. Qed. End example.β init β β§ β‘ β¨nextβ© β§ weak_fairness ab β§ weak_fairness bc β’ β Ξ» s, s.(x) = A β ~~> β Ξ» s, s.(x) = C β