Coverage Report

Created: 2024-08-19 11:27

/home/liu/actions-runner/_work/ccv/ccv/test/unit/nnc/while.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 while_5(ccv_nnc_tensor_t* const* const inputs, const int input_size, const void* const data)
15
96
{
16
96
  int i;
17
234
  for (i = 0; i < input_size; 
i++138
)
18
138
    { assert(!CCV_IS_TENSOR_MULTIVIEW(inputs[i])); }
19
96
  return inputs[0]->data.i64[0] < 5;
20
96
}
21
22
TEST_CASE("graph for a while loop to compute 0.34 * 1.11 ^ 5")
23
1
{
24
1
  ccv_nnc_graph_t* graph = ccv_nnc_graph_new();
25
1
  ccv_nnc_tensor_t* x = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 1), 0);
26
1
  ccv_nnc_tensor_t* y = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 1), 0);
27
1
  ccv_nnc_tensor_t* z = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 1), 0);
28
1
  ccv_nnc_graph_t* while_graph = ccv_nnc_graph_new();
29
1
  ccv_nnc_graph_exec_t noop = ccv_nnc_graph_exec_new(while_graph, CMD_NOOP(), ccv_nnc_no_hint, 0, 0, 0, 0);
30
1
  ccv_nnc_graph_exec_t prod0 = ccv_nnc_graph_exec_new(while_graph, CMD_EWPROD_FORWARD(), ccv_nnc_no_hint, TENSOR_LIST(y, z), TENSOR_LIST(z));
31
1
  ccv_nnc_graph_exec_concat(while_graph, noop, prod0);
32
1
  ccv_nnc_graph_exec_t loop = ccv_nnc_graph_while(graph, CCV_NNC_GRAPH_FORWARD, while_graph);
33
1
  ccv_nnc_graph_set_sources(while_graph, GRAPH_EXEC_LIST(noop));
34
1
  ccv_nnc_graph_set_destinations(while_graph, GRAPH_EXEC_LIST(prod0));
35
1
  ccv_nnc_tensor_t count_tensor = ccv_nnc_tensor_for_while_count(while_graph);
36
1
  ccv_nnc_graph_set_while_expr(while_graph, while_5, 0, TENSOR_LIST(&count_tensor), GRAPH_EXEC_LIST(noop));
37
1
  ccv_nnc_graph_exec_t prod1 = ccv_nnc_graph_exec_new(graph, CMD_EWPROD_FORWARD(), ccv_nnc_no_hint, TENSOR_LIST(x, z), TENSOR_LIST(z));
38
1
  ccv_nnc_graph_exec_concat(graph, loop, prod1);
39
1
  GRAPH_GEN(graph, CCV_NNC_LONG_DOT_GRAPH);
40
1
  x->data.f32[0] = 0.34;
41
1
  y->data.f32[0] = 1.11;
42
1
  z->data.f32[0] = 1;
43
1
  ccv_nnc_graph_autotune(graph, 0, 0, TRAVERSE_FULL);
44
1
  ccv_nnc_graph_run(graph, 0, GRAPH_EXEC_LIST(loop), GRAPH_EXEC_LIST(prod1), 0, 0);
45
1
  ccv_nnc_graph_free(graph);
46
1
  REQUIRE_EQ_WITH_TOLERANCE(z->data.f32[0], 0.34 * 1.11 * 1.11 * 1.11 * 1.11 * 1.11, 1e-6, "computed result of 0.34 * 1.11 ^ 5 should be the same");
47
1
  ccv_nnc_tensor_free(x);
48
1
  ccv_nnc_tensor_free(y);
49
1
  ccv_nnc_tensor_free(z);
50
1
}
51
52
TEST_CASE("graph for a while loop by reuse tensor allocations for 0.32 * 2.8 ^ 5")
53
1
{
54
1
  ccv_nnc_graph_t* graph = ccv_nnc_graph_new();
55
1
  ccv_nnc_graph_t* while_graph = ccv_nnc_graph_new();
56
1
  ccv_nnc_graph_exec_t loop = ccv_nnc_graph_while(graph, CCV_NNC_GRAPH_FORWARD, while_graph);
57
1
  ccv_nnc_graph_exec_t noop = ccv_nnc_graph_exec_new(while_graph, CMD_NOOP(), ccv_nnc_no_hint, 0, 0, 0, 0);
58
1
  ccv_nnc_tensor_t* x = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 1), 0);
59
1
  ccv_nnc_tensor_t* y = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 1), 0);
60
1
  ccv_nnc_tensor_t* z = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 1), 0);
61
1
  ccv_nnc_tensor_multiview_t xx;
62
1
  ccv_nnc_tensor_multiview((ccv_nnc_tensor_t*[]){
63
1
      x, z
64
1
  }, CCV_NNC_MULTIVIEW_K0N, 2, while_graph, &xx);
65
1
  ccv_nnc_tensor_multiview_t zz;
66
1
  ccv_nnc_tensor_multiview((ccv_nnc_tensor_t*[]){
67
1
      z, x
68
1
  }, CCV_NNC_MULTIVIEW_K0N, 2, while_graph, &zz);
69
1
  ccv_nnc_tensor_t zbb = ccv_nnc_tensor(0, CPU_TENSOR_NHWC(32F, 1), 0);
70
1
  ccv_nnc_tensor_synchronize_to_multiview(&zz, &zbb);
71
1
  ccv_nnc_graph_exec_t prod = ccv_nnc_graph_exec_new(while_graph, CMD_EWPROD_FORWARD(), ccv_nnc_no_hint, TENSOR_LIST((ccv_nnc_tensor_t*)&xx, y), TENSOR_LIST((ccv_nnc_tensor_t*)&zz));
72
1
  ccv_nnc_graph_set_sources(while_graph, GRAPH_EXEC_LIST(noop));
73
1
  ccv_nnc_graph_set_destinations(while_graph, GRAPH_EXEC_LIST(prod));
74
1
  ccv_nnc_tensor_t count_tensor = ccv_nnc_tensor_for_while_count(while_graph);
75
1
  ccv_nnc_graph_set_while_expr(while_graph, while_5, 0, TENSOR_LIST(&count_tensor), GRAPH_EXEC_LIST(noop));
76
1
  ccv_nnc_graph_exec_concat(while_graph, noop, prod);
77
1
  GRAPH_GEN(graph, CCV_NNC_LONG_DOT_GRAPH);
78
1
  x->data.f32[0] = 0.32;
79
1
  y->data.f32[0] = 2.8;
80
1
  ccv_nnc_graph_autotune(graph, 0, 0, TRAVERSE_FULL);
81
1
  ccv_nnc_graph_run(graph, 0, GRAPH_EXEC_LIST(loop), GRAPH_EXEC_LIST(loop), 0, 0);
82
1
  REQUIRE_EQ_WITH_TOLERANCE(z->data.f32[0], 0.32 * 2.8 * 2.8 * 2.8 * 2.8 * 2.8, 1e-5, "computed result of 0.32 * 2.8 ^ 5 should be the same");
83
1
  REQUIRE(z->data.f32 == zbb.data.f32, "Two pointers should be the same");
84
1
  ccv_nnc_tensor_multiview_free(xx);
85
1
  ccv_nnc_tensor_multiview_free(zz);
86
1
  ccv_nnc_graph_free(graph);
87
1
  ccv_nnc_tensor_free(x);
88
1
  ccv_nnc_tensor_free(y);
89
1
  ccv_nnc_tensor_free(z);
90
1
}
91
92
TEST_CASE("while graph add and re-add reuse tensor allocations for 0.47 * 5.5 ^ 5")
93
1
{
94
1
  ccv_nnc_graph_t* graph = ccv_nnc_graph_new();
95
1
  ccv_nnc_graph_t* while_graph = ccv_nnc_graph_new();
96
1
  ccv_nnc_graph_exec_t loop = ccv_nnc_graph_while(graph, CCV_NNC_GRAPH_FORWARD, while_graph);
97
1
  ccv_nnc_graph_exec_t noop = ccv_nnc_graph_exec_new(while_graph, CMD_NOOP(), ccv_nnc_no_hint, 0, 0, 0, 0);
98
1
  ccv_nnc_tensor_t* x = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 1), 0);
99
1
  ccv_nnc_tensor_t* y = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 1), 0);
100
1
  ccv_nnc_tensor_t* z = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 1), 0);
101
1
  ccv_nnc_tensor_multiview_t xx;
102
1
  ccv_nnc_tensor_multiview((ccv_nnc_tensor_t*[]){
103
1
      x, z
104
1
  }, CCV_NNC_MULTIVIEW_K0N, 2, while_graph, &xx);
105
1
  ccv_nnc_tensor_multiview_t zz;
