1 // This file is part of Eigen, a lightweight C++ template library 2 // for linear algebra. 3 // 4 // Copyright (C) 2014 Benoit Steiner <[email protected]> 5 // 6 // This Source Code Form is subject to the terms of the Mozilla 7 // Public License v. 2.0. If a copy of the MPL was not distributed 8 // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. 9 10 #ifndef EIGEN_CXX11_TENSOR_TENSOR_FIXED_SIZE_H 11 #define EIGEN_CXX11_TENSOR_TENSOR_FIXED_SIZE_H 12 13 namespace Eigen { 14 15 /** \class TensorFixedSize 16 * \ingroup CXX11_Tensor_Module 17 * 18 * \brief The fixed sized version of the tensor class. 19 * 20 * The fixed sized equivalent of 21 * Eigen::Tensor<float, 3> t(3, 5, 7); 22 * is 23 * Eigen::TensorFixedSize<float, Sizes<3,5,7>> t; 24 */ 25 26 template<typename Scalar_, typename Dimensions_, int Options_, typename IndexType> 27 class TensorFixedSize : public TensorBase<TensorFixedSize<Scalar_, Dimensions_, Options_, IndexType> > 28 { 29 public: 30 typedef TensorFixedSize<Scalar_, Dimensions_, Options_, IndexType> Self; 31 typedef TensorBase<TensorFixedSize<Scalar_, Dimensions_, Options_, IndexType> > Base; 32 typedef typename Eigen::internal::nested<Self>::type Nested; 33 typedef typename internal::traits<Self>::StorageKind StorageKind; 34 typedef typename internal::traits<Self>::Index Index; 35 typedef Scalar_ Scalar; 36 typedef typename NumTraits<Scalar>::Real RealScalar; 37 typedef typename Base::CoeffReturnType CoeffReturnType; 38 39 static const int Options = Options_; 40 41 enum { 42 IsAligned = bool(EIGEN_MAX_ALIGN_BYTES>0), 43 PacketAccess = (internal::packet_traits<Scalar>::size > 1), 44 BlockAccess = false, 45 PreferBlockAccess = false, 46 Layout = Options_ & RowMajor ? RowMajor : ColMajor, 47 CoordAccess = true, 48 RawAccess = true 49 }; 50 51 //===- Tensor block evaluation strategy (see TensorBlock.h) -------------===// 52 typedef internal::TensorBlockNotImplemented TensorBlock; 53 //===--------------------------------------------------------------------===// 54 55 typedef Dimensions_ Dimensions; 56 static const std::size_t NumIndices = Dimensions::count; 57 58 protected: 59 TensorStorage<Scalar, Dimensions, Options> m_storage; 60 61 public: rank()62 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index rank() const { return NumIndices; } dimension(std::size_t n)63 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index dimension(std::size_t n) const { return m_storage.dimensions()[n]; } dimensions()64 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Dimensions& dimensions() const { return m_storage.dimensions(); } size()65 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index size() const { return m_storage.size(); } data()66 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar *data() { return m_storage.data(); } data()67 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar *data() const { return m_storage.data(); } 68 69 // This makes EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED 70 // work, because that uses base().coeffRef() - and we don't yet 71 // implement a similar class hierarchy base()72 inline Self& base() { return *this; } base()73 inline const Self& base() const { return *this; } 74 75 #if EIGEN_HAS_VARIADIC_TEMPLATES 76 template<typename... IndexTypes> coeff(Index firstIndex,IndexTypes...otherIndices)77 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar& coeff(Index firstIndex, IndexTypes... otherIndices) const 78 { 79 // The number of indices used to access a tensor coefficient must be equal to the rank of the tensor. 80 EIGEN_STATIC_ASSERT(sizeof...(otherIndices) + 1 == NumIndices, YOU_MADE_A_PROGRAMMING_MISTAKE) 81 return coeff(array<Index, NumIndices>{{firstIndex, otherIndices...}}); 82 } 83 #endif 84 85 EIGEN_DEVICE_FUNC coeff(const array<Index,NumIndices> & indices)86 EIGEN_STRONG_INLINE const Scalar& coeff(const array<Index, NumIndices>& indices) const 87 { 88 eigen_internal_assert(checkIndexRange(indices)); 89 return m_storage.data()[linearizedIndex(indices)]; 90 } 91 92 EIGEN_DEVICE_FUNC coeff(Index index)93 EIGEN_STRONG_INLINE const Scalar& coeff(Index index) const 94 { 95 eigen_internal_assert(index >= 0 && index < size()); 96 return m_storage.data()[index]; 97 } 98 99 EIGEN_DEVICE_FUNC coeff()100 EIGEN_STRONG_INLINE const Scalar& coeff() const 101 { 102 EIGEN_STATIC_ASSERT(NumIndices == 0, YOU_MADE_A_PROGRAMMING_MISTAKE); 103 return m_storage.data()[0]; 104 } 105 106 107 #if EIGEN_HAS_VARIADIC_TEMPLATES 108 template<typename... IndexTypes> coeffRef(Index firstIndex,IndexTypes...otherIndices)109 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& coeffRef(Index firstIndex, IndexTypes... otherIndices) 110 { 111 // The number of indices used to access a tensor coefficient must be equal to the rank of the tensor. 112 EIGEN_STATIC_ASSERT(sizeof...(otherIndices) + 1 == NumIndices, YOU_MADE_A_PROGRAMMING_MISTAKE) 113 return coeffRef(array<Index, NumIndices>{{firstIndex, otherIndices...}}); 114 } 115 #endif 116 117 EIGEN_DEVICE_FUNC coeffRef(const array<Index,NumIndices> & indices)118 EIGEN_STRONG_INLINE Scalar& coeffRef(const array<Index, NumIndices>& indices) 119 { 120 eigen_internal_assert(checkIndexRange(indices)); 121 return m_storage.data()[linearizedIndex(indices)]; 122 } 123 124 EIGEN_DEVICE_FUNC coeffRef(Index index)125 EIGEN_STRONG_INLINE Scalar& coeffRef(Index index) 126 { 127 eigen_internal_assert(index >= 0 && index < size()); 128 return m_storage.data()[index]; 129 } 130 131 EIGEN_DEVICE_FUNC coeffRef()132 EIGEN_STRONG_INLINE Scalar& coeffRef() 133 { 134 EIGEN_STATIC_ASSERT(NumIndices == 0, YOU_MADE_A_PROGRAMMING_MISTAKE); 135 return m_storage.data()[0]; 136 } 137 138 #if EIGEN_HAS_VARIADIC_TEMPLATES 139 template<typename... IndexTypes> operator()140 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar& operator()(Index firstIndex, IndexTypes... otherIndices) const 141 { 142 // The number of indices used to access a tensor coefficient must be equal to the rank of the tensor. 143 EIGEN_STATIC_ASSERT(sizeof...(otherIndices) + 1 == NumIndices, YOU_MADE_A_PROGRAMMING_MISTAKE) 144 return this->operator()(array<Index, NumIndices>{{firstIndex, otherIndices...}}); 145 } 146 #else 147 EIGEN_DEVICE_FUNC operator()148 EIGEN_STRONG_INLINE const Scalar& operator()(Index i0, Index i1) const 149 { 150 if (Options&RowMajor) { 151 const Index index = i1 + i0 * m_storage.dimensions()[1]; 152 return m_storage.data()[index]; 153 } else { 154 const Index index = i0 + i1 * m_storage.dimensions()[0]; 155 return m_storage.data()[index]; 156 } 157 } 158 EIGEN_DEVICE_FUNC operator()159 EIGEN_STRONG_INLINE const Scalar& operator()(Index i0, Index i1, Index i2) const 160 { 161 if (Options&RowMajor) { 162 const Index index = i2 + m_storage.dimensions()[2] * (i1 + m_storage.dimensions()[1] * i0); 163 return m_storage.data()[index]; 164 } else { 165 const Index index = i0 + m_storage.dimensions()[0] * (i1 + m_storage.dimensions()[1] * i2); 166 return m_storage.data()[index]; 167 } 168 } 169 EIGEN_DEVICE_FUNC operator()170 EIGEN_STRONG_INLINE const Scalar& operator()(Index i0, Index i1, Index i2, Index i3) const 171 { 172 if (Options&RowMajor) { 173 const Index index = i3 + m_storage.dimensions()[3] * (i2 + m_storage.dimensions()[2] * (i1 + m_storage.dimensions()[1] * i0)); 174 return m_storage.data()[index]; 175 } else { 176 const Index index = i0 + m_storage.dimensions()[0] * (i1 + m_storage.dimensions()[1] * (i2 + m_storage.dimensions()[2] * i3)); 177 return m_storage.data()[index]; 178 } 179 } 180 EIGEN_DEVICE_FUNC operator()181 EIGEN_STRONG_INLINE const Scalar& operator()(Index i0, Index i1, Index i2, Index i3, Index i4) const 182 { 183 if (Options&RowMajor) { 184 const Index index = i4 + m_storage.dimensions()[4] * (i3 + m_storage.dimensions()[3] * (i2 + m_storage.dimensions()[2] * (i1 + m_storage.dimensions()[1] * i0))); 185 return m_storage.data()[index]; 186 } else { 187 const Index index = i0 + m_storage.dimensions()[0] * (i1 + m_storage.dimensions()[1] * (i2 + m_storage.dimensions()[2] * (i3 + m_storage.dimensions()[3] * i4))); 188 return m_storage.data()[index]; 189 } 190 } 191 #endif 192 193 194 EIGEN_DEVICE_FUNC operator()195 EIGEN_STRONG_INLINE const Scalar& operator()(const array<Index, NumIndices>& indices) const 196 { 197 eigen_assert(checkIndexRange(indices)); 198 return coeff(indices); 199 } 200 201 EIGEN_DEVICE_FUNC operator()202 EIGEN_STRONG_INLINE const Scalar& operator()(Index index) const 203 { 204 eigen_internal_assert(index >= 0 && index < size()); 205 return coeff(index); 206 } 207 208 EIGEN_DEVICE_FUNC operator()209 EIGEN_STRONG_INLINE const Scalar& operator()() const 210 { 211 EIGEN_STATIC_ASSERT(NumIndices == 0, YOU_MADE_A_PROGRAMMING_MISTAKE); 212 return coeff(); 213 } 214 215 EIGEN_DEVICE_FUNC 216 EIGEN_STRONG_INLINE const Scalar& operator[](Index index) const 217 { 218 // The bracket operator is only for vectors, use the parenthesis operator instead. 219 EIGEN_STATIC_ASSERT(NumIndices == 1, YOU_MADE_A_PROGRAMMING_MISTAKE); 220 return coeff(index); 221 } 222 223 #if EIGEN_HAS_VARIADIC_TEMPLATES 224 template<typename... IndexTypes> operator()225 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& operator()(Index firstIndex, IndexTypes... otherIndices) 226 { 227 // The number of indices used to access a tensor coefficient must be equal to the rank of the tensor. 228 EIGEN_STATIC_ASSERT(sizeof...(otherIndices) + 1 == NumIndices, YOU_MADE_A_PROGRAMMING_MISTAKE) 229 return operator()(array<Index, NumIndices>{{firstIndex, otherIndices...}}); 230 } 231 #else 232 EIGEN_DEVICE_FUNC operator()233 EIGEN_STRONG_INLINE Scalar& operator()(Index i0, Index i1) 234 { 235 if (Options&RowMajor) { 236 const Index index = i1 + i0 * m_storage.dimensions()[1]; 237 return m_storage.data()[index]; 238 } else { 239 const Index index = i0 + i1 * m_storage.dimensions()[0]; 240 return m_storage.data()[index]; 241 } 242 } 243 EIGEN_DEVICE_FUNC operator()244 EIGEN_STRONG_INLINE Scalar& operator()(Index i0, Index i1, Index i2) 245 { 246 if (Options&RowMajor) { 247 const Index index = i2 + m_storage.dimensions()[2] * (i1 + m_storage.dimensions()[1] * i0); 248 return m_storage.data()[index]; 249 } else { 250 const Index index = i0 + m_storage.dimensions()[0] * (i1 + m_storage.dimensions()[1] * i2); 251 return m_storage.data()[index]; 252 } 253 } 254 EIGEN_DEVICE_FUNC operator()255 EIGEN_STRONG_INLINE Scalar& operator()(Index i0, Index i1, Index i2, Index i3) 256 { 257 if (Options&RowMajor) { 258 const Index index = i3 + m_storage.dimensions()[3] * (i2 + m_storage.dimensions()[2] * (i1 + m_storage.dimensions()[1] * i0)); 259 return m_storage.data()[index]; 260 } else { 261 const Index index = i0 + m_storage.dimensions()[0] * (i1 + m_storage.dimensions()[1] * (i2 + m_storage.dimensions()[2] * i3)); 262 return m_storage.data()[index]; 263 } 264 } 265 EIGEN_DEVICE_FUNC operator()266 EIGEN_STRONG_INLINE Scalar& operator()(Index i0, Index i1, Index i2, Index i3, Index i4) 267 { 268 if (Options&RowMajor) { 269 const Index index = i4 + m_storage.dimensions()[4] * (i3 + m_storage.dimensions()[3] * (i2 + m_storage.dimensions()[2] * (i1 + m_storage.dimensions()[1] * i0))); 270 return m_storage.data()[index]; 271 } else { 272 const Index index = i0 + m_storage.dimensions()[0] * (i1 + m_storage.dimensions()[1] * (i2 + m_storage.dimensions()[2] * (i3 + m_storage.dimensions()[3] * i4))); 273 return m_storage.data()[index]; 274 } 275 } 276 #endif 277 278 EIGEN_DEVICE_FUNC operator()279 EIGEN_STRONG_INLINE Scalar& operator()(const array<Index, NumIndices>& indices) 280 { 281 eigen_assert(checkIndexRange(indices)); 282 return coeffRef(indices); 283 } 284 285 EIGEN_DEVICE_FUNC operator()286 EIGEN_STRONG_INLINE Scalar& operator()(Index index) 287 { 288 eigen_assert(index >= 0 && index < size()); 289 return coeffRef(index); 290 } 291 292 EIGEN_DEVICE_FUNC operator()293 EIGEN_STRONG_INLINE Scalar& operator()() 294 { 295 EIGEN_STATIC_ASSERT(NumIndices == 0, YOU_MADE_A_PROGRAMMING_MISTAKE); 296 return coeffRef(); 297 } 298 299 EIGEN_DEVICE_FUNC 300 EIGEN_STRONG_INLINE Scalar& operator[](Index index) 301 { 302 // The bracket operator is only for vectors, use the parenthesis operator instead 303 EIGEN_STATIC_ASSERT(NumIndices == 1, YOU_MADE_A_PROGRAMMING_MISTAKE) 304 return coeffRef(index); 305 } 306 307 EIGEN_DEVICE_FUNC TensorFixedSize()308 EIGEN_STRONG_INLINE TensorFixedSize() 309 : m_storage() 310 { 311 } 312 313 EIGEN_DEVICE_FUNC TensorFixedSize(const Self & other)314 EIGEN_STRONG_INLINE TensorFixedSize(const Self& other) 315 : m_storage(other.m_storage) 316 { 317 } 318 319 #if EIGEN_HAS_RVALUE_REFERENCES TensorFixedSize(Self && other)320 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorFixedSize(Self&& other) 321 : m_storage(other.m_storage) 322 { 323 } 324 #endif 325 326 template<typename OtherDerived> 327 EIGEN_DEVICE_FUNC TensorFixedSize(const TensorBase<OtherDerived,ReadOnlyAccessors> & other)328 EIGEN_STRONG_INLINE TensorFixedSize(const TensorBase<OtherDerived, ReadOnlyAccessors>& other) 329 { 330 typedef TensorAssignOp<TensorFixedSize, const OtherDerived> Assign; 331 Assign assign(*this, other.derived()); 332 internal::TensorExecutor<const Assign, DefaultDevice>::run(assign, DefaultDevice()); 333 } 334 template<typename OtherDerived> 335 EIGEN_DEVICE_FUNC TensorFixedSize(const TensorBase<OtherDerived,WriteAccessors> & other)336 EIGEN_STRONG_INLINE TensorFixedSize(const TensorBase<OtherDerived, WriteAccessors>& other) 337 { 338 typedef TensorAssignOp<TensorFixedSize, const OtherDerived> Assign; 339 Assign assign(*this, other.derived()); 340 internal::TensorExecutor<const Assign, DefaultDevice>::run(assign, DefaultDevice()); 341 } 342 343 // FIXME: check that the dimensions of other match the dimensions of *this. 344 // Unfortunately this isn't possible yet when the rhs is an expression. EIGEN_TENSOR_INHERIT_ASSIGNMENT_EQUAL_OPERATOR(TensorFixedSize)345 EIGEN_TENSOR_INHERIT_ASSIGNMENT_EQUAL_OPERATOR(TensorFixedSize) 346 347 348 protected: 349 EIGEN_DEVICE_FUNC 350 EIGEN_STRONG_INLINE bool checkIndexRange(const array<Index, NumIndices>& /*indices*/) const 351 { 352 using internal::array_apply_and_reduce; 353 using internal::array_zip_and_reduce; 354 using internal::greater_equal_zero_op; 355 using internal::logical_and_op; 356 using internal::lesser_op; 357 358 return true; 359 // check whether the indices are all >= 0 360 /* array_apply_and_reduce<logical_and_op, greater_equal_zero_op>(indices) && 361 // check whether the indices fit in the dimensions 362 array_zip_and_reduce<logical_and_op, lesser_op>(indices, m_storage.dimensions());*/ 363 } 364 365 EIGEN_DEVICE_FUNC linearizedIndex(const array<Index,NumIndices> & indices)366 EIGEN_STRONG_INLINE Index linearizedIndex(const array<Index, NumIndices>& indices) const 367 { 368 if (Options&RowMajor) { 369 return m_storage.dimensions().IndexOfRowMajor(indices); 370 } else { 371 return m_storage.dimensions().IndexOfColMajor(indices); 372 } 373 } 374 }; 375 376 377 } // end namespace Eigen 378 379 #endif // EIGEN_CXX11_TENSOR_TENSOR_FIXED_SIZE_H 380