Built with Alectryon, running Coq+SerAPI v8.18.0+0.18.2. Bubbles () indicate interactive fragments: hover for details, tap to reveal contents. Use Ctrl+↑ Ctrl+↓ to navigate, Ctrl+πŸ–±οΈ to focus. On Mac, use ⌘ instead of Ctrl.

Example: ABC transition system

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⌝.

[Loading ML file ssrmatching_plugin.cmxs (using legacy method) ... done]
[Loading ML file ssreflect_plugin.cmxs (using legacy method) ... done]
[Loading ML file ring_plugin.cmxs (using legacy method) ... done]
[Loading ML file zify_plugin.cmxs (using legacy method) ... done]
[Loading ML file micromega_plugin.cmxs (using legacy method) ... done]

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) ].

Safety

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'

βˆ€ s, init s β†’ safe s
stm.

βˆ€ s s', safe s β†’ next s s' β†’ safe s'
stm. Qed.

Liveness

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 s

βˆ€ s s', s.(x) = A β†’ next s s' β†’ s'.(x) = A ∨ s'.(x) = B
stm.

βˆ€ s s', s.(x) = A β†’ next s s' β†’ ab s s' β†’ s'.(x) = B
stm.

βˆ€ s, s.(x) = A β†’ enabled ab s
stm. Qed.

⌜ init ⌝ ⊒ ⌜ λ s, s.(x) = A ⌝

⌜ init ⌝ ⊒ ⌜ λ s, s.(x) = A ⌝
s: state

init s β†’ s.(x) = A
stm. Qed.

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 ⌝

⌜ init ⌝ ∧ β–‘ ⟨next⟩ ∧ weak_fairness ab ⊒ ⌜ Ξ» s, s.(x) = A ⌝
rewrite init_a; tla_prop.

⌜ init ⌝ ∧ β–‘ ⟨next⟩ ∧ weak_fairness ab ⊒ ⌜ Ξ» s, s.(x) = A ⌝ ~~> ⌜ Ξ» s, s.(x) = B ⌝
tla_apply a_leads_to_b. Qed.

β–‘ ⟨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 s

βˆ€ s s', s.(x) = B β†’ next s s' β†’ s'.(x) = B ∨ s'.(x) = C
stm.

βˆ€ s s', s.(x) = B β†’ next s s' β†’ bc s s' β†’ s'.(x) = C
stm.

βˆ€ s, s.(x) = B β†’ enabled bc s
stm. Qed.

β–‘ ⟨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 ⌝

β–‘ ⟨next⟩ ∧ weak_fairness ab ∧ weak_fairness bc ⊒ ⌜ Ξ» s, s.(x) = A ⌝ ~~> ⌜ Ξ» s, s.(x) = B ⌝
tla_apply a_leads_to_b.

β–‘ ⟨next⟩ ∧ weak_fairness ab ∧ weak_fairness bc ⊒ ⌜ Ξ» s, s.(x) = B ⌝ ~~> ⌜ Ξ» s, s.(x) = C ⌝
tla_apply b_leads_to_c. Qed.

⊒ 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 ⌝

⌜ init ⌝ ∧ β–‘ ⟨next⟩ ∧ weak_fairness ab ∧ weak_fairness bc ⊒ ⌜ Ξ» s, s.(x) = A ⌝
rewrite init_a; tla_prop.

⌜ init ⌝ ∧ β–‘ ⟨next⟩ ∧ weak_fairness ab ∧ weak_fairness bc ⊒ ⌜ Ξ» s, s.(x) = A ⌝ ~~> ⌜ Ξ» s, s.(x) = C ⌝
tla_apply a_leads_to_c. Qed. End example.