106
1
  ccv_nnc_tensor_multiview((ccv_nnc_tensor_t*[]){
107
1
      z, x
108
1
  }, CCV_NNC_MULTIVIEW_K0N, 2, while_graph, &zz);
109
1
  ccv_nnc_graph_exec_t prod = ccv_nnc_graph_exec_new(while_graph, CMD_EWPROD_FORWARD(), ccv_nnc_no_hint, TENSOR_LIST((ccv_nnc_tensor_t*)&xx, y), TENSOR_LIST((ccv_nnc_tensor_t*)&zz));
110
1
  ccv_nnc_graph_set_sources(while_graph, GRAPH_EXEC_LIST(noop));
111
1
  ccv_nnc_graph_set_destinations(while_graph, GRAPH_EXEC_LIST(prod));
112
1
  ccv_nnc_tensor_t count_tensor = ccv_nnc_tensor_for_while_count(while_graph);
113
1
  ccv_nnc_graph_set_while_expr(while_graph, while_5, 0, TENSOR_LIST(&count_tensor), GRAPH_EXEC_LIST(noop));
114
1
  ccv_nnc_graph_exec_concat(while_graph, noop, prod);
115
1
  ccv_nnc_graph_exec_set_io(while_graph, prod, TENSOR_LIST(x, y), TENSOR_LIST(z));
116
1
  ccv_nnc_graph_exec_set_io(while_graph, prod, TENSOR_LIST((ccv_nnc_tensor_t*)&zz, y), TENSOR_LIST((ccv_nnc_tensor_t*)&xx));
117
1
  GRAPH_GEN(graph, CCV_NNC_LONG_DOT_GRAPH);
118
1
  x->data.f32[0] = 0.32;
119
1
  z->data.f32[0] = 0.47;
120
1
  y->data.f32[0] = 5.5;
121
1
  ccv_nnc_graph_autotune(graph, 0, 0, TRAVERSE_FULL);
122
1
  ccv_nnc_graph_run(graph, 0, GRAPH_EXEC_LIST(loop), GRAPH_EXEC_LIST(loop), 0, 0);
123
1
  REQUIRE_EQ_WITH_TOLERANCE(x->data.f32[0], 0.47 * 5.5 * 5.5 * 5.5 * 5.5 * 5.5, 1e-2, "computed result of 0.47 * 5.5 ^ 5 should be the same");
124
1
  ccv_nnc_graph_free(graph);
125
1
  ccv_nnc_tensor_free(x);
126
1
  ccv_nnc_tensor_free(y);
127
1
  ccv_nnc_tensor_free(z);
128
1
}
129
130
TEST_CASE("symbolic graph get while graph from symbol")
131
1
{
132
1
  ccv_nnc_symbolic_graph_t* const symbolic_graph = ccv_nnc_symbolic_graph_new();
133
1
  ccv_nnc_symbolic_graph_t* const while_graph_0 = ccv_nnc_symbolic_graph_new();
134
1
  ccv_nnc_graph_exec_symbol_t while_0 = ccv_nnc_symbolic_graph_while(symbolic_graph, CCV_NNC_GRAPH_FORWARD, while_graph_0, "while 0");
135
1
  ccv_nnc_symbolic_graph_t* const while_graph_1 = ccv_nnc_symbolic_graph_new();
136
1
  ccv_nnc_graph_exec_symbol_t while_1 = ccv_nnc_symbolic_graph_while(symbolic_graph, CCV_NNC_GRAPH_FORWARD, while_graph_1, "while 1");
137
1
  REQUIRE(while_graph_0 == ccv_nnc_symbolic_graph_from_while_symbol(symbolic_graph, while_0), "graph extracted from symbol should be equal");
138
1
  REQUIRE(while_graph_1 == ccv_nnc_symbolic_graph_from_while_symbol(symbolic_graph, while_1), "graph extracted from symbol should be equal");
139
1
  ccv_nnc_symbolic_graph_free(symbolic_graph);
140
1
}
141
142
TEST_CASE("symbolic graph for a while loop to compute x ^ 5 * y")
143
1
{
144
1
  ccv_nnc_symbolic_graph_t* symbolic_graph = ccv_nnc_symbolic_graph_new();
145
1
  ccv_nnc_tensor_symbol_t x = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "x");
146
1
  ccv_nnc_tensor_symbol_t y = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "y");
147
1
  ccv_nnc_symbolic_graph_t* while_graph = ccv_nnc_symbolic_graph_new();
148
1
  ccv_nnc_symbolic_graph_while(symbolic_graph, CCV_NNC_GRAPH_FORWARD, while_graph, "for 1..5");
149
1
  ccv_nnc_tensor_symbol_t z0 = ccv_nnc_tensor_symbol_new(while_graph, CPU_TENSOR_NHWC(32F, 1), "z0");
150
1
  ccv_nnc_tensor_symbol_t z1 = ccv_nnc_tensor_symbol_new(while_graph, CPU_TENSOR_NHWC(32F, 1), "z1");
151
1
  ccv_nnc_graph_exec_symbol_t noop = ccv_nnc_graph_exec_symbol_new(while_graph, CMD_NOOP(), 0, 0, 0, 0, "noop");
152
1
  ccv_nnc_graph_exec_symbol_t prod0 = ccv_nnc_graph_exec_symbol_new(while_graph, CMD_EWPROD_FORWARD(), TENSOR_SYMBOL_LIST(z0, x), TENSOR_SYMBOL_LIST(z1), "prod0");
153
1
  ccv_nnc_graph_exec_symbol_concat(while_graph, noop, prod0);
154
1
  ccv_nnc_tensor_symbol_t z2 = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "z2");
155
1
  ccv_nnc_graph_exec_symbol_new(symbolic_graph, CMD_EWPROD_FORWARD(), TENSOR_SYMBOL_LIST(z1, y), TENSOR_SYMBOL_LIST(z2), "prod1");
156
1
  ccv_nnc_graph_exec_symbol_autogen(symbolic_graph, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS);
157
  // Test whether we can ignore the noop graph properly in compilation.
158
1
  ccv_nnc_symbolic_graph_t* noop_graph = ccv_nnc_symbolic_graph_new();
159
1
  ccv_nnc_symbolic_graph_while(symbolic_graph, CCV_NNC_GRAPH_FORWARD, noop_graph, "no op");
160
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(noop));
161
1
  ccv_nnc_symbolic_graph_set_carry_overs(while_graph, TENSOR_SYMBOL_MAP(KV(z1, z0)));
162
1
  ccv_nnc_symbolic_graph_set_sources(while_graph, GRAPH_EXEC_SYMBOL_LIST(noop));
163
1
  ccv_nnc_symbolic_graph_set_destinations(while_graph, GRAPH_EXEC_SYMBOL_LIST(prod0));
164
1
  ccv_nnc_graph_t* graph = 0;
165
1
  ccv_nnc_tensor_arena_t* tensor_arena = 0;
166
1
  ccv_nnc_graph_exec_arena_t* graph_exec_arena = 0;
167
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);
168
1
  SYMBOLIC_GRAPH_GEN(symbolic_graph, CCV_NNC_LONG_DOT_GRAPH);
169
1
  GRAPH_GEN(graph, CCV_NNC_LONG_DOT_GRAPH);
170
1
  ccv_nnc_tensor_t* x_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, x);
171
1
  ccv_nnc_tensor_t* y_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, y);
172
1
  ccv_nnc_tensor_t* z0_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, z0);
173
1
  ccv_nnc_tensor_t* z_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, z2);
174
1
  x_tensor->data.f32[0] = 0.92;
175
1
  y_tensor->data.f32[0] = 3.2;
176
1
  z0_tensor->data.f32[0] = 1;
177
1
  ccv_nnc_graph_autotune(graph, 0, 0, TRAVERSE_FULL);
178
1
  ccv_nnc_graph_run(graph, 0, TRAVERSE_FULL, 0, 0);
179
1
  REQUIRE_EQ_WITH_TOLERANCE(z_tensor->data.f32[0], 0.92 * 0.92 * 0.92 * 0.92 * 0.92 * 3.2, 1e-6, "z should be equal to x ^ 5 * y");
180
1
  ccv_nnc_symbolic_graph_free(symbolic_graph);
181
1
  ccv_nnc_graph_exec_arena_free(graph_exec_arena);
182
1
  ccv_nnc_tensor_arena_free(tensor_arena);
183
1
  ccv_nnc_graph_free(graph);
184
1
}
185
186
TEST_CASE("symbolic graph for a while loop to compute z * x ^ 5 * y + z")
187
1
{
188
1
  ccv_nnc_symbolic_graph_t* symbolic_graph = ccv_nnc_symbolic_graph_new();
189
1
  ccv_nnc_tensor_symbol_t x = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "x");
