24#ifndef TVM_TOPI_TRANSFORM_H_
25#define TVM_TOPI_TRANSFORM_H_
46#include <unordered_set>
50#include "tvm/ffi/dtype.h"
56using namespace topi::detail;
76 ffi::Array<int64_t> strides, std::string name =
"T_sliding_window",
77 std::string tag =
"") {
78 TVM_FFI_ICHECK_GE(axis, 0);
79 auto _axis = size_t(axis);
80 TVM_FFI_ICHECK_LT(_axis, x->shape.size()) <<
"axis must be a valid dimension index of x.";
81 TVM_FFI_ICHECK_EQ(x->shape.size() - _axis, window_shape.size())
82 <<
"There must be a window shape for every dimension of x "
83 <<
"over which we are sliding the window.";
84 TVM_FFI_ICHECK_EQ(strides.size(), window_shape.size())
85 <<
"Windows and strides should be the same length.";
88 ffi::Array<PrimExpr> new_shape;
90 for (
size_t i = 0; i < _axis; ++i) {
91 new_shape.push_back(x->shape[i]);
96 for (
size_t i = 0; i < window_shape.size(); ++i) {
98 auto dim_len = x->shape[_axis + i];
104 new_shape.push_back(
floordiv(dim_len - (window_len - 1) + stride - 1, stride));
108 for (
size_t i = 0; i < window_shape.size(); ++i) {
112 TVM_FFI_ICHECK(new_shape.size() == _axis + 2 * window_shape.size());
116 [&](
const ffi::Array<PrimVar>& indices) {
118 ffi::Array<PrimExpr> idx;
121 for (
size_t i = 0; i < _axis; ++i) {
122 idx.push_back(indices[i]);
125 for (
size_t i = 0; i < window_shape.size(); ++i) {
127 auto window_idx = indices[_axis + i];
129 auto idx_within_window = indices[_axis + window_shape.size() + i];
133 idx.push_back(window_idx * stride + idx_within_window);
136 TVM_FFI_ICHECK(idx.size() == x->shape.size());
156 std::string name =
"T_expand_dims", std::string tag =
kBroadcast) {
157 int ndim =
static_cast<int>(x->shape.size());
158 TVM_FFI_ICHECK(-ndim - 1 <= axis && axis <= ndim)
159 <<
"expand_dims only accepts `axis` in [-data.ndim - 1, data.ndim]"
160 <<
", but got axis = " << axis <<
", and data.ndim = " << ndim;
161 TVM_FFI_ICHECK(num_newaxis >= 0) <<
"expand_dims only accepts `num_newaxis >= 0`"
162 <<
", but got num_newaxis = " << num_newaxis;
165 axis = ndim + axis + 1;
167 ffi::Array<PrimExpr> new_shape;
168 for (
size_t i = 0; i < static_cast<size_t>(axis); ++i) {
169 new_shape.push_back(x->shape[i]);
171 for (
size_t i = 0; i < static_cast<size_t>(num_newaxis); ++i) {
172 new_shape.push_back(1);
174 for (
size_t i = axis; i < x->shape.size(); ++i) {
175 new_shape.push_back(x->shape[i]);
180 [&](
const ffi::Array<PrimVar>& indices) {
181 ffi::Array<PrimExpr> idx;
182 for (
size_t i = 0; i < static_cast<size_t>(axis); ++i) {
183 idx.push_back(indices[i]);
185 for (
size_t i = axis + num_newaxis; i < indices.size(); ++i) {
186 idx.push_back(indices[i]);
205 std::string name =
"T_transpose", std::string tag =
kInjective) {
206 ffi::Array<int64_t> axes = opt_axes.value_or({});
207 if (axes.size() == 0) {
208 for (
int i =
static_cast<int>(x->shape.size()) - 1; i >= 0; --i) {
213 ffi::Array<PrimExpr> new_shape;
214 for (
size_t i = 0; i < axes.size(); ++i) {
215 int axis =
static_cast<int>(axes[i]);
218 new_axis =
static_cast<int>(x->shape.size()) + axis;
219 axes.Set(i, new_axis);
221 TVM_FFI_ICHECK((new_axis >= 0) && (new_axis <
static_cast<int>(x->shape.size())))
222 <<
"axis=" << axis <<
" is invalid for the " <<
static_cast<int>(x->shape.size())
223 <<
"-dimensional input tensor";
225 for (
size_t j = 0; j < axes.size(); ++j) {
227 TVM_FFI_ICHECK(new_axis !=
static_cast<int>(axes[j])) <<
"repeated axis in transpose";
230 new_shape.push_back(x->shape[new_axis]);
235 [&](
const ffi::Array<PrimVar>& indices) {
236 std::vector<PrimExpr> idx;
237 for (
size_t i = 0; i < axes.size(); ++i) {
240 for (
size_t i = 0; i < axes.size(); ++i) {
241 int axis =
static_cast<int>(axes[i]);
242 idx[axis] = indices[i];
264 int seq_axis = 1,
int batch_axis = 0,
265 std::string name =
"T_reverse_sequence",
267 size_t src_tensor_dim = x->shape.size();
268 int seq_axis_inp = seq_axis;
270 if (seq_lengths.has_value()) {
271 size_t seq_lengths_dim = seq_lengths.value()->shape.size();
272 int batch_axis_inp = batch_axis;
273 if (batch_axis < 0) {
274 batch_axis =
static_cast<int>(x->shape.size()) + batch_axis;
277 TVM_FFI_ICHECK(seq_lengths_dim == 1) <<
"seq_lengths should be 1D vector";
279 TVM_FFI_ICHECK(GetConstInt(seq_lengths.value()->shape[0]) == GetConstInt(x->shape[batch_axis]))
280 <<
"For reverse_sequnece seq_lengths size should match with dimension of batch axis"
281 <<
", but got dimension of batch_axis = " << GetConstInt(x->shape[batch_axis])
282 <<
", and seq_length size = " << GetConstInt(seq_lengths.value()->shape[0]);
284 TVM_FFI_ICHECK((0 <= batch_axis) && (batch_axis <
static_cast<int>(x->shape.size())))
285 <<
"batch_axis=" << batch_axis_inp <<
" is invalid for the "
286 <<
static_cast<int>(x->shape.size()) <<
"-dimensional input tensor";
290 seq_axis =
static_cast<int>(x->shape.size()) + seq_axis;
292 TVM_FFI_ICHECK((0 <= seq_axis) && (seq_axis <
static_cast<int>(x->shape.size())))
293 <<
"seq_axis=" << seq_axis_inp <<
" is invalid for the " <<
static_cast<int>(x->shape.size())
294 <<
"-dimensional input tensor";
296 auto func = [&](
const ffi::Array<PrimVar>& indices) {
297 ffi::Array<PrimExpr> real_indices;
298 for (
size_t i = 0; i < src_tensor_dim; ++i) {
299 if (i ==
static_cast<size_t>(seq_axis)) {
300 if (seq_lengths.has_value()) {
301 auto len = seq_lengths.value()(indices[batch_axis]);
303 len <= 1 || len <= indices[i], indices[i],
304 if_then_else(len > x->shape[i], x->shape[i] - 1 - indices[i], len - 1 - indices[i]));
305 real_indices.push_back(idx);
307 real_indices.push_back(x->shape[i] - 1 - indices[i]);
310 real_indices.push_back(indices[i]);
313 return x(real_indices);
316 return compute(x->shape, func, name, tag);
330 std::string name =
"T_reshape", std::string tag =
kInjective) {
331 auto x_shape = x->shape;
332 ffi::Array<PrimExpr> target_shape;
334 for (
const auto& ele : newshape) {
335 target_shape.push_back(ele);
339 if (is_empty_shape(target_shape) || is_empty_shape(x->shape)) {
347 [&](
const ffi::Array<PrimVar>& indices) {
348 ffi::Array<PrimExpr> prim_indices =
350 return x(UnravelIndex(RavelIndex(prim_indices, target_shape), x_shape));
369 auto x_shape = x->shape;
370 auto shape_shape =
shape->shape;
372 ffi::Array<PrimExpr> oshape;
373 oshape.push_back(shape_shape[0]);
374 if (x_shape.size() != 0) {
375 oshape.push_back(x_shape[0]);
378 auto func = [&](
const ffi::Array<PrimVar>& indices) {
380 std::vector<PrimExpr> indices_divs;
385 if (x_shape.size() != 0) {
386 index_val = x[indices[1]];
390 indices_divs.push_back(index_val);
391 for (
int v = GetConstInt(shape_shape[0]) - 1; v >= 0; --v) {
394 indices_divs.push_back(cur_val);
399 return compute(oshape, func, name, tag);
416 bool atleast1d =
false, std::string name =
"T_squeeze",
418 auto ndim = x->shape.size();
419 std::vector<int> axis_val;
420 if (!opt_axes.has_value()) {
421 for (
size_t i = 0; i < ndim; ++i) {
422 if (IsConstInt(x->shape[i]) && x->shape[i].as_or_throw<
IntImm>()->value == 1) {
423 axis_val.push_back(
static_cast<int>(i));
427 ffi::Array<int64_t> axis = *std::move(opt_axes);
428 for (
size_t i = 0; i < axis.size(); ++i) {
429 int64_t val = axis[i];
431 val +=
static_cast<int>(x->shape.size());
434 bool is_const = IsConstInt(x->shape[val]);
435 if ((is_const && x->shape[val].as_or_throw<
IntImm>()->value == 1) || !is_const) {
436 axis_val.push_back(val);
441 std::unordered_set<int> axis_set(axis_val.begin(), axis_val.end());
443 ffi::Array<PrimExpr> out_shape;
444 for (
size_t i = 0; i < ndim; ++i) {
445 if (axis_set.count(
static_cast<int>(i)) == 0) {
446 out_shape.push_back(x->shape[i]);
449 if (out_shape.size() == 0 && atleast1d) {
450 out_shape.push_back(1);
455 [&](
const ffi::Array<PrimVar>& indices) {
456 ffi::Array<PrimExpr> real_indices;
458 for (
size_t i = 0; i < ndim; ++i) {
459 if (axis_set.count(
static_cast<int>(i)) == 0) {
460 real_indices.push_back(indices[i - flag]);
462 real_indices.push_back(0);
466 return x(real_indices);
482 std::string name =
"T_concat", std::string tag =
kInjective) {
483 int ndim =
static_cast<int>(inputs[0]->shape.size());
484 TVM_FFI_ICHECK(-ndim <= axis && axis < ndim)
485 <<
"concatenate only accepts `axis` in [-ndim, ndim)"
486 <<
", but got axis = " << axis <<
", and ndim = " << ndim;
490 TVM_FFI_ICHECK_LT(axis, inputs[0]->
shape.size()) <<
"axis out of bounds";
492 ffi::Array<PrimExpr> axis_sizes;
493 for (
auto t : inputs) {
494 axis_sizes.push_back(t->shape[axis]);
498 for (
size_t i = 1; i < axis_sizes.size(); ++i) {
499 join_size += axis_sizes[i];
501 join_size = analyzer->Simplify(join_size);
502 ffi::Array<PrimExpr> out_shape;
503 for (
size_t i = 0; i < inputs[0]->shape.size(); ++i) {
504 out_shape.push_back(i ==
static_cast<size_t>(axis) ? join_size : inputs[0]->shape[i]);
509 [&](
const ffi::Array<PrimVar>& indices) {
510 auto ret = inputs[0](indices);
512 for (
size_t i = 0; i < inputs.size() - 1; ++i) {
513 ind -= axis_sizes[i];
515 ffi::Array<PrimExpr> idx;
516 for (
size_t i = 0; i < static_cast<size_t>(axis); ++i) {
517 idx.push_back(indices[i]);
520 for (
size_t i = axis + 1; i < indices.size(); ++i) {
521 idx.push_back(indices[i]);
541inline Tensor stack(
const ffi::Array<Tensor>& inputs,
int axis = 0, std::string name =
"T_stack",
543 int ndim =
static_cast<int>(inputs[0]->shape.size());
544 TVM_FFI_ICHECK(-ndim - 1 <= axis && axis <= ndim)
545 <<
"stack only accepts `axis` in [-ndim, ndim)"
546 <<
", but got axis = " << axis <<
", and ndim = " << ndim;
550 TVM_FFI_ICHECK_LT(axis, inputs[0]->
shape.size() + 1) <<
"axis out of bounds";
552 const int stack_size =
static_cast<int>(inputs.size());
553 ffi::Array<PrimExpr> out_shape;
554 for (
size_t i = 0; i < static_cast<size_t>(axis); ++i) out_shape.push_back(inputs[0]->shape[i]);
555 out_shape.push_back(stack_size);
556 for (
size_t i =
static_cast<size_t>(axis); i < static_cast<size_t>(ndim); ++i)
557 out_shape.push_back(inputs[0]->shape[i]);
561 [&](
const ffi::Array<PrimVar>& indices) {
562 ffi::Array<PrimExpr> idx;
563 for (
size_t i = 0; i < indices.size(); ++i)
564 if (i !=
static_cast<size_t>(axis)) idx.push_back(indices[i]);
565 auto ind = indices[axis];
566 auto ret = inputs[0](idx);
567 for (
int i = 0; i < static_cast<int>(inputs.size() - 1); ++i) {
588 int axis, std::string name =
"T_split",
591 axis +=
static_cast<int>(x->shape.size());
593 TVM_FFI_ICHECK_LT(axis, x->shape.size()) <<
"axis out of bounds";
595 auto src_axis_size = x->shape[axis];
596 std::vector<PrimExpr> begin_ids;
597 begin_ids.push_back(0);
599 for (
auto idx : split_indices) {
601 auto back_node = begin_ids.back().as<
IntImmNode>();
602 if (idx_node && back_node) {
603 TVM_FFI_ICHECK_GT(idx_node->value, back_node->
value) <<
"split_indices must be sorted";
605 begin_ids.push_back(idx);
608 ffi::Array<ffi::Array<PrimExpr>> out_shapes;
609 for (
size_t i = 0; i < begin_ids.size(); ++i) {
611 (i == begin_ids.size() - 1 ? src_axis_size : begin_ids[i + 1]) - begin_ids[i];
613 ffi::Array<PrimExpr>
shape;
614 for (
size_t i = 0; i < static_cast<size_t>(axis); ++i) {
615 shape.push_back(x->shape[i]);
617 shape.push_back(out_axis_size);
618 for (
size_t i = axis + 1; i < x->shape.size(); ++i) {
619 shape.push_back(x->shape[i]);
622 out_shapes.push_back(
shape);
625 ffi::Array<Tensor> result;
626 for (
size_t i = 0; i < begin_ids.size(); ++i) {
629 [&](
const ffi::Array<PrimVar>& indices) {
630 auto begin = begin_ids[i];
631 ffi::Array<PrimExpr> real_indices;
632 for (
size_t j = 0; j < static_cast<size_t>(axis); ++j) {
633 real_indices.push_back(indices[j]);
635 real_indices.push_back(indices[axis] + begin);
636 for (
size_t j = axis + 1; j < indices.size(); ++j) {
637 real_indices.push_back(indices[j]);
640 return x(real_indices);
649 if (index.same_as(extent)) {
664 int64_t begin_range = stride < 0 ? -1 : 0;
665 int64_t end_range = stride < 0 ? extent - 1 : extent;
669 return std::min(std::max(index, begin_range), end_range);
683 bool assume_inbound =
true) {
684 if (assume_inbound) {
685 return ceildiv(end - begin, stride);
687 begin = CanonicalizeIndex(begin, extent, stride);
688 end = CanonicalizeIndex(end, extent, stride);
710 const te::Tensor& x,
const ffi::Array<PrimExpr>& begin,
const ffi::Array<PrimExpr>& end,
711 const ffi::Array<PrimExpr>& strides,
const ffi::Array<int64_t>& axes,
712 bool assume_inbound =
true, std::string name =
"T_dynamic_strided_slice_with_axes",
714 const size_t src_tensor_dim = x->shape.size();
715 TVM_FFI_ICHECK_EQ(begin.size(), end.size());
716 TVM_FFI_ICHECK_EQ(begin.size(), strides.size());
717 TVM_FFI_ICHECK_EQ(begin.size(), axes.size());
718 TVM_FFI_ICHECK_LE(begin.size(), src_tensor_dim);
720 for (
const auto& axis_imm : axes) {
721 int axis =
static_cast<int>(axis_imm);
722 TVM_FFI_ICHECK_LT(axis, src_tensor_dim);
727 ffi::Array<PrimExpr> out_shape = x->shape;
728 for (
size_t i = 0; i < begin.size(); i++) {
729 int axis =
static_cast<int>(axes[i]);
730 PrimExpr new_shape = analyzer->Simplify(
731 GetLength(begin[i], end[i], strides[i], out_shape[axis], assume_inbound));
732 out_shape.Set(axis, new_shape);
737 [&](
const ffi::Array<tvm::PrimVar>& indices) {
738 ffi::Array<PrimExpr> real_indices =
741 for (
size_t i = 0; i < begin.size(); i++) {
742 int axis =
static_cast<int>(axes[i]);
744 if (!assume_inbound) {
745 begin_index = CanonicalizeIndex(begin_index, x->shape[axis], strides[i]);
747 PrimExpr new_index = indices[axis] * strides[i] + begin_index;
748 real_indices.Set(axis, new_index);
751 return x(real_indices);
771 const ffi::Array<PrimExpr>& end,
772 const ffi::Array<PrimExpr>& strides,
bool assume_inbound =
true,
773 std::string name =
"T_dynamic_strided_slice",
775 const size_t src_tensor_dim = x->shape.size();
776 TVM_FFI_ICHECK_LE(begin.size(), src_tensor_dim);
777 TVM_FFI_ICHECK_LE(end.size(), src_tensor_dim);
778 TVM_FFI_ICHECK_LE(strides.size(), src_tensor_dim);
779 TVM_FFI_ICHECK_EQ(begin.size(), end.size());
780 TVM_FFI_ICHECK_EQ(begin.size(), strides.size());
782 const size_t num_slice_axes = begin.size();
783 ffi::Array<PrimExpr> out_shape;
786 for (
size_t i = 0; i < num_slice_axes; ++i) {
790 analyzer->Simplify(
GetLength(begin[i], end[i], strides[i], x->shape[i], assume_inbound)));
796 for (
size_t i = num_slice_axes; i < src_tensor_dim; ++i) {
797 out_shape.push_back(x->shape[i]);
802 [&](
const ffi::Array<tvm::PrimVar>& indices) {
803 ffi::Array<PrimExpr> real_indices;
804 for (
size_t i = 0; i < num_slice_axes; ++i) {
806 if (!assume_inbound) {
807 begin_index = CanonicalizeIndex(begin[i], x->shape[i], strides[i]);
809 real_indices.push_back(indices[i] * strides[i] + begin_index);
812 for (
size_t i = num_slice_axes; i < src_tensor_dim; ++i) {
813 real_indices.push_back(indices[i]);
815 return x(real_indices);
836 bool assume_inbound =
true,
837 std::string name =
"T_strided_slice_dynamic",
839 PrimType index_ty = begin->shape[0].ty();
840 const int64_t num_dynamic_axes =
static_cast<int64_t
>(begin->shape[0].as<
IntImmNode>()->value);
841 TVM_FFI_ICHECK_EQ(end->shape[0].as<
IntImmNode>()->
value, num_dynamic_axes);
842 TVM_FFI_ICHECK_EQ(strides->shape[0].as<
IntImmNode>()->
value, num_dynamic_axes);
844 ffi::Array<PrimExpr> begin_expr, end_expr, strides_expr;
845 for (int64_t i = 0; i < num_dynamic_axes; ++i) {
846 auto ind =
IntImm(index_ty, i);
847 begin_expr.push_back(begin(ind));
848 end_expr.push_back(end(ind));
849 strides_expr.push_back(strides(ind));
868inline ffi::Array<PrimExpr> StridedSliceOutputShape(
const ffi::Array<PrimExpr>& ishape,
869 const ffi::Array<ffi::Optional<IntImm>>& begin,
870 const ffi::Array<ffi::Optional<IntImm>>& end,
871 const ffi::Array<IntImm>& strides,
872 const ffi::Array<int64_t>& axes,
873 const std::string& slice_mode) {
874 TVM_FFI_ICHECK(axes.size() == begin.size() && axes.size() == end.size() &&
875 axes.size() == strides.size());
876 std::vector<int64_t> begin_vec, end_vec, strides_vec;
877 std::tie(begin_vec, end_vec, strides_vec) = ConvertToVec(begin, end, strides, slice_mode);
879 (begin.size() > 0 && begin[0].has_value()) ? begin[0].value().ty() :
PrimType::Int(64);
880 auto begin_canonicalized =
881 StridedSliceCanonicalizeBegin(ishape, begin_vec, strides_vec, axes, index_ty, slice_mode);
882 return StridedSliceOutputShape(ishape, begin_vec, end_vec, strides_vec, axes, slice_mode,
883 begin_canonicalized,
true);
903 const Tensor& x,
const ffi::Array<ffi::Optional<IntImm>>& begin,
904 const ffi::Array<ffi::Optional<IntImm>>& end,
const ffi::Array<IntImm>& strides,
905 const ffi::Array<int64_t>& axes, std::string slice_mode =
"end",
906 std::string name =
"T_strided_slice_with_axes", std::string tag =
kInjective) {
907 const int64_t src_tensor_dim =
static_cast<int64_t
>(x->shape.size());
908 TVM_FFI_ICHECK(
static_cast<int64_t
>(axes.size()) <= src_tensor_dim);
909 TVM_FFI_ICHECK(axes.size() == begin.size() && axes.size() == end.size() &&
910 axes.size() == strides.size());
913 ffi::Array<int64_t> normalized_axes;
914 for (
size_t i = 0; i < axes.size(); ++i) {
915 int64_t axis = axes[i];
917 axis += src_tensor_dim;
919 TVM_FFI_ICHECK(axis >= 0 && axis < src_tensor_dim)
920 <<
"Axis " << axes[i] <<
" is out of bounds for tensor with " << src_tensor_dim
922 normalized_axes.push_back(axis);
925 std::vector<int64_t> begin_vec, end_vec, strides_vec;
926 std::tie(begin_vec, end_vec, strides_vec) = ConvertToVec(begin, end, strides, slice_mode);
929 (begin.size() > 0 && begin[0].has_value()) ? begin[0].value().ty() :
PrimType::Int(64);
930 auto begin_expr = StridedSliceCanonicalizeBegin(x->shape, begin_vec, strides_vec, normalized_axes,
931 index_ty, slice_mode);
932 auto out_shape = StridedSliceOutputShape(x->shape, begin_vec, end_vec, strides_vec,
933 normalized_axes, slice_mode, begin_expr);
937 [&](
const ffi::Array<PrimVar>& indices) {
938 ffi::Array<PrimExpr> real_indices;
939 for (
size_t i = 0; i < out_shape.size(); ++i) real_indices.push_back(indices[i]);
940 for (
size_t i = 0; i < normalized_axes.size(); ++i) {
941 int64_t ax = normalized_axes[i];
942 auto stride =
IntImm(strides[i]->ty.as_or_throw<
PrimType>(), strides_vec[i]);
943 PrimExpr ind = indices[ax] * stride + begin_expr[i];
944 real_indices.Set(ax, ind);
946 return x(real_indices);
966 const ffi::Array<ffi::Optional<IntImm>>& end,
967 const ffi::Array<IntImm>& strides, std::string slice_mode =
"end",
968 std::string name =
"T_strided_slice", std::string tag =
kInjective) {
970 size_t src_tensor_dim =
static_cast<size_t>(x->shape.size());
971 ffi::Array<int64_t> axes;
972 for (
size_t i = 0; i < src_tensor_dim; ++i) axes.push_back(i);
973 ffi::Array<ffi::Optional<IntImm>> begin_full(begin);
974 ffi::Array<ffi::Optional<IntImm>> end_full(end);
975 ffi::Array<IntImm> strides_full(strides);
978 (begin.size() > 0 && begin[0].has_value()) ? begin[0].value().ty() :
PrimType::Int(64);
981 const IntImm max_range = max_value(index_ty).as_or_throw<
IntImm>();
983 for (
size_t i = strides.size(); i < src_tensor_dim; ++i) {
984 strides_full.push_back(one);
986 for (
size_t i = begin.size(); i < src_tensor_dim; ++i) {
987 begin_full.push_back(strides_full[i]->value > 0 ? zero : max_range);
989 for (
size_t i = end.size(); i < src_tensor_dim; ++i) {
990 end_full.push_back(strides_full[i]->value < 0 ? zero : max_range);
1010 std::string name =
"T_split_sections",
1013 axis +=
static_cast<int>(x->shape.size());
1015 TVM_FFI_ICHECK_LT(axis, x->shape.size()) <<
"axis out of bounds";
1017 auto src_axis_size = x->shape[axis];
1019 TVM_FFI_ICHECK_GT(num_sections, 0) <<
"Slice count must be > 0";
1021 ffi::Array<PrimExpr> split_indices;
1022 auto seg_size =
indexdiv(src_axis_size + num_sections - 1, num_sections);
1023 for (
int i = 0; i < num_sections; ++i) {
1026 split_indices.push_back(seg_size * i);
1046 std::string mode =
"fast", std::string name =
"T_take",
1048 ffi::Array<PrimExpr> a_shape = a->shape;
1049 ffi::Array<PrimExpr> out_shape = indices->shape;
1051 for (
size_t i = 0; i < a_shape.size(); ++i) {
1052 a_size = a_size * a_shape[i];
1055 if (mode ==
"clip") {
1058 [&](
const ffi::Array<PrimVar>& out_index) {
1060 return a(UnravelIndex(idx, a_shape));
1063 }
else if (mode ==
"fast") {
1064 LOG(WARNING) <<
"Fast mode segfaults when there are out-of-bounds indices. "
1065 "Make sure input indices are in bound";
1068 [&](
const ffi::Array<PrimVar>& out_index) {
1069 return a(UnravelIndex(indices(out_index), a_shape));
1072 }
else if (mode ==
"nan") {
1075 [&](
const ffi::Array<PrimVar>& out_index) {
1077 indices(out_index) < 0 || indices(out_index) >= a_size,
1079 indices(out_index));
1080 return a(UnravelIndex(idx, a_shape));
1086 [&](
const ffi::Array<PrimVar>& out_index) {
1087 auto idx =
truncmod(
truncmod(indices(out_index), a_size) + a_size, a_size);
1088 return a(UnravelIndex(idx, a_shape));
1107 int axis, std::string name =
"T_sequence_mask",
1109 TVM_FFI_ICHECK(axis == 0 || axis == 1) <<
"axis must be either 0 or 1";
1110 TVM_FFI_ICHECK_EQ(valid_length->shape.size(), 1)
1111 <<
"valid_length must have ndim=1, i.e., (batch_size,).";
1112 auto length_dim = data->shape[axis];
1113 auto batch_dim = data->shape[1 - axis];
1114 ffi::Array<PrimExpr> out_shape = data->shape;
1117 [&](
const ffi::Array<PrimVar>& out_index) {
1118 ffi::Array<PrimExpr> len_index;
1119 auto tid = out_index[axis];
1120 auto bid = out_index[1 - axis];
1121 len_index.push_back(bid);
1146 int axis, std::string mode =
"fast", std::string name =
"T_take",
1149 axis +=
static_cast<int>(a->shape.size());
1151 TVM_FFI_ICHECK_GE(axis, 0) <<
"axis out of bounds";
1152 TVM_FFI_ICHECK_LT(axis, a->shape.size()) <<
"axis out of bounds";
1153 auto axis_dim = a->shape[axis];
1154 auto indices_shape = [&]() -> ffi::Array<PrimExpr> {
1155 if (
auto tensor = indices.as<
TensorNode>()) {
1156 return tensor->shape;
1162 int indices_len =
static_cast<int>(indices_shape.size());
1164 int batch_dims_ = batch_dims;
1165 if (batch_dims_ != 0) {
1166 TVM_FFI_ICHECK_GE(batch_dims_, -indices_len) <<
"batch_dims out of bounds";
1167 TVM_FFI_ICHECK_LE(batch_dims_, indices_len) <<
"batch_dims out of bounds";
1169 if (batch_dims_ < 0) {
1170 batch_dims_ = indices_len + batch_dims_;
1173 TVM_FFI_ICHECK_LT(batch_dims_, a->shape.size()) <<
"batch_dims out of bounds";
1174 TVM_FFI_ICHECK_LE(batch_dims_, axis) <<
"batch_dims must be less than or equal to axis";
1175 for (
int i = 0; i < batch_dims_; ++i) {
1176 auto addr1 = a->shape[i];
1177 auto addr2 = indices_shape[i];
1178 auto v1 =
static_cast<IntImm*
>(&addr1)->get()->value;
1179 auto v2 =
static_cast<IntImm*
>(&addr2)->get()->value;
1180 TVM_FFI_ICHECK_EQ(v1, v2) <<
"a.shape[" << i <<
"] should be equal to indices.shape[" << i
1188 ffi::Array<PrimExpr> out_shape;
1189 for (
int i = 0; i < batch_dims_; ++i) {
1190 out_shape.push_back(a->shape[i]);
1192 for (
int i = batch_dims_; i < axis; ++i) {
1193 out_shape.push_back(a->shape[i]);
1195 for (
int i = batch_dims_; i < indices_len; ++i) {
1196 out_shape.push_back(indices_shape[i]);
1198 for (
size_t i = axis + 1; i < a->shape.size(); ++i) {
1199 out_shape.push_back(a->shape[i]);
1202 auto get_index = [&](
const ffi::Array<PrimExpr>& indices_position) ->
PrimExpr {
1203 if (
auto tensor = indices.as<
Tensor>()) {
1204 return tensor.value()(indices_position);
1206 auto prim = indices.as<
PrimExpr>();
1207 TVM_FFI_ICHECK(prim.has_value()) <<
"Variant did not contain either allowed type";
1208 TVM_FFI_ICHECK_EQ(indices_position.size(), 0);
1209 return prim.value();
1212 if (mode ==
"clip") {
1213 if (batch_dims_ == 0) {
1216 [&](
const ffi::Array<PrimVar>& out_index) {
1217 ffi::Array<PrimExpr> indices_position;
1218 for (
size_t j = axis; j < static_cast<size_t>(axis + indices_len); ++j) {
1219 indices_position.push_back(out_index[j]);
1221 ffi::Array<PrimExpr> real_indices;
1222 for (
size_t j = 0; j < static_cast<size_t>(axis); ++j) {
1223 real_indices.push_back(out_index[j]);
1225 auto idx =
tvm::min(
tvm::max(0, get_index(indices_position)), axis_dim - 1);
1226 real_indices.push_back(idx);
1227 for (
size_t j = axis + indices_len; j < out_index.size(); ++j) {
1228 real_indices.push_back(out_index[j]);
1230 return a(real_indices);
1236 [&](
const ffi::Array<PrimVar>& out_index) {
1237 ffi::Array<PrimExpr> indices_position;
1238 for (
size_t j = 0; j < static_cast<size_t>(batch_dims_); ++j) {
1239 indices_position.push_back(out_index[j]);
1241 for (
size_t j = axis; j < static_cast<size_t>(axis + indices_len - batch_dims_); ++j) {
1242 indices_position.push_back(out_index[j]);
1244 ffi::Array<PrimExpr> real_indices;
1245 for (
size_t j = 0; j < static_cast<size_t>(axis); ++j) {
1246 real_indices.push_back(out_index[j]);
1248 auto idx =
tvm::min(
tvm::max(0, get_index(indices_position)), axis_dim - 1);
1249 real_indices.push_back(idx);
1250 for (
size_t j = axis + indices_len - batch_dims_; j < out_index.size(); ++j) {
1251 real_indices.push_back(out_index[j]);
1253 return a(real_indices);
1257 }
else if (mode ==
"fast") {
1258 LOG(WARNING) <<
"Fast mode segfaults when there are out-of-bounds indices. "
1259 "Make sure input indices are in bound";
1262 [&](
const ffi::Array<PrimVar>& out_index) {
1263 ffi::Array<PrimExpr> indices_position;
1264 for (
size_t j = axis; j < static_cast<size_t>(axis + indices_len); ++j) {
1265 indices_position.push_back(out_index[j]);
1267 ffi::Array<PrimExpr> real_indices;
1268 for (
size_t j = 0; j < static_cast<size_t>(axis); ++j) {
1269 real_indices.push_back(out_index[j]);
1271 real_indices.push_back(get_index(indices_position));
1272 for (
size_t j = axis + indices_len; j < out_index.size(); ++j) {
1273 real_indices.push_back(out_index[j]);
1275 return a(real_indices);
1278 }
else if (mode ==
"nan") {
1281 [&](
const ffi::Array<PrimVar>& out_index) {
1282 ffi::Array<PrimExpr> indices_position;
1283 for (
size_t j = axis; j < static_cast<size_t>(axis + indices_len); ++j) {
1284 indices_position.push_back(out_index[j]);
1286 ffi::Array<PrimExpr> real_indices;
1287 for (
size_t j = 0; j < static_cast<size_t>(axis); ++j) {
1288 real_indices.push_back(out_index[j]);
1290 PrimExpr idx = get_index(indices_position);
1291 real_indices.push_back(idx);
1292 for (
size_t j = axis + indices_len; j < out_index.size(); ++j) {
1293 real_indices.push_back(out_index[j]);
1295 PrimExpr in_bounds = idx >= 0 && idx < axis_dim;
1297 in_bounds, a(real_indices),
1304 [&](
const ffi::Array<PrimVar>& out_index) {
1305 ffi::Array<PrimExpr> indices_position;
1306 for (
size_t j = axis; j < static_cast<size_t>(axis + indices_len); ++j) {
1307 indices_position.push_back(out_index[j]);
1309 ffi::Array<PrimExpr> real_indices;
1310 for (
size_t j = 0; j < static_cast<size_t>(axis); ++j) {
1311 real_indices.push_back(out_index[j]);
1313 auto idx =
truncmod(
truncmod(get_index(indices_position), axis_dim) + axis_dim, axis_dim);
1314 real_indices.push_back(idx);
1315 for (
size_t j = axis + indices_len; j < out_index.size(); ++j) {
1316 real_indices.push_back(out_index[j]);
1318 return a(real_indices);
1336 std::string name =
"T_where", std::string tag =
kBroadcast) {
1337 TVM_FFI_ICHECK_EQ(x->dtype, y->dtype)
1338 <<
"x and y must have the same dtype: " << x->dtype <<
" vs " << y->dtype;
1339 auto get_out_shape = [&]() {
1340 auto bh1 = detail::BroadcastShape(x->shape, y->shape);
1341 ffi::Array<PrimExpr> common_shape1(bh1.common_shape.begin(), bh1.common_shape.end());
1342 auto bh2 = detail::BroadcastShape(condition->shape, common_shape1);
1343 ffi::Array<PrimExpr> common_shape2(bh2.common_shape.begin(), bh2.common_shape.end());
1344 return common_shape2;
1347 auto oshape = get_out_shape();
1349 auto c_bh = detail::BroadcastShape(condition->shape, oshape);
1350 auto x_bh = detail::BroadcastShape(x->shape, oshape);
1351 auto y_bh = detail::BroadcastShape(y->shape, oshape);
1353 auto select = [&](tvm::ffi::Array<tvm::PrimVar> ovars) {
1354 auto c = condition(InputIndexFromBroadcast(ovars, condition, c_bh.vars1, c_bh.all_vars));
1355 auto true_val = x(InputIndexFromBroadcast(ovars, x, x_bh.vars1, x_bh.all_vars));
1356 auto false_val = y(InputIndexFromBroadcast(ovars, y, y_bh.vars1, y_bh.all_vars));
1360 return compute(oshape, select, name, tag);
1377 int ndim =
static_cast<int>(x->shape.size());
1378 TVM_FFI_ICHECK(-ndim - 1 <= axis && axis <= ndim)
1379 <<
"repeat only accepts `axis` in [-data.ndim - 1, data.ndim]"
1380 <<
", but got axis = " << axis <<
", and data.ndim = " << ndim;
1381 TVM_FFI_ICHECK(repeats >= 1) <<
"repeat only accepts `repeats >= 1`"
1382 <<
", but got repeats = " << repeats;
1387 ffi::Array<PrimExpr> new_shape;
1388 for (
size_t i = 0; i < static_cast<size_t>(axis); ++i) {
1389 new_shape.push_back(x->shape[i]);
1391 new_shape.push_back(repeats * x->shape[axis]);
1392 for (
size_t i = axis + 1; i < x->shape.size(); ++i) {
1393 new_shape.push_back(x->shape[i]);
1398 [&](
const ffi::Array<PrimVar>& indices) {
1399 ffi::Array<PrimExpr> idx;
1400 for (
size_t i = 0; i < static_cast<size_t>(axis); ++i) {
1401 idx.push_back(indices[i]);
1403 idx.push_back(
indexdiv(indices[axis], repeats));
1404 for (
size_t i = axis + 1; i < indices.size(); ++i) {
1405 idx.push_back(indices[i]);
1424 size_t ndim = x->shape.size();
1425 size_t rdim = reps.size();
1426 size_t tdim = (ndim > rdim) ? ndim : rdim;
1427 ffi::Array<PrimExpr> data_shape;
1428 ffi::Array<PrimExpr> reps_shape;
1429 ffi::Array<PrimExpr> new_shape;
1431 for (
size_t i = 0; i < ndim; ++i) {
1432 data_shape.push_back(x->shape[i]);
1435 }
else if (ndim > rdim) {
1436 for (
size_t i = 0; i < ndim; ++i) data_shape.push_back(x->shape[i]);
1437 for (
size_t i = 0; i < (ndim - rdim); ++i) reps_shape.push_back(1);
1438 for (
size_t i = 0; i < rdim; ++i) reps_shape.push_back(
IntImm::Int64(reps[i]));
1440 for (
size_t i = 0; i < (rdim - ndim); ++i) data_shape.push_back(1);
1441 for (
size_t i = 0; i < ndim; ++i) data_shape.push_back(x->shape[i]);
1442 for (
size_t i = 0; i < rdim; ++i) reps_shape.push_back(
IntImm::Int64(reps[i]));
1444 for (
size_t i = 0; i < tdim; ++i) new_shape.push_back(data_shape[i] * reps_shape[i]);
1446 if (is_empty_shape(new_shape)) {
1454 [&](
const ffi::Array<PrimVar>& indices) {
1455 ffi::Array<PrimExpr> idx;
1457 for (
size_t i = 0; i < ndim; ++i) idx.push_back(
indexmod(indices[i], x->shape[i]));
1459 for (
size_t i = 0; i < ndim; ++i)
1460 idx.push_back(
indexmod(indices[rdim - ndim + i], x->shape[i]));
1480 std::string name =
"T_tile", std::string tag =
kBroadcast) {
1481 size_t ndim = x->shape.size();
1482 if (is_empty_shape(new_shape)) {
1490 [&](
const ffi::Array<PrimVar>& indices) {
1491 ffi::Array<PrimExpr> idx;
1493 for (
size_t i = 0; i < ndim; ++i) {
1494 idx.push_back(
indexmod(indices[i], x->shape[i]));
1497 for (
size_t i = 0; i < ndim; ++i) {
1498 idx.push_back(
indexmod(indices[rdim - ndim + i], x->shape[i]));
1519 std::string name =
"T_gather", std::string tag =
kInjective) {
1520 size_t ndim_d = data->shape.size();
1521 size_t ndim_i = indices->shape.size();
1522 TVM_FFI_ICHECK_GE(ndim_d, 1) <<
"Cannot gather from a scalar.";
1523 TVM_FFI_ICHECK_EQ(ndim_d, ndim_i);
1527 TVM_FFI_ICHECK_GE(axis, 0);
1528 TVM_FFI_ICHECK_LT(axis, ndim_d);
1530 size_t indices_dim_i =
static_cast<size_t>(GetConstInt(indices->shape[axis]));
1531 TVM_FFI_ICHECK_GE(indices_dim_i, 1);
1534 PrimType indices_ty = indices->dtype;
1535 TVM_FFI_ICHECK(indices_ty.
MatchesCode(DLDataTypeCode::kDLInt, DLDataTypeCode::kDLUInt));
1537 ffi::Array<PrimExpr> out_shape;
1538 for (
size_t i = 0; i < ndim_i; ++i) {
1539 out_shape.push_back(indices->shape[i]);
1544 [&](
const ffi::Array<PrimVar>& out_index) {
1545 ffi::Array<PrimExpr> indices_position;
1546 for (
size_t i = 0; i < ndim_i; ++i) {
1547 indices_position.push_back(out_index[i]);
1549 ffi::Array<PrimExpr> real_indices;
1550 for (
size_t i = 0; i < ndim_i; ++i) {
1551 if (i ==
static_cast<size_t>(axis)) {
1552 real_indices.push_back(indices(indices_position));
1554 real_indices.push_back(indices_position[i]);
1557 return data(real_indices);
1574 std::string name =
"T_gather_nd", std::string tag =
kInjective) {
1575 size_t ndim_d = data->shape.size();
1576 size_t ndim_i = indices->shape.size();
1577 TVM_FFI_ICHECK_GE(ndim_i, 1) <<
"indices tensor must have at least 1 dimensions";
1578 size_t indices_dim0 =
static_cast<size_t>(GetConstInt(indices->shape[0]));
1579 TVM_FFI_ICHECK_LE(indices_dim0, ndim_d) <<
"dim 0 of indices tensor must be no more "
1580 <<
"than dimensions of data tensor";
1581 ffi::Array<PrimExpr> out_shape;
1582 for (
size_t i = 1; i < ndim_i; ++i) {
1583 out_shape.push_back(indices->shape[i]);
1585 for (
size_t i = indices_dim0 + batch_dims; i < ndim_d; ++i) {
1586 out_shape.push_back(data->shape[i]);
1590 [&](
const ffi::Array<PrimVar>& out_index) {
1591 ffi::Array<PrimExpr> indices_position;
1592 indices_position.push_back(0);
1593 for (
size_t i = 0; i < ndim_i - 1; ++i) {
1594 indices_position.push_back(out_index[i]);
1596 ffi::Array<PrimExpr> real_indices;
1597 for (
size_t i = 0; i < static_cast<size_t>(batch_dims); ++i) {
1598 real_indices.push_back(out_index[i]);
1600 for (
size_t i = 0; i < indices_dim0; ++i) {
1604 PrimType indices_ty = indices->dtype;
1605 if (indices_ty.
MatchesCode(DLDataTypeCode::kDLInt, DLDataTypeCode::kDLUInt)) {
1606 real_indices.push_back(indices(indices_position));
1608 real_indices.push_back(
1612 if (real_indices.size() == ndim_d) {
1613 return data(real_indices);
1615 for (
size_t i = ndim_i - 1; i < out_index.size(); ++i) {
1616 real_indices.push_back(out_index[i]);
1618 return data(real_indices);
1639 bool trans_a =
false,
bool trans_b =
false,
1640 std::string name =
"T_matmul", std::string tag =
kMatMul) {
1641 tvm::ffi::Array<tvm::PrimExpr> output_shape{A->shape[trans_a ? 1 : 0], B->shape[trans_b ? 0 : 1]};
1644 return tvm::prim::sum((trans_a ? A[k][i] : A[i][k]) * (trans_b ? B[j][k] : B[k][j]), {k});
1661 std::string name =
"T_tensordot", std::string tag =
kMatMul) {
1663 TVM_FFI_ICHECK_GE(A->shape.size(), axes);
1664 TVM_FFI_ICHECK_GE(B->shape.size(), axes);
1666 ffi::Array<PrimExpr> output_shape(A->shape.begin(), A->shape.end() + (-axes));
1667 for (
auto it = B->shape.begin() + axes; it != B->shape.end(); ++it) output_shape.push_back(*it);
1669 ffi::Array<IterVar> iter_vars;
1670 for (
int i = 0; i < axes; ++i)
1671 iter_vars.push_back(
reduce_axis(
Range(0, B->shape[i]),
"k" + std::to_string(i)));
1673 auto func = [&A, &B, &iter_vars, axes](
const ffi::Array<PrimVar>& input_indices) {
1674 ffi::Array<PrimExpr> A_indices;
1675 for (
auto it = input_indices.begin(); it != input_indices.begin() + (A->shape.size() - axes);
1677 A_indices.push_back((*it).as_or_throw<
PrimExpr>());
1679 for (
auto& v : iter_vars) A_indices.push_back(v);
1681 ffi::Array<PrimExpr> B_indices;
1682 for (
auto& v : iter_vars) B_indices.push_back(v);
1684 auto it = input_indices.begin() + (A->shape.size() - axes);
1685 for (; it != input_indices.end(); ++it) {
1686 B_indices.push_back((*it).as_or_throw<
PrimExpr>());
1690 if (iter_vars.empty()) {
1691 return A(A_indices) * B(B_indices);
1693 return sum(A(A_indices) * B(B_indices), iter_vars);
1697 return compute(output_shape, func, name, tag);
1713 ffi::Array<PrimExpr> B_axes, std::string name =
"T_tensordot",
1716 TVM_FFI_ICHECK_EQ(A_axes.size(), B_axes.size());
1718 auto A_axes_val = GetConstIntValues(A_axes,
"A_axes");
1719 auto B_axes_val = GetConstIntValues(B_axes,
"B_axes");
1721 ffi::Array<PrimExpr> output_shape;
1722 for (
unsigned i = 0; i < A->shape.size(); ++i)
1723 if (std::find(A_axes_val.begin(), A_axes_val.end(), i) == A_axes_val.end())
1724 output_shape.push_back(A->shape[i]);
1725 for (
unsigned i = 0; i < B->shape.size(); ++i)
1726 if (std::find(B_axes_val.begin(), B_axes_val.end(), i) == B_axes_val.end())
1727 output_shape.push_back(B->shape[i]);
1729 ffi::Array<IterVar> iter_vars;
1730 for (
unsigned i = 0; i < B_axes_val.size(); ++i)
1731 iter_vars.push_back(
reduce_axis(
Range(0, B->shape[B_axes_val[i]]),
"k" + std::to_string(i)));
1733 auto func = [&A, &B, &iter_vars, A_axes_val,
1734 B_axes_val](
const ffi::Array<PrimVar>& input_indices) {
1736 ffi::Array<PrimExpr> A_indices;
1737 for (
unsigned i = 0; i < A->shape.size(); ++i) {
1738 auto axes_pos = std::find(A_axes_val.begin(), A_axes_val.end(), i);
1739 if (axes_pos == A_axes_val.end()) {
1740 A_indices.push_back(input_indices[idx_input++]);
1742 A_indices.push_back(iter_vars[axes_pos - A_axes_val.begin()]);
1746 ffi::Array<PrimExpr> B_indices;
1747 for (
unsigned i = 0; i < B->shape.size(); ++i) {
1748 auto axes_pos = std::find(B_axes_val.begin(), B_axes_val.end(), i);
1749 if (axes_pos == B_axes_val.end()) {
1750 B_indices.push_back(input_indices[idx_input++]);
1752 B_indices.push_back(iter_vars[axes_pos - B_axes_val.begin()]);
1755 return sum(A(A_indices) * B(B_indices), iter_vars);
1757 return compute(output_shape, func, name, tag);
1766 bool is_all_int = start_ty.
code() == DLDataTypeCode::kDLInt &&
1767 stop_ty.
code() == DLDataTypeCode::kDLInt &&
1768 step_ty.
code() == DLDataTypeCode::kDLInt;
1770 if (is_all_int && analyzer->CanProveGreaterEqual(step, 1)) {
1773 }
else if (is_all_int && analyzer->CanProveLess(step, 0)) {
1783 num_elem = analyzer->Simplify(num_elem);
1787 [&](
const ffi::Array<PrimVar>& indices) {
1803inline ffi::Array<Tensor>
meshgrid(
const ffi::Array<Tensor>& inputs,
const std::string& indexing,
1804 std::string name =
"T_meshgrid", std::string tag =
kInjective) {
1805 const bool cartesian_indexing = indexing ==
"xy" && inputs.size() >= 2;
1806 ffi::Array<PrimExpr> out_shape;
1807 for (
size_t i = 0; i < inputs.size(); ++i) {
1808 const int src_index = (cartesian_indexing && i < 2) ? 1 - i : i;
1809 out_shape.push_back(inputs[src_index]->
shape.size() == 0 ? 1 : inputs[src_index]->shape[0]);
1811 ffi::Array<Tensor> result;
1812 for (
size_t i = 0; i < inputs.size(); ++i) {
1815 [&](
const ffi::Array<PrimVar>& indices) {
1816 const int src_index = (cartesian_indexing && i < 2) ? 1 - i : i;
1817 auto ndim = inputs[i]->GetShape().size();
1818 ffi::Array<PrimExpr> real_indices = {};
1820 real_indices = {indices[src_index]};
1822 return inputs[i](real_indices);
1840 const std::string& dst_layout,
1841 const std::string schedule_rule =
"None",
1842 const std::string name =
"T_layout_trans",
1844 SLayout src_layout_struct(src_layout);
1845 SLayout dst_layout_struct(dst_layout);
1847 if (src_layout_struct.
Equals(dst_layout_struct)) {
1851 TVM_FFI_ICHECK(src_layout_struct.defined() && dst_layout_struct.defined())
1852 <<
"cannot convert from/to undefined layout";
1855 TVM_FFI_ICHECK(layout_converter.has_value())
1856 <<
"cannot convert from " << src_layout <<
" to " << dst_layout;
1858 ffi::Array<PrimExpr> dst_shape = layout_converter.value().ForwardShape(src->shape);
1860 ffi::Map<ffi::String, ffi::Any> attrs = {
1869 [&](
const ffi::Array<PrimVar>& dst_indices) {
1870 ffi::Array<PrimExpr> dst_indices_expr =
1872 ffi::Array<PrimExpr> src_indices = layout_converter.value().BackwardIndex(dst_indices_expr);
1874 for (
size_t i = 0; i < src.
ndim(); ++i) {
1875 in_range = in_range && (src_indices[i] < src->shape[i]);
1885 std::vector<std::string>* axes) {
1887 std::string axis =
"";
1888 for (
char c : std::string(layout)) {
1889 if (c >=
'A' && c <=
'z') {
1892 shape->push_back(factor);
1895 }
else if (c >=
'0' && c <=
'9') {
1896 factor = factor * 10 + c -
'0';
1897 if (!axis.empty()) {
1898 axes->push_back(axis);
1902 TVM_FFI_THROW(InternalError) <<
"Invalid layout " << layout;
1905 if (!axis.empty()) {
1906 axes->push_back(axis);
1921 const Tensor& src,
const ffi::String& src_layout,
const ffi::String& dst_layout,
1922 const ffi::String name =
"T_auto_scheduler_layout_trans",
const ffi::String tag =
kInjective) {
1923 ffi::Array<PrimExpr> src_shape;
1924 std::vector<std::string> src_axes;
1925 ffi::Array<PrimExpr> dst_shape;
1926 std::vector<std::string> dst_axes;
1932 [&](
const ffi::Array<PrimVar>& dst_indices) {
1933 ffi::Array<PrimExpr> dst_indices_expr =
1935 ffi::Array<PrimExpr> src_indices;
1936 for (
const std::string& src_axis : src_axes) {
1938 TVM_FFI_ICHECK_EQ(dst_indices_expr.size(), dst_axes.size());
1939 for (
size_t i = 0; i < dst_axes.size(); ++i) {
1940 if (dst_axes[i] == src_axis) {
1941 src_index = src_index * dst_shape[i] + dst_indices_expr[i];
1944 src_indices.push_back(src_index);
1946 return src(src_indices);
1989 const ffi::String name =
"T_meta_schedule_layout_trans",
const ffi::String tag =
kInjective) {
1991 ffi::Array<Range> iter_domain;
1992 iter_domain.reserve(src->shape.size());
1993 for (
const PrimExpr& e : src->shape) {
1996 ffi::Array<PrimExpr> post_transform_shape = index_map->MapShape(src->shape, analyzer);
1998 post_transform_shape,
1999 [src, inv = index_map.
Inverse(iter_domain, analyzer),
2000 &analyzer](
const ffi::Array<PrimVar>& indices) ->
PrimExpr {
2001 ffi::Array<PrimExpr> prim_indices =
2002 indices.Map([](const PrimVar& var) { return var.as_or_throw<PrimExpr>(); });
2003 return src(inv->MapIndices(prim_indices, analyzer));
2017 const std::string tag = kInjective) {
2018 int ndim =
static_cast<int>(src->shape.size());
2019 ffi::Array<PrimExpr> out_shape{ndim};
2022 [&](
const ffi::Array<PrimVar>& indices) {
2023 auto idx = indices[0];
2025 for (
int i = 0; i < ndim; ++i) {
2034 const std::string tag = kInjective) {
2047 const std::string& name =
"tensor_size",
2048 const std::string& tag = kInjective) {
2049 int ndim =
static_cast<int>(src->shape.size());
2050 ffi::Array<PrimExpr> out_tensor_size = {};
2053 [&](
const ffi::Array<PrimVar>& indices) {
2055 for (
int i = 0; i < ndim; ++i) {
2056 ret *= src->shape[i];
2064 const std::string& name =
"tensor_size",
2065 const std::string& tag = kInjective) {
2084 int depth,
int axis,
PrimType dtype,
2085 ffi::Array<PrimExpr> oshape = ffi::Array<PrimExpr>(),
2086 const std::string name =
"T_one_hot",
const std::string tag = kInjective) {
2087 int true_axis = (axis == -1) ? indices->shape.size() : axis;
2088 if (oshape.size() == 0) {
2089 int ndim = indices->shape.size() + 1;
2090 int indices_index = 0;
2091 for (
int i = 0; i < ndim; i++) {
2092 if (i == true_axis) {
2095 oshape.push_back(indices->shape[indices_index++]);
2104 [&](
const ffi::Array<PrimVar>& iter_vars) {
2105 ffi::Array<PrimVar> indices_indices;
2106 for (
size_t i = 0; i < iter_vars.size(); i++) {
2107 if (
static_cast<int>(i) == true_axis) {
2111 indices_indices.push_back(iter_vars[i]);
2114 auto idx = iter_vars[true_axis];
2122 int depth,
int axis, DLDataType dtype,
2123 ffi::Array<PrimExpr> oshape = ffi::Array<PrimExpr>(),
2124 const std::string name =
"T_one_hot",
const std::string tag = kInjective) {
2125 return one_hot(indices, on_value, off_value, depth, axis,
PrimType(dtype), std::move(oshape),
2140 const ffi::Array<PrimExpr>& output_shape,
const Tensor& sparse_values,
2142 const std::string name =
"T_sparse_to_dense",
2143 const std::string tag = kInjective) {
2145 TVM_FFI_ICHECK_EQ(sparse_indices->dtype.code(), DLDataTypeCode::kDLInt)
2146 <<
"sparse_indices only accepts integer values";
2147 TVM_FFI_ICHECK_LE(sparse_indices->shape.size(), 3)
2148 <<
"sparse_indices tensor should be 0D, 1D, or 2D only";
2149 TVM_FFI_ICHECK_LE(sparse_values->shape.size(), 2)
2150 <<
"sparse_values tensor should be 0D or 1D only";
2152 const auto rank_sparse_indices =
static_cast<int>(sparse_indices->shape.size());
2153 ffi::Array<PrimExpr> oshape;
2154 for (
auto l : output_shape) {
2155 oshape.push_back(l);
2159 [&](
const ffi::Array<PrimVar>& indices) {
2161 if (0 == rank_sparse_indices) {
2162 ret =
if_then_else(indices[0].as_or_throw<PrimExpr>() == sparse_indices(),
2163 sparse_values(), ret);
2164 }
else if (1 == rank_sparse_indices) {
2165 for (
int j = 0; j < GetConstInt(sparse_indices->shape[0]); j++) {
2166 ret =
if_then_else(indices[0].as_or_throw<PrimExpr>() == sparse_indices[j],
2167 sparse_values[j], ret);
2170 for (
int j = 0; j < GetConstInt(sparse_indices->shape[0]); j++) {
2172 for (
int k = 0; k < GetConstInt(sparse_indices->shape[1]); k++) {
2173 PrimExpr comparision = indices[k].as_or_throw<
PrimExpr>() == sparse_indices[j][k];
2174 aggregate_condition = aggregate_condition && comparision;
2176 ret =
if_then_else(aggregate_condition, sparse_values[j], ret);
2197 bool super_diag_right_align,
bool sub_diag_right_align,
2198 const std::string name =
"T_matrix_set_diag",
2199 const std::string tag = kInjective) {
2200 size_t ndim = input->shape.size() - 1;
2202 bool only_one_diagonal = k1 == k2;
2206 [&](
const ffi::Array<PrimVar>& iter_vars) {
2207 auto get_diag = [&]() {
2208 ffi::Array<PrimExpr> diagonal_indices;
2209 PrimExpr k = only_one_diagonal ? PrimExpr(k1) : iter_vars[ndim] - iter_vars[ndim - 1];
2210 PrimExpr offset = 0;
2211 for (size_t i = 0; i < ndim - 1; i++) {
2212 diagonal_indices.push_back(iter_vars[i]);
2214 if (!only_one_diagonal) {
2216 diagonal_indices.push_back(k2 - k);
2219 auto get_offset = [&](PrimExpr M, PrimExpr N) {
2221 return diagonal->shape[diagonal->shape.size() - 1] - if_then_else(M < N, M, N);
2223 offset = if_then_else(
2225 super_diag_right_align ? get_offset(input->shape[ndim] - k, input->shape[ndim - 1])
2227 sub_diag_right_align ? get_offset(input->shape[ndim], input->shape[ndim - 1] + k)
2230 diagonal_indices.push_back(if_then_else(k >= 0, iter_vars[ndim - 1], iter_vars[ndim]) +
2232 return diagonal(diagonal_indices);
2236 get_diag(), input(iter_vars)),
2251 const std::string name =
"advanced_index",
2252 const std::string tag = kInjective) {
2253 TVM_FFI_ICHECK_LE(indices.size(), data->shape.size()) <<
"too many indices for data!";
2254 ffi::Array<PrimExpr> oshape;
2255 ffi::Array<PrimExpr> broadcast_shape;
2256 ffi::Array<Tensor> bindices;
2258 broadcast_shape = indices[0]->shape;
2259 for (
size_t i = 1; i < indices.size(); ++i) {
2260 auto bh = detail::BroadcastShape(broadcast_shape, indices[i]->
shape);
2261 broadcast_shape = ffi::Array<PrimExpr>(bh.common_shape.begin(), bh.common_shape.end());
2263 if (indices.size() == 1) {
2268 for (
size_t i = 0; i < indices.size(); ++i) {
2269 bindices.push_back(
broadcast_to(indices[i], broadcast_shape));
2273 for (
const auto& dim : broadcast_shape) {
2274 oshape.push_back(dim);
2276 for (
size_t i = indices.size(); i < data->shape.size(); ++i) {
2277 oshape.push_back(data->shape[i]);
2282 [&](
const ffi::Array<PrimVar>& iter_var) {
2283 ffi::Array<PrimExpr> tensor_indices;
2284 for (
size_t i = 0; i < broadcast_shape.size(); ++i) {
2285 tensor_indices.push_back(iter_var[i]);
2287 ffi::Array<PrimExpr> real_indices;
2288 for (
size_t i = 0; i < bindices.size(); ++i) {
2289 real_indices.push_back(bindices[i](tensor_indices));
2291 for (
size_t i = broadcast_shape.size(); i < iter_var.size(); ++i) {
2292 real_indices.push_back(iter_var[i]);
2295 return data(real_indices);
2304 ffi::Array<PrimExpr> output_shape,
2305 std::string name =
"T_strided_slice_dynamic",
2306 std::string tag = kInjective) {
2307 const size_t num_dynamic_axes = x.
ndim();
2308 TVM_FFI_ICHECK_EQ(begin.
ndim(), 1);
2309 TVM_FFI_ICHECK_EQ(end.
ndim(), 1);
2310 TVM_FFI_ICHECK_EQ(strides.
ndim(), 1);
2311 const auto* len_begin = begin->shape[0].as<
IntImmNode>();
2312 const auto* len_end = end->shape[0].as<
IntImmNode>();
2313 const auto* len_strides = strides->shape[0].as<
IntImmNode>();
2314 TVM_FFI_ICHECK(len_begin);
2315 TVM_FFI_ICHECK(len_end);
2316 TVM_FFI_ICHECK(len_strides);
2317 TVM_FFI_ICHECK_EQ(len_begin->value, num_dynamic_axes);
2318 TVM_FFI_ICHECK_EQ(len_end->
value, num_dynamic_axes);
2319 TVM_FFI_ICHECK_EQ(len_strides->
value, num_dynamic_axes);
2323 [&](
const ffi::Array<tvm::PrimVar>& indices) {
2324 ffi::Array<PrimExpr> real_indices;
2325 for (
size_t i = 0; i < num_dynamic_axes; ++i) {
2326 auto ind = IntImm::Int64(i);
2327 PrimExpr begin_index = CanonicalizeIndex(begin(ind), x->shape[i], strides(ind));
2328 real_indices.push_back(indices[i] * strides(ind) + begin_index);
2330 return x(real_indices);
Algebra expression simplifications.
Broadcast op constructions.
Managed reference class to FloatImmNode.
Definition expr.h:232
Constant integer literals in the program.
Definition expr.h:135
ffi::BigInt value
the Internal value.
Definition expr.h:138
Managed reference class to IntImmNode.
Definition expr.h:152
static IntImm Int64(ffi::BigInt value, Location loc=UnknownLoc())
Construct a scalar int64 constant.
Definition expr.h:195
static IntImm Bool(bool value, Location loc=UnknownLoc())
Construct a scalar boolean constant.
Definition expr.h:172
static IntImm Int32(ffi::BigInt value, Location loc=UnknownLoc())
Construct a scalar int32 constant.
Definition expr.h:181
Typed reference/view over any Expr whose ExprNode::ty is PrimType.
Definition base_expr.h:447
Definition base_expr.h:161
TVM_FFI_INLINE DLDataTypeCode code() const
Definition base_expr.h:198
TVM_FFI_INLINE bool MatchesCode(Codes... codes) const
Check whether the dtype code matches any of the provided DLPack codes.
Definition base_expr.h:232
static TVM_TIRX_DLL PrimType Int(int bits, int lanes=1)
Construct a signed integer type with fixed lanes.
static TVM_TIRX_DLL PrimType Float(int bits, int lanes=1)
Construct a floating-point type with fixed lanes.
Checked scalar view over a VarNode.
Definition expr.h:742
Range container
Definition expr.h:1025
static TVM_TIRX_DLL Range FromMinExtent(PrimExpr min, PrimExpr extent, Location loc=UnknownLoc())
construct a new range with min and extent The corresponding constructor is removed,...
ExpectedType ty() const
Definition base_expr.h:424
Managed reference to SelectNode.
Definition expr.h:712
Managed reference to AnalyzerObj.
Definition analyzer.h:916
Opaque construction-time node that represents a tensor.
Definition tensor.h:83
Tensor structure representing a possible input, or intermediate computation result.
Definition tensor.h:111
size_t ndim() const
Definition tensor.h:236
Definition index_map.h:190
IndexMap Inverse(ffi::Array< Range > initial_ranges) const
Generate the inverse mapping using a fresh analyzer.
static ffi::Optional< SBijectiveLayout > Create(SLayout src_layout, SLayout dst_layout)
Managed reference to SLayoutNode.
Definition data_layout.h:128
bool Equals(const SLayout &rhs) const
Whether the two layouts are equal.
Definition data_layout.h:331
Utility functions for handling constants in TVM expressions.
SLayout expression to describe the data organization of a tensor. And SBijectiveLayout to mapping two...
Defines a remapping of tensor indices.
Shared primitive construction and constant helpers.
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
TVM_TIRX_DLL PrimExpr cast(PrimType t, PrimExpr value, Location loc=UnknownLoc())
cast value to type.
constexpr const char * kScheduleRule
Definition stmt.h:388
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.
bool IsTensorLoad(const Expr &expr)
Return whether an expression calls the registered te.tensor_load operator.
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...
DLDataType DefaultIndexType()
Definition type.h:48
constexpr const char * kSrcLayout
Definition tags.h:57
constexpr const char * kInputShape
Definition tags.h:59
constexpr const char * kDstLayout
Definition tags.h:58
PrimExpr GetLength(PrimExpr begin, PrimExpr end, PrimExpr stride, PrimExpr extent, bool assume_inbound=true)
Definition transform.h:682
Tensor sequence_mask(const Tensor &data, const Tensor &valid_length, double mask_value, int axis, std::string name="T_sequence_mask", std::string tag=kInjective)
Mask the out-of-boundary elements of each sequence.
Definition transform.h:1106
Tensor gather_nd(const Tensor &data, const Tensor &indices, int batch_dims=0, std::string name="T_gather_nd", std::string tag=kInjective)
Gather elements from a n-dimension array.
Definition transform.h:1573
int64_t StaticCanonicalizeIndex(int64_t index, int64_t extent, int64_t stride)
Definition transform.h:663
Tensor reshape(const Tensor &x, ffi::Array< PrimExpr > newshape, std::string name="T_reshape", std::string tag=kInjective)
Reshape a tensor.
Definition transform.h:329
Tensor shape(const Tensor &src, PrimType dtype, const std::string name="T_shape", const std::string tag=kInjective)
Get the shape of input tensor.
Definition transform.h:2016
tvm::te::Tensor broadcast_to(const tvm::te::Tensor &t, const tvm::ffi::Array< tvm::PrimExpr > &output_shape, std::string name="T_broadcast_to", std::string tag=kBroadcast)
Creates an operation that broadcasts a tensor into a compatible shape according to numpy's rules.
Definition broadcast.h:48
constexpr auto kBroadcast
Definition tags.h:36
Tensor reverse_sequence(const Tensor &x, const ffi::Optional< Tensor > &seq_lengths, int seq_axis=1, int batch_axis=0, std::string name="T_reverse_sequence", std::string tag=kInjective)
Reverse the tensor for variable length slices. Input is first sliced along batch axis and then elemen...
Definition transform.h:263
constexpr auto kInjective
Definition tags.h:33
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 stack(const ffi::Array< Tensor > &inputs, int axis=0, std::string name="T_stack", std::string tag=kInjective)
Join a sequence of tensors along a new axis.
Definition transform.h:541
Tensor arange(const PrimExpr &start, const PrimExpr &stop, const PrimExpr &step, PrimType dtype, std::string name="T_arange", std::string tag=kInjective)
Definition transform.h:1760
Tensor strided_slice(const Tensor &x, const ffi::Array< ffi::Optional< IntImm > > &begin, const ffi::Array< ffi::Optional< IntImm > > &end, const ffi::Array< IntImm > &strides, std::string slice_mode="end", std::string name="T_strided_slice", std::string tag=kInjective)
strided_slice of a tensor
Definition transform.h:965
Tensor auto_scheduler_layout_transform(const Tensor &src, const ffi::String &src_layout, const ffi::String &dst_layout, const ffi::String name="T_auto_scheduler_layout_trans", const ffi::String tag=kInjective)
Transform the auto-scheduler generated layout according to src_layout and dst_layout.
Definition transform.h:1920
Tensor squeeze(const Tensor &x, ffi::Optional< ffi::Array< int64_t > > opt_axes, bool atleast1d=false, std::string name="T_squeeze", std::string tag=kInjective)
Remove size 1 dimensions from the shape of a tensor. The removed dimensions must have a constant size...
Definition transform.h:415
ffi::Array< Tensor > meshgrid(const ffi::Array< Tensor > &inputs, const std::string &indexing, std::string name="T_meshgrid", std::string tag=kInjective)
Produce grids by expanding input over dimensions defined by other inputs.
Definition transform.h:1803
void parse_auto_scheduler_layout(const ffi::String &layout, ffi::Array< PrimExpr > *shape, std::vector< std::string > *axes)
Utility function for auto_scheduler_layout_transform.
Definition transform.h:1884
Tensor strided_slice_with_axes(const Tensor &x, const ffi::Array< ffi::Optional< IntImm > > &begin, const ffi::Array< ffi::Optional< IntImm > > &end, const ffi::Array< IntImm > &strides, const ffi::Array< int64_t > &axes, std::string slice_mode="end", std::string name="T_strided_slice_with_axes", std::string tag=kInjective)
strided_slice of a tensor
Definition transform.h:902
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 sparse_to_dense(const Tensor &sparse_indices, const ffi::Array< PrimExpr > &output_shape, const Tensor &sparse_values, const PrimExpr &default_value, const std::string name="T_sparse_to_dense", const std::string tag=kInjective)
Get a dense tensor.
Definition transform.h:2139
Tensor sliding_window(const Tensor &x, int axis, ffi::Array< int64_t > window_shape, ffi::Array< int64_t > strides, std::string name="T_sliding_window", std::string tag="")
Creates an operation to slide a window over the input x.
Definition transform.h:75
Tensor unravel_index(const Tensor &x, const Tensor &shape, std::string name="T_unravel", std::string tag=kInjective)
Converts a flat index or array of flat indices into a tuple of coordinate arrays.
Definition transform.h:367
Tensor layout_transform(const Tensor &src, const std::string &src_layout, const std::string &dst_layout, const std::string schedule_rule="None", const std::string name="T_layout_trans", const std::string tag=kInjective)
Transform the layout according to src_layout and dst_layout.
Definition transform.h:1839
Tensor adv_index(const Tensor &data, const ffi::Array< Tensor > &indices, const std::string name="advanced_index", const std::string tag=kInjective)
Numpy style advanced indexing with tensor.
Definition transform.h:2250
Tensor concatenate(const ffi::Array< Tensor > &inputs, int axis=0, std::string name="T_concat", std::string tag=kInjective)
Join a sequence of tensors along an existing axis.
Definition transform.h:481
constexpr auto kMatMul
Definition tags.h:37
ffi::Array< Tensor > split_n_sections(const Tensor &x, int num_sections, int axis, std::string name="T_split_sections", std::string tag=kInjective)
Split a tensor into a number of sub-tensors.
Definition transform.h:1009
Tensor dyn_tile(const Tensor &x, ffi::Array< PrimExpr > new_shape, size_t rdim, std::string name="T_tile", std::string tag=kBroadcast)
Creates an operation to tile elements of an array.
Definition transform.h:1479
te::Tensor tensor_size(const te::Tensor &src, PrimType dtype, const std::string &name="tensor_size", const std::string &tag=kInjective)
Get the size of input tensor.
Definition transform.h:2046
Tensor one_hot(const Tensor &indices, const PrimExpr on_value, const PrimExpr off_value, int depth, int axis, PrimType dtype, ffi::Array< PrimExpr > oshape=ffi::Array< PrimExpr >(), const std::string name="T_one_hot", const std::string tag=kInjective)
Returns a one-hot tensor where the locations repsented by indices take value on_value,...
Definition transform.h:2083
Tensor tensordot(const Tensor &A, const tvm::te::Tensor &B, int axes=2, std::string name="T_tensordot", std::string tag=kMatMul)
A generalization of matrix multiplication to tensors.
Definition transform.h:1660
Tensor meta_schedule_layout_transform(const Tensor &src, const tirx::IndexMap &index_map, const ffi::String name="T_meta_schedule_layout_trans", const ffi::String tag=kInjective)
Transform the meta-schedule generated layout according to TIR's IndexMap.
Definition transform.h:1987
te::Tensor dynamic_strided_slice_with_axes(const te::Tensor &x, const ffi::Array< PrimExpr > &begin, const ffi::Array< PrimExpr > &end, const ffi::Array< PrimExpr > &strides, const ffi::Array< int64_t > &axes, bool assume_inbound=true, std::string name="T_dynamic_strided_slice_with_axes", std::string tag=kInjective)
strided_slice of a tensor where begin/end/stride can be mixed static and dynamic
Definition transform.h:709
Tensor take(const Tensor &a, const Tensor &indices, int batch_dims, std::string mode="fast", std::string name="T_take", std::string tag=kInjective)
Take elements from an flattened input array when axis is None.
Definition transform.h:1045
PrimExpr DynamicCanonicalizeIndex(PrimExpr index, PrimExpr extent, PrimExpr stride)
Definition transform.h:648
tvm::te::Tensor matmul(const tvm::te::Tensor &A, const tvm::te::Tensor &B, bool trans_a=false, bool trans_b=false, std::string name="T_matmul", std::string tag=kMatMul)
Creates an operation that calculates a matrix multiplication (row-major notation): A(i,...
Definition transform.h:1638
Tensor transpose(const Tensor &x, ffi::Optional< ffi::Array< int64_t > > opt_axes, std::string name="T_transpose", std::string tag=kInjective)
Permute the dimensions of an array.
Definition transform.h:204
ffi::Array< Tensor > split_indices_array(const Tensor &x, ffi::Array< PrimExpr > split_indices, int axis, std::string name="T_split", std::string tag=kInjective)
Split a tensor into multiple sub-tensors.
Definition transform.h:587
Tensor dynamic_strided_slice(const Tensor &x, const ffi::Array< PrimExpr > &begin, const ffi::Array< PrimExpr > &end, const ffi::Array< PrimExpr > &strides, bool assume_inbound=true, std::string name="T_dynamic_strided_slice", std::string tag=kInjective)
strided_slice of a tensor where begin/end/stride can be mixed static and dynamic
Definition transform.h:770
Tensor matrix_set_diag(const Tensor &input, const Tensor &diagonal, int k1, int k2, bool super_diag_right_align, bool sub_diag_right_align, const std::string name="T_matrix_set_diag", const std::string tag=kInjective)
Returns a tensor with the diagonal of input tensor replaced with the provided diagonals.
Definition transform.h:2196
Tensor where(const Tensor &condition, const Tensor &x, const Tensor &y, std::string name="T_where", std::string tag=kBroadcast)
Return the elements, either from x or y, depending on the condition.
Definition transform.h:1335
Tensor gather(const Tensor &data, int axis, const Tensor &indices, std::string name="T_gather", std::string tag=kInjective)
Gather values along given axis from given indices.
Definition transform.h:1518
Tensor tile(const Tensor &x, ffi::Array< int64_t > reps, std::string name="T_tile", std::string tag=kBroadcast)
Creates an operation to tile elements of an array.
Definition transform.h:1422
Tensor repeat(const Tensor &x, int repeats, int axis, std::string name="T_repeat", std::string tag=kBroadcast)
Creates an operation to repeat elements of an array.
Definition transform.h:1375
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 if_then_else(PrimExpr cond, PrimExpr true_value, PrimExpr false_value, Location loc=UnknownLoc())
Conditional expression.
TVM_TIRX_DLL PrimExpr min(PrimExpr a, PrimExpr b, Location loc=UnknownLoc())
take minimum of two values
TVM_TIRX_DLL PrimExpr indexdiv(PrimExpr a, PrimExpr b, Location loc=UnknownLoc())
compute floor(a / b) where a and b are non-negative.
TVM_TIRX_DLL PrimExpr truncmod(PrimExpr a, PrimExpr b, Location loc=UnknownLoc())
compute the remainder of truncdiv
TVM_TIRX_DLL PrimExpr floordiv(PrimExpr a, PrimExpr b, Location loc=UnknownLoc())
compute floor(a / b)
TVM_TIRX_DLL PrimExpr ceildiv(PrimExpr a, PrimExpr b, Location loc=UnknownLoc())
compute ceil(a / b)
TVM_TIRX_DLL PrimExpr ceil(PrimExpr x, Location loc=UnknownLoc())
Round up to the nearest integral value, preserving the input type.
TVM_TIRX_DLL PrimExpr indexmod(PrimExpr a, PrimExpr b, Location loc=UnknownLoc())
compute the remainder floor(a / b) where a and b are non-negative.
Operation node can generate one or multiple Tensors.
Index ravel and unraval operations.
S-TIR (Schedulable TIR) statements and attributes.
Utility functions for strided_slice op.
Utility functions for handling tensor.