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 // 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_REF_H 11 #define EIGEN_CXX11_TENSOR_TENSOR_REF_H 12 13 namespace Eigen { 14 15 namespace internal { 16 17 template <typename Dimensions, typename Scalar> 18 class TensorLazyBaseEvaluator { 19 public: TensorLazyBaseEvaluator()20 TensorLazyBaseEvaluator() : m_refcount(0) { } ~TensorLazyBaseEvaluator()21 virtual ~TensorLazyBaseEvaluator() { } 22 23 EIGEN_DEVICE_FUNC virtual const Dimensions& dimensions() const = 0; 24 EIGEN_DEVICE_FUNC virtual const Scalar* data() const = 0; 25 26 EIGEN_DEVICE_FUNC virtual const Scalar coeff(DenseIndex index) const = 0; 27 EIGEN_DEVICE_FUNC virtual Scalar& coeffRef(DenseIndex index) = 0; 28 incrRefCount()29 void incrRefCount() { ++m_refcount; } decrRefCount()30 void decrRefCount() { --m_refcount; } refCount()31 int refCount() const { return m_refcount; } 32 33 private: 34 // No copy, no assignment; 35 TensorLazyBaseEvaluator(const TensorLazyBaseEvaluator& other); 36 TensorLazyBaseEvaluator& operator = (const TensorLazyBaseEvaluator& other); 37 38 int m_refcount; 39 }; 40 41 42 template <typename Dimensions, typename Expr, typename Device> 43 class TensorLazyEvaluatorReadOnly : public TensorLazyBaseEvaluator<Dimensions, typename TensorEvaluator<Expr, Device>::Scalar> { 44 public: 45 // typedef typename TensorEvaluator<Expr, Device>::Dimensions Dimensions; 46 typedef typename TensorEvaluator<Expr, Device>::Scalar Scalar; 47 typedef StorageMemory<Scalar, Device> Storage; 48 typedef typename Storage::Type EvaluatorPointerType; 49 typedef TensorEvaluator<Expr, Device> EvalType; 50 TensorLazyEvaluatorReadOnly(const Expr & expr,const Device & device)51 TensorLazyEvaluatorReadOnly(const Expr& expr, const Device& device) : m_impl(expr, device), m_dummy(Scalar(0)) { 52 m_dims = m_impl.dimensions(); 53 m_impl.evalSubExprsIfNeeded(NULL); 54 } ~TensorLazyEvaluatorReadOnly()55 virtual ~TensorLazyEvaluatorReadOnly() { 56 m_impl.cleanup(); 57 } 58 dimensions()59 EIGEN_DEVICE_FUNC virtual const Dimensions& dimensions() const { 60 return m_dims; 61 } data()62 EIGEN_DEVICE_FUNC virtual const Scalar* data() const { 63 return m_impl.data(); 64 } 65 coeff(DenseIndex index)66 EIGEN_DEVICE_FUNC virtual const Scalar coeff(DenseIndex index) const { 67 return m_impl.coeff(index); 68 } coeffRef(DenseIndex)69 EIGEN_DEVICE_FUNC virtual Scalar& coeffRef(DenseIndex /*index*/) { 70 eigen_assert(false && "can't reference the coefficient of a rvalue"); 71 return m_dummy; 72 }; 73 74 protected: 75 TensorEvaluator<Expr, Device> m_impl; 76 Dimensions m_dims; 77 Scalar m_dummy; 78 }; 79 80 template <typename Dimensions, typename Expr, typename Device> 81 class TensorLazyEvaluatorWritable : public TensorLazyEvaluatorReadOnly<Dimensions, Expr, Device> { 82 public: 83 typedef TensorLazyEvaluatorReadOnly<Dimensions, Expr, Device> Base; 84 typedef typename Base::Scalar Scalar; 85 typedef StorageMemory<Scalar, Device> Storage; 86 typedef typename Storage::Type EvaluatorPointerType; 87 TensorLazyEvaluatorWritable(const Expr & expr,const Device & device)88 TensorLazyEvaluatorWritable(const Expr& expr, const Device& device) : Base(expr, device) { 89 } ~TensorLazyEvaluatorWritable()90 virtual ~TensorLazyEvaluatorWritable() { 91 } 92 coeffRef(DenseIndex index)93 EIGEN_DEVICE_FUNC virtual Scalar& coeffRef(DenseIndex index) { 94 return this->m_impl.coeffRef(index); 95 } 96 }; 97 98 template <typename Dimensions, typename Expr, typename Device> 99 class TensorLazyEvaluator : public internal::conditional<bool(internal::is_lvalue<Expr>::value), 100 TensorLazyEvaluatorWritable<Dimensions, Expr, Device>, 101 TensorLazyEvaluatorReadOnly<Dimensions, const Expr, Device> >::type { 102 public: 103 typedef typename internal::conditional<bool(internal::is_lvalue<Expr>::value), 104 TensorLazyEvaluatorWritable<Dimensions, Expr, Device>, 105 TensorLazyEvaluatorReadOnly<Dimensions, const Expr, Device> >::type Base; 106 typedef typename Base::Scalar Scalar; 107 TensorLazyEvaluator(const Expr & expr,const Device & device)108 TensorLazyEvaluator(const Expr& expr, const Device& device) : Base(expr, device) { 109 } ~TensorLazyEvaluator()110 virtual ~TensorLazyEvaluator() { 111 } 112 }; 113 114 } // namespace internal 115 116 117 /** \class TensorRef 118 * \ingroup CXX11_Tensor_Module 119 * 120 * \brief A reference to a tensor expression 121 * The expression will be evaluated lazily (as much as possible). 122 * 123 */ 124 template<typename PlainObjectType> class TensorRef : public TensorBase<TensorRef<PlainObjectType> > 125 { 126 public: 127 typedef TensorRef<PlainObjectType> Self; 128 typedef typename PlainObjectType::Base Base; 129 typedef typename Eigen::internal::nested<Self>::type Nested; 130 typedef typename internal::traits<PlainObjectType>::StorageKind StorageKind; 131 typedef typename internal::traits<PlainObjectType>::Index Index; 132 typedef typename internal::traits<PlainObjectType>::Scalar Scalar; 133 typedef typename NumTraits<Scalar>::Real RealScalar; 134 typedef typename Base::CoeffReturnType CoeffReturnType; 135 typedef Scalar* PointerType; 136 typedef PointerType PointerArgType; 137 138 static const Index NumIndices = PlainObjectType::NumIndices; 139 typedef typename PlainObjectType::Dimensions Dimensions; 140 141 enum { 142 IsAligned = false, 143 PacketAccess = false, 144 BlockAccess = false, 145 PreferBlockAccess = false, 146 Layout = PlainObjectType::Layout, 147 CoordAccess = false, // to be implemented 148 RawAccess = false 149 }; 150 151 //===- Tensor block evaluation strategy (see TensorBlock.h) -----------===// 152 typedef internal::TensorBlockNotImplemented TensorBlock; 153 //===------------------------------------------------------------------===// 154 TensorRef()155 EIGEN_STRONG_INLINE TensorRef() : m_evaluator(NULL) { 156 } 157 158 template <typename Expression> TensorRef(const Expression & expr)159 EIGEN_STRONG_INLINE TensorRef(const Expression& expr) : m_evaluator(new internal::TensorLazyEvaluator<Dimensions, Expression, DefaultDevice>(expr, DefaultDevice())) { 160 m_evaluator->incrRefCount(); 161 } 162 163 template <typename Expression> 164 EIGEN_STRONG_INLINE TensorRef& operator = (const Expression& expr) { 165 unrefEvaluator(); 166 m_evaluator = new internal::TensorLazyEvaluator<Dimensions, Expression, DefaultDevice>(expr, DefaultDevice()); 167 m_evaluator->incrRefCount(); 168 return *this; 169 } 170 ~TensorRef()171 ~TensorRef() { 172 unrefEvaluator(); 173 } 174 TensorRef(const TensorRef & other)175 TensorRef(const TensorRef& other) : m_evaluator(other.m_evaluator) { 176 eigen_assert(m_evaluator->refCount() > 0); 177 m_evaluator->incrRefCount(); 178 } 179 180 TensorRef& operator = (const TensorRef& other) { 181 if (this != &other) { 182 unrefEvaluator(); 183 m_evaluator = other.m_evaluator; 184 eigen_assert(m_evaluator->refCount() > 0); 185 m_evaluator->incrRefCount(); 186 } 187 return *this; 188 } 189 190 EIGEN_DEVICE_FUNC rank()191 EIGEN_STRONG_INLINE Index rank() const { return m_evaluator->dimensions().size(); } 192 EIGEN_DEVICE_FUNC dimension(Index n)193 EIGEN_STRONG_INLINE Index dimension(Index n) const { return m_evaluator->dimensions()[n]; } 194 EIGEN_DEVICE_FUNC dimensions()195 EIGEN_STRONG_INLINE const Dimensions& dimensions() const { return m_evaluator->dimensions(); } 196 EIGEN_DEVICE_FUNC size()197 EIGEN_STRONG_INLINE Index size() const { return m_evaluator->dimensions().TotalSize(); } 198 EIGEN_DEVICE_FUNC data()199 EIGEN_STRONG_INLINE const Scalar* data() const { return m_evaluator->data(); } 200 201 EIGEN_DEVICE_FUNC operator()202 EIGEN_STRONG_INLINE const Scalar operator()(Index index) const 203 { 204 return m_evaluator->coeff(index); 205 } 206 207 #if EIGEN_HAS_VARIADIC_TEMPLATES 208 template<typename... IndexTypes> EIGEN_DEVICE_FUNC operator()209 EIGEN_STRONG_INLINE const Scalar operator()(Index firstIndex, IndexTypes... otherIndices) const 210 { 211 const std::size_t num_indices = (sizeof...(otherIndices) + 1); 212 const array<Index, num_indices> indices{{firstIndex, otherIndices...}}; 213 return coeff(indices); 214 } 215 template<typename... IndexTypes> EIGEN_DEVICE_FUNC coeffRef(Index firstIndex,IndexTypes...otherIndices)216 EIGEN_STRONG_INLINE Scalar& coeffRef(Index firstIndex, IndexTypes... otherIndices) 217 { 218 const std::size_t num_indices = (sizeof...(otherIndices) + 1); 219 const array<Index, num_indices> indices{{firstIndex, otherIndices...}}; 220 return coeffRef(indices); 221 } 222 #else 223 224 EIGEN_DEVICE_FUNC operator()225 EIGEN_STRONG_INLINE const Scalar operator()(Index i0, Index i1) const 226 { 227 array<Index, 2> indices; 228 indices[0] = i0; 229 indices[1] = i1; 230 return coeff(indices); 231 } 232 EIGEN_DEVICE_FUNC operator()233 EIGEN_STRONG_INLINE const Scalar operator()(Index i0, Index i1, Index i2) const 234 { 235 array<Index, 3> indices; 236 indices[0] = i0; 237 indices[1] = i1; 238 indices[2] = i2; 239 return coeff(indices); 240 } 241 EIGEN_DEVICE_FUNC operator()242 EIGEN_STRONG_INLINE const Scalar operator()(Index i0, Index i1, Index i2, Index i3) const 243 { 244 array<Index, 4> indices; 245 indices[0] = i0; 246 indices[1] = i1; 247 indices[2] = i2; 248 indices[3] = i3; 249 return coeff(indices); 250 } 251 EIGEN_DEVICE_FUNC operator()252 EIGEN_STRONG_INLINE const Scalar operator()(Index i0, Index i1, Index i2, Index i3, Index i4) const 253 { 254 array<Index, 5> indices; 255 indices[0] = i0; 256 indices[1] = i1; 257 indices[2] = i2; 258 indices[3] = i3; 259 indices[4] = i4; 260 return coeff(indices); 261 } 262 EIGEN_DEVICE_FUNC coeffRef(Index i0,Index i1)263 EIGEN_STRONG_INLINE Scalar& coeffRef(Index i0, Index i1) 264 { 265 array<Index, 2> indices; 266 indices[0] = i0; 267 indices[1] = i1; 268 return coeffRef(indices); 269 } 270 EIGEN_DEVICE_FUNC coeffRef(Index i0,Index i1,Index i2)271 EIGEN_STRONG_INLINE Scalar& coeffRef(Index i0, Index i1, Index i2) 272 { 273 array<Index, 3> indices; 274 indices[0] = i0; 275 indices[1] = i1; 276 indices[2] = i2; 277 return coeffRef(indices); 278 } 279 EIGEN_DEVICE_FUNC operator()280 EIGEN_STRONG_INLINE Scalar& operator()(Index i0, Index i1, Index i2, Index i3) 281 { 282 array<Index, 4> indices; 283 indices[0] = i0; 284 indices[1] = i1; 285 indices[2] = i2; 286 indices[3] = i3; 287 return coeffRef(indices); 288 } 289 EIGEN_DEVICE_FUNC coeffRef(Index i0,Index i1,Index i2,Index i3,Index i4)290 EIGEN_STRONG_INLINE Scalar& coeffRef(Index i0, Index i1, Index i2, Index i3, Index i4) 291 { 292 array<Index, 5> indices; 293 indices[0] = i0; 294 indices[1] = i1; 295 indices[2] = i2; 296 indices[3] = i3; 297 indices[4] = i4; 298 return coeffRef(indices); 299 } 300 #endif 301 302 template <std::size_t NumIndices> EIGEN_DEVICE_FUNC coeff(const array<Index,NumIndices> & indices)303 EIGEN_STRONG_INLINE const Scalar coeff(const array<Index, NumIndices>& indices) const 304 { 305 const Dimensions& dims = this->dimensions(); 306 Index index = 0; 307 if (PlainObjectType::Options & RowMajor) { 308 index += indices[0]; 309 for (size_t i = 1; i < NumIndices; ++i) { 310 index = index * dims[i] + indices[i]; 311 } 312 } else { 313 index += indices[NumIndices-1]; 314 for (int i = NumIndices-2; i >= 0; --i) { 315 index = index * dims[i] + indices[i]; 316 } 317 } 318 return m_evaluator->coeff(index); 319 } 320 template <std::size_t NumIndices> EIGEN_DEVICE_FUNC coeffRef(const array<Index,NumIndices> & indices)321 EIGEN_STRONG_INLINE Scalar& coeffRef(const array<Index, NumIndices>& indices) 322 { 323 const Dimensions& dims = this->dimensions(); 324 Index index = 0; 325 if (PlainObjectType::Options & RowMajor) { 326 index += indices[0]; 327 for (size_t i = 1; i < NumIndices; ++i) { 328 index = index * dims[i] + indices[i]; 329 } 330 } else { 331 index += indices[NumIndices-1]; 332 for (int i = NumIndices-2; i >= 0; --i) { 333 index = index * dims[i] + indices[i]; 334 } 335 } 336 return m_evaluator->coeffRef(index); 337 } 338 339 EIGEN_DEVICE_FUNC coeff(Index index)340 EIGEN_STRONG_INLINE const Scalar coeff(Index index) const 341 { 342 return m_evaluator->coeff(index); 343 } 344 345 EIGEN_DEVICE_FUNC coeffRef(Index index)346 EIGEN_STRONG_INLINE Scalar& coeffRef(Index index) 347 { 348 return m_evaluator->coeffRef(index); 349 } 350 351 private: unrefEvaluator()352 EIGEN_STRONG_INLINE void unrefEvaluator() { 353 if (m_evaluator) { 354 m_evaluator->decrRefCount(); 355 if (m_evaluator->refCount() == 0) { 356 delete m_evaluator; 357 } 358 } 359 } 360 361 internal::TensorLazyBaseEvaluator<Dimensions, Scalar>* m_evaluator; 362 }; 363 364 365 // evaluator for rvalues 366 template<typename Derived, typename Device> 367 struct TensorEvaluator<const TensorRef<Derived>, Device> 368 { 369 typedef typename Derived::Index Index; 370 typedef typename Derived::Scalar Scalar; 371 typedef typename Derived::Scalar CoeffReturnType; 372 typedef typename PacketType<CoeffReturnType, Device>::type PacketReturnType; 373 typedef typename Derived::Dimensions Dimensions; 374 typedef StorageMemory<CoeffReturnType, Device> Storage; 375 typedef typename Storage::Type EvaluatorPointerType; 376 377 enum { 378 IsAligned = false, 379 PacketAccess = false, 380 BlockAccess = false, 381 PreferBlockAccess = false, 382 Layout = TensorRef<Derived>::Layout, 383 CoordAccess = false, // to be implemented 384 RawAccess = false 385 }; 386 387 //===- Tensor block evaluation strategy (see TensorBlock.h) -------------===// 388 typedef internal::TensorBlockNotImplemented TensorBlock; 389 //===--------------------------------------------------------------------===// 390 391 EIGEN_STRONG_INLINE TensorEvaluator(const TensorRef<Derived>& m, const Device&) 392 : m_ref(m) 393 { } 394 395 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Dimensions& dimensions() const { return m_ref.dimensions(); } 396 397 EIGEN_STRONG_INLINE bool evalSubExprsIfNeeded(EvaluatorPointerType) { 398 return true; 399 } 400 401 EIGEN_STRONG_INLINE void cleanup() { } 402 403 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(Index index) const { 404 return m_ref.coeff(index); 405 } 406 407 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& coeffRef(Index index) { 408 return m_ref.coeffRef(index); 409 } 410 411 EIGEN_DEVICE_FUNC const Scalar* data() const { return m_ref.data(); } 412 413 protected: 414 TensorRef<Derived> m_ref; 415 }; 416 417 418 // evaluator for lvalues 419 template<typename Derived, typename Device> 420 struct TensorEvaluator<TensorRef<Derived>, Device> : public TensorEvaluator<const TensorRef<Derived>, Device> 421 { 422 typedef typename Derived::Index Index; 423 typedef typename Derived::Scalar Scalar; 424 typedef typename Derived::Scalar CoeffReturnType; 425 typedef typename PacketType<CoeffReturnType, Device>::type PacketReturnType; 426 typedef typename Derived::Dimensions Dimensions; 427 428 typedef TensorEvaluator<const TensorRef<Derived>, Device> Base; 429 430 enum { 431 IsAligned = false, 432 PacketAccess = false, 433 BlockAccess = false, 434 PreferBlockAccess = false, 435 RawAccess = false 436 }; 437 438 //===- Tensor block evaluation strategy (see TensorBlock.h) -------------===// 439 typedef internal::TensorBlockNotImplemented TensorBlock; 440 //===--------------------------------------------------------------------===// 441 442 EIGEN_STRONG_INLINE TensorEvaluator(TensorRef<Derived>& m, const Device& d) : Base(m, d) 443 { } 444 445 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& coeffRef(Index index) { 446 return this->m_ref.coeffRef(index); 447 } 448 }; 449 450 451 452 } // end namespace Eigen 453 454 #endif // EIGEN_CXX11_TENSOR_TENSOR_REF_H 455