190
1
  ccv_nnc_tensor_symbol_t y = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "y");
191
1
  ccv_nnc_tensor_symbol_t z0 = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "z0");
192
1
  ccv_nnc_symbolic_graph_t* while_graph = ccv_nnc_symbolic_graph_new();
193
1
  ccv_nnc_symbolic_graph_while(symbolic_graph, CCV_NNC_GRAPH_FORWARD, while_graph, "for 1..5");
194
1
  ccv_nnc_tensor_symbol_t z1 = ccv_nnc_tensor_symbol_new(while_graph, CPU_TENSOR_NHWC(32F, 1), "z1");
195
1
  ccv_nnc_graph_exec_symbol_t noop = ccv_nnc_graph_exec_symbol_new(while_graph, CMD_NOOP(), 0, 0, 0, 0, "noop");
196
1
  ccv_nnc_graph_exec_symbol_t prod0 = ccv_nnc_graph_exec_symbol_new(while_graph, CMD_EWPROD_FORWARD(), TENSOR_SYMBOL_LIST(z0, x), TENSOR_SYMBOL_LIST(z1), "prod0");
197
1
  ccv_nnc_graph_exec_symbol_concat(while_graph, noop, prod0);
198
1
  ccv_nnc_tensor_symbol_t z2 = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "z2");
199
1
  ccv_nnc_tensor_symbol_t z3 = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "z3");
200
1
  ccv_nnc_graph_exec_symbol_new(symbolic_graph, CMD_EWPROD_FORWARD(), TENSOR_SYMBOL_LIST(z1, y), TENSOR_SYMBOL_LIST(z2), "prod1");
201
1
  ccv_nnc_graph_exec_symbol_new(symbolic_graph, CMD_EWSUM_FORWARD(), TENSOR_SYMBOL_LIST(z2, z0), TENSOR_SYMBOL_LIST(z3), "sum");
202
1
  ccv_nnc_graph_exec_symbol_autogen(symbolic_graph, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS);
203
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), z0), GRAPH_EXEC_SYMBOL_LIST(noop));
204
1
  ccv_nnc_symbolic_graph_set_carry_overs(while_graph, TENSOR_SYMBOL_MAP(KV(z1, z0)));
205
1
  ccv_nnc_symbolic_graph_set_sources(while_graph, GRAPH_EXEC_SYMBOL_LIST(noop));
206
1
  ccv_nnc_symbolic_graph_set_destinations(while_graph, GRAPH_EXEC_SYMBOL_LIST(prod0));
207
1
  ccv_nnc_graph_t* graph = 0;
208
1
  ccv_nnc_tensor_arena_t* tensor_arena = 0;
209
1
  ccv_nnc_graph_exec_arena_t* graph_exec_arena = 0;
210
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);
211
1
  SYMBOLIC_GRAPH_GEN(symbolic_graph, CCV_NNC_LONG_DOT_GRAPH);
212
1
  GRAPH_GEN(graph, CCV_NNC_LONG_DOT_GRAPH);
213
1
  ccv_nnc_tensor_t* x_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, x);
214
1
  ccv_nnc_tensor_t* y_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, y);
215
1
  ccv_nnc_tensor_t* z0_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, z0);
216
1
  x_tensor->data.f32[0] = 0.92;
217
1
  y_tensor->data.f32[0] = 3.2;
218
1
  z0_tensor->data.f32[0] = 1.2;
219
1
  ccv_nnc_graph_autotune(graph, 0, 0, TRAVERSE_FULL);
220
1
  ccv_nnc_graph_run(graph, 0, TRAVERSE_FULL, 0, 0);
221
1
  ccv_nnc_tensor_t* z_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, z3);
222
1
  REQUIRE_EQ_WITH_TOLERANCE(z_tensor->data.f32[0], 1.2 * 0.92 * 0.92 * 0.92 * 0.92 * 0.92 * 3.2 + 1.2, 1e-6, "z should be equal to z * x ^ 5 * y + z");
223
1
  ccv_nnc_symbolic_graph_free(symbolic_graph);
224
1
  ccv_nnc_graph_exec_arena_free(graph_exec_arena);
225
1
  ccv_nnc_tensor_arena_free(tensor_arena);
226
1
  ccv_nnc_graph_free(graph);
227
1
}
228
229
TEST_CASE("symbolic graph for a while loop to compute x = max(conv(x, w, b), 3x3) 5 times")
230
1
{
231
1
  ccv_nnc_symbolic_graph_t* symbolic_graph = ccv_nnc_symbolic_graph_new();
232
1
  ccv_nnc_symbolic_graph_t* while_graph = ccv_nnc_symbolic_graph_new();
233
1
  ccv_nnc_symbolic_graph_while(symbolic_graph, CCV_NNC_GRAPH_FORWARD, while_graph, "while 1..5");
234
1
  ccv_nnc_tensor_symbol_t x = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 5, 5, 4), "x");
235
1
  ccv_nnc_tensor_symbol_t w = ccv_nnc_tensor_symbol_new(while_graph, CPU_TENSOR_NHWC(32F, 4, 3, 3, 4), "w");
236
1
  ccv_nnc_tensor_symbol_t b = ccv_nnc_tensor_symbol_new(while_graph, CPU_TENSOR_NHWC(32F, 4), "b");
237
1
  ccv_nnc_tensor_symbol_t y = ccv_nnc_tensor_symbol_new(while_graph, CPU_TENSOR_NHWC(32F, 5, 5, 4), "y");
238
1
  ccv_nnc_tensor_symbol_t z = ccv_nnc_tensor_symbol_new(while_graph, CPU_TENSOR_NHWC(32F, 5, 5, 4), "z");
239
1
  ccv_nnc_graph_exec_symbol_t noop = ccv_nnc_graph_exec_symbol_new(while_graph, CMD_NOOP(), 0, 0, 0, 0, "noop");
240
1
  ccv_nnc_graph_exec_symbol_t conv = ccv_nnc_graph_exec_symbol_new(while_graph, CMD_CONVOLUTION_FORWARD(1, 4, 3, 3, 4), TENSOR_SYMBOL_LIST(x, w, b), TENSOR_SYMBOL_LIST(y), "conv");
241
1
  ccv_nnc_graph_exec_symbol_t avg = ccv_nnc_graph_exec_symbol_new(while_graph, CMD_AVERAGE_POOL_FORWARD(3, 3), TENSOR_SYMBOL_LIST(y), TENSOR_SYMBOL_LIST(z), "avg");
242
1
  ccv_nnc_graph_exec_symbol_concat(while_graph, noop, conv);
243
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), w), GRAPH_EXEC_SYMBOL_LIST(noop));
244
1
  ccv_nnc_symbolic_graph_set_carry_overs(while_graph, TENSOR_SYMBOL_MAP(KV(z, x)));
245
1
  ccv_nnc_symbolic_graph_set_sources(while_graph, GRAPH_EXEC_SYMBOL_LIST(noop));
246
1
  ccv_nnc_symbolic_graph_set_destinations(while_graph, GRAPH_EXEC_SYMBOL_LIST(avg));
247
1
  ccv_nnc_graph_t* graph = 0;
248
1
  ccv_nnc_tensor_arena_t* tensor_arena = 0;
249
1
  ccv_nnc_graph_exec_arena_t* graph_exec_arena = 0;
250
1
  ccv_nnc_graph_exec_symbol_autogen(symbolic_graph, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS);
251
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);
252
1
  SYMBOLIC_GRAPH_GEN(symbolic_graph, CCV_NNC_LONG_DOT_GRAPH);
253
1
  GRAPH_GEN(graph, CCV_NNC_LONG_DOT_GRAPH);
254
1
  ccv_nnc_tensor_t* x_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, x);
255
1
  ccv_nnc_tensor_t* w_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, w);
256
1
  ccv_nnc_tensor_t* b_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, b);
257
1
  int i;
258
1
  dsfmt_t dsfmt;
259
1
  dsfmt_init_gen_rand(&dsfmt, 0);
260
101
  for (i = 0; i < 5 * 5 * 4; 
i++100
)
261
100
    x_tensor->data.f32[i] = dsfmt_genrand_open_close(&dsfmt);
262
145
  for (i = 0; i < 4 * 3 * 3 * 4; 
i++144
)
263
144
    w_tensor->data.f32[i] = dsfmt_genrand_open_close(&dsfmt) / (4 * 3 * 3);
264
5
  for (i = 0; i < 4; 
i++4
)
265
4
    b_tensor->data.f32[i] = 3.2;
266
1
  ccv_nnc_tensor_t* x1 = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 5, 5, 4), 0);
267
1
  memcpy(x1->data.f32, x_tensor->data.f32, sizeof(float) * 5 * 5 * 4);
