Coverage Report

Created: 2026-05-04 15:30

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/home/liu/actions-runner/_work/ccv/ccv/test/unit/nnc/tensor.tests.c
Line
Count
Source
1
#include "ccv.h"
2
#include "case.h"
3
#include "ccv_case.h"
4
#include "ccv_nnc_case.h"
5
#include "nnc/ccv_nnc.h"
6
#include "nnc/ccv_nnc_easy.h"
7
#include "3rdparty/sqlite3/sqlite3.h"
8
#include "3rdparty/dsfmt/dSFMT.h"
9
10
TEST_SETUP()
11
{
12
  ccv_nnc_init();
13
}
14
15
TEST_CASE("zero out a tensor")
16
{
17
  const ccv_nnc_tensor_param_t params = {
18
    .type = CCV_TENSOR_CPU_MEMORY,
19
    .format = CCV_TENSOR_FORMAT_NHWC,
20
    .datatype = CCV_32F,
21
    .dim = {
22
      10, 20, 30, 4, 5, 6,
23
    },
24
  };
25
  ccv_nnc_tensor_t* tensor = ccv_nnc_tensor_new(0, params, 0);
26
  int i;
27
  for (i = 0; i < 10 * 20 * 30 * 4 * 5 * 6; i++)
28
    tensor->data.f32[i] = 1;
29
  ccv_nnc_tensor_zero(tensor);
30
  for (i = 0; i < 10 * 20 * 30 * 4 * 5 * 6; i++)
31
    REQUIRE_EQ(0, tensor->data.f32[i], "should be zero'ed at %d", i);
32
  ccv_nnc_tensor_free(tensor);
33
}
34
35
TEST_CASE("zero out a tensor view")
36
1
{
37
1
  const ccv_nnc_tensor_param_t params = {
38
1
    .type = CCV_TENSOR_CPU_MEMORY,
39
1
    .format = CCV_TENSOR_FORMAT_NHWC,
40
1
    .datatype = CCV_32F,
41
1
    .dim = {
42
1
      10, 20, 30, 4, 5, 6,
43
1
    },
44
1
  };
45
1
  ccv_nnc_tensor_t* a_tensor = ccv_nnc_tensor_new(0, params, 0);
46
1
  int c;
47
720k
  for (c = 0; c < 10 * 20 * 30 * 4 * 5 * 6; 
c++720k
)
48
720k
    a_tensor->data.f32[c] = 1;
49
1
  int ofs[CCV_NNC_MAX_DIM_ALLOC] = {
50
1
    1, 2, 5, 1, 1, 1,
51
1
  };
52
1
  const ccv_nnc_tensor_param_t new_params = {
53
1
    .type = CCV_TENSOR_CPU_MEMORY,
54
1
    .format = CCV_TENSOR_FORMAT_NHWC,
55
1
    .datatype = CCV_32F,
56
1
    .dim = {
57
1
      8, 12, 15, 2, 3, 4,
58
1
    },
59
1
  };
60
1
  ccv_nnc_tensor_view_t a_tensor_view = ccv_nnc_tensor_view(a_tensor, new_params, ofs, DIM_ALLOC(20 * 30 * 4 * 5 * 6, 30 * 4 * 5 * 6, 4 * 5 * 6, 5 * 6, 6, 1));
61
1
  ccv_nnc_tensor_zero(&a_tensor_view);
62
1
  ccv_nnc_tensor_t* b_tensor = ccv_nnc_tensor_new(0, params, 0);
63
720k
  for (c = 0; c < 10 * 20 * 30 * 4 * 5 * 6; 
c++720k
)
64
720k
    b_tensor->data.f32[c] = 1;
65
1
  ccv_nnc_tensor_view_t b_tensor_view = ccv_nnc_tensor_view(b_tensor, new_params, ofs, DIM_ALLOC(20 * 30 * 4 * 5 * 6, 30 * 4 * 5 * 6, 4 * 5 * 6, 5 * 6, 6, 1));
66
1
  int i[6];
67
1
  float* tvp[6];
68
1
  tvp[5] = b_tensor_view.data.f32;
69
9
  for (i[5] = 0; i[5] < b_tensor_view.info.dim[0]; 
i[5]++8
)
70
8
  {
71
8
    tvp[4] = tvp[5];
72
104
    for (i[4] = 0; i[4] < b_tensor_view.info.dim[1]; 
i[4]++96
)
73
96
    {
74
96
      tvp[3] = tvp[4];
75
1.53k
      for (i[3] = 0; i[3] < b_tensor_view.info.dim[2]; 
i[3]++1.44k
)
76
1.44k
      {
77
1.44k
        tvp[2] = tvp[3];
78
4.32k
        for (i[2] = 0; i[2] < b_tensor_view.info.dim[3]; 
i[2]++2.88k
)
79
2.88k
        {
80
2.88k
          tvp[1] = tvp[2];
81
11.5k
          for (i[1] = 0; i[1] < b_tensor_view.info.dim[4]; 
i[1]++8.64k
)
82
8.64k
          {
83
8.64k
            tvp[0] = tvp[1];
84
43.2k
            for (i[0] = 0; i[0] < b_tensor_view.info.dim[5]; 
i[0]++34.5k
)
85
34.5k
            {
86
34.5k
              tvp[0][i[0]] = 0;
87
34.5k
            }
88
8.64k
            tvp[1] += b_tensor_view.stride[4];
89
8.64k
          }
90
2.88k
          tvp[2] += b_tensor_view.stride[3];
91
2.88k
        }
92
1.44k
        tvp[3] += b_tensor_view.stride[2];
93
1.44k
      }
94
96
      tvp[4] += b_tensor_view.stride[1];
95
96
    }
96
8
    tvp[5] += b_tensor_view.stride[0];
97
8
  }
98
1
  REQUIRE_TENSOR_EQ(a_tensor, b_tensor, "zero'ed tensor view should be equal");
99
1
  ccv_nnc_tensor_free(a_tensor);
100
1
  ccv_nnc_tensor_free(b_tensor);
101
1
}
102
103
TEST_CASE("hint tensor")
104
1
{
105
1
  ccv_nnc_tensor_param_t a = CPU_TENSOR_NHWC(32F, 234, 128, 3);
106
1
  ccv_nnc_hint_t hint = {
107
1
    .border = {
108
1
      .begin = {1, 1},
109
1
      .end = {1, 2}
110
1
    },
111
1
    .stride = {
112
1
      .dim = {8, 7}
113
1
    }
114
1
  };
115
1
  ccv_nnc_cmd_t cmd = CMD_CONVOLUTION_FORWARD(1, 128, 4, 5, 3);
116
1
  ccv_nnc_tensor_param_t b;
117
1
  ccv_nnc_tensor_param_t w = CPU_TENSOR_NHWC(32F, 128, 4, 5, 3);
118
1
  ccv_nnc_tensor_param_t bias = CPU_TENSOR_NHWC(32F, 128);
119
1
  ccv_nnc_hint_tensor_auto(cmd, TENSOR_PARAM_LIST(a, w, bias), hint, &b, 1);
120
1
  REQUIRE_EQ(b.dim[0], 30, "height should be 30");
121
1
  REQUIRE_EQ(b.dim[1], 19, "width should be 19");
122
1
  REQUIRE_EQ(b.dim[2], 128, "channel should be the convolution filter count");
123
1
}
124
125
TEST_CASE("tensor mapped from file")
126
1
{
127
1
  FILE* w = fopen("data/tensor.bin", "w+");
128
1
  float* w_a = (float*)ccmalloc(sizeof(float) * 4096 * 5);
129
1
  int i;
130
20.4k
  for (i = 0; i < 4096 * 5; 
i++20.4k
)
131
20.4k
    w_a[i] = (float)(i + 1);
132
1
  fwrite(w_a, 1, sizeof(float) * 4096 * 5, w);
133
1
  fclose(w);
134
1
  ccfree(w_a);
135
1
  float a[] = {1, 2, 3, 4, 5};
136
1
  ccv_nnc_tensor_t* tensor_a = ccv_nnc_tensor_new_from_file(CPU_TENSOR_NHWC(32F, 5), "data/tensor.bin", 0, 0);
137
1
  REQUIRE_ARRAY_EQ_WITH_TOLERANCE(float, tensor_a->data.f32, a, 5, 1e-5, "the first 5 element should be equal");
138
1
  float b[] = {4096 * 4 + 1, 4096 * 4 + 2, 4096 * 4 + 3, 4096 * 4 + 4};
139
1
  ccv_nnc_tensor_t* tensor_b = ccv_nnc_tensor_new_from_file(CPU_TENSOR_NHWC(32F, 4), "data/tensor.bin", (4096 * 4 * 4), 0);
140
1
  REQUIRE_ARRAY_EQ_WITH_TOLERANCE(float, tensor_b->data.f32, b, 4, 1e-5, "the first 4 element should be equal");
141
1
  ccv_nnc_tensor_free(tensor_a);
142
1
  ccv_nnc_tensor_free(tensor_b);
143
1
}
144
145
TEST_CASE("tensor persistence")
146
1
{
147
1
  sqlite3* handle;
148
1
  sqlite3_open("tensors.sqlite3", &handle);
149
1
  ccv_nnc_tensor_t* const tensor = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 10, 20, 30), 0);
