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