Coverage Report

Created: 2024-08-19 11:27

/home/liu/actions-runner/_work/ccv/ccv/test/unit/nnc/case_of.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
static int piecewise_case_of(ccv_nnc_tensor_t* const* const inputs, const int input_size, const void* const data)
15
25
{
16
25
  assert(input_size == 1);
17
25
  if (inputs[0]->data.f32[0] < 0)
18
3
    return 0;
19
22
  else if (inputs[0]->data.f32[0] < 1)
20
9
    return -1; // Pass through because the computation is essentially x * 1
21
13
  else if (inputs[0]->data.f32[0] < 2)
22
8
    return 1;
23
5
  else if (inputs[0]->data.f32[0] > 1000)
24
1
    return 3;
25
4
  else
26
4
    return 2;
27
25
}
28
29
static int while_4(ccv_nnc_tensor_t* const* const inputs, const int input_size, const void* const data)
30
15
{
31
15
  return inputs[0]->data.i64[0] < 4;
32
15
}
33
34
TEST_CASE("graph for a piece-wise linear function")
35
1
{
36
1
  ccv_nnc_graph_t* const graph = ccv_nnc_graph_new();
37
1
  ccv_nnc_tensor_t* x = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 1), 0);
38
1
  ccv_nnc_graph_exec_t case_of = ccv_nnc_graph_case_of_new(graph, CCV_NNC_GRAPH_FORWARD, TENSOR_LIST(x), 0, 0);
39
1
  ccv_nnc_graph_set_case_of_expr(graph, case_of, piecewise_case_of, 0, 0);
40
1
  ccv_nnc_graph_t* graph_0 = ccv_nnc_graph_new();
41
1
  ccv_nnc_graph_exec_t set_0 = ccv_nnc_graph_exec_new(graph_0, CMD_SET_FORWARD(0), ccv_nnc_no_hint, 0, 0, TENSOR_LIST(x));
42
1
  ccv_nnc_graph_set_sources(graph_0, GRAPH_EXEC_LIST(set_0));
43
1
  ccv_nnc_graph_set_destinations(graph_0, GRAPH_EXEC_LIST(set_0));
44
1
  ccv_nnc_graph_set_case_of(graph, case_of, graph_0, 0);
45
1
  ccv_nnc_graph_t* graph_1 = ccv_nnc_graph_new();
46
1
  ccv_nnc_tensor_t* p1 = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 1), 0);
47
1
  p1->data.f32[0] = 0.5;
48
1
  ccv_nnc_tensor_t* s1 = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 1), 0);
49
1
  s1->data.f32[0] = 0.5;
50
1
  ccv_nnc_graph_exec_t prod_1 = ccv_nnc_graph_exec_new(graph_1, CMD_EWPROD_FORWARD(), ccv_nnc_no_hint, TENSOR_LIST(x, p1), TENSOR_LIST(x));
51
1
  ccv_nnc_graph_exec_t sum_1 = ccv_nnc_graph_exec_new(graph_1, CMD_EWSUM_FORWARD(), ccv_nnc_no_hint, TENSOR_LIST(x, s1), TENSOR_LIST(x));
52
1
  ccv_nnc_graph_exec_concat(graph_1, prod_1, sum_1);
53
1
  ccv_nnc_graph_set_sources(graph_1, GRAPH_EXEC_LIST(prod_1));
54
1
  ccv_nnc_graph_set_destinations(graph_1, GRAPH_EXEC_LIST(sum_1));
55
1
  ccv_nnc_graph_set_case_of(graph, case_of, graph_1, 1);
56
1
  ccv_nnc_graph_t* graph_2 = ccv_nnc_graph_new();
57
1
  ccv_nnc_graph_exec_t set_2 = ccv_nnc_graph_exec_new(graph_2, CMD_SET_FORWARD(1.5), ccv_nnc_no_hint, 0, 0, TENSOR_LIST(x));
58
1
  ccv_nnc_graph_set_sources(graph_2, GRAPH_EXEC_LIST(set_2));
59
1
  ccv_nnc_graph_set_destinations(graph_2, GRAPH_EXEC_LIST(set_2));
60
1
  ccv_nnc_graph_set_case_of(graph, case_of, graph_2, 2);
61
1
  GRAPH_GEN(graph, CCV_NNC_LONG_DOT_GRAPH);
62
1
  x->data.f32[0] = -1;
63
1
  ccv_nnc_graph_run(graph, 0, GRAPH_EXEC_LIST(case_of), GRAPH_EXEC_LIST(case_of), 0, 0);
64
1
  REQUIRE_EQ_WITH_TOLERANCE(x->data.f32[0], 0, 1e-5, "in negative region should equal to 0");
65
1
  x->data.f32[0] = 0.76;
66
1
  ccv_nnc_graph_run(graph, 0, GRAPH_EXEC_LIST(case_of), GRAPH_EXEC_LIST(case_of), 0, 0);
67
1
  REQUIRE_EQ_WITH_TOLERANCE(x->data.f32[0], 0.76, 1e-5, "y = x in (0, 1)");
68
1
  x->data.f32[0] = 1.226;
69
1
  ccv_nnc_graph_run(graph, 0, GRAPH_EXEC_LIST(case_of), GRAPH_EXEC_LIST(case_of), 0, 0);
70
1
  REQUIRE_EQ_WITH_TOLERANCE(x->data.f32[0], (1.226 - 1) * 0.5 + 1, 1e-5, "y = (x - 1) * 0.5 + 1 in (1, 2)");
