Module separation

Require Export list vector.

Local Unset Elimination Schemes.
Class SeparationOps (A : Type) : Type := {
  sep_valid : AProp;
  sep_empty :> Empty A;
  sep_disjoint :> Disjoint A;
  sep_union :> Union A;
  sep_subseteq :> SubsetEq A;
  sep_difference :> Difference A;
  sep_splittable : AProp;
  sep_half :> Half A;
  sep_unmapped : AProp;
  sep_unshared : AProp;
  sep_valid_dec (x : A) :> Decision (sep_valid x);
  sep_subseteq_dec (x y : A) :> Decision (xy);
  sep_disjoint_dec (x y : A) :> Decision (xy);
  sep_eq_dec (x y : A) :> Decision (x = y);
  sep_unshared_dec (x : A) :> Decision (sep_unshared x);
  sep_splittable_dec (x : A) :> Decision (sep_splittable x);
  sep_unmapped_dec (x : A) :> Decision (sep_unmapped x)
}.
Arguments sep_valid _ _ _ : simpl never.
Arguments sep_empty _ _ : simpl never.
Arguments sep_disjoint _ _ _ _ : simpl never.
Arguments sep_union _ _ _ _ : simpl never.
Arguments sep_subseteq _ _ _ _ : simpl never.
Arguments sep_difference _ _ _ _ : simpl never.
Arguments sep_splittable _ _ _ : simpl never.
Arguments sep_half _ _ _ : simpl never.
Arguments sep_unmapped _ _ _ : simpl never.
Arguments sep_unshared _ _ _ : simpl never.
Arguments sep_valid_dec _ _ _ : simpl never.
Arguments sep_subseteq_dec _ _ _ _ : simpl never.
Arguments sep_disjoint_dec _ _ _ _ : simpl never.
Arguments sep_eq_dec _ _ _ _ : simpl never.
Arguments sep_unshared_dec _ _ _ : simpl never.
Arguments sep_splittable_dec _ _ _ : simpl never.
Arguments sep_unmapped_dec _ _ _ : simpl never.
Ltac sep_unfold :=
  unfold disjoint, sep_disjoint, sep_valid, subseteq, sep_subseteq,
  sep_unshared, sep_splittable, sep_unmapped, empty, sep_empty, union,
  sep_union, difference, sep_difference, half, sep_half; simpl.

Class Separation (A : Type) `{SeparationOps A} : Prop := {
  sep_inhabited : ∃ x : A, sep_valid x ∧ ¬sep_unmapped x;
  sep_disjoint_valid_l (x y : A) : xysep_valid x;
  sep_union_valid (x y : A) : xysep_valid (xy);
  sep_disjoint_empty_l (x : A) : sep_valid x → ∅ ⊥ x;
  sep_left_id (x : A) : sep_valid x → ∅ ∪ x = x;
  sep_symmetric :> Symmetric (@disjoint A _);
  sep_commutative' (x y : A) : xyxy = yx;
  sep_disjoint_ll (x y z : A) : xyxyzxz;
  sep_disjoint_move_l (x y z : A) : xyxyzxyz;
  sep_associative' (x y z : A) :
    yzxyzx ∪ (yz) = (xy) ∪ z;
  sep_positive_l' (x y : A) : xyxy = ∅ → x = ∅;
  sep_cancel_l' (x y z : A) :
    zxzyzx = zyx = y;
  sep_union_subseteq_l' (x y : A) : xyxxy;
  sep_disjoint_difference' (x y : A) : xyxyx;
  sep_union_difference (x y : A) : xyxyx = y;
  sep_splittable_union' (x : A) : xxsep_splittable (xx);
  sep_splittable_weaken (x y : A) : sep_splittable yxysep_splittable x;
  sep_disjoint_half' (x : A) : sep_splittable x → ½ x ⊥ ½ x;
  sep_union_half (x : A) : sep_splittable x → ½ x ∪ ½ x = x;
  sep_union_half_distr' (x y : A) :
    xysep_splittable (xy) → ½ (xy) = ½ x ∪ ½ y;
  sep_unmapped_valid x : sep_unmapped xsep_valid x;
  sep_unmapped_empty : sep_unmapped ∅;
  sep_unmapped_weaken x y : sep_unmapped yxysep_unmapped x;
  sep_unmapped_union_2' (x y : A) :
    xysep_unmapped xsep_unmapped ysep_unmapped (xy);
  sep_unshared_spec' (x : A) :
    sep_unshared xsep_valid x ∧ ∀ y, xysep_unmapped y;
  sep_unshared_unmapped (x : A) : sep_unshared xsep_unmapped xFalse
}.
Arguments sep_inhabited _ {_ _} : clear implicits.

We define a relation xs1 ≡⊥ xs2 that states that lists xs1 and xs2 behave equivalently with respect to disjointness. For example, we have ∅ :: xs ≡⊥ xs and xy :: xs ≡⊥ x :: y :: xs. Since this relation is an equivalence relation, and is respected by the list operations, it allows us to use Coq's setoid mechanism to conveniently reason about disjoint permissions/ memories/... Likewise, we define an order xs1 ⊆⊥ xs2.
Definition sep_disjoint_le `{SeparationOps A} : relation (list A) :=
  λ xs1 xs2, ∀ x, ⊥ (x :: xs1) → ⊥ (x :: xs2).
Notation "xs ⊆⊥ ys" := (sep_disjoint_le xs ys)
  (at level 70, format "xs ⊆⊥ ys") : C_scope.
Notation "(⊆⊥)" := (sep_disjoint_le) (only parsing) : C_scope.

Definition sep_disjoint_equiv `{SeparationOps A} : relation (list A) :=
  λ xs1 xs2, xs1 ⊆⊥ xs2xs2 ⊆⊥ xs1.
Notation "xs ≡⊥ ys" := (sep_disjoint_equiv xs ys)
  (at level 70, format "xs ≡⊥ ys") : C_scope.
Notation "(≡⊥)" := sep_disjoint_equiv (only parsing) : C_scope.

Section separation.
Context `{Separation A}.
Implicit Types x y z : A.
Implicit Types xs ys zs : list A.

Properties of the (⊥) relation

Lemma sep_disjoint_empty_r x : sep_valid xx ⊥ ∅.
Proof. symmetry. by apply sep_disjoint_empty_l. Qed.
Lemma sep_disjoint_valid_r x y : xysep_valid y.
Proof. rewrite (symmetry_iff (⊥)). apply sep_disjoint_valid_l. Qed.
Lemma sep_disjoint_lr x y z : xyxyzyz.
Proof. intro. rewrite sep_commutative' by done. by apply sep_disjoint_ll. Qed.
Lemma sep_disjoint_rl x y z : yzxyzxy.
Proof. rewrite !(symmetry_iff _ x). apply sep_disjoint_ll. Qed.
Lemma sep_disjoint_rr x y z : yzxyzxz.
Proof. intro. rewrite sep_commutative' by done. by apply sep_disjoint_rl. Qed.
Lemma sep_disjoint_move_r x y z : yzxyzxyz.
Proof.
  intros. symmetry. rewrite sep_commutative'; [|eauto using sep_disjoint_rl].
  apply sep_disjoint_move_l; [done |]. by rewrite sep_commutative'.
