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. Proof. (* don't use the IPM *) (* TODO: exercise *) Admitted. Lemma ent_comm_premise P Q R : (Q -∗ P -∗ R) ⊢ P -∗ Q -∗ R. Proof. (* don't use the IPM *) (* TODO: exercise *) Admitted. Lemma ent_sep_or_disj2 P Q R : (P ∨ R) ∗ (Q ∨ R) ⊢ (P ∗ Q) ∨ R. Proof. (* don't use the IPM *) (* TODO: exercise *) Admitted. 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]". - by iApply H1. - 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]". (* 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. } 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. (* TODO: exercise *) Admitted. Lemma ent_lem2 P Q : P ∗ (P -∗ Q) ⊢ Q. Proof. (* TODO: exercise *) Admitted. Lemma ent_lem3 P Q R : (P ∨ Q) ⊢ R -∗ (P ∗ R) ∨ (Q ∗ R). Proof. (* TODO: exercise *) Admitted. End without_ipm. Lemma ent_lem1_ipm P Q : True ⊢ P -∗ Q -∗ P ∗ Q. Proof. (* TODO: exercise *) Admitted. Lemma ent_lem2_ipm P Q : P ∗ (P -∗ Q) ⊢ Q. Proof. (* TODO: exercise *) Admitted. Lemma ent_lem3_ipm P Q R : (P ∨ Q) ⊢ R -∗ (P ∗ R) ∨ (Q ∗ R). Proof. (* TODO: exercise *) Admitted. (** 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. (* don't use the IPM *) (* TODO: exercise *) Admitted. (** Exercise 4 *) Lemma hoare_load l v : {{ l ↦ v }} !#l {{ w, ⌜w = v⌝ ∗ l ↦ v }}. Proof. (* don't use the IPM *) (* TODO: exercise *) Admitted. Lemma hoare_store l (v w : val) : {{ l ↦ v }} #l <- w {{ _, l ↦ w }}. Proof. (* don't use the IPM *) (* TODO: exercise *) Admitted. Lemma hoare_new (v : val) : {{ True }} ref v {{ w, ∃ l : loc, ⌜w = #l⌝ ∗ l ↦ v }}. Proof. (* don't use the IPM *) (* TODO: exercise *) Admitted. (** 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. (* don't use the IPM *) (* TODO: exercise *) Admitted. Lemma cons_ll_correct (v x : val) xs : {{ is_ll xs v }} cons_ll x v {{ u, is_ll (x :: xs) u }}. Proof. (* don't use the IPM *) (* TODO: exercise *) Admitted. Lemma head_ll_correct (v x : val) xs : {{ is_ll (x :: xs) v }} head_ll v {{ w, ⌜w = x⌝ }}. Proof. (* don't use the IPM *) (* TODO: exercise *) Admitted. Lemma tail_ll_correct v x xs : {{ is_ll (x :: xs) v }} tail_ll v {{ w, is_ll xs w }}. Proof. (* don't use the IPM *) (* TODO: exercise *) Admitted. Lemma len_ll_correct v xs : {{ is_ll xs v }} len_ll v {{ w, ⌜w = #(length xs)⌝ ∗ is_ll xs v }}. Proof. (* don't use the IPM *) (* TODO: exercise *) Admitted.