71
1
  x->data.f32[0] = 2.1;
72
1
  ccv_nnc_graph_run(graph, 0, GRAPH_EXEC_LIST(case_of), GRAPH_EXEC_LIST(case_of), 0, 0);
73
1
  REQUIRE_EQ_WITH_TOLERANCE(x->data.f32[0], 1.5, 1e-5, "y = 1.5 if x > 2");
74
1
  ccv_nnc_tensor_free(x);
75
1
  ccv_nnc_tensor_free(p1);
76
1
  ccv_nnc_tensor_free(s1);
77
1
  ccv_nnc_graph_free(graph);
78
1
}
79
80
TEST_CASE("symbolic graph for piece-wise function")
81
1
{
82
1
  ccv_nnc_symbolic_graph_t* const symbolic_graph = ccv_nnc_symbolic_graph_new();
83
1
  ccv_nnc_tensor_symbol_t x = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "x");
84
1
  ccv_nnc_tensor_symbol_t y = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "y");
85
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(x, y)), "piece-wise linear");
86
1
  ccv_nnc_symbolic_graph_set_case_of_expr(symbolic_graph, case_of, piecewise_case_of, 0);
87
1
  ccv_nnc_symbolic_graph_t* const symbolic_graph_0 = ccv_nnc_symbolic_graph_new();
88
1
  ccv_nnc_tensor_symbol_t y0 = ccv_nnc_tensor_symbol_new(symbolic_graph_0, CPU_TENSOR_NHWC(32F, 1), "y0");
89
1
  ccv_nnc_symbolic_graph_set_case_of(symbolic_graph, case_of, symbolic_graph_0, 0, TENSOR_SYMBOL_MAP(KV(y0, y)));
90
1
  ccv_nnc_graph_exec_symbol_new(symbolic_graph_0, CMD_SET_FORWARD(0), 0, 0, TENSOR_SYMBOL_LIST(y0), "set");
91
1
  ccv_nnc_graph_exec_symbol_autogen(symbolic_graph_0, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS);
92
1
  ccv_nnc_symbolic_graph_t* const symbolic_graph_1 = ccv_nnc_symbolic_graph_new();
93
1
  ccv_nnc_tensor_symbol_t y1 = ccv_nnc_tensor_symbol_new(symbolic_graph_1, CPU_TENSOR_NHWC(32F, 1), "y1");
94
1
  ccv_nnc_symbolic_graph_set_case_of(symbolic_graph, case_of, symbolic_graph_1, 1, TENSOR_SYMBOL_MAP(KV(y1, y)));
95
1
  ccv_nnc_tensor_symbol_t s1 = ccv_nnc_tensor_symbol_new(symbolic_graph_1, CPU_TENSOR_NHWC(32F, 1), "s");
96
1
  ccv_nnc_tensor_symbol_t z1 = ccv_nnc_tensor_symbol_new(symbolic_graph_1, CPU_TENSOR_NHWC(32F, 1), "z1");
97
1
  ccv_nnc_tensor_symbol_t p1 = ccv_nnc_tensor_symbol_new(symbolic_graph_1, CPU_TENSOR_NHWC(32F, 1), "p");
98
1
  ccv_nnc_graph_exec_symbol_new(symbolic_graph_1, CMD_EWPROD_FORWARD(), TENSOR_SYMBOL_LIST(x, s1), TENSOR_SYMBOL_LIST(z1), "prod");
99
1
  ccv_nnc_graph_exec_symbol_new(symbolic_graph_1, CMD_EWSUM_FORWARD(), TENSOR_SYMBOL_LIST(z1, p1), TENSOR_SYMBOL_LIST(y1), "sum");
100
1
  ccv_nnc_graph_exec_symbol_autogen(symbolic_graph_1, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS);
101
1
  ccv_nnc_symbolic_graph_t* const symbolic_graph_2 = ccv_nnc_symbolic_graph_new();
102
1
  ccv_nnc_tensor_symbol_t y2 = ccv_nnc_tensor_symbol_new(symbolic_graph_2, CPU_TENSOR_NHWC(32F, 1), "y2");
103
1
  ccv_nnc_symbolic_graph_set_case_of(symbolic_graph, case_of, symbolic_graph_2, 2, TENSOR_SYMBOL_MAP(KV(y2, y)));
104
1
  ccv_nnc_graph_exec_symbol_new(symbolic_graph_2, CMD_SET_FORWARD(1.5), 0, 0, TENSOR_SYMBOL_LIST(y2), "set");
105
1
  ccv_nnc_graph_exec_symbol_autogen(symbolic_graph_2, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS);
106
1
  SYMBOLIC_GRAPH_GEN(symbolic_graph, CCV_NNC_LONG_DOT_GRAPH);
107
1
  ccv_nnc_graph_t* graph = 0;
108
1
  ccv_nnc_tensor_arena_t* tensor_arena = 0;
109
1
  ccv_nnc_graph_exec_arena_t* graph_exec_arena = 0;
110
1
  ccv_nnc_symbolic_graph_compile(symbolic_graph, ccv_nnc_default_compile_params, 0, 0, 0, 0, &case_of, 1, &case_of, 1, &graph, &tensor_arena, &graph_exec_arena);
111
1
  GRAPH_GEN(graph, CCV_NNC_LONG_DOT_GRAPH);
112
1
  ccv_nnc_tensor_t* x_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, x);
