Skip to content

Commit 46f9359

Browse files
jt0202luisacicolini
authored andcommitted
feat: verify toList for hash maps (leanprover#6954)
This PR verifies the `toList`function for hash maps and dependent hash maps.
1 parent eef4537 commit 46f9359

File tree

12 files changed

+617
-65
lines changed

12 files changed

+617
-65
lines changed

src/Std/Data/DHashMap/Basic.lean

+8-8
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,14 @@ end
180180
@[inline, inherit_doc Raw.keys] def keys (m : DHashMap α β) : List α :=
181181
m.1.keys
182182

183+
@[inline, inherit_doc Raw.toList] def toList (m : DHashMap α β) :
184+
List ((a : α) × β a) :=
185+
m.1.toList
186+
187+
@[inline, inherit_doc Raw.Const.toList] def Const.toList {β : Type v}
188+
(m : DHashMap α (fun _ => β)) : List (α × β) :=
189+
Raw.Const.toList m.1
190+
183191
section Unverified
184192

185193
/-! We currently do not provide lemmas for the functions below. -/
@@ -219,18 +227,10 @@ instance [BEq α] [Hashable α] : ForM m (DHashMap α β) ((a : α) × β a) whe
219227
instance [BEq α] [Hashable α] : ForIn m (DHashMap α β) ((a : α) × β a) where
220228
forIn m init f := m.forIn (fun a b acc => f ⟨a, b⟩ acc) init
221229

222-
@[inline, inherit_doc Raw.toList] def toList (m : DHashMap α β) :
223-
List ((a : α) × β a) :=
224-
m.1.toList
225-
226230
@[inline, inherit_doc Raw.toArray] def toArray (m : DHashMap α β) :
227231
Array ((a : α) × β a) :=
228232
m.1.toArray
229233

230-
@[inline, inherit_doc Raw.Const.toList] def Const.toList {β : Type v}
231-
(m : DHashMap α (fun _ => β)) : List (α × β) :=
232-
Raw.Const.toList m.1
233-
234234
@[inline, inherit_doc Raw.Const.toArray] def Const.toArray {β : Type v}
235235
(m : DHashMap α (fun _ => β)) : Array (α × β) :=
236236
Raw.Const.toArray m.1

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

+85-4
Original file line numberDiff line numberDiff line change
@@ -89,9 +89,8 @@ private def queryNames : Array Name :=
8989
``Const.get_eq_getValue, ``get!_eq_getValueCast!, ``getD_eq_getValueCastD,
9090
``Const.get!_eq_getValue!, ``Const.getD_eq_getValueD, ``getKey?_eq_getKey?,
9191
``getKey_eq_getKey, ``getKeyD_eq_getKeyD, ``getKey!_eq_getKey!,
92-
``Raw.length_keys_eq_length_keys, ``Raw.isEmpty_keys_eq_isEmpty_keys,
93-
``Raw.contains_keys_eq_contains_keys, ``Raw.mem_keys_iff_contains_keys,
94-
``Raw.pairwise_keys_iff_pairwise_keys]
92+
``Raw.toList_eq_toListModel, ``Raw.keys_eq_keys_toListModel,
93+
``Raw.Const.toList_eq_toListModel_map]
9594

9695
private def modifyMap : Std.DHashMap Name (fun _ => Name) :=
9796
.ofList
@@ -848,13 +847,95 @@ theorem contains_keys [EquivBEq α] [LawfulHashable α] (h : m.1.WF) {k : α} :
848847
@[simp]
849848
theorem mem_keys [LawfulBEq α] (h : m.1.WF) {k : α} :
850849
k ∈ m.1.keys ↔ m.contains k := by
850+
rw [← List.contains_iff]
851851
simp_to_model
852852
rw [List.containsKey_eq_keys_contains]
853853

854854
theorem distinct_keys [EquivBEq α] [LawfulHashable α] (h : m.1.WF) :
855855
m.1.keys.Pairwise (fun a b => (a == b) = false) := by
856856
simp_to_model using (Raw.WF.out h).distinct.distinct
857857

