### Support sequence point, add permissions, and update prelude.

Both the operational and axiomatic semantics are extended with sequence points and a permission system based on fractional permissions. In order to achieve this, the memory model has been completely revised, and is now built on top of an abstract interface for permissions. Apart from these changed, the library on lists and sets has been heavily extended, and minor changed have been made to other parts of the prelude.

(* Copyright (c) 2012, Robbert Krebbers. *) | ||

(* Copyright (c) 2012-2013, Robbert Krebbers. *) | ||

(* This file is distributed under the terms of the BSD license. *) | ||

(** This file collects definitions and theorems on collections. Most | ||

importantly, it implements some tactics to automatically solve goals involving | ||

collections. *) | ||

Require Export base tactics orders. | ||

(** * Theorems *) | ||

(** * Basic theorems *) | ||

Section simple_collection. | ||

Context `{SimpleCollection A C}. | ||

... | ... | @@ -28,6 +28,9 @@ Section simple_collection. |

Lemma elem_of_equiv_alt X Y : | ||

X ≡ Y ↔ (∀ x, x ∈ X → x ∈ Y) ∧ (∀ x, x ∈ Y → x ∈ X). | ||

Proof. firstorder. Qed. | ||

Lemma elem_of_equiv_empty X : X ≡ ∅ ↔ ∀ x, x ∉ X. | ||

Proof. firstorder. Qed. | ||

Lemma elem_of_subseteq_singleton x X : x ∈ X ↔ {[ x ]} ⊆ X. | ||

Proof. | ||

split. | ||

... | ... | @@ -60,33 +63,92 @@ Section simple_collection. |

Lemma not_elem_of_union x X Y : x ∉ X ∪ Y ↔ x ∉ X ∧ x ∉ Y. | ||

Proof. rewrite elem_of_union. tauto. Qed. | ||

Context `{∀ X Y : C, Decision (X ⊆ Y)}. | ||

Global Instance elem_of_dec_slow (x : A) (X : C) : Decision (x ∈ X) | 100. | ||

Proof. | ||

refine (cast_if (decide_rel (⊆) {[ x ]} X)); | ||

by rewrite elem_of_subseteq_singleton. | ||

Defined. | ||

Section leibniz. | ||

Context `{!LeibnizEquiv C}. | ||

Lemma elem_of_equiv_L X Y : X = Y ↔ ∀ x, x ∈ X ↔ x ∈ Y. | ||

Proof. unfold_leibniz. apply elem_of_equiv. Qed. | ||

Lemma elem_of_equiv_alt_L X Y : | ||

X = Y ↔ (∀ x, x ∈ X → x ∈ Y) ∧ (∀ x, x ∈ Y → x ∈ X). | ||

Proof. unfold_leibniz. apply elem_of_equiv_alt. Qed. | ||

Lemma elem_of_equiv_empty_L X : X = ∅ ↔ ∀ x, x ∉ X. | ||

Proof. unfold_leibniz. apply elem_of_equiv_empty. Qed. | ||

Lemma non_empty_singleton_L x : {[ x ]} ≠ ∅. | ||

Proof. unfold_leibniz. apply non_empty_singleton. Qed. | ||

End leibniz. | ||

Section dec. | ||

Context `{∀ X Y : C, Decision (X ⊆ Y)}. | ||

Global Instance elem_of_dec_slow (x : A) (X : C) : Decision (x ∈ X) | 100. | ||

Proof. | ||

refine (cast_if (decide_rel (⊆) {[ x ]} X)); | ||

by rewrite elem_of_subseteq_singleton. | ||

Defined. | ||

End dec. | ||

End simple_collection. | ||

(** * Tactics *) | ||

(** Given a hypothesis [H : _ ∈ _], the tactic [destruct_elem_of H] will | ||

recursively split [H] for [(∪)], [(∩)], [(∖)], [map], [∅], [{[_]}]. *) | ||

Tactic Notation "decompose_elem_of" hyp(H) := | ||

let rec go H := | ||

lazymatch type of H with | ||

| _ ∈ ∅ => apply elem_of_empty in H; destruct H | ||

| ?x ∈ {[ ?y ]} => | ||

apply elem_of_singleton in H; try first [subst y | subst x] | ||

| _ ∈ _ ∪ _ => | ||

