diff --git a/theories/ars.v b/theories/ars.v
new file mode 100644
index 0000000000000000000000000000000000000000..9a4fb2241c948fe322d0c2a3aff8a6c4141eded3
--- /dev/null
+++ b/theories/ars.v
@@ -0,0 +1,159 @@
+(* Copyright (c) 2012, Robbert Krebbers. *)
+(* This file is distributed under the terms of the BSD license. *)
+(** This file collects definitions and theorems on abstract rewriting systems.
+These are particularly useful as we define the operational semantics as a
+small step semantics. This file defines a hint database [ars] containing
+some theorems on abstract rewriting systems. *)
+Require Export tactics base.
+
+(** * Definitions *)
+Section definitions.
+  Context `(R : relation A).
+
+  (** An element is reducible if a step is possible. *)
+  Definition red (x : A) := ∃ y, R x y.
+
+  (** An element is in normal form if no further steps are possible. *)
+  Definition nf (x : A) := ¬red x.
+
+  (** The reflexive transitive closure. *)
+  Inductive rtc : relation A :=
+    | rtc_refl x : rtc x x
+    | rtc_l x y z : R x y → rtc y z → rtc x z.
+
+  (** Reductions of exactly [n] steps. *)
+  Inductive nsteps : nat → relation A :=
+    | nsteps_O x : nsteps 0 x x
+    | nsteps_l n x y z : R x y → nsteps n y z → nsteps (S n) x z.
+
+  (** Reduction of at most [n] steps. *)
+  Inductive bsteps : nat → relation A :=
+    | bsteps_refl n x : bsteps n x x
+    | bsteps_l n x y z : R x y → bsteps n y z → bsteps (S n) x z.
+
+  (** The transitive closure. *)
+  Inductive tc : relation A :=
+    | tc_once x y : R x y → tc x y
+    | tc_l x y z : R x y → tc y z → tc x z.
+
+  (** An element [x] is looping if all paths starting at [x] are infinite. *)
+  CoInductive looping : A → Prop :=
+    | looping_do_step x : red x → (∀ y, R x y → looping y) → looping x.
+End definitions.
+
+Hint Constructors rtc nsteps bsteps tc : ars.
+
+(** * General theorems *)
+Section rtc.
+  Context `{R : relation A}.
+
+  Global Instance: Reflexive (rtc R).
+  Proof rtc_refl R.
+  Global Instance rtc_trans: Transitive (rtc R).
+  Proof. red; induction 1; eauto with ars. Qed.
+  Lemma rtc_once x y : R x y → rtc R x y.
+  Proof. eauto with ars. Qed.
+  Global Instance: subrelation R (rtc R).
+  Proof. exact @rtc_once. Qed.
+  Lemma rtc_r x y z : rtc R x y → R y z → rtc R x z.
+  Proof. intros. etransitivity; eauto with ars. Qed.
+
+  Lemma rtc_inv x z : rtc R x z → x = z ∨ ∃ y, R x y ∧ rtc R y z.
+  Proof. inversion_clear 1; eauto. Qed.
+
+  Lemma rtc_ind_r (P : A → A → Prop)
+    (Prefl : ∀ x, P x x) (Pstep : ∀ x y z, rtc R x y → R y z → P x y → P x z) :
+    ∀ y z, rtc R y z → P y z.
+  Proof.
+    cut (∀ y z, rtc R y z → ∀ x, rtc R x y → P x y → P x z).
+    { eauto using rtc_refl. }
+    induction 1; eauto using rtc_r.
+  Qed.
+
+  Lemma rtc_inv_r x z : rtc R x z → x = z ∨ ∃ y, rtc R x y ∧ R y z.
+  Proof. revert x z. apply rtc_ind_r; eauto. Qed.
+
+  Lemma nsteps_once x y : R x y → nsteps R 1 x y.
+  Proof. eauto with ars. Qed.
+  Lemma nsteps_trans n m x y z :
+    nsteps R n x y → nsteps R m y z → nsteps R (n + m) x z.
+  Proof. induction 1; simpl; eauto with ars. Qed.
+  Lemma nsteps_r n x y z : nsteps R n x y → R y z → nsteps R (S n) x z.
+  Proof. induction 1; eauto with ars. Qed.
+  Lemma nsteps_rtc n x y : nsteps R n x y → rtc R x y.
+  Proof. induction 1; eauto with ars. Qed.
+  Lemma rtc_nsteps x y : rtc R x y → ∃ n, nsteps R n x y.
+  Proof. induction 1; firstorder eauto with ars. Qed.
+
+  Lemma bsteps_once n x y : R x y → bsteps R (S n) x y.
+  Proof. eauto with ars. Qed.
+  Lemma bsteps_plus_r n m x y :
+    bsteps R n x y → bsteps R (n + m) x y.
+  Proof. induction 1; simpl; eauto with ars. Qed.
+  Lemma bsteps_weaken n m x y :
+    n ≤ m → bsteps R n x y → bsteps R m x y.
+  Proof.
+    intros. rewrite (Minus.le_plus_minus n m); auto using bsteps_plus_r.
+  Qed.
+  Lemma bsteps_plus_l n m x y :
+    bsteps R n x y → bsteps R (m + n) x y.
+  Proof. apply bsteps_weaken. auto with arith. Qed.
+  Lemma bsteps_S n x y :  bsteps R n x y → bsteps R (S n) x y.
+  Proof. apply bsteps_weaken. auto with arith. Qed.
+  Lemma bsteps_trans n m x y z :
+    bsteps R n x y → bsteps R m y z → bsteps R (n + m) x z.
+  Proof. induction 1; simpl; eauto using bsteps_plus_l with ars. Qed.
+  Lemma bsteps_r n x y z : bsteps R n x y → R y z → bsteps R (S n) x z.
+  Proof. induction 1; eauto with ars. Qed.
+  Lemma bsteps_rtc n x y : bsteps R n x y → rtc R x y.
+  Proof. induction 1; eauto with ars. Qed.
+  Lemma rtc_bsteps x y : rtc R x y → ∃ n, bsteps R n x y.
+  Proof. induction 1. exists 0. auto with ars. firstorder eauto with ars. Qed.
+
+  Global Instance tc_trans: Transitive (tc R).
+  Proof. red; induction 1; eauto with ars. Qed.
+  Lemma tc_r x y z : tc R x y → R y z → tc R x z.
+  Proof. intros. etransitivity; eauto with ars. Qed.
+  Lemma tc_rtc x y : tc R x y → rtc R x y.
+  Proof. induction 1; eauto with ars. Qed.
+  Global Instance: subrelation (tc R) (rtc R).
+  Proof. exact @tc_rtc. Qed.
+
+  Lemma looping_red x : looping R x → red R x.
+  Proof. destruct 1; auto. Qed.
+  Lemma looping_step x y : looping R x → R x y → looping R y.
+  Proof. destruct 1; auto. Qed.
+  Lemma looping_rtc x y : looping R x → rtc R x y → looping R y.
+  Proof. induction 2; eauto using looping_step. Qed.
+
+  Lemma looping_alt x :
+    looping R x ↔ ∀ y, rtc R x y → red R y.
+  Proof.
+    split.
+    * eauto using looping_red, looping_rtc.
+    * intros H. cut (∀ z, rtc R x z → looping R z).
+      { eauto with ars. }
+      cofix FIX. constructor; eauto using rtc_r with ars.
+  Qed.
+End rtc.
+
+Hint Resolve rtc_once rtc_r tc_r : ars.
+
+(** * Theorems on sub relations *)
+Section subrel.
+  Context {A} (R1 R2 : relation A) (Hsub : subrelation R1 R2).
+
+  Lemma red_subrel x : red R1 x → red R2 x.
+  Proof. intros [y ?]. exists y. now apply Hsub. Qed.
+  Lemma nf_subrel x : nf R2 x → nf R1 x.
+  Proof. intros H1 H2. destruct H1. now apply red_subrel. Qed.
+
+  Global Instance rtc_subrel: subrelation (rtc R1) (rtc R2).
+  Proof. induction 1; [left|eright]; eauto; now apply Hsub. Qed.
+  Global Instance nsteps_subrel: subrelation (nsteps R1 n) (nsteps R2 n).
+  Proof. induction 1; [left|eright]; eauto; now apply Hsub. Qed.
+  Global Instance bsteps_subrel: subrelation (bsteps R1 n) (bsteps R2 n).
+  Proof. induction 1; [left|eright]; eauto; now apply Hsub. Qed.
+  Global Instance tc_subrel: subrelation (tc R1) (tc R2).
+  Proof. induction 1; [left|eright]; eauto; now apply Hsub. Qed.
+End subrel.
diff --git a/theories/base.v b/theories/base.v
index b021a29870abbba8ad8b133a06261c983b46b99c..06a1a94d166f90f9e7a8ae739ad03eb63dd75666 100644
--- a/theories/base.v
+++ b/theories/base.v
@@ -1,20 +1,34 @@
+(* Copyright (c) 2012, Robbert Krebbers. *)
+(* This file is distributed under the terms of the BSD license. *)
+(** This file collects type class interfaces, notations, and general theorems
+that are used throughout the whole development. Most importantly it contains
+abstract interfaces for ordered structures, collections, and various other data
+structures. *)
 Global Generalizable All Variables.
 Global Set Automatic Coercions Import.
 Require Export Morphisms RelationClasses List Bool Utf8 Program Setoid NArith.
 
+(** * General *)
+(** The following coercion allows us to use Booleans as propositions. *)
+Coercion Is_true : bool >-> Sortclass.
+
+(** Ensure that [simpl] unfolds [id] and [compose] when fully applied. *)
 Arguments id _ _/.
 Arguments compose _ _ _ _ _ _ /.
 
-(* Change True and False into notations so we can overload them *)
+(** Change [True] and [False] into notations in order to enable overloading.
+We will use this in the file [assertions] to give [True] and [False] a
+different interpretation in [assert_scope] used for assertions of our axiomatic
+semantics. *)
 Notation "'True'" := True : type_scope.
 Notation "'False'" := False : type_scope.
 
-Arguments existT {_ _} _ _.
-
-(*  Common notations *)
+(** Throughout this development we use [C_scope] for all general purpose
+notations that do not belong to a more specific scope. *)
 Delimit Scope C_scope with C.
 Global Open Scope C_scope.
 
+(** Introduce some Haskell style like notations. *)
 Notation "(=)" := eq (only parsing) : C_scope.
 Notation "( x =)" := (eq x) (only parsing) : C_scope.
 Notation "(= x )" := (λ y, eq y x) (only parsing) : C_scope.
@@ -33,17 +47,39 @@ Infix "∘" := compose : C_scope.
 Notation "(∘)" := compose (only parsing) : C_scope.
 Notation "( f ∘)" := (compose f) (only parsing) : C_scope.
 Notation "(∘ f )" := (λ g, compose g f) (only parsing) : C_scope.
+
+(** Set convenient implicit arguments for [existT] and introduce notations. *)
+Arguments existT {_ _} _ _.
 Notation "x ↾ p" := (exist _ x p) (at level 20) : C_scope.
 Notation "` x" := (proj1_sig x) : C_scope.
 
-(* Provable propositions *)
+(** * Type classes *)
+(** ** Provable propositions *)
+(** This type class collects provable propositions. It is useful to constraint
+type classes by arbitrary propositions. *)
 Class PropHolds (P : Prop) := prop_holds: P.
 
