344 lines
14 KiB
C++
344 lines
14 KiB
C++
//*****************************************************************************
|
|
// Copyright 2017-2020 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 <memory>
|
|
|
|
#include "gtest/gtest.h"
|
|
#include "ngraph/file_util.hpp"
|
|
#include "ngraph/graph_util.hpp"
|
|
#include "ngraph/log.hpp"
|
|
#include "ngraph/ngraph.hpp"
|
|
#include "ngraph/op/abs.hpp"
|
|
#include "ngraph/op/add.hpp"
|
|
#include "ngraph/op/constant.hpp"
|
|
#include "ngraph/op/divide.hpp"
|
|
#include "ngraph/op/multiply.hpp"
|
|
#include "ngraph/op/product.hpp"
|
|
#include "ngraph/op/sqrt.hpp"
|
|
#include "ngraph/op/subtract.hpp"
|
|
#include "ngraph/op/sum.hpp"
|
|
#include "ngraph/pass/cse.hpp"
|
|
#include "ngraph/pass/manager.hpp"
|
|
#include "util/test_tools.hpp"
|
|
|
|
using namespace ngraph;
|
|
using namespace std;
|
|
|
|
TEST(CSE, abs_abs)
|
|
{
|
|
Shape zero_shape{0};
|
|
auto A = std::make_shared<op::Parameter>(element::i32, zero_shape);
|
|
auto abs1 = std::make_shared<op::Abs>(A);
|
|
auto abs2 = std::make_shared<op::Abs>(A);
|
|
auto f = std::make_shared<Function>(NodeVector{abs1, abs2}, ParameterVector{A});
|
|
pass::Manager pass_manager;
|
|
|
|
pass_manager.register_pass<ngraph::pass::CommonSubexpressionElimination>();
|
|
pass_manager.run_passes(f);
|
|
ASSERT_EQ(f->get_results().at(0)->get_argument(0), f->get_results().at(1)->get_argument(0));
|
|
}
|
|
|
|
TEST(CSE, abs_abs_negative)
|
|
{
|
|
Shape zero_shape{0};
|
|
auto A = std::make_shared<op::Parameter>(element::i32, zero_shape);
|
|
auto B = std::make_shared<op::Parameter>(element::i32, zero_shape);
|
|
auto abs1 = std::make_shared<op::Abs>(A);
|
|
auto abs2 = std::make_shared<op::Abs>(B);
|
|
auto f = std::make_shared<Function>(NodeVector{abs1, abs2}, ParameterVector{A, B});
|
|
pass::Manager pass_manager;
|
|
|
|
pass_manager.register_pass<ngraph::pass::CommonSubexpressionElimination>();
|
|
pass_manager.run_passes(f);
|
|
ASSERT_EQ(f->get_results().at(0)->get_argument(0), abs1);
|
|
ASSERT_EQ(f->get_results().at(1)->get_argument(0), abs2);
|
|
}
|
|
|
|
TEST(CSE, add_add)
|
|
{
|
|
Shape zero_shape{0};
|
|
auto A = std::make_shared<op::Parameter>(element::i32, zero_shape);
|
|
auto B = std::make_shared<op::Parameter>(element::i32, zero_shape);
|
|
auto add1 = std::make_shared<op::Add>(A, B);
|
|
auto add2 = std::make_shared<op::Add>(A, B);
|
|
auto f = std::make_shared<Function>(NodeVector{add1, add2}, ParameterVector{A, B});
|
|
pass::Manager pass_manager;
|
|
|
|
pass_manager.register_pass<ngraph::pass::CommonSubexpressionElimination>();
|
|
pass_manager.run_passes(f);
|
|
ASSERT_EQ(f->get_results().at(0)->get_argument(0), f->get_results().at(1)->get_argument(0));
|
|
}
|
|
|
|
TEST(CSE, add_add_commutative)
|
|
{
|
|
Shape zero_shape{0};
|
|
auto A = std::make_shared<op::Parameter>(element::i32, zero_shape);
|
|
auto B = std::make_shared<op::Parameter>(element::i32, zero_shape);
|
|
auto add1 = std::make_shared<op::Add>(A, B);
|
|
auto add2 = std::make_shared<op::Add>(B, A);
|
|
auto f = std::make_shared<Function>(NodeVector{add1, add2}, ParameterVector{A, B});
|
|
pass::Manager pass_manager;
|
|
|
|
pass_manager.register_pass<ngraph::pass::CommonSubexpressionElimination>();
|
|
pass_manager.run_passes(f);
|
|
ASSERT_EQ(f->get_results().at(0)->get_argument(0), f->get_results().at(1)->get_argument(0));
|
|
}
|
|
|
|
TEST(CSE, add_add_negative)
|
|
{
|
|
Shape zero_shape{0};
|
|
auto A = std::make_shared<op::Parameter>(element::i32, zero_shape);
|
|
auto B = std::make_shared<op::Parameter>(element::i32, zero_shape);
|
|
auto C = std::make_shared<op::Parameter>(element::i32, zero_shape);
|
|
auto D = std::make_shared<op::Parameter>(element::i32, zero_shape);
|
|
auto add1 = std::make_shared<op::Add>(A, B);
|
|
auto add2 = std::make_shared<op::Add>(C, D);
|
|
auto f = std::make_shared<Function>(NodeVector{add1, add2}, ParameterVector{A, B, C, D});
|
|
pass::Manager pass_manager;
|
|
|
|
pass_manager.register_pass<ngraph::pass::CommonSubexpressionElimination>();
|
|
pass_manager.run_passes(f);
|
|
ASSERT_EQ(f->get_results().at(0)->get_argument(0), add1);
|
|
ASSERT_EQ(f->get_results().at(1)->get_argument(0), add2);
|
|
}
|
|
|
|
TEST(CSE, abs_add)
|
|
{
|
|
Shape zero_shape{0};
|
|
auto A = std::make_shared<op::Parameter>(element::i32, zero_shape);
|
|
auto B = std::make_shared<op::Parameter>(element::i32, zero_shape);
|
|
auto abs_a1 = std::make_shared<op::Abs>(A);
|
|
auto abs_b1 = std::make_shared<op::Abs>(B);
|
|
auto abs_a2 = std::make_shared<op::Abs>(A);
|
|
auto abs_b2 = std::make_shared<op::Abs>(B);
|
|
auto add1 = std::make_shared<op::Add>(abs_a1, abs_b1);
|
|
auto add2 = std::make_shared<op::Add>(abs_a2, abs_b2);
|
|
auto f = std::make_shared<Function>(NodeVector{add1, add2}, ParameterVector{A, B});
|
|
pass::Manager pass_manager;
|
|
|
|
pass_manager.register_pass<ngraph::pass::CommonSubexpressionElimination>();
|
|
pass_manager.run_passes(f);
|
|
ASSERT_EQ(f->get_results().at(0)->get_argument(0), f->get_results().at(1)->get_argument(0));
|
|
}
|
|
|
|
TEST(CSE, abs_add_reshape_broadcast)
|
|
{
|
|
Shape zero_shape{1};
|
|
auto A = std::make_shared<op::Parameter>(element::i32, zero_shape);
|
|
auto B = std::make_shared<op::Parameter>(element::i32, zero_shape);
|
|
auto abs_a1 = std::make_shared<op::Abs>(A);
|
|
auto abs_b1 = std::make_shared<op::Abs>(B);
|
|
auto abs_a2 = std::make_shared<op::Abs>(A);
|
|
auto abs_b2 = std::make_shared<op::Abs>(B);
|
|
auto add1 = std::make_shared<op::Add>(abs_a1, abs_b1);
|
|
auto add2 = std::make_shared<op::Add>(abs_a2, abs_b2);
|
|
{
|
|
// success case
|
|
auto reshape1 = std::make_shared<op::Reshape>(add1, AxisVector{0}, Shape{1, 1});
|
|
auto reshape2 = std::make_shared<op::Reshape>(add2, AxisVector{0}, Shape{1, 1});
|
|
auto broadcast1 = std::make_shared<op::Broadcast>(reshape1, Shape{1, 1, 3}, AxisSet{2});
|
|
auto broadcast2 = std::make_shared<op::Broadcast>(reshape2, Shape{1, 1, 3}, AxisSet{2});
|
|
auto f =
|
|
std::make_shared<Function>(NodeVector{broadcast1, broadcast2}, ParameterVector{A, B});
|
|
pass::Manager pass_manager;
|
|
|
|
pass_manager.register_pass<ngraph::pass::CommonSubexpressionElimination>();
|
|
pass_manager.run_passes(f);
|
|
ASSERT_EQ(f->get_results().at(0)->get_argument(0), f->get_results().at(1)->get_argument(0));
|
|
}
|
|
{
|
|
// fail case
|
|
auto reshape1 = std::make_shared<op::Reshape>(add1, AxisVector{0}, Shape{1});
|
|
auto reshape2 = std::make_shared<op::Reshape>(add2, AxisVector{0}, Shape{1, 1});
|
|
auto f = std::make_shared<Function>(NodeVector{reshape1, reshape2}, ParameterVector{A, B});
|
|
pass::Manager pass_manager;
|
|
|
|
pass_manager.register_pass<ngraph::pass::CommonSubexpressionElimination>();
|
|
pass_manager.run_passes(f);
|
|
ASSERT_NE(f->get_results().at(0)->get_argument(0), f->get_results().at(1)->get_argument(0));
|
|
}
|
|
{
|
|
// fail case
|
|
auto broadcast1 = std::make_shared<op::Broadcast>(add1, Shape{1, 2}, AxisSet{1});
|
|
auto broadcast2 = std::make_shared<op::Broadcast>(add2, Shape{1, 1, 2}, AxisSet{1, 2});
|
|
auto f =
|
|
std::make_shared<Function>(NodeVector{broadcast1, broadcast2}, ParameterVector{A, B});
|
|
pass::Manager pass_manager;
|
|
|
|
pass_manager.register_pass<ngraph::pass::CommonSubexpressionElimination>();
|
|
pass_manager.run_passes(f);
|
|
ASSERT_NE(f->get_results().at(0)->get_argument(0), f->get_results().at(1)->get_argument(0));
|
|
}
|
|
}
|
|
|
|
TEST(CSE, abs_add_abs_add)
|
|
{
|
|
Shape zero_shape{0};
|
|
auto A = std::make_shared<op::Parameter>(element::i32, zero_shape);
|
|
auto B = std::make_shared<op::Parameter>(element::i32, zero_shape);
|
|
auto abs_a1 = std::make_shared<op::Abs>(A);
|
|
auto abs_b1 = std::make_shared<op::Abs>(B);
|
|
auto abs_a2 = std::make_shared<op::Abs>(A);
|
|
auto abs_b2 = std::make_shared<op::Abs>(B);
|
|
auto add1 = std::make_shared<op::Add>(abs_a1, abs_b1);
|
|
auto add2 = std::make_shared<op::Add>(abs_a2, abs_b2);
|
|
auto abs_add1 = std::make_shared<op::Abs>(add1);
|
|
auto abs_add2 = std::make_shared<op::Abs>(add2);
|
|
auto C = std::make_shared<op::Parameter>(element::i32, zero_shape);
|
|
auto add3 = std::make_shared<op::Add>(abs_add1, C);
|
|
auto add4 = std::make_shared<op::Add>(abs_add2, C);
|
|
auto f = std::make_shared<Function>(NodeVector{add3, add4}, ParameterVector{A, B, C});
|
|
pass::Manager pass_manager;
|
|
|
|
pass_manager.register_pass<ngraph::pass::CommonSubexpressionElimination>();
|
|
pass_manager.run_passes(f);
|
|
ASSERT_EQ(f->get_results().at(0)->get_argument(0), f->get_results().at(1)->get_argument(0));
|
|
}
|
|
|
|
TEST(CSE, abs_add_abs_add_negative)
|
|
{
|
|
Shape zero_shape{0};
|
|
auto A = std::make_shared<op::Parameter>(element::i32, zero_shape);
|
|
auto B = std::make_shared<op::Parameter>(element::i32, zero_shape);
|
|
auto abs_a1 = std::make_shared<op::Abs>(A);
|
|
auto abs_b1 = std::make_shared<op::Abs>(B);
|
|
auto abs_a2 = std::make_shared<op::Abs>(A);
|
|
auto abs_b2 = std::make_shared<op::Abs>(B);
|
|
auto add1 = std::make_shared<op::Add>(abs_a1, abs_b1);
|
|
auto add2 = std::make_shared<op::Add>(abs_a2, abs_b2);
|
|
auto abs_add1 = std::make_shared<op::Abs>(add1);
|
|
auto abs_add2 = std::make_shared<op::Abs>(add2);
|
|
auto C = std::make_shared<op::Parameter>(element::i32, zero_shape);
|
|
auto D = std::make_shared<op::Parameter>(element::i32, zero_shape);
|
|
auto add3 = std::make_shared<op::Add>(abs_add1, C);
|
|
auto add4 = std::make_shared<op::Add>(abs_add2, D);
|
|
auto f = std::make_shared<Function>(NodeVector{add3, add4}, ParameterVector{A, B, C, D});
|
|
pass::Manager pass_manager;
|
|
|
|
pass_manager.register_pass<ngraph::pass::CommonSubexpressionElimination>();
|
|
pass_manager.run_passes(f);
|
|
auto oadd3 = f->get_results().at(0)->get_argument(0);
|
|
auto oadd4 = f->get_results().at(1)->get_argument(0);
|
|
ASSERT_EQ(oadd3, add3);
|
|
ASSERT_EQ(oadd4, add4);
|
|
ASSERT_EQ(oadd3->get_argument(1), C);
|
|
ASSERT_EQ(oadd4->get_argument(1), D);
|
|
ASSERT_EQ(oadd3->get_argument(0), oadd4->get_argument(0));
|
|
}
|
|
|
|
template <typename T>
|
|
static void execute_cse_reduction_test()
|
|
{
|
|
Shape zero_shape{0};
|
|
auto A = std::make_shared<op::Parameter>(element::i32, Shape{3, 5});
|
|
auto a_reduction_op = std::make_shared<T>(A, AxisSet{0, 1});
|
|
auto a_reduction_op2 = std::make_shared<T>(A, AxisSet{0, 1});
|
|
auto a_reduction_op3 = std::make_shared<T>(A, AxisSet{0});
|
|
auto sub_aa = a_reduction_op - a_reduction_op2;
|
|
|
|
auto B = std::make_shared<op::Parameter>(element::i32, Shape{3, 5});
|
|
auto b_reduction_op = std::make_shared<T>(B, AxisSet{0, 1});
|
|
|
|
auto sub_ab = a_reduction_op - b_reduction_op;
|
|
auto f = std::make_shared<Function>(NodeVector{sub_aa, sub_ab, a_reduction_op3},
|
|
ParameterVector{A, B});
|
|
pass::Manager pass_manager;
|
|
|
|
pass_manager.register_pass<ngraph::pass::CommonSubexpressionElimination>();
|
|
pass_manager.run_passes(f);
|
|
|
|
ASSERT_EQ(sub_aa->get_argument(0), sub_aa->get_argument(1));
|
|
ASSERT_NE(sub_ab->get_argument(0), sub_ab->get_argument(1));
|
|
ASSERT_NE(f->get_results().at(2)->get_argument(0), sub_aa->get_argument(0));
|
|
}
|
|
|
|
TEST(CSE, reduction_ops)
|
|
{
|
|
execute_cse_reduction_test<op::Sum>();
|
|
execute_cse_reduction_test<op::Product>();
|
|
}
|
|
|
|
TEST(CSE, constant)
|
|
{
|
|
Shape zero_shape{0};
|
|
auto iconst0 = op::Constant::create(element::i32, Shape{}, {0});
|
|
auto iconst0_1 = op::Constant::create(element::i32, Shape{}, {0});
|
|
auto iconst1 = op::Constant::create(element::i32, Shape{}, {1});
|
|
auto iconst1_1 = op::Constant::create(element::i32, Shape{}, {1});
|
|
auto fconst0 = op::Constant::create(element::f32, Shape{}, {0});
|
|
auto iconst111 = op::Constant::create(element::i32, Shape{3}, {1, 1, 1});
|
|
auto iconst112 = op::Constant::create(element::i32, Shape{3}, {1, 1, 2});
|
|
|
|
auto abs0 = std::make_shared<op::Abs>(iconst0);
|
|
auto abs0_1 = std::make_shared<op::Abs>(iconst0_1);
|
|
|
|
auto abs1 = std::make_shared<op::Abs>(iconst1);
|
|
auto abs1_1 = std::make_shared<op::Abs>(iconst1_1);
|
|
|
|
auto absf = std::make_shared<op::Abs>(fconst0);
|
|
|
|
auto abs111 = std::make_shared<op::Abs>(iconst111);
|
|
auto abs112 = std::make_shared<op::Abs>(iconst112);
|
|
|
|
auto f = std::make_shared<Function>(
|
|
NodeVector{abs0, abs0_1, abs1, abs1_1, absf, abs111, abs112}, ParameterVector{});
|
|
pass::Manager pass_manager;
|
|
|
|
pass_manager.register_pass<ngraph::pass::CommonSubexpressionElimination>();
|
|
pass_manager.run_passes(f);
|
|
|
|
ASSERT_EQ(abs0->get_argument(0), abs0_1->get_argument(0));
|
|
ASSERT_EQ(abs1->get_argument(0), abs1_1->get_argument(0));
|
|
ASSERT_NE(abs0->get_argument(0), abs1->get_argument(0));
|
|
ASSERT_NE(abs0->get_argument(0), absf->get_argument(0));
|
|
ASSERT_NE(abs111->get_argument(0), abs112->get_argument(0));
|
|
}
|
|
|
|
TEST(CSE, one_hot)
|
|
{
|
|
pass::Manager pass_manager;
|
|
pass_manager.register_pass<ngraph::pass::CommonSubexpressionElimination>();
|
|
{
|
|
Shape param_shape{8};
|
|
Shape out_shape{8, 16};
|
|
auto A = std::make_shared<op::Parameter>(element::i32, param_shape);
|
|
auto onehot1 = std::make_shared<op::OneHot>(A, out_shape, 1);
|
|
auto onehot2 = std::make_shared<op::OneHot>(A, out_shape, 1);
|
|
auto f = std::make_shared<Function>(NodeVector{onehot1, onehot2}, ParameterVector{A});
|
|
pass_manager.run_passes(f);
|
|
ASSERT_EQ(f->get_results().at(0)->get_argument(0), f->get_results().at(1)->get_argument(0));
|
|
}
|
|
{
|
|
Shape param_shape{8, 1};
|
|
Shape out_shape{8, 16};
|
|
auto A = std::make_shared<op::Parameter>(element::i32, param_shape);
|
|
auto reshape1 = std::make_shared<op::Reshape>(A, AxisVector{0, 1}, Shape{8});
|
|
auto reshape2 = std::make_shared<op::Reshape>(A, AxisVector{0, 1}, Shape{8});
|
|
auto onehot1 = std::make_shared<op::OneHot>(reshape1, out_shape, 1);
|
|
auto onehot2 = std::make_shared<op::OneHot>(reshape2, out_shape, 1);
|
|
auto f = std::make_shared<Function>(NodeVector{onehot1, onehot2}, ParameterVector{A});
|
|
pass_manager.run_passes(f);
|
|
ASSERT_EQ(f->get_results().at(0)->get_argument(0), f->get_results().at(1)->get_argument(0));
|
|
}
|
|
}
|
|
|
|
TEST(CSE, pass_property)
|
|
{
|
|
auto pass = std::make_shared<ngraph::pass::CommonSubexpressionElimination>();
|
|
ASSERT_TRUE(pass->get_property(pass::PassProperty::REQUIRE_STATIC_SHAPE));
|
|
ASSERT_FALSE(pass->get_property(pass::PassProperty::CHANGE_DYNAMIC_STATE));
|
|
}
|