## 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/reduce.tests.c

    Line
    Count
    Source
    1
    #include "case.h"
    2
    #include "ccv_case.h"
    3
    #include "ccv_nnc_case.h"
    4
    #include <ccv.h>
    5
    #include <nnc/ccv_nnc.h>
    6
    #include <nnc/ccv_nnc_easy.h>
    7
    #include "3rdparty/dsfmt/dSFMT.h"
    8
    9
    TEST_SETUP()
    10
    {
    11
      ccv_nnc_init();
    12
    }
    13
    14
    TEST_CASE("reduce sum for [[1, 2, 3], [4, 5, 6]] on axis 1")
    15
    {
    16
      ccv_nnc_tensor_t* const a = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 3), 0);
    17
      ccv_nnc_tensor_t* const b = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 1), 0);
    18
      a->data.f32[0] = 1;
    19
      a->data.f32[1] = 2;
    20
      a->data.f32[2] = 3;
    21
      a->data.f32[3] = 4;
    22
      a->data.f32[4] = 5;
    23
      a->data.f32[5] = 6;
    24
      ccv_nnc_cmd_exec(CMD_REDUCE_SUM_FORWARD(1), ccv_nnc_no_hint, 0, TENSOR_LIST(a), TENSOR_LIST(b), 0);
    25
      float btp[] = {
    26
        6,
    27
        15
    28
      };
    29
      ccv_nnc_tensor_t bt = ccv_nnc_tensor(btp, CPU_TENSOR_NHWC(32F, 2, 1), 0);
    30
      REQUIRE_TENSOR_EQ(b, &bt, "result should be equal");
    31
      ccv_nnc_tensor_free(a);
    32
      ccv_nnc_tensor_free(b);
    33
    }
    34
    35
    TEST_CASE("reduce sum for [[1, 2, 3], [4, 5, 6]] on axis 0")
    36
    1
    {
    37
    1
      ccv_nnc_tensor_t* const a = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 3), 0);
    38
    1
      ccv_nnc_tensor_t* const b = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 3), 0);
    39
    1
      a->data.f32[0] = 1;
    40
    1
      a->data.f32[1] = 2;
    41
    1
      a->data.f32[2] = 3;
    42
    1
      a->data.f32[3] = 4;
    43
    1
      a->data.f32[4] = 5;
    44
    1
      a->data.f32[5] = 6;
    45
    1
      ccv_nnc_cmd_exec(CMD_REDUCE_SUM_FORWARD(0), ccv_nnc_no_hint, 0, TENSOR_LIST(a), TENSOR_LIST(b), 0);
    46
    1
      float btp[] = {
    47
    1
        5, 7, 9
    48
    1
      };
    49
    1
      ccv_nnc_tensor_t bt = ccv_nnc_tensor(btp, CPU_TENSOR_NHWC(32F, 3), 0);
    50
    1
      REQUIRE_TENSOR_EQ(b, &bt, "result should be equal");
    51
    1
      ccv_nnc_tensor_free(a);
    52
    1
      ccv_nnc_tensor_free(b);
    53
    1
    }
    54
    55
    TEST_CASE("reduce mean for [[1, 2, 3], [4, 5, 6]] on axis 1")
    56
    1
    {
    57
    1
      ccv_nnc_tensor_t* const a = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 3), 0);
    58
    1
      ccv_nnc_tensor_t* const b = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 1), 0);
    59
    1
      a->data.f32[0] = 1;
    60
    1
      a->data.f32[1] = 2;
    61
    1
      a->data.f32[2] = 3;
    62
    1
      a->data.f32[3] = 4;
    63
    1
      a->data.f32[4] = 5;
    64
    1
      a->data.f32[5] = 6;
    65
    1
      ccv_nnc_cmd_exec(CMD_REDUCE_MEAN_FORWARD(1), ccv_nnc_no_hint, 0, TENSOR_LIST(a), TENSOR_LIST(b), 0);
    66
    1
      float btp[] = {
    67
    1
        2,
    68
    1
        5
    69
    1
      };
    70
    1
      ccv_nnc_tensor_t bt = ccv_nnc_tensor(btp, CPU_TENSOR_NHWC(32F, 2, 1), 0);
    71
    1
      REQUIRE_TENSOR_EQ(b, &bt, "result should be equal");
    72
    1
      ccv_nnc_tensor_free(a);
    73
    1
      ccv_nnc_tensor_free(b);
    74
    1
    }
    75
    76
    TEST_CASE("reduce mean for [[1, 2, 3], [4, 5, 6]] on axis 0")
    77
    1
    {
    78
    1
      ccv_nnc_tensor_t* const a = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 3), 0);
    79
    1
      ccv_nnc_tensor_t* const b = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 3), 0);
    80
    1
      a->data.f32[0] = 1;
    81
    1
      a->data.f32[1] = 2;
    82
    1
      a->data.f32[2] = 3;
    83
    1
      a->data.f32[3] = 4;
    84
    1
      a->data.f32[4] = 5;
    85
    1
      a->data.f32[5] = 6;
    86
    1
      ccv_nnc_cmd_exec(CMD_REDUCE_MEAN_FORWARD(0), ccv_nnc_no_hint, 0, TENSOR_LIST(a), TENSOR_LIST(b), 0);
    87
    1
      float btp[] = {
    88
    1
        2.5, 3.5, 4.5
    89
    1
      };
    90
    1
      ccv_nnc_tensor_t bt = ccv_nnc_tensor(btp, CPU_TENSOR_NHWC(32F, 3), 0);
    91
    1
      REQUIRE_TENSOR_EQ(b, &bt, "result should be equal");
    92
    1
      ccv_nnc_tensor_free(a);
    93
    1
      ccv_nnc_tensor_free(b);
    94
    1
    }
    95
    96
    TEST_CASE("use reduce for softmax")
    97
    1
    {
    98
    1
      ccv_nnc_symbolic_graph_t* const symbolic_graph = ccv_nnc_symbolic_graph_new();
    99
    1
      ccv_nnc_tensor_symbol_t x = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 100), "x");
    100
    1
      ccv_nnc_tensor_symbol_t max = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "max");
    101
    1
      ccv_nnc_graph_exec_symbol_new(symbolic_graph, CMD_REDUCE_MAX_FORWARD(0), TENSOR_SYMBOL_LIST(x), TENSOR_SYMBOL_LIST(max), "max");
    102
    1
      ccv_nnc_tensor_symbol_t y = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 100), "y");
    103
    1
      ccv_nnc_graph_exec_symbol_new(symbolic_graph, CMD_ADD_FORWARD(1, -1), TENSOR_SYMBOL_LIST(x, max), TENSOR_SYMBOL_LIST(y), "neg");
    104
    1
      ccv_nnc_tensor_symbol_t z = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 100), "z");
    105
    1
      ccv_nnc_graph_exec_symbol_new(symbolic_graph, CMD_EWEXP_FORWARD(), TENSOR_SYMBOL_LIST(y), TENSOR_SYMBOL_LIST(z), "exp");
    106
    1
      ccv_nnc_tensor_symbol_t sum = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "sum");
    107
    1
      ccv_nnc_graph_exec_symbol_new(symbolic_graph, CMD_REDUCE_SUM_FORWARD(0), TENSOR_SYMBOL_LIST(z), TENSOR_SYMBOL_LIST(sum), "sum");
    108
    1
      ccv_nnc_tensor_symbol_t inv_sum = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "1 / sum");
    109
    1
      ccv_nnc_graph_exec_symbol_new(symbolic_graph, CMD_EWDIV_FORWARD(), TENSOR_SYMBOL_LIST(NO_TENSOR_SYMBOL, sum), TENSOR_SYMBOL_LIST(inv_sum), "inv sum");
    110
    1
      ccv_nnc_tensor_symbol_t a = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 100), "a");
    111
    1
      ccv_nnc_graph_exec_symbol_new(symbolic_graph, CMD_MUL_FORWARD(1), TENSOR_SYMBOL_LIST(z, inv_sum), TENSOR_SYMBOL_LIST(a), "softmax");
    112
    1
      ccv_nnc_graph_exec_symbol_autogen(symbolic_graph, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS);
    113
    1
      ccv_nnc_symbolic_graph_backward(symbolic_graph, TENSOR_SYMBOL_LIST(a), TENSOR_SYMBOL_LIST(x), SYMBOLIC_GRAPH_SOURCES(symbolic_graph), SYMBOLIC_GRAPH_DESTINATIONS(symbolic_graph));
    114
    1
      ccv_nnc_graph_exec_symbol_autogen(symbolic_graph, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS);
    115
    1
      ccv_nnc_tensor_symbol_t da = ccv_nnc_tensor_symbol_for_backward(symbolic_graph, a);
    116
    1
      ccv_nnc_tensor_symbol_t dx = ccv_nnc_tensor_symbol_for_backward(symbolic_graph, x);
    117
    1
      SYMBOLIC_GRAPH_GEN(symbolic_graph, CCV_NNC_LONG_DOT_GRAPH);
    118
    1
      ccv_nnc_graph_t* graph = 0;
    119
    1
      ccv_nnc_tensor_arena_t* tensor_arena = 0;
    120
    1
      ccv_nnc_graph_exec_arena_t* graph_exec_arena = 0;
    121
    1
      ccv_nnc_tensor_t* const a_tensor = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 100), 0);
    122
    1
      ccv_nnc_tensor_t* const da_tensor = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 100), 0);
    123
    1
      ccv_nnc_symbolic_graph_compile(symbolic_graph, ccv_nnc_default_compile_params, TENSOR_BIND_MAP(KV(a, a_tensor), KV(da, da_tensor)), 0, 0, SYMBOLIC_GRAPH_SOURCES(symbolic_graph), SYMBOLIC_GRAPH_DESTINATIONS(symbolic_graph), &graph, &tensor_arena, &graph_exec_arena);
    124
    1
      GRAPH_GEN(graph, CCV_NNC_LONG_DOT_GRAPH);
    125
    1
      ccv_nnc_tensor_t* const tx_tensor = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 100), 0);
    126
    1
      ccv_nnc_tensor_t* const x_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, x);
    127
    1
      dsfmt_t dsfmt;
    128
    1
      int i;
    129
    1
      dsfmt_init_gen_rand(&dsfmt, 1);
    130
    101
      for (i = 0; i < 100; i++100)
    131
    100
        x_tensor->data.f32[i] = tx_tensor->data.f32[i] = dsfmt_genrand_open_close(&dsfmt);
    132
    101
      for (i = 0; i < 100; i++100)
    133
    100
        da_tensor->data.f32[i] = 0;
    134
    1
      da_tensor->data.f32[88] = 1;
    135
    1
      ccv_nnc_graph_run(graph, 0, TRAVERSE_FULL, 0, 0);
    136
    1
      ccv_nnc_tensor_t* const ta_tensor = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 100), 0);
    137
    1
      ccv_nnc_cmd_exec(CMD_SOFTMAX_FORWARD(), ccv_nnc_no_hint, 0, TENSOR_LIST(tx_tensor), TENSOR_LIST(ta_tensor), 0);
    138
    1
      REQUIRE_TENSOR_EQ(a_tensor, ta_tensor, "softmax should match from the graph");
    139
    1
      ccv_nnc_tensor_t* const tdx_tensor = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 100), 0);
    140
    1
      ccv_nnc_cmd_exec(CMD_SOFTMAX_BACKWARD(), ccv_nnc_no_hint, 0, TENSOR_LIST(da_tensor, 0, ta_tensor), TENSOR_LIST(tdx_tensor), 0);
    141
    1
      ccv_nnc_tensor_t* const dx_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, dx);
    142
    1
      REQUIRE_TENSOR_EQ(dx_tensor, tdx_tensor, "softmax backward should match from the graph");
    143
    1
      ccv_nnc_tensor_free(tdx_tensor);
    144
    1
      ccv_nnc_tensor_free(tx_tensor);
    145
    1
      ccv_nnc_tensor_free(ta_tensor);
    146
    1
      ccv_nnc_tensor_free(a_tensor);
    147
    1
      ccv_nnc_tensor_free(da_tensor);
    148
    1
      ccv_nnc_symbolic_graph_free(symbolic_graph);
    149
    1
      ccv_nnc_graph_free(graph);
    150
    1
      ccv_nnc_tensor_arena_free(tensor_arena);
    151
    1
      ccv_nnc_graph_exec_arena_free(graph_exec_arena);
    152
    1
    }
    153
    154
    TEST_CASE("reduce max for [[1, 2, 3], [4, 5, 6]] on axis 1")
    155
    1
    {
    156
    1
      ccv_nnc_tensor_t* const a = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 3), 0);
    157
    1
      ccv_nnc_tensor_t* const b = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 1), 0);
    158
    1
      a->data.f32[0] = 1;
    159
    1
      a->data.f32[1] = 2;
    160
    1
      a->data.f32[2] = 3;
    161
    1
      a->data.f32[3] = 4;
    162
    1
      a->data.f32[4] = 5;
    163
    1
      a->data.f32[5] = 6;
    164
    1
      ccv_nnc_cmd_exec(CMD_REDUCE_MAX_FORWARD(1), ccv_nnc_no_hint, 0, TENSOR_LIST(a), TENSOR_LIST(b), 0);
    165
    1
      float btp[] = {
    166
    1
        3,
    167
    1
        6
    168
    1
      };
    169
    1
      ccv_nnc_tensor_t bt = ccv_nnc_tensor(btp, CPU_TENSOR_NHWC(32F, 2, 1), 0);
    170
    1
      REQUIRE_TENSOR_EQ(b, &bt, "result should be equal");
    171
    1
      ccv_nnc_tensor_free(a);
    172
    1
      ccv_nnc_tensor_free(b);
    173
    1
    }
    174
    175
    TEST_CASE("reduce max for [[1, 2, 3], [4, 5, 6]] on axis 0")
    176
    1
    {
    177
    1
      ccv_nnc_tensor_t* const a = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 3), 0);
    178
    1
      ccv_nnc_tensor_t* const b = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 3), 0);
    179
    1
      a->data.f32[0] = 1;
    180
    1
      a->data.f32[1] = 2;
    181
    1
      a->data.f32[2] = 3;
    182
    1
      a->data.f32[3] = 4;
    183
    1
      a->data.f32[4] = 5;
    184
    1
      a->data.f32[5] = 6;
    185
    1
      ccv_nnc_cmd_exec(CMD_REDUCE_MAX_FORWARD(0), ccv_nnc_no_hint, 0, TENSOR_LIST(a), TENSOR_LIST(b), 0);
    186
    1
      float btp[] = {
    187
    1
        4, 5, 6
    188
    1
      };
    189
    1
      ccv_nnc_tensor_t bt = ccv_nnc_tensor(btp, CPU_TENSOR_NHWC(32F, 3), 0);
    190
    1
      REQUIRE_TENSOR_EQ(b, &bt, "result should be equal");
    191
    1
      ccv_nnc_tensor_free(a);
    192
    1
      ccv_nnc_tensor_free(b);
    193
    1
    }
    194
    195
    TEST_CASE("reduce min for [[1, 2, 3], [4, 5, 6]] on axis 1")
    196
    1
    {
    197
    1
      ccv_nnc_tensor_t* const a = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 3), 0);
    198
    1
      ccv_nnc_tensor_t* const b = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 1), 0);
    199
    1
      a->data.f32[0] = 1;
    200
    1
      a->data.f32[1] = 2;
    201
    1
      a->data.f32[2] = 3;
    202
    1
      a->data.f32[3] = 4;
    203
    1
      a->data.f32[4] = 5;
    204
    1
      a->data.f32[5] = 6;
    205
    1
      ccv_nnc_cmd_exec(CMD_REDUCE_MIN_FORWARD(1), ccv_nnc_no_hint, 0, TENSOR_LIST(a), TENSOR_LIST(b), 0);
    206
    1
      float btp[] = {
    207
    1
        1,
    208
    1
        4
    209
    1
      };
    210
    1
      ccv_nnc_tensor_t bt = ccv_nnc_tensor(btp, CPU_TENSOR_NHWC(32F, 2, 1), 0);
    211
    1
      REQUIRE_TENSOR_EQ(b, &bt, "result should be equal");
    212
    1
      ccv_nnc_tensor_free(a);
    213
    1
      ccv_nnc_tensor_free(b);
    214
    1
    }
    215
    216
    TEST_CASE("reduce min for [[1, 2, 3], [4, 5, 6]] on axis 0")
    217
    {
    218
      ccv_nnc_tensor_t* const a = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 3), 0);
    219
      ccv_nnc_tensor_t* const b = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 3), 0);
    220
      a->data.f32[0] = 1;
    221
      a->data.f32[1] = 2;
    222
      a->data.f32[2] = 3;
    223
      a->data.f32[3] = 4;
    224
      a->data.f32[4] = 5;
    225
      a->data.f32[5] = 6;
    226
      ccv_nnc_cmd_exec(CMD_REDUCE_MIN_FORWARD(0), ccv_nnc_no_hint, 0, TENSOR_LIST(a), TENSOR_LIST(b), 0);
    227
      float btp[] = {
    228
        1, 2, 3
    229
      };
    230
      ccv_nnc_tensor_t bt = ccv_nnc_tensor(btp, CPU_TENSOR_NHWC(32F, 3), 0);
    231
      REQUIRE_TENSOR_EQ(b, &bt, "result should be equal");
    232
      ccv_nnc_tensor_free(a);
    233
      ccv_nnc_tensor_free(b);
    234
    }
    235
    236
    TEST_CASE("reduce sum for [[1, 2, 3], [4, 5, 6]] on axis 1 with model")
    237
    1
    {
    238
    1
      ccv_nnc_tensor_t* const a = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 3), 0);
    239
    1
      ccv_nnc_tensor_t* const b = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 1), 0);
    240
    1
      a->data.f32[0] = 1;
    241
    1
      a->data.f32[1] = 2;
    242
    1
      a->data.f32[2] = 3;
    243
    1
      a->data.f32[3] = 4;
    244
    1
      a->data.f32[4] = 5;
    245
    1
      a->data.f32[5] = 6;
    246
    1
      const int axis = 1;
    247
    1
      ccv_cnnp_model_t* const reduce_sum = ccv_cnnp_reduce_sum(&axis, 1, 0);
    248
    1
      const ccv_nnc_tensor_param_t a_params = CPU_TENSOR_NHWC(32F, 2, 3);
    249
    1
      ccv_cnnp_model_compile(reduce_sum, TENSOR_PARAM_LIST(a_params), CMD_NOOP(), CMD_NOOP());
    250
    1
      ccv_cnnp_model_evaluate(reduce_sum, (ccv_cnnp_evaluate_param_t){
    251
    1
        .requires_grad = 0,
    252
    1
        .is_test = 0,
    253
    1
        .disable_outgrad = CCV_CNNP_DISABLE_OUTGRAD_ALL
    254
    1
      }, TENSOR_LIST(a), TENSOR_LIST(b), 0, 0);
    255
    1
      float btp[] = {
    256
    1
        6,
    257
    1
        15
    258
    1
      };
    259
    1
      ccv_nnc_tensor_t bt = ccv_nnc_tensor(btp, CPU_TENSOR_NHWC(32F, 2, 1), 0);
    260
    1
      REQUIRE_TENSOR_EQ(b, &bt, "result should be equal");
    261
    1
      ccv_cnnp_model_free(reduce_sum);
    262
    1
      ccv_nnc_tensor_free(a);
    263
    1
      ccv_nnc_tensor_free(b);
    264
    1
    }
    265
    266
    TEST_CASE("reduce max for [[1, 2, 3], [4, 5, 6]] on axis 0 with model")
    267
    {
    268
      ccv_nnc_tensor_t* const a = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 3), 0);
    269
      ccv_nnc_tensor_t* const b = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 3), 0);
    270
      a->data.f32[0] = 1;
    271
      a->data.f32[1] = 2;
    272
      a->data.f32[2] = 3;
    273
      a->data.f32[3] = 4;
    274
      a->data.f32[4] = 5;
    275
      a->data.f32[5] = 6;
    276
      const int axis = 0;
    277
      ccv_cnnp_model_t* const reduce_max = ccv_cnnp_reduce_max(&axis, 1, 0);
    278
      const ccv_nnc_tensor_param_t a_params = CPU_TENSOR_NHWC(32F, 2, 3);
    279
      ccv_cnnp_model_compile(reduce_max, TENSOR_PARAM_LIST(a_params), CMD_NOOP(), CMD_NOOP());
    280
      ccv_cnnp_model_evaluate(reduce_max, (ccv_cnnp_evaluate_param_t){
    281
        .requires_grad = 0,
    282
        .is_test = 0,
    283
        .disable_outgrad = CCV_CNNP_DISABLE_OUTGRAD_ALL
    284
      }, TENSOR_LIST(a), TENSOR_LIST(b), 0, 0);
    285
      float btp[] = {
    286
        4, 5, 6
    287
      };
    288
      ccv_nnc_tensor_t bt = ccv_nnc_tensor(btp, CPU_TENSOR_NHWC(32F, 3), 0);
    289
      REQUIRE_TENSOR_EQ(b, &bt, "result should be equal");
    290
      ccv_cnnp_model_free(reduce_max);
    291
      ccv_nnc_tensor_free(a);
    292
      ccv_nnc_tensor_free(b);
    293
    }
    294
    295
    TEST_CASE("reduce min for [[1, 2, 3], [4, 5, 6]] on axis 0 with model")
    296
    1
    {
    297
    1
      ccv_nnc_tensor_t* const a = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 3), 0);
    298
    1
      ccv_nnc_tensor_t* const b = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 3), 0);
    299
    1
      a->data.f32[0] = 1;
    300
    1
      a->data.f32[1] = 2;
    301
    1
      a->data.f32[2] = 3;
    302
    1
      a->data.f32[3] = 4;
    303
    1
      a->data.f32[4] = 5;
    304
    1
      a->data.f32[5] = 6;
    305
    1
      const int axis = 0;
    306
    1
      ccv_cnnp_model_t* const reduce_min = ccv_cnnp_reduce_min(&axis, 1, 0);
    307
    1
      const ccv_nnc_tensor_param_t a_params = CPU_TENSOR_NHWC(32F, 2, 3);
    308
    1
      ccv_cnnp_model_compile(reduce_min, TENSOR_PARAM_LIST(a_params), CMD_NOOP(), CMD_NOOP());
    309
    1
      ccv_cnnp_model_evaluate(reduce_min, (ccv_cnnp_evaluate_param_t){
    310
    1
        .requires_grad = 0,
    311
    1
        .is_test = 0,
    312
    1
        .disable_outgrad = CCV_CNNP_DISABLE_OUTGRAD_ALL
    313
    1
      }, TENSOR_LIST(a), TENSOR_LIST(b), 0, 0);
    314
    1
      float btp[] = {
    315
    1
        1, 2, 3
    316
    1
      };
    317
    1
      ccv_nnc_tensor_t bt = ccv_nnc_tensor(btp, CPU_TENSOR_NHWC(32F, 3), 0);
    318
    1
      REQUIRE_TENSOR_EQ(b, &bt, "result should be equal");
    319
    1
      ccv_cnnp_model_free(reduce_min);
    320
    1
      ccv_nnc_tensor_free(a);
    321
    1
      ccv_nnc_tensor_free(b);
    322
    1
    }
    323
    324
    TEST_CASE("argmax for [[1, 2, 3], [4, 5, 2]] on axis 0 with model")
    325
    1
    {
    326
    1
      ccv_nnc_tensor_t* const a = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 3), 0);
    327
    1
      ccv_nnc_tensor_t* const b = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32S, 3), 0);
    328
    1
      a->data.f32[0] = 1;
    329
    1
      a->data.f32[1] = 2;
    330
    1
      a->data.f32[2] = 3;
    331
    1
      a->data.f32[3] = 4;
    332
    1
      a->data.f32[4] = 5;
    333
    1
      a->data.f32[5] = 2;
    334
    1
      ccv_cnnp_model_t* const argmax = ccv_cnnp_argmax(0, 0);
    335
    1
      const ccv_nnc_tensor_param_t a_params = CPU_TENSOR_NHWC(32F, 2, 3);
    336
    1
      ccv_cnnp_model_compile(argmax, TENSOR_PARAM_LIST(a_params), CMD_NOOP(), CMD_NOOP());
    337
    1
      ccv_cnnp_model_evaluate(argmax, (ccv_cnnp_evaluate_param_t){
    338
    1
        .requires_grad = 0,
    339
    1
        .is_test = 0,
    340
    1
        .disable_outgrad = CCV_CNNP_DISABLE_OUTGRAD_ALL
    341
    1
      }, TENSOR_LIST(a), TENSOR_LIST(b), 0, 0);
    342
    1
      int btp[] = {
    343
    1
        1, 1, 0
    344
    1
      };
    345
    1
      ccv_nnc_tensor_t bt = ccv_nnc_tensor(btp, CPU_TENSOR_NHWC(32S, 3), 0);
    346
    1
      REQUIRE_TENSOR_EQ(b, &bt, "result should be equal");
    347
    1
      ccv_cnnp_model_free(argmax);
    348
    1
      ccv_nnc_tensor_free(a);
    349
    1
      ccv_nnc_tensor_free(b);
    350
    1
    }
    351
    352
    TEST_CASE("argmin for [[1, 2, 3], [4, 5, 2]] on axis 0 with model")
    353
    1
    {
    354
    1
      ccv_nnc_tensor_t* const a = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 3), 0);
    355
    1
      ccv_nnc_tensor_t* const b = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32S, 3), 0);
    356
    1
      a->data.f32[0] = 1;
    357
    1
      a->data.f32[1] = 2;
    358
    1
      a->data.f32[2] = 3;
    359
    1
      a->data.f32[3] = 4;
    360
    1
      a->data.f32[4] = 5;
    361
    1
      a->data.f32[5] = 2;
    362
    1
      ccv_cnnp_model_t* const argmin = ccv_cnnp_argmin(0, 0);
    363
    1
      const ccv_nnc_tensor_param_t a_params = CPU_TENSOR_NHWC(32F, 2, 3);
    364
    1
      ccv_cnnp_model_compile(argmin, TENSOR_PARAM_LIST(a_params), CMD_NOOP(), CMD_NOOP());
    365
    1
      ccv_cnnp_model_evaluate(argmin, (ccv_cnnp_evaluate_param_t){
    366
    1
        .requires_grad = 0,
    367
    1
        .is_test = 0,
    368
    1
        .disable_outgrad = CCV_CNNP_DISABLE_OUTGRAD_ALL
    369
    1
      }, TENSOR_LIST(a), TENSOR_LIST(b), 0, 0);
    370
    1
      int btp[] = {
    371
    1
        0, 0, 1
    372
    1
      };
    373
    1
      ccv_nnc_tensor_t bt = ccv_nnc_tensor(btp, CPU_TENSOR_NHWC(32S, 3), 0);
    374
    1
      REQUIRE_TENSOR_EQ(b, &bt, "result should be equal");
    375
    1
      ccv_cnnp_model_free(argmin);
    376
    1
      ccv_nnc_tensor_free(a);
    377
    1
      ccv_nnc_tensor_free(b);
    378
    1
    }
    379
    380
    TEST_CASE("reduce mean for [[1, 2, 3], [4, 5, 6]] on axis 1 with model")
    381
    1
    {
    382
    1
      ccv_nnc_tensor_t* const a = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 3), 0);
    383
    1
      ccv_nnc_tensor_t* const b = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 1), 0);
    384
    1
      a->data.f32[0] = 1;
    385
    1
      a->data.f32[1] = 2;
    386
    1
      a->data.f32[2] = 3;
    387
    1
      a->data.f32[3] = 4;
    388
    1
      a->data.f32[4] = 5;
    389
    1
      a->data.f32[5] = 6;
    390
    1
      const int axis = 1;
    391
    1
      ccv_cnnp_model_t* const reduce_mean = ccv_cnnp_reduce_mean(&axis, 1, 0);
    392
    1
      const ccv_nnc_tensor_param_t a_params = CPU_TENSOR_NHWC(32F, 2, 3);
    393
    1
      ccv_cnnp_model_compile(reduce_mean, TENSOR_PARAM_LIST(a_params), CMD_NOOP(), CMD_NOOP());
    394
    1
      ccv_cnnp_model_evaluate(reduce_mean, (ccv_cnnp_evaluate_param_t){
    395
    1
        .requires_grad = 0,
    396
    1
        .is_test = 0,
    397
    1
        .disable_outgrad = CCV_CNNP_DISABLE_OUTGRAD_ALL
    398
    1
      }, TENSOR_LIST(a), TENSOR_LIST(b), 0, 0);
    399
    1
      float btp[] = {
    400
    1
        2,
    401
    1
        5
    402
    1
      };
    403
    1
      ccv_nnc_tensor_t bt = ccv_nnc_tensor(btp, CPU_TENSOR_NHWC(32F, 2, 1), 0);
    404
    1
      REQUIRE_TENSOR_EQ(b, &bt, "result should be equal");
    405
    1
      ccv_cnnp_model_free(reduce_mean);
    406
    1
      ccv_nnc_tensor_free(a);
    407
    1
      ccv_nnc_tensor_free(b);
    408
    1
    }
    409
    410
    TEST_CASE("argmax for [[1, 2, 7], [5, 6, 4]] on axis 0")
    411
    1
    {
    412
    1
      ccv_nnc_tensor_t* const a = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 3), 0);
    413
    1
      ccv_nnc_tensor_t* const b = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32S, 3), 0);
    414
    1
      a->data.f32[0] = 1;
    415
    1
      a->data.f32[1] = 2;
    416
    1
      a->data.f32[2] = 7;
    417
    1
      a->data.f32[3] = 5;
    418
    1
      a->data.f32[4] = 6;
    419
    1
      a->data.f32[5] = 4;
    420
    1
      ccv_nnc_cmd_exec(CMD_ARGMAX_FORWARD(0), ccv_nnc_no_hint, 0, TENSOR_LIST(a), TENSOR_LIST(b), 0);
    421
    1
      int btp[] = {
    422
    1
        1, 1, 0
    423
    1
      };
    424
    1
      ccv_nnc_tensor_t bt = ccv_nnc_tensor(btp, CPU_TENSOR_NHWC(32S, 3), 0);
    425
    1
      REQUIRE_TENSOR_EQ(b, &bt, "result should be equal");
    426
    1
      ccv_nnc_tensor_free(a);
    427
    1
      ccv_nnc_tensor_free(b);
    428
    1
    }
    429
    430
    TEST_CASE("argmin for [[1, 2, 7], [5, 6, 4]] on axis 0")
    431
    1
    {
    432
    1
      ccv_nnc_tensor_t* const a = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 3), 0);
    433
    1
      ccv_nnc_tensor_t* const b = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32S, 3), 0);
    434
    1
      a->data.f32[0] = 1;
    435
    1
      a->data.f32[1] = 2;
    436
    1
      a->data.f32[2] = 7;
    437
    1
      a->data.f32[3] = 5;
    438
    1
      a->data.f32[4] = 6;
    439
    1
      a->data.f32[5] = 4;
    440
    1
      ccv_nnc_cmd_exec(CMD_ARGMIN_FORWARD(0), ccv_nnc_no_hint, 0, TENSOR_LIST(a), TENSOR_LIST(b), 0);
    441
    1
      int btp[] = {
    442
    1
        0, 0, 1
    443
    1
      };
    444
    1
      ccv_nnc_tensor_t bt = ccv_nnc_tensor(btp, CPU_TENSOR_NHWC(32S, 3), 0);
    445
    1
      REQUIRE_TENSOR_EQ(b, &bt, "result should be equal");
    446
    1
      ccv_nnc_tensor_free(a);
    447
    1
      ccv_nnc_tensor_free(b);
    448
    1
    }
    449
    450
    TEST_CASE("argmax for [[1, 2, 7], [5, 6, 4]] on axis 1")
    451
    1
    {
    452
    1
      ccv_nnc_tensor_t* const a = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 3), 0);
    453
    1
      ccv_nnc_tensor_t* const b = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32S, 2, 1), 0);
    454
    1
      a->data.f32[0] = 1;
    455
    1
      a->data.f32[1] = 2;
    456
    1
      a->data.f32[2] = 7;
    457
    1
      a->data.f32[3] = 5;
    458
    1
      a->data.f32[4] = 6;
    459
    1
      a->data.f32[5] = 4;
    460
    1
      ccv_nnc_cmd_exec(CMD_ARGMAX_FORWARD(1), ccv_nnc_no_hint, 0, TENSOR_LIST(a), TENSOR_LIST(b), 0);
    461
    1
      int btp[] = {
    462
    1
        2,
    463
    1
        1
    464
    1
      };
    465
    1
      ccv_nnc_tensor_t bt = ccv_nnc_tensor(btp, CPU_TENSOR_NHWC(32S, 2, 1), 0);
    466
    1
      REQUIRE_TENSOR_EQ(b, &bt, "result should be equal");
    467
    1
      ccv_nnc_tensor_free(a);
    468
    1
      ccv_nnc_tensor_free(b);
    469
    1
    }
    470
    471
    TEST_CASE("reduce norm2 for [[1, 2, 3], [4, 5, 6]] on axis 1")
    472
    1
    {
    473
    1
      ccv_nnc_tensor_t* const a = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 3), 0);
    474
    1
      ccv_nnc_tensor_t* const b = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 1), 0);
    475
    1
      a->data.f32[0] = 1;
    476
    1
      a->data.f32[1] = 2;
    477
    1
      a->data.f32[2] = 3;
    478
    1
      a->data.f32[3] = 4;
    479
    1
      a->data.f32[4] = 5;
    480
    1
      a->data.f32[5] = 6;
    481
    1
      ccv_nnc_cmd_exec(CMD_REDUCE_NORM2_FORWARD(1), ccv_nnc_no_hint, 0, TENSOR_LIST(a), TENSOR_LIST(b), 0);
    482
    1
      float btp[] = {
    483
    1
        sqrt(1 + 2 * 2 + 3 * 3),
    484
    1
        sqrt(4 * 4 + 5 * 5 + 6 * 6)
    485
    1
      };
    486
    1
      ccv_nnc_tensor_t bt = ccv_nnc_tensor(btp, CPU_TENSOR_NHWC(32F, 2, 1), 0);
    487
    1
      REQUIRE_TENSOR_EQ(b, &bt, "result should be equal");
    488
    1
      ccv_nnc_tensor_free(a);
    489
    1
      ccv_nnc_tensor_free(b);
    490
    1
    }
    491
    492
    TEST_CASE("reduce norm2 for [[1, 2, 3], [4, 5, 6]] on axis 0")
    493
    1
    {
    494
    1
      ccv_nnc_tensor_t* const a = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 3), 0);
    495
    1
      ccv_nnc_tensor_t* const b = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 3), 0);
    496
    1
      a->data.f32[0] = 1;
    497
    1
      a->data.f32[1] = 2;
    498
    1
      a->data.f32[2] = 3;
    499
    1
      a->data.f32[3] = 4;
    500
    1
      a->data.f32[4] = 5;
    501
    1
      a->data.f32[5] = 6;
    502
    1
      ccv_nnc_cmd_exec(CMD_REDUCE_NORM2_FORWARD(0), ccv_nnc_no_hint, 0, TENSOR_LIST(a), TENSOR_LIST(b), 0);
    503
    1
      float btp[] = {
    504
    1
        sqrt(1 + 4 * 4), sqrt(2 * 2 + 5 * 5), sqrt(3 * 3 + 6 * 6)
    505
    1
      };
    506
    1
      ccv_nnc_tensor_t bt = ccv_nnc_tensor(btp, CPU_TENSOR_NHWC(32F, 3), 0);
    507
    1
      REQUIRE_TENSOR_EQ(b, &bt, "result should be equal");
    508
    1
      ccv_nnc_tensor_free(a);
    509
    1
      ccv_nnc_tensor_free(b);
    510
    1
    }
    511
    512
    TEST_CASE("reduce norm2 for [[1, 2, 3], [4, 5, 6]] on axis 1 backward")
    513
    1
    {
    514
    1
      ccv_nnc_tensor_t* const a = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 3), 0);
    515
    1
      ccv_nnc_tensor_t* const b = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 1), 0);
    516
    1
      a->data.f32[0] = 1;
    517
    1
      a->data.f32[1] = 2;
    518
    1
      a->data.f32[2] = 3;
    519
    1
      a->data.f32[3] = 4;
    520
    1
      a->data.f32[4] = 5;
    521
    1
      a->data.f32[5] = 6;
    522
    1
      ccv_nnc_cmd_exec(CMD_REDUCE_NORM2_FORWARD(1), ccv_nnc_no_hint, 0, TENSOR_LIST(a), TENSOR_LIST(b), 0);
    523
    1
      ccv_nnc_tensor_t* const g = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 1), 0);
    524
    1
      g->data.f32[0] = 0.5;
    525
    1
      g->data.f32[1] = 0.5;
    526
    1
      ccv_nnc_tensor_t* const h = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 3), 0);
    527
    1
      ccv_nnc_cmd_exec(CMD_REDUCE_NORM2_BACKWARD(1), ccv_nnc_no_hint, 0, TENSOR_LIST(g, a, b), TENSOR_LIST(h), 0);
    528
    1
      float htp[] = {
    529
    1
        0.5 * 1 / sqrt(1 + 2 * 2 + 3 * 3),
    530
    1
        0.5 * 2 / sqrt(1 + 2 * 2 + 3 * 3),
    531
    1
        0.5 * 3 / sqrt(1 + 2 * 2 + 3 * 3),
    532
    1
        0.5 * 4 / sqrt(4 * 4 + 5 * 5 + 6 * 6),
    533
    1
        0.5 * 5 / sqrt(4 * 4 + 5 * 5 + 6 * 6),
    534
    1
        0.5 * 6 / sqrt(4 * 4 + 5 * 5 + 6 * 6),
    535
    1
      };
    536
    1
      ccv_nnc_tensor_t ht = ccv_nnc_tensor(htp, CPU_TENSOR_NHWC(32F, 2, 3), 0);
    537
    1
      REQUIRE_TENSOR_EQ(h, &ht, "result should be equal");
    538
    1
      ccv_nnc_tensor_free(a);
    539
    1
      ccv_nnc_tensor_free(b);
    540
    1
      ccv_nnc_tensor_free(g);
    541
    1
      ccv_nnc_tensor_free(h);
    542
    1
    }
    543
    544
    TEST_CASE("reduce norm2 for [[1, 2, 3], [4, 5, 6]] on axis 0 backward")
    545
    1
    {
    546
    1
      ccv_nnc_tensor_t* const a = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 3), 0);
    547
    1
      ccv_nnc_tensor_t* const b = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 3), 0);
    548
    1
      a->data.f32[0] = 1;
    549
    1
      a->data.f32[1] = 2;
    550
    1
      a->data.f32[2] = 3;
    551
    1
      a->data.f32[3] = 4;
    552
    1
      a->data.f32[4] = 5;
    553
    1
      a->data.f32[5] = 6;
    554
    1
      ccv_nnc_cmd_exec(CMD_REDUCE_NORM2_FORWARD(0), ccv_nnc_no_hint, 0, TENSOR_LIST(a), TENSOR_LIST(b), 0);
    555
    1
      ccv_nnc_tensor_t* const g = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 3), 0);
    556
    1
      g->data.f32[0] = 1;
    557
    1
      g->data.f32[1] = 1;
    558
    1
      g->data.f32[2] = 1;
    559
    1
      ccv_nnc_tensor_t* const h = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 3), 0);
    560
    1
      ccv_nnc_cmd_exec(CMD_REDUCE_NORM2_BACKWARD(0), ccv_nnc_no_hint, 0, TENSOR_LIST(g, a, b), TENSOR_LIST(h), 0);
    561
    1
      float htp[] = {
    562
    1
        1 / sqrt(1 + 4 * 4), 2 / sqrt(2 * 2 + 5 * 5), 3 / sqrt(3 * 3 + 6 * 6),
    563
    1
        4 / sqrt(1 + 4 * 4), 5 / sqrt(2 * 2 + 5 * 5), 6 / sqrt(3 * 3 + 6 * 6)
    564
    1
      };
    565
    1
      ccv_nnc_tensor_t ht = ccv_nnc_tensor(htp, CPU_TENSOR_NHWC(32F, 2, 3), 0);
    566
    1
      REQUIRE_TENSOR_EQ(h, &ht, "result should be equal");
    567
    1
      ccv_nnc_tensor_free(a);
    568
    1
      ccv_nnc_tensor_free(b);
    569
    1
      ccv_nnc_tensor_free(g);
    570
    1
      ccv_nnc_tensor_free(h);
    571
    1
    }
    572
    573
    TEST_CASE("reduce norm2 for [[1, 2, 3], [4, 5, 6]] on axis 0 with model")
    574
    1
    {
    575
    1
      ccv_nnc_tensor_t* const a = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 3), 0);
    576
    1
      ccv_nnc_tensor_t* const b = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 3), 0);
    577
    1
      a->data.f32[0] = 1;
    578
    1
      a->data.f32[1] = 2;
    579
    1
      a->data.f32[2] = 3;
    580
    1
      a->data.f32[3] = 4;
    581
    1
      a->data.f32[4] = 5;
    582
    1
      a->data.f32[5] = 6;
    583
    1
      const int axis = 0;
    584
    1
      ccv_cnnp_model_t* const reduce_norm2 = ccv_cnnp_reduce_norm2(&axis, 1, 0);
    585
    1
      const ccv_nnc_tensor_param_t a_params = CPU_TENSOR_NHWC(32F, 2, 3);
    586
    1
      ccv_cnnp_model_compile(reduce_norm2, TENSOR_PARAM_LIST(a_params), CMD_NOOP(), CMD_NOOP());
    587
    1
      ccv_cnnp_model_evaluate(reduce_norm2, (ccv_cnnp_evaluate_param_t){
    588
    1
        .requires_grad = 0,
    589
    1
        .is_test = 0,
    590
    1
        .disable_outgrad = CCV_CNNP_DISABLE_OUTGRAD_ALL
    591
    1
      }, TENSOR_LIST(a), TENSOR_LIST(b), 0, 0);
    592
    1
      float btp[] = {
    593
    1
        sqrt(1 + 4 * 4), sqrt(2 * 2 + 5 * 5), sqrt(3 * 3 + 6 * 6)
    594
    1
      };
    595
    1
      ccv_nnc_tensor_t bt = ccv_nnc_tensor(btp, CPU_TENSOR_NHWC(32F, 3), 0);
    596
    1
      REQUIRE_TENSOR_EQ(b, &bt, "result should be equal");
    597
    1
      ccv_cnnp_model_free(reduce_norm2);
    598
    1
      ccv_nnc_tensor_free(a);
    599
    1
      ccv_nnc_tensor_free(b);
    600
    1
    }
    601
    602
    TEST_CASE("isnan for [[1, 2, 3], [4, 5, 6]] on axis 1")
    603
    1
    {
    604
    1
      ccv_nnc_tensor_t* const a = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 3), 0);
    605
    1
      ccv_nnc_tensor_t* const b = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32S, 2, 1), 0);
    606
    1
      a->data.f32[0] = NAN;
    607
    1
      a->data.f32[1] = 2;
    608
    1
      a->data.f32[2] = 3;
    609
    1
      a->data.f32[3] = 4;
    610
    1
      a->data.f32[4] = 5;
    611
    1
      a->data.f32[5] = 6;
    612
    1
      ccv_nnc_cmd_exec(CMD_REDUCE_ISNAN_FORWARD(1), ccv_nnc_no_hint, 0, TENSOR_LIST(a), TENSOR_LIST(b), 0);
    613
    1
      int btp[] = {
    614
    1
        1,
    615
    1
        0
    616
    1
      };
    617
    1
      ccv_nnc_tensor_t bt = ccv_nnc_tensor(btp, CPU_TENSOR_NHWC(32S, 2, 1), 0);
    618
    1
      REQUIRE_TENSOR_EQ(b, &bt, "result should be equal");
    619
    1
      ccv_nnc_tensor_free(a);
    620
    1
      ccv_nnc_tensor_free(b);
    621
    1
    }
    622
    623
    #include "case_main.h"