feat: extensional hash maps (#8004)

This PR adds extensional hash maps and hash sets under the names
`Std.ExtDHashMap`, `Std.ExtHashMap` and `Std.ExtHashSet`. Extensional
hash maps work like regular hash maps, except that they have
extensionality lemmas which make them easier to use in proofs. This
however makes it also impossible to regularly iterate over its entries.
This commit is contained in:
Rob23oba 2025-04-28 08:48:25 +02:00 committed by GitHub
parent 2ba021ecc2
commit 747ea853b5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
25 changed files with 7477 additions and 59 deletions

View file

@ -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)

View file

@ -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

View file

@ -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 }

View file

@ -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

View file

@ -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 :=

View file

@ -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`.
-/

View file

@ -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

View file

@ -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

View file

@ -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

File diff suppressed because it is too large Load diff

View file

@ -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

View file

@ -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

File diff suppressed because it is too large Load diff

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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₂ :=

View file

@ -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`.
-/

View file

@ -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) :

View file

@ -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

View file

@ -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₂ :=

View file

@ -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`.
-/

View file

@ -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₂ :=

View file

@ -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