Move downgrade passes to pass folder (#1675)
[platform/upstream/dldt.git] / ngraph / test / provenance.cpp
1 //*****************************************************************************
2 // Copyright 2017-2020 Intel Corporation
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //     http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //*****************************************************************************
16
17 #include <fstream>
18 #include <sstream>
19 #include <string>
20 #include <vector>
21
22 #include "gmock/gmock.h"
23 #include "gtest/gtest.h"
24
25 #include "ngraph/builder/norm.hpp"
26 #include "ngraph/graph_util.hpp"
27 #include "ngraph/ngraph.hpp"
28 #include "ngraph/pass/manager.hpp"
29 #include "ngraph/provenance.hpp"
30 #include "pass/fused_op_decomposition.hpp"
31 #include "pass/opset0_downgrade.hpp"
32 #include "pass/opset1_upgrade.hpp"
33 #include "util/provenance_enabler.hpp"
34
35 using namespace std;
36 using namespace ngraph;
37 using ::testing::Return;
38
39 NGRAPH_SUPPRESS_DEPRECATED_START
40
41 using ProvSet = std::unordered_set<std::string>;
42
43 TEST(provenance, provenance)
44 {
45     test::ProvenanceEnabler provenance_enabler;
46
47     //
48     // Before:
49     //
50     //   A{tag_a}  B{tag_b}
51     //         |   |
52     //        C{tag_c}
53     //
54     // Replacement:
55     //
56     //       A{tag_a} B{tag_b}
57     //              | |
58     //         C := D{}
59     //
60     // After:
61     //
62     //   A{tag_a}  B{tag_b}
63     //         |   |
64     //        D{tag_c}
65     //
66     // Comment:
67     //   * D is the replacement root, and its insertion kills C. We should not, however, consider
68     //     A and B to be killed, because they are not post-dominated by D until after C is cut out
69     //     of the graph.
70     //
71     {
72         auto x = make_shared<op::Parameter>(element::i32, PartialShape{2, 3, 4});
73         auto y = make_shared<op::Parameter>(element::i32, PartialShape{2, 3, 4});
74
75         auto a = make_shared<op::Add>(x, y);
76         a->add_provenance_tag("tag_a");
77         auto b = make_shared<op::Multiply>(y, x);
78         b->add_provenance_tag("tag_b");
79         auto c = make_shared<op::Subtract>(a, b);
80         c->add_provenance_tag("tag_c");
81
82         auto f = make_shared<Function>(c, ParameterVector{x, y});
83
84         auto new_c = make_shared<op::Subtract>(a, b);
85         replace_node(c, new_c);
86
87         EXPECT_EQ(new_c->get_provenance_tags(), ProvSet{"tag_c"});
88     }
89
90     //
91     // Before:
92     //
93     //   A{tag_a}  B{tag_b}
94     //         |   |
95     //        C{tag_c}
96     //
97     // Replacement:
98     //
99     //
100     //
101     //     A{tag_a}  B{tag_b}
102     //        |      |
103     //   C -> D{tag_d}
104     //
105     // After:
106     //
107     //   A{tag_a}  B{tag_b}
108     //         |   |
109     //        D{tag_c,tag_d}
110     //
111     // Comment:
112     //   * D is the replacement root, and its insertion kills C. We should not, however, consider
113     //     A and B to be killed, because they are not post-dominated by D until after C is cut out
114     //     of the graph.
115     //
116     {
117         auto x = make_shared<op::Parameter>(element::i32, PartialShape{2, 3, 4});
118         auto y = make_shared<op::Parameter>(element::i32, PartialShape{2, 3, 4});
119
120         auto a = make_shared<op::Add>(x, y);
121         a->add_provenance_tag("tag_a");
122         auto b = make_shared<op::Multiply>(y, x);
123         b->add_provenance_tag("tag_b");
124         auto c = make_shared<op::Subtract>(a, b);
125         c->add_provenance_tag("tag_c");
126
127         auto f = make_shared<Function>(c, ParameterVector{x, y});
128
129         auto d = make_shared<op::Subtract>(a, b);
130         d->add_provenance_tag("tag_d");
131         replace_node(c, d);
132
133         EXPECT_EQ(d->get_provenance_tags(), (ProvSet{"tag_c", "tag_d"}));
134     }
135
136     //
137     // Before:
138     //
139     //   A{tag_a}  B{tag_b}
140     //         |   |
141     //        C{tag_c}
142     //
143     // Replacement:
144     //
145     //   C -> D{tag_d}
146     //
147     // After:
148     //
149     //   D{tag_a,tag_b,tag_c,tag_d}
150     //
151     // Comment:
152     //   * D is the replacement root, and its insertion kills A, B, and C.
153     //
154     {
155         auto x = make_shared<op::Parameter>(element::i32, PartialShape{2, 3, 4});
156         auto y = make_shared<op::Parameter>(element::i32, PartialShape{2, 3, 4});
157
158         auto a = make_shared<op::Add>(x, y);
159         a->add_provenance_tag("tag_a");
160         auto b = make_shared<op::Multiply>(y, x);
161         b->add_provenance_tag("tag_b");
162         auto c = make_shared<op::Subtract>(a, b);
163         c->add_provenance_tag("tag_c");
164
165         auto f = make_shared<Function>(c, ParameterVector{x, y});
166
167         auto d = make_zero(element::i32, Shape{2, 3, 4});
168         d->add_provenance_tag("tag_d");
169         replace_node(c, d);
170
171         EXPECT_EQ(d->get_provenance_tags(), (ProvSet{"tag_a", "tag_b", "tag_c", "tag_d"}));
172     }
173
174     //
175     // Before:
176     //
177     //   A{tag_a}  B{tag_b}
178     //         |   |
179     //        C{tag_c}
180     //
181     // Replacement:
182     //
183     //   C -> D{}
184     //
185     // After:
186     //
187     //   D{tag_a,tag_b,tag_c}
188     //
189     // Comment:
190     //   * D is the replacement root, and its insertion kills A, B, and C.
191     //
192     {
193         auto x = make_shared<op::Parameter>(element::i32, PartialShape{2, 3, 4});
194         auto y = make_shared<op::Parameter>(element::i32, PartialShape{2, 3, 4});
195
196         auto a = make_shared<op::Add>(x, y);
197         a->add_provenance_tag("tag_a");
198         auto b = make_shared<op::Multiply>(y, x);
199         b->add_provenance_tag("tag_b");
200         auto c = make_shared<op::Subtract>(a, b);
201         c->add_provenance_tag("tag_c");
202
203         auto f = make_shared<Function>(c, ParameterVector{x, y});
204
205         auto d = make_zero(element::i32, Shape{2, 3, 4});
206         replace_node(c, d);
207
208         EXPECT_EQ(d->get_provenance_tags(), (ProvSet{"tag_a", "tag_b", "tag_c"}));
209     }
210
211     //
212     // Before:
213     //
214     //   A{tag_a}  B{tag_b}
215     //         |   |
216     //        C{tag_c}
217     //
218     //
219     // Replacement:
220     //
221     //   A{tag_a}  B{tag_b}
222     //         |     |
223     //        E{}    |
224     //         |     |
225     //    C -> D{tag_d}
226     //
227     //
228     // After:
229     //
230     //   A{tag_a}          B{tag_b}
231     //         |             |
232     //      E{tag_c}         |
233     //           |           |
234     //          D{tag_c, tag_d}
235     //
236     // Comment:
237     //   * D is the replacement root replacing C and creating a new argument node E
238     //
239     {
240         auto x = make_shared<op::Parameter>(element::i32, PartialShape{2, 3, 4});
241         auto y = make_shared<op::Parameter>(element::i32, PartialShape{2, 3, 4});
242
243         auto a = make_shared<op::Add>(x, y);
244         a->add_provenance_tag("tag_a");
245         auto b = make_shared<op::Multiply>(y, x);
246         b->add_provenance_tag("tag_b");
247         auto c = make_shared<op::Subtract>(a, b);
248         c->add_provenance_tag("tag_c");
249
250         auto f = make_shared<Function>(c, ParameterVector{x, y});
251
252         auto e = make_shared<op::Subtract>(a, x);
253         auto d = make_shared<op::Subtract>(e, b);
254         d->add_provenance_tag("tag_d");
255
256         replace_node(c, d);
257
258         EXPECT_EQ(d->get_provenance_tags(), (ProvSet{"tag_c", "tag_d"}));
259         EXPECT_EQ(e->get_provenance_tags(), (ProvSet{"tag_c"}));
260     }
261
262     //
263     // Before:
264     //
265     //   A{tag_a}  B{tag_b}
266     //         |   |
267     //        C{tag_c}
268     //
269     //
270     // Replacement:
271     //
272     //   A{tag_a}  B{tag_b}
273     //         |      |
274     //       E{tag_e} |
275     //           |    |
276     //     C -> D{tag_d}
277     //
278     //
279     // After:
280     //
281     //   A{tag_a}               B{tag_b}
282     //       \                    /
283     //   E{tag_c, tag_d, tag_e}  /
284     //          \               /
285     //           D{tag_c, tag_d}
286     //
287     // Comment:
288     //   * D is the replacement root replacing C and creating a new argument node E
289     //
290     {
291         auto x = make_shared<op::Parameter>(element::i32, PartialShape{2, 3, 4});
292         auto y = make_shared<op::Parameter>(element::i32, PartialShape{2, 3, 4});
293
294         auto a = make_shared<op::Add>(x, y);
295         a->add_provenance_tag("tag_a");
296         auto b = make_shared<op::Multiply>(y, x);
297         b->add_provenance_tag("tag_b");
298         auto c = make_shared<op::Subtract>(a, b);
299         c->add_provenance_tag("tag_c");
300
301         auto f = make_shared<Function>(c, ParameterVector{x, y});
302
303         auto e = make_shared<op::Subtract>(a, x);
304         e->add_provenance_tag("tag_e");
305         auto d = make_shared<op::Subtract>(e, b);
306         d->add_provenance_tag("tag_d");
307
308         replace_node(c, d);
309
310         EXPECT_EQ(d->get_provenance_tags(), (ProvSet{"tag_c", "tag_d"}));
311         EXPECT_EQ(e->get_provenance_tags(), (ProvSet{"tag_c", "tag_e"}));
312     }
313 }
314
315 TEST(provenance, add_group_above)
316 {
317     auto p1 = make_shared<op::Parameter>(element::i32, PartialShape{2, 3, 4});
318     p1->add_provenance_tag("P1");
319     auto p2 = make_shared<op::Parameter>(element::i32, PartialShape{2, 3, 4});
320     p2->add_provenance_tag("P2");
321     auto a1 = p1 + p2;
322     auto m1 = (a1 * a1)->add_provenance_group_members_above({p1, p2});
323     m1->add_provenance_tag("m1");
324     EXPECT_EQ(p1->get_provenance_tags(), (ProvSet{"P1"}));
325     EXPECT_EQ(p2->get_provenance_tags(), (ProvSet{"P2"}));
326     EXPECT_EQ(a1->get_provenance_tags(), (ProvSet{"m1"}));
327     EXPECT_EQ(m1->get_provenance_tags(), (ProvSet{"m1"}));
328 }
329
330 TEST(provenance, add_tags_above)
331 {
332     auto x = make_shared<op::Parameter>(element::i32, PartialShape{2, 3, 4});
333     auto y = make_shared<op::Parameter>(element::i32, PartialShape{2, 3, 4});
334
335     auto a = make_shared<op::Add>(x, y);
336     auto b = make_shared<op::Multiply>(x, y);
337     auto c = make_shared<op::Subtract>(a, b);
338     auto d = make_shared<op::Abs>(c);
339
340     // Add tags to Subtract and all nodes until Parameters (all above c, until params x, y)
341     c->add_provenance_tags_above(OutputVector{x, y}, {"tag_above_c - until_params"});
342     // Add tags to Abs and Subtract (above d, until c inputs)
343     d->add_provenance_tags_above(c->input_values(), {"tag_above_d - until_c_inputs"});
344     // Add tags to Abs and all nodes above
345     d->add_provenance_tags_above(OutputVector{}, {"tag_all_above_d"});
346
347     auto x_tags = x->get_provenance_tags();
348     EXPECT_EQ(x_tags.size(), 1);
349     EXPECT_TRUE(x_tags.find("tag_all_above_d") != x_tags.end());
350
351     auto y_tags = y->get_provenance_tags();
352     EXPECT_EQ(y_tags.size(), 1);
353     EXPECT_TRUE(y_tags.find("tag_all_above_d") != y_tags.end());
354
355     auto a_tags = a->get_provenance_tags();
356     EXPECT_EQ(a_tags.size(), 2);
357     EXPECT_TRUE(a_tags.find("tag_above_c - until_params") != a_tags.end());
358     EXPECT_FALSE(a_tags.find("tag_above_d - until_c_inputs") != a_tags.end());
359     EXPECT_TRUE(a_tags.find("tag_all_above_d") != a_tags.end());
360
361     auto b_tags = b->get_provenance_tags();
362     EXPECT_EQ(b_tags.size(), 2);
363     EXPECT_TRUE(b_tags.find("tag_above_c - until_params") != b_tags.end());
364     EXPECT_FALSE(b_tags.find("tag_above_d - until_c_inputs") != b_tags.end());
365     EXPECT_TRUE(b_tags.find("tag_all_above_d") != b_tags.end());
366
367     auto c_tags = c->get_provenance_tags();
368     EXPECT_EQ(c_tags.size(), 3);
369     EXPECT_TRUE(c_tags.find("tag_above_c - until_params") != c_tags.end());
370     EXPECT_TRUE(c_tags.find("tag_above_d - until_c_inputs") != c_tags.end());
371     EXPECT_TRUE(c_tags.find("tag_all_above_d") != c_tags.end());
372
373     auto d_tags = d->get_provenance_tags();
374     EXPECT_EQ(d_tags.size(), 2);
375     EXPECT_FALSE(d_tags.find("tag_above_c - until_params") != d_tags.end());
376     EXPECT_TRUE(d_tags.find("tag_above_d - until_c_inputs") != d_tags.end());
377     EXPECT_TRUE(d_tags.find("tag_all_above_d") != d_tags.end());
378 }
379
380 TEST(provenance, builder)
381 {
382     auto p1 = make_shared<op::Parameter>(element::i32, PartialShape{2, 3, 4});
383     p1->add_provenance_tag("P1");
384     auto norm = builder::opset1::lp_norm(p1, op::Constant::create(element::i64, {}, {0}), 1, 0);
385     norm->add_provenance_tag("norm");
386     for (auto node : topological_sort(NodeVector{norm}))
387     {
388         if (node == p1)
389         {
390             EXPECT_EQ(node->get_provenance_tags(), (ProvSet{"P1"}));
391         }
392         else
393         {
394             EXPECT_EQ(node->get_provenance_tags(), (ProvSet{"norm"}));
395         }
396     }
397 }
398
399 TEST(provenance, fused_copy_origin_tags)
400 {
401     test::ProvenanceEnabler provenance_enabler;
402
403     auto p1 = make_shared<op::Parameter>(element::f32, PartialShape{2, 3, 4});
404     p1->add_provenance_tag("P1");
405     auto g = make_shared<op::Gelu>(p1);
406     g->add_provenance_tag("G");
407     auto r = make_shared<op::Result>(g);
408     auto f = make_shared<Function>(ResultVector{r}, ParameterVector{p1});
409
410     pass::Manager manager;
411     manager.register_pass<pass::FusedOpDecomposition>();
412     manager.run_passes(f);
413
414     traverse_nodes(f, [&](const std::shared_ptr<Node>& node) {
415         auto tags = node->get_provenance_tags();
416         if (node == p1)
417         {
418             EXPECT_EQ(tags.size(), 1);
419             EXPECT_TRUE(tags.find("P1") != tags.end());
420         }
421         else if (node == r)
422         {
423         }
424         else
425         {
426             EXPECT_TRUE(tags.find("G") != tags.end());
427             EXPECT_TRUE(tags.find("<Decomposed from Gelu>") != tags.end());
428         }
429     });
430 }
431
432 TEST(provenance, fused_decomposition_tag)
433 {
434     test::ProvenanceEnabler provenance_enabler;
435
436     auto p1 = make_shared<op::Parameter>(element::f32, PartialShape{2, 3, 4});
437     auto fused_op = make_shared<op::MVN>(p1);
438     auto result = make_shared<op::Result>(fused_op);
439     auto f = make_shared<Function>(ResultVector{result}, ParameterVector{p1});
440
441     pass::Manager manager;
442     manager.register_pass<pass::FusedOpDecomposition>();
443     manager.run_passes(f);
444
445     const auto tag = "<Decomposed from MVN>";
446     auto tag_check = [&tag](std::shared_ptr<ngraph::Node> node) {
447         auto tags = node->get_provenance_tags();
448         EXPECT_TRUE(tags.find(tag) != tags.end());
449     };
450     const auto decomposed_op = f->get_result()->get_input_node_shared_ptr(0);
451     traverse_nodes(as_node_vector(decomposed_op->outputs()), tag_check, {p1});
452 }
453
454 TEST(provenance, topk_setk)
455 {
456     auto p1 = make_shared<op::Parameter>(element::f32, PartialShape{20, 3, 4});
457     p1->add_provenance_tag("P1");
458     auto tk = make_shared<op::TopK>(p1, 0, element::i32, 10);
459     tk->add_provenance_tag("TK");
460     auto tkc0 = tk->input_value(1).get_node_shared_ptr();
461     tkc0->add_provenance_tag("TKC0");
462     for (auto node : topological_sort(NodeVector{tk}))
463     {
464         if (node == p1)
465         {
466             EXPECT_EQ(node->get_provenance_tags(), (ProvSet{"P1"}));
467         }
468         else if (node == tkc0)
469         {
470             EXPECT_EQ(node->get_provenance_tags(), (ProvSet{"TK", "TKC0"}));
471         }
472         else
473         {
474             EXPECT_EQ(node->get_provenance_tags(), (ProvSet{"TK"}));
475         }
476     }
477     tk->set_k(5);
478     auto tkc1 = tk->input_value(1).get_node_shared_ptr();
479     tkc1->add_provenance_tag("TKC1");
480     for (auto node : topological_sort(NodeVector{tk}))
481     {
482         if (node == p1)
483         {
484             EXPECT_EQ(node->get_provenance_tags(), (ProvSet{"P1"}));
485         }
486         else if (node == tkc1)
487         {
488             EXPECT_EQ(node->get_provenance_tags(), (ProvSet{"TK", "TKC0", "TKC1"}));
489         }
490         else
491         {
492             EXPECT_EQ(node->get_provenance_tags(), (ProvSet{"TK"}));
493         }
494     }
495 }
496
497 TEST(provenance, empty_group)
498 {
499     auto p1 = make_shared<op::Parameter>(element::i32, PartialShape{2, 3, 4});
500     p1->add_provenance_tag("P1");
501     auto abs = make_shared<op::Abs>(p1);
502     // Make sure group is empty
503     abs->add_provenance_group_members_above({abs});
504     abs->add_provenance_tag("abs");
505     for (auto node : topological_sort(NodeVector{abs}))
506     {
507         if (node == p1)
508         {
509             EXPECT_EQ(node->get_provenance_tags(), (ProvSet{"P1"}));
510         }
511         else
512         {
513             EXPECT_EQ(node->get_provenance_tags(), (ProvSet{"abs"}));
514         }
515     }
516 }
517
518 TEST(provenance, opset1_upgrade_pass_topk)
519 {
520     test::ProvenanceEnabler provenance_enabler;
521
522     const size_t axis = 2;
523     const size_t k = 10;
524     const auto data = make_shared<op::Parameter>(element::i32, Shape{5, 10, 15});
525
526     const auto topk_v0 = make_shared<op::v0::TopK>(data, axis, element::i32, k);
527     const auto result = make_shared<op::Result>(topk_v0->output(0));
528     auto f = make_shared<Function>(ResultVector{result}, ParameterVector{data});
529
530     ngraph::pass::Manager pass_manager;
531     pass_manager.register_pass<pass::Opset1Upgrade>();
532     pass_manager.run_passes(f);
533
534     const auto pass_replacement_node = f->get_result()->get_input_node_shared_ptr(0);
535     const auto topk_v1 = as_type_ptr<op::v1::TopK>(pass_replacement_node);
536
537     const std::string tag = "<Opset1_Upgrade (v0 TopK)>";
538     auto tag_check = [&tag](std::shared_ptr<ngraph::Node> node) {
539         auto tags = node->get_provenance_tags();
540         EXPECT_TRUE(tags.find(tag) != tags.end());
541     };
542     traverse_nodes({topk_v1}, tag_check, as_node_vector(topk_v0->input_values()));
543 }
544
545 TEST(provenance, opset0_downgrade_pass_topk)
546 {
547     test::ProvenanceEnabler provenance_enabler;
548
549     const auto data = make_shared<op::Parameter>(element::i32, Shape{5, 10, 15});
550     const int32_t k = 10;
551     const auto k_node = op::Constant::create(element::i64, Shape{}, {k});
552     const size_t axis = 2;
553     const auto mode = op::v1::TopK::Mode::MAX;
554     const auto sort = op::v1::TopK::SortType::SORT_INDICES;
555     const auto elem_type = element::i64;
556
557     const auto topk_v1 = make_shared<op::v1::TopK>(data, k_node, axis, mode, sort, elem_type);
558     const auto result = make_shared<op::Result>(topk_v1->output(0));
559     auto f = make_shared<Function>(ResultVector{result}, ParameterVector{data});
560
561     ngraph::pass::Manager pass_manager;
562     pass_manager.register_pass<pass::Opset0Downgrade>();
563     pass_manager.run_passes(f);
564
565     const auto pass_replacement_node = f->get_result()->get_input_node_shared_ptr(0);
566     const auto topk_v0 = as_type_ptr<op::v0::TopK>(pass_replacement_node);
567
568     const std::string tag = "<Opset0_Downgrade (v1 TopK)>";
569     auto tag_check = [&tag](std::shared_ptr<ngraph::Node> node) {
570         auto tags = node->get_provenance_tags();
571         EXPECT_TRUE(tags.find(tag) != tags.end());
572     };
573     traverse_nodes({topk_v0}, tag_check, as_node_vector(topk_v1->input_values()));
574 }
575
576 TEST(provenance, opset1_upgrade_pass_graph)
577 {
578     test::ProvenanceEnabler provenance_enabler;
579
580     auto x = make_shared<op::Parameter>(element::i32, PartialShape{2, 3, 4});
581     auto y = make_shared<op::Parameter>(element::i32, PartialShape{2, 3, 4});
582
583     auto a = make_shared<op::v0::Add>(x, y);
584     auto b = make_shared<op::v0::Subtract>(x, y);
585     auto c = make_shared<op::v0::Abs>(b);
586     auto d = make_shared<op::v0::Multiply>(a, b);
587
588     auto f = make_shared<Function>(d, ParameterVector{x, y});
589
590     ngraph::pass::Manager pass_manager;
591     pass_manager.register_pass<pass::Opset1Upgrade>();
592     pass_manager.run_passes(f);
593
594     for (auto node : f->get_ordered_ops())
595     {
596         auto tags = node->get_provenance_tags();
597         if (as_type_ptr<op::v1::Add>(node))
598         {
599             EXPECT_EQ(tags.size(), 1);
600             EXPECT_TRUE(tags.find("<Opset1_Upgrade (v0 Add)>") != tags.end());
601         }
602         else if (as_type_ptr<op::v1::Multiply>(node))
603         {
604             EXPECT_EQ(tags.size(), 1);
605             EXPECT_TRUE(tags.find("<Opset1_Upgrade (v0 Multiply)>") != tags.end());
606         }
607         else if (as_type_ptr<op::v1::Subtract>(node))
608         {
609             EXPECT_EQ(tags.size(), 1);
610             EXPECT_TRUE(tags.find("<Opset1_Upgrade (v0 Subtract)>") != tags.end());
611         }
612         else if (as_type_ptr<op::v0::Abs>(node))
613         {
614             EXPECT_TRUE(tags.empty());
615         }
616     }
617 }
618
619 TEST(provenance, opset0_downgrade_pass_graph)
620 {
621     test::ProvenanceEnabler provenance_enabler;
622
623     auto x = make_shared<op::Parameter>(element::i32, PartialShape{2, 3, 4});
624     auto y = make_shared<op::Parameter>(element::i32, PartialShape{2, 3, 4});
625
626     auto a = make_shared<op::v1::Add>(x, y);
627     auto b = make_shared<op::v1::Subtract>(x, y);
628     auto c = make_shared<op::v0::Abs>(b);
629     auto d = make_shared<op::v1::Multiply>(a, b);
630
631     auto f = make_shared<Function>(d, ParameterVector{x, y});
632
633     ngraph::pass::Manager pass_manager;
634     pass_manager.register_pass<pass::Opset0Downgrade>();
635     pass_manager.run_passes(f);
636
637     for (auto node : f->get_ordered_ops())
638     {
639         auto tags = node->get_provenance_tags();
640         if (as_type_ptr<op::v0::Add>(node))
641         {
642             EXPECT_EQ(tags.size(), 1);
643             EXPECT_TRUE(tags.find("<Opset0_Downgrade (v1 Add)>") != tags.end());
644         }
645         else if (as_type_ptr<op::v0::Multiply>(node))
646         {
647             EXPECT_EQ(tags.size(), 1);
648             EXPECT_TRUE(tags.find("<Opset0_Downgrade (v1 Multiply)>") != tags.end());
649         }
650         else if (as_type_ptr<op::v0::Subtract>(node))
651         {
652             EXPECT_EQ(tags.size(), 1);
653             EXPECT_TRUE(tags.find("<Opset0_Downgrade (v1 Subtract)>") != tags.end());
654         }
655         else if (as_type_ptr<op::v0::Abs>(node))
656         {
657             EXPECT_TRUE(tags.empty());
658         }
659     }
660 }