113
1
  ccv_nnc_tensor_t* y_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, y);
114
1
  ccv_nnc_tensor_t* s1_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, s1);
115
1
  ccv_nnc_tensor_t* p1_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, p1);
116
1
  s1_tensor->data.f32[0] = 0.5;
117
1
  p1_tensor->data.f32[0] = 0.5;
118
1
  x_tensor->data.f32[0] = -1;
119
1
  ccv_nnc_graph_run(graph, 0, TRAVERSE_FULL, 0, 0);
120
1
  REQUIRE_EQ_WITH_TOLERANCE(y_tensor->data.f32[0], 0, 1e-5, "in negative region should equal to 0");
121
1
  x_tensor->data.f32[0] = 0.76;
122
1
  ccv_nnc_graph_run(graph, 0, TRAVERSE_FULL, 0, 0);
123
1
  REQUIRE_EQ_WITH_TOLERANCE(y_tensor->data.f32[0], 0.76, 1e-5, "y = x in (0, 1)");
124
1
  s1_tensor->data.f32[0] = 0.5;
125
1
  p1_tensor->data.f32[0] = 0.5;
126
1
  x_tensor->data.f32[0] = 1.226;
127
1
  ccv_nnc_graph_run(graph, 0, TRAVERSE_FULL, 0, 0);
128
1
  REQUIRE_EQ_WITH_TOLERANCE(y_tensor->data.f32[0], (1.226 - 1) * 0.5 + 1, 1e-5, "y = (x - 1) * 0.5 + 1 in (1, 2)");
129
1
  s1_tensor->data.f32[0] = 0.5;
130
1
  p1_tensor->data.f32[0] = 0.5;
131
1
  x_tensor->data.f32[0] = 2.1;
132
1
  ccv_nnc_graph_run(graph, 0, TRAVERSE_FULL, 0, 0);
133
1
  REQUIRE_EQ_WITH_TOLERANCE(y_tensor->data.f32[0], 1.5, 1e-5, "y = 1.5 if x > 2");
134
1
  ccv_nnc_symbolic_graph_free(symbolic_graph);
135
1
  ccv_nnc_graph_exec_arena_free(graph_exec_arena);
136
1
  ccv_nnc_tensor_arena_free(tensor_arena);
137
1
  ccv_nnc_graph_free(graph);
138
1
}
139
140
TEST_CASE("symbolic graph case..of when reuse intermediate tensors")
141
1
{
142
1
  ccv_nnc_symbolic_graph_t* const symbolic_graph = ccv_nnc_symbolic_graph_new();
143
1
  ccv_nnc_tensor_symbol_t x = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 2), "x");
144
1
  ccv_nnc_tensor_symbol_t y = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 2), "y");
145
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(x, y)), "piece-wise linear vector");
146
1
  ccv_nnc_symbolic_graph_set_case_of_expr(symbolic_graph, case_of, piecewise_case_of, 0);
147
1
  ccv_nnc_symbolic_graph_t* const symbolic_graph_0 = ccv_nnc_symbolic_graph_new();
148
1
  ccv_nnc_tensor_symbol_t z0 = ccv_nnc_tensor_symbol_new(symbolic_graph_0, CPU_TENSOR_NHWC(32F, 2), "z0");
149
1
  ccv_nnc_tensor_symbol_t u0 = ccv_nnc_tensor_symbol_new(symbolic_graph_0, CPU_TENSOR_NHWC(32F, 2, 2), "u0");
150
1
  ccv_nnc_tensor_symbol_t w0 = ccv_nnc_tensor_symbol_new(symbolic_graph_0, CPU_TENSOR_NHWC(32F, 2, 2), "w0");
151
1
  ccv_nnc_tensor_symbol_t b0 = ccv_nnc_tensor_symbol_new(symbolic_graph_0, CPU_TENSOR_NHWC(32F, 2), "b0");
152
1
  ccv_nnc_tensor_symbol_t c0 = ccv_nnc_tensor_symbol_new(symbolic_graph_0, CPU_TENSOR_NHWC(32F, 2), "c0");
153
1
  ccv_nnc_tensor_symbol_t y0 = ccv_nnc_tensor_symbol_new(symbolic_graph_0, CPU_TENSOR_NHWC(32F, 2), "y0");
154
1
  ccv_nnc_symbolic_graph_set_case_of(symbolic_graph, case_of, symbolic_graph_0, 0, TENSOR_SYMBOL_MAP(KV(y0, y)));
155
1
  ccv_nnc_graph_exec_symbol_new(symbolic_graph_0, CMD_GEMM_FORWARD(NO_TRANSPOSE, TRANSPOSE(0, 1)), TENSOR_SYMBOL_LIST(x, u0, b0), TENSOR_SYMBOL_LIST(z0), "mmu");
156
1
  ccv_nnc_graph_exec_symbol_new(symbolic_graph_0, CMD_GEMM_FORWARD(NO_TRANSPOSE, TRANSPOSE(0, 1)), TENSOR_SYMBOL_LIST(z0, w0, c0), TENSOR_SYMBOL_LIST(y0), "mmw");
157
1
  ccv_nnc_graph_exec_symbol_autogen(symbolic_graph_0, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS);
158
1
  ccv_nnc_symbolic_graph_t* const symbolic_graph_1 = ccv_nnc_symbolic_graph_new();
159
1
  ccv_nnc_tensor_symbol_t z1 = ccv_nnc_tensor_symbol_new(symbolic_graph_1, CPU_TENSOR_NHWC(32F, 2), "z1");
