Skip to content

Commit 8a09a13

Browse files
authored
HumanEval114 (#203)
This PR solves problem 114.
1 parent b2e7751 commit 8a09a13

File tree

1 file changed

+261
-3
lines changed

1 file changed

+261
-3
lines changed

HumanEvalLean/HumanEval114.lean

Lines changed: 261 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,263 @@
1-
def minSubArraySum : Unit :=
2-
()
1+
import Std.Tactic.Do
2+
open Std.Do
3+
set_option mvcgen.warning false
4+
5+
/-!
6+
## Implementation
7+
-/
8+
9+
@[grind]
10+
def Array.minD [Min α] (xs : Array α) (fallback : α) : α :=
11+
xs.toList.min?.getD fallback
12+
13+
@[grind]
14+
def List.minD [Min α] (xs : List α) (fallback : α) : α :=
15+
xs.min?.getD fallback
16+
17+
def minSubarraySum (xs : Array Int) : Int := Id.run do
18+
let mut minSum := 0
19+
let mut s := 0
20+
for num in xs do
21+
s := min 0 (s + num)
22+
minSum := min s minSum
23+
if minSum < 0 then
24+
return minSum
25+
else
26+
return xs.minD 0
27+
28+
/-!
29+
## Tests
30+
-/
31+
32+
example : minSubarraySum #[2, 3, 4, 1, 2, 4] = 1 := by decide
33+
example : minSubarraySum #[-1, -2, -3] = -6 := by decide
34+
example : minSubarraySum #[-1, -2, -3, 2, -10] = -14 := by decide
35+
example : minSubarraySum #[-9999999999999999] = -9999999999999999 := by decide
36+
example : minSubarraySum #[0, 10, 20, 1000000] = 0 := by decide
37+
example : minSubarraySum #[-1, -2, -3, 10, -5] = -6 := by decide
38+
example : minSubarraySum #[100, -1, -2, -3, 10, -5] = -6 := by decide
39+
example : minSubarraySum #[10, 11, 13, 8, 3, 4] = 3 := by decide
40+
example : minSubarraySum #[100, -33, 32, -1, 0, -2] = -33 := by decide
41+
example : minSubarraySum #[-10] = -10 := by decide
42+
example : minSubarraySum #[7] = 7 := by decide
43+
example : minSubarraySum #[1, -1] = -1 := by decide
44+
45+
-- This edge case is unspecified in the task description.
46+
example : minSubarraySum #[] = 0 := by decide
47+
48+
/-!
49+
## Verification
50+
-/
51+
52+
/-!
53+
### Missing API
54+
-/
55+
56+
attribute [grind =] List.toList_mkSlice_rco List.toList_mkSlice_rci List.le_min_iff
57+
attribute [grind →] List.mem_of_mem_take List.mem_of_mem_drop
58+
59+
@[simp, grind =]
60+
theorem Array.minD_empty [Min α] {fallback : α} :
61+
(#[] : Array α).minD fallback = fallback := by
62+
simp [Array.minD]
63+
64+
@[simp, grind =]
65+
theorem List.minD_nil [Min α] {fallback : α} :
66+
([] : List α).minD fallback = fallback := by
67+
simp [List.minD]
68+
69+
@[simp, grind =]
70+
theorem List.sum_append_int {l₁ l₂ : List Int} : (l₁ ++ l₂).sum = l₁.sum + l₂.sum := by
71+
induction l₁ generalizing l₂ <;> simp_all [Int.add_assoc]
72+
73+
/-!
74+
### Helper lemmas
75+
-/
76+
77+
@[simp, grind =]
78+
theorem minSubarraySum_empty : minSubarraySum #[] = 0 := by simp [minSubarraySum]
79+
80+
/--
81+
`s` is the minimum sum of every possibly empty subarray of `xs`.
82+
-/
83+
def IsMinSubarraySum₀ (xs : List Int) (s : Int) : Prop :=
84+
(∃ (i j : Nat), i ≤ j ∧ j ≤ xs.length ∧ s = xs[i...j].toList.sum) ∧
85+
(∀ (i j : Nat), i ≤ j → j ≤ xs.length → s ≤ xs[i...j].toList.sum)
86+
87+
/--
88+
`s` is the minimum sum of every possibly empty suffix of `xs`.
89+
-/
90+
def IsMinSuffixSum₀ (xs : List Int) (s : Int) : Prop :=
91+
(∃ (i : Nat), i ≤ xs.length ∧ s = xs[i...*].toList.sum) ∧
92+
(∀ (i : Nat), i ≤ xs.length → s ≤ xs[i...*].toList.sum)
93+
94+
/--
95+
`s` is the minimum sum of every nonempty subarray of `xs`.
96+
-/
97+
def IsMinSubarraySum (xs : List Int) (s : Int) : Prop :=
98+
if xs = [] then s = 0 else
99+
(∃ (i j : Nat), i < j ∧ j ≤ xs.length ∧ s = xs[i...j].toList.sum) ∧
100+
(∀ (i j : Nat), i < j → j ≤ xs.length → s ≤ xs[i...j].toList.sum)
101+
102+
@[simp, grind .]
103+
theorem isMinSubarraySum₀_nil :
104+
IsMinSubarraySum₀ [] 0 :=
105+
⟨⟨0, 0, by grind, by grind, by grind⟩, fun i j hi hj => by grind⟩
106+
107+
@[simp, grind .]
108+
theorem isMinSuffixSum₀_nil :
109+
IsMinSuffixSum₀ [] 0 :=
110+
⟨⟨0, by grind, by grind⟩, fun i hi => by grind⟩
111+
112+
@[grind →]
113+
theorem isMinSubarraySum₀_le_zero {xs : List Int} {s : Int} :
114+
IsMinSubarraySum₀ xs s → s ≤ 0 := by
115+
intro h
116+
have := h.2 0 0
117+
grind [IsMinSubarraySum₀]
118+
119+
theorem isMinSuffixSum₀_le_zero {xs : List Int} {s : Int} :
120+
IsMinSuffixSum₀ xs s → s ≤ 0 := by
121+
intro h
122+
have := h.2 xs.length
123+
grind [IsMinSuffixSum₀]
124+
125+
@[grind ←, grind →]
126+
theorem isMinSubarraySum_of_isMinSubarraySum₀_of_neg {xs : List Int} {s : Int} (hs : s < 0) :
127+
IsMinSubarraySum₀ xs s → IsMinSubarraySum xs s := by
128+
grind [IsMinSubarraySum, IsMinSubarraySum₀, List.drop_take_self]
129+
130+
@[grind =>]
131+
theorem isMinSubarraySum₀_append_singleton_eq {xs : List Int} {x minSum minSuff : Int}
132+
(h₁ : IsMinSubarraySum₀ xs minSum) (h₂ : IsMinSuffixSum₀ xs minSuff) :
133+
IsMinSubarraySum₀ (xs ++ [x]) (min (min 0 (minSuff + x)) minSum) := by
134+
have : min (min 0 (minSuff + x)) minSum = min (minSuff + x) minSum := by grind
135+
rw [this]
136+
by_cases h : minSum ≤ minSuff + x
137+
· rw [show min (minSuff + x) minSum = minSum by grind]
138+
apply And.intro
139+
· grind [IsMinSubarraySum₀, List.take_append_of_le_length]
140+
· intro i j hi hj
141+
simp only [List.toList_mkSlice_rco]
142+
by_cases heq : j = (xs ++ [x]).length
143+
· by_cases hieq : i = (xs ++ [x]).length
144+
· grind
145+
· simp only [heq, List.take_length]
146+
rw [List.drop_append_of_le_length (by grind), List.sum_append_int]
147+
have := h₂.2 i
148+
grind
149+
· rw [List.take_append_of_le_length (by grind)]
150+
have := h₁.2 i j hi
151+
grind
152+
· rw [show min (minSuff + x) minSum = minSuff + x by grind]
153+
apply And.intro
154+
· obtain ⟨i, hi, h₂₁⟩ := h₂.1
155+
exact ⟨i, xs.length + 1, by grind, by grind, by grind⟩
156+
· intro i j hi hj
157+
by_cases heq : j = (xs ++ [x]).length
158+
· by_cases hieq : i = (xs ++ [x]).length
159+
· grind
160+
· simp only [heq, List.toList_mkSlice_rco, List.take_length]
161+
have := h₂.2 i (by grind)
162+
grind [List.drop_append_of_le_length]
163+
· have := h₁.2 i j (by grind) (by grind)
164+
grind [List.take_append_of_le_length]
165+
166+
@[grind =>]
167+
theorem isMinSuffixSum₀_append_singleton_eq {xs : List Int} {x minSuff : Int}
168+
(h : IsMinSuffixSum₀ xs minSuff) :
169+
IsMinSuffixSum₀ (xs ++ [x]) (min 0 (minSuff + x)) := by
170+
by_cases hle : 0 ≤ minSuff + x
171+
· rw [show min 0 (minSuff + x) = 0 by grind]
172+
apply And.intro
173+
· refine ⟨xs.length + 1, by grind, ?_⟩
174+
simp only [List.toList_mkSlice_rci, List.drop_length_add_append]
175+
grind
176+
· intro i hi
177+
by_cases hieq : i = (xs ++ [x]).length
178+
· grind
179+
· simp only [IsMinSuffixSum₀] at h
180+
grind [List.drop_append_of_le_length]
181+
· rw [show min 0 (minSuff + x) = minSuff + x by grind]
182+
apply And.intro
183+
· simp only [IsMinSuffixSum₀] at h
184+
grind [List.drop_append_of_le_length]
185+
· intro i hi
186+
by_cases hieq : i = (xs ++ [x]).length
187+
· grind
188+
· simp only [IsMinSuffixSum₀] at h
189+
grind [List.drop_append_of_le_length]
190+
191+
theorem List.zero_le_min_of_zero_le_sum {xs : List Int} (hne : xs ≠ []) (h : xs.sum ≤ 0) :
192+
xs.min hne ≤ 0 := by
193+
induction xs
194+
· grind
195+
· rename_i x xs ih
196+
cases xs
197+
· simp_all [List.min_eq_get_min?]
198+
· grind [min?_cons, min_eq_get_min?]
199+
200+
theorem List.length_mul_le_sum {xs : List Int} {m : Int} (h : ∀ x, x ∈ xs → m ≤ x) :
201+
xs.length * m ≤ xs.sum := by
202+
induction xs
203+
· grind
204+
· rename_i x xs ih
205+
simp only [mem_cons, forall_eq_or_imp, length_cons] at *
206+
grind
207+
208+
theorem this_should_not_be_so_hard (a : Int) (b : Nat) (h : 0 ≤ a) (h' : 0 < b) :
209+
a ≤ b * a := by
210+
match b with
211+
| 0 => grind
212+
| b + 1 =>
213+
induction b <;> grind
214+
215+
@[grind →, grind <=]
216+
theorem isMinSubarraySum_of_nonneg {xs : List Int} {minSum : Int}
217+
(h : IsMinSubarraySum₀ xs minSum) (hs : minSum ≥ 0) :
218+
IsMinSubarraySum xs (xs.minD 0) := by
219+
rw [IsMinSubarraySum]
220+
split
221+
· simp [*]
222+
· have : minSum = 0 := by grind
223+
have := this
224+
rw [List.minD, List.min?_eq_some_min (by grind), Option.getD_some]
225+
have hmin : xs.min (by grind) = xs.min (by grind) := rfl
226+
rw [List.min_eq_iff, List.mem_iff_getElem] at hmin
227+
have : 0 ≤ xs.min (by grind) := by
228+
false_or_by_contra
229+
obtain ⟨i, _, hi⟩ := hmin.1
230+
have := h.2 i (i + 1) (by grind) (by grind)
231+
simp only [List.toList_mkSlice_rco, List.take_add_one] at this
232+
grind
233+
apply And.intro
234+
· obtain ⟨i, _, hi⟩ := hmin.1
235+
exact ⟨i, i + 1, by grind, by grind, by grind [List.take_add_one]⟩
236+
· intro i j hi hj
237+
have : ∀ a, a ∈ (xs.take j).drop i → xs.min (by grind) ≤ a := by grind
238+
have := List.length_mul_le_sum this
239+
simp only [List.toList_mkSlice_rco, *]
240+
refine Int.le_trans ?_ this
241+
simp only [List.length_drop, List.length_take]
242+
apply this_should_not_be_so_hard <;> grind
243+
244+
/-!
245+
### Final theorems
246+
-/
247+
248+
theorem isMinSubarraySum_minSubarraySum {xs : Array Int} :
249+
IsMinSubarraySum xs.toList (minSubarraySum xs) := by
250+
generalize hwp : minSubarraySum xs = w
251+
apply Std.Do.Id.of_wp_run_eq hwp
252+
mvcgen
253+
case inv1 => exact .noThrow fun ⟨cursor, minSum, minSuff⟩ =>
254+
⌜IsMinSubarraySum₀ cursor.prefix minSum ∧
255+
IsMinSuffixSum₀ cursor.prefix minSuff⌝
256+
all_goals grind
257+
258+
theorem isMinSubarraySum_nil :
259+
IsMinSubarraySum [] 0 := by
260+
grind [IsMinSubarraySum]
3261

4262
/-!
5263
## Prompt
@@ -53,4 +311,4 @@ def check(candidate):
53311
assert candidate([7]) == 7
54312
assert candidate([1, -1]) == -1
55313
```
56-
-/
314+
-/

0 commit comments

Comments
 (0)