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 - 2020 Intel Corporation
6
7
8 #include "../test_precomp.hpp"
9
10 #include <ade/graph.hpp>
11 #include <ade/typed_graph.hpp>
12
13 #include "compiler/transactions.hpp"
14
15 namespace opencv_test
16 {
17 namespace
18 {
19
contains(const ade::Graph & graph,const ade::NodeHandle & node)20 bool contains(const ade::Graph& graph, const ade::NodeHandle& node)
21 {
22 auto nodes = graph.nodes();
23 return nodes.end() != std::find(nodes.begin(), nodes.end(), node);
24 }
25
connected(const ade::NodeHandle & src_node,const ade::NodeHandle & dst_node)26 bool connected(const ade::NodeHandle& src_node, const ade::NodeHandle& dst_node)
27 {
28 auto nodes = src_node->outNodes();
29 return nodes.end() != std::find(nodes.begin(), nodes.end(), dst_node);
30 }
31
32 struct SimpleGraph
33 {
34 // ehs[0] ehs[1] ehs[2] ehs[3]
35 // nhs[0] -- > nhs[1] --> nhs[2] --> nhs[3] --> nhs[4]
36
37 enum { node_nums = 5 };
38 ade::Graph graph;
39 ade::NodeHandle fused_nh; // For check that fusion node is connected to the
40 // inputs of the prod and the outputs of the cons
41 std::array<ade::NodeHandle, node_nums> nhs;
42 std::array<ade::EdgeHandle, node_nums - 1> ehs;
43 using Change = ChangeT<>;
44 Change::List changes;
45
SimpleGraphopencv_test::__anon10147bff0111::SimpleGraph46 SimpleGraph()
47 {
48 nhs[0] = graph.createNode();
49 for (int i = 1; i < node_nums; ++i)
50 {
51 nhs[i ] = graph.createNode();
52 ehs[i - 1] = graph.link(nhs[i - 1], nhs[i]);
53 }
54 }
55
fuseopencv_test::__anon10147bff0111::SimpleGraph56 void fuse()
57 {
58 // nhs[0] --> fused_nh --> nhs[4]
59
60 fused_nh = graph.createNode();
61 changes.enqueue<Change::NodeCreated>(fused_nh);
62 changes.enqueue<Change::NewLink> (graph, nhs[0], fused_nh);
63 changes.enqueue<Change::DropLink>(graph, nhs[1], ehs[0]);
64 changes.enqueue<Change::NewLink> (graph, fused_nh, nhs[4]);
65 changes.enqueue<Change::DropLink>(graph, nhs[3], ehs[3]);
66 changes.enqueue<Change::DropLink>(graph, nhs[1], ehs[1]);
67 changes.enqueue<Change::DropLink>(graph, nhs[2], ehs[2]);
68 changes.enqueue<Change::DropNode>(nhs[1]);
69 changes.enqueue<Change::DropNode>(nhs[2]);
70 changes.enqueue<Change::DropNode>(nhs[3]);
71 }
72
commitopencv_test::__anon10147bff0111::SimpleGraph73 void commit() { changes.commit(graph); }
rollbackopencv_test::__anon10147bff0111::SimpleGraph74 void rollback() { changes.rollback(graph); }
75
76 };
77
78 struct Transactions: public ::testing::Test, public SimpleGraph {};
79
80 } // anonymous namespace
81
TEST_F(Transactions,NodeCreated_Create)82 TEST_F(Transactions, NodeCreated_Create)
83 {
84 auto new_nh = graph.createNode();
85 Change::NodeCreated node_created(new_nh);
86
87 EXPECT_EQ(6u, static_cast<std::size_t>(graph.nodes().size()));
88 EXPECT_TRUE(contains(graph, new_nh));
89 }
90
TEST_F(Transactions,NodeCreated_RollBack)91 TEST_F(Transactions, NodeCreated_RollBack)
92 {
93 auto new_nh = graph.createNode();
94 Change::NodeCreated node_created(new_nh);
95
96 node_created.rollback(graph);
97
98 EXPECT_EQ(5u, static_cast<std::size_t>(graph.nodes().size()));
99 EXPECT_FALSE(contains(graph, new_nh));
100 }
101
TEST_F(Transactions,NodeCreated_Commit)102 TEST_F(Transactions, NodeCreated_Commit)
103 {
104 auto new_nh = graph.createNode();
105 Change::NodeCreated node_created(new_nh);
106
107 node_created.commit(graph);
108
109 EXPECT_EQ(6u, static_cast<std::size_t>(graph.nodes().size()));
110 EXPECT_TRUE(contains(graph, new_nh));
111 }
112
TEST_F(Transactions,DropLink_Create)113 TEST_F(Transactions, DropLink_Create)
114 {
115 Change::DropLink drop_link(graph, nhs[0], ehs[0]);
116
117 EXPECT_FALSE(connected(nhs[0], nhs[1]));
118 }
119
TEST_F(Transactions,DropLink_RollBack)120 TEST_F(Transactions, DropLink_RollBack)
121 {
122 Change::DropLink drop_link(graph, nhs[0], ehs[0]);
123
124 drop_link.rollback(graph);
125
126 EXPECT_TRUE(connected(nhs[0], nhs[1]));
127 }
128
TEST_F(Transactions,DropLink_Commit)129 TEST_F(Transactions, DropLink_Commit)
130 {
131 Change::DropLink drop_link(graph, nhs[0], ehs[0]);
132
133 drop_link.commit(graph);
134
135 EXPECT_FALSE(connected(nhs[0], nhs[1]));
136 }
137
TEST_F(Transactions,NewLink_Create)138 TEST_F(Transactions, NewLink_Create)
139 {
140 auto new_nh = graph.createNode();
141 Change::NewLink new_link(graph, new_nh, nhs[0]);
142
143 EXPECT_TRUE(connected(new_nh, nhs[0]));
144 }
145
TEST_F(Transactions,NewLink_RollBack)146 TEST_F(Transactions, NewLink_RollBack)
147 {
148 auto new_nh = graph.createNode();
149 Change::NewLink new_link(graph, new_nh, nhs[0]);
150
151 new_link.rollback(graph);
152
153 EXPECT_FALSE(connected(new_nh, nhs[0]));
154 }
155
TEST_F(Transactions,NewLink_Commit)156 TEST_F(Transactions, NewLink_Commit)
157 {
158 auto new_nh = graph.createNode();
159 Change::NewLink new_link(graph, new_nh, nhs[0]);
160
161 new_link.commit(graph);
162
163 EXPECT_TRUE(connected(new_nh, nhs[0]));
164 }
165
TEST_F(Transactions,DropNode_Create)166 TEST_F(Transactions, DropNode_Create)
167 {
168 auto new_nh = graph.createNode();
169 Change::DropNode drop_node(new_nh);
170
171 EXPECT_EQ(6u, static_cast<std::size_t>(graph.nodes().size()));
172 EXPECT_TRUE(contains(graph, new_nh));
173 }
174
TEST_F(Transactions,DropNode_RollBack)175 TEST_F(Transactions, DropNode_RollBack)
176 {
177 auto new_nh = graph.createNode();
178 Change::DropNode drop_node(new_nh);
179
180 drop_node.rollback(graph);
181
182 EXPECT_EQ(6u, static_cast<std::size_t>(graph.nodes().size()));
183 EXPECT_TRUE(contains(graph, new_nh));
184 }
185
TEST_F(Transactions,DropNode_Commit)186 TEST_F(Transactions, DropNode_Commit)
187 {
188 auto new_nh = graph.createNode();
189 Change::DropNode drop_node(new_nh);
190
191 drop_node.commit(graph);
192
193 EXPECT_EQ(5u, static_cast<std::size_t>(graph.nodes().size()));
194 EXPECT_FALSE(contains(graph, new_nh));
195 }
196
TEST_F(Transactions,Fusion_Commit)197 TEST_F(Transactions, Fusion_Commit)
198 {
199 fuse();
200 commit();
201
202 EXPECT_EQ(3u, static_cast<std::size_t>(graph.nodes().size()));
203 EXPECT_TRUE(connected(nhs[0] , fused_nh));
204 EXPECT_TRUE(connected(fused_nh, nhs[4]));
205 }
206
TEST_F(Transactions,Fusion_RollBack)207 TEST_F(Transactions, Fusion_RollBack)
208 {
209 fuse();
210 rollback();
211
212 EXPECT_EQ(static_cast<std::size_t>(node_nums),
213 static_cast<std::size_t>(graph.nodes().size()));
214 EXPECT_FALSE(contains(graph, fused_nh));
215
216 for (int i = 0; i < static_cast<int>(node_nums) - 1; ++i)
217 {
218 EXPECT_TRUE(connected(nhs[i], nhs[i + 1]));
219 }
220 }
221
222 namespace
223 {
224 struct MetaInt {
nameopencv_test::__anon10147bff0311::MetaInt225 static const char *name() { return "int_meta"; }
226 int x;
227 };
228
229 struct MetaStr {
nameopencv_test::__anon10147bff0311::MetaStr230 static const char *name() { return "string_meta"; }
231 std::string s;
232 };
233 }
234
TEST(PreservedMeta,TestMetaCopy_Full)235 TEST(PreservedMeta, TestMetaCopy_Full)
236 {
237 ade::Graph g;
238 ade::TypedGraph<MetaInt, MetaStr> tg(g);
239
240 auto src_nh = tg.createNode();
241 tg.metadata(src_nh).set(MetaInt{42});
242 tg.metadata(src_nh).set(MetaStr{"hi"});
243
244 auto dst_nh = tg.createNode();
245
246 EXPECT_FALSE(tg.metadata(dst_nh).contains<MetaInt>());
247 EXPECT_FALSE(tg.metadata(dst_nh).contains<MetaStr>());
248
249 // Here we specify all the meta types we know about the src node
250 // Assume Preserved copies its all for us
251 Preserved<ade::NodeHandle, MetaInt, MetaStr>(g, src_nh).copyTo(g, dst_nh);
252
253 ASSERT_TRUE(tg.metadata(dst_nh).contains<MetaInt>());
254 ASSERT_TRUE(tg.metadata(dst_nh).contains<MetaStr>());
255
256 EXPECT_EQ(42, tg.metadata(dst_nh).get<MetaInt>().x);
257 EXPECT_EQ("hi", tg.metadata(dst_nh).get<MetaStr>().s);
258 }
259
260
TEST(PreservedMeta,TestMetaCopy_Partial_Dst)261 TEST(PreservedMeta, TestMetaCopy_Partial_Dst)
262 {
263 ade::Graph g;
264 ade::TypedGraph<MetaInt, MetaStr> tg(g);
265
266 auto tmp_nh1 = tg.createNode();
267 auto tmp_nh2 = tg.createNode();
268 auto src_eh = tg.link(tmp_nh1, tmp_nh2);
269
270 tg.metadata(src_eh).set(MetaInt{42});
271 tg.metadata(src_eh).set(MetaStr{"hi"});
272
273 auto tmp_nh3 = tg.createNode();
274 auto tmp_nh4 = tg.createNode();
275 auto dst_eh = tg.link(tmp_nh3, tmp_nh4);
276
277 EXPECT_FALSE(tg.metadata(dst_eh).contains<MetaInt>());
278 EXPECT_FALSE(tg.metadata(dst_eh).contains<MetaStr>());
279
280 // Here we specify just a single meta type for the src node
281 // Assume Preserved copies only this type and nothing else
282 Preserved<ade::EdgeHandle, MetaStr>(g, src_eh).copyTo(g, dst_eh);
283
284 ASSERT_FALSE(tg.metadata(dst_eh).contains<MetaInt>());
285 ASSERT_TRUE (tg.metadata(dst_eh).contains<MetaStr>());
286
287 EXPECT_EQ("hi", tg.metadata(dst_eh).get<MetaStr>().s);
288 }
289
TEST(PreservedMeta,TestMetaCopy_Partial_Src)290 TEST(PreservedMeta, TestMetaCopy_Partial_Src)
291 {
292 ade::Graph g;
293 ade::TypedGraph<MetaInt, MetaStr> tg(g);
294
295 auto src_nh = tg.createNode();
296 tg.metadata(src_nh).set(MetaInt{42});
297
298 auto dst_nh = tg.createNode();
299
300 EXPECT_FALSE(tg.metadata(dst_nh).contains<MetaInt>());
301 EXPECT_FALSE(tg.metadata(dst_nh).contains<MetaStr>());
302
303 // Here we specify all the meta types we know about the src node
304 // but the src node has just one of them.
305 // A valid situation, only MetaInt to be copied.
306 Preserved<ade::NodeHandle, MetaInt, MetaStr>(g, src_nh).copyTo(g, dst_nh);
307
308 ASSERT_TRUE (tg.metadata(dst_nh).contains<MetaInt>());
309 ASSERT_FALSE(tg.metadata(dst_nh).contains<MetaStr>());
310
311 EXPECT_EQ(42, tg.metadata(dst_nh).get<MetaInt>().x);
312 }
313
TEST(PreservedMeta,TestMetaCopy_Nothing)314 TEST(PreservedMeta, TestMetaCopy_Nothing)
315 {
316 ade::Graph g;
317 ade::TypedGraph<MetaInt, MetaStr> tg(g);
318
319 auto src_nh = tg.createNode();
320 auto dst_nh = tg.createNode();
321
322 EXPECT_FALSE(tg.metadata(src_nh).contains<MetaInt>());
323 EXPECT_FALSE(tg.metadata(src_nh).contains<MetaStr>());
324
325 EXPECT_FALSE(tg.metadata(dst_nh).contains<MetaInt>());
326 EXPECT_FALSE(tg.metadata(dst_nh).contains<MetaStr>());
327
328 // Here we specify all the meta types we know about the src node
329 // but the src node has none of those. See how it works now
330 Preserved<ade::NodeHandle, MetaInt, MetaStr>(g, src_nh).copyTo(g, dst_nh);
331
332 ASSERT_FALSE(tg.metadata(dst_nh).contains<MetaInt>());
333 ASSERT_FALSE(tg.metadata(dst_nh).contains<MetaStr>());
334 }
335
TEST(PreservedMeta,DropEdge)336 TEST(PreservedMeta, DropEdge)
337 {
338 ade::Graph g;
339 ade::TypedGraph<MetaInt, MetaStr> tg(g);
340
341 auto nh1 = tg.createNode();
342 auto nh2 = tg.createNode();
343 auto eh = tg.link(nh1, nh2);
344
345 tg.metadata(eh).set(MetaInt{42});
346 tg.metadata(eh).set(MetaStr{"hi"});
347
348 // Drop an edge using the transaction API
349 using Change = ChangeT<MetaInt, MetaStr>;
350 Change::List changes;
351 changes.enqueue<Change::DropLink>(g, nh1, eh);
352
353 EXPECT_EQ(0u, nh1->outNodes().size());
354 EXPECT_EQ(nullptr, eh);
355
356 // Now restore the edge and check if it's meta was restored
357 changes.rollback(g);
358
359 ASSERT_EQ(1u, nh1->outNodes().size());
360 eh = *nh1->outEdges().begin();
361
362 ASSERT_TRUE(tg.metadata(eh).contains<MetaInt>());
363 ASSERT_TRUE(tg.metadata(eh).contains<MetaStr>());
364
365 EXPECT_EQ(42, tg.metadata(eh).get<MetaInt>().x);
366 EXPECT_EQ("hi", tg.metadata(eh).get<MetaStr>().s);
367 }
368
369 } // opencv_test
370