858+
theorem map_sigma_fst_toList_eq_keys [EquivBEq α] [LawfulHashable α] :
859+
m.1.toList.map Sigma.fst = m.1.keys := by
860+
simp_to_model
861+
rw [List.keys_eq_map]
862+
863+
theorem length_toList [EquivBEq α] [LawfulHashable α] (h : m.1.WF) :
864+
m.1.toList.length = m.1.size := by
865+
simp_to_model
866+
867+
theorem isEmpty_toList [EquivBEq α] [LawfulHashable α] (h : m.1.WF) :
868+
m.1.toList.isEmpty = m.1.isEmpty := by
869+
simp_to_model
870+
871+
theorem mem_toList_iff_get?_eq_some [LawfulBEq α] (h : m.1.WF)
872+
{k : α} {v : β k} :
873+
⟨k, v⟩ ∈ m.1.toList ↔ m.get? k = some v := by
874+
simp_to_model using List.mem_iff_getValueCast?_eq_some
875+
876+
theorem find?_toList_eq_some_iff_get?_eq_some [LawfulBEq α]
877+
(h : m.1.WF) {k : α} {v : β k} :
878+
m.1.toList.find? (·.1 == k) = some ⟨k, v⟩ ↔ m.get? k = some v := by
879+
simp_to_model using List.find?_eq_some_iff_getValueCast?_eq_some
880+
881+
theorem find?_toList_eq_none_iff_contains_eq_false [EquivBEq α] [LawfulHashable α]
882+
(h : m.1.WF) {k : α} :
883+
m.1.toList.find? (·.1 == k) = none ↔ m.contains k = false := by
884+
simp_to_model using List.find?_eq_none_iff_containsKey_eq_false
885+
886+
theorem distinct_keys_toList [EquivBEq α] [LawfulHashable α] (h : m.1.WF) :
887+
m.1.toList.Pairwise (fun a b => (a.1 == b.1) = false) := by
888+
simp_to_model using List.pairwise_fst_eq_false
889+
890+
namespace Const
891+
892+
variable {β : Type v} (m : Raw₀ α (fun _ => β))
893+
894+
theorem map_prod_fst_toList_eq_keys [EquivBEq α] [LawfulHashable α] :
895+
(Raw.Const.toList m.1).map Prod.fst = m.1.keys := by
896+
simp_to_model using List.map_prod_fst_map_toProd_eq_keys
897+
898+
theorem length_toList [EquivBEq α] [LawfulHashable α] (h : m.1.WF) :
899+
(Raw.Const.toList m.1).length = m.1.size := by
900+
simp_to_model using List.length_map
901+
902+
theorem isEmpty_toList [EquivBEq α] [LawfulHashable α] (h : m.1.WF) :
903+
(Raw.Const.toList m.1).isEmpty = m.1.isEmpty := by
904+
simp_to_model
905+
rw [Bool.eq_iff_iff, List.isEmpty_iff,List.isEmpty_iff, List.map_eq_nil_iff]
906+
907+
theorem mem_toList_iff_get?_eq_some [LawfulBEq α] (h : m.1.WF)
908+
{k : α} {v : β} :
909+
(k, v) ∈ Raw.Const.toList m.1 ↔ get? m k = some v := by
910+
simp_to_model using List.mem_map_toProd_iff_getValue?_eq_some
911+
912+
theorem get?_eq_some_iff_exists_beq_and_mem_toList [EquivBEq α] [LawfulHashable α] (h : m.1.WF)
913+
{k : α} {v : β} :
914+
get? m k = some v ↔ ∃ (k' : α), k == k' ∧ (k', v) ∈ Raw.Const.toList m.1 := by
915+
simp_to_model using getValue?_eq_some_iff_exists_beq_and_mem_toList
916+
917+
theorem find?_toList_eq_some_iff_getKey?_eq_some_and_get?_eq_some
918+
[EquivBEq α] [LawfulHashable α] (h : m.1.WF) {k k' : α} {v : β} :
919+
(Raw.Const.toList m.1).find? (fun a => a.1 == k) = some ⟨k', v⟩ ↔
920+
m.getKey? k = some k' ∧ get? m k = some v := by
921+
simp_to_model using List.find?_map_toProd_eq_some_iff_getKey?_eq_some_and_getValue?_eq_some
922+
923+
theorem find?_toList_eq_none_iff_contains_eq_false [EquivBEq α] [LawfulHashable α]
924+
(h : m.1.WF) {k : α} :
925+
(Raw.Const.toList m.1).find? (·.1 == k) = none ↔ m.contains k = false := by
926+
simp_to_model using List.find?_map_eq_none_iff_containsKey_eq_false
927+
928+
theorem mem_toList_iff_getKey?_eq_some_and_get?_eq_some [EquivBEq α] [LawfulHashable α]
929+
(h : m.1.WF) {k: α} {v : β} :
930+
(k, v) ∈ (Raw.Const.toList m.1) ↔ m.getKey? k = some k ∧ get? m k = some v := by
931+
simp_to_model using List.mem_map_toProd_iff_getKey?_eq_some_and_getValue?_eq_some
932+
933+
theorem distinct_keys_toList [EquivBEq α] [LawfulHashable α] (h : m.1.WF) :
934+
(Raw.Const.toList m.1).Pairwise (fun a b => (a.1 == b.1) = false) := by
935+
simp_to_model using List.pairwise_fst_eq_false_map_toProd
936+
937+
end Const
938+
858939
@[simp]
859940
theorem insertMany_nil :
860941
m.insertMany [] = m := by
@@ -1230,7 +1311,7 @@ theorem getKey?_insertManyIfNewUnit_list_of_contains [EquivBEq α] [LawfulHashab
12301311
simp_to_model [Const.insertManyIfNewUnit] using List.getKey?_insertListIfNewUnit_of_contains
12311312

12321313
theorem getKey_insertManyIfNewUnit_list_of_contains [EquivBEq α] [LawfulHashable α]
1233-
(h : m.1.WF) {l : List α} {k : α} {h'} (contains : m.contains k):
1314+
(h : m.1.WF) {l : List α} {k : α} {h'} (contains : m.contains k) :
12341315
getKey (insertManyIfNewUnit m l).1 k h' = getKey m k contains := by
12351316
simp_to_model [Const.insertManyIfNewUnit] using List.getKey_insertListIfNewUnit_of_contains
12361317

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

+12-24
Original file line numberDiff line numberDiff line change
@@ -104,37 +104,25 @@ theorem foldRev_cons {l : Raw α β} {acc : List ((a : α) × β a)} :
104104
l.foldRev (fun acc k v => ⟨k, v⟩ :: acc) acc = toListModel l.buckets ++ acc := by
105105
simp [foldRev_cons_apply]
106106

107+
theorem foldRev_cons_mk {β : Type v} {l : Raw α (fun _ => β)} {acc : List (α × β)} :
108+
l.foldRev (fun acc k v => (k, v) :: acc) acc =
109+
(toListModel l.buckets).map (fun ⟨k, v⟩ => (k, v)) ++ acc := by
110+
simp [foldRev_cons_apply]
111+
107112
theorem foldRev_cons_key {l : Raw α β} {acc : List α} :
108113
l.foldRev (fun acc k _ => k :: acc) acc = List.keys (toListModel l.buckets) ++ acc := by
109114
rw [foldRev_cons_apply, keys_eq_map]
110115

111-
theorem toList_perm_toListModel {m : Raw α β} : Perm m.toList (toListModel m.buckets) := by
116+
theorem toList_eq_toListModel {m : Raw α β} : m.toList = toListModel m.buckets := by
112117
simp [Raw.toList, foldRev_cons]
113118

114-
theorem keys_perm_keys_toListModel {m : Raw α β} :
115-
Perm m.keys (List.keys (toListModel m.buckets)) := by
116-
simp [Raw.keys, foldRev_cons_key, keys_eq_map]
117-
118-
theorem length_keys_eq_length_keys {m : Raw α β} :
119-
m.keys.length = (List.keys (toListModel m.buckets)).length :=
120-
keys_perm_keys_toListModel.length_eq
119+
theorem Const.toList_eq_toListModel_map {β : Type v} {m : Raw α (fun _ => β)} :
120+
Raw.Const.toList m = (toListModel m.buckets).map (fun ⟨k, v⟩ => ⟨k, v⟩) := by
121+
simp [Raw.Const.toList, foldRev_cons_mk]
121122

122-
theorem isEmpty_keys_eq_isEmpty_keys {m : Raw α β} :
123-
m.keys.isEmpty = (List.keys (toListModel m.buckets)).isEmpty :=
124-
keys_perm_keys_toListModel.isEmpty_eq
125-
126-
theorem contains_keys_eq_contains_keys [BEq α] {m : Raw α β} {k : α} :
127-
m.keys.contains k = (List.keys (toListModel m.buckets)).contains k :=
128-
keys_perm_keys_toListModel.contains_eq
129-
130-
theorem mem_keys_iff_contains_keys [BEq α] [LawfulBEq α] {m : Raw α β} {k : α} :
131-
k ∈ m.keys ↔ (List.keys (toListModel m.buckets)).contains k := by
132-
rw [← List.contains_iff_mem, contains_keys_eq_contains_keys]
133-
134-
theorem pairwise_keys_iff_pairwise_keys [BEq α] [PartialEquivBEq α] {m : Raw α β} :
135-
m.keys.Pairwise (fun a b => (a == b) = false) ↔
136-
(List.keys (toListModel m.buckets)).Pairwise (fun a b => (a == b) = false) :=
137-
keys_perm_keys_toListModel.pairwise_iff BEq.symm_false
123+
theorem keys_eq_keys_toListModel {m : Raw α β }:
124+
m.keys = List.keys (toListModel m.buckets) := by
125+
simp [Raw.keys, foldRev_cons_key, keys_eq_map]
138126

139127
end Raw
140128

src/Std/Data/DHashMap/Lemmas.lean

+103
Original file line numberDiff line numberDiff line change
@@ -963,6 +963,109 @@ theorem distinct_keys [EquivBEq α] [LawfulHashable α] :
963963
m.keys.Pairwise (fun a b => (a == b) = false) :=
964964
Raw₀.distinct_keys ⟨m.1, m.2.size_buckets_pos⟩ m.2
965965

966+
@[simp]
967+
theorem map_sigma_fst_toList_eq_keys [EquivBEq α] [LawfulHashable α] :
968+
m.1.toList.map Sigma.fst = m.1.keys :=
969+
Raw₀.map_sigma_fst_toList_eq_keys ⟨m.1, m.2.size_buckets_pos⟩
970+
971+
@[simp]
972+
theorem length_toList [EquivBEq α] [LawfulHashable α] :
973+
m.toList.length = m.size :=
974+
Raw₀.length_toList ⟨m.1, m.2.size_buckets_pos⟩ m.2
975+
976+
@[simp]
977+
theorem isEmpty_toList [EquivBEq α] [LawfulHashable α] :
978+
m.toList.isEmpty = m.isEmpty :=
979+
Raw₀.isEmpty_toList ⟨m.1, m.2.size_buckets_pos⟩ m.2
980+
981+
@[simp]
982+
theorem mem_toList_iff_get?_eq_some [LawfulBEq α]
983+
{k : α} {v : β k} :
984+
⟨k, v⟩ ∈ m.toList ↔ m.get? k = some v :=
985+
Raw₀.mem_toList_iff_get?_eq_some ⟨m.1, m.2.size_buckets_pos⟩ m.2
986+
987+
theorem find?_toList_eq_some_iff_get?_eq_some [LawfulBEq α]
988+
{k : α} {v : β k} :
989+
m.toList.find? (·.1 == k) = some ⟨k, v⟩ ↔ m.get? k = some v :=
990+
Raw₀.find?_toList_eq_some_iff_get?_eq_some ⟨m.1, m.2.size_buckets_pos⟩ m.2
991+
992+
theorem find?_toList_eq_none_iff_contains_eq_false [EquivBEq α] [LawfulHashable α]
993+
{k : α} :
994+
m.toList.find? (·.1 == k) = none ↔ m.contains k = false :=
995+
Raw₀.find?_toList_eq_none_iff_contains_eq_false ⟨m.1, m.2.size_buckets_pos⟩ m.2
996+
997+
@[simp]
998+
theorem find?_toList_eq_none_iff_not_mem [EquivBEq α] [LawfulHashable α]
999+
{k : α} :
1000+
m.toList.find? (·.1 == k) = none ↔ ¬ k ∈ m := by
1001+
simp only [Bool.not_eq_true, mem_iff_contains]
1002+
apply Raw₀.find?_toList_eq_none_iff_contains_eq_false ⟨m.1, m.2.size_buckets_pos⟩ m.2
1003+
1004+
theorem distinct_keys_toList [EquivBEq α] [LawfulHashable α] :
1005+
m.toList.Pairwise (fun a b => (a.1 == b.1) = false) :=
1006+
Raw₀.distinct_keys_toList ⟨m.1, m.2.size_buckets_pos⟩ m.2
1007+
1008+
namespace Const
1009+
1010+
variable {β : Type v} {m : DHashMap α (fun _ => β)}
1011+
1012+
@[simp]
1013+
theorem map_prod_fst_toList_eq_keys [EquivBEq α] [LawfulHashable α] :
1014+
(toList m).map Prod.fst = m.keys :=
1015+
Raw₀.Const.map_prod_fst_toList_eq_keys ⟨m.1, m.2.size_buckets_pos⟩
1016+
1017+
@[simp]
1018+
theorem length_toList [EquivBEq α] [LawfulHashable α] :
1019+
(toList m).length = m.size :=
1020+
Raw₀.Const.length_toList ⟨m.1, m.2.size_buckets_pos⟩ m.2
1021+
1022+
@[simp]
1023+
theorem isEmpty_toList [EquivBEq α] [LawfulHashable α] :
1024+
(toList m).isEmpty = m.isEmpty :=
1025+
Raw₀.Const.isEmpty_toList ⟨m.1, m.2.size_buckets_pos⟩ m.2
1026+
1027+
@[simp]
1028+
theorem mem_toList_iff_get?_eq_some [LawfulBEq α]
1029+
{k : α} {v : β} :
1030+
(k, v) ∈ toList m ↔ get? m k = some v :=
1031+
Raw₀.Const.mem_toList_iff_get?_eq_some ⟨m.1, m.2.size_buckets_pos⟩ m.2
1032+
1033+
@[simp]
1034+
theorem mem_toList_iff_getKey?_eq_some_and_get?_eq_some [EquivBEq α] [LawfulHashable α]
1035+
{k : α} {v : β} :
1036+
(k, v) ∈ toList m ↔ m.getKey? k = some k ∧ get? m k = some v :=
1037+
Raw₀.Const.mem_toList_iff_getKey?_eq_some_and_get?_eq_some ⟨m.1, m.2.size_buckets_pos⟩ m.2
1038+
1039+
theorem get?_eq_some_iff_exists_beq_and_mem_toList [EquivBEq α] [LawfulHashable α]
1040+
{k : α} {v : β} :
1041+
get? m k = some v ↔ ∃ (k' : α), k == k' ∧ (k', v) ∈ toList m :=
1042+
Raw₀.Const.get?_eq_some_iff_exists_beq_and_mem_toList ⟨m.1, m.2.size_buckets_pos⟩ m.2
1043+
1044+
theorem find?_toList_eq_some_iff_getKey?_eq_some_and_get?_eq_some
1045+
[EquivBEq α] [LawfulHashable α] {k k' : α} {v : β} :
1046+
(toList m).find? (fun a => a.1 == k) = some ⟨k', v⟩ ↔
1047+
m.getKey? k = some k' ∧ get? m k = some v :=
1048+
Raw₀.Const.find?_toList_eq_some_iff_getKey?_eq_some_and_get?_eq_some
1049+
⟨m.1, m.2.size_buckets_pos⟩ m.2
1050+
1051+
theorem find?_toList_eq_none_iff_contains_eq_false [EquivBEq α] [LawfulHashable α]
1052+
{k : α} :
1053+
(toList m).find? (·.1 == k) = none ↔ m.contains k = false :=
1054+
Raw₀.Const.find?_toList_eq_none_iff_contains_eq_false ⟨m.1, m.2.size_buckets_pos⟩ m.2
1055+
1056+
@[simp]
1057+
theorem find?_toList_eq_none_iff_not_mem [EquivBEq α] [LawfulHashable α]
1058+
{k : α} :
1059+
(toList m).find? (·.1 == k) = none ↔ ¬ k ∈ m := by
1060+
simp only [Bool.not_eq_true, mem_iff_contains]
1061+
apply Raw₀.Const.find?_toList_eq_none_iff_contains_eq_false ⟨m.1, m.2.size_buckets_pos⟩ m.2
1062+
1063+
theorem distinct_keys_toList [EquivBEq α] [LawfulHashable α] :
1064+
(toList m).Pairwise (fun a b => (a.1 == b.1) = false) :=
1065+
Raw₀.Const.distinct_keys_toList ⟨m.1, m.2.size_buckets_pos⟩ m.2
1066+
1067+
end Const
1068+
9661069
@[simp]
9671070
theorem insertMany_nil :
9681071
m.insertMany [] = m :=

src/Std/Data/DHashMap/Raw.lean

+10-10
Original file line numberDiff line numberDiff line change
@@ -399,18 +399,10 @@ instance : ForM m (Raw α β) ((a : α) × β a) where
399399
instance : ForIn m (Raw α β) ((a : α) × β a) where
400400
forIn m init f := m.forIn (fun a b acc => f ⟨a, b⟩ acc) init
401401

402-
/-- Transforms the hash map into a list of mappings in some order. -/
403-
@[inline] def toList (m : Raw α β) : List ((a : α) × β a) :=
404-
m.foldRev (fun acc k v => ⟨k, v⟩ :: acc) []
405-
406402
/-- Transforms the hash map into an array of mappings in some order. -/
407403
@[inline] def toArray (m : Raw α β) : Array ((a : α) × β a) :=
408404
m.fold (fun acc k v => acc.push ⟨k, v⟩) #[]
409405

410-
@[inline, inherit_doc Raw.toList] def Const.toList {β : Type v} (m : Raw α (fun _ => β)) :
411-
List (α × β) :=
412-
m.foldRev (fun acc k v => ⟨k, v⟩ :: acc) []
413-
414406
@[inline, inherit_doc Raw.toArray] def Const.toArray {β : Type v} (m : Raw α (fun _ => β)) :
415407
Array (α × β) :=
416408
m.fold (fun acc k v => acc.push ⟨k, v⟩) #[]
@@ -483,11 +475,19 @@ implementation detail.
483475
def Internal.numBuckets (m : Raw α β) : Nat :=
484476
m.buckets.size
485477

478+
end Unverified
479+
480+
/-- Transforms the hash map into a list of mappings in some order. -/
481+
@[inline] def toList (m : Raw α β) : List ((a : α) × β a) :=
482+
m.foldRev (fun acc k v => ⟨k, v⟩ :: acc) []
483+
484+
@[inline, inherit_doc Raw.toList] def Const.toList {β : Type v} (m : Raw α (fun _ => β)) :
485+
List (α × β) :=
486+
m.foldRev (fun acc k v => ⟨k, v⟩ :: acc) []
487+
486488
instance [Repr α] [(a : α) → Repr (β a)] : Repr (Raw α β) where
487489
reprPrec m prec := Repr.addAppParen ("Std.DHashMap.Raw.ofList " ++ reprArg m.toList) prec
488490

489-
end Unverified
490-
491491
/-- Returns a list of all keys present in the hash map in some order. -/
492492
@[inline] def keys (m : Raw α β) : List α :=
493493
m.foldRev (fun acc k _ => k :: acc) []

0 commit comments

Comments
 (0)