let H1 := fresh in let H2 := fresh in apply elem_of_union in H; | ||

destruct H as [H1|H2]; [go H1 | go H2] | ||

| _ ∈ _ ∩ _ => | ||

let H1 := fresh in let H2 := fresh in apply elem_of_intersection in H; | ||

destruct H as [H1 H2]; go H1; go H2 | ||

| _ ∈ _ ∖ _ => | ||

let H1 := fresh in let H2 := fresh in apply elem_of_difference in H; | ||

destruct H as [H1 H2]; go H1; go H2 | ||

| ?x ∈ _ <$> _ => | ||

let H1 := fresh in apply elem_of_fmap in H; | ||

destruct H as [? [? H1]]; try (subst x); go H1 | ||

| _ ∈ _ ≫= _ => | ||

let H1 := fresh in let H2 := fresh in apply elem_of_bind in H; | ||

destruct H as [? [H1 H2]]; go H1; go H2 | ||

| ?x ∈ mret ?y => | ||

apply elem_of_ret in H; try first [subst y | subst x] | ||

| _ ∈ mjoin _ ≫= _ => | ||

let H1 := fresh in let H2 := fresh in apply elem_of_join in H; | ||

destruct H as [? [H1 H2]]; go H1; go H2 | ||

| _ => idtac | ||

end in go H. | ||

Tactic Notation "decompose_elem_of" := | ||

repeat_on_hyps (fun H => decompose_elem_of H). | ||

Ltac decompose_empty := repeat | ||

match goal with | ||

| H : ∅ ≡ ∅ |- _ => clear H | ||

| H : ∅ = ∅ |- _ => clear H | ||

| H : ∅ ≡ _ |- _ => symmetry in H | ||

| H : ∅ = _ |- _ => symmetry in H | ||

| H : _ ∪ _ ≡ ∅ |- _ => apply empty_union in H; destruct H | ||

| H : _ ∪ _ ≢ ∅ |- _ => apply non_empty_union in H; destruct H | ||

| H : {[ _ ]} ≡ ∅ |- _ => destruct (non_empty_singleton _ H) | ||

| H : _ ∪ _ = ∅ |- _ => apply empty_union_L in H; destruct H | ||

| H : _ ∪ _ ≠ ∅ |- _ => apply non_empty_union_L in H; destruct H | ||

| H : {[ _ ]} = ∅ |- _ => destruct (non_empty_singleton_L _ H) | ||

end. | ||

(** * Tactics *) | ||

(** The first pass consists of eliminating all occurrences of [(∪)], [(∩)], | ||

[(∖)], [map], [∅], [{[_]}], [(≡)], and [(⊆)], by rewriting these into | ||

logically equivalent propositions. For example we rewrite [A → x ∈ X ∪ ∅] into | ||

[A → x ∈ X ∨ False]. *) | ||

(** The first pass of our collection tactic consists of eliminating all | ||

occurrences of [(∪)], [(∩)], [(∖)], [(<$>)], [∅], [{[_]}], [(≡)], and [(⊆)], | ||

by rewriting these into logically equivalent propositions. For example we | ||

rewrite [A → x ∈ X ∪ ∅] into [A → x ∈ X ∨ False]. *) | ||

Ltac unfold_elem_of := | ||