150
1
  int i;
151
1
  dsfmt_t dsfmt;
152
1
  dsfmt_init_gen_rand(&dsfmt, 1);
153
6.00k
  for (i = 0; i < 10 * 20 * 30; 
i++6.00k
)
154
6.00k
    tensor->data.f32[i] = dsfmt_genrand_open_close(&dsfmt) * 2 - 1;
155
1
  ccv_nnc_tensor_write(tensor, handle, "x", 0);
156
1
  sqlite3_close(handle);
157
1
  handle = 0;
158
1
  sqlite3_open("tensors.sqlite3", &handle);
159
1
  ccv_nnc_tensor_t* tensor1 = 0;
160
1
  ccv_nnc_tensor_read(handle, "x", 0, 0, 0, &tensor1);
161
1
  ccv_nnc_tensor_t* tensor2 = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 10), 0);
162
1
  ccv_nnc_tensor_read(handle, "x", 0, 0, 0, &tensor2);
163
1
  sqlite3_close(handle);
164
1
  REQUIRE_TENSOR_EQ(tensor1, tensor, "the first tensor should equal to the second");
165
1
  REQUIRE_ARRAY_EQ_WITH_TOLERANCE(float, tensor2->data.f32, tensor->data.f32, 10, 1e-5, "the first 10 element should be equal");
166
1
  REQUIRE(ccv_nnc_tensor_nd(tensor2->info.dim) == 1, "should be 1-d tensor");
167
1
  REQUIRE_EQ(tensor2->info.dim[0], 10, "should be 1-d tensor with 10-element");
168
1
  ccv_nnc_tensor_free(tensor1);
169
1
  ccv_nnc_tensor_free(tensor2);
170
1
  ccv_nnc_tensor_free(tensor);
171
1
}
172
173
static int _tensor_split_count(sqlite3* const handle, const char* const name)
174
3
{
175
3
  const char tensor_split_count_qs[] = "SELECT COUNT(*) FROM tensor_splits WHERE name=$name";
176
3
  sqlite3_stmt* tensor_split_count_stmt = 0;
177
3
  if (sqlite3_prepare_v2(handle, tensor_split_count_qs, sizeof(tensor_split_count_qs), &tensor_split_count_stmt, 0) != SQLITE_OK)
178
0
    return -1;
179
3
  sqlite3_bind_text(tensor_split_count_stmt, 1, name, -1, SQLITE_STATIC);
180
3
  int count = -1;
181
3
  if (sqlite3_step(tensor_split_count_stmt) == SQLITE_ROW)
182
3
    count = sqlite3_column_int(tensor_split_count_stmt, 0);
183
3
  sqlite3_finalize(tensor_split_count_stmt);
184
3
  return count;
185
3
}
186
187
static int _tensor_split_table_exists(sqlite3* const handle)
188
1
{
189
1
  const char tensor_split_table_qs[] = "SELECT COUNT(*) FROM sqlite_master WHERE type='table' AND name='tensor_splits'";
190
1
  sqlite3_stmt* tensor_split_table_stmt = 0;
191
1
  if (sqlite3_prepare_v2(handle, tensor_split_table_qs, sizeof(tensor_split_table_qs), &tensor_split_table_stmt, 0) != SQLITE_OK)
192
0
    return -1;
193
1
  int exists = -1;
194
1
  if (sqlite3_step(tensor_split_table_stmt) == SQLITE_ROW)
195
1
    exists = sqlite3_column_int(tensor_split_table_stmt, 0);
196
1
  sqlite3_finalize(tensor_split_table_stmt);
197
1
  return exists;
198
1
}
199
200
static sqlite_int64 _tensor_format(sqlite3* const handle, const char* const name)
201
1
{
202
1
  const char tensor_format_qs[] = "SELECT format FROM tensors WHERE name=$name";
203
1
  sqlite3_stmt* tensor_format_stmt = 0;
204
1
  if (sqlite3_prepare_v2(handle, tensor_format_qs, sizeof(tensor_format_qs), &tensor_format_stmt, 0) != SQLITE_OK)
205
0
    return -1;
206
1
  sqlite3_bind_text(tensor_format_stmt, 1, name, -1, SQLITE_STATIC);
207
1
  sqlite_int64 format = -1;
208
1
  if (sqlite3_step(tensor_format_stmt) == SQLITE_ROW)
209
1
    format = sqlite3_column_int64(tensor_format_stmt, 0);
210
1
  sqlite3_finalize(tensor_format_stmt);
211
1
  return format;
212
1
}
213
214
TEST_CASE("tensor persistence without split blobs does not create split table")
215
1
{
216
1
  sqlite3* handle;
217
1
  sqlite3_open(":memory:", &handle);
218
1
  ccv_nnc_tensor_t* const tensor = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 10), 0);