160
1
  ccv_nnc_tensor_symbol_t u1 = ccv_nnc_tensor_symbol_new(symbolic_graph_1, CPU_TENSOR_NHWC(32F, 2, 2), "u1");
161
1
  ccv_nnc_tensor_symbol_t w1 = ccv_nnc_tensor_symbol_new(symbolic_graph_1, CPU_TENSOR_NHWC(32F, 2, 2), "w1");
162
1
  ccv_nnc_tensor_symbol_t b1 = ccv_nnc_tensor_symbol_new(symbolic_graph_1, CPU_TENSOR_NHWC(32F, 2), "b1");
163
1
  ccv_nnc_tensor_symbol_t c1 = ccv_nnc_tensor_symbol_new(symbolic_graph_1, CPU_TENSOR_NHWC(32F, 2), "c1");
164
1
  ccv_nnc_tensor_symbol_t y1 = ccv_nnc_tensor_symbol_new(symbolic_graph_1, CPU_TENSOR_NHWC(32F, 2), "y1");
165
1
  ccv_nnc_symbolic_graph_set_case_of(symbolic_graph, case_of, symbolic_graph_1, 1, TENSOR_SYMBOL_MAP(KV(y1, y)));
166
1
  ccv_nnc_graph_exec_symbol_new(symbolic_graph_1, CMD_GEMM_FORWARD(NO_TRANSPOSE, TRANSPOSE(0, 1)), TENSOR_SYMBOL_LIST(x, u1, b1), TENSOR_SYMBOL_LIST(z1), "mmu1");
167
1
  ccv_nnc_graph_exec_symbol_new(symbolic_graph_1, CMD_GEMM_FORWARD(NO_TRANSPOSE, TRANSPOSE(0, 1)), TENSOR_SYMBOL_LIST(z1, w1, c1), TENSOR_SYMBOL_LIST(y1), "mmw1");
168
1
  ccv_nnc_graph_exec_symbol_autogen(symbolic_graph_1, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS);
169
1
  SYMBOLIC_GRAPH_GEN(symbolic_graph, CCV_NNC_LONG_DOT_GRAPH);
170
1
  ccv_nnc_graph_t* graph = 0;
171
1
  ccv_nnc_tensor_arena_t* tensor_arena = 0;
172
1
  ccv_nnc_graph_exec_arena_t* graph_exec_arena = 0;
173
1
  ccv_nnc_symbolic_graph_compile(symbolic_graph, ccv_nnc_default_compile_params, 0, 0, 0, 0, &case_of, 1, &case_of, 1, &graph, &tensor_arena, &graph_exec_arena);
174
1
  GRAPH_GEN(graph, CCV_NNC_LONG_DOT_GRAPH);
175
1
  ccv_nnc_tensor_t* z0_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, z0);
176
1
  ccv_nnc_tensor_t* z1_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, z1);
177
1
  REQUIRE(z0_tensor->data.f32 == z1_tensor->data.f32, "z0 and z1 should be allocated to the same location");
178
1
  ccv_nnc_symbolic_graph_free(symbolic_graph);
179
1
  ccv_nnc_graph_exec_arena_free(graph_exec_arena);
180
1
  ccv_nnc_tensor_arena_free(tensor_arena);
181
1
  ccv_nnc_graph_free(graph);
182
1
}
183
184
TEST_CASE("symbolic graph case..of with 4 branches")
185
1
{
186
1
  ccv_nnc_symbolic_graph_t* const symbolic_graph = ccv_nnc_symbolic_graph_new();
187
1
  ccv_nnc_tensor_symbol_t x = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "x");
188
1
  ccv_nnc_tensor_symbol_t y = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "y");
189
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(x, y)), "4 branches");
190
1
  ccv_nnc_symbolic_graph_set_case_of_expr(symbolic_graph, case_of, piecewise_case_of, 0);
191
1
  ccv_nnc_symbolic_graph_t* const case_of_0 = ccv_nnc_symbolic_graph_new();
192
1
  ccv_nnc_tensor_symbol_t b = ccv_nnc_tensor_symbol_new(case_of_0, CPU_TENSOR_NHWC(32F, 1), "b0");
193
1
  ccv_nnc_symbolic_graph_set_case_of(symbolic_graph, case_of, case_of_0, 0, TENSOR_SYMBOL_MAP(KV(b, y)));
194
1
  ccv_nnc_graph_exec_symbol_new(case_of_0, CMD_EWEXP_FORWARD(), TENSOR_SYMBOL_LIST(x), TENSOR_SYMBOL_LIST(b), "exp");
195
1
  ccv_nnc_graph_exec_symbol_autogen(case_of_0, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS);
196
1
  ccv_nnc_symbolic_graph_t* const case_of_1 = ccv_nnc_symbolic_graph_new();
197
1
  b = ccv_nnc_tensor_symbol_new(case_of_1, CPU_TENSOR_NHWC(32F, 1), "b1");
198
1
  ccv_nnc_symbolic_graph_set_case_of(symbolic_graph, case_of, case_of_1, 1, TENSOR_SYMBOL_MAP(KV(b, y)));
199
1
  ccv_nnc_graph_exec_symbol_new(case_of_1, CMD_EWLOG_FORWARD(), TENSOR_SYMBOL_LIST(x), TENSOR_SYMBOL_LIST(b), "log");
200
1
  ccv_nnc_graph_exec_symbol_autogen(case_of_1, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS);
