IndexingUtils.h 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. #pragma once
  2. #include <ATen/ExpandUtils.h>
  3. #include <ATen/native/CanUse32BitIndexMath.h>
  4. #include <ATen/native/TensorIterator.h>
  5. #include <ATen/core/IListRef.h>
  6. #include <c10/util/irange.h>
  7. namespace at { namespace native {
  8. [[noreturn]]
  9. static void invalid_mask(const Tensor & self, int64_t idx, const Tensor & mask, int64_t maskIdx) {
  10. TORCH_CHECK_INDEX(false, "The shape of the mask ", mask.sizes(), " at index ", maskIdx,
  11. " does not match the shape of the indexed tensor ", self.sizes(), " at index ", idx);
  12. }
  13. static C10_UNUSED std::vector<Tensor> expandTensors(const Tensor & self, IOptTensorListRef indices) {
  14. // If indices come in as ByteTensor or BoolTensor (masks), expand them into the equivalent indexing by LongTensors
  15. std::vector<Tensor> result;
  16. for (const auto& index_opt : indices) {
  17. if (!index_opt.has_value()) {
  18. result.emplace_back();
  19. } else {
  20. const auto& index = *index_opt;
  21. if (index.scalar_type() == kByte || index.scalar_type() == kBool) {
  22. if (index.scalar_type() == kByte) {
  23. TORCH_WARN("indexing with dtype torch.uint8 is now deprecated," \
  24. " please use a dtype torch.bool instead.");
  25. }
  26. // The sizes of the ByteTensor mask or bool tensor must match the sizes of the
  27. // corresponding dimensions in self
  28. for (const auto j : c10::irange(index.dim())) {
  29. int64_t srcIdx = result.size() + j;
  30. if (index.size(j) != self.size(srcIdx)) {
  31. invalid_mask(self, srcIdx, index, j);
  32. }
  33. }
  34. // Replace with nonzeros
  35. auto nonzero = index.nonzero();
  36. for (const auto j : c10::irange(index.dim())) {
  37. result.emplace_back(nonzero.select(1, j));
  38. }
  39. } else {
  40. result.emplace_back(std::move(index));
  41. }
  42. }
  43. }
  44. return result;
  45. }
  46. static C10_UNUSED void checkIndexTensorTypes(IOptTensorListRef indices, bool allow_int=false) {
  47. for (const auto& tensor : indices) {
  48. if (tensor.has_value() && tensor->defined()) {
  49. auto scalarType = tensor->scalar_type();
  50. if (allow_int) {
  51. if (scalarType != kLong && scalarType != kByte && scalarType != kBool && scalarType != kInt) {
  52. TORCH_CHECK_INDEX(false, "tensors used as indices must be long, int, byte or bool tensors");
  53. }
  54. } else {
  55. if (scalarType != kLong && scalarType != kByte && scalarType != kBool) {
  56. TORCH_CHECK_INDEX(false, "tensors used as indices must be long, byte or bool tensors");
  57. }
  58. }
  59. }
  60. }
  61. }
  62. inline torch::List<c10::optional<Tensor>> toListOfOptionalTensors(ArrayRef<Tensor> list) {
  63. torch::List<c10::optional<Tensor>> result;
  64. result.reserve(list.size());
  65. for (const Tensor& a : list) {
  66. result.push_back(a);
  67. }
  68. return result;
  69. }
  70. inline torch::List<c10::optional<Tensor>> toListOfOptionalTensors(ArrayRef<IValue> list) {
  71. torch::List<c10::optional<Tensor>> result;
  72. result.reserve(list.size());
  73. for (const IValue& a : list) {
  74. result.push_back(a.isTensor() ? c10::optional<Tensor>(a.toTensor()) : c10::optional<Tensor>());
  75. }
  76. return result;
  77. }
  78. static C10_UNUSED bool hasContiguousSubspace(TensorList tl) {
  79. // true if all the non-null tensors are adjacent
  80. auto isDefined = [](const Tensor & tensor){ return tensor.defined(); };
  81. auto isNull = [](const Tensor & tensor){ return !tensor.defined(); };
  82. auto start = std::find_if(tl.begin(), tl.end(), isDefined);
  83. auto stop = std::find_if(tl.rbegin(), tl.rend(), isDefined);
  84. auto it = std::find_if(start, stop.base(), isNull);
  85. return it == stop.base();
  86. }
  87. // Transposes the tensor and indices together so that all the non-null indices
  88. // index the first k dimensions of the tensor. Returns the transposed tensor
  89. // and the reordered indices. For example:
  90. // transposeToFront(tensor, {nullptr, a, nullptr, b})
  91. // returns
  92. // tensor.permute([1, 3, 0, 2]), {a, b, nullptr, nullptr}
  93. static C10_UNUSED std::tuple<Tensor, std::vector<Tensor>>
  94. transposeToFront(Tensor self, TensorList indices) {
  95. std::vector<int64_t> dims;
  96. std::vector<Tensor> transposedIndices;
  97. dims.reserve(self.dim());
  98. for (const auto i : c10::irange(self.dim())) {
  99. if (indices[i].defined()) {
  100. dims.push_back(i);
  101. transposedIndices.emplace_back(indices[i]);
  102. }
  103. }
  104. for (const auto i : c10::irange(self.dim())) {
  105. if (!indices[i].defined()) {
  106. dims.push_back(i);
  107. transposedIndices.emplace_back();
  108. }
  109. }
  110. return std::make_tuple(self.permute(dims), std::move(transposedIndices));
  111. }
  112. inline std::tuple<Tensor, std::vector<Tensor>, std::vector<int64_t>>
  113. transposeToFrontAndInvPerm(Tensor self, TensorList indices) {
  114. std::vector<int64_t> dims;
  115. std::vector<int64_t> invPerm;
  116. std::vector<Tensor> transposedIndices;
  117. dims.reserve(self.dim());
  118. invPerm.resize(self.dim());
  119. for (const auto i : c10::irange(self.dim())) {
  120. if (indices[i].defined()) {
  121. dims.push_back(i);
  122. transposedIndices.emplace_back(indices[i]);
  123. }
  124. }
  125. for (const auto i : c10::irange(self.dim())) {
  126. if (!indices[i].defined()) {
  127. dims.push_back(i);
  128. transposedIndices.emplace_back();
  129. }
  130. }
  131. for (const auto i : c10::irange(self.dim())) {
  132. invPerm[dims[i]] = i;
  133. }
  134. return std::make_tuple(self.permute(dims), std::move(transposedIndices), std::move(invPerm));
  135. }
  136. struct AdvancedIndex {
  137. AdvancedIndex(const Tensor& src, TensorList indices);
  138. Tensor src;
  139. std::vector<Tensor> indices;
  140. DimVector indexed_sizes;
  141. DimVector indexed_strides;
  142. int64_t dims_before;
  143. int64_t dims_after;
  144. };
  145. }}