219
1
  int i;
220
11
  for (i = 0; i < 10; 
i++10
)
221
10
    tensor->data.f32[i] = (float)(i + 1);
222
1
  REQUIRE_EQ(ccv_nnc_tensor_write(tensor, handle, "x", 0), CCV_IO_FINAL, "write should succeed");
223
1
  REQUIRE_EQ(_tensor_split_table_exists(handle), 0, "non-split write should not create tensor_splits");
224
1
  ccv_nnc_tensor_t* tensor1 = 0;
225
1
  REQUIRE_EQ(ccv_nnc_tensor_read(handle, "x", 0, 0, 0, &tensor1), CCV_IO_FINAL, "read should succeed");
226
1
  REQUIRE_TENSOR_EQ(tensor1, tensor, "tensor should round-trip");
227
1
  sqlite3_close(handle);
228
1
  ccv_nnc_tensor_free(tensor1);
229
1
  ccv_nnc_tensor_free(tensor);
230
1
}
231
232
TEST_CASE("tensor persistence with split blobs")
233
1
{
234
1
  sqlite3* handle;
235
1
  sqlite3_open("tensors_split.sqlite3", &handle);
236
1
  sqlite3_limit(handle, SQLITE_LIMIT_LENGTH, 8192);
237
1
  ccv_nnc_tensor_t* const tensor = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 5000), 0);
238
1
  int i;
239
5.00k
  for (i = 0; i < 5000; 
i++5.00k
)
240
5.00k
    tensor->data.f32[i] = (float)(i + 1);
241
1
  REQUIRE_EQ(ccv_nnc_tensor_write(tensor, handle, "x", 0), CCV_IO_FINAL, "write should succeed");
242
1
  const int split_count = _tensor_split_count(handle, "x");
243
1
  REQUIRE(split_count > 0, "large tensor should be split");
244
1
  ccv_nnc_tensor_t* tensor1 = 0;
245
1
  REQUIRE_EQ(ccv_nnc_tensor_read(handle, "x", 0, 0, 0, &tensor1), CCV_IO_FINAL, "read should succeed");
246
1
  REQUIRE_TENSOR_EQ(tensor1, tensor, "split tensor should round-trip");
247
1
  ccv_nnc_tensor_t* const small_tensor = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 10), 0);
248
11
  for (i = 0; i < 10; 
i++10
)
249
10
    small_tensor->data.f32[i] = (float)(i + 1) * 0.5;
250
1
  REQUIRE_EQ(ccv_nnc_tensor_write(small_tensor, handle, "x", 0), CCV_IO_FINAL, "small rewrite should succeed");
251
1
  REQUIRE_EQ(_tensor_format(handle, "x") >> 32, 0, "small rewrite should clear split marker");
252
1
  REQUIRE_EQ(_tensor_split_count(handle, "x"), split_count, "small rewrite should not touch old split rows");
253
1
  ccv_nnc_tensor_t* small_tensor1 = 0;
254
1
  REQUIRE_EQ(ccv_nnc_tensor_read(handle, "x", 0, 0, 0, &small_tensor1), CCV_IO_FINAL, "small read should succeed");
255
1
  REQUIRE_TENSOR_EQ(small_tensor1, small_tensor, "rewritten small tensor should round-trip");
256
1
  sqlite3_close(handle);
257
1
  ccv_nnc_tensor_free(tensor1);
258
1
  ccv_nnc_tensor_free(small_tensor1);
259
1
  ccv_nnc_tensor_free(tensor);
260
1
  ccv_nnc_tensor_free(small_tensor);
261
1
}
262
263
static int _tensor_xor_encode(const void* const data, const size_t data_size, const int datatype, const int* const dimensions, const int dimension_count, void* const context, void* const encoded, size_t* const encoded_size, ccv_nnc_tensor_param_t* const params, unsigned int* const identifier)
264
{
265
  unsigned char* const u8 = (unsigned char*)data;
266
  unsigned char* const u8enc = (unsigned char*)encoded;
267
  int i;
268
  for (i = 0; i < data_size; i++)
269
    u8enc[i] = u8[i] ^ 0x13;
270
  *encoded_size = data_size;
271
  *identifier = 1;
272
  return 1;
273
}
274
275
static int _tensor_xor_decode(const void* const data, const size_t data_size, const int datatype, const int* const dimensions, const int dimension_count, const unsigned int identifier, void* const context, const ccv_nnc_tensor_param_t tensor_params, ccv_nnc_tensor_t** const tensor_out, void* decoded, size_t* const decoded_size)
276
{
277
  if (identifier != 1)
278
    return 0;
279
  if (!tensor_out[0])
280
  {
281
    tensor_out[0] = ccv_nnc_tensor_new(0, tensor_params, 0);
282
    if (!decoded)
283
      decoded = tensor_out[0]->data.u8;
284
  }
285
  unsigned char* const u8 = (unsigned char*)data;
286
  unsigned char* const u8dec = (unsigned char*)decoded;
287
  const size_t expected_size = *decoded_size;
288
  int i;
289
  for (i = 0; i < ccv_min(expected_size, data_size); i++)
290
    u8dec[i] = u8[i] ^ 0x13;
291
  *decoded_size = ccv_min(expected_size, data_size);
292
  return 1;
293
}
294
295
static int _tensor_noop_encode(const void* const data, const size_t data_size, const int datatype, const int* const dimensions, const int dimension_count, void* const context, void* const encoded, size_t* const encoded_size, ccv_nnc_tensor_param_t* const params, unsigned int* const identifier)
296
{
297
  return 0;
298
}
299
300
static int _tensor_noop_decode(const void* const data, const size_t data_size, const int datatype, const int* const dimensions, const int dimension_count, const unsigned int identifier, void* const context, const ccv_nnc_tensor_param_t tensor_params, ccv_nnc_tensor_t** const tensor_out, void* const decoded, size_t* const decoded_size)
301
{
302
  return 0;
303
}
304
305
TEST_CASE("tensor persistence with split blobs and encoder / decoder")
306
1
{
307
1
  sqlite3* handle;
308
1
  sqlite3_open("tensors_split_de.sqlite3", &handle);
309
1
  sqlite3_limit(handle, SQLITE_LIMIT_LENGTH, 8192);
310
1
  ccv_nnc_tensor_t* const tensor = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 5000), 0);
311
1
  int i;
312
5.00k
  for (i = 0; i < 5000; 
i++5.00k
)
313
5.00k
    tensor->data.f32[i] = (float)(i + 1);
