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:
parent
2ba021ecc2
commit
747ea853b5
25 changed files with 7477 additions and 59 deletions
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 }
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 :=
|
||||
|
|
|
|||
|
|
@ -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`.
|
||||
-/
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
8
src/Std/Data/ExtDHashMap.lean
Normal file
8
src/Std/Data/ExtDHashMap.lean
Normal 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
|
||||
337
src/Std/Data/ExtDHashMap/Basic.lean
Normal file
337
src/Std/Data/ExtDHashMap/Basic.lean
Normal 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
|
||||
3289
src/Std/Data/ExtDHashMap/Lemmas.lean
Normal file
3289
src/Std/Data/ExtDHashMap/Lemmas.lean
Normal file
File diff suppressed because it is too large
Load diff
8
src/Std/Data/ExtHashMap.lean
Normal file
8
src/Std/Data/ExtHashMap.lean
Normal 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
|
||||
248
src/Std/Data/ExtHashMap/Basic.lean
Normal file
248
src/Std/Data/ExtHashMap/Basic.lean
Normal 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
|
||||
2116
src/Std/Data/ExtHashMap/Lemmas.lean
Normal file
2116
src/Std/Data/ExtHashMap/Lemmas.lean
Normal file
File diff suppressed because it is too large
Load diff
8
src/Std/Data/ExtHashSet.lean
Normal file
8
src/Std/Data/ExtHashSet.lean
Normal 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
|
||||
202
src/Std/Data/ExtHashSet/Basic.lean
Normal file
202
src/Std/Data/ExtHashSet/Basic.lean
Normal 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
|
||||
694
src/Std/Data/ExtHashSet/Lemmas.lean
Normal file
694
src/Std/Data/ExtHashSet/Lemmas.lean
Normal 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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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₂ :=
|
||||
|
|
|
|||
|
|
@ -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`.
|
||||
-/
|
||||
|
||||
|
|
|
|||
|
|
@ -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) :
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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₂ :=
|
||||
|
|
|
|||
|
|
@ -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`.
|
||||
-/
|
||||
|
||||
|
|
|
|||
|
|
@ -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₂ :=
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue