577bc0bc408932409d58c4d2e753f7e12a08d1a7
[platform/upstream/dldt.git] / ngraph / test / constant_folding.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 "gtest/gtest.h"
18
19 #include "ngraph/ngraph.hpp"
20 #include "ngraph/pass/constant_folding.hpp"
21 #include "ngraph/pass/manager.hpp"
22 #include "util/all_close_f.hpp"
23 #include "util/test_tools.hpp"
24
25 NGRAPH_SUPPRESS_DEPRECATED_START
26
27 using namespace ngraph;
28 using namespace std;
29
30 template <typename T>
31 static std::vector<T> get_result_constant(std::shared_ptr<Function> f, size_t pos)
32 {
33     auto new_const =
34         as_type_ptr<op::Constant>(f->get_results().at(pos)->input_value(0).get_node_shared_ptr());
35     return new_const->cast_vector<T>();
36 }
37
38 void range_test_check(const vector<double>& values_out, const vector<double>& values_expected)
39 {
40     ASSERT_TRUE(test::all_close_f(values_out, values_expected, MIN_FLOAT_TOLERANCE_BITS));
41 }
42
43 void range_test_check(const vector<float>& values_out, const vector<float>& values_expected)
44 {
45     ASSERT_TRUE(test::all_close_f(values_out, values_expected, MIN_FLOAT_TOLERANCE_BITS));
46 }
47
48 template <typename T>
49 typename std::enable_if<std::is_integral<T>::value>::type
50     range_test_check(const vector<T>& values_out, const vector<T>& values_expected)
51 {
52     ASSERT_EQ(values_out, values_expected);
53 }
54
55 TEST(constant_folding, acosh)
56 {
57     Shape shape_in{2, 4, 1};
58
59     vector<float> values_in{0, 1, 2, 3, 4, 5, 6, 7};
60     vector<float> expected;
61     for (float f : values_in)
62     {
63         expected.push_back(std::acosh(f));
64     }
65     auto constant = make_shared<op::Constant>(element::f32, shape_in, values_in);
66     auto acosh = make_shared<op::Acosh>(constant);
67     acosh->set_friendly_name("test");
68     auto f = make_shared<Function>(acosh, ParameterVector{});
69
70     pass::Manager pass_manager;
71     pass_manager.register_pass<pass::ConstantFolding>();
72     pass_manager.run_passes(f);
73
74     EXPECT_EQ(count_ops_of_type<op::Acosh>(f), 0);
75     EXPECT_EQ(count_ops_of_type<op::Constant>(f), 1);
76     ASSERT_EQ(f->get_results().size(), 1);
77
78     auto new_const =
79         as_type_ptr<op::Constant>(f->get_results()[0]->input_value(0).get_node_shared_ptr());
80     EXPECT_TRUE(new_const);
81     ASSERT_EQ(new_const->get_friendly_name(), "test");
82
83     auto values_out = new_const->get_vector<float>();
84     EXPECT_TRUE(test::all_close_f(expected, values_out, MIN_FLOAT_TOLERANCE_BITS));
85 }
86
87 TEST(constant_folding, asinh)
88 {
89     Shape shape_in{2, 4, 1};
90
91     vector<float> values_in{0, 1, 2, 3, 4, 5, 6, 7};
92     vector<float> expected;
93     for (float f : values_in)
94     {
95         expected.push_back(std::asinh(f));
96     }
97     auto constant = make_shared<op::Constant>(element::f32, shape_in, values_in);
98     auto asinh = make_shared<op::Asinh>(constant);
99     asinh->set_friendly_name("test");
100     auto f = make_shared<Function>(asinh, ParameterVector{});
101
102     pass::Manager pass_manager;
103     pass_manager.register_pass<pass::ConstantFolding>();
104     pass_manager.run_passes(f);
105
106     EXPECT_EQ(count_ops_of_type<op::Asinh>(f), 0);
107     EXPECT_EQ(count_ops_of_type<op::Constant>(f), 1);
108     ASSERT_EQ(f->get_results().size(), 1);
109
110     auto new_const =
111         as_type_ptr<op::Constant>(f->get_results()[0]->input_value(0).get_node_shared_ptr());
112     EXPECT_TRUE(new_const);
113     ASSERT_EQ(new_const->get_friendly_name(), "test");
114
115     auto values_out = new_const->get_vector<float>();
116     EXPECT_TRUE(test::all_close_f(expected, values_out, MIN_FLOAT_TOLERANCE_BITS));
117 }
118
119 TEST(constant_folding, atanh)
120 {
121     Shape shape_in{2, 4, 1};
122
123     vector<float> values_in{0, 1, 2, 3, 4, 5, 6, 7};
124     vector<float> expected;
125     for (float f : values_in)
126     {
127         expected.push_back(std::atanh(f));
128     }
129     auto constant = make_shared<op::Constant>(element::f32, shape_in, values_in);
130     auto atanh = make_shared<op::Atanh>(constant);
131     atanh->set_friendly_name("test");
132     auto f = make_shared<Function>(atanh, ParameterVector{});
133
134     pass::Manager pass_manager;
135     pass_manager.register_pass<pass::ConstantFolding>();
136     pass_manager.run_passes(f);
137
138     EXPECT_EQ(count_ops_of_type<op::Atanh>(f), 0);
139     EXPECT_EQ(count_ops_of_type<op::Constant>(f), 1);
140     ASSERT_EQ(f->get_results().size(), 1);
141
142     auto new_const =
143         as_type_ptr<op::Constant>(f->get_results()[0]->input_value(0).get_node_shared_ptr());
144     EXPECT_TRUE(new_const);
145     ASSERT_EQ(new_const->get_friendly_name(), "test");
146
147     auto values_out = new_const->get_vector<float>();
148     EXPECT_TRUE(test::all_close_f(expected, values_out, MIN_FLOAT_TOLERANCE_BITS));
149 }
150
151 TEST(constant_folding, constant_squeeze)
152 {
153     Shape shape_in{2, 4, 1};
154     Shape shape_out{2, 4};
155     Shape axes_shape{1};
156
157     vector<float> values_in{0, 1, 2, 3, 4, 5, 6, 7};
158     auto constant = make_shared<op::Constant>(element::f32, shape_in, values_in);
159     vector<int64_t> values_axes{2};
160     auto constant_axes = op::Constant::create(element::i64, axes_shape, values_axes);
161     auto squeeze = make_shared<op::Squeeze>(constant, constant_axes);
162     squeeze->set_friendly_name("test");
163     auto f = make_shared<Function>(squeeze, ParameterVector{});
164
165     pass::Manager pass_manager;
166     pass_manager.register_pass<pass::ConstantFolding>();
167     pass_manager.run_passes(f);
168
169     ASSERT_EQ(count_ops_of_type<op::Squeeze>(f), 0);
170     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 1);
171
172     auto new_const =
173         as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
174     ASSERT_TRUE(new_const);
175     ASSERT_EQ(new_const->get_friendly_name(), "test");
176     ASSERT_EQ(new_const->get_shape(), shape_out);
177
178     auto values_out = new_const->get_vector<float>();
179     ASSERT_TRUE(test::all_close_f(values_in, values_out, MIN_FLOAT_TOLERANCE_BITS));
180 }
181
182 TEST(constant_folding, constant_unsqueeze)
183 {
184     Shape shape_in{2, 4};
185     Shape shape_out{2, 4, 1, 1};
186     Shape axes_shape{2};
187
188     vector<float> values_in{0, 1, 2, 3, 4, 5, 6, 7};
189     auto constant = make_shared<op::Constant>(element::f32, shape_in, values_in);
190     vector<int64_t> values_axes{2, 3};
191     auto constant_axes = op::Constant::create(element::i64, axes_shape, values_axes);
192     auto unsqueeze = make_shared<op::Unsqueeze>(constant, constant_axes);
193     unsqueeze->set_friendly_name("test");
194     auto f = make_shared<Function>(unsqueeze, ParameterVector{});
195
196     pass::Manager pass_manager;
197     pass_manager.register_pass<pass::ConstantFolding>();
198     pass_manager.run_passes(f);
199
200     ASSERT_EQ(count_ops_of_type<op::Unsqueeze>(f), 0);
201     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 1);
202
203     auto new_const =
204         as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
205     ASSERT_TRUE(new_const);
206     ASSERT_EQ(new_const->get_friendly_name(), "test");
207     ASSERT_EQ(new_const->get_shape(), shape_out);
208
209     auto values_out = new_const->get_vector<float>();
210     ASSERT_TRUE(test::all_close_f(values_in, values_out, MIN_FLOAT_TOLERANCE_BITS));
211 }
212
213 TEST(constant_folding, constant_reshape)
214 {
215     Shape shape_in{2, 4};
216     Shape shape_out{2, 4, 1};
217
218     vector<float> values_in{0, 1, 2, 3, 4, 5, 6, 7};
219     auto constant = make_shared<op::Constant>(element::f32, shape_in, values_in);
220     auto reshape = make_shared<op::Reshape>(constant, AxisVector{0, 1}, shape_out);
221     reshape->set_friendly_name("test");
222     auto f = make_shared<Function>(reshape, ParameterVector{});
223
224     pass::Manager pass_manager;
225     pass_manager.register_pass<pass::ConstantFolding>();
226     pass_manager.run_passes(f);
227
228     ASSERT_EQ(count_ops_of_type<op::Reshape>(f), 0);
229     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 1);
230
231     auto new_const =
232         as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
233     ASSERT_TRUE(new_const);
234     ASSERT_EQ(new_const->get_friendly_name(), "test");
235     auto values_out = new_const->get_vector<float>();
236
237     ASSERT_TRUE(test::all_close_f(values_in, values_out, MIN_FLOAT_TOLERANCE_BITS));
238 }
239
240 TEST(constant_folding, DISABLED_constant_reshape_permute)
241 {
242     Shape shape_in{2, 4};
243     Shape shape_out{4, 2};
244
245     vector<double> values_in{0, 1, 2, 3, 4, 5, 6, 7};
246     auto constant = make_shared<op::Constant>(element::f64, shape_in, values_in);
247     auto reshape = make_shared<op::Reshape>(constant, AxisVector{1, 0}, shape_out);
248     reshape->set_friendly_name("test");
249     auto f = make_shared<Function>(reshape, ParameterVector{});
250
251     pass::Manager pass_manager;
252     pass_manager.register_pass<pass::ConstantFolding>();
253     pass_manager.run_passes(f);
254
255     ASSERT_EQ(count_ops_of_type<op::Reshape>(f), 0);
256     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 1);
257
258     auto new_const =
259         as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
260     ASSERT_TRUE(new_const);
261     ASSERT_EQ(new_const->get_friendly_name(), "test");
262     auto values_out = new_const->get_vector<double>();
263
264     vector<double> values_permute{0, 4, 1, 5, 2, 6, 3, 7};
265     ASSERT_TRUE(test::all_close_f(values_permute, values_out, MIN_FLOAT_TOLERANCE_BITS));
266 }
267
268 TEST(constant_folding, constant_broadcast)
269 {
270     Shape shape_in{2};
271     Shape shape_out{2, 4};
272
273     vector<int> values_in{0, 1};
274     auto constant = make_shared<op::Constant>(element::i32, shape_in, values_in);
275     auto broadcast = make_shared<op::Broadcast>(constant, shape_out, AxisSet{1});
276     broadcast->set_friendly_name("test");
277     auto f = make_shared<Function>(broadcast, ParameterVector{});
278
279     pass::Manager pass_manager;
280     pass_manager.register_pass<pass::ConstantFolding>();
281     pass_manager.run_passes(f);
282
283     ASSERT_EQ(count_ops_of_type<op::Broadcast>(f), 0);
284     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 1);
285
286     auto new_const =
287         as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
288     ASSERT_TRUE(new_const);
289     ASSERT_EQ(new_const->get_friendly_name(), "test");
290
291     auto values_out = new_const->get_vector<int>();
292
293     vector<int> values_expected{0, 0, 0, 0, 1, 1, 1, 1};
294     ASSERT_EQ(values_expected, values_out);
295 }
296
297 TEST(constant_folding, constant_broadcast_v1)
298 {
299     vector<int32_t> values_in{0, 1};
300     auto constant_in = make_shared<op::Constant>(element::i32, Shape{2}, values_in);
301     vector<int64_t> shape_in{2, 4};
302     auto constant_shape = make_shared<op::Constant>(element::i64, Shape{2}, shape_in);
303     vector<int64_t> axes_in{0};
304     auto constant_axes = make_shared<op::Constant>(element::i64, Shape{1}, axes_in);
305     auto broadcast_v1 = make_shared<op::v1::Broadcast>(constant_in, constant_shape, constant_axes);
306     broadcast_v1->set_friendly_name("test");
307     auto f = make_shared<Function>(broadcast_v1, ParameterVector{});
308
309     pass::Manager pass_manager;
310     pass_manager.register_pass<pass::ConstantFolding>();
311     pass_manager.run_passes(f);
312
313     ASSERT_EQ(count_ops_of_type<op::v1::Broadcast>(f), 0);
314     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 1);
315
316     auto new_const =
317         as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
318     ASSERT_TRUE(new_const);
319     ASSERT_EQ(new_const->get_friendly_name(), "test");
320     auto values_out = new_const->get_vector<int32_t>();
321
322     vector<int32_t> values_expected{0, 0, 0, 0, 1, 1, 1, 1};
323     ASSERT_EQ(values_expected, values_out);
324 }
325
326 TEST(constant_folding, constant_broadcast_v1_with_target_shape)
327 {
328     vector<int32_t> values_in{1};
329     auto constant_in = make_shared<op::Constant>(element::i32, Shape{1, 1, 1, 1}, values_in);
330     vector<int64_t> shape_in{1, 3, 1, 1};
331     auto target_shape = make_shared<op::Constant>(element::i64, Shape{4}, shape_in);
332     auto broadcast_v1 = make_shared<op::v1::Broadcast>(constant_in, target_shape);
333     broadcast_v1->set_friendly_name("test");
334     auto f = make_shared<Function>(broadcast_v1, ParameterVector{});
335
336     pass::Manager pass_manager;
337     pass_manager.register_pass<pass::ConstantFolding>();
338     pass_manager.run_passes(f);
339
340     ASSERT_EQ(count_ops_of_type<op::v1::Broadcast>(f), 0);
341     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 1);
342
343     auto new_const =
344         as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
345     ASSERT_TRUE(new_const);
346     ASSERT_EQ(new_const->get_friendly_name(), "test");
347     auto values_out = new_const->get_vector<int32_t>();
348
349     vector<int32_t> values_expected{1, 1, 1};
350     ASSERT_EQ(values_expected, values_out);
351 }
352
353 TEST(constant_folding, constant_broadcast_v1_numpy)
354 {
355     vector<int32_t> values_in{0, 1};
356     auto constant_in = make_shared<op::Constant>(element::i32, Shape{2}, values_in);
357     vector<int64_t> shape_in{4, 2};
358     auto constant_shape = make_shared<op::Constant>(element::i64, Shape{2}, shape_in);
359     auto broadcast_v1 = make_shared<op::v1::Broadcast>(constant_in, constant_shape);
360     broadcast_v1->set_friendly_name("test");
361     auto f = make_shared<Function>(broadcast_v1, ParameterVector{});
362
363     pass::Manager pass_manager;
364     pass_manager.register_pass<pass::ConstantFolding>();
365     pass_manager.run_passes(f);
366
367     ASSERT_EQ(count_ops_of_type<op::v1::Broadcast>(f), 0);
368     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 1);
369
370     auto new_const =
371         as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
372     ASSERT_TRUE(new_const);
373     ASSERT_EQ(new_const->get_friendly_name(), "test");
374     auto values_out = new_const->get_vector<int32_t>();
375
376     vector<int32_t> values_expected{0, 1, 0, 1, 0, 1, 0, 1};
377     ASSERT_EQ(values_expected, values_out);
378 }
379
380 TEST(constant_folding, constant_unary_binary)
381 {
382     vector<int> values_a{1, 2, 3, 4};
383     vector<int> values_b{1, 2, 3, 4};
384     vector<int> values_c{-1, -1, -1, -1};
385     vector<int> values_d{1, 4, 9, 16};
386     vector<int> values_e{5, 6};
387     vector<int> values_f{0, 10};
388     vector<int> values_g{1, 4};
389     vector<char> values_h{0, 0, 1, 1};
390     vector<char> values_i{0, 1};
391     auto a = make_shared<op::Constant>(element::i32, Shape{2, 2}, values_a);
392     auto b = make_shared<op::Constant>(element::i32, Shape{2, 2}, values_b);
393     auto c = make_shared<op::Constant>(element::i32, Shape{2, 2}, values_c);
394     auto d = make_shared<op::Constant>(element::i32, Shape{2, 2}, values_d);
395     auto e = make_shared<op::Constant>(element::i32, Shape{2}, values_e);
396     auto f = make_shared<op::Constant>(element::i32, Shape{2}, values_f);
397     auto g = make_shared<op::Constant>(element::i32, Shape{2}, values_g);
398     auto h = make_shared<op::Constant>(element::boolean, Shape{2, 2}, values_h);
399     auto i = make_shared<op::Constant>(element::boolean, Shape{2}, values_i);
400
401     auto add = a + b;
402     auto sub = a - b;
403     auto mul = a * b;
404     auto divn = a / b;
405     auto pow = make_shared<op::Power>(a, b);
406     auto min = make_shared<op::Minimum>(c, a);
407     auto max = make_shared<op::Maximum>(a, c);
408     auto absn = make_shared<op::Abs>(c);
409     auto neg = make_shared<op::Negative>(c);
410     auto sqrt = make_shared<op::Sqrt>(d);
411     auto add_autob_numpy = make_shared<op::Add>(a, e, op::AutoBroadcastType::NUMPY);
412     auto sub_autob_numpy = make_shared<op::Subtract>(a, e, op::AutoBroadcastType::NUMPY);
413     auto mul_autob_numpy = make_shared<op::Multiply>(a, e, op::AutoBroadcastType::NUMPY);
414     auto div_autob_numpy = make_shared<op::Divide>(a, g, op::AutoBroadcastType::NUMPY);
415     auto pow_autob_numpy = make_shared<op::Power>(a, g, op::AutoBroadcastType::NUMPY);
416     auto min_autob_numpy = make_shared<op::Minimum>(a, f, op::AutoBroadcastType::NUMPY);
417     auto max_autob_numpy = make_shared<op::Maximum>(a, f, op::AutoBroadcastType::NUMPY);
418     auto equal_autob_numpy = make_shared<op::Equal>(a, g, op::AutoBroadcastType::NUMPY);
419     auto not_equal_autob_numpy = make_shared<op::NotEqual>(a, g, op::AutoBroadcastType::NUMPY);
420     auto greater_autob_numpy = make_shared<op::Greater>(a, g, op::AutoBroadcastType::NUMPY);
421     auto greater_eq_autob_numpy = make_shared<op::GreaterEq>(a, g, op::AutoBroadcastType::NUMPY);
422     auto less_autob_numpy = make_shared<op::Less>(a, g, op::AutoBroadcastType::NUMPY);
423     auto less_eq_autob_numpy = make_shared<op::LessEq>(a, g, op::AutoBroadcastType::NUMPY);
424     auto logical_or_autob_numpy = make_shared<op::Or>(h, i, op::AutoBroadcastType::NUMPY);
425     auto logical_xor_autob_numpy = make_shared<op::Xor>(h, i, op::AutoBroadcastType::NUMPY);
426
427     auto neg_sqrt = make_shared<op::Sqrt>(c);
428
429     auto func = make_shared<Function>(NodeVector{add,
430                                                  sub,
431                                                  mul,
432                                                  divn,
433                                                  pow,
434                                                  min,
435                                                  max,
436                                                  absn,
437                                                  neg,
438                                                  sqrt,
439                                                  add_autob_numpy,
440                                                  sub_autob_numpy,
441                                                  mul_autob_numpy,
442                                                  div_autob_numpy,
443                                                  pow_autob_numpy,
444                                                  min_autob_numpy,
445                                                  max_autob_numpy,
446                                                  equal_autob_numpy,
447                                                  not_equal_autob_numpy,
448                                                  greater_autob_numpy,
449                                                  greater_eq_autob_numpy,
450                                                  less_autob_numpy,
451                                                  less_eq_autob_numpy,
452                                                  logical_or_autob_numpy,
453                                                  logical_xor_autob_numpy},
454                                       ParameterVector{});
455     auto func_error = make_shared<Function>(NodeVector{neg_sqrt}, ParameterVector{});
456
457     pass::Manager pass_manager;
458     pass_manager.register_pass<pass::ConstantFolding>();
459     pass_manager.run_passes(func);
460
461     // expected values
462     vector<int> add_expected{2, 4, 6, 8};
463     vector<int> sub_expected{0, 0, 0, 0};
464     vector<int> mul_expected{1, 4, 9, 16};
465     vector<int> div_expected{1, 1, 1, 1};
466     vector<int> pow_expected{1, 4, 27, 256};
467     vector<int> min_expected{-1, -1, -1, -1};
468     vector<int> max_expected{1, 2, 3, 4};
469     vector<int> abs_neg_expected{1, 1, 1, 1};
470     vector<int> sqrt_expected{1, 2, 3, 4};
471     vector<int> add_autob_numpy_expected{6, 8, 8, 10};
472     vector<int> sub_autob_numpy_expected{-4, -4, -2, -2};
473     vector<int> mul_autob_numpy_expected{5, 12, 15, 24};
474     vector<int> div_autob_numpy_expected{1, 0, 3, 1};
475     vector<int> pow_autob_numpy_expected{1, 16, 3, 256};
476     vector<int> min_autob_numpy_expected{0, 2, 0, 4};
477     vector<int> max_autob_numpy_expected{1, 10, 3, 10};
478     vector<char> equal_autob_numpy_expected{1, 0, 0, 1};
479     vector<char> not_equal_autob_numpy_expected{0, 1, 1, 0};
480     vector<char> greater_autob_numpy_expected{0, 0, 1, 0};
481     vector<char> greater_eq_autob_numpy_expected{1, 0, 1, 1};
482     vector<char> less_autob_numpy_expected{0, 1, 0, 0};
483     vector<char> less_eq_autob_numpy_expected{1, 1, 0, 1};
484     vector<char> logical_or_autob_numpy_expected{0, 1, 1, 1};
485     vector<char> logical_xor_autob_numpy_expected{0, 1, 1, 0};
486
487     ASSERT_EQ(get_result_constant<int>(func, 0), add_expected);
488     ASSERT_EQ(get_result_constant<int>(func, 1), sub_expected);
489     ASSERT_EQ(get_result_constant<int>(func, 2), mul_expected);
490     ASSERT_EQ(get_result_constant<int>(func, 3), div_expected);
491     ASSERT_EQ(get_result_constant<int>(func, 4), pow_expected);
492     ASSERT_EQ(get_result_constant<int>(func, 5), min_expected);
493     ASSERT_EQ(get_result_constant<int>(func, 6), max_expected);
494     ASSERT_EQ(get_result_constant<int>(func, 7), abs_neg_expected);
495     ASSERT_EQ(get_result_constant<int>(func, 8), abs_neg_expected);
496     ASSERT_EQ(get_result_constant<int>(func, 9), sqrt_expected);
497     ASSERT_EQ(get_result_constant<int>(func, 10), add_autob_numpy_expected);
498     ASSERT_EQ(get_result_constant<int>(func, 11), sub_autob_numpy_expected);
499     ASSERT_EQ(get_result_constant<int>(func, 12), mul_autob_numpy_expected);
500     ASSERT_EQ(get_result_constant<int>(func, 13), div_autob_numpy_expected);
501     ASSERT_EQ(get_result_constant<int>(func, 14), pow_autob_numpy_expected);
502     ASSERT_EQ(get_result_constant<int>(func, 15), min_autob_numpy_expected);
503     ASSERT_EQ(get_result_constant<int>(func, 16), max_autob_numpy_expected);
504     ASSERT_EQ(get_result_constant<char>(func, 17), equal_autob_numpy_expected);
505     ASSERT_EQ(get_result_constant<char>(func, 18), not_equal_autob_numpy_expected);
506     ASSERT_EQ(get_result_constant<char>(func, 19), greater_autob_numpy_expected);
507     ASSERT_EQ(get_result_constant<char>(func, 20), greater_eq_autob_numpy_expected);
508     ASSERT_EQ(get_result_constant<char>(func, 21), less_autob_numpy_expected);
509     ASSERT_EQ(get_result_constant<char>(func, 22), less_eq_autob_numpy_expected);
510     ASSERT_EQ(get_result_constant<char>(func, 23), logical_or_autob_numpy_expected);
511     ASSERT_EQ(get_result_constant<char>(func, 24), logical_xor_autob_numpy_expected);
512     ASSERT_NO_THROW(pass_manager.run_passes(func_error));
513 }
514
515 TEST(constant_folding, const_quantize)
516 {
517     Shape input_shape{12};
518     Shape scale_offset_shape;
519     AxisSet quantization_axes;
520
521     auto quant_type = element::u8;
522     auto output_type = element::u8;
523     typedef uint8_t output_c_type;
524
525     vector<float> values_in{1.0, 2.0, 2.0, 3.0, 3.0, 4.0, 4.0, 5.0, 5.0, 6.0, 6.0, 7.0};
526     auto constant = op::Constant::create(element::f32, input_shape, values_in);
527     auto scale = op::Constant::create(element::f32, scale_offset_shape, {2});
528     auto offset = op::Constant::create(quant_type, scale_offset_shape, {1});
529     auto mode = op::Quantize::RoundMode::ROUND_NEAREST_TOWARD_INFINITY;
530     auto quantize =
531         make_shared<op::Quantize>(constant, scale, offset, output_type, quantization_axes, mode);
532     quantize->set_friendly_name("test");
533     auto f = make_shared<Function>(quantize, ParameterVector{});
534
535     pass::Manager pass_manager;
536     pass_manager.register_pass<pass::ConstantFolding>();
537     pass_manager.run_passes(f);
538
539     ASSERT_EQ(count_ops_of_type<op::Quantize>(f), 0);
540     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 1);
541
542     auto new_const =
543         as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
544     ASSERT_TRUE(new_const);
545     ASSERT_EQ(new_const->get_friendly_name(), "test");
546     auto values_out = new_const->get_vector<output_c_type>();
547
548     vector<output_c_type> values_quantize{2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5};
549     ASSERT_EQ(values_quantize, values_out);
550 }
551
552 TEST(constant_folding, const_convert)
553 {
554     Shape input_shape{3, 4};
555
556     vector<int32_t> values_in{1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7};
557     auto constant = op::Constant::create(element::f32, input_shape, values_in);
558     auto convert = make_shared<op::Convert>(constant, element::u64);
559     convert->set_friendly_name("test");
560     auto f = make_shared<Function>(convert, ParameterVector{});
561
562     pass::Manager pass_manager;
563     pass_manager.register_pass<pass::ConstantFolding>();
564     pass_manager.run_passes(f);
565
566     ASSERT_EQ(count_ops_of_type<op::Convert>(f), 0);
567     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 1);
568
569     auto new_const =
570         as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
571     ASSERT_TRUE(new_const);
572     ASSERT_EQ(new_const->get_friendly_name(), "test");
573     ASSERT_EQ(new_const->get_output_element_type(0), element::u64);
574     auto values_out = new_const->get_vector<uint64_t>();
575
576     vector<uint64_t> values_expected{1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7};
577     ASSERT_EQ(values_expected, values_out);
578 }
579
580 TEST(constant_folding, shape_of_v0)
581 {
582     Shape input_shape{3, 4, 0, 22, 608, 909, 3};
583
584     auto param = make_shared<op::Parameter>(element::boolean, input_shape);
585     auto shape_of = make_shared<op::v0::ShapeOf>(param);
586     shape_of->set_friendly_name("test");
587     auto f = make_shared<Function>(shape_of, ParameterVector{param});
588
589     pass::Manager pass_manager;
590     pass_manager.register_pass<pass::ConstantFolding>();
591     pass_manager.run_passes(f);
592
593     ASSERT_EQ(count_ops_of_type<op::v0::ShapeOf>(f), 0);
594     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 1);
595
596     auto new_const =
597         as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
598     ASSERT_TRUE(new_const);
599     ASSERT_EQ(new_const->get_friendly_name(), "test");
600     ASSERT_EQ(new_const->get_output_element_type(0), element::i64);
601     auto values_out = new_const->get_vector<int64_t>();
602
603     ASSERT_EQ((vector<int64_t>{3, 4, 0, 22, 608, 909, 3}), values_out);
604 }
605
606 TEST(constant_folding, shape_of_v3)
607 {
608     Shape input_shape{3, 4, 0, 22, 608, 909, 3};
609
610     auto param = make_shared<op::Parameter>(element::boolean, input_shape);
611     auto shape_of = make_shared<op::v3::ShapeOf>(param);
612     shape_of->set_friendly_name("test");
613     auto f = make_shared<Function>(shape_of, ParameterVector{param});
614
615     pass::Manager pass_manager;
616     pass_manager.register_pass<pass::ConstantFolding>();
617     pass_manager.run_passes(f);
618
619     ASSERT_EQ(count_ops_of_type<op::v3::ShapeOf>(f), 0);
620     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 1);
621
622     auto new_const =
623         as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
624     ASSERT_TRUE(new_const);
625     ASSERT_EQ(new_const->get_friendly_name(), "test");
626     ASSERT_EQ(new_const->get_output_element_type(0), element::i64);
627     auto values_out = new_const->get_vector<int64_t>();
628
629     ASSERT_EQ((vector<int64_t>{3, 4, 0, 22, 608, 909, 3}), values_out);
630 }
631
632 TEST(constant_folding, shape_of_i32_v3)
633 {
634     Shape input_shape{3, 4, 0, 22, 608, 909, 3};
635
636     auto param = make_shared<op::Parameter>(element::boolean, input_shape);
637     auto shape_of = make_shared<op::v3::ShapeOf>(param, element::i32);
638     shape_of->set_friendly_name("test");
639     auto f = make_shared<Function>(shape_of, ParameterVector{param});
640
641     pass::Manager pass_manager;
642     pass_manager.register_pass<pass::ConstantFolding>();
643     pass_manager.run_passes(f);
644
645     ASSERT_EQ(count_ops_of_type<op::v3::ShapeOf>(f), 0);
646     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 1);
647
648     auto new_const =
649         as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
650     ASSERT_TRUE(new_const);
651     ASSERT_EQ(new_const->get_friendly_name(), "test");
652     ASSERT_EQ(new_const->get_output_element_type(0), element::i32);
653     auto values_out = new_const->get_vector<int32_t>();
654
655     ASSERT_EQ((vector<int32_t>{3, 4, 0, 22, 608, 909, 3}), values_out);
656 }
657
658 TEST(constant_folding, shape_of_dynamic_v0)
659 {
660     PartialShape input_shape{3, 4, Dimension::dynamic(), 22, 608, 909, 3};
661
662     auto param = make_shared<op::Parameter>(element::boolean, input_shape);
663     auto shape_of = make_shared<op::v0::ShapeOf>(param);
664     shape_of->set_friendly_name("test");
665     auto f = make_shared<Function>(shape_of, ParameterVector{param});
666
667     pass::Manager pass_manager;
668     pass_manager.register_pass<pass::ConstantFolding>();
669     pass_manager.run_passes(f);
670
671     ASSERT_EQ(count_ops_of_type<op::v0::ShapeOf>(f), 1);
672     ASSERT_EQ(count_ops_of_type<op::v1::Gather>(f), 1);
673     ASSERT_EQ(count_ops_of_type<op::Concat>(f), 1);
674     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 8);
675
676     auto result_as_concat =
677         as_type_ptr<op::Concat>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
678     ASSERT_TRUE(result_as_concat);
679     ASSERT_EQ(result_as_concat->get_friendly_name(), "test");
680     ASSERT_EQ(result_as_concat->get_output_shape(0), Shape{7});
681 }
682
683 TEST(constant_folding, shape_of_dynamic_v3)
684 {
685     PartialShape input_shape{3, 4, Dimension::dynamic(), 22, 608, 909, 3};
686
687     auto param = make_shared<op::Parameter>(element::boolean, input_shape);
688     auto shape_of = make_shared<op::v3::ShapeOf>(param);
689     shape_of->set_friendly_name("test");
690     auto f = make_shared<Function>(shape_of, ParameterVector{param});
691
692     pass::Manager pass_manager;
693     pass_manager.register_pass<pass::ConstantFolding>();
694     pass_manager.run_passes(f);
695
696     ASSERT_EQ(count_ops_of_type<op::v3::ShapeOf>(f), 1);
697     ASSERT_EQ(count_ops_of_type<op::v1::Gather>(f), 1);
698     ASSERT_EQ(count_ops_of_type<op::Concat>(f), 1);
699     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 8);
700
701     auto result_as_concat =
702         as_type_ptr<op::Concat>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
703     ASSERT_TRUE(result_as_concat);
704     ASSERT_EQ(result_as_concat->get_friendly_name(), "test");
705     ASSERT_EQ(result_as_concat->get_output_shape(0), Shape{7});
706     ASSERT_EQ(result_as_concat->get_output_element_type(0), element::i64);
707 }
708
709 TEST(constant_folding, shape_of_dynamic_i32_v3)
710 {
711     PartialShape input_shape{3, 4, Dimension::dynamic(), 22, 608, 909, 3};
712
713     auto param = make_shared<op::Parameter>(element::boolean, input_shape);
714     auto shape_of = make_shared<op::v3::ShapeOf>(param, element::i32);
715     shape_of->set_friendly_name("test");
716     auto f = make_shared<Function>(shape_of, ParameterVector{param});
717
718     pass::Manager pass_manager;
719     pass_manager.register_pass<pass::ConstantFolding>();
720     pass_manager.run_passes(f);
721
722     ASSERT_EQ(count_ops_of_type<op::v3::ShapeOf>(f), 1);
723     ASSERT_EQ(count_ops_of_type<op::v1::Gather>(f), 1);
724     ASSERT_EQ(count_ops_of_type<op::Concat>(f), 1);
725     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 8);
726
727     auto result_as_concat =
728         as_type_ptr<op::Concat>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
729     ASSERT_TRUE(result_as_concat);
730     ASSERT_EQ(result_as_concat->get_friendly_name(), "test");
731     ASSERT_EQ(result_as_concat->get_output_shape(0), Shape{7});
732     ASSERT_EQ(result_as_concat->get_output_element_type(0), element::i32);
733 }
734
735 // We need to be sure that constant folding won't be calculated endlessly.
736 TEST(constant_folding, shape_of_dynamic_double_folding_v0)
737 {
738     PartialShape input_shape{3, 4, Dimension::dynamic(), 22, 608, 909, 3};
739
740     auto param = make_shared<op::Parameter>(element::boolean, input_shape);
741     auto shape_of = make_shared<op::v0::ShapeOf>(param);
742     shape_of->set_friendly_name("test");
743     auto f = make_shared<Function>(shape_of, ParameterVector{param});
744
745     pass::Manager pass_manager;
746     pass_manager.register_pass<pass::ConstantFolding>();
747     pass_manager.run_passes(f);
748     pass_manager.run_passes(f);
749
750     ASSERT_EQ(count_ops_of_type<op::v0::ShapeOf>(f), 1);
751     ASSERT_EQ(count_ops_of_type<op::v1::Gather>(f), 1);
752     ASSERT_EQ(count_ops_of_type<op::Concat>(f), 1);
753     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 8);
754
755     auto result_as_concat =
756         as_type_ptr<op::Concat>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
757     ASSERT_TRUE(result_as_concat);
758     ASSERT_EQ(result_as_concat->get_friendly_name(), "test");
759     ASSERT_EQ(result_as_concat->get_output_shape(0), Shape{7});
760 }
761
762 TEST(constant_folding, shape_of_dynamic_double_folding_v3)
763 {
764     PartialShape input_shape{3, 4, Dimension::dynamic(), 22, 608, 909, 3};
765
766     auto param = make_shared<op::Parameter>(element::boolean, input_shape);
767     auto shape_of = make_shared<op::v3::ShapeOf>(param);
768     shape_of->set_friendly_name("test");
769     auto f = make_shared<Function>(shape_of, ParameterVector{param});
770
771     pass::Manager pass_manager;
772     pass_manager.register_pass<pass::ConstantFolding>();
773     pass_manager.run_passes(f);
774     pass_manager.run_passes(f);
775
776     ASSERT_EQ(count_ops_of_type<op::v3::ShapeOf>(f), 1);
777     ASSERT_EQ(count_ops_of_type<op::v1::Gather>(f), 1);
778     ASSERT_EQ(count_ops_of_type<op::Concat>(f), 1);
779     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 8);
780
781     auto result_as_concat =
782         as_type_ptr<op::Concat>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
783     ASSERT_TRUE(result_as_concat);
784     ASSERT_EQ(result_as_concat->get_friendly_name(), "test");
785     ASSERT_EQ(result_as_concat->get_output_shape(0), Shape{7});
786 }
787
788 // Constant folding will not succeed on ShapeOf if the argument rank is dynamic.
789 // We want to make sure it fails gracefully, leaving the ShapeOf op in place.
790 TEST(constant_folding, shape_of_rank_dynamic_v0)
791 {
792     PartialShape input_shape{PartialShape::dynamic()};
793
794     auto param = make_shared<op::Parameter>(element::boolean, input_shape);
795     auto shape_of = make_shared<op::v0::ShapeOf>(param);
796     shape_of->set_friendly_name("test");
797     auto f = make_shared<Function>(shape_of, ParameterVector{param});
798
799     pass::Manager pass_manager;
800     pass_manager.register_pass<pass::ConstantFolding>();
801     pass_manager.run_passes(f);
802
803     ASSERT_EQ(count_ops_of_type<op::v0::ShapeOf>(f), 1);
804     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 0);
805
806     auto result_shape_of = f->get_results().at(0)->get_input_node_shared_ptr(0);
807     ASSERT_EQ(result_shape_of, shape_of);
808     ASSERT_EQ(result_shape_of->get_friendly_name(), "test");
809 }
810
811 TEST(constant_folding, shape_of_rank_dynamic_v3)
812 {
813     PartialShape input_shape{PartialShape::dynamic()};
814
815     auto param = make_shared<op::Parameter>(element::boolean, input_shape);
816     auto shape_of = make_shared<op::v3::ShapeOf>(param);
817     shape_of->set_friendly_name("test");
818     auto f = make_shared<Function>(shape_of, ParameterVector{param});
819
820     pass::Manager pass_manager;
821     pass_manager.register_pass<pass::ConstantFolding>();
822     pass_manager.run_passes(f);
823
824     ASSERT_EQ(count_ops_of_type<op::v3::ShapeOf>(f), 1);
825     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 0);
826
827     auto result_shape_of = f->get_results().at(0)->get_input_node_shared_ptr(0);
828     ASSERT_EQ(result_shape_of, shape_of);
829     ASSERT_EQ(result_shape_of->get_friendly_name(), "test");
830 }
831
832 TEST(constant_folding, const_reverse)
833 {
834     Shape input_shape{3, 3};
835
836     vector<int32_t> values_in{1, 2, 3, 4, 5, 6, 7, 8, 9};
837     auto constant = op::Constant::create(element::i32, input_shape, values_in);
838     auto convert = make_shared<op::Reverse>(constant, AxisSet{1});
839     convert->set_friendly_name("test");
840     auto f = make_shared<Function>(convert, ParameterVector{});
841
842     pass::Manager pass_manager;
843     pass_manager.register_pass<pass::ConstantFolding>();
844     pass_manager.run_passes(f);
845
846     ASSERT_EQ(count_ops_of_type<op::Reverse>(f), 0);
847     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 1);
848
849     auto new_const =
850         as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
851     ASSERT_TRUE(new_const);
852     ASSERT_EQ(new_const->get_friendly_name(), "test");
853     auto values_out = new_const->get_vector<int32_t>();
854
855     vector<int32_t> values_expected{3, 2, 1, 6, 5, 4, 9, 8, 7};
856     ASSERT_EQ(values_expected, values_out);
857 }
858
859 TEST(constant_folding, const_product)
860 {
861     Shape input_shape{3, 3};
862
863     vector<int32_t> values_in{1, 2, 3, 4, 5, 6, 7, 8, 9};
864     auto constant = op::Constant::create(element::i32, input_shape, values_in);
865     auto convert = make_shared<op::Product>(constant, AxisSet{1});
866     convert->set_friendly_name("test");
867     auto f = make_shared<Function>(convert, ParameterVector{});
868
869     pass::Manager pass_manager;
870     pass_manager.register_pass<pass::ConstantFolding>();
871     pass_manager.run_passes(f);
872
873     ASSERT_EQ(count_ops_of_type<op::Product>(f), 0);
874     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 1);
875
876     auto new_const =
877         as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
878     ASSERT_TRUE(new_const);
879     ASSERT_EQ(new_const->get_friendly_name(), "test");
880     auto values_out = new_const->get_vector<int32_t>();
881
882     vector<int32_t> values_expected{6, 120, 504};
883     ASSERT_EQ(values_expected, values_out);
884 }
885
886 TEST(constant_folding, const_reduceprod)
887 {
888     Shape input_shape{3, 3};
889     Shape output_shape{3};
890
891     vector<int32_t> values_in{1, 2, 3, 4, 5, 6, 7, 8, 9};
892     auto constant = op::Constant::create(element::i32, input_shape, values_in);
893     Shape axes_shape{1};
894     vector<int32_t> values_axes{1};
895     auto constant_axes = op::Constant::create(element::i64, axes_shape, values_axes);
896     auto convert = make_shared<op::v1::ReduceProd>(constant, constant_axes);
897     convert->set_friendly_name("test");
898     auto f = make_shared<Function>(convert, ParameterVector{});
899
900     pass::Manager pass_manager;
901     pass_manager.register_pass<pass::ConstantFolding>();
902     pass_manager.run_passes(f);
903
904     ASSERT_EQ(count_ops_of_type<op::v1::ReduceProd>(f), 0);
905     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 1);
906
907     auto new_const =
908         as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
909     ASSERT_TRUE(new_const);
910     ASSERT_EQ(new_const->get_friendly_name(), "test");
911     ASSERT_EQ(new_const->get_shape(), output_shape);
912
913     auto values_out = new_const->get_vector<int32_t>();
914
915     vector<int32_t> values_expected{6, 120, 504};
916
917     ASSERT_EQ(values_expected, values_out);
918 }
919
920 TEST(constant_folding, const_reduceprod_keepdims)
921 {
922     Shape input_shape{3, 3};
923     Shape output_shape{3, 1};
924
925     vector<int32_t> values_in{1, 2, 3, 4, 5, 6, 7, 8, 9};
926     auto constant = op::Constant::create(element::i32, input_shape, values_in);
927     Shape axes_shape{1};
928     vector<int32_t> values_axes{1};
929     auto constant_axes = op::Constant::create(element::i64, axes_shape, values_axes);
930     auto convert = make_shared<op::v1::ReduceProd>(constant, constant_axes, true);
931     convert->set_friendly_name("test");
932     auto f = make_shared<Function>(convert, ParameterVector{});
933
934     pass::Manager pass_manager;
935     pass_manager.register_pass<pass::ConstantFolding>();
936     pass_manager.run_passes(f);
937
938     ASSERT_EQ(count_ops_of_type<op::v1::ReduceProd>(f), 0);
939     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 1);
940
941     auto new_const =
942         as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
943     ASSERT_TRUE(new_const);
944     ASSERT_EQ(new_const->get_friendly_name(), "test");
945     ASSERT_EQ(new_const->get_shape(), output_shape);
946
947     auto values_out = new_const->get_vector<int32_t>();
948
949     vector<int32_t> values_expected{6, 120, 504};
950
951     ASSERT_EQ(values_expected, values_out);
952 }
953
954 TEST(constant_folding, const_sum)
955 {
956     Shape input_shape{3, 3};
957
958     vector<int32_t> values_in{1, 2, 3, 4, 5, 6, 7, 8, 9};
959     auto constant = op::Constant::create(element::i32, input_shape, values_in);
960     auto convert = make_shared<op::Sum>(constant, AxisSet{1});
961     convert->set_friendly_name("test");
962     auto f = make_shared<Function>(convert, ParameterVector{});
963
964     pass::Manager pass_manager;
965     pass_manager.register_pass<pass::ConstantFolding>();
966     pass_manager.run_passes(f);
967
968     ASSERT_EQ(count_ops_of_type<op::Sum>(f), 0);
969     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 1);
970
971     auto new_const =
972         as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
973     ASSERT_TRUE(new_const);
974     ASSERT_EQ(new_const->get_friendly_name(), "test");
975     auto values_out = new_const->get_vector<int32_t>();
976
977     vector<int32_t> values_expected{6, 15, 24};
978
979     ASSERT_EQ(values_expected, values_out);
980 }
981
982 TEST(constant_folding, const_reducesum)
983 {
984     Shape input_shape{3, 3};
985     Shape output_shape{3};
986
987     vector<int32_t> values_in{1, 2, 3, 4, 5, 6, 7, 8, 9};
988     auto constant = op::Constant::create(element::i32, input_shape, values_in);
989     Shape axes_shape{1};
990     vector<int32_t> values_axes{1};
991     auto constant_axes = op::Constant::create(element::i64, axes_shape, values_axes);
992     auto convert = make_shared<op::v1::ReduceSum>(constant, constant_axes);
993     convert->set_friendly_name("test");
994     auto f = make_shared<Function>(convert, ParameterVector{});
995
996     pass::Manager pass_manager;
997     pass_manager.register_pass<pass::ConstantFolding>();
998     pass_manager.run_passes(f);
999
1000     ASSERT_EQ(count_ops_of_type<op::v1::ReduceSum>(f), 0);
1001     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 1);
1002
1003     auto new_const =
1004         as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
1005     ASSERT_TRUE(new_const);
1006     ASSERT_EQ(new_const->get_friendly_name(), "test");
1007     ASSERT_EQ(new_const->get_shape(), output_shape);
1008
1009     auto values_out = new_const->get_vector<int32_t>();
1010
1011     vector<int32_t> values_expected{6, 15, 24};
1012
1013     ASSERT_EQ(values_expected, values_out);
1014 }
1015
1016 TEST(constant_folding, const_reducesum_keepdims)
1017 {
1018     Shape input_shape{3, 3};
1019     Shape output_shape{3, 1};
1020
1021     vector<int32_t> values_in{1, 2, 3, 4, 5, 6, 7, 8, 9};
1022     auto constant = op::Constant::create(element::i32, input_shape, values_in);
1023     Shape axes_shape{1};
1024     vector<int32_t> values_axes{1};
1025     auto constant_axes = op::Constant::create(element::i64, axes_shape, values_axes);
1026     auto convert = make_shared<op::v1::ReduceSum>(constant, constant_axes, true);
1027     convert->set_friendly_name("test");
1028     auto f = make_shared<Function>(convert, ParameterVector{});
1029
1030     pass::Manager pass_manager;
1031     pass_manager.register_pass<pass::ConstantFolding>();
1032     pass_manager.run_passes(f);
1033
1034     ASSERT_EQ(count_ops_of_type<op::v1::ReduceSum>(f), 0);
1035     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 1);
1036
1037     auto new_const =
1038         as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
1039     ASSERT_TRUE(new_const);
1040     ASSERT_EQ(new_const->get_friendly_name(), "test");
1041     ASSERT_EQ(new_const->get_shape(), output_shape);
1042
1043     auto values_out = new_const->get_vector<int32_t>();
1044
1045     vector<int32_t> values_expected{6, 15, 24};
1046
1047     ASSERT_EQ(values_expected, values_out);
1048 }
1049
1050 TEST(constant_folding, const_max)
1051 {
1052     Shape input_shape{3, 3};
1053
1054     vector<int32_t> values_in{1, 2, 3, 4, 5, 6, 7, 8, 9};
1055     auto constant = op::Constant::create(element::i32, input_shape, values_in);
1056     auto convert = make_shared<op::Max>(constant, AxisSet{1});
1057     convert->set_friendly_name("test");
1058     auto f = make_shared<Function>(convert, ParameterVector{});
1059
1060     pass::Manager pass_manager;
1061     pass_manager.register_pass<pass::ConstantFolding>();
1062     pass_manager.run_passes(f);
1063
1064     ASSERT_EQ(count_ops_of_type<op::Max>(f), 0);
1065     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 1);
1066
1067     auto new_const =
1068         as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
1069     ASSERT_TRUE(new_const);
1070     ASSERT_EQ(new_const->get_friendly_name(), "test");
1071     auto values_out = new_const->get_vector<int32_t>();
1072
1073     vector<int32_t> values_expected{3, 6, 9};
1074
1075     ASSERT_EQ(values_expected, values_out);
1076 }
1077
1078 TEST(constant_folding, const_reducemax)
1079 {
1080     Shape input_shape{3, 2};
1081     Shape output_shape{3};
1082
1083     vector<int32_t> values_in{1, 2, 3, 4, 5, 6};
1084     auto constant = op::Constant::create(element::i32, input_shape, values_in);
1085     Shape axes_shape{1};
1086     vector<int32_t> values_axes{1};
1087     auto constant_axes = op::Constant::create(element::i64, axes_shape, values_axes);
1088     auto convert = make_shared<op::v1::ReduceMax>(constant, constant_axes);
1089     convert->set_friendly_name("test");
1090     auto f = make_shared<Function>(convert, ParameterVector{});
1091
1092     pass::Manager pass_manager;
1093     pass_manager.register_pass<pass::ConstantFolding>();
1094     pass_manager.run_passes(f);
1095
1096     ASSERT_EQ(count_ops_of_type<op::v1::ReduceMax>(f), 0);
1097     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 1);
1098
1099     auto new_const =
1100         as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
1101     ASSERT_TRUE(new_const);
1102     ASSERT_EQ(new_const->get_friendly_name(), "test");
1103     ASSERT_EQ(new_const->get_shape(), output_shape);
1104
1105     auto values_out = new_const->get_vector<int32_t>();
1106
1107     vector<int32_t> values_expected{2, 4, 6};
1108
1109     ASSERT_EQ(values_expected, values_out);
1110 }
1111
1112 TEST(constant_folding, const_reducemax_keepdims)
1113 {
1114     Shape input_shape{3, 2};
1115     Shape output_shape{3, 1};
1116
1117     vector<int32_t> values_in{1, 2, 3, 4, 5, 6};
1118     auto constant = op::Constant::create(element::i32, input_shape, values_in);
1119     Shape axes_shape{1};
1120     vector<int32_t> values_axes{1};
1121     auto constant_axes = op::Constant::create(element::i64, axes_shape, values_axes);
1122     auto convert = make_shared<op::v1::ReduceMax>(constant, constant_axes, true);
1123     convert->set_friendly_name("test");
1124     auto f = make_shared<Function>(convert, ParameterVector{});
1125
1126     pass::Manager pass_manager;
1127     pass_manager.register_pass<pass::ConstantFolding>();
1128     pass_manager.run_passes(f);
1129
1130     ASSERT_EQ(count_ops_of_type<op::v1::ReduceMax>(f), 0);
1131     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 1);
1132
1133     auto new_const =
1134         as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
1135     ASSERT_TRUE(new_const);
1136     ASSERT_EQ(new_const->get_friendly_name(), "test");
1137     ASSERT_EQ(new_const->get_shape(), output_shape);
1138
1139     auto values_out = new_const->get_vector<int32_t>();
1140
1141     vector<int32_t> values_expected{2, 4, 6};
1142
1143     ASSERT_EQ(values_expected, values_out);
1144 }
1145
1146 TEST(constant_folding, const_min)
1147 {
1148     Shape input_shape{3, 3};
1149
1150     vector<int32_t> values_in{1, 2, 3, 4, 5, 6, 7, 8, 9};
1151     auto constant = op::Constant::create(element::i32, input_shape, values_in);
1152     auto convert = make_shared<op::Min>(constant, AxisSet{1});
1153     convert->set_friendly_name("test");
1154     auto f = make_shared<Function>(convert, ParameterVector{});
1155
1156     pass::Manager pass_manager;
1157     pass_manager.register_pass<pass::ConstantFolding>();
1158     pass_manager.run_passes(f);
1159
1160     ASSERT_EQ(count_ops_of_type<op::Min>(f), 0);
1161     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 1);
1162
1163     auto new_const =
1164         as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
1165     ASSERT_TRUE(new_const);
1166     ASSERT_EQ(new_const->get_friendly_name(), "test");
1167     auto values_out = new_const->get_vector<int32_t>();
1168
1169     vector<int32_t> values_expected{1, 4, 7};
1170
1171     ASSERT_EQ(values_expected, values_out);
1172 }
1173
1174 TEST(constant_folding, const_reducemin)
1175 {
1176     Shape input_shape{3, 2};
1177     Shape output_shape{3};
1178
1179     vector<int32_t> values_in{1, 2, 3, 4, 5, 6};
1180     auto constant = op::Constant::create(element::i32, input_shape, values_in);
1181     Shape axes_shape{1};
1182     vector<int32_t> values_axes{1};
1183     auto constant_axes = op::Constant::create(element::i64, axes_shape, values_axes);
1184     auto convert = make_shared<op::v1::ReduceMin>(constant, constant_axes);
1185     convert->set_friendly_name("test");
1186     auto f = make_shared<Function>(convert, ParameterVector{});
1187
1188     pass::Manager pass_manager;
1189     pass_manager.register_pass<pass::ConstantFolding>();
1190     pass_manager.run_passes(f);
1191
1192     ASSERT_EQ(count_ops_of_type<op::v1::ReduceMin>(f), 0);
1193     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 1);
1194
1195     auto new_const =
1196         as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
1197     ASSERT_TRUE(new_const);
1198     ASSERT_EQ(new_const->get_friendly_name(), "test");
1199     ASSERT_EQ(new_const->get_shape(), output_shape);
1200
1201     auto values_out = new_const->get_vector<int32_t>();
1202
1203     vector<int32_t> values_expected{1, 3, 5};
1204
1205     ASSERT_EQ(values_expected, values_out);
1206 }
1207
1208 TEST(constant_folding, const_reducemin_keepdims)
1209 {
1210     Shape input_shape{3, 2};
1211     Shape output_shape{3, 1};
1212
1213     vector<int32_t> values_in{1, 2, 3, 4, 5, 6};
1214     auto constant = op::Constant::create(element::i32, input_shape, values_in);
1215     Shape axes_shape{1};
1216     vector<int32_t> values_axes{1};
1217     auto constant_axes = op::Constant::create(element::i64, axes_shape, values_axes);
1218     auto convert = make_shared<op::v1::ReduceMin>(constant, constant_axes, true);
1219     convert->set_friendly_name("test");
1220     auto f = make_shared<Function>(convert, ParameterVector{});
1221
1222     pass::Manager pass_manager;
1223     pass_manager.register_pass<pass::ConstantFolding>();
1224     pass_manager.run_passes(f);
1225
1226     ASSERT_EQ(count_ops_of_type<op::v1::ReduceMin>(f), 0);
1227     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 1);
1228
1229     auto new_const =
1230         as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
1231     ASSERT_TRUE(new_const);
1232     ASSERT_EQ(new_const->get_friendly_name(), "test");
1233     ASSERT_EQ(new_const->get_shape(), output_shape);
1234
1235     auto values_out = new_const->get_vector<int32_t>();
1236
1237     vector<int32_t> values_expected{1, 3, 5};
1238
1239     ASSERT_EQ(values_expected, values_out);
1240 }
1241
1242 TEST(constant_folding, const_reducemean)
1243 {
1244     Shape input_shape{3, 3};
1245     Shape output_shape{3};
1246
1247     vector<int32_t> values_in{1, 2, 3, 4, 5, 6, 7, 8, 9};
1248     auto constant = op::Constant::create(element::i32, input_shape, values_in);
1249     Shape axes_shape{1};
1250     vector<int32_t> values_axes{1};
1251     auto constant_axes = op::Constant::create(element::i64, axes_shape, values_axes);
1252     auto convert = make_shared<op::v1::ReduceMean>(constant, constant_axes);
1253     convert->set_friendly_name("test");
1254     auto f = make_shared<Function>(convert, ParameterVector{});
1255
1256     pass::Manager pass_manager;
1257     pass_manager.register_pass<pass::ConstantFolding>();
1258     pass_manager.run_passes(f);
1259
1260     ASSERT_EQ(count_ops_of_type<op::v1::ReduceMean>(f), 0);
1261     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 1);
1262
1263     auto new_const =
1264         as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
1265     ASSERT_TRUE(new_const);
1266     ASSERT_EQ(new_const->get_friendly_name(), "test");
1267     ASSERT_EQ(new_const->get_shape(), output_shape);
1268
1269     auto values_out = new_const->get_vector<int32_t>();
1270
1271     vector<int32_t> values_expected{2, 5, 8};
1272
1273     ASSERT_EQ(values_expected, values_out);
1274 }
1275
1276 TEST(constant_folding, const_reducemean_keepdims)
1277 {
1278     Shape input_shape{3, 3};
1279     Shape output_shape{3, 1};
1280
1281     vector<int32_t> values_in{1, 2, 3, 4, 5, 6, 7, 8, 9};
1282     auto constant = op::Constant::create(element::i32, input_shape, values_in);
1283     Shape axes_shape{1};
1284     vector<int32_t> values_axes{1};
1285     auto constant_axes = op::Constant::create(element::i64, axes_shape, values_axes);
1286     auto convert = make_shared<op::v1::ReduceMean>(constant, constant_axes, true);
1287     convert->set_friendly_name("test");
1288     auto f = make_shared<Function>(convert, ParameterVector{});
1289
1290     pass::Manager pass_manager;
1291     pass_manager.register_pass<pass::ConstantFolding>();
1292     pass_manager.run_passes(f);
1293
1294     ASSERT_EQ(count_ops_of_type<op::v1::ReduceMean>(f), 0);
1295     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 1);
1296
1297     auto new_const =
1298         as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
1299     ASSERT_TRUE(new_const);
1300     ASSERT_EQ(new_const->get_friendly_name(), "test");
1301     ASSERT_EQ(new_const->get_shape(), output_shape);
1302
1303     auto values_out = new_const->get_vector<int32_t>();
1304
1305     vector<int32_t> values_expected{2, 5, 8};
1306
1307     ASSERT_EQ(values_expected, values_out);
1308 }
1309
1310 TEST(constant_folding, const_reduce_logical_and__no_keepdims)
1311 {
1312     const Shape input_shape{3, 3};
1313
1314     const vector<char> values_in{0, 1, 1, 0, 1, 0, 1, 1, 1};
1315     const auto data = op::Constant::create(element::boolean, input_shape, values_in);
1316     const auto axes = op::Constant::create(element::i64, {1}, {1});
1317     const auto convert = make_shared<op::v1::ReduceLogicalAnd>(data, axes, false);
1318     convert->set_friendly_name("test");
1319     auto f = make_shared<Function>(convert, ParameterVector{});
1320
1321     pass::Manager pass_manager;
1322     pass_manager.register_pass<pass::ConstantFolding>();
1323     pass_manager.run_passes(f);
1324
1325     ASSERT_EQ(count_ops_of_type<op::v1::ReduceLogicalAnd>(f), 0);
1326     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 1);
1327
1328     const auto new_const =
1329         as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
1330     ASSERT_TRUE(new_const);
1331     ASSERT_EQ(new_const->get_friendly_name(), "test");
1332
1333     const Shape expected_out_shape{3};
1334     ASSERT_EQ(new_const->get_shape(), expected_out_shape);
1335
1336     const auto values_out = new_const->get_vector<char>();
1337
1338     const vector<char> values_expected{0, 0, 1};
1339
1340     ASSERT_EQ(values_expected, values_out);
1341 }
1342
1343 TEST(constant_folding, const_reduce_logical_and__keepdims)
1344 {
1345     const Shape input_shape{3, 3};
1346
1347     const vector<char> values_in{0, 1, 1, 0, 1, 0, 1, 1, 1};
1348     const auto data = op::Constant::create(element::boolean, input_shape, values_in);
1349     const auto axes = op::Constant::create(element::i64, {1}, {1});
1350     const auto convert = make_shared<op::v1::ReduceLogicalAnd>(data, axes, true);
1351     convert->set_friendly_name("test");
1352     auto f = make_shared<Function>(convert, ParameterVector{});
1353
1354     pass::Manager pass_manager;
1355     pass_manager.register_pass<pass::ConstantFolding>();
1356     pass_manager.run_passes(f);
1357
1358     ASSERT_EQ(count_ops_of_type<op::v1::ReduceLogicalAnd>(f), 0);
1359     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 1);
1360
1361     const auto new_const =
1362         as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
1363     ASSERT_TRUE(new_const);
1364     ASSERT_EQ(new_const->get_friendly_name(), "test");
1365
1366     // the output shape is expected to have 'ones' at the positions specified in the reduction axes
1367     // in case the keep_dims attribute of ReduceLogicalAnd is set to true
1368     const Shape expected_out_shape{3, 1};
1369     ASSERT_EQ(new_const->get_shape(), expected_out_shape);
1370
1371     const auto values_out = new_const->get_vector<char>();
1372
1373     const vector<char> values_expected{0, 0, 1};
1374
1375     ASSERT_EQ(values_expected, values_out);
1376 }
1377
1378 TEST(constant_folding, const_reduce_logical_and__keepdims_3d)
1379 {
1380     const Shape input_shape{2, 2, 2};
1381
1382     const vector<char> values_in{1, 1, 0, 0, 1, 0, 0, 1};
1383     const auto data = op::Constant::create(element::boolean, input_shape, values_in);
1384     const auto axes = op::Constant::create(element::i64, {2}, {0, 2});
1385     const auto convert = make_shared<op::v1::ReduceLogicalAnd>(data, axes, true);
1386     convert->set_friendly_name("test");
1387     auto f = make_shared<Function>(convert, ParameterVector{});
1388
1389     pass::Manager pass_manager;
1390     pass_manager.register_pass<pass::ConstantFolding>();
1391     pass_manager.run_passes(f);
1392
1393     ASSERT_EQ(count_ops_of_type<op::v1::ReduceLogicalAnd>(f), 0);
1394     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 1);
1395
1396     const auto new_const =
1397         as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
1398     ASSERT_TRUE(new_const);
1399     ASSERT_EQ(new_const->get_friendly_name(), "test");
1400
1401     const Shape expected_out_shape{1, 2, 1};
1402     ASSERT_EQ(new_const->get_shape(), expected_out_shape);
1403
1404     const auto values_out = new_const->get_vector<char>();
1405
1406     const vector<char> values_expected{0, 0};
1407
1408     ASSERT_EQ(values_expected, values_out);
1409 }
1410
1411 TEST(constant_folding, const_reduce_logical_or__no_keepdims)
1412 {
1413     const Shape input_shape{3, 3};
1414
1415     const vector<char> values_in{1, 0, 0, 1, 0, 1, 0, 0, 0};
1416     const auto data = op::Constant::create(element::boolean, input_shape, values_in);
1417     const auto axes = op::Constant::create(element::i64, {1}, {1});
1418     const auto convert = make_shared<op::v1::ReduceLogicalOr>(data, axes, false);
1419     convert->set_friendly_name("test");
1420     auto f = make_shared<Function>(convert, ParameterVector{});
1421
1422     pass::Manager pass_manager;
1423     pass_manager.register_pass<pass::ConstantFolding>();
1424     pass_manager.run_passes(f);
1425
1426     ASSERT_EQ(count_ops_of_type<op::v1::ReduceLogicalAnd>(f), 0);
1427     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 1);
1428
1429     const auto new_const =
1430         as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
1431     ASSERT_TRUE(new_const);
1432     ASSERT_EQ(new_const->get_friendly_name(), "test");
1433
1434     const Shape expected_out_shape{3};
1435     ASSERT_EQ(new_const->get_shape(), expected_out_shape);
1436
1437     const auto values_out = new_const->get_vector<char>();
1438
1439     const vector<char> values_expected{1, 1, 0};
1440
1441     ASSERT_EQ(values_expected, values_out);
1442 }
1443
1444 TEST(constant_folding, const_concat)
1445 {
1446     auto constant0 =
1447         op::Constant::create(element::i32, Shape{2, 3}, vector<int32_t>{1, 2, 3, 4, 5, 6});
1448     auto constant1 = op::Constant::create(element::i32, Shape{2, 1}, vector<int32_t>{7, 8});
1449     auto concat = make_shared<op::Concat>(NodeVector{constant0, constant1}, 1);
1450     concat->set_friendly_name("test");
1451     auto f = make_shared<Function>(concat, ParameterVector{});
1452
1453     pass::Manager pass_manager;
1454     pass_manager.register_pass<pass::ConstantFolding>();
1455     pass_manager.run_passes(f);
1456
1457     ASSERT_EQ(count_ops_of_type<op::Concat>(f), 0);
1458     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 1);
1459
1460     auto new_const =
1461         as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
1462     ASSERT_TRUE(new_const);
1463     ASSERT_EQ(new_const->get_friendly_name(), "test");
1464     auto values_out = new_const->get_vector<int32_t>();
1465
1466     vector<int32_t> values_expected{1, 2, 3, 7, 4, 5, 6, 8};
1467
1468     ASSERT_EQ(values_expected, values_out);
1469 }
1470
1471 TEST(constant_folding, const_concat_3d_single_elem)
1472 {
1473     auto constant_1 = op::Constant::create(element::i32, Shape{1, 1, 1}, vector<int32_t>{1});
1474     auto constant_2 = op::Constant::create(element::i32, Shape{1, 1, 1}, vector<int32_t>{2});
1475     auto concat = make_shared<op::Concat>(NodeVector{constant_1, constant_2}, 0);
1476     concat->set_friendly_name("test");
1477     auto f = make_shared<Function>(concat, ParameterVector{});
1478
1479     pass::Manager pass_manager;
1480     pass_manager.register_pass<pass::ConstantFolding>();
1481     pass_manager.run_passes(f);
1482
1483     ASSERT_EQ(count_ops_of_type<op::Concat>(f), 0);
1484     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 1);
1485
1486     auto new_const =
1487         as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
1488
1489     ASSERT_TRUE(new_const);
1490     ASSERT_EQ(new_const->get_friendly_name(), "test");
1491     ASSERT_EQ(new_const->get_output_shape(0), (Shape{2, 1, 1}));
1492
1493     auto values_out = new_const->get_vector<int32_t>();
1494     vector<int32_t> values_expected{1, 2};
1495     ASSERT_EQ(values_expected, values_out);
1496 }
1497
1498 TEST(constant_folding, const_concat_axis_2)
1499 {
1500     auto constant_1 =
1501         op::Constant::create(element::i32, Shape{3, 1, 2}, vector<int32_t>{1, 2, 3, 4, 5, 6});
1502     auto constant_2 = op::Constant::create(
1503         element::i32, Shape{3, 1, 4}, vector<int32_t>{7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18});
1504     auto concat = make_shared<op::Concat>(NodeVector{constant_1, constant_2}, 2);
1505     concat->set_friendly_name("test");
1506     auto f = make_shared<Function>(concat, ParameterVector{});
1507
1508     pass::Manager pass_manager;
1509     pass_manager.register_pass<pass::ConstantFolding>();
1510     pass_manager.run_passes(f);
1511
1512     ASSERT_EQ(count_ops_of_type<op::Concat>(f), 0);
1513     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 1);
1514
1515     auto new_const =
1516         as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
1517
1518     ASSERT_TRUE(new_const);
1519     ASSERT_EQ(new_const->get_friendly_name(), "test");
1520     ASSERT_EQ(new_const->get_output_shape(0), (Shape{3, 1, 6}));
1521
1522     auto values_out = new_const->get_vector<int32_t>();
1523     vector<int32_t> values_expected{1, 2, 7, 8, 9, 10, 3, 4, 11, 12, 13, 14, 5, 6, 15, 16, 17, 18};
1524     ASSERT_EQ(values_expected, values_out);
1525 }
1526
1527 TEST(constant_folding, const_concat_axis_1_bool_type)
1528 {
1529     auto constant_1 =
1530         op::Constant::create(element::boolean, Shape{1, 1, 2}, vector<int32_t>{true, true});
1531     auto constant_2 = op::Constant::create(
1532         element::boolean, Shape{1, 2, 2}, vector<char>{true, false, true, false});
1533     auto constant_3 = op::Constant::create(
1534         element::boolean, Shape{1, 3, 2}, vector<char>{true, false, true, false, true, false});
1535     auto concat = make_shared<op::Concat>(NodeVector{constant_1, constant_2, constant_3}, 1);
1536     concat->set_friendly_name("test");
1537     auto f = make_shared<Function>(concat, ParameterVector{});
1538
1539     pass::Manager pass_manager;
1540     pass_manager.register_pass<pass::ConstantFolding>();
1541     pass_manager.run_passes(f);
1542
1543     ASSERT_EQ(count_ops_of_type<op::Concat>(f), 0);
1544     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 1);
1545
1546     auto new_const =
1547         as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
1548
1549     ASSERT_TRUE(new_const);
1550     ASSERT_EQ(new_const->get_friendly_name(), "test");
1551     ASSERT_EQ(new_const->get_output_shape(0), (Shape{1, 6, 2}));
1552
1553     auto values_out = new_const->get_vector<char>();
1554     vector<char> values_expected{
1555         true, true, true, false, true, false, true, false, true, false, true, false};
1556     ASSERT_EQ(values_expected, values_out);
1557 }
1558
1559 TEST(constant_folding, const_not)
1560 {
1561     auto constant =
1562         op::Constant::create(element::boolean, Shape{2, 3}, vector<char>{0, 1, 0, 0, 1, 1});
1563     auto logical_not = make_shared<op::Not>(constant);
1564     logical_not->set_friendly_name("test");
1565     auto f = make_shared<Function>(logical_not, ParameterVector{});
1566
1567     pass::Manager pass_manager;
1568     pass_manager.register_pass<pass::ConstantFolding>();
1569     pass_manager.run_passes(f);
1570
1571     ASSERT_EQ(count_ops_of_type<op::Not>(f), 0);
1572     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 1);
1573
1574     auto new_const =
1575         as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
1576     ASSERT_TRUE(new_const);
1577     ASSERT_EQ(new_const->get_friendly_name(), "test");
1578     auto values_out = new_const->get_vector<char>();
1579
1580     vector<char> values_expected{1, 0, 1, 1, 0, 0};
1581
1582     ASSERT_EQ(values_expected, values_out);
1583 }
1584
1585 TEST(constant_folding, const_equal)
1586 {
1587     auto constant0 =
1588         op::Constant::create(element::i32, Shape{2, 3}, vector<int32_t>{1, 2, 3, 4, 5, 6});
1589     auto constant1 =
1590         op::Constant::create(element::i32, Shape{2, 3}, vector<int32_t>{1, 2, 2, 3, 5, 6});
1591     auto eq = make_shared<op::Equal>(constant0, constant1);
1592     eq->set_friendly_name("test");
1593     auto f = make_shared<Function>(eq, ParameterVector{});
1594
1595     pass::Manager pass_manager;
1596     pass_manager.register_pass<pass::ConstantFolding>();
1597     pass_manager.run_passes(f);
1598
1599     ASSERT_EQ(count_ops_of_type<op::Equal>(f), 0);
1600     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 1);
1601
1602     auto new_const =
1603         as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
1604     ASSERT_TRUE(new_const);
1605     ASSERT_EQ(new_const->get_friendly_name(), "test");
1606     auto values_out = new_const->get_vector<char>();
1607
1608     vector<char> values_expected{1, 1, 0, 0, 1, 1};
1609
1610     ASSERT_EQ(values_expected, values_out);
1611 }
1612
1613 TEST(constant_folding, const_not_equal)
1614 {
1615     auto constant0 =
1616         op::Constant::create(element::i32, Shape{2, 3}, vector<int32_t>{1, 2, 3, 4, 5, 6});
1617     auto constant1 =
1618         op::Constant::create(element::i32, Shape{2, 3}, vector<int32_t>{1, 2, 2, 3, 5, 6});
1619     auto eq = make_shared<op::NotEqual>(constant0, constant1);
1620     eq->set_friendly_name("test");
1621     auto f = make_shared<Function>(eq, ParameterVector{});
1622
1623     pass::Manager pass_manager;
1624     pass_manager.register_pass<pass::ConstantFolding>();
1625     pass_manager.run_passes(f);
1626
1627     ASSERT_EQ(count_ops_of_type<op::NotEqual>(f), 0);
1628     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 1);
1629
1630     auto new_const =
1631         as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
1632     ASSERT_TRUE(new_const);
1633     ASSERT_EQ(new_const->get_friendly_name(), "test");
1634     auto values_out = new_const->get_vector<char>();
1635
1636     vector<char> values_expected{0, 0, 1, 1, 0, 0};
1637
1638     ASSERT_EQ(values_expected, values_out);
1639 }
1640
1641 TEST(constant_folding, const_greater)
1642 {
1643     auto constant0 =
1644         op::Constant::create(element::i32, Shape{2, 3}, vector<int32_t>{1, 2, 3, 4, 5, 6});
1645     auto constant1 =
1646         op::Constant::create(element::i32, Shape{2, 3}, vector<int32_t>{2, 2, 2, 5, 5, 5});
1647     auto eq = make_shared<op::Greater>(constant0, constant1);
1648     eq->set_friendly_name("test");
1649     auto f = make_shared<Function>(eq, ParameterVector{});
1650
1651     pass::Manager pass_manager;
1652     pass_manager.register_pass<pass::ConstantFolding>();
1653     pass_manager.run_passes(f);
1654
1655     ASSERT_EQ(count_ops_of_type<op::Greater>(f), 0);
1656     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 1);
1657
1658     auto new_const =
1659         as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
1660     ASSERT_TRUE(new_const);
1661     ASSERT_EQ(new_const->get_friendly_name(), "test");
1662     auto values_out = new_const->get_vector<char>();
1663
1664     vector<char> values_expected{0, 0, 1, 0, 0, 1};
1665
1666     ASSERT_EQ(values_expected, values_out);
1667 }
1668
1669 TEST(constant_folding, const_greater_eq)
1670 {
1671     auto constant0 =
1672         op::Constant::create(element::i32, Shape{2, 3}, vector<int32_t>{1, 2, 3, 4, 5, 6});
1673     auto constant1 =
1674         op::Constant::create(element::i32, Shape{2, 3}, vector<int32_t>{2, 2, 2, 5, 5, 5});
1675     auto eq = make_shared<op::GreaterEq>(constant0, constant1);
1676     eq->set_friendly_name("test");
1677     auto f = make_shared<Function>(eq, ParameterVector{});
1678
1679     pass::Manager pass_manager;
1680     pass_manager.register_pass<pass::ConstantFolding>();
1681     pass_manager.run_passes(f);
1682
1683     ASSERT_EQ(count_ops_of_type<op::GreaterEq>(f), 0);
1684     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 1);
1685
1686     auto new_const =
1687         as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
1688     ASSERT_TRUE(new_const);
1689     ASSERT_EQ(new_const->get_friendly_name(), "test");
1690     auto values_out = new_const->get_vector<char>();
1691
1692     vector<char> values_expected{0, 1, 1, 0, 1, 1};
1693
1694     ASSERT_EQ(values_expected, values_out);
1695 }
1696
1697 TEST(constant_folding, const_less)
1698 {
1699     auto constant0 =
1700         op::Constant::create(element::i32, Shape{2, 3}, vector<int32_t>{1, 2, 3, 4, 5, 6});
1701     auto constant1 =
1702         op::Constant::create(element::i32, Shape{2, 3}, vector<int32_t>{2, 2, 2, 5, 5, 5});
1703     auto eq = make_shared<op::Less>(constant0, constant1);
1704     eq->set_friendly_name("test");
1705     auto f = make_shared<Function>(eq, ParameterVector{});
1706
1707     pass::Manager pass_manager;
1708     pass_manager.register_pass<pass::ConstantFolding>();
1709     pass_manager.run_passes(f);
1710
1711     ASSERT_EQ(count_ops_of_type<op::Less>(f), 0);
1712     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 1);
1713
1714     auto new_const =
1715         as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
1716     ASSERT_TRUE(new_const);
1717     ASSERT_EQ(new_const->get_friendly_name(), "test");
1718     auto values_out = new_const->get_vector<char>();
1719
1720     vector<char> values_expected{1, 0, 0, 1, 0, 0};
1721
1722     ASSERT_EQ(values_expected, values_out);
1723 }
1724
1725 TEST(constant_folding, const_less_eq)
1726 {
1727     auto constant0 =
1728         op::Constant::create(element::i32, Shape{2, 3}, vector<int32_t>{1, 2, 3, 4, 5, 6});
1729     auto constant1 =
1730         op::Constant::create(element::i32, Shape{2, 3}, vector<int32_t>{2, 2, 2, 5, 5, 5});
1731     auto eq = make_shared<op::LessEq>(constant0, constant1);
1732     eq->set_friendly_name("test");
1733     auto f = make_shared<Function>(eq, ParameterVector{});
1734
1735     pass::Manager pass_manager;
1736     pass_manager.register_pass<pass::ConstantFolding>();
1737     pass_manager.run_passes(f);
1738
1739     ASSERT_EQ(count_ops_of_type<op::LessEq>(f), 0);
1740     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 1);
1741
1742     auto new_const =
1743         as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
1744     ASSERT_TRUE(new_const);
1745     ASSERT_EQ(new_const->get_friendly_name(), "test");
1746     auto values_out = new_const->get_vector<char>();
1747
1748     vector<char> values_expected{1, 1, 0, 1, 1, 0};
1749
1750     ASSERT_EQ(values_expected, values_out);
1751 }
1752
1753 TEST(constant_folding, const_or)
1754 {
1755     auto constant0 =
1756         op::Constant::create(element::boolean, Shape{2, 3}, vector<int32_t>{0, 0, 1, 0, 1, 1});
1757     auto constant1 =
1758         op::Constant::create(element::boolean, Shape{2, 3}, vector<int32_t>{0, 1, 1, 1, 0, 1});
1759     auto eq = make_shared<op::Or>(constant0, constant1);
1760     eq->set_friendly_name("test");
1761     auto f = make_shared<Function>(eq, ParameterVector{});
1762
1763     pass::Manager pass_manager;
1764     pass_manager.register_pass<pass::ConstantFolding>();
1765     pass_manager.run_passes(f);
1766
1767     ASSERT_EQ(count_ops_of_type<op::Or>(f), 0);
1768     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 1);
1769
1770     auto new_const =
1771         as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
1772     ASSERT_TRUE(new_const);
1773     ASSERT_EQ(new_const->get_friendly_name(), "test");
1774     auto values_out = new_const->get_vector<char>();
1775
1776     vector<char> values_expected{0, 1, 1, 1, 1, 1};
1777
1778     ASSERT_EQ(values_expected, values_out);
1779 }
1780
1781 TEST(constant_folding, const_xor)
1782 {
1783     auto constant0 =
1784         op::Constant::create(element::boolean, Shape{2, 3}, vector<int32_t>{0, 0, 1, 0, 1, 1});
1785     auto constant1 =
1786         op::Constant::create(element::boolean, Shape{2, 3}, vector<int32_t>{0, 1, 1, 1, 0, 1});
1787     auto eq = make_shared<op::Xor>(constant0, constant1);
1788     eq->set_friendly_name("test");
1789     auto f = make_shared<Function>(eq, ParameterVector{});
1790
1791     pass::Manager pass_manager;
1792     pass_manager.register_pass<pass::ConstantFolding>();
1793     pass_manager.run_passes(f);
1794
1795     ASSERT_EQ(count_ops_of_type<op::Xor>(f), 0);
1796     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 1);
1797
1798     auto new_const =
1799         as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
1800     ASSERT_TRUE(new_const);
1801     ASSERT_EQ(new_const->get_friendly_name(), "test");
1802     auto values_out = new_const->get_vector<char>();
1803
1804     vector<char> values_expected{0, 1, 0, 1, 1, 0};
1805
1806     ASSERT_EQ(values_expected, values_out);
1807 }
1808
1809 TEST(constant_folding, const_ceiling)
1810 {
1811     auto constant = op::Constant::create(
1812         element::f32, Shape{2, 3}, vector<float>{0.0f, 0.1f, -0.1f, -2.5f, 2.5f, 3.0f});
1813     auto ceil = make_shared<op::Ceiling>(constant);
1814     ceil->set_friendly_name("test");
1815     auto f = make_shared<Function>(ceil, ParameterVector{});
1816
1817     pass::Manager pass_manager;
1818     pass_manager.register_pass<pass::ConstantFolding>();
1819     pass_manager.run_passes(f);
1820
1821     ASSERT_EQ(count_ops_of_type<op::Ceiling>(f), 0);
1822     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 1);
1823
1824     auto new_const =
1825         as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
1826     ASSERT_TRUE(new_const);
1827     ASSERT_EQ(new_const->get_friendly_name(), "test");
1828     auto values_out = new_const->get_vector<float>();
1829
1830     vector<float> values_expected{0.0f, 1.0f, 0.0f, -2.0f, 3.0f, 3.0f};
1831
1832     ASSERT_TRUE(test::all_close_f(values_out, values_expected, MIN_FLOAT_TOLERANCE_BITS));
1833 }
1834
1835 TEST(constant_folding, const_floor)
1836 {
1837     auto constant = op::Constant::create(
1838         element::f32, Shape{2, 3}, vector<float>{0.0f, 0.1f, -0.1f, -2.5f, 2.5f, 3.0f});
1839     auto floor = make_shared<op::Floor>(constant);
1840     floor->set_friendly_name("test");
1841     auto f = make_shared<Function>(floor, ParameterVector{});
1842
1843     pass::Manager pass_manager;
1844     pass_manager.register_pass<pass::ConstantFolding>();
1845     pass_manager.run_passes(f);
1846
1847     ASSERT_EQ(count_ops_of_type<op::Floor>(f), 0);
1848     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 1);
1849
1850     auto new_const =
1851         as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
1852     ASSERT_TRUE(new_const);
1853     ASSERT_EQ(new_const->get_friendly_name(), "test");
1854     auto values_out = new_const->get_vector<float>();
1855
1856     vector<float> values_expected{0.0f, 0.0f, -1.0f, -3.0f, 2.0f, 3.0f};
1857
1858     ASSERT_TRUE(test::all_close_f(values_out, values_expected, MIN_FLOAT_TOLERANCE_BITS));
1859 }
1860
1861 TEST(constant_folding, const_gather)
1862 {
1863     auto constant_data = op::Constant::create(
1864         element::f32,
1865         Shape{2, 5},
1866         vector<float>{1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f});
1867     auto constant_indices =
1868         op::Constant::create(element::i64, Shape{4}, vector<int64_t>{0, 3, 2, 2});
1869     size_t gather_axis = 1;
1870     auto gather = make_shared<op::v0::Gather>(constant_data, constant_indices, gather_axis);
1871     gather->set_friendly_name("test");
1872     auto f = make_shared<Function>(gather, ParameterVector{});
1873
1874     pass::Manager pass_manager;
1875     pass_manager.register_pass<pass::ConstantFolding>();
1876     pass_manager.run_passes(f);
1877
1878     ASSERT_EQ(count_ops_of_type<op::v0::Gather>(f), 0);
1879     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 1);
1880
1881     auto new_const =
1882         as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
1883     ASSERT_TRUE(new_const);
1884     ASSERT_EQ(new_const->get_friendly_name(), "test");
1885     auto values_out = new_const->get_vector<float>();
1886
1887     vector<float> values_expected{1.0f, 4.0f, 3.0f, 3.0f, 6.0f, 9.0f, 8.0f, 8.0f};
1888
1889     ASSERT_TRUE(test::all_close_f(values_out, values_expected, MIN_FLOAT_TOLERANCE_BITS));
1890 }
1891
1892 TEST(constant_folding, const_gather_v1)
1893 {
1894     auto constant_data = op::Constant::create(
1895         element::f32,
1896         Shape{2, 5},
1897         vector<float>{1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f});
1898     auto constant_indices =
1899         op::Constant::create(element::i64, Shape{4}, vector<int64_t>{0, 3, 2, 2});
1900     auto constant_axis = op::Constant::create(element::i64, Shape{1}, vector<int64_t>{1});
1901     auto gather = make_shared<op::v1::Gather>(constant_data, constant_indices, constant_axis);
1902     gather->set_friendly_name("test");
1903     auto f = make_shared<Function>(gather, ParameterVector{});
1904
1905     pass::Manager pass_manager;
1906     pass_manager.register_pass<pass::ConstantFolding>();
1907     pass_manager.run_passes(f);
1908
1909     ASSERT_EQ(count_ops_of_type<op::v1::Gather>(f), 0);
1910     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 1);
1911
1912     auto new_const =
1913         as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
1914     ASSERT_TRUE(new_const);
1915     ASSERT_EQ(new_const->get_friendly_name(), "test");
1916     auto values_out = new_const->get_vector<float>();
1917
1918     vector<float> values_expected{1.0f, 4.0f, 3.0f, 3.0f, 6.0f, 9.0f, 8.0f, 8.0f};
1919
1920     ASSERT_TRUE(test::all_close_f(values_out, values_expected, MIN_FLOAT_TOLERANCE_BITS));
1921 }
1922
1923 TEST(constant_folding, const_gather_v1_scalar)
1924 {
1925     auto constant_data = op::Constant::create(
1926         element::f32,
1927         Shape{2, 5},
1928         vector<float>{1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f});
1929     auto constant_indices =
1930         op::Constant::create(element::i64, Shape{4}, vector<int64_t>{0, 3, 2, 2});
1931     auto constant_axis = op::Constant::create(element::i64, Shape{}, vector<int64_t>{1});
1932     auto gather = make_shared<op::v1::Gather>(constant_data, constant_indices, constant_axis);
1933     gather->set_friendly_name("test");
1934     auto f = make_shared<Function>(gather, ParameterVector{});
1935
1936     pass::Manager pass_manager;
1937     pass_manager.register_pass<pass::ConstantFolding>();
1938     pass_manager.run_passes(f);
1939
1940     ASSERT_EQ(count_ops_of_type<op::v1::Gather>(f), 0);
1941     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 1);
1942
1943     auto new_const =
1944         as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
1945     ASSERT_TRUE(new_const);
1946     ASSERT_EQ(new_const->get_friendly_name(), "test");
1947     auto values_out = new_const->get_vector<float>();
1948
1949     vector<float> values_expected{1.0f, 4.0f, 3.0f, 3.0f, 6.0f, 9.0f, 8.0f, 8.0f};
1950
1951     ASSERT_TRUE(test::all_close_f(values_out, values_expected, MIN_FLOAT_TOLERANCE_BITS));
1952 }
1953
1954 TEST(constant_folding, const_gather_v1_subgraph)
1955 {
1956     const auto A = make_shared<op::Parameter>(element::f32, Shape{1});
1957     const float b_value = 3.21f;
1958     const auto B_const = op::Constant::create(element::f32, {1}, {b_value});
1959     const auto C = make_shared<op::Parameter>(element::f32, Shape{1});
1960     const int64_t axis = 0;
1961     const auto axis_const = op::Constant::create(element::i64, {}, {axis});
1962
1963     const auto concat = make_shared<op::Concat>(NodeVector{A, B_const, C}, axis);
1964
1965     const vector<int64_t> indices{1};
1966     const auto indices_const = op::Constant::create(element::i64, {indices.size()}, indices);
1967     const auto gather = make_shared<op::v1::Gather>(concat, indices_const, axis_const);
1968     gather->set_friendly_name("test");
1969     auto f = make_shared<Function>(gather, ParameterVector{A, C});
1970
1971     pass::Manager pass_manager;
1972     pass_manager.register_pass<pass::ConstantFolding>();
1973     pass_manager.run_passes(f);
1974
1975     ASSERT_EQ(count_ops_of_type<op::Concat>(f), 0);
1976     ASSERT_EQ(count_ops_of_type<op::v1::Gather>(f), 0);
1977     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 1);
1978
1979     const auto new_const =
1980         as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
1981     ASSERT_TRUE(new_const);
1982     ASSERT_EQ(new_const->get_friendly_name(), "test");
1983
1984     const auto values_out = new_const->get_vector<float>();
1985     ASSERT_TRUE(test::all_close_f(values_out, {b_value}, MIN_FLOAT_TOLERANCE_BITS));
1986 }
1987
1988 TEST(constant_folding, const_gather_v1_subgraph_neg_axis)
1989 {
1990     const auto A = make_shared<op::Parameter>(element::f32, Shape{1});
1991     const float b_value = 1.23f;
1992     const auto B = make_shared<op::Parameter>(element::f32, Shape{1});
1993     const auto C_const = op::Constant::create(element::f32, {1}, {b_value});
1994     const int64_t axis = 0;
1995     const auto axis_const = op::Constant::create(element::i64, {}, {axis});
1996
1997     const auto concat = make_shared<op::Concat>(NodeVector{A, B, C_const}, axis);
1998
1999     const vector<int64_t> indices{-1};
2000     const auto indices_const = op::Constant::create(element::i64, {indices.size()}, indices);
2001     const auto gather = make_shared<op::v1::Gather>(concat, indices_const, axis_const);
2002     gather->set_friendly_name("test");
2003     auto f = make_shared<Function>(gather, ParameterVector{A, B});
2004
2005     pass::Manager pass_manager;
2006     pass_manager.register_pass<pass::ConstantFolding>();
2007     pass_manager.run_passes(f);
2008
2009     ASSERT_EQ(count_ops_of_type<op::Concat>(f), 0);
2010     ASSERT_EQ(count_ops_of_type<op::v1::Gather>(f), 0);
2011     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 1);
2012
2013     const auto new_const =
2014         as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
2015     ASSERT_TRUE(new_const);
2016     ASSERT_EQ(new_const->get_friendly_name(), "test");
2017
2018     const auto values_out = new_const->get_vector<float>();
2019     ASSERT_TRUE(test::all_close_f(values_out, {b_value}, MIN_FLOAT_TOLERANCE_BITS));
2020 }
2021
2022 TEST(constant_folding, const_gather_v1_subgraph_no_constant_input)
2023 {
2024     const auto A = make_shared<op::Parameter>(element::f32, Shape{1});
2025     const auto B = make_shared<op::Parameter>(element::f32, Shape{1});
2026     const auto C = make_shared<op::Parameter>(element::f32, Shape{1});
2027     const int64_t axis = 0;
2028     const auto axis_const = op::Constant::create(element::i64, {}, {axis});
2029
2030     const auto concat = make_shared<op::Concat>(NodeVector{A, B, C}, axis);
2031
2032     const vector<int64_t> indices{1};
2033     const auto indices_const = op::Constant::create(element::i64, {indices.size()}, indices);
2034     const auto gather = make_shared<op::v1::Gather>(concat, indices_const, axis_const);
2035     gather->set_friendly_name("test");
2036     auto f = make_shared<Function>(gather, ParameterVector{A, B, C});
2037
2038     pass::Manager pass_manager;
2039     pass_manager.register_pass<pass::ConstantFolding>();
2040     pass_manager.run_passes(f);
2041
2042     ASSERT_EQ(count_ops_of_type<op::Concat>(f), 0);
2043     ASSERT_EQ(count_ops_of_type<op::v1::Gather>(f), 0);
2044 }
2045
2046 TEST(constant_folding, const_gather_v1_subgraph_no_constant_input_scalar)
2047 {
2048     const auto A = make_shared<op::Parameter>(element::f32, Shape{1});
2049     const auto B = make_shared<op::Parameter>(element::f32, Shape{1});
2050     const auto C = make_shared<op::Parameter>(element::f32, Shape{1});
2051     const int64_t axis = 0;
2052     const auto axis_const = op::Constant::create(element::i64, {}, {axis});
2053
2054     const auto concat = make_shared<op::Concat>(NodeVector{A, B, C}, axis);
2055
2056     const vector<int64_t> indices{1};
2057     const auto indices_const = op::Constant::create(element::i64, {}, indices);
2058     const auto gather = make_shared<op::v1::Gather>(concat, indices_const, axis_const);
2059     auto f = make_shared<Function>(gather, ParameterVector{A, B, C});
2060
2061     pass::Manager pass_manager;
2062     pass_manager.register_pass<pass::ConstantFolding>();
2063     pass_manager.run_passes(f);
2064
2065     ASSERT_EQ(count_ops_of_type<op::Concat>(f), 0);
2066     ASSERT_EQ(count_ops_of_type<op::v1::Gather>(f), 0);
2067     ASSERT_EQ(count_ops_of_type<op::v0::Squeeze>(f), 1);
2068 }
2069
2070 TEST(constant_folding, const_gather_v1_subgraph_skip_if_non_zero_axis)
2071 {
2072     const auto A = make_shared<op::Parameter>(element::f32, Shape{2, 2});
2073     const auto B = make_shared<op::Parameter>(element::f32, Shape{2, 2});
2074     const auto C = make_shared<op::Parameter>(element::f32, Shape{2, 2});
2075     const int64_t axis = 1;
2076     const auto axis_const = op::Constant::create(element::i64, {}, {axis});
2077
2078     const auto concat = make_shared<op::Concat>(NodeVector{A, B, C}, axis);
2079
2080     const vector<int64_t> indices{1};
2081     const auto indices_const = op::Constant::create(element::i64, {indices.size()}, indices);
2082     const auto gather = make_shared<op::v1::Gather>(concat, indices_const, axis_const);
2083     auto f = make_shared<Function>(gather, ParameterVector{A, B, C});
2084
2085     pass::Manager pass_manager;
2086     pass_manager.register_pass<pass::ConstantFolding>();
2087     pass_manager.run_passes(f);
2088
2089     ASSERT_EQ(count_ops_of_type<op::Concat>(f), 1);
2090     ASSERT_EQ(count_ops_of_type<op::v1::Gather>(f), 1);
2091 }
2092
2093 TEST(constant_folding, const_gather_v1_subgraph_skip_if_non_single_indices)
2094 {
2095     const auto A = make_shared<op::Parameter>(element::f32, Shape{1});
2096     const auto B = make_shared<op::Parameter>(element::f32, Shape{1});
2097     const auto C = make_shared<op::Parameter>(element::f32, Shape{1});
2098     const int64_t axis = 0;
2099     const auto axis_const = op::Constant::create(element::i64, {}, {axis});
2100
2101     const auto concat = make_shared<op::Concat>(NodeVector{A, B, C}, axis);
2102
2103     const vector<int64_t> indices{0, 1};
2104     const auto indices_const = op::Constant::create(element::i64, {indices.size()}, indices);
2105     const auto gather = make_shared<op::v1::Gather>(concat, indices_const, axis_const);
2106     auto f = make_shared<Function>(gather, ParameterVector{A, B, C});
2107
2108     pass::Manager pass_manager;
2109     pass_manager.register_pass<pass::ConstantFolding>();
2110     pass_manager.run_passes(f);
2111
2112     ASSERT_EQ(count_ops_of_type<op::Concat>(f), 1);
2113     ASSERT_EQ(count_ops_of_type<op::v1::Gather>(f), 1);
2114 }
2115
2116 TEST(constant_folding, const_gather_v1_subgraph_skip_if_concat_output_shape_dynamic)
2117 {
2118     const auto A = make_shared<op::Parameter>(element::f32, PartialShape::dynamic());
2119     const auto B = make_shared<op::Parameter>(element::f32, Shape{1});
2120     const auto C = make_shared<op::Parameter>(element::f32, Shape{1});
2121     const int64_t axis = 0;
2122     const auto axis_const = op::Constant::create(element::i64, {}, {axis});
2123
2124     const auto concat = make_shared<op::Concat>(NodeVector{A, B, C}, axis);
2125
2126     const vector<int64_t> indices{1};
2127     const auto indices_const = op::Constant::create(element::i64, {indices.size()}, indices);
2128     const auto gather = make_shared<op::v1::Gather>(concat, indices_const, axis_const);
2129     auto f = make_shared<Function>(gather, ParameterVector{A, B, C});
2130
2131     pass::Manager pass_manager;
2132     pass_manager.register_pass<pass::ConstantFolding>();
2133     pass_manager.run_passes(f);
2134
2135     ASSERT_EQ(count_ops_of_type<op::Concat>(f), 1);
2136     ASSERT_EQ(count_ops_of_type<op::v1::Gather>(f), 1);
2137 }
2138
2139 TEST(constant_folding, const_gather_v1_subgraph_skip_if_not_single_input)
2140 {
2141     const auto A = make_shared<op::Parameter>(element::f32, Shape{2});
2142     const auto B = make_shared<op::Parameter>(element::f32, Shape{1});
2143     const auto C = make_shared<op::Parameter>(element::f32, Shape{1});
2144     const int64_t axis = 0;
2145     const auto axis_const = op::Constant::create(element::i64, {}, {axis});
2146
2147     const auto concat = make_shared<op::Concat>(NodeVector{A, B, C}, axis);
2148
2149     const vector<int64_t> indices{1};
2150     const auto indices_const = op::Constant::create(element::i64, {indices.size()}, indices);
2151     const auto gather = make_shared<op::v1::Gather>(concat, indices_const, axis_const);
2152     auto f = make_shared<Function>(gather, ParameterVector{A, B, C});
2153
2154     pass::Manager pass_manager;
2155     pass_manager.register_pass<pass::ConstantFolding>();
2156     pass_manager.run_passes(f);
2157
2158     ASSERT_EQ(count_ops_of_type<op::Concat>(f), 1);
2159     ASSERT_EQ(count_ops_of_type<op::v1::Gather>(f), 1);
2160 }
2161
2162 TEST(constant_folding, const_slice)
2163 {
2164     Shape shape_in{16};
2165
2166     vector<int> values_in{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
2167     auto constant = make_shared<op::Constant>(element::i32, shape_in, values_in);
2168     auto slice = make_shared<op::Slice>(constant, Coordinate{2}, Coordinate{15}, Strides{3});
2169     slice->set_friendly_name("test");
2170
2171     auto f = make_shared<Function>(slice, ParameterVector{});
2172
2173     pass::Manager pass_manager;
2174     pass_manager.register_pass<pass::ConstantFolding>();
2175     pass_manager.run_passes(f);
2176
2177     ASSERT_EQ(count_ops_of_type<op::Slice>(f), 0);
2178     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 1);
2179
2180     auto new_const =
2181         as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
2182     ASSERT_TRUE(new_const);
2183     ASSERT_EQ(new_const->get_friendly_name(), "test");
2184     auto values_out = new_const->get_vector<int>();
2185
2186     vector<int> sliced_values{3, 6, 9, 12, 15};
2187     ASSERT_EQ(sliced_values, values_out);
2188 }
2189
2190 TEST(constant_folding, constant_dyn_reshape)
2191 {
2192     Shape shape_in{2, 4};
2193     vector<float> values_in{0, 1, 2, 3, 4, 5, 6, 7};
2194
2195     Shape shape_shape{3};
2196     vector<int64_t> values_shape{2, 4, 1};
2197
2198     auto constant_in = make_shared<op::Constant>(element::f32, shape_in, values_in);
2199     auto constant_shape = make_shared<op::Constant>(element::i64, shape_shape, values_shape);
2200     auto dyn_reshape = make_shared<op::v1::Reshape>(constant_in, constant_shape, false);
2201     dyn_reshape->set_friendly_name("test");
2202     auto f = make_shared<Function>(dyn_reshape, ParameterVector{});
2203
2204     pass::Manager pass_manager;
2205     pass_manager.register_pass<pass::ConstantFolding>();
2206     pass_manager.run_passes(f);
2207
2208     ASSERT_EQ(count_ops_of_type<op::v1::Reshape>(f), 0);
2209     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 1);
2210
2211     auto new_const =
2212         as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
2213     ASSERT_TRUE(new_const);
2214     ASSERT_EQ(new_const->get_friendly_name(), "test");
2215     auto values_out = new_const->get_vector<float>();
2216
2217     ASSERT_TRUE(test::all_close_f(values_in, values_out, MIN_FLOAT_TOLERANCE_BITS));
2218 }
2219
2220 TEST(constant_folding, constant_dyn_reshape_shape_not_originally_constant)
2221 {
2222     Shape shape_in{2, 4};
2223     vector<float> values_in{0, 1, 2, 3, 4, 5, 6, 7};
2224
2225     Shape shape_shape{3};
2226     // We're going to add these two together elementwise to get {2, 4, 1}.
2227     // This means that when ConstantFolding starts, v1::Reshape will not yet
2228     // have static output shape. But by the time the Add op is folded, the
2229     // v1::Reshape's shape should be inferrable.
2230     vector<int64_t> values_shape_a{1, 3, 0};
2231     vector<int64_t> values_shape_b{1, 1, 1};
2232
2233     auto constant_in = make_shared<op::Constant>(element::f32, shape_in, values_in);
2234     auto constant_shape_a = make_shared<op::Constant>(element::i64, shape_shape, values_shape_a);
2235     auto constant_shape_b = make_shared<op::Constant>(element::i64, shape_shape, values_shape_b);
2236     auto dyn_reshape =
2237         make_shared<op::v1::Reshape>(constant_in, constant_shape_a + constant_shape_b, false);
2238     dyn_reshape->set_friendly_name("test");
2239     auto f = make_shared<Function>(dyn_reshape, ParameterVector{});
2240
2241     ASSERT_TRUE(dyn_reshape->get_output_partial_shape(0).is_dynamic());
2242
2243     pass::Manager pass_manager;
2244     pass_manager.register_pass<pass::ConstantFolding>();
2245     pass_manager.run_passes(f);
2246
2247     ASSERT_EQ(count_ops_of_type<op::v1::Reshape>(f), 0);
2248     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 1);
2249
2250     auto new_const =
2251         as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
2252     ASSERT_TRUE(new_const);
2253     ASSERT_EQ(new_const->get_friendly_name(), "test");
2254     auto values_out = new_const->get_vector<float>();
2255
2256     ASSERT_TRUE(test::all_close_f(values_in, values_out, MIN_FLOAT_TOLERANCE_BITS));
2257 }
2258
2259 TEST(constant_folding, constant_transpose)
2260 {
2261     Shape shape_in{2, 4};
2262     vector<double> values_in{0, 1, 2, 3, 4, 5, 6, 7};
2263
2264     Shape shape_perm{2};
2265     vector<int64_t> values_perm{1, 0};
2266
2267     auto constant_in = make_shared<op::Constant>(element::f64, shape_in, values_in);
2268     auto constant_perm = make_shared<op::Constant>(element::i64, shape_perm, values_perm);
2269     auto transpose = make_shared<op::Transpose>(constant_in, constant_perm);
2270     transpose->set_friendly_name("test");
2271     auto f = make_shared<Function>(transpose, ParameterVector{});
2272
2273     pass::Manager pass_manager;
2274     pass_manager.register_pass<pass::ConstantFolding>();
2275     pass_manager.run_passes(f);
2276
2277     ASSERT_EQ(count_ops_of_type<op::Transpose>(f), 0);
2278     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 1);
2279
2280     auto new_const =
2281         as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
2282     ASSERT_TRUE(new_const);
2283     ASSERT_EQ(new_const->get_friendly_name(), "test");
2284     auto values_out = new_const->get_vector<double>();
2285
2286     vector<double> values_permute{0, 4, 1, 5, 2, 6, 3, 7};
2287     ASSERT_TRUE(test::all_close_f(values_permute, values_out, MIN_FLOAT_TOLERANCE_BITS));
2288 }
2289
2290 template <typename T>
2291 void range_test(T start, T stop, T step, const vector<T>& values_expected)
2292 {
2293     vector<T> values_start{start};
2294     vector<T> values_stop{stop};
2295     vector<T> values_step{step};
2296
2297     auto constant_start = make_shared<op::Constant>(element::from<T>(), Shape{}, values_start);
2298     auto constant_stop = make_shared<op::Constant>(element::from<T>(), Shape{}, values_stop);
2299     auto constant_step = make_shared<op::Constant>(element::from<T>(), Shape{}, values_step);
2300     auto range = make_shared<op::Range>(constant_start, constant_stop, constant_step);
2301     range->set_friendly_name("test");
2302     auto f = make_shared<Function>(range, ParameterVector{});
2303
2304     pass::Manager pass_manager;
2305     pass_manager.register_pass<pass::ConstantFolding>();
2306     pass_manager.run_passes(f);
2307
2308     ASSERT_EQ(count_ops_of_type<op::Range>(f), 0);
2309     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 1);
2310
2311     auto new_const =
2312         as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
2313     ASSERT_TRUE(new_const);
2314     ASSERT_EQ(new_const->get_friendly_name(), "test");
2315
2316     auto values_out = new_const->template get_vector<T>();
2317
2318     range_test_check(values_out, values_expected);
2319 }
2320
2321 TEST(constant_folding, constant_range)
2322 {
2323     range_test<int8_t>(5, 12, 2, {5, 7, 9, 11});
2324     range_test<int32_t>(5, 12, 2, {5, 7, 9, 11});
2325     range_test<int64_t>(5, 12, 2, {5, 7, 9, 11});
2326     range_test<uint64_t>(5, 12, 2, {5, 7, 9, 11});
2327     range_test<double>(5, 12, 2, {5, 7, 9, 11});
2328     range_test<float>(5, 12, 2, {5, 7, 9, 11});
2329
2330     range_test<int32_t>(5, 12, -2, {});
2331     range_test<float>(12, 4, -2, {12, 10, 8, 6});
2332 }
2333
2334 TEST(constant_folding, constant_select)
2335 {
2336     Shape shape{2, 4};
2337     vector<char> values_selection{0, 1, 1, 0, 1, 0, 0, 1};
2338     vector<int64_t> values_t{2, 4, 6, 8, 10, 12, 14, 16};
2339     vector<int64_t> values_f{1, 3, 5, 7, 9, 11, 13, 15};
2340
2341     auto constant_selection = make_shared<op::Constant>(element::boolean, shape, values_selection);
2342     auto constant_t = make_shared<op::Constant>(element::i64, shape, values_t);
2343     auto constant_f = make_shared<op::Constant>(element::i64, shape, values_f);
2344     auto select = make_shared<op::Select>(constant_selection, constant_t, constant_f);
2345     select->set_friendly_name("test");
2346     auto f = make_shared<Function>(select, ParameterVector{});
2347
2348     pass::Manager pass_manager;
2349     pass_manager.register_pass<pass::ConstantFolding>();
2350     pass_manager.run_passes(f);
2351
2352     ASSERT_EQ(count_ops_of_type<op::Select>(f), 0);
2353     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 1);
2354
2355     auto new_const =
2356         as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
2357     ASSERT_TRUE(new_const);
2358     ASSERT_EQ(new_const->get_friendly_name(), "test");
2359     auto values_out = new_const->get_vector<int64_t>();
2360
2361     vector<int64_t> values_expected{1, 4, 6, 7, 10, 11, 13, 16};
2362     ASSERT_EQ(values_expected, values_out);
2363 }
2364
2365 TEST(constant_folding, constant_v1_select)
2366 {
2367     Shape shape{2, 4};
2368     vector<char> values_selection{0, 1, 1, 0};
2369     vector<int64_t> values_t{1, 2, 3, 4};
2370     vector<int64_t> values_f{11, 12, 13, 14, 15, 16, 17, 18};
2371
2372     auto constant_selection =
2373         make_shared<op::Constant>(element::boolean, Shape{4}, values_selection);
2374     auto constant_t = make_shared<op::Constant>(element::i64, Shape{4}, values_t);
2375     auto constant_f = make_shared<op::Constant>(element::i64, Shape{2, 4}, values_f);
2376     auto select = make_shared<op::v1::Select>(constant_selection, constant_t, constant_f);
2377     select->set_friendly_name("test");
2378     auto f = make_shared<Function>(select, ParameterVector{});
2379
2380     pass::Manager pass_manager;
2381     pass_manager.register_pass<pass::ConstantFolding>();
2382     pass_manager.run_passes(f);
2383
2384     ASSERT_EQ(count_ops_of_type<op::Select>(f), 0);
2385     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 1);
2386
2387     auto new_const =
2388         as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
2389     ASSERT_TRUE(new_const);
2390     ASSERT_EQ(new_const->get_friendly_name(), "test");
2391     auto values_out = new_const->get_vector<int64_t>();
2392
2393     vector<int64_t> values_expected{11, 2, 3, 14, 15, 2, 3, 18};
2394     ASSERT_EQ(values_expected, values_out);
2395 }
2396
2397 TEST(constant_folding, constant_v1_split)
2398 {
2399     vector<float> data{.1f, .2f, .3f, .4f, .5f, .6f};
2400     const auto const_data = op::Constant::create(element::f32, Shape{data.size()}, data);
2401     const auto const_axis = op::Constant::create(element::i64, Shape{}, {0});
2402     const auto num_splits = 3;
2403
2404     auto split_v1 = make_shared<op::v1::Split>(const_data, const_axis, num_splits);
2405     auto f = make_shared<Function>(split_v1->outputs(), ParameterVector{});
2406
2407     pass::Manager pass_manager;
2408     pass_manager.register_pass<pass::ConstantFolding>();
2409     pass_manager.run_passes(f);
2410
2411     ASSERT_EQ(count_ops_of_type<op::v1::Split>(f), 0);
2412     ASSERT_EQ(count_ops_of_type<op::Constant>(f), num_splits);
2413
2414     auto res1 =
2415         as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
2416     auto res2 =
2417         as_type_ptr<op::Constant>(f->get_results().at(1)->input_value(0).get_node_shared_ptr());
2418     auto res3 =
2419         as_type_ptr<op::Constant>(f->get_results().at(2)->input_value(0).get_node_shared_ptr());
2420     ASSERT_TRUE(res1);
2421     ASSERT_TRUE(res2);
2422     ASSERT_TRUE(res3);
2423
2424     auto res1_values = res1->get_vector<float>();
2425     ASSERT_TRUE(test::all_close_f(vector<float>(data.begin(), data.begin() + 2), res1_values));
2426     auto res2_values = res2->get_vector<float>();
2427     ASSERT_TRUE(test::all_close_f(vector<float>(data.begin() + 2, data.begin() + 4), res2_values));
2428     auto res3_values = res3->get_vector<float>();
2429     ASSERT_TRUE(test::all_close_f(vector<float>(data.begin() + 4, data.end()), res3_values));
2430 }
2431
2432 TEST(constant_folding, constant_v1_split_specialized)
2433 {
2434     vector<float> data{.1f, .2f, .3f, .4f, .5f, .6f};
2435     const auto const_data = op::Constant::create(element::f32, Shape{data.size()}, data);
2436     const auto const_axis = op::Constant::create(element::i64, Shape{}, {0});
2437     const auto num_splits = 3;
2438
2439     auto split_v1 = make_shared<op::v1::Split>(const_data, const_axis, num_splits);
2440     auto f = make_shared<Function>(split_v1->outputs(), ParameterVector{});
2441
2442     pass::Manager pass_manager;
2443     pass_manager.register_pass<pass::ConstantFolding>();
2444     pass_manager.run_passes(f);
2445
2446     ASSERT_EQ(count_ops_of_type<op::v1::Split>(f), 0);
2447     ASSERT_EQ(count_ops_of_type<op::Constant>(f), num_splits);
2448
2449     auto res1 =
2450         as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
2451     auto res2 =
2452         as_type_ptr<op::Constant>(f->get_results().at(1)->input_value(0).get_node_shared_ptr());
2453     auto res3 =
2454         as_type_ptr<op::Constant>(f->get_results().at(2)->input_value(0).get_node_shared_ptr());
2455     ASSERT_TRUE(res1);
2456     ASSERT_TRUE(res2);
2457     ASSERT_TRUE(res3);
2458
2459     auto res1_values = res1->get_vector<float>();
2460     ASSERT_TRUE(test::all_close_f(vector<float>(data.begin(), data.begin() + 2), res1_values));
2461     auto res2_values = res2->get_vector<float>();
2462     ASSERT_TRUE(test::all_close_f(vector<float>(data.begin() + 2, data.begin() + 4), res2_values));
2463     auto res3_values = res3->get_vector<float>();
2464     ASSERT_TRUE(test::all_close_f(vector<float>(data.begin() + 4, data.end()), res3_values));
2465 }
2466
2467 TEST(constant_folding, constant_v1_split_axis_1_4_splits)
2468 {
2469     vector<int64_t> data{0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  10, 11, 12, 13, 14, 15,
2470
2471                          16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
2472
2473                          32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
2474
2475                          48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63};
2476
2477     const auto const_data = op::Constant::create(element::i64, Shape{4, 4, 4}, data);
2478     const auto const_axis = op::Constant::create(element::i64, Shape{}, {1});
2479     const auto num_splits = 4;
2480
2481     auto split_v1 = make_shared<op::v1::Split>(const_data, const_axis, num_splits);
2482     split_v1->set_friendly_name("test");
2483     auto f = make_shared<Function>(split_v1->outputs(), ParameterVector{});
2484
2485     pass::Manager pass_manager;
2486     pass_manager.register_pass<pass::ConstantFolding>();
2487     pass_manager.run_passes(f);
2488
2489     ASSERT_EQ(count_ops_of_type<op::v1::Split>(f), 0);
2490     ASSERT_EQ(count_ops_of_type<op::Constant>(f), num_splits);
2491
2492     auto res1 =
2493         as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
2494     auto res2 =
2495         as_type_ptr<op::Constant>(f->get_results().at(1)->input_value(0).get_node_shared_ptr());
2496     auto res3 =
2497         as_type_ptr<op::Constant>(f->get_results().at(2)->input_value(0).get_node_shared_ptr());
2498     auto res4 =
2499         as_type_ptr<op::Constant>(f->get_results().at(3)->input_value(0).get_node_shared_ptr());
2500     ASSERT_TRUE(res1);
2501     ASSERT_EQ(res1->get_friendly_name(), "test.0");
2502     ASSERT_TRUE(res2);
2503     ASSERT_EQ(res2->get_friendly_name(), "test.1");
2504     ASSERT_TRUE(res3);
2505     ASSERT_EQ(res3->get_friendly_name(), "test.2");
2506     ASSERT_TRUE(res4);
2507     ASSERT_EQ(res4->get_friendly_name(), "test.3");
2508
2509     auto res1_values = res1->get_vector<int64_t>();
2510     ASSERT_EQ(vector<int64_t>({0, 1, 2, 3, 16, 17, 18, 19, 32, 33, 34, 35, 48, 49, 50, 51}),
2511               res1_values);
2512     auto res2_values = res2->get_vector<int64_t>();
2513     ASSERT_EQ(vector<int64_t>({4, 5, 6, 7, 20, 21, 22, 23, 36, 37, 38, 39, 52, 53, 54, 55}),
2514               res2_values);
2515     auto res3_values = res3->get_vector<int64_t>();
2516     ASSERT_EQ(vector<int64_t>({8, 9, 10, 11, 24, 25, 26, 27, 40, 41, 42, 43, 56, 57, 58, 59}),
2517               res3_values);
2518     auto res4_values = res4->get_vector<int64_t>();
2519     ASSERT_EQ(vector<int64_t>({12, 13, 14, 15, 28, 29, 30, 31, 44, 45, 46, 47, 60, 61, 62, 63}),
2520               res4_values);
2521 }
2522
2523 TEST(constant_folding, constant_v1_split_axis_1_2_splits)
2524 {
2525     vector<int64_t> data{0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  10, 11, 12, 13, 14, 15,
2526
2527                          16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
2528
2529                          32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
2530
2531                          48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63};
2532
2533     const auto const_data = op::Constant::create(element::i64, Shape{4, 4, 4}, data);
2534     const auto const_axis = op::Constant::create(element::i64, Shape{}, {1});
2535     const auto num_splits = 2;
2536
2537     auto split_v1 = make_shared<op::v1::Split>(const_data, const_axis, num_splits);
2538     auto f = make_shared<Function>(split_v1->outputs(), ParameterVector{});
2539
2540     pass::Manager pass_manager;
2541     pass_manager.register_pass<pass::ConstantFolding>();
2542     pass_manager.run_passes(f);
2543
2544     ASSERT_EQ(count_ops_of_type<op::v1::Split>(f), 0);
2545     ASSERT_EQ(count_ops_of_type<op::Constant>(f), num_splits);
2546
2547     auto res1 =
2548         as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
2549     auto res2 =
2550         as_type_ptr<op::Constant>(f->get_results().at(1)->input_value(0).get_node_shared_ptr());
2551     ASSERT_TRUE(res1);
2552     ASSERT_TRUE(res2);
2553
2554     auto res1_values = res1->get_vector<int64_t>();
2555     ASSERT_EQ(vector<int64_t>({0,  1,  2,  3,  4,  5,  6,  7,  16, 17, 18, 19, 20, 21, 22, 23,
2556                                32, 33, 34, 35, 36, 37, 38, 39, 48, 49, 50, 51, 52, 53, 54, 55}),
2557               res1_values);
2558     auto res2_values = res2->get_vector<int64_t>();
2559     ASSERT_EQ(vector<int64_t>({8,  9,  10, 11, 12, 13, 14, 15, 24, 25, 26, 27, 28, 29, 30, 31,
2560                                40, 41, 42, 43, 44, 45, 46, 47, 56, 57, 58, 59, 60, 61, 62, 63}),
2561               res2_values);
2562 }
2563
2564 TEST(constant_folding, constant_v1_variadic_split_axis_1_2_splits)
2565 {
2566     vector<int64_t> data{0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  10, 11, 12, 13, 14, 15,
2567
2568                          16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
2569
2570                          32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
2571
2572                          48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63};
2573
2574     const auto const_data = op::Constant::create(element::i64, Shape{4, 4, 4}, data);
2575     const auto const_axis = op::Constant::create(element::i16, Shape{}, {1});
2576     vector<int64_t> values_lengths{3, 1};
2577     auto constant_lengths =
2578         make_shared<op::Constant>(element::i64, Shape{values_lengths.size()}, values_lengths);
2579
2580     auto variadic_split_v1 =
2581         make_shared<op::v1::VariadicSplit>(const_data, const_axis, constant_lengths);
2582     auto f = make_shared<Function>(variadic_split_v1->outputs(), ParameterVector{});
2583
2584     pass::Manager pass_manager;
2585     pass_manager.register_pass<pass::ConstantFolding>();
2586     pass_manager.run_passes(f);
2587
2588     ASSERT_EQ(count_ops_of_type<op::v1::VariadicSplit>(f), 0);
2589     ASSERT_EQ(count_ops_of_type<op::Constant>(f), values_lengths.size());
2590
2591     auto res1 =
2592         as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
2593     auto res2 =
2594         as_type_ptr<op::Constant>(f->get_results().at(1)->input_value(0).get_node_shared_ptr());
2595     ASSERT_TRUE(res1);
2596     ASSERT_TRUE(res2);
2597
2598     auto res1_values = res1->get_vector<int64_t>();
2599     ASSERT_EQ(vector<int64_t>({0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  10, 11, 16, 17, 18, 19,
2600                                20, 21, 22, 23, 24, 25, 26, 27, 32, 33, 34, 35, 36, 37, 38, 39,
2601                                40, 41, 42, 43, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59}),
2602               res1_values);
2603     auto res2_values = res2->get_vector<int64_t>();
2604     ASSERT_EQ(vector<int64_t>({12, 13, 14, 15, 28, 29, 30, 31, 44, 45, 46, 47, 60, 61, 62, 63}),
2605               res2_values);
2606 }
2607
2608 TEST(constant_folding, constant_v1_variadic_split_axis_1_3_splits_neg_length)
2609 {
2610     vector<int64_t> data{0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  10, 11, 12, 13, 14, 15,
2611
2612                          16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
2613
2614                          32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
2615
2616                          48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63};
2617
2618     const auto const_data = op::Constant::create(element::i64, Shape{4, 4, 4}, data);
2619     const auto const_axis = op::Constant::create(element::i32, Shape{}, {1});
2620     vector<int64_t> values_lengths{1, 1, -1};
2621     auto constant_lengths =
2622         make_shared<op::Constant>(element::i64, Shape{values_lengths.size()}, values_lengths);
2623
2624     auto variadic_split_v1 =
2625         make_shared<op::v1::VariadicSplit>(const_data, const_axis, constant_lengths);
2626     auto f = make_shared<Function>(variadic_split_v1->outputs(), ParameterVector{});
2627
2628     pass::Manager pass_manager;
2629     pass_manager.register_pass<pass::ConstantFolding>();
2630     pass_manager.run_passes(f);
2631
2632     ASSERT_EQ(count_ops_of_type<op::v1::VariadicSplit>(f), 0);
2633     ASSERT_EQ(count_ops_of_type<op::Constant>(f), values_lengths.size());
2634
2635     auto res1 =
2636         as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
2637     auto res2 =
2638         as_type_ptr<op::Constant>(f->get_results().at(1)->input_value(0).get_node_shared_ptr());
2639     auto res3 =
2640         as_type_ptr<op::Constant>(f->get_results().at(2)->input_value(0).get_node_shared_ptr());
2641     ASSERT_TRUE(res1);
2642     ASSERT_TRUE(res2);
2643     ASSERT_TRUE(res3);
2644
2645     auto res1_values = res1->get_vector<int64_t>();
2646     ASSERT_EQ(vector<int64_t>({0, 1, 2, 3, 16, 17, 18, 19, 32, 33, 34, 35, 48, 49, 50, 51}),
2647               res1_values);
2648     auto res2_values = res2->get_vector<int64_t>();
2649     ASSERT_EQ(vector<int64_t>({4, 5, 6, 7, 20, 21, 22, 23, 36, 37, 38, 39, 52, 53, 54, 55}),
2650               res2_values);
2651     auto res3_values = res3->get_vector<int64_t>();
2652     ASSERT_EQ(vector<int64_t>({8,  9,  10, 11, 12, 13, 14, 15, 24, 25, 26, 27, 28, 29, 30, 31,
2653                                40, 41, 42, 43, 44, 45, 46, 47, 56, 57, 58, 59, 60, 61, 62, 63}),
2654               res3_values);
2655 }
2656
2657 TEST(constant_folding, constant_v1_one_hot)
2658 {
2659     vector<int64_t> indices{0, 1, 2};
2660     float16 on_value = 1.123f;
2661     float16 off_value = 0.321f;
2662
2663     const auto indices_const = op::Constant::create(element::i64, Shape{3}, indices);
2664     const auto depth_const = op::Constant::create(element::i64, Shape{}, {3});
2665     const auto on_const = op::Constant::create(element::f16, Shape{}, {on_value});
2666     const auto off_const = op::Constant::create(element::f16, Shape{}, {off_value});
2667     int64_t axis = 1;
2668
2669     auto one_hot_v1 =
2670         make_shared<op::v1::OneHot>(indices_const, depth_const, on_const, off_const, axis);
2671     auto f = make_shared<Function>(one_hot_v1, ParameterVector{});
2672
2673     pass::Manager pass_manager;
2674     pass_manager.register_pass<pass::ConstantFolding>();
2675     pass_manager.run_passes(f);
2676
2677     ASSERT_EQ(count_ops_of_type<op::v1::OneHot>(f), 0);
2678     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 1);
2679
2680     auto res =
2681         as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
2682     ASSERT_TRUE(res);
2683
2684     ASSERT_EQ((Shape{3, 3}), res->get_output_shape(0));
2685     ASSERT_EQ(vector<float16>({on_value,
2686                                off_value,
2687                                off_value,
2688                                off_value,
2689                                on_value,
2690                                off_value,
2691                                off_value,
2692                                off_value,
2693                                on_value}),
2694               res->get_vector<float16>());
2695 }
2696
2697 TEST(constant_folding, constant_v1_one_hot_negative_axes)
2698 {
2699     vector<int64_t> indices{0, 2, -1, 1};
2700     int16_t on_value = 4;
2701     int16_t off_value = 1;
2702
2703     const auto indices_const = op::Constant::create(element::i64, Shape{4}, indices);
2704     const auto depth_const = op::Constant::create(element::i64, Shape{}, {3});
2705     const auto on_const = op::Constant::create(element::i16, Shape{}, {on_value});
2706     const auto off_const = op::Constant::create(element::i16, Shape{}, {off_value});
2707     int64_t axis = -1;
2708
2709     auto one_hot_v1 =
2710         make_shared<op::v1::OneHot>(indices_const, depth_const, on_const, off_const, axis);
2711     auto f = make_shared<Function>(one_hot_v1, ParameterVector{});
2712
2713     pass::Manager pass_manager;
2714     pass_manager.register_pass<pass::ConstantFolding>();
2715     pass_manager.run_passes(f);
2716
2717     ASSERT_EQ(count_ops_of_type<op::v1::OneHot>(f), 0);
2718     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 1);
2719
2720     auto res =
2721         as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
2722     ASSERT_TRUE(res);
2723
2724     ASSERT_EQ((Shape{4, 3}), res->get_output_shape(0));
2725     ASSERT_EQ(vector<int16_t>({on_value,
2726                                off_value,
2727                                off_value,
2728                                off_value,
2729                                off_value,
2730                                on_value,
2731                                off_value,
2732                                off_value,
2733                                off_value,
2734                                off_value,
2735                                on_value,
2736                                off_value}),
2737               res->get_vector<int16_t>());
2738 }
2739
2740 TEST(constant_folding, constant_v1_one_hot_negative_axes_2)
2741 {
2742     vector<int64_t> indices{0, 2, 1, -1};
2743     auto on_value = true;
2744     auto off_value = false;
2745
2746     const auto indices_const = op::Constant::create(element::i64, Shape{2, 2}, indices);
2747     const auto depth_const = op::Constant::create(element::i64, Shape{}, {3});
2748     const auto on_const = op::Constant::create(element::boolean, Shape{}, {on_value});
2749     const auto off_const = op::Constant::create(element::boolean, Shape{}, {off_value});
2750     int64_t axis = -1;
2751
2752     auto one_hot_v1 =
2753         make_shared<op::v1::OneHot>(indices_const, depth_const, on_const, off_const, axis);
2754     one_hot_v1->set_friendly_name("test");
2755     auto f = make_shared<Function>(one_hot_v1, ParameterVector{});
2756
2757     pass::Manager pass_manager;
2758     pass_manager.register_pass<pass::ConstantFolding>();
2759     pass_manager.run_passes(f);
2760
2761     ASSERT_EQ(count_ops_of_type<op::v1::OneHot>(f), 0);
2762     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 1);
2763
2764     auto res =
2765         as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
2766     ASSERT_TRUE(res);
2767     ASSERT_EQ(res->get_friendly_name(), "test");
2768
2769     ASSERT_EQ((Shape{2, 2, 3}), res->get_output_shape(0));
2770     ASSERT_EQ(vector<bool>({on_value,
2771                             off_value,
2772                             off_value,
2773                             off_value,
2774                             off_value,
2775                             on_value,
2776                             off_value,
2777                             on_value,
2778                             off_value,
2779                             off_value,
2780                             off_value,
2781                             off_value}),
2782               res->get_vector<bool>());
2783 }
2784
2785 TEST(constant_folding, constant_tile_1d)
2786 {
2787     Shape shape_in{2};
2788     Shape shape_repeats{1};
2789     Shape shape_out{4};
2790
2791     vector<int> values_in{0, 1};
2792     auto data = make_shared<op::Constant>(element::i32, shape_in, values_in);
2793     vector<int> values_repeats{2};
2794     auto repeats = make_shared<op::Constant>(element::i64, shape_repeats, values_repeats);
2795     auto tile = make_shared<op::v0::Tile>(data, repeats);
2796     tile->set_friendly_name("test");
2797     auto f = make_shared<Function>(tile, ParameterVector{});
2798
2799     pass::Manager pass_manager;
2800     pass_manager.register_pass<pass::ConstantFolding>();
2801     pass_manager.run_passes(f);
2802
2803     ASSERT_EQ(count_ops_of_type<op::v0::Tile>(f), 0);
2804     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 1);
2805
2806     auto new_const =
2807         as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
2808     ASSERT_TRUE(new_const);
2809     ASSERT_EQ(new_const->get_friendly_name(), "test");
2810     auto values_out = new_const->get_vector<int>();
2811
2812     vector<int> values_expected{0, 1, 0, 1};
2813     ASSERT_EQ(values_expected, values_out);
2814 }
2815
2816 TEST(constant_folding, constant_tile_3d_small_data_rank)
2817 {
2818     Shape shape_in{2};
2819     Shape shape_repeats{3};
2820     Shape shape_out{2, 2, 4};
2821
2822     vector<int> values_in{0, 1};
2823     auto data = make_shared<op::Constant>(element::i32, shape_in, values_in);
2824     vector<int> values_repeats{2, 2, 2};
2825     auto repeats = make_shared<op::Constant>(element::i64, shape_repeats, values_repeats);
2826     auto tile = make_shared<op::v0::Tile>(data, repeats);
2827     tile->set_friendly_name("test");
2828     auto f = make_shared<Function>(tile, ParameterVector{});
2829
2830     pass::Manager pass_manager;
2831     pass_manager.register_pass<pass::ConstantFolding>();
2832     pass_manager.run_passes(f);
2833
2834     ASSERT_EQ(count_ops_of_type<op::v0::Tile>(f), 0);
2835     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 1);
2836
2837     auto new_const =
2838         as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
2839     ASSERT_TRUE(new_const);
2840     ASSERT_EQ(new_const->get_friendly_name(), "test");
2841     auto values_out = new_const->get_vector<int>();
2842
2843     vector<int> values_expected{0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1};
2844     ASSERT_EQ(values_expected, values_out);
2845 }
2846
2847 TEST(constant_folding, constant_tile_3d_few_repeats)
2848 {
2849     Shape shape_in{2, 1, 3};
2850     Shape shape_repeats{2};
2851     Shape shape_out{2, 2, 3};
2852
2853     vector<int> values_in{1, 2, 3, 4, 5, 6};
2854     auto data = make_shared<op::Constant>(element::i32, shape_in, values_in);
2855     vector<int> values_repeats{2, 1};
2856     auto repeats = make_shared<op::Constant>(element::i64, shape_repeats, values_repeats);
2857     auto tile = make_shared<op::v0::Tile>(data, repeats);
2858     tile->set_friendly_name("test");
2859     auto f = make_shared<Function>(tile, ParameterVector{});
2860
2861     pass::Manager pass_manager;
2862     pass_manager.register_pass<pass::ConstantFolding>();
2863     pass_manager.run_passes(f);
2864
2865     ASSERT_EQ(count_ops_of_type<op::v0::Tile>(f), 0);
2866     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 1);
2867
2868     auto new_const =
2869         as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
2870     ASSERT_TRUE(new_const);
2871     ASSERT_EQ(new_const->get_friendly_name(), "test");
2872     auto values_out = new_const->get_vector<int>();
2873
2874     vector<int> values_expected{1, 2, 3, 1, 2, 3, 4, 5, 6, 4, 5, 6};
2875     ASSERT_EQ(values_expected, values_out);
2876 }
2877
2878 TEST(constant_folding, constant_tile_1d_0_repeats)
2879 {
2880     Shape shape_in{2};
2881     Shape shape_repeats{1};
2882     Shape shape_out{};
2883
2884     vector<int> values_in{0, 1};
2885     auto data = make_shared<op::Constant>(element::i32, shape_in, values_in);
2886     vector<int> values_repeats{0};
2887     auto repeats = make_shared<op::Constant>(element::i64, shape_repeats, values_repeats);
2888     auto tile = make_shared<op::v0::Tile>(data, repeats);
2889     tile->set_friendly_name("test");
2890     auto f = make_shared<Function>(tile, ParameterVector{});
2891
2892     pass::Manager pass_manager;
2893     pass_manager.register_pass<pass::ConstantFolding>();
2894     pass_manager.run_passes(f);
2895
2896     ASSERT_EQ(count_ops_of_type<op::v0::Tile>(f), 0);
2897     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 1);
2898
2899     auto new_const =
2900         as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
2901     ASSERT_TRUE(new_const);
2902     ASSERT_EQ(new_const->get_friendly_name(), "test");
2903     auto values_out = new_const->get_vector<int>();
2904
2905     vector<int> values_expected{};
2906     ASSERT_EQ(values_expected, values_out);
2907 }
2908
2909 TEST(constant_folding, constant_tile_0_rank_data)
2910 {
2911     Shape shape_in{};
2912     Shape shape_repeats{1};
2913     Shape shape_out{4};
2914
2915     vector<int> values_in{1};
2916     auto data = make_shared<op::Constant>(element::i32, shape_in, values_in);
2917     vector<int> values_repeats{4};
2918     auto repeats = make_shared<op::Constant>(element::i64, shape_repeats, values_repeats);
2919     auto tile = make_shared<op::v0::Tile>(data, repeats);
2920     tile->set_friendly_name("test");
2921     auto f = make_shared<Function>(tile, ParameterVector{});
2922
2923     pass::Manager pass_manager;
2924     pass_manager.register_pass<pass::ConstantFolding>();
2925     pass_manager.run_passes(f);
2926
2927     ASSERT_EQ(count_ops_of_type<op::v0::Tile>(f), 0);
2928     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 1);
2929
2930     auto new_const =
2931         as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
2932     ASSERT_TRUE(new_const);
2933     ASSERT_EQ(new_const->get_friendly_name(), "test");
2934     auto values_out = new_const->get_vector<int>();
2935
2936     vector<int> values_expected{1, 1, 1, 1};
2937     ASSERT_EQ(values_expected, values_out);
2938 }
2939
2940 TEST(constant_folding, constant_non_zero_0D)
2941 {
2942     auto data = op::Constant::create(element::i32, Shape{}, {1});
2943     auto non_zero = make_shared<op::v3::NonZero>(data);
2944     non_zero->set_friendly_name("test");
2945     auto f = make_shared<Function>(non_zero, ParameterVector{});
2946
2947     pass::Manager pass_manager;
2948     pass_manager.register_pass<pass::ConstantFolding>();
2949     pass_manager.run_passes(f);
2950
2951     // Fold into constant with shape of {1, 1} for scalar input with
2952     // non-zero value
2953     ASSERT_EQ(count_ops_of_type<op::v3::NonZero>(f), 0);
2954     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 1);
2955
2956     const auto new_const =
2957         as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
2958     ASSERT_TRUE(new_const);
2959     ASSERT_EQ(new_const->get_friendly_name(), "test");
2960     const auto values_out = new_const->get_vector<int64_t>();
2961
2962     const vector<int64_t> values_expected{0};
2963     ASSERT_EQ(values_expected, values_out);
2964     ASSERT_EQ((Shape{1, 1}), new_const->get_shape());
2965 }
2966
2967 TEST(constant_folding, constant_non_zero_1D)
2968 {
2969     vector<int> values_in{0, 1, 0, 1};
2970     auto data = make_shared<op::Constant>(element::i32, Shape{4}, values_in);
2971     auto non_zero = make_shared<op::v3::NonZero>(data);
2972     non_zero->set_friendly_name("test");
2973     auto f = make_shared<Function>(non_zero, ParameterVector{});
2974
2975     pass::Manager pass_manager;
2976     pass_manager.register_pass<pass::ConstantFolding>();
2977     pass_manager.run_passes(f);
2978
2979     ASSERT_EQ(count_ops_of_type<op::v3::NonZero>(f), 0);
2980     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 1);
2981
2982     const auto new_const =
2983         as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
2984     ASSERT_TRUE(new_const);
2985     ASSERT_EQ(new_const->get_friendly_name(), "test");
2986     const auto values_out = new_const->get_vector<int64_t>();
2987
2988     const vector<int64_t> values_expected{1, 3};
2989     ASSERT_EQ(values_expected, values_out);
2990     ASSERT_EQ((Shape{1, 2}), new_const->get_shape());
2991 }
2992
2993 TEST(constant_folding, constant_non_zero_int32_output_type)
2994 {
2995     vector<int> values_in{0, 1, 0, 1};
2996     auto data = make_shared<op::Constant>(element::i32, Shape{4}, values_in);
2997     auto non_zero = make_shared<op::v3::NonZero>(data, element::i32);
2998     non_zero->set_friendly_name("test");
2999     auto f = make_shared<Function>(non_zero, ParameterVector{});
3000
3001     pass::Manager pass_manager;
3002     pass_manager.register_pass<pass::ConstantFolding>();
3003     pass_manager.run_passes(f);
3004
3005     ASSERT_EQ(count_ops_of_type<op::v3::NonZero>(f), 0);
3006     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 1);
3007
3008     const auto new_const =
3009         as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
3010     ASSERT_TRUE(new_const);
3011     ASSERT_EQ(new_const->get_friendly_name(), "test");
3012     ASSERT_EQ(element::i32, new_const->get_element_type());
3013     const auto values_out = new_const->get_vector<int32_t>();
3014
3015     const vector<int32_t> values_expected{1, 3};
3016     ASSERT_EQ(values_expected, values_out);
3017     ASSERT_EQ((Shape{1, 2}), new_const->get_shape());
3018 }
3019
3020 TEST(constant_folding, constant_non_zero_1D_all_indices)
3021 {
3022     const vector<float> values_in{1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f};
3023     const auto data = make_shared<op::Constant>(element::f32, Shape{values_in.size()}, values_in);
3024     const auto non_zero = make_shared<op::v3::NonZero>(data);
3025     non_zero->set_friendly_name("test");
3026     auto f = make_shared<Function>(non_zero, ParameterVector{});
3027
3028     pass::Manager pass_manager;
3029     pass_manager.register_pass<pass::ConstantFolding>();
3030     pass_manager.run_passes(f);
3031
3032     ASSERT_EQ(count_ops_of_type<op::v3::NonZero>(f), 0);
3033     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 1);
3034
3035     const auto new_const =
3036         as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
3037     ASSERT_TRUE(new_const);
3038     ASSERT_EQ(new_const->get_friendly_name(), "test");
3039     const auto values_out = new_const->get_vector<int64_t>();
3040
3041     const vector<int64_t> values_expected{0, 1, 2, 3, 4, 5, 6, 7};
3042     ASSERT_EQ(values_expected, values_out);
3043     ASSERT_EQ((Shape{1, values_in.size()}), new_const->get_shape());
3044 }
3045
3046 TEST(constant_folding, constant_non_zero_2D)
3047 {
3048     vector<int> values_in{1, 0, 0, 0, 1, 0, 1, 1, 0};
3049     auto data = make_shared<op::Constant>(element::i32, Shape{3, 3}, values_in);
3050     auto non_zero = make_shared<op::v3::NonZero>(data);
3051     non_zero->set_friendly_name("test");
3052     auto f = make_shared<Function>(non_zero, ParameterVector{});
3053
3054     pass::Manager pass_manager;
3055     pass_manager.register_pass<pass::ConstantFolding>();
3056     pass_manager.run_passes(f);
3057
3058     ASSERT_EQ(count_ops_of_type<op::v3::NonZero>(f), 0);
3059     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 1);
3060
3061     const auto new_const =
3062         as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
3063     ASSERT_TRUE(new_const);
3064     ASSERT_EQ(new_const->get_friendly_name(), "test");
3065     const auto values_out = new_const->get_vector<int64_t>();
3066
3067     const vector<int64_t> values_expected{0, 1, 2, 2, 0, 1, 0, 1};
3068     ASSERT_EQ(values_expected, values_out);
3069     ASSERT_EQ((Shape{2, 4}), new_const->get_shape());
3070 }
3071
3072 TEST(constant_folding, DISABLED_constant_non_zero_2D_all_indices)
3073 {
3074     const vector<int8_t> values_in{1, 1, 1, 1, 1, 1, 1, 1, 1};
3075     const auto data = make_shared<op::Constant>(element::i8, Shape{3, 3}, values_in);
3076     const auto non_zero = make_shared<op::v3::NonZero>(data);
3077     non_zero->set_friendly_name("test");
3078     auto f = make_shared<Function>(non_zero, ParameterVector{});
3079
3080     pass::Manager pass_manager;
3081     pass_manager.register_pass<pass::ConstantFolding>();
3082     pass_manager.run_passes(f);
3083
3084     ASSERT_EQ(count_ops_of_type<op::v3::NonZero>(f), 0);
3085     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 1);
3086
3087     const auto new_const =
3088         as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
3089     ASSERT_TRUE(new_const);
3090     ASSERT_EQ(new_const->get_friendly_name(), "test");
3091     const auto values_out = new_const->get_vector<int64_t>();
3092
3093     const vector<int64_t> values_expected{0, 0, 0, 1, 1, 1, 2, 2, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2};
3094     ASSERT_EQ(values_expected, values_out);
3095     ASSERT_EQ((Shape{2, values_in.size()}), new_const->get_shape());
3096 }
3097
3098 TEST(constant_folding, DISABLED_constant_non_zero_2D_all_zeros)
3099 {
3100     const vector<uint8_t> values_in{0, 0, 0, 0, 0, 0};
3101     const auto data = make_shared<op::Constant>(element::u8, Shape{2, 3}, values_in);
3102     const auto non_zero = make_shared<op::v3::NonZero>(data);
3103     non_zero->set_friendly_name("test");
3104     auto f = make_shared<Function>(non_zero, ParameterVector{});
3105
3106     pass::Manager pass_manager;
3107     pass_manager.register_pass<pass::ConstantFolding>();
3108     pass_manager.run_passes(f);
3109
3110     // fold into Constant with shape of {0}
3111     ASSERT_EQ(count_ops_of_type<op::v3::NonZero>(f), 0);
3112     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 1);
3113
3114     const auto new_const =
3115         as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
3116     ASSERT_TRUE(new_const);
3117     ASSERT_EQ(new_const->get_friendly_name(), "test");
3118     ASSERT_EQ(shape_size(new_const->get_shape()), 0);
3119 }
3120
3121 TEST(constant_folding, constant_non_zero_3D)
3122 {
3123     vector<int> values_in{1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0};
3124     auto data = make_shared<op::Constant>(element::i32, Shape{2, 3, 3}, values_in);
3125     auto non_zero = make_shared<op::v3::NonZero>(data);
3126     non_zero->set_friendly_name("test");
3127     auto f = make_shared<Function>(non_zero, ParameterVector{});
3128
3129     pass::Manager pass_manager;
3130     pass_manager.register_pass<pass::ConstantFolding>();
3131     pass_manager.run_passes(f);
3132
3133     ASSERT_EQ(count_ops_of_type<op::v3::NonZero>(f), 0);
3134     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 1);
3135
3136     const auto new_const =
3137         as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
3138     ASSERT_TRUE(new_const);
3139     ASSERT_EQ(new_const->get_friendly_name(), "test");
3140     const auto values_out = new_const->get_vector<int64_t>();
3141
3142     const vector<int64_t> values_expected{0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 2, 2, 2,
3143                                           0, 0, 0, 1, 1, 2, 0, 2, 1, 0, 1, 2, 0, 1, 2, 0, 2, 1};
3144     ASSERT_EQ(values_expected, values_out);
3145     ASSERT_EQ((Shape{3, 12}), new_const->get_shape());
3146 }
3147
3148 TEST(constant_folding, constant_scatter_elements_update_basic)
3149 {
3150     const Shape data_shape{3, 3};
3151     const Shape indices_shape{2, 3};
3152
3153     const auto data_const = op::Constant::create(
3154         element::f32, data_shape, std::vector<float>(shape_size(data_shape), 0.f));
3155     const auto indices_const =
3156         op::Constant::create(element::i32, indices_shape, {1, 0, 2, 0, 2, 1});
3157     const auto updates_const =
3158         op::Constant::create(element::f32, indices_shape, {1.0f, 1.1f, 1.2f, 2.0f, 2.1f, 2.2f});
3159     const auto axis_const = op::Constant::create(element::i64, Shape{}, {0});
3160
3161     auto scatter_elem_updt = make_shared<op::v3::ScatterElementsUpdate>(
3162         data_const, indices_const, updates_const, axis_const);
3163     scatter_elem_updt->set_friendly_name("test");
3164     auto f = make_shared<Function>(scatter_elem_updt, ParameterVector{});
3165
3166     pass::Manager pass_manager;
3167     pass_manager.register_pass<pass::ConstantFolding>();
3168     pass_manager.run_passes(f);
3169
3170     ASSERT_EQ(count_ops_of_type<op::v3::ScatterElementsUpdate>(f), 0);
3171     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 1);
3172
3173     auto result_node =
3174         as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
3175     ASSERT_TRUE(result_node);
3176     ASSERT_EQ(result_node->get_friendly_name(), "test");
3177     ASSERT_EQ(data_shape, result_node->get_output_shape(0));
3178     std::vector<float> expected{2.f, 1.1f, 0.0f, 1.f, 0.0f, 2.2f, 0.f, 2.1f, 1.2f};
3179     range_test_check(result_node->cast_vector<float>(), expected);
3180 }
3181
3182 TEST(constant_folding, constant_scatter_elements_update_negative_axis)
3183 {
3184     const Shape data_shape{3, 3};
3185     const Shape indices_shape{2, 3};
3186
3187     const auto data_const = op::Constant::create(
3188         element::f32, data_shape, std::vector<float>(shape_size(data_shape), 0.f));
3189     const auto indices_const =
3190         op::Constant::create(element::i32, indices_shape, {1, 0, 2, 0, 2, 1});
3191     const auto updates_const =
3192         op::Constant::create(element::f32, indices_shape, {1.0f, 1.1f, 1.2f, 2.0f, 2.1f, 2.2f});
3193     const auto axis_const = op::Constant::create(element::i64, Shape{}, {-1});
3194
3195     auto scatter_elem_updt = make_shared<op::v3::ScatterElementsUpdate>(
3196         data_const, indices_const, updates_const, axis_const);
3197     auto f = make_shared<Function>(scatter_elem_updt, ParameterVector{});
3198
3199     pass::Manager pass_manager;
3200     pass_manager.register_pass<pass::ConstantFolding>();
3201     pass_manager.run_passes(f);
3202
3203     ASSERT_EQ(count_ops_of_type<op::v3::ScatterElementsUpdate>(f), 0);
3204     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 1);
3205
3206     auto result_node =
3207         as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
3208     ASSERT_TRUE(result_node);
3209     ASSERT_EQ(data_shape, result_node->get_output_shape(0));
3210     std::vector<float> expected{1.1f, 1.0f, 1.2f, 2.0f, 2.2f, 2.1f, 0.0f, 0.0f, 0.0f};
3211     range_test_check(result_node->cast_vector<float>(), expected);
3212 }
3213
3214 TEST(constant_folding, constant_scatter_elements_update_1d_axis)
3215 {
3216     const Shape data_shape{3, 3};
3217     const Shape indices_shape{2, 3};
3218
3219     const auto data_const = op::Constant::create(
3220         element::f32, data_shape, std::vector<float>(shape_size(data_shape), 0.f));
3221     const auto indices_const =
3222         op::Constant::create(element::i32, indices_shape, {1, 0, 2, 0, 2, 1});
3223     const auto updates_const =
3224         op::Constant::create(element::f32, indices_shape, {1.0f, 1.1f, 1.2f, 2.0f, 2.1f, 2.2f});
3225     const auto axis_const = op::Constant::create(element::i64, Shape{1}, {0});
3226
3227     auto scatter_elem_updt = make_shared<op::v3::ScatterElementsUpdate>(
3228         data_const, indices_const, updates_const, axis_const);
3229     auto f = make_shared<Function>(scatter_elem_updt, ParameterVector{});
3230
3231     pass::Manager pass_manager;
3232     pass_manager.register_pass<pass::ConstantFolding>();
3233     pass_manager.run_passes(f);
3234
3235     ASSERT_EQ(count_ops_of_type<op::v3::ScatterElementsUpdate>(f), 0);
3236     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 1);
3237
3238     auto result_node =
3239         as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
3240     ASSERT_TRUE(result_node);
3241     ASSERT_EQ(data_shape, result_node->get_output_shape(0));
3242     std::vector<float> expected{2.f, 1.1f, 0.0f, 1.f, 0.0f, 2.2f, 0.f, 2.1f, 1.2f};
3243     range_test_check(result_node->cast_vector<float>(), expected);
3244 }
3245
3246 TEST(constant_folding, constant_scatter_elements_update_3d_i16)
3247 {
3248     const Shape data_shape{3, 3, 3};
3249     const Shape indices_shape{2, 2, 3};
3250
3251     const auto data_const = op::Constant::create(
3252         element::i16, data_shape, std::vector<int16_t>(shape_size(data_shape), 0));
3253     const auto indices_const =
3254         op::Constant::create(element::i16, indices_shape, {1, 0, 2, 0, 2, 1, 2, 2, 2, 0, 1, 0});
3255     const auto updates_const =
3256         op::Constant::create(element::i16, indices_shape, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12});
3257     const auto axis_const = op::Constant::create(element::i64, Shape{}, {1});
3258
3259     auto scatter_elem_updt = make_shared<op::v3::ScatterElementsUpdate>(
3260         data_const, indices_const, updates_const, axis_const);
3261     auto f = make_shared<Function>(scatter_elem_updt, ParameterVector{});
3262
3263     pass::Manager pass_manager;
3264     pass_manager.register_pass<pass::ConstantFolding>();
3265     pass_manager.run_passes(f);
3266
3267     ASSERT_EQ(count_ops_of_type<op::v3::ScatterElementsUpdate>(f), 0);
3268     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 1);
3269
3270     auto result_node =
3271         as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
3272     ASSERT_TRUE(result_node);
3273     ASSERT_EQ(data_shape, result_node->get_output_shape(0));
3274     std::vector<int16_t> expected{4, 2, 0, 1, 0, 6, 0, 5, 3, 10, 0, 12, 0, 11,
3275                                   0, 7, 8, 9, 0, 0, 0, 0, 0, 0,  0, 0,  0};
3276     range_test_check(result_node->cast_vector<int16_t>(), expected);
3277 }
3278
3279 TEST(constant_folding, constant_scatter_elements_update_one_elem)
3280 {
3281     const Shape data_shape{3, 3, 3};
3282     const Shape indices_shape{1, 1, 1};
3283     const auto input_data = std::vector<int32_t>(shape_size(data_shape), 0);
3284
3285     const auto data_const = op::Constant::create(element::i32, data_shape, input_data);
3286     const auto indices_const = op::Constant::create(element::i32, indices_shape, {1});
3287     const auto updates_const = op::Constant::create(element::i32, indices_shape, {2});
3288     const auto axis_const = op::Constant::create(element::i64, Shape{}, {0});
3289
3290     auto scatter_elem_updt = make_shared<op::v3::ScatterElementsUpdate>(
3291         data_const, indices_const, updates_const, axis_const);
3292     auto f = make_shared<Function>(scatter_elem_updt, ParameterVector{});
3293
3294     pass::Manager pass_manager;
3295     pass_manager.register_pass<pass::ConstantFolding>();
3296     pass_manager.run_passes(f);
3297
3298     ASSERT_EQ(count_ops_of_type<op::v3::ScatterElementsUpdate>(f), 0);
3299     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 1);
3300
3301     auto result_node =
3302         as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
3303     ASSERT_TRUE(result_node);
3304     ASSERT_EQ(data_shape, result_node->get_output_shape(0));
3305     std::vector<int32_t> expected{input_data};
3306     // we have updated coordinate (1, 0, 0)
3307     expected.at(9) = 2;
3308     range_test_check(result_node->cast_vector<int32_t>(), expected);
3309 }
3310
3311 void test_constant_folding_reshape_v1(Shape& shape_in,
3312                                       vector<float>& values_in,
3313                                       Shape shape_shape,
3314                                       vector<int32_t> values_shape,
3315                                       bool zero_flag = false)
3316 {
3317     auto constant_in = make_shared<op::Constant>(element::f32, shape_in, values_in);
3318     auto constant_shape = make_shared<op::Constant>(element::i64, shape_shape, values_shape);
3319     auto dyn_reshape = make_shared<op::v1::Reshape>(constant_in, constant_shape, zero_flag);
3320     dyn_reshape->set_friendly_name("test");
3321     auto f = make_shared<Function>(dyn_reshape, ParameterVector{});
3322
3323     pass::Manager pass_manager;
3324     pass_manager.register_pass<pass::ConstantFolding>();
3325     pass_manager.run_passes(f);
3326
3327     ASSERT_EQ(count_ops_of_type<op::v1::Reshape>(f), 0);
3328     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 1);
3329
3330     auto new_const =
3331         as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
3332     ASSERT_TRUE(new_const);
3333     ASSERT_EQ(new_const->get_friendly_name(), "test");
3334     auto values_out = new_const->get_vector<float>();
3335
3336     ASSERT_TRUE(test::all_close_f(values_in, values_out, MIN_FLOAT_TOLERANCE_BITS));
3337 }
3338 TEST(constant_folding, constant_dyn_reshape_v1_2d)
3339 {
3340     Shape shape_in{2, 5};
3341     vector<float> values_in{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
3342
3343     test_constant_folding_reshape_v1(shape_in, values_in, {4}, {1, 1, 1, 10});
3344     test_constant_folding_reshape_v1(shape_in, values_in, {4}, {1, 1, 2, 5});
3345     test_constant_folding_reshape_v1(shape_in, values_in, {3}, {1, 2, 5});
3346     test_constant_folding_reshape_v1(shape_in, values_in, {3}, {5, 2, 1});
3347 }
3348
3349 TEST(constant_folding, constant_dyn_reshape_v1_pattern_with_negative_indices)
3350 {
3351     Shape shape_in{2, 2, 2, 2};
3352     vector<float> values_in{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
3353
3354     test_constant_folding_reshape_v1(shape_in, values_in, {3}, {4, -1, 2});
3355     test_constant_folding_reshape_v1(shape_in, values_in, {2}, {4, -1});
3356     test_constant_folding_reshape_v1(shape_in, values_in, {1}, {-1});
3357 }
3358
3359 TEST(constant_folding, constant_dyn_reshape_v1_pattern_with_zero_dims)
3360 {
3361     Shape shape_in{2, 2, 2, 2};
3362     vector<float> values_in{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
3363
3364     test_constant_folding_reshape_v1(shape_in, values_in, {4}, {2, -1, 2, 0}, true);
3365     test_constant_folding_reshape_v1(shape_in, values_in, {4}, {4, 1, 0, 2}, true);
3366 }
3367
3368 TEST(constant_folding, disable_constant_folding)
3369 {
3370     auto input = make_shared<op::Parameter>(element::f32, Shape{1, 3});
3371     auto constant_shape = op::Constant::create(element::i64, Shape{1}, {3});
3372     auto dyn_reshape = make_shared<op::v1::Reshape>(input, constant_shape, true);
3373     auto& rt_info = dyn_reshape->get_rt_info();
3374     rt_info["DISABLED_CONSTANT_FOLDING"];
3375     auto f = make_shared<Function>(dyn_reshape, ParameterVector{input});
3376
3377     pass::Manager pass_manager;
3378     pass_manager.register_pass<pass::ConstantFolding>();
3379     pass_manager.run_passes(f);
3380
3381     ASSERT_EQ(count_ops_of_type<op::v1::Reshape>(f), 1);
3382     ASSERT_EQ(count_ops_of_type<op::Constant>(f), 1);
3383 }