314
1
  ccv_nnc_tensor_io_option_t options = {
315
1
    .encode = _tensor_xor_encode,
316
1
    .decode = _tensor_xor_decode
317
1
  };
318
1
  REQUIRE_EQ(ccv_nnc_tensor_write(tensor, handle, "x", &options), CCV_IO_FINAL, "write should succeed");
319
1
  REQUIRE(_tensor_split_count(handle, "x") > 0, "encoded large tensor should be split");
320
1
  ccv_nnc_tensor_t* tensor1 = 0;
321
1
  REQUIRE_EQ(ccv_nnc_tensor_read(handle, "x", &options, 0, 0, &tensor1), CCV_IO_FINAL, "read should succeed");
322
1
  REQUIRE_TENSOR_EQ(tensor1, tensor, "split encoded tensor should round-trip");
323
1
  sqlite3_close(handle);
324
1
  ccv_nnc_tensor_free(tensor1);
325
1
  ccv_nnc_tensor_free(tensor);
326
1
}
327
328
TEST_CASE("tensor persistence with encoder / decoder")
329
1
{
330
1
  sqlite3* handle;
331
1
  sqlite3_open("tensors_de.sqlite3", &handle);
332
1
  ccv_nnc_tensor_t* const tensor = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 10, 20, 30), 0);
333
1
  int i;
334
1
  dsfmt_t dsfmt;
335
1
  dsfmt_init_gen_rand(&dsfmt, 1);
336
6.00k
  for (i = 0; i < 10 * 20 * 30; 
i++6.00k
)
337
6.00k
    tensor->data.f32[i] = dsfmt_genrand_open_close(&dsfmt) * 2 - 1;
338
1
  ccv_nnc_tensor_io_option_t options = {
339
1
    .encode = _tensor_xor_encode,
340
1
    .decode = _tensor_xor_decode
341
1
  };
342
1
  ccv_nnc_tensor_write(tensor, handle, "y", &options);
343
1
  sqlite3_close(handle);
344
1
  handle = 0;
345
1
  sqlite3_open("tensors_de.sqlite3", &handle);
346
1
  ccv_nnc_tensor_t* tensor1 = 0;
347
1
  ccv_nnc_tensor_read(handle, "y", &options, 0, 0, &tensor1);
348
1
  ccv_nnc_tensor_t* tensor2 = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 10), 0);
349
1
  ccv_nnc_tensor_read(handle, "y", &options, 0, 0, &tensor2);
350
1
  sqlite3_close(handle);
351
1
  REQUIRE_TENSOR_EQ(tensor1, tensor, "the first tensor should equal to the second");
352
1
  REQUIRE_ARRAY_EQ_WITH_TOLERANCE(float, tensor2->data.f32, tensor->data.f32, 10, 1e-5, "the first 10 element should be equal");
353
1
  REQUIRE(ccv_nnc_tensor_nd(tensor2->info.dim) == 1, "should be 1-d tensor");
354
1
  REQUIRE_EQ(tensor2->info.dim[0], 10, "should be 1-d tensor with 10-element");
355
1
  ccv_nnc_tensor_free(tensor1);
356
1
  ccv_nnc_tensor_free(tensor2);
357
1
  ccv_nnc_tensor_free(tensor);
358
1
}
359
360
TEST_CASE("tensor persistence with noop encoder / decoder")
361
1
{
362
1
  sqlite3* handle;
363
1
  sqlite3_open("tensors_noop_de.sqlite3", &handle);
364
1
  ccv_nnc_tensor_t* const tensor = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 10, 20, 30), 0);
365
1
  int i;
366
1
  dsfmt_t dsfmt;
367
1
  dsfmt_init_gen_rand(&dsfmt, 1);
368
6.00k
  for (i = 0; i < 10 * 20 * 30; 
i++6.00k
)
369
6.00k
    tensor->data.f32[i] = dsfmt_genrand_open_close(&dsfmt) * 2 - 1;
370
1
  ccv_nnc_tensor_io_option_t options = {
371
1
    .encode = _tensor_noop_encode,
372
1
    .decode = _tensor_noop_decode
373
1
  };
374
1
  ccv_nnc_tensor_write(tensor, handle, "y", &options);
375
1
  sqlite3_close(handle);
376
1
  handle = 0;
377
1
  sqlite3_open("tensors_noop_de.sqlite3", &handle);
378
1
  ccv_nnc_tensor_t* tensor1 = 0;
379
1
  ccv_nnc_tensor_read(handle, "y", &options, 0, 0, &tensor1);
380
1
  ccv_nnc_tensor_t* tensor2 = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 10), 0);
381
1
  ccv_nnc_tensor_read(handle, "y", &options, 0, 0, &tensor2);
382
1
  sqlite3_close(handle);
383
1
  REQUIRE_TENSOR_EQ(tensor1, tensor, "the first tensor should equal to the second");
384
1
  REQUIRE_ARRAY_EQ_WITH_TOLERANCE(float, tensor2->data.f32, tensor->data.f32, 10, 1e-5, "the first 10 element should be equal");
385
1
  REQUIRE(ccv_nnc_tensor_nd(tensor2->info.dim) == 1, "should be 1-d tensor");
386
1
  REQUIRE_EQ(tensor2->info.dim[0], 10, "should be 1-d tensor with 10-element");
387
1
  ccv_nnc_tensor_free(tensor1);
388
1
  ccv_nnc_tensor_free(tensor2);
389
1
  ccv_nnc_tensor_free(tensor);
390
1
}
391
392
TEST_CASE("tensor persistence and read metadata only")
393
1
{
394
1
  sqlite3* handle;
395
1
  sqlite3_open("tensors_md.sqlite3", &handle);
396
1
  ccv_nnc_tensor_t* const tensorf32 = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 10, 20, 30), 0);
397
1
  int i;
398
1
  dsfmt_t dsfmt;
399
1
  dsfmt_init_gen_rand(&dsfmt, 1);
400
6.00k
  for (i = 0; i < 10 * 20 * 30; 
i++6.00k
)
401
6.00k
    tensorf32->data.f32[i] = dsfmt_genrand_open_close(&dsfmt) * 2 - 1;
402
1
  ccv_nnc_tensor_t* const tensorf16 = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(16F, 10, 20, 30), 0);
403
1
  ccv_float_to_half_precision(tensorf32->data.f32, (uint16_t*)tensorf16->data.f16, 10 * 20 * 30);
404
6.00k
  for (i = 0; i < 10 * 20 * 30; 
i++6.00k
)
405
6.00k
    tensorf32->data.f32[i] = dsfmt_genrand_open_close(&dsfmt) * 2 - 1;
406
1
  ccv_nnc_tensor_write(tensorf16, handle, "x", 0);
407
1
  ccv_nnc_tensor_write(tensorf32, handle, "y", 0);
408
1
  sqlite3_close(handle);
409
1
  handle = 0;
410
1
  sqlite3_open("tensors_md.sqlite3", &handle);
