diff --git a/src/Init/Core.lean b/src/Init/Core.lean index 797e1b024f..ee0b64d603 100644 --- a/src/Init/Core.lean +++ b/src/Init/Core.lean @@ -938,6 +938,34 @@ term. theorem eqRec_heq {α : Sort u} {φ : α → Sort v} {a a' : α} : (h : a = a') → (p : φ a) → HEq (Eq.recOn (motive := fun x _ => φ x) h p) p | rfl, p => HEq.refl p +/-- +Heterogenous equality with an `Eq.rec` application on the left is equivalent to a heterogenous +equality on the original term. +-/ +theorem eqRec_heq_iff {α : Sort u} {a : α} {motive : (b : α) → a = b → Sort v} + {b : α} {refl : motive a (Eq.refl a)} {h : a = b} {c : motive b h} : + HEq (@Eq.rec α a motive refl b h) c ↔ HEq refl c := + h.rec (fun _ => ⟨id, id⟩) c + +/-- +Heterogenous equality with an `Eq.rec` application on the right is equivalent to a heterogenous +equality on the original term. +-/ +theorem heq_eqRec_iff {α : Sort u} {a : α} {motive : (b : α) → a = b → Sort v} + {b : α} {refl : motive a (Eq.refl a)} {h : a = b} {c : motive b h} : + HEq c (@Eq.rec α a motive refl b h) ↔ HEq c refl := + h.rec (fun _ => ⟨id, id⟩) c + +/-- +Moves an cast using `Eq.rec` from the function to the argument. +Note: because the motive isn't reliably detected by unification, +it needs to be provided as an explicit parameter. +-/ +theorem apply_eqRec {α : Sort u} {a : α} (motive : (b : α) → a = b → Sort v) + {b : α} {h : a = b} {c : motive a (Eq.refl a) → β} {d : motive b h} : + @Eq.rec α a (fun b h => motive b h → β) c b h d = c (h.symm ▸ d) := by + cases h; rfl + /-- If casting a term with `Eq.rec` to another type makes it equal to some other term, then the two terms are heterogeneously equal. @@ -983,7 +1011,7 @@ theorem HEq.comm {a : α} {b : β} : HEq a b ↔ HEq b a := Iff.intro HEq.symm H theorem heq_comm {a : α} {b : β} : HEq a b ↔ HEq b a := HEq.comm @[symm] theorem Iff.symm (h : a ↔ b) : b ↔ a := Iff.intro h.mpr h.mp -theorem Iff.comm: (a ↔ b) ↔ (b ↔ a) := Iff.intro Iff.symm Iff.symm +theorem Iff.comm : (a ↔ b) ↔ (b ↔ a) := Iff.intro Iff.symm Iff.symm theorem iff_comm : (a ↔ b) ↔ (b ↔ a) := Iff.comm @[symm] theorem And.symm : a ∧ b → b ∧ a := fun ⟨ha, hb⟩ => ⟨hb, ha⟩ @@ -1148,12 +1176,12 @@ theorem dif_eq_if (c : Prop) {h : Decidable c} {α : Sort u} (t : α) (e : α) : | isTrue _ => rfl | isFalse _ => rfl -instance {c t e : Prop} [dC : Decidable c] [dT : Decidable t] [dE : Decidable e] : Decidable (if c then t else e) := +instance {c t e : Prop} [dC : Decidable c] [dT : Decidable t] [dE : Decidable e] : Decidable (if c then t else e) := match dC with | isTrue _ => dT | isFalse _ => dE -instance {c : Prop} {t : c → Prop} {e : ¬c → Prop} [dC : Decidable c] [dT : ∀ h, Decidable (t h)] [dE : ∀ h, Decidable (e h)] : Decidable (if h : c then t h else e h) := +instance {c : Prop} {t : c → Prop} {e : ¬c → Prop} [dC : Decidable c] [dT : ∀ h, Decidable (t h)] [dE : ∀ h, Decidable (e h)] : Decidable (if h : c then t h else e h) := match dC with | isTrue hc => dT hc | isFalse hc => dE hc @@ -1869,9 +1897,7 @@ protected abbrev hrecOn (f : (a : α) → motive (Quot.mk r a)) (c : (a b : α) → (p : r a b) → HEq (f a) (f b)) : motive q := - Quot.recOn q f fun a b p => eq_of_heq <| - have p₁ : HEq (Eq.ndrec (f a) (sound p)) (f a) := eqRec_heq (sound p) (f a) - HEq.trans p₁ (c a b p) + Quot.recOn q f fun a b p => eq_of_heq (eqRec_heq_iff.mpr (c a b p)) end end Quot @@ -2234,6 +2260,27 @@ theorem funext {α : Sort u} {β : α → Sort v} {f g : (x : α) → β x} show extfunApp (Quot.mk eqv f) = extfunApp (Quot.mk eqv g) exact congrArg extfunApp (Quot.sound h) +/-- +Like `Quot.liftOn q f h` but allows `f a` to "know" that `q = Quot.mk r a`. +-/ +protected abbrev Quot.pliftOn {α : Sort u} {r : α → α → Prop} + (q : Quot r) + (f : (a : α) → q = Quot.mk r a → β) + (h : ∀ (a b : α) (h h'), r a b → f a h = f b h') : β := + q.rec (motive := fun q' => q = q' → β) f + (fun a b p => funext fun h' => + (apply_eqRec (motive := fun b _ => q = b)).trans + (@h a b (h'.trans (sound p).symm) h' p)) rfl + +/-- +Like `Quotient.liftOn q f h` but allows `f a` to "know" that `q = Quotient.mk s a`. +-/ +protected abbrev Quotient.pliftOn {α : Sort u} {s : Setoid α} + (q : Quotient s) + (f : (a : α) → q = Quotient.mk s a → β) + (h : ∀ (a b : α) (h h'), a ≈ b → f a h = f b h') : β := + Quot.pliftOn q f h + instance Pi.instSubsingleton {α : Sort u} {β : α → Sort v} [∀ a, Subsingleton (β a)] : Subsingleton (∀ a, β a) where allEq f g := funext fun a => Subsingleton.elim (f a) (g a) diff --git a/src/Std/Data.lean b/src/Std/Data.lean index 0b27735c58..38b090df67 100644 --- a/src/Std/Data.lean +++ b/src/Std/Data.lean @@ -10,6 +10,9 @@ import Std.Data.HashSet import Std.Data.DTreeMap import Std.Data.TreeMap import Std.Data.TreeSet +import Std.Data.ExtDHashMap +import Std.Data.ExtHashMap +import Std.Data.ExtHashSet -- The imports above only import the modules needed to work with the version which bundles -- the well-formedness invariant, so we need to additionally import the files that deal with the diff --git a/src/Std/Data/DHashMap/Basic.lean b/src/Std/Data/DHashMap/Basic.lean index 8a5997f3e6..e10e1468b2 100644 --- a/src/Std/Data/DHashMap/Basic.lean +++ b/src/Std/Data/DHashMap/Basic.lean @@ -18,7 +18,7 @@ Lemmas about the operations on `Std.Data.DHashMap` are available in the module `Std.Data.DHashMap.Lemmas`. See the module `Std.Data.DHashMap.Raw` for a variant of this type which is safe to use in -nested inductive types. +nested inductive types and the module `Std.Data.ExtDHashMap` for a variant with extensionality. For implementation notes, see the docstring of the module `Std.Data.DHashMap.Internal.Defs`. -/ @@ -54,9 +54,12 @@ should be an equivalence relation and `a == b` should imply `hash a = hash b` (s instance is lawful, i.e., if `a == b` implies `a = b`. These hash maps contain a bundled well-formedness invariant, which means that they cannot -be used in nested inductive types. For these use cases, `Std.Data.DHashMap.Raw` and -`Std.Data.DHashMap.Raw.WF` unbundle the invariant from the hash map. When in doubt, prefer +be used in nested inductive types. For these use cases, `Std.DHashMap.Raw` and +`Std.DHashMap.Raw.WF` unbundle the invariant from the hash map. When in doubt, prefer `DHashMap` over `DHashMap.Raw`. + +For a variant that is more convenient for use in proofs because of extensionalities, see +`Std.ExtDHashMap` which is defined in the module `Std.Data.ExtDHashMap`. -/ def DHashMap (α : Type u) (β : α → Type v) [BEq α] [Hashable α] := { m : DHashMap.Raw α β // m.WF } diff --git a/src/Std/Data/DHashMap/Internal/RawLemmas.lean b/src/Std/Data/DHashMap/Internal/RawLemmas.lean index e2ba6f36b2..18a4710e07 100644 --- a/src/Std/Data/DHashMap/Internal/RawLemmas.lean +++ b/src/Std/Data/DHashMap/Internal/RawLemmas.lean @@ -1178,8 +1178,6 @@ theorem foldRevM_eq_foldrM_toList [Monad m'] [LawfulMonad m'] {f : δ → α → β → m' δ} {init : δ} : Raw.Internal.foldRevM f init m.1 = (Raw.Const.toList m.1).foldrM (fun a b => f b a.1 a.2) init := by - have :=Raw.foldRevM_eq_foldrM_toListModel (m := m') (b := m.1) (init := init) (f := f) - simp_to_model [foldRevM, Const.toList] using List.foldrM_eq_foldrM_toProd' theorem foldRev_eq_foldr_toList {f : δ → α → β → δ} {init : δ} : @@ -1199,6 +1197,16 @@ end Const end monadic +section insertMany + +variable {ρ : Type w} [ForIn Id ρ ((a : α) × β a)] + +@[elab_as_elim] +theorem insertMany_ind {motive : Raw₀ α β → Prop} (m : Raw₀ α β) (l : ρ) + (init : motive m) (insert : ∀ m a b, motive m → motive (m.insert a b)) : + motive (m.insertMany l).1 := + (m.insertMany l).2 motive (insert _ _ _) init + @[simp] theorem insertMany_nil : m.insertMany [] = m := by @@ -1227,6 +1235,14 @@ theorem contains_of_contains_insertMany_list [EquivBEq α] [LawfulHashable α] ( (m.insertMany l).1.contains k → (l.map Sigma.fst).contains k = false → m.contains k := by simp_to_model [insertMany, contains] using List.containsKey_of_containsKey_insertList +theorem contains_insertMany_of_contains [EquivBEq α] [LawfulHashable α] (h : m.1.WF) + {l : ρ} {k : α} (h' : m.contains k) : (m.insertMany l).1.contains k := by + refine (?_ : _ ∧ (m.insertMany l).1.1.WF).1 + refine insertMany_ind m l ⟨h', h⟩ ?_ + intro m a b ⟨h', h⟩ + simp only [h, contains_insert, h', Bool.or_true, true_and] + exact h.insert₀ + theorem get?_insertMany_list_of_contains_eq_false [LawfulBEq α] (h : m.1.WF) {l : List ((a : α) × β a)} {k : α} (h' : (l.map Sigma.fst).contains k = false) : @@ -1352,6 +1368,15 @@ theorem size_le_size_insertMany_list [EquivBEq α] [LawfulHashable α] (h : m.1. m.1.size ≤ (m.insertMany l).1.1.size := by simp_to_model [insertMany, size] using List.length_le_length_insertList +theorem size_le_size_insertMany [EquivBEq α] [LawfulHashable α] (h : m.1.WF) + {l : ρ} : m.1.size ≤ (m.insertMany l).1.1.size := by + refine (?_ : _ ∧ (m.insertMany l).1.1.WF).1 + refine insertMany_ind m l ⟨Nat.le_refl _, h⟩ ?_ + intro m' a b ⟨h', h⟩ + constructor + · exact Nat.le_trans h' (size_le_size_insert m' h) + · exact h.insert₀ + theorem size_insertMany_list_le [EquivBEq α] [LawfulHashable α] (h : m.1.WF) {l : List ((a : α) × β a)} : (m.insertMany l).1.1.size ≤ m.1.size + l.length := by @@ -1363,9 +1388,26 @@ theorem isEmpty_insertMany_list [EquivBEq α] [LawfulHashable α] (h : m.1.WF) (m.insertMany l).1.1.isEmpty = (m.1.isEmpty && l.isEmpty) := by simp_to_model [insertMany, isEmpty] using List.isEmpty_insertList +theorem isEmpty_of_isEmpty_insertMany [EquivBEq α] [LawfulHashable α] (h : m.1.WF) + {l : ρ} : (m.insertMany l).1.1.isEmpty → m.1.isEmpty := by + refine (?_ : _ ∧ (m.insertMany l).1.1.WF).1 + refine insertMany_ind m l ⟨id, h⟩ ?_ + intro m' a b ⟨h', h⟩ + constructor + · intro h'' + simp only [isEmpty_insert, h, Bool.false_eq_true] at h'' + · exact h.insert₀ + namespace Const variable {β : Type v} (m : Raw₀ α (fun _ => β)) +variable {ρ : Type w} [ForIn Id ρ (α × β)] + +@[elab_as_elim] +theorem insertMany_ind {motive : Raw₀ α (fun _ => β) → Prop} (m : Raw₀ α fun _ => β) (l : ρ) + (init : motive m) (insert : ∀ m a b, motive m → motive (m.insert a b)) : + motive (insertMany m l).1 := + (insertMany m l).2 motive (insert _ _ _) init @[simp] theorem insertMany_nil : @@ -1395,6 +1437,14 @@ theorem contains_of_contains_insertMany_list [EquivBEq α] [LawfulHashable α] ( (insertMany m l).1.contains k → (l.map Prod.fst).contains k = false → m.contains k := by simp_to_model [Const.insertMany, contains] using List.containsKey_of_containsKey_insertListConst +theorem contains_insertMany_of_contains [EquivBEq α] [LawfulHashable α] (h : m.1.WF) + {l : ρ} {k : α} (h' : m.contains k) : (insertMany m l).1.contains k := by + refine (?_ : _ ∧ (insertMany m l).1.1.WF).1 + refine insertMany_ind m l ⟨h', h⟩ ?_ + intro m a b ⟨h', h⟩ + simp only [h, contains_insert, h', Bool.or_true, true_and] + exact h.insert₀ + theorem getKey?_insertMany_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α] (h : m.1.WF) {l : List (α × β)} {k : α} (h' : (l.map Prod.fst).contains k = false) : @@ -1466,6 +1516,15 @@ theorem size_le_size_insertMany_list [EquivBEq α] [LawfulHashable α] (h : m.1. m.1.size ≤ (insertMany m l).1.1.size := by simp_to_model [Const.insertMany, size] using List.length_le_length_insertListConst +theorem size_le_size_insertMany [EquivBEq α] [LawfulHashable α] (h : m.1.WF) + {l : ρ} : m.1.size ≤ (insertMany m l).1.1.size := by + refine (?_ : _ ∧ (insertMany m l).1.1.WF).1 + refine insertMany_ind m l ⟨Nat.le_refl _, h⟩ ?_ + intro m' a b ⟨h', h⟩ + constructor + · exact Nat.le_trans h' (size_le_size_insert m' h) + · exact h.insert₀ + theorem size_insertMany_list_le [EquivBEq α] [LawfulHashable α] (h : m.1.WF) {l : List (α × β)} : (insertMany m l).1.1.size ≤ m.1.size + l.length := by @@ -1477,6 +1536,16 @@ theorem isEmpty_insertMany_list [EquivBEq α] [LawfulHashable α] (h : m.1.WF) (insertMany m l).1.1.isEmpty = (m.1.isEmpty && l.isEmpty) := by simp_to_model [Const.insertMany, isEmpty] using List.isEmpty_insertListConst +theorem isEmpty_of_isEmpty_insertMany [EquivBEq α] [LawfulHashable α] (h : m.1.WF) + {l : ρ} : (insertMany m l).1.1.isEmpty → m.1.isEmpty := by + refine (?_ : _ ∧ (insertMany m l).1.1.WF).1 + refine insertMany_ind m l ⟨id, h⟩ ?_ + intro m' a b ⟨h', h⟩ + constructor + · intro h'' + simp only [isEmpty_insert, h, Bool.false_eq_true] at h'' + · exact h.insert₀ + theorem get?_insertMany_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α] (h : m.1.WF) {l : List (α × β)} {k : α} (h' : (l.map Prod.fst).contains k = false) : @@ -1532,6 +1601,15 @@ theorem getD_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α] (h : m.1.W variable (m : Raw₀ α (fun _ => Unit)) +variable {ρ : Type w} [ForIn Id ρ α] + +@[elab_as_elim] +theorem insertManyIfNewUnit_ind {motive : Raw₀ α (fun _ => Unit) → Prop} + (m : Raw₀ α fun _ => Unit) (l : ρ) + (init : motive m) (insert : ∀ m a, motive m → motive (m.insertIfNew a ())) : + motive (insertManyIfNewUnit m l).1 := + (insertManyIfNewUnit m l).2 motive (insert _ _) init + @[simp] theorem insertManyIfNewUnit_nil : insertManyIfNewUnit m [] = m := by @@ -1561,6 +1639,14 @@ theorem contains_of_contains_insertManyIfNewUnit_list [EquivBEq α] [LawfulHasha simp_to_model [Const.insertManyIfNewUnit, contains] using List.containsKey_of_containsKey_insertListIfNewUnit +theorem contains_insertManyIfNewUnit_of_contains [EquivBEq α] [LawfulHashable α] (h : m.1.WF) + {l : ρ} {k : α} (h' : m.contains k) : (insertManyIfNewUnit m l).1.contains k := by + refine (?_ : _ ∧ (insertManyIfNewUnit m l).1.1.WF).1 + refine insertManyIfNewUnit_ind m l ⟨h', h⟩ ?_ + intro m a ⟨h', h⟩ + simp only [h, contains_insertIfNew, h', Bool.or_true, true_and] + exact h.insertIfNew₀ + theorem getKey?_insertManyIfNewUnit_list_of_contains_eq_false_of_contains_eq_false [EquivBEq α] [LawfulHashable α] (h : m.1.WF) {l : List α} {k : α} : @@ -1652,6 +1738,15 @@ theorem size_le_size_insertManyIfNewUnit_list [EquivBEq α] [LawfulHashable α] m.1.size ≤ (insertManyIfNewUnit m l).1.1.size := by simp_to_model [Const.insertManyIfNewUnit, size] using List.length_le_length_insertListIfNewUnit +theorem size_le_size_insertManyIfNewUnit [EquivBEq α] [LawfulHashable α] (h : m.1.WF) + {l : ρ} : m.1.size ≤ (insertManyIfNewUnit m l).1.1.size := by + refine (?_ : _ ∧ (insertManyIfNewUnit m l).1.1.WF).1 + refine insertManyIfNewUnit_ind m l ⟨Nat.le_refl _, h⟩ ?_ + intro m' a ⟨h', h⟩ + constructor + · exact Nat.le_trans h' (size_le_size_insertIfNew m' h) + · exact h.insertIfNew₀ + theorem size_insertManyIfNewUnit_list_le [EquivBEq α] [LawfulHashable α] (h : m.1.WF) {l : List α} : (insertManyIfNewUnit m l).1.1.size ≤ m.1.size + l.length := by @@ -1663,6 +1758,16 @@ theorem isEmpty_insertManyIfNewUnit_list [EquivBEq α] [LawfulHashable α] (h : (insertManyIfNewUnit m l).1.1.isEmpty = (m.1.isEmpty && l.isEmpty) := by simp_to_model [Const.insertManyIfNewUnit, isEmpty] using List.isEmpty_insertListIfNewUnit +theorem isEmpty_of_isEmpty_insertManyIfNewUnit [EquivBEq α] [LawfulHashable α] (h : m.1.WF) + {l : ρ} : (insertManyIfNewUnit m l).1.1.isEmpty → m.1.isEmpty := by + refine (?_ : _ ∧ (insertManyIfNewUnit m l).1.1.WF).1 + refine insertManyIfNewUnit_ind m l ⟨id, h⟩ ?_ + intro m' a ⟨h', h⟩ + constructor + · intro h'' + simp only [isEmpty_insertIfNew, h, Bool.false_eq_true] at h'' + · exact h.insertIfNew₀ + theorem get?_insertManyIfNewUnit_list [EquivBEq α] [LawfulHashable α] (h : m.1.WF) {l : List α} {k : α} : get? (insertManyIfNewUnit m l).1 k = @@ -2329,6 +2434,8 @@ abbrev getD_insertManyIfNewUnit_empty_list := @getD_insertManyIfNewUnit_emptyWit end Const +end insertMany + section Alter theorem isEmpty_alter_eq_isEmpty_erase [LawfulBEq α] (h : m.1.WF) {k : α} @@ -3069,10 +3176,20 @@ theorem modify_equiv_congr (h₁ : m₁.1.WF) (h₂ : m₂.1.WF) (h : m₁.1 ~m {k : α} (f : β → β) : (modify m₁ k f).1 ~m (modify m₂ k f).1 := by simp_to_model [Equiv, Const.modify] using List.Const.modifyKey_of_perm _ h.1 +theorem equiv_of_forall_getKey_eq_of_forall_get?_eq (h₁ : m₁.1.WF) (h₂ : m₂.1.WF) : + (∀ k hk hk', m₁.getKey k hk = m₂.getKey k hk') → (∀ k, get? m₁ k = get? m₂ k) → m₁.1 ~m m₂.1 := by + simp_to_model [getKey, Const.get?, contains, Equiv] using List.getKey_getValue?_ext + +@[deprecated equiv_of_forall_getKey_eq_of_forall_get?_eq (since := "2025-04-25")] theorem equiv_of_forall_getKey?_eq_of_forall_get?_eq (h₁ : m₁.1.WF) (h₂ : m₂.1.WF) : (∀ k, m₁.getKey? k = m₂.getKey? k) → (∀ k, get? m₁ k = get? m₂ k) → m₁.1 ~m m₂.1 := by simp_to_model [getKey?, Const.get?, Equiv] using List.getKey?_getValue?_ext +theorem equiv_of_forall_get?_eq {α : Type u} [BEq α] [Hashable α] [LawfulBEq α] + {m₁ m₂ : Raw₀ α fun _ => β} (h₁ : m₁.1.WF) (h₂ : m₂.1.WF) : + (∀ k, get? m₁ k = get? m₂ k) → m₁.1 ~m m₂.1 := by + simpa only [Const.get?_eq_get?, h₁, h₂] using Raw₀.equiv_of_forall_get?_eq m₁ m₂ h₁ h₂ + theorem equiv_of_forall_getKey?_unit_eq {m₁ m₂ : Raw₀ α fun _ => Unit} (h₁ : m₁.1.WF) (h₂ : m₂.1.WF) : (∀ k, m₁.getKey? k = m₂.getKey? k) → m₁.1 ~m m₂.1 := by simp_to_model [getKey?, Equiv] using List.getKey?_ext diff --git a/src/Std/Data/DHashMap/Lemmas.lean b/src/Std/Data/DHashMap/Lemmas.lean index a1abfb9a2f..209ee68d56 100644 --- a/src/Std/Data/DHashMap/Lemmas.lean +++ b/src/Std/Data/DHashMap/Lemmas.lean @@ -11,7 +11,7 @@ import Std.Data.DHashMap.AdditionalOperations /-! # Dependent hash map lemmas -This file contains lemmas about `Std.Data.DHashMap`. Most of the lemmas require +This file contains lemmas about `Std.DHashMap`. Most of the lemmas require `EquivBEq α` and `LawfulHashable α` for the key type `α`. The easiest way to obtain these instances is to provide an instance of `LawfulBEq α`. -/ @@ -1345,6 +1345,8 @@ end Const end monadic +variable {ρ : Type w} [ForIn Id ρ ((a : α) × β a)] + @[simp] theorem insertMany_nil : m.insertMany [] = m := @@ -1359,6 +1361,14 @@ theorem insertMany_cons {l : List ((a : α) × β a)} {k : α} {v : β k} : m.insertMany (⟨k, v⟩ :: l) = (m.insert k v).insertMany l := Subtype.eq (congrArg Subtype.val (Raw₀.insertMany_cons ⟨m.1, m.2.size_buckets_pos⟩) :) +@[elab_as_elim] +theorem insertMany_ind {motive : DHashMap α β → Prop} (m : DHashMap α β) (l : ρ) + (init : motive m) (insert : ∀ m a b, motive m → motive (m.insert a b)) : + motive (m.insertMany l) := + (Raw₀.insertMany_ind ⟨m.1, _⟩ l ⟨m.2, init⟩ + (fun m a b ⟨h, h'⟩ => ⟨h.insert₀, insert ⟨m, h⟩ a b h'⟩) : + ∃ h, motive ⟨(Raw₀.insertMany _ l).1, h⟩).2 + @[simp] theorem contains_insertMany_list [EquivBEq α] [LawfulHashable α] {l : List ((a : α) × β a)} {k : α} : @@ -1377,6 +1387,10 @@ theorem mem_of_mem_insertMany_list [EquivBEq α] [LawfulHashable α] k ∈ m := Raw₀.contains_of_contains_insertMany_list ⟨m.1, _⟩ m.2 mem contains_eq_false +theorem mem_insertMany_of_mem [EquivBEq α] [LawfulHashable α] + {l : ρ} {k : α} (h : k ∈ m) : k ∈ (m.insertMany l) := + Raw₀.contains_insertMany_of_contains ⟨m.1, _⟩ m.2 h + theorem get?_insertMany_list_of_contains_eq_false [LawfulBEq α] {l : List ((a : α) × β a)} {k : α} (contains_eq_false : (l.map Sigma.fst).contains k = false) : @@ -1502,6 +1516,10 @@ theorem size_le_size_insertMany_list [EquivBEq α] [LawfulHashable α] m.size ≤ (m.insertMany l).size := Raw₀.size_le_size_insertMany_list ⟨m.1, _⟩ m.2 +theorem size_le_size_insertMany [EquivBEq α] [LawfulHashable α] + {l : ρ} : m.size ≤ (m.insertMany l).size := + Raw₀.size_le_size_insertMany ⟨m.1, _⟩ m.2 + theorem size_insertMany_list_le [EquivBEq α] [LawfulHashable α] {l : List ((a : α) × β a)} : (m.insertMany l).size ≤ m.size + l.length := @@ -1513,9 +1531,14 @@ theorem isEmpty_insertMany_list [EquivBEq α] [LawfulHashable α] (m.insertMany l).isEmpty = (m.isEmpty && l.isEmpty) := Raw₀.isEmpty_insertMany_list ⟨m.1, _⟩ m.2 +theorem isEmpty_of_isEmpty_insertMany [EquivBEq α] [LawfulHashable α] + {l : ρ} : (m.insertMany l).isEmpty → m.isEmpty := + Raw₀.isEmpty_of_isEmpty_insertMany ⟨m.1, _⟩ m.2 + namespace Const variable {β : Type v} {m : DHashMap α (fun _ => β)} +variable {ρ : Type w} [ForIn Id ρ (α × β)] @[simp] theorem insertMany_nil : @@ -1532,6 +1555,14 @@ theorem insertMany_cons {l : List (α × β)} {k : α} {v : β} : insertMany m (⟨k, v⟩ :: l) = insertMany (m.insert k v) l := Subtype.eq (congrArg Subtype.val (Raw₀.Const.insertMany_cons ⟨m.1, m.2.size_buckets_pos⟩) :) +@[elab_as_elim] +theorem insertMany_ind {motive : DHashMap α (fun _ => β) → Prop} (m : DHashMap α fun _ => β) (l : ρ) + (init : motive m) (insert : ∀ m a b, motive m → motive (m.insert a b)) : + motive (insertMany m l) := + (Raw₀.Const.insertMany_ind ⟨m.1, _⟩ l ⟨m.2, init⟩ + (fun m a b ⟨h, h'⟩ => ⟨h.insert₀, insert ⟨m, h⟩ a b h'⟩) : + ∃ h, motive ⟨(Raw₀.Const.insertMany _ l).1, h⟩).2 + @[simp] theorem contains_insertMany_list [EquivBEq α] [LawfulHashable α] {l : List (α × β)} {k : α} : @@ -1550,6 +1581,10 @@ theorem mem_of_mem_insertMany_list [EquivBEq α] [LawfulHashable α] k ∈ m := Raw₀.Const.contains_of_contains_insertMany_list ⟨m.1, _⟩ m.2 mem contains_eq_false +theorem mem_insertMany_of_mem [EquivBEq α] [LawfulHashable α] + {l : ρ} {k : α} (h : k ∈ m) : k ∈ insertMany m l := + Raw₀.Const.contains_insertMany_of_contains ⟨m.1, _⟩ m.2 h + theorem getKey?_insertMany_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α] {l : List (α × β)} {k : α} (contains_eq_false : (l.map Prod.fst).contains k = false) : @@ -1621,6 +1656,10 @@ theorem size_le_size_insertMany_list [EquivBEq α] [LawfulHashable α] m.size ≤ (insertMany m l).size := Raw₀.Const.size_le_size_insertMany_list ⟨m.1, _⟩ m.2 +theorem size_le_size_insertMany [EquivBEq α] [LawfulHashable α] + {l : ρ} : m.size ≤ (insertMany m l).size := + Raw₀.Const.size_le_size_insertMany ⟨m.1, _⟩ m.2 + theorem size_insertMany_list_le [EquivBEq α] [LawfulHashable α] {l : List (α × β)} : (insertMany m l).size ≤ m.size + l.length := @@ -1632,6 +1671,10 @@ theorem isEmpty_insertMany_list [EquivBEq α] [LawfulHashable α] (insertMany m l).isEmpty = (m.isEmpty && l.isEmpty) := Raw₀.Const.isEmpty_insertMany_list ⟨m.1, _⟩ m.2 +theorem isEmpty_of_isEmpty_insertMany [EquivBEq α] [LawfulHashable α] + {l : ρ} : (insertMany m l).isEmpty → m.isEmpty := + Raw₀.Const.isEmpty_of_isEmpty_insertMany ⟨m.1, _⟩ m.2 + theorem get?_insertMany_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α] {l : List (α × β)} {k : α} (contains_eq_false : (l.map Prod.fst).contains k = false) : @@ -1682,6 +1725,7 @@ theorem getD_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α] Raw₀.Const.getD_insertMany_list_of_mem ⟨m.1, _⟩ m.2 k_beq distinct mem variable {m : DHashMap α (fun _ => Unit)} +variable {ρ : Type w} [ForIn Id ρ α] @[simp] theorem insertManyIfNewUnit_nil : @@ -1700,6 +1744,15 @@ theorem insertManyIfNewUnit_cons {l : List α} {k : α} : Subtype.eq (congrArg Subtype.val (Raw₀.Const.insertManyIfNewUnit_cons ⟨m.1, m.2.size_buckets_pos⟩) :) +@[elab_as_elim] +theorem insertManyIfNewUnit_ind {motive : DHashMap α (fun _ => Unit) → Prop} + (m : DHashMap α fun _ => Unit) (l : ρ) + (init : motive m) (insert : ∀ m a, motive m → motive (m.insertIfNew a ())) : + motive (insertManyIfNewUnit m l) := + (Raw₀.Const.insertManyIfNewUnit_ind ⟨m.1, _⟩ l ⟨m.2, init⟩ + (fun m a ⟨h, h'⟩ => ⟨h.insertIfNew₀, insert ⟨m, h⟩ a h'⟩) : + ∃ h, motive ⟨(Raw₀.Const.insertManyIfNewUnit _ l).1, h⟩).2 + @[simp] theorem contains_insertManyIfNewUnit_list [EquivBEq α] [LawfulHashable α] {l : List α} {k : α} : @@ -1717,6 +1770,10 @@ theorem mem_of_mem_insertManyIfNewUnit_list [EquivBEq α] [LawfulHashable α] k ∈ insertManyIfNewUnit m l → k ∈ m := Raw₀.Const.contains_of_contains_insertManyIfNewUnit_list ⟨m.1, _⟩ m.2 contains_eq_false +theorem mem_insertManyIfNewUnit_of_mem [EquivBEq α] [LawfulHashable α] + {l : ρ} {k : α} (h : k ∈ m) : k ∈ insertManyIfNewUnit m l := + Raw₀.Const.contains_insertManyIfNewUnit_of_contains ⟨m.1, _⟩ m.2 h + theorem getKey?_insertManyIfNewUnit_list_of_not_mem_of_contains_eq_false [EquivBEq α] [LawfulHashable α] {l : List α} {k : α} (not_mem : ¬ k ∈ m) (contains_eq_false : l.contains k = false) : @@ -1810,6 +1867,10 @@ theorem size_le_size_insertManyIfNewUnit_list [EquivBEq α] [LawfulHashable α] m.size ≤ (insertManyIfNewUnit m l).size := Raw₀.Const.size_le_size_insertManyIfNewUnit_list ⟨m.1, _⟩ m.2 +theorem size_le_size_insertManyIfNewUnit [EquivBEq α] [LawfulHashable α] + {l : ρ} : m.size ≤ (insertManyIfNewUnit m l).size := + Raw₀.Const.size_le_size_insertManyIfNewUnit ⟨m.1, _⟩ m.2 + theorem size_insertManyIfNewUnit_list_le [EquivBEq α] [LawfulHashable α] {l : List α} : (insertManyIfNewUnit m l).size ≤ m.size + l.length := @@ -1821,6 +1882,10 @@ theorem isEmpty_insertManyIfNewUnit_list [EquivBEq α] [LawfulHashable α] (insertManyIfNewUnit m l).isEmpty = (m.isEmpty && l.isEmpty) := Raw₀.Const.isEmpty_insertManyIfNewUnit_list ⟨m.1, _⟩ m.2 +theorem isEmpty_of_isEmpty_insertManyIfNewUnit [EquivBEq α] [LawfulHashable α] + {l : ρ} : (insertManyIfNewUnit m l).isEmpty → m.isEmpty := + Raw₀.Const.isEmpty_of_isEmpty_insertManyIfNewUnit ⟨m.1, _⟩ m.2 + theorem get?_insertManyIfNewUnit_list [EquivBEq α] [LawfulHashable α] {l : List α} {k : α} : get? (insertManyIfNewUnit m l) k = @@ -2916,12 +2981,15 @@ namespace Equiv variable {m₁ m₂ m₃ : Std.DHashMap α β} -theorem refl (m : Std.DHashMap α β) : m ~m m := ⟨⟨.rfl⟩⟩ +@[refl, simp] theorem refl (m : Std.DHashMap α β) : m ~m m := ⟨⟨.rfl⟩⟩ theorem rfl : m ~m m := ⟨⟨.rfl⟩⟩ -theorem symm : m₁ ~m m₂ → m₂ ~m m₁ +@[symm] theorem symm : m₁ ~m m₂ → m₂ ~m m₁ | ⟨⟨h⟩⟩ => ⟨⟨h.symm⟩⟩ theorem trans : m₁ ~m m₂ → m₂ ~m m₃ → m₁ ~m m₃ | ⟨⟨h₁⟩⟩, ⟨⟨h₂⟩⟩ => ⟨⟨h₁.trans h₂⟩⟩ + +instance instTrans : Trans (α := Std.DHashMap α β) Equiv Equiv Equiv := ⟨trans⟩ + theorem comm : m₁ ~m m₂ ↔ m₂ ~m m₁ := ⟨symm, symm⟩ theorem congr_left (h : m₁ ~m m₂) : m₁ ~m m₃ ↔ m₂ ~m m₃ := ⟨h.symm.trans, h.trans⟩ theorem congr_right (h : m₁ ~m m₂) : m₃ ~m m₁ ↔ m₃ ~m m₂ := @@ -3066,11 +3134,22 @@ theorem constModify [EquivBEq α] [LawfulHashable α] (k : α) (f : β → β) ( Const.modify m₁ k f ~m Const.modify m₂ k f := ⟨Raw₀.Const.modify_equiv_congr ⟨m₁.1, _⟩ ⟨m₂.1, _⟩ m₁.2 m₂.2 h.1 f⟩ +theorem of_forall_getKey_eq_of_forall_constGet?_eq [EquivBEq α] [LawfulHashable α] + (hk : ∀ k hk hk', m₁.getKey k hk = m₂.getKey k hk') (hv : ∀ k, Const.get? m₁ k = Const.get? m₂ k) : + m₁ ~m m₂ := + ⟨Raw₀.Const.equiv_of_forall_getKey_eq_of_forall_get?_eq ⟨m₁.1, _⟩ ⟨m₂.1, _⟩ m₁.2 m₂.2 hk hv⟩ + +set_option linter.deprecated false in +@[deprecated of_forall_getKey_eq_of_forall_constGet?_eq (since := "2025-04-25")] theorem of_forall_getKey?_eq_of_forall_constGet?_eq [EquivBEq α] [LawfulHashable α] (hk : ∀ k, m₁.getKey? k = m₂.getKey? k) (hv : ∀ k, Const.get? m₁ k = Const.get? m₂ k) : m₁ ~m m₂ := ⟨Raw₀.Const.equiv_of_forall_getKey?_eq_of_forall_get?_eq ⟨m₁.1, _⟩ ⟨m₂.1, _⟩ m₁.2 m₂.2 hk hv⟩ +theorem of_forall_constGet?_eq [LawfulBEq α] (hv : ∀ k, Const.get? m₁ k = Const.get? m₂ k) : + m₁ ~m m₂ := + ⟨Raw₀.Const.equiv_of_forall_get?_eq m₁.2 m₂.2 hv⟩ + theorem of_forall_getKey?_unit_eq [EquivBEq α] [LawfulHashable α] {m₁ m₂ : DHashMap α fun _ => Unit} (h : ∀ k, m₁.getKey? k = m₂.getKey? k) : m₁ ~m m₂ := ⟨Raw₀.Const.equiv_of_forall_getKey?_unit_eq m₁.2 m₂.2 h⟩ @@ -3087,6 +3166,15 @@ end Const end Equiv +/-- Internal implementation detail of the hash map. -/ +def isSetoid (α β) [BEq α] [Hashable α] : Setoid (DHashMap α β) where + r := Equiv + iseqv := { + refl := .refl + symm := .symm + trans := .trans + } + @[simp] theorem equiv_emptyWithCapacity_iff_isEmpty [EquivBEq α] [LawfulHashable α] {c : Nat} : m ~m emptyWithCapacity c ↔ m.isEmpty := diff --git a/src/Std/Data/DHashMap/Raw.lean b/src/Std/Data/DHashMap/Raw.lean index cbc918fbcb..e415eb1e8a 100644 --- a/src/Std/Data/DHashMap/Raw.lean +++ b/src/Std/Data/DHashMap/Raw.lean @@ -8,17 +8,17 @@ import Init.Data.BEq import Init.Data.Hashable import Std.Data.DHashMap.Internal.Defs -/- +/-! # Dependent hash maps with unbundled well-formedness invariant This file develops the type `Std.DHashMap.Raw` of dependent hash maps with unbundled well-formedness invariant. This version is safe to use in nested inductive types. The well-formedness predicate is -available as `Std.Data.DHashMap.Raw.WF` and we prove in this file that all operations preserve +available as `Std.DHashMap.Raw.WF` and we prove in this file that all operations preserve well-formedness. When in doubt, prefer `DHashMap` over `DHashMap.Raw`. -Lemmas about the operations on `Std.Data.DHashMap.Raw` are available in the module +Lemmas about the operations on `Std.DHashMap.Raw` are available in the module `Std.Data.DHashMap.RawLemmas`. -/ diff --git a/src/Std/Data/DHashMap/RawLemmas.lean b/src/Std/Data/DHashMap/RawLemmas.lean index bd9b9ce7a1..69aea52310 100644 --- a/src/Std/Data/DHashMap/RawLemmas.lean +++ b/src/Std/Data/DHashMap/RawLemmas.lean @@ -1438,6 +1438,10 @@ end Const end monadic +section insertMany + +variable {ρ : Type w} [ForIn Id ρ ((a : α) × β a)] + @[simp] theorem insertMany_nil [EquivBEq α] [LawfulHashable α] (h : m.WF) : m.insertMany [] = m := by @@ -1456,6 +1460,17 @@ theorem insertMany_cons {l : List ((a : α) × β a)} {k : α} {v : β k} [Equiv simp_to_raw rw [Raw₀.insertMany_cons] +@[elab_as_elim] +theorem insertMany_ind {motive : Raw α β → Prop} (m : Raw α β) (l : ρ) + (init : motive m) (insert : ∀ m a b, motive m → motive (m.insert a b)) : + motive (m.insertMany l) := by + dsimp [insertMany] + split + · rename_i h + refine Raw₀.insertMany_ind ⟨m, h⟩ l init (fun m a b h => ?_) + simpa only [Raw.insert, m.2, ↓reduceDIte] using insert m.1 a b h + · exact init + @[simp] theorem contains_insertMany_list [EquivBEq α] [LawfulHashable α] (h : m.WF) {l : List ((a : α) × β a)} {k : α} : @@ -1474,6 +1489,11 @@ theorem mem_of_mem_insertMany_list [EquivBEq α] [LawfulHashable α] (h : m.WF) simp only [mem_iff_contains] simp_to_raw using Raw₀.contains_of_contains_insertMany_list +theorem mem_insertMany_of_mem [EquivBEq α] [LawfulHashable α] (h : m.WF) + {l : ρ} {k : α} : k ∈ m → k ∈ m.insertMany l := by + simp only [mem_iff_contains] + simp_to_raw using Raw₀.contains_insertMany_of_contains + theorem get?_insertMany_list_of_contains_eq_false [LawfulBEq α] (h : m.WF) {l : List ((a : α) × β a)} {k : α} (contains_eq_false : (l.map Sigma.fst).contains k = false) : @@ -1600,6 +1620,10 @@ theorem size_le_size_insertMany_list [EquivBEq α] [LawfulHashable α] (h : m.WF m.size ≤ (m.insertMany l).size := by simp_to_raw using Raw₀.size_le_size_insertMany_list ⟨m, _⟩ +theorem size_le_size_insertMany [EquivBEq α] [LawfulHashable α] (h : m.WF) + {l : ρ} : m.size ≤ (m.insertMany l).size := by + simp_to_raw using Raw₀.size_le_size_insertMany ⟨m, _⟩ + theorem size_insertMany_list_le [EquivBEq α] [LawfulHashable α] (h : m.WF) {l : List ((a : α) × β a)} : (m.insertMany l).size ≤ m.size + l.length := by @@ -1611,9 +1635,14 @@ theorem isEmpty_insertMany_list [EquivBEq α] [LawfulHashable α] (h : m.WF) (m.insertMany l).isEmpty = (m.isEmpty && l.isEmpty) := by simp_to_raw using Raw₀.isEmpty_insertMany_list +theorem isEmpty_of_isEmpty_insertMany [EquivBEq α] [LawfulHashable α] (h : m.WF) + {l : ρ} : (m.insertMany l).isEmpty → m.isEmpty := by + simp_to_raw using Raw₀.isEmpty_of_isEmpty_insertMany + namespace Const variable {β : Type v} {m : Raw α (fun _ => β)} +variable {ρ : Type w} [ForIn Id ρ (α × β)] @[simp] theorem insertMany_nil (h : m.WF) : @@ -1634,6 +1663,17 @@ theorem insertMany_cons (h : m.WF) {l : List (α × β)} simp_to_raw rw [Raw₀.Const.insertMany_cons] +@[elab_as_elim] +theorem insertMany_ind {motive : Raw α (fun _ => β) → Prop} (m : Raw α fun _ => β) (l : ρ) + (init : motive m) (insert : ∀ m a b, motive m → motive (m.insert a b)) : + motive (insertMany m l) := by + dsimp [insertMany] + split + · rename_i h + refine Raw₀.Const.insertMany_ind ⟨m, h⟩ l init (fun m a b h => ?_) + simpa only [Raw.insert, m.2, ↓reduceDIte] using insert m.1 a b h + · exact init + @[simp] theorem contains_insertMany_list [EquivBEq α] [LawfulHashable α] (h : m.WF) {l : List (α × β)} {k : α} : @@ -1652,6 +1692,11 @@ theorem mem_of_mem_insertMany_list [EquivBEq α] [LawfulHashable α] (h : m.WF) simp only [mem_iff_contains] simp_to_raw using Raw₀.Const.contains_of_contains_insertMany_list +theorem mem_insertMany_of_mem [EquivBEq α] [LawfulHashable α] (h : m.WF) + {l : ρ} {k : α} : k ∈ m → k ∈ insertMany m l := by + simp only [mem_iff_contains] + simp_to_raw using Raw₀.Const.contains_insertMany_of_contains + theorem getKey?_insertMany_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α] (h : m.WF) {l : List (α × β)} {k : α} (contains_eq_false : (l.map Prod.fst).contains k = false) : @@ -1724,6 +1769,10 @@ theorem size_le_size_insertMany_list [EquivBEq α] [LawfulHashable α] (h : m.WF m.size ≤ (insertMany m l).size := by simp_to_raw using Raw₀.Const.size_le_size_insertMany_list ⟨m, _⟩ +theorem size_le_size_insertMany [EquivBEq α] [LawfulHashable α] (h : m.WF) + {l : ρ} : m.size ≤ (insertMany m l).size := by + simp_to_raw using Raw₀.Const.size_le_size_insertMany ⟨m, _⟩ + theorem size_insertMany_list_le [EquivBEq α] [LawfulHashable α] (h : m.WF) {l : List (α × β)} : (insertMany m l).size ≤ m.size + l.length := by @@ -1735,6 +1784,10 @@ theorem isEmpty_insertMany_list [EquivBEq α] [LawfulHashable α] (h : m.WF) (insertMany m l).isEmpty = (m.isEmpty && l.isEmpty) := by simp_to_raw using Raw₀.Const.isEmpty_insertMany_list +theorem isEmpty_of_isEmpty_insertMany [EquivBEq α] [LawfulHashable α] (h : m.WF) + {l : ρ} : (insertMany m l).isEmpty → m.isEmpty := by + simp_to_raw using Raw₀.Const.isEmpty_of_isEmpty_insertMany + theorem get?_insertMany_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α] (h : m.WF) {l : List (α × β)} {k : α} (contains_eq_false : (l.map Prod.fst).contains k = false) : @@ -1787,6 +1840,8 @@ theorem getD_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α] (h : m.WF) variable {m : Raw α (fun _ => Unit)} +variable {ρ : Type w} [ForIn Id ρ α] + @[simp] theorem insertManyIfNewUnit_nil (h : m.WF) : insertManyIfNewUnit m [] = m := by @@ -1804,6 +1859,18 @@ theorem insertManyIfNewUnit_cons (h : m.WF) {l : List α} {k : α} : simp_to_raw rw [Raw₀.Const.insertManyIfNewUnit_cons] +@[elab_as_elim] +theorem insertManyIfNewUnit_ind {motive : Raw α (fun _ => Unit) → Prop} + (m : Raw α fun _ => Unit) (l : ρ) + (init : motive m) (insert : ∀ m a, motive m → motive (m.insertIfNew a ())) : + motive (insertManyIfNewUnit m l) := by + dsimp [insertManyIfNewUnit] + split + · rename_i h + refine Raw₀.Const.insertManyIfNewUnit_ind ⟨m, h⟩ l init (fun m a h => ?_) + simpa only [Raw.insertIfNew, m.2, ↓reduceDIte] using insert m.1 a h + · exact init + @[simp] theorem contains_insertManyIfNewUnit_list [EquivBEq α] [LawfulHashable α] (h : m.WF) {l : List α} {k : α} : @@ -1822,6 +1889,11 @@ theorem mem_of_mem_insertManyIfNewUnit_list [EquivBEq α] [LawfulHashable α] (h simp only [mem_iff_contains] simp_to_raw using Raw₀.Const.contains_of_contains_insertManyIfNewUnit_list +theorem mem_insertManyIfNewUnit_of_mem [EquivBEq α] [LawfulHashable α] (h : m.WF) + {l : ρ} {k : α} : k ∈ m → k ∈ insertManyIfNewUnit m l := by + simp only [mem_iff_contains] + simp_to_raw using Raw₀.Const.contains_insertManyIfNewUnit_of_contains + theorem getKey?_insertManyIfNewUnit_list_of_not_mem_of_contains_eq_false [EquivBEq α] [LawfulHashable α] (h : m.WF) {l : List α} {k : α} : ¬ k ∈ m → l.contains k = false → @@ -1909,6 +1981,10 @@ theorem size_le_size_insertManyIfNewUnit_list [EquivBEq α] [LawfulHashable α] m.size ≤ (insertManyIfNewUnit m l).size := by simp_to_raw using Raw₀.Const.size_le_size_insertManyIfNewUnit_list ⟨m, _⟩ +theorem size_le_size_insertManyIfNewUnit [EquivBEq α] [LawfulHashable α] (h : m.WF) + {l : ρ} : m.size ≤ (insertManyIfNewUnit m l).size := by + simp_to_raw using Raw₀.Const.size_le_size_insertManyIfNewUnit ⟨m, _⟩ + theorem size_insertManyIfNewUnit_list_le [EquivBEq α] [LawfulHashable α] (h : m.WF) {l : List α} : (insertManyIfNewUnit m l).size ≤ m.size + l.length := by @@ -1920,6 +1996,10 @@ theorem isEmpty_insertManyIfNewUnit_list [EquivBEq α] [LawfulHashable α] (h : (insertManyIfNewUnit m l).isEmpty = (m.isEmpty && l.isEmpty) := by simp_to_raw using Raw₀.Const.isEmpty_insertManyIfNewUnit_list +theorem isEmpty_of_isEmpty_insertManyIfNewUnit [EquivBEq α] [LawfulHashable α] (h : m.WF) + {l : ρ} : (insertManyIfNewUnit m l).isEmpty → m.isEmpty := by + simp_to_raw using Raw₀.Const.isEmpty_of_isEmpty_insertManyIfNewUnit + @[simp] theorem get?_insertManyIfNewUnit_list [EquivBEq α] [LawfulHashable α] (h : m.WF) {l : List α} {k : α} : @@ -1948,6 +2028,8 @@ theorem getD_insertManyIfNewUnit_list end Const +end insertMany + end Raw namespace Raw @@ -3092,12 +3174,15 @@ section Raw variable {α : Type u} {β : α → Type v} {m m₁ m₂ m₃ : Std.DHashMap.Raw α β} -theorem refl (m : Std.DHashMap.Raw α β) : m ~m m := ⟨.rfl⟩ +@[refl, simp] theorem refl (m : Std.DHashMap.Raw α β) : m ~m m := ⟨.rfl⟩ theorem rfl : m ~m m := ⟨.rfl⟩ -theorem symm : m₁ ~m m₂ → m₂ ~m m₁ +@[symm] theorem symm : m₁ ~m m₂ → m₂ ~m m₁ | ⟨h⟩ => ⟨h.symm⟩ theorem trans : m₁ ~m m₂ → m₂ ~m m₃ → m₁ ~m m₃ | ⟨h₁⟩, ⟨h₂⟩ => ⟨h₁.trans h₂⟩ + +instance instTrans : Trans (α := Std.DHashMap.Raw α β) Equiv Equiv Equiv := ⟨trans⟩ + theorem comm : m₁ ~m m₂ ↔ m₂ ~m m₁ := ⟨symm, symm⟩ theorem congr_left (h : m₁ ~m m₂) : m₁ ~m m₃ ↔ m₂ ~m m₃ := ⟨h.symm.trans, h.trans⟩ theorem congr_right (h : m₁ ~m m₂) : m₃ ~m m₁ ↔ m₃ ~m m₂ := @@ -3265,11 +3350,23 @@ theorem constModify [EquivBEq α] [LawfulHashable α] (h₁ : m₁.WF) (h₂ : m Const.modify m₁ k f ~m Const.modify m₂ k f := by simp_to_raw using Raw₀.Const.modify_equiv_congr +theorem of_forall_getKey_eq_of_forall_constGet?_eq [EquivBEq α] [LawfulHashable α] + (h₁ : m₁.WF) (h₂ : m₂.WF) : (∀ k hk hk', m₁.getKey k hk = m₂.getKey k hk') → + (∀ k, Const.get? m₁ k = Const.get? m₂ k) → m₁ ~m m₂ := by + simp only [mem_iff_contains] + simp_to_raw using Raw₀.Const.equiv_of_forall_getKey_eq_of_forall_get?_eq + +set_option linter.deprecated false in +@[deprecated of_forall_getKey_eq_of_forall_constGet?_eq (since := "2025-04-25")] theorem of_forall_getKey?_eq_of_forall_constGet?_eq [EquivBEq α] [LawfulHashable α] (h₁ : m₁.WF) (h₂ : m₂.WF) : (∀ k, m₁.getKey? k = m₂.getKey? k) → (∀ k, Const.get? m₁ k = Const.get? m₂ k) → m₁ ~m m₂ := by simp_to_raw using Raw₀.Const.equiv_of_forall_getKey?_eq_of_forall_get?_eq +theorem of_forall_constGet?_eq [LawfulBEq α] + (h₁ : m₁.WF) (h₂ : m₂.WF) : (∀ k, Const.get? m₁ k = Const.get? m₂ k) → m₁ ~m m₂ := by + simp_to_raw using Raw₀.Const.equiv_of_forall_get?_eq + theorem of_forall_getKey?_unit_eq [EquivBEq α] [LawfulHashable α] {m₁ m₂ : DHashMap.Raw α fun _ => Unit} (h₁ : m₁.WF) (h₂ : m₂.WF) : (∀ k, m₁.getKey? k = m₂.getKey? k) → m₁ ~m m₂ := by diff --git a/src/Std/Data/ExtDHashMap.lean b/src/Std/Data/ExtDHashMap.lean new file mode 100644 index 0000000000..77718d42e5 --- /dev/null +++ b/src/Std/Data/ExtDHashMap.lean @@ -0,0 +1,8 @@ +/- +Copyright (c) 2025 Robin Arnez. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Robin Arnez +-/ +prelude +import Std.Data.ExtDHashMap.Basic +import Std.Data.ExtDHashMap.Lemmas diff --git a/src/Std/Data/ExtDHashMap/Basic.lean b/src/Std/Data/ExtDHashMap/Basic.lean new file mode 100644 index 0000000000..3f72892965 --- /dev/null +++ b/src/Std/Data/ExtDHashMap/Basic.lean @@ -0,0 +1,337 @@ +/- +Copyright (c) 2025 Robin Arnez. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Robin Arnez +-/ +prelude +import Std.Data.DHashMap.Lemmas + +/-! +# Extensional dependent hash maps + +This file develops the type `Std.ExtDHashMap` of extensional dependent hash maps. + +Lemmas about the operations on `Std.ExtDHashMap` are available in the +module `Std.Data.ExtDHashMap.Lemmas`. +-/ + +set_option linter.missingDocs true +set_option autoImplicit false + +attribute [local instance] Std.DHashMap.isSetoid + +universe u v w + +variable {α : Type u} {β : α → Type v} {γ : α → Type w} + +variable {_ : BEq α} {_ : Hashable α} + +open scoped Std.DHashMap + +namespace Std + +/-- +Extensional dependent hash maps. + +This is a simple separate-chaining hash table. The data of the hash map consists of a cached size +and an array of buckets, where each bucket is a linked list of key-value pais. The number of buckets +is always a power of two. The hash map doubles its size upon inserting an element such that the +number of elements is more than 75% of the number of buckets. + +The hash table is backed by an `Array`. Users should make sure that the hash map is used linearly to +avoid expensive copies. + +The hash map uses `==` (provided by the `BEq` typeclass) to compare keys and `hash` (provided by +the `Hashable` typeclass) to hash them. To ensure that the operations behave as expected, `==` +must be an equivalence relation and `a == b` must imply `hash a = hash b` (see also the +`EquivBEq` and `LawfulHashable` typeclasses). Both of these conditions are automatic if the BEq +instance is lawful, i.e., if `a == b` implies `a = b`. + +In contrast to regular dependent hash maps, `Std.ExtDHashMap` offers several extensionality lemmas +and therefore has more lemmas about equality of hash maps. This however also makes it lose the +ability to iterate freely over the hash map. + +These hash maps contain a bundled well-formedness invariant, which means that they cannot +be used in nested inductive types. For these use cases, `Std.DHashMap.Raw` and +`Std.DHashMap.Raw.WF` unbundle the invariant from the hash map. When in doubt, prefer +`DHashMap` over `DHashMap.Raw`. +-/ +def ExtDHashMap (α : Type u) (β : α → Type v) [BEq α] [Hashable α] := + Quotient (DHashMap.isSetoid α β) + +namespace ExtDHashMap + +@[inline, inherit_doc DHashMap.emptyWithCapacity] +def emptyWithCapacity [BEq α] [Hashable α] + (capacity := 8) : ExtDHashMap α β := + Quotient.mk' (DHashMap.emptyWithCapacity capacity) + +instance [BEq α] [Hashable α] : EmptyCollection (ExtDHashMap α β) where + emptyCollection := emptyWithCapacity + +instance [BEq α] [Hashable α] : Inhabited (DHashMap α β) where + default := ∅ + +@[inline, inherit_doc DHashMap.insert] +def insert [EquivBEq α] [LawfulHashable α] (m : ExtDHashMap α β) (a : α) + (b : β a) : ExtDHashMap α β := + m.lift (fun m => Quotient.mk' (m.insert a b)) + (fun m m' (h : m ~m m') => Quotient.sound (h.insert a b)) + +instance [EquivBEq α] [LawfulHashable α] : Singleton ((a : α) × β a) (ExtDHashMap α β) where + singleton | ⟨a, b⟩ => (∅ : ExtDHashMap α β).insert a b + +instance [EquivBEq α] [LawfulHashable α] : Insert ((a : α) × β a) (ExtDHashMap α β) where + insert | ⟨a, b⟩, s => s.insert a b + +instance [EquivBEq α] [LawfulHashable α] : LawfulSingleton ((a : α) × β a) (ExtDHashMap α β) := + ⟨fun _ => rfl⟩ + +@[inline, inherit_doc DHashMap.insertIfNew] +def insertIfNew [EquivBEq α] [LawfulHashable α] (m : ExtDHashMap α β) + (a : α) (b : β a) : ExtDHashMap α β := + m.lift (fun m => Quotient.mk' (m.insertIfNew a b)) + (fun m m' (h : m ~m m') => Quotient.sound (h.insertIfNew a b)) + +@[inline, inherit_doc DHashMap.containsThenInsert] +def containsThenInsert [EquivBEq α] [LawfulHashable α] + (m : ExtDHashMap α β) (a : α) (b : β a) : Bool × ExtDHashMap α β := + m.lift (fun m => let m' := m.containsThenInsert a b; ⟨m'.1, Quotient.mk' m'.2⟩) + (fun m m' (h : m ~m m') => + Prod.ext + (m.containsThenInsert_fst.symm ▸ m'.containsThenInsert_fst.symm ▸ h.contains_eq) + (Quotient.sound <| + m.containsThenInsert_snd.symm ▸ m'.containsThenInsert_snd.symm ▸ h.insert a b)) + +@[inline, inherit_doc DHashMap.containsThenInsertIfNew] +def containsThenInsertIfNew [EquivBEq α] [LawfulHashable α] + (m : ExtDHashMap α β) (a : α) (b : β a) : Bool × ExtDHashMap α β := + m.lift (fun m => let m' := m.containsThenInsertIfNew a b; ⟨m'.1, Quotient.mk' m'.2⟩) + (fun m m' (h : m ~m m') => + Prod.ext + (m.containsThenInsertIfNew_fst.symm ▸ m'.containsThenInsertIfNew_fst.symm ▸ h.contains_eq) + (Quotient.sound <| + m.containsThenInsertIfNew_snd.symm ▸ m'.containsThenInsertIfNew_snd.symm ▸ h.insertIfNew a b)) + +@[inline, inherit_doc DHashMap.getThenInsertIfNew?] +def getThenInsertIfNew? [LawfulBEq α] + (m : ExtDHashMap α β) (a : α) (b : β a) : Option (β a) × ExtDHashMap α β := + m.lift (fun m => let m' := m.getThenInsertIfNew? a b; ⟨m'.1, Quotient.mk' m'.2⟩) + (fun m m' (h : m ~m m') => + Prod.ext + (m.getThenInsertIfNew?_fst.symm ▸ m'.getThenInsertIfNew?_fst.symm ▸ h.get?_eq) + (Quotient.sound <| + m.getThenInsertIfNew?_snd.symm ▸ m'.getThenInsertIfNew?_snd.symm ▸ h.insertIfNew a b)) + +@[inline, inherit_doc DHashMap.get?] +def get? [LawfulBEq α] (m : ExtDHashMap α β) + (a : α) : Option (β a) := + m.lift (fun m => m.get? a) (fun m m' (h : m ~m m') => h.get?_eq) + +@[inline, inherit_doc DHashMap.contains] +def contains [EquivBEq α] [LawfulHashable α] (m : ExtDHashMap α β) (a : α) : + Bool := + m.lift (fun m => m.contains a) (fun m m' (h : m ~m m') => h.contains_eq) + +instance [EquivBEq α] [LawfulHashable α] : Membership α (ExtDHashMap α β) where + mem m a := m.contains a + +instance [EquivBEq α] [LawfulHashable α] {m : ExtDHashMap α β} {a : α} : Decidable (a ∈ m) := + inferInstanceAs <| Decidable (m.contains a) + +@[inline, inherit_doc DHashMap.get] +def get [LawfulBEq α] (m : ExtDHashMap α β) (a : α) + (h : a ∈ m) : β a := + m.pliftOn (fun m h' => m.get a (h' ▸ h :)) + (fun m m' _ _ (h : m ~m m') => h.get_eq _) + +@[inline, inherit_doc DHashMap.get!] +def get! [LawfulBEq α] (m : ExtDHashMap α β) + (a : α) [Inhabited (β a)] : β a := + m.lift (fun m => m.get! a) (fun m m' (h : m ~m m') => h.get!_eq) + +@[inline, inherit_doc DHashMap.getD] +def getD [LawfulBEq α] (m : ExtDHashMap α β) + (a : α) (fallback : β a) : β a := + m.lift (fun m => m.getD a fallback) (fun m m' (h : m ~m m') => h.getD_eq) + +@[inline, inherit_doc DHashMap.erase] +def erase [EquivBEq α] [LawfulHashable α] (m : ExtDHashMap α β) (a : α) : + ExtDHashMap α β := + m.lift (fun m => Quotient.mk' (m.erase a)) + (fun m m' (h : m ~m m') => Quotient.sound (h.erase a)) + +namespace Const + +variable {β : Type v} + +@[inline, inherit_doc DHashMap.Const.get?] +def get? [EquivBEq α] [LawfulHashable α] + (m : ExtDHashMap α (fun _ => β)) (a : α) : Option β := + m.lift (fun m => DHashMap.Const.get? m a) + (fun m m' (h : m ~m m') => h.constGet?_eq) + +@[inline, inherit_doc DHashMap.Const.get] +def get [EquivBEq α] [LawfulHashable α] + (m : ExtDHashMap α (fun _ => β)) (a : α) (h : a ∈ m) : β := + m.pliftOn (fun m h' => DHashMap.Const.get m a (h' ▸ h :)) + (fun m m' _ _ (h : m ~m m') => h.constGet_eq _) + +@[inline, inherit_doc DHashMap.Const.getD] +def getD [EquivBEq α] [LawfulHashable α] + (m : ExtDHashMap α (fun _ => β)) (a : α) (fallback : β) : β := + m.lift (fun m => DHashMap.Const.getD m a fallback) + (fun m m' (h : m ~m m') => h.constGetD_eq) + +@[inline, inherit_doc DHashMap.Const.get!] +def get! [EquivBEq α] [LawfulHashable α] [Inhabited β] + (m : ExtDHashMap α (fun _ => β)) (a : α) : β := + m.lift (fun m => DHashMap.Const.get! m a) + (fun m m' (h : m ~m m') => h.constGet!_eq) + +@[inline, inherit_doc DHashMap.Const.getThenInsertIfNew?] +def getThenInsertIfNew? [EquivBEq α] [LawfulHashable α] + (m : ExtDHashMap α (fun _ => β)) (a : α) (b : β) : + Option β × ExtDHashMap α (fun _ => β) := + m.lift (fun m => + let m' := DHashMap.Const.getThenInsertIfNew? m a b + ⟨m'.1, Quotient.mk' m'.2⟩) + (fun m m' (h : m ~m m') => + Prod.ext + (DHashMap.Const.getThenInsertIfNew?_fst.symm ▸ + DHashMap.Const.getThenInsertIfNew?_fst.symm ▸ h.constGet?_eq) + (Quotient.sound <| + DHashMap.Const.getThenInsertIfNew?_snd.symm ▸ + DHashMap.Const.getThenInsertIfNew?_snd.symm ▸ h.insertIfNew a b)) + +end Const + +@[inline, inherit_doc DHashMap.getKey?] +def getKey? [EquivBEq α] [LawfulHashable α] (m : ExtDHashMap α β) (a : α) : Option α := + m.lift (fun m => m.getKey? a) (fun m m' (h : m ~m m') => h.getKey?_eq) + +@[inline, inherit_doc DHashMap.getKey] +def getKey [EquivBEq α] [LawfulHashable α] (m : ExtDHashMap α β) (a : α) (h : a ∈ m) : α := + m.pliftOn (fun m h' => m.getKey a (h' ▸ h :)) + (fun m m' _ _ (h : m ~m m') => h.getKey_eq _) + +@[inline, inherit_doc DHashMap.getKey!] +def getKey! [EquivBEq α] [LawfulHashable α] [Inhabited α] (m : ExtDHashMap α β) (a : α) : α := + m.lift (fun m => m.getKey! a) (fun m m' (h : m ~m m') => h.getKey!_eq) + +@[inline, inherit_doc DHashMap.getKeyD] +def getKeyD [EquivBEq α] [LawfulHashable α] (m : ExtDHashMap α β) (a : α) (fallback : α) : α := + m.lift (fun m => m.getKeyD a fallback) + (fun m m' (h : m ~m m') => h.getKeyD_eq) + +@[inline, inherit_doc DHashMap.size] +def size [EquivBEq α] [LawfulHashable α] (m : ExtDHashMap α β) : Nat := + m.lift (fun m => m.size) (fun m m' (h : m ~m m') => h.size_eq) + +@[inline, inherit_doc DHashMap.isEmpty] +def isEmpty [EquivBEq α] [LawfulHashable α] (m : ExtDHashMap α β) : Bool := + m.lift (fun m => m.isEmpty) (fun m m' (h : m ~m m') => h.isEmpty_eq) + +-- TODO: add fold similar to `Finset.fold` + +@[inline, inherit_doc DHashMap.filter] +def filter [EquivBEq α] [LawfulHashable α] (f : (a : α) → β a → Bool) + (m : ExtDHashMap α β) : ExtDHashMap α β := + m.lift (fun m => Quotient.mk' (m.filter f)) + (fun m m' (h : m ~m m') => Quotient.sound (h.filter f)) + +@[inline, inherit_doc DHashMap.map] +def map [EquivBEq α] [LawfulHashable α] (f : (a : α) → β a → γ a) + (m : ExtDHashMap α β) : ExtDHashMap α γ := + m.lift (fun m => Quotient.mk' (m.map f)) + (fun m m' (h : m ~m m') => Quotient.sound (h.map f)) + +@[inline, inherit_doc DHashMap.filterMap] +def filterMap [EquivBEq α] [LawfulHashable α] (f : (a : α) → β a → Option (γ a)) + (m : ExtDHashMap α β) : ExtDHashMap α γ := + m.lift (fun m => Quotient.mk' (m.filterMap f)) + (fun m m' (h : m ~m m') => Quotient.sound (h.filterMap f)) + +@[inline, inherit_doc DHashMap.modify] +def modify [LawfulBEq α] (m : ExtDHashMap α β) + (a : α) (f : β a → β a) : ExtDHashMap α β := + m.lift (fun m => Quotient.mk' (m.modify a f)) + (fun m m' (h : m ~m m') => Quotient.sound (h.modify a f)) + +@[inline, inherit_doc DHashMap.Const.modify] +def Const.modify [EquivBEq α] [LawfulHashable α] {β : Type v} (m : ExtDHashMap α (fun _ => β)) + (a : α) (f : β → β) : ExtDHashMap α (fun _ => β) := + m.lift (fun m => Quotient.mk' (DHashMap.Const.modify m a f)) + (fun m m' (h : m ~m m') => Quotient.sound (h.constModify a f)) + +@[inline, inherit_doc DHashMap.alter] +def alter [LawfulBEq α] (m : ExtDHashMap α β) + (a : α) (f : Option (β a) → Option (β a)) : ExtDHashMap α β := + m.lift (fun m => Quotient.mk' (m.alter a f)) + (fun m m' (h : m ~m m') => Quotient.sound (h.alter a f)) + +@[inline, inherit_doc DHashMap.Const.alter] +def Const.alter [EquivBEq α] [LawfulHashable α] {β : Type v} (m : ExtDHashMap α (fun _ => β)) + (a : α) (f : Option β → Option β) : ExtDHashMap α (fun _ => β) := + m.lift (fun m => Quotient.mk' (DHashMap.Const.alter m a f)) + (fun m m' (h : m ~m m') => Quotient.sound (h.constAlter a f)) + +/- +Note: We can't use the existing functions because weird (noncomputable) `ForIn` instances +can break congruence. The subtype is still used to provide the `insertMany_ind` theorem. +-/ + +@[inline, inherit_doc DHashMap.insertMany] +def insertMany [EquivBEq α] [LawfulHashable α] {ρ : Type w} + [ForIn Id ρ ((a : α) × β a)] (m : ExtDHashMap α β) (l : ρ) : ExtDHashMap α β := Id.run do + let mut m : { x // ∀ P : ExtDHashMap α β → Prop, + P m → (∀ {m a b}, P m → P (m.insert a b)) → P x } := ⟨m, fun _ h _ => h⟩ + for ⟨a, b⟩ in l do + m := ⟨m.1.insert a b, fun _ init step => step (m.2 _ init step)⟩ + return m.1 + +@[inline, inherit_doc DHashMap.Const.insertMany] +def Const.insertMany [EquivBEq α] [LawfulHashable α] {β : Type v} {ρ : Type w} + [ForIn Id ρ (α × β)] (m : ExtDHashMap α (fun _ => β)) + (l : ρ) : ExtDHashMap α (fun _ => β) := Id.run do + let mut m : { x // ∀ P : ExtDHashMap α (fun _ => β) → Prop, + P m → (∀ {m a b}, P m → P (m.insert a b)) → P x } := ⟨m, fun _ h _ => h⟩ + for (a, b) in l do + m := ⟨m.1.insert a b, fun _ init step => step (m.2 _ init step)⟩ + return m.1 + +@[inline, inherit_doc DHashMap.Const.insertManyIfNewUnit] +def Const.insertManyIfNewUnit [EquivBEq α] [LawfulHashable α] {ρ : Type w} + [ForIn Id ρ α] (m : ExtDHashMap α (fun _ => Unit)) + (l : ρ) : ExtDHashMap α (fun _ => Unit) := Id.run do + let mut m : { x // ∀ P : ExtDHashMap α (fun _ => Unit) → Prop, + P m → (∀ {m a}, P m → P (m.insertIfNew a ())) → P x } := ⟨m, fun _ h _ => h⟩ + for a in l do + m := ⟨m.1.insertIfNew a (), fun _ init step => step (m.2 _ init step)⟩ + return m.1 + +-- TODO (after verification): partition, union + +@[inline, inherit_doc DHashMap.Const.unitOfArray] +def Const.unitOfArray [BEq α] [Hashable α] (l : Array α) : + ExtDHashMap α (fun _ => Unit) := + Quotient.mk' (DHashMap.Const.unitOfArray l) + +@[inline, inherit_doc DHashMap.ofList] +def ofList [BEq α] [Hashable α] (l : List ((a : α) × β a)) : + ExtDHashMap α β := + Quotient.mk' (DHashMap.ofList l) + +@[inline, inherit_doc DHashMap.Const.ofList] +def Const.ofList {β : Type v} [BEq α] [Hashable α] (l : List (α × β)) : + ExtDHashMap α (fun _ => β) := + Quotient.mk' (DHashMap.Const.ofList l) + +@[inline, inherit_doc DHashMap.Const.unitOfList] +def Const.unitOfList [BEq α] [Hashable α] (l : List α) : + ExtDHashMap α (fun _ => Unit) := + Quotient.mk' (DHashMap.Const.unitOfList l) + +end ExtDHashMap + +end Std diff --git a/src/Std/Data/ExtDHashMap/Lemmas.lean b/src/Std/Data/ExtDHashMap/Lemmas.lean new file mode 100644 index 0000000000..0369dcad15 --- /dev/null +++ b/src/Std/Data/ExtDHashMap/Lemmas.lean @@ -0,0 +1,3289 @@ +/- +Copyright (c) 2025 Robin Arnez. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Robin Arnez +-/ +prelude +import Std.Data.ExtDHashMap.Basic + +/-! +# Extensional dependent hash map lemmas + +This file contains lemmas about `Std.ExtDHashMap`. +-/ + +set_option linter.missingDocs true +set_option autoImplicit false + +attribute [local instance] Std.DHashMap.isSetoid + +universe u v w w' + +variable {α : Type u} {_ : BEq α} {_ : Hashable α} +variable {β : α → Type v} {γ : α → Type w} + +namespace Std.ExtDHashMap + +variable {m : ExtDHashMap α β} + +@[simp] +theorem isEmpty_iff [EquivBEq α] [LawfulHashable α] : m.isEmpty ↔ m = ∅ := by + rcases m with ⟨m⟩ + refine m.equiv_empty_iff_isEmpty.symm.trans ?_ + exact ⟨fun h => Quotient.sound h, Quotient.exact⟩ + +@[simp] +theorem isEmpty_eq_false_iff [EquivBEq α] [LawfulHashable α] : m.isEmpty = false ↔ ¬m = ∅ := + (Bool.not_eq_true _).symm.to_iff.trans (not_congr isEmpty_iff) + +@[simp] +theorem empty_eq : ∅ = m ↔ m = ∅ := eq_comm + +@[simp] +theorem emptyWithCapacity_eq [EquivBEq α] [LawfulHashable α] {c} : (emptyWithCapacity c : ExtDHashMap α β) = ∅ := + isEmpty_iff.mp DHashMap.isEmpty_emptyWithCapacity + +@[simp] +theorem not_insert_eq_empty [EquivBEq α] [LawfulHashable α] {k : α} {v : β k} : + ¬m.insert k v = ∅ := + m.inductionOn fun _ => isEmpty_eq_false_iff.mp DHashMap.isEmpty_insert + +theorem mem_iff_contains [EquivBEq α] [LawfulHashable α] {a : α} : a ∈ m ↔ m.contains a := + Iff.rfl + +theorem contains_congr [EquivBEq α] [LawfulHashable α] {a b : α} (hab : a == b) : m.contains a = m.contains b := + m.inductionOn fun _ => DHashMap.contains_congr hab + +theorem mem_congr [EquivBEq α] [LawfulHashable α] {a b : α} (hab : a == b) : a ∈ m ↔ b ∈ m := + m.inductionOn fun _ => DHashMap.mem_congr hab + +@[simp] +theorem contains_empty [EquivBEq α] [LawfulHashable α] {a : α} : (∅ : DHashMap α β).contains a = false := + DHashMap.contains_empty + +@[simp] +theorem not_mem_empty [EquivBEq α] [LawfulHashable α] {a : α} : ¬a ∈ (∅ : DHashMap α β) := + DHashMap.not_mem_empty + +theorem eq_empty_iff_forall_contains [EquivBEq α] [LawfulHashable α] : m = ∅ ↔ ∀ a, m.contains a = false := + isEmpty_iff.symm.trans <| m.inductionOn fun _ => DHashMap.isEmpty_iff_forall_contains + +theorem eq_empty_iff_forall_not_mem [EquivBEq α] [LawfulHashable α] : m = ∅ ↔ ∀ a, ¬a ∈ m := + isEmpty_iff.symm.trans <| m.inductionOn fun _ => DHashMap.isEmpty_iff_forall_not_mem + +@[simp] +theorem insert_eq_insert [EquivBEq α] [LawfulHashable α] {p : (a : α) × β a} : + Insert.insert p m = m.insert p.1 p.2 := + rfl + +@[simp] +theorem singleton_eq_insert [EquivBEq α] [LawfulHashable α] {p : (a : α) × β a} : + Singleton.singleton p = (∅ : DHashMap α β).insert p.1 p.2 := + rfl + +@[simp] +theorem contains_insert [EquivBEq α] [LawfulHashable α] {k a : α} {v : β k} : + (m.insert k v).contains a = (k == a || m.contains a) := + m.inductionOn fun _ => DHashMap.contains_insert + +@[simp] +theorem mem_insert [EquivBEq α] [LawfulHashable α] {k a : α} {v : β k} : a ∈ m.insert k v ↔ k == a ∨ a ∈ m := + m.inductionOn fun _ => DHashMap.mem_insert + +theorem contains_of_contains_insert [EquivBEq α] [LawfulHashable α] {k a : α} {v : β k} : + (m.insert k v).contains a → (k == a) = false → m.contains a := + m.inductionOn fun _ => DHashMap.contains_of_contains_insert + +theorem mem_of_mem_insert [EquivBEq α] [LawfulHashable α] {k a : α} {v : β k} : a ∈ m.insert k v → (k == a) = false → a ∈ m := + m.inductionOn fun _ => DHashMap.mem_of_mem_insert + +theorem contains_insert_self [EquivBEq α] [LawfulHashable α] {k : α} {v : β k} : (m.insert k v).contains k := by simp + +theorem mem_insert_self [EquivBEq α] [LawfulHashable α] {k : α} {v : β k} : k ∈ m.insert k v := by simp + +@[simp] +theorem size_empty [EquivBEq α] [LawfulHashable α] : (∅ : ExtDHashMap α β).size = 0 := rfl + +theorem eq_empty_iff_size_eq_zero [EquivBEq α] [LawfulHashable α] : m = ∅ ↔ m.size = 0 := + isEmpty_iff.symm.trans <| m.inductionOn fun _ => + (Bool.eq_iff_iff.mp DHashMap.isEmpty_eq_size_eq_zero).trans beq_iff_eq + +theorem size_insert [EquivBEq α] [LawfulHashable α] {k : α} {v : β k} : + (m.insert k v).size = if k ∈ m then m.size else m.size + 1 := + m.inductionOn fun _ => DHashMap.size_insert + +theorem size_le_size_insert [EquivBEq α] [LawfulHashable α] {k : α} {v : β k} : m.size ≤ (m.insert k v).size := + m.inductionOn fun _ => DHashMap.size_le_size_insert + +theorem size_insert_le [EquivBEq α] [LawfulHashable α] {k : α} {v : β k} : (m.insert k v).size ≤ m.size + 1 := + m.inductionOn fun _ => DHashMap.size_insert_le + +@[simp] +theorem erase_empty [EquivBEq α] [LawfulHashable α] {k : α} : (∅ : ExtDHashMap α β).erase k = ∅ := + congrArg Quotient.mk' DHashMap.erase_empty + +@[simp] +theorem erase_eq_empty_iff [EquivBEq α] [LawfulHashable α] {k : α} : + m.erase k = ∅ ↔ m = ∅ ∨ m.size = 1 ∧ k ∈ m := by + apply isEmpty_iff.symm.trans + rcases m with ⟨m⟩ + rw [← isEmpty_iff] + dsimp only [erase, isEmpty, Quotient.mk', Quotient.mk, Quotient.lift] + simp only [DHashMap.isEmpty_erase, Bool.or_eq_true, Bool.and_eq_true, beq_iff_eq] + rfl + +@[simp] +theorem contains_erase [EquivBEq α] [LawfulHashable α] {k a : α} : + (m.erase k).contains a = (!(k == a) && m.contains a) := + m.inductionOn fun _ => DHashMap.contains_erase + +@[simp] +theorem mem_erase [EquivBEq α] [LawfulHashable α] {k a : α} : + a ∈ m.erase k ↔ (k == a) = false ∧ a ∈ m := by + simp [mem_iff_contains, contains_erase] + +theorem contains_of_contains_erase [EquivBEq α] [LawfulHashable α] {k a : α} : + (m.erase k).contains a → m.contains a := + m.inductionOn fun _ => DHashMap.contains_of_contains_erase + +theorem mem_of_mem_erase [EquivBEq α] [LawfulHashable α] {k a : α} : a ∈ m.erase k → a ∈ m := by + simp + +theorem size_erase [EquivBEq α] [LawfulHashable α] {k : α} : + (m.erase k).size = if k ∈ m then m.size - 1 else m.size := + m.inductionOn fun _ => DHashMap.size_erase + +theorem size_erase_le [EquivBEq α] [LawfulHashable α] {k : α} : (m.erase k).size ≤ m.size := + m.inductionOn fun _ => DHashMap.size_erase_le + +theorem size_le_size_erase [EquivBEq α] [LawfulHashable α] {k : α} : + m.size ≤ (m.erase k).size + 1 := + m.inductionOn fun _ => DHashMap.size_le_size_erase + +@[simp] +theorem containsThenInsert_fst [EquivBEq α] [LawfulHashable α] {k : α} {v : β k} : (m.containsThenInsert k v).1 = m.contains k := + m.inductionOn fun _ => DHashMap.containsThenInsert_fst + +@[simp] +theorem containsThenInsert_snd [EquivBEq α] [LawfulHashable α] {k : α} {v : β k} : (m.containsThenInsert k v).2 = m.insert k v := + m.inductionOn fun _ => congrArg Quotient.mk' DHashMap.containsThenInsert_snd + +@[simp] +theorem containsThenInsertIfNew_fst [EquivBEq α] [LawfulHashable α] {k : α} {v : β k} : + (m.containsThenInsertIfNew k v).1 = m.contains k := + m.inductionOn fun _ => DHashMap.containsThenInsertIfNew_fst + +@[simp] +theorem containsThenInsertIfNew_snd [EquivBEq α] [LawfulHashable α] {k : α} {v : β k} : + (m.containsThenInsertIfNew k v).2 = m.insertIfNew k v := + m.inductionOn fun _ => congrArg Quotient.mk' DHashMap.containsThenInsertIfNew_snd + +@[simp] +theorem get?_empty [LawfulBEq α] {a : α} : (∅ : ExtDHashMap α β).get? a = none := + DHashMap.get?_empty + +theorem get?_insert [LawfulBEq α] {a k : α} {v : β k} : (m.insert k v).get? a = + if h : k == a then some (cast (congrArg β (eq_of_beq h)) v) else m.get? a := + m.inductionOn fun _ => DHashMap.get?_insert + +@[simp] +theorem get?_insert_self [LawfulBEq α] {k : α} {v : β k} : (m.insert k v).get? k = some v := + m.inductionOn fun _ => DHashMap.get?_insert_self + +theorem contains_eq_isSome_get? [LawfulBEq α] {a : α} : m.contains a = (m.get? a).isSome := + m.inductionOn fun _ => DHashMap.contains_eq_isSome_get? + +theorem mem_iff_isSome_get? [LawfulBEq α] {a : α} : a ∈ m ↔ (m.get? a).isSome := + m.inductionOn fun _ => DHashMap.mem_iff_isSome_get? + +theorem get?_eq_none_of_contains_eq_false [LawfulBEq α] {a : α} : + m.contains a = false → m.get? a = none := + m.inductionOn fun _ => DHashMap.get?_eq_none_of_contains_eq_false + +theorem get?_eq_none [LawfulBEq α] {a : α} : ¬a ∈ m → m.get? a = none := by + simpa [mem_iff_contains] using get?_eq_none_of_contains_eq_false + +theorem get?_erase [LawfulBEq α] {k a : α} : + (m.erase k).get? a = if k == a then none else m.get? a := + m.inductionOn fun _ => DHashMap.get?_erase + +@[simp] +theorem get?_erase_self [LawfulBEq α] {k : α} : (m.erase k).get? k = none := + m.inductionOn fun _ => DHashMap.get?_erase_self + +namespace Const + +variable {β : Type v} {m : ExtDHashMap α (fun _ => β)} + +@[simp] +theorem get?_empty [EquivBEq α] [LawfulHashable α] {a : α} : get? (∅ : ExtDHashMap α (fun _ => β)) a = none := + DHashMap.Const.get?_empty + +theorem get?_insert [EquivBEq α] [LawfulHashable α] {k a : α} {v : β} : + get? (m.insert k v) a = if k == a then some v else get? m a := + m.inductionOn fun _ => DHashMap.Const.get?_insert + +@[simp] +theorem get?_insert_self [EquivBEq α] [LawfulHashable α] {k : α} {v : β} : + get? (m.insert k v) k = some v := + m.inductionOn fun _ => DHashMap.Const.get?_insert_self + +theorem contains_eq_isSome_get? [EquivBEq α] [LawfulHashable α] {a : α} : + m.contains a = (get? m a).isSome := + m.inductionOn fun _ => DHashMap.Const.contains_eq_isSome_get? + +theorem mem_iff_isSome_get? [EquivBEq α] [LawfulHashable α] {a : α} : a ∈ m ↔ (get? m a).isSome := + m.inductionOn fun _ => DHashMap.Const.mem_iff_isSome_get? + +theorem get?_eq_none_of_contains_eq_false [EquivBEq α] [LawfulHashable α] {a : α} : + m.contains a = false → get? m a = none := + m.inductionOn fun _ => DHashMap.Const.get?_eq_none_of_contains_eq_false + +theorem get?_eq_none [EquivBEq α] [LawfulHashable α] {a : α} : ¬a ∈ m → get? m a = none := by + simpa [mem_iff_contains] using get?_eq_none_of_contains_eq_false + +theorem get?_erase [EquivBEq α] [LawfulHashable α] {k a : α} : + Const.get? (m.erase k) a = if k == a then none else get? m a := + m.inductionOn fun _ => DHashMap.Const.get?_erase + +@[simp] +theorem get?_erase_self [EquivBEq α] [LawfulHashable α] {k : α} : get? (m.erase k) k = none := + m.inductionOn fun _ => DHashMap.Const.get?_erase_self + +theorem get?_eq_get? [LawfulBEq α] {a : α} : get? m a = m.get? a := + m.inductionOn fun _ => DHashMap.Const.get?_eq_get? + +theorem get?_congr [EquivBEq α] [LawfulHashable α] {a b : α} (hab : a == b) : get? m a = get? m b := + m.inductionOn fun _ => DHashMap.Const.get?_congr hab + +end Const + +theorem get_insert [LawfulBEq α] {k a : α} {v : β k} {h₁} : + (m.insert k v).get a h₁ = + if h₂ : k == a then + cast (congrArg β (eq_of_beq h₂)) v + else + m.get a (mem_of_mem_insert h₁ (Bool.eq_false_iff.2 h₂)) := + m.inductionOn (fun _ _ => DHashMap.get_insert) h₁ + +@[simp] +theorem get_insert_self [LawfulBEq α] {k : α} {v : β k} : + (m.insert k v).get k mem_insert_self = v := + m.inductionOn fun _ => DHashMap.get_insert_self + +@[simp] +theorem get_erase [LawfulBEq α] {k a : α} {h'} : + (m.erase k).get a h' = m.get a (mem_of_mem_erase h') := + m.inductionOn (fun _ _ => DHashMap.get_erase) h' + +theorem get?_eq_some_get [LawfulBEq α] {a : α} (h) : m.get? a = some (m.get a h) := + m.inductionOn (fun _ h => DHashMap.get?_eq_some_get h) h + +theorem get_eq_get_get? [LawfulBEq α] {a : α} {h} : + m.get a h = (m.get? a).get (mem_iff_isSome_get?.mp h) := + m.inductionOn (fun _ _ => DHashMap.get_eq_get_get?) h + +theorem get_get? [LawfulBEq α] {a : α} {h} : + (m.get? a).get h = m.get a (mem_iff_isSome_get?.mpr h) := + m.inductionOn (fun _ _ => DHashMap.get_get?) h + +namespace Const + +variable {β : Type v} {m : ExtDHashMap α (fun _ => β)} + +theorem get_insert [EquivBEq α] [LawfulHashable α] {k a : α} {v : β} {h₁} : + get (m.insert k v) a h₁ = + if h₂ : k == a then v else get m a (mem_of_mem_insert h₁ (Bool.eq_false_iff.2 h₂)) := + m.inductionOn (fun _ _ => DHashMap.Const.get_insert) h₁ + +@[simp] +theorem get_insert_self [EquivBEq α] [LawfulHashable α] {k : α} {v : β} : + get (m.insert k v) k mem_insert_self = v := + m.inductionOn fun _ => DHashMap.Const.get_insert_self + +@[simp] +theorem get_erase [EquivBEq α] [LawfulHashable α] {k a : α} {h'} : + get (m.erase k) a h' = get m a (mem_of_mem_erase h') := + m.inductionOn (fun _ _ => DHashMap.Const.get_erase) h' + +theorem get?_eq_some_get [EquivBEq α] [LawfulHashable α] {a : α} (h) : + get? m a = some (get m a h) := + m.inductionOn (fun _ h => DHashMap.Const.get?_eq_some_get h) h + +theorem get_eq_get_get? [EquivBEq α] [LawfulHashable α] {a : α} {h} : + get m a h = (get? m a).get (mem_iff_isSome_get?.mp h) := + m.inductionOn (fun _ _ => DHashMap.Const.get_eq_get_get?) h + +theorem get_get? [EquivBEq α] [LawfulHashable α] {a : α} {h} : + (get? m a).get h = get m a (mem_iff_isSome_get?.mpr h) := + m.inductionOn (fun _ _ => DHashMap.Const.get_get?) h + +theorem get_eq_get [LawfulBEq α] {a : α} {h} : get m a h = m.get a h := + m.inductionOn (fun _ _ => DHashMap.Const.get_eq_get) h + +theorem get_congr [EquivBEq α] [LawfulHashable α] {a b : α} (hab : a == b) {h'} : + get m a h' = get m b ((mem_congr hab).1 h') := + m.inductionOn (fun _ hab _ => DHashMap.Const.get_congr hab) hab h' + +end Const + +@[simp] +theorem get!_empty [LawfulBEq α] {a : α} [Inhabited (β a)] : + (∅ : ExtDHashMap α β).get! a = default := + DHashMap.get!_empty + +theorem get!_insert [LawfulBEq α] {k a : α} [Inhabited (β a)] {v : β k} : + (m.insert k v).get! a = + if h : k == a then cast (congrArg β (eq_of_beq h)) v else m.get! a := + m.inductionOn fun _ => DHashMap.get!_insert + +@[simp] +theorem get!_insert_self [LawfulBEq α] {a : α} [Inhabited (β a)] {b : β a} : + (m.insert a b).get! a = b := + m.inductionOn fun _ => DHashMap.get!_insert_self + +theorem get!_eq_default_of_contains_eq_false [LawfulBEq α] {a : α} [Inhabited (β a)] : + m.contains a = false → m.get! a = default := + m.inductionOn fun _ => DHashMap.get!_eq_default_of_contains_eq_false + +theorem get!_eq_default [LawfulBEq α] {a : α} [Inhabited (β a)] : + ¬a ∈ m → m.get! a = default := + m.inductionOn fun _ => DHashMap.get!_eq_default + +theorem get!_erase [LawfulBEq α] {k a : α} [Inhabited (β a)] : + (m.erase k).get! a = if k == a then default else m.get! a := + m.inductionOn fun _ => DHashMap.get!_erase + +@[simp] +theorem get!_erase_self [LawfulBEq α] {k : α} [Inhabited (β k)] : + (m.erase k).get! k = default := + m.inductionOn fun _ => DHashMap.get!_erase_self + +theorem get?_eq_some_get!_of_contains [LawfulBEq α] {a : α} [Inhabited (β a)] : + m.contains a = true → m.get? a = some (m.get! a) := + m.inductionOn fun _ => DHashMap.get?_eq_some_get!_of_contains + +theorem get?_eq_some_get! [LawfulBEq α] {a : α} [Inhabited (β a)] : + a ∈ m → m.get? a = some (m.get! a) := + m.inductionOn fun _ => DHashMap.get?_eq_some_get! + +theorem get!_eq_get!_get? [LawfulBEq α] {a : α} [Inhabited (β a)] : + m.get! a = (m.get? a).get! := + m.inductionOn fun _ => DHashMap.get!_eq_get!_get? + +theorem get_eq_get! [LawfulBEq α] {a : α} [Inhabited (β a)] {h} : + m.get a h = m.get! a := + m.inductionOn (fun _ _ => DHashMap.get_eq_get!) h + +namespace Const + +variable {β : Type v} {m : ExtDHashMap α (fun _ => β)} + +@[simp] +theorem get!_empty [EquivBEq α] [LawfulHashable α] [Inhabited β] {a : α} : get! (∅ : ExtDHashMap α (fun _ => β)) a = default := + DHashMap.Const.get!_empty + +theorem get!_insert [EquivBEq α] [LawfulHashable α] [Inhabited β] {k a : α} {v : β} : + get! (m.insert k v) a = if k == a then v else get! m a := + m.inductionOn fun _ => DHashMap.Const.get!_insert + +@[simp] +theorem get!_insert_self [EquivBEq α] [LawfulHashable α] [Inhabited β] {k : α} {v : β} : + get! (m.insert k v) k = v := + m.inductionOn fun _ => DHashMap.Const.get!_insert_self + +theorem get!_eq_default_of_contains_eq_false [EquivBEq α] [LawfulHashable α] [Inhabited β] {a : α} : + m.contains a = false → get! m a = default := + m.inductionOn fun _ => DHashMap.Const.get!_eq_default_of_contains_eq_false + +theorem get!_eq_default [EquivBEq α] [LawfulHashable α] [Inhabited β] {a : α} : + ¬a ∈ m → get! m a = default := + m.inductionOn fun _ => DHashMap.Const.get!_eq_default + +theorem get!_erase [EquivBEq α] [LawfulHashable α] [Inhabited β] {k a : α} : + get! (m.erase k) a = if k == a then default else get! m a := + m.inductionOn fun _ => DHashMap.Const.get!_erase + +@[simp] +theorem get!_erase_self [EquivBEq α] [LawfulHashable α] [Inhabited β] {k : α} : + get! (m.erase k) k = default := + m.inductionOn fun _ => DHashMap.Const.get!_erase_self + +theorem get?_eq_some_get!_of_contains [EquivBEq α] [LawfulHashable α] [Inhabited β] {a : α} : + m.contains a = true → get? m a = some (get! m a) := + m.inductionOn fun _ => DHashMap.Const.get?_eq_some_get!_of_contains + +theorem get?_eq_some_get! [EquivBEq α] [LawfulHashable α] [Inhabited β] {a : α} : + a ∈ m → get? m a = some (get! m a) := + m.inductionOn fun _ => DHashMap.Const.get?_eq_some_get! + +theorem get!_eq_get!_get? [EquivBEq α] [LawfulHashable α] [Inhabited β] {a : α} : + get! m a = (get? m a).get! := + m.inductionOn fun _ => DHashMap.Const.get!_eq_get!_get? + +theorem get_eq_get! [EquivBEq α] [LawfulHashable α] [Inhabited β] {a : α} {h} : + get m a h = get! m a := + m.inductionOn (fun _ _ => DHashMap.Const.get_eq_get!) h + +theorem get!_eq_get! [LawfulBEq α] [Inhabited β] {a : α} : + get! m a = m.get! a := + m.inductionOn fun _ => DHashMap.Const.get!_eq_get! + +theorem get!_congr [EquivBEq α] [LawfulHashable α] [Inhabited β] {a b : α} (hab : a == b) : + get! m a = get! m b := + m.inductionOn (fun _ hab => DHashMap.Const.get!_congr hab) hab + +end Const + +@[simp] +theorem getD_empty [LawfulBEq α] {a : α} {fallback : β a} : + (∅ : ExtDHashMap α β).getD a fallback = fallback := + DHashMap.getD_empty + +theorem getD_insert [LawfulBEq α] {k a : α} {fallback : β a} {v : β k} : + (m.insert k v).getD a fallback = + if h : k == a then cast (congrArg β (eq_of_beq h)) v else m.getD a fallback := + m.inductionOn fun _ => DHashMap.getD_insert + +@[simp] +theorem getD_insert_self [LawfulBEq α] {k : α} {fallback v : β k} : + (m.insert k v).getD k fallback = v := + m.inductionOn fun _ => DHashMap.getD_insert_self + +theorem getD_eq_fallback_of_contains_eq_false [LawfulBEq α] {a : α} {fallback : β a} : + m.contains a = false → m.getD a fallback = fallback := + m.inductionOn fun _ => DHashMap.getD_eq_fallback_of_contains_eq_false + +theorem getD_eq_fallback [LawfulBEq α] {a : α} {fallback : β a} : + ¬a ∈ m → m.getD a fallback = fallback := + m.inductionOn fun _ => DHashMap.getD_eq_fallback + +theorem getD_erase [LawfulBEq α] {k a : α} {fallback : β a} : + (m.erase k).getD a fallback = if k == a then fallback else m.getD a fallback := + m.inductionOn fun _ => DHashMap.getD_erase + +@[simp] +theorem getD_erase_self [LawfulBEq α] {k : α} {fallback : β k} : + (m.erase k).getD k fallback = fallback := + m.inductionOn fun _ => DHashMap.getD_erase_self + +theorem get?_eq_some_getD_of_contains [LawfulBEq α] {a : α} {fallback : β a} : + m.contains a = true → m.get? a = some (m.getD a fallback) := + m.inductionOn fun _ => DHashMap.get?_eq_some_getD_of_contains + +theorem get?_eq_some_getD [LawfulBEq α] {a : α} {fallback : β a} : + a ∈ m → m.get? a = some (m.getD a fallback) := + m.inductionOn fun _ => DHashMap.get?_eq_some_getD + +theorem getD_eq_getD_get? [LawfulBEq α] {a : α} {fallback : β a} : + m.getD a fallback = (m.get? a).getD fallback := + m.inductionOn fun _ => DHashMap.getD_eq_getD_get? + +theorem get_eq_getD [LawfulBEq α] {a : α} {fallback : β a} {h} : + m.get a h = m.getD a fallback := + m.inductionOn (fun _ _ => DHashMap.get_eq_getD) h + +theorem get!_eq_getD_default [LawfulBEq α] {a : α} [Inhabited (β a)] : + m.get! a = m.getD a default := + m.inductionOn fun _ => DHashMap.get!_eq_getD_default + +namespace Const + +variable {β : Type v} {m : ExtDHashMap α (fun _ => β)} + +@[simp] +theorem getD_empty [EquivBEq α] [LawfulHashable α] {a : α} {fallback : β} : + getD (∅ : ExtDHashMap α (fun _ => β)) a fallback = fallback := + DHashMap.Const.getD_empty + +theorem getD_insert [EquivBEq α] [LawfulHashable α] {k a : α} {fallback v : β} : + getD (m.insert k v) a fallback = if k == a then v else getD m a fallback := + m.inductionOn fun _ => DHashMap.Const.getD_insert + +@[simp] +theorem getD_insert_self [EquivBEq α] [LawfulHashable α] {k : α} {fallback v : β} : + getD (m.insert k v) k fallback = v := + m.inductionOn fun _ => DHashMap.Const.getD_insert_self + +theorem getD_eq_fallback_of_contains_eq_false [EquivBEq α] [LawfulHashable α] {a : α} + {fallback : β} : m.contains a = false → getD m a fallback = fallback := + m.inductionOn fun _ => DHashMap.Const.getD_eq_fallback_of_contains_eq_false + +theorem getD_eq_fallback [EquivBEq α] [LawfulHashable α] {a : α} {fallback : β} : + ¬a ∈ m → getD m a fallback = fallback := + m.inductionOn fun _ => DHashMap.Const.getD_eq_fallback + +theorem getD_erase [EquivBEq α] [LawfulHashable α] {k a : α} {fallback : β} : + getD (m.erase k) a fallback = if k == a then fallback else getD m a fallback := + m.inductionOn fun _ => DHashMap.Const.getD_erase + +@[simp] +theorem getD_erase_self [EquivBEq α] [LawfulHashable α] {k : α} {fallback : β} : + getD (m.erase k) k fallback = fallback := + m.inductionOn fun _ => DHashMap.Const.getD_erase_self + +theorem get?_eq_some_getD_of_contains [EquivBEq α] [LawfulHashable α] {a : α} {fallback : β} : + m.contains a = true → get? m a = some (getD m a fallback) := + m.inductionOn fun _ => DHashMap.Const.get?_eq_some_getD_of_contains + +theorem get?_eq_some_getD [EquivBEq α] [LawfulHashable α] {a : α} {fallback : β} : + a ∈ m → get? m a = some (getD m a fallback) := + m.inductionOn fun _ => DHashMap.Const.get?_eq_some_getD + +theorem getD_eq_getD_get? [EquivBEq α] [LawfulHashable α] {a : α} {fallback : β} : + getD m a fallback = (get? m a).getD fallback := + m.inductionOn fun _ => DHashMap.Const.getD_eq_getD_get? + +theorem get_eq_getD [EquivBEq α] [LawfulHashable α] {a : α} {fallback : β} {h} : + get m a h = getD m a fallback := + m.inductionOn (fun _ _ => DHashMap.Const.get_eq_getD) h + +theorem get!_eq_getD_default [EquivBEq α] [LawfulHashable α] [Inhabited β] {a : α} : + get! m a = getD m a default := + m.inductionOn fun _ => DHashMap.Const.get!_eq_getD_default + +theorem getD_eq_getD [LawfulBEq α] {a : α} {fallback : β} : + getD m a fallback = m.getD a fallback := + m.inductionOn fun _ => DHashMap.Const.getD_eq_getD + +theorem getD_congr [EquivBEq α] [LawfulHashable α] {a b : α} {fallback : β} (hab : a == b) : + getD m a fallback = getD m b fallback := + m.inductionOn (fun _ hab => DHashMap.Const.getD_congr hab) hab + +end Const + +@[simp] +theorem getKey?_empty [EquivBEq α] [LawfulHashable α] {a : α} : (∅ : ExtDHashMap α β).getKey? a = none := + DHashMap.getKey?_empty + +theorem getKey?_insert [EquivBEq α] [LawfulHashable α] {a k : α} {v : β k} : + (m.insert k v).getKey? a = if k == a then some k else m.getKey? a := + m.inductionOn fun _ => DHashMap.getKey?_insert + +@[simp] +theorem getKey?_insert_self [EquivBEq α] [LawfulHashable α] {k : α} {v : β k} : + (m.insert k v).getKey? k = some k := + m.inductionOn fun _ => DHashMap.getKey?_insert_self + +theorem contains_eq_isSome_getKey? [EquivBEq α] [LawfulHashable α] {a : α} : + m.contains a = (m.getKey? a).isSome := + m.inductionOn fun _ => DHashMap.contains_eq_isSome_getKey? + +theorem mem_iff_isSome_getKey? [EquivBEq α] [LawfulHashable α] {a : α} : + a ∈ m ↔ (m.getKey? a).isSome := + m.inductionOn fun _ => DHashMap.mem_iff_isSome_getKey? + +theorem mem_of_getKey?_eq_some [EquivBEq α] [LawfulHashable α] {k k' : α} + (h : m.getKey? k = some k') : k' ∈ m := + m.inductionOn (fun _ h => DHashMap.mem_of_getKey?_eq_some h) h + +theorem getKey?_eq_none_of_contains_eq_false [EquivBEq α] [LawfulHashable α] {a : α} : + m.contains a = false → m.getKey? a = none := + m.inductionOn fun _ => DHashMap.getKey?_eq_none_of_contains_eq_false + +theorem getKey?_eq_none [EquivBEq α] [LawfulHashable α] {a : α} : ¬a ∈ m → m.getKey? a = none := + m.inductionOn fun _ => DHashMap.getKey?_eq_none + +theorem getKey?_erase [EquivBEq α] [LawfulHashable α] {k a : α} : + (m.erase k).getKey? a = if k == a then none else m.getKey? a := + m.inductionOn fun _ => DHashMap.getKey?_erase + +@[simp] +theorem getKey?_erase_self [EquivBEq α] [LawfulHashable α] {k : α} : (m.erase k).getKey? k = none := + m.inductionOn fun _ => DHashMap.getKey?_erase_self + +theorem getKey?_beq [EquivBEq α] [LawfulHashable α] {k : α} : + (m.getKey? k).all (· == k) := + m.inductionOn fun _ => DHashMap.getKey?_beq + +theorem getKey?_congr [EquivBEq α] [LawfulHashable α] {k k' : α} (h : k == k') : + m.getKey? k = m.getKey? k' := + m.inductionOn (fun _ h => DHashMap.getKey?_congr h) h + +theorem getKey?_eq_some_of_contains [LawfulBEq α] {k : α} (h : m.contains k) : + m.getKey? k = some k := + m.inductionOn (fun _ h => DHashMap.getKey?_eq_some_of_contains h) h + +theorem getKey?_eq_some [LawfulBEq α] {k : α} (h : k ∈ m) : m.getKey? k = some k := + m.inductionOn (fun _ h => DHashMap.getKey?_eq_some h) h + +theorem getKey_insert [EquivBEq α] [LawfulHashable α] {k a : α} {v : β k} {h₁} : + (m.insert k v).getKey a h₁ = + if h₂ : k == a then + k + else + m.getKey a (mem_of_mem_insert h₁ (Bool.eq_false_iff.2 h₂)) := + m.inductionOn (fun _ _ => DHashMap.getKey_insert) h₁ + +@[simp] +theorem getKey_insert_self [EquivBEq α] [LawfulHashable α] {k : α} {v : β k} : + (m.insert k v).getKey k mem_insert_self = k := + m.inductionOn fun _ => DHashMap.getKey_insert_self + +@[simp] +theorem getKey_erase [EquivBEq α] [LawfulHashable α] {k a : α} {h'} : + (m.erase k).getKey a h' = m.getKey a (mem_of_mem_erase h') := + m.inductionOn (fun _ _ => DHashMap.getKey_erase) h' + +theorem getKey?_eq_some_getKey [EquivBEq α] [LawfulHashable α] {a : α} (h) : + m.getKey? a = some (m.getKey a h) := + m.inductionOn (fun _ h => DHashMap.getKey?_eq_some_getKey h) h + +theorem getKey_eq_get_getKey? [EquivBEq α] [LawfulHashable α] {a : α} {h} : + m.getKey a h = (m.getKey? a).get (mem_iff_isSome_getKey?.mp h) := + m.inductionOn (fun _ _ => DHashMap.getKey_eq_get_getKey?) h + +theorem get_getKey? [EquivBEq α] [LawfulHashable α] {a : α} {h} : + (m.getKey? a).get h = m.getKey a (mem_iff_isSome_getKey?.mpr h) := + m.inductionOn (fun _ _ => DHashMap.get_getKey?) h + +theorem getKey_beq [EquivBEq α] [LawfulHashable α] {k : α} (h : k ∈ m) : m.getKey k h == k := + m.inductionOn (fun _ h => DHashMap.getKey_beq h) h + +theorem getKey_congr [EquivBEq α] [LawfulHashable α] {k₁ k₂ : α} (h : k₁ == k₂) + (h₁ : k₁ ∈ m) : m.getKey k₁ h₁ = m.getKey k₂ ((mem_congr h).mp h₁) := + m.inductionOn (fun _ h h₁ => DHashMap.getKey_congr h h₁) h h₁ + +theorem getKey_eq [LawfulBEq α] {k : α} (h : k ∈ m) : m.getKey k h = k := + m.inductionOn (fun _ h => DHashMap.getKey_eq h) h + +@[simp] +theorem getKey!_empty [EquivBEq α] [LawfulHashable α] [Inhabited α] {a : α} : + (∅ : ExtDHashMap α β).getKey! a = default := + DHashMap.getKey!_empty + +theorem getKey!_insert [EquivBEq α] [LawfulHashable α] [Inhabited α] {k a : α} {v : β k} : + (m.insert k v).getKey! a = + if k == a then k else m.getKey! a := + m.inductionOn fun _ => DHashMap.getKey!_insert + +@[simp] +theorem getKey!_insert_self [EquivBEq α] [LawfulHashable α] [Inhabited α] {a : α} {b : β a} : + (m.insert a b).getKey! a = a := + m.inductionOn fun _ => DHashMap.getKey!_insert_self + +theorem getKey!_eq_default_of_contains_eq_false [EquivBEq α] [LawfulHashable α] [Inhabited α] + {a : α} : + m.contains a = false → m.getKey! a = default := + m.inductionOn fun _ => DHashMap.getKey!_eq_default_of_contains_eq_false + +theorem getKey!_eq_default [EquivBEq α] [LawfulHashable α] [Inhabited α] {a : α} : + ¬a ∈ m → m.getKey! a = default := + m.inductionOn fun _ => DHashMap.getKey!_eq_default + +theorem getKey!_erase [EquivBEq α] [LawfulHashable α] [Inhabited α] {k a : α} : + (m.erase k).getKey! a = if k == a then default else m.getKey! a := + m.inductionOn fun _ => DHashMap.getKey!_erase + +@[simp] +theorem getKey!_erase_self [EquivBEq α] [LawfulHashable α] [Inhabited α] {k : α} : + (m.erase k).getKey! k = default := + m.inductionOn fun _ => DHashMap.getKey!_erase_self + +theorem getKey?_eq_some_getKey!_of_contains [EquivBEq α] [LawfulHashable α] [Inhabited α] {a : α} : + m.contains a = true → m.getKey? a = some (m.getKey! a) := + m.inductionOn fun _ => DHashMap.getKey?_eq_some_getKey!_of_contains + +theorem getKey?_eq_some_getKey! [EquivBEq α] [LawfulHashable α] [Inhabited α] {a : α} : + a ∈ m → m.getKey? a = some (m.getKey! a) := + m.inductionOn fun _ => DHashMap.getKey?_eq_some_getKey! + +theorem getKey!_eq_get!_getKey? [EquivBEq α] [LawfulHashable α] [Inhabited α] {a : α} : + m.getKey! a = (m.getKey? a).get! := + m.inductionOn fun _ => DHashMap.getKey!_eq_get!_getKey? + +theorem getKey_eq_getKey! [EquivBEq α] [LawfulHashable α] [Inhabited α] {a : α} {h} : + m.getKey a h = m.getKey! a := + m.inductionOn (fun _ _ => DHashMap.getKey_eq_getKey!) h + +theorem getKey!_congr [EquivBEq α] [LawfulHashable α] [Inhabited α] {k k' : α} (h : k == k') : + m.getKey! k = m.getKey! k' := + m.inductionOn (fun _ h => DHashMap.getKey!_congr h) h + +theorem getKey!_eq_of_contains [LawfulBEq α] [Inhabited α] {k : α} (h : m.contains k) : + m.getKey! k = k := + m.inductionOn (fun _ h => DHashMap.getKey!_eq_of_contains h) h + +theorem getKey!_eq_of_mem [LawfulBEq α] [Inhabited α] {k : α} (h : k ∈ m) : m.getKey! k = k := + m.inductionOn (fun _ h => DHashMap.getKey!_eq_of_mem h) h + +@[simp] +theorem getKeyD_empty [EquivBEq α] [LawfulHashable α] {a fallback : α} : + (∅ : ExtDHashMap α β).getKeyD a fallback = fallback := + DHashMap.getKeyD_empty + +theorem getKeyD_insert [EquivBEq α] [LawfulHashable α] {k a fallback : α} {v : β k} : + (m.insert k v).getKeyD a fallback = + if k == a then k else m.getKeyD a fallback := + m.inductionOn fun _ => DHashMap.getKeyD_insert + +@[simp] +theorem getKeyD_insert_self [EquivBEq α] [LawfulHashable α] {k fallback : α} {v : β k} : + (m.insert k v).getKeyD k fallback = k := + m.inductionOn fun _ => DHashMap.getKeyD_insert_self + +theorem getKeyD_eq_fallback_of_contains_eq_false [EquivBEq α] [LawfulHashable α] {a : α} + {fallback : α} : + m.contains a = false → m.getKeyD a fallback = fallback := + m.inductionOn fun _ => DHashMap.getKeyD_eq_fallback_of_contains_eq_false + +theorem getKeyD_eq_fallback [EquivBEq α] [LawfulHashable α] {a fallback : α} : + ¬a ∈ m → m.getKeyD a fallback = fallback := + m.inductionOn fun _ => DHashMap.getKeyD_eq_fallback + +theorem getKeyD_erase [EquivBEq α] [LawfulHashable α] {k a fallback : α} : + (m.erase k).getKeyD a fallback = if k == a then fallback else m.getKeyD a fallback := + m.inductionOn fun _ => DHashMap.getKeyD_erase + +@[simp] +theorem getKeyD_erase_self [EquivBEq α] [LawfulHashable α] {k fallback : α} : + (m.erase k).getKeyD k fallback = fallback := + m.inductionOn fun _ => DHashMap.getKeyD_erase_self + +theorem getKey?_eq_some_getKeyD_of_contains [EquivBEq α] [LawfulHashable α] {a fallback : α} : + m.contains a = true → m.getKey? a = some (m.getKeyD a fallback) := + m.inductionOn fun _ => DHashMap.getKey?_eq_some_getKeyD_of_contains + +theorem getKey?_eq_some_getKeyD [EquivBEq α] [LawfulHashable α] {a fallback : α} : + a ∈ m → m.getKey? a = some (m.getKeyD a fallback) := + m.inductionOn fun _ => DHashMap.getKey?_eq_some_getKeyD + +theorem getKeyD_eq_getD_getKey? [EquivBEq α] [LawfulHashable α] {a fallback : α} : + m.getKeyD a fallback = (m.getKey? a).getD fallback := + m.inductionOn fun _ => DHashMap.getKeyD_eq_getD_getKey? + +theorem getKey_eq_getKeyD [EquivBEq α] [LawfulHashable α] {a fallback : α} {h} : + m.getKey a h = m.getKeyD a fallback := + m.inductionOn (fun _ _ => DHashMap.getKey_eq_getKeyD) h + +theorem getKey!_eq_getKeyD_default [EquivBEq α] [LawfulHashable α] [Inhabited α] {a : α} : + m.getKey! a = m.getKeyD a default := + m.inductionOn fun _ => DHashMap.getKey!_eq_getKeyD_default + +theorem getKeyD_congr [EquivBEq α] [LawfulHashable α] {k k' fallback : α} + (h : k == k') : m.getKeyD k fallback = m.getKeyD k' fallback := + m.inductionOn (fun _ h => DHashMap.getKeyD_congr h) h + +theorem getKeyD_eq_of_contains [LawfulBEq α] {k fallback : α} (h : m.contains k) : + m.getKeyD k fallback = k := + m.inductionOn (fun _ h => DHashMap.getKeyD_eq_of_contains h) h + +theorem getKeyD_eq_of_mem [LawfulBEq α] {k fallback : α} (h : k ∈ m) : + m.getKeyD k fallback = k := + m.inductionOn (fun _ h => DHashMap.getKeyD_eq_of_mem h) h + +@[simp] +theorem not_insertIfNew_eq_empty [EquivBEq α] [LawfulHashable α] {k : α} {v : β k} : + ¬m.insertIfNew k v = ∅ := + isEmpty_eq_false_iff.mp <| m.inductionOn fun _ => DHashMap.isEmpty_insertIfNew + +@[simp] +theorem contains_insertIfNew [EquivBEq α] [LawfulHashable α] {k a : α} {v : β k} : + (m.insertIfNew k v).contains a = (k == a || m.contains a) := + m.inductionOn fun _ => DHashMap.contains_insertIfNew + +@[simp] +theorem mem_insertIfNew [EquivBEq α] [LawfulHashable α] {k a : α} {v : β k} : + a ∈ m.insertIfNew k v ↔ k == a ∨ a ∈ m := + m.inductionOn fun _ => DHashMap.mem_insertIfNew + +theorem contains_insertIfNew_self [EquivBEq α] [LawfulHashable α] {k : α} {v : β k} : + (m.insertIfNew k v).contains k := + m.inductionOn fun _ => DHashMap.contains_insertIfNew_self + +theorem mem_insertIfNew_self [EquivBEq α] [LawfulHashable α] {k : α} {v : β k} : + k ∈ m.insertIfNew k v := + m.inductionOn fun _ => DHashMap.mem_insertIfNew_self + +theorem contains_of_contains_insertIfNew [EquivBEq α] [LawfulHashable α] {k a : α} {v : β k} : + (m.insertIfNew k v).contains a → (k == a) = false → m.contains a := + m.inductionOn fun _ => DHashMap.contains_of_contains_insertIfNew + +theorem mem_of_mem_insertIfNew [EquivBEq α] [LawfulHashable α] {k a : α} {v : β k} : + a ∈ m.insertIfNew k v → (k == a) = false → a ∈ m := + m.inductionOn fun _ => DHashMap.mem_of_mem_insertIfNew + +/-- This is a restatement of `contains_of_contains_insertIfNew` that is written to exactly match the proof +obligation in the statement of `get_insertIfNew`. -/ +theorem contains_of_contains_insertIfNew' [EquivBEq α] [LawfulHashable α] {k a : α} {v : β k} : + (m.insertIfNew k v).contains a → ¬((k == a) ∧ m.contains k = false) → m.contains a := + m.inductionOn fun _ => DHashMap.contains_of_contains_insertIfNew' + +/-- This is a restatement of `mem_of_mem_insertIfNew` that is written to exactly match the proof obligation +in the statement of `get_insertIfNew`. -/ +theorem mem_of_mem_insertIfNew' [EquivBEq α] [LawfulHashable α] {k a : α} {v : β k} : + a ∈ m.insertIfNew k v → ¬((k == a) ∧ ¬k ∈ m) → a ∈ m := + m.inductionOn fun _ => DHashMap.mem_of_mem_insertIfNew' + +theorem size_insertIfNew [EquivBEq α] [LawfulHashable α] {k : α} {v : β k} : + (m.insertIfNew k v).size = if k ∈ m then m.size else m.size + 1 := + m.inductionOn fun _ => DHashMap.size_insertIfNew + +theorem size_le_size_insertIfNew [EquivBEq α] [LawfulHashable α] {k : α} {v : β k} : + m.size ≤ (m.insertIfNew k v).size := + m.inductionOn fun _ => DHashMap.size_le_size_insertIfNew + +theorem size_insertIfNew_le [EquivBEq α] [LawfulHashable α] {k : α} {v : β k} : + (m.insertIfNew k v).size ≤ m.size + 1 := + m.inductionOn fun _ => DHashMap.size_insertIfNew_le + +theorem get?_insertIfNew [LawfulBEq α] {k a : α} {v : β k} : (m.insertIfNew k v).get? a = + if h : k == a ∧ ¬k ∈ m then some (cast (congrArg β (eq_of_beq h.1)) v) else m.get? a := + m.inductionOn fun _ => DHashMap.get?_insertIfNew + +theorem get_insertIfNew [LawfulBEq α] {k a : α} {v : β k} {h₁} : (m.insertIfNew k v).get a h₁ = + if h₂ : k == a ∧ ¬k ∈ m then cast (congrArg β (eq_of_beq h₂.1)) v else m.get a + (mem_of_mem_insertIfNew' h₁ h₂) := + m.inductionOn (fun _ _ => DHashMap.get_insertIfNew) h₁ + +theorem get!_insertIfNew [LawfulBEq α] {k a : α} [Inhabited (β a)] {v : β k} : + (m.insertIfNew k v).get! a = + if h : k == a ∧ ¬k ∈ m then cast (congrArg β (eq_of_beq h.1)) v else m.get! a := + m.inductionOn fun _ => DHashMap.get!_insertIfNew + +theorem getD_insertIfNew [LawfulBEq α] {k a : α} {fallback : β a} {v : β k} : + (m.insertIfNew k v).getD a fallback = + if h : k == a ∧ ¬k ∈ m then cast (congrArg β (eq_of_beq h.1)) v + else m.getD a fallback := + m.inductionOn fun _ => DHashMap.getD_insertIfNew + +namespace Const + +variable {β : Type v} {m : ExtDHashMap α (fun _ => β)} + +theorem get?_insertIfNew [EquivBEq α] [LawfulHashable α] {k a : α} {v : β} : + get? (m.insertIfNew k v) a = if k == a ∧ ¬k ∈ m then some v else get? m a := + m.inductionOn fun _ => DHashMap.Const.get?_insertIfNew + +theorem get_insertIfNew [EquivBEq α] [LawfulHashable α] {k a : α} {v : β} {h₁} : + get (m.insertIfNew k v) a h₁ = + if h₂ : k == a ∧ ¬k ∈ m then v else get m a (mem_of_mem_insertIfNew' h₁ h₂) := + m.inductionOn (fun _ _ => DHashMap.Const.get_insertIfNew) h₁ + +theorem get!_insertIfNew [EquivBEq α] [LawfulHashable α] [Inhabited β] {k a : α} {v : β} : + get! (m.insertIfNew k v) a = if k == a ∧ ¬k ∈ m then v else get! m a := + m.inductionOn fun _ => DHashMap.Const.get!_insertIfNew + +theorem getD_insertIfNew [EquivBEq α] [LawfulHashable α] {k a : α} {fallback v : β} : + getD (m.insertIfNew k v) a fallback = + if k == a ∧ ¬k ∈ m then v else getD m a fallback := + m.inductionOn fun _ => DHashMap.Const.getD_insertIfNew + +end Const + +theorem getKey?_insertIfNew [EquivBEq α] [LawfulHashable α] {k a : α} {v : β k} : + getKey? (m.insertIfNew k v) a = if k == a ∧ ¬k ∈ m then some k else getKey? m a := + m.inductionOn fun _ => DHashMap.getKey?_insertIfNew + +theorem getKey_insertIfNew [EquivBEq α] [LawfulHashable α] {k a : α} {v : β k} {h₁} : + getKey (m.insertIfNew k v) a h₁ = + if h₂ : k == a ∧ ¬k ∈ m then k else getKey m a (mem_of_mem_insertIfNew' h₁ h₂) := + m.inductionOn (fun _ _ => DHashMap.getKey_insertIfNew) h₁ + +theorem getKey!_insertIfNew [EquivBEq α] [LawfulHashable α] [Inhabited α] {k a : α} {v : β k} : + getKey! (m.insertIfNew k v) a = if k == a ∧ ¬k ∈ m then k else getKey! m a := + m.inductionOn fun _ => DHashMap.getKey!_insertIfNew + +theorem getKeyD_insertIfNew [EquivBEq α] [LawfulHashable α] {k a fallback : α} {v : β k} : + getKeyD (m.insertIfNew k v) a fallback = + if k == a ∧ ¬k ∈ m then k else getKeyD m a fallback := + m.inductionOn fun _ => DHashMap.getKeyD_insertIfNew + +@[simp] +theorem getThenInsertIfNew?_fst [LawfulBEq α] {k : α} {v : β k} : + (m.getThenInsertIfNew? k v).1 = m.get? k := + m.inductionOn fun _ => DHashMap.getThenInsertIfNew?_fst + +@[simp] +theorem getThenInsertIfNew?_snd [LawfulBEq α] {k : α} {v : β k} : + (m.getThenInsertIfNew? k v).2 = m.insertIfNew k v := + m.inductionOn fun _ => congrArg Quotient.mk' DHashMap.getThenInsertIfNew?_snd + +namespace Const + +variable {β : Type v} {m : ExtDHashMap α (fun _ => β)} + +@[simp] +theorem getThenInsertIfNew?_fst [EquivBEq α] [LawfulHashable α] {k : α} {v : β} : (getThenInsertIfNew? m k v).1 = get? m k := + m.inductionOn fun _ => DHashMap.Const.getThenInsertIfNew?_fst + +@[simp] +theorem getThenInsertIfNew?_snd [EquivBEq α] [LawfulHashable α] {k : α} {v : β} : + (getThenInsertIfNew? m k v).2 = m.insertIfNew k v := + m.inductionOn fun _ => congrArg Quotient.mk' DHashMap.Const.getThenInsertIfNew?_snd + +end Const + +section insertMany + +variable {ρ : Type w} [ForIn Id ρ ((a : α) × β a)] + +@[simp] +theorem insertMany_nil [EquivBEq α] [LawfulHashable α] : m.insertMany [] = m := rfl + +@[simp] +theorem insertMany_list_singleton [EquivBEq α] [LawfulHashable α] {k : α} {v : β k} : + m.insertMany [⟨k, v⟩] = m.insert k v := rfl + +theorem insertMany_cons [EquivBEq α] [LawfulHashable α] + {l : List ((a : α) × β a)} {p : (a : α) × β a} : + m.insertMany (p :: l) = (m.insert p.1 p.2).insertMany l := by + rcases p with ⟨k, v⟩ + unfold insertMany + simp only [Id.pure_eq, Id.bind_eq, Id.run, List.forIn_yield_eq_foldl, List.foldl_cons] + refine Eq.trans ?_ (Eq.symm ?_ : l.foldl (fun b a => b.insert a.1 a.2) (m.insert k v) = _) + exact (List.foldl_hom (f := Subtype.val) fun x y => rfl).symm + exact (List.foldl_hom (f := Subtype.val) fun x y => rfl).symm + +private theorem insertMany_list_mk [EquivBEq α] [LawfulHashable α] + {m : DHashMap α β} {l : List ((a : α) × β a)} : + (ExtDHashMap.insertMany (Quotient.mk _ m) l : ExtDHashMap α β) = Quotient.mk _ (m.insertMany l) := by + simp only [Quotient.mk] + induction l generalizing m with + | nil => rfl + | cons x l ih => + rcases x with ⟨k, v⟩ + simp only [insertMany_cons, DHashMap.insertMany_cons, insert, + Quotient.mk', Quotient.mk, Quotient.lift, ih] + +@[elab_as_elim] +theorem insertMany_ind [EquivBEq α] [LawfulHashable α] {motive : ExtDHashMap α β → Prop} (m : ExtDHashMap α β) (l : ρ) + (init : motive m) (insert : ∀ m a b, motive m → motive (m.insert a b)) : + motive (m.insertMany l) := by + change motive (Subtype.val ?my_mvar) + exact Subtype.property ?my_mvar motive init (insert _ _ _) + +@[simp] +theorem contains_insertMany_list [EquivBEq α] [LawfulHashable α] + {l : List ((a : α) × β a)} {k : α} : + (m.insertMany l).contains k = (m.contains k || (l.map Sigma.fst).contains k) := by + refine m.inductionOn fun _ => ?_ + simp only [insertMany_list_mk] + exact DHashMap.contains_insertMany_list + +@[simp] +theorem mem_insertMany_list [EquivBEq α] [LawfulHashable α] + {l : List ((a : α) × β a)} {k : α} : + k ∈ m.insertMany l ↔ k ∈ m ∨ (l.map Sigma.fst).contains k := by + refine m.inductionOn fun _ => ?_ + simp only [insertMany_list_mk] + exact DHashMap.mem_insertMany_list + +theorem mem_of_mem_insertMany_list [EquivBEq α] [LawfulHashable α] + {l : List ((a : α) × β a)} {k : α} (mem : k ∈ m.insertMany l) + (contains_eq_false : (l.map Sigma.fst).contains k = false) : + k ∈ m := by + refine m.inductionOn (fun _ mem contains_eq_false => ?_) mem contains_eq_false + simp only [insertMany_list_mk] at mem + exact DHashMap.mem_of_mem_insertMany_list mem contains_eq_false + +theorem mem_insertMany_of_mem [EquivBEq α] [LawfulHashable α] {l : ρ} {k : α} (h' : k ∈ m) : k ∈ m.insertMany l := + insertMany_ind m l h' fun _ _ _ h => mem_insert.mpr (.inr h) + +theorem get?_insertMany_list_of_contains_eq_false [LawfulBEq α] + {l : List ((a : α) × β a)} {k : α} + (contains_eq_false : (l.map Sigma.fst).contains k = false) : + (m.insertMany l).get? k = m.get? k := by + refine m.inductionOn (fun _ contains_eq_false => ?_) contains_eq_false + simp only [insertMany_list_mk] + exact DHashMap.get?_insertMany_list_of_contains_eq_false contains_eq_false + +theorem get?_insertMany_list_of_mem [LawfulBEq α] + {l : List ((a : α) × β a)} {k k' : α} (k_beq : k == k') {v : β k} + (distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) + (mem : ⟨k, v⟩ ∈ l) : + (m.insertMany l).get? k' = some (cast (by congr; apply LawfulBEq.eq_of_beq k_beq) v) := by + refine m.inductionOn (fun _ k_beq distinct mem => ?_) k_beq distinct mem + simp only [insertMany_list_mk] + exact DHashMap.get?_insertMany_list_of_mem k_beq distinct mem + +theorem get_insertMany_list_of_contains_eq_false [LawfulBEq α] + {l : List ((a : α) × β a)} {k : α} + (contains_eq_false : (l.map Sigma.fst).contains k = false) + {h} : + (m.insertMany l).get k h = + m.get k (mem_of_mem_insertMany_list h contains_eq_false) := by + refine m.inductionOn (fun _ contains_eq_false _ => ?_) contains_eq_false h + simp only [insertMany_list_mk] + exact DHashMap.get_insertMany_list_of_contains_eq_false contains_eq_false + +theorem get_insertMany_list_of_mem [LawfulBEq α] + {l : List ((a : α) × β a)} {k k' : α} (k_beq : k == k') {v : β k} + (distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) + (mem : ⟨k, v⟩ ∈ l) + {h} : + (m.insertMany l).get k' h = cast (by congr; apply LawfulBEq.eq_of_beq k_beq) v := by + refine m.inductionOn (fun _ k_beq distinct mem _ => ?_) k_beq distinct mem h + simp only [insertMany_list_mk] + exact DHashMap.get_insertMany_list_of_mem k_beq distinct mem + +theorem get!_insertMany_list_of_contains_eq_false [LawfulBEq α] + {l : List ((a : α) × β a)} {k : α} [Inhabited (β k)] + (contains_eq_false : (l.map Sigma.fst).contains k = false) : + (m.insertMany l).get! k = m.get! k := by + refine m.inductionOn (fun _ contains_eq_false => ?_) contains_eq_false + simp only [insertMany_list_mk] + exact DHashMap.get!_insertMany_list_of_contains_eq_false contains_eq_false + +theorem get!_insertMany_list_of_mem [LawfulBEq α] + {l : List ((a : α) × β a)} {k k' : α} (k_beq : k == k') {v : β k} [Inhabited (β k')] + (distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) + (mem : ⟨k, v⟩ ∈ l) : + (m.insertMany l).get! k' = cast (by congr; apply LawfulBEq.eq_of_beq k_beq) v := by + refine m.inductionOn (fun _ k_beq distinct mem => ?_) k_beq distinct mem + simp only [insertMany_list_mk] + exact DHashMap.get!_insertMany_list_of_mem k_beq distinct mem + +theorem getD_insertMany_list_of_contains_eq_false [LawfulBEq α] + {l : List ((a : α) × β a)} {k : α} {fallback : β k} + (contains_eq_false : (l.map Sigma.fst).contains k = false) : + (m.insertMany l).getD k fallback = m.getD k fallback := by + refine m.inductionOn (fun _ contains_eq_false => ?_) contains_eq_false + simp only [insertMany_list_mk] + exact DHashMap.getD_insertMany_list_of_contains_eq_false contains_eq_false + +theorem getD_insertMany_list_of_mem [LawfulBEq α] + {l : List ((a : α) × β a)} {k k' : α} (k_beq : k == k') {v : β k} {fallback : β k'} + (distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) + (mem : ⟨k, v⟩ ∈ l) : + (m.insertMany l).getD k' fallback = cast (by congr; apply LawfulBEq.eq_of_beq k_beq) v := by + refine m.inductionOn (fun _ k_beq distinct mem => ?_) k_beq distinct mem + simp only [insertMany_list_mk] + exact DHashMap.getD_insertMany_list_of_mem k_beq distinct mem + +theorem getKey?_insertMany_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α] + {l : List ((a : α) × β a)} {k : α} + (contains_eq_false : (l.map Sigma.fst).contains k = false) : + (m.insertMany l).getKey? k = m.getKey? k := by + refine m.inductionOn (fun _ contains_eq_false => ?_) contains_eq_false + simp only [insertMany_list_mk] + exact DHashMap.getKey?_insertMany_list_of_contains_eq_false contains_eq_false + +theorem getKey?_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α] + {l : List ((a : α) × β a)} + {k k' : α} (k_beq : k == k') + (distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) + (mem : k ∈ l.map Sigma.fst) : + (m.insertMany l).getKey? k' = some k := by + refine m.inductionOn (fun _ k_beq distinct mem => ?_) k_beq distinct mem + simp only [insertMany_list_mk] + exact DHashMap.getKey?_insertMany_list_of_mem k_beq distinct mem + +theorem getKey_insertMany_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α] + {l : List ((a : α) × β a)} {k : α} + (contains_eq_false : (l.map Sigma.fst).contains k = false) + {h} : + (m.insertMany l).getKey k h = + m.getKey k (mem_of_mem_insertMany_list h contains_eq_false) := by + refine m.inductionOn (fun _ contains_eq_false _ => ?_) contains_eq_false h + simp only [insertMany_list_mk] + exact DHashMap.getKey_insertMany_list_of_contains_eq_false contains_eq_false + +theorem getKey_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α] + {l : List ((a : α) × β a)} + {k k' : α} (k_beq : k == k') + (distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) + (mem : k ∈ l.map Sigma.fst) + {h} : + (m.insertMany l).getKey k' h = k := by + refine m.inductionOn (fun _ k_beq distinct mem _ => ?_) k_beq distinct mem h + simp only [insertMany_list_mk] + exact DHashMap.getKey_insertMany_list_of_mem k_beq distinct mem + +theorem getKey!_insertMany_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α] [Inhabited α] + {l : List ((a : α) × β a)} {k : α} + (contains_eq_false : (l.map Sigma.fst).contains k = false) : + (m.insertMany l).getKey! k = m.getKey! k := by + refine m.inductionOn (fun _ contains_eq_false => ?_) contains_eq_false + simp only [insertMany_list_mk] + exact DHashMap.getKey!_insertMany_list_of_contains_eq_false contains_eq_false + +theorem getKey!_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α] [Inhabited α] + {l : List ((a : α) × β a)} + {k k' : α} (k_beq : k == k') + (distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) + (mem : k ∈ l.map Sigma.fst) : + (m.insertMany l).getKey! k' = k := by + refine m.inductionOn (fun _ k_beq distinct mem => ?_) k_beq distinct mem + simp only [insertMany_list_mk] + exact DHashMap.getKey!_insertMany_list_of_mem k_beq distinct mem + +theorem getKeyD_insertMany_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α] + {l : List ((a : α) × β a)} {k fallback : α} + (contains_eq_false : (l.map Sigma.fst).contains k = false) : + (m.insertMany l).getKeyD k fallback = m.getKeyD k fallback := by + refine m.inductionOn (fun _ contains_eq_false => ?_) contains_eq_false + simp only [insertMany_list_mk] + exact DHashMap.getKeyD_insertMany_list_of_contains_eq_false contains_eq_false + +theorem getKeyD_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α] + {l : List ((a : α) × β a)} + {k k' fallback : α} (k_beq : k == k') + (distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) + (mem : k ∈ l.map Sigma.fst) : + (m.insertMany l).getKeyD k' fallback = k := by + refine m.inductionOn (fun _ k_beq distinct mem => ?_) k_beq distinct mem + simp only [insertMany_list_mk] + exact DHashMap.getKeyD_insertMany_list_of_mem k_beq distinct mem + +theorem size_insertMany_list [EquivBEq α] [LawfulHashable α] + {l : List ((a : α) × β a)} (distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) : + (∀ (a : α), a ∈ m → (l.map Sigma.fst).contains a = false) → + (m.insertMany l).size = m.size + l.length := by + refine m.inductionOn (fun _ distinct => ?_) distinct + simp only [insertMany_list_mk] + exact DHashMap.size_insertMany_list distinct + +theorem size_le_size_insertMany_list [EquivBEq α] [LawfulHashable α] + {l : List ((a : α) × β a)} : + m.size ≤ (m.insertMany l).size := by + refine m.inductionOn fun _ => ?_ + simp only [insertMany_list_mk] + exact DHashMap.size_le_size_insertMany_list + +theorem size_le_size_insertMany [EquivBEq α] [LawfulHashable α] {l : ρ} : m.size ≤ (m.insertMany l).size := + insertMany_ind m l (Nat.le_refl _) fun _ _ _ h => Nat.le_trans h size_le_size_insert + +theorem size_insertMany_list_le [EquivBEq α] [LawfulHashable α] + {l : List ((a : α) × β a)} : + (m.insertMany l).size ≤ m.size + l.length := by + refine m.inductionOn fun _ => ?_ + simp only [insertMany_list_mk] + exact DHashMap.size_insertMany_list_le + +@[simp] +theorem insertMany_list_eq_empty_iff [EquivBEq α] [LawfulHashable α] {l : List ((a : α) × β a)} : + m.insertMany l = ∅ ↔ m = ∅ ∧ l = [] := by + refine m.inductionOn fun _ => ?_ + simp only [insertMany_list_mk, ← isEmpty_iff, ← List.isEmpty_iff, + Bool.coe_iff_coe, ← Bool.and_eq_true] + exact DHashMap.isEmpty_insertMany_list + +theorem eq_empty_of_insertMany_eq_empty [EquivBEq α] [LawfulHashable α] {l : ρ} : + m.insertMany l = ∅ → m = ∅ := + insertMany_ind m l id fun _ _ _ _ h => absurd h not_insert_eq_empty + +namespace Const + +variable {β : Type v} {m : ExtDHashMap α (fun _ => β)} +variable {ρ : Type w} [ForIn Id ρ (α × β)] + +@[simp] +theorem insertMany_nil [EquivBEq α] [LawfulHashable α] : insertMany m [] = m := + rfl + +@[simp] +theorem insertMany_list_singleton [EquivBEq α] [LawfulHashable α] {k : α} {v : β} : + insertMany m [⟨k, v⟩] = m.insert k v := rfl + +theorem insertMany_cons [EquivBEq α] [LawfulHashable α] {l : List (α × β)} {p : α × β} : + insertMany m (p :: l) = insertMany (m.insert p.1 p.2) l := by + rcases p with ⟨k, v⟩ + unfold insertMany + simp only [Id.pure_eq, Id.bind_eq, Id.run, List.forIn_yield_eq_foldl, List.foldl_cons] + refine Eq.trans ?_ (Eq.symm ?_ : l.foldl (fun b a => b.insert a.1 a.2) (m.insert k v) = _) + exact (List.foldl_hom (f := Subtype.val) fun x y => rfl).symm + exact (List.foldl_hom (f := Subtype.val) fun x y => rfl).symm + +private theorem insertMany_list_mk [EquivBEq α] [LawfulHashable α] + {m : DHashMap α fun _ => β} {l : List (α × β)} : + (insertMany (Quotient.mk _ m) l : ExtDHashMap α fun _ => β) = + Quotient.mk _ (DHashMap.Const.insertMany m l) := by + simp only [Quotient.mk] + induction l generalizing m with + | nil => rfl + | cons x l ih => + rcases x with ⟨k, v⟩ + simp only [insertMany_cons, DHashMap.Const.insertMany_cons, insert, + Quotient.mk', Quotient.mk, Quotient.lift, ih] + +@[elab_as_elim] +theorem insertMany_ind [EquivBEq α] [LawfulHashable α] {motive : ExtDHashMap α (fun _ => β) → Prop} + (m : ExtDHashMap α fun _ => β) (l : ρ) + (init : motive m) (insert : ∀ m a b, motive m → motive (m.insert a b)) : + motive (insertMany m l) := by + change motive (Subtype.val ?my_mvar) + exact Subtype.property ?my_mvar motive init (insert _ _ _) + +@[simp] +theorem contains_insertMany_list [EquivBEq α] [LawfulHashable α] + {l : List (α × β)} {k : α} : + (Const.insertMany m l).contains k = (m.contains k || (l.map Prod.fst).contains k) := by + refine m.inductionOn fun _ => ?_ + simp only [insertMany_list_mk] + exact DHashMap.Const.contains_insertMany_list + +@[simp] +theorem mem_insertMany_list [EquivBEq α] [LawfulHashable α] + {l : List (α × β)} {k : α} : + k ∈ insertMany m l ↔ k ∈ m ∨ (l.map Prod.fst).contains k := by + refine m.inductionOn fun _ => ?_ + simp only [insertMany_list_mk] + exact DHashMap.Const.mem_insertMany_list + +theorem mem_of_mem_insertMany_list [EquivBEq α] [LawfulHashable α] + {l : List (α × β)} {k : α} (mem : k ∈ insertMany m l) + (contains_eq_false : (l.map Prod.fst).contains k = false) : + k ∈ m := by + refine m.inductionOn (fun _ mem contains_eq_false => ?_) mem contains_eq_false + simp only [insertMany_list_mk] at mem + exact DHashMap.Const.mem_of_mem_insertMany_list mem contains_eq_false + +theorem mem_insertMany_of_mem [EquivBEq α] [LawfulHashable α] {l : ρ} {k : α} (h' : k ∈ m) : k ∈ insertMany m l := + insertMany_ind m l h' fun _ _ _ h => mem_insert.mpr (.inr h) + +theorem getKey?_insertMany_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α] + {l : List (α × β)} {k : α} + (contains_eq_false : (l.map Prod.fst).contains k = false) : + (insertMany m l).getKey? k = m.getKey? k := by + refine m.inductionOn (fun _ contains_eq_false => ?_) contains_eq_false + simp only [insertMany_list_mk] + exact DHashMap.Const.getKey?_insertMany_list_of_contains_eq_false contains_eq_false + +theorem getKey?_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α] + {l : List (α × β)} + {k k' : α} (k_beq : k == k') + (distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) + (mem : k ∈ l.map Prod.fst) : + (insertMany m l).getKey? k' = some k := by + refine m.inductionOn (fun _ k_beq distinct mem => ?_) k_beq distinct mem + simp only [insertMany_list_mk] + exact DHashMap.Const.getKey?_insertMany_list_of_mem k_beq distinct mem + +theorem getKey_insertMany_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α] + {l : List (α × β)} {k : α} + (contains_eq_false : (l.map Prod.fst).contains k = false) + {h} : + (insertMany m l).getKey k h = + m.getKey k (mem_of_mem_insertMany_list h contains_eq_false) := by + refine m.inductionOn (fun _ contains_eq_false _ => ?_) contains_eq_false h + simp only [insertMany_list_mk] + exact DHashMap.Const.getKey_insertMany_list_of_contains_eq_false contains_eq_false + +theorem getKey_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α] + {l : List (α × β)} + {k k' : α} (k_beq : k == k') + (distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) + (mem : k ∈ l.map Prod.fst) + {h} : + (insertMany m l).getKey k' h = k := by + refine m.inductionOn (fun _ k_beq distinct mem _ => ?_) k_beq distinct mem h + simp only [insertMany_list_mk] + exact DHashMap.Const.getKey_insertMany_list_of_mem k_beq distinct mem + +theorem getKey!_insertMany_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α] [Inhabited α] + {l : List (α × β)} {k : α} + (contains_eq_false : (l.map Prod.fst).contains k = false) : + (insertMany m l).getKey! k = m.getKey! k := by + refine m.inductionOn (fun _ contains_eq_false => ?_) contains_eq_false + simp only [insertMany_list_mk] + exact DHashMap.Const.getKey!_insertMany_list_of_contains_eq_false contains_eq_false + +theorem getKey!_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α] [Inhabited α] + {l : List (α × β)} + {k k' : α} (k_beq : k == k') + (distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) + (mem : k ∈ l.map Prod.fst) : + (insertMany m l).getKey! k' = k := by + refine m.inductionOn (fun _ k_beq distinct mem => ?_) k_beq distinct mem + simp only [insertMany_list_mk] + exact DHashMap.Const.getKey!_insertMany_list_of_mem k_beq distinct mem + +theorem getKeyD_insertMany_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α] + {l : List (α × β)} {k fallback : α} + (contains_eq_false : (l.map Prod.fst).contains k = false) : + (insertMany m l).getKeyD k fallback = m.getKeyD k fallback := by + refine m.inductionOn (fun _ contains_eq_false => ?_) contains_eq_false + simp only [insertMany_list_mk] + exact DHashMap.Const.getKeyD_insertMany_list_of_contains_eq_false contains_eq_false + +theorem getKeyD_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α] + {l : List (α × β)} + {k k' fallback : α} (k_beq : k == k') + (distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) + (mem : k ∈ l.map Prod.fst) : + (insertMany m l).getKeyD k' fallback = k := by + refine m.inductionOn (fun _ k_beq distinct mem => ?_) k_beq distinct mem + simp only [insertMany_list_mk] + exact DHashMap.Const.getKeyD_insertMany_list_of_mem k_beq distinct mem + +theorem size_insertMany_list [EquivBEq α] [LawfulHashable α] + {l : List (α × β)} + (distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) : + (∀ (a : α), a ∈ m → (l.map Prod.fst).contains a = false) → + (insertMany m l).size = m.size + l.length := by + refine m.inductionOn (fun _ distinct => ?_) distinct + simp only [insertMany_list_mk] + exact DHashMap.Const.size_insertMany_list distinct + +theorem size_le_size_insertMany_list [EquivBEq α] [LawfulHashable α] + {l : List (α × β)} : + m.size ≤ (insertMany m l).size := by + refine m.inductionOn fun _ => ?_ + simp only [insertMany_list_mk] + exact DHashMap.Const.size_le_size_insertMany_list + +theorem size_le_size_insertMany [EquivBEq α] [LawfulHashable α] {l : ρ} : m.size ≤ (insertMany m l).size := + insertMany_ind m l (Nat.le_refl _) fun _ _ _ h => Nat.le_trans h size_le_size_insert + +theorem size_insertMany_list_le [EquivBEq α] [LawfulHashable α] + {l : List (α × β)} : + (insertMany m l).size ≤ m.size + l.length := by + refine m.inductionOn fun _ => ?_ + simp only [insertMany_list_mk] + exact DHashMap.Const.size_insertMany_list_le + +@[simp] +theorem insertMany_list_eq_empty_iff [EquivBEq α] [LawfulHashable α] {l : List (α × β)} : + insertMany m l = ∅ ↔ m = ∅ ∧ l = [] := by + refine m.inductionOn fun _ => ?_ + simp only [insertMany_list_mk, ← isEmpty_iff, ← List.isEmpty_iff, + Bool.coe_iff_coe, ← Bool.and_eq_true] + exact DHashMap.Const.isEmpty_insertMany_list + +theorem eq_empty_of_insertMany_eq_empty [EquivBEq α] [LawfulHashable α] {l : ρ} : insertMany m l = ∅ → m = ∅ := + insertMany_ind m l id fun _ _ _ _ h => absurd h not_insert_eq_empty + +theorem get?_insertMany_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α] + {l : List (α × β)} {k : α} + (contains_eq_false : (l.map Prod.fst).contains k = false) : + get? (insertMany m l) k = get? m k := by + refine m.inductionOn (fun _ contains_eq_false => ?_) contains_eq_false + simp only [insertMany_list_mk] + exact DHashMap.Const.get?_insertMany_list_of_contains_eq_false contains_eq_false + +theorem get?_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α] + {l : List (α × β)} {k k' : α} (k_beq : k == k') {v : β} + (distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) (mem : ⟨k, v⟩ ∈ l) : + get? (insertMany m l) k' = some v := by + refine m.inductionOn (fun _ k_beq distinct mem => ?_) k_beq distinct mem + simp only [insertMany_list_mk] + exact DHashMap.Const.get?_insertMany_list_of_mem k_beq distinct mem + +theorem get_insertMany_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α] + {l : List (α × β)} {k : α} + (contains_eq_false : (l.map Prod.fst).contains k = false) + {h} : + get (insertMany m l) k h = get m k (mem_of_mem_insertMany_list h contains_eq_false) := by + refine m.inductionOn (fun _ contains_eq_false _ => ?_) contains_eq_false h + simp only [insertMany_list_mk] + exact DHashMap.Const.get_insertMany_list_of_contains_eq_false contains_eq_false + +theorem get_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α] + {l : List (α × β)} {k k' : α} (k_beq : k == k') {v : β} + (distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) (mem : ⟨k, v⟩ ∈ l) {h} : + get (insertMany m l) k' h = v := by + refine m.inductionOn (fun _ k_beq distinct mem _ => ?_) k_beq distinct mem h + simp only [insertMany_list_mk] + exact DHashMap.Const.get_insertMany_list_of_mem k_beq distinct mem + +theorem get!_insertMany_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α] + [Inhabited β] {l : List (α × β)} {k : α} + (contains_eq_false : (l.map Prod.fst).contains k = false) : + get! (insertMany m l) k = get! m k := by + refine m.inductionOn (fun _ contains_eq_false => ?_) contains_eq_false + simp only [insertMany_list_mk] + exact DHashMap.Const.get!_insertMany_list_of_contains_eq_false contains_eq_false + +theorem get!_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α] [Inhabited β] + {l : List (α × β)} {k k' : α} (k_beq : k == k') {v : β} + (distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) (mem : ⟨k, v⟩ ∈ l) : + get! (insertMany m l) k' = v := by + refine m.inductionOn (fun _ k_beq distinct mem => ?_) k_beq distinct mem + simp only [insertMany_list_mk] + exact DHashMap.Const.get!_insertMany_list_of_mem k_beq distinct mem + +theorem getD_insertMany_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α] + {l : List (α × β)} {k : α} {fallback : β} + (contains_eq_false : (l.map Prod.fst).contains k = false) : + getD (insertMany m l) k fallback = getD m k fallback := by + refine m.inductionOn (fun _ contains_eq_false => ?_) contains_eq_false + simp only [insertMany_list_mk] + exact DHashMap.Const.getD_insertMany_list_of_contains_eq_false contains_eq_false + +theorem getD_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α] + {l : List (α × β)} {k k' : α} (k_beq : k == k') {v fallback : β} + (distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) (mem : ⟨k, v⟩ ∈ l) : + getD (insertMany m l) k' fallback = v := by + refine m.inductionOn (fun _ k_beq distinct mem => ?_) k_beq distinct mem + simp only [insertMany_list_mk] + exact DHashMap.Const.getD_insertMany_list_of_mem k_beq distinct mem + +variable {m : ExtDHashMap α (fun _ => Unit)} +variable {ρ : Type w} [ForIn Id ρ α] + +@[simp] +theorem insertManyIfNewUnit_nil [EquivBEq α] [LawfulHashable α] : + insertManyIfNewUnit m [] = m := + rfl + +@[simp] +theorem insertManyIfNewUnit_list_singleton [EquivBEq α] [LawfulHashable α] {k : α} : + insertManyIfNewUnit m [k] = m.insertIfNew k () := rfl + +theorem insertManyIfNewUnit_cons [EquivBEq α] [LawfulHashable α] {l : List α} {k : α} : + insertManyIfNewUnit m (k :: l) = insertManyIfNewUnit (m.insertIfNew k ()) l := by + unfold insertManyIfNewUnit + simp only [Id.pure_eq, Id.bind_eq, Id.run, List.forIn_yield_eq_foldl, List.foldl_cons] + refine Eq.trans ?_ (Eq.symm ?_ : l.foldl (fun b a => b.insertIfNew a ()) (m.insertIfNew k ()) = _) + exact (List.foldl_hom (f := Subtype.val) fun x y => rfl).symm + exact (List.foldl_hom (f := Subtype.val) fun x y => rfl).symm + +private theorem insertManyIfNewUnit_list_mk [EquivBEq α] [LawfulHashable α] + {m : DHashMap α fun _ => Unit} {l : List α} : + (insertManyIfNewUnit (Quotient.mk _ m) l : ExtDHashMap α fun _ => Unit) = + Quotient.mk _ (DHashMap.Const.insertManyIfNewUnit m l) := by + simp only [Quotient.mk] + induction l generalizing m with + | nil => rfl + | cons x l ih => + simp only [insertManyIfNewUnit_cons, DHashMap.Const.insertManyIfNewUnit_cons, insertIfNew, + Quotient.mk', Quotient.mk, Quotient.lift, ih] + +@[elab_as_elim] +theorem insertManyIfNewUnit_ind [EquivBEq α] [LawfulHashable α] {motive : ExtDHashMap α (fun _ => Unit) → Prop} + (m : ExtDHashMap α fun _ => Unit) (l : ρ) + (init : motive m) (insert : ∀ m a, motive m → motive (m.insertIfNew a ())) : + motive (insertManyIfNewUnit m l) := by + change motive (Subtype.val ?my_mvar) + exact Subtype.property ?my_mvar motive init (insert _ _) + +@[simp] +theorem contains_insertManyIfNewUnit_list [EquivBEq α] [LawfulHashable α] + {l : List α} {k : α} : + (insertManyIfNewUnit m l).contains k = (m.contains k || l.contains k) := by + refine m.inductionOn fun _ => ?_ + simp only [insertManyIfNewUnit_list_mk] + exact DHashMap.Const.contains_insertManyIfNewUnit_list + +@[simp] +theorem mem_insertManyIfNewUnit_list [EquivBEq α] [LawfulHashable α] + {l : List α} {k : α} : + k ∈ insertManyIfNewUnit m l ↔ k ∈ m ∨ l.contains k := by + refine m.inductionOn fun _ => ?_ + simp only [insertManyIfNewUnit_list_mk] + exact DHashMap.Const.mem_insertManyIfNewUnit_list + +theorem mem_of_mem_insertManyIfNewUnit_list [EquivBEq α] [LawfulHashable α] + {l : List α} {k : α} (contains_eq_false : l.contains k = false) : + k ∈ insertManyIfNewUnit m l → k ∈ m := by + refine m.inductionOn (fun _ contains_eq_false => ?_) contains_eq_false + simp only [insertManyIfNewUnit_list_mk] + exact DHashMap.Const.mem_of_mem_insertManyIfNewUnit_list contains_eq_false + +theorem mem_insertManyIfNewUnit_of_mem [EquivBEq α] [LawfulHashable α] {l : ρ} {k : α} (h : k ∈ m) : + k ∈ insertManyIfNewUnit m l := + insertManyIfNewUnit_ind m l h fun _ _ h => mem_insertIfNew.mpr (.inr h) + +theorem getKey?_insertManyIfNewUnit_list_of_not_mem_of_contains_eq_false [EquivBEq α] [LawfulHashable α] + {l : List α} {k : α} + (not_mem : ¬ k ∈ m) (contains_eq_false : l.contains k = false) : + getKey? (insertManyIfNewUnit m l) k = none := by + refine m.inductionOn (fun _ not_mem contains_eq_false => ?_) not_mem contains_eq_false + simp only [insertManyIfNewUnit_list_mk] + exact DHashMap.Const.getKey?_insertManyIfNewUnit_list_of_not_mem_of_contains_eq_false not_mem contains_eq_false + +theorem getKey?_insertManyIfNewUnit_list_of_not_mem_of_mem [EquivBEq α] [LawfulHashable α] + {l : List α} {k k' : α} (k_beq : k == k') + (not_mem : ¬ k ∈ m) + (distinct : l.Pairwise (fun a b => (a == b) = false)) (mem : k ∈ l) : + getKey? (insertManyIfNewUnit m l) k' = some k := by + refine m.inductionOn (fun _ k_beq not_mem distinct mem => ?_) k_beq not_mem distinct mem + simp only [insertManyIfNewUnit_list_mk] + exact DHashMap.Const.getKey?_insertManyIfNewUnit_list_of_not_mem_of_mem k_beq not_mem distinct mem + +theorem getKey?_insertManyIfNewUnit_list_of_mem [EquivBEq α] [LawfulHashable α] + {l : List α} {k : α} (h' : k ∈ m) : + getKey? (insertManyIfNewUnit m l) k = getKey? m k := by + refine m.inductionOn (fun _ h' => ?_) h' + simp only [insertManyIfNewUnit_list_mk] + exact DHashMap.Const.getKey?_insertManyIfNewUnit_list_of_mem h' + +theorem getKey_insertManyIfNewUnit_list_of_not_mem_of_mem [EquivBEq α] [LawfulHashable α] + {l : List α} + {k k' : α} (k_beq : k == k') + (not_mem : ¬ k ∈ m) (distinct : l.Pairwise (fun a b => (a == b) = false)) + (mem : k ∈ l) {h} : + getKey (insertManyIfNewUnit m l) k' h = k := by + refine m.inductionOn (fun _ k_beq not_mem distinct mem _ => ?_) k_beq not_mem distinct mem h + simp only [insertManyIfNewUnit_list_mk] + exact DHashMap.Const.getKey_insertManyIfNewUnit_list_of_not_mem_of_mem k_beq not_mem distinct mem + +theorem getKey_insertManyIfNewUnit_list_of_mem [EquivBEq α] [LawfulHashable α] + {l : List α} {k : α} (mem : k ∈ m) {h} : + getKey (insertManyIfNewUnit m l) k h = getKey m k mem := by + refine m.inductionOn (fun _ mem _ => ?_) mem h + simp only [insertManyIfNewUnit_list_mk] + exact DHashMap.Const.getKey_insertManyIfNewUnit_list_of_mem mem + +theorem getKey!_insertManyIfNewUnit_list_of_not_mem_of_contains_eq_false [EquivBEq α] [LawfulHashable α] + [Inhabited α] {l : List α} {k : α} + (not_mem : ¬ k ∈ m) (contains_eq_false : l.contains k = false) : + getKey! (insertManyIfNewUnit m l) k = default := by + refine m.inductionOn (fun _ not_mem contains_eq_false => ?_) not_mem contains_eq_false + simp only [insertManyIfNewUnit_list_mk] + exact DHashMap.Const.getKey!_insertManyIfNewUnit_list_of_not_mem_of_contains_eq_false not_mem contains_eq_false + +theorem getKey!_insertManyIfNewUnit_list_of_not_mem_of_mem [EquivBEq α] [LawfulHashable α] + [Inhabited α] {l : List α} {k k' : α} (k_beq : k == k') + (not_mem : ¬ k ∈ m) (distinct : l.Pairwise (fun a b => (a == b) = false)) + (mem : k ∈ l) : + getKey! (insertManyIfNewUnit m l) k' = k := by + refine m.inductionOn (fun _ k_beq not_mem distinct mem => ?_) k_beq not_mem distinct mem + simp only [insertManyIfNewUnit_list_mk] + exact DHashMap.Const.getKey!_insertManyIfNewUnit_list_of_not_mem_of_mem k_beq not_mem distinct mem + +theorem getKey!_insertManyIfNewUnit_list_of_mem [EquivBEq α] [LawfulHashable α] + [Inhabited α] {l : List α} {k : α} (mem : k ∈ m) : + getKey! (insertManyIfNewUnit m l) k = getKey! m k := by + refine m.inductionOn (fun _ mem => ?_) mem + simp only [insertManyIfNewUnit_list_mk] + exact DHashMap.Const.getKey!_insertManyIfNewUnit_list_of_mem mem + +theorem getKeyD_insertManyIfNewUnit_list_of_not_mem_of_contains_eq_false [EquivBEq α] [LawfulHashable α] + {l : List α} {k fallback : α} + (not_mem : ¬ k ∈ m) (contains_eq_false : l.contains k = false) : + getKeyD (insertManyIfNewUnit m l) k fallback = fallback := by + refine m.inductionOn (fun _ not_mem contains_eq_false => ?_) not_mem contains_eq_false + simp only [insertManyIfNewUnit_list_mk] + exact DHashMap.Const.getKeyD_insertManyIfNewUnit_list_of_not_mem_of_contains_eq_false not_mem contains_eq_false + +theorem getKeyD_insertManyIfNewUnit_list_of_not_mem_of_mem [EquivBEq α] [LawfulHashable α] + {l : List α} {k k' fallback : α} (k_beq : k == k') + (not_mem : ¬ k ∈ m) + (distinct : l.Pairwise (fun a b => (a == b) = false)) (mem : k ∈ l) : + getKeyD (insertManyIfNewUnit m l) k' fallback = k := by + refine m.inductionOn (fun _ k_beq not_mem distinct mem => ?_) k_beq not_mem distinct mem + simp only [insertManyIfNewUnit_list_mk] + exact DHashMap.Const.getKeyD_insertManyIfNewUnit_list_of_not_mem_of_mem k_beq not_mem distinct mem + +theorem getKeyD_insertManyIfNewUnit_list_of_mem [EquivBEq α] [LawfulHashable α] + {l : List α} {k fallback : α} (mem : k ∈ m) : + getKeyD (insertManyIfNewUnit m l) k fallback = getKeyD m k fallback := by + refine m.inductionOn (fun _ mem => ?_) mem + simp only [insertManyIfNewUnit_list_mk] + exact DHashMap.Const.getKeyD_insertManyIfNewUnit_list_of_mem mem + +theorem size_insertManyIfNewUnit_list [EquivBEq α] [LawfulHashable α] + {l : List α} + (distinct : l.Pairwise (fun a b => (a == b) = false)) : + (∀ (a : α), a ∈ m → l.contains a = false) → + (insertManyIfNewUnit m l).size = m.size + l.length := by + refine m.inductionOn (fun _ distinct => ?_) distinct + simp only [insertManyIfNewUnit_list_mk] + exact DHashMap.Const.size_insertManyIfNewUnit_list distinct + +theorem size_le_size_insertManyIfNewUnit_list [EquivBEq α] [LawfulHashable α] + {l : List α} : + m.size ≤ (insertManyIfNewUnit m l).size := by + refine m.inductionOn fun _ => ?_ + simp only [insertManyIfNewUnit_list_mk] + exact DHashMap.Const.size_le_size_insertManyIfNewUnit_list + +theorem size_le_size_insertManyIfNewUnit [EquivBEq α] [LawfulHashable α] + {l : ρ} : m.size ≤ (insertManyIfNewUnit m l).size := + insertManyIfNewUnit_ind m l (Nat.le_refl _) fun _ _ h => Nat.le_trans h size_le_size_insertIfNew + +theorem size_insertManyIfNewUnit_list_le [EquivBEq α] [LawfulHashable α] + {l : List α} : + (insertManyIfNewUnit m l).size ≤ m.size + l.length := by + refine m.inductionOn fun _ => ?_ + simp only [insertManyIfNewUnit_list_mk] + exact DHashMap.Const.size_insertManyIfNewUnit_list_le + +@[simp] +theorem insertManyIfNewUnit_list_eq_empty_iff [EquivBEq α] [LawfulHashable α] {l : List α} : + insertManyIfNewUnit m l = ∅ ↔ m = ∅ ∧ l = [] := by + refine m.inductionOn fun _ => ?_ + simp only [insertManyIfNewUnit_list_mk, ← isEmpty_iff, ← List.isEmpty_iff, + Bool.coe_iff_coe, ← Bool.and_eq_true] + exact DHashMap.Const.isEmpty_insertManyIfNewUnit_list + +theorem eq_empty_of_insertManyIfNewUnit_eq_empty [EquivBEq α] [LawfulHashable α] {l : ρ} : + insertManyIfNewUnit m l = ∅ → m = ∅ := + insertManyIfNewUnit_ind m l id fun _ _ _ h => absurd h not_insertIfNew_eq_empty + +theorem get?_insertManyIfNewUnit_list [EquivBEq α] [LawfulHashable α] + {l : List α} {k : α} : + get? (insertManyIfNewUnit m l) k = + if k ∈ m ∨ l.contains k then some () else none := by + refine m.inductionOn fun _ => ?_ + simp only [insertManyIfNewUnit_list_mk] + exact DHashMap.Const.get?_insertManyIfNewUnit_list + +theorem get_insertManyIfNewUnit_list [EquivBEq α] [LawfulHashable α] + {l : List α} {k : α} {h} : + get (insertManyIfNewUnit m l) k h = () := + rfl + +theorem get!_insertManyIfNewUnit_list [EquivBEq α] [LawfulHashable α] + {l : List α} {k : α} : + get! (insertManyIfNewUnit m l) k = () := + rfl + +theorem getD_insertManyIfNewUnit_list [EquivBEq α] [LawfulHashable α] + {l : List α} {k : α} {fallback : Unit} : + getD (insertManyIfNewUnit m l) k fallback = () := + rfl + +end Const + +end insertMany + +end ExtDHashMap + +namespace ExtDHashMap + +@[simp] +theorem ofList_nil [EquivBEq α] [LawfulHashable α] : + ofList ([] : List ((a : α) × β a)) = ∅ := rfl + +@[simp] +theorem ofList_singleton [EquivBEq α] [LawfulHashable α] {k : α} {v : β k} : + ofList [⟨k, v⟩] = (∅ : ExtDHashMap α β).insert k v := rfl + +theorem ofList_cons [EquivBEq α] [LawfulHashable α] {k : α} {v : β k} {tl : List ((a : α) × β a)} : + ofList (⟨k, v⟩ :: tl) = ((∅ : ExtDHashMap α β).insert k v).insertMany tl := by + conv => rhs; apply insertMany_list_mk + exact congrArg Quotient.mk' DHashMap.ofList_cons + +@[simp] +theorem contains_ofList [EquivBEq α] [LawfulHashable α] + {l : List ((a : α) × β a)} {k : α} : + (ofList l).contains k = (l.map Sigma.fst).contains k := + DHashMap.contains_ofList + +@[simp] +theorem mem_ofList [EquivBEq α] [LawfulHashable α] + {l : List ((a : α) × β a)} {k : α} : + k ∈ ofList l ↔ (l.map Sigma.fst).contains k := + DHashMap.mem_ofList + +theorem get?_ofList_of_contains_eq_false [LawfulBEq α] + {l : List ((a : α) × β a)} {k : α} + (contains_eq_false : (l.map Sigma.fst).contains k = false) : + (ofList l).get? k = none := + DHashMap.get?_ofList_of_contains_eq_false contains_eq_false + +theorem get?_ofList_of_mem [LawfulBEq α] + {l : List ((a : α) × β a)} {k k' : α} (k_beq : k == k') {v : β k} + (distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) + (mem : ⟨k, v⟩ ∈ l) : + (ofList l).get? k' = some (cast (by congr; apply LawfulBEq.eq_of_beq k_beq) v) := + DHashMap.get?_ofList_of_mem k_beq distinct mem + +theorem get_ofList_of_mem [LawfulBEq α] + {l : List ((a : α) × β a)} {k k' : α} (k_beq : k == k') {v : β k} + (distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) + (mem : ⟨k, v⟩ ∈ l) + {h} : + (ofList l).get k' h = cast (by congr; apply LawfulBEq.eq_of_beq k_beq) v := + DHashMap.get_ofList_of_mem k_beq distinct mem + +theorem get!_ofList_of_contains_eq_false [LawfulBEq α] + {l : List ((a : α) × β a)} {k : α} [Inhabited (β k)] + (contains_eq_false : (l.map Sigma.fst).contains k = false) : + (ofList l).get! k = default := + DHashMap.get!_ofList_of_contains_eq_false contains_eq_false + +theorem get!_ofList_of_mem [LawfulBEq α] + {l : List ((a : α) × β a)} {k k' : α} (k_beq : k == k') {v : β k} [Inhabited (β k')] + (distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) + (mem : ⟨k, v⟩ ∈ l) : + (ofList l).get! k' = cast (by congr; apply LawfulBEq.eq_of_beq k_beq) v := + DHashMap.get!_ofList_of_mem k_beq distinct mem + +theorem getD_ofList_of_contains_eq_false [LawfulBEq α] + {l : List ((a : α) × β a)} {k : α} {fallback : β k} + (contains_eq_false : (l.map Sigma.fst).contains k = false) : + (ofList l).getD k fallback = fallback := + DHashMap.getD_ofList_of_contains_eq_false contains_eq_false + +theorem getD_ofList_of_mem [LawfulBEq α] + {l : List ((a : α) × β a)} {k k' : α} (k_beq : k == k') {v : β k} {fallback : β k'} + (distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) + (mem : ⟨k, v⟩ ∈ l) : + (ofList l).getD k' fallback = cast (by congr; apply LawfulBEq.eq_of_beq k_beq) v := + DHashMap.getD_ofList_of_mem k_beq distinct mem + +theorem getKey?_ofList_of_contains_eq_false [EquivBEq α] [LawfulHashable α] + {l : List ((a : α) × β a)} {k : α} + (contains_eq_false : (l.map Sigma.fst).contains k = false) : + (ofList l).getKey? k = none := + DHashMap.getKey?_ofList_of_contains_eq_false contains_eq_false + +theorem getKey?_ofList_of_mem [EquivBEq α] [LawfulHashable α] + {l : List ((a : α) × β a)} + {k k' : α} (k_beq : k == k') + (distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) + (mem : k ∈ l.map Sigma.fst) : + (ofList l).getKey? k' = some k := + DHashMap.getKey?_ofList_of_mem k_beq distinct mem + +theorem getKey_ofList_of_mem [EquivBEq α] [LawfulHashable α] + {l : List ((a : α) × β a)} + {k k' : α} (k_beq : k == k') + (distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) + (mem : k ∈ l.map Sigma.fst) + {h} : + (ofList l).getKey k' h = k := + DHashMap.getKey_ofList_of_mem k_beq distinct mem + +theorem getKey!_ofList_of_contains_eq_false [EquivBEq α] [LawfulHashable α] [Inhabited α] + {l : List ((a : α) × β a)} {k : α} + (contains_eq_false : (l.map Sigma.fst).contains k = false) : + (ofList l).getKey! k = default := + DHashMap.getKey!_ofList_of_contains_eq_false contains_eq_false + +theorem getKey!_ofList_of_mem [EquivBEq α] [LawfulHashable α] [Inhabited α] + {l : List ((a : α) × β a)} + {k k' : α} (k_beq : k == k') + (distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) + (mem : k ∈ l.map Sigma.fst) : + (ofList l).getKey! k' = k := + DHashMap.getKey!_ofList_of_mem k_beq distinct mem + +theorem getKeyD_ofList_of_contains_eq_false [EquivBEq α] [LawfulHashable α] + {l : List ((a : α) × β a)} {k fallback : α} + (contains_eq_false : (l.map Sigma.fst).contains k = false) : + (ofList l).getKeyD k fallback = fallback := + DHashMap.getKeyD_ofList_of_contains_eq_false contains_eq_false + +theorem getKeyD_ofList_of_mem [EquivBEq α] [LawfulHashable α] + {l : List ((a : α) × β a)} + {k k' fallback : α} (k_beq : k == k') + (distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) + (mem : k ∈ l.map Sigma.fst) : + (ofList l).getKeyD k' fallback = k := + DHashMap.getKeyD_ofList_of_mem k_beq distinct mem + +theorem size_ofList [EquivBEq α] [LawfulHashable α] + {l : List ((a : α) × β a)} (distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) : + (ofList l).size = l.length := + DHashMap.size_ofList distinct + +theorem size_ofList_le [EquivBEq α] [LawfulHashable α] + {l : List ((a : α) × β a)} : + (ofList l).size ≤ l.length := + DHashMap.size_ofList_le + +@[simp] +theorem ofList_eq_empty_iff [EquivBEq α] [LawfulHashable α] {l : List ((a : α) × β a)} : + ofList l = ∅ ↔ l = [] := by + simpa only [← isEmpty_iff, ← List.isEmpty_iff, Bool.coe_iff_coe] using + DHashMap.isEmpty_ofList + +namespace Const + +variable {β : Type v} + +@[simp] +theorem ofList_nil [EquivBEq α] [LawfulHashable α] : + ofList ([] : List (α × β)) = ∅ := + rfl + +@[simp] +theorem ofList_singleton [EquivBEq α] [LawfulHashable α] {k : α} {v : β} : + ofList [⟨k, v⟩] = (∅ : ExtDHashMap α (fun _ => β)).insert k v := + rfl + +theorem ofList_cons [EquivBEq α] [LawfulHashable α] {k : α} {v : β} {tl : List (α × β)} : + ofList (⟨k, v⟩ :: tl) = insertMany ((∅ : ExtDHashMap α (fun _ => β)).insert k v) tl := by + conv => rhs; apply insertMany_list_mk + exact congrArg Quotient.mk' DHashMap.Const.ofList_cons + +@[simp] +theorem contains_ofList [EquivBEq α] [LawfulHashable α] + {l : List (α × β)} {k : α} : + (ofList l).contains k = (l.map Prod.fst).contains k := + DHashMap.Const.contains_ofList + +@[simp] +theorem mem_ofList [EquivBEq α] [LawfulHashable α] + {l : List (α × β)} {k : α} : + k ∈ ofList l ↔ (l.map Prod.fst).contains k := + DHashMap.Const.mem_ofList + +theorem get?_ofList_of_contains_eq_false [EquivBEq α] [LawfulHashable α] + {l : List (α × β)} {k : α} + (contains_eq_false : (l.map Prod.fst).contains k = false) : + get? (ofList l) k = none := + DHashMap.Const.get?_ofList_of_contains_eq_false contains_eq_false + +theorem get?_ofList_of_mem [EquivBEq α] [LawfulHashable α] + {l : List (α × β)} {k k' : α} (k_beq : k == k') {v : β} + (distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) + (mem : ⟨k, v⟩ ∈ l) : + get? (ofList l) k' = some v := + DHashMap.Const.get?_ofList_of_mem k_beq distinct mem + +theorem get_ofList_of_mem [EquivBEq α] [LawfulHashable α] + {l : List (α × β)} {k k' : α} (k_beq : k == k') {v : β} + (distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) + (mem : ⟨k, v⟩ ∈ l) + {h} : + get (ofList l) k' h = v := + DHashMap.Const.get_ofList_of_mem k_beq distinct mem + +theorem get!_ofList_of_contains_eq_false [EquivBEq α] [LawfulHashable α] + {l : List (α × β)} {k : α} [Inhabited β] + (contains_eq_false : (l.map Prod.fst).contains k = false) : + get! (ofList l) k = (default : β) := + DHashMap.Const.get!_ofList_of_contains_eq_false contains_eq_false + +theorem get!_ofList_of_mem [EquivBEq α] [LawfulHashable α] + {l : List (α × β)} {k k' : α} (k_beq : k == k') {v : β} [Inhabited β] + (distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) + (mem : ⟨k, v⟩ ∈ l) : + get! (ofList l) k' = v := + DHashMap.Const.get!_ofList_of_mem k_beq distinct mem + +theorem getD_ofList_of_contains_eq_false [EquivBEq α] [LawfulHashable α] + {l : List (α × β)} {k : α} {fallback : β} + (contains_eq_false : (l.map Prod.fst).contains k = false) : + getD (ofList l) k fallback = fallback := + DHashMap.Const.getD_ofList_of_contains_eq_false contains_eq_false + +theorem getD_ofList_of_mem [EquivBEq α] [LawfulHashable α] + {l : List (α × β)} {k k' : α} (k_beq : k == k') {v : β} {fallback : β} + (distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) + (mem : ⟨k, v⟩ ∈ l) : + getD (ofList l) k' fallback = v := + DHashMap.Const.getD_ofList_of_mem k_beq distinct mem + +theorem getKey?_ofList_of_contains_eq_false [EquivBEq α] [LawfulHashable α] + {l : List (α × β)} {k : α} + (contains_eq_false : (l.map Prod.fst).contains k = false) : + (ofList l).getKey? k = none := + DHashMap.Const.getKey?_ofList_of_contains_eq_false contains_eq_false + +theorem getKey?_ofList_of_mem [EquivBEq α] [LawfulHashable α] + {l : List (α × β)} + {k k' : α} (k_beq : k == k') + (distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) + (mem : k ∈ l.map Prod.fst) : + (ofList l).getKey? k' = some k := + DHashMap.Const.getKey?_ofList_of_mem k_beq distinct mem + +theorem getKey_ofList_of_mem [EquivBEq α] [LawfulHashable α] + {l : List (α × β)} + {k k' : α} (k_beq : k == k') + (distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) + (mem : k ∈ l.map Prod.fst) + {h} : + (ofList l).getKey k' h = k := + DHashMap.Const.getKey_ofList_of_mem k_beq distinct mem + +theorem getKey!_ofList_of_contains_eq_false [EquivBEq α] [LawfulHashable α] + [Inhabited α] {l : List (α × β)} {k : α} + (contains_eq_false : (l.map Prod.fst).contains k = false) : + (ofList l).getKey! k = default := + DHashMap.Const.getKey!_ofList_of_contains_eq_false contains_eq_false + +theorem getKey!_ofList_of_mem [EquivBEq α] [LawfulHashable α] [Inhabited α] + {l : List (α × β)} + {k k' : α} (k_beq : k == k') + (distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) + (mem : k ∈ l.map Prod.fst) : + (ofList l).getKey! k' = k := + DHashMap.Const.getKey!_ofList_of_mem k_beq distinct mem + +theorem getKeyD_ofList_of_contains_eq_false [EquivBEq α] [LawfulHashable α] + {l : List (α × β)} {k fallback : α} + (contains_eq_false : (l.map Prod.fst).contains k = false) : + (ofList l).getKeyD k fallback = fallback := + DHashMap.Const.getKeyD_ofList_of_contains_eq_false contains_eq_false + +theorem getKeyD_ofList_of_mem [EquivBEq α] [LawfulHashable α] + {l : List (α × β)} + {k k' fallback : α} (k_beq : k == k') + (distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) + (mem : k ∈ l.map Prod.fst) : + (ofList l).getKeyD k' fallback = k := + DHashMap.Const.getKeyD_ofList_of_mem k_beq distinct mem + +theorem size_ofList [EquivBEq α] [LawfulHashable α] + {l : List (α × β)} (distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) : + (ofList l).size = l.length := + DHashMap.Const.size_ofList distinct + +theorem size_ofList_le [EquivBEq α] [LawfulHashable α] + {l : List (α × β)} : + (ofList l).size ≤ l.length := + DHashMap.Const.size_ofList_le + +@[simp] +theorem ofList_eq_empty_iff [EquivBEq α] [LawfulHashable α] {l : List (α × β)} : + ofList l = ∅ ↔ l = [] := by + simpa only [← isEmpty_iff, ← List.isEmpty_iff, Bool.coe_iff_coe] using + DHashMap.Const.isEmpty_ofList + +@[simp] +theorem unitOfList_nil [EquivBEq α] [LawfulHashable α] : + unitOfList ([] : List α) = ∅ := + congrArg Quotient.mk' DHashMap.Const.unitOfList_nil + +@[simp] +theorem unitOfList_singleton [EquivBEq α] [LawfulHashable α] {k : α} : + unitOfList [k] = (∅ : ExtDHashMap α (fun _ => Unit)).insertIfNew k () := + congrArg Quotient.mk' DHashMap.Const.unitOfList_singleton + +theorem unitOfList_cons [EquivBEq α] [LawfulHashable α] {hd : α} {tl : List α} : + unitOfList (hd :: tl) = + insertManyIfNewUnit ((∅ : ExtDHashMap α (fun _ => Unit)).insertIfNew hd ()) tl := by + conv => rhs; apply insertManyIfNewUnit_list_mk + exact congrArg Quotient.mk' DHashMap.Const.unitOfList_cons + +@[simp] +theorem contains_unitOfList [EquivBEq α] [LawfulHashable α] + {l : List α} {k : α} : + (unitOfList l).contains k = l.contains k := + DHashMap.Const.contains_unitOfList + +@[simp] +theorem mem_unitOfList [EquivBEq α] [LawfulHashable α] + {l : List α} {k : α} : + k ∈ unitOfList l ↔ l.contains k := + DHashMap.Const.mem_unitOfList + +theorem getKey?_unitOfList_of_contains_eq_false [EquivBEq α] [LawfulHashable α] + {l : List α} {k : α} (contains_eq_false : l.contains k = false) : + getKey? (unitOfList l) k = none := + DHashMap.Const.getKey?_unitOfList_of_contains_eq_false contains_eq_false + +theorem getKey?_unitOfList_of_mem [EquivBEq α] [LawfulHashable α] + {l : List α} {k k' : α} (k_beq : k == k') + (distinct : l.Pairwise (fun a b => (a == b) = false)) (mem : k ∈ l) : + getKey? (unitOfList l) k' = some k := + DHashMap.Const.getKey?_unitOfList_of_mem k_beq distinct mem + +theorem getKey_unitOfList_of_mem [EquivBEq α] [LawfulHashable α] + {l : List α} + {k k' : α} (k_beq : k == k') + (distinct : l.Pairwise (fun a b => (a == b) = false)) + (mem : k ∈ l) {h} : + getKey (unitOfList l) k' h = k := + DHashMap.Const.getKey_unitOfList_of_mem k_beq distinct mem + +theorem getKey!_unitOfList_of_contains_eq_false [EquivBEq α] [LawfulHashable α] + [Inhabited α] {l : List α} {k : α} + (contains_eq_false : l.contains k = false) : + getKey! (unitOfList l) k = default := + DHashMap.Const.getKey!_unitOfList_of_contains_eq_false contains_eq_false + +theorem getKey!_unitOfList_of_mem [EquivBEq α] [LawfulHashable α] + [Inhabited α] {l : List α} {k k' : α} (k_beq : k == k') + (distinct : l.Pairwise (fun a b => (a == b) = false)) + (mem : k ∈ l) : + getKey! (unitOfList l) k' = k := + DHashMap.Const.getKey!_unitOfList_of_mem k_beq distinct mem + +theorem getKeyD_unitOfList_of_contains_eq_false [EquivBEq α] [LawfulHashable α] + {l : List α} {k fallback : α} + (contains_eq_false : l.contains k = false) : + getKeyD (unitOfList l) k fallback = fallback := + DHashMap.Const.getKeyD_unitOfList_of_contains_eq_false contains_eq_false + +theorem getKeyD_unitOfList_of_mem [EquivBEq α] [LawfulHashable α] + {l : List α} {k k' fallback : α} (k_beq : k == k') + (distinct : l.Pairwise (fun a b => (a == b) = false)) + (mem : k ∈ l) : + getKeyD (unitOfList l) k' fallback = k := + DHashMap.Const.getKeyD_unitOfList_of_mem k_beq distinct mem + +theorem size_unitOfList [EquivBEq α] [LawfulHashable α] + {l : List α} + (distinct : l.Pairwise (fun a b => (a == b) = false)) : + (unitOfList l).size = l.length := + DHashMap.Const.size_unitOfList distinct + +theorem size_unitOfList_le [EquivBEq α] [LawfulHashable α] + {l : List α} : + (unitOfList l).size ≤ l.length := + DHashMap.Const.size_unitOfList_le + +@[simp] +theorem unitOfList_eq_empty_iff [EquivBEq α] [LawfulHashable α] {l : List α} : + unitOfList l = ∅ ↔ l = [] := by + simpa only [← isEmpty_iff, ← List.isEmpty_iff, Bool.coe_iff_coe] using + DHashMap.Const.isEmpty_unitOfList + +@[simp] +theorem get?_unitOfList [EquivBEq α] [LawfulHashable α] + {l : List α} {k : α} : + get? (unitOfList l) k = + if l.contains k then some () else none := + DHashMap.Const.get?_unitOfList + +@[simp] +theorem get_unitOfList [EquivBEq α] [LawfulHashable α] + {l : List α} {k : α} {h} : + get (unitOfList l) k h = () := + DHashMap.Const.get_unitOfList + +@[simp] +theorem get!_unitOfList [EquivBEq α] [LawfulHashable α] + {l : List α} {k : α} : + get! (unitOfList l) k = () := + DHashMap.Const.get!_unitOfList + +@[simp] +theorem getD_unitOfList [EquivBEq α] [LawfulHashable α] + {l : List α} {k : α} {fallback : Unit} : + getD (unitOfList l) k fallback = () := + DHashMap.Const.getD_unitOfList + +end Const + +variable {m : ExtDHashMap α β} + +section Alter + +theorem alter_eq_empty_iff_erase_eq_empty [LawfulBEq α] {k : α} {f : Option (β k) → Option (β k)} : + m.alter k f = ∅ ↔ m.erase k = ∅ ∧ f (m.get? k) = none := by + rcases m with ⟨m⟩ + simp only [← isEmpty_iff] + dsimp only [isEmpty, alter, Quotient.lift, Quotient.mk', Quotient.mk] + simp only [DHashMap.isEmpty_alter_eq_isEmpty_erase, Bool.and_eq_true, Option.isNone_iff_eq_none] + rfl + +@[simp] +theorem alter_eq_empty_iff [LawfulBEq α] {k : α} {f : Option (β k) → Option (β k)} : + alter m k f = ∅ ↔ (m = ∅ ∨ (m.size = 1 ∧ k ∈ m)) ∧ f (get? m k) = none := by + simp only [alter_eq_empty_iff_erase_eq_empty, erase_eq_empty_iff] + +theorem contains_alter [LawfulBEq α] {k k' : α} {f : Option (β k) → Option (β k)} : + (m.alter k f).contains k' = if k == k' then (f (m.get? k)).isSome else m.contains k' := + m.inductionOn fun _ => DHashMap.contains_alter + +theorem mem_alter [LawfulBEq α] {k k' : α} {f : Option (β k) → Option (β k)} : + k' ∈ m.alter k f ↔ if k == k' then (f (m.get? k)).isSome = true else k' ∈ m := + m.inductionOn fun _ => DHashMap.mem_alter + +theorem mem_alter_of_beq [LawfulBEq α] {k k' : α} {f : Option (β k) → Option (β k)} (h : k == k') : + k' ∈ m.alter k f ↔ (f (m.get? k)).isSome := + m.inductionOn (fun _ h => DHashMap.mem_alter_of_beq h) h + +@[simp] +theorem contains_alter_self [LawfulBEq α] {k : α} {f : Option (β k) → Option (β k)} : + (m.alter k f).contains k = (f (m.get? k)).isSome := + m.inductionOn fun _ => DHashMap.contains_alter_self + +@[simp] +theorem mem_alter_self [LawfulBEq α] {k : α} {f : Option (β k) → Option (β k)} : + k ∈ m.alter k f ↔ (f (m.get? k)).isSome := + m.inductionOn fun _ => DHashMap.mem_alter_self + +theorem contains_alter_of_beq_eq_false [LawfulBEq α] {k k' : α} {f : Option (β k) → Option (β k)} + (h : (k == k') = false) : (m.alter k f).contains k' = m.contains k' := + m.inductionOn (fun _ h => DHashMap.contains_alter_of_beq_eq_false h) h + +theorem mem_alter_of_beq_eq_false [LawfulBEq α] {k k' : α} {f : Option (β k) → Option (β k)} + (h : (k == k') = false) : k' ∈ m.alter k f ↔ k' ∈ m := + m.inductionOn (fun _ h => DHashMap.mem_alter_of_beq_eq_false h) h + +theorem size_alter [LawfulBEq α] {k : α} {f : Option (β k) → Option (β k)} : + (m.alter k f).size = + if k ∈ m ∧ (f (m.get? k)).isNone then + m.size - 1 + else if k ∉ m ∧ (f (m.get? k)).isSome then + m.size + 1 + else + m.size := + m.inductionOn fun _ => DHashMap.size_alter + +theorem size_alter_eq_add_one [LawfulBEq α] {k : α} {f : Option (β k) → Option (β k)} + (h : k ∉ m) (h' : (f (m.get? k)).isSome) : + (m.alter k f).size = m.size + 1 := + m.inductionOn (fun _ h h' => DHashMap.size_alter_eq_add_one h h') h h' + +theorem size_alter_eq_sub_one [LawfulBEq α] {k : α} {f : Option (β k) → Option (β k)} + (h : k ∈ m) (h' : (f (m.get? k)).isNone) : + (m.alter k f).size = m.size - 1 := + m.inductionOn (fun _ h h' => DHashMap.size_alter_eq_sub_one h h') h h' + +theorem size_alter_eq_self_of_not_mem [LawfulBEq α] {k : α} {f : Option (β k) → Option (β k)} + (h : k ∉ m) (h' : (f (m.get? k)).isNone) : (m.alter k f).size = m.size := + m.inductionOn (fun _ h h' => DHashMap.size_alter_eq_self_of_not_mem h h') h h' + +theorem size_alter_eq_self_of_mem [LawfulBEq α] {k : α} {f : Option (β k) → Option (β k)} + (h : k ∈ m) (h' : (f (m.get? k)).isSome) : (m.alter k f).size = m.size := + m.inductionOn (fun _ h h' => DHashMap.size_alter_eq_self_of_mem h h') h h' + +theorem size_alter_le_size [LawfulBEq α] {k : α} {f : Option (β k) → Option (β k)} : + (m.alter k f).size ≤ m.size + 1 := + m.inductionOn fun _ => DHashMap.size_alter_le_size + +theorem size_le_size_alter [LawfulBEq α] {k : α} {f : Option (β k) → Option (β k)} : + m.size - 1 ≤ (m.alter k f).size := + m.inductionOn fun _ => DHashMap.size_le_size_alter + +theorem get?_alter [LawfulBEq α] {k k' : α} {f : Option (β k) → Option (β k)} : + (m.alter k f).get? k' = + if h : k == k' then + (cast (congrArg (Option ∘ β) (eq_of_beq h)) (f (m.get? k))) + else + m.get? k' := + m.inductionOn fun _ => DHashMap.get?_alter + +@[simp] +theorem get?_alter_self [LawfulBEq α] {k : α} {f : Option (β k) → Option (β k)} : + (m.alter k f).get? k = f (m.get? k) := + m.inductionOn fun _ => DHashMap.get?_alter_self + +theorem get_alter [LawfulBEq α] {k k' : α} {f : Option (β k) → Option (β k)} + {h : k' ∈ m.alter k f} : + (m.alter k f).get k' h = + if heq : k == k' then + haveI h' : (f (m.get? k)).isSome := mem_alter_of_beq heq |>.mp h + cast (congrArg β (eq_of_beq heq)) <| (f (m.get? k)).get <| h' + else + haveI h' : k' ∈ m := mem_alter_of_beq_eq_false (Bool.not_eq_true _ ▸ heq) |>.mp h + m.get k' h' := + m.inductionOn (fun _ _ => DHashMap.get_alter) h + +@[simp] +theorem get_alter_self [LawfulBEq α] {k : α} {f : Option (β k) → Option (β k)} + {h : k ∈ m.alter k f} : + haveI h' : (f (m.get? k)).isSome := mem_alter_self.mp h + (m.alter k f).get k h = (f (m.get? k)).get h' := + m.inductionOn (fun _ _ => DHashMap.get_alter_self) h + +theorem get!_alter [LawfulBEq α] {k k' : α} [hi : Inhabited (β k')] + {f : Option (β k) → Option (β k)} : (m.alter k f).get! k' = + if heq : k == k' then + (f (m.get? k)).map (cast (congrArg β (eq_of_beq heq))) |>.get! + else + m.get! k' := + m.inductionOn fun _ => DHashMap.get!_alter + +@[simp] +theorem get!_alter_self [LawfulBEq α] {k : α} [Inhabited (β k)] {f : Option (β k) → Option (β k)} : + (m.alter k f).get! k = (f (m.get? k)).get! := + m.inductionOn fun _ => DHashMap.get!_alter_self + +theorem getD_alter [LawfulBEq α] {k k' : α} {fallback : β k'} {f : Option (β k) → Option (β k)} : + (m.alter k f).getD k' fallback = + if heq : k == k' then + f (m.get? k) |>.map (cast (congrArg β <| eq_of_beq heq)) |>.getD fallback + else + m.getD k' fallback := + m.inductionOn fun _ => DHashMap.getD_alter + +@[simp] +theorem getD_alter_self [LawfulBEq α] {k : α} {fallback : β k} {f : Option (β k) → Option (β k)} : + (m.alter k f).getD k fallback = (f (m.get? k)).getD fallback := + m.inductionOn fun _ => DHashMap.getD_alter_self + +theorem getKey?_alter [LawfulBEq α] {k k' : α} {f : Option (β k) → Option (β k)} : + (m.alter k f).getKey? k' = + if k == k' then + if (f (m.get? k)).isSome then some k else none + else + m.getKey? k' := + m.inductionOn fun _ => DHashMap.getKey?_alter + +theorem getKey?_alter_self [LawfulBEq α] {k : α} {f : Option (β k) → Option (β k)} : + (m.alter k f).getKey? k = if (f (m.get? k)).isSome then some k else none := + m.inductionOn fun _ => DHashMap.getKey?_alter_self + +theorem getKey!_alter [LawfulBEq α] [Inhabited α] {k k' : α} {f : Option (β k) → Option (β k)} : + (m.alter k f).getKey! k' = + if k == k' then + if (f (m.get? k)).isSome then k else default + else + m.getKey! k' := + m.inductionOn fun _ => DHashMap.getKey!_alter + +theorem getKey!_alter_self [LawfulBEq α] [Inhabited α] {k : α} {f : Option (β k) → Option (β k)} : + (m.alter k f).getKey! k = if (f (m.get? k)).isSome then k else default := + m.inductionOn fun _ => DHashMap.getKey!_alter_self + +theorem getKey_alter [LawfulBEq α] [Inhabited α] {k k' : α} {f : Option (β k) → Option (β k)} + {h : k' ∈ m.alter k f} : + (m.alter k f).getKey k' h = + if heq : k == k' then + k + else + haveI h' : k' ∈ m := mem_alter_of_beq_eq_false (Bool.not_eq_true _ ▸ heq) |>.mp h + m.getKey k' h' := + m.inductionOn (fun _ _ => DHashMap.getKey_alter) h + +@[simp] +theorem getKey_alter_self [LawfulBEq α] [Inhabited α] {k : α} {f : Option (β k) → Option (β k)} + {h : k ∈ m.alter k f} : (m.alter k f).getKey k h = k := + m.inductionOn (fun _ _ => DHashMap.getKey_alter_self) h + +theorem getKeyD_alter [LawfulBEq α] {k k' fallback : α} {f : Option (β k) → Option (β k)} : + (m.alter k f).getKeyD k' fallback = + if k == k' then + if (f (m.get? k)).isSome then k else fallback + else + m.getKeyD k' fallback := + m.inductionOn fun _ => DHashMap.getKeyD_alter + +@[simp] +theorem getKeyD_alter_self [LawfulBEq α] [Inhabited α] {k : α} {fallback : α} + {f : Option (β k) → Option (β k)} : + (m.alter k f).getKeyD k fallback = if (f (m.get? k)).isSome then k else fallback := + m.inductionOn fun _ => DHashMap.getKeyD_alter_self + +namespace Const + +variable {β : Type v} {m : ExtDHashMap α (fun _ => β)} + +theorem alter_eq_empty_iff_erase_eq_empty [EquivBEq α] [LawfulHashable α] {k : α} {f : Option β → Option β} : + alter m k f = ∅ ↔ m.erase k = ∅ ∧ f (get? m k) = none := by + rcases m with ⟨m⟩ + simp only [← isEmpty_iff] + dsimp only [isEmpty, alter, Quotient.lift, Quotient.mk', Quotient.mk] + simp only [DHashMap.Const.isEmpty_alter_eq_isEmpty_erase, Bool.and_eq_true, + Option.isNone_iff_eq_none] + rfl + +@[simp] +theorem alter_eq_empty_iff [EquivBEq α] [LawfulHashable α] {k : α} {f : Option β → Option β} : + alter m k f = ∅ ↔ (m = ∅ ∨ (m.size = 1 ∧ k ∈ m)) ∧ f (get? m k) = none := by + simp only [alter_eq_empty_iff_erase_eq_empty, erase_eq_empty_iff] + +theorem contains_alter [EquivBEq α] [LawfulHashable α] {k k': α} {f : Option β → Option β} : + (Const.alter m k f).contains k' = + if k == k' then (f (Const.get? m k)).isSome else m.contains k' := + m.inductionOn fun _ => DHashMap.Const.contains_alter + +theorem mem_alter [EquivBEq α] [LawfulHashable α] {k k': α} {f : Option β → Option β} : + k' ∈ Const.alter m k f ↔ if k == k' then (f (Const.get? m k)).isSome = true else k' ∈ m := + m.inductionOn fun _ => DHashMap.Const.mem_alter + +theorem mem_alter_of_beq [EquivBEq α] [LawfulHashable α] {k k': α} {f : Option β → Option β} + (h : k == k') : k' ∈ Const.alter m k f ↔ (f (Const.get? m k)).isSome := + m.inductionOn (fun _ h => DHashMap.Const.mem_alter_of_beq h) h + +@[simp] +theorem contains_alter_self [EquivBEq α] [LawfulHashable α] {k : α} {f : Option β → Option β} : + (Const.alter m k f).contains k = (f (Const.get? m k)).isSome := + m.inductionOn fun _ => DHashMap.Const.contains_alter_self + +@[simp] +theorem mem_alter_self [EquivBEq α] [LawfulHashable α] {k : α} {f : Option β → Option β} : + k ∈ Const.alter m k f ↔ (f (Const.get? m k)).isSome := + m.inductionOn fun _ => DHashMap.Const.mem_alter_self + +theorem contains_alter_of_beq_eq_false [EquivBEq α] [LawfulHashable α] {k k' : α} + {f : Option β → Option β} (h : (k == k') = false) : + (Const.alter m k f).contains k' = m.contains k' := + m.inductionOn (fun _ h => DHashMap.Const.contains_alter_of_beq_eq_false h) h + +theorem mem_alter_of_beq_eq_false [EquivBEq α] [LawfulHashable α] {k k' : α} + {f : Option β → Option β} (h : (k == k') = false) : k' ∈ Const.alter m k f ↔ k' ∈ m := + m.inductionOn (fun _ h => DHashMap.Const.mem_alter_of_beq_eq_false h) h + +theorem size_alter [EquivBEq α] [LawfulHashable α] {k : α} {f : Option β → Option β} : + (Const.alter m k f).size = + if k ∈ m ∧ (f (Const.get? m k)).isNone then + m.size - 1 + else if k ∉ m ∧ (f (Const.get? m k)).isSome then + m.size + 1 + else + m.size := + m.inductionOn fun _ => DHashMap.Const.size_alter + +theorem size_alter_eq_add_one [EquivBEq α] [LawfulHashable α] {k : α} {f : Option β → Option β} + (h : k ∉ m) (h' : (f (Const.get? m k)).isSome) : + (Const.alter m k f).size = m.size + 1 := + m.inductionOn (fun _ h h' => DHashMap.Const.size_alter_eq_add_one h h') h h' + +theorem size_alter_eq_sub_one [EquivBEq α] [LawfulHashable α] {k : α} {f : Option β → Option β} + (h : k ∈ m) (h' : (f (Const.get? m k)).isNone) : + (Const.alter m k f).size = m.size - 1 := + m.inductionOn (fun _ h h' => DHashMap.Const.size_alter_eq_sub_one h h') h h' + +theorem size_alter_eq_self_of_not_mem [EquivBEq α] [LawfulHashable α] {k : α} {f : Option β → Option β} + (h : k ∉ m) (h' : (f (Const.get? m k)).isNone) : (Const.alter m k f).size = m.size := + m.inductionOn (fun _ h h' => DHashMap.Const.size_alter_eq_self_of_not_mem h h') h h' + +theorem size_alter_eq_self_of_mem [EquivBEq α] [LawfulHashable α] {k : α} {f : Option β → Option β} + (h : k ∈ m) (h' : (f (Const.get? m k)).isSome) : (Const.alter m k f).size = m.size := + m.inductionOn (fun _ h h' => DHashMap.Const.size_alter_eq_self_of_mem h h') h h' + +theorem size_alter_le_size [EquivBEq α] [LawfulHashable α] {k : α} {f : Option β → Option β} : + (Const.alter m k f).size ≤ m.size + 1 := + m.inductionOn fun _ => DHashMap.Const.size_alter_le_size + +theorem size_le_size_alter [EquivBEq α] [LawfulHashable α] {k : α} {f : Option β → Option β} : + m.size - 1 ≤ (Const.alter m k f).size := + m.inductionOn fun _ => DHashMap.Const.size_le_size_alter + +theorem get?_alter [EquivBEq α] [LawfulHashable α] {k k' : α} {f : Option β → Option β} : + Const.get? (Const.alter m k f) k' = + if k == k' then + f (Const.get? m k) + else + Const.get? m k' := + m.inductionOn fun _ => DHashMap.Const.get?_alter + +@[simp] +theorem get?_alter_self [EquivBEq α] [LawfulHashable α] {k : α} {f : Option β → Option β} : + Const.get? (Const.alter m k f) k = f (Const.get? m k) := + m.inductionOn fun _ => DHashMap.Const.get?_alter_self + +theorem get_alter [EquivBEq α] [LawfulHashable α] {k k' : α} {f : Option β → Option β} + {h : k' ∈ Const.alter m k f} : + Const.get (Const.alter m k f) k' h = + if heq : k == k' then + haveI h' : (f (Const.get? m k)).isSome := mem_alter_of_beq heq |>.mp h + f (Const.get? m k) |>.get h' + else + haveI h' : k' ∈ m := mem_alter_of_beq_eq_false (Bool.not_eq_true _ ▸ heq) |>.mp h + Const.get m k' h' := + m.inductionOn (fun _ _ => DHashMap.Const.get_alter) h + +@[simp] +theorem get_alter_self [EquivBEq α] [LawfulHashable α] {k : α} {f : Option β → Option β} + {h : k ∈ Const.alter m k f} : + haveI h' : (f (Const.get? m k)).isSome := mem_alter_self.mp h + Const.get (Const.alter m k f) k h = (f (Const.get? m k)).get h' := + m.inductionOn (fun _ _ => DHashMap.Const.get_alter_self) h + +theorem get!_alter [EquivBEq α] [LawfulHashable α] {k k' : α} [Inhabited β] + {f : Option β → Option β} : Const.get! (Const.alter m k f) k' = + if k == k' then + f (Const.get? m k) |>.get! + else + Const.get! m k' := + m.inductionOn fun _ => DHashMap.Const.get!_alter + +@[simp] +theorem get!_alter_self [EquivBEq α] [LawfulHashable α] {k : α} [Inhabited β] + {f : Option β → Option β} : Const.get! (Const.alter m k f) k = (f (Const.get? m k)).get! := + m.inductionOn fun _ => DHashMap.Const.get!_alter_self + +theorem getD_alter [EquivBEq α] [LawfulHashable α] {k k' : α} {fallback : β} + {f : Option β → Option β} : + Const.getD (Const.alter m k f) k' fallback = + if k == k' then + f (Const.get? m k) |>.getD fallback + else + Const.getD m k' fallback := + m.inductionOn fun _ => DHashMap.Const.getD_alter + +@[simp] +theorem getD_alter_self [EquivBEq α] [LawfulHashable α] {k : α} {fallback : β} + {f : Option β → Option β} : + Const.getD (Const.alter m k f) k fallback = (f (Const.get? m k)).getD fallback := + m.inductionOn fun _ => DHashMap.Const.getD_alter_self + +theorem getKey?_alter [EquivBEq α] [LawfulHashable α] {k k' : α} {f : Option β → Option β} : + (Const.alter m k f).getKey? k' = + if k == k' then + if (f (Const.get? m k)).isSome then some k else none + else + m.getKey? k' := + m.inductionOn fun _ => DHashMap.Const.getKey?_alter + +theorem getKey?_alter_self [EquivBEq α] [LawfulHashable α] {k : α} {f : Option β → Option β} : + (Const.alter m k f).getKey? k = if (f (Const.get? m k)).isSome then some k else none := + m.inductionOn fun _ => DHashMap.Const.getKey?_alter_self + +theorem getKey!_alter [EquivBEq α] [LawfulHashable α] [Inhabited α] {k k' : α} + {f : Option β → Option β} : (Const.alter m k f).getKey! k' = + if k == k' then + if (f (Const.get? m k)).isSome then k else default + else + m.getKey! k' := + m.inductionOn fun _ => DHashMap.Const.getKey!_alter + +theorem getKey!_alter_self [EquivBEq α] [LawfulHashable α] [Inhabited α] {k : α} + {f : Option β → Option β} : + (Const.alter m k f).getKey! k = if (f (Const.get? m k)).isSome then k else default := + m.inductionOn fun _ => DHashMap.Const.getKey!_alter_self + +theorem getKey_alter [EquivBEq α] [LawfulHashable α] [Inhabited α] {k k' : α} + {f : Option β → Option β} {h : k' ∈ Const.alter m k f} : + (Const.alter m k f).getKey k' h = + if heq : k == k' then + k + else + haveI h' : k' ∈ m := mem_alter_of_beq_eq_false (Bool.not_eq_true _ ▸ heq) |>.mp h + m.getKey k' h' := + m.inductionOn (fun _ _ => DHashMap.Const.getKey_alter) h + +@[simp] +theorem getKey_alter_self [EquivBEq α] [LawfulHashable α] [Inhabited α] {k : α} + {f : Option β → Option β} {h : k ∈ Const.alter m k f} : + (Const.alter m k f).getKey k h = k := + m.inductionOn (fun _ _ => DHashMap.Const.getKey_alter_self) h + +theorem getKeyD_alter [EquivBEq α] [LawfulHashable α] {k k' fallback : α} {f : Option β → Option β} : + (Const.alter m k f).getKeyD k' fallback = + if k == k' then + if (f (Const.get? m k)).isSome then k else fallback + else + m.getKeyD k' fallback := + m.inductionOn fun _ => DHashMap.Const.getKeyD_alter + +theorem getKeyD_alter_self [EquivBEq α] [LawfulHashable α] [Inhabited α] {k fallback : α} + {f : Option β → Option β} : + (Const.alter m k f).getKeyD k fallback = + if (f (Const.get? m k)).isSome then k else fallback := + m.inductionOn fun _ => DHashMap.Const.getKeyD_alter_self + +end Const + +end Alter + +section Modify + +@[simp] +theorem modify_eq_empty_iff [LawfulBEq α] {k : α} {f : β k → β k} : + m.modify k f = ∅ ↔ m = ∅ := by + simp only [← isEmpty_iff, Bool.coe_iff_coe] + exact m.inductionOn fun _ => DHashMap.isEmpty_modify + +@[simp] +theorem contains_modify [LawfulBEq α] {k k': α} {f : β k → β k} : + (m.modify k f).contains k' = m.contains k' := + m.inductionOn fun _ => DHashMap.contains_modify + +@[simp] +theorem mem_modify [LawfulBEq α] {k k': α} {f : β k → β k} : k' ∈ m.modify k f ↔ k' ∈ m := + m.inductionOn fun _ => DHashMap.mem_modify + +@[simp] +theorem size_modify [LawfulBEq α] {k : α} {f : β k → β k} : (m.modify k f).size = m.size := + m.inductionOn fun _ => DHashMap.size_modify + +theorem get?_modify [LawfulBEq α] {k k' : α} {f : β k → β k} : + (m.modify k f).get? k' = if h : k == k' then + (cast (congrArg (Option ∘ β) (eq_of_beq h)) ((m.get? k).map f)) + else + m.get? k' := + m.inductionOn fun _ => DHashMap.get?_modify + +@[simp] +theorem get?_modify_self [LawfulBEq α] {k : α} {f : β k → β k} : + (m.modify k f).get? k = (m.get? k).map f := + m.inductionOn fun _ => DHashMap.get?_modify_self + +theorem get_modify [LawfulBEq α] {k k' : α} {f : β k → β k} + (h : k' ∈ m.modify k f) : + (m.modify k f).get k' h = + if heq : k == k' then + haveI h' : k ∈ m := mem_congr heq |>.mpr <| mem_modify.mp h + cast (congrArg β (eq_of_beq heq)) <| f (m.get k h') + else + haveI h' : k' ∈ m := mem_modify.mp h + m.get k' h' := + m.inductionOn (fun _ h => DHashMap.get_modify h) h + +@[simp] +theorem get_modify_self [LawfulBEq α] {k : α} {f : β k → β k} {h : k ∈ m.modify k f} : + haveI h' : k ∈ m := mem_modify.mp h + (m.modify k f).get k h = f (m.get k h') := + m.inductionOn (fun _ _ => DHashMap.get_modify_self) h + +theorem get!_modify [LawfulBEq α] {k k' : α} [hi : Inhabited (β k')] {f : β k → β k} : + (m.modify k f).get! k' = + if heq : k == k' then + m.get? k |>.map f |>.map (cast (congrArg β (eq_of_beq heq))) |>.get! + else + m.get! k' := + m.inductionOn fun _ => DHashMap.get!_modify + +@[simp] +theorem get!_modify_self [LawfulBEq α] {k : α} [Inhabited (β k)] {f : β k → β k} : + (m.modify k f).get! k = ((m.get? k).map f).get! := + m.inductionOn fun _ => DHashMap.get!_modify_self + +theorem getD_modify [LawfulBEq α] {k k' : α} {fallback : β k'} {f : β k → β k} : + (m.modify k f).getD k' fallback = + if heq : k == k' then + m.get? k |>.map f |>.map (cast (congrArg β <| eq_of_beq heq)) |>.getD fallback + else + m.getD k' fallback := + m.inductionOn fun _ => DHashMap.getD_modify + +@[simp] +theorem getD_modify_self [LawfulBEq α] {k : α} {fallback : β k} {f : β k → β k} : + (m.modify k f).getD k fallback = ((m.get? k).map f).getD fallback := + m.inductionOn fun _ => DHashMap.getD_modify_self + +theorem getKey?_modify [LawfulBEq α] {k k' : α} {f : β k → β k} : + (m.modify k f).getKey? k' = + if k == k' then + if k ∈ m then some k else none + else + m.getKey? k' := + m.inductionOn fun _ => DHashMap.getKey?_modify + +theorem getKey?_modify_self [LawfulBEq α] {k : α} {f : β k → β k} : + (m.modify k f).getKey? k = if k ∈ m then some k else none := + m.inductionOn fun _ => DHashMap.getKey?_modify_self + +theorem getKey!_modify [LawfulBEq α] [Inhabited α] {k k' : α} {f : β k → β k} : + (m.modify k f).getKey! k' = + if k == k' then + if k ∈ m then k else default + else + m.getKey! k' := + m.inductionOn fun _ => DHashMap.getKey!_modify + +theorem getKey!_modify_self [LawfulBEq α] [Inhabited α] {k : α} {f : β k → β k} : + (m.modify k f).getKey! k = if k ∈ m then k else default := + m.inductionOn fun _ => DHashMap.getKey!_modify_self + +theorem getKey_modify [LawfulBEq α] [Inhabited α] {k k' : α} {f : β k → β k} + {h : k' ∈ m.modify k f} : + (m.modify k f).getKey k' h = + if k == k' then + k + else + haveI h' : k' ∈ m := mem_modify.mp h + m.getKey k' h' := + m.inductionOn (fun _ _ => DHashMap.getKey_modify) h + +@[simp] +theorem getKey_modify_self [LawfulBEq α] [Inhabited α] {k : α} {f : β k → β k} + {h : k ∈ m.modify k f} : (m.modify k f).getKey k h = k := + m.inductionOn (fun _ _ => DHashMap.getKey_modify_self) h + +theorem getKeyD_modify [LawfulBEq α] {k k' fallback : α} {f : β k → β k} : + (m.modify k f).getKeyD k' fallback = + if k == k' then + if k ∈ m then k else fallback + else + m.getKeyD k' fallback := + m.inductionOn fun _ => DHashMap.getKeyD_modify + +theorem getKeyD_modify_self [LawfulBEq α] [Inhabited α] {k fallback : α} {f : β k → β k} : + (m.modify k f).getKeyD k fallback = if k ∈ m then k else fallback := + m.inductionOn fun _ => DHashMap.getKeyD_modify_self + +namespace Const + +variable {β : Type v} {m : ExtDHashMap α (fun _ => β)} + +@[simp] +theorem modify_eq_empty_iff [EquivBEq α] [LawfulHashable α] {k : α} {f : β → β} : + Const.modify m k f = ∅ ↔ m = ∅ := by + simp only [← isEmpty_iff, Bool.coe_iff_coe] + exact m.inductionOn fun _ => DHashMap.Const.isEmpty_modify + +@[simp] +theorem contains_modify [EquivBEq α] [LawfulHashable α] {k k': α} {f : β → β} : + (Const.modify m k f).contains k' = m.contains k' := + m.inductionOn fun _ => DHashMap.Const.contains_modify + +@[simp] +theorem mem_modify [EquivBEq α] [LawfulHashable α] {k k': α} {f : β → β} : + k' ∈ Const.modify m k f ↔ k' ∈ m := + m.inductionOn fun _ => DHashMap.Const.mem_modify + +@[simp] +theorem size_modify [EquivBEq α] [LawfulHashable α] {k : α} {f : β → β} : + (Const.modify m k f).size = m.size := + m.inductionOn fun _ => DHashMap.Const.size_modify + +theorem get?_modify [EquivBEq α] [LawfulHashable α] {k k' : α} {f : β → β} : + Const.get? (Const.modify m k f) k' = if k == k' then + Const.get? m k |>.map f + else + Const.get? m k' := + m.inductionOn fun _ => DHashMap.Const.get?_modify + +@[simp] +theorem get?_modify_self [EquivBEq α] [LawfulHashable α] {k : α} {f : β → β} : + Const.get? (Const.modify m k f) k = (Const.get? m k).map f := + m.inductionOn fun _ => DHashMap.Const.get?_modify_self + +theorem get_modify [EquivBEq α] [LawfulHashable α] {k k' : α} {f : β → β} + {h : k' ∈ Const.modify m k f} : + Const.get (Const.modify m k f) k' h = + if heq : k == k' then + haveI h' : k ∈ m := mem_congr heq |>.mpr <| mem_modify.mp h + f (Const.get m k h') + else + haveI h' : k' ∈ m := mem_modify.mp h + Const.get m k' h' := + m.inductionOn (fun _ _ => DHashMap.Const.get_modify) h + +@[simp] +theorem get_modify_self [EquivBEq α] [LawfulHashable α] {k : α} {f : β → β} + {h : k ∈ Const.modify m k f} : + haveI h' : k ∈ m := mem_modify.mp h + Const.get (Const.modify m k f) k h = f (Const.get m k h') := + m.inductionOn (fun _ _ => DHashMap.Const.get_modify_self) h + +theorem get!_modify [EquivBEq α] [LawfulHashable α] {k k' : α} [Inhabited β] {f : β → β} : + Const.get! (Const.modify m k f) k' = + if k == k' then + Const.get? m k |>.map f |>.get! + else + Const.get! m k' := + m.inductionOn fun _ => DHashMap.Const.get!_modify + +@[simp] +theorem get!_modify_self [EquivBEq α] [LawfulHashable α] {k : α} [Inhabited β] {f : β → β} : + Const.get! (Const.modify m k f) k = ((Const.get? m k).map f).get! := + m.inductionOn fun _ => DHashMap.Const.get!_modify_self + +theorem getD_modify [EquivBEq α] [LawfulHashable α] {k k' : α} {fallback : β} {f : β → β} : + Const.getD (Const.modify m k f) k' fallback = + if k == k' then + Const.get? m k |>.map f |>.getD fallback + else + Const.getD m k' fallback := + m.inductionOn fun _ => DHashMap.Const.getD_modify + +@[simp] +theorem getD_modify_self [EquivBEq α] [LawfulHashable α] {k : α} {fallback : β} {f : β → β} : + Const.getD (Const.modify m k f) k fallback = ((Const.get? m k).map f).getD fallback := + m.inductionOn fun _ => DHashMap.Const.getD_modify_self + +theorem getKey?_modify [EquivBEq α] [LawfulHashable α] {k k' : α} {f : β → β} : + (Const.modify m k f).getKey? k' = + if k == k' then + if k ∈ m then some k else none + else + m.getKey? k' := + m.inductionOn fun _ => DHashMap.Const.getKey?_modify + +theorem getKey?_modify_self [EquivBEq α] [LawfulHashable α] {k : α} {f : β → β} : + (Const.modify m k f).getKey? k = if k ∈ m then some k else none := + m.inductionOn fun _ => DHashMap.Const.getKey?_modify_self + +theorem getKey!_modify [EquivBEq α] [LawfulHashable α] [Inhabited α] {k k' : α} {f : β → β} : + (Const.modify m k f).getKey! k' = + if k == k' then + if k ∈ m then k else default + else + m.getKey! k' := + m.inductionOn fun _ => DHashMap.Const.getKey!_modify + +theorem getKey!_modify_self [EquivBEq α] [LawfulHashable α] [Inhabited α] {k : α} {f : β → β} : + (Const.modify m k f).getKey! k = if k ∈ m then k else default := + m.inductionOn fun _ => DHashMap.Const.getKey!_modify_self + +theorem getKey_modify [EquivBEq α] [LawfulHashable α] [Inhabited α] {k k' : α} {f : β → β} + {h : k' ∈ Const.modify m k f} : + (Const.modify m k f).getKey k' h = + if k == k' then + k + else + haveI h' : k' ∈ m := mem_modify.mp h + m.getKey k' h' := + m.inductionOn (fun _ _ => DHashMap.Const.getKey_modify) h + +@[simp] +theorem getKey_modify_self [EquivBEq α] [LawfulHashable α] [Inhabited α] {k : α} {f : β → β} + {h : k ∈ Const.modify m k f} : (Const.modify m k f).getKey k h = k := + m.inductionOn (fun _ _ => DHashMap.Const.getKey_modify_self) h + +theorem getKeyD_modify [EquivBEq α] [LawfulHashable α] {k k' fallback : α} {f : β → β} : + (Const.modify m k f).getKeyD k' fallback = + if k == k' then + if k ∈ m then k else fallback + else + m.getKeyD k' fallback := + m.inductionOn fun _ => DHashMap.Const.getKeyD_modify + +theorem getKeyD_modify_self [EquivBEq α] [LawfulHashable α] [Inhabited α] {k fallback : α} {f : β → β} : + (Const.modify m k f).getKeyD k fallback = if k ∈ m then k else fallback := + m.inductionOn fun _ => DHashMap.Const.getKeyD_modify_self + +end Const + +end Modify + +section Ext + +variable {m₁ m₂ : Std.ExtDHashMap α β} + +@[ext] +theorem ext_get? [LawfulBEq α] {m₁ m₂ : Std.ExtDHashMap α β} (h : ∀ k, m₁.get? k = m₂.get? k) : m₁ = m₂ := + m₁.inductionOn₂ m₂ (fun _ _ h => Quotient.sound (.of_forall_get?_eq h)) h + +namespace Const + +variable {β : Type v} {m₁ m₂ : ExtDHashMap α fun _ => β} + +theorem ext_getKey_get? [EquivBEq α] [LawfulHashable α] + (hk : ∀ k hk hk', m₁.getKey k hk = m₂.getKey k hk') + (hv : ∀ k, Const.get? m₁ k = Const.get? m₂ k) : m₁ = m₂ := + m₁.inductionOn₂ m₂ (fun _ _ hk hv => Quotient.sound + (.of_forall_getKey_eq_of_forall_constGet?_eq hk hv)) hk hv + +theorem ext_get? [LawfulBEq α] (h : ∀ k, get? m₁ k = get? m₂ k) : m₁ = m₂ := + m₁.inductionOn₂ m₂ (fun _ _ h => Quotient.sound (.of_forall_constGet?_eq h)) h + +theorem ext_getKey?_unit [EquivBEq α] [LawfulHashable α] {m₁ m₂ : ExtDHashMap α fun _ => Unit} + (h : ∀ k, m₁.getKey? k = m₂.getKey? k) : m₁ = m₂ := + m₁.inductionOn₂ m₂ (fun _ _ h => Quotient.sound (.of_forall_getKey?_unit_eq h)) h + +theorem ext_contains_unit [LawfulBEq α] {m₁ m₂ : ExtDHashMap α fun _ => Unit} + (h : ∀ k, m₁.contains k = m₂.contains k) : m₁ = m₂ := + m₁.inductionOn₂ m₂ (fun _ _ h => Quotient.sound (.of_forall_contains_unit_eq h)) h + +theorem ext_mem_unit [LawfulBEq α] {m₁ m₂ : ExtDHashMap α fun _ => Unit} + (h : ∀ k, k ∈ m₁ ↔ k ∈ m₂) : m₁ = m₂ := + m₁.inductionOn₂ m₂ (fun _ _ h => Quotient.sound (.of_forall_mem_unit_iff h)) h + +end Const + +end Ext + +section filterMap + +variable {γ : α → Type w} + +theorem filterMap_eq_empty_iff [LawfulBEq α] + {f : (a : α) → β a → Option (γ a)} : + m.filterMap f = ∅ ↔ ∀ k h, f k (m.get k h) = none := + isEmpty_iff.symm.trans <| m.inductionOn fun _ => DHashMap.isEmpty_filterMap_iff + +theorem contains_filterMap [LawfulBEq α] + {f : (a : α) → β a → Option (γ a)} {k : α} : + (m.filterMap f).contains k = (m.get? k).any (f k · |>.isSome) := + m.inductionOn fun _ => DHashMap.contains_filterMap + +theorem mem_filterMap [LawfulBEq α] + {f : (a : α) → β a → Option (γ a)} {k : α} : + k ∈ m.filterMap f ↔ ∃ h, (f k (m.get k h)).isSome := + m.inductionOn fun _ => DHashMap.mem_filterMap + +theorem contains_of_contains_filterMap [EquivBEq α] [LawfulHashable α] + {f : (a : α) → β a → Option (γ a)} {k : α} : + (m.filterMap f).contains k = true → m.contains k = true := + m.inductionOn fun _ => DHashMap.contains_of_contains_filterMap + +theorem mem_of_mem_filterMap [EquivBEq α] [LawfulHashable α] + {f : (a : α) → β a → Option (γ a)} {k : α} : + k ∈ m.filterMap f → k ∈ m := + m.inductionOn fun _ => DHashMap.mem_of_mem_filterMap + +theorem size_filterMap_le_size [EquivBEq α] [LawfulHashable α] + {f : (a : α) → β a → Option (γ a)} : + (m.filterMap f).size ≤ m.size := + m.inductionOn fun _ => DHashMap.size_filterMap_le_size + +theorem size_filterMap_eq_size_iff [LawfulBEq α] + {f : (a : α) → β a → Option (γ a)} : + (m.filterMap f).size = m.size ↔ ∀ (a : α) (h : a ∈ m), (f a (m.get a h)).isSome := + m.inductionOn fun _ => DHashMap.size_filterMap_eq_size_iff + +@[simp] +theorem get?_filterMap [LawfulBEq α] + {f : (a : α) → β a → Option (γ a)} {k : α} : + (m.filterMap f).get? k = (m.get? k).bind (f k) := + m.inductionOn fun _ => DHashMap.get?_filterMap + +theorem isSome_apply_of_mem_filterMap [LawfulBEq α] + {f : (a : α) → β a → Option (γ a)} {k : α} : + ∀ (h' : k ∈ m.filterMap f), + (f k (m.get k (mem_of_mem_filterMap h'))).isSome := + m.inductionOn fun _ => DHashMap.isSome_apply_of_mem_filterMap + +@[simp] +theorem get_filterMap [LawfulBEq α] + {f : (a : α) → β a → Option (γ a)} {k : α} {h'} : + (m.filterMap f).get k h' = + (f k (m.get k (mem_of_mem_filterMap h'))).get + (isSome_apply_of_mem_filterMap h') := + m.inductionOn (fun _ _ => DHashMap.get_filterMap) h' + +theorem get!_filterMap [LawfulBEq α] + {f : (a : α) → β a → Option (γ a)} {k : α} [Inhabited (γ k)] : + (m.filterMap f).get! k = ((m.get? k).bind (f k)).get! := + m.inductionOn fun _ => DHashMap.get!_filterMap + +theorem getD_filterMap [LawfulBEq α] + {f : (a : α) → β a → Option (γ a)} {k : α} {fallback : γ k} : + (m.filterMap f).getD k fallback = ((m.get? k).bind (f k)).getD fallback := + m.inductionOn fun _ => DHashMap.getD_filterMap + +theorem getKey?_filterMap [LawfulBEq α] + {f : (a : α) → β a → Option (γ a)} {k : α} : + (m.filterMap f).getKey? k = + (m.getKey? k).pfilter (fun x h' => + (f x (m.get x (mem_of_getKey?_eq_some h'))).isSome) := + m.inductionOn fun _ => DHashMap.getKey?_filterMap + +@[simp] +theorem getKey_filterMap [EquivBEq α] [LawfulHashable α] + {f : (a : α) → β a → Option (γ a)} {k : α} {h'} : + (m.filterMap f).getKey k h' = m.getKey k (mem_of_mem_filterMap h') := + m.inductionOn (fun _ _ => DHashMap.getKey_filterMap) h' + +theorem getKey!_filterMap [LawfulBEq α] [Inhabited α] + {f : (a : α) → β a → Option (γ a)} {k : α} : + (m.filterMap f).getKey! k = + ((m.getKey? k).pfilter (fun x h' => + (f x (m.get x (mem_of_getKey?_eq_some h'))).isSome)).get! := + m.inductionOn fun _ => DHashMap.getKey!_filterMap + +theorem getKeyD_filterMap [LawfulBEq α] + {f : (a : α) → β a → Option (γ a)} {k fallback : α} : + (m.filterMap f).getKeyD k fallback = + ((m.getKey? k).pfilter (fun x h' => + (f x (m.get x (mem_of_getKey?_eq_some h'))).isSome)).getD fallback := + m.inductionOn fun _ => DHashMap.getKeyD_filterMap + +namespace Const + +variable {β : Type v} {γ : Type w} {m : ExtDHashMap α (fun _ => β)} + +theorem filterMap_eq_empty_iff [EquivBEq α] [LawfulHashable α] {f : α → β → Option γ} : + m.filterMap f = ∅ ↔ ∀ k h, f (m.getKey k h) (get m k h) = none := + isEmpty_iff.symm.trans <| m.inductionOn fun _ => DHashMap.Const.isEmpty_filterMap_iff + +theorem mem_filterMap [EquivBEq α] [LawfulHashable α] + {f : α → β → Option γ} {k : α} : + k ∈ m.filterMap f ↔ ∃ h, (f (m.getKey k h) (Const.get m k h)).isSome := + m.inductionOn fun _ => DHashMap.Const.mem_filterMap + +theorem size_filterMap_eq_size_iff [EquivBEq α] [LawfulHashable α] + {f : α → β → Option γ} : + (m.filterMap f).size = m.size ↔ ∀ k h, (f (m.getKey k h) (Const.get m k h)).isSome := + m.inductionOn fun _ => DHashMap.Const.size_filterMap_eq_size_iff + +theorem get?_filterMap [EquivBEq α] [LawfulHashable α] + {f : α → β → Option γ} {k : α} : + Const.get? (m.filterMap f) k = (Const.get? m k).pbind (fun x h' => + f (m.getKey k (mem_iff_isSome_get?.mpr (Option.isSome_of_eq_some h'))) x) := + m.inductionOn fun _ => DHashMap.Const.get?_filterMap + +theorem get?_filterMap_of_getKey?_eq_some [EquivBEq α] [LawfulHashable α] + {f : α → β → Option γ} {k k' : α} (h : m.getKey? k = some k') : + Const.get? (m.filterMap f) k = (Const.get? m k).bind (f k') := + m.inductionOn (fun _ h => DHashMap.Const.get?_filterMap_of_getKey?_eq_some h) h + +theorem isSome_apply_of_mem_filterMap [EquivBEq α] [LawfulHashable α] + {f : α → β → Option γ} {k : α} : + ∀ (h : k ∈ m.filterMap f), + (f (m.getKey k (mem_of_mem_filterMap h)) + (Const.get m k (mem_of_mem_filterMap h))).isSome := + m.inductionOn fun _ => DHashMap.Const.isSome_apply_of_mem_filterMap + +@[simp] +theorem get_filterMap [EquivBEq α] [LawfulHashable α] + {f : α → β → Option γ} {k : α} {h} : + Const.get (m.filterMap f) k h = + (f (m.getKey k (mem_of_mem_filterMap h)) + (Const.get m k (mem_of_mem_filterMap h))).get + (isSome_apply_of_mem_filterMap h) := + m.inductionOn (fun _ _ => DHashMap.Const.get_filterMap) h + +theorem get!_filterMap [EquivBEq α] [LawfulHashable α] [Inhabited γ] + {f : α → β → Option γ} {k : α} : + Const.get! (m.filterMap f) k = + ((Const.get? m k).pbind (fun x h' => + f (m.getKey k (mem_iff_isSome_get?.mpr (Option.isSome_of_eq_some h'))) x)).get! := + m.inductionOn fun _ => DHashMap.Const.get!_filterMap + +theorem get!_filterMap_of_getKey?_eq_some [EquivBEq α] [LawfulHashable α] [Inhabited γ] + {f : α → β → Option γ} {k k' : α} (h : m.getKey? k = some k') : + Const.get! (m.filterMap f) k = ((Const.get? m k).bind (f k')).get! := + m.inductionOn (fun _ h => DHashMap.Const.get!_filterMap_of_getKey?_eq_some h) h + +theorem getD_filterMap [EquivBEq α] [LawfulHashable α] + {f : α → β → Option γ} {k : α} {fallback : γ} : + Const.getD (m.filterMap f) k fallback = + ((Const.get? m k).pbind (fun x h' => + f (m.getKey k (mem_iff_isSome_get?.mpr (Option.isSome_of_eq_some h'))) x)).getD fallback := + m.inductionOn fun _ => DHashMap.Const.getD_filterMap + +theorem getD_filterMap_of_getKey?_eq_some [EquivBEq α] [LawfulHashable α] + {f : α → β → Option γ} {k k' : α} {fallback : γ} (h : m.getKey? k = some k') : + Const.getD (m.filterMap f) k fallback = ((Const.get? m k).bind (f k')).getD fallback := + m.inductionOn (fun _ h => DHashMap.Const.getD_filterMap_of_getKey?_eq_some h) h + +theorem getKey?_filterMap [EquivBEq α] [LawfulHashable α] + {f : α → β → Option γ} {k : α} : + (m.filterMap f).getKey? k = + (m.getKey? k).pfilter (fun x h' => + (f x (Const.get m x (mem_of_getKey?_eq_some h'))).isSome) := + m.inductionOn fun _ => DHashMap.Const.getKey?_filterMap + +theorem getKey!_filterMap [EquivBEq α] [LawfulHashable α] [Inhabited α] + {f : α → β → Option γ} {k : α} : + (m.filterMap f).getKey! k = + ((m.getKey? k).pfilter (fun x h' => + (f x (Const.get m x (mem_of_getKey?_eq_some h'))).isSome)).get! := + m.inductionOn fun _ => DHashMap.Const.getKey!_filterMap + +theorem getKeyD_filterMap [EquivBEq α] [LawfulHashable α] + {f : α → β → Option γ} {k fallback : α} : + (m.filterMap f).getKeyD k fallback = + ((m.getKey? k).pfilter (fun x h' => + (f x (Const.get m x (mem_of_getKey?_eq_some h'))).isSome)).getD fallback := + m.inductionOn fun _ => DHashMap.Const.getKeyD_filterMap + +end Const + +end filterMap + +section filter + +theorem filterMap_eq_filter [EquivBEq α] [LawfulHashable α] {f : (a : α) → β a → Bool} : + m.filterMap (fun k => Option.guard (fun v => f k v)) = m.filter f := + m.inductionOn fun _ => Quotient.sound DHashMap.filterMap_equiv_filter + +@[simp] +theorem filter_eq_empty_iff [LawfulBEq α] + {f : (a : α) → β a → Bool} : + m.filter f = ∅ ↔ ∀ k h, f k (m.get k h) = false := + isEmpty_iff.symm.trans <| m.inductionOn fun _ => DHashMap.isEmpty_filter_iff + +theorem filter_key_eq_empty_iff [EquivBEq α] [LawfulHashable α] {f : α → Bool} : + m.filter (fun a _ => f a) = ∅ ↔ ∀ k h, f (m.getKey k h) = false := + isEmpty_iff.symm.trans <| m.inductionOn fun _ => DHashMap.isEmpty_filter_key_iff + +theorem contains_filter [LawfulBEq α] {f : (a : α) → β a → Bool} {k : α} : + (m.filter f).contains k = (m.get? k).any (f k) := + m.inductionOn fun _ => DHashMap.contains_filter + +theorem mem_filter [LawfulBEq α] {f : (a : α) → β a → Bool} {k : α} : + k ∈ m.filter f ↔ ∃ h, f k (m.get k h) := + m.inductionOn fun _ => DHashMap.mem_filter + +theorem mem_filter_key [EquivBEq α] [LawfulHashable α] {f : α → Bool} {k : α} : + k ∈ m.filter (fun a _ => f a) ↔ ∃ h, f (m.getKey k h) := + m.inductionOn fun _ => DHashMap.mem_filter_key + +theorem contains_of_contains_filter [EquivBEq α] [LawfulHashable α] {f : (a : α) → β a → Bool} {k : α} : + (m.filter f).contains k = true → m.contains k = true := + m.inductionOn fun _ => DHashMap.contains_of_contains_filter + +theorem mem_of_mem_filter [EquivBEq α] [LawfulHashable α] {f : (a : α) → β a → Bool} {k : α} : + k ∈ (m.filter f) → k ∈ m := + m.inductionOn fun _ => DHashMap.mem_of_mem_filter + +theorem size_filter_le_size [EquivBEq α] [LawfulHashable α] {f : (a : α) → β a → Bool} : + (m.filter f).size ≤ m.size := + m.inductionOn fun _ => DHashMap.size_filter_le_size + +theorem size_filter_eq_size_iff [LawfulBEq α] {f : (a : α) → β a → Bool} : + (m.filter f).size = m.size ↔ ∀ k h, f k (m.get k h) := + m.inductionOn fun _ => DHashMap.size_filter_eq_size_iff + +theorem filter_eq_self_iff [LawfulBEq α] {f : (a : α) → β a → Bool} : + m.filter f = m ↔ ∀ k h, f k (m.get k h) := + m.inductionOn fun _ => Iff.trans ⟨Quotient.exact, Quotient.sound⟩ DHashMap.filter_equiv_self_iff + +theorem filter_key_equiv_self_iff [EquivBEq α] [LawfulHashable α] {f : (a : α) → Bool} : + m.filter (fun k _ => f k) = m ↔ ∀ k h, f (m.getKey k h) := + m.inductionOn fun _ => Iff.trans ⟨Quotient.exact, Quotient.sound⟩ DHashMap.filter_key_equiv_self_iff + +theorem size_filter_key_eq_size_iff [EquivBEq α] [LawfulHashable α] {f : α → Bool} : + (m.filter fun k _ => f k).size = m.size ↔ ∀ k h, f (m.getKey k h) := + m.inductionOn fun _ => DHashMap.size_filter_key_eq_size_iff + +@[simp] +theorem get?_filter [LawfulBEq α] + {f : (a : α) → β a → Bool} {k : α} : + (m.filter f).get? k = (m.get? k).filter (f k) := + m.inductionOn fun _ => DHashMap.get?_filter + +@[simp] +theorem get_filter [LawfulBEq α] + {f : (a : α) → β a → Bool} {k : α} {h'} : + (m.filter f).get k h' = m.get k (mem_of_mem_filter h') := + m.inductionOn (fun _ _ => DHashMap.get_filter) h' + +theorem get!_filter [LawfulBEq α] + {f : (a : α) → β a → Bool} {k : α} [Inhabited (β k)] : + (m.filter f).get! k = ((m.get? k).filter (f k)).get! := + m.inductionOn fun _ => DHashMap.get!_filter + +theorem getD_filter [LawfulBEq α] + {f : (a : α) → β a → Bool} {k : α} {fallback : β k} : + (m.filter f).getD k fallback = ((m.get? k).filter (f k)).getD fallback := + m.inductionOn fun _ => DHashMap.getD_filter + +theorem getKey?_filter [LawfulBEq α] + {f : (a : α) → β a → Bool} {k : α} : + (m.filter f).getKey? k = + (m.getKey? k).pfilter (fun x h' => + f x (m.get x (mem_of_getKey?_eq_some h'))) := + m.inductionOn fun _ => DHashMap.getKey?_filter + +theorem getKey?_filter_key [EquivBEq α] [LawfulHashable α] + {f : α → Bool} {k : α} : + (m.filter fun k _ => f k).getKey? k = (m.getKey? k).filter f := + m.inductionOn fun _ => DHashMap.getKey?_filter_key + +@[simp] +theorem getKey_filter [EquivBEq α] [LawfulHashable α] + {f : (a : α) → β a → Bool} {k : α} {h'} : + (m.filter f).getKey k h' = m.getKey k (mem_of_mem_filter h') := + m.inductionOn (fun _ _ => DHashMap.getKey_filter) h' + +theorem getKey!_filter [LawfulBEq α] [Inhabited α] + {f : (a : α) → β a → Bool} {k : α} : + (m.filter f).getKey! k = + ((m.getKey? k).pfilter (fun x h' => + f x (m.get x (mem_of_getKey?_eq_some h')))).get! := + m.inductionOn fun _ => DHashMap.getKey!_filter + +theorem getKey!_filter_key [EquivBEq α] [LawfulHashable α] [Inhabited α] + {f : α → Bool} {k : α} : + (m.filter fun k _ => f k).getKey! k = ((m.getKey? k).filter f).get! := + m.inductionOn fun _ => DHashMap.getKey!_filter_key + +theorem getKeyD_filter [LawfulBEq α] + {f : (a : α) → β a → Bool} {k fallback : α} : + (m.filter f).getKeyD k fallback = + ((m.getKey? k).pfilter (fun x h' => + f x (m.get x (mem_of_getKey?_eq_some h')))).getD fallback := + m.inductionOn fun _ => DHashMap.getKeyD_filter + +theorem getKeyD_filter_key [EquivBEq α] [LawfulHashable α] + {f : α → Bool} {k fallback : α} : + (m.filter fun k _ => f k).getKeyD k fallback = ((m.getKey? k).filter f).getD fallback := + m.inductionOn fun _ => DHashMap.getKeyD_filter_key + +namespace Const + +variable {β : Type v} {γ : Type w} {m : ExtDHashMap α (fun _ => β)} + +theorem filter_eq_empty_iff [EquivBEq α] [LawfulHashable α] {f : α → β → Bool} : + m.filter f = ∅ ↔ ∀ k h, f (m.getKey k h) (Const.get m k h) = false := + isEmpty_iff.symm.trans <| m.inductionOn fun _ => DHashMap.Const.isEmpty_filter_iff + +theorem mem_filter [EquivBEq α] [LawfulHashable α] + {f : α → β → Bool} {k : α} : + k ∈ m.filter f ↔ ∃ (h' : k ∈ m), + f (m.getKey k h') (Const.get m k h') := + m.inductionOn fun _ => DHashMap.Const.mem_filter + +theorem size_filter_le_size [EquivBEq α] [LawfulHashable α] + {f : α → β → Bool} : + (m.filter f).size ≤ m.size := + m.inductionOn fun _ => DHashMap.Const.size_filter_le_size + +theorem size_filter_eq_size_iff [EquivBEq α] [LawfulHashable α] + {f : α → β → Bool} : + (m.filter f).size = m.size ↔ ∀ (a : α) (h : a ∈ m), + f (m.getKey a h) (Const.get m a h) := + m.inductionOn fun _ => DHashMap.Const.size_filter_eq_size_iff + +theorem filter_eq_self_iff [EquivBEq α] [LawfulHashable α] {f : α → β → Bool} : + m.filter f = m ↔ ∀ k h, f (m.getKey k h) (Const.get m k h) := + m.inductionOn fun _ => Iff.trans ⟨Quotient.exact, Quotient.sound⟩ DHashMap.Const.filter_equiv_self_iff + +theorem get?_filter [EquivBEq α] [LawfulHashable α] + {f : α → β → Bool} {k : α} : + Const.get? (m.filter f) k = (Const.get? m k).pfilter (fun x h' => + f (m.getKey k (mem_iff_isSome_get?.mpr (Option.isSome_of_eq_some h'))) x) := + m.inductionOn fun _ => DHashMap.Const.get?_filter + +theorem get?_filter_of_getKey?_eq_some [EquivBEq α] [LawfulHashable α] + {f : α → β → Bool} {k k' : α} : + m.getKey? k = some k' → + Const.get? (m.filter f) k = (Const.get? m k).filter (fun x => f k' x) := + m.inductionOn fun _ => DHashMap.Const.get?_filter_of_getKey?_eq_some + +@[simp] +theorem get_filter [EquivBEq α] [LawfulHashable α] + {f : α → β → Bool} {k : α} {h'} : + Const.get (m.filter f) k h' = Const.get m k (mem_of_mem_filter h') := + m.inductionOn (fun _ _ => DHashMap.Const.get_filter) h' + +theorem get!_filter [EquivBEq α] [LawfulHashable α] [Inhabited β] + {f : α → β → Bool} {k : α} : + Const.get! (m.filter f) k = + ((Const.get? m k).pfilter (fun x h' => + f (m.getKey k (mem_iff_isSome_get?.mpr (Option.isSome_of_eq_some h'))) x)).get! := + m.inductionOn fun _ => DHashMap.Const.get!_filter + +theorem get!_filter_of_getKey?_eq_some [EquivBEq α] [LawfulHashable α] [Inhabited β] + {f : α → β → Bool} {k k' : α} : + m.getKey? k = some k' → + Const.get! (m.filter f) k = ((Const.get? m k).filter (fun x => f k' x)).get! := + m.inductionOn fun _ => DHashMap.Const.get!_filter_of_getKey?_eq_some + +theorem getD_filter [EquivBEq α] [LawfulHashable α] + {f : α → β → Bool} {k : α} {fallback : β} : + Const.getD (m.filter f) k fallback = ((Const.get? m k).pfilter (fun x h' => + f (m.getKey k (mem_iff_isSome_get?.mpr (Option.isSome_of_eq_some h'))) x)).getD fallback := + m.inductionOn fun _ => DHashMap.Const.getD_filter + +theorem getD_filter_of_getKey?_eq_some [EquivBEq α] [LawfulHashable α] + {f : α → β → Bool} {k k' : α} {fallback : β} : + m.getKey? k = some k' → + Const.getD (m.filter f) k fallback = + ((Const.get? m k).filter (fun x => f k' x)).getD fallback := + m.inductionOn fun _ => DHashMap.Const.getD_filter_of_getKey?_eq_some + +theorem getKey?_filter [EquivBEq α] [LawfulHashable α] + {f : α → β → Bool} {k : α} : + (m.filter f).getKey? k = + (m.getKey? k).pfilter (fun x h' => + (f x (Const.get m x (mem_of_getKey?_eq_some h')))) := + m.inductionOn fun _ => DHashMap.Const.getKey?_filter + +theorem getKey!_filter [EquivBEq α] [LawfulHashable α] [Inhabited α] + {f : α → β → Bool} {k : α} : + (m.filter f).getKey! k = + ((m.getKey? k).pfilter (fun x h' => + (f x (Const.get m x (mem_of_getKey?_eq_some h'))))).get! := + m.inductionOn fun _ => DHashMap.Const.getKey!_filter + +theorem getKeyD_filter [EquivBEq α] [LawfulHashable α] + {f : α → β → Bool} {k fallback : α} : + (m.filter f).getKeyD k fallback = + ((m.getKey? k).pfilter (fun x h' => + (f x (Const.get m x (mem_of_getKey?_eq_some h'))))).getD fallback := + m.inductionOn fun _ => DHashMap.Const.getKeyD_filter + +end Const + +end filter + +section map + +variable {γ : α → Type w} {δ : α → Type w'} + +@[simp] +theorem map_id_fun [EquivBEq α] [LawfulHashable α] : m.map (fun _ v => v) = m := + m.inductionOn fun _ => Quotient.sound DHashMap.map_id_equiv + +@[simp] +theorem map_map [EquivBEq α] [LawfulHashable α] {f : (a : α) → β a → γ a} {g : (a : α) → γ a → δ a} : + (m.map f).map g = m.map fun k v => g k (f k v) := + m.inductionOn fun _ => Quotient.sound DHashMap.map_map_equiv + +theorem filterMap_eq_map [EquivBEq α] [LawfulHashable α] {f : (a : α) → β a → γ a} : + (m.filterMap (fun k v => some (f k v))) = m.map f := + m.inductionOn fun _ => Quotient.sound DHashMap.filterMap_equiv_map + +@[simp] +theorem map_eq_empty_iff [EquivBEq α] [LawfulHashable α] {f : (a : α) → β a → γ a} : + m.map f = ∅ ↔ m = ∅ := by + simp only [← isEmpty_iff, Bool.coe_iff_coe] + exact m.inductionOn fun _ => DHashMap.isEmpty_map + +theorem contains_map [EquivBEq α] [LawfulHashable α] + {f : (a : α) → β a → γ a} {k : α} : + (m.map f).contains k = m.contains k := + m.inductionOn fun _ => DHashMap.contains_map + +theorem contains_of_contains_map [EquivBEq α] [LawfulHashable α] + {f : (a : α) → β a → γ a} {k : α} : + (m.map f).contains k = true → m.contains k = true := + m.inductionOn fun _ => DHashMap.contains_of_contains_map + +@[simp] +theorem mem_map [EquivBEq α] [LawfulHashable α] + {f : (a : α) → β a → γ a} {k : α} : + k ∈ m.map f ↔ k ∈ m := + m.inductionOn fun _ => DHashMap.mem_map + +theorem mem_of_mem_map [EquivBEq α] [LawfulHashable α] + {f : (a : α) → β a → γ a} {k : α} : + k ∈ m.map f → k ∈ m := + m.inductionOn fun _ => DHashMap.mem_of_mem_map + +@[simp] +theorem size_map [EquivBEq α] [LawfulHashable α] + {f : (a : α) → β a → γ a} : + (m.map f).size = m.size := + m.inductionOn fun _ => DHashMap.size_map + +@[simp] +theorem get?_map [LawfulBEq α] + {f : (a : α) → β a → γ a} {k : α} : + (m.map f).get? k = (m.get? k).map (f k) := + m.inductionOn fun _ => DHashMap.get?_map + +@[simp] +theorem get_map [LawfulBEq α] + {f : (a : α) → β a → γ a} {k : α} {h'} : + (m.map f).get k h' = f k (m.get k (mem_of_mem_map h')) := + m.inductionOn (fun _ _ => DHashMap.get_map) h' + +theorem get!_map [LawfulBEq α] + {f : (a : α) → β a → γ a} {k : α} [Inhabited (γ k)] : + (m.map f).get! k = ((m.get? k).map (f k)).get! := + m.inductionOn fun _ => DHashMap.get!_map + +theorem getD_map [LawfulBEq α] + {f : (a : α) → β a → γ a} {k : α} {fallback : γ k} : + (m.map f).getD k fallback = ((m.get? k).map (f k)).getD fallback := + m.inductionOn fun _ => DHashMap.getD_map + +@[simp] +theorem getKey?_map [EquivBEq α] [LawfulHashable α] + {f : (a : α) → β a → γ a} {k : α} : + (m.map f).getKey? k = m.getKey? k := + m.inductionOn fun _ => DHashMap.getKey?_map + +@[simp] +theorem getKey_map [EquivBEq α] [LawfulHashable α] + {f : (a : α) → β a → γ a} {k : α} {h'} : + (m.map f).getKey k h' = m.getKey k (mem_of_mem_map h') := + m.inductionOn (fun _ _ => DHashMap.getKey_map) h' + +@[simp] +theorem getKey!_map [EquivBEq α] [LawfulHashable α] [Inhabited α] + {f : (a : α) → β a → γ a} {k : α} : + (m.map f).getKey! k = m.getKey! k := + m.inductionOn fun _ => DHashMap.getKey!_map + +@[simp] +theorem getKeyD_map [EquivBEq α] [LawfulHashable α] + {f : (a : α) → β a → γ a} {k fallback : α} : + (m.map f).getKeyD k fallback = m.getKeyD k fallback := + m.inductionOn fun _ => DHashMap.getKeyD_map + +namespace Const + +variable {β : Type v} {γ : Type w} {m : ExtDHashMap α fun _ => β} + +theorem get?_map [EquivBEq α] [LawfulHashable α] + {f : α → β → γ} {k : α} : + Const.get? (m.map f) k = (Const.get? m k).pmap (fun v h' => f (m.getKey k h') v) + (fun _ h' => mem_iff_isSome_get?.mpr (Option.isSome_of_eq_some h')) := + m.inductionOn fun _ => DHashMap.Const.get?_map + +theorem get?_map_of_getKey?_eq_some [EquivBEq α] [LawfulHashable α] + {f : α → β → γ} {k k' : α} (h : m.getKey? k = some k') : + Const.get? (m.map f) k = (Const.get? m k).map (f k') := + m.inductionOn (fun _ h => DHashMap.Const.get?_map_of_getKey?_eq_some h) h + +@[simp] +theorem get_map [EquivBEq α] [LawfulHashable α] + {f : α → β → γ} {k : α} {h'} : + Const.get (m.map f) k h' = + f (m.getKey k (mem_of_mem_map h')) (Const.get m k (mem_of_mem_map h')) := + m.inductionOn (fun _ _ => DHashMap.Const.get_map) h' + +theorem get!_map [EquivBEq α] [LawfulHashable α] [Inhabited γ] + {f : α → β → γ} {k : α} : + Const.get! (m.map f) k = + ((get? m k).pmap (fun v h => f (m.getKey k h) v) + (fun _ h' => mem_iff_isSome_get?.mpr (Option.isSome_of_mem h'))).get! := + m.inductionOn fun _ => DHashMap.Const.get!_map + +theorem get!_map_of_getKey?_eq_some [EquivBEq α] [LawfulHashable α] [Inhabited γ] + {f : α → β → γ} {k k' : α} (h : m.getKey? k = some k') : + Const.get! (m.map f) k = ((Const.get? m k).map (f k')).get! := + m.inductionOn (fun _ h => DHashMap.Const.get!_map_of_getKey?_eq_some h) h + +theorem getD_map [EquivBEq α] [LawfulHashable α] + {f : α → β → γ} {k : α} {fallback : γ} : + Const.getD (m.map f) k fallback = + ((get? m k).pmap (fun v h => f (m.getKey k h) v) + (fun _ h' => mem_iff_isSome_get?.mpr (Option.isSome_of_eq_some h'))).getD fallback := + m.inductionOn fun _ => DHashMap.Const.getD_map + +theorem getD_map_of_getKey?_eq_some [EquivBEq α] [LawfulHashable α] [Inhabited γ] + {f : α → β → γ} {k k' : α} {fallback : γ} (h : m.getKey? k = some k') : + Const.getD (m.map f) k fallback = ((Const.get? m k).map (f k')).getD fallback := + m.inductionOn (fun _ h => DHashMap.Const.getD_map_of_getKey?_eq_some h) h + +end Const + +end map + +end Std.ExtDHashMap diff --git a/src/Std/Data/ExtHashMap.lean b/src/Std/Data/ExtHashMap.lean new file mode 100644 index 0000000000..7bc2eaf27f --- /dev/null +++ b/src/Std/Data/ExtHashMap.lean @@ -0,0 +1,8 @@ +/- +Copyright (c) 2025 Robin Arnez. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Robin Arnez +-/ +prelude +import Std.Data.ExtHashMap.Basic +import Std.Data.ExtHashMap.Lemmas diff --git a/src/Std/Data/ExtHashMap/Basic.lean b/src/Std/Data/ExtHashMap/Basic.lean new file mode 100644 index 0000000000..f3385bb1f6 --- /dev/null +++ b/src/Std/Data/ExtHashMap/Basic.lean @@ -0,0 +1,248 @@ +/- +Copyright (c) 2025 Robin Arnez. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Robin Arnez +-/ +prelude +import Std.Data.ExtDHashMap.Basic + +set_option linter.missingDocs true +set_option autoImplicit false + +/-! +# Extensional hash maps + +This module develops the type `Std.ExtHashMap` of extensional hash maps. Dependent hash maps +are defined in `Std.Data.ExtDHashMap`. + +Lemmas about the operations on `Std.ExtHashMap` are available in the +module `Std.Data.ExtHashMap.Lemmas`. +-/ + +universe u v w + +variable {α : Type u} {β : Type v} {γ : Type w} {_ : BEq α} {_ : Hashable α} + +namespace Std + +/-- +Hash maps. + +This is a simple separate-chaining hash table. The data of the hash map consists of a cached size +and an array of buckets, where each bucket is a linked list of key-value pais. The number of buckets +is always a power of two. The hash map doubles its size upon inserting an element such that the +number of elements is more than 75% of the number of buckets. + +The hash table is backed by an `Array`. Users should make sure that the hash map is used linearly to +avoid expensive copies. + +The hash map uses `==` (provided by the `BEq` typeclass) to compare keys and `hash` (provided by +the `Hashable` typeclass) to hash them. To ensure that the operations behave as expected, `==` +should be an equivalence relation and `a == b` should imply `hash a = hash b` (see also the +`EquivBEq` and `LawfulHashable` typeclasses). Both of these conditions are automatic if the BEq +instance is lawful, i.e., if `a == b` implies `a = b`. + +In contrast to regular hash maps, `Std.ExtHashMap` offers several extensionality lemmas +and therefore has more lemmas about equality of hash maps. This however also makes it lose the +ability to iterate freely over hash maps. + +These hash maps contain a bundled well-formedness invariant, which means that they cannot +be used in nested inductive types. For these use cases, `Std.HashMap.Raw` and +`Std.HashMap.Raw.WF` unbundle the invariant from the hash map. When in doubt, prefer +`HashMap` or `ExtHashMap` over `HashMap.Raw`. + +Dependent hash maps, in which keys may occur in their values' types, are available as +`Std.ExtDHashMap` in the module `Std.Data.ExtDHashMap`. +-/ +structure ExtHashMap (α : Type u) (β : Type v) [BEq α] [Hashable α] where + /-- Internal implementation detail of the hash map -/ + inner : ExtDHashMap α (fun _ => β) + +namespace ExtHashMap + +@[inline, inherit_doc ExtDHashMap.emptyWithCapacity] +def emptyWithCapacity [BEq α] [Hashable α] (capacity := 8) : + ExtHashMap α β := + ⟨ExtDHashMap.emptyWithCapacity capacity⟩ + +instance [BEq α] [Hashable α] : EmptyCollection (ExtHashMap α β) where + emptyCollection := emptyWithCapacity + +instance [BEq α] [Hashable α] : Inhabited (ExtHashMap α β) where + default := ∅ + +@[inline, inherit_doc ExtDHashMap.insert] +def insert [EquivBEq α] [LawfulHashable α] (m : ExtHashMap α β) (a : α) + (b : β) : ExtHashMap α β := + ⟨m.inner.insert a b⟩ + +instance [EquivBEq α] [LawfulHashable α] : Singleton (α × β) (ExtHashMap α β) where + singleton | ⟨a, b⟩ => (∅ : ExtHashMap α β).insert a b + +instance [EquivBEq α] [LawfulHashable α] : Insert (α × β) (ExtHashMap α β) where + insert | ⟨a, b⟩, s => s.insert a b + +instance [EquivBEq α] [LawfulHashable α] : LawfulSingleton (α × β) (ExtHashMap α β) := + ⟨fun _ => rfl⟩ + +@[inline, inherit_doc ExtDHashMap.insertIfNew] +def insertIfNew [EquivBEq α] [LawfulHashable α] (m : ExtHashMap α β) + (a : α) (b : β) : ExtHashMap α β := + ⟨m.inner.insertIfNew a b⟩ + +@[inline, inherit_doc ExtDHashMap.containsThenInsert] +def containsThenInsert [EquivBEq α] [LawfulHashable α] + (m : ExtHashMap α β) (a : α) (b : β) : Bool × ExtHashMap α β := + let ⟨replaced, r⟩ := m.inner.containsThenInsert a b + ⟨replaced, ⟨r⟩⟩ + +@[inline, inherit_doc ExtDHashMap.containsThenInsertIfNew] +def containsThenInsertIfNew [EquivBEq α] [LawfulHashable α] + (m : ExtHashMap α β) (a : α) (b : β) : Bool × ExtHashMap α β := + let ⟨replaced, r⟩ := m.inner.containsThenInsertIfNew a b + ⟨replaced, ⟨r⟩⟩ + +/-- +Checks whether a key is present in a map, returning the associate value, and inserts a value for +the key if it was not found. + +If the returned value is `some v`, then the returned map is unaltered. If it is `none`, then the +returned map has a new value inserted. + +Equivalent to (but potentially faster than) calling `get?` followed by `insertIfNew`. +-/ +@[inline] +def getThenInsertIfNew? [EquivBEq α] [LawfulHashable α] (m : ExtHashMap α β) (a : α) (b : β) : + Option β × ExtHashMap α β := + let ⟨previous, r⟩ := ExtDHashMap.Const.getThenInsertIfNew? m.inner a b + ⟨previous, ⟨r⟩⟩ + +/-- +The notation `m[a]?` is preferred over calling this function directly. + +Tries to retrieve the mapping for the given key, returning `none` if no such mapping is present. +-/ +@[inline] def get? [EquivBEq α] [LawfulHashable α] (m : ExtHashMap α β) (a : α) : Option β := + ExtDHashMap.Const.get? m.inner a + +@[inline, inherit_doc ExtDHashMap.contains] +def contains [EquivBEq α] [LawfulHashable α] (m : ExtHashMap α β) + (a : α) : Bool := + m.inner.contains a + +instance [BEq α] [Hashable α] [EquivBEq α] [LawfulHashable α] : Membership α (ExtHashMap α β) where + mem m a := a ∈ m.inner + +instance [BEq α] [Hashable α] [EquivBEq α] [LawfulHashable α] + {m : ExtHashMap α β} {a : α} : Decidable (a ∈ m) := + inferInstanceAs (Decidable (a ∈ m.inner)) + +/-- +The notation `m[a]` or `m[a]'h` is preferred over calling this function directly. + +Retrieves the mapping for the given key. Ensures that such a mapping exists by requiring a proof of +`a ∈ m`. +-/ +@[inline] def get [EquivBEq α] [LawfulHashable α] (m : ExtHashMap α β) (a : α) (h : a ∈ m) : β := + ExtDHashMap.Const.get m.inner a h + +@[inline, inherit_doc ExtDHashMap.Const.getD] +def getD [EquivBEq α] [LawfulHashable α] (m : ExtHashMap α β) (a : α) + (fallback : β) : β := + ExtDHashMap.Const.getD m.inner a fallback + +/-- +The notation `m[a]!` is preferred over calling this function directly. + +Tries to retrieve the mapping for the given key, panicking if no such mapping is present. +-/ +@[inline] +def get! [EquivBEq α] [LawfulHashable α] [Inhabited β] (m : ExtHashMap α β) (a : α) : β := + ExtDHashMap.Const.get! m.inner a + +instance [BEq α] [Hashable α] [EquivBEq α] [LawfulHashable α] : + GetElem? (ExtHashMap α β) α β (fun m a => a ∈ m) where + getElem m a h := m.get a h + getElem? m a := m.get? a + getElem! m a := m.get! a + +@[inline, inherit_doc ExtDHashMap.getKey?] +def getKey? [EquivBEq α] [LawfulHashable α] (m : ExtHashMap α β) (a : α) : Option α := + ExtDHashMap.getKey? m.inner a + +@[inline, inherit_doc ExtDHashMap.getKey] +def getKey [EquivBEq α] [LawfulHashable α] (m : ExtHashMap α β) (a : α) (h : a ∈ m) : α := + ExtDHashMap.getKey m.inner a h + +@[inline, inherit_doc ExtDHashMap.getKeyD] +def getKeyD [EquivBEq α] [LawfulHashable α] (m : ExtHashMap α β) (a : α) (fallback : α) : α := + ExtDHashMap.getKeyD m.inner a fallback + +@[inline, inherit_doc ExtDHashMap.getKey!] +def getKey! [EquivBEq α] [LawfulHashable α] [Inhabited α] (m : ExtHashMap α β) (a : α) : α := + ExtDHashMap.getKey! m.inner a + +@[inline, inherit_doc ExtDHashMap.erase] +def erase [EquivBEq α] [LawfulHashable α] (m : ExtHashMap α β) (a : α) : + ExtHashMap α β := + ⟨m.inner.erase a⟩ + +@[inline, inherit_doc ExtDHashMap.size] +def size [EquivBEq α] [LawfulHashable α] (m : ExtHashMap α β) : Nat := + m.inner.size + +@[inline, inherit_doc ExtDHashMap.isEmpty] +def isEmpty [EquivBEq α] [LawfulHashable α] (m : ExtHashMap α β) : Bool := + m.inner.isEmpty + +@[inline, inherit_doc ExtDHashMap.Const.ofList] +def ofList [BEq α] [Hashable α] (l : List (α × β)) : + ExtHashMap α β := + ⟨ExtDHashMap.Const.ofList l⟩ + +@[inline, inherit_doc ExtDHashMap.Const.unitOfList] +def unitOfList [BEq α] [Hashable α] (l : List α) : + ExtHashMap α Unit := + ⟨ExtDHashMap.Const.unitOfList l⟩ + +@[inline, inherit_doc ExtDHashMap.filter] +def filter [EquivBEq α] [LawfulHashable α] (f : α → β → Bool) + (m : ExtHashMap α β) : ExtHashMap α β := + ⟨m.inner.filter f⟩ + +@[inline, inherit_doc ExtDHashMap.map] +def map [EquivBEq α] [LawfulHashable α] (f : α → β → γ) + (m : ExtHashMap α β) : ExtHashMap α γ := + ⟨m.inner.map f⟩ + +@[inline, inherit_doc ExtDHashMap.filterMap] +def filterMap [EquivBEq α] [LawfulHashable α] (f : α → β → Option γ) + (m : ExtHashMap α β) : ExtHashMap α γ := + ⟨m.inner.filterMap f⟩ + +@[inline, inherit_doc ExtDHashMap.modify] +def modify [EquivBEq α] [LawfulHashable α] (m : ExtHashMap α β) (a : α) (f : β → β) : + ExtHashMap α β := + ⟨ExtDHashMap.Const.modify m.inner a f⟩ + +@[inline, inherit_doc ExtDHashMap.alter] +def alter [EquivBEq α] [LawfulHashable α] (m : ExtHashMap α β) (a : α) + (f : Option β → Option β) : ExtHashMap α β := + ⟨ExtDHashMap.Const.alter m.inner a f⟩ + +@[inline, inherit_doc ExtDHashMap.Const.insertMany] +def insertMany [EquivBEq α] [LawfulHashable α] {ρ : Type w} + [ForIn Id ρ (α × β)] (m : ExtHashMap α β) (l : ρ) : ExtHashMap α β := + ⟨ExtDHashMap.Const.insertMany m.inner l⟩ + +@[inline, inherit_doc ExtDHashMap.Const.insertManyIfNewUnit] +def insertManyIfNewUnit [EquivBEq α] [LawfulHashable α] + {ρ : Type w} [ForIn Id ρ α] (m : ExtHashMap α Unit) (l : ρ) : ExtHashMap α Unit := + ⟨ExtDHashMap.Const.insertManyIfNewUnit m.inner l⟩ + +@[inline, inherit_doc ExtDHashMap.Const.unitOfArray] +def unitOfArray [BEq α] [Hashable α] (l : Array α) : + ExtHashMap α Unit := + ⟨ExtDHashMap.Const.unitOfArray l⟩ + +end Std.ExtHashMap diff --git a/src/Std/Data/ExtHashMap/Lemmas.lean b/src/Std/Data/ExtHashMap/Lemmas.lean new file mode 100644 index 0000000000..ff086e624f --- /dev/null +++ b/src/Std/Data/ExtHashMap/Lemmas.lean @@ -0,0 +1,2116 @@ +/- +Copyright (c) 2025 Robin Arnez, LLC. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Robin Arnez +-/ +prelude +import Std.Data.ExtHashMap.Basic +import Std.Data.ExtDHashMap.Lemmas + +/-! +# Extensional hash map lemmas + +This module contains lemmas about `Std.ExtHashMap`. +-/ + +set_option linter.missingDocs true +set_option autoImplicit false + +universe u v w w' + +variable {α : Type u} {β : Type v} {γ : Type w} {δ : Type w'} {_ : BEq α} {_ : Hashable α} + +namespace Std.ExtHashMap + +section + +variable {m : ExtHashMap α β} + +private theorem ext {m m' : ExtHashMap α β} : m.inner = m'.inner → m = m' := by + cases m; cases m'; rintro rfl; rfl + +private theorem ext_iff {m m' : ExtHashMap α β} : m = m' ↔ m.inner = m'.inner := + ⟨fun h => h ▸ rfl, ext⟩ + +@[simp] +theorem isEmpty_iff [EquivBEq α] [LawfulHashable α] : m.isEmpty ↔ m = ∅ := + ExtDHashMap.isEmpty_iff.trans ext_iff.symm + +@[simp] +theorem isEmpty_eq_false_iff [EquivBEq α] [LawfulHashable α] : m.isEmpty = false ↔ ¬m = ∅ := + (Bool.not_eq_true _).symm.to_iff.trans (not_congr isEmpty_iff) + +@[simp] +theorem empty_eq : ∅ = m ↔ m = ∅ := eq_comm + +@[simp] +theorem emptyWithCapacity_eq [EquivBEq α] [LawfulHashable α] {c} : (emptyWithCapacity c : ExtHashMap α β) = ∅ := + ext ExtDHashMap.emptyWithCapacity_eq + +@[simp] +theorem not_insert_eq_empty [EquivBEq α] [LawfulHashable α] {k : α} {v : β} : + ¬m.insert k v = ∅ := + (not_congr ext_iff).mpr ExtDHashMap.not_insert_eq_empty + +theorem mem_iff_contains [EquivBEq α] [LawfulHashable α] {a : α} : a ∈ m ↔ m.contains a := + ExtDHashMap.mem_iff_contains + +theorem contains_congr [EquivBEq α] [LawfulHashable α] {a b : α} (hab : a == b) : + m.contains a = m.contains b := + ExtDHashMap.contains_congr hab + +theorem mem_congr [EquivBEq α] [LawfulHashable α] {a b : α} (hab : a == b) : + a ∈ m ↔ b ∈ m := + ExtDHashMap.mem_congr hab + +@[simp] theorem contains_empty [EquivBEq α] [LawfulHashable α] {a : α} : (∅ : ExtHashMap α β).contains a = false := + ExtDHashMap.contains_empty + +@[simp] theorem not_mem_empty [EquivBEq α] [LawfulHashable α] {a : α} : ¬a ∈ (∅ : ExtHashMap α β) := + ExtDHashMap.not_mem_empty + +theorem eq_empty_iff_forall_contains [EquivBEq α] [LawfulHashable α] : m = ∅ ↔ ∀ a, m.contains a = false := + ext_iff.trans ExtDHashMap.eq_empty_iff_forall_contains + +theorem eq_empty_iff_forall_not_mem [EquivBEq α] [LawfulHashable α] : m = ∅ ↔ ∀ a, ¬a ∈ m := + ext_iff.trans ExtDHashMap.eq_empty_iff_forall_not_mem + +@[simp] theorem insert_eq_insert [EquivBEq α] [LawfulHashable α] {p : α × β} : + Insert.insert p m = m.insert p.1 p.2 := + rfl + +@[simp] theorem singleton_eq_insert [EquivBEq α] [LawfulHashable α] {p : α × β} : + Singleton.singleton p = (∅ : ExtHashMap α β).insert p.1 p.2 := + rfl + +@[simp] +theorem contains_insert [EquivBEq α] [LawfulHashable α] {k a : α} {v : β} : + (m.insert k v).contains a = (k == a || m.contains a) := + ExtDHashMap.contains_insert + +@[simp] +theorem mem_insert [EquivBEq α] [LawfulHashable α] {k a : α} {v : β} : + a ∈ m.insert k v ↔ k == a ∨ a ∈ m := + ExtDHashMap.mem_insert + +theorem contains_of_contains_insert [EquivBEq α] [LawfulHashable α] {k a : α} {v : β} : + (m.insert k v).contains a → (k == a) = false → m.contains a := + ExtDHashMap.contains_of_contains_insert + +theorem mem_of_mem_insert [EquivBEq α] [LawfulHashable α] {k a : α} {v : β} : + a ∈ m.insert k v → (k == a) = false → a ∈ m := + ExtDHashMap.mem_of_mem_insert + +theorem contains_insert_self [EquivBEq α] [LawfulHashable α] {k : α} {v : β} : + (m.insert k v).contains k := by simp + +theorem mem_insert_self [EquivBEq α] [LawfulHashable α] {k : α} {v : β} : k ∈ m.insert k v := by + simp + +@[simp] +theorem size_empty [EquivBEq α] [LawfulHashable α] : (∅ : ExtHashMap α β).size = 0 := + ExtDHashMap.size_empty + +theorem eq_empty_iff_size_eq_zero [EquivBEq α] [LawfulHashable α] : m = ∅ ↔ m.size = 0 := + ext_iff.trans ExtDHashMap.eq_empty_iff_size_eq_zero + +theorem size_insert [EquivBEq α] [LawfulHashable α] {k : α} {v : β} : + (m.insert k v).size = if k ∈ m then m.size else m.size + 1 := + ExtDHashMap.size_insert + +theorem size_le_size_insert [EquivBEq α] [LawfulHashable α] {k : α} {v : β} : + m.size ≤ (m.insert k v).size := + ExtDHashMap.size_le_size_insert + +theorem size_insert_le [EquivBEq α] [LawfulHashable α] {k : α} {v : β} : + (m.insert k v).size ≤ m.size + 1 := + ExtDHashMap.size_insert_le + +@[simp] +theorem erase_empty [EquivBEq α] [LawfulHashable α] {a : α} : (∅ : ExtHashMap α β).erase a = ∅ := + ext ExtDHashMap.erase_empty + +@[simp] +theorem erase_eq_empty_iff [EquivBEq α] [LawfulHashable α] {k : α} : + m.erase k = ∅ ↔ m = ∅ ∨ m.size = 1 ∧ k ∈ m := by + simpa only [ext_iff] using ExtDHashMap.erase_eq_empty_iff + +@[simp] +theorem contains_erase [EquivBEq α] [LawfulHashable α] {k a : α} : + (m.erase k).contains a = (!(k == a) && m.contains a) := + ExtDHashMap.contains_erase + +@[simp] +theorem mem_erase [EquivBEq α] [LawfulHashable α] {k a : α} : + a ∈ m.erase k ↔ (k == a) = false ∧ a ∈ m := + ExtDHashMap.mem_erase + +theorem contains_of_contains_erase [EquivBEq α] [LawfulHashable α] {k a : α} : + (m.erase k).contains a → m.contains a := + ExtDHashMap.contains_of_contains_erase + +theorem mem_of_mem_erase [EquivBEq α] [LawfulHashable α] {k a : α} : a ∈ m.erase k → a ∈ m := + ExtDHashMap.mem_of_mem_erase + +theorem size_erase [EquivBEq α] [LawfulHashable α] {k : α} : + (m.erase k).size = if k ∈ m then m.size - 1 else m.size := + ExtDHashMap.size_erase + +theorem size_erase_le [EquivBEq α] [LawfulHashable α] {k : α} : (m.erase k).size ≤ m.size := + ExtDHashMap.size_erase_le + +theorem size_le_size_erase [EquivBEq α] [LawfulHashable α] {k : α} : + m.size ≤ (m.erase k).size + 1 := + ExtDHashMap.size_le_size_erase + +@[simp] +theorem containsThenInsert_fst [EquivBEq α] [LawfulHashable α] {k : α} {v : β} : + (m.containsThenInsert k v).1 = m.contains k := + ExtDHashMap.containsThenInsert_fst + +@[simp] +theorem containsThenInsert_snd [EquivBEq α] [LawfulHashable α] {k : α} {v : β} : + (m.containsThenInsert k v).2 = m.insert k v := + ext (ExtDHashMap.containsThenInsert_snd) + +@[simp] +theorem containsThenInsertIfNew_fst [EquivBEq α] [LawfulHashable α] {k : α} {v : β} : + (m.containsThenInsertIfNew k v).1 = m.contains k := + ExtDHashMap.containsThenInsertIfNew_fst + +@[simp] +theorem containsThenInsertIfNew_snd [EquivBEq α] [LawfulHashable α] {k : α} {v : β} : + (m.containsThenInsertIfNew k v).2 = m.insertIfNew k v := + ext ExtDHashMap.containsThenInsertIfNew_snd + +@[simp] theorem get_eq_getElem [EquivBEq α] [LawfulHashable α] {a : α} {h} : get m a h = m[a]'h := rfl +@[simp] theorem get?_eq_getElem? [EquivBEq α] [LawfulHashable α] {a : α} : get? m a = m[a]? := rfl +@[simp] theorem get!_eq_getElem! [EquivBEq α] [LawfulHashable α] [Inhabited β] {a : α} : get! m a = m[a]! := rfl + +@[simp] +theorem getElem?_empty [EquivBEq α] [LawfulHashable α] {a : α} : (∅ : ExtHashMap α β)[a]? = none := + ExtDHashMap.Const.get?_empty + +theorem getElem?_insert [EquivBEq α] [LawfulHashable α] {k a : α} {v : β} : + (m.insert k v)[a]? = if k == a then some v else m[a]? := + ExtDHashMap.Const.get?_insert + +@[simp] +theorem getElem?_insert_self [EquivBEq α] [LawfulHashable α] {k : α} {v : β} : + (m.insert k v)[k]? = some v := + ExtDHashMap.Const.get?_insert_self + +theorem contains_eq_isSome_getElem? [EquivBEq α] [LawfulHashable α] {a : α} : + m.contains a = m[a]?.isSome := + ExtDHashMap.Const.contains_eq_isSome_get? + +theorem mem_iff_isSome_getElem? [EquivBEq α] [LawfulHashable α] {a : α} : + a ∈ m ↔ m[a]?.isSome := + ExtDHashMap.Const.mem_iff_isSome_get? + +theorem getElem?_eq_none_of_contains_eq_false [EquivBEq α] [LawfulHashable α] {a : α} : + m.contains a = false → m[a]? = none := + ExtDHashMap.Const.get?_eq_none_of_contains_eq_false + +theorem getElem?_eq_none [EquivBEq α] [LawfulHashable α] {a : α} : ¬a ∈ m → m[a]? = none := + ExtDHashMap.Const.get?_eq_none + +theorem getElem?_erase [EquivBEq α] [LawfulHashable α] {k a : α} : + (m.erase k)[a]? = if k == a then none else m[a]? := + ExtDHashMap.Const.get?_erase + +@[simp] +theorem getElem?_erase_self [EquivBEq α] [LawfulHashable α] {k : α} : (m.erase k)[k]? = none := + ExtDHashMap.Const.get?_erase_self + +theorem getElem?_congr [EquivBEq α] [LawfulHashable α] {a b : α} (hab : a == b) : m[a]? = m[b]? := + ExtDHashMap.Const.get?_congr hab + +theorem getElem_insert [EquivBEq α] [LawfulHashable α] {k a : α} {v : β} {h₁} : + (m.insert k v)[a]'h₁ = + if h₂ : k == a then v else m[a]'(mem_of_mem_insert h₁ (Bool.eq_false_iff.2 h₂)) := + ExtDHashMap.Const.get_insert (h₁ := h₁) + +@[simp] +theorem getElem_insert_self [EquivBEq α] [LawfulHashable α] {k : α} {v : β} : + (m.insert k v)[k]'mem_insert_self = v := + ExtDHashMap.Const.get_insert_self + +@[simp] +theorem getElem_erase [EquivBEq α] [LawfulHashable α] {k a : α} {h'} : + (m.erase k)[a]'h' = m[a]'(mem_of_mem_erase h') := + ExtDHashMap.Const.get_erase (h' := h') + +theorem getElem?_eq_some_getElem [EquivBEq α] [LawfulHashable α] {a : α} (h' : a ∈ m) : + m[a]? = some (m[a]'h') := + ExtDHashMap.Const.get?_eq_some_get h' + +theorem getElem_eq_get_getElem? [EquivBEq α] [LawfulHashable α] {a : α} {h} : + m[a]'h = m[a]?.get (mem_iff_isSome_getElem?.mp h) := + ExtDHashMap.Const.get_eq_get_get? (h := h) + +theorem get_getElem? [EquivBEq α] [LawfulHashable α] {a : α} {h} : + m[a]?.get h = m[a]'(mem_iff_isSome_getElem?.mpr h) := + ExtDHashMap.Const.get_get? + +theorem getElem_congr [EquivBEq α] [LawfulHashable α] {a b : α} (hab : a == b) {h'} : + m[a]'h' = m[b]'((mem_congr hab).1 h') := + ExtDHashMap.Const.get_congr hab (h' := h') + +@[simp] +theorem getElem!_empty [EquivBEq α] [LawfulHashable α] [Inhabited β] {a : α} : + (∅ : ExtHashMap α β)[a]! = default := + ExtDHashMap.Const.get!_empty + +theorem getElem!_insert [EquivBEq α] [LawfulHashable α] [Inhabited β] {k a : α} {v : β} : + (m.insert k v)[a]! = if k == a then v else m[a]! := + ExtDHashMap.Const.get!_insert + +@[simp] +theorem getElem!_insert_self [EquivBEq α] [LawfulHashable α] [Inhabited β] {k : α} {v : β} : + (m.insert k v)[k]! = v := + ExtDHashMap.Const.get!_insert_self + +theorem getElem!_eq_default_of_contains_eq_false [EquivBEq α] [LawfulHashable α] [Inhabited β] + {a : α} : m.contains a = false → m[a]! = default := + ExtDHashMap.Const.get!_eq_default_of_contains_eq_false + +theorem getElem!_eq_default [EquivBEq α] [LawfulHashable α] [Inhabited β] {a : α} : + ¬a ∈ m → m[a]! = default := + ExtDHashMap.Const.get!_eq_default + +theorem getElem!_erase [EquivBEq α] [LawfulHashable α] [Inhabited β] {k a : α} : + (m.erase k)[a]! = if k == a then default else m[a]! := + ExtDHashMap.Const.get!_erase + +@[simp] +theorem getElem!_erase_self [EquivBEq α] [LawfulHashable α] [Inhabited β] {k : α} : + (m.erase k)[k]! = default := + ExtDHashMap.Const.get!_erase_self + +theorem getElem?_eq_some_getElem!_of_contains [EquivBEq α] [LawfulHashable α] [Inhabited β] + {a : α} : m.contains a = true → m[a]? = some m[a]! := + ExtDHashMap.Const.get?_eq_some_get!_of_contains + +theorem getElem?_eq_some_getElem! [EquivBEq α] [LawfulHashable α] [Inhabited β] {a : α} : + a ∈ m → m[a]? = some m[a]! := + ExtDHashMap.Const.get?_eq_some_get! + +theorem getElem!_eq_get!_getElem? [EquivBEq α] [LawfulHashable α] [Inhabited β] {a : α} : + m[a]! = m[a]?.get! := + ExtDHashMap.Const.get!_eq_get!_get? + +theorem getElem_eq_getElem! [EquivBEq α] [LawfulHashable α] [Inhabited β] {a : α} {h'} : + m[a]'h' = m[a]! := + @ExtDHashMap.Const.get_eq_get! _ _ _ _ _ _ _ _ _ h' + +theorem getElem!_congr [EquivBEq α] [LawfulHashable α] [Inhabited β] {a b : α} (hab : a == b) : + m[a]! = m[b]! := + ExtDHashMap.Const.get!_congr hab + +@[simp] +theorem getD_empty [EquivBEq α] [LawfulHashable α] {a : α} {fallback : β} : + (∅ : ExtHashMap α β).getD a fallback = fallback := + ExtDHashMap.Const.getD_empty + +theorem getD_insert [EquivBEq α] [LawfulHashable α] {k a : α} {fallback v : β} : + (m.insert k v).getD a fallback = if k == a then v else m.getD a fallback := + ExtDHashMap.Const.getD_insert + +@[simp] +theorem getD_insert_self [EquivBEq α] [LawfulHashable α] {k : α} {fallback v : β} : + (m.insert k v).getD k fallback = v := + ExtDHashMap.Const.getD_insert_self + +theorem getD_eq_fallback_of_contains_eq_false [EquivBEq α] [LawfulHashable α] {a : α} + {fallback : β} : m.contains a = false → m.getD a fallback = fallback := + ExtDHashMap.Const.getD_eq_fallback_of_contains_eq_false + +theorem getD_eq_fallback [EquivBEq α] [LawfulHashable α] {a : α} {fallback : β} : + ¬a ∈ m → m.getD a fallback = fallback := + ExtDHashMap.Const.getD_eq_fallback + +theorem getD_erase [EquivBEq α] [LawfulHashable α] {k a : α} {fallback : β} : + (m.erase k).getD a fallback = if k == a then fallback else m.getD a fallback := + ExtDHashMap.Const.getD_erase + +@[simp] +theorem getD_erase_self [EquivBEq α] [LawfulHashable α] {k : α} {fallback : β} : + (m.erase k).getD k fallback = fallback := + ExtDHashMap.Const.getD_erase_self + +theorem getElem?_eq_some_getD_of_contains [EquivBEq α] [LawfulHashable α] {a : α} {fallback : β} : + m.contains a = true → m[a]? = some (m.getD a fallback) := + ExtDHashMap.Const.get?_eq_some_getD_of_contains + +theorem getElem?_eq_some_getD [EquivBEq α] [LawfulHashable α] {a : α} {fallback : β} : + a ∈ m → m[a]? = some (m.getD a fallback) := + ExtDHashMap.Const.get?_eq_some_getD + +theorem getD_eq_getD_getElem? [EquivBEq α] [LawfulHashable α] {a : α} {fallback : β} : + m.getD a fallback = m[a]?.getD fallback := + ExtDHashMap.Const.getD_eq_getD_get? + +theorem getElem_eq_getD [EquivBEq α] [LawfulHashable α] {a : α} {fallback : β} {h'} : + m[a]'h' = m.getD a fallback := + @ExtDHashMap.Const.get_eq_getD _ _ _ _ _ _ _ _ _ h' + +theorem getElem!_eq_getD_default [EquivBEq α] [LawfulHashable α] [Inhabited β] {a : α} : + m[a]! = m.getD a default := + ExtDHashMap.Const.get!_eq_getD_default + +theorem getD_congr [EquivBEq α] [LawfulHashable α] {a b : α} {fallback : β} (hab : a == b) : + m.getD a fallback = m.getD b fallback := + ExtDHashMap.Const.getD_congr hab + +@[simp] +theorem getKey?_empty [EquivBEq α] [LawfulHashable α] {a : α} : + (∅ : ExtHashMap α β).getKey? a = none := + ExtDHashMap.getKey?_empty + +theorem getKey?_insert [EquivBEq α] [LawfulHashable α] {k a : α} {v : β} : + (m.insert k v).getKey? a = if k == a then some k else m.getKey? a := + ExtDHashMap.getKey?_insert + +@[simp] +theorem getKey?_insert_self [EquivBEq α] [LawfulHashable α] {k : α} {v : β} : + (m.insert k v).getKey? k = some k := + ExtDHashMap.getKey?_insert_self + +theorem contains_eq_isSome_getKey? [EquivBEq α] [LawfulHashable α] {a : α} : + m.contains a = (m.getKey? a).isSome := + ExtDHashMap.contains_eq_isSome_getKey? + +theorem mem_iff_isSome_getKey? [EquivBEq α] [LawfulHashable α] {a : α} : + a ∈ m ↔ (m.getKey? a).isSome := + ExtDHashMap.mem_iff_isSome_getKey? + +theorem mem_of_getKey?_eq_some [EquivBEq α] [LawfulHashable α] {k k' : α} + (h : m.getKey? k = some k') : k' ∈ m := + ExtDHashMap.mem_of_getKey?_eq_some h + +theorem getKey?_eq_none_of_contains_eq_false [EquivBEq α] [LawfulHashable α] {a : α} : + m.contains a = false → m.getKey? a = none := + ExtDHashMap.getKey?_eq_none_of_contains_eq_false + +theorem getKey?_eq_none [EquivBEq α] [LawfulHashable α] {a : α} : ¬a ∈ m → m.getKey? a = none := + ExtDHashMap.getKey?_eq_none + +theorem getKey?_erase [EquivBEq α] [LawfulHashable α] {k a : α} : + (m.erase k).getKey? a = if k == a then none else m.getKey? a := + ExtDHashMap.getKey?_erase + +@[simp] +theorem getKey?_erase_self [EquivBEq α] [LawfulHashable α] {k : α} : (m.erase k).getKey? k = none := + ExtDHashMap.getKey?_erase_self + +theorem getKey?_beq [EquivBEq α] [LawfulHashable α] {k : α} : (m.getKey? k).all (· == k) := + ExtDHashMap.getKey?_beq + +theorem getKey?_congr [EquivBEq α] [LawfulHashable α] {k k' : α} (h : k == k') : + m.getKey? k = m.getKey? k' := + ExtDHashMap.getKey?_congr h + +theorem getKey?_eq_some_of_contains [LawfulBEq α] {k : α} (h : m.contains k) : + m.getKey? k = some k := + ExtDHashMap.getKey?_eq_some h + +theorem getKey?_eq_some [LawfulBEq α] {k : α} (h : k ∈ m) : m.getKey? k = some k := by + simpa only [mem_iff_contains] using getKey?_eq_some_of_contains h + +theorem getKey_insert [EquivBEq α] [LawfulHashable α] {k a : α} {v : β} {h₁} : + (m.insert k v)[a]'h₁ = + if h₂ : k == a then v else m[a]'(mem_of_mem_insert h₁ (Bool.eq_false_iff.2 h₂)) := + ExtDHashMap.Const.get_insert (h₁ := h₁) + +@[simp] +theorem getKey_insert_self [EquivBEq α] [LawfulHashable α] {k : α} {v : β} : + (m.insert k v).getKey k mem_insert_self = k := + ExtDHashMap.getKey_insert_self + +@[simp] +theorem getKey_erase [EquivBEq α] [LawfulHashable α] {k a : α} {h'} : + (m.erase k).getKey a h' = m.getKey a (mem_of_mem_erase h') := + ExtDHashMap.getKey_erase (h' := h') + +theorem getKey?_eq_some_getKey [EquivBEq α] [LawfulHashable α] {a : α} (h : a ∈ m) : + m.getKey? a = some (m.getKey a h) := + ExtDHashMap.getKey?_eq_some_getKey h + +theorem getKey_eq_get_getKey? [EquivBEq α] [LawfulHashable α] {a : α} {h} : + m.getKey a h = (m.getKey? a).get (mem_iff_isSome_getKey?.mp h) := + ExtDHashMap.getKey_eq_get_getKey? + +theorem get_getKey? [EquivBEq α] [LawfulHashable α] {a : α} {h} : + (m.getKey? a).get h = m.getKey a (mem_iff_isSome_getKey?.mpr h) := + ExtDHashMap.get_getKey? + +theorem getKey_beq [EquivBEq α] [LawfulHashable α] {k : α} (h : k ∈ m) : m.getKey k h == k := + ExtDHashMap.getKey_beq h + +theorem getKey_congr [EquivBEq α] [LawfulHashable α] {k₁ k₂ : α} (h : k₁ == k₂) + (h₁ : k₁ ∈ m) : m.getKey k₁ h₁ = m.getKey k₂ ((mem_congr h).mp h₁) := + ExtDHashMap.getKey_congr h h₁ + +theorem getKey_eq [LawfulBEq α] {k : α} (h : k ∈ m) : m.getKey k h = k := + ExtDHashMap.getKey_eq h + +@[simp] +theorem getKey!_empty [EquivBEq α] [LawfulHashable α] [Inhabited α] {a : α} : + (∅ : ExtHashMap α β).getKey! a = default := + ExtDHashMap.getKey!_empty + +theorem getKey!_insert [EquivBEq α] [LawfulHashable α] [Inhabited α] {k a : α} {v : β} : + (m.insert k v).getKey! a = if k == a then k else m.getKey! a := + ExtDHashMap.getKey!_insert + +@[simp] +theorem getKey!_insert_self [EquivBEq α] [LawfulHashable α] [Inhabited α] {k : α} {v : β} : + (m.insert k v).getKey! k = k := + ExtDHashMap.getKey!_insert_self + +theorem getKey!_eq_default_of_contains_eq_false [EquivBEq α] [LawfulHashable α] [Inhabited α] + {a : α} : m.contains a = false → m.getKey! a = default := + ExtDHashMap.getKey!_eq_default_of_contains_eq_false + +theorem getKey!_eq_default [EquivBEq α] [LawfulHashable α] [Inhabited α] {a : α} : + ¬a ∈ m → m.getKey! a = default := + ExtDHashMap.getKey!_eq_default + +theorem getKey!_erase [EquivBEq α] [LawfulHashable α] [Inhabited α] {k a : α} : + (m.erase k).getKey! a = if k == a then default else m.getKey! a := + ExtDHashMap.getKey!_erase + +@[simp] +theorem getKey!_erase_self [EquivBEq α] [LawfulHashable α] [Inhabited α] {k : α} : + (m.erase k).getKey! k = default := + ExtDHashMap.getKey!_erase_self + +theorem getKey?_eq_some_getKey!_of_contains [EquivBEq α] [LawfulHashable α] [Inhabited α] + {a : α} : m.contains a = true → m.getKey? a = some (m.getKey! a) := + ExtDHashMap.getKey?_eq_some_getKey!_of_contains + +theorem getKey?_eq_some_getKey! [EquivBEq α] [LawfulHashable α] [Inhabited α] {a : α} : + a ∈ m → m.getKey? a = some (m.getKey! a) := + ExtDHashMap.getKey?_eq_some_getKey! + +theorem getKey!_eq_get!_getKey? [EquivBEq α] [LawfulHashable α] [Inhabited α] {a : α} : + m.getKey! a = (m.getKey? a).get! := + ExtDHashMap.getKey!_eq_get!_getKey? + +theorem getKey_eq_getKey! [EquivBEq α] [LawfulHashable α] [Inhabited α] {a : α} {h'} : + m.getKey a h' = m.getKey! a := + @ExtDHashMap.getKey_eq_getKey! _ _ _ _ _ _ _ _ _ h' + +theorem getKey!_congr [EquivBEq α] [LawfulHashable α] [Inhabited α] {k k' : α} (h : k == k') : + m.getKey! k = m.getKey! k' := + ExtDHashMap.getKey!_congr h + +theorem getKey!_eq_of_contains [LawfulBEq α] [Inhabited α] {k : α} (h : m.contains k) : + m.getKey! k = k := + ExtDHashMap.getKey!_eq_of_contains h + +theorem getKey!_eq_of_mem [LawfulBEq α] [Inhabited α] {k : α} (h : k ∈ m) : m.getKey! k = k := + ExtDHashMap.getKey!_eq_of_mem h + +@[simp] +theorem getKeyD_empty [EquivBEq α] [LawfulHashable α] {a : α} {fallback : α} : + (∅ : ExtHashMap α β).getKeyD a fallback = fallback := + ExtDHashMap.getKeyD_empty + +theorem getKeyD_insert [EquivBEq α] [LawfulHashable α] {k a fallback : α} {v : β} : + (m.insert k v).getKeyD a fallback = if k == a then k else m.getKeyD a fallback := + ExtDHashMap.getKeyD_insert + +@[simp] +theorem getKeyD_insert_self [EquivBEq α] [LawfulHashable α] {k fallback : α} {v : β} : + (m.insert k v).getKeyD k fallback = k := + ExtDHashMap.getKeyD_insert_self + +theorem getKeyD_eq_fallback_of_contains_eq_false [EquivBEq α] [LawfulHashable α] {a : α} + {fallback : α} : m.contains a = false → m.getKeyD a fallback = fallback := + ExtDHashMap.getKeyD_eq_fallback_of_contains_eq_false + +theorem getKeyD_eq_fallback [EquivBEq α] [LawfulHashable α] {a : α} {fallback : α} : + ¬a ∈ m → m.getKeyD a fallback = fallback := + ExtDHashMap.getKeyD_eq_fallback + +theorem getKeyD_erase [EquivBEq α] [LawfulHashable α] {k a : α} {fallback : α} : + (m.erase k).getKeyD a fallback = if k == a then fallback else m.getKeyD a fallback := + ExtDHashMap.getKeyD_erase + +@[simp] +theorem getKeyD_erase_self [EquivBEq α] [LawfulHashable α] {k : α} {fallback : α} : + (m.erase k).getKeyD k fallback = fallback := + ExtDHashMap.getKeyD_erase_self + +theorem getKey?_eq_some_getKeyD_of_contains [EquivBEq α] [LawfulHashable α] {a : α} {fallback : α} : + m.contains a = true → m.getKey? a = some (m.getKeyD a fallback) := + ExtDHashMap.getKey?_eq_some_getKeyD_of_contains + +theorem getKey?_eq_some_getKeyD [EquivBEq α] [LawfulHashable α] {a : α} {fallback : α} : + a ∈ m → m.getKey? a = some (m.getKeyD a fallback) := + ExtDHashMap.getKey?_eq_some_getKeyD + +theorem getKeyD_eq_getD_getKey? [EquivBEq α] [LawfulHashable α] {a : α} {fallback : α} : + m.getKeyD a fallback = (m.getKey? a).getD fallback := + ExtDHashMap.getKeyD_eq_getD_getKey? + +theorem getKey_eq_getKeyD [EquivBEq α] [LawfulHashable α] {a : α} {fallback : α} {h'} : + m.getKey a h' = m.getKeyD a fallback := + @ExtDHashMap.getKey_eq_getKeyD _ _ _ _ _ _ _ _ _ h' + +theorem getKey!_eq_getKeyD_default [EquivBEq α] [LawfulHashable α] [Inhabited α] {a : α} : + m.getKey! a = m.getKeyD a default := + ExtDHashMap.getKey!_eq_getKeyD_default + +theorem getKeyD_congr [EquivBEq α] [LawfulHashable α] {k k' fallback : α} + (h : k == k') : m.getKeyD k fallback = m.getKeyD k' fallback := + ExtDHashMap.getKeyD_congr h + +theorem getKeyD_eq_of_contains [LawfulBEq α] {k fallback : α} (h : m.contains k) : + m.getKeyD k fallback = k := + ExtDHashMap.getKeyD_eq_of_contains h + +theorem getKeyD_eq_of_mem [LawfulBEq α] {k fallback : α} (h : k ∈ m) : + m.getKeyD k fallback = k := + ExtDHashMap.getKeyD_eq_of_mem h + +@[simp] +theorem not_insertIfNew_eq_empty [EquivBEq α] [LawfulHashable α] {k : α} {v : β} : + ¬m.insertIfNew k v = ∅ := + (not_congr ext_iff).mpr ExtDHashMap.not_insertIfNew_eq_empty + +@[simp] +theorem contains_insertIfNew [EquivBEq α] [LawfulHashable α] {k a : α} {v : β} : + (m.insertIfNew k v).contains a = (k == a || m.contains a) := + ExtDHashMap.contains_insertIfNew + +@[simp] +theorem mem_insertIfNew [EquivBEq α] [LawfulHashable α] {k a : α} {v : β} : + a ∈ m.insertIfNew k v ↔ k == a ∨ a ∈ m := + ExtDHashMap.mem_insertIfNew + +theorem contains_insertIfNew_self [EquivBEq α] [LawfulHashable α] {k : α} {v : β} : + (m.insertIfNew k v).contains k := + ExtDHashMap.contains_insertIfNew_self + +theorem mem_insertIfNew_self [EquivBEq α] [LawfulHashable α] {k : α} {v : β} : + k ∈ m.insertIfNew k v := + ExtDHashMap.mem_insertIfNew_self + +theorem contains_of_contains_insertIfNew [EquivBEq α] [LawfulHashable α] {k a : α} {v : β} : + (m.insertIfNew k v).contains a → (k == a) = false → m.contains a := + ExtDHashMap.contains_of_contains_insertIfNew + +theorem mem_of_mem_insertIfNew [EquivBEq α] [LawfulHashable α] {k a : α} {v : β} : + a ∈ m.insertIfNew k v → (k == a) = false → a ∈ m := + ExtDHashMap.mem_of_mem_insertIfNew + +/-- This is a restatement of `contains_of_contains_insertIfNew` that is written to exactly match the proof +obligation in the statement of `getElem_insertIfNew`. -/ +theorem contains_of_contains_insertIfNew' [EquivBEq α] [LawfulHashable α] {k a : α} {v : β} : + (m.insertIfNew k v).contains a → ¬((k == a) ∧ m.contains k = false) → m.contains a := + ExtDHashMap.contains_of_contains_insertIfNew' + +/-- This is a restatement of `mem_of_mem_insertIfNew` that is written to exactly match the proof obligation +in the statement of `getElem_insertIfNew`. -/ +theorem mem_of_mem_insertIfNew' [EquivBEq α] [LawfulHashable α] {k a : α} {v : β} : + a ∈ m.insertIfNew k v → ¬((k == a) ∧ ¬k ∈ m) → a ∈ m := + ExtDHashMap.mem_of_mem_insertIfNew' + +theorem size_insertIfNew [EquivBEq α] [LawfulHashable α] {k : α} {v : β} : + (m.insertIfNew k v).size = if k ∈ m then m.size else m.size + 1 := + ExtDHashMap.size_insertIfNew + +theorem size_le_size_insertIfNew [EquivBEq α] [LawfulHashable α] {k : α} {v : β} : + m.size ≤ (m.insertIfNew k v).size := + ExtDHashMap.size_le_size_insertIfNew + +theorem size_insertIfNew_le [EquivBEq α] [LawfulHashable α] {k : α} {v : β} : + (m.insertIfNew k v).size ≤ m.size + 1 := + ExtDHashMap.size_insertIfNew_le + +theorem getElem?_insertIfNew [EquivBEq α] [LawfulHashable α] {k a : α} {v : β} : + (m.insertIfNew k v)[a]? = if k == a ∧ ¬k ∈ m then some v else m[a]? := + ExtDHashMap.Const.get?_insertIfNew + +theorem getElem_insertIfNew [EquivBEq α] [LawfulHashable α] {k a : α} {v : β} {h₁} : + (m.insertIfNew k v)[a]'h₁ = + if h₂ : k == a ∧ ¬k ∈ m then v else m[a]'(mem_of_mem_insertIfNew' h₁ h₂) := + ExtDHashMap.Const.get_insertIfNew (h₁ := h₁) + +theorem getElem!_insertIfNew [EquivBEq α] [LawfulHashable α] [Inhabited β] {k a : α} {v : β} : + (m.insertIfNew k v)[a]! = if k == a ∧ ¬k ∈ m then v else m[a]! := + ExtDHashMap.Const.get!_insertIfNew + +theorem getD_insertIfNew [EquivBEq α] [LawfulHashable α] {k a : α} {fallback v : β} : + (m.insertIfNew k v).getD a fallback = + if k == a ∧ ¬k ∈ m then v else m.getD a fallback := + ExtDHashMap.Const.getD_insertIfNew + +theorem getKey?_insertIfNew [EquivBEq α] [LawfulHashable α] {k a : α} {v : β} : + getKey? (m.insertIfNew k v) a = if k == a ∧ ¬k ∈ m then some k else getKey? m a := + ExtDHashMap.getKey?_insertIfNew + +theorem getKey_insertIfNew [EquivBEq α] [LawfulHashable α] {k a : α} {v : β} {h₁} : + getKey (m.insertIfNew k v) a h₁ = + if h₂ : k == a ∧ ¬k ∈ m then k else getKey m a (mem_of_mem_insertIfNew' h₁ h₂) := + ExtDHashMap.getKey_insertIfNew + +theorem getKey!_insertIfNew [EquivBEq α] [LawfulHashable α] [Inhabited α] {k a : α} {v : β} : + getKey! (m.insertIfNew k v) a = if k == a ∧ ¬k ∈ m then k else getKey! m a := + ExtDHashMap.getKey!_insertIfNew + +theorem getKeyD_insertIfNew [EquivBEq α] [LawfulHashable α] {k a fallback : α} {v : β} : + getKeyD (m.insertIfNew k v) a fallback = if k == a ∧ ¬k ∈ m then k else getKeyD m a fallback := + ExtDHashMap.getKeyD_insertIfNew + +@[simp] +theorem getThenInsertIfNew?_fst [EquivBEq α] [LawfulHashable α] {k : α} {v : β} : + (getThenInsertIfNew? m k v).1 = get? m k := + ExtDHashMap.Const.getThenInsertIfNew?_fst + +@[simp] +theorem getThenInsertIfNew?_snd [EquivBEq α] [LawfulHashable α] {k : α} {v : β} : + (getThenInsertIfNew? m k v).2 = m.insertIfNew k v := + ext (ExtDHashMap.Const.getThenInsertIfNew?_snd) + +instance [EquivBEq α] [LawfulHashable α] : LawfulGetElem (ExtHashMap α β) α β (fun m a => a ∈ m) where + getElem?_def m a _ := by + split + · exact getElem?_eq_some_getElem ‹_› + · exact getElem?_eq_none ‹_› + getElem!_def m a := by + rw [getElem!_eq_get!_getElem?] + split <;> simp_all + +variable {ρ : Type w} [ForIn Id ρ (α × β)] + +@[simp] +theorem insertMany_nil [EquivBEq α] [LawfulHashable α] : + insertMany m [] = m := + ext ExtDHashMap.Const.insertMany_nil + +@[simp] +theorem insertMany_list_singleton [EquivBEq α] [LawfulHashable α] {k : α} {v : β} : + insertMany m [⟨k, v⟩] = m.insert k v := + ext ExtDHashMap.Const.insertMany_list_singleton + +theorem insertMany_cons [EquivBEq α] [LawfulHashable α] {l : List (α × β)} {k : α} {v : β} : + insertMany m (⟨k, v⟩ :: l) = insertMany (m.insert k v) l := + ext ExtDHashMap.Const.insertMany_cons + +@[elab_as_elim] +theorem insertMany_ind [EquivBEq α] [LawfulHashable α] + {motive : ExtHashMap α β → Prop} (m : ExtHashMap α β) {l : ρ} + (init : motive m) (insert : ∀ m a b, motive m → motive (m.insert a b)) : + motive (m.insertMany l) := + show motive ⟨ExtDHashMap.Const.insertMany m.1 l⟩ from + ExtDHashMap.Const.insertMany_ind m.inner l init fun m => insert ⟨m⟩ + +@[simp] +theorem contains_insertMany_list [EquivBEq α] [LawfulHashable α] + {l : List (α × β)} {k : α} : + (insertMany m l).contains k = (m.contains k || (l.map Prod.fst).contains k) := + ExtDHashMap.Const.contains_insertMany_list + +@[simp] +theorem mem_insertMany_list [EquivBEq α] [LawfulHashable α] + {l : List (α × β)} {k : α} : + k ∈ insertMany m l ↔ k ∈ m ∨ (l.map Prod.fst).contains k := + ExtDHashMap.Const.mem_insertMany_list + +theorem mem_of_mem_insertMany_list [EquivBEq α] [LawfulHashable α] + {l : List (α × β)} {k : α} (mem : k ∈ insertMany m l) + (contains_eq_false : (l.map Prod.fst).contains k = false) : + k ∈ m := + ExtDHashMap.Const.mem_of_mem_insertMany_list mem contains_eq_false + +theorem mem_insertMany_of_mem [EquivBEq α] [LawfulHashable α] + {l : ρ} {k : α} : k ∈ m → k ∈ m.insertMany l := + ExtDHashMap.Const.mem_insertMany_of_mem + +theorem getElem?_insertMany_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α] + {l : List (α × β)} {k : α} + (contains_eq_false : (l.map Prod.fst).contains k = false) : + (insertMany m l)[k]? = m[k]? := + ExtDHashMap.Const.get?_insertMany_list_of_contains_eq_false contains_eq_false + +theorem getElem?_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α] + {l : List (α × β)} {k k' : α} (k_beq : k == k') {v : β} + (distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) (mem : ⟨k, v⟩ ∈ l) : + (insertMany m l)[k']? = some v := + ExtDHashMap.Const.get?_insertMany_list_of_mem k_beq distinct mem + +theorem getElem_insertMany_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α] + {l : List (α × β)} {k : α} + (contains_eq_false : (l.map Prod.fst).contains k = false) + {h} : + (insertMany m l)[k] = m[k]'(mem_of_mem_insertMany_list h contains_eq_false) := + ExtDHashMap.Const.get_insertMany_list_of_contains_eq_false contains_eq_false (h := h) + +theorem getElem_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α] + {l : List (α × β)} {k k' : α} (k_beq : k == k') {v : β} + (distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) (mem : ⟨k, v⟩ ∈ l) {h} : + (insertMany m l)[k'] = v := + ExtDHashMap.Const.get_insertMany_list_of_mem k_beq distinct mem (h := h) + +theorem getElem!_insertMany_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α] + [Inhabited β] {l : List (α × β)} {k : α} + (contains_eq_false : (l.map Prod.fst).contains k = false) : + (insertMany m l)[k]! = m[k]! := + ExtDHashMap.Const.get!_insertMany_list_of_contains_eq_false contains_eq_false + +theorem getElem!_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α] [Inhabited β] + {l : List (α × β)} {k k' : α} (k_beq : k == k') {v : β} + (distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) (mem : ⟨k, v⟩ ∈ l) : + (insertMany m l)[k']! = v := + ExtDHashMap.Const.get!_insertMany_list_of_mem k_beq distinct mem + +theorem getD_insertMany_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α] + {l : List (α × β)} {k : α} {fallback : β} + (contains_eq_false : (l.map Prod.fst).contains k = false) : + getD (insertMany m l) k fallback = getD m k fallback := + ExtDHashMap.Const.getD_insertMany_list_of_contains_eq_false contains_eq_false + +theorem getD_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α] + {l : List (α × β)} {k k' : α} (k_beq : k == k') {v fallback : β} + (distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) (mem : ⟨k, v⟩ ∈ l) : + getD (insertMany m l) k' fallback = v := + ExtDHashMap.Const.getD_insertMany_list_of_mem k_beq distinct mem + +theorem getKey?_insertMany_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α] + {l : List (α × β)} {k : α} + (contains_eq_false : (l.map Prod.fst).contains k = false) : + (insertMany m l).getKey? k = m.getKey? k := + ExtDHashMap.Const.getKey?_insertMany_list_of_contains_eq_false contains_eq_false + +theorem getKey?_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α] + {l : List (α × β)} + {k k' : α} (k_beq : k == k') + (distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) + (mem : k ∈ l.map Prod.fst) : + (insertMany m l).getKey? k' = some k := + ExtDHashMap.Const.getKey?_insertMany_list_of_mem k_beq distinct mem + +theorem getKey_insertMany_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α] + {l : List (α × β)} {k : α} + (contains_eq_false : (l.map Prod.fst).contains k = false) + {h} : + (insertMany m l).getKey k h = + m.getKey k (mem_of_mem_insertMany_list h contains_eq_false) := + ExtDHashMap.Const.getKey_insertMany_list_of_contains_eq_false contains_eq_false + +theorem getKey_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α] + {l : List (α × β)} + {k k' : α} (k_beq : k == k') + (distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) + (mem : k ∈ l.map Prod.fst) + {h} : + (insertMany m l).getKey k' h = k := + ExtDHashMap.Const.getKey_insertMany_list_of_mem k_beq distinct mem + +theorem getKey!_insertMany_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α] [Inhabited α] + {l : List (α × β)} {k : α} + (contains_eq_false : (l.map Prod.fst).contains k = false) : + (insertMany m l).getKey! k = m.getKey! k := + ExtDHashMap.Const.getKey!_insertMany_list_of_contains_eq_false contains_eq_false + +theorem getKey!_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α] [Inhabited α] + {l : List (α × β)} + {k k' : α} (k_beq : k == k') + (distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) + (mem : k ∈ l.map Prod.fst) : + (insertMany m l).getKey! k' = k := + ExtDHashMap.Const.getKey!_insertMany_list_of_mem k_beq distinct mem + +theorem getKeyD_insertMany_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α] + {l : List (α × β)} {k fallback : α} + (contains_eq_false : (l.map Prod.fst).contains k = false) : + (insertMany m l).getKeyD k fallback = m.getKeyD k fallback := + ExtDHashMap.Const.getKeyD_insertMany_list_of_contains_eq_false contains_eq_false + +theorem getKeyD_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α] + {l : List (α × β)} + {k k' fallback : α} (k_beq : k == k') + (distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) + (mem : k ∈ l.map Prod.fst) : + (insertMany m l).getKeyD k' fallback = k := + ExtDHashMap.Const.getKeyD_insertMany_list_of_mem k_beq distinct mem + +theorem size_insertMany_list [EquivBEq α] [LawfulHashable α] + {l : List (α × β)} + (distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) : + (∀ (a : α), a ∈ m → (l.map Prod.fst).contains a = false) → + (insertMany m l).size = m.size + l.length := + ExtDHashMap.Const.size_insertMany_list distinct + +theorem size_le_size_insertMany_list [EquivBEq α] [LawfulHashable α] + {l : List (α × β)} : + m.size ≤ (insertMany m l).size := + ExtDHashMap.Const.size_le_size_insertMany_list + +theorem size_le_size_insertMany [EquivBEq α] [LawfulHashable α] + {l : ρ} : m.size ≤ (insertMany m l).size := + ExtDHashMap.Const.size_le_size_insertMany + +theorem size_insertMany_list_le [EquivBEq α] [LawfulHashable α] + {l : List (α × β)} : + (insertMany m l).size ≤ m.size + l.length := + ExtDHashMap.Const.size_insertMany_list_le + +@[simp] +theorem insertMany_list_eq_empty_iff [EquivBEq α] [LawfulHashable α] {l : List (α × β)} : + m.insertMany l = ∅ ↔ m = ∅ ∧ l = [] := by + simpa only [ext_iff] using ExtDHashMap.Const.insertMany_list_eq_empty_iff + +theorem eq_empty_of_insertMany_eq_empty [EquivBEq α] [LawfulHashable α] {l : ρ} : + m.insertMany l = ∅ → m = ∅ := by + simpa only [ext_iff] using ExtDHashMap.Const.eq_empty_of_insertMany_eq_empty + +variable {m : ExtHashMap α Unit} +variable {ρ : Type w} [ForIn Id ρ α] + +@[simp] +theorem insertManyIfNewUnit_nil [EquivBEq α] [LawfulHashable α] : + insertManyIfNewUnit m [] = m := + ext ExtDHashMap.Const.insertManyIfNewUnit_nil + +@[simp] +theorem insertManyIfNewUnit_list_singleton [EquivBEq α] [LawfulHashable α] {k : α} : + insertManyIfNewUnit m [k] = m.insertIfNew k () := + ext ExtDHashMap.Const.insertManyIfNewUnit_list_singleton + +theorem insertManyIfNewUnit_cons [EquivBEq α] [LawfulHashable α] {l : List α} {k : α} : + insertManyIfNewUnit m (k :: l) = insertManyIfNewUnit (m.insertIfNew k ()) l := + ext ExtDHashMap.Const.insertManyIfNewUnit_cons + +@[elab_as_elim] +theorem insertManyIfNewUnit_ind [EquivBEq α] [LawfulHashable α] + {motive : ExtHashMap α Unit → Prop} (m : ExtHashMap α Unit) (l : ρ) + (init : motive m) (insert : ∀ m a, motive m → motive (m.insertIfNew a ())) : + motive (insertManyIfNewUnit m l) := + show motive ⟨ExtDHashMap.Const.insertManyIfNewUnit m.1 l⟩ from + ExtDHashMap.Const.insertManyIfNewUnit_ind m.inner l init fun m => insert ⟨m⟩ + +@[simp] +theorem contains_insertManyIfNewUnit_list [EquivBEq α] [LawfulHashable α] + {l : List α} {k : α} : + (insertManyIfNewUnit m l).contains k = (m.contains k || l.contains k) := + ExtDHashMap.Const.contains_insertManyIfNewUnit_list + +@[simp] +theorem mem_insertManyIfNewUnit_list [EquivBEq α] [LawfulHashable α] + {l : List α} {k : α} : + k ∈ insertManyIfNewUnit m l ↔ k ∈ m ∨ l.contains k := + ExtDHashMap.Const.mem_insertManyIfNewUnit_list + +theorem mem_of_mem_insertManyIfNewUnit_list [EquivBEq α] [LawfulHashable α] + {l : List α} {k : α} (contains_eq_false : l.contains k = false) : + k ∈ insertManyIfNewUnit m l → k ∈ m := + ExtDHashMap.Const.mem_of_mem_insertManyIfNewUnit_list contains_eq_false + +theorem mem_insertManyIfNewUnit_of_mem [EquivBEq α] [LawfulHashable α] + {l : ρ} {k : α} : k ∈ m → k ∈ insertManyIfNewUnit m l := + ExtDHashMap.Const.mem_insertManyIfNewUnit_of_mem + +theorem getElem?_insertManyIfNewUnit_list [EquivBEq α] [LawfulHashable α] + {l : List α} {k : α} : + (insertManyIfNewUnit m l)[k]? = + if k ∈ m ∨ l.contains k then some () else none := + ExtDHashMap.Const.get?_insertManyIfNewUnit_list + +theorem getElem_insertManyIfNewUnit_list [EquivBEq α] [LawfulHashable α] + {l : List α} {k : α} {h} : + (insertManyIfNewUnit m l)[k] = () := + rfl + +theorem getElem!_insertManyIfNewUnit_list [EquivBEq α] [LawfulHashable α] + {l : List α} {k : α} : + (insertManyIfNewUnit m l)[k]! = () := + rfl + +theorem getD_insertManyIfNewUnit_list [EquivBEq α] [LawfulHashable α] + {l : List α} {k : α} {fallback : Unit} : + getD (insertManyIfNewUnit m l) k fallback = () := by + rfl + +theorem getKey?_insertManyIfNewUnit_list_of_not_mem_of_contains_eq_false + [EquivBEq α] [LawfulHashable α] {l : List α} {k : α} + (not_mem : ¬ k ∈ m) (contains_eq_false : l.contains k = false) : + getKey? (insertManyIfNewUnit m l) k = none := + ExtDHashMap.Const.getKey?_insertManyIfNewUnit_list_of_not_mem_of_contains_eq_false + not_mem contains_eq_false + +theorem getKey?_insertManyIfNewUnit_list_of_not_mem_of_mem [EquivBEq α] [LawfulHashable α] + {l : List α} {k k' : α} (k_beq : k == k') (not_mem : ¬ k ∈ m) + (distinct : l.Pairwise (fun a b => (a == b) = false)) (mem : k ∈ l) : + getKey? (insertManyIfNewUnit m l) k' = some k := + ExtDHashMap.Const.getKey?_insertManyIfNewUnit_list_of_not_mem_of_mem + k_beq not_mem distinct mem + +theorem getKey?_insertManyIfNewUnit_list_of_mem [EquivBEq α] [LawfulHashable α] + {l : List α} {k : α} (mem : k ∈ m) : + getKey? (insertManyIfNewUnit m l) k = getKey? m k := + ExtDHashMap.Const.getKey?_insertManyIfNewUnit_list_of_mem mem + +theorem getKey_insertManyIfNewUnit_list_of_not_mem_of_mem [EquivBEq α] [LawfulHashable α] + {l : List α} {k k' : α} (k_beq : k == k') (not_mem : ¬ k ∈ m) + (distinct : l.Pairwise (fun a b => (a == b) = false)) (mem : k ∈ l) {h} : + getKey (insertManyIfNewUnit m l) k' h = k := + ExtDHashMap.Const.getKey_insertManyIfNewUnit_list_of_not_mem_of_mem + k_beq not_mem distinct mem + +theorem getKey_insertManyIfNewUnit_list_of_mem [EquivBEq α] [LawfulHashable α] + {l : List α} {k : α} (mem : k ∈ m) {h} : + getKey (insertManyIfNewUnit m l) k h = getKey m k mem := + ExtDHashMap.Const.getKey_insertManyIfNewUnit_list_of_mem mem + +theorem getKey!_insertManyIfNewUnit_list_of_not_mem_of_contains_eq_false + [EquivBEq α] [LawfulHashable α] [Inhabited α] {l : List α} {k : α} + (not_mem : ¬ k ∈ m) (contains_eq_false : l.contains k = false) : + getKey! (insertManyIfNewUnit m l) k = default := + ExtDHashMap.Const.getKey!_insertManyIfNewUnit_list_of_not_mem_of_contains_eq_false + not_mem contains_eq_false + +theorem getKey!_insertManyIfNewUnit_list_of_not_mem_of_mem [EquivBEq α] [LawfulHashable α] + [Inhabited α] {l : List α} {k k' : α} (k_beq : k == k') + (not_mem : ¬ k ∈ m) + (distinct : l.Pairwise (fun a b => (a == b) = false)) (mem : k ∈ l) : + getKey! (insertManyIfNewUnit m l) k' = k := + ExtDHashMap.Const.getKey!_insertManyIfNewUnit_list_of_not_mem_of_mem + k_beq not_mem distinct mem + +theorem getKey!_insertManyIfNewUnit_list_of_mem [EquivBEq α] [LawfulHashable α] + [Inhabited α] {l : List α} {k : α} (mem : k ∈ m) : + getKey! (insertManyIfNewUnit m l) k = getKey! m k := + ExtDHashMap.Const.getKey!_insertManyIfNewUnit_list_of_mem mem + +theorem getKeyD_insertManyIfNewUnit_list_of_not_mem_of_contains_eq_false + [EquivBEq α] [LawfulHashable α] {l : List α} {k fallback : α} + (not_mem : ¬ k ∈ m) (contains_eq_false : l.contains k = false) : + getKeyD (insertManyIfNewUnit m l) k fallback = fallback := + ExtDHashMap.Const.getKeyD_insertManyIfNewUnit_list_of_not_mem_of_contains_eq_false + not_mem contains_eq_false + +theorem getKeyD_insertManyIfNewUnit_list_of_not_mem_of_mem [EquivBEq α] [LawfulHashable α] + {l : List α} {k k' fallback : α} (k_beq : k == k') + (not_mem : ¬ k ∈ m) + (distinct : l.Pairwise (fun a b => (a == b) = false)) (mem : k ∈ l ) : + getKeyD (insertManyIfNewUnit m l) k' fallback = k := + ExtDHashMap.Const.getKeyD_insertManyIfNewUnit_list_of_not_mem_of_mem + k_beq not_mem distinct mem + +theorem getKeyD_insertManyIfNewUnit_list_of_mem [EquivBEq α] [LawfulHashable α] + {l : List α} {k fallback : α} (mem : k ∈ m) : + getKeyD (insertManyIfNewUnit m l) k fallback = getKeyD m k fallback := + ExtDHashMap.Const.getKeyD_insertManyIfNewUnit_list_of_mem mem + +theorem size_insertManyIfNewUnit_list [EquivBEq α] [LawfulHashable α] + {l : List α} + (distinct : l.Pairwise (fun a b => (a == b) = false)) : + (∀ (a : α), a ∈ m → l.contains a = false) → + (insertManyIfNewUnit m l).size = m.size + l.length := + ExtDHashMap.Const.size_insertManyIfNewUnit_list distinct + +theorem size_le_size_insertManyIfNewUnit_list [EquivBEq α] [LawfulHashable α] + {l : List α} : + m.size ≤ (insertManyIfNewUnit m l).size := + ExtDHashMap.Const.size_le_size_insertManyIfNewUnit_list + +theorem size_le_size_insertManyIfNewUnit [EquivBEq α] [LawfulHashable α] + {l : ρ} : m.size ≤ (insertManyIfNewUnit m l).size := + ExtDHashMap.Const.size_le_size_insertManyIfNewUnit + +theorem size_insertManyIfNewUnit_list_le [EquivBEq α] [LawfulHashable α] + {l : List α} : + (insertManyIfNewUnit m l).size ≤ m.size + l.length := + ExtDHashMap.Const.size_insertManyIfNewUnit_list_le + +@[simp] +theorem insertManyIfNewUnit_list_eq_empty_iff [EquivBEq α] [LawfulHashable α] {l : List α} : + insertManyIfNewUnit m l = ∅ ↔ m = ∅ ∧ l = [] := by + simpa only [ext_iff] using ExtDHashMap.Const.insertManyIfNewUnit_list_eq_empty_iff + +theorem eq_empty_of_insertManyIfNewUnit_eq_empty [EquivBEq α] [LawfulHashable α] {l : ρ} : + insertManyIfNewUnit m l = ∅ → m = ∅ := by + simpa only [ext_iff] using ExtDHashMap.Const.eq_empty_of_insertManyIfNewUnit_eq_empty + +end + +section + +@[simp] +theorem ofList_nil [EquivBEq α] [LawfulHashable α] : + ofList ([] : List (α × β)) = ∅ := + ext ExtDHashMap.Const.ofList_nil + +@[simp] +theorem ofList_singleton [EquivBEq α] [LawfulHashable α] {k : α} {v : β} : + ofList [⟨k, v⟩] = (∅ : ExtHashMap α β).insert k v := + ext ExtDHashMap.Const.ofList_singleton + +theorem ofList_cons [EquivBEq α] [LawfulHashable α] {k : α} {v : β} {tl : List (α × β)} : + ofList (⟨k, v⟩ :: tl) = insertMany ((∅ : ExtHashMap α β).insert k v) tl := + ext ExtDHashMap.Const.ofList_cons + +@[simp] +theorem contains_ofList [EquivBEq α] [LawfulHashable α] + {l : List (α × β)} {k : α} : + (ofList l).contains k = (l.map Prod.fst).contains k := + ExtDHashMap.Const.contains_ofList + +@[simp] +theorem mem_ofList [EquivBEq α] [LawfulHashable α] + {l : List (α × β)} {k : α} : + k ∈ ofList l ↔ (l.map Prod.fst).contains k := + ExtDHashMap.Const.mem_ofList + +theorem getElem?_ofList_of_contains_eq_false [EquivBEq α] [LawfulHashable α] + {l : List (α × β)} {k : α} + (contains_eq_false : (l.map Prod.fst).contains k = false) : + (ofList l)[k]? = none := + ExtDHashMap.Const.get?_ofList_of_contains_eq_false contains_eq_false + +theorem getElem?_ofList_of_mem [EquivBEq α] [LawfulHashable α] + {l : List (α × β)} {k k' : α} (k_beq : k == k') {v : β} + (distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) + (mem : ⟨k, v⟩ ∈ l) : + (ofList l)[k']? = some v := + ExtDHashMap.Const.get?_ofList_of_mem k_beq distinct mem + +theorem getElem_ofList_of_mem [EquivBEq α] [LawfulHashable α] + {l : List (α × β)} {k k' : α} (k_beq : k == k') {v : β} + (distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) + (mem : ⟨k, v⟩ ∈ l) + {h} : + (ofList l)[k'] = v := + ExtDHashMap.Const.get_ofList_of_mem k_beq distinct mem (h := h) + +theorem getElem!_ofList_of_contains_eq_false [EquivBEq α] [LawfulHashable α] + {l : List (α × β)} {k : α} [Inhabited β] + (contains_eq_false : (l.map Prod.fst).contains k = false) : + (ofList l)[k]! = (default : β) := + ExtDHashMap.Const.get!_ofList_of_contains_eq_false contains_eq_false + +theorem getElem!_ofList_of_mem [EquivBEq α] [LawfulHashable α] + {l : List (α × β)} {k k' : α} (k_beq : k == k') {v : β} [Inhabited β] + (distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) + (mem : ⟨k, v⟩ ∈ l) : + (ofList l)[k']! = v := + ExtDHashMap.Const.get!_ofList_of_mem k_beq distinct mem + +theorem getD_ofList_of_contains_eq_false [EquivBEq α] [LawfulHashable α] + {l : List (α × β)} {k : α} {fallback : β} + (contains_eq_false : (l.map Prod.fst).contains k = false) : + getD (ofList l) k fallback = fallback := + ExtDHashMap.Const.getD_ofList_of_contains_eq_false contains_eq_false + +theorem getD_ofList_of_mem [EquivBEq α] [LawfulHashable α] + {l : List (α × β)} {k k' : α} (k_beq : k == k') {v : β} {fallback : β} + (distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) + (mem : ⟨k, v⟩ ∈ l) : + getD (ofList l) k' fallback = v := + ExtDHashMap.Const.getD_ofList_of_mem k_beq distinct mem + +theorem getKey?_ofList_of_contains_eq_false [EquivBEq α] [LawfulHashable α] + {l : List (α × β)} {k : α} + (contains_eq_false : (l.map Prod.fst).contains k = false) : + (ofList l).getKey? k = none := + ExtDHashMap.Const.getKey?_ofList_of_contains_eq_false contains_eq_false + +theorem getKey?_ofList_of_mem [EquivBEq α] [LawfulHashable α] + {l : List (α × β)} + {k k' : α} (k_beq : k == k') + (distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) + (mem : k ∈ l.map Prod.fst) : + (ofList l).getKey? k' = some k := + ExtDHashMap.Const.getKey?_ofList_of_mem k_beq distinct mem + +theorem getKey_ofList_of_mem [EquivBEq α] [LawfulHashable α] + {l : List (α × β)} + {k k' : α} (k_beq : k == k') + (distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) + (mem : k ∈ l.map Prod.fst) + {h} : + (ofList l).getKey k' h = k := + ExtDHashMap.Const.getKey_ofList_of_mem k_beq distinct mem + +theorem getKey!_ofList_of_contains_eq_false [EquivBEq α] [LawfulHashable α] + [Inhabited α] {l : List (α × β)} {k : α} + (contains_eq_false : (l.map Prod.fst).contains k = false) : + (ofList l).getKey! k = default := + ExtDHashMap.Const.getKey!_ofList_of_contains_eq_false contains_eq_false + +theorem getKey!_ofList_of_mem [EquivBEq α] [LawfulHashable α] [Inhabited α] + {l : List (α × β)} + {k k' : α} (k_beq : k == k') + (distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) + (mem : k ∈ l.map Prod.fst) : + (ofList l).getKey! k' = k := + ExtDHashMap.Const.getKey!_ofList_of_mem k_beq distinct mem + +theorem getKeyD_ofList_of_contains_eq_false [EquivBEq α] [LawfulHashable α] + {l : List (α × β)} {k fallback : α} + (contains_eq_false : (l.map Prod.fst).contains k = false) : + (ofList l).getKeyD k fallback = fallback := + ExtDHashMap.Const.getKeyD_ofList_of_contains_eq_false contains_eq_false + +theorem getKeyD_ofList_of_mem [EquivBEq α] [LawfulHashable α] + {l : List (α × β)} + {k k' fallback : α} (k_beq : k == k') + (distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) + (mem : k ∈ l.map Prod.fst) : + (ofList l).getKeyD k' fallback = k := + ExtDHashMap.Const.getKeyD_ofList_of_mem k_beq distinct mem + +theorem size_ofList [EquivBEq α] [LawfulHashable α] + {l : List (α × β)} (distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) : + (ofList l).size = l.length := + ExtDHashMap.Const.size_ofList distinct + +theorem size_ofList_le [EquivBEq α] [LawfulHashable α] + {l : List (α × β)} : + (ofList l).size ≤ l.length := + ExtDHashMap.Const.size_ofList_le + +@[simp] +theorem ofList_eq_empty_iff [EquivBEq α] [LawfulHashable α] {l : List (α × β)} : + ofList l = ∅ ↔ l = [] := + ext_iff.trans ExtDHashMap.Const.ofList_eq_empty_iff + +@[simp] +theorem unitOfList_nil [EquivBEq α] [LawfulHashable α] : + unitOfList ([] : List α) = ∅ := + ext ExtDHashMap.Const.unitOfList_nil + +@[simp] +theorem unitOfList_singleton [EquivBEq α] [LawfulHashable α] {k : α} : + unitOfList [k] = (∅ : ExtHashMap α Unit).insertIfNew k () := + ext ExtDHashMap.Const.unitOfList_singleton + +theorem unitOfList_cons [EquivBEq α] [LawfulHashable α] {hd : α} {tl : List α} : + unitOfList (hd :: tl) = + insertManyIfNewUnit ((∅ : ExtHashMap α Unit).insertIfNew hd ()) tl := + ext ExtDHashMap.Const.unitOfList_cons + +@[simp] +theorem contains_unitOfList [EquivBEq α] [LawfulHashable α] + {l : List α} {k : α} : + (unitOfList l).contains k = l.contains k := + ExtDHashMap.Const.contains_unitOfList + +@[simp] +theorem mem_unitOfList [EquivBEq α] [LawfulHashable α] + {l : List α} {k : α} : + k ∈ unitOfList l ↔ l.contains k := + ExtDHashMap.Const.mem_unitOfList + +@[simp] +theorem getElem?_unitOfList [EquivBEq α] [LawfulHashable α] + {l : List α} {k : α} : + (unitOfList l)[k]? = + if l.contains k then some () else none := + ExtDHashMap.Const.get?_unitOfList + +@[simp] +theorem getElem_unitOfList [EquivBEq α] [LawfulHashable α] + {l : List α} {k : α} {h} : + (unitOfList l)[k] = () := + rfl + +@[simp] +theorem getElem!_unitOfList [EquivBEq α] [LawfulHashable α] + {l : List α} {k : α} : + (unitOfList l)[k]! = () := + rfl + +@[simp] +theorem getD_unitOfList [EquivBEq α] [LawfulHashable α] + {l : List α} {k : α} {fallback : Unit} : + getD (unitOfList l) k fallback = () := + rfl + +theorem getKey?_unitOfList_of_contains_eq_false [EquivBEq α] [LawfulHashable α] + {l : List α} {k : α} (contains_eq_false : l.contains k = false) : + getKey? (unitOfList l) k = none := + ExtDHashMap.Const.getKey?_unitOfList_of_contains_eq_false contains_eq_false + +theorem getKey?_unitOfList_of_mem [EquivBEq α] [LawfulHashable α] + {l : List α} {k k' : α} (k_beq : k == k') + (distinct : l.Pairwise (fun a b => (a == b) = false)) (mem : k ∈ l) : + getKey? (unitOfList l) k' = some k := + ExtDHashMap.Const.getKey?_unitOfList_of_mem k_beq distinct mem + +theorem getKey_unitOfList_of_mem [EquivBEq α] [LawfulHashable α] + {l : List α} + {k k' : α} (k_beq : k == k') + (distinct : l.Pairwise (fun a b => (a == b) = false)) + (mem : k ∈ l) {h} : + getKey (unitOfList l) k' h = k := + ExtDHashMap.Const.getKey_unitOfList_of_mem k_beq distinct mem + +theorem getKey!_unitOfList_of_contains_eq_false [EquivBEq α] [LawfulHashable α] + [Inhabited α] {l : List α} {k : α} + (contains_eq_false : l.contains k = false) : + getKey! (unitOfList l) k = default := + ExtDHashMap.Const.getKey!_unitOfList_of_contains_eq_false contains_eq_false + +theorem getKey!_unitOfList_of_mem [EquivBEq α] [LawfulHashable α] + [Inhabited α] {l : List α} {k k' : α} (k_beq : k == k') + (distinct : l.Pairwise (fun a b => (a == b) = false)) + (mem : k ∈ l) : + getKey! (unitOfList l) k' = k := + ExtDHashMap.Const.getKey!_unitOfList_of_mem k_beq distinct mem + +theorem getKeyD_unitOfList_of_contains_eq_false [EquivBEq α] [LawfulHashable α] + {l : List α} {k fallback : α} + (contains_eq_false : l.contains k = false) : + getKeyD (unitOfList l) k fallback = fallback := + ExtDHashMap.Const.getKeyD_unitOfList_of_contains_eq_false contains_eq_false + +theorem getKeyD_unitOfList_of_mem [EquivBEq α] [LawfulHashable α] + {l : List α} {k k' fallback : α} (k_beq : k == k') + (distinct : l.Pairwise (fun a b => (a == b) = false)) + (mem : k ∈ l) : + getKeyD (unitOfList l) k' fallback = k := + ExtDHashMap.Const.getKeyD_unitOfList_of_mem k_beq distinct mem + +theorem size_unitOfList [EquivBEq α] [LawfulHashable α] + {l : List α} + (distinct : l.Pairwise (fun a b => (a == b) = false)) : + (unitOfList l).size = l.length := + ExtDHashMap.Const.size_unitOfList distinct + +theorem size_unitOfList_le [EquivBEq α] [LawfulHashable α] + {l : List α} : + (unitOfList l).size ≤ l.length := + ExtDHashMap.Const.size_unitOfList_le + +@[simp] +theorem unitOfList_eq_empty_iff [EquivBEq α] [LawfulHashable α] {l : List α} : + unitOfList l = ∅ ↔ l = [] := + ext_iff.trans ExtDHashMap.Const.unitOfList_eq_empty_iff + +end + +section Alter + +variable {m : ExtHashMap α β} + +theorem alter_eq_empty_iff_erase_eq_empty [EquivBEq α] [LawfulHashable α] {k : α} {f : Option β → Option β} : + alter m k f = ∅ ↔ m.erase k = ∅ ∧ f m[k]? = none := by + simpa only [ext_iff] using ExtDHashMap.Const.alter_eq_empty_iff_erase_eq_empty + +@[simp] +theorem alter_eq_empty_iff [EquivBEq α] [LawfulHashable α] {k : α} {f : Option β → Option β} : + alter m k f = ∅ ↔ (m = ∅ ∨ (m.size = 1 ∧ k ∈ m)) ∧ f m[k]? = none := by + simpa only [ext_iff] using ExtDHashMap.Const.alter_eq_empty_iff + +theorem contains_alter [EquivBEq α] [LawfulHashable α] {k k': α} {f : Option β → Option β} : + (alter m k f).contains k' = if k == k' then (f m[k]?).isSome else m.contains k' := + ExtDHashMap.Const.contains_alter + +theorem mem_alter [EquivBEq α] [LawfulHashable α] {k k': α} {f : Option β → Option β} : + k' ∈ alter m k f ↔ if k == k' then (f m[k]?).isSome = true else k' ∈ m := + ExtDHashMap.Const.mem_alter + +theorem mem_alter_of_beq [EquivBEq α] [LawfulHashable α] {k k': α} {f : Option β → Option β} + (h : k == k') : k' ∈ alter m k f ↔ (f m[k]?).isSome := + ExtDHashMap.Const.mem_alter_of_beq h + +@[simp] +theorem contains_alter_self [EquivBEq α] [LawfulHashable α] {k : α} {f : Option β → Option β} : + (alter m k f).contains k = (f m[k]?).isSome := + ExtDHashMap.Const.contains_alter_self + +@[simp] +theorem mem_alter_self [EquivBEq α] [LawfulHashable α] {k : α} {f : Option β → Option β} : + k ∈ alter m k f ↔ (f m[k]?).isSome := + ExtDHashMap.Const.mem_alter_self + +theorem contains_alter_of_beq_eq_false [EquivBEq α] [LawfulHashable α] {k k' : α} + {f : Option β → Option β} (h : (k == k') = false) : + (alter m k f).contains k' = m.contains k' := + ExtDHashMap.Const.contains_alter_of_beq_eq_false h + +theorem mem_alter_of_beq_eq_false [EquivBEq α] [LawfulHashable α] {k k' : α} + {f : Option β → Option β} (h : (k == k') = false) : k' ∈ alter m k f ↔ k' ∈ m := + ExtDHashMap.Const.mem_alter_of_beq_eq_false h + +theorem size_alter [EquivBEq α] [LawfulHashable α] {k : α} {f : Option β → Option β} : + (m.alter k f).size = + if k ∈ m ∧ (f m[k]?).isNone then + m.size - 1 + else if k ∉ m ∧ (f m[k]?).isSome then + m.size + 1 + else + m.size := + ExtDHashMap.Const.size_alter + +theorem size_alter_eq_add_one [EquivBEq α] [LawfulHashable α] {k : α} {f : Option β → Option β} + (h : k ∉ m) (h' : (f m[k]?).isSome) : + (alter m k f).size = m.size + 1 := + ExtDHashMap.Const.size_alter_eq_add_one h h' + +theorem size_alter_eq_sub_one [EquivBEq α] [LawfulHashable α] {k : α} {f : Option β → Option β} + (h : k ∈ m) (h' : (f m[k]?).isNone) : + (alter m k f).size = m.size - 1 := + ExtDHashMap.Const.size_alter_eq_sub_one h h' + +theorem size_alter_eq_self_of_not_mem [EquivBEq α] [LawfulHashable α] {k : α} {f : Option β → Option β} + (h : k ∉ m) (h' : (f m[k]?).isNone) : + (alter m k f).size = m.size := + ExtDHashMap.Const.size_alter_eq_self_of_not_mem h h' + +theorem size_alter_eq_self_of_mem [EquivBEq α] [LawfulHashable α] {k : α} {f : Option β → Option β} + (h : k ∈ m) (h' : (f m[k]?).isSome) : + (alter m k f).size = m.size := + ExtDHashMap.Const.size_alter_eq_self_of_mem h h' + +theorem size_alter_le_size [EquivBEq α] [LawfulHashable α] {k : α} {f : Option β → Option β} : + (alter m k f).size ≤ m.size + 1 := + ExtDHashMap.Const.size_alter_le_size + +theorem size_le_size_alter [EquivBEq α] [LawfulHashable α] {k : α} {f : Option β → Option β} : + m.size - 1 ≤ (alter m k f).size := + ExtDHashMap.Const.size_le_size_alter + +theorem getElem?_alter [EquivBEq α] [LawfulHashable α] {k k' : α} {f : Option β → Option β} : + (alter m k f)[k']? = + if k == k' then + f m[k]? + else + m[k']? := + ExtDHashMap.Const.get?_alter + +@[deprecated getElem?_alter (since := "2025-02-09")] +theorem get?_alter [EquivBEq α] [LawfulHashable α] {k k' : α} {f : Option β → Option β} : + get? (alter m k f) k' = + if k == k' then + f (get? m k) + else + get? m k' := + ExtDHashMap.Const.get?_alter + +@[simp] +theorem getElem?_alter_self [EquivBEq α] [LawfulHashable α] {k : α} {f : Option β → Option β} : + (alter m k f)[k]? = f m[k]? := + ExtDHashMap.Const.get?_alter_self + +@[deprecated getElem?_alter_self (since := "2025-02-09")] +theorem get?_alter_self [EquivBEq α] [LawfulHashable α] {k : α} {f : Option β → Option β} : + get? (alter m k f) k = f (get? m k) := + ExtDHashMap.Const.get?_alter_self + +theorem getElem_alter [EquivBEq α] [LawfulHashable α] {k k' : α} {f : Option β → Option β} + {h : k' ∈ alter m k f} : + (alter m k f)[k'] = + if heq : k == k' then + haveI h' : (f m[k]?).isSome := mem_alter_of_beq heq |>.mp h + f m[k]? |>.get h' + else + haveI h' : k' ∈ m := mem_alter_of_beq_eq_false (Bool.not_eq_true _ ▸ heq) |>.mp h + m[(k')]'h' := + ExtDHashMap.Const.get_alter (h := h) + +@[deprecated getElem_alter (since := "2025-02-09")] +theorem get_alter [EquivBEq α] [LawfulHashable α] {k k' : α} {f : Option β → Option β} + {h : k' ∈ alter m k f} : + get (alter m k f) k' h = + if heq : k == k' then + haveI h' : (f (get? m k)).isSome := mem_alter_of_beq heq |>.mp h + f (get? m k) |>.get h' + else + haveI h' : k' ∈ m := mem_alter_of_beq_eq_false (Bool.not_eq_true _ ▸ heq) |>.mp h + get m k' h' := + ExtDHashMap.Const.get_alter + +@[simp] +theorem getElem_alter_self [EquivBEq α] [LawfulHashable α] {k : α} {f : Option β → Option β} + {h : k ∈ alter m k f} : + haveI h' : (f m[k]?).isSome := mem_alter_self.mp h + (alter m k f)[k] = (f m[k]?).get h' := + ExtDHashMap.Const.get_alter_self (h := h) + +@[deprecated getElem_alter_self (since := "2025-02-09")] +theorem get_alter_self [EquivBEq α] [LawfulHashable α] {k : α} {f : Option β → Option β} + {h : k ∈ alter m k f} : + haveI h' : (f (get? m k)).isSome := mem_alter_self.mp h + get (alter m k f) k h = (f (get? m k)).get h' := + ExtDHashMap.Const.get_alter_self + +theorem getElem!_alter [EquivBEq α] [LawfulHashable α] {k k' : α} [Inhabited β] + {f : Option β → Option β} : (alter m k f)[k']! = + if k == k' then + f m[k]? |>.get! + else + m[k']! := + ExtDHashMap.Const.get!_alter + +@[deprecated getElem!_alter (since := "2025-02-09")] +theorem get!_alter [EquivBEq α] [LawfulHashable α] {k k' : α} [Inhabited β] + {f : Option β → Option β} : get! (alter m k f) k' = + if k == k' then + f (get? m k) |>.get! + else + get! m k' := + ExtDHashMap.Const.get!_alter + +@[simp] +theorem getElem!_alter_self [EquivBEq α] [LawfulHashable α] {k : α} [Inhabited β] + {f : Option β → Option β} : (alter m k f)[k]! = (f m[k]?).get! := + ExtDHashMap.Const.get!_alter_self + +@[deprecated getElem!_alter_self (since := "2025-02-09")] +theorem get!_alter_self [EquivBEq α] [LawfulHashable α] {k : α} [Inhabited β] + {f : Option β → Option β} : get! (alter m k f) k = (f (get? m k)).get! := + ExtDHashMap.Const.get!_alter_self + +theorem getD_alter [EquivBEq α] [LawfulHashable α] {k k' : α} {fallback : β} + {f : Option β → Option β} : + getD (alter m k f) k' fallback = + if k == k' then + f m[k]? |>.getD fallback + else + getD m k' fallback := + ExtDHashMap.Const.getD_alter + +@[simp] +theorem getD_alter_self [EquivBEq α] [LawfulHashable α] {k : α} {fallback : β} + {f : Option β → Option β} : + getD (alter m k f) k fallback = (f m[k]?).getD fallback := + ExtDHashMap.Const.getD_alter_self + +theorem getKey?_alter [EquivBEq α] [LawfulHashable α] {k k' : α} {f : Option β → Option β} : + (alter m k f).getKey? k' = + if k == k' then + if (f m[k]?).isSome then some k else none + else + m.getKey? k' := + ExtDHashMap.Const.getKey?_alter + +theorem getKey?_alter_self [EquivBEq α] [LawfulHashable α] {k : α} {f : Option β → Option β} : + (alter m k f).getKey? k = if (f m[k]?).isSome then some k else none := + ExtDHashMap.Const.getKey?_alter_self + +theorem getKey!_alter [EquivBEq α] [LawfulHashable α] [Inhabited α] {k k' : α} + {f : Option β → Option β} : (alter m k f).getKey! k' = + if k == k' then + if (f m[k]?).isSome then k else default + else + m.getKey! k' := + ExtDHashMap.Const.getKey!_alter + +theorem getKey!_alter_self [EquivBEq α] [LawfulHashable α] [Inhabited α] {k : α} + {f : Option β → Option β} : + (alter m k f).getKey! k = if (f m[k]?).isSome then k else default := + ExtDHashMap.Const.getKey!_alter_self + +theorem getKey_alter [EquivBEq α] [LawfulHashable α] [Inhabited α] {k k' : α} + {f : Option β → Option β} {h : k' ∈ alter m k f} : + (alter m k f).getKey k' h = + if heq : k == k' then + k + else + haveI h' : k' ∈ m := mem_alter_of_beq_eq_false (Bool.not_eq_true _ ▸ heq) |>.mp h + m.getKey k' h' := + ExtDHashMap.Const.getKey_alter + +@[simp] +theorem getKey_alter_self [EquivBEq α] [LawfulHashable α] [Inhabited α] {k : α} + {f : Option β → Option β} {h : k ∈ alter m k f} : + (alter m k f).getKey k h = k := + ExtDHashMap.Const.getKey_alter_self + +theorem getKeyD_alter [EquivBEq α] [LawfulHashable α] {k k' fallback : α} + {f : Option β → Option β} : + (alter m k f).getKeyD k' fallback = + if k == k' then + if (f m[k]?).isSome then k else fallback + else + m.getKeyD k' fallback := + ExtDHashMap.Const.getKeyD_alter + +theorem getKeyD_alter_self [EquivBEq α] [LawfulHashable α] [Inhabited α] {k fallback : α} + {f : Option β → Option β} : + (alter m k f).getKeyD k fallback = if (f m[k]?).isSome then k else fallback := + ExtDHashMap.Const.getKeyD_alter_self + +end Alter + +section Modify + +variable {m : ExtHashMap α β} + +@[simp] +theorem modify_eq_empty_iff [EquivBEq α] [LawfulHashable α] {k : α} {f : β → β} : + modify m k f = ∅ ↔ m = ∅ := by + simpa only [ext_iff] using ExtDHashMap.Const.modify_eq_empty_iff + +@[simp] +theorem contains_modify [EquivBEq α] [LawfulHashable α] {k k': α} {f : β → β} : + (modify m k f).contains k' = m.contains k' := + ExtDHashMap.Const.contains_modify + +@[simp] +theorem mem_modify [EquivBEq α] [LawfulHashable α] {k k': α} {f : β → β} : + k' ∈ modify m k f ↔ k' ∈ m := + ExtDHashMap.Const.mem_modify + +@[simp] +theorem size_modify [EquivBEq α] [LawfulHashable α] {k : α} {f : β → β} : + (modify m k f).size = m.size := + ExtDHashMap.Const.size_modify + +theorem getElem?_modify [EquivBEq α] [LawfulHashable α] {k k' : α} {f : β → β} : + (modify m k f)[k']? = + if k == k' then + m[k]?.map f + else + m[k']? := + ExtDHashMap.Const.get?_modify + +@[deprecated getElem?_modify (since := "2025-02-09")] +theorem get?_modify [EquivBEq α] [LawfulHashable α] {k k' : α} {f : β → β} : + get? (modify m k f) k' = + if k == k' then + get? m k |>.map f + else + get? m k' := + ExtDHashMap.Const.get?_modify + +@[simp] +theorem getElem?_modify_self [EquivBEq α] [LawfulHashable α] {k : α} {f : β → β} : + (modify m k f)[k]? = m[k]?.map f := + ExtDHashMap.Const.get?_modify_self + +@[deprecated getElem?_modify_self (since := "2025-02-09")] +theorem get?_modify_self [EquivBEq α] [LawfulHashable α] {k : α} {f : β → β} : + get? (modify m k f) k = (get? m k).map f := + ExtDHashMap.Const.get?_modify_self + +theorem getElem_modify [EquivBEq α] [LawfulHashable α] {k k' : α} {f : β → β} + {h : k' ∈ modify m k f} : + (modify m k f)[k'] = + if heq : k == k' then + haveI h' : k ∈ m := mem_congr heq |>.mpr <| mem_modify.mp h + f m[k] + else + haveI h' : k' ∈ m := mem_modify.mp h + m[k'] := + ExtDHashMap.Const.get_modify (h := h) + +@[deprecated getElem_modify (since := "2025-02-09")] +theorem get_modify [EquivBEq α] [LawfulHashable α] {k k' : α} {f : β → β} + {h : k' ∈ modify m k f} : + get (modify m k f) k' h = + if heq : k == k' then + haveI h' : k ∈ m := mem_congr heq |>.mpr <| mem_modify.mp h + f (get m k h') + else + haveI h' : k' ∈ m := mem_modify.mp h + get m k' h' := + ExtDHashMap.Const.get_modify + +@[simp] +theorem getElem_modify_self [EquivBEq α] [LawfulHashable α] {k : α} {f : β → β} + {h : k ∈ modify m k f} : + haveI h' : k ∈ m := mem_modify.mp h + (modify m k f)[k] = f m[k] := + ExtDHashMap.Const.get_modify_self (h := h) + +@[deprecated getElem_modify_self (since := "2025-02-09")] +theorem get_modify_self [EquivBEq α] [LawfulHashable α] {k : α} {f : β → β} + {h : k ∈ modify m k f} : + haveI h' : k ∈ m := mem_modify.mp h + get (modify m k f) k h = f (get m k h') := + ExtDHashMap.Const.get_modify_self + +theorem getElem!_modify [EquivBEq α] [LawfulHashable α] {k k' : α} [Inhabited β] {f : β → β} : + (modify m k f)[k']! = + if k == k' then + m[k]?.map f |>.get! + else + m[k']! := + ExtDHashMap.Const.get!_modify + +@[deprecated getElem!_modify (since := "2025-02-09")] +theorem get!_modify [EquivBEq α] [LawfulHashable α] {k k' : α} [Inhabited β] {f : β → β} : + get! (modify m k f) k' = + if k == k' then + get? m k |>.map f |>.get! + else + get! m k' := + ExtDHashMap.Const.get!_modify + +@[simp] +theorem getElem!_modify_self [EquivBEq α] [LawfulHashable α] {k : α} [Inhabited β] {f : β → β} : + (modify m k f)[k]! = (m[k]?.map f).get! := + ExtDHashMap.Const.get!_modify_self + +@[deprecated getElem!_modify_self (since := "2025-02-09")] +theorem get!_modify_self [EquivBEq α] [LawfulHashable α] {k : α} [Inhabited β] {f : β → β} : + get! (modify m k f) k = ((get? m k).map f).get! := + ExtDHashMap.Const.get!_modify_self + +theorem getD_modify [EquivBEq α] [LawfulHashable α] {k k' : α} {fallback : β} {f : β → β} : + getD (modify m k f) k' fallback = + if k == k' then + m[k]?.map f |>.getD fallback + else + getD m k' fallback := + ExtDHashMap.Const.getD_modify + +@[simp] +theorem getD_modify_self [EquivBEq α] [LawfulHashable α] {k : α} {fallback : β} {f : β → β} : + getD (modify m k f) k fallback = (m[k]?.map f).getD fallback := + ExtDHashMap.Const.getD_modify_self + +theorem getKey?_modify [EquivBEq α] [LawfulHashable α] {k k' : α} {f : β → β} : + (modify m k f).getKey? k' = + if k == k' then + if k ∈ m then some k else none + else + m.getKey? k' := + ExtDHashMap.Const.getKey?_modify + +theorem getKey?_modify_self [EquivBEq α] [LawfulHashable α] {k : α} {f : β → β} : + (modify m k f).getKey? k = if k ∈ m then some k else none := + ExtDHashMap.Const.getKey?_modify_self + +theorem getKey!_modify [EquivBEq α] [LawfulHashable α] [Inhabited α] {k k' : α} {f : β → β} : + (modify m k f).getKey! k' = + if k == k' then + if k ∈ m then k else default + else + m.getKey! k' := + ExtDHashMap.Const.getKey!_modify + +theorem getKey!_modify_self [EquivBEq α] [LawfulHashable α] [Inhabited α] {k : α} {f : β → β} : + (modify m k f).getKey! k = if k ∈ m then k else default := + ExtDHashMap.Const.getKey!_modify_self + +theorem getKey_modify [EquivBEq α] [LawfulHashable α] [Inhabited α] {k k' : α} {f : β → β} + {h : k' ∈ modify m k f} : + (modify m k f).getKey k' h = + if k == k' then + k + else + haveI h' : k' ∈ m := mem_modify.mp h + m.getKey k' h' := + ExtDHashMap.Const.getKey_modify + +@[simp] +theorem getKey_modify_self [EquivBEq α] [LawfulHashable α] [Inhabited α] {k : α} {f : β → β} + {h : k ∈ modify m k f} : (modify m k f).getKey k h = k := + ExtDHashMap.Const.getKey_modify_self + +theorem getKeyD_modify [EquivBEq α] [LawfulHashable α] {k k' fallback : α} {f : β → β} : + (modify m k f).getKeyD k' fallback = + if k == k' then + if k ∈ m then k else fallback + else + m.getKeyD k' fallback := + ExtDHashMap.Const.getKeyD_modify + +theorem getKeyD_modify_self [EquivBEq α] [LawfulHashable α] [Inhabited α] {k fallback : α} + {f : β → β} : (modify m k f).getKeyD k fallback = if k ∈ m then k else fallback := + ExtDHashMap.Const.getKeyD_modify_self + +end Modify + +section Ext + +variable {m₁ m₂ : ExtHashMap α β} + +@[ext 900] +theorem ext_getKey_getElem? [EquivBEq α] [LawfulHashable α] + {m₁ m₂ : ExtHashMap α β} + (hk : ∀ k hk hk', m₁.getKey k hk = m₂.getKey k hk') + (hv : ∀ k : α, m₁[k]? = m₂[k]?) : m₁ = m₂ := + ext (ExtDHashMap.Const.ext_getKey_get? hk hv) + +@[ext] +theorem ext_getElem? [LawfulBEq α] {m₁ m₂ : ExtHashMap α β} + (h : ∀ k : α, m₁[k]? = m₂[k]?) : m₁ = m₂ := + ext (ExtDHashMap.Const.ext_get? h) + +theorem ext_getKey?_unit [EquivBEq α] [LawfulHashable α] + {m₁ m₂ : ExtHashMap α Unit} (h : ∀ k, m₁.getKey? k = m₂.getKey? k) : m₁ = m₂ := + ext (ExtDHashMap.Const.ext_getKey?_unit h) + +theorem ext_contains_unit [LawfulBEq α] + {m₁ m₂ : ExtHashMap α Unit} (h : ∀ k, m₁.contains k = m₂.contains k) : m₁ = m₂ := + ext (ExtDHashMap.Const.ext_contains_unit h) + +theorem ext_mem_unit [LawfulBEq α] + {m₁ m₂ : ExtHashMap α Unit} (h : ∀ k, k ∈ m₁ ↔ k ∈ m₂) : m₁ = m₂ := + ext (ExtDHashMap.Const.ext_mem_unit h) + +end Ext + +section filterMap + +variable {m : ExtHashMap α β} + +theorem filterMap_eq_empty_iff [EquivBEq α] [LawfulHashable α] {f : α → β → Option γ} : + m.filterMap f = ∅ ↔ ∀ k h, f (m.getKey k h) (m[k]'h) = none := + ext_iff.trans ExtDHashMap.Const.filterMap_eq_empty_iff + +theorem mem_filterMap [EquivBEq α] [LawfulHashable α] + {f : α → β → Option γ} {k : α} : + k ∈ m.filterMap f ↔ ∃ h, (f (m.getKey k h) m[k]).isSome := + ExtDHashMap.Const.mem_filterMap + +theorem contains_of_contains_filterMap [EquivBEq α] [LawfulHashable α] + {f : α → β → Option γ} {k : α} : + (m.filterMap f).contains k = true → m.contains k = true := + ExtDHashMap.contains_of_contains_filterMap + +theorem mem_of_mem_filterMap [EquivBEq α] [LawfulHashable α] + {f : α → β → Option γ} {k : α} : + k ∈ m.filterMap f → k ∈ m := + ExtDHashMap.mem_of_mem_filterMap + +theorem size_filterMap_le_size [EquivBEq α] [LawfulHashable α] + {f : α → β → Option γ} : + (m.filterMap f).size ≤ m.size := + ExtDHashMap.size_filterMap_le_size + +theorem size_filterMap_eq_size_iff [EquivBEq α] [LawfulHashable α] + {f : α → β → Option γ} : + (m.filterMap f).size = m.size ↔ ∀ k h, (f (m.getKey k h) m[k]).isSome := + ExtDHashMap.Const.size_filterMap_eq_size_iff + +theorem getElem?_filterMap [EquivBEq α] [LawfulHashable α] + {f : α → β → Option γ} {k : α} : + (m.filterMap f)[k]? = m[k]?.pbind (fun x h' => + f (m.getKey k (mem_iff_isSome_getElem?.mpr (Option.isSome_of_eq_some h'))) x) := + ExtDHashMap.Const.get?_filterMap + +theorem getElem?_filterMap_of_getKey?_eq_some [EquivBEq α] [LawfulHashable α] + {f : α → β → Option γ} {k k' : α} (h : m.getKey? k = some k') : + (m.filterMap f)[k]? = m[k]?.bind (f k') := + ExtDHashMap.Const.get?_filterMap_of_getKey?_eq_some h + +theorem isSome_apply_of_mem_filterMap [EquivBEq α] [LawfulHashable α] + {f : α → β → Option γ} {k : α} : + ∀ (h : k ∈ m.filterMap f), + (f (m.getKey k (mem_of_mem_filterMap h)) + (m[k]'(mem_of_mem_filterMap h))).isSome := + ExtDHashMap.Const.isSome_apply_of_mem_filterMap + +@[simp] +theorem getElem_filterMap [EquivBEq α] [LawfulHashable α] + {f : α → β → Option γ} {k : α} {h} : + (m.filterMap f)[k]'h = + (f (m.getKey k (mem_of_mem_filterMap h)) + (m[k]'(mem_of_mem_filterMap h))).get + (isSome_apply_of_mem_filterMap h) := + ExtDHashMap.Const.get_filterMap (h := h) + +theorem getElem!_filterMap [EquivBEq α] [LawfulHashable α] [Inhabited γ] + {f : α → β → Option γ} {k : α} : + (m.filterMap f)[k]! = + (m[k]?.pbind (fun x h' => + f (m.getKey k (mem_iff_isSome_getElem?.mpr (Option.isSome_of_eq_some h'))) x)).get! := + ExtDHashMap.Const.get!_filterMap + +theorem getElem!_filterMap_of_getKey?_eq_some [EquivBEq α] [LawfulHashable α] [Inhabited γ] + {f : α → β → Option γ} {k k' : α} (h : m.getKey? k = some k') : + (m.filterMap f)[k]! = (m[k]?.bind (f k')).get! := + ExtDHashMap.Const.get!_filterMap_of_getKey?_eq_some h + +theorem getD_filterMap [EquivBEq α] [LawfulHashable α] + {f : α → β → Option γ} {k : α} {fallback : γ} : + (m.filterMap f).getD k fallback = + (m[k]?.pbind (fun x h' => + f (m.getKey k (mem_iff_isSome_getElem?.mpr (Option.isSome_of_eq_some h'))) x)).getD fallback := + ExtDHashMap.Const.getD_filterMap + +theorem getD_filterMap_of_getKey?_eq_some [EquivBEq α] [LawfulHashable α] + {f : α → β → Option γ} {k k' : α} {fallback : γ} (h : m.getKey? k = some k') : + (m.filterMap f).getD k fallback = (m[k]?.bind (f k')).getD fallback := + ExtDHashMap.Const.getD_filterMap_of_getKey?_eq_some h + +theorem getKey?_filterMap [EquivBEq α] [LawfulHashable α] + {f : α → β → Option γ} {k : α} : + (m.filterMap f).getKey? k = + (m.getKey? k).pfilter (fun x h' => + (f x (m[x]'(mem_of_getKey?_eq_some h'))).isSome) := + ExtDHashMap.Const.getKey?_filterMap + +@[simp] +theorem getKey_filterMap [EquivBEq α] [LawfulHashable α] + {f : α → β → Option γ} {k : α} {h'} : + (m.filterMap f).getKey k h' = m.getKey k (mem_of_mem_filterMap h') := + ExtDHashMap.getKey_filterMap + +theorem getKey!_filterMap [EquivBEq α] [LawfulHashable α] [Inhabited α] + {f : α → β → Option γ} {k : α} : + (m.filterMap f).getKey! k = + ((m.getKey? k).pfilter (fun x h' => + (f x (m[x]'(mem_of_getKey?_eq_some h'))).isSome)).get! := + ExtDHashMap.Const.getKey!_filterMap + +theorem getKeyD_filterMap [EquivBEq α] [LawfulHashable α] + {f : α → β → Option γ} {k fallback : α} : + (m.filterMap f).getKeyD k fallback = + ((m.getKey? k).pfilter (fun x h' => + (f x (m[x]'(mem_of_getKey?_eq_some h'))).isSome)).getD fallback := + ExtDHashMap.Const.getKeyD_filterMap + +end filterMap + +section filter + +variable {m : ExtHashMap α β} + +theorem filterMap_eq_filter [EquivBEq α] [LawfulHashable α] {f : α → β → Bool} : + (m.filterMap (fun k => Option.guard (fun v => f k v))) = m.filter f := + ext ExtDHashMap.filterMap_eq_filter + +theorem filter_eq_empty_iff [EquivBEq α] [LawfulHashable α] {f : α → β → Bool} : + m.filter f = ∅ ↔ ∀ k h, f (m.getKey k h) (m[k]'h) = false := + ext_iff.trans ExtDHashMap.Const.filter_eq_empty_iff + +theorem mem_filter [EquivBEq α] [LawfulHashable α] + {f : α → β → Bool} {k : α} : + k ∈ m.filter f ↔ ∃ (h' : k ∈ m), f (m.getKey k h') m[k] := + ExtDHashMap.Const.mem_filter + +theorem contains_of_contains_filter [EquivBEq α] [LawfulHashable α] + {f : α → β → Bool} {k : α} : + (m.filter f).contains k = true → m.contains k = true := + ExtDHashMap.contains_of_contains_filter + +theorem mem_of_mem_filter [EquivBEq α] [LawfulHashable α] + {f : α → β → Bool} {k : α} : + k ∈ m.filter f → k ∈ m := + ExtDHashMap.mem_of_mem_filter + +theorem size_filter_le_size [EquivBEq α] [LawfulHashable α] + {f : α → β → Bool} : + (m.filter f).size ≤ m.size := + ExtDHashMap.size_filter_le_size + +theorem size_filter_eq_size_iff [EquivBEq α] [LawfulHashable α] + {f : α → β → Bool} : + (m.filter f).size = m.size ↔ ∀ k h, f (m.getKey k h) (m.get k h) := + ExtDHashMap.Const.size_filter_eq_size_iff + +theorem filter_eq_self_iff [EquivBEq α] [LawfulHashable α] + {f : α → β → Bool} : + m.filter f = m ↔ ∀ k h, f (m.getKey k h) (m.get k h) := + ext_iff.trans ExtDHashMap.Const.filter_eq_self_iff + +theorem getElem?_filter [EquivBEq α] [LawfulHashable α] + {f : α → β → Bool} {k : α} : + (m.filter f)[k]? = m[k]?.pfilter (fun x h' => + f (m.getKey k (mem_iff_isSome_getElem?.mpr (Option.isSome_of_eq_some h'))) x) := + ExtDHashMap.Const.get?_filter + +theorem getElem?_filter_of_getKey?_eq_some [EquivBEq α] [LawfulHashable α] + {f : α → β → Bool} {k k' : α} : + m.getKey? k = some k' → + (m.filter f)[k]? = m[k]?.filter (fun x => f k' x) := + ExtDHashMap.Const.get?_filter_of_getKey?_eq_some + +@[simp] +theorem getElem_filter [EquivBEq α] [LawfulHashable α] + {f : α → β → Bool} {k : α} {h'} : + (m.filter f)[k]'(h') = m[k]'(mem_of_mem_filter h') := + ExtDHashMap.Const.get_filter (h' := h') + +theorem getElem!_filter [EquivBEq α] [LawfulHashable α] [Inhabited β] + {f : α → β → Bool} {k : α} : + (m.filter f)[k]! = + (m[k]?.pfilter (fun x h' => + f (m.getKey k (mem_iff_isSome_getElem?.mpr (Option.isSome_of_eq_some h'))) x)).get! := + ExtDHashMap.Const.get!_filter + +theorem getElem!_filter_of_getKey?_eq_some [EquivBEq α] [LawfulHashable α] [Inhabited β] + {f : α → β → Bool} {k k' : α} : + m.getKey? k = some k' → + (m.filter f)[k]! = (m[k]?.filter (f k')).get! := + ExtDHashMap.Const.get!_filter_of_getKey?_eq_some + +theorem getD_filter [EquivBEq α] [LawfulHashable α] + {f : α → β → Bool} {k : α} {fallback : β} : + (m.filter f).getD k fallback = (m[k]?.pfilter (fun x h' => + f (m.getKey k (mem_iff_isSome_getElem?.mpr (Option.isSome_of_eq_some h'))) x)).getD fallback := + ExtDHashMap.Const.getD_filter + +theorem getD_filter_of_getKey?_eq_some [EquivBEq α] [LawfulHashable α] + {f : α → β → Bool} {k k' : α} {fallback : β} : + m.getKey? k = some k' → + (m.filter f).getD k fallback = + (m[k]?.filter (fun x => f k' x)).getD fallback := + ExtDHashMap.Const.getD_filter_of_getKey?_eq_some + +theorem getKey?_filter [EquivBEq α] [LawfulHashable α] + {f : α → β → Bool} {k : α} : + (m.filter f).getKey? k = + (m.getKey? k).pfilter (fun x h' => + (f x (m[x]'(mem_of_getKey?_eq_some h')))) := + ExtDHashMap.Const.getKey?_filter + +theorem getKey?_filter_key [EquivBEq α] [LawfulHashable α] + {f : α → Bool} {k : α} : + (m.filter fun k _ => f k).getKey? k = (m.getKey? k).filter f := + ExtDHashMap.getKey?_filter_key + +@[simp] +theorem getKey_filter [EquivBEq α] [LawfulHashable α] + {f : α → β → Bool} {k : α} {h'} : + (m.filter f).getKey k h' = m.getKey k (mem_of_mem_filter h') := + ExtDHashMap.getKey_filter + +theorem getKey!_filter [EquivBEq α] [LawfulHashable α] [Inhabited α] + {f : α → β → Bool} {k : α} : + (m.filter f).getKey! k = + ((m.getKey? k).pfilter (fun x h' => + (f x (m[x]'(mem_of_getKey?_eq_some h'))))).get! := + ExtDHashMap.Const.getKey!_filter + +theorem getKey!_filter_key [EquivBEq α] [LawfulHashable α] [Inhabited α] + {f : α → Bool} {k : α} : + (m.filter fun k _ => f k).getKey! k = ((m.getKey? k).filter f).get! := + ExtDHashMap.getKey!_filter_key + +theorem getKeyD_filter [EquivBEq α] [LawfulHashable α] + {f : α → β → Bool} {k fallback : α} : + (m.filter f).getKeyD k fallback = + ((m.getKey? k).pfilter (fun x h' => + (f x (m[x]'(mem_of_getKey?_eq_some h'))))).getD fallback := + ExtDHashMap.Const.getKeyD_filter + +theorem getKeyD_filter_key [EquivBEq α] [LawfulHashable α] + {f : α → Bool} {k fallback : α} : + (m.filter fun k _ => f k).getKeyD k fallback = ((m.getKey? k).filter f).getD fallback := + ExtDHashMap.getKeyD_filter_key + +end filter + +section map + +variable {m : ExtHashMap α β} + +@[simp] +theorem map_id_fun [EquivBEq α] [LawfulHashable α] : m.map (fun _ v => v) = m := + ext ExtDHashMap.map_id_fun + +@[simp] +theorem map_map [EquivBEq α] [LawfulHashable α] {f : α → β → γ} {g : α → γ → δ} : + (m.map f).map g = m.map fun k v => g k (f k v) := + ext ExtDHashMap.map_map + +theorem filterMap_equiv_map [EquivBEq α] [LawfulHashable α] + {f : α → β → γ} : + (m.filterMap (fun k v => some (f k v))) = m.map f := + ext ExtDHashMap.filterMap_eq_map + +@[simp] +theorem map_eq_empty_iff [EquivBEq α] [LawfulHashable α] {f : α → β → γ} : + m.map f = ∅ ↔ m = ∅ := by + simpa only [ext_iff] using ExtDHashMap.map_eq_empty_iff + +@[simp] +theorem contains_map [EquivBEq α] [LawfulHashable α] + {f : α → β → γ} {k : α} : + (m.map f).contains k = m.contains k := + ExtDHashMap.contains_map + +theorem contains_of_contains_map [EquivBEq α] [LawfulHashable α] + {f : α → β → γ} {k : α} : + (m.map f).contains k = true → m.contains k = true := + ExtDHashMap.contains_of_contains_map + +@[simp] +theorem mem_map [EquivBEq α] [LawfulHashable α] + {f : α → β → γ} {k : α} : + k ∈ m.map f ↔ k ∈ m := by + simp only [mem_iff_contains, contains_map] + +theorem mem_of_mem_map [EquivBEq α] [LawfulHashable α] + {f : α → β → γ} {k : α} : + k ∈ m.map f → k ∈ m := + ExtDHashMap.contains_of_contains_map + +@[simp] +theorem size_map [EquivBEq α] [LawfulHashable α] + {f : α → β → γ} : + (m.map f).size = m.size := + ExtDHashMap.size_map + +theorem getElem?_map [EquivBEq α] [LawfulHashable α] + {f : α → β → γ} {k : α} : + (m.map f)[k]? = m[k]?.pmap (fun v h' => f (m.getKey k h') v) + (fun _ h' => mem_iff_isSome_getElem?.mpr (Option.isSome_of_eq_some h')) := + ExtDHashMap.Const.get?_map + +theorem getElem?_map_of_getKey?_eq_some [EquivBEq α] [LawfulHashable α] + {f : α → β → γ} {k k' : α} (h : m.getKey? k = some k') : + (m.map f)[k]? = m[k]?.map (f k') := + ExtDHashMap.Const.get?_map_of_getKey?_eq_some h + +@[simp] +theorem getElem_map [EquivBEq α] [LawfulHashable α] + {f : α → β → γ} {k : α} {h'} : + (m.map f)[k]'(h') = + f (m.getKey k (mem_of_mem_map h')) (m[k]'(mem_of_mem_map h')) := + ExtDHashMap.Const.get_map (h' := h') + +theorem getElem!_map [EquivBEq α] [LawfulHashable α] [Inhabited γ] + {f : α → β → γ} {k : α} : + (m.map f)[k]! = + (m[k]?.pmap (fun v h => f (m.getKey k h) v) + (fun _ h' => mem_iff_isSome_getElem?.mpr (Option.isSome_of_mem h'))).get! := + ExtDHashMap.Const.get!_map + +theorem getElem!_map_of_getKey?_eq_some [EquivBEq α] [LawfulHashable α] [Inhabited γ] + {f : α → β → γ} {k k' : α} (h : m.getKey? k = some k') : + (m.map f)[k]! = (m[k]?.map (f k')).get! := + ExtDHashMap.Const.get!_map_of_getKey?_eq_some h + +theorem getD_map [EquivBEq α] [LawfulHashable α] + {f : α → β → γ} {k : α} {fallback : γ} : + (m.map f).getD k fallback = + (m[k]?.pmap (fun v h => f (m.getKey k h) v) + (fun _ h' => mem_iff_isSome_getElem?.mpr (Option.isSome_of_eq_some h'))).getD fallback := + ExtDHashMap.Const.getD_map + +theorem getD_map_of_getKey?_eq_some [EquivBEq α] [LawfulHashable α] [Inhabited γ] + {f : α → β → γ} {k k' : α} {fallback : γ} (h : m.getKey? k = some k') : + (m.map f).getD k fallback = (m[k]?.map (f k')).getD fallback := + ExtDHashMap.Const.getD_map_of_getKey?_eq_some h + +@[simp] +theorem getKey?_map [EquivBEq α] [LawfulHashable α] + {f : α → β → γ} {k : α} : + (m.map f).getKey? k = m.getKey? k := + ExtDHashMap.getKey?_map + +@[simp] +theorem getKey_map [EquivBEq α] [LawfulHashable α] + {f : α → β → γ} {k : α} {h'} : + (m.map f).getKey k h' = m.getKey k (mem_of_mem_map h') := + ExtDHashMap.getKey_map + +@[simp] +theorem getKey!_map [EquivBEq α] [LawfulHashable α] [Inhabited α] + {f : α → β → γ} {k : α} : + (m.map f).getKey! k = m.getKey! k := + ExtDHashMap.getKey!_map + +@[simp] +theorem getKeyD_map [EquivBEq α] [LawfulHashable α] + {f : α → β → γ} {k fallback : α} : + (m.map f).getKeyD k fallback = m.getKeyD k fallback := + ExtDHashMap.getKeyD_map + +end map + +end Std.ExtHashMap diff --git a/src/Std/Data/ExtHashSet.lean b/src/Std/Data/ExtHashSet.lean new file mode 100644 index 0000000000..ef3e2ff1a0 --- /dev/null +++ b/src/Std/Data/ExtHashSet.lean @@ -0,0 +1,8 @@ +/- +Copyright (c) 2025 Robin Arnez. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Robin Arnez +-/ +prelude +import Std.Data.ExtHashSet.Basic +import Std.Data.ExtHashSet.Lemmas diff --git a/src/Std/Data/ExtHashSet/Basic.lean b/src/Std/Data/ExtHashSet/Basic.lean new file mode 100644 index 0000000000..f74708fa06 --- /dev/null +++ b/src/Std/Data/ExtHashSet/Basic.lean @@ -0,0 +1,202 @@ +/- +Copyright (c) 2025 Robin Arnez. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Robin Arnez +-/ +prelude +import Std.Data.ExtHashMap.Basic + +/-! +# Extensional hash sets + +This module develops the type `Std.ExtHashSet` of extensional hash sets. + +Lemmas about the operations on `Std.ExtHashSet` are available in the +module `Std.Data.ExtHashSet.Lemmas`. +-/ + +set_option linter.missingDocs true +set_option autoImplicit false + +universe u v + +variable {α : Type u} {_ : BEq α} {_ : Hashable α} + +namespace Std + +/-- +Hash sets. + +This is a simple separate-chaining hash table. The data of the hash set consists of a cached size +and an array of buckets, where each bucket is a linked list of keys. The number of buckets +is always a power of two. The hash set doubles its size upon inserting an element such that the +number of elements is more than 75% of the number of buckets. + +The hash table is backed by an `Array`. Users should make sure that the hash set is used linearly to +avoid expensive copies. + +The hash set uses `==` (provided by the `BEq` typeclass) to compare elements and `hash` (provided by +the `Hashable` typeclass) to hash them. To ensure that the operations behave as expected, `==` +should be an equivalence relation and `a == b` should imply `hash a = hash b` (see also the +`EquivBEq` and `LawfulHashable` typeclasses). Both of these conditions are automatic if the BEq +instance is lawful, i.e., if `a == b` implies `a = b`. + +In contrast to regular hash sets, `Std.ExtHashSet` offers several extensionality lemmas +and therefore has more lemmas about equality of hash maps. This however also makes it lose the +ability to iterate freely over hash sets. + +These hash sets contain a bundled well-formedness invariant, which means that they cannot +be used in nested inductive types. For these use cases, `Std.HashSet.Raw` and +`Std.HashSet.Raw.WF` unbundle the invariant from the hash set. When in doubt, prefer +`HashSet` or `ExtHashSet` over `HashSet.Raw`. +-/ +structure ExtHashSet (α : Type u) [BEq α] [Hashable α] where + /-- Internal implementation detail of the hash set. -/ + inner : ExtHashMap α Unit + +namespace ExtHashSet + +/-- +Creates a new empty hash set. The optional parameter `capacity` can be supplied to presize the +set so that it can hold the given number of elements without reallocating. It is also possible to +use the empty collection notations `∅` and `{}` to create an empty hash set with the default +capacity. +-/ +@[inline] def emptyWithCapacity [BEq α] [Hashable α] (capacity := 8) : ExtHashSet α := + ⟨ExtHashMap.emptyWithCapacity capacity⟩ + +instance [BEq α] [Hashable α] : EmptyCollection (ExtHashSet α) where + emptyCollection := emptyWithCapacity + +instance [BEq α] [Hashable α] : Inhabited (ExtHashSet α) where + default := ∅ + +/-- +Inserts the given element into the set. If the hash set already contains an element that is +equal (with regard to `==`) to the given element, then the hash set is returned unchanged. + +Note: this non-replacement behavior is true for `ExtHashSet` and `ExtHashSet.Raw`. +The `insert` function on `ExtHashMap`, `DExtHashMap`, `ExtHashMap.Raw` and `DExtHashMap.Raw` behaves +differently: it will overwrite an existing mapping. +-/ +@[inline] def insert [EquivBEq α] [LawfulHashable α] (m : ExtHashSet α) (a : α) : ExtHashSet α := + ⟨m.inner.insertIfNew a ()⟩ + +instance [EquivBEq α] [LawfulHashable α] : Singleton α (ExtHashSet α) where + singleton a := (∅ : ExtHashSet α).insert a + +instance [EquivBEq α] [LawfulHashable α] : Insert α (ExtHashSet α) where + insert a s := s.insert a + +/-- +Checks whether an element is present in a set and inserts the element if it was not found. +If the hash set already contains an element that is equal (with regard to `==`) to the given +element, then the hash set is returned unchanged. + +Equivalent to (but potentially faster than) calling `contains` followed by `insert`. +-/ +@[inline] +def containsThenInsert [EquivBEq α] [LawfulHashable α] (m : ExtHashSet α) + (a : α) : Bool × ExtHashSet α := + let ⟨replaced, r⟩ := m.inner.containsThenInsertIfNew a () + ⟨replaced, ⟨r⟩⟩ + +/-- +Returns `true` if the given key is present in the set. There is also a `Prop`-valued version of +this: `a ∈ m` is equivalent to `m.contains a = true`. + +Observe that this is different behavior than for lists: for lists, `∈` uses `=` and `contains` use +`==` for comparisons, while for hash sets, both use `==`. +-/ +@[inline] def contains [EquivBEq α] [LawfulHashable α] (m : ExtHashSet α) (a : α) : Bool := + m.inner.contains a + +instance [BEq α] [Hashable α] [EquivBEq α] [LawfulHashable α] : Membership α (ExtHashSet α) where + mem m a := a ∈ m.inner + +instance [BEq α] [Hashable α] [EquivBEq α] [LawfulHashable α] + {m : ExtHashSet α} {a : α} : Decidable (a ∈ m) := + inferInstanceAs (Decidable (a ∈ m.inner)) + +/-- Removes the element if it exists. -/ +@[inline] def erase [EquivBEq α] [LawfulHashable α] (m : ExtHashSet α) (a : α) : ExtHashSet α := + ⟨m.inner.erase a⟩ + +/-- The number of elements present in the set -/ +@[inline] def size [EquivBEq α] [LawfulHashable α] (m : ExtHashSet α) : Nat := + m.inner.size + +/-- +Checks if given key is contained and returns the key if it is, otherwise `none`. +The result in the `some` case is guaranteed to be pointer equal to the key in the set. +-/ +@[inline] def get? [EquivBEq α] [LawfulHashable α] (m : ExtHashSet α) (a : α) : Option α := + m.inner.getKey? a + +/-- +Retrieves the key from the set that matches `a`. Ensures that such a key exists by requiring a proof +of `a ∈ m`. The result is guaranteed to be pointer equal to the key in the set. +-/ +@[inline] def get [EquivBEq α] [LawfulHashable α] + (m : ExtHashSet α) (a : α) (h : a ∈ m) : α := + m.inner.getKey a h + +/-- +Checks if given key is contained and returns the key if it is, otherwise `fallback`. +If they key is contained the result is guaranteed to be pointer equal to the key in the set. +-/ +@[inline] def getD [EquivBEq α] [LawfulHashable α] (m : ExtHashSet α) (a : α) (fallback : α) : α := + m.inner.getKeyD a fallback + +/-- +Checks if given key is contained and returns the key if it is, otherwise panics. +If no panic occurs the result is guaranteed to be pointer equal to the key in the set. +-/ +@[inline] def get! [EquivBEq α] [LawfulHashable α] [Inhabited α] (m : ExtHashSet α) (a : α) : α := + m.inner.getKey! a + +/-- +Returns `true` if the hash set contains no elements. + +Note that if your `BEq` instance is not reflexive or your `Hashable` instance is not +lawful, then it is possible that this function returns `false` even though `m.contains a = false` +for all `a`. +-/ +@[inline] def isEmpty [EquivBEq α] [LawfulHashable α] (m : ExtHashSet α) : Bool := + m.inner.isEmpty + +/-- +Creates a hash set from a list of elements. Note that unlike repeatedly calling `insert`, if the +collection contains multiple elements that are equal (with regard to `==`), then the last element +in the collection will be present in the returned hash set. +-/ +@[inline] def ofList [BEq α] [Hashable α] (l : List α) : ExtHashSet α := + ⟨ExtHashMap.unitOfList l⟩ + +/-- Removes all elements from the hash set for which the given function returns `false`. -/ +@[inline] def filter [EquivBEq α] [LawfulHashable α] (f : α → Bool) (m : ExtHashSet α) : ExtHashSet α := + ⟨m.inner.filter fun a _ => f a⟩ + +/-- +Inserts multiple mappings into the hash set by iterating over the given collection and calling +`insert`. If the same key appears multiple times, the first occurrence takes precedence. + +Note: this precedence behavior is true for `ExtHashSet` and `ExtHashSet.Raw`. The `insertMany` function on +`ExtHashMap`, `DExtHashMap`, `ExtHashMap.Raw` and `DExtHashMap.Raw` behaves differently: it will prefer the last +appearance. +-/ +@[inline] def insertMany [EquivBEq α] [LawfulHashable α] {ρ : Type v} [ForIn Id ρ α] + (m : ExtHashSet α) (l : ρ) : ExtHashSet α := + ⟨m.inner.insertManyIfNewUnit l⟩ + +/-- +Creates a hash set from an array of elements. Note that unlike repeatedly calling `insert`, if the +collection contains multiple elements that are equal (with regard to `==`), then the last element +in the collection will be present in the returned hash set. +-/ +@[inline] def ofArray [BEq α] [Hashable α] (l : Array α) : ExtHashSet α := + ⟨ExtHashMap.unitOfArray l⟩ + +end ExtHashSet + +end Std diff --git a/src/Std/Data/ExtHashSet/Lemmas.lean b/src/Std/Data/ExtHashSet/Lemmas.lean new file mode 100644 index 0000000000..6fa412b893 --- /dev/null +++ b/src/Std/Data/ExtHashSet/Lemmas.lean @@ -0,0 +1,694 @@ +/- +Copyright (c) 2024 Lean FRO, LLC. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Markus Himmel +-/ +prelude +import Std.Data.ExtHashMap.Lemmas +import Std.Data.ExtHashSet.Basic + +/-! +# Extensional hash set lemmas + +This module contains lemmas about `Std.ExtHashSet`. +-/ + +set_option linter.missingDocs true +set_option autoImplicit false + +universe u v + +variable {α : Type u} {_ : BEq α} {_ : Hashable α} + +namespace Std.ExtHashSet + +section + +variable {m : ExtHashSet α} + +private theorem ext {m m' : ExtHashSet α} : m.inner = m'.inner → m = m' := by + cases m; cases m'; rintro rfl; rfl + +private theorem ext_iff {m m' : ExtHashSet α} : m = m' ↔ m.inner = m'.inner := + ⟨fun h => h ▸ rfl, ext⟩ + +@[simp] +theorem isEmpty_iff [EquivBEq α] [LawfulHashable α] : m.isEmpty ↔ m = ∅ := + ExtHashMap.isEmpty_iff.trans ext_iff.symm + +@[simp] +theorem isEmpty_eq_false_iff [EquivBEq α] [LawfulHashable α] : m.isEmpty = false ↔ ¬m = ∅ := + (Bool.not_eq_true _).symm.to_iff.trans (not_congr isEmpty_iff) + +@[simp] +theorem empty_eq : ∅ = m ↔ m = ∅ := eq_comm + +@[simp] +theorem emptyWithCapacity_eq [EquivBEq α] [LawfulHashable α] {c} : (emptyWithCapacity c : ExtHashSet α) = ∅ := + ext ExtHashMap.emptyWithCapacity_eq + +@[simp] +theorem not_insert_eq_empty [EquivBEq α] [LawfulHashable α] {k : α} : + ¬m.insert k = ∅ := + (not_congr ext_iff).mpr ExtHashMap.not_insertIfNew_eq_empty + +theorem mem_iff_contains [EquivBEq α] [LawfulHashable α] {a : α} : a ∈ m ↔ m.contains a := + ExtHashMap.mem_iff_contains + +theorem contains_congr [EquivBEq α] [LawfulHashable α] {a b : α} (hab : a == b) : + m.contains a = m.contains b := + ExtHashMap.contains_congr hab + +theorem mem_congr [EquivBEq α] [LawfulHashable α] {a b : α} (hab : a == b) : a ∈ m ↔ b ∈ m := + ExtHashMap.mem_congr hab + +@[simp] theorem contains_empty [EquivBEq α] [LawfulHashable α] {a : α} : + (∅ : ExtHashSet α).contains a = false := + ExtHashMap.contains_empty + +@[simp] theorem not_mem_empty [EquivBEq α] [LawfulHashable α] {a : α} : ¬a ∈ (∅ : ExtHashSet α) := + ExtHashMap.not_mem_empty + +theorem eq_empty_iff_forall_contains [EquivBEq α] [LawfulHashable α] : m = ∅ ↔ ∀ a, m.contains a = false := + ext_iff.trans ExtHashMap.eq_empty_iff_forall_contains + +theorem eq_empty_iff_forall_not_mem [EquivBEq α] [LawfulHashable α] : m = ∅ ↔ ∀ a, ¬a ∈ m := + ext_iff.trans ExtHashMap.eq_empty_iff_forall_not_mem + +@[simp] theorem insert_eq_insert [EquivBEq α] [LawfulHashable α] {a : α} : + Insert.insert a m = m.insert a := + rfl + +@[simp] theorem singleton_eq_insert [EquivBEq α] [LawfulHashable α] {a : α} : + Singleton.singleton a = (∅ : ExtHashSet α).insert a := + rfl + +@[simp] +theorem contains_insert [EquivBEq α] [LawfulHashable α] {k a : α} : + (m.insert k).contains a = (k == a || m.contains a) := + ExtHashMap.contains_insertIfNew + +@[simp] +theorem mem_insert [EquivBEq α] [LawfulHashable α] {k a : α} : a ∈ m.insert k ↔ k == a ∨ a ∈ m := + ExtHashMap.mem_insertIfNew + +theorem contains_of_contains_insert [EquivBEq α] [LawfulHashable α] {k a : α} : + (m.insert k).contains a → (k == a) = false → m.contains a := + ExtHashMap.contains_of_contains_insertIfNew + +theorem mem_of_mem_insert [EquivBEq α] [LawfulHashable α] {k a : α} : + a ∈ m.insert k → (k == a) = false → a ∈ m := + ExtHashMap.mem_of_mem_insertIfNew + +/-- This is a restatement of `contains_insert` that is written to exactly match the proof +obligation in the statement of `get_insert`. -/ +theorem contains_of_contains_insert' [EquivBEq α] [LawfulHashable α] {k a : α} : + (m.insert k).contains a → ¬((k == a) ∧ m.contains k = false) → m.contains a := + ExtHashMap.contains_of_contains_insertIfNew' + +/-- This is a restatement of `mem_insert` that is written to exactly match the proof obligation +in the statement of `get_insert`. -/ +theorem mem_of_mem_insert' [EquivBEq α] [LawfulHashable α] {k a : α} : + a ∈ m.insert k → ¬((k == a) ∧ ¬k ∈ m) → a ∈ m := + ExtHashMap.mem_of_mem_insertIfNew' + +theorem contains_insert_self [EquivBEq α] [LawfulHashable α] {k : α} : (m.insert k).contains k := by + simp + +theorem mem_insert_self [EquivBEq α] [LawfulHashable α] {k : α} : k ∈ m.insert k := by simp + +@[simp] +theorem size_empty [EquivBEq α] [LawfulHashable α] : (∅ : ExtHashSet α).size = 0 := + ExtHashMap.size_empty + +theorem eq_empty_iff_size_eq_zero [EquivBEq α] [LawfulHashable α] : m = ∅ ↔ m.size = 0 := + ext_iff.trans ExtHashMap.eq_empty_iff_size_eq_zero + +theorem size_insert [EquivBEq α] [LawfulHashable α] {k : α} : + (m.insert k).size = if k ∈ m then m.size else m.size + 1 := + ExtHashMap.size_insertIfNew + +theorem size_le_size_insert [EquivBEq α] [LawfulHashable α] {k : α} : m.size ≤ (m.insert k).size := + ExtHashMap.size_le_size_insertIfNew + +theorem size_insert_le [EquivBEq α] [LawfulHashable α] {k : α} : + (m.insert k).size ≤ m.size + 1 := + ExtHashMap.size_insertIfNew_le + +@[simp] +theorem erase_empty [EquivBEq α] [LawfulHashable α] {a : α} : (∅ : ExtHashSet α).erase a = ∅ := + ext ExtHashMap.erase_empty + +@[simp] +theorem erase_eq_empty_iff [EquivBEq α] [LawfulHashable α] {k : α} : + m.erase k = ∅ ↔ m = ∅ ∨ m.size = 1 ∧ k ∈ m := by + simpa only [ext_iff] using ExtHashMap.erase_eq_empty_iff + +@[simp] +theorem contains_erase [EquivBEq α] [LawfulHashable α] {k a : α} : + (m.erase k).contains a = (!(k == a) && m.contains a) := + ExtHashMap.contains_erase + +@[simp] +theorem mem_erase [EquivBEq α] [LawfulHashable α] {k a : α} : + a ∈ m.erase k ↔ (k == a) = false ∧ a ∈ m := + ExtHashMap.mem_erase + +theorem contains_of_contains_erase [EquivBEq α] [LawfulHashable α] {k a : α} : + (m.erase k).contains a → m.contains a := + ExtHashMap.contains_of_contains_erase + +theorem mem_of_mem_erase [EquivBEq α] [LawfulHashable α] {k a : α} : a ∈ m.erase k → a ∈ m := + ExtHashMap.mem_of_mem_erase + +theorem size_erase [EquivBEq α] [LawfulHashable α] {k : α} : + (m.erase k).size = if k ∈ m then m.size - 1 else m.size := + ExtHashMap.size_erase + +theorem size_erase_le [EquivBEq α] [LawfulHashable α] {k : α} : (m.erase k).size ≤ m.size := + ExtHashMap.size_erase_le + +theorem size_le_size_erase [EquivBEq α] [LawfulHashable α] {k : α} : + m.size ≤ (m.erase k).size + 1 := + ExtHashMap.size_le_size_erase + +@[simp] +theorem get?_empty [EquivBEq α] [LawfulHashable α] {a : α} : (∅ : ExtHashSet α).get? a = none := + ExtHashMap.getKey?_empty + +theorem get?_insert [EquivBEq α] [LawfulHashable α] {k a : α} : + (m.insert k).get? a = if k == a ∧ ¬k ∈ m then some k else m.get? a := + ExtHashMap.getKey?_insertIfNew + +theorem contains_eq_isSome_get? [EquivBEq α] [LawfulHashable α] {a : α} : + m.contains a = (m.get? a).isSome := + ExtHashMap.contains_eq_isSome_getKey? + +theorem mem_iff_isSome_get? [EquivBEq α] [LawfulHashable α] {a : α} : + a ∈ m ↔ (m.get? a).isSome := + ExtHashMap.mem_iff_isSome_getKey? + +theorem get?_eq_none_of_contains_eq_false [EquivBEq α] [LawfulHashable α] {a : α} : + m.contains a = false → m.get? a = none := + ExtHashMap.getKey?_eq_none_of_contains_eq_false + +theorem get?_eq_none [EquivBEq α] [LawfulHashable α] {a : α} : ¬a ∈ m → m.get? a = none := + ExtHashMap.getKey?_eq_none + +theorem get?_erase [EquivBEq α] [LawfulHashable α] {k a : α} : + (m.erase k).get? a = if k == a then none else m.get? a := + ExtHashMap.getKey?_erase + +@[simp] +theorem get?_erase_self [EquivBEq α] [LawfulHashable α] {k : α} : (m.erase k).get? k = none := + ExtHashMap.getKey?_erase_self + +theorem get?_beq [EquivBEq α] [LawfulHashable α] {k : α} : (m.get? k).all (· == k) := + ExtHashMap.getKey?_beq + +theorem get?_congr [EquivBEq α] [LawfulHashable α] {k k' : α} (h : k == k') : + m.get? k = m.get? k' := + ExtHashMap.getKey?_congr h + +theorem get?_eq_some_of_contains [LawfulBEq α] {k : α} (h : m.contains k) : m.get? k = some k := + ExtHashMap.getKey?_eq_some_of_contains h + +theorem get?_eq_some [LawfulBEq α] {k : α} (h : k ∈ m) : m.get? k = some k := + ExtHashMap.getKey?_eq_some h + +theorem get_insert [EquivBEq α] [LawfulHashable α] {k a : α} {h₁} : + (m.insert k).get a h₁ = + if h₂ : k == a ∧ ¬k ∈ m then k else m.get a (mem_of_mem_insert' h₁ h₂) := + ExtHashMap.getKey_insertIfNew (h₁ := h₁) + +@[simp] +theorem get_erase [EquivBEq α] [LawfulHashable α] {k a : α} {h'} : + (m.erase k).get a h' = m.get a (mem_of_mem_erase h') := + ExtHashMap.getKey_erase (h' := h') + +theorem get?_eq_some_get [EquivBEq α] [LawfulHashable α] {a : α} (h' : a ∈ m) : + m.get? a = some (m.get a h') := + ExtHashMap.getKey?_eq_some_getKey h' + +theorem get_eq_get_get? [EquivBEq α] [LawfulHashable α] {k : α} {h} : + m.get k h = (m.get? k).get (mem_iff_isSome_get?.mp h) := + ExtHashMap.getKey_eq_get_getKey? + +theorem get_get? [EquivBEq α] [LawfulHashable α] {k : α} {h} : + (m.get? k).get h = m.get k (mem_iff_isSome_get?.mpr h) := + ExtHashMap.get_getKey? + +theorem get_beq [EquivBEq α] [LawfulHashable α] {k : α} (h : k ∈ m) : m.get k h == k := + ExtHashMap.getKey_beq h + +theorem get_congr [EquivBEq α] [LawfulHashable α] {k₁ k₂ : α} (h : k₁ == k₂) + (h₁ : k₁ ∈ m) : m.get k₁ h₁ = m.get k₂ ((mem_congr h).mp h₁) := + ExtHashMap.getKey_congr h h₁ + +theorem get_eq [LawfulBEq α] {k : α} (h : k ∈ m) : m.get k h = k := + ExtHashMap.getKey_eq h + +@[simp] +theorem get!_empty [EquivBEq α] [LawfulHashable α] [Inhabited α] {a : α} : + (∅ : ExtHashSet α).get! a = default := + ExtHashMap.getKey!_empty + +theorem get!_insert [Inhabited α] [EquivBEq α] [LawfulHashable α] {k a : α} : + (m.insert k).get! a = if k == a ∧ ¬k ∈ m then k else m.get! a := + ExtHashMap.getKey!_insertIfNew + +theorem get!_eq_default_of_contains_eq_false [Inhabited α] [EquivBEq α] [LawfulHashable α] {a : α} : + m.contains a = false → m.get! a = default := + ExtHashMap.getKey!_eq_default_of_contains_eq_false + +theorem get!_eq_default [Inhabited α] [EquivBEq α] [LawfulHashable α] {a : α} : + ¬a ∈ m → m.get! a = default := + ExtHashMap.getKey!_eq_default + +theorem get!_erase [Inhabited α] [EquivBEq α] [LawfulHashable α] {k a : α} : + (m.erase k).get! a = if k == a then default else m.get! a := + ExtHashMap.getKey!_erase + +@[simp] +theorem get!_erase_self [Inhabited α] [EquivBEq α] [LawfulHashable α] {k : α} : + (m.erase k).get! k = default := + ExtHashMap.getKey!_erase_self + +theorem get?_eq_some_get!_of_contains [EquivBEq α] [LawfulHashable α] [Inhabited α] + {a : α} : m.contains a = true → m.get? a = some (m.get! a) := + ExtHashMap.getKey?_eq_some_getKey!_of_contains + +theorem get?_eq_some_get! [EquivBEq α] [LawfulHashable α] [Inhabited α] {a : α} : + a ∈ m → m.get? a = some (m.get! a) := + ExtHashMap.getKey?_eq_some_getKey! + +theorem get!_eq_get!_get? [EquivBEq α] [LawfulHashable α] [Inhabited α] {a : α} : + m.get! a = (m.get? a).get! := + ExtHashMap.getKey!_eq_get!_getKey? + +theorem get_eq_get! [EquivBEq α] [LawfulHashable α] [Inhabited α] {a : α} {h'} : + m.get a h' = m.get! a := + ExtHashMap.getKey_eq_getKey! + +theorem get!_congr [EquivBEq α] [LawfulHashable α] [Inhabited α] {k k' : α} (h : k == k') : + m.get! k = m.get! k' := + ExtHashMap.getKey!_congr h + +theorem get!_eq_of_contains [LawfulBEq α] [Inhabited α] {k : α} (h : m.contains k) : m.get! k = k := + ExtHashMap.getKey!_eq_of_contains h + +theorem get!_eq_of_mem [LawfulBEq α] [Inhabited α] {k : α} (h : k ∈ m) : m.get! k = k := + ExtHashMap.getKey!_eq_of_mem h + +@[simp] +theorem getD_empty [EquivBEq α] [LawfulHashable α] {a fallback : α} : + (∅ : ExtHashSet α).getD a fallback = fallback := + ExtHashMap.getKeyD_empty + +theorem getD_insert [EquivBEq α] [LawfulHashable α] {k a fallback : α} : + (m.insert k).getD a fallback = if k == a ∧ ¬k ∈ m then k else m.getD a fallback := + ExtHashMap.getKeyD_insertIfNew + +theorem getD_eq_fallback_of_contains_eq_false [EquivBEq α] [LawfulHashable α] + {a fallback : α} : + m.contains a = false → m.getD a fallback = fallback := + ExtHashMap.getKeyD_eq_fallback_of_contains_eq_false + +theorem getD_eq_fallback [EquivBEq α] [LawfulHashable α] {a fallback : α} : + ¬a ∈ m → m.getD a fallback = fallback := + ExtHashMap.getKeyD_eq_fallback + +theorem getD_erase [EquivBEq α] [LawfulHashable α] {k a fallback : α} : + (m.erase k).getD a fallback = if k == a then fallback else m.getD a fallback := + ExtHashMap.getKeyD_erase + +@[simp] +theorem getD_erase_self [EquivBEq α] [LawfulHashable α] {k fallback : α} : + (m.erase k).getD k fallback = fallback := + ExtHashMap.getKeyD_erase_self + +theorem get?_eq_some_getD_of_contains [EquivBEq α] [LawfulHashable α] {a fallback : α} : + m.contains a = true → m.get? a = some (m.getD a fallback) := + ExtHashMap.getKey?_eq_some_getKeyD_of_contains + +theorem get?_eq_some_getD [EquivBEq α] [LawfulHashable α] {a fallback : α} : + a ∈ m → m.get? a = some (m.getD a fallback) := + ExtHashMap.getKey?_eq_some_getKeyD + +theorem getD_eq_getD_get? [EquivBEq α] [LawfulHashable α] {a fallback : α} : + m.getD a fallback = (m.get? a).getD fallback := + ExtHashMap.getKeyD_eq_getD_getKey? + +theorem get_eq_getD [EquivBEq α] [LawfulHashable α] {a fallback : α} {h'} : + m.get a h' = m.getD a fallback := + @ExtHashMap.getKey_eq_getKeyD _ _ _ _ _ _ _ _ _ h' + +theorem get!_eq_getD_default [EquivBEq α] [LawfulHashable α] [Inhabited α] {a : α} : + m.get! a = m.getD a default := + ExtHashMap.getKey!_eq_getKeyD_default + +theorem getD_congr [EquivBEq α] [LawfulHashable α] {k k' fallback : α} + (h : k == k') : m.getD k fallback = m.getD k' fallback := + ExtHashMap.getKeyD_congr h + +theorem getD_eq_of_contains [LawfulBEq α] {k fallback : α} (h : m.contains k) : + m.getD k fallback = k := + ExtHashMap.getKeyD_eq_of_contains h + +theorem getD_eq_of_mem [LawfulBEq α] {k fallback : α} (h : k ∈ m) : m.getD k fallback = k := + ExtHashMap.getKeyD_eq_of_mem h + +@[simp] +theorem containsThenInsert_fst [EquivBEq α] [LawfulHashable α] {k : α} : + (m.containsThenInsert k).1 = m.contains k := + ExtHashMap.containsThenInsertIfNew_fst + +@[simp] +theorem containsThenInsert_snd [EquivBEq α] [LawfulHashable α] {k : α} : + (m.containsThenInsert k).2 = m.insert k := + ext ExtHashMap.containsThenInsertIfNew_snd + +variable {ρ : Type v} [ForIn Id ρ α] + +@[simp] +theorem insertMany_nil [EquivBEq α] [LawfulHashable α] : + insertMany m [] = m := + ext ExtHashMap.insertManyIfNewUnit_nil + +@[simp] +theorem insertMany_list_singleton [EquivBEq α] [LawfulHashable α] {k : α} : + insertMany m [k] = m.insert k := + ext ExtHashMap.insertManyIfNewUnit_list_singleton + +theorem insertMany_cons [EquivBEq α] [LawfulHashable α] {l : List α} {k : α} : + insertMany m (k :: l) = insertMany (m.insert k) l := + ext ExtHashMap.insertManyIfNewUnit_cons + +@[elab_as_elim] +theorem insertMany_ind [EquivBEq α] [LawfulHashable α] + {motive : ExtHashSet α → Prop} (m : ExtHashSet α) {l : ρ} + (init : motive m) (insert : ∀ m a, motive m → motive (m.insert a)) : + motive (m.insertMany l) := + show motive ⟨m.1.insertManyIfNewUnit l⟩ from + ExtHashMap.insertManyIfNewUnit_ind m.inner l init fun m => insert ⟨m⟩ + +@[simp] +theorem contains_insertMany_list [EquivBEq α] [LawfulHashable α] + {l : List α} {k : α} : + (insertMany m l).contains k = (m.contains k || l.contains k) := + ExtHashMap.contains_insertManyIfNewUnit_list + +@[simp] +theorem mem_insertMany_list [EquivBEq α] [LawfulHashable α] + {l : List α} {k : α} : + k ∈ insertMany m l ↔ k ∈ m ∨ l.contains k := + ExtHashMap.mem_insertManyIfNewUnit_list + +theorem mem_of_mem_insertMany_list [EquivBEq α] [LawfulHashable α] + {l : List α} {k : α} (contains_eq_false : l.contains k = false) : + k ∈ insertMany m l → k ∈ m := + ExtHashMap.mem_of_mem_insertManyIfNewUnit_list contains_eq_false + +theorem mem_insertMany_of_mem [EquivBEq α] [LawfulHashable α] + {l : ρ} {k : α} : k ∈ m → k ∈ m.insertMany l := + ExtHashMap.mem_insertManyIfNewUnit_of_mem + +theorem get?_insertMany_list_of_not_mem_of_contains_eq_false + [EquivBEq α] [LawfulHashable α] {l : List α} {k : α} + (not_mem : ¬ k ∈ m) (contains_eq_false : l.contains k = false) : + get? (insertMany m l) k = none := + ExtHashMap.getKey?_insertManyIfNewUnit_list_of_not_mem_of_contains_eq_false + not_mem contains_eq_false + +theorem get?_insertMany_list_of_not_mem_of_mem [EquivBEq α] [LawfulHashable α] + {l : List α} {k k' : α} (k_beq : k == k') + (not_mem : ¬ k ∈ m) + (distinct : l.Pairwise (fun a b => (a == b) = false)) (mem : k ∈ l) : + get? (insertMany m l) k' = some k := + ExtHashMap.getKey?_insertManyIfNewUnit_list_of_not_mem_of_mem + k_beq not_mem distinct mem + +theorem get?_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α] + {l : List α} {k : α} (mem : k ∈ m) : + get? (insertMany m l) k = get? m k := + ExtHashMap.getKey?_insertManyIfNewUnit_list_of_mem mem + +theorem get_insertMany_list_of_not_mem_of_mem [EquivBEq α] [LawfulHashable α] + {l : List α} + {k k' : α} (k_beq : k == k') + (not_mem : ¬ k ∈ m) + (distinct : l.Pairwise (fun a b => (a == b) = false)) (mem : k ∈ l) {h} : + get (insertMany m l) k' h = k := + ExtHashMap.getKey_insertManyIfNewUnit_list_of_not_mem_of_mem + k_beq not_mem distinct mem + +theorem get_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α] + {l : List α} {k : α} (mem : k ∈ m) {h} : + get (insertMany m l) k h = get m k mem := + ExtHashMap.getKey_insertManyIfNewUnit_list_of_mem mem + +theorem get!_insertMany_list_of_not_mem_of_contains_eq_false + [EquivBEq α] [LawfulHashable α] [Inhabited α] {l : List α} {k : α} + (not_mem : ¬ k ∈ m) (contains_eq_false : l.contains k = false) : + get! (insertMany m l) k = default := + ExtHashMap.getKey!_insertManyIfNewUnit_list_of_not_mem_of_contains_eq_false + not_mem contains_eq_false + +theorem get!_insertMany_list_of_not_mem_of_mem [EquivBEq α] [LawfulHashable α] + [Inhabited α] {l : List α} {k k' : α} (k_beq : k == k') + (not_mem : ¬ k ∈ m) + (distinct : l.Pairwise (fun a b => (a == b) = false)) (mem : k ∈ l) : + get! (insertMany m l) k' = k := + ExtHashMap.getKey!_insertManyIfNewUnit_list_of_not_mem_of_mem + k_beq not_mem distinct mem + +theorem get!_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α] + [Inhabited α] {l : List α} {k : α} (mem : k ∈ m) : + get! (insertMany m l) k = get! m k := + ExtHashMap.getKey!_insertManyIfNewUnit_list_of_mem mem + +theorem getD_insertMany_list_of_not_mem_of_contains_eq_false + [EquivBEq α] [LawfulHashable α] {l : List α} {k fallback : α} + (not_mem : ¬ k ∈ m) (contains_eq_false : l.contains k = false) : + getD (insertMany m l) k fallback = fallback := + ExtHashMap.getKeyD_insertManyIfNewUnit_list_of_not_mem_of_contains_eq_false + not_mem contains_eq_false + +theorem getD_insertMany_list_of_not_mem_of_mem [EquivBEq α] [LawfulHashable α] + {l : List α} {k k' fallback : α} (k_beq : k == k') + (not_mem : ¬ k ∈ m) + (distinct : l.Pairwise (fun a b => (a == b) = false)) (mem : k ∈ l) : + getD (insertMany m l) k' fallback = k := + ExtHashMap.getKeyD_insertManyIfNewUnit_list_of_not_mem_of_mem + k_beq not_mem distinct mem + +theorem getD_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α] + {l : List α} {k fallback : α} (mem : k ∈ m) : + getD (insertMany m l) k fallback = getD m k fallback := + ExtHashMap.getKeyD_insertManyIfNewUnit_list_of_mem mem + +theorem size_insertMany_list [EquivBEq α] [LawfulHashable α] + {l : List α} + (distinct : l.Pairwise (fun a b => (a == b) = false)) : + (∀ (a : α), a ∈ m → l.contains a = false) → + (insertMany m l).size = m.size + l.length := + ExtHashMap.size_insertManyIfNewUnit_list distinct + +theorem size_le_size_insertMany_list [EquivBEq α] [LawfulHashable α] + {l : List α} : + m.size ≤ (insertMany m l).size := + ExtHashMap.size_le_size_insertManyIfNewUnit_list + +theorem size_le_size_insertMany [EquivBEq α] [LawfulHashable α] + {l : ρ} : m.size ≤ (insertMany m l).size := + ExtHashMap.size_le_size_insertManyIfNewUnit + +theorem size_insertMany_list_le [EquivBEq α] [LawfulHashable α] + {l : List α} : + (insertMany m l).size ≤ m.size + l.length := + ExtHashMap.size_insertManyIfNewUnit_list_le + +@[simp] +theorem insertMany_list_eq_empty_iff [EquivBEq α] [LawfulHashable α] {l : List α} : + m.insertMany l = ∅ ↔ m = ∅ ∧ l = [] := by + simpa only [ext_iff] using ExtHashMap.insertManyIfNewUnit_list_eq_empty_iff + +theorem eq_empty_of_insertMany_eq_empty [EquivBEq α] [LawfulHashable α] {l : ρ} : + m.insertMany l = ∅ → m = ∅ := by + simpa only [ext_iff] using ExtHashMap.eq_empty_of_insertManyIfNewUnit_eq_empty + +end + +section + +@[simp] +theorem ofList_nil [EquivBEq α] [LawfulHashable α] : + ofList ([] : List α) = ∅ := + ext ExtHashMap.unitOfList_nil + +@[simp] +theorem ofList_singleton [EquivBEq α] [LawfulHashable α] {k : α} : + ofList [k] = (∅ : ExtHashSet α).insert k := + ext ExtHashMap.unitOfList_singleton + +theorem ofList_cons [EquivBEq α] [LawfulHashable α] {hd : α} {tl : List α} : + ofList (hd :: tl) = + insertMany ((∅ : ExtHashSet α).insert hd) tl := + ext ExtHashMap.unitOfList_cons + +@[simp] +theorem contains_ofList [EquivBEq α] [LawfulHashable α] + {l : List α} {k : α} : + (ofList l).contains k = l.contains k := + ExtHashMap.contains_unitOfList + +@[simp] +theorem mem_ofList [EquivBEq α] [LawfulHashable α] + {l : List α} {k : α} : + k ∈ ofList l ↔ l.contains k := + ExtHashMap.mem_unitOfList + +theorem get?_ofList_of_contains_eq_false [EquivBEq α] [LawfulHashable α] + {l : List α} {k : α} (contains_eq_false : l.contains k = false) : + get? (ofList l) k = none := + ExtHashMap.getKey?_unitOfList_of_contains_eq_false contains_eq_false + +theorem get?_ofList_of_mem [EquivBEq α] [LawfulHashable α] + {l : List α} {k k' : α} (k_beq : k == k') + (distinct : l.Pairwise (fun a b => (a == b) = false)) (mem : k ∈ l) : + get? (ofList l) k' = some k := + ExtHashMap.getKey?_unitOfList_of_mem k_beq distinct mem + +theorem get_ofList_of_mem [EquivBEq α] [LawfulHashable α] + {l : List α} + {k k' : α} (k_beq : k == k') + (distinct : l.Pairwise (fun a b => (a == b) = false)) + (mem : k ∈ l) {h} : + get (ofList l) k' h = k := + ExtHashMap.getKey_unitOfList_of_mem k_beq distinct mem + +theorem get!_ofList_of_contains_eq_false [EquivBEq α] [LawfulHashable α] + [Inhabited α] {l : List α} {k : α} + (contains_eq_false : l.contains k = false) : + get! (ofList l) k = default := + ExtHashMap.getKey!_unitOfList_of_contains_eq_false contains_eq_false + +theorem get!_ofList_of_mem [EquivBEq α] [LawfulHashable α] + [Inhabited α] {l : List α} {k k' : α} (k_beq : k == k') + (distinct : l.Pairwise (fun a b => (a == b) = false)) + (mem : k ∈ l) : + get! (ofList l) k' = k := + ExtHashMap.getKey!_unitOfList_of_mem k_beq distinct mem + +theorem getD_ofList_of_contains_eq_false [EquivBEq α] [LawfulHashable α] + {l : List α} {k fallback : α} + (contains_eq_false : l.contains k = false) : + getD (ofList l) k fallback = fallback := + ExtHashMap.getKeyD_unitOfList_of_contains_eq_false contains_eq_false + +theorem getD_ofList_of_mem [EquivBEq α] [LawfulHashable α] + {l : List α} {k k' fallback : α} (k_beq : k == k') + (distinct : l.Pairwise (fun a b => (a == b) = false)) + (mem : k ∈ l) : + getD (ofList l) k' fallback = k := + ExtHashMap.getKeyD_unitOfList_of_mem k_beq distinct mem + +theorem size_ofList [EquivBEq α] [LawfulHashable α] + {l : List α} + (distinct : l.Pairwise (fun a b => (a == b) = false)) : + (ofList l).size = l.length := + ExtHashMap.size_unitOfList distinct + +theorem size_ofList_le [EquivBEq α] [LawfulHashable α] + {l : List α} : + (ofList l).size ≤ l.length := + ExtHashMap.size_unitOfList_le + +@[simp] +theorem ofList_eq_empty_iff [EquivBEq α] [LawfulHashable α] {l : List α} : + ofList l = ∅ ↔ l = [] := + ext_iff.trans ExtHashMap.unitOfList_eq_empty_iff + +end + +section Ext + +@[ext 900] +theorem ext_get? [EquivBEq α] [LawfulHashable α] {m₁ m₂ : ExtHashSet α} + (h : ∀ k, m₁.get? k = m₂.get? k) : m₁ = m₂ := + ext (ExtHashMap.ext_getKey?_unit h) + +theorem ext_contains [LawfulBEq α] {m₁ m₂ : ExtHashSet α} + (h : ∀ k, m₁.contains k = m₂.contains k) : m₁ = m₂ := + ext (ExtHashMap.ext_contains_unit h) + +@[ext] +theorem ext_mem [LawfulBEq α] {m₁ m₂ : ExtHashSet α} (h : ∀ k, k ∈ m₁ ↔ k ∈ m₂) : m₁ = m₂ := + ext (ExtHashMap.ext_mem_unit h) + +end Ext + +section filter + +variable {m : ExtHashSet α} + +theorem filter_eq_empty_iff [EquivBEq α] [LawfulHashable α] {f : α → Bool} : + m.filter f = ∅ ↔ ∀ k h, f (m.get k h) = false := + ext_iff.trans ExtHashMap.filter_eq_empty_iff + +@[simp] +theorem mem_filter [EquivBEq α] [LawfulHashable α] + {f : α → Bool} {k : α} : + k ∈ m.filter f ↔ ∃ h, f (m.get k h) := + ExtHashMap.mem_filter + +theorem contains_of_contains_filter [EquivBEq α] [LawfulHashable α] + {f : α → Bool} {k : α} : + (m.filter f).contains k → m.contains k := + ExtHashMap.contains_of_contains_filter + +theorem mem_of_mem_filter [EquivBEq α] [LawfulHashable α] + {f : α → Bool} {k : α} : + k ∈ m.filter f → k ∈ m := + ExtHashMap.mem_of_mem_filter + +theorem size_filter_le_size [EquivBEq α] [LawfulHashable α] + {f : α → Bool} : + (m.filter f).size ≤ m.size := + ExtHashMap.size_filter_le_size + +theorem size_filter_eq_size_iff [EquivBEq α] [LawfulHashable α] + {f : α → Bool} : + (m.filter f).size = m.size ↔ ∀ k h, f (m.get k h) := + ExtHashMap.size_filter_eq_size_iff + +theorem filter_eq_self_iff [EquivBEq α] [LawfulHashable α] + {f : α → Bool} : + m.filter f = m ↔ ∀ k h, f (m.get k h) := + ext_iff.trans ExtHashMap.filter_eq_self_iff + +@[simp] +theorem get?_filter [EquivBEq α] [LawfulHashable α] + {f : α → Bool} {k : α} : + (m.filter f).get? k = (m.get? k).filter f := + ExtHashMap.getKey?_filter_key + +@[simp] +theorem get_filter [EquivBEq α] [LawfulHashable α] + {f : α → Bool} {k : α} {h} : + (m.filter f).get k h = m.get k (mem_of_mem_filter h) := + ExtHashMap.getKey_filter + +theorem get!_filter [EquivBEq α] [LawfulHashable α] [Inhabited α] + {f : α → Bool} {k : α} : + (m.filter f).get! k = ((m.get? k).filter f).get! := + ExtHashMap.getKey!_filter_key + +theorem getD_filter [EquivBEq α] [LawfulHashable α] + {f : α → Bool} {k fallback : α} : + (m.filter f).getD k fallback = ((m.get? k).filter f).getD fallback := + ExtHashMap.getKeyD_filter_key + +end filter + +end Std.ExtHashSet diff --git a/src/Std/Data/HashMap/Basic.lean b/src/Std/Data/HashMap/Basic.lean index 6101ea4c38..073437e067 100644 --- a/src/Std/Data/HashMap/Basic.lean +++ b/src/Std/Data/HashMap/Basic.lean @@ -12,13 +12,13 @@ set_option autoImplicit false /-! # Hash maps -This module develops the type `Std.Data.HashMap` of hash maps. Dependent hash maps are defined in +This module develops the type `Std.HashMap` of hash maps. Dependent hash maps are defined in `Std.Data.DHashMap`. -The operations `map` and `filterMap` on `Std.Data.HashMap` are defined in the module +The operations `map` and `filterMap` on `Std.HashMap` are defined in the module `Std.Data.HashMap.AdditionalOperations`. -Lemmas about the operations on `Std.Data.HashMap` are available in the +Lemmas about the operations on `Std.HashMap` are available in the module `Std.Data.HashMap.Lemmas`. See the module `Std.Data.HashMap.Raw` for a variant of this type which is safe to use in diff --git a/src/Std/Data/HashMap/Lemmas.lean b/src/Std/Data/HashMap/Lemmas.lean index 127fee1603..c02e63da60 100644 --- a/src/Std/Data/HashMap/Lemmas.lean +++ b/src/Std/Data/HashMap/Lemmas.lean @@ -935,6 +935,8 @@ theorem forIn_eq_forIn_keys [Monad m'] [LawfulMonad m'] end monadic +variable {ρ : Type w} [ForIn Id ρ (α × β)] + @[simp] theorem insertMany_nil : insertMany m [] = m := @@ -949,6 +951,13 @@ theorem insertMany_cons {l : List (α × β)} {k : α} {v : β} : insertMany m (⟨k, v⟩ :: l) = insertMany (m.insert k v) l := ext DHashMap.Const.insertMany_cons +@[elab_as_elim] +theorem insertMany_ind {motive : HashMap α β → Prop} (m : HashMap α β) {l : ρ} + (init : motive m) (insert : ∀ m a b, motive m → motive (m.insert a b)) : + motive (m.insertMany l) := + show motive ⟨DHashMap.Const.insertMany m.1 l⟩ from + DHashMap.Const.insertMany_ind m.inner l init fun m => insert ⟨m⟩ + @[simp] theorem contains_insertMany_list [EquivBEq α] [LawfulHashable α] {l : List (α × β)} {k : α} : @@ -967,6 +976,10 @@ theorem mem_of_mem_insertMany_list [EquivBEq α] [LawfulHashable α] k ∈ m := DHashMap.Const.mem_of_mem_insertMany_list mem contains_eq_false +theorem mem_insertMany_of_mem [EquivBEq α] [LawfulHashable α] + {l : ρ} {k : α} : k ∈ m → k ∈ m.insertMany l := + DHashMap.Const.mem_insertMany_of_mem + theorem getElem?_insertMany_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α] {l : List (α × β)} {k : α} (contains_eq_false : (l.map Prod.fst).contains k = false) : @@ -1087,6 +1100,10 @@ theorem size_le_size_insertMany_list [EquivBEq α] [LawfulHashable α] m.size ≤ (insertMany m l).size := DHashMap.Const.size_le_size_insertMany_list +theorem size_le_size_insertMany [EquivBEq α] [LawfulHashable α] + {l : ρ} : m.size ≤ (insertMany m l).size := + DHashMap.Const.size_le_size_insertMany + theorem size_insertMany_list_le [EquivBEq α] [LawfulHashable α] {l : List (α × β)} : (insertMany m l).size ≤ m.size + l.length := @@ -1098,7 +1115,12 @@ theorem isEmpty_insertMany_list [EquivBEq α] [LawfulHashable α] (insertMany m l).isEmpty = (m.isEmpty && l.isEmpty) := DHashMap.Const.isEmpty_insertMany_list +theorem isEmpty_of_isEmpty_insertMany [EquivBEq α] [LawfulHashable α] + {l : ρ} : (insertMany m l).isEmpty → m.isEmpty := + DHashMap.Const.isEmpty_of_isEmpty_insertMany + variable {m : HashMap α Unit} +variable {ρ : Type w} [ForIn Id ρ α] @[simp] theorem insertManyIfNewUnit_nil : @@ -1114,6 +1136,13 @@ theorem insertManyIfNewUnit_cons {l : List α} {k : α} : insertManyIfNewUnit m (k :: l) = insertManyIfNewUnit (m.insertIfNew k ()) l := ext DHashMap.Const.insertManyIfNewUnit_cons +@[elab_as_elim] +theorem insertManyIfNewUnit_ind {motive : HashMap α Unit → Prop} (m : HashMap α Unit) (l : ρ) + (init : motive m) (insert : ∀ m a, motive m → motive (m.insertIfNew a ())) : + motive (insertManyIfNewUnit m l) := + show motive ⟨DHashMap.Const.insertManyIfNewUnit m.1 l⟩ from + DHashMap.Const.insertManyIfNewUnit_ind m.inner l init fun m => insert ⟨m⟩ + @[simp] theorem contains_insertManyIfNewUnit_list [EquivBEq α] [LawfulHashable α] {l : List α} {k : α} : @@ -1131,6 +1160,10 @@ theorem mem_of_mem_insertManyIfNewUnit_list [EquivBEq α] [LawfulHashable α] k ∈ insertManyIfNewUnit m l → k ∈ m := DHashMap.Const.mem_of_mem_insertManyIfNewUnit_list contains_eq_false +theorem mem_insertManyIfNewUnit_of_mem [EquivBEq α] [LawfulHashable α] + {l : ρ} {k : α} : k ∈ m → k ∈ insertManyIfNewUnit m l := + DHashMap.Const.mem_insertManyIfNewUnit_of_mem + theorem getElem?_insertManyIfNewUnit_list [EquivBEq α] [LawfulHashable α] {l : List α} {k : α} : (insertManyIfNewUnit m l)[k]? = @@ -1235,6 +1268,10 @@ theorem size_le_size_insertManyIfNewUnit_list [EquivBEq α] [LawfulHashable α] m.size ≤ (insertManyIfNewUnit m l).size := DHashMap.Const.size_le_size_insertManyIfNewUnit_list +theorem size_le_size_insertManyIfNewUnit [EquivBEq α] [LawfulHashable α] + {l : ρ} : m.size ≤ (insertManyIfNewUnit m l).size := + DHashMap.Const.size_le_size_insertManyIfNewUnit + theorem size_insertManyIfNewUnit_list_le [EquivBEq α] [LawfulHashable α] {l : List α} : (insertManyIfNewUnit m l).size ≤ m.size + l.length := @@ -1246,6 +1283,10 @@ theorem isEmpty_insertManyIfNewUnit_list [EquivBEq α] [LawfulHashable α] (insertManyIfNewUnit m l).isEmpty = (m.isEmpty && l.isEmpty) := DHashMap.Const.isEmpty_insertManyIfNewUnit_list +theorem isEmpty_of_isEmpty_insertManyIfNewUnit [EquivBEq α] [LawfulHashable α] + {l : ρ} : (m.insertManyIfNewUnit l).isEmpty → m.isEmpty := + DHashMap.Const.isEmpty_of_isEmpty_insertManyIfNewUnit + end section @@ -1937,12 +1978,15 @@ namespace Equiv variable {m m₁ m₂ m₃ : HashMap α β} -theorem refl (m : HashMap α β) : m ~m m := ⟨.rfl⟩ +@[refl, simp] theorem refl (m : HashMap α β) : m ~m m := ⟨.rfl⟩ theorem rfl : m ~m m := ⟨.rfl⟩ -theorem symm : m₁ ~m m₂ → m₂ ~m m₁ +@[symm] theorem symm : m₁ ~m m₂ → m₂ ~m m₁ | ⟨h⟩ => ⟨h.symm⟩ theorem trans : m₁ ~m m₂ → m₂ ~m m₃ → m₁ ~m m₃ | ⟨h₁⟩, ⟨h₂⟩ => ⟨h₁.trans h₂⟩ + +instance instTrans : Trans (α := HashMap α β) Equiv Equiv Equiv := ⟨trans⟩ + theorem comm : m₁ ~m m₂ ↔ m₂ ~m m₁ := ⟨symm, symm⟩ theorem congr_left (h : m₁ ~m m₂) : m₁ ~m m₃ ↔ m₂ ~m m₃ := ⟨h.symm.trans, h.trans⟩ theorem congr_right (h : m₁ ~m m₂) : m₃ ~m m₁ ↔ m₃ ~m m₂ := @@ -2043,15 +2087,20 @@ theorem map (f : α → β → γ) (h : m₁ ~m m₂) : m₁.map f ~m m₂.map f theorem filterMap (f : α → β → Option γ) (h : m₁ ~m m₂) : m₁.filterMap f ~m m₂.filterMap f := ⟨h.1.filterMap f⟩ +theorem of_forall_getKey_eq_of_forall_getElem?_eq [EquivBEq α] [LawfulHashable α] + (hk : ∀ k hk hk', m₁.getKey k hk = m₂.getKey k hk') (hv : ∀ k : α, m₁[k]? = m₂[k]?) : + m₁ ~m m₂ := + ⟨.of_forall_getKey_eq_of_forall_constGet?_eq hk hv⟩ + +set_option linter.deprecated false in +@[deprecated of_forall_getKey_eq_of_forall_getElem?_eq (since := "2025-04-25")] theorem of_forall_getKey?_eq_of_forall_getElem?_eq [EquivBEq α] [LawfulHashable α] (hk : ∀ k, m₁.getKey? k = m₂.getKey? k) (hv : ∀ k : α, m₁[k]? = m₂[k]?) : m₁ ~m m₂ := ⟨.of_forall_getKey?_eq_of_forall_constGet?_eq hk hv⟩ theorem of_forall_getElem?_eq [LawfulBEq α] (h : ∀ k : α, m₁[k]? = m₂[k]?) : m₁ ~m m₂ := - ⟨.of_forall_get?_eq fun k => - DHashMap.Const.get?_eq_get? (m := m₁.1) ▸ - DHashMap.Const.get?_eq_get? (m := m₂.1) ▸ h k⟩ + ⟨.of_forall_constGet?_eq h⟩ theorem of_forall_getKey?_unit_eq [EquivBEq α] [LawfulHashable α] {m₁ m₂ : HashMap α Unit} (h : ∀ k, m₁.getKey? k = m₂.getKey? k) : m₁ ~m m₂ := diff --git a/src/Std/Data/HashMap/Raw.lean b/src/Std/Data/HashMap/Raw.lean index 17afb02cf6..dfad43e1f8 100644 --- a/src/Std/Data/HashMap/Raw.lean +++ b/src/Std/Data/HashMap/Raw.lean @@ -9,17 +9,17 @@ import Std.Data.DHashMap.Raw set_option linter.missingDocs true set_option autoImplicit false -/- +/-! # Hash maps with unbundled well-formedness invariant -This module develops the type `Std.Data.HashMap.Raw` of dependent hash maps with unbundled +This module develops the type `Std.HashMap.Raw` of dependent hash maps with unbundled well-formedness invariant. This version is safe to use in nested inductive types. The well-formedness predicate is -available as `Std.Data.HashMap.Raw.WF` and we prove in this file that all operations preserve -well-formedness. When in doubt, prefer `HashMap` over `DHashMap.Raw`. +available as `Std.HashMap.Raw.WF` and we prove in this file that all operations preserve +well-formedness. When in doubt, prefer `HashMap` over `HashMap.Raw`. -Lemmas about the operations on `Std.Data.HashMap.Raw` are available in the module +Lemmas about the operations on `Std.HashMap.Raw` are available in the module `Std.Data.HashMap.RawLemmas`. -/ diff --git a/src/Std/Data/HashMap/RawLemmas.lean b/src/Std/Data/HashMap/RawLemmas.lean index 6182bee378..0b3157b415 100644 --- a/src/Std/Data/HashMap/RawLemmas.lean +++ b/src/Std/Data/HashMap/RawLemmas.lean @@ -958,6 +958,8 @@ theorem forIn_eq_forIn_keys [Monad m'] [LawfulMonad m'] (h : m.WF) end monadic +variable {ρ : Type w} [ForIn Id ρ (α × β)] + @[simp] theorem insertMany_nil (h : m.WF) : insertMany m [] = m := @@ -974,6 +976,13 @@ theorem insertMany_cons (h : m.WF) {l : List (α × β)} insertMany m (⟨k, v⟩ :: l) = insertMany (m.insert k v) l := ext (DHashMap.Raw.Const.insertMany_cons h.out) +@[elab_as_elim] +theorem insertMany_ind {motive : Raw α β → Prop} (m : Raw α β) {l : ρ} + (init : motive m) (insert : ∀ m a b, motive m → motive (m.insert a b)) : + motive (m.insertMany l) := + show motive ⟨DHashMap.Raw.Const.insertMany m.1 l⟩ from + DHashMap.Raw.Const.insertMany_ind m.inner l init fun m => insert ⟨m⟩ + @[simp] theorem contains_insertMany_list [EquivBEq α] [LawfulHashable α] (h : m.WF) {l : List (α × β)} {k : α} : @@ -991,6 +1000,10 @@ theorem mem_of_mem_insertMany_list [EquivBEq α] [LawfulHashable α] (h : m.WF) k ∈ insertMany m l → (l.map Prod.fst).contains k = false → k ∈ m := DHashMap.Raw.Const.mem_of_mem_insertMany_list h.out +theorem mem_insertMany_of_mem [EquivBEq α] [LawfulHashable α] (h : m.WF) + {l : ρ} {k : α} : k ∈ m → k ∈ m.insertMany l := + DHashMap.Raw.Const.mem_insertMany_of_mem h.out + theorem getKey?_insertMany_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α] (h : m.WF) {l : List (α × β)} {k : α} (contains_eq_false : (l.map Prod.fst).contains k = false) : @@ -1062,6 +1075,10 @@ theorem size_le_size_insertMany_list [EquivBEq α] [LawfulHashable α] m.size ≤ (insertMany m l).size := DHashMap.Raw.Const.size_le_size_insertMany_list h.out +theorem size_le_size_insertMany [EquivBEq α] [LawfulHashable α] (h : m.WF) + {l : ρ} : m.size ≤ (insertMany m l).size := + DHashMap.Raw.Const.size_le_size_insertMany h.out + theorem size_insertMany_list_le [EquivBEq α] [LawfulHashable α] (h : m.WF) {l : List (α × β)} : (insertMany m l).size ≤ m.size + l.length := @@ -1073,6 +1090,10 @@ theorem isEmpty_insertMany_list [EquivBEq α] [LawfulHashable α] (insertMany m l).isEmpty = (m.isEmpty && l.isEmpty) := DHashMap.Raw.Const.isEmpty_insertMany_list h.out +theorem isEmpty_of_isEmpty_insertMany [EquivBEq α] [LawfulHashable α] (h : m.WF) + {l : ρ} : (insertMany m l).isEmpty → m.isEmpty := + DHashMap.Raw.Const.isEmpty_of_isEmpty_insertMany h.out + theorem getElem?_insertMany_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α] (h : m.WF) {l : List (α × β)} {k : α} (contains_eq_false : (l.map Prod.fst).contains k = false) : @@ -1124,6 +1145,7 @@ theorem getD_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α] DHashMap.Raw.Const.getD_insertMany_list_of_mem h.out k_beq distinct mem variable {m : Raw α Unit} +variable {ρ : Type w} [ForIn Id ρ α] @[simp] theorem insertManyIfNewUnit_nil (h : m.WF) : @@ -1139,6 +1161,13 @@ theorem insertManyIfNewUnit_cons (h : m.WF) {l : List α} {k : α} : insertManyIfNewUnit m (k :: l) = insertManyIfNewUnit (m.insertIfNew k ()) l := ext (DHashMap.Raw.Const.insertManyIfNewUnit_cons h.out) +@[elab_as_elim] +theorem insertManyIfNewUnit_ind {motive : Raw α Unit → Prop} (m : Raw α Unit) (l : ρ) + (init : motive m) (insert : ∀ m a, motive m → motive (m.insertIfNew a ())) : + motive (insertManyIfNewUnit m l) := + show motive ⟨DHashMap.Raw.Const.insertManyIfNewUnit m.1 l⟩ from + DHashMap.Raw.Const.insertManyIfNewUnit_ind m.inner l init fun m => insert ⟨m⟩ + @[simp] theorem contains_insertManyIfNewUnit_list [EquivBEq α] [LawfulHashable α] (h : m.WF) {l : List α} {k : α} : @@ -1156,6 +1185,10 @@ theorem mem_of_mem_insertManyIfNewUnit_list [EquivBEq α] [LawfulHashable α] (h k ∈ insertManyIfNewUnit m l → k ∈ m := DHashMap.Raw.Const.mem_of_mem_insertManyIfNewUnit_list h.out contains_eq_false +theorem mem_insertManyIfNewUnit_of_mem [EquivBEq α] [LawfulHashable α] (h : m.WF) + {l : ρ} {k : α} : k ∈ m → k ∈ insertManyIfNewUnit m l := + DHashMap.Raw.Const.mem_insertManyIfNewUnit_of_mem h.out + theorem getKey?_insertManyIfNewUnit_list_of_not_mem_of_contains_eq_false [EquivBEq α] [LawfulHashable α] (h : m.WF) {l : List α} {k : α} (not_mem : ¬ k ∈ m) (contains_eq_false : l.contains k = false) : @@ -1242,6 +1275,10 @@ theorem size_le_size_insertManyIfNewUnit_list [EquivBEq α] [LawfulHashable α] m.size ≤ (insertManyIfNewUnit m l).size := DHashMap.Raw.Const.size_le_size_insertManyIfNewUnit_list h.out +theorem size_le_size_insertManyIfNewUnit [EquivBEq α] [LawfulHashable α] (h : m.WF) + {l : ρ} : m.size ≤ (insertManyIfNewUnit m l).size := + DHashMap.Raw.Const.size_le_size_insertManyIfNewUnit h.out + theorem size_insertManyIfNewUnit_list_le [EquivBEq α] [LawfulHashable α] (h : m.WF) {l : List α} : (insertManyIfNewUnit m l).size ≤ m.size + l.length := @@ -1253,6 +1290,10 @@ theorem isEmpty_insertManyIfNewUnit_list [EquivBEq α] [LawfulHashable α] (h : (insertManyIfNewUnit m l).isEmpty = (m.isEmpty && l.isEmpty) := DHashMap.Raw.Const.isEmpty_insertManyIfNewUnit_list h.out +theorem isEmpty_of_isEmpty_insertManyIfNewUnit [EquivBEq α] [LawfulHashable α] (h : m.WF) + {l : ρ} : (m.insertManyIfNewUnit l).isEmpty → m.isEmpty := + DHashMap.Raw.Const.isEmpty_of_isEmpty_insertManyIfNewUnit h.out + @[simp] theorem getElem?_insertManyIfNewUnit_list [EquivBEq α] [LawfulHashable α] (h : m.WF) {l : List α} {k : α} : @@ -1969,12 +2010,15 @@ section Raw variable {α : Type u} {β : Type v} {m m₁ m₂ m₃ : Raw α β} -theorem refl (m : Raw α β) : m ~m m := ⟨.rfl⟩ +@[refl, simp] theorem refl (m : Raw α β) : m ~m m := ⟨.rfl⟩ theorem rfl : m ~m m := ⟨.rfl⟩ -theorem symm : m₁ ~m m₂ → m₂ ~m m₁ +@[symm] theorem symm : m₁ ~m m₂ → m₂ ~m m₁ | ⟨h⟩ => ⟨h.symm⟩ theorem trans : m₁ ~m m₂ → m₂ ~m m₃ → m₁ ~m m₃ | ⟨h₁⟩, ⟨h₂⟩ => ⟨h₁.trans h₂⟩ + +instance instTrans : Trans (α := Raw α β) Equiv Equiv Equiv := ⟨trans⟩ + theorem comm : m₁ ~m m₂ ↔ m₂ ~m m₁ := ⟨symm, symm⟩ theorem congr_left (h : m₁ ~m m₂) : m₁ ~m m₃ ↔ m₂ ~m m₃ := ⟨h.symm.trans, h.trans⟩ theorem congr_right (h : m₁ ~m m₂) : m₃ ~m m₁ ↔ m₃ ~m m₂ := @@ -2086,6 +2130,13 @@ theorem filterMap (h₁ : m₁.WF) (h₂ : m₂.WF) (f : α → β → Option γ m₁.filterMap f ~m m₂.filterMap f := ⟨h.1.filterMap h₁.1 h₂.1 f⟩ +theorem of_forall_getKey_eq_of_forall_getElem?_eq [EquivBEq α] [LawfulHashable α] + (h₁ : m₁.WF) (h₂ : m₂.WF) (hk : ∀ k hk hk', m₁.getKey k hk = m₂.getKey k hk') + (hv : ∀ k : α, m₁[k]? = m₂[k]?) : m₁ ~m m₂ := + ⟨.of_forall_getKey_eq_of_forall_constGet?_eq h₁.1 h₂.1 hk hv⟩ + +set_option linter.deprecated false in +@[deprecated of_forall_getKey_eq_of_forall_getElem?_eq (since := "2025-04-25")] theorem of_forall_getKey?_eq_of_forall_getElem?_eq [EquivBEq α] [LawfulHashable α] (h₁ : m₁.WF) (h₂ : m₂.WF) (hk : ∀ k, m₁.getKey? k = m₂.getKey? k) (hv : ∀ k : α, m₁[k]? = m₂[k]?) : m₁ ~m m₂ := @@ -2093,9 +2144,7 @@ theorem of_forall_getKey?_eq_of_forall_getElem?_eq [EquivBEq α] [LawfulHashable theorem of_forall_getElem?_eq [LawfulBEq α] (h₁ : m₁.WF) (h₂ : m₂.WF) (h : ∀ k : α, m₁[k]? = m₂[k]?) : m₁ ~m m₂ := - ⟨.of_forall_get?_eq h₁.1 h₂.1 fun k => - DHashMap.Raw.Const.get?_eq_get? h₁.1 ▸ - DHashMap.Raw.Const.get?_eq_get? h₂.1 ▸ h k⟩ + ⟨.of_forall_constGet?_eq h₁.1 h₂.1 h⟩ theorem of_forall_getKey?_unit_eq [EquivBEq α] [LawfulHashable α] {m₁ m₂ : HashMap.Raw α Unit} (h₁ : m₁.WF) (h₂ : m₂.WF) @@ -2112,7 +2161,6 @@ theorem of_forall_mem_unit_iff [LawfulBEq α] (h : ∀ k, k ∈ m₁ ↔ k ∈ m₂) : m₁ ~m m₂ := ⟨.of_forall_mem_unit_iff h₁.1 h₂.1 h⟩ - end Equiv theorem equiv_emptyWithCapacity_iff_isEmpty [EquivBEq α] [LawfulHashable α] {c : Nat} (h : m.WF) : diff --git a/src/Std/Data/HashSet/Basic.lean b/src/Std/Data/HashSet/Basic.lean index a93362739d..e3e495e679 100644 --- a/src/Std/Data/HashSet/Basic.lean +++ b/src/Std/Data/HashSet/Basic.lean @@ -9,9 +9,9 @@ import Std.Data.HashMap.Basic /-! # Hash sets -This module develops the type `Std.Data.HashSet` of dependent hash sets. +This module develops the type `Std.HashSet` of hash sets. -Lemmas about the operations on `Std.Data.HashSet` are available in the +Lemmas about the operations on `Std.HashSet` are available in the module `Std.Data.HashSet.Lemmas`. See the module `Std.Data.HashSet.Raw` for a variant of this type which is safe to use in diff --git a/src/Std/Data/HashSet/Lemmas.lean b/src/Std/Data/HashSet/Lemmas.lean index 02c47970d2..51fb5917e4 100644 --- a/src/Std/Data/HashSet/Lemmas.lean +++ b/src/Std/Data/HashSet/Lemmas.lean @@ -496,6 +496,8 @@ theorem forIn_eq_forIn_toList [Monad m'] [LawfulMonad m'] end monadic +variable {ρ : Type v} [ForIn Id ρ α] + @[simp] theorem insertMany_nil : insertMany m [] = m := @@ -510,6 +512,13 @@ theorem insertMany_cons {l : List α} {k : α} : insertMany m (k :: l) = insertMany (m.insert k) l := ext HashMap.insertManyIfNewUnit_cons +@[elab_as_elim] +theorem insertMany_ind {motive : HashSet α → Prop} (m : HashSet α) {l : ρ} + (init : motive m) (insert : ∀ m a, motive m → motive (m.insert a)) : + motive (m.insertMany l) := + show motive ⟨m.1.insertManyIfNewUnit l⟩ from + HashMap.insertManyIfNewUnit_ind m.inner l init fun m => insert ⟨m⟩ + @[simp] theorem contains_insertMany_list [EquivBEq α] [LawfulHashable α] {l : List α} {k : α} : @@ -527,6 +536,10 @@ theorem mem_of_mem_insertMany_list [EquivBEq α] [LawfulHashable α] k ∈ insertMany m l → k ∈ m := HashMap.mem_of_mem_insertManyIfNewUnit_list contains_eq_false +theorem mem_insertMany_of_mem [EquivBEq α] [LawfulHashable α] + {l : ρ} {k : α} : k ∈ m → k ∈ m.insertMany l := + HashMap.mem_insertManyIfNewUnit_of_mem + theorem get?_insertMany_list_of_not_mem_of_contains_eq_false [EquivBEq α] [LawfulHashable α] {l : List α} {k : α} (not_mem : ¬ k ∈ m) (contains_eq_false : l.contains k = false) : @@ -613,6 +626,10 @@ theorem size_le_size_insertMany_list [EquivBEq α] [LawfulHashable α] m.size ≤ (insertMany m l).size := HashMap.size_le_size_insertManyIfNewUnit_list +theorem size_le_size_insertMany [EquivBEq α] [LawfulHashable α] + {l : ρ} : m.size ≤ (insertMany m l).size := + HashMap.size_le_size_insertManyIfNewUnit + theorem size_insertMany_list_le [EquivBEq α] [LawfulHashable α] {l : List α} : (insertMany m l).size ≤ m.size + l.length := @@ -624,6 +641,10 @@ theorem isEmpty_insertMany_list [EquivBEq α] [LawfulHashable α] (insertMany m l).isEmpty = (m.isEmpty && l.isEmpty) := HashMap.isEmpty_insertManyIfNewUnit_list +theorem isEmpty_of_isEmpty_insertMany [EquivBEq α] [LawfulHashable α] + {l : ρ} : (insertMany m l).isEmpty → m.isEmpty := + HashMap.isEmpty_of_isEmpty_insertManyIfNewUnit + end section @@ -723,12 +744,15 @@ namespace Equiv variable {m m₁ m₂ m₃ : HashSet α} -theorem refl (m : HashSet α) : m ~m m := ⟨.rfl⟩ +@[refl, simp] theorem refl (m : HashSet α) : m ~m m := ⟨.rfl⟩ theorem rfl : m ~m m := ⟨.rfl⟩ -theorem symm : m₁ ~m m₂ → m₂ ~m m₁ +@[symm] theorem symm : m₁ ~m m₂ → m₂ ~m m₁ | ⟨h⟩ => ⟨h.symm⟩ theorem trans : m₁ ~m m₂ → m₂ ~m m₃ → m₁ ~m m₃ | ⟨h₁⟩, ⟨h₂⟩ => ⟨h₁.trans h₂⟩ + +instance instTrans : Trans (α := HashSet α) Equiv Equiv Equiv := ⟨trans⟩ + theorem comm : m₁ ~m m₂ ↔ m₂ ~m m₁ := ⟨symm, symm⟩ theorem congr_left (h : m₁ ~m m₂) : m₁ ~m m₃ ↔ m₂ ~m m₃ := ⟨h.symm.trans, h.trans⟩ theorem congr_right (h : m₁ ~m m₂) : m₃ ~m m₁ ↔ m₃ ~m m₂ := diff --git a/src/Std/Data/HashSet/Raw.lean b/src/Std/Data/HashSet/Raw.lean index 9d69422796..7b2914dd29 100644 --- a/src/Std/Data/HashSet/Raw.lean +++ b/src/Std/Data/HashSet/Raw.lean @@ -6,17 +6,17 @@ Authors: Markus Himmel prelude import Std.Data.HashMap.Raw -/- +/-! # Hash sets with unbundled well-formedness invariant -This module develops the type `Std.Data.HashSet.Raw` of dependent hash -set with unbundled well-formedness invariant. +This module develops the type `Std.HashSet.Raw` of hash sets with +unbundled well-formedness invariant. This version is safe to use in nested inductive types. The well-formedness predicate is -available as `Std.Data.HashSet.Raw.WF` and we prove in this file that all operations preserve +available as `Std.HashSet.Raw.WF` and we prove in this file that all operations preserve well-formedness. When in doubt, prefer `HashSet` over `HashSet.Raw`. -Lemmas about the operations on `Std.Data.HashSet.Raw` are available in the module +Lemmas about the operations on `Std.HashSet.Raw` are available in the module `Std.Data.HashSet.RawLemmas`. -/ diff --git a/src/Std/Data/HashSet/RawLemmas.lean b/src/Std/Data/HashSet/RawLemmas.lean index 57005af7a3..a220b40a56 100644 --- a/src/Std/Data/HashSet/RawLemmas.lean +++ b/src/Std/Data/HashSet/RawLemmas.lean @@ -521,6 +521,8 @@ theorem forIn_eq_forIn_toList [Monad m'] [LawfulMonad m'] (h : m.WF) end monadic +variable {ρ : Type v} [ForIn Id ρ α] + @[simp] theorem insertMany_nil (h : m.WF) : insertMany m [] = m := @@ -535,6 +537,13 @@ theorem insertMany_cons (h : m.WF) {l : List α} {k : α} : insertMany m (k :: l) = insertMany (m.insert k) l := ext (HashMap.Raw.insertManyIfNewUnit_cons h.1) +@[elab_as_elim] +theorem insertMany_ind {motive : Raw α → Prop} (m : Raw α) (l : ρ) + (init : motive m) (insert : ∀ m a, motive m → motive (m.insert a)) : + motive (insertMany m l) := + show motive ⟨m.1.insertManyIfNewUnit l⟩ from + HashMap.Raw.insertManyIfNewUnit_ind m.inner l init fun m => insert ⟨m⟩ + @[simp] theorem contains_insertMany_list [EquivBEq α] [LawfulHashable α] (h : m.WF) {l : List α} {k : α} : @@ -552,6 +561,10 @@ theorem mem_of_mem_insertMany_list [EquivBEq α] [LawfulHashable α] (h : m.WF) k ∈ insertMany m l → k ∈ m := HashMap.Raw.mem_of_mem_insertManyIfNewUnit_list h.1 contains_eq_false +theorem mem_insertMany_of_mem [EquivBEq α] [LawfulHashable α] (h : m.WF) + {l : ρ} {k : α} : k ∈ m → k ∈ insertMany m l := + HashMap.Raw.mem_insertManyIfNewUnit_of_mem h.out + theorem get?_insertMany_list_of_not_mem_of_contains_eq_false [EquivBEq α] [LawfulHashable α] (h : m.WF) {l : List α} {k : α} (not_mem : ¬ k ∈ m) (contains_eq_false : l.contains k = false) : @@ -638,6 +651,10 @@ theorem size_le_size_insertMany_list [EquivBEq α] [LawfulHashable α] (h : m.WF m.size ≤ (insertMany m l).size := HashMap.Raw.size_le_size_insertManyIfNewUnit_list h.1 +theorem size_le_size_insertMany [EquivBEq α] [LawfulHashable α] (h : m.WF) + {l : ρ} : m.size ≤ (insertMany m l).size := + HashMap.Raw.size_le_size_insertManyIfNewUnit h.out + theorem size_insertMany_list_le [EquivBEq α] [LawfulHashable α] (h : m.WF) {l : List α} : (insertMany m l).size ≤ m.size + l.length := @@ -649,6 +666,10 @@ theorem isEmpty_insertMany_list [EquivBEq α] [LawfulHashable α] (h : m.WF) (insertMany m l).isEmpty = (m.isEmpty && l.isEmpty) := HashMap.Raw.isEmpty_insertManyIfNewUnit_list h.1 +theorem isEmpty_of_isEmpty_insertMany [EquivBEq α] [LawfulHashable α] (h : m.WF) + {l : ρ} : (insertMany m l).isEmpty → m.isEmpty := + HashMap.Raw.isEmpty_of_isEmpty_insertManyIfNewUnit h.out + @[simp] theorem ofList_nil : ofList ([] : List α) = ∅ := @@ -744,12 +765,15 @@ section Raw variable {α : Type u} {β : Type v} {m m₁ m₂ m₃ : Raw α} -theorem refl (m : Raw α) : m ~m m := ⟨.rfl⟩ +@[refl, simp] theorem refl (m : Raw α) : m ~m m := ⟨.rfl⟩ theorem rfl : m ~m m := ⟨.rfl⟩ -theorem symm : m₁ ~m m₂ → m₂ ~m m₁ +@[symm] theorem symm : m₁ ~m m₂ → m₂ ~m m₁ | ⟨h⟩ => ⟨h.symm⟩ theorem trans : m₁ ~m m₂ → m₂ ~m m₃ → m₁ ~m m₃ | ⟨h₁⟩, ⟨h₂⟩ => ⟨h₁.trans h₂⟩ + +instance instTrans : Trans (α := Raw α) Equiv Equiv Equiv := ⟨trans⟩ + theorem comm : m₁ ~m m₂ ↔ m₂ ~m m₁ := ⟨symm, symm⟩ theorem congr_left (h : m₁ ~m m₂) : m₁ ~m m₃ ↔ m₂ ~m m₃ := ⟨h.symm.trans, h.trans⟩ theorem congr_right (h : m₁ ~m m₂) : m₃ ~m m₁ ↔ m₃ ~m m₂ := diff --git a/src/Std/Data/Internal/List/Associative.lean b/src/Std/Data/Internal/List/Associative.lean index 21bbc749a6..af8dab8e8c 100644 --- a/src/Std/Data/Internal/List/Associative.lean +++ b/src/Std/Data/Internal/List/Associative.lean @@ -2229,24 +2229,32 @@ theorem getValueCast?_ext [BEq α] [LawfulBEq α] {l l' : List ((a : α) × β a intro a simp only [getEntry?_eq_getValueCast?, h] -theorem getKey?_getValue?_ext [BEq α] [EquivBEq α] {β : Type v} +theorem getKey_getValue?_ext [BEq α] [EquivBEq α] {β : Type v} {l l' : List ((_ : α) × β)} (hl : DistinctKeys l) (hl' : DistinctKeys l') - (hk : ∀ a, getKey? a l = getKey? a l') (hv : ∀ a, getValue? a l = getValue? a l') : + (hk : ∀ a h h', getKey a l h = getKey a l' h') (hv : ∀ a, getValue? a l = getValue? a l') : Perm l l' := by apply getEntry?_ext hl hl' intro a specialize hk a; specialize hv a by_cases h' : containsKey a l' - · simp only [getKey?_eq_some_getKey h'] at hk - have h'' := containsKey_eq_isSome_getKey?.trans (hk ▸ rfl : (getKey? a l).isSome = true) - simp only [getKey?_eq_some_getKey, getValue?_eq_some_getValue, - getEntry?_eq_some_getEntry, h', h'', Option.some.injEq, - getEntry_eq_getKey_getValue, Sigma.mk.injEq] at hk hv ⊢ - exact ⟨hk, hv ▸ .rfl⟩ - · simp only [getKey?_eq_none, h'] at hk - have h'' := containsKey_eq_isSome_getKey?.trans (hk ▸ rfl : (getKey? a l).isSome = false) + · simp only [getValue?_eq_some_getValue h'] at hv + have h'' := containsKey_eq_isSome_getValue?.trans (hv ▸ rfl : (getValue? a l).isSome = true) + specialize hk h'' h' + simp only [getEntry?_eq_some_getEntry, h', h'', getEntry_eq_getKey_getValue, Sigma.mk.injEq] + simp only [getValue?_eq_some_getValue h'', Option.some.injEq] at hv + rw [hk, hv] + · simp only [getValue?_eq_none.mpr, h'] at hv + have h'' := containsKey_eq_isSome_getValue?.trans (hv ▸ rfl : (getValue? a l).isSome = false) simp only [getEntry?_eq_none.mpr, h', h''] +theorem getKey?_getValue?_ext [BEq α] [EquivBEq α] {β : Type v} + {l l' : List ((_ : α) × β)} (hl : DistinctKeys l) (hl' : DistinctKeys l') + (hk : ∀ a, getKey? a l = getKey? a l') (hv : ∀ a, getValue? a l = getValue? a l') : + Perm l l' := by + refine getKey_getValue?_ext hl hl' ?_ hv + intro a ha ha' + simp only [getKey, hk] + theorem getKey?_ext [BEq α] [EquivBEq α] {l l' : List ((_ : α) × Unit)} (hl : DistinctKeys l) (hl' : DistinctKeys l') (h : ∀ a, getKey? a l = getKey? a l') : Perm l l' := by