Qed.


Algebraic properties

Lemma sep_right_id x : sep_valid xx ∪ ∅ = x.
Proof.
  intros. by rewrite sep_commutative', sep_left_id
    by auto using sep_disjoint_empty_r.
Qed.

Lemma sep_empty_valid : sep_valid ∅.
Proof.
  destruct (sep_inhabited A) as (x&Hx&_).
  by apply sep_disjoint_valid_l with x, sep_disjoint_empty_l.
Qed.

Lemma sep_positive_r' x y : xyxy = ∅ → y = ∅.
Proof. intro. rewrite sep_commutative' by done. by apply sep_positive_l'. Qed.
Lemma sep_union_empty' x y : xyxy = ∅ ↔ x = ∅ ∧ y = ∅.
Proof.
  split; [eauto using sep_positive_l', sep_positive_r'|].
  intros [-> ->]; eauto using sep_left_id, sep_disjoint_valid_l.
Qed.

Lemma sep_cancel_r' x y z : xzyzxz = yzx = y.
Proof.
  intros ??. rewrite !(sep_commutative' _ z) by done. by apply sep_cancel_l'.
Qed.

Lemma sep_cancel_empty_l x y : xyxy = yx = ∅.
Proof.
  intros. apply sep_cancel_r' with y;
    rewrite ?sep_left_id by eauto using sep_disjoint_valid_l;
    eauto using sep_disjoint_empty_l, sep_disjoint_valid_l.
Qed.

Lemma sep_cancel_empty_r x y : xyxy = xy = ∅.
Proof.
  intro. rewrite sep_commutative' by done. by apply sep_cancel_empty_l.
Qed.

Lemma sep_associative_rev x y z : xyxyzxyz = x ∪ (yz).
Proof.
  eauto using eq_sym, sep_associative', sep_disjoint_move_l, sep_disjoint_lr.
Qed.

Lemma sep_permute x y z : xyxyzxyz = xzy.
Proof.
  intros. assert (xz) by eauto using sep_disjoint_ll.
  assert (xzy).
  { rewrite sep_commutative' by done. by apply sep_disjoint_move_r. }
  by rewrite !sep_associative_rev,
    (sep_commutative' y) by eauto using sep_disjoint_lr.
Qed.


Properties of the (⊆) relation

Lemma sep_subseteq_spec' x y : xy ↔ ∃ z, y = xzxz.
Proof.
  split; [|intros (?&->&?); by apply sep_union_subseteq_l']. exists (yx).
  eauto using sep_disjoint_difference', sep_union_difference, eq_sym.
Qed.

Lemma sep_subseteq_valid_r x y : xysep_valid y.
Proof.
  rewrite !sep_subseteq_spec'. intros (z&->&?). by apply sep_union_valid.
Qed.

Lemma sep_subseteq_valid_l x y : xysep_valid x.
Proof.
  rewrite !sep_subseteq_spec'. intros (z&_&?).
  by apply sep_disjoint_valid_l with z.
Qed.

Lemma sep_reflexive x : sep_valid xxx.
Proof.
  rewrite sep_subseteq_spec'. eexists ∅.
  rewrite sep_right_id; auto using sep_disjoint_empty_r.
Qed.

Global Instance: Transitive (@subseteq A _).
Proof.
  intros x y z. rewrite !sep_subseteq_spec'. intros (z1&->&?) (z2&->&?).
  exists (z1z2); eauto 8 using sep_associative',
    sep_disjoint_lr, sep_disjoint_move_l, eq_sym.
Qed.

Global Instance: AntiSymmetric (=) (@subseteq A _).
Proof.
  intros x y. rewrite !sep_subseteq_spec'; intros (z1&->&?) (z2&Hx&?).
  rewrite <-(sep_right_id x) in Hx at 1 by eauto using sep_disjoint_valid_l.
  rewrite <-sep_associative' in Hx by
    eauto using sep_disjoint_move_l, sep_disjoint_lr.
  apply sep_cancel_l' in Hx;
    eauto using sep_disjoint_empty_r, sep_disjoint_move_l, sep_disjoint_valid_l.
  by rewrite (sep_positive_l' z1 z2), sep_right_id by
    (by eauto 2 using sep_disjoint_lr, sep_disjoint_valid_l).
Qed.

Lemma sep_subseteq_empty x : sep_valid x → ∅ ⊆ x.
Proof.
  intros. rewrite sep_subseteq_spec'. exists x.
  rewrite sep_left_id; auto using sep_disjoint_empty_l.
Qed.

Lemma sep_union_subseteq_r' x y : xyyxy.
Proof.
  intro. rewrite sep_commutative' by done. by apply sep_union_subseteq_l'.
Qed.

Lemma sep_disjoint_weaken_l x y z : xyzxzy.
Proof.
  rewrite !sep_subseteq_spec'.
  intros ? (?&->&?); eauto using sep_disjoint_ll.
Qed.

Lemma sep_disjoint_weaken_r x y z : xyzyxz.
Proof.
  rewrite !sep_subseteq_spec'.
  intros ? (?&->&?); eauto using sep_disjoint_rl.
Qed.

Global Instance: Proper ((⊆) ==> (⊆) ==> flip impl) (@disjoint A _).
Proof.
  repeat intro; eauto using sep_disjoint_weaken_l, sep_disjoint_weaken_r.
Qed.

Lemma sep_union_difference_alt x y : xy → (xy) ∖ x = y.
Proof.
  intros. apply sep_cancel_l' with x;
    auto using sep_disjoint_difference', sep_union_subseteq_l'.
  by rewrite sep_union_difference by auto using sep_union_subseteq_l'.
Qed.

Lemma sep_difference_subseteq x y : xyyxy.
Proof.
  rewrite sep_subseteq_spec'; intros (z&->&?).
  rewrite sep_union_difference_alt; auto using sep_union_subseteq_r'.
Qed.


Properties of the (∖) operation

Lemma sep_difference_valid x y : xysep_valid (yx).
Proof. eauto using sep_disjoint_valid_r, sep_disjoint_difference'. Qed.
Lemma sep_difference_diag x : sep_valid xxx = ∅.
Proof.
  intros. apply (sep_cancel_l' _ _ x);
    auto using sep_disjoint_difference', sep_disjoint_empty_r, sep_reflexive.
  by rewrite sep_union_difference, sep_right_id by auto using sep_reflexive.
Qed.

Lemma sep_difference_empty x : sep_valid xx ∖ ∅ = x.
Proof.
  intros. by rewrite <-(sep_left_id (x ∖ ∅)), sep_union_difference
    by auto using sep_difference_valid, sep_subseteq_empty.
Qed.

Lemma sep_difference_empty_rev x y : xyyx = ∅ → x = y.
Proof.
  intros ? Hxy. by rewrite <-(sep_right_id x), <-Hxy,
    sep_union_difference by eauto using sep_subseteq_valid_l.
Qed.


Properties of the half operation

Lemma sep_splittable_valid x : sep_splittable xsep_valid x.
Proof.
  intros. rewrite <-(sep_union_half x) by done.
  auto using sep_union_valid, sep_disjoint_half'.
Qed.

Lemma sep_half_valid x : sep_splittable xsep_validx).
Proof. eauto using sep_disjoint_valid_l, sep_disjoint_half'. Qed.
Lemma sep_half_subseteq x : sep_splittable x → ½ xx.
Proof.
  rewrite sep_subseteq_spec'. intros. existsx).
  eauto using sep_disjoint_half', sep_union_half, eq_sym.
Qed.

Lemma sep_splittable_empty : sep_splittable ∅.
Proof.
  rewrite <-(sep_right_id ∅) by auto using sep_empty_valid.
  apply sep_splittable_union';
    auto using sep_disjoint_empty_l, sep_empty_valid.
Qed.

Lemma sep_half_empty : ½ (∅ : A) = ∅.
Proof.
  apply sep_positive_l' with (½ ∅);
    eauto using sep_union_half, sep_disjoint_half', sep_splittable_empty.
Qed.

Lemma sep_half_empty_rev x : sep_splittable x → ½ x = ∅ → x = ∅.
Proof.
  intros ? Hx. by rewrite <-(sep_union_half x), !Hx, sep_left_id
    by auto using sep_empty_valid.
Qed.

Lemma sep_splittable_half x : sep_splittable xsep_splittablex).
Proof. eauto using sep_splittable_weaken, sep_half_subseteq. Qed.

Properties of the sep_unmapped predicate

Lemma sep_unmapped_empty_alt x : x = ∅ → sep_unmapped x.
Proof. intros ->; by apply sep_unmapped_empty. Qed.
Lemma sep_unmapped_union_l' x y :
  xysep_unmapped (xy) → sep_unmapped x.
Proof. eauto using sep_unmapped_weaken, sep_union_subseteq_l'. Qed.
Lemma sep_unmapped_union_r' x y :
  xysep_unmapped (xy) → sep_unmapped y.
Proof. eauto using sep_unmapped_weaken, sep_union_subseteq_r'. Qed.
Lemma sep_unmapped_union' x y :
  xysep_unmapped (xy) ↔ sep_unmapped xsep_unmapped y.
Proof.
  naive_solver eauto using sep_unmapped_union_l',
    sep_unmapped_union_r', sep_unmapped_union_2'.
Qed.

Lemma sep_unmapped_half x :
  sep_splittable xsep_unmappedx) ↔ sep_unmapped x.
Proof.
  intros. rewrite <-(sep_union_half x) at 2 by done. rewrite
    sep_unmapped_union' by eauto using sep_disjoint_half'; tauto.
Qed.

Lemma sep_unmapped_half_1 x :
  sep_splittable xsep_unmappedx) → sep_unmapped x.
Proof. intros. by apply sep_unmapped_half. Qed.
Lemma sep_unmapped_difference x y :
  xysep_unmapped xsep_unmapped (yx) ↔ sep_unmapped y.
Proof.
  intros. rewrite <-(sep_union_difference x y) at 2 by done.
  by rewrite sep_unmapped_union' by eauto using sep_disjoint_difference'.
Qed.

Lemma sep_unmapped_difference_1 x y :
  xysep_unmapped xsep_unmapped (yx) → sep_unmapped y.
Proof. intros. by apply (sep_unmapped_difference x y). Qed.
Lemma sep_unmapped_difference_2 x y :
  xysep_unmapped ysep_unmapped (yx).
Proof. intros. by apply (sep_unmapped_difference x y). Qed.

Properties of the sep_unshared predicate

Lemma sep_unshared_empty : ¬sep_unshared ∅.
Proof.
  rewrite sep_unshared_spec'; intros [??].
  destruct (sep_inhabited A) as (x&?&[]); eauto using sep_disjoint_empty_l.
Qed.

Lemma sep_unshared_ne_empty x : sep_unshared xx ≠ ∅.
Proof. intros ? ->. by apply sep_unshared_empty. Qed.
Lemma sep_unshared_valid x : sep_unshared xsep_valid x.
Proof. rewrite sep_unshared_spec'. by intros [??]. Qed.
Lemma sep_disjoint_unshared_unmapped x y :
  xysep_unshared xsep_unmapped y.
Proof. rewrite sep_unshared_spec'; naive_solver. Qed.
Lemma sep_unshared_weaken x y : sep_unshared xxysep_unshared y.
Proof.
  rewrite !sep_unshared_spec'.
  naive_solver eauto using sep_disjoint_weaken_l, sep_subseteq_valid_r.
Qed.

Lemma sep_unshared_union_l' x y :
  xysep_unshared xsep_unshared (xy).
Proof. eauto using sep_unshared_weaken, sep_union_subseteq_l'. Qed.
Lemma sep_unshared_union_r' x y :
  xysep_unshared ysep_unshared (xy).
Proof. eauto using sep_unshared_weaken, sep_union_subseteq_r'. Qed.

Properties of disjointness of lists

Lemma sep_disjoint_list_valid xs : ⊥ xsForall sep_valid xs.
Proof. induction 1; constructor; eauto using sep_disjoint_valid_l. Qed.
Lemma sep_disjoint_list_singleton x : ⊥ [x] ↔ sep_valid x.
Proof.
  intros. rewrite !disjoint_list_cons, disjoint_list_nil; simpl.
  intuition eauto using sep_disjoint_empty_r, sep_disjoint_valid_l.
Qed.

Lemma sep_disjoint_list_double x y : ⊥ [x; y] ↔ xy.
Proof.
  rewrite disjoint_list_cons, sep_disjoint_list_singleton; simpl. split.
  * intros [Hxy ?]. by rewrite sep_right_id in Hxy.
  * intros. rewrite sep_right_id; eauto using sep_disjoint_valid_r.
Qed.

Lemma sep_disjoint_list_double_1 x y : ⊥ [x; y] → xy.
Proof. by rewrite sep_disjoint_list_double. Qed.
Lemma sep_disjoint_list_double_2 x y : xy → ⊥ [x; y].
Proof. by rewrite sep_disjoint_list_double. Qed.
Lemma sep_disjoint_list_symmetric x y : ⊥ [x; y] → ⊥ [y; x].
Proof. by rewrite !sep_disjoint_list_double. Qed.
Hint Immediate sep_disjoint_list_double_1 sep_disjoint_list_symmetric.
Hint Resolve sep_disjoint_list_double_2.
Lemma sep_subseteq_spec x y : xy ↔ ∃ z, y = xz ∧ ⊥ [x; z].
Proof.
  setoid_rewrite sep_disjoint_list_double. apply sep_subseteq_spec'.
Qed.

Lemma sep_associative x y z : ⊥ [x; y; z] → x ∪ (yz) = (xy) ∪ z.
Proof.
  rewrite !disjoint_list_cons; simpl. intros (Hxyz&Hyz&?&_).
  rewrite sep_right_id in Hxyz, Hyz by eauto using sep_disjoint_valid_l.
  by apply sep_associative'.
Qed.

Lemma sep_commutative x y : ⊥ [x; y] → xy = yx.
Proof. rewrite sep_disjoint_list_double. apply sep_commutative'. Qed.

Lemma sep_cancel_l x y z : ⊥ [z; x] → ⊥ [z; y] → zx = zyx = y.
Proof. eauto using sep_cancel_l', sep_disjoint_list_double_1. Qed.
Lemma sep_cancel_r x y z : ⊥ [x; z] → ⊥ [y; z] → xz = yzx = y.
Proof.
  intros ??. rewrite !(sep_commutative _ z) by done. eauto using sep_cancel_l.
Qed.

Lemma sep_positive_l x y : ⊥ [x; y] → xy = ∅ → x = ∅.
Proof. rewrite sep_disjoint_list_double. eauto using sep_positive_l'. Qed.
Lemma sep_positive_r x y : ⊥ [x; y] → xy = ∅ → y = ∅.
Proof. rewrite sep_disjoint_list_double. apply sep_positive_r'. Qed.
Lemma sep_union_subseteq_l x y : ⊥[x; y] → xxy.
Proof. rewrite sep_disjoint_list_double. apply sep_union_subseteq_l'. Qed.
Lemma sep_union_subseteq_r x y : ⊥[x; y] → yxy.
Proof. rewrite sep_disjoint_list_double. apply sep_union_subseteq_r'. Qed.
Lemma sep_union_subseteq_l_transitive x y z : ⊥ [y; z] → xyxyz.
Proof. intros. transitivity y; auto using sep_union_subseteq_l. Qed.
Lemma sep_union_subseteq_r_transitive x y z : ⊥ [y; z] → xzxyz.
Proof. intros. transitivity z; auto using sep_union_subseteq_r. Qed.
Lemma sep_preserving_l x y z : ⊥ [z; y] → xyzxzy.
Proof.
  rewrite !sep_subseteq_spec; setoid_rewrite sep_disjoint_list_double.
  intros ? (z1&->&?). exists z1.
  rewrite sep_associative'; auto using sep_disjoint_move_r.
Qed.

Lemma sep_preserving_r x y z : ⊥ [y; z] → xyxzyz.
Proof.
  rewrite sep_disjoint_list_double; intros.
  rewrite !(sep_commutative' _ z) by eauto using sep_disjoint_weaken_l.
  apply sep_preserving_l; auto.
Qed.

Lemma sep_preserving x y z z' : ⊥ [y; z'] → xyzz' → xzyz'.
Proof.
  rewrite sep_disjoint_list_double; intros.
  transitivity (xz'); auto using sep_preserving_r.
  apply sep_preserving_l; eauto using sep_disjoint_weaken_l.
Qed.

Lemma sep_reflecting_l x y z : ⊥ [z; x] → ⊥ [z; y] → zxzyxy.
Proof.
  rewrite !sep_subseteq_spec; setoid_rewrite sep_disjoint_list_double.
  intros ?? (z1&?&?). exists z1. split; eauto 2 using sep_disjoint_lr.
  apply (sep_cancel_l' _ _ z); auto using sep_disjoint_move_l.
  by rewrite sep_associative' by
    eauto using sep_disjoint_lr, sep_disjoint_move_l.
Qed.

Lemma sep_reflecting_r x y z : ⊥ [x; z] → ⊥ [y; z] → xzyzxy.
Proof.
  intros ??. rewrite !(sep_commutative _ z) by done.
  eauto using sep_reflecting_l.
Qed.

Lemma sep_disjoint_difference x y : xy → ⊥[x; yx].
Proof. rewrite sep_disjoint_list_double. apply sep_disjoint_difference'. Qed.
Lemma sep_splittable_union x : ⊥ [x; x] → sep_splittable (xx).
Proof. rewrite sep_disjoint_list_double. apply sep_splittable_union'. Qed.
Lemma sep_disjoint_half x : sep_splittable x → ⊥ [½ x; ½ x].
Proof. rewrite sep_disjoint_list_double. apply sep_disjoint_half'. Qed.
Lemma sep_splittable_spec x : sep_splittable x ↔ ∃ y, x = yy ∧ ⊥ [y; y].
Proof.
  split.
  * existsx); eauto using sep_disjoint_half, sep_union_half, eq_sym.
  * intros (?&->&?); auto using sep_splittable_union.
Qed.

Lemma sep_union_half_distr x y :
  ⊥ [x; y] → sep_splittable (xy) → ½ (xy) = ½ x ∪ ½ y.
Proof. rewrite sep_disjoint_list_double. apply sep_union_half_distr'. Qed.
Lemma sep_half_unique x y : ⊥ [y; y] → x = yyy = ½ x.
Proof.
  intros ? ->.
  assert (sep_splittable (yy)) by auto using sep_splittable_union.
  assert (sep_splittable y) by
    eauto using sep_splittable_weaken, sep_union_subseteq_l.
  by rewrite sep_union_half_distr, sep_union_half by done.
Qed.

Lemma sep_union_list_valid xs : ⊥ xssep_valid (⋃ xs).
Proof. induction 1; simpl; auto using sep_empty_valid, sep_union_valid. Qed.
Lemma sep_disjoint_contains_aux xs1 xs2 :
  ⊥ xs2xs1 `contains` xs2 → ⊥ xs1 ∧ ⋃ xs1 ⊆ ⋃ xs2.
Proof.
  intros Hxs2 Hxs. revert Hxs2. induction Hxs as
  [|x xs1 xs2 ? IH|x1 x2 xs|x xs1 xs2 ? IH|xs1 xs2 xs3 ? IH1 ? IH2]; simpl in *.
  * auto using sep_reflexive, sep_empty_valid.
  * rewrite !disjoint_list_cons. intros [??]. destruct IH as [IH1 IH2]; auto.
    eauto 7 using sep_preserving_l, sep_disjoint_weaken_r.
  * rewrite !disjoint_list_cons; simpl. intros (?&?&?). split_ands.
    + apply sep_disjoint_move_l.
      { symmetry. eauto using sep_disjoint_rl. }
      rewrite sep_commutative' by (symmetry; eauto using sep_disjoint_rl).
      eauto using sep_disjoint_move_r.
    + eauto using sep_disjoint_rr.
    + done.
    + rewrite (sep_associative' x1), (sep_commutative' x1 x2)
        by eauto using sep_disjoint_rl.
      assert (x2x1 ∪ ⋃ xs).
      { rewrite (sep_commutative' x1) by eauto 2 using sep_disjoint_rr.
        by apply sep_disjoint_move_l. }
      rewrite <-sep_associative' by (eauto 2 using sep_disjoint_rr).
      by apply sep_reflexive, sep_union_valid.
  * rewrite !disjoint_list_cons. intros [??].
    destruct IH as [IH1 IH2]; eauto using sep_union_subseteq_r_transitive.
  * intros. destruct IH1; auto; destruct IH2; auto.
    split; auto. by transitivity (⋃ xs2).
Qed.

Lemma sep_disjoint_contains xs1 xs2 : ⊥ xs2xs1 `contains` xs2 → ⊥ xs1.
Proof. intros. by apply (sep_disjoint_contains_aux xs1 xs2). Qed.
Lemma sep_union_list_subseteq xs1 xs2 :
  ⊥ xs2xs1 `contains` xs2 → ⋃ xs1 ⊆ ⋃ xs2.
Proof. intros. by apply sep_disjoint_contains_aux. Qed.
Global Instance: Proper (@Permutation A ==> iff) disjoint_list.
Proof.
  intros xs1 xs2 Hxs; split; intros.
  * apply (sep_disjoint_contains xs2 xs1). done. by rewrite Hxs.
  * apply (sep_disjoint_contains xs1 xs2). done. by rewrite Hxs.
Qed.

Lemma sep_list_preserving xs1 xs2 : ⊥ xs2xs1 ⊆* xs2 → ⋃ xs1 ⊆ ⋃ xs2.
Proof.
  intros Hxs2. induction 1; simpl; inversion_clear Hxs2;
    auto using sep_preserving, sep_reflexive, sep_empty_valid.
Qed.

Lemma sep_disjoint_empty_alt xs : ⊥ (∅ :: xs) ↔ ⊥ xs.
Proof.
  rewrite disjoint_list_cons. intuition auto using sep_disjoint_empty_l.
  eauto using sep_disjoint_empty_l, sep_union_list_valid.
Qed.

Lemma sep_disjoint_alt x y xs : ⊥ (x :: y :: xs) ↔ xy ∧ ⊥ (xy :: xs).
Proof.
  rewrite !disjoint_list_cons. simpl. split; intros (?&?&?).
  * eauto using sep_disjoint_rl, sep_disjoint_move_r.
  * eauto using sep_disjoint_lr, sep_disjoint_move_l.
Qed.

Lemma sep_disjoint_list_alt xs1 xs2 :
  ⊥ (xs1 ++ xs2) ↔ ⊥ xs1 ∧ ⊥ (⋃ xs1 :: xs2).
Proof.
  revert xs2. induction xs1 as [|x xs1 IH]; simpl; intros xs2.
  { rewrite sep_disjoint_empty_alt, disjoint_list_nil. naive_solver. }
  rewrite Permutation_middle, IH, Permutation_swap, sep_disjoint_alt.
  rewrite (disjoint_list_cons x). naive_solver.
Qed.

Lemma sep_unmapped_union_l x y :
  ⊥ [x; y] → sep_unmapped (xy) → sep_unmapped x.
Proof. eauto using sep_unmapped_weaken, sep_union_subseteq_l. Qed.
Lemma sep_unmapped_union_r x y :
  ⊥ [x; y] → sep_unmapped (xy) → sep_unmapped y.
Proof. eauto using sep_unmapped_weaken, sep_union_subseteq_r. Qed.

Properties of (⊆⊥)

Global Instance: PreOrder (⊆⊥).
Proof. unfold sep_disjoint_le. split; red; naive_solver. Qed.
Global Instance: Proper ((⊆⊥) ==> impl) disjoint_list.
Proof.
  intros xs1 xs2 Hxs. red. rewrite <-(sep_disjoint_empty_alt xs1),
    <-(sep_disjoint_empty_alt xs2). by apply (Hxs ∅).
Qed.

Global Instance: Proper ((≡ₚ) ==> (≡ₚ) ==> iff) (⊆⊥).
Proof.
  unfold sep_disjoint_le, impl. intros xs1 xs2 Hxs12 xs3 xs4 Hxs34.
  by setoid_rewrite Hxs12; setoid_rewrite Hxs34.
Qed.

Global Instance: Proper ((⊆⊥) ==> (⊆⊥)) (z ::).
Proof.
  unfold sep_disjoint_le, impl. intros z xs1 xs2 Hxs12 y; subst.
  rewrite !sep_disjoint_alt. naive_solver.
Qed.

Global Instance: Proper (flip (⊆⊥) ==> flip (⊆⊥)) (z ::).
Proof. by intros z x y Hxy; simpl in *; rewrite Hxy. Qed.
Global Instance: Proper ((⊆⊥) ==> (⊆⊥) ==> (⊆⊥)) (++).
Proof.
  unfold sep_disjoint_le. intros xs1 xs2 Hxs12 xs3 xs4 Hxs34 y.
  apply impl_transitive with ( ⊥ (y :: xs2 ++ xs3)).
  * rewrite !(commutative (++) _ xs3), !app_comm_cons.
    rewrite !sep_disjoint_list_alt. naive_solver.
  * rewrite !app_comm_cons, !sep_disjoint_list_alt. naive_solver.
Qed.

Global Instance: Proper (flip (⊆⊥) ==> flip (⊆⊥) ==> flip (⊆⊥)) (++).
Proof. by intros x1 y1 Hxy1 x2 y2 Hxy2; simpl in *; rewrite Hxy1, Hxy2. Qed.
Lemma sep_disjoint_cons_le_inj x y xs : [x] ⊆⊥ [y] → x :: xs ⊆⊥ y :: xs.
Proof. intros. change ([x] ++ xs ⊆⊥ [y] ++ xs). by f_equiv. Qed.

Properties of (≡⊥)

Lemma sep_disjoint_equiv_alt xs1 xs2 :
  xs1 ≡⊥ xs2 ↔ ∀ x, ⊥ (x :: xs1) ↔ ⊥ (x :: xs2).
Proof. unfold sep_disjoint_equiv, sep_disjoint_le. naive_solver. Qed.
Global Instance: Equivalence (≡⊥).
Proof.
  split.
  * done.
  * by intros ?? [??].
  * by intros x y z [??] [??]; split; transitivity y.
Qed.

Global Instance: AntiSymmetric (≡⊥) (⊆⊥).
Proof. by split. Qed.
Global Instance: Proper ((≡⊥) ==> iff) disjoint_list.
Proof. intros ?? [Hxs1 Hxs2]. split. by rewrite Hxs1. by rewrite Hxs2. Qed.
Global Instance: Proper ((≡⊥) ==> (≡⊥) ==> iff) (⊆⊥).
Proof.
  intros x y [??] z x4 [??]. split; intro.
  * transitivity x; auto. transitivity z; auto.
  * transitivity y; auto. transitivity x4; auto.
Qed.

Global Instance: Proper ((≡ₚ) ==> (≡ₚ) ==> iff) (≡⊥).
Proof.
  intros xs1 xs2 Hxs12 xs3 xs4 Hxs34. rewrite !sep_disjoint_equiv_alt.
  by setoid_rewrite Hxs12; setoid_rewrite Hxs34.
Qed.

Global Instance: Proper ((=) ==> (≡⊥) ==> (≡⊥)) (::).
Proof.
  intros ??? ?? [Hxs1 Hxs2]; subst. split. by rewrite Hxs1. by rewrite Hxs2.
Qed.

Global Instance: Proper ((≡⊥) ==> (≡⊥) ==> (≡⊥)) (++).
Proof.
  intros ?? [Hxs1 Hxs2] ?? [Hxs3 Hxs4].
  split. by rewrite Hxs1, Hxs3. by rewrite Hxs2, Hxs4.
Qed.

Lemma sep_disjoint_cons_inj x y xs : [x] ≡⊥ [y] → x :: xs ≡⊥ y :: xs.
Proof. intros. change ([x] ++ xs ≡⊥ [y] ++ xs). by f_equiv. Qed.
Lemma sep_disjoint_equiv_empty xs : ∅ :: xs ≡⊥ xs.
Proof.
  by split; intros y; rewrite (Permutation_swap _ y), sep_disjoint_empty_alt.
Qed.

Lemma sep_disjoint_le_union x y xs : x :: y :: xs ⊆⊥ xy :: xs.
Proof.
  intros y'. rewrite !(Permutation_swap _ y'),
    (sep_disjoint_alt x y), <-sep_disjoint_list_double. by intros [??].
Qed.

Lemma sep_disjoint_equiv_union x y xs : ⊥[x; y] → xy :: xs ≡⊥ x :: y :: xs.
Proof.
  split; auto using sep_disjoint_le_union. intros y'.
  rewrite !(Permutation_swap _ y'), (sep_disjoint_alt x y),
    <-sep_disjoint_list_double; tauto.
Qed.

Lemma sep_disjoint_le_union_list xs1 xs2 : xs1 ++ xs2 ⊆⊥ ⋃ xs1 :: xs2.
Proof.
  intros y. rewrite !(Permutation_swap _ y), Permutation_middle,
    sep_disjoint_list_alt; tauto.
Qed.

Lemma sep_disjoint_le_union_list_singleton xs : xs ⊆⊥ [⋃ xs].
Proof. by rewrite <-sep_disjoint_le_union_list, (right_id_L [] (++)). Qed.
Lemma sep_disjoint_equiv_union_list xs1 xs2: ⊥ xs1 → ⋃ xs1 :: xs2 ≡⊥ xs1 ++ xs2.
Proof.
  split; auto using sep_disjoint_le_union_list.
  intros y. rewrite !(Permutation_swap _ y), Permutation_middle,
    sep_disjoint_list_alt; tauto.
Qed.

Lemma sep_disjoint_equiv_union_list_singleton xs : ⊥ xs → [⋃ xs] ≡⊥ xs.
Proof.
  intros. by rewrite sep_disjoint_equiv_union_list, (right_id_L [] (++)).
Qed.

Lemma sep_disjoint_equiv_difference x y xs :
  xyy :: xs ≡⊥ x :: yx :: xs.
Proof.
  intros. by rewrite <-sep_disjoint_equiv_union, sep_union_difference
    by auto using sep_disjoint_difference.
Qed.

Lemma sep_subseteq_disjoint_le x y xs : xyy :: xs ⊆⊥ x :: xs.
Proof.
  rewrite sep_subseteq_spec; intros (z&->&?); intros y.
  rewrite sep_disjoint_equiv_union by done; intros Hyxz.
  apply (sep_disjoint_contains _ _ Hyxz); solve_contains.
Qed.

Lemma sep_difference_distr_l x y z :
  zx → ⊥ [x; y] → (xy) ∖ z = (xz) ∪ y.
Proof.
  intros. apply (sep_cancel_l _ _ z).
  { by apply sep_disjoint_difference, sep_union_subseteq_l_transitive. }
  { by rewrite <-sep_disjoint_le_union, <-sep_disjoint_equiv_difference. }
  assert ( ⊥ [z; xz; y]) by (by rewrite <-sep_disjoint_equiv_difference).
  by rewrite sep_associative, !sep_union_difference
    by auto using sep_union_subseteq_l_transitive.
Qed.

Lemma sep_difference_distr_r x y z :
  zy → ⊥ [x; y] → (xy) ∖ z = x ∪ (yz).
Proof.
  intros. assert ( ⊥ [yz; x]).
  { apply (disjoint_list_cons z).
    rewrite <-sep_disjoint_equiv_difference; eauto. }
  by rewrite !(sep_commutative x), sep_difference_distr_l by eauto.
Qed.

Lemma sep_disjoint_equiv_half x xs :
  sep_splittable x → ½ x :: ½ x :: xs ≡⊥ x :: xs.
Proof.
  intros. by rewrite <-sep_disjoint_equiv_union, sep_union_half
    by auto using sep_disjoint_half.
Qed.


Properties with respect to vectors

Lemma sep_disjoint_equiv_insert {n} (xs : vec A n) (i : fin n) x :
  vinsert i x xs ≡⊥ x :: delete (fin_to_nat i) (vec_to_list xs).
Proof.
  induction xs as [|x' ? xs IH]; inv_fin i; simpl; [done|intros i].
  by rewrite Permutation_swap, IH.
Qed.

Lemma sep_disjoint_equiv_delete {n} (xs : vec A n) (i : fin n) :
  xs !!! i :: delete (fin_to_nat i) (vec_to_list xs) ≡⊥ xs.
Proof. by rewrite <-sep_disjoint_equiv_insert, vlookup_insert_self. Qed.
Lemma sep_union_delete {n} (xs : vec A n) (i : fin n) :
  ⊥ xsxs !!! i ∪ ⋃ delete (fin_to_nat i) (vec_to_list xs) = ⋃ xs.
Proof.
  induction xs as [|x ? xs IH]; inversion_clear 1; inv_fin i; simpl; [done|].
  intros i.
  assert (⊥ [xs !!! i; ⋃ (delete (fin_to_nat i) (vec_to_list xs)); x]) as Hxs.
  { rewrite <-sep_disjoint_le_union_list, app_comm_cons,
      sep_disjoint_equiv_delete, sep_disjoint_list_alt; auto. }
  rewrite (sep_commutative x), sep_associative
    by (apply (sep_disjoint_contains _ _ Hxs); solve_contains).
  by rewrite IH, sep_commutative by auto.
Qed.

Lemma sep_union_insert {n} (xs : vec A n) (i : fin n) x :
  ⊥ (x :: delete (fin_to_nat i) (vec_to_list xs)) →
  ⋃ vinsert i x xs = x ∪ ⋃ delete (fin_to_nat i) (vec_to_list xs).
Proof.
  induction xs as [|x' ? xs IH]; inv_fin i; simpl; [done |].
  intros i; rewrite !disjoint_list_cons; simpl; intros (?&?&?).
  assert (⊥ [x; x'; ⋃ delete (fin_to_nat i) (vec_to_list xs)]) as Hxs.
  { constructor; simpl;
      rewrite ?sep_right_id by eauto using sep_disjoint_valid_l; auto. }
  by rewrite IH, !sep_associative, (sep_commutative x') by
    (rewrite <-?(sep_disjoint_equiv_union_list_singleton (delete _ _)) by done;
     by (apply (sep_disjoint_contains _ _ Hxs); solve_contains)).
Qed.

Lemma sep_subseteq_lookup {n} (xs : vec A n) (i : fin n) :
  ⊥ xsxs !!! i ⊆ ⋃ xs.
Proof.
  intros. rewrite <-(sep_union_delete _ i) by done.
  apply sep_union_subseteq_l.
  rewrite Permutation_swap, <-sep_disjoint_le_union_list, (commutative (++)).
  by simpl; rewrite sep_disjoint_equiv_delete.
Qed.


Properties lifted to lists

Lemma seps_subseteq_empty xs n :
  length xs = nForall sep_valid xsreplicate n ∅ ⊆* xs.
Proof. eauto using Forall2_replicate_l, Forall_impl, sep_subseteq_empty. Qed.
Lemma seps_left_id xs ys : xs ⊥* ysForall (∅ =) xsxs ∪* ys = ys.
Proof.
  induction 1; intros; decompose_Forall_hyps;
    f_equal; eauto using sep_left_id, sep_disjoint_valid_l.
Qed.

Lemma seps_right_id xs ys : xs ⊥* ysForall (∅ =) ysxs ∪* ys = xs.
Proof.
  induction 1; intros; decompose_Forall_hyps;
    f_equal; eauto using sep_right_id, sep_disjoint_valid_l.
Qed.

Lemma seps_disjoint_valid_l xs ys : xs ⊥* ysForall sep_valid xs.
Proof. induction 1; simpl; constructor; eauto using sep_disjoint_valid_l. Qed.
Lemma seps_union_valid xs ys : xs ⊥* ysForall sep_valid (xs ∪* ys).
Proof. induction 1; simpl; constructor; auto using sep_union_valid. Qed.
Lemma seps_positive_l xs ys :
  xs ⊥* ysForall (∅ =) (xs ∪* ys) → Forall (∅ =) xs.
Proof.
  induction 1; intros; decompose_Forall_hyps;
    eauto using sep_positive_l', eq_sym.
Qed.

Lemma seps_positive_r xs ys :
  xs ⊥* ysForall (∅ =) (xs ∪* ys) → Forall (∅ =) ys.
Proof.
  induction 1; intros; decompose_Forall_hyps;
    eauto using sep_positive_r', eq_sym.
Qed.

Lemma seps_union_empty xs ys :
  Forall (∅ =) xsForall (∅ =) ysForall (∅ =) (xs ∪* ys).
Proof.
  intros Hxs. revert ys. induction Hxs; intros ? [|????];
    simplify_equality'; auto using sep_left_id, sep_empty_valid, eq_sym.
Qed.

Lemma seps_unmapped_union_l xs ys :
  xs ⊥* ysForall sep_unmapped (xs ∪* ys) → Forall sep_unmapped xs.
Proof.
  induction 1; intros; decompose_Forall_hyps;
    eauto using sep_unmapped_union_l'.
Qed.

Lemma seps_unmapped_union_r xs ys :
  xs ⊥* ysForall sep_unmapped (xs ∪* ys) → Forall sep_unmapped ys.
Proof.
  induction 1; intros; decompose_Forall_hyps;
    eauto using sep_unmapped_union_r'.
Qed.

Lemma seps_unmapped_union xs ys :
  xs ⊥* ysForall sep_unmapped xsForall sep_unmapped ys
  Forall sep_unmapped (xs ∪* ys).
Proof.
  induction 1; intros; decompose_Forall_hyps;
    eauto using sep_unmapped_union_2'.
Qed.

Lemma seps_commutative xs ys : xs ⊥* ysxs ∪* ys = ys ∪* xs.
Proof. induction 1; f_equal'; eauto using sep_commutative'. Qed.
Lemma seps_disjoint_ll xs ys zs : xs ⊥* ysxs ∪* ys ⊥* zsxs ⊥* zs.
Proof.
  intros Hxs. revert zs. induction Hxs; intros;
    decompose_Forall_hyps; constructor; eauto using sep_disjoint_ll.
Qed.

Lemma seps_disjoint_lr xs ys zs: xs ⊥* ysxs ∪* ys ⊥* zsys ⊥* zs.
Proof.
  intros Hxs. revert zs. induction Hxs; intros;
    decompose_Forall_hyps; constructor; eauto using sep_disjoint_lr.
Qed.

Lemma seps_disjoint_rl xs ys zs : ys ⊥* zsxs ⊥* ys ∪* zsxs ⊥* ys.
Proof.
  intros Hys. revert xs. induction Hys; intros;
    decompose_Forall_hyps; constructor; eauto using sep_disjoint_rl.
Qed.

Lemma seps_disjoint_rr xs ys zs : ys ⊥* zsxs ⊥* ys ∪* zsxs ⊥* zs.
Proof.
  intros Hys. revert xs. induction Hys; intros;
    decompose_Forall_hyps; constructor; eauto using sep_disjoint_rr.
Qed.

Lemma seps_disjoint_move_l xs ys zs :
  xs ⊥* ysxs ∪* ys ⊥* zsxs ⊥* ys ∪* zs.
Proof.
  intros Hxs. revert zs. induction Hxs; intros;
    decompose_Forall_hyps; constructor; auto using sep_disjoint_move_l.
Qed.

Lemma seps_disjoint_move_r xs ys zs :
  ys ⊥* zsxs ⊥* ys ∪* zsxs ∪* ys ⊥* zs.
Proof.
  intros Hys. revert xs. induction Hys; intros;
    decompose_Forall_hyps; constructor; auto using sep_disjoint_move_r.
Qed.

Lemma seps_associative xs ys zs :
  ys ⊥* zsxs ⊥* ys ∪* zsxs ∪* (ys ∪* zs) = xs ∪* ys ∪* zs.
Proof.
  intros Hxs. revert xs. induction Hxs; intros;
    decompose_Forall_hyps; f_equal; auto using sep_associative'.
Qed.

Lemma seps_associative_rev xs ys zs :
  xs ⊥* ysxs ∪* ys ⊥* zsxs ∪* ys ∪* zs = xs ∪* (ys ∪* zs).
Proof.
  eauto using eq_sym, seps_associative,seps_disjoint_move_l, seps_disjoint_lr.
Qed.

Lemma seps_permute xs ys zs :
  xs ⊥* ysxs ∪* ys ⊥* zsxs ∪* ys ∪* zs = xs ∪* zs ∪* ys.
Proof.
  intros Hxs. revert zs. induction Hxs; intros;
    decompose_Forall_hyps; f_equal; auto using sep_permute.
Qed.

Lemma seps_cancel_l xs ys zs :
  zs ⊥* xszs ⊥* yszs ∪* xs = zs ∪* ysxs = ys.
Proof.
  intros Hzs. revert ys. induction Hzs; intros; decompose_Forall_hyps;
    f_equal; eauto using sep_cancel_l'.
Qed.

Lemma seps_cancel_r xs ys zs :
  xs ⊥* zsys ⊥* zsxs ∪* zs = ys ∪* zsxs = ys.
Proof.
  intros Hzs. revert ys. induction Hzs; intros; decompose_Forall_hyps;
    f_equal; eauto using sep_cancel_r'.
Qed.

Lemma seps_cancel_empty_l xs ys : xs ⊥* ysxs ∪* ys = ysForall (∅ =) xs.
Proof. induction 1; naive_solver eauto using sep_cancel_empty_l, eq_sym. Qed.
Lemma seps_cancel_empty_r xs ys : xs ⊥* ysxs ∪* ys = xsForall (∅ =) ys.
Proof. induction 1; naive_solver eauto using sep_cancel_empty_r, eq_sym. Qed.
Lemma seps_reflexive xs : Forall sep_valid xsxs ⊆* xs.
Proof. induction 1; simpl; auto using sep_reflexive. Qed.
Lemma seps_union_subseteq_l xs ys : xs ⊥* ysxs ⊆* xs ∪* ys.
Proof. induction 1; simpl; auto using sep_union_subseteq_l'. Qed.
Lemma seps_union_subseteq_r xs ys : xs ⊥* ysys ⊆* xs ∪* ys.
Proof. induction 1; simpl; auto using sep_union_subseteq_r'. Qed.
Lemma seps_disjoint_difference xs1 xs2 : xs1 ⊆* xs2xs1 ⊥* xs2 ∖* xs1.
Proof. induction 1; constructor; auto using sep_disjoint_difference'. Qed.
Lemma seps_difference_valid xs ys : xs ⊆* ysForall sep_valid (ys ∖* xs).
Proof. induction 1; simpl; auto using sep_difference_valid. Qed.
Lemma seps_union_difference xs ys : xs ⊆* ysxs ∪* ys ∖* xs = ys.
Proof. induction 1; f_equal'; auto using sep_union_difference. Qed.
Lemma seps_difference_empty_rev xs ys :
  xs ⊆* ysForall (∅ =) (ys ∖* xs) → xs = ys.
Proof.
  induction 1; intros; decompose_Forall_hyps;
    f_equal; auto using sep_difference_empty_rev.
Qed.

Lemma seps_unmapped_difference_1 xs ys :
  xs ⊆* ysForall sep_unmapped xs
  Forall sep_unmapped (ys ∖* xs) → Forall sep_unmapped ys.
Proof.
  induction 1; intros; decompose_Forall_hyps;
    eauto using sep_unmapped_difference_1.
Qed.

Lemma seps_unmapped_difference_2 xs ys :
  xs ⊆* ysForall sep_unmapped ysForall sep_unmapped (ys ∖* xs).
Proof.
  induction 1; intros; decompose_Forall_hyps;
    eauto using sep_unmapped_difference_2.
Qed.

Lemma seps_splittable_union xs : xs ⊥* xsForall sep_splittable (xs ∪* xs).
Proof.
  induction xs; intros; decompose_Forall_hyps;
    constructor; eauto using sep_splittable_union'.
Qed.

Lemma seps_splittable_weaken xs ys :
  Forall sep_splittable ysxs ⊆* ysForall sep_splittable xs.
Proof.
  induction 2; decompose_Forall_hyps; eauto using sep_splittable_weaken.
Qed.

Lemma seps_disjoint_half xs : Forall sep_splittable xs → ½* xs ⊥* ½* xs.
Proof. induction 1; csimpl; auto using sep_disjoint_half'. Qed.
Lemma seps_union_half xs : Forall sep_splittable xs → ½* xs ∪* ½* xs = xs.
Proof. induction 1; f_equal'; auto using sep_union_half. Qed.
Lemma seps_unmapped_half_1 xs :
  Forall sep_splittable xs
  Forall sep_unmapped (½* xs) → Forall sep_unmapped xs.
Proof. induction 1; inversion_clear 1; auto using sep_unmapped_half_1. Qed.
Lemma seps_half_empty_rev xs :
  Forall sep_splittable xsForall (∅ =) (½* xs) → Forall (∅ =) xs.
Proof.
  induction 1; inversion_clear 1; auto using sep_half_empty_rev, eq_sym.
Qed.

Lemma seps_union_half_distr xs ys :
  xs ⊥* ysForall sep_splittable (xs ∪* ys) → ½* (xs ∪* ys) = ½* xs ∪* ½* ys.
Proof.
  induction 1; intros; decompose_Forall_hyps;
    f_equal; auto using sep_union_half_distr'.
Qed.

Lemma seps_unmapped_valid xs : Forall sep_unmapped xsForall sep_valid xs.
Proof. induction 1; simpl; auto using sep_unmapped_valid. Qed.
Lemma seps_unshared_valid xs : Forall sep_unshared xsForall sep_valid xs.
Proof. induction 1; simpl; auto using sep_unshared_valid. Qed.
Lemma seps_disjoint_unshared_unmapped xs ys :
  xs ⊥* ysForall sep_unshared xsForall sep_unmapped ys.
Proof.
  induction 1; inversion_clear 1; eauto using sep_disjoint_unshared_unmapped.
Qed.

Lemma seps_unshared_weaken xs ys :
  Forall sep_unshared xsxs ⊆* ysForall sep_unshared ys.
Proof.
  induction 2; decompose_Forall_hyps; eauto using sep_unshared_weaken.
Qed.

Lemma seps_unshared_unmapped xs :
  Forall sep_unshared xsForall (notsep_unmapped) xs.
Proof. induction 1; eauto using sep_unshared_unmapped. Qed.
End separation.

Tactic

The tactic solve_sep_disjoint solves goals of the shape xs. It first eliminates all occurences of , , and from the hypotheses using the tactic simplify_sep_disjoint_hyps. Then it performs the same job on the conclusion and finally tries to prove that one of assumptions implies the conclusion.
Ltac solve_simple_sep_disjoint :=
  repeat first
  [ rewrite sep_disjoint_equiv_empty
  | rewrite <-sep_disjoint_le_union_list
  | rewrite <-sep_disjoint_le_union ];
  match goal with
  | _ => done
  | |- ⊥ [] => by apply disjoint_list_nil
  | H : ⊥ ?xs2 |- ⊥ ?xs1 => apply (sep_disjoint_contains _ _ H); solve_contains
  end.
Ltac simplify_sep_disjoint_hyps := repeat
  match goal with
  | H : sep_valid _ |- _ => apply sep_disjoint_list_singleton in H
  | H : ⊥ [] |- _ => clear H
  | H : ?x ⊥ ?y |- _ => apply sep_disjoint_list_double in H
  | H : ⊥ ?xs |- _ =>
    progress repeat first
    [ rewrite sep_disjoint_equiv_empty in H
    | rewrite sep_disjoint_equiv_union_list in H by solve_simple_sep_disjoint
    | rewrite sep_disjoint_equiv_union in H by solve_simple_sep_disjoint ]
  end.
Ltac solve_sep_disjoint :=
  match goal with
  | |- ⊥ [] => by apply disjoint_list_nil
  | |- ⊥ [_] => by apply sep_disjoint_list_singleton
  | |- ⊥ _ => try done
  | |- sep_valid _ => done || apply sep_disjoint_list_singleton
  | |- __ => done || apply sep_disjoint_list_double
  end;
  simplify_sep_disjoint_hyps; solve_simple_sep_disjoint.