201
1
  ccv_nnc_symbolic_graph_t* const case_of_2 = ccv_nnc_symbolic_graph_new();
202
1
  b = ccv_nnc_tensor_symbol_new(case_of_2, CPU_TENSOR_NHWC(32F, 1), "b2");
203
1
  ccv_nnc_symbolic_graph_set_case_of(symbolic_graph, case_of, case_of_2, 2, TENSOR_SYMBOL_MAP(KV(b, y)));
204
1
  ccv_nnc_graph_exec_symbol_new(case_of_2, CMD_EWDIV_FORWARD(), TENSOR_SYMBOL_LIST(NO_TENSOR_SYMBOL, x), TENSOR_SYMBOL_LIST(b), "1/b");
205
1
  ccv_nnc_graph_exec_symbol_autogen(case_of_2, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS);
206
1
  ccv_nnc_symbolic_graph_t* const case_of_3 = ccv_nnc_symbolic_graph_new();
207
1
  b = ccv_nnc_tensor_symbol_new(case_of_3, CPU_TENSOR_NHWC(32F, 1), "b3");
208
1
  ccv_nnc_symbolic_graph_set_case_of(symbolic_graph, case_of, case_of_3, 3, TENSOR_SYMBOL_MAP(KV(b, y)));
209
1
  ccv_nnc_graph_exec_symbol_new(case_of_3, CMD_SCALAR_MUL_FORWARD(1.1), TENSOR_SYMBOL_LIST(x), TENSOR_SYMBOL_LIST(b), "1.1b");
210
1
  ccv_nnc_graph_exec_symbol_autogen(case_of_3, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS);
211
1
  ccv_nnc_graph_exec_symbol_autogen(symbolic_graph, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS);
212
1
  SYMBOLIC_GRAPH_GEN(symbolic_graph, CCV_NNC_LONG_DOT_GRAPH);
213
1
  ccv_nnc_graph_t* graph = 0;
214
1
  ccv_nnc_tensor_arena_t* tensor_arena = 0;
215
1
  ccv_nnc_graph_exec_arena_t* graph_exec_arena = 0;
216
1
  ccv_nnc_symbolic_graph_compile(symbolic_graph, ccv_nnc_default_compile_params, 0, 0, 0, 0, &case_of, 1, &case_of, 1, &graph, &tensor_arena, &graph_exec_arena);
217
1
  GRAPH_GEN(graph, CCV_NNC_LONG_DOT_GRAPH);
218
1
  ccv_nnc_tensor_t* x_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, x);
219
1
  x_tensor->data.f32[0] = -2.2;
220
1
  ccv_nnc_graph_run(graph, 0, TRAVERSE_FULL, 0, 0);
221
1
  ccv_nnc_tensor_t* y_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, y);
222
1
  REQUIRE_EQ_WITH_TOLERANCE(y_tensor->data.f32[0], expf(-2.2), 1e-5, "y should be expf(-2.2)");
223
1
  x_tensor->data.f32[0] = 1.1;
224
1
  ccv_nnc_graph_run(graph, 0, TRAVERSE_FULL, 0, 0);
225
1
  y_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, y);
226
1
  REQUIRE_EQ_WITH_TOLERANCE(y_tensor->data.f32[0], logf(1.1), 1e-5, "y should be logf(1.1)");
227
1
  x_tensor->data.f32[0] = 0.9;
228
1
  ccv_nnc_graph_run(graph, 0, TRAVERSE_FULL, 0, 0);
229
1
  y_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, y);
230
1
  REQUIRE_EQ_WITH_TOLERANCE(y_tensor->data.f32[0], 0.9, 1e-5, "y should be 0.9");
231
1
  x_tensor->data.f32[0] = 2.2;
232
1
  ccv_nnc_graph_run(graph, 0, TRAVERSE_FULL, 0, 0);
233
1
  y_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, y);
234
1
  REQUIRE_EQ_WITH_TOLERANCE(y_tensor->data.f32[0], 1. / 2.2, 1e-5, "y should be 1 / 2.2");
235
1
  x_tensor->data.f32[0] = 1001;
236
1
  ccv_nnc_graph_run(graph, 0, TRAVERSE_FULL, 0, 0);
237
1
  y_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, y);
238
1
  REQUIRE_EQ_WITH_TOLERANCE(y_tensor->data.f32[0], 1.1 * 1001, 1e-2, "y should be 1.1 * 1001");
239
1
  ccv_nnc_symbolic_graph_free(symbolic_graph);
240
1
  ccv_nnc_graph_exec_arena_free(graph_exec_arena);
241
1
  ccv_nnc_tensor_arena_free(tensor_arena);
242
1
  ccv_nnc_graph_free(graph);
243
244
1
}
245
246
TEST_CASE("symbolic while graph contains a case..of graph and multiply its output with 0.3")
247
1
{
248
1
  ccv_nnc_symbolic_graph_t* const symbolic_graph = ccv_nnc_symbolic_graph_new();
249
1
  ccv_nnc_tensor_symbol_t x = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "x");
250
1
  ccv_nnc_symbolic_graph_t* const while_graph = ccv_nnc_symbolic_graph_new();
251
1
  ccv_nnc_graph_exec_symbol_t noop = ccv_nnc_graph_exec_symbol_new(while_graph, CMD_NOOP(), 0, 0, 0, 0, "noop");
252
1
  ccv_nnc_symbolic_graph_while(symbolic_graph, CCV_NNC_GRAPH_FORWARD, while_graph, "while 4");
