24 #ifndef TVM_TOPI_TRANSFORM_H_
25 #define TVM_TOPI_TRANSFORM_H_
43 #include <unordered_set>
57 using namespace topi::detail;
77 Array<Integer> strides, std::string name =
"T_sliding_window",
78 std::string tag =
"") {
80 auto _axis = size_t(axis);
81 CHECK_LT(_axis, x->shape.size()) <<
"axis must be a valid dimension index of x.";
82 CHECK_EQ(x->shape.size() - _axis, window_shape.size())
83 <<
"There must be a window shape for every dimension of x "
84 <<
"over which we are sliding the window.";
85 CHECK_EQ(strides.size(), window_shape.size()) <<
"Windows and strides should be the same length.";
88 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];
100 auto window_len = window_shape[i];
102 auto stride = strides[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) {
109 new_shape.push_back(window_shape[i]);
112 ICHECK(new_shape.size() == _axis + 2 * window_shape.size());
116 [&](
const Array<Var>& indices) {
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];
131 auto stride = strides[i];
133 idx.push_back(window_idx * stride + idx_within_window);
136 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 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 ICHECK(num_newaxis >= 0) <<
"expand_dims only accepts `num_newaxis >= 0`"
162 <<
", but got num_newaxis = " << num_newaxis;
165 axis = ndim + axis + 1;
167 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 Array<Var>& indices) {
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 Array<Integer> 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 Array<PrimExpr> new_shape;
214 for (
size_t i = 0; i < axes.size(); ++i) {
215 int axis =
static_cast<int>(axes[i]->value);
218 new_axis =
static_cast<int>(x->shape.size()) + axis;
219 axes.Set(i, new_axis);
221 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 ICHECK(new_axis !=
static_cast<int>(axes[j]->value)) <<
"repeated axis in transpose";
230 new_shape.push_back(x->shape[new_axis]);
235 [&](
const Array<Var>& 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]->value);
242 idx[axis] = indices[i];
264 int batch_axis = 0, std::string name =
"T_reverse_sequence",
266 size_t src_tensor_dim = x->shape.size();
267 int seq_axis_inp = seq_axis;
269 if (seq_lengths.defined()) {
270 size_t seq_lengths_dim = seq_lengths->shape.size();
271 int batch_axis_inp = batch_axis;
272 if (batch_axis < 0) {
273 batch_axis =
static_cast<int>(x->shape.size()) + batch_axis;
276 ICHECK(seq_lengths_dim == 1) <<
"seq_lengths should be 1D vector";
278 ICHECK(GetConstInt(seq_lengths->shape[0]) == GetConstInt(x->shape[batch_axis]))
279 <<
"For reverse_sequnece seq_lengths size should match with dimension of batch axis"
280 <<
", but got dimension of batch_axis = " << GetConstInt(x->shape[batch_axis])
281 <<
", and seq_length size = " << GetConstInt(seq_lengths->shape[0]);
283 ICHECK((0 <= batch_axis) && (batch_axis <
static_cast<int>(x->shape.size())))
284 <<
"batch_axis=" << batch_axis_inp <<
" is invalid for the "
285 <<
static_cast<int>(x->shape.size()) <<
"-dimensional input tensor";
289 seq_axis =
static_cast<int>(x->shape.size()) + seq_axis;
291 ICHECK((0 <= seq_axis) && (seq_axis <
static_cast<int>(x->shape.size())))
292 <<
"seq_axis=" << seq_axis_inp <<
" is invalid for the " <<
static_cast<int>(x->shape.size())
293 <<
"-dimensional input tensor";
295 auto func = [&](
const Array<Var>& indices) {
296 Array<PrimExpr> real_indices;
297 for (
size_t i = 0; i < src_tensor_dim; ++i) {
298 if (i ==
static_cast<size_t>(seq_axis)) {
299 if (seq_lengths.defined()) {
300 auto len = seq_lengths(indices[batch_axis]);
302 len <= 1 || len <= indices[i], indices[i],
303 if_then_else(len > x->shape[i], x->shape[i] - 1 - indices[i], len - 1 - indices[i]));
304 real_indices.push_back(idx);
306 real_indices.push_back(x->shape[i] - 1 - indices[i]);
309 real_indices.push_back(indices[i]);
312 return x(real_indices);
315 return compute(x->shape, func, name, tag);
330 auto x_shape = x->shape;
331 Array<PrimExpr> target_shape;
333 for (
const auto& ele : newshape) {
334 target_shape.push_back(ele);
338 if (is_empty_shape(target_shape) || is_empty_shape(x->shape)) {
340 target_shape, [&](
const Array<Var>& indices) {
return tvm::cast(x->dtype, 0); }, name, tag);
344 [&](
const Array<Var>& indices) {
345 return x(UnravelIndex(
346 RavelIndex(Array<PrimExpr>{indices.begin(), indices.end()}, target_shape), x_shape));
365 auto x_shape = x->shape;
366 auto shape_shape =
shape->shape;
368 Array<PrimExpr> oshape;
369 oshape.push_back(shape_shape[0]);
370 if (x_shape.size() != 0) {
371 oshape.push_back(x_shape[0]);
374 auto func = [&](
const Array<Var>& indices) {
376 std::vector<PrimExpr> indices_divs;
381 if (x_shape.size() != 0) {
382 index_val = x[indices[1]];
386 indices_divs.push_back(index_val);
387 for (
int v = GetConstInt(shape_shape[0]) - 1; v >= 0; --v) {
390 indices_divs.push_back(cur_val);
395 return compute(oshape, func, name, tag);
412 std::string name =
"T_squeeze", std::string tag =
kInjective) {
413 auto ndim = x->shape.size();
414 std::vector<int> axis_val;
415 if (!opt_axes.has_value()) {
416 for (
size_t i = 0; i < ndim; ++i) {
417 if (IsConstInt(x->shape[i]) && GetConstInt(x->shape[i]) == 1) {
418 axis_val.push_back(
static_cast<int>(i));
422 Array<Integer> axis = *std::move(opt_axes);
423 for (
size_t i = 0; i < axis.size(); ++i) {
424 int64_t val = axis[i]->value;
426 val +=
static_cast<int>(x->shape.size());
428 if (IsConstInt(x->shape[val])) {
429 ICHECK_EQ(GetConstInt(x->shape[val]), 1) <<
"Dimension " << val <<
" must have size 1";
431 axis_val.push_back(val);
435 std::unordered_set<int> axis_set(axis_val.begin(), axis_val.end());
437 Array<PrimExpr> out_shape;
438 for (
size_t i = 0; i < ndim; ++i) {
439 if (axis_set.count(
static_cast<int>(i)) == 0) {
440 out_shape.push_back(x->shape[i]);
443 if (out_shape.size() == 0 && atleast1d) {
444 out_shape.push_back(1);
449 [&](
const Array<Var>& indices) {
450 Array<PrimExpr> real_indices;
452 for (
size_t i = 0; i < ndim; ++i) {
453 if (axis_set.count(
static_cast<int>(i)) == 0) {
454 real_indices.push_back(indices[i - flag]);
456 real_indices.push_back(0);
460 return x(real_indices);
475 inline Tensor concatenate(
const Array<Tensor>& inputs,
int axis = 0, std::string name =
"T_concat",
477 int ndim =
static_cast<int>(inputs[0]->shape.size());
478 ICHECK(-ndim <= axis && axis < ndim) <<
"concatenate only accepts `axis` in [-ndim, ndim)"
479 <<
", but got axis = " << axis <<
", and ndim = " << ndim;
483 ICHECK_LT(axis, inputs[0]->
shape.size()) <<
"axis out of bounds";
485 Array<PrimExpr> axis_sizes;
486 for (
auto t : inputs) {
487 axis_sizes.push_back(t->shape[axis]);
491 for (
size_t i = 1; i < axis_sizes.size(); ++i) {
492 join_size += axis_sizes[i];
494 join_size = analyzer.
Simplify(join_size);
495 Array<PrimExpr> out_shape;
496 for (
size_t i = 0; i < inputs[0]->shape.size(); ++i) {
497 out_shape.push_back(i ==
static_cast<size_t>(axis) ? join_size : inputs[0]->
shape[i]);
502 [&](
const Array<Var>& indices) {
503 auto ret = inputs[0](indices);
504 auto ind = indices[axis];
505 for (
size_t i = 0; i < inputs.size() - 1; ++i) {
506 ind -= axis_sizes[i];
509 for (
size_t i = 0; i < static_cast<size_t>(axis); ++i) {
510 idx.push_back(indices[i]);
513 for (
size_t i = axis + 1; i < indices.size(); ++i) {
514 idx.push_back(indices[i]);
534 inline Tensor stack(
const Array<Tensor>& inputs,
int axis = 0, std::string name =
"T_stack",
536 int ndim =
static_cast<int>(inputs[0]->shape.size());
537 ICHECK(-ndim - 1 <= axis && axis <= ndim)
538 <<
"stack only accepts `axis` in [-ndim, ndim)"
539 <<
", but got axis = " << axis <<
", and ndim = " << ndim;
543 ICHECK_LT(axis, inputs[0]->
shape.size() + 1) <<
"axis out of bounds";
545 const int stack_size =
static_cast<int>(inputs.size());
546 Array<PrimExpr> out_shape;
547 for (
size_t i = 0; i < static_cast<size_t>(axis); ++i) out_shape.push_back(inputs[0]->shape[i]);
548 out_shape.push_back(stack_size);
549 for (
size_t i =
static_cast<size_t>(axis); i < static_cast<size_t>(ndim); ++i)
550 out_shape.push_back(inputs[0]->shape[i]);
554 [&](
const Array<Var>& indices) {
556 for (
size_t i = 0; i < indices.size(); ++i)
557 if (i !=
static_cast<size_t>(axis)) idx.push_back(indices[i]);
558 auto ind = indices[axis];
559 auto ret = inputs[0](idx);
560 for (
int i = 0; i < static_cast<int>(inputs.size() - 1); ++i) {
581 std::string name =
"T_split",
584 axis +=
static_cast<int>(x->shape.size());
586 ICHECK_LT(axis, x->shape.size()) <<
"axis out of bounds";
588 auto src_axis_size = x->shape[axis];
589 std::vector<PrimExpr> begin_ids;
590 begin_ids.push_back(0);
592 for (
auto idx : split_indices) {
594 auto back_node = begin_ids.back().as<
IntImmNode>();
595 if (idx_node && back_node) {
596 ICHECK_GT(idx_node->value, back_node->
value) <<
"split_indices must be sorted";
598 begin_ids.push_back(idx);
601 Array<Array<PrimExpr>> out_shapes;
602 for (
size_t i = 0; i < begin_ids.size(); ++i) {
604 if (i == begin_ids.size() - 1) {
605 out_axis_size = src_axis_size - begin_ids[i];
607 out_axis_size = begin_ids[i + 1] - begin_ids[i];
610 Array<PrimExpr>
shape;
611 for (
size_t i = 0; i < static_cast<size_t>(axis); ++i) {
612 shape.push_back(x->shape[i]);
614 shape.push_back(out_axis_size);
615 for (
size_t i = axis + 1; i < x->shape.size(); ++i) {
616 shape.push_back(x->shape[i]);
619 out_shapes.push_back(
shape);
622 Array<Tensor> result;
623 for (
size_t i = 0; i < begin_ids.size(); ++i) {
626 [&](
const Array<Var>& indices) {
627 auto begin = begin_ids[i];
628 Array<PrimExpr> real_indices;
629 for (
size_t j = 0; j < static_cast<size_t>(axis); ++j) {
630 real_indices.push_back(indices[j]);
632 real_indices.push_back(indices[axis] + begin);
633 for (
size_t j = axis + 1; j < indices.size(); ++j) {
634 real_indices.push_back(indices[j]);
637 return x(real_indices);
656 if (!(index->IsInstance<
tvm::IntImmNode>() && GetConstInt(index) >= 0)) {
664 int64_t begin_range = stride < 0 ? -1 : 0;
665 int64_t end_range = stride < 0 ? extent - 1 : extent;
683 bool assume_inbound =
true) {
684 if (assume_inbound) {
685 return ceildiv(end - begin, stride);
710 const Tensor& x,
const Array<PrimExpr>& begin,
const Array<PrimExpr>& end,
711 const Array<PrimExpr>& strides,
const Array<Integer>& axes,
bool assume_inbound =
true,
712 std::string name =
"T_dynamic_strided_slice_with_axes", std::string tag =
kInjective) {
713 const size_t src_tensor_dim = x->shape.size();
714 ICHECK_EQ(begin.size(), end.size());
715 ICHECK_EQ(begin.size(), strides.size());
716 ICHECK_EQ(begin.size(), axes.size());
717 ICHECK_LE(begin.size(), src_tensor_dim);
719 for (
const auto& axis_imm : axes) {
720 int axis = axis_imm->value;
721 ICHECK_LT(axis, src_tensor_dim);
726 Array<PrimExpr> out_shape = x->shape;
727 for (
size_t i = 0; i < begin.size(); i++) {
728 int axis = axes[i]->value;
730 analyzer.
Simplify(
GetLength(begin[i], end[i], strides[i], out_shape[axis], assume_inbound));
731 out_shape.Set(axis, new_shape);
736 [&](
const Array<tvm::tir::Var>& indices) {
737 Array<PrimExpr> real_indices = indices.Map([](
const auto&
var) ->
PrimExpr {
return var; });
739 for (
size_t i = 0; i < begin.size(); i++) {
740 int axis = axes[i]->value;
741 PrimExpr new_index = indices[axis] * strides[i] + begin[i];
742 real_indices.Set(axis, new_index);
745 return x(real_indices);
765 const Array<PrimExpr>& end,
const Array<PrimExpr>& strides,
766 bool assume_inbound =
true,
767 std::string name =
"T_dynamic_strided_slice",
769 const size_t src_tensor_dim = x->shape.size();
770 ICHECK_LE(begin.size(), src_tensor_dim);
771 ICHECK_LE(end.size(), src_tensor_dim);
772 ICHECK_LE(strides.size(), src_tensor_dim);
773 ICHECK_EQ(begin.size(), end.size());
774 ICHECK_EQ(begin.size(), strides.size());
776 const size_t num_slice_axes = begin.size();
777 Array<PrimExpr> out_shape;
780 for (
size_t i = 0; i < num_slice_axes; ++i) {
782 if (!begin[i]->IsInstance<ProducerLoadNode>() && !end[i]->IsInstance<ProducerLoadNode>() &&
783 !strides[i]->IsInstance<ProducerLoadNode>()) {
785 analyzer.
Simplify(
GetLength(begin[i], end[i], strides[i], x->shape[i], assume_inbound)));
791 for (
size_t i = num_slice_axes; i < src_tensor_dim; ++i) {
792 out_shape.push_back(x->shape[i]);
797 [&](
const Array<tvm::tir::Var>& indices) {
798 Array<PrimExpr> real_indices;
799 for (
size_t i = 0; i < num_slice_axes; ++i) {
800 real_indices.push_back(indices[i] * strides[i] +
tvm::min(begin[i], x->shape[i] - 1));
803 for (
size_t i = num_slice_axes; i < src_tensor_dim; ++i) {
804 real_indices.push_back(indices[i]);
806 return x(real_indices);
827 bool assume_inbound =
true,
828 std::string name =
"T_strided_slice_dynamic",
830 DataType index_dtype = begin->shape[0]->dtype;
831 const int64_t num_dynamic_axes = begin->shape[0].as<
IntImmNode>()->value;
833 ICHECK_EQ(strides->shape[0].as<
IntImmNode>()->
value, num_dynamic_axes);
835 Array<PrimExpr> begin_expr, end_expr, strides_expr;
836 for (int64_t i = 0; i < num_dynamic_axes; ++i) {
838 begin_expr.push_back(begin(ind));
839 end_expr.push_back(end(ind));
840 strides_expr.push_back(strides(ind));
860 const Array<PrimExpr>& ishape,
const Array<Integer>& begin,
const Array<Integer>& end,
861 const Array<Integer>& strides,
const Array<Integer>& axes,
const std::string& slice_mode) {
862 ICHECK(axes.size() == begin.size() && axes.size() == end.size() && axes.size() == strides.size());
863 std::vector<int64_t> begin_vec, end_vec, strides_vec;
864 std::tie(begin_vec, end_vec, strides_vec) = ConvertToVec(begin, end, strides, slice_mode);
865 auto begin_canonicalized = StridedSliceCanonicalizeBegin(ishape, begin_vec, strides_vec, axes,
866 begin[0]->dtype, slice_mode);
868 begin_canonicalized,
true);
888 const Array<Integer>& end,
const Array<Integer>& strides,
889 const Array<Integer>& axes, std::string slice_mode =
"end",
890 std::string name =
"T_strided_slice_with_axes",
892 const size_t src_tensor_dim = x->shape.size();
893 ICHECK(axes.size() <= src_tensor_dim);
894 ICHECK(axes.size() == begin.size() && axes.size() == end.size() && axes.size() == strides.size());
896 std::vector<int64_t> begin_vec, end_vec, strides_vec;
897 std::tie(begin_vec, end_vec, strides_vec) = ConvertToVec(begin, end, strides, slice_mode);
899 auto begin_expr = StridedSliceCanonicalizeBegin(x->shape, begin_vec, strides_vec, axes,
900 begin[0]->dtype, slice_mode);
902 slice_mode, begin_expr);
906 [&](
const Array<tir::Var>& indices) {
907 Array<PrimExpr> real_indices;
908 for (
size_t i = 0; i < out_shape.size(); ++i) real_indices.push_back(indices[i]);
909 for (
size_t i = 0; i < axes.size(); ++i) {
910 auto stride =
make_const(strides[i].dtype(), strides_vec[i]);
911 PrimExpr ind = indices[axes[i].IntValue()] * stride + begin_expr[i];
912 real_indices.Set(axes[i].IntValue(), ind);
914 return x(real_indices);
934 const Array<Integer>& strides, std::string slice_mode =
"end",
935 std::string name =
"T_strided_slice", std::string tag =
kInjective) {
936 size_t src_tensor_dim =
static_cast<size_t>(x->shape.size());
938 for (
size_t i = 0; i < src_tensor_dim; ++i) axes.push_back(i);
939 Array<Integer> begin_full(begin);
940 Array<Integer> end_full(end);
941 Array<Integer> strides_full(strides);
948 for (
size_t i = strides.size(); i < src_tensor_dim; ++i) {
949 strides_full.push_back(one);
951 for (
size_t i = begin.size(); i < src_tensor_dim; ++i) {
952 begin_full.push_back(GetConstInt(strides_full[i]) > 0 ? zero : max_range);
954 for (
size_t i = end.size(); i < src_tensor_dim; ++i) {
955 end_full.push_back(GetConstInt(strides_full[i]) < 0 ? zero : max_range);
975 std::string name =
"T_split_sections",
978 axis +=
static_cast<int>(x->shape.size());
980 ICHECK_LT(axis, x->shape.size()) <<
"axis out of bounds";
982 auto src_axis_size = x->shape[axis];
984 ICHECK_GT(num_sections, 0) <<
"Slice count must be > 0";
986 Array<PrimExpr> split_indices;
987 auto seg_size =
indexdiv(src_axis_size + num_sections - 1, num_sections);
988 for (
int i = 0; i < num_sections; ++i) {
991 split_indices.push_back(seg_size * i);
1011 std::string mode =
"fast", std::string name =
"T_take",
1013 Array<PrimExpr> a_shape = a->shape;
1014 Array<PrimExpr> out_shape = indices->shape;
1016 for (
size_t i = 0; i < a_shape.size(); ++i) {
1017 a_size = a_size * a_shape[i];
1020 if (mode ==
"clip") {
1023 [&](
const Array<Var>& out_index) {
1025 return a(UnravelIndex(idx, a_shape));
1028 }
else if (mode ==
"fast") {
1029 LOG(WARNING) <<
"Fast mode segfaults when there are out-of-bounds indices. "
1030 "Make sure input indices are in bound";
1033 [&](
const Array<Var>& out_index) {
return a(UnravelIndex(indices(out_index), a_shape)); },
1035 }
else if (mode ==
"nan") {
1038 [&](
const Array<Var>& out_index) {
1040 indices(out_index) < 0 || indices(out_index) >= a_size,
1041 tvm::FloatImm(a->dtype, std::numeric_limits<float>::quiet_NaN()), indices(out_index));
1042 return a(UnravelIndex(idx, a_shape));
1048 [&](
const Array<Var>& out_index) {
1049 auto idx =
truncmod(
truncmod(indices(out_index), a_size) + a_size, a_size);
1050 return a(UnravelIndex(idx, a_shape));
1069 int axis, std::string name =
"T_sequence_mask",
1071 ICHECK(axis == 0 || axis == 1) <<
"axis must be either 0 or 1";
1072 ICHECK_EQ(valid_length->shape.size(), 1) <<
"valid_length must have ndim=1, i.e., (batch_size,).";
1073 auto length_dim = data->shape[axis];
1074 auto batch_dim = data->shape[1 - axis];
1075 Array<PrimExpr> out_shape = data->shape;
1078 [&](
const Array<Var>& out_index) {
1079 Array<PrimExpr> len_index;
1080 auto tid = out_index[axis];
1081 auto bid = out_index[1 - axis];
1082 len_index.push_back(bid);
1106 inline Tensor take(
const Tensor& a, Variant<Tensor, PrimExpr> indices,
int batch_dims,
int axis,
1107 std::string mode =
"fast", std::string name =
"T_take",
1110 axis +=
static_cast<int>(a->shape.size());
1112 ICHECK_GE(axis, 0) <<
"axis out of bounds";
1113 ICHECK_LT(axis, a->shape.size()) <<
"axis out of bounds";
1114 auto axis_dim = a->shape[axis];
1115 auto indices_shape = [&]() -> Array<PrimExpr> {
1116 if (
auto tensor = indices.as<
TensorNode>()) {
1117 return tensor->shape;
1123 int indices_len =
static_cast<int>(indices_shape.size());
1125 int batch_dims_ = batch_dims;
1126 if (batch_dims_ != 0) {
1127 ICHECK_GE(batch_dims_, -indices_len) <<
"batch_dims out of bounds";
1128 ICHECK_LE(batch_dims_, indices_len) <<
"batch_dims out of bounds";
1130 if (batch_dims_ < 0) {
1131 batch_dims_ = indices_len + batch_dims_;
1134 ICHECK_LT(batch_dims_, a->shape.size()) <<
"batch_dims out of bounds";
1135 ICHECK_LE(batch_dims_, axis) <<
"batch_dims must be less than or equal to axis";
1136 for (
int i = 0; i < batch_dims_; ++i) {
1137 auto addr1 = a->shape[i];
1138 auto addr2 = indices_shape[i];
1139 auto v1 =
static_cast<IntImm*
>(&addr1)->get()->value;
1140 auto v2 =
static_cast<IntImm*
>(&addr2)->get()->value;
1141 ICHECK_EQ(v1, v2) <<
"a.shape[" << i <<
"] should be equal to indices.shape[" << i <<
"]";
1148 Array<PrimExpr> out_shape;
1149 for (
int i = 0; i < batch_dims_; ++i) {
1150 out_shape.push_back(a->shape[i]);
1152 for (
int i = batch_dims_; i < axis; ++i) {
1153 out_shape.push_back(a->shape[i]);
1155 for (
int i = batch_dims_; i < indices_len; ++i) {
1156 out_shape.push_back(indices_shape[i]);
1158 for (
size_t i = axis + 1; i < a->shape.size(); ++i) {
1159 out_shape.push_back(a->shape[i]);
1162 auto get_index = [&](
const Array<PrimExpr>& indices_position) ->
PrimExpr {
1163 if (
auto tensor = indices.as<
Tensor>()) {
1164 return tensor.value()(indices_position);
1165 }
else if (
auto prim = indices.as<
PrimExpr>()) {
1166 ICHECK_EQ(indices_position.size(), 0);
1167 return prim.value();
1169 LOG(FATAL) <<
"Variant did not contain either allowed type";
1173 if (mode ==
"clip") {
1174 if (batch_dims_ == 0) {
1177 [&](
const Array<Var>& out_index) {
1178 Array<PrimExpr> indices_position;
1179 for (
size_t j = axis; j < static_cast<size_t>(axis + indices_len); ++j) {
1180 indices_position.push_back(out_index[j]);
1182 Array<PrimExpr> real_indices;
1183 for (
size_t j = 0; j < static_cast<size_t>(axis); ++j) {
1184 real_indices.push_back(out_index[j]);
1186 auto idx =
tvm::min(
tvm::max(0, get_index(indices_position)), axis_dim - 1);
1187 real_indices.push_back(idx);
1188 for (
size_t j = axis + indices_len; j < out_index.size(); ++j) {
1189 real_indices.push_back(out_index[j]);
1191 return a(real_indices);
1197 [&](
const Array<Var>& out_index) {
1198 Array<PrimExpr> indices_position;
1199 for (
size_t j = 0; j < static_cast<size_t>(batch_dims_); ++j) {
1200 indices_position.push_back(out_index[j]);
1202 for (
size_t j = axis; j < static_cast<size_t>(axis + indices_len - batch_dims_); ++j) {
1203 indices_position.push_back(out_index[j]);
1205 Array<PrimExpr> real_indices;
1206 for (
size_t j = 0; j < static_cast<size_t>(axis); ++j) {
1207 real_indices.push_back(out_index[j]);
1209 auto idx =
tvm::min(
tvm::max(0, get_index(indices_position)), axis_dim - 1);
1210 real_indices.push_back(idx);
1211 for (
size_t j = axis + indices_len - batch_dims_; j < out_index.size(); ++j) {
1212 real_indices.push_back(out_index[j]);
1214 return a(real_indices);
1218 }
else if (mode ==
"fast") {
1219 LOG(WARNING) <<
"Fast mode segfaults when there are out-of-bounds indices. "
1220 "Make sure input indices are in bound";
1223 [&](
const Array<Var>& out_index) {
1224 Array<PrimExpr> indices_position;
1225 for (
size_t j = axis; j < static_cast<size_t>(axis + indices_len); ++j) {
1226 indices_position.push_back(out_index[j]);
1228 Array<PrimExpr> real_indices;
1229 for (
size_t j = 0; j < static_cast<size_t>(axis); ++j) {
1230 real_indices.push_back(out_index[j]);
1232 real_indices.push_back(get_index(indices_position));
1233 for (
size_t j = axis + indices_len; j < out_index.size(); ++j) {
1234 real_indices.push_back(out_index[j]);
1236 return a(real_indices);
1239 }
else if (mode ==
"nan") {
1242 [&](
const Array<Var>& out_index) {
1243 Array<PrimExpr> indices_position;
1244 for (
size_t j = axis; j < static_cast<size_t>(axis + indices_len); ++j) {
1245 indices_position.push_back(out_index[j]);
1247 Array<PrimExpr> real_indices;
1248 for (
size_t j = 0; j < static_cast<size_t>(axis); ++j) {
1249 real_indices.push_back(out_index[j]);
1251 PrimExpr idx = get_index(indices_position);
1252 real_indices.push_back(idx);
1253 for (
size_t j = axis + indices_len; j < out_index.size(); ++j) {
1254 real_indices.push_back(out_index[j]);
1256 PrimExpr in_bounds = idx >= 0 && idx < axis_dim;
1258 in_bounds, a(real_indices),
1265 [&](
const Array<Var>& out_index) {
1266 Array<PrimExpr> indices_position;
1267 for (
size_t j = axis; j < static_cast<size_t>(axis + indices_len); ++j) {
1268 indices_position.push_back(out_index[j]);
1270 Array<PrimExpr> real_indices;
1271 for (
size_t j = 0; j < static_cast<size_t>(axis); ++j) {
1272 real_indices.push_back(out_index[j]);
1274 auto idx =
truncmod(
truncmod(get_index(indices_position), axis_dim) + axis_dim, axis_dim);
1275 real_indices.push_back(idx);
1276 for (
size_t j = axis + indices_len; j < out_index.size(); ++j) {
1277 real_indices.push_back(out_index[j]);
1279 return a(real_indices);
1297 std::string name =
"T_where", std::string tag =
kBroadcast) {
1298 ICHECK_EQ(x->dtype, y->dtype) <<
"x and y must have the same dtype: " << x->dtype <<
" vs "
1300 auto get_out_shape = [&]() {
1301 auto bh1 = detail::BroadcastShape(x->shape, y->shape);
1302 Array<PrimExpr> common_shape1(bh1.common_shape.begin(), bh1.common_shape.end());
1303 auto bh2 = detail::BroadcastShape(condition->shape, common_shape1);
1304 Array<PrimExpr> common_shape2(bh2.common_shape.begin(), bh2.common_shape.end());
1305 return common_shape2;
1308 auto oshape = get_out_shape();
1310 auto c_bh = detail::BroadcastShape(condition->shape, oshape);
1311 auto x_bh = detail::BroadcastShape(x->shape, oshape);
1312 auto y_bh = detail::BroadcastShape(y->shape, oshape);
1314 auto select = [&](tvm::Array<tvm::tir::Var> ovars) {
1315 auto c = condition(InputIndexFromBroadcast(ovars, condition, c_bh.vars1, c_bh.all_vars));
1316 auto true_val = x(InputIndexFromBroadcast(ovars, x, x_bh.vars1, x_bh.all_vars));
1317 auto false_val = y(InputIndexFromBroadcast(ovars, y, y_bh.vars1, y_bh.all_vars));
1321 return compute(oshape, select, name, tag);
1338 int ndim =
static_cast<int>(x->shape.size());
1339 ICHECK(-ndim - 1 <= axis && axis <= ndim)
1340 <<
"repeat only accepts `axis` in [-data.ndim - 1, data.ndim]"
1341 <<
", but got axis = " << axis <<
", and data.ndim = " << ndim;
1342 ICHECK(repeats >= 1) <<
"repeat only accepts `repeats >= 1`"
1343 <<
", but got repeats = " << repeats;
1348 Array<PrimExpr> new_shape;
1349 for (
size_t i = 0; i < static_cast<size_t>(axis); ++i) {
1350 new_shape.push_back(x->shape[i]);
1352 new_shape.push_back(repeats * x->shape[axis]);
1353 for (
size_t i = axis + 1; i < x->shape.size(); ++i) {
1354 new_shape.push_back(x->shape[i]);
1359 [&](
const Array<Var>& indices) {
1360 Array<PrimExpr> idx;
1361 for (
size_t i = 0; i < static_cast<size_t>(axis); ++i) {
1362 idx.push_back(indices[i]);
1364 idx.push_back(
indexdiv(indices[axis], repeats));
1365 for (
size_t i = axis + 1; i < indices.size(); ++i) {
1366 idx.push_back(indices[i]);
1385 size_t ndim = x->shape.size();
1386 size_t rdim = reps.size();
1387 size_t tdim = (ndim > rdim) ? ndim : rdim;
1388 Array<PrimExpr> data_shape;
1389 Array<PrimExpr> reps_shape;
1390 Array<PrimExpr> new_shape;
1392 for (
size_t i = 0; i < ndim; ++i) {
1393 data_shape.push_back(x->shape[i]);
1394 reps_shape.push_back(reps[i]);
1396 }
else if (ndim > rdim) {
1397 for (
size_t i = 0; i < ndim; ++i) data_shape.push_back(x->shape[i]);
1398 for (
size_t i = 0; i < (ndim - rdim); ++i) reps_shape.push_back(1);
1399 for (
size_t i = 0; i < rdim; ++i) reps_shape.push_back(reps[i]);
1401 for (
size_t i = 0; i < (rdim - ndim); ++i) data_shape.push_back(1);
1402 for (
size_t i = 0; i < ndim; ++i) data_shape.push_back(x->shape[i]);
1403 for (
size_t i = 0; i < rdim; ++i) reps_shape.push_back(reps[i]);
1405 for (
size_t i = 0; i < tdim; ++i) new_shape.push_back(data_shape[i] * reps_shape[i]);
1407 if (is_empty_shape(new_shape)) {
1409 new_shape, [&](
const Array<Var>& indices) {
return tvm::cast(x->dtype, 0); }, name, tag);
1413 [&](
const Array<Var>& indices) {
1414 Array<PrimExpr> idx;
1416 for (
size_t i = 0; i < ndim; ++i) idx.push_back(
indexmod(indices[i], x->shape[i]));
1418 for (
size_t i = 0; i < ndim; ++i)
1419 idx.push_back(
indexmod(indices[rdim - ndim + i], x->shape[i]));
1439 std::string name =
"T_tile", std::string tag =
kBroadcast) {
1440 size_t ndim = x->shape.size();
1441 if (is_empty_shape(new_shape)) {
1443 new_shape, [&](
const Array<Var>& indices) {
return tvm::cast(x->dtype, 0); }, name, tag);
1447 [&](
const Array<Var>& indices) {
1448 Array<PrimExpr> idx;
1450 for (
size_t i = 0; i < ndim; ++i) {
1451 idx.push_back(
indexmod(indices[i], x->shape[i]));
1454 for (
size_t i = 0; i < ndim; ++i) {
1455 idx.push_back(
indexmod(indices[rdim - ndim + i], x->shape[i]));
1476 std::string name =
"T_gather", std::string tag =
kInjective) {
1477 size_t ndim_d = data->shape.size();
1478 size_t ndim_i = indices->shape.size();
1479 ICHECK_GE(ndim_d, 1) <<
"Cannot gather from a scalar.";
1480 ICHECK_EQ(ndim_d, ndim_i);
1485 ICHECK_LT(axis, ndim_d);
1487 size_t indices_dim_i =
static_cast<size_t>(GetConstInt(indices->shape[axis]));
1488 ICHECK_GE(indices_dim_i, 1);
1490 ICHECK(indices->dtype.is_int() || indices->dtype.is_uint());
1492 Array<PrimExpr> out_shape;
1493 for (
size_t i = 0; i < ndim_i; ++i) {
1494 out_shape.push_back(indices->shape[i]);
1499 [&](
const Array<Var>& out_index) {
1500 Array<PrimExpr> indices_position;
1501 for (
size_t i = 0; i < ndim_i; ++i) {
1502 indices_position.push_back(out_index[i]);
1504 Array<PrimExpr> real_indices;
1505 for (
size_t i = 0; i < ndim_i; ++i) {
1506 if (i ==
static_cast<size_t>(axis)) {
1507 real_indices.push_back(indices(indices_position));
1509 real_indices.push_back(indices_position[i]);
1512 return data(real_indices);
1529 std::string name =
"T_gather_nd", std::string tag =
kInjective) {
1530 size_t ndim_d = data->shape.size();
1531 size_t ndim_i = indices->shape.size();
1532 ICHECK_GE(ndim_i, 1) <<
"indices tensor must have at least 1 dimensions";
1533 size_t indices_dim0 =
static_cast<size_t>(GetConstInt(indices->shape[0]));
1534 ICHECK_LE(indices_dim0, ndim_d) <<
"dim 0 of indices tensor must be no more "
1535 <<
"than dimensions of data tensor";
1536 Array<PrimExpr> out_shape;
1537 for (
size_t i = 1; i < ndim_i; ++i) {
1538 out_shape.push_back(indices->shape[i]);
1540 for (
size_t i = indices_dim0 + batch_dims; i < ndim_d; ++i) {
1541 out_shape.push_back(data->shape[i]);
1545 [&](
const Array<Var>& out_index) {
1546 Array<PrimExpr> indices_position;
1547 indices_position.push_back(0);
1548 for (
size_t i = 0; i < ndim_i - 1; ++i) {
1549 indices_position.push_back(out_index[i]);
1551 Array<PrimExpr> real_indices;
1552 for (
size_t i = 0; i < static_cast<size_t>(batch_dims); ++i) {
1553 real_indices.push_back(out_index[i]);
1555 for (
size_t i = 0; i < indices_dim0; ++i) {
1557 if (indices->dtype.is_int() || indices->dtype.is_uint()) {
1558 real_indices.push_back(indices(indices_position));
1563 if (real_indices.size() == ndim_d) {
1564 return data(real_indices);
1566 for (
size_t i = ndim_i - 1; i < out_index.size(); ++i) {
1567 real_indices.push_back(out_index[i]);
1569 return data(real_indices);
1590 bool trans_a =
false,
bool trans_b =
false,
1591 std::string name =
"T_matmul", std::string tag =
kMatMul) {
1592 tvm::Array<tvm::PrimExpr> output_shape{A->shape[trans_a ? 1 : 0], B->shape[trans_b ? 0 : 1]};
1595 return tvm::sum((trans_a ? A[k][i] : A[i][k]) * (trans_b ? B[j][k] : B[k][j]), {k});
1612 std::string name =
"T_tensordot", std::string tag =
kMatMul) {
1613 ICHECK_GE(A->shape.size(), axes);
1614 ICHECK_GE(B->shape.size(), axes);
1616 Array<PrimExpr> output_shape(A->shape.begin(), A->shape.end() + (-axes));
1617 for (
auto it = B->shape.begin() + axes; it != B->shape.end(); ++it) output_shape.push_back(*it);
1619 Array<IterVar> iter_vars;
1620 for (
int i = 0; i < axes; ++i)
1621 iter_vars.push_back(
reduce_axis(
Range(0, B->shape[i]),
"k" + std::to_string(i)));
1623 auto func = [&A, &B, &iter_vars, axes](
const Array<Var>& input_indices) {
1624 Array<PrimExpr> A_indices(input_indices.begin(),
1625 input_indices.begin() + (A->shape.size() - axes));
1626 for (
auto& v : iter_vars) A_indices.push_back(v);
1628 Array<PrimExpr> B_indices;
1629 for (
auto& v : iter_vars) B_indices.push_back(v);
1631 auto it = input_indices.begin() + (A->shape.size() - axes);
1632 for (; it != input_indices.end(); ++it) B_indices.push_back(*it);
1635 if (iter_vars.empty()) {
1636 return A(A_indices) * B(B_indices);
1638 return sum(A(A_indices) * B(B_indices), iter_vars);
1642 return compute(output_shape, func, name, tag);
1658 Array<PrimExpr> B_axes, std::string name =
"T_tensordot",
1660 ICHECK_EQ(A_axes.size(), B_axes.size());
1662 auto A_axes_val = GetConstIntValues(A_axes,
"A_axes");
1663 auto B_axes_val = GetConstIntValues(B_axes,
"B_axes");
1665 Array<PrimExpr> output_shape;
1666 for (
unsigned i = 0; i < A->shape.size(); ++i)
1667 if (std::find(A_axes_val.begin(), A_axes_val.end(), i) == A_axes_val.end())
1668 output_shape.push_back(A->shape[i]);
1669 for (
unsigned i = 0; i < B->shape.size(); ++i)
1670 if (std::find(B_axes_val.begin(), B_axes_val.end(), i) == B_axes_val.end())
1671 output_shape.push_back(B->shape[i]);
1673 Array<IterVar> iter_vars;
1674 for (
unsigned i = 0; i < B_axes_val.size(); ++i)
1675 iter_vars.push_back(
reduce_axis(
Range(0, B->shape[B_axes_val[i]]),
"k" + std::to_string(i)));
1677 auto func = [&A, &B, &iter_vars, A_axes_val, B_axes_val](
const Array<Var>& input_indices) {
1679 Array<PrimExpr> A_indices;
1680 for (
unsigned i = 0; i < A->shape.size(); ++i) {
1681 auto axes_pos = std::find(A_axes_val.begin(), A_axes_val.end(), i);
1682 if (axes_pos == A_axes_val.end()) {
1683 A_indices.push_back(input_indices[idx_input++]);
1685 A_indices.push_back(iter_vars[axes_pos - A_axes_val.begin()]);
1689 Array<PrimExpr> B_indices;
1690 for (
unsigned i = 0; i < B->shape.size(); ++i) {
1691 auto axes_pos = std::find(B_axes_val.begin(), B_axes_val.end(), i);
1692 if (axes_pos == B_axes_val.end()) {
1693 B_indices.push_back(input_indices[idx_input++]);
1695 B_indices.push_back(iter_vars[axes_pos - B_axes_val.begin()]);
1698 return sum(A(A_indices) * B(B_indices), iter_vars);
1700 return compute(output_shape, func, name, tag);
1711 }
else if (is_all_int && analyzer.
CanProveLess(step, 0)) {
1719 num_elem = analyzer.
Simplify(num_elem);
1723 [&](
const Array<Var>& indices) {
return tvm::cast(dtype, start + step * indices[0]); }, name,
1737 inline Array<Tensor>
meshgrid(
const Array<Tensor>& inputs,
const std::string& indexing,
1738 std::string name =
"T_meshgrid", std::string tag =
kInjective) {
1739 const bool cartesian_indexing = indexing ==
"xy" && inputs.size() >= 2;
1740 Array<PrimExpr> out_shape;
1741 for (
size_t i = 0; i < inputs.size(); ++i) {
1742 const int src_index = (cartesian_indexing && i < 2) ? 1 - i : i;
1743 out_shape.push_back(inputs[src_index]->
shape.size() == 0 ? 1 : inputs[src_index]->shape[0]);
1745 Array<Tensor> result;
1746 for (
size_t i = 0; i < inputs.size(); ++i) {
1749 [&](
const Array<Var>& indices) {
1750 const int src_index = (cartesian_indexing && i < 2) ? 1 - i : i;
1751 auto ndim = inputs[i]->GetShape().size();
1752 Array<PrimExpr> real_indices = {};
1754 real_indices = {indices[src_index]};
1756 return inputs[i](real_indices);
1774 const std::string& dst_layout,
1775 const std::string schedule_rule =
"None",
1776 const std::string name =
"T_layout_trans",
1778 Layout src_layout_struct(src_layout);
1779 Layout dst_layout_struct(dst_layout);
1781 if (src_layout_struct.
Equals(dst_layout_struct)) {
1785 ICHECK(src_layout_struct.defined() && dst_layout_struct.defined())
1786 <<
"cannot convert from/to undefined layout";
1789 ICHECK(layout_converter.defined())
1790 <<
"cannot convert from " << src_layout <<
" to " << dst_layout;
1792 Array<PrimExpr> dst_shape = layout_converter.ForwardShape(src->shape);
1794 Map<String, ffi::Any> attrs = {{
"schedule_rule", String(schedule_rule)},
1796 {
"src_layout", String(src_layout)},
1797 {
"dst_layout", String(dst_layout)},
1798 {
"input_shape", src->shape}};
1802 [&](
const Array<Var>& dst_indices) {
1803 Array<PrimExpr> dst_indices_expr(dst_indices.begin(), dst_indices.end());
1804 Array<PrimExpr> src_indices = layout_converter.BackwardIndex(dst_indices_expr);
1806 for (
size_t i = 0; i < src.
ndim(); ++i) {
1807 in_range = in_range && (src_indices[i] < src->shape[i]);
1816 std::vector<std::string>* axes) {
1818 std::string axis =
"";
1819 for (
char c : std::string(layout)) {
1820 if (c >=
'A' && c <=
'z') {
1823 shape->push_back(factor);
1826 }
else if (c >=
'0' && c <=
'9') {
1827 factor = factor * 10 + c -
'0';
1828 if (!axis.empty()) {
1829 axes->push_back(axis);
1833 LOG(FATAL) <<
"Invalid layout " << layout;
1836 if (!axis.empty()) {
1837 axes->push_back(axis);
1852 const String& dst_layout,
1853 const String name =
"T_auto_scheduler_layout_trans",
1855 Array<PrimExpr> src_shape;
1856 std::vector<std::string> src_axes;
1857 Array<PrimExpr> dst_shape;
1858 std::vector<std::string> dst_axes;
1864 [&](
const Array<Var>& dst_indices) {
1865 Array<PrimExpr> dst_indices_expr(dst_indices.begin(), dst_indices.end());
1866 Array<PrimExpr> src_indices;
1867 for (
const std::string& src_axis : src_axes) {
1869 CHECK_EQ(dst_indices_expr.size(), dst_axes.size());
1870 for (
size_t i = 0; i < dst_axes.size(); ++i) {
1871 if (dst_axes[i] == src_axis) {
1872 src_index = src_index * dst_shape[i] + dst_indices_expr[i];
1875 src_indices.push_back(src_index);
1877 return src(src_indices);
1919 const String name =
"T_meta_schedule_layout_trans",
1922 Array<Range> iter_domain;
1923 iter_domain.reserve(src->shape.size());
1924 for (
const PrimExpr& e : src->shape) {
1927 Array<PrimExpr> post_transform_shape = index_map->MapShape(src->shape, &analyzer);
1929 post_transform_shape,
1930 [src, inv = index_map.
Inverse(iter_domain, &analyzer),
1931 &analyzer](
const Array<Var>& indices) ->
PrimExpr {
1932 return src(inv->MapIndices(Array<PrimExpr>{indices.begin(), indices.end()}, &analyzer));
1947 int ndim =
static_cast<int>(src->shape.size());
1948 Array<PrimExpr> out_shape{ndim};
1951 [&](
const Array<Var>& indices) {
1952 auto idx = indices[0];
1954 for (
int i = 0; i < ndim; ++i) {
1971 const std::string& name =
"ndarray_size",
1973 int ndim =
static_cast<int>(src->shape.size());
1974 Array<PrimExpr> out_ndarray_size = {};
1977 [&](
const Array<Var>& indices) {
1979 for (
int i = 0; i < ndim; ++i) {
1980 ret *= src->shape[i];
2002 int depth,
int axis,
const DataType& dtype,
2003 Array<PrimExpr> oshape = Array<PrimExpr>(),
2004 const std::string name =
"T_one_hot",
const std::string tag =
kInjective) {
2005 int true_axis = (axis == -1) ? indices->shape.size() : axis;
2006 if (oshape.size() == 0) {
2007 int ndim = indices->shape.size() + 1;
2008 int indices_index = 0;
2009 for (
int i = 0; i < ndim; i++) {
2010 if (i == true_axis) {
2011 oshape.push_back(
Integer(depth));
2013 oshape.push_back(indices->shape[indices_index++]);
2022 [&](
const Array<Var>& iter_vars) {
2023 Array<Var> indices_indices;
2024 for (
size_t i = 0; i < iter_vars.size(); i++) {
2025 if (
static_cast<int>(i) == true_axis) {
2029 indices_indices.push_back(iter_vars[i]);
2032 auto idx = iter_vars[true_axis];
2033 return tir::Select(indices(indices_indices) == idx, on_value_cast, off_value_cast);
2050 const std::string name =
"T_sparse_to_dense",
2052 ICHECK(sparse_indices->dtype.is_int()) <<
"sparse_indices only accepts integer values";
2053 ICHECK_LE(sparse_indices->shape.size(), 3)
2054 <<
"sparse_indices tensor should be 0D, 1D, or 2D only";
2055 ICHECK_LE(sparse_values->shape.size(), 2) <<
"sparse_values tensor should be 0D or 1D only";
2057 const auto rank_sparse_indices =
static_cast<int>(sparse_indices->shape.size());
2058 Array<PrimExpr> oshape;
2059 for (
auto l : output_shape) {
2060 oshape.push_back(l);
2064 [&](
const Array<Var>& indices) {
2066 if (0 == rank_sparse_indices) {
2068 }
else if (1 == rank_sparse_indices) {
2069 for (
int j = 0; j < GetConstInt(sparse_indices->shape[0]); j++) {
2073 for (
int j = 0; j < GetConstInt(sparse_indices->shape[0]); j++) {
2075 for (
int k = 0; k < GetConstInt(sparse_indices->shape[1]); k++) {
2076 PrimExpr comparision = indices[k] == sparse_indices[j][k];
2077 aggregate_condition = 0 == k ? comparision : aggregate_condition && comparision;
2100 bool super_diag_right_align,
bool sub_diag_right_align,
2101 const std::string name =
"T_matrix_set_diag",
2103 size_t ndim = input->shape.size() - 1;
2105 bool only_one_diagonal = k1 == k2;
2109 [&](
const Array<Var>& iter_vars) {
2110 auto get_diag = [&]() {
2111 Array<PrimExpr> diagonal_indices;
2112 PrimExpr k, offset = 0;
2113 for (size_t i = 0; i < ndim - 1; i++) {
2114 diagonal_indices.push_back(iter_vars[i]);
2116 if (only_one_diagonal) {
2120 k = iter_vars[ndim] - iter_vars[ndim - 1];
2121 diagonal_indices.push_back(k2 - k);
2124 auto get_offset = [&](PrimExpr M, PrimExpr N) {
2126 return diagonal->shape[diagonal->shape.size() - 1] - if_then_else(M < N, M, N);
2128 offset = if_then_else(
2130 super_diag_right_align ? get_offset(input->shape[ndim] - k, input->shape[ndim - 1])
2132 sub_diag_right_align ? get_offset(input->shape[ndim], input->shape[ndim - 1] + k)
2135 diagonal_indices.push_back(if_then_else(k >= 0, iter_vars[ndim - 1], iter_vars[ndim]) +
2137 return diagonal(diagonal_indices);
2141 get_diag(), input(iter_vars)),
2156 const std::string name =
"advanced_index",
2158 ICHECK_LE(indices.size(), data->shape.size()) <<
"too many indices for data!";
2159 Array<PrimExpr> oshape;
2160 Array<PrimExpr> broadcast_shape;
2161 Array<Tensor> bindices;
2163 broadcast_shape = indices[0]->shape;
2164 for (
size_t i = 1; i < indices.size(); ++i) {
2165 auto bh = detail::BroadcastShape(broadcast_shape, indices[i]->
shape);
2166 broadcast_shape = Array<PrimExpr>(bh.common_shape.begin(), bh.common_shape.end());
2168 if (indices.size() == 1) {
2173 for (
size_t i = 0; i < indices.size(); ++i) {
2174 bindices.push_back(
broadcast_to(indices[i], broadcast_shape));
2178 for (
const auto& dim : broadcast_shape) {
2179 oshape.push_back(dim);
2181 for (
size_t i = indices.size(); i < data->
shape.size(); ++i) {
2182 oshape.push_back(data->shape[i]);
2187 [&](
const Array<Var>& iter_var) {
2188 Array<PrimExpr> tensor_indices;
2189 for (
size_t i = 0; i < broadcast_shape.size(); ++i) {
2190 tensor_indices.push_back(iter_var[i]);
2192 Array<PrimExpr> real_indices;
2193 for (
size_t i = 0; i < bindices.size(); ++i) {
2194 real_indices.push_back(bindices[i](tensor_indices));
2196 for (
size_t i = broadcast_shape.size(); i < iter_var.size(); ++i) {
2197 real_indices.push_back(iter_var[i]);
2200 return data(real_indices);
2209 Array<PrimExpr> output_shape,
2210 std::string name =
"T_strided_slice_dynamic",
2212 const size_t num_dynamic_axes = x.
ndim();
2213 ICHECK_EQ(begin.
ndim(), 1);
2214 ICHECK_EQ(end.
ndim(), 1);
2215 ICHECK_EQ(strides.
ndim(), 1);
2216 const auto* len_begin = begin->shape[0].as<
IntImmNode>();
2217 const auto* len_end = end->shape[0].as<
IntImmNode>();
2218 const auto* len_strides = strides->shape[0].as<
IntImmNode>();
2221 ICHECK(len_strides);
2222 ICHECK_EQ(len_begin->value, num_dynamic_axes);
2223 ICHECK_EQ(len_end->
value, num_dynamic_axes);
2224 ICHECK_EQ(len_strides->
value, num_dynamic_axes);
2228 [&](
const Array<tvm::tir::Var>& indices) {
2229 Array<PrimExpr> real_indices;
2230 for (
size_t i = 0; i < num_dynamic_axes; ++i) {
2232 real_indices.push_back(indices[i] * strides(ind) +
tvm::min(begin(ind), x->shape[i] - 1));
2234 return x(real_indices);
Algebra expression simplifications.
Broadcast op constructions.
Managed reference class to FloatImmNode.
Definition: expr.h:557
Constant integer literals in the program.
Definition: expr.h:501
int64_t value
the Internal value.
Definition: expr.h:504
Managed reference class to IntImmNode.
Definition: expr.h:520
Container of constant int that adds more constructors.
Definition: expr.h:612
Reference to PrimExprNode.
Definition: expr.h:129
DataType dtype() const
Definition: expr.h:143
Range container
Definition: expr.h:698
static Range FromMinExtent(PrimExpr min, PrimExpr extent, Span span=Span())
construct a new range with min and extent The corresponding constructor is removed,...
Analyzer that contains bunch of sub-analyzers.
Definition: analyzer.h:636
bool CanProveGreaterEqual(const PrimExpr &expr, int64_t lower_bound)
Whether can we prove expr >= val.
PrimExpr Simplify(const PrimExpr &expr, int steps=2)
Simplify expr.
bool CanProveLess(const PrimExpr &expr, int64_t upper_bound)
Whether can we prove expr < val.
Runtime primitive data type.
Definition: data_type.h:47
static DataType Float(int bits, int lanes=1)
Construct an float type.
Definition: data_type.h:291
bool is_int() const
Definition: data_type.h:190
static DataType Int(int bits, int lanes=1)
Construct an int type.
Definition: data_type.h:274
Node to represent a tensor.
Definition: tensor.h:69
Tensor structure representing a possible input, or intermediate computation result.
Definition: tensor.h:100
size_t ndim() const
Definition: tensor.h:212
Bijective function mapping for data layout transformation. Given two Layout, BijectiveLayout build an...
Definition: data_layout.h:337
Definition: index_map.h:169
IndexMap Inverse(Array< Range > initial_ranges, arith::Analyzer *analyzer) const
Generate the inverse mapping.
Managed reference to LayoutNode.
Definition: data_layout.h:126
bool Equals(const Layout &rhs) const
Whether the two layouts are equal.
Definition: data_layout.h:281
Managed reference to SelectNode.
Definition: expr.h:523
A variable node in the IR.
Definition: var.h:48
String name_hint
The hint to the variable name.
Definition: var.h:54
a named variable in TIR
Definition: var.h:78
Utility functions for handling constants in TVM expressions.
Layout expression to describe the data organization of a tensor. And BijectiveLayout to mapping two d...
Defines a remapping of buffer indices.
Tensor expression language DSL.
Definition: extracted_task.h:33
IterVar reduce_axis(Range dom, std::string name="rv")
Create a new IterVar for reduction operations.
Var var(std::string name_hint, DataType t=DataType::Int(32))
Construct a new Var expression.
Tensor compute(Array< PrimExpr > shape, FCompute fcompute, std::string name="tensor", std::string tag="", Map< String, ffi::Any > attrs={})
Construct a new tensor by computing over shape, using the computation rule: result_tensor[axis] = fco...
PrimExpr make_const(DataType t, ValueType value, Span span=Span())
Make a const value with certain data type.
Definition: op.h:980
DataType DefaultIndexType()
if TVM_INDEX_DEFAULT_I64 is set, return int64, otherwise return int32
Definition: buffer.h:43
PrimExpr make_zero(DataType t, Span span=Span())
Make a const zero expr.
Definition: op.h:994
te::Tensor dynamic_strided_slice(const te::Tensor &x, const te::Tensor &begin, const te::Tensor &end, const te::Tensor &strides, Array< PrimExpr > output_shape, std::string name="T_strided_slice_dynamic", std::string tag=kInjective)
Definition: transform.h:2207
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:1068
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:1528
int64_t StaticCanonicalizeIndex(int64_t index, int64_t extent, int64_t stride)
Definition: transform.h:663
Tensor squeeze(const Tensor &x, Optional< Array< Integer >> 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:411
constexpr auto kBroadcast
Definition: tags.h:36
Tensor sum(const Tensor &data, const Optional< Array< Integer >> &axis, bool keepdims=false, bool atleast1d=false)
Creates an operation that sums array elements over a given axis.
Definition: reduction.h:326
Tensor arange(const PrimExpr &start, const PrimExpr &stop, const PrimExpr &step, DataType dtype, std::string name="T_arange", std::string tag=kInjective)
Definition: transform.h:1703
Tensor strided_slice(const Tensor &x, const Array< Integer > &begin, const Array< Integer > &end, const Array< Integer > &strides, std::string slice_mode="end", std::string name="T_strided_slice", std::string tag=kInjective)
strided_slice of a tensor
Definition: transform.h:933
constexpr auto kInjective
Definition: tags.h:33
Array< Tensor > split_indices_array(const Tensor &x, 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:580
Tensor sliding_window(const Tensor &x, int axis, Array< Integer > window_shape, Array< Integer > strides, std::string name="T_sliding_window", std::string tag="")
Creates an operation to slide a window over the input x.
Definition: transform.h:76
Tensor reshape(const Tensor &x, Array< PrimExpr > newshape, std::string name="T_reshape", std::string tag=kInjective)
Reshape a tensor.
Definition: transform.h:328
Tensor one_hot(const Tensor &indices, const PrimExpr on_value, const PrimExpr off_value, int depth, int axis, const DataType &dtype, Array< PrimExpr > oshape=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:2001
Tensor dynamic_strided_slice(const Tensor &x, const Array< PrimExpr > &begin, const Array< PrimExpr > &end, const 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:764
Tensor meta_schedule_layout_transform(const Tensor &src, const tir::IndexMap &index_map, const String name="T_meta_schedule_layout_trans", const String tag=kInjective)
Transform the meta-schedule generated layout according to TIR's IndexMap.
Definition: transform.h:1918
Array< Tensor > meshgrid(const 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:1737
Tensor tile(const Tensor &x, Array< Integer > reps, std::string name="T_tile", std::string tag=kBroadcast)
Creates an operation to tile elements of an array.
Definition: transform.h:1383
PrimExpr CanonicalizeIndex(PrimExpr index, PrimExpr extent, PrimExpr stride)
Definition: transform.h:672
tvm::te::Tensor broadcast_to(const tvm::te::Tensor &t, const tvm::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
Tensor dyn_tile(const Tensor &x, 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:1438
Tensor adv_index(const Tensor &data, const Array< Tensor > &indices, const std::string name="advanced_index", const std::string tag=kInjective)
Numpy style advanced indexing with tensor.
Definition: transform.h:2155
Tensor concatenate(const 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:475
void parse_auto_scheduler_layout(const String &layout, Array< PrimExpr > *shape, std::vector< std::string > *axes)
Utility function for auto_scheduler_layout_transform.
Definition: transform.h:1815
Tensor cast(const Tensor &x, DataType type, std::string name="T_cast", std::string tag=kElementWise)
Cast each element of x to the given type. If expr is scalar and type is a corresponding vector type,...
Definition: elemwise.h:281
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 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:2048
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:363
Tensor auto_scheduler_layout_transform(const Tensor &src, const String &src_layout, const String &dst_layout, const String name="T_auto_scheduler_layout_trans", const String tag=kInjective)
Transform the auto-scheduler generated layout according to src_layout and dst_layout.
Definition: transform.h:1851
Tensor ndarray_size(const Tensor &src, const DataType &dtype, const std::string &name="ndarray_size", const std::string &tag=kInjective)
Get the size of input tensor.
Definition: transform.h:1970
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:974
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:1773
constexpr auto kMatMul
Definition: tags.h:37
Tensor reverse_sequence(const Tensor &x, const 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
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:1611
Tensor dynamic_strided_slice_with_axes(const Tensor &x, const Array< PrimExpr > &begin, const Array< PrimExpr > &end, const Array< PrimExpr > &strides, const Array< Integer > &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 stack(const 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:534
Tensor strided_slice_with_axes(const Tensor &x, const Array< Integer > &begin, const Array< Integer > &end, const Array< Integer > &strides, const Array< Integer > &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:887
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:1010
PrimExpr DynamicCanonicalizeIndex(PrimExpr index, PrimExpr extent, PrimExpr stride)
Definition: transform.h:645
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:1589
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:2099
Tensor transpose(const Tensor &x, Optional< Array< Integer >> opt_axes, std::string name="T_transpose", std::string tag=kInjective)
Permute the dimensions of an array.
Definition: transform.h:204
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:1296
Tensor shape(const Tensor &src, DataType dtype, const std::string name="T_shape", const std::string tag=kInjective)
Get the shape of input tensor.
Definition: transform.h:1945
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:1475
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:1336
Array< PrimExpr > StridedSliceOutputShape(const Array< PrimExpr > &ishape, const Array< Integer > &begin, const Array< Integer > &end, const Array< Integer > &strides, const Array< Integer > &axes, const std::string &slice_mode)
Calculate the output shape of strided_slice, the entry point for Relax type relation.
Definition: transform.h:859
Performance counters for profiling via the PAPI library.
Definition: analyzer.h:37
PrimExpr ceildiv(PrimExpr a, PrimExpr b, Span span=Span())
compute ceil(a / b)
PrimExpr ret(PrimExpr value, Span span=Span())
Return the value.
PrimExpr max(PrimExpr a, PrimExpr b, Span span=Span())
take maximum of two values
PrimExpr truncmod(PrimExpr a, PrimExpr b, Span span=Span())
compute the remainder of truncdiv
PrimExpr if_then_else(PrimExpr cond, PrimExpr true_value, PrimExpr false_value, Span span=Span())
Conditional expression.
PrimExpr cast(const DataType &t, PrimExpr value, Span span=Span())
cast value to type.
PrimExpr max_value(const DataType &dtype, Span span=Span())
PrimExpr ceil(PrimExpr x, Span span=Span())
Calculate ceil(x)
PrimExpr indexdiv(PrimExpr a, PrimExpr b, Span span=Span())
compute floor(a / b) where a and b are non-negative.
PrimExpr min(PrimExpr a, PrimExpr b, Span span=Span())
take minimum of two values
PrimExpr indexmod(PrimExpr a, PrimExpr b, Span span=Span())
compute the remainder floor(a / b) where a and b are non-negative.
PrimExpr floordiv(PrimExpr a, PrimExpr b, Span span=Span())
compute floor(a / b)
PrimExpr sum(PrimExpr source, Array< tir::IterVar > axis, Array< PrimExpr > init={}, Span span=Span())
sum of source expression over axis
Operation node can generate one or multiple Tensors.
Index ravel and unraval operations.
Utility functions for strided_slice op.
Utility functions for handling tensor.
Common operators defined for Expr.