## 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/histogram.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("logarithmic histogram v.s. bins histogram")
    15
    1
    {
    16
    1
      ccv_nnc_tensor_t* const a = ccv_nnc_tensor_new(0, CPU_TENSOR_NCHW(32F, 3000, 2000), 0);
    17
    1
      ccv_nnc_tensor_t* const h = ccv_nnc_tensor_new(0, CPU_TENSOR_NCHW(32F, 774 * 2), 0);
    18
    1
      double v = 1e-12;
    19
    1
      int i;
    20
    775
      for (i = 0; v < 1e20; i++, v *= 1.1774)
    21
    774
      {
    22
    774
        h->data.f32[i + 774] = v;
    23
    774
        h->data.f32[774 - i - 1] = -v;
    24
    774
      }
    25
    1
      dsfmt_t dsfmt;
    26
    1
      dsfmt_init_gen_rand(&dsfmt, 1);
    27
    6.00M
      for (i = 0; i < 3000 * 2000; i++6.00M)
    28
    6.00M
        a->data.f32[i] = dsfmt_genrand_open_close(&dsfmt) * 2000 - 1000;
    29
    1
      a->data.f32[0] = NAN;
    30
    1
      a->data.f32[1] = -FLT_MAX;
    31
    1
      a->data.f32[2] = FLT_MAX;
    32
    1
      a->data.f32[3] = 0;
    33
    1
      a->data.f32[4] = 1e-20;
    34
    1
      a->data.f32[5] = -1e-20;
    35
    1
      a->data.f32[6] = 1e20 - 1e18;
    36
    1
      a->data.f32[7] = -1e20 + 1e18;
    37
    1
      ccv_nnc_tensor_t* const bl = ccv_nnc_tensor_new(0, CPU_TENSOR_NCHW(32S, 775 * 2), 0);
    38
    1
      ccv_nnc_tensor_t* const bb = ccv_nnc_tensor_new(0, CPU_TENSOR_NCHW(32S, 775 * 2), 0);
    39
    1
      ccv_nnc_tensor_t* const sl = ccv_nnc_tensor_new(0, CPU_TENSOR_NCHW(32F, 4), 0);
    40
    1
      ccv_nnc_tensor_t* const sb = ccv_nnc_tensor_new(0, CPU_TENSOR_NCHW(32F, 4), 0);
    41
    1
      ccv_nnc_cmd_exec(CMD_HISTOGRAM_LOG(), ccv_nnc_no_hint, 0, TENSOR_LIST(a), TENSOR_LIST(bl, sl), 0);
    42
    1
      ccv_nnc_cmd_exec(CMD_HISTOGRAM_BINS(), ccv_nnc_no_hint, 0, TENSOR_LIST(a, h), TENSOR_LIST(bb, sb), 0);
    43
    1.55k
      for (i = 0; i < 775 * 2; i++1.55k)
    44
    1.55k
      {
    45
    1.55k
        const int sum = bb->data.i32[i] + bl->data.i32[i];
    46
    1.55k
        const float tol = sum > 10 ? fabsf((float)(bl->data.i32[i] - bb->data.i32[i])) / (float)sum232 : abs(bl->data.i32[i] - bb->data.i32[i])1.31k;
    47
    1.55k
        REQUIRE(tol < 0.1, "should be smaller than tolerance for bl->data.i32[%d](%d), bb->data.i32[%d](%d)", i, bl->data.i32[i], i, bb->data.i32[i]);
    48
    1.55k
      }
    49
    1
      REQUIRE_EQ(sl->data.f32[0], -FLT_MAX, "should be equal to the minimal");
    50
    1
      REQUIRE_EQ(sl->data.f32[1], FLT_MAX, "should be equal to the maximal");
    51
    1
      REQUIRE(isnan(sl->data.f32[2]), "sum is nan");
    52
    1
      REQUIRE(isnan(sl->data.f32[3]), "sum of squares is nan");
    53
    1
      REQUIRE_EQ(bb->data.i32[0], 1, "should have 1 smaller than minimal value");
    54
    1
      REQUIRE_EQ(bb->data.i32[774 * 2], 1, "should have 1 larger than maximal value");
    55
    1
      REQUIRE_EQ(bb->data.i32[775 * 2 - 1], 1, "should have 1 nan");
    56
    1
      REQUIRE_EQ(bb->data.i32[774 * 2 - 1], 1, "should have 1 in the range (1e20 / 1.1, 1e20)");
    57
    1
      REQUIRE_EQ(bb->data.i32[1], 1, "should have 1 in the range (-1e20, -1e20 / 1.1)");
    58
    1
      REQUIRE_EQ(bb->data.i32[774], 3, "should have 3 in the range (-1e-12, 1e-12)");
    59
    1
      REQUIRE_EQ(bl->data.i32[0], 1, "should have 1 smaller than minimal value");
    60
    1
      REQUIRE_EQ(bl->data.i32[774 * 2], 1, "should have 1 larger than maximal value");
    61
    1
      REQUIRE_EQ(bl->data.i32[775 * 2 - 1], 1, "should have 1 nan");
    62
    1
      REQUIRE_EQ(bl->data.i32[774 * 2 - 1], 1, "should have 1 in the range (1e20 / 1.1, 1e20)");
    63
    1
      REQUIRE_EQ(bl->data.i32[1], 1, "should have 1 in the range (-1e20, -1e20 / 1.1)");
    64
    1
      REQUIRE_EQ(bl->data.i32[774], 3, "should have 3 in the range (-1e-12, 1e-12)");
    65
    1
      REQUIRE_TENSOR_EQ(sl, sb, "computed stats should be equal");
    66
    1
      ccv_nnc_tensor_free(a);
    67
    1
      ccv_nnc_tensor_free(h);
    68
    1
      ccv_nnc_tensor_free(bl);
    69
    1
      ccv_nnc_tensor_free(bb);
    70
    1
      ccv_nnc_tensor_free(sl);
    71
    1
      ccv_nnc_tensor_free(sb);
    72
    1
    }
    73
    74
    TEST_CASE("even histogram v.s. bins histogram")
    75
    1
    {
    76
    1
      ccv_nnc_tensor_t* const a = ccv_nnc_tensor_new(0, CPU_TENSOR_NCHW(32F, 3000, 2000), 0);
    77
    1
      ccv_nnc_tensor_t* const h = ccv_nnc_tensor_new(0, CPU_TENSOR_NCHW(32F, 201), 0);
    78
    1
      int i;
    79
    202
      for (i = 0; i < 201; i++201)
    80
    201
      {
    81
    201
        h->data.f32[i] = (i - 100) * 10;
    82
    201
      }
    83
    1
      dsfmt_t dsfmt;
    84
    1
      dsfmt_init_gen_rand(&dsfmt, 1);
    85
    6.00M
      for (i = 0; i < 3000 * 2000; i++6.00M)
    86
    6.00M
        a->data.f32[i] = dsfmt_genrand_open_close(&dsfmt) * 2000 - 1000;
    87
    1
      a->data.f32[0] = NAN;
    88
    1
      a->data.f32[1] = -FLT_MAX;
    89
    1
      a->data.f32[2] = FLT_MAX;
    90
    1
      a->data.f32[3] = 0;
    91
    1
      a->data.f32[4] = 1e-20;
    92
    1
      a->data.f32[5] = -1e-20;
    93
    1
      a->data.f32[6] = 1e20 - 1e18;
    94
    1
      a->data.f32[7] = -1e20 + 1e18;
    95
    1
      ccv_nnc_tensor_t* const bl = ccv_nnc_tensor_new(0, CPU_TENSOR_NCHW(32S, 203), 0);
    96
    1
      ccv_nnc_tensor_t* const bb = ccv_nnc_tensor_new(0, CPU_TENSOR_NCHW(32S, 203), 0);
    97
    1
      ccv_nnc_tensor_t* const sl = ccv_nnc_tensor_new(0, CPU_TENSOR_NCHW(32F, 4), 0);
    98
    1
      ccv_nnc_tensor_t* const sb = ccv_nnc_tensor_new(0, CPU_TENSOR_NCHW(32F, 4), 0);
    99
    1
      ccv_nnc_cmd_exec(CMD_HISTOGRAM_EVEN(200, -1000, 1000), ccv_nnc_no_hint, 0, TENSOR_LIST(a), TENSOR_LIST(bl, sl), 0);
    100
    1
      ccv_nnc_cmd_exec(CMD_HISTOGRAM_BINS(), ccv_nnc_no_hint, 0, TENSOR_LIST(a, h), TENSOR_LIST(bb, sb), 0);
    101
    204
      for (i = 0; i < 203; i++203)
    102
    203
      {
    103
    203
        const int diff = abs(bb->data.i32[i] - bl->data.i32[i]);
    104
    203
        REQUIRE(diff < 5, "differences should be smaller than 5 for bl->data.i32[%d](%d), bb->data.i32[%d](%d)", i, bl->data.i32[i], i, bb->data.i32[i]);
    105
    203
      }
    106
    1
      REQUIRE_EQ(sl->data.f32[0], -FLT_MAX, "should be equal to the minimal");
    107
    1
      REQUIRE_EQ(sl->data.f32[1], FLT_MAX, "should be equal to the maximal");
    108
    1
      REQUIRE(isnan(sl->data.f32[2]), "sum is nan");
    109
    1
      REQUIRE(isnan(sl->data.f32[3]), "sum of squares is nan");
    110
    1
      REQUIRE_EQ(bb->data.i32[0], 2, "should have 2 smaller than minimal value");
    111
    1
      REQUIRE_EQ(bb->data.i32[201], 2, "should have 2 larger than maximal value");
    112
    1
      REQUIRE_EQ(bb->data.i32[202], 1, "should have 1 nan");
    113
    1
      REQUIRE_EQ(bl->data.i32[0], 2, "should have 2 smaller than minimal value");
    114
    1
      REQUIRE_EQ(bl->data.i32[201], 2, "should have 2 larger than maximal value");
    115
    1
      REQUIRE_EQ(bl->data.i32[202], 1, "should have 1 nan");
    116
    1
      REQUIRE_TENSOR_EQ(sl, sb, "computed stats should be equal");
    117
    1
      ccv_nnc_tensor_free(a);
    118
    1
      ccv_nnc_tensor_free(h);
    119
    1
      ccv_nnc_tensor_free(bl);
    120
    1
      ccv_nnc_tensor_free(bb);
    121
    1
      ccv_nnc_tensor_free(sl);
    122
    1
      ccv_nnc_tensor_free(sb);
    123
    1
    }
    124
    125
    TEST_CASE("logarithmic histogram v.s. bins histogram on tensor view")
    126
    1
    {
    127
    1
      ccv_nnc_tensor_t* const a = ccv_nnc_tensor_new(0, CPU_TENSOR_NCHW(32F, 30, 100, 20, 100), 0);
    128
    1
      ccv_nnc_tensor_t* const h = ccv_nnc_tensor_new(0, CPU_TENSOR_NCHW(32F, 774 * 2), 0);
    129
    1
      double v = 1e-12;
    130
    1
      int i;
    131
    775
      for (i = 0; v < 1e20; i++, v *= 1.1774)
    132
    774
      {
    133
    774
        h->data.f32[i + 774] = v;
    134
    774
        h->data.f32[774 - i - 1] = -v;
    135
    774
      }
    136
    1
      dsfmt_t dsfmt;
    137
    1
      dsfmt_init_gen_rand(&dsfmt, 1);
    138
    6.00M
      for (i = 0; i < 3000 * 2000; i++6.00M)
    139
    6.00M
        a->data.f32[i] = dsfmt_genrand_open_close(&dsfmt) * 2000 - 1000;
    140
    1
      ccv_nnc_tensor_view_t* const av = ccv_nnc_tensor_view_new(a, CPU_TENSOR_NCHW(32F, 30, 20, 20, 40), DIM_ALLOC(0, 10, 0, 20), DIM_ALLOC(100 * 20 * 100, 20 * 100, 100, 1));
    141
      // All these skipped.
    142
    1
      a->data.f32[0] = NAN;
    143
    1
      a->data.f32[1] = -FLT_MAX;
    144
    1
      a->data.f32[2] = FLT_MAX;
    145
    1
      a->data.f32[3] = 0;
    146
    1
      a->data.f32[4] = 1e-20;
    147
    1
      a->data.f32[5] = -1e-20;
    148
    1
      a->data.f32[6] = 1e20 - 1e18;
    149
    1
      a->data.f32[7] = -1e20 + 1e18;
    150
    1
      ccv_nnc_tensor_t* const bl = ccv_nnc_tensor_new(0, CPU_TENSOR_NCHW(32S, 775 * 2), 0);
    151
    1
      ccv_nnc_tensor_t* const bb = ccv_nnc_tensor_new(0, CPU_TENSOR_NCHW(32S, 775 * 2), 0);
    152
    1
      ccv_nnc_tensor_t* const sl = ccv_nnc_tensor_new(0, CPU_TENSOR_NCHW(32F, 4), 0);
    153
    1
      ccv_nnc_tensor_t* const sb = ccv_nnc_tensor_new(0, CPU_TENSOR_NCHW(32F, 4), 0);
    154
    1
      ccv_nnc_cmd_exec(CMD_HISTOGRAM_LOG(), ccv_nnc_no_hint, 0, TENSOR_LIST((ccv_nnc_tensor_t*)av), TENSOR_LIST(bl, sl), 0);
    155
    1
      ccv_nnc_cmd_exec(CMD_HISTOGRAM_BINS(), ccv_nnc_no_hint, 0, TENSOR_LIST((ccv_nnc_tensor_t*)av, h), TENSOR_LIST(bb, sb), 0);
    156
    1.55k
      for (i = 0; i < 775 * 2; i++1.55k)
    157
    1.55k
      {
    158
    1.55k
        const int sum = bb->data.i32[i] + bl->data.i32[i];
    159
    1.55k
        const float tol = sum > 10 ? fabsf((float)(bl->data.i32[i] - bb->data.i32[i])) / (float)sum174 : abs(bl->data.i32[i] - bb->data.i32[i])1.37k;
    160
    1.55k
        REQUIRE(tol < 0.1, "should be smaller than tolerance for bl->data.i32[%d](%d), bb->data.i32[%d](%d)", i, bl->data.i32[i], i, bb->data.i32[i]);
    161
    1.55k
      }
    162
    1
      REQUIRE(sl->data.f32[0] < -990, "minimal should be close to the edge");
    163
    1
      REQUIRE(sl->data.f32[1] > 990, "maximal should be close to the edge");
    164
    1
      REQUIRE(sl->data.f32[2] / (float)ccv_nnc_tensor_count(av->info) < 1, "sum should be close to 0");
    165
    1
      REQUIRE_EQ_WITH_TOLERANCE(sl->data.f32[3] / (float)ccv_nnc_tensor_count(av->info), 2000 * 2000 / 12, 1e3, "sum of squares should be close to its expected value in uniform distribution");
    166
    1
      REQUIRE_EQ(bb->data.i32[0], 0, "should've skipped all manual numbers");
    167
    1
      REQUIRE_EQ(bb->data.i32[774 * 2], 0, "should've skipped all manual numbers");
    168
    1
      REQUIRE_EQ(bb->data.i32[775 * 2 - 1], 0, "should've skipped all manual numbers");
    169
    1
      REQUIRE_EQ(bb->data.i32[774 * 2 - 1], 0, "should've skipped all manual numbers");
    170
    1
      REQUIRE_EQ(bb->data.i32[1], 0, "should've skipped all manual numbers");
    171
    1
      REQUIRE_EQ(bb->data.i32[774], 0, "should've skipped all manual numbers");
    172
    1
      REQUIRE_EQ(bl->data.i32[0], 0, "should've skipped all manual numbers");
    173
    1
      REQUIRE_EQ(bl->data.i32[774 * 2], 0, "should've skipped all manual numbers");
    174
    1
      REQUIRE_EQ(bl->data.i32[775 * 2 - 1], 0, "should've skipped all manual numbers");
    175
    1
      REQUIRE_EQ(bl->data.i32[774 * 2 - 1], 0, "should've skipped all manual numbers");
    176
    1
      REQUIRE_EQ(bl->data.i32[1], 0, "should've skipped all manual numbers");
    177
    1
      REQUIRE_EQ(bl->data.i32[774], 0, "should've skipped all manual numbers");
    178
    1
      REQUIRE_TENSOR_EQ(sl, sb, "computed stats should be equal");
    179
    1
      ccv_nnc_tensor_free(a);
    180
    1
      ccv_nnc_tensor_view_free(av);
    181
    1
      ccv_nnc_tensor_free(h);
    182
    1
      ccv_nnc_tensor_free(bl);
    183
    1
      ccv_nnc_tensor_free(bb);
    184
    1
      ccv_nnc_tensor_free(sl);
    185
    1
      ccv_nnc_tensor_free(sb);
    186
    1
    }
    187
    188
    TEST_CASE("even histogram v.s. bins histogram on tensor view")
    189
    1
    {
    190
    1
      ccv_nnc_tensor_t* const a = ccv_nnc_tensor_new(0, CPU_TENSOR_NCHW(32F, 30, 100, 20, 100), 0);
    191
    1
      ccv_nnc_tensor_t* const h = ccv_nnc_tensor_new(0, CPU_TENSOR_NCHW(32F, 201), 0);
    192
    1
      int i;
    193
    202
      for (i = 0; i < 201; i++201)
    194
    201
      {
    195
    201
        h->data.f32[i] = (i - 100) * 10;
    196
    201
      }
    197
    1
      dsfmt_t dsfmt;
    198
    1
      dsfmt_init_gen_rand(&dsfmt, 1);
    199
    6.00M
      for (i = 0; i < 3000 * 2000; i++6.00M)
    200
    6.00M
        a->data.f32[i] = dsfmt_genrand_open_close(&dsfmt) * 2000 - 1000;
    201
    1
      ccv_nnc_tensor_view_t* const av = ccv_nnc_tensor_view_new(a, CPU_TENSOR_NCHW(32F, 30, 20, 20, 40), DIM_ALLOC(0, 10, 0, 20), DIM_ALLOC(100 * 20 * 100, 20 * 100, 100, 1));
    202
    1
      a->data.f32[0] = NAN;
    203
    1
      a->data.f32[1] = -FLT_MAX;
    204
    1
      a->data.f32[2] = FLT_MAX;
    205
    1
      a->data.f32[3] = 0;
    206
    1
      a->data.f32[4] = 1e-20;
    207
    1
      a->data.f32[5] = -1e-20;
    208
    1
      a->data.f32[6] = 1e20 - 1e18;
    209
    1
      a->data.f32[7] = -1e20 + 1e18;
    210
    1
      ccv_nnc_tensor_t* const bl = ccv_nnc_tensor_new(0, CPU_TENSOR_NCHW(32S, 203), 0);
    211
    1
      ccv_nnc_tensor_t* const bb = ccv_nnc_tensor_new(0, CPU_TENSOR_NCHW(32S, 203), 0);
    212
    1
      ccv_nnc_tensor_t* const sl = ccv_nnc_tensor_new(0, CPU_TENSOR_NCHW(32F, 4), 0);
    213
    1
      ccv_nnc_tensor_t* const sb = ccv_nnc_tensor_new(0, CPU_TENSOR_NCHW(32F, 4), 0);
    214
    1
      ccv_nnc_cmd_exec(CMD_HISTOGRAM_EVEN(200, -1000, 1000), ccv_nnc_no_hint, 0, TENSOR_LIST((ccv_nnc_tensor_t*)av), TENSOR_LIST(bl, sl), 0);
    215
    1
      ccv_nnc_cmd_exec(CMD_HISTOGRAM_BINS(), ccv_nnc_no_hint, 0, TENSOR_LIST((ccv_nnc_tensor_t*)av, h), TENSOR_LIST(bb, sb), 0);
    216
    204
      for (i = 0; i < 203; i++203)
    217
    203
      {
    218
    203
        const int diff = abs(bb->data.i32[i] - bl->data.i32[i]);
    219
    203
        REQUIRE(diff < 5, "differences should be smaller than 5 for bl->data.i32[%d](%d), bb->data.i32[%d](%d)", i, bl->data.i32[i], i, bb->data.i32[i]);
    220
    203
      }
    221
    1
      REQUIRE(sl->data.f32[0] < -990, "minimal should be close to the edge");
    222
    1
      REQUIRE(sl->data.f32[1] > 990, "maximal should be close to the edge");
    223
    1
      REQUIRE(sl->data.f32[2] / (float)ccv_nnc_tensor_count(av->info) < 1, "sum should be close to 0");
    224
    1
      REQUIRE_EQ_WITH_TOLERANCE(sl->data.f32[3] / (float)ccv_nnc_tensor_count(av->info), 2000 * 2000 / 12, 1e3, "sum of squares should be close to its expected value in uniform distribution");
    225
    1
      REQUIRE_EQ(bb->data.i32[0], 0, "should've skipped all manual numbers");
    226
    1
      REQUIRE_EQ(bb->data.i32[201], 0, "should've skipped all manual numbers");
    227
    1
      REQUIRE_EQ(bb->data.i32[202], 0, "should've skipped all manual numbers");
    228
    1
      REQUIRE_EQ(bl->data.i32[0], 0, "should've skipped all manual numbers");
    229
    1
      REQUIRE_EQ(bl->data.i32[201], 0, "should've skipped all manual numbers");
    230
    1
      REQUIRE_EQ(bl->data.i32[202], 0, "should've skipped all manual numbers");
    231
    1
      REQUIRE_TENSOR_EQ(sl, sb, "computed stats should be equal");
    232
    1
      ccv_nnc_tensor_free(a);
    233
    1
      ccv_nnc_tensor_view_free(av);
    234
    1
      ccv_nnc_tensor_free(h);
    235
    1
      ccv_nnc_tensor_free(bl);
    236
    1
      ccv_nnc_tensor_free(bb);
    237
    1
      ccv_nnc_tensor_free(sl);
    238
    1
      ccv_nnc_tensor_free(sb);
    239
    1
    }
    240
    241
    #include "case_main.h"