Library zoo_std.array

From Stdlib Require Import
  ZifyNat.

From zoo Require Import
  prelude.
From zoo.common Require Import
  list
  math.
From zoo.iris.bi Require Import
  big_op.
From zoo.language Require Import
  notations.
From zoo.diaframe Require Import
  diaframe.
From zoo_std Require Export
  base
  array__code.
From zoo_std Require Import
  for_
  assume
  chunk.
From zoo Require Import
  options.

Implicit Types b : bool.
Implicit Types i j k n : nat.
Implicit Types l : location.
Implicit Types v t fn acc : val.
Implicit Types vs vs_left vs_right ws : list val.

Definition array٠unsafe_xchg : val :=
  fun: "t" "i" "v"
    Xchg ("t", "i") "v".

Definition array٠unsafe_cas : val :=
  fun: "t" "i" "v1" "v2"
    CAS ("t", "i") "v1" "v2".

Definition array٠unsafe_faa : val :=
  fun: "t" "i" "incr"
    FAA ("t", "i") "incr".

Section zoo_G.
  Context `{zoo_G : !ZooG Σ}.

  Section array_inv.
    Definition array_inv t (sz : nat) : iProp Σ :=
       l,
      t = #l
      l ↦ₕ Header 0 sz.

    #[global] Instance array_inv_timeless t sz :
      Timeless (array_inv t sz).

    #[global] Instance array_inv_persistent t sz :
      Persistent (array_inv t sz).

    Lemma array_inv_agree t sz1 sz2 :
      array_inv t sz1 -∗
      array_inv t sz2 -∗
      sz1 = sz2.
  End array_inv.

  Section array_slice.
    Definition array_slice t i dq vs : iProp Σ :=
       l,
      t = #l
      chunk_model (l +ₗ i) dq vs.

    #[global] Instance array_slice_timeless t i dq vs :
      Timeless (array_slice t i dq vs).

    #[global] Instance array_slice_persistent t i vs :
      Persistent (array_slice t i DfracDiscarded vs).

    #[global] Instance array_slice_fractional t i vs :
      Fractional (λ q, array_slice t i (DfracOwn q) vs).
    #[global] Instance array_slice_as_fractional t i q vs :
      AsFractional (array_slice t i (DfracOwn q) vs) (λ q, array_slice t i (DfracOwn q) vs) q.

    Lemma array_slice_valid t i dq vs :
      0 < length vs
      array_slice t i dq vs
       dq.
    Lemma array_slice_combine t i dq1 vs1 dq2 vs2 :
      length vs1 = length vs2
      array_slice t i dq1 vs1 -∗
      array_slice t i dq2 vs2 -∗
        vs1 = vs2
        array_slice t i (dq1 dq2) vs1.
    Lemma array_slice_valid_2 t i dq1 vs1 dq2 vs2 :
      0 < length vs1
      length vs1 = length vs2
      array_slice t i dq1 vs1 -∗
      array_slice t i dq2 vs2 -∗
         (dq1 dq2)
        vs1 = vs2.
    Lemma array_slice_agree t i dq1 vs1 dq2 vs2 :
      length vs1 = length vs2
      array_slice t i dq1 vs1 -∗
      array_slice t i dq2 vs2 -∗
      vs1 = vs2.
    Lemma array_slice_dfrac_ne t1 i1 dq1 vs1 t2 i2 dq2 vs2 :
      0 < length vs1
      length vs1 = length vs2
      ¬ (dq1 dq2)
      array_slice t1 i1 dq1 vs1 -∗
      array_slice t2 i2 dq2 vs2 -∗
      t1 t2 i1 i2.
    Lemma array_slice_ne t1 i1 vs1 t2 i2 dq2 vs2 :
      0 < length vs1
      length vs1 = length vs2
      array_slice t1 i1 (DfracOwn 1) vs1 -∗
      array_slice t2 i2 dq2 vs2 -∗
      t1 t2 i1 i2.
    Lemma array_slice_exclusive t i vs1 dq2 vs2 :
      0 < length vs1
      length vs1 = length vs2
      array_slice t i (DfracOwn 1) vs1 -∗
      array_slice t i dq2 vs2 -∗
      False.
    Lemma array_slice_persist t i dq vs :
      array_slice t i dq vs |==>
      array_slice t i DfracDiscarded vs.

    Lemma array_slice_nil {t i1 dq1 vs1} i2 dq2 :
      array_slice t i1 dq1 vs1
      array_slice t i2 dq2 [].

    Lemma array_slice_app t i dq vs1 vs2 :
      array_slice t i dq vs1
      array_slice t (i + length vs1) dq vs2 ⊣⊢
      array_slice t i dq (vs1 ++ vs2).
    Lemma array_slice_app_1 t i dq vs1 vs2 :
      array_slice t i dq vs1 -∗
      array_slice t (i + length vs1) dq vs2 -∗
      array_slice t i dq (vs1 ++ vs2).
    Lemma array_slice_app_1' {t dq i1 vs1} i2 vs2 :
      i2 = i1 + length vs1
      array_slice t i1 dq vs1 -∗
      array_slice t i2 dq vs2 -∗
      array_slice t i1 dq (vs1 ++ vs2).
    Lemma array_slice_app_2 {t i dq vs} vs1 vs2 :
      vs = vs1 ++ vs2
      array_slice t i dq vs
        array_slice t i dq vs1
        array_slice t (i + length vs1) dq vs2.

    Lemma array_slice_app3 {t i dq} vs1 vs2 vs3 :
      array_slice t i dq vs1
      array_slice t (i + length vs1) dq vs2
      array_slice t (i + length vs1 + length vs2) dq vs3 ⊣⊢
      array_slice t i dq (vs1 ++ vs2 ++ vs3).
    Lemma array_slice_app3_1 t dq i1 vs1 i2 vs2 i3 vs3 :
      i2 = i1 + length vs1
      i3 = i1 + length vs1 + length vs2
      array_slice t i1 dq vs1 -∗
      array_slice t i2 dq vs2 -∗
      array_slice t i3 dq vs3 -∗
      array_slice t i1 dq (vs1 ++ vs2 ++ vs3).
    Lemma array_slice_app3_2 {t i dq vs} vs1 vs2 vs3 :
      vs = vs1 ++ vs2 ++ vs3
      array_slice t i dq vs
        array_slice t i dq vs1
        array_slice t (i + length vs1) dq vs2
        array_slice t (i + length vs1 + length vs2) dq vs3.

    Lemma array_slice_cons t i dq v vs :
      array_slice t i dq (v :: vs) ⊣⊢
        array_slice t i dq [v]
        array_slice t (S i) dq vs.
    Lemma array_slice_cons_1 t i dq v vs :
      array_slice t i dq (v :: vs)
        array_slice t i dq [v]
        array_slice t (S i) dq vs.
    Lemma array_slice_cons_2 t i dq v vs :
      array_slice t i dq [v] -∗
      array_slice t (S i) dq vs -∗
      array_slice t i dq (v :: vs).
    Lemma array_slice_cons_2' t i1 dq v i2 vs :
      i2 = S i1
      array_slice t i1 dq [v] -∗
      array_slice t i2 dq vs -∗
      array_slice t i1 dq (v :: vs).

    Lemma array_slice_atomize t i dq vs :
      array_slice t i dq vs
      [∗ list] j v vs,
        array_slice t (i + j) dq [v].

    Lemma array_slice_update {t i dq vs} j v :
      vs !! j = Some v
      array_slice t i dq vs
        array_slice t (i + j) dq [v]
        ( w,
          array_slice t (i + j) dq [w] -∗
          array_slice t i dq (<[j := w]> vs)
        ).
    Lemma array_slice_lookup_acc {t i dq vs} j v :
      vs !! j = Some v
      array_slice t i dq vs
        array_slice t (i + j) dq [v]
        ( array_slice t (i + j) dq [v] -∗
          array_slice t i dq vs
        ).
    Lemma array_slice_lookup {t i dq vs} j v :
      vs !! j = Some v
      array_slice t i dq vs
      array_slice t (i + j) dq [v].
  End array_slice.

  Section array_model.
    Definition array_model t dq vs : iProp Σ :=
       l,
      t = #l
      l ↦ₕ Header 0 (length vs)
      chunk_model l dq vs.

    Lemma array_model_to_inv t dq vs :
      array_model t dq vs
      array_inv t (length vs).
    Lemma array_slice_to_model t sz dq vs :
      sz = length vs
      array_inv t sz -∗
      array_slice t 0 dq vs -∗
      array_model t dq vs.
    Lemma array_model_to_slice t dq vs :
      array_model t dq vs ⊣⊢
        array_inv t (length vs)
        array_slice t 0 dq vs.
    Lemma array_model_to_slice' t dq vs :
      array_model t dq vs
        array_slice t 0 dq vs
         (
           vs',
          length vs' = length vs -∗
          array_slice t 0 dq vs' -∗
          array_model t dq vs'
        ).

    #[global] Instance array_model_timeless t dq vs :
      Timeless (array_model t dq vs).

    #[global] Instance array_model_persistent t vs :
      Persistent (array_model t DfracDiscarded vs).

    #[global] Instance array_model_fractional t vs :
      Fractional (λ q, array_model t (DfracOwn q) vs).
    #[global] Instance array_model_as_fractional t q vs :
      AsFractional (array_model t (DfracOwn q) vs) (λ q, array_model t (DfracOwn q) vs) q.

    Lemma array_inv_model_agree t sz dq vs :
      array_inv t sz -∗
      array_model t dq vs -∗
      length vs = sz.

    Lemma array_model_valid t dq vs :
      0 < length vs
      array_model t dq vs
       dq.
    Lemma array_model_combine t dq1 vs1 dq2 vs2 :
      array_model t dq1 vs1 -∗
      array_model t dq2 vs2 -∗
        vs1 = vs2
        array_model t (dq1 dq2) vs1.
    Lemma array_model_valid_2 t dq1 vs1 dq2 vs2 :
      0 < length vs1
      array_model t dq1 vs1 -∗
      array_model t dq2 vs2 -∗
         (dq1 dq2)
        vs1 = vs2.
    Lemma array_model_agree t dq1 vs1 dq2 vs2 :
      array_model t dq1 vs1 -∗
      array_model t dq2 vs2 -∗
      vs1 = vs2.
    Lemma array_model_dfrac_ne t1 dq1 vs1 t2 dq2 vs2 :
      0 < length vs1
      ¬ (dq1 dq2)
      array_model t1 dq1 vs1 -∗
      array_model t2 dq2 vs2 -∗
      t1 t2.
    Lemma array_model_ne t1 vs1 t2 dq2 vs2 :
      0 < length vs1
      array_model t1 (DfracOwn 1) vs1 -∗
      array_model t2 dq2 vs2 -∗
      t1 t2.
    Lemma array_model_exclusive t vs1 dq2 vs2 :
      0 < length vs1
      array_model t (DfracOwn 1) vs1 -∗
      array_model t dq2 vs2 -∗
      False.
    Lemma array_model_persist t dq vs :
      array_model t dq vs |==>
      array_model t DfracDiscarded vs.

    Lemma array_model_atomize t dq vs :
      array_model t dq vs
        array_inv t (length vs)
        [∗ list] i v vs,
          array_slice t i dq [v].

    #[local] Typeclasses Opaque array_slice.
    Lemma array_model_update {t dq vs} i v :
      vs !! i = Some v
      array_model t dq vs
        array_inv t (length vs)
        array_slice t i dq [v]
        ( w,
          array_slice t i dq [w] -∗
          array_model t dq (<[i := w]> vs)
        ).
    Lemma array_model_lookup_acc {t dq vs} i v :
      vs !! i = Some v
      array_model t dq vs
        array_slice t i dq [v]
        ( array_slice t i dq [v] -∗
          array_model t dq vs
        ).
    Lemma array_model_lookup {t dq vs} i v :
      vs !! i = Some v
      array_model t dq vs
      array_slice t i dq [v].
  End array_model.

  Section array_cslice.
    Definition array_cslice t (sz : nat) i dq vs : iProp Σ :=
       l,
      t = #l
      l ↦ₕ Header 0 sz
      chunk_cslice l sz i dq vs.

    Lemma array_cslice_to_inv t sz i dq vs :
      array_cslice t sz i dq vs
      array_inv t sz.
    Lemma array_model_to_cslice t dq vs :
      array_model t dq vs
      array_cslice t (length vs) 0 dq vs.
    Lemma array_cslice_to_slice t sz i dq vs :
      0 < sz
      length vs sz
      array_cslice t sz i dq vs ⊣⊢
        array_inv t sz
        array_slice t (i `mod` sz) dq (take (sz - i `mod` sz) vs)
        array_slice t 0 dq (drop (sz - i `mod` sz) vs).
    Lemma array_cslice_to_slice' t sz i dq vs :
      0 < sz
      length vs sz
      array_cslice t sz i dq vs
        array_slice t (i `mod` sz) dq (take (sz - i `mod` sz) vs)
        array_slice t 0 dq (drop (sz - i `mod` sz) vs).
    Lemma array_cslice_to_model t sz i dq vs :
      0 < sz
      length vs = sz
      array_cslice t sz i dq vs ⊣⊢
      array_model t dq (rotation (sz - i `mod` sz) vs).
    Lemma array_cslice_to_slice_cell t sz i dq v :
      array_cslice t sz i dq [v] ⊣⊢
        array_inv t sz
        array_slice t (i `mod` sz) dq [v].
    Lemma array_cslice_to_slice_cell' t sz i dq v :
      array_cslice t sz i dq [v]
      array_slice t (i `mod` sz) dq [v].
    Lemma array_slice_to_cslice_cell t sz i dq v :
      array_inv t sz -∗
      array_slice t (i `mod` sz) dq [v] -∗
      array_cslice t sz i dq [v].

    #[global] Instance array_cslice_timeless t sz i dq vs :
      Timeless (array_cslice t sz i dq vs).

    #[global] Instance array_cslice_persistent t sz i vs :
      Persistent (array_cslice t sz i DfracDiscarded vs).

    #[global] Instance array_cslice_fractional t sz i vs :
      Fractional (λ q, array_cslice t sz i (DfracOwn q) vs).
    #[global] Instance array_cslice_as_fractionak t sz i q vs :
      AsFractional (array_cslice t sz i (DfracOwn q) vs) (λ q, array_cslice t sz i (DfracOwn q) vs) q.

    Lemma array_inv_cslice_agree t sz1 sz2 i dq vs :
      array_inv t sz1 -∗
      array_cslice t sz2 i dq vs -∗
      sz1 = sz2.

    Lemma array_cslice_nil t sz i dq :
      array_inv t sz
      array_cslice t sz i dq [].

    Lemma array_cslice_app t sz i dq vs1 vs2 :
      array_cslice t sz i dq vs1
      array_cslice t sz (i + length vs1) dq vs2 ⊣⊢
      array_cslice t sz i dq (vs1 ++ vs2).
    Lemma array_cslice_app_1 t sz dq i1 vs1 i2 vs2 :
      i2 = i1 + length vs1
      array_cslice t sz i1 dq vs1 -∗
      array_cslice t sz i2 dq vs2 -∗
      array_cslice t sz i1 dq (vs1 ++ vs2).
    Lemma array_cslice_app_2 {t sz i dq vs} vs1 vs2 :
      vs = vs1 ++ vs2
      array_cslice t sz i dq vs
        array_cslice t sz i dq vs1
        array_cslice t sz (i + length vs1) dq vs2.

    Lemma array_cslice_app3 t sz i dq vs1 vs2 vs3 :
      array_cslice t sz i dq vs1
      array_cslice t sz (i + length vs1) dq vs2
      array_cslice t sz (i + length vs1 + length vs2) dq vs3 ⊣⊢
      array_cslice t sz i dq (vs1 ++ vs2 ++ vs3).
    Lemma array_cslice_app3_1 t sz dq i1 vs1 i2 vs2 i3 vs3 :
      i2 = i1 + length vs1
      i3 = i1 + length vs1 + length vs2
      array_cslice t sz i1 dq vs1 -∗
      array_cslice t sz i2 dq vs2 -∗
      array_cslice t sz i3 dq vs3 -∗
      array_cslice t sz i1 dq (vs1 ++ vs2 ++ vs3).
    Lemma array_cslice_app3_2 {t sz i dq vs} vs1 vs2 vs3 :
      vs = vs1 ++ vs2 ++ vs3
      array_cslice t sz i dq vs
        array_cslice t sz i dq vs1
        array_cslice t sz (i + length vs1) dq vs2
        array_cslice t sz (i + length vs1 + length vs2) dq vs3.

    Lemma array_cslice_cons t sz i dq v vs :
      array_cslice t sz i dq (v :: vs) ⊣⊢
        array_cslice t sz i dq [v]
        array_cslice t sz (S i) dq vs.
    Lemma array_cslice_cons_1 t sz i dq v vs :
      array_cslice t sz i dq (v :: vs)
        array_cslice t sz i dq [v]
        array_cslice t sz (S i) dq vs.
    Lemma array_cslice_cons_2 t sz i dq v vs :
      array_cslice t sz i dq [v] -∗
      array_cslice t sz (S i) dq vs -∗
      array_cslice t sz i dq (v :: vs).
    Lemma array_cslice_cons_2' t sz i1 dq v i2 vs :
      i2 = S i1
      array_cslice t sz i1 dq [v] -∗
      array_cslice t sz i2 dq vs -∗
      array_cslice t sz i1 dq (v :: vs).

    Lemma array_cslice_atomize sz t i dq vs :
      array_cslice t sz i dq vs
      [∗ list] j v vs,
        array_cslice t sz (i + j) dq [v].

    Lemma array_cslice_update {t sz i dq vs} j v :
      vs !! j = Some v
      array_cslice t sz i dq vs
        array_cslice t sz (i + j) dq [v]
        ( w,
          array_cslice t sz (i + j) dq [w] -∗
          array_cslice t sz i dq (<[j := w]> vs)
        ).
    Lemma array_cslice_lookup_acc {t sz i dq vs} j v :
      vs !! j = Some v
      array_cslice t sz i dq vs
        array_cslice t sz (i + j) dq [v]
        ( array_cslice t sz (i + j) dq [v] -∗
          array_cslice t sz i dq vs
        ).
    Lemma array_cslice_lookup {t sz i dq vs} j v :
      vs !! j = Some v
      array_cslice t sz i dq vs
      array_cslice t sz (i + j) dq [v].

    Lemma array_cslice_shift t sz i dq vs :
      array_cslice t sz i dq vs ⊣⊢
      array_cslice t sz (i + sz) dq vs.

    Lemma array_cslice_shift_right t sz i dq vs :
      array_cslice t sz i dq vs
      array_cslice t sz (i + sz) dq vs.
    Lemma array_cslice_shift_right' {t sz i1 dq vs} i2 :
      i2 = i1 + sz
      array_cslice t sz i1 dq vs
      array_cslice t sz i2 dq vs.

    Lemma array_cslice_shift_left t sz i dq vs :
      sz i
      array_cslice t sz i dq vs
      array_cslice t sz (i - sz) dq vs.
    Lemma array_cslice_shift_left' {t sz i1 dq vs} i2 :
      sz i1
      i2 = i1 - sz
      array_cslice t sz i1 dq vs
      array_cslice t sz i2 dq vs.

    Lemma array_cslice_rotation_right {t sz i dq vs} n :
      0 < sz
      length vs = sz
      array_cslice t sz i dq vs ⊣⊢
      array_cslice t sz (i + n) dq (rotation (n `mod` sz) vs).
    Lemma array_cslice_rotation_right_1 {t sz i dq vs} n :
      0 < sz
      length vs = sz
      array_cslice t sz i dq vs
      array_cslice t sz (i + n) dq (rotation (n `mod` sz) vs).
    Lemma array_cslice_rotation_right_0 {t sz dq vs} i :
      0 < sz
      length vs = sz
      array_cslice t sz 0 dq vs ⊣⊢
      array_cslice t sz i dq (rotation (i `mod` sz) vs).

    Lemma array_cslice_rotation_right' {t sz i1 dq vs} i2 n :
      0 < sz
      length vs = sz
      i2 = i1 + n
      array_cslice t sz i1 dq vs ⊣⊢
      array_cslice t sz i2 dq (rotation (n `mod` sz) vs).
    Lemma array_cslice_rotation_right_1' {t sz i1 dq vs} i2 n :
      0 < sz
      length vs = sz
      i2 = i1 + n
      array_cslice t sz i1 dq vs
      array_cslice t sz i2 dq (rotation (n `mod` sz) vs).

    Lemma array_cslice_rotation_right_small {t sz i dq vs} n :
      0 < sz
      length vs = sz
      n < sz
      array_cslice t sz i dq vs ⊣⊢
      array_cslice t sz (i + n) dq (rotation n vs).
    Lemma array_cslice_rotation_right_small_1 {t sz i dq vs} n :
      0 < sz
      length vs = sz
      n < sz
      array_cslice t sz i dq vs
      array_cslice t sz (i + n) dq (rotation n vs).

    Lemma array_cslice_rotation_right_small' {t sz i1 dq vs} i2 n :
      0 < sz
      length vs = sz
      i2 = i1 + n
      n < sz
      array_cslice t sz i1 dq vs ⊣⊢
      array_cslice t sz i2 dq (rotation n vs).
    Lemma array_cslice_rotation_right_small_1' {t sz i1 dq vs} i2 n :
      0 < sz
      length vs = sz
      i2 = i1 + n
      n < sz
      array_cslice t sz i1 dq vs
      array_cslice t sz i2 dq (rotation n vs).

    Lemma array_cslice_rotation_left t sz i n dq vs :
      0 < sz
      length vs = sz
      array_cslice t sz (i + n) dq vs ⊣⊢
      array_cslice t sz i dq (rotation (sz - n `mod` sz) vs).
    Lemma array_cslice_rotation_left_1 t sz i n dq vs :
      0 < sz
      length vs = sz
      array_cslice t sz (i + n) dq vs
      array_cslice t sz i dq (rotation (sz - n `mod` sz) vs).
    Lemma array_cslice_rotation_left_0 t sz i dq vs :
      0 < sz
      length vs = sz
      array_cslice t sz i dq vs ⊣⊢
      array_cslice t sz 0 dq (rotation (sz - i `mod` sz) vs).

    Lemma array_cslice_rotation_left' {t sz i1 dq vs} i2 n :
      0 < sz
      length vs = sz
      i1 = i2 + n
      array_cslice t sz i1 dq vs ⊣⊢
      array_cslice t sz i2 dq (rotation (sz - n `mod` sz) vs).
    Lemma array_cslice_rotation_left_1' {t sz i1 dq vs} i2 n :
      0 < sz
      length vs = sz
      i1 = i2 + n
      array_cslice t sz i1 dq vs
      array_cslice t sz i2 dq (rotation (sz - n `mod` sz) vs).

    Lemma array_cslice_rotation_left_small t sz i n dq vs :
      0 < sz
      length vs = sz
      n < sz
      array_cslice t sz (i + n) dq vs ⊣⊢
      array_cslice t sz i dq (rotation (sz - n) vs).
    Lemma array_cslice_rotation_left_small_1 t sz i n dq vs :
      0 < sz
      length vs = sz
      n < sz
      array_cslice t sz (i + n) dq vs
      array_cslice t sz i dq (rotation (sz - n) vs).

    Lemma array_cslice_rotation_left_small' {t sz i1 dq vs} i2 n :
      0 < sz
      length vs = sz
      i1 = i2 + n
      n < sz
      array_cslice t sz i1 dq vs ⊣⊢
      array_cslice t sz i2 dq (rotation (sz - n) vs).
    Lemma array_cslice_rotation_left_small_1' {t sz i1 dq vs} i2 n :
      0 < sz
      length vs = sz
      i1 = i2 + n
      n < sz
      array_cslice t sz i1 dq vs
      array_cslice t sz i2 dq (rotation (sz - n) vs).

    Lemma array_cslice_rebase {t sz i1 dq vs1} i2 :
      0 < sz
      length vs1 = sz
      array_cslice t sz i1 dq vs1
         vs2 n,
        vs2 = rotation n vs1
        array_cslice t sz i2 dq vs2
        ( array_cslice t sz i2 dq vs2 -∗
          array_cslice t sz i1 dq vs1
        ).

    Lemma array_cslice_valid t sz i dq vs :
      0 < length vs
      array_cslice t sz i dq vs
       dq.
    Lemma array_cslice_combine t sz i dq1 vs1 dq2 vs2 :
      length vs1 = length vs2
      array_cslice t sz i dq1 vs1 -∗
      array_cslice t sz i dq2 vs2 -∗
        vs1 = vs2
        array_cslice t sz i (dq1 dq2) vs1.
    Lemma array_cslice_valid_2 t sz i dq1 vs1 dq2 vs2 :
      0 < length vs1
      length vs1 = length vs2
      array_cslice t sz i dq1 vs1 -∗
      array_cslice t sz i dq2 vs2 -∗
         (dq1 dq2)
        vs1 = vs2.
    Lemma array_cslice_agree t sz i dq1 vs1 dq2 vs2 :
      length vs1 = length vs2
      array_cslice t sz i dq1 vs1 -∗
      array_cslice t sz i dq2 vs2 -∗
      vs1 = vs2.
    Lemma array_cslice_dfrac_ne t sz i1 dq1 vs1 i2 dq2 vs2 :
      0 < length vs1
      length vs1 = length vs2
      ¬ (dq1 dq2)
      array_cslice t sz i1 dq1 vs1 -∗
      array_cslice t sz i2 dq2 vs2 -∗
      i1 i2.
    Lemma array_cslice_ne t sz i1 vs1 i2 dq2 vs2 :
      0 < length vs1
      length vs1 = length vs2
      array_cslice t sz i1 (DfracOwn 1) vs1 -∗
      array_cslice t sz i2 dq2 vs2 -∗
      i1 i2.
    Lemma array_cslice_exclusive t sz i vs1 dq2 vs2 :
      0 < length vs1
      length vs1 = length vs2
      array_cslice t sz i (DfracOwn 1) vs1 -∗
      array_cslice t sz i dq2 vs2 -∗
      False.
    Lemma array_cslice_persist t sz i dq vs :
      array_cslice t sz i dq vs |==>
      array_cslice t sz i DfracDiscarded vs.

    Lemma array_cslice_length t sz i vs :
      0 < sz
      array_cslice t sz i (DfracOwn 1) vs
      length vs sz.
  End array_cslice.

  #[local] Typeclasses Opaque
    array_inv
    array_slice
    array_model
    array_cslice.

  Notation au_load t i Φ := (
    AU <{
      ∃∃ dq v,
      array_slice t i dq [v]
    }> @ , <{
      array_slice t i dq [v],
    COMM
      Φ v
    }>
  )%I.
  Notation au_store t i v P := (
    AU <{
      ∃∃ w,
      array_slice t i (DfracOwn 1) [w]
    }> @ , <{
      array_slice t i (DfracOwn 1) [v],
    COMM
      P
    }>
  )%I.

  Lemma array٠unsafe_alloc𑁒spec sz :
    (0 sz)%Z
    {{{
      True
    }}}
      array٠unsafe_alloc #sz
    {{{
      t
    , RET t;
      array_model t (DfracOwn 1) (replicate sz ()%V)
    }}}.

  Lemma array٠alloc𑁒spec sz :
    {{{
      True
    }}}
      array٠alloc #sz
    {{{
      t
    , RET t;
      0 sz%Z
      array_model t (DfracOwn 1) (replicate sz ()%V)
    }}}.

  Lemma array٠create𑁒spec :
    {{{
      True
    }}}
      array٠create ()
    {{{
      t
    , RET t;
      array_model t (DfracOwn 1) []
    }}}.

  Lemma array٠size𑁒spec_inv t sz :
    {{{
      array_inv t sz
    }}}
      array٠size t
    {{{
      RET #sz;
      True
    }}}.
  Lemma array٠size𑁒spec_atomic t :
    <<<
      True
    | ∀∀ dq vs,
      array_model t dq vs
    >>>
      array٠size t
    <<<
      array_model t dq vs
    | RET #(length vs);
      £ 1
      array_inv t (length vs)
    >>>.
  Lemma array٠size𑁒spec_atomic_cslice t :
    <<<
      True
    | ∀∀ sz i dq vs,
      array_cslice t sz i dq vs
    >>>
      array٠size t
    <<<
      array_cslice t sz i dq vs
    | RET #sz;
      £ 1
      array_inv t sz
    >>>.
  Lemma array٠size𑁒spec t dq vs :
    {{{
      array_model t dq vs
    }}}
      array٠size t
    {{{
      RET #(length vs);
      array_model t dq vs
    }}}.
  Lemma array٠size𑁒spec_cslice t sz i dq vs :
    {{{
      array_cslice t sz i dq vs
    }}}
      array٠size t
    {{{
      RET #sz;
      array_cslice t sz i dq vs
    }}}.

  Lemma array٠unsafe_get𑁒spec_atomic_slice t (j : Z) :
    <<<
      True
    | ∀∀ dq vs i v,
      (i j)%Z
      vs !! (j - i) = Some v
      array_slice t i dq vs
    >>>
      array٠unsafe_get t #j
    <<<
      array_slice t i dq vs
    | RET v;
      £ 1
    >>>.
  Lemma array٠unsafe_get𑁒spec_atomic_cell t (i : Z) :
    <<<
      True
    | ∀∀ i_ dq v,
      i = ⁺i_
      array_slice t i_ dq [v]
    >>>
      array٠unsafe_get t #i
    <<<
      array_slice t i dq [v]
    | RET v;
      £ 1
    >>>.
  Lemma array٠unsafe_get𑁒spec_atomic t (i : Z) :
    (0 i)%Z
    <<<
      True
    | ∀∀ dq vs v,
      vs !! i = Some v
      array_model t dq vs
    >>>
      array٠unsafe_get t #i
    <<<
      array_model t dq vs
    | RET v;
      £ 1
    >>>.
  Lemma array٠unsafe_get𑁒spec_atomic_inv t (sz : nat) (i : Z) :
    (0 i < sz)%Z
    <<<
      array_inv t sz
    | ∀∀ vs,
      array_model t (DfracOwn 1) vs
    >>>
      array٠unsafe_get t #i
    <<<
      ∃∃ v,
      vs !! i = Some v
      array_model t (DfracOwn 1) vs
    | RET v;
      £ 1
    >>>.
  Lemma array٠unsafe_get𑁒spec_slice k t i dq vs (j : Z) v :
    (i j)%Z
    vs !! k = Some v
    k = j - i
    {{{
      array_slice t i dq vs
    }}}
      array٠unsafe_get t #j
    {{{
      RET v;
      array_slice t i dq vs
    }}}.
  Lemma array٠unsafe_get𑁒spec_cell t (i : Z) i_ dq v :
    i = i_
    {{{
      array_slice t i_ dq [v]
    }}}
      array٠unsafe_get t #i
    {{{
      RET v;
      array_slice t i_ dq [v]
    }}}.
  Lemma array٠unsafe_get𑁒spec i_ t (i : Z) dq vs v :
    (0 i)%Z
    vs !! i_ = Some v
    i_ = i
    {{{
      array_model t dq vs
    }}}
      array٠unsafe_get t #i
    {{{
      RET v;
      array_model t dq vs
    }}}.

  Lemma array٠get𑁒spec_atomic_slice t sz (j : Z) :
    <<<
      array_inv t sz
    | ∀∀ dq vs i v,
      0 j < sz%Z -∗
        i j
        vs !! (j - i) = Some v
        array_slice t i dq vs
    >>>
      array٠get t #j
    <<<
      array_slice t i dq vs
    | RET v;
      0 j < sz%Z
      £ 1
    >>>.
  Lemma array٠get𑁒spec_atomic_cell t sz (i : Z) i_ :
    i_ = i
    <<<
      array_inv t sz
    | ∀∀ dq v,
      0 i < sz%Z -∗
      array_slice t i_ dq [v]
    >>>
      array٠get t #i
    <<<
      array_slice t i_ dq [v]
    | RET v;
      0 i < sz%Z
      £ 1
    >>>.
  Lemma array٠get𑁒spec_atomic t sz (i : Z) :
    <<<
      array_inv t sz
    | ∀∀ dq vs v,
      0 i < sz%Z -∗
        vs !! i = Some v
        array_model t dq vs
    >>>
      array٠get t #i
    <<<
      array_model t dq vs
    | RET v;
      0 i < sz%Z
      £ 1
    >>>.
  Lemma array٠get𑁒spec_slice k t sz i dq vs (j : Z) v :
    {{{
      array_inv t sz
      ( 0 j < sz%Z -∗
          i j
          vs !! k = Some v
          k = j - i
          array_slice t i dq vs
      )
    }}}
      array٠get t #j
    {{{
      RET v;
      0 j < sz%Z
      array_slice t i dq vs
    }}}.
  Lemma array٠get𑁒spec_cell t sz (i : Z) i_ dq v :
    i_ = i
    {{{
      array_inv t sz
      ( 0 i < sz%Z -∗
        array_slice t i_ dq [v]
      )
    }}}
      array٠get t #i
    {{{
      RET v;
      0 i < sz%Z
      array_slice t i_ dq [v]
    }}}.
  Lemma array٠get𑁒spec t (i : Z) dq vs v :
    {{{
      array_model t dq vs
      ( 0 i < length vs%Z -∗
        vs !! i = Some v
      )
    }}}
      array٠get t #i
    {{{
      RET v;
      0 i < length vs%Z
      array_model t dq vs
    }}}.

  Lemma array٠unsafe_set𑁒spec_atomic_slice t (j : Z) v :
    <<<
      True
    | ∀∀ vs i,
      i j < i + length vs%Z
      array_slice t i (DfracOwn 1) vs
    >>>
      array٠unsafe_set t #j v
    <<<
      ∃∃ w,
      vs !! (j - i) = Some w
      array_slice t i (DfracOwn 1) (<[j - i := v]> vs)
    | RET ();
      £ 1
    >>>.
  Lemma array٠unsafe_set𑁒spec_atomic_cell t (i : Z) v :
    <<<
      True
    | ∀∀ i_ w,
      i = ⁺i_
      array_slice t i_ (DfracOwn 1) [w]
    >>>
      array٠unsafe_set t #i v
    <<<
      array_slice t i_ (DfracOwn 1) [v]
    | RET ();
      £ 1
    >>>.
  Lemma array٠unsafe_set𑁒spec_atomic t (i : Z) v :
    (0 i)%Z
    <<<
      True
    | ∀∀ vs,
      i < length vs%Z
      array_model t (DfracOwn 1) vs
    >>>
      array٠unsafe_set t #i v
    <<<
      ∃∃ w,
      vs !! i = Some w
      array_model t (DfracOwn 1) (<[i := v]> vs)
    | RET ();
      £ 1
    >>>.
  Lemma array٠unsafe_set𑁒spec_atomic_inv t (sz : nat) (i : Z) v :
    (0 i < sz)%Z
    <<<
      array_inv t sz
    | ∀∀ vs,
      array_model t (DfracOwn 1) vs
    >>>
      array٠unsafe_set t #i v
    <<<
      ∃∃ w,
      vs !! i = Some w
      array_model t (DfracOwn 1) (<[i := v]> vs)
    | RET ();
      £ 1
    >>>.
  Lemma array٠unsafe_set𑁒spec_slice t i vs (j : Z) v :
    (i j < i + length vs)%Z
    {{{
      array_slice t i (DfracOwn 1) vs
    }}}
      array٠unsafe_set t #j v
    {{{
      RET ();
      array_slice t i (DfracOwn 1) (<[j - i := v]> vs)
    }}}.
  Lemma array٠unsafe_set𑁒spec_cell t (i : Z) i_ w v :
    i = ⁺i_
    {{{
      array_slice t i_ (DfracOwn 1) [w]
    }}}
      array٠unsafe_set t #i v
    {{{
      RET ();
      array_slice t i_ (DfracOwn 1) [v]
    }}}.
  Lemma array٠unsafe_set𑁒spec t (i : Z) vs v :
    (0 i < length vs)%Z
    {{{
      array_model t (DfracOwn 1) vs
    }}}
      array٠unsafe_set t #i v
    {{{
      RET ();
      array_model t (DfracOwn 1) (<[i := v]> vs)
    }}}.

  Lemma array٠set𑁒spec_atomic_slice t sz (j : Z) v :
    <<<
      array_inv t sz
    | ∀∀ vs i,
      0 j < sz%Z -∗
        i j < i + length vs
        array_slice t i (DfracOwn 1) vs
    >>>
      array٠set t #j v
    <<<
      array_slice t i (DfracOwn 1) (<[j - i := v]> vs)
    | RET ();
      0 j < sz%Z
      £ 1
    >>>.
  Lemma array٠set𑁒spec_atomic_cell t sz (i : Z) i_ v :
    i_ = i
    <<<
      array_inv t sz
    | ∀∀ w,
      0 i < sz%Z -∗
      array_slice t i_ (DfracOwn 1) [w]
    >>>
      array٠set t #i v
    <<<
      array_slice t i_ (DfracOwn 1) [v]
    | RET ();
      0 i < sz%Z
      £ 1
    >>>.
  Lemma array٠set𑁒spec_atomic t sz (i : Z) v :
    <<<
      array_inv t sz
    | ∀∀ vs,
      0 i < sz%Z -∗
        (i < length vs)%Z
        array_model t (DfracOwn 1) vs
    >>>
      array٠set t #i v
    <<<
      array_model t (DfracOwn 1) (<[i := v]> vs)
    | RET ();
      0 i < sz%Z
      £ 1
    >>>.
  Lemma array٠set𑁒spec_slice t sz i vs (j : Z) v :
    {{{
      array_inv t sz
      ( 0 j < sz%Z -∗
          i j < i + length vs
          array_slice t i (DfracOwn 1) vs
      )
    }}}
      array٠set t #j v
    {{{
      RET ();
      0 j < sz%Z
      array_slice t i (DfracOwn 1) (<[j - i := v]> vs)
    }}}.
  Lemma array٠set𑁒spec_cell t sz (i : Z) i_ w v :
    i_ = i
    {{{
      array_inv t sz
      ( 0 i < sz%Z -∗
        array_slice t i_ (DfracOwn 1) [w]
      )
    }}}
      array٠set t #i v
    {{{
      RET ();
      0 i < sz%Z
      array_slice t i_ (DfracOwn 1) [v]
    }}}.
  Lemma array٠set𑁒spec t (i : Z) vs v :
    {{{
      array_model t (DfracOwn 1) vs
    }}}
      array٠set t #i v
    {{{
      RET ();
      array_model t (DfracOwn 1) (<[i := v]> vs)
    }}}.

  Lemma array٠unsafe_xchg𑁒spec_atomic_slice t (j : Z) v :
    <<<
      True
    | ∀∀ vs i,
      i j < i + length vs%Z
      array_slice t i (DfracOwn 1) vs
    >>>
      array٠unsafe_xchg t #j v
    <<<
      ∃∃ w,
      vs !! (j - i) = Some w
      array_slice t i (DfracOwn 1) (<[j - i := v]> vs)
    | RET w;
      £ 1
    >>>.
  Lemma array٠unsafe_xchg𑁒spec_atomic_cell t (i : Z) v :
    <<<
      True
    | ∀∀ i_ w,
      i = ⁺i_
      array_slice t i_ (DfracOwn 1) [w]
    >>>
      array٠unsafe_xchg t #i v
    <<<
      array_slice t i_ (DfracOwn 1) [v]
    | RET w;
      £ 1
    >>>.
  Lemma array٠unsafe_xchg𑁒spec_atomic t (i : Z) v :
    (0 i)%Z
    <<<
      True
    | ∀∀ vs,
      i < length vs%Z
      array_model t (DfracOwn 1) vs
    >>>
      array٠unsafe_xchg t #i v
    <<<
      ∃∃ w,
      vs !! i = Some w
      array_model t (DfracOwn 1) (<[i := v]> vs)
    | RET w;
      £ 1
    >>>.
  Lemma array٠unsafe_xchg𑁒spec_atomic_inv t (sz : nat) (i : Z) v :
    (0 i < sz)%Z
    <<<
      array_inv t sz
    | ∀∀ vs,
      array_model t (DfracOwn 1) vs
    >>>
      array٠unsafe_xchg t #i v
    <<<
      ∃∃ w,
      vs !! i = Some w
      array_model t (DfracOwn 1) (<[i := v]> vs)
    | RET w;
      £ 1
    >>>.
  Lemma array٠unsafe_xchg𑁒spec_slice t i vs (j : Z) v :
    (i j < i + length vs)%Z
    {{{
      array_slice t i (DfracOwn 1) vs
    }}}
      array٠unsafe_xchg t #j v
    {{{
      w
    , RET w;
      vs !! (j - i) = Some w
      array_slice t i (DfracOwn 1) (<[j - i := v]> vs)
    }}}.
  Lemma array٠unsafe_xchg𑁒spec_cell t (i : Z) i_ w v :
    i = ⁺i_
    {{{
      array_slice t i_ (DfracOwn 1) [w]
    }}}
      array٠unsafe_xchg t #i v
    {{{
      RET w;
      array_slice t i_ (DfracOwn 1) [v]
    }}}.
  Lemma array٠unsafe_xchg𑁒spec t (i : Z) vs v :
    (0 i < length vs)%Z
    {{{
      array_model t (DfracOwn 1) vs
    }}}
      array٠unsafe_xchg t #i v
    {{{
      w
    , RET w;
      vs !! i = Some w
      array_model t (DfracOwn 1) (<[i := v]> vs)
    }}}.

  Lemma array٠unsafe_cas𑁒spec_atomic_slice t (j : Z) v1 v2 :
    <<<
      True
    | ∀∀ vs i,
      i j < i + length vs%Z
      array_slice t i (DfracOwn 1) vs
    >>>
      array٠unsafe_cas t #j v1 v2
    <<<
      ∃∃ b v,
      vs !! (j - i) = Some v
      (if b then (≈) else (≉)) v v1
      array_slice t i (DfracOwn 1) (if b then <[j - i := v2]> vs else vs)
    | RET #b;
      £ 1
    >>>.
  Lemma array٠unsafe_cas𑁒spec_atomic_cell t (i : Z) v1 v2 :
    <<<
      True
    | ∀∀ i_ v,
      i = ⁺i_
      array_slice t i_ (DfracOwn 1) [v]
    >>>
      array٠unsafe_cas t #i v1 v2
    <<<
      ∃∃ b,
      (if b then (≈) else (≉)) v v1
      array_slice t i_ (DfracOwn 1) [if b then v2 else v]
    | RET #b;
      £ 1
    >>>.
  Lemma array٠unsafe_cas𑁒spec_atomic t (i : Z) v1 v2 :
    (0 i)%Z
    <<<
      True
    | ∀∀ vs,
      i < length vs%Z
      array_model t (DfracOwn 1) vs
    >>>
      array٠unsafe_cas t #i v1 v2
    <<<
      ∃∃ b v,
      vs !! i = Some v
      (if b then (≈) else (≉)) v v1
      array_model t (DfracOwn 1) (if b then <[i := v2]> vs else vs)
    | RET #b;
      £ 1
    >>>.
  Lemma array٠unsafe_cas𑁒spec_atomic_inv t (sz : nat) (i : Z) v1 v2 :
    (0 i < sz)%Z
    <<<
      array_inv t sz
    | ∀∀ vs,
      array_model t (DfracOwn 1) vs
    >>>
      array٠unsafe_cas t #i v1 v2
    <<<
      ∃∃ b v,
      vs !! i = Some v
      (if b then (≈) else (≉)) v v1
      array_model t (DfracOwn 1) (if b then <[i := v2]> vs else vs)
    | RET #b;
      £ 1
    >>>.
  Lemma array٠unsafe_cas𑁒spec_slice t i vs (j : Z) v1 v2 :
    (i j < i + length vs)%Z
    {{{
      array_slice t i (DfracOwn 1) vs
    }}}
      array٠unsafe_cas t #j v1 v2
    {{{
      b v
    , RET #b;
      vs !! (j - i) = Some v
      (if b then (≈) else (≉)) v v1
      array_slice t i (DfracOwn 1) (if b then <[j - i := v2]> vs else vs)
    }}}.
  Lemma array٠unsafe_cas𑁒spec_cell t (i : Z) i_ v v1 v2 :
    i = ⁺i_
    {{{
      array_slice t i_ (DfracOwn 1) [v]
    }}}
      array٠unsafe_cas t #i v1 v2
    {{{
      b
    , RET #b;
      (if b then (≈) else (≉)) v v1
      array_slice t i_ (DfracOwn 1) [if b then v2 else v]
    }}}.
  Lemma array٠unsafe_cas𑁒spec t (i : Z) vs v1 v2 :
    (0 i < length vs)%Z
    {{{
      array_model t (DfracOwn 1) vs
    }}}
      array٠unsafe_cas t #i v1 v2
    {{{
      b v
    , RET #b;
      vs !! i = Some v
      (if b then (≈) else (≉)) v v1
      array_model t (DfracOwn 1) (if b then <[i := v2]> vs else vs)
    }}}.

  Lemma array٠unsafe_swap𑁒spec_slice {t i vs} {i1 : Z} k1 {v1} {i2 : Z} k2 v2 :
    (i i1)%Z
    (i i2)%Z
    vs !! k1 = Some v1
    k1 = i1 - i
    vs !! k2 = Some v2
    k2 = i2 - i
    {{{
      array_slice t i (DfracOwn 1) vs
    }}}
      array٠unsafe_swap t #i1 #i2
    {{{
      RET ();
      array_slice t i (DfracOwn 1) (<[k2 := v1]> $ <[k1 := v2]> vs)
    }}}.
  Lemma array٠unsafe_swap𑁒spec_slice_id t i vs (i1 i2 : Z) :
    i1 = i2
    (i i1 < i + length vs)%Z
    {{{
      array_slice t i (DfracOwn 1) vs
    }}}
      array٠unsafe_swap t #i1 #i2
    {{{
      RET ();
      array_slice t i (DfracOwn 1) vs
    }}}.
  Lemma array٠unsafe_swap𑁒spec {t vs} {i1 : Z} i1_ {v1} {i2 : Z} i2_ v2 :
    (0 i1)%Z
    (0 i2)%Z
    vs !! i1_ = Some v1
    i1_ = i1
    vs !! i2_ = Some v2
    i2_ = i2
    {{{
      array_model t (DfracOwn 1) vs
    }}}
      array٠unsafe_swap t #i1 #i2
    {{{
      RET ();
      array_model t (DfracOwn 1) (<[i2_ := v1]> $ <[i1_ := v2]> vs)
    }}}.

  Lemma array٠unsafe_fill_slice𑁒spec_atomic Ψ t (i n : Z) v :
    (0 i)%Z
    {{{
       Ψ 0
       (
         j,
        j < n -∗
        Ψ j -∗
        au_store t (i + j) v (
           Ψ (S j)
        )
      )
    }}}
      array٠unsafe_fill_slice t #i #n v
    {{{
      RET ();
      Ψ n
    }}}.
  Lemma array٠unsafe_fill_slice𑁒spec_slice_fit t vs (i : Z) i_ (n : Z) v :
    i = ⁺i_
    n = length vs
    {{{
      array_slice t i_ (DfracOwn 1) vs
    }}}
      array٠unsafe_fill_slice t #i #n v
    {{{
      RET ();
      array_slice t i_ (DfracOwn 1) (replicate n v)
    }}}.
  Lemma array٠unsafe_fill_slice𑁒spec_slice t vs (i : Z) j (n : Z) v :
    (j i)%Z
    i + n j + length vs
    {{{
      array_slice t j (DfracOwn 1) vs
    }}}
      array٠unsafe_fill_slice t #i #n v
    {{{
      RET ();
      array_slice t j (DfracOwn 1) (with_slice (i - j) n vs (replicate n v))
    }}}.
  Lemma array٠unsafe_fill_slice𑁒spec t vs (i : Z) (n : Z) v :
    (0 i)%Z
    i + n length vs
    {{{
      array_model t (DfracOwn 1) vs
    }}}
      array٠unsafe_fill_slice t #i #n v
    {{{
      RET ();
      array_model t (DfracOwn 1) (with_slice i n vs (replicate n v))
    }}}.

  Lemma array٠fill_slice𑁒spec t sz vs (i : Z) i_ (n : Z) v :
    i_ = i
    n = length vs
    {{{
      array_inv t sz
      array_slice t i_ (DfracOwn 1) vs
    }}}
      array٠fill_slice t #i #n v
    {{{
      RET ();
      0 i%Z
      0 n%Z
      i + n sz%Z
      array_slice t i_ (DfracOwn 1) (replicate n v)
    }}}.

  Lemma array٠fill𑁒spec t vs v :
    {{{
      array_model t (DfracOwn 1) vs
    }}}
      array٠fill t v
    {{{
      RET ();
      array_model t (DfracOwn 1) (replicate (length vs) v)
    }}}.

  Lemma array٠unsafe_make𑁒spec sz v :
    (0 sz)%Z
    {{{
      True
    }}}
      array٠unsafe_make #sz v
    {{{
      t
    , RET t;
      array_model t (DfracOwn 1) (replicate sz v)
    }}}.

  Lemma array٠make𑁒spec sz v :
    {{{
      True
    }}}
      array٠make #sz v
    {{{
      t
    , RET t;
      0 sz%Z
      array_model t (DfracOwn 1) (replicate sz v)
    }}}.

  #[local] Lemma array٠foldli_aux𑁒spec vs Ψ fn t sz i acc :
    i sz
    i = length vs
    {{{
       Ψ i vs None acc
       (
         i vs (o : option val) acc,
        i < sz -∗
        i = length vs -∗
        Ψ i vs o acc -∗
        match o with
        | None
            au_load t i (λ v,
               Ψ i vs (Some v) acc
            )
        | Some v
            WP fn #i acc v {{ acc,
               Ψ (S i) (vs ++ [v]) None acc
            }}
        end
      )
    }}}
      array٠foldli_aux fn t #sz #i acc
    {{{
      vs' acc
    , RET acc;
      (length vs + length vs')%nat = sz
      Ψ sz (vs ++ vs') None acc
    }}}.
  Lemma array٠foldli𑁒spec_atomic Ψ fn acc t sz :
    {{{
      array_inv t sz
       Ψ 0 [] None acc
       (
         i vs (o : option val) acc,
        i < sz -∗
        i = length vs -∗
        Ψ i vs o acc -∗
        match o with
        | None
            au_load t i (λ v,
               Ψ i vs (Some v) acc
            )
        | Some v
            WP fn #i acc v {{ acc,
               Ψ (S i) (vs ++ [v]) None acc
            }}
        end
      )
    }}}
      array٠foldli fn acc t
    {{{
      vs acc
    , RET acc;
      length vs = sz
      Ψ sz vs None acc
    }}}.
  Lemma array٠foldli𑁒spec Ψ fn acc t dq vs :
    {{{
       Ψ 0 [] acc
      array_model t dq vs
       (
         i v acc,
        vs !! i = Some v -∗
        Ψ i (take i vs) acc -∗
        WP fn #i acc v {{ acc,
           Ψ (S i) (take i vs ++ [v]) acc
        }}
      )
    }}}
      array٠foldli fn acc t
    {{{
      acc
    , RET acc;
      array_model t dq vs
      Ψ (length vs) vs acc
    }}}.
  Lemma array٠foldli𑁒spec' Ψ fn acc t dq vs :
    {{{
       Ψ 0 [] acc
      array_model t dq vs
      ( [∗ list] i v vs,
         acc,
        Ψ i (take i vs) acc -∗
        WP fn #i acc v {{ acc,
           Ψ (S i) (take i vs ++ [v]) acc
        }}
      )
    }}}
      array٠foldli fn acc t
    {{{
      acc
    , RET acc;
      array_model t dq vs
      Ψ (length vs) vs acc
    }}}.

  Lemma array٠foldl𑁒spec_atomic Ψ fn acc t sz :
    {{{
      array_inv t sz
       Ψ 0 [] None acc
       (
         i vs (o : option val) acc,
        i < sz -∗
        i = length vs -∗
        Ψ i vs o acc -∗
        match o with
        | None
            au_load t i (λ v,
               Ψ i vs (Some v) acc
            )
        | Some v
            WP fn acc v {{ acc,
               Ψ (S i) (vs ++ [v]) None acc
            }}
        end
      )
    }}}
      array٠foldl fn acc t
    {{{
      vs acc
    , RET acc;
      length vs = sz
      Ψ sz vs None acc
    }}}.
  Lemma array٠foldl𑁒spec Ψ fn acc t dq vs :
    {{{
       Ψ 0 [] acc
      array_model t dq vs
       (
         i v acc,
        vs !! i = Some v -∗
        Ψ i (take i vs) acc -∗
        WP fn acc v {{ acc,
           Ψ (S i) (take i vs ++ [v]) acc
        }}
      )
    }}}
      array٠foldl fn acc t
    {{{
      acc
    , RET acc;
      array_model t dq vs
      Ψ (length vs) vs acc
    }}}.
  Lemma array٠foldl𑁒spec' Ψ fn acc t dq vs :
    {{{
       Ψ 0 [] acc
      array_model t dq vs
      ( [∗ list] i v vs,
         acc,
        Ψ i (take i vs) acc -∗
        WP fn acc v {{ acc,
           Ψ (S i) (take i vs ++ [v]) acc
        }}
      )
    }}}
      array٠foldl fn acc t
    {{{
      acc
    , RET acc;
      array_model t dq vs
      Ψ (length vs) vs acc
    }}}.

  #[local] Lemma array٠foldri_aux𑁒spec sz vs Ψ fn t (i : Z) acc :
    i + length vs = sz
    {{{
       Ψ i acc None vs
       (
         i acc (o : option val) vs,
        (S i + length vs)%nat = sz -∗
        Ψ (S i) acc o vs -∗
        match o with
        | None
            au_load t i (λ v,
               Ψ (S i) acc (Some v) vs
            )
        | Some v
            WP fn #i v acc {{ acc,
               Ψ i acc None (v :: vs)
            }}
        end
      )
    }}}
      array٠foldri_aux fn t #i acc
    {{{
      acc vs'
    , RET acc;
      (length vs' + length vs)%nat = sz
      Ψ 0 acc None (vs' ++ vs)
    }}}.
  Lemma array٠foldri𑁒spec_atomic Ψ fn t sz acc :
    {{{
      array_inv t sz
       Ψ sz acc None []
       (
         i acc (o : option val) vs,
        (S i + length vs)%nat = sz -∗
        Ψ (S i) acc o vs -∗
        match o with
        | None
            au_load t i (λ v,
               Ψ (S i) acc (Some v) vs
            )
        | Some v
            WP fn #i v acc {{ acc,
               Ψ i acc None (v :: vs)
            }}
        end
      )
    }}}
      array٠foldri fn t acc
    {{{
      acc vs
    , RET acc;
      length vs = sz
      Ψ 0 acc None vs
    }}}.
  Lemma array٠foldri𑁒spec Ψ fn t dq vs acc :
    {{{
      array_model t dq vs
       Ψ (length vs) acc []
       (
         i v acc,
        vs !! i = Some v -∗
        Ψ (S i) acc (drop (S i) vs) -∗
        WP fn #i v acc {{ acc,
           Ψ i acc (v :: drop (S i) vs)
        }}
      )
    }}}
      array٠foldri fn t acc
    {{{
      acc
    , RET acc;
      Ψ 0 acc vs
      array_model t dq vs
    }}}.
  Lemma array٠foldri𑁒spec' Ψ fn t dq vs acc :
    {{{
      array_model t dq vs
       Ψ (length vs) acc []
      ( [∗ list] i v vs,
         acc,
        Ψ (S i) acc (drop (S i) vs) -∗
        WP fn #i v acc {{ acc,
           Ψ i acc (v :: drop (S i) vs)
        }}
      )
    }}}
      array٠foldri fn t acc
    {{{
      acc
    , RET acc;
      Ψ 0 acc vs
      array_model t dq vs
    }}}.

  Lemma array٠foldr𑁒spec_atomic Ψ fn t sz acc :
    {{{
      array_inv t sz
       Ψ sz acc None []
       (
         i acc (o : option val) vs,
        (S i + length vs)%nat = sz -∗
        Ψ (S i) acc o vs -∗
        match o with
        | None
            au_load t i (λ v,
               Ψ (S i) acc (Some v) vs
            )
        | Some v
            WP fn v acc {{ acc,
               Ψ i acc None (v :: vs)
            }}
        end
      )
    }}}
      array٠foldr fn t acc
    {{{
      acc vs
    , RET acc;
      length vs = sz
      Ψ 0 acc None vs
    }}}.
  Lemma array٠foldr𑁒spec Ψ fn t dq vs acc :
    {{{
      array_model t dq vs
       Ψ (length vs) acc []
       (
         i v acc,
        vs !! i = Some v -∗
        Ψ (S i) acc (drop (S i) vs) -∗
        WP fn v acc {{ acc,
           Ψ i acc (v :: drop (S i) vs)
        }}
      )
    }}}
      array٠foldr fn t acc
    {{{
      acc
    , RET acc;
      Ψ 0 acc vs
      array_model t dq vs
    }}}.
  Lemma array٠foldr𑁒spec' Ψ fn t dq vs acc :
    {{{
      array_model t dq vs
       Ψ (length vs) acc []
      ( [∗ list] i v vs,
         acc,
        Ψ (S i) acc (drop (S i) vs) -∗
        WP fn v acc {{ acc,
           Ψ i acc (v :: drop (S i) vs)
        }}
      )
    }}}
      array٠foldr fn t acc
    {{{
      acc
    , RET acc;
      Ψ 0 acc vs
      array_model t dq vs
    }}}.

  Lemma array٠unsafe_iteri_slice𑁒spec_atomic Ψ fn t (sz : nat) (i n : Z) :
    (0 i sz)%Z
    (0 n)%Z
    (i + n sz)%Z
    {{{
      array_inv t sz
       Ψ 0 [] None
       (
         k vs (o : option val),
        k < n -∗
        k = length vs -∗
        Ψ k vs o -∗
        match o with
        | None
            au_load t (i + k) (λ v,
               Ψ k vs (Some v)
            )
        | Some v
            WP fn #k v {{ res,
              res = ()%V
               Ψ (S k) (vs ++ [v]) None
            }}
        end
      )
    }}}
      array٠unsafe_iteri_slice fn t #i #n
    {{{
      vs
    , RET ();
      length vs = n
      Ψ n vs None
    }}}.
  Lemma array٠unsafe_iteri_slice𑁒spec Ψ fn t dq vs (i n : Z) :
    (0 i length vs)%Z
    (0 n)%Z
    (i + n length vs)%Z
    {{{
       Ψ 0 []
      array_model t dq vs
       (
         k v,
        k < n -∗
        vs !! (i + k)%nat = Some v -∗
        Ψ k (slice i k vs) -∗
        WP fn #k v {{ res,
          res = ()%V
           Ψ (S k) (slice i k vs ++ [v])
        }}
      )
    }}}
      array٠unsafe_iteri_slice fn t #i #n
    {{{
      RET ();
      array_model t dq vs
      Ψ n (slice i n vs)
    }}}.
  Lemma array٠unsafe_iteri_slice𑁒spec' Ψ fn t dq vs (i n : Z) :
    (0 i length vs)%Z
    (0 n)%Z
    (i + n length vs)%Z
    {{{
       Ψ 0 []
      array_model t dq vs
      ( [∗ list] k v slice i n vs,
        Ψ k (slice i k vs) -∗
        WP fn #k v {{ res,
          res = ()%V
           Ψ (S k) (slice i k vs ++ [v])
        }}
      )
    }}}
      array٠unsafe_iteri_slice fn t #i #n
    {{{
      RET ();
      array_model t dq vs
      Ψ n (slice i n vs)
    }}}.
  Lemma array٠unsafe_iteri_slice𑁒spec_disentangled Ψ fn t dq vs (i n : Z) :
    (0 i length vs)%Z
    (0 n)%Z
    (i + n length vs)%Z
    {{{
      array_model t dq vs
       (
         k v,
        k < n -∗
        vs !! (i + k)%nat = Some v -∗
        WP fn #k v {{ res,
          res = ()%V
           Ψ k v
        }}
      )
    }}}
      array٠unsafe_iteri_slice fn t #i #n
    {{{
      RET ();
      array_model t dq vs
      ( [∗ list] k v slice i n vs,
        Ψ k v
      )
    }}}.
  Lemma array٠unsafe_iteri_slice𑁒spec_disentangled' Ψ fn t dq vs (i n : Z) :
    (0 i length vs)%Z
    (0 n)%Z
    (i + n length vs)%Z
    {{{
      array_model t dq vs
      ( [∗ list] k v slice i n vs,
        WP fn #k v {{ res,
          res = ()%V
           Ψ k v
        }}
      )
    }}}
      array٠unsafe_iteri_slice fn t #i #n
    {{{
      RET ();
      array_model t dq vs
      ( [∗ list] k v slice i n vs,
        Ψ k v
      )
    }}}.

  Lemma array٠iteri_slice𑁒spec_atomic Ψ fn t (sz : nat) (i n : Z) :
    {{{
      array_inv t sz
       Ψ 0 [] None
       (
         k vs (o : option val),
        k < n -∗
        k = length vs -∗
        Ψ k vs o -∗
        match o with
        | None
            au_load t (i + k) (λ v,
               Ψ k vs (Some v)
            )
        | Some v
            WP fn #k v {{ res,
              res = ()%V
               Ψ (S k) (vs ++ [v]) None
            }}
        end
      )
    }}}
      array٠iteri_slice fn t #i #n
    {{{
      vs
    , RET ();
      0 i sz%Z
      0 n%Z
      i + n sz%Z
      length vs = n
      Ψ n vs None
    }}}.
  Lemma array٠iteri_slice𑁒spec Ψ fn t dq vs (i n : Z) :
    {{{
       Ψ 0 []
      array_model t dq vs
       (
         k v,
        k < n -∗
        vs !! (i + k)%nat = Some v -∗
        Ψ k (slice i k vs) -∗
        WP fn #k v {{ res,
          res = ()%V
           Ψ (S k) (slice i k vs ++ [v])
        }}
      )
    }}}
      array٠iteri_slice fn t #i #n
    {{{
      RET ();
      0 i length vs%Z
      0 n%Z
      i + n length vs%Z
      array_model t dq vs
      Ψ n (slice i n vs)
    }}}.
  Lemma array٠iteri_slice𑁒spec' Ψ fn t dq vs (i n : Z) :
    {{{
       Ψ 0 []
      array_model t dq vs
      ( [∗ list] k v slice i n vs,
        Ψ k (slice i k vs) -∗
        WP fn #k v {{ res,
          res = ()%V
           Ψ (S k) (slice i k vs ++ [v])
        }}
      )
    }}}
      array٠iteri_slice fn t #i #n
    {{{
      RET ();
      0 i length vs%Z
      0 n%Z
      i + n length vs%Z
      array_model t dq vs
      Ψ n (slice i n vs)
    }}}.
  Lemma array٠iteri_slice𑁒spec_disentangled Ψ fn t dq vs (i n : Z) :
    {{{
      array_model t dq vs
       (
         k v,
        k < n -∗
        vs !! (i + k)%nat = Some v -∗
        WP fn #k v {{ res,
          res = ()%V
           Ψ k v
        }}
      )
    }}}
      array٠iteri_slice fn t #i #n
    {{{
      RET ();
      0 i length vs%Z
      0 n%Z
      i + n length vs%Z
      array_model t dq vs
      ( [∗ list] k v slice i n vs,
        Ψ k v
      )
    }}}.
  Lemma array٠iteri_slice𑁒spec_disentangled' Ψ fn t dq vs (i n : Z) :
    {{{
      array_model t dq vs
      ( [∗ list] k v slice i n vs,
        WP fn #k v {{ res,
          res = ()%V
           Ψ k v
        }}
      )
    }}}
      array٠iteri_slice fn t #i #n
    {{{
      RET ();
      0 i length vs%Z
      0 n%Z
      i + n length vs%Z
      array_model t dq vs
      ( [∗ list] k v slice i n vs,
        Ψ k v
      )
    }}}.

  Lemma array٠unsafe_iter_slice𑁒spec_atomic Ψ fn t (sz : nat) (i n : Z) :
    (0 i sz)%Z
    (0 n)%Z
    (i + n sz)%Z
    {{{
      array_inv t sz
       Ψ 0 [] None
       (
         k vs (o : option val),
        k < n -∗
        k = length vs -∗
        Ψ k vs o -∗
        match o with
        | None
            au_load t (i + k) (λ v,
               Ψ k vs (Some v)
            )
        | Some v
            WP fn v {{ res,
              res = ()%V
               Ψ (S k) (vs ++ [v]) None
            }}
        end
      )
    }}}
      array٠unsafe_iter_slice fn t #i #n
    {{{
      vs
    , RET ();
      length vs = n
      Ψ n vs None
    }}}.
  Lemma array٠unsafe_iter_slice𑁒spec Ψ fn t dq vs (i n : Z) :
    (0 i length vs)%Z
    (0 n)%Z
    (i + n length vs)%Z
    {{{
       Ψ 0 []
      array_model t dq vs
       (
         k v,
        k < n -∗
        vs !! (i + k)%nat = Some v -∗
        Ψ k (slice i k vs) -∗
        WP fn v {{ res,
          res = ()%V
           Ψ (S k) (slice i k vs ++ [v])
        }}
      )
    }}}
      array٠unsafe_iter_slice fn t #i #n
    {{{
      RET ();
      array_model t dq vs
      Ψ n (slice i n vs)
    }}}.
  Lemma array٠unsafe_iter_slice𑁒spec' Ψ fn t dq vs (i n : Z) :
    (0 i length vs)%Z
    (0 n)%Z
    (i + n length vs)%Z
    {{{
       Ψ 0 []
      array_model t dq vs
      ( [∗ list] k v slice i n vs,
        Ψ k (slice i k vs) -∗
        WP fn v {{ res,
          res = ()%V
           Ψ (S k) (slice i k vs ++ [v])
        }}
      )
    }}}
      array٠unsafe_iter_slice fn t #i #n
    {{{
      RET ();
      array_model t dq vs
      Ψ n (slice i n vs)
    }}}.
  Lemma array٠unsafe_iter_slice𑁒spec_disentangled Ψ fn t dq vs (i n : Z) :
    (0 i length vs)%Z
    (0 n)%Z
    (i + n length vs)%Z
    {{{
      array_model t dq vs
       (
         k v,
        k < n -∗
        vs !! (i + k)%nat = Some v -∗
        WP fn v {{ res,
          res = ()%V
           Ψ k v
        }}
      )
    }}}
      array٠unsafe_iter_slice fn t #i #n
    {{{
      RET ();
      array_model t dq vs
      ( [∗ list] k v slice i n vs,
        Ψ k v
      )
    }}}.
  Lemma array٠unsafe_iter_slice𑁒spec_disentangled' Ψ fn t dq vs (i n : Z) :
    (0 i length vs)%Z
    (0 n)%Z
    (i + n length vs)%Z
    {{{
      array_model t dq vs
      ( [∗ list] k v slice i n vs,
        WP fn v {{ res,
          res = ()%V
           Ψ k v
        }}
      )
    }}}
      array٠unsafe_iter_slice fn t #i #n
    {{{
      RET ();
      array_model t dq vs
      ( [∗ list] k v slice i n vs,
        Ψ k v
      )
    }}}.

  Lemma array٠iter_slice𑁒spec_atomic Ψ fn t (sz : nat) (i n : Z) :
    {{{
      array_inv t sz
       Ψ 0 [] None
       (
         k vs (o : option val),
        k < n -∗
        k = length vs -∗
        Ψ k vs o -∗
        match o with
        | None
            au_load t (i + k) (λ v,
               Ψ k vs (Some v)
            )
        | Some v
            WP fn v {{ res,
              res = ()%V
               Ψ (S k) (vs ++ [v]) None
            }}
        end
      )
    }}}
      array٠iter_slice fn t #i #n
    {{{
      vs
    , RET ();
      0 i sz%Z
      0 n%Z
      i + n sz%Z
      length vs = n
      Ψ n vs None
    }}}.
  Lemma array٠iter_slice𑁒spec Ψ fn t dq vs (i n : Z) :
    {{{
       Ψ 0 []
      array_model t dq vs
       (
         k v,
        k < n -∗
        vs !! (i + k)%nat = Some v -∗
        Ψ k (slice i k vs) -∗
        WP fn v {{ res,
          res = ()%V
           Ψ (S k) (slice i k vs ++ [v])
        }}
      )
    }}}
      array٠iter_slice fn t #i #n
    {{{
      RET ();
      0 i length vs%Z
      0 n%Z
      i + n length vs%Z
      array_model t dq vs
      Ψ n (slice i n vs)
    }}}.
  Lemma array٠iter_slice𑁒spec' Ψ fn t dq vs (i n : Z) :
    {{{
       Ψ 0 []
      array_model t dq vs
      ( [∗ list] k v slice i n vs,
        Ψ k (slice i k vs) -∗
        WP fn v {{ res,
          res = ()%V
           Ψ (S k) (slice i k vs ++ [v])
        }}
      )
    }}}
      array٠iter_slice fn t #i #n
    {{{
      RET ();
      0 i length vs%Z
      0 n%Z
      i + n length vs%Z
      array_model t dq vs
      Ψ n (slice i n vs)
    }}}.
  Lemma array٠iter_slice𑁒spec_disentangled Ψ fn t dq vs (i n : Z) :
    {{{
      array_model t dq vs
       (
         k v,
        k < n -∗
        vs !! (i + k)%nat = Some v -∗
        WP fn v {{ res,
          res = ()%V
           Ψ k v
        }}
      )
    }}}
      array٠iter_slice fn t #i #n
    {{{
      RET ();
      0 i length vs%Z
      0 n%Z
      i + n length vs%Z
      array_model t dq vs
      ( [∗ list] k v slice i n vs,
        Ψ k v
      )
    }}}.
  Lemma array٠iter_slice𑁒spec_disentangled' Ψ fn t dq vs (i n : Z) :
    {{{
      array_model t dq vs
      ( [∗ list] k v slice i n vs,
        WP fn v {{ res,
          res = ()%V
           Ψ k v
        }}
      )
    }}}
      array٠iter_slice fn t #i #n
    {{{
      RET ();
      0 i length vs%Z
      0 n%Z
      i + n length vs%Z
      array_model t dq vs
      ( [∗ list] k v slice i n vs,
        Ψ k v
      )
    }}}.

  Lemma array٠iteri𑁒spec_atomic Ψ fn t sz :
    {{{
      array_inv t sz
       Ψ 0 [] None
       (
         i vs (o : option val),
        i < sz -∗
        i = length vs -∗
        Ψ i vs o -∗
        match o with
        | None
            au_load t i (λ v,
               Ψ i vs (Some v)
            )
        | Some v
            WP fn #i v {{ res,
              res = ()%V
               Ψ (S i) (vs ++ [v]) None
            }}
        end
      )
    }}}
      array٠iteri fn t
    {{{
      vs
    , RET ();
      length vs = sz
      Ψ sz vs None
    }}}.
  Lemma array٠iteri𑁒spec Ψ fn t dq vs :
    {{{
       Ψ 0 []
      array_model t dq vs
       (
         i v,
        vs !! i = Some v -∗
        Ψ i (take i vs) -∗
        WP fn #i v {{ res,
          res = ()%V
           Ψ (S i) (take i vs ++ [v])
        }}
      )
    }}}
      array٠iteri fn t
    {{{
      RET ();
      array_model t dq vs
      Ψ (length vs) vs
    }}}.
  Lemma array٠iteri𑁒spec' Ψ fn t dq vs :
    {{{
       Ψ 0 []
      array_model t dq vs
      ( [∗ list] i v vs,
        Ψ i (take i vs) -∗
        WP fn #i v {{ res,
          res = ()%V
           Ψ (S i) (take i vs ++ [v])
        }}
      )
    }}}
      array٠iteri fn t
    {{{
      RET ();
      array_model t dq vs
      Ψ (length vs) vs
    }}}.
  Lemma array٠iteri𑁒spec_disentangled Ψ fn t dq vs :
    {{{
      array_model t dq vs
       (
         i v,
        vs !! i = Some v -∗
        WP fn #i v {{ res,
          res = ()%V
           Ψ i v
        }}
      )
    }}}
      array٠iteri fn t
    {{{
      RET ();
      array_model t dq vs
      ( [∗ list] i v vs,
        Ψ i v
      )
    }}}.
  Lemma array٠iteri𑁒spec_disentangled' Ψ fn t dq vs :
    {{{
      array_model t dq vs
      ( [∗ list] i v vs,
        WP fn #i v {{ res,
          res = ()%V
           Ψ i v
        }}
      )
    }}}
      array٠iteri fn t
    {{{
      RET ();
      array_model t dq vs
      ( [∗ list] i v vs,
        Ψ i v
      )
    }}}.

  Lemma array٠iter𑁒spec_atomic Ψ fn t sz :
    {{{
      array_inv t sz
       Ψ 0 [] None
       (
         i vs (o : option val),
        i < sz -∗
        i = length vs -∗
        Ψ i vs o -∗
        match o with
        | None
            au_load t i (λ v,
               Ψ i vs (Some v)
            )
        | Some v
            WP fn v {{ res,
              res = ()%V
               Ψ (S i) (vs ++ [v]) None
            }}
        end
      )
    }}}
      array٠iter fn t
    {{{
      vs
    , RET ();
      length vs = sz
      Ψ sz vs None
    }}}.
  Lemma array٠iter𑁒spec Ψ fn t dq vs :
    {{{
       Ψ 0 []
      array_model t dq vs
       (
         i v,
        vs !! i = Some v -∗
        Ψ i (take i vs) -∗
        WP fn v {{ res,
          res = ()%V
           Ψ (S i) (take i vs ++ [v])
        }}
      )
    }}}
      array٠iter fn t
    {{{
      RET ();
      array_model t dq vs
      Ψ (length vs) vs
    }}}.
  Lemma array٠iter𑁒spec' Ψ fn t dq vs :
    {{{
       Ψ 0 []
      array_model t dq vs
      ( [∗ list] i v vs,
        Ψ i (take i vs) -∗
        WP fn v {{ res,
          res = ()%V
           Ψ (S i) (take i vs ++ [v])
        }}
      )
    }}}
      array٠iter fn t
    {{{
      RET ();
      array_model t dq vs
      Ψ (length vs) vs
    }}}.
  Lemma array٠iter𑁒spec_disentangled Ψ fn t dq vs :
    {{{
      array_model t dq vs
       (
         i v,
        vs !! i = Some v -∗
        WP fn v {{ res,
          res = ()%V
           Ψ i v
        }}
      )
    }}}
      array٠iter fn t
    {{{
      RET ();
      array_model t dq vs
      ( [∗ list] i v vs,
        Ψ i v
      )
    }}}.
  Lemma array٠iter𑁒spec_disentangled' Ψ fn t dq vs :
    {{{
      array_model t dq vs
      ( [∗ list] i v vs,
        WP fn v {{ res,
          res = ()%V
           Ψ i v
        }}
      )
    }}}
      array٠iter fn t
    {{{
      RET ();
      array_model t dq vs
      ( [∗ list] i v vs,
        Ψ i v
      )
    }}}.

  Lemma array٠unsafe_applyi_slice𑁒spec_atomic Ψ fn t (sz : nat) (i n : Z) :
    (0 i sz)%Z
    (0 n)%Z
    (i + n sz)%Z
    {{{
      array_inv t sz
       Ψ 0 [] None []
       (
         k vs (o : option (val + val × val)) ws,
        k < n -∗
        k = length vs -∗
        length vs = length ws -∗
        Ψ k vs o ws -∗
        match o with
        | None
            au_load t (i + k) (λ v,
               Ψ k vs (Some $ inl v) ws
            )
        | Some (inl v) ⇒
            WP fn #k v {{ w,
               Ψ k vs (Some $ inr (v, w)) ws
            }}
        | Some (inr (v, w)) ⇒
            au_store t (i + k) w (
               Ψ (S k) (vs ++ [v]) None (ws ++ [w])
            )
        end
      )
    }}}
      array٠unsafe_applyi_slice fn t #i #n
    {{{
      vs ws
    , RET ();
      length vs = n
      length vs = length ws
      Ψ n vs None ws
    }}}.
  Lemma array٠unsafe_applyi_slice𑁒spec Ψ fn t vs (i n : Z) :
    (0 i length vs)%Z
    (0 n)%Z
    (i + n length vs)%Z
    {{{
       Ψ 0 [] []
      array_model t (DfracOwn 1) vs
       (
         k v ws,
        k = length ws -∗
        k < n -∗
        vs !! (i + k)%nat = Some v -∗
        Ψ k (slice i k vs) ws -∗
        WP fn #k v {{ w,
           Ψ (S k) (slice i k vs ++ [v]) (ws ++ [w])
        }}
      )
    }}}
      array٠unsafe_applyi_slice fn t #i #n
    {{{
      ws
    , RET ();
      length ws = n
      array_model t (DfracOwn 1) (with_slice i n vs ws)
      Ψ n (slice i n vs) ws
    }}}.
  Lemma array٠unsafe_applyi_slice𑁒spec' Ψ fn t vs (i n : Z) :
    (0 i length vs)%Z
    (0 n)%Z
    (i + n length vs)%Z
    {{{
       Ψ 0 [] []
      array_model t (DfracOwn 1) vs
      ( [∗ list] k v slice i n vs,
         ws,
        k = length ws -∗
        Ψ k (slice i k vs) ws -∗
        WP fn #k v {{ w,
           Ψ (S k) (slice i k vs ++ [v]) (ws ++ [w])
        }}
      )
    }}}
      array٠unsafe_applyi_slice fn t #i #n
    {{{
      ws
    , RET ();
      length ws = n
      array_model t (DfracOwn 1) (with_slice i n vs ws)
      Ψ n (slice i n vs) ws
    }}}.
  Lemma array٠unsafe_applyi_slice𑁒spec_disentangled Ψ fn t vs (i n : Z) :
    (0 i length vs)%Z
    (0 n)%Z
    (i + n length vs)%Z
    {{{
      array_model t (DfracOwn 1) vs
       (
         k v,
        k < n -∗
        vs !! (i + k)%nat = Some v -∗
        WP fn #k v {{ w,
           Ψ k w
        }}
      )
    }}}
      array٠unsafe_applyi_slice fn t #i #n
    {{{
      ws
    , RET ();
      length ws = n
      array_model t (DfracOwn 1) (with_slice i n vs ws)
      ( [∗ list] i w ws,
        Ψ i w
      )
    }}}.
  Lemma array٠unsafe_applyi_slice𑁒spec_disentangled' Ψ fn t vs (i n : Z) :
    (0 i length vs)%Z
    (0 n)%Z
    (i + n length vs)%Z
    {{{
      array_model t (DfracOwn 1) vs
      ( [∗ list] k v slice i n vs,
        WP fn #k v {{ w,
           Ψ k w
        }}
      )
    }}}
      array٠unsafe_applyi_slice fn t #i #n
    {{{
      ws
    , RET ();
      array_model t (DfracOwn 1) (with_slice i n vs ws)
      ( [∗ list] i w ws,
        Ψ i w
      )
    }}}.

  Lemma array٠applyi_slice𑁒spec_atomic Ψ fn t (sz : nat) (i n : Z) :
    {{{
      array_inv t sz
       Ψ 0 [] None []
       (
         k vs (o : option (val + val × val)) ws,
        k < n -∗
        k = length vs -∗
        length vs = length ws -∗
        Ψ k vs o ws -∗
        match o with
        | None
            au_load t (i + k) (λ v,
               Ψ k vs (Some $ inl v) ws
            )
        | Some (inl v) ⇒
            WP fn #k v {{ w,
               Ψ k vs (Some $ inr (v, w)) ws
            }}
        | Some (inr (v, w)) ⇒
            au_store t (i + k) w (
               Ψ (S k) (vs ++ [v]) None (ws ++ [w])
            )
        end
      )
    }}}
      array٠applyi_slice fn t #i #n
    {{{
      vs ws
    , RET ();
      0 i sz%Z
      0 n%Z
      i + n sz%Z
      length vs = n
      length vs = length ws
      Ψ n vs None ws
    }}}.
  Lemma array٠applyi_slice𑁒spec Ψ fn t vs (i n : Z) :
    {{{
       Ψ 0 [] []
      array_model t (DfracOwn 1) vs
       (
         k v ws,
        k = length ws -∗
        k < n -∗
        vs !! (i + k)%nat = Some v -∗
        Ψ k (slice i k vs) ws -∗
        WP fn #k v {{ w,
           Ψ (S k) (slice i k vs ++ [v]) (ws ++ [w])
        }}
      )
    }}}
      array٠applyi_slice fn t #i #n
    {{{
      ws
    , RET ();
      0 i length vs%Z
      0 n%Z
      i + n length vs%Z
      length ws = n
      array_model t (DfracOwn 1) (with_slice i n vs ws)
      Ψ n (slice i n vs) ws
    }}}.
  Lemma array٠applyi_slice𑁒spec' Ψ fn t vs (i n : Z) :
    {{{
       Ψ 0 [] []
      array_model t (DfracOwn 1) vs
      ( [∗ list] k v slice i n vs,
         ws,
        k = length ws -∗
        Ψ k (slice i k vs) ws -∗
        WP fn #k v {{ w,
           Ψ (S k) (slice i k vs ++ [v]) (ws ++ [w])
        }}
      )
    }}}
      array٠applyi_slice fn t #i #n
    {{{
      ws
    , RET ();
      0 i length vs%Z
      0 n%Z
      i + n length vs%Z
      length ws = n
      array_model t (DfracOwn 1) (with_slice i n vs ws)
      Ψ n (slice i n vs) ws
    }}}.
  Lemma array٠applyi_slice𑁒spec_disentangled Ψ fn t vs (i n : Z) :
    {{{
      array_model t (DfracOwn 1) vs
       (
         k v,
        k < n -∗
        vs !! (i + k)%nat = Some v -∗
        WP fn #k v {{ w,
           Ψ k w
        }}
      )
    }}}
      array٠applyi_slice fn t #i #n
    {{{
      ws
    , RET ();
      0 i length vs%Z
      0 n%Z
      i + n length vs%Z
      length ws = n
      array_model t (DfracOwn 1) (with_slice i n vs ws)
      ( [∗ list] i w ws,
        Ψ i w
      )
    }}}.
  Lemma array٠applyi_slice𑁒spec_disentangled' Ψ fn t vs (i n : Z) :
    {{{
      array_model t (DfracOwn 1) vs
      ( [∗ list] k v slice i n vs,
        WP fn #k v {{ w,
           Ψ k w
        }}
      )
    }}}
      array٠applyi_slice fn t #i #n
    {{{
      ws
    , RET ();
      0 i length vs%Z
      0 n%Z
      i + n length vs%Z
      array_model t (DfracOwn 1) (with_slice i n vs ws)
      ( [∗ list] i w ws,
        Ψ i w
      )
    }}}.

  Lemma array٠unsafe_apply_slice𑁒spec_atomic Ψ fn t (sz : nat) (i n : Z) :
    (0 i sz)%Z
    (0 n)%Z
    (i + n sz)%Z
    {{{
      array_inv t sz
       Ψ 0 [] None []
       (
         k vs (o : option (val + val × val)) ws,
        k < n -∗
        k = length vs -∗
        length vs = length ws -∗
        Ψ k vs o ws -∗
        match o with
        | None
            au_load t (i + k) (λ v,
               Ψ k vs (Some $ inl v) ws
            )
        | Some (inl v) ⇒
            WP fn v {{ w,
               Ψ k vs (Some $ inr (v, w)) ws
            }}
        | Some (inr (v, w)) ⇒
            au_store t (i + k) w (
               Ψ (S k) (vs ++ [v]) None (ws ++ [w])
            )
        end
      )
    }}}
      array٠unsafe_apply_slice fn t #i #n
    {{{
      vs ws
    , RET ();
      length vs = n
      length vs = length ws
      Ψ n vs None ws
    }}}.
  Lemma array٠unsafe_apply_slice𑁒spec Ψ fn t vs (i n : Z) :
    (0 i length vs)%Z
    (0 n)%Z
    (i + n length vs)%Z
    {{{
       Ψ 0 [] []
      array_model t (DfracOwn 1) vs
       (
         k v ws,
        k = length ws -∗
        k < n -∗
        vs !! (i + k)%nat = Some v -∗
        Ψ k (slice i k vs) ws -∗
        WP fn v {{ w,
           Ψ (S k) (slice i k vs ++ [v]) (ws ++ [w])
        }}
      )
    }}}
      array٠unsafe_apply_slice fn t #i #n
    {{{
      ws
    , RET ();
      length ws = n
      array_model t (DfracOwn 1) (with_slice i n vs ws)
      Ψ n (slice i n vs) ws
    }}}.
  Lemma array٠unsafe_apply_slice𑁒spec' Ψ fn t vs (i n : Z) :
    (0 i length vs)%Z
    (0 n)%Z
    (i + n length vs)%Z
    {{{
       Ψ 0 [] []
      array_model t (DfracOwn 1) vs
      ( [∗ list] k v slice i n vs,
         ws,
        k = length ws -∗
        Ψ k (slice i k vs) ws -∗
        WP fn v {{ w,
           Ψ (S k) (slice i k vs ++ [v]) (ws ++ [w])
        }}
      )
    }}}
      array٠unsafe_apply_slice fn t #i #n
    {{{
      ws
    , RET ();
      length ws = n
      array_model t (DfracOwn 1) (with_slice i n vs ws)
      Ψ n (slice i n vs) ws
    }}}.
  Lemma array٠unsafe_apply_slice𑁒spec_disentangled Ψ fn t vs (i n : Z) :
    (0 i length vs)%Z
    (0 n)%Z
    (i + n length vs)%Z
    {{{
      array_model t (DfracOwn 1) vs
       (
         k v,
        k < n -∗
        vs !! (i + k)%nat = Some v -∗
        WP fn v {{ w,
           Ψ k w
        }}
      )
    }}}
      array٠unsafe_apply_slice fn t #i #n
    {{{
      ws
    , RET ();
      length ws = n
      array_model t (DfracOwn 1) (with_slice i n vs ws)
      ( [∗ list] i w ws,
        Ψ i w
      )
    }}}.
  Lemma array٠unsafe_apply_slice𑁒spec_disentangled' Ψ fn t vs (i n : Z) :
    (0 i length vs)%Z
    (0 n)%Z
    (i + n length vs)%Z
    {{{
      array_model t (DfracOwn 1) vs
      ( [∗ list] k v slice i n vs,
        WP fn v {{ w,
           Ψ k w
        }}
      )
    }}}
      array٠unsafe_apply_slice fn t #i #n
    {{{
      ws
    , RET ();
      array_model t (DfracOwn 1) (with_slice i n vs ws)
      ( [∗ list] i w ws,
        Ψ i w
      )
    }}}.

  Lemma array٠apply_slice𑁒spec_atomic Ψ fn t (sz : nat) (i n : Z) :
    {{{
      array_inv t sz
       Ψ 0 [] None []
       (
         k vs (o : option (val + val × val)) ws,
        k < n -∗
        k = length vs -∗
        length vs = length ws -∗
        Ψ k vs o ws -∗
        match o with
        | None
            au_load t (i + k) (λ v,
               Ψ k vs (Some $ inl v) ws
            )
        | Some (inl v) ⇒
            WP fn v {{ w,
               Ψ k vs (Some $ inr (v, w)) ws
            }}
        | Some (inr (v, w)) ⇒
            au_store t (i + k) w (
               Ψ (S k) (vs ++ [v]) None (ws ++ [w])
            )
        end
      )
    }}}
      array٠apply_slice fn t #i #n
    {{{
      vs ws
    , RET ();
      0 i sz%Z
      0 n%Z
      i + n sz%Z
      length vs = n
      length vs = length ws
      Ψ n vs None ws
    }}}.
  Lemma array٠apply_slice𑁒spec Ψ fn t vs (i n : Z) :
    {{{
       Ψ 0 [] []
      array_model t (DfracOwn 1) vs
       (
         k v ws,
        k = length ws -∗
        k < n -∗
        vs !! (i + k)%nat = Some v -∗
        Ψ k (slice i k vs) ws -∗
        WP fn v {{ w,
           Ψ (S k) (slice i k vs ++ [v]) (ws ++ [w])
        }}
      )
    }}}
      array٠apply_slice fn t #i #n
    {{{
      ws
    , RET ();
      0 i length vs%Z
      0 n%Z
      i + n length vs%Z
      length ws = n
      array_model t (DfracOwn 1) (with_slice i n vs ws)
      Ψ n (slice i n vs) ws
    }}}.
  Lemma array٠apply_slice𑁒spec' Ψ fn t vs (i n : Z) :
    {{{
       Ψ 0 [] []
      array_model t (DfracOwn 1) vs
      ( [∗ list] k v slice i n vs,
         ws,
        k = length ws -∗
        Ψ k (slice i k vs) ws -∗
        WP fn v {{ w,
           Ψ (S k) (slice i k vs ++ [v]) (ws ++ [w])
        }}
      )
    }}}
      array٠apply_slice fn t #i #n
    {{{
      ws
    , RET ();
      0 i length vs%Z
      0 n%Z
      i + n length vs%Z
      length ws = n
      array_model t (DfracOwn 1) (with_slice i n vs ws)
      Ψ n (slice i n vs) ws
    }}}.
  Lemma array٠apply_slice𑁒spec_disentangled Ψ fn t vs (i n : Z) :
    {{{
      array_model t (DfracOwn 1) vs
       (
         k v,
        k < n -∗
        vs !! (i + k)%nat = Some v -∗
        WP fn v {{ w,
           Ψ k w
        }}
      )
    }}}
      array٠apply_slice fn t #i #n
    {{{
      ws
    , RET ();
      0 i length vs%Z
      0 n%Z
      i + n length vs%Z
      length ws = n
      array_model t (DfracOwn 1) (with_slice i n vs ws)
      ( [∗ list] i w ws,
        Ψ i w
      )
    }}}.
  Lemma array٠apply_slice𑁒spec_disentangled' Ψ fn t vs (i n : Z) :
    {{{
      array_model t (DfracOwn 1) vs
      ( [∗ list] k v slice i n vs,
        WP fn v {{ w,
           Ψ k w
        }}
      )
    }}}
      array٠apply_slice fn t #i #n
    {{{
      ws
    , RET ();
      0 i length vs%Z
      0 n%Z
      i + n length vs%Z
      array_model t (DfracOwn 1) (with_slice i n vs ws)
      ( [∗ list] i w ws,
        Ψ i w
      )
    }}}.

  Lemma array٠applyi𑁒spec_atomic Ψ fn t sz :
    {{{
      array_inv t sz
       Ψ 0 [] None []
       (
         i vs (o : option (val + val × val)) ws,
        i < sz -∗
        i = length vs -∗
        length vs = length ws -∗
        Ψ i vs o ws -∗
        match o with
        | None
            au_load t i (λ v,
               Ψ i vs (Some $ inl v) ws
            )
        | Some (inl v) ⇒
            WP fn #i v {{ w,
               Ψ i vs (Some $ inr (v, w)) ws
            }}
        | Some (inr (v, w)) ⇒
            au_store t i w (
               Ψ (S i) (vs ++ [v]) None (ws ++ [w])
            )
        end
      )
    }}}
      array٠applyi fn t
    {{{
      vs ws
    , RET ();
      length vs = sz
      length vs = length ws
      Ψ sz vs None ws
    }}}.
  Lemma array٠applyi𑁒spec Ψ fn t vs :
    {{{
       Ψ 0 [] []
      array_model t (DfracOwn 1) vs
       (
         i v ws,
        i = length ws -∗
        vs !! i = Some v -∗
        Ψ i (take i vs) ws -∗
        WP fn #i v {{ w,
           Ψ (S i) (take i vs ++ [v]) (ws ++ [w])
        }}
      )
    }}}
      array٠applyi fn t
    {{{
      ws
    , RET ();
      length vs = length ws
      array_model t (DfracOwn 1) ws
      Ψ (length vs) vs ws
    }}}.
  Lemma array٠applyi𑁒spec' Ψ fn t vs :
    {{{
       Ψ 0 [] []
      array_model t (DfracOwn 1) vs
      ( [∗ list] i v vs,
         ws,
        i = length ws -∗
        Ψ i (take i vs) ws -∗
        WP fn #i v {{ w,
           Ψ (S i) (take i vs ++ [v]) (ws ++ [w])
        }}
      )
    }}}
      array٠applyi fn t
    {{{
      ws
    , RET ();
      length vs = length ws
      array_model t (DfracOwn 1) ws
      Ψ (length vs) vs ws
    }}}.
  Lemma array٠applyi𑁒spec_disentangled Ψ fn t vs :
    {{{
      array_model t (DfracOwn 1) vs
       (
         i v,
        vs !! i = Some v -∗
        WP fn #i v {{ w,
           Ψ i w
        }}
      )
    }}}
      array٠applyi fn t
    {{{
      ws
    , RET ();
      length vs = length ws
      array_model t (DfracOwn 1) ws
      ( [∗ list] i w ws,
        Ψ i w
      )
    }}}.
  Lemma array٠applyi𑁒spec_disentangled' Ψ fn t vs :
    {{{
      array_model t (DfracOwn 1) vs
      ( [∗ list] i v vs,
        WP fn #i v {{ w,
           Ψ i w
        }}
      )
    }}}
      array٠applyi fn t
    {{{
      ws
    , RET ();
      array_model t (DfracOwn 1) ws
      ( [∗ list] i w ws,
        Ψ i w
      )
    }}}.

  Lemma array٠apply𑁒spec_atomic Ψ fn t sz :
    {{{
      array_inv t sz
       Ψ 0 [] None []
       (
         i vs (o : option (val + val × val)) ws,
        i < sz -∗
        i = length vs -∗
        length vs = length ws -∗
        Ψ i vs o ws -∗
        match o with
        | None
            au_load t i (λ v,
               Ψ i vs (Some $ inl v) ws
            )
        | Some (inl v) ⇒
            WP fn v {{ w,
               Ψ i vs (Some $ inr (v, w)) ws
            }}
        | Some (inr (v, w)) ⇒
            au_store t i w (
               Ψ (S i) (vs ++ [v]) None (ws ++ [w])
            )
        end
      )
    }}}
      array٠apply fn t
    {{{
      vs ws
    , RET ();
      length vs = sz
      length vs = length ws
      Ψ sz vs None ws
    }}}.
  Lemma array٠apply𑁒spec Ψ fn t vs :
    {{{
       Ψ 0 [] []
      array_model t (DfracOwn 1) vs
       (
         i v ws,
        i = length ws -∗
        vs !! i = Some v -∗
        Ψ i (take i vs) ws -∗
        WP fn v {{ w,
           Ψ (S i) (take i vs ++ [v]) (ws ++ [w])
        }}
      )
    }}}
      array٠apply fn t
    {{{
      ws
    , RET ();
      length vs = length ws
      array_model t (DfracOwn 1) ws
      Ψ (length vs) vs ws
    }}}.
  Lemma array٠apply𑁒spec' Ψ fn t vs :
    {{{
       Ψ 0 [] []
      array_model t (DfracOwn 1) vs
      ( [∗ list] i v vs,
         ws,
        i = length ws -∗
        Ψ i (take i vs) ws -∗
        WP fn v {{ w,
           Ψ (S i) (take i vs ++ [v]) (ws ++ [w])
        }}
      )
    }}}
      array٠apply fn t
    {{{
      ws
    , RET ();
      length vs = length ws
      array_model t (DfracOwn 1) ws
      Ψ (length vs) vs ws
    }}}.
  Lemma array٠apply𑁒spec_disentangled Ψ fn t vs :
    {{{
      array_model t (DfracOwn 1) vs
       (
         i v,
        vs !! i = Some v -∗
        WP fn v {{ w,
           Ψ i w
        }}
      )
    }}}
      array٠apply fn t
    {{{
      ws
    , RET ();
      length vs = length ws
      array_model t (DfracOwn 1) ws
      ( [∗ list] i w ws,
        Ψ i w
      )
    }}}.
  Lemma array٠apply𑁒spec_disentangled' Ψ fn t vs :
    {{{
      array_model t (DfracOwn 1) vs
      ( [∗ list] i v vs,
        WP fn v {{ w,
           Ψ i w
        }}
      )
    }}}
      array٠apply fn t
    {{{
      ws
    , RET ();
      array_model t (DfracOwn 1) ws
      ( [∗ list] i w ws,
        Ψ i w
      )
    }}}.

  Lemma array٠unsafe_initi𑁒spec Ψ sz fn :
    (0 sz)%Z
    {{{
       (
         t,
        |={}=> Ψ t 0 []
      )
       (
         t i vs,
        i < sz -∗
        i = length vs -∗
        Ψ t i vs -∗
        WP fn #i {{ v,
           Ψ t (S i) (vs ++ [v])
        }}
      )
    }}}
      array٠unsafe_initi #sz fn
    {{{
      t vs
    , RET t;
      length vs = sz
      array_model t (DfracOwn 1) vs
      Ψ t sz vs
    }}}.
  Lemma array٠unsafe_initi𑁒spec' Ψ sz fn :
    (0 sz)%Z
    {{{
       (
         t,
        |={}=> Ψ t 0 []
      )
      ( [∗ list] i seq 0 sz,
         t vs,
        i = length vs -∗
        Ψ t i vs -∗
        WP fn #i {{ v,
           Ψ t (S i) (vs ++ [v])
        }}
      )
    }}}
      array٠unsafe_initi #sz fn
    {{{
      t vs
    , RET t;
      length vs = sz
      array_model t (DfracOwn 1) vs
      Ψ t sz vs
    }}}.
  Lemma array٠unsafe_initi𑁒spec_disentangled_strong Χ Ψ sz fn :
    (0 sz)%Z
    {{{
       (
         t,
        |={}=> Χ t
      )
       (
         t i,
        Χ t -∗
        i < sz -∗
        WP fn #i {{ v,
          Χ t
           Ψ t i v
        }}
      )
    }}}
      array٠unsafe_initi #sz fn
    {{{
      t vs
    , RET t;
      length vs = sz
      array_model t (DfracOwn 1) vs
      Χ t
      ( [∗ list] i v vs,
        Ψ t i v
      )
    }}}.
  Lemma array٠unsafe_initi𑁒spec_disentangled Ψ sz fn :
    (0 sz)%Z
    {{{
       (
         i,
        i < sz -∗
        WP fn #i {{ v,
           Ψ i v
        }}
      )
    }}}
      array٠unsafe_initi #sz fn
    {{{
      t vs
    , RET t;
      length vs = sz
      array_model t (DfracOwn 1) vs
      ( [∗ list] i v vs,
        Ψ i v
      )
    }}}.
  Lemma array٠unsafe_initi𑁒spec_disentangled_strong' Χ Ψ sz fn :
    (0 sz)%Z
    {{{
       (
         t,
        |={}=> Χ t
      )
      ( [∗ list] i seq 0 sz,
         t,
        Χ t -∗
        WP fn #i {{ v,
          Χ t
           Ψ t i v
        }}
      )
    }}}
      array٠unsafe_initi #sz fn
    {{{
      t vs
    , RET t;
      length vs = sz
      array_model t (DfracOwn 1) vs
      Χ t
      ( [∗ list] i v vs,
        Ψ t i v
      )
    }}}.
  Lemma array٠unsafe_initi𑁒spec_disentangled' Ψ sz fn :
    (0 sz)%Z
    {{{
      ( [∗ list] i seq 0 sz,
        WP fn #i {{ v,
           Ψ i v
        }}
      )
    }}}
      array٠unsafe_initi #sz fn
    {{{
      t vs
    , RET t;
      length vs = sz
      array_model t (DfracOwn 1) vs
      ( [∗ list] i v vs,
        Ψ i v
      )
    }}}.

  Lemma array٠initi𑁒spec Ψ sz fn :
    {{{
       (
         t,
        |={}=> Ψ t 0 []
      )
       (
         t i vs,
        i < sz -∗
        i = length vs -∗
        Ψ t i vs -∗
        WP fn #i {{ v,
           Ψ t (S i) (vs ++ [v])
        }}
      )
    }}}
      array٠initi #sz fn
    {{{
      t vs
    , RET t;
      0 sz%Z
      length vs = sz
      array_model t (DfracOwn 1) vs
      Ψ t sz vs
    }}}.
  Lemma array٠initi𑁒spec' Ψ sz fn :
    {{{
       (
         t,
        |={}=> Ψ t 0 []
      )
      ( [∗ list] i seq 0 sz,
         t vs,
        i = length vs -∗
        Ψ t i vs -∗
        WP fn #i {{ v,
           Ψ t (S i) (vs ++ [v])
        }}
      )
    }}}
      array٠initi #sz fn
    {{{
      t vs
    , RET t;
      0 sz%Z
      length vs = sz
      array_model t (DfracOwn 1) vs
      Ψ t sz vs
    }}}.
  Lemma array٠initi𑁒spec_disentangled Ψ sz fn :
    {{{
       (
         i,
        i < sz -∗
        WP fn #i {{ v,
           Ψ i v
        }}
      )
    }}}
      array٠initi #sz fn
    {{{
      t vs
    , RET t;
      0 sz%Z
      length vs = sz
      array_model t (DfracOwn 1) vs
      ( [∗ list] i v vs,
        Ψ i v
      )
    }}}.
  Lemma array٠initi𑁒spec_disentangled' Ψ sz fn :
    {{{
      ( [∗ list] i seq 0 sz,
        WP fn #i {{ v,
           Ψ i v
        }}
      )
    }}}
      array٠initi #sz fn
    {{{
      t vs
    , RET t;
      0 sz%Z
      length vs = sz
      array_model t (DfracOwn 1) vs
      ( [∗ list] i v vs,
        Ψ i v
      )
    }}}.

  Lemma array٠unsafe_init𑁒spec Ψ sz fn :
    (0 sz)%Z
    {{{
       (
         t,
        |={}=> Ψ t 0 []
      )
       (
         t i vs,
        i < sz -∗
        i = length vs -∗
        Ψ t i vs -∗
        WP fn () {{ v,
           Ψ t (S i) (vs ++ [v])
        }}
      )
    }}}
      array٠unsafe_init #sz fn
    {{{
      t vs
    , RET t;
      length vs = sz
      array_model t (DfracOwn 1) vs
      Ψ t sz vs
    }}}.
  Lemma array٠unsafe_init𑁒spec' Ψ sz fn :
    (0 sz)%Z
    {{{
       (
         t,
        |={}=> Ψ t 0 []
      )
      ( [∗ list] i seq 0 sz,
         t vs,
        i = length vs -∗
        Ψ t i vs -∗
        WP fn () {{ v,
           Ψ t (S i) (vs ++ [v])
        }}
      )
    }}}
      array٠unsafe_init #sz fn
    {{{
      t vs
    , RET t;
      length vs = sz
      array_model t (DfracOwn 1) vs
      Ψ t sz vs
    }}}.
  Lemma array٠unsafe_init𑁒spec_disentangled Ψ sz fn :
    (0 sz)%Z
    {{{
       (
         i,
        i < sz -∗
        WP fn () {{ v,
           Ψ i v
        }}
      )
    }}}
      array٠unsafe_init #sz fn
    {{{
      t vs
    , RET t;
      length vs = sz
      array_model t (DfracOwn 1) vs
      ( [∗ list] i v vs,
        Ψ i v
      )
    }}}.
  Lemma array٠unsafe_init𑁒spec_disentangled' Ψ sz fn :
    (0 sz)%Z
    {{{
      ( [∗ list] i seq 0 sz,
        WP fn () {{ v,
           Ψ i v
        }}
      )
    }}}
      array٠unsafe_init #sz fn
    {{{
      t vs
    , RET t;
      length vs = sz
      array_model t (DfracOwn 1) vs
      ( [∗ list] i v vs,
        Ψ i v
      )
    }}}.

  Lemma array٠init𑁒spec Ψ sz fn :
    {{{
       (
         t,
        |={}=> Ψ t 0 []
      )
       (
         t i vs,
        i < sz -∗
        i = length vs -∗
        Ψ t i vs -∗
        WP fn () {{ v,
           Ψ t (S i) (vs ++ [v])
        }}
      )
    }}}
      array٠init #sz fn
    {{{
      t vs
    , RET t;
      0 sz%Z
      length vs = sz
      array_model t (DfracOwn 1) vs
      Ψ t sz vs
    }}}.
  Lemma array٠init𑁒spec' Ψ sz fn :
    {{{
       (
         t,
        |={}=> Ψ t 0 []
      )
      ( [∗ list] i seq 0 sz,
         t vs,
        i = length vs -∗
        Ψ t i vs -∗
        WP fn () {{ v,
           Ψ t (S i) (vs ++ [v])
        }}
      )
    }}}
      array٠init #sz fn
    {{{
      t vs
    , RET t;
      0 sz%Z
      length vs = sz
      array_model t (DfracOwn 1) vs
      Ψ t sz vs
    }}}.
  Lemma array٠init𑁒spec_disentangled Ψ sz fn :
    {{{
       (
         i,
        i < sz -∗
        WP fn () {{ v,
           Ψ i v
        }}
      )
    }}}
      array٠init #sz fn
    {{{
      t vs
    , RET t;
      0 sz%Z
      length vs = sz
      array_model t (DfracOwn 1) vs
      ( [∗ list] i v vs,
        Ψ i v
      )
    }}}.
  Lemma array٠init𑁒spec_disentangled' Ψ sz fn :
    {{{
      ( [∗ list] i seq 0 sz,
        WP fn () {{ v,
           Ψ i v
        }}
      )
    }}}
      array٠init #sz fn
    {{{
      t vs
    , RET t;
      0 sz%Z
      length vs = sz
      array_model t (DfracOwn 1) vs
      ( [∗ list] i v vs,
        Ψ i v
      )
    }}}.

  Lemma array٠mapi𑁒spec_atomic Ψ fn t sz :
    {{{
      array_inv t sz
       Ψ 0 [] None []
       (
         i vs (o : option val) ws,
        i < sz -∗
        i = length vs -∗
        length vs = length ws -∗
        Ψ i vs o ws -∗
        match o with
        | None
            au_load t i (λ v,
               Ψ i vs (Some v) ws
            )
        | Some v
            WP fn #i v {{ w,
               Ψ (S i) (vs ++ [v]) None (ws ++ [w])
            }}
        end
      )
    }}}
      array٠mapi fn t
    {{{
      t' vs ws
    , RET t';
      length vs = sz
      length vs = length ws
      array_model t' (DfracOwn 1) ws
      Ψ sz vs None ws
    }}}.
  Lemma array٠mapi𑁒spec Ψ fn t dq vs :
    {{{
       Ψ 0 [] []
      array_model t dq vs
       (
         i v ws,
        vs !! i = Some v -∗
        i = length ws -∗
        Ψ i (take i vs) ws -∗
        WP fn #i v {{ w,
           Ψ (S i) (take i vs ++ [v]) (ws ++ [w])
        }}
      )
    }}}
      array٠mapi fn t
    {{{
      t' ws
    , RET t';
      length ws = length vs
      array_model t dq vs
      array_model t' (DfracOwn 1) ws
      Ψ (length vs) vs ws
    }}}.
  Lemma array٠mapi𑁒spec' Ψ fn t dq vs :
    {{{
       Ψ 0 [] []
      array_model t dq vs
      ( [∗ list] i v vs,
         ws,
        i = length ws -∗
        Ψ i (take i vs) ws -∗
        WP fn #i v {{ w,
           Ψ (S i) (take i vs ++ [v]) (ws ++ [w])
        }}
      )
    }}}
      array٠mapi fn t
    {{{
      t' ws
    , RET t';
      length ws = length vs
      array_model t dq vs
      array_model t' (DfracOwn 1) ws
      Ψ (length vs) vs ws
    }}}.
  Lemma array٠mapi𑁒spec_disentangled Ψ fn t dq vs :
    {{{
      array_model t dq vs
       (
         i v,
        vs !! i = Some v -∗
        WP fn #i v {{ w,
           Ψ i v w
        }}
      )
    }}}
      array٠mapi fn t
    {{{
      t' ws
    , RET t';
      length ws = length vs
      array_model t dq vs
      array_model t' (DfracOwn 1) ws
      ( [∗ list] i v; w vs; ws,
        Ψ i v w
      )
    }}}.
  Lemma array٠mapi𑁒spec_disentangled' Ψ fn t dq vs :
    {{{
      array_model t dq vs
      ( [∗ list] i v vs,
        WP fn #i v {{ w,
           Ψ i v w
        }}
      )
    }}}
      array٠mapi fn t
    {{{
      t' ws
    , RET t';
      length ws = length vs
      array_model t dq vs
      array_model t' (DfracOwn 1) ws
      ( [∗ list] i v; w vs; ws,
        Ψ i v w
      )
    }}}.

  Lemma array٠map𑁒spec_atomic Ψ fn t sz :
    {{{
      array_inv t sz
       Ψ 0 [] None []
       (
         i vs (o : option val) ws,
        i < sz -∗
        i = length vs -∗
        length vs = length ws -∗
        Ψ i vs o ws -∗
        match o with
        | None
            au_load t i (λ v,
               Ψ i vs (Some v) ws
            )
        | Some v
            WP fn v {{ w,
               Ψ (S i) (vs ++ [v]) None (ws ++ [w])
            }}
        end
      )
    }}}
      array٠map fn t
    {{{
      t' vs ws
    , RET t';
      length vs = sz
      length vs = length ws
      array_model t' (DfracOwn 1) ws
      Ψ sz vs None ws
    }}}.
  Lemma array٠map𑁒spec Ψ fn t dq vs :
    {{{
       Ψ 0 [] []
      array_model t dq vs
       (
         i v ws,
        vs !! i = Some v -∗
        i = length ws -∗
        Ψ i (take i vs) ws -∗
        WP fn v {{ w,
           Ψ (S i) (take i vs ++ [v]) (ws ++ [w])
        }}
      )
    }}}
      array٠map fn t
    {{{
      t' ws
    , RET t';
      length ws = length vs
      array_model t dq vs
      array_model t' (DfracOwn 1) ws
      Ψ (length vs) vs ws
    }}}.
  Lemma array٠map𑁒spec' Ψ fn t dq vs :
    {{{
       Ψ 0 [] []
      array_model t dq vs
      ( [∗ list] i v vs,
         ws,
        i = length ws -∗
        Ψ i (take i vs) ws -∗
        WP fn v {{ w,
           Ψ (S i) (take i vs ++ [v]) (ws ++ [w])
        }}
      )
    }}}
      array٠map fn t
    {{{
      t' ws
    , RET t';
      length ws = length vs
      array_model t dq vs
      array_model t' (DfracOwn 1) ws
      Ψ (length vs) vs ws
    }}}.
  Lemma array٠map𑁒spec_disentangled Ψ fn t dq vs :
    {{{
      array_model t dq vs
       (
         i v,
        vs !! i = Some v -∗
        WP fn v {{ w,
           Ψ i v w
        }}
      )
    }}}
      array٠map fn t
    {{{
      t' ws
    , RET t';
      length ws = length vs
      array_model t dq vs
      array_model t' (DfracOwn 1) ws
      ( [∗ list] i v; w vs; ws,
        Ψ i v w
      )
    }}}.
  Lemma array٠map𑁒spec_disentangled' Ψ fn t dq vs :
    {{{
      array_model t dq vs
      ( [∗ list] i v vs,
        WP fn v {{ w,
           Ψ i v w
        }}
      )
    }}}
      array٠map fn t
    {{{
      t' ws
    , RET t';
      length ws = length vs
      array_model t dq vs
      array_model t' (DfracOwn 1) ws
      ( [∗ list] i v; w vs; ws,
        Ψ i v w
      )
    }}}.

  Lemma array٠unsafe_copy_slice𑁒spec_atomic Ψ t1 (i1 : Z) t2 (i2 n : Z) :
    (0 i1)%Z
    (0 i2)%Z
    (0 n)%Z
    {{{
       Ψ 0 [] None
       (
         k vs o,
        k < n -∗
        k = length vs -∗
        Ψ k vs o -∗
        match o with
        | None
            au_load t1 (i1 + k) (λ v,
               Ψ k vs (Some v)
            )
        | Some v
            au_store t2 (i2 + k) v (
               Ψ (S k) (vs ++ [v]) None
            )
        end
      )
    }}}
      array٠unsafe_copy_slice t1 #i1 t2 #i2 #n
    {{{
      vs
    , RET ();
      length vs = n
      Ψ n vs None
    }}}.
  Lemma array٠unsafe_copy_slice𑁒spec_slice_fit t1 (i1 : Z) i1_ dq1 vs1 t2 (i2 : Z) i2_ vs2 (n : Z) :
    i1 = ⁺i1_
    i2 = ⁺i2_
    n = length vs1
    length vs1 = length vs2
    {{{
      array_slice t1 i1_ dq1 vs1
      array_slice t2 i2_ (DfracOwn 1) vs2
    }}}
      array٠unsafe_copy_slice t1 #i1 t2 #i2 #n
    {{{
      RET ();
      array_slice t1 i1_ dq1 vs1
      array_slice t2 i2_ (DfracOwn 1) vs1
    }}}.
  Lemma array٠unsafe_copy_slice𑁒spec_slice_fit_src t1 (i1 : Z) i1_ dq1 vs1 t2 i2 (j2 : Z) vs2 (n : Z) :
    i1 = ⁺i1_
    (i2 j2)%Z
    n = length vs1
    (j2 + n i2 + length vs2)%Z
    {{{
      array_slice t1 i1_ dq1 vs1
      array_slice t2 i2 (DfracOwn 1) vs2
    }}}
      array٠unsafe_copy_slice t1 #i1 t2 #j2 #n
    {{{
      RET ();
      array_slice t1 i1_ dq1 vs1
      array_slice t2 i2 (DfracOwn 1) (with_slice (j2 - i2) n vs2 vs1)
    }}}.
  Lemma array٠unsafe_copy_slice𑁒spec_slice_fit_dst t1 i1 (j1 : Z) dq1 vs1 t2 (i2 : Z) i2_ vs2 (n : Z) :
    (i1 j1)%Z
    i2 = ⁺i2_
    n = length vs2
    (j1 + n i1 + length vs1)%Z
    {{{
      array_slice t1 i1 dq1 vs1
      array_slice t2 i2_ (DfracOwn 1) vs2
    }}}
      array٠unsafe_copy_slice t1 #j1 t2 #i2 #n
    {{{
      RET ();
      array_slice t1 i1 dq1 vs1
      array_slice t2 i2_ (DfracOwn 1) (slice (j1 - i1) n vs1)
    }}}.
  Lemma array٠unsafe_copy_slice𑁒spec_slice t1 i1 (j1 : Z) dq1 vs1 t2 i2 (j2 : Z) vs2 (n : Z) :
    (i1 j1)%Z
    (i2 j2)%Z
    (0 n)%Z
    (j1 + n i1 + length vs1)%Z
    (j2 + n i2 + length vs2)%Z
    {{{
      array_slice t1 i1 dq1 vs1
      array_slice t2 i2 (DfracOwn 1) vs2
    }}}
      array٠unsafe_copy_slice t1 #j1 t2 #j2 #n
    {{{
      RET ();
      array_slice t1 i1 dq1 vs1
      array_slice t2 i2 (DfracOwn 1) (with_slice (j2 - i2) n vs2 (take n (drop (j1 - i1) vs1)))
    }}}.
  Lemma array٠unsafe_copy_slice𑁒spec t1 (i1 : Z) dq1 vs1 t2 (i2 : Z) vs2 (n : Z) :
    (0 i1)%Z
    (0 i2)%Z
    (0 n)%Z
    (i1 + n length vs1)%Z
    (i2 + n length vs2)%Z
    {{{
      array_model t1 dq1 vs1
      array_model t2 (DfracOwn 1) vs2
    }}}
      array٠unsafe_copy_slice t1 #i1 t2 #i2 #n
    {{{
      RET ();
      array_model t1 dq1 vs1
      array_model t2 (DfracOwn 1) (with_slice i2 n vs2 (take n (drop i1 vs1)))
    }}}.

  Lemma array٠copy_slice𑁒spec_slice_fit t1 sz1 (i1 : Z) i1_ dq1 vs1 t2 sz2 (i2 : Z) i2_ vs2 (n : Z) :
    i1_ = i1
    i2_ = i2
    {{{
      array_inv t1 sz1
      array_inv t2 sz2
      ( 0 i1%Z -∗
        0 i2%Z -∗
        0 n%Z -∗
        i1 + n sz1%Z -∗
        i2 + n sz2%Z -∗
          n = length vs1
          length vs1 = length vs2
          array_slice t1 i1_ dq1 vs1
          array_slice t2 i2_ (DfracOwn 1) vs2
      )
    }}}
      array٠copy_slice t1 #i1 t2 #i2 #n
    {{{
      RET ();
      0 i1%Z
      0 i2%Z
      0 n%Z
      i1 + n sz1%Z
      i2 + n sz2%Z
      array_slice t1 i1_ dq1 vs1
      array_slice t2 i2_ (DfracOwn 1) vs1
    }}}.
  Lemma array٠copy_slice𑁒spec_slice t1 sz1 i1 (j1 : Z) dq1 vs1 t2 sz2 i2 (j2 : Z) vs2 (n : Z) :
    {{{
      array_inv t1 sz1
      array_inv t2 sz2
      ( 0 j1%Z -∗
        0 j2%Z -∗
        0 n%Z -∗
        j1 + n sz1%Z -∗
        j2 + n sz2%Z -∗
          i1 j1
          i2 j2
          j1 + n i1 + length vs1%Z
          j2 + n i2 + length vs2%Z
          array_slice t1 i1 dq1 vs1
          array_slice t2 i2 (DfracOwn 1) vs2
      )
    }}}
      array٠copy_slice t1 #j1 t2 #j2 #n
    {{{
      RET ();
      0 j1%Z
      0 j2%Z
      0 n%Z
      j1 + n sz1%Z
      j2 + n sz2%Z
      array_slice t1 i1 dq1 vs1
      array_slice t2 i2 (DfracOwn 1) (with_slice (j2 - i2) n vs2 (take n (drop (j1 - i1) vs1)))
    }}}.
  Lemma array٠copy_slice𑁒spec t1 (i1 : Z) dq1 vs1 t2 (i2 : Z) vs2 (n : Z) :
    {{{
      array_model t1 dq1 vs1
      array_model t2 (DfracOwn 1) vs2
    }}}
      array٠copy_slice t1 #i1 t2 #i2 #n
    {{{
      RET ();
      0 i1%Z
      0 i2%Z
      0 n%Z
      i1 + n length vs1%Z
      i2 + n length vs2%Z
      array_model t1 dq1 vs1
      array_model t2 (DfracOwn 1) (with_slice i2 n vs2 (take n (drop i1 vs1)))
    }}}.

  Lemma array٠unsafe_copy𑁒spec_atomic Ψ t1 sz1 t2 sz2 (i2 : Z) :
    (0 i2)%Z
    {{{
      array_inv t1 sz1
      array_inv t2 sz2
       Ψ 0 [] None
       (
         k vs o,
        k < sz1 -∗
        k = length vs -∗
        Ψ k vs o -∗
        match o with
        | None
            au_load t1 k (λ v,
               Ψ k vs (Some v)
            )
        | Some v
            au_store t2 (i2 + k) v (
               Ψ (S k) (vs ++ [v]) None
            )
        end
      )
    }}}
      array٠unsafe_copy t1 t2 #i2
    {{{
      vs
    , RET ();
      length vs = sz1
      Ψ sz1 vs None
    }}}.
  Lemma array٠unsafe_copy𑁒spec_slice_fit t1 dq1 vs1 t2 (i2 : Z) i2_ vs2 :
    i2 = ⁺i2_
    length vs1 = length vs2
    {{{
      array_model t1 dq1 vs1
      array_slice t2 i2_ (DfracOwn 1) vs2
    }}}
      array٠unsafe_copy t1 t2 #i2
    {{{
      RET ();
      array_model t1 dq1 vs1
      array_slice t2 i2_ (DfracOwn 1) vs1
    }}}.
  Lemma array٠unsafe_copy𑁒spec_slice t1 dq1 vs1 t2 i2 (j2 : Z) vs2 :
    (i2 j2)%Z
    (j2 + length vs1 i2 + length vs2)%Z
    {{{
      array_model t1 dq1 vs1
      array_slice t2 i2 (DfracOwn 1) vs2
    }}}
      array٠unsafe_copy t1 t2 #j2
    {{{
      RET ();
      array_model t1 dq1 vs1
      array_slice t2 i2 (DfracOwn 1) (with_slice (j2 - i2) (length vs1) vs2 vs1)
    }}}.
  Lemma array٠unsafe_copy𑁒spec t1 dq1 vs1 t2 (i2 : Z) vs2 :
    (0 i2)%Z
    (i2 + length vs1 length vs2)%Z
    {{{
      array_model t1 dq1 vs1
      array_model t2 (DfracOwn 1) vs2
    }}}
      array٠unsafe_copy t1 t2 #i2
    {{{
      RET ();
      array_model t1 dq1 vs1
      array_model t2 (DfracOwn 1) (with_slice i2 (length vs1) vs2 vs1)
    }}}.

  Lemma array٠copy𑁒spec_slice_fit t1 dq1 vs1 t2 sz2 (i2 : Z) i2_ vs2 :
    i2_ = i2
    {{{
      array_model t1 dq1 vs1
      array_inv t2 sz2
      ( 0 i2%Z -∗
        i2 + length vs1 sz2%Z -∗
          length vs1 = length vs2
          array_slice t2 i2_ (DfracOwn 1) vs2
      )
    }}}
      array٠copy t1 t2 #i2
    {{{
      RET ();
      0 i2%Z
      i2 + length vs1 sz2%Z
      array_model t1 dq1 vs1
      array_slice t2 i2_ (DfracOwn 1) vs1
    }}}.
  Lemma array٠copy𑁒spec_slice t1 dq1 vs1 t2 sz2 i2 (j2 : Z) vs2 :
    {{{
      array_model t1 dq1 vs1
      array_inv t2 sz2
      ( 0 j2%Z -∗
        j2 + length vs1 sz2%Z -∗
          i2 j2%Z
          j2 + length vs1 i2 + length vs2%Z
          array_slice t2 i2 (DfracOwn 1) vs2
      )
    }}}
      array٠copy t1 t2 #j2
    {{{
      RET ();
      0 i2
      i2 + length vs1 sz2
      array_model t1 dq1 vs1
      array_slice t2 i2 (DfracOwn 1) (with_slice (j2 - i2) (length vs1) vs2 vs1)
    }}}.
  Lemma array٠copy𑁒spec t1 dq1 vs1 t2 (i2 : Z) vs2 :
    {{{
      array_model t1 dq1 vs1
      array_model t2 (DfracOwn 1) vs2
    }}}
      array٠copy t1 t2 #i2
    {{{
      RET ();
      0 i2%Z
      i2 + length vs1 length vs2%Z
      array_model t1 dq1 vs1
      array_model t2 (DfracOwn 1) (with_slice i2 (length vs1) vs2 vs1)
    }}}.

  Lemma array٠unsafe_grow𑁒spec t dq vs sz' v' :
    (length vs sz')%Z
    {{{
      array_model t dq vs
    }}}
      array٠unsafe_grow t #sz' v'
    {{{
      t'
    , RET t';
      array_model t dq vs
      array_model t' (DfracOwn 1) (vs ++ replicate (sz' - length vs) v')
    }}}.

  Lemma array٠grow𑁒spec t dq vs sz' v' :
    {{{
      array_model t dq vs
    }}}
      array٠grow t #sz' v'
    {{{
      t'
    , RET t';
      length vs sz'%Z
      array_model t dq vs
      array_model t' (DfracOwn 1) (vs ++ replicate (sz' - length vs) v')
    }}}.

  Lemma array٠unsafe_sub𑁒spec_slice_fit t dq vs (i : Z) i_ (n : Z) :
    i = ⁺i_
    n = length vs
    {{{
      array_slice t i_ dq vs
    }}}
      array٠unsafe_sub t #i #n
    {{{
      t'
    , RET t';
      array_slice t i_ dq vs
      array_model t' (DfracOwn 1) (take n vs)
    }}}.
  Lemma array٠unsafe_sub𑁒spec_slice t dq vs i (j n : Z) :
    (i j)%Z
    (0 n)%Z
    (j + n i + length vs)%Z
    {{{
      array_slice t i dq vs
    }}}
      array٠unsafe_sub t #j #n
    {{{
      t'
    , RET t';
      array_slice t i dq vs
      array_model t' (DfracOwn 1) (take n (drop (j - i) vs))
    }}}.
  Lemma array٠unsafe_sub𑁒spec t dq vs (i n : Z) :
    (0 i)%Z
    (0 n)%Z
    (i + n length vs)%Z
    {{{
      array_model t dq vs
    }}}
      array٠unsafe_sub t #i #n
    {{{
      t'
    , RET t';
      array_model t dq vs
      array_model t' (DfracOwn 1) (take n (drop i vs))
    }}}.

  Lemma array٠sub𑁒spec_slice_fit t sz dq vs (i : Z) i_ (n : Z) :
    i_ = i
    {{{
      array_inv t sz
      ( 0 i%Z -∗
        0 n%Z -∗
        i + n sz%Z -∗
          n = length vs
          array_slice t i_ dq vs
      )
    }}}
      array٠sub t #i #n
    {{{
      t'
    , RET t';
      0 i%Z
      0 n%Z
      i + n sz%Z
      array_slice t i_ dq vs
      array_model t' (DfracOwn 1) (take n vs)
    }}}.
  Lemma array٠sub𑁒spec_slice t sz dq vs i (j n : Z) :
    {{{
      array_inv t sz
      ( 0 j%Z -∗
        0 n%Z -∗
        j + n sz%Z -∗
          i j
          j + n i + length vs
          array_slice t i dq vs
      )
    }}}
      array٠sub t #j #n
    {{{
      t'
    , RET t';
      0 j%Z
      0 n%Z
      j + n sz%Z
      array_slice t i dq vs
      array_model t' (DfracOwn 1) (take n (drop (j - i) vs))
    }}}.
  Lemma array٠sub𑁒spec t dq vs (i n : Z) :
    {{{
      array_model t dq vs
    }}}
      array٠sub t #i #n
    {{{
      t'
    , RET t';
      0 i%Z
      0 n%Z
      i + n length vs%Z
      array_model t dq vs
      array_model t' (DfracOwn 1) (take n (drop i vs))
    }}}.

  Lemma array٠unsafe_shrink𑁒spec t dq vs (n : Z) :
    (0 n length vs)%Z
    {{{
      array_model t dq vs
    }}}
      array٠unsafe_shrink t #n
    {{{
      t'
    , RET t';
      array_model t dq vs
      array_model t' (DfracOwn 1) (take n vs)
    }}}.

  Lemma array٠shrink𑁒spec t dq vs (n : Z) :
    {{{
      array_model t dq vs
    }}}
      array٠shrink t #n
    {{{
      t'
    , RET t';
      0 n length vs%Z
      array_model t dq vs
      array_model t' (DfracOwn 1) (take n vs)
    }}}.

  Lemma array٠clone𑁒spec t dq vs :
    {{{
      array_model t dq vs
    }}}
      array٠clone t
    {{{
      t'
    , RET t';
      array_model t dq vs
      array_model t' (DfracOwn 1) vs
    }}}.

  Lemma array٠unsafe_cget𑁒spec_atomic t (j : Z) :
    <<<
      True
    | ∀∀ sz i dq vs v,
      (i j)%Z
      vs !! (j - i) = Some v
      array_cslice t sz i dq vs
    >>>
      array٠unsafe_cget t #j
    <<<
      array_cslice t sz i dq vs
    | RET v;
      £ 1
    >>>.
  Lemma array٠unsafe_cget𑁒spec_atomic_weak t (i : Z) :
    (0 i)%Z
    <<<
      True
    | ∀∀ sz j dq vs,
      array_cslice t sz j dq vs
      0 < sz
      length vs = sz
    >>>
      array٠unsafe_cget t #i
    <<<
      array_cslice t sz j dq vs
    | v,
      RET v;
      £ 1
    >>>.
  Lemma array٠unsafe_cget𑁒spec_atomic_cell t sz (i : Z) :
    <<<
      True
    | ∀∀ i_ dq v,
      i = ⁺i_
      array_cslice t sz i_ dq [v]
    >>>
      array٠unsafe_cget t #i
    <<<
      array_cslice t sz i_ dq [v]
    | RET v;
      £ 1
    >>>.
  Lemma array٠unsafe_cget𑁒spec k v t sz i dq vs (j : Z) :
    (i j)%Z
    vs !! k = Some v
    k = j - i
    {{{
      array_cslice t sz i dq vs
    }}}
      array٠unsafe_cget t #j
    {{{
      RET v;
      array_cslice t sz i dq vs
    }}}.
  Lemma array٠unsafe_cget𑁒spec_cell t sz (i : Z) i_ dq v :
    i = ⁺i_
    {{{
      array_cslice t sz i_ dq [v]
    }}}
      array٠unsafe_cget t #i
    {{{
      RET v;
      array_cslice t sz i_ dq [v]
    }}}.
  Lemma array٠unsafe_cget𑁒spec_model v t dq vs (j : Z) :
    (0 j)%Z
    vs !! (j `mod` length vs) = Some v
    {{{
      array_model t dq vs
    }}}
      array٠unsafe_cget t #j
    {{{
      RET v;
      array_model t dq vs
    }}}.

  Lemma array٠cget𑁒spec_atomic t sz (j : Z) :
    <<<
      array_inv t sz
    | ∀∀ dq vs i v,
      0 j%Z -∗
      0 < sz%Z -∗
        i j
        vs !! (j - i) = Some v
        array_cslice t sz i dq vs
    >>>
      array٠cget t #j
    <<<
      array_cslice t sz i dq vs
    | RET v;
      0 j%Z
      0 < sz%Z
      £ 1
    >>>.
  Lemma array٠cget𑁒spec_atomic_weak t sz (i : Z) :
    <<<
      array_inv t sz
    | ∀∀ j dq vs,
      array_cslice t sz j dq vs
      length vs = sz
    >>>
      array٠cget t #i
    <<<
      array_cslice t sz j dq vs
    | v,
      RET v;
      £ 1
    >>>.
  Lemma array٠cget𑁒spec_atomic_cell t sz (i : Z) i_ :
    i_ = i
    <<<
      array_inv t sz
    | ∀∀ dq v,
      0 i%Z -∗
      0 < sz%Z -∗
      array_cslice t sz i_ dq [v]
    >>>
      array٠cget t #i
    <<<
      array_cslice t sz i_ dq [v]
    | RET v;
      0 i%Z
      0 < sz%Z
      £ 1
    >>>.
  Lemma array٠cget𑁒spec k v t sz i dq vs (j : Z) :
    {{{
      array_inv t sz
      ( 0 < sz -∗
        0 j%Z -∗
          i j
          vs !! k = Some v
          k = j - i
          array_cslice t sz i dq vs
      )
    }}}
      array٠cget t #j
    {{{
      RET v;
      0 < sz
      0 j%Z
      array_cslice t sz i dq vs
    }}}.
  Lemma array٠cget𑁒spec_cell t sz (i : Z) i_ dq v :
    i_ = i
    {{{
      array_inv t sz
      ( 0 < sz -∗
        0 i%Z -∗
        array_cslice t sz i_ dq [v]
      )
    }}}
      array٠cget t #i
    {{{
      RET v;
      0 < sz
      0 i%Z
      array_cslice t sz i_ dq [v]
    }}}.
  Lemma array٠cget𑁒spec_model v t dq vs (j : Z) :
    vs !! (j `mod` length vs) = Some v
    {{{
      array_model t dq vs
    }}}
      array٠cget t #j
    {{{
      RET v;
      array_model t dq vs
    }}}.

  Lemma array٠unsafe_cset𑁒spec_atomic t (j : Z) v :
    <<<
      True
    | ∀∀ sz i vs,
      i j < i + length vs%Z
      array_cslice t sz i (DfracOwn 1) vs
    >>>
      array٠unsafe_cset t #j v
    <<<
      array_cslice t sz i (DfracOwn 1) (<[j - i := v]> vs)
    | RET ();
      £ 1
    >>>.
  Lemma array٠unsafe_cset𑁒spec_atomic_cell t sz (i : Z) v :
    <<<
      True
    | ∀∀ i_ w,
      i = ⁺i_
      array_cslice t sz i_ (DfracOwn 1) [w]
    >>>
      array٠unsafe_cset t #i v
    <<<
      array_cslice t sz i_ (DfracOwn 1) [v]
    | RET ();
      £ 1
    >>>.
  Lemma array٠unsafe_cset𑁒spec t sz i vs (j : Z) v :
    (i j < i + length vs)%Z
    {{{
      array_cslice t sz i (DfracOwn 1) vs
    }}}
      array٠unsafe_cset t #j v
    {{{
      RET ();
      array_cslice t sz i (DfracOwn 1) (<[j - i := v]> vs)
    }}}.
  Lemma array٠unsafe_cset𑁒spec_cell t sz (i : Z) i_ w v :
    i = ⁺i_
    {{{
      array_cslice t sz i_ (DfracOwn 1) [w]
    }}}
      array٠unsafe_cset t #i v
    {{{
      RET ();
      array_cslice t sz i_ (DfracOwn 1) [v]
    }}}.
  Lemma array٠unsafe_cset𑁒spec_model t vs (j : Z) v :
    0 < length vs
    (0 j)%Z
    {{{
      array_model t (DfracOwn 1) vs
    }}}
      array٠unsafe_cset t #j v
    {{{
      RET ();
      array_model t (DfracOwn 1) (<[j `mod` length vs := v]> vs)
    }}}.

  Lemma array٠cset𑁒spec_atomic t sz (j : Z) v :
    <<<
      array_inv t sz
    | ∀∀ vs i,
      0 < sz -∗
      0 j%Z -∗
        i j < i + length vs
        array_cslice t sz i (DfracOwn 1) vs
    >>>
      array٠cset t #j v
    <<<
      array_cslice t sz i (DfracOwn 1) (<[j - i := v]> vs)
    | RET ();
      0 < sz
      0 j%Z
      £ 1
    >>>.
  Lemma array٠cset𑁒spec_atomic_cell t sz (i : Z) i_ v :
    i_ = i
    <<<
      array_inv t sz
    | ∀∀ w,
      0 < sz -∗
      0 i%Z -∗
      array_cslice t sz i_ (DfracOwn 1) [w]
    >>>
      array٠cset t #i v
    <<<
      array_cslice t sz i_ (DfracOwn 1) [v]
    | RET ();
      0 < sz
      0 i%Z
      £ 1
    >>>.
  Lemma array٠cset𑁒spec t sz i vs (j : Z) v :
    {{{
      array_inv t sz
      ( 0 < sz -∗
        0 j%Z -∗
          i j < i + length vs
          array_cslice t sz i (DfracOwn 1) vs
      )
    }}}
      array٠cset t #j v
    {{{
      RET ();
      0 < sz
      0 j%Z
      array_cslice t sz i (DfracOwn 1) (<[j - i := v]> vs)
    }}}.
  Lemma array٠cset𑁒spec_cell t sz (i : Z) i_ w v :
    i_ = i
    {{{
      array_inv t sz
      ( 0 < sz -∗
        0 i%Z -∗
        array_cslice t sz i_ (DfracOwn 1) [w]
      )
    }}}
      array٠cset t #i v
    {{{
      RET ();
      0 < sz
      0 i%Z
      array_cslice t sz i_ (DfracOwn 1) [v]
    }}}.
  Lemma array٠cset𑁒spec_model t vs (j : Z) v :
    {{{
      array_model t (DfracOwn 1) vs
    }}}
      array٠cset t #j v
    {{{
      RET ();
      array_model t (DfracOwn 1) (<[j `mod` length vs := v]> vs)
    }}}.

  #[local] Lemma array٠unsafe_ccopy_slice₀𑁒spec t1 (i1 : Z) i1_ dq1 vs1 t2 sz2 (i2 : Z) i2_ vs2 (n : Z) :
    0 < sz2
    i1 = ⁺i1_
    i2 = ⁺i2_
    n = length vs1
    length vs1 = length vs2
    {{{
      array_slice t1 i1_ dq1 vs1
      array_cslice t2 sz2 i2_ (DfracOwn 1) vs2
    }}}
      array٠unsafe_ccopy_slice₀ t1 #i1 t2 #i2 #n
    {{{
      RET ();
      array_slice t1 i1_ dq1 vs1
      array_cslice t2 sz2 i2_ (DfracOwn 1) vs1
    }}}.
  Lemma array٠unsafe_ccopy_slice𑁒spec_fit t1 sz1 (i1 : Z) i1_ dq1 vs1 t2 sz2 (i2 : Z) i2_ vs2 (n : Z) :
    0 < sz1
    length vs1 sz1
    0 < sz2
    i1 = ⁺i1_
    i2 = ⁺i2_
    n = length vs1
    length vs1 = length vs2
    {{{
      array_cslice t1 sz1 i1_ dq1 vs1
      array_cslice t2 sz2 i2_ (DfracOwn 1) vs2
    }}}
      array٠unsafe_ccopy_slice t1 #i1 t2 #i2 #n
    {{{
      RET ();
      array_cslice t1 sz1 i1_ dq1 vs1
      array_cslice t2 sz2 i2_ (DfracOwn 1) vs1
    }}}.
  Lemma array٠unsafe_ccopy_slice𑁒spec_fit_src t1 sz1 (i1 : Z) i1_ dq1 vs1 t2 sz2 i2 (j2 : Z) vs2 (n : Z) :
    0 < sz1
    length vs1 sz1
    0 < sz2
    i1 = ⁺i1_
    (i2 j2)%Z
    n = length vs1
    (j2 + n i2 + length vs2)%Z
    {{{
      array_cslice t1 sz1 i1_ dq1 vs1
      array_cslice t2 sz2 i2 (DfracOwn 1) vs2
    }}}
      array٠unsafe_ccopy_slice t1 #i1 t2 #j2 #n
    {{{
      RET ();
      array_cslice t1 sz1 i1_ dq1 vs1
      array_cslice t2 sz2 i2 (DfracOwn 1) (with_slice (j2 - i2) n vs2 vs1)
    }}}.
  Lemma array٠unsafe_ccopy_slice𑁒spec_fit_dst t1 sz1 i1 (j1 : Z) dq1 vs1 t2 sz2 (i2 : Z) i2_ vs2 (n : Z) :
    0 < sz1
    length vs1 sz1
    0 < sz2
    (i1 j1)%Z
    i2 = ⁺i2_
    n = length vs2
    (j1 + n i1 + length vs1)%Z
    {{{
      array_cslice t1 sz1 i1 dq1 vs1
      array_cslice t2 sz2 i2_ (DfracOwn 1) vs2
    }}}
      array٠unsafe_ccopy_slice t1 #j1 t2 #i2 #n
    {{{
      RET ();
      array_cslice t1 sz1 i1 dq1 vs1
      array_cslice t2 sz2 i2_ (DfracOwn 1) (slice (j1 - i1) n vs1)
    }}}.
  Lemma array٠unsafe_ccopy_slice𑁒spec t1 sz1 i1 (j1 : Z) dq1 vs1 t2 sz2 i2 (j2 : Z) vs2 (n : Z) :
    0 < sz1
    length vs1 sz1
    0 < sz2
    (i1 j1)%Z
    (i2 j2)%Z
    (0 n)%Z
    (j1 + n i1 + length vs1)%Z
    (j2 + n i2 + length vs2)%Z
    {{{
      array_cslice t1 sz1 i1 dq1 vs1
      array_cslice t2 sz2 i2 (DfracOwn 1) vs2
    }}}
      array٠unsafe_ccopy_slice t1 #j1 t2 #j2 #n
    {{{
      RET ();
      array_cslice t1 sz1 i1 dq1 vs1
      array_cslice t2 sz2 i2 (DfracOwn 1) (with_slice (j2 - i2) n vs2 (take n (drop (j1 - i1) vs1)))
    }}}.

  Lemma array٠ccopy_slice𑁒spec_fit t1 sz1 (i1 : Z) i1_ dq1 vs1 t2 sz2 (i2 : Z) i2_ vs2 (n : Z) :
    i1_ = i1
    i2_ = i2
    {{{
      array_inv t1 sz1
      array_inv t2 sz2
      ( 0 < sz1 -∗
        0 < sz2 -∗
        0 i1%Z -∗
        0 i2%Z -∗
        0 n%Z -∗
        n sz1%Z -∗
        n sz2%Z -∗
          n = length vs1
          length vs1 = length vs2
          array_cslice t1 sz1 i1_ dq1 vs1
          array_cslice t2 sz2 i2_ (DfracOwn 1) vs2
      )
    }}}
      array٠ccopy_slice t1 #i1 t2 #i2 #n
    {{{
      RET ();
      0 < sz1
      0 < sz2
      0 i1%Z
      0 i2%Z
      0 n%Z
      n sz1%Z
      n sz2%Z
      array_cslice t1 sz1 i1_ dq1 vs1
      array_cslice t2 sz2 i2_ (DfracOwn 1) vs1
    }}}.
  Lemma array٠ccopy_slice𑁒spec t1 sz1 i1 (j1 : Z) dq1 vs1 t2 sz2 i2 (j2 : Z) vs2 (n : Z) :
    {{{
      array_inv t1 sz1
      array_inv t2 sz2
      ( 0 < sz1 -∗
        0 < sz2 -∗
        0 j1%Z -∗
        0 j2%Z -∗
        0 n%Z -∗
        n sz1%Z -∗
        n sz2%Z -∗
          length vs1 sz1
          i1 j1
          i2 j2
          j1 + n i1 + length vs1%Z
          j2 + n i2 + length vs2%Z
          array_cslice t1 sz1 i1 dq1 vs1
          array_cslice t2 sz2 i2 (DfracOwn 1) vs2
      )
    }}}
      array٠ccopy_slice t1 #j1 t2 #j2 #n
    {{{
      RET ();
      0 < sz1
      0 < sz2
      0 j1%Z
      0 j2%Z
      0 n%Z
      n sz1%Z
      n sz2%Z
      array_cslice t1 sz1 i1 dq1 vs1
      array_cslice t2 sz2 i2 (DfracOwn 1) (with_slice (j2 - i2) n vs2 (take n (drop (j1 - i1) vs1)))
    }}}.

  Lemma array٠unsafe_ccopy𑁒spec_fit t1 sz1 (i1 : Z) i1_ dq1 vs1 t2 sz2 (i2 : Z) i2_ vs2 :
    0 < sz1
    0 < sz2
    i1 = ⁺i1_
    i2 = ⁺i2_
    length vs1 = sz1
    length vs1 = length vs2
    {{{
      array_cslice t1 sz1 i1_ dq1 vs1
      array_cslice t2 sz2 i2_ (DfracOwn 1) vs2
    }}}
      array٠unsafe_ccopy t1 #i1 t2 #i2
    {{{
      RET ();
      array_cslice t1 sz1 i1_ dq1 vs1
      array_cslice t2 sz2 i2_ (DfracOwn 1) vs1
    }}}.
  Lemma array٠unsafe_ccopy𑁒spec t1 sz1 (i1 : Z) i1_ dq1 vs1 t2 sz2 i2 (j2 : Z) vs2 :
    0 < sz1
    0 < sz2
    i1 = ⁺i1_
    length vs1 = sz1
    (i2 j2)%Z
    (j2 + length vs1 i2 + length vs2)%Z
    {{{
      array_cslice t1 sz1 i1_ dq1 vs1
      array_cslice t2 sz2 i2 (DfracOwn 1) vs2
    }}}
      array٠unsafe_ccopy t1 #i1 t2 #j2
    {{{
      RET ();
      array_cslice t1 sz1 i1_ dq1 vs1
      array_cslice t2 sz2 i2 (DfracOwn 1) (with_slice (j2 - i2) (length vs1) vs2 vs1)
    }}}.

  Lemma array٠ccopy𑁒spec_fit t1 sz1 (i1 : Z) i1_ dq1 vs1 t2 sz2 (i2 : Z) i2_ vs2 :
    i1_ = i1
    i2_ = i2
    length vs1 = sz1
    length vs1 = length vs2
    {{{
      array_inv t1 sz1
      array_inv t2 sz2
      ( 0 < sz1 -∗
        0 < sz2 -∗
        0 i1%Z -∗
        0 i2%Z -∗
          array_cslice t1 sz1 i1_ dq1 vs1
          array_cslice t2 sz2 i2_ (DfracOwn 1) vs2
      )
    }}}
      array٠ccopy t1 #i1 t2 #i2
    {{{
      RET ();
      0 < sz1
      0 < sz2
      0 i1%Z
      0 i2%Z
      array_cslice t1 sz1 i1_ dq1 vs1
      array_cslice t2 sz2 i2_ (DfracOwn 1) vs1
    }}}.
  Lemma array٠ccopy𑁒spec t1 sz1 (i1 : Z) dq1 vs1 t2 sz2 i2 (j2 : Z) vs2 :
    length vs1 = sz1
    {{{
      array_inv t1 sz1
      array_inv t2 sz2
      ( 0 < sz1 -∗
        0 < sz2 -∗
        0 i1%Z -∗
        0 j2%Z -∗
          i2 j2%Z
          j2 + length vs1 i2 + length vs2%Z
          array_cslice t1 sz1 i1 dq1 vs1
          array_cslice t2 sz2 i2 (DfracOwn 1) vs2
      )
    }}}
      array٠ccopy t1 #i1 t2 #j2
    {{{
      RET ();
      0 < sz1
      0 < sz2
      0 i1%Z
      0 j2%Z
      array_cslice t1 sz1 i1 dq1 vs1
      array_cslice t2 sz2 i2 (DfracOwn 1) (with_slice (j2 - i2) (length vs1) vs2 vs1)
    }}}.

  Lemma array٠unsafe_cgrow_slice𑁒spec t sz (i : Z) i_ dq vs (n : Z) sz' v :
    0 < sz
    length vs sz
    i = ⁺i_
    n = (length vs)
    (0 < sz')%Z
    (n sz')%Z
    {{{
      array_cslice t sz i_ dq vs
    }}}
      array٠unsafe_cgrow_slice t #i #n #sz' v
    {{{
      t'
    , RET t';
      array_cslice t sz i_ dq vs
      array_cslice t' sz' i_ (DfracOwn 1) (vs ++ replicate (sz' - n) v)
    }}}.

  Lemma array٠unsafe_cgrow𑁒spec t (sz : nat) (i : Z) i_ dq vs sz' v :
    0 < sz
    i = ⁺i_
    length vs = sz
    (0 < sz')%Z
    (sz sz')%Z
    {{{
      array_cslice t sz i_ dq vs
    }}}
      array٠unsafe_cgrow t #i #sz' v
    {{{
      t'
    , RET t';
      array_cslice t sz i_ dq vs
      array_cslice t' sz' i_ (DfracOwn 1) (vs ++ replicate (sz' - sz) v)
    }}}.

  Lemma array٠unsafe_cshrink_slice𑁒spec_fit t sz (i : Z) i_ dq vs sz' :
    0 < sz
    length vs sz
    i = ⁺i_
    (0 < sz' length vs)%Z
    {{{
      array_cslice t sz i_ dq vs
    }}}
      array٠unsafe_cshrink_slice t #i #sz'
    {{{
      t'
    , RET t';
      array_cslice t sz i_ dq vs
      array_cslice t' sz' i_ (DfracOwn 1) (take sz' vs)
    }}}.
  Lemma array٠unsafe_cshrink_slice𑁒spec t sz i dq vs (j : Z) sz' :
    0 < sz
    length vs sz
    (i j)%Z
    (0 < sz')%Z
    (j + sz' i + length vs)%Z
    {{{
      array_cslice t sz i dq vs
    }}}
      array٠unsafe_cshrink_slice t #j #sz'
    {{{
      t'
    , RET t';
      array_cslice t sz i dq vs
      array_cslice t' sz' j (DfracOwn 1) (slice (j - i) sz' vs)
    }}}.

  Definition itype_array τ `{!iType _ τ} (sz : nat) t : iProp Σ :=
     l,
    t = #l
    l ↦ₕ Header 0 sz
    itype_chunk τ sz l.
  #[global] Instance itype_array_itype τ `{!iType _ τ} sz :
    iType _ (itype_array τ sz).

  Lemma itype_array_intro τ `{!iType _ τ} t vs :
    array_model t (DfracOwn 1) vs -∗
    ([∗ list] v vs, τ v) ={}=∗
    itype_array τ (length vs) t.
  Lemma itype_array_intro_slice τ `{!iType _ τ} t sz vs :
    length vs = sz
    array_inv t sz -∗
    array_slice t 0 (DfracOwn 1) vs -∗
    ([∗ list] v vs, τ v) ={}=∗
    itype_array τ sz t.
  Lemma itype_array_intro_cslice τ `{!iType _ τ} t sz i vs :
    0 < sz
    length vs = sz
    array_cslice t sz i (DfracOwn 1) vs -∗
    ([∗ list] v vs, τ v) ={}=∗
    itype_array τ sz t.
  Lemma itype_array_to_inv τ `{!iType _ τ} sz t :
    itype_array τ sz t
    array_inv t sz.

  Lemma array٠create𑁒type τ `{!iType _ τ} :
    {{{
      True
    }}}
      array٠create ()
    {{{
      t
    , RET t;
      itype_array τ 0 t
    }}}.

  Lemma array٠size𑁒type τ `{!iType _ τ} t sz :
    {{{
      itype_array τ sz t
    }}}
      array٠size t
    {{{
      RET #sz;
      True
    }}}.

  Lemma array٠unsafe_get𑁒type τ `{!iType _ τ} t (sz : nat) (i : Z) :
    (0 i < sz)%Z
    {{{
      itype_array τ sz t
    }}}
      array٠unsafe_get t #i
    {{{
      v
    , RET v;
      τ v
    }}}.

  Lemma array٠get𑁒type τ `{!iType _ τ} t sz (i : Z) :
    {{{
      itype_array τ sz t
    }}}
      array٠get t #i
    {{{
      v
    , RET v;
      0 i < sz%Z
      τ v
    }}}.

  Lemma array٠unsafe_set𑁒type τ `{!iType _ τ} t (sz : nat) (i : Z) v :
    (0 i < sz)%Z
    {{{
      itype_array τ sz t
      τ v
    }}}
      array٠unsafe_set t #i v
    {{{
      RET ();
      True
    }}}.

  Lemma array٠set𑁒type τ `{!iType _ τ} t sz (i : Z) v :
    {{{
      itype_array τ sz t
      τ v
    }}}
      array٠set t #i v
    {{{
      RET ();
      0 i < sz%Z
    }}}.

  Lemma array٠unsafe_xchg𑁒type τ `{!iType _ τ} t (sz : nat) (i : Z) v :
    (0 i < sz)%Z
    {{{
      itype_array τ sz t
      τ v
    }}}
      array٠unsafe_xchg t #i v
    {{{
      w
    , RET w;
      τ w
    }}}.

  Lemma array٠unsafe_cas𑁒type τ `{!iType _ τ} t (sz : nat) (i : Z) v1 v2 :
    (0 i < sz)%Z
    {{{
      itype_array τ sz t
      τ v1
      τ v2
    }}}
      array٠unsafe_cas t #i v1 v2
    {{{
      b
    , RET #b;
      True
    }}}.

  Lemma array٠unsafe_fill_slice𑁒type τ `{!iType _ τ} t (sz : nat) (i n : Z) v :
    (0 i)%Z
    (0 n)%Z
    (i + n sz)%Z
    {{{
      itype_array τ sz t
      τ v
    }}}
      array٠unsafe_fill_slice t #i #n v
    {{{
      RET ();
      True
    }}}.

  Lemma array٠fill_slice𑁒type τ `{!iType _ τ} t sz (i n : Z) v :
    {{{
      itype_array τ sz t
      τ v
    }}}
      array٠fill_slice t #i #n v
    {{{
      RET ();
      0 i%Z
      0 n%Z
      i + n sz%Z
    }}}.

  Lemma array٠fill𑁒type τ `{!iType _ τ} t sz v :
    {{{
      itype_array τ sz t
      τ v
    }}}
      array٠fill t v
    {{{
      RET ();
      True
    }}}.

  Lemma array٠unsafe_make𑁒type τ `{!iType _ τ} sz v :
    (0 sz)%Z
    {{{
      τ v
    }}}
      array٠unsafe_make #sz v
    {{{
      t
    , RET t;
      itype_array τ sz t
    }}}.

  Lemma array٠make𑁒type τ `{!iType _ τ} sz v :
    {{{
      τ v
    }}}
      array٠make #sz v
    {{{
      t
    , RET t;
      0 sz%Z
      itype_array τ sz t
    }}}.

  Lemma array٠foldli𑁒type τ `{!iType _ τ} υ `{!iType _ υ} fn acc t sz :
    {{{
      itype_array τ sz t
      υ acc
      (itype_nat_upto sz --> υ --> τ --> υ)%T fn
    }}}
      array٠foldli fn acc t
    {{{
      acc'
    , RET acc';
      υ acc'
    }}}.

  Lemma array٠foldl𑁒type τ `{!iType _ τ} υ `{!iType _ υ} fn acc t sz :
    {{{
      itype_array τ sz t
      υ acc
      (υ --> τ --> υ)%T fn
    }}}
      array٠foldl fn acc t
    {{{
      acc'
    , RET acc';
      υ acc'
    }}}.

  Lemma array٠foldri𑁒type τ `{!iType _ τ} υ `{!iType _ υ} fn acc t sz :
    {{{
      itype_array τ sz t
      (itype_nat_upto sz --> τ --> υ --> υ)%T fn
      υ acc
    }}}
      array٠foldri fn t acc
    {{{
      acc'
    , RET acc';
      υ acc'
    }}}.

  Lemma array٠foldr𑁒type τ `{!iType _ τ} υ `{!iType _ υ} fn t sz acc :
    {{{
      itype_array τ sz t
      (τ --> υ --> υ)%T fn
      υ acc
    }}}
      array٠foldr fn t acc
    {{{
      acc'
    , RET acc';
      υ acc'
    }}}.

  Lemma array٠unsafe_iteri_slice𑁒type τ `{!iType _ τ} fn t (sz : nat) (i n : Z) :
    (0 i sz)%Z
    (0 n)%Z
    (i + n sz)%Z
    {{{
      itype_array τ sz t
      (itype_nat_upto n --> τ --> itype_unit)%T fn
    }}}
      array٠unsafe_iteri_slice fn t #i #n
    {{{
      RET ();
      True
    }}}.

  Lemma array٠iteri_slice𑁒type τ `{!iType _ τ} fn t (sz : nat) (i n : Z) :
    {{{
      itype_array τ sz t
      (itype_nat_upto n --> τ --> itype_unit)%T fn
    }}}
      array٠iteri_slice fn t #i #n
    {{{
      RET ();
      0 i sz%Z
      0 n%Z
      i + n sz%Z
    }}}.

  Lemma array٠unsafe_iter_slice𑁒type τ `{!iType _ τ} fn t (sz : nat) (i n : Z) :
    (0 i sz)%Z
    (0 n)%Z
    (i + n sz)%Z
    {{{
      itype_array τ sz t
      (τ --> itype_unit)%T fn
    }}}
      array٠unsafe_iter_slice fn t #i #n
    {{{
      RET ();
      True
    }}}.

  Lemma array٠iter_slice𑁒type τ `{!iType _ τ} fn t (sz : nat) (i n : Z) :
    {{{
      itype_array τ sz t
      (τ --> itype_unit)%T fn
    }}}
      array٠iter_slice fn t #i #n
    {{{
      RET ();
      0 i sz%Z
      0 n%Z
      i + n sz%Z
    }}}.

  Lemma array٠iteri𑁒type τ `{!iType _ τ} fn t sz :
    {{{
      itype_array τ sz t
      (itype_nat_upto sz --> τ --> itype_unit)%T fn
    }}}
      array٠iteri fn t
    {{{
      RET ();
      True
    }}}.

  Lemma array٠iter𑁒type τ `{!iType _ τ} fn t sz :
    {{{
      itype_array τ sz t
      (τ --> itype_unit)%T fn
    }}}
      array٠iter fn t
    {{{
      RET ();
      True
    }}}.

  Lemma array٠unsafe_applyi_slice𑁒type τ `{!iType _ τ} fn t (sz : nat) (i n : Z) :
    (0 i sz)%Z
    (0 n)%Z
    (i + n sz)%Z
    {{{
      itype_array τ sz t
      (itype_nat_upto n --> τ --> τ)%T fn
    }}}
      array٠unsafe_applyi_slice fn t #i #n
    {{{
      RET ();
      True
    }}}.

  Lemma array٠applyi_slice𑁒type τ `{!iType _ τ} fn t (sz : nat) (i n : Z) :
    {{{
      itype_array τ sz t
      (itype_nat_upto n --> τ --> τ)%T fn
    }}}
      array٠applyi_slice fn t #i #n
    {{{
      RET ();
      0 i sz%Z
      0 n%Z
      i + n sz%Z
    }}}.

  Lemma array٠unsafe_apply_slice𑁒type τ `{!iType _ τ} fn t (sz : nat) (i n : Z) :
    (0 i sz)%Z
    (0 n)%Z
    (i + n sz)%Z
    {{{
      itype_array τ sz t
      (τ --> τ)%T fn
    }}}
      array٠unsafe_apply_slice fn t #i #n
    {{{
      RET ();
      True
    }}}.

  Lemma array٠apply_slice𑁒type τ `{!iType _ τ} fn t (sz : nat) (i n : Z) :
    {{{
      itype_array τ sz t
      (τ --> τ)%T fn
    }}}
      array٠apply_slice fn t #i #n
    {{{
      RET ();
      0 i sz%Z
      0 n%Z
      i + n sz%Z
    }}}.

  Lemma array٠applyi𑁒type τ `{!iType _ τ} fn t sz :
    {{{
      itype_array τ sz t
      (itype_nat_upto sz --> τ --> τ)%T fn
    }}}
      array٠applyi fn t
    {{{
      RET ();
      True
    }}}.

  Lemma array٠apply𑁒type τ `{!iType _ τ} fn t sz :
    {{{
      itype_array τ sz t
      (τ --> τ)%T fn
    }}}
      array٠apply fn t
    {{{
      RET ();
      True
    }}}.

  Lemma array٠unsafe_initi𑁒type τ `{!iType _ τ} sz sz_ fn :
    sz = ⁺sz_
    {{{
      (itype_nat_upto sz_ --> τ)%T fn
    }}}
      array٠unsafe_initi #sz fn
    {{{
      t
    , RET t;
      itype_array τ sz_ t
    }}}.

  Lemma array٠initi𑁒type τ `{!iType _ τ} sz fn :
    {{{
      (itype_nat_upto sz --> τ)%T fn
    }}}
      array٠initi #sz fn
    {{{
      t
    , RET t;
      0 sz%Z
      itype_array τ sz t
    }}}.

  Lemma array٠unsafe_init𑁒type τ `{!iType _ τ} sz fn :
    (0 sz)%Z
    {{{
      (itype_unit --> τ)%T fn
    }}}
      array٠unsafe_init #sz fn
    {{{
      t
    , RET t;
      itype_array τ sz t
    }}}.

  Lemma array٠init𑁒type τ `{!iType _ τ} sz fn :
    {{{
      (itype_unit --> τ)%T fn
    }}}
      array٠init #sz fn
    {{{
      t
    , RET t;
      0 sz%Z
      itype_array τ sz t
    }}}.

  Lemma array٠mapi𑁒type τ `{!iType _ τ} υ `{!iType _ υ} fn t sz sz_ :
    sz_ = ⁺sz
    {{{
      itype_array τ sz t
      (itype_nat_upto sz --> τ --> υ)%T fn
    }}}
      array٠mapi fn t
    {{{
      t'
    , RET t';
      itype_array υ sz t'
    }}}.

  Lemma array٠map𑁒type τ `{!iType _ τ} υ `{!iType _ υ} fn t sz sz_ :
    sz_ = ⁺sz
    {{{
      itype_array τ sz t
      (τ --> υ)%T fn
    }}}
      array٠map fn t
    {{{
      t'
    , RET t';
      itype_array υ sz t'
    }}}.

  Lemma array٠unsafe_copy_slice𑁒type τ `{!iType _ τ} t1 (sz1 : nat) (i1 : Z) t2 (sz2 : nat) (i2 n : Z) :
    (0 i1)%Z
    (0 i2)%Z
    (0 n)%Z
    (i1 + n sz1)%Z
    (i2 + n sz2)%Z
    {{{
      itype_array τ sz1 t1
      itype_array τ sz2 t2
    }}}
      array٠unsafe_copy_slice t1 #i1 t2 #i2 #n
    {{{
      RET ();
      True
    }}}.
  Lemma array٠unsafe_copy_slice𑁒type' τ `{!iType _ τ} t1 (sz : nat) (i1 : Z) t2 (i2 : Z) i2_ vs (n : Z) :
    (0 i1)%Z
    i2 = ⁺i2_
    n = length vs
    (i1 + n sz)%Z
    {{{
      itype_array τ sz t1
      array_slice t2 i2_ (DfracOwn 1) vs
    }}}
      array٠unsafe_copy_slice t1 #i1 t2 #i2 #n
    {{{
      ws
    , RET ();
      length ws = length vs
      array_slice t2 i2_ (DfracOwn 1) ws
      [∗ list] w ws, τ w
    }}}.

  Lemma array٠copy_slice𑁒type τ `{!iType _ τ} t1 sz1 (i1 : Z) t2 sz2 (i2 n : Z) :
    {{{
      itype_array τ sz1 t1
      itype_array τ sz2 t2
    }}}
      array٠copy_slice t1 #i1 t2 #i2 #n
    {{{
      RET ();
      0 i1%Z
      0 i2%Z
      0 n%Z
      i1 + n sz1%Z
      i2 + n sz2%Z
    }}}.

  Lemma array٠unsafe_copy𑁒type τ `{!iType _ τ} t1 (sz1 : nat) t2 (sz2 : nat) (i2 : Z) :
    (0 i2)%Z
    (i2 + sz1 sz2)%Z
    {{{
      itype_array τ sz1 t1
      itype_array τ sz2 t2
    }}}
      array٠unsafe_copy t1 t2 #i2
    {{{
      RET ();
      i2 + sz1 sz2%Z
    }}}.
  Lemma array٠unsafe_copy𑁒type' τ `{!iType _ τ} t1 sz t2 (i2 : Z) i2_ vs :
    i2 = ⁺i2_
    sz = length vs
    {{{
      itype_array τ sz t1
      array_slice t2 i2_ (DfracOwn 1) vs
    }}}
      array٠unsafe_copy t1 t2 #i2
    {{{
      ws
    , RET ();
      length ws = length vs
      array_slice t2 i2_ (DfracOwn 1) ws
      [∗ list] w ws, τ w
    }}}.

  Lemma array٠copy𑁒type τ `{!iType _ τ} t1 sz1 t2 sz2 (i2 : Z) :
    {{{
      itype_array τ sz1 t1
      itype_array τ sz2 t2
    }}}
      array٠copy t1 t2 #i2
    {{{
      RET ();
      0 i2%Z
      i2 + sz1 sz2%Z
    }}}.

  Lemma array٠unsafe_grow𑁒type τ `{!iType _ τ} t (sz : nat) sz' v' :
    (sz sz')%Z
    {{{
      itype_array τ sz t
      τ v'
    }}}
      array٠unsafe_grow t #sz' v'
    {{{
      t'
    , RET t';
      itype_array τ sz' t'
    }}}.

  Lemma array٠grow𑁒type τ `{!iType _ τ} t sz sz' v' :
    {{{
      itype_array τ sz t
      τ v'
    }}}
      array٠grow t #sz' v'
    {{{
      t'
    , RET t';
      sz sz'
      itype_array τ sz' t'
    }}}.

  Lemma array٠unsafe_sub𑁒type τ `{!iType _ τ} t (sz : nat) (i n : Z) :
    (0 i)%Z
    (0 n)%Z
    (i + n sz)%Z
    {{{
      itype_array τ sz t
    }}}
      array٠unsafe_sub t #i #n
    {{{
      t'
    , RET t';
      itype_array τ n t'
    }}}.
  Lemma array٠sub𑁒type τ `{!iType _ τ} t sz (i n : Z) :
    {{{
      itype_array τ sz t
    }}}
      array٠sub t #i #n
    {{{
      t'
    , RET t';
      0 i%Z
      0 n%Z
      i + n sz%Z
      itype_array τ n t'
    }}}.

  Lemma array٠unsafe_shrink𑁒type τ `{!iType _ τ} t (sz : nat) (n : Z) :
    (0 n sz)%Z
    {{{
      itype_array τ sz t
    }}}
      array٠unsafe_shrink t #n
    {{{
      t'
    , RET t';
      itype_array τ n t'
    }}}.

  Lemma array٠shrink𑁒type τ `{!iType _ τ} t sz (n : Z) :
    {{{
      itype_array τ sz t
    }}}
      array٠shrink t #n
    {{{
      t'
    , RET t';
      0 n sz%Z
      itype_array τ n t'
    }}}.

  Lemma array٠clone𑁒type τ `{!iType _ τ} t sz :
    {{{
      itype_array τ sz t
    }}}
      array٠clone t
    {{{
      t'
    , RET t';
      itype_array τ sz t'
    }}}.

  Lemma array٠unsafe_cget𑁒type τ `{!iType _ τ} t sz (i : Z) :
    0 < sz
    (0 i)%Z
    {{{
      itype_array τ sz t
    }}}
      array٠unsafe_cget t #i
    {{{
      v
    , RET v;
      τ v
    }}}.
  Lemma array٠cget𑁒type τ `{!iType _ τ} t sz (i : Z) :
    {{{
      itype_array τ sz t
    }}}
      array٠cget t #i
    {{{
      v
    , RET v;
      0 < sz
      0 i%Z
      τ v
    }}}.

  Lemma array٠unsafe_cset𑁒type τ `{!iType _ τ} t sz (i : Z) v :
    0 < sz
    (0 i)%Z
    {{{
      itype_array τ sz t
      τ v
    }}}
      array٠unsafe_cset t #i v
    {{{
      RET ();
      True
    }}}.
  Lemma array٠cset𑁒type τ `{!iType _ τ} t sz (i : Z) v :
    {{{
      itype_array τ sz t
      τ v
    }}}
      array٠cset t #i v
    {{{
      RET ();
      0 < sz
      0 i%Z
    }}}.

  #[local] Lemma array٠unsafe_ccopy_slice₀𑁒type τ `{!iType _ τ} t1 sz1 (i1 : Z) t2 sz2 (i2 n : Z) :
    0 < sz1
    0 < sz2
    (0 i1)%Z
    (0 i2)%Z
    (0 n)%Z
    (i1 + n sz1)%Z
    (n sz2)%Z
    {{{
      itype_array τ sz1 t1
      itype_array τ sz2 t2
    }}}
      array٠unsafe_ccopy_slice₀ t1 #i1 t2 #i2 #n
    {{{
      RET ();
      True
    }}}.
  Lemma array٠unsafe_ccopy_slice𑁒type τ `{!iType _ τ} t1 sz1 (i1 : Z) t2 sz2 (i2 n : Z) :
    0 < sz1
    0 < sz2
    (0 i1)%Z
    (0 i2)%Z
    (0 n)%Z
    (n sz1)%Z
    (n sz2)%Z
    {{{
      itype_array τ sz1 t1
      itype_array τ sz2 t2
    }}}
      array٠unsafe_ccopy_slice t1 #i1 t2 #i2 #n
    {{{
      RET ();
      True
    }}}.
  #[local] Lemma array٠unsafe_ccopy_slice₀𑁒type' τ `{!iType _ τ} t1 sz1 (i1 : Z) t2 sz2 (i2 : Z) i2_ vs (n : Z) :
    0 < sz1
    0 < sz2
    length vs sz2
    (0 i1)%Z
    (i1 + length vs sz1)%Z
    i2 = ⁺i2_
    n = length vs
    {{{
      itype_array τ sz1 t1
      array_cslice t2 sz2 i2_ (DfracOwn 1) vs
    }}}
      array٠unsafe_ccopy_slice₀ t1 #i1 t2 #i2 #n
    {{{
      ws
    , RET ();
      length ws = length vs
      array_cslice t2 sz2 i2_ (DfracOwn 1) ws
      [∗ list] w ws, τ w
    }}}.
  Lemma array٠unsafe_ccopy_slice𑁒type' τ `{!iType _ τ} t1 sz1 (i1 : Z) t2 sz2 (i2 : Z) i2_ vs (n : Z) :
    0 < sz1
    length vs sz1
    0 < sz2
    length vs sz2
    (0 i1)%Z
    i2 = ⁺i2_
    n = length vs
    {{{
      itype_array τ sz1 t1
      array_cslice t2 sz2 i2_ (DfracOwn 1) vs
    }}}
      array٠unsafe_ccopy_slice t1 #i1 t2 #i2 #n
    {{{
      ws
    , RET ();
      length ws = length vs
      array_cslice t2 sz2 i2_ (DfracOwn 1) ws
      [∗ list] w ws, τ w
    }}}.

  Lemma array٠ccopy_slice𑁒type τ `{!iType _ τ} t1 sz1 (i1 : Z) t2 sz2 (i2 : Z) (n : Z) :
    0 < sz1
    0 < sz2
    {{{
      itype_array τ sz1 t1
      itype_array τ sz2 t2
    }}}
      array٠ccopy_slice t1 #i1 t2 #i2 #n
    {{{
      RET ();
      0 < sz1
      0 < sz2
      0 i1%Z
      0 i2%Z
    }}}.

  Lemma array٠unsafe_ccopy𑁒type τ `{!iType _ τ} t1 sz1 (i1 : Z) t2 sz2 (i2 : Z) :
    0 < sz1
    0 < sz2
    sz1 sz2
    (0 i1)%Z
    (0 i2)%Z
    {{{
      itype_array τ sz1 t1
      itype_array τ sz2 t2
    }}}
      array٠unsafe_ccopy t1 #i1 t2 #i2
    {{{
      RET ();
      True
    }}}.

  Lemma array٠ccopy𑁒type τ `{!iType _ τ} t1 sz1 (i1 : Z) t2 sz2 (i2 : Z) :
    {{{
      itype_array τ sz1 t1
      itype_array τ sz2 t2
    }}}
      array٠ccopy t1 #i1 t2 #i2
    {{{
      RET ();
      0 < sz1
      0 < sz2
      0 i1%Z
      0 i2%Z
    }}}.

  Lemma array٠unsafe_cgrow_slice𑁒type τ `{!iType _ τ} sz t (i n : Z) sz' v :
    0 < sz
    (0 i)%Z
    (0 n)%Z
    (0 < sz')%Z
    (n sz)%Z
    (n sz')%Z
    {{{
      itype_array τ sz t
      τ v
    }}}
      array٠unsafe_cgrow_slice t #i #n #sz' v
    {{{
      t'
    , RET t';
      itype_array τ sz' t'
    }}}.

  Lemma array٠unsafe_cgrow𑁒type τ `{!iType _ τ} sz t (i n : Z) sz' v :
    0 < sz
    (0 i)%Z
    (0 < sz')%Z
    (sz sz')%Z
    {{{
      itype_array τ sz t
      τ v
    }}}
      array٠unsafe_cgrow t #i #sz' v
    {{{
      t'
    , RET t';
      itype_array τ sz' t'
    }}}.

  Lemma array٠unsafe_cshrink_slice𑁒type τ `{!iType _ τ} sz t (i : Z) sz' :
    0 < sz
    (0 i)%Z
    (0 < sz')%Z
    (sz' sz)%Z
    {{{
      itype_array τ sz t
    }}}
      array٠unsafe_cshrink_slice t #i #sz'
    {{{
      t'
    , RET t';
      itype_array τ sz' t'
    }}}.
End zoo_G.

From zoo_std Require
  array__opaque.
#[global] Opaque array٠unsafe_xchg.
#[global] Opaque array٠unsafe_cas.
#[global] Opaque array٠unsafe_faa.

#[global] Opaque array_inv.
#[global] Opaque array_slice.
#[global] Opaque array_model.
#[global] Opaque array_cslice.
#[global] Opaque itype_array.