-(* Decidable propositions *)
+Hint Extern 0 (PropHolds _) => assumption : typeclass_instances.
+Instance: Proper (iff ==> iff) PropHolds.
+Proof. now repeat intro. Qed.
+
+Ltac solve_propholds :=
+  match goal with
+  | [ |- PropHolds (?P) ] => apply _
+  | [ |- ?P ] => change (PropHolds P); apply _
+  end.
+
+(** ** Decidable propositions *)
+(** This type class by (Spitters/van der Weegen, 2011) collects decidable
+propositions. For example to declare a parameter expressing decidable equality
+on a type [A] we write [`{∀ x y : A, Decision (x = y)}] and use it by writing
+[decide (x = y)]. *)
 Class Decision (P : Prop) := decide : {P} + {¬P}.
 Arguments decide _ {_}.
 
-(* Common relations & operations *)
+(** ** Setoid equality *)
+(** We define an operational type class for setoid equality. This is based on
+(Spitters/van der Weegen, 2011). *)
 Class Equiv A := equiv: relation A.
 Infix "≡" := equiv (at level 70, no associativity) : C_scope.
 Notation "(≡)" := equiv (only parsing) : C_scope.
@@ -54,31 +90,54 @@ Notation "x ≢ y":= (¬x ≡ y) (at level 70, no associativity) : C_scope.
 Notation "( x ≢)" := (λ y, x ≢ y) (only parsing) : C_scope.
 Notation "(≢ x )" := (λ y, y ≢ x) (only parsing) : C_scope.
 
+(** A [Params f n] instance forces the setoid rewriting mechanism not to
+rewrite in the first [n] arguments of the function [f]. We will declare such
+instances for all operational type classes in this development. *)
+Instance: Params (@equiv) 2.
+
+(** The following instance forces [setoid_replace] to use setoid equality
+(for types that have an [Equiv] instance) rather than the standard Leibniz
+equality. *)
 Instance equiv_default_relation `{Equiv A} : DefaultRelation (≡) | 3.
 Hint Extern 0 (?x ≡ ?x) => reflexivity.
 
+(** ** Operations on collections *)
+(** We define operational type classes for the standard operations and
+relations on collections: the empty collection [∅], the union [(∪)],
+intersection [(∩)], difference [(∖)], and the singleton [{[_]}]
+operation, and the subset [(⊆)] and element of [(∈)] relation. *)
 Class Empty A := empty: A.
 Notation "∅" := empty : C_scope.
 
 Class Union A := union: A → A → A.
+Instance: Params (@union) 2.
 Infix "∪" := union (at level 50, left associativity) : C_scope.
 Notation "(∪)" := union (only parsing) : C_scope.
 Notation "( x ∪)" := (union x) (only parsing) : C_scope.
 Notation "(∪ x )" := (λ y, union y x) (only parsing) : C_scope.
 
 Class Intersection A := intersection: A → A → A.
+Instance: Params (@intersection) 2.
 Infix "∩" := intersection (at level 40) : C_scope.
 Notation "(∩)" := intersection (only parsing) : C_scope.
 Notation "( x ∩)" := (intersection x) (only parsing) : C_scope.
 Notation "(∩ x )" := (λ y, intersection y x) (only parsing) : C_scope.
 
 Class Difference A := difference: A → A → A.
+Instance: Params (@difference) 2.
 Infix "∖" := difference (at level 40) : C_scope.
 Notation "(∖)" := difference (only parsing) : C_scope.
 Notation "( x ∖)" := (difference x) (only parsing) : C_scope.
 Notation "(∖ x )" := (λ y, difference y x) (only parsing) : C_scope.
 
+Class Singleton A B := singleton: A → B.
+Instance: Params (@singleton) 3.
+Notation "{[ x ]}" := (singleton x) : C_scope.
+Notation "{[ x ; y ; .. ; z ]}" :=
+  (union .. (union (singleton x) (singleton y)) .. (singleton z)) : C_scope.
+
 Class SubsetEq A := subseteq: A → A → Prop.
+Instance: Params (@subseteq) 2.
 Infix "⊆" := subseteq (at level 70) : C_scope.
 Notation "(⊆)" := subseteq (only parsing) : C_scope.
 Notation "( X ⊆ )" := (subseteq X) (only parsing) : C_scope.
@@ -90,12 +149,8 @@ Notation "( ⊈ X )" := (λ Y, Y ⊈ X) (only parsing) : C_scope.
 
 Hint Extern 0 (?x ⊆ ?x) => reflexivity.
 
-Class Singleton A B := singleton: A → B.
-Notation "{[ x ]}" := (singleton x) : C_scope.
-Notation "{[ x ; y ; .. ; z ]}" :=
-  (union .. (union (singleton x) (singleton y)) .. (singleton z)) : C_scope.
-
 Class ElemOf A B := elem_of: A → B → Prop.
+Instance: Params (@elem_of) 3.
 Infix "∈" := elem_of (at level 70) : C_scope.
 Notation "(∈)" := elem_of (only parsing) : C_scope.
 Notation "( x ∈)" := (elem_of x) (only parsing) : C_scope.
@@ -105,14 +160,87 @@ Notation "(∉)" := (λ x X, x ∉ X) (only parsing) : C_scope.
 Notation "( x ∉)" := (λ X, x ∉ X) (only parsing) : C_scope.
 Notation "(∉ X )" := (λ x, x ∉ X) (only parsing) : C_scope.
 
+(** ** Operations on maps *)
+(** In this file we will only define operational type classes for the
+operations on maps. In the file [fin_maps] we will axiomatize finite maps.
+The function lookup [m !! k] should yield the element at key [k] in [m]. *)
+Class Lookup K M := lookup: ∀ {A}, K → M A → option A.
+Instance: Params (@lookup) 4.
+
+Notation "m !! i" := (lookup i m) (at level 20) : C_scope.
+Notation "(!!)" := lookup (only parsing) : C_scope.
+Notation "( m !!)" := (λ i, lookup i m) (only parsing) : C_scope.
+Notation "(!! i )" := (lookup i) (only parsing) : C_scope.
+
+(** The function insert [<[k:=a]>m] should update the element at key [k] with
+value [a] in [m]. *)
+Class Insert K M :=
+  insert: ∀ {A}, K → A → M A → M A.
+Instance: Params (@insert) 4.
+Notation "<[ k := a ]>" := (insert k a)
+  (at level 5, right associativity, format "<[ k := a ]>") : C_scope.
+
+(** The function delete [delete k m] should deletes the value at key [k] in
+[m]. *)
+Class Delete K M :=
+  delete: K → M → M.
+Instance: Params (@delete) 3.
+
+(** The function [alter f k m] should update the value at key [k] using the
+function [f], which is called with the original value at key [k]. When [k] is
+not a member of [m], the original map should be returned. *)
+Class Alter K M :=
+  alter: ∀ {A}, (A → A) → K → M A → M A.
+Instance: Params (@alter) 4.
+
+(** The function [alter f k m] should update the value at key [k] using the
+function [f], which is called with the original value at key [k] or [None] if
+[k] is not a member of [m]. The value at [k] should be deleted if [f] yields
+[None]. *)
+Class PartialAlter K M :=
+  partial_alter: ∀ {A}, (option A → option A) → K → M A → M A.
+Instance: Params (@partial_alter) 4.
+
+(** The function [dom C m] should yield the domain of [m]. That is a finite
+collection of type [C] that contains the keys that are a member of [m]. *)
+Class Dom K M :=
+  dom: ∀ C `{Empty C} `{Union C} `{Singleton K C}, M → C.
+Instance: Params (@dom) 7.
+
+(** The function [merge f m1 m2] should merge the maps [m1] and [m2] by
+constructing a new map whose value at key [k] is [f (m1 !! k) (m2 !! k)]
+provided that [k] is a member of either [m1] or [m2].*)
+Class Merge M :=
+  merge: ∀ {A}, (option A → option A → option A) → M A → M A → M A.
+Instance: Params (@merge) 3.
+
+(** We lift the insert and delete operation to lists of elements. *)
+Definition insert_list `{Insert K M} {A} (l : list (K * A)) (m : M A) : M A :=
+  fold_right (λ p, <[ fst p := snd p ]>) m l.
+Instance: Params (@insert_list) 4.
+Definition delete_list `{Delete K M} (l : list K) (m : M) : M :=
+  fold_right delete m l.
+Instance: Params (@delete_list) 3.
+
+(** The function [union_with f m1 m2] should yield the union of [m1] and [m2]
+using the function [f] to combine values of members that are in both [m1] and
+[m2]. *)
 Class UnionWith M :=
   union_with: ∀ {A}, (A → A → A) → M A → M A → M A.
+Instance: Params (@union_with) 3.
+
+(** Similarly for the intersection and difference. *)
 Class IntersectionWith M :=
   intersection_with: ∀ {A}, (A → A → A) → M A → M A → M A.
+Instance: Params (@intersection_with) 3.
 Class DifferenceWith M :=
   difference_with: ∀ {A}, (A → A → option A) → M A → M A → M A.
+Instance: Params (@difference_with) 3.
 
-(* Common properties *)
+(** ** Common properties *)
+(** These operational type classes allow us to refer to common mathematical
+properties in a generic way. For example, for injectivity of [(k ++)] it
+allows us to write [injective (k ++)] instead of [app_inv_head k]. *)
 Class Injective {A B} R S (f : A → B) :=
   injective: ∀ x y : A, S (f x) (f y) → R x y.
 Class Idempotent {A} R (f : A → A → A) :=
@@ -133,7 +261,9 @@ Arguments left_id {_ _} _ _ {_} _.
 Arguments right_id {_ _} _ _ {_} _.
 Arguments associative {_ _} _ {_} _ _ _.
 
-(* Using idempotent_eq we can force Coq to not use the setoid mechanism *)
+(** The following lemmas are more specific versions of the projections of the
+above type classes. These lemmas allow us to enforce Coq not to use the setoid
+rewriting mechanism. *)
 Lemma idempotent_eq {A} (f : A → A → A) `{!Idempotent (=) f} x :
   f x x = x.
 Proof. auto. Qed.
@@ -150,7 +280,10 @@ Lemma associative_eq {A} (f : A → A → A) `{!Associative (=) f} x y z :
   f x (f y z) = f (f x y) z.
 Proof. auto. Qed.
 
-(* Monadic operations *)
+(** ** Monadic operations *)
+(** We do use the operation type classes for monads merely for convenient
+overloading of notations and do not formalize any theory on monads (we do not
+define a class with the monad laws). *)
 Section monad_ops.
   Context (M : Type → Type).
 
@@ -160,9 +293,13 @@ Section monad_ops.
   Class FMap := fmap: ∀ {A B}, (A → B) → M A → M B.
 End monad_ops.
 
+Instance: Params (@mret) 3.
 Arguments mret {M MRet A} _.
+Instance: Params (@mbind) 4.
 Arguments mbind {M MBind A B} _ _.
+Instance: Params (@mjoin) 3.
 Arguments mjoin {M MJoin A} _.
+Instance: Params (@fmap) 4.
 Arguments fmap {M FMap A B} _ _.
 
 Notation "m ≫= f" := (mbind f m) (at level 60, right associativity) : C_scope.
@@ -170,14 +307,17 @@ Notation "x ← y ; z" := (y ≫= (λ x : _, z))
   (at level 65, next at level 35, right associativity) : C_scope.
 Infix "<$>" := fmap (at level 65, right associativity, only parsing) : C_scope.
 
-(* Ordered structures *)
+(** ** Axiomatization of ordered structures *)
+(** A pre-order equiped with a smallest element. *)
 Class BoundedPreOrder A `{Empty A} `{SubsetEq A} := {
   bounded_preorder :>> PreOrder (⊆);
   subseteq_empty x : ∅ ⊆ x
 }.
 
-(* Note: no equality to avoid the need for setoids. We define setoid 
-equality in a generic way. *)
+(** We do not include equality in the following interfaces so as to avoid the
+need for proofs that the  relations and operations respect setoid equality.
+Instead, we will define setoid equality in a generic way as
+[λ X Y, X ⊆ Y ∧ Y ⊆ X]. *)
 Class BoundedJoinSemiLattice A `{Empty A} `{SubsetEq A} `{Union A} := {
   jsl_preorder :>> BoundedPreOrder A;
   subseteq_union_l x y : x ⊆ x ∪ y;
@@ -191,13 +331,15 @@ Class MeetSemiLattice A `{Empty A} `{SubsetEq A} `{Intersection A} := {
   intersection_greatest x y z : z ⊆ x → z ⊆ y → z ⊆ x ∩ y
 }.
 
-(* Containers *)
-Class Size C := size: C → nat.
+(** ** Axiomatization of collections *)
+(** The class [Collection A C] axiomatizes a collection of type [C] with
+elements of type [A]. Since [C] is not dependent on [A], we use the monomorphic
+[Map] type class instead of the polymorphic [FMap]. *)
 Class Map A C := map: (A → A) → (C → C).
-
-Class Collection A C `{ElemOf A C} `{Empty C} `{Union C} 
+Instance: Params (@map) 3.
+Class Collection A C `{ElemOf A C} `{Empty C} `{Union C}
     `{Intersection C} `{Difference C} `{Singleton A C} `{Map A C} := {
-  elem_of_empty (x : A) : x ∉ ∅;
+  not_elem_of_empty (x : A) : x ∉ ∅;
   elem_of_singleton (x y : A) : x ∈ {[ y ]} ↔ x = y;
   elem_of_union X Y (x : A) : x ∈ X ∪ Y ↔ x ∈ X ∨ x ∈ Y;
   elem_of_intersection X Y (x : A) : x ∈ X ∩ Y ↔ x ∈ X ∧ x ∈ Y;
@@ -205,52 +347,42 @@ Class Collection A C `{ElemOf A C} `{Empty C} `{Union C}
   elem_of_map f X (x : A) : x ∈ map f X ↔ ∃ y, x = f y ∧ y ∈ X
 }.
 
+(** We axiomative a finite collection as a collection whose elements can be
+enumerated as a list. These elements, given by the [elements] function, may be
+in any order and should not contain duplicates. *)
 Class Elements A C := elements: C → list A.
-Class FinCollection A C `{Empty C} `{Union C} `{Intersection C} `{Difference C} 
+Instance: Params (@elements) 3.
+Class FinCollection A C `{Empty C} `{Union C} `{Intersection C} `{Difference C}
     `{Singleton A C} `{ElemOf A C} `{Map A C} `{Elements A C} := {
   fin_collection :>> Collection A C;
   elements_spec X x : x ∈ X ↔ In x (elements X);
   elements_nodup X : NoDup (elements X)
-}. 
+}.
+Class Size C := size: C → nat.
+Instance: Params (@size) 2.
 
+(** The function [fresh X] yields an element that is not contained in [X]. We
+will later prove that [fresh] is [Proper] with respect to the induced setoid
+equality on collections. *)
 Class Fresh A C := fresh: C → A.
+Instance: Params (@fresh) 3.
 Class FreshSpec A C `{!Fresh A C} `{!ElemOf A C} := {
-  fresh_proper X Y : (∀ x, x ∈ X ↔ x ∈ Y) → fresh X = fresh Y;
+  fresh_proper_alt X Y : (∀ x, x ∈ X ↔ x ∈ Y) → fresh X = fresh Y;
   is_fresh (X : C) : fresh X ∉ X
 }.
 
-(* Maps *)
-Class Lookup K M := lookup: ∀ {A}, K → M A → option A.
-Notation "m !! i" := (lookup i m) (at level 20) : C_scope.
-Notation "(!!)" := lookup (only parsing) : C_scope.
-Notation "( m !!)" := (λ i, lookup i m) (only parsing) : C_scope.
-Notation "(!! i )" := (lookup i) (only parsing) : C_scope.
+(** * Miscellaneous *)
+Lemma proj1_sig_inj {A} (P : A → Prop) x (Px : P x) y (Py : P y) :
+  x↾Px = y↾Py → x = y.
+Proof. now injection 1. Qed.
 
-Class PartialAlter K M :=
-  partial_alter: ∀ {A}, (option A → option A) → K → M A → M A.
-Class Alter K M :=
-  alter: ∀ {A}, (A → A) → K → M A → M A.
-Class Dom K M :=
-  dom: ∀ C `{Empty C} `{Union C} `{Singleton K C}, M → C.
-Class Merge M :=
-  merge: ∀ {A}, (option A → option A → option A) → M A → M A → M A.
-Class Insert K M :=
-  insert: ∀ {A}, K → A → M A → M A.
-Notation "<[ k := a ]>" := (insert k a) 
-  (at level 5, right associativity, format "<[ k := a ]>") : C_scope.
-Class Delete K M :=
-  delete: K → M → M.
-
-Definition insert_list `{Insert K M} {A} (l : list (K * A)) (m : M A) : M A :=
-  fold_right (λ p, <[ fst p := snd p ]>) m l.
-Definition delete_list `{Delete K M} (l : list K) (m : M) : M := 
-  fold_right delete m l.
-
-(* Misc *)
 Lemma symmetry_iff `(R : relation A) `{!Symmetric R} (x y : A) :
   R x y ↔ R y x.
 Proof. intuition. Qed.
 
+(** ** Pointwise relations *)
+(** These instances are in Coq trunk since revision 15455, but are not in Coq
+8.4 yet. *)
 Instance pointwise_reflexive {A} `{R : relation B} :
   Reflexive R → Reflexive (pointwise_relation A R) | 9.
 Proof. firstorder. Qed.
@@ -261,6 +393,7 @@ Instance pointwise_transitive {A} `{R : relation B} :
   Transitive R → Transitive (pointwise_relation A R) | 9.
 Proof. firstorder. Qed.
 
+(** ** Products *)
 Definition fst_map {A A' B} (f : A → A') (p : A * B) : A' * B :=
   (f (fst p), snd p).
 Definition snd_map {A B B'} (f : B → B') (p : A * B) : A * B' :=
@@ -290,6 +423,7 @@ Section prod_relation.
   Proof. firstorder eauto. Qed.
 End prod_relation.
 
+(** ** Other *)
 Definition lift_relation {A B} (R : relation A)
   (f : B → A) : relation B := λ x y, R (f x) (f y).
 Definition lift_relation_equivalence {A B} (R : relation A) (f : B → A) :
@@ -320,80 +454,3 @@ Proof. easy. Qed.
 Instance idem_propholds {A} (R : relation A) f :
   Idempotent R f → ∀ x, PropHolds (R (f x x) x).
 Proof. easy. Qed.
-
-Ltac simplify_eqs := repeat
-  match goal with
-  | |- _ => progress subst
-  | |- _ = _ => reflexivity
-  | H : _ ≠ _ |- _ => now destruct H
-  | H : _ = _ → False |- _ => now destruct H
-  | H : _ = _ |- _ => discriminate H
-  | H : _ = _ |-  ?G =>
-    change (id G); injection H; clear H; intros; unfold id at 1
-  | H : ?f _ = ?f _ |- _ => apply (injective f) in H
-  | H : ?f _ ?x = ?f _ ?x |- _ => apply (injective (λ y, f y x)) in H
-  end.
-
-Hint Extern 0 (PropHolds _) => assumption : typeclass_instances.
-Instance: Proper (iff ==> iff) PropHolds.
-Proof. now repeat intro. Qed.
-
-Ltac solve_propholds :=
-  match goal with
-  | [ |- PropHolds (?P) ] => apply _
-  | [ |- ?P ] => change (PropHolds P); apply _
-  end.
-
-Tactic Notation "remember" constr(t) "as" "(" ident(x) "," ident(E) ")" :=
-  remember t as x;
-  match goal with
-  | E' : x = _ |- _ => rename E' into E
-  end.
-
-Ltac feed tac H :=
-  let H' := type of H in
-  match eval hnf in H' with
-  | ?T1 → ?T2 =>
-    let HT1 := fresh in assert T1 as HT1;
-    [| feed tac (H HT1); clear HT1 ]
-  | _ => tac H
-  end.
-Tactic Notation "feed" tactic(tac) constr(H) := feed tac H.
-
-Ltac efeed tac H :=
-  let H' := type of H in
-  match eval hnf in H' with
-  | ?T1 → ?T2 =>
-    let HT1 := fresh in assert T1 as HT1; [| efeed tac (H HT1); clear HT1 ]
-  | ?T1 → _ =>
-    let e := fresh in evar (e:T1);
-    let e' := eval unfold e in e in
-    clear e; efeed tac (H e')
-  | _ => tac H
-  end.
-Tactic Notation "efeed" tactic(tac) constr(H) := efeed tac H.
-
-Tactic Notation "feed" "pose" "proof" constr(H) "as" ident(H') :=
-  feed (fun H => pose proof H as H') H.
-Tactic Notation "feed" "pose" "proof" constr(H) :=
-  feed (fun H => pose proof H) H.
-
-Tactic Notation "efeed" "pose" "proof" constr(H) "as" ident(H') :=
-  efeed (fun H => pose proof H as H') H.
-Tactic Notation "efeed" "pose" "proof" constr(H) :=
-  efeed (fun H => pose proof H) H.
-
-Tactic Notation "feed" "specialize" ident(H) :=
-  feed (fun H => specialize H) H.
-Tactic Notation "efeed" "specialize" ident(H) :=
-  efeed (fun H => specialize H) H.
-
-Tactic Notation "feed" "inversion" constr(H) :=
-  feed (fun H => let H':=fresh in pose proof H as H'; inversion H') H.
-Tactic Notation "feed" "inversion" constr(H) "as" simple_intropattern(IP) :=
-  feed (fun H => let H':=fresh in pose proof H as H'; inversion H' as IP) H.
-
-Tactic Notation "feed" "destruct" constr(H) :=
-  feed (fun H => let H':=fresh in pose proof H as H'; destruct H') H.
-Tactic Notation "feed" "destruct" constr(H) "as" simple_intropattern(IP) :=
-  feed (fun H => let H':=fresh in pose proof H as H'; destruct H' as IP) H.
diff --git a/theories/collections.v b/theories/collections.v
index d7e107ef91b1d30fca19daa2c7d1be6b1d2ff40a..8cef0c32b6f07cb99ac6b82487ca4a1db7d9917d 100644
--- a/theories/collections.v
+++ b/theories/collections.v
@@ -1,17 +1,27 @@
-Require Export base orders.
-
+(* Copyright (c) 2012, 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 *)
 Section collection.
   Context `{Collection A B}.
 
-  Lemma elem_of_empty_iff x : x ∈ ∅ ↔ False.
-  Proof. split. apply elem_of_empty. easy. Qed.
-
+  Lemma elem_of_empty x : x ∈ ∅ ↔ False.
+  Proof. split. apply not_elem_of_empty. easy. Qed.
   Lemma elem_of_union_l x X Y : x ∈ X → x ∈ X ∪ Y.
   Proof. intros. apply elem_of_union. auto. Qed.
   Lemma elem_of_union_r x X Y : x ∈ Y → x ∈ X ∪ Y.
   Proof. intros. apply elem_of_union. auto. Qed.
+  Lemma not_elem_of_singleton x y : x ∉ {[ y ]} ↔ x ≠ y.
+  Proof. now rewrite elem_of_singleton. Qed.
+  Lemma not_elem_of_union x X Y : x ∉ X ∪ Y ↔ x ∉ X ∧ x ∉ Y.
+  Proof. rewrite elem_of_union. tauto. Qed.
 
-  Global Instance collection_subseteq: SubsetEq B := λ X Y, ∀ x, x ∈ X → x ∈ Y.
+  Global Instance collection_subseteq: SubsetEq B := λ X Y,
+    ∀ x, x ∈ X → x ∈ Y.
   Global Instance: BoundedJoinSemiLattice B.
   Proof. firstorder. Qed.
   Global Instance: MeetSemiLattice B.
@@ -25,17 +35,20 @@ Section collection.
     X ≡ Y ↔ (∀ x, x ∈ X → x ∈ Y) ∧ (∀ x, x ∈ Y → x ∈ X).
   Proof. firstorder. Qed.
 
-  Global Instance: Proper ((=) ==> (≡) ==> iff) (∈).
+  Global Instance singleton_proper : Proper ((=) ==> (≡)) singleton.
+  Proof. repeat intro. now subst. Qed.
+  Global Instance elem_of_proper: Proper ((=) ==> (≡) ==> iff) (∈).
   Proof. intros ???. subst. firstorder. Qed.
 
-  Lemma empty_ne_singleton x :  ∅ ≢ {[ x ]}.
+  Lemma empty_ne_singleton x : ∅ ≢ {[ x ]}.
   Proof.
-    intros [_ E]. destruct (elem_of_empty x).
+    intros [_ E]. apply (elem_of_empty x).
     apply E. now apply elem_of_singleton.
-  Qed. 
+  Qed.
 End collection.
 
-Section cmap.
+(** * Theorems about map *)
+Section map.
   Context `{Collection A C}.
 
   Lemma elem_of_map_1 (f : A → A) (X : C) (x : A) :
@@ -47,19 +60,18 @@ Section cmap.
   Lemma elem_of_map_2 (f : A → A) (X : C) (x : A) :
     x ∈ map f X → ∃ y, x = f y ∧ y ∈ X.
   Proof. intros. now apply (elem_of_map _). Qed.
-End cmap.
-
-Definition fresh_sig `{FreshSpec A C} (X : C) : { x : A | x ∉ X } :=
-  exist (∉ X) (fresh X) (is_fresh X).
-
-Lemma elem_of_fresh_iff `{FreshSpec A C} (X : C) : fresh X ∈ X ↔ False.
-Proof. split. apply is_fresh. easy. Qed.
-
-Ltac split_elem_ofs := repeat
+End map.
+
+(** * 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]. *)
+Ltac unfold_elem_of := repeat
   match goal with
   | H : context [ _ ⊆ _ ] |- _ => setoid_rewrite elem_of_subseteq in H
   | H : context [ _ ≡ _ ] |- _ => setoid_rewrite elem_of_equiv_alt in H
-  | H : context [ _ ∈ ∅ ] |- _ => setoid_rewrite elem_of_empty_iff in H
+  | H : context [ _ ∈ ∅ ] |- _ => setoid_rewrite elem_of_empty in H
   | H : context [ _ ∈ {[ _ ]} ] |- _ => setoid_rewrite elem_of_singleton in H
   | H : context [ _ ∈ _ ∪ _ ] |- _ => setoid_rewrite elem_of_union in H
   | H : context [ _ ∈ _ ∩ _ ] |- _ => setoid_rewrite elem_of_intersection in H
@@ -67,7 +79,7 @@ Ltac split_elem_ofs := repeat
   | H : context [ _ ∈ map _ _ ] |- _ => setoid_rewrite elem_of_map in H
   | |- context [ _ ⊆ _ ] => setoid_rewrite elem_of_subseteq
   | |- context [ _ ≡ _ ] => setoid_rewrite elem_of_equiv_alt
-  | |- context [ _ ∈ ∅ ] => setoid_rewrite elem_of_empty_iff
+  | |- context [ _ ∈ ∅ ] => setoid_rewrite elem_of_empty
   | |- context [ _ ∈ {[ _ ]} ] => setoid_rewrite elem_of_singleton
   | |- context [ _ ∈ _ ∪ _ ] => setoid_rewrite elem_of_union
   | |- context [ _ ∈ _ ∩ _ ] => setoid_rewrite elem_of_intersection
@@ -75,56 +87,49 @@ Ltac split_elem_ofs := repeat
   | |- context [ _ ∈ map _ _ ] => setoid_rewrite elem_of_map
   end.
 
-Ltac destruct_elem_ofs := repeat
-  match goal with
-  | H : context [ @elem_of (_ * _) _ _ ?x _ ] |- _ => is_var x; destruct x
-  | H : context [ @elem_of (_ + _) _ _ ?x _] |- _ => is_var x; destruct x
-  end.
-
-Tactic Notation "simplify_elem_of" tactic(t) :=
-  intros; (* due to bug #2790 *)
+(** The tactic [solve_elem_of tac] composes the above tactic with [intuition].
+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" tactic(tac) :=
   simpl in *;
-  split_elem_ofs;
-  destruct_elem_ofs;
-  intuition (simplify_eqs; t).
-Tactic Notation "simplify_elem_of" := simplify_elem_of auto.
-
-Ltac naive_firstorder t :=
-  match goal with
-  (* intros *)
-  | |- ∀ _, _ => intro; naive_firstorder t
-  (* destructs without information loss *)
-  | H : False |- _ => destruct H
-  | H : ?X, Hneg : ¬?X|- _ => now destruct Hneg
-  | H : _ ∧ _ |- _ => destruct H; naive_firstorder t
-  | H : ∃ _, _  |- _ => destruct H; naive_firstorder t
-  (* simplification *)
-  | |- _ => progress (simplify_eqs; simpl in *); naive_firstorder t
-  (* constructs *)
-  | |- _ ∧ _ => split; naive_firstorder t
-  (* solve *)
-  | |- _ => solve [t]
-  (* dirty destructs *)
-  | H : context [ ∃ _, _ ] |- _ =>
-    edestruct H; clear H;naive_firstorder t || clear H; naive_firstorder t
-  | H : context [ _ ∧ _ ] |- _ => 
-    destruct H; clear H; naive_firstorder t || clear H; naive_firstorder t
-  | H : context [ _ ∨ _ ] |- _ =>
-    edestruct H; clear H; naive_firstorder t || clear H; naive_firstorder t
-  (* dirty constructs *)
-  | |- ∃ x, _ => eexists; naive_firstorder t
-  | |- _ ∨ _ => left; naive_firstorder t || right; naive_firstorder t
-  | H : _ → False |- _ => destruct H; naive_firstorder t
-  end.
-Tactic Notation "naive_firstorder" tactic(t) :=
-  unfold iff, not in *; 
-  naive_firstorder t.
-
-Tactic Notation "esimplify_elem_of" tactic(t) := 
-  (simplify_elem_of t); 
-  try naive_firstorder t.
-Tactic Notation "esimplify_elem_of" := esimplify_elem_of (eauto 5).
-
+  unfold_elem_of;
+  solve [intuition (simplify_equality; tac)].
+Tactic Notation "solve_elem_of" := solve_elem_of auto.
+
+(** For goals with quantifiers we could use the above tactic but with
+[firstorder] instead of [intuition] as finishing tactic. However, [firstorder]
+fails or loops on very small goals generated by [solve_elem_of] already. We
+use the [naive_solver] tactic as a substitute. This tactic either fails or
+proves the goal. *)
+Tactic Notation "esolve_elem_of" tactic(tac) :=
+  simpl in *;
+  unfold_elem_of;
+  naive_solver tac.
+Tactic Notation "esolve_elem_of" := esolve_elem_of eauto.
+
+(** Given an assumption [H : _ ∈ _], the tactic [destruct_elem_of H] will
+recursively split [H] for [(∪)], [(∩)], [(∖)], [map], [∅], [{[_]}]. *)
+Tactic Notation "destruct_elem_of" hyp(H) :=
+  let rec go H :=
+  lazymatch type of H with
+  | _ ∈ ∅ => apply elem_of_empty in H; destruct H
+  | _ ∈ {[ ?l' ]} => apply elem_of_singleton in H; subst l'
+  | _ ∈ _ ∪ _ =>
+    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
+  | _ ∈ map _ _ =>
+    let H1 := fresh in apply elem_of_map in H;
+    destruct H as [?[? H1]]; go H1
+  | _ => idtac
+  end in go H.
+
+(** * Sets without duplicates up to an equivalence *)
 Section no_dup.
   Context `{Collection A B} (R : relation A) `{!Equivalence R}.
 
@@ -143,33 +148,34 @@ Section no_dup.
   Proof. firstorder. Qed.
 
   Lemma elem_of_upto_elem_of x X : x ∈ X → elem_of_upto x X.
-  Proof. unfold elem_of_upto. esimplify_elem_of. Qed.
+  Proof. unfold elem_of_upto. esolve_elem_of. Qed.
   Lemma elem_of_upto_empty x : ¬elem_of_upto x ∅.
-  Proof. unfold elem_of_upto. esimplify_elem_of. Qed.
+  Proof. unfold elem_of_upto. esolve_elem_of. Qed.
   Lemma elem_of_upto_singleton x y : elem_of_upto x {[ y ]} ↔ R x y.
-  Proof. unfold elem_of_upto. esimplify_elem_of. Qed.
+  Proof. unfold elem_of_upto. esolve_elem_of. Qed.
 
   Lemma elem_of_upto_union X Y x :
     elem_of_upto x (X ∪ Y) ↔ elem_of_upto x X ∨ elem_of_upto x Y.
-  Proof. unfold elem_of_upto. esimplify_elem_of. Qed.
+  Proof. unfold elem_of_upto. esolve_elem_of. Qed.
   Lemma not_elem_of_upto x X : ¬elem_of_upto x X → ∀ y, y ∈ X → ¬R x y.
-  Proof. unfold elem_of_upto. esimplify_elem_of. Qed.
+  Proof. unfold elem_of_upto. esolve_elem_of. Qed.
 
   Lemma no_dup_empty: no_dup ∅.
-  Proof. unfold no_dup. simplify_elem_of. Qed.
+  Proof. unfold no_dup. solve_elem_of. Qed.
   Lemma no_dup_add x X : ¬elem_of_upto x X → no_dup X → no_dup ({[ x ]} ∪ X).
-  Proof. unfold no_dup, elem_of_upto. esimplify_elem_of. Qed.
+  Proof. unfold no_dup, elem_of_upto. esolve_elem_of. Qed.
   Lemma no_dup_inv_add x X : x ∉ X → no_dup ({[ x ]} ∪ X) → ¬elem_of_upto x X.
   Proof.
     intros Hin Hnodup [y [??]].
-    rewrite (Hnodup x y) in Hin; simplify_elem_of.
+    rewrite (Hnodup x y) in Hin; solve_elem_of.
   Qed.
   Lemma no_dup_inv_union_l X Y : no_dup (X ∪ Y) → no_dup X.
-  Proof. unfold no_dup. simplify_elem_of. Qed.
+  Proof. unfold no_dup. solve_elem_of. Qed.
   Lemma no_dup_inv_union_r X Y : no_dup (X ∪ Y) → no_dup Y.
-  Proof. unfold no_dup. simplify_elem_of. Qed.
+  Proof. unfold no_dup. solve_elem_of. Qed.
 End no_dup.
 
+(** * Quantifiers *)
 Section quantifiers.
   Context `{Collection A B} (P : A → Prop).
 
@@ -177,48 +183,65 @@ Section quantifiers.
   Definition cexists X := ∃ x, x ∈ X ∧ P x.
 
   Lemma cforall_empty : cforall ∅.
-  Proof. unfold cforall. simplify_elem_of. Qed.
+  Proof. unfold cforall. solve_elem_of. Qed.
   Lemma cforall_singleton x : cforall {[ x ]} ↔ P x.
-  Proof. unfold cforall. simplify_elem_of. Qed.
+  Proof. unfold cforall. solve_elem_of. Qed.
   Lemma cforall_union X Y : cforall X → cforall Y → cforall (X ∪ Y).
-  Proof. unfold cforall. simplify_elem_of. Qed.
+  Proof. unfold cforall. solve_elem_of. Qed.
   Lemma cforall_union_inv_1 X Y : cforall (X ∪ Y) → cforall X.
-  Proof. unfold cforall. simplify_elem_of. Qed.
+  Proof. unfold cforall. solve_elem_of. Qed.
   Lemma cforall_union_inv_2 X Y : cforall (X ∪ Y) → cforall Y.
-  Proof. unfold cforall. simplify_elem_of. Qed.
+  Proof. unfold cforall. solve_elem_of. Qed.
 
   Lemma cexists_empty : ¬cexists ∅.
-  Proof. unfold cexists. esimplify_elem_of. Qed.
+  Proof. unfold cexists. esolve_elem_of. Qed.
   Lemma cexists_singleton x : cexists {[ x ]} ↔ P x.
-  Proof. unfold cexists. esimplify_elem_of. Qed.
+  Proof. unfold cexists. esolve_elem_of. Qed.
   Lemma cexists_union_1 X Y : cexists X → cexists (X ∪ Y).
-  Proof. unfold cexists. esimplify_elem_of. Qed.
+  Proof. unfold cexists. esolve_elem_of. Qed.
   Lemma cexists_union_2 X Y : cexists Y → cexists (X ∪ Y).
-  Proof. unfold cexists. esimplify_elem_of. Qed.
+  Proof. unfold cexists. esolve_elem_of. Qed.
   Lemma cexists_union_inv X Y : cexists (X ∪ Y) → cexists X ∨ cexists Y.
-  Proof. unfold cexists. esimplify_elem_of. Qed.
+  Proof. unfold cexists. esolve_elem_of. Qed.
 End quantifiers.
 
 Section more_quantifiers.
   Context `{Collection A B}.
-  
+
   Lemma cforall_weak (P Q : A → Prop) (Hweak : ∀ x, P x → Q x) X :
     cforall P X → cforall Q X.
-  Proof. firstorder. Qed.
+  Proof. unfold cforall. naive_solver. Qed.
   Lemma cexists_weak (P Q : A → Prop) (Hweak : ∀ x, P x → Q x) X :
     cexists P X → cexists Q X.
-  Proof. firstorder. Qed.
+  Proof. unfold cexists. naive_solver. Qed.
 End more_quantifiers.
 
+(** * Fresh elements *)
+(** We collect some properties on the [fresh] operation. In particular we
+generalize [fresh] to generate lists of fresh elements. *)
 Section fresh.
   Context `{Collection A C} `{Fresh A C} `{!FreshSpec A C} .
 
+  Definition fresh_sig (X : C) : { x : A | x ∉ X } :=
+    exist (∉ X) (fresh X) (is_fresh X).
+
+  Global Instance fresh_proper: Proper ((≡) ==> (=)) fresh.
+  Proof. intros ???. now apply fresh_proper_alt, elem_of_equiv. Qed.
+
   Fixpoint fresh_list (n : nat) (X : C) : list A :=
     match n with
     | 0 => []
     | S n => let x := fresh X in x :: fresh_list n ({[ x ]} ∪ X)
     end.
 
+  Global Instance fresh_list_proper: Proper ((=) ==> (≡) ==> (=)) fresh_list.
+  Proof.
+    intros ? n ?. subst.
+    induction n; simpl; intros ?? E; f_equal.
+    * now rewrite E.
+    * apply IHn. now rewrite E.
+  Qed.
+
   Lemma fresh_list_length n X : length (fresh_list n X) = n.
   Proof. revert X. induction n; simpl; auto. Qed.
 
@@ -228,7 +251,7 @@ Section fresh.
     * easy.
     * intros X [?| Hin]. subst.
       + apply is_fresh.
-      + apply IHn in Hin. simplify_elem_of.
+      + apply IHn in Hin. solve_elem_of.
   Qed.
 
   Lemma fresh_list_nodup n X : NoDup (fresh_list n X).
@@ -236,6 +259,6 @@ Section fresh.
     revert X.
     induction n; simpl; constructor; auto.
     intros Hin. apply fresh_list_is_fresh in Hin.
-    simplify_elem_of.
+    solve_elem_of.
   Qed.
 End fresh.
diff --git a/theories/decidable.v b/theories/decidable.v
index 3cbb71240d3fbba45d802d8551555064b42aeb0f..3bdfbf967dd79a1e01bc9e5b9a08974153fec38c 100644
--- a/theories/decidable.v
+++ b/theories/decidable.v
@@ -1,58 +1,60 @@
+(* Copyright (c) 2012, Robbert Krebbers. *)
+(* This file is distributed under the terms of the BSD license. *)
+(** This file collects theorems, definitions, tactics, related to propositions
+with a decidable equality. Such propositions are collected by the [Decision]
+type class. *)
 Require Export base.
 
-Definition decide_rel {A B} (R : A → B → Prop) 
-  {dec : ∀ x y, Decision (R x y)} (x : A) (y : B) : Decision (R x y) := dec x y.
+(** We introduce [decide_rel] to avoid inefficienct computation due to eager
+evaluation of propositions by [vm_compute]. This inefficiency occurs if
+[(x = y) := (f x = f y)] as [decide (x = y)] evaluates to [decide (f x = f y)]
+which then might lead to evaluation of [f x] and [f y]. Using [decide_rel]
+we hide [f] under a lambda abstraction to avoid this unnecessary evaluation. *)
+Definition decide_rel {A B} (R : A → B → Prop) {dec : ∀ x y, Decision (R x y)}
+  (x : A) (y : B) : Decision (R x y) := dec x y.
+Lemma decide_rel_correct {A B} (R : A → B → Prop) `{∀ x y, Decision (R x y)}
+  (x : A) (y : B) : decide_rel R x y = decide (R x y).
+Proof. easy. Qed.
 
-Ltac case_decide := 
+(** The tactic [case_decide] performs case analysis on an arbitrary occurrence
+of [decide] or [decide_rel] in the conclusion or assumptions. *)
+Ltac case_decide :=
   match goal with
-  | H : context [@decide ?P ?dec] |- _ => case (@decide P dec) in *
+  | H : context [@decide ?P ?dec] |- _ =>
+    destruct (@decide P dec)
   | H : context [@decide_rel _ _ ?R ?x ?y ?dec] |- _ =>
-     case (@decide_rel _ _ R x y dec) in *
-  | |- context [@decide ?P ?dec] => case (@decide P dec) in *
+    destruct (@decide_rel _ _ R x y dec)
+  | |- context [@decide ?P ?dec] =>
+    destruct (@decide P dec)
   | |- context [@decide_rel _ _ ?R ?x ?y ?dec] =>
-     case (@decide_rel _ _ R x y dec) in *
+    destruct (@decide_rel _ _ R x y dec)
   end.
 
+(** The tactic [solve_decision] uses Coq's [decide equality] tactic together
+with instance resolution to automatically generate decision procedures. *)
 Ltac solve_trivial_decision :=
   match goal with
   | [ |- Decision (?P) ] => apply _
   | [ |- sumbool ?P (¬?P) ] => change (Decision P); apply _
   end.
-Ltac solve_decision := 
+Ltac solve_decision :=
   intros; first [ solve_trivial_decision
                 | unfold Decision; decide equality; solve_trivial_decision ].
 
-Program Instance True_dec: Decision True := left _.
-Program Instance False_dec: Decision False := right _.
-Program Instance prod_eq_dec `(A_dec : ∀ x y : A, Decision (x = y))
-    `(B_dec : ∀ x y : B, Decision (x = y)) : ∀ x y : A * B, Decision (x = y) := λ x y,
-  match A_dec (fst x) (fst y) with
-  | left _ => match B_dec (snd x) (snd y) with left _ => left _ | right _ => right _ end
-  | right _ => right _
-  end.
-Solve Obligations using (program_simpl; f_equal; firstorder).
-Program Instance and_dec `(P_dec : Decision P) `(Q_dec : Decision Q) :
-    Decision (P ∧ Q) :=
-  match P_dec with
-  | left _ => match Q_dec with left _ => left _ | right _ => right _ end
-  | right _ => right _
-  end.
-Solve Obligations using (program_simpl; tauto).
-Program Instance or_dec `(P_dec : Decision P) `(Q_dec : Decision Q) :
-    Decision (P ∨ Q) :=
-  match P_dec with
-  | left _ => left _
-  | right _ => match Q_dec with left _ => left _ | right _ => right _ end
-  end.
-Solve Obligations using (program_simpl; firstorder).
+(** We can convert decidable propositions to booleans. *)
+Definition bool_decide (P : Prop) {dec : Decision P} : bool :=
+  if dec then true else false.
 
-Definition bool_decide (P : Prop) {dec : Decision P} : bool := if dec then true else false.
-Coercion Is_true : bool >-> Sortclass.
 Lemma bool_decide_unpack (P : Prop) {dec : Decision P} : bool_decide P → P.
 Proof. unfold bool_decide. now destruct dec. Qed.
 Lemma bool_decide_pack (P : Prop) {dec : Decision P} : P → bool_decide P.
 Proof. unfold bool_decide. now destruct dec. Qed.
 
+(** * Decidable Sigma types *)
+(** Leibniz equality on Sigma types requires the equipped proofs to be
+equal as Coq does not support proof irrelevance. For decidable we
+propositions we define the type [dsig P] whose Leibniz equality is proof
+irrelevant. That is [∀ x y : dsig P, x = y ↔ `x = `y]. *)
 Definition dsig `(P : A → Prop) `{∀ x : A, Decision (P x)} :=
   { x | bool_decide (P x) }.
 Definition proj2_dsig `{∀ x : A, Decision (P x)} (x : dsig P) : P (`x) :=
@@ -60,15 +62,46 @@ Definition proj2_dsig `{∀ x : A, Decision (P x)} (x : dsig P) : P (`x) :=
 Definition dexist `{∀ x : A, Decision (P x)} (x : A) (p : P x) : dsig P :=
   x↾bool_decide_pack _ p.
 
-Lemma proj1_dsig_inj {A} (P : A → Prop) x (Px : P x) y (Py : P y) :
-  x↾Px = y↾Py → x = y.
-Proof. now injection 1. Qed.
 Lemma dsig_eq {A} (P : A → Prop) {dec : ∀ x, Decision (P x)}
-  (x y : { x | bool_decide (P x) }) : `x = `y → x = y.
+  (x y : dsig P) : x = y ↔ `x = `y.
 Proof.
-  intros H1. destruct x as [x Hx], y as [y Hy].
-  simpl in *. subst. f_equal.
-  revert Hx Hy. case (bool_decide (P y)).
-  * now intros [] [].
-  * easy.
+  split.
+  * destruct x, y. apply proj1_sig_inj.
+  * intro. destruct x as [x Hx], y as [y Hy].
+    simpl in *. subst. f_equal.
+    revert Hx Hy. case (bool_decide (P y)).
+    + now intros [] [].
+    + easy.
 Qed.
+
+(** * Instances of Decision *)
+(** Instances of [Decision] for operators of propositional logic. *)
+Program Instance True_dec: Decision True := left _.
+Program Instance False_dec: Decision False := right _.
+Program Instance and_dec `(P_dec : Decision P) `(Q_dec : Decision Q) :
+    Decision (P ∧ Q) :=
+  match P_dec with
+  | left _ => match Q_dec with left _ => left _ | right _ => right _ end
+  | right _ => right _
+  end.
+Solve Obligations using intuition.
+Program Instance or_dec `(P_dec : Decision P) `(Q_dec : Decision Q) :
+    Decision (P ∨ Q) :=
+  match P_dec with
+  | left _ => left _
+  | right _ => match Q_dec with left _ => left _ | right _ => right _ end
+  end.
+Solve Obligations using intuition.
+
+(** Instances of [Decision] for common data types. *)
+Program Instance prod_eq_dec `(A_dec : ∀ x y : A, Decision (x = y))
+    `(B_dec : ∀ x y : B, Decision (x = y)) (x y : A * B) : Decision (x = y) :=
+  match A_dec (fst x) (fst y) with
+  | left _ =>
+    match B_dec (snd x) (snd y) with
+    | left _ => left _
+    | right _ => right _
+    end
+  | right _ => right _
+  end.
+Solve Obligations using intuition (simpl;congruence).
diff --git a/theories/fin_collections.v b/theories/fin_collections.v
index f823d7c506297f002de628c29d2846aef44f1d5b..06caeb1784d064725ee799ae937d5928b400152b 100644
--- a/theories/fin_collections.v
+++ b/theories/fin_collections.v
@@ -1,9 +1,14 @@
+(* Copyright (c) 2012, Robbert Krebbers. *)
+(* This file is distributed under the terms of the BSD license. *)
+(** This file collects definitions and theorems on finite collections. Most
+importantly, it implements a fold and size function and some useful induction
+principles on finite collections . *)
 Require Import Permutation.
 Require Export collections listset.
 
 Instance collection_size `{Elements A C} : Size C := λ X, length (elements X).
-Definition collection_fold `{Elements A C} {B} (f : A → B → B) (b : B) (X : C) : B := 
-  fold_right f b (elements X).
+Definition collection_fold `{Elements A C} {B} (f : A → B → B)
+  (b : B) (X : C) : B := fold_right f b (elements X).
 
 Section fin_collection.
 Context `{FinCollection A C}.
@@ -22,7 +27,7 @@ Lemma size_empty : size ∅ = 0.
 Proof.
   unfold size, collection_size. rewrite (in_nil_inv (elements ∅)).
   * easy.
-  * intro. rewrite <-elements_spec. simplify_elem_of.
+  * intro. rewrite <-elements_spec. solve_elem_of.
 Qed.
 Lemma size_empty_inv X : size X = 0 → X ≡ ∅.
 Proof.
@@ -38,7 +43,7 @@ Proof.
   apply Permutation_length, NoDup_Permutation.
   * apply elements_nodup.
   * apply NoDup_singleton.
-  * intros. rewrite <-elements_spec. esimplify_elem_of firstorder.
+  * intros. rewrite <-elements_spec. esolve_elem_of firstorder.
 Qed.
 Lemma size_singleton_inv X x y : size X = 1 → x ∈ X → y ∈ X → x = y.
 Proof.
@@ -51,14 +56,13 @@ Qed.
 
 Lemma choose X : X ≢ ∅ → { x | x ∈ X }.
 Proof.
-  case_eq (elements X).
-  * intros E. intros []. apply equiv_empty.
+  destruct (elements X) as [|x l] eqn:E.
+  * intros []. apply equiv_empty.
     intros x. rewrite elements_spec, E. contradiction.
-  * intros x l E. exists x.
-    rewrite elements_spec, E. now left.
+  * exists x. rewrite elements_spec, E. now left.
 Qed.
 Lemma size_pos_choose X : 0 < size X → { x | x ∈ X }.
-Proof. 
+Proof.
   intros E. apply choose.
   intros E2. rewrite E2, size_empty in E.
   now destruct (Lt.lt_n_0 0).
@@ -67,10 +71,13 @@ Lemma size_1_choose X : size X = 1 → { x | X ≡ {[ x ]} }.
 Proof.
   intros E. destruct (size_pos_choose X).
   * rewrite E. auto with arith.
-  * exists x. simplify_elem_of. eapply size_singleton_inv; eauto.
+  * exists x. apply elem_of_equiv. split.
+    + intro. rewrite elem_of_singleton. eauto using size_singleton_inv.
+    + solve_elem_of.
 Qed.
 
-Program Instance collection_car_eq_dec_slow (x y : A) : Decision (x = y) | 100 :=
+Program Instance collection_car_eq_dec_slow (x y : A) :
+    Decision (x = y) | 100 :=
   match Compare_dec.zerop (size ({[ x ]} ∩ {[ y ]})) with
   | left _ => right _
   | right _ => left _
@@ -79,9 +86,9 @@ Next Obligation.
   intro. apply empty_ne_singleton with x.
   transitivity ({[ x ]} ∩ {[ y ]}).
   * symmetry. now apply size_empty_iff.
-  * simplify_elem_of.
+  * solve_elem_of.
 Qed.
-Next Obligation. edestruct size_pos_choose; esimplify_elem_of. Qed.
+Next Obligation. edestruct size_pos_choose; esolve_elem_of. Qed.
 
 Instance elem_of_dec_slow (x : A) (X : C) : Decision (x ∈ X) | 100 :=
   match decide_rel In x (elements X) with
@@ -90,40 +97,44 @@ Instance elem_of_dec_slow (x : A) (X : C) : Decision (x ∈ X) | 100 :=
   end.
 
 Lemma union_difference X Y : X ∪ Y ∖ X ≡ X ∪ Y.
-Proof. split; intros x; destruct (decide (x ∈ X)); simplify_elem_of. Qed.
+Proof. split; intros x; destruct (decide (x ∈ X)); solve_elem_of. Qed.
 
 Lemma size_union X Y : X ∩ Y ≡ ∅ → size (X ∪ Y) = size X + size Y.
 Proof.
   intros [E _]. unfold size, collection_size. rewrite <-app_length.
   apply Permutation_length, NoDup_Permutation.
-    apply elements_nodup.
-   apply NoDup_app; try apply elements_nodup.
-   intros x. rewrite <-!elements_spec.
-   intros ??. apply (elem_of_empty x), E. simplify_elem_of.
-  intros. rewrite in_app_iff, <-!elements_spec. simplify_elem_of.
+  * apply elements_nodup.
+  * apply NoDup_app; try apply elements_nodup.
+    intros x. rewrite <-!elements_spec. esolve_elem_of.
+  * intros. rewrite in_app_iff, <-!elements_spec. solve_elem_of.
 Qed.
 Lemma size_union_alt X Y : size (X ∪ Y) = size X + size (Y ∖ X).
-Proof. rewrite <-size_union. now rewrite union_difference. simplify_elem_of. Qed.
+Proof.
+  rewrite <-size_union. now rewrite union_difference. solve_elem_of.
+Qed.
 Lemma size_add X x : x ∉ X → size ({[ x ]} ∪ X) = S (size X).
-Proof. intros. rewrite size_union. now rewrite size_singleton. simplify_elem_of. Qed.
+Proof.
+  intros. rewrite size_union. now rewrite size_singleton. solve_elem_of.
+Qed.
 Lemma size_difference X Y : X ⊆ Y → size X + size (Y ∖ X) = size Y.
 Proof. intros. now rewrite <-size_union_alt, subseteq_union_1. Qed.
 Lemma size_remove X x : x ∈ X → S (size (X ∖ {[ x ]})) = size X.
 Proof.
   intros. rewrite <-(size_difference {[ x ]} X).
   * rewrite size_singleton. auto with arith.
-  * simplify_elem_of.
+  * solve_elem_of.
 Qed.
 
 Lemma subseteq_size X Y : X ⊆ Y → size X ≤ size Y.
 Proof.
   intros. rewrite <-(subseteq_union_1 X Y) by easy.
-  rewrite <-(union_difference X Y), size_union by simplify_elem_of.
+  rewrite <-(union_difference X Y), size_union by solve_elem_of.
   auto with arith.
-Qed. 
+Qed.
 
 Lemma collection_wf_ind (P : C → Prop) :
-  (∀ X, (∀ Y, size Y < size X → P Y) → P X) → ∀ X, P X.
+  (∀ X, (∀ Y, size Y < size X → P Y) → P X) →
+  ∀ X, P X.
 Proof.
   intros Hind. cut (∀ n X, size X < n → P X).
   { intros help X. apply help with (S (size X)). auto with arith. }
@@ -133,15 +144,18 @@ Proof.
 Qed.
 
 Lemma collection_ind (P : C → Prop) :
-  Proper ((≡) ==> iff) P → P ∅ → (∀ x X, x ∉ X → P X → P ({[ x ]} ∪ X)) → ∀ X, P X.
+  Proper ((≡) ==> iff) P →
+  P ∅ →
+  (∀ x X, x ∉ X → P X → P ({[ x ]} ∪ X)) →
+  ∀ X, P X.
 Proof.
   intros ? Hemp Hadd. apply collection_wf_ind.
   intros X IH. destruct (Compare_dec.zerop (size X)).
   * now rewrite size_empty_inv.
   * destruct (size_pos_choose X); auto.
-    rewrite <-(subseteq_union_1 {[ x ]} X) by simplify_elem_of.
+    rewrite <-(subseteq_union_1 {[ x ]} X) by solve_elem_of.
     rewrite <-union_difference.
-    apply Hadd; simplify_elem_of. apply IH.
+    apply Hadd; [solve_elem_of |]. apply IH.
     rewrite <-(size_remove X x); auto with arith.
 Qed.
 
@@ -157,17 +171,18 @@ Proof.
   induction 1 as [|x l ?? IHl]; simpl.
   * intros X HX. rewrite equiv_empty. easy. intros ??. firstorder.
   * intros X HX.
-    rewrite <-(subseteq_union_1 {[ x ]} X) by esimplify_elem_of.
+    rewrite <-(subseteq_union_1 {[ x ]} X) by esolve_elem_of.
     rewrite <-union_difference.
-    apply Hadd. simplify_elem_of. apply IHl.
+    apply Hadd. solve_elem_of. apply IHl.
     intros y. split.
-    + intros. destruct (proj1 (HX y)); simplify_elem_of.
-    + esimplify_elem_of.
+    + intros. destruct (proj1 (HX y)); solve_elem_of.
+    + esolve_elem_of.
 Qed.
 
 Lemma collection_fold_proper {B} (f : A → B → B) (b : B) :
-  (∀ a1 a2 b, f a1 (f a2 b) = f a2 (f a1 b)) → Proper ((≡) ==> (=)) (collection_fold f b).
-Proof. intros ??? E. apply fold_right_permutation. auto. now rewrite E. Qed. 
+  (∀ a1 a2 b, f a1 (f a2 b) = f a2 (f a1 b)) →
+  Proper ((≡) ==> (=)) (collection_fold f b).
+Proof. intros ??? E. apply fold_right_permutation. auto. now rewrite E. Qed.
 
 Global Program Instance cforall_dec `(P : A → Prop)
     `{∀ x, Decision (P x)} X : Decision (cforall P X) | 100 :=
@@ -177,7 +192,7 @@ Global Program Instance cforall_dec `(P : A → Prop)
   end.
 Next Obligation.
   red. setoid_rewrite elements_spec. now apply Forall_forall.
-Qed. 
+Qed.
 Next Obligation.
   intro. apply Hall, Forall_forall. setoid_rewrite <-elements_spec. auto.
 Qed.
@@ -189,12 +204,17 @@ Global Program Instance cexists_dec `(P : A → Prop)
   | right Hex => right _
   end.
 Next Obligation.
-  red. setoid_rewrite elements_spec. now apply Exists_exists. 
-Qed. 
+  red. setoid_rewrite elements_spec. now apply Exists_exists.
+Qed.
 Next Obligation.
   intro. apply Hex, Exists_exists. setoid_rewrite <-elements_spec. auto.
 Qed.
 
 Global Instance rel_elem_of_dec `{∀ x y, Decision (R x y)} x X :
   Decision (elem_of_upto R x X) | 100 := decide (cexists (R x) X).
+
+Lemma not_elem_of_intersection x X Y : x ∉ X ∩ Y ↔ x ∉ X ∨ x ∉ Y.
+Proof. destruct (decide (x ∈ X)); solve_elem_of. Qed.
+Lemma not_elem_of_difference x X Y : x ∉ X ∖ Y ↔ x ∉ X ∨ x ∈ Y.
+Proof. destruct (decide (x ∈ Y)); solve_elem_of. Qed.
 End fin_collection.
diff --git a/theories/fin_maps.v b/theories/fin_maps.v
index f9a755a8373f2979da5034023577c3699178c60b..f023e46cfdc2389b4d609ac0b96f948f671d1178 100644
--- a/theories/fin_maps.v
+++ b/theories/fin_maps.v
@@ -1,6 +1,25 @@
+(* Copyright (c) 2012, Robbert Krebbers. *)
+(* This file is distributed under the terms of the BSD license. *)
+(** Finite maps associate data to keys. This file defines an interface for
+finite maps and collects some theory on it. Most importantly, it proves useful
+induction principles for finite maps and implements the tactic [simplify_map]
+to simplify goals involving finite maps. *)
 Require Export prelude.
 
-Class FinMap K M `{∀ A, Empty (M A)} `{Lookup K M} `{FMap M} 
+(** * Axiomatization of finite maps *)
+(** We require Leibniz equality to be extensional on finite maps. This of
+course limits the class of finite map implementations, but since we are mainly
+interested in finite maps with numbers or paths as indexes, we do not consider
+this a serious limitation. The main application of finite maps is to implement
+the memory, where extensionality of Leibniz equality becomes very important for
+a convenient use in assertions of our axiomatic semantics. *)
+(** Finiteness is axiomatized by requiring each map to have a finite domain.
+Since we may have multiple implementations of finite sets, the [dom] function is
+parametrized by an implementation of finite sets over the map's key type. *)
+(** Finite map implementations are required to implement the [merge] function
+which enables us to give a generic implementation of [union_with],
+[intersection_with], and [difference_with]. *)
+Class FinMap K M `{∀ A, Empty (M A)} `{Lookup K M} `{FMap M}
     `{PartialAlter K M} `{∀ A, Dom K (M A)} `{Merge M} := {
   finmap_eq {A} (m1 m2 : M A) :
     (∀ i, m1 !! i = m2 !! i) → m1 = m2;
@@ -14,21 +33,26 @@ Class FinMap K M `{∀ A, Empty (M A)} `{Lookup K M} `{FMap M}
     (f <$> m) !! i = f <$> m !! i;
   elem_of_dom C {A} `{Collection K C} (m : M A) i :
     i ∈ dom C m ↔ is_Some (m !! i);
-  merge_spec {A} f `{!PropHolds (f None None = None)} 
+  merge_spec {A} f `{!PropHolds (f None None = None)}
     (m1 m2 : M A) i : merge f m1 m2 !! i = f (m1 !! i) (m2 !! i)
 }.
 
+(** * Derived operations *)
+(** All of the following functions are defined in a generic way for arbitrary
+finite map implementations. These generic implementations do not cause a
+significant enough performance loss to make including them in the finite map
+axiomatization worthwhile. *)
 Instance finmap_alter `{PartialAlter K M} : Alter K M := λ A f,
   partial_alter (fmap f).
 Instance finmap_insert `{PartialAlter K M} : Insert K M := λ A k x,
   partial_alter (λ _, Some x) k.
 Instance finmap_delete `{PartialAlter K M} {A} : Delete K (M A) :=
   partial_alter (λ _, None).
-Instance finmap_singleton `{PartialAlter K M} {A} 
+Instance finmap_singleton `{PartialAlter K M} {A}
   `{Empty (M A)} : Singleton (K * A) (M A) := λ p, <[fst p:=snd p]>∅.
 
-Definition list_to_map `{Insert K M} {A} `{Empty (M A)} (l : list (K * A)) : M A :=
-  insert_list l ∅.
+Definition list_to_map `{Insert K M} {A} `{Empty (M A)}
+  (l : list (K * A)) : M A := insert_list l ∅.
 
 Instance finmap_union `{Merge M} : UnionWith M := λ A f,
   merge (union_with f).
@@ -37,6 +61,7 @@ Instance finmap_intersection `{Merge M} : IntersectionWith M := λ A f,
 Instance finmap_difference `{Merge M} : DifferenceWith M := λ A f,
   merge (difference_with f).
 
+(** * General theorems *)
 Section finmap.
 Context `{FinMap K M} `{∀ i j : K, Decision (i = j)} {A : Type}.
 
@@ -64,12 +89,12 @@ Lemma dom_empty C `{Collection K C} : dom C (∅ : M A) ≡ ∅.
 Proof.
   split; intro.
   * rewrite (elem_of_dom C), lookup_empty. simplify_is_Some.
-  * simplify_elem_of.
+  * solve_elem_of.
 Qed.
 Lemma dom_empty_inv C `{Collection K C} (m : M A) : dom C m ≡ ∅ → m = ∅.
 Proof.
   intros E. apply finmap_empty. intros. apply (not_elem_of_dom C).
-  rewrite E. simplify_elem_of.
+  rewrite E. solve_elem_of.
 Qed.
 
 Lemma lookup_empty_not i : ¬is_Some ((∅ : M A) !! i).
@@ -198,10 +223,10 @@ Qed.
 Lemma delete_partial_alter (m : M A) i f :
   m !! i = None → delete i (partial_alter f i m) = m.
 Proof.
-  intros. unfold delete, finmap_delete. rewrite <-partial_alter_compose. 
+  intros. unfold delete, finmap_delete. rewrite <-partial_alter_compose.
   rapply partial_alter_self_alt. congruence.
 Qed.
-Lemma delete_partial_alter_dom C `{Collection K C} (m : M A) i f : 
+Lemma delete_partial_alter_dom C `{Collection K C} (m : M A) i f :
   i ∉ dom C m → delete i (partial_alter f i m) = m.
 Proof. rewrite (not_elem_of_dom C). apply delete_partial_alter. Qed.
 Lemma delete_insert (m : M A) i x : m !! i = None → delete i (<[i:=x]>m) = m.
@@ -226,6 +251,47 @@ Lemma not_elem_of_dom_delete C `{Collection K C} (m : M A) i :
   i ∉ dom C (delete i m).
 Proof. apply (not_elem_of_dom C), lookup_delete. Qed.
 
+(** * Induction principles *)
+(** We use the induction principle on finite collections to prove the
+following induction principle on finite maps. *)
+Lemma finmap_ind_alt C (P : M A → Prop) `{FinCollection K C} :
+  P ∅ →
+  (∀ i x m, i ∉ dom C m → P m → P (<[i:=x]>m)) →
+  ∀ m, P m.
+Proof.
+  intros Hemp Hinsert m.
+  apply (collection_ind (λ X, ∀ m, dom C m ≡ X → P m)) with (dom C m).
+  * solve_proper.
+  * clear m. intros m Hm. rewrite finmap_empty.
+    + easy.
+    + intros. rewrite <-(not_elem_of_dom C), Hm.
+      now solve_elem_of.
+  * clear m. intros i X Hi IH m Hdom.
+    assert (is_Some (m !! i)) as [x Hx].
+    { apply (elem_of_dom C).
+      rewrite Hdom. clear Hdom.
+      now solve_elem_of. }
+    rewrite <-(insert_delete m i x) by easy.
+    apply Hinsert.
+    { now apply (not_elem_of_dom_delete C). }
+    apply IH. apply elem_of_equiv. intros.
+    rewrite (elem_of_dom_delete C).
+    esolve_elem_of.
+  * easy.
+Qed.
+
+(** We use the [listset] implementation to prove an induction principle that
+does not mention the map's domain. *)
+Lemma finmap_ind (P : M A → Prop) :
+  P ∅ →
+  (∀ i x m, m !! i = None → P m → P (<[i:=x]>m)) →
+  ∀ m, P m.
+Proof.
+  setoid_rewrite <-(not_elem_of_dom (listset _)).
+  apply (finmap_ind_alt (listset _) P).
+Qed.
+
+(** * Deleting and inserting multiple elements *)
 Lemma lookup_delete_list (m : M A) is j :
   In j is → delete_list is m !! j = None.
 Proof.
@@ -256,30 +322,23 @@ Proof.
   intros. rewrite IHis, delete_insert_comm; tauto.
 Qed.
 
-Lemma finmap_ind C (P : M A → Prop) `{FinCollection K C} :
-  P ∅ → (∀ i x m, i ∉ dom C m → P m → P (<[i:=x]>m)) → ∀ m, P m.
+Lemma lookup_insert_list (m : M A) l1 l2 i x :
+  (∀y, ¬In (i,y) l1) → insert_list (l1 ++ (i,x) :: l2) m !! i = Some x.
 Proof.
-  intros Hemp Hinsert.
-  intros m. apply (collection_ind (λ X, ∀ m, dom C m ≡ X → P m)) with (dom C m).
-  * solve_proper.
-  * clear m. intros m Hm. rewrite finmap_empty.
-    + easy.
-    + intros. rewrite <-(not_elem_of_dom C), Hm.
-      now simplify_elem_of.
-  * clear m. intros i X Hi IH m Hdom.
-    assert (is_Some (m !! i)) as [x Hx].
-    { apply (elem_of_dom C).
-      rewrite Hdom. clear Hdom.
-      now simplify_elem_of. }
-    rewrite <-(insert_delete m i x) by easy.
-    apply Hinsert.
-    { now apply (not_elem_of_dom_delete C). }
-    apply IH. apply elem_of_equiv. intros.
-    rewrite (elem_of_dom_delete C). rewrite Hdom.
-    clear Hdom. simplify_elem_of.
+  induction l1 as [|[j y] l1 IH]; simpl.
+  * intros. now rewrite lookup_insert.
+  * intros Hy. rewrite lookup_insert_ne; naive_solver.
+Qed.
+
+Lemma lookup_insert_list_not_in (m : M A) l i :
+  (∀y, ¬In (i,y) l) → insert_list l m !! i = m !! i.
+Proof.
+  induction l as [|[j y] l IH]; simpl.
   * easy.
+  * intros Hy. rewrite lookup_insert_ne; naive_solver.
 Qed.
 
+(** * Properties of the merge operation *)
 Section merge.
   Context (f : option A → option A → option A).
 
@@ -314,22 +373,26 @@ Section merge.
   Proof. intros ???. apply merge_comm. intros. now apply (commutative f). Qed.
 
   Lemma merge_assoc m1 m2 m3 :
-    (∀ i, f (m1 !! i) (f (m2 !! i) (m3 !! i)) = f (f (m1 !! i) (m2 !! i)) (m3 !! i)) → 
+    (∀ i, f (m1 !! i) (f (m2 !! i) (m3 !! i)) =
+          f (f (m1 !! i) (m2 !! i)) (m3 !! i)) →
     merge f m1 (merge f m2 m3) = merge f (merge f m1 m2) m3.
   Proof. intros. apply finmap_eq. intros. now rewrite !(merge_spec f). Qed.
   Global Instance: Associative (=) f → Associative (=) (merge f).
   Proof. intros ????. apply merge_assoc. intros. now apply (associative f). Qed.
 End merge.
 
+(** * Properties of the union and intersection operation *)
 Section union_intersection.
   Context (f : A → A → A).
 
   Lemma finmap_union_merge m1 m2 i x y :
-    m1 !! i = Some x → m2 !! i = Some y → union_with f m1 m2 !! i = Some (f x y).
+    m1 !! i = Some x →
+    m2 !! i = Some y →
+    union_with f m1 m2 !! i = Some (f x y).
   Proof.
     intros Hx Hy. unfold union_with, finmap_union.
     now rewrite (merge_spec _), Hx, Hy.
-  Qed.   
+  Qed.
   Lemma finmap_union_l m1 m2 i x :
     m1 !! i = Some x → m2 !! i = None → union_with f m1 m2 !! i = Some x.
   Proof.
@@ -358,31 +421,15 @@ Section union_intersection.
   Global Instance:
     Idempotent (=) f → Idempotent (=) (union_with f : M A → M A → M A) := _.
 End union_intersection.
-
-Lemma lookup_insert_list (m : M A) l1 l2 i x :
-  (∀y, ¬In (i,y) l1) → insert_list (l1 ++ (i,x) :: l2) m !! i = Some x.
-Proof.
-  induction l1 as [|[j y] l1 IH]; simpl.
-   intros. now rewrite lookup_insert.
-  intros Hy. rewrite lookup_insert_ne. apply IH.
-   firstorder.
-  intro. apply (Hy y). left. congruence.
-Qed.
-
-Lemma lookup_insert_list_not_in (m : M A) l i :
-  (∀y, ¬In (i,y) l) → insert_list l m !! i = m !! i.
-Proof.
-  induction l as [|[j y] l IH]; simpl.
-   easy.
-  intros Hy. rewrite lookup_insert_ne.
-   firstorder.
-  intro. apply (Hy y). left. congruence.
-Qed.
 End finmap.
 
+(** * The finite map tactic *)
+(** The tactic [simplify_map by tac] simplifies finite map expressions
+occuring in the conclusion and assumptions. It uses [tac] to discharge generated
+inequalities. *)
 Tactic Notation "simplify_map" "by" tactic(T) := repeat
   match goal with
-  | _ => progress simplify_eqs
+  | _ => progress simplify_equality
   | H : context[ ∅ !! _ ] |- _ => rewrite lookup_empty in H
   | H : context[ (<[_:=_]>_) !! _ ] |- _ => rewrite lookup_insert in H
   | H : context[ (<[_:=_]>_) !! _ ] |- _ => rewrite lookup_insert_ne in H by T
diff --git a/theories/list.v b/theories/list.v
index 975e2078172d47b6711bf3684235de4b96707117..34dc58d6e5c19389775e0cb64bc56671ca5602b1 100644
--- a/theories/list.v
+++ b/theories/list.v
@@ -1,4 +1,8 @@
-Require Import Permutation. 
+(* Copyright (c) 2012, Robbert Krebbers. *)
+(* This file is distributed under the terms of the BSD license. *)
+(** This file collects general purpose definitions and theorems on lists that
+are not in the Coq standard library. *)
+Require Import Permutation.
 Require Export base decidable option.
 
 Arguments cons {_} _ _.
@@ -15,6 +19,8 @@ Notation "(++)" := app (only parsing) : C_scope.
 Notation "( l ++)" := (app l) (only parsing) : C_scope.
 Notation "(++ k )" := (λ l, app l k) (only parsing) : C_scope.
 
+(** * General definitions *)
+(** Looking up elements and updating elements in a list. *)
 Global Instance list_lookup: Lookup nat list :=
   fix list_lookup A (i : nat) (l : list A) {struct l} : option A :=
   match l with
@@ -26,20 +32,6 @@ Global Instance list_lookup: Lookup nat list :=
     end
   end.
 
-(* The [simpl] tactic does not unfold [list_lookup] as it is wrapped into
-a type class. Therefore we use the following tactic. Bug: does not simplify
-under binders.
-*)
-Ltac simplify_list_lookup := repeat
-  match goal with
-  | |- context f [@nil ?A !! _] => let X := (context f [@None A]) in change X
-  | |- context f [(?x :: _) !! 0] => let X := (context f [Some x]) in change X
-  | |- context f [(_ :: ?l) !! S ?i] => let X := (context f [l !! i]) in change X
-  | H : context f [@nil ?A !! _] |- _ => let X := (context f [@None A]) in change X in H
-  | H : context f [(?x :: _) !! 0] |- _ => let X := (context f [Some x]) in change X in H
-  | H : context f [(_ :: ?l) !! S ?i] |- _  => let X := (context f [l !! i]) in change X in H
-  end.
-
 Global Instance list_alter: Alter nat list :=
   fix list_alter A (f : A → A) (i : nat) (l : list A) {struct l} :=
   match l with
@@ -51,11 +43,37 @@ Global Instance list_alter: Alter nat list :=
     end
   end.
 
+(** The [simpl] tactic does not simplify [list_lookup] as it is wrapped into
+an operational type class and we cannot let it unfold on a per instance basis.
+Therefore we use the [simplify_list_lookup] tactic to perform these
+simplifications. Bug: it does not unfold under binders. *)
+Ltac simplify_list_lookup := repeat
+  match goal with
+  | |- context C [@nil ?A !! _] =>
+    let X := (context C [@None A]) in change X
+  | |- context C [(?x :: _) !! 0] =>
+    let X := (context C [Some x]) in change X
+  | |- context C [(_ :: ?l) !! S ?i] =>
+    let X := (context C [l !! i]) in change X
+  | H : context C [@nil ?A !! _] |- _ =>
+    let X := (context C [@None A]) in change X in H
+  | H : context C [(?x :: _) !! 0] |- _ =>
+    let X := (context C [Some x]) in change X in H
+  | H : context C [(_ :: ?l) !! S ?i] |- _  =>
+    let X := (context C [l !! i]) in change X in H
+  end.
+
+(** The function [option_list] converts an element of the option type into
+a list. *)
 Definition option_list {A} : option A → list A := option_rect _ (λ x, [x]) [].
+
+(** The predicate [prefix_of] holds if the first list is a prefix of the second.
+The predicate [suffix_of] holds if the first list is a suffix of the second. *)
 Definition prefix_of {A} (l1 l2 : list A) : Prop := ∃ k, l2 = l1 ++ k.
 Definition suffix_of {A} (l1 l2 : list A) : Prop := ∃ k, l2 = k ++ l1.
 
-Section list_properties.
+(** * General theorems *)
+Section general_properties.
 Context {A : Type}.
 
 Lemma list_eq (l1 l2 : list A) : (∀ i, l1 !! i = l2 !! i) → l1 = l2.
@@ -75,7 +93,7 @@ Proof. now destruct l. Qed.
 Lemma list_lookup_Some_In (l : list A) i x : l !! i = Some x → In x l.
 Proof.
   revert i. induction l; intros [|i] ?;
-    simplify_list_lookup; simplify_eqs; constructor (solve [eauto]).
+    simplify_list_lookup; simplify_equality; constructor (solve [eauto]).
 Qed.
 
 Lemma list_lookup_In_Some (l : list A) x : In x l → ∃ i, l !! i = Some x.
@@ -103,6 +121,11 @@ Lemma list_lookup_weaken (l l' : list A) i x :
   l !! i = Some x → (l ++ l') !! i = Some x.
 Proof. revert i. induction l. discriminate. now intros []. Qed.
 
+Lemma fold_right_permutation {B} (f : A → B → B) (b : B) :
+  (∀ a1 a2 b, f a1 (f a2 b) = f a2 (f a1 b)) →
+  Proper (Permutation ==> (=)) (fold_right f b).
+Proof. intro. induction 1; simpl; congruence. Qed.
+
 Lemma Forall_impl (P Q : A → Prop) l :
   Forall P l → (∀ x, P x → Q x) → Forall Q l.
 Proof. induction 1; auto. Qed.
@@ -116,8 +139,13 @@ Lemma Forall2_impl {B} (P Q : A → B → Prop) l1 l2 :
 Proof. induction 1; auto. Qed.
 
 Lemma Forall2_unique {B} (P : A → B → Prop) l k1 k2 :
-  Forall2 P l k1 → Forall2 P l k2 → (∀ x y1 y2, P x y1 → P x y2 → y1 = y2) → k1 = k2.
-Proof. intros H. revert k2. induction H; inversion_clear 1; intros; f_equal; eauto. Qed.
+  Forall2 P l k1 →
+  Forall2 P l k2 →
+  (∀ x y1 y2, P x y1 → P x y2 → y1 = y2) →
+  k1 = k2.
+Proof.
+  intros H. revert k2. induction H; inversion_clear 1; intros; f_equal; eauto.
+Qed.
 
 Lemma NoDup_singleton (x : A) : NoDup [x].
 Proof. constructor. easy. constructor. Qed.
@@ -199,6 +227,11 @@ Global Instance Exists_dec (P : A → Prop) {dec : ∀ x, Decision (P x)} :
       end
     end
   end.
+End general_properties.
+
+(** * Theorems on the prefix and suffix predicates *)
+Section prefix_postfix.
+Context {A : Type}.
 
 Global Instance: PreOrder (@prefix_of A).
 Proof.
@@ -273,10 +306,14 @@ Lemma suffix_of_cons x y (l1 l2 : list A) :
 Proof. intros ? [k E]. exists k. subst. now rewrite app_assoc. Qed.
 Lemma suffix_of_snoc_inv_1 x y (l1 l2 : list A) :
   suffix_of (l1 ++ [x]) (l2 ++ [y]) → x = y.
-Proof. rewrite suffix_prefix_rev, !rev_unit. now apply prefix_of_cons_inv_1. Qed.
+Proof.
+  rewrite suffix_prefix_rev, !rev_unit. now apply prefix_of_cons_inv_1.
+Qed.
 Lemma suffix_of_snoc_inv_2 x y (l1 l2 : list A) :
   suffix_of (l1 ++ [x]) (l2 ++ [y]) → suffix_of l1 l2.
-Proof. rewrite !suffix_prefix_rev, !rev_unit. now apply prefix_of_cons_inv_2. Qed.
+Proof.
+  rewrite !suffix_prefix_rev, !rev_unit. now apply prefix_of_cons_inv_2.
+Qed.
 
 Lemma suffix_of_cons_l (l1 l2 : list A) x :
   suffix_of (x :: l1) l2 → suffix_of l1 l2.
@@ -291,18 +328,18 @@ Lemma suffix_of_app_r (l1 l2 l3 : list A) :
   suffix_of l1 l2 → suffix_of l1 (l3 ++ l2).
 Proof. intros [k ?]. exists (l3 ++ k). subst. now rewrite app_assoc. Qed.
 
-Lemma suffix_of_cons_inv (l1 l2 : list A) x y : 
+Lemma suffix_of_cons_inv (l1 l2 : list A) x y :
   suffix_of (x :: l1) (y :: l2) → x :: l1 = y :: l2 ∨ suffix_of (x :: l1) l2.
 Proof.
   intros [[|? k] E].
    now left.
-  right. simplify_eqs. now apply suffix_of_app_r.
+  right. simplify_equality. now apply suffix_of_app_r.
 Qed.
 Lemma suffix_of_cons_not x (l : list A) : ¬suffix_of (x :: l) l.
 Proof.
   intros [k E]. change ([] ++ l = k ++ [x] ++ l) in E.
   rewrite app_assoc in E. apply app_inv_tail in E.
-  destruct k; simplify_eqs.
+  destruct k; simplify_equality.
 Qed.
 
 Global Program Instance suffix_of_dec `{∀ x y : A, Decision (x = y)} l1 l2 :
@@ -312,41 +349,54 @@ Global Program Instance suffix_of_dec `{∀ x y : A, Decision (x = y)} l1 l2 :
   | right Hpre => right _
   end.
 Next Obligation. apply suffix_prefix_rev. now rewrite !rev_alt. Qed.
-Next Obligation. 
-  intro. destruct Hpre. rewrite <-!rev_alt. 
+Next Obligation.
+  intro. destruct Hpre. rewrite <-!rev_alt.
   now apply suffix_prefix_rev.
 Qed.
-End list_properties.
-
-Hint Resolve suffix_of_nil suffix_of_cons_r suffix_of_app_r : list.
-Hint Extern 0 (prefix_of _ _) => reflexivity : list.
-Hint Extern 0 (suffix_of _ _) => reflexivity: list.
-Hint Extern 0 (PropHolds (suffix_of _ _)) => red; auto with list : typeclass_instances.
+End prefix_postfix.
 
+(** The [simplify_suffix_of] removes [suffix_of] assumptions that are
+tautologies, and simplifies [suffix_of] assumptions involving [(::)] and
+[(++)]. *)
 Ltac simplify_suffix_of := repeat
   match goal with
-  | H : suffix_of (_ :: _) _ |- _ => destruct (suffix_of_cons_not _ _ H)
-  | H : suffix_of (_ :: _) [] |- _ => destruct (suffix_of_nil_not _ _ H)
+  | H : suffix_of (_ :: _) _ |- _ =>
+    destruct (suffix_of_cons_not _ _ H)
+  | H : suffix_of (_ :: _) [] |- _ =>
+    destruct (suffix_of_nil_not _ _ H)
   | H : suffix_of (_ :: _) (_ :: _) |- _ =>
     destruct (suffix_of_cons_inv _ _ _ _ H); clear H
   | H : suffix_of ?x ?x |- _ => clear H
   | H : suffix_of ?x (_ :: ?x) |- _ => clear H
   | H : suffix_of ?x (_ ++ ?x) |- _ => clear H
-  | _ => progress simplify_eqs
+  | _ => progress simplify_equality
   end.
 
-(* Extremely dirty way to discrimate inconsistent suffix_of assumptions *)
-Ltac discriminate_suffix_of := solve [repeat
+(** The [solve_suffix_of] tries to solve goals involving [suffix_of]. It uses
+[simplify_suffix_of] to simplify assumptions, tries to solve [suffix_of]
+conclusions, and adds transitive consequences of assumptions to the context. 
+This tactic either fails or proves the goal. *)
+Ltac solve_suffix_of :=
+  let rec go :=
   match goal with
-  | _ => progress simplify_suffix_of
+  | _ => progress simplify_suffix_of; go
+  | |- suffix_of [] _ => apply suffix_of_nil
+  | |- suffix_of _ _ => reflexivity
+  | |- suffix_of _ _ => solve [auto]
+  | |- suffix_of _ (_ :: _) => apply suffix_of_cons_r; go
+  | |- suffix_of _ (_ ++ _) => apply suffix_of_app_r; go
+  | H : ¬suffix_of _ _ |- _ => destruct H; go
   | H1 : suffix_of ?x ?y, H2 : suffix_of ?y ?z |- _ =>
      match goal with
-     | _ : suffix_of x z |- _ => fail 2
+     | _ : suffix_of x z |- _ => fail 1
      | _ => assert (suffix_of x z) by (transitivity y; assumption);
-                 clear H1; clear H2 (* to avoid loops *)
+            clear H1; clear H2; go (**i clear to avoid loops *)
      end
-  end].
+  end in go.
+Hint Extern 0 (PropHolds (suffix_of _ _)) =>
+  unfold PropHolds; solve_suffix_of : typeclass_instances.
 
+(** * Monadic operations *)
 Global Instance list_ret: MRet list := λ A a, [a].
 Global Instance list_fmap: FMap list :=
   fix go A B (f : A → B) (l : list A) :=
@@ -354,7 +404,7 @@ Global Instance list_fmap: FMap list :=
   | [] => []
   | x :: l => f x :: @fmap _ go _ _ f l
   end.
-Global Instance list_join: MJoin list := 
+Global Instance list_join: MJoin list :=
   fix go A (l : list (list A)) : list A :=
   match l with
   | [] =>  []
@@ -362,11 +412,11 @@ Global Instance list_join: MJoin list :=
   end.
 Global Instance list_bind: MBind list := λ A B f l, mjoin (f <$> l).
 
-Local Arguments fmap _ _ _ _ _ !_ /.
-
 Section list_fmap.
   Context {A B : Type} (f : A → B).
 
+  Local Arguments fmap _ _ _ _ _ !_ /.
+
   Lemma fmap_length l : length (f <$> l) = length l.
   Proof. induction l; simpl; auto. Qed.
 
@@ -398,6 +448,9 @@ Lemma Forall_snd {A B} (l : list (A * B)) (P : B → Prop) :
   Forall (P ∘ snd) l ↔ Forall P (snd <$> l).
 Proof. induction l; split; inversion 1; subst; constructor; firstorder auto. Qed.
 
+(** * Indexed folds and maps *)
+(** We define stronger variants of map and fold that also take the index of the
+element into account. *)
 Definition imap_go {A B} (f : nat → A → B) : nat → list A → list B :=
   fix go (n : nat) (l : list A) :=
   match l with
@@ -406,22 +459,24 @@ Definition imap_go {A B} (f : nat → A → B) : nat → list A → list B :=
   end.
 Definition imap {A B} (f : nat → A → B) : list A → list B := imap_go f 0.
 
-Lemma fold_right_permutation `(f : A → B → B) (b : B) :
-  (∀ a1 a2 b, f a1 (f a2 b) = f a2 (f a1 b)) →
-  Proper (Permutation ==> (=)) (fold_right f b).
-Proof. intro. induction 1; simpl; congruence. Qed.
-
-Definition ifold_right {A B} (f : nat → B → A → A) (a : nat → A) : nat → list B → A :=
+Definition ifold_right {A B} (f : nat → B → A → A)
+    (a : nat → A) : nat → list B → A :=
   fix go (n : nat) (l : list B) : A :=
   match l with
   | nil => a n
   | b :: l => f n b (go (S n) l)
   end.
 
-Lemma ifold_right_app {A B} (f : nat → B → A → A) (a : nat → A) (l1 l2 : list B) n :
+Lemma ifold_right_app {A B} (f : nat → B → A → A) (a : nat → A)
+    (l1 l2 : list B) n :
   ifold_right f a n (l1 ++ l2) = ifold_right f (λ n, ifold_right f a n l2) n l1.
-Proof. revert n a. induction l1 as [| b l1 IH ]; intros; simpl; f_equal; auto. Qed.
+Proof.
+  revert n a. induction l1 as [| b l1 IH ]; intros; simpl; f_equal; auto.
+Qed.
 
+(** * Lists of the same length *)
+(** The [same_length] view allows convenient induction over two lists with the
+same length. *)
 Section same_length.
   Context {A B : Type}.
 
@@ -448,11 +503,16 @@ Section same_length.
   Qed.
 End same_length.
 
+(** * Zipping lists *)
+(** Since we prefer Haskell style naming, we rename the standard library's
+implementation [combine] into [zip] using a notation. *)
 Notation zip := combine.
 
 Section zip.
   Context {A B : Type}.
 
+  Local Arguments fmap _ _ _ _ _ !_ /.
+
   Lemma zip_fst_le (l1 : list A) (l2 : list B) :
     length l1 ≤ length l2 → fst <$> zip l1 l2 = l1.
   Proof.
diff --git a/theories/listset.v b/theories/listset.v
index 2af31ad9e77aefc90bb53bfd0ce048561662a5b6..682319f0fddbf80043c36fe0360266e204e0bd1e 100644
--- a/theories/listset.v
+++ b/theories/listset.v
@@ -1,3 +1,8 @@
+(* Copyright (c) 2012, Robbert Krebbers. *)
+(* This file is distributed under the terms of the BSD license. *)
+(** This file implements finite as unordered lists without duplicates.
+Although this implementation is slow, it is very useful as decidable equality
+is the only constraint on the carrier set. *)
 Require Export base decidable list collections.
 
 Definition listset A := sig (@NoDup A).
@@ -18,25 +23,32 @@ Fixpoint listset_difference_raw (l k : list A) :=
     then listset_difference_raw l k
     else x :: listset_difference_raw l k
   end.
-Lemma listset_difference_raw_in l k x : In x (listset_difference_raw l k) ↔ In x l ∧ ¬In x k.
-Proof. split; induction l; simpl; try case_decide; simpl; intuition congruence. Qed.
-Lemma listset_difference_raw_nodup l k : NoDup l → NoDup (listset_difference_raw l k).
-Proof. 
+Lemma listset_difference_raw_in l k x :
+  In x (listset_difference_raw l k) ↔ In x l ∧ ¬In x k.
+Proof.
+  split; induction l; simpl; try case_decide; simpl; intuition congruence.
+Qed.
+Lemma listset_difference_raw_nodup l k :
+  NoDup l → NoDup (listset_difference_raw l k).
+Proof.
   induction 1; simpl; try case_decide.
   * constructor.
   * easy.
   * constructor. rewrite listset_difference_raw_in; intuition. easy.
 Qed.
 Global Instance listset_difference: Difference (listset A) := λ l k,
-  listset_difference_raw (`l) (`k)↾listset_difference_raw_nodup (`l) (`k) (proj2_sig l).
+  listset_difference_raw (`l) (`k)↾
+    listset_difference_raw_nodup (`l) (`k) (proj2_sig l).
 
 Definition listset_union_raw (l k : list A) := listset_difference_raw l k ++ k.
-Lemma listset_union_raw_in l k x : In x (listset_union_raw l k) ↔ In x l ∨ In x k.
-Proof. 
+Lemma listset_union_raw_in l k x :
+  In x (listset_union_raw l k) ↔ In x l ∨ In x k.
+Proof.
   unfold listset_union_raw. rewrite in_app_iff, listset_difference_raw_in.
   intuition. case (decide (In x k)); intuition.
 Qed.
-Lemma listset_union_raw_nodup l k : NoDup l → NoDup k → NoDup (listset_union_raw l k).
+Lemma listset_union_raw_nodup l k :
+  NoDup l → NoDup k → NoDup (listset_union_raw l k).
 Proof.
   intros. apply NoDup_app.
   * now apply listset_difference_raw_nodup.
@@ -44,7 +56,8 @@ Proof.
   * intro. rewrite listset_difference_raw_in. intuition.
 Qed.
 Global Instance listset_union: Union (listset A) := λ l k,
-  listset_union_raw (`l) (`k)↾listset_union_raw_nodup (`l) (`k) (proj2_sig l) (proj2_sig k).
+  listset_union_raw (`l) (`k)↾
+    listset_union_raw_nodup (`l) (`k) (proj2_sig l) (proj2_sig k).
 
 Fixpoint listset_intersection_raw (l k : list A) :=
   match l with
@@ -68,14 +81,17 @@ Proof.
   * easy.
 Qed.
 Global Instance listset_intersection: Intersection (listset A) := λ l k,
-  listset_intersection_raw (`l) (`k)↾listset_intersection_raw_nodup (`l) (`k) (proj2_sig l).
+  listset_intersection_raw (`l) (`k)↾
+    listset_intersection_raw_nodup (`l) (`k) (proj2_sig l).
 
 Definition listset_add_raw x (l : list A) : list A :=
   if decide_rel In x l then l else x :: l.
 Lemma listset_add_raw_in x l y : In y (listset_add_raw x l) ↔ y = x ∨ In y l.
-Proof. unfold listset_add_raw. case (decide_rel _); firstorder congruence. Qed.
+Proof. unfold listset_add_raw. case_decide; firstorder congruence. Qed.
 Lemma listset_add_raw_nodup x l : NoDup l → NoDup (listset_add_raw x l).
-Proof. unfold listset_add_raw. case (decide_rel _); try constructor; firstorder. Qed. 
+Proof.
+  unfold listset_add_raw. case_decide; try constructor; firstorder.
+Qed.
 
 Fixpoint listset_map_raw (f : A → A) (l : list A) :=
   match l with
@@ -84,7 +100,8 @@ Fixpoint listset_map_raw (f : A → A) (l : list A) :=
   end.
 Lemma listset_map_raw_nodup f l : NoDup (listset_map_raw f l).
 Proof. induction l; simpl. constructor. now apply listset_add_raw_nodup. Qed.
-Lemma listset_map_raw_in f l x : In x (listset_map_raw f l) ↔ ∃ y, x = f y ∧ In y l.
+Lemma listset_map_raw_in f l x :
+  In x (listset_map_raw f l) ↔ ∃ y, x = f y ∧ In y l.
 Proof.
   split.
   * induction l; simpl; [easy |].
diff --git a/theories/monads.v b/theories/monads.v
deleted file mode 100644
index 62d6b392550e634e9e062688282c048289607e6c..0000000000000000000000000000000000000000
--- a/theories/monads.v
+++ /dev/null
@@ -1,20 +0,0 @@
-Require Import base.
-
-Section monad_ops.
-  Context (M : Type → Type).
-
-  Class MRet := mret: ∀ {A}, A → M A.
-  Class MBind := mbind: ∀ {A B}, (A → M B) → M A → M B.
-  Class MJoin := mjoin: ∀ {A}, M (M A) → M A.
-  Class FMap := fmap: ∀ {A B}, (A → B) → M A → M B.
-End monad_ops.
-
-Arguments mret {M MRet A} _.
-Arguments mbind {M MBind A B} _ _.
-Arguments mjoin {M MJoin A} _.
-Arguments fmap {M FMap A B} _ _.
-
-Notation "m ≫= f" := (mbind f m) (at level 60, right associativity) : C_scope.
-Notation "x ← y ; z" := (y ≫= (λ x : _, z))
-  (at level 65, next at level 35, right associativity) : C_scope.
-Infix "<$>" := fmap (at level 65, right associativity, only parsing) : C_scope.
diff --git a/theories/nmap.v b/theories/nmap.v
index 03791529e53c1baad78761c3178938ab7c0b4690..8e6fe722136c8231833bc8291b80fb460b70eeb9 100644
--- a/theories/nmap.v
+++ b/theories/nmap.v
@@ -1,3 +1,7 @@
+(* Copyright (c) 2012, Robbert Krebbers. *)
+(* This file is distributed under the terms of the BSD license. *)
+(** This files extends the implementation of finite over [positive] to finite
+maps whose keys range over Coq's data type of binary naturals [N]. *)
 Require Import pmap.
 Require Export prelude fin_maps.
 
@@ -8,8 +12,10 @@ Arguments Nmap_0 {_} _.
 Arguments Nmap_pos {_} _.
 Arguments Build_Nmap {_} _ _.
 
-Global Instance Pmap_dec `{∀ x y : A, Decision (x = y)} : ∀ x y : Nmap A, Decision (x = y).
+Global Instance Pmap_dec `{∀ x y : A, Decision (x = y)} :
+  ∀ x y : Nmap A, Decision (x = y).
 Proof. solve_decision. Defined.
+
 Global Instance Nempty {A} : Empty (Nmap A) := Build_Nmap None ∅.
 Global Instance Nlookup: Lookup N Nmap := λ A i t,
   match i with
@@ -49,7 +55,7 @@ Proof.
   * intros ??? [??] []. easy. apply lookup_fmap.
   * intros ?? ???????? [o t] n; unfold dom, lookup, Ndom, Nlookup; simpl.
     rewrite elem_of_union, Plookup_raw_dom.
-    destruct o, n; esimplify_elem_of (simplify_is_Some; eauto).
+    destruct o, n; esolve_elem_of (simplify_is_Some; eauto).
   * intros ? f ? [o1 t1] [o2 t2] [|?].
     + easy.
     + apply (merge_spec f t1 t2).
diff --git a/theories/numbers.v b/theories/numbers.v
index a3df40efe0254e10420b2ad441d17dcea64f1cea..dbf29a5b00bb81f12a1cd71395b25836674093a3 100644
--- a/theories/numbers.v
+++ b/theories/numbers.v
@@ -1,3 +1,7 @@
+(* Copyright (c) 2012, Robbert Krebbers. *)
+(* This file is distributed under the terms of the BSD license. *)
+(** This file collects some trivial facts on Coq's number data types [nat],
+[N], and [Z], and introduces some useful notations. *)
 Require Export PArith NArith ZArith.
 Require Export base decidable fin_collections.
 
@@ -24,13 +28,30 @@ Notation "(≤)" := Z.le (only parsing) : Z_scope.
 Instance Z_eq_dec: ∀ x y : Z, Decision (x = y) := Z.eq_dec.
 Instance Z_le_dec: ∀ x y : Z, Decision (x ≤ y)%Z := Z_le_dec.
 
-Definition Z_to_option_N (x : Z) :=
+(** * Conversions *)
+(** Converts an integer [x] into a natural number by giving [None] in case [x]
+is negative. *)
+Definition Z_to_option_N (x : Z) : option N :=
   match x with
   | Z0 => Some N0
   | Zpos p => Some (Npos p)
   | Zneg _ => None
   end.
 
+(** The function [Z_decide] converts a decidable proposition [P] into an integer
+by yielding one if [P] holds and zero if [P] does not. *)
+Definition Z_decide (P : Prop) {dec : Decision P} : Z :=
+  (if dec then 1 else 0)%Z.
+
+(** The function [Z_decide_rel] is the more efficient variant of [Z_decide] for
+decidable binary relations. It yields one if [R x y] and zero if not [R x y]. *)
+Definition Z_decide_rel {A B} (R : A → B → Prop)
+    {dec : ∀ x y, Decision (R x y)} (x : A) (y : B) : Z :=
+  (if dec x y then 1 else 0)%Z.
+
+(** * Fresh binary naturals *)
+(** Given a finite set of binary naturals [N], we generate a fresh element by
+taking the maximum, and adding one to it. *)
 Definition Nmax `{Elements N C} : C → N := collection_fold Nmax 0%N.
 
 Instance Nmax_proper `{FinCollection N C} : Proper ((≡) ==> (=)) Nmax.
@@ -44,8 +65,8 @@ Proof.
   change ((λ b X, x ∈ X → (x ≤ b)%N) (collection_fold N.max 0%N X) X).
   apply collection_fold_ind.
   * solve_proper.
-  * simplify_elem_of.
-  * simplify_elem_of. apply N.le_max_l. apply N.max_le_iff; auto.
+  * solve_elem_of.
+  * solve_elem_of (eauto using N.le_max_l, N.le_max_r, N.le_trans).
 Qed.
 
 Instance Nfresh `{FinCollection N C} : Fresh N C := λ l, (1 + Nmax l)%N.
diff --git a/theories/option.v b/theories/option.v
index 7b7f7c0c4eea93c7ddbd1aae7efe5ca81aee77a6..09beb718e6e3b4ee55705cf6c0c0f5388af42dbb 100644
--- a/theories/option.v
+++ b/theories/option.v
@@ -1,5 +1,11 @@
-Require Export base decidable orders.
-
+(* Copyright (c) 2012, Robbert Krebbers. *)
+(* This file is distributed under the terms of the BSD license. *)
+(** This file collects general purpose definitions and theorems on the option
+data type that are not in the Coq standard library. *)
+Require Export base tactics decidable orders.
+
+(** * General definitions and theorems *)
+(** Basic properties about equality. *)
 Lemma None_ne_Some `(a : A) : None ≠ Some a.
 Proof. congruence. Qed.
 Lemma Some_ne_None `(a : A) : Some a ≠ None.
@@ -9,36 +15,43 @@ Proof. congruence. Qed.
 Instance Some_inj {A} : Injective (=) (=) (@Some A).
 Proof. congruence. Qed.
 
-Definition option_case {A B} (f : A → B) (b : B) (x : option A) :=
+(** The non dependent elimination principle on the option type. *)
+Definition option_case {A B} (f : A → B) (b : B) (x : option A) : B :=
   match x with
   | None => b
   | Some a => f a
   end.
 
-Definition maybe {A} (a : A) (x : option A) :=
+(** The [maybe] function allows us to get the value out of the option type
+by specifying a default value. *)
+Definition maybe {A} (a : A) (x : option A) : A :=
   match x with
   | None => a
-  | Some a => a
+  | Some b => b
   end.
 
+(** An alternative, but equivalent, definition of equality on the option
+data type. This theorem is useful to prove that two options are the same. *)
 Lemma option_eq {A} (x y : option A) :
   x = y ↔ ∀ a, x = Some a ↔ y = Some a.
 Proof.
   split.
-  * intros. now subst.
-  * intros E. destruct x, y.
-    + now apply E.
-    + symmetry. now apply E.
-    + now apply E.
-    + easy.
+  { intros. now subst. }
+  intros E. destruct x, y.
+  + now apply E.
+  + symmetry. now apply E.
+  + now apply E.
+  + easy.
 Qed.
 
-Definition is_Some `(x : option A) := ∃ a, x = Some a.
+(** We define [is_Some] as a [sig] instead of a [sigT] as extraction of
+witnesses can be derived (see [is_Some_sigT] below). *)
+Definition is_Some `(x : option A) : Prop := ∃ a, x = Some a.
 Hint Extern 10 (is_Some _) => solve [eexists; eauto].
 
 Ltac simplify_is_Some := repeat intro; repeat
   match goal with
-  | _ => progress simplify_eqs
+  | _ => progress simplify_equality
   | H : is_Some _ |- _ => destruct H as [??]
   | |- is_Some _ => eauto
   end.
@@ -48,23 +61,24 @@ Proof. simplify_is_Some. Qed.
 Lemma None_not_is_Some {A} : ¬is_Some (@None A).
 Proof. simplify_is_Some. Qed.
 
-Definition is_Some_1 `(x : option A) : is_Some x → { a | x = Some a } :=
+Definition is_Some_sigT `(x : option A) : is_Some x → { a | x = Some a } :=
   match x with
   | None => False_rect _ ∘ ex_ind None_ne_Some
   | Some a => λ _, a↾eq_refl
   end.
-Lemma is_Some_2 `(x : option A) a : x = Some a → is_Some x.
+Lemma eq_Some_is_Some `(x : option A) a : x = Some a → is_Some x.
 Proof. simplify_is_Some. Qed.
 
 Lemma eq_None_not_Some `(x : option A) : x = None ↔ ¬is_Some x.
 Proof. destruct x; simpl; firstorder congruence. Qed.
 
-Lemma make_eq_Some {A} (x : option A) a : 
+Lemma make_eq_Some {A} (x : option A) a :
   is_Some x → (∀ b, x = Some b → b = a) → x = Some a.
 Proof. intros [??] H. subst. f_equal. auto. Qed.
 
-Instance option_eq_dec `{dec : ∀ x y : A, Decision (x = y)} (x y : option A) :
-    Decision (x = y) :=
+(** Equality on [option] is decidable. *)
+Instance option_eq_dec `{dec : ∀ x y : A, Decision (x = y)}
+    (x y : option A) : Decision (x = y) :=
   match x with
   | Some a =>
     match y with
@@ -82,49 +96,7 @@ Instance option_eq_dec `{dec : ∀ x y : A, Decision (x = y)} (x y : option A) :
     end
   end.
 
-Inductive option_lift `(P : A → Prop) : option A → Prop :=
-  | option_lift_some x : P x → option_lift P (Some x)
-  | option_lift_None : option_lift P None.
-
-Ltac option_lift_inv := repeat
-  match goal with
-  | H : option_lift _ (Some _) |- _ => inversion H; clear H; subst
-  | H : option_lift _ None |- _ => inversion H
-  end.
-
-Lemma option_lift_inv_Some `(P : A → Prop) x : option_lift P (Some x) → P x.
-Proof. intros. now option_lift_inv. Qed.
-
-Definition option_lift_sig `(P : A → Prop) (x : option A) :
-    option_lift P x → option (sig P) :=
-  match x with
-  | Some a => λ p, Some (exist _ a (option_lift_inv_Some P a p))
-  | None => λ _, None
-  end.
-
-Definition option_lift_dsig `(P : A → Prop) `{∀ x : A, Decision (P x)} 
-    (x : option A) : option_lift P x → option (dsig P) :=
-  match x with
-  | Some a => λ p, Some (dexist a (option_lift_inv_Some P a p))
-  | None => λ _, None
-  end.
-
-Lemma option_lift_dsig_Some `(P : A → Prop) `{∀ x : A, Decision (P x)} x y px py :
-  option_lift_dsig P x px = Some (y↾py) ↔ x = Some y.
-Proof.
-  split.
-  * destruct x; simpl; intros; now simplify_eqs.
-  * intros. subst. simpl. f_equal. now apply dsig_eq.
-Qed.
-
-Lemma option_lift_dsig_is_Some `(P : A → Prop) `{∀ x : A, Decision (P x)} x px :
-  is_Some (option_lift_dsig P x px) ↔ is_Some x.
-Proof.
-  split.
-  * intros [[??] ?]. eapply is_Some_2, option_lift_dsig_Some; eauto.
-  * intros [??]. subst. eapply is_Some_2. reflexivity.
-Qed.
-
+(** * Monadic operations *)
 Instance option_ret: MRet option := @Some.
 Instance option_bind: MBind option := λ A B f x,
   match x with
@@ -138,18 +110,6 @@ Instance option_join: MJoin option := λ A x,
   end.
 Instance option_fmap: FMap option := @option_map.
 
-Ltac simplify_options := repeat
-  match goal with
-  | _ => progress simplify_eqs
-  | H : mbind (M:=option) ?f ?o = ?x |- _ =>
-    change (option_bind _ _ f o = x) in H;
-    destruct o; simpl in H; try discriminate
-  | H : context [ ?o = _ ] |- mbind (M:=option) ?f ?o = ?x =>
-    change (option_bind _ _ f o = x);
-    erewrite H by eauto;
-    simpl
-  end.
-
 Lemma option_fmap_is_Some {A B} (f : A → B) (x : option A) :
   is_Some x ↔ is_Some (f <$> x).
 Proof. destruct x; split; intros [??]; subst; compute; eauto; discriminate. Qed.
@@ -157,6 +117,26 @@ Lemma option_fmap_is_None {A B} (f : A → B) (x : option A) :
   x = None ↔ f <$> x = None.
 Proof. unfold fmap, option_fmap. destruct x; simpl; split; congruence. Qed.
 
+Ltac simplify_option_bind := repeat
+  match goal with
+  | |- context C [mbind (M:=option) ?f None] =>
+    let X := (context C [ None ]) in change X
+  | H : context C [mbind (M:=option) ?f None] |- _ =>
+    let X := (context C [ None ]) in change X in H
+  | |- context C [mbind (M:=option) ?f (Some ?a)] =>
+    let X := (context C [ f a ]) in
+    let X' := eval simpl in X in change X'
+  | H : context C [mbind (M:=option) ?f (Some ?a)] |- _ =>
+    let X := context C [ f a ] in
+    let X' := eval simpl in X in change X' in H
+  | _ => progress simplify_equality
+  | H : mbind (M:=option) ?f ?o = ?x |- _ =>
+    destruct o eqn:?
+  | H : context [ ?o = _ ] |- mbind (M:=option) ?f ?o = ?x =>
+    erewrite H by eauto
+  end.
+
+(** * Union, intersection and difference *)
 Instance option_union: UnionWith option := λ A f x y,
   match x, y with
   | Some a, Some b => Some (f a b)
@@ -184,11 +164,36 @@ Section option_union_intersection.
   Global Instance: RightId (=) None (union_with f).
   Proof. now intros [?|]. Qed.
   Global Instance: Commutative (=) f → Commutative (=) (union_with f).
-  Proof. intros ? [?|] [?|]; compute; try reflexivity. now rewrite (commutative f). Qed.
+  Proof.
+    intros ? [?|] [?|]; compute; try reflexivity.
+    now rewrite (commutative f).
+  Qed.
   Global Instance: Associative (=) f → Associative (=) (union_with f).
-  Proof. intros ? [?|] [?|] [?|]; compute; try reflexivity. now rewrite (associative f). Qed.
+  Proof.
+    intros ? [?|] [?|] [?|]; compute; try reflexivity.
+    now rewrite (associative f).
+  Qed.
   Global Instance: Idempotent (=) f → Idempotent (=) (union_with f).
-  Proof. intros ? [?|]; compute; try reflexivity. now rewrite (idempotent f). Qed.
+  Proof.
+    intros ? [?|]; compute; try reflexivity.
+    now rewrite (idempotent f).
+  Qed.
+
+  Global Instance: Commutative (=) f → Commutative (=) (intersection_with f).
+  Proof.
+    intros ? [?|] [?|]; compute; try reflexivity.
+    now rewrite (commutative f).
+  Qed.
+  Global Instance: Associative (=) f → Associative (=) (intersection_with f).
+  Proof.
+    intros ? [?|] [?|] [?|]; compute; try reflexivity.
+    now rewrite (associative f).
+  Qed.
+  Global Instance: Idempotent (=) f → Idempotent (=) (intersection_with f).
+  Proof.
+    intros ? [?|]; compute; try reflexivity.
+    now rewrite (idempotent f).
+  Qed.
 End option_union_intersection.
 
 Section option_difference.
diff --git a/theories/orders.v b/theories/orders.v
index 9d164b9c7ffef9f3d768e1bdf933ec07dd8c7880..a763f908cf51a4743b8c16ae50386c59f2ff74ee 100644
--- a/theories/orders.v
+++ b/theories/orders.v
@@ -1,5 +1,12 @@
+(* Copyright (c) 2012, Robbert Krebbers. *)
+(* This file is distributed under the terms of the BSD license. *)
+(** This file collects common properties of pre-orders and semi lattices. This
+theory will mainly be used for the theory on collections and finite maps. *)
 Require Export base.
 
+(** * Pre-orders *)
+(** We extend a pre-order to a partial order by defining equality as
+[λ X Y, X ⊆ Y ∧ Y ⊆ X]. We prove that this indeed gives rise to a setoid. *)
 Section preorder.
   Context `{SubsetEq A} `{!PreOrder (⊆)}.
 
@@ -24,6 +31,8 @@ End preorder.
 Hint Extern 0 (@Equivalence _ (≡)) =>
   class_apply preorder_equivalence : typeclass_instances.
 
+(** * Join semi lattices *)
+(** General purpose theorems on join semi lattices. *)
 Section bounded_join_sl.
   Context `{BoundedJoinSemiLattice A}.
 
@@ -72,6 +81,8 @@ Section bounded_join_sl.
   Proof. split; eauto. Qed.
 End bounded_join_sl.
 
+(** * Meet semi lattices *)
+(** The dual of the above section, but now for meet semi lattices. *)
 Section meet_sl.
   Context `{MeetSemiLattice A}.
 
diff --git a/theories/pmap.v b/theories/pmap.v
index 65897410bc17602df70e7f86522a61a1b33e9d63..d760798ee2976581afa9bc308dabd6d92526e880 100644
--- a/theories/pmap.v
+++ b/theories/pmap.v
@@ -1,3 +1,12 @@
+(* Copyright (c) 2012, Robbert Krebbers. *)
+(* This file is distributed under the terms of the BSD license. *)
+(** This files implements an efficient implementation of finite maps whose keys
+range over Coq's data type of positive binary naturals [positive]. The
+implementation is based on Xavier Leroy's implementation of radix-2 search
+trees (uncompressed Patricia trees) and guarantees logarithmic-time operations.
+However, we extend Leroy's implementation by packing the trees into a Sigma
+type such that canonicity of representation is ensured. This is necesarry for
+Leibniz equality to become extensional. *)
 Require Import PArith.
 Require Export prelude fin_maps.
 
@@ -5,12 +14,18 @@ Local Open Scope positive_scope.
 Local Hint Extern 0 (@eq positive _ _) => congruence.
 Local Hint Extern 0 (¬@eq positive _ _) => congruence.
 
+(** Enable unfolding of the finite map operations in this file. *)
 Local Arguments lookup _ _ _ _ _ !_ /.
 Local Arguments partial_alter _ _ _ _ _ _ !_ /.
 Local Arguments fmap _ _ _ _ _ !_ /.
 Local Arguments merge _ _ _ _ !_ _ /.
 Local Arguments mbind _ _ _ _ _ !_/.
 
+(** * The tree data structure *)
+(** The data type [Pmap_raw] specifies radix-2 search trees. These trees do
+not ensure canonical representations of maps. For example the empty map can
+be represented as a binary tree of an arbitrary size that contains [None] at
+all nodes. *)
 Inductive Pmap_raw A :=
   | Pleaf: Pmap_raw A
   | Pnode: Pmap_raw A → option A → Pmap_raw A → Pmap_raw A.
@@ -21,6 +36,7 @@ Instance Pmap_raw_eq_dec `{∀ x y : A, Decision (x = y)} (x y : Pmap_raw A) :
   Decision (x = y).
 Proof. solve_decision. Defined.
 
+(** The following predicate describes non empty trees. *)
 Inductive Pmap_ne {A} : Pmap_raw A → Prop :=
   | Pmap_ne_val l x r : Pmap_ne (Pnode l (Some x) r)
   | Pmap_ne_l l r : Pmap_ne l → Pmap_ne (Pnode l None r)
@@ -36,6 +52,8 @@ Proof.
       inversion_clear 1; contradiction.
 Qed.
 
+(** The following predicate describes well well formed trees. A tree is well
+formed if it is empty or if all nodes at the bottom contain a value. *)
 Inductive Pmap_wf {A} : Pmap_raw A → Prop :=
   | Pmap_wf_leaf : Pmap_wf Pleaf
   | Pmap_wf_node l x r : Pmap_wf l → Pmap_wf r → Pmap_wf (Pnode l (Some x) r)
@@ -49,17 +67,19 @@ Proof.
   * intuition.
   * destruct IHl, IHr; try solve [left; intuition];
       right; inversion_clear 1; intuition.
-  * destruct IHl, IHr, (decide (Pmap_ne l)), (decide (Pmap_ne r)); 
+  * destruct IHl, IHr, (decide (Pmap_ne l)), (decide (Pmap_ne r));
       try solve [left; intuition]; right; inversion_clear 1; intuition.
 Qed.
 
+(** Now we restrict the data type of trees to those that are well formed. *)
 Definition Pmap A := @dsig (Pmap_raw A) Pmap_wf _.
 
+(** * Operations on the data structure *)
 Global Instance Pmap_dec `{∀ x y : A, Decision (x = y)} (t1 t2 : Pmap A) :
     Decision (t1 = t2) :=
   match Pmap_raw_eq_dec (`t1) (`t2) with
-  | left H => left (dsig_eq _ t1 t2 H)
-  | right H => right (H ∘ eq_ind _ (λ x, `t1 = `x) eq_refl _)
+  | left H => left (proj2 (dsig_eq _ t1 t2) H)
+  | right H => right (H ∘ proj1 (dsig_eq _ t1 t2))
   end.
 
 Instance Pempty_raw {A} : Empty (Pmap_raw A) := Pleaf.
@@ -152,13 +172,13 @@ Lemma Pnode_canon_wf `(l : Pmap_raw A) (o : option A) (r : Pmap_raw A) :
 Proof. intros H1 H2. destruct H1, o, H2; simpl; intuition. Qed.
 Local Hint Resolve Pnode_canon_wf.
 
-Lemma Pnode_canon_lookup_xH `(l : Pmap_raw A) (o : option A) (r : Pmap_raw A) :
+Lemma Pnode_canon_lookup_xH `(l : Pmap_raw A) o (r : Pmap_raw A) :
   Pnode_canon l o r !! 1 = o.
 Proof. now destruct l,o,r. Qed.
-Lemma Pnode_canon_lookup_xO `(l : Pmap_raw A) (o : option A) (r : Pmap_raw A) i :
+Lemma Pnode_canon_lookup_xO `(l : Pmap_raw A) o (r : Pmap_raw A) i :
   Pnode_canon l o r !! i~0 = l !! i.
 Proof. now destruct l,o,r. Qed.
-Lemma Pnode_canon_lookup_xI `(l : Pmap_raw A) (o : option A) (r : Pmap_raw A) i :
+Lemma Pnode_canon_lookup_xI `(l : Pmap_raw A) o (r : Pmap_raw A) i :
   Pnode_canon l o r !! i~1 = r !! i.
 Proof. now destruct l,o,r. Qed.
 Ltac Pnode_canon_rewrite := repeat (
@@ -222,11 +242,13 @@ Instance Pfmap_raw: FMap Pmap_raw :=
     Pnode (@fmap _ Pfmap_raw _ _ f l) (fmap f x) (@fmap _ Pfmap_raw _ _ f r)
   end.
 
-Lemma Pfmap_raw_ne `(f : A → B) (t : Pmap_raw A) : Pmap_ne t → Pmap_ne (fmap f t).
-Proof. induction 1; simpl; auto. Qed. 
+Lemma Pfmap_raw_ne `(f : A → B) (t : Pmap_raw A) :
+  Pmap_ne t → Pmap_ne (fmap f t).
+Proof. induction 1; simpl; auto. Qed.
 Local Hint Resolve Pfmap_raw_ne.
-Lemma Pfmap_raw_wf `(f : A → B) (t : Pmap_raw A) : Pmap_wf t → Pmap_wf (fmap f t).
-Proof. induction 1; simpl; intuition auto. Qed. 
+Lemma Pfmap_raw_wf `(f : A → B) (t : Pmap_raw A) :
+  Pmap_wf t → Pmap_wf (fmap f t).
+Proof. induction 1; simpl; intuition auto. Qed.
 
 Global Instance Pfmap: FMap Pmap := λ A B f t,
   dexist _ (Pfmap_raw_wf f _ (proj2_dsig t)).
@@ -235,6 +257,8 @@ Lemma Plookup_raw_fmap `(f : A → B) (t : Pmap_raw A) i :
   fmap f t !! i = fmap f (t !! i).
 Proof. revert i. induction t. easy. intros [?|?|]; simpl; auto. Qed.
 
+(** The [dom] function is rather inefficient, but since we do not intend to
+use it for computation it does not really matter to us. *)
 Section dom.
   Context `{Collection B D}.
 
@@ -249,22 +273,22 @@ Section dom.
     x ∈ Pdom_raw f t ↔ ∃ i, x = f i ∧ is_Some (t !! i).
   Proof.
     split.
-    * revert f. induction t as [|? IHl [?|] ? IHr]; esimplify_elem_of.
+    * revert f. induction t as [|? IHl [?|] ? IHr]; esolve_elem_of.
     * intros [i [? Hlookup]]; subst. revert f i Hlookup.
       induction t as [|? IHl [?|] ? IHr]; intros f [?|?|];
-        simplify_elem_of (now apply (IHl (f ∘ (~0))) 
+        solve_elem_of (now apply (IHl (f ∘ (~0)))
         || now apply (IHr (f ∘ (~1))) || simplify_is_Some).
   Qed.
 End dom.
 
-Global Instance Pdom {A} : Dom positive (Pmap A) := λ C _ _ _ t, Pdom_raw id (`t).
+Global Instance Pdom {A} : Dom positive (Pmap A) := λ C _ _ _ t,
+  Pdom_raw id (`t).
 
 Fixpoint Pmerge_aux `(f : option A → option B) (t : Pmap_raw A) : Pmap_raw B :=
   match t with
   | Pleaf => Pleaf
   | Pnode l o r => Pnode_canon (Pmerge_aux f l) (f o) (Pmerge_aux f r)
   end.
-Local Hint Constructors option_lift.
 
 Lemma Pmerge_aux_wf `(f : option A → option B) (t : Pmap_raw A) :
   Pmap_wf t → Pmap_wf (Pmerge_aux f t).
@@ -284,7 +308,8 @@ Global Instance Pmerge_raw: Merge Pmap_raw :=
   match t1, t2 with
   | Pleaf, t2 => Pmerge_aux (f None) t2
   | t1, Pleaf => Pmerge_aux (flip f None) t1
-  | Pnode l1 o1 r1, Pnode l2 o2 r2 => Pnode_canon (@merge _ Pmerge_raw _ f l1 l2)
+  | Pnode l1 o1 r1, Pnode l2 o2 r2 =>
+     Pnode_canon (@merge _ Pmerge_raw _ f l1 l2)
       (f o1 o2) (@merge _ Pmerge_raw _ f r1 r2)
   end.
 Local Arguments Pmerge_aux _ _ _ _ : simpl never.
@@ -293,7 +318,8 @@ Lemma Pmerge_wf {A} f (t1 t2 : Pmap_raw A) :
   Pmap_wf t1 → Pmap_wf t2 → Pmap_wf (merge f t1 t2).
 Proof. intros t1wf. revert t2. induction t1wf; destruct 1; simpl; auto. Qed.
 Global Instance Pmerge: Merge Pmap := λ A f t1 t2,
-  dexist (merge f (`t1) (`t2)) (Pmerge_wf _ _ _ (proj2_dsig t1) (proj2_dsig t2)).
+  dexist (merge f (`t1) (`t2))
+    (Pmerge_wf _ _ _ (proj2_dsig t1) (proj2_dsig t2)).
 
 Lemma Pmerge_raw_spec {A} f (Hf : f None None = None) (t1 t2 : Pmap_raw A) i :
   merge f t1 t2 !! i = f (t1 !! i) (t2 !! i).
diff --git a/theories/prelude.v b/theories/prelude.v
index 86fe754c144d2ec36cded163891a11364dbcd1cf..39beaa8d556a2dc5aee8b828094681bb250bbb2a 100644
--- a/theories/prelude.v
+++ b/theories/prelude.v
@@ -1,10 +1,14 @@
+(* Copyright (c) 2012, Robbert Krebbers. *)
+(* This file is distributed under the terms of the BSD license. *)
 Require Export
-  base 
+  base
+  tactics
   decidable
   orders
-  collections
-  fin_collections
   option
   list
+  collections
+  fin_collections
+  listset
   subset
-  numbers.
\ No newline at end of file
+  numbers.
diff --git a/theories/subset.v b/theories/subset.v
index 27662375b256e4a73057b7445793d55324fbe41c..00a45e9586b9e8f867a3e743db06d33fcd0af5b9 100644
--- a/theories/subset.v
+++ b/theories/subset.v
@@ -1,3 +1,7 @@
+(* Copyright (c) 2012, Robbert Krebbers. *)
+(* This file is distributed under the terms of the BSD license. *)
+(** This file implements the operations on non computable subsets [A → Prop]
+over some carrier [A]. *)
 Require Export base.
 
 Definition subset A := A → Prop.
@@ -6,7 +10,8 @@ Instance subset_elem_of {A} : ElemOf A (subset A) | 100 := λ x P, P x.
 Instance subset_empty {A} : Empty (subset A) := λ _, False.
 Instance subset_singleton {A} : Singleton A (subset A) := (=).
 Instance subset_union {A} : Union (subset A) := λ P Q x, P x ∨ Q x.
-Instance subset_intersection {A} : Intersection (subset A) := λ P Q x, P x ∧ Q x.
+Instance subset_intersection {A} : Intersection (subset A) := λ P Q x,
+  P x ∧ Q x.
 Instance subset_difference {A} : Difference (subset A) := λ P Q x, P x ∧ ¬Q x.
 Instance subset_map {A} : Map A (subset A) := λ f P x, ∃ y, f y = x ∧ P y.
 
diff --git a/theories/tactics.v b/theories/tactics.v
new file mode 100644
index 0000000000000000000000000000000000000000..ea2b9ce066648b293e5edf80d1a2fe2c66cfc75d
--- /dev/null
+++ b/theories/tactics.v
@@ -0,0 +1,171 @@
+(* Copyright (c) 2012, Robbert Krebbers. *)
+(* This file is distributed under the terms of the BSD license. *)
+(** This file collects some general purpose tactics that are used throughout
+the development. *)
+Require Export base.
+
+(** The tactic [simplify_equality] repeatedly substitutes, discriminates,
+and injects equalities, and tries to contradict impossible inequalities. *)
+Ltac simplify_equality := repeat
+  match goal with
+  | |- _ => progress subst
+  | |- _ = _ => reflexivity
+  | H : _ ≠ _ |- _ => now destruct H
+  | H : _ = _ → False |- _ => now destruct H
+  | H : _ = _ |- _ => discriminate H
+  | H : _ = _ |-  ?G =>
+    (* avoid introducing additional equalities *)
+    change (id G); injection H; clear H; intros; unfold id at 1
+  end.
+
+(** Coq's default [remember] tactic does have an option to name the generated
+equality. The following tactic extends [remember] to do so. *)
+Tactic Notation "remember" constr(t) "as" "(" ident(x) "," ident(E) ")" :=
+  remember t as x;
+  match goal with
+  | E' : x = _ |- _ => rename E' into E
+  end.
+
+(** Given a list [l], the tactic [map tac l] runs [tac x] for each element [x]
+of the list [l]. It will succeed for the first element [x] of [l] for which 
+[tac x] succeeds. *)
+Tactic Notation "map" tactic(tac) tactic(l) :=
+  let rec go l :=
+  match l with
+  | nil => idtac
+  | ?x :: ?l => tac x || go l
+  end in go l.
+
+(** Given H : [A_1 → ... → A_n → B] (where each [A_i] is non-dependent), the
+tactic [feed tac H tac_by] creates a subgoal for each [A_i] and calls [tac p]
+with the generated proof [p] of [B]. *)
+Tactic Notation "feed" tactic(tac) constr(H) :=
+  let rec go H :=
+  let T := type of H in
+  lazymatch eval hnf in T with
+  | ?T1 → ?T2 =>
+    (* Use a separate counter for fresh names to make it more likely that
+    the generated name is "fresh" with respect to those generated before
+    calling the [feed] tactic. In particular, this hack makes sure that
+    tactics like [let H' := fresh in feed (fun p => pose proof p as H') H] do
+    not break. *)
+    let HT1 := fresh "feed" in assert T1 as HT1;
+      [| go (H HT1); clear HT1 ]
+  | ?T1 => tac H
+  end in go H.
+
+(** The tactic [efeed tac H] is similar to [feed], but it also instantiates
+dependent premises of [H] with evars. *)
+Tactic Notation "efeed" tactic(tac) constr(H) :=
+  let rec go H :=
+  let T := type of H in
+  lazymatch eval hnf in T with
+  | ?T1 → ?T2 =>
+    let HT1 := fresh "feed" in assert T1 as HT1;
+      [| go (H HT1); clear HT1 ]
+  | ?T1 → _ =>
+    let e := fresh "feed" in evar (e:T1);
+    let e' := eval unfold e in e in
+    clear e; go (H e')
+  | ?T1 => tac H
+  end in go H.
+
+(** The following variants of [pose proof], [specialize], [inversion], and
+[destruct], use the [feed] tactic before invoking the actual tactic. *)
+Tactic Notation "feed" "pose" "proof" constr(H) "as" ident(H') :=
+  feed (fun p => pose proof p as H') H.
+Tactic Notation "feed" "pose" "proof" constr(H) :=
+  feed (fun p => pose proof p) H.
+
+Tactic Notation "efeed" "pose" "proof" constr(H) "as" ident(H') :=
+  efeed (fun p => pose proof p as H') H.
+Tactic Notation "efeed" "pose" "proof" constr(H) :=
+  efeed (fun p => pose proof p) H.
+
+Tactic Notation "feed" "specialize" hyp(H) :=
+  feed (fun p => specialize p) H.
+Tactic Notation "efeed" "specialize" hyp(H) :=
+  efeed (fun p => specialize p) H.
+
+Tactic Notation "feed" "inversion" constr(H) :=
+  feed (fun p => let H':=fresh in pose proof p as H'; inversion H') H.
+Tactic Notation "feed" "inversion" constr(H) "as" simple_intropattern(IP) :=
+  feed (fun p => let H':=fresh in pose proof p as H'; inversion H' as IP) H.
+
+Tactic Notation "feed" "destruct" constr(H) :=
+  feed (fun p => let H':=fresh in pose proof p as H'; destruct H') H.
+Tactic Notation "feed" "destruct" constr(H) "as" simple_intropattern(IP) :=
+  feed (fun p => let H':=fresh in pose proof p as H'; destruct H' as IP) H.
+
+(** The tactic [is_non_dependent H] determines whether the goal's conclusion or
+assumptions depend on [H]. *)
+Tactic Notation "is_non_dependent" constr(H) :=
+  match goal with
+  | _ : context [ H ] |- _ => fail 1
+  | |- context [ H ] => fail 1
+  | _ => idtac
+  end.
+
+(** Coq's [firstorder] tactic fails or loops on rather small goals already. In 
+particular, on those generated by the tactic [unfold_elem_ofs] to solve
+propositions on collections. The [naive_solver] tactic implements an ad-hoc
+and incomplete [firstorder]-like solver using Ltac's backtracking mechanism.
+The tactic suffers from the following limitations:
+- It might leave unresolved evars as Ltac provides no way to detect that.
+- To avoid the tactic going into pointless loops, it just does not allow a
+  universally quantified hypothesis to be used more than once.
+- It does not perform backtracking on instantiation of universally quantified
+  assumptions.
+
+Despite these limitations, it works much better than Coq's [firstorder] tactic
+for the purposes of this development. This tactic either fails or proves the
+goal. *)
+Tactic Notation "naive_solver" tactic(tac) :=
+  unfold iff, not in *;
+  let rec go :=
+  repeat match goal with
+  (**i intros *)
+  | |- ∀ _, _ => intro
+  (**i simplification of assumptions *)
+  | H : False |- _ => destruct H
+  | H : _ ∧ _ |- _ => destruct H
+  | H : ∃ _, _  |- _ => destruct H
+  (**i simplify and solve equalities *)
+  | |- _ => progress simpl in *
+  | |- _ => progress simplify_equality
+  (**i solve the goal *)
+  | |- _ => eassumption
+  | |- _ => now constructor
+  | |- _ => now symmetry
+  (**i operations that generate more subgoals *)
+  | |- _ ∧ _ => split
+  | H : _ ∨ _ |- _ => destruct H
+  (**i solve the goal using the user supplied tactic *)
+  | |- _ => solve [tac]
+  end;
+  (**i use recursion to enable backtracking on the following clauses *)
+  match goal with
+  (**i instantiations of assumptions *)
+  | H : _ → _ |- _ =>
+    is_non_dependent H; eapply H; clear H; go
+  | H : _ → _ |- _ =>
+    is_non_dependent H;
+    (**i create subgoals for all premises *)
+    efeed (fun p =>
+      match type of p with
+      | _ ∧ _ =>
+        let H' := fresh in pose proof p as H'; destruct H'
+      | ∃ _, _ =>
+        let H' := fresh in pose proof p as H'; destruct H'
+      | _ ∨ _ =>
+        let H' := fresh in pose proof p as H'; destruct H'
+      | False =>
+        let H' := fresh in pose proof p as H'; destruct H'
+      end) H;
+    (**i solve these subgoals, but clear [H] to avoid loops *)
+    clear H; go
+  (**i instantiation of the conclusion *)
+  | |- ∃ x, _ => eexists; go
+  | |- _ ∨ _ => first [left; go | right; go]
+  end in go.
+Tactic Notation "naive_solver" := naive_solver eauto.
diff --git a/theories/trs.v b/theories/trs.v
deleted file mode 100644
index 17f79db56e67f42a31610db1afc7230046c674af..0000000000000000000000000000000000000000
--- a/theories/trs.v
+++ /dev/null
@@ -1,141 +0,0 @@
-Require Export base.
-
-Definition red `(R : relation A) (x : A) := ∃ y, R x y.
-Definition nf `(R : relation A) (x : A) := ¬red R x.
-
-(* The reflexive transitive closure *)
-Inductive rtc `(R : relation A) : relation A :=
-  | rtc_refl x : rtc R x x
-  | rtc_l x y z : R x y → rtc R y z → rtc R x z.
-(* A reduction of exactly n steps *)
-Inductive nsteps `(R : relation A) : nat → relation A :=
-  | nsteps_O x : nsteps R 0 x x
-  | nsteps_l n x y z : R x y → nsteps R n y z → nsteps R (S n) x z.
-(* A reduction whose length is bounded by n *)
-Inductive bsteps `(R : relation A) : nat → relation A :=
-  | bsteps_refl n x : bsteps R n x x
-  | bsteps_l n x y z : R x y → bsteps R n y z → bsteps R (S n) x z.
-(* The transitive closure *)
-Inductive tc `(R : relation A) : relation A :=
-  | tc_once x y : R x y → tc R x y
-  | tc_l x y z : R x y → tc R y z → tc R x z.
-
-Hint Constructors rtc nsteps bsteps tc : trs.
-
-Arguments rtc_l {_ _ _ _ _} _ _.
-Arguments nsteps_l {_ _ _ _ _ _} _ _.
-Arguments bsteps_refl {_ _} _ _.
-Arguments bsteps_l {_ _ _ _ _ _} _ _.
-Arguments tc_once {_ _ _} _ _.
-Arguments tc_l {_ _ _ _ _} _ _.
-
-Ltac generalize_rtc H :=
-  match type of H with
-  | rtc ?R ?x ?y =>
-    let Hx := fresh in let Hy := fresh in
-    let Heqx := fresh in let Heqy := fresh in
-    remember x as (Hx,Heqx); remember y as (Hy,Heqy);
-    revert Heqx Heqy; repeat
-      match x with
-      | context [ ?z ] => revert z
-      end; repeat
-      match y with
-      | context [ ?z ] => revert z
-      end
-  end.
-
-Section rtc.
-  Context `{R : relation A}.
-
-  Global Instance: Reflexive (rtc R).
-  Proof rtc_refl R.
-  Global Instance rtc_trans: Transitive (rtc R).
-  Proof. red; induction 1; eauto with trs. Qed.
-  Lemma rtc_once {x y} : R x y → rtc R x y.
-  Proof. eauto with trs. Qed.
-  Global Instance: subrelation R (rtc R).
-  Proof. exact @rtc_once. Qed.
-  Lemma rtc_r {x y z} : rtc R x y → R y z → rtc R x z.
-  Proof. intros. etransitivity; eauto with trs. Qed.
-
-  Lemma rtc_inv {x z} : rtc R x z → x = z ∨ ∃ y, R x y ∧ rtc R y z.
-  Proof. inversion_clear 1; eauto. Qed.
-
-  Lemma rtc_ind_r (P : A → A → Prop) 
-    (Prefl : ∀ x, P x x) (Pstep : ∀ x y z, rtc R x y → R y z → P x y → P x z) :
-    ∀ y z, rtc R y z → P y z.
-  Proof.
-    cut (∀ y z, rtc R y z → ∀ x, rtc R x y → P x y → P x z).
-    { eauto using rtc_refl. }
-    induction 1; eauto using rtc_r.
-  Qed.
-
-  Lemma rtc_inv_r {x z} : rtc R x z → x = z ∨ ∃ y, rtc R x y ∧ R y z.
-  Proof. revert x z. apply rtc_ind_r; eauto. Qed.
-
-  Lemma nsteps_once {x y} : R x y → nsteps R 1 x y.
-  Proof. eauto with trs. Qed.
-  Lemma nsteps_trans {n m x y z} :
-    nsteps R n x y → nsteps R m y z → nsteps R (n + m) x z.
-  Proof. induction 1; simpl; eauto with trs. Qed.
-  Lemma nsteps_r {n x y z} : nsteps R n x y → R y z → nsteps R (S n) x z.
-  Proof. induction 1; eauto with trs. Qed.
-  Lemma nsteps_rtc {n x y} : nsteps R n x y → rtc R x y.
-  Proof. induction 1; eauto with trs. Qed.
-  Lemma rtc_nsteps {x y} : rtc R x y → ∃ n, nsteps R n x y.
-  Proof. induction 1; firstorder eauto with trs. Qed.
-
-  Lemma bsteps_once {n x y} : R x y → bsteps R (S n) x y.
-  Proof. eauto with trs. Qed.
-  Lemma bsteps_plus_r {n m x y} :
-    bsteps R n x y → bsteps R (n + m) x y.
-  Proof. induction 1; simpl; eauto with trs. Qed.
-  Lemma bsteps_weaken {n m x y} :
-    n ≤ m → bsteps R n x y → bsteps R m x y.
-  Proof.
-    intros. rewrite (Minus.le_plus_minus n m); auto using bsteps_plus_r.
-  Qed.
-  Lemma bsteps_plus_l {n m x y} :
-    bsteps R n x y → bsteps R (m + n) x y.
-  Proof. apply bsteps_weaken. auto with arith. Qed.
-  Lemma bsteps_S {n x y} :  bsteps R n x y → bsteps R (S n) x y.
-  Proof. apply bsteps_weaken. auto with arith. Qed.
-  Lemma bsteps_trans {n m x y z} :
-    bsteps R n x y → bsteps R m y z → bsteps R (n + m) x z.
-  Proof. induction 1; simpl; eauto using bsteps_plus_l with trs. Qed.
-  Lemma bsteps_r {n x y z} : bsteps R n x y → R y z → bsteps R (S n) x z.
-  Proof. induction 1; eauto with trs. Qed.
-  Lemma bsteps_rtc {n x y} : bsteps R n x y → rtc R x y.
-  Proof. induction 1; eauto with trs. Qed.
-  Lemma rtc_bsteps {x y} : rtc R x y → ∃ n, bsteps R n x y.
-  Proof. induction 1. exists 0. auto with trs. firstorder eauto with trs. Qed.
-
-  Global Instance tc_trans: Transitive (tc R).
-  Proof. red; induction 1; eauto with trs. Qed.
-  Lemma tc_r {x y z} : tc R x y → R y z → tc R x z.
-  Proof. intros. etransitivity; eauto with trs. Qed.
-  Lemma tc_rtc {x y} : tc R x y → rtc R x y.
-  Proof. induction 1; eauto with trs. Qed.
-  Global Instance: subrelation (tc R) (rtc R).
-  Proof. exact @tc_rtc. Qed.
-End rtc.
-
-Hint Resolve rtc_once rtc_r tc_r : trs.
-
-Section subrel.
-  Context {A} (R1 R2 : relation A) (Hsub : subrelation R1 R2).
-
-  Lemma red_subrel x : red R1 x → red R2 x.
-  Proof. intros [y ?]. exists y. now apply Hsub. Qed.
-  Lemma nf_subrel x : nf R2 x → nf R1 x.
-  Proof. intros H1 H2. destruct H1. now apply red_subrel. Qed.
-
-  Global Instance rtc_subrel: subrelation (rtc R1) (rtc R2).
-  Proof. induction 1; [left|eright]; eauto; now apply Hsub. Qed.
-  Global Instance nsteps_subrel: subrelation (nsteps R1 n) (nsteps R2 n).
-  Proof. induction 1; [left|eright]; eauto; now apply Hsub. Qed.
-  Global Instance bsteps_subrel: subrelation (bsteps R1 n) (bsteps R2 n).
-  Proof. induction 1; [left|eright]; eauto; now apply Hsub. Qed.
-  Global Instance tc_subrel: subrelation (tc R1) (tc R2).
-  Proof. induction 1; [left|eright]; eauto; now apply Hsub. Qed.
-End subrel.