/home/liu/actions-runner/_work/ccv/ccv/test/unit/util.tests.c
Line | Count | Source |
1 | | #include "ccv.h" |
2 | | #include "case.h" |
3 | | #include "ccv_case.h" |
4 | | #include "3rdparty/dsfmt/dSFMT.h" |
5 | | #include "3rdparty/sfmt/SFMT.h" |
6 | | |
7 | | TEST_CASE("type size macro") |
8 | 1 | { |
9 | 1 | REQUIRE_EQ(CCV_GET_DATA_TYPE_SIZE(CCV_8U), 1, "CCV_8U should have size 1"); |
10 | 1 | REQUIRE_EQ(CCV_GET_DATA_TYPE_SIZE(CCV_32S), 4, "CCV_32S should have size 4"); |
11 | 1 | REQUIRE_EQ(CCV_GET_DATA_TYPE_SIZE(CCV_32F), 4, "CCV_32F should have size 4"); |
12 | 1 | REQUIRE_EQ(CCV_GET_DATA_TYPE_SIZE(CCV_64S), 8, "CCV_64S should have size 8"); |
13 | 1 | REQUIRE_EQ(CCV_GET_DATA_TYPE_SIZE(CCV_64F), 8, "CCV_64F should have size 8"); |
14 | 1 | REQUIRE_EQ(CCV_GET_DATA_TYPE_SIZE(CCV_16F), 2, "CCV_64F should have size 2"); |
15 | 1 | REQUIRE_EQ(sizeof(ccv_float16_t), 2, "sizeof float16 should be 2"); |
16 | 1 | } |
17 | | |
18 | | TEST_CASE("dynamic array") |
19 | 1 | { |
20 | 1 | ccv_array_t* array = ccv_array_new(4, 2, 0); |
21 | 1 | int i; |
22 | 1 | i = 1; |
23 | 1 | ccv_array_push(array, &i); |
24 | 1 | i = 2; |
25 | 1 | ccv_array_push(array, &i); |
26 | 1 | i = 3; |
27 | 1 | ccv_array_push(array, &i); |
28 | 1 | i = 4; |
29 | 1 | ccv_array_push(array, &i); |
30 | 1 | i = 5; |
31 | 1 | ccv_array_push(array, &i); |
32 | 1 | REQUIRE_EQ(5, array->rnum, "should have 5 elements pushed to array"); |
33 | 6 | for (i = 0; i < array->rnum; i++5 ) |
34 | 5 | REQUIRE_EQ(i + 1, ((int*)ccv_array_get(array, i))[0], "check element values in array"); |
35 | 1 | ccv_array_clear(array); |
36 | 1 | i = 3; |
37 | 1 | ccv_array_push(array, &i); |
38 | 1 | i = 4; |
39 | 1 | ccv_array_push(array, &i); |
40 | 1 | i = 5; |
41 | 1 | ccv_array_push(array, &i); |
42 | 1 | REQUIRE_EQ(3, array->rnum, "should have 3 elements after clear"); |
43 | 4 | for (i = 0; i < array->rnum; i++3 ) |
44 | 3 | REQUIRE_EQ(i + 3, ((int*)ccv_array_get(array, i))[0], "check element values in array after clear at index %d", i); |
45 | 1 | ccv_array_free(array); |
46 | 1 | } |
47 | | |
48 | | TEST_CASE("array resize") |
49 | 1 | { |
50 | 1 | ccv_array_t* array = ccv_array_new(4, 2, 0); |
51 | 1 | int i; |
52 | 1 | i = 1; |
53 | 1 | ccv_array_push(array, &i); |
54 | 1 | ccv_array_resize(array, 4); |
55 | 1 | REQUIRE_EQ(4, array->rnum, "should have 4 elements in array"); |
56 | 1 | REQUIRE_EQ(1, ((int*)ccv_array_get(array, 0))[0], "check element values in array"); |
57 | 4 | for (i = 1; i < array->rnum; i++3 ) |
58 | 3 | REQUIRE_EQ(0, ((int*)ccv_array_get(array, i))[0], "check element values in array"); |
59 | 1 | ccv_array_free(array); |
60 | 1 | } |
61 | | |
62 | | int is_equal(const void* r1, const void* r2, void* data) |
63 | 56 | { |
64 | 56 | int a = *(int*)r1; |
65 | 56 | int b = *(int*)r2; |
66 | 56 | return a == b; |
67 | 56 | } |
68 | | |
69 | | TEST_CASE("group array with is_equal function") |
70 | 1 | { |
71 | 1 | ccv_array_t* array = ccv_array_new(4, 2, 0); |
72 | 1 | int i; |
73 | 1 | i = 1; |
74 | 1 | ccv_array_push(array, &i); |
75 | 1 | i = 2; |
76 | 1 | ccv_array_push(array, &i); |
77 | 1 | i = 2; |
78 | 1 | ccv_array_push(array, &i); |
79 | 1 | i = 2; |
80 | 1 | ccv_array_push(array, &i); |
81 | 1 | i = 5; |
82 | 1 | ccv_array_push(array, &i); |
83 | 1 | i = 3; |
84 | 1 | ccv_array_push(array, &i); |
85 | 1 | i = 4; |
86 | 1 | ccv_array_push(array, &i); |
87 | 1 | i = 5; |
88 | 1 | ccv_array_push(array, &i); |
89 | 1 | ccv_array_t* idx = 0; |
90 | 1 | ccv_array_group(array, &idx, is_equal, 0); |
91 | 1 | REQUIRE_EQ(((int*)ccv_array_get(idx, 1))[0], ((int*)ccv_array_get(idx, 2))[0], "element 2, 3 should in the same group"); |
92 | 1 | REQUIRE_EQ(((int*)ccv_array_get(idx, 2))[0], ((int*)ccv_array_get(idx, 3))[0], "element 3, 4 should in the same group"); |
93 | 1 | REQUIRE_EQ(((int*)ccv_array_get(idx, 4))[0], ((int*)ccv_array_get(idx, 7))[0], "element 4, 8 should in the same group"); |
94 | 1 | REQUIRE_NOT_EQ(((int*)ccv_array_get(idx, 0))[0], ((int*)ccv_array_get(idx, 1))[0], "element 1, 2 should not in the same group"); |
95 | 1 | REQUIRE_NOT_EQ(((int*)ccv_array_get(idx, 0))[0], ((int*)ccv_array_get(idx, 4))[0], "element 1, 5 should not in the same group"); |
96 | 1 | REQUIRE_NOT_EQ(((int*)ccv_array_get(idx, 0))[0], ((int*)ccv_array_get(idx, 5))[0], "element 1, 6 should not in the same group"); |
97 | 1 | REQUIRE_NOT_EQ(((int*)ccv_array_get(idx, 0))[0], ((int*)ccv_array_get(idx, 6))[0], "element 1, 7 should not in the same group"); |
98 | 1 | REQUIRE_NOT_EQ(((int*)ccv_array_get(idx, 1))[0], ((int*)ccv_array_get(idx, 4))[0], "element 2, 5 should not in the same group"); |
99 | 1 | REQUIRE_NOT_EQ(((int*)ccv_array_get(idx, 1))[0], ((int*)ccv_array_get(idx, 5))[0], "element 2, 6 should not in the same group"); |
100 | 1 | REQUIRE_NOT_EQ(((int*)ccv_array_get(idx, 1))[0], ((int*)ccv_array_get(idx, 6))[0], "element 2, 7 should not in the same group"); |
101 | 1 | REQUIRE_NOT_EQ(((int*)ccv_array_get(idx, 4))[0], ((int*)ccv_array_get(idx, 5))[0], "element 5, 6 should not in the same group"); |
102 | 1 | REQUIRE_NOT_EQ(((int*)ccv_array_get(idx, 4))[0], ((int*)ccv_array_get(idx, 6))[0], "element 5, 7 should not in the same group"); |
103 | 1 | REQUIRE_NOT_EQ(((int*)ccv_array_get(idx, 5))[0], ((int*)ccv_array_get(idx, 6))[0], "element 6, 7 should not in the same group"); |
104 | 1 | ccv_array_free(array); |
105 | 1 | ccv_array_free(idx); |
106 | 1 | } |
107 | | |
108 | | TEST_CASE("specific sparse matrix insertion") |
109 | 1 | { |
110 | 1 | ccv_sparse_matrix_t* mat = ccv_sparse_matrix_new(1, 70, CCV_32S | CCV_C1, CCV_SPARSE_ROW_MAJOR, 0); |
111 | 1 | const int k = 1; |
112 | 1 | int idx[] = {26, 29, 30, 34, 35, 38, 39, 42, 43, 47, 48, 51, 52, 55, 56, 60, 61, 65, 66, 68, 69}; |
113 | 1 | int i; |
114 | 22 | for (i = 0; i < sizeof(idx) / sizeof(int); i++21 ) |
115 | 21 | ccv_set_sparse_matrix_cell(mat, 0, idx[i], &k); |
116 | 22 | for (i = 0; i < sizeof(idx) / sizeof(int); i++21 ) |
117 | 21 | { |
118 | 21 | ccv_numeric_data_t cell = ccv_get_sparse_matrix_cell(mat, 0, idx[i]); |
119 | 21 | REQUIRE(cell.u8 != 0, "cell at (%d, %d) doesn't contain any valid value", 0, idx[i]); |
120 | 21 | REQUIRE_EQ(1, cell.i32[0], "cell at (%d, %d) doesn't match inserted value", 0, idx[i]); |
121 | 21 | } |
122 | 1 | ccv_matrix_free(mat); |
123 | 1 | } |
124 | | |
125 | | TEST_CASE("sparse matrix basic insertion") |
126 | 1 | { |
127 | 1 | ccv_sparse_matrix_t* mat = ccv_sparse_matrix_new(1000, 1000, CCV_32S | CCV_C1, CCV_SPARSE_ROW_MAJOR, 0); |
128 | 1 | int i, j, k, n; |
129 | 1 | k = 0; |
130 | 1.00k | for (i = 0; i < 1000; i++1.00k ) |
131 | 1.00M | for (j = 0; 1.00k j < 1000; j++1.00M ) |
132 | 1.00M | { |
133 | 1.00M | ccv_set_sparse_matrix_cell(mat, i, j, &k); |
134 | 1.00M | k++; |
135 | 1.00M | } |
136 | 1 | REQUIRE_EQ(1597, mat->size, "sparse matrix column size should be the prime number 1597"); |
137 | 101 | for (n = 0; n < 100; n++100 ) |
138 | 100 | { |
139 | 100 | k = 0; |
140 | 100k | for (i = 0; i < 1000; i++100k ) |
141 | 100M | for (j = 0; 100k j < 1000; j++100M ) |
142 | 100M | { |
143 | 100M | ccv_numeric_data_t cell = ccv_get_sparse_matrix_cell(mat, i, j); |
144 | 100M | REQUIRE(cell.u8 != 0, "cell at (%d, %d) doesn't contain any valid value", i, j); |
145 | 100M | REQUIRE_EQ(k, cell.i32[0], "cell at (%d, %d) doesn't match inserted value", i, j); |
146 | 100M | k++; |
147 | 100M | } |
148 | 100 | } |
149 | 1 | ccv_matrix_free(mat); |
150 | 1 | } |
151 | | |
152 | | TEST_CASE("compress sparse matrix") |
153 | 1 | { |
154 | 1 | ccv_sparse_matrix_t* mat = ccv_sparse_matrix_new(3, 3, CCV_32F | CCV_C1, CCV_SPARSE_ROW_MAJOR, 0); |
155 | 1 | float cell; |
156 | 1 | cell = 1.0; |
157 | 1 | ccv_set_sparse_matrix_cell(mat, 0, 0, &cell); |
158 | 1 | cell = 2.0; |
159 | 1 | ccv_set_sparse_matrix_cell(mat, 0, 2, &cell); |
160 | 1 | cell = 3.0; |
161 | 1 | ccv_set_sparse_matrix_cell(mat, 1, 2, &cell); |
162 | 1 | cell = 4.0; |
163 | 1 | ccv_set_sparse_matrix_cell(mat, 2, 0, &cell); |
164 | 1 | cell = 5.0; |
165 | 1 | ccv_set_sparse_matrix_cell(mat, 2, 1, &cell); |
166 | 1 | cell = 6.0; |
167 | 1 | ccv_set_sparse_matrix_cell(mat, 2, 2, &cell); |
168 | 1 | ccv_compressed_sparse_matrix_t* csm = 0; |
169 | 1 | ccv_compress_sparse_matrix(mat, &csm); |
170 | 1 | float dm[6] = {1, 2, 3, 4, 5, 6}; |
171 | 1 | int di[6] = {0, 2, 2, 0, 1, 2}; |
172 | 1 | REQUIRE_EQ(6, csm->nnz, "compress to non-zero factor of 6"); |
173 | 1 | REQUIRE_ARRAY_EQ_WITH_TOLERANCE(float, dm, csm->data.f32, 6, 1e-6, "actual element value should be the same"); |
174 | 1 | REQUIRE_ARRAY_EQ(int, di, csm->index, 6, "element index of CSR"); |
175 | 1 | REQUIRE_EQ(3, csm->rows, "compress should have the same number of rows (CSR)"); |
176 | 1 | int df[4] = {0, 2, 3, 6}; |
177 | 1 | REQUIRE_ARRAY_EQ(int, df, csm->offset, 4, "offset of leading element in each row"); |
178 | 1 | ccv_sparse_matrix_t* smt = 0; |
179 | 1 | ccv_decompress_sparse_matrix(csm, &smt); |
180 | 1 | float m[3][3] = {{1, 0, 2}, {0, 0, 3}, {4, 5, 6}}; |
181 | 1 | int i, j; |
182 | 4 | for (i = 0; i < 3; i++3 ) |
183 | 12 | for (j = 0; 3 j < 3; j++9 ) |
184 | 9 | { |
185 | 9 | ccv_numeric_data_t cell = ccv_get_sparse_matrix_cell(smt, i, j); |
186 | 9 | REQUIRE_EQ_WITH_TOLERANCE(m[i][j], (cell.u8 != 0) ? cell.f32[0] : 0, 1e-6, "should have the same matrix after decompressed at row %d, col %d", i, j); |
187 | 9 | } |
188 | 1 | ccv_matrix_free(smt); |
189 | 1 | ccv_matrix_free(mat); |
190 | 1 | ccv_matrix_free(csm); |
191 | 1 | } |
192 | | |
193 | | TEST_CASE("loop over sparse matrix") |
194 | 1 | { |
195 | 1 | ccv_sparse_matrix_t* mat = ccv_sparse_matrix_new(1000, 1000, CCV_32F | CCV_C1, CCV_SPARSE_ROW_MAJOR, 0); |
196 | 1 | ccv_dense_matrix_t* a = ccv_dense_matrix_new(1000, 1000, CCV_32F | CCV_C1, 0, 0); |
197 | 1 | ccv_zero(a); |
198 | 1 | ccv_dense_matrix_t* b = ccv_dense_matrix_new(1000, 1000, CCV_32F | CCV_C1, 0, 0); |
199 | 1 | ccv_zero(b); |
200 | 1 | dsfmt_t dsfmt; |
201 | 1 | dsfmt_init_gen_rand(&dsfmt, 0xdead); |
202 | 1 | sfmt_t sfmt; |
203 | 1 | sfmt_init_gen_rand(&sfmt, 0xbeef); |
204 | 1 | int i; |
205 | 51 | for (i = 0; i < 50; i++50 ) |
206 | 50 | { |
207 | 50 | int x = sfmt_genrand_uint32(&sfmt) % 1000; |
208 | 50 | int y = sfmt_genrand_uint32(&sfmt) % 1000; |
209 | 50 | float v = dsfmt_genrand_close_open(&dsfmt); |
210 | 50 | a->data.f32[y * 1000 + x] = v; |
211 | 50 | ccv_set_sparse_matrix_cell(mat, y, x, &v); |
212 | 50 | } |
213 | 50 | #define block(y, x, v) { b->data.f32[y * 1000 + x] = ((float*)v)[0]; } |
214 | 50 | CCV_SPARSE_FOREACH1 (mat, block); |
215 | 1 | #undef block |
216 | 1 | REQUIRE_MATRIX_EQ(a, b, "matrix should be exactly equal when looped over the sparse one"); |
217 | 1 | ccv_matrix_free(mat); |
218 | 1 | ccv_matrix_free(a); |
219 | 1 | ccv_matrix_free(b); |
220 | 1 | } |
221 | | |
222 | | TEST_CASE("loop over column major sparse matrix") |
223 | 1 | { |
224 | 1 | ccv_sparse_matrix_t* mat = ccv_sparse_matrix_new(1000, 1000, CCV_32F | CCV_C1, CCV_SPARSE_COL_MAJOR, 0); |
225 | 1 | ccv_dense_matrix_t* a = ccv_dense_matrix_new(1000, 1000, CCV_32F | CCV_C1, 0, 0); |
226 | 1 | ccv_zero(a); |
227 | 1 | ccv_dense_matrix_t* b = ccv_dense_matrix_new(1000, 1000, CCV_32F | CCV_C1, 0, 0); |
228 | 1 | ccv_zero(b); |
229 | 1 | dsfmt_t dsfmt; |
230 | 1 | dsfmt_init_gen_rand(&dsfmt, 0xdead); |
231 | 1 | sfmt_t sfmt; |
232 | 1 | sfmt_init_gen_rand(&sfmt, 0xbeef); |
233 | 1 | int i; |
234 | 201 | for (i = 0; i < 200; i++200 ) |
235 | 200 | { |
236 | 200 | int x = sfmt_genrand_uint32(&sfmt) % 1000; |
237 | 200 | int y = sfmt_genrand_uint32(&sfmt) % 1000; |
238 | 200 | float v = dsfmt_genrand_close_open(&dsfmt); |
239 | 200 | a->data.f32[y * 1000 + x] = v; |
240 | 200 | ccv_set_sparse_matrix_cell(mat, y, x, &v); |
241 | 200 | } |
242 | 200 | #define block(y, x, v) { b->data.f32[y * 1000 + x] = ((float*)v)[0]; } |
243 | 200 | CCV_SPARSE_FOREACH1 (mat, block); |
244 | 1 | #undef block |
245 | 1 | REQUIRE_MATRIX_EQ(a, b, "matrix should be exactly equal when looped over the sparse one"); |
246 | 1 | ccv_matrix_free(mat); |
247 | 1 | ccv_matrix_free(a); |
248 | 1 | ccv_matrix_free(b); |
249 | 1 | } |
250 | | |
251 | | TEST_CASE("loop over sparse matrix with dense vector") |
252 | 1 | { |
253 | 1 | ccv_sparse_matrix_t* mat = ccv_sparse_matrix_new(1000, 1000, CCV_32F | CCV_C1 | CCV_DENSE_VECTOR, CCV_SPARSE_ROW_MAJOR, 0); |
254 | 1 | ccv_dense_matrix_t* a = ccv_dense_matrix_new(1000, 1000, CCV_32F | CCV_C1, 0, 0); |
255 | 1 | ccv_zero(a); |
256 | 1 | ccv_dense_matrix_t* b = ccv_dense_matrix_new(1000, 1000, CCV_32F | CCV_C1, 0, 0); |
257 | 1 | ccv_zero(b); |
258 | 1 | dsfmt_t dsfmt; |
259 | 1 | dsfmt_init_gen_rand(&dsfmt, 0xdead); |
260 | 1 | sfmt_t sfmt; |
261 | 1 | sfmt_init_gen_rand(&sfmt, 0xbeef); |
262 | 1 | int i; |
263 | 201 | for (i = 0; i < 200; i++200 ) |
264 | 200 | { |
265 | 200 | int x = sfmt_genrand_uint32(&sfmt) % 1000; |
266 | 200 | int y = sfmt_genrand_uint32(&sfmt) % 1000; |
267 | 200 | float v = dsfmt_genrand_close_open(&dsfmt); |
268 | 200 | a->data.f32[y * 1000 + x] = v; |
269 | 200 | ccv_set_sparse_matrix_cell(mat, y, x, &v); |
270 | 200 | } |
271 | 182k | #define block(y, x, v) { b->data.f32[y * 1000 + x] = ((float*)v)[0]; } |
272 | 182k | CCV_SPARSE_FOREACH1 (mat, block); |
273 | 1 | #undef block |
274 | 1 | REQUIRE_MATRIX_EQ(a, b, "matrix should be exactly equal when looped over the sparse one"); |
275 | 1 | ccv_matrix_free(mat); |
276 | 1 | ccv_matrix_free(a); |
277 | 1 | ccv_matrix_free(b); |
278 | 1 | } |
279 | | |
280 | | TEST_CASE("loop over sparse matrix vector") |
281 | 1 | { |
282 | 1 | ccv_sparse_matrix_t* mat = ccv_sparse_matrix_new(1000, 1000, CCV_32F | CCV_C1, CCV_SPARSE_ROW_MAJOR, 0); |
283 | 1 | ccv_dense_matrix_t* a = ccv_dense_matrix_new(1, 1000, CCV_32F | CCV_C1, 0, 0); |
284 | 1 | ccv_zero(a); |
285 | 1 | ccv_dense_matrix_t* b = ccv_dense_matrix_new(1, 1000, CCV_32F | CCV_C1, 0, 0); |
286 | 1 | ccv_zero(b); |
287 | 1 | dsfmt_t dsfmt; |
288 | 1 | dsfmt_init_gen_rand(&dsfmt, 0xdead); |
289 | 1 | sfmt_t sfmt; |
290 | 1 | sfmt_init_gen_rand(&sfmt, 0xbeef); |
291 | 1 | int i; |
292 | 51 | for (i = 0; i < 50; i++50 ) |
293 | 50 | { |
294 | 50 | int x = sfmt_genrand_uint32(&sfmt) % 1000; |
295 | 50 | float v = dsfmt_genrand_close_open(&dsfmt); |
296 | 50 | a->data.f32[x] = v; |
297 | 50 | ccv_set_sparse_matrix_cell(mat, 38, x, &v); |
298 | 50 | } |
299 | 1 | ccv_sparse_matrix_vector_t* vector = ccv_get_sparse_matrix_vector(mat, 38); |
300 | 48 | #define block(x, v) { b->data.f32[x] = ((float*)v)[0]; } |
301 | 48 | CCV_SPARSE_VECTOR_FOREACH1 (mat, vector, block); |
302 | 1 | #undef block |
303 | 1 | REQUIRE_MATRIX_EQ(a, b, "matrix should be exactly equal when looped over the sparse one"); |
304 | 1 | ccv_matrix_free(mat); |
305 | 1 | ccv_matrix_free(a); |
306 | 1 | ccv_matrix_free(b); |
307 | 1 | } |
308 | | |
309 | | TEST_CASE("loop over sparse matrix dense vector") |
310 | 1 | { |
311 | 1 | ccv_sparse_matrix_t* mat = ccv_sparse_matrix_new(1000, 1000, CCV_32F | CCV_C1 | CCV_DENSE_VECTOR, CCV_SPARSE_ROW_MAJOR, 0); |
312 | 1 | ccv_dense_matrix_t* a = ccv_dense_matrix_new(1, 1000, CCV_32F | CCV_C1, 0, 0); |
313 | 1 | ccv_zero(a); |
314 | 1 | ccv_dense_matrix_t* b = ccv_dense_matrix_new(1, 1000, CCV_32F | CCV_C1, 0, 0); |
315 | 1 | ccv_zero(b); |
316 | 1 | dsfmt_t dsfmt; |
317 | 1 | dsfmt_init_gen_rand(&dsfmt, 0xdead); |
318 | 1 | sfmt_t sfmt; |
319 | 1 | sfmt_init_gen_rand(&sfmt, 0xbeef); |
320 | 1 | int i; |
321 | 201 | for (i = 0; i < 200; i++200 ) |
322 | 200 | { |
323 | 200 | int x = sfmt_genrand_uint32(&sfmt) % 1000; |
324 | 200 | float v = dsfmt_genrand_close_open(&dsfmt); |
325 | 200 | a->data.f32[x] = v; |
326 | 200 | ccv_set_sparse_matrix_cell(mat, 38, x, &v); |
327 | 200 | } |
328 | 1 | ccv_sparse_matrix_vector_t* vector = ccv_get_sparse_matrix_vector(mat, 38); |
329 | 1.00k | #define block(x, v) { b->data.f32[x] = ((float*)v)[0]; } |
330 | 1.00k | CCV_SPARSE_VECTOR_FOREACH1 (mat, vector, block); |
331 | 1 | #undef block |
332 | 1 | REQUIRE_MATRIX_EQ(a, b, "matrix should be exactly equal when looped over the sparse one"); |
333 | 1 | ccv_matrix_free(mat); |
334 | 1 | ccv_matrix_free(a); |
335 | 1 | ccv_matrix_free(b); |
336 | 1 | } |
337 | | |
338 | | #ifdef HAVE_LIBPNG |
339 | | TEST_CASE("matrix slice") |
340 | 1 | { |
341 | 1 | ccv_dense_matrix_t* image = 0; |
342 | 1 | ccv_read("../../samples/chessbox.png", &image, CCV_IO_ANY_FILE); |
343 | 1 | ccv_dense_matrix_t* b = 0; |
344 | 1 | ccv_slice(image, (ccv_matrix_t**)&b, 0, 33, 41, 111, 91); |
345 | 1 | REQUIRE_MATRIX_FILE_EQ(b, "data/chessbox.slice.bin", "should have data/chessbox.png sliced at (33, 41) with 111 x 91"); |
346 | 1 | ccv_matrix_free(image); |
347 | 1 | ccv_matrix_free(b); |
348 | 1 | } |
349 | | #endif |
350 | | |
351 | | TEST_CASE("matrix flatten") |
352 | 1 | { |
353 | 1 | ccv_dense_matrix_t* dmt = ccv_dense_matrix_new(2, 2, CCV_8U | CCV_C2, 0, 0); |
354 | 1 | dmt->data.u8[0] = 200; |
355 | 1 | dmt->data.u8[1] = 100; |
356 | 1 | dmt->data.u8[2] = 150; |
357 | 1 | dmt->data.u8[3] = 50; |
358 | 1 | dmt->data.u8[4] = 25; |
359 | 1 | dmt->data.u8[5] = 20; |
360 | 1 | dmt->data.u8[6] = 200; |
361 | 1 | dmt->data.u8[7] = 250; |
362 | 1 | ccv_dense_matrix_t* result = 0; |
363 | 1 | ccv_flatten(dmt, (ccv_matrix_t**)&result, 0, 0); |
364 | 1 | ccv_matrix_free(dmt); |
365 | 1 | int rf[4] = {300, 200, 45, 450}; |
366 | 1 | REQUIRE_EQ(CCV_GET_CHANNEL(result->type), CCV_C1, "flatten matrix should have only one channel"); |
367 | 1 | REQUIRE_ARRAY_EQ(int, result->data.i32, rf, 4, "matrix flatten should have same value as reference array"); |
368 | 1 | ccv_matrix_free(result); |
369 | 1 | } |
370 | | |
371 | | TEST_CASE("matrix reshape") |
372 | 1 | { |
373 | 1 | ccv_dense_matrix_t* dmt = ccv_dense_matrix_new(2, 4, CCV_32S | CCV_C1, 0, 0); |
374 | 1 | dmt->data.i32[0] = 200; |
375 | 1 | dmt->data.i32[1] = 100; |
376 | 1 | dmt->data.i32[2] = 150; |
377 | 1 | dmt->data.i32[3] = 50; |
378 | 1 | dmt->data.i32[4] = 25; |
379 | 1 | dmt->data.i32[5] = 20; |
380 | 1 | dmt->data.i32[6] = 200; |
381 | 1 | dmt->data.i32[7] = 250; |
382 | 1 | ccv_dense_matrix_t sub = ccv_reshape(dmt, 0, 2, 2, 2); |
383 | 1 | ccv_dense_matrix_t* a = ccv_dense_matrix_new(2, 2, CCV_32S | CCV_C1, 0, 0); |
384 | 1 | a->data.i32[0] = 100; |
385 | 1 | a->data.i32[1] = 100; |
386 | 1 | a->data.i32[2] = 100; |
387 | 1 | a->data.i32[3] = 100; |
388 | 1 | ccv_subtract(a, &sub, (ccv_matrix_t**)&a, 0); |
389 | 1 | int rf[4] = {-50, 50, -100, -150}; |
390 | 1 | REQUIRE_ARRAY_EQ(int, a->data.i32, rf, 4, "matrix subtract a reshaped matrix should have same value as reference array"); |
391 | 1 | ccv_matrix_free(a); |
392 | 1 | ccv_matrix_free(dmt); |
393 | 1 | } |
394 | | |
395 | | TEST_CASE("matrix border") |
396 | 1 | { |
397 | 1 | ccv_dense_matrix_t* dmt = ccv_dense_matrix_new(1, 1, CCV_32F | CCV_C1, 0, 0); |
398 | 1 | dmt->data.f32[0] = 2.0; |
399 | 1 | ccv_dense_matrix_t* result = 0; |
400 | 1 | ccv_margin_t margin = ccv_margin(2, 3, 1, 2); |
401 | 1 | ccv_border(dmt, (ccv_matrix_t**)&result, 0, margin); |
402 | 1 | ccv_matrix_free(dmt); |
403 | 1 | float rf[24] = { |
404 | 1 | 0, 0, 0, 0, |
405 | 1 | 0, 0, 0, 0, |
406 | 1 | 0, 0, 0, 0, |
407 | 1 | 0, 0, 2, 0, |
408 | 1 | 0, 0, 0, 0, |
409 | 1 | 0, 0, 0, 0, |
410 | 1 | }; |
411 | 1 | REQUIRE_EQ(margin.top + margin.bottom + 1, result->rows, "bordered matrix should have margin.top + margin.bottom + 1 rows"); |
412 | 1 | REQUIRE_EQ(margin.left + margin.right + 1, result->cols, "bordered matrix should have margin.left + margin.right + 1 cols"); |
413 | 1 | REQUIRE_ARRAY_EQ_WITH_TOLERANCE(float, result->data.f32, rf, 24, 1e-5, "matrix border should have same value as reference array"); |
414 | 1 | ccv_matrix_free(result); |
415 | 1 | } |
416 | | |
417 | | TEST_CASE("half precision and float-point conversion") |
418 | 1 | { |
419 | 1 | uint16_t* h = (uint16_t*)ccmalloc(sizeof(uint16_t) * 0x10000); |
420 | 1 | float* f = (float*)ccmalloc(sizeof(float) * 0x10000); |
421 | 1 | uint16_t* b = (uint16_t*)ccmalloc(sizeof(uint16_t) * 0x10000); |
422 | 1 | float* c = (float*)ccmalloc(sizeof(float) * 0x10000); |
423 | 1 | int i; |
424 | 65.5k | for (i = 0; i < 0x10000; i++65.5k ) |
425 | 65.5k | h[i] = i; |
426 | 1 | ccv_half_precision_to_float(h, f, 0x10000); |
427 | 1 | ccv_float_to_half_precision(f, b, 0x10000); |
428 | 1 | REQUIRE_ARRAY_EQ(uint16_t, h, b, 0x10000, "half precision convert to float and then convert back should match exactly"); |
429 | 2.05k | for (i = 0; i <= 2048; i++2.04k ) |
430 | 2.04k | f[i] = i; |
431 | 1 | ccv_float_to_half_precision(f, h, 2049); |
432 | 1 | ccv_half_precision_to_float(h, c, 2049); |
433 | 1 | REQUIRE_ARRAY_EQ_WITH_TOLERANCE(float, f, c, 2049, 1e-5, "0-2048 integer to half precision and convert back should match exactly"); |
434 | 4.09k | for (i = 4097; i <= 8192; i++4.09k ) |
435 | 4.09k | f[i - 4097] = i; |
436 | 1 | ccv_float_to_half_precision(f, h, 8192 - 4097 + 1); |
437 | 1 | ccv_half_precision_to_float(h, c, 8192 - 4097 + 1); |
438 | 1 | REQUIRE_ARRAY_EQ_WITH_TOLERANCE(float, f, c, 8192 - 4097 + 1, 4 + 1e-5, "4097-8192 integer to half precision and convert back should round to multiple of 4"); |
439 | 1 | ccfree(h); |
440 | 1 | ccfree(f); |
441 | 1 | ccfree(b); |
442 | 1 | ccfree(c); |
443 | 1 | } |
444 | | |
445 | | #include "case_main.h" |