-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtest_opt_labelencoder_transform.flow
More file actions
214 lines (196 loc) · 5.74 KB
/
Copy pathtest_opt_labelencoder_transform.flow
File metadata and controls
214 lines (196 loc) · 5.74 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
# Regression test for the optimized LabelEncoder.transform (roadmap rank 92,
# issue #301).
#
# label_encoder_transform now locates each label with a search over the sorted
# class vector instead of scanning every class for every sample. The encoded
# output must match the old full-scan behaviour exactly, including the case of
# a label that was never seen during fit, which the old code left at the 0.0
# the calloc-backed result buffer already held.
import "lib/scikit/scikit.flow"
# Literal reimplementation of the pre-optimization scan, used as the oracle.
function tolet_reference_transform(classes: ptr<f32>, n_classes: i32, y: ptr<f32>, n: i32, out: ptr<f32>) -> void {
for i in 0 to n {
out[i] = 0.0
}
for i in 0 to n {
for k in 0 to n_classes {
if classes[k] == y[i] {
out[i] = (k as f32)
}
}
}
return
}
function tolet_known_values() -> i32 {
let mut failures: i32 = 0
let y: ptr<f32> = array_new_f32(6)
y[0] = 2.0
y[1] = 0.0
y[2] = 1.0
y[3] = 2.0
y[4] = 0.0
y[5] = 1.0
let enc: LabelEncoder = label_encoder_fit(y, 6)
let want: ptr<f32> = array_new_f32(6)
want[0] = 2.0
want[1] = 0.0
want[2] = 1.0
want[3] = 2.0
want[4] = 0.0
want[5] = 1.0
let got: ptr<f32> = label_encoder_transform(enc, y, 6)
for i in 0 to 6 {
if got[i] != want[i] {
print(" FAIL basic encode at ")
print(i)
print(": got ")
print(got[i])
print(" wanted ")
println(want[i])
failures = failures + 1
}
}
if failures == 0 {
println(" OK basic encode")
}
array_free_f32(got)
# Labels the encoder never saw. The old code left these at 0.0.
let unseen: ptr<f32> = array_new_f32(4)
unseen[0] = -5.0
unseen[1] = 0.0
unseen[2] = 99.0
unseen[3] = 1.5
let got2: ptr<f32> = label_encoder_transform(enc, unseen, 4)
let mut bad: i32 = 0
if got2[0] != 0.0 {
bad = 1
}
if got2[1] != 0.0 {
bad = 1
}
if got2[2] != 0.0 {
bad = 1
}
if got2[3] != 0.0 {
bad = 1
}
if bad != 0 {
println(" FAIL unseen labels did not encode as 0.0")
failures = failures + 1
} else {
println(" OK unseen labels encode as 0.0")
}
array_free_f32(got2)
array_free_f32(unseen)
array_free_f32(want)
label_encoder_free(enc)
array_free_f32(y)
# Single class: everything maps to 0.
let s: ptr<f32> = array_new_f32(3)
s[0] = 4.0
s[1] = 4.0
s[2] = 4.0
let enc1: LabelEncoder = label_encoder_fit(s, 3)
let g1: ptr<f32> = label_encoder_transform(enc1, s, 3)
if g1[0] != 0.0 || g1[1] != 0.0 || g1[2] != 0.0 {
println(" FAIL single class encode")
failures = failures + 1
} else {
println(" OK single class encode")
}
array_free_f32(g1)
label_encoder_free(enc1)
array_free_f32(s)
# Negative and fractional labels, first and last class both exercised.
let m: ptr<f32> = array_new_f32(5)
m[0] = 3.25
m[1] = -7.5
m[2] = 0.0
m[3] = -7.5
m[4] = 3.25
let encm: LabelEncoder = label_encoder_fit(m, 5)
let gm: ptr<f32> = label_encoder_transform(encm, m, 5)
if gm[0] != 2.0 || gm[1] != 0.0 || gm[2] != 1.0 || gm[3] != 0.0 || gm[4] != 2.0 {
print(" FAIL negative/fractional encode: ")
print(gm[0])
print(" ")
print(gm[1])
print(" ")
println(gm[2])
failures = failures + 1
} else {
println(" OK negative and fractional labels")
}
array_free_f32(gm)
label_encoder_free(encm)
array_free_f32(m)
return failures
}
function tolet_workload(n: i32, n_classes: i32, seed: i32) -> i32 {
let y: ptr<f32> = array_new_f32(n)
let mut s: i32 = seed
for i in 0 to n {
s = (s * 1103515245 + 12345) % 2147483647
if s < 0 {
s = 0 - s
}
y[i] = ((s % n_classes) as f32) * 0.5 - 3.0
}
let enc: LabelEncoder = label_encoder_fit(y, n)
# Query set contains labels the encoder saw plus labels it did not.
let q: ptr<f32> = array_new_f32(n)
for i in 0 to n {
if i % 7 == 0 {
q[i] = 1000.0 + (i as f32)
} else {
q[i] = y[i]
}
}
let want: ptr<f32> = array_new_f32(n)
tolet_reference_transform(enc.classes, enc.n_classes, q, n, want)
let got: ptr<f32> = label_encoder_transform(enc, q, n)
let mut failures: i32 = 0
for i in 0 to n {
if got[i] != want[i] {
if failures == 0 {
print(" FAIL workload at ")
print(i)
print(": got ")
print(got[i])
print(" wanted ")
println(want[i])
}
failures = 1
}
}
if failures == 0 {
print(" OK workload n=")
print(n)
print(" classes=")
print(enc.n_classes)
println("")
}
array_free_f32(got)
array_free_f32(want)
array_free_f32(q)
label_encoder_free(enc)
array_free_f32(y)
return failures
}
function main() -> i32 {
println("LabelEncoder.transform optimization regression test")
println("==================================================")
let mut failures: i32 = 0
failures = failures + tolet_known_values()
failures = failures + tolet_workload(5000, 12, 5)
failures = failures + tolet_workload(5000, 13, 5)
failures = failures + tolet_workload(5000, 251, 17)
failures = failures + tolet_workload(1500, 1500, 23)
if failures != 0 {
print("FAILURES: ")
println(failures)
return 1
}
println("All LabelEncoder.transform optimization tests passed!")
return 0
}