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::Packet Packet;
33  typedef typename Derived::Scalar CoeffReturnType;
34  typedef typename Derived::Packet PacketReturnType;
35  typedef typename Derived::Dimensions Dimensions;
36 
37  // NumDimensions is -1 for variable dim tensors
38  static const int NumCoords = internal::traits<Derived>::NumDimensions > 0 ?
39  internal::traits<Derived>::NumDimensions : 0;
40 
41  enum {
42  IsAligned = Derived::IsAligned,
43  PacketAccess = Derived::PacketAccess,
44  Layout = Derived::Layout,
45  CoordAccess = NumCoords > 0,
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<Packet, LoadMode>(m_data + index);
78  }
79 
80  template <int StoreMode> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
81  void writePacket(Index index, const Packet& x)
82  {
83  return internal::pstoret<Scalar, Packet, 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 Scalar* data() const { return m_data; }
105 
106  protected:
107  Scalar* m_data;
108  Dimensions m_dims;
109  const Device& m_device;
110 };
111 
112 namespace {
113 template <typename T> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE
114 T loadConstant(const T* address) {
115  return *address;
116 }
117 // Use the texture cache on CUDA devices whenever possible
118 #if defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 350
119 template <> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE
120 float loadConstant(const float* address) {
121  return __ldg(address);
122 }
123 template <> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE
124 double loadConstant(const double* address) {
125  return __ldg(address);
126 }
127 #endif
128 }
129 
130 
131 // Default evaluator for rvalues
132 template<typename Derived, typename Device>
133 struct TensorEvaluator<const Derived, Device>
134 {
135  typedef typename Derived::Index Index;
136  typedef typename Derived::Scalar Scalar;
137  typedef typename Derived::Packet Packet;
138  typedef typename Derived::Scalar CoeffReturnType;
139  typedef typename Derived::Packet PacketReturnType;
140  typedef typename Derived::Dimensions Dimensions;
141 
142  // NumDimensions is -1 for variable dim tensors
143  static const int NumCoords = internal::traits<Derived>::NumDimensions > 0 ?
144  internal::traits<Derived>::NumDimensions : 0;
145 
146  enum {
147  IsAligned = Derived::IsAligned,
148  PacketAccess = Derived::PacketAccess,
149  Layout = Derived::Layout,
150  CoordAccess = NumCoords > 0,
151  };
152 
153  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorEvaluator(const Derived& m, const Device& device)
154  : m_data(m.data()), m_dims(m.dimensions()), m_device(device)
155  { }
156 
157  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Dimensions& dimensions() const { return m_dims; }
158 
159  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool evalSubExprsIfNeeded(CoeffReturnType* data) {
160  if (!NumTraits<typename internal::remove_const<Scalar>::type>::RequireInitialization && data) {
161  m_device.memcpy((void*)data, m_data, m_dims.TotalSize() * sizeof(Scalar));
162  return false;
163  }
164  return true;
165  }
166 
167  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void cleanup() { }
168 
169  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(Index index) const {
170  eigen_assert(m_data);
171  return loadConstant(m_data+index);
172  }
173 
174  template<int LoadMode> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
175  PacketReturnType packet(Index index) const
176  {
177  return internal::ploadt_ro<Packet, LoadMode>(m_data + index);
178  }
179 
180  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(const array<DenseIndex, NumCoords>& coords) const {
181  eigen_assert(m_data);
182  const Index index = (static_cast<int>(Layout) == static_cast<int>(ColMajor)) ? m_dims.IndexOfColMajor(coords)
183  : m_dims.IndexOfRowMajor(coords);
184  return loadConstant(m_data+index);
185  }
186 
187  EIGEN_DEVICE_FUNC const Scalar* data() const { return m_data; }
188 
189  protected:
190  const Scalar* m_data;
191  Dimensions m_dims;
192  const Device& m_device;
193 };
194 
195 
196 
197 
198 // -------------------- CwiseNullaryOp --------------------
199 
200 template<typename NullaryOp, typename ArgType, typename Device>
201 struct TensorEvaluator<const TensorCwiseNullaryOp<NullaryOp, ArgType>, Device>
202 {
203  typedef TensorCwiseNullaryOp<NullaryOp, ArgType> XprType;
204 
205  enum {
206  IsAligned = true,
207  PacketAccess = internal::functor_traits<NullaryOp>::PacketAccess,
208  Layout = TensorEvaluator<ArgType, Device>::Layout,
209  CoordAccess = false, // to be implemented
210  };
211 
212  EIGEN_DEVICE_FUNC
213  TensorEvaluator(const XprType& op, const Device& device)
214  : m_functor(op.functor()), m_argImpl(op.nestedExpression(), device)
215  { }
216 
217  typedef typename XprType::Index Index;
218  typedef typename XprType::Scalar Scalar;
219  typedef typename internal::traits<XprType>::Scalar CoeffReturnType;
220  typedef typename internal::traits<XprType>::Packet PacketReturnType;
221  typedef typename TensorEvaluator<ArgType, Device>::Dimensions Dimensions;
222 
223  EIGEN_DEVICE_FUNC const Dimensions& dimensions() const { return m_argImpl.dimensions(); }
224 
225  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool evalSubExprsIfNeeded(CoeffReturnType*) { return true; }
226  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void cleanup() { }
227 
228  EIGEN_DEVICE_FUNC CoeffReturnType coeff(Index index) const
229  {
230  return m_functor(index);
231  }
232 
233  template<int LoadMode>
234  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketReturnType packet(Index index) const
235  {
236  return m_functor.template packetOp<Index,PacketReturnType>(index);
237  }
238 
239  EIGEN_DEVICE_FUNC CoeffReturnType* data() const { return NULL; }
240 
241  private:
242  const NullaryOp m_functor;
243  TensorEvaluator<ArgType, Device> m_argImpl;
244 };
245 
246 
247 
248 // -------------------- CwiseUnaryOp --------------------
249 
250 template<typename UnaryOp, typename ArgType, typename Device>
251 struct TensorEvaluator<const TensorCwiseUnaryOp<UnaryOp, ArgType>, Device>
252 {
253  typedef TensorCwiseUnaryOp<UnaryOp, ArgType> XprType;
254 
255  enum {
256  IsAligned = TensorEvaluator<ArgType, Device>::IsAligned,
257  PacketAccess = TensorEvaluator<ArgType, Device>::PacketAccess & internal::functor_traits<UnaryOp>::PacketAccess,
258  Layout = TensorEvaluator<ArgType, Device>::Layout,
259  CoordAccess = false, // to be implemented
260  };
261 
262  EIGEN_DEVICE_FUNC TensorEvaluator(const XprType& op, const Device& device)
263  : m_functor(op.functor()),
264  m_argImpl(op.nestedExpression(), device)
265  { }
266 
267  typedef typename XprType::Index Index;
268  typedef typename XprType::Scalar Scalar;
269  typedef typename internal::traits<XprType>::Scalar CoeffReturnType;
270  typedef typename internal::traits<XprType>::Packet PacketReturnType;
271  typedef typename TensorEvaluator<ArgType, Device>::Dimensions Dimensions;
272 
273  EIGEN_DEVICE_FUNC const Dimensions& dimensions() const { return m_argImpl.dimensions(); }
274 
275  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool evalSubExprsIfNeeded(Scalar*) {
276  m_argImpl.evalSubExprsIfNeeded(NULL);
277  return true;
278  }
279  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void cleanup() {
280  m_argImpl.cleanup();
281  }
282 
283  EIGEN_DEVICE_FUNC CoeffReturnType coeff(Index index) const
284  {
285  return m_functor(m_argImpl.coeff(index));
286  }
287 
288  template<int LoadMode>
289  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketReturnType packet(Index index) const
290  {
291  return m_functor.packetOp(m_argImpl.template packet<LoadMode>(index));
292  }
293 
294  EIGEN_DEVICE_FUNC CoeffReturnType* data() const { return NULL; }
295 
296  private:
297  const UnaryOp m_functor;
298  TensorEvaluator<ArgType, Device> m_argImpl;
299 };
300 
301 
302 // -------------------- CwiseBinaryOp --------------------
303 
304 template<typename BinaryOp, typename LeftArgType, typename RightArgType, typename Device>
305 struct TensorEvaluator<const TensorCwiseBinaryOp<BinaryOp, LeftArgType, RightArgType>, Device>
306 {
307  typedef TensorCwiseBinaryOp<BinaryOp, LeftArgType, RightArgType> XprType;
308 
309  enum {
310  IsAligned = TensorEvaluator<LeftArgType, Device>::IsAligned & TensorEvaluator<RightArgType, Device>::IsAligned,
311  PacketAccess = TensorEvaluator<LeftArgType, Device>::PacketAccess & TensorEvaluator<RightArgType, Device>::PacketAccess &
312  internal::functor_traits<BinaryOp>::PacketAccess,
313  Layout = TensorEvaluator<LeftArgType, Device>::Layout,
314  CoordAccess = false, // to be implemented
315  };
316 
317  EIGEN_DEVICE_FUNC TensorEvaluator(const XprType& op, const Device& device)
318  : m_functor(op.functor()),
319  m_leftImpl(op.lhsExpression(), device),
320  m_rightImpl(op.rhsExpression(), device)
321  {
322  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);
323  eigen_assert(dimensions_match(m_leftImpl.dimensions(), m_rightImpl.dimensions()));
324  }
325 
326  typedef typename XprType::Index Index;
327  typedef typename XprType::Scalar Scalar;
328  typedef typename internal::traits<XprType>::Scalar CoeffReturnType;
329  typedef typename internal::traits<XprType>::Packet PacketReturnType;
330  typedef typename TensorEvaluator<LeftArgType, Device>::Dimensions Dimensions;
331 
332  EIGEN_DEVICE_FUNC const Dimensions& dimensions() const
333  {
334  // TODO: use right impl instead if right impl dimensions are known at compile time.
335  return m_leftImpl.dimensions();
336  }
337 
338  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool evalSubExprsIfNeeded(CoeffReturnType*) {
339  m_leftImpl.evalSubExprsIfNeeded(NULL);
340  m_rightImpl.evalSubExprsIfNeeded(NULL);
341  return true;
342  }
343  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void cleanup() {
344  m_leftImpl.cleanup();
345  m_rightImpl.cleanup();
346  }
347 
348  EIGEN_DEVICE_FUNC CoeffReturnType coeff(Index index) const
349  {
350  return m_functor(m_leftImpl.coeff(index), m_rightImpl.coeff(index));
351  }
352  template<int LoadMode>
353  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketReturnType packet(Index index) const
354  {
355  return m_functor.packetOp(m_leftImpl.template packet<LoadMode>(index), m_rightImpl.template packet<LoadMode>(index));
356  }
357 
358  EIGEN_DEVICE_FUNC CoeffReturnType* data() const { return NULL; }
359 
360  private:
361  const BinaryOp m_functor;
362  TensorEvaluator<LeftArgType, Device> m_leftImpl;
363  TensorEvaluator<RightArgType, Device> m_rightImpl;
364 };
365 
366 
367 // -------------------- SelectOp --------------------
368 
369 template<typename IfArgType, typename ThenArgType, typename ElseArgType, typename Device>
370 struct TensorEvaluator<const TensorSelectOp<IfArgType, ThenArgType, ElseArgType>, Device>
371 {
372  typedef TensorSelectOp<IfArgType, ThenArgType, ElseArgType> XprType;
373  typedef typename XprType::Scalar Scalar;
374 
375  enum {
376  IsAligned = TensorEvaluator<ThenArgType, Device>::IsAligned & TensorEvaluator<ElseArgType, Device>::IsAligned,
377  PacketAccess = TensorEvaluator<ThenArgType, Device>::PacketAccess & TensorEvaluator<ElseArgType, Device>::PacketAccess &
378  internal::packet_traits<Scalar>::HasBlend,
379  Layout = TensorEvaluator<IfArgType, Device>::Layout,
380  CoordAccess = false, // to be implemented
381  };
382 
383  EIGEN_DEVICE_FUNC TensorEvaluator(const XprType& op, const Device& device)
384  : m_condImpl(op.ifExpression(), device),
385  m_thenImpl(op.thenExpression(), device),
386  m_elseImpl(op.elseExpression(), device)
387  {
388  EIGEN_STATIC_ASSERT((static_cast<int>(TensorEvaluator<IfArgType, Device>::Layout) == static_cast<int>(TensorEvaluator<ThenArgType, Device>::Layout)), YOU_MADE_A_PROGRAMMING_MISTAKE);
389  EIGEN_STATIC_ASSERT((static_cast<int>(TensorEvaluator<IfArgType, Device>::Layout) == static_cast<int>(TensorEvaluator<ElseArgType, Device>::Layout)), YOU_MADE_A_PROGRAMMING_MISTAKE);
390  eigen_assert(dimensions_match(m_condImpl.dimensions(), m_thenImpl.dimensions()));
391  eigen_assert(dimensions_match(m_thenImpl.dimensions(), m_elseImpl.dimensions()));
392  }
393 
394  typedef typename XprType::Index Index;
395  typedef typename internal::traits<XprType>::Scalar CoeffReturnType;
396  typedef typename internal::traits<XprType>::Packet PacketReturnType;
397  typedef typename TensorEvaluator<IfArgType, Device>::Dimensions Dimensions;
398 
399  EIGEN_DEVICE_FUNC const Dimensions& dimensions() const
400  {
401  // TODO: use then or else impl instead if they happen to be known at compile time.
402  return m_condImpl.dimensions();
403  }
404 
405  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool evalSubExprsIfNeeded(CoeffReturnType*) {
406  m_condImpl.evalSubExprsIfNeeded(NULL);
407  m_thenImpl.evalSubExprsIfNeeded(NULL);
408  m_elseImpl.evalSubExprsIfNeeded(NULL);
409  return true;
410  }
411  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void cleanup() {
412  m_condImpl.cleanup();
413  m_thenImpl.cleanup();
414  m_elseImpl.cleanup();
415  }
416 
417  EIGEN_DEVICE_FUNC CoeffReturnType coeff(Index index) const
418  {
419  return m_condImpl.coeff(index) ? m_thenImpl.coeff(index) : m_elseImpl.coeff(index);
420  }
421  template<int LoadMode>
422  EIGEN_DEVICE_FUNC PacketReturnType packet(Index index) const
423  {
424  const int PacketSize = internal::unpacket_traits<PacketReturnType>::size;
425  internal::Selector<PacketSize> select;
426  for (Index i = 0; i < PacketSize; ++i) {
427  select.select[i] = m_condImpl.coeff(index+i);
428  }
429  return internal::pblend(select,
430  m_thenImpl.template packet<LoadMode>(index),
431  m_elseImpl.template packet<LoadMode>(index));
432  }
433 
434  EIGEN_DEVICE_FUNC CoeffReturnType* data() const { return NULL; }
435 
436  private:
437  TensorEvaluator<IfArgType, Device> m_condImpl;
438  TensorEvaluator<ThenArgType, Device> m_thenImpl;
439  TensorEvaluator<ElseArgType, Device> m_elseImpl;
440 };
441 
442 
443 } // end namespace Eigen
444 
445 #endif // EIGEN_CXX11_TENSOR_TENSOR_EVALUATOR_H
Namespace containing all symbols from the Eigen library.
Definition: CXX11Meta.h:13
The tensor evaluator classes.
Definition: TensorEvaluator.h:28