Coverage Report

Created: 2024-08-18 16:21

/home/liu/actions-runner/_work/ccv/ccv/test/unit/nnc/histogram.tests.c
Line
Count
Source
1
#include "case.h"
2
#include "ccv_case.h"
3
#include "ccv_nnc_case.h"
4
#include <ccv.h>
5
#include <nnc/ccv_nnc.h>
6
#include <nnc/ccv_nnc_easy.h>
7
#include "3rdparty/dsfmt/dSFMT.h"
8
9
TEST_SETUP()
10
{
11
  ccv_nnc_init();
12
}
13
14
TEST_CASE("logarithmic histogram v.s. bins histogram")
15
1
{
16
1
  ccv_nnc_tensor_t* const a = ccv_nnc_tensor_new(0, CPU_TENSOR_NCHW(32F, 3000, 2000), 0);
17
1
  ccv_nnc_tensor_t* const h = ccv_nnc_tensor_new(0, CPU_TENSOR_NCHW(32F, 774 * 2), 0);
18
1
  double v = 1e-12;
19
1
  int i;
20
775
  for (i = 0; v < 1e20; 
i++, v *= 1.1774
)
21
774
  {
22
774
    h->data.f32[i + 774] = v;
23
774
    h->data.f32[774 - i - 1] = -v;
24
774
  }
25
1
  dsfmt_t dsfmt;
26
1
  dsfmt_init_gen_rand(&dsfmt, 1);
27
6.00M
  for (i = 0; i < 3000 * 2000; 
i++6.00M
)
28
6.00M
    a->data.f32[i] = dsfmt_genrand_open_close(&dsfmt) * 2000 - 1000;
29
1
  a->data.f32[0] = NAN;
30
1
  a->data.f32[1] = -FLT_MAX;
31
1
  a->data.f32[2] = FLT_MAX;
32
1
  a->data.f32[3] = 0;
33
1
  a->data.f32[4] = 1e-20;
34
1
  a->data.f32[5] = -1e-20;
35
1
  a->data.f32[6] = 1e20 - 1e18;
36
1
  a->data.f32[7] = -1e20 + 1e18;
37
1
  ccv_nnc_tensor_t* const bl = ccv_nnc_tensor_new(0, CPU_TENSOR_NCHW(32S, 775 * 2), 0);
38
1
  ccv_nnc_tensor_t* const bb = ccv_nnc_tensor_new(0, CPU_TENSOR_NCHW(32S, 775 * 2), 0);
39
1
  ccv_nnc_tensor_t* const sl = ccv_nnc_tensor_new(0, CPU_TENSOR_NCHW(32F, 4), 0);
40
1
  ccv_nnc_tensor_t* const sb = ccv_nnc_tensor_new(0, CPU_TENSOR_NCHW(32F, 4), 0);
41
1
  ccv_nnc_cmd_exec(CMD_HISTOGRAM_LOG(), ccv_nnc_no_hint, 0, TENSOR_LIST(a), TENSOR_LIST(bl, sl), 0);
42
1
  ccv_nnc_cmd_exec(CMD_HISTOGRAM_BINS(), ccv_nnc_no_hint, 0, TENSOR_LIST(a, h), TENSOR_LIST(bb, sb), 0);
43
1.55k
  for (i = 0; i < 775 * 2; 
i++1.55k
)
44
1.55k
  {
45
1.55k
    const int sum = bb->data.i32[i] + bl->data.i32[i];
46
1.55k
    const float tol = sum > 10 ? 
fabsf((float)(bl->data.i32[i] - bb->data.i32[i])) / (float)sum232
:
abs(bl->data.i32[i] - bb->data.i32[i])1.31k
;
47
1.55k
    REQUIRE(tol < 0.1, "should be smaller than tolerance for bl->data.i32[%d](%d), bb->data.i32[%d](%d)", i, bl->data.i32[i], i, bb->data.i32[i]);
48
1.55k
  }
49
1
  REQUIRE_EQ(sl->data.f32[0], -FLT_MAX, "should be equal to the minimal");
50
1
  REQUIRE_EQ(sl->data.f32[1], FLT_MAX, "should be equal to the maximal");
51
1
  REQUIRE(isnan(sl->data.f32[2]), "sum is nan");
52
1
  REQUIRE(isnan(sl->data.f32[3]), "sum of squares is nan");
53
1
  REQUIRE_EQ(bb->data.i32[0], 1, "should have 1 smaller than minimal value");
54
1
  REQUIRE_EQ(bb->data.i32[774 * 2], 1, "should have 1 larger than maximal value");
55
1
  REQUIRE_EQ(bb->data.i32[775 * 2 - 1], 1, "should have 1 nan");
56
1
  REQUIRE_EQ(bb->data.i32[774 * 2 - 1], 1, "should have 1 in the range (1e20 / 1.1, 1e20)");
57
1
  REQUIRE_EQ(bb->data.i32[1], 1, "should have 1 in the range (-1e20, -1e20 / 1.1)");
58
1
  REQUIRE_EQ(bb->data.i32[774], 3, "should have 3 in the range (-1e-12, 1e-12)");
59
1
  REQUIRE_EQ(bl->data.i32[0], 1, "should have 1 smaller than minimal value");
60
1
  REQUIRE_EQ(bl->data.i32[774 * 2], 1, "should have 1 larger than maximal value");
61
1
  REQUIRE_EQ(bl->data.i32[775 * 2 - 1], 1, "should have 1 nan");
62
1
  REQUIRE_EQ(bl->data.i32[774 * 2 - 1], 1, "should have 1 in the range (1e20 / 1.1, 1e20)");
63
1
  REQUIRE_EQ(bl->data.i32[1], 1, "should have 1 in the range (-1e20, -1e20 / 1.1)");
64
1
  REQUIRE_EQ(bl->data.i32[774], 3, "should have 3 in the range (-1e-12, 1e-12)");
65
1
  REQUIRE_TENSOR_EQ(sl, sb, "computed stats should be equal");
66
1
  ccv_nnc_tensor_free(a);
67
1
  ccv_nnc_tensor_free(h);
68
1
  ccv_nnc_tensor_free(bl);
69
1
  ccv_nnc_tensor_free(bb);
70
1
  ccv_nnc_tensor_free(sl);
71
1
  ccv_nnc_tensor_free(sb);
72
1
}
73
74
TEST_CASE("even histogram v.s. bins histogram")
75
1
{
76
1
  ccv_nnc_tensor_t* const a = ccv_nnc_tensor_new(0, CPU_TENSOR_NCHW(32F, 3000, 2000), 0);
77
1
  ccv_nnc_tensor_t* const h = ccv_nnc_tensor_new(0, CPU_TENSOR_NCHW(32F, 201), 0);
78
1
  int i;
79
202
  for (i = 0; i < 201; 
i++201
)
80
201
  {
81
201
    h->data.f32[i] = (i - 100) * 10;
82
201
  }
83
1
  dsfmt_t dsfmt;
84
1
  dsfmt_init_gen_rand(&dsfmt, 1);
85
6.00M
  for (i = 0; i < 3000 * 2000; 
i++6.00M
)
86
6.00M
    a->data.f32[i] = dsfmt_genrand_open_close(&dsfmt) * 2000 - 1000;
87
1
  a->data.f32[0] = NAN;
88
1
  a->data.f32[1] = -FLT_MAX;
89
1
  a->data.f32[2] = FLT_MAX;
90
1
  a->data.f32[3] = 0;
91
1
  a->data.f32[4] = 1e-20;
92
1
  a->data.f32[5] = -1e-20;
93
1
  a->data.f32[6] = 1e20 - 1e18;
94
1
  a->data.f32[7] = -1e20 + 1e18;
95
1
  ccv_nnc_tensor_t* const bl = ccv_nnc_tensor_new(0, CPU_TENSOR_NCHW(32S, 203), 0);
96
1
  ccv_nnc_tensor_t* const bb = ccv_nnc_tensor_new(0, CPU_TENSOR_NCHW(32S, 203), 0);
97
1
  ccv_nnc_tensor_t* const sl = ccv_nnc_tensor_new(0, CPU_TENSOR_NCHW(32F, 4), 0);
98
1
  ccv_nnc_tensor_t* const sb = ccv_nnc_tensor_new(0, CPU_TENSOR_NCHW(32F, 4), 0);
99
1
  ccv_nnc_cmd_exec(CMD_HISTOGRAM_EVEN(200, -1000, 1000), ccv_nnc_no_hint, 0, TENSOR_LIST(a), TENSOR_LIST(bl, sl), 0);
100
1
  ccv_nnc_cmd_exec(CMD_HISTOGRAM_BINS(), ccv_nnc_no_hint, 0, TENSOR_LIST(a, h), TENSOR_LIST(bb, sb), 0);
101
204
  for (i = 0; i < 203; 
i++203
)
102
203
  {
103
203
    const int diff = abs(bb->data.i32[i] - bl->data.i32[i]);
104
203
    REQUIRE(diff < 5, "differences should be smaller than 5 for bl->data.i32[%d](%d), bb->data.i32[%d](%d)", i, bl->data.i32[i], i, bb->data.i32[i]);
105
203
  }
106
1
  REQUIRE_EQ(sl->data.f32[0], -FLT_MAX, "should be equal to the minimal");
107
1
  REQUIRE_EQ(sl->data.f32[1], FLT_MAX, "should be equal to the maximal");
108
1
  REQUIRE(isnan(sl->data.f32[2]), "sum is nan");
109
1
  REQUIRE(isnan(sl->data.f32[3]), "sum of squares is nan");
110
1
  REQUIRE_EQ(bb->data.i32[0], 2, "should have 2 smaller than minimal value");
111
1
  REQUIRE_EQ(bb->data.i32[201], 2, "should have 2 larger than maximal value");
112
1
  REQUIRE_EQ(bb->data.i32[202], 1, "should have 1 nan");
113
1
  REQUIRE_EQ(bl->data.i32[0], 2, "should have 2 smaller than minimal value");
114
1
  REQUIRE_EQ(bl->data.i32[201], 2, "should have 2 larger than maximal value");
115
1
  REQUIRE_EQ(bl->data.i32[202], 1, "should have 1 nan");
116
1
  REQUIRE_TENSOR_EQ(sl, sb, "computed stats should be equal");
117
1
  ccv_nnc_tensor_free(a);
118
1
  ccv_nnc_tensor_free(h);
119
1
  ccv_nnc_tensor_free(bl);
120
1
  ccv_nnc_tensor_free(bb);
121
1
  ccv_nnc_tensor_free(sl);
122
1
  ccv_nnc_tensor_free(sb);
123
1
}
124
125
TEST_CASE("logarithmic histogram v.s. bins histogram on tensor view")
126
1
{
127
1
  ccv_nnc_tensor_t* const a = ccv_nnc_tensor_new(0, CPU_TENSOR_NCHW(32F, 30, 100, 20, 100), 0);
128
1
  ccv_nnc_tensor_t* const h = ccv_nnc_tensor_new(0, CPU_TENSOR_NCHW(32F, 774 * 2), 0);
129
1
  double v = 1e-12;
130
1
  int i;
131
775
  for (i = 0; v < 1e20; 
i++, v *= 1.1774
)
132
774
  {
133
774
    h->data.f32[i + 774] = v;
134
774
    h->data.f32[774 - i - 1] = -v;
135
774
  }
136
1
  dsfmt_t dsfmt;
137
1
  dsfmt_init_gen_rand(&dsfmt, 1);
138
6.00M
  for (i = 0; i < 3000 * 2000; 
i++6.00M
)
139
6.00M
    a->data.f32[i] = dsfmt_genrand_open_close(&dsfmt) * 2000 - 1000;
140
1
  ccv_nnc_tensor_view_t* const av = ccv_nnc_tensor_view_new(a, CPU_TENSOR_NCHW(32F, 30, 20, 20, 40), DIM_ALLOC(0, 10, 0, 20), DIM_ALLOC(100 * 20 * 100, 20 * 100, 100, 1));
141
  // All these skipped.
142
1
  a->data.f32[0] = NAN;
143
1
  a->data.f32[1] = -FLT_MAX;
144
1
  a->data.f32[2] = FLT_MAX;
145
1
  a->data.f32[3] = 0;
146
1
  a->data.f32[4] = 1e-20;
147
1
  a->data.f32[5] = -1e-20;
148
1
  a->data.f32[6] = 1e20 - 1e18;
149
1
  a->data.f32[7] = -1e20 + 1e18;
150
1
  ccv_nnc_tensor_t* const bl = ccv_nnc_tensor_new(0, CPU_TENSOR_NCHW(32S, 775 * 2), 0);
151
1
  ccv_nnc_tensor_t* const bb = ccv_nnc_tensor_new(0, CPU_TENSOR_NCHW(32S, 775 * 2), 0);
152
1
  ccv_nnc_tensor_t* const sl = ccv_nnc_tensor_new(0, CPU_TENSOR_NCHW(32F, 4), 0);
153
1
  ccv_nnc_tensor_t* const sb = ccv_nnc_tensor_new(0, CPU_TENSOR_NCHW(32F, 4), 0);
154
1
  ccv_nnc_cmd_exec(CMD_HISTOGRAM_LOG(), ccv_nnc_no_hint, 0, TENSOR_LIST((ccv_nnc_tensor_t*)av), TENSOR_LIST(bl, sl), 0);
155
1
  ccv_nnc_cmd_exec(CMD_HISTOGRAM_BINS(), ccv_nnc_no_hint, 0, TENSOR_LIST((ccv_nnc_tensor_t*)av, h), TENSOR_LIST(bb, sb), 0);
156
1.55k
  for (i = 0; i < 775 * 2; 
i++1.55k
)
157
1.55k
  {
158
1.55k
    const int sum = bb->data.i32[i] + bl->data.i32[i];
159
1.55k
    const float tol = sum > 10 ? 
fabsf((float)(bl->data.i32[i] - bb->data.i32[i])) / (float)sum174
:
abs(bl->data.i32[i] - bb->data.i32[i])1.37k
;
160
1.55k
    REQUIRE(tol < 0.1, "should be smaller than tolerance for bl->data.i32[%d](%d), bb->data.i32[%d](%d)", i, bl->data.i32[i], i, bb->data.i32[i]);
161
1.55k
  }
162
1
  REQUIRE(sl->data.f32[0] < -990, "minimal should be close to the edge");
163
1
  REQUIRE(sl->data.f32[1] > 990, "maximal should be close to the edge");
164
1
  REQUIRE(sl->data.f32[2] / (float)ccv_nnc_tensor_count(av->info) < 1, "sum should be close to 0");
165
1
  REQUIRE_EQ_WITH_TOLERANCE(sl->data.f32[3] / (float)ccv_nnc_tensor_count(av->info), 2000 * 2000 / 12, 1e3, "sum of squares should be close to its expected value in uniform distribution");
166
1
  REQUIRE_EQ(bb->data.i32[0], 0, "should've skipped all manual numbers");
167
1
  REQUIRE_EQ(bb->data.i32[774 * 2], 0, "should've skipped all manual numbers");
168
1
  REQUIRE_EQ(bb->data.i32[775 * 2 - 1], 0, "should've skipped all manual numbers");
169
1
  REQUIRE_EQ(bb->data.i32[774 * 2 - 1], 0, "should've skipped all manual numbers");
170
1
  REQUIRE_EQ(bb->data.i32[1], 0, "should've skipped all manual numbers");
171
1
  REQUIRE_EQ(bb->data.i32[774], 0, "should've skipped all manual numbers");
172
1
  REQUIRE_EQ(bl->data.i32[0], 0, "should've skipped all manual numbers");
173
1
  REQUIRE_EQ(bl->data.i32[774 * 2], 0, "should've skipped all manual numbers");
174
1
  REQUIRE_EQ(bl->data.i32[775 * 2 - 1], 0, "should've skipped all manual numbers");
175
1
  REQUIRE_EQ(bl->data.i32[774 * 2 - 1], 0, "should've skipped all manual numbers");
176
1
  REQUIRE_EQ(bl->data.i32[1], 0, "should've skipped all manual numbers");
177
1
  REQUIRE_EQ(bl->data.i32[774], 0, "should've skipped all manual numbers");
178
1
  REQUIRE_TENSOR_EQ(sl, sb, "computed stats should be equal");
179
1
  ccv_nnc_tensor_free(a);
180
1
  ccv_nnc_tensor_view_free(av);
181
1
  ccv_nnc_tensor_free(h);
182
1
  ccv_nnc_tensor_free(bl);
183
1
  ccv_nnc_tensor_free(bb);
184
1
  ccv_nnc_tensor_free(sl);
185
1
  ccv_nnc_tensor_free(sb);
186
1
}
187
188
TEST_CASE("even histogram v.s. bins histogram on tensor view")
189
1
{
190
1
  ccv_nnc_tensor_t* const a = ccv_nnc_tensor_new(0, CPU_TENSOR_NCHW(32F, 30, 100, 20, 100), 0);
191
1
  ccv_nnc_tensor_t* const h = ccv_nnc_tensor_new(0, CPU_TENSOR_NCHW(32F, 201), 0);
192
1
  int i;
193
202
  for (i = 0; i < 201; 
i++201
)
194
201
  {
195
201
    h->data.f32[i] = (i - 100) * 10;
196
201
  }
197
1
  dsfmt_t dsfmt;
198
1
  dsfmt_init_gen_rand(&dsfmt, 1);
199
6.00M
  for (i = 0; i < 3000 * 2000; 
i++6.00M
)
200
6.00M
    a->data.f32[i] = dsfmt_genrand_open_close(&dsfmt) * 2000 - 1000;
201
1
  ccv_nnc_tensor_view_t* const av = ccv_nnc_tensor_view_new(a, CPU_TENSOR_NCHW(32F, 30, 20, 20, 40), DIM_ALLOC(0, 10, 0, 20), DIM_ALLOC(100 * 20 * 100, 20 * 100, 100, 1));
202
1
  a->data.f32[0] = NAN;
203
1
  a->data.f32[1] = -FLT_MAX;
204
1
  a->data.f32[2] = FLT_MAX;
205
1
  a->data.f32[3] = 0;
206
1
  a->data.f32[4] = 1e-20;
207
1
  a->data.f32[5] = -1e-20;
208
1
  a->data.f32[6] = 1e20 - 1e18;
209
1
  a->data.f32[7] = -1e20 + 1e18;
210
1
  ccv_nnc_tensor_t* const bl = ccv_nnc_tensor_new(0, CPU_TENSOR_NCHW(32S, 203), 0);
211
1
  ccv_nnc_tensor_t* const bb = ccv_nnc_tensor_new(0, CPU_TENSOR_NCHW(32S, 203), 0);
212
1
  ccv_nnc_tensor_t* const sl = ccv_nnc_tensor_new(0, CPU_TENSOR_NCHW(32F, 4), 0);
213
1
  ccv_nnc_tensor_t* const sb = ccv_nnc_tensor_new(0, CPU_TENSOR_NCHW(32F, 4), 0);
214
1
  ccv_nnc_cmd_exec(CMD_HISTOGRAM_EVEN(200, -1000, 1000), ccv_nnc_no_hint, 0, TENSOR_LIST((ccv_nnc_tensor_t*)av), TENSOR_LIST(bl, sl), 0);
215
1
  ccv_nnc_cmd_exec(CMD_HISTOGRAM_BINS(), ccv_nnc_no_hint, 0, TENSOR_LIST((ccv_nnc_tensor_t*)av, h), TENSOR_LIST(bb, sb), 0);
216
204
  for (i = 0; i < 203; 
i++203
)
217
203
  {
218
203
    const int diff = abs(bb->data.i32[i] - bl->data.i32[i]);
219
203
    REQUIRE(diff < 5, "differences should be smaller than 5 for bl->data.i32[%d](%d), bb->data.i32[%d](%d)", i, bl->data.i32[i], i, bb->data.i32[i]);
220
203
  }
221
1
  REQUIRE(sl->data.f32[0] < -990, "minimal should be close to the edge");
222
1
  REQUIRE(sl->data.f32[1] > 990, "maximal should be close to the edge");
223
1
  REQUIRE(sl->data.f32[2] / (float)ccv_nnc_tensor_count(av->info) < 1, "sum should be close to 0");
224
1
  REQUIRE_EQ_WITH_TOLERANCE(sl->data.f32[3] / (float)ccv_nnc_tensor_count(av->info), 2000 * 2000 / 12, 1e3, "sum of squares should be close to its expected value in uniform distribution");
225
1
  REQUIRE_EQ(bb->data.i32[0], 0, "should've skipped all manual numbers");
226
1
  REQUIRE_EQ(bb->data.i32[201], 0, "should've skipped all manual numbers");
227
1
  REQUIRE_EQ(bb->data.i32[202], 0, "should've skipped all manual numbers");
228
1
  REQUIRE_EQ(bl->data.i32[0], 0, "should've skipped all manual numbers");
229
1
  REQUIRE_EQ(bl->data.i32[201], 0, "should've skipped all manual numbers");
230
1
  REQUIRE_EQ(bl->data.i32[202], 0, "should've skipped all manual numbers");
231
1
  REQUIRE_TENSOR_EQ(sl, sb, "computed stats should be equal");
232
1
  ccv_nnc_tensor_free(a);
233
1
  ccv_nnc_tensor_view_free(av);
234
1
  ccv_nnc_tensor_free(h);
235
1
  ccv_nnc_tensor_free(bl);
236
1
  ccv_nnc_tensor_free(bb);
237
1
  ccv_nnc_tensor_free(sl);
238
1
  ccv_nnc_tensor_free(sb);
239
1
}
240
241
#include "case_main.h"