clutch.eris.examples.dynamic_vec
From clutch.eris Require Export eris hash lib.map.
Import Hierarchy.
Section faulty_allocator.
Context `{!erisGS Σ}.
Context (ε : nonnegreal).
Import Hierarchy.
Section faulty_allocator.
Context `{!erisGS Σ}.
Context (ε : nonnegreal).
Here we implement a faulty memory allocator, whose operations can fail
with some probability ε
Definition extend_spec (f : val) :=
forall (n : nat) l (vs : list val),
(0 < n)%Z →
{{{ ↯ (nnreal_mult (nnreal_nat n) ε) ∗ ▷ l ↦∗ vs }}} f (Val $ LitV $ LitInt $ n) #l
{{{ l', RET #l';
l' ↦∗ (vs ++ (replicate (Z.to_nat n) #())) }}}.
Definition store_spec (f : val) :=
forall (l : loc) (off : nat) (vs : list val) (v : val),
is_Some (vs !! off) →
{{{ ↯ ε ∗ l ↦∗ vs }}} f #l #off v {{{ RET #(); l ↦∗ <[off:=v]> vs }}}.
Definition load_spec (f : val) :=
forall (l : loc) (off : nat) (vs : list val) (v : val),
vs !! off = Some v →
{{{ ↯ ε ∗ l ↦∗ vs }}} f #l {{{ RET v; l ↦∗ vs }}}.
Definition vec_push_back (ext str: val) : val :=
λ: "vec" "v",
let, ( "l", "s", "r" ) := "vec" in
str "l" "s" "v" ;;
if: "s" + #1 = "r" then
let: "l'" := ext "r" "l" in
( "l'", "s" + #1, #2 * "r" )
else ( "l", "s" + #1, "r" ).
Definition vec_spec (vec : val) (vs : list val) : iProp Σ :=
∃ (l : loc) (sval rval : nat) xs (p : nonnegreal),
⌜ vec = ( #l, #sval, #rval )%V ⌝ ∗
(* The potential of error credits *)
↯ p ∗
l ↦∗ (vs ++ xs) ∗
⌜ sval < rval ⌝ ∗
⌜ sval = (length vs) ⌝ ∗
⌜ rval = (length (vs ++ xs)) ⌝ ∗
(* The current potential plus the expected potential
is equal to the length
of the vector times the error cost of allocation.
This ensures we can resize "for free".
*)
⌜ (nonneg p + (2 * length xs * ε) = rval * ε)%R ⌝.
Lemma wp_push_back vs ext str (vec v : val) :
extend_spec ext ->
store_spec str ->
{{{ vec_spec vec vs ∗ ↯ (nnreal_mult (nnreal_nat 3) ε) }}}
vec_push_back ext str vec v
{{{ vec', RET vec' ; vec_spec vec' (vs ++ (cons v nil)) }}}.
Proof.
rewrite /extend_spec /store_spec.
iIntros (Hext Hstr Φ) "(Hvec & Herr) HΦ".
iDestruct "Hvec" as (l sval rval xs p) "(-> &Herr2 & Hl & %Hleq & %Hlen1 & %Hlen2 & %Hpot)".
rewrite /vec_push_back.
assert ((nnreal_nat 3 * ε = ε + (nnreal_nat 2) * ε)%NNR) as ->.
{
apply nnreal_ext. simpl.
lra.
}
assert ((sval + 1 < rval)%nat \/ (sval + 1 = rval)%nat) as [Hno | Hyes].
{
apply INR_lt in Hleq.
inversion Hleq.
- right. lia.
- left. lia.
}
(* Case: No resizing *)
- wp_pures.
iPoseProof (ec_split _ _ with "Herr") as "(Herr3 & Herr4)"; [apply cond_nonneg..|].
wp_bind (str _ _ _).
wp_apply (Hstr with "[$Herr3 Hl //]").
{ apply lookup_lt_is_Some_2.
rewrite -Hlen2.
by apply INR_lt.
}
iIntros "Hl".
wp_pures.
rewrite bool_decide_eq_false_2; last first.
{
intro H.
inversion H.
lia.
}
wp_pures.
iModIntro.
iApply "HΦ".
rewrite /vec_spec.
iExists l, (sval + 1)%nat, rval.
destruct xs as [| x xs].
{
rewrite length_app /= in Hlen2.
lia.
}
iExists xs, (nnreal_plus p (nnreal_mult (nnreal_nat 2) ε)).
assert (#(sval + 1)%nat = #(sval + 1)) as Hsval.
{
do 2 f_equal. lia.
}
rewrite Hsval.
iSplit; auto.
iSplitL "Herr2 Herr4".
{ iApply ec_combine. iFrame. }
iSplit.
{
rewrite cons_middle app_assoc insert_app_l.
- rewrite -(Nat.add_0_r sval) Hlen1.
rewrite insert_app_r //.
- rewrite length_app /=.
lia.
}
iSplit.
{
iPureIntro.
by apply lt_INR in Hno.
}
iSplit.
{
iPureIntro.
rewrite length_app Hlen1 /= //.
}
iSplit.
{
iPureIntro.
rewrite Hlen2.
do 3 rewrite length_app /=.
lia.
}
iPureIntro.
simpl.
rewrite -Hpot length_cons S_INR.
rewrite Rmult_plus_distr_r Rmult_1_l.
rewrite Rplus_assoc.
rewrite Rmult_plus_distr_r Rmult_1_l.
rewrite Rmult_plus_distr_l Rmult_1_r /=.
lra.
(* Case : Resizing *)
- wp_pures.
iPoseProof (ec_split _ _ with "Herr") as "(Herr3 & Herr4)"; [apply cond_nonneg..|].
wp_bind (str _ _ _).
wp_apply (Hstr with "[$Herr3 Hl //]").
{ apply lookup_lt_is_Some_2.
apply INR_lt.
rewrite -Hlen2 //.
}
iIntros "Hl".
wp_pures.
assert (#(sval + 1)%nat = #(sval + 1)) as Hsval.
{
do 2 f_equal. lia.
}
assert (length xs = 1%nat) as Hxs.
{
rewrite length_app -Hlen1 in Hlen2. lia.
}
rewrite bool_decide_eq_true_2; last first.
{
do 2 f_equal; lia.
}
wp_pures.
wp_bind (ext _ _)%E.
wp_apply (Hext rval l with "[Herr2 Herr4 Hl]").
{ simpl; lia. }
{
iFrame.
replace (nnreal_nat rval * ε)%NNR with
(nnreal_plus p (nnreal_nat 2 * ε))%NNR.
- iApply ec_combine; iFrame.
- apply nnreal_ext. simpl.
rewrite -Hpot Hxs.
simpl. lra.
}
iIntros (l') "Hl'".
wp_pures.
iApply "HΦ".
iMod (ec_zero).
iModIntro.
rewrite /vec_spec.
iExists l', (sval + 1)%nat, (2*rval)%nat.
rewrite Hsval.
iExists (replicate (Z.to_nat (sval + 1)%nat) #()), (nnreal_zero).
iFrame.
iSplit.
{
assert (#(2 * rval)%nat = #(2 * rval)) as ->; auto.
do 2 f_equal. lia.
}
iSplitL "Hl'".
{
destruct xs as [| x xs]; [simpl in Hxs; done |].
destruct xs as [| x' xs]; [ | simpl in Hxs; done].
rewrite cons_middle app_assoc insert_app_l.
- rewrite Hyes.
rewrite -(Nat.add_0_r sval) Hlen1 /=.
rewrite insert_app_r /=.
rewrite app_nil_r.
iFrame.
- rewrite length_app /=.
lia.
}
iSplit.
{
iPureIntro.
rewrite Hyes mult_INR /=.
assert (0 < rval); [ | lra].
eapply Rle_lt_trans; last eauto.
apply pos_INR.
}
iSplit.
{
iPureIntro.
rewrite length_app /=.
apply INR_eq.
do 2 rewrite plus_INR.
rewrite Hlen1. lra.
}
iSplit.
{
iPureIntro.
do 2 rewrite length_app /=.
rewrite -Hyes.
rewrite length_replicate /=.
rewrite -Hlen1.
apply INR_eq.
rewrite Nat2Z.id.
do 6 rewrite plus_INR /=.
lra.
}
iPureIntro.
simpl.
rewrite Hyes length_replicate /=.
rewrite Nat2Z.id.
do 2 rewrite plus_INR /=.
lra.
Qed.
End faulty_allocator.