253
1
  ccv_nnc_tensor_symbol_t y = ccv_nnc_tensor_symbol_new(while_graph, CPU_TENSOR_NHWC(32F, 1), "y");
254
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));
255
1
  ccv_nnc_graph_exec_symbol_t case_of = ccv_nnc_symbolic_graph_case_of_new(while_graph, CCV_NNC_GRAPH_FORWARD, TENSOR_SYMBOL_LIST(x), TENSOR_SYMBOL_MAP(KV(x, y)), "piece-wise linear vector");
256
1
  ccv_nnc_symbolic_graph_set_case_of_expr(while_graph, case_of, piecewise_case_of, 0);
257
1
  ccv_nnc_graph_exec_symbol_concat(while_graph, noop, case_of);
258
1
  ccv_nnc_symbolic_graph_set_sources(while_graph, GRAPH_EXEC_SYMBOL_LIST(noop));
259
1
  ccv_nnc_symbolic_graph_set_destinations(while_graph, GRAPH_EXEC_SYMBOL_LIST(case_of));
260
1
  ccv_nnc_symbolic_graph_t* const case_of_0 = ccv_nnc_symbolic_graph_new();
261
1
  ccv_nnc_tensor_symbol_t y0 = ccv_nnc_tensor_symbol_new(case_of_0, CPU_TENSOR_NHWC(32F, 1), "y0");
262
1
  ccv_nnc_symbolic_graph_set_case_of(while_graph, case_of, case_of_0, 0, TENSOR_SYMBOL_MAP(KV(y0, y)));
263
1
  ccv_nnc_graph_exec_symbol_new(case_of_0, CMD_SET_FORWARD(0), 0, 0, TENSOR_SYMBOL_LIST(y0), "set");
264
1
  ccv_nnc_graph_exec_symbol_autogen(case_of_0, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS);
265
1
  ccv_nnc_symbolic_graph_t* const case_of_1 = ccv_nnc_symbolic_graph_new();
266
1
  ccv_nnc_tensor_symbol_t y1 = ccv_nnc_tensor_symbol_new(case_of_1, CPU_TENSOR_NHWC(32F, 1), "y1");
267
1
  ccv_nnc_symbolic_graph_set_case_of(while_graph, case_of, case_of_1, 1, TENSOR_SYMBOL_MAP(KV(y1, y)));
268
1
  ccv_nnc_tensor_symbol_t s1 = ccv_nnc_tensor_symbol_new(case_of_1, CPU_TENSOR_NHWC(32F, 1), "s");
269
1
  ccv_nnc_tensor_symbol_t z1 = ccv_nnc_tensor_symbol_new(case_of_1, CPU_TENSOR_NHWC(32F, 1), "z1");
270
1
  ccv_nnc_tensor_symbol_t p1 = ccv_nnc_tensor_symbol_new(case_of_1, CPU_TENSOR_NHWC(32F, 1), "p");
271
1
  ccv_nnc_graph_exec_symbol_new(case_of_1, CMD_EWPROD_FORWARD(), TENSOR_SYMBOL_LIST(x, s1), TENSOR_SYMBOL_LIST(z1), "prod0");
272
1
  ccv_nnc_graph_exec_symbol_new(case_of_1, CMD_EWSUM_FORWARD(), TENSOR_SYMBOL_LIST(z1, p1), TENSOR_SYMBOL_LIST(y1), "sum");
273
1
  ccv_nnc_graph_exec_symbol_autogen(case_of_1, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS);
274
1
  ccv_nnc_symbolic_graph_t* const case_of_2 = ccv_nnc_symbolic_graph_new();
275
1
  ccv_nnc_tensor_symbol_t y2 = ccv_nnc_tensor_symbol_new(case_of_2, CPU_TENSOR_NHWC(32F, 1), "y2");
276
1
  ccv_nnc_symbolic_graph_set_case_of(while_graph, case_of, case_of_2, 2, TENSOR_SYMBOL_MAP(KV(y2, y)));
277
1
  ccv_nnc_graph_exec_symbol_new(case_of_2, CMD_SET_FORWARD(1.5), 0, 0, TENSOR_SYMBOL_LIST(y2), "set");
278
1
  ccv_nnc_graph_exec_symbol_autogen(case_of_2, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS);
279
1
  ccv_nnc_symbolic_graph_set_carry_overs(while_graph, TENSOR_SYMBOL_MAP(KV(y, x)));
280
1
  ccv_nnc_tensor_symbol_t z = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "z");
281
1
  ccv_nnc_tensor_symbol_t a = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "a");
282
1
  ccv_nnc_graph_exec_symbol_new(symbolic_graph, CMD_EWPROD_FORWARD(), TENSOR_SYMBOL_LIST(a, y), TENSOR_SYMBOL_LIST(z), "prod1");
283
1
  ccv_nnc_graph_exec_symbol_autogen(symbolic_graph, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS);
284
1
  SYMBOLIC_GRAPH_GEN(symbolic_graph, CCV_NNC_LONG_DOT_GRAPH);
285
1
  ccv_nnc_graph_t* graph = 0;
286
1
  ccv_nnc_tensor_arena_t* tensor_arena = 0;
287
1
  ccv_nnc_graph_exec_arena_t* graph_exec_arena = 0;
