Files
paddlepaddle--paddle/paddle/cinn/common/integer_set.h
T
2026-07-13 12:40:42 +08:00

153 lines
6.1 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.
#pragma once
#include <optional>
#include "paddle/cinn/ir/ir.h"
#include "paddle/cinn/ir/ir_printer.h"
#include "paddle/cinn/optim/ir_simplify.h"
namespace cinn {
namespace common {
/**
* Interval of a _Var_.
*/
struct CasInterval {
template <typename T>
CasInterval(T l, T r) : l(l), r(r) {
PADDLE_ENFORCE_LE(l,
r,
::common::errors::InvalidArgument(
"left should not be larger than right"));
}
/**
* @brief When iterator's upper_bound is an ir::Min of a constant value and a
* inconstant value, choose the constant value. When iterator's lower_bound is
* an ir::Max of a constant value and a inconstant value, choose the constant
* value. E.g: expr_l = max(x, 1) and expr_r = min(y,5): max(x, 1) <=
* iterator_i <= min(y,5)
*
* the bounds will be simplified to e_l = 1 and e_r = 5:
* 1 <= iterator_i <= 5
*/
CasInterval(ir::Expr expr_l, ir::Expr expr_r);
ir::Expr ReplaceMinToConstant(ir::Expr expr);
ir::Expr ReplaceMaxToConstant(ir::Expr expr);
int l, r;
// Note: not verify l <= r and (e_l, e_r) has higher priority than (l, r)
ir::Expr e_l, e_r;
friend std::ostream& operator<<(std::ostream& os, const CasInterval& i);
};
using cas_intervals_t = paddle::flat_hash_map<std::string, CasInterval>;
cas_intervals_t CollectVarIntervalsOfExprs(const std::vector<ir::Expr>& exprs,
bool is_lower_bound_zero = true);
// A naive implementation of Symbolic Expression Analyzer
class SymbolicExprAnalyzer {
public:
explicit SymbolicExprAnalyzer(const cas_intervals_t& var_intervals)
: var_intervals_(var_intervals) {}
SymbolicExprAnalyzer(const SymbolicExprAnalyzer&) = default;
SymbolicExprAnalyzer(SymbolicExprAnalyzer&&) = default;
SymbolicExprAnalyzer& operator=(const SymbolicExprAnalyzer&) = delete;
SymbolicExprAnalyzer& operator=(SymbolicExprAnalyzer&&) = delete;
// Try to prove the relationship of 2 symbolic expressions,
// with the return value being optional.
// If proven, return true. If falsified, return false.
// If unable to prove or falsify, return nullopt.
std::optional<bool> Prove(const ir::Expr& condition) const;
std::optional<bool> ProveEQ(const ir::Expr& lhs, const ir::Expr& rhs) const;
std::optional<bool> ProveNE(const ir::Expr& lhs, const ir::Expr& rhs) const;
std::optional<bool> ProveGE(const ir::Expr& lhs, const ir::Expr& rhs) const;
std::optional<bool> ProveLE(const ir::Expr& lhs, const ir::Expr& rhs) const;
std::optional<bool> ProveGT(const ir::Expr& lhs, const ir::Expr& rhs) const;
std::optional<bool> ProveLT(const ir::Expr& lhs, const ir::Expr& rhs) const;
std::optional<bool> ProveDivisible(const ir::Expr& lhs,
const ir::Expr& rhs) const;
ir::Expr LowerBound(const ir::Expr& expr) const;
ir::Expr UpperBound(const ir::Expr& expr) const;
private:
const cas_intervals_t& var_intervals_;
};
// A helper struct to represent the positive infinity and negative infinity
struct SymbolicExprLimit {
static ir::Expr positive_inf;
static ir::Expr negative_inf;
};
// The set consisting of all integers in the interval from min to max
class SingleIntervalIntSet {
public:
explicit SingleIntervalIntSet(
const ir::Expr& min = SymbolicExprLimit::positive_inf,
const ir::Expr& max = SymbolicExprLimit::negative_inf,
cas_intervals_t var_intervals = {});
SingleIntervalIntSet(const SingleIntervalIntSet& set) = default;
SingleIntervalIntSet(SingleIntervalIntSet&& set) = default;
SingleIntervalIntSet& operator=(const SingleIntervalIntSet& set) = default;
SingleIntervalIntSet& operator=(SingleIntervalIntSet&& set) = default;
// Try to prove or construct the relationship between two symbolic integer
// sets, if unable to determine or construct, return nullopt.
std::optional<bool> ProveEmpty() const;
std::optional<bool> ProveAll() const;
std::optional<bool> ProvePoint() const;
std::optional<bool> ProveSubSet(const SingleIntervalIntSet& other) const;
std::optional<bool> ProveSuperSet(const SingleIntervalIntSet& other) const;
friend std::optional<bool> ProveEQ(const SingleIntervalIntSet& lhs,
const SingleIntervalIntSet& rhs);
friend std::optional<SingleIntervalIntSet> ProvedUnion(
const SingleIntervalIntSet& a, const SingleIntervalIntSet& b);
friend std::optional<SingleIntervalIntSet> ProvedIntersect(
const SingleIntervalIntSet& a, const SingleIntervalIntSet& b);
friend cas_intervals_t MergeVarIntervals(const SingleIntervalIntSet& a,
const SingleIntervalIntSet& b);
inline ir::Expr Min() const { return min_; }
inline ir::Expr Max() const { return max_; }
private:
ir::Expr min_ = SymbolicExprLimit::positive_inf;
ir::Expr max_ = SymbolicExprLimit::negative_inf;
cas_intervals_t var_intervals_;
};
std::optional<bool> ProveEQ(const SingleIntervalIntSet& lhs,
const SingleIntervalIntSet& rhs);
std::optional<SingleIntervalIntSet> ProvedUnion(const SingleIntervalIntSet& a,
const SingleIntervalIntSet& b);
std::optional<SingleIntervalIntSet> ProvedIntersect(
const SingleIntervalIntSet& a, const SingleIntervalIntSet& b);
cas_intervals_t MergeVarIntervals(const SingleIntervalIntSet& a,
const SingleIntervalIntSet& b);
ir::Expr EnhancedSimplifyModExpr(
ir::Expr e,
const paddle::flat_hash_map<std::string, CasInterval>& var_intervals);
} // namespace common
} // namespace cinn