Library zoo_std.inf_array

Require Import Stdlib.Logic.FunctionalExtensionality.

Require Import zoo.prelude.
Require Import zoo.common.countable.
Require Import zoo.common.function.
Require Import zoo.iris.base_logic.lib.twins.
Require Import zoo.base.
Require Export zoo_std.inf_array__code.
Require Import zoo_std.inf_array__types.
Require Import zoo.options.

Implicit Type b : bool.
Implicit Type l : location.
Implicit Type pid : prophet_id.
Implicit Type v v_resolve t fn : val.
Implicit Type us : list val.
Implicit Type vs : nat val.

Class InfArrayG Σ `{zoo۰G : !ZooG Σ} :=
  { #[local] inf_array۰G۰mutex۰G :: MutexG Σ
  ; #[local] inf_array۰G۰model۰G :: TwinsG Σ (nat -d> val_O)
  }.

Definition inf_array۰Σ :=
  #[mutex۰Σ
  ; twins۰Σ (nat -d> val_O)
  ].
#[global] Instance subGinf_array۰Σ Σ `{zoo۰G : !ZooG Σ} :
  subG inf_array۰Σ Σ
  InfArrayG Σ .

Section inf_array۰G.
  Context `{inf_array۰G : InfArrayG Σ}.

  Record metadata :=
    { metadata۰default : val
    ; metadata۰model : gname
    }.
  Implicit Type γ : metadata.

  #[local] Instance metadataeq_dec : EqDecision metadata :=
    ltac:(solve_decision).
  #[local] Instance metadatacountable :
    Countable metadata.

  #[local] Definition model₁' γ_model vs :=
    twins۰twin₁ γ_model (DfracOwn 1) vs.
  #[local] Definition model₁ γ vs :=
    model₁' γ.(metadata۰model) vs.
  #[local] Definition model₂' γ_model vs :=
    twins۰twin₂ γ_model vs.
  #[local] Definition model₂ γ vs :=
    model₂' γ.(metadata۰model) vs.

  #[local] Definition inv₂ l γ us : iProp Σ :=
     data vs,
    l.[data] data
    array۰model data (DfracOwn 1) us
    model₂ γ vs
    vs = λ i, if decide (i < length us) then us !!! i else γ.(metadata۰default).
  #[local] Instance : CustomIpat "inv₂" :=
    " ( %data & %vs & Hl_data & Hdata & Hmodel₂ & %Hvs ) ".
  #[local] Definition inv₁ l γ : iProp Σ :=
     us,
    inv₂ l γ us.
  #[local] Instance : CustomIpat "inv₁" :=
    " ( %us{} & {{lazy}Hinv;(:inv₂)} ) ".
  Definition inf_array۰inv t : iProp Σ :=
     l γ mtx,
    t = #l
    l γ
    l.[default] γ.(metadata۰default)
    l.[mutex] mtx
    mutex۰inv mtx (inv₁ l γ).
  #[local] Instance : CustomIpat "inv" :=
    " ( %l & %γ & %mtx & -> & #Hmeta & #Hl_mtx & #Hl_default & #Hmtx_inv ) ".

  Definition inf_array۰model t vs : iProp Σ :=
     l γ,
    t = #l
    l γ
    model₁ γ vs.
  #[local] Instance : CustomIpat "model" :=
    " ( %l_ & %γ_ & %Heq & #Hmeta_ & Hmodel₁ ) ".
  Definition inf_array۰model' t vs vs :=
    inf_array۰model t (
      λ i,
        if decide (i < length vs) then vs !!! i else vs (i - length vs)
    ).

  #[global] Instance inf_array۰invpersistent t :
    Persistent (inf_array۰inv t).

  #[global] Instance inf_array۰modelne t n :
    Proper (pointwise_relation nat (=) ==> (≡{n}≡)) (inf_array۰model t).
  #[global] Instance inf_array۰modelproper t :
    Proper (pointwise_relation nat (=) ==> (≡)) (inf_array۰model t).

  #[global] Instance inf_array۰modeltimeless t vs :
    Timeless (inf_array۰model t vs).

  #[global] Instance inf_array۰model'ne t n :
    Proper ((=) ==> pointwise_relation nat (=) ==> (≡{n}≡)) (inf_array۰model' t).
  #[global] Instance inf_array۰model'proper t :
    Proper ((=) ==> pointwise_relation nat (=) ==> (≡)) (inf_array۰model' t).

  #[global] Instance inf_array۰model'timeless t vs vs :
    Timeless (inf_array۰model' t vs vs).

  #[local] Lemma modelalloc default :
     |==>
       γ_model,
      model₁' γ_model (λ _, default)
      model₂' γ_model (λ _, default).
  #[local] Lemma modelagree γ vs1 vs2 :
    model₁ γ vs1 -∗
    model₂ γ vs2 -∗
    vs1 = vs2.
  #[local] Lemma modelupdate {γ vs1 vs2} vs :
    model₁ γ vs1 -∗
    model₂ γ vs2 ==∗
      model₁ γ vs
      model₂ γ vs.

  Lemma inf_array۰modeltomodel' {t vs} vs :
    ( i v, vs !! i = Some v vs i = v)
    inf_array۰model t vs
    inf_array۰model' t vs (λ i, vs (length vs + i)).
  Lemma inf_array۰modeltomodel'replicate {t vs} n v :
    ( i, i < n vs i = v)
    inf_array۰model t vs
    inf_array۰model' t (replicate n v) (λ i, vs (n + i)).
  Lemma inf_array۰modeltomodel'constant {t v} n :
    inf_array۰model t (λ _, v)
    inf_array۰model' t (replicate n v) (λ _, v).

  Lemma inf_array۰model'shift t vs v vs :
    inf_array۰model' t (vs ++ [v]) vs ⊣⊢
    inf_array۰model' t vs (v .: vs).
  Lemma inf_array۰model'shiftr t vs v vs :
    inf_array۰model' t (vs ++ [v]) vs
    inf_array۰model' t vs (v .: vs).
  Lemma inf_array۰model'shiftl t vs vs v vsᵣ' :
    vs ≡ᶠ v .: vsᵣ'
    inf_array۰model' t vs vs
    inf_array۰model' t (vs ++ [v]) vsᵣ'.
  Lemma inf_array۰model'shiftl' t vs vs :
    inf_array۰model' t vs vs
    inf_array۰model' t (vs ++ [vs 0]) (vs S).

  Lemma inf_array٠createspec default :
    {{{
      True
    }}}
      inf_array٠create default
    {{{
      t
    , RET t;
      inf_array۰inv t
      inf_array۰model t (λ _, default)
    }}}.

  #[local] Lemma inf_array٠next_capacityspec n :
    (0 n)%Z
    {{{
      True
    }}}
      inf_array٠next_capacity #n
    {{{
      m
    , RET #m;
      n m%Z
    }}}.
  #[local] Lemma inf_array٠reservespec l γ us n :
    (0 n)%Z
    {{{
      l.[default] γ.(metadata۰default)
      inv₂ l γ us
    }}}
      inf_array٠reserve #l #n
    {{{
      us
    , RET ();
      inv₂ l γ us
      n length us
    }}}.

  Lemma inf_array٠getspec t i :
    (0 i)%Z
    <<<
      inf_array۰inv t
    | ∀∀ vs,
      inf_array۰model t vs
    >>>
      inf_array٠get t #i
    <<<
      inf_array۰model t vs
    | RET vs i;
      £ 1
    >>>.
  Lemma inf_array٠getspec' t i :
    (0 i)%Z
    <<<
      inf_array۰inv t
    | ∀∀ vs vs,
      inf_array۰model' t vs vs
    >>>
      inf_array٠get t #i
    <<<
      inf_array۰model' t vs vs
    | RET
        if decide (i < length vs) then
          vs !!! i
        else
          vs (i - length vs);
      £ 1
    >>>.

  Lemma inf_array٠updatespec Ψ1 Ψ2 t i fn :
    (0 i)%Z
    <<<
      inf_array۰inv t
      ( v, Ψ1 v -∗ WP fn v {{ Ψ2 v }})
    | ∀∀ vs,
      inf_array۰model t vs
       Ψ1 (vs i)
    >>>
      inf_array٠update t #i fn
    <<<
      ∃∃ v,
      inf_array۰model t (<[i := v]> vs)
      Ψ2 (vs i) v
    | RET vs i;
      £ 1
    >>>.

  Lemma inf_array٠xchgspec t i v :
    (0 i)%Z
    <<<
      inf_array۰inv t
    | ∀∀ vs,
      inf_array۰model t vs
    >>>
      inf_array٠xchg t #i v
    <<<
      inf_array۰model t (<[i := v]> vs)
    | RET vs i;
      £ 1
    >>>.

  Lemma inf_array٠xchg_resolvespec t i v pid v_resolve Φ E :
    (0 i)%Z
    inf_array۰inv t -∗
    ( |={,E}=>
       vs,
      inf_array۰model t vs
      ( e,
        PureExec True 1 e () -∗
        to_val e = None -∗
        inf_array۰model t (<[i := v]> vs) -∗
        WP Resolve e #pid v_resolve @ E {{ _,
          |={E,}=>
          Φ (vs i)
        }}
      )
    ) -∗
    WP inf_array٠xchg_resolve t #i v #pid v_resolve {{ Φ }}.

  Lemma inf_array٠setspec t i v :
    (0 i)%Z
    <<<
      inf_array۰inv t
    | ∀∀ vs,
      inf_array۰model t vs
    >>>
      inf_array٠set t #i v
    <<<
      inf_array۰model t (<[i := v]> vs)
    | RET ();
      £ 1
    >>>.
  Lemma inf_array٠setspec' t i v :
    (0 i)%Z
    <<<
      inf_array۰inv t
    | ∀∀ vs vs,
      inf_array۰model' t vs vs
    >>>
      inf_array٠set t #i v
    <<<
      if decide (i < length vs) then
        inf_array۰model' t (<[i := v]> vs) vs
      else
        inf_array۰model' t vs (<[i - length vs := v]> vs)
    | RET ();
      £ 1
    >>>.

  Lemma inf_array٠casspec t i v1 v2 :
    (0 i)%Z
    <<<
      inf_array۰inv t
    | ∀∀ vs,
      inf_array۰model t vs
    >>>
      inf_array٠cas t #i v1 v2
    <<<
      ∃∃ b,
      (if b then (≈) else (≉)) (vs i) v1
      inf_array۰model t (if b then <[i := v2]> vs else vs)
    | RET #b;
      £ 1
    >>>.

  Lemma inf_array٠cas_resolvespec t i v1 v2 pid v_resolve Φ E :
    (0 i)%Z
    inf_array۰inv t -∗
    ( |={,E}=>
       vs,
      inf_array۰model t vs
      ( e b,
        PureExec True 1 e () -∗
        to_val e = None -∗
        (if b then (≈) else (≉)) (vs i) v1 -∗
        inf_array۰model t (if b then <[i := v2]> vs else vs) -∗
        WP Resolve e #pid v_resolve @ E {{ _,
          |={E,}=>
          Φ #b
        }}
      )
    ) -∗
    WP inf_array٠cas_resolve t #i v1 v2 #pid v_resolve {{ Φ }}.

  Lemma inf_array٠faaspec t i (incr : Z) :
    (0 i)%Z
    <<<
      inf_array۰inv t
    | ∀∀ vs (n : Z),
      vs i = #n
      inf_array۰model t vs
    >>>
      inf_array٠faa t #i #incr
    <<<
      inf_array۰model t (<[i := #(n + incr)]> vs)
    | RET vs i;
      £ 1
    >>>.
End inf_array۰G.

Require zoo_std.inf_array__opaque.

#[global] Opaque inf_array۰inv.
#[global] Opaque inf_array۰model.
#[global] Opaque inf_array۰model'.