Skip to content

Commit 8c9644f

Browse files
hargoniXtobiasgrosser
authored andcommitted
feat: (DHashMap|HashMap|HashSet).(getKey?|getKey|getKey!|getKeyD) (leanprover#5244)
1 parent 1b4956b commit 8c9644f

File tree

20 files changed

+1872
-11
lines changed

20 files changed

+1872
-11
lines changed

src/Std/Data/DHashMap/Basic.lean

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,18 @@ variable {β : Type v}
152152

153153
end
154154

155+
@[inline, inherit_doc Raw.getKey?] def getKey? (m : DHashMap α β) (a : α) : Option α :=
156+
Raw₀.getKey? ⟨m.1, m.2.size_buckets_pos⟩ a
157+
158+
@[inline, inherit_doc Raw.getKey] def getKey (m : DHashMap α β) (a : α) (h : a ∈ m) : α :=
159+
Raw₀.getKey ⟨m.1, m.2.size_buckets_pos⟩ a h
160+
161+
@[inline, inherit_doc Raw.getKey!] def getKey! [Inhabited α] (m : DHashMap α β) (a : α) : α :=
162+
Raw₀.getKey! ⟨m.1, m.2.size_buckets_pos⟩ a
163+
164+
@[inline, inherit_doc Raw.getKeyD] def getKeyD (m : DHashMap α β) (a : α) (fallback : α) : α :=
165+
Raw₀.getKeyD ⟨m.1, m.2.size_buckets_pos⟩ a fallback
166+
155167
@[inline, inherit_doc Raw.size] def size (m : DHashMap α β) : Nat :=
156168
m.1.size
157169

src/Std/Data/DHashMap/Internal/AssocList/Basic.lean

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,16 +102,31 @@ def getCast [BEq α] [LawfulBEq α] (a : α) : (l : AssocList α β) → l.conta
102102
| cons k v es, h => if hka : k == a then cast (congrArg β (eq_of_beq hka)) v
103103
else es.getCast a (by rw [← h, contains, Bool.of_not_eq_true hka, Bool.false_or])
104104

105+
/-- Internal implementation detail of the hash map -/
106+
def getKey [BEq α] (a : α) : (l : AssocList α β) → l.contains a → α
107+
| cons k _ es, h => if hka : k == a then k
108+
else es.getKey a (by rw [← h, contains, Bool.of_not_eq_true hka, Bool.false_or])
109+
105110
/-- Internal implementation detail of the hash map -/
106111
def getCast! [BEq α] [LawfulBEq α] (a : α) [Inhabited (β a)] : AssocList α β → β a
107112
| nil => panic! "key is not present in hash table"
108113
| cons k v es => if h : k == a then cast (congrArg β (eq_of_beq h)) v else es.getCast! a
109114

115+
/-- Internal implementation detail of the hash map -/
116+
def getKey? [BEq α] (a : α) : AssocList α β → Option α
117+
| nil => none
118+
| cons k _ es => if k == a then some k else es.getKey? a
119+
110120
/-- Internal implementation detail of the hash map -/
111121
def get! {β : Type v} [BEq α] [Inhabited β] (a : α) : AssocList α (fun _ => β) → β
112122
| nil => panic! "key is not present in hash table"
113123
| cons k v es => bif k == a then v else es.get! a
114124

125+
/-- Internal implementation detail of the hash map -/
126+
def getKey! [BEq α] [Inhabited α] (a : α) : AssocList α β → α
127+
| nil => panic! "key is not present in hash table"
128+
| cons k _ es => if k == a then k else es.getKey! a
129+
115130
/-- Internal implementation detail of the hash map -/
116131
def getCastD [BEq α] [LawfulBEq α] (a : α) (fallback : β a) : AssocList α β → β a
117132
| nil => fallback
@@ -123,6 +138,11 @@ def getD {β : Type v} [BEq α] (a : α) (fallback : β) : AssocList α (fun _ =
123138
| nil => fallback
124139
| cons k v es => bif k == a then v else es.getD a fallback
125140

141+
/-- Internal implementation detail of the hash map -/
142+
def getKeyD [BEq α] (a : α) (fallback : α) : AssocList α β → α
143+
| nil => fallback
144+
| cons k _ es => if k == a then k else es.getKeyD a fallback
145+
126146
/-- Internal implementation detail of the hash map -/
127147
def replace [BEq α] (a : α) (b : β a) : AssocList α β → AssocList α β
128148
| nil => nil

src/Std/Data/DHashMap/Internal/AssocList/Lemmas.lean

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,32 @@ theorem get!_eq {β : Type v} [BEq α] [Inhabited β] {l : AssocList α (fun _ =
112112
· simp_all [get!, List.getValue!, List.getValue!, List.getValue?_cons,
113113
Bool.apply_cond Option.get!]
114114

115+
@[simp]
116+
theorem getKey?_eq [BEq α] {l : AssocList α β} {a : α} :
117+
l.getKey? a = List.getKey? a l.toList := by
118+
induction l <;> simp_all [getKey?]
119+
120+
@[simp]
121+
theorem getKey_eq [BEq α] {l : AssocList α β} {a : α} {h} :
122+
l.getKey a h = List.getKey a l.toList (contains_eq.symm.trans h) := by
123+
induction l
124+
· simp [contains] at h
125+
· next k v t ih => simp only [getKey, toList_cons, List.getKey_cons, ih]
126+
127+
@[simp]
128+
theorem getKeyD_eq [BEq α] {l : AssocList α β} {a fallback : α} :
129+
l.getKeyD a fallback = List.getKeyD a l.toList fallback := by
130+
induction l
131+
· simp [getKeyD, List.getKeyD]
132+
· simp_all [getKeyD, List.getKeyD, Bool.apply_cond (fun x => Option.getD x fallback)]
133+
134+
@[simp]
135+
theorem getKey!_eq [BEq α] [Inhabited α] {l : AssocList α β} {a : α} :
136+
l.getKey! a = List.getKey! a l.toList := by
137+
induction l
138+
· simp [getKey!, List.getKey!]
139+
· simp_all [getKey!, List.getKey!, Bool.apply_cond Option.get!]
140+
115141
@[simp]
116142
theorem toList_replace [BEq α] {l : AssocList α β} {a : α} {b : β a} :
117143
(l.replace a b).toList = replaceEntry a b l.toList := by

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

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -100,9 +100,9 @@ Here is a summary of the steps required to add and verify a new operation:
100100
* Connect the implementation on lists and associative lists in `Internal.AssocList.Lemmas` via a
101101
lemma `AssocList.operation_eq`.
102102
3. Write the model implementation
103-
* Write the model implementation `Raw₀.operationₘ` in `Internal.List.Model`
103+
* Write the model implementation `Raw₀.operationₘ` in `Internal.Model`
104104
* Prove that the model implementation is equal to the actual implementation in
105-
`Internal.List.Model` via a lemma `operation_eq_operationₘ`.
105+
`Internal.Model` via a lemma `operation_eq_operationₘ`.
106106
4. Verify the model implementation
107107
* In `Internal.WF`, prove `operationₘ_eq_List.operation` (for access operations) or
108108
`wfImp_operationₘ` and `toListModel_operationₘ`
@@ -121,18 +121,18 @@ Here is a summary of the steps required to add and verify a new operation:
121121
might also have to prove that your list operation is invariant under permutation and add that to
122122
the tactic.
123123
7. State and prove the user-facing lemmas
124-
* Restate all of your lemmas for `DHashMap.Raw` in `DHashMap.Lemmas` and prove them using the
124+
* Restate all of your lemmas for `DHashMap.Raw` in `DHashMap.RawLemmas` and prove them using the
125125
provided tactic after hooking in your `operation_eq` and `operation_val` from step 5.
126126
* Restate all of your lemmas for `DHashMap` in `DHashMap.Lemmas` and prove them by reducing to
127127
`Raw₀`.
128-
* Restate all of your lemmas for `HashMap.Raw` in `HashMap.Lemmas` and prove them by reducing to
128+
* Restate all of your lemmas for `HashMap.Raw` in `HashMap.RawLemmas` and prove them by reducing to
129129
`DHashMap.Raw`.
130130
* Restate all of your lemmas for `HashMap` in `HashMap.Lemmas` and prove them by reducing to
131131
`DHashMap`.
132-
* Restate all of your lemmas for `HashSet.Raw` in `HashSet.Lemmas` and prove them by reducing to
133-
`DHashSet.Raw`.
132+
* Restate all of your lemmas for `HashSet.Raw` in `HashSet.RawLemmas` and prove them by reducing to
133+
`HashMap.Raw`.
134134
* Restate all of your lemmas for `HashSet` in `HashSet.Lemmas` and prove them by reducing to
135-
`DHashSet`.
135+
`HashMap`.
136136
137137
This sounds like a lot of work (and it is if you have to add a lot of user-facing lemmas), but the
138138
framework is set up in such a way that each step is really easy and the proofs are all really short
@@ -420,6 +420,30 @@ variable {β : Type v}
420420

421421
end
422422

423+
/-- Internal implementation detail of the hash map -/
424+
@[inline] def getKey? [BEq α] [Hashable α] (m : Raw₀ α β) (a : α) : Option α :=
425+
let ⟨⟨_, buckets⟩, h⟩ := m
426+
let ⟨i, h⟩ := mkIdx buckets.size h (hash a)
427+
buckets[i].getKey? a
428+
429+
/-- Internal implementation detail of the hash map -/
430+
@[inline] def getKey [BEq α] [Hashable α] (m : Raw₀ α β) (a : α) (hma : m.contains a) : α :=
431+
let ⟨⟨_, buckets⟩, h⟩ := m
432+
let idx := mkIdx buckets.size h (hash a)
433+
buckets[idx.1].getKey a hma
434+
435+
/-- Internal implementation detail of the hash map -/
436+
@[inline] def getKeyD [BEq α] [Hashable α] (m : Raw₀ α β) (a : α) (fallback : α) : α :=
437+
let ⟨⟨_, buckets⟩, h⟩ := m
438+
let idx := mkIdx buckets.size h (hash a)
439+
buckets[idx.1].getKeyD a fallback
440+
441+
/-- Internal implementation detail of the hash map -/
442+
@[inline] def getKey! [BEq α] [Hashable α] [Inhabited α] (m : Raw₀ α β) (a : α) : α :=
443+
let ⟨⟨_, buckets⟩, h⟩ := m
444+
let idx := mkIdx buckets.size h (hash a)
445+
buckets[idx.1].getKey! a
446+
423447
end Raw₀
424448

425449
/-- Internal implementation detail of the hash map -/

0 commit comments

Comments
 (0)