TensorMorphing.h
Go to the documentation of this file.
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_MORPHING_H
11 #define EIGEN_CXX11_TENSOR_TENSOR_MORPHING_H
12 
13 namespace Eigen {
14 
22 namespace internal {
23 template<typename NewDimensions, typename XprType>
24 struct traits<TensorReshapingOp<NewDimensions, XprType> > : public traits<XprType>
25 {
26  typedef typename XprType::Scalar Scalar;
28  typedef typename XprTraits::StorageKind StorageKind;
29  typedef typename XprTraits::Index Index;
30  typedef typename XprType::Nested Nested;
32  static const int NumDimensions = array_size<NewDimensions>::value;
33  static const int Layout = XprTraits::Layout;
34 };
35 
36 template<typename NewDimensions, typename XprType>
37 struct eval<TensorReshapingOp<NewDimensions, XprType>, Eigen::Dense>
38 {
40 };
41 
42 template<typename NewDimensions, typename XprType>
43 struct nested<TensorReshapingOp<NewDimensions, XprType>, 1, typename eval<TensorReshapingOp<NewDimensions, XprType> >::type>
44 {
46 };
47 
48 } // end namespace internal
49 
50 
51 
52 template<typename NewDimensions, typename XprType>
53 class TensorReshapingOp : public TensorBase<TensorReshapingOp<NewDimensions, XprType>, WriteAccessors>
54 {
55  public:
61 
62  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorReshapingOp(const XprType& expr, const NewDimensions& dims)
63  : m_xpr(expr), m_dims(dims) {}
64 
65  EIGEN_DEVICE_FUNC
66  const NewDimensions& dimensions() const { return m_dims; }
67 
68  EIGEN_DEVICE_FUNC
70  expression() const { return m_xpr; }
71 
72  EIGEN_DEVICE_FUNC
74  {
76  Assign assign(*this, other);
78  return *this;
79  }
80 
81  template<typename OtherDerived>
82  EIGEN_DEVICE_FUNC
83  EIGEN_STRONG_INLINE TensorReshapingOp& operator = (const OtherDerived& other)
84  {
86  Assign assign(*this, other);
88  return *this;
89  }
90 
91  protected:
92  typename XprType::Nested m_xpr;
93  const NewDimensions m_dims;
94 };
95 
96 
97 // Eval as rvalue
98 template<typename NewDimensions, typename ArgType, typename Device>
99 struct TensorEvaluator<const TensorReshapingOp<NewDimensions, ArgType>, Device>
100 {
102  typedef NewDimensions Dimensions;
103 
104  enum {
108  CoordAccess = false, // to be implemented
110  };
111 
112  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorEvaluator(const XprType& op, const Device& device)
113  : m_impl(op.expression(), device), m_dimensions(op.dimensions())
114  {
115  // The total size of the reshaped tensor must be equal to the total size
116  // of the input tensor.
117  eigen_assert(internal::array_prod(m_impl.dimensions()) == internal::array_prod(op.dimensions()));
118  }
119 
120  typedef typename XprType::Index Index;
121  typedef typename XprType::Scalar Scalar;
124 
125  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Dimensions& dimensions() const { return m_dimensions; }
126 
127  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool evalSubExprsIfNeeded(CoeffReturnType* data) {
128  return m_impl.evalSubExprsIfNeeded(data);
129  }
130  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void cleanup() {
131  m_impl.cleanup();
132  }
133 
134  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(Index index) const
135  {
136  return m_impl.coeff(index);
137  }
138 
139  template<int LoadMode>
140  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketReturnType packet(Index index) const
141  {
142  return m_impl.template packet<LoadMode>(index);
143  }
144 
145  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorOpCost costPerCoeff(bool vectorized) const {
146  return m_impl.costPerCoeff(vectorized);
147  }
148 
149  EIGEN_DEVICE_FUNC Scalar* data() const { return const_cast<Scalar*>(m_impl.data()); }
150 
151  EIGEN_DEVICE_FUNC const TensorEvaluator<ArgType, Device>& impl() const { return m_impl; }
152 
153  protected:
155  NewDimensions m_dimensions;
156 };
157 
158 
159 // Eval as lvalue
160 template<typename NewDimensions, typename ArgType, typename Device>
161  struct TensorEvaluator<TensorReshapingOp<NewDimensions, ArgType>, Device>
162  : public TensorEvaluator<const TensorReshapingOp<NewDimensions, ArgType>, Device>
163 
164 {
167  typedef NewDimensions Dimensions;
168 
169  enum {
173  CoordAccess = false, // to be implemented
175  };
176 
177  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorEvaluator(const XprType& op, const Device& device)
178  : Base(op, device)
179  { }
180 
181  typedef typename XprType::Index Index;
182  typedef typename XprType::Scalar Scalar;
185 
186  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType& coeffRef(Index index)
187  {
188  return this->m_impl.coeffRef(index);
189  }
190  template <int StoreMode> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
191  void writePacket(Index index, const PacketReturnType& x)
192  {
193  this->m_impl.template writePacket<StoreMode>(index, x);
194  }
195 };
196 
197 
205 namespace internal {
206 template<typename StartIndices, typename Sizes, typename XprType>
207 struct traits<TensorSlicingOp<StartIndices, Sizes, XprType> > : public traits<XprType>
208 {
209  typedef typename XprType::Scalar Scalar;
211  typedef typename XprTraits::StorageKind StorageKind;
212  typedef typename XprTraits::Index Index;
213  typedef typename XprType::Nested Nested;
215  static const int NumDimensions = array_size<StartIndices>::value;
216  static const int Layout = XprTraits::Layout;
217 };
218 
219 template<typename StartIndices, typename Sizes, typename XprType>
220 struct eval<TensorSlicingOp<StartIndices, Sizes, XprType>, Eigen::Dense>
221 {
223 };
224 
225 template<typename StartIndices, typename Sizes, typename XprType>
226 struct nested<TensorSlicingOp<StartIndices, Sizes, XprType>, 1, typename eval<TensorSlicingOp<StartIndices, Sizes, XprType> >::type>
227 {
229 };
230 
231 } // end namespace internal
232 
233 
234 
235 template<typename StartIndices, typename Sizes, typename XprType>
236 class TensorSlicingOp : public TensorBase<TensorSlicingOp<StartIndices, Sizes, XprType> >
237 {
238  public:
240  typedef typename XprType::CoeffReturnType CoeffReturnType;
244 
245  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorSlicingOp(const XprType& expr, const StartIndices& indices, const Sizes& sizes)
246  : m_xpr(expr), m_indices(indices), m_sizes(sizes) {}
247 
248  EIGEN_DEVICE_FUNC
249  const StartIndices& startIndices() const { return m_indices; }
250  EIGEN_DEVICE_FUNC
251  const Sizes& sizes() const { return m_sizes; }
252 
253  EIGEN_DEVICE_FUNC
255  expression() const { return m_xpr; }
256 
257  template<typename OtherDerived>
258  EIGEN_DEVICE_FUNC
259  EIGEN_STRONG_INLINE TensorSlicingOp& operator = (const OtherDerived& other)
260  {
262  Assign assign(*this, other);
264  return *this;
265  }
266 
267  EIGEN_DEVICE_FUNC
269  {
271  Assign assign(*this, other);
273  return *this;
274  }
275 
276 
277  protected:
278  typename XprType::Nested m_xpr;
279  const StartIndices m_indices;
280  const Sizes m_sizes;
281 };
282 
283 
284 // Fixme: figure out the exact threshold
285 namespace {
286 template <typename Index, typename Device> struct MemcpyTriggerForSlicing {
287  EIGEN_DEVICE_FUNC MemcpyTriggerForSlicing(const Device& device) : threshold_(2 * device.numThreads()) { }
288  EIGEN_DEVICE_FUNC bool operator ()(Index val) const { return val > threshold_; }
289 
290  private:
292 };
293 
294 // It is very expensive to start the memcpy kernel on GPU: we therefore only
295 // use it for large copies.
296 #ifdef EIGEN_USE_GPU
297 template <typename Index> struct MemcpyTriggerForSlicing<Index, GpuDevice> {
298  EIGEN_DEVICE_FUNC MemcpyTriggerForSlicing(const GpuDevice&) { }
299  EIGEN_DEVICE_FUNC bool operator ()(Index val) const { return val > 4*1024*1024; }
300 };
301 #endif
302 }
303 
304 // Eval as rvalue
305 template<typename StartIndices, typename Sizes, typename ArgType, typename Device>
306 struct TensorEvaluator<const TensorSlicingOp<StartIndices, Sizes, ArgType>, Device>
307 {
309  static const int NumDims = internal::array_size<Sizes>::value;
310 
311  enum {
312  // Alignment can't be guaranteed at compile time since it depends on the
313  // slice offsets and sizes.
314  IsAligned = /*TensorEvaluator<ArgType, Device>::IsAligned*/false,
317  CoordAccess = false,
318  RawAccess = false
319  };
320 
321  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorEvaluator(const XprType& op, const Device& device)
322  : m_impl(op.expression(), device), m_device(device), m_dimensions(op.sizes()), m_offsets(op.startIndices())
323  {
325  eigen_assert(m_impl.dimensions()[i] >= op.sizes()[i] + op.startIndices()[i]);
326  }
327 
328  const typename TensorEvaluator<ArgType, Device>::Dimensions& input_dims = m_impl.dimensions();
329  const Sizes& output_dims = op.sizes();
330  if (static_cast<int>(Layout) == static_cast<int>(ColMajor)) {
331  m_inputStrides[0] = 1;
332  for (int i = 1; i < NumDims; ++i) {
333  m_inputStrides[i] = m_inputStrides[i-1] * input_dims[i-1];
334  }
335 
336  // Don't initialize m_fastOutputStrides[0] since it won't ever be accessed.
337  m_outputStrides[0] = 1;
338  for (int i = 1; i < NumDims; ++i) {
339  m_outputStrides[i] = m_outputStrides[i-1] * output_dims[i-1];
340  m_fastOutputStrides[i] = internal::TensorIntDivisor<Index>(m_outputStrides[i]);
341  }
342  } else {
343  m_inputStrides[NumDims-1] = 1;
344  for (int i = NumDims - 2; i >= 0; --i) {
345  m_inputStrides[i] = m_inputStrides[i+1] * input_dims[i+1];
346  }
347 
348  // Don't initialize m_fastOutputStrides[NumDims-1] since it won't ever be accessed.
349  m_outputStrides[NumDims-1] = 1;
350  for (int i = NumDims - 2; i >= 0; --i) {
351  m_outputStrides[i] = m_outputStrides[i+1] * output_dims[i+1];
352  m_fastOutputStrides[i] = internal::TensorIntDivisor<Index>(m_outputStrides[i]);
353  }
354  }
355  }
356 
357  typedef typename XprType::Index Index;
358  typedef typename XprType::Scalar Scalar;
361  typedef Sizes Dimensions;
362 
363  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Dimensions& dimensions() const { return m_dimensions; }
364 
365 
366  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool evalSubExprsIfNeeded(CoeffReturnType* data) {
367  m_impl.evalSubExprsIfNeeded(NULL);
368  if (!NumTraits<typename internal::remove_const<Scalar>::type>::RequireInitialization && data && m_impl.data()) {
369  Index contiguous_values = 1;
370  if (static_cast<int>(Layout) == static_cast<int>(ColMajor)) {
371  for (int i = 0; i < NumDims; ++i) {
372  contiguous_values *= dimensions()[i];
373  if (dimensions()[i] != m_impl.dimensions()[i]) {
374  break;
375  }
376  }
377  } else {
378  for (int i = NumDims-1; i >= 0; --i) {
379  contiguous_values *= dimensions()[i];
380  if (dimensions()[i] != m_impl.dimensions()[i]) {
381  break;
382  }
383  }
384  }
385  // Use memcpy if it's going to be faster than using the regular evaluation.
386  const MemcpyTriggerForSlicing<Index, Device> trigger(m_device);
387  if (trigger(contiguous_values)) {
388  Scalar* src = (Scalar*)m_impl.data();
389  for (int i = 0; i < internal::array_prod(dimensions()); i += contiguous_values) {
390  Index offset = srcCoeff(i);
391  m_device.memcpy((void*)(data+i), src+offset, contiguous_values * sizeof(Scalar));
392  }
393  return false;
394  }
395  }
396  return true;
397  }
398 
399  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void cleanup() {
400  m_impl.cleanup();
401  }
402 
403  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(Index index) const
404  {
405  return m_impl.coeff(srcCoeff(index));
406  }
407 
408  template<int LoadMode>
409  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketReturnType packet(Index index) const
410  {
412  EIGEN_STATIC_ASSERT((packetSize > 1), YOU_MADE_A_PROGRAMMING_MISTAKE)
413  eigen_assert(index+packetSize-1 < internal::array_prod(dimensions()));
414 
415  Index inputIndices[] = {0, 0};
416  Index indices[] = {index, index + packetSize - 1};
417  if (static_cast<int>(Layout) == static_cast<int>(ColMajor)) {
418  for (int i = NumDims - 1; i > 0; --i) {
419  const Index idx0 = indices[0] / m_fastOutputStrides[i];
420  const Index idx1 = indices[1] / m_fastOutputStrides[i];
421  inputIndices[0] += (idx0 + m_offsets[i]) * m_inputStrides[i];
422  inputIndices[1] += (idx1 + m_offsets[i]) * m_inputStrides[i];
423  indices[0] -= idx0 * m_outputStrides[i];
424  indices[1] -= idx1 * m_outputStrides[i];
425  }
426  inputIndices[0] += (indices[0] + m_offsets[0]);
427  inputIndices[1] += (indices[1] + m_offsets[0]);
428  } else {
429  for (int i = 0; i < NumDims - 1; ++i) {
430  const Index idx0 = indices[0] / m_fastOutputStrides[i];
431  const Index idx1 = indices[1] / m_fastOutputStrides[i];
432  inputIndices[0] += (idx0 + m_offsets[i]) * m_inputStrides[i];
433  inputIndices[1] += (idx1 + m_offsets[i]) * m_inputStrides[i];
434  indices[0] -= idx0 * m_outputStrides[i];
435  indices[1] -= idx1 * m_outputStrides[i];
436  }
437  inputIndices[0] += (indices[0] + m_offsets[NumDims-1]);
438  inputIndices[1] += (indices[1] + m_offsets[NumDims-1]);
439  }
440  if (inputIndices[1] - inputIndices[0] == packetSize - 1) {
441  PacketReturnType rslt = m_impl.template packet<Unaligned>(inputIndices[0]);
442  return rslt;
443  }
444  else {
446  values[0] = m_impl.coeff(inputIndices[0]);
447  values[packetSize-1] = m_impl.coeff(inputIndices[1]);
448  for (int i = 1; i < packetSize-1; ++i) {
449  values[i] = coeff(index+i);
450  }
451  PacketReturnType rslt = internal::pload<PacketReturnType>(values);
452  return rslt;
453  }
454  }
455 
456  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorOpCost costPerCoeff(bool vectorized) const {
457  return m_impl.costPerCoeff(vectorized) + TensorOpCost(0, 0, NumDims);
458  }
459 
460 
461  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar* data() const {
462  Scalar* result = m_impl.data();
463  if (result) {
464  Index offset = 0;
465  if (static_cast<int>(Layout) == static_cast<int>(ColMajor)) {
466  for (int i = 0; i < NumDims; ++i) {
467  if (m_dimensions[i] != m_impl.dimensions()[i]) {
468  offset += m_offsets[i] * m_inputStrides[i];
469  for (int j = i+1; j < NumDims; ++j) {
470  if (m_dimensions[j] > 1) {
471  return NULL;
472  }
473  offset += m_offsets[j] * m_inputStrides[j];
474  }
475  break;
476  }
477  }
478  } else {
479  for (int i = NumDims - 1; i >= 0; --i) {
480  if (m_dimensions[i] != m_impl.dimensions()[i]) {
481  offset += m_offsets[i] * m_inputStrides[i];
482  for (int j = i-1; j >= 0; --j) {
483  if (m_dimensions[j] > 1) {
484  return NULL;
485  }
486  offset += m_offsets[j] * m_inputStrides[j];
487  }
488  break;
489  }
490  }
491  }
492  return result + offset;
493  }
494  return NULL;
495  }
496 
497  protected:
498  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index srcCoeff(Index index) const
499  {
500  Index inputIndex = 0;
501  if (static_cast<int>(Layout) == static_cast<int>(ColMajor)) {
502  for (int i = NumDims - 1; i > 0; --i) {
503  const Index idx = index / m_fastOutputStrides[i];
504  inputIndex += (idx + m_offsets[i]) * m_inputStrides[i];
505  index -= idx * m_outputStrides[i];
506  }
507  inputIndex += (index + m_offsets[0]);
508  } else {
509  for (int i = 0; i < NumDims - 1; ++i) {
510  const Index idx = index / m_fastOutputStrides[i];
511  inputIndex += (idx + m_offsets[i]) * m_inputStrides[i];
512  index -= idx * m_outputStrides[i];
513  }
514  inputIndex += (index + m_offsets[NumDims-1]);
515  }
516  return inputIndex;
517  }
518 
523  const Device& m_device;
524  Dimensions m_dimensions;
525  const StartIndices m_offsets;
526 };
527 
528 
529 // Eval as lvalue
530 template<typename StartIndices, typename Sizes, typename ArgType, typename Device>
531 struct TensorEvaluator<TensorSlicingOp<StartIndices, Sizes, ArgType>, Device>
532  : public TensorEvaluator<const TensorSlicingOp<StartIndices, Sizes, ArgType>, Device>
533 {
536  static const int NumDims = internal::array_size<Sizes>::value;
537 
538  enum {
539  IsAligned = /*TensorEvaluator<ArgType, Device>::IsAligned*/false,
542  CoordAccess = false,
543  RawAccess = false
544  };
545 
546  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorEvaluator(const XprType& op, const Device& device)
547  : Base(op, device)
548  { }
549 
550  typedef typename XprType::Index Index;
551  typedef typename XprType::Scalar Scalar;
554  typedef Sizes Dimensions;
555 
556  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType& coeffRef(Index index)
557  {
558  return this->m_impl.coeffRef(this->srcCoeff(index));
559  }
560 
561  template <int StoreMode> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
562  void writePacket(Index index, const PacketReturnType& x)
563  {
565  Index inputIndices[] = {0, 0};
566  Index indices[] = {index, index + packetSize - 1};
567  if (static_cast<int>(Layout) == static_cast<int>(ColMajor)) {
568  for (int i = NumDims - 1; i > 0; --i) {
569  const Index idx0 = indices[0] / this->m_fastOutputStrides[i];
570  const Index idx1 = indices[1] / this->m_fastOutputStrides[i];
571  inputIndices[0] += (idx0 + this->m_offsets[i]) * this->m_inputStrides[i];
572  inputIndices[1] += (idx1 + this->m_offsets[i]) * this->m_inputStrides[i];
573  indices[0] -= idx0 * this->m_outputStrides[i];
574  indices[1] -= idx1 * this->m_outputStrides[i];
575  }
576  inputIndices[0] += (indices[0] + this->m_offsets[0]);
577  inputIndices[1] += (indices[1] + this->m_offsets[0]);
578  } else {
579  for (int i = 0; i < NumDims - 1; ++i) {
580  const Index idx0 = indices[0] / this->m_fastOutputStrides[i];
581  const Index idx1 = indices[1] / this->m_fastOutputStrides[i];
582  inputIndices[0] += (idx0 + this->m_offsets[i]) * this->m_inputStrides[i];
583  inputIndices[1] += (idx1 + this->m_offsets[i]) * this->m_inputStrides[i];
584  indices[0] -= idx0 * this->m_outputStrides[i];
585  indices[1] -= idx1 * this->m_outputStrides[i];
586  }
587  inputIndices[0] += (indices[0] + this->m_offsets[NumDims-1]);
588  inputIndices[1] += (indices[1] + this->m_offsets[NumDims-1]);
589  }
590  if (inputIndices[1] - inputIndices[0] == packetSize - 1) {
591  this->m_impl.template writePacket<StoreMode>(inputIndices[0], x);
592  }
593  else {
594  EIGEN_ALIGN_MAX CoeffReturnType values[packetSize];
595  internal::pstore<CoeffReturnType, PacketReturnType>(values, x);
596  this->m_impl.coeffRef(inputIndices[0]) = values[0];
597  this->m_impl.coeffRef(inputIndices[1]) = values[packetSize-1];
598  for (int i = 1; i < packetSize-1; ++i) {
599  this->coeffRef(index+i) = values[i];
600  }
601  }
602  }
603 };
604 
605 
606 
607 namespace internal {
608 template<typename StartIndices, typename StopIndices, typename Strides, typename XprType>
609 struct traits<TensorStridingSlicingOp<StartIndices, StopIndices, Strides, XprType> > : public traits<XprType>
610 {
611  typedef typename XprType::Scalar Scalar;
613  typedef typename XprTraits::StorageKind StorageKind;
614  typedef typename XprTraits::Index Index;
615  typedef typename XprType::Nested Nested;
617  static const int NumDimensions = array_size<StartIndices>::value;
618  static const int Layout = XprTraits::Layout;
619 };
620 
621 template<typename StartIndices, typename StopIndices, typename Strides, typename XprType>
622 struct eval<TensorStridingSlicingOp<StartIndices, StopIndices, Strides, XprType>, Eigen::Dense>
623 {
625 };
626 
627 template<typename StartIndices, typename StopIndices, typename Strides, typename XprType>
628 struct nested<TensorStridingSlicingOp<StartIndices, StopIndices, Strides, XprType>, 1, typename eval<TensorStridingSlicingOp<StartIndices, StopIndices, Strides, XprType> >::type>
629 {
631 };
632 
633 } // end namespace internal
634 
635 
636 template<typename StartIndices, typename StopIndices, typename Strides, typename XprType>
637 class TensorStridingSlicingOp : public TensorBase<TensorStridingSlicingOp<StartIndices, StopIndices, Strides, XprType> >
638 {
639  public:
641  typedef typename XprType::CoeffReturnType CoeffReturnType;
645 
647  const XprType& expr, const StartIndices& startIndices,
648  const StopIndices& stopIndices, const Strides& strides)
649  : m_xpr(expr), m_startIndices(startIndices), m_stopIndices(stopIndices),
650  m_strides(strides) {}
651 
652  EIGEN_DEVICE_FUNC
653  const StartIndices& startIndices() const { return m_startIndices; }
654  EIGEN_DEVICE_FUNC
655  const StartIndices& stopIndices() const { return m_stopIndices; }
656  EIGEN_DEVICE_FUNC
657  const StartIndices& strides() const { return m_strides; }
658 
659  EIGEN_DEVICE_FUNC
661  expression() const { return m_xpr; }
662 
663  EIGEN_DEVICE_FUNC
665  {
667  Assign assign(*this, other);
669  assign, DefaultDevice());
670  return *this;
671  }
672 
673  template<typename OtherDerived>
674  EIGEN_DEVICE_FUNC
675  EIGEN_STRONG_INLINE TensorStridingSlicingOp& operator = (const OtherDerived& other)
676  {
678  Assign assign(*this, other);
680  assign, DefaultDevice());
681  return *this;
682  }
683 
684  protected:
685  typename XprType::Nested m_xpr;
686  const StartIndices m_startIndices;
687  const StopIndices m_stopIndices;
688  const Strides m_strides;
689 };
690 
691 // Eval as rvalue
692 template<typename StartIndices, typename StopIndices, typename Strides, typename ArgType, typename Device>
693 struct TensorEvaluator<const TensorStridingSlicingOp<StartIndices, StopIndices, Strides, ArgType>, Device>
694 {
696  static const int NumDims = internal::array_size<Strides>::value;
697 
698  enum {
699  // Alignment can't be guaranteed at compile time since it depends on the
700  // slice offsets and sizes.
701  IsAligned = false,
702  PacketAccess = false,
703  BlockAccess = false,
705  RawAccess = false
706  };
707 
708  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorEvaluator(const XprType& op, const Device& device)
709  : m_impl(op.expression(), device), m_device(device), m_strides(op.strides())
710  {
711  // Handle degenerate intervals by gracefully clamping and allowing m_dimensions to be zero
712  DSizes<Index,NumDims> startIndicesClamped, stopIndicesClamped;
713  for (size_t i = 0; i < internal::array_size<Dimensions>::value; ++i) {
714  eigen_assert(m_strides[i] != 0 && "0 stride is invalid");
715  if(m_strides[i]>0){
716  startIndicesClamped[i] = clamp(op.startIndices()[i], 0, m_impl.dimensions()[i]);
717  stopIndicesClamped[i] = clamp(op.stopIndices()[i], 0, m_impl.dimensions()[i]);
718  }else{
719  /* implies m_strides[i]<0 by assert */
720  startIndicesClamped[i] = clamp(op.startIndices()[i], -1, m_impl.dimensions()[i] - 1);
721  stopIndicesClamped[i] = clamp(op.stopIndices()[i], -1, m_impl.dimensions()[i] - 1);
722  }
723  m_startIndices[i] = startIndicesClamped[i];
724  }
725 
726  const typename TensorEvaluator<ArgType, Device>::Dimensions& input_dims = m_impl.dimensions();
727 
728  // check for degenerate intervals and compute output tensor shape
729  bool degenerate = false;;
730  for(int i = 0; i < NumDims; i++){
731  Index interval = stopIndicesClamped[i] - startIndicesClamped[i];
732  if(interval == 0 || ((interval<0) != (m_strides[i]<0))){
733  m_dimensions[i] = 0;
734  degenerate = true;
735  }else{
736  m_dimensions[i] = interval / m_strides[i]
737  + (interval % m_strides[i] != 0 ? 1 : 0);
738  eigen_assert(m_dimensions[i] >= 0);
739  }
740  }
741  Strides output_dims = m_dimensions;
742 
743  if (static_cast<int>(Layout) == static_cast<int>(ColMajor)) {
744  m_inputStrides[0] = m_strides[0];
745  m_offsets[0] = startIndicesClamped[0];
746  Index previousDimProduct = 1;
747  for (int i = 1; i < NumDims; ++i) {
748  previousDimProduct *= input_dims[i-1];
749  m_inputStrides[i] = previousDimProduct * m_strides[i];
750  m_offsets[i] = startIndicesClamped[i] * previousDimProduct;
751  }
752 
753  // Don't initialize m_fastOutputStrides[0] since it won't ever be accessed.
754  m_outputStrides[0] = 1;
755  for (int i = 1; i < NumDims; ++i) {
756  m_outputStrides[i] = m_outputStrides[i-1] * output_dims[i-1];
757  // NOTE: if tensor is degenerate, we send 1 to prevent TensorIntDivisor constructor crash
758  m_fastOutputStrides[i] = internal::TensorIntDivisor<Index>(degenerate ? 1 : m_outputStrides[i]);
759  }
760  } else {
761  m_inputStrides[NumDims-1] = m_strides[NumDims-1];
762  m_offsets[NumDims-1] = startIndicesClamped[NumDims-1];
763  Index previousDimProduct = 1;
764  for (int i = NumDims - 2; i >= 0; --i) {
765  previousDimProduct *= input_dims[i+1];
766  m_inputStrides[i] = previousDimProduct * m_strides[i];
767  m_offsets[i] = startIndicesClamped[i] * previousDimProduct;
768  }
769 
770  m_outputStrides[NumDims-1] = 1;
771  for (int i = NumDims - 2; i >= 0; --i) {
772  m_outputStrides[i] = m_outputStrides[i+1] * output_dims[i+1];
773  // NOTE: if tensor is degenerate, we send 1 to prevent TensorIntDivisor constructor crash
774  m_fastOutputStrides[i] = internal::TensorIntDivisor<Index>(degenerate ? 1 : m_outputStrides[i]);
775  }
776  }
777  m_block_total_size_max = numext::maxi(static_cast<std::size_t>(1),
778  device.lastLevelCacheSize() /
779  sizeof(Scalar));
780  }
781 
782  typedef typename XprType::Index Index;
783  typedef typename XprType::Scalar Scalar;
787  typedef Strides Dimensions;
788 
789  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Dimensions& dimensions() const { return m_dimensions; }
790 
791 
792  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool evalSubExprsIfNeeded(CoeffReturnType*) {
793  m_impl.evalSubExprsIfNeeded(NULL);
794  return true;
795  }
796 
797  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void cleanup() {
798  m_impl.cleanup();
799  }
800 
801  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(Index index) const
802  {
803  return m_impl.coeff(srcCoeff(index));
804  }
805 
806  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorOpCost costPerCoeff(bool vectorized) const {
807  return m_impl.costPerCoeff(vectorized) + TensorOpCost(0, 0, NumDims);
808  }
809 
810  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar* data() const {
811  return NULL;
812  }
813 
814  protected:
815  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index srcCoeff(Index index) const
816  {
817  Index inputIndex = 0;
818  if (static_cast<int>(Layout) == static_cast<int>(ColMajor)) {
819  for (int i = NumDims - 1; i >= 0; --i) {
820  const Index idx = index / m_fastOutputStrides[i];
821  inputIndex += idx * m_inputStrides[i] + m_offsets[i];
822  index -= idx * m_outputStrides[i];
823  }
824  } else {
825  for (int i = 0; i < NumDims; ++i) {
826  const Index idx = index / m_fastOutputStrides[i];
827  inputIndex += idx * m_inputStrides[i] + m_offsets[i];
828  index -= idx * m_outputStrides[i];
829  }
830  }
831  return inputIndex;
832  }
833 
834  static EIGEN_STRONG_INLINE Index clamp(Index value, Index min, Index max) {
835  return numext::maxi(min, numext::mini(max,value));
836  }
837 
842  const Device& m_device;
843  DSizes<Index, NumDims> m_startIndices; // clamped startIndices
845  DSizes<Index, NumDims> m_offsets; // offset in a flattened shape
846  const Strides m_strides;
848 };
849 
850 // Eval as lvalue
851 template<typename StartIndices, typename StopIndices, typename Strides, typename ArgType, typename Device>
852 struct TensorEvaluator<TensorStridingSlicingOp<StartIndices, StopIndices, Strides, ArgType>, Device>
853  : public TensorEvaluator<const TensorStridingSlicingOp<StartIndices, StopIndices, Strides, ArgType>, Device>
854 {
857  static const int NumDims = internal::array_size<Strides>::value;
858 
859  enum {
860  IsAligned = false,
861  PacketAccess = false,
862  BlockAccess = false,
865  RawAccess = false
866  };
867 
868  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorEvaluator(const XprType& op, const Device& device)
869  : Base(op, device)
870  { }
871 
872  typedef typename XprType::Index Index;
873  typedef typename XprType::Scalar Scalar;
877  typedef Strides Dimensions;
878 
879  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType& coeffRef(Index index)
880  {
881  return this->m_impl.coeffRef(this->srcCoeff(index));
882  }
883 };
884 
885 
886 } // end namespace Eigen
887 
888 #endif // EIGEN_CXX11_TENSOR_TENSOR_MORPHING_H
SCALAR Scalar
Definition: bench_gemm.cpp:33
EIGEN_DEVICE_FUNC const StartIndices & strides() const
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE std::ptrdiff_t array_prod(const Sizes< Indices... > &)
#define max(a, b)
Definition: datatypes.h:20
#define EIGEN_STRONG_INLINE
Definition: Macros.h:494
internal::traits< TensorStridingSlicingOp >::Scalar Scalar
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorEvaluator(const XprType &op, const Device &device)
Eigen::internal::traits< TensorSlicingOp >::Index Index
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Dimensions & dimensions() const
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorEvaluator(const XprType &op, const Device &device)
#define min(a, b)
Definition: datatypes.h:19
EIGEN_DEVICE_FUNC const Sizes & sizes() const
std::vector< Array2i > sizes
TensorEvaluator< const TensorStridingSlicingOp< StartIndices, StopIndices, Strides, ArgType >, Device > Base
leaf::MyValues values
set noclip points set clip one set noclip two set bar set border lt lw set xdata set ydata set zdata set x2data set y2data set boxwidth set dummy y set format x g set format y g set format x2 g set format y2 g set format z g set angles radians set nogrid set key title set key left top Right noreverse box linetype linewidth samplen spacing width set nolabel set noarrow set nologscale set logscale x set set pointsize set encoding default set nopolar set noparametric set set set set surface set nocontour set clabel set mapping cartesian set nohidden3d set cntrparam order set cntrparam linear set cntrparam levels auto set cntrparam points set size set set xzeroaxis lt lw set x2zeroaxis lt lw set yzeroaxis lt lw set y2zeroaxis lt lw set tics in set ticslevel set tics set mxtics default set mytics default set mx2tics default set my2tics default set xtics border mirror norotate autofreq set ytics border mirror norotate autofreq set ztics border nomirror norotate autofreq set nox2tics set noy2tics set timestamp bottom norotate offset
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType & coeffRef(Index index)
Namespace containing all symbols from the Eigen library.
Definition: jet.h:637
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketReturnType packet(Index index) const
A cost model used to limit the number of threads used for evaluating tensor expression.
Holds information about the various numeric (i.e. scalar) types allowed by Eigen. ...
Definition: NumTraits.h:150
#define EIGEN_STATIC_ASSERT(CONDITION, MSG)
Definition: StaticAssert.h:124
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorOpCost costPerCoeff(bool vectorized) const
EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE T maxi(const T &x, const T &y)
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Dimensions & dimensions() const
internal::nested< TensorStridingSlicingOp >::type Nested
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(Index index) const
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Dimensions & dimensions() const
internal::remove_const< typename XprType::CoeffReturnType >::type CoeffReturnType
vector< size_t > dimensions(L.begin(), L.end())
internal::traits< TensorStridingSlicingOp >::Index Index
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool evalSubExprsIfNeeded(CoeffReturnType *data)
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorOpCost costPerCoeff(bool vectorized) const
EIGEN_DEVICE_FUNC const StartIndices & startIndices() const
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorStridingSlicingOp(const XprType &expr, const StartIndices &startIndices, const StopIndices &stopIndices, const Strides &strides)
EIGEN_DEVICE_FUNC const internal::remove_all< typename XprType::Nested >::type & expression() const
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorEvaluator(const XprType &op, const Device &device)
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorEvaluator(const XprType &op, const Device &device)
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool evalSubExprsIfNeeded(CoeffReturnType *data)
Values result
Eigen::internal::traits< TensorSlicingOp >::Scalar Scalar
EIGEN_DEVICE_FUNC const NewDimensions & dimensions() const
Eigen::internal::traits< TensorReshapingOp >::StorageKind StorageKind
Eigen::internal::traits< TensorSlicingOp >::StorageKind StorageKind
internal::traits< TensorStridingSlicingOp >::StorageKind StorageKind
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(Index index) const
EIGEN_DEFAULT_DENSE_INDEX_TYPE Index
The Index type as used for the API.
Definition: Meta.h:33
#define eigen_assert(x)
Definition: Macros.h:579
int data[]
Eigen::internal::traits< TensorReshapingOp >::Scalar Scalar
EIGEN_DEVICE_FUNC const StartIndices & startIndices() const
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorEvaluator(const XprType &op, const Device &device)
const TensorStridingSlicingOp< StartIndices, StopIndices, Strides, XprType > & type
static EIGEN_DEVICE_FUNC void run(const Expression &expr, const Device &device=Device())
TensorStridingSlicingOp< StartIndices, StopIndices, Strides, ArgType > XprType
#define NULL
Definition: ccolamd.c:609
TensorEvaluator< const TensorReshapingOp< NewDimensions, ArgType >, Device > Base
EIGEN_DEVICE_FUNC const internal::remove_all< typename XprType::Nested >::type & expression() const
EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE T mini(const T &x, const T &y)
The tensor base class.
Definition: TensorBase.h:829
Eigen::internal::nested< TensorReshapingOp >::type Nested
EIGEN_DEVICE_FUNC const internal::remove_all< typename XprType::Nested >::type & expression() const
const StartIndices m_indices
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void writePacket(Index index, const PacketReturnType &x)
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorEvaluator(const XprType &op, const Device &device)
XprType::Nested m_xpr
#define EIGEN_ALIGN_MAX
Definition: Macros.h:757
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketReturnType packet(Index index) const
EIGEN_DEVICE_FUNC const TensorEvaluator< ArgType, Device > & impl() const
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType & coeffRef(Index index)
XprType::CoeffReturnType CoeffReturnType
const StartIndices m_startIndices
Eigen::internal::traits< TensorReshapingOp >::Index Index
TensorEvaluator< const TensorSlicingOp< StartIndices, Sizes, ArgType >, Device > Base
XprType::CoeffReturnType CoeffReturnType
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorSlicingOp(const XprType &expr, const StartIndices &indices, const Sizes &sizes)
const NewDimensions m_dims
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void writePacket(Index index, const PacketReturnType &x)
set noclip points set clip one set noclip two set bar set border lt lw set xdata set ydata set zdata set x2data set y2data set boxwidth set dummy x
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorOpCost costPerCoeff(bool vectorized) const
Eigen::internal::nested< TensorSlicingOp >::type Nested
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorReshapingOp(const XprType &expr, const NewDimensions &dims)
std::ptrdiff_t j
EIGEN_DEVICE_FUNC const StartIndices & stopIndices() const
Index threshold_
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index srcCoeff(Index index) const


gtsam
Author(s):
autogenerated on Sat May 8 2021 02:45:38