342 lines
14 KiB
C++
342 lines
14 KiB
C++
// Copyright (c) 2023 CINN Authors. All Rights Reserved.
|
|
//
|
|
// 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 "paddle/cinn/common/integer_set.h"
|
|
|
|
#include <glog/logging.h>
|
|
#include <gtest/gtest.h>
|
|
#include "paddle/cinn/ir/op/ir_operators.h"
|
|
|
|
namespace cinn {
|
|
namespace common {
|
|
|
|
class TestSymbolicExprAnalyzer : public ::testing::Test {
|
|
public:
|
|
void SetUp() override {
|
|
// Var is [lower_bound, upper_bound)
|
|
i = ir::Var(ir::Expr(0), ir::Expr(7), "i"); // i ∈ [0, 7)
|
|
j = ir::Var(ir::Expr(0), ir::Expr(15), "j"); // j ∈ [0, 15)
|
|
// CasInterval is [lower_bound, upper_bound]
|
|
var_intervals = {
|
|
{"i", CasInterval(i->lower_bound, i->upper_bound - 1)}, // i ∈ [0, 6]
|
|
{"j", CasInterval(j->lower_bound, j->upper_bound - 1)}, // j ∈ [0, 14]
|
|
};
|
|
}
|
|
|
|
ir::Var i;
|
|
ir::Var j;
|
|
cas_intervals_t var_intervals;
|
|
SymbolicExprAnalyzer analyzer{var_intervals};
|
|
};
|
|
|
|
TEST_F(TestSymbolicExprAnalyzer, bound) {
|
|
ir::Expr e1 = i + j;
|
|
EXPECT_EQ(analyzer.LowerBound(e1), ir::Expr(0));
|
|
EXPECT_EQ(analyzer.UpperBound(e1), ir::Expr(20)); // 6 + 14 = 20
|
|
|
|
ir::Expr e2 = 16 * i + j;
|
|
EXPECT_EQ(analyzer.LowerBound(e2), ir::Expr(0));
|
|
EXPECT_EQ(analyzer.UpperBound(e2), ir::Expr(110)); // 16 * 6 + 14 = 110
|
|
|
|
ir::Expr e3 = 16 * i + j + 1;
|
|
EXPECT_EQ(analyzer.LowerBound(e3), ir::Expr(1));
|
|
EXPECT_EQ(analyzer.UpperBound(e3), ir::Expr(111)); // 16 * 6 + 15 = 111
|
|
|
|
ir::Expr e4 = (16 * i + j) / 16;
|
|
EXPECT_EQ(analyzer.LowerBound(e4), ir::Expr(0));
|
|
EXPECT_EQ(analyzer.UpperBound(e4), ir::Expr(6)); // 110 / 16 = 6
|
|
|
|
ir::Expr e5 = (16 * i + j) % 16;
|
|
EXPECT_EQ(analyzer.LowerBound(e5), ir::Expr(0));
|
|
EXPECT_EQ(analyzer.UpperBound(e5), ir::Expr(14)); // 110 % 16
|
|
|
|
ir::Expr e6 = i - j;
|
|
EXPECT_EQ(analyzer.LowerBound(e6), ir::Expr(-14)); // 0 - 14
|
|
EXPECT_EQ(analyzer.UpperBound(e6), ir::Expr(6)); // 6 - 0
|
|
|
|
ir::Expr e7 = 0 - i - j;
|
|
EXPECT_EQ(analyzer.LowerBound(e7), ir::Expr(-20)); // 0 - 6 - 14
|
|
EXPECT_EQ(analyzer.UpperBound(e7), ir::Expr(0)); // 0 - 0 - 0
|
|
|
|
ir::Expr e8 = -1 * i - j;
|
|
EXPECT_EQ(analyzer.LowerBound(e8), ir::Expr(-20)); // -1 * 6 - 14
|
|
EXPECT_EQ(analyzer.UpperBound(e8), ir::Expr(0)); // -1 * 0 - 0
|
|
}
|
|
|
|
TEST_F(TestSymbolicExprAnalyzer, compare) {
|
|
// case 1
|
|
ir::Expr e1 = 4 * i + 2 * j;
|
|
ir::Expr e2 = 2 * i + j;
|
|
|
|
EXPECT_TRUE(analyzer.ProveEQ(e1, e1).value() &&
|
|
analyzer.Prove(ir::EQ::Make(e1, e1)).value());
|
|
EXPECT_FALSE(analyzer.ProveEQ(e1, e2).has_value() ||
|
|
analyzer.Prove(ir::EQ::Make(e1, e2)).has_value());
|
|
EXPECT_FALSE(analyzer.ProveNE(e1, e1).value() &&
|
|
analyzer.Prove(ir::NE::Make(e1, e1)).value());
|
|
EXPECT_FALSE(analyzer.ProveNE(e1, e2).has_value() ||
|
|
analyzer.Prove(ir::NE::Make(e1, e2)).has_value());
|
|
|
|
EXPECT_TRUE(analyzer.ProveGE(e1, e2).value() &&
|
|
analyzer.Prove(e1 >= e2).value());
|
|
EXPECT_FALSE(analyzer.ProveGE(e2, e1).has_value() ||
|
|
analyzer.Prove(e2 >= e1).has_value());
|
|
EXPECT_TRUE(analyzer.ProveLE(e2, e1).value() &&
|
|
analyzer.Prove(e2 <= e1).value());
|
|
EXPECT_FALSE(analyzer.ProveLE(e1, e2).has_value() ||
|
|
analyzer.Prove(e1 <= e2).has_value());
|
|
|
|
EXPECT_FALSE(analyzer.ProveGT(e1, e2).has_value() ||
|
|
analyzer.Prove(e1 > e2).has_value());
|
|
EXPECT_FALSE(analyzer.ProveGT(e2, e1).value() &&
|
|
analyzer.Prove(e2 > e1).value());
|
|
EXPECT_FALSE(analyzer.ProveLT(e2, e1).has_value() ||
|
|
analyzer.Prove(e2 < e1).has_value());
|
|
EXPECT_FALSE(analyzer.ProveLT(e1, e2).value() &&
|
|
analyzer.Prove(e1 < e2).value());
|
|
|
|
// case 2
|
|
ir::Expr e3 = i + j + 1;
|
|
ir::Expr e4 = i + j;
|
|
|
|
EXPECT_TRUE(analyzer.ProveEQ(e3, e3).value() &&
|
|
analyzer.Prove(ir::EQ::Make(e3, e3)).value());
|
|
EXPECT_FALSE(analyzer.ProveEQ(e3, e4).value() &&
|
|
analyzer.Prove(ir::EQ::Make(e3, e4)).value());
|
|
EXPECT_TRUE(analyzer.ProveNE(e3, e4).value() &&
|
|
analyzer.Prove(ir::NE::Make(e3, e4)).value());
|
|
EXPECT_FALSE(analyzer.ProveNE(e4, e4).value() &&
|
|
analyzer.Prove(ir::NE::Make(e4, e4)).value());
|
|
|
|
EXPECT_TRUE(analyzer.ProveGE(e3, e4).value() &&
|
|
analyzer.Prove(e3 >= e4).value());
|
|
EXPECT_FALSE(analyzer.ProveGE(e4, e3).value() &&
|
|
analyzer.Prove(e4 >= e3).value());
|
|
EXPECT_TRUE(analyzer.ProveLE(e4, e3).value() &&
|
|
analyzer.Prove(e4 <= e3).value());
|
|
EXPECT_FALSE(analyzer.ProveLE(e3, e4).value() &&
|
|
analyzer.Prove(e3 <= e4).value());
|
|
|
|
EXPECT_TRUE(analyzer.ProveGT(e3, e4).value() &&
|
|
analyzer.Prove(e3 > e4).value());
|
|
EXPECT_FALSE(analyzer.ProveGT(e4, e3).value() &&
|
|
analyzer.Prove(e4 > e3).value());
|
|
EXPECT_TRUE(analyzer.ProveLT(e4, e3).value() &&
|
|
analyzer.Prove(e4 < e3).value());
|
|
EXPECT_FALSE(analyzer.ProveLT(e3, e4).value() &&
|
|
analyzer.Prove(e3 < e4).value());
|
|
}
|
|
|
|
TEST_F(TestSymbolicExprAnalyzer, Divisible) {
|
|
auto x = ir::Var(ir::Expr(1), ir::Expr(7), "x");
|
|
auto y = ir::Var(ir::Expr(1), ir::Expr(15), "y");
|
|
auto S = ir::Var(ir::Expr(16), ir::Expr(256), "S");
|
|
|
|
cas_intervals_t divisible_var_intervals = {
|
|
{"x", CasInterval(x->lower_bound, x->upper_bound - ir::Expr(1))},
|
|
{"y", CasInterval(y->lower_bound, y->upper_bound - ir::Expr(1))},
|
|
{"S", CasInterval(S->lower_bound, S->upper_bound - ir::Expr(1))},
|
|
};
|
|
SymbolicExprAnalyzer divisible_analyzer{divisible_var_intervals};
|
|
|
|
// case 1
|
|
ir::Expr e1 = 4 * x + 2 * y * x;
|
|
ir::Expr e2 = x;
|
|
ir::Expr e3 = y;
|
|
|
|
EXPECT_TRUE(divisible_analyzer.ProveDivisible(e1, e2).value_or(false));
|
|
EXPECT_FALSE(divisible_analyzer.ProveDivisible(e1, e3).value_or(false));
|
|
|
|
// case 2
|
|
ir::Expr e4 = y + y * x + 4 * y - x * y;
|
|
|
|
EXPECT_TRUE(divisible_analyzer.ProveDivisible(e4, e3).value_or(false));
|
|
EXPECT_FALSE(divisible_analyzer.ProveDivisible(e4, e2).value_or(false));
|
|
|
|
// case 3
|
|
ir::Expr e5 = x / y + x + y;
|
|
|
|
EXPECT_FALSE(divisible_analyzer.ProveDivisible(e5, e3).value_or(false));
|
|
EXPECT_FALSE(divisible_analyzer.ProveDivisible(e5, e2).value_or(false));
|
|
|
|
// case 4
|
|
ir::Expr e6 = S * x / 4 + x * y;
|
|
|
|
EXPECT_FALSE(divisible_analyzer.ProveDivisible(e6, e2).value_or(false));
|
|
EXPECT_FALSE(divisible_analyzer.ProveDivisible(e6, e3).value_or(false));
|
|
|
|
ir::Expr e7 = 16 * x / 4 + x * y;
|
|
|
|
EXPECT_TRUE(divisible_analyzer.ProveDivisible(e7, e2).value_or(false));
|
|
EXPECT_FALSE(divisible_analyzer.ProveDivisible(e7, e3).value_or(false));
|
|
}
|
|
|
|
TEST(SingleIntervalIntSet, constant) {
|
|
SingleIntervalIntSet empty_set(ir::Expr(0), ir::Expr(-1));
|
|
SingleIntervalIntSet all_set(SymbolicExprLimit::negative_inf,
|
|
SymbolicExprLimit::positive_inf);
|
|
SingleIntervalIntSet single_point(ir::Expr(0), ir::Expr(0));
|
|
SingleIntervalIntSet interval_0_2_set(ir::Expr(0), ir::Expr(2));
|
|
SingleIntervalIntSet interval_0_4_set(ir::Expr(0), ir::Expr(4));
|
|
SingleIntervalIntSet interval_2_6_set(ir::Expr(2), ir::Expr(6));
|
|
SingleIntervalIntSet interval_8_9_set(ir::Expr(8), ir::Expr(9));
|
|
|
|
EXPECT_TRUE(empty_set.ProveEmpty().value());
|
|
EXPECT_FALSE(empty_set.ProveAll().value());
|
|
EXPECT_FALSE(all_set.ProveEmpty().value());
|
|
EXPECT_TRUE(all_set.ProveAll().value());
|
|
EXPECT_TRUE(single_point.ProvePoint().value());
|
|
EXPECT_FALSE(interval_0_2_set.ProvePoint().value());
|
|
EXPECT_TRUE(interval_0_2_set.ProveSubSet(interval_0_4_set).value());
|
|
EXPECT_FALSE(interval_0_4_set.ProveSubSet(interval_0_2_set).value());
|
|
EXPECT_FALSE(interval_0_2_set.ProveSuperSet(interval_0_4_set).value());
|
|
EXPECT_TRUE(interval_0_4_set.ProveSuperSet(interval_0_2_set).value());
|
|
|
|
EXPECT_TRUE(ProveEQ(interval_0_2_set, interval_0_2_set).value());
|
|
EXPECT_FALSE(ProveEQ(interval_0_2_set, interval_0_4_set).value());
|
|
|
|
SingleIntervalIntSet union_0_6_set =
|
|
ProvedUnion(interval_0_2_set, interval_2_6_set).value();
|
|
EXPECT_EQ(union_0_6_set.Min(), ir::Expr(0));
|
|
EXPECT_EQ(union_0_6_set.Max(), ir::Expr(6));
|
|
union_0_6_set = ProvedUnion(interval_2_6_set, interval_0_2_set).value();
|
|
EXPECT_EQ(union_0_6_set.Min(), ir::Expr(0));
|
|
EXPECT_EQ(union_0_6_set.Max(), ir::Expr(6));
|
|
SingleIntervalIntSet union_0_4_set =
|
|
ProvedUnion(interval_0_2_set, interval_0_4_set).value();
|
|
EXPECT_EQ(union_0_4_set.Min(), ir::Expr(0));
|
|
EXPECT_EQ(union_0_4_set.Max(), ir::Expr(4));
|
|
union_0_4_set = ProvedUnion(interval_0_4_set, interval_0_2_set).value();
|
|
EXPECT_EQ(union_0_4_set.Min(), ir::Expr(0));
|
|
EXPECT_EQ(union_0_4_set.Max(), ir::Expr(4));
|
|
SingleIntervalIntSet union_0_9_set =
|
|
ProvedUnion(interval_0_4_set, interval_8_9_set).value();
|
|
EXPECT_EQ(union_0_9_set.Min(), ir::Expr(0));
|
|
EXPECT_EQ(union_0_9_set.Max(), ir::Expr(9));
|
|
union_0_9_set = ProvedUnion(interval_8_9_set, interval_0_4_set).value();
|
|
EXPECT_EQ(union_0_9_set.Min(), ir::Expr(0));
|
|
EXPECT_EQ(union_0_9_set.Max(), ir::Expr(9));
|
|
|
|
SingleIntervalIntSet intersect_0_2_set =
|
|
ProvedIntersect(interval_0_2_set, interval_0_4_set).value();
|
|
EXPECT_EQ(intersect_0_2_set.Min(), ir::Expr(0));
|
|
EXPECT_EQ(intersect_0_2_set.Max(), ir::Expr(2));
|
|
intersect_0_2_set =
|
|
ProvedIntersect(interval_0_4_set, interval_0_2_set).value();
|
|
EXPECT_EQ(intersect_0_2_set.Min(), ir::Expr(0));
|
|
EXPECT_EQ(intersect_0_2_set.Max(), ir::Expr(2));
|
|
SingleIntervalIntSet intersect_2_2_set =
|
|
ProvedIntersect(interval_0_2_set, interval_2_6_set).value();
|
|
EXPECT_EQ(intersect_2_2_set.Min(), ir::Expr(2));
|
|
EXPECT_EQ(intersect_2_2_set.Max(), ir::Expr(2));
|
|
intersect_2_2_set =
|
|
ProvedIntersect(interval_2_6_set, interval_0_2_set).value();
|
|
EXPECT_EQ(intersect_2_2_set.Min(), ir::Expr(2));
|
|
EXPECT_EQ(intersect_2_2_set.Max(), ir::Expr(2));
|
|
SingleIntervalIntSet intersect_empty_set =
|
|
ProvedIntersect(interval_0_4_set, interval_8_9_set).value();
|
|
EXPECT_TRUE(intersect_empty_set.ProveEmpty().value());
|
|
intersect_empty_set =
|
|
ProvedIntersect(interval_8_9_set, interval_0_4_set).value();
|
|
EXPECT_TRUE(intersect_empty_set.ProveEmpty().value());
|
|
}
|
|
|
|
TEST(SingleIntervalIntSet, case_0) {
|
|
ir::Var S0 = ir::Var(ir::Expr(0), ir::Expr(7), "S0");
|
|
ir::Expr e1 = S0 * 16;
|
|
ir::Expr e2 = S0 * 16 + 7;
|
|
ir::Expr e3 = S0 * 16 + 15;
|
|
SingleIntervalIntSet empty_set(e2, e1);
|
|
SingleIntervalIntSet single_point(e3, e3);
|
|
SingleIntervalIntSet set_0(e1, e2);
|
|
SingleIntervalIntSet set_1(e1, e3);
|
|
|
|
EXPECT_TRUE(empty_set.ProveEmpty().value());
|
|
EXPECT_FALSE(empty_set.ProveAll().value());
|
|
EXPECT_TRUE(single_point.ProvePoint().value());
|
|
EXPECT_FALSE(set_0.ProvePoint().value());
|
|
EXPECT_TRUE(ProveEQ(set_0, set_0).value());
|
|
EXPECT_FALSE(ProveEQ(set_0, set_1).value());
|
|
|
|
EXPECT_TRUE(set_0.ProveSubSet(set_1).value());
|
|
EXPECT_FALSE(set_1.ProveSubSet(set_0).value());
|
|
EXPECT_FALSE(set_0.ProveSuperSet(set_1).value());
|
|
EXPECT_TRUE(set_1.ProveSuperSet(set_0).value());
|
|
|
|
EXPECT_TRUE(ProveEQ(ProvedUnion(set_0, set_1).value(), set_1).value());
|
|
EXPECT_TRUE(ProveEQ(ProvedIntersect(set_0, set_1).value(), set_0).value());
|
|
EXPECT_TRUE(ProveEQ(ProvedUnion(set_1, single_point).value(), set_1).value());
|
|
EXPECT_TRUE(
|
|
ProveEQ(ProvedIntersect(set_1, single_point).value(), single_point)
|
|
.value());
|
|
EXPECT_TRUE(ProveEQ(ProvedUnion(set_0, empty_set).value(), set_0).value());
|
|
EXPECT_TRUE(
|
|
ProveEQ(ProvedIntersect(set_0, empty_set).value(), empty_set).value());
|
|
EXPECT_TRUE(ProveEQ(ProvedUnion(set_0, single_point).value(), set_1).value());
|
|
EXPECT_TRUE(ProvedIntersect(set_0, single_point).value().ProveEmpty());
|
|
}
|
|
|
|
TEST(SingleIntervalIntSet, case_1) {
|
|
ir::Var S0 = ir::Var(ir::Expr(0), ir::Expr(7), "S0");
|
|
ir::Var S1 = ir::Var(ir::Expr(0), ir::Expr(15), "S1");
|
|
ir::Expr e1 = S0 * 16;
|
|
ir::Expr e2 = S0 * 16 + S1;
|
|
ir::Expr e3 = S0 * 16 + S1 * 2 + 1;
|
|
SingleIntervalIntSet empty_set(e3, e1);
|
|
SingleIntervalIntSet single_point(e3, e3);
|
|
SingleIntervalIntSet set_0(e1, e2);
|
|
SingleIntervalIntSet set_1(e1, e3);
|
|
|
|
EXPECT_TRUE(empty_set.ProveEmpty().value());
|
|
EXPECT_FALSE(empty_set.ProveAll().value());
|
|
EXPECT_TRUE(single_point.ProvePoint().value());
|
|
EXPECT_FALSE(set_0.ProvePoint().has_value());
|
|
EXPECT_TRUE(ProveEQ(set_0, set_0).value());
|
|
EXPECT_FALSE(ProveEQ(set_0, set_1).value());
|
|
|
|
EXPECT_TRUE(set_0.ProveSubSet(set_1).value());
|
|
EXPECT_FALSE(set_1.ProveSubSet(set_0).value());
|
|
EXPECT_FALSE(set_0.ProveSuperSet(set_1).value());
|
|
EXPECT_TRUE(set_1.ProveSuperSet(set_0).value());
|
|
|
|
EXPECT_TRUE(ProveEQ(ProvedUnion(set_0, set_1).value(), set_1).value());
|
|
EXPECT_TRUE(ProveEQ(ProvedIntersect(set_0, set_1).value(), set_0).value());
|
|
EXPECT_TRUE(ProveEQ(ProvedUnion(set_1, single_point).value(), set_1).value());
|
|
EXPECT_TRUE(
|
|
ProveEQ(ProvedIntersect(set_1, single_point).value(), single_point)
|
|
.value());
|
|
EXPECT_TRUE(ProveEQ(ProvedUnion(set_0, empty_set).value(), set_0).value());
|
|
EXPECT_TRUE(
|
|
ProveEQ(ProvedIntersect(set_0, empty_set).value(), empty_set).value());
|
|
EXPECT_TRUE(ProveEQ(ProvedUnion(set_0, single_point).value(), set_1).value());
|
|
EXPECT_TRUE(
|
|
ProvedIntersect(set_0, single_point).value().ProveEmpty().value());
|
|
}
|
|
|
|
TEST(SingleIntervalIntSet, case_2) {
|
|
ir::Var S = ir::Var(ir::Expr(0), ir::Expr(1), "S"); // S ∈ [0, 1)
|
|
|
|
SingleIntervalIntSet set_0{S, S + Expr(1)}; // [0, 1]
|
|
SingleIntervalIntSet set_1{Expr(0), Expr(1)}; // [0, 1]
|
|
SingleIntervalIntSet set_2{Expr(0), Expr(2)}; // [0, 2]
|
|
|
|
EXPECT_TRUE(ProveEQ(set_0, set_1).value());
|
|
EXPECT_FALSE(ProveEQ(set_0, set_2).value());
|
|
EXPECT_TRUE(set_0.ProveSubSet(set_2).value());
|
|
EXPECT_TRUE(set_2.ProveSuperSet(set_0).value());
|
|
}
|
|
|
|
} // namespace common
|
|
} // namespace cinn
|