Library stdpp.fin_maps
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_eq to simplify goals involving finite maps.
From Coq Require Import Permutation.
From stdpp Require Export relations orders vector fin_sets.
From stdpp Require Import options.
Unset Default Proof Using.
From stdpp Require Export relations orders vector fin_sets.
From stdpp Require Import options.
Unset Default Proof Using.
Axiomatization of finite maps
We require Leibniz equality to be extensional on finite maps. This of course limits the space of finite map implementations, but since we are mainly interested in finite maps with numbers as indexes, we do not consider this to be a serious limitation. The main application of finite maps is to implement the memory, where extensionality of Leibniz equality is very important for a convenient use in the assertions of our axiomatic semantics.Class FinMapToList K A M := map_to_list: M → list (K × A).
Global Hint Mode FinMapToList ! - - : typeclass_instances.
Global Hint Mode FinMapToList - - ! : typeclass_instances.
The function diag_None f is used in the specification and lemmas of
merge f. It lifts a function f : option A → option B → option C by returning
None if both arguments are None, to make sure that in merge f m1 m2, the
function f can only operate on elements that are in the domain of either m1
or m2.
Definition diag_None {A B C} (f : option A → option B → option C)
(mx : option A) (my : option B) : option C :=
match mx, my with None, None ⇒ None | _, _ ⇒ f mx my end.
Class FinMap K M `{FMap M, ∀ A, Lookup K A (M A), ∀ A, Empty (M A), ∀ A,
PartialAlter K A (M A), OMap M, Merge M, ∀ A, FinMapToList K A (M A),
EqDecision K} := {
map_eq {A} (m1 m2 : M A) : (∀ i, m1 !! i = m2 !! i) → m1 = m2;
lookup_empty {A} i : (∅ : M A) !! i = None;
lookup_partial_alter {A} f (m : M A) i :
partial_alter f i m !! i = f (m !! i);
lookup_partial_alter_ne {A} f (m : M A) i j :
i ≠ j → partial_alter f i m !! j = m !! j;
lookup_fmap {A B} (f : A → B) (m : M A) i : (f <$> m) !! i = f <$> m !! i;
NoDup_map_to_list {A} (m : M A) : NoDup (map_to_list m);
elem_of_map_to_list {A} (m : M A) i x :
(i,x) ∈ map_to_list m ↔ m !! i = Some x;
lookup_omap {A B} (f : A → option B) (m : M A) i :
omap f m !! i = m !! i ≫= f;
lookup_merge {A B C} (f : option A → option B → option C) (m1 : M A) (m2 : M B) i :
merge f m1 m2 !! i = diag_None f (m1 !! i) (m2 !! i)
}.
(mx : option A) (my : option B) : option C :=
match mx, my with None, None ⇒ None | _, _ ⇒ f mx my end.
Class FinMap K M `{FMap M, ∀ A, Lookup K A (M A), ∀ A, Empty (M A), ∀ A,
PartialAlter K A (M A), OMap M, Merge M, ∀ A, FinMapToList K A (M A),
EqDecision K} := {
map_eq {A} (m1 m2 : M A) : (∀ i, m1 !! i = m2 !! i) → m1 = m2;
lookup_empty {A} i : (∅ : M A) !! i = None;
lookup_partial_alter {A} f (m : M A) i :
partial_alter f i m !! i = f (m !! i);
lookup_partial_alter_ne {A} f (m : M A) i j :
i ≠ j → partial_alter f i m !! j = m !! j;
lookup_fmap {A B} (f : A → B) (m : M A) i : (f <$> m) !! i = f <$> m !! i;
NoDup_map_to_list {A} (m : M A) : NoDup (map_to_list m);
elem_of_map_to_list {A} (m : M A) i x :
(i,x) ∈ map_to_list m ↔ m !! i = Some x;
lookup_omap {A B} (f : A → option B) (m : M A) i :
omap f m !! i = m !! i ≫= f;
lookup_merge {A B C} (f : option A → option B → option C) (m1 : M A) (m2 : M B) i :
merge f m1 m2 !! i = diag_None 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 performance loss, which justifies including them in the finite map interface as primitive operations.
Global Instance map_insert `{PartialAlter K A M} : Insert K A M :=
λ i x, partial_alter (λ _, Some x) i.
Global Instance map_alter `{PartialAlter K A M} : Alter K A M :=
λ f, partial_alter (fmap f).
Global Instance map_delete `{PartialAlter K A M} : Delete K M :=
partial_alter (λ _, None).
Global Instance map_singleton `{PartialAlter K A M, Empty M} :
SingletonM K A M := λ i x, <[i:=x]> ∅.
Definition list_to_map `{Insert K A M, Empty M} : list (K × A) → M :=
fold_right (λ p, <[p.1:=p.2]>) ∅.
Global Instance map_size `{FinMapToList K A M} : Size M := λ m,
length (map_to_list m).
Definition map_to_set `{FinMapToList K A M,
Singleton B C, Empty C, Union C} (f : K → A → B) (m : M) : C :=
list_to_set (uncurry f <$> map_to_list m).
Definition set_to_map `{Elements B C, Insert K A M, Empty M}
(f : B → K × A) (X : C) : M :=
list_to_map (f <$> elements X).
Global Instance map_union_with `{Merge M} {A} : UnionWith A (M A) :=
λ f, merge (union_with f).
Global Instance map_intersection_with `{Merge M} {A} : IntersectionWith A (M A) :=
λ f, merge (intersection_with f).
Global Instance map_difference_with `{Merge M} {A} : DifferenceWith A (M A) :=
λ f, merge (difference_with f).
λ i x, partial_alter (λ _, Some x) i.
Global Instance map_alter `{PartialAlter K A M} : Alter K A M :=
λ f, partial_alter (fmap f).
Global Instance map_delete `{PartialAlter K A M} : Delete K M :=
partial_alter (λ _, None).
Global Instance map_singleton `{PartialAlter K A M, Empty M} :
SingletonM K A M := λ i x, <[i:=x]> ∅.
Definition list_to_map `{Insert K A M, Empty M} : list (K × A) → M :=
fold_right (λ p, <[p.1:=p.2]>) ∅.
Global Instance map_size `{FinMapToList K A M} : Size M := λ m,
length (map_to_list m).
Definition map_to_set `{FinMapToList K A M,
Singleton B C, Empty C, Union C} (f : K → A → B) (m : M) : C :=
list_to_set (uncurry f <$> map_to_list m).
Definition set_to_map `{Elements B C, Insert K A M, Empty M}
(f : B → K × A) (X : C) : M :=
list_to_map (f <$> elements X).
Global Instance map_union_with `{Merge M} {A} : UnionWith A (M A) :=
λ f, merge (union_with f).
Global Instance map_intersection_with `{Merge M} {A} : IntersectionWith A (M A) :=
λ f, merge (intersection_with f).
Global Instance map_difference_with `{Merge M} {A} : DifferenceWith A (M A) :=
λ f, merge (difference_with f).
Higher precedence to make sure it's not used for other types with a Lookup
instance, such as lists.
Global Instance map_equiv `{∀ A, Lookup K A (M A), Equiv A} : Equiv (M A) | 20 :=
λ m1 m2, ∀ i, m1 !! i ≡ m2 !! i.
Definition map_Forall `{Lookup K A M} (P : K → A → Prop) : M → Prop :=
λ m, ∀ i x, m !! i = Some x → P i x.
Definition map_Exists `{Lookup K A M} (P : K → A → Prop) : M → Prop :=
λ m, ∃ i x, m !! i = Some x ∧ P i x.
Definition map_relation `{∀ A, Lookup K A (M A)} {A B} (R : A → B → Prop)
(P : A → Prop) (Q : B → Prop) (m1 : M A) (m2 : M B) : Prop := ∀ i,
option_relation R P Q (m1 !! i) (m2 !! i).
Definition map_included `{∀ A, Lookup K A (M A)} {A}
(R : relation A) : relation (M A) := map_relation R (λ _, False) (λ _, True).
Definition map_agree `{∀ A, Lookup K A (M A)} {A} : relation (M A) :=
map_relation (=) (λ _, True) (λ _, True).
Definition map_disjoint `{∀ A, Lookup K A (M A)} {A} : relation (M A) :=
map_relation (λ _ _, False) (λ _, True) (λ _, True).
Infix "##ₘ" := map_disjoint (at level 70) : stdpp_scope.
Global Hint Extern 0 (_ ##ₘ _) ⇒ symmetry; eassumption : core.
Notation "( m ##ₘ.)" := (map_disjoint m) (only parsing) : stdpp_scope.
Notation "(.##ₘ m )" := (λ m2, m2 ##ₘ m) (only parsing) : stdpp_scope.
Global Instance map_subseteq `{∀ A, Lookup K A (M A)} {A} : SubsetEq (M A) :=
map_included (=).
λ m1 m2, ∀ i, m1 !! i ≡ m2 !! i.
Definition map_Forall `{Lookup K A M} (P : K → A → Prop) : M → Prop :=
λ m, ∀ i x, m !! i = Some x → P i x.
Definition map_Exists `{Lookup K A M} (P : K → A → Prop) : M → Prop :=
λ m, ∃ i x, m !! i = Some x ∧ P i x.
Definition map_relation `{∀ A, Lookup K A (M A)} {A B} (R : A → B → Prop)
(P : A → Prop) (Q : B → Prop) (m1 : M A) (m2 : M B) : Prop := ∀ i,
option_relation R P Q (m1 !! i) (m2 !! i).
Definition map_included `{∀ A, Lookup K A (M A)} {A}
(R : relation A) : relation (M A) := map_relation R (λ _, False) (λ _, True).
Definition map_agree `{∀ A, Lookup K A (M A)} {A} : relation (M A) :=
map_relation (=) (λ _, True) (λ _, True).
Definition map_disjoint `{∀ A, Lookup K A (M A)} {A} : relation (M A) :=
map_relation (λ _ _, False) (λ _, True) (λ _, True).
Infix "##ₘ" := map_disjoint (at level 70) : stdpp_scope.
Global Hint Extern 0 (_ ##ₘ _) ⇒ symmetry; eassumption : core.
Notation "( m ##ₘ.)" := (map_disjoint m) (only parsing) : stdpp_scope.
Notation "(.##ₘ m )" := (λ m2, m2 ##ₘ m) (only parsing) : stdpp_scope.
Global Instance map_subseteq `{∀ A, Lookup K A (M A)} {A} : SubsetEq (M A) :=
map_included (=).
The union of two finite maps only has a meaningful definition for maps
that are disjoint. However, as working with partial functions is inconvenient
in Coq, we define the union as a total function. In case both finite maps
have a value at the same index, we take the value of the first map.
Global Instance map_union `{Merge M} {A} : Union (M A) := union_with (λ x _, Some x).
Global Instance map_intersection `{Merge M} {A} : Intersection (M A) :=
intersection_with (λ x _, Some x).
Global Instance map_intersection `{Merge M} {A} : Intersection (M A) :=
intersection_with (λ x _, Some x).
The difference operation removes all values from the first map whose
index contains a value in the second map as well.
A stronger variant of map that allows the mapped function to use the index
of the elements. Implemented by conversion to lists, so not very efficient.
Definition map_imap `{∀ A, Insert K A (M A), ∀ A, Empty (M A),
∀ A, FinMapToList K A (M A)} {A B} (f : K → A → option B) (m : M A) : M B :=
list_to_map (omap (λ ix, (fst ix ,.) <$> uncurry f ix) (map_to_list m)).
∀ A, FinMapToList K A (M A)} {A B} (f : K → A → option B) (m : M A) : M B :=
list_to_map (omap (λ ix, (fst ix ,.) <$> uncurry f ix) (map_to_list m)).
Given a function f : K1 → K2, the function kmap f turns a maps with
keys of type K1 into a map with keys of type K2. The function kmap f
is only well-behaved if f is injective, as otherwise it could map multiple
entries into the same entry. All lemmas about kmap f thus have the premise
Inj (=) (=) f.
Definition kmap `{∀ A, Insert K2 A (M2 A), ∀ A, Empty (M2 A),
∀ A, FinMapToList K1 A (M1 A)} {A} (f : K1 → K2) (m : M1 A) : M2 A :=
list_to_map (fmap (prod_map f id) (map_to_list m)).
Definition map_zip_with `{Merge M} {A B C} (f : A → B → C) : M A → M B → M C :=
merge (λ mx my,
match mx, my with Some x, Some y ⇒ Some (f x y) | _, _ ⇒ None end).
Notation map_zip := (map_zip_with pair).
Definition map_fold `{FinMapToList K A M} {B}
(f : K → A → B → B) (b : B) : M → B := foldr (uncurry f) b ∘ map_to_list.
Global Instance map_filter
`{FinMapToList K A M, Insert K A M, Empty M} : Filter (K × A) M :=
λ P _, map_fold (λ k v m, if decide (P (k,v)) then <[k := v]>m else m) ∅.
Fixpoint map_seq `{Insert nat A M, Empty M} (start : nat) (xs : list A) : M :=
match xs with
| [] ⇒ ∅
| x :: xs ⇒ <[start:=x]> (map_seq (S start) xs)
end.
Fixpoint map_seqZ `{Insert Z A M, Empty M} (start : Z) (xs : list A) : M :=
match xs with
| [] ⇒ ∅
| x :: xs ⇒ <[start:=x]> (map_seqZ (Z.succ start) xs)
end.
Global Instance map_lookup_total `{!Lookup K A (M A), !Inhabited A} :
LookupTotal K A (M A) | 20 := λ i m, default inhabitant (m !! i).
Typeclasses Opaque map_lookup_total.
∀ A, FinMapToList K1 A (M1 A)} {A} (f : K1 → K2) (m : M1 A) : M2 A :=
list_to_map (fmap (prod_map f id) (map_to_list m)).
Definition map_zip_with `{Merge M} {A B C} (f : A → B → C) : M A → M B → M C :=
merge (λ mx my,
match mx, my with Some x, Some y ⇒ Some (f x y) | _, _ ⇒ None end).
Notation map_zip := (map_zip_with pair).
Definition map_fold `{FinMapToList K A M} {B}
(f : K → A → B → B) (b : B) : M → B := foldr (uncurry f) b ∘ map_to_list.
Global Instance map_filter
`{FinMapToList K A M, Insert K A M, Empty M} : Filter (K × A) M :=
λ P _, map_fold (λ k v m, if decide (P (k,v)) then <[k := v]>m else m) ∅.
Fixpoint map_seq `{Insert nat A M, Empty M} (start : nat) (xs : list A) : M :=
match xs with
| [] ⇒ ∅
| x :: xs ⇒ <[start:=x]> (map_seq (S start) xs)
end.
Fixpoint map_seqZ `{Insert Z A M, Empty M} (start : Z) (xs : list A) : M :=
match xs with
| [] ⇒ ∅
| x :: xs ⇒ <[start:=x]> (map_seqZ (Z.succ start) xs)
end.
Global Instance map_lookup_total `{!Lookup K A (M A), !Inhabited A} :
LookupTotal K A (M A) | 20 := λ i m, default inhabitant (m !! i).
Typeclasses Opaque map_lookup_total.
Given a finite map m with keys K and values A, the preimage
map_preimage m gives a finite map with keys A and values being sets of K.
The type of map_preimage is very generic to support different map and set
implementations. A possible instance is MKA:=gmap K A, MASK:=gmap A (gset K),
and SK:=gset K.
Definition map_preimage `{FinMapToList K A MKA, Empty MASK,
PartialAlter A SK MASK, Empty SK, Singleton K SK, Union SK}
(m : MKA) : MASK :=
map_fold (λ i, partial_alter (λ mX, Some $ {[ i ]} ∪ default ∅ mX)) ∅ m.
Typeclasses Opaque map_preimage.
PartialAlter A SK MASK, Empty SK, Singleton K SK, Union SK}
(m : MKA) : MASK :=
map_fold (λ i, partial_alter (λ mX, Some $ {[ i ]} ∪ default ∅ mX)) ∅ m.
Typeclasses Opaque map_preimage.
Lemma map_eq_iff {A} (m1 m2 : M A) : m1 = m2 ↔ ∀ i, m1 !! i = m2 !! i.
Proof. split; [by intros ->|]. apply map_eq. Qed.
Lemma map_subseteq_spec {A} (m1 m2 : M A) :
m1 ⊆ m2 ↔ ∀ i x, m1 !! i = Some x → m2 !! i = Some x.
Proof.
unfold subseteq, map_subseteq, map_relation. split; intros Hm i;
specialize (Hm i); destruct (m1 !! i), (m2 !! i); naive_solver.
Qed.
Global Instance map_included_preorder {A} (R : relation A) :
PreOrder R → PreOrder (map_included R : relation (M A)).
Proof.
split; [intros m i; by destruct (m !! i); simpl|].
intros m1 m2 m3 Hm12 Hm23 i; specialize (Hm12 i); specialize (Hm23 i).
destruct (m1 !! i), (m2 !! i), (m3 !! i); simplify_eq/=;
done || etrans; eauto.
Qed.
Global Instance map_subseteq_po {A} : PartialOrder (⊆@{M A}).
Proof.
split; [apply _|].
intros m1 m2; rewrite !map_subseteq_spec.
intros; apply map_eq; intros i; apply option_eq; naive_solver.
Qed.
Lemma lookup_total_alt `{!Inhabited A} (m : M A) i :
m !!! i = default inhabitant (m !! i).
Proof. reflexivity. Qed.
Lemma lookup_total_correct `{!Inhabited A} (m : M A) i x :
m !! i = Some x → m !!! i = x.
Proof. rewrite lookup_total_alt. by intros →. Qed.
Lemma lookup_lookup_total `{!Inhabited A} (m : M A) i :
is_Some (m !! i) → m !! i = Some (m !!! i).
Proof. intros [x Hx]. by rewrite (lookup_total_correct m i x). Qed.
Lemma lookup_weaken {A} (m1 m2 : M A) i x :
m1 !! i = Some x → m1 ⊆ m2 → m2 !! i = Some x.
Proof. rewrite !map_subseteq_spec. auto. Qed.
Lemma lookup_weaken_is_Some {A} (m1 m2 : M A) i :
is_Some (m1 !! i) → m1 ⊆ m2 → is_Some (m2 !! i).
Proof. inversion 1. eauto using lookup_weaken. Qed.
Lemma lookup_weaken_None {A} (m1 m2 : M A) i :
m2 !! i = None → m1 ⊆ m2 → m1 !! i = None.
Proof.
rewrite map_subseteq_spec, !eq_None_not_Some.
intros Hm2 Hm [??]; destruct Hm2; eauto.
Qed.
Lemma lookup_weaken_inv {A} (m1 m2 : M A) i x y :
m1 !! i = Some x → m1 ⊆ m2 → m2 !! i = Some y → x = y.
Proof. intros Hm1 ? Hm2. eapply lookup_weaken in Hm1; eauto. congruence. Qed.
Lemma lookup_ne {A} (m : M A) i j : m !! i ≠ m !! j → i ≠ j.
Proof. congruence. Qed.
Lemma map_empty {A} (m : M A) : m = ∅ ↔ ∀ i, m !! i = None.
Proof.
split.
- intros → i. by rewrite lookup_empty.
- intros Hm. apply map_eq. intros i. by rewrite Hm, lookup_empty.
Qed.
Lemma lookup_empty_is_Some {A} i : ¬is_Some ((∅ : M A) !! i).
Proof. rewrite lookup_empty. by inversion 1. Qed.
Lemma lookup_empty_Some {A} i (x : A) : ¬(∅ : M A) !! i = Some x.
Proof. by rewrite lookup_empty. Qed.
Lemma loopup_total_empty `{!Inhabited A} i : (∅ : M A) !!! i = inhabitant.
Proof. by rewrite lookup_total_alt, lookup_empty. Qed.
Lemma map_subset_empty {A} (m : M A) : m ⊄ ∅.
Proof.
intros [_ []]. rewrite map_subseteq_spec. intros ??. by rewrite lookup_empty.
Qed.
Lemma map_empty_subseteq {A} (m : M A) : ∅ ⊆ m.
Proof. apply map_subseteq_spec. intros k v []%lookup_empty_Some. Qed.
Lemma map_subset_alt {A} (m1 m2 : M A) :
m1 ⊂ m2 ↔ m1 ⊆ m2 ∧ ∃ i, m1 !! i = None ∧ is_Some (m2 !! i).
Proof.
rewrite strict_spec_alt. split.
- intros [? Heq]; split; [done|].
destruct (decide (Exists (λ ix, m1 !! ix.1 = None) (map_to_list m2)))
as [[[i x] [?%elem_of_map_to_list ?]]%Exists_exists
|Hm%(not_Exists_Forall _)]; [eauto|].
destruct Heq; apply (anti_symm (⊆)), map_subseteq_spec; [done|intros i x Hi].
assert (is_Some (m1 !! i)) as [x' ?].
{ by apply not_eq_None_Some,
(proj1 (Forall_forall _ _) Hm (i,x)), elem_of_map_to_list. }
by rewrite <-(lookup_weaken_inv m1 m2 i x' x).
- intros [? (i&?&x&?)]; split; [done|]. congruence.
Qed.
Proof. split; [by intros ->|]. apply map_eq. Qed.
Lemma map_subseteq_spec {A} (m1 m2 : M A) :
m1 ⊆ m2 ↔ ∀ i x, m1 !! i = Some x → m2 !! i = Some x.
Proof.
unfold subseteq, map_subseteq, map_relation. split; intros Hm i;
specialize (Hm i); destruct (m1 !! i), (m2 !! i); naive_solver.
Qed.
Global Instance map_included_preorder {A} (R : relation A) :
PreOrder R → PreOrder (map_included R : relation (M A)).
Proof.
split; [intros m i; by destruct (m !! i); simpl|].
intros m1 m2 m3 Hm12 Hm23 i; specialize (Hm12 i); specialize (Hm23 i).
destruct (m1 !! i), (m2 !! i), (m3 !! i); simplify_eq/=;
done || etrans; eauto.
Qed.
Global Instance map_subseteq_po {A} : PartialOrder (⊆@{M A}).
Proof.
split; [apply _|].
intros m1 m2; rewrite !map_subseteq_spec.
intros; apply map_eq; intros i; apply option_eq; naive_solver.
Qed.
Lemma lookup_total_alt `{!Inhabited A} (m : M A) i :
m !!! i = default inhabitant (m !! i).
Proof. reflexivity. Qed.
Lemma lookup_total_correct `{!Inhabited A} (m : M A) i x :
m !! i = Some x → m !!! i = x.
Proof. rewrite lookup_total_alt. by intros →. Qed.
Lemma lookup_lookup_total `{!Inhabited A} (m : M A) i :
is_Some (m !! i) → m !! i = Some (m !!! i).
Proof. intros [x Hx]. by rewrite (lookup_total_correct m i x). Qed.
Lemma lookup_weaken {A} (m1 m2 : M A) i x :
m1 !! i = Some x → m1 ⊆ m2 → m2 !! i = Some x.
Proof. rewrite !map_subseteq_spec. auto. Qed.
Lemma lookup_weaken_is_Some {A} (m1 m2 : M A) i :
is_Some (m1 !! i) → m1 ⊆ m2 → is_Some (m2 !! i).
Proof. inversion 1. eauto using lookup_weaken. Qed.
Lemma lookup_weaken_None {A} (m1 m2 : M A) i :
m2 !! i = None → m1 ⊆ m2 → m1 !! i = None.
Proof.
rewrite map_subseteq_spec, !eq_None_not_Some.
intros Hm2 Hm [??]; destruct Hm2; eauto.
Qed.
Lemma lookup_weaken_inv {A} (m1 m2 : M A) i x y :
m1 !! i = Some x → m1 ⊆ m2 → m2 !! i = Some y → x = y.
Proof. intros Hm1 ? Hm2. eapply lookup_weaken in Hm1; eauto. congruence. Qed.
Lemma lookup_ne {A} (m : M A) i j : m !! i ≠ m !! j → i ≠ j.
Proof. congruence. Qed.
Lemma map_empty {A} (m : M A) : m = ∅ ↔ ∀ i, m !! i = None.
Proof.
split.
- intros → i. by rewrite lookup_empty.
- intros Hm. apply map_eq. intros i. by rewrite Hm, lookup_empty.
Qed.
Lemma lookup_empty_is_Some {A} i : ¬is_Some ((∅ : M A) !! i).
Proof. rewrite lookup_empty. by inversion 1. Qed.
Lemma lookup_empty_Some {A} i (x : A) : ¬(∅ : M A) !! i = Some x.
Proof. by rewrite lookup_empty. Qed.
Lemma loopup_total_empty `{!Inhabited A} i : (∅ : M A) !!! i = inhabitant.
Proof. by rewrite lookup_total_alt, lookup_empty. Qed.
Lemma map_subset_empty {A} (m : M A) : m ⊄ ∅.
Proof.
intros [_ []]. rewrite map_subseteq_spec. intros ??. by rewrite lookup_empty.
Qed.
Lemma map_empty_subseteq {A} (m : M A) : ∅ ⊆ m.
Proof. apply map_subseteq_spec. intros k v []%lookup_empty_Some. Qed.
Lemma map_subset_alt {A} (m1 m2 : M A) :
m1 ⊂ m2 ↔ m1 ⊆ m2 ∧ ∃ i, m1 !! i = None ∧ is_Some (m2 !! i).
Proof.
rewrite strict_spec_alt. split.
- intros [? Heq]; split; [done|].
destruct (decide (Exists (λ ix, m1 !! ix.1 = None) (map_to_list m2)))
as [[[i x] [?%elem_of_map_to_list ?]]%Exists_exists
|Hm%(not_Exists_Forall _)]; [eauto|].
destruct Heq; apply (anti_symm (⊆)), map_subseteq_spec; [done|intros i x Hi].
assert (is_Some (m1 !! i)) as [x' ?].
{ by apply not_eq_None_Some,
(proj1 (Forall_forall _ _) Hm (i,x)), elem_of_map_to_list. }
by rewrite <-(lookup_weaken_inv m1 m2 i x' x).
- intros [? (i&?&x&?)]; split; [done|]. congruence.
Qed.
Properties of the partial_alter operation
Lemma partial_alter_ext {A} (f g : option A → option A) (m : M A) i :
(∀ x, m !! i = x → f x = g x) → partial_alter f i m = partial_alter g i m.
Proof.
intros. apply map_eq; intros j. by destruct (decide (i = j)) as [->|?];
rewrite ?lookup_partial_alter, ?lookup_partial_alter_ne; auto.
Qed.
Lemma partial_alter_compose {A} f g (m : M A) i:
partial_alter (f ∘ g) i m = partial_alter f i (partial_alter g i m).
Proof.
intros. apply map_eq. intros ii. by destruct (decide (i = ii)) as [->|?];
rewrite ?lookup_partial_alter, ?lookup_partial_alter_ne.
Qed.
Lemma partial_alter_commute {A} f g (m : M A) i j :
i ≠ j → partial_alter f i (partial_alter g j m) =
partial_alter g j (partial_alter f i m).
Proof.
intros. apply map_eq; intros jj. destruct (decide (jj = j)) as [->|?].
{ by rewrite lookup_partial_alter_ne,
!lookup_partial_alter, lookup_partial_alter_ne. }
destruct (decide (jj = i)) as [->|?].
- by rewrite lookup_partial_alter,
!lookup_partial_alter_ne, lookup_partial_alter by congruence.
- by rewrite !lookup_partial_alter_ne by congruence.
Qed.
Lemma partial_alter_self_alt {A} (m : M A) i x :
x = m !! i → partial_alter (λ _, x) i m = m.
Proof.
intros. apply map_eq. intros ii. by destruct (decide (i = ii)) as [->|];
rewrite ?lookup_partial_alter, ?lookup_partial_alter_ne.
Qed.
Lemma partial_alter_self {A} (m : M A) i : partial_alter (λ _, m !! i) i m = m.
Proof. by apply partial_alter_self_alt. Qed.
Lemma partial_alter_subseteq {A} f (m : M A) i :
m !! i = None → m ⊆ partial_alter f i m.
Proof.
rewrite map_subseteq_spec. intros Hi j x Hj.
rewrite lookup_partial_alter_ne; congruence.
Qed.
Lemma partial_alter_subset {A} f (m : M A) i :
m !! i = None → is_Some (f (m !! i)) → m ⊂ partial_alter f i m.
Proof.
intros Hi Hfi. apply map_subset_alt; split; [by apply partial_alter_subseteq|].
∃ i. by rewrite lookup_partial_alter.
Qed.
Lemma lookup_partial_alter_Some {A} (f : option A → option A) (m : M A) i j x :
partial_alter f i m !! j = Some x ↔
(i = j ∧ f (m !! i) = Some x) ∨ (i ≠ j ∧ m !! j = Some x).
Proof.
destruct (decide (i = j)); subst.
- rewrite lookup_partial_alter. naive_solver.
- rewrite lookup_partial_alter_ne; naive_solver.
Qed.
Lemma lookup_total_partial_alter {A} `{Inhabited A}
(f : option A → option A) (m : M A) i:
partial_alter f i m !!! i = default inhabitant (f (m !! i)).
Proof. by rewrite lookup_total_alt, lookup_partial_alter. Qed.
(∀ x, m !! i = x → f x = g x) → partial_alter f i m = partial_alter g i m.
Proof.
intros. apply map_eq; intros j. by destruct (decide (i = j)) as [->|?];
rewrite ?lookup_partial_alter, ?lookup_partial_alter_ne; auto.
Qed.
Lemma partial_alter_compose {A} f g (m : M A) i:
partial_alter (f ∘ g) i m = partial_alter f i (partial_alter g i m).
Proof.
intros. apply map_eq. intros ii. by destruct (decide (i = ii)) as [->|?];
rewrite ?lookup_partial_alter, ?lookup_partial_alter_ne.
Qed.
Lemma partial_alter_commute {A} f g (m : M A) i j :
i ≠ j → partial_alter f i (partial_alter g j m) =
partial_alter g j (partial_alter f i m).
Proof.
intros. apply map_eq; intros jj. destruct (decide (jj = j)) as [->|?].
{ by rewrite lookup_partial_alter_ne,
!lookup_partial_alter, lookup_partial_alter_ne. }
destruct (decide (jj = i)) as [->|?].
- by rewrite lookup_partial_alter,
!lookup_partial_alter_ne, lookup_partial_alter by congruence.
- by rewrite !lookup_partial_alter_ne by congruence.
Qed.
Lemma partial_alter_self_alt {A} (m : M A) i x :
x = m !! i → partial_alter (λ _, x) i m = m.
Proof.
intros. apply map_eq. intros ii. by destruct (decide (i = ii)) as [->|];
rewrite ?lookup_partial_alter, ?lookup_partial_alter_ne.
Qed.
Lemma partial_alter_self {A} (m : M A) i : partial_alter (λ _, m !! i) i m = m.
Proof. by apply partial_alter_self_alt. Qed.
Lemma partial_alter_subseteq {A} f (m : M A) i :
m !! i = None → m ⊆ partial_alter f i m.
Proof.
rewrite map_subseteq_spec. intros Hi j x Hj.
rewrite lookup_partial_alter_ne; congruence.
Qed.
Lemma partial_alter_subset {A} f (m : M A) i :
m !! i = None → is_Some (f (m !! i)) → m ⊂ partial_alter f i m.
Proof.
intros Hi Hfi. apply map_subset_alt; split; [by apply partial_alter_subseteq|].
∃ i. by rewrite lookup_partial_alter.
Qed.
Lemma lookup_partial_alter_Some {A} (f : option A → option A) (m : M A) i j x :
partial_alter f i m !! j = Some x ↔
(i = j ∧ f (m !! i) = Some x) ∨ (i ≠ j ∧ m !! j = Some x).
Proof.
destruct (decide (i = j)); subst.
- rewrite lookup_partial_alter. naive_solver.
- rewrite lookup_partial_alter_ne; naive_solver.
Qed.
Lemma lookup_total_partial_alter {A} `{Inhabited A}
(f : option A → option A) (m : M A) i:
partial_alter f i m !!! i = default inhabitant (f (m !! i)).
Proof. by rewrite lookup_total_alt, lookup_partial_alter. Qed.
Properties of the alter operation
Lemma lookup_alter {A} (f : A → A) (m : M A) i : alter f i m !! i = f <$> m !! i.
Proof. unfold alter. apply lookup_partial_alter. Qed.
Lemma lookup_alter_ne {A} (f : A → A) (m : M A) i j :
i ≠ j → alter f i m !! j = m !! j.
Proof. unfold alter. apply lookup_partial_alter_ne. Qed.
Lemma alter_ext {A} (f g : A → A) (m : M A) i :
(∀ x, m !! i = Some x → f x = g x) → alter f i m = alter g i m.
Proof. intro. apply partial_alter_ext. intros [x|] ?; f_equal/=; auto. Qed.
Lemma alter_compose {A} (f g : A → A) (m : M A) i:
alter (f ∘ g) i m = alter f i (alter g i m).
Proof.
unfold alter, map_alter. rewrite <-partial_alter_compose.
apply partial_alter_ext. by intros [?|].
Qed.
Lemma alter_commute {A} (f g : A → A) (m : M A) i j :
i ≠ j → alter f i (alter g j m) = alter g j (alter f i m).
Proof. apply partial_alter_commute. Qed.
Lemma alter_insert {A} (m : M A) i f x :
alter f i (<[i := x]> m) = <[i := f x]> m.
Proof.
unfold alter, insert, map_alter, map_insert.
by rewrite <-partial_alter_compose.
Qed.
Lemma alter_insert_ne {A} (m : M A) i j f x :
i ≠ j →
alter f i (<[j := x]> m) = <[j := x]> (alter f i m).
Proof. intros. symmetry. by apply partial_alter_commute. Qed.
Lemma lookup_alter_Some {A} (f : A → A) (m : M A) i j y :
alter f i m !! j = Some y ↔
(i = j ∧ ∃ x, m !! j = Some x ∧ y = f x) ∨ (i ≠ j ∧ m !! j = Some y).
Proof.
destruct (decide (i = j)) as [->|?].
- rewrite lookup_alter. naive_solver (simplify_option_eq; eauto).
- rewrite lookup_alter_ne by done. naive_solver.
Qed.
Lemma lookup_alter_None {A} (f : A → A) (m : M A) i j :
alter f i m !! j = None ↔ m !! j = None.
Proof.
by destruct (decide (i = j)) as [->|?];
rewrite ?lookup_alter, ?fmap_None, ?lookup_alter_ne.
Qed.
Lemma lookup_alter_is_Some {A} (f : A → A) (m : M A) i j :
is_Some (alter f i m !! j) ↔ is_Some (m !! j).
Proof. by rewrite <-!not_eq_None_Some, lookup_alter_None. Qed.
Lemma alter_id {A} (f : A → A) (m : M A) i :
(∀ x, m !! i = Some x → f x = x) → alter f i m = m.
Proof.
intros Hi; apply map_eq; intros j; destruct (decide (i = j)) as [->|?].
{ rewrite lookup_alter; destruct (m !! j); f_equal/=; auto. }
by rewrite lookup_alter_ne by done.
Qed.
Lemma alter_mono {A} f (m1 m2 : M A) i : m1 ⊆ m2 → alter f i m1 ⊆ alter f i m2.
Proof.
rewrite !map_subseteq_spec. intros ? j x.
rewrite !lookup_alter_Some. naive_solver.
Qed.
Lemma alter_strict_mono {A} f (m1 m2 : M A) i :
m1 ⊂ m2 → alter f i m1 ⊂ alter f i m2.
Proof.
rewrite !map_subset_alt.
intros [? (j&?&?)]; split; auto using alter_mono.
∃ j. by rewrite lookup_alter_None, lookup_alter_is_Some.
Qed.
Proof. unfold alter. apply lookup_partial_alter. Qed.
Lemma lookup_alter_ne {A} (f : A → A) (m : M A) i j :
i ≠ j → alter f i m !! j = m !! j.
Proof. unfold alter. apply lookup_partial_alter_ne. Qed.
Lemma alter_ext {A} (f g : A → A) (m : M A) i :
(∀ x, m !! i = Some x → f x = g x) → alter f i m = alter g i m.
Proof. intro. apply partial_alter_ext. intros [x|] ?; f_equal/=; auto. Qed.
Lemma alter_compose {A} (f g : A → A) (m : M A) i:
alter (f ∘ g) i m = alter f i (alter g i m).
Proof.
unfold alter, map_alter. rewrite <-partial_alter_compose.
apply partial_alter_ext. by intros [?|].
Qed.
Lemma alter_commute {A} (f g : A → A) (m : M A) i j :
i ≠ j → alter f i (alter g j m) = alter g j (alter f i m).
Proof. apply partial_alter_commute. Qed.
Lemma alter_insert {A} (m : M A) i f x :
alter f i (<[i := x]> m) = <[i := f x]> m.
Proof.
unfold alter, insert, map_alter, map_insert.
by rewrite <-partial_alter_compose.
Qed.
Lemma alter_insert_ne {A} (m : M A) i j f x :
i ≠ j →
alter f i (<[j := x]> m) = <[j := x]> (alter f i m).
Proof. intros. symmetry. by apply partial_alter_commute. Qed.
Lemma lookup_alter_Some {A} (f : A → A) (m : M A) i j y :
alter f i m !! j = Some y ↔
(i = j ∧ ∃ x, m !! j = Some x ∧ y = f x) ∨ (i ≠ j ∧ m !! j = Some y).
Proof.
destruct (decide (i = j)) as [->|?].
- rewrite lookup_alter. naive_solver (simplify_option_eq; eauto).
- rewrite lookup_alter_ne by done. naive_solver.
Qed.
Lemma lookup_alter_None {A} (f : A → A) (m : M A) i j :
alter f i m !! j = None ↔ m !! j = None.
Proof.
by destruct (decide (i = j)) as [->|?];
rewrite ?lookup_alter, ?fmap_None, ?lookup_alter_ne.
Qed.
Lemma lookup_alter_is_Some {A} (f : A → A) (m : M A) i j :
is_Some (alter f i m !! j) ↔ is_Some (m !! j).
Proof. by rewrite <-!not_eq_None_Some, lookup_alter_None. Qed.
Lemma alter_id {A} (f : A → A) (m : M A) i :
(∀ x, m !! i = Some x → f x = x) → alter f i m = m.
Proof.
intros Hi; apply map_eq; intros j; destruct (decide (i = j)) as [->|?].
{ rewrite lookup_alter; destruct (m !! j); f_equal/=; auto. }
by rewrite lookup_alter_ne by done.
Qed.
Lemma alter_mono {A} f (m1 m2 : M A) i : m1 ⊆ m2 → alter f i m1 ⊆ alter f i m2.
Proof.
rewrite !map_subseteq_spec. intros ? j x.
rewrite !lookup_alter_Some. naive_solver.
Qed.
Lemma alter_strict_mono {A} f (m1 m2 : M A) i :
m1 ⊂ m2 → alter f i m1 ⊂ alter f i m2.
Proof.
rewrite !map_subset_alt.
intros [? (j&?&?)]; split; auto using alter_mono.
∃ j. by rewrite lookup_alter_None, lookup_alter_is_Some.
Qed.
Properties of the delete operation
Lemma lookup_delete {A} (m : M A) i : delete i m !! i = None.
Proof. apply lookup_partial_alter. Qed.
Lemma lookup_total_delete `{!Inhabited A} (m : M A) i :
delete i m !!! i = inhabitant.
Proof. by rewrite lookup_total_alt, lookup_delete. Qed.
Lemma lookup_delete_ne {A} (m : M A) i j : i ≠ j → delete i m !! j = m !! j.
Proof. apply lookup_partial_alter_ne. Qed.
Lemma lookup_total_delete_ne `{!Inhabited A} (m : M A) i j :
i ≠ j → delete i m !!! j = m !!! j.
Proof. intros. by rewrite lookup_total_alt, lookup_delete_ne. Qed.
Lemma lookup_delete_Some {A} (m : M A) i j y :
delete i m !! j = Some y ↔ i ≠ j ∧ m !! j = Some y.
Proof.
split.
- destruct (decide (i = j)) as [->|?];
rewrite ?lookup_delete, ?lookup_delete_ne; intuition congruence.
- intros [??]. by rewrite lookup_delete_ne.
Qed.
Lemma lookup_delete_is_Some {A} (m : M A) i j :
is_Some (delete i m !! j) ↔ i ≠ j ∧ is_Some (m !! j).
Proof. unfold is_Some; setoid_rewrite lookup_delete_Some; naive_solver. Qed.
Lemma lookup_delete_None {A} (m : M A) i j :
delete i m !! j = None ↔ i = j ∨ m !! j = None.
Proof.
destruct (decide (i = j)) as [->|?];
rewrite ?lookup_delete, ?lookup_delete_ne; tauto.
Qed.
Lemma delete_empty {A} i : delete i ∅ =@{M A} ∅.
Proof. rewrite <-(partial_alter_self ∅) at 2. by rewrite lookup_empty. Qed.
Lemma delete_commute {A} (m : M A) i j :
delete i (delete j m) = delete j (delete i m).
Proof.
destruct (decide (i = j)) as [->|]; [done|]. by apply partial_alter_commute.
Qed.
Lemma delete_notin {A} (m : M A) i : m !! i = None → delete i m = m.
Proof.
intros. apply map_eq. intros j. by destruct (decide (i = j)) as [->|?];
rewrite ?lookup_delete, ?lookup_delete_ne.
Qed.
Lemma delete_idemp {A} (m : M A) i :
delete i (delete i m) = delete i m.
Proof. by setoid_rewrite <-partial_alter_compose. Qed.
Lemma delete_partial_alter {A} (m : M A) i f :
m !! i = None → delete i (partial_alter f i m) = m.
Proof.
intros. unfold delete, map_delete. rewrite <-partial_alter_compose.
unfold compose. by apply partial_alter_self_alt.
Qed.
Lemma delete_insert {A} (m : M A) i x :
m !! i = None → delete i (<[i:=x]>m) = m.
Proof. apply delete_partial_alter. Qed.
Lemma delete_insert_delete {A} (m : M A) i x :
delete i (<[i:=x]>m) = delete i m.
Proof. by setoid_rewrite <-partial_alter_compose. Qed.
Lemma delete_insert_ne {A} (m : M A) i j x :
i ≠ j → delete i (<[j:=x]>m) = <[j:=x]>(delete i m).
Proof. intro. by apply partial_alter_commute. Qed.
Lemma delete_alter {A} (m : M A) i f :
delete i (alter f i m) = delete i m.
Proof.
unfold delete, alter, map_delete, map_alter.
by rewrite <-partial_alter_compose.
Qed.
Lemma delete_alter_ne {A} (m : M A) i j f :
i ≠ j → delete i (alter f j m) = alter f j (delete i m).
Proof. intro. by apply partial_alter_commute. Qed.
Lemma delete_subseteq {A} (m : M A) i : delete i m ⊆ m.
Proof.
rewrite !map_subseteq_spec. intros j x. rewrite lookup_delete_Some. tauto.
Qed.
Lemma delete_subset {A} (m : M A) i : is_Some (m !! i) → delete i m ⊂ m.
Proof.
intros [x ?]; apply map_subset_alt; split; [apply delete_subseteq|].
∃ i. rewrite lookup_delete; eauto.
Qed.
Lemma delete_mono {A} (m1 m2 : M A) i : m1 ⊆ m2 → delete i m1 ⊆ delete i m2.
Proof.
rewrite !map_subseteq_spec. intros ? j x.
rewrite !lookup_delete_Some. intuition eauto.
Qed.
Proof. apply lookup_partial_alter. Qed.
Lemma lookup_total_delete `{!Inhabited A} (m : M A) i :
delete i m !!! i = inhabitant.
Proof. by rewrite lookup_total_alt, lookup_delete. Qed.
Lemma lookup_delete_ne {A} (m : M A) i j : i ≠ j → delete i m !! j = m !! j.
Proof. apply lookup_partial_alter_ne. Qed.
Lemma lookup_total_delete_ne `{!Inhabited A} (m : M A) i j :
i ≠ j → delete i m !!! j = m !!! j.
Proof. intros. by rewrite lookup_total_alt, lookup_delete_ne. Qed.
Lemma lookup_delete_Some {A} (m : M A) i j y :
delete i m !! j = Some y ↔ i ≠ j ∧ m !! j = Some y.
Proof.
split.
- destruct (decide (i = j)) as [->|?];
rewrite ?lookup_delete, ?lookup_delete_ne; intuition congruence.
- intros [??]. by rewrite lookup_delete_ne.
Qed.
Lemma lookup_delete_is_Some {A} (m : M A) i j :
is_Some (delete i m !! j) ↔ i ≠ j ∧ is_Some (m !! j).
Proof. unfold is_Some; setoid_rewrite lookup_delete_Some; naive_solver. Qed.
Lemma lookup_delete_None {A} (m : M A) i j :
delete i m !! j = None ↔ i = j ∨ m !! j = None.
Proof.
destruct (decide (i = j)) as [->|?];
rewrite ?lookup_delete, ?lookup_delete_ne; tauto.
Qed.
Lemma delete_empty {A} i : delete i ∅ =@{M A} ∅.
Proof. rewrite <-(partial_alter_self ∅) at 2. by rewrite lookup_empty. Qed.
Lemma delete_commute {A} (m : M A) i j :
delete i (delete j m) = delete j (delete i m).
Proof.
destruct (decide (i = j)) as [->|]; [done|]. by apply partial_alter_commute.
Qed.
Lemma delete_notin {A} (m : M A) i : m !! i = None → delete i m = m.
Proof.
intros. apply map_eq. intros j. by destruct (decide (i = j)) as [->|?];
rewrite ?lookup_delete, ?lookup_delete_ne.
Qed.
Lemma delete_idemp {A} (m : M A) i :
delete i (delete i m) = delete i m.
Proof. by setoid_rewrite <-partial_alter_compose. Qed.
Lemma delete_partial_alter {A} (m : M A) i f :
m !! i = None → delete i (partial_alter f i m) = m.
Proof.
intros. unfold delete, map_delete. rewrite <-partial_alter_compose.
unfold compose. by apply partial_alter_self_alt.
Qed.
Lemma delete_insert {A} (m : M A) i x :
m !! i = None → delete i (<[i:=x]>m) = m.
Proof. apply delete_partial_alter. Qed.
Lemma delete_insert_delete {A} (m : M A) i x :
delete i (<[i:=x]>m) = delete i m.
Proof. by setoid_rewrite <-partial_alter_compose. Qed.
Lemma delete_insert_ne {A} (m : M A) i j x :
i ≠ j → delete i (<[j:=x]>m) = <[j:=x]>(delete i m).
Proof. intro. by apply partial_alter_commute. Qed.
Lemma delete_alter {A} (m : M A) i f :
delete i (alter f i m) = delete i m.
Proof.
unfold delete, alter, map_delete, map_alter.
by rewrite <-partial_alter_compose.
Qed.
Lemma delete_alter_ne {A} (m : M A) i j f :
i ≠ j → delete i (alter f j m) = alter f j (delete i m).
Proof. intro. by apply partial_alter_commute. Qed.
Lemma delete_subseteq {A} (m : M A) i : delete i m ⊆ m.
Proof.
rewrite !map_subseteq_spec. intros j x. rewrite lookup_delete_Some. tauto.
Qed.
Lemma delete_subset {A} (m : M A) i : is_Some (m !! i) → delete i m ⊂ m.
Proof.
intros [x ?]; apply map_subset_alt; split; [apply delete_subseteq|].
∃ i. rewrite lookup_delete; eauto.
Qed.
Lemma delete_mono {A} (m1 m2 : M A) i : m1 ⊆ m2 → delete i m1 ⊆ delete i m2.
Proof.
rewrite !map_subseteq_spec. intros ? j x.
rewrite !lookup_delete_Some. intuition eauto.
Qed.
Properties of the insert operation
Lemma lookup_insert {A} (m : M A) i x : <[i:=x]>m !! i = Some x.
Proof. unfold insert. apply lookup_partial_alter. Qed.
Lemma lookup_total_insert `{!Inhabited A} (m : M A) i x : <[i:=x]>m !!! i = x.
Proof. by rewrite lookup_total_alt, lookup_insert. Qed.
Lemma lookup_insert_rev {A} (m : M A) i x y : <[i:=x]>m !! i = Some y → x = y.
Proof. rewrite lookup_insert. congruence. Qed.
Lemma lookup_insert_ne {A} (m : M A) i j x : i ≠ j → <[i:=x]>m !! j = m !! j.
Proof. unfold insert. apply lookup_partial_alter_ne. Qed.
Lemma lookup_total_insert_ne `{!Inhabited A} (m : M A) i j x :
i ≠ j → <[i:=x]>m !!! j = m !!! j.
Proof. intros. by rewrite lookup_total_alt, lookup_insert_ne. Qed.
Lemma insert_insert {A} (m : M A) i x y : <[i:=x]>(<[i:=y]>m) = <[i:=x]>m.
Proof. unfold insert, map_insert. by rewrite <-partial_alter_compose. Qed.
Lemma insert_commute {A} (m : M A) i j x y :
i ≠ j → <[i:=x]>(<[j:=y]>m) = <[j:=y]>(<[i:=x]>m).
Proof. apply partial_alter_commute. Qed.
Lemma lookup_insert_Some {A} (m : M A) i j x y :
<[i:=x]>m !! j = Some y ↔ (i = j ∧ x = y) ∨ (i ≠ j ∧ m !! j = Some y).
Proof.
split.
- destruct (decide (i = j)) as [->|?];
rewrite ?lookup_insert, ?lookup_insert_ne; intuition congruence.
- intros [[-> ->]|[??]]; [apply lookup_insert|]. by rewrite lookup_insert_ne.
Qed.
Lemma lookup_insert_is_Some {A} (m : M A) i j x :
is_Some (<[i:=x]>m !! j) ↔ i = j ∨ i ≠ j ∧ is_Some (m !! j).
Proof. unfold is_Some; setoid_rewrite lookup_insert_Some; naive_solver. Qed.
Lemma lookup_insert_is_Some' {A} (m : M A) i j x :
is_Some (<[i:=x]>m !! j) ↔ i = j ∨ is_Some (m !! j).
Proof. rewrite lookup_insert_is_Some. destruct (decide (i=j)); naive_solver. Qed.
Lemma lookup_insert_None {A} (m : M A) i j x :
<[i:=x]>m !! j = None ↔ m !! j = None ∧ i ≠ j.
Proof.
split; [|by intros [??]; rewrite lookup_insert_ne].
destruct (decide (i = j)) as [->|];
rewrite ?lookup_insert, ?lookup_insert_ne; intuition congruence.
Qed.
Lemma insert_id {A} (m : M A) i x : m !! i = Some x → <[i:=x]>m = m.
Proof.
intros; apply map_eq; intros j; destruct (decide (i = j)) as [->|];
by rewrite ?lookup_insert, ?lookup_insert_ne by done.
Qed.
Lemma insert_included {A} R `{!Reflexive R} (m : M A) i x :
(∀ y, m !! i = Some y → R y x) → map_included R m (<[i:=x]>m).
Proof.
intros ? j; destruct (decide (i = j)) as [->|].
- rewrite lookup_insert. destruct (m !! j); simpl; eauto.
- rewrite lookup_insert_ne by done. by destruct (m !! j); simpl.
Qed.
Lemma insert_empty {A} i (x : A) : <[i:=x]> ∅ =@{M A} {[i := x]}.
Proof. done. Qed.
Lemma insert_non_empty {A} (m : M A) i x : <[i:=x]>m ≠ ∅.
Proof.
intros Hi%(f_equal (.!! i)). by rewrite lookup_insert, lookup_empty in Hi.
Qed.
Lemma insert_delete_insert {A} (m : M A) i x : <[i:=x]>(delete i m) = <[i:=x]> m.
Proof. symmetry; apply (partial_alter_compose (λ _, Some x)). Qed.
Lemma insert_delete {A} (m : M A) i x :
m !! i = Some x → <[i:=x]> (delete i m) = m.
Proof. intros. rewrite insert_delete_insert, insert_id; done. Qed.
Lemma insert_subseteq {A} (m : M A) i x : m !! i = None → m ⊆ <[i:=x]>m.
Proof. apply partial_alter_subseteq. Qed.
Lemma insert_subset {A} (m : M A) i x : m !! i = None → m ⊂ <[i:=x]>m.
Proof. intro. apply partial_alter_subset; eauto. Qed.
Lemma insert_mono {A} (m1 m2 : M A) i x : m1 ⊆ m2 → <[i:=x]> m1 ⊆ <[i:=x]>m2.
Proof.
rewrite !map_subseteq_spec.
intros Hm j y. rewrite !lookup_insert_Some. naive_solver.
Qed.
Lemma insert_subseteq_r {A} (m1 m2 : M A) i x :
m1 !! i = None → m1 ⊆ m2 → m1 ⊆ <[i:=x]>m2.
Proof.
intros. trans (<[i:=x]> m1); eauto using insert_subseteq, insert_mono.
Qed.
Lemma insert_subseteq_l {A} (m1 m2 : M A) i x :
m2 !! i = Some x → m1 ⊆ m2 → <[i:=x]> m1 ⊆ m2.
Proof.
intros Hi Hincl. etrans; [apply insert_mono, Hincl|]. by rewrite insert_id.
Qed.
Lemma insert_delete_subseteq {A} (m1 m2 : M A) i x :
m1 !! i = None → <[i:=x]> m1 ⊆ m2 → m1 ⊆ delete i m2.
Proof.
rewrite !map_subseteq_spec. intros Hi Hix j y Hj.
destruct (decide (i = j)) as [->|]; [congruence|].
rewrite lookup_delete_ne by done.
apply Hix; by rewrite lookup_insert_ne by done.
Qed.
Lemma delete_insert_subseteq {A} (m1 m2 : M A) i x :
m1 !! i = Some x → delete i m1 ⊆ m2 → m1 ⊆ <[i:=x]> m2.
Proof.
rewrite !map_subseteq_spec.
intros Hix Hi j y Hj. destruct (decide (i = j)) as [->|?].
- rewrite lookup_insert. congruence.
- rewrite lookup_insert_ne by done. apply Hi. by rewrite lookup_delete_ne.
Qed.
Lemma insert_delete_subset {A} (m1 m2 : M A) i x :
m1 !! i = None → <[i:=x]> m1 ⊂ m2 → m1 ⊂ delete i m2.
Proof.
intros ? [Hm12 Hm21]; split; [eauto using insert_delete_subseteq|].
contradict Hm21. apply delete_insert_subseteq; auto.
eapply lookup_weaken, Hm12. by rewrite lookup_insert.
Qed.
Lemma insert_subset_inv {A} (m1 m2 : M A) i x :
m1 !! i = None → <[i:=x]> m1 ⊂ m2 →
∃ m2', m2 = <[i:=x]>m2' ∧ m1 ⊂ m2' ∧ m2' !! i = None.
Proof.
intros Hi Hm1m2. ∃ (delete i m2). split_and?.
- rewrite insert_delete; [done|].
eapply lookup_weaken, strict_include; eauto. by rewrite lookup_insert.
- eauto using insert_delete_subset.
- by rewrite lookup_delete.
Qed.
Proof. unfold insert. apply lookup_partial_alter. Qed.
Lemma lookup_total_insert `{!Inhabited A} (m : M A) i x : <[i:=x]>m !!! i = x.
Proof. by rewrite lookup_total_alt, lookup_insert. Qed.
Lemma lookup_insert_rev {A} (m : M A) i x y : <[i:=x]>m !! i = Some y → x = y.
Proof. rewrite lookup_insert. congruence. Qed.
Lemma lookup_insert_ne {A} (m : M A) i j x : i ≠ j → <[i:=x]>m !! j = m !! j.
Proof. unfold insert. apply lookup_partial_alter_ne. Qed.
Lemma lookup_total_insert_ne `{!Inhabited A} (m : M A) i j x :
i ≠ j → <[i:=x]>m !!! j = m !!! j.
Proof. intros. by rewrite lookup_total_alt, lookup_insert_ne. Qed.
Lemma insert_insert {A} (m : M A) i x y : <[i:=x]>(<[i:=y]>m) = <[i:=x]>m.
Proof. unfold insert, map_insert. by rewrite <-partial_alter_compose. Qed.
Lemma insert_commute {A} (m : M A) i j x y :
i ≠ j → <[i:=x]>(<[j:=y]>m) = <[j:=y]>(<[i:=x]>m).
Proof. apply partial_alter_commute. Qed.
Lemma lookup_insert_Some {A} (m : M A) i j x y :
<[i:=x]>m !! j = Some y ↔ (i = j ∧ x = y) ∨ (i ≠ j ∧ m !! j = Some y).
Proof.
split.
- destruct (decide (i = j)) as [->|?];
rewrite ?lookup_insert, ?lookup_insert_ne; intuition congruence.
- intros [[-> ->]|[??]]; [apply lookup_insert|]. by rewrite lookup_insert_ne.
Qed.
Lemma lookup_insert_is_Some {A} (m : M A) i j x :
is_Some (<[i:=x]>m !! j) ↔ i = j ∨ i ≠ j ∧ is_Some (m !! j).
Proof. unfold is_Some; setoid_rewrite lookup_insert_Some; naive_solver. Qed.
Lemma lookup_insert_is_Some' {A} (m : M A) i j x :
is_Some (<[i:=x]>m !! j) ↔ i = j ∨ is_Some (m !! j).
Proof. rewrite lookup_insert_is_Some. destruct (decide (i=j)); naive_solver. Qed.
Lemma lookup_insert_None {A} (m : M A) i j x :
<[i:=x]>m !! j = None ↔ m !! j = None ∧ i ≠ j.
Proof.
split; [|by intros [??]; rewrite lookup_insert_ne].
destruct (decide (i = j)) as [->|];
rewrite ?lookup_insert, ?lookup_insert_ne; intuition congruence.
Qed.
Lemma insert_id {A} (m : M A) i x : m !! i = Some x → <[i:=x]>m = m.
Proof.
intros; apply map_eq; intros j; destruct (decide (i = j)) as [->|];
by rewrite ?lookup_insert, ?lookup_insert_ne by done.
Qed.
Lemma insert_included {A} R `{!Reflexive R} (m : M A) i x :
(∀ y, m !! i = Some y → R y x) → map_included R m (<[i:=x]>m).
Proof.
intros ? j; destruct (decide (i = j)) as [->|].
- rewrite lookup_insert. destruct (m !! j); simpl; eauto.
- rewrite lookup_insert_ne by done. by destruct (m !! j); simpl.
Qed.
Lemma insert_empty {A} i (x : A) : <[i:=x]> ∅ =@{M A} {[i := x]}.
Proof. done. Qed.
Lemma insert_non_empty {A} (m : M A) i x : <[i:=x]>m ≠ ∅.
Proof.
intros Hi%(f_equal (.!! i)). by rewrite lookup_insert, lookup_empty in Hi.
Qed.
Lemma insert_delete_insert {A} (m : M A) i x : <[i:=x]>(delete i m) = <[i:=x]> m.
Proof. symmetry; apply (partial_alter_compose (λ _, Some x)). Qed.
Lemma insert_delete {A} (m : M A) i x :
m !! i = Some x → <[i:=x]> (delete i m) = m.
Proof. intros. rewrite insert_delete_insert, insert_id; done. Qed.
Lemma insert_subseteq {A} (m : M A) i x : m !! i = None → m ⊆ <[i:=x]>m.
Proof. apply partial_alter_subseteq. Qed.
Lemma insert_subset {A} (m : M A) i x : m !! i = None → m ⊂ <[i:=x]>m.
Proof. intro. apply partial_alter_subset; eauto. Qed.
Lemma insert_mono {A} (m1 m2 : M A) i x : m1 ⊆ m2 → <[i:=x]> m1 ⊆ <[i:=x]>m2.
Proof.
rewrite !map_subseteq_spec.
intros Hm j y. rewrite !lookup_insert_Some. naive_solver.
Qed.
Lemma insert_subseteq_r {A} (m1 m2 : M A) i x :
m1 !! i = None → m1 ⊆ m2 → m1 ⊆ <[i:=x]>m2.
Proof.
intros. trans (<[i:=x]> m1); eauto using insert_subseteq, insert_mono.
Qed.
Lemma insert_subseteq_l {A} (m1 m2 : M A) i x :
m2 !! i = Some x → m1 ⊆ m2 → <[i:=x]> m1 ⊆ m2.
Proof.
intros Hi Hincl. etrans; [apply insert_mono, Hincl|]. by rewrite insert_id.
Qed.
Lemma insert_delete_subseteq {A} (m1 m2 : M A) i x :
m1 !! i = None → <[i:=x]> m1 ⊆ m2 → m1 ⊆ delete i m2.
Proof.
rewrite !map_subseteq_spec. intros Hi Hix j y Hj.
destruct (decide (i = j)) as [->|]; [congruence|].
rewrite lookup_delete_ne by done.
apply Hix; by rewrite lookup_insert_ne by done.
Qed.
Lemma delete_insert_subseteq {A} (m1 m2 : M A) i x :
m1 !! i = Some x → delete i m1 ⊆ m2 → m1 ⊆ <[i:=x]> m2.
Proof.
rewrite !map_subseteq_spec.
intros Hix Hi j y Hj. destruct (decide (i = j)) as [->|?].
- rewrite lookup_insert. congruence.
- rewrite lookup_insert_ne by done. apply Hi. by rewrite lookup_delete_ne.
Qed.
Lemma insert_delete_subset {A} (m1 m2 : M A) i x :
m1 !! i = None → <[i:=x]> m1 ⊂ m2 → m1 ⊂ delete i m2.
Proof.
intros ? [Hm12 Hm21]; split; [eauto using insert_delete_subseteq|].
contradict Hm21. apply delete_insert_subseteq; auto.
eapply lookup_weaken, Hm12. by rewrite lookup_insert.
Qed.
Lemma insert_subset_inv {A} (m1 m2 : M A) i x :
m1 !! i = None → <[i:=x]> m1 ⊂ m2 →
∃ m2', m2 = <[i:=x]>m2' ∧ m1 ⊂ m2' ∧ m2' !! i = None.
Proof.
intros Hi Hm1m2. ∃ (delete i m2). split_and?.
- rewrite insert_delete; [done|].
eapply lookup_weaken, strict_include; eauto. by rewrite lookup_insert.
- eauto using insert_delete_subset.
- by rewrite lookup_delete.
Qed.
Lemma lookup_singleton_Some {A} i j (x y : A) :
({[i := x]} : M A) !! j = Some y ↔ i = j ∧ x = y.
Proof.
rewrite <-insert_empty,lookup_insert_Some, lookup_empty; intuition congruence.
Qed.
Lemma lookup_singleton_None {A} i j (x : A) :
({[i := x]} : M A) !! j = None ↔ i ≠ j.
Proof. rewrite <-insert_empty,lookup_insert_None, lookup_empty; tauto. Qed.
Lemma lookup_singleton {A} i (x : A) : ({[i := x]} : M A) !! i = Some x.
Proof. by rewrite lookup_singleton_Some. Qed.
Lemma lookup_total_singleton `{!Inhabited A} i (x : A) :
({[i := x]} : M A) !!! i = x.
Proof. by rewrite lookup_total_alt, lookup_singleton. Qed.
Lemma lookup_singleton_ne {A} i j (x : A) :
i ≠ j → ({[i := x]} : M A) !! j = None.
Proof. by rewrite lookup_singleton_None. Qed.
Lemma lookup_total_singleton_ne `{!Inhabited A} i j (x : A) :
i ≠ j → ({[i := x]} : M A) !!! j = inhabitant.
Proof. intros. by rewrite lookup_total_alt, lookup_singleton_ne. Qed.
Global Instance map_singleton_inj {A} : Inj2 (=) (=) (=) (singletonM (M:=M A)).
Proof.
intros i1 x1 i2 x2 Heq%(f_equal (lookup i1)).
rewrite lookup_singleton in Heq. destruct (decide (i1 = i2)) as [->|].
- rewrite lookup_singleton in Heq. naive_solver.
- rewrite lookup_singleton_ne in Heq by done. naive_solver.
Qed.
Lemma map_non_empty_singleton {A} i (x : A) : {[i := x]} ≠@{M A} ∅.
Proof.
intros Hix. apply (f_equal (.!! i)) in Hix.
by rewrite lookup_empty, lookup_singleton in Hix.
Qed.
Lemma insert_singleton {A} i (x y : A) : <[i:=y]> {[i := x]} =@{M A} {[i := y]}.
Proof.
unfold singletonM, map_singleton, insert, map_insert.
by rewrite <-partial_alter_compose.
Qed.
Lemma alter_singleton {A} (f : A → A) i x :
alter f i {[i := x]} =@{M A} {[i := f x]}.
Proof.
intros. apply map_eq. intros i'. destruct (decide (i = i')) as [->|?].
- by rewrite lookup_alter, !lookup_singleton.
- by rewrite lookup_alter_ne, !lookup_singleton_ne.
Qed.
Lemma alter_singleton_ne {A} (f : A → A) i j x :
i ≠ j → alter f i {[j := x]}=@{M A} {[j := x]}.
Proof.
intros. apply map_eq; intros i'. by destruct (decide (i = i')) as [->|?];
rewrite ?lookup_alter, ?lookup_singleton_ne, ?lookup_alter_ne by done.
Qed.
Lemma singleton_non_empty {A} i (x : A) : {[i:=x]} ≠@{M A} ∅.
Proof. apply insert_non_empty. Qed.
Lemma delete_singleton {A} i (x : A) : delete i {[i := x]} =@{M A} ∅.
Proof. setoid_rewrite <-partial_alter_compose. apply delete_empty. Qed.
Lemma delete_singleton_ne {A} i j (x : A) :
i ≠ j → delete i {[j := x]} =@{M A} {[j := x]}.
Proof. intro. apply delete_notin. by apply lookup_singleton_ne. Qed.
Lemma map_singleton_subseteq_l {A} i (x : A) (m : M A) :
{[i := x]} ⊆ m ↔ m !! i = Some x.
Proof.
rewrite map_subseteq_spec. setoid_rewrite lookup_singleton_Some. naive_solver.
Qed.
Lemma map_singleton_subseteq {A} i j (x y : A) :
{[i := x]} ⊆@{M A} {[j := y]} ↔ i = j ∧ x = y.
Proof.
rewrite map_subseteq_spec. setoid_rewrite lookup_singleton_Some. naive_solver.
Qed.
({[i := x]} : M A) !! j = Some y ↔ i = j ∧ x = y.
Proof.
rewrite <-insert_empty,lookup_insert_Some, lookup_empty; intuition congruence.
Qed.
Lemma lookup_singleton_None {A} i j (x : A) :
({[i := x]} : M A) !! j = None ↔ i ≠ j.
Proof. rewrite <-insert_empty,lookup_insert_None, lookup_empty; tauto. Qed.
Lemma lookup_singleton {A} i (x : A) : ({[i := x]} : M A) !! i = Some x.
Proof. by rewrite lookup_singleton_Some. Qed.
Lemma lookup_total_singleton `{!Inhabited A} i (x : A) :
({[i := x]} : M A) !!! i = x.
Proof. by rewrite lookup_total_alt, lookup_singleton. Qed.
Lemma lookup_singleton_ne {A} i j (x : A) :
i ≠ j → ({[i := x]} : M A) !! j = None.
Proof. by rewrite lookup_singleton_None. Qed.
Lemma lookup_total_singleton_ne `{!Inhabited A} i j (x : A) :
i ≠ j → ({[i := x]} : M A) !!! j = inhabitant.
Proof. intros. by rewrite lookup_total_alt, lookup_singleton_ne. Qed.
Global Instance map_singleton_inj {A} : Inj2 (=) (=) (=) (singletonM (M:=M A)).
Proof.
intros i1 x1 i2 x2 Heq%(f_equal (lookup i1)).
rewrite lookup_singleton in Heq. destruct (decide (i1 = i2)) as [->|].
- rewrite lookup_singleton in Heq. naive_solver.
- rewrite lookup_singleton_ne in Heq by done. naive_solver.
Qed.
Lemma map_non_empty_singleton {A} i (x : A) : {[i := x]} ≠@{M A} ∅.
Proof.
intros Hix. apply (f_equal (.!! i)) in Hix.
by rewrite lookup_empty, lookup_singleton in Hix.
Qed.
Lemma insert_singleton {A} i (x y : A) : <[i:=y]> {[i := x]} =@{M A} {[i := y]}.
Proof.
unfold singletonM, map_singleton, insert, map_insert.
by rewrite <-partial_alter_compose.
Qed.
Lemma alter_singleton {A} (f : A → A) i x :
alter f i {[i := x]} =@{M A} {[i := f x]}.
Proof.
intros. apply map_eq. intros i'. destruct (decide (i = i')) as [->|?].
- by rewrite lookup_alter, !lookup_singleton.
- by rewrite lookup_alter_ne, !lookup_singleton_ne.
Qed.
Lemma alter_singleton_ne {A} (f : A → A) i j x :
i ≠ j → alter f i {[j := x]}=@{M A} {[j := x]}.
Proof.
intros. apply map_eq; intros i'. by destruct (decide (i = i')) as [->|?];
rewrite ?lookup_alter, ?lookup_singleton_ne, ?lookup_alter_ne by done.
Qed.
Lemma singleton_non_empty {A} i (x : A) : {[i:=x]} ≠@{M A} ∅.
Proof. apply insert_non_empty. Qed.
Lemma delete_singleton {A} i (x : A) : delete i {[i := x]} =@{M A} ∅.
Proof. setoid_rewrite <-partial_alter_compose. apply delete_empty. Qed.
Lemma delete_singleton_ne {A} i j (x : A) :
i ≠ j → delete i {[j := x]} =@{M A} {[j := x]}.
Proof. intro. apply delete_notin. by apply lookup_singleton_ne. Qed.
Lemma map_singleton_subseteq_l {A} i (x : A) (m : M A) :
{[i := x]} ⊆ m ↔ m !! i = Some x.
Proof.
rewrite map_subseteq_spec. setoid_rewrite lookup_singleton_Some. naive_solver.
Qed.
Lemma map_singleton_subseteq {A} i j (x y : A) :
{[i := x]} ⊆@{M A} {[j := y]} ↔ i = j ∧ x = y.
Proof.
rewrite map_subseteq_spec. setoid_rewrite lookup_singleton_Some. naive_solver.
Qed.
Global Instance map_fmap_inj {A B} (f : A → B) :
Inj (=) (=) f → Inj (=@{M A}) (=@{M B}) (fmap f).
Proof.
intros ? m1 m2 Hm. apply map_eq; intros i.
apply (inj (fmap (M:=option) f)). by rewrite <-!lookup_fmap, Hm.
Qed.
Lemma lookup_fmap_Some {A B} (f : A → B) (m : M A) i y :
(f <$> m) !! i = Some y ↔ ∃ x, f x = y ∧ m !! i = Some x.
Proof. rewrite lookup_fmap, fmap_Some. naive_solver. Qed.
Lemma lookup_omap_Some {A B} (f : A → option B) (m : M A) i y :
omap f m !! i = Some y ↔ ∃ x, f x = Some y ∧ m !! i = Some x.
Proof. rewrite lookup_omap, bind_Some. naive_solver. Qed.
Lemma lookup_omap_id_Some {A} (m : M (option A)) i x :
omap id m !! i = Some x ↔ m !! i = Some (Some x).
Proof. rewrite lookup_omap_Some. naive_solver. Qed.
Lemma fmap_empty {A B} (f : A → B) : f <$> ∅ =@{M B} ∅.
Proof. apply map_empty; intros i. by rewrite lookup_fmap, lookup_empty. Qed.
Lemma omap_empty {A B} (f : A → option B) : omap f ∅ =@{M B} ∅.
Proof. apply map_empty; intros i. by rewrite lookup_omap, lookup_empty. Qed.
Lemma fmap_empty_iff {A B} (f : A → B) m : f <$> m =@{M B} ∅ ↔ m = ∅.
Proof.
split; [|intros ->; by rewrite fmap_empty].
intros Hm. apply map_eq; intros i. generalize (f_equal (lookup i) Hm).
by rewrite lookup_fmap, !lookup_empty, fmap_None.
Qed.
Lemma fmap_empty_inv {A B} (f : A → B) m : f <$> m =@{M B} ∅ → m = ∅.
Proof. apply fmap_empty_iff. Qed.
Lemma fmap_insert {A B} (f: A → B) (m : M A) i x :
f <$> <[i:=x]>m = <[i:=f x]>(f <$> m).
Proof.
apply map_eq; intros i'; destruct (decide (i' = i)) as [->|].
- by rewrite lookup_fmap, !lookup_insert.
- by rewrite lookup_fmap, !lookup_insert_ne, lookup_fmap by done.
Qed.
Lemma omap_insert {A B} (f : A → option B) (m : M A) i x :
omap f (<[i:=x]>m) =
(match f x with Some y ⇒ <[i:=y]> | None ⇒ delete i end) (omap f m).
Proof.
intros; apply map_eq; intros i'; destruct (decide (i' = i)) as [->|].
- rewrite lookup_omap, !lookup_insert. destruct (f x) as [y|] eqn:Hx; simpl.
+ by rewrite lookup_insert.
+ by rewrite lookup_delete, Hx.
- rewrite lookup_omap, !lookup_insert_ne by done.
destruct (f x) as [y|] eqn:Hx; simpl.
+ by rewrite lookup_insert_ne, lookup_omap by done.
+ by rewrite lookup_delete_ne, lookup_omap by done.
Qed.
Lemma omap_insert_Some {A B} (f : A → option B) (m : M A) i x y :
f x = Some y → omap f (<[i:=x]>m) = <[i:=y]>(omap f m).
Proof. intros Hx. by rewrite omap_insert, Hx. Qed.
Lemma omap_insert_None {A B} (f : A → option B) (m : M A) i x :
f x = None → omap f (<[i:=x]>m) = delete i (omap f m).
Proof. intros Hx. by rewrite omap_insert, Hx. Qed.
Lemma fmap_delete {A B} (f: A → B) (m : M A) i :
f <$> delete i m = delete i (f <$> m).
Proof.
apply map_eq; intros i'; destruct (decide (i' = i)) as [->|].
- by rewrite lookup_fmap, !lookup_delete.
- by rewrite lookup_fmap, !lookup_delete_ne, lookup_fmap by done.
Qed.
Lemma omap_delete {A B} (f: A → option B) (m : M A) i :
omap f (delete i m) = delete i (omap f m).
Proof.
apply map_eq; intros i'; destruct (decide (i' = i)) as [->|].
- by rewrite lookup_omap, !lookup_delete.
- by rewrite lookup_omap, !lookup_delete_ne, lookup_omap by done.
Qed.
Lemma map_fmap_singleton {A B} (f : A → B) i x :
f <$> {[i := x]} =@{M B} {[i := f x]}.
Proof.
by unfold singletonM, map_singleton; rewrite fmap_insert, fmap_empty.
Qed.
Lemma map_fmap_singleton_inv {A B} (f : A → B) (m : M A) i y :
f <$> m = {[i := y]} → ∃ x, y = f x ∧ m = {[ i := x ]}.
Proof.
intros Hm. pose proof (f_equal (.!! i) Hm) as Hmi.
rewrite lookup_fmap, lookup_singleton, fmap_Some in Hmi.
destruct Hmi as (x&?&->). ∃ x. split; [done|].
apply map_eq; intros j. destruct (decide (i = j)) as[->|?].
- by rewrite lookup_singleton.
- rewrite lookup_singleton_ne by done.
apply (fmap_None f). by rewrite <-lookup_fmap, Hm, lookup_singleton_ne.
Qed.
Lemma omap_singleton {A B} (f : A → option B) i x :
omap f {[ i := x ]} =@{M B} match f x with Some y ⇒ {[ i:=y ]} | None ⇒ ∅ end.
Proof.
rewrite <-insert_empty, omap_insert, omap_empty. destruct (f x) as [y|]; simpl.
- by rewrite insert_empty.
- by rewrite delete_empty.
Qed.
Lemma omap_singleton_Some {A B} (f : A → option B) i x y :
f x = Some y → omap f {[ i := x ]} =@{M B} {[ i := y ]}.
Proof. intros Hx. by rewrite omap_singleton, Hx. Qed.
Lemma omap_singleton_None {A B} (f : A → option B) i x :
f x = None → omap f {[ i := x ]} =@{M B} ∅.
Proof. intros Hx. by rewrite omap_singleton, Hx. Qed.
Lemma map_fmap_id {A} (m : M A) : id <$> m = m.
Proof. apply map_eq; intros i; by rewrite lookup_fmap, option_fmap_id. Qed.
Lemma map_fmap_compose {A B C} (f : A → B) (g : B → C) (m : M A) :
g ∘ f <$> m = g <$> (f <$> m).
Proof. apply map_eq; intros i; by rewrite !lookup_fmap,option_fmap_compose. Qed.
Lemma map_fmap_ext {A B} (f1 f2 : A → B) (m : M A) :
(∀ i x, m !! i = Some x → f1 x = f2 x) → f1 <$> m = f2 <$> m.
Proof.
intros Hi; apply map_eq; intros i; rewrite !lookup_fmap.
by destruct (m !! i) eqn:?; simpl; erewrite ?Hi by eauto.
Qed.
Lemma omap_ext {A B} (f1 f2 : A → option B) (m : M A) :
(∀ i x, m !! i = Some x → f1 x = f2 x) → omap f1 m = omap f2 m.
Proof.
intros Hi; apply map_eq; intros i; rewrite !lookup_omap.
by destruct (m !! i) eqn:?; simpl; erewrite ?Hi by eauto.
Qed.
Lemma map_fmap_omap {A B C} (f : A → option B) (g : B → C) (m : M A) :
g <$> omap f m = omap (λ x, g <$> f x) m.
Proof.
apply map_eq. intros i.
rewrite !lookup_fmap, !lookup_omap. destruct (m !! i); done.
Qed.
Lemma map_fmap_alt {A B} (f : A → B) (m : M A) :
f <$> m = omap (λ x, Some (f x)) m.
Proof.
apply map_eq. intros i.
rewrite lookup_fmap, lookup_omap. destruct (m !! i); done.
Qed.
Lemma map_fmap_mono {A B} (f : A → B) (m1 m2 : M A) :
m1 ⊆ m2 → f <$> m1 ⊆ f <$> m2.
Proof.
rewrite !map_subseteq_spec; intros Hm i x.
rewrite !lookup_fmap, !fmap_Some. naive_solver.
Qed.
Lemma map_fmap_strict_mono {A B} (f : A → B) (m1 m2 : M A) :
m1 ⊂ m2 → f <$> m1 ⊂ f <$> m2.
Proof.
rewrite !map_subset_alt.
intros [? (j&?&?)]; split; auto using map_fmap_mono.
∃ j. by rewrite !lookup_fmap, fmap_None, fmap_is_Some.
Qed.
Lemma map_omap_mono {A B} (f : A → option B) (m1 m2 : M A) :
m1 ⊆ m2 → omap f m1 ⊆ omap f m2.
Proof.
rewrite !map_subseteq_spec; intros Hm i x.
rewrite !lookup_omap, !bind_Some. naive_solver.
Qed.
Inj (=) (=) f → Inj (=@{M A}) (=@{M B}) (fmap f).
Proof.
intros ? m1 m2 Hm. apply map_eq; intros i.
apply (inj (fmap (M:=option) f)). by rewrite <-!lookup_fmap, Hm.
Qed.
Lemma lookup_fmap_Some {A B} (f : A → B) (m : M A) i y :
(f <$> m) !! i = Some y ↔ ∃ x, f x = y ∧ m !! i = Some x.
Proof. rewrite lookup_fmap, fmap_Some. naive_solver. Qed.
Lemma lookup_omap_Some {A B} (f : A → option B) (m : M A) i y :
omap f m !! i = Some y ↔ ∃ x, f x = Some y ∧ m !! i = Some x.
Proof. rewrite lookup_omap, bind_Some. naive_solver. Qed.
Lemma lookup_omap_id_Some {A} (m : M (option A)) i x :
omap id m !! i = Some x ↔ m !! i = Some (Some x).
Proof. rewrite lookup_omap_Some. naive_solver. Qed.
Lemma fmap_empty {A B} (f : A → B) : f <$> ∅ =@{M B} ∅.
Proof. apply map_empty; intros i. by rewrite lookup_fmap, lookup_empty. Qed.
Lemma omap_empty {A B} (f : A → option B) : omap f ∅ =@{M B} ∅.
Proof. apply map_empty; intros i. by rewrite lookup_omap, lookup_empty. Qed.
Lemma fmap_empty_iff {A B} (f : A → B) m : f <$> m =@{M B} ∅ ↔ m = ∅.
Proof.
split; [|intros ->; by rewrite fmap_empty].
intros Hm. apply map_eq; intros i. generalize (f_equal (lookup i) Hm).
by rewrite lookup_fmap, !lookup_empty, fmap_None.
Qed.
Lemma fmap_empty_inv {A B} (f : A → B) m : f <$> m =@{M B} ∅ → m = ∅.
Proof. apply fmap_empty_iff. Qed.
Lemma fmap_insert {A B} (f: A → B) (m : M A) i x :
f <$> <[i:=x]>m = <[i:=f x]>(f <$> m).
Proof.
apply map_eq; intros i'; destruct (decide (i' = i)) as [->|].
- by rewrite lookup_fmap, !lookup_insert.
- by rewrite lookup_fmap, !lookup_insert_ne, lookup_fmap by done.
Qed.
Lemma omap_insert {A B} (f : A → option B) (m : M A) i x :
omap f (<[i:=x]>m) =
(match f x with Some y ⇒ <[i:=y]> | None ⇒ delete i end) (omap f m).
Proof.
intros; apply map_eq; intros i'; destruct (decide (i' = i)) as [->|].
- rewrite lookup_omap, !lookup_insert. destruct (f x) as [y|] eqn:Hx; simpl.
+ by rewrite lookup_insert.
+ by rewrite lookup_delete, Hx.
- rewrite lookup_omap, !lookup_insert_ne by done.
destruct (f x) as [y|] eqn:Hx; simpl.
+ by rewrite lookup_insert_ne, lookup_omap by done.
+ by rewrite lookup_delete_ne, lookup_omap by done.
Qed.
Lemma omap_insert_Some {A B} (f : A → option B) (m : M A) i x y :
f x = Some y → omap f (<[i:=x]>m) = <[i:=y]>(omap f m).
Proof. intros Hx. by rewrite omap_insert, Hx. Qed.
Lemma omap_insert_None {A B} (f : A → option B) (m : M A) i x :
f x = None → omap f (<[i:=x]>m) = delete i (omap f m).
Proof. intros Hx. by rewrite omap_insert, Hx. Qed.
Lemma fmap_delete {A B} (f: A → B) (m : M A) i :
f <$> delete i m = delete i (f <$> m).
Proof.
apply map_eq; intros i'; destruct (decide (i' = i)) as [->|].
- by rewrite lookup_fmap, !lookup_delete.
- by rewrite lookup_fmap, !lookup_delete_ne, lookup_fmap by done.
Qed.
Lemma omap_delete {A B} (f: A → option B) (m : M A) i :
omap f (delete i m) = delete i (omap f m).
Proof.
apply map_eq; intros i'; destruct (decide (i' = i)) as [->|].
- by rewrite lookup_omap, !lookup_delete.
- by rewrite lookup_omap, !lookup_delete_ne, lookup_omap by done.
Qed.
Lemma map_fmap_singleton {A B} (f : A → B) i x :
f <$> {[i := x]} =@{M B} {[i := f x]}.
Proof.
by unfold singletonM, map_singleton; rewrite fmap_insert, fmap_empty.
Qed.
Lemma map_fmap_singleton_inv {A B} (f : A → B) (m : M A) i y :
f <$> m = {[i := y]} → ∃ x, y = f x ∧ m = {[ i := x ]}.
Proof.
intros Hm. pose proof (f_equal (.!! i) Hm) as Hmi.
rewrite lookup_fmap, lookup_singleton, fmap_Some in Hmi.
destruct Hmi as (x&?&->). ∃ x. split; [done|].
apply map_eq; intros j. destruct (decide (i = j)) as[->|?].
- by rewrite lookup_singleton.
- rewrite lookup_singleton_ne by done.
apply (fmap_None f). by rewrite <-lookup_fmap, Hm, lookup_singleton_ne.
Qed.
Lemma omap_singleton {A B} (f : A → option B) i x :
omap f {[ i := x ]} =@{M B} match f x with Some y ⇒ {[ i:=y ]} | None ⇒ ∅ end.
Proof.
rewrite <-insert_empty, omap_insert, omap_empty. destruct (f x) as [y|]; simpl.
- by rewrite insert_empty.
- by rewrite delete_empty.
Qed.
Lemma omap_singleton_Some {A B} (f : A → option B) i x y :
f x = Some y → omap f {[ i := x ]} =@{M B} {[ i := y ]}.
Proof. intros Hx. by rewrite omap_singleton, Hx. Qed.
Lemma omap_singleton_None {A B} (f : A → option B) i x :
f x = None → omap f {[ i := x ]} =@{M B} ∅.
Proof. intros Hx. by rewrite omap_singleton, Hx. Qed.
Lemma map_fmap_id {A} (m : M A) : id <$> m = m.
Proof. apply map_eq; intros i; by rewrite lookup_fmap, option_fmap_id. Qed.
Lemma map_fmap_compose {A B C} (f : A → B) (g : B → C) (m : M A) :
g ∘ f <$> m = g <$> (f <$> m).
Proof. apply map_eq; intros i; by rewrite !lookup_fmap,option_fmap_compose. Qed.
Lemma map_fmap_ext {A B} (f1 f2 : A → B) (m : M A) :
(∀ i x, m !! i = Some x → f1 x = f2 x) → f1 <$> m = f2 <$> m.
Proof.
intros Hi; apply map_eq; intros i; rewrite !lookup_fmap.
by destruct (m !! i) eqn:?; simpl; erewrite ?Hi by eauto.
Qed.
Lemma omap_ext {A B} (f1 f2 : A → option B) (m : M A) :
(∀ i x, m !! i = Some x → f1 x = f2 x) → omap f1 m = omap f2 m.
Proof.
intros Hi; apply map_eq; intros i; rewrite !lookup_omap.
by destruct (m !! i) eqn:?; simpl; erewrite ?Hi by eauto.
Qed.
Lemma map_fmap_omap {A B C} (f : A → option B) (g : B → C) (m : M A) :
g <$> omap f m = omap (λ x, g <$> f x) m.
Proof.
apply map_eq. intros i.
rewrite !lookup_fmap, !lookup_omap. destruct (m !! i); done.
Qed.
Lemma map_fmap_alt {A B} (f : A → B) (m : M A) :
f <$> m = omap (λ x, Some (f x)) m.
Proof.
apply map_eq. intros i.
rewrite lookup_fmap, lookup_omap. destruct (m !! i); done.
Qed.
Lemma map_fmap_mono {A B} (f : A → B) (m1 m2 : M A) :
m1 ⊆ m2 → f <$> m1 ⊆ f <$> m2.
Proof.
rewrite !map_subseteq_spec; intros Hm i x.
rewrite !lookup_fmap, !fmap_Some. naive_solver.
Qed.
Lemma map_fmap_strict_mono {A B} (f : A → B) (m1 m2 : M A) :
m1 ⊂ m2 → f <$> m1 ⊂ f <$> m2.
Proof.
rewrite !map_subset_alt.
intros [? (j&?&?)]; split; auto using map_fmap_mono.
∃ j. by rewrite !lookup_fmap, fmap_None, fmap_is_Some.
Qed.
Lemma map_omap_mono {A B} (f : A → option B) (m1 m2 : M A) :
m1 ⊆ m2 → omap f m1 ⊆ omap f m2.
Proof.
rewrite !map_subseteq_spec; intros Hm i x.
rewrite !lookup_omap, !bind_Some. naive_solver.
Qed.
Lemma elem_of_map_to_list' {A} (m : M A) ix :
ix ∈ map_to_list m ↔ m !! ix.1 = Some (ix.2).
Proof. destruct ix as [i x]. apply elem_of_map_to_list. Qed.
Lemma map_to_list_unique {A} (m : M A) i x y :
(i,x) ∈ map_to_list m → (i,y) ∈ map_to_list m → x = y.
Proof. rewrite !elem_of_map_to_list. congruence. Qed.
Lemma NoDup_fst_map_to_list {A} (m : M A) : NoDup ((map_to_list m).*1).
Proof. eauto using NoDup_fmap_fst, map_to_list_unique, NoDup_map_to_list. Qed.
Lemma elem_of_list_to_map_1' {A} (l : list (K × A)) i x :
(∀ y, (i,y) ∈ l → x = y) → (i,x) ∈ l → (list_to_map l : M A) !! i = Some x.
Proof.
induction l as [|[j y] l IH]; csimpl; [by rewrite elem_of_nil|].
setoid_rewrite elem_of_cons.
intros Hdup [?|?]; simplify_eq; [by rewrite lookup_insert|].
destruct (decide (i = j)) as [->|].
- rewrite lookup_insert; f_equal; eauto using eq_sym.
- rewrite lookup_insert_ne by done; eauto.
Qed.
Lemma elem_of_list_to_map_1 {A} (l : list (K × A)) i x :
NoDup (l.*1) → (i,x) ∈ l → (list_to_map l : M A) !! i = Some x.
Proof.
intros ? Hx; apply elem_of_list_to_map_1'; eauto using NoDup_fmap_fst.
intros y; revert Hx. rewrite !elem_of_list_lookup; intros [i' Hi'] [j' Hj'].
cut (i' = j'); [naive_solver|]. apply NoDup_lookup with (l.*1) i;
by rewrite ?list_lookup_fmap, ?Hi', ?Hj'.
Qed.
Lemma elem_of_list_to_map_2 {A} (l : list (K × A)) i x :
(list_to_map l : M A) !! i = Some x → (i,x) ∈ l.
Proof.
induction l as [|[j y] l IH]; simpl; [by rewrite lookup_empty|].
rewrite elem_of_cons. destruct (decide (i = j)) as [->|];
rewrite ?lookup_insert, ?lookup_insert_ne; intuition congruence.
Qed.
Lemma elem_of_list_to_map' {A} (l : list (K × A)) i x :
(∀ x', (i,x) ∈ l → (i,x') ∈ l → x = x') →
(i,x) ∈ l ↔ (list_to_map l : M A) !! i = Some x.
Proof. split; auto using elem_of_list_to_map_1', elem_of_list_to_map_2. Qed.
Lemma elem_of_list_to_map {A} (l : list (K × A)) i x :
NoDup (l.*1) → (i,x) ∈ l ↔ (list_to_map l : M A) !! i = Some x.
Proof. split; auto using elem_of_list_to_map_1, elem_of_list_to_map_2. Qed.
Lemma not_elem_of_list_to_map_1 {A} (l : list (K × A)) i :
i ∉ l.*1 → (list_to_map l : M A) !! i = None.
Proof.
rewrite elem_of_list_fmap, eq_None_not_Some. intros Hi [x ?]; destruct Hi.
∃ (i,x); simpl; auto using elem_of_list_to_map_2.
Qed.
Lemma not_elem_of_list_to_map_2 {A} (l : list (K × A)) i :
(list_to_map l : M A) !! i = None → i ∉ l.*1.
Proof.
induction l as [|[j y] l IH]; csimpl; [rewrite elem_of_nil; tauto|].
rewrite elem_of_cons. destruct (decide (i = j)); simplify_eq.
- by rewrite lookup_insert.
- by rewrite lookup_insert_ne; intuition.
Qed.
Lemma not_elem_of_list_to_map {A} (l : list (K × A)) i :
i ∉ l.*1 ↔ (list_to_map l : M A) !! i = None.
Proof. red; auto using not_elem_of_list_to_map_1,not_elem_of_list_to_map_2. Qed.
Lemma list_to_map_proper {A} (l1 l2 : list (K × A)) :
NoDup (l1.*1) → l1 ≡ₚ l2 → (list_to_map l1 : M A) = list_to_map l2.
Proof.
intros ? Hperm. apply map_eq. intros i. apply option_eq. intros x.
by rewrite <-!elem_of_list_to_map; rewrite <-?Hperm.
Qed.
Lemma list_to_map_inj {A} (l1 l2 : list (K × A)) :
NoDup (l1.*1) → NoDup (l2.*1) →
(list_to_map l1 : M A) = list_to_map l2 → l1 ≡ₚ l2.
Proof.
intros ?? Hl1l2. apply NoDup_Permutation; [by eauto using NoDup_fmap_1..|].
intros [i x]. by rewrite !elem_of_list_to_map, Hl1l2.
Qed.
Lemma list_to_map_to_list {A} (m : M A) : list_to_map (map_to_list m) = m.
Proof.
apply map_eq. intros i. apply option_eq. intros x.
by rewrite <-elem_of_list_to_map, elem_of_map_to_list
by auto using NoDup_fst_map_to_list.
Qed.
Lemma map_to_list_to_map {A} (l : list (K × A)) :
NoDup (l.*1) → map_to_list (list_to_map l) ≡ₚ l.
Proof. auto using list_to_map_inj, NoDup_fst_map_to_list, list_to_map_to_list. Qed.
Lemma map_to_list_inj {A} (m1 m2 : M A) :
map_to_list m1 ≡ₚ map_to_list m2 → m1 = m2.
Proof.
intros. rewrite <-(list_to_map_to_list m1), <-(list_to_map_to_list m2).
auto using list_to_map_proper, NoDup_fst_map_to_list.
Qed.
Lemma list_to_map_flip {A} (m1 : M A) l2 :
map_to_list m1 ≡ₚ l2 → m1 = list_to_map l2.
Proof.
intros. rewrite <-(list_to_map_to_list m1).
auto using list_to_map_proper, NoDup_fst_map_to_list.
Qed.
Lemma list_to_map_nil {A} : list_to_map [] =@{M A} ∅.
Proof. done. Qed.
Lemma list_to_map_cons {A} (l : list (K × A)) i x :
list_to_map ((i, x) :: l) =@{M A} <[i:=x]>(list_to_map l).
Proof. done. Qed.
Lemma list_to_map_snoc {A} (l : list (K × A)) i x :
i ∉ l.*1 → list_to_map (l ++ [(i, x)]) =@{M A} <[i:=x]>(list_to_map l).
Proof.
induction l as [|[k y] l IH]; [done|]. csimpl.
intros [Hneq Hni]%not_elem_of_cons.
by rewrite (IH Hni), insert_commute by done.
Qed.
Lemma list_to_map_fmap {A B} (f : A → B) l :
list_to_map (prod_map id f <$> l) = f <$> (list_to_map l : M A).
Proof.
induction l as [|[i x] l IH]; csimpl; rewrite ?fmap_empty; auto.
rewrite <-list_to_map_cons; simpl. by rewrite IH, <-fmap_insert.
Qed.
Lemma map_to_list_empty {A} : map_to_list ∅ = @nil (K × A).
Proof.
apply elem_of_nil_inv. intros [i x].
rewrite elem_of_map_to_list. apply lookup_empty_Some.
Qed.
Lemma map_to_list_insert {A} (m : M A) i x :
m !! i = None → map_to_list (<[i:=x]>m) ≡ₚ (i,x) :: map_to_list m.
Proof.
intros. apply list_to_map_inj; csimpl.
- apply NoDup_fst_map_to_list.
- constructor; [|by auto using NoDup_fst_map_to_list].
rewrite elem_of_list_fmap. intros [[??] [? Hlookup]]; subst; simpl in ×.
rewrite elem_of_map_to_list in Hlookup. congruence.
- by rewrite !list_to_map_to_list.
Qed.
Lemma map_to_list_singleton {A} i (x : A) :
map_to_list ({[i:=x]} : M A) = [(i,x)].
Proof.
apply Permutation_singleton_r. unfold singletonM, map_singleton.
by rewrite map_to_list_insert, map_to_list_empty by eauto using lookup_empty.
Qed.
Lemma map_to_list_delete {A} (m : M A) i x :
m !! i = Some x → (i,x) :: map_to_list (delete i m) ≡ₚ map_to_list m.
Proof.
intros. rewrite <-map_to_list_insert by (by rewrite lookup_delete).
by rewrite insert_delete.
Qed.
Lemma map_to_list_submseteq {A} (m1 m2 : M A) :
m1 ⊆ m2 → map_to_list m1 ⊆+ map_to_list m2.
Proof.
intros; apply NoDup_submseteq; [by eauto using NoDup_map_to_list|].
intros [i x]. rewrite !elem_of_map_to_list; eauto using lookup_weaken.
Qed.
Lemma map_to_list_fmap {A B} (f : A → B) (m : M A) :
map_to_list (f <$> m) ≡ₚ prod_map id f <$> map_to_list m.
Proof.
assert (NoDup ((prod_map id f <$> map_to_list m).*1)).
{ erewrite <-list_fmap_compose, (list_fmap_ext _ fst) by done.
apply NoDup_fst_map_to_list. }
rewrite <-(list_to_map_to_list m) at 1.
by rewrite <-list_to_map_fmap, map_to_list_to_map.
Qed.
Lemma map_to_list_empty_iff {A} (m : M A) : map_to_list m = [] ↔ m = ∅.
Proof.
split.
- rewrite <-Permutation_nil_r, <-map_to_list_empty. apply map_to_list_inj.
- intros →. apply map_to_list_empty.
Qed.
Lemma map_to_list_insert_inv {A} (m : M A) l i x :
map_to_list m ≡ₚ (i,x) :: l → m = <[i:=x]>(list_to_map l).
Proof.
intros Hperm. apply map_to_list_inj.
assert (i ∉ l.*1 ∧ NoDup (l.*1)) as [].
{ rewrite <-NoDup_cons. change (NoDup (((i,x)::l).*1)). rewrite <-Hperm.
auto using NoDup_fst_map_to_list. }
rewrite Hperm, map_to_list_insert, map_to_list_to_map;
auto using not_elem_of_list_to_map_1.
Qed.
Lemma map_choose {A} (m : M A) : m ≠ ∅ → ∃ i x, m !! i = Some x.
Proof.
rewrite <-map_to_list_empty_iff.
intros Hemp. destruct (map_to_list m) as [|[i x] l] eqn:Hm; [done|].
∃ i, x. rewrite <-elem_of_map_to_list, Hm. by left.
Qed.
Global Instance map_eq_dec_empty {A} (m : M A) : Decision (m = ∅) | 20.
Proof.
refine (cast_if (decide (map_to_list m = [])));
by rewrite <-?map_to_list_empty_iff.
Defined.
ix ∈ map_to_list m ↔ m !! ix.1 = Some (ix.2).
Proof. destruct ix as [i x]. apply elem_of_map_to_list. Qed.
Lemma map_to_list_unique {A} (m : M A) i x y :
(i,x) ∈ map_to_list m → (i,y) ∈ map_to_list m → x = y.
Proof. rewrite !elem_of_map_to_list. congruence. Qed.
Lemma NoDup_fst_map_to_list {A} (m : M A) : NoDup ((map_to_list m).*1).
Proof. eauto using NoDup_fmap_fst, map_to_list_unique, NoDup_map_to_list. Qed.
Lemma elem_of_list_to_map_1' {A} (l : list (K × A)) i x :
(∀ y, (i,y) ∈ l → x = y) → (i,x) ∈ l → (list_to_map l : M A) !! i = Some x.
Proof.
induction l as [|[j y] l IH]; csimpl; [by rewrite elem_of_nil|].
setoid_rewrite elem_of_cons.
intros Hdup [?|?]; simplify_eq; [by rewrite lookup_insert|].
destruct (decide (i = j)) as [->|].
- rewrite lookup_insert; f_equal; eauto using eq_sym.
- rewrite lookup_insert_ne by done; eauto.
Qed.
Lemma elem_of_list_to_map_1 {A} (l : list (K × A)) i x :
NoDup (l.*1) → (i,x) ∈ l → (list_to_map l : M A) !! i = Some x.
Proof.
intros ? Hx; apply elem_of_list_to_map_1'; eauto using NoDup_fmap_fst.
intros y; revert Hx. rewrite !elem_of_list_lookup; intros [i' Hi'] [j' Hj'].
cut (i' = j'); [naive_solver|]. apply NoDup_lookup with (l.*1) i;
by rewrite ?list_lookup_fmap, ?Hi', ?Hj'.
Qed.
Lemma elem_of_list_to_map_2 {A} (l : list (K × A)) i x :
(list_to_map l : M A) !! i = Some x → (i,x) ∈ l.
Proof.
induction l as [|[j y] l IH]; simpl; [by rewrite lookup_empty|].
rewrite elem_of_cons. destruct (decide (i = j)) as [->|];
rewrite ?lookup_insert, ?lookup_insert_ne; intuition congruence.
Qed.
Lemma elem_of_list_to_map' {A} (l : list (K × A)) i x :
(∀ x', (i,x) ∈ l → (i,x') ∈ l → x = x') →
(i,x) ∈ l ↔ (list_to_map l : M A) !! i = Some x.
Proof. split; auto using elem_of_list_to_map_1', elem_of_list_to_map_2. Qed.
Lemma elem_of_list_to_map {A} (l : list (K × A)) i x :
NoDup (l.*1) → (i,x) ∈ l ↔ (list_to_map l : M A) !! i = Some x.
Proof. split; auto using elem_of_list_to_map_1, elem_of_list_to_map_2. Qed.
Lemma not_elem_of_list_to_map_1 {A} (l : list (K × A)) i :
i ∉ l.*1 → (list_to_map l : M A) !! i = None.
Proof.
rewrite elem_of_list_fmap, eq_None_not_Some. intros Hi [x ?]; destruct Hi.
∃ (i,x); simpl; auto using elem_of_list_to_map_2.
Qed.
Lemma not_elem_of_list_to_map_2 {A} (l : list (K × A)) i :
(list_to_map l : M A) !! i = None → i ∉ l.*1.
Proof.
induction l as [|[j y] l IH]; csimpl; [rewrite elem_of_nil; tauto|].
rewrite elem_of_cons. destruct (decide (i = j)); simplify_eq.
- by rewrite lookup_insert.
- by rewrite lookup_insert_ne; intuition.
Qed.
Lemma not_elem_of_list_to_map {A} (l : list (K × A)) i :
i ∉ l.*1 ↔ (list_to_map l : M A) !! i = None.
Proof. red; auto using not_elem_of_list_to_map_1,not_elem_of_list_to_map_2. Qed.
Lemma list_to_map_proper {A} (l1 l2 : list (K × A)) :
NoDup (l1.*1) → l1 ≡ₚ l2 → (list_to_map l1 : M A) = list_to_map l2.
Proof.
intros ? Hperm. apply map_eq. intros i. apply option_eq. intros x.
by rewrite <-!elem_of_list_to_map; rewrite <-?Hperm.
Qed.
Lemma list_to_map_inj {A} (l1 l2 : list (K × A)) :
NoDup (l1.*1) → NoDup (l2.*1) →
(list_to_map l1 : M A) = list_to_map l2 → l1 ≡ₚ l2.
Proof.
intros ?? Hl1l2. apply NoDup_Permutation; [by eauto using NoDup_fmap_1..|].
intros [i x]. by rewrite !elem_of_list_to_map, Hl1l2.
Qed.
Lemma list_to_map_to_list {A} (m : M A) : list_to_map (map_to_list m) = m.
Proof.
apply map_eq. intros i. apply option_eq. intros x.
by rewrite <-elem_of_list_to_map, elem_of_map_to_list
by auto using NoDup_fst_map_to_list.
Qed.
Lemma map_to_list_to_map {A} (l : list (K × A)) :
NoDup (l.*1) → map_to_list (list_to_map l) ≡ₚ l.
Proof. auto using list_to_map_inj, NoDup_fst_map_to_list, list_to_map_to_list. Qed.
Lemma map_to_list_inj {A} (m1 m2 : M A) :
map_to_list m1 ≡ₚ map_to_list m2 → m1 = m2.
Proof.
intros. rewrite <-(list_to_map_to_list m1), <-(list_to_map_to_list m2).
auto using list_to_map_proper, NoDup_fst_map_to_list.
Qed.
Lemma list_to_map_flip {A} (m1 : M A) l2 :
map_to_list m1 ≡ₚ l2 → m1 = list_to_map l2.
Proof.
intros. rewrite <-(list_to_map_to_list m1).
auto using list_to_map_proper, NoDup_fst_map_to_list.
Qed.
Lemma list_to_map_nil {A} : list_to_map [] =@{M A} ∅.
Proof. done. Qed.
Lemma list_to_map_cons {A} (l : list (K × A)) i x :
list_to_map ((i, x) :: l) =@{M A} <[i:=x]>(list_to_map l).
Proof. done. Qed.
Lemma list_to_map_snoc {A} (l : list (K × A)) i x :
i ∉ l.*1 → list_to_map (l ++ [(i, x)]) =@{M A} <[i:=x]>(list_to_map l).
Proof.
induction l as [|[k y] l IH]; [done|]. csimpl.
intros [Hneq Hni]%not_elem_of_cons.
by rewrite (IH Hni), insert_commute by done.
Qed.
Lemma list_to_map_fmap {A B} (f : A → B) l :
list_to_map (prod_map id f <$> l) = f <$> (list_to_map l : M A).
Proof.
induction l as [|[i x] l IH]; csimpl; rewrite ?fmap_empty; auto.
rewrite <-list_to_map_cons; simpl. by rewrite IH, <-fmap_insert.
Qed.
Lemma map_to_list_empty {A} : map_to_list ∅ = @nil (K × A).
Proof.
apply elem_of_nil_inv. intros [i x].
rewrite elem_of_map_to_list. apply lookup_empty_Some.
Qed.
Lemma map_to_list_insert {A} (m : M A) i x :
m !! i = None → map_to_list (<[i:=x]>m) ≡ₚ (i,x) :: map_to_list m.
Proof.
intros. apply list_to_map_inj; csimpl.
- apply NoDup_fst_map_to_list.
- constructor; [|by auto using NoDup_fst_map_to_list].
rewrite elem_of_list_fmap. intros [[??] [? Hlookup]]; subst; simpl in ×.
rewrite elem_of_map_to_list in Hlookup. congruence.
- by rewrite !list_to_map_to_list.
Qed.
Lemma map_to_list_singleton {A} i (x : A) :
map_to_list ({[i:=x]} : M A) = [(i,x)].
Proof.
apply Permutation_singleton_r. unfold singletonM, map_singleton.
by rewrite map_to_list_insert, map_to_list_empty by eauto using lookup_empty.
Qed.
Lemma map_to_list_delete {A} (m : M A) i x :
m !! i = Some x → (i,x) :: map_to_list (delete i m) ≡ₚ map_to_list m.
Proof.
intros. rewrite <-map_to_list_insert by (by rewrite lookup_delete).
by rewrite insert_delete.
Qed.
Lemma map_to_list_submseteq {A} (m1 m2 : M A) :
m1 ⊆ m2 → map_to_list m1 ⊆+ map_to_list m2.
Proof.
intros; apply NoDup_submseteq; [by eauto using NoDup_map_to_list|].
intros [i x]. rewrite !elem_of_map_to_list; eauto using lookup_weaken.
Qed.
Lemma map_to_list_fmap {A B} (f : A → B) (m : M A) :
map_to_list (f <$> m) ≡ₚ prod_map id f <$> map_to_list m.
Proof.
assert (NoDup ((prod_map id f <$> map_to_list m).*1)).
{ erewrite <-list_fmap_compose, (list_fmap_ext _ fst) by done.
apply NoDup_fst_map_to_list. }
rewrite <-(list_to_map_to_list m) at 1.
by rewrite <-list_to_map_fmap, map_to_list_to_map.
Qed.
Lemma map_to_list_empty_iff {A} (m : M A) : map_to_list m = [] ↔ m = ∅.
Proof.
split.
- rewrite <-Permutation_nil_r, <-map_to_list_empty. apply map_to_list_inj.
- intros →. apply map_to_list_empty.
Qed.
Lemma map_to_list_insert_inv {A} (m : M A) l i x :
map_to_list m ≡ₚ (i,x) :: l → m = <[i:=x]>(list_to_map l).
Proof.
intros Hperm. apply map_to_list_inj.
assert (i ∉ l.*1 ∧ NoDup (l.*1)) as [].
{ rewrite <-NoDup_cons. change (NoDup (((i,x)::l).*1)). rewrite <-Hperm.
auto using NoDup_fst_map_to_list. }
rewrite Hperm, map_to_list_insert, map_to_list_to_map;
auto using not_elem_of_list_to_map_1.
Qed.
Lemma map_choose {A} (m : M A) : m ≠ ∅ → ∃ i x, m !! i = Some x.
Proof.
rewrite <-map_to_list_empty_iff.
intros Hemp. destruct (map_to_list m) as [|[i x] l] eqn:Hm; [done|].
∃ i, x. rewrite <-elem_of_map_to_list, Hm. by left.
Qed.
Global Instance map_eq_dec_empty {A} (m : M A) : Decision (m = ∅) | 20.
Proof.
refine (cast_if (decide (map_to_list m = [])));
by rewrite <-?map_to_list_empty_iff.
Defined.
Properties of the imap function
Lemma map_lookup_imap {A B} (f : K → A → option B) (m : M A) i :
map_imap f m !! i = m !! i ≫= f i.
Proof.
unfold map_imap; destruct (m !! i ≫= f i) as [y|] eqn:Hi; simpl.
- destruct (m !! i) as [x|] eqn:?; simplify_eq/=.
apply elem_of_list_to_map_1'.
{ intros y'; rewrite elem_of_list_omap; intros ([i' x']&Hi'&?).
by rewrite elem_of_map_to_list in Hi'; simplify_option_eq. }
apply elem_of_list_omap; ∃ (i,x); split;
[by apply elem_of_map_to_list|by simplify_option_eq].
- apply not_elem_of_list_to_map; rewrite elem_of_list_fmap.
intros ([i' x]&->&Hi'); simplify_eq/=.
rewrite elem_of_list_omap in Hi'; destruct Hi' as ([j y]&Hj&?).
rewrite elem_of_map_to_list in Hj; simplify_option_eq.
Qed.
Lemma map_imap_Some {A} (m : M A) : map_imap (λ _, Some) m = m.
Proof.
apply map_eq. intros i. rewrite map_lookup_imap. by destruct (m !! i).
Qed.
Lemma map_imap_insert {A B} (f : K → A → option B) i x (m : M A) :
map_imap f (<[i:=x]> m) =
(match f i x with Some y ⇒ <[i:=y]> | None ⇒ delete i end) (map_imap f m).
Proof.
destruct (f i x) as [y|] eqn:Hw; simpl.
- apply map_eq. intros k. rewrite map_lookup_imap.
destruct (decide (k = i)) as [->|Hk_not_i].
+ by rewrite lookup_insert, lookup_insert.
+ rewrite !lookup_insert_ne by done.
by rewrite map_lookup_imap.
- apply map_eq. intros k. rewrite map_lookup_imap.
destruct (decide (k = i)) as [->|Hk_not_i].
+ by rewrite lookup_insert, lookup_delete.
+ rewrite lookup_insert_ne, lookup_delete_ne by done.
by rewrite map_lookup_imap.
Qed.
Lemma map_imap_insert_Some {A B} (f : K → A → option B) i x (m : M A) y :
f i x = Some y → map_imap f (<[i:=x]> m) = <[i:=y]> (map_imap f m).
Proof. intros Hi. by rewrite map_imap_insert, Hi. Qed.
Lemma map_imap_insert_None {A B} (f : K → A → option B) i x (m : M A) :
f i x = None → map_imap f (<[i:=x]> m) = delete i (map_imap f m).
Proof. intros Hi. by rewrite map_imap_insert, Hi. Qed.
Lemma map_imap_delete {A B} (f : K → A → option B) (m : M A) (i : K) :
map_imap f (delete i m) = delete i (map_imap f m).
Proof.
apply map_eq. intros k. rewrite map_lookup_imap.
destruct (decide (k = i)) as [->|Hk_not_i].
- by rewrite !lookup_delete.
- rewrite !lookup_delete_ne by done.
by rewrite map_lookup_imap.
Qed.
Lemma map_imap_ext {A1 A2 B} (f1 : K → A1 → option B)
(f2 : K → A2 → option B) (m1 : M A1) (m2 : M A2) :
(∀ k, f1 k <$> (m1 !! k) = f2 k <$> (m2 !! k)) →
map_imap f1 m1 = map_imap f2 m2.
Proof.
intros HExt. apply map_eq. intros i. rewrite !map_lookup_imap.
specialize (HExt i). destruct (m1 !! i), (m2 !! i); naive_solver.
Qed.
Lemma map_imap_compose {A1 A2 B} (f1 : K → A1 → option B)
(f2 : K → A2 → option A1) (m : M A2) :
map_imap f1 (map_imap f2 m) = map_imap (λ k x, f2 k x ≫= f1 k) m.
Proof.
apply map_eq. intros i. rewrite !map_lookup_imap. by destruct (m !! i).
Qed.
Lemma map_imap_empty {A B} (f : K → A → option B) :
map_imap f ∅ =@{M B} ∅.
Proof. unfold map_imap. by rewrite map_to_list_empty. Qed.
map_imap f m !! i = m !! i ≫= f i.
Proof.
unfold map_imap; destruct (m !! i ≫= f i) as [y|] eqn:Hi; simpl.
- destruct (m !! i) as [x|] eqn:?; simplify_eq/=.
apply elem_of_list_to_map_1'.
{ intros y'; rewrite elem_of_list_omap; intros ([i' x']&Hi'&?).
by rewrite elem_of_map_to_list in Hi'; simplify_option_eq. }
apply elem_of_list_omap; ∃ (i,x); split;
[by apply elem_of_map_to_list|by simplify_option_eq].
- apply not_elem_of_list_to_map; rewrite elem_of_list_fmap.
intros ([i' x]&->&Hi'); simplify_eq/=.
rewrite elem_of_list_omap in Hi'; destruct Hi' as ([j y]&Hj&?).
rewrite elem_of_map_to_list in Hj; simplify_option_eq.
Qed.
Lemma map_imap_Some {A} (m : M A) : map_imap (λ _, Some) m = m.
Proof.
apply map_eq. intros i. rewrite map_lookup_imap. by destruct (m !! i).
Qed.
Lemma map_imap_insert {A B} (f : K → A → option B) i x (m : M A) :
map_imap f (<[i:=x]> m) =
(match f i x with Some y ⇒ <[i:=y]> | None ⇒ delete i end) (map_imap f m).
Proof.
destruct (f i x) as [y|] eqn:Hw; simpl.
- apply map_eq. intros k. rewrite map_lookup_imap.
destruct (decide (k = i)) as [->|Hk_not_i].
+ by rewrite lookup_insert, lookup_insert.
+ rewrite !lookup_insert_ne by done.
by rewrite map_lookup_imap.
- apply map_eq. intros k. rewrite map_lookup_imap.
destruct (decide (k = i)) as [->|Hk_not_i].
+ by rewrite lookup_insert, lookup_delete.
+ rewrite lookup_insert_ne, lookup_delete_ne by done.
by rewrite map_lookup_imap.
Qed.
Lemma map_imap_insert_Some {A B} (f : K → A → option B) i x (m : M A) y :
f i x = Some y → map_imap f (<[i:=x]> m) = <[i:=y]> (map_imap f m).
Proof. intros Hi. by rewrite map_imap_insert, Hi. Qed.
Lemma map_imap_insert_None {A B} (f : K → A → option B) i x (m : M A) :
f i x = None → map_imap f (<[i:=x]> m) = delete i (map_imap f m).
Proof. intros Hi. by rewrite map_imap_insert, Hi. Qed.
Lemma map_imap_delete {A B} (f : K → A → option B) (m : M A) (i : K) :
map_imap f (delete i m) = delete i (map_imap f m).
Proof.
apply map_eq. intros k. rewrite map_lookup_imap.
destruct (decide (k = i)) as [->|Hk_not_i].
- by rewrite !lookup_delete.
- rewrite !lookup_delete_ne by done.
by rewrite map_lookup_imap.
Qed.
Lemma map_imap_ext {A1 A2 B} (f1 : K → A1 → option B)
(f2 : K → A2 → option B) (m1 : M A1) (m2 : M A2) :
(∀ k, f1 k <$> (m1 !! k) = f2 k <$> (m2 !! k)) →
map_imap f1 m1 = map_imap f2 m2.
Proof.
intros HExt. apply map_eq. intros i. rewrite !map_lookup_imap.
specialize (HExt i). destruct (m1 !! i), (m2 !! i); naive_solver.
Qed.
Lemma map_imap_compose {A1 A2 B} (f1 : K → A1 → option B)
(f2 : K → A2 → option A1) (m : M A2) :
map_imap f1 (map_imap f2 m) = map_imap (λ k x, f2 k x ≫= f1 k) m.
Proof.
apply map_eq. intros i. rewrite !map_lookup_imap. by destruct (m !! i).
Qed.
Lemma map_imap_empty {A B} (f : K → A → option B) :
map_imap f ∅ =@{M B} ∅.
Proof. unfold map_imap. by rewrite map_to_list_empty. Qed.
Lemma map_size_empty {A} : size (∅ : M A) = 0.
Proof. unfold size, map_size. by rewrite map_to_list_empty. Qed.
Lemma map_size_empty_iff {A} (m : M A) : size m = 0 ↔ m = ∅.
Proof.
unfold size, map_size. by rewrite length_zero_iff_nil, map_to_list_empty_iff.
Qed.
Lemma map_size_empty_inv {A} (m : M A) : size m = 0 → m = ∅.
Proof. apply map_size_empty_iff. Qed.
Lemma map_size_non_empty_iff {A} (m : M A) : size m ≠ 0 ↔ m ≠ ∅.
Proof. by rewrite map_size_empty_iff. Qed.
Lemma map_size_singleton {A} i (x : A) : size ({[ i := x ]} : M A) = 1.
Proof. unfold size, map_size. by rewrite map_to_list_singleton. Qed.
Lemma map_size_insert {A} i x (m : M A) :
size (<[i:=x]> m) = (match m !! i with Some _ ⇒ id | None ⇒ S end) (size m).
Proof.
destruct (m !! i) as [y|] eqn:?; simpl.
- rewrite <-(insert_id m i y) at 2 by done. rewrite <-!(insert_delete_insert m).
unfold size, map_size.
by rewrite !map_to_list_insert by (by rewrite lookup_delete).
- unfold size, map_size. by rewrite map_to_list_insert.
Qed.
Lemma map_size_insert_Some {A} i x (m : M A) :
is_Some (m !! i) → size (<[i:=x]> m) = size m.
Proof. intros [y Hi]. by rewrite map_size_insert, Hi. Qed.
Lemma map_size_insert_None {A} i x (m : M A) :
m !! i = None → size (<[i:=x]> m) = S (size m).
Proof. intros Hi. by rewrite map_size_insert, Hi. Qed.
Lemma map_size_delete {A} i (m : M A) :
size (delete i m) = (match m !! i with Some _ ⇒ pred | None ⇒ id end) (size m).
Proof.
destruct (m !! i) as [y|] eqn:?; simpl.
- unfold size, map_size. by rewrite <-(map_to_list_delete m).
- by rewrite delete_notin.
Qed.
Lemma map_size_delete_Some {A} i (m : M A) :
is_Some (m !! i) → size (delete i m) = pred (size m).
Proof. intros [y Hi]. by rewrite map_size_delete, Hi. Qed.
Lemma map_size_delete_None {A} i (m : M A) :
m !! i = None → size (delete i m) = size m.
Proof. intros Hi. by rewrite map_size_delete, Hi. Qed.
Lemma map_size_fmap {A B} (f : A → B) (m : M A) : size (f <$> m) = size m.
Proof. intros. unfold size, map_size. by rewrite map_to_list_fmap, fmap_length. Qed.
Proof. unfold size, map_size. by rewrite map_to_list_empty. Qed.
Lemma map_size_empty_iff {A} (m : M A) : size m = 0 ↔ m = ∅.
Proof.
unfold size, map_size. by rewrite length_zero_iff_nil, map_to_list_empty_iff.
Qed.
Lemma map_size_empty_inv {A} (m : M A) : size m = 0 → m = ∅.
Proof. apply map_size_empty_iff. Qed.
Lemma map_size_non_empty_iff {A} (m : M A) : size m ≠ 0 ↔ m ≠ ∅.
Proof. by rewrite map_size_empty_iff. Qed.
Lemma map_size_singleton {A} i (x : A) : size ({[ i := x ]} : M A) = 1.
Proof. unfold size, map_size. by rewrite map_to_list_singleton. Qed.
Lemma map_size_insert {A} i x (m : M A) :
size (<[i:=x]> m) = (match m !! i with Some _ ⇒ id | None ⇒ S end) (size m).
Proof.
destruct (m !! i) as [y|] eqn:?; simpl.
- rewrite <-(insert_id m i y) at 2 by done. rewrite <-!(insert_delete_insert m).
unfold size, map_size.
by rewrite !map_to_list_insert by (by rewrite lookup_delete).
- unfold size, map_size. by rewrite map_to_list_insert.
Qed.
Lemma map_size_insert_Some {A} i x (m : M A) :
is_Some (m !! i) → size (<[i:=x]> m) = size m.
Proof. intros [y Hi]. by rewrite map_size_insert, Hi. Qed.
Lemma map_size_insert_None {A} i x (m : M A) :
m !! i = None → size (<[i:=x]> m) = S (size m).
Proof. intros Hi. by rewrite map_size_insert, Hi. Qed.
Lemma map_size_delete {A} i (m : M A) :
size (delete i m) = (match m !! i with Some _ ⇒ pred | None ⇒ id end) (size m).
Proof.
destruct (m !! i) as [y|] eqn:?; simpl.
- unfold size, map_size. by rewrite <-(map_to_list_delete m).
- by rewrite delete_notin.
Qed.
Lemma map_size_delete_Some {A} i (m : M A) :
is_Some (m !! i) → size (delete i m) = pred (size m).
Proof. intros [y Hi]. by rewrite map_size_delete, Hi. Qed.
Lemma map_size_delete_None {A} i (m : M A) :
m !! i = None → size (delete i m) = size m.
Proof. intros Hi. by rewrite map_size_delete, Hi. Qed.
Lemma map_size_fmap {A B} (f : A → B) (m : M A) : size (f <$> m) = size m.
Proof. intros. unfold size, map_size. by rewrite map_to_list_fmap, fmap_length. Qed.
Section set_to_map.
Context {A : Type} `{FinSet B C}.
Lemma lookup_set_to_map (f : B → K × A) (Y : C) i x :
(∀ y y', y ∈ Y → y' ∈ Y → (f y).1 = (f y').1 → y = y') →
(set_to_map f Y : M A) !! i = Some x ↔ ∃ y, y ∈ Y ∧ f y = (i,x).
Proof.
intros Hinj. assert (∀ x',
(i, x) ∈ f <$> elements Y → (i, x') ∈ f <$> elements Y → x = x').
{ intros x'. intros (y&Hx&Hy)%elem_of_list_fmap (y'&Hx'&Hy')%elem_of_list_fmap.
rewrite elem_of_elements in Hy, Hy'.
cut (y = y'); [congruence|]. apply Hinj; auto. by rewrite <-Hx, <-Hx'. }
unfold set_to_map; rewrite <-elem_of_list_to_map' by done.
rewrite elem_of_list_fmap. setoid_rewrite elem_of_elements; naive_solver.
Qed.
Lemma elem_of_map_to_set (f : K → A → B) (m : M A) (y : B) :
y ∈ map_to_set (C:=C) f m ↔ ∃ i x, m !! i = Some x ∧ f i x = y.
Proof.
unfold map_to_set; simpl.
rewrite elem_of_list_to_set, elem_of_list_fmap. split.
- intros ([i x] & ? & ?%elem_of_map_to_list); eauto.
- intros (i&x&?&?). ∃ (i,x). by rewrite elem_of_map_to_list.
Qed.
Lemma map_to_set_empty (f : K → A → B) :
map_to_set f (∅ : M A) = (∅ : C).
Proof. unfold map_to_set; simpl. by rewrite map_to_list_empty. Qed.
Lemma map_to_set_insert (f : K → A → B)(m : M A) i x :
m !! i = None →
map_to_set f (<[i:=x]>m) ≡@{C} {[f i x]} ∪ map_to_set f m.
Proof.
intros. unfold map_to_set; simpl. by rewrite map_to_list_insert.
Qed.
Lemma map_to_set_insert_L `{!LeibnizEquiv C} (f : K → A → B) (m : M A) i x :
m !! i = None →
map_to_set f (<[i:=x]>m) =@{C} {[f i x]} ∪ map_to_set f m.
Proof. unfold_leibniz. apply map_to_set_insert. Qed.
End set_to_map.
Lemma lookup_set_to_map_id `{FinSet (K × A) C} (X : C) i x :
(∀ i y y', (i,y) ∈ X → (i,y') ∈ X → y = y') →
(set_to_map id X : M A) !! i = Some x ↔ (i,x) ∈ X.
Proof.
intros. etrans; [apply lookup_set_to_map|naive_solver].
intros [] [] ???; simplify_eq/=; eauto with f_equal.
Qed.
Lemma elem_of_map_to_set_pair `{FinSet (K × A) C} (m : M A) i x :
(i,x) ∈@{C} map_to_set pair m ↔ m !! i = Some x.
Proof. rewrite elem_of_map_to_set. naive_solver. Qed.
Context {A : Type} `{FinSet B C}.
Lemma lookup_set_to_map (f : B → K × A) (Y : C) i x :
(∀ y y', y ∈ Y → y' ∈ Y → (f y).1 = (f y').1 → y = y') →
(set_to_map f Y : M A) !! i = Some x ↔ ∃ y, y ∈ Y ∧ f y = (i,x).
Proof.
intros Hinj. assert (∀ x',
(i, x) ∈ f <$> elements Y → (i, x') ∈ f <$> elements Y → x = x').
{ intros x'. intros (y&Hx&Hy)%elem_of_list_fmap (y'&Hx'&Hy')%elem_of_list_fmap.
rewrite elem_of_elements in Hy, Hy'.
cut (y = y'); [congruence|]. apply Hinj; auto. by rewrite <-Hx, <-Hx'. }
unfold set_to_map; rewrite <-elem_of_list_to_map' by done.
rewrite elem_of_list_fmap. setoid_rewrite elem_of_elements; naive_solver.
Qed.
Lemma elem_of_map_to_set (f : K → A → B) (m : M A) (y : B) :
y ∈ map_to_set (C:=C) f m ↔ ∃ i x, m !! i = Some x ∧ f i x = y.
Proof.
unfold map_to_set; simpl.
rewrite elem_of_list_to_set, elem_of_list_fmap. split.
- intros ([i x] & ? & ?%elem_of_map_to_list); eauto.
- intros (i&x&?&?). ∃ (i,x). by rewrite elem_of_map_to_list.
Qed.
Lemma map_to_set_empty (f : K → A → B) :
map_to_set f (∅ : M A) = (∅ : C).
Proof. unfold map_to_set; simpl. by rewrite map_to_list_empty. Qed.
Lemma map_to_set_insert (f : K → A → B)(m : M A) i x :
m !! i = None →
map_to_set f (<[i:=x]>m) ≡@{C} {[f i x]} ∪ map_to_set f m.
Proof.
intros. unfold map_to_set; simpl. by rewrite map_to_list_insert.
Qed.
Lemma map_to_set_insert_L `{!LeibnizEquiv C} (f : K → A → B) (m : M A) i x :
m !! i = None →
map_to_set f (<[i:=x]>m) =@{C} {[f i x]} ∪ map_to_set f m.
Proof. unfold_leibniz. apply map_to_set_insert. Qed.
End set_to_map.
Lemma lookup_set_to_map_id `{FinSet (K × A) C} (X : C) i x :
(∀ i y y', (i,y) ∈ X → (i,y') ∈ X → y = y') →
(set_to_map id X : M A) !! i = Some x ↔ (i,x) ∈ X.
Proof.
intros. etrans; [apply lookup_set_to_map|naive_solver].
intros [] [] ???; simplify_eq/=; eauto with f_equal.
Qed.
Lemma elem_of_map_to_set_pair `{FinSet (K × A) C} (m : M A) i x :
(i,x) ∈@{C} map_to_set pair m ↔ m !! i = Some x.
Proof. rewrite elem_of_map_to_set. naive_solver. Qed.
Lemma map_ind {A} (P : M A → Prop) :
P ∅ → (∀ i x m, m !! i = None → P m → P (<[i:=x]>m)) → ∀ m, P m.
Proof.
intros ? Hins. cut (∀ l, NoDup (l.*1) → ∀ m, map_to_list m ≡ₚ l → P m).
{ intros help m.
apply (help (map_to_list m)); auto using NoDup_fst_map_to_list. }
intros l. induction l as [|[i x] l IH]; intros Hnodup m Hml.
{ rewrite Permutation_nil_r, map_to_list_empty_iff in Hml. by rewrite Hml. }
inversion_clear Hnodup.
apply map_to_list_insert_inv in Hml; subst m. apply Hins.
- by apply not_elem_of_list_to_map_1.
- apply IH; auto using map_to_list_to_map.
Qed.
Lemma map_to_list_length {A} (m1 m2 : M A) :
m1 ⊂ m2 → length (map_to_list m1) < length (map_to_list m2).
Proof.
revert m2. induction m1 as [|i x m ? IH] using map_ind.
{ intros m2 Hm2. rewrite map_to_list_empty. simpl.
apply Nat.neq_0_lt_0, Nat.neq_sym. intros Hlen. symmetry in Hlen.
apply nil_length_inv, map_to_list_empty_iff in Hlen.
rewrite Hlen in Hm2. destruct (irreflexivity (⊂) ∅ Hm2). }
intros m2 Hm2.
destruct (insert_subset_inv m m2 i x) as (m2'&?&?&?); auto; subst.
rewrite !map_to_list_insert; simpl; auto with arith.
Qed.
Lemma map_wf {A} : wf (⊂@{M A}).
Proof.
apply (wf_projected (<) (length ∘ map_to_list)).
- by apply map_to_list_length.
- by apply lt_wf.
Qed.
P ∅ → (∀ i x m, m !! i = None → P m → P (<[i:=x]>m)) → ∀ m, P m.
Proof.
intros ? Hins. cut (∀ l, NoDup (l.*1) → ∀ m, map_to_list m ≡ₚ l → P m).
{ intros help m.
apply (help (map_to_list m)); auto using NoDup_fst_map_to_list. }
intros l. induction l as [|[i x] l IH]; intros Hnodup m Hml.
{ rewrite Permutation_nil_r, map_to_list_empty_iff in Hml. by rewrite Hml. }
inversion_clear Hnodup.
apply map_to_list_insert_inv in Hml; subst m. apply Hins.
- by apply not_elem_of_list_to_map_1.
- apply IH; auto using map_to_list_to_map.
Qed.
Lemma map_to_list_length {A} (m1 m2 : M A) :
m1 ⊂ m2 → length (map_to_list m1) < length (map_to_list m2).
Proof.
revert m2. induction m1 as [|i x m ? IH] using map_ind.
{ intros m2 Hm2. rewrite map_to_list_empty. simpl.
apply Nat.neq_0_lt_0, Nat.neq_sym. intros Hlen. symmetry in Hlen.
apply nil_length_inv, map_to_list_empty_iff in Hlen.
rewrite Hlen in Hm2. destruct (irreflexivity (⊂) ∅ Hm2). }
intros m2 Hm2.
destruct (insert_subset_inv m m2 i x) as (m2'&?&?&?); auto; subst.
rewrite !map_to_list_insert; simpl; auto with arith.
Qed.
Lemma map_wf {A} : wf (⊂@{M A}).
Proof.
apply (wf_projected (<) (length ∘ map_to_list)).
- by apply map_to_list_length.
- by apply lt_wf.
Qed.
Lemma map_fold_empty {A B} (f : K → A → B → B) (b : B) :
map_fold f b ∅ = b.
Proof. unfold map_fold; simpl. by rewrite map_to_list_empty. Qed.
Lemma map_fold_insert {A B} (R : relation B) `{!PreOrder R}
(f : K → A → B → B) (b : B) (i : K) (x : A) (m : M A) :
(∀ j z, Proper (R ==> R) (f j z)) →
(∀ j1 j2 z1 z2 y,
j1 ≠ j2 → <[i:=x]> m !! j1 = Some z1 → <[i:=x]> m !! j2 = Some z2 →
R (f j1 z1 (f j2 z2 y)) (f j2 z2 (f j1 z1 y))) →
m !! i = None →
R (map_fold f b (<[i:=x]> m)) (f i x (map_fold f b m)).
Proof.
intros Hf_proper Hf Hi. unfold map_fold; simpl.
assert (∀ kz, Proper (R ==> R) (uncurry f kz)) by (intros []; apply _).
trans (foldr (uncurry f) b ((i, x) :: map_to_list m)); [|done].
eapply (foldr_permutation R (uncurry f) b), map_to_list_insert; auto.
intros j1 [k1 y1] j2 [k2 y2] c Hj Hj1 Hj2. apply Hf.
- intros →.
eapply Hj, NoDup_lookup; [apply (NoDup_fst_map_to_list (<[i:=x]> m))| | ].
+ by rewrite list_lookup_fmap, Hj1.
+ by rewrite list_lookup_fmap, Hj2.
- by eapply elem_of_map_to_list, elem_of_list_lookup_2.
- by eapply elem_of_map_to_list, elem_of_list_lookup_2.
Qed.
Lemma map_fold_insert_L {A B} (f : K → A → B → B) (b : B) (i : K) (x : A) (m : M A) :
(∀ j1 j2 z1 z2 y,
j1 ≠ j2 → <[i:=x]> m !! j1 = Some z1 → <[i:=x]> m !! j2 = Some z2 →
f j1 z1 (f j2 z2 y) = f j2 z2 (f j1 z1 y)) →
m !! i = None →
map_fold f b (<[i:=x]> m) = f i x (map_fold f b m).
Proof. apply map_fold_insert; apply _. Qed.
Lemma map_fold_ind {A B} (P : B → M A → Prop) (f : K → A → B → B) (b : B) :
P b ∅ →
(∀ i x m r, m !! i = None → P r m → P (f i x r) (<[i:=x]> m)) →
∀ m, P (map_fold f b m) m.
Proof.
intros Hemp Hinsert.
cut (∀ l, NoDup l →
∀ m, (∀ i x, m !! i = Some x ↔ (i,x) ∈ l) → P (foldr (uncurry f) b l) m).
{ intros help ?. apply help; [apply NoDup_map_to_list|].
intros i x. by rewrite elem_of_map_to_list. }
induction 1 as [|[i x] l ?? IH]; simpl.
{ intros m Hm. cut (m = ∅); [by intros ->|]. apply map_empty; intros i.
apply eq_None_not_Some; intros [x []%Hm%elem_of_nil]. }
intros m Hm. assert (m !! i = Some x) by (apply Hm; by left).
rewrite <-(insert_delete m i x) by done.
apply Hinsert; auto using lookup_delete.
apply IH. intros j y. rewrite lookup_delete_Some, Hm. split.
- by intros [? [[= ??]|?]%elem_of_cons].
- intros ?; split; [intros ->|by right].
assert (m !! j = Some y) by (apply Hm; by right). naive_solver.
Qed.
map_fold f b ∅ = b.
Proof. unfold map_fold; simpl. by rewrite map_to_list_empty. Qed.
Lemma map_fold_insert {A B} (R : relation B) `{!PreOrder R}
(f : K → A → B → B) (b : B) (i : K) (x : A) (m : M A) :
(∀ j z, Proper (R ==> R) (f j z)) →
(∀ j1 j2 z1 z2 y,
j1 ≠ j2 → <[i:=x]> m !! j1 = Some z1 → <[i:=x]> m !! j2 = Some z2 →
R (f j1 z1 (f j2 z2 y)) (f j2 z2 (f j1 z1 y))) →
m !! i = None →
R (map_fold f b (<[i:=x]> m)) (f i x (map_fold f b m)).
Proof.
intros Hf_proper Hf Hi. unfold map_fold; simpl.
assert (∀ kz, Proper (R ==> R) (uncurry f kz)) by (intros []; apply _).
trans (foldr (uncurry f) b ((i, x) :: map_to_list m)); [|done].
eapply (foldr_permutation R (uncurry f) b), map_to_list_insert; auto.
intros j1 [k1 y1] j2 [k2 y2] c Hj Hj1 Hj2. apply Hf.
- intros →.
eapply Hj, NoDup_lookup; [apply (NoDup_fst_map_to_list (<[i:=x]> m))| | ].
+ by rewrite list_lookup_fmap, Hj1.
+ by rewrite list_lookup_fmap, Hj2.
- by eapply elem_of_map_to_list, elem_of_list_lookup_2.
- by eapply elem_of_map_to_list, elem_of_list_lookup_2.
Qed.
Lemma map_fold_insert_L {A B} (f : K → A → B → B) (b : B) (i : K) (x : A) (m : M A) :
(∀ j1 j2 z1 z2 y,
j1 ≠ j2 → <[i:=x]> m !! j1 = Some z1 → <[i:=x]> m !! j2 = Some z2 →
f j1 z1 (f j2 z2 y) = f j2 z2 (f j1 z1 y)) →
m !! i = None →
map_fold f b (<[i:=x]> m) = f i x (map_fold f b m).
Proof. apply map_fold_insert; apply _. Qed.
Lemma map_fold_ind {A B} (P : B → M A → Prop) (f : K → A → B → B) (b : B) :
P b ∅ →
(∀ i x m r, m !! i = None → P r m → P (f i x r) (<[i:=x]> m)) →
∀ m, P (map_fold f b m) m.
Proof.
intros Hemp Hinsert.
cut (∀ l, NoDup l →
∀ m, (∀ i x, m !! i = Some x ↔ (i,x) ∈ l) → P (foldr (uncurry f) b l) m).
{ intros help ?. apply help; [apply NoDup_map_to_list|].
intros i x. by rewrite elem_of_map_to_list. }
induction 1 as [|[i x] l ?? IH]; simpl.
{ intros m Hm. cut (m = ∅); [by intros ->|]. apply map_empty; intros i.
apply eq_None_not_Some; intros [x []%Hm%elem_of_nil]. }
intros m Hm. assert (m !! i = Some x) by (apply Hm; by left).
rewrite <-(insert_delete m i x) by done.
apply Hinsert; auto using lookup_delete.
apply IH. intros j y. rewrite lookup_delete_Some, Hm. split.
- by intros [? [[= ??]|?]%elem_of_cons].
- intros ?; split; [intros ->|by right].
assert (m !! j = Some y) by (apply Hm; by right). naive_solver.
Qed.
Properties of the map_Forall predicate
Section map_Forall.
Context {A} (P : K → A → Prop).
Implicit Types m : M A.
Lemma map_Forall_to_list m : map_Forall P m ↔ Forall (uncurry P) (map_to_list m).
Proof.
rewrite Forall_forall. split.
- intros Hforall [i x]. rewrite elem_of_map_to_list. by apply (Hforall i x).
- intros Hforall i x. rewrite <-elem_of_map_to_list. by apply (Hforall (i,x)).
Qed.
Lemma map_Forall_empty : map_Forall P (∅ : M A).
Proof. intros i x. by rewrite lookup_empty. Qed.
Lemma map_Forall_impl (Q : K → A → Prop) m :
map_Forall P m → (∀ i x, P i x → Q i x) → map_Forall Q m.
Proof. unfold map_Forall; naive_solver. Qed.
Lemma map_Forall_insert_1_1 m i x : map_Forall P (<[i:=x]>m) → P i x.
Proof. intros Hm. by apply Hm; rewrite lookup_insert. Qed.
Lemma map_Forall_insert_1_2 m i x :
m !! i = None → map_Forall P (<[i:=x]>m) → map_Forall P m.
Proof.
intros ? Hm j y ?; apply Hm. by rewrite lookup_insert_ne by congruence.
Qed.
Lemma map_Forall_insert_2 m i x :
P i x → map_Forall P m → map_Forall P (<[i:=x]>m).
Proof. intros ?? j y; rewrite lookup_insert_Some; naive_solver. Qed.
Lemma map_Forall_insert m i x :
m !! i = None → map_Forall P (<[i:=x]>m) ↔ P i x ∧ map_Forall P m.
Proof.
naive_solver eauto using map_Forall_insert_1_1,
map_Forall_insert_1_2, map_Forall_insert_2.
Qed.
Lemma map_Forall_singleton (i : K) (x : A) :
map_Forall P ({[i := x]} : M A) ↔ P i x.
Proof.
unfold map_Forall. setoid_rewrite lookup_singleton_Some. naive_solver.
Qed.
Lemma map_Forall_delete m i : map_Forall P m → map_Forall P (delete i m).
Proof. intros Hm j x; rewrite lookup_delete_Some. naive_solver. Qed.
Lemma map_Forall_lookup m :
map_Forall P m ↔ ∀ i x, m !! i = Some x → P i x.
Proof. done. Qed.
Lemma map_Forall_lookup_1 m i x :
map_Forall P m → m !! i = Some x → P i x.
Proof. intros ?. by apply map_Forall_lookup. Qed.
Lemma map_Forall_lookup_2 m :
(∀ i x, m !! i = Some x → P i x) → map_Forall P m.
Proof. intros ?. by apply map_Forall_lookup. Qed.
Lemma map_Forall_foldr_delete m is :
map_Forall P m → map_Forall P (foldr delete m is).
Proof. induction is; eauto using map_Forall_delete. Qed.
Lemma map_Forall_ind (Q : M A → Prop) :
Q ∅ →
(∀ m i x, m !! i = None → P i x → map_Forall P m → Q m → Q (<[i:=x]>m)) →
∀ m, map_Forall P m → Q m.
Proof.
intros Hnil Hinsert m. induction m using map_ind; auto.
rewrite map_Forall_insert by done; intros [??]; eauto.
Qed.
Context `{∀ i x, Decision (P i x)}.
Global Instance map_Forall_dec m : Decision (map_Forall P m).
Proof.
refine (cast_if (decide (Forall (uncurry P) (map_to_list m))));
by rewrite map_Forall_to_list.
Defined.
Lemma map_not_Forall (m : M A) :
¬map_Forall P m ↔ ∃ i x, m !! i = Some x ∧ ¬P i x.
Proof.
split; [|intros (i&x&?&?) Hm; specialize (Hm i x); tauto].
rewrite map_Forall_to_list. intros Hm.
apply (not_Forall_Exists _), Exists_exists in Hm.
destruct Hm as ([i x]&?&?). ∃ i, x. by rewrite <-elem_of_map_to_list.
Qed.
End map_Forall.
Context {A} (P : K → A → Prop).
Implicit Types m : M A.
Lemma map_Forall_to_list m : map_Forall P m ↔ Forall (uncurry P) (map_to_list m).
Proof.
rewrite Forall_forall. split.
- intros Hforall [i x]. rewrite elem_of_map_to_list. by apply (Hforall i x).
- intros Hforall i x. rewrite <-elem_of_map_to_list. by apply (Hforall (i,x)).
Qed.
Lemma map_Forall_empty : map_Forall P (∅ : M A).
Proof. intros i x. by rewrite lookup_empty. Qed.
Lemma map_Forall_impl (Q : K → A → Prop) m :
map_Forall P m → (∀ i x, P i x → Q i x) → map_Forall Q m.
Proof. unfold map_Forall; naive_solver. Qed.
Lemma map_Forall_insert_1_1 m i x : map_Forall P (<[i:=x]>m) → P i x.
Proof. intros Hm. by apply Hm; rewrite lookup_insert. Qed.
Lemma map_Forall_insert_1_2 m i x :
m !! i = None → map_Forall P (<[i:=x]>m) → map_Forall P m.
Proof.
intros ? Hm j y ?; apply Hm. by rewrite lookup_insert_ne by congruence.
Qed.
Lemma map_Forall_insert_2 m i x :
P i x → map_Forall P m → map_Forall P (<[i:=x]>m).
Proof. intros ?? j y; rewrite lookup_insert_Some; naive_solver. Qed.
Lemma map_Forall_insert m i x :
m !! i = None → map_Forall P (<[i:=x]>m) ↔ P i x ∧ map_Forall P m.
Proof.
naive_solver eauto using map_Forall_insert_1_1,
map_Forall_insert_1_2, map_Forall_insert_2.
Qed.
Lemma map_Forall_singleton (i : K) (x : A) :
map_Forall P ({[i := x]} : M A) ↔ P i x.
Proof.
unfold map_Forall. setoid_rewrite lookup_singleton_Some. naive_solver.
Qed.
Lemma map_Forall_delete m i : map_Forall P m → map_Forall P (delete i m).
Proof. intros Hm j x; rewrite lookup_delete_Some. naive_solver. Qed.
Lemma map_Forall_lookup m :
map_Forall P m ↔ ∀ i x, m !! i = Some x → P i x.
Proof. done. Qed.
Lemma map_Forall_lookup_1 m i x :
map_Forall P m → m !! i = Some x → P i x.
Proof. intros ?. by apply map_Forall_lookup. Qed.
Lemma map_Forall_lookup_2 m :
(∀ i x, m !! i = Some x → P i x) → map_Forall P m.
Proof. intros ?. by apply map_Forall_lookup. Qed.
Lemma map_Forall_foldr_delete m is :
map_Forall P m → map_Forall P (foldr delete m is).
Proof. induction is; eauto using map_Forall_delete. Qed.
Lemma map_Forall_ind (Q : M A → Prop) :
Q ∅ →
(∀ m i x, m !! i = None → P i x → map_Forall P m → Q m → Q (<[i:=x]>m)) →
∀ m, map_Forall P m → Q m.
Proof.
intros Hnil Hinsert m. induction m using map_ind; auto.
rewrite map_Forall_insert by done; intros [??]; eauto.
Qed.
Context `{∀ i x, Decision (P i x)}.
Global Instance map_Forall_dec m : Decision (map_Forall P m).
Proof.
refine (cast_if (decide (Forall (uncurry P) (map_to_list m))));
by rewrite map_Forall_to_list.
Defined.
Lemma map_not_Forall (m : M A) :
¬map_Forall P m ↔ ∃ i x, m !! i = Some x ∧ ¬P i x.
Proof.
split; [|intros (i&x&?&?) Hm; specialize (Hm i x); tauto].
rewrite map_Forall_to_list. intros Hm.
apply (not_Forall_Exists _), Exists_exists in Hm.
destruct Hm as ([i x]&?&?). ∃ i, x. by rewrite <-elem_of_map_to_list.
Qed.
End map_Forall.
Properties of the map_Exists predicate
Section map_Exists.
Context {A} (P : K → A → Prop).
Implicit Types m : M A.
Lemma map_Exists_to_list m : map_Exists P m ↔ Exists (uncurry P) (map_to_list m).
Proof.
rewrite Exists_exists. split.
- intros [? [? [? ?]]]. eexists (_, _). by rewrite elem_of_map_to_list.
- intros [[??] [??]]. eexists _, _. by rewrite <-elem_of_map_to_list.
Qed.
Lemma map_Exists_empty : ¬ map_Exists P (∅ : M A).
Proof. intros [?[?[Hm ?]]]. by rewrite lookup_empty in Hm. Qed.
Lemma map_Exists_impl (Q : K → A → Prop) m :
map_Exists P m → (∀ i x, P i x → Q i x) → map_Exists Q m.
Proof. unfold map_Exists; naive_solver. Qed.
Lemma map_Exists_insert_1 m i x :
map_Exists P (<[i:=x]>m) → P i x ∨ map_Exists P m.
Proof. intros [j[y[?%lookup_insert_Some ?]]]. unfold map_Exists. naive_solver. Qed.
Lemma map_Exists_insert_2_1 m i x : P i x → map_Exists P (<[i:=x]>m).
Proof. intros Hm. ∃ i, x. by rewrite lookup_insert. Qed.
Lemma map_Exists_insert_2_2 m i x :
m !! i = None → map_Exists P m → map_Exists P (<[i:=x]>m).
Proof.
intros Hm [j[y[??]]]. ∃ j, y. by rewrite lookup_insert_ne by congruence.
Qed.
Lemma map_Exists_insert m i x :
m !! i = None → map_Exists P (<[i:=x]>m) ↔ P i x ∨ map_Exists P m.
Proof.
naive_solver eauto using map_Exists_insert_1,
map_Exists_insert_2_1, map_Exists_insert_2_2.
Qed.
Lemma map_Exists_singleton (i : K) (x : A) :
map_Exists P ({[i := x]} : M A) ↔ P i x.
Proof.
unfold map_Exists. setoid_rewrite lookup_singleton_Some. naive_solver.
Qed.
Lemma map_Exists_delete m i : map_Exists P (delete i m) → map_Exists P m.
Proof.
intros [j [y [Hm ?]]]. rewrite lookup_delete_Some in Hm.
unfold map_Exists. naive_solver.
Qed.
Lemma map_Exists_lookup m :
map_Exists P m ↔ ∃ i x, m !! i = Some x ∧ P i x.
Proof. done. Qed.
Lemma map_Exists_lookup_1 m :
map_Exists P m → ∃ i x, m !! i = Some x ∧ P i x.
Proof. by rewrite map_Exists_lookup. Qed.
Lemma map_Exists_lookup_2 m i x :
m !! i = Some x → P i x → map_Exists P m.
Proof. rewrite map_Exists_lookup. by eauto. Qed.
Lemma map_Exists_foldr_delete m is :
map_Exists P (foldr delete m is) → map_Exists P m.
Proof. induction is; eauto using map_Exists_delete. Qed.
Lemma map_Exists_ind (Q : M A → Prop) :
(∀ i x, P i x → Q {[ i := x ]}) →
(∀ m i x, m !! i = None → map_Exists P m → Q m → Q (<[i:=x]>m)) →
∀ m, map_Exists P m → Q m.
Proof.
intros Hsingleton Hinsert m Hm. induction m as [|i x m Hi IH] using map_ind.
{ by destruct map_Exists_empty. }
apply map_Exists_insert in Hm as [?|?]; [|by eauto..].
clear IH. induction m
Context {A} (P : K → A → Prop).
Implicit Types m : M A.
Lemma map_Exists_to_list m : map_Exists P m ↔ Exists (uncurry P) (map_to_list m).
Proof.
rewrite Exists_exists. split.
- intros [? [? [? ?]]]. eexists (_, _). by rewrite elem_of_map_to_list.
- intros [[??] [??]]. eexists _, _. by rewrite <-elem_of_map_to_list.
Qed.
Lemma map_Exists_empty : ¬ map_Exists P (∅ : M A).
Proof. intros [?[?[Hm ?]]]. by rewrite lookup_empty in Hm. Qed.
Lemma map_Exists_impl (Q : K → A → Prop) m :
map_Exists P m → (∀ i x, P i x → Q i x) → map_Exists Q m.
Proof. unfold map_Exists; naive_solver. Qed.
Lemma map_Exists_insert_1 m i x :
map_Exists P (<[i:=x]>m) → P i x ∨ map_Exists P m.
Proof. intros [j[y[?%lookup_insert_Some ?]]]. unfold map_Exists. naive_solver. Qed.
Lemma map_Exists_insert_2_1 m i x : P i x → map_Exists P (<[i:=x]>m).
Proof. intros Hm. ∃ i, x. by rewrite lookup_insert. Qed.
Lemma map_Exists_insert_2_2 m i x :
m !! i = None → map_Exists P m → map_Exists P (<[i:=x]>m).
Proof.
intros Hm [j[y[??]]]. ∃ j, y. by rewrite lookup_insert_ne by congruence.
Qed.
Lemma map_Exists_insert m i x :
m !! i = None → map_Exists P (<[i:=x]>m) ↔ P i x ∨ map_Exists P m.
Proof.
naive_solver eauto using map_Exists_insert_1,
map_Exists_insert_2_1, map_Exists_insert_2_2.
Qed.
Lemma map_Exists_singleton (i : K) (x : A) :
map_Exists P ({[i := x]} : M A) ↔ P i x.
Proof.
unfold map_Exists. setoid_rewrite lookup_singleton_Some. naive_solver.
Qed.
Lemma map_Exists_delete m i : map_Exists P (delete i m) → map_Exists P m.
Proof.
intros [j [y [Hm ?]]]. rewrite lookup_delete_Some in Hm.
unfold map_Exists. naive_solver.
Qed.
Lemma map_Exists_lookup m :
map_Exists P m ↔ ∃ i x, m !! i = Some x ∧ P i x.
Proof. done. Qed.
Lemma map_Exists_lookup_1 m :
map_Exists P m → ∃ i x, m !! i = Some x ∧ P i x.
Proof. by rewrite map_Exists_lookup. Qed.
Lemma map_Exists_lookup_2 m i x :
m !! i = Some x → P i x → map_Exists P m.
Proof. rewrite map_Exists_lookup. by eauto. Qed.
Lemma map_Exists_foldr_delete m is :
map_Exists P (foldr delete m is) → map_Exists P m.
Proof. induction is; eauto using map_Exists_delete. Qed.
Lemma map_Exists_ind (Q : M A → Prop) :
(∀ i x, P i x → Q {[ i := x ]}) →
(∀ m i x, m !! i = None → map_Exists P m → Q m → Q (<[i:=x]>m)) →
∀ m, map_Exists P m → Q m.
Proof.
intros Hsingleton Hinsert m Hm. induction m as [|i x m Hi IH] using map_ind.
{ by destruct map_Exists_empty. }
apply map_Exists_insert in Hm as [?|?]; [|by eauto..].
clear IH. induction m