## 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"