Skip to content
Snippets Groups Projects

Compute service example

Merged Jonas Kastberg requested to merge jonas/compute_list_par into master
Files
7
+ 400
0
 
From iris.algebra Require Import frac.
 
From iris.heap_lang Require Import metatheory.
 
From actris.utils Require Import llist.
 
From actris.channel Require Import proofmode proto channel.
 
From actris.logrel Require Import term_typing_rules session_typing_rules
 
subtyping_rules napp.
 
From actris.logrel.lib Require Import par_start.
 
From actris.logrel.examples Require Import compute_service.
 
 
Definition send_all_par : val :=
 
rec: "go" "c" "xs" "lk" "counter" :=
 
if: lisnil "xs" then
 
acquire "lk";; select "c" #stop;; release "lk";; #()
 
else
 
acquire "lk";;
 
select "c" #cont;; send "c" (lpop "xs");;
 
"counter" <- !"counter"+#1;;
 
release "lk";;
 
"go" "c" "xs" "lk" "counter".
 
 
Definition recv_all_par : val :=
 
rec: "go" "c" "ys" "n" "lk" "counter" :=
 
if: "n" = #0 then #() else
 
acquire "lk";;
 
if: (#0 = !"counter") then
 
release "lk";; "go" "c" "ys" "n" "lk" "counter"
 
else
 
let: "x" := recv "c" in
 
"counter" <- !"counter"-#1;;
 
release "lk";;
 
"go" "c" "ys" ("n"-#1) "lk" "counter";;
 
lcons "x" "ys".
 
 
Definition compute_client : val :=
 
λ: "xs" "c",
 
let: "n" := llength "xs" in
 
let: "counter" := ref #0 in
 
let: "ys" := lnil #() in
 
let: "lk" := newlock #() in
 
(send_all_par "c" "xs" "lk" "counter" |||
 
recv_all_par "c" "ys" "n" "lk" "counter");; "ys".
 
 
Definition lty_list_aux `{!heapG Σ} (A : ltty Σ) (X : ltty Σ) : ltty Σ :=
 
ref_uniq (() + (A * X)).
 
Instance lty_list_aux_contractive `{!heapG Σ} A :
 
Contractive (@lty_list_aux Σ _ A).
 
Proof. solve_proto_contractive. Qed.
 
Definition lty_list `{!heapG Σ} (A : ltty Σ) : ltty Σ := lty_rec (lty_list_aux A).
 
 
Notation "'list' A" := (lty_list A) (at level 10) : lty_scope.
 
 
Section compute_example.
 
Context `{heapG Σ, chanG Σ, lockG Σ, spawnG Σ}.
 
Context `{!inG Σ fracR}.
 
 
Definition compute_type_client_aux (rec : lsty Σ) : lsty Σ :=
 
lty_select $ <[cont := (<!! A> TY () A; <??> TY A ; rec)%lty]> $
 
<[stop := END%lty]>∅.
 
Instance compute_type_client_contractive :
 
Contractive (compute_type_client_aux).
 
Proof. solve_proto_contractive. Qed.
 
Definition compute_type_client : lsty Σ :=
 
lty_rec (compute_type_client_aux).
 
Global Instance compute_type_client_unfold :
 
ProtoUnfold (lsty_car (compute_type_client))
 
(lsty_car (compute_type_client_aux compute_type_client)).
 
Proof. apply proto_unfold_eq, (fixpoint_unfold compute_type_client_aux). Qed.
 
 
Definition list_pred (A : ltty Σ) : val val iProp Σ :=
 
(λ v w : val, v = w ltty_car A v)%I.
 
 
Lemma llength_spec A (l : loc) :
 
{{{ ltty_car (list A) #l }}} llength #l
 
{{{ xs (n:Z), RET #n; Z.of_nat (length xs) = n
 
llist (λ v w , v = w ltty_car A v) l xs }}}.
 
Proof.
 
iIntros "!>" (Φ) "Hl HΦ".
 
iLöb as "IH" forall (l Φ).
 
wp_lam.
 
rewrite {2}/lty_list /lty_rec /lty_list_aux fixpoint_unfold.
 
iDestruct "Hl" as (ltmp l' [=<-]) "[Hl [ Hl' | Hl' ]]".
 
- wp_load. iDestruct "Hl'" as (xs ->) "Hl'". wp_pures.
 
iAssert (llist (list_pred A) l [])%I with "[Hl Hl']" as "Hl".
 
{ rewrite /llist. iDestruct "Hl'" as %->. iApply "Hl". }
 
iApply "HΦ". eauto with iFrame.
 
- wp_load. iDestruct "Hl'" as (xs ->) "Hl'". wp_pures.
 
iDestruct "Hl'" as (x vl' ->) "[HA Hl']".
 
(* iDestruct "Hl'" as (l' xs ->) "[Hl' Hl'']". *)
 
wp_pures.
 
rewrite fixpoint_unfold.
 
iDestruct "Hl'" as (l' xs ->) "[Hl' Hl'']".
 
wp_apply ("IH" with "[Hl' Hl'']").
 
{ rewrite /lty_list /lty_rec.
 
iEval (rewrite fixpoint_unfold).
 
iExists _, _. iFrame "Hl' Hl''". done. }
 
iIntros (ys n) "[<- H]".
 
iAssert (llist (list_pred A) l (x :: ys))%I with "[Hl HA H]" as "Hl".
 
{ iExists x, l'. eauto with iFrame. }
 
wp_pures. iApply "HΦ". iFrame "Hl". by rewrite (Nat2Z.inj_add 1).
 
Qed.
 
 
Definition cont_type (A : ltty Σ) : lsty Σ :=
 
(lty_select (<[ cont := <!!> TY () A ; END ]>∅))%lty.
 
Definition stop_type : lsty Σ :=
 
(lty_select (<[ stop := END ]>∅))%lty.
 
Definition recv_type (A : ltty Σ) : lsty Σ :=
 
(<??> TY A ; END)%lty.
 
 
Definition compute_type_invariant
 
γ (A : ltty Σ) (c : val) (counter : loc) : iProp Σ :=
 
( (n : nat) (b : bool),
 
(if b then True else own γ 1%Qp)
 
counter #n
 
c (lsty_car (lty_napp (recv_type A) n <++>
 
(if b then compute_type_client else END)%lty)))%I.
 
 
Lemma compute_type_client_unfold_app_cont A :
 
compute_type_client <:
 
(cont_type A <++> (recv_type A <++> compute_type_client)).
 
Proof.
 
rewrite {1}/compute_type_client /lty_rec fixpoint_unfold.
 
replace (fixpoint (compute_type_client_aux)) with
 
(compute_type_client) by eauto.
 
rewrite /compute_type_client_aux.
 
iApply lty_le_trans.
 
{ iApply lty_le_select.
 
iApply (big_sepM2_insert _ _ (<[stop:=END%lty]>∅));
 
[ done | done | ].
 
iSplit.
 
- iExists A. iApply lty_le_refl.
 
- iApply big_sepM2_insert; [ done | done | ].
 
iSplit; [ iApply lty_le_refl | done ]. }
 
iApply lty_le_trans.
 
{ iApply lty_le_select_subseteq.
 
apply insert_mono, insert_subseteq; done. }
 
rewrite /cont_type /recv_type.
 
iPoseProof (lty_le_app_select) as "[_ Hle]".
 
iApply (lty_le_trans); last by iApply "Hle".
 
rewrite fmap_insert fmap_empty.
 
rewrite lty_app_send lty_app_end_l.
 
rewrite lty_app_recv lty_app_end_l.
 
iApply lty_le_refl.
 
Qed.
 
 
Lemma compute_type_client_unfold_app_stop :
 
compute_type_client <: lty_select (<[stop := END%lty]>∅).
 
Proof.
 
rewrite {1}/compute_type_client /lty_rec fixpoint_unfold.
 
replace (fixpoint (compute_type_client_aux)) with
 
(compute_type_client) by eauto.
 
rewrite /compute_type_client_aux.
 
iApply lty_le_select_subseteq.
 
rewrite insert_commute; [ | eauto ].
 
apply insert_mono, insert_subseteq; done.
 
Qed.
 
 
Lemma recv_type_cont_type_swap A B :
 
recv_type B <++> cont_type A <: cont_type A <++> recv_type B.
 
Proof.
 
iApply lty_le_trans.
 
rewrite lty_app_recv lty_app_end_l.
 
iApply lty_le_swap_recv_select. rewrite fmap_insert fmap_empty.
 
iPoseProof (lty_le_app_select) as "[_ Hle]".
 
iApply (lty_le_trans); last by iApply "Hle".
 
rewrite fmap_insert fmap_empty.
 
iApply lty_le_select.
 
iApply big_sepM2_insert; [ done | done | ].
 
iSplit; [ | done ].
 
rewrite lty_app_send lty_app_end_l.
 
iApply lty_le_swap_recv_send.
 
Qed.
 
 
Lemma recv_type_stop_type_swap B :
 
recv_type B <++> stop_type <: stop_type <++> recv_type B.
 
Proof.
 
iApply lty_le_trans.
 
rewrite lty_app_recv lty_app_end_l.
 
iApply lty_le_swap_recv_select. rewrite fmap_insert fmap_empty.
 
iPoseProof (lty_le_app_select) as "[_ Hle]".
 
iApply (lty_le_trans); last by iApply "Hle".
 
rewrite fmap_insert fmap_empty.
 
iApply lty_le_select.
 
iApply big_sepM2_insert; [ done | done | ].
 
iSplit; [ | done ].
 
rewrite lty_app_end_l. eauto.
 
Qed.
 
 
Lemma send_all_par_spec γ γf A c l xs lk counter :
 
{{{ llist (list_pred (() A)) l xs own γf 1%Qp
 
is_lock γ lk (compute_type_invariant γf A c counter) }}}
 
send_all_par c #l lk #counter
 
{{{ RET #(); llist (list_pred (() A)) l []
 
is_lock γ lk (compute_type_invariant γf A c counter) }}}.
 
Proof.
 
iIntros (Φ) "(Hl & Hf & #Hlk) HΦ".
 
iInduction xs as [|x xs] "IH".
 
{ wp_lam. wp_apply (lisnil_spec with "Hl"); iIntros "Hl".
 
rewrite /select.
 
wp_apply (acquire_spec with "Hlk").
 
iIntros "[Hlocked HI]".
 
iDestruct "HI" as (n [ | ]) "(Hf' & Hcounter & Hc)"; last first.
 
{ by iDestruct (own_valid_2 with "Hf Hf'") as %[]. }
 
iDestruct (iProto_mapsto_le with "Hc []") as "Hc".
 
{ iApply iProto_le_trans.
 
{ iApply iProto_le_app; [ iApply iProto_le_refl | ].
 
iApply compute_type_client_unfold_app_stop. }
 
rewrite -lsty_car_app.
 
iApply lsty_car_mono.
 
iApply lty_napp_swap.
 
iApply recv_type_stop_type_swap. }
 
wp_send with "[]"; [ eauto | ].
 
wp_apply (release_spec with "[-HΦ Hl]").
 
{ iFrame "Hlk Hlocked".
 
iExists n, false.
 
rewrite lookup_total_insert -lsty_car_app lty_app_end_l lty_app_end_r.
 
iFrame "Hf Hcounter Hc". }
 
iIntros "_". wp_pures. iApply "HΦ". iFrame "Hl Hlk Hsf". }
 
wp_lam. wp_apply (lisnil_spec with "Hl"); iIntros "Hl".
 
wp_apply (acquire_spec with "Hlk").
 
iIntros "[Hlocked HI]".
 
iDestruct "HI" as (n [ | ]) "(Hf' & Hcounter & Hc)"; last first.
 
{ by iDestruct (own_valid_2 with "Hf Hf'") as %[]. }
 
iDestruct (iProto_mapsto_le with "Hc []") as "Hc".
 
{ iApply iProto_le_trans.
 
{ iApply iProto_le_app; [ iApply iProto_le_refl | ].
 
iApply compute_type_client_unfold_app_cont. }
 
rewrite assoc. rewrite assoc. rewrite assoc.
 
iApply iProto_le_app; [ | iApply iProto_le_refl ].
 
iApply iProto_le_app; [ | iApply iProto_le_refl ].
 
rewrite -lsty_car_app.
 
iApply lsty_car_mono.
 
iApply lty_napp_swap.
 
iApply recv_type_cont_type_swap. }
 
rewrite /select.
 
wp_send with "[]"; [ eauto | ].
 
rewrite lookup_total_insert.
 
wp_apply (lpop_spec with "Hl"); iIntros (v) "[HIx Hl]".
 
wp_send with "[HIx]".
 
{ iDestruct "HIx" as (->) "$HIx". }
 
wp_load. wp_store.
 
wp_apply (release_spec with "[-HΦ Hf Hl]").
 
{ iFrame "Hlk Hlocked".
 
iExists (n+1), true.
 
rewrite assoc.
 
rewrite left_id.
 
rewrite assoc.
 
repeat rewrite -lsty_car_app.
 
rewrite -lty_napp_S_r.
 
rewrite Nat.add_succ_r.
 
rewrite -plus_n_O.
 
replace (Z.of_nat n + 1)%Z with (Z.of_nat (S n)) by lia.
 
iFrame "Hc Hcounter". }
 
iIntros "_". wp_pures.
 
iApply ("IH" with "Hl Hf").
 
iApply "HΦ".
 
Qed.
 
 
Lemma recv_all_par_spec γ γf A c l n lk counter :
 
{{{ llist (list_pred A) l []
 
is_lock γ lk (compute_type_invariant γf A c counter) }}}
 
recv_all_par c #l #n lk #counter
 
{{{ ys, RET #(); n = length ys
 
llist (list_pred A) l ys
 
is_lock γ lk (compute_type_invariant γf A c counter) }}}.
 
Proof.
 
iIntros (Φ) "(Hl & #Hlk) HΦ".
 
iLöb as "IH" forall (n Φ).
 
destruct n as [ | n ].
 
{ wp_lam. wp_pures. iApply "HΦ". by iFrame "Hl Hlk". }
 
wp_lam.
 
wp_apply (acquire_spec with "Hlk").
 
iIntros "[Hlocked HI]".
 
iDestruct "HI" as (m b) "(Hb & Hcounter & Hc)".
 
wp_load.
 
destruct m as [ | m ].
 
{ wp_apply (release_spec with "[$Hlocked $Hlk Hb Hcounter Hc]").
 
{ iExists 0, b. iFrame "Hb Hcounter Hc". }
 
iIntros "_". wp_pures. iApply ("IH" with "Hl").
 
iApply "HΦ". }
 
wp_recv (w) as "Hw". wp_pures.
 
rewrite Nat2Z.inj_succ.
 
wp_load. wp_store.
 
replace (Z.succ (Z.of_nat m) - 1)%Z with (Z.of_nat m) by lia.
 
wp_apply (release_spec with "[$Hlocked $Hlk Hb Hcounter Hc]").
 
{ replace (Z.succ (Z.of_nat m) - 1)%Z with (Z.of_nat m) by lia.
 
iExists m, b. iFrame "Hb Hcounter Hc". }
 
iIntros "_".
 
wp_pures.
 
replace (Z.of_nat (S n) - 1)%Z with (Z.of_nat (n)) by lia.
 
wp_apply ("IH" with "Hl").
 
iIntros (ys). iDestruct 1 as (Heq) "(Hl & Hc)".
 
wp_apply (lcons_spec with "[$Hl $Hw//]").
 
iIntros "Hl". iApply "HΦ". iFrame.
 
iPureIntro. by rewrite Heq.
 
Qed.
 
 
Lemma llist_lty_list lys ys A :
 
llist (list_pred A) lys ys -∗
 
ltty_car (lty_list A) #lys.
 
Proof.
 
iIntros "Hlys".
 
iInduction ys as [|y ys] "IH" forall (lys).
 
- rewrite /lty_list /lty_rec fixpoint_unfold.
 
iExists lys, NONEV. rewrite /llist. iFrame "Hlys".
 
iSplit; [ done | ].
 
iLeft. eauto.
 
- iDestruct "Hlys" as (vb l'') "[[-> HB] [Hl' Hrec]]".
 
iEval (rewrite /lty_list /lty_rec fixpoint_unfold).
 
iExists lys, _. iFrame "Hl'".
 
iSplit; [ done | ].
 
rewrite /lty_list /lty_rec.
 
iRight. iExists _. iSplit; [ done | ]. iExists _, _. iSplit; [ done | ].
 
iFrame "HB". by iApply ("IH" with "Hrec").
 
Qed.
 
 
Lemma ltyped_compute_client Γ (A : ltty Σ) :
 
Γ compute_client : lty_list (() A)
 
chan compute_type_client
 
lty_list A.
 
Proof.
 
iApply ltyped_val_ltyped.
 
iApply ltyped_val_lam.
 
iApply ltyped_post_nil.
 
iApply (ltyped_lam [EnvItem "xs" _]).
 
iIntros "!>" (vs) "HΓ". simplify_map_eq.
 
iDestruct (env_ltyped_cons _ _ "c" with "HΓ") as (vc ->) "[Hc HΓ]".
 
iDestruct (env_ltyped_cons _ _ "xs" with "HΓ") as (vlxs ->) "[Hlxs HΓ]".
 
rewrite /lty_list /lty_rec fixpoint_unfold.
 
iDestruct "Hlxs" as (l' v ->) "[Hlxs Hv]".
 
wp_apply (llength_spec with "[Hlxs Hv]").
 
{ iEval (rewrite /lty_list /lty_rec fixpoint_unfold).
 
iExists l', v. eauto with iFrame. }
 
iIntros (xs n) "[<- Hlxs]".
 
wp_alloc counter as "Hcounter".
 
wp_apply (lnil_spec); [ done | ].
 
iIntros (lys) "Hlys".
 
iMod (own_alloc 1%Qp) as (γf) "Hf"; [ done | ].
 
wp_apply (newlock_spec (compute_type_invariant γf A vc counter)
 
with "[Hcounter Hc]").
 
{ iExists 0, true. repeat rewrite left_id. iFrame "Hcounter Hc". }
 
iIntros (lk γ) "#Hlk".
 
wp_apply (par_spec
 
(λ v, v = #())%I
 
(λ v, ys, v = #() llist (list_pred A) lys ys)%I
 
with "[Hlxs Hf] [Hlys]").
 
{ wp_apply (send_all_par_spec with "[$Hlxs $Hf $Hlk]").
 
iIntros "(Hlxs & _)". eauto. }
 
{ wp_apply (recv_all_par_spec with "[$Hlys $Hlk]").
 
iIntros (ys) "(Heq & Hlys & _)".
 
iExists ys. iFrame. eauto. }
 
iIntros (w1 w2) "[-> Hw2]".
 
iDestruct "Hw2" as (ys) "(-> & Hlys)".
 
iIntros "!>".
 
wp_pures. iFrame "HΓ".
 
by iApply llist_lty_list.
 
Qed.
 
 
Lemma lty_le_compute_type_dual :
 
lty_dual compute_type_service <: compute_type_client.
 
Proof.
 
rewrite /compute_type_client /compute_type_service.
 
iLöb as "IH".
 
iApply lty_le_r; [ | iApply lty_bi_le_sym; iApply lty_le_rec_unfold ].
 
iApply lty_le_dual_l.
 
iApply lty_le_r; [ | iApply lty_bi_le_sym; iApply lty_le_rec_unfold ].
 
iApply lty_le_l; [ iApply lty_le_dual_select | ].
 
iApply lty_le_branch. rewrite fmap_insert fmap_insert fmap_empty.
 
iApply big_sepM2_insert; [ done | done | ].
 
iSplit.
 
- iApply lty_le_l; [ iApply lty_le_dual_send_exist | ].
 
iIntros (As). iExists (As).
 
iApply lty_le_recv; [ iApply lty_le_refl | ].
 
iApply lty_le_l; [ iApply lty_le_dual_recv | ].
 
iApply lty_le_send; [ iApply lty_le_refl | ].
 
iIntros "!>!>!>". iApply lty_le_dual_l. iApply "IH".
 
- iApply big_sepM2_insert; [ done | done | ]. iSplit; [ | done ].
 
iApply lty_le_l; [ iApply lty_le_dual_end | iApply lty_le_refl ].
 
Qed.
 
 
Lemma ltyped_compute_list_par A e Γ Γ' :
 
(Γ e : lty_list (() A) Γ') -∗
 
Γ par_start (compute_service) (compute_client e) :
 
(() * (lty_list A)) Γ'.
 
Proof.
 
iIntros "He".
 
iApply (ltyped_app with "[He]").
 
{ iApply (ltyped_app with "He").
 
iApply ltyped_compute_client. }
 
iApply ltyped_app.
 
{ iApply ltyped_compute_service. }
 
iApply ltyped_subsumption; [ iApply env_le_refl | | iApply env_le_refl | ].
 
{ iApply lty_le_arr; [ iApply lty_le_refl | ].
 
iApply lty_le_arr; [ | iApply lty_le_refl ].
 
iApply lty_le_arr; [ | iApply lty_le_refl ].
 
iApply lty_le_chan.
 
iApply lty_le_compute_type_dual. }
 
iApply ltyped_par_start.
 
Qed.
 
 
End compute_example.
Loading