Skip to content
Snippets Groups Projects
Commit ebb6c018 authored by Ralf Jung's avatar Ralf Jung
Browse files

Merge branch 'msammler/multithread_adequacy' into 'master'

Make adequacy apply to multiple initial threads

See merge request !485
parents e28498f5 996ec297
No related branches found
No related tags found
No related merge requests found
...@@ -63,6 +63,12 @@ With this release, we dropped support for Coq 8.9. ...@@ -63,6 +63,12 @@ With this release, we dropped support for Coq 8.9.
`auth_alloc`. `auth_alloc`.
* Change `uPred_mono` to only require inclusion at the smaller step-index. * Change `uPred_mono` to only require inclusion at the smaller step-index.
**Changes in `program_logic`:**
* `wp_strong_adequacy` now applies to an initial state with multiple
threads instead of only a single thread. The derived adequacy lemmas
are unchanged.
The following `sed` script helps adjust your code to the renaming (on macOS, The following `sed` script helps adjust your code to the renaming (on macOS,
replace `sed` by `gsed`, installed via e.g. `brew install gnu-sed`). replace `sed` by `gsed`, installed via e.g. `brew install gnu-sed`).
Note that the script is not idempotent, do not run it twice. Note that the script is not idempotent, do not run it twice.
......
...@@ -214,17 +214,18 @@ The purpose of the adequacy statement is to show that our notion of weakest prec ...@@ -214,17 +214,18 @@ The purpose of the adequacy statement is to show that our notion of weakest prec
The most general form of the adequacy statement is about proving properties of an arbitrary program execution. The most general form of the adequacy statement is about proving properties of an arbitrary program execution.
\begin{thm}[Adequacy] \begin{thm}[Adequacy]
Assume we are given some $\expr_1$, $\state_1$, $\vec\obs$, $\tpool_2$, $\state_2$ such that $([\expr_1], \state_1) \tpsteps[\vec\obs] (\tpool_2, \state_2)$, and we are also given a \emph{meta-level} property $\metaprop$ that we want to show. Assume we are given some $\vec\expr_1$, $\state_1$, $\vec\obs$, $\tpool_2$, $\state_2$ such that $(\vec\expr_1, \state_1) \tpsteps[\vec\obs] (\tpool_2, \state_2)$, and we are also given a \emph{meta-level} property $\metaprop$ that we want to show.
To verify that $\metaprop$ holds, it is sufficient to show the following Iris entailment: To verify that $\metaprop$ holds, it is sufficient to show the following Iris entailment:
\begin{align*} \begin{align*}
&\TRUE \proves \pvs[\top] \Exists \stuckness, \stateinterp, \pred, \pred_F. \stateinterp(\state_1,\vec\obs,0) * \wpre[\stateinterp;\pred_F]{\expr_1}[\stuckness;\top]{x.\; \pred(x)} * \left(\consstate^{\stateinterp;\pred;\pred_F}_{\stuckness}(\tpool_2, \state_2) \vs[\top][\emptyset] \hat{\metaprop}\right) &\TRUE \proves \pvs[\top] \Exists \stuckness, \stateinterp, \vec\pred, \pred_F. \stateinterp(\state_1,\vec\obs,0) * \left(\Sep_{\expr,\pred \in \vec\expr_1,\vec\pred} \wpre[\stateinterp;\pred_F]{\expr}[\stuckness;\top]{x.\; \pred(x)}\right) * \left(\consstate^{\stateinterp;\vec\pred;\pred_F}_{\stuckness}(\tpool_2, \state_2) \vs[\top][\emptyset] \hat{\metaprop}\right)
\end{align*} \end{align*}
where $\consstate$ describes states that are consistent with the state interpretation and postconditions: where $\consstate$ describes states that are consistent with the state interpretation and postconditions:
\begin{align*} \begin{align*}
\consstate^{\stateinterp;\pred;\pred_F}_{\stuckness}(\tpool_2, \state_2) \eqdef{}&\Exists \expr_2, \tpool_2'. \tpool_2 = [\expr_2] \dplus \tpool_2' * {}\\ \consstate^{\stateinterp;\vec\pred;\pred_F}_{\stuckness}(\tpool_2, \state_2) \eqdef{}&\Exists \vec\expr_2, \tpool_2'. \tpool_2 = \vec\expr_2 \dplus \tpool_2' * {}\\
&\quad |\vec\expr_1| = |\vec\expr_2| *{}\\
&\quad (s = \NotStuck \Ra \All \expr \in \tpool_2. \toval(\expr) \neq \bot \lor \red(\expr, \state_2) ) *{}\\ &\quad (s = \NotStuck \Ra \All \expr \in \tpool_2. \toval(\expr) \neq \bot \lor \red(\expr, \state_2) ) *{}\\
&\quad \stateinterp(\state_2, (), |\tpool_2'|) *{}\\ &\quad \stateinterp(\state_2, (), |\tpool_2'|) *{}\\
&\quad (\toval(\expr_2) \ne \bot \wand \pred(\toval(\expr_2))) *{}\\ &\quad \left(\Sep_{\expr,\pred \in \vec\expr_2,\vec\pred} \toval(\expr) \ne \bot \wand \pred(\toval(\expr))\right) *{}\\
&\quad \left(\Sep_{\expr \in \tpool_2'} \toval(\expr) \ne \bot \wand \pred_F(\toval(\expr))\right) &\quad \left(\Sep_{\expr \in \tpool_2'} \toval(\expr) \ne \bot \wand \pred_F(\toval(\expr))\right)
\end{align*} \end{align*}
The $\hat\metaprop$ here arises because we need a way to talk about $\metaprop$ inside Iris. The $\hat\metaprop$ here arises because we need a way to talk about $\metaprop$ inside Iris.
...@@ -238,7 +239,7 @@ Furthermore, we assume that the \emph{interpretation} $\Sem{\hat{\metaprop}}$ of ...@@ -238,7 +239,7 @@ Furthermore, we assume that the \emph{interpretation} $\Sem{\hat{\metaprop}}$ of
The signature can of course state arbitrary additional properties of $\hat{\metaprop}$, as long as they are proven sound. The signature can of course state arbitrary additional properties of $\hat{\metaprop}$, as long as they are proven sound.
\end{thm} \end{thm}
In other words, to show that $\metaprop$ holds, we have to prove an entailment in Iris that, starting from the empty context, chooses some state interpretation, postcondition, forked-thread postcondition and stuckness and then proves: In other words, to show that $\metaprop$ holds, we have to prove an entailment in Iris that, starting from the empty context, chooses some state interpretation, postconditions for the initial threads, forked-thread postcondition and stuckness and then proves:
\begin{itemize} \begin{itemize}
\item the initial state interpretation, \item the initial state interpretation,
\item a weakest-precondition, \item a weakest-precondition,
...@@ -247,12 +248,12 @@ In other words, to show that $\metaprop$ holds, we have to prove an entailment i ...@@ -247,12 +248,12 @@ In other words, to show that $\metaprop$ holds, we have to prove an entailment i
Notice that the state interpretation and the postconditions are chosen \emph{after} doing a fancy update, which allows them to depend on the names of ghost variables that are picked in that initial fancy update. Notice that the state interpretation and the postconditions are chosen \emph{after} doing a fancy update, which allows them to depend on the names of ghost variables that are picked in that initial fancy update.
This gives us a chance to allocate some ``global'' ghost state that state interpretation and postcondition can refer to. This gives us a chance to allocate some ``global'' ghost state that state interpretation and postcondition can refer to.
$\consstate^{\stateinterp;\pred;\pred_F}_{\stuckness}(\tpool_2, \state_2)$ says that: $\consstate^{\stateinterp;\vec\pred;\pred_F}_{\stuckness}(\tpool_2, \state_2)$ says that:
\begin{itemize} \begin{itemize}
\item The final thread-pool $\tpool_2$ contains the final state of the main thread $\expr_2$, and any number of additional forked threads in $\tpool_2'$. \item The final thread-pool $\tpool_2$ contains the final state of the initial threads $\vec\expr_2$, and any number of additional forked threads in $\tpool_2'$.
\item If this is a stuck-free weakest precondition, then all threads in the final thread-pool are either values or are reducible in the final state $\state_2$. \item If this is a stuck-free weakest precondition, then all threads in the final thread-pool are either values or are reducible in the final state $\state_2$.
\item The state interpretation $\stateinterp$ holds for the final state. \item The state interpretation $\stateinterp$ holds for the final state.
\item If the main thread reduced to a value, the post-condition $\pred$ of the weakest precondition holds for that value. \item If one of the initial threads reduced to a value, the corresponding post-condition $\pred \in \vec\pred$ holds for that value.
\item If any other thread reduced to a value, the forked-thread post-condition $\pred_F$ holds for that value. \item If any other thread reduced to a value, the forked-thread post-condition $\pred_F$ holds for that value.
\end{itemize} \end{itemize}
...@@ -271,7 +272,7 @@ As an example for how to use this adequacy theorem, let us say we wanted to prov ...@@ -271,7 +272,7 @@ As an example for how to use this adequacy theorem, let us say we wanted to prov
\end{cor} \end{cor}
To prove the conclusion of this corollary, we assume some $\state_1, \vec\obs, \tpool_2, \state_2$ and $([\expr_1], \state_1) \tpsteps[\vec\obs] (\tpool_2, \state_2)$, and we instantiate the main theorem with this execution and $\metaprop \eqdef \All \expr \in \tpool_2. \toval(\expr) \neq \bot \lor \red(\expr, \state_2)$. To prove the conclusion of this corollary, we assume some $\state_1, \vec\obs, \tpool_2, \state_2$ and $([\expr_1], \state_1) \tpsteps[\vec\obs] (\tpool_2, \state_2)$, and we instantiate the main theorem with this execution and $\metaprop \eqdef \All \expr \in \tpool_2. \toval(\expr) \neq \bot \lor \red(\expr, \state_2)$.
We can then show the premise of adequacy using the Iris entailment that we assumed in the corollary and: We can then show the premise of adequacy using the Iris entailment that we assumed in the corollary and:
\[ \TRUE \proves \consstate^{\stateinterp;\pred;\pred_F}_{\NotStuck}(\tpool_2, \state_2) \vs[\top][\emptyset] \metaprop \] \[ \TRUE \proves \consstate^{\stateinterp;[\pred];\pred_F}_{\NotStuck}(\tpool_2, \state_2) \vs[\top][\emptyset] \metaprop \]
This proof, just like the following, also exploits that we can freely swap between meta-level universal quantification ($\All x. \TRUE \proves \prop$) and quantification in Iris ($\TRUE \proves \All x. \prop$). This proof, just like the following, also exploits that we can freely swap between meta-level universal quantification ($\All x. \TRUE \proves \prop$) and quantification in Iris ($\TRUE \proves \All x. \prop$).
~\par ~\par
...@@ -289,7 +290,7 @@ Similarly we could show that the postcondition makes adequate statements about t ...@@ -289,7 +290,7 @@ Similarly we could show that the postcondition makes adequate statements about t
\end{cor} \end{cor}
To show this, we assume some $\state_1, \vec\obs, \val_2, \tpool_2, \state_2$ such that $([\expr_1], \state_1) \tpsteps[\vec\obs] ([\ofval(\val_2)] \dplus \tpool_2, \state_2)$, and we instantiate adequacy with this execution and $\metaprop \eqdef \val_2 \in \Val$. To show this, we assume some $\state_1, \vec\obs, \val_2, \tpool_2, \state_2$ such that $([\expr_1], \state_1) \tpsteps[\vec\obs] ([\ofval(\val_2)] \dplus \tpool_2, \state_2)$, and we instantiate adequacy with this execution and $\metaprop \eqdef \val_2 \in \Val$.
Then we only have to show: Then we only have to show:
$$\TRUE \proves \consstate^{\stateinterp;(\Lam \val. \val \in \Val);\pred_F}_{\stuckness}([\ofval(\val_2)] \dplus \tpool_2, \state_2) \vs[\top][\emptyset] \val_2 \in \Val $$ $$\TRUE \proves \consstate^{\stateinterp;[(\Lam \val. \val \in \Val)];\pred_F}_{\stuckness}([\ofval(\val_2)] \dplus \tpool_2, \state_2) \vs[\top][\emptyset] \val_2 \in \Val $$
~\par ~\par
...@@ -307,7 +308,7 @@ As a final example, we could use adequacy to show that the state $\state$ of the ...@@ -307,7 +308,7 @@ As a final example, we could use adequacy to show that the state $\state$ of the
To show this, we assume some $\state_1, \vec\obs, \tpool_2, \state_2$ such that $([\expr_1], \state_1) \tpsteps[\vec\obs] (\tpool_2, \state_2)$, and we instantiate adequacy with this execution and $\metaprop \eqdef \state_2 \in \Sigma$. To show this, we assume some $\state_1, \vec\obs, \tpool_2, \state_2$ such that $([\expr_1], \state_1) \tpsteps[\vec\obs] (\tpool_2, \state_2)$, and we instantiate adequacy with this execution and $\metaprop \eqdef \state_2 \in \Sigma$.
Then we have to show: Then we have to show:
\[ \[
(\All \state_2, m. \stateinterp(\state_2,(),m) \!\vs[\top][\emptyset] \state_2 \in \Sigma) \proves \consstate^{\stateinterp;\pred;\pred_F}_{\stuckness}(\tpool_2, \state_2) \vs[\top][\emptyset] \state_2 \in \Sigma (\All \state_2, m. \stateinterp(\state_2,(),m) \!\vs[\top][\emptyset] \state_2 \in \Sigma) \proves \consstate^{\stateinterp;[\pred];\pred_F}_{\stuckness}(\tpool_2, \state_2) \vs[\top][\emptyset] \state_2 \in \Sigma
\] \]
\paragraph{Hoare triples.} \paragraph{Hoare triples.}
...@@ -331,7 +332,7 @@ We only give some of the proof rules for Hoare triples here, since we usually do ...@@ -331,7 +332,7 @@ We only give some of the proof rules for Hoare triples here, since we usually do
\and \and
\inferH{Ht-csq} \inferH{Ht-csq}
{\prop \vs \prop' \\ {\prop \vs \prop' \\
\hoare{\prop'}{\expr}{\Ret\val.\propB'}[\mask] \\ \hoare{\prop'}{\expr}{\Ret\val.\propB'}[\mask] \\
\All \val. \propB' \vs \propB} \All \val. \propB' \vs \propB}
{\hoare{\prop}{\expr}{\Ret\val.\propB}[\mask]} {\hoare{\prop}{\expr}{\Ret\val.\propB}[\mask]}
\and \and
...@@ -349,7 +350,7 @@ We only give some of the proof rules for Hoare triples here, since we usually do ...@@ -349,7 +350,7 @@ We only give some of the proof rules for Hoare triples here, since we usually do
% \and % \and
\inferH{Ht-atomic} \inferH{Ht-atomic}
{\prop \vs[\mask \uplus \mask'][\mask] \prop' \\ {\prop \vs[\mask \uplus \mask'][\mask] \prop' \\
\hoare{\prop'}{\expr}{\Ret\val.\propB'}[\mask] \\ \hoare{\prop'}{\expr}{\Ret\val.\propB'}[\mask] \\
\All\val. \propB' \vs[\mask][\mask \uplus \mask'] \propB \\ \All\val. \propB' \vs[\mask][\mask \uplus \mask'] \propB \\
\atomic(\expr) \atomic(\expr)
} }
......
...@@ -14,61 +14,57 @@ Implicit Types P Q : iProp Σ. ...@@ -14,61 +14,57 @@ Implicit Types P Q : iProp Σ.
Implicit Types Φ : val Λ iProp Σ. Implicit Types Φ : val Λ iProp Σ.
Implicit Types Φs : list (val Λ iProp Σ). Implicit Types Φs : list (val Λ iProp Σ).
Notation wptp s t := ([ list] ef t, WP ef @ s; {{ fork_post }})%I. Notation wptp s t Φs := ([ list] e;Φ t;Φs, WP e @ s; {{ Φ }})%I.
Lemma wp_step s e1 σ1 κ κs e2 σ2 efs m Φ : Lemma wp_step s e1 σ1 κ κs e2 σ2 efs nt Φ :
prim_step e1 σ1 κ e2 σ2 efs prim_step e1 σ1 κ e2 σ2 efs
state_interp σ1 (κ ++ κs) m -∗ WP e1 @ s; {{ Φ }} ={}[]▷=∗ state_interp σ1 (κ ++ κs) nt -∗ WP e1 @ s; {{ Φ }} ={}[]▷=∗
state_interp σ2 κs (length efs + m) WP e2 @ s; {{ Φ }} wptp s efs. state_interp σ2 κs (nt + length efs) WP e2 @ s; {{ Φ }}
wptp s efs (replicate (length efs) fork_post).
Proof. Proof.
rewrite {1}wp_unfold /wp_pre. iIntros (?) "Hσ H". rewrite {1}wp_unfold /wp_pre. iIntros (?) "Hσ H".
rewrite (val_stuck e1 σ1 κ e2 σ2 efs) //. rewrite (val_stuck e1 σ1 κ e2 σ2 efs) //.
iMod ("H" $! σ1 with "Hσ") as "(_ & H)". iMod ("H" $! σ1 with "Hσ") as "(_ & H)".
iMod ("H" $! e2 σ2 efs with "[//]") as "H". iMod ("H" $! e2 σ2 efs with "[//]") as "H".
by iIntros "!> !>". by rewrite Nat.add_comm big_sepL2_replicate_r.
Qed. Qed.
Lemma wptp_step s e1 t1 t2 κ κs σ1 σ2 Φ : Lemma wptp_step s es1 es2 κ κs σ1 σ2 Φs nt :
step (e1 :: t1,σ1) κ (t2, σ2) step (es1,σ1) κ (es2, σ2)
state_interp σ1 (κ ++ κs) (length t1) -∗ WP e1 @ s; {{ Φ }} -∗ wptp s t1 == state_interp σ1 (κ ++ κs) nt -∗ wptp s es1 Φs -
e2 t2', t2 = e2 :: t2' nt', |={}[]▷=> state_interp σ2 κs (nt + nt')
|={}[]▷=> state_interp σ2 κs (pred (length t2)) WP e2 @ s; {{ Φ }} wptp s t2'. wptp s es2 (Φs ++ replicate nt' fork_post).
Proof. Proof.
iIntros (Hstep) "Hσ He Ht". iIntros (Hstep) "Hσ Ht".
destruct Hstep as [e1' σ1' e2' σ2' efs [|? t1'] t2' ?? Hstep]; simplify_eq/=. destruct Hstep as [e1' σ1' e2' σ2' efs t2' t3 Hstep]; simplify_eq/=.
- iExists e2', (t2' ++ efs). iModIntro. iSplitR; first by eauto. iDestruct (big_sepL2_app_inv_l with "Ht") as (Φs1 Φs2 ->) "[? Ht]".
iMod (wp_step with "Hσ He") as "H"; first done. iDestruct (big_sepL2_cons_inv_l with "Ht") as (Φ Φs3 ->) "[Ht ?]".
iIntros "!> !>". iMod "H" as "(Hσ & He2 & Hefs)". iExists _. iMod (wp_step with "Hσ Ht") as "H"; first done.
iIntros "!>". rewrite Nat.add_comm app_length. iFrame. iIntros "!> !>". iMod "H" as "($ & He2 & Hefs)". iIntros "!>".
- iExists e, (t1' ++ e2' :: t2' ++ efs); iSplitR; first eauto. rewrite -(assoc_L app) -app_comm_cons. iFrame.
iFrame "He". iDestruct "Ht" as "(Ht1 & He1 & Ht2)".
iModIntro. iMod (wp_step with "Hσ He1") as "H"; first done.
iIntros "!> !>". iMod "H" as "(Hσ & He2 & Hefs)". iIntros "!>".
rewrite !app_length /= !app_length.
replace (length t1' + S (length t2' + length efs))
with (length efs + (length t1' + S (length t2'))) by lia. iFrame.
Qed. Qed.
Lemma wptp_steps s n e1 t1 κs κs' t2 σ1 σ2 Φ : Lemma wptp_steps s n es1 es2 κs κs' σ1 σ2 Φs nt :
nsteps n (e1 :: t1, σ1) κs (t2, σ2) nsteps n (es1, σ1) κs (es2, σ2)
state_interp σ1 (κs ++ κs') (length t1) -∗ WP e1 @ s; {{ Φ }} -∗ wptp s t1 state_interp σ1 (κs ++ κs') nt -∗ wptp s es1 Φs
={}[]▷=∗^n e2 t2', ={}[]▷=∗^n nt',
t2 = e2 :: t2' state_interp σ2 κs' (nt + nt') wptp s es2 (Φs ++ replicate nt' fork_post).
state_interp σ2 κs' (pred (length t2))
WP e2 @ s; {{ Φ }} wptp s t2'.
Proof. Proof.
revert e1 t1 κs κs' t2 σ1 σ2; simpl. revert nt es1 es2 κs κs' σ1 σ2 Φs.
induction n as [|n IH]=> e1 t1 κs κs' t2 σ1 σ2 /=. induction n as [|n IH]=> nt es1 es2 κs κs' σ1 σ2 Φs /=.
{ inversion_clear 1; iIntros "???"; iExists e1, t1; iFrame; eauto 10. } { inversion_clear 1; iIntros "? ?"; iExists 0=> /=.
iIntros (Hsteps) "Hσ He Ht". inversion_clear Hsteps as [|?? [t1' σ1']]. rewrite Nat.add_0_r right_id_L. by iFrame. }
iIntros (Hsteps) "Hσ He". inversion_clear Hsteps as [|?? [t1' σ1']].
rewrite -(assoc_L (++)). rewrite -(assoc_L (++)).
iMod (wptp_step with "Hσ He Ht") as (e1' t1'' ?) ">H"; first eauto; simplify_eq. iDestruct (wptp_step with "Hσ He") as (nt') ">H"; first eauto; simplify_eq.
iIntros "!> !>". iMod "H" as "(Hσ & He & Ht)". iModIntro. iIntros "!> !>". iMod "H" as "(Hσ & He)". iModIntro.
by iApply (IH with "Hσ He Ht"). iApply (step_fupdN_wand with "[Hσ He]"); first by iApply (IH with "Hσ He").
iDestruct 1 as (nt'') "[??]". rewrite -Nat.add_assoc -(assoc_L app) -replicate_plus.
by eauto with iFrame.
Qed. Qed.
Lemma wp_not_stuck κs m e σ Φ : Lemma wp_not_stuck κs nt e σ Φ :
state_interp σ κs m -∗ WP e {{ Φ }} ={}=∗ not_stuck e σ⌝. state_interp σ κs nt -∗ WP e {{ Φ }} ={}=∗ not_stuck e σ⌝.
Proof. Proof.
rewrite wp_unfold /wp_pre /not_stuck. iIntros "Hσ H". rewrite wp_unfold /wp_pre /not_stuck. iIntros "Hσ H".
destruct (to_val e) as [v|] eqn:?; first by eauto. destruct (to_val e) as [v|] eqn:?; first by eauto.
...@@ -76,83 +72,88 @@ Proof. ...@@ -76,83 +72,88 @@ Proof.
iMod (fupd_plain_mask with "H") as %?; eauto. iMod (fupd_plain_mask with "H") as %?; eauto.
Qed. Qed.
Lemma wptp_strong_adequacy Φ κs' s n e1 t1 κs t2 σ1 σ2 : Lemma wptp_strong_adequacy Φs κs' s n es1 es2 κs σ1 σ2 nt:
nsteps n (e1 :: t1, σ1) κs (t2, σ2) nsteps n (es1, σ1) κs (es2, σ2)
state_interp σ1 (κs ++ κs') (length t1) -∗ state_interp σ1 (κs ++ κs') nt -∗
WP e1 @ s; {{ Φ }} -∗ wptp s es1 Φs ={}[]▷=∗^(S n) nt',
wptp s t1 ={}[]▷=∗^(S n) e2 t2', e2, s = NotStuck e2 es2 not_stuck e2 σ2
t2 = e2 :: t2' state_interp σ2 κs' (nt + nt')
e2, s = NotStuck e2 t2 not_stuck e2 σ2 [ list] e;Φ es2;Φs ++ replicate nt' fork_post, from_option Φ True (to_val e).
state_interp σ2 κs' (length t2')
from_option Φ True (to_val e2)
([ list] v omap to_val t2', fork_post v).
Proof. Proof.
iIntros (Hstep) "Hσ He Ht". rewrite Nat_iter_S_r. iIntros (Hstep) "Hσ He". rewrite Nat_iter_S_r.
iDestruct (wptp_steps with "Hσ He Ht") as "Hwp"; first done. iDestruct (wptp_steps with "Hσ He") as "Hwp"; first done.
iApply (step_fupdN_wand with "Hwp"). iApply (step_fupdN_wand with "Hwp").
iDestruct 1 as (e2' t2' ?) "(Hσ & Hwp & Ht)"; simplify_eq/=. iDestruct 1 as (nt') "(Hσ & Ht)"; simplify_eq/=.
iMod (fupd_plain_keep_l iMod (fupd_plain_keep_l
e2, s = NotStuck e2 (e2' :: t2') not_stuck e2 σ2 ⌝%I e2, s = NotStuck e2 es2 not_stuck e2 σ2 ⌝%I
(state_interp σ2 κs' (length t2') WP e2' @ s; {{ v, Φ v }} wptp s t2')%I (state_interp σ2 κs' (nt + nt') wptp s es2 (Φs ++ replicate nt' fork_post))%I
with "[$Hσ $Hwp $Ht]") as "(Hsafe&Hσ&Hwp&Hvs)". with "[$Hσ $Ht]") as "(%&Hσ&Hwp)".
{ iIntros "(Hσ & Hwp & Ht)" (e' -> He'). { iIntros "(Hσ & Ht)" (e' -> He').
apply elem_of_cons in He' as [<-|(t1''&t2''&->)%elem_of_list_split]. move: He' => /(elem_of_list_split _ _)[?[?->]].
- iMod (wp_not_stuck with "Hσ Hwp") as "$"; auto. iDestruct (big_sepL2_app_inv_l with "Ht") as (Φs1 Φs2 ?) "[? Hwp]".
- iDestruct "Ht" as "(_ & He' & _)". by iMod (wp_not_stuck with "Hσ He'"). } iDestruct (big_sepL2_cons_inv_l with "Hwp") as (Φ Φs3 ->) "[Hwp ?]".
iMod (wp_not_stuck with "Hσ Hwp") as "$"; auto. }
iApply step_fupd_fupd. iApply step_fupd_intro; first done. iNext. iApply step_fupd_fupd. iApply step_fupd_intro; first done. iNext.
iExists _, _. iSplitL ""; first done. iFrame "Hsafe Hσ". iExists _. iSplitR; first done. iFrame "Hσ".
iSplitL "Hwp". iApply big_sepL2_fupd.
- destruct (to_val e2') as [v2|] eqn:He2'; last done. iApply (big_sepL2_impl with "Hwp").
apply of_to_val in He2' as <-. iApply (wp_value_inv' with "Hwp"). iIntros "!#" (? e Φ ??) "Hwp".
- clear Hstep. iInduction t2' as [|e t2'] "IH"; csimpl; first by iFrame. destruct (to_val e) as [v2|] eqn:He2'; last done.
iDestruct "Hvs" as "[Hv Hvs]". destruct (to_val e) as [v|] eqn:He. apply of_to_val in He2' as <-. iApply (wp_value_inv' with "Hwp").
+ apply of_to_val in He as <-. iMod (wp_value_inv' with "Hv") as "$".
by iApply "IH".
+ by iApply "IH".
Qed. Qed.
End adequacy. End adequacy.
(** Iris's generic adequacy result *) (** Iris's generic adequacy result *)
Theorem wp_strong_adequacy Σ Λ `{!invPreG Σ} e1 σ1 n κs t2 σ2 φ : Theorem wp_strong_adequacy Σ Λ `{!invPreG Σ} es σ1 n κs t2 σ2 φ :
( `{Hinv : !invG Σ}, ( `{Hinv : !invG Σ},
|={}=> |={}=>
(s: stuckness) (s: stuckness)
(stateI : state Λ list (observation Λ) nat iProp Σ) (stateI : state Λ list (observation Λ) nat iProp Σ)
(Φ fork_post : val Λ iProp Σ), (Φs : list (val Λ iProp Σ))
(fork_post : val Λ iProp Σ),
let _ : irisG Λ Σ := IrisG _ _ Hinv stateI fork_post in let _ : irisG Λ Σ := IrisG _ _ Hinv stateI fork_post in
stateI σ1 κs 0 stateI σ1 κs 0
WP e1 @ s; {{ Φ }} ([ list] e;Φ es;Φs, WP e @ s; {{ Φ }})
( e2 t2', ( es' t2',
(* e2 is the final state of the main thread, t2' the rest *) (* es' is the final state of the initial threads, t2' the rest *)
t2 = e2 :: t2' -∗ t2 = es' ++ t2' -∗
(* es' corresponds to the initial threads *)
length es' = length es -∗
(* If this is a stuck-free triple (i.e. [s = NotStuck]), then all (* If this is a stuck-free triple (i.e. [s = NotStuck]), then all
threads in [t2] are not stuck *) threads in [t2] are not stuck *)
e2, s = NotStuck e2 t2 not_stuck e2 σ2 -∗ e2, s = NotStuck e2 t2 not_stuck e2 σ2 -∗
(* The state interpretation holds for [σ2] *) (* The state interpretation holds for [σ2] *)
stateI σ2 [] (length t2') -∗ stateI σ2 [] (length t2') -∗
(* If the main thread is done, its post-condition [Φ] holds *) (* If the initial threads are done, their post-condition [Φ] holds *)
from_option Φ True (to_val e2) -∗ ([ list] e;Φ es';Φs, from_option Φ True (to_val e)) -∗
(* For all threads that are done, their postcondition [fork_post] holds. *) (* For all forked-off threads that are done, their postcondition
[fork_post] holds. *)
([ list] v omap to_val t2', fork_post v) -∗ ([ list] v omap to_val t2', fork_post v) -∗
(* Under all these assumptions, and while opening all invariants, we (* Under all these assumptions, and while opening all invariants, we
can conclude [φ] in the logic. After opening all required invariants, can conclude [φ] in the logic. After opening all required invariants,
one can use [fupd_intro_mask'] or [fupd_mask_weaken] to introduce the one can use [fupd_intro_mask'] or [fupd_mask_weaken] to introduce the
fancy update. *) fancy update. *)
|={,}=> φ )) |={,}=> φ ))
nsteps n ([e1], σ1) κs (t2, σ2) nsteps n (es, σ1) κs (t2, σ2)
(* Then we can conclude [φ] at the meta-level. *) (* Then we can conclude [φ] at the meta-level. *)
φ. φ.
Proof. Proof.
intros Hwp ?. intros Hwp ?.
eapply (step_fupdN_soundness' _ (S (S n)))=> Hinv. rewrite Nat_iter_S. eapply (step_fupdN_soundness' _ (S (S n)))=> Hinv. rewrite Nat_iter_S.
iMod Hwp as (s stateI Φ fork_post) "(Hσ & Hwp & Hφ)". iMod Hwp as (s stateI Φ fork_post) "(Hσ & Hwp & Hφ)".
iDestruct (big_sepL2_length with "Hwp") as %Hlen1.
iApply step_fupd_intro; [done|]; iModIntro. iApply step_fupd_intro; [done|]; iModIntro.
iApply step_fupdN_S_fupd. iApply (step_fupdN_wand with "[-Hφ]"). iApply step_fupdN_S_fupd. iApply (step_fupdN_wand with "[-Hφ]").
{ iApply (@wptp_strong_adequacy _ _ (IrisG _ _ Hinv stateI fork_post) _ [] { iApply (@wptp_strong_adequacy _ _ (IrisG _ _ Hinv stateI fork_post) _ []
with "[Hσ] Hwp"); eauto; by rewrite right_id_L. } with "[Hσ] Hwp"); eauto; by rewrite right_id_L. }
iIntros "Hpost". iDestruct "Hpost" as (e2 t2' ->) "(? & ? & ? & ?)". iDestruct 1 as (nt' ?) "(Hσ & Hval) /=".
iDestruct (big_sepL2_app_inv_r with "Hval") as (es' t2' ->) "[Hes' Ht2']".
iDestruct (big_sepL2_length with "Ht2'") as %Hlen2.
rewrite replicate_length in Hlen2; subst.
iDestruct (big_sepL2_length with "Hes'") as %Hlen3.
iApply fupd_plain_mask_empty. iApply fupd_plain_mask_empty.
iMod ("Hφ" with "[% //] [$] [$] [$] [$]"). done. iApply ("Hφ" with "[//] [%] [//] Hσ Hes'"); [congruence|].
by rewrite big_sepL2_replicate_r // big_sepL_omap.
Qed. Qed.
(** Since the full adequacy statement is quite a mouthful, we prove some more (** Since the full adequacy statement is quite a mouthful, we prove some more
...@@ -202,9 +203,11 @@ Proof. ...@@ -202,9 +203,11 @@ Proof.
intros Hwp. apply adequate_alt; intros t2 σ2 [n [κs ?]]%erased_steps_nsteps. intros Hwp. apply adequate_alt; intros t2 σ2 [n [κs ?]]%erased_steps_nsteps.
eapply (wp_strong_adequacy Σ _); [|done]=> ?. eapply (wp_strong_adequacy Σ _); [|done]=> ?.
iMod Hwp as (stateI fork_post) "[Hσ Hwp]". iMod Hwp as (stateI fork_post) "[Hσ Hwp]".
iExists s, (λ σ κs _, stateI σ κs), (λ v, φ v⌝%I), fork_post. iExists s, (λ σ κs _, stateI σ κs), [(λ v, φ v⌝%I)], fork_post => /=.
iIntros "{$Hσ $Hwp} !>" (e2 t2' -> ?) "_ H _". iIntros "{$Hσ $Hwp} !>" (e2 t2' -> ? ?) "_ H _".
iApply fupd_mask_weaken; [done|]. iSplit; [|done]. iApply fupd_mask_weaken; [done|]. iSplit; [|done].
iDestruct (big_sepL2_cons_inv_r with "H") as (e' ? ->) "[Hwp H]".
iDestruct (big_sepL2_nil_inv_r with "H") as %->.
iIntros (v2 t2'' [= -> <-]). by rewrite to_of_val. iIntros (v2 t2'' [= -> <-]). by rewrite to_of_val.
Qed. Qed.
...@@ -222,8 +225,10 @@ Proof. ...@@ -222,8 +225,10 @@ Proof.
intros Hwp [n [κs ?]]%erased_steps_nsteps. intros Hwp [n [κs ?]]%erased_steps_nsteps.
eapply (wp_strong_adequacy Σ _); [|done]=> ?. eapply (wp_strong_adequacy Σ _); [|done]=> ?.
iMod (Hwp _ κs) as (stateI fork_post) "(Hσ & Hwp & Hφ)". iMod (Hwp _ κs) as (stateI fork_post) "(Hσ & Hwp & Hφ)".
iExists s, stateI, (λ _, True)%I, fork_post. iExists s, stateI, [(λ _, True)%I], fork_post => /=.
iIntros "{$Hσ $Hwp} !>" (e2 t2' -> _) "Hσ _ _ /=". iIntros "{$Hσ $Hwp} !>" (e2 t2' -> _ _) "Hσ H _ /=".
iDestruct (big_sepL2_cons_inv_r with "H") as (? ? ->) "[_ H]".
iDestruct (big_sepL2_nil_inv_r with "H") as %->.
iDestruct ("Hφ" with "Hσ") as (E) ">Hφ". iDestruct ("Hφ" with "Hσ") as (E) ">Hφ".
by iApply fupd_mask_weaken; first set_solver. by iApply fupd_mask_weaken; first set_solver.
Qed. Qed.
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment