Skip to content

Commit 836c494

Browse files
authored
128 using mvcgen (#217)
This PR solves problem 128.
1 parent ea11893 commit 836c494

File tree

1 file changed

+100
-3
lines changed

1 file changed

+100
-3
lines changed

HumanEvalLean/HumanEval128.lean

Lines changed: 100 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,102 @@
1-
def prod_signs : Unit :=
2-
()
1+
import Std
2+
3+
open Std Std.Do
4+
5+
set_option mvcgen.warning false
6+
7+
/-!
8+
# HumanEval 128: Sum of magnitudes times product of signs
9+
10+
This problem description asks us to compute the sum of absolute values of an array, multiplied by
11+
the product of the signs of all elements. We demonstrate how to implement and verify an
12+
efficient implementation using `do` notation and `mvcgen`.
13+
-/
14+
15+
/-!
16+
## Missing API
17+
-/
18+
19+
def List.product (xs : List Int) : Int :=
20+
xs.foldr (· * ·) 1
21+
22+
@[grind =]
23+
theorem List.product_nil : ([] : List Int).product = 1 := by
24+
rfl
25+
26+
@[grind =]
27+
theorem List.product_cons {x : Int} {xs : List Int} :
28+
(x :: xs).product = x * xs.product := by
29+
grind [List.product]
30+
31+
@[grind =]
32+
theorem List.product_append {xs ys : List Int} :
33+
(xs ++ ys).product = xs.product * ys.product := by
34+
induction xs <;> grind [List.product_cons, Int.mul_assoc]
35+
36+
theorem List.product_eq_zero_iff {xs : List Int} :
37+
xs.product = 00 ∈ xs := by
38+
induction xs <;> grind [List.product_cons, Int.mul_eq_zero]
39+
40+
theorem Option.of_wp {α} {prog : Option α} (P : Option α → Prop) :
41+
(⊢ₛ wp⟦prog⟧ post⟨fun a => ⌜P (some a)⌝, fun _ => ⌜P none⌝⟩) → P prog := by
42+
intro hspec
43+
simp only [wp, PredTrans.pushOption_apply, PredTrans.pure_apply] at hspec
44+
split at hspec
45+
case h_1 a s' heq => rw [← heq] at hspec; exact hspec True.intro
46+
case h_2 s' heq => rw [← heq] at hspec; exact hspec True.intro
47+
48+
theorem Option.of_wp_eq {α : Type} {x : Option α} {prog : Option α} (h : prog = x) (P : Option α → Prop) :
49+
(⊢ₛ wp⟦prog⟧ post⟨fun a => ⌜P (some a)⌝, fun _ => ⌜P none⌝⟩) → P x := by
50+
rw [← h]
51+
apply Option.of_wp
52+
53+
/-!
54+
## Implementation
55+
-/
56+
57+
def prodSigns (arr : List Int) : Option Int := do
58+
if arr.isEmpty then
59+
none
60+
let mut sum := 0
61+
let mut sign := 1
62+
for x in arr do
63+
if x = 0 then
64+
return 0
65+
sum := sum + x.natAbs
66+
sign := sign * x.sign
67+
return sum * sign
68+
69+
/-!
70+
## Tests
71+
-/
72+
73+
example : prodSigns [1, 2, 2, -4] = some (-9) := by native_decide
74+
example : prodSigns [0, 1] = some 0 := by native_decide
75+
example : prodSigns [] = none := by native_decide
76+
example : prodSigns [1, 1, 1, 2, 3, -1, 1] = some (-10) := by native_decide
77+
example : prodSigns [2, 4, 1, 2, -1, -1, 9] = some 20 := by native_decide
78+
example : prodSigns [-1, 1, -1, 1] = some 4 := by native_decide
79+
example : prodSigns [-1, 1, 1, 1] = some (-4) := by native_decide
80+
example : prodSigns [-1, 1, 1, 0] = some 0 := by native_decide
81+
82+
/-!
83+
## Verification
84+
-/
85+
86+
theorem prodSigns_nil :
87+
prodSigns [] = none := by
88+
grind [prodSigns]
89+
90+
theorem prodSigns_of_ne_nil {xs : List Int} (h : xs ≠ []) :
91+
prodSigns xs = some ((xs.map Int.natAbs).sum * (xs.map Int.sign).product) := by
92+
generalize hwp : prodSigns xs = wp
93+
apply Option.of_wp_eq hwp
94+
mvcgen [prodSigns]
95+
invariants
96+
· .withEarlyReturn
97+
(fun cur ⟨sign, sum⟩ => ⌜sum = (cur.prefix.map Int.natAbs).sum ∧ sign = (cur.prefix.map Int.sign).product⌝)
98+
(fun ret ⟨sign, sum⟩ => ⌜ret = 00 ∈ xs⌝)
99+
with grind [List.product_eq_zero_iff]
3100

4101
/-!
5102
## Prompt
@@ -48,4 +145,4 @@ def check(candidate):
48145
assert True, "This prints if this assert fails 2 (also good for debugging!)"
49146
50147
```
51-
-/
148+
-/

0 commit comments

Comments
 (0)