Skip to content

Commit d21eaeb

Browse files
authored
HumanEval12 (#205)
This PR solves problem 12.
1 parent cebb5f9 commit d21eaeb

File tree

1 file changed

+234
-3
lines changed

1 file changed

+234
-3
lines changed

HumanEvalLean/HumanEval12.lean

Lines changed: 234 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,236 @@
1-
def longest : Unit :=
2-
()
1+
module
2+
3+
open Std
4+
5+
/-!
6+
## Implementation
7+
-/
8+
9+
def argmax [LE β] [DecidableLE β] (f : α → β) (x y : α) : α :=
10+
if f y ≤ f x then x else y
11+
12+
/-
13+
`List.argmax` exists in mathlib, but:
14+
* it returns an `Option`, so it should actually be named `argmax?`
15+
* it relies on mathlib's `Preorder` type class and `DecidableLT`. In the standard library,
16+
it would be more consistent to use `LE` and `DecidableLE`.
17+
18+
Moreover, lemmas such as `List.index_of_argmax` aren't easily applicable because one would need
19+
`BEq α` and `LawfulBEq α` in order to use `idxOf`. Moreover, some API about `idxOf` and `findIdx`
20+
is still missing. In this file, we avoid these difficulties by not relying on `idxOf` and `findIdx`
21+
at all.
22+
-/
23+
def List.argmax [LE β] [DecidableLE β] (xs : List α) (f : α → β) (h : xs ≠ []) : α :=
24+
match xs with
25+
| x :: xs => xs.foldl (init := x) (_root_.argmax f)
26+
27+
def List.argmax? [LE β] [DecidableLE β] (xs : List α) (f : α → β) : Option α :=
28+
if h : xs ≠ [] then
29+
some (xs.argmax f h)
30+
else
31+
none
32+
33+
def longest? (xs : List String) : Option String :=
34+
xs.argmax? String.length
35+
36+
/-!
37+
## Tests
38+
-/
39+
40+
example : longest? [] = none := by native_decide
41+
example : longest? ["x", "y", "z"] = some "x" := by native_decide
42+
example : longest? ["x", "yyy", "zzzz", "www", "kkkk", "abc"] = some "zzzz" := by native_decide
43+
44+
/-!
45+
## Verification
46+
-/
47+
48+
@[grind =]
49+
theorem List.argmax_singleton [LE β] [DecidableLE β] {x : α} {f : α → β} :
50+
[x].argmax f (by grind) = x := by
51+
grind [argmax]
52+
53+
@[grind =]
54+
theorem argmax_assoc [LE β] [DecidableLE β] [IsLinearPreorder β] {f : α → β} {x y z : α} :
55+
argmax f (argmax f x y) z = argmax f x (argmax f y z) := by
56+
grind [argmax]
57+
58+
instance [LE β] [DecidableLE β] [IsLinearPreorder β] {f : α → β} :
59+
Associative (argmax f) where
60+
assoc := by apply argmax_assoc
61+
62+
theorem List.argmax_cons
63+
[LE β] [DecidableLE β] [IsLinearPreorder β] {x : α} {xs : List α} {f : α → β} :
64+
(x :: xs).argmax f (by grind) =
65+
if h : xs = [] then x else _root_.argmax f x (xs.argmax f h) := by
66+
simp only [argmax]
67+
match xs with
68+
| [] => simp
69+
| y :: xs => simp [foldl_assoc]
70+
71+
theorem argmax_eq_or [LE β] [DecidableLE β] {f : α → β} {x y : α} :
72+
argmax f x y = x ∨ argmax f x y = y := by
73+
grind [argmax]
74+
75+
@[grind =]
76+
theorem argmax_self [LE β] [DecidableLE β] [IsLinearPreorder β] {f : α → β} {x : α} :
77+
argmax f x x = x := by
78+
grind [argmax]
79+
80+
@[grind =]
81+
theorem argmax_eq_left [LE β] [DecidableLE β] {f : α → β} {x y : α} (h : f y ≤ f x) :
82+
argmax f x y = x := by
83+
grind [argmax]
84+
85+
@[grind =]
86+
theorem argmax_eq_right [LE β] [DecidableLE β] {f : α → β} {x y : α} (h : ¬ f y ≤ f x) :
87+
argmax f x y = y := by
88+
grind [argmax]
89+
90+
@[grind =>]
91+
theorem apply_left_le_apply_argmax [LE β] [DecidableLE β] [IsLinearPreorder β] {f : α → β}
92+
{x y : α} : f x ≤ f (argmax f x y) := by
93+
grind [argmax]
94+
95+
@[grind =>]
96+
theorem apply_right_le_apply_argmax [LE β] [DecidableLE β] [IsLinearPreorder β]
97+
{f : α → β} {x y : α} : f y ≤ f (argmax f x y) := by
98+
grind [argmax]
99+
100+
@[grind .]
101+
theorem List.argmax_mem [LE β] [DecidableLE β] [IsLinearPreorder β] {xs : List α}
102+
{f : α → β} {h : xs ≠ []} : xs.argmax f h ∈ xs := by
103+
simp only [List.argmax]
104+
match xs with
105+
| x :: xs =>
106+
fun_induction xs.foldl (init := x) (_root_.argmax f) <;> grind [argmax_eq_or]
107+
108+
@[grind =>]
109+
theorem List.le_apply_argmax_of_mem [LE β] [DecidableLE β] [IsLinearPreorder β]
110+
{xs : List α} {f : α → β} {y : α} (hx : y ∈ xs) :
111+
f y ≤ f (xs.argmax f (List.ne_nil_of_mem hx)) := by
112+
have h : xs ≠ [] := List.ne_nil_of_mem hx
113+
simp only [List.argmax]
114+
match xs with
115+
| x :: xs =>
116+
fun_induction xs.foldl (init := x) (_root_.argmax f) generalizing y <;> grind
117+
118+
@[grind =]
119+
theorem List.argmax_append [LE β] [DecidableLE β] [IsLinearPreorder β] {xs ys : List α}
120+
{f : α → β} (hxs : xs ≠ []) (hys : ys ≠ []) :
121+
(xs ++ ys).argmax f (by simp [hxs]) = _root_.argmax f (xs.argmax f hxs) (ys.argmax f hys) := by
122+
match xs, ys with
123+
| x :: xs, y :: ys => simp [argmax, foldl_assoc]
124+
125+
/--
126+
`List.argmax xs f h` comes before any other element in `xs` where `f` attains its maximum.
127+
-/
128+
theorem List.argmax_left_leaning
129+
[LE β] [DecidableLE β] [IsLinearPreorder β] {xs : List α} {f : α → β} (h : xs ≠ []) :
130+
∃ j : Fin xs.length, xs[j] = xs.argmax f h ∧
131+
∀ i : Fin j, ¬ f (xs.argmax f h) ≤ f xs[i] := by
132+
simp only [List.argmax]
133+
match xs with
134+
| x :: xs =>
135+
simp only
136+
clear h
137+
fun_induction xs.foldl (init := x) (_root_.argmax f)
138+
· exact ⟨⟨0, by grind⟩, by grind⟩
139+
· rename_i x y xs ih
140+
obtain ⟨j, ih⟩ := ih
141+
by_cases hj : j.val = 0
142+
· by_cases hm : f y ≤ f x
143+
· exact ⟨⟨0, by grind⟩, by grind⟩
144+
· exact ⟨⟨1, by grind⟩, by grind⟩
145+
· refine ⟨⟨j + 1, by grind⟩, ?_⟩
146+
obtain ⟨j, _⟩ := Nat.exists_eq_succ_of_ne_zero hj
147+
apply And.intro
148+
· grind
149+
· intro i hi
150+
have : i.val ≥ 2 := by have := ih.20, by grind⟩; grind
151+
obtain ⟨i, _⟩ := Nat.exists_eq_add_of_le this
152+
have := ih.2 ⟨i + 1, by grind⟩
153+
grind
154+
155+
/-- `List.argmax?` returns `none` when applied to an empty list. -/
156+
@[grind =]
157+
theorem List.argmax?_nil [LE β] [DecidableLE β] {f : α → β} :
158+
([] : List α).argmax? f = none := by
159+
simp [argmax?]
160+
161+
@[grind =]
162+
theorem List.argmax?_cons
163+
[LE β] [DecidableLE β] [IsLinearPreorder β] {f : α → β} {x : α} {xs : List α} :
164+
(x :: xs).argmax? f = (xs.argmax? f).elim x (_root_.argmax f x) := by
165+
grind [argmax?, argmax_cons]
166+
167+
@[grind =>]
168+
theorem List.isSome_argmax?_of_mem
169+
[LE β] [DecidableLE β] {f : α → β} {xs : List α} {x : α} (h : x ∈ xs) :
170+
(xs.argmax? f).isSome := by
171+
grind [argmax?]
172+
173+
theorem List.le_apply_argmax?_get_of_mem
174+
[LE β] [DecidableLE β] [IsLinearPreorder β] {f : α → β} {xs : List α} {x : α} (h : x ∈ xs) :
175+
f x ≤ f ((xs.argmax? f).get (isSome_argmax?_of_mem h)) := by
176+
grind [argmax?]
177+
178+
-- The suggested patterns are not useful because all involve `IsLinearPreorder`.
179+
grind_pattern List.le_apply_argmax?_get_of_mem => x ∈ xs, (xs.argmax? f).get _
180+
181+
theorem List.argmax?_left_leaning [LE β] [DecidableLE β] [IsLinearPreorder β] {xs : List α} {f : α → β} {x : α}
182+
(hx : xs.argmax? f = some x) :
183+
∃ j : Fin xs.length, xs[j] = x ∧ ∀ i : Fin j, ¬ f x ≤ f xs[i] := by
184+
simp only [argmax?] at hx
185+
split at hx
186+
· simp only [Option.some.injEq] at hx
187+
rw [← hx]
188+
apply argmax_left_leaning
189+
· grind
190+
191+
@[grind =]
192+
theorem List.argmax?_append [LE β] [DecidableLE β] [IsLinearPreorder β] (xs ys : List α) (f : α → β) :
193+
(xs ++ ys).argmax? f =
194+
(xs.argmax? f).merge (_root_.argmax f) (ys.argmax? f) := by
195+
grind [argmax?, append_eq_nil_iff]
196+
197+
/-!
198+
### Main theorems
199+
200+
The following theorems verify important properties of `longest?`.
201+
The requirements from the prompt are verified by `le_length_longest?_get_of_mem` and
202+
`longest?_left_leaning`.
203+
204+
Some other useful properties are proved by the remaining lemmas.
205+
-/
206+
207+
theorem longest?_nil : longest? [] = none := by
208+
grind [longest?]
209+
210+
theorem longest?_singleton : longest? [x] = some x := by
211+
grind [longest?]
212+
213+
theorem longest?_append {xs ys : List String} :
214+
longest? (xs ++ ys) = (longest? xs).merge (_root_.argmax String.length) (longest? ys) := by
215+
grind [longest?]
216+
217+
theorem isSome_longest?_of_mem {xs : List String} {x : String} (h : x ∈ xs) :
218+
(longest? xs).isSome := by
219+
grind [longest?]
220+
221+
theorem le_length_longest?_get_of_mem {xs : List String} {x : String} (h : x ∈ xs) :
222+
x.length ≤ ((longest? xs).get (isSome_longest?_of_mem h)).length := by
223+
grind [longest?]
224+
225+
/--
226+
`longest?` returns the first string with maximum length: any other string with maximum length
227+
appears at an index greater than the returned string's index.
228+
-/
229+
theorem longest?_left_leaning {xs : List String} {x : String} (h : longest? xs = some x) :
230+
∃ j : Fin xs.length, xs[j] = x ∧ ∀ i : Fin j, xs[i].length < x.length := by
231+
rw [longest?] at h
232+
have := List.argmax?_left_leaning h
233+
grind
3234

4235
/-!
5236
## Prompt
@@ -48,4 +279,4 @@ def check(candidate):
48279
assert candidate(['x', 'y', 'z']) == 'x'
49280
assert candidate(['x', 'yyy', 'zzzz', 'www', 'kkkk', 'abc']) == 'zzzz'
50281
```
51-
-/
282+
-/

0 commit comments

Comments
 (0)