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 = 0 ↔ 0 ∈ 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 = 0 ∧ 0 ∈ 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