268
1
  ccv_nnc_tensor_t* y1 = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 5, 5, 4), 0);
269
6
  for (i = 0; i < 5; 
i++5
)
270
5
  {
271
5
    ccv_nnc_cmd_exec(CMD_CONVOLUTION_FORWARD(1, 4, 3, 3, 4), HINT((1, 1), (1, 1)), 0, TENSOR_LIST(x1, w_tensor, b_tensor), TENSOR_LIST(y1), 0);
272
5
    ccv_nnc_cmd_exec(CMD_AVERAGE_POOL_FORWARD(3, 3), HINT((1, 1), (1, 1)), 0, TENSOR_LIST(y1), TENSOR_LIST(x1), 0);
273
5
  }
274
1
  ccv_nnc_graph_autotune(graph, 0, 0, TRAVERSE_FULL);
275
1
  ccv_nnc_graph_run(graph, 0, TRAVERSE_FULL, 0, 0);
276
1
  ccv_nnc_tensor_t* z_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, z);
277
1
  REQUIRE_MATRIX_EQ(x1, z_tensor, "5x5x4 matrix should be exactly the same");
278
1
  ccv_nnc_tensor_free(x1);
279
1
  ccv_nnc_tensor_free(y1);
280
1
  ccv_nnc_symbolic_graph_free(symbolic_graph);
281
1
  ccv_nnc_graph_exec_arena_free(graph_exec_arena);
282
1
  ccv_nnc_tensor_arena_free(tensor_arena);
283
1
  ccv_nnc_graph_free(graph);
284
1
}
285
286
TEST_CASE("symbolic graph for a while loop to compute x = conv(x, w, b) 5 times")
287
1
{
288
1
  ccv_nnc_symbolic_graph_t* symbolic_graph = ccv_nnc_symbolic_graph_new();
289
1
  ccv_nnc_symbolic_graph_t* while_graph = ccv_nnc_symbolic_graph_new();
290
1
  ccv_nnc_symbolic_graph_while(symbolic_graph, CCV_NNC_GRAPH_FORWARD, while_graph, "while 1..5");
291
1
  ccv_nnc_tensor_symbol_t x = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 5, 5, 4), "x");
292
1
  ccv_nnc_tensor_symbol_t w = ccv_nnc_tensor_symbol_new(while_graph, CPU_TENSOR_NHWC(32F, 4, 3, 3, 4), "w");
293
1
  ccv_nnc_tensor_symbol_t b = ccv_nnc_tensor_symbol_new(while_graph, CPU_TENSOR_NHWC(32F, 4), "b");
294
1
  ccv_nnc_tensor_symbol_t y = ccv_nnc_tensor_symbol_new(while_graph, CPU_TENSOR_NHWC(32F, 5, 5, 4), "y");
295
1
  ccv_nnc_tensor_symbol_t z0 = ccv_nnc_tensor_symbol_alias_new(while_graph, y, DIM_ALLOC(0, 0, 1), DIM_ALLOC(5 * 4, 4, 1), CPU_TENSOR_NHWC(32F, 5, 5, 3), "z0");
296
1
  ccv_nnc_tensor_symbol_t z1 = ccv_nnc_tensor_symbol_alias_new(while_graph, y, DIM_ALLOC(4), DIM_ALLOC(1), CPU_TENSOR_NHWC(32F, 6), "z1");
297
1
  ccv_nnc_graph_exec_symbol_t noop = ccv_nnc_graph_exec_symbol_new(while_graph, CMD_NOOP(), 0, 0, 0, 0, "noop");
298
1
  ccv_nnc_graph_exec_symbol_t conv = ccv_nnc_graph_exec_symbol_new(while_graph, CMD_CONVOLUTION_FORWARD(1, 4, 3, 3, 4), TENSOR_SYMBOL_LIST(x, w, b), TENSOR_SYMBOL_LIST(y), "conv");
299
1
  ccv_nnc_graph_exec_symbol_concat(while_graph, noop, conv);
300
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(noop));
301
1
  ccv_nnc_symbolic_graph_set_carry_overs(while_graph, TENSOR_SYMBOL_MAP(KV(y, x)));
302
1
  ccv_nnc_symbolic_graph_set_sources(while_graph, GRAPH_EXEC_SYMBOL_LIST(noop));
303
1
  ccv_nnc_symbolic_graph_set_destinations(while_graph, GRAPH_EXEC_SYMBOL_LIST(conv));
304
1
  ccv_nnc_graph_t* graph = 0;
305
1
  ccv_nnc_tensor_arena_t* tensor_arena = 0;
306
1
  ccv_nnc_graph_exec_arena_t* graph_exec_arena = 0;
307
1
  ccv_nnc_graph_exec_symbol_autogen(symbolic_graph, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS);
308
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);
309
1
  SYMBOLIC_GRAPH_GEN(symbolic_graph, CCV_NNC_LONG_DOT_GRAPH);
310
1
  GRAPH_GEN(graph, CCV_NNC_LONG_DOT_GRAPH);
311
1
  ccv_nnc_tensor_t* x_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, x);
312
1
  ccv_nnc_tensor_t* w_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, w);
313
1
  ccv_nnc_tensor_t* b_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, b);
314
1
  ccv_nnc_tensor_t* y_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, y);
315
1
  ccv_nnc_tensor_t* z0_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, z0);
316
1
  ccv_nnc_tensor_t* z1_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, z1);
317
1
  int i;
318
1
  dsfmt_t dsfmt;
319
1
  dsfmt_init_gen_rand(&dsfmt, 0);
320
101
  for (i = 0; i < 5 * 5 * 4; 
i++100
)
321
100
    x_tensor->data.f32[i] = dsfmt_genrand_open_close(&dsfmt);
322
1
  ccv_nnc_tensor_t* x1 = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 5, 5, 4), 0);
323
1
  memcpy(x1->data.f32, x_tensor->data.f32, sizeof(float) * 5 * 5 * 4);
324
145
  for (i = 0; i < 4 * 3 * 3 * 4; 
i++144
)
325
144
    w_tensor->data.f32[i] = dsfmt_genrand_open_close(&dsfmt) / (4 * 3 * 3);
326
5
  for (i = 0; i < 4; 
i++4
)
327
4
    b_tensor->data.f32[i] = 0.1;
328
101
  for (i = 0; i < 5 * 5 * 4; 
i++100
)
329
100
    y_tensor->data.f32[i] = 1;
330
1
  REQUIRE(y_tensor->data.f32 != x_tensor->data.f32, "y tensor and x tensor should point to different data");
331
1
  ccv_nnc_tensor_t* y1 = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 5, 5, 4), 0);
332
6
  for (i = 0; i < 5; 
i++5
)
333
5
  {
334
5
    ccv_nnc_cmd_exec(CMD_CONVOLUTION_FORWARD(1, 4, 3, 3, 4), HINT((1, 1), (1, 1)), 0, TENSOR_LIST(x1, w_tensor, b_tensor), TENSOR_LIST(y1), 0);
335
5
    memcpy(x1->data.f32, y1->data.f32, sizeof(float) * 5 * 5 * 4);
336
5
  }
337
1
  ccv_nnc_graph_autotune(graph, 0, 0, TRAVERSE_FULL);
338
1
  ccv_nnc_graph_run(graph, 0, TRAVERSE_FULL, 0, 0);
339
1
  REQUIRE_MATRIX_EQ(y1, y_tensor, "5x5x4 matrix should be exactly the same");
340
1
  REQUIRE(z0_tensor->data.f32 == y_tensor->data.f32 + 1, "z0 should point to the same memory region as y, offset by 1");
341
  // z0 and z1 trigger different code path (z1 will trigger one additional tensor setup).
342
1
  REQUIRE(z1_tensor->data.f32 == y_tensor->data.f32 + 4, "z1 should point to the same memory region as y, offset by 4");
343
1
  ccv_nnc_tensor_free(x1);
344
1
  ccv_nnc_tensor_free(y1);
345
1
  ccv_nnc_symbolic_graph_free(symbolic_graph);
346
1
  ccv_nnc_graph_exec_arena_free(graph_exec_arena);
347
1
  ccv_nnc_tensor_arena_free(tensor_arena);
348
1
  ccv_nnc_graph_free(graph);
349
1
}
350
351
TEST_CASE("symbolic graph for a while loop to compute x = conv(x, w, b) 5 times then z = x0 + x")
352
1
{
353
1
  ccv_nnc_symbolic_graph_t* symbolic_graph = ccv_nnc_symbolic_graph_new();
354
1
  ccv_nnc_symbolic_graph_t* while_graph = ccv_nnc_symbolic_graph_new();
355
1
  ccv_nnc_symbolic_graph_while(symbolic_graph, CCV_NNC_GRAPH_FORWARD, while_graph, "while 1..5");
356
1
  ccv_nnc_tensor_symbol_t x = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 5, 5, 4), "x");
