Skip to content

Commit beb81cb

Browse files
committed
...
1 parent 1847054 commit beb81cb

File tree

1 file changed

+49
-72
lines changed

1 file changed

+49
-72
lines changed

HumanEvalLean/HumanEval69.lean

Lines changed: 49 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ def search (xs : List Nat) : Int :=
1717
|>.first?
1818
kv.getD (-1)
1919

20+
-- missing api
21+
2022
@[simp, grind =]
2123
theorem Std.Iter.first?_toList {α β : Type w} [Iterator α Id β] [IteratorLoop α Id Id]
2224
[Iterators.Finite α Id] [LawfulIteratorLoop α Id Id] {it : Iter (α := α) β} :
@@ -25,38 +27,6 @@ theorem Std.Iter.first?_toList {α β : Type w} [Iterator α Id β] [IteratorLoo
2527
rw [first?_eq_match_step, toList_eq_match_step]
2628
cases it.step using PlausibleIterStep.casesOn <;> simp [*]
2729

28-
theorem getElem?_frequencies {k : Nat} :
29-
(frequencies xs)[k]? = (some (xs.count k)).filter (0 < ·) := by
30-
-- We express the statement in terms of `List.foldr`, which makes the induction over `xs`
31-
-- easier because the initial tree map of the fold never changes. If the statement is expressed in
32-
-- terms of `List.foldl`, we would need to generalize the statement for general initial tree maps.
33-
rw [← List.reverse_reverse (as := xs), frequencies, List.foldl_reverse]
34-
generalize xs.reverse = xs
35-
induction xs <;> grind
36-
37-
theorem getElem_frequencies {k : Nat} {h} :
38-
(frequencies xs)[k]'h = xs.count k := by
39-
grind [getElem?_frequencies]
40-
41-
theorem mem_frequencies :
42-
x ∈ frequencies xs ↔ x ∈ xs := by
43-
rw [← TreeMap.isSome_getElem?_iff_mem, getElem?_frequencies]
44-
simp
45-
46-
theorem search_eq_neg_one (h : ∀ x, x = 0 ∨ xs.count x < x) :
47-
search xs = -1 := by
48-
simp only [search, ← Iter.first?_toList, Option.getD_eq_iff, Iter.toList_map, Iter.toList_filter,
49-
TreeMap.toList_iter]
50-
grind [List.length_filter_pos_iff, getElem?_frequencies]
51-
52-
theorem search_eq_neg_one_iff :
53-
search xs = -1 ↔ ∀ x, x = 0 ∨ xs.count x < x := by
54-
simp [search, ← Iter.first?_toList, Option.getD_eq_iff, Iter.toList_map, Iter.toList_filter,
55-
TreeMap.toList_iter, getElem?_frequencies]
56-
grind [List.length_filter_pos_iff]
57-
58-
def IsCandidate (xs : List Nat) (x : Nat) : Prop := 0 < x ∧ x ≤ xs.count x
59-
6030
theorem List.find?_eq_some_iff_of_pairwise_eq_lt {xs : List α} {cmp : α → α → Ordering}
6131
[OrientedCmp cmp] (h : xs.Pairwise (cmp · · = .lt)) :
6232
xs.find? P = some x ↔ x ∈ xs ∧ P x ∧ ∀ y ∈ xs, P y → (cmp x y).isLE := by
@@ -82,49 +52,56 @@ theorem List.find?_eq_some_iff_of_pairwise_eq_lt {xs : List α} {cmp : α → α
8252
grind
8353
grind [Ordering.ne_gt_iff_isLE]
8454

85-
theorem search_eq (h : IsCandidate xs x ∧ ∀ y, IsCandidate xs y → y ≤ x) :
86-
search xs = x := by
55+
theorem List.find?_eq_find? {xs : List α} {p q : α → Bool} (h : ∀ x ∈ xs, p x = q x) :
56+
xs.find? p = xs.find? q := by
57+
ext
58+
grind [List.find?_eq_some_iff_append]
59+
60+
theorem Option.getD_map_eq_elim {o : Option α} {f : α → β} {fallback : β} :
61+
(o.map f).getD fallback = o.elim fallback f := by
62+
cases o <;> simp
63+
64+
-- verification
65+
66+
theorem getElem?_frequencies {k : Nat} :
67+
(frequencies xs)[k]? = (some (xs.count k)).filter (0 < ·) := by
68+
-- We express the statement in terms of `List.foldr`, which makes the induction over `xs`
69+
-- easier because the initial tree map of the fold never changes. If the statement is expressed in
70+
-- terms of `List.foldl`, we would need to generalize the statement for general initial tree maps.
71+
rw [← List.reverse_reverse (as := xs), frequencies, List.foldl_reverse]
72+
generalize xs.reverse = xs
73+
induction xs <;> grind
74+
75+
theorem mem_frequencies :
76+
x ∈ frequencies xs ↔ x ∈ xs := by
77+
rw [← TreeMap.isSome_getElem?_iff_mem, getElem?_frequencies]
78+
simp
79+
80+
theorem search_eq_getD_find? :
81+
search xs = (frequencies xs |>.toList.find? (fun x => 0 < x.1 ∧ x.1 ≤ xs.count x.1) |>.map (↑·.fst) |>.getD (-1 : Int)) := by
82+
simp only [search, ← Iter.first?_toList, Iter.toList_map, Iter.toList_filter,
83+
TreeMap.toList_iter, List.head?_map]
84+
grind [List.find?_eq_find?, getElem?_frequencies]
85+
86+
theorem search_eq_neg_one_iff :
87+
search xs = -1 ↔ ∀ x, x = 0 ∨ xs.count x < x := by
88+
simp [search_eq_getD_find?, Option.getD_eq_iff, getElem?_frequencies]
89+
grind [List.length_filter_pos_iff]
90+
91+
theorem search_eq_iff_of_ne_neg_one (h : y ≠ -1) :
92+
search xs = y ↔ 0 < y ∧ y ≤ xs.count y.toNat ∧ ∀ z, 0 < z → z ≤ xs.count z → z ≤ y := by
93+
-- Prepare `OrientedCmp` instance to be used by `List.find?_eq_some_iff_of_pairwise_eq_lt`
8794
have : OrientedCmp (fun x y : Nat × Nat => compare y.1 x.1) := by
8895
constructor
8996
grind [Nat.compare_swap]
90-
simp [search, ← Iter.first?_toList, Option.getD_eq_iff, List.find?_eq_some_iff_of_pairwise_eq_lt (frequencies xs).ordered_keys_toList, Int.natCast_inj]
91-
have : x ∈ xs := by grind [IsCandidate, List.count_pos_iff]
92-
refine ⟨(frequencies xs)[x]'(by simpa [mem_frequencies]), ?_⟩
93-
grind [getElem?_frequencies, IsCandidate, Nat.isLE_compare]
94-
95-
/-
96-
Memo:
97-
98-
* grind runs into deep recursion
99-
* hard to debug and minimize
100-
101-
[grind] Diagnostics ▼
102-
[thm] E-Matching instances ▼
103-
[] getElem?_neg ↦ 1
104-
[] getElem?_pos ↦ 1
105-
[] List.getElem?_map ↦ 1
106-
[] List.getElem_of_getElem? ↦ 1
107-
[] List.length_filter_pos_iff ↦ 1
108-
109-
110-
[thm] getElem?_neg: [@getElem? #8 #7 #6 #5 #4 #2 #1]
111-
[thm] getElem?_pos: [@getElem? #8 #7 #6 #5 #4 #2 #1]
112-
[thm] List.getElem?_map: [@getElem? (List #3) `[Nat] _ _ _ (@List.map #4 _ #2 #1) #0]
113-
[thm] List.map_map: [@List.map #5 #4 #2 (@List.map #3 _ #1 #0)]
114-
[thm] List.filter_map: [@List.filter #3 #1 (@List.map #4 _ #2 #0)]
115-
[thm] List.getElem?_filter: [@getElem? (List #6) `[Nat] _ _ _ (@List.filter _ #3 #4) #2, @some _ #5]
116-
[thm] List.getElem_of_getElem?: [@getElem? (List #4) `[Nat] _ _ _ #1 #3, @some _ #2]
117-
[thm] TreeMap.length_toList: [@List.length (Prod #3 #2) (@TreeMap.toList _ _ #1 #0)]
118-
[thm] List.length_filter_le: [@List.length #2 (@List.filter _ #1 #0)]
119-
[thm] List.length_map: [@List.length #2 (@List.map #3 _ #0 #1)]
120-
[thm] List.eq_nil_of_length_eq_zero: [@List.length #2 #1]
121-
[thm] List.getElem?_eq_none: [@List.length #3 #2, @getElem? (List _) `[Nat] _ _ _ #2 #1]
122-
[thm] Option.some_le_some: [@LE.le (Option #3) _ (@some _ #1) (@some _ #0)]
123-
[thm] Option.not_some_le_none: [@LE.le (Option #2) _ (@some _ #0) (@none _)]
124-
[thm] Option.none_le: [@LE.le (Option #2) _ (@none _) #0]
125-
[thm] Option.map_some: [@Option.map #3 #2 #0 (@some _ #1)]
126-
[thm] Option.map_none: [@Option.map #2 #1 #0 (@none _)]
127-
-/
97+
simp only [search_eq_getD_find?, Option.getD_map_eq_elim, Option.elim]
98+
split <;> rename_i heq
99+
· simp only [List.find?_eq_some_iff_of_pairwise_eq_lt (frequencies xs).ordered_keys_toList,
100+
Prod.forall, TreeMap.mem_toList_iff_getElem?_eq_some, getElem?_frequencies] at heq
101+
grind [List.count_pos_iff, isLE_compare]
102+
· simp only [List.find?_eq_none, Prod.forall, TreeMap.mem_toList_iff_getElem?_eq_some,
103+
getElem?_frequencies, Option.filter_eq_some_iff, and_imp] at heq
104+
grind [mem_frequencies]
128105

129106
/-!
130107
## Prompt

0 commit comments

Comments
 (0)