repeat_on_hyps (fun H => | ||

repeat match type of H with | ||

| context [ _ ⊆ _ ] => setoid_rewrite elem_of_subseteq in H | ||

| context [ _ ⊂ _ ] => setoid_rewrite subset_spec in H | ||

| context [ _ ≡ ∅ ] => setoid_rewrite elem_of_equiv_empty in H | ||

| context [ _ ≡ _ ] => setoid_rewrite elem_of_equiv_alt in H | ||

| context [ _ = ∅ ] => setoid_rewrite elem_of_equiv_empty_L in H | ||

| context [ _ = _ ] => setoid_rewrite elem_of_equiv_alt_L in H | ||

| context [ _ ∈ ∅ ] => setoid_rewrite elem_of_empty in H | ||

| context [ _ ∈ {[ _ ]} ] => setoid_rewrite elem_of_singleton in H | ||

| context [ _ ∈ _ ∪ _ ] => setoid_rewrite elem_of_union in H | ||

... | ... | @@ -100,7 +162,10 @@ Ltac unfold_elem_of := |

repeat match goal with | ||

| |- context [ _ ⊆ _ ] => setoid_rewrite elem_of_subseteq | ||

| |- context [ _ ⊂ _ ] => setoid_rewrite subset_spec | ||

| |- context [ _ ≡ ∅ ] => setoid_rewrite elem_of_equiv_empty | ||

| |- context [ _ ≡ _ ] => setoid_rewrite elem_of_equiv_alt | ||

| |- context [ _ = ∅ ] => setoid_rewrite elem_of_equiv_empty_L | ||

| |- context [ _ = _ ] => setoid_rewrite elem_of_equiv_alt_L | ||

| |- context [ _ ∈ ∅ ] => setoid_rewrite elem_of_empty | ||

| |- context [ _ ∈ {[ _ ]} ] => setoid_rewrite elem_of_singleton | ||

| |- context [ _ ∈ _ ∪ _ ] => setoid_rewrite elem_of_union | ||

... | ... | @@ -117,6 +182,7 @@ For goals that do not involve [≡], [⊆], [map], or quantifiers this tactic is |

generally powerful enough. This tactic either fails or proves the goal. *) | ||

Tactic Notation "solve_elem_of" tactic3(tac) := | ||

simpl in *; | ||

decompose_empty; | ||

unfold_elem_of; | ||

solve [intuition (simplify_equality; tac)]. | ||

Tactic Notation "solve_elem_of" := solve_elem_of auto. | ||

... | ... | @@ -128,48 +194,22 @@ use the [naive_solver] tactic as a substitute. This tactic either fails or |

proves the goal. *) | ||

Tactic Notation "esolve_elem_of" tactic3(tac) := | ||

simpl in *; | ||

decompose_empty; | ||

unfold_elem_of; | ||

naive_solver tac. | ||

Tactic Notation "esolve_elem_of" := esolve_elem_of eauto. | ||

(** Given a hypothesis [H : _ ∈ _], the tactic [destruct_elem_of H] will | ||

recursively split [H] for [(∪)], [(∩)], [(∖)], [map], [∅], [{[_]}]. *) | ||

Tactic Notation "decompose_elem_of" hyp(H) := | ||

let rec go H := | ||

lazymatch type of H with | ||

| _ ∈ ∅ => apply elem_of_empty in H; destruct H | ||

| ?x ∈ {[ ?y ]} => | ||

apply elem_of_singleton in H; try first [subst y | subst x] | ||

| _ ∈ _ ∪ _ => | ||

let H1 := fresh in let H2 := fresh in apply elem_of_union in H; | ||

destruct H as [H1|H2]; [go H1 | go H2] | ||

| _ ∈ _ ∩ _ => | ||

let H1 := fresh in let H2 := fresh in apply elem_of_intersection in H; | ||

destruct H as [H1 H2]; go H1; go H2 | ||

| _ ∈ _ ∖ _ => | ||

let H1 := fresh in let H2 := fresh in apply elem_of_difference in H; | ||

destruct H as [H1 H2]; go H1; go H2 | ||

| ?x ∈ _ <$> _ => | ||

let H1 := fresh in apply elem_of_fmap in H; | ||

destruct H as [? [? H1]]; try (subst x); go H1 | ||

| _ ∈ _ ≫= _ => | ||

let H1 := fresh in let H2 := fresh in apply elem_of_bind in H; | ||

destruct H as [? [H1 H2]]; go H1; go H2 | ||

| ?x ∈ mret ?y => | ||

apply elem_of_ret in H; try first [subst y | subst x] | ||

| _ ∈ mjoin _ ≫= _ => | ||

let H1 := fresh in let H2 := fresh in apply elem_of_join in H; | ||

destruct H as [? [H1 H2]]; go H1; go H2 | ||

| _ => idtac | ||

end in go H. | ||

Tactic Notation "decompose_elem_of" := | ||

repeat_on_hyps (fun H => decompose_elem_of H). | ||

(** * More theorems *) | ||

Section collection. | ||

Context `{Collection A C}. | ||

Global Instance: LowerBoundedLattice C. | ||

Proof. split. apply _. firstorder auto. Qed. | ||

Proof. | ||

split. | ||

* apply _. | ||

* firstorder auto. | ||

* solve_elem_of. | ||

</ |