Commit 52c3006d authored by Robbert Krebbers's avatar Robbert Krebbers Committed by Jacques-Henri Jourdan

Generalize proofmode.

parent 65bde879
......@@ -24,17 +24,21 @@ theories/algebra/local_updates.v
theories/algebra/gset.v
theories/algebra/coPset.v
theories/algebra/deprecated.v
theories/bi/interface.v
theories/bi/derived.v
theories/bi/big_op.v
theories/bi/bi.v
theories/bi/tactics.v
theories/bi/fractional.v
theories/base_logic/upred.v
theories/base_logic/primitive.v
theories/base_logic/derived.v
theories/base_logic/base_logic.v
theories/base_logic/tactics.v
theories/base_logic/big_op.v
theories/base_logic/hlist.v
theories/base_logic/soundness.v
theories/base_logic/double_negation.v
theories/base_logic/deprecated.v
theories/base_logic/fixpoint.v
theories/base_logic/proofmode.v
theories/base_logic/proofmode_classes.v
theories/base_logic/lib/iprop.v
theories/base_logic/lib/own.v
theories/base_logic/lib/saved_prop.v
......@@ -49,7 +53,6 @@ theories/base_logic/lib/boxes.v
theories/base_logic/lib/na_invariants.v
theories/base_logic/lib/cancelable_invariants.v
theories/base_logic/lib/counter_examples.v
theories/base_logic/lib/fractional.v
theories/base_logic/lib/gen_heap.v
theories/base_logic/lib/core.v
theories/base_logic/lib/fancy_updates_from_vs.v
......@@ -89,6 +92,7 @@ theories/proofmode/class_instances.v
theories/tests/heap_lang.v
theories/tests/one_shot.v
theories/tests/proofmode.v
theories/tests/proofmode_iris.v
theories/tests/list_reverse.v
theories/tests/tree_sum.v
theories/tests/ipm_paper.v
......
From iris.algebra Require Export excl local_updates.
From iris.base_logic Require Import base_logic.
From iris.proofmode Require Import classes.
From iris.base_logic Require Import base_logic proofmode_classes.
Set Default Proof Using "Type".
Record auth (A : Type) := Auth { authoritative : excl' A; auth_own : A }.
......
From Coq.QArith Require Import Qcanon.
From iris.algebra Require Export cmra.
From iris.proofmode Require Import classes.
From iris.base_logic Require Import proofmode_classes.
Set Default Proof Using "Type".
Notation frac := Qp (only parsing).
......
From iris.algebra Require Export frac auth.
From iris.algebra Require Export updates local_updates.
From iris.proofmode Require Import classes.
From iris.base_logic Require Import proofmode_classes.
Definition frac_authR (A : cmraT) : cmraT :=
authR (optionUR (prodR fracR A)).
......
From iris.base_logic Require Export derived.
From iris.bi Require Export bi.
Set Default Proof Using "Type".
Module Import uPred.
Export upred.uPred.
Export primitive.uPred.
Export derived.uPred.
Export bi.
End uPred.
(* Hint DB for the logic *)
......@@ -12,6 +13,6 @@ Hint Resolve pure_intro.
Hint Resolve or_elim or_intro_l' or_intro_r' : I.
Hint Resolve and_intro and_elim_l' and_elim_r' : I.
Hint Resolve persistently_mono : I.
Hint Resolve sep_elim_l' sep_elim_r' sep_mono : I.
Hint Resolve sep_mono : I. (* sep_elim_l' sep_elim_r' *)
Hint Immediate True_intro False_elim : I.
Hint Immediate iff_refl internal_eq_refl' : I.
Hint Immediate iff_refl internal_eq_refl : I.
(*
FIXME
From iris.base_logic Require Import primitive.
Set Default Proof Using "Type".
......@@ -10,3 +13,4 @@ Notation "x = y" := (uPred_pure (x%C%type = y%C%type)) (only parsing) : uPred_sc
(* Deprecated 2016-11-22. Use ⌜x ⊥ y ⌝ instead. *)
Notation "x ⊥ y" := (uPred_pure (x%C%type ⊥ y%C%type)) (only parsing) : uPred_scope.
*)
From iris.base_logic Require Export primitive.
From iris.base_logic Require Export upred.
From iris.bi Require Export interface derived.
Set Default Proof Using "Type".
Import upred.uPred primitive.uPred.
Definition uPred_iff {M} (P Q : uPred M) : uPred M := ((P Q) (Q P))%I.
Instance: Params (@uPred_iff) 1.
Infix "↔" := uPred_iff : uPred_scope.
Definition uPred_laterN {M} (n : nat) (P : uPred M) : uPred M :=
Nat.iter n uPred_later P.
Instance: Params (@uPred_laterN) 2.
Notation "▷^ n P" := (uPred_laterN n P)
(at level 20, n at level 9, P at level 20,
format "▷^ n P") : uPred_scope.
Notation "▷? p P" := (uPred_laterN (Nat.b2n p) P)
(at level 20, p at level 9, P at level 20,
format "▷? p P") : uPred_scope.
Definition uPred_persistently_if {M} (p : bool) (P : uPred M) : uPred M :=
(if p then P else P)%I.
Instance: Params (@uPred_persistently_if) 2.
Arguments uPred_persistently_if _ !_ _/.
Notation "□? p P" := (uPred_persistently_if p P)
(at level 20, p at level 9, P at level 20, format "□? p P").
Definition uPred_except_0 {M} (P : uPred M) : uPred M := False P.
Notation "◇ P" := (uPred_except_0 P)
(at level 20, right associativity) : uPred_scope.
Instance: Params (@uPred_except_0) 1.
Typeclasses Opaque uPred_except_0.
Class Timeless {M} (P : uPred M) := timelessP : P P.
Arguments timelessP {_} _ {_}.
Hint Mode Timeless + ! : typeclass_instances.
Instance: Params (@Timeless) 1.
Class Persistent {M} (P : uPred M) := persistent : P P.
Arguments persistent {_} _ {_}.
Hint Mode Persistent + ! : typeclass_instances.
Instance: Params (@Persistent) 1.
Import upred.uPred.
Import interface.bi derived.bi.
Module uPred.
Section derived.
......@@ -45,728 +10,46 @@ Context {M : ucmraT}.
Implicit Types φ : Prop.
Implicit Types P Q : uPred M.
Implicit Types A : Type.
Notation "P ⊢ Q" := (@uPred_entails M P%I Q%I). (* Force implicit argument M *)
Notation "P ⊣⊢ Q" := (equiv (A:=uPred M) P%I Q%I). (* Force implicit argument M *)
(* Derived logical stuff *)
Lemma False_elim P : False P.
Proof. by apply (pure_elim' False). Qed.
Lemma True_intro P : P True.
Proof. by apply pure_intro. Qed.
Lemma and_elim_l' P Q R : (P R) P Q R.
Proof. by rewrite and_elim_l. Qed.
Lemma and_elim_r' P Q R : (Q R) P Q R.
Proof. by rewrite and_elim_r. Qed.
Lemma or_intro_l' P Q R : (P Q) P Q R.
Proof. intros ->; apply or_intro_l. Qed.
Lemma or_intro_r' P Q R : (P R) P Q R.
Proof. intros ->; apply or_intro_r. Qed.
Lemma exist_intro' {A} P (Ψ : A uPred M) a : (P Ψ a) P a, Ψ a.
Proof. intros ->; apply exist_intro. Qed.
Lemma forall_elim' {A} P (Ψ : A uPred M) : (P a, Ψ a) a, P Ψ a.
Proof. move=> HP a. by rewrite HP forall_elim. Qed.
Hint Resolve pure_intro.
Hint Resolve or_elim or_intro_l' or_intro_r'.
Hint Resolve and_intro and_elim_l' and_elim_r'.
Hint Immediate True_intro False_elim.
Lemma impl_intro_l P Q R : (Q P R) P Q R.
Proof. intros HR; apply impl_intro_r; rewrite -HR; auto. Qed.
Lemma impl_elim_l P Q : (P Q) P Q.
Proof. apply impl_elim with P; auto. Qed.
Lemma impl_elim_r P Q : P (P Q) Q.
Proof. apply impl_elim with P; auto. Qed.
Lemma impl_elim_l' P Q R : (P Q R) P Q R.
Proof. intros; apply impl_elim with Q; auto. Qed.
Lemma impl_elim_r' P Q R : (Q P R) P Q R.
Proof. intros; apply impl_elim with P; auto. Qed.
Lemma impl_entails P Q : (P Q)%I P Q.
Proof. intros HPQ; apply impl_elim with P; rewrite -?HPQ; auto. Qed.
Lemma entails_impl P Q : (P Q) (P Q)%I.
Proof. intro. apply impl_intro_l. auto. Qed.
Lemma and_mono P P' Q Q' : (P Q) (P' Q') P P' Q Q'.
Proof. auto. Qed.
Lemma and_mono_l P P' Q : (P Q) P P' Q P'.
Proof. by intros; apply and_mono. Qed.
Lemma and_mono_r P P' Q' : (P' Q') P P' P Q'.
Proof. by apply and_mono. Qed.
Lemma or_mono P P' Q Q' : (P Q) (P' Q') P P' Q Q'.
Proof. auto. Qed.
Lemma or_mono_l P P' Q : (P Q) P P' Q P'.
Proof. by intros; apply or_mono. Qed.
Lemma or_mono_r P P' Q' : (P' Q') P P' P Q'.
Proof. by apply or_mono. Qed.
Lemma impl_mono P P' Q Q' : (Q P) (P' Q') (P P') Q Q'.
Proof.
intros HP HQ'; apply impl_intro_l; rewrite -HQ'.
apply impl_elim with P; eauto.
Qed.
Lemma forall_mono {A} (Φ Ψ : A uPred M) :
( a, Φ a Ψ a) ( a, Φ a) a, Ψ a.
Proof.
intros HP. apply forall_intro=> a; rewrite -(HP a); apply forall_elim.
Qed.
Lemma exist_mono {A} (Φ Ψ : A uPred M) :
( a, Φ a Ψ a) ( a, Φ a) a, Ψ a.
Proof. intros HΦ. apply exist_elim=> a; rewrite (HΦ a); apply exist_intro. Qed.
Global Instance and_mono' : Proper (() ==> () ==> ()) (@uPred_and M).
Proof. by intros P P' HP Q Q' HQ; apply and_mono. Qed.
Global Instance and_flip_mono' :
Proper (flip () ==> flip () ==> flip ()) (@uPred_and M).
Proof. by intros P P' HP Q Q' HQ; apply and_mono. Qed.
Global Instance or_mono' : Proper (() ==> () ==> ()) (@uPred_or M).
Proof. by intros P P' HP Q Q' HQ; apply or_mono. Qed.
Global Instance or_flip_mono' :
Proper (flip () ==> flip () ==> flip ()) (@uPred_or M).
Proof. by intros P P' HP Q Q' HQ; apply or_mono. Qed.
Global Instance impl_mono' :
Proper (flip () ==> () ==> ()) (@uPred_impl M).
Proof. by intros P P' HP Q Q' HQ; apply impl_mono. Qed.
Global Instance impl_flip_mono' :
Proper (() ==> flip () ==> flip ()) (@uPred_impl M).
Proof. by intros P P' HP Q Q' HQ; apply impl_mono. Qed.
Global Instance forall_mono' A :
Proper (pointwise_relation _ () ==> ()) (@uPred_forall M A).
Proof. intros P1 P2; apply forall_mono. Qed.
Global Instance forall_flip_mono' A :
Proper (pointwise_relation _ (flip ()) ==> flip ()) (@uPred_forall M A).
Proof. intros P1 P2; apply forall_mono. Qed.
Global Instance exist_mono' A :
Proper (pointwise_relation _ () ==> ()) (@uPred_exist M A).
Proof. intros P1 P2; apply exist_mono. Qed.
Global Instance exist_flip_mono' A :
Proper (pointwise_relation _ (flip ()) ==> flip ()) (@uPred_exist M A).
Proof. intros P1 P2; apply exist_mono. Qed.
Global Instance and_idem : IdemP () (@uPred_and M).
Proof. intros P; apply (anti_symm ()); auto. Qed.
Global Instance or_idem : IdemP () (@uPred_or M).
Proof. intros P; apply (anti_symm ()); auto. Qed.
Global Instance and_comm : Comm () (@uPred_and M).
Proof. intros P Q; apply (anti_symm ()); auto. Qed.
Global Instance True_and : LeftId () True%I (@uPred_and M).
Proof. intros P; apply (anti_symm ()); auto. Qed.
Global Instance and_True : RightId () True%I (@uPred_and M).
Proof. intros P; apply (anti_symm ()); auto. Qed.
Global Instance False_and : LeftAbsorb () False%I (@uPred_and M).
Proof. intros P; apply (anti_symm ()); auto. Qed.
Global Instance and_False : RightAbsorb () False%I (@uPred_and M).
Proof. intros P; apply (anti_symm ()); auto. Qed.
Global Instance True_or : LeftAbsorb () True%I (@uPred_or M).
Proof. intros P; apply (anti_symm ()); auto. Qed.
Global Instance or_True : RightAbsorb () True%I (@uPred_or M).
Proof. intros P; apply (anti_symm ()); auto. Qed.
Global Instance False_or : LeftId () False%I (@uPred_or M).
Proof. intros P; apply (anti_symm ()); auto. Qed.
Global Instance or_False : RightId () False%I (@uPred_or M).
Proof. intros P; apply (anti_symm ()); auto. Qed.
Global Instance and_assoc : Assoc () (@uPred_and M).
Proof. intros P Q R; apply (anti_symm ()); auto. Qed.
Global Instance or_comm : Comm () (@uPred_or M).
Proof. intros P Q; apply (anti_symm ()); auto. Qed.
Global Instance or_assoc : Assoc () (@uPred_or M).
Proof. intros P Q R; apply (anti_symm ()); auto. Qed.
Global Instance True_impl : LeftId () True%I (@uPred_impl M).
Proof.
intros P; apply (anti_symm ()).
- by rewrite -(left_id True%I uPred_and (_ _)%I) impl_elim_r.
- by apply impl_intro_l; rewrite left_id.
Qed.
Lemma False_impl P : (False P) True.
Proof.
apply (anti_symm ()); [by auto|].
apply impl_intro_l. rewrite left_absorb. auto.
Qed.
Lemma exists_impl_forall {A} P (Ψ : A uPred M) :
(( x : A, Ψ x) P) x : A, Ψ x P.
Proof.
apply equiv_spec; split.
- apply forall_intro=>x. by rewrite -exist_intro.
- apply impl_intro_r, impl_elim_r', exist_elim=>x.
apply impl_intro_r. by rewrite (forall_elim x) impl_elim_r.
Qed.
Lemma or_and_l P Q R : P Q R (P Q) (P R).
Proof.
apply (anti_symm ()); first auto.
do 2 (apply impl_elim_l', or_elim; apply impl_intro_l); auto.
Qed.
Lemma or_and_r P Q R : P Q R (P R) (Q R).
Proof. by rewrite -!(comm _ R) or_and_l. Qed.
Lemma and_or_l P Q R : P (Q R) P Q P R.
Proof.
apply (anti_symm ()); last auto.
apply impl_elim_r', or_elim; apply impl_intro_l; auto.
Qed.
Lemma and_or_r P Q R : (P Q) R P R Q R.
Proof. by rewrite -!(comm _ R) and_or_l. Qed.
Lemma and_exist_l {A} P (Ψ : A uPred M) : P ( a, Ψ a) a, P Ψ a.
Proof.
apply (anti_symm ()).
- apply impl_elim_r'. apply exist_elim=>a. apply impl_intro_l.
by rewrite -(exist_intro a).
- apply exist_elim=>a. apply and_intro; first by rewrite and_elim_l.
by rewrite -(exist_intro a) and_elim_r.
Qed.
Lemma and_exist_r {A} P (Φ: A uPred M) : ( a, Φ a) P a, Φ a P.
Proof.
rewrite -(comm _ P) and_exist_l. apply exist_proper=>a. by rewrite comm.
Qed.
Lemma or_exist {A} (Φ Ψ : A uPred M) :
( a, Φ a Ψ a) ( a, Φ a) ( a, Ψ a).
Proof.
apply (anti_symm ()).
- apply exist_elim=> a. by rewrite -!(exist_intro a).
- apply or_elim; apply exist_elim=> a; rewrite -(exist_intro a); auto.
Qed.
Lemma pure_elim φ Q R : (Q ⌜φ⌝) (φ Q R) Q R.
Proof.
intros HQ HQR. rewrite -(idemp uPred_and Q) {1}HQ.
apply impl_elim_l', pure_elim'=> ?. by apply entails_impl, HQR.
Qed.
Lemma pure_mono φ1 φ2 : (φ1 φ2) ⌜φ1 ⌜φ2.
Proof. intros; apply pure_elim with φ1; eauto. Qed.
Global Instance pure_mono' : Proper (impl ==> ()) (@uPred_pure M).
Proof. intros φ1 φ2; apply pure_mono. Qed.
Global Instance pure_flip_mono : Proper (flip impl ==> flip ()) (@uPred_pure M).
Proof. intros φ1 φ2; apply pure_mono. Qed.
Lemma pure_iff φ1 φ2 : (φ1 φ2) ⌜φ1 ⌜φ2.
Proof. intros [??]; apply (anti_symm _); auto using pure_mono. Qed.
Lemma pure_intro_l φ Q R : φ (⌜φ⌝ Q R) Q R.
Proof. intros ? <-; auto using pure_intro. Qed.
Lemma pure_intro_r φ Q R : φ (Q ⌜φ⌝ R) Q R.
Proof. intros ? <-; auto. Qed.
Lemma pure_intro_impl φ Q R : φ (Q ⌜φ⌝ R) Q R.
Proof. intros ? ->. eauto using pure_intro_l, impl_elim_r. Qed.
Lemma pure_elim_l φ Q R : (φ Q R) ⌜φ⌝ Q R.
Proof. intros; apply pure_elim with φ; eauto. Qed.
Lemma pure_elim_r φ Q R : (φ Q R) Q ⌜φ⌝ R.
Proof. intros; apply pure_elim with φ; eauto. Qed.
Lemma pure_True (φ : Prop) : φ ⌜φ⌝ True.
Proof. intros; apply (anti_symm _); auto. Qed.
Lemma pure_False (φ : Prop) : ¬φ ⌜φ⌝ False.
Proof. intros; apply (anti_symm _); eauto using pure_elim. Qed.
Lemma pure_and φ1 φ2 : ⌜φ1 φ2 ⌜φ1 ⌜φ2.
Proof.
apply (anti_symm _).
- eapply pure_elim=> // -[??]; auto.
- eapply (pure_elim φ1); [auto|]=> ?. eapply (pure_elim φ2); auto.
Qed.
Lemma pure_or φ1 φ2 : ⌜φ1 φ2 ⌜φ1 ⌜φ2.
Proof.
apply (anti_symm _).
- eapply pure_elim=> // -[?|?]; auto.
- apply or_elim; eapply pure_elim; eauto.
Qed.
Lemma pure_impl φ1 φ2 : ⌜φ1 φ2 (⌜φ1 ⌜φ2).
Proof.
apply (anti_symm _).
- apply impl_intro_l. rewrite -pure_and. apply pure_mono. naive_solver.
- rewrite -pure_forall_2. apply forall_intro=> ?.
by rewrite -(left_id True uPred_and (_→_))%I (pure_True φ1) // impl_elim_r.
Qed.
Lemma pure_forall {A} (φ : A Prop) : x, φ x x, ⌜φ x.
Proof.
apply (anti_symm _); auto using pure_forall_2.
apply forall_intro=> x. eauto using pure_mono.
Qed.
Lemma pure_exist {A} (φ : A Prop) : x, φ x x, ⌜φ x.
Proof.
apply (anti_symm _).
- eapply pure_elim=> // -[x ?]. rewrite -(exist_intro x); auto.
- apply exist_elim=> x. eauto using pure_mono.
Qed.
Lemma internal_eq_refl' {A : ofeT} (a : A) P : P a a.
Proof. rewrite (True_intro P). apply internal_eq_refl. Qed.
Hint Resolve internal_eq_refl'.
Lemma equiv_internal_eq {A : ofeT} P (a b : A) : a b P a b.
Proof. by intros ->. Qed.
Lemma internal_eq_sym {A : ofeT} (a b : A) : a b b a.
Proof. apply (internal_eq_rewrite a b (λ b, b a)%I); auto. solve_proper. Qed.
Lemma internal_eq_rewrite_contractive {A : ofeT} a b (Ψ : A uPred M) P
{HΨ : Contractive Ψ} : (P (a b)) (P Ψ a) P Ψ b.
Proof.
move: HΨ=> /contractiveI HΨ Heq ?.
apply (internal_eq_rewrite (Ψ a) (Ψ b) id _)=>//=. by rewrite -HΨ.
Qed.
Lemma pure_impl_forall φ P : (⌜φ⌝ P) ( _ : φ, P).
Proof.
apply (anti_symm _).
- apply forall_intro=> ?. by rewrite pure_True // left_id.
- apply impl_intro_l, pure_elim_l=> Hφ. by rewrite (forall_elim Hφ).
Qed.
Lemma pure_alt φ : ⌜φ⌝ _ : φ, True.
Proof.
apply (anti_symm _).
- eapply pure_elim; eauto=> H. rewrite -(exist_intro H); auto.
- by apply exist_elim, pure_intro.
Qed.
Lemma and_alt P Q : P Q b : bool, if b then P else Q.
Proof.
apply (anti_symm _); first apply forall_intro=> -[]; auto.
apply and_intro. by rewrite (forall_elim true). by rewrite (forall_elim false).
Qed.
Lemma or_alt P Q : P Q b : bool, if b then P else Q.
Proof.
apply (anti_symm _); last apply exist_elim=> -[]; auto.
apply or_elim. by rewrite -(exist_intro true). by rewrite -(exist_intro false).
Qed.
Global Instance iff_ne : NonExpansive2 (@uPred_iff M).
Proof. unfold uPred_iff; solve_proper. Qed.
Global Instance iff_proper :
Proper (() ==> () ==> ()) (@uPred_iff M) := ne_proper_2 _.
Lemma iff_refl Q P : Q P P.
Proof. rewrite /uPred_iff; apply and_intro; apply impl_intro_l; auto. Qed.
Lemma iff_equiv P Q : (P Q)%I (P Q).
Proof.
intros HPQ; apply (anti_symm ());
apply impl_entails; rewrite /uPred_valid HPQ /uPred_iff; auto.
Qed.
Lemma equiv_iff P Q : (P Q) (P Q)%I.
Proof. intros ->; apply iff_refl. Qed.
Lemma internal_eq_iff P Q : P Q P Q.
Proof.
apply (internal_eq_rewrite P Q (λ Q, P Q))%I;
first solve_proper; auto using iff_refl.
Qed.
(* Derived BI Stuff *)
Hint Resolve sep_mono.
Lemma sep_mono_l P P' Q : (P Q) P P' Q P'.
Proof. by intros; apply sep_mono. Qed.
Lemma sep_mono_r P P' Q' : (P' Q') P P' P Q'.
Proof. by apply sep_mono. Qed.
Global Instance sep_mono' : Proper (() ==> () ==> ()) (@uPred_sep M).
Proof. by intros P P' HP Q Q' HQ; apply sep_mono. Qed.
Global Instance sep_flip_mono' :
Proper (flip () ==> flip () ==> flip ()) (@uPred_sep M).
Proof. by intros P P' HP Q Q' HQ; apply sep_mono. Qed.
Lemma wand_mono P P' Q Q' : (Q P) (P' Q') (P - P') Q - Q'.
Proof.
intros HP HQ; apply wand_intro_r. rewrite HP -HQ. by apply wand_elim_l'.
Qed.
Global Instance wand_mono' : Proper (flip () ==> () ==> ()) (@uPred_wand M).
Proof. by intros P P' HP Q Q' HQ; apply wand_mono. Qed.
Global Instance wand_flip_mono' :
Proper (() ==> flip () ==> flip ()) (@uPred_wand M).
Proof. by intros P P' HP Q Q' HQ; apply wand_mono. Qed.
Global Instance sep_comm : Comm () (@uPred_sep M).
Proof. intros P Q; apply (anti_symm _); auto using sep_comm'. Qed.
Global Instance sep_assoc : Assoc () (@uPred_sep M).
Proof.
intros P Q R; apply (anti_symm _); auto using sep_assoc'.
by rewrite !(comm _ P) !(comm _ _ R) sep_assoc'.
Qed.
Global Instance True_sep : LeftId () True%I (@uPred_sep M).
Proof. intros P; apply (anti_symm _); auto using True_sep_1, True_sep_2. Qed.
Global Instance sep_True : RightId () True%I (@uPred_sep M).
Proof. by intros P; rewrite comm left_id. Qed.
Lemma sep_elim_l P Q : P Q P.
Proof. by rewrite (True_intro Q) right_id. Qed.
Lemma sep_elim_r P Q : P Q Q.
Proof. by rewrite (comm ())%I; apply sep_elim_l. Qed.
Lemma sep_elim_l' P Q R : (P R) P Q R.
Proof. intros ->; apply sep_elim_l. Qed.
Lemma sep_elim_r' P Q R : (Q R) P Q R.
Proof. intros ->; apply sep_elim_r. Qed.
Hint Resolve sep_elim_l' sep_elim_r'.
Lemma sep_intro_True_l P Q R : P%I (R Q) R P Q.
Proof. by intros; rewrite -(left_id True%I uPred_sep R); apply sep_mono. Qed.
Lemma sep_intro_True_r P Q R : (R P) Q%I R P Q.
Proof. by intros; rewrite -(right_id True%I uPred_sep R); apply sep_mono. Qed.
Lemma sep_elim_True_l P Q R : P (P R Q) R Q.
Proof. by intros HP; rewrite -HP left_id. Qed.
Lemma sep_elim_True_r P Q R : P (R P Q) R Q.
Proof. by intros HP; rewrite -HP right_id. Qed.
Lemma wand_intro_l P Q R : (Q P R) P Q - R.
Proof. rewrite comm; apply wand_intro_r. Qed.
Lemma wand_elim_l P Q : (P - Q) P Q.
Proof. by apply wand_elim_l'. Qed.
Lemma wand_elim_r P Q : P (P - Q) Q.
Proof. rewrite (comm _ P); apply wand_elim_l. Qed.
Lemma wand_elim_r' P Q R : (Q P - R) P Q R.
Proof. intros ->; apply wand_elim_r. Qed.
Lemma wand_apply P Q R S : (P Q - R) (S P Q) S R.
Proof. intros HR%wand_elim_l' HQ. by rewrite HQ. Qed.
Lemma wand_frame_l P Q R : (Q - R) P Q - P R.
Proof. apply wand_intro_l. rewrite -assoc. apply sep_mono_r, wand_elim_r. Qed.
Lemma wand_frame_r P Q R : (Q - R) Q P - R P.
Proof.
apply wand_intro_l. rewrite ![(_ P)%I]comm -assoc.
apply sep_mono_r, wand_elim_r.
Qed.
Lemma wand_diag P : (P - P) True.
Proof. apply (anti_symm _); auto. apply wand_intro_l; by rewrite right_id. Qed.
Lemma wand_True P : (True - P) P.
Proof.
apply (anti_symm _); last by auto using wand_intro_l.
eapply sep_elim_True_l; last by apply wand_elim_r. done.
Qed.
Lemma wand_entails P Q : (P - Q)%I P Q.
Proof.
intros HPQ. eapply sep_elim_True_r; first exact: HPQ. by rewrite wand_elim_r.