/** * Copyright 2021-2022 Huawei Technologies Co., Ltd * * 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 #include #include #include #include "common/common_test.h" #include "mindapi/base/logging.h" #include "mindapi/ir/func_graph.h" #include "mindapi/ir/primitive.h" #include "mindapi/ir/tensor.h" #include "mindapi/ir/utils.h" namespace mindspore::api { class TestMindApi : public UT::Common { public: TestMindApi() = default; }; /// Feature: MindAPI /// Description: test basic 'is()' 'cast()' /// Expectation: is/cast works correctly. TEST_F(TestMindApi, test_base_isa_cast) { auto value_node = MakeShared(MakeValue(0)); auto base = MakeShared(value_node->impl()); ASSERT_TRUE(base->isa()); ASSERT_TRUE(base->isa()); ASSERT_TRUE(base->isa()); ASSERT_FALSE(base->isa()); auto anf_node = base->cast(); ASSERT_TRUE(anf_node != nullptr); ASSERT_TRUE(anf_node->impl() == value_node->impl()); ASSERT_TRUE(base->cast() == nullptr); } /// Feature: MindAPI /// Description: test graph construction. /// Expectation: graph is constructed as expected. TEST_F(TestMindApi, test_graph_construction) { // fg(x) { return myprim(x, 1); } auto fg = FuncGraph::Create(); auto x = fg->add_parameter(); x->set_name("x"); auto prim = MakeShared("myprim"); auto prim_node = MakeShared(prim); auto value_node = MakeShared(MakeValue(1)); auto cnode = fg->NewCNode({prim_node, x, value_node}); fg->set_output(cnode); // Now we check the graph. ASSERT_EQ(fg->parameters().size(), 1); ASSERT_TRUE(fg->parameters()[0]->isa()); ASSERT_EQ(fg->parameters()[0]->cast()->name(), "x"); auto ret_node = fg->get_return(); ASSERT_TRUE(ret_node != nullptr); auto output_node = fg->output(); ASSERT_TRUE(output_node != nullptr); ASSERT_TRUE(output_node->isa()); auto output_cnode = output_node->cast(); ASSERT_EQ(output_cnode->inputs().size(), 3); ASSERT_TRUE(output_cnode->input(0)->isa()); ASSERT_TRUE(output_cnode->input(0)->cast()->value()->isa()); ASSERT_EQ(output_cnode->input(0)->cast()->value()->cast()->name(), "myprim"); ASSERT_TRUE(output_cnode->input(1)->isa()); ASSERT_EQ(output_cnode->input(1)->cast()->name(), "x"); ASSERT_TRUE(output_cnode->input(2)->isa()); ASSERT_EQ(output_cnode->impl(), cnode->impl()); } /// Feature: MindAPI /// Description: test value related functions. /// Expectation: value related functions work as expected. TEST_F(TestMindApi, test_values) { int64_t one = 1; auto s = MakeValue("hello"); auto i = MakeValue(one); auto i2 = MakeValue(2); auto b = MakeValue(true); auto f = MakeValue(3.14f); auto seq = MakeValue(std::vector{3, 4, 5}); auto seq_str = MakeValue(std::vector({"this", "is", "mindspore", "api"})); ASSERT_TRUE(s->isa()); ASSERT_TRUE(i->isa()); ASSERT_TRUE(i2->isa()); ASSERT_TRUE(b->isa()); ASSERT_TRUE(f->isa()); ASSERT_TRUE(seq->isa()); ASSERT_TRUE(seq_str->isa()); ASSERT_EQ(GetValue(s), "hello"); ASSERT_EQ(GetValue(i), one); ASSERT_EQ(GetValue(i2), 2); ASSERT_TRUE(GetValue(b)); ASSERT_TRUE(std::abs(GetValue(f) - 3.14f) < 0.00001f); ASSERT_EQ(GetValue(i), ""); ASSERT_EQ(GetValue(s), 0); ASSERT_FALSE(GetValue(s)); ASSERT_EQ(GetValue(s), 0.0f); auto seq_ptr = seq->cast(); ASSERT_TRUE(seq_ptr != nullptr); ASSERT_EQ(seq_ptr->size(), 3); ASSERT_EQ(seq_ptr->value().size(), 3); ASSERT_TRUE(seq_ptr->value()[0]->isa()); ASSERT_EQ(GetValue(seq_ptr->value()[0]), 3); ASSERT_EQ(GetValue(seq_ptr->value()[1]), 4); ASSERT_EQ(GetValue(seq_ptr->value()[2]), 5); auto seq_values = GetValue>(seq); ASSERT_EQ(seq_values.size(), 3); ASSERT_EQ(seq_values[0], 3); ASSERT_EQ(seq_values[1], 4); ASSERT_EQ(seq_values[2], 5); auto str_values = GetValue>(seq_str); ASSERT_EQ(str_values.size(), 4); ASSERT_EQ(str_values[0], "this"); ASSERT_EQ(str_values[1], "is"); ASSERT_EQ(str_values[2], "mindspore"); ASSERT_EQ(str_values[3], "api"); auto value_list = GetValue(seq); ASSERT_EQ(value_list.size(), 3); ASSERT_EQ(utils::cast(value_list[0]), 3); ASSERT_EQ(utils::cast(value_list[1]), 4); ASSERT_EQ(utils::cast(value_list[2]), 5); std::vector vec_uint8{5, 6, 7}; auto uint8_seq = MakeValue>(vec_uint8); ASSERT_TRUE(uint8_seq->isa()); auto uint8_values = GetValue>(uint8_seq); ASSERT_EQ(uint8_values.size(), 3); ASSERT_EQ(uint8_values[0], 5); ASSERT_EQ(uint8_values[1], 6); ASSERT_EQ(uint8_values[2], 7); auto seq_bool = MakeValue(std::vector{true, false, true}); auto seq_bool_ptr = seq_bool->cast(); ASSERT_TRUE(seq_bool_ptr != nullptr); ASSERT_EQ(seq_bool_ptr->size(), 3); ASSERT_EQ(seq_bool_ptr->value().size(), 3); ASSERT_TRUE(seq_bool_ptr->value()[0]->isa()); ASSERT_TRUE(GetValue(seq_bool_ptr->value()[0])); ASSERT_FALSE(GetValue(seq_bool_ptr->value()[1])); ASSERT_TRUE(GetValue(seq_bool_ptr->value()[2])); auto prim = MakeShared("myprim"); auto node = NewValueNode(prim); ASSERT_TRUE(node != nullptr); ASSERT_EQ(node->value(), prim); } /// Feature: MindAPI /// Description: test graph manager functions. /// Expectation: graph manager functions work as expected. TEST_F(TestMindApi, test_func_graph_manager) { // fg(x, y) { return myprim(add(x, y), 1); } auto fg = FuncGraph::Create(); auto x = fg->add_parameter(); x->set_name("x"); auto y = fg->add_parameter(); y->set_name("y"); auto add = MakeShared("add"); auto add_node = MakeShared(add); auto add_cnode = fg->NewCNode({add_node, x, y}); auto prim = MakeShared("myprim"); auto prim_node = MakeShared(prim); auto value_node = MakeShared(MakeValue(1)); auto cnode = fg->NewCNode({prim_node, add_cnode, value_node}); fg->set_output(cnode); auto mgr = FuncGraphManager::Manage(fg); ASSERT_TRUE(mgr != nullptr); ASSERT_TRUE(fg->manager() != nullptr); ASSERT_EQ(fg->manager()->impl(), mgr->impl()); ASSERT_EQ(fg->manager(), mgr); ASSERT_EQ(cnode->input(1)->impl(), add_cnode->impl()); mgr->Replace(add_cnode, x); ASSERT_EQ(cnode->input(1)->impl(), x->impl()); mgr->SetEdge(cnode, 1, y); ASSERT_EQ(cnode->input(1)->impl(), y->impl()); mgr->AddEdge(cnode, x); ASSERT_EQ(cnode->size(), 4); ASSERT_EQ(cnode->input(3)->impl(), x->impl()); auto users = mgr->GetUsers(value_node); ASSERT_EQ(users.size(), 1); ASSERT_EQ(users[0].first, cnode); ASSERT_EQ(users[0].second, 2); } /// Feature: MindAPI /// Description: test value node utils. /// Expectation: value node utils work as expected. TEST_F(TestMindApi, test_value_node_utils) { auto fg = FuncGraph::Create(); auto fg_node = MakeShared(fg); auto prim = MakeShared("myprim"); auto prim_node = MakeShared(prim); auto one = MakeShared(MakeValue(1)); auto cnode = fg->NewCNode({fg_node, prim_node, one}); ASSERT_TRUE(GetValueNode(cnode) == nullptr); auto fg1 = GetValueNode(cnode->input(0)); ASSERT_TRUE(fg1 != nullptr); ASSERT_TRUE(fg1->isa()); auto prim1 = GetValueNode(cnode->input(1)); ASSERT_TRUE(prim1 != nullptr); ASSERT_TRUE(prim1->isa()); auto imm = GetValueNode(cnode->input(2)); ASSERT_TRUE(imm != nullptr); ASSERT_TRUE(imm->isa()); ASSERT_EQ(imm->cast()->value(), 1); auto value = GetValueNode(cnode->input(2)); ASSERT_TRUE(value != nullptr); ASSERT_EQ(GetValue(value), 1); ASSERT_TRUE(GetValueNode(cnode->input(0)) == nullptr); ASSERT_TRUE(GetValueNode(cnode->input(1)) == nullptr); ASSERT_TRUE(GetValueNode(cnode->input(2)) == nullptr); // Test NewValueNode. auto int_node = NewValueNode(1); auto bool_node = NewValueNode(true); auto float_node = NewValueNode(1.23f); auto str_node = NewValueNode("hello"); ASSERT_TRUE(int_node->value()->isa()); ASSERT_EQ(int_node->value()->cast()->value(), 1); ASSERT_TRUE(bool_node->value()->isa()); ASSERT_TRUE(bool_node->value()->cast()->value()); ASSERT_TRUE(float_node->value()->isa()); ASSERT_TRUE(std::abs(float_node->value()->cast()->value() - 1.23f) < 0.0000001f); ASSERT_TRUE(str_node->value()->isa()); ASSERT_EQ(str_node->value()->cast()->value(), "hello"); } /// Feature: MindAPI /// Description: test SharedPtr. /// Expectation: SharedPtr work as expected. TEST_F(TestMindApi, test_object_ptr) { auto fg = FuncGraph::Create(); auto fg_node = MakeShared(fg); auto prim = MakeShared("myprim"); auto prim_node = MakeShared(prim); auto one = MakeShared(MakeValue(1)); auto cnode = fg->NewCNode({fg_node, prim_node, one}); ASSERT_TRUE(fg != nullptr); ASSERT_FALSE(!fg); ASSERT_TRUE(fg ? true : false); ASSERT_TRUE((*cnode).input(0) == fg_node); ASSERT_TRUE(cnode->input(0) == fg_node); ASSERT_TRUE(cnode.get()->input(0) == fg_node); ASSERT_EQ(cnode->input(0), fg_node); ASSERT_EQ(cnode->input(1), prim_node); ASSERT_EQ(cnode->input(2), one); ASSERT_TRUE(cnode->input(0) != fg); AnfNodePtr p = fg_node; ASSERT_TRUE(p == fg_node); ASSERT_TRUE(p->isa()); ASSERT_TRUE(p->cast() != nullptr); ASSERT_TRUE(p->cast() == fg_node); p = cnode; ASSERT_TRUE(p == cnode); ASSERT_TRUE(p->isa()); ASSERT_TRUE(p->cast() != nullptr); ASSERT_TRUE(p->cast() == cnode); ASSERT_TRUE(p.get() == cnode.get()); ASSERT_TRUE(p != nullptr); ASSERT_FALSE(p == nullptr); ASSERT_TRUE(p > nullptr); ASSERT_FALSE(p < nullptr); ASSERT_TRUE(p >= nullptr); ASSERT_FALSE(p <= nullptr); ASSERT_TRUE(nullptr != p); ASSERT_FALSE(nullptr == p); ASSERT_TRUE(nullptr < p); ASSERT_FALSE(nullptr > p); ASSERT_TRUE(nullptr <= p); ASSERT_FALSE(nullptr >= p); AnfNodePtr q = fg_node; ASSERT_TRUE(p != q); if (p.get()->impl() > q.get()->impl()) { ASSERT_TRUE(p > q); ASSERT_TRUE(p >= q); ASSERT_TRUE(q < p); ASSERT_TRUE(q <= p); } else { ASSERT_TRUE(p < q); ASSERT_TRUE(p <= q); ASSERT_TRUE(q > p); ASSERT_TRUE(q >= p); } std::stringstream ss1; std::stringstream ss2; ss1 << p; ss2 << cnode.get()->impl().get(); ASSERT_EQ(ss1.str(), ss2.str()); std::unordered_map mymap; mymap.emplace(p, q); mymap.emplace(q, p); ASSERT_TRUE(mymap.find(p) != mymap.end()); ASSERT_TRUE(mymap.find(q) != mymap.end()); ASSERT_TRUE(mymap[p] == q); ASSERT_TRUE(mymap[q] == p); } /// Feature: MindAPI /// Description: test Tensor API. /// Expectation: Tensor API work as expected. TEST_F(TestMindApi, test_tensor_api) { ShapeVector shape{1, 2, 3}; auto tensor = MakeShared(kNumberTypeFloat32, shape); ASSERT_EQ(tensor->data_type(), kNumberTypeFloat32); ASSERT_EQ(tensor->shape(), shape); ASSERT_EQ(tensor->DataSize(), 6); ASSERT_EQ(tensor->Size(), 24); ShapeVector shape2{2, 3}; tensor->set_data_type(kNumberTypeInt32); tensor->set_shape(shape2); ASSERT_EQ(tensor->data_type(), kNumberTypeInt32); ASSERT_EQ(tensor->shape(), shape2); // TensorType. TypePtr tensor_type = MakeShared(Type::GetType(TypeId::kNumberTypeFloat32)); ASSERT_TRUE(tensor_type->isa()); ASSERT_EQ(tensor_type->cast()->element()->type_id(), kNumberTypeFloat32); } /// Feature: MindAPI /// Description: test Tensor with dynamic shape. /// Expectation: Tensor API work as expected. TEST_F(TestMindApi, test_tensor_with_dyn_shape) { ShapeVector shape{1, 2, -1, -2}; auto tensor = MakeShared(kNumberTypeFloat32, shape); ASSERT_EQ(tensor->data_type(), kNumberTypeFloat32); ASSERT_EQ(tensor->shape(), shape); ASSERT_EQ(tensor->DataSize(), 0); ASSERT_EQ(tensor->Size(), 0); ShapeVector shape2{2, 3}; tensor->set_data_type(kNumberTypeInt32); tensor->set_shape(shape2); ASSERT_EQ(tensor->data_type(), kNumberTypeInt32); ASSERT_EQ(tensor->shape(), shape2); ShapeVector shape3{1, -1, 3}; auto tensor2 = MakeShared(kNumberTypeFloat32, shape); ASSERT_EQ(tensor2->data_type(), kNumberTypeFloat32); ASSERT_EQ(tensor2->shape(), shape); ASSERT_EQ(tensor2->DataSize(), 0); ASSERT_EQ(tensor2->Size(), 0); ShapeVector shape4{3, 4}; tensor2->set_data_type(kNumberTypeInt32); tensor2->set_shape(shape4); ASSERT_EQ(tensor2->data_type(), kNumberTypeInt32); ASSERT_EQ(tensor2->shape(), shape4); } /// Feature: MindAPI /// Description: test utils API. /// Expectation: Tensor API work as expected. TEST_F(TestMindApi, test_api_utils) { // Test utils::isa, utils::cast. auto anf_node = NewValueNode("hello"); ASSERT_TRUE(utils::isa(anf_node)); ASSERT_TRUE(utils::isa(anf_node)); ASSERT_FALSE(utils::isa(anf_node)); ASSERT_TRUE(utils::cast(anf_node) != nullptr); ASSERT_TRUE(utils::cast(anf_node) == nullptr); ASSERT_TRUE(utils::isa(anf_node->value())); ASSERT_EQ(utils::cast(anf_node->value()), "hello"); auto int_value = MakeValue(123); ASSERT_TRUE(utils::isa(int_value)); ASSERT_EQ(utils::cast(int_value), 123); anf_node = nullptr; ASSERT_FALSE(utils::isa(anf_node)); ASSERT_FALSE(utils::isa(anf_node)); ASSERT_TRUE(utils::cast(anf_node) == nullptr); // Test clone graph. auto fg = FuncGraph::Create(); auto x = fg->add_parameter(); x->set_name("x"); auto y = fg->add_parameter(); y->set_name("y"); auto add = MakeShared("add"); auto add_node = MakeShared(add); auto add_cnode = fg->NewCNode({add_node, x, y}); auto prim = MakeShared("myprim"); auto prim_node = MakeShared(prim); auto value_node = MakeShared(MakeValue(1)); auto cnode = fg->NewCNode({prim_node, add_cnode, value_node}); fg->set_output(cnode); auto cloned_fg = utils::CloneGraph(fg); ASSERT_TRUE(cloned_fg != nullptr); ASSERT_EQ(cloned_fg->parameters().size(), 2); auto new_output = cloned_fg->output(); ASSERT_TRUE(new_output != nullptr); ASSERT_TRUE(new_output->isa()); ASSERT_EQ(new_output->cast()->size(), cnode->size()); ASSERT_TRUE(new_output != cnode); ASSERT_TRUE(new_output->cast() != cnode); // Test get pad mode. auto pm_lower = MakeValue("pad"); auto pm_upper = MakeValue("PAD"); ASSERT_EQ(utils::GetPadMode(pm_lower), 0); ASSERT_EQ(utils::GetPadMode(pm_lower, false), 0); ASSERT_EQ(utils::GetPadMode(pm_upper, true), 0); } /// Feature: MindAPI /// Description: test logging API. /// Expectation: logging work as expected. TEST_F(TestMindApi, test_api_logging) { std::string name = "mindspore"; MS_LOG(DEBUG) << "hello debug"; MS_LOG(INFO) << "hello info"; MS_LOG(WARNING) << "hello warning"; MS_LOG(ERROR) << "hello error"; MS_LOG(ERROR) << name; MS_LOG(ERROR) << "hello " << name; MS_LOG(ERROR) << name << " hello"; try { MS_LOG(EXCEPTION) << "hello exception"; ASSERT_TRUE(false); } catch (...) { } ASSERT_TRUE(true); } /// Feature: MindAPI /// Description: test AbstractSequence API. /// Expectation: AbstractSequence work as expected. TEST_F(TestMindApi, test_abstract_sequence) { AbstractBasePtrList abs_list; abs_list.emplace_back(MakeShared(int64_t(1))); abs_list.emplace_back(MakeShared(float(1.2f))); abs_list.emplace_back(MakeShared(true)); abs_list.emplace_back(MakeShared(std::string("hello"))); ShapeVector shape{1, 2, 3}; abs_list.emplace_back(MakeShared(TypeId::kNumberTypeFloat32, shape)); auto abs_tuple = MakeShared(abs_list); ASSERT_EQ(abs_tuple->elements().size(), abs_list.size()); ASSERT_EQ(GetValue(abs_tuple->elements()[0]->value()), 1); ASSERT_TRUE(abs_tuple->elements()[1]->value()->isa()); ASSERT_TRUE(GetValue(abs_tuple->elements()[2]->value())); ASSERT_EQ(GetValue(abs_tuple->elements()[3]->value()), "hello"); ASSERT_TRUE(abs_tuple->elements()[4]->isa()); ASSERT_EQ(abs_tuple->elements()[4]->type()->type_id(), TypeId::kObjectTypeTensorType); ASSERT_EQ(abs_tuple->elements()[4]->shape()->shape(), shape); ASSERT_EQ(abs_tuple->elements()[4]->cast()->element()->type()->type_id(), TypeId::kNumberTypeFloat32); ShapeVector shape2{2, 3, 4}; abs_tuple->elements()[4]->set_shape(MakeShared(shape2)); ASSERT_EQ(abs_tuple->elements()[4]->shape()->shape(), shape2); } } // namespace mindspore::api