411
1
  ccv_nnc_tensor_t* tensor1 = 0;
412
1
  ccv_nnc_tensor_read(handle, "x", 0, CCV_NNC_TENSOR_READ_METADATA_ONLY, 0, &tensor1);
413
1
  ccv_nnc_tensor_t* tensor2 = 0;
414
1
  ccv_nnc_tensor_read(handle, "y", 0, CCV_NNC_TENSOR_READ_METADATA_ONLY, 0, &tensor2);
415
1
  sqlite3_close(handle);
416
1
  REQUIRE(tensor1->data.u8 == 0, "should have no data");
417
1
  REQUIRE(tensor2->data.u8 == 0, "should have no data");
418
1
  REQUIRE_EQ(tensor1->info.dim[0], 10, "should be 3-d tensor with 10, 20, 30");
419
1
  REQUIRE_EQ(tensor2->info.dim[0], 10, "should be 3-d tensor with 10, 20, 30");
420
1
  REQUIRE_EQ(tensor1->info.dim[1], 20, "should be 3-d tensor with 10, 20, 30");
421
1
  REQUIRE_EQ(tensor2->info.dim[1], 20, "should be 3-d tensor with 10, 20, 30");
422
1
  REQUIRE_EQ(tensor1->info.dim[2], 30, "should be 3-d tensor with 10, 20, 30");
423
1
  REQUIRE_EQ(tensor2->info.dim[2], 30, "should be 3-d tensor with 10, 20, 30");
424
1
  REQUIRE_EQ(tensor1->info.dim[3], 0, "should be 3-d tensor with 10, 20, 30");
425
1
  REQUIRE_EQ(tensor2->info.dim[3], 0, "should be 3-d tensor with 10, 20, 30");
426
1
  ccv_nnc_tensor_free(tensor1);
427
1
  ccv_nnc_tensor_free(tensor2);
428
1
  ccv_nnc_tensor_free(tensorf16);
429
1
  ccv_nnc_tensor_free(tensorf32);
430
1
}
431
432
TEST_CASE("tensor persistence with type coercion")
433
1
{
434
1
  sqlite3* handle;
435
1
  sqlite3_open("tensors_tc.sqlite3", &handle);
436
1
  ccv_nnc_tensor_t* const tensorf32 = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 10, 20, 30), 0);
437
1
  int i;
438
1
  dsfmt_t dsfmt;
439
1
  dsfmt_init_gen_rand(&dsfmt, 1);
440
6.00k
  for (i = 0; i < 10 * 20 * 30; 
i++6.00k
)
441
6.00k
    tensorf32->data.f32[i] = dsfmt_genrand_open_close(&dsfmt) * 2 - 1;
442
1
  ccv_nnc_tensor_t* const tensorf16 = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(16F, 10, 20, 30), 0);
443
1
  ccv_float_to_half_precision(tensorf32->data.f32, (uint16_t*)tensorf16->data.f16, 10 * 20 * 30);
444
6.00k
  for (i = 0; i < 10 * 20 * 30; 
i++6.00k
)
445
6.00k
    tensorf32->data.f32[i] = dsfmt_genrand_open_close(&dsfmt) * 2 - 1;
446
1
  ccv_nnc_tensor_write(tensorf16, handle, "x", 0);
447
1
  ccv_nnc_tensor_write(tensorf32, handle, "y", 0);
448
1
  sqlite3_close(handle);
449
1
  handle = 0;
450
1
  sqlite3_open("tensors_tc.sqlite3", &handle);
451
1
  ccv_nnc_tensor_t* tensor1 = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 10), 0);
452
1
  ccv_nnc_tensor_read(handle, "x", 0, 0, 0, &tensor1);
453
1
  ccv_nnc_tensor_t* tensor2 = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(16F, 10), 0);
454
1
  ccv_nnc_tensor_read(handle, "y", 0, 0, 0, &tensor2);
455
1
  sqlite3_close(handle);
456
1
  float* tensor1_ref = (float*)ccmalloc(sizeof(float) * 10);
457
1
  ccv_half_precision_to_float((uint16_t*)tensorf16->data.f16, tensor1_ref, 10);
458
1
  float* tensor2_ret = (float*)ccmalloc(sizeof(float) * 10);
459
1
  ccv_half_precision_to_float((uint16_t*)tensor2->data.f16, tensor2_ret, 10);
460
1
  REQUIRE_ARRAY_EQ_WITH_TOLERANCE(float, tensor1->data.f32, tensor1_ref, 10, 1e-3, "the first 10 element should be equal");
461
1
  REQUIRE_ARRAY_EQ_WITH_TOLERANCE(float, tensor2_ret, tensorf32->data.f32, 10, 1e-3, "the first 10 element should be equal");
462
1
  REQUIRE(ccv_nnc_tensor_nd(tensor1->info.dim) == 1, "should be 1-d tensor");
463
1
  REQUIRE(ccv_nnc_tensor_nd(tensor2->info.dim) == 1, "should be 1-d tensor");
464
1
  REQUIRE_EQ(tensor1->info.dim[0], 10, "should be 1-d tensor with 10-element");
465
1
  REQUIRE_EQ(tensor2->info.dim[0], 10, "should be 1-d tensor with 10-element");
466
1
  ccv_nnc_tensor_free(tensor1);
467
1
  ccv_nnc_tensor_free(tensor2);
468
1
  ccv_nnc_tensor_free(tensorf16);
469
1
  ccv_nnc_tensor_free(tensorf32);
470
1
  ccfree(tensor1_ref);
471
1
  ccfree(tensor2_ret);
472
1
}
473
474
TEST_CASE("tensor persistence with type coercion and encoder / decoder")
475
1
{
476
1
  sqlite3* handle;
477
1
  sqlite3_open("tensors_tc_de.sqlite3", &handle);
478
1
  ccv_nnc_tensor_t* const tensorf32 = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 10, 20, 30), 0);
479
1
  int i;
480
1
  dsfmt_t dsfmt;
481
1
  dsfmt_init_gen_rand(&dsfmt, 1);
482
6.00k
  for (i = 0; i < 10 * 20 * 30; 
i++6.00k
)
483
6.00k
    tensorf32->data.f32[i] = dsfmt_genrand_open_close(&dsfmt) * 2 - 1;
484
1
  ccv_nnc_tensor_t* const tensorf16 = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(16F, 10, 20, 30), 0);
485
1
  ccv_float_to_half_precision(tensorf32->data.f32, (uint16_t*)tensorf16->data.f16, 10 * 20 * 30);
486
6.00k
  for (i = 0; i < 10 * 20 * 30; 
i++6.00k
)
487
6.00k
    tensorf32->data.f32[i] = dsfmt_genrand_open_close(&dsfmt) * 2 - 1;
488
1
  ccv_nnc_tensor_io_option_t options = {
489
1
    .encode = _tensor_xor_encode,
490
1
    .decode = _tensor_xor_decode
491
1
  };
