Library zoo_saturn.bag_2

Require Import zoo.prelude.
Require Import zoo.common.countable.
Require Import zoo.common.fin_maps.
Require Import zoo.iris.bi.big_op.
Require Import zoo.iris.base_logic.lib.mono_gmap.
Require Import zoo.iris.base_logic.lib.twins.
Require Import zoo.base.
Require Import zoo_std.option.
Require Import zoo_std.xtchain.
Require Export zoo_saturn.bag_2__code.
Require Import zoo_saturn.bag_2__types.
Require Import zoo.options.

Implicit Type l node π‘π‘œπ‘›π‘ π‘’π‘šπ‘’π‘Ÿ : location.
Implicit Type nodes : list location.
Implicit Type v t producer consumer : val.
Implicit Type o : option val.
Implicit Type vs ws : list val.
Implicit Type vss wss : gmap val (list val).

Class Bag2G Ξ£ `{zooΫ°G : !ZooG Ξ£} :=
  { #[local] bag_2Ϋ°GΫ°queue_spmcΫ°G :: QueueSpmcG Ξ£
  ; #[local] bag_2Ϋ°GΫ°queuesΫ°G :: MonoGmapG Ξ£ location val
  ; #[local] bag_2Ϋ°GΫ°modelΫ°G :: TwinsG Ξ£ (leibnizO (gmap val (list val)))
  }.

Definition bag_2Ϋ°Ξ£ :=
  #[queue_spmcΫ°Ξ£
  ; mono_gmapΫ°Ξ£ location val
  ; twinsΫ°Ξ£ (leibnizO (gmap val (list val)))
  ].
#[global] Instance subGο½°bag_2Ϋ°Ξ£ Ξ£ `{zooΫ°G : !ZooG Ξ£} :
  subG bag_2Ϋ°Ξ£ Ξ£ β†’
  Bag2G Ξ£.

Record producer :=
  { producerΫ°queue : val
  ; producerΫ°node : location
  }.
Implicit Type π‘π‘Ÿπ‘œπ‘‘π‘’π‘π‘’π‘Ÿ : producer.

#[local] Coercion producerΫ°to_val π‘π‘Ÿπ‘œπ‘‘π‘’π‘π‘’π‘Ÿ : val :=
  ( π‘π‘Ÿπ‘œπ‘‘π‘’π‘π‘’π‘Ÿ.(producerΫ°queue),
    #π‘π‘Ÿπ‘œπ‘‘π‘’π‘π‘’π‘Ÿ.(producerΫ°node)
  ).

#[local] Lemma producerο½°eqο½°alt π‘π‘Ÿπ‘œπ‘‘π‘’π‘π‘’π‘Ÿ1 π‘π‘Ÿπ‘œπ‘‘π‘’π‘π‘’π‘Ÿ2 :
  π‘π‘Ÿπ‘œπ‘‘π‘’π‘π‘’π‘Ÿ1.(producerΫ°queue) = π‘π‘Ÿπ‘œπ‘‘π‘’π‘π‘’π‘Ÿ2.(producerΫ°queue) β†’
  π‘π‘Ÿπ‘œπ‘‘π‘’π‘π‘’π‘Ÿ1.(producerΫ°node) = π‘π‘Ÿπ‘œπ‘‘π‘’π‘π‘’π‘Ÿ2.(producerΫ°node) β†’
  π‘π‘Ÿπ‘œπ‘‘π‘’π‘π‘’π‘Ÿ1 = π‘π‘Ÿπ‘œπ‘‘π‘’π‘π‘’π‘Ÿ2.
#[local] Instance producerΫ°to_valο½°inj :
  Inj (=) (=) producerΫ°to_val.

Record descriptor :=
  { descriptorΫ°queue : val
  ; descriptorΫ°vals : list val
  }.
Implicit Type descr : descriptor.
Implicit Type descrs : gmap location descriptor.

