Coverage Report

Created: 2021-04-06 02:31

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