main.bend
mlbend-report@0.1.0.0 · 254 lines · 27 definitions
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21import Base
22import mlbend-metrics@0.1.0.0/main.bend as M
23
24
25
26type Cls is Data:
27 Cls{precision: F32, recall: F32, f1: F32, support: Nat}
28
29
30
31
32type Report is Data:
33 Report{classes: List<&2, Cls>, macro_avg: Cls, weighted_avg: Cls, accuracy: F32}
34
35
36
37
38
39
40
41
42
43
44def cell.go(ys: List<&2, Nat>, ps: List<&2, Nat>, +i: Nat, +j: Nat, n: Nat) -> Nat:
45 match ys ps:
46 case Con{y, yt} Con{p, pt}:
47 cell.go(yt, pt, i, j, (n + M.same(y, i) * M.same(p, j) : Nat))
48 case _ _:
49 n
50
51def cell(ys: List<&2, Nat>, ps: List<&2, Nat>, +i: Nat, +j: Nat) -> Nat:
52 cell.go(ys, ps, i, j, 0n)
53
54
55def rows_of(m: List<&2, List<&2, Nat>>) -> Nat:
56 match m:
57 case Nil{}:
58 0n
59 case Con{h, t}:
60 (1n + rows_of(t) : Nat)
61
62
63def cells_of(row: List<&2, Nat>) -> Nat:
64 match row:
65 case Nil{}:
66 0n
67 case Con{h, t}:
68 (1n + cells_of(t) : Nat)
69
70
71
72
73
74def row_from(+ys: List<&2, Nat>, +ps: List<&2, Nat>, +k: Nat, +i: Nat, n: Nat, +j: Nat) ->
75 List<&2, Nat>:
76 match n:
77 case 0n:
78 Nil{}
79 case 1n+rest:
80 Con{cell(ys, ps, i, j), row_from(ys, ps, k, i, rest, (1n + j : Nat))}
81
82
83def row(ys: List<&2, Nat>, ps: List<&2, Nat>, +k: Nat, +i: Nat) -> List<&2, Nat>:
84 row_from(ys, ps, k, i, k, 0n)
85
86
87def matrix_from(+ys: List<&2, Nat>, +ps: List<&2, Nat>, +k: Nat, n: Nat, +i: Nat) ->
88 List<&2, List<&2, Nat>>:
89 match n:
90 case 0n:
91 Nil{}
92 case 1n+rest:
93 Con{row(ys, ps, k, i), matrix_from(ys, ps, k, rest, (1n + i : Nat))}
94
95
96
97def matrix(ys: List<&2, Nat>, ps: List<&2, Nat>, +k: Nat) ->
98 List<&2, List<&2, Nat>>:
99 matrix_from(ys, ps, k, k, 0n)
100
101
102law matrix_rows:
103 for +ys: List<&2, Nat>
104 for +ps: List<&2, Nat>
105 for +k: Nat
106 for +n: Nat
107 for +i: Nat
108 {rows_of(matrix_from(ys, ps, k, n, i)) == n : Nat}
109
110
111def matrix_rows(ys, ps, k, n, i):
112 match n:
113 case 0n:
114 {==}
115 case 1n+rest:
116 %matrix_rows(ys, ps, k, rest, (1n + i : Nat)) :
117 {1n+rows_of(matrix_from(ys, ps, k, rest, (1n + i : Nat))) == 1n+_ : Nat}
118 {==}
119
120
121law row_length:
122 for +ys: List<&2, Nat>
123 for +ps: List<&2, Nat>
124 for +k: Nat
125 for +i: Nat
126 for +n: Nat
127 for +j: Nat
128 {cells_of(row_from(ys, ps, k, i, n, j)) == n : Nat}
129
130
131def row_length(ys, ps, k, i, n, j):
132 match n:
133 case 0n:
134 {==}
135 case 1n+rest:
136 %row_length(ys, ps, k, i, rest, (1n + j : Nat)) :
137 {1n+cells_of(row_from(ys, ps, k, i, rest, (1n + j : Nat))) == 1n+_ : Nat}
138 {==}
139
140
141
142
143
144
145
146
147
148
149def cls_of(+ys: List<&2, Nat>, +ps: List<&2, Nat>, +i: Nat) -> Cls:
150 +hits = M.count_both(ys, ps, i)
151 +support = M.count_true(ys, i)
152 +p = M.ratio(hits, M.count_pred(ps, i))
153 +r = M.ratio(hits, support)
154 Cls{p, r, M.f1_num(p, r), support}
155
156
157def classes_of.go(+ys: List<&2, Nat>, +ps: List<&2, Nat>, n: Nat, +i: Nat) ->
158 List<&2, Cls>:
159 match n:
160 case 0n:
161 Nil{}
162 case 1n+rest:
163 Con{cls_of(ys, ps, i), classes_of.go(ys, ps, rest, (1n + i : Nat))}
164
165
166def classes_of(ys: List<&2, Nat>, ps: List<&2, Nat>, +k: Nat) -> List<&2, Cls>:
167 classes_of.go(ys, ps, k, 0n)
168
169
170
171
172
173
174type Tot is Data:
175 Tot{p: F32, r: F32, f: F32, support: Nat}
176
177
178def tot_add(t: Tot, c: Cls) -> Tot:
179 match t:
180 case Tot{p, r, f, support}:
181 match c:
182 case Cls{p2, r2, f2, support2}:
183 Tot{(p + p2 : F32), (r + r2 : F32), (f + f2 : F32), (support + support2 : Nat)}
184
185
186def tot_of.go(classes: List<&2, Cls>, acc: Tot) -> Tot:
187 match classes:
188 case Nil{}:
189 acc
190 case Con{c, t}:
191 tot_of.go(t, tot_add(acc, c))
192
193def tot_of(classes: List<&2, Cls>) -> Tot:
194 tot_of.go(classes, Tot{0.0, 0.0, 0.0, 0n})
195
196
197def divide(+a: F32, +b: F32) -> F32:
198 Bool.pick(F32, F32.is_eq(b, 0.0), 0.0, (a / b : F32))
199
200def macro_of.go(t: Tot, +k: Nat) -> Cls:
201 match t:
202 case Tot{p, r, f, support}:
203 +n = F32.from_nat(k)
204 Cls{divide(p, n), divide(r, n), divide(f, n), support}
205
206
207
208def macro_of(classes: List<&2, Cls>, +k: Nat) -> Cls:
209 macro_of.go(tot_of(classes), k)
210
211
212def weighted_sums(classes: List<&2, Cls>, +p: F32, +r: F32, +f: F32) -> Tot:
213 match classes:
214 case Nil{}:
215 Tot{p, r, f, 0n}
216 case Con{c, t}:
217 match c:
218 case Cls{p2, r2, f2, s2}:
219 +w = F32.from_nat(s2)
220 weighted_sums(t, (p + p2 * w : F32), (r + r2 * w : F32), (f + f2 * w : F32))
221
222def weighted_of.go(t: Tot, +total: Nat) -> Cls:
223 match t:
224 case Tot{p, r, f, support}:
225 +n = F32.from_nat(total)
226 Cls{divide(p, n), divide(r, n), divide(f, n), total}
227
228
229
230
231def weighted_of(classes: List<&2, Cls>, +total: Nat) -> Cls:
232 weighted_of.go(weighted_sums(classes, 0.0, 0.0, 0.0), total)
233
234
235
236
237
238
239
240def report.go(r: Result<&1, &1, M.Bad, Nat>, +ys: List<&2, Nat>, +ps: List<&2, Nat>, +k: Nat) ->
241 Result<&1, &1, M.Bad, Report>:
242 match r:
243 case Done{+n}:
244 +classes = classes_of(ys, ps, k)
245 Done{Report{classes, macro_of(classes, k), weighted_of(classes, n),
246 M.ratio(M.count_right(ys, ps), n)}}
247 case Fail{M.Mismatch{expected, got}}:
248 Fail{M.Mismatch{expected, got}}
249 case Fail{M.Empty{}}:
250 Fail{M.Empty{}}
251
252def report(+ys: List<&2, Nat>, +ps: List<&2, Nat>, +k: Nat) ->
253 Result<&1, &1, M.Bad, Report>:
254 report.go(M.pairs(&2, Nat, ys, ps), ys, ps, k)