357
1
  ccv_nnc_tensor_symbol_t w = ccv_nnc_tensor_symbol_new(while_graph, CPU_TENSOR_NHWC(32F, 4, 3, 3, 4), "w");
358
1
  ccv_nnc_tensor_symbol_t b = ccv_nnc_tensor_symbol_new(while_graph, CPU_TENSOR_NHWC(32F, 4), "b");
359
1
  ccv_nnc_tensor_symbol_t y = ccv_nnc_tensor_symbol_new(while_graph, CPU_TENSOR_NHWC(32F, 5, 5, 4), "y");
360
1
  ccv_nnc_graph_exec_symbol_t noop = ccv_nnc_graph_exec_symbol_new(while_graph, CMD_NOOP(), 0, 0, 0, 0, "noop");
361
1
  ccv_nnc_graph_exec_symbol_t conv = ccv_nnc_graph_exec_symbol_new(while_graph, CMD_CONVOLUTION_FORWARD(1, 4, 3, 3, 4), TENSOR_SYMBOL_LIST(x, w, b), TENSOR_SYMBOL_LIST(y), "conv");
362
1
  ccv_nnc_graph_exec_symbol_concat(while_graph, noop, conv);
363
1
  ccv_nnc_tensor_symbol_t xz = ccv_nnc_tensor_symbol_alias_new(symbolic_graph, x, ccv_nnc_no_ofs, DIM_ALLOC(1), CPU_TENSOR_NHWC(32F, 5 * 5 * 4), "x0");
364
1
  ccv_nnc_tensor_symbol_t yz = ccv_nnc_tensor_symbol_alias_new(while_graph, y, ccv_nnc_no_ofs, DIM_ALLOC(1), CPU_TENSOR_NHWC(32F, 5 * 5 * 4), "y0");
365
1
  ccv_nnc_tensor_symbol_t z = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 5 * 5 * 4), "z");
366
1
  ccv_nnc_graph_exec_symbol_new(symbolic_graph, CMD_EWSUM_FORWARD(), TENSOR_SYMBOL_LIST(xz, yz), TENSOR_SYMBOL_LIST(z), "sum");
367
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(noop));
368
1
  ccv_nnc_symbolic_graph_set_carry_overs(while_graph, TENSOR_SYMBOL_MAP(KV(y, x)));
369
1
  ccv_nnc_symbolic_graph_set_sources(while_graph, GRAPH_EXEC_SYMBOL_LIST(noop));
370
1
  ccv_nnc_symbolic_graph_set_destinations(while_graph, GRAPH_EXEC_SYMBOL_LIST(conv));
371
1
  ccv_nnc_graph_t* graph = 0;
372
1
  ccv_nnc_tensor_arena_t* tensor_arena = 0;
373
1
  ccv_nnc_graph_exec_arena_t* graph_exec_arena = 0;
374
1
  ccv_nnc_graph_exec_symbol_autogen(symbolic_graph, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS);
375
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);
376
1
  SYMBOLIC_GRAPH_GEN(symbolic_graph, CCV_NNC_LONG_DOT_GRAPH);
377
1
  GRAPH_GEN(graph, CCV_NNC_LONG_DOT_GRAPH);
378
1
  ccv_nnc_tensor_t* x_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, x);
379
1
  ccv_nnc_tensor_t* w_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, w);
380
1
  ccv_nnc_tensor_t* b_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, b);
381
1
  ccv_nnc_tensor_t* y_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, y);
382
1
  ccv_nnc_tensor_t* z_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, z);
383
1
  int i;
384
1
  dsfmt_t dsfmt;
385
1
  dsfmt_init_gen_rand(&dsfmt, 0);
386
101
  for (i = 0; i < 5 * 5 * 4; 
i++100
)
387
100
    x_tensor->data.f32[i] = dsfmt_genrand_open_close(&dsfmt);
388
1
  ccv_nnc_tensor_t* x0 = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 5, 5, 4), 0);
389
1
  ccv_nnc_tensor_t* x1 = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 5, 5, 4), 0);
390
1
  memcpy(x0->data.f32, x_tensor->data.f32, sizeof(float) * 5 * 5 * 4);
391
1
  memcpy(x1->data.f32, x_tensor->data.f32, sizeof(float) * 5 * 5 * 4);
392
145
  for (i = 0; i < 4 * 3 * 3 * 4; 
i++144
)
393
144
    w_tensor->data.f32[i] = dsfmt_genrand_open_close(&dsfmt) / (4 * 3 * 3);
394
5
  for (i = 0; i < 4; 
i++4
)
395
4
    b_tensor->data.f32[i] = 0.1;
396
101
  for (i = 0; i < 5 * 5 * 4; 
i++100
)
397
100
    y_tensor->data.f32[i] = 1;
398
1
  REQUIRE(y_tensor->data.f32 != x_tensor->data.f32, "y tensor and x tensor should point to different data");
399
1
  ccv_nnc_tensor_t* y1 = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 5, 5, 4), 0);
400
6
  for (i = 0; i < 5; 
i++5
)
401
5
  {
402
5
    ccv_nnc_cmd_exec(CMD_CONVOLUTION_FORWARD(1, 4, 3, 3, 4), HINT((1, 1), (1, 1)), 0, TENSOR_LIST(x1, w_tensor, b_tensor), TENSOR_LIST(y1), 0);
403
5
    memcpy(x1->data.f32, y1->data.f32, sizeof(float) * 5 * 5 * 4);
404
5
  }
405
101
  for (i = 0; i < 5 * 5 * 4; 
i++100
)
406
100
    x0->data.f32[i] += y1->data.f32[i];
407
1
  ccv_nnc_tensor_t z0 = ccv_nnc_tensor(x0->data.f32, CPU_TENSOR_NHWC(32F, 5 * 5 * 4), 0);
408
1
  ccv_nnc_graph_autotune(graph, 0, 0, TRAVERSE_FULL);
409
1
  ccv_nnc_graph_run(graph, 0, TRAVERSE_FULL, 0, 0);
410
1
  REQUIRE_MATRIX_EQ(&z0, z_tensor, "5x5x4 matrix should be exactly the same");
411
1
  ccv_nnc_tensor_free(x0);
412
1
  ccv_nnc_tensor_free(x1);
413
1
  ccv_nnc_tensor_free(y1);
414
1
  ccv_nnc_symbolic_graph_free(symbolic_graph);
415
1
  ccv_nnc_graph_exec_arena_free(graph_exec_arena);
416
1
  ccv_nnc_tensor_arena_free(tensor_arena);
417
1
  ccv_nnc_graph_free(graph);