288
1
  ccv_nnc_symbolic_graph_compile(symbolic_graph, ccv_nnc_default_compile_params, 0, 0, 0, 0, ccv_nnc_symbolic_graph_sources(symbolic_graph), ccv_nnc_symbolic_graph_source_size(symbolic_graph), ccv_nnc_symbolic_graph_destinations(symbolic_graph), ccv_nnc_symbolic_graph_destination_size(symbolic_graph), &graph, &tensor_arena, &graph_exec_arena);
289
1
  GRAPH_GEN(graph, CCV_NNC_LONG_DOT_GRAPH);
290
1
  ccv_nnc_tensor_t* x_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, x);
291
1
  ccv_nnc_tensor_t* s1_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, s1);
292
1
  s1_tensor->data.f32[0] = 0.5;
293
1
  ccv_nnc_tensor_t* p1_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, p1);
294
1
  p1_tensor->data.f32[0] = 0.5;
295
1
  ccv_nnc_tensor_t* a_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, a);
296
1
  a_tensor->data.f32[0] = 0.3;
297
1
  x_tensor->data.f32[0] = 1.226;
298
1
  ccv_nnc_graph_run(graph, 0, TRAVERSE_FULL, 0, 0);
299
1
  ccv_nnc_tensor_t* z_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, z);
300
1
  REQUIRE_EQ_WITH_TOLERANCE((1 + 0.226 * 0.5 * 0.5 * 0.5 * 0.5) * 0.3, z_tensor->data.f32[0], 1e-6, "The piece-wise linear function applied 4 times");
301
1
  a_tensor->data.f32[0] = 0.3;
302
1
  x_tensor->data.f32[0] = 0.8;
303
1
  ccv_nnc_graph_run(graph, 0, TRAVERSE_FULL, 0, 0);
304
1
  z_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, z);
305
1
  REQUIRE_EQ_WITH_TOLERANCE(0.8 * 0.3, z_tensor->data.f32[0], 1e-6, "The piece-wise linear function applied 4 times");
306
1
  ccv_nnc_symbolic_graph_free(symbolic_graph);
307
1
  ccv_nnc_graph_exec_arena_free(graph_exec_arena);
308
1
  ccv_nnc_tensor_arena_free(tensor_arena);
309
1
  ccv_nnc_graph_free(graph);
310
1
}
311
312
TEST_CASE("symbolic while graph contains a case..of graph takes input by multiplying to 0.8 and multiply its output with 0.3")
313
1
{
314
1
  ccv_nnc_symbolic_graph_t* const symbolic_graph = ccv_nnc_symbolic_graph_new();
315
1
  ccv_nnc_tensor_symbol_t b = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "b");
316
1
  ccv_nnc_symbolic_graph_t* const while_graph = ccv_nnc_symbolic_graph_new();
317
1
  ccv_nnc_graph_exec_symbol_t noop = ccv_nnc_graph_exec_symbol_new(while_graph, CMD_NOOP(), 0, 0, 0, 0, "noop");
318
1
  ccv_nnc_symbolic_graph_while(symbolic_graph, CCV_NNC_GRAPH_FORWARD, while_graph, "while 4");
319
1
  ccv_nnc_tensor_symbol_t s0 = ccv_nnc_tensor_symbol_new(while_graph, CPU_TENSOR_NHWC(32F, 1), "s0");
320
1
  ccv_nnc_tensor_symbol_t x = ccv_nnc_tensor_symbol_new(while_graph, CPU_TENSOR_NHWC(32F, 1), "x");
321
1
  ccv_nnc_graph_exec_symbol_t prod = ccv_nnc_graph_exec_symbol_new(while_graph, CMD_EWPROD_FORWARD(), TENSOR_SYMBOL_LIST(b, s0), TENSOR_SYMBOL_LIST(x), "prod");
322
1
  ccv_nnc_tensor_symbol_t y = ccv_nnc_tensor_symbol_new(while_graph, CPU_TENSOR_NHWC(32F, 1), "y");
323
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));
324
1
  ccv_nnc_graph_exec_symbol_t case_of = ccv_nnc_symbolic_graph_case_of_new(while_graph, CCV_NNC_GRAPH_FORWARD, TENSOR_SYMBOL_LIST(x), TENSOR_SYMBOL_MAP(KV(x, y)), "piece-wise linear vector");
325
1
  ccv_nnc_symbolic_graph_set_case_of_expr(while_graph, case_of, piecewise_case_of, 0);
326
1
  ccv_nnc_graph_exec_symbol_concat(while_graph, noop, prod);
327
1
  ccv_nnc_symbolic_graph_set_sources(while_graph, GRAPH_EXEC_SYMBOL_LIST(noop));
328
1
  ccv_nnc_symbolic_graph_set_destinations(while_graph, GRAPH_EXEC_SYMBOL_LIST(case_of));
329
1
  ccv_nnc_symbolic_graph_t* const case_of_0 = ccv_nnc_symbolic_graph_new();
330
1
  ccv_nnc_tensor_symbol_t y0 = ccv_nnc_tensor_symbol_new(case_of_0, CPU_TENSOR_NHWC(32F, 1), "y0");
331
1
  ccv_nnc_symbolic_graph_set_case_of(while_graph, case_of, case_of_0, 0, TENSOR_SYMBOL_MAP(KV(y0, y)));
332
1
  ccv_nnc_graph_exec_symbol_new(case_of_0, CMD_SET_FORWARD(0), 0, 0, TENSOR_SYMBOL_LIST(y0), "set");
333
1
  ccv_nnc_graph_exec_symbol_autogen(case_of_0, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS);
