## 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/compare.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("min of two tensors")
    15
    {
    16
      ccv_nnc_tensor_t* const a = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 2, 3), 0);
    17
      ccv_nnc_tensor_t* const b = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 2, 3), 0);
    18
      ccv_nnc_tensor_t* const c = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 2, 3), 0);
    19
      int i;
    20
      for (i = 0; i < 2 * 2 * 3; i++)
    21
        a->data.f32[i] = i;
    22
      for (i = 0; i < 2 * 2 * 3; i++)
    23
        b->data.f32[i] = i - 1;
    24
      ccv_nnc_cmd_exec(CMD_MIN_FORWARD(), ccv_nnc_no_hint, 0, TENSOR_LIST(a, b), TENSOR_LIST(c), 0);
    25
      REQUIRE_TENSOR_EQ(b, c, "c should be the minimal of the two");
    26
      ccv_nnc_tensor_free(a);
    27
      ccv_nnc_tensor_free(b);
    28
      ccv_nnc_tensor_free(c);
    29
    }
    30
    31
    TEST_CASE("min of two tensor views")
    32
    1
    {
    33
    1
      ccv_nnc_tensor_t* const a = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 4, 4, 3), 0);
    34
    1
      ccv_nnc_tensor_t* const b = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 4, 4, 3), 0);
    35
    1
      ccv_nnc_tensor_t* const c = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 2, 3), 0);
    36
    1
      int i;
    37
    49
      for (i = 0; i < 4 * 4 * 3; i++48)
    38
    48
        a->data.f32[i] = i;
    39
    49
      for (i = 0; i < 4 * 4 * 3; i++48)
    40
    48
        b->data.f32[i] = i - 1;
    41
    1
      ccv_nnc_tensor_view_t* const av = ccv_nnc_tensor_view_new(a, CPU_TENSOR_NHWC(32F, 2, 2, 3), DIM_ALLOC(), DIM_ALLOC(4 * 3, 3, 1));
    42
    1
      ccv_nnc_tensor_view_t* const bv = ccv_nnc_tensor_view_new(b, CPU_TENSOR_NHWC(32F, 2, 2, 3), DIM_ALLOC(), DIM_ALLOC(4 * 3, 3, 1));
    43
    1
      ccv_nnc_cmd_exec(CMD_MIN_FORWARD(), ccv_nnc_no_hint, 0, TENSOR_LIST((ccv_nnc_tensor_t*)av, (ccv_nnc_tensor_t*)bv), TENSOR_LIST(c), 0);
    44
    1
      ccv_nnc_tensor_t* const bvt = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 2, 3), 0);
    45
    1
      ccv_nnc_cmd_exec(CMD_DATATYPE_CONVERSION_FORWARD(), ccv_nnc_no_hint, 0, TENSOR_LIST((ccv_nnc_tensor_t*)bv), TENSOR_LIST(bvt), 0);
    46
    1
      REQUIRE_TENSOR_EQ(bvt, c, "c should be the minimal of the two");
    47
    1
      ccv_nnc_tensor_free(a);
    48
    1
      ccv_nnc_tensor_free(b);
    49
    1
      ccv_nnc_tensor_free(c);
    50
    1
      ccv_nnc_tensor_free(bvt);
    51
    1
      ccv_nnc_tensor_view_free(av);
    52
    1
      ccv_nnc_tensor_view_free(bv);
    53
    1
    }
    54
    55
    TEST_CASE("min of two tensors backward")
    56
    1
    {
    57
    1
      ccv_nnc_tensor_t* const a = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 2, 3), 0);
    58
    1
      ccv_nnc_tensor_t* const b = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 2, 3), 0);
    59
    1
      ccv_nnc_tensor_t* const g = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 2, 3), 0);
    60
    1
      ccv_nnc_tensor_t* const ha = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 2, 3), 0);
    61
    1
      ccv_nnc_tensor_t* const hb = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 2, 3), 0);
    62
    1
      ccv_nnc_tensor_t* const hat = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 2, 3), 0);
    63
    1
      ccv_nnc_tensor_t* const hbt = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 2, 3), 0);
    64
    1
      int i;
    65
    13
      for (i = 0; i < 2 * 2 * 3; i++12)
    66
    12
        a->data.f32[i] = i;
    67
    13
      for (i = 0; i < 2 * 2 * 3; i++12)
    68
    12
        b->data.f32[i] = i < 3 ? i3 : i - 19;
    69
    13
      for (i = 0; i < 2 * 2 * 3; i++12)
    70
    12
        g->data.f32[i] = -1;
    71
    1
      ccv_nnc_cmd_exec(CMD_MIN_BACKWARD(), ccv_nnc_no_hint, 0, TENSOR_LIST(g, a, b), TENSOR_LIST(ha, hb), 0);
    72
    13
      for (i = 0; i < 2 * 2 * 3; i++12)
    73
    12
        hat->data.f32[i] = i < 3 ? -13 : 09;
    74
    13
      for (i = 0; i < 2 * 2 * 3; i++12)
    75
    12
        hbt->data.f32[i] = -1;
    76
    1
      REQUIRE_TENSOR_EQ(ha, hat, "ha should only carry gradients for the first 3");
    77
    1
      REQUIRE_TENSOR_EQ(hb, hbt, "hb should only carry all gradients");
    78
    1
      ccv_nnc_tensor_free(a);
    79
    1
      ccv_nnc_tensor_free(b);
    80
    1
      ccv_nnc_tensor_free(g);
    81
    1
      ccv_nnc_tensor_free(ha);
    82
    1
      ccv_nnc_tensor_free(hb);
    83
    1
      ccv_nnc_tensor_free(hat);
    84
    1
      ccv_nnc_tensor_free(hbt);
    85
    1
    }
    86
    87
    TEST_CASE("min of two tensors backward with null")
    88
    1
    {
    89
    1
      ccv_nnc_tensor_t* const a = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 2, 3), 0);
    90
    1
      ccv_nnc_tensor_t* const b = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 2, 3), 0);
    91
    1
      ccv_nnc_tensor_t* const ha = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 2, 3), 0);
    92
    1
      ccv_nnc_tensor_t* const hb = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 2, 3), 0);
    93
    1
      ccv_nnc_tensor_t* const hat = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 2, 3), 0);
    94
    1
      ccv_nnc_tensor_t* const hbt = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 2, 3), 0);
    95
    1
      int i;
    96
    13
      for (i = 0; i < 2 * 2 * 3; i++12)
    97
    12
        a->data.f32[i] = i;
    98
    13
      for (i = 0; i < 2 * 2 * 3; i++12)
    99
    12
        b->data.f32[i] = i < 3 ? i3 : i - 19;
    100
    1
      ccv_nnc_cmd_exec(CMD_MIN_BACKWARD(), ccv_nnc_no_hint, 0, TENSOR_LIST(0, a, b), TENSOR_LIST(ha, hb), 0);
    101
    13
      for (i = 0; i < 2 * 2 * 3; i++12)
    102
    12
        hat->data.f32[i] = i < 3 ? 13 : 09;
    103
    13
      for (i = 0; i < 2 * 2 * 3; i++12)
    104
    12
        hbt->data.f32[i] = 1;
    105
    1
      REQUIRE_TENSOR_EQ(ha, hat, "ha should only carry gradients for the first 3");
    106
    1
      REQUIRE_TENSOR_EQ(hb, hbt, "hb should only carry all gradients");
    107
    1
      ccv_nnc_tensor_free(a);
    108
    1
      ccv_nnc_tensor_free(b);
    109
    1
      ccv_nnc_tensor_free(ha);
    110
    1
      ccv_nnc_tensor_free(hb);
    111
    1
      ccv_nnc_tensor_free(hat);
    112
    1
      ccv_nnc_tensor_free(hbt);
    113
    1
    }
    114
    115
    TEST_CASE("min of two tensor views backward")
    116
    1
    {
    117
    1
      ccv_nnc_tensor_t* const a = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 4, 4, 3), 0);
    118
    1
      ccv_nnc_tensor_t* const b = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 4, 4, 3), 0);
    119
    1
      ccv_nnc_tensor_t* const g = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 2, 3), 0);
    120
    1
      ccv_nnc_tensor_t* const ha = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 2, 3), 0);
    121
    1
      ccv_nnc_tensor_t* const hb = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 2, 3), 0);
    122
    1
      ccv_nnc_tensor_t* const hat = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 2, 3), 0);
    123
    1
      ccv_nnc_tensor_t* const hbt = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 2, 3), 0);
    124
    1
      int i;
    125
    49
      for (i = 0; i < 4 * 4 * 3; i++48)
    126
    48
        a->data.f32[i] = i;
    127
    49
      for (i = 0; i < 4 * 4 * 3; i++48)
    128
    48
        b->data.f32[i] = i < 3 ? i3 : i - 145;
    129
    1
      ccv_nnc_tensor_view_t* const av = ccv_nnc_tensor_view_new(a, CPU_TENSOR_NHWC(32F, 2, 2, 3), DIM_ALLOC(), DIM_ALLOC(4 * 3, 3, 1));
    130
    1
      ccv_nnc_tensor_view_t* const bv = ccv_nnc_tensor_view_new(b, CPU_TENSOR_NHWC(32F, 2, 2, 3), DIM_ALLOC(), DIM_ALLOC(4 * 3, 3, 1));
    131
    13
      for (i = 0; i < 2 * 2 * 3; i++12)
    132
    12
        g->data.f32[i] = -1;
    133
    1
      ccv_nnc_cmd_exec(CMD_MIN_BACKWARD(), ccv_nnc_no_hint, 0, TENSOR_LIST(g, (ccv_nnc_tensor_t*)av, (ccv_nnc_tensor_t*)bv), TENSOR_LIST(ha, hb), 0);
    134
    13
      for (i = 0; i < 2 * 2 * 3; i++12)
    135
    12
        hat->data.f32[i] = i < 3 ? -13 : 09;
    136
    13
      for (i = 0; i < 2 * 2 * 3; i++12)
    137
    12
        hbt->data.f32[i] = -1;
    138
    1
      REQUIRE_TENSOR_EQ(ha, hat, "ha should only carry gradients for the first 3");
    139
    1
      REQUIRE_TENSOR_EQ(hb, hbt, "hb should only carry all gradients");
    140
    1
      ccv_nnc_tensor_free(a);
    141
    1
      ccv_nnc_tensor_free(b);
    142
    1
      ccv_nnc_tensor_view_free(av);
    143
    1
      ccv_nnc_tensor_view_free(bv);
    144
    1
      ccv_nnc_tensor_free(g);
    145
    1
      ccv_nnc_tensor_free(ha);
    146
    1
      ccv_nnc_tensor_free(hb);
    147
    1
      ccv_nnc_tensor_free(hat);
    148
    1
      ccv_nnc_tensor_free(hbt);
    149
    1
    }
    150
    151
    TEST_CASE("min of two tensor views backward with null")
    152
    1
    {
    153
    1
      ccv_nnc_tensor_t* const a = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 4, 4, 3), 0);
    154
    1
      ccv_nnc_tensor_t* const b = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 4, 4, 3), 0);
    155
    1
      ccv_nnc_tensor_t* const ha = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 2, 3), 0);
    156
    1
      ccv_nnc_tensor_t* const hb = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 2, 3), 0);
    157
    1
      ccv_nnc_tensor_t* const hat = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 2, 3), 0);
    158
    1
      ccv_nnc_tensor_t* const hbt = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 2, 3), 0);
    159
    1
      int i;
    160
    49
      for (i = 0; i < 4 * 4 * 3; i++48)
    161
    48
        a->data.f32[i] = i;
    162
    49
      for (i = 0; i < 4 * 4 * 3; i++48)
    163
    48
        b->data.f32[i] = i < 3 ? i3 : i - 145;
    164
    1
      ccv_nnc_tensor_view_t* const av = ccv_nnc_tensor_view_new(a, CPU_TENSOR_NHWC(32F, 2, 2, 3), DIM_ALLOC(), DIM_ALLOC(4 * 3, 3, 1));
    165
    1
      ccv_nnc_tensor_view_t* const bv = ccv_nnc_tensor_view_new(b, CPU_TENSOR_NHWC(32F, 2, 2, 3), DIM_ALLOC(), DIM_ALLOC(4 * 3, 3, 1));
    166
    1
      ccv_nnc_cmd_exec(CMD_MIN_BACKWARD(), ccv_nnc_no_hint, 0, TENSOR_LIST(0, (ccv_nnc_tensor_t*)av, (ccv_nnc_tensor_t*)bv), TENSOR_LIST(ha, hb), 0);
    167
    13
      for (i = 0; i < 2 * 2 * 3; i++12)
    168
    12
        hat->data.f32[i] = i < 3 ? 13 : 09;
    169
    13
      for (i = 0; i < 2 * 2 * 3; i++12)
    170
    12
        hbt->data.f32[i] = 1;
    171
    1
      REQUIRE_TENSOR_EQ(ha, hat, "ha should only carry gradients for the first 3");
    172
    1
      REQUIRE_TENSOR_EQ(hb, hbt, "hb should only carry all gradients");
    173
    1
      ccv_nnc_tensor_free(a);
    174
    1
      ccv_nnc_tensor_free(b);
    175
    1
      ccv_nnc_tensor_view_free(av);
    176
    1
      ccv_nnc_tensor_view_free(bv);
    177
    1
      ccv_nnc_tensor_free(ha);
    178
    1
      ccv_nnc_tensor_free(hb);
    179
    1
      ccv_nnc_tensor_free(hat);
    180
    1
      ccv_nnc_tensor_free(hbt);
    181
    1
    }
    182
    183
    TEST_CASE("min of two tensors with model")
    184
    1
    {
    185
    1
      ccv_nnc_tensor_t* const a = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 2, 3), 0);
    186
    1
      ccv_nnc_tensor_t* const b = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 2, 3), 0);
    187
    1
      ccv_nnc_tensor_t* const c = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 2, 3), 0);
    188
    1
      int i;
    189
    13
      for (i = 0; i < 2 * 2 * 3; i++12)
    190
    12
        a->data.f32[i] = i;
    191
    13
      for (i = 0; i < 2 * 2 * 3; i++12)
    192
    12
        b->data.f32[i] = i - 1;
    193
    1
      ccv_cnnp_model_t* const min = ccv_cnnp_min(0);
    194
    1
      const ccv_nnc_tensor_param_t a_params = CPU_TENSOR_NHWC(32F, 2, 2, 3);
    195
    1
      const ccv_nnc_tensor_param_t b_params = CPU_TENSOR_NHWC(32F, 2, 2, 3);
    196
    1
      ccv_cnnp_model_compile(min, TENSOR_PARAM_LIST(a_params, b_params), CMD_NOOP(), CMD_NOOP());
    197
    1
      ccv_cnnp_model_evaluate(min, (ccv_cnnp_evaluate_param_t){
    198
    1
        .requires_grad = 0,
    199
    1
        .is_test = 0,
    200
    1
        .disable_outgrad = CCV_CNNP_DISABLE_OUTGRAD_ALL
    201
    1
      }, TENSOR_LIST(a, b), TENSOR_LIST(c), 0, 0);
    202
    1
      REQUIRE_TENSOR_EQ(b, c, "c should be the minimal of the two");
    203
    1
      ccv_cnnp_model_free(min);
    204
    1
      ccv_nnc_tensor_free(a);
    205
    1
      ccv_nnc_tensor_free(b);
    206
    1
      ccv_nnc_tensor_free(c);
    207
    1
    }
    208
    209
    TEST_CASE("max of two tensors")
    210
    1
    {
    211
    1
      ccv_nnc_tensor_t* const a = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 2, 3), 0);
    212
    1
      ccv_nnc_tensor_t* const b = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 2, 3), 0);
    213
    1
      ccv_nnc_tensor_t* const c = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 2, 3), 0);
    214
    1
      int i;
    215
    13
      for (i = 0; i < 2 * 2 * 3; i++12)
    216
    12
        a->data.f32[i] = i;
    217
    13
      for (i = 0; i < 2 * 2 * 3; i++12)
    218
    12
        b->data.f32[i] = i + 1;
    219
    1
      ccv_nnc_cmd_exec(CMD_MAX_FORWARD(), ccv_nnc_no_hint, 0, TENSOR_LIST(a, b), TENSOR_LIST(c), 0);
    220
    1
      REQUIRE_TENSOR_EQ(b, c, "c should be the maximal of the two");
    221
    1
      ccv_nnc_tensor_free(a);
    222
    1
      ccv_nnc_tensor_free(b);
    223
    1
      ccv_nnc_tensor_free(c);
    224
    1
    }
    225
    226
    TEST_CASE("max of two tensor views")
    227
    1
    {
    228
    1
      ccv_nnc_tensor_t* const a = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 4, 4, 3), 0);
    229
    1
      ccv_nnc_tensor_t* const b = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 4, 4, 3), 0);
    230
    1
      ccv_nnc_tensor_t* const c = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 2, 3), 0);
    231
    1
      int i;
    232
    49
      for (i = 0; i < 4 * 4 * 3; i++48)
    233
    48
        a->data.f32[i] = i;
    234
    49
      for (i = 0; i < 4 * 4 * 3; i++48)
    235
    48
        b->data.f32[i] = i + 1;
    236
    1
      ccv_nnc_tensor_view_t* const av = ccv_nnc_tensor_view_new(a, CPU_TENSOR_NHWC(32F, 2, 2, 3), DIM_ALLOC(), DIM_ALLOC(4 * 3, 3, 1));
    237
    1
      ccv_nnc_tensor_view_t* const bv = ccv_nnc_tensor_view_new(b, CPU_TENSOR_NHWC(32F, 2, 2, 3), DIM_ALLOC(), DIM_ALLOC(4 * 3, 3, 1));
    238
    1
      ccv_nnc_cmd_exec(CMD_MAX_FORWARD(), ccv_nnc_no_hint, 0, TENSOR_LIST((ccv_nnc_tensor_t*)av, (ccv_nnc_tensor_t*)bv), TENSOR_LIST(c), 0);
    239
    1
      ccv_nnc_tensor_t* const bvt = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 2, 3), 0);
    240
    1
      ccv_nnc_cmd_exec(CMD_DATATYPE_CONVERSION_FORWARD(), ccv_nnc_no_hint, 0, TENSOR_LIST((ccv_nnc_tensor_t*)bv), TENSOR_LIST(bvt), 0);
    241
    1
      REQUIRE_TENSOR_EQ(bvt, c, "c should be the maximal of the two");
    242
    1
      ccv_nnc_tensor_free(a);
    243
    1
      ccv_nnc_tensor_free(b);
    244
    1
      ccv_nnc_tensor_free(c);
    245
    1
      ccv_nnc_tensor_free(bvt);
    246
    1
      ccv_nnc_tensor_view_free(av);
    247
    1
      ccv_nnc_tensor_view_free(bv);
    248
    1
    }
    249
    250
    TEST_CASE("max of two tensors backward")
    251
    1
    {
    252
    1
      ccv_nnc_tensor_t* const a = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 2, 3), 0);
    253
    1
      ccv_nnc_tensor_t* const b = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 2, 3), 0);
    254
    1
      ccv_nnc_tensor_t* const g = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 2, 3), 0);
    255
    1
      ccv_nnc_tensor_t* const ha = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 2, 3), 0);
    256
    1
      ccv_nnc_tensor_t* const hb = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 2, 3), 0);
    257
    1
      ccv_nnc_tensor_t* const hat = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 2, 3), 0);
    258
    1
      ccv_nnc_tensor_t* const hbt = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 2, 3), 0);
    259
    1
      int i;
    260
    13
      for (i = 0; i < 2 * 2 * 3; i++12)
    261
    12
        a->data.f32[i] = i;
    262
    13
      for (i = 0; i < 2 * 2 * 3; i++12)
    263
    12
        b->data.f32[i] = i < 3 ? i3 : i + 19;
    264
    13
      for (i = 0; i < 2 * 2 * 3; i++12)
    265
    12
        g->data.f32[i] = -1;
    266
    1
      ccv_nnc_cmd_exec(CMD_MAX_BACKWARD(), ccv_nnc_no_hint, 0, TENSOR_LIST(g, a, b), TENSOR_LIST(ha, hb), 0);
    267
    13
      for (i = 0; i < 2 * 2 * 3; i++12)
    268
    12
        hat->data.f32[i] = i < 3 ? -13 : 09;
    269
    13
      for (i = 0; i < 2 * 2 * 3; i++12)
    270
    12
        hbt->data.f32[i] = -1;
    271
    1
      REQUIRE_TENSOR_EQ(ha, hat, "ha should only carry gradients for the first 3");
    272
    1
      REQUIRE_TENSOR_EQ(hb, hbt, "hb should only carry all gradients");
    273
    1
      ccv_nnc_tensor_free(a);
    274
    1
      ccv_nnc_tensor_free(b);
    275
    1
      ccv_nnc_tensor_free(g);
    276
    1
      ccv_nnc_tensor_free(ha);
    277
    1
      ccv_nnc_tensor_free(hb);
    278
    1
      ccv_nnc_tensor_free(hat);
    279
    1
      ccv_nnc_tensor_free(hbt);
    280
    1
    }
    281
    282
    TEST_CASE("max of two tensors backward with null")
    283
    1
    {
    284
    1
      ccv_nnc_tensor_t* const a = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 2, 3), 0);
    285
    1
      ccv_nnc_tensor_t* const b = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 2, 3), 0);
    286
    1
      ccv_nnc_tensor_t* const ha = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 2, 3), 0);
    287
    1
      ccv_nnc_tensor_t* const hb = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 2, 3), 0);
    288
    1
      ccv_nnc_tensor_t* const hat = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 2, 3), 0);
    289
    1
      ccv_nnc_tensor_t* const hbt = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 2, 3), 0);
    290
    1
      int i;
    291
    13
      for (i = 0; i < 2 * 2 * 3; i++12)
    292
    12
        a->data.f32[i] = i;
    293
    13
      for (i = 0; i < 2 * 2 * 3; i++12)
    294
    12
        b->data.f32[i] = i < 3 ? i3 : i + 19;
    295
    1
      ccv_nnc_cmd_exec(CMD_MAX_BACKWARD(), ccv_nnc_no_hint, 0, TENSOR_LIST(0, a, b), TENSOR_LIST(ha, hb), 0);
    296
    13
      for (i = 0; i < 2 * 2 * 3; i++12)
    297
    12
        hat->data.f32[i] = i < 3 ? 13 : 09;
    298
    13
      for (i = 0; i < 2 * 2 * 3; i++12)
    299
    12
        hbt->data.f32[i] = 1;
    300
    1
      REQUIRE_TENSOR_EQ(ha, hat, "ha should only carry gradients for the first 3");
    301
    1
      REQUIRE_TENSOR_EQ(hb, hbt, "hb should only carry all gradients");
    302
    1
      ccv_nnc_tensor_free(a);
    303
    1
      ccv_nnc_tensor_free(b);
    304
    1
      ccv_nnc_tensor_free(ha);
    305
    1
      ccv_nnc_tensor_free(hb);
    306
    1
      ccv_nnc_tensor_free(hat);
    307
    1
      ccv_nnc_tensor_free(hbt);
    308
    1
    }
    309
    310
    TEST_CASE("max of two tensor views backward")
    311
    1
    {
    312
    1
      ccv_nnc_tensor_t* const a = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 4, 4, 3), 0);
    313
    1
      ccv_nnc_tensor_t* const b = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 4, 4, 3), 0);
    314
    1
      ccv_nnc_tensor_t* const g = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 2, 3), 0);
    315
    1
      ccv_nnc_tensor_t* const ha = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 2, 3), 0);
    316
    1
      ccv_nnc_tensor_t* const hb = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 2, 3), 0);
    317
    1
      ccv_nnc_tensor_t* const hat = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 2, 3), 0);
    318
    1
      ccv_nnc_tensor_t* const hbt = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 2, 3), 0);
    319
    1
      int i;
    320
    49
      for (i = 0; i < 4 * 4 * 3; i++48)
    321
    48
        a->data.f32[i] = i;
    322
    49
      for (i = 0; i < 4 * 4 * 3; i++48)
    323
    48
        b->data.f32[i] = i < 3 ? i3 : i + 145;
    324
    1
      ccv_nnc_tensor_view_t* const av = ccv_nnc_tensor_view_new(a, CPU_TENSOR_NHWC(32F, 2, 2, 3), DIM_ALLOC(), DIM_ALLOC(4 * 3, 3, 1));
    325
    1
      ccv_nnc_tensor_view_t* const bv = ccv_nnc_tensor_view_new(b, CPU_TENSOR_NHWC(32F, 2, 2, 3), DIM_ALLOC(), DIM_ALLOC(4 * 3, 3, 1));
    326
    13
      for (i = 0; i < 2 * 2 * 3; i++12)
    327
    12
        g->data.f32[i] = -1;
    328
    1
      ccv_nnc_cmd_exec(CMD_MAX_BACKWARD(), ccv_nnc_no_hint, 0, TENSOR_LIST(g, (ccv_nnc_tensor_t*)av, (ccv_nnc_tensor_t*)bv), TENSOR_LIST(ha, hb), 0);
    329
    13
      for (i = 0; i < 2 * 2 * 3; i++12)
    330
    12
        hat->data.f32[i] = i < 3 ? -13 : 09;
    331
    13
      for (i = 0; i < 2 * 2 * 3; i++12)
    332
    12
        hbt->data.f32[i] = -1;
    333
    1
      REQUIRE_TENSOR_EQ(ha, hat, "ha should only carry gradients for the first 3");
    334
    1
      REQUIRE_TENSOR_EQ(hb, hbt, "hb should only carry all gradients");
    335
    1
      ccv_nnc_tensor_free(a);
    336
    1
      ccv_nnc_tensor_free(b);
    337
    1
      ccv_nnc_tensor_view_free(av);
    338
    1
      ccv_nnc_tensor_view_free(bv);
    339
    1
      ccv_nnc_tensor_free(g);
    340
    1
      ccv_nnc_tensor_free(ha);
    341
    1
      ccv_nnc_tensor_free(hb);
    342
    1
      ccv_nnc_tensor_free(hat);
    343
    1
      ccv_nnc_tensor_free(hbt);
    344
    1
    }
    345
    346
    TEST_CASE("max of two tensor views backward with null")
    347
    1
    {
    348
    1
      ccv_nnc_tensor_t* const a = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 4, 4, 3), 0);
    349
    1
      ccv_nnc_tensor_t* const b = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 4, 4, 3), 0);
    350
    1
      ccv_nnc_tensor_t* const ha = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 2, 3), 0);
    351
    1
      ccv_nnc_tensor_t* const hb = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 2, 3), 0);
    352
    1
      ccv_nnc_tensor_t* const hat = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 2, 3), 0);
    353
    1
      ccv_nnc_tensor_t* const hbt = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 2, 3), 0);
    354
    1
      int i;
    355
    49
      for (i = 0; i < 4 * 4 * 3; i++48)
    356
    48
        a->data.f32[i] = i;
    357
    49
      for (i = 0; i < 4 * 4 * 3; i++48)
    358
    48
        b->data.f32[i] = i < 3 ? i3 : i + 145;
    359
    1
      ccv_nnc_tensor_view_t* const av = ccv_nnc_tensor_view_new(a, CPU_TENSOR_NHWC(32F, 2, 2, 3), DIM_ALLOC(), DIM_ALLOC(4 * 3, 3, 1));
    360
    1
      ccv_nnc_tensor_view_t* const bv = ccv_nnc_tensor_view_new(b, CPU_TENSOR_NHWC(32F, 2, 2, 3), DIM_ALLOC(), DIM_ALLOC(4 * 3, 3, 1));
    361
    1
      ccv_nnc_cmd_exec(CMD_MAX_BACKWARD(), ccv_nnc_no_hint, 0, TENSOR_LIST(0, (ccv_nnc_tensor_t*)av, (ccv_nnc_tensor_t*)bv), TENSOR_LIST(ha, hb), 0);
    362
    13
      for (i = 0; i < 2 * 2 * 3; i++12)
    363
    12
        hat->data.f32[i] = i < 3 ? 13 : 09;
    364
    13
      for (i = 0; i < 2 * 2 * 3; i++12)
    365
    12
        hbt->data.f32[i] = 1;
    366
    1
      REQUIRE_TENSOR_EQ(ha, hat, "ha should only carry gradients for the first 3");
    367
    1
      REQUIRE_TENSOR_EQ(hb, hbt, "hb should only carry all gradients");
    368
    1
      ccv_nnc_tensor_free(a);
    369
    1
      ccv_nnc_tensor_free(b);
    370
    1
      ccv_nnc_tensor_view_free(av);
    371
    1
      ccv_nnc_tensor_view_free(bv);
    372
    1
      ccv_nnc_tensor_free(ha);
    373
    1
      ccv_nnc_tensor_free(hb);
    374
    1
      ccv_nnc_tensor_free(hat);
    375
    1
      ccv_nnc_tensor_free(hbt);
    376
    1
    }
    377
    378
    TEST_CASE("max of two tensors with model")
    379
    1
    {
    380
    1
      ccv_nnc_tensor_t* const a = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 2, 3), 0);
    381
    1
      ccv_nnc_tensor_t* const b = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 2, 3), 0);
    382
    1
      ccv_nnc_tensor_t* const c = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 2, 3), 0);
    383
    1
      int i;
    384
    13
      for (i = 0; i < 2 * 2 * 3; i++12)
    385
    12
        a->data.f32[i] = i;
    386
    13
      for (i = 0; i < 2 * 2 * 3; i++12)
    387
    12
        b->data.f32[i] = i + 1;
    388
    1
      ccv_cnnp_model_t* const max = ccv_cnnp_max(0);
    389
    1
      const ccv_nnc_tensor_param_t a_params = CPU_TENSOR_NHWC(32F, 2, 2, 3);
    390
    1
      const ccv_nnc_tensor_param_t b_params = CPU_TENSOR_NHWC(32F, 2, 2, 3);
    391
    1
      ccv_cnnp_model_compile(max, TENSOR_PARAM_LIST(a_params, b_params), CMD_NOOP(), CMD_NOOP());
    392
    1
      ccv_cnnp_model_evaluate(max, (ccv_cnnp_evaluate_param_t){
    393
    1
        .requires_grad = 0,
    394
    1
        .is_test = 0,
    395
    1
        .disable_outgrad = CCV_CNNP_DISABLE_OUTGRAD_ALL
    396
    1
      }, TENSOR_LIST(a, b), TENSOR_LIST(c), 0, 0);
    397
    1
      REQUIRE_TENSOR_EQ(b, c, "c should be the maximal of the two");
    398
    1
      ccv_cnnp_model_free(max);
    399
    1
      ccv_nnc_tensor_free(a);
    400
    1
      ccv_nnc_tensor_free(b);
    401
    1
      ccv_nnc_tensor_free(c);
    402
    1
    }
    403
    404
    #include "case_main.h"