492
1
  ccv_nnc_tensor_write(tensorf16, handle, "x", &options);
493
1
  ccv_nnc_tensor_write(tensorf32, handle, "y", &options);
494
1
  sqlite3_close(handle);
495
1
  handle = 0;
496
1
  sqlite3_open("tensors_tc_de.sqlite3", &handle);
497
1
  ccv_nnc_tensor_t* tensor1 = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 10), 0);
498
1
  ccv_nnc_tensor_read(handle, "x", &options, 0, 0, &tensor1);
499
1
  ccv_nnc_tensor_t* tensor2 = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(16F, 10), 0);
500
1
  ccv_nnc_tensor_read(handle, "y", &options, 0, 0, &tensor2);
501
1
  sqlite3_close(handle);
502
1
  float* tensor1_ref = (float*)ccmalloc(sizeof(float) * 10);
503
1
  ccv_half_precision_to_float((uint16_t*)tensorf16->data.f16, tensor1_ref, 10);
504
1
  float* tensor2_ret = (float*)ccmalloc(sizeof(float) * 10);
505
1
  ccv_half_precision_to_float((uint16_t*)tensor2->data.f16, tensor2_ret, 10);
506
1
  REQUIRE_ARRAY_EQ_WITH_TOLERANCE(float, tensor1->data.f32, tensor1_ref, 10, 1e-3, "the first 10 element should be equal");
507
1
  REQUIRE_ARRAY_EQ_WITH_TOLERANCE(float, tensor2_ret, tensorf32->data.f32, 10, 1e-3, "the first 10 element should be equal");
508
1
  REQUIRE(ccv_nnc_tensor_nd(tensor1->info.dim) == 1, "should be 1-d tensor");
509
1
  REQUIRE(ccv_nnc_tensor_nd(tensor2->info.dim) == 1, "should be 1-d tensor");
510
1
  REQUIRE_EQ(tensor1->info.dim[0], 10, "should be 1-d tensor with 10-element");
511
1
  REQUIRE_EQ(tensor2->info.dim[0], 10, "should be 1-d tensor with 10-element");
512
1
  ccv_nnc_tensor_free(tensor1);
513
1
  ccv_nnc_tensor_free(tensor2);
514
1
  ccv_nnc_tensor_free(tensorf16);
515
1
  ccv_nnc_tensor_free(tensorf32);
516
1
  ccfree(tensor1_ref);
517
1
  ccfree(tensor2_ret);
518
1
}
519
520
TEST_CASE("tensor persistence with type coercion and noop encoder / decoder")
521
1
{
522
1
  sqlite3* handle;
523
1
  sqlite3_open("tensors_tc_noop_de.sqlite3", &handle);
524
1
  ccv_nnc_tensor_t* const tensorf32 = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 10, 20, 30), 0);
525
1
  int i;
526
1
  dsfmt_t dsfmt;
527
1
  dsfmt_init_gen_rand(&dsfmt, 1);
528
6.00k
  for (i = 0; i < 10 * 20 * 30; 
i++6.00k
)
529
6.00k
    tensorf32->data.f32[i] = dsfmt_genrand_open_close(&dsfmt) * 2 - 1;
530
1
  ccv_nnc_tensor_t* const tensorf16 = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(16F, 10, 20, 30), 0);
531
1
  ccv_float_to_half_precision(tensorf32->data.f32, (uint16_t*)tensorf16->data.f16, 10 * 20 * 30);
532
6.00k
  for (i = 0; i < 10 * 20 * 30; 
i++6.00k
)
533
6.00k
    tensorf32->data.f32[i] = dsfmt_genrand_open_close(&dsfmt) * 2 - 1;
534
1
  ccv_nnc_tensor_io_option_t options = {
535
1
    .encode = _tensor_noop_encode,
536
1
    .decode = _tensor_noop_decode
537
1
  };
538
1
  ccv_nnc_tensor_write(tensorf16, handle, "x", &options);
539
1
  ccv_nnc_tensor_write(tensorf32, handle, "y", &options);
540
1
  sqlite3_close(handle);
541
1
  handle = 0;
542
1
  sqlite3_open("tensors_tc_noop_de.sqlite3", &handle);
543
1
  ccv_nnc_tensor_t* tensor1 = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 10), 0);
544
1
  ccv_nnc_tensor_read(handle, "x", &options, 0, 0, &tensor1);
545
1
  ccv_nnc_tensor_t* tensor2 = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(16F, 10), 0);
546
1
  ccv_nnc_tensor_read(handle, "y", &options, 0, 0, &tensor2);
547
1
  sqlite3_close(handle);
548
1
  float* tensor1_ref = (float*)ccmalloc(sizeof(float) * 10);
549
1
  ccv_half_precision_to_float((uint16_t*)tensorf16->data.f16, tensor1_ref, 10);
550
1
  float* tensor2_ret = (float*)ccmalloc(sizeof(float) * 10);
551
1
  ccv_half_precision_to_float((uint16_t*)tensor2->data.f16, tensor2_ret, 10);
552
1
  REQUIRE_ARRAY_EQ_WITH_TOLERANCE(float, tensor1->data.f32, tensor1_ref, 10, 1e-3, "the first 10 element should be equal");
553
1
  REQUIRE_ARRAY_EQ_WITH_TOLERANCE(float, tensor2_ret, tensorf32->data.f32, 10, 1e-3, "the first 10 element should be equal");
554
1
  REQUIRE(ccv_nnc_tensor_nd(tensor1->info.dim) == 1, "should be 1-d tensor");
555
1
  REQUIRE(ccv_nnc_tensor_nd(tensor2->info.dim) == 1, "should be 1-d tensor");
556
1
  REQUIRE_EQ(tensor1->info.dim[0], 10, "should be 1-d tensor with 10-element");
557
1
  REQUIRE_EQ(tensor2->info.dim[0], 10, "should be 1-d tensor with 10-element");
558
1
  ccv_nnc_tensor_free(tensor1);
559
1
  ccv_nnc_tensor_free(tensor2);
560
1
  ccv_nnc_tensor_free(tensorf16);
561
1
  ccv_nnc_tensor_free(tensorf32);
562
1
  ccfree(tensor1_ref);
563
1
  ccfree(tensor2_ret);
564
1
}
565
566
TEST_CASE("resize tensor")
567
1
{
568
1
  ccv_nnc_tensor_t* tensor = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 12, 12, 3), 0);
569
1
  int i;
570
433
  for (i = 0; i < 12 * 12 * 3; 
i++432
)
571
432
    tensor->data.f32[i] = i;
572
1
  tensor = ccv_nnc_tensor_resize(tensor, CPU_TENSOR_NHWC(32F, 23, 23, 3));
573
1.15k
  for (i = 12 * 12 * 3; i < 23 * 23 * 3; 
i++1.15k
)
574
1.15k
    tensor->data.f32[i] = i;
