clutch.eris.tutorial.basic
From clutch.eris Require Import eris tutorial.eris_rules.
From clutch.eris.tutorial Require Import eris_rules.
(* ################################### *)
From clutch.eris.tutorial Require Import eris_rules.
(* ################################### *)
Separation logic in Rocq
The theorems we can prove in Iris have the form P ⊢ Q (type \vdash),
saying that the separation logic assertion P implies the assertion Q.
Iris is built on top of Rocq and has a custom interface called the Iris
Proof Mode (IPM). IPM has its own versions of many Rocq tactics, which
maintain a new context, called the spatial context, in addition to the usual
Rocq-level context. goal.
The regular Rocq tactics can still be used when we work within the
non-spatial context, but, in general, we shall use the new tactics that work
natively with the spatial context. These new tactics start with 'i', and
since many of them simply 'lift' the regular tactics to also work with the
spatial context, they borrow the regular names but with the 'i' prefixed.
For instance, the tactic intros H becomes iIntros "H", and instead of
apply H we use iApply "H". For technical reasons, identifiers for
hypotheses in the spatial context are strings
Let us start by provin prove the statement ⊢ P -∗ P, for all P.
We start by introducing the assumption P.
iIntros "H".
This adds P to the spatial context with the identifier "H" and we are
left with the goal P. In a typical Rocq proof, we would continue by
either exact or apply. In Iris, we use either iExact or iApply.
iApply "H".
Qed.
(* ================================================================= *)
Qed.
(* ================================================================= *)
Separation Logic Connectives
P1 ∗ P2 ⊢ Q1 ∗ Q2
To eliminate a separating conjunction we use the tactic iDestruct with
the usual destruction pattern.
iDestruct "H" as "(HP & HQ)".
Alternatively, we can introduce and destruct resources simultaneously.
(* Restart. iIntros "HP HQ" *)
Unlike ∧, the separating conjunction ∗ is not idempotent. That is,
there are Iris propositions for which P ⊢ P ∗ P is not the case. Because
of this, it is generally not possible to use iSplit to introduce ∗.
The iSplit tactic would duplicate the spatial context and is therefore
not available when the context is non-empty.
Fail iSplit.
Instead, Iris introduces the tactics iSplitL and iSplitR that allow
you to specify how you want to separate your resources to prove each
subgoal. The hypotheses mentioned by iSplitL are given to the left
subgoal, and the remaining to the right. Conversely for iSplitR.
iSplitL "HQ".
- iApply "HQ".
- iApply "HP".
Qed.
- iApply "HQ".
- iApply "HP".
Qed.
Separating conjunction has an analogue to implication which, instead of
introducing the antecedent to the assumptions with conjunction, introduces
it with separating conjunction. This connective is written as P -∗ Q and
pronounced `magic wand' or simply `wand'.
Just as with Rocq tactics, Iris supports complex nested introduction and
destruction patterns. For example, you can use a pattern like (H1 & .. & H2
& H3) as a shorthand for [H1 .. [H2 H3] ..].
Exercise: use an introduction pattern of with parentheses to prove
associativity of ∗. Note that ∗ is right-associative, so P ∗ Q ∗ R is
parsed as P ∗ (Q ∗ R).
(* *)
Lemma sep_assoc_1 (P Q R : iProp Σ) : P ∗ Q ∗ R ⊢ (P ∗ Q) ∗ R.
Proof.
(* exercise *)
Admitted.
Lemma sep_assoc_1 (P Q R : iProp Σ) : P ∗ Q ∗ R ⊢ (P ∗ Q) ∗ R.
Proof.
(* exercise *)
Admitted.
Manually splitting separating conjunctions quickly becomes tedious. To
alleviate this, the iFrame tactic automatically pairs up hypotheses with
conjuncts in the goal separation sequence.
Lemma sep_comm_v2 (P Q : iProp Σ) : P ∗ Q ⊢ Q ∗ P.
Proof.
iIntros "H".
iDestruct "H" as "[HP HQ]".
iFrame.
Qed.
Proof.
iIntros "H".
iDestruct "H" as "[HP HQ]".
iFrame.
Qed.
For assertions with multiple assumptions, i.e. nested magic wands, it is
often necessary specify which part of the context should go where. This is
done using iApply ("H" with "[H1 H2 H3] [H4 H5]"). Each set of square
brackets specifies the part of the context going to that argument.
Let's try it out.
Lemma wand_adj_1 (P Q R : iProp Σ) : (P -∗ Q -∗ R) ∗ P ∗ Q ⊢ R.
Proof.
iIntros "H".
iDestruct "H" as "(H & HP & HQ)".
Proof.
iIntros "H".
iDestruct "H" as "(H & HP & HQ)".
When applying "H", we get the subgoals P and Q. To specify that
we want to use "HP" to prove the first subgoal, and "HQ" the second,
we add "HP" in the first square bracket, and "HQ" in the second.
Here is another proof strategy based on forward-reasoning instead.
Lemma wand_adj_2 (P Q R : iProp Σ) : (P -∗ Q -∗ R) ∗ P ∗ Q ⊢ R.
Proof.
iIntros "H".
iDestruct "H" as "(H & HP & HQ)".
Proof.
iIntros "H".
iDestruct "H" as "(H & HP & HQ)".
Instead of applying "H", we can also just "feed the arguments" to the
implication. This allows us to deducing more assertions from our
assumptions instead of working backwards from the goal.
Finally, we can use the specialized implication, now exactly matching
our goal.
iApply "HR".
Qed.
Qed.
Hypotheses that fit arguments exactly can be supplied directly without a
square bracket to avoid trivial subgoals, as in the above. Try this in the
following exercise.
As usual, from a contradiction, any assertion P follows.
Disjunctions ∨ are treated just like disjunctions in Rocq. The
introduction pattern [ _ | _ ] allows us to eliminate a disjunction, while
the tactics iLeft and iRight let us introduce them.
Prove that disjunction commutes.
We can even prove the usual elimination rule for or-elimination written with
separation. This version is, however, not very useful, as it does not allow
the two cases to share resources.
Lemma or_elim (P Q R : iProp Σ) : ⊢ (P -∗ R) -∗ (Q -∗ R) -∗ P ∨ Q -∗ R.
Proof.
(* exercise *)
Admitted.
Proof.
(* exercise *)
Admitted.
Separating conjunction distributes over disjunction (for the same reason as
ordinary conjunction).
Lemma sep_or_distr_1 (P Q R : iProp Σ) : P ∗ (Q ∨ R) ⊢ P ∗ Q ∨ P ∗ R.
Proof.
(* exercise *)
Admitted.
Lemma sep_or_distr_2 (P Q R : iProp Σ) : P ∗ Q ∨ P ∗ R ⊢ P ∗ (Q ∨ R) .
Proof.
(* exercise *)
Admitted.
Proof.
(* exercise *)
Admitted.
Lemma sep_or_distr_2 (P Q R : iProp Σ) : P ∗ Q ∨ P ∗ R ⊢ P ∗ (Q ∨ R) .
Proof.
(* exercise *)
Admitted.
Iris propositions can be existentialy and universally quantified over any
Rocq type. Existential quantifiers are proved using the iExists tactic,
using the same syntax as for exists. Elimination of existentials is done
through the pattern "[%x Hx]" or as part of a "(_ & .. & _)" with a %
in front of the existential variable. (type \exists).
Lemma sep_ex_distr {A} (P : iProp Σ) (Φ : A → iProp Σ) :
(P ∗ ∃ x, Φ x) ⊣⊢ ∃ x, P ∗ Φ x.
Proof.
iSplit.
- iIntros "H".
iDestruct "H" as "(HP & HΦ)".
iDestruct "HΦ" as "(%x & HΦ)".
iExists x.
iFrame.
- (* exercise *)
Admitted.
(P ∗ ∃ x, Φ x) ⊣⊢ ∃ x, P ∗ Φ x.
Proof.
iSplit.
- iIntros "H".
iDestruct "H" as "(HP & HΦ)".
iDestruct "HΦ" as "(%x & HΦ)".
iExists x.
iFrame.
- (* exercise *)
Admitted.
Likewise, universal quantification works almost as in Rocq. To introduce a
universal qunatifier, you can either use iIntros (x y z) or iIntros "%x
%y %z". These patterns are interchangeable. To specify the parameters of
hypotheses, we write iApply ("H" $! x y z). (type \forall)
Lemma sep_all_distr {A} (P Q : A → iProp Σ) :
⊢ (∀ x, P x) ∗ (∀ x, Q x) -∗ (∀ x, P x ∗ Q x).
Proof.
(* exercise *)
Admitted.
⊢ (∀ x, P x) ∗ (∀ x, Q x) -∗ (∀ x, P x ∗ Q x).
Proof.
(* exercise *)
Admitted.
More useful introduction and elmination patterns can be found in the Iris
documentation at
https://gitlab.mpi-sws.org/iris/iris/-/blob/master/docs/proof_mode.md?ref_type=heads#introduction-patterns-ipat