text: //*****************************************************************************
  // Copyright 2017-2019 Intel Corporation
  //
  // Licensed under the Apache License, Version 2.0 (the "License");
  // you may not use this file except in compliance with the License.
  // You may obtain a copy of the License at
  //
  //     http://www.apache.org/licenses/LICENSE-2.0
  //
  // Unless required by applicable law or agreed to in writing, software
  // distributed under the License is distributed on an "AS IS" BASIS,
  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  // See the License for the specific language governing permissions and
  // limitations under the License.
  //*****************************************************************************
  
  #include "gtest/gtest.h"
  
  #include "ngraph/file_util.hpp"
  #include "ngraph/ngraph.hpp"
  #include "ngraph/serializer.hpp"
  #include "util/test_tools.hpp"
  
  #include <memory>
  using namespace std;
  using namespace ngraph;
  
  TEST(build_graph, build_simple)
  {
      // Function with 4 parameters
      auto arg0 = make_shared<op::Parameter>(element::f32, Shape{7, 3});
      auto arg1 = make_shared<op::Parameter>(element::f32, Shape{3});
      auto arg2 = make_shared<op::Parameter>(element::f32, Shape{32, 7});
      auto arg3 = make_shared<op::Parameter>(element::f32, Shape{32, 7});
      auto broadcast_1 = make_shared<op::Broadcast>(arg3, Shape{10, 32, 7}, AxisSet{0});
      auto b1 = make_shared<op::Broadcast>(arg3, Shape{10, 32, 7}, AxisSet{0});
      auto dot = make_shared<op::Dot>(arg2, arg0);
      ASSERT_EQ(dot->get_arguments()[0], arg2);
      ASSERT_EQ(dot->get_arguments()[1], arg0);
  
      auto cluster_0 = make_shared<Function>(dot, ParameterVector{arg0, arg1, arg2, arg3});
  
      ASSERT_EQ(cluster_0->get_output_op(0)->get_argument(0), dot);
  }
  
  // Check node comparisons
  TEST(build_graph, node_comparison)
  {
      auto arg0 = make_shared<op::Parameter>(element::f32, Shape{32, 3});
      auto arg1 = make_shared<op::Parameter>(element::f32, Shape{3});
      auto arg2 = make_shared<op::Parameter>(element::f32, Shape{32});
  
      auto dot = make_shared<op::Dot>(arg0, arg1);
      auto add = make_shared<op::Add>(dot, arg2);
  
      auto parg = make_shared<op::Parameter>(element::f32, Shape{});
      auto pattern_dot = make_shared<op::Dot>(parg, parg);
  }
  
  TEST(build_graph, literal)
  {
      // float scalar from a float
      // auto float0 = FloatConstant::make(3.0);
      vector<float> float_t{3.0};
      auto float0 = make_shared<op::Constant>(element::f32, Shape{}, float_t);
      ASSERT_EQ(float0->get_vector<float>(), std::vector<float>{3.0});
      ASSERT_EQ(float0->get_element_type(), element::f32);
      ASSERT_EQ(float0->get_shape(), Shape{});
      auto d = make_shared<op::Dot>(float0, float0);
      ASSERT_EQ(d->get_arguments().at(0), float0);
      ASSERT_EQ(d->get_arguments().at(1), float0);
  
      vector<int32_t> int32{3};
      auto int32_0 = make_shared<op::Constant>(element::i32, Shape{}, int32);
      ASSERT_EQ(int32_0->get_vector<int32_t>(), std::vector<int>{3});
      ASSERT_EQ(int32_0->get_element_type(), element::i32);
      ASSERT_EQ(int32_0->get_shape(), Shape{});
  }
  
  TEST(build_graph, tensor)
  {
      // float scalar from a float
      // auto float0 = FloatConstant::make(3.0);
      Shape shape{2, 3};
      vector<float> float_t(shape_size(shape), 0);
      auto float0 = make_shared<op::Constant>(element::f32, shape, float_t);
      ASSERT_EQ(float0->get_element_type(), element::f32);
      ASSERT_EQ(float0->get_shape(), shape);
      auto d = make_shared<op::Add>(float0, float0);
      ASSERT_EQ(d->get_arguments().at(0), float0);
      ASSERT_EQ(d->get_arguments().at(1), float0);
  
      Shape ishape{3, 5};
      vector<int32_t> idata(shape_size(ishape), 0);
      auto int32_0 = make_shared<op::Constant>(element::i32, ishape, idata);
      ASSERT_EQ(int32_0->get_element_type(), element::i32);
      ASSERT_EQ(int32_0->get_shape(), ishape);
  }
  
  // Check functions with undeclared parameters
  TEST(build_graph, function_undeclared_parameters)
  {
      // Function with 4 parameters
      auto arg0 = make_shared<op::Parameter>(element::f32, Shape{7, 3});
      auto arg1 = make_shared<op::Parameter>(element::f32, Shape{3});
      auto arg2 = make_shared<op::Parameter>(element::f32, Shape{32, 7});
      auto arg3 = make_shared<op::Parameter>(element::f32, Shape{32, 7});
      auto broadcast_1 = make_shared<op::Broadcast>(arg3, Shape{10, 32, 7}, AxisSet{0});
      auto b1 = make_shared<op::Broadcast>(arg3, Shape{10, 32, 7}, AxisSet{0});
      auto dot = make_shared<op::Dot>(arg2, arg0);
      ASSERT_EQ(dot->get_arguments()[0], arg2);
      ASSERT_EQ(dot->get_arguments()[1], arg0);
      try
      {
          auto f = make_shared<Function>(dot, ParameterVector{arg0, arg1, arg3});
          f->get_ops();
          // Should have thrown, so fail if it didn't
          FAIL() << "Undeclared parameter not detected.";
      }
      catch (const ngraph_error& error)
      {
          EXPECT_EQ(error.what(), std::string("Function references undeclared parameter"));
      }
      catch (...)
      {
          FAIL() << "Function construction failed for unexpected reason";
      }
  }
  
  // Check no-arg construction
  TEST(build_graph, no_arg_construction)
  {
      // The ops
      // Parameters aren't converted yet
      auto arg0 = make_shared<op::Parameter>(element::f32, Shape{7});
      auto arg1 = make_shared<op::Parameter>(element::f32, Shape{7});
      auto arg2 = make_shared<op::Parameter>(element::f32, Shape{7});
      auto arg3 = make_shared<op::Parameter>(element::f32, Shape{7});
      auto add0 = make_shared<op::Add>();
      auto abs0 = make_shared<op::Abs>();
      auto acos0 = make_shared<op::Acos>();
      auto add1 = make_shared<op::Add>();
      add0->set_argument(1, arg0);
      add0->set_argument(0, arg1);
      abs0->set_argument(0, add0);
      acos0->set_argument(0, add0);
      add1->set_argument(0, acos0);
      add1->set_argument(1, abs0);
      NodeVector ops{arg0, arg1, add0, abs0, acos0, add1};
      validate_nodes_and_infer_types(ops);
      ASSERT_EQ(add1->get_output_shape(0), Shape{7});
  }
  
  TEST(build_graph, multi_output_split)
  {
      const auto data = make_shared<op::Parameter>(element::f32, Shape{64, 8, 100, 150});
      auto filters = make_shared<op::Parameter>(element::f32, Shape{128, 2, 10, 20});
      const auto axis = op::Constant::create(element::i64, Shape{}, {1});
      const auto split = make_shared<op::Split>(data, axis, 2);
      auto conv = make_shared<op::GroupConvolution>(split->output(1),
                                                    filters,
                                                    Strides{1, 1},
                                                    Strides{1, 1},
                                                    CoordinateDiff{0, 0},
                                                    CoordinateDiff{0, 0},
                                                    Strides{1, 1},
                                                    2);
      EXPECT_EQ(conv->get_shape(), (Shape{64, 128, 91, 131}));
  }
  
  TEST(build_graph, multi_output_split_dynamic)
  {
      const auto data = make_shared<op::Parameter>(element::f32, PartialShape::dynamic());
      const auto axis = op::Constant::create(element::i64, Shape{}, {1});
      const auto split = make_shared<op::Split>(data, axis, 2);
      auto abs = make_shared<op::Abs>(split->output(1));
      EXPECT_TRUE(abs->get_output_partial_shape(0).same_scheme(PartialShape::dynamic()));
  
      auto f = make_shared<Function>(abs, ParameterVector{data});
      auto new_parameter = make_shared<op::Parameter>(element::f32, Shape{2, 4});
      split->input(0).replace_source_output(new_parameter->output(0));
      f->validate_nodes_and_infer_types();
      EXPECT_EQ(abs->get_shape(), (Shape{2, 2}));
  }
  
  TEST(build_graph, function_revalidate_and_infer)
  {
      auto arg = make_shared<op::Parameter>(element::f32, Shape{2, 4, 6, 8});
      auto pattern = op::Constant::create(element::i64, Shape{6}, {1, 3, 16, 2, 2, 2});
  
      auto r = make_shared<op::DynReshape>(arg, pattern);
      auto relu = make_shared<op::Relu>(r);
      auto f = make_shared<Function>(relu, ParameterVector{arg});
  
      EXPECT_EQ(r->get_output_element_type(0), element::f32);
      EXPECT_EQ(r->get_output_shape(0), (Shape{1, 3, 16, 2, 2, 2}));
      EXPECT_EQ(f->get_output_shape(0), (Shape{1, 3, 16, 2, 2, 2}));
  
      auto new_pattern = op::Constant::create(element::i64, Shape{2}, {32, 12});
      r->input(1).replace_source_output(new_pattern->output(0));
  
      f->validate_nodes_and_infer_types();
      EXPECT_EQ(r->get_output_shape(0), (Shape{32, 12}));
      EXPECT_EQ(f->get_output_shape(0), (Shape{32, 12}));
  }
  
  TEST(build_graph, validate_function_for_dynamic_shape)
  {
      auto make_function = [&](bool dynamic_shape) {
  
          auto param1_shape =
              dynamic_shape ? PartialShape{Dimension::dynamic(), 2, 3} : Shape{5, 4, 2};
          auto param2_shape = dynamic_shape ? PartialShape::dynamic() : Shape{5, 2, 3};
          auto param_1 = std::make_shared<op::Parameter>(element::f32, param1_shape);
          auto param_2 = std::make_shared<op::Parameter>(element::f32, param2_shape);
          auto batch_dot = make_shared<op::BatchMatMul>(param_1, param_2);
          auto f = make_shared<Function>(NodeVector{batch_dot}, ParameterVector{param_1, param_2});
          return f;
      };
  
      EXPECT_TRUE(make_function(true)->is_dynamic());
      EXPECT_FALSE(make_function(false)->is_dynamic());
  }
  