418
1
}
419
420
TEST_CASE("symbolic graph for a while loop to compute (x = conv(x, w, b) 5 times, z = x0 + x (x <- z)) 5 times")
421
1
{
422
1
  ccv_nnc_symbolic_graph_t* symbolic_graph = ccv_nnc_symbolic_graph_new();
423
1
  ccv_nnc_symbolic_graph_t* while_graph = ccv_nnc_symbolic_graph_new();
424
1
  ccv_nnc_symbolic_graph_t* sub_while_graph = ccv_nnc_symbolic_graph_new();
425
1
  ccv_nnc_symbolic_graph_while(symbolic_graph, CCV_NNC_GRAPH_FORWARD, while_graph, "while 1..5");
426
1
  ccv_nnc_graph_exec_symbol_t sub_while = ccv_nnc_symbolic_graph_while(while_graph, CCV_NNC_GRAPH_FORWARD, sub_while_graph, "while 1..5");
427
1
  ccv_nnc_tensor_symbol_t x = ccv_nnc_tensor_symbol_new(while_graph, CPU_TENSOR_NHWC(32F, 5, 5, 4), "x");
428
1
  ccv_nnc_tensor_symbol_t w = ccv_nnc_tensor_symbol_new(sub_while_graph, CPU_TENSOR_NHWC(32F, 4, 3, 3, 4), "w");
429
1
  ccv_nnc_tensor_symbol_t b = ccv_nnc_tensor_symbol_new(sub_while_graph, CPU_TENSOR_NHWC(32F, 4), "b");
430
1
  ccv_nnc_tensor_symbol_t y = ccv_nnc_tensor_symbol_new(while_graph, CPU_TENSOR_NHWC(32F, 5, 5, 4), "y");
431
1
  ccv_nnc_graph_exec_symbol_t sub_noop = ccv_nnc_graph_exec_symbol_new(sub_while_graph, CMD_NOOP(), 0, 0, 0, 0, "noop");
432
1
  ccv_nnc_graph_exec_symbol_t conv = ccv_nnc_graph_exec_symbol_new(sub_while_graph, CMD_CONVOLUTION_FORWARD(1, 4, 3, 3, 4), TENSOR_SYMBOL_LIST(x, w, b), TENSOR_SYMBOL_LIST(y), "conv");
433
1
  ccv_nnc_graph_exec_symbol_concat(sub_while_graph, sub_noop, conv);
434
1
  ccv_nnc_tensor_symbol_t xz = ccv_nnc_tensor_symbol_alias_new(while_graph, x, ccv_nnc_no_ofs, DIM_ALLOC(1), CPU_TENSOR_NHWC(32F, 5 * 5 * 4), "x0");
435
1
  ccv_nnc_tensor_symbol_t yz = ccv_nnc_tensor_symbol_alias_new(while_graph, y, ccv_nnc_no_ofs, DIM_ALLOC(1), CPU_TENSOR_NHWC(32F, 5 * 5 * 4), "y0");
436
1
  ccv_nnc_tensor_symbol_t z = ccv_nnc_tensor_symbol_new(while_graph, CPU_TENSOR_NHWC(32F, 5, 5, 4), "z");
437
1
  ccv_nnc_tensor_symbol_t zz = ccv_nnc_tensor_symbol_alias_new(while_graph, z, ccv_nnc_no_ofs, DIM_ALLOC(1), CPU_TENSOR_NHWC(32F, 5 * 5 * 4), "z0");
438
1
  ccv_nnc_graph_exec_symbol_t sum = ccv_nnc_graph_exec_symbol_new(while_graph, CMD_EWSUM_FORWARD(), TENSOR_SYMBOL_LIST(xz, yz), TENSOR_SYMBOL_LIST(zz), "sum");
439
1
  ccv_nnc_symbolic_graph_set_while_expr(sub_while_graph, while_5, 0, TENSOR_SYMBOL_LIST(ccv_nnc_tensor_symbol_for_while_count(sub_while_graph), ccv_nnc_tensor_symbol_for_while_count(while_graph)), GRAPH_EXEC_SYMBOL_LIST(sub_noop));
440
1
  ccv_nnc_symbolic_graph_set_carry_overs(sub_while_graph, TENSOR_SYMBOL_MAP(KV(y, x)));
441
1
  ccv_nnc_symbolic_graph_set_sources(sub_while_graph, GRAPH_EXEC_SYMBOL_LIST(sub_noop));
442
1
  ccv_nnc_symbolic_graph_set_destinations(sub_while_graph, GRAPH_EXEC_SYMBOL_LIST(conv));
443
1
  ccv_nnc_graph_exec_symbol_t noop = ccv_nnc_graph_exec_symbol_new(while_graph, CMD_NOOP(), 0, 0, 0, 0, "noop");
444
1
  ccv_nnc_graph_exec_symbol_concat(while_graph, noop, sub_while);
445
1
  ccv_nnc_graph_exec_symbol_concat(while_graph, sub_while, sum);
446
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(noop));
447
1
  ccv_nnc_symbolic_graph_set_carry_overs(while_graph, TENSOR_SYMBOL_MAP(KV(z, x)));
448
1
  ccv_nnc_symbolic_graph_set_sources(while_graph, GRAPH_EXEC_SYMBOL_LIST(noop));
449
1
  ccv_nnc_symbolic_graph_set_destinations(while_graph, GRAPH_EXEC_SYMBOL_LIST(sum));
450
1
  ccv_nnc_graph_exec_symbol_autogen(symbolic_graph, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS);
451
1
  SYMBOLIC_GRAPH_GEN(symbolic_graph, CCV_NNC_LONG_DOT_GRAPH);
452
1
  ccv_nnc_graph_t* graph = 0;
453
1
  ccv_nnc_tensor_arena_t* tensor_arena = 0;
454
1
  ccv_nnc_graph_exec_arena_t* graph_exec_arena = 0;
455
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);
456
1
  GRAPH_GEN(graph, CCV_NNC_LONG_DOT_GRAPH);
457
1
  ccv_nnc_tensor_t* x_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, x);
458
1
  ccv_nnc_tensor_t* w_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, w);
459
1
  ccv_nnc_tensor_t* b_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, b);
460
1
  ccv_nnc_tensor_t* y_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, y);
461
1
  ccv_nnc_tensor_t* z_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, z);
462
1
  int i, j;
463
1
  dsfmt_t dsfmt;
464
1
  dsfmt_init_gen_rand(&dsfmt, 0);
465
101
  for (i = 0; i < 5 * 5 * 4; 
i++100
)
466
100
    x_tensor->data.f32[i] = dsfmt_genrand_open_close(&dsfmt);
467
1
  ccv_nnc_tensor_t* x0 = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 5, 5, 4), 0);
468
1
  ccv_nnc_tensor_t* x1 = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 5, 5, 4), 0);
469
1
  memcpy(x0->data.f32, x_tensor->data.f32, sizeof(float) * 5 * 5 * 4);
470
145
  for (i = 0; i < 4 * 3 * 3 * 4; 
i++144
)
471
144
    w_tensor->data.f32[i] = dsfmt_genrand_open_close(&dsfmt) / (4 * 3 * 3);
472
5
  for (i = 0; i < 4; 
i++4
)
473
4
    b_tensor->data.f32[i] = 0.1;
474
101
  for (i = 0; i < 5 * 5 * 4; 
i++100
)
475
100
    y_tensor->data.f32[i] = 1;
476
1
  REQUIRE(y_tensor->data.f32 != x_tensor->data.f32, "y tensor and x tensor should point to different data");
477
1
  ccv_nnc_tensor_t* y1 = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 5, 5, 4), 0);
478
6
  for (i = 0; i < 5; 
i++5
)
479
5
  {
480
5
    memcpy(x1->data.f32, x0->data.f32, sizeof(float) * 5 * 5 * 4);
481
30
    for (j = 0; j < 5; 
j++25
)
482
25
    {
483
25
      ccv_nnc_cmd_exec(CMD_CONVOLUTION_FORWARD(1, 4, 3, 3, 4), HINT((1, 1), (1, 1)), 0, TENSOR_LIST(x1, w_tensor, b_tensor), TENSOR_LIST(y1), 0);
484
25
      memcpy(x1->data.f32, y1->data.f32, sizeof(float) * 5 * 5 * 4);
485
25
    }
486
505
    for (j = 0; j < 5 * 5 * 4; 
j++500
)
487
500
      x0->data.f32[j] += y1->data.f32[j];
488
5
  }
489
1
  ccv_nnc_graph_autotune(graph, 0, 0, TRAVERSE_FULL);
490
1
  ccv_nnc_graph_run(graph, 0, TRAVERSE_FULL, 0, 0);
491
1
  REQUIRE_MATRIX_EQ(x0, z_tensor, "5x5x4 matrix should be exactly the same");
492
1
  ccv_nnc_tensor_free(x0);
493
1
  ccv_nnc_tensor_free(x1);
494
1
  ccv_nnc_tensor_free(y1);
495
1
  ccv_nnc_graph_exec_arena_free(graph_exec_arena);
496
1
  ccv_nnc_tensor_arena_free(tensor_arena);
497
1
  ccv_nnc_graph_free(graph);
498
1
  ccv_nnc_symbolic_graph_free(symbolic_graph);
499
1
}
500
501
TEST_CASE("symbolic graph for a while loop to compute y = conv(x1, w, b), x2 = x0 + y 5 times, (x0 <- x1, x1 <- x2)")
502
1
{
503
1
  ccv_nnc_symbolic_graph_t* symbolic_graph = ccv_nnc_symbolic_graph_new();
504
1
  ccv_nnc_symbolic_graph_t* while_graph = ccv_nnc_symbolic_graph_new();
505
1
  ccv_nnc_symbolic_graph_while(symbolic_graph, CCV_NNC_GRAPH_FORWARD, while_graph, "while 1..5");
506
1
  ccv_nnc_tensor_symbol_t x1 = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 5, 5, 4), "x1");
507
1
  ccv_nnc_tensor_symbol_t x0 = ccv_nnc_tensor_symbol_new(while_graph, CPU_TENSOR_NHWC(32F, 5, 5, 4), "x0");
508
1
  ccv_nnc_tensor_symbol_t w = ccv_nnc_tensor_symbol_new(while_graph, CPU_TENSOR_NHWC(32F, 4, 3, 3, 4), "w");
509
1
  ccv_nnc_tensor_symbol_t b = ccv_nnc_tensor_symbol_new(while_graph, CPU_TENSOR_NHWC(32F, 4), "b");
510
1
  ccv_nnc_tensor_symbol_t y = ccv_nnc_tensor_symbol_new(while_graph, CPU_TENSOR_NHWC(32F, 5, 5, 4), "y");
