ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
AdvancedIndexing.h
Go to the documentation of this file.
1 // ----------------------------------------------------------------------------
2 // - CloudViewer: www.cloudViewer.org -
3 // ----------------------------------------------------------------------------
4 // Copyright (c) 2018-2024 www.cloudViewer.org
5 // SPDX-License-Identifier: MIT
6 // ----------------------------------------------------------------------------
7 
8 #pragma once
9 
10 #include <vector>
11 
12 #include "cloudViewer/Macro.h"
16 
17 namespace cloudViewer {
18 namespace core {
19 
22 public:
24  const std::vector<Tensor>& index_tensors)
25  : tensor_(tensor), index_tensors_(ExpandBoolTensors(index_tensors)) {
26  RunPreprocess();
27  }
28 
29  inline Tensor GetTensor() const { return tensor_; }
30 
31  inline std::vector<Tensor> GetIndexTensors() const {
32  return index_tensors_;
33  }
34 
35  inline SizeVector GetOutputShape() const { return output_shape_; }
36 
37  inline SizeVector GetIndexedShape() const { return indexed_shape_; }
38 
39  inline SizeVector GetIndexedStrides() const { return indexed_strides_; }
40 
44  static bool IsIndexSplittedBySlice(
45  const std::vector<Tensor>& index_tensors);
46 
49  static std::pair<Tensor, std::vector<Tensor>> ShuffleIndexedDimsToFront(
50  const Tensor& tensor, const std::vector<Tensor>& index_tensors);
51 
54  static std::pair<std::vector<Tensor>, SizeVector>
55  ExpandToCommonShapeExceptZeroDim(const std::vector<Tensor>& index_tensors);
56 
57  // Replace indexed dimensions with stride 0 and the size of the result
58  // tensor.
59  //
60  // The offset in these dimensions is computed by the kernel using
61  // the index tensor's values and the stride of the tensor. The new shape is
62  // not meaningful. It's used to make the shape compatible with the result
63  // tensor.
64  //
65  // Effectively, we throw away the tensor's shape and strides for the sole
66  // purpose of element-wise iteration for the Indexer. The tensor's original
67  // strides are stored in indexed_shape_ and indexed_strides_,
68  // which are passed to fancy indexing kernels.
69  static Tensor RestrideTensor(const Tensor& tensor,
70  int64_t dims_before,
71  int64_t dims_indexed,
72  SizeVector replacement_shape);
73 
74  // Add dimensions of size 1 to an index tensor so that it can be broadcast
75  // to the result shape and iterated over element-wise like the result tensor
76  // and the restrided src.
77  static Tensor RestrideIndexTensor(const Tensor& index_tensor,
78  int64_t dims_before,
79  int64_t dims_after);
80 
81 protected:
83  void RunPreprocess();
84 
86  static std::vector<Tensor> ExpandBoolTensors(
87  const std::vector<Tensor>& index_tensors);
88 
92 
94  std::vector<Tensor> index_tensors_;
95 
98 
102 
106 };
107 
118 public:
119  enum class AdvancedIndexerMode { SET, GET };
120 
122  const Tensor& dst,
123  const std::vector<Tensor>& index_tensors,
124  const SizeVector& indexed_shape,
125  const SizeVector& indexed_strides,
126  AdvancedIndexerMode mode)
127  : mode_(mode) {
128  if (indexed_shape.size() != indexed_strides.size()) {
130  "Internal error: indexed_shape's ndim {} does not equal to "
131  "indexed_strides' ndim {}",
132  indexed_shape.size(), indexed_strides.size());
133  }
134  num_indices_ = indexed_shape.size();
135 
136  // Initialize Indexer
137  std::vector<Tensor> inputs;
138  inputs.push_back(src);
139  for (const Tensor& index_tensor : index_tensors) {
140  if (index_tensor.NumDims() != 0) {
141  inputs.push_back(index_tensor);
142  }
143  }
144  indexer_ = Indexer({inputs}, dst, DtypePolicy::NONE);
145 
146  // Fill shape and strides
147  if (num_indices_ != static_cast<int64_t>(indexed_strides.size())) {
149  "Internal error: indexed_shape's ndim {} does not equal to "
150  "indexd_strides' ndim {}",
151  num_indices_, indexed_strides.size());
152  }
153  for (int64_t i = 0; i < num_indices_; ++i) {
154  indexed_shape_[i] = indexed_shape[i];
155  indexed_strides_[i] = indexed_strides[i];
156  }
157 
158  // Check dtypes
159  if (src.GetDtype() != dst.GetDtype()) {
161  "src's dtype {} is not the same as dst's dtype {}.",
162  src.GetDtype().ToString(), dst.GetDtype().ToString());
163  }
165  }
166 
168  int64_t workload_idx) const {
169  char* ptr = indexer_.GetInputPtr(0, workload_idx);
170  ptr += GetIndexedOffset(workload_idx) * element_byte_size_ *
172  return ptr;
173  }
174 
176  int64_t workload_idx) const {
177  char* ptr = indexer_.GetOutputPtr(workload_idx);
178  ptr += GetIndexedOffset(workload_idx) * element_byte_size_ *
180  return ptr;
181  }
182 
183  inline CLOUDVIEWER_HOST_DEVICE int64_t
184  GetIndexedOffset(int64_t workload_idx) const {
185  int64_t offset = 0;
186  for (int64_t i = 0; i < num_indices_; ++i) {
187  int64_t index = *(reinterpret_cast<int64_t*>(
188  indexer_.GetInputPtr(i + 1, workload_idx)));
189  CLOUDVIEWER_ASSERT(index >= -indexed_shape_[i] &&
190  index < indexed_shape_[i] &&
191  "Index out of bounds.");
192  index += indexed_shape_[i] * (index < 0);
193  offset += index * indexed_strides_[i];
194  }
195  return offset;
196  }
197 
198  int64_t NumWorkloads() const { return indexer_.NumWorkloads(); }
199 
200 protected:
203  int64_t num_indices_;
207 };
208 
209 } // namespace core
210 } // namespace cloudViewer
#define CLOUDVIEWER_HOST_DEVICE
Definition: CUDAUtils.h:44
int offset
#define CLOUDVIEWER_ASSERT(...)
Definition: Macro.h:51
This class is based on PyTorch's aten/src/ATen/native/Indexing.cpp.
std::vector< Tensor > index_tensors_
The processed index tensors.
std::vector< Tensor > GetIndexTensors() const
void RunPreprocess()
Preprocess tensor and index tensors.
static std::pair< std::vector< Tensor >, SizeVector > ExpandToCommonShapeExceptZeroDim(const std::vector< Tensor > &index_tensors)
static std::vector< Tensor > ExpandBoolTensors(const std::vector< Tensor > &index_tensors)
Expand boolean tensor to integer index.
static bool IsIndexSplittedBySlice(const std::vector< Tensor > &index_tensors)
static Tensor RestrideIndexTensor(const Tensor &index_tensor, int64_t dims_before, int64_t dims_after)
static std::pair< Tensor, std::vector< Tensor > > ShuffleIndexedDimsToFront(const Tensor &tensor, const std::vector< Tensor > &index_tensors)
AdvancedIndexPreprocessor(const Tensor &tensor, const std::vector< Tensor > &index_tensors)
static Tensor RestrideTensor(const Tensor &tensor, int64_t dims_before, int64_t dims_indexed, SizeVector replacement_shape)
CLOUDVIEWER_HOST_DEVICE char * GetOutputPtr(int64_t workload_idx) const
CLOUDVIEWER_HOST_DEVICE int64_t GetIndexedOffset(int64_t workload_idx) const
CLOUDVIEWER_HOST_DEVICE char * GetInputPtr(int64_t workload_idx) const
AdvancedIndexer(const Tensor &src, const Tensor &dst, const std::vector< Tensor > &index_tensors, const SizeVector &indexed_shape, const SizeVector &indexed_strides, AdvancedIndexerMode mode)
std::string ToString() const
Definition: Dtype.h:65
int64_t ByteSize() const
Definition: Dtype.h:59
CLOUDVIEWER_HOST_DEVICE char * GetInputPtr(int64_t input_idx, int64_t workload_idx) const
Definition: Indexer.h:406
CLOUDVIEWER_HOST_DEVICE char * GetOutputPtr(int64_t workload_idx) const
Definition: Indexer.h:438
int64_t NumWorkloads() const
Definition: Indexer.cpp:406
Dtype GetDtype() const
Definition: Tensor.h:1164
#define LogError(...)
Definition: Logging.h:60
static constexpr int64_t MAX_DIMS
Definition: Indexer.h:38
Generic file read and write utility for python interface.