Publishing 2019 R1 content
[platform/upstream/dldt.git] / inference-engine / thirdparty / fluid / modules / gapi / src / api / gcomputation.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 "precomp.hpp"
9 #include <algorithm> // remove_if
10 #include <cctype>    // isspace (non-locale version)
11 #include <ade/util/algorithm.hpp>
12
13 #include "logger.hpp" // GAPI_LOG
14
15 #include "opencv2/gapi/gcomputation.hpp"
16 #include "opencv2/gapi/gkernel.hpp"
17
18 #include "api/gcomputation_priv.hpp"
19 #include "api/gcall_priv.hpp"
20 #include "api/gnode_priv.hpp"
21
22 #include "compiler/gmodelbuilder.hpp"
23 #include "compiler/gcompiler.hpp"
24
25 // cv::GComputation private implementation /////////////////////////////////////
26 // <none>
27
28 // cv::GComputation public implementation //////////////////////////////////////
29 cv::GComputation::GComputation(const Generator& gen)
30     : m_priv(gen().m_priv)
31 {
32 }
33
34 cv::GComputation::GComputation(GMat in, GMat out)
35     : cv::GComputation(cv::GIn(in), cv::GOut(out))
36 {
37 }
38
39
40 cv::GComputation::GComputation(GMat in, GScalar out)
41     : cv::GComputation(cv::GIn(in), cv::GOut(out))
42 {
43 }
44
45 cv::GComputation::GComputation(GMat in1, GMat in2, GMat out)
46     : cv::GComputation(cv::GIn(in1, in2), cv::GOut(out))
47 {
48 }
49
50 cv::GComputation::GComputation(GMat in1, GMat in2, GScalar out)
51     : cv::GComputation(cv::GIn(in1, in2), cv::GOut(out))
52 {
53 }
54
55 cv::GComputation::GComputation(const std::vector<GMat> &ins,
56                                const std::vector<GMat> &outs)
57     : m_priv(new Priv())
58 {
59     const auto wrap = [](cv::GMat m) { return GProtoArg(m); };
60     ade::util::transform(ins,  std::back_inserter(m_priv->m_ins),  wrap);
61     ade::util::transform(outs, std::back_inserter(m_priv->m_outs), wrap);
62 }
63
64 cv::GComputation::GComputation(cv::GProtoInputArgs &&ins,
65                                cv::GProtoOutputArgs &&outs)
66     : m_priv(new Priv())
67 {
68     m_priv->m_ins  = std::move(ins.m_args);
69     m_priv->m_outs = std::move(outs.m_args);
70 }
71
72 cv::GCompiled cv::GComputation::compile(GMetaArgs &&metas, GCompileArgs &&args)
73 {
74     // FIXME: Cache gcompiled per parameters here?
75     cv::gimpl::GCompiler comp(*this, std::move(metas), std::move(args));
76     return comp.compile();
77 }
78
79 // FIXME: Introduce similar query/test method for GMetaArgs as a building block
80 // for functions like this?
81 static bool formats_are_same(const cv::GMetaArgs& metas1, const cv::GMetaArgs& metas2)
82 {
83     return std::equal(metas1.cbegin(), metas1.cend(), metas2.cbegin(),
84                       [](const cv::GMetaArg& meta1, const cv::GMetaArg& meta2) {
85                           if (meta1.index() == meta2.index() && meta1.index() == cv::GMetaArg::index_of<cv::GMatDesc>())
86                           {
87                               const auto& desc1 = cv::util::get<cv::GMatDesc>(meta1);
88                               const auto& desc2 = cv::util::get<cv::GMatDesc>(meta2);
89
90                               // comparison by size is omitted
91                               return (desc1.chan  == desc2.chan &&
92                                       desc1.depth == desc2.depth);
93                           }
94                           else
95                           {
96                               return meta1 == meta2;
97                           }
98                      });
99 }
100
101 void cv::GComputation::apply(GRunArgs &&ins, GRunArgsP &&outs, GCompileArgs &&args)
102 {
103     const auto in_metas = descr_of(ins);
104     // FIXME Graph should be recompiled when GCompileArgs have changed
105     if (m_priv->m_lastMetas != in_metas)
106     {
107         if (m_priv->m_lastCompiled &&
108             m_priv->m_lastCompiled.canReshape() &&
109             formats_are_same(m_priv->m_lastMetas, in_metas))
110         {
111             m_priv->m_lastCompiled.reshape(in_metas, args);
112         }
113         else
114         {
115             // FIXME: Had to construct temporary object as compile() takes && (r-value)
116             m_priv->m_lastCompiled = compile(GMetaArgs(in_metas), std::move(args));
117         }
118         m_priv->m_lastMetas = in_metas;
119     }
120     m_priv->m_lastCompiled(std::move(ins), std::move(outs));
121 }
122
123 void cv::GComputation::apply(const std::vector<cv::gapi::own::Mat> &ins,
124                              const std::vector<cv::gapi::own::Mat> &outs,
125                              GCompileArgs &&args)
126 {
127     GRunArgs call_ins;
128     GRunArgsP call_outs;
129
130     auto tmp = outs;
131     for (const cv::gapi::own::Mat &m : ins) { call_ins.emplace_back(m);   }
132     for (      cv::gapi::own::Mat &m : tmp) { call_outs.emplace_back(&m); }
133
134     apply(std::move(call_ins), std::move(call_outs), std::move(args));
135 }
136
137 #if !defined(GAPI_STANDALONE)
138 void cv::GComputation::apply(cv::Mat in, cv::Mat &out, GCompileArgs &&args)
139 {
140     apply(cv::gin(in), cv::gout(out), std::move(args));
141     // FIXME: The following doesn't work!
142     // Operation result is not replicated into user's object
143     // apply({GRunArg(in)}, {GRunArg(out)});
144 }
145
146 void cv::GComputation::apply(cv::Mat in, cv::Scalar &out, GCompileArgs &&args)
147 {
148     apply(cv::gin(in), cv::gout(out), std::move(args));
149 }
150
151 void cv::GComputation::apply(cv::Mat in1, cv::Mat in2, cv::Mat &out, GCompileArgs &&args)
152 {
153     apply(cv::gin(in1, in2), cv::gout(out), std::move(args));
154 }
155
156 void cv::GComputation::apply(cv::Mat in1, cv::Mat in2, cv::Scalar &out, GCompileArgs &&args)
157 {
158     apply(cv::gin(in1, in2), cv::gout(out), std::move(args));
159 }
160
161 void cv::GComputation::apply(const std::vector<cv::Mat> &ins,
162                              const std::vector<cv::Mat> &outs,
163                              GCompileArgs &&args)
164 {
165     GRunArgs call_ins;
166     GRunArgsP call_outs;
167
168     // Make a temporary copy of vector outs - cv::Mats are copies anyway
169     auto tmp = outs;
170     for (const cv::Mat &m : ins) { call_ins.emplace_back(m);   }
171     for (      cv::Mat &m : tmp) { call_outs.emplace_back(&m); }
172
173     apply(std::move(call_ins), std::move(call_outs), std::move(args));
174 }
175 #endif // !defined(GAPI_STANDALONE)
176
177 cv::GComputation::Priv& cv::GComputation::priv()
178 {
179     return *m_priv;
180 }
181
182 const cv::GComputation::Priv& cv::GComputation::priv() const
183 {
184     return *m_priv;
185 }
186
187 // Islands /////////////////////////////////////////////////////////////////////
188
189 void cv::gapi::island(const std::string       &name,
190                             GProtoInputArgs  &&ins,
191                             GProtoOutputArgs &&outs)
192 {
193     {
194         // Island must have a printable name.
195         // Forbid names which contain only spaces.
196         GAPI_Assert(!name.empty());
197         const auto first_printable_it = std::find_if_not(name.begin(), name.end(), isspace);
198         const bool likely_printable   = first_printable_it != name.end();
199         GAPI_Assert(likely_printable);
200     }
201     // Even if the name contains spaces, keep it unmodified as user will
202     // then use this string to assign affinity, etc.
203
204     // First, set island tags on all operations from `ins` to `outs`
205     auto island = cv::gimpl::unrollExpr(ins.m_args, outs.m_args);
206     if (island.all_ops.empty())
207     {
208         util::throw_error(std::logic_error("Operation range is empty"));
209     }
210     for (auto &op_expr_node : island.all_ops)
211     {
212         auto &op_expr_node_p = op_expr_node.priv();
213
214         GAPI_Assert(op_expr_node.shape() == GNode::NodeShape::CALL);
215         const GCall&       call   = op_expr_node.call();
216         const GCall::Priv& call_p = call.priv();
217
218         if (!op_expr_node_p.m_island.empty())
219         {
220             util::throw_error(std::logic_error
221                               (  "Operation " + call_p.m_k.name
222                                + " is already assigned to island \""
223                                + op_expr_node_p.m_island + "\""));
224         }
225         else
226         {
227             op_expr_node_p.m_island = name;
228             GAPI_LOG_INFO(NULL,
229                           "Assigned " << call_p.m_k.name << "_" << &call_p <<
230                           " to island \"" << name << "\"");
231         }
232     }
233
234     // Note - this function only sets islands to all operations in
235     // expression tree, it is just a first step.
236     // The second step is assigning intermediate data objects to Islands,
237     // see passes::initIslands for details.
238 }