$darkmode
Eigen-unsupported  5.0.1-dev
Tensor.h
1 // This file is part of Eigen, a lightweight C++ template library
2 // for linear algebra.
3 //
4 // Copyright (C) 2014 Benoit Steiner <benoit.steiner.goog@gmail.com>
5 // Copyright (C) 2013 Christian Seiler <christian@iwakd.de>
6 //
7 // This Source Code Form is subject to the terms of the Mozilla
8 // Public License v. 2.0. If a copy of the MPL was not distributed
9 // with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 
11 #ifndef EIGEN_CXX11_TENSOR_TENSOR_H
12 #define EIGEN_CXX11_TENSOR_TENSOR_H
13 
14 // IWYU pragma: private
15 #include "./InternalHeaderCheck.h"
16 
17 namespace Eigen {
18 
67 template <typename Scalar_, int NumIndices_, int Options_, typename IndexType_>
68 class Tensor : public TensorBase<Tensor<Scalar_, NumIndices_, Options_, IndexType_> > {
69  public:
72  typedef typename Eigen::internal::nested<Self>::type Nested;
73  typedef typename internal::traits<Self>::StorageKind StorageKind;
74  typedef typename internal::traits<Self>::Index Index;
75  typedef Scalar_ Scalar;
76  typedef typename NumTraits<Scalar>::Real RealScalar;
77  typedef typename Base::CoeffReturnType CoeffReturnType;
78 
79  enum { IsAligned = (EIGEN_MAX_ALIGN_BYTES > 0) && !(Options_ & DontAlign), CoordAccess = true, RawAccess = true };
80 
81  static constexpr int Layout = Options_ & RowMajor ? RowMajor : ColMajor;
82  static constexpr int Options = Options_;
83  static constexpr int NumIndices = NumIndices_;
84  typedef DSizes<Index, NumIndices_> Dimensions;
85 
86  protected:
87  TensorStorage<Scalar, Dimensions, Options> m_storage;
88 
89  template <typename CustomIndices>
90  struct isOfNormalIndex {
91  static const bool is_array = internal::is_base_of<array<Index, NumIndices>, CustomIndices>::value;
92  static const bool is_int = NumTraits<CustomIndices>::IsInteger;
93  static const bool value = is_array | is_int;
94  };
95 
96  public:
97  // Metadata
98  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index rank() const { return NumIndices; }
99  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index dimension(std::size_t n) const { return m_storage.dimensions()[n]; }
100  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Dimensions& dimensions() const { return m_storage.dimensions(); }
101  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index size() const { return m_storage.size(); }
102  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar* data() { return m_storage.data(); }
103  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar* data() const { return m_storage.data(); }
104 
105  // This makes EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED
106  // work, because that uses base().coeffRef() - and we don't yet
107  // implement a similar class hierarchy
108  inline Self& base() { return *this; }
109  inline const Self& base() const { return *this; }
110 
111  template <typename... IndexTypes>
112  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar& coeff(Index firstIndex, Index secondIndex,
113  IndexTypes... otherIndices) const {
114  // The number of indices used to access a tensor coefficient must be equal to the rank of the tensor.
115  EIGEN_STATIC_ASSERT(sizeof...(otherIndices) + 2 == NumIndices, YOU_MADE_A_PROGRAMMING_MISTAKE)
116  return coeff(array<Index, NumIndices>{{firstIndex, secondIndex, otherIndices...}});
117  }
118 
119  // normal indices
120  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar& coeff(const array<Index, NumIndices>& indices) const {
121  eigen_internal_assert(checkIndexRange(indices));
122  return m_storage.data()[linearizedIndex(indices)];
123  }
124 
125  // custom indices
126  template <typename CustomIndices, EIGEN_SFINAE_ENABLE_IF(!(isOfNormalIndex<CustomIndices>::value))>
127  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar& coeff(CustomIndices& indices) const {
128  return coeff(internal::customIndices2Array<Index, NumIndices>(indices));
129  }
130 
131  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar& coeff() const {
132  EIGEN_STATIC_ASSERT(NumIndices == 0, YOU_MADE_A_PROGRAMMING_MISTAKE);
133  return m_storage.data()[0];
134  }
135 
136  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar& coeff(Index index) const {
137  eigen_internal_assert(index >= 0 && index < size());
138  return m_storage.data()[index];
139  }
140 
141  template <typename... IndexTypes>
142  inline Scalar& coeffRef(Index firstIndex, Index secondIndex, IndexTypes... otherIndices) {
143  // The number of indices used to access a tensor coefficient must be equal to the rank of the tensor.
144  EIGEN_STATIC_ASSERT(sizeof...(otherIndices) + 2 == NumIndices, YOU_MADE_A_PROGRAMMING_MISTAKE)
145  return coeffRef(array<Index, NumIndices>{{firstIndex, secondIndex, otherIndices...}});
146  }
147 
148  // normal indices
149  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& coeffRef(const array<Index, NumIndices>& indices) {
150  eigen_internal_assert(checkIndexRange(indices));
151  return m_storage.data()[linearizedIndex(indices)];
152  }
153 
154  // custom indices
155  template <typename CustomIndices, EIGEN_SFINAE_ENABLE_IF(!(isOfNormalIndex<CustomIndices>::value))>
156  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& coeffRef(CustomIndices& indices) {
157  return coeffRef(internal::customIndices2Array<Index, NumIndices>(indices));
158  }
159 
160  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& coeffRef() {
161  EIGEN_STATIC_ASSERT(NumIndices == 0, YOU_MADE_A_PROGRAMMING_MISTAKE);
162  return m_storage.data()[0];
163  }
164 
165  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& coeffRef(Index index) {
166  eigen_internal_assert(index >= 0 && index < size());
167  return m_storage.data()[index];
168  }
169 
170  template <typename... IndexTypes>
171  inline const Scalar& operator()(Index firstIndex, Index secondIndex, IndexTypes... otherIndices) const {
172  // The number of indices used to access a tensor coefficient must be equal to the rank of the tensor.
173  EIGEN_STATIC_ASSERT(sizeof...(otherIndices) + 2 == NumIndices, YOU_MADE_A_PROGRAMMING_MISTAKE)
174  return this->operator()(array<Index, NumIndices>{{firstIndex, secondIndex, otherIndices...}});
175  }
176 
177  // custom indices
178  template <typename CustomIndices, EIGEN_SFINAE_ENABLE_IF(!(isOfNormalIndex<CustomIndices>::value))>
179  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar& operator()(CustomIndices& indices) const {
180  return coeff(internal::customIndices2Array<Index, NumIndices>(indices));
181  }
182 
183  // normal indices
184  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar& operator()(const array<Index, NumIndices>& indices) const {
185  return coeff(indices);
186  }
187 
188  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar& operator()(Index index) const {
189  eigen_internal_assert(index >= 0 && index < size());
190  return coeff(index);
191  }
192 
193  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar& operator()() const {
194  EIGEN_STATIC_ASSERT(NumIndices == 0, YOU_MADE_A_PROGRAMMING_MISTAKE);
195  return coeff();
196  }
197 
198  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar& operator[](Index index) const {
199  // The bracket operator is only for vectors, use the parenthesis operator instead.
200  EIGEN_STATIC_ASSERT(NumIndices == 1, YOU_MADE_A_PROGRAMMING_MISTAKE);
201  return coeff(index);
202  }
203 
204  template <typename... IndexTypes>
205  inline Scalar& operator()(Index firstIndex, Index secondIndex, IndexTypes... otherIndices) {
206  // The number of indices used to access a tensor coefficient must be equal to the rank of the tensor.
207  EIGEN_STATIC_ASSERT(sizeof...(otherIndices) + 2 == NumIndices, YOU_MADE_A_PROGRAMMING_MISTAKE)
208  return operator()(array<Index, NumIndices>{{firstIndex, secondIndex, otherIndices...}});
209  }
210 
211  // normal indices
212  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& operator()(const array<Index, NumIndices>& indices) {
213  return coeffRef(indices);
214  }
215 
216  // custom indices
217  template <typename CustomIndices, EIGEN_SFINAE_ENABLE_IF(!(isOfNormalIndex<CustomIndices>::value))>
218  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& operator()(CustomIndices& indices) {
219  return coeffRef(internal::customIndices2Array<Index, NumIndices>(indices));
220  }
221 
222  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& operator()(Index index) {
223  eigen_assert(index >= 0 && index < size());
224  return coeffRef(index);
225  }
226 
227  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& operator()() {
228  EIGEN_STATIC_ASSERT(NumIndices == 0, YOU_MADE_A_PROGRAMMING_MISTAKE);
229  return coeffRef();
230  }
231 
232  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& operator[](Index index) {
233  // The bracket operator is only for vectors, use the parenthesis operator instead
234  EIGEN_STATIC_ASSERT(NumIndices == 1, YOU_MADE_A_PROGRAMMING_MISTAKE)
235  return coeffRef(index);
236  }
237 
238  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Tensor() : m_storage() {}
239 
240  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Tensor(const Self& other) : Base(other), m_storage(other.m_storage) {}
241 
242  template <typename... IndexTypes>
243  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Tensor(Index firstDimension, IndexTypes... otherDimensions)
244  : m_storage(firstDimension, otherDimensions...) {
245  // The number of dimensions used to construct a tensor must be equal to the rank of the tensor.
246  EIGEN_STATIC_ASSERT(sizeof...(otherDimensions) + 1 == NumIndices, YOU_MADE_A_PROGRAMMING_MISTAKE)
247  }
248 
250  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE explicit Tensor(const array<Index, NumIndices>& dimensions)
251  : m_storage(internal::array_prod(dimensions), dimensions) {
252  EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED
253  }
254 
255  template <typename OtherDerived>
256  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Tensor(const TensorBase<OtherDerived, ReadOnlyAccessors>& other) {
257  EIGEN_STATIC_ASSERT(OtherDerived::NumDimensions == Base::NumDimensions, Number_of_dimensions_must_match)
259  Assign assign(*this, other.derived());
260  resize(TensorEvaluator<const Assign, DefaultDevice>(assign, DefaultDevice()).dimensions());
262  }
263 
264  template <typename OtherDerived>
265  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Tensor(const TensorBase<OtherDerived, WriteAccessors>& other) {
266  EIGEN_STATIC_ASSERT(OtherDerived::NumDimensions == Base::NumDimensions, Number_of_dimensions_must_match)
267  typedef TensorAssignOp<Tensor, const OtherDerived> Assign;
268  Assign assign(*this, other.derived());
269  resize(TensorEvaluator<const Assign, DefaultDevice>(assign, DefaultDevice()).dimensions());
270  internal::TensorExecutor<const Assign, DefaultDevice>::run(assign, DefaultDevice());
271  }
272 
273  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Tensor(Self&& other) : m_storage(std::move(other.m_storage)) {}
274  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Tensor& operator=(Self&& other) {
275  m_storage = std::move(other.m_storage);
276  return *this;
277  }
278 
279  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Tensor& operator=(const Tensor& other) {
280  typedef TensorAssignOp<Tensor, const Tensor> Assign;
281  Assign assign(*this, other);
282  resize(TensorEvaluator<const Assign, DefaultDevice>(assign, DefaultDevice()).dimensions());
283  internal::TensorExecutor<const Assign, DefaultDevice>::run(assign, DefaultDevice());
284  return *this;
285  }
286  template <typename OtherDerived>
287  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Tensor& operator=(const OtherDerived& other) {
288  typedef TensorAssignOp<Tensor, const OtherDerived> Assign;
289  Assign assign(*this, other);
290  resize(TensorEvaluator<const Assign, DefaultDevice>(assign, DefaultDevice()).dimensions());
291  internal::TensorExecutor<const Assign, DefaultDevice>::run(assign, DefaultDevice());
292  return *this;
293  }
294 
295  template <typename... IndexTypes>
296  EIGEN_DEVICE_FUNC void resize(Index firstDimension, IndexTypes... otherDimensions) {
297  // The number of dimensions used to resize a tensor must be equal to the rank of the tensor.
298  EIGEN_STATIC_ASSERT(sizeof...(otherDimensions) + 1 == NumIndices, YOU_MADE_A_PROGRAMMING_MISTAKE)
299  resize(array<Index, NumIndices>{{firstDimension, otherDimensions...}});
300  }
301 
303  EIGEN_DEVICE_FUNC void resize(const array<Index, NumIndices>& dimensions) {
304 #ifndef EIGEN_NO_DEBUG
305  Index size = Index(1);
306  for (int i = 0; i < NumIndices; i++) {
307  internal::check_rows_cols_for_overflow<Dynamic, Dynamic, Dynamic>::run(size, dimensions[i]);
308  size *= dimensions[i];
309  }
310 #else
311  Index size = internal::array_prod(dimensions);
312 #endif
313 
314 #ifdef EIGEN_INITIALIZE_COEFFS
315  bool size_changed = size != this->size();
316  m_storage.resize(size, dimensions);
317  if (size_changed) EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED
318 #else
319  m_storage.resize(size, dimensions);
320 #endif
321  }
322 
323  EIGEN_DEVICE_FUNC void resize() {
324  EIGEN_STATIC_ASSERT(NumIndices == 0, YOU_MADE_A_PROGRAMMING_MISTAKE);
325  // Nothing to do: rank 0 tensors have fixed size
326  }
327 
328  template <typename FirstType, typename... OtherTypes>
329  EIGEN_DEVICE_FUNC void resize(const Eigen::IndexList<FirstType, OtherTypes...>& dimensions) {
330  array<Index, NumIndices> dims;
331  for (int i = 0; i < NumIndices; ++i) {
332  dims[i] = static_cast<Index>(dimensions[i]);
333  }
334  resize(dims);
335  }
336 
338  template <typename CustomDimension, EIGEN_SFINAE_ENABLE_IF(!(isOfNormalIndex<CustomDimension>::value))>
339  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void resize(CustomDimension& dimensions) {
340  resize(internal::customIndices2Array<Index, NumIndices>(dimensions));
341  }
342 
343  template <typename std::ptrdiff_t... Indices>
344  EIGEN_DEVICE_FUNC void resize(const Sizes<Indices...>& dimensions) {
345  array<Index, NumIndices> dims;
346  for (int i = 0; i < NumIndices; ++i) {
347  dims[i] = static_cast<Index>(dimensions[i]);
348  }
349  resize(dims);
350  }
351 
352 #ifdef EIGEN_TENSOR_PLUGIN
353 #include EIGEN_TENSOR_PLUGIN
354 #endif
355 
356  protected:
357  bool checkIndexRange(const array<Index, NumIndices>& indices) const {
358  using internal::array_apply_and_reduce;
359  using internal::array_zip_and_reduce;
360  using internal::greater_equal_zero_op;
361  using internal::lesser_op;
362  using internal::logical_and_op;
363 
364  return
365  // check whether the indices are all >= 0
366  array_apply_and_reduce<logical_and_op, greater_equal_zero_op>(indices) &&
367  // check whether the indices fit in the dimensions
368  array_zip_and_reduce<logical_and_op, lesser_op>(indices, m_storage.dimensions());
369  }
370 
371  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index linearizedIndex(const array<Index, NumIndices>& indices) const {
372  if (Options & RowMajor) {
373  return m_storage.dimensions().IndexOfRowMajor(indices);
374  } else {
375  return m_storage.dimensions().IndexOfColMajor(indices);
376  }
377  }
378 };
379 
380 } // end namespace Eigen
381 
382 #endif // EIGEN_CXX11_TENSOR_TENSOR_H
The tensor executor class.
Definition: TensorExecutor.h:76
void resize(const array< Index, NumIndices > &dimensions)
Definition: Tensor.h:303
Namespace containing all symbols from the Eigen library.
The tensor evaluator class.
Definition: TensorEvaluator.h:30
Definition: AutoDiffScalar.h:629
Definition: TensorAssign.h:55
Tensor(const array< Index, NumIndices > &dimensions)
Definition: Tensor.h:250
EIGEN_DEFAULT_DENSE_INDEX_TYPE Index
The tensor base class.
Definition: TensorForwardDeclarations.h:68
void resize(CustomDimension &dimensions)
Definition: Tensor.h:339
The tensor class.
Definition: Tensor.h:68