1 //*****************************************************************************
2 // Copyright 2017-2020 Intel Corporation
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
8 // http://www.apache.org/licenses/LICENSE-2.0
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 //*****************************************************************************
20 #include "gtest/gtest.h"
22 #include "ngraph/ngraph.hpp"
23 #include "ngraph/opsets/opset5.hpp"
24 #include "util/ndarray.hpp"
25 #include "util/test_tools.hpp"
27 NGRAPH_SUPPRESS_DEPRECATED_START
30 using namespace ngraph;
32 template <typename OP>
36 auto arg0 = make_shared<op::Parameter>(element::f32, shape);
37 OutputVector new_args{make_shared<op::Parameter>(element::f32, shape)};
39 auto node = make_shared<OP>(arg0);
40 auto new_node = node->copy_with_new_inputs(new_args);
42 return (nullptr != new_node) && (new_args == new_node->input_values());
45 template <typename OP>
49 auto arg0 = make_shared<op::Parameter>(element::f32, shape);
50 auto arg1 = make_shared<op::Parameter>(element::f32, shape);
51 OutputVector new_args{make_shared<op::Parameter>(element::f32, shape),
52 make_shared<op::Parameter>(element::f32, shape)};
54 auto node = make_shared<OP>(arg0, arg1);
55 auto new_node = node->copy_with_new_inputs(new_args);
57 return (nullptr != new_node) && (new_args == new_node->input_values());
62 ASSERT_TRUE(check_unary<op::Abs>());
67 ASSERT_TRUE(check_unary<op::Acos>());
72 ASSERT_TRUE(check_binary<op::Add>());
77 ASSERT_TRUE(check_unary<op::Asin>());
82 ASSERT_TRUE(check_unary<op::Atan>());
88 Shape new_shape{4, 1, 3};
90 auto arg0 = make_shared<op::Parameter>(element::f32, shape);
91 OutputVector new_args{make_shared<op::Parameter>(element::f32, shape),
92 op::Constant::create(element::u64, Shape{new_shape.size()}, new_shape),
93 op::Constant::create(element::i64, Shape{axes.size()}, axes.to_vector())};
95 auto node = make_shared<op::v1::Broadcast>(
97 op::Constant::create(element::u64, Shape{new_shape.size()}, new_shape),
98 op::Constant::create(element::i64, Shape{axes.size()}, axes.to_vector()));
99 auto new_node = node->copy_with_new_inputs(new_args);
100 auto node_cast = as_type_ptr<op::v1::Broadcast>(new_node);
101 ASSERT_NE(node_cast, nullptr);
103 ASSERT_NE(nullptr, new_node);
104 ASSERT_EQ(new_args, new_node->input_values());
105 bool axes_determined;
106 AxisSet broadcast_axes;
107 std::tie(axes_determined, broadcast_axes) = node_cast->get_broadcast_axes();
108 ASSERT_EQ(true, axes_determined);
109 ASSERT_EQ(AxisSet{0}, broadcast_axes);
114 ASSERT_TRUE(check_unary<op::Ceiling>());
120 auto arg0 = make_shared<op::Parameter>(element::f32, shape);
121 auto arg1 = make_shared<op::Parameter>(element::f32, shape);
122 OutputVector new_args{make_shared<op::Parameter>(element::f32, shape),
123 make_shared<op::Parameter>(element::f32, shape)};
125 auto node = make_shared<op::Concat>(NodeVector{arg0, arg1}, axis);
126 auto new_node = node->clone_with_new_inputs(new_args);
127 auto node_cast = as_type_ptr<op::Concat>(new_node);
128 ASSERT_NE(node_cast, nullptr);
130 ASSERT_TRUE(nullptr != new_node);
131 ASSERT_TRUE(new_args == new_node->input_values());
132 ASSERT_TRUE(node_cast->get_concatenation_axis() == axis);
138 vector<float> c{2.4f};
139 auto& et = element::f32;
140 auto node = op::Constant::create(et, shape, c);
141 auto new_node = node->clone_with_new_inputs(OutputVector{});
142 auto node_cast = as_type_ptr<op::Constant>(new_node);
143 ASSERT_NE(node_cast, nullptr);
144 ASSERT_TRUE(nullptr != new_node);
145 ASSERT_TRUE(OutputVector{} == new_node->input_values());
146 ASSERT_TRUE(node_cast->get_vector<float>() == c);
147 ASSERT_TRUE(node_cast->get_shape() == shape);
148 ASSERT_TRUE(node_cast->get_element_type() == et);
154 auto& et = element::f64;
155 auto arg0 = make_shared<op::Parameter>(element::f32, shape);
156 OutputVector new_args{make_shared<op::Parameter>(element::f32, shape)};
158 auto node = make_shared<op::Convert>(arg0, et);
159 auto new_node = node->clone_with_new_inputs(new_args);
160 auto node_cast = as_type_ptr<op::Convert>(new_node);
161 ASSERT_NE(node_cast, nullptr);
163 ASSERT_TRUE(nullptr != new_node);
164 ASSERT_TRUE(new_args == new_node->input_values());
165 ASSERT_TRUE(et == node_cast->get_convert_element_type());
170 ASSERT_TRUE(check_unary<op::Cos>());
175 ASSERT_TRUE(check_unary<op::Cosh>());
180 ASSERT_TRUE(check_binary<op::Divide>());
185 ASSERT_TRUE(check_binary<op::Dot>());
190 ASSERT_TRUE(check_binary<op::Equal>());
195 ASSERT_TRUE(check_unary<op::Exp>());
200 ASSERT_TRUE(check_unary<op::Floor>());
203 TEST(copy, greater_eq)
205 ASSERT_TRUE(check_binary<op::GreaterEq>());
210 ASSERT_TRUE(check_binary<op::Greater>());
215 ASSERT_TRUE(check_binary<op::LessEq>());
220 ASSERT_TRUE(check_binary<op::Less>());
225 ASSERT_TRUE(check_unary<op::Log>());
230 ASSERT_TRUE(check_binary<op::Maximum>());
235 ASSERT_TRUE(check_binary<op::Minimum>());
240 ASSERT_TRUE(check_binary<op::Multiply>());
245 ASSERT_TRUE(check_unary<op::Negative>());
248 TEST(copy, not_equal)
250 ASSERT_TRUE(check_binary<op::NotEqual>());
253 TEST(copy, parameter)
256 auto node = make_shared<op::Parameter>(element::f32, shape);
257 auto new_node = node->clone_with_new_inputs({});
258 auto node_cast = as_type_ptr<op::Parameter>(new_node);
259 ASSERT_NE(node_cast, nullptr);
261 ASSERT_TRUE(nullptr != new_node);
262 ASSERT_TRUE(new_node->input_values().size() == 0);
263 ASSERT_TRUE(node->has_same_type(new_node));
268 ASSERT_TRUE(check_binary<op::Power>());
273 Shape shape_in{2, 3, 4};
274 AxisVector axes{0, 1, 2};
275 Shape shape_out{6, 4};
277 auto arg0 = make_shared<op::Parameter>(element::f32, shape_in);
278 OutputVector new_args{make_shared<op::Parameter>(element::f32, shape_in)};
280 auto node = make_shared<op::Reshape>(arg0, axes, shape_out);
281 auto new_node = node->clone_with_new_inputs(new_args);
282 auto node_cast = as_type_ptr<op::Reshape>(new_node);
283 ASSERT_NE(node_cast, nullptr);
285 ASSERT_TRUE(nullptr != new_node);
286 ASSERT_TRUE(new_args == new_node->input_values());
287 ASSERT_TRUE(axes == node_cast->get_input_order());
288 ASSERT_TRUE(shape_out == node_cast->get_output_shape(0));
294 auto arg0 = make_shared<op::Parameter>(element::boolean, shape);
295 auto arg1 = make_shared<op::Parameter>(element::f32, shape);
296 auto arg2 = make_shared<op::Parameter>(element::f32, shape);
297 OutputVector new_args{make_shared<op::Parameter>(element::boolean, shape),
298 make_shared<op::Parameter>(element::f32, shape),
299 make_shared<op::Parameter>(element::f32, shape)};
301 auto node = make_shared<op::Select>(arg0, arg1, arg2);
302 auto new_node = node->clone_with_new_inputs(new_args);
303 auto node_cast = as_type_ptr<op::Select>(new_node);
304 ASSERT_NE(node_cast, nullptr);
306 ASSERT_TRUE(nullptr != new_node);
307 ASSERT_TRUE(new_args == new_node->input_values());
312 ASSERT_TRUE(check_unary<op::Sign>());
317 ASSERT_TRUE(check_unary<op::Sin>());
322 ASSERT_TRUE(check_unary<op::Sinh>());
327 Shape shape_in{2, 3, 4};
328 Coordinate lower{0, 0, 0};
329 Coordinate upper{2, 3, 4};
330 Strides strides{1, 1, 1};
332 auto arg0 = make_shared<op::Parameter>(element::f32, shape_in);
333 OutputVector new_args{make_shared<op::Parameter>(element::f32, shape_in)};
335 auto node = make_shared<op::Slice>(arg0, lower, upper, strides);
336 auto new_node = node->clone_with_new_inputs(new_args);
337 auto node_cast = as_type_ptr<op::Slice>(new_node);
338 ASSERT_NE(node_cast, nullptr);
340 ASSERT_TRUE(nullptr != new_node);
341 ASSERT_TRUE(new_args == new_node->input_values());
342 ASSERT_TRUE(lower == node_cast->get_lower_bounds());
343 ASSERT_TRUE(upper == node_cast->get_upper_bounds());
344 ASSERT_TRUE(strides == node_cast->get_strides());
349 ASSERT_TRUE(check_binary<op::Subtract>());
356 auto arg0 = make_shared<op::Parameter>(element::f32, shape);
358 auto node = make_shared<op::Sum>(arg0, axes);
359 OutputVector new_args{make_shared<op::Parameter>(element::f32, shape),
360 node->input_value(1).get_node_shared_ptr()};
361 auto new_node = node->clone_with_new_inputs(new_args);
362 auto node_cast = as_type_ptr<op::Sum>(new_node);
363 ASSERT_NE(node_cast, nullptr);
365 ASSERT_TRUE(nullptr != new_node);
366 ASSERT_TRUE(new_args == new_node->input_values());
367 ASSERT_TRUE(axes == node_cast->get_reduction_axes());
372 ASSERT_TRUE(check_unary<op::Tan>());
377 ASSERT_TRUE(check_unary<op::Tanh>());
382 // That which we iterate over
383 auto X = make_shared<opset5::Parameter>(element::f32, Shape{32, 1, 10});
384 auto Y = make_shared<opset5::Parameter>(element::f32, Shape{32, 1, 10});
385 auto M = make_shared<opset5::Parameter>(element::f32, Shape{32, 1, 10});
387 // Set up the cell body, a function from (Xi, Yi) -> (Zo)
389 auto current_iteration = make_shared<opset5::Parameter>(element::i64, Shape{});
390 auto Xi = make_shared<opset5::Parameter>(element::f32, PartialShape::dynamic());
391 auto Yi = make_shared<opset5::Parameter>(element::f32, PartialShape::dynamic());
392 auto M_body = make_shared<opset5::Parameter>(element::f32, PartialShape::dynamic());
393 auto body_condition =
394 std::make_shared<ngraph::opset5::Constant>(ngraph::element::boolean, ngraph::Shape{}, true);
397 std::make_shared<ngraph::opset5::Constant>(ngraph::element::i64, ngraph::Shape{}, 10);
398 auto exec_condition =
399 std::make_shared<ngraph::opset5::Constant>(ngraph::element::boolean, ngraph::Shape{}, true);
401 auto sum = make_shared<ngraph::opset5::Add>(Xi, Yi);
402 auto Zo = make_shared<ngraph::opset5::Multiply>(sum, M_body);
403 auto body = make_shared<ngraph::Function>(OutputVector{Zo, body_condition},
404 ParameterVector{Xi, current_iteration, Yi, M_body});
406 auto loop = make_shared<opset5::Loop>(trip_count, exec_condition);
407 loop->set_function(body);
408 loop->set_special_body_ports(ngraph::opset5::Loop::SpecialBodyPorts{1, 1});
410 loop->set_invariant_input(Xi, X);
411 loop->set_invariant_input(Yi, Y);
412 loop->set_merged_input(M_body, M, Zo);
414 // Output 0 is last Zo
415 auto out0 = loop->get_iter_value(body_condition, -1);
416 auto out1 = loop->get_iter_value(Zo, -1);
417 // Output 1 is concat of Zos
418 // start=0, stride=1, part_size=1, end=-1, axis=1
419 auto out2 = loop->get_concatenated_slices(Zo, 0, 1, 1, -1, 1);
420 loop->validate_and_infer_types();
421 // That which we iterate over
422 auto X_new = make_shared<opset5::Parameter>(element::f32, Shape{3, 2, 5});
423 auto Y_new = make_shared<opset5::Parameter>(element::f32, Shape{3, 2, 5});
424 auto M_new = make_shared<opset5::Parameter>(element::f32, Shape{3, 2, 5});
425 OutputVector new_args = {trip_count, exec_condition, X_new, Y_new, M_new};
426 auto loop_copy = loop->clone_with_new_inputs(new_args);
428 auto node_cast = std::dynamic_pointer_cast<opset5::Loop>(loop_copy);
429 ASSERT_NE(node_cast, nullptr);
430 ASSERT_TRUE(nullptr != loop_copy);
431 EXPECT_EQ(loop->get_num_iterations(), node_cast->get_num_iterations());
432 EXPECT_EQ(loop->get_special_body_ports().body_condition_output_idx,
433 node_cast->get_special_body_ports().body_condition_output_idx);
434 EXPECT_EQ(loop->get_special_body_ports().current_iteration_input_idx,
435 node_cast->get_special_body_ports().current_iteration_input_idx);
436 ASSERT_TRUE(new_args == loop_copy->input_values());
438 loop_copy->validate_and_infer_types();
440 Shape out1_shape{3, 2, 5};
441 Shape out2_shape{3, 20, 5};
442 EXPECT_EQ(loop_copy->get_output_shape(0), out0_shape);
443 EXPECT_EQ(loop_copy->get_output_shape(1), out1_shape);
444 EXPECT_EQ(loop_copy->get_output_shape(2), out2_shape);