clutch.coneris.examples.lazy_rand.lazy_rand_race

From iris.algebra Require Import excl_auth.
From clutch.coneris Require Import coneris par spawn lazy_rand_interface.

Set Default Proof Using "Type*".
Section lemmas.
  Context `{!inG Σ (excl_authR boolO)}.

  (* Helpful lemmas *)
  Lemma ghost_var_alloc b :
     |==> γ, own γ (E b) own γ (E b).
  Proof.
    iMod (own_alloc (E b E b)) as (γ) "[??]".
    - by apply excl_auth_valid.
    - by eauto with iFrame.
  Qed.

  Lemma ghost_var_agree γ b c :
    own γ (E b) -∗ own γ (E c) -∗ b = c .
  Proof.
    iIntros "Hγ● Hγ◯".
    by iCombine "Hγ● Hγ◯" gives %->%excl_auth_agree_L.
  Qed.

  Lemma ghost_var_update γ b' b c :
    own γ (E b) -∗ own γ (E c) ==∗ own γ (E b') own γ (E b').
  Proof.
    iIntros "Hγ● Hγ◯".
    iMod (own_update_2 _ _ _ (E b' E b') with "Hγ● Hγ◯") as "[$$]".
    { by apply excl_auth_update. }
    done.
  Qed.
End lemmas.

Section race.
  Context `{!conerisGS Σ, !spawnG Σ, c:!lazy_rand 1, !inG Σ (excl_authR boolO) }.


  Definition race_prog : expr :=
  let: "r" := init_lazy_rand #() in
  ( lazy_read_rand "r" (allocate_tape #()) #0)
  |||
  ( lazy_read_rand "r" (allocate_tape #()) #1).

  Lemma race_prog_spec:
  {{{ (1/2) }}}
    race_prog
    {{{ (n:nat), RET ((#n,#n),(#n,#n))%Z; n<=1 }}}.
  Proof.
    iIntros (Φ) "Herr HΦ".
    rewrite /race_prog.
    iMod (ghost_var_alloc false) as (γ) "[Hauth Hfrag]".
    wp_apply (lazy_rand_init (nroot.@"1") (λ x, x = None own γ (E false)
                                                 x1, x=Some (x1, x1) (own γ (E true)))%I
                                                
               with "[Hfrag]").
    { iLeft. iFrame. done. }
    iIntros (?) "(%&%&%&#Hinv)".
    iMod (inv_alloc (nroot.@"inv") _ (own γ (E false) (1/2) own γ (E true))%I with "[Herr Hauth ]") as "#Hinv2".
    { iLeft. iFrame. }
    wp_pures.
    wp_apply (wp_par (λ res, (n:nat), (#n, #n)%V = res rand_frag n n _)%I
                (λ res, (n:nat), (#n, #n)%V = res rand_frag n n _)%I with "[][]").
    - wp_apply (lazy_rand_alloc_tape _ _ with "[//]").
      iIntros (α) "Ht".
      replace #0 with (# (Z.of_nat 0)) by done.
      wp_apply (lazy_rand_spec _ _ (λ x : option (nat * nat),
                                      x = None own γ (E false)
                                                    x1 : nat, x = Some (x1, x1) own γ (E true))%I
                  _ _ _ (λ x y, x=y rand_frag x x _)%I (λ x y, x=y rand_frag x x _)%I with "[-]").
      + iSplit; first done.
        simpl. iIntros (n) "H1 Hauth".
        iApply (state_update_inv_acc with "Hinv2"); first done.
        iIntros ">[[H2 Herr]|H2]"; iDestruct "H1" as "[(->&?)|(%&->&?)]"; iDestruct (ghost_var_agree with "[$][$]") as "%"; simplify_eq.
        * iMod (rand_tape_presample _ _ _ _ _ _ _ _ _ (λ x, if bool_decide (fin_to_nat x = 0%nat) then 0 else 1) with "[$][$][$]") as "(%n&?&?)".
          { apply subseteq_difference_r; last done.
            by apply ndot_ne_disjoint.
          }
          { intros. case_bool_decide; simpl; lra. }
          { rewrite SeriesC_finite_foldr/=. lra. }
          iAssert (fin_to_nat n=0%nat)%I as "%Heq".
          { case_bool_decide; first done. iDestruct (ec_contradict with "[$]") as "[]".
            simpl. lra. }
          rewrite bool_decide_eq_true_2; last done.
          iFrame.
          iMod (ghost_var_update with "[$][$]") as "[H1 H2]".
          iFrame.
          iModIntro.
          iIntros. iSplitR "H1"; last first.
          { by iRight. }
          iMod (rand_auth_update (0,_) with "[$]") as "?".
          { simpl. lia. }
          iDestruct (rand_auth_duplicate with "[$]") as "#?".
          rewrite Heq. iFrame. iIntros.
          iModIntro. simpl. repeat iSplit; try done.
          iRight. iFrame. iExists _. done.
        * iDestruct (rand_auth_duplicate with "[$]") as "#?".
          iFrame. iModIntro.
          repeat iSplit; try done.
          iRight. iFrame. by iExists _.
      + by iIntros (??) "[(->&#$)|(->&#$)]".
    - wp_apply (lazy_rand_alloc_tape _ _ ); first done.
      iIntros (α) "Ht".
      replace #1 with (# (Z.of_nat 1)) by done.
      wp_apply (lazy_rand_spec _ _
                  (λ x : option (nat * nat),
                     x = None own γ (E false)
                                   x1 : nat, x = Some (x1, x1) own γ (E true))%I
                  _ _ _ (λ x y, x=y rand_frag x x _)%I (λ x y, x=y rand_frag x x _)%I with "[-]").
      + iSplit; first done.
        simpl. iIntros (n) "H1 Hauth".
        iApply (state_update_inv_acc with "Hinv2"); first done.
        iIntros ">[[H2 Herr]|H2]"; iDestruct "H1" as "[(->&?)|(%&->&?)]"; iDestruct (ghost_var_agree with "[$][$]") as "%"; simplify_eq.
        * iMod (rand_tape_presample _ _ _ _ _ _ _ _ _ (λ x, if bool_decide (fin_to_nat x = 1%nat) then 0 else 1) with "[$][$][$]") as "(%n&?&?)".
          { apply subseteq_difference_r; last done.
            by apply ndot_ne_disjoint.
          }
          { intros. case_bool_decide; simpl; lra. }
          { rewrite SeriesC_finite_foldr/=. lra. }
          iAssert (fin_to_nat n=1%nat)%I as "%Heq".
          { case_bool_decide; first done. iDestruct (ec_contradict with "[$]") as "[]".
            simpl. lra. }
          rewrite bool_decide_eq_true_2; last done.
          iFrame.
          iMod (ghost_var_update with "[$][$]") as "[H1 H2]".
          iFrame.
          iModIntro.
          iIntros. iSplitR "H1"; last first.
          { by iRight. }
          iMod (rand_auth_update (1,_) with "[$]") as "?".
          { simpl. lia. }
          iDestruct (rand_auth_duplicate with "[$]") as "#?".
          rewrite Heq. iFrame. iIntros.
          iModIntro. simpl. repeat iSplit; try done.
          iRight. iFrame. iExists _. done.
        * iDestruct (rand_auth_duplicate with "[$]") as "#?".
          iFrame. iModIntro.
          repeat iSplit; try done.
          iRight. iFrame. by iExists _.
      + by iIntros (??) "[(->&#$)|(->&#$)]".
    - iIntros (??) "[(%&<-&?) (%&<-&?)]".
      iDestruct (rand_frag_frag_agree with "[$][$]") as "[% %]".
      simplify_eq.
      iApply "HΦ".
      iNext.
      iDestruct (rand_frag_valid with "[$]") as "%".
      done.
  Qed.


End race.