From stdpp Require Import gmap. From stdpp Require Export relations orders. From semantics.lib Require Export sets. (** * Finite maps *) (** This file provides lemmas on finite maps (functions with a finite domain) [gmap]. The stdpp library provides a definitions and lemmas on finite maps [gmap], but states lemmas axiomatically in terms of the [FinMap] typeclass, which may make them hard to read for novice users of stdpp. We therefore instantiate the most important lemmas specifically for [gmap] to make the statements easier to comprehend. The most important operations are: - the empty map ∅ contains no elements - the singleton map {[ i := v ]} defines a singleton map that maps key i to value v - the insert operation <[ i := v ]> m inserts the association i ↦ v to the map m, overriding any mappings for i in m - the delete operatin delete i m deletes the mapping for key i from m - the lookup operation m !! i lookups a key i, and yields the optional value associated with i - the fmap operation f <$> m maps a function f over all values stored in the map - the subset relation m1 ⊆ m2 states that all associations of map m1 are also included in map m2 - the dom operation dom m yields a finite set ([gset]) of the domain of the map stdpp's maps satisfy extensional Leibniz equality -- that is, two maps X and Y are equal (X = Y) iff they represent the same finite function. *) Section map. (* keys need to be countable, i.e., have an injection into positive integers *) Context {K} {A B : Type} `{Countable K}. Implicit Types (m : gmap K A). Definition gmap := gmap. #[global] Arguments gmap _ {_ _}. Lemma lookup_empty i : (∅ : gmap K A) !! i = None. Proof. apply lookup_empty. Qed. Lemma lookup_fmap (f : A → B) (m : gmap K A) i : (f <$> m) !! i = f <$> m !! i. Proof. apply lookup_fmap. Qed. Lemma map_fmap_mono (f : A → B) m1 m2 : m1 ⊆ m2 → f <$> m1 ⊆ f <$> m2. Proof. apply map_fmap_mono. Qed. Lemma fmap_insert (f : A → B) m i x : f <$> <[i := x]> m = <[i := f x]> (f <$> m). Proof. apply fmap_insert. Qed. Lemma fmap_empty (f : A → B) : f <$> (∅ : gmap K A) = ∅. Proof. apply fmap_empty. Qed. Lemma map_fmap_compose {C} (f : A → B) (g : B → C) m : g ∘ f <$> m = g <$> (f <$> m). Proof. apply map_fmap_compose. Qed. Lemma map_fmap_ext (f1 f2 : A → B) m : (∀ i x, m !! i = Some x → f1 x = f2 x) → f1 <$> m = f2 <$> m. Proof. apply map_fmap_ext. Qed. Lemma map_eq_iff m1 m2 : m1 = m2 ↔ ∀ i, m1 !! i = m2 !! i. Proof. apply map_eq_iff. Qed. Lemma map_subseteq_spec m1 m2 : m1 ⊆ m2 ↔ ∀ i x, m1 !! i = Some x → m2 !! i = Some x. Proof. apply map_subseteq_spec. Qed. Lemma lookup_weaken m1 m2 i x : m1 !! i = Some x → m1 ⊆ m2 → m2 !! i = Some x. Proof. apply lookup_weaken. Qed. Lemma lookup_weaken_is_Some m1 m2 i : is_Some (m1 !! i) → m1 ⊆ m2 → is_Some (m2 !! i). Proof. apply lookup_weaken_is_Some. Qed. Lemma lookup_weaken_None m1 m2 i : m2 !! i = None → m1 ⊆ m2 → m1 !! i = None. Proof. apply lookup_weaken_None. Qed. Lemma lookup_weaken_inv m1 m2 i x y : m1 !! i = Some x → m1 ⊆ m2 → m2 !! i = Some y → x = y. Proof. apply lookup_weaken_inv. Qed. Lemma lookup_ne m i j : m !! i ≠ m !! j → i ≠ j. Proof. apply lookup_ne. Qed. Lemma map_empty m : m = ∅ ↔ ∀ i, m !! i = None. Proof. apply map_empty. Qed. Lemma lookup_empty_is_Some i : ¬is_Some ((∅ : gmap K A) !! i). Proof. apply lookup_empty_is_Some. Qed. Lemma lookup_empty_Some i (x : A) : ¬(∅ : gmap K A) !! i = Some x. Proof. apply lookup_empty_Some. Qed. Lemma map_empty_subseteq m : ∅ ⊆ m. Proof. apply map_empty_subseteq. Qed. Lemma lookup_delete m i : delete i m !! i = None. Proof. apply lookup_delete. Qed. Lemma lookup_delete_ne m i j : i ≠ j → delete i m !! j = m !! j. Proof. apply lookup_delete_ne. Qed. Lemma lookup_delete_Some m i j y : delete i m !! j = Some y ↔ i ≠ j ∧ m !! j = Some y. Proof. apply lookup_delete_Some. Qed. Lemma lookup_delete_is_Some m i j : is_Some (delete i m !! j) ↔ i ≠ j ∧ is_Some (m !! j). Proof. apply lookup_delete_is_Some. Qed. Lemma lookup_delete_None m i j : delete i m !! j = None ↔ i = j ∨ m !! j = None. Proof. apply lookup_delete_None. Qed. Lemma delete_empty i : delete i ∅ = (∅ : gmap K A). Proof. apply delete_empty. Qed. Lemma delete_commute m i j : delete i (delete j m) = delete j (delete i m). Proof. apply delete_commute. Qed. Lemma delete_insert_ne m i j x : i ≠ j → delete i (<[j:=x]>m) = <[j:=x]>(delete i m). Proof. apply delete_insert_ne. Qed. Lemma delete_notin m i : m !! i = None → delete i m = m. Proof. apply delete_notin. Qed. Lemma delete_idemp m i : delete i (delete i m) = delete i m. Proof. apply delete_idemp. Qed. Lemma delete_insert m i x : m !! i = None → delete i (<[i:=x]>m) = m. Proof. apply delete_insert. Qed. Lemma delete_insert_delete m i x : delete i (<[i:=x]>m) = delete i m. Proof. apply delete_insert_delete. Qed. Lemma delete_subseteq m i : delete i m ⊆ m. Proof. apply delete_subseteq. Qed. Lemma delete_mono m1 m2 i : m1 ⊆ m2 → delete i m1 ⊆ delete i m2. Proof. apply delete_mono. Qed. (** ** Properties of the [insert] operation *) Lemma lookup_insert m i x : <[i:=x]>m !! i = Some x. Proof. apply lookup_insert. Qed. Lemma lookup_insert_rev m i x y : <[i:=x]>m !! i = Some y → x = y. Proof. apply lookup_insert_rev. Qed. Lemma lookup_insert_ne m i j x : i ≠ j → <[i:=x]>m !! j = m !! j. Proof. apply lookup_insert_ne. Qed. Lemma insert_insert m i x y : <[i:=x]>(<[i:=y]>m) = <[i:=x]>m. Proof. apply insert_insert. Qed. Lemma insert_commute m i j x y : i ≠ j → <[i:=x]>(<[j:=y]>m) = <[j:=y]>(<[i:=x]>m). Proof. apply insert_commute. Qed. Lemma lookup_insert_Some m i j x y : <[i:=x]>m !! j = Some y ↔ (i = j ∧ x = y) ∨ (i ≠ j ∧ m !! j = Some y). Proof. apply lookup_insert_Some. Qed. Lemma lookup_insert_is_Some m i j x : is_Some (<[i:=x]>m !! j) ↔ i = j ∨ i ≠ j ∧ is_Some (m !! j). Proof. apply lookup_insert_is_Some. Qed. Lemma lookup_insert_None m i j x : <[i:=x]>m !! j = None ↔ m !! j = None ∧ i ≠ j. Proof. apply lookup_insert_None. Qed. Lemma insert_id m i x : m !! i = Some x → <[i:=x]>m = m. Proof. apply insert_id. Qed. Lemma insert_non_empty m i x : <[i:=x]>m ≠ ∅. Proof. apply insert_non_empty. Qed. Lemma insert_delete_insert m i x : <[i:=x]>(delete i m) = <[i:=x]> m. Proof. apply insert_delete_insert. Qed. Lemma insert_delete m i x : m !! i = Some x → <[i:=x]> (delete i m) = m. Proof. apply insert_delete. Qed. Lemma insert_subseteq m i x : m !! i = None → m ⊆ <[i:=x]>m. Proof. apply insert_subseteq. Qed. Lemma insert_mono m1 m2 i x : m1 ⊆ m2 → <[i:=x]> m1 ⊆ <[i:=x]>m2. Proof. apply insert_mono. Qed. Lemma insert_subseteq_r m1 m2 i x : m1 !! i = None → m1 ⊆ m2 → m1 ⊆ <[i:=x]>m2. Proof. apply insert_subseteq_r. Qed. Lemma insert_subseteq_l m1 m2 i x : m2 !! i = Some x → m1 ⊆ m2 → <[i:=x]> m1 ⊆ m2. Proof. apply insert_subseteq_l. Qed. Lemma insert_delete_subseteq m1 m2 i x : m1 !! i = None → <[i:=x]> m1 ⊆ m2 → m1 ⊆ delete i m2. Proof. apply insert_delete_subseteq. Qed. Lemma delete_insert_subseteq m1 m2 i x : m1 !! i = Some x → delete i m1 ⊆ m2 → m1 ⊆ <[i:=x]> m2. Proof. apply delete_insert_subseteq. Qed. Lemma map_delete_subseteq (k : K) m : delete k m ⊆ m. Proof. apply map_subseteq_spec. intros i x. rewrite lookup_delete_Some. intros [ ]; done. Qed. Lemma insert_union_singleton_l (k : K) m x : <[ k := x ]> m = {[ k := x ]} ∪ m. Proof. apply insert_union_singleton_l. Qed. Lemma insert_union_singleton_r (k : K) m x : m !! k = None → <[ k := x ]> m = m ∪ {[ k := x ]}. Proof. apply insert_union_singleton_r. Qed. Lemma lookup_union_Some_l m1 m2 (k : K) x : m1 !! k = Some x → (m1 ∪ m2) !! k = Some x. Proof. apply lookup_union_Some_l. Qed. Lemma lookup_union_r m1 m2 (k : K) : m1 !! k = None → (m1 ∪ m2) !! k = m2 !! k. Proof. apply lookup_union_r. Qed. (** map disjoint *) Definition map_disjoint := @map_disjoint K (gmap K) _ A. Lemma map_disjoint_spec m1 m2 : m1 ##ₘ m2 ↔ ∀ i x y, m1 !! i = Some x → m2 !! i = Some y → False. Proof. apply map_disjoint_spec. Qed. Lemma map_disjoint_alt m1 m2 : m1 ##ₘ m2 ↔ ∀ i, m1 !! i = None ∨ m2 !! i = None. Proof. apply map_disjoint_alt. Qed. Lemma map_not_disjoint m1 m2 : ¬m1 ##ₘ m2 ↔ ∃ i x1 x2, m1 !! i = Some x1 ∧ m2 !! i = Some x2. Proof. apply map_not_disjoint. Qed. Global Instance map_disjoint_sym : Symmetric (map_disjoint). Proof. apply map_disjoint_sym. Qed. Lemma map_disjoint_empty_l m : ∅ ##ₘ m. Proof. apply map_disjoint_empty_l. Qed. Lemma map_disjoint_empty_r m : m ##ₘ ∅. Proof. apply map_disjoint_empty_r. Qed. (** Domain *) Definition dom := @base.dom (gmap K A) (gset K) _. Lemma elem_of_dom m i : i ∈ dom m ↔ is_Some (m !! i). Proof. apply elem_of_dom. Qed. Lemma elem_of_dom_2 m i x : m !! i = Some x → i ∈ dom m. Proof. apply elem_of_dom_2. Qed. Lemma not_elem_of_dom m i : i ∉ dom m ↔ m !! i = None. Proof. apply not_elem_of_dom. Qed. Lemma subseteq_dom m1 m2 : m1 ⊆ m2 → dom m1 ⊆ dom m2. Proof. apply subseteq_dom. Qed. Lemma dom_empty : dom ∅ = ∅. Proof. apply dom_empty_L. Qed. Lemma dom_empty_iff m : dom m = ∅ ↔ m = ∅. Proof. apply dom_empty_iff_L. Qed. Lemma dom_insert m i x : dom (<[i:=x]>m) = {[ i ]} ∪ dom m. Proof. apply dom_insert_L. Qed. Lemma dom_insert_lookup m i x : is_Some (m !! i) → dom (<[i:=x]>m) = dom m. Proof. apply dom_insert_lookup_L. Qed. Lemma dom_insert_subseteq m i x : dom m ⊆ dom (<[i:=x]>m). Proof. apply dom_insert_subseteq. Qed. Lemma dom_singleton (i : K) (x : A) : dom ({[i := x]} : gmap K A) = {[ i ]}. Proof. apply dom_singleton_L. Qed. Lemma dom_delete m i : dom (delete i m) = dom m ∖ {[ i ]}. Proof. apply dom_delete_L. Qed. Lemma dom_fmap f m : dom (f <$> m) = dom m. Proof. apply dom_fmap_L. Qed. (** difference *) (* TODO: upstream? *) Lemma map_difference_mono m1 m2 m3 : m1 ⊆ m2 → m1 ∖ m3 ⊆ m2 ∖ m3. Proof. intros ?. apply map_subseteq_spec. intros i x. rewrite !lookup_difference_Some. intros [? ?]; split; [ | done]. by eapply map_subseteq_spec. Qed. (* Upstream? *) Lemma map_difference_union' m1 m2 m3 : m1 ##ₘ m2 → (m1 ∪ m2) ∖ m3 = (m1 ∖ m3) ∪ (m2 ∖ m3). Proof. intros Hdisj. apply map_eq. intros i. destruct (((m1 ∪ m2) ∖ m3) !! i) as [ s | ] eqn:Hlook. - apply lookup_difference_Some in Hlook as [Hlook1 Hlook2]. apply lookup_union_Some in Hlook1; [ | done]. symmetry. apply lookup_union_Some. { eapply map_disjoint_weaken; [ done | | ]; apply map_subseteq_difference_l; done. } destruct Hlook1 as [ Hlook1 | Hlook1]; [left | right]; apply lookup_difference_Some; done. - symmetry. apply lookup_difference_None in Hlook as [ Hlook | Hlook]. + apply lookup_union_None in Hlook as [ ? ?]. apply lookup_union_None; split; apply lookup_difference_None; eauto. + apply lookup_union_None; split; apply lookup_difference_None; eauto. Qed. (* TODO: upstream the first inclusion as a lemma? *) Lemma map_disjoint_difference m1 m2 : m1 ##ₘ m2 → m1 = m1 ∖ m2. Proof. intros Hdisj. apply (partial_order_anti_symm (R := (⊆))). - apply map_subseteq_spec. intros i x Hlook. apply lookup_difference_Some. split; [done | ]. by eapply map_disjoint_Some_l. - by apply map_subseteq_difference_l. Qed. End map. Infix "##ₘ" := map_disjoint (at level 70) : stdpp_scope. Global Hint Extern 0 (_ ##ₘ _) => symmetry; eassumption : core.