MAIA bb96820c
Multiphysics at AIA
Loading...
Searching...
No Matches
tensor.h
Go to the documentation of this file.
1// Copyright (C) 2024 The m-AIA AUTHORS
2//
3// This file is part of m-AIA (https://git.rwth-aachen.de/aia/m-AIA/m-AIA)
4//
5// SPDX-License-Identifier: LGPL-3.0-only
6
7#ifndef TENSOR_H_
8#define TENSOR_H_
9
10#include <ostream>
11#include "INCLUDE/maiatypes.h"
12#include "debug.h"
13#include "functions.h"
14
15namespace maia {
22namespace tensor {
23
24// Forward declaration of TensorStorage
25namespace detail_ {
26template <class T>
27class TensorStorage;
28}
29
40template <class T>
41class Tensor {
42 public:
43 // Public types
45 typedef T value_type;
47 typedef const value_type* const_pointer;
52 typedef MInt dim_type;
53
54 // Constructors & destructor
56 explicit Tensor(size_type n0, size_type n1 = 1, size_type n2 = 1, size_type n3 = 1, size_type n4 = 1);
57 Tensor(T* data, size_type n0, size_type n1 = 1, size_type n2 = 1, size_type n3 = 1, size_type n4 = 1);
59
60 size_type size() const;
61 size_type resize(size_type n0, size_type n1 = 1, size_type n2 = 1, size_type n3 = 1, size_type n4 = 1);
62 void assign(size_type n, const T& newValue);
63 void set(const T& value);
64 void clear();
65 void transpose();
66
67 void swap(Tensor<T>& other);
68 template <class TT>
69 friend void swap(Tensor<TT>& a, Tensor<TT>& b);
70
72 size_type dim0() const;
73 size_type dim1() const;
74 size_type dim2() const;
75 size_type dim3() const;
76 size_type dim4() const;
77
79 Tensor<T>(Tensor<T>&& copy) = default;
80 Tensor<T>(const Tensor<T>& copy) = default;
81
82
84 const T& operator[](size_type index) const;
86 const T& operator()(size_type i0) const;
88 const T& operator()(size_type i0, size_type i1) const;
90 const T& operator()(size_type i0, size_type i1, size_type i2) const;
92 const T& operator()(size_type i0, size_type i1, size_type i2, size_type i3) const;
94 const T& operator()(size_type i0, size_type i1, size_type i2, size_type i3, size_type i4) const;
95
96 private:
97 static const dim_type m_maxNoDims = 5;
99
103};
104
105
112template <class T>
113inline Tensor<T>::Tensor() : m_data(), m_size(0) {
114 m_dim[0] = 0;
115 m_dim[1] = 0;
116 m_dim[2] = 0;
117 m_dim[3] = 0;
118 m_dim[4] = 0;
119}
120
134template <class T>
136 ASSERT(n0 > 0, "Dimension n0 must be greater than zero");
137 ASSERT(n1 > 0, "Dimension n1 must be greater than zero");
138 ASSERT(n2 > 0, "Dimension n2 must be greater than zero");
139 ASSERT(n3 > 0, "Dimension n3 must be greater than zero");
140 ASSERT(n4 > 0, "Dimension n4 must be greater than zero");
141
142 m_dim[0] = n0;
143 m_dim[1] = n1;
144 m_dim[2] = n2;
145 m_dim[3] = n3;
146 m_dim[4] = n4;
147
148 m_size = n0 * n1 * n2 * n3 * n4;
149 m_data.resize(m_size);
150}
151
152
166template <class T>
168 ASSERT(n0 > 0, "Dimension n0 must be greater than zero");
169 ASSERT(n1 > 0, "Dimension n1 must be greater than zero");
170 ASSERT(n2 > 0, "Dimension n2 must be greater than zero");
171 ASSERT(n3 > 0, "Dimension n3 must be greater than zero");
172 ASSERT(n4 > 0, "Dimension n4 must be greater than zero");
173
174 m_dim[0] = n0;
175 m_dim[1] = n1;
176 m_dim[2] = n2;
177 m_dim[3] = n3;
178 m_dim[4] = n4;
179
180 m_size = n0 * n1 * n2 * n3 * n4;
181 m_data.resize(m_size, data);
182}
183
190template <class T>
192 clear();
193}
194
195
205template <class T>
206inline typename Tensor<T>::size_type Tensor<T>::size() const {
207 return m_size;
208}
209
210
229template <class T>
231 size_type n4) {
232 m_dim[0] = n0;
233 m_dim[1] = n1;
234 m_dim[2] = n2;
235 m_dim[3] = n3;
236 m_dim[4] = n4;
237
238 m_size = n0 * n1 * n2 * n3 * n4;
239 m_data.resize(size());
240
241 return size();
242}
243
244
255template <class T>
256inline void Tensor<T>::assign(size_type n, const T& value) {
257 resize(n);
258 set(value);
259}
260
261
270template <class T>
271inline void Tensor<T>::set(const T& value) {
272 std::fill_n(&m_data[0], size(), value);
273}
274
275
282template <class T>
283inline void Tensor<T>::clear() {
284 m_dim[0] = 0;
285 m_dim[1] = 0;
286 m_dim[2] = 0;
287 m_dim[3] = 0;
288 m_dim[4] = 0;
289
290 m_size = 0;
291 m_data.clear();
292}
293
294
305template <class T>
306inline void Tensor<T>::transpose() {
307 Tensor<T> tmp(*this);
308
309 std::swap(m_dim[0], m_dim[1]);
310
311 for(MInt i = 0; i < tmp.dim0(); i++) {
312 for(MInt j = 0; j < tmp.dim1(); j++) {
313 (*this)(j, i) = tmp(i, j);
314 }
315 }
316}
317
318
328template <class T>
329inline void Tensor<T>::swap(Tensor<T>& other) {
330 using std::swap;
331 swap(m_data, other.m_data);
332 swap(m_size, other.m_size);
333 for(dim_type i = 0; i < m_maxNoDims; ++i)
334 swap(m_dim[i], other.m_dim[i]);
335}
336
337
348template <class T>
350 ASSERT(d >= 0, "Dimension d must be greater than or equal to zero!");
351 ASSERT(d < m_maxNoDims, "Dimension d must be less than m_maxNoDims!");
352
353 return m_dim[d];
354}
355
356
365template <class T>
366inline typename Tensor<T>::size_type Tensor<T>::dim0() const {
367 return m_dim[0];
368}
369
370
379template <class T>
380inline typename Tensor<T>::size_type Tensor<T>::dim1() const {
381 return m_dim[1];
382}
383
384
393template <class T>
394inline typename Tensor<T>::size_type Tensor<T>::dim2() const {
395 return m_dim[2];
396}
397
398
407template <class T>
408inline typename Tensor<T>::size_type Tensor<T>::dim3() const {
409 return m_dim[3];
410}
411
412
421template <class T>
422inline typename Tensor<T>::size_type Tensor<T>::dim4() const {
423 return m_dim[4];
424}
425
426
437template <class T>
439 swap(copy);
440
441 return *this;
442}
443
444
458template <class T>
460 ASSERT(index >= 0 && index < size(), "Index out of bounds");
461
462 return m_data[index];
463}
464
465
479template <class T>
480inline const T& Tensor<T>::operator[](size_type index) const {
481 ASSERT(index >= 0 && index < size(), "Index out of bounds");
482
483 return m_data[index];
484}
485
486
497template <class T>
499 ASSERT(i0 >= 0 && i0 < dim0(), "Index i0 out of bounds");
500
501 return m_data[i0];
502}
503
504
515template <class T>
516inline const T& Tensor<T>::operator()(size_type i0) const {
517 ASSERT(i0 >= 0 && i0 < dim0(), "Index i0 out of bounds");
518
519 return m_data[i0];
520}
521
522
534template <class T>
536 ASSERT(i0 >= 0 && i0 < dim0(), "Index i0 out of bounds");
537 ASSERT(i1 >= 0 && i1 < dim1(), "Index i1 out of bounds");
538
539 return m_data[i0 * dim1() + i1];
540}
541
542
554template <class T>
555inline const T& Tensor<T>::operator()(size_type i0, size_type i1) const {
556 ASSERT(i0 >= 0 && i0 < dim0(), "Index i0 out of bounds");
557 ASSERT(i1 >= 0 && i1 < dim1(), "Index i1 out of bounds");
558
559 return m_data[i0 * dim1() + i1];
560}
561
562
575template <class T>
577 ASSERT(i0 >= 0 && i0 < dim0(), "Index i0 out of bounds");
578 ASSERT(i1 >= 0 && i1 < dim1(), "Index i1 out of bounds");
579 ASSERT(i2 >= 0 && i2 < dim2(), "Index i2 out of bounds");
580
581 return m_data[i0 * dim1() * dim2() + i1 * dim2() + i2];
582}
583
584
597template <class T>
598inline const T& Tensor<T>::operator()(size_type i0, size_type i1, size_type i2) const {
599 ASSERT(i0 >= 0 && i0 < dim0(), "Index i0 out of bounds");
600 ASSERT(i1 >= 0 && i1 < dim1(), "Index i1 out of bounds");
601 ASSERT(i2 >= 0 && i2 < dim2(), "Index i2 out of bounds");
602
603 return m_data[i0 * dim1() * dim2() + i1 * dim2() + i2];
604}
605
606
620template <class T>
622 ASSERT(i0 >= 0 && i0 < dim0(), "Index i0 out of bounds");
623 ASSERT(i1 >= 0 && i1 < dim1(), "Index i1 out of bounds");
624 ASSERT(i2 >= 0 && i2 < dim2(), "Index i2 out of bounds");
625 ASSERT(i3 >= 0 && i3 < dim3(), "Index i3 out of bounds");
626
627 return m_data[i0 * dim1() * dim2() * dim3() + i1 * dim2() * dim3() + i2 * dim3() + i3];
628}
629
630
644template <class T>
645inline const T& Tensor<T>::operator()(size_type i0, size_type i1, size_type i2, size_type i3) const {
646 ASSERT(i0 >= 0 && i0 < dim0(), "Index i0 out of bounds");
647 ASSERT(i1 >= 0 && i1 < dim1(), "Index i1 out of bounds");
648 ASSERT(i2 >= 0 && i2 < dim2(), "Index i2 out of bounds");
649 ASSERT(i3 >= 0 && i3 < dim3(), "Index i3 out of bounds");
650
651 return m_data[i0 * dim1() * dim2() * dim3() + i1 * dim2() * dim3() + i2 * dim3() + i3];
652}
653
654
669template <class T>
671 ASSERT(i0 >= 0 && i0 < dim0(), "Index i0 out of bounds");
672 ASSERT(i1 >= 0 && i1 < dim1(), "Index i1 out of bounds");
673 ASSERT(i2 >= 0 && i2 < dim2(), "Index i2 out of bounds");
674 ASSERT(i3 >= 0 && i3 < dim3(), "Index i3 out of bounds");
675 ASSERT(i4 >= 0 && i4 < dim4(), "Index i4 out of bounds");
676
677 return m_data[i0 * dim1() * dim2() * dim3() * dim4() + i1 * dim2() * dim3() * dim4() + i2 * dim3() * dim4()
678 + i3 * dim4() + i4];
679}
680
681
696template <class T>
697inline const T& Tensor<T>::operator()(size_type i0, size_type i1, size_type i2, size_type i3, size_type i4) const {
698 ASSERT(i0 >= 0 && i0 < dim0(), "Index i0 out of bounds");
699 ASSERT(i1 >= 0 && i1 < dim1(), "Index i1 out of bounds");
700 ASSERT(i2 >= 0 && i2 < dim2(), "Index i2 out of bounds");
701 ASSERT(i3 >= 0 && i3 < dim3(), "Index i3 out of bounds");
702 ASSERT(i4 >= 0 && i4 < dim4(), "Index i4 out of bounds");
703
704 return m_data[i0 * dim1() * dim2() * dim3() * dim4() + i1 * dim2() * dim3() * dim4() + i2 * dim3() * dim4()
705 + i3 * dim4() + i4];
706}
707
708
721template <class TT>
722std::ostream& operator<<(std::ostream& os, const Tensor<TT>& t) {
723 for(MInt i = 0; i < t.dim0(); i++) {
724 for(MInt j = 0; j < t.dim1(); j++) {
725 for(MInt k = 0; k < t.dim2(); k++) {
726 for(MInt l = 0; l < t.dim3(); l++) {
727 os << "(" << i << "," << j << "," << k << "," << l << ") = ";
728 os << t(i, j, k, l) << std::endl;
729 }
730 }
731 }
732 }
733
734 os << "Dimensions (i,j,k,l) = (" << t.dim0() << "," << t.dim1() << "," << t.dim2() << "," << t.dim3() << ")"
735 << std::endl;
736
737 return os;
738}
739
740
751template <class TT>
752inline void swap(Tensor<TT>& a, Tensor<TT>& b) {
753 a.swap(b);
754}
755
756
758
759
760// Internal namespace for methods/class that are generally not needed outside of Tensor
761namespace detail_ {
762
779template <class T>
781 public:
782 // Public types
784 typedef T value_type;
786 typedef const value_type* const_pointer;
791
792 // Constructors & destructor
798
801 void resize(size_type n, T* data);
802
803 void clear();
804 void swap(TensorStorage<T>& other);
805 template <class TT>
807
810 const T& operator[](size_type n) const;
811
812 private:
815
816 private:
820};
821
822
829template <class T>
830inline TensorStorage<T>::TensorStorage() : m_data(0), m_size(0), m_isAllocated(false) {
831 // Nothing here
832}
833
834
846template <class T>
847inline TensorStorage<T>::TensorStorage(const TensorStorage<T>& ts) : m_data(0), m_size(0), m_isAllocated(false) {
848 // Allocate new memory and copy the data members
849 reallocate(ts.size());
850 std::copy(&ts.m_data[0], &ts.m_data[0] + ts.size(), m_data);
851}
852
853
862template <class T>
863inline TensorStorage<T>::TensorStorage(size_type n) : m_data(0), m_size(0), m_isAllocated(false) {
864 resize(n);
865}
866
867
882template <class T>
883inline TensorStorage<T>::TensorStorage(size_type n, T* data) : m_data(data), m_size(n), m_isAllocated(false) {
884 ASSERT(n >= 0, "New storage size must be greater or equal to zero.");
885 ASSERT(data != 0, "Data pointer may not be a null pointer.");
886}
887
888
895template <class T>
897 clear();
898}
899
900
909template <class T>
911 return m_size;
912}
913
914
923template <class T>
925 ASSERT(n >= 0, "New storage size must be greater or equal to zero.");
926
927 reallocate(n);
928}
929
930
941template <class T>
942inline void TensorStorage<T>::resize(size_type n, T* data) {
943 ASSERT(n >= 0, "New storage size must be greater or equal to zero.");
944 ASSERT(data != 0, "Data pointer may not be a null pointer.");
945
946 clear();
947 m_size = n;
948 m_data = data;
949}
950
951
958template <class T>
960 if(isAllocated()) {
961 delete[] m_data;
962 }
963
964 m_data = 0;
965 m_size = 0;
966 m_isAllocated = false;
967}
968
969
978template <class T>
980 using std::swap;
981 swap(m_data, other.m_data);
982 swap(m_size, other.m_size);
983 swap(m_isAllocated, other.m_isAllocated);
984}
985
986
997template <class TT>
999 a.swap(b);
1000}
1001
1002
1013template <class T>
1015 swap(copy);
1016
1017 return *this;
1018}
1019
1020
1031template <class T>
1033 ASSERT(n >= 0 && n < size(), "Index out of bounds");
1034
1035 return m_data[n];
1036}
1037
1038
1049template <class T>
1050inline const T& TensorStorage<T>::operator[](size_type n) const {
1051 ASSERT(n >= 0 && n < size(), "Index out of bounds");
1052
1053 return m_data[n];
1054}
1055
1056
1063template <class T>
1065 return m_isAllocated;
1066}
1067
1068
1078template <class T>
1079[[gnu::noinline]] // this is neccesary for flto compilation
1081 clear();
1082
1083 m_data = (n <= 0) ? nullptr : new T[std::min(n, PTRDIFF_MAX)];
1084 m_size = n;
1085 m_isAllocated = true;
1086}
1087
1088} // namespace detail_
1089
1090
1091} // namespace tensor
1092} // namespace maia
1093
1094// Define some types for ease of use
1104
1105#endif /* TENSOR_H_ */
Provides a lightweight and fast class for accessing 1D arrays as multi-dimensional tensors (up to 4D)...
Definition: tensor.h:41
size_type m_dim[m_maxNoDims]
Definition: tensor.h:102
T & operator()(size_type i0, size_type i1)
Provides tensor access element using index notation (2D, non-const version).
Definition: tensor.h:535
Tensor(T *data, size_type n0, size_type n1=1, size_type n2=1, size_type n3=1, size_type n4=1)
Initializes the Tensor object by setting the data pointer and the internal dimensions.
Definition: tensor.h:167
const_pointer const_iterator
Definition: tensor.h:51
void transpose()
Transposes the first two dimensions (i.e. acting as if the tensor is a matrix).
Definition: tensor.h:306
const T & operator[](size_type index) const
Returns a reference to the element at position index (const version).
Definition: tensor.h:480
size_type dim0() const
Return the size of dimension 0.
Definition: tensor.h:366
void clear()
Deletes the data (if internal storage was used) and resets dimensions to zero.
Definition: tensor.h:283
size_type dim1() const
Return the size of dimension 1.
Definition: tensor.h:380
void set(const T &value)
Initializes tensor to constant value.
Definition: tensor.h:271
void assign(size_type n, const T &newValue)
Resizes the tensor to a 1D vector of length 'n' and with initial value 'value'.
Definition: tensor.h:256
const T & operator()(size_type i0) const
Provides tensor element access using index notation (1D, const version).
Definition: tensor.h:516
const value_type & const_reference
Definition: tensor.h:49
size_type size() const
Returns the size of the array as product of all five dimensions (i.e. not the actual array size but t...
Definition: tensor.h:206
size_type dim(size_type d) const
Return the size of dimension d.
Definition: tensor.h:349
value_type * pointer
Definition: tensor.h:46
Tensor()
Default constructor does nothing but setting all internal member variables to zero.
Definition: tensor.h:113
DataStorage m_data
Definition: tensor.h:100
void swap(Tensor< T > &other)
Efficiently swap this tensor with another one (uses copying of pointers, no data is moved).
Definition: tensor.h:329
detail_::TensorStorage< T > DataStorage
Definition: tensor.h:98
T & operator()(size_type i0, size_type i1, size_type i2)
Provides tensor access element using index notation (3D, non-const version).
Definition: tensor.h:576
const T & operator()(size_type i0, size_type i1, size_type i2, size_type i3, size_type i4) const
Provides tensor element access using index notation (5D, const version).
Definition: tensor.h:697
T & operator()(size_type i0)
Provides tensor access element using index notation (1D, non-const version).
Definition: tensor.h:498
T & operator()(size_type i0, size_type i1, size_type i2, size_type i3)
Provides tensor access element using index notation (4D, non-const version).
Definition: tensor.h:621
size_type m_size
Definition: tensor.h:101
Tensor(size_type n0, size_type n1=1, size_type n2=1, size_type n3=1, size_type n4=1)
Initializes the Tensor object by setting the data pointer and the internal dimensions.
Definition: tensor.h:135
T & operator[](size_type index)
Returns a reference to the element at position index (non-const version).
Definition: tensor.h:459
T & operator()(size_type i0, size_type i1, size_type i2, size_type i3, size_type i4)
Provides tensor access element using index notation (5D, non-const version).
Definition: tensor.h:670
size_type resize(size_type n0, size_type n1=1, size_type n2=1, size_type n3=1, size_type n4=1)
Deletes the old data structure and creates a new one with the requested dimensions.
Definition: tensor.h:230
static const dim_type m_maxNoDims
Definition: tensor.h:97
size_type dim2() const
Return the size of dimension 2.
Definition: tensor.h:394
const value_type * const_pointer
Definition: tensor.h:47
Tensor< T > & operator=(Tensor< T > copy)
Assignment operator.
Definition: tensor.h:438
pointer iterator
Definition: tensor.h:50
friend void swap(Tensor< TT > &a, Tensor< TT > &b)
Non-member swap exchanges the contents of two Tensors.
Definition: tensor.h:752
const T & operator()(size_type i0, size_type i1, size_type i2) const
Provides tensor element access using index notation (3D, const version).
Definition: tensor.h:598
value_type & reference
Definition: tensor.h:48
size_type dim4() const
Return the size of dimension 4.
Definition: tensor.h:422
const T & operator()(size_type i0, size_type i1, size_type i2, size_type i3) const
Provides tensor element access using index notation (4D, const version).
Definition: tensor.h:645
size_type dim3() const
Return the size of dimension 3.
Definition: tensor.h:408
~Tensor()
Resets all internal pointers and variables to zero.
Definition: tensor.h:191
const T & operator()(size_type i0, size_type i1) const
Provides tensor element access using index notation (2D, const version).
Definition: tensor.h:555
A vector-like data storage class that supports both internal and external storage mechanisms.
Definition: tensor.h:780
TensorStorage(size_type n)
Creates a new TensorStorage object using internal storage.
Definition: tensor.h:863
TensorStorage(size_type n, T *data)
Creates a new TensorStorage object using external storage, i.e. no memory is allocated.
Definition: tensor.h:883
MBool isAllocated()
Returns true if this class has allocated its own memory, and false if external memory is used.
Definition: tensor.h:1064
~TensorStorage()
The destructor only calls clear().
Definition: tensor.h:896
void reallocate(size_type n)
Clears any existing internal data storage and then allocates new memory to store as many elements as ...
Definition: tensor.h:1080
TensorStorage()
Default constructor does not allocate any memory but creates a zero-sized storage container.
Definition: tensor.h:830
T & operator[](size_type n)
Returns a reference to the element at position n (non-const version).
Definition: tensor.h:1032
size_type size() const
Returns the current size of the data container.
Definition: tensor.h:910
void resize(size_type n)
Resizes the container by first dropping all existing elements and then reallocating new memory.
Definition: tensor.h:924
friend void swap(TensorStorage< TT > &a, TensorStorage< TT > &b)
Swap the contents between two TensorStorage objects.
Definition: tensor.h:998
void clear()
Clears the data storage by deallocating any previously allocated memory and setting the size to zero.
Definition: tensor.h:959
TensorStorage(const TensorStorage< T > &ts)
Copy constructor creates a copy of the provided object.
Definition: tensor.h:847
TensorStorage< T > & operator=(TensorStorage< T > copy)
Assignment operator copies another object to the current one.
Definition: tensor.h:1014
const value_type * const_pointer
Definition: tensor.h:786
void swap(TensorStorage< T > &other)
Swap the contents of the existing TensorStorage object with another one.
Definition: tensor.h:979
void resize(size_type n, T *data)
Resizes the container by first dropping all existing elements and then using the external data pointe...
Definition: tensor.h:942
const value_type & const_reference
Definition: tensor.h:788
const T & operator[](size_type n) const
Returns a reference to the element at position n (const version).
Definition: tensor.h:1050
int32_t MInt
Definition: maiatypes.h:62
int64_t MLong
Definition: maiatypes.h:64
bool MBool
Definition: maiatypes.h:58
void swap(TensorStorage< TT > &a, TensorStorage< TT > &b)
Swap the contents between two TensorStorage objects.
Definition: tensor.h:998
std::ostream & operator<<(std::ostream &os, const Tensor< TT > &t)
Prints the values of the Tensor object together with the respective index.
Definition: tensor.h:722
void swap(Tensor< TT > &a, Tensor< TT > &b)
Non-member swap exchanges the contents of two Tensors.
Definition: tensor.h:752
Namespace for auxiliary functions/classes.
Definition: contexttypes.h:19
maia::tensor::Tensor< MFloat > MFloatMatrix
Definition: tensor.h:1098
maia::tensor::Tensor< MInt > MIntVector
Definition: tensor.h:1096
maia::tensor::Tensor< MInt > MIntMatrix
Definition: tensor.h:1099
maia::tensor::Tensor< MFloat > MFloatTensor
Definition: tensor.h:1101
maia::tensor::Tensor< MInt > MIntTensor
Definition: tensor.h:1102
maia::tensor::Tensor< MFloat > MFloatVector
Definition: tensor.h:1095