Skip to content

Commit 799d594

Browse files
wkrozowskiTwoFX
andauthored
feat: add difference on DHashMap/HashMap/HashSet (#11212)
This PR adds support for difference operation for `DHashMap`/`HashMap`/`HashSet` and proves several lemmas about it. --------- Co-authored-by: Markus Himmel <[email protected]>
1 parent 586ea55 commit 799d594

File tree

18 files changed

+2955
-13
lines changed

18 files changed

+2955
-13
lines changed

src/Std/Data/DHashMap/Basic.lean

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,8 +346,19 @@ This function always iterates through the smaller map, so the expected runtime i
346346
inner := Raw₀.inter ⟨m₁.1, m₁.2.size_buckets_pos⟩ ⟨m₂.1, m₂.2.size_buckets_pos⟩
347347
wf := Std.DHashMap.Raw.WF.inter₀ m₁.2 m₂.2
348348

349+
/--
350+
Computes the difference of the given hash maps.
351+
352+
This function always iterates through the smaller map, so the expected runtime is
353+
`O(min(m₁.size, m₂.size))`.
354+
-/
355+
@[inline] def diff [BEq α] [Hashable α] (m₁ m₂ : DHashMap α β) : DHashMap α β where
356+
inner := Raw₀.diff ⟨m₁.1, m₁.2.size_buckets_pos⟩ ⟨m₂.1, m₂.2.size_buckets_pos⟩
357+
wf := Std.DHashMap.Raw.WF.diff₀ m₁.2 m₂.2
358+
349359
instance [BEq α] [Hashable α] : Union (DHashMap α β) := ⟨union⟩
350360
instance [BEq α] [Hashable α] : Inter (DHashMap α β) := ⟨inter⟩
361+
instance [BEq α] [Hashable α] : SDiff (DHashMap α β) := ⟨diff⟩
351362

352363
section Unverified
353364

src/Std/Data/DHashMap/Internal/Defs.lean

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -451,6 +451,16 @@ def insertMany {ρ : Type w} [ForIn Id ρ ((a : α) × β a)] [BEq α] [Hashable
451451
r := ⟨r.1.insert a b, fun _ h hm => h (r.2 _ h hm)⟩
452452
return r
453453

454+
/-- Internal implementation detail of the hash map -/
455+
def eraseManyEntries {ρ : Type w} [ForIn Id ρ ((a : α) × β a)] [BEq α] [Hashable α]
456+
(m : Raw₀ α β) (l : ρ) : { m' : Raw₀ α β // ∀ (P : Raw₀ α β → Prop),
457+
(∀ {m'' a}, P m'' → P (m''.erase a)) → P m → P m' } := Id.run do
458+
let mut r : { m' : Raw₀ α β // ∀ (P : Raw₀ α β → Prop),
459+
(∀ {m'' a}, P m'' → P (m''.erase a)) → P m → P m' } := ⟨m, fun _ _ => id⟩
460+
for ⟨a, _⟩ in l do
461+
r := ⟨r.1.erase a, fun _ h hm => h (r.2 _ h hm)⟩
462+
return r
463+
454464
/-- Internal implementation detail of the hash map -/
455465
@[inline] def insertManyIfNew {ρ : Type w} [ForIn Id ρ ((a : α) × β a)] [BEq α] [Hashable α]
456466
(m : Raw₀ α β) (l : ρ) : { m' : Raw₀ α β // ∀ (P : Raw₀ α β → Prop),
@@ -480,6 +490,11 @@ def interSmaller [BEq α] [Hashable α] (m₁ : Raw₀ α β) (m₂ : Raw α β)
480490
def inter [BEq α] [Hashable α] (m₁ m₂ : Raw₀ α β) : Raw₀ α β :=
481491
if m₁.1.size ≤ m₂.1.size then m₁.filter fun k _ => m₂.contains k else interSmaller m₁ m₂
482492

493+
/-- Internal implementation detail of the hash map -/
494+
@[inline] def diff [BEq α] [Hashable α] (m₁ m₂ : Raw₀ α β) : Raw₀ α β :=
495+
if m₁.1.size ≤ m₂.1.size then m₁.filter (fun k _ => !m₂.contains k) else (eraseManyEntries m₁ m₂.1).1
496+
497+
483498
section
484499

485500
variable {β : Type v}

src/Std/Data/DHashMap/Internal/Model.lean

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -407,6 +407,19 @@ def insertListₘ [BEq α] [Hashable α] (m : Raw₀ α β) (l : List ((a : α)
407407
| .nil => m
408408
| .cons hd tl => insertListₘ (m.insert hd.1 hd.2) tl
409409

410+
/-- Internal implementation detail of the hash map -/
411+
def eraseListₘ [BEq α] [Hashable α] (m : Raw₀ α β) (l : List α) : Raw₀ α β :=
412+
match l with
413+
| .nil => m
414+
| .cons hd tl => eraseListₘ (m.erase hd) tl
415+
416+
/-- Internal implementation detail of the hash map -/
417+
def diffₘ [BEq α] [Hashable α] (m₁ m₂ : Raw₀ α β) : Raw₀ α β :=
418+
if m₁.1.size ≤ m₂.1.size then
419+
filterₘ m₁ (fun k _ => !containsₘ m₂ k)
420+
else
421+
eraseManyEntries m₁ (toListModel m₂.1.buckets)
422+
410423
/-- Internal implementation detail of the hash map -/
411424
def insertListIfNewₘ [BEq α] [Hashable α] (m : Raw₀ α β) (l : List ((a : α) × β a)) : Raw₀ α β :=
412425
match l with
@@ -656,6 +669,20 @@ theorem insertMany_eq_insertListₘ [BEq α] [Hashable α] (m : Raw₀ α β) (l
656669
simp only [List.foldl_cons, insertListₘ]
657670
apply ih
658671

672+
theorem eraseManyEntries_eq_eraseListₘ [BEq α] [Hashable α] (m : Raw₀ α β) (l : List ((a : α) × β a)) :
673+
eraseManyEntries m l = eraseListₘ m (l.map (·.1)) := by
674+
simp only [eraseManyEntries, Id.run_pure, pure_bind, List.forIn_pure_yield_eq_foldl]
675+
suffices ∀ (t : { m' // ∀ (P : Raw₀ α β → Prop),
676+
(∀ {m'' : Raw₀ α β} {a : α}, P m'' → P (m''.erase a)) → P m → P m' }),
677+
(List.foldl (fun m' p => ⟨m'.val.erase p.1, fun P h₁ h₂ => h₁ (m'.2 _ h₁ h₂)⟩) t l).val =
678+
t.val.eraseListₘ (l.map (·.1)) from this _
679+
intro t
680+
induction l generalizing m with
681+
| nil => simp [eraseListₘ]
682+
| cons hd tl ih =>
683+
simp only [List.foldl_cons]
684+
apply ih
685+
659686
theorem insertManyIfNew_eq_insertListIfNewₘ [BEq α] [Hashable α] (m : Raw₀ α β) (l : List ((a : α) × β a)) :
660687
insertManyIfNew m l = insertListIfNewₘ m l := by
661688
simp only [insertManyIfNew, Id.run_pure, pure_bind, List.forIn_pure_yield_eq_foldl]

src/Std/Data/DHashMap/Internal/Raw.lean

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,10 @@ theorem inter_eq [BEq α] [Hashable α] {m₁ m₂ : Raw α β} (h₁ : m₁.WF)
154154
m₁.inter m₂ = Raw₀.inter ⟨m₁, h₁.size_buckets_pos⟩ ⟨m₂, h₂.size_buckets_pos⟩ := by
155155
simp [Raw.inter, h₁.size_buckets_pos, h₂.size_buckets_pos]
156156

157+
theorem diff_eq [BEq α] [Hashable α] {m₁ m₂ : Raw α β} (h₁ : m₁.WF) (h₂ : m₂.WF) :
158+
m₁.diff m₂ = Raw₀.diff ⟨m₁, h₁.size_buckets_pos⟩ ⟨m₂, h₂.size_buckets_pos⟩ := by
159+
simp [Raw.diff, h₁.size_buckets_pos, h₂.size_buckets_pos]
160+
157161
section
158162

159163
variable {β : Type v}

0 commit comments

Comments
 (0)