TensorEvaluator.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 //
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_EVALUATOR_H
11 #define EIGEN_CXX11_TENSOR_TENSOR_EVALUATOR_H
12 
13 namespace Eigen {
14 
26 // Generic evaluator
27 template<typename Derived, typename Device>
29 {
30  typedef typename Derived::Index Index;
31  typedef typename Derived::Scalar Scalar;
32  typedef typename Derived::Scalar CoeffReturnType;
33  typedef typename PacketType<CoeffReturnType, Device>::type PacketReturnType;
34  typedef typename Derived::Dimensions Dimensions;
35 
36  // NumDimensions is -1 for variable dim tensors
37  static const int NumCoords = internal::traits<Derived>::NumDimensions > 0 ?
38  internal::traits<Derived>::NumDimensions : 0;
39 
40  enum {
41  IsAligned = Derived::IsAligned,
42  PacketAccess = (internal::unpacket_traits<PacketReturnType>::size > 1),
43  Layout = Derived::Layout,
44  CoordAccess = NumCoords > 0,
45  RawAccess = true
46  };
47 
48  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorEvaluator(const Derived& m, const Device& device)
49  : m_data(const_cast<Scalar*>(m.data())), m_dims(m.dimensions()), m_device(device)
50  { }
51 
52  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Dimensions& dimensions() const { return m_dims; }
53 
54  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool evalSubExprsIfNeeded(CoeffReturnType* dest) {
55  if (dest) {
56  m_device.memcpy((void*)dest, m_data, sizeof(Scalar) * m_dims.TotalSize());
57  return false;
58  }
59  return true;
60  }
61 
62  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void cleanup() { }
63 
64  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(Index index) const {
65  eigen_assert(m_data);
66  return m_data[index];
67  }
68 
69  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& coeffRef(Index index) {
70  eigen_assert(m_data);
71  return m_data[index];
72  }
73 
74  template<int LoadMode> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
75  PacketReturnType packet(Index index) const
76  {
77  return internal::ploadt<PacketReturnType, LoadMode>(m_data + index);
78  }
79 
80  template <int StoreMode> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
81  void writePacket(Index index, const PacketReturnType& x)
82  {
83  return internal::pstoret<Scalar, PacketReturnType, StoreMode>(m_data + index, x);
84  }
85 
86  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(const array<DenseIndex, NumCoords>& coords) const {
87  eigen_assert(m_data);
88  if (static_cast<int>(Layout) == static_cast<int>(ColMajor)) {
89  return m_data[m_dims.IndexOfColMajor(coords)];
90  } else {
91  return m_data[m_dims.IndexOfRowMajor(coords)];
92  }
93  }
94 
95  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& coeffRef(const array<DenseIndex, NumCoords>& coords) {
96  eigen_assert(m_data);
97  if (static_cast<int>(Layout) == static_cast<int>(ColMajor)) {
98  return m_data[m_dims.IndexOfColMajor(coords)];
99  } else {
100  return m_data[m_dims.IndexOfRowMajor(coords)];
101  }
102  }
103 
104  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorOpCost costPerCoeff(bool vectorized) const {
105  return TensorOpCost(sizeof(CoeffReturnType), 0, 0, vectorized,
106  internal::unpacket_traits<PacketReturnType>::size);
107  }
108 
109  EIGEN_DEVICE_FUNC Scalar* data() const { return m_data; }
110 
111  protected:
112  Scalar* m_data;
113  Dimensions m_dims;
114  const Device& m_device;
115 };
116 
117 namespace {
118 template <typename T> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE
119 T loadConstant(const T* address) {
120  return *address;
121 }
122 // Use the texture cache on CUDA devices whenever possible
123 #if defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 350
124 template <> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE
125 float loadConstant(const float* address) {
126  return __ldg(address);
127 }
128 template <> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE
129 double loadConstant(const double* address) {
130  return __ldg(address);
131 }
132 template <> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE
133 Eigen::half loadConstant(const Eigen::half* address) {
134  return Eigen::half(internal::raw_uint16_to_half(__ldg(&address->x)));
135 }
136 #endif
137 }
138 
139 
140 // Default evaluator for rvalues
141 template<typename Derived, typename Device>
142 struct TensorEvaluator<const Derived, Device>
143 {
144  typedef typename Derived::Index Index;
145  typedef typename Derived::Scalar Scalar;
146  typedef typename Derived::Scalar CoeffReturnType;
147  typedef typename PacketType<CoeffReturnType, Device>::type PacketReturnType;
148  typedef typename Derived::Dimensions Dimensions;
149 
150  // NumDimensions is -1 for variable dim tensors
151  static const int NumCoords = internal::traits<Derived>::NumDimensions > 0 ?
152  internal::traits<Derived>::NumDimensions : 0;
153 
154  enum {
155  IsAligned = Derived::IsAligned,
156  PacketAccess = (internal::unpacket_traits<PacketReturnType>::size > 1),
157  Layout = Derived::Layout,
158  CoordAccess = NumCoords > 0,
159  RawAccess = true
160  };
161 
162  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorEvaluator(const Derived& m, const Device& device)
163  : m_data(m.data()), m_dims(m.dimensions()), m_device(device)
164  { }
165 
166  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Dimensions& dimensions() const { return m_dims; }
167 
168  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool evalSubExprsIfNeeded(CoeffReturnType* data) {
169  if (!NumTraits<typename internal::remove_const<Scalar>::type>::RequireInitialization && data) {
170  m_device.memcpy((void*)data, m_data, m_dims.TotalSize() * sizeof(Scalar));
171  return false;
172  }
173  return true;
174  }
175 
176  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void cleanup() { }
177 
178  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(Index index) const {
179  eigen_assert(m_data);
180  return loadConstant(m_data+index);
181  }
182 
183  template<int LoadMode> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
184  PacketReturnType packet(Index index) const
185  {
186  return internal::ploadt_ro<PacketReturnType, LoadMode>(m_data + index);
187  }
188 
189  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(const array<DenseIndex, NumCoords>& coords) const {
190  eigen_assert(m_data);
191  const Index index = (static_cast<int>(Layout) == static_cast<int>(ColMajor)) ? m_dims.IndexOfColMajor(coords)
192  : m_dims.IndexOfRowMajor(coords);
193  return loadConstant(m_data+index);
194  }
195 
196  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorOpCost costPerCoeff(bool vectorized) const {
197  return TensorOpCost(sizeof(CoeffReturnType), 0, 0, vectorized,
198  internal::unpacket_traits<PacketReturnType>::size);
199  }
200 
201  EIGEN_DEVICE_FUNC const Scalar* data() const { return m_data; }
202 
203  protected:
204  const Scalar* m_data;
205  Dimensions m_dims;
206  const Device& m_device;
207 };
208 
209 
210 
211 
212 // -------------------- CwiseNullaryOp --------------------
213 
214 template<typename NullaryOp, typename ArgType, typename Device>
215 struct TensorEvaluator<const TensorCwiseNullaryOp<NullaryOp, ArgType>, Device>
216 {
217  typedef TensorCwiseNullaryOp<NullaryOp, ArgType> XprType;
218 
219  enum {
220  IsAligned = true,
221  PacketAccess = internal::functor_traits<NullaryOp>::PacketAccess,
223  CoordAccess = false, // to be implemented
224  RawAccess = false
225  };
226 
227  EIGEN_DEVICE_FUNC
228  TensorEvaluator(const XprType& op, const Device& device)
229  : m_functor(op.functor()), m_argImpl(op.nestedExpression(), device)
230  { }
231 
232  typedef typename XprType::Index Index;
233  typedef typename XprType::Scalar Scalar;
234  typedef typename internal::traits<XprType>::Scalar CoeffReturnType;
235  typedef typename PacketType<CoeffReturnType, Device>::type PacketReturnType;
236  static const int PacketSize = internal::unpacket_traits<PacketReturnType>::size;
237  typedef typename TensorEvaluator<ArgType, Device>::Dimensions Dimensions;
238 
239  EIGEN_DEVICE_FUNC const Dimensions& dimensions() const { return m_argImpl.dimensions(); }
240 
241  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool evalSubExprsIfNeeded(CoeffReturnType*) { return true; }
242  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void cleanup() { }
243 
244  EIGEN_DEVICE_FUNC CoeffReturnType coeff(Index index) const
245  {
246  return m_functor(index);
247  }
248 
249  template<int LoadMode>
250  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketReturnType packet(Index index) const
251  {
252  return m_functor.template packetOp<Index, PacketReturnType>(index);
253  }
254 
255  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorOpCost
256  costPerCoeff(bool vectorized) const {
257  return TensorOpCost(sizeof(CoeffReturnType), 0, 0, vectorized,
258  internal::unpacket_traits<PacketReturnType>::size);
259  }
260 
261  EIGEN_DEVICE_FUNC CoeffReturnType* data() const { return NULL; }
262 
263  private:
264  const NullaryOp m_functor;
266 };
267 
268 
269 
270 // -------------------- CwiseUnaryOp --------------------
271 
272 template<typename UnaryOp, typename ArgType, typename Device>
273 struct TensorEvaluator<const TensorCwiseUnaryOp<UnaryOp, ArgType>, Device>
274 {
275  typedef TensorCwiseUnaryOp<UnaryOp, ArgType> XprType;
276 
277  enum {
279  PacketAccess = TensorEvaluator<ArgType, Device>::PacketAccess & internal::functor_traits<UnaryOp>::PacketAccess,
281  CoordAccess = false, // to be implemented
282  RawAccess = false
283  };
284 
285  EIGEN_DEVICE_FUNC TensorEvaluator(const XprType& op, const Device& device)
286  : m_functor(op.functor()),
287  m_argImpl(op.nestedExpression(), device)
288  { }
289 
290  typedef typename XprType::Index Index;
291  typedef typename XprType::Scalar Scalar;
292  typedef typename internal::traits<XprType>::Scalar CoeffReturnType;
293  typedef typename PacketType<CoeffReturnType, Device>::type PacketReturnType;
294  static const int PacketSize = internal::unpacket_traits<PacketReturnType>::size;
295  typedef typename TensorEvaluator<ArgType, Device>::Dimensions Dimensions;
296 
297  EIGEN_DEVICE_FUNC const Dimensions& dimensions() const { return m_argImpl.dimensions(); }
298 
299  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool evalSubExprsIfNeeded(Scalar*) {
300  m_argImpl.evalSubExprsIfNeeded(NULL);
301  return true;
302  }
303  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void cleanup() {
304  m_argImpl.cleanup();
305  }
306 
307  EIGEN_DEVICE_FUNC CoeffReturnType coeff(Index index) const
308  {
309  return m_functor(m_argImpl.coeff(index));
310  }
311 
312  template<int LoadMode>
313  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketReturnType packet(Index index) const
314  {
315  return m_functor.packetOp(m_argImpl.template packet<LoadMode>(index));
316  }
317 
318  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorOpCost costPerCoeff(bool vectorized) const {
319  const double functor_cost = internal::functor_traits<UnaryOp>::Cost;
320  return m_argImpl.costPerCoeff(vectorized) +
321  TensorOpCost(0, 0, functor_cost, vectorized, PacketSize);
322  }
323 
324  EIGEN_DEVICE_FUNC CoeffReturnType* data() const { return NULL; }
325 
326  private:
327  const UnaryOp m_functor;
329 };
330 
331 
332 // -------------------- CwiseBinaryOp --------------------
333 
334 template<typename BinaryOp, typename LeftArgType, typename RightArgType, typename Device>
335 struct TensorEvaluator<const TensorCwiseBinaryOp<BinaryOp, LeftArgType, RightArgType>, Device>
336 {
337  typedef TensorCwiseBinaryOp<BinaryOp, LeftArgType, RightArgType> XprType;
338 
339  enum {
342  internal::functor_traits<BinaryOp>::PacketAccess,
344  CoordAccess = false, // to be implemented
345  RawAccess = false
346  };
347 
348  EIGEN_DEVICE_FUNC TensorEvaluator(const XprType& op, const Device& device)
349  : m_functor(op.functor()),
350  m_leftImpl(op.lhsExpression(), device),
351  m_rightImpl(op.rhsExpression(), device)
352  {
353  EIGEN_STATIC_ASSERT((static_cast<int>(TensorEvaluator<LeftArgType, Device>::Layout) == static_cast<int>(TensorEvaluator<RightArgType, Device>::Layout) || internal::traits<XprType>::NumDimensions <= 1), YOU_MADE_A_PROGRAMMING_MISTAKE);
354  eigen_assert(dimensions_match(m_leftImpl.dimensions(), m_rightImpl.dimensions()));
355  }
356 
357  typedef typename XprType::Index Index;
358  typedef typename XprType::Scalar Scalar;
359  typedef typename internal::traits<XprType>::Scalar CoeffReturnType;
360  typedef typename PacketType<CoeffReturnType, Device>::type PacketReturnType;
361  static const int PacketSize = internal::unpacket_traits<PacketReturnType>::size;
362  typedef typename TensorEvaluator<LeftArgType, Device>::Dimensions Dimensions;
363 
364  EIGEN_DEVICE_FUNC const Dimensions& dimensions() const
365  {
366  // TODO: use right impl instead if right impl dimensions are known at compile time.
367  return m_leftImpl.dimensions();
368  }
369 
370  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool evalSubExprsIfNeeded(CoeffReturnType*) {
371  m_leftImpl.evalSubExprsIfNeeded(NULL);
372  m_rightImpl.evalSubExprsIfNeeded(NULL);
373  return true;
374  }
375  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void cleanup() {
376  m_leftImpl.cleanup();
377  m_rightImpl.cleanup();
378  }
379 
380  EIGEN_DEVICE_FUNC CoeffReturnType coeff(Index index) const
381  {
382  return m_functor(m_leftImpl.coeff(index), m_rightImpl.coeff(index));
383  }
384  template<int LoadMode>
385  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketReturnType packet(Index index) const
386  {
387  return m_functor.packetOp(m_leftImpl.template packet<LoadMode>(index), m_rightImpl.template packet<LoadMode>(index));
388  }
389 
390  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorOpCost
391  costPerCoeff(bool vectorized) const {
392  const double functor_cost = internal::functor_traits<BinaryOp>::Cost;
393  return m_leftImpl.costPerCoeff(vectorized) +
394  m_rightImpl.costPerCoeff(vectorized) +
395  TensorOpCost(0, 0, functor_cost, vectorized, PacketSize);
396  }
397 
398  EIGEN_DEVICE_FUNC CoeffReturnType* data() const { return NULL; }
399 
400  private:
401  const BinaryOp m_functor;
404 };
405 
406 // -------------------- CwiseTernaryOp --------------------
407 
408 template<typename TernaryOp, typename Arg1Type, typename Arg2Type, typename Arg3Type, typename Device>
409 struct TensorEvaluator<const TensorCwiseTernaryOp<TernaryOp, Arg1Type, Arg2Type, Arg3Type>, Device>
410 {
411  typedef TensorCwiseTernaryOp<TernaryOp, Arg1Type, Arg2Type, Arg3Type> XprType;
412 
413  enum {
416  internal::functor_traits<TernaryOp>::PacketAccess,
418  CoordAccess = false, // to be implemented
419  RawAccess = false
420  };
421 
422  EIGEN_DEVICE_FUNC TensorEvaluator(const XprType& op, const Device& device)
423  : m_functor(op.functor()),
424  m_arg1Impl(op.arg1Expression(), device),
425  m_arg2Impl(op.arg2Expression(), device),
426  m_arg3Impl(op.arg3Expression(), device)
427  {
428  EIGEN_STATIC_ASSERT((static_cast<int>(TensorEvaluator<Arg1Type, Device>::Layout) == static_cast<int>(TensorEvaluator<Arg3Type, Device>::Layout) || internal::traits<XprType>::NumDimensions <= 1), YOU_MADE_A_PROGRAMMING_MISTAKE);
429 
430  EIGEN_STATIC_ASSERT((internal::is_same<typename internal::traits<Arg1Type>::StorageKind,
431  typename internal::traits<Arg2Type>::StorageKind>::value),
432  STORAGE_KIND_MUST_MATCH)
433  EIGEN_STATIC_ASSERT((internal::is_same<typename internal::traits<Arg1Type>::StorageKind,
434  typename internal::traits<Arg3Type>::StorageKind>::value),
435  STORAGE_KIND_MUST_MATCH)
436  EIGEN_STATIC_ASSERT((internal::is_same<typename internal::traits<Arg1Type>::Index,
437  typename internal::traits<Arg2Type>::Index>::value),
438  STORAGE_INDEX_MUST_MATCH)
439  EIGEN_STATIC_ASSERT((internal::is_same<typename internal::traits<Arg1Type>::Index,
440  typename internal::traits<Arg3Type>::Index>::value),
441  STORAGE_INDEX_MUST_MATCH)
442 
443  eigen_assert(dimensions_match(m_arg1Impl.dimensions(), m_arg2Impl.dimensions()) && dimensions_match(m_arg1Impl.dimensions(), m_arg3Impl.dimensions()));
444  }
445 
446  typedef typename XprType::Index Index;
447  typedef typename XprType::Scalar Scalar;
448  typedef typename internal::traits<XprType>::Scalar CoeffReturnType;
449  typedef typename PacketType<CoeffReturnType, Device>::type PacketReturnType;
450  static const int PacketSize = internal::unpacket_traits<PacketReturnType>::size;
451  typedef typename TensorEvaluator<Arg1Type, Device>::Dimensions Dimensions;
452 
453  EIGEN_DEVICE_FUNC const Dimensions& dimensions() const
454  {
455  // TODO: use arg2 or arg3 dimensions if they are known at compile time.
456  return m_arg1Impl.dimensions();
457  }
458 
459  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool evalSubExprsIfNeeded(CoeffReturnType*) {
460  m_arg1Impl.evalSubExprsIfNeeded(NULL);
461  m_arg2Impl.evalSubExprsIfNeeded(NULL);
462  m_arg3Impl.evalSubExprsIfNeeded(NULL);
463  return true;
464  }
465  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void cleanup() {
466  m_arg1Impl.cleanup();
467  m_arg2Impl.cleanup();
468  m_arg3Impl.cleanup();
469  }
470 
471  EIGEN_DEVICE_FUNC CoeffReturnType coeff(Index index) const
472  {
473  return m_functor(m_arg1Impl.coeff(index), m_arg2Impl.coeff(index), m_arg3Impl.coeff(index));
474  }
475  template<int LoadMode>
476  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketReturnType packet(Index index) const
477  {
478  return m_functor.packetOp(m_arg1Impl.template packet<LoadMode>(index),
479  m_arg2Impl.template packet<LoadMode>(index),
480  m_arg3Impl.template packet<LoadMode>(index));
481  }
482 
483  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorOpCost
484  costPerCoeff(bool vectorized) const {
485  const double functor_cost = internal::functor_traits<TernaryOp>::Cost;
486  return m_arg1Impl.costPerCoeff(vectorized) +
487  m_arg2Impl.costPerCoeff(vectorized) +
488  m_arg3Impl.costPerCoeff(vectorized) +
489  TensorOpCost(0, 0, functor_cost, vectorized, PacketSize);
490  }
491 
492  EIGEN_DEVICE_FUNC CoeffReturnType* data() const { return NULL; }
493 
494  private:
495  const TernaryOp m_functor;
499 };
500 
501 
502 // -------------------- SelectOp --------------------
503 
504 template<typename IfArgType, typename ThenArgType, typename ElseArgType, typename Device>
505 struct TensorEvaluator<const TensorSelectOp<IfArgType, ThenArgType, ElseArgType>, Device>
506 {
507  typedef TensorSelectOp<IfArgType, ThenArgType, ElseArgType> XprType;
508  typedef typename XprType::Scalar Scalar;
509 
510  enum {
513  internal::packet_traits<Scalar>::HasBlend,
515  CoordAccess = false, // to be implemented
516  RawAccess = false
517  };
518 
519  EIGEN_DEVICE_FUNC TensorEvaluator(const XprType& op, const Device& device)
520  : m_condImpl(op.ifExpression(), device),
521  m_thenImpl(op.thenExpression(), device),
522  m_elseImpl(op.elseExpression(), device)
523  {
524  EIGEN_STATIC_ASSERT((static_cast<int>(TensorEvaluator<IfArgType, Device>::Layout) == static_cast<int>(TensorEvaluator<ThenArgType, Device>::Layout)), YOU_MADE_A_PROGRAMMING_MISTAKE);
525  EIGEN_STATIC_ASSERT((static_cast<int>(TensorEvaluator<IfArgType, Device>::Layout) == static_cast<int>(TensorEvaluator<ElseArgType, Device>::Layout)), YOU_MADE_A_PROGRAMMING_MISTAKE);
526  eigen_assert(dimensions_match(m_condImpl.dimensions(), m_thenImpl.dimensions()));
527  eigen_assert(dimensions_match(m_thenImpl.dimensions(), m_elseImpl.dimensions()));
528  }
529 
530  typedef typename XprType::Index Index;
531  typedef typename internal::traits<XprType>::Scalar CoeffReturnType;
532  typedef typename PacketType<CoeffReturnType, Device>::type PacketReturnType;
533  static const int PacketSize = internal::unpacket_traits<PacketReturnType>::size;
534  typedef typename TensorEvaluator<IfArgType, Device>::Dimensions Dimensions;
535 
536  EIGEN_DEVICE_FUNC const Dimensions& dimensions() const
537  {
538  // TODO: use then or else impl instead if they happen to be known at compile time.
539  return m_condImpl.dimensions();
540  }
541 
542  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool evalSubExprsIfNeeded(CoeffReturnType*) {
543  m_condImpl.evalSubExprsIfNeeded(NULL);
544  m_thenImpl.evalSubExprsIfNeeded(NULL);
545  m_elseImpl.evalSubExprsIfNeeded(NULL);
546  return true;
547  }
548  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void cleanup() {
549  m_condImpl.cleanup();
550  m_thenImpl.cleanup();
551  m_elseImpl.cleanup();
552  }
553 
554  EIGEN_DEVICE_FUNC CoeffReturnType coeff(Index index) const
555  {
556  return m_condImpl.coeff(index) ? m_thenImpl.coeff(index) : m_elseImpl.coeff(index);
557  }
558  template<int LoadMode>
559  EIGEN_DEVICE_FUNC PacketReturnType packet(Index index) const
560  {
561  internal::Selector<PacketSize> select;
562  for (Index i = 0; i < PacketSize; ++i) {
563  select.select[i] = m_condImpl.coeff(index+i);
564  }
565  return internal::pblend(select,
566  m_thenImpl.template packet<LoadMode>(index),
567  m_elseImpl.template packet<LoadMode>(index));
568  }
569 
570  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorOpCost
571  costPerCoeff(bool vectorized) const {
572  return m_condImpl.costPerCoeff(vectorized) +
573  m_thenImpl.costPerCoeff(vectorized)
574  .cwiseMax(m_elseImpl.costPerCoeff(vectorized));
575  }
576 
577  EIGEN_DEVICE_FUNC CoeffReturnType* data() const { return NULL; }
578 
579  private:
583 };
584 
585 
586 } // end namespace Eigen
587 
588 #endif // EIGEN_CXX11_TENSOR_TENSOR_EVALUATOR_H
Namespace containing all symbols from the Eigen library.
Definition: AdolcForward:45
A cost model used to limit the number of threads used for evaluating tensor expression.
Definition: TensorEvaluator.h:28