Commit 955aa2d2 authored by Aleš Bizjak's avatar Aleš Bizjak

Add more examples from the lecture notes.

parent e146b872
......@@ -9,6 +9,14 @@ theories/barrier/example_joining_existentials.v
theories/lecture_notes/coq_intro_example_1.v
theories/lecture_notes/coq_intro_example_2.v
theories/lecture_notes/lists.v
theories/lecture_notes/lists_guarded.v
theories/lecture_notes/lock.v
theories/lecture_notes/lock_unary_spec.v
theories/lecture_notes/modular_incr.v
theories/lecture_notes/recursion_through_the_store.v
theories/lecture_notes/stack.v
theories/lecture_notes/ccounter.v
theories/spanning_tree/graph.v
theories/spanning_tree/mon.v
......
(* Counter with contributions. A specification derived from the modular
specification proved in modular_incr module. *)
From iris.program_logic Require Export weakestpre.
From iris.heap_lang Require Export lang proofmode notation.
From iris.proofmode Require Import tactics.
From iris.algebra Require Import frac_auth.
From iris_examples.lecture_notes Require Import modular_incr.
Class ccounterG Σ := CCounterG { ccounter_inG :> inG Σ (frac_authR natR) }.
Definition ccounterΣ : gFunctors := #[GFunctor (frac_authR natR)].
Instance subG_ccounterΣ {Σ} : subG ccounterΣ Σ ccounterG Σ.
Proof. solve_inG. Qed.
Section ccounter.
Context `{!heapG Σ, !cntG Σ, !ccounterG Σ} (N : namespace).
Lemma ccounterRA_valid (m n : natR) (q : frac): (! m !{q} n) (n m)%nat.
Proof.
intros ?.
(* This property follows directly from the generic properties of the relevant RAs. *)
by apply nat_included, (frac_auth_included_total q).
Qed.
Lemma ccounterRA_valid_full (m n : natR): (! m ! n) (n = m)%nat.
Proof.
by intros ?%frac_auth_agree.
Qed.
Lemma ccounterRA_update (m n : natR) (q : frac): (! m !{q} n) ~~> (! (S m) !{q} (S n)).
Proof.
apply frac_auth_update, (nat_local_update _ _ (S _) (S _)).
lia.
Qed.
Definition ccounter_inv (γ₁ γ₂ : gname): iProp Σ :=
( n, own γ₁ (! n) γ₂ ⤇½ (Z.of_nat n))%I.
Definition is_ccounter (γ₁ γ₂ : gname) (l : loc) (q : frac) (n : natR) : iProp Σ := (own γ₁ (!{q} n) inv (N .@ "counter") (ccounter_inv γ₁ γ₂) Cnt N l γ₂)%I.
(** The main proofs. *)
Lemma is_ccounter_op γ₁ γ₂ q1 q2 (n1 n2 : nat) :
is_ccounter γ₁ γ₂ (q1 + q2) (n1 + n2)%nat ⊣⊢ is_ccounter γ₁ γ₂ q1 n1 is_ccounter γ₁ γ₂ q2 n2.
Proof.
apply uPred.equiv_spec; split; rewrite /is_ccounter frag_auth_op own_op.
- iIntros "[? #?]".
iFrame "#"; iFrame.
- iIntros "[[? #?] [? _]]".
iFrame "#"; iFrame.
Qed.
Lemma newcounter_contrib_spec (R : iProp Σ) m:
{{{ True }}}
newcounter #m
{{{ γ₁ γ₂ , RET #; is_ccounter γ₁ γ₂ 1 m%nat }}}.
Proof.
iIntros (Φ) "_ HΦ". rewrite -wp_fupd.
wp_apply newcounter_spec; auto.
iIntros () "H"; iDestruct "H" as (γ₂) "[#HCnt Hown]".
iMod (own_alloc (! m%nat ! m%nat)) as (γ₁) "[Hγ Hγ']"; first done.
iMod (inv_alloc (N .@ "counter") _ (ccounter_inv γ₁ γ₂) with "[Hγ Hown]").
{ iNext. iExists _. by iFrame. }
iModIntro. iApply "HΦ". rewrite /is_ccounter; eauto.
Qed.
Lemma incr_contrib_spec γ₁ γ₂ q n :
{{{ is_ccounter γ₁ γ₂ q n }}}
incr #
{{{ (y : Z), RET #y; is_ccounter γ₁ γ₂ q (S n) }}}.
Proof.
iIntros (Φ) "[Hown #[Hinv HCnt]] HΦ".
iApply (incr_spec N γ₂ _ (own γ₁ (!{q} n))%I (λ _, (own γ₁ (!{q} (S n))))%I with "[] [Hown]"); first set_solver.
- iIntros (m) "!# [HOwnElem HP]".
iInv (N .@ "counter") as (k) "[>H1 >H2]" "HClose".
iDestruct (makeElem_eq with "HOwnElem H2") as %->.
iMod (makeElem_update _ _ _ (k+1) with "HOwnElem H2") as "[HOwnElem H2]".
iMod (own_update_2 with "H1 HP") as "[H1 HP]".
{ apply ccounterRA_update. }
iMod ("HClose" with "[H1 H2]") as "_".
{ iNext; iExists (S k); iFrame.
rewrite Nat2Z.inj_succ Z.add_1_r //.
}
by iFrame.
- by iFrame.
- iNext.
iIntros (m) "[HCnt' Hown]".
iApply "HΦ". by iFrame.
Qed.
Lemma read_contrib_spec γ₁ γ₂ q n :
{{{ is_ccounter γ₁ γ₂ q n }}}
read #
{{{ (c : Z), RET #c; Z.of_nat n c is_ccounter γ₁ γ₂ q n }}}.
Proof.
iIntros (Φ) "[Hown #[Hinv HCnt]] HΦ".
wp_apply (read_spec N γ₂ _ (own γ₁ (!{q} n))%I (λ m, n m (own γ₁ (!{q} n)))%I with "[] [Hown]"); first set_solver.
- iIntros (m) "!# [HownE HOwnfrag]".
iInv (N .@ "counter") as (k) "[>H1 >H2]" "HClose".
iDestruct (makeElem_eq with "HownE H2") as %->.
iDestruct (own_valid_2 with "H1 HOwnfrag") as %Hleq%ccounterRA_valid.
iMod ("HClose" with "[H1 H2]") as "_".
{ iExists _; by iFrame. }
iFrame; iIntros "!>!%".
auto using inj_le.
- by iFrame.
- iIntros (i) "[_ [% HQ]]".
iApply "HΦ".
iSplit; first by iIntros "!%".
iFrame; iFrame "#".
Qed.
Lemma read_contrib_spec_1 γ₁ γ₂ n :
{{{ is_ccounter γ₁ γ₂ 1%Qp n }}} read #
{{{ RET #n; is_ccounter γ₁ γ₂ 1 n }}}.
Proof.
iIntros (Φ) "[Hown #[Hinv HCnt]] HΦ".
wp_apply (read_spec N γ₂ _ (own γ₁ (! n))%I (λ m, Z.of_nat n = m (own γ₁ (! n)))%I with "[] [Hown]"); first set_solver.
- iIntros (m) "!# [HownE HOwnfrag]".
iInv (N .@ "counter") as (k) "[>H1 >H2]" "HClose".
iDestruct (makeElem_eq with "HownE H2") as %->.
iDestruct (own_valid_2 with "H1 HOwnfrag") as %Hleq%ccounterRA_valid_full; simplify_eq.
iMod ("HClose" with "[H1 H2]") as "_".
{ iExists _; by iFrame. }
iFrame; by iIntros "!>!%".
- by iFrame.
- iIntros (i) "[_ [% HQ]]".
simplify_eq. iApply "HΦ".
iFrame; iFrame "#".
Qed.
End ccounter.
\ No newline at end of file
This diff is collapsed.
(* In this file we explain how to do the "list examples" from the Chapter on
Separation Logic for Sequential Programs in the Iris Lecture Notes, but where
we use the guarded fixed point and Löb induction to define and work with the
isList predicate. *)
(* Contains definitions of the weakest precondition assertion, and its basic rules. *)
From iris.program_logic Require Export weakestpre.
(* Instantiation of Iris with the particular language. The notation file
contains many shorthand notations for the programming language constructs, and
the lang file contains the actual language syntax. *)
From iris.heap_lang Require Export notation lang.
(* Files related to the interactive proof mode. The first import includes the
general tactics of the proof mode. The second provides some more specialized
tactics particular to the instantiation of Iris to a particular programming
language. *)
From iris.proofmode Require Export tactics.
From iris.heap_lang Require Import proofmode.
(* The following line makes Coq check that we do not use any admitted facts /
additional assumptions not in the statement of the theorems being proved. *)
Set Default Proof Using "Type".
(* ---------------------------------------------------------------------- *)
Section list_model.
(* This section contains the definition of our model of lists, i.e.,
definitions relating pointer data structures to our model, which is
simply mathematical sequences (Coq lists). *)
(* In order to do the proof we need to assume certain things about the
instantiation of Iris. The particular, even the heap is handled in an
analogous way as other ghost state. This line states that we assume the
Iris instantiation has sufficient structure to manipulate the heap, e.g.,
it allows us to use the points-to predicate. *)
Context `{!heapG Σ}.
Implicit Types l : loc.
(* The variable Σ has to do with what ghost state is available, and the type
of Iris propositions (written Prop in the lecture notes) depends on this Σ.
But since Σ is the same throughout the development we shall define
shorthand notation which hides it. *)
Notation iProp := (iProp Σ).
(* First we define the is_list representation predicate via a guarded fixed
point of the functional is_list_pre. Note the use of the later modality. The
arrows -c> express that the arrow is an arrow in the category of COFE's,
i.e., it is a non-expansive function. To fully understand the meaning of this
it is necessary to understand the model of Iris.
Since the type val is discrete the non-expansiveness condition is trivially
satisfied in this case, and we might as well have used the ordinary arrow,
but in more complex examples the domain of the predicate we are defining will
not be a discrete type, and the condition will be meaningful and necessary.
*)
Definition is_list_pre (Φ : val -c> list val -c> iProp): val -c> list val -c> iProp := λ hd xs,
match xs with
[] => hd = NONEV
| (x::xs) => ( ( : loc) (hd' : val), hd = SOMEV #ℓ⌝ (x,hd') Φ hd' xs)
end%I.
(* To construct the fixed point we need to show that the functional we have defined is contractive.
Most of the proof is automated via the f_contractive tactic. *)
Local Instance is_list_pre_contractive: Contractive is_list_pre.
Proof.
rewrite /is_list_pre.
intros n Φ Φ' Hdist hd .
repeat (f_contractive || f_equiv); apply Hdist.
Qed.
Definition is_list_def: val list val iProp := fixpoint is_list_pre.
Definition is_list_aux: seal (@is_list_def). by eexists. Qed.
Definition is_list := unseal (@is_list_aux).
Definition is_list_eq : @is_list = @is_list_def := seal_eq is_list_aux.
Lemma is_list_unfold hd xs: is_list hd xs ⊣⊢ is_list_pre is_list hd xs.
Proof. rewrite is_list_eq. apply (fixpoint_unfold is_list_pre). Qed.
(* Exercise.
Using an approach as above, given a predicate Ψ : val → iProp, define a
predicate is_list_Ψ : val → iProp, where is_list_Ψ hd means that hd points to a linked list of elements, all of which satisfy Ψ.
*)
(* Exercise. Reprove all the specifications from lists.v using the above definition of is_list. *)
End list_model.
\ No newline at end of file
(* This file contains the specification of the lock module implemented as a simple spin lock and discussed in
section 7.6 in the invariants and ghost state chapter of the Iris Lecture Notes.
*)
(* Contains definitions of the weakest precondition assertion, and its basic rules. *)
From iris.program_logic Require Export weakestpre.
(* Instantiation of Iris with the particular language. The notation file
contains many shorthand notations for the programming language constructs, and
the lang file contains the actual language syntax. *)
From iris.heap_lang Require Export notation lang.
(* Files related to the interactive proof mode. The first import includes the
general tactics of the proof mode. The second provides some more specialized
tactics particular to the instantiation of Iris to a particular programming
language. *)
From iris.proofmode Require Export tactics.
From iris.heap_lang Require Import proofmode.
(* Definition of invariants and their rules (expressed using the fancy update modality). *)
From iris.base_logic.lib Require Export invariants.
(* The exclusive resource algebra. *)
From iris.algebra Require Import excl.
Section lock_model.
(* In order to do the proof we need to assume certain things about the
instantiation of Iris. The particular, even the heap is handled in an
analogous way as other ghost state. This line states that we assume the Iris
instantiation has sufficient structure to manipulate the heap, e.g., it
allows us to use the points-to predicate, and that the ghost state includes
the exclusive resource algebra over the singleton set (represented using the
unitR type). *)
Context `{heapG Σ}.
Context `{inG Σ (exclR unitR)}.
(* We use a ghost name with a token to model whether the lock is locked or not.
The the token is just exclusive ownerwhip of unit value. *)
Definition locked γ := own γ (Excl ()).
(* The name of a lock. *)
Definition lockN (l : loc) := nroot .@ "lock" .@ l.
(* The lock invariant *)
Definition is_lock γ l P :=
inv (lockN l) ((l (#false) P locked γ)
l (#true))%I.
(* The is_lock predicate is persistent *)
Global Instance is_lock_persistent γ l Φ : Persistent (is_lock γ l Φ).
Proof. apply _. Qed.
End lock_model.
Section lock_code.
(* Here is the standard spin lock code *)
Definition newlock : val := λ: <>, ref #false.
Definition acquire : val :=
rec: "acquire" "l" :=
if: CAS "l" #false #true then #() else "acquire" "l".
Definition release : val := λ: "l", "l" <- #false.
End lock_code.
Section lock_spec.
Context `{heapG Σ}.
Context `{inG Σ (exclR unitR)}.
Lemma wp_newlock_t P:
{{{ P }}} newlock #() {{{v, RET v; (l: loc) γ, v = #l is_lock γ l P }}}.
Proof.
iIntros (φ) "Hi Hcont".
rewrite -wp_fupd /newlock.
wp_lam.
wp_alloc l as "HPt".
iMod (own_alloc (Excl ())) as (γ) "Hld"; first done.
iMod (inv_alloc _ _
((l (#false) P locked γ) l (#true))%I with "[-Hcont]")
as "Hinv"; last eauto.
{ iNext; iLeft; iFrame. }
iApply "Hcont".
iExists l, γ.
iModIntro. iSplit; first done.
iFrame.
Qed.
Lemma wp_acquire_t E γ l P :
nclose (lockN l) E
{{{ is_lock γ l P }}} acquire (#l) @ E {{{v, RET #v; P locked γ}}}.
Proof.
iIntros (HE φ) "#Hi Hcont"; rewrite /acquire.
iLöb as "IH".
wp_rec.
wp_bind (CAS _ _ _).
iInv (lockN l) as "[(Hl & HP & Ht)|Hl]" "Hcl".
- wp_cas_suc.
iMod ("Hcl" with "[Hl]") as "_"; first by iRight.
iModIntro.
wp_if.
iApply "Hcont".
iFrame.
- wp_cas_fail.
iMod ("Hcl" with "[Hl]") as "_"; first by iRight.
iModIntro.
wp_if.
iApply ("IH" with "[$Hcont]").
Qed.
Lemma wp_release_t E γ l P :
nclose (lockN l) E
{{{ is_lock γ l P locked γ P }}} release (#l) @ E {{{RET #(); True}}}.
Proof.
iIntros (HE φ) "(#Hi & Hld & HP) Hcont"; rewrite /release.
wp_lam.
iInv (lockN l) as "[(Hl & HQ & >Ht)|Hl]" "Hcl".
- iDestruct (own_valid_2 with "Hld Ht") as %Hv. done.
- wp_store.
iMod ("Hcl" with "[-Hcont]") as "_"; first by iNext; iLeft; iFrame.
iApply "Hcont".
done.
Qed.
Global Opaque newlock release acquire.
End lock_spec.
Typeclasses Opaque locked.
Global Opaque locked.
Typeclasses Opaque is_lock.
Global Opaque is_lock.
\ No newline at end of file
(* This file contains the specification of a lock module discussed
in the section on the Fancy update modality and weakest precondition
in the Iris Lecture Notes.
Recall from loc. cit. that the point of this
alternative lock specification is that it allows ones
to allocate the lock before one knows what the resource
of the invariant it is going to protect is.
*)
(* Contains definitions of the weakest precondition assertion, and its basic rules. *)
From iris.program_logic Require Export weakestpre.
(* Instantiation of Iris with the particular language. The notation file
contains many shorthand notations for the programming language constructs, and
the lang file contains the actual language syntax. *)
From iris.heap_lang Require Export notation lang.
(* Files related to the interactive proof mode. The first import includes the
general tactics of the proof mode. The second provides some more specialized
tactics particular to the instantiation of Iris to a particular programming
language. *)
From iris.proofmode Require Export tactics.
From iris.heap_lang Require Import proofmode.
(* Definition of invariants and their rules (expressed using the fancy update
modality). *)
From iris.base_logic.lib Require Export invariants.
(* The exclusive resource algebra *)
From iris.algebra Require Import excl.
Section lock_model.
(* In order to do the proof we need to assume certain things about the
instantiation of Iris. The particular, even the heap is handled in an
analogous way as other ghost state. This line states that we assume the Iris
instantiation has sufficient structure to manipulate the heap, e.g., it
allows us to use the points-to predicate, and that the ghost state includes
the exclusive resource algebra over the singleton set (represented using the
unitR type). *)
Context `{heapG Σ}.
Context `{inG Σ (exclR unitR)}.
(* We use a ghost name with a token to model whether the lock is locked or not.
The the token is just exclusive ownerwhip of unit value. *)
Definition locked γ := own γ (Excl ()).
(* The name of a lock. *)
Definition lockN (l : loc) := nroot .@ "lock" .@ l.
(* The lock invariant *)
Definition is_lock γ l P :=
inv (lockN l) ((l (#false) P locked γ)
l (#true))%I.
(* The is_lock predicate is persistent *)
Global Instance is_lock_persistent γ l Φ : Persistent (is_lock γ l Φ).
Proof. apply _. Qed.
End lock_model.
Section lock_code.
(* Here is the standard spin lock code *)
Definition newlock : val := λ: <>, ref #false.
Definition acquire : val :=
rec: "acquire" "l" :=
if: CAS "l" #false #true then #() else "acquire" "l".
Definition release : val := λ: "l", "l" <- #false.
End lock_code.
Section lock_spec.
Context `{heapG Σ}.
Context `{inG Σ (exclR unitR)}.
(* Here is the interesting part of this example, namely the new specification
for newlock, which allows one to get a post-condition which can be instantiated
with the lock invariant at some point later, when it is known.
See the discussion in Iris Lecture Notes.
First we show the specs using triples, and afterwards using weakest preconditions.
*)
Lemma wp_newlock_t :
{{{ True }}} newlock #() {{{v, RET v; (l: loc) γ, v = #l ( P E, P ={E}= is_lock γ l P) }}}.
Proof.
iIntros (φ) "Hi Hcont".
rewrite -wp_fupd /newlock.
wp_lam.
wp_alloc l as "HPt".
iApply "Hcont".
iExists l.
iMod (own_alloc (Excl ())) as (γ) "Hld"; first done.
iExists γ.
iModIntro. iSplit; first done.
iIntros (P E) "HP".
iMod (inv_alloc _ _
((l (#false) P locked γ) l (#true))%I with "[-]")
as "Hinv"; last eauto.
{ iNext; iLeft; iFrame. }
Qed.
Lemma wp_acquire_t E γ l P :
nclose (lockN l) E
{{{ is_lock γ l P }}} acquire (#l) @ E {{{v, RET #v; P locked γ}}}.
Proof.
iIntros (HE φ) "#Hi Hcont"; rewrite /acquire.
iLöb as "IH".
wp_rec.
wp_bind (CAS _ _ _).
iInv (lockN l) as "[(Hl & HP & Ht)|Hl]" "Hcl".
- wp_cas_suc.
iMod ("Hcl" with "[Hl]") as "_"; first by iRight.
iModIntro.
wp_if.
iApply "Hcont".
iFrame.
- wp_cas_fail.
iMod ("Hcl" with "[Hl]") as "_"; first by iRight.
iModIntro.
wp_if.
iApply ("IH" with "[$Hcont]").
Qed.
Lemma wp_release_t E γ l P :
nclose (lockN l) E
{{{ is_lock γ l P locked γ P }}} release (#l) @ E {{{RET #(); True}}}.
Proof.
iIntros (HE φ) "(#Hi & Hld & HP) Hcont"; rewrite /release.
wp_lam.
iInv (lockN l) as "[(Hl & HQ & >Ht)|Hl]" "Hcl".
- iDestruct (own_valid_2 with "Hld Ht") as %Hv. done.
- wp_store.
iMod ("Hcl" with "[-Hcont]") as "_"; first by iNext; iLeft; iFrame.
iApply "Hcont".
done.
Qed.
(* Here are the specifications again, just written using weakest preconditions *)
Lemma wp_newlock :
True WP newlock #() {{v, (l: loc) γ, v = #l ( P E, P ={E}= is_lock γ l P) }}.
Proof.
iIntros "_".
rewrite -wp_fupd /newlock.
wp_lam.
wp_alloc l as "HPt".
iExists l.
iMod (own_alloc (Excl ())) as (γ) "Hld"; first done.
iExists γ.
iModIntro. iSplit; first done.
iIntros (P E) "HP".
iMod (inv_alloc _ _
((l (#false) P locked γ) l (#true))%I with "[-]")
as "Hinv"; last eauto.
{ iNext; iLeft; iFrame. }
Qed.
Lemma wp_acquire E γ l P :
nclose (lockN l) E
is_lock γ l P WP acquire (#l) @ E {{v, P locked γ}}.
Proof.
iIntros (HE) "#Hi"; rewrite /acquire.
iLöb as "IH".
wp_rec.
wp_bind (CAS _ _ _).
iInv (lockN l) as "[(Hl & HP & Ht)|Hl]" "Hcl".
- wp_cas_suc.
iMod ("Hcl" with "[Hl]") as "_"; first by iRight.
iModIntro.
wp_if.
iFrame.
- wp_cas_fail.
iMod ("Hcl" with "[Hl]") as "_"; first by iRight.
iModIntro.
wp_if.
iApply "IH".
Qed.
Lemma wp_release E γ l P :
nclose (lockN l) E
is_lock γ l P locked γ P WP release (#l) @ E {{v, True}}.
Proof.
iIntros (HE) "(#Hi & Hld & HP)"; rewrite /release.
wp_lam.
iInv (lockN l) as "[(Hl & HQ & >Ht)|Hl]" "Hcl".
- iDestruct (own_valid_2 with "Hld Ht") as %Hv. done.
- wp_store.
iMod ("Hcl" with "[-]") as "_"; first by iNext; iLeft; iFrame.
done.
Qed.
Global Opaque newlock release acquire.
(* We now present a simple client of the lock which cannot be verified with the
lock specification described in the Chapter on Invariants and Ghost State in the
Iris Lecture Notes, but which can be specifed and verified with the current
specification.
*)
Definition test : expr :=
let: "l" := newlock #() in
let: "r" := ref #0 in
(λ: <>, acquire "l";; "r" <- !"r" + #1;; release "l").
Lemma test_spec :
{{{ True }}} test #() {{{ v, RET v; True }}}.
Proof.
iIntros (φ) "Hi HCont"; rewrite /test.
wp_bind (newlock #())%E.
iApply (wp_newlock_t); auto.
iNext.
iIntros (v) "Hs".
wp_lam.
wp_bind (ref #0)%E.
wp_alloc l as "Hl".
wp_lam.
wp_lam.
wp_bind (acquire v)%E.
iDestruct "Hs" as (l' γ) "[% H2]".
subst.
iMod ("H2" $! ( (n : Z), l #n)%I with "[Hl]") as "#H3".
{ iExists 0; iFrame. }
wp_apply (wp_acquire_t with "H3"); auto.
iIntros (v) "(Hpt & Hlocked)".
iDestruct "Hpt" as (u) "Hpt".
wp_lam.
wp_load.
wp_op.
wp_store.
wp_apply (wp_release_t with "[-HCont]"); auto.
iFrame "H3 Hlocked".
iExists _; iFrame.
Qed.
End lock_spec.
Typeclasses Opaque locked.
Global Opaque locked.
Typeclasses Opaque is_lock.
Global Opaque is_lock.
\ No newline at end of file
(* Modular Specifications for Concurrent Modules. *)
From iris.program_logic Require Export hoare weakestpre.
From iris.heap_lang Require Export lang proofmode notation.
From iris.proofmode Require Import tactics.
From iris.algebra Require Import agree frac frac_auth.
From iris.base_logic.lib Require Import fractional.
From iris.heap_lang.lib Require Import par.
Definition cntCmra : cmraT := (prodR fracR (agreeR (leibnizC Z))).
Class cntG Σ := CntG { CntG_inG :> inG Σ cntCmra }.
Definition cntΣ : gFunctors := #[GFunctor cntCmra ].
Instance subG_cntΣ {Σ} : subG cntΣ Σ cntG Σ.
Proof. solve_inG. Qed.
Definition newcounter : val :=
λ: "m", ref "m".
Definition read : val := λ: "ℓ", !"ℓ".
Definition incr: val :=
rec: "incr" "l" :=
let: "oldv" := !"l" in
if: CAS "l" "oldv" ("oldv" + #1)
then "oldv" (* return old value if success *)
else "incr" "l".
Definition wk_incr : val :=
λ: "l", let: "n" := !"l" in
"l" <- "n" + #1.
Section cnt_model.
Context `{!cntG Σ}.
Definition makeElem (q : Qp) (m : Z) : cntCmra := (q, to_agree m).
Notation "γ ⤇[ q ] m" := (own γ (makeElem q m))
(at level 20, q at level 50, format "γ ⤇[ q ] m") : uPred_scope.
Notation "γ ⤇½ m" := (own γ (makeElem (1/2) m))
(at level 20, format "γ ⤇½ m") : uPred_scope.
Global Instance makeElem_fractional γ m: Fractional (λ q, γ [q] m)%I.
Proof.
intros p q. rewrite /makeElem.
rewrite -own_op; f_equiv.