ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
TensorList.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 <string>
11 
13 
14 namespace cloudViewer {
15 namespace core {
16 
18 static void AssertIsResizable(const TensorList& tensorlist,
19  const std::string& func_name) {
20  if (!tensorlist.IsResizable()) {
22  "TensorList::{}: TensorList is not resizable. Typically this "
23  "tensorlist is created with shared memory from a Tensor.",
24  func_name);
25  }
26 }
27 
28 TensorList TensorList::FromTensor(const Tensor& tensor, bool inplace) {
29  SizeVector shape = tensor.GetShape();
30  if (shape.size() == 0) {
31  utility::LogError("Tensor should at least have one dimension.");
32  }
33  SizeVector element_shape =
34  SizeVector(std::next(shape.begin()), shape.end());
35  int64_t size = shape[0];
36 
37  if (inplace) {
38  if (!tensor.IsContiguous()) {
40  "Tensor must be contiguous for inplace tensorlist "
41  "construction.");
42  }
43  return TensorList(element_shape, size, size, tensor,
44  /*is_resizable=*/false);
45  } else {
46  int64_t reserved_size = TensorList::ComputeReserveSize(size);
47  Tensor internal_tensor = Tensor::Empty(
48  shape_util::Concat({reserved_size}, element_shape),
49  tensor.GetDtype(), tensor.GetDevice());
50  internal_tensor.Slice(0, 0, size) = tensor;
51  return TensorList(element_shape, size, reserved_size, internal_tensor,
52  /*is_resizable=*/true);
53  }
54 }
55 
57  TensorList copied(*this);
58  copied.CopyFrom(*this);
59  return copied;
60 }
61 
62 void TensorList::CopyFrom(const TensorList& other) {
63  *this = other;
64  // Copy the full other.internal_tensor_, not just other.AsTensor().
66  // After copy, the resulting tensorlist is always resizable.
67  is_resizable_ = true;
68 }
69 
71  return internal_tensor_.Slice(0, 0, size_);
72 }
73 
74 void TensorList::Resize(int64_t new_size) {
75  AssertIsResizable(*this, __FUNCTION__);
76 
77  // Increase internal tensor size.
78  int64_t old_size = size_;
79  ResizeWithExpand(new_size);
80  internal_tensor_.Slice(0, old_size, new_size).Fill(0);
81 }
82 
83 void TensorList::PushBack(const Tensor& tensor) {
84  AssertIsResizable(*this, __FUNCTION__);
85 
86  AssertTensorDevice(tensor, GetDevice());
87  AssertTensorDtype(tensor, GetDtype());
89 
91  internal_tensor_[size_ - 1] = tensor; // same as operator[](-1) = tensor;
92 }
93 
94 void TensorList::Extend(const TensorList& other) {
95  AssertIsResizable(*this, __FUNCTION__);
96 
97  // Check consistency
98  if (element_shape_ != other.GetElementShape()) {
99  utility::LogError("TensorList shapes {} and {} are inconsistent.",
101  }
102  if (GetDevice() != other.GetDevice()) {
103  utility::LogError("TensorList device {} and {} are inconsistent.",
104  GetDevice().ToString(), other.GetDevice().ToString());
105  }
106  if (GetDtype() != other.GetDtype()) {
107  utility::LogError("TensorList dtype {} and {} are inconsistent.",
108  GetDtype().ToString(), other.GetDtype().ToString());
109  }
110 
111  // Expand *this.
112  int64_t other_size = other.GetSize();
113  ResizeWithExpand(size_ + other_size);
114 
115  // Needs to slice other since *this and other can be the same tensorlist.
116  // Assigning to a Tensor rvalue is an actual copy.
117  internal_tensor_.Slice(0, size_ - other_size, size_) =
118  other.AsTensor().Slice(0, 0, other_size);
119 }
120 
122  // A full copy of a is required.
123  TensorList result = a.Clone();
124  result.Extend(b);
125  return result;
126 }
127 
128 Tensor TensorList::operator[](int64_t index) const {
129  // WrapDim asserts index is within range.
130  index = shape_util::WrapDim(index, size_);
131  return internal_tensor_[index];
132 }
133 
135  AssertIsResizable(*this, __FUNCTION__);
137 }
138 
139 // Protected
140 void TensorList::ResizeWithExpand(int64_t new_size) {
141  int64_t new_reserved_size = ComputeReserveSize(new_size);
142  if (new_reserved_size <= reserved_size_) {
143  size_ = new_size;
144  } else {
145  Tensor new_internal_tensor(
146  shape_util::Concat({new_reserved_size}, element_shape_),
147  GetDtype(), GetDevice());
148  new_internal_tensor.Slice(0, 0, size_) =
150  internal_tensor_ = new_internal_tensor;
151  reserved_size_ = new_reserved_size;
152  size_ = new_size;
153  }
154 }
155 
156 int64_t TensorList::ComputeReserveSize(int64_t n) {
157  if (n < 0) {
158  utility::LogError("Negative tensorlist size {} is not supported.", n);
159  }
160 
161  int64_t base = 1;
162  if (n > (base << 61)) {
163  utility::LogError("Too large tensorlist size {} is not supported.", n);
164  }
165 
166  for (int i = 63; i >= 0; --i) {
167  // First nnz bit
168  if (((base << i) & n) > 0) {
169  if (n == (base << i)) {
170  // Power of 2: 2 * n. For instance, 8 tensors will be
171  // reserved for size=4
172  return (base << (i + 1));
173  } else {
174  // Non-power of 2: ceil(log(2)) * 2. For instance, 16
175  // tensors will be reserved for size=5
176  return (base << (i + 2));
177  }
178  }
179  }
180 
181  // No nnz bit: by default reserve 1 element.
182  return 1;
183 }
184 
185 std::string TensorList::ToString() const {
186  return fmt::format(
187  "TensorList[size: {}, element_shape: {}, dtype: {}, device: {}]",
189  GetDevice().ToString());
190 }
191 
192 } // namespace core
193 } // namespace cloudViewer
filament::Texture::InternalFormat format
int size
math::float4 next
#define AssertTensorDevice(tensor,...)
Definition: TensorCheck.h:45
#define AssertTensorDtype(tensor,...)
Definition: TensorCheck.h:21
#define AssertTensorShape(tensor,...)
Definition: TensorCheck.h:61
core::Tensor result
Definition: VtkUtils.cpp:76
std::string ToString() const
Returns string representation of device, e.g. "CPU:0", "CUDA:0".
Definition: Device.cpp:89
std::string ToString() const
Definition: Dtype.h:65
std::string ToString() const
Definition: SizeVector.cpp:132
Tensor AsTensor() const
Return the reference of the contained valid tensors with shared memory.
Definition: TensorList.cpp:70
TensorList()
Useful to support operator[] in a map.
Definition: TensorList.h:42
void CopyFrom(const TensorList &other)
Definition: TensorList.cpp:62
static TensorList Concatenate(const TensorList &a, const TensorList &b)
Definition: TensorList.cpp:121
std::string ToString() const
Definition: TensorList.cpp:185
SizeVector GetElementShape() const
Definition: TensorList.h:241
static TensorList FromTensor(const Tensor &tensor, bool inplace=false)
Definition: TensorList.cpp:28
TensorList Clone() const
Definition: TensorList.cpp:56
Tensor internal_tensor_
The internal tensor for data storage.
Definition: TensorList.h:320
void Extend(const TensorList &other)
Definition: TensorList.cpp:94
void Resize(int64_t new_size)
Definition: TensorList.cpp:74
SizeVector element_shape_
The shape for each element tensor in the tensorlist.
Definition: TensorList.h:301
void ResizeWithExpand(int64_t new_size)
Definition: TensorList.cpp:140
void PushBack(const Tensor &tensor)
Definition: TensorList.cpp:83
Tensor operator[](int64_t index) const
Definition: TensorList.cpp:128
static int64_t ComputeReserveSize(int64_t size)
Definition: TensorList.cpp:156
bool IsContiguous() const
Definition: Tensor.h:1036
Dtype GetDtype() const
Definition: Tensor.h:1164
Device GetDevice() const override
Definition: Tensor.cpp:1435
Tensor Clone() const
Copy Tensor to the same device.
Definition: Tensor.h:502
static Tensor Empty(const SizeVector &shape, Dtype dtype, const Device &device=Device("CPU:0"))
Create a tensor with uninitialized values.
Definition: Tensor.cpp:400
SizeVector GetShape() const
Definition: Tensor.h:1127
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 Slice(int64_t dim, int64_t start, int64_t stop, int64_t step=1) const
Definition: Tensor.cpp:857
#define LogError(...)
Definition: Logging.h:60
SizeVector Concat(const SizeVector &l_shape, const SizeVector &r_shape)
Concatenate two shapes.
Definition: ShapeUtil.cpp:199
int64_t WrapDim(int64_t dim, int64_t max_dim, bool inclusive)
Wrap around negative dim.
Definition: ShapeUtil.cpp:131
static void AssertIsResizable(const TensorList &tensorlist, const std::string &func_name)
Asserts that the tensor list is resizable.
Definition: TensorList.cpp:18
Generic file read and write utility for python interface.