511
1
  ccv_nnc_graph_exec_symbol_t noop = ccv_nnc_graph_exec_symbol_new(while_graph, CMD_NOOP(), 0, 0, 0, 0, "noop");
512
1
  ccv_nnc_graph_exec_symbol_t conv = ccv_nnc_graph_exec_symbol_new(while_graph, CMD_CONVOLUTION_FORWARD(1, 4, 3, 3, 4), TENSOR_SYMBOL_LIST(x1, w, b), TENSOR_SYMBOL_LIST(y), "conv");
513
1
  ccv_nnc_graph_exec_symbol_concat(while_graph, noop, conv);
514
1
  ccv_nnc_tensor_symbol_t x0z = ccv_nnc_tensor_symbol_alias_new(while_graph, x0, ccv_nnc_no_ofs, DIM_ALLOC(1), CPU_TENSOR_NHWC(32F, 5 * 5 * 4), "x0");
515
1
  ccv_nnc_tensor_symbol_t yz = ccv_nnc_tensor_symbol_alias_new(while_graph, y, ccv_nnc_no_ofs, DIM_ALLOC(1), CPU_TENSOR_NHWC(32F, 5 * 5 * 4), "y");
516
1
  ccv_nnc_tensor_symbol_t x2 = ccv_nnc_tensor_symbol_new(while_graph, CPU_TENSOR_NHWC(32F, 5, 5, 4), "x2");
517
1
  ccv_nnc_tensor_symbol_t x2z = ccv_nnc_tensor_symbol_alias_new(while_graph, x2, ccv_nnc_no_ofs, DIM_ALLOC(1), CPU_TENSOR_NHWC(32F, 5 * 5 * 4), "x2");
518
1
  ccv_nnc_graph_exec_symbol_new(while_graph, CMD_EWSUM_FORWARD(), TENSOR_SYMBOL_LIST(x0z, yz), TENSOR_SYMBOL_LIST(x2z), "sum");
519
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(noop));
520
1
  ccv_nnc_symbolic_graph_set_carry_overs(while_graph, TENSOR_SYMBOL_MAP(KV(x2, x1), KV(x1, x0)));
521
1
  ccv_nnc_symbolic_graph_set_sources(while_graph, GRAPH_EXEC_SYMBOL_LIST(noop));
522
1
  ccv_nnc_symbolic_graph_set_destinations(while_graph, GRAPH_EXEC_SYMBOL_LIST(conv));
523
1
  ccv_nnc_graph_t* graph = 0;
524
1
  ccv_nnc_tensor_arena_t* tensor_arena = 0;
525
1
  ccv_nnc_graph_exec_arena_t* graph_exec_arena = 0;
526
1
  ccv_nnc_graph_exec_symbol_autogen(symbolic_graph, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS);
527
1
  SYMBOLIC_GRAPH_GEN(symbolic_graph, CCV_NNC_LONG_DOT_GRAPH);
528
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);
529
1
  GRAPH_GEN(graph, CCV_NNC_LONG_DOT_GRAPH);
530
1
  ccv_nnc_tensor_t* x0_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, x0);
531
1
  ccv_nnc_tensor_t* x1_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, x1);
532
1
  ccv_nnc_tensor_t* w_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, w);
533
1
  ccv_nnc_tensor_t* b_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, b);
534
1
  ccv_nnc_tensor_t* y_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, y);
535
1
  int i, j;
536
1
  memset(x0_tensor->data.f32, 0, sizeof(float) * 5 * 5 * 4);
537
1
  dsfmt_t dsfmt;
538
1
  dsfmt_init_gen_rand(&dsfmt, 0);
539
101
  for (i = 0; i < 5 * 5 * 4; 
i++100
)
540
100
    x1_tensor->data.f32[i] = dsfmt_genrand_open_close(&dsfmt);
541
145
  for (i = 0; i < 4 * 3 * 3 * 4; 
i++144
)
542
144
    w_tensor->data.f32[i] = dsfmt_genrand_open_close(&dsfmt) / (4 * 3 * 3);
543
5
  for (i = 0; i < 4; 
i++4
)
544
4
    b_tensor->data.f32[i] = 0.1;
545
101
  for (i = 0; i < 5 * 5 * 4; 
i++100
)
546
100
    y_tensor->data.f32[i] = 1;
547
1
  ccv_nnc_tensor_t* x0t = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 5, 5, 4), 0);
548
1
  memset(x0t->data.f32, 0, sizeof(float) * 5 * 5 * 4);
549
1
  ccv_nnc_tensor_t* x1t = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 5, 5, 4), 0);
550
1
  memcpy(x1t->data.f32, x1_tensor->data.f32, sizeof(float) * 5 * 5 * 4);
551
1
  ccv_nnc_tensor_t* x2t = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 5, 5, 4), 0);
552
6
  for (i = 0; i < 5; 
i++5
)
553
5
  {
554
5
    ccv_nnc_cmd_exec(CMD_CONVOLUTION_FORWARD(1, 4, 3, 3, 4), HINT((1, 1), (1, 1)), 0, TENSOR_LIST(x1t, w_tensor, b_tensor), TENSOR_LIST(x2t), 0);
555
505
    for (j = 0; j < 5 * 5 * 4; 
j++500
)
556
500
      x2t->data.f32[j] += x0t->data.f32[j];
557
5
    memcpy(x0t->data.f32, x1t->data.f32, sizeof(float) * 5 * 5 * 4);
558
5
    memcpy(x1t->data.f32, x2t->data.f32, sizeof(float) * 5 * 5 * 4);
559
5
  }
560
1
  ccv_nnc_graph_autotune(graph, 0, 0, TRAVERSE_FULL);
561
1
  ccv_nnc_graph_run(graph, 0, TRAVERSE_FULL, 0, 0);
562
1
  ccv_nnc_tensor_t* x2_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, x2);
563
1
  REQUIRE_MATRIX_EQ(x2t, x2_tensor, "5x5x4 matrix should be exactly the same");
564
1
  ccv_nnc_tensor_free(x0t);
565
1
  ccv_nnc_tensor_free(x1t);
566
1
  ccv_nnc_tensor_free(x2t);
567
1
  ccv_nnc_symbolic_graph_free(symbolic_graph);
568
1
  ccv_nnc_graph_exec_arena_free(graph_exec_arena);
569
1
  ccv_nnc_tensor_arena_free(tensor_arena);
570
1
  ccv_nnc_graph_free(graph);
571
1
}
572
573
TEST_CASE("a while loop to compute y = conv(x1, w, b), y1 = 1.2 * y, x3 = x0 + y1 5 times, then z = y + x3 + x2 + x1 + x0, (x0 <- x1, x1 <- x2, x2 <- x3)")
574
1
{
575
1
  ccv_nnc_symbolic_graph_t* symbolic_graph = ccv_nnc_symbolic_graph_new();
576
1
  ccv_nnc_symbolic_graph_t* while_graph = ccv_nnc_symbolic_graph_new();
577
1
  ccv_nnc_symbolic_graph_while(symbolic_graph, CCV_NNC_GRAPH_FORWARD, while_graph, "while 1..5");
578
1
  ccv_nnc_tensor_symbol_t x1 = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 5, 5, 4), "x1");
579
1
  ccv_nnc_tensor_symbol_t y0 = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 5 * 5 * 4), "y0");
580
1
  ccv_nnc_tensor_symbol_t x0 = ccv_nnc_tensor_symbol_new(while_graph, CPU_TENSOR_NHWC(32F, 5, 5, 4), "x0");
581
1
  ccv_nnc_tensor_symbol_t w = ccv_nnc_tensor_symbol_new(while_graph, CPU_TENSOR_NHWC(32F, 4, 3, 3, 4), "w");
582
1
  ccv_nnc_tensor_symbol_t b = ccv_nnc_tensor_symbol_new(while_graph, CPU_TENSOR_NHWC(32F, 4), "b");
583
1
  ccv_nnc_tensor_symbol_t y = ccv_nnc_tensor_symbol_new(while_graph, CPU_TENSOR_NHWC(32F, 5, 5, 4), "y");
584
1
  ccv_nnc_tensor_symbol_t y1 = ccv_nnc_tensor_symbol_new(while_graph, CPU_TENSOR_NHWC(32F, 5 * 5 * 4), "y1");
585
1
  ccv_nnc_graph_exec_symbol_t noop = ccv_nnc_graph_exec_symbol_new(while_graph, CMD_NOOP(), 0, 0, 0, 0, "noop");
