ABACUS develop
Atomic-orbital Based Ab-initio Computation at UStc
Loading...
Searching...
No Matches
tensor.h
Go to the documentation of this file.
1#ifndef ATEN_CORE_TENSOR_H_
2#define ATEN_CORE_TENSOR_H_
3
9
10#include <ATen/kernels/memory.h>
11
12#include <base/macros/macros.h>
13
14// TODO:
15// 1. add log system
16// 2. add exception system
17// 3. refact cmake system, use cmake parant scope to construct the libraries
18
19namespace ct = container;
20
21namespace container {
22
32class Tensor {
33 public:
34
41 Tensor();
42
52 explicit Tensor(DataType data_type);
53
61
72
74
82 Tensor(const Tensor& other);
83
93 Tensor(Tensor&& other) noexcept;
94
95 ~Tensor();
107 template <typename T>
108 Tensor(std::initializer_list<T> values, DeviceType device = DeviceType::CpuDevice) :
109 Tensor(DataTypeToEnum<T>::value, device, TensorShape({static_cast<int64_t>(values.size())})) {
110 TEMPLATE_ALL_2(this->data_type_, this->device_,
112 this->data<T>(), values.begin(), this->NumElements()))
113 }
114
120 DataType data_type() const;
121
127 DeviceType device_type() const;
128
134 const TensorShape& shape() const;
135
141 int64_t NumElements() const;
142
148 void* data() const;
149
163 template <typename T>
164 T* data() const {
165 if ((std::is_same<T, float>::value && data_type_ != DataType::DT_FLOAT) ||
166 (std::is_same<T, int>::value && data_type_ != DataType::DT_INT) ||
167 (std::is_same<T, int64_t>::value && data_type_ != DataType::DT_INT64) ||
168 (std::is_same<T, double>::value && data_type_ != DataType::DT_DOUBLE) ||
169 (std::is_same<T, std::complex<float>>::value && data_type_ != DataType::DT_COMPLEX) ||
170 (std::is_same<T, std::complex<double>>::value && data_type_ != DataType::DT_COMPLEX_DOUBLE))
171 {
172 std::cerr << "Tensor data type does not match requested type." << std::endl;
173 exit(EXIT_FAILURE);
174 }
175 return buffer_->base<T>();
176 }
177
197 switch (data_type) {
199 return sizeof(float);
200 case DataType::DT_INT:
201 return sizeof(int32_t);
203 return sizeof(int64_t);
205 return sizeof(double);
207 return sizeof(std::complex<float>);
209 return sizeof(std::complex<double>);
210 default:
211 std::cerr << "Unsupported data type!" << std::endl;
212 exit(EXIT_FAILURE);
213 }
214 }
215
221 const TensorBuffer& buffer() const;
222
230 template <typename DEVICE>
233 return *this;
234 }
235 // Create output tensor on device
237
238 // Copy data to a specified device
239 // TODO: move the memory operator into the tensor_buff class.
240 TEMPLATE_ALL_2(this->data_type_, this->device_,
242 output.data<T_>(), this->data<T_>(), this->NumElements()))
243
244 return output;
245 }
246
268 template <typename DEVICE, typename T>
269 void copy_from_device(const T* data, int64_t num_elements = -1) {
270 if (num_elements == -1) {
271 num_elements = this->NumElements();
272 }
273 REQUIRES_OK(this->shape_.NumElements() >= num_elements,
274 "The number of elements of the input data must match the number of elements of the tensor.")
275
276 TEMPLATE_CZ_2(this->data_type_, this->device_,
278 this->data<T_>(), data, num_elements))
279 }
280
288 template <typename T>
289 Tensor cast() const {
290 // Create output tensor on device
292
293 // TODO: error handle of cast memory
294 // TODO: move the memory operator into the tensor_buff class.
295 // Copy data to a specified device
296 TEMPLATE_CZ_2(this->data_type_, this->device_,
298 output.data<T>(), this->data<T_>(), this->NumElements()))
299
300 return output;
301 }
302
306 void zero();
307
316
324 Tensor shaped(const TensorShape& shape) const;
325
336 Tensor slice(const std::vector<int>& start, const std::vector<int>& size) const;
337
351 void resize(const TensorShape& new_shape);
352
360 // TODO: Delete this function, and use a singleton allocator class.
362
373 template <typename T, typename... Indices>
374 T& get_value(Indices... indices) const {
375 if (sizeof...(Indices) != shape_.ndim()) {
376 throw std::invalid_argument("Incorrect number of indices.");
377 }
378
379 // Calculate the linear index corresponding to the given indices
380 size_t linearIndex = calculateLinearIndex(indices...);
381
382 // Access the element at the calculated linear index
383 return *reinterpret_cast<T*>(data<T>() + linearIndex);
384 }
385
397 template <typename T>
398 T* inner_most_ptr(const int &index) const {
399 if (shape_.ndim() > 2) {
400 throw std::invalid_argument("Invalid call, inner_most_ptr only support tensor rank <= 2!");
401 }
402 if (index > shape_.dim_size(static_cast<int>(shape_.ndim() - 2))) {
403 throw std::invalid_argument("Invalid index, index of the inner-most must less than the inner-most shape size!");
404 }
405 if (shape_.ndim() == 1) {
406 return data<T>() + index;
407 }
408 return data<T>() + index * shape_.dim_size(static_cast<int>(shape_.ndim()) - 1);
409 }
410
411
421 bool operator==(const Tensor& other) const;
422
432 Tensor& operator=(const Tensor& other);
433
445 Tensor& operator=(Tensor&& other) noexcept;
446
457 bool CopyFrom(const Tensor& other);
458
473 bool CopyFrom(const Tensor& other, const TensorShape& shape);
474
486 bool AllocateFrom(const Tensor& other, const TensorShape& shape);
487
499 template <typename T, size_t N, typename index_t = int64_t>
501 // Check if the tensor's rank is greater than 0
502 static_assert(N > 0,
503 "Accessor is used to access the data of a tensor with rank > 0, for scalars use *data<T>()");
504 // Check if the rank of the tensor matches the rank of the accessor
505 REQUIRES_OK(this->shape_.ndim() == N,
506 "The rank of the tensor must match the rank of the accessor.")
507 // Create and return a TensorAccessor object
508 return TensorAccessor<T, N, index_t>(this->data<T>(), this->shape_.dims().data(), this->shape_.strides().data());
509 }
510 template<typename T, size_t N, typename index_t = int>
512
520 void sync(const Tensor& rhs);
521
530 Tensor operator[] (const int& index) const;
531
532 explicit operator bool() const {
533 return this->NumElements() > 0;
534 }
535
536 template<typename T>
537 void set_value(T value) {
538 TEMPLATE_ALL_2(this->data_type_, this->device_,
539 kernels::set_memory<T, DEVICE_>()(this->data<T>(), value, this->NumElements()))
540 }
541
542protected:
543
548
553
558
563
576 template <typename... Indices>
577 size_t calculateLinearIndex(Indices... indices) const {
578 size_t stride = 1;
579 size_t linearIndex = 0;
580 size_t indexArray[] = { static_cast<size_t>(indices)... };
581
582 for (int ii = static_cast<int>(shape_.ndim()) - 1; ii >= 0; --ii) {
583 linearIndex += indexArray[ii] * stride;
584 stride *= shape_.dim_size(ii);
585 }
586 return linearIndex;
587 }
588
589 // This function is used to copy data and properties from another Tensor instance, 'other', into the current Tensor instance.
590 // The 'shape' parameter specifies the new shape for the current Tensor.
591 inline void CopyFromInternal(const Tensor& other, const TensorShape& shape) {
592 // Copy the data type and device from the 'other' Tensor.
593 data_type_ = other.data_type_;
594 device_ = other.device_;
595 // Set the shape of the current Tensor to the provided 'shape'.
596 shape_ = shape;
597 // Check if the buffer of the current Tensor is different from the buffer of the 'other' Tensor.
598 if (buffer_ != other.buffer_) {
599 // If the current Tensor has a buffer, decrease its reference count.
600 // Note this could indicate a deleted of current buffer_
601 if (buffer_) buffer_->unref();
602 // Assign the buffer of the 'other' Tensor to the current Tensor's buffer.
603 buffer_ = other.buffer_;
604 // Increase the reference count of the buffer to indicate shared ownership.
605 if (buffer_) buffer_->ref();
606 }
607 }
608
609};
610
621std::ostream& operator<<(std::ostream& os, const Tensor& tensor);
622
623} // namespace container
624
625#endif // ATEN_CORE_TENSOR_H_
An abstract base class for memory allocators.
Definition allocator.h:17
bool unref() const
Decreases the reference count by one.
Definition refcount.cpp:13
void ref() const
Increases the reference count by one.
Definition refcount.cpp:9
Definition tensor_accessor.h:68
Interface to access the raw ref-counted data buffer.
Definition tensor_buffer.h:13
T * base() const
Reinterpret the buffer as an array of type T.
Definition tensor_buffer.h:94
A class for representing the shape of a tensor.
Definition tensor_shape.h:13
int64_t dim_size(int dim) const
Get the size of a dimension in the tensor.
Definition tensor_shape.cpp:31
const std::vector< int64_t > & dims() const
Get all dimension sizes in the tensor.
Definition tensor_shape.cpp:36
int64_t NumElements() const
Returns the total number of elements in the shape.
Definition tensor_shape.cpp:51
unsigned int ndim() const
Get the ndim of the tensor.
Definition tensor_shape.cpp:46
A multi-dimensional array of elements of a single data type.
Definition tensor.h:32
Tensor()
Creates a 1-dimentional, 0-element float tensor.
Definition tensor.cpp:10
Tensor cast() const
Method to transform data from a given tensor object to the output tensor with a given data type.
Definition tensor.h:289
Tensor to_device() const
Method to transform data from a given tensor object to the output tensor with a given device type.
Definition tensor.h:231
void * data() const
Get a pointer to the data buffer of the tensor.
Definition tensor.cpp:73
static base::core::Allocator * GetAllocator(DeviceType device)
Get the Allocator object according to the given device type.
Definition tensor.cpp:79
size_t calculateLinearIndex(Indices... indices) const
Calculates the linear index corresponding to the given indices.
Definition tensor.h:577
T & get_value(Indices... indices) const
Get the element at the specified indices.
Definition tensor.h:374
T * inner_most_ptr(const int &index) const
Get the pointer to the specified row.
Definition tensor.h:398
int64_t NumElements() const
Get the total number of elements in the tensor.
Definition tensor.cpp:70
void sync(const Tensor &rhs)
Synchronize the current Tensor with another Tensor.
Definition tensor.cpp:296
void zero()
Set all elements in current tensor object to zero.
Definition tensor.cpp:97
bool AllocateFrom(const Tensor &other, const TensorShape &shape)
Copies data from another Tensor with memory allocation and specified shape.
Definition tensor.cpp:286
TensorAccessor< T, N, index_t > accessor() &&=delete
DeviceType device_type() const
Get the data type of the tensor.
Definition tensor.cpp:64
void reshape(TensorShape shape)
Set all elements in current tensor object to zero.
Definition tensor.cpp:103
bool operator==(const Tensor &other) const
Equality comparison operator for tensors.
Definition tensor.cpp:253
void resize(const TensorShape &new_shape)
Resize the tensor to the new shape.
Definition tensor.cpp:207
TensorBuffer * buffer_
The TensorBuffer object that holds the data of the tensor.
Definition tensor.h:562
TensorAccessor< T, N, index_t > accessor() const &
Accessor function for a multi-dimensional tensor.
Definition tensor.h:500
const TensorBuffer & buffer() const
Get the TensorBuffer object that holds the data of the tensor.
Definition tensor.cpp:76
DataType data_type() const
Get the data type of the tensor.
Definition tensor.cpp:61
Tensor slice(const std::vector< int > &start, const std::vector< int > &size) const
Return a new Tensor slice starting at the specified indices with the given size.
Definition tensor.cpp:147
static size_t SizeOfType(DataType data_type)
Returns the size of a single element for a given data type.
Definition tensor.h:196
void set_value(T value)
Definition tensor.h:537
Tensor shaped(const TensorShape &shape) const
Set all elements in current tensor object to zero.
Definition tensor.cpp:139
void copy_from_device(const T *data, int64_t num_elements=-1)
Copies data from a given device to the current tensor object.
Definition tensor.h:269
Tensor(std::initializer_list< T > values, DeviceType device=DeviceType::CpuDevice)
Constructor for the Tensor class using an initializer list of values.
Definition tensor.h:108
DataType data_type_
The data type of the tensor.
Definition tensor.h:547
Tensor & operator=(const Tensor &other)
Assignment operator overload for the Tensor class.
Definition tensor.cpp:220
Tensor operator[](const int &index) const
Access a sub-Tensor based on an index.
Definition tensor.cpp:312
~Tensor()
Definition tensor.cpp:55
TensorShape shape_
The shape of the tensor.
Definition tensor.h:557
DeviceType device_
The device type of the tensor.
Definition tensor.h:552
bool CopyFrom(const Tensor &other)
Copy the data from another tensor into this tensor.
Definition tensor.cpp:273
T * data() const
Get a typed pointer to the data buffer of the tensor.
Definition tensor.h:164
const TensorShape & shape() const
Get the shape of the tensor.
Definition tensor.cpp:67
void CopyFromInternal(const Tensor &other, const TensorShape &shape)
Definition tensor.h:591
Definition output.h:13
#define N
Definition exp.cpp:24
#define T
Definition exp.cpp:237
#define REQUIRES_OK(expr,...)
Definition macros.h:60
#define TEMPLATE_CZ_2(TYPE_ENUM, DEVICE_ENUM,...)
Definition macros.h:227
#define TEMPLATE_ALL_2(TYPE_ENUM, DEVICE_ENUM,...)
Definition macros.h:214
Definition tensor.cpp:8
DataType
Enumeration of data types for tensors. The DataType enum lists the supported data types for tensors....
Definition tensor_types.h:50
@ DT_COMPLEX
32-bit complex *‍/
@ DT_INT64
64-bit integer *‍/
@ DT_FLOAT
Single-precision floating point *‍/.
@ DT_INT
32-bit integer *‍/
@ DT_DOUBLE
Double-precision floating point *‍/.
DeviceType
The type of memory used by an allocator.
Definition tensor_types.h:73
@ CpuDevice
Memory type is CPU.
std::ostream & operator<<(std::ostream &os, const Tensor &tensor)
Overloaded operator<< for the Tensor class.
Definition tensor.cpp:329
Template struct for mapping a DataType to its corresponding enum value.
Definition tensor_types.h:194
Template struct for mapping a Device Type to its corresponding enum value.
Definition tensor_types.h:158
Casts memory between devices.
Definition memory.h:107
A functor to set memory to a constant value.
Definition memory.h:37
Synchronizes memory between devices.
Definition memory.h:58
This file contains the definition of the DataType enum class.
iclock::time_point start
Definition test_partition.cpp:22