24#ifndef TVM_TOPI_REDUCTION_H_
25#define TVM_TOPI_REDUCTION_H_
46 ffi::Array<PrimExpr> init,
Location loc)>;
50 ffi::Array<PrimExpr> exprs,
const ffi::Array<IterVar>& axis,
PrimExpr* condition)>;
64inline std::vector<int>
GetRealAxis(
int ndim,
const ffi::Optional<ffi::Array<int64_t>>& axis) {
65 std::vector<int> real_axis;
66 if (!axis.has_value()) {
67 for (
int i = 0; i < ndim; ++i) {
68 real_axis.push_back(i);
72 for (int64_t elem : axis.value()) {
77 TVM_FFI_ICHECK_LT(val, ndim) <<
" exceeds the maximum dimension " << ndim;
78 TVM_FFI_ICHECK_GE(val, 0);
79 real_axis.push_back(
static_cast<int>(val));
81 std::sort(real_axis.begin(), real_axis.end());
82 real_axis.resize(std::unique(real_axis.begin(), real_axis.end()) - real_axis.begin());
89 ffi::Array<IterVar> reduce_axes;
90 for (
auto i : real_axis) {
91 std::string name =
"k" + std::to_string(i);
99 const Tensor& data,
bool keepdims,
101 auto ndim = data->shape.size();
102 ffi::Array<PrimExpr> target_shape;
104 for (
size_t i = 0; i < ndim; ++i) {
105 if (std::find(real_axis.begin(), real_axis.end(), i) != real_axis.end()) {
107 target_shape.push_back(1);
109 target_shape.push_back(data->shape[i]);
113 for (
size_t i = 0; i < ndim; ++i) {
114 if (std::find(real_axis.begin(), real_axis.end(), i) == real_axis.end()) {
116 target_shape.push_back(data->shape[i]);
120 if (target_shape.size() == 0 && atleast1d) {
121 target_shape.push_back(1);
140 const ffi::Array<PrimExpr>& target_shape,
141 const std::vector<int>& reduce_axes,
144 auto compute = [&](
const ffi::Array<PrimVar>& indices) {
145 ffi::Array<PrimExpr> eval_range;
146 ffi::Array<PrimVar> eval_indices;
150 for (
size_t i = 0; i < data->shape.size(); ++i) {
151 bool squeeze_i = std::find(squeeze_axes.begin(), squeeze_axes.end(), i) != squeeze_axes.end();
152 if (std::find(reduce_axes.begin(), reduce_axes.end(), i) != reduce_axes.end()) {
154 eval_range.push_back(r_axes[red_counter]);
155 eval_indices.push_back(r_axes[red_counter]->
var);
157 arg_counter += !squeeze_i;
160 eval_range.push_back(indices[arg_counter]);
164 return func(data(eval_range), r_axes, {}, loc);
184 FReduce func,
bool keepdims,
bool atleast1d) {
185 auto ndim = data->shape.size();
190 auto real_axis =
GetRealAxis(
static_cast<int>(ndim), axis);
192 return DoCommReduce(data, func, target_shape, real_axis,
193 keepdims ? std::vector<int>() : real_axis);
211 auto ndim = data->shape.size();
212 TVM_FFI_ICHECK_NE(ndim, 0) <<
"Cannot reduce a 0 dim Tensor";
213 auto real_axis =
GetRealAxis(
static_cast<int>(ndim), axis);
217 auto compute = [ndim, keepdims, &real_axis, &reduce_axes, &func,
218 &data](
const ffi::Array<PrimVar>& indices) {
219 ffi::Array<PrimExpr> eval_range;
220 ffi::Array<PrimExpr> eval_indices;
224 for (
size_t i = 0; i < ndim; ++i) {
225 if (std::find(real_axis.begin(), real_axis.end(), i) != real_axis.end()) {
227 eval_range.push_back(reduce_axes[red_counter]);
228 eval_indices.push_back(reduce_axes[red_counter]->
var);
232 eval_range.push_back(indices[arg_counter]);
235 eval_range.push_back(indices[i]);
240 ffi::Array<PrimExpr> ravel_shape;
241 for (
auto i : real_axis) {
242 ravel_shape.push_back(data->shape[i]);
244 auto idx = detail::RavelIndex(eval_indices, ravel_shape);
245 return func({idx, data(eval_range)}, reduce_axes,
nullptr);
250 auto temp_idx = temp_idx_val[0];
251 auto temp_val = temp_idx_val[1];
253 target_shape, [&temp_idx](
const ffi::Array<PrimVar>& indices) {
return temp_idx(indices); },
259 std::function<ffi::Array<PrimExpr>(ffi::Array<PrimVar> lhs, ffi::Array<PrimVar> rhs)>;
262using FIdentity = std::function<ffi::Array<PrimExpr>(std::vector<PrimType> types)>;
274 std::string name =
"reduce") {
275 return [fcombine, fidentity, name](ffi::Array<PrimExpr> exprs,
const ffi::Array<IterVar>& axis,
277 ffi::Array<PrimVar> lhs, rhs;
278 ffi::Array<PrimVar> callback_lhs, callback_rhs;
279 std::vector<PrimType> dtypes;
281 for (
size_t i = 0; i < exprs.size(); ++i) {
283 dtypes.push_back(dtype);
284 PrimVar lhs_var(name +
"_lhs_" + std::to_string(i), dtype);
285 PrimVar rhs_var(name +
"_rhs_" + std::to_string(i), dtype);
286 lhs.push_back(lhs_var);
287 rhs.push_back(rhs_var);
288 callback_lhs.push_back(lhs_var);
289 callback_rhs.push_back(rhs_var);
292 auto result = fcombine(callback_lhs, callback_rhs);
293 auto id_elem = fidentity(dtypes);
294 auto cond = condition !=
nullptr ? *condition :
IntImm::Bool(
true);
297 ffi::Array<PrimExpr> outputs;
298 for (
size_t i = 0; i < exprs.size(); ++i) {
299 outputs.push_back(
tvm::te::Reduce(combiner, exprs, axis, cond,
static_cast<int>(i), {}));
308 return tvm::min(source, axis, init, loc);
314 return tvm::max(source, axis, init, loc);
337 bool keepdims =
false,
bool atleast1d =
false) {
339 if (data->dtype.code() == DLDataTypeCode::kDLBool) {
347 const auto& ishape = data->shape;
348 const auto& oshape = target_shape;
349 int isize = data->shape.size();
350 int osize = target_shape.size();
352 TVM_FFI_ICHECK_GE(isize, osize)
353 <<
"Invalid collapse: input dimensionality smaller than output dimensionality.\ninput shape: "
354 << data->shape <<
"\nvs\noutput shape: " << target_shape;
356 std::vector<int> reduce_axes;
357 std::vector<int> squeeze_axes;
360 for (
int i_ax = isize - 1, o_ax = osize - 1; i_ax >= 0; --i_ax) {
361 if (o_ax >= 0 && topi::detail::EqualCheck(ishape[i_ax], oshape[o_ax])) {
365 reduce_axes.push_back(i_ax);
367 squeeze_axes.push_back(i_ax);
368 }
else if (topi::detail::EqualCheck(one, oshape[o_ax])) {
373 if (reduce_axes.size() == 0)
return topi::identity(data,
"tensor", kCommReduce);
375 std::reverse(reduce_axes.begin(), reduce_axes.end());
376 std::reverse(squeeze_axes.begin(), squeeze_axes.end());
395 bool keepdims =
false,
bool atleast1d =
false) {
414 bool keepdims =
false,
bool atleast1d =
false) {
433 bool keepdims =
false,
bool atleast1d =
false) {
452 bool keepdims =
false,
bool atleast1d =
false) {
458 auto fcombine = [=](ffi::Array<PrimVar> lhs, ffi::Array<PrimVar> rhs) {
459 ffi::Array<PrimExpr> result;
468 auto is_smaller = lhs_val < rhs_val;
469 auto is_same = lhs_val == rhs_val;
474 PrimExpr proper_index = select_last_index ? lhs_idx > rhs_idx : lhs_idx < rhs_idx;
476 PrimExpr update_index = is_smaller || (is_same && proper_index);
481 auto fidentity = [&](std::vector<PrimType> types) {
482 ffi::Array<PrimExpr> result;
507 bool keepdims =
false,
bool atleast1d =
false,
508 bool select_last_index =
false) {
510 return CommReduceIdx(data, axis, reducer, keepdims, atleast1d);
515 auto fcombine = [=](ffi::Array<PrimVar> lhs, ffi::Array<PrimVar> rhs) {
516 ffi::Array<PrimExpr> result;
525 auto is_bigger = lhs_val > rhs_val;
526 auto is_same = lhs_val == rhs_val;
531 PrimExpr proper_index = select_last_index ? lhs_idx > rhs_idx : lhs_idx < rhs_idx;
533 PrimExpr update_index = is_bigger || (is_same && proper_index);
538 auto fidentity = [&](std::vector<PrimType> types) {
539 ffi::Array<PrimExpr> result;
563 bool keepdims =
false,
bool atleast1d =
false,
564 bool select_last_index =
false) {
566 return CommReduceIdx(data, axis, reducer, keepdims, atleast1d);
583 bool keepdims =
false,
bool atleast1d =
false) {
591 auto fcombine = [](ffi::Array<PrimVar> lhs, ffi::Array<PrimVar> rhs) {
592 ffi::Array<PrimExpr> result;
593 TVM_FFI_ICHECK_EQ(lhs.size(), rhs.size());
594 result.reserve(lhs.size());
595 for (
size_t i = 0; i < lhs.size(); ++i) {
596 result.push_back(lhs[i] + rhs[i]);
600 auto fidentity = [](std::vector<PrimType> types) {
601 ffi::Array<PrimExpr> result;
602 for (
size_t i = 0; i < types.size(); ++i) {
Broadcast op constructions.
static IntImm Bool(bool value, Location loc=UnknownLoc())
Construct a scalar boolean constant.
Definition expr.h:172
Non-nullable source-location metadata.
Definition location.h:91
Typed reference/view over any Expr whose ExprNode::ty is PrimType.
Definition base_expr.h:447
Definition base_expr.h:161
Checked scalar view over a VarNode.
Definition expr.h:742
Range container
Definition expr.h:1025
Reference to the shared immutable unknown location.
Definition location.h:105
Managed reference to SelectNode.
Definition expr.h:712
Managed reference to CommReducerNode.
Definition operation.h:91
Managed reference to ReduceNode.
Definition operation.h:139
Tensor structure representing a possible input, or intermediate computation result.
Definition tensor.h:111
Utility functions for handling constants in TVM expressions.
Elementwise op constructions.
TVM_TIRX_DLL PrimExpr min_value(PrimType dtype, Location loc=UnknownLoc())
PrimExpr all(PrimExpr source, ffi::Array< s_tir::IterVar > axis, ffi::Array< PrimExpr > init={}, Location loc=UnknownLoc())
logical And of source expression over axis
PrimExpr prod(PrimExpr source, ffi::Array< s_tir::IterVar > axis, ffi::Array< PrimExpr > init={}, Location loc=UnknownLoc())
product of source expression over axis
TVM_TIRX_DLL PrimExpr max_value(PrimType dtype, Location loc=UnknownLoc())
PrimExpr sum(PrimExpr source, ffi::Array< s_tir::IterVar > axis, ffi::Array< PrimExpr > init={}, Location loc=UnknownLoc())
sum of source expression over axis
PrimExpr MakeConst(PrimType dtype, ValueType value, Location loc=UnknownLoc())
Make a const value with certain data type.
Definition op.h:553
PrimExpr any(PrimExpr source, ffi::Array< s_tir::IterVar > axis, ffi::Array< PrimExpr > init={}, Location loc=UnknownLoc())
logical Or of source expression over axis
Tensor expression language DSL.
Definition extracted_task.h:33
PrimVar var(std::string name_hint, PrimType t=PrimType::Int(32))
Construct a new Var expression.
IterVar reduce_axis(Range dom, std::string name="rv")
Create a new IterVar for reduction operations.
Tensor compute(ffi::Array< PrimExpr > shape, FCompute fcompute, std::string name="tensor", std::string tag="", ffi::Map< ffi::String, ffi::Any > attrs={})
Construct a new tensor by computing over shape, using the computation rule: result_tensor[axis] = fco...
Tensor collapse_sum(const Tensor &data, ffi::Array< PrimExpr > target_shape)
Definition reduction.h:346
ffi::Array< PrimExpr > MakeReduceTargetShape(const std::vector< int > &real_axis, const Tensor &data, bool keepdims, bool atleast1d)
Calculate the target shape for a reduce op.
Definition reduction.h:98
std::function< ffi::Array< PrimExpr >(ffi::Array< PrimVar > lhs, ffi::Array< PrimVar > rhs)> FCombine
A combiner function for a reduction.
Definition reduction.h:259
ffi::Array< IterVar > MakeReduceAxes(const std::vector< int > &real_axis, const Tensor &data)
Enumerate the axes for a reduce op.
Definition reduction.h:88
FCommReduce MakeTupleSumReducer()
Create communitive reducer summing over tuples.
Definition reduction.h:590
PrimExpr MinOp(PrimExpr source, ffi::Array< IterVar > axis, ffi::Array< PrimExpr > init={}, Location loc=UnknownLoc())
Wrap tvm::min to ensure we get the correct overload.
Definition reduction.h:306
std::vector< int > GetRealAxis(int ndim, const ffi::Optional< ffi::Array< int64_t > > &axis)
Convert a reduction axis which could be empty or have negative elements into a real axis with valid d...
Definition reduction.h:64
FCommReduce MakeCommReducer(FCombine fcombine, FIdentity fidentity, std::string name="reduce")
Create a commutative reducer for a reduction.
Definition reduction.h:273
std::function< ffi::Array< PrimExpr >(std::vector< PrimType > types)> FIdentity
An initializer function for a reduction.
Definition reduction.h:262
std::function< ffi::Array< PrimExpr >(ffi::Array< PrimExpr > exprs, const ffi::Array< IterVar > &axis, PrimExpr *condition)> FCommReduce
The operation to use for CommReduceIdx.
Definition reduction.h:50
Tensor sum(const Tensor &data, const ffi::Optional< ffi::Array< int64_t > > &axis, bool keepdims=false, bool atleast1d=false)
Creates an operation that sums array elements over a given axis.
Definition reduction.h:336
Tensor min(const Tensor &data, const ffi::Optional< ffi::Array< int64_t > > &axis, bool keepdims=false, bool atleast1d=false)
Creates an operation that finds the minimum of elements over a given axis.
Definition reduction.h:432
std::function< PrimExpr(PrimExpr source, const ffi::Array< IterVar > &axis, ffi::Array< PrimExpr > init, Location loc)> FReduce
The operation to use for CommReduce.
Definition reduction.h:46
FCommReduce MakeArgmaxReducer(bool select_last_index=false)
Definition reduction.h:513
Tensor DoCommReduce(const Tensor &data, FReduce func, const ffi::Array< PrimExpr > &target_shape, const std::vector< int > &reduce_axes, const std::vector< int > &squeeze_axes, Location loc=UnknownLoc())
Create a reduction operation.
Definition reduction.h:139
PrimExpr ProdOp(PrimExpr source, ffi::Array< IterVar > axis, ffi::Array< PrimExpr > init={}, Location loc=UnknownLoc())
Wrap tvm::prim::prod to ensure we get the correct overload.
Definition reduction.h:318
Tensor max(const Tensor &data, const ffi::Optional< ffi::Array< int64_t > > &axis, bool keepdims=false, bool atleast1d=false)
Creates an operation that finds the maximum of elements over a given axis.
Definition reduction.h:451
Tensor expand_dims(const Tensor &x, int axis, int num_newaxis=1, std::string name="T_expand_dims", std::string tag=kBroadcast)
Creates an operation to insert new dimensions of length 1.
Definition transform.h:155
Tensor prod(const Tensor &data, const ffi::Optional< ffi::Array< int64_t > > &axis, bool keepdims=false, bool atleast1d=false)
Creates product operation over given axis.
Definition reduction.h:582
Tensor any(const Tensor &data, const ffi::Optional< ffi::Array< int64_t > > &axis, bool keepdims=false, bool atleast1d=false)
Creates an operation that computes the logical OR of elements over a given axis.
Definition reduction.h:413
Tensor argmin(const Tensor &data, const ffi::Optional< ffi::Array< int64_t > > &axis, bool keepdims=false, bool atleast1d=false, bool select_last_index=false)
Creates an operation that finds the indices of the minimum values over a given axis.
Definition reduction.h:506
constexpr auto kCommReduceIdx
Definition tags.h:35
FCommReduce MakeArgminReducer(bool select_last_index=false)
Definition reduction.h:456
Tensor identity(const Tensor &x, std::string name="T_identity", std::string tag=kElementWise)
Creates an operation that returns identity of a given tensor.
Definition elemwise.h:154
Tensor CommReduceIdx(const Tensor &data, const ffi::Optional< ffi::Array< int64_t > > &axis, FCommReduce func, bool keepdims, bool atleast1d)
Create an index reduction operation.
Definition reduction.h:209
Tensor CommReduce(const Tensor &data, const ffi::Optional< ffi::Array< int64_t > > &axis, FReduce func, bool keepdims, bool atleast1d)
Create a reduction operation.
Definition reduction.h:183
PrimExpr MaxOp(PrimExpr source, ffi::Array< IterVar > axis, ffi::Array< PrimExpr > init={}, Location loc=UnknownLoc())
Wrap tvm::max to ensure we get the correct overload.
Definition reduction.h:312
Tensor argmax(const Tensor &data, const ffi::Optional< ffi::Array< int64_t > > &axis, bool keepdims=false, bool atleast1d=false, bool select_last_index=false)
Creates an operation that finds the indices of the maximum values over a given axis.
Definition reduction.h:562
Tensor all(const Tensor &data, const ffi::Optional< ffi::Array< int64_t > > &axis, bool keepdims=false, bool atleast1d=false)
Creates an operation that computes the logical AND of elements over a given axis.
Definition reduction.h:394
An object that builds and maintains block scope and StmtSref mapping for Dependence analysis.
Definition attr.h:23
TVM_TIRX_DLL PrimExpr max(PrimExpr a, PrimExpr b, Location loc=UnknownLoc())
take maximum of two values
TVM_TIRX_DLL PrimExpr min(PrimExpr a, PrimExpr b, Location loc=UnknownLoc())
take minimum of two values
Operation node can generate one or multiple Tensors.
Index ravel and unraval operations.