clutch.clutch.adequacy

From iris.proofmode Require Import base proofmode.
From iris.bi Require Export lib.fixpoint_mono big_op.
From iris.base_logic.lib Require Import ghost_map invariants fancy_updates.
From iris.algebra Require Import excl.
From iris.prelude Require Import options.

From clutch.prelude Require Import stdpp_ext iris_ext.
From clutch.bi Require Import weakestpre.
From clutch.prob_lang Require Import erasure.
From clutch.common Require Export language.
From clutch.clutch Require Import weakestpre primitive_laws.
From clutch.prob Require Import distribution.
Import uPred.

Section adequacy.
  Context `{!clutchGS Σ}.

  Lemma refRcoupl_step_fupdN_dbind `{Countable A, Countable A', Countable B, Countable B'}
    n (f : A → distr A') (g : B → distr B') (μ1 : distr A) (μ2 : distr B) (R : A → B → Prop) (T : A' → B' → Prop) :
    ⌜μ1 ≾ μ2 : R⌝ -∗
    (∀ a b, ⌜R a b⌝ ={∅}=∗ |={∅}▷=>^n ⌜f a ≾ g b : T⌝) -∗
    |={∅}=> |={∅}▷=>^n ⌜(μ1 ≫= f) ≾ (μ2 ≫= g) : T⌝ : iProp Σ.
  Proof.
    iIntros (HR) "H".
    iApply (step_fupdN_mono _ _ _ (⌜(∀ a b, R a b → f a ≾ g b : T)⌝)).
    { iIntros (?). iPureIntro. by eapply refRcoupl_dbind. }
    iIntros (???) "/=".
    by iMod ("H" with "[//]") as "H".
  Qed.

  Lemma wp_adequacy_spec_coupl n m e1 σ1 e1' σ1' Z φ :
    spec_coupl ∅ σ1 e1' σ1' Z -∗
    (∀ σ2 e2' σ2', Z σ2 e2' σ2' ={∅}=∗ |={∅}▷=>^n ⌜exec m (e1, σ2) ≾ lim_exec (e2', σ2') : φ⌝) -∗
    |={∅}=> |={∅}▷=>^n ⌜exec m (e1, σ1) ≾ lim_exec (e1', σ1') : φ⌝.
  Proof.
    iRevert (σ1 e1' σ1').
    iApply spec_coupl_ind.
    iIntros "!>" (σ1 e1' σ1')
      "[H |(%R & %p & %μ1 & %μ1' & % & %Hμ1 & %Hμ1' & H)] HZ".
    - by iMod ("HZ" with "[$]").
    - iEval (rewrite -Hμ1 -(erasable_pexec_lim_exec μ1' p) //).
      iApply refRcoupl_step_fupdN_dbind; [iPureIntro|].
      { by eapply Rcoupl_refRcoupl. }
      iIntros (σ2 [e2' σ2'] HR).
      iMod ("H" with "[//]") as "H".
      by iApply "H".
  Qed.

  Lemma wp_refRcoupl_val_fupd (e e' : expr) (σ σ' : state) n φ v :
    to_val e = Some v →
    state_interp σ ∗ spec_interp (e', σ') ∗ WP e {{ v, ∃ v' : val, ⤇ Val v' ∗ ⌜φ v v'⌝ }} ⊢
    |={⊤, ∅}=> ⌜exec n (e, σ) ≾ lim_exec (e', σ') : φ⌝.
  Proof.
    iIntros (He) "(Hσ & Hs & Hwp)".
    rewrite wp_unfold /wp_pre /= He.
    iMod ("Hwp" with "[$]") as "Hwp".
    iApply (wp_adequacy_spec_coupl 0 with "Hwp").
    iIntros (σ1 e1' σ1') "> (? & Hs & (% & Hv & %)) /=".
    iDestruct (spec_auth_prog_agree with "Hs Hv") as %->.
    erewrite exec_is_final; [|done].
    erewrite lim_exec_final; [|done].
    iApply fupd_mask_intro; [set_solver|]; iIntros "_".
    iPureIntro. by eapply refRcoupl_dret.
  Qed.

  Lemma wp_refRcoupl_step_fupdN (e e' : expr) (σ σ' : state) n φ :
    state_interp σ ∗ spec_interp (e', σ') ∗ WP e {{ v, ∃ v', ⤇ Val v' ∗ ⌜φ v v'⌝ }} ⊢
    |={⊤,∅}=> |={∅}▷=>^n ⌜exec n (e, σ) ≾ lim_exec (e', σ') : φ⌝.
  Proof.
    iIntros "(Hσ & HspecI_auth & Hwp)".
    iInduction n as [|n] "IH" forall (e σ e' σ').
    { destruct (to_val e) eqn:He.
      - iMod (wp_refRcoupl_val_fupd with "[$]") as %?; [done|].
        by iApply step_fupdN_intro.
      - iApply fupd_mask_intro; [done|]; iIntros "_ /=".
        iPureIntro. rewrite He. apply refRcoupl_dzero. }
    destruct (to_val e) eqn:He.
    { iMod (wp_refRcoupl_val_fupd with "[$]") as %?; [done|].
      by iApply step_fupdN_intro. }
    iEval (rewrite wp_unfold /wp_pre /= He) in "Hwp".
    iMod ("Hwp" with "[$]") as "Hwp".
    iApply (wp_adequacy_spec_coupl with "Hwp").
    iIntros (σ2 e2' σ2') "(%R' & %m & %μ2' & % & % & %Hμ2' & Hwp)".
    iEval (rewrite -(erasable_pexec_lim_exec μ2' m) //).
    iEval (rewrite exec_Sn /step_or_final /= He).
    rewrite -step_fupdN_Sn.
    iApply refRcoupl_step_fupdN_dbind; [iPureIntro|].
    { by apply Rcoupl_refRcoupl. }
    iIntros "/=" ([e3 σ3] [e3' σ3'] HR').
    iMod ("Hwp" with "[//]") as "Hwp".
    clear.
    iIntros "!> !> !>".
    iApply (wp_adequacy_spec_coupl with "Hwp").
    iIntros (σ4 e4' σ4') ">(Hσ & Hs & Hwp)".
    iApply ("IH" with "Hσ Hs Hwp").
  Qed.

End adequacy.

Theorem wp_refRcoupl Σ `{clutchGpreS Σ} (e e' : expr) (σ σ' : state) n φ :
  (∀ `{clutchGS Σ}, ⊢ ⤇ e' -∗ WP e {{ v, ∃ v', ⤇ Val v' ∗ ⌜φ v v'⌝ }}) →
  exec n (e, σ) ≾ lim_exec (e', σ') : φ.
Proof.
  intros Hwp.
  eapply pure_soundness, (step_fupdN_soundness_no_lc _ n 0).
  iIntros (Hinv) "_".
  iMod (ghost_map_alloc σ.(heap)) as "[%γH [Hh _]]".
  iMod (ghost_map_alloc σ.(tapes)) as "[%γT [Ht _]]".
  iMod spec_ra_init as (HspecGS) "(Hs & Hj & ?)".
  set (HclutchGS := HeapG Σ _ _ _ γH γT HspecGS).
  pose proof wp_refRcoupl_step_fupdN as h. iApply h.
  iFrame "Hh Ht Hs". by iApply (Hwp with "[Hj]").
  Unshelve. apply _.
Qed.

Corollary wp_refRcoupl_mass Σ `{clutchGpreS Σ} (e e' : expr) (σ σ' : state) φ :
  (∀ `{clutchGS Σ}, ⊢ ⤇ e' -∗ WP e {{ v, ∃ v', ⤇ Val v' ∗ ⌜φ v v'⌝ }}) →
  SeriesC (lim_exec (e, σ)) <= SeriesC (lim_exec (e', σ')).
Proof.
  intros Hwp.
  apply: lim_exec_leq_mass => n.
  eapply refRcoupl_mass_eq.
  by eapply wp_refRcoupl.
Qed.