#[local] Definition descriptorΫ°update_vals descr f :=
  {|descriptorΫ°queue := descr.(descriptorΫ°queue)
  ; descriptorΫ°vals := f descr.(descriptorΫ°vals)
  |}.

#[local] Definition descriptorΫ°to_producer descr node :=
  {|producerΫ°queue := descr.(descriptorΫ°queue)
  ; producerΫ°node := node
  |}.

#[local] Lemma descriptorΫ°to_producerο½°inj descr1 node1 descr2 node2 :
  descriptorΫ°to_producer descr1 node1 = descriptorΫ°to_producer descr2 node2 β†’
  node1 = node2.

Section bag_2Ϋ°G.
  Context `{bag_2Ϋ°G : Bag2G Ξ£}.

  Record metadata :=
    { metadataΫ°inv : namespace
    ; metadataΫ°model : gname
    ; metadataΫ°queues : gname
    }.
  Implicit Type Ξ³ : metadata.

  #[local] Instance metadataο½°eq_dec : EqDecision metadata :=
    ltac:(solve_decision).
  #[local] Instance metadataο½°countable :
    Countable metadata.

  #[local] Definition queuesΫ°auth' Ξ³_queues nodes descrs wss : iProp Ξ£ :=
    mono_gmapΫ°auth Ξ³_queues (DfracOwn 1) (descriptorΫ°queue <$> descrs) βˆ—
    βŒœdom descrs = list_to_set nodes⌝ βˆ—
    βŒœ map_Forall (Ξ» node descr,
        wss !! (descriptorΫ°to_producer descr node : val) = Some descr.(descriptorΫ°vals)
      ) descrs
    βŒ.
  #[local] Instance : CustomIpat "queuesΫ°auth" :=
    " ( Hauth & %Hnodes & %Hdescrs ) ".
  #[local] Definition queuesΫ°auth Ξ³ :=
    queuesΫ°auth' Ξ³.(metadataΫ°queues).
  #[local] Definition queuesΫ°at' :=
    mono_gmapΫ°at.
  #[local] Definition queuesΫ°at Ξ³ :=
    queuesΫ°at' Ξ³.(metadataΫ°queues).
  #[local] Definition queuesΫ°elem Ξ³ queue : iProp Ξ£ :=
    match queue with
    | None β‡’
        True
    | Some queue β‡’
        βˆƒ node,
        queuesΫ°at Ξ³ node queue βˆ—
        queue_spmcΫ°inv queue (Ξ³.(metadataΫ°inv).@"producer")
    end.
  #[local] Instance : CustomIpat "queuesΫ°elem" :=
    " ( %node & #Hqueues_at & #Hqueue_inv ) ".

  #[local] Definition model₁' Ξ³_model vss :=
    twinsΫ°twin₁ Ξ³_model (DfracOwn 1) vss.
  #[local] Definition model₁ Ξ³ :=
    model₁' Ξ³.(metadataΫ°model).
  #[local] Definition modelβ‚‚' Ξ³_model vss :=
    twinsΫ°twinβ‚‚ Ξ³_model vss.
  #[local] Definition modelβ‚‚ Ξ³ :=
    modelβ‚‚' Ξ³.(metadataΫ°model).

  #[local] Definition descriptorΫ°model Ξ³ node descr : iProp Ξ£ :=
    βˆƒ o,
    node.[queue] ↦ o βˆ—
    βŒœfrom_option (.= descr.(descriptorΫ°queue)) True o⌝ βˆ—
    queue_spmcΫ°inv descr.(descriptorΫ°queue) (Ξ³.(metadataΫ°inv).@"producer") βˆ—
    queue_spmcΫ°model descr.(descriptorΫ°queue) descr.(descriptorΫ°vals).
  #[local] Instance : CustomIpat "descriptorΫ°model" :=
    " ( %o{} & Hnode{}_queue & {>;}%Ho{} & {{inv}#Hqueue{}_inv;{inv}#Hqueue_inv;_} & {>;}Hqueue{}_model ) ".

  #[local] Definition invΫ°inner l Ξ³ : iProp Ξ£ :=
    βˆƒ nodes descrs wss,
    l.[producers] ↦ from_option #@{location} Β§Null (head nodes) βˆ—
    xtchain (Header Β§Node 2) DfracDiscarded nodes Β§Null βˆ—
    queuesΫ°auth Ξ³ nodes descrs wss βˆ—
    modelβ‚‚ Ξ³ wss βˆ—
    [βˆ— map] node ↦ descr ∈ descrs,
      descriptorΫ°model Ξ³ node descr.
  #[local] Instance : CustomIpat "invΫ°inner" :=
    " ( %nodes{} & %descrs{} & %wss & Hl_producers & Hnodes{} & >Hqueues_auth & >Hmodelβ‚‚ & Hdescrs ) ".
  #[local] Definition inv' l Ξ³ :=
    inv (Ξ³.(metadataΫ°inv).@"inv") (invΫ°inner l Ξ³).
  Definition bag_2Ϋ°inv t ΞΉ : iProp Ξ£ :=
    βˆƒ l Ξ³,
    βŒœt = #l⌝ βˆ—
    βŒœΞΉ = Ξ³.(metadataΫ°inv)⌝ βˆ—
    l β†ͺ Ξ³ βˆ—
    inv' l Ξ³.
  #[local] Instance : CustomIpat "inv" :=
    " ( %l & %Ξ³ & -> & -> & #Hmeta & #Hinv ) ".

  Definition bag_2Ϋ°model t vss : iProp Ξ£ :=
    βˆƒ l Ξ³,
    βŒœt = #l⌝ βˆ—
    l β†ͺ Ξ³ βˆ—
    model₁ Ξ³ vss.
  #[local] Instance : CustomIpat "model" :=
    " ( %l{;_} & %Ξ³{;_} & %Heq{} & #Hmeta_{} & Hmodel₁{_{}} ) ".

  Definition bag_2Ϋ°producer t producer ws : iProp Ξ£ :=
    βˆƒ l Ξ³ π‘π‘Ÿπ‘œπ‘‘π‘’π‘π‘’π‘Ÿ,
    βŒœt = #l⌝ βˆ—
    βŒœproducer = π‘π‘Ÿπ‘œπ‘‘π‘’π‘π‘’π‘ŸβŒ βˆ—
    l β†ͺ Ξ³ βˆ—
    π‘π‘Ÿπ‘œπ‘‘π‘’π‘π‘’π‘Ÿ.(producerΫ°node) ↦ₕ Header Β§Node 2 βˆ—
    queuesΫ°at Ξ³ π‘π‘Ÿπ‘œπ‘‘π‘’π‘π‘’π‘Ÿ.(producerΫ°node) π‘π‘Ÿπ‘œπ‘‘π‘’π‘π‘’π‘Ÿ.(producerΫ°queue) βˆ—
    queue_spmcΫ°inv π‘π‘Ÿπ‘œπ‘‘π‘’π‘π‘’π‘Ÿ.(producerΫ°queue) (Ξ³.(metadataΫ°inv).@"producer") βˆ—
    queue_spmcΫ°producer π‘π‘Ÿπ‘œπ‘‘π‘’π‘π‘’π‘Ÿ.(producerΫ°queue) ws.
  #[local] Instance : CustomIpat "producer" :=
    " ( %l{;_} & %Ξ³{;_} & %π‘π‘Ÿπ‘œπ‘‘π‘’π‘π‘’π‘Ÿ{} & %Ht_eq{} & {%Hproducer_eq{};->} & #Hmeta{_{};_} & #Hnode_header{_{}} & #Hqueues_at{_{}} & #Hqueue_inv{_{}} & Hqueue_producer{_{}} ) ".

  Definition bag_2Ϋ°consumer t consumer : iProp Ξ£ :=
    βˆƒ l Ξ³ π‘π‘œπ‘›π‘ π‘’π‘šπ‘’π‘Ÿ (queue : option val),
    βŒœt = #l⌝ βˆ—
    l β†ͺ Ξ³ βˆ—
    βŒœconsumer = #π‘π‘œπ‘›π‘ π‘’π‘šπ‘’π‘ŸβŒ βˆ—
    π‘π‘œπ‘›π‘ π‘’π‘šπ‘’π‘Ÿ.[consumer_queue] ↦ queue βˆ—
    queuesΫ°elem Ξ³ queue.
  #[local] Instance : CustomIpat "consumer" :=
    " ( %l{;_} & %Ξ³{;_} & %π‘π‘œπ‘›π‘ π‘’π‘šπ‘’π‘Ÿ{} & %queue{} & %Heq{} & Hmeta_{} & {%Hconsumer_eq{};->} & Hconsumer_queue{_{}} & #Hqueues_elem{_{}} ) ".

  #[local] Instance queuesΫ°authο½°timeless Ξ³ nodes descrs wss :
    Timeless (queuesΫ°auth Ξ³ nodes descrs wss).
  #[global] Instance bag_2Ϋ°modelο½°timeless t vss :
    Timeless (bag_2Ϋ°model t vss).

  #[global] Instance bag_2Ϋ°invο½°persistent t ΞΉ :
    Persistent (bag_2Ϋ°inv t ΞΉ).

  #[local] Lemma queuesο½°alloc :
    βŠ’ |==>
      βˆƒ Ξ³_queues,
      queuesΫ°auth' Ξ³_queues [] βˆ… βˆ….
  #[local] Lemma queuesΫ°atο½°get {Ξ³ nodes descrs wss} i node :
    nodes !! i = Some node β†’
    queuesΫ°auth Ξ³ nodes descrs wss ⊒
      βˆƒ descr,
      βŒœdescrs !! node = Some descr⌝ βˆ—
      queuesΫ°at Ξ³ node descr.(descriptorΫ°queue).
  #[local] Lemma queuesΫ°atο½°valid Ξ³ nodes descrs wss node queue :
    queuesΫ°auth Ξ³ nodes descrs wss -βˆ—
    queuesΫ°at Ξ³ node queue -βˆ—
      βˆƒ descr,
      βŒœdescrs !! node = Some descr⌝ βˆ—
      βŒœdescr.(descriptorΫ°queue) = queue⌝ βˆ—
      βŒœwss !! (descriptorΫ°to_producer descr node : val) = Some descr.(descriptorΫ°vals)⌝.
  #[local] Lemma queuesΫ°atο½°validο½°producer Ξ³ nodes descrs wss π‘π‘Ÿπ‘œπ‘‘π‘’π‘π‘’π‘Ÿ :
    queuesΫ°auth Ξ³ nodes descrs wss -βˆ—
    queuesΫ°at Ξ³ π‘π‘Ÿπ‘œπ‘‘π‘’π‘π‘’π‘Ÿ.(producerΫ°node) π‘π‘Ÿπ‘œπ‘‘π‘’π‘π‘’π‘Ÿ.(producerΫ°queue) -βˆ—
      βˆƒ descr,
      βŒœdescrs !! π‘π‘Ÿπ‘œπ‘‘π‘’π‘π‘’π‘Ÿ.(producerΫ°node) = Some descr⌝ βˆ—
      βŒœdescr.(descriptorΫ°queue) = π‘π‘Ÿπ‘œπ‘‘π‘’π‘π‘’π‘Ÿ.(producerΫ°queue)⌝ βˆ—
      βŒœwss !! (π‘π‘Ÿπ‘œπ‘‘π‘’π‘π‘’π‘Ÿ : val) = Some descr.(descriptorΫ°vals)⌝.
  #[local] Lemma queuesο½°insert {Ξ³ nodes descrs wss} node descr :
    descrs !! node = None β†’
    queuesΫ°auth Ξ³ nodes descrs wss ⊒ |==>
      queuesΫ°auth Ξ³
        (node :: nodes)
        (<[node := descr]> descrs)
        (<[descriptorΫ°to_producer descr node : val := descr.(descriptorΫ°vals)]> wss) βˆ—
      queuesΫ°at Ξ³ node descr.(descriptorΫ°queue).
  #[local] Lemma queuesο½°update {Ξ³ nodes descrs wss} node descr f :
    descrs !! node = Some descr β†’
    queuesΫ°auth Ξ³ nodes descrs wss ⊒
    queuesΫ°auth Ξ³
      nodes
      (<[node := descriptorΫ°update_vals descr f]> descrs)
      (<[descriptorΫ°to_producer descr node : val := f descr.(descriptorΫ°vals)]> wss).
  #[local] Lemma queuesο½°updateο½°producer {Ξ³ nodes descrs wss} π‘π‘Ÿπ‘œπ‘‘π‘’π‘π‘’π‘Ÿ descr f :
    descrs !! π‘π‘Ÿπ‘œπ‘‘π‘’π‘π‘’π‘Ÿ.(producerΫ°node) = Some descr β†’
    descr.(descriptorΫ°queue) = π‘π‘Ÿπ‘œπ‘‘π‘’π‘π‘’π‘Ÿ.(producerΫ°queue) β†’
    queuesΫ°auth Ξ³ nodes descrs wss ⊒
    queuesΫ°auth Ξ³
      nodes
      (<[π‘π‘Ÿπ‘œπ‘‘π‘’π‘π‘’π‘Ÿ.(producerΫ°node) := descriptorΫ°update_vals descr f]> descrs)
      (<[π‘π‘Ÿπ‘œπ‘‘π‘’π‘π‘’π‘Ÿ : val := f descr.(descriptorΫ°vals)]> wss).

  #[local] Lemma modelο½°alloc :
    βŠ’ |==>
      βˆƒ Ξ³_model,
      model₁' Ξ³_model βˆ… βˆ—
      modelβ‚‚' Ξ³_model βˆ….
  #[local] Lemma model₁ーexclusive Ξ³ vss1 vss2 :
    model₁ Ξ³ vss1 -βˆ—
    model₁ Ξ³ vss2 -βˆ—
    False.
  #[local] Lemma modelο½°agree Ξ³ vss1 vss2 :
    model₁ Ξ³ vss1 -βˆ—
    modelβ‚‚ Ξ³ vss2 -βˆ—
    βŒœvss1 = vss2⌝.
  #[local] Lemma modelο½°update {Ξ³ vss1 vss2} vss :
    model₁ Ξ³ vss1 -βˆ—
    modelβ‚‚ Ξ³ vss2 ==βˆ—
      model₁ Ξ³ vss βˆ—
      modelβ‚‚ Ξ³ vss.

  Opaque queuesΫ°auth'.

  Lemma bag_2Ϋ°modelο½°exclusive t vss1 vss2 :
    bag_2Ϋ°model t vss1 -βˆ—
    bag_2Ϋ°model t vss2 -βˆ—
    False.

  Lemma bag_2Ϋ°producerο½°valid t ΞΉ vss producer ws E :
    β†‘ΞΉ βŠ† E β†’
    bag_2Ϋ°inv t ΞΉ -βˆ—
    bag_2Ϋ°model t vss -βˆ—
    bag_2Ϋ°producer t producer ws ={E}=βˆ—
      βˆƒ vs,
      βŒœvss !! producer = Some vs⌝ βˆ—
      βŒœvs `suffix_of` ws⌝.
  Lemma bag_2Ϋ°producerο½°exclusive t1 t2 producer ws1 ws2 :
    bag_2Ϋ°producer t1 producer ws1 -βˆ—
    bag_2Ϋ°producer t2 producer ws2 -βˆ—
    False.

  Lemma bag_2Ϋ°consumerο½°exclusive t1 t2 consumer :
    bag_2Ϋ°consumer t1 consumer -βˆ—
    bag_2Ϋ°consumer t2 consumer -βˆ—
    False.

  Lemma bag_2Ω createο½°spec ΞΉ :
    {{{
      True
    }}}
      bag_2Ω create ()
    {{{
      t
    , RET t;
      bag_2Ϋ°inv t ΞΉ βˆ—
      bag_2Ϋ°model t βˆ…
    }}}.

  #[local] Lemma bag_2Ω add_producer₁ーspec l Ξ³ (queue : val) :
    <<<
      l β†ͺ Ξ³ βˆ—
      inv' l Ξ³ βˆ—
      queue_spmcΫ°inv queue (Ξ³.(metadataΫ°inv).@"producer") βˆ—
      queue_spmcΫ°model queue []
    | βˆ€βˆ€ vss,
      model₁ Ξ³ vss
    >>>
      bag_2Ω add_producer₁ #l (Some queue) @ ↑γ.(metadataΫ°inv)
    <<<
      βˆƒβˆƒ node,
      let π‘π‘Ÿπ‘œπ‘‘π‘’π‘π‘’π‘Ÿ :=
        {|producerΫ°queue := queue
        ; producerΫ°node := node
        |}
      in
      model₁ Ξ³ (<[π‘π‘Ÿπ‘œπ‘‘π‘’π‘π‘’π‘Ÿ : val := []]> vss)
    | RET #node;
      node ↦ₕ Header Β§Node 2 βˆ—
      queuesΫ°at Ξ³ node queue
    >>>.
  #[local] Lemma bag_2Ω add_producerο½°spec l Ξ³ (queue : val) :
    <<<
      l β†ͺ Ξ³ βˆ—
      inv' l Ξ³ βˆ—
      queue_spmcΫ°inv queue (Ξ³.(metadataΫ°inv).@"producer") βˆ—
      queue_spmcΫ°model queue []
    | βˆ€βˆ€ vss,
      model₁ Ξ³ vss
    >>>
      bag_2Ω add_producer #l queue @ ↑γ.(metadataΫ°inv)
    <<<
      βˆƒβˆƒ node,
      let π‘π‘Ÿπ‘œπ‘‘π‘’π‘π‘’π‘Ÿ :=
        {|producerΫ°queue := queue
        ; producerΫ°node := node
        |}
      in
      model₁ Ξ³ (<[π‘π‘Ÿπ‘œπ‘‘π‘’π‘π‘’π‘Ÿ : val := []]> vss)
    | RET #node;
      node ↦ₕ Header Β§Node 2 βˆ—
      queuesΫ°at Ξ³ node queue
    >>>.
  Lemma bag_2Ω create_producerο½°spec t ΞΉ :
    <<<
      bag_2Ϋ°inv t ΞΉ
    | βˆ€βˆ€ vss,
      bag_2Ϋ°model t vss
    >>>
      bag_2Ω create_producer t @ ↑ι
    <<<
      βˆƒβˆƒ producer,
      bag_2Ϋ°model t (<[producer := []]> vss)
    | RET producer;
      bag_2Ϋ°producer t producer []
    >>>.

  Lemma bag_2Ω close_producerο½°spec t ΞΉ producer ws :
    {{{
      bag_2Ϋ°inv t ΞΉ βˆ—
      bag_2Ϋ°producer t producer ws
    }}}
      bag_2Ω close_producer producer
    {{{
      RET ();
      bag_2Ϋ°producer t producer ws
    }}}.

  Lemma bag_2Ω create_consumerο½°spec t ΞΉ :
    {{{
      bag_2Ϋ°inv t ΞΉ
    }}}
      bag_2Ω create_consumer t
    {{{
      consumer
    , RET consumer;
      bag_2Ϋ°consumer t consumer
    }}}.

  Lemma bag_2Ω pushο½°spec t ΞΉ producer ws v :
    <<<
      bag_2Ϋ°inv t ΞΉ βˆ—
      bag_2Ϋ°producer t producer ws
    | βˆ€βˆ€ vss,
      bag_2Ϋ°model t vss
    >>>
      bag_2Ω push producer v @ ↑ι
    <<<
      βˆƒβˆƒ vs,
      βŒœvss !! producer = Some vs⌝ βˆ—
      bag_2Ϋ°model t (<[producer := vs ++ [v]]> vss)
    | RET ();
      bag_2Ϋ°producer t producer (vs ++ [v])
    >>>.

  #[local] Lemma bag_2Ω popβ‚‚ο½°spec l Ξ³ π‘π‘œπ‘›π‘ π‘’π‘šπ‘’π‘Ÿ (queue : option val) nodes :
    <<<
      l β†ͺ Ξ³ βˆ—
      inv' l Ξ³ βˆ—
      π‘π‘œπ‘›π‘ π‘’π‘šπ‘’π‘Ÿ.[consumer_queue] ↦ queue βˆ—
      queuesΫ°elem Ξ³ queue βˆ—
      xtchain (Header Β§Node 2) DfracDiscarded nodes Β§Null βˆ—
      [βˆ— list] node ∈ nodes,
        βˆƒ queue,
        queuesΫ°at Ξ³ node queue
    | βˆ€βˆ€ vss,
      model₁ Ξ³ vss
    >>>
      bag_2Ω popβ‚‚ #π‘π‘œπ‘›π‘ π‘’π‘šπ‘’π‘Ÿ (from_option #@{location} Β§Null%V $ head nodes) @ ↑γ.(metadataΫ°inv)
    <<<
      βˆƒβˆƒ o,
      match o with
      | None β‡’
          model₁ Ξ³ vss
      | Some v β‡’
          βˆƒ producer vs,
          βŒœvss !! producer = Some (v :: vs)⌝ βˆ—
          model₁ Ξ³ (<[producer := vs]> vss)
      end
    | queue : option val,
      RET o;
      π‘π‘œπ‘›π‘ π‘’π‘šπ‘’π‘Ÿ.[consumer_queue] ↦ queue βˆ—
      queuesΫ°elem Ξ³ queue
    >>>.
  #[local] Lemma bag_2Ω pop₁ーspec t ΞΉ consumer :
    <<<
      bag_2Ϋ°inv t ΞΉ βˆ—
      bag_2Ϋ°consumer t consumer
    | βˆ€βˆ€ vss,
      bag_2Ϋ°model t vss
    >>>
      bag_2Ω pop₁ t consumer @ ↑ι
    <<<
      βˆƒβˆƒ o,
      match o with
      | None β‡’
          bag_2Ϋ°model t vss
      | Some v β‡’
          βˆƒ producer vs,
          βŒœvss !! producer = Some (v :: vs)⌝ βˆ—
          bag_2Ϋ°model t (<[producer := vs]> vss)
      end
    | RET o;
      bag_2Ϋ°consumer t consumer
    >>>.
  Lemma bag_2Ω popο½°spec t ΞΉ consumer :
    <<<
      bag_2Ϋ°inv t ΞΉ βˆ—
      bag_2Ϋ°consumer t consumer
    | βˆ€βˆ€ vss,
      bag_2Ϋ°model t vss
    >>>
      bag_2Ω pop t consumer @ ↑ι
    <<<
      βˆƒβˆƒ o,
      match o with
      | None β‡’
          bag_2Ϋ°model t vss
      | Some v β‡’
          βˆƒ producer vs,
          βŒœvss !! producer = Some (v :: vs)⌝ βˆ—
          bag_2Ϋ°model t (<[producer := vs]> vss)
      end
    | RET o;
      bag_2Ϋ°consumer t consumer
    >>>.
End bag_2Ϋ°G.

Require zoo_saturn.bag_2__opaque.

#[global] Opaque bag_2Ϋ°inv.
#[global] Opaque bag_2Ϋ°model.
#[global] Opaque bag_2Ϋ°producer.
#[global] Opaque bag_2Ϋ°consumer.