586
1
  ccv_nnc_graph_exec_symbol_t conv = ccv_nnc_graph_exec_symbol_new(while_graph, CMD_CONVOLUTION_FORWARD(1, 4, 3, 3, 4), TENSOR_SYMBOL_LIST(x1, w, b), TENSOR_SYMBOL_LIST(y), "conv");
587
1
  ccv_nnc_graph_exec_symbol_concat(while_graph, noop, conv);
588
1
  ccv_nnc_tensor_symbol_t x0z = ccv_nnc_tensor_symbol_alias_new(while_graph, x0, ccv_nnc_no_ofs, DIM_ALLOC(1), CPU_TENSOR_NHWC(32F, 5 * 5 * 4), "x0");
589
1
  ccv_nnc_tensor_symbol_t yz = ccv_nnc_tensor_symbol_alias_new(while_graph, y, ccv_nnc_no_ofs, DIM_ALLOC(1), CPU_TENSOR_NHWC(32F, 5 * 5 * 4), "y");
590
1
  ccv_nnc_graph_exec_symbol_new(while_graph, CMD_EWPROD_FORWARD(), TENSOR_SYMBOL_LIST(yz, y0), TENSOR_SYMBOL_LIST(y1), "prod");
591
1
  ccv_nnc_tensor_symbol_t x2 = ccv_nnc_tensor_symbol_new(while_graph, CPU_TENSOR_NHWC(32F, 5, 5, 4), "x2");
592
1
  ccv_nnc_tensor_symbol_t x2z = ccv_nnc_tensor_symbol_alias_new(while_graph, x2, ccv_nnc_no_ofs, DIM_ALLOC(1), CPU_TENSOR_NHWC(32F, 5 * 5 * 4), "x2");
593
1
  ccv_nnc_tensor_symbol_t x3 = ccv_nnc_tensor_symbol_new(while_graph, CPU_TENSOR_NHWC(32F, 5, 5, 4), "x3");
594
1
  ccv_nnc_tensor_symbol_t x3z = ccv_nnc_tensor_symbol_alias_new(while_graph, x3, ccv_nnc_no_ofs, DIM_ALLOC(1), CPU_TENSOR_NHWC(32F, 5 * 5 * 4), "x2");
595
1
  ccv_nnc_graph_exec_symbol_new(while_graph, CMD_EWSUM_FORWARD(), TENSOR_SYMBOL_LIST(x0z, y1), TENSOR_SYMBOL_LIST(x3z), "sum");
596
1
  ccv_nnc_tensor_symbol_t x1s = ccv_nnc_tensor_symbol_resolve(while_graph, x1);
597
1
  ccv_nnc_tensor_symbol_t x1z = ccv_nnc_tensor_symbol_alias_new(while_graph, x1s, ccv_nnc_no_ofs, DIM_ALLOC(1), CPU_TENSOR_NHWC(32F, 5 * 5 * 4), "x1");
598
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(noop));
599
1
  ccv_nnc_symbolic_graph_set_carry_overs(while_graph, TENSOR_SYMBOL_MAP(KV(x3, x2), KV(x2, x1), KV(x1, x0)));
600
1
  ccv_nnc_symbolic_graph_set_sources(while_graph, GRAPH_EXEC_SYMBOL_LIST(noop));
601
1
  ccv_nnc_symbolic_graph_set_destinations(while_graph, GRAPH_EXEC_SYMBOL_LIST(conv));
602
1
  ccv_nnc_tensor_symbol_t z = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 5 * 5 * 4), "z");
603
1
  ccv_nnc_graph_exec_symbol_new(symbolic_graph, CMD_EWSUM_FORWARD(), TENSOR_SYMBOL_LIST(yz, x0z, x1z, x2z, x3z), TENSOR_SYMBOL_LIST(z), "sum1");
604
1
  ccv_nnc_graph_t* graph = 0;
605
1
  ccv_nnc_tensor_arena_t* tensor_arena = 0;
606
1
  ccv_nnc_graph_exec_arena_t* graph_exec_arena = 0;
607
1
  ccv_nnc_graph_exec_symbol_autogen(symbolic_graph, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS);
608
1
  SYMBOLIC_GRAPH_GEN(symbolic_graph, CCV_NNC_LONG_DOT_GRAPH);
609
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);
610
1
  GRAPH_GEN(graph, CCV_NNC_LONG_DOT_GRAPH);
611
1
  ccv_nnc_tensor_t* x0_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, x0);
612
1
  ccv_nnc_tensor_t* x1_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, x1);
613
1
  ccv_nnc_tensor_t* w_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, w);
614
1
  ccv_nnc_tensor_t* b_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, b);
615
1
  ccv_nnc_tensor_t* y_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, y);
616
1
  ccv_nnc_tensor_t* y0_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, y0);
617
1
  int i, j;
618
1
  memset(x0_tensor->data.f32, 0, sizeof(float) * 5 * 5 * 4);
619
1
  dsfmt_t dsfmt;
620
1
  dsfmt_init_gen_rand(&dsfmt, 0);
621
101
  for (i = 0; i < 5 * 5 * 4; 
i++100
)
622
100
    x1_tensor->data.f32[i] = dsfmt_genrand_open_close(&dsfmt);
623
145
  for (i = 0; i < 4 * 3 * 3 * 4; 
i++144
)
624
144
    w_tensor->data.f32[i] = dsfmt_genrand_open_close(&dsfmt) / (4 * 3 * 3);
625
5
  for (i = 0; i < 4; 
i++4
)
626
4
    b_tensor->data.f32[i] = 0.1;
627
101
  for (i = 0; i < 5 * 5 * 4; 
i++100
)
628
100
    y_tensor->data.f32[i] = 1;
629
101
  for (i = 0; i < 5 * 5 * 4; 
i++100
)
630
100
    y0_tensor->data.f32[i] = 1.2;
631
1
  ccv_nnc_tensor_t* yt = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 5, 5, 4), 0);
632
1
  ccv_nnc_tensor_t* x0t = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 5, 5, 4), 0);
633
1
  memset(x0t->data.f32, 0, sizeof(float) * 5 * 5 * 4);
634
1
  ccv_nnc_tensor_t* x1t = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 5, 5, 4), 0);
635
1
  memcpy(x1t->data.f32, x1_tensor->data.f32, sizeof(float) * 5 * 5 * 4);
636
1
  ccv_nnc_tensor_t* x2t = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 5, 5, 4), 0);
637
1
  ccv_nnc_tensor_t* x3t = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 5, 5, 4), 0);
638
6
  for (i = 0; i < 5; 
i++5
)
639
5
  {
640
5
    ccv_nnc_cmd_exec(CMD_CONVOLUTION_FORWARD(1, 4, 3, 3, 4), HINT((1, 1), (1, 1)), 0, TENSOR_LIST(x1t, w_tensor, b_tensor), TENSOR_LIST(yt), 0);
641
505
    for (j = 0; j < 5 * 5 * 4; 
j++500
)
642
500
      x3t->data.f32[j] = 1.2 * yt->data.f32[j] + x0t->data.f32[j];
643
5
    memcpy(x0t->data.f32, x1t->data.f32, sizeof(float) * 5 * 5 * 4);
644
5
    memcpy(x1t->data.f32, x2t->data.f32, sizeof(float) * 5 * 5 * 4);
645
5
    memcpy(x2t->data.f32, x3t->data.f32, sizeof(float) * 5 * 5 * 4);
646
5
  }
647
101
  for (j = 0; j < 5 * 5 * 4; 
j++100
)
648
100
    x3t->data.f32[j] += yt->data.f32[j] + x2t->data.f32[j] + x1t->data.f32[j] + x0t->data.f32[j];
649
1
  ccv_nnc_tensor_t zt = ccv_nnc_tensor(x3t->data.f32, CPU_TENSOR_NHWC(32F, 5 * 5 * 4), 0);
650
1
  ccv_nnc_graph_autotune(graph, 0, 0, TRAVERSE_FULL);
651
1
  ccv_nnc_graph_run(graph, 0, TRAVERSE_FULL, 0, 0);
652
1
  ccv_nnc_tensor_t* z_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, z);
653
1
  REQUIRE_MATRIX_EQ(&zt, z_tensor, "100 vector should be exactly the same");
654
1
  ccv_nnc_tensor_free(yt);
655
1
  ccv_nnc_tensor_free(x0t);
656
1
  ccv_nnc_tensor_free(x1t);
657
1
  ccv_nnc_tensor_free(x2t);
658
1
  ccv_nnc_tensor_free(x3t);
659
1
  ccv_nnc_symbolic_graph_free(symbolic_graph);
660
1
  ccv_nnc_graph_exec_arena_free(graph_exec_arena);
661
1
  ccv_nnc_tensor_arena_free(tensor_arena);
662
1
  ccv_nnc_graph_free(graph);
663
1
}
664
665
#include "case_main.h"