ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
Tensor.cpp
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 
9 
10 #include <Logging.h>
11 #include <Optional.h>
12 
13 #include <numeric>
14 #include <sstream>
15 
17 #include "cloudViewer/core/Blob.h"
22 #include "cloudViewer/core/Dtype.h"
40 
41 namespace cloudViewer {
42 namespace core {
43 
45  if (dtype == core::Float32) return DLDataTypeCode::kDLFloat;
46  if (dtype == core::Float64) return DLDataTypeCode::kDLFloat;
47  if (dtype == core::Int8) return DLDataTypeCode::kDLInt;
48  if (dtype == core::Int16) return DLDataTypeCode::kDLInt;
49  if (dtype == core::Int32) return DLDataTypeCode::kDLInt;
50  if (dtype == core::Int64) return DLDataTypeCode::kDLInt;
51  if (dtype == core::UInt8) return DLDataTypeCode::kDLUInt;
52  if (dtype == core::UInt16) return DLDataTypeCode::kDLUInt;
53  if (dtype == core::UInt32) return DLDataTypeCode::kDLUInt;
54  if (dtype == core::UInt64) return DLDataTypeCode::kDLUInt;
55  if (dtype == core::Bool) return DLDataTypeCode::kDLBool;
56  utility::LogError("Unsupported data type");
57  return DLDataTypeCode();
58 }
59 
60 static Dtype DLDataTypeToDtype(const DLDataType& dltype) {
61  if (dltype.lanes != 1) {
62  utility::LogError("Only supports lanes == 1, but lanes == {}",
63  dltype.lanes);
64  }
65  switch (dltype.code) {
67  return core::Bool;
68  break;
70  switch (dltype.bits) {
71  case 8:
72  return core::UInt8;
73  case 16:
74  return core::UInt16;
75  case 32:
76  return core::UInt32;
77  case 64:
78  return core::UInt64;
79  default:
80  utility::LogError("Unsupported kDLUInt bits {}",
81  dltype.bits);
82  }
83  break;
85  switch (dltype.bits) {
86  case 8:
87  return core::Int8;
88  case 16:
89  return core::Int16;
90  case 32:
91  return core::Int32;
92  case 64:
93  return core::Int64;
94  default:
95  utility::LogError("Unsupported kDLInt bits {}",
96  dltype.bits);
97  }
98  break;
100  switch (dltype.bits) {
101  case 32:
102  return core::Float32;
103  case 64:
104  return core::Float64;
105  default:
106  utility::LogError("Unsupported kDLFloat bits {}",
107  dltype.bits);
108  }
109  break;
110  default:
111  utility::LogError("Unsupported dtype code {}", dltype.code);
112  }
113  return core::Undefined;
114 }
115 
116 namespace {
117 // Adds version information for DLManagedTensorVersioned.
118 // This is a no-op for the other types.
119 template <class T>
120 void fillVersion(T& tensor) {}
121 
122 template <>
123 void fillVersion<DLManagedTensorVersioned>(DLManagedTensorVersioned& tensor) {
124  tensor.flags = 0;
127 }
128 
129 } // namespace
130 
132 template <typename DLMT>
134 private:
135  Open3DDLManagedTensor(const Tensor& o3d_tensor) {
136  o3d_tensor_ = o3d_tensor;
137 
138  // Prepare dl_device
139  DLDevice dl_device = getDLPackDevice(o3d_tensor_);
140 
141  // Prepare dl_data_type
142  DLDataType dl_data_type;
143  Dtype dtype = o3d_tensor_.GetDtype();
144 
145  dl_data_type.code = DtypeToDLDataTypeCode(dtype);
146  dl_data_type.bits = static_cast<uint8_t>(dtype.ByteSize() * 8);
147  dl_data_type.lanes = 1;
148 
149  // Prepare dl_tensor, this uses dl_device_type, dl_device and
150  // dl_data_type prepared above.
151  DLTensor dl_tensor;
152  // Not Blob's data pointer.
153  dl_tensor.data = const_cast<void*>(o3d_tensor_.GetDataPtr());
154  dl_tensor.device = dl_device;
155  dl_tensor.ndim = static_cast<int>(o3d_tensor_.GetShape().size());
156  dl_tensor.dtype = dl_data_type;
157  // The shape pointer is alive for the lifetime of Open3DDLManagedTensor.
158  dl_tensor.shape =
159  const_cast<int64_t*>(o3d_tensor_.GetShapeRef().data());
160  // The strides pointer is alive for the lifetime of
161  // Open3DDLManagedTensor.
162  dl_tensor.strides =
163  const_cast<int64_t*>(o3d_tensor_.GetStridesRef().data());
164  dl_tensor.byte_offset = 0;
165 
166  fillVersion(dl_managed_tensor_);
167  dl_managed_tensor_.manager_ctx = this;
168  dl_managed_tensor_.deleter = &Open3DDLManagedTensor::Deleter;
169  dl_managed_tensor_.dl_tensor = dl_tensor;
170  }
171 
172  Tensor o3d_tensor_;
173  DLMT dl_managed_tensor_;
174 
175 public:
181  static DLMT* Create(const Tensor& o3d_tensor) {
182  Open3DDLManagedTensor* o3d_dl_tensor =
183  new Open3DDLManagedTensor(o3d_tensor);
184  return &o3d_dl_tensor->dl_managed_tensor_;
185  }
186 
187  static DLDevice getDLPackDevice(const Tensor& o3d_tensor) {
188  // Prepare dl_device_type
189  DLDeviceType dl_device_type;
190  Device device = o3d_tensor.GetDevice();
191  switch (device.GetType()) {
193  dl_device_type = DLDeviceType::kDLCPU;
194  break;
196  dl_device_type = DLDeviceType::kDLCUDA;
197  break;
199  dl_device_type = DLDeviceType::kDLOneAPI;
200  break;
201  default:
202  utility::LogError("ToDLPack: unsupported device type {}",
203  device.ToString());
204  }
205  return DLDevice{dl_device_type, device.GetID()};
206  }
207 
208  static void Deleter(DLMT* arg) {
209  delete static_cast<Open3DDLManagedTensor*>(arg->manager_ctx);
210  }
211 };
212 // Explicitly instantiate the template above for both classes.
213 template class Open3DDLManagedTensor<DLManagedTensor>; // DLPack v0.x
214 template class Open3DDLManagedTensor<DLManagedTensorVersioned>; // DLPack v1.x
215 
217  Tensor* tensor_;
218  int64_t index_;
219  Tensor tensor_slice_; // Stores temporary tensor slice with shared memory
220  // as the original tensor. This allows taking the &
221  // of the tensor for Iterator::operator->.
222 };
223 
224 Tensor::Iterator::Iterator(pointer tensor, int64_t index)
225  : impl_(std::make_unique<Impl>()) {
226  impl_->tensor_ = tensor;
227  impl_->index_ = index;
228 }
229 
231  : impl_(std::make_unique<Impl>()) {
232  impl_->tensor_ = other.impl_->tensor_;
233  impl_->index_ = other.impl_->index_;
234 }
235 
236 // Empty destructor since Impl is incomplete type in Tensor.h.
237 // https://stackoverflow.com/a/34073093/1255535
239 
241  return impl_->tensor_->operator[](impl_->index_);
242 }
243 
245  impl_->tensor_slice_ = impl_->tensor_->operator[](impl_->index_);
246  return &impl_->tensor_slice_;
247 }
248 
250  impl_->index_++;
251  return *this;
252 }
253 
255  Iterator tmp(impl_->tensor_, impl_->index_);
256  impl_->index_++;
257  return tmp;
258 }
259 
261  return impl_->tensor_ == other.impl_->tensor_ &&
262  impl_->index_ == other.impl_->index_;
263 }
264 
266  return !(*this == other);
267 }
268 
270  if (NumDims() == 0) {
271  utility::LogError("Cannot iterate a scalar (0-dim) tensor.");
272  }
273  return Iterator(this, 0);
274 }
275 
277  if (NumDims() == 0) {
278  utility::LogError("Cannot iterate a scalar (0-dim) tensor.");
279  }
280  return Iterator(this, shape_[0]);
281 }
282 
284  const Tensor* tensor_;
285  int64_t index_;
286  Tensor tensor_slice_; // Stores temporary tensor slice with shared memory
287  // as the original tensor. This allows taking the &
288  // of the tensor for ConstIterator::operator->.
289 };
290 
292  : impl_(std::make_unique<Impl>()) {
293  impl_->tensor_ = tensor;
294  impl_->index_ = index;
295 }
296 
298  : impl_(std::make_unique<Impl>()) {
299  impl_->tensor_ = other.impl_->tensor_;
300  impl_->index_ = other.impl_->index_;
301 }
302 
303 // Empty destructor since Impl is incomplete type in Tensor.h.
304 // https://stackoverflow.com/a/34073093/1255535
306 
308  return impl_->tensor_->operator[](impl_->index_);
309 }
310 
312  impl_->tensor_slice_ = impl_->tensor_->operator[](impl_->index_);
313  return &impl_->tensor_slice_;
314 }
315 
317  impl_->index_++;
318  return *this;
319 }
320 
322  ConstIterator tmp(impl_->tensor_, impl_->index_);
323  impl_->index_++;
324  return tmp;
325 }
326 
328  const Tensor::ConstIterator& other) const {
329  return impl_->tensor_ == other.impl_->tensor_ &&
330  impl_->index_ == other.impl_->index_;
331 }
332 
334  const Tensor::ConstIterator& other) const {
335  return !(*this == other);
336 }
337 
339  if (NumDims() == 0) {
340  utility::LogError("Cannot iterate a scalar (0-dim) tensor.");
341  }
342  return ConstIterator(this, 0);
343 }
344 
346  if (NumDims() == 0) {
347  utility::LogError("Cannot iterate a scalar (0-dim) tensor.");
348  }
349  return ConstIterator(this, shape_[0]);
350 }
351 
352 // Equivalent to `Tensor& operator=(const Tensor& other) & = default;`.
353 // Manual implentaiton is need to avoid MSVC bug (error C2580: multiple
354 // versions of a defaulted special member functions are not allowed.)
355 Tensor& Tensor::operator=(const Tensor& other) & {
356  shape_ = other.shape_;
357  strides_ = other.strides_;
358  dtype_ = other.dtype_;
359  blob_ = other.blob_;
360  data_ptr_ = other.data_ptr_;
361  return *this;
362 }
363 
364 // Equivalent to `Tensor& operator=(Tensor&& other) & = default;`.
365 // Manual implentaiton is need to avoid MSVC bug (error C2580: multiple
366 // versions of a defaulted special member functions are not allowed.)
368  shape_ = other.shape_;
369  strides_ = other.strides_;
370  dtype_ = other.dtype_;
371  blob_ = other.blob_;
372  data_ptr_ = other.data_ptr_;
373  return *this;
374 }
375 
377 Tensor& Tensor::operator=(const Tensor& other) && {
378  kernel::Copy(other, *this);
379  return *this;
380 }
381 
384  kernel::Copy(other, *this);
385  return *this;
386 }
387 
389  if (dtype_.ByteSize() != dtype.ByteSize()) {
391  "Cannot reinterpret cast between data-types of different "
392  "sizes. Expected data-type of {} bytes ({}), but got "
393  "data-type {} of {} bytes.",
394  dtype_.ByteSize(), dtype_.ToString(), dtype.ToString(),
395  dtype.ByteSize());
396  }
397  return Tensor(shape_, strides_, data_ptr_, dtype, blob_);
398 }
399 
401  Dtype dtype,
402  const Device& device) {
403  return Tensor(shape, dtype, device);
404 }
405 
407  Dtype dtype,
408  const Device& device) {
409  return Full(shape, 0, dtype, device);
410 }
411 
413  Dtype dtype,
414  const Device& device) {
415  return Full(shape, 1, dtype, device);
416 }
417 
418 Tensor Tensor::Eye(int64_t n, Dtype dtype, const Device& device) {
419  Tensor eye = Tensor::Zeros({n, n}, dtype, device);
420  eye.AsStrided({n}, {eye.strides_[0] + eye.strides_[1]}).Fill(1);
421  return eye;
422 }
423 
424 Tensor Tensor::Diag(const Tensor& input) {
425  const SizeVector& shape = input.GetShape();
426  if (shape.size() != 1) {
427  utility::LogError("Input tensor must be 1D, but got shape {}.",
428  input.shape_.ToString());
429  }
430  int64_t n = shape[0];
431  Tensor diag = Tensor::Zeros({n, n}, input.GetDtype(), input.GetDevice());
432  diag.AsStrided({n}, {diag.strides_[0] + diag.strides_[1]}) = input;
433  return diag;
434 }
435 
437  const Scalar stop,
438  const Scalar step,
439  const Dtype dtype,
440  const Device& device) {
441  start.AssertSameScalarType(stop,
442  "start must have the same scalar type as stop.");
443  start.AssertSameScalarType(step,
444  "start must have the same scalar type as step.");
445 
446  if (step.Equal(0)) {
447  utility::LogError("Step cannot be 0.");
448  }
449  if (stop.Equal(start)) {
450  return Tensor({0}, dtype, device);
451  }
452 
453  Tensor t_start;
454  Tensor t_stop;
455  Tensor t_step;
456  DISPATCH_DTYPE_TO_TEMPLATE(dtype, [&]() {
457  t_start = Tensor::Full({}, start.To<scalar_t>(), dtype, device);
458  t_stop = Tensor::Full({}, stop.To<scalar_t>(), dtype, device);
459  t_step = Tensor::Full({}, step.To<scalar_t>(), dtype, device);
460  });
461 
462  return kernel::Arange(t_start, t_stop, t_step);
463 }
464 
466  // TODO: Unoptimized with ai. Can be improved when negative step in Slice is
467  // implemented.
468  int64_t n = NumElements();
469  Tensor reverse_idx = Tensor::Arange(n - 1, -1, -1);
470  return View({n}).IndexGet({reverse_idx}).View(GetShape());
471 }
472 
473 Tensor Tensor::GetItem(const TensorKey& tk) const {
475  return IndexExtract(0, tk.GetIndex());
476  } else if (tk.GetMode() == TensorKey::TensorKeyMode::Slice) {
477  if (NumDims() == 0) {
478  utility::LogError("Cannot slice a scalar (0-dim) tensor.");
479  }
480  TensorKey tk_new = tk.InstantiateDimSize(shape_[0]);
481  return Slice(0, tk_new.GetStart(), tk_new.GetStop(), tk_new.GetStep());
482  } else if (tk.GetMode() == TensorKey::TensorKeyMode::IndexTensor) {
483  return IndexGet({tk.GetIndexTensor()});
484  } else {
485  utility::LogError("Internal error: wrong TensorKeyMode.");
486  }
487 }
488 
489 Tensor Tensor::GetItem(const std::vector<TensorKey>& tks) const {
490  if (std::any_of(tks.begin(), tks.end(), [](const TensorKey& tk) {
491  return tk.GetMode() == TensorKey::TensorKeyMode::IndexTensor;
492  })) {
493  // If tks contains one or more IndexTensor, the advanced indexing mode
494  // is enabled. Under Advanced indexing mode, we do some preprocessing
495  // with regular slicing, before sending to the advanced indexing engine.
496  //
497  // 1) TensorKey::Index: convert to a TensorKey::IndexTensor with the
498  // specified index.
499  // 2) TensorKey::Slice: if the slice is non-full slice, slice the tensor
500  // first and then use full slice for the advanced indexing engine.
501  //
502  // e.g.
503  // dst = src[1, 0:2, [1, 2]]
504  // ^ ^ ^
505  // Index Slice IndexTensor
506  // is done in two steps:
507  // temp = src[:, 0:2, :]
508  // dst = temp[[1], :, [1, 2]]
509 
510  std::vector<TensorKey> preprocess_tks;
511 
512  // Performs `temp = src[:, 0:2, :]`, see the example above.
513  for (const TensorKey& tk : tks) {
515  preprocess_tks.push_back(TensorKey::Slice(None, None, None));
516  } else if (tk.GetMode() == TensorKey::TensorKeyMode::Slice) {
517  preprocess_tks.push_back(tk);
518  } else if (tk.GetMode() == TensorKey::TensorKeyMode::IndexTensor) {
519  preprocess_tks.push_back(TensorKey::Slice(None, None, None));
520  } else {
521  utility::LogError("Internal error: wrong TensorKeyMode.");
522  }
523  }
524  Tensor preprocess_t = GetItem(preprocess_tks);
525 
526  // Performs `dst = temp[[1], :, [1, 2]]`, see the example above.
527  std::vector<Tensor> index_tensors;
528  for (const TensorKey& tk : tks) {
530  index_tensors.push_back(
531  Tensor(std::vector<int64_t>({tk.GetIndex()}), {1},
532  core::Int64, GetDevice()));
533  } else if (tk.GetMode() == TensorKey::TensorKeyMode::Slice) {
534  index_tensors.push_back(Tensor(std::vector<int64_t>{},
535  core::Int64, GetDevice()));
536  } else if (tk.GetMode() == TensorKey::TensorKeyMode::IndexTensor) {
537  index_tensors.push_back(tk.GetIndexTensor());
538  } else {
539  utility::LogError("Internal error: wrong TensorKeyMode.");
540  }
541  }
542 
543  // Calls Advanced indexing engine.
544  return preprocess_t.IndexGet(index_tensors);
545  }
546 
547  Tensor t = *this;
548  int64_t slice_dim = 0;
549  for (const TensorKey& tk : tks) {
551  t = t.IndexExtract(slice_dim, tk.GetIndex());
552  } else if (tk.GetMode() == TensorKey::TensorKeyMode::Slice) {
553  TensorKey tk_new = tk.InstantiateDimSize(t.shape_[slice_dim]);
554  t = t.Slice(slice_dim, tk_new.GetStart(), tk_new.GetStop(),
555  tk_new.GetStep());
556  slice_dim++;
557  } else {
558  utility::LogError("Internal error: wrong TensorKeyMode.");
559  }
560  }
561  return t;
562 }
563 
565  this->AsRvalue() = value;
566  return *this;
567 }
568 
569 Tensor Tensor::SetItem(const TensorKey& tk, const Tensor& value) {
571  IndexSet({tk.GetIndexTensor()}, value);
572  } else {
573  this->GetItem(tk) = value;
574  }
575  return *this;
576 }
577 
578 Tensor Tensor::SetItem(const std::vector<TensorKey>& tks, const Tensor& value) {
579  if (std::any_of(tks.begin(), tks.end(), [](const TensorKey& tk) {
580  return tk.GetMode() == TensorKey::TensorKeyMode::IndexTensor;
581  })) {
582  // Advanced indexing mode, see Tensor::GetItem for detailed docs.
583  std::vector<TensorKey> preprocess_tks;
584 
585  for (const TensorKey& tk : tks) {
587  preprocess_tks.push_back(TensorKey::Slice(None, None, None));
588  } else if (tk.GetMode() == TensorKey::TensorKeyMode::Slice) {
589  preprocess_tks.push_back(tk);
590  } else if (tk.GetMode() == TensorKey::TensorKeyMode::IndexTensor) {
591  preprocess_tks.push_back(TensorKey::Slice(None, None, None));
592  } else {
593  utility::LogError("Internal error: wrong TensorKeyMode.");
594  }
595  }
596  Tensor preprocess_t = GetItem(preprocess_tks);
597 
598  std::vector<Tensor> index_tensors;
599  for (const TensorKey& tk : tks) {
601  index_tensors.push_back(
602  Tensor(std::vector<int64_t>({tk.GetIndex()}), {1},
603  core::Int64, GetDevice()));
604  } else if (tk.GetMode() == TensorKey::TensorKeyMode::Slice) {
605  index_tensors.push_back(Tensor(std::vector<int64_t>{},
606  core::Int64, GetDevice()));
607  } else if (tk.GetMode() == TensorKey::TensorKeyMode::IndexTensor) {
608  index_tensors.push_back(tk.GetIndexTensor());
609  } else {
610  utility::LogError("Internal error: wrong TensorKeyMode.");
611  }
612  }
613 
614  preprocess_t.IndexSet(index_tensors, value);
615  } else {
616  this->GetItem(tks) = value;
617  }
618 
619  return *this;
620 }
621 
623  const utility::optional<int64_t>& axis) const {
624  return core::Append(*this, other, axis);
625 }
626 
628 Tensor Tensor::Broadcast(const SizeVector& dst_shape) const {
629  if (!shape_util::CanBeBrocastedToShape(shape_, dst_shape)) {
630  utility::LogError("Cannot broadcast shape {} to shape {}.",
631  shape_.ToString(), dst_shape);
632  }
633  Tensor dst_tensor(dst_shape, dtype_, GetDevice());
634  dst_tensor.AsRvalue() = *this;
635  return dst_tensor;
636 }
637 
638 Tensor Tensor::Expand(const SizeVector& dst_shape) const {
639  if (!shape_util::CanBeBrocastedToShape(shape_, dst_shape)) {
640  utility::LogError("Cannot expand shape {} to shape {}.",
641  shape_.ToString(), dst_shape);
642  }
643  int64_t src_ndims = NumDims();
644  int64_t dst_ndims = dst_shape.size();
645  int64_t omitted_ndims = dst_ndims - src_ndims;
646 
647  // Fill 1 in shape for omitted dimensions in front.
648  // Noe that unexpanded_new_shape is not the expanded shape. The expanded
649  // shape is the dst_shape.
650  SizeVector unexpanded_new_shape(dst_ndims, 1);
651  for (int64_t i = 0; i < src_ndims; ++i) {
652  unexpanded_new_shape[i + omitted_ndims] = shape_[i];
653  }
654 
655  // Fill 0 in strides for omitted dimensions in front.
656  SizeVector new_strides(dst_ndims, 0);
657  for (int64_t i = 0; i < src_ndims; ++i) {
658  new_strides[i + omitted_ndims] = strides_[i];
659  }
660 
661  // Set stride to 0 if the dimension is expanded.
662  for (int64_t i = 0; i < dst_ndims; ++i) {
663  if (unexpanded_new_shape[i] == 1 && dst_shape[i] != 1) {
664  new_strides[i] = 0;
665  }
666  }
667 
668  return AsStrided(dst_shape, new_strides);
669 }
670 
671 Tensor Tensor::Reshape(const SizeVector& dst_shape) const {
672  SizeVector inferred_dst_shape =
673  shape_util::InferShape(dst_shape, NumElements());
674  bool can_restride;
675  SizeVector new_strides;
676  std::tie(can_restride, new_strides) =
677  shape_util::Restride(shape_, strides_, inferred_dst_shape);
678  if (can_restride) {
679  return AsStrided(inferred_dst_shape, new_strides);
680  } else {
681  return Contiguous().View(inferred_dst_shape);
682  }
683 }
684 
685 Tensor Tensor::Flatten(int64_t start_dim /*= 0*/,
686  int64_t end_dim /*= -1*/) const {
687  int64_t num_dims = NumDims();
688  if (num_dims == 0) {
689  // Flattening a 0-d tensor is equivalent to flattening the tensor
690  // reshaped to 1-d. Technically, we cannot have a start_dim or end_dim,
691  // since a 0-d tensor cannot be indexed, e.g. np.array(100)[0] is not
692  // valid. But start_dim = 0 and end_dim = -1 are the default parameter
693  // values so we make an exception case for 0-d. We reshape it to 1-d for
694  // boundary checks of start_dim and end_dim.
695  return Reshape({1}).Flatten(start_dim, end_dim);
696  }
697  core::SizeVector shape = GetShape();
698  core::SizeVector dst_shape;
699  start_dim = shape_util::WrapDim(start_dim, num_dims, false);
700  end_dim = shape_util::WrapDim(end_dim, num_dims, false);
701  if (end_dim < start_dim) {
703  "start_dim {} must be smaller or equal to end_dim {}.",
704  start_dim, end_dim);
705  }
706  // Multiply the flattened dimensions together.
707  int64_t flat_dimension_size = 1;
708  for (int64_t dim = 0; dim < num_dims; dim++) {
709  if (dim >= start_dim && dim <= end_dim) {
710  flat_dimension_size *= shape[dim];
711  if (dim == end_dim) {
712  dst_shape.push_back(flat_dimension_size);
713  }
714  } else {
715  dst_shape.push_back(shape[dim]);
716  }
717  }
718  return Reshape(dst_shape);
719 }
720 
721 Tensor Tensor::View(const SizeVector& dst_shape) const {
722  SizeVector inferred_dst_shape =
723  shape_util::InferShape(dst_shape, NumElements());
724  bool can_restride;
725  SizeVector new_strides;
726  std::tie(can_restride, new_strides) =
727  shape_util::Restride(shape_, strides_, inferred_dst_shape);
728  if (can_restride) {
729  return AsStrided(inferred_dst_shape, new_strides);
730  } else {
732  "View shape {} is not compatible with Tensor's size {} and "
733  "sride {}, at least one dimension spacs across two contiguous "
734  "subspaces. Use Reshape() instead.",
735  dst_shape, shape_, strides_);
736  }
737 }
738 
739 Tensor Tensor::To(Dtype dtype, bool copy /*= false*/) const {
740  if (!copy && dtype_ == dtype) {
741  return *this;
742  }
743  // We only support scalar type conversion.
744  if (dtype_.IsObject() || dtype.IsObject()) {
745  utility::LogError("Cannot cast type from {} to {}.", dtype_.ToString(),
746  dtype.ToString());
747  }
748  Tensor dst_tensor(shape_, dtype, GetDevice());
749  kernel::Copy(*this, dst_tensor);
750  return dst_tensor;
751 }
752 
753 Tensor Tensor::To(const Device& device, bool copy /*= false*/) const {
754  if (!copy && GetDevice() == device) {
755  return *this;
756  }
757  Tensor dst_tensor(shape_, dtype_, device);
758  kernel::Copy(*this, dst_tensor);
759  return dst_tensor;
760 }
761 
762 Tensor Tensor::To(const Device& device,
763  Dtype dtype,
764  bool copy /*= false*/) const {
765  Tensor dst_tensor = To(dtype, copy);
766  dst_tensor = dst_tensor.To(device, copy);
767  return dst_tensor;
768 }
769 
770 void Tensor::CopyFrom(const Tensor& other) { AsRvalue() = other; }
771 
773  if (IsContiguous()) {
774  return *this;
775  } else {
776  return To(GetDevice(), /*copy=*/true);
777  }
778 }
779 
780 std::string Tensor::ToString(bool with_suffix,
781  const std::string& indent) const {
782  std::ostringstream rc;
783  if (IsCUDA() || IsSYCL() || !IsContiguous()) {
784  Tensor host_contiguous_tensor = Contiguous().To(Device("CPU:0"));
785  rc << host_contiguous_tensor.ToString(false, indent);
786  } else {
787  if (shape_.NumElements() == 0) {
788  rc << indent;
789  rc << "0-element Tensor";
790  } else if (shape_.size() == 0) {
791  rc << indent;
793  } else if (shape_.size() == 1) {
794  const char* ptr = static_cast<const char*>(data_ptr_);
795  rc << "[";
796  std::string delim = "";
797  int64_t element_byte_size = dtype_.ByteSize();
798  for (int64_t i = 0; i < shape_.NumElements(); ++i) {
799  rc << delim << ScalarPtrToString(ptr);
800  delim = " ";
801  ptr += element_byte_size;
802  }
803  rc << "]";
804  } else {
805  rc << "[";
806  std::string delim = "";
807  std::string child_indent = "";
808  for (int64_t i = 0; i < shape_[0]; ++i) {
809  rc << delim << child_indent
810  << this->operator[](i).ToString(false, indent + " ");
811  delim = ",\n";
812  child_indent = indent + " ";
813  }
814  rc << "]";
815  }
816  }
817  if (with_suffix) {
818  rc << fmt::format("\nTensor[shape={}, stride={}, {}, {}, {}]",
821  }
822  return rc.str();
823 }
824 
825 std::string Tensor::ScalarPtrToString(const void* ptr) const {
826  std::string str = "";
827  if (dtype_ == core::Bool) {
828  str = *static_cast<const unsigned char*>(ptr) ? "True" : "False";
829  } else if (dtype_.IsObject()) {
830  str = fmt::format("{}", fmt::ptr(ptr));
831  } else {
833  str = fmt::format("{}", *static_cast<const scalar_t*>(ptr));
834  });
835  }
836  return str;
837 }
838 
839 Tensor Tensor::operator[](int64_t i) const { return IndexExtract(0, i); }
840 
841 Tensor Tensor::IndexExtract(int64_t dim, int64_t idx) const {
842  if (shape_.size() == 0) {
843  utility::LogError("Tensor has shape (), cannot be indexed.");
844  }
845  dim = shape_util::WrapDim(dim, NumDims());
846  idx = shape_util::WrapDim(idx, shape_[dim]);
847 
848  SizeVector new_shape(shape_);
849  new_shape.erase(new_shape.begin() + dim);
850  SizeVector new_strides(strides_);
851  new_strides.erase(new_strides.begin() + dim);
852  void* new_data_ptr = static_cast<char*>(data_ptr_) +
853  strides_[dim] * dtype_.ByteSize() * idx;
854  return Tensor(new_shape, new_strides, new_data_ptr, dtype_, blob_);
855 }
856 
857 Tensor Tensor::Slice(int64_t dim,
858  int64_t start,
859  int64_t stop,
860  int64_t step) const {
861  if (shape_.size() == 0) {
862  utility::LogError("Slice cannot be applied to 0-dim Tensor.");
863  }
864  dim = shape_util::WrapDim(dim, NumDims());
865  if (dim < 0 || dim >= static_cast<int64_t>(shape_.size())) {
866  utility::LogError("Dim {} is out of bound for SizeVector of length {}.",
867  dim, shape_.size());
868  }
869  if (step == 0) {
870  utility::LogError("Step size cannot be 0.");
871  } else if (step < 0) {
872  // TODO: support negative step sizes
873  utility::LogError("Step size cannot be < 0.");
874  }
875 
876  // Wrap start. Out-of-range slice is valid and produces empty Tensor.
877  if (start < 0) {
878  start += shape_[dim];
879  }
880  if (start < 0) {
881  start = 0;
882  } else if (start >= shape_[dim]) {
883  start = shape_[dim];
884  }
885 
886  // Wrap stop. Out-of-range slice is valid and produces empty Tensor.
887  if (stop < 0) {
888  stop += shape_[dim];
889  }
890  if (stop < start) {
891  stop = start;
892  } else if (stop >= shape_[dim]) {
893  stop = shape_[dim];
894  }
895 
896  void* new_data_ptr = static_cast<char*>(data_ptr_) +
897  start * strides_[dim] * dtype_.ByteSize();
898  SizeVector new_shape = shape_;
899  SizeVector new_strides = strides_;
900  new_shape[dim] = (stop - start + step - 1) / step;
901  new_strides[dim] = strides_[dim] * step;
902  return Tensor(new_shape, new_strides, new_data_ptr, dtype_, blob_);
903 }
904 
905 Tensor Tensor::IndexGet(const std::vector<Tensor>& index_tensors) const {
906  if (NumDims() == 0) {
907  if (index_tensors.size() != 1) {
909  "A 0-D tensor can only be indexed by a 0-D boolean tensor, "
910  "but got {} index tensors.",
911  index_tensors.size());
912  }
913  Tensor index_tensor = index_tensors[0];
914  core::AssertTensorShape(index_tensor, {});
915  core::AssertTensorDtype(index_tensor, core::Bool);
916 
917  if (index_tensor.IsNonZero()) {
918  // E.g. np.array(5)[np.array(True)].
919  return Clone();
920  } else {
921  // E.g. np.array(5)[np.array(False)].
922  // The output tensor becomes 1D of 0 element.
923  return Tensor(/*shape=*/{0}, GetDtype(), GetDevice());
924  }
925  }
926 
927  AdvancedIndexPreprocessor aip(*this, index_tensors);
928  Tensor dst = Tensor(aip.GetOutputShape(), dtype_, GetDevice());
929 
930  kernel::IndexGet(aip.GetTensor(), dst, aip.GetIndexTensors(),
931  aip.GetIndexedShape(), aip.GetIndexedStrides());
932 
933  return dst;
934 }
935 
936 void Tensor::IndexSet(const std::vector<Tensor>& index_tensors,
937  const Tensor& src_tensor) {
938  if (NumDims() == 0) {
939  if (index_tensors.size() != 1) {
941  "A 0-D tensor can only be indexed by a 0-D boolean tensor, "
942  "but got {} index tensors.",
943  index_tensors.size());
944  }
945  Tensor index_tensor = index_tensors[0];
946  core::AssertTensorShape(index_tensor, {});
947  core::AssertTensorDtype(index_tensor, core::Bool);
948 
949  // Example index set
950  // t = np.array(5)
951  // t[np.array(True)] = 10 // Works, assigned
952  // t[np.array(True)] = np.array(10) // Works, assigned
953  // t[np.array(True)] = np.array([10]) // Works, assigned
954  // t[np.array(True)] = np.array([[10]]) // Cannot assign 2D
955  // t[np.array(True)] = np.array([10, 11]) // Cannot assign 1+ values
956  // t[np.array(False)] = 10 // Works, unchanged
957  // t[np.array(False)] = np.array(10) // Works, unchanged
958  // t[np.array(False)] = np.array([10]) // Works, unchanged
959  // t[np.array(False)] = np.array([[10]]) // Cannot assign 2D
960  // t[np.array(False)] = np.array([10, 11]) // Cannot assign 1+ values
961 
962  // Assert 0-D or 1-D.
963  if (src_tensor.NumDims() > 1) {
965  "Boolean indexing of a 0-D tensor can only be assigned "
966  "with 0 or 1-dimensional input, but got {} dimensions.",
967  src_tensor.NumDims());
968  }
969  // Assert single element.
970  if (src_tensor.NumElements() != 1) {
972  "Boolean indexing of a 0-D tensor can only be assigned "
973  "with input containing 1 element, but got {} elements.",
974  src_tensor.NumElements());
975  }
976  if (index_tensors[0].IsNonZero()) {
977  DISPATCH_DTYPE_TO_TEMPLATE_WITH_BOOL(src_tensor.GetDtype(), [&]() {
978  AsRvalue() = src_tensor.Item<scalar_t>();
979  });
980  }
981  return;
982  }
983 
984  AdvancedIndexPreprocessor aip(*this, index_tensors);
985  Tensor pre_processed_dst = aip.GetTensor();
986 
987  kernel::IndexSet(src_tensor, pre_processed_dst, aip.GetIndexTensors(),
988  aip.GetIndexedShape(), aip.GetIndexedStrides());
989 }
990 
991 void Tensor::IndexAdd_(int64_t dim, const Tensor& index, const Tensor& src) {
992  if (index.NumDims() != 1) {
993  utility::LogError("IndexAdd_ only supports 1D index tensors.");
994  }
995 
996  // Dim check.
997  if (dim < 0) {
998  utility::LogError("IndexAdd_ only supports sum at non-negative dim.");
999  }
1000  if (NumDims() <= dim) {
1001  utility::LogError("Sum dim {} exceeds tensor dim {}.", dim, NumDims());
1002  }
1003 
1004  // shape check
1005  if (src.NumDims() != NumDims()) {
1007  "IndexAdd_ only supports src tensor with same dimension as "
1008  "this tensor.");
1009  }
1010  for (int64_t d = 0; d < NumDims(); ++d) {
1011  if (d != dim && src.GetShape(d) != GetShape(d)) {
1013  "IndexAdd_ only supports src tensor with same shape as "
1014  "this "
1015  "tensor except dim {}.",
1016  dim);
1017  }
1018  }
1019 
1020  // Type check.
1022  AssertTensorDtype(*this, src.GetDtype());
1023 
1024  // Apply kernel.
1025  kernel::IndexAdd_(dim, index, src, *this);
1026 }
1027 
1028 Tensor Tensor::Permute(const SizeVector& dims) const {
1029  // Check dimension size
1030  if (static_cast<int64_t>(dims.size()) != NumDims()) {
1032  "Tensor has {} dimensions, but permuntation have {} "
1033  "dimensions.",
1034  NumDims(), dims.size());
1035  }
1036  int64_t n_dims = NumDims();
1037 
1038  // Check dims are permuntation of [0, 1, 2, ..., n-1]
1039  std::vector<bool> seen_dims(n_dims, false);
1040  for (const int64_t& dim : dims) {
1041  seen_dims[shape_util::WrapDim(dim, n_dims)] = true;
1042  }
1043  if (!std::all_of(seen_dims.begin(), seen_dims.end(),
1044  [](bool seen) { return seen; })) {
1045  utility::LogError("Permute dims must be a permuntation from 0 to {}",
1046  dims.size() - 1);
1047  }
1048 
1049  // Map to new shape and strides
1050  SizeVector new_shape(n_dims);
1051  SizeVector new_strides(n_dims);
1052  for (int64_t i = 0; i < n_dims; ++i) {
1053  int64_t old_dim = shape_util::WrapDim(dims[i], n_dims);
1054  new_shape[i] = shape_[old_dim];
1055  new_strides[i] = strides_[old_dim];
1056  }
1057 
1058  return AsStrided(new_shape, new_strides);
1059 }
1060 
1062  const SizeVector& new_strides) const {
1063  Tensor result(new_shape, new_strides, const_cast<void*>(data_ptr_), dtype_,
1064  blob_);
1065  return result;
1066 }
1067 
1068 Tensor Tensor::Transpose(int64_t dim0, int64_t dim1) const {
1069  int64_t n_dims = NumDims();
1070  dim0 = shape_util::WrapDim(dim0, n_dims);
1071  dim1 = shape_util::WrapDim(dim1, n_dims);
1072  SizeVector dims(n_dims);
1073  std::iota(dims.begin(), dims.end(), 0);
1074  dims[dim0] = dim1;
1075  dims[dim1] = dim0;
1076  return Permute(dims);
1077 }
1078 
1080  int64_t n_dims = NumDims();
1081  if (n_dims <= 1) {
1082  return *this;
1083  } else if (n_dims == 2) {
1084  return Transpose(0, 1);
1085  } else {
1087  "Tensor::T() expects a Tensor with <= 2 dimensions, but the "
1088  "Tensor as {} dimensions.");
1089  }
1090 }
1091 
1092 double Tensor::Det() const {
1093  AssertTensorDtypes(*this, {Float32, Float64});
1094  return core::Det(*this);
1095 }
1096 
1097 Tensor Tensor::Add(const Tensor& value) const {
1098  AssertTensorDevice(value, GetDevice());
1099  AssertTensorDtype(value, GetDtype());
1100 
1101  Tensor dst_tensor(shape_util::BroadcastedShape(shape_, value.shape_),
1102  dtype_, GetDevice());
1103  kernel::BinaryEW(*this, value, dst_tensor, kernel::BinaryEWOpCode::Add);
1104 
1105  return dst_tensor;
1106 }
1107 
1108 Tensor Tensor::Add(Scalar value) const {
1109  Tensor dst_tensor;
1111  dst_tensor = Add(
1112  Tensor::Full({}, value.To<scalar_t>(), dtype_, GetDevice()));
1113  });
1114  return dst_tensor;
1115 }
1116 
1117 Tensor Tensor::Add_(const Tensor& value) {
1118  AssertTensorDevice(value, GetDevice());
1119  AssertTensorDtype(value, GetDtype());
1120 
1121  kernel::BinaryEW(*this, value, *this, kernel::BinaryEWOpCode::Add);
1122 
1123  return *this;
1124 }
1125 
1128  Add_(Tensor::Full({}, value.To<scalar_t>(), dtype_, GetDevice()));
1129  });
1130  return *this;
1131 }
1132 
1133 Tensor Tensor::Sub(const Tensor& value) const {
1134  AssertTensorDevice(value, GetDevice());
1135  AssertTensorDtype(value, GetDtype());
1136 
1137  Tensor dst_tensor(shape_util::BroadcastedShape(shape_, value.shape_),
1138  dtype_, GetDevice());
1139  kernel::BinaryEW(*this, value, dst_tensor, kernel::BinaryEWOpCode::Sub);
1140 
1141  return dst_tensor;
1142 }
1143 
1144 Tensor Tensor::Sub(Scalar value) const {
1145  Tensor dst_tensor;
1147  dst_tensor = Sub(
1148  Tensor::Full({}, value.To<scalar_t>(), dtype_, GetDevice()));
1149  });
1150  return dst_tensor;
1151 }
1152 
1153 Tensor Tensor::Sub_(const Tensor& value) {
1154  AssertTensorDevice(value, GetDevice());
1155  AssertTensorDtype(value, GetDtype());
1156 
1157  kernel::BinaryEW(*this, value, *this, kernel::BinaryEWOpCode::Sub);
1158 
1159  return *this;
1160 }
1161 
1164  Sub_(Tensor::Full({}, value.To<scalar_t>(), dtype_, GetDevice()));
1165  });
1166  return *this;
1167 }
1168 
1169 Tensor Tensor::Mul(const Tensor& value) const {
1170  AssertTensorDevice(value, GetDevice());
1171  AssertTensorDtype(value, GetDtype());
1172 
1173  Tensor dst_tensor(shape_util::BroadcastedShape(shape_, value.shape_),
1174  dtype_, GetDevice());
1175  kernel::BinaryEW(*this, value, dst_tensor, kernel::BinaryEWOpCode::Mul);
1176 
1177  return dst_tensor;
1178 }
1179 
1180 Tensor Tensor::Mul(Scalar value) const {
1181  Tensor dst_tensor;
1183  dst_tensor = Mul(
1184  Tensor::Full({}, value.To<scalar_t>(), dtype_, GetDevice()));
1185  });
1186  return dst_tensor;
1187 }
1188 
1189 Tensor Tensor::Mul_(const Tensor& value) {
1190  AssertTensorDevice(value, GetDevice());
1191  AssertTensorDtype(value, GetDtype());
1192 
1193  kernel::BinaryEW(*this, value, *this, kernel::BinaryEWOpCode::Mul);
1194 
1195  return *this;
1196 }
1197 
1200  Mul_(Tensor::Full({}, value.To<scalar_t>(), dtype_, GetDevice()));
1201  });
1202  return *this;
1203 }
1204 
1205 Tensor Tensor::Div(const Tensor& value) const {
1206  AssertTensorDevice(value, GetDevice());
1207  AssertTensorDtype(value, GetDtype());
1208 
1209  Tensor dst_tensor(shape_util::BroadcastedShape(shape_, value.shape_),
1210  dtype_, GetDevice());
1211  kernel::BinaryEW(*this, value, dst_tensor, kernel::BinaryEWOpCode::Div);
1212 
1213  return dst_tensor;
1214 }
1215 
1216 Tensor Tensor::Div(Scalar value) const {
1217  Tensor dst_tensor;
1219  dst_tensor = Div(
1220  Tensor::Full({}, value.To<scalar_t>(), dtype_, GetDevice()));
1221  });
1222  return dst_tensor;
1223 }
1224 
1225 Tensor Tensor::Div_(const Tensor& value) {
1226  AssertTensorDevice(value, GetDevice());
1227  AssertTensorDtype(value, GetDtype());
1228 
1229  kernel::BinaryEW(*this, value, *this, kernel::BinaryEWOpCode::Div);
1230  return *this;
1231 }
1232 
1235  Div_(Tensor::Full({}, value.To<scalar_t>(), dtype_, GetDevice()));
1236  });
1237  return *this;
1238 }
1239 
1240 Tensor Tensor::Sum(const SizeVector& dims, bool keepdim) const {
1241  Tensor dst(shape_util::ReductionShape(shape_, dims, keepdim), dtype_,
1242  GetDevice());
1243  kernel::Reduction(*this, dst, dims, keepdim, kernel::ReductionOpCode::Sum);
1244  return dst;
1245 }
1246 
1247 Tensor Tensor::Mean(const SizeVector& dims, bool keepdim) const {
1248  AssertTensorDtypes(*this, {Float32, Float64});
1249 
1250  // Following Numpy's semantics, reduction on 0-sized Tensor will result in
1251  // NaNs and a warning. A straightforward method is used now. Later it can be
1252  // extended to handle overflow and underflow in a better way.
1253  if (NumElements() == 0) {
1254  utility::LogWarning("Computing mean of 0-sized Tensor.");
1255  }
1256  Tensor sum = Sum(dims, keepdim);
1257  double factor = static_cast<double>(sum.NumElements()) / NumElements();
1258  return sum * factor;
1259 }
1260 
1261 Tensor Tensor::Prod(const SizeVector& dims, bool keepdim) const {
1262  Tensor dst(shape_util::ReductionShape(shape_, dims, keepdim), dtype_,
1263  GetDevice());
1264  kernel::Reduction(*this, dst, dims, keepdim, kernel::ReductionOpCode::Prod);
1265  return dst;
1266 }
1267 
1268 Tensor Tensor::Min(const SizeVector& dims, bool keepdim) const {
1269  Tensor dst(shape_util::ReductionShape(shape_, dims, keepdim), dtype_,
1270  GetDevice());
1271  kernel::Reduction(*this, dst, dims, keepdim, kernel::ReductionOpCode::Min);
1272  return dst;
1273 }
1274 
1275 Tensor Tensor::Max(const SizeVector& dims, bool keepdim) const {
1276  Tensor dst(shape_util::ReductionShape(shape_, dims, keepdim), dtype_,
1277  GetDevice());
1278  kernel::Reduction(*this, dst, dims, keepdim, kernel::ReductionOpCode::Max);
1279  return dst;
1280 }
1281 
1282 Tensor Tensor::ArgMin(const SizeVector& dims) const {
1284  GetDevice());
1285  kernel::Reduction(*this, dst, dims, false, kernel::ReductionOpCode::ArgMin);
1286  return dst;
1287 }
1288 
1289 Tensor Tensor::ArgMax(const SizeVector& dims) const {
1291  GetDevice());
1292  kernel::Reduction(*this, dst, dims, false, kernel::ReductionOpCode::ArgMax);
1293  return dst;
1294 }
1295 
1297  Tensor dst_tensor(shape_, dtype_, GetDevice());
1298  kernel::UnaryEW(*this, dst_tensor, kernel::UnaryEWOpCode::Sqrt);
1299  return dst_tensor;
1300 }
1301 
1304  return *this;
1305 }
1306 
1308  Tensor dst_tensor(shape_, dtype_, GetDevice());
1309  kernel::UnaryEW(*this, dst_tensor, kernel::UnaryEWOpCode::Sin);
1310  return dst_tensor;
1311 }
1312 
1315  return *this;
1316 }
1317 
1319  Tensor dst_tensor(shape_, dtype_, GetDevice());
1320  kernel::UnaryEW(*this, dst_tensor, kernel::UnaryEWOpCode::Cos);
1321  return dst_tensor;
1322 }
1323 
1326  return *this;
1327 }
1328 
1330  Tensor dst_tensor(shape_, dtype_, GetDevice());
1331  kernel::UnaryEW(*this, dst_tensor, kernel::UnaryEWOpCode::Neg);
1332  return dst_tensor;
1333 }
1334 
1337  return *this;
1338 }
1339 
1341  Tensor dst_tensor(shape_, dtype_, GetDevice());
1342  kernel::UnaryEW(*this, dst_tensor, kernel::UnaryEWOpCode::Exp);
1343  return dst_tensor;
1344 }
1345 
1348  return *this;
1349 }
1350 
1352  Tensor dst_tensor(shape_, dtype_, GetDevice());
1353  kernel::UnaryEW(*this, dst_tensor, kernel::UnaryEWOpCode::Abs);
1354  return dst_tensor;
1355 }
1356 
1359  return *this;
1360 }
1361 
1363  if (dtype_ == core::Float32 || dtype_ == core::Float64) {
1364  Tensor dst_tensor(shape_, core::Bool, GetDevice());
1365  kernel::UnaryEW(*this, dst_tensor, kernel::UnaryEWOpCode::IsNan);
1366  return dst_tensor;
1367  } else {
1369  }
1370 }
1371 
1373  if (dtype_ == core::Float32 || dtype_ == core::Float64) {
1374  Tensor dst_tensor(shape_, core::Bool, GetDevice());
1375  kernel::UnaryEW(*this, dst_tensor, kernel::UnaryEWOpCode::IsInf);
1376  return dst_tensor;
1377  } else {
1379  }
1380 }
1381 
1383  if (dtype_ == core::Float32 || dtype_ == core::Float64) {
1384  Tensor dst_tensor(shape_, core::Bool, GetDevice());
1386  return dst_tensor;
1387  } else {
1389  }
1390 }
1391 
1392 Tensor Tensor::Clip(Scalar min_val, Scalar max_val) const {
1393  Tensor dst_tensor = this->Clone();
1394  return dst_tensor.Clip_(min_val, max_val);
1395 }
1396 
1397 // TODO: Implement with kernel.
1398 Tensor Tensor::Clip_(Scalar min_val, Scalar max_val) {
1400  scalar_t min_val_casted = min_val.To<scalar_t>();
1401  this->SetItem(TensorKey::IndexTensor(this->Lt(min_val_casted)),
1402  Full({}, min_val_casted, dtype_, GetDevice()));
1403 
1404  scalar_t max_val_casted = max_val.To<scalar_t>();
1405  this->SetItem(TensorKey::IndexTensor(this->Gt(max_val_casted)),
1406  Full({}, max_val_casted, dtype_, GetDevice()));
1407  });
1408  return *this;
1409 }
1410 
1412  Tensor dst_tensor(shape_, dtype_, GetDevice());
1413  kernel::UnaryEW(*this, dst_tensor, kernel::UnaryEWOpCode::Floor);
1414  return dst_tensor;
1415 }
1416 
1418  Tensor dst_tensor(shape_, dtype_, GetDevice());
1419  kernel::UnaryEW(*this, dst_tensor, kernel::UnaryEWOpCode::Ceil);
1420  return dst_tensor;
1421 }
1422 
1424  Tensor dst_tensor(shape_, dtype_, GetDevice());
1425  kernel::UnaryEW(*this, dst_tensor, kernel::UnaryEWOpCode::Round);
1426  return dst_tensor;
1427 }
1428 
1430  Tensor dst_tensor(shape_, dtype_, GetDevice());
1431  kernel::UnaryEW(*this, dst_tensor, kernel::UnaryEWOpCode::Trunc);
1432  return dst_tensor;
1433 }
1434 
1436  if (blob_ == nullptr) {
1437  utility::LogError("Blob is null, cannot get device");
1438  }
1439  return blob_->GetDevice();
1440 }
1441 
1443  Tensor dst_tensor(shape_, core::Bool, GetDevice());
1445  return dst_tensor;
1446 }
1447 
1450  return *this;
1451 }
1452 
1453 Tensor Tensor::LogicalAnd(const Tensor& value) const {
1454  AssertTensorDevice(value, GetDevice());
1455 
1456  Tensor dst_tensor(shape_util::BroadcastedShape(shape_, value.shape_),
1457  core::Bool, GetDevice());
1458  kernel::BinaryEW(*this, value, dst_tensor,
1460  return dst_tensor;
1461 }
1462 
1464  Tensor dst_tensor;
1466  dst_tensor = LogicalAnd(
1467  Tensor::Full({}, value.To<scalar_t>(), dtype_, GetDevice()));
1468  });
1469  return dst_tensor;
1470 }
1471 
1473  AssertTensorDevice(value, GetDevice());
1474 
1476  return *this;
1477 }
1478 
1481  LogicalAnd_(
1482  Tensor::Full({}, value.To<scalar_t>(), dtype_, GetDevice()));
1483  });
1484  return *this;
1485 }
1486 
1487 Tensor Tensor::LogicalOr(const Tensor& value) const {
1488  AssertTensorDevice(value, GetDevice());
1489 
1490  Tensor dst_tensor(shape_util::BroadcastedShape(shape_, value.shape_),
1491  core::Bool, GetDevice());
1492  kernel::BinaryEW(*this, value, dst_tensor,
1494  return dst_tensor;
1495 }
1496 
1498  Tensor dst_tensor;
1500  dst_tensor = LogicalOr(
1501  Tensor::Full({}, value.To<scalar_t>(), dtype_, GetDevice()));
1502  });
1503  return dst_tensor;
1504 }
1505 
1507  AssertTensorDevice(value, GetDevice());
1508 
1510  return *this;
1511 }
1512 
1515  LogicalOr_(Tensor::Full({}, value.To<scalar_t>(), dtype_, GetDevice()));
1516  });
1517  return *this;
1518 }
1519 
1520 Tensor Tensor::LogicalXor(const Tensor& value) const {
1521  AssertTensorDevice(value, GetDevice());
1522 
1523  Tensor dst_tensor(shape_util::BroadcastedShape(shape_, value.shape_),
1524  core::Bool, GetDevice());
1525  kernel::BinaryEW(*this, value, dst_tensor,
1527  return dst_tensor;
1528 }
1529 
1531  Tensor dst_tensor;
1533  dst_tensor = LogicalXor(
1534  Tensor::Full({}, value.To<scalar_t>(), dtype_, GetDevice()));
1535  });
1536  return dst_tensor;
1537 }
1538 
1540  AssertTensorDevice(value, GetDevice());
1541 
1543  return *this;
1544 }
1545 
1548  LogicalXor_(
1549  Tensor::Full({}, value.To<scalar_t>(), dtype_, GetDevice()));
1550  });
1551  return *this;
1552 }
1553 
1554 Tensor Tensor::Gt(const Tensor& value) const {
1555  AssertTensorDevice(value, GetDevice());
1556 
1557  Tensor dst_tensor(shape_util::BroadcastedShape(shape_, value.shape_),
1558  core::Bool, GetDevice());
1559  kernel::BinaryEW(*this, value, dst_tensor, kernel::BinaryEWOpCode::Gt);
1560  return dst_tensor;
1561 }
1562 
1563 Tensor Tensor::Gt(Scalar value) const {
1564  Tensor dst_tensor;
1566  dst_tensor =
1567  Gt(Tensor::Full({}, value.To<scalar_t>(), dtype_, GetDevice()));
1568  });
1569  return dst_tensor;
1570 }
1571 
1572 Tensor Tensor::Gt_(const Tensor& value) {
1573  AssertTensorDevice(value, GetDevice());
1574 
1575  kernel::BinaryEW(*this, value, *this, kernel::BinaryEWOpCode::Gt);
1576  return *this;
1577 }
1578 
1581  Gt_(Tensor::Full({}, value.To<scalar_t>(), dtype_, GetDevice()));
1582  });
1583  return *this;
1584 }
1585 
1586 Tensor Tensor::Lt(const Tensor& value) const {
1587  AssertTensorDevice(value, GetDevice());
1588 
1589  Tensor dst_tensor(shape_util::BroadcastedShape(shape_, value.shape_),
1590  core::Bool, GetDevice());
1591  kernel::BinaryEW(*this, value, dst_tensor, kernel::BinaryEWOpCode::Lt);
1592  return dst_tensor;
1593 }
1594 
1595 Tensor Tensor::Lt(Scalar value) const {
1596  Tensor dst_tensor;
1598  dst_tensor =
1599  Lt(Tensor::Full({}, value.To<scalar_t>(), dtype_, GetDevice()));
1600  });
1601  return dst_tensor;
1602 }
1603 
1604 Tensor Tensor::Lt_(const Tensor& value) {
1605  AssertTensorDevice(value, GetDevice());
1606 
1607  kernel::BinaryEW(*this, value, *this, kernel::BinaryEWOpCode::Lt);
1608  return *this;
1609 }
1610 
1613  Lt_(Tensor::Full({}, value.To<scalar_t>(), dtype_, GetDevice()));
1614  });
1615  return *this;
1616 }
1617 
1618 Tensor Tensor::Ge(const Tensor& value) const {
1619  AssertTensorDevice(value, GetDevice());
1620 
1621  Tensor dst_tensor(shape_util::BroadcastedShape(shape_, value.shape_),
1622  core::Bool, GetDevice());
1623  kernel::BinaryEW(*this, value, dst_tensor, kernel::BinaryEWOpCode::Ge);
1624  return dst_tensor;
1625 }
1626 
1627 Tensor Tensor::Ge(Scalar value) const {
1628  Tensor dst_tensor;
1630  dst_tensor =
1631  Ge(Tensor::Full({}, value.To<scalar_t>(), dtype_, GetDevice()));
1632  });
1633  return dst_tensor;
1634 }
1635 
1636 Tensor Tensor::Ge_(const Tensor& value) {
1637  AssertTensorDevice(value, GetDevice());
1638 
1639  kernel::BinaryEW(*this, value, *this, kernel::BinaryEWOpCode::Ge);
1640  return *this;
1641 }
1642 
1645  Ge_(Tensor::Full({}, value.To<scalar_t>(), dtype_, GetDevice()));
1646  });
1647  return *this;
1648 }
1649 
1650 Tensor Tensor::Le(const Tensor& value) const {
1651  AssertTensorDevice(value, GetDevice());
1652 
1653  Tensor dst_tensor(shape_util::BroadcastedShape(shape_, value.shape_),
1654  core::Bool, GetDevice());
1655  kernel::BinaryEW(*this, value, dst_tensor, kernel::BinaryEWOpCode::Le);
1656  return dst_tensor;
1657 }
1658 
1659 Tensor Tensor::Le(Scalar value) const {
1660  Tensor dst_tensor;
1662  dst_tensor =
1663  Le(Tensor::Full({}, value.To<scalar_t>(), dtype_, GetDevice()));
1664  });
1665  return dst_tensor;
1666 }
1667 
1668 Tensor Tensor::Le_(const Tensor& value) {
1669  AssertTensorDevice(value, GetDevice());
1670 
1671  kernel::BinaryEW(*this, value, *this, kernel::BinaryEWOpCode::Le);
1672  return *this;
1673 }
1674 
1677  Le_(Tensor::Full({}, value.To<scalar_t>(), dtype_, GetDevice()));
1678  });
1679  return *this;
1680 }
1681 
1682 Tensor Tensor::Eq(const Tensor& value) const {
1683  AssertTensorDevice(value, GetDevice());
1684 
1685  Tensor dst_tensor(shape_util::BroadcastedShape(shape_, value.shape_),
1686  core::Bool, GetDevice());
1687  kernel::BinaryEW(*this, value, dst_tensor, kernel::BinaryEWOpCode::Eq);
1688  return dst_tensor;
1689 }
1690 
1691 Tensor Tensor::Eq(Scalar value) const {
1692  Tensor dst_tensor;
1694  dst_tensor =
1695  Eq(Tensor::Full({}, value.To<scalar_t>(), dtype_, GetDevice()));
1696  });
1697  return dst_tensor;
1698 }
1699 
1700 Tensor Tensor::Eq_(const Tensor& value) {
1701  AssertTensorDevice(value, GetDevice());
1702 
1703  kernel::BinaryEW(*this, value, *this, kernel::BinaryEWOpCode::Eq);
1704  return *this;
1705 }
1706 
1709  Eq_(Tensor::Full({}, value.To<scalar_t>(), dtype_, GetDevice()));
1710  });
1711  return *this;
1712 }
1713 
1714 Tensor Tensor::Ne(const Tensor& value) const {
1715  AssertTensorDevice(value, GetDevice());
1716 
1717  Tensor dst_tensor(shape_util::BroadcastedShape(shape_, value.shape_),
1718  core::Bool, GetDevice());
1719  kernel::BinaryEW(*this, value, dst_tensor, kernel::BinaryEWOpCode::Ne);
1720  return dst_tensor;
1721 }
1722 
1723 Tensor Tensor::Ne(Scalar value) const {
1724  Tensor dst_tensor;
1726  dst_tensor =
1727  Ne(Tensor::Full({}, value.To<scalar_t>(), dtype_, GetDevice()));
1728  });
1729  return dst_tensor;
1730 }
1731 
1732 Tensor Tensor::Ne_(const Tensor& value) {
1733  AssertTensorDevice(value, GetDevice());
1734 
1735  kernel::BinaryEW(*this, value, *this, kernel::BinaryEWOpCode::Ne);
1736  return *this;
1737 }
1738 
1741  Ne_(Tensor::Full({}, value.To<scalar_t>(), dtype_, GetDevice()));
1742  });
1743  return *this;
1744 }
1745 
1746 std::vector<Tensor> Tensor::NonZeroNumpy() const {
1747  Tensor result = kernel::NonZero(*this);
1748  std::vector<Tensor> results;
1749  for (int64_t dim = 0; dim < NumDims(); dim++) {
1750  results.push_back(result[dim].Clone());
1751  }
1752  return results;
1753 }
1754 
1755 Tensor Tensor::NonZero() const { return kernel::NonZero(*this); }
1756 
1757 bool Tensor::IsNonZero() const {
1758  if (shape_.NumElements() != 1) {
1760  "Tensor must have exactly one element to be evaluated as "
1761  "boolean.");
1762  }
1763  bool rc = false;
1765  rc = Item<scalar_t>() != static_cast<scalar_t>(0);
1766  });
1767  return rc;
1768 }
1769 
1771  bool keepdim) const {
1772  AssertTensorDtype(*this, core::Bool);
1773 
1774  Tensor dst;
1775  if (dims.has_value()) {
1776  dst = Tensor(shape_util::ReductionShape(shape_, dims.value(), keepdim),
1777  dtype_, GetDevice());
1778  kernel::Reduction(*this, dst, dims.value(), keepdim,
1780  } else {
1781  dst = Tensor({}, dtype_, GetDevice());
1782  kernel::Reduction(*this, dst, shape_util::Iota(NumDims()), false,
1784  }
1785 
1786  return dst;
1787 }
1788 
1790  bool keepdim) const {
1791  AssertTensorDtype(*this, core::Bool);
1792 
1793  Tensor dst;
1794  if (dims.has_value()) {
1795  dst = Tensor(shape_util::ReductionShape(shape_, dims.value(), keepdim),
1796  dtype_, GetDevice());
1797  kernel::Reduction(*this, dst, dims.value(), keepdim,
1799  } else {
1800  dst = Tensor({}, dtype_, GetDevice());
1801  kernel::Reduction(*this, dst, shape_util::Iota(NumDims()), false,
1803  }
1804 
1805  return dst;
1806 }
1807 
1810 }
1813 }
1814 
1815 namespace {
1816 template <typename DLMT>
1817 Tensor FromDLPackImpl(const DLMT* src, std::function<void(void*)> deleter) {
1818  Device src_device;
1819  switch (src->dl_tensor.device.device_type) {
1820  case DLDeviceType::kDLCPU:
1821  src_device = Device("CPU", src->dl_tensor.device.device_id);
1822  break;
1823  case DLDeviceType::kDLCUDA:
1824  src_device = Device("CUDA", src->dl_tensor.device.device_id);
1825  break;
1827  src_device = Device("SYCL", src->dl_tensor.device.device_id);
1828  break;
1829  default:
1831  "Unsupported device_type {}",
1832  static_cast<int>(src->dl_tensor.device.device_type));
1833  }
1834 
1835  Dtype dtype = DLDataTypeToDtype(src->dl_tensor.dtype);
1836 
1837  // Open3D Blob's expects an std::function<void(void*)> deleter.
1838  if (!deleter) {
1839  deleter = [src](void* dummy) -> void {
1840  if (src->deleter != nullptr) {
1841  src->deleter(const_cast<DLMT*>(src));
1842  }
1843  };
1844  }
1845 
1846  SizeVector shape(src->dl_tensor.shape,
1847  src->dl_tensor.shape + src->dl_tensor.ndim);
1848 
1849  SizeVector strides;
1850  if (!src->dl_tensor.strides) { // default row major contiguous strides
1851  strides = shape_util::DefaultStrides(shape);
1852  } else {
1853  strides = SizeVector(src->dl_tensor.strides,
1854  src->dl_tensor.strides + src->dl_tensor.ndim);
1855  }
1856 
1857  auto blob =
1858  std::make_shared<Blob>(src_device, src->dl_tensor.data, deleter);
1859 
1860  // src->dl_tensor.byte_offset is ignored in PyTorch and MXNet, but
1861  // according to dlpack.h, we added the offset here.
1862  return Tensor(shape, strides,
1863  reinterpret_cast<char*>(blob->GetDataPtr()) +
1864  src->dl_tensor.byte_offset,
1865  dtype, blob);
1866 }
1867 } // namespace
1869  std::function<void(void*)> deleter) {
1870  return FromDLPackImpl<DLManagedTensor>(src, std::move(deleter));
1871 }
1873  std::function<void(void*)> deleter) {
1874  return FromDLPackImpl<DLManagedTensorVersioned>(src, std::move(deleter));
1875 }
1876 
1877 void Tensor::Save(const std::string& file_name) const {
1878  t::io::WriteNpy(file_name, *this);
1879 }
1880 
1881 Tensor Tensor::Load(const std::string& file_name) {
1882  return t::io::ReadNpy(file_name);
1883 }
1884 
1885 bool Tensor::AllEqual(const Tensor& other) const {
1886  AssertTensorDevice(other, GetDevice());
1887  AssertTensorDtype(other, GetDtype());
1888 
1889  if (shape_ != other.shape_) {
1890  return false;
1891  }
1892  return (*this == other).All().Item<bool>();
1893 }
1894 
1895 bool Tensor::AllClose(const Tensor& other, double rtol, double atol) const {
1896  // TODO: support nan;
1897  return IsClose(other, rtol, atol).All().Item<bool>();
1898 }
1899 
1900 Tensor Tensor::IsClose(const Tensor& other, double rtol, double atol) const {
1901  AssertTensorDevice(other, GetDevice());
1902  AssertTensorDtype(other, GetDtype());
1903  AssertTensorShape(other, GetShape());
1904 
1905  Tensor lhs = this->To(core::Float64);
1906  Tensor rhs = other.To(core::Float64);
1907  Tensor actual_error = (lhs - rhs).Abs();
1908  Tensor max_error = atol + rtol * rhs.Abs();
1909  return actual_error <= max_error;
1910 }
1911 
1912 bool Tensor::IsSame(const Tensor& other) const {
1913  AssertTensorDevice(other, GetDevice());
1914  return blob_ == other.blob_ && shape_ == other.shape_ &&
1915  strides_ == other.strides_ && data_ptr_ == other.data_ptr_ &&
1916  dtype_ == other.dtype_;
1917 }
1918 
1919 Tensor Tensor::Matmul(const Tensor& rhs) const {
1920  AssertTensorDevice(rhs, GetDevice());
1921  AssertTensorDtype(rhs, GetDtype());
1922 
1923  Tensor output;
1924  core::Matmul(*this, rhs, output);
1925  return output;
1926 }
1927 
1928 Tensor Tensor::Solve(const Tensor& rhs) const {
1929  AssertTensorDtypes(*this, {Float32, Float64});
1930  AssertTensorDevice(rhs, GetDevice());
1931  AssertTensorDtype(rhs, GetDtype());
1932 
1933  Tensor output;
1934  core::Solve(*this, rhs, output);
1935  return output;
1936 }
1937 
1939  AssertTensorDtypes(*this, {Float32, Float64});
1940  AssertTensorDevice(rhs, GetDevice());
1941  AssertTensorDtype(rhs, GetDtype());
1942 
1943  Tensor output;
1944  core::LeastSquares(*this, rhs, output);
1945  return output;
1946 }
1947 
1948 std::tuple<Tensor, Tensor, Tensor> Tensor::LU(const bool permute_l) const {
1949  AssertTensorDtypes(*this, {Float32, Float64});
1950 
1951  core::Tensor permutation, lower, upper;
1952  core::LU(*this, permutation, lower, upper, permute_l);
1953  return std::make_tuple(permutation, lower, upper);
1954 }
1955 
1956 std::tuple<Tensor, Tensor> Tensor::LUIpiv() const {
1957  AssertTensorDtypes(*this, {Float32, Float64});
1958 
1959  core::Tensor ipiv, output;
1960  core::LUIpiv(*this, ipiv, output);
1961  return std::make_tuple(ipiv, output);
1962 }
1963 
1964 Tensor Tensor::Triu(const int diagonal) const {
1965  Tensor output;
1966  core::Triu(*this, output, diagonal);
1967  return output;
1968 }
1969 
1970 Tensor Tensor::Tril(const int diagonal) const {
1971  Tensor output;
1972  core::Tril(*this, output, diagonal);
1973  return output;
1974 }
1975 
1976 std::tuple<Tensor, Tensor> Tensor::Triul(const int diagonal) const {
1977  Tensor upper, lower;
1978  core::Triul(*this, upper, lower, diagonal);
1979  return std::make_tuple(upper, lower);
1980 }
1981 
1983  AssertTensorDtypes(*this, {Float32, Float64});
1984 
1985  Tensor output;
1986  core::Inverse(*this, output);
1987  return output;
1988 }
1989 
1990 std::tuple<Tensor, Tensor, Tensor> Tensor::SVD() const {
1991  AssertTensorDtypes(*this, {Float32, Float64});
1992 
1993  Tensor U, S, VT;
1994  core::SVD(*this, U, S, VT);
1995  return std::tie(U, S, VT);
1996 }
1997 
1998 } // namespace core
1999 } // namespace cloudViewer
Common CUDA utilities.
DLDataTypeCode
The type code options DLDataType.
Definition: DLPack.h:160
@ kDLInt
signed integer
Definition: DLPack.h:162
@ kDLFloat
IEEE floating point.
Definition: DLPack.h:166
@ kDLUInt
unsigned integer
Definition: DLPack.h:164
@ kDLBool
boolean
Definition: DLPack.h:181
DLDeviceType
The device type in DLDevice.
Definition: DLPack.h:92
@ kDLCUDA
CUDA GPU device.
Definition: DLPack.h:97
@ kDLOneAPI
Unified shared memory allocated on a oneAPI non-partititioned device. Call to oneAPI runtime is requi...
Definition: DLPack.h:132
@ kDLCPU
CPU device.
Definition: DLPack.h:95
#define DLPACK_MAJOR_VERSION
The current major version of dlpack.
Definition: DLPack.h:37
#define DLPACK_MINOR_VERSION
The current minor version of dlpack.
Definition: DLPack.h:40
#define DISPATCH_DTYPE_TO_TEMPLATE_WITH_BOOL(DTYPE,...)
Definition: Dispatch.h:68
#define DISPATCH_DTYPE_TO_TEMPLATE(DTYPE,...)
Definition: Dispatch.h:31
filament::Texture::InternalFormat format
#define AssertTensorDevice(tensor,...)
Definition: TensorCheck.h:45
#define AssertTensorDtype(tensor,...)
Definition: TensorCheck.h:21
#define AssertTensorDtypes(tensor,...)
Definition: TensorCheck.h:33
#define AssertTensorShape(tensor,...)
Definition: TensorCheck.h:61
core::Tensor result
Definition: VtkUtils.cpp:76
bool copy
Definition: VtkUtils.cpp:74
This class is based on PyTorch's aten/src/ATen/native/Indexing.cpp.
std::vector< Tensor > GetIndexTensors() const
DeviceType GetType() const
Returns type of the device, e.g. DeviceType::CPU, DeviceType::CUDA.
Definition: Device.h:58
std::string ToString() const
Returns string representation of device, e.g. "CPU:0", "CUDA:0".
Definition: Device.cpp:89
int GetID() const
Returns the device index (within the same device type).
Definition: Device.h:61
std::string ToString() const
Definition: Dtype.h:65
bool IsObject() const
Definition: Dtype.h:63
int64_t ByteSize() const
Definition: Dtype.h:59
bool IsCUDA() const
Definition: Device.h:99
CloudViewer DLPack Tensor manager.
Definition: Tensor.cpp:133
static void Deleter(DLMT *arg)
Definition: Tensor.cpp:208
static DLDevice getDLPackDevice(const Tensor &o3d_tensor)
Definition: Tensor.cpp:187
static DLMT * Create(const Tensor &o3d_tensor)
Definition: Tensor.cpp:181
void AssertSameScalarType(Scalar other, const std::string &error_msg) const
Definition: Scalar.h:140
T To() const
To<T>() does not check for scalar type and overflows.
Definition: Scalar.h:128
bool Equal(T value) const
Definition: Scalar.h:172
std::string ToString() const
Definition: SizeVector.cpp:132
iterator erase(const_iterator CI)
Definition: SmallVector.h:779
pointer data()
Return a pointer to the vector's buffer, even if empty().
Definition: SmallVector.h:324
TensorKey is used to represent single index, slice or advanced indexing on a Tensor.
Definition: TensorKey.h:26
TensorKeyMode GetMode() const
Returns TensorKey mode.
Definition: TensorKey.cpp:130
TensorKey InstantiateDimSize(int64_t dim_size) const
Definition: TensorKey.cpp:177
static TensorKey IndexTensor(const Tensor &index_tensor)
Definition: TensorKey.cpp:144
Tensor GetIndexTensor() const
Definition: TensorKey.cpp:186
static TensorKey Slice(utility::optional< int64_t > start, utility::optional< int64_t > stop, utility::optional< int64_t > step)
Definition: TensorKey.cpp:138
Tensor LogicalOr_(const Tensor &value)
Definition: Tensor.cpp:1506
bool AllClose(const Tensor &other, double rtol=1e-5, double atol=1e-8) const
Definition: Tensor.cpp:1895
Tensor & operator=(const Tensor &other) &
Definition: Tensor.cpp:355
double Det() const
Compute the determinant of a 2D square tensor.
Definition: Tensor.cpp:1092
Tensor Reverse() const
Reverse a Tensor's elements by viewing the tensor as a 1D array.
Definition: Tensor.cpp:465
Tensor NonZero() const
Definition: Tensor.cpp:1755
Tensor Abs_()
Element-wise absolute value of a tensor, in-place.
Definition: Tensor.cpp:1357
Tensor Solve(const Tensor &rhs) const
Definition: Tensor.cpp:1928
Tensor Sqrt() const
Element-wise square root of a tensor, returns a new tensor.
Definition: Tensor.cpp:1296
Tensor Contiguous() const
Definition: Tensor.cpp:772
Tensor Matmul(const Tensor &rhs) const
Definition: Tensor.cpp:1919
SizeVector shape_
SizeVector of the Tensor. shape_[i] is the length of dimension i.
Definition: Tensor.h:1309
void IndexSet(const std::vector< Tensor > &index_tensors, const Tensor &src_tensor)
Advanced indexing getter.
Definition: Tensor.cpp:936
int64_t NumDims() const
Definition: Tensor.h:1172
std::tuple< Tensor, Tensor > Triul(const int diagonal=0) const
Returns the tuple of upper and lower triangular matrix of the 2D tensor, above and below the given di...
Definition: Tensor.cpp:1976
bool IsContiguous() const
Definition: Tensor.h:1036
Tensor AsStrided(const SizeVector &new_shape, const SizeVector &new_strides) const
Create a Tensor view of specified shape and strides. The underlying buffer and data_ptr offsets remai...
Definition: Tensor.cpp:1061
Tensor Neg() const
Element-wise negation of a tensor, returning a new tensor.
Definition: Tensor.cpp:1329
Tensor Append(const Tensor &other, const utility::optional< int64_t > &axis=utility::nullopt) const
Appends the other tensor, along the given axis and returns a copy of the tensor. The other tensors mu...
Definition: Tensor.cpp:622
void CopyFrom(const Tensor &other)
Copy Tensor values to current tensor from the source tensor.
Definition: Tensor.cpp:770
Tensor Triu(const int diagonal=0) const
Returns the upper triangular matrix of the 2D tensor, above the given diagonal index....
Definition: Tensor.cpp:1964
DLManagedTensorVersioned * ToDLPackVersioned() const
Convert the Tensor to DLManagedTensorVersioned (DLPack v1.x).
Definition: Tensor.cpp:1811
Tensor Sum(const SizeVector &dims, bool keepdim=false) const
Definition: Tensor.cpp:1240
void Save(const std::string &file_name) const
Save tensor to numpy's npy format.
Definition: Tensor.cpp:1877
Tensor Gt(const Tensor &value) const
Element-wise greater-than of tensors, returning a new boolean tensor.
Definition: Tensor.cpp:1554
std::vector< Tensor > NonZeroNumpy() const
Definition: Tensor.cpp:1746
Tensor ArgMax(const SizeVector &dims) const
Definition: Tensor.cpp:1289
Tensor Broadcast(const SizeVector &dst_shape) const
Broadcast Tensor to a new broadcastable shape.
Definition: Tensor.cpp:628
Tensor LogicalAnd(const Tensor &value) const
Definition: Tensor.cpp:1453
Tensor IndexExtract(int64_t dim, int64_t idx) const
Definition: Tensor.cpp:841
Tensor Ge(const Tensor &value) const
Definition: Tensor.cpp:1618
Tensor Eq(const Tensor &value) const
Element-wise equals-to of tensors, returning a new boolean tensor.
Definition: Tensor.cpp:1682
static Tensor Arange(const Scalar start, const Scalar stop, const Scalar step=1, const Dtype dtype=core::Int64, const Device &device=core::Device("CPU:0"))
Create a 1D tensor with evenly spaced values in the given interval.
Definition: Tensor.cpp:436
Tensor Expand(const SizeVector &dst_shape) const
Definition: Tensor.cpp:638
Tensor Transpose(int64_t dim0, int64_t dim1) const
Transpose a Tensor by swapping dimension dim0 and dim1.
Definition: Tensor.cpp:1068
Tensor Neg_()
Element-wise negation of a tensor, in-place.
Definition: Tensor.cpp:1335
ConstIterator cend() const
Definition: Tensor.cpp:345
Tensor Ge_(const Tensor &value)
Definition: Tensor.cpp:1636
Tensor Ne(const Tensor &value) const
Element-wise not-equals-to of tensors, returning a new boolean tensor.
Definition: Tensor.cpp:1714
Tensor Round() const
Element-wise round value of a tensor, returning a new tensor.
Definition: Tensor.cpp:1423
Dtype GetDtype() const
Definition: Tensor.h:1164
Tensor Trunc() const
Element-wise trunc value of a tensor, returning a new tensor.
Definition: Tensor.cpp:1429
Tensor LogicalXor(const Tensor &value) const
Definition: Tensor.cpp:1520
void IndexAdd_(int64_t dim, const Tensor &index, const Tensor &src)
Advanced in-place reduction by index.
Definition: Tensor.cpp:991
std::tuple< Tensor, Tensor > LUIpiv() const
Computes LU factorisation of the 2D square tensor, using A = P * L * U; where P is the permutation ma...
Definition: Tensor.cpp:1956
Tensor Any(const utility::optional< SizeVector > &dims=utility::nullopt, bool keepdim=false) const
Definition: Tensor.cpp:1789
Tensor LogicalNot() const
Definition: Tensor.cpp:1442
Tensor Tril(const int diagonal=0) const
Returns the lower triangular matrix of the 2D tensor, above the given diagonal index....
Definition: Tensor.cpp:1970
Tensor Clip_(Scalar min_val, Scalar max_val)
Definition: Tensor.cpp:1398
static Tensor FromDLPack(const DLManagedTensor *dlmt, std::function< void(void *)> deleter=nullptr)
Convert DLManagedTensor to Tensor (DLPack v0.x).
Definition: Tensor.cpp:1868
const SizeVector & GetStridesRef() const
Definition: Tensor.h:1137
Tensor Exp() const
Element-wise exponential of a tensor, returning a new tensor.
Definition: Tensor.cpp:1340
Tensor Cos() const
Element-wise cosine of a tensor, returning a new tensor.
Definition: Tensor.cpp:1318
Tensor Inverse() const
Definition: Tensor.cpp:1982
Tensor GetItem(const TensorKey &tk) const
Definition: Tensor.cpp:473
static Tensor Load(const std::string &file_name)
Load tensor from numpy's npy format.
Definition: Tensor.cpp:1881
Tensor LogicalAnd_(const Tensor &value)
Definition: Tensor.cpp:1472
Tensor Prod(const SizeVector &dims, bool keepdim=false) const
Definition: Tensor.cpp:1261
Tensor Sub_(const Tensor &value)
Definition: Tensor.cpp:1153
Tensor Permute(const SizeVector &dims) const
Permute (dimension shuffle) the Tensor, returns a view.
Definition: Tensor.cpp:1028
std::tuple< Tensor, Tensor, Tensor > LU(const bool permute_l=false) const
Computes LU factorisation of the 2D square tensor, using A = P * L * U; where P is the permutation ma...
Definition: Tensor.cpp:1948
bool IsNonZero() const
Definition: Tensor.cpp:1757
Dtype dtype_
Data type.
Definition: Tensor.h:1336
Tensor Sub(const Tensor &value) const
Substracts a tensor and returns the resulting tensor.
Definition: Tensor.cpp:1133
static Tensor Eye(int64_t n, Dtype dtype, const Device &device)
Create an identity matrix of size n x n.
Definition: Tensor.cpp:418
Tensor IsFinite() const
Definition: Tensor.cpp:1382
Tensor Abs() const
Element-wise absolute value of a tensor, returning a new tensor.
Definition: Tensor.cpp:1351
Tensor SetItem(const Tensor &value)
Set all items. Equivalent to tensor[:] = value in Python.
Definition: Tensor.cpp:564
Tensor Max(const SizeVector &dims, bool keepdim=false) const
Definition: Tensor.cpp:1275
Tensor IndexGet(const std::vector< Tensor > &index_tensors) const
Advanced indexing getter. This will always allocate a new Tensor.
Definition: Tensor.cpp:905
Tensor Flatten(int64_t start_dim=0, int64_t end_dim=-1) const
Definition: Tensor.cpp:685
Tensor Sin() const
Element-wise sine of a tensor, returning a new tensor.
Definition: Tensor.cpp:1307
int64_t NumElements() const
Definition: Tensor.h:1170
Tensor Mul_(const Tensor &value)
Definition: Tensor.cpp:1189
Tensor All(const utility::optional< SizeVector > &dims=utility::nullopt, bool keepdim=false) const
Definition: Tensor.cpp:1770
Tensor Le(const Tensor &value) const
Definition: Tensor.cpp:1650
Tensor Clip(Scalar min_val, Scalar max_val) const
Definition: Tensor.cpp:1392
static Tensor Zeros(const SizeVector &shape, Dtype dtype, const Device &device=Device("CPU:0"))
Create a tensor fill with zeros.
Definition: Tensor.cpp:406
Tensor Ceil() const
Element-wise ceil value of a tensor, returning a new tensor.
Definition: Tensor.cpp:1417
Tensor Add(const Tensor &value) const
Adds a tensor and returns the resulting tensor.
Definition: Tensor.cpp:1097
Tensor Sqrt_()
Element-wise square root of a tensor, in-place.
Definition: Tensor.cpp:1302
static Tensor Diag(const Tensor &input)
Create a square matrix with specified diagonal elements in input.
Definition: Tensor.cpp:424
Tensor View(const SizeVector &dst_shape) const
Definition: Tensor.cpp:721
Tensor LogicalOr(const Tensor &value) const
Definition: Tensor.cpp:1487
Tensor Lt_(const Tensor &value)
Definition: Tensor.cpp:1604
Tensor Gt_(const Tensor &value)
Definition: Tensor.cpp:1572
Tensor Ne_(const Tensor &value)
Definition: Tensor.cpp:1732
Tensor IsClose(const Tensor &other, double rtol=1e-5, double atol=1e-8) const
Definition: Tensor.cpp:1900
static Tensor FromDLPackVersioned(const DLManagedTensorVersioned *dlmt, std::function< void(void *)> deleter=nullptr)
Convert DLManagedTensorVersioned to Tensor (DLPack v1.x).
Definition: Tensor.cpp:1872
Tensor Add_(const Tensor &value)
Definition: Tensor.cpp:1117
Device GetDevice() const override
Definition: Tensor.cpp:1435
std::shared_ptr< Blob > blob_
Underlying memory buffer for Tensor.
Definition: Tensor.h:1339
Tensor ReinterpretCast(const core::Dtype &dtype) const
Definition: Tensor.cpp:388
Tensor LeastSquares(const Tensor &rhs) const
Definition: Tensor.cpp:1938
Tensor Min(const SizeVector &dims, bool keepdim=false) const
Definition: Tensor.cpp:1268
Tensor Reshape(const SizeVector &dst_shape) const
Definition: Tensor.cpp:671
Tensor Clone() const
Copy Tensor to the same device.
Definition: Tensor.h:502
Tensor operator[](int64_t i) const
Extract the i-th Tensor along the first axis, returning a new view.
Definition: Tensor.cpp:839
std::string ToString(bool with_suffix=true, const std::string &indent="") const
Definition: Tensor.cpp:780
std::string ScalarPtrToString(const void *ptr) const
Definition: Tensor.cpp:825
Tensor Mean(const SizeVector &dims, bool keepdim=false) const
Definition: Tensor.cpp:1247
static Tensor Empty(const SizeVector &shape, Dtype dtype, const Device &device=Device("CPU:0"))
Create a tensor with uninitialized values.
Definition: Tensor.cpp:400
static Tensor Ones(const SizeVector &shape, Dtype dtype, const Device &device=Device("CPU:0"))
Create a tensor fill with ones.
Definition: Tensor.cpp:412
Tensor Div_(const Tensor &value)
Definition: Tensor.cpp:1225
Tensor IsInf() const
Definition: Tensor.cpp:1372
Tensor IsNan() const
Definition: Tensor.cpp:1362
bool IsSame(const Tensor &other) const
Definition: Tensor.cpp:1912
Tensor Cos_()
Element-wise cosine of a tensor, in-place.
Definition: Tensor.cpp:1324
Tensor Le_(const Tensor &value)
Definition: Tensor.cpp:1668
SizeVector GetShape() const
Definition: Tensor.h:1127
std::tuple< Tensor, Tensor, Tensor > SVD() const
Definition: Tensor.cpp:1990
Tensor Sin_()
Element-wise sine of a tensor, in-place.
Definition: Tensor.cpp:1313
void Fill(S v)
Fill the whole Tensor with a scalar value, the scalar will be casted to the Tensor's Dtype.
Definition: Tensor.h:1400
Tensor T() const
Expects input to be <= 2-D Tensor by swapping dimension 0 and 1.
Definition: Tensor.cpp:1079
Tensor ArgMin(const SizeVector &dims) const
Definition: Tensor.cpp:1282
Tensor Mul(const Tensor &value) const
Multiplies a tensor and returns the resulting tensor.
Definition: Tensor.cpp:1169
Tensor Slice(int64_t dim, int64_t start, int64_t stop, int64_t step=1) const
Definition: Tensor.cpp:857
Tensor Div(const Tensor &value) const
Divides a tensor and returns the resulting tensor.
Definition: Tensor.cpp:1205
Tensor To(Dtype dtype, bool copy=false) const
Definition: Tensor.cpp:739
DLManagedTensor * ToDLPack() const
Convert the Tensor to DLManagedTensor (DLPack v0.x).
Definition: Tensor.cpp:1808
Tensor Floor() const
Element-wise floor value of a tensor, returning a new tensor.
Definition: Tensor.cpp:1411
const SizeVector & GetShapeRef() const
Definition: Tensor.h:1129
Tensor Lt(const Tensor &value) const
Element-wise less-than of tensors, returning a new boolean tensor.
Definition: Tensor.cpp:1586
Tensor LogicalXor_(const Tensor &value)
Definition: Tensor.cpp:1539
static Tensor Full(const SizeVector &shape, T fill_value, Dtype dtype, const Device &device=Device("CPU:0"))
Create a tensor fill with specified value.
Definition: Tensor.h:253
ConstIterator cbegin() const
Definition: Tensor.cpp:338
bool AllEqual(const Tensor &other) const
Definition: Tensor.cpp:1885
Tensor Exp_()
Element-wise base-e exponential of a tensor, in-place.
Definition: Tensor.cpp:1346
Tensor Eq_(const Tensor &value)
Definition: Tensor.cpp:1700
constexpr bool has_value() const noexcept
Definition: Optional.h:440
constexpr T const & value() const &
Definition: Optional.h:465
#define LogWarning(...)
Definition: Logging.h:72
#define LogError(...)
Definition: Logging.h:60
void BinaryEW(const Tensor &lhs, const Tensor &rhs, Tensor &dst, BinaryEWOpCode op_code)
Definition: BinaryEW.cpp:30
void IndexSet(const Tensor &src, Tensor &dst, const std::vector< Tensor > &index_tensors, const SizeVector &indexed_shape, const SizeVector &indexed_strides)
Definition: IndexGetSet.cpp:52
void Copy(const Tensor &src, Tensor &dst)
Definition: UnaryEW.cpp:66
void IndexAdd_(int64_t dim, const Tensor &index, const Tensor &src, Tensor &dst)
Tensor NonZero(const Tensor &src)
Definition: NonZero.cpp:19
void UnaryEW(const Tensor &src, Tensor &dst, UnaryEWOpCode op_code)
Definition: UnaryEW.cpp:19
void Reduction(const Tensor &src, Tensor &dst, const SizeVector &dims, bool keepdim, ReductionOpCode op_code)
Definition: Reduction.cpp:16
void IndexGet(const Tensor &src, Tensor &dst, const std::vector< Tensor > &index_tensors, const SizeVector &indexed_shape, const SizeVector &indexed_strides)
Definition: IndexGetSet.cpp:22
Tensor Arange(const Tensor &start, const Tensor &stop, const Tensor &step)
Definition: Arange.cpp:17
int64_t WrapDim(int64_t dim, int64_t max_dim, bool inclusive)
Wrap around negative dim.
Definition: ShapeUtil.cpp:131
bool CanBeBrocastedToShape(const SizeVector &src_shape, const SizeVector &dst_shape)
Returns true if src_shape can be brocasted to dst_shape.
Definition: ShapeUtil.cpp:90
SizeVector BroadcastedShape(const SizeVector &l_shape, const SizeVector &r_shape)
Returns the broadcasted shape of two shapes.
Definition: ShapeUtil.cpp:56
SizeVector ReductionShape(const SizeVector &src_shape, const SizeVector &dims, bool keepdim)
Returns the shape after reduction.
Definition: ShapeUtil.cpp:99
std::pair< bool, SizeVector > Restride(const SizeVector &old_shape, const SizeVector &old_strides, const SizeVector &new_shape)
Definition: ShapeUtil.cpp:225
SizeVector Iota(int64_t n)
Returns a SizeVector of {0, 1, ..., n - 1}, similar to std::iota.
Definition: ShapeUtil.cpp:205
SizeVector InferShape(SizeVector shape, int64_t num_elements)
Definition: ShapeUtil.cpp:150
SizeVector DefaultStrides(const SizeVector &shape)
Compute default strides for a shape when a tensor is contiguous.
Definition: ShapeUtil.cpp:214
static Dtype DLDataTypeToDtype(const DLDataType &dltype)
Definition: Tensor.cpp:60
const Dtype Undefined
Definition: Dtype.cpp:41
void LeastSquares(const Tensor &A, const Tensor &B, Tensor &X)
Solve AX = B with QR decomposition. A is a full-rank m x n matrix (m >= n).
const Dtype Int8
Definition: Dtype.cpp:44
const Dtype Bool
Definition: Dtype.cpp:52
void Solve(const Tensor &A, const Tensor &B, Tensor &X)
Solve AX = B with LU decomposition. A is a square matrix.
Definition: Solve.cpp:22
void SVD(const Tensor &A, Tensor &U, Tensor &S, Tensor &VT)
Definition: SVD.cpp:17
void LUIpiv(const Tensor &A, Tensor &ipiv, Tensor &output)
Definition: LU.cpp:62
const Dtype Int64
Definition: Dtype.cpp:47
const Dtype UInt64
Definition: Dtype.cpp:51
const Dtype UInt32
Definition: Dtype.cpp:50
void Triu(const Tensor &A, Tensor &output, const int diagonal)
Definition: Tri.cpp:35
void Triul(const Tensor &A, Tensor &upper, Tensor &lower, const int diagonal)
Definition: Tri.cpp:79
const Dtype UInt8
Definition: Dtype.cpp:48
const Dtype Int16
Definition: Dtype.cpp:45
Tensor Append(const Tensor &self, const Tensor &other, const utility::optional< int64_t > &axis)
Appends the two tensors, along the given axis into a new tensor. Both the tensors must have same data...
void Inverse(const Tensor &A, Tensor &output)
Computes A^{-1} with LU factorization, where A is a N x N square matrix.
Definition: Inverse.cpp:18
void Tril(const Tensor &A, Tensor &output, const int diagonal)
Definition: Tri.cpp:57
void Matmul(const Tensor &A, const Tensor &B, Tensor &output)
Computes matrix multiplication C = AB.
Definition: Matmul.cpp:17
static DLDataTypeCode DtypeToDLDataTypeCode(const Dtype &dtype)
Definition: Tensor.cpp:44
void LU(const Tensor &A, Tensor &permutation, Tensor &lower, Tensor &upper, const bool permute_l)
Definition: LU.cpp:126
const Dtype Float64
Definition: Dtype.cpp:43
double Det(const Tensor &A)
Definition: Det.cpp:16
const Dtype UInt16
Definition: Dtype.cpp:49
constexpr utility::nullopt_t None
Definition: TensorKey.h:20
const Dtype Int32
Definition: Dtype.cpp:46
const Dtype Float32
Definition: Dtype.cpp:42
core::Tensor ReadNpy(const std::string &file_name)
Definition: NumpyIO.cpp:662
void WriteNpy(const std::string &file_name, const core::Tensor &tensor)
Definition: NumpyIO.cpp:671
Generic file read and write utility for python interface.
Definition: Eigen.h:85
The data type the tensor can hold. The data type is assumed to follow the native endian-ness....
Definition: DLPack.h:226
uint16_t lanes
Number of lanes in the type, used for vector types.
Definition: DLPack.h:238
uint8_t bits
Number of bits, common choices are 8, 16, 32.
Definition: DLPack.h:236
uint8_t code
Type code of base types. We keep it uint8_t instead of DLDataTypeCode for minimal memory footprint,...
Definition: DLPack.h:232
A Device for Tensor and operator.
Definition: DLPack.h:146
A versioned and managed C Tensor object, manage memory of DLTensor.
Definition: DLPack.h:366
DLPackVersion version
The API and ABI version of the current managed Tensor.
Definition: DLPack.h:370
uint64_t flags
Additional bitmask flags information about the tensor.
Definition: DLPack.h:398
C Tensor object, manage memory of DLTensor. This data structure is intended to facilitate the borrowi...
Definition: DLPack.h:319
uint32_t minor
DLPack minor version.
Definition: DLPack.h:83
uint32_t major
DLPack major version.
Definition: DLPack.h:81
Plain C Tensor object, does not manage memory.
Definition: DLPack.h:244
int32_t ndim
Number of dimensions.
Definition: DLPack.h:278
int64_t * strides
strides of the tensor (in number of elements, not bytes), can not be NULL if ndim !...
Definition: DLPack.h:300
DLDevice device
The device of the tensor.
Definition: DLPack.h:276
uint64_t byte_offset
The offset in bytes to the beginning pointer to data.
Definition: DLPack.h:302
void * data
The data pointer points to the allocated data. This will be CUDA device pointer or cl_mem handle in O...
Definition: DLPack.h:274
int64_t * shape
The shape of the tensor.
Definition: DLPack.h:286
DLDataType dtype
The data type of the pointer.
Definition: DLPack.h:280
Const iterator for Tensor.
Definition: Tensor.h:1234
bool operator!=(const ConstIterator &other) const
Definition: Tensor.cpp:333
ConstIterator(pointer tensor, int64_t index)
Definition: Tensor.cpp:291
bool operator==(const ConstIterator &other) const
Definition: Tensor.cpp:327
Iterator for Tensor.
Definition: Tensor.h:1207
Iterator(pointer tensor, int64_t index)
Definition: Tensor.cpp:224
bool operator==(const Iterator &other) const
Definition: Tensor.cpp:260
bool operator!=(const Iterator &other) const
Definition: Tensor.cpp:265