You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

635 lines
15 KiB

10 months ago
From iris.proofmode Require Import tactics.
From iris.heap_lang Require Import lang primitive_laws notation.
From iris.base_logic Require Import invariants.
From semantics.pl.heap_lang Require Import adequacy proofmode primitive_laws_nolater.
From semantics.pl Require Import hoare_lib.
From semantics.pl.program_logic Require Import notation.
(** ** Magic is in the air *)
Import hoare.
Check ent_wand_intro.
Check ent_wand_elim.
Section primitive.
Implicit Types (P Q R: iProp).
Lemma ent_or_sep_dist P Q R :
(P Q) R (P R) (Q R).
Proof.
apply ent_wand_elim.
apply ent_or_elim.
- apply ent_wand_intro. apply ent_or_introl.
- apply ent_wand_intro. apply ent_or_intror.
Qed.
(** Exercise 1 *)
Lemma ent_carry_res P Q :
P Q - (P Q).
10 months ago
Proof.
apply ent_wand_intro.
reflexivity.
Qed.
10 months ago
Lemma ent_comm_premise P Q R :
(Q - P - R) P - Q - R.
Proof.
apply ent_wand_intro.
apply ent_wand_intro.
rewrite <-ent_sep_assoc.
rewrite (ent_sep_comm P Q).
rewrite ent_sep_assoc.
apply ent_wand_elim.
apply ent_wand_elim.
reflexivity.
Qed.
Lemma ent_or_comm P Q :
P Q Q P.
Proof.
apply bi.equiv_entails; constructor.
- apply ent_or_elim.
+ apply ent_or_intror.
+ apply ent_or_introl.
- apply ent_or_elim.
+ apply ent_or_intror.
+ apply ent_or_introl.
Qed.
10 months ago
Lemma ent_or_cancel_left P Q Q' :
(Q Q') P Q P Q'.
Proof.
intro H.
apply ent_or_elim.
- apply ent_or_introl.
- etrans; [ apply H | apply ent_or_intror ].
Qed.
10 months ago
Lemma ent_sep_or_disj2 P Q R :
(P R) (Q R) (P Q) R.
Proof.
apply ent_wand_elim.
apply ent_or_elim.
- apply ent_wand_intro.
rewrite ent_sep_comm.
etrans; [ apply ent_or_sep_dist | ].
rewrite ent_sep_comm.
apply ent_or_cancel_left.
apply ent_sep_weaken.
- apply ent_wand_intro.
rewrite ent_sep_comm.
etrans; [ apply ent_or_sep_dist | ].
rewrite ent_sep_comm.
etrans; first apply ent_or_elim; [ apply ent_sep_weaken | apply ent_sep_weaken | apply ent_or_intror ].
Qed.
10 months ago
End primitive.
(** ** Using the IPM *)
Implicit Types
(P Q R: iProp)
(Φ Ψ : val iProp)
.
Lemma or_elim P Q R:
(P R)
(Q R)
(P Q) R.
Proof.
iIntros (H1 H2) "[P|Q]".
- iApply H1.
iExact "P".
10 months ago
- by iApply H2.
Qed.
Lemma or_intro_l P Q:
P P Q.
Proof.
iIntros "P". iLeft. iFrame "P".
(* [iExact] corresponds to Coq's [exact] *)
Restart.
iIntros "P". iLeft. iExact "P".
(* [iAssumption] can solve the goal if there is an exact match in the context *)
Restart.
iIntros "P". iLeft. iAssumption.
(* This directly frames the introduced proposition. The IPM will automatically try to pick a disjunct. *)
Restart.
iIntros "$".
Qed.
Lemma or_sep P Q R: (P Q) R (P R) (Q R).
Proof.
(* we first introduce, destructing the separating conjunction *)
iIntros "[HPQ HR]".
iDestruct "HPQ" as "[HP | HQ]".
- iLeft. iFrame.
- iRight. iFrame.
(* we can also split more explicitly *)
Restart.
iIntros "[HPQ HR]".
iDestruct "HPQ" as "[HP | HQ]".
- iLeft.
(* [iSplitL] uses the given hypotheses to prove the left conjunct and the rest for the right conjunct *)
(* symmetrically, [iSplitR] gives the specified hypotheses to the right *)
iSplitL "HP". all: iAssumption.
- iRight.
(* if we don't give any hypotheses, everything will go to the left. *)
iSplitL. (* now we're stuck... *)
(* alternative: directly destruct the disjunction *)
Restart.
(* iFrame will also directly pick the disjunct *)
iIntros "[[HP | HQ] HR]"; iFrame.
Abort.
(* Using entailments *)
Lemma or_sep P Q R: (P Q) R (P R) (Q R).
Proof.
iIntros "[HPQ HR]". iDestruct "HPQ" as "[HP | HQ]".
- (* this will make the entailment ⊢ into a wand *)
iPoseProof (ent_or_introl (P R) (Q R)) as "-#Hor".
iApply "Hor". iFrame.
- (* we can also directly apply the entailment *)
iApply ent_or_intror.
iFrame.
Abort.
(* Proving pure Coq propositions *)
Lemma prove_pure P : P 42 > 0.
Proof.
iIntros "HP".
(* [iPureIntro] will switch to a Coq goal, of course losing access to the Iris context *)
iPureIntro. lia.
Abort.
(* Destructing assumptions *)
Lemma destruct_ex {X} (p : X Prop) (Φ : X iProp) : ( x : X, p x Φ x) False.
Proof.
(* we can lead the identifier with a [%] to introduce to the Coq context *)
iIntros "[%w Hw]".
iDestruct "Hw" as "[%Hw1 Hw2]".
10 months ago
(* more compactly: *)
Restart.
iIntros "(%w & %Hw1 & Hw2)".
Restart.
(* we cannot introduce an existential to the Iris context *)
Fail iIntros "(w & Hw)".
Restart.
iIntros "(%w & Hw1 & Hw2)".
(* if we first introduce a pure proposition into the Iris context,
we can later move it to the Coq context *)
iDestruct "Hw1" as "%Hw1".
Abort.
(* Specializing assumptions *)
Lemma specialize_assum P Q R :
P -
R -
(P R - (P R) (Q R)) -
(P R) (Q R).
Proof.
iIntros "HP HR Hw".
iSpecialize ("Hw" with "[HR HP]").
{ iFrame. }
iAssumption.
10 months ago
Restart.
iIntros "HP HR Hw".
(* we can also directly frame it *)
iSpecialize ("Hw" with "[$HR $HP]").
Restart.
iIntros "HP HR Hw".
(* we can let it frame all hypotheses *)
iSpecialize ("Hw" with "[$]").
Restart.
(* we can also use [iPoseProof], and introduce the generated hypothesis with [as] *)
iIntros "HP HR Hw".
iPoseProof ("Hw" with "[$HR $HP]") as "$".
Restart.
iIntros "HP HR Hw".
(* [iApply] can similarly be specialized *)
iApply ("Hw" with "[$HP $HR]").
Abort.
(* Nested specialization *)
Lemma specialize_nested P Q R :
P -
(P - R) -
(R - Q) -
Q.
Proof.
iIntros "HP HPR HRQ".
(* we can use the pattern with round parentheses to specialize a hypothesis in a nested way *)
iSpecialize ("HRQ" with "(HPR HP)").
(* can finish the proof with [iExact] *)
iExact "HRQ".
(* of course, this also works for [iApply] *)
Restart.
iIntros "HP HPR HRQ". iApply ("HRQ" with "(HPR HP)").
Abort.
(* Existentials *)
Lemma prove_existential (Φ : nat iProp) :
Φ 1337 - n m, n > 41 Φ m.
Proof.
(* [iExists] can instantiate existentials *)
iIntros "Ha".
iExists 42.
iExists 1337. iSplitR. { iPureIntro. lia. } iFrame.
Restart.
iIntros "Ha". iExists 42, 1337.
(* [iSplit] works if the goal is a conjunction or one of the separating conjuncts is pure.
In that case, the hypotheses will be available for both sides. *)
iSplit.
Restart.
iIntros "Ha". iExists 42, 1337. iSplitR; iFrame; iPureIntro. lia.
Abort.
(* specializing universals *)
Lemma specialize_universal (Φ : nat iProp) :
( n, n = 42 - Φ n) - Φ 42.
Proof.
iIntros "Hn".
(* we can use [$!] to specialize Iris hypotheses with pure Coq terms *)
iSpecialize ("Hn" $! 42).
iApply "Hn". done.
Restart.
iIntros "Hn".
(* we can combine this with [with] patterns. The [%] pattern will generate a pure Coq goal. *)
iApply ("Hn" $! 42 with "[%]").
done.
Restart.
iIntros "Hn".
(* ...and ending the pattern with // will call done *)
iApply ("Hn" $! 42 with "[//]").
Abort.
Section without_ipm.
(** Prove the following entailments without using the IPM. *)
(** Exercise 2 *)
Lemma ent_lem1 P Q :
True P - Q - P Q.
Proof.
repeat apply ent_wand_intro.
rewrite <-ent_sep_assoc.
rewrite ent_sep_comm.
apply ent_sep_weaken.
Qed.
10 months ago
Lemma ent_lem2 P Q :
P (P - Q) Q.
Proof.
rewrite ent_sep_comm.
apply ent_wand_elim.
reflexivity.
Qed.
10 months ago
Lemma ent_lem3 P Q R :
(P Q) R - (P R) (Q R).
Proof.
apply ent_wand_intro.
apply ent_or_sep_dist.
Qed.
10 months ago
End without_ipm.
Lemma ent_lem1_ipm P Q :
True P - Q - P Q.
Proof.
iIntros "_ HP HQ".
iSplitL "HP".
all: iAssumption.
Qed.
10 months ago
Lemma ent_lem2_ipm P Q :
P (P - Q) Q.
Proof.
iIntros "[HP HPQ]".
iSpecialize ("HPQ" with "HP").
iAssumption.
Qed.
10 months ago
Lemma ent_lem3_ipm P Q R :
(P Q) R - (P R) (Q R).
Proof.
iIntros "[HP | HQ] HR".
- iLeft.
iFrame.
- iRight.
iFrame.
Qed.
10 months ago
(** Weakest precondition rules *)
Check ent_wp_value.
Check ent_wp_wand.
Check ent_wp_bind.
Check ent_wp_pure_step.
Check ent_wp_new.
Check ent_wp_load.
Check ent_wp_store.
Lemma ent_wp_pure_steps e e' Φ :
rtc pure_step e e'
WP e' {{ Φ }} WP e {{ Φ }}.
Proof.
iIntros (Hpure) "Hwp".
iInduction Hpure as [|] "IH"; first done.
iApply ent_wp_pure_step; first done. by iApply "IH".
Qed.
Print hoare.
(** Exercise 3 *)
(** We can re-derive the Hoare rules from the weakest pre rules. *)
Lemma hoare_frame' P R Φ e :
{{ P }} e {{ Φ }}
{{ P R }} e {{ v, Φ v R }}.
Proof.
intro HP.
unfold hoare in *.
etrans; first apply ent_sep_split; [ exact HP | reflexivity | ].
etrans; last apply ent_wp_wand.
simpl.
rewrite ent_sep_comm.
apply ent_sep_split; [ apply ent_all_intro; intro v | reflexivity ].
apply ent_wand_intro.
rewrite ent_sep_comm.
reflexivity.
Qed.
10 months ago
(** Exercise 4 *)
Lemma hoare_load l v :
{{ l v }} !#l {{ w, w = v l v }}.
Proof.
unfold hoare.
etrans; last apply ent_wp_load; simpl.
etrans; [ apply ent_sep_true | rewrite ent_sep_comm; apply ent_sep_split ].
1: reflexivity.
apply ent_wand_intro; rewrite ent_sep_comm.
etrans; [ apply ent_sep_weaken | etrans; first apply ent_sep_true ].
apply ent_sep_split; [ | reflexivity ].
apply ent_prove_pure.
reflexivity.
Qed.
10 months ago
Lemma hoare_store l (v w : val) :
{{ l v }} #l <- w {{ _, l w }}.
Proof.
unfold hoare.
etrans; last apply ent_wp_store; simpl.
etrans; first apply ent_sep_true.
rewrite ent_sep_comm; apply ent_sep_split; first reflexivity.
apply ent_wand_intro.
rewrite ent_sep_comm; apply ent_sep_weaken.
Qed.
10 months ago
Lemma hoare_new (v : val) :
{{ True }} ref v {{ w, l : loc, w = #l l v }}.
Proof.
unfold hoare.
etrans; last apply ent_wp_new; simpl.
apply ent_all_intro; intro l.
apply ent_wand_intro.
etrans; first apply ent_sep_split; [ apply ent_prove_pure | reflexivity | ].
exact (eq_refl #l).
eapply ent_exist_intro.
reflexivity.
Qed.
10 months ago
(** Exercise 5 *)
(** Linked lists using the IPM *)
Fixpoint is_ll (xs : list val) (v : val) : iProp :=
match xs with
| [] => v = NONEV
| x :: xs =>
(l : loc) (w : val),
v = SOMEV #l l (x, w) is_ll xs w
end.
Definition new_ll : val :=
λ: <>, NONEV.
Definition cons_ll : val :=
λ: "h" "l", SOME (ref ("h", "l")).
Definition head_ll : val :=
λ: "x", match: "x" with NONE => #() | SOME "r" => Fst (!"r") end.
Definition tail_ll : val :=
λ: "x", match: "x" with NONE => #() | SOME "r" => Snd (!"r") end.
Definition len_ll : val :=
rec: "len" "x" := match: "x" with NONE => #0 | SOME "r" => #1 + "len" (Snd !"r") end.
Definition app_ll : val :=
rec: "app" "x" "y" :=
match: "x" with NONE => "y" | SOME "r" =>
let: "rs" := !"r" in
"r" <- (Fst "rs", "app" (Snd "rs") "y");;
SOME "r"
end.
Lemma app_ll_correct xs ys v w :
{{ is_ll xs v is_ll ys w }} app_ll v w {{ u, is_ll (xs ++ ys) u }}.
Proof.
iIntros "[Hv Hw]".
iRevert (v) "Hv Hw".
(* We use the [iInduction] tactic which lifts Coq's induction into Iris.
["IH"] is the name the inductive hypothesis should get in the Iris context.
Note that the inductive hypothesis is printed above another line [-----].
This is another kind of context which you will learn about soon; for now, just
treat it the same as any other elements of the Iris context.
*)
iInduction xs as [ | x xs] "IH"; simpl; iIntros (v) "Hv Hw".
Restart.
(* simpler: use the [forall] clause of [iInduction] to let it quantify over [v] *)
iIntros "[Hv Hw]".
iInduction xs as [ | x xs] "IH" forall (v); simpl.
- iDestruct "Hv" as "->". unfold app_ll. wp_pures. iApply wp_value. done.
- iDestruct "Hv" as "(%l & %w' & -> & Hl & Hv)".
(* Note: [wp_pures] does not unfold the definition *)
wp_pures.
unfold app_ll. wp_pures. fold app_ll. wp_load. wp_pures.
wp_bind (app_ll _ _). iApply (ent_wp_wand' with "[Hl] [Hv Hw]"); first last.
{ iApply ("IH" with "Hv Hw"). }
simpl. iIntros (v) "Hv". wp_store. wp_pures. iApply wp_value. eauto with iFrame.
Qed.
Lemma new_ll_correct :
{{ True }} new_ll #() {{ v, is_ll [] v }}.
Proof.
unfold new_ll.
unfold is_ll.
iIntros "_".
wp_pures.
iApply (ent_wp_value).
iPureIntro.
reflexivity.
Qed.
10 months ago
Lemma cons_ll_correct (v x : val) xs :
{{ is_ll xs v }} cons_ll x v {{ u, is_ll (x :: xs) u }}.
Proof.
unfold hoare, cons_ll, is_ll.
fold is_ll.
etrans; last eapply ent_wp_pure_steps.
2: {
eapply rtc_l.
{
apply (pure_step_fill [AppLCtx _]).
apply pure_step_beta.
}
simpl.
etrans.
{
apply (rtc_pure_step_fill [AppLCtx _]).
apply pure_step_val; eauto.
}
simpl.
eapply rtc_l; last reflexivity.
apply pure_step_beta.
}
simpl.
etrans; last eapply (hoare_bind [InjRCtx]); [
apply ent_sep_true
| apply hoare_frame
| intro w
].
eapply hoare_pure_steps.
{
apply (rtc_pure_step_fill [AllocNRCtx _]).
apply pure_step_val.
eauto.
}
simpl.
1: apply hoare_new.
simpl.
unfold hoare.
etrans; first apply ent_exists_sep.
apply ent_exist_elim; intro l.
etrans; last eapply hoare_pure_steps; [ | apply pure_step_val; eauto | apply ent_wp_value ].
apply (ent_exist_intro l).
apply (ent_exist_intro v).
(* My patience is up. *)
iIntros "[[%w_eq HL] HV]".
rewrite w_eq.
iSplitR.
{ iPureIntro; reflexivity. }
iFrame.
Qed.
10 months ago
Lemma head_ll_correct (v x : val) xs :
{{ is_ll (x :: xs) v }} head_ll v {{ w, w = x }}.
Proof.
unfold head_ll, is_ll; fold is_ll.
iIntros "(%l & %w & %eq & HL & HW)".
subst.
wp_pures.
iApply (ent_wp_bind _ [FstCtx]).
iApply ent_wp_load.
iFrame.
simpl.
iIntros "_".
wp_pures.
iApply wp_value.
iPureIntro; reflexivity.
Qed.
10 months ago
Lemma tail_ll_correct v x xs :
{{ is_ll (x :: xs) v }} tail_ll v {{ w, is_ll xs w }}.
Proof.
unfold tail_ll, is_ll; fold is_ll.
iIntros "(%l & %w & %eq & HL & HW)".
subst.
wp_pures.
iApply (ent_wp_bind _ [SndCtx]).
iApply ent_wp_load.
iFrame.
simpl.
iIntros "_".
wp_pures.
iApply wp_value.
iAssumption.
Qed.
10 months ago
Lemma len_ll_correct v xs :
{{ is_ll xs v }} len_ll v {{ w, w = #(length xs) is_ll xs v }}.
Proof.
iInduction xs as [ | w xs ] "IH" forall (v); simpl.
- iIntros "%eq".
subst.
unfold len_ll.
wp_pures.
iApply wp_value.
iSplit; iPureIntro; reflexivity.
- iIntros "(%l & %x & %eq & HL & HX)".
subst.
unfold len_ll.
wp_pures.
iApply (ent_wp_bind _ [BinOpRCtx _ #1]).
simpl.
10 months ago
iApply (ent_wp_bind _ [SndCtx; AppRCtx _]).
iApply ent_wp_load.
iSplitL "HL"; [ iExact "HL" | iIntros "HL"; simpl ].
iApply (ent_wp_bind _ [AppRCtx _]).
wp_pures.
iApply (ent_wp_value).
simpl.
iSpecialize ("IH" $! x).
iSpecialize ("IH" with "HX").
iApply (ent_wp_wand' with "[HL]"); last iExact "IH".
iIntros "%v [%eq HX]".
subst.
wp_pures.
iApply (ent_wp_value).
iSplitR.
{
iPureIntro.
have h : (1 + length xs = S (length xs))%Z.
lia.
rewrite h.
reflexivity.
}
iExists l, x.
iSplitR.
{ iPureIntro; reflexivity. }
iFrame.
Qed.