clutch.clutch.examples.id_rec
From clutch Require Export clutch clutch.lib.flip.
Set Default Proof Using "Type*".
Section proofs.
Context `{!clutchRGS Σ}.
Definition idrecN := nroot.@"idrec".
(* Warmup: λx.x refines the function that recurses once before returning its
argument. Nothing probabilistic, just recursion and state. *)
Lemma id_rec_det : ⊢ REL
(λ: "x", "x")
<<
(let: "c" := ref #0 in
(rec: "f" "x" := if: !"c" = #1 then "x" else "c" <- #1 ;; "f" "x"))
: (lrel_bool → lrel_bool).
Proof with try rel_pures_l ; try rel_pures_r.
rel_alloc_r c as "c"...
set (P := (REL (λ: "x", "x")%V
<<
(rec: "f" "x" := if: ! #c = #1 then "x" else #c <- #1;; "f" "x")%V :
lrel_bool → lrel_bool)).
iApply (refines_na_alloc (c ↦ₛ #0 ∨ ((c ↦ₛ #1) ∗ P)) idrecN).
iSplitL ; iFrame.
iIntros "#Hinv".
iApply refines_arrow_val.
iIntros "!#" (??) "#(%b&->&->)".
iRevert (b).
iLöb as "HH".
iIntros (b).
rel_rec_r.
iApply (refines_na_inv with "[$Hinv]") ; [done|].
iIntros "[HHH Hclose]".
rel_pure_l.
iDestruct "HHH" as "[c0 | c1]".
- (* First call: Set the counter and unfold the rec. def. once more. *)
rel_load_r. subst. rel_pures_r. rel_store_r. do 2 rel_pure_r.
rel_pures_r. rel_load_r...
iApply (refines_na_close with "[- $Hclose]") ; iSplitL.
{
iNext. iRight. iSplitL ; iFrame.
unfold P.
iApply refines_arrow_val.
iIntros "!#" (??) "#(%b'&->&->)".
iApply "HH".
}
rel_values.
- (* Not first call: Actually act like the identity. *)
subst...
iDestruct "c1" as "(c1 & p)".
rel_load_r...
iApply (refines_na_close with "[- $Hclose]") ;
iSplitL. { iRight. iFrame. }
rel_values.
Qed.
Lemma rec_id :
⊢ REL
let: "α" := allocB in
(rec: "f" "x" := if: flipL "α" then "x" else "f" "x")
<<
(λ: "x", "x")
: (lrel_bool → lrel_bool).
Proof with try rel_pures_l ; try rel_pures_r.
rel_alloctape_l α as "α"...
iApply (refines_na_alloc (α ↪B []) idrecN) ; iFrame.
iIntros "#Hinv".
iApply refines_arrow_val.
iIntros "!#" (??) "#(%b&->&->)".
iLöb as "HH".
rel_rec_l.
iApply (refines_na_inv with "[$Hinv]") ; [done|].
iIntros "[> α Hclose]".
rel_apply_l refines_flipL_empty_l ; iFrame.
iIntros ([]) "α".
1: iApply (refines_na_close with "[- $Hclose]") ; iFrame... 1: rel_values.
rel_pure_l.
iApply (refines_na_close with "[- $Hclose]") ; iFrame.
iApply "HH".
Qed.
Lemma id_rec :
⊢ REL
(λ: "x", "x")
<<
(let: "c" := ref #0 in
(rec: "f" "x" := if: !"c" = #1 then "x" else "c" <- #1 ;; "f" "x"))
: (lrel_bool → lrel_bool).
Proof with try rel_pures_l ; try rel_pures_r.
rel_alloc_r c as "c"...
iApply (refines_na_alloc (∃ n, c ↦ₛ #n ∗ ⌜(n = 0 ∨ n = 1)⌝) idrecN).
iSplitL ; [iExists _ ; iFrame ; eauto|].
iIntros "#Hinv".
iApply refines_arrow_val.
iIntros "!#" (??) "#(%b&->&->)".
iLöb as "HH".
rel_rec_r.
iApply (refines_na_inv with "[$Hinv]") ; [done|].
iIntros "[>[%b' [c %hb']] Hclose]".
rel_load_r.
destruct hb'.
- subst. rel_pures_r. rel_store_r. do 2 rel_pure_r.
iApply (refines_na_close with "[- $Hclose]") ;
iSplitL ; [iExists _ ; iFrame ; eauto|].
rel_pure_l.
(* Not clear how to proceed, so we *)
give_up.
- subst... iApply (refines_na_close with "[- $Hclose]") ;
iSplitL ; [iExists _ ; iFrame ; eauto|].
rel_values.
Abort.
End proofs.
Set Default Proof Using "Type*".
Section proofs.
Context `{!clutchRGS Σ}.
Definition idrecN := nroot.@"idrec".
(* Warmup: λx.x refines the function that recurses once before returning its
argument. Nothing probabilistic, just recursion and state. *)
Lemma id_rec_det : ⊢ REL
(λ: "x", "x")
<<
(let: "c" := ref #0 in
(rec: "f" "x" := if: !"c" = #1 then "x" else "c" <- #1 ;; "f" "x"))
: (lrel_bool → lrel_bool).
Proof with try rel_pures_l ; try rel_pures_r.
rel_alloc_r c as "c"...
set (P := (REL (λ: "x", "x")%V
<<
(rec: "f" "x" := if: ! #c = #1 then "x" else #c <- #1;; "f" "x")%V :
lrel_bool → lrel_bool)).
iApply (refines_na_alloc (c ↦ₛ #0 ∨ ((c ↦ₛ #1) ∗ P)) idrecN).
iSplitL ; iFrame.
iIntros "#Hinv".
iApply refines_arrow_val.
iIntros "!#" (??) "#(%b&->&->)".
iRevert (b).
iLöb as "HH".
iIntros (b).
rel_rec_r.
iApply (refines_na_inv with "[$Hinv]") ; [done|].
iIntros "[HHH Hclose]".
rel_pure_l.
iDestruct "HHH" as "[c0 | c1]".
- (* First call: Set the counter and unfold the rec. def. once more. *)
rel_load_r. subst. rel_pures_r. rel_store_r. do 2 rel_pure_r.
rel_pures_r. rel_load_r...
iApply (refines_na_close with "[- $Hclose]") ; iSplitL.
{
iNext. iRight. iSplitL ; iFrame.
unfold P.
iApply refines_arrow_val.
iIntros "!#" (??) "#(%b'&->&->)".
iApply "HH".
}
rel_values.
- (* Not first call: Actually act like the identity. *)
subst...
iDestruct "c1" as "(c1 & p)".
rel_load_r...
iApply (refines_na_close with "[- $Hclose]") ;
iSplitL. { iRight. iFrame. }
rel_values.
Qed.
Lemma rec_id :
⊢ REL
let: "α" := allocB in
(rec: "f" "x" := if: flipL "α" then "x" else "f" "x")
<<
(λ: "x", "x")
: (lrel_bool → lrel_bool).
Proof with try rel_pures_l ; try rel_pures_r.
rel_alloctape_l α as "α"...
iApply (refines_na_alloc (α ↪B []) idrecN) ; iFrame.
iIntros "#Hinv".
iApply refines_arrow_val.
iIntros "!#" (??) "#(%b&->&->)".
iLöb as "HH".
rel_rec_l.
iApply (refines_na_inv with "[$Hinv]") ; [done|].
iIntros "[> α Hclose]".
rel_apply_l refines_flipL_empty_l ; iFrame.
iIntros ([]) "α".
1: iApply (refines_na_close with "[- $Hclose]") ; iFrame... 1: rel_values.
rel_pure_l.
iApply (refines_na_close with "[- $Hclose]") ; iFrame.
iApply "HH".
Qed.
Lemma id_rec :
⊢ REL
(λ: "x", "x")
<<
(let: "c" := ref #0 in
(rec: "f" "x" := if: !"c" = #1 then "x" else "c" <- #1 ;; "f" "x"))
: (lrel_bool → lrel_bool).
Proof with try rel_pures_l ; try rel_pures_r.
rel_alloc_r c as "c"...
iApply (refines_na_alloc (∃ n, c ↦ₛ #n ∗ ⌜(n = 0 ∨ n = 1)⌝) idrecN).
iSplitL ; [iExists _ ; iFrame ; eauto|].
iIntros "#Hinv".
iApply refines_arrow_val.
iIntros "!#" (??) "#(%b&->&->)".
iLöb as "HH".
rel_rec_r.
iApply (refines_na_inv with "[$Hinv]") ; [done|].
iIntros "[>[%b' [c %hb']] Hclose]".
rel_load_r.
destruct hb'.
- subst. rel_pures_r. rel_store_r. do 2 rel_pure_r.
iApply (refines_na_close with "[- $Hclose]") ;
iSplitL ; [iExists _ ; iFrame ; eauto|].
rel_pure_l.
(* Not clear how to proceed, so we *)
give_up.
- subst... iApply (refines_na_close with "[- $Hclose]") ;
iSplitL ; [iExists _ ; iFrame ; eauto|].
rel_values.
Abort.
End proofs.