exercises.adequacy
From iris.algebra Require Import excl.
From iris.base_logic.lib Require Export token.
From iris.heap_lang Require Import adequacy lang proofmode notation par.
From exercises Require Import spin_lock.
(* ################################ *)
From iris.base_logic.lib Require Export token.
From iris.heap_lang Require Import adequacy lang proofmode notation par.
From exercises Require Import spin_lock.
(* ################################ *)
Adequacy
- The program won't get stuck.
- The program satisfies the postcondition.
Now, let us define steps in terms of configurations. To model the
non-sequential behaviour of threads, we define steps to be a step in
any thread.
Inductive step (ρ1 ρ2 : cfg) : Prop :=
step_atomic e1 σ1 e2 σ2 efs t1 t2 :
ρ1 = (t1 ++ e1 :: t2, σ1) →
ρ2 = (t1 ++ e2 :: t2 ++ efs, σ2) →
prim_step e1 σ1 [] e2 σ2 efs →
step ρ1 ρ2.
step_atomic e1 σ1 e2 σ2 efs t1 t2 :
ρ1 = (t1 ++ e1 :: t2, σ1) →
ρ2 = (t1 ++ e2 :: t2 ++ efs, σ2) →
prim_step e1 σ1 [] e2 σ2 efs →
step ρ1 ρ2.
With this, we can define multiple steps as the reflexive transitive
closure (rtc) of step.
Now, a program is stuck if any thread cannot take a step and is not a
value. Conversely, a thread is not stuck if it is either a value or
can take a step.
With this, we can now express the first adequacy criterion: a program
will not get stuck if all possible future configurations are not
stuck.
∀ t σ' e', rtc step ([e], σ) (t, σ') → e' ∈ t → not_stuck e' σ'
Likewise, for the second criterion, we say that a program satisfies a
postcondition when the main thread terminates to a value, and that
value satisfies the postcondition.
∀ t σ' v, rtc step ([e], σ) (of_val v :: t, σ') → φ v σ'
Together, these two properties define adequate. However, adequate
takes an extra parameter of type stuckness. This parameter specifies
whether adequacy includes the first criterion.
The proof that the weakest precondition implies adequacy is:
heap_adequacy Σ `{!heapGpreS Σ} s e σ φ : ∀ _ : heapGS Σ,
inv_heap_inv -∗ WP e @ s; ⊤ {{ v, ⌜φ v⌝}} → adequate s e σ (λ v σ,
φ v)
To use this statement, we have to actually instantiate Σ. It needs
to contain all the kinds of resources we needed to prove the weakest
precondition. Let us use prog from the Spin Lock chapter as an
example. To prove prog_spec, we used the resource of heaps as well
as tokens. The resources needed by the resource of heaps are all
contained in heapΣ. Likewise, the resources needed by token
(exclR unitO) are contained in tokenΣ.
heap_adequacy Σ `{!heapGpreS Σ} s e σ φ : ∀ _ : heapGS Σ,
inv_heap_inv -∗ WP e @ s; ⊤ {{ v, ⌜φ v⌝}} → adequate s e σ (λ v σ,
φ v)
Definition progΣ : gFunctors := #[
heapΣ; (* The resources required by HeapLang *)
tokenΣ (* The resources we used for spin-lock *)
].
Finally, we can combine the pieces to prove adequacy.
Lemma prog_adequacy σ :
adequate NotStuck prog σ (λ v _, v = #0 ∨ v = #1).
Proof.
apply (heap_adequacy progΣ).
iIntros "%_ _".
iApply prog_spec.
Qed.
adequate NotStuck prog σ (λ v _, v = #0 ∨ v = #1).
Proof.
apply (heap_adequacy progΣ).
iIntros "%_ _".
iApply prog_spec.
Qed.