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

    Line
    Count
    Source
    1
    2
    #include "case.h"
    3
    #include "ccv_case.h"
    4
    #include "ccv_nnc_case.h"
    5
    #include <ccv.h>
    6
    #include <nnc/ccv_nnc.h>
    7
    #include <nnc/ccv_nnc_easy.h>
    8
    #include "3rdparty/dsfmt/dSFMT.h"
    9
    10
    TEST_SETUP()
    11
    {
    12
      ccv_nnc_init();
    13
    }
    14
    15
    static int while_4(ccv_nnc_tensor_t* const* const inputs, const int input_size, const void* const data)
    16
    5
    {
    17
    5
      return inputs[0]->data.i64[0] < 4;
    18
    5
    }
    19
    20
    TEST_CASE("while z = a * x + b (x <- z) compiled a and b binded to a tensor")
    21
    1
    {
    22
    1
      ccv_nnc_symbolic_graph_t* symbolic_graph = ccv_nnc_symbolic_graph_new();
    23
    1
      ccv_nnc_tensor_symbol_t x = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "x");
    24
    1
      ccv_nnc_symbolic_graph_t* while_graph = ccv_nnc_symbolic_graph_new();
    25
    1
      ccv_nnc_symbolic_graph_while(symbolic_graph, CCV_NNC_GRAPH_FORWARD, while_graph, "while");
    26
    1
      ccv_nnc_tensor_symbol_t a = ccv_nnc_tensor_symbol_new(while_graph, CPU_TENSOR_NHWC(32F, 1), "a");
    27
    1
      ccv_nnc_tensor_symbol_t b = ccv_nnc_tensor_symbol_new(while_graph, CPU_TENSOR_NHWC(32F, 1), "b");
    28
    1
      ccv_nnc_tensor_symbol_t y = ccv_nnc_tensor_symbol_new(while_graph, CPU_TENSOR_NHWC(32F, 1), "y");
    29
    1
      ccv_nnc_tensor_symbol_t z = ccv_nnc_tensor_symbol_new(while_graph, CPU_TENSOR_NHWC(32F, 1), "z");
    30
    1
      ccv_nnc_graph_exec_symbol_new(while_graph, CMD_EWPROD_FORWARD(), TENSOR_SYMBOL_LIST(a, x), TENSOR_SYMBOL_LIST(y), "prod");
    31
    1
      ccv_nnc_graph_exec_symbol_t sum = ccv_nnc_graph_exec_symbol_new(while_graph, CMD_EWSUM_FORWARD(), TENSOR_SYMBOL_LIST(y, b), TENSOR_SYMBOL_LIST(z), "sum");
    32
    1
      ccv_nnc_graph_exec_symbol_t noop = ccv_nnc_graph_exec_symbol_new(while_graph, CMD_NOOP(), 0, 0, 0, 0, "noop");
    33
    1
      ccv_nnc_graph_exec_symbol_concat(while_graph, sum, noop);
    34
    1
      ccv_nnc_graph_exec_symbol_autogen(while_graph, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS);
    35
    1
      ccv_nnc_symbolic_graph_set_while_expr(while_graph, while_4, 0, TENSOR_SYMBOL_LIST(ccv_nnc_tensor_symbol_for_while_count(while_graph)), GRAPH_EXEC_SYMBOL_LIST(noop));
    36
    1
      ccv_nnc_symbolic_graph_set_carry_overs(while_graph, TENSOR_SYMBOL_MAP(KV(z, x)));
    37
    1
      ccv_nnc_graph_exec_symbol_autogen(symbolic_graph, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS);
    38
    1
      SYMBOLIC_GRAPH_GEN(symbolic_graph, CCV_NNC_LONG_DOT_GRAPH);
    39
    1
      ccv_nnc_graph_t* graph = 0;
    40
    1
      ccv_nnc_tensor_arena_t* tensor_arena = 0;
    41
    1
      ccv_nnc_graph_exec_arena_t* graph_exec_arena = 0;
    42
    1
      ccv_nnc_tensor_t* a_tensor = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 1), 0);
    43
    1
      a_tensor->data.f32[0] = 0.3;
    44
    1
      ccv_nnc_tensor_t* b_tensor = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 1), 0);
    45
    1
      b_tensor->data.f32[0] = 1.1;
    46
    1
      ccv_nnc_symbolic_graph_compile(symbolic_graph, ccv_nnc_default_compile_params,
    47
    1
        TENSOR_BIND_MAP(KV(a, a_tensor), KV(b, b_tensor)), // Binding the tensors.
    48
    1
        0, 0,
    49
    1
        SYMBOLIC_GRAPH_SOURCES(symbolic_graph), SYMBOLIC_GRAPH_DESTINATIONS(symbolic_graph),
    50
    1
        &graph, &tensor_arena, &graph_exec_arena);
    51
    1
      GRAPH_GEN(graph, CCV_NNC_LONG_DOT_GRAPH);
    52
    1
      ccv_nnc_tensor_t* x_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, x);
    53
    1
      x_tensor->data.f32[0] = 0.88;
    54
    1
      ccv_nnc_tensor_t* z_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, z);
    55
    1
      ccv_nnc_graph_exec_t source = ccv_nnc_graph_exec_source(graph_exec_arena);
    56
    1
      ccv_nnc_graph_exec_t destination = ccv_nnc_graph_exec_destination(graph_exec_arena);
    57
    1
      ccv_nnc_graph_run(graph, 0, &source, 1, &destination, 1, 0, 0);
    58
    1
      int i;
    59
    1
      float z_val = 0.88;
    60
    6
      for (i = 0; i < 5; i++5)
    61
    5
        z_val = 0.3 * z_val + 1.1;
    62
    1
      REQUIRE_EQ_WITH_TOLERANCE(z_tensor->data.f32[0], z_val, 1e-6, "z should be equal to a * x + b (5)");
    63
    1
      ccv_nnc_tensor_free(a_tensor);
    64
    1
      ccv_nnc_tensor_free(b_tensor);
    65
    1
      ccv_nnc_symbolic_graph_free(symbolic_graph);
    66
    1
      ccv_nnc_graph_exec_arena_free(graph_exec_arena);
    67
    1
      ccv_nnc_tensor_arena_free(tensor_arena);
    68
    1
      ccv_nnc_graph_free(graph);
    69
    1
    }
    70
    71
    TEST_CASE("compile graph (a[1] + a[0]) * a where a is a binded tensor")
    72
    1
    {
    73
    1
      ccv_nnc_symbolic_graph_t* const symbolic_graph = ccv_nnc_symbolic_graph_new();
    74
    1
      const ccv_nnc_tensor_symbol_t a = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 2), "a");
    75
    1
      const ccv_nnc_tensor_symbol_t a0 = ccv_nnc_tensor_symbol_alias_new(symbolic_graph, a, ccv_nnc_no_ofs, DIM_ALLOC(1), CPU_TENSOR_NHWC(32F, 1), "a[0]");
    76
    1
      const ccv_nnc_tensor_symbol_t a1 = ccv_nnc_tensor_symbol_alias_new(symbolic_graph, a, DIM_ALLOC(1), DIM_ALLOC(1), CPU_TENSOR_NHWC(32F, 1), "a[1]");
    77
    1
      const ccv_nnc_tensor_symbol_t b = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "b");
    78
    1
      ccv_nnc_graph_exec_symbol_new(symbolic_graph, CMD_EWSUM_FORWARD(), TENSOR_SYMBOL_LIST(a0, a1), TENSOR_SYMBOL_LIST(b), "sum");
    79
    1
      const ccv_nnc_tensor_symbol_t c = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 2), "c");
    80
    1
      ccv_nnc_graph_exec_symbol_new(symbolic_graph, CMD_MUL_FORWARD(1), TENSOR_SYMBOL_LIST(b, a), TENSOR_SYMBOL_LIST(c), "mul");
    81
    1
      ccv_nnc_graph_exec_symbol_autogen(symbolic_graph, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS);
    82
    1
      SYMBOLIC_GRAPH_GEN(symbolic_graph, CCV_NNC_LONG_DOT_GRAPH);
    83
    1
      ccv_nnc_graph_t* graph = 0;
    84
    1
      ccv_nnc_tensor_arena_t* tensor_arena = 0;
    85
    1
      ccv_nnc_graph_exec_arena_t* graph_exec_arena = 0;
    86
    1
      ccv_nnc_symbolic_graph_compile(symbolic_graph, ccv_nnc_default_compile_params,
    87
    1
        0, 0,
    88
    1
        0, 0,
    89
    1
        SYMBOLIC_GRAPH_SOURCES(symbolic_graph), SYMBOLIC_GRAPH_DESTINATIONS(symbolic_graph),
    90
    1
        &graph, &tensor_arena, &graph_exec_arena);
    91
    1
      GRAPH_GEN(graph, CCV_NNC_LONG_DOT_GRAPH);
    92
    1
      ccv_nnc_tensor_t* const a_tensor = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2), 0);
    93
    1
      a_tensor->data.f32[0] = 1.1;
    94
    1
      a_tensor->data.f32[1] = 0.4;
    95
    1
      ccv_nnc_tensor_bind_symbol(tensor_arena, a, a_tensor);
    96
    1
      ccv_nnc_graph_run(graph, 0, TRAVERSE_FULL, 0, 0);
    97
    1
      ccv_nnc_tensor_t* const c_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, c);
    98
    1
      float ct[] = {
    99
    1
        (1.1 + 0.4) * 1.1,
    100
    1
        (1.1 + 0.4) * 0.4,
    101
    1
      };
    102
    1
      ccv_nnc_tensor_t ct_tensor = ccv_nnc_tensor(ct, CPU_TENSOR_NHWC(32F, 2), 0);
    103
    1
      REQUIRE_TENSOR_EQ(c_tensor, &ct_tensor, "c should be equal to [(1.1 + 0.4) * 11, (1.1 + 0.4) * 0.4]");
    104
    1
      ccv_nnc_tensor_free(a_tensor);
    105
    1
      ccv_nnc_symbolic_graph_free(symbolic_graph);
    106
    1
      ccv_nnc_graph_exec_arena_free(graph_exec_arena);
    107
    1
      ccv_nnc_tensor_arena_free(tensor_arena);
    108
    1
      ccv_nnc_graph_free(graph);
    109
    1
    }
    110
    111
    TEST_CASE("compile a graph with tensor bindings, verify tensor arena doesn't allocate these tensors")
    112
    1
    {
    113
    1
      ccv_nnc_symbolic_graph_t* const symbolic_graph = ccv_nnc_symbolic_graph_new();
    114
    1
      const ccv_nnc_tensor_symbol_t a = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1, 2), "a");
    115
    1
      const ccv_nnc_tensor_symbol_t b = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 2, 1), "b");
    116
    1
      const ccv_nnc_tensor_symbol_t c = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "c");
    117
    1
      ccv_nnc_graph_exec_symbol_new(symbolic_graph, CMD_GEMM_FORWARD(), TENSOR_SYMBOL_LIST(a, b), TENSOR_SYMBOL_LIST(c), "gemm");
    118
    1
      const ccv_nnc_tensor_symbol_t d = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "d");
    119
    1
      const ccv_nnc_tensor_symbol_t e = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "e");
    120
    1
      ccv_nnc_graph_exec_symbol_new(symbolic_graph, CMD_GEMM_FORWARD(), TENSOR_SYMBOL_LIST(c, d), TENSOR_SYMBOL_LIST(e), "mul");
    121
    1
      ccv_nnc_graph_exec_symbol_autogen(symbolic_graph, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS);
    122
    1
      SYMBOLIC_GRAPH_GEN(symbolic_graph, CCV_NNC_LONG_DOT_GRAPH);
    123
    1
      ccv_nnc_tensor_t* const a_tensor = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 1, 2), 0);
    124
    1
      ccv_nnc_tensor_t* const d_tensor = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 1), 0);
    125
    1
      ccv_nnc_tensor_t* const e_tensor = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 1), 0);
    126
    1
      ccv_nnc_graph_t* graph = 0;
    127
    1
      ccv_nnc_tensor_arena_t* tensor_arena = 0;
    128
    1
      ccv_nnc_graph_exec_arena_t* graph_exec_arena = 0;
    129
    1
      ccv_nnc_symbolic_graph_compile(symbolic_graph, ccv_nnc_default_compile_params,
    130
    1
        TENSOR_BIND_MAP(KV(a, a_tensor), KV(d, d_tensor), KV(e, e_tensor)),
    131
    1
        0, 0,
    132
    1
        SYMBOLIC_GRAPH_SOURCES(symbolic_graph), SYMBOLIC_GRAPH_DESTINATIONS(symbolic_graph),
    133
    1
        &graph, &tensor_arena, &graph_exec_arena);
    134
    1
      GRAPH_GEN(graph, CCV_NNC_LONG_DOT_GRAPH);
    135
    1
      const uint64_t size = ccv_nnc_tensor_arena_size(tensor_arena);
    136
    1
      const uint64_t tensor_size = ccv_nnc_tensor_data_size(CPU_TENSOR_NHWC(32F, 1, 2)) + ccv_nnc_tensor_data_size(CPU_TENSOR_NHWC(32F, 1));
    137
    1
      REQUIRE_EQ(size, tensor_size, "tensor arena should only allocate for two symbols");
    138
    1
      a_tensor->data.f32[0] = 1.1;
    139
    1
      a_tensor->data.f32[1] = 11003;
    140
    1
      ccv_nnc_tensor_t* const b_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, b);
    141
    1
      b_tensor->data.f32[0] = -1;
    142
    1
      b_tensor->data.f32[1] = -0.12;
    143
    1
      d_tensor->data.f32[0] = 0.5;
    144
    1
      ccv_nnc_graph_run(graph, 0, TRAVERSE_FULL, 0, 0);
    145
    1
      REQUIRE_EQ_WITH_TOLERANCE(e_tensor->data.f32[0], -(11003 * 0.12 + 1.1) * 0.5, 1e-2, "result should be equal");
    146
    1
      ccv_nnc_tensor_free(a_tensor);
    147
    1
      ccv_nnc_tensor_free(d_tensor);
    148
    1
      ccv_nnc_tensor_free(e_tensor);
    149
    1
      ccv_nnc_symbolic_graph_free(symbolic_graph);
    150
    1
      ccv_nnc_graph_exec_arena_free(graph_exec_arena);
    151
    1
      ccv_nnc_tensor_arena_free(tensor_arena);
    152
    1
      ccv_nnc_graph_free(graph);
    153
    1
    }
    154
    155
    TEST_CASE("compile a graph with tensor binded to alias")
    156
    1
    {
    157
    1
      ccv_nnc_symbolic_graph_t* const symbolic_graph = ccv_nnc_symbolic_graph_new();
    158
    1
      const ccv_nnc_tensor_symbol_t a = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "a");
    159
    1
      const ccv_nnc_tensor_symbol_t b = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "b");
    160
    1
      ccv_nnc_graph_exec_symbol_new(symbolic_graph, CMD_EWLOG_FORWARD(), TENSOR_SYMBOL_LIST(a), TENSOR_SYMBOL_LIST(b), "log");
    161
    1
      const ccv_nnc_tensor_symbol_t b_alias = ccv_nnc_tensor_symbol_alias_new(symbolic_graph, b, DIM_ALLOC(), DIM_ALLOC(1), CPU_TENSOR_NHWC(32F, 1), "alias");
    162
    1
      ccv_nnc_graph_exec_symbol_autogen(symbolic_graph, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS);
    163
    1
      SYMBOLIC_GRAPH_GEN(symbolic_graph, CCV_NNC_LONG_DOT_GRAPH);
    164
    1
      ccv_nnc_tensor_t* const a_tensor = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 1), 0);
    165
    1
      ccv_nnc_tensor_t* const b_tensor = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 1), 0);
    166
    1
      ccv_nnc_graph_t* graph = 0;
    167
    1
      ccv_nnc_tensor_arena_t* tensor_arena = 0;
    168
    1
      ccv_nnc_graph_exec_arena_t* graph_exec_arena = 0;
    169
    1
      ccv_nnc_symbolic_graph_compile(symbolic_graph, ccv_nnc_default_compile_params,
    170
    1
          TENSOR_BIND_MAP(KV(a, a_tensor), KV(b_alias, b_tensor)),
    171
    1
          0, 0,
    172
    1
          SYMBOLIC_GRAPH_SOURCES(symbolic_graph), SYMBOLIC_GRAPH_DESTINATIONS(symbolic_graph),
    173
    1
          &graph, &tensor_arena, &graph_exec_arena);
    174
    1
      b_tensor->data.f32[0] = 0;
    175
    1
      a_tensor->data.f32[0] = 2.34;
    176
    1
      ccv_nnc_graph_run(graph, 0, TRAVERSE_FULL, 0, 0);
    177
    1
      REQUIRE_EQ_WITH_TOLERANCE(b_tensor->data.f32[0], log(2.34), 1e-5, "result should be equal");
    178
    1
      ccv_nnc_tensor_free(a_tensor);
    179
    1
      ccv_nnc_tensor_free(b_tensor);
    180
    1
      ccv_nnc_symbolic_graph_free(symbolic_graph);
    181
    1
      ccv_nnc_graph_exec_arena_free(graph_exec_arena);
    182
    1
      ccv_nnc_tensor_arena_free(tensor_arena);
    183
    1
      ccv_nnc_graph_free(graph);
    184
    1
    }
    185
    186
    TEST_CASE("compile a graph with tensor alias and bind to the alias later")
    187
    1
    {
    188
    1
      ccv_nnc_symbolic_graph_t* const symbolic_graph = ccv_nnc_symbolic_graph_new();
    189
    1
      const ccv_nnc_tensor_symbol_t a = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "a");
    190
    1
      const ccv_nnc_tensor_symbol_t b = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "b");
    191
    1
      ccv_nnc_graph_exec_symbol_new(symbolic_graph, CMD_EWLOG_FORWARD(), TENSOR_SYMBOL_LIST(a), TENSOR_SYMBOL_LIST(b), "log");
    192
    1
      const ccv_nnc_tensor_symbol_t b_alias = ccv_nnc_tensor_symbol_alias_new(symbolic_graph, b, DIM_ALLOC(), DIM_ALLOC(1), CPU_TENSOR_NHWC(32F, 1), "alias");
    193
    1
      ccv_nnc_graph_exec_symbol_autogen(symbolic_graph, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS);
    194
    1
      SYMBOLIC_GRAPH_GEN(symbolic_graph, CCV_NNC_LONG_DOT_GRAPH);
    195
    1
      ccv_nnc_tensor_t* const a_tensor = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 1), 0);
    196
    1
      ccv_nnc_tensor_t* const b_tensor = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 1), 0);
    197
    1
      ccv_nnc_graph_t* graph = 0;
    198
    1
      ccv_nnc_tensor_arena_t* tensor_arena = 0;
    199
    1
      ccv_nnc_graph_exec_arena_t* graph_exec_arena = 0;
    200
    1
      ccv_nnc_symbolic_graph_compile(symbolic_graph, ccv_nnc_default_compile_params,
    201
    1
          TENSOR_BIND_MAP(KV(a, a_tensor)),
    202
    1
          0, 0,
    203
    1
          SYMBOLIC_GRAPH_SOURCES(symbolic_graph), SYMBOLIC_GRAPH_DESTINATIONS(symbolic_graph),
    204
    1
          &graph, &tensor_arena, &graph_exec_arena);
    205
    1
      b_tensor->data.f32[0] = 0;
    206
    1
      a_tensor->data.f32[0] = 2.34;
    207
    1
      ccv_nnc_tensor_bind_symbol(tensor_arena, b_alias, b_tensor);
    208
    1
      ccv_nnc_graph_run(graph, 0, TRAVERSE_FULL, 0, 0);
    209
    1
      REQUIRE_EQ_WITH_TOLERANCE(b_tensor->data.f32[0], log(2.34), 1e-5, "result should be equal");
    210
    1
      ccv_nnc_tensor_free(a_tensor);
    211
    1
      ccv_nnc_tensor_free(b_tensor);
    212
    1
      ccv_nnc_symbolic_graph_free(symbolic_graph);
    213
    1
      ccv_nnc_graph_exec_arena_free(graph_exec_arena);
    214
    1
      ccv_nnc_tensor_arena_free(tensor_arena);
    215
    1
      ccv_nnc_graph_free(graph);
    216
    1
    }
    217
    218
    #include "case_main.h"