ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
TensorFunction.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 
11 
12 namespace cloudViewer {
13 namespace core {
14 
15 static Tensor ConcatenateImpl(const std::vector<Tensor>& tensors,
16  const int64_t axis) {
17  const int num_tensors = tensors.size();
18  const int64_t num_dims = tensors[0].NumDims();
19  const int64_t axis_d = shape_util::WrapDim(axis, num_dims);
20 
21  const Device device = tensors[0].GetDevice();
22  const Dtype dtype = tensors[0].GetDtype();
23  SizeVector combined_shape = tensors[0].GetShape();
24 
25  // Asserts input tensor properties such as device, dtype and dimensions.
26  for (int i = 1; i < num_tensors; ++i) {
27  core::AssertTensorDevice(tensors[i], device);
28  core::AssertTensorDtype(tensors[i], dtype);
29 
30  if (tensors[i].NumDims() != num_dims) {
32  "All the input tensors must have same number of "
33  "dimensions, but the tensor at index 0 has {} dimension(s) "
34  "and the tensor at index {} has {} dimension(s).",
35  num_dims, i, tensors[i].NumDims());
36  }
37 
38  // Check Shape.
39  for (int64_t j = 0; j < num_dims; ++j) {
40  if (j != axis_d && combined_shape[j] != tensors[i].GetShape(j)) {
42  "All the input tensor dimensions, other than dimension "
43  "size along concatenation axis must be same, but along "
44  "dimension {}, the tensor at index 0 has size {} and "
45  "the tensor at index {} has size {}.",
46  j, combined_shape[j], i, tensors[i].GetShape(j));
47  }
48  }
49 
50  combined_shape[axis_d] += tensors[i].GetShape(axis_d);
51  }
52 
53  // Common TensorKey for dimensions < axis_d.
54  std::vector<TensorKey> common_tks;
55  for (int i = 0; i < axis_d; ++i) {
56  common_tks.push_back(TensorKey::Slice(0, combined_shape[i], 1));
57  }
58 
59  Tensor combined_tensor(combined_shape, dtype, device);
60 
61  // Cumulate length along `axis`.
62  int64_t cumulated_length = 0;
63  for (int i = 0; i < num_tensors; ++i) {
64  const int64_t local_length = tensors[i].GetShape(axis_d);
65 
66  // TensorKey(s) for individual tensors.
67  std::vector<TensorKey> local_tks = common_tks;
68  local_tks.push_back(TensorKey::Slice(
69  cumulated_length, cumulated_length + local_length, 1));
70 
71  cumulated_length += local_length;
72 
73  combined_tensor.SetItem(local_tks, tensors[i]);
74  }
75 
76  return combined_tensor;
77 }
78 
79 Tensor Concatenate(const std::vector<Tensor>& tensors,
80  const utility::optional<int64_t>& axis) {
81  const int num_tensors = tensors.size();
82 
83  if (num_tensors < 1) {
84  utility::LogError("Expected at least 1 tensor, but got 0.");
85  }
86  if (num_tensors == 1) {
87  std::vector<Tensor> split_tensors;
88  split_tensors.reserve(tensors[0].GetLength());
89 
90  for (int i = 0; i < tensors[0].GetLength(); ++i) {
91  split_tensors.push_back(tensors[0][i]);
92  }
93 
94  return Concatenate(split_tensors, axis);
95  }
96 
97  if (!axis.has_value()) {
98  std::vector<Tensor> flattened_tensors;
99  for (int i = 0; i < num_tensors; ++i) {
100  // TODO: Implement Tensor::FlattenTensor
101  flattened_tensors.push_back(
102  tensors[i].Reshape({tensors[i].NumElements(), 1}));
103  }
104 
105  return ConcatenateImpl(flattened_tensors, 0).Reshape({-1});
106  } else {
107  if (tensors[0].NumDims() == 0) {
109  "Zero-dimensional tensor can only be concatenated along "
110  "axis = null, but got {}.",
111  axis.value());
112  }
113 
114  return ConcatenateImpl(tensors, axis.value());
115  }
116 }
117 
118 Tensor Append(const Tensor& self,
119  const Tensor& other,
120  const utility::optional<int64_t>& axis) {
121  return Concatenate({self, other}, axis);
122 }
123 
124 Tensor Maximum(const Tensor& input, const Tensor& other) {
125  core::AssertTensorDevice(input, other.GetDevice());
126  core::AssertTensorDtype(input, other.GetDtype());
127 
128  Tensor dst_tensor(
130  input.GetDtype(), input.GetDevice());
131  kernel::BinaryEW(input, other, dst_tensor, kernel::BinaryEWOpCode::Maximum);
132 
133  return dst_tensor;
134 }
135 
136 Tensor Minimum(const Tensor& input, const Tensor& other) {
137  core::AssertTensorDevice(input, other.GetDevice());
138  core::AssertTensorDtype(input, other.GetDtype());
139 
140  Tensor dst_tensor(
142  input.GetDtype(), input.GetDevice());
143  kernel::BinaryEW(input, other, dst_tensor, kernel::BinaryEWOpCode::Minimum);
144 
145  return dst_tensor;
146 }
147 
148 } // namespace core
149 } // namespace cloudViewer
#define AssertTensorDevice(tensor,...)
Definition: TensorCheck.h:45
#define AssertTensorDtype(tensor,...)
Definition: TensorCheck.h:21
static TensorKey Slice(utility::optional< int64_t > start, utility::optional< int64_t > stop, utility::optional< int64_t > step)
Definition: TensorKey.cpp:138
int64_t NumDims() const
Definition: Tensor.h:1172
Dtype GetDtype() const
Definition: Tensor.h:1164
Tensor SetItem(const Tensor &value)
Set all items. Equivalent to tensor[:] = value in Python.
Definition: Tensor.cpp:564
Device GetDevice() const override
Definition: Tensor.cpp:1435
Tensor Reshape(const SizeVector &dst_shape) const
Definition: Tensor.cpp:671
SizeVector GetShape() const
Definition: Tensor.h:1127
constexpr bool has_value() const noexcept
Definition: Optional.h:440
constexpr T const & value() const &
Definition: Optional.h:465
#define LogError(...)
Definition: Logging.h:60
void BinaryEW(const Tensor &lhs, const Tensor &rhs, Tensor &dst, BinaryEWOpCode op_code)
Definition: BinaryEW.cpp:30
int64_t WrapDim(int64_t dim, int64_t max_dim, bool inclusive)
Wrap around negative dim.
Definition: ShapeUtil.cpp:131
SizeVector BroadcastedShape(const SizeVector &l_shape, const SizeVector &r_shape)
Returns the broadcasted shape of two shapes.
Definition: ShapeUtil.cpp:56
Tensor Concatenate(const std::vector< Tensor > &tensors, const utility::optional< int64_t > &axis)
Concatenates the list of tensors in their order, along the given axis into a new tensor....
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...
Tensor Minimum(const Tensor &input, const Tensor &other)
Computes the element-wise minimum of input and other. The tensors must have same data type and device...
Tensor Maximum(const Tensor &input, const Tensor &other)
Computes the element-wise maximum of input and other. The tensors must have same data type and device...
static Tensor ConcatenateImpl(const std::vector< Tensor > &tensors, const int64_t axis)
Generic file read and write utility for python interface.