Publishing 2019 R1 content
[platform/upstream/dldt.git] / inference-engine / thirdparty / fluid / modules / gapi / test / internal / gapi_int_gmodel_builder_test.cpp
1 // This file is part of OpenCV project.
2 // It is subject to the license terms in the LICENSE file found in the top-level directory
3 // of this distribution and at http://opencv.org/license.html.
4 //
5 // Copyright (C) 2018-2019 Intel Corporation
6
7
8 #include "test_precomp.hpp"
9
10 #include <ade/util/zip_range.hpp>   // util::indexed
11
12 #include "opencv2/gapi/gkernel.hpp"
13 #include "compiler/gmodelbuilder.hpp"
14 #include "compiler/gmodel.hpp" // RcDesc, GModel::init
15
16 namespace opencv_test
17 {
18
19 namespace test
20 {
21
22 namespace
23 {
24     cv::GMat unaryOp(cv::GMat m)
25     {
26         return cv::GCall(cv::GKernel{"gapi.test.unaryop", nullptr, { GShape::GMAT } }).pass(m).yield(0);
27     }
28
29     cv::GMat binaryOp(cv::GMat m1, cv::GMat m2)
30     {
31         return cv::GCall(cv::GKernel{"gapi.test.binaryOp", nullptr, { GShape::GMAT } }).pass(m1, m2).yield(0);
32     }
33
34     std::vector<ade::NodeHandle> collectOperations(const cv::gimpl::GModel::Graph& gr)
35     {
36         std::vector<ade::NodeHandle> ops;
37         for (const auto& nh : gr.nodes())
38         {
39             if (gr.metadata(nh).get<cv::gimpl::NodeType>().t == cv::gimpl::NodeType::OP)
40                 ops.push_back(nh);
41         }
42         return ops;
43     }
44
45     ade::NodeHandle inputOf(cv::gimpl::GModel::Graph& gm, ade::NodeHandle nh, std::size_t port)
46     {
47         for (const auto& eh : nh->inEdges())
48         {
49             if (gm.metadata(eh).get<cv::gimpl::Input>().port == port)
50             {
51                 return eh->srcNode();
52             }
53         }
54         util::throw_error(std::logic_error("port " + std::to_string(port) + " not found"));
55     }
56 }
57 }// namespace opencv_test::test
58
59 TEST(GModelBuilder, Unroll_TestUnary)
60 {
61     cv::GMat in;
62     cv::GMat out = test::unaryOp(in);
63
64     auto unrolled = cv::gimpl::unrollExpr(cv::GIn(in).m_args, cv::GOut(out).m_args);
65
66     EXPECT_EQ(1u, unrolled.all_ops.size());  // There is one operation
67     EXPECT_EQ(2u, unrolled.all_data.size()); // And two data objects (in, out)
68
69     // TODO check what the operation is, and so on, and so on
70 }
71
72 TEST(GModelBuilder, Unroll_TestUnaryOfUnary)
73 {
74     cv::GMat in;
75     cv::GMat out = test::unaryOp(test::unaryOp(in));
76
77     auto unrolled = cv::gimpl::unrollExpr(cv::GIn(in).m_args, cv::GOut(out).m_args);
78
79     EXPECT_EQ(2u, unrolled.all_ops.size());  // There're two operations
80     EXPECT_EQ(3u, unrolled.all_data.size()); // And three data objects (in, out)
81
82     // TODO check what the operation is, and so on, and so on
83 }
84
85 TEST(GModelBuilder, Unroll_Not_All_Protocol_Inputs_Are_Reached)
86 {
87     cv::GMat in1, in2;                                      // in1 -> unaryOp() -> u_op1 -> unaryOp() -> out
88     auto u_op1 = test::unaryOp(in1);                        // in2 -> unaryOp() -> u_op2
89     auto u_op2 = test::unaryOp(in2);
90     auto out   = test::unaryOp(u_op1);
91
92     EXPECT_THROW(cv::gimpl::unrollExpr(cv::GIn(in1, in2).m_args, cv::GOut(out).m_args), std::logic_error);
93 }
94
95 TEST(GModelBuilder, Unroll_Parallel_Path)
96 {
97     cv::GMat in1, in2;                                      // in1 -> unaryOp() -> out1
98     auto out1 = test::unaryOp(in1);                         // in2 -> unaryOp() -> out2
99     auto out2 = test::unaryOp(in2);
100
101     auto unrolled = cv::gimpl::unrollExpr(cv::GIn(in1, in2).m_args, cv::GOut(out1, out2).m_args);
102
103     EXPECT_EQ(unrolled.all_ops.size(),  2u);
104     EXPECT_EQ(unrolled.all_data.size(), 4u);
105 }
106
107 TEST(GModelBuilder, Unroll_WithBranch)
108 {
109     // in -> unaryOp() -> tmp -->unaryOp() -> out1
110     //                     `---->unaryOp() -> out2
111
112     GMat in;
113     auto tmp = test::unaryOp(in);
114     auto out1 = test::unaryOp(tmp);
115     auto out2 = test::unaryOp(tmp);
116
117     auto unrolled = cv::gimpl::unrollExpr(cv::GIn(in).m_args, cv::GOut(out1, out2).m_args);
118
119     EXPECT_EQ(unrolled.all_ops.size(),  3u);
120     EXPECT_EQ(unrolled.all_data.size(), 4u);
121 }
122
123 TEST(GModelBuilder, Build_Unary)
124 {
125     cv::GMat in;
126     cv::GMat out = test::unaryOp(in);
127
128     ade::Graph g;
129     cv::gimpl::GModel::Graph gm(g);
130     cv::gimpl::GModel::init(gm);
131     cv::gimpl::GModelBuilder(g).put(cv::GIn(in).m_args, cv::GOut(out).m_args);
132
133     EXPECT_EQ(3u, static_cast<std::size_t>(g.nodes().size()));    // Generated graph should have three nodes
134
135     // TODO: Check what the nodes are
136 }
137
138 TEST(GModelBuilder, Constant_GScalar)
139 {
140     // in -> addC()-----(GMat)---->mulC()-----(GMat)---->unaryOp()----out
141     //         ^                     ^
142     //         |                     |
143     // 3-------`           c_s-------'
144
145     cv::GMat in;
146     cv::GScalar c_s = 5;
147     auto out = test::unaryOp((in + 3) * c_s);    // 3 converted to GScalar
148
149     ade::Graph g;
150     cv::gimpl::GModel::Graph gm(g);
151     cv::gimpl::GModel::init(gm);
152     auto proto_slots = cv::gimpl::GModelBuilder(g).put(cv::GIn(in).m_args, cv::GOut(out).m_args);
153     cv::gimpl::Protocol p;
154     std::tie(p.inputs, p.outputs, p.in_nhs, p.out_nhs) = proto_slots;
155
156     auto in_nh   = p.in_nhs.front();
157     auto addC_nh = in_nh->outNodes().front();
158     auto mulC_nh = addC_nh->outNodes().front()->outNodes().front();
159
160     ASSERT_TRUE(gm.metadata(addC_nh).get<cv::gimpl::NodeType>().t == cv::gimpl::NodeType::OP);
161     ASSERT_TRUE(gm.metadata(mulC_nh).get<cv::gimpl::NodeType>().t == cv::gimpl::NodeType::OP);
162
163     auto s_3 = test::inputOf(gm, addC_nh, 1);
164     auto s_5 = test::inputOf(gm, mulC_nh, 1);
165
166     EXPECT_EQ(9u, static_cast<std::size_t>(g.nodes().size()));          // 6 data nodes (1 -input, 1 output, 2 constant, 2 temp) and 3 op nodes
167     EXPECT_EQ(2u, static_cast<std::size_t>(addC_nh->inNodes().size())); // in and 3
168     EXPECT_EQ(2u, static_cast<std::size_t>(mulC_nh->inNodes().size())); // addC output and c_s
169     EXPECT_EQ(3, (util::get<cv::gapi::own::Scalar>(gm.metadata(s_3).get<cv::gimpl::ConstValue>().arg))[0]);
170     EXPECT_EQ(5, (util::get<cv::gapi::own::Scalar>(gm.metadata(s_5).get<cv::gimpl::ConstValue>().arg))[0]);
171 }
172
173 TEST(GModelBuilder, Check_Multiple_Outputs)
174 {
175     //            ------------------------------> r
176     //            '
177     //            '                    -----------> i_out1
178     //            '                    '
179     // in ----> split3() ---> g ---> integral()
180     //            '                    '
181     //            '                    -----------> i_out2
182     //            '
183     //            '---------> b ---> unaryOp() ---> u_out
184
185     cv::GMat in, r, g, b, i_out1, i_out2, u_out;
186     std::tie(r, g, b) = cv::gapi::split3(in);
187     std::tie(i_out1, i_out2) = cv::gapi::integral(g, 1, 1);
188     u_out = test::unaryOp(b);
189
190     ade::Graph gr;
191     cv::gimpl::GModel::Graph gm(gr);
192     cv::gimpl::GModel::init(gm);
193     auto proto_slots = cv::gimpl::GModelBuilder(gr).put(cv::GIn(in).m_args, cv::GOut(r, i_out1, i_out2, u_out).m_args);
194     cv::gimpl::Protocol p;
195     std::tie(p.inputs, p.outputs, p.in_nhs, p.out_nhs) = proto_slots;
196
197     EXPECT_EQ(4u, static_cast<std::size_t>(p.out_nhs.size()));
198     EXPECT_EQ(0u, gm.metadata(p.out_nhs[0]->inEdges().front()).get<cv::gimpl::Output>().port);
199     EXPECT_EQ(0u, gm.metadata(p.out_nhs[1]->inEdges().front()).get<cv::gimpl::Output>().port);
200     EXPECT_EQ(1u, gm.metadata(p.out_nhs[2]->inEdges().front()).get<cv::gimpl::Output>().port);
201     EXPECT_EQ(0u, gm.metadata(p.out_nhs[3]->inEdges().front()).get<cv::gimpl::Output>().port);
202     for (const auto& it : ade::util::indexed(p.out_nhs))
203     {
204         const auto& out_nh = ade::util::value(it);
205
206         EXPECT_EQ(cv::gimpl::NodeType::DATA, gm.metadata(out_nh).get<cv::gimpl::NodeType>().t);
207         EXPECT_EQ(GShape::GMAT, gm.metadata(out_nh).get<cv::gimpl::Data>().shape);
208     }
209 }
210
211 TEST(GModelBuilder, Unused_Outputs)
212 {
213     cv::GMat in;
214     auto yuv_p = cv::gapi::split3(in);
215
216     ade::Graph g;
217     cv::gimpl::GModel::Graph gm(g);
218     cv::gimpl::GModel::init(gm);
219     cv::gimpl::GModelBuilder(g).put(cv::GIn(in).m_args, cv::GOut(std::get<0>(yuv_p)).m_args);
220
221     EXPECT_EQ(5u, static_cast<std::size_t>(g.nodes().size()));    // 1 input, 1 operation, 3 outputs
222 }
223
224 TEST(GModelBuilder, Work_With_One_Channel_From_Split3)
225 {
226     cv::GMat in, y, u, v;
227     std::tie(y, u, v) = cv::gapi::split3(in);
228     auto y_blur = cv::gapi::gaussianBlur(y, cv::Size(3, 3), 1);
229
230     ade::Graph g;
231     cv::gimpl::GModel::Graph gm(g);
232     cv::gimpl::GModel::init(gm);
233     cv::gimpl::GModelBuilder(g).put(cv::GIn(in).m_args, cv::GOut(y_blur).m_args);
234
235     EXPECT_EQ(7u, static_cast<std::size_t>(g.nodes().size())); // 1 input, 2 operation, 3 nodes from split3, 1 output
236 }
237
238 TEST(GModelBuilder, Add_Nodes_To_Unused_Nodes)
239 {
240     cv::GMat in, y, u, v;
241     std::tie(y, u, v) = cv::gapi::split3(in);
242     auto y_blur = cv::gapi::gaussianBlur(y, cv::Size(3, 3), 1);
243     // unused nodes
244     auto u_blur = cv::gapi::gaussianBlur(y, cv::Size(3, 3), 1);
245     auto v_blur = cv::gapi::gaussianBlur(y, cv::Size(3, 3), 1);
246
247     ade::Graph g;
248     cv::gimpl::GModel::Graph gm(g);
249     cv::gimpl::GModel::init(gm);
250     cv::gimpl::GModelBuilder(g).put(cv::GIn(in).m_args, cv::GOut(y_blur).m_args);
251
252     EXPECT_EQ(7u, static_cast<std::size_t>(g.nodes().size())); // 1 input, 2 operation, 3 nodes from split3, 1 output
253 }
254
255 TEST(GModelBuilder, Unlisted_Inputs)
256 {
257     // in1 -> binaryOp() -> out
258     //         ^
259     //         |
260     // in2 ----'
261
262     cv::GMat in1, in2;
263     auto out = test::binaryOp(in1, in2);
264
265     ade::Graph g;
266     cv::gimpl::GModel::Graph gm(g);
267     cv::gimpl::GModel::init(gm);
268     // add required 2 inputs but pass 1
269     EXPECT_THROW(cv::gimpl::GModelBuilder(g).put(cv::GIn(in1).m_args, cv::GOut(out).m_args), std::logic_error);
270 }
271
272 TEST(GModelBuilder, Unroll_No_Link_Between_In_And_Out)
273 {
274     // in    -> unaryOp() -> u_op
275     // other -> unaryOp() -> out
276
277     cv::GMat in, other;
278     auto u_op = test::unaryOp(in);
279     auto out  = test::unaryOp(other);
280
281     EXPECT_THROW(cv::gimpl::unrollExpr(cv::GIn(in).m_args, cv::GOut(out).m_args), std::logic_error);
282 }
283
284
285 TEST(GModel_builder, Check_Binary_Op)
286 {
287     // in1 -> binaryOp() -> out
288     //          ^
289     //          |
290     // in2 -----'
291
292     cv::GMat in1, in2;
293     auto out = test::binaryOp(in1, in2);
294
295     ade::Graph g;
296     cv::gimpl::GModel::Graph gm(g);
297     cv::gimpl::GModel::init(gm);
298     auto proto_slots = cv::gimpl::GModelBuilder(g).put(cv::GIn(in1, in2).m_args, cv::GOut(out).m_args);
299
300     cv::gimpl::Protocol p;
301     std::tie(p.inputs, p.outputs, p.in_nhs, p.out_nhs) = proto_slots;
302     auto ops = test::collectOperations(g);
303
304     EXPECT_EQ(1u, ops.size());
305     EXPECT_EQ("gapi.test.binaryOp", gm.metadata(ops.front()).get<cv::gimpl::Op>().k.name);
306     EXPECT_EQ(2u, static_cast<std::size_t>(ops.front()->inEdges().size()));
307     EXPECT_EQ(1u, static_cast<std::size_t>(ops.front()->outEdges().size()));
308     EXPECT_EQ(1u, static_cast<std::size_t>(ops.front()->outNodes().size()));
309 }
310
311 TEST(GModelBuilder, Add_Operation_With_Two_Out_One_Time)
312 {
313     // in -> integral() --> out_b1 -> unaryOp() -> out1
314     //            |
315     //            '-------> out_b2 -> unaryOp() -> out2
316
317     cv::GMat in, out_b1, out_b2;
318     std::tie(out_b1, out_b2) = cv::gapi::integral(in, 1, 1);
319     auto out1 = test::unaryOp(out_b1);
320     auto out2 = test::unaryOp(out_b1);
321
322     ade::Graph g;
323     cv::gimpl::GModel::Graph gm(g);
324     cv::gimpl::GModel::init(gm);
325     auto proto_slots = cv::gimpl::GModelBuilder(g).put(cv::GIn(in).m_args, cv::GOut(out1, out2).m_args);
326
327     auto ops = test::collectOperations(gm);
328
329     cv::gimpl::Protocol p;
330     std::tie(p.inputs, p.outputs, p.in_nhs, p.out_nhs) = proto_slots;
331     auto integral_nh = p.in_nhs.front()->outNodes().front();
332
333     EXPECT_EQ(3u, ops.size());
334     EXPECT_EQ("org.opencv.core.matrixop.integral", gm.metadata(integral_nh).get<cv::gimpl::Op>().k.name);
335     EXPECT_EQ(1u, static_cast<std::size_t>(integral_nh->inEdges().size()));
336     EXPECT_EQ(2u, static_cast<std::size_t>(integral_nh->outEdges().size()));
337     EXPECT_EQ(2u, static_cast<std::size_t>(integral_nh->outNodes().size()));
338 }
339 TEST(GModelBuilder, Add_Operation_With_One_Out_One_Time)
340 {
341     // in1 -> binaryOp() -> b_out -> unaryOp() -> out1
342     //            ^           |
343     //            |           |
344     // in2 -------            '----> unaryOp() -> out2
345
346     cv::GMat in1, in2;
347     auto b_out = test::binaryOp(in1, in2);
348     auto out1 = test::unaryOp(b_out);
349     auto out2 = test::unaryOp(b_out);
350
351     ade::Graph g;
352     cv::gimpl::GModel::Graph gm(g);
353     cv::gimpl::GModel::init(gm);
354     auto proto_slots = cv::gimpl::GModelBuilder(g).put(cv::GIn(in1, in2).m_args, cv::GOut(out1, out2).m_args);
355     cv::gimpl::Protocol p;
356     std::tie(p.inputs, p.outputs, p.in_nhs, p.out_nhs) = proto_slots;
357     cv::gimpl::GModel::Graph gr(g);
358     auto binaryOp_nh = p.in_nhs.front()->outNodes().front();
359
360     EXPECT_EQ(2u, static_cast<std::size_t>(binaryOp_nh->inEdges().size()));
361     EXPECT_EQ(1u, static_cast<std::size_t>(binaryOp_nh->outEdges().size()));
362     EXPECT_EQ(8u, static_cast<std::size_t>(g.nodes().size()));
363 }
364 } // namespace opencv_test