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