575
1
  ccv_nnc_tensor_t* b = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 23, 23, 3), 0);
576
1.58k
  for (i = 0; i < 23 * 23 * 3; 
i++1.58k
)
577
1.58k
    b->data.f32[i] = i;
578
1
  REQUIRE_TENSOR_EQ(tensor, b, "should retain the content when resize a tensor");
579
1
  ccv_nnc_tensor_free(tensor);
580
1
  ccv_nnc_tensor_free(b);
581
1
}
582
583
TEST_CASE("format 5-d tensor into string")
584
1
{
585
1
  ccv_nnc_tensor_t* tensor = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32S, 2, 5, 2, 9, 9), 0);
586
1
  int i;
587
1.62k
  for (i = 0; i < 81 * 2 * 5 * 2; 
i++1.62k
)
588
1.62k
    tensor->data.i32[i] = i;
589
1
  char* str = ccv_nnc_tensor_format_new(tensor);
590
1
  const char t[] = "[\n"
591
1
"  [[[[         0,          1,          2,  ...,          6,          7,          8],\n"
592
1
"     [         9,         10,         11,  ...,         15,         16,         17],\n"
593
1
"     [        18,         19,         20,  ...,         24,         25,         26],\n"
594
1
"     ...,\n"
595
1
"     [        54,         55,         56,  ...,         60,         61,         62],\n"
596
1
"     [        63,         64,         65,  ...,         69,         70,         71],\n"
597
1
"     [        72,         73,         74,  ...,         78,         79,         80]],\n"
598
1
"    [[        81,         82,         83,  ...,         87,         88,         89],\n"
599
1
"     [        90,         91,         92,  ...,         96,         97,         98],\n"
600
1
"     [        99,        100,        101,  ...,        105,        106,        107],\n"
601
1
"     ...,\n"
602
1
"     [       135,        136,        137,  ...,        141,        142,        143],\n"
603
1
"     [       144,        145,        146,  ...,        150,        151,        152],\n"
604
1
"     [       153,        154,        155,  ...,        159,        160,        161]]],\n"
605
1
"   [[[       162,        163,        164,  ...,        168,        169,        170],\n"
606
1
"     [       171,        172,        173,  ...,        177,        178,        179],\n"
607
1
"     [       180,        181,        182,  ...,        186,        187,        188],\n"
608
1
"     ...,\n"
609
1
"     [       216,        217,        218,  ...,        222,        223,        224],\n"
610
1
"     [       225,        226,        227,  ...,        231,        232,        233],\n"
611
1
"     [       234,        235,        236,  ...,        240,        241,        242]],\n"
612
1
"    [[       243,        244,        245,  ...,        249,        250,        251],\n"
613
1
"     [       252,        253,        254,  ...,        258,        259,        260],\n"
614
1
"     [       261,        262,        263,  ...,        267,        268,        269],\n"
615
1
"     ...,\n"
616
1
"     [       297,        298,        299,  ...,        303,        304,        305],\n"
617
1
"     [       306,        307,        308,  ...,        312,        313,        314],\n"
618
1
"     [       315,        316,        317,  ...,        321,        322,        323]]],\n"
619
1
"   ...,\n"
620
1
"   [[[       486,        487,        488,  ...,        492,        493,        494],\n"
621
1
"     [       495,        496,        497,  ...,        501,        502,        503],\n"
622
1
"     [       504,        505,        506,  ...,        510,        511,        512],\n"
623
1
"     ...,\n"
624
1
"     [       540,        541,        542,  ...,        546,        547,        548],\n"
625
1
"     [       549,        550,        551,  ...,        555,        556,        557],\n"
626
1
"     [       558,        559,        560,  ...,        564,        565,        566]],\n"
627
1
"    [[       567,        568,        569,  ...,        573,        574,        575],\n"
628
1
"     [       576,        577,        578,  ...,        582,        583,        584],\n"
629
1
"     [       585,        586,        587,  ...,        591,        592,        593],\n"
630
1
"     ...,\n"
631
1
"     [       621,        622,        623,  ...,        627,        628,        629],\n"
632
1
"     [       630,        631,        632,  ...,        636,        637,        638],\n"
633
1
"     [       639,        640,        641,  ...,        645,        646,        647]]],\n"
634
1
"   [[[       648,        649,        650,  ...,        654,        655,        656],\n"
635
1
"     [       657,        658,        659,  ...,        663,        664,        665],\n"
636
1
"     [       666,        667,        668,  ...,        672,        673,        674],\n"
637
1
"     ...,\n"
638
1
"     [       702,        703,        704,  ...,        708,        709,        710],\n"
639
1
"     [       711,        712,        713,  ...,        717,        718,        719],\n"
640
1
"     [       720,        721,        722,  ...,        726,        727,        728]],\n"
641
1
"    [[       729,        730,        731,  ...,        735,        736,        737],\n"
642
1
"     [       738,        739,        740,  ...,        744,        745,        746],\n"
643
1
"     [       747,        748,        749,  ...,        753,        754,        755],\n"
644
1
"     ...,\n"
645
1
"     [       783,        784,        785,  ...,        789,        790,        791],\n"
646
1
"     [       792,        793,        794,  ...,        798,        799,        800],\n"
647
1
"     [       801,        802,        803,  ...,        807,        808,        809]]]],\n"
648
1
"  [[[[       810,        811,        812,  ...,        816,        817,        818],\n"
649
1
"     [       819,        820,        821,  ...,        825,        826,        827],\n"
650
1
"     [       828,        829,        830,  ...,        834,        835,        836],\n"
651
1
"     ...,\n"
652
1
"     [       864,        865,        866,  ...,        870,        871,        872],\n"
653
1
"     [       873,        874,        875,  ...,        879,        880,        881],\n"
654
1
"     [       882,        883,        884,  ...,        888,        889,        890]],\n"
655
1
"    [[       891,        892,        893,  ...,        897,        898,        899],\n"
656
1
"     [       900,        901,        902,  ...,        906,        907,        908],\n"
657
1
"     [       909,        910,        911,  ...,        915,        916,        917],\n"
658
1
"     ...,\n"
659
1
"     [       945,        946,        947,  ...,        951,        952,        953],\n"
660
1
"     [       954,        955,        956,  ...,        960,        961,        962],\n"
661
1
"     [       963,        964,        965,  ...,        969,        970,        971]]],\n"
662
1
"   [[[       972,        973,        974,  ...,        978,        979,        980],\n"
663
1
"     [       981,        982,        983,  ...,        987,        988,        989],\n"
664
1
"     [       990,        991,        992,  ...,        996,        997,        998],\n"
665
1
"     ...,\n"
666
1
"     [      1026,       1027,       1028,  ...,       1032,       1033,       1034],\n"
667
1
"     [      1035,       1036,       1037,  ...,       1041,       1042,       1043],\n"
668
1
"     [      1044,       1045,       1046,  ...,       1050,       1051,       1052]],\n"
669
1
"    [[      1053,       1054,       1055,  ...,       1059,       1060,       1061],\n"
670
1
"     [      1062,       1063,       1064,  ...,       1068,       1069,       1070],\n"
671
1
"     [      1071,       1072,       1073,  ...,       1077,       1078,       1079],\n"
672
1
"     ...,\n"
673
1
"     [      1107,       1108,       1109,  ...,       1113,       1114,       1115],\n"
674
1
"     [      1116,       1117,       1118,  ...,       1122,       1123,       1124],\n"
675
1
"     [      1125,       1126,       1127,  ...,       1131,       1132,       1133]]],\n"
676
1
"   ...,\n"
677
1
"   [[[      1296,       1297,       1298,  ...,       1302,       1303,       1304],\n"
678
1
"     [      1305,       1306,       1307,  ...,       1311,       1312,       1313],\n"
679
1
"     [      1314,       1315,       1316,  ...,       1320,       1321,       1322],\n"
680
1
"     ...,\n"
681
1
"     [      1350,       1351,       1352,  ...,       1356,       1357,       1358],\n"
682
1
"     [      1359,       1360,       1361,  ...,       1365,       1366,       1367],\n"
683
1
"     [      1368,       1369,       1370,  ...,       1374,       1375,       1376]],\n"
684
1
"    [[      1377,       1378,       1379,  ...,       1383,       1384,       1385],\n"
685
1
"     [      1386,       1387,       1388,  ...,       1392,       1393,       1394],\n"
686
1
"     [      1395,       1396,       1397,  ...,       1401,       1402,       1403],\n"
687
1
"     ...,\n"
688
1
"     [      1431,       1432,       1433,  ...,       1437,       1438,       1439],\n"
689
1
"     [      1440,       1441,       1442,  ...,       1446,       1447,       1448],\n"
690
1
"     [      1449,       1450,       1451,  ...,       1455,       1456,       1457]]],\n"
691
1
"   [[[      1458,       1459,       1460,  ...,       1464,       1465,       1466],\n"
692
1
"     [      1467,       1468,       1469,  ...,       1473,       1474,       1475],\n"
693
1
"     [      1476,       1477,       1478,  ...,       1482,       1483,       1484],\n"
694
1
"     ...,\n"
695
1
"     [      1512,       1513,       1514,  ...,       1518,       1519,       1520],\n"
696
1
"     [      1521,       1522,       1523,  ...,       1527,       1528,       1529],\n"
697
1
"     [      1530,       1531,       1532,  ...,       1536,       1537,       1538]],\n"
698
1
"    [[      1539,       1540,       1541,  ...,       1545,       1546,       1547],\n"
699
1
"     [      1548,       1549,       1550,  ...,       1554,       1555,       1556],\n"
700
1
"     [      1557,       1558,       1559,  ...,       1563,       1564,       1565],\n"
701
1
"     ...,\n"
702
1
"     [      1593,       1594,       1595,  ...,       1599,       1600,       1601],\n"
703
1
"     [      1602,       1603,       1604,  ...,       1608,       1609,       1610],\n"
704
1
"     [      1611,       1612,       1613,  ...,       1617,       1618,       1619]]]]\n"
705
1
"]";
706
1
  REQUIRE(memcmp(str, t, strlen(t) + 1) == 0, "output should be equal");
