Coverage Report

Created: 2019-07-03 22:50

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