334
1
  ccv_nnc_symbolic_graph_t* const case_of_1 = ccv_nnc_symbolic_graph_new();
335
1
  ccv_nnc_tensor_symbol_t y1 = ccv_nnc_tensor_symbol_new(case_of_1, CPU_TENSOR_NHWC(32F, 1), "y1");
336
1
  ccv_nnc_symbolic_graph_set_case_of(while_graph, case_of, case_of_1, 1, TENSOR_SYMBOL_MAP(KV(y1, y)));
337
1
  ccv_nnc_tensor_symbol_t s1 = ccv_nnc_tensor_symbol_new(case_of_1, CPU_TENSOR_NHWC(32F, 1), "s");
338
1
  ccv_nnc_tensor_symbol_t z1 = ccv_nnc_tensor_symbol_new(case_of_1, CPU_TENSOR_NHWC(32F, 1), "z1");
339
1
  ccv_nnc_tensor_symbol_t p1 = ccv_nnc_tensor_symbol_new(case_of_1, CPU_TENSOR_NHWC(32F, 1), "p");
340
1
  ccv_nnc_graph_exec_symbol_new(case_of_1, CMD_EWPROD_FORWARD(), TENSOR_SYMBOL_LIST(x, s1), TENSOR_SYMBOL_LIST(z1), "prod0");
341
1
  ccv_nnc_graph_exec_symbol_new(case_of_1, CMD_EWSUM_FORWARD(), TENSOR_SYMBOL_LIST(z1, p1), TENSOR_SYMBOL_LIST(y1), "sum");
342
1
  ccv_nnc_graph_exec_symbol_autogen(case_of_1, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS);
343
1
  ccv_nnc_symbolic_graph_t* const case_of_2 = ccv_nnc_symbolic_graph_new();
344
1
  ccv_nnc_tensor_symbol_t y2 = ccv_nnc_tensor_symbol_new(case_of_2, CPU_TENSOR_NHWC(32F, 1), "y2");
345
1
  ccv_nnc_symbolic_graph_set_case_of(while_graph, case_of, case_of_2, 2, TENSOR_SYMBOL_MAP(KV(y2, y)));
346
1
  ccv_nnc_graph_exec_symbol_new(case_of_2, CMD_SET_FORWARD(1.5), 0, 0, TENSOR_SYMBOL_LIST(y2), "set");
347
1
  ccv_nnc_graph_exec_symbol_autogen(case_of_2, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS);
348
1
  ccv_nnc_symbolic_graph_set_carry_overs(while_graph, TENSOR_SYMBOL_MAP(KV(y, b)));
349
1
  ccv_nnc_tensor_symbol_t z = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "z");
350
1
  ccv_nnc_tensor_symbol_t a = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "a");
351
1
  ccv_nnc_graph_exec_symbol_new(symbolic_graph, CMD_EWPROD_FORWARD(), TENSOR_SYMBOL_LIST(a, y), TENSOR_SYMBOL_LIST(z), "prod1");
352
1
  ccv_nnc_graph_exec_symbol_autogen(symbolic_graph, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS);
353
1
  SYMBOLIC_GRAPH_GEN(symbolic_graph, CCV_NNC_LONG_DOT_GRAPH);
354
1
  ccv_nnc_graph_t* graph = 0;
355
1
  ccv_nnc_tensor_arena_t* tensor_arena = 0;
356
1
  ccv_nnc_graph_exec_arena_t* graph_exec_arena = 0;
357
1
  ccv_nnc_symbolic_graph_compile(symbolic_graph, ccv_nnc_default_compile_params, 0, 0, 0, 0, ccv_nnc_symbolic_graph_sources(symbolic_graph), ccv_nnc_symbolic_graph_source_size(symbolic_graph), ccv_nnc_symbolic_graph_destinations(symbolic_graph), ccv_nnc_symbolic_graph_destination_size(symbolic_graph), &graph, &tensor_arena, &graph_exec_arena);
358
1
  GRAPH_GEN(graph, CCV_NNC_LONG_DOT_GRAPH);
359
1
  ccv_nnc_tensor_t* b_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, b);
360
1
  ccv_nnc_tensor_t* s0_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, s0);
361
1
  s0_tensor->data.f32[0] = 0.8;
362
1
  ccv_nnc_tensor_t* s1_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, s1);
363
1
  s1_tensor->data.f32[0] = 0.5;
364
1
  ccv_nnc_tensor_t* p1_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, p1);
365
1
  p1_tensor->data.f32[0] = 0.5;
366
1
  ccv_nnc_tensor_t* a_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, a);
367
1
  a_tensor->data.f32[0] = 0.3;
368
1
  b_tensor->data.f32[0] = 2.5;
369
1
  ccv_nnc_graph_run(graph, 0, TRAVERSE_FULL, 0, 0);
370
1
  ccv_nnc_tensor_t* z_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, z);
371
1
  REQUIRE_EQ_WITH_TOLERANCE(1.1 * 0.8 * 0.8 * 0.3, z_tensor->data.f32[0], 1e-6, "The piece-wise linear function applied 4 times");
372
1
  ccv_nnc_symbolic_graph_free(symbolic_graph);
373
1
  ccv_nnc_graph_exec_arena_free(graph_exec_arena);
374
1
  ccv_nnc_tensor_arena_free(tensor_arena);
375
1
  ccv_nnc_graph_free(graph);
376
1
}
377
378
#include "case_main.h"