707
1
  ccfree(str);
708
1
  ccv_nnc_tensor_free(tensor);
709
1
}
710
711
TEST_CASE("format small 2-d tensor into string")
712
1
{
713
1
  ccv_nnc_tensor_t* tensor = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32S, 4, 4), 0);
714
1
  int i;
715
17
  for (i = 0; i < 4 * 4; 
i++16
)
716
16
    tensor->data.i32[i] = i;
717
1
  char* str = ccv_nnc_tensor_format_new(tensor);
718
1
  const char t[] = "[\n"
719
1
"  [         0,          1,          2,          3],\n"
720
1
"  [         4,          5,          6,          7],\n"
721
1
"  [         8,          9,         10,         11],\n"
722
1
"  [        12,         13,         14,         15]\n"
723
1
"]";
724
1
  REQUIRE(memcmp(str, t, strlen(t) + 1) == 0, "output should be equal");
725
1
  ccfree(str);
726
1
  ccv_nnc_tensor_free(tensor);
727
1
}
728
729
TEST_CASE("format small 1-d tensor into string")
730
1
{
731
1
  ccv_nnc_tensor_t* tensor = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32S, 12), 0);
732
1
  int i;
733
13
  for (i = 0; i < 12; 
i++12
)
734
12
    tensor->data.i32[i] = i;
735
1
  char* str = ccv_nnc_tensor_format_new(tensor);
736
1
  const char t[] = "[\n"
737
1
"           0,          1,          2,          3,          4,          5,          6,          7,\n"
738
1
"           8,          9,         10,         11\n"
739
1
"]";
740
1
  REQUIRE(memcmp(str, t, strlen(t) + 1) == 0, "output should be equal");
741
1
  ccfree(str);
742
1
  ccv_nnc_tensor_free(tensor);
743
1
}
744
745
TEST_CASE("format large 1-d tensor into string")
746
1
{
747
1
  ccv_nnc_tensor_t* tensor = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32S, 68), 0);
748
1
  int i;
749
69
  for (i = 0; i < 68; 
i++68
)
750
68
    tensor->data.i32[i] = i;
751
1
  char* str = ccv_nnc_tensor_format_new(tensor);
752
1
  const char t[] = "[\n"
753
1
"           0,          1,          2,          3,          4,          5,          6,          7,\n"
754
1
"           8,          9,         10,         11,         12,         13,         14,         15,\n"
755
1
"          16,         17,         18,         19,         20,         21,         22,         23,\n"
756
1
"  ...,\n"
757
1
"          48,         49,         50,         51,         52,         53,         54,         55,\n"
758
1
"          56,         57,         58,         59,         60,         61,         62,         63,\n"
759
1
"          64,         65,         66,         67\n"
760
1
"]";
761
1
  REQUIRE(memcmp(str, t, strlen(t) + 1) == 0, "output should be equal");
762
1
  ccfree(str);
763
1
  ccv_nnc_tensor_free(tensor);
764
1
}
765
766
TEST_CASE("allocate palettize tensor with quantization to 5-bit")
767
1
{
768
1
  ccv_nnc_tensor_t* const tensor = ccv_nnc_tensor_new(0, ccv_nnc_tensor_palettize(CPU_TENSOR_NHWC(32F, 10, 20, 30), 5, 512), 0);
769
1
  REQUIRE_EQ(5312, ccv_nnc_tensor_data_size(tensor->info), "should be this size");
770
1
  ccv_nnc_tensor_free(tensor);
771
1
}
772
773
#include "case_main.h"