1- def mean_absolute_deviation : Unit :=
2- ()
1+ module
2+
3+ import Std
4+ open Std
5+
6+ /-! ## Missing API -/
7+
8+ theorem List.sum_eq_foldl [Zero α] [Add α]
9+ [Associative (α := α) (· + ·)][Commutative (α := α) (· + ·)]
10+ [LawfulLeftIdentity (· + ·) (0 : α)]
11+ {xs : List α} :
12+ xs.sum = xs.foldl (init := 0 ) (· + ·) := by
13+ conv => lhs; rw [← List.reverse_reverse (as := xs)]
14+ rw [List.sum_reverse, List.sum_eq_foldr, List.foldr_reverse]
15+ simp only [Commutative.comm]
16+
17+ def Std.Iter.sum [Add β] [Zero β] [Iterator α Id β] [IteratorLoop α Id Id]
18+ (it : Iter (α := α) β) : β :=
19+ it.fold (init := 0 ) (· + ·)
20+
21+ theorem Std.Iter.sum_toList [Add β] [Zero β]
22+ [Associative (α := β) (· + ·)] [Commutative (α := β) (· + ·)]
23+ [LawfulLeftIdentity (· + ·) (0 : β)]
24+ [Iterator α Id β] [IteratorLoop α Id Id]
25+ [LawfulIteratorLoop α Id Id] [Iterators.Finite α Id] {it : Iter (α := α) β} :
26+ it.toList.sum = it.sum := by
27+ simp only [Iter.sum, ← Iter.foldl_toList, List.sum_eq_foldl]
28+
29+ theorem Array.size_singleton {x : α} :
30+ #[x].size = 1 := by
31+ simp
32+
33+ @ [simp, grind =]
34+ theorem Array.sum_singleton [Add α] [Zero α] [LawfulRightIdentity (· + ·) (0 : α)] {x : α} :
35+ #[x].sum = x := by
36+ simp [Array.sum_eq_foldr, LawfulRightIdentity.right_id x]
37+
38+ -- Library defect: remove the `LeftIdentity` parameter from Array.sum_append
39+
40+ @ [simp, grind =]
41+ theorem Array.sum_push [Add α] [Zero α]
42+ [Associative (α := α) (· + ·)]
43+ [LawfulIdentity (· + ·) (0 : α)]
44+ {xs : Array α} {x : α} :
45+ (xs.push x).sum = xs.sum + x := by
46+ simp [Array.sum_eq_foldr, LawfulRightIdentity.right_id, LawfulLeftIdentity.left_id,
47+ ← Array.foldr_assoc]
48+
49+ def Rat.abs (x : Rat) :=
50+ if 0 ≤ x then x else - x
51+
52+ theorem Rat.abs_nonneg {x : Rat} :
53+ 0 ≤ x.abs := by
54+ simp only [Rat.abs]
55+ grind
56+
57+ theorem Rat.abs_of_nonneg {x : Rat} (h : 0 ≤ x) :
58+ x.abs = x := by
59+ grind [Rat.abs]
60+
61+ theorem Rat.abs_of_nonpos {x : Rat} (h : x ≤ 0 ) :
62+ x.abs = - x := by
63+ grind [Rat.abs]
64+
65+ theorem Rat.abs_sub_comm {x y : Rat} :
66+ (x - y).abs = (y - x).abs := by
67+ grind [Rat.abs]
68+
69+ instance Rat.instAssociativeHAdd : Associative (α := Rat) (· + ·) := ⟨Rat.add_assoc⟩
70+ instance Rat.instCommutativeHAdd : Commutative (α := Rat) (· + ·) := ⟨Rat.add_comm⟩
71+ instance : Std.LawfulIdentity (· + ·) (0 : Rat) where
72+ left_id := Rat.zero_add
73+ right_id := Rat.add_zero
74+
75+ /-! ## Implementation -/
76+
77+ def mean (xs : Array Rat) : Rat :=
78+ xs.sum / xs.size
79+
80+ def meanAbsoluteDeviation (xs : Array Rat) : Rat :=
81+ let mean := mean xs
82+ (xs.iter
83+ |>.map (fun x => (x - mean).abs)
84+ |>.sum) / xs.size
85+
86+ /-! ## Tests -/
87+
88+ example : meanAbsoluteDeviation #[(1 : Rat), 2 , 3 ] = (2 : Rat) / 3 := by native_decide
89+ example : meanAbsoluteDeviation #[(1 : Rat), 2 , 3 , 4 ] = 1 := by native_decide
90+ example : meanAbsoluteDeviation #[(1 : Rat), 2 , 3 , 4 , 5 ] = (6 : Rat) / 5 := by native_decide
91+
92+ /-!
93+ ## Verification
94+
95+ In order to verify the implementation, we point to library lemmas verifying `Array.sum`, `Rat.abs`,
96+ `Array.size` and `Array.map`. Then we show that `mean` is actually the quotient of `sum` and `size`
97+ and that `meanAbsoluteDeviation` computes the mean of absolute deviations from the mean,
98+ expressed using said four library functions.
99+ -/
100+
101+ section API
102+
103+ variable {x : Rat} {xs ys : Array Rat} {f : Rat → β}
104+
105+ example : (#[] : Array Rat).sum = 0 := Array.sum_empty
106+ example : (#[x]).sum = x := Array.sum_singleton
107+ example : (xs.push x).sum = xs.sum + x := Array.sum_push
108+ example : (xs ++ ys).sum = xs.sum + ys.sum := Array.sum_append
109+
110+ example (h : 0 ≤ x) : x.abs = x := Rat.abs_of_nonneg h
111+ example (h : x ≤ 0 ) : x.abs = - x := Rat.abs_of_nonpos h
112+ example : 0 ≤ x.abs := Rat.abs_nonneg
113+
114+ example : (#[] : Array Rat).size = 0 := Array.size_empty
115+ example : (#[x]).size = 1 := Array.size_singleton
116+ example : (xs.push x).size = xs.size + 1 := Array.size_push _
117+ example : (xs ++ ys).size = xs.size + ys.size := Array.size_append
118+
119+ example : (#[] : Array Rat).map f = #[] := Array.map_empty
120+ example : #[x].map f = #[f x] := Array.map_singleton
121+ example : (xs.push x).map f = (xs.map f).push (f x) := Array.map_push
122+ example : (xs ++ ys).map f = xs.map f ++ ys.map f := Array.map_append
123+
124+ end API
125+
126+ theorem mean_spec {xs : Array Rat} :
127+ mean xs = xs.sum / xs.size := by
128+ simp [mean]
129+
130+ theorem meanAbsoluteDeviation_spec {xs : Array Rat} :
131+ meanAbsoluteDeviation xs =
132+ mean (xs.map (fun x => (x - mean xs).abs)) := by
133+ simp [meanAbsoluteDeviation, mean, ← Iter.sum_toList, ← Array.sum_toList]
3134
4135/-!
5136## Prompt
@@ -43,4 +174,4 @@ def check(candidate):
43174 assert abs(candidate([1.0, 2.0, 3.0, 4.0, 5.0]) - 6.0/5.0) < 1e-6
44175
45176```
46- -/
177+ -/
0 commit comments