## 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/simplify.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
    8
    TEST_SETUP()
    9
    {
    10
      ccv_nnc_init();
    11
    }
    12
    13
    TEST_CASE("simplify graph (x + y) * (x + y)")
    14
    1
    {
    15
    1
      ccv_nnc_symbolic_graph_t* const symbolic_graph = ccv_nnc_symbolic_graph_new();
    16
    1
      ccv_nnc_tensor_symbol_t x = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "x");
    17
    1
      ccv_nnc_tensor_symbol_t y = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "y");
    18
    1
      ccv_nnc_tensor_symbol_t z1 = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "z1");
    19
    1
      ccv_nnc_graph_exec_symbol_new(symbolic_graph, CMD_EWSUM_FORWARD(), TENSOR_SYMBOL_LIST(x, y), TENSOR_SYMBOL_LIST(z1), "sum1");
    20
    1
      ccv_nnc_tensor_symbol_t z2 = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "z2");
    21
    1
      ccv_nnc_graph_exec_symbol_new(symbolic_graph, CMD_EWSUM_FORWARD(), TENSOR_SYMBOL_LIST(x, y), TENSOR_SYMBOL_LIST(z2), "sum2");
    22
    1
      ccv_nnc_tensor_symbol_t z = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "z");
    23
    1
      ccv_nnc_graph_exec_symbol_new(symbolic_graph, CMD_EWPROD_FORWARD(), TENSOR_SYMBOL_LIST(z1, z2), TENSOR_SYMBOL_LIST(z), "prod");
    24
    1
      ccv_nnc_graph_exec_symbol_autogen(symbolic_graph, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS);
    25
    1
      ccv_nnc_symbolic_graph_simplify(symbolic_graph,
    26
    1
        SYMBOLIC_GRAPH_PASSES(CCV_NNC_SIMPLIFY_COMMON_SUBEXPRESSION_ELIMINATION,
    27
    1
          CCV_NNC_SIMPLIFY_DATA_TRANSFER_OPT,
    28
    1
          CCV_NNC_SIMPLIFY_OPS_FUSION,
    29
    1
          CCV_NNC_SIMPLIFY_GRAPH_PRUNING),
    30
    1
        0, 0,
    31
    1
        TENSOR_SYMBOL_LIST(z), SYMBOLIC_GRAPH_SOURCES(symbolic_graph), SYMBOLIC_GRAPH_DESTINATIONS(symbolic_graph));
    32
    1
      ccv_nnc_graph_exec_symbol_autogen(symbolic_graph, 0, 0, CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS);
    33
    1
      SYMBOLIC_GRAPH_GEN(symbolic_graph, CCV_NNC_LONG_DOT_GRAPH);
    34
    1
      ccv_nnc_graph_t* graph = 0;
    35
    1
      ccv_nnc_tensor_arena_t* tensor_arena = 0;
    36
    1
      ccv_nnc_graph_exec_arena_t* graph_exec_arena = 0;
    37
    1
      ccv_nnc_symbolic_graph_compile(symbolic_graph, ccv_nnc_default_compile_params, 0, 0, 0, 0, SYMBOLIC_GRAPH_SOURCES(symbolic_graph), SYMBOLIC_GRAPH_DESTINATIONS(symbolic_graph), &graph, &tensor_arena, &graph_exec_arena);
    38
    1
      GRAPH_GEN(graph, CCV_NNC_LONG_DOT_GRAPH);
    39
    1
      ccv_nnc_tensor_t* const x_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, x);
    40
    1
      x_tensor->data.f32[0] = 10;
    41
    1
      ccv_nnc_tensor_t* const y_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, y);
    42
    1
      y_tensor->data.f32[0] = 8;
    43
    1
      ccv_nnc_graph_run(graph, 0, TRAVERSE_FULL, 0, 0);
    44
    1
      ccv_nnc_tensor_t* const z_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, z);
    45
    1
      REQUIRE_EQ_WITH_TOLERANCE(z_tensor->data.f32[0], (10 + 8) * (10 + 8), 1e-5, "result should be equal");
    46
    1
      ccv_nnc_symbolic_graph_free(symbolic_graph);
    47
    1
      ccv_nnc_graph_free(graph);
    48
    1
      ccv_nnc_tensor_arena_free(tensor_arena);
    49
    1
      ccv_nnc_graph_exec_arena_free(graph_exec_arena);
    50
    1
    }
    51
    52
    TEST_CASE("simplify graph with data transfer")
    53
    1
    {
    54
    1
      ccv_nnc_symbolic_graph_t* const symbolic_graph = ccv_nnc_symbolic_graph_new();
    55
    1
      ccv_nnc_tensor_symbol_t x = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "x");
    56
    1
      ccv_nnc_tensor_symbol_t y = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "y");
    57
    1
      ccv_nnc_tensor_symbol_t a1 = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "a1");
    58
    1
      ccv_nnc_graph_exec_symbol_new(symbolic_graph, CMD_EWSUM_FORWARD(), TENSOR_SYMBOL_LIST(x, y), TENSOR_SYMBOL_LIST(a1), "sum1");
    59
    1
      ccv_nnc_tensor_symbol_t z = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 2), "z");
    60
    1
      ccv_nnc_tensor_symbol_t z1 = ccv_nnc_tensor_symbol_alias_new(symbolic_graph, z, DIM_ALLOC(0), DIM_ALLOC(1), CPU_TENSOR_NHWC(32F, 1), "z1");
    61
    1
      ccv_nnc_graph_exec_symbol_new(symbolic_graph, CMD_DATA_TRANSFER_FORWARD(), TENSOR_SYMBOL_LIST(a1), TENSOR_SYMBOL_LIST(z1), "dt1");
    62
    1
      ccv_nnc_tensor_symbol_t a2 = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "a2");
    63
    1
      ccv_nnc_graph_exec_symbol_new(symbolic_graph, CMD_DATA_TRANSFER_BACKWARD(), TENSOR_SYMBOL_LIST(x, y), TENSOR_SYMBOL_LIST(a2), "dt2");
    64
    1
      ccv_nnc_tensor_symbol_t z2 = ccv_nnc_tensor_symbol_alias_new(symbolic_graph, z, DIM_ALLOC(1), DIM_ALLOC(1), CPU_TENSOR_NHWC(32F, 1), "z2");
    65
    1
      ccv_nnc_graph_exec_symbol_new(symbolic_graph, CMD_DATA_TRANSFER_FORWARD(), TENSOR_SYMBOL_LIST(a2), TENSOR_SYMBOL_LIST(z2), "dt3");
    66
    1
      ccv_nnc_graph_exec_symbol_autogen(symbolic_graph, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS);
    67
    1
      ccv_nnc_symbolic_graph_simplify(symbolic_graph,
    68
    1
        SYMBOLIC_GRAPH_PASSES(CCV_NNC_SIMPLIFY_COMMON_SUBEXPRESSION_ELIMINATION,
    69
    1
          CCV_NNC_SIMPLIFY_DATA_TRANSFER_OPT,
    70
    1
          CCV_NNC_SIMPLIFY_OPS_FUSION,
    71
    1
          CCV_NNC_SIMPLIFY_GRAPH_PRUNING),
    72
    1
        0, 0,
    73
    1
        TENSOR_SYMBOL_LIST(z), SYMBOLIC_GRAPH_SOURCES(symbolic_graph), SYMBOLIC_GRAPH_DESTINATIONS(symbolic_graph));
    74
    1
      ccv_nnc_graph_exec_symbol_autogen(symbolic_graph, 0, 0, CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS);
    75
    1
      SYMBOLIC_GRAPH_GEN(symbolic_graph, CCV_NNC_LONG_DOT_GRAPH);
    76
    1
      ccv_nnc_graph_t* graph = 0;
    77
    1
      ccv_nnc_tensor_arena_t* tensor_arena = 0;
    78
    1
      ccv_nnc_graph_exec_arena_t* graph_exec_arena = 0;
    79
    1
      ccv_nnc_symbolic_graph_compile(symbolic_graph, ccv_nnc_default_compile_params, 0, 0, 0, 0, SYMBOLIC_GRAPH_SOURCES(symbolic_graph), SYMBOLIC_GRAPH_DESTINATIONS(symbolic_graph), &graph, &tensor_arena, &graph_exec_arena);
    80
    1
      GRAPH_GEN(graph, CCV_NNC_LONG_DOT_GRAPH);
    81
    1
      ccv_nnc_tensor_t* const z2_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, z2);
    82
    1
      z2_tensor->data.f32[0] = 1.2;
    83
    1
      ccv_nnc_tensor_t* const y_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, y);
    84
    1
      y_tensor->data.f32[0] = 8;
    85
    1
      ccv_nnc_graph_run(graph, 0, TRAVERSE_FULL, 0, 0);
    86
    1
      ccv_nnc_tensor_t* const z_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, z);
    87
    1
      REQUIRE_EQ_WITH_TOLERANCE(z_tensor->data.f32[0], 1.2 + 8, 1e-5, "result should be equal");
    88
    1
      REQUIRE_EQ_WITH_TOLERANCE(z_tensor->data.f32[1], 1.2, 1e-5, "result should be equal");
    89
    1
      ccv_nnc_symbolic_graph_free(symbolic_graph);
    90
    1
      ccv_nnc_graph_free(graph);
    91
    1
      ccv_nnc_tensor_arena_free(tensor_arena);
    92
    1
      ccv_nnc_graph_exec_arena_free(graph_exec_arena);
    93
    1
    }
    94
    95
    TEST_CASE("simplify graph with softmax + crossentropy")
    96
    1
    {
    97
    1
      ccv_nnc_symbolic_graph_t* const symbolic_graph = ccv_nnc_symbolic_graph_new();
    98
    1
      const ccv_nnc_tensor_symbol_t a = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 2, 3), "a");
    99
    1
      const ccv_nnc_tensor_symbol_t b0 = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 2, 3), "b0");
    100
    1
      ccv_nnc_graph_exec_symbol_new(symbolic_graph, CMD_SOFTMAX_FORWARD(), TENSOR_SYMBOL_LIST(a), TENSOR_SYMBOL_LIST(b0), "softmax");
    101
    1
      const ccv_nnc_tensor_symbol_t label = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32S, 2), "label");
    102
    1
      const ccv_nnc_tensor_symbol_t loss0 = ccv_nnc_tensor_symbol_new(symbolic_graph, ccv_nnc_tensor_auto, "loss0");
    103
    1
      ccv_nnc_graph_exec_symbol_new(symbolic_graph, CMD_CATEGORICAL_CROSSENTROPY_FORWARD(), TENSOR_SYMBOL_LIST(b0, label), TENSOR_SYMBOL_LIST(loss0), "categorical crossentropy");
    104
    1
      ccv_nnc_graph_exec_symbol_autogen(symbolic_graph, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS);
    105
    1
      ccv_nnc_symbolic_graph_backward(symbolic_graph, TENSOR_SYMBOL_LIST(loss0), TENSOR_SYMBOL_LIST(a), SYMBOLIC_GRAPH_SOURCES(symbolic_graph), SYMBOLIC_GRAPH_DESTINATIONS(symbolic_graph));
    106
    1
      const ccv_nnc_tensor_symbol_t dloss0 = ccv_nnc_tensor_symbol_for_backward(symbolic_graph, loss0);
    107
    1
      const ccv_nnc_tensor_symbol_t da0 = ccv_nnc_tensor_symbol_for_backward(symbolic_graph, a);
    108
    1
      ccv_nnc_graph_exec_symbol_new(symbolic_graph, CMD_SET_FORWARD(1), 0, 0, TENSOR_SYMBOL_LIST(dloss0), "set 1");
    109
    1
      ccv_nnc_graph_exec_symbol_autogen(symbolic_graph, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS);
    110
    1
      ccv_nnc_symbolic_graph_simplify(symbolic_graph,
    111
    1
        SYMBOLIC_GRAPH_PASSES(CCV_NNC_SIMPLIFY_COMMON_SUBEXPRESSION_ELIMINATION,
    112
    1
          CCV_NNC_SIMPLIFY_DATA_TRANSFER_OPT,
    113
    1
          CCV_NNC_SIMPLIFY_OPS_FUSION,
    114
    1
          CCV_NNC_SIMPLIFY_GRAPH_PRUNING),
    115
    1
        0, 0,
    116
    1
        TENSOR_SYMBOL_LIST(da0), SYMBOLIC_GRAPH_SOURCES(symbolic_graph), SYMBOLIC_GRAPH_DESTINATIONS(symbolic_graph));
    117
    1
      ccv_nnc_graph_exec_symbol_autogen(symbolic_graph, 0, 0, CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS);
    118
    1
      SYMBOLIC_GRAPH_GEN(symbolic_graph, CCV_NNC_LONG_DOT_GRAPH);
    119
    1
      ccv_nnc_graph_t* graph;
    120
    1
      ccv_nnc_tensor_arena_t* tensor_arena;
    121
    1
      ccv_nnc_graph_exec_arena_t* graph_exec_arena;
    122
    1
      ccv_nnc_symbolic_graph_compile(symbolic_graph, ccv_nnc_default_compile_params, 0, 0, 0, 0, SYMBOLIC_GRAPH_SOURCES(symbolic_graph), SYMBOLIC_GRAPH_DESTINATIONS(symbolic_graph), &graph, &tensor_arena, &graph_exec_arena);
    123
    1
      ccv_nnc_tensor_t* const a_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, a);
    124
    1
      ccv_nnc_tensor_t* const a0_tensor = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 3), 0);
    125
    1
      a0_tensor->data.f32[0] = a_tensor->data.f32[0] = 10;
    126
    1
      a0_tensor->data.f32[1] = a_tensor->data.f32[1] = -1;
    127
    1
      a0_tensor->data.f32[2] = a_tensor->data.f32[2] = -5;
    128
    1
      a0_tensor->data.f32[3] = a_tensor->data.f32[3] = 12;
    129
    1
      a0_tensor->data.f32[4] = a_tensor->data.f32[4] = 4;
    130
    1
      a0_tensor->data.f32[5] = a_tensor->data.f32[5] = 24;
    131
    1
      ccv_nnc_tensor_t* const label0_tensor = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32S, 2), 0);
    132
    1
      ccv_nnc_tensor_t* const label_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, label);
    133
    1
      label0_tensor->data.i32[0] = label_tensor->data.i32[0] = 2;
    134
    1
      label0_tensor->data.i32[1] = label_tensor->data.i32[1] = 1;
    135
    1
      ccv_nnc_graph_run(graph, 0, TRAVERSE_FULL, 0, 0);
    136
    1
      ccv_nnc_tensor_t* const loss0_tensor = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2), 0);
    137
    1
      ccv_nnc_tensor_t* const softmax_tensor = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 3), 0);
    138
    1
      ccv_nnc_cmd_exec(CMD_SOFTMAX_CROSSENTROPY_FORWARD(), ccv_nnc_no_hint, 0, TENSOR_LIST(a0_tensor, label0_tensor), TENSOR_LIST(loss0_tensor, softmax_tensor), 0);
    139
    1
      ccv_nnc_tensor_free(a0_tensor);
    140
    1
      ccv_nnc_tensor_free(loss0_tensor);
    141
    1
      ccv_nnc_tensor_t* const da1_tensor = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 3), 0);
    142
    1
      ccv_nnc_cmd_exec(CMD_SOFTMAX_CROSSENTROPY_BACKWARD(), ccv_nnc_no_hint, 0, TENSOR_LIST(0, 0, 0, label0_tensor, 0, softmax_tensor), TENSOR_LIST(da1_tensor), 0);
    143
    1
      ccv_nnc_tensor_t* const da0_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, da0);
    144
    1
      REQUIRE_TENSOR_EQ(da0_tensor, da1_tensor, "two tensors from combined op and separate ops should be equal");
    145
    1
      ccv_nnc_graph_free(graph);
    146
    1
      ccv_nnc_tensor_arena_free(tensor_arena);
    147
    1
      ccv_nnc_graph_exec_arena_free(graph_exec_arena);
    148
    1
      ccv_nnc_symbolic_graph_free(symbolic_graph);
    149
    1
      ccv_nnc_tensor_free(label0_tensor);
    150
    1
      ccv_nnc_tensor_free(softmax_tensor);
    151
    1
      ccv_nnc_tensor_free(da1_tensor);
    152
    1
    }
    153
    154
    static int custom_case_of(ccv_nnc_tensor_t* const* const inputs, const int input_size, const void* const data)
    155
    2
    {
    156
    2
      assert(input_size == 1);
    157
    2
      if (inputs[0]->data.f32[0] < 0)
    158
    1
        return 0;
    159
    1
      else if (inputs[0]->data.f32[0] < 2)
    160
    1
        return 1;
    161
    0
      return -1;
    162
    2
    }
    163
    164
    TEST_CASE("simplify graph with case..of")
    165
    1
    {
    166
    1
      ccv_nnc_symbolic_graph_t* const symbolic_graph = ccv_nnc_symbolic_graph_new();
    167
    1
      ccv_nnc_tensor_symbol_t x = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "x");
    168
    1
      ccv_nnc_tensor_symbol_t y = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "y");
    169
    1
      ccv_nnc_tensor_symbol_t sum1 = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), 0);
    170
    1
      ccv_nnc_graph_exec_symbol_new(symbolic_graph, CMD_EWSUM_FORWARD(), TENSOR_SYMBOL_LIST(x, y), TENSOR_SYMBOL_LIST(sum1), "sum1");
    171
    1
      ccv_nnc_tensor_symbol_t z = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "z");
    172
    1
      ccv_nnc_tensor_symbol_t prod1 = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), 0);
    173
    1
      ccv_nnc_graph_exec_symbol_new(symbolic_graph, CMD_EWPROD_FORWARD(), TENSOR_SYMBOL_LIST(sum1, z), TENSOR_SYMBOL_LIST(prod1), "prod1");
    174
    1
      ccv_nnc_tensor_symbol_t sum2 = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), 0);
    175
    1
      ccv_nnc_graph_exec_symbol_new(symbolic_graph, CMD_EWSUM_FORWARD(), TENSOR_SYMBOL_LIST(x, y), TENSOR_SYMBOL_LIST(sum2), "sum2");
    176
    1
      ccv_nnc_tensor_symbol_t prod2 = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), 0);
    177
    1
      ccv_nnc_graph_exec_symbol_new(symbolic_graph, CMD_EWPROD_FORWARD(), TENSOR_SYMBOL_LIST(sum2, z), TENSOR_SYMBOL_LIST(prod2), "prod2");
    178
    1
      ccv_nnc_tensor_symbol_t q = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), 0);
    179
    1
      ccv_nnc_graph_exec_symbol_t case_of = ccv_nnc_symbolic_graph_case_of_new(symbolic_graph, CCV_NNC_GRAPH_FORWARD, TENSOR_SYMBOL_LIST(x), TENSOR_SYMBOL_MAP(KV(prod1, q)), "case..of");
    180
    1
      ccv_nnc_symbolic_graph_t* const case_of_1 = ccv_nnc_symbolic_graph_new();
    181
    1
      ccv_nnc_tensor_symbol_t y1 = ccv_nnc_tensor_symbol_new(case_of_1, CPU_TENSOR_NHWC(32F, 1), "y1");
    182
    1
      ccv_nnc_symbolic_graph_set_case_of(symbolic_graph, case_of, case_of_1, 0, TENSOR_SYMBOL_MAP(KV(y1, q)));
    183
    1
      ccv_nnc_graph_exec_symbol_new(case_of_1, CMD_EWSUM_FORWARD(), TENSOR_SYMBOL_LIST(sum1, prod1, prod2), TENSOR_SYMBOL_LIST(y1), 0);
    184
    1
      ccv_nnc_graph_exec_symbol_autogen(case_of_1, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS);
    185
    1
      ccv_nnc_symbolic_graph_t* const case_of_2 = ccv_nnc_symbolic_graph_new();
    186
    1
      ccv_nnc_tensor_symbol_t y2 = ccv_nnc_tensor_symbol_new(case_of_2, CPU_TENSOR_NHWC(32F, 1), "y2");
    187
    1
      ccv_nnc_symbolic_graph_set_case_of(symbolic_graph, case_of, case_of_2, 1, TENSOR_SYMBOL_MAP(KV(y2, q)));
    188
    1
      ccv_nnc_graph_exec_symbol_new(case_of_2, CMD_EWPROD_FORWARD(), TENSOR_SYMBOL_LIST(prod2, sum2), TENSOR_SYMBOL_LIST(y2), 0);
    189
    1
      ccv_nnc_graph_exec_symbol_autogen(case_of_2, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS);
    190
    1
      ccv_nnc_symbolic_graph_set_case_of_expr(symbolic_graph, case_of, custom_case_of, 0);
    191
    1
      ccv_nnc_graph_exec_symbol_autogen(symbolic_graph, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS);
    192
    1
      ccv_nnc_symbolic_graph_simplify(symbolic_graph,
    193
    1
        SYMBOLIC_GRAPH_PASSES(CCV_NNC_SIMPLIFY_COMMON_SUBEXPRESSION_ELIMINATION,
    194
    1
          CCV_NNC_SIMPLIFY_DATA_TRANSFER_OPT,
    195
    1
          CCV_NNC_SIMPLIFY_OPS_FUSION,
    196
    1
          CCV_NNC_SIMPLIFY_GRAPH_PRUNING),
    197
    1
        0, 0,
    198
    1
        TENSOR_SYMBOL_LIST(q), SYMBOLIC_GRAPH_SOURCES(symbolic_graph), SYMBOLIC_GRAPH_DESTINATIONS(symbolic_graph));
    199
    1
      ccv_nnc_graph_exec_symbol_autogen(symbolic_graph, 0, 0, CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS);
    200
    1
      SYMBOLIC_GRAPH_GEN(symbolic_graph, CCV_NNC_LONG_DOT_GRAPH);
    201
    1
      ccv_nnc_graph_t* graph = 0;
    202
    1
      ccv_nnc_tensor_arena_t* tensor_arena = 0;
    203
    1
      ccv_nnc_graph_exec_arena_t* graph_exec_arena = 0;
    204
    1
      ccv_nnc_symbolic_graph_compile(symbolic_graph, ccv_nnc_default_compile_params, 0, 0, 0, 0, SYMBOLIC_GRAPH_SOURCES(symbolic_graph), SYMBOLIC_GRAPH_DESTINATIONS(symbolic_graph), &graph, &tensor_arena, &graph_exec_arena);
    205
    1
      GRAPH_GEN(graph, CCV_NNC_LONG_DOT_GRAPH);
    206
    1
      ccv_nnc_tensor_t* x_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, x);
    207
    1
      ccv_nnc_tensor_t* y_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, y);
    208
    1
      ccv_nnc_tensor_t* z_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, z);
    209
    1
      x_tensor->data.f32[0] = -2;
    210
    1
      y_tensor->data.f32[0] = 1.1;
    211
    1
      z_tensor->data.f32[0] = 2.2;
    212
    1
      ccv_nnc_graph_run(graph, 0, TRAVERSE_FULL, 0, 0);
    213
    1
      ccv_nnc_tensor_t* q_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, q);
    214
    1
      REQUIRE_EQ_WITH_TOLERANCE(q_tensor->data.f32[0], (-2 + 1.1) + (-2 + 1.1) * 2.2 + (-2 + 1.1) * 2.2, 1e-5, "q should be equal");
    215
    1
      x_tensor->data.f32[0] = 1.5;
    216
    1
      y_tensor->data.f32[0] = 1.1;
    217
    1
      z_tensor->data.f32[0] = 2.2;
    218
    1
      ccv_nnc_graph_run(graph, 0, TRAVERSE_FULL, 0, 0);
    219
    1
      q_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, q);
    220
    1
      REQUIRE_EQ_WITH_TOLERANCE(q_tensor->data.f32[0], (1.5 + 1.1) * (1.5 + 1.1) * 2.2, 1e-5, "q should be equal");
    221
    1
      ccv_nnc_symbolic_graph_free(symbolic_graph);
    222
    1
      ccv_nnc_graph_free(graph);
    223
    1
      ccv_nnc_tensor_arena_free(tensor_arena);
    224
    1
      ccv_nnc_graph_exec_arena_free(graph_exec_arena);
    225
    1
    }
    226
    227
    static int while_5(ccv_nnc_tensor_t* const* const inputs, const int input_size, const void* const data)
    228
    18
    {
    229
    18
      return inputs[0]->data.i64[0] < 5;
    230
    18
    }
    231
    232
    TEST_CASE("simplify graph with while, variant 1")
    233
    1
    {
    234
    1
      ccv_nnc_symbolic_graph_t* const symbolic_graph = ccv_nnc_symbolic_graph_new();
    235
    1
      ccv_nnc_symbolic_graph_t* const while_graph = ccv_nnc_symbolic_graph_new();
    236
    1
      ccv_nnc_tensor_symbol_t x = ccv_nnc_tensor_symbol_new(while_graph, CPU_TENSOR_NHWC(32F, 1), "x");
    237
    1
      ccv_nnc_tensor_symbol_t y = ccv_nnc_tensor_symbol_new(while_graph, CPU_TENSOR_NHWC(32F, 1), "y");
    238
    1
      ccv_nnc_tensor_symbol_t z1 = ccv_nnc_tensor_symbol_new(while_graph, CPU_TENSOR_NHWC(32F, 1), "z1");
    239
    1
      ccv_nnc_graph_exec_symbol_new(while_graph, CMD_EWPROD_FORWARD(), TENSOR_SYMBOL_LIST(x, y), TENSOR_SYMBOL_LIST(z1), 0);
    240
    1
      ccv_nnc_tensor_symbol_t p = ccv_nnc_tensor_symbol_new(while_graph, CPU_TENSOR_NHWC(32F, 1), "p");
    241
    1
      ccv_nnc_graph_exec_symbol_new(while_graph, CMD_EWPROD_FORWARD(), TENSOR_SYMBOL_LIST(x, y), TENSOR_SYMBOL_LIST(p), 0);
    242
    1
      ccv_nnc_tensor_symbol_t z2 = ccv_nnc_tensor_symbol_new(while_graph, CPU_TENSOR_NHWC(32F, 1), "z2");
    243
    1
      ccv_nnc_graph_exec_symbol_t sum = ccv_nnc_graph_exec_symbol_new(while_graph, CMD_EWSUM_FORWARD(), TENSOR_SYMBOL_LIST(z1, p), TENSOR_SYMBOL_LIST(z2), 0);
    244
    1
      ccv_nnc_graph_exec_symbol_autogen(while_graph, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS);
    245
    1
      ccv_nnc_symbolic_graph_while(symbolic_graph, CCV_NNC_GRAPH_FORWARD, while_graph, "while");
    246
    1
      ccv_nnc_symbolic_graph_set_while_expr(while_graph, while_5, 0, TENSOR_SYMBOL_LIST(ccv_nnc_tensor_symbol_for_while_count(while_graph)), GRAPH_EXEC_SYMBOL_LIST(sum));
    247
    1
      ccv_nnc_symbolic_graph_set_carry_overs(while_graph, TENSOR_SYMBOL_MAP(KV(z2, x)));
    248
    1
      ccv_nnc_tensor_symbol_t f = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "f");
    249
      // Use p here so the graph can be simplified by replacing p with z1.
    250
    1
      ccv_nnc_graph_exec_symbol_new(symbolic_graph, CMD_EWSUM_FORWARD(), TENSOR_SYMBOL_LIST(p, z2), TENSOR_SYMBOL_LIST(f), 0);
    251
    1
      ccv_nnc_graph_exec_symbol_autogen(symbolic_graph, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS);
    252
    1
      ccv_nnc_symbolic_graph_simplify(while_graph,
    253
    1
        SYMBOLIC_GRAPH_PASSES(CCV_NNC_SIMPLIFY_COMMON_SUBEXPRESSION_ELIMINATION,
    254
    1
          CCV_NNC_SIMPLIFY_DATA_TRANSFER_OPT,
    255
    1
          CCV_NNC_SIMPLIFY_OPS_FUSION,
    256
    1
          CCV_NNC_SIMPLIFY_GRAPH_PRUNING),
    257
    1
        0, 0,
    258
    1
        TENSOR_SYMBOL_LIST(z2), SYMBOLIC_GRAPH_SOURCES(while_graph), SYMBOLIC_GRAPH_DESTINATIONS(while_graph));
    259
    1
      ccv_nnc_graph_exec_symbol_autogen(symbolic_graph, 0, 0, CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS);
    260
    1
      SYMBOLIC_GRAPH_GEN(symbolic_graph, CCV_NNC_LONG_DOT_GRAPH);
    261
    1
      ccv_nnc_graph_t* graph = 0;
    262
    1
      ccv_nnc_tensor_arena_t* tensor_arena = 0;
    263
    1
      ccv_nnc_graph_exec_arena_t* graph_exec_arena = 0;
    264
    1
      ccv_nnc_symbolic_graph_compile(symbolic_graph, ccv_nnc_default_compile_params, 0, 0, 0, 0, SYMBOLIC_GRAPH_SOURCES(symbolic_graph), SYMBOLIC_GRAPH_DESTINATIONS(symbolic_graph), &graph, &tensor_arena, &graph_exec_arena);
    265
    1
      GRAPH_GEN(graph, CCV_NNC_LONG_DOT_GRAPH);
    266
    1
      ccv_nnc_tensor_t* const x_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, x);
    267
    1
      x_tensor->data.f32[0] = 0.5;
    268
    1
      ccv_nnc_tensor_t* const y_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, y);
    269
    1
      y_tensor->data.f32[0] = 1.1;
    270
    1
      ccv_nnc_graph_run(graph, 0, TRAVERSE_FULL, 0, 0);
    271
    1
      ccv_nnc_tensor_t* const f_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, f);
    272
    1
      int i;
    273
    1
      float r = 0.5;
    274
    7
      for (i = 0; i < 6; i++6)
    275
    6
        r = r * 1.1 * 2;
    276
    1
      REQUIRE_EQ_WITH_TOLERANCE(f_tensor->data.f32[0], r + r * 0.5, 1e-5, "should be equal");
    277
    1
      ccv_nnc_symbolic_graph_free(symbolic_graph);
    278
    1
      ccv_nnc_graph_free(graph);
    279
    1
      ccv_nnc_tensor_arena_free(tensor_arena);
    280
    1
      ccv_nnc_graph_exec_arena_free(graph_exec_arena);
    281
    1
    }
    282
    283
    TEST_CASE("simplify graph with while, variant 2")
    284
    1
    {
    285
    1
      ccv_nnc_symbolic_graph_t* const symbolic_graph = ccv_nnc_symbolic_graph_new();
    286
    1
      ccv_nnc_symbolic_graph_t* const while_graph = ccv_nnc_symbolic_graph_new();
    287
    1
      ccv_nnc_tensor_symbol_t x = ccv_nnc_tensor_symbol_new(while_graph, CPU_TENSOR_NHWC(32F, 1), "x");
    288
    1
      ccv_nnc_tensor_symbol_t y = ccv_nnc_tensor_symbol_new(while_graph, CPU_TENSOR_NHWC(32F, 1), "y");
    289
    1
      ccv_nnc_tensor_symbol_t z1 = ccv_nnc_tensor_symbol_new(while_graph, CPU_TENSOR_NHWC(32F, 1), "z1");
    290
    1
      ccv_nnc_graph_exec_symbol_new(while_graph, CMD_EWPROD_FORWARD(), TENSOR_SYMBOL_LIST(x, y), TENSOR_SYMBOL_LIST(z1), 0);
    291
    1
      ccv_nnc_tensor_symbol_t p = ccv_nnc_tensor_symbol_new(while_graph, CPU_TENSOR_NHWC(32F, 1), "p");
    292
    1
      ccv_nnc_graph_exec_symbol_new(while_graph, CMD_EWPROD_FORWARD(), TENSOR_SYMBOL_LIST(x, y), TENSOR_SYMBOL_LIST(p), 0);
    293
    1
      ccv_nnc_tensor_symbol_t z2 = ccv_nnc_tensor_symbol_new(while_graph, CPU_TENSOR_NHWC(32F, 1), "z2");
    294
    1
      ccv_nnc_graph_exec_symbol_t sum = ccv_nnc_graph_exec_symbol_new(while_graph, CMD_EWSUM_FORWARD(), TENSOR_SYMBOL_LIST(z1, p), TENSOR_SYMBOL_LIST(z2), 0);
    295
    1
      ccv_nnc_graph_exec_symbol_autogen(while_graph, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS);
    296
    1
      ccv_nnc_symbolic_graph_while(symbolic_graph, CCV_NNC_GRAPH_FORWARD, while_graph, "while");
    297
    1
      ccv_nnc_symbolic_graph_set_while_expr(while_graph, while_5, 0, TENSOR_SYMBOL_LIST(ccv_nnc_tensor_symbol_for_while_count(while_graph)), GRAPH_EXEC_SYMBOL_LIST(sum));
    298
    1
      ccv_nnc_symbolic_graph_set_carry_overs(while_graph, TENSOR_SYMBOL_MAP(KV(z2, x)));
    299
    1
      ccv_nnc_tensor_symbol_t f = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "f");
    300
      // Use z1 here so the branch produces p will be eliminated.
    301
    1
      ccv_nnc_graph_exec_symbol_new(symbolic_graph, CMD_EWSUM_FORWARD(), TENSOR_SYMBOL_LIST(z1, z2), TENSOR_SYMBOL_LIST(f), 0);
    302
    1
      ccv_nnc_graph_exec_symbol_autogen(symbolic_graph, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS);
    303
    1
      ccv_nnc_symbolic_graph_simplify(while_graph,
    304
    1
        SYMBOLIC_GRAPH_PASSES(CCV_NNC_SIMPLIFY_COMMON_SUBEXPRESSION_ELIMINATION,
    305
    1
          CCV_NNC_SIMPLIFY_DATA_TRANSFER_OPT,
    306
    1
          CCV_NNC_SIMPLIFY_OPS_FUSION,
    307
    1
          CCV_NNC_SIMPLIFY_GRAPH_PRUNING),
    308
    1
        0, 0,
    309
    1
        TENSOR_SYMBOL_LIST(z2), SYMBOLIC_GRAPH_SOURCES(while_graph), SYMBOLIC_GRAPH_DESTINATIONS(while_graph));
    310
    1
      ccv_nnc_graph_exec_symbol_autogen(symbolic_graph, 0, 0, CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS);
    311
    1
      SYMBOLIC_GRAPH_GEN(symbolic_graph, CCV_NNC_LONG_DOT_GRAPH);
    312
    1
      ccv_nnc_graph_t* graph = 0;
    313
    1
      ccv_nnc_tensor_arena_t* tensor_arena = 0;
    314
    1
      ccv_nnc_graph_exec_arena_t* graph_exec_arena = 0;
    315
    1
      ccv_nnc_symbolic_graph_compile(symbolic_graph, ccv_nnc_default_compile_params, 0, 0, 0, 0, SYMBOLIC_GRAPH_SOURCES(symbolic_graph), SYMBOLIC_GRAPH_DESTINATIONS(symbolic_graph), &graph, &tensor_arena, &graph_exec_arena);
    316
    1
      GRAPH_GEN(graph, CCV_NNC_LONG_DOT_GRAPH);
    317
    1
      ccv_nnc_tensor_t* const x_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, x);
    318
    1
      x_tensor->data.f32[0] = 0.5;
    319
    1
      ccv_nnc_tensor_t* const y_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, y);
    320
    1
      y_tensor->data.f32[0] = 1.1;
    321
    1
      ccv_nnc_graph_run(graph, 0, TRAVERSE_FULL, 0, 0);
    322
    1
      ccv_nnc_tensor_t* const f_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, f);
    323
    1
      int i;
    324
    1
      float r = 0.5;
    325
    7
      for (i = 0; i < 6; i++6)
    326
    6
        r = r * 1.1 * 2;
    327
    1
      REQUIRE_EQ_WITH_TOLERANCE(f_tensor->data.f32[0], r + r * 0.5, 1e-5, "should be equal");
    328
    1
      ccv_nnc_symbolic_graph_free(symbolic_graph);
    329
    1
      ccv_nnc_graph_free(graph);
    330
    1
      ccv_nnc_tensor_arena_free(tensor_arena);
    331
    1
      ccv_nnc_graph_exec_arena_free(graph_exec_arena);
    332
    1
    }
    333
    334
    TEST_CASE("simplify graph with while, variant 3")
    335
    1
    {
    336
    1
      ccv_nnc_symbolic_graph_t* const symbolic_graph = ccv_nnc_symbolic_graph_new();
    337
    1
      ccv_nnc_symbolic_graph_t* const while_graph = ccv_nnc_symbolic_graph_new();
    338
    1
      ccv_nnc_tensor_symbol_t x = ccv_nnc_tensor_symbol_new(while_graph, CPU_TENSOR_NHWC(32F, 1), "x");
    339
    1
      ccv_nnc_tensor_symbol_t y = ccv_nnc_tensor_symbol_new(while_graph, CPU_TENSOR_NHWC(32F, 1), "y");
    340
    1
      ccv_nnc_tensor_symbol_t z1 = ccv_nnc_tensor_symbol_new(while_graph, CPU_TENSOR_NHWC(32F, 1), "z1");
    341
    1
      ccv_nnc_graph_exec_symbol_new(while_graph, CMD_EWPROD_FORWARD(), TENSOR_SYMBOL_LIST(x, y), TENSOR_SYMBOL_LIST(z1), 0);
    342
    1
      ccv_nnc_tensor_symbol_t p = ccv_nnc_tensor_symbol_new(while_graph, CPU_TENSOR_NHWC(32F, 1), "p");
    343
    1
      ccv_nnc_graph_exec_symbol_new(while_graph, CMD_EWPROD_FORWARD(), TENSOR_SYMBOL_LIST(x, y), TENSOR_SYMBOL_LIST(p), 0);
    344
    1
      ccv_nnc_tensor_symbol_t z2 = ccv_nnc_tensor_symbol_new(while_graph, CPU_TENSOR_NHWC(32F, 1), "z2");
    345
    1
      ccv_nnc_graph_exec_symbol_t sum = ccv_nnc_graph_exec_symbol_new(while_graph, CMD_EWSUM_FORWARD(), TENSOR_SYMBOL_LIST(z1, p), TENSOR_SYMBOL_LIST(z2), 0);
    346
    1
      ccv_nnc_graph_exec_symbol_autogen(while_graph, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS);
    347
    1
      ccv_nnc_symbolic_graph_while(symbolic_graph, CCV_NNC_GRAPH_FORWARD, while_graph, "while");
    348
    1
      ccv_nnc_symbolic_graph_set_while_expr(while_graph, while_5, 0, TENSOR_SYMBOL_LIST(ccv_nnc_tensor_symbol_for_while_count(while_graph)), GRAPH_EXEC_SYMBOL_LIST(sum));
    349
    1
      ccv_nnc_symbolic_graph_set_carry_overs(while_graph, TENSOR_SYMBOL_MAP(KV(z2, x)));
    350
    1
      ccv_nnc_tensor_symbol_t f = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "f");
    351
      // Use both z1 and p so this graph cannot be simplified (due to current implementation limitation).
    352
    1
      ccv_nnc_graph_exec_symbol_new(symbolic_graph, CMD_EWSUM_FORWARD(), TENSOR_SYMBOL_LIST(z1, p, z2), TENSOR_SYMBOL_LIST(f), 0);
    353
    1
      ccv_nnc_graph_exec_symbol_autogen(symbolic_graph, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS);
    354
    1
      ccv_nnc_symbolic_graph_simplify(while_graph,
    355
    1
        SYMBOLIC_GRAPH_PASSES(CCV_NNC_SIMPLIFY_COMMON_SUBEXPRESSION_ELIMINATION,
    356
    1
          CCV_NNC_SIMPLIFY_DATA_TRANSFER_OPT,
    357
    1
          CCV_NNC_SIMPLIFY_OPS_FUSION,
    358
    1
          CCV_NNC_SIMPLIFY_GRAPH_PRUNING),
    359
    1
        0, 0,
    360
    1
        TENSOR_SYMBOL_LIST(z2), SYMBOLIC_GRAPH_SOURCES(while_graph), SYMBOLIC_GRAPH_DESTINATIONS(while_graph));
    361
    1
      ccv_nnc_graph_exec_symbol_autogen(symbolic_graph, 0, 0, CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS);
    362
    1
      SYMBOLIC_GRAPH_GEN(symbolic_graph, CCV_NNC_LONG_DOT_GRAPH);
    363
    1
      ccv_nnc_graph_t* graph = 0;
    364
    1
      ccv_nnc_tensor_arena_t* tensor_arena = 0;
    365
    1
      ccv_nnc_graph_exec_arena_t* graph_exec_arena = 0;
    366
    1
      ccv_nnc_symbolic_graph_compile(symbolic_graph, ccv_nnc_default_compile_params, 0, 0, 0, 0, SYMBOLIC_GRAPH_SOURCES(symbolic_graph), SYMBOLIC_GRAPH_DESTINATIONS(symbolic_graph), &graph, &tensor_arena, &graph_exec_arena);
    367
    1
      GRAPH_GEN(graph, CCV_NNC_LONG_DOT_GRAPH);
    368
    1
      ccv_nnc_tensor_t* const x_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, x);
    369
    1
      x_tensor->data.f32[0] = 0.5;
    370
    1
      ccv_nnc_tensor_t* const y_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, y);
    371
    1
      y_tensor->data.f32[0] = 1.1;
    372
    1
      ccv_nnc_graph_run(graph, 0, TRAVERSE_FULL, 0, 0);
    373
    1
      ccv_nnc_tensor_t* const f_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, f);
    374
    1
      int i;
    375
    1
      float r = 0.5;
    376
    7
      for (i = 0; i < 6; i++6)
    377
    6
        r = r * 1.1 * 2;
    378
    1
      REQUIRE_EQ_WITH_TOLERANCE(f_tensor->data.f32[0], r + r * 0.5 + r * 0.5, 1e-5, "should be equal");
    379
    1
      ccv_nnc_symbolic_graph_free(symbolic_graph);
    380
    1
      ccv_nnc_graph_free(graph);
    381
    1
      ccv_nnc_tensor_arena_free(tensor_arena);
    382
    1
      ccv_nnc_graph_exec_arena_free(graph_exec_arena);
    383
    1
    }
    384
    385
    #include "case_main.h"