This PR adds `BEq` instance for `DHashMap`/`HashMap`/`HashSet` and their extensional variants and proves lemmas relating it to the equivalence of hashmaps/equality of extensional variants.
434 lines
18 KiB
Text
434 lines
18 KiB
Text
/-
|
||
Copyright (c) 2025 Robin Arnez. All rights reserved.
|
||
Released under Apache 2.0 license as described in the file LICENSE.
|
||
Authors: Robin Arnez
|
||
-/
|
||
module
|
||
|
||
prelude
|
||
public import Std.Data.DHashMap.Lemmas
|
||
import all Std.Data.DHashMap.Lemmas
|
||
|
||
public section
|
||
|
||
/-!
|
||
# 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 pairs. 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`.
|
||
-/
|
||
structure ExtDHashMap (α : Type u) (β : α → Type v) [BEq α] [Hashable α] where
|
||
/-- Internal implementation detail of the hash map. -/
|
||
mk' ::
|
||
/-- Internal implementation detail of the hash map. -/
|
||
inner : Quotient (DHashMap.isSetoid α β)
|
||
|
||
namespace ExtDHashMap
|
||
|
||
/-- Internal implementation detail of the hash map. -/
|
||
abbrev mk (m : DHashMap α β) : ExtDHashMap α β :=
|
||
mk' (.mk _ m)
|
||
|
||
/-- Internal implementation detail of the hash map. -/
|
||
def lift {γ : Sort w} (f : DHashMap α β → γ) (h : ∀ a b, a ~m b → f a = f b) (m : ExtDHashMap α β) : γ :=
|
||
m.1.lift f h
|
||
|
||
/-- Internal implementation detail of the hash map. -/
|
||
def lift₂ {γ : Sort w} (f : DHashMap α β → DHashMap α β → γ) (h : ∀ a b c d, a ~m c → b ~m d → f a b = f c d) (m₁ m₂ : ExtDHashMap α β) : γ :=
|
||
Quotient.lift₂ f h m₁.inner m₂.inner
|
||
|
||
/-- Internal implementation detail of the hash map. -/
|
||
def pliftOn {γ : Sort w} (m : ExtDHashMap α β) (f : (a : DHashMap α β) → m = mk a → γ)
|
||
(h : ∀ a b h₁ h₂, a ~m b → f a h₁ = f b h₂) : γ :=
|
||
m.1.pliftOn (fun a ha => f a (by cases m; cases ha; rfl)) (fun _ _ _ _ h' => h _ _ _ _ h')
|
||
|
||
@[induction_eliminator, cases_eliminator, elab_as_elim]
|
||
theorem inductionOn {motive : ExtDHashMap α β → Prop} (m : ExtDHashMap α β)
|
||
(mk : (a : DHashMap α β) → motive (mk a)) : motive m :=
|
||
(m.1.inductionOn fun _ => mk _ : motive ⟨m.1⟩)
|
||
|
||
@[elab_as_elim]
|
||
theorem inductionOn₂ {motive : ExtDHashMap α β → ExtDHashMap α β → Prop}
|
||
(m₁ m₂ : ExtDHashMap α β) (mk : (a b : DHashMap α β) → motive (mk a) (mk b)) : motive m₁ m₂ :=
|
||
m₁.inductionOn fun _ => m₂.inductionOn fun _ => mk _ _
|
||
|
||
theorem sound {m₁ m₂ : DHashMap α β} (h : m₁ ~m m₂) : mk m₁ = mk m₂ :=
|
||
congrArg mk' (Quotient.sound h)
|
||
|
||
theorem exact {m₁ m₂ : DHashMap α β} (h : mk m₁ = mk m₂) : m₁ ~m m₂ :=
|
||
Quotient.exact (congrArg inner h)
|
||
|
||
@[inline, inherit_doc DHashMap.emptyWithCapacity]
|
||
def emptyWithCapacity [BEq α] [Hashable α]
|
||
(capacity := 8) : ExtDHashMap α β :=
|
||
mk (DHashMap.emptyWithCapacity capacity)
|
||
|
||
instance [BEq α] [Hashable α] : EmptyCollection (ExtDHashMap α β) where
|
||
emptyCollection := emptyWithCapacity
|
||
|
||
instance [BEq α] [Hashable α] : Inhabited (ExtDHashMap α β) where
|
||
default := ∅
|
||
|
||
@[inline, inherit_doc DHashMap.insert]
|
||
def insert [EquivBEq α] [LawfulHashable α] (m : ExtDHashMap α β) (a : α)
|
||
(b : β a) : ExtDHashMap α β :=
|
||
m.lift (fun m => mk (m.insert a b))
|
||
(fun m m' (h : m ~m m') => 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 => mk (m.insertIfNew a b))
|
||
(fun m m' (h : m ~m m') => 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, mk m'.2⟩)
|
||
(fun m m' (h : m ~m m') =>
|
||
Prod.ext
|
||
(m.containsThenInsert_fst.symm ▸ m'.containsThenInsert_fst.symm ▸ h.contains_eq)
|
||
(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, mk m'.2⟩)
|
||
(fun m m' (h : m ~m m') =>
|
||
Prod.ext
|
||
(m.containsThenInsertIfNew_fst.symm ▸ m'.containsThenInsertIfNew_fst.symm ▸ h.contains_eq)
|
||
(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, mk m'.2⟩)
|
||
(fun m m' (h : m ~m m') =>
|
||
Prod.ext
|
||
(m.getThenInsertIfNew?_fst.symm ▸ m'.getThenInsertIfNew?_fst.symm ▸ h.get?_eq)
|
||
(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 => mk (m.erase a))
|
||
(fun m m' (h : m ~m m') => 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, 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)
|
||
(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 => mk (m.filter f))
|
||
(fun m m' (h : m ~m m') => sound (h.filter f))
|
||
|
||
@[inline, inherit_doc DHashMap.map]
|
||
def map [EquivBEq α] [LawfulHashable α] (f : (a : α) → β a → γ a)
|
||
(m : ExtDHashMap α β) : ExtDHashMap α γ :=
|
||
m.lift (fun m => mk (m.map f))
|
||
(fun m m' (h : m ~m m') => 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 => mk (m.filterMap f))
|
||
(fun m m' (h : m ~m m') => sound (h.filterMap f))
|
||
|
||
@[inline, inherit_doc DHashMap.modify]
|
||
def modify [LawfulBEq α] (m : ExtDHashMap α β)
|
||
(a : α) (f : β a → β a) : ExtDHashMap α β :=
|
||
m.lift (fun m => mk (m.modify a f))
|
||
(fun m m' (h : m ~m m') => 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 => mk (DHashMap.Const.modify m a f))
|
||
(fun m m' (h : m ~m m') => 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 => mk (m.alter a f))
|
||
(fun m m' (h : m ~m m') => 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 => mk (DHashMap.Const.alter m a f))
|
||
(fun m m' (h : m ~m m') => 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
|
||
|
||
@[inline, inherit_doc DHashMap.union]
|
||
def union [EquivBEq α] [LawfulHashable α] (m₁ m₂ : ExtDHashMap α β) : ExtDHashMap α β := lift₂ (fun x y : DHashMap α β => mk (x.union y))
|
||
(fun a b c d equiv₁ equiv₂ => by
|
||
simp only [DHashMap.union_eq, mk'.injEq]
|
||
apply Quotient.sound
|
||
apply DHashMap.Equiv.union_congr
|
||
. exact equiv₁
|
||
. exact equiv₂) m₁ m₂
|
||
|
||
instance [EquivBEq α] [LawfulHashable α] : Union (ExtDHashMap α β) := ⟨union⟩
|
||
|
||
instance [LawfulBEq α] [∀ k, BEq (β k)] : BEq (ExtDHashMap α β) where
|
||
beq m₁ m₂ := lift₂ (fun x y : DHashMap α β => x.beq y) (fun _ _ _ _ => DHashMap.Equiv.beq_congr) m₁ m₂
|
||
|
||
instance [LawfulBEq α] [∀ k, BEq (β k)] [∀ k, ReflBEq (β k)] : ReflBEq (ExtDHashMap α β) where
|
||
rfl {a} := a.inductionOn fun x => DHashMap.Equiv.beq <| DHashMap.Equiv.refl x
|
||
|
||
instance [LawfulBEq α] [∀ k, BEq (β k)] [∀ k, LawfulBEq (β k)] : LawfulBEq (ExtDHashMap α β) where
|
||
eq_of_beq {m₁} {m₂} := m₁.inductionOn₂ m₂ fun _ _ hyp => sound <| DHashMap.equiv_of_beq hyp
|
||
|
||
namespace Const
|
||
|
||
variable {β : Type v}
|
||
|
||
@[inline, inherit_doc DHashMap.beq]
|
||
def beq [EquivBEq α] [LawfulHashable α] [BEq β] (m₁ m₂ : ExtDHashMap α fun _ => β) : Bool :=
|
||
lift₂ (fun x y : DHashMap α fun _ => β => DHashMap.Const.beq x y) (fun _ _ _ _ => DHashMap.Const.Equiv.beq_congr) m₁ m₂
|
||
|
||
theorem beq_of_eq [EquivBEq α] [LawfulHashable α] [BEq β] [ReflBEq β] (m₁ m₂ : ExtDHashMap α fun _ => β) : m₁ = m₂ → Const.beq m₁ m₂ :=
|
||
m₁.inductionOn₂ m₂ fun _ _ h => DHashMap.Const.Equiv.beq <| exact h
|
||
|
||
theorem eq_of_beq [LawfulBEq α] [BEq β] [LawfulBEq β] (m₁ m₂ : ExtDHashMap α fun _ => β) : Const.beq m₁ m₂ → m₁ = m₂ :=
|
||
m₁.inductionOn₂ m₂ fun _ _ h => sound <| DHashMap.Const.equiv_of_beq h
|
||
|
||
end Const
|
||
|
||
@[inline, inherit_doc DHashMap.inter]
|
||
def inter [EquivBEq α] [LawfulHashable α] (m₁ m₂ : ExtDHashMap α β) : ExtDHashMap α β := lift₂ (fun x y : DHashMap α β => mk (x.inter y))
|
||
(fun a b c d equiv₁ equiv₂ => by
|
||
simp only [DHashMap.inter_eq, mk'.injEq]
|
||
apply Quotient.sound
|
||
apply DHashMap.Equiv.inter_congr
|
||
· exact equiv₁
|
||
· exact equiv₂) m₁ m₂
|
||
|
||
instance [EquivBEq α] [LawfulHashable α] : Inter (ExtDHashMap α β) := ⟨inter⟩
|
||
|
||
@[inline, inherit_doc DHashMap.diff]
|
||
def diff [EquivBEq α] [LawfulHashable α] (m₁ m₂ : ExtDHashMap α β) : ExtDHashMap α β := lift₂ (fun x y : DHashMap α β => mk (x.diff y))
|
||
(fun a b c d equiv₁ equiv₂ => by
|
||
simp only [DHashMap.diff_eq, mk'.injEq]
|
||
apply Quotient.sound
|
||
apply DHashMap.Equiv.diff_congr
|
||
· exact equiv₁
|
||
· exact equiv₂) m₁ m₂
|
||
|
||
instance [EquivBEq α] [LawfulHashable α] : SDiff (ExtDHashMap α β) := ⟨diff⟩
|
||
|
||
@[inline, inherit_doc DHashMap.Const.unitOfArray]
|
||
def Const.unitOfArray [BEq α] [Hashable α] (l : Array α) :
|
||
ExtDHashMap α (fun _ => Unit) :=
|
||
mk (DHashMap.Const.unitOfArray l)
|
||
|
||
@[inline, inherit_doc DHashMap.ofList]
|
||
def ofList [BEq α] [Hashable α] (l : List ((a : α) × β a)) :
|
||
ExtDHashMap α β :=
|
||
mk (DHashMap.ofList l)
|
||
|
||
@[inline, inherit_doc DHashMap.Const.ofList]
|
||
def Const.ofList {β : Type v} [BEq α] [Hashable α] (l : List (α × β)) :
|
||
ExtDHashMap α (fun _ => β) :=
|
||
mk (DHashMap.Const.ofList l)
|
||
|
||
@[inline, inherit_doc DHashMap.Const.unitOfList]
|
||
def Const.unitOfList [BEq α] [Hashable α] (l : List α) :
|
||
ExtDHashMap α (fun _ => Unit) :=
|
||
mk (DHashMap.Const.unitOfList l)
|
||
|
||
end ExtDHashMap
|
||
|
||
end Std
|