$darkmode
Eigen-unsupported  5.0.1-dev
TensorMorphing.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_MORPHING_H
11 #define EIGEN_CXX11_TENSOR_TENSOR_MORPHING_H
12 
13 // IWYU pragma: private
14 #include "./InternalHeaderCheck.h"
15 
16 namespace Eigen {
17 
18 namespace internal {
19 template <typename NewDimensions, typename XprType>
20 struct traits<TensorReshapingOp<NewDimensions, XprType>> : public traits<XprType> {
21  typedef typename XprType::Scalar Scalar;
22  typedef traits<XprType> XprTraits;
23  typedef typename XprTraits::StorageKind StorageKind;
24  typedef typename XprTraits::Index Index;
25  typedef typename XprType::Nested Nested;
26  typedef std::remove_reference_t<Nested> Nested_;
27  static constexpr int NumDimensions = array_size<NewDimensions>::value;
28  static constexpr int Layout = XprTraits::Layout;
29  typedef typename XprTraits::PointerType PointerType;
30 };
31 
32 template <typename NewDimensions, typename XprType>
33 struct eval<TensorReshapingOp<NewDimensions, XprType>, Eigen::Dense> {
34  typedef const TensorReshapingOp<NewDimensions, XprType> EIGEN_DEVICE_REF type;
35 };
36 
37 template <typename NewDimensions, typename XprType>
38 struct nested<TensorReshapingOp<NewDimensions, XprType>, 1,
39  typename eval<TensorReshapingOp<NewDimensions, XprType>>::type> {
40  typedef TensorReshapingOp<NewDimensions, XprType> type;
41 };
42 
43 } // end namespace internal
44 
50 template <typename NewDimensions, typename XprType>
51 class TensorReshapingOp : public TensorBase<TensorReshapingOp<NewDimensions, XprType>, WriteAccessors> {
52  public:
53  typedef TensorBase<TensorReshapingOp<NewDimensions, XprType>, WriteAccessors> Base;
54  typedef typename Eigen::internal::traits<TensorReshapingOp>::Scalar Scalar;
55  typedef std::remove_const_t<typename XprType::CoeffReturnType> CoeffReturnType;
56  typedef typename Eigen::internal::nested<TensorReshapingOp>::type Nested;
57  typedef typename Eigen::internal::traits<TensorReshapingOp>::StorageKind StorageKind;
58  typedef typename Eigen::internal::traits<TensorReshapingOp>::Index Index;
59 
60  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorReshapingOp(const XprType& expr, const NewDimensions& dims)
61  : m_xpr(expr), m_dims(dims) {}
62 
63  EIGEN_DEVICE_FUNC const NewDimensions& dimensions() const { return m_dims; }
64 
65  EIGEN_DEVICE_FUNC const internal::remove_all_t<typename XprType::Nested>& expression() const { return m_xpr; }
66 
67  EIGEN_TENSOR_INHERIT_ASSIGNMENT_OPERATORS(TensorReshapingOp)
68 
69  protected:
70  typename XprType::Nested m_xpr;
71  const NewDimensions m_dims;
72 };
73 
74 // Eval as rvalue
75 template <typename NewDimensions, typename ArgType, typename Device>
76 struct TensorEvaluator<const TensorReshapingOp<NewDimensions, ArgType>, Device> {
77  typedef TensorReshapingOp<NewDimensions, ArgType> XprType;
78  typedef NewDimensions Dimensions;
79 
80  typedef typename XprType::Index Index;
81  typedef typename XprType::Scalar Scalar;
82  typedef typename XprType::CoeffReturnType CoeffReturnType;
83  typedef typename PacketType<CoeffReturnType, Device>::type PacketReturnType;
84  typedef StorageMemory<CoeffReturnType, Device> Storage;
85  typedef typename Storage::Type EvaluatorPointerType;
86  typedef StorageMemory<std::remove_const_t<CoeffReturnType>, Device> ConstCastStorage;
87 
88  static constexpr int NumOutputDims = internal::array_size<Dimensions>::value;
89  static constexpr int NumInputDims =
90  internal::array_size<typename TensorEvaluator<ArgType, Device>::Dimensions>::value;
91 
92  enum ReshapingKind {
93  // We do not use layout information to determine reshaping kind.
94  // Depending on the layout `N` can be inner or outer dimension.
95  OneByN = 0, // expr.reshape(1, N)
96  NByOne = 1, // expr.reshape(N, 1)
97  Runtime = 2 // Reshape dimensions are dynamic (specified at runtime).
98  };
99 
100  // clang-format off
101  static const ReshapingKind kind =
102  (NumOutputDims == 2 && internal::index_statically_eq<NewDimensions>(/*index=*/0, /*value=*/1)) ? OneByN
103  : (NumOutputDims == 2 && internal::index_statically_eq<NewDimensions>(/*index=*/1, /*value=*/1)) ? NByOne
104  : Runtime;
105  // clang-format on
106 
107  static constexpr int Layout = TensorEvaluator<ArgType, Device>::Layout;
108  enum {
109  IsAligned = TensorEvaluator<ArgType, Device>::IsAligned,
110  PacketAccess = TensorEvaluator<ArgType, Device>::PacketAccess,
111  // For trivial reshapes with raw access to underlying data we will provide
112  // zero overhead block access.
113  // TODO(ezhulenev): Consider adding block access without raw access?
114  BlockAccess = TensorEvaluator<ArgType, Device>::RawAccess && NumInputDims > 0 && NumOutputDims > 0,
115  PreferBlockAccess = false,
116  CoordAccess = false, // to be implemented
117  RawAccess = TensorEvaluator<ArgType, Device>::RawAccess
118  };
119 
120  typedef std::remove_const_t<Scalar> ScalarNoConst;
121 
122  //===- Tensor block evaluation strategy (see TensorBlock.h) -------------===//
123  typedef internal::TensorBlockDescriptor<NumOutputDims, Index> TensorBlockDesc;
124  typedef internal::TensorBlockScratchAllocator<Device> TensorBlockScratch;
125 
126  typedef typename internal::TensorMaterializedBlock<ScalarNoConst, NumOutputDims, Layout, Index> TensorBlock;
127  //===--------------------------------------------------------------------===//
128 
129  EIGEN_STRONG_INLINE TensorEvaluator(const XprType& op, const Device& device)
130  : m_impl(op.expression(), device), m_dimensions(op.dimensions()) {
131  // The total size of the reshaped tensor must be equal to the total size
132  // of the input tensor.
133  eigen_assert(internal::array_prod(m_impl.dimensions()) == internal::array_prod(op.dimensions()));
134  }
135 
136  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Dimensions& dimensions() const { return m_dimensions; }
137 
138 #ifdef EIGEN_USE_THREADS
139  template <typename EvalSubExprsCallback>
140  EIGEN_STRONG_INLINE void evalSubExprsIfNeededAsync(EvaluatorPointerType data, EvalSubExprsCallback done) {
141  m_impl.evalSubExprsIfNeededAsync(data, std::move(done));
142  }
143 #endif
144 
145  EIGEN_STRONG_INLINE bool evalSubExprsIfNeeded(EvaluatorPointerType data) { return m_impl.evalSubExprsIfNeeded(data); }
146  EIGEN_STRONG_INLINE void cleanup() { m_impl.cleanup(); }
147 
148  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(Index index) const { return m_impl.coeff(index); }
149 
150  template <int LoadMode>
151  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketReturnType packet(Index index) const {
152  return m_impl.template packet<LoadMode>(index);
153  }
154 
155  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorOpCost costPerCoeff(bool vectorized) const {
156  return m_impl.costPerCoeff(vectorized);
157  }
158 
159  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE internal::TensorBlockResourceRequirements getResourceRequirements() const {
160  return internal::TensorBlockResourceRequirements::any();
161  }
162 
163  // required in block(OutputTensorBlock* output_block) const
164  // For C++03 compatibility this must be defined outside the method
165  struct BlockIteratorState {
166  Index stride;
167  Index span;
168  Index size;
169  Index count;
170  };
171 
172  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorBlock block(TensorBlockDesc& desc, TensorBlockScratch& scratch,
173  bool /*root_of_expr_ast*/ = false) const {
174  eigen_assert(m_impl.data() != NULL);
175  eigen_assert((kind == Runtime) || (kind == OneByN && desc.dimensions()[0] == 1) ||
176  (kind == NByOne && desc.dimensions()[1] == 1));
177 
178  if (kind == OneByN || kind == NByOne) {
179  // We can guarantee at compile time that block is just a contiguous slice
180  // of the underlying expression memory buffer.
181  return TensorBlock(internal::TensorBlockKind::kView, m_impl.data() + desc.offset(), desc.dimensions());
182  } else {
183  // This will do additional runtime checks, and in the end it might be also
184  // a view, or it might be a block materialized in the temporary buffer.
185  return TensorBlock::materialize(m_impl.data(), m_dimensions, desc, scratch);
186  }
187  }
188 
189  EIGEN_DEVICE_FUNC typename Storage::Type data() const { return constCast(m_impl.data()); }
190 
191  EIGEN_DEVICE_FUNC const TensorEvaluator<ArgType, Device>& impl() const { return m_impl; }
192 
193  protected:
194  TensorEvaluator<ArgType, Device> m_impl;
195  NewDimensions m_dimensions;
196 };
197 
198 // Eval as lvalue
199 template <typename NewDimensions, typename ArgType, typename Device>
200 struct TensorEvaluator<TensorReshapingOp<NewDimensions, ArgType>, Device>
201  : public TensorEvaluator<const TensorReshapingOp<NewDimensions, ArgType>, Device>
202 
203 {
204  typedef TensorEvaluator<const TensorReshapingOp<NewDimensions, ArgType>, Device> Base;
205  typedef TensorReshapingOp<NewDimensions, ArgType> XprType;
206  typedef NewDimensions Dimensions;
207 
208  static constexpr int Layout = TensorEvaluator<ArgType, Device>::Layout;
209  enum {
210  IsAligned = TensorEvaluator<ArgType, Device>::IsAligned,
211  PacketAccess = TensorEvaluator<ArgType, Device>::PacketAccess,
212  BlockAccess = TensorEvaluator<ArgType, Device>::RawAccess,
213  PreferBlockAccess = false,
214  CoordAccess = false, // to be implemented
215  RawAccess = TensorEvaluator<ArgType, Device>::RawAccess
216  };
217 
218  EIGEN_STRONG_INLINE TensorEvaluator(const XprType& op, const Device& device) : Base(op, device) {}
219 
220  typedef typename XprType::Index Index;
221  typedef typename XprType::Scalar Scalar;
222  typedef typename XprType::CoeffReturnType CoeffReturnType;
223  typedef typename PacketType<CoeffReturnType, Device>::type PacketReturnType;
224 
225  //===- Tensor block evaluation strategy (see TensorBlock.h) -------------===//
226  typedef internal::TensorBlockDescriptor<TensorEvaluator::NumOutputDims, Index> TensorBlockDesc;
227  //===--------------------------------------------------------------------===//
228 
229  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType& coeffRef(Index index) const {
230  return this->m_impl.coeffRef(index);
231  }
232 
233  template <int StoreMode>
234  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void writePacket(Index index, const PacketReturnType& x) const {
235  this->m_impl.template writePacket<StoreMode>(index, x);
236  }
237 
238  template <typename TensorBlock>
239  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void writeBlock(const TensorBlockDesc& desc, const TensorBlock& block) {
240  eigen_assert(this->m_impl.data() != NULL);
241 
242  typedef typename TensorBlock::XprType TensorBlockExpr;
243  typedef internal::TensorBlockAssignment<Scalar, TensorEvaluator::NumOutputDims, TensorBlockExpr, Index>
244  TensorBlockAssign;
245 
246  TensorBlockAssign::Run(TensorBlockAssign::target(desc.dimensions(), internal::strides<Layout>(this->dimensions()),
247  this->m_impl.data(), desc.offset()),
248  block.expr());
249  }
250 };
251 
259 namespace internal {
260 template <typename StartIndices, typename Sizes, typename XprType>
261 struct traits<TensorSlicingOp<StartIndices, Sizes, XprType>> : public traits<XprType> {
262  typedef typename XprType::Scalar Scalar;
263  typedef traits<XprType> XprTraits;
264  typedef typename XprTraits::StorageKind StorageKind;
265  typedef typename XprTraits::Index Index;
266  typedef typename XprType::Nested Nested;
267  typedef std::remove_reference_t<Nested> Nested_;
268  static constexpr int NumDimensions = array_size<StartIndices>::value;
269  static constexpr int Layout = XprTraits::Layout;
270  typedef typename XprTraits::PointerType PointerType;
271 };
272 
273 template <typename StartIndices, typename Sizes, typename XprType>
274 struct eval<TensorSlicingOp<StartIndices, Sizes, XprType>, Eigen::Dense> {
275  typedef const TensorSlicingOp<StartIndices, Sizes, XprType> EIGEN_DEVICE_REF type;
276 };
277 
278 template <typename StartIndices, typename Sizes, typename XprType>
279 struct nested<TensorSlicingOp<StartIndices, Sizes, XprType>, 1,
280  typename eval<TensorSlicingOp<StartIndices, Sizes, XprType>>::type> {
281  typedef TensorSlicingOp<StartIndices, Sizes, XprType> type;
282 };
283 
284 } // end namespace internal
285 
286 template <typename StartIndices, typename Sizes, typename XprType>
287 class TensorSlicingOp : public TensorBase<TensorSlicingOp<StartIndices, Sizes, XprType>> {
288  public:
289  typedef TensorBase<TensorSlicingOp<StartIndices, Sizes, XprType>> Base;
290  typedef typename Eigen::internal::traits<TensorSlicingOp>::Scalar Scalar;
291  typedef typename XprType::CoeffReturnType CoeffReturnType;
292  typedef typename Eigen::internal::nested<TensorSlicingOp>::type Nested;
293  typedef typename Eigen::internal::traits<TensorSlicingOp>::StorageKind StorageKind;
294  typedef typename Eigen::internal::traits<TensorSlicingOp>::Index Index;
295 
296  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorSlicingOp(const XprType& expr, const StartIndices& indices,
297  const Sizes& sizes)
298  : m_xpr(expr), m_indices(indices), m_sizes(sizes) {}
299 
300  EIGEN_DEVICE_FUNC const StartIndices& startIndices() const { return m_indices; }
301  EIGEN_DEVICE_FUNC const Sizes& sizes() const { return m_sizes; }
302 
303  EIGEN_DEVICE_FUNC const internal::remove_all_t<typename XprType::Nested>& expression() const { return m_xpr; }
304 
305  EIGEN_TENSOR_INHERIT_ASSIGNMENT_OPERATORS(TensorSlicingOp)
306 
307  protected:
308  typename XprType::Nested m_xpr;
309  const StartIndices m_indices;
310  const Sizes m_sizes;
311 };
312 
313 namespace internal {
314 
315 // Fixme: figure out the exact threshold
316 template <typename Index, typename Device, bool BlockAccess>
317 struct MemcpyTriggerForSlicing {
318  EIGEN_DEVICE_FUNC MemcpyTriggerForSlicing(const Device& device) : threshold_(2 * device.numThreads()) {}
319  EIGEN_DEVICE_FUNC bool operator()(Index total, Index contiguous) const {
320  const bool prefer_block_evaluation = BlockAccess && total > 32 * 1024;
321  return !prefer_block_evaluation && contiguous > threshold_;
322  }
323 
324  private:
325  Index threshold_;
326 };
327 
328 // It is very expensive to start the memcpy kernel on GPU: we therefore only
329 // use it for large copies.
330 #ifdef EIGEN_USE_GPU
331 template <typename Index, bool BlockAccess>
332 struct MemcpyTriggerForSlicing<Index, GpuDevice, BlockAccess> {
333  EIGEN_DEVICE_FUNC MemcpyTriggerForSlicing(const GpuDevice&) {}
334  EIGEN_DEVICE_FUNC bool operator()(Index, Index contiguous) const { return contiguous > 4 * 1024 * 1024; }
335 };
336 #endif
337 
338 // It is very expensive to start the memcpy kernel on GPU: we therefore only
339 // use it for large copies.
340 #ifdef EIGEN_USE_SYCL
341 template <typename Index, bool BlockAccess>
342 struct MemcpyTriggerForSlicing<Index, Eigen::SyclDevice, BlockAccess> {
343  EIGEN_DEVICE_FUNC MemcpyTriggerForSlicing(const SyclDevice&) {}
344  EIGEN_DEVICE_FUNC bool operator()(Index, Index contiguous) const { return contiguous > 4 * 1024 * 1024; }
345 };
346 #endif
347 
348 } // namespace internal
349 
350 // Eval as rvalue
351 template <typename StartIndices, typename Sizes, typename ArgType, typename Device>
352 struct TensorEvaluator<const TensorSlicingOp<StartIndices, Sizes, ArgType>, Device> {
353  typedef TensorSlicingOp<StartIndices, Sizes, ArgType> XprType;
354  static constexpr int NumDims = internal::array_size<Sizes>::value;
355 
356  typedef typename XprType::Index Index;
357  typedef typename XprType::Scalar Scalar;
358  typedef typename XprType::CoeffReturnType CoeffReturnType;
359  typedef typename PacketType<CoeffReturnType, Device>::type PacketReturnType;
360  typedef Sizes Dimensions;
361  typedef StorageMemory<CoeffReturnType, Device> Storage;
362  typedef StorageMemory<std::remove_const_t<CoeffReturnType>, Device> ConstCastStorage;
363  typedef typename Storage::Type EvaluatorPointerType;
364 
365  static constexpr int Layout = TensorEvaluator<ArgType, Device>::Layout;
366  enum {
367  // Alignment can't be guaranteed at compile time since it depends on the
368  // slice offsets and sizes.
369  IsAligned = false,
370  PacketAccess = TensorEvaluator<ArgType, Device>::PacketAccess,
371  BlockAccess = TensorEvaluator<ArgType, Device>::BlockAccess &&
372  // FIXME: Temporary workaround for bug in slicing of bool tensors.
373  !internal::is_same<std::remove_const_t<Scalar>, bool>::value,
374  PreferBlockAccess = true,
375  CoordAccess = false,
376  RawAccess = false
377  };
378 
379  typedef std::remove_const_t<Scalar> ScalarNoConst;
380 
381  //===- Tensor block evaluation strategy (see TensorBlock.h) -------------===//
382  typedef internal::TensorBlockDescriptor<NumDims, Index> TensorBlockDesc;
383  typedef internal::TensorBlockScratchAllocator<Device> TensorBlockScratch;
384 
385  // Tensor slicing does not change the block type.
386  typedef typename TensorEvaluator<const ArgType, Device>::TensorBlock TensorBlock;
387  //===--------------------------------------------------------------------===//
388 
389  EIGEN_STRONG_INLINE TensorEvaluator(const XprType& op, const Device& device)
390  : m_impl(op.expression(), device), m_device(device), m_dimensions(op.sizes()), m_offsets(op.startIndices()) {
391  m_is_identity = true;
392  for (int i = 0; i < internal::array_size<Dimensions>::value; ++i) {
393  eigen_assert(m_impl.dimensions()[i] >= op.sizes()[i] + op.startIndices()[i]);
394  if (m_impl.dimensions()[i] != op.sizes()[i] || op.startIndices()[i] != 0) {
395  m_is_identity = false;
396  }
397  }
398 
399  // No strides for scalars.
400  if (NumDims == 0) return;
401 
402  const typename TensorEvaluator<ArgType, Device>::Dimensions& input_dims = m_impl.dimensions();
403  const Sizes& output_dims = op.sizes();
404  if (static_cast<int>(Layout) == static_cast<int>(ColMajor)) {
405  m_inputStrides[0] = 1;
406  for (int i = 1; i < NumDims; ++i) {
407  m_inputStrides[i] = m_inputStrides[i - 1] * input_dims[i - 1];
408  }
409 
410  // Don't initialize m_fastOutputStrides[0] since it won't ever be accessed.
411  m_outputStrides[0] = 1;
412  for (int i = 1; i < NumDims; ++i) {
413  m_outputStrides[i] = m_outputStrides[i - 1] * output_dims[i - 1];
414  m_fastOutputStrides[i] = internal::TensorIntDivisor<Index>(m_outputStrides[i] > 0 ? m_outputStrides[i] : 1);
415  }
416  } else {
417  m_inputStrides[NumDims - 1] = 1;
418  for (int i = NumDims - 2; i >= 0; --i) {
419  m_inputStrides[i] = m_inputStrides[i + 1] * input_dims[i + 1];
420  }
421 
422  // Don't initialize m_fastOutputStrides[NumDims-1] since it won't ever be accessed.
423  m_outputStrides[NumDims - 1] = 1;
424  for (int i = NumDims - 2; i >= 0; --i) {
425  m_outputStrides[i] = m_outputStrides[i + 1] * output_dims[i + 1];
426  m_fastOutputStrides[i] = internal::TensorIntDivisor<Index>(m_outputStrides[i] > 0 ? m_outputStrides[i] : 1);
427  }
428  }
429  }
430 
431  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Dimensions& dimensions() const { return m_dimensions; }
432 
433  EIGEN_STRONG_INLINE bool evalSubExprsIfNeeded(EvaluatorPointerType data) {
434  m_impl.evalSubExprsIfNeeded(NULL);
435  if (!NumTraits<std::remove_const_t<Scalar>>::RequireInitialization && data && m_impl.data()) {
436  Index contiguous_values = 1;
437  if (static_cast<int>(Layout) == static_cast<int>(ColMajor)) {
438  for (int i = 0; i < NumDims; ++i) {
439  contiguous_values *= dimensions()[i];
440  if (dimensions()[i] != m_impl.dimensions()[i]) {
441  break;
442  }
443  }
444  } else {
445  for (int i = NumDims - 1; i >= 0; --i) {
446  contiguous_values *= dimensions()[i];
447  if (dimensions()[i] != m_impl.dimensions()[i]) {
448  break;
449  }
450  }
451  }
452  // Use memcpy if it's going to be faster than using the regular evaluation.
453  const internal::MemcpyTriggerForSlicing<Index, Device, BlockAccess> trigger(m_device);
454  if (trigger(internal::array_prod(dimensions()), contiguous_values)) {
455  EvaluatorPointerType src = (EvaluatorPointerType)m_impl.data();
456  for (Index i = 0; i < internal::array_prod(dimensions()); i += contiguous_values) {
457  Index offset = srcCoeff(i);
458  m_device.memcpy((void*)(m_device.get(data + i)), m_device.get(src + offset),
459  contiguous_values * sizeof(Scalar));
460  }
461  return false;
462  }
463  }
464  return true;
465  }
466 
467 #ifdef EIGEN_USE_THREADS
468  template <typename EvalSubExprsCallback>
469  EIGEN_STRONG_INLINE void evalSubExprsIfNeededAsync(EvaluatorPointerType /*data*/, EvalSubExprsCallback done) {
470  m_impl.evalSubExprsIfNeededAsync(nullptr, [done](bool) { done(true); });
471  }
472 #endif // EIGEN_USE_THREADS
473 
474  EIGEN_STRONG_INLINE void cleanup() { m_impl.cleanup(); }
475 
476  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(Index index) const {
477  if (m_is_identity) {
478  return m_impl.coeff(index);
479  } else {
480  return m_impl.coeff(srcCoeff(index));
481  }
482  }
483 
484  template <int LoadMode>
485  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketReturnType packet(Index index) const {
486  const int packetSize = PacketType<CoeffReturnType, Device>::size;
487  EIGEN_STATIC_ASSERT((packetSize > 1), YOU_MADE_A_PROGRAMMING_MISTAKE)
488  eigen_assert(index + packetSize - 1 < internal::array_prod(dimensions()));
489 
490  if (m_is_identity) {
491  return m_impl.template packet<LoadMode>(index);
492  }
493 
494  Index inputIndices[] = {0, 0};
495  Index indices[] = {index, index + packetSize - 1};
496  if (static_cast<int>(Layout) == static_cast<int>(ColMajor)) {
497  EIGEN_UNROLL_LOOP
498  for (int i = NumDims - 1; i > 0; --i) {
499  const Index idx0 = indices[0] / m_fastOutputStrides[i];
500  const Index idx1 = indices[1] / m_fastOutputStrides[i];
501  inputIndices[0] += (idx0 + m_offsets[i]) * m_inputStrides[i];
502  inputIndices[1] += (idx1 + m_offsets[i]) * m_inputStrides[i];
503  indices[0] -= idx0 * m_outputStrides[i];
504  indices[1] -= idx1 * m_outputStrides[i];
505  }
506  inputIndices[0] += (indices[0] + m_offsets[0]);
507  inputIndices[1] += (indices[1] + m_offsets[0]);
508  } else {
509  EIGEN_UNROLL_LOOP
510  for (int i = 0; i < NumDims - 1; ++i) {
511  const Index idx0 = indices[0] / m_fastOutputStrides[i];
512  const Index idx1 = indices[1] / m_fastOutputStrides[i];
513  inputIndices[0] += (idx0 + m_offsets[i]) * m_inputStrides[i];
514  inputIndices[1] += (idx1 + m_offsets[i]) * m_inputStrides[i];
515  indices[0] -= idx0 * m_outputStrides[i];
516  indices[1] -= idx1 * m_outputStrides[i];
517  }
518  inputIndices[0] += (indices[0] + m_offsets[NumDims - 1]);
519  inputIndices[1] += (indices[1] + m_offsets[NumDims - 1]);
520  }
521  if (inputIndices[1] - inputIndices[0] == packetSize - 1) {
522  PacketReturnType rslt = m_impl.template packet<Unaligned>(inputIndices[0]);
523  return rslt;
524  } else {
525  EIGEN_ALIGN_MAX std::remove_const_t<CoeffReturnType> values[packetSize];
526  values[0] = m_impl.coeff(inputIndices[0]);
527  values[packetSize - 1] = m_impl.coeff(inputIndices[1]);
528  EIGEN_UNROLL_LOOP
529  for (int i = 1; i < packetSize - 1; ++i) {
530  values[i] = coeff(index + i);
531  }
532  PacketReturnType rslt = internal::pload<PacketReturnType>(values);
533  return rslt;
534  }
535  }
536 
537  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorOpCost costPerCoeff(bool vectorized) const {
538  return m_impl.costPerCoeff(vectorized) + TensorOpCost(0, 0, m_is_identity ? 1 : NumDims);
539  }
540 
541  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE internal::TensorBlockResourceRequirements getResourceRequirements() const {
542  const size_t target_size = m_device.lastLevelCacheSize();
543  return internal::TensorBlockResourceRequirements::merge(
544  internal::TensorBlockResourceRequirements::skewed<Scalar>(target_size), m_impl.getResourceRequirements());
545  }
546 
547  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorBlock block(TensorBlockDesc& desc, TensorBlockScratch& scratch,
548  bool /*root_of_expr_ast*/ = false) const {
549  TensorBlockDesc arg_desc = desc.WithOffset(srcCoeff(desc.offset()));
550  TensorBlock block = m_impl.block(arg_desc, scratch);
551  if (!arg_desc.HasDestinationBuffer()) desc.DropDestinationBuffer();
552  return block;
553  }
554 
555  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE typename Storage::Type data() const {
556  typename Storage::Type result = constCast(m_impl.data());
557  if (result) {
558  Index offset = 0;
559  if (static_cast<int>(Layout) == static_cast<int>(ColMajor)) {
560  for (int i = 0; i < NumDims; ++i) {
561  if (m_dimensions[i] != m_impl.dimensions()[i]) {
562  offset += m_offsets[i] * m_inputStrides[i];
563  for (int j = i + 1; j < NumDims; ++j) {
564  if (m_dimensions[j] > 1) {
565  return NULL;
566  }
567  offset += m_offsets[j] * m_inputStrides[j];
568  }
569  break;
570  }
571  }
572  } else {
573  for (int i = NumDims - 1; i >= 0; --i) {
574  if (m_dimensions[i] != m_impl.dimensions()[i]) {
575  offset += m_offsets[i] * m_inputStrides[i];
576  for (int j = i - 1; j >= 0; --j) {
577  if (m_dimensions[j] > 1) {
578  return NULL;
579  }
580  offset += m_offsets[j] * m_inputStrides[j];
581  }
582  break;
583  }
584  }
585  }
586  return result + offset;
587  }
588  return NULL;
589  }
590 
591  protected:
592  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index srcCoeff(Index index) const {
593  Index inputIndex = 0;
594  if (static_cast<int>(Layout) == static_cast<int>(ColMajor)) {
595  EIGEN_UNROLL_LOOP
596  for (int i = NumDims - 1; i > 0; --i) {
597  const Index idx = index / m_fastOutputStrides[i];
598  inputIndex += (idx + m_offsets[i]) * m_inputStrides[i];
599  index -= idx * m_outputStrides[i];
600  }
601  inputIndex += (index + m_offsets[0]);
602  } else {
603  EIGEN_UNROLL_LOOP
604  for (int i = 0; i < NumDims - 1; ++i) {
605  const Index idx = index / m_fastOutputStrides[i];
606  inputIndex += (idx + m_offsets[i]) * m_inputStrides[i];
607  index -= idx * m_outputStrides[i];
608  }
609  inputIndex += (index + m_offsets[NumDims - 1]);
610  }
611  return inputIndex;
612  }
613 
614  array<Index, NumDims> m_outputStrides;
615  array<internal::TensorIntDivisor<Index>, NumDims> m_fastOutputStrides;
616  array<Index, NumDims> m_inputStrides;
617  TensorEvaluator<ArgType, Device> m_impl;
618  const Device EIGEN_DEVICE_REF m_device;
619  Dimensions m_dimensions;
620  bool m_is_identity;
621  const StartIndices m_offsets;
622 };
623 
624 // Eval as lvalue
625 template <typename StartIndices, typename Sizes, typename ArgType, typename Device>
626 struct TensorEvaluator<TensorSlicingOp<StartIndices, Sizes, ArgType>, Device>
627  : public TensorEvaluator<const TensorSlicingOp<StartIndices, Sizes, ArgType>, Device> {
628  typedef TensorEvaluator<const TensorSlicingOp<StartIndices, Sizes, ArgType>, Device> Base;
629  typedef TensorSlicingOp<StartIndices, Sizes, ArgType> XprType;
630  static constexpr int NumDims = internal::array_size<Sizes>::value;
631 
632  typedef typename XprType::Index Index;
633  typedef typename XprType::Scalar Scalar;
634  typedef typename XprType::CoeffReturnType CoeffReturnType;
635  typedef typename PacketType<CoeffReturnType, Device>::type PacketReturnType;
636  typedef Sizes Dimensions;
637 
638  static constexpr int Layout = TensorEvaluator<ArgType, Device>::Layout;
639  enum {
640  IsAligned = false,
641  PacketAccess = TensorEvaluator<ArgType, Device>::PacketAccess,
642  BlockAccess = TensorEvaluator<ArgType, Device>::BlockAccess,
643  PreferBlockAccess = true,
644  CoordAccess = false,
645  RawAccess = (NumDims == 1) & TensorEvaluator<ArgType, Device>::RawAccess
646  };
647 
648  typedef std::remove_const_t<Scalar> ScalarNoConst;
649 
650  //===- Tensor block evaluation strategy (see TensorBlock.h) -------------===//
651  typedef internal::TensorBlockDescriptor<NumDims, Index> TensorBlockDesc;
652  typedef internal::TensorBlockScratchAllocator<Device> TensorBlockScratch;
653  //===--------------------------------------------------------------------===//
654 
655  EIGEN_STRONG_INLINE TensorEvaluator(const XprType& op, const Device& device) : Base(op, device) {}
656 
657  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType& coeffRef(Index index) const {
658  if (this->m_is_identity) {
659  return this->m_impl.coeffRef(index);
660  } else {
661  return this->m_impl.coeffRef(this->srcCoeff(index));
662  }
663  }
664 
665  template <int StoreMode>
666  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void writePacket(Index index, const PacketReturnType& x) const {
667  if (this->m_is_identity) {
668  this->m_impl.template writePacket<StoreMode>(index, x);
669  return;
670  }
671 
672  const int packetSize = PacketType<CoeffReturnType, Device>::size;
673  Index inputIndices[] = {0, 0};
674  Index indices[] = {index, index + packetSize - 1};
675  if (static_cast<int>(Layout) == static_cast<int>(ColMajor)) {
676  EIGEN_UNROLL_LOOP
677  for (int i = NumDims - 1; i > 0; --i) {
678  const Index idx0 = indices[0] / this->m_fastOutputStrides[i];
679  const Index idx1 = indices[1] / this->m_fastOutputStrides[i];
680  inputIndices[0] += (idx0 + this->m_offsets[i]) * this->m_inputStrides[i];
681  inputIndices[1] += (idx1 + this->m_offsets[i]) * this->m_inputStrides[i];
682  indices[0] -= idx0 * this->m_outputStrides[i];
683  indices[1] -= idx1 * this->m_outputStrides[i];
684  }
685  inputIndices[0] += (indices[0] + this->m_offsets[0]);
686  inputIndices[1] += (indices[1] + this->m_offsets[0]);
687  } else {
688  EIGEN_UNROLL_LOOP
689  for (int i = 0; i < NumDims - 1; ++i) {
690  const Index idx0 = indices[0] / this->m_fastOutputStrides[i];
691  const Index idx1 = indices[1] / this->m_fastOutputStrides[i];
692  inputIndices[0] += (idx0 + this->m_offsets[i]) * this->m_inputStrides[i];
693  inputIndices[1] += (idx1 + this->m_offsets[i]) * this->m_inputStrides[i];
694  indices[0] -= idx0 * this->m_outputStrides[i];
695  indices[1] -= idx1 * this->m_outputStrides[i];
696  }
697  inputIndices[0] += (indices[0] + this->m_offsets[NumDims - 1]);
698  inputIndices[1] += (indices[1] + this->m_offsets[NumDims - 1]);
699  }
700  if (inputIndices[1] - inputIndices[0] == packetSize - 1) {
701  this->m_impl.template writePacket<StoreMode>(inputIndices[0], x);
702  } else {
703  EIGEN_ALIGN_MAX CoeffReturnType values[packetSize];
704  internal::pstore<CoeffReturnType, PacketReturnType>(values, x);
705  this->m_impl.coeffRef(inputIndices[0]) = values[0];
706  this->m_impl.coeffRef(inputIndices[1]) = values[packetSize - 1];
707  EIGEN_UNROLL_LOOP
708  for (int i = 1; i < packetSize - 1; ++i) {
709  this->coeffRef(index + i) = values[i];
710  }
711  }
712  }
713 
714  template <typename TensorBlock>
715  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void writeBlock(const TensorBlockDesc& desc, const TensorBlock& block) {
716  TensorBlockDesc arg_desc = desc.WithOffset(this->srcCoeff(desc.offset()));
717  this->m_impl.writeBlock(arg_desc, block);
718  }
719 };
720 
721 namespace internal {
722 template <typename StartIndices, typename StopIndices, typename Strides, typename XprType>
723 struct traits<TensorStridingSlicingOp<StartIndices, StopIndices, Strides, XprType>> : public traits<XprType> {
724  typedef typename XprType::Scalar Scalar;
725  typedef traits<XprType> XprTraits;
726  typedef typename XprTraits::StorageKind StorageKind;
727  typedef typename XprTraits::Index Index;
728  typedef typename XprType::Nested Nested;
729  typedef std::remove_reference_t<Nested> Nested_;
730  static constexpr int NumDimensions = array_size<StartIndices>::value;
731  static constexpr int Layout = XprTraits::Layout;
732  typedef typename XprTraits::PointerType PointerType;
733 };
734 
735 template <typename StartIndices, typename StopIndices, typename Strides, typename XprType>
736 struct eval<TensorStridingSlicingOp<StartIndices, StopIndices, Strides, XprType>, Eigen::Dense> {
737  typedef const TensorStridingSlicingOp<StartIndices, StopIndices, Strides, XprType> EIGEN_DEVICE_REF type;
738 };
739 
740 template <typename StartIndices, typename StopIndices, typename Strides, typename XprType>
741 struct nested<TensorStridingSlicingOp<StartIndices, StopIndices, Strides, XprType>, 1,
742  typename eval<TensorStridingSlicingOp<StartIndices, StopIndices, Strides, XprType>>::type> {
743  typedef TensorStridingSlicingOp<StartIndices, StopIndices, Strides, XprType> type;
744 };
745 
746 } // end namespace internal
747 
748 template <typename StartIndices, typename StopIndices, typename Strides, typename XprType>
749 class TensorStridingSlicingOp
750  : public TensorBase<TensorStridingSlicingOp<StartIndices, StopIndices, Strides, XprType>> {
751  public:
752  typedef TensorBase<TensorStridingSlicingOp<StartIndices, StopIndices, Strides, XprType>> Base;
753  typedef typename internal::traits<TensorStridingSlicingOp>::Scalar Scalar;
754  typedef typename XprType::CoeffReturnType CoeffReturnType;
755  typedef typename internal::nested<TensorStridingSlicingOp>::type Nested;
756  typedef typename internal::traits<TensorStridingSlicingOp>::StorageKind StorageKind;
757  typedef typename internal::traits<TensorStridingSlicingOp>::Index Index;
758 
759  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorStridingSlicingOp(const XprType& expr, const StartIndices& startIndices,
760  const StopIndices& stopIndices, const Strides& strides)
761  : m_xpr(expr), m_startIndices(startIndices), m_stopIndices(stopIndices), m_strides(strides) {}
762 
763  EIGEN_DEVICE_FUNC const StartIndices& startIndices() const { return m_startIndices; }
764  EIGEN_DEVICE_FUNC const StartIndices& stopIndices() const { return m_stopIndices; }
765  EIGEN_DEVICE_FUNC const StartIndices& strides() const { return m_strides; }
766 
767  EIGEN_DEVICE_FUNC const internal::remove_all_t<typename XprType::Nested>& expression() const { return m_xpr; }
768 
769  EIGEN_TENSOR_INHERIT_ASSIGNMENT_OPERATORS(TensorStridingSlicingOp)
770 
771  protected:
772  typename XprType::Nested m_xpr;
773  const StartIndices m_startIndices;
774  const StopIndices m_stopIndices;
775  const Strides m_strides;
776 };
777 
778 // Eval as rvalue
779 template <typename StartIndices, typename StopIndices, typename Strides, typename ArgType, typename Device>
780 struct TensorEvaluator<const TensorStridingSlicingOp<StartIndices, StopIndices, Strides, ArgType>, Device> {
781  typedef TensorStridingSlicingOp<StartIndices, StopIndices, Strides, ArgType> XprType;
782  static constexpr int NumDims = internal::array_size<Strides>::value;
783  typedef typename XprType::Index Index;
784  typedef typename XprType::Scalar Scalar;
785  typedef typename XprType::CoeffReturnType CoeffReturnType;
786  typedef typename PacketType<CoeffReturnType, Device>::type PacketReturnType;
787  typedef StorageMemory<CoeffReturnType, Device> Storage;
788  typedef typename Storage::Type EvaluatorPointerType;
789  typedef Strides Dimensions;
790 
791  static constexpr int Layout = TensorEvaluator<ArgType, Device>::Layout;
792  enum {
793  // Alignment can't be guaranteed at compile time since it depends on the
794  // slice offsets and sizes.
795  IsAligned = false,
796  PacketAccess = false,
797  BlockAccess = false,
798  PreferBlockAccess = TensorEvaluator<ArgType, Device>::PreferBlockAccess,
799  RawAccess = false
800  };
801 
802  //===- Tensor block evaluation strategy (see TensorBlock.h) -------------===//
803  typedef internal::TensorBlockNotImplemented TensorBlock;
804  //===--------------------------------------------------------------------===//
805 
806  EIGEN_STRONG_INLINE TensorEvaluator(const XprType& op, const Device& device)
807  : m_impl(op.expression(), device), m_device(device), m_strides(op.strides()) {
808  // Handle degenerate intervals by gracefully clamping and allowing m_dimensions to be zero
809  DSizes<Index, NumDims> startIndicesClamped, stopIndicesClamped;
810  for (ptrdiff_t i = 0; i < internal::array_size<Dimensions>::value; ++i) {
811  eigen_assert(m_strides[i] != 0 && "0 stride is invalid");
812  if (m_strides[i] > 0) {
813  startIndicesClamped[i] = clamp(op.startIndices()[i], 0, m_impl.dimensions()[i]);
814  stopIndicesClamped[i] = clamp(op.stopIndices()[i], 0, m_impl.dimensions()[i]);
815  } else {
816  /* implies m_strides[i] < 0 by assert */
817  startIndicesClamped[i] = clamp(op.startIndices()[i], -1, m_impl.dimensions()[i] - 1);
818  stopIndicesClamped[i] = clamp(op.stopIndices()[i], -1, m_impl.dimensions()[i] - 1);
819  }
820  m_startIndices[i] = startIndicesClamped[i];
821  }
822 
823  typedef typename TensorEvaluator<ArgType, Device>::Dimensions InputDimensions;
824  const InputDimensions& input_dims = m_impl.dimensions();
825 
826  // compute output tensor shape
827  m_is_identity = true;
828  for (int i = 0; i < NumDims; i++) {
829  Index interval = stopIndicesClamped[i] - startIndicesClamped[i];
830  if (interval == 0 || ((interval < 0) != (m_strides[i] < 0))) {
831  m_dimensions[i] = 0;
832  } else {
833  m_dimensions[i] = (interval / m_strides[i]) + (interval % m_strides[i] != 0 ? 1 : 0);
834  eigen_assert(m_dimensions[i] >= 0);
835  }
836  if (m_strides[i] != 1 || interval != m_impl.dimensions()[i]) {
837  m_is_identity = false;
838  }
839  }
840 
841  Strides output_dims = m_dimensions;
842 
843  if (static_cast<int>(Layout) == static_cast<int>(ColMajor)) {
844  m_inputStrides[0] = m_strides[0];
845  m_offsets[0] = startIndicesClamped[0];
846  Index previousDimProduct = 1;
847  for (int i = 1; i < NumDims; ++i) {
848  previousDimProduct *= input_dims[i - 1];
849  m_inputStrides[i] = previousDimProduct * m_strides[i];
850  m_offsets[i] = startIndicesClamped[i] * previousDimProduct;
851  }
852 
853  // Don't initialize m_fastOutputStrides[0] since it won't ever be accessed.
854  m_outputStrides[0] = 1;
855  for (int i = 1; i < NumDims; ++i) {
856  m_outputStrides[i] = m_outputStrides[i - 1] * output_dims[i - 1];
857  m_fastOutputStrides[i] = internal::TensorIntDivisor<Index>(m_outputStrides[i] > 0 ? m_outputStrides[i] : 1);
858  }
859  } else {
860  m_inputStrides[NumDims - 1] = m_strides[NumDims - 1];
861  m_offsets[NumDims - 1] = startIndicesClamped[NumDims - 1];
862  Index previousDimProduct = 1;
863  for (int i = NumDims - 2; i >= 0; --i) {
864  previousDimProduct *= input_dims[i + 1];
865  m_inputStrides[i] = previousDimProduct * m_strides[i];
866  m_offsets[i] = startIndicesClamped[i] * previousDimProduct;
867  }
868 
869  m_outputStrides[NumDims - 1] = 1;
870  for (int i = NumDims - 2; i >= 0; --i) {
871  m_outputStrides[i] = m_outputStrides[i + 1] * output_dims[i + 1];
872  m_fastOutputStrides[i] = internal::TensorIntDivisor<Index>(m_outputStrides[i] > 0 ? m_outputStrides[i] : 1);
873  }
874  }
875  }
876 
877  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Dimensions& dimensions() const { return m_dimensions; }
878 
879  EIGEN_STRONG_INLINE bool evalSubExprsIfNeeded(EvaluatorPointerType) {
880  m_impl.evalSubExprsIfNeeded(NULL);
881  return true;
882  }
883 
884  EIGEN_STRONG_INLINE void cleanup() { m_impl.cleanup(); }
885 
886  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(Index index) const {
887  if (m_is_identity) {
888  return m_impl.coeff(index);
889  } else {
890  return m_impl.coeff(srcCoeff(index));
891  }
892  }
893 
894  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorOpCost costPerCoeff(bool vectorized) const {
895  return m_impl.costPerCoeff(vectorized) + TensorOpCost(0, 0, m_is_identity ? 1 : NumDims);
896  }
897 
898  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE typename Storage::Type data() const { return NULL; }
899 
900  protected:
901  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index srcCoeff(Index index) const {
902  Index inputIndex = 0;
903  if (static_cast<int>(Layout) == static_cast<int>(ColMajor)) {
904  EIGEN_UNROLL_LOOP
905  for (int i = NumDims - 1; i >= 0; --i) {
906  const Index idx = index / m_fastOutputStrides[i];
907  inputIndex += idx * m_inputStrides[i] + m_offsets[i];
908  index -= idx * m_outputStrides[i];
909  }
910  } else {
911  EIGEN_UNROLL_LOOP
912  for (int i = 0; i < NumDims; ++i) {
913  const Index idx = index / m_fastOutputStrides[i];
914  inputIndex += idx * m_inputStrides[i] + m_offsets[i];
915  index -= idx * m_outputStrides[i];
916  }
917  }
918  return inputIndex;
919  }
920 
921  static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index clamp(Index value, Index min, Index max) {
922 #ifndef SYCL_DEVICE_ONLY
923  return numext::maxi(min, numext::mini(max, value));
924 #else
925  return cl::sycl::clamp(value, min, max);
926 #endif
927  }
928 
929  array<Index, NumDims> m_outputStrides;
930  array<internal::TensorIntDivisor<Index>, NumDims> m_fastOutputStrides;
931  array<Index, NumDims> m_inputStrides;
932  bool m_is_identity;
933  TensorEvaluator<ArgType, Device> m_impl;
934  const Device EIGEN_DEVICE_REF m_device;
935  DSizes<Index, NumDims> m_startIndices; // clamped startIndices
936  DSizes<Index, NumDims> m_dimensions;
937  DSizes<Index, NumDims> m_offsets; // offset in a flattened shape
938  const Strides m_strides;
939 };
940 
941 // Eval as lvalue
942 template <typename StartIndices, typename StopIndices, typename Strides, typename ArgType, typename Device>
943 struct TensorEvaluator<TensorStridingSlicingOp<StartIndices, StopIndices, Strides, ArgType>, Device>
944  : public TensorEvaluator<const TensorStridingSlicingOp<StartIndices, StopIndices, Strides, ArgType>, Device> {
945  typedef TensorEvaluator<const TensorStridingSlicingOp<StartIndices, StopIndices, Strides, ArgType>, Device> Base;
946  typedef TensorStridingSlicingOp<StartIndices, StopIndices, Strides, ArgType> XprType;
947  static constexpr int NumDims = internal::array_size<Strides>::value;
948  static constexpr int Layout = TensorEvaluator<ArgType, Device>::Layout;
949 
950  enum {
951  IsAligned = false,
952  PacketAccess = false,
953  BlockAccess = false,
954  PreferBlockAccess = TensorEvaluator<ArgType, Device>::PreferBlockAccess,
955  CoordAccess = TensorEvaluator<ArgType, Device>::CoordAccess,
956  RawAccess = false
957  };
958 
959  //===- Tensor block evaluation strategy (see TensorBlock.h) -------------===//
960  typedef internal::TensorBlockNotImplemented TensorBlock;
961  //===--------------------------------------------------------------------===//
962 
963  EIGEN_STRONG_INLINE TensorEvaluator(const XprType& op, const Device& device) : Base(op, device) {}
964 
965  typedef typename XprType::Index Index;
966  typedef typename XprType::Scalar Scalar;
967  typedef typename XprType::CoeffReturnType CoeffReturnType;
968  typedef typename PacketType<CoeffReturnType, Device>::type PacketReturnType;
969  typedef Strides Dimensions;
970 
971  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType& coeffRef(Index index) const {
972  if (this->m_is_identity) {
973  return this->m_impl.coeffRef(index);
974  } else {
975  return this->m_impl.coeffRef(this->srcCoeff(index));
976  }
977  }
978 };
979 
980 } // end namespace Eigen
981 
982 #endif // EIGEN_CXX11_TENSOR_TENSOR_MORPHING_H
WriteAccessors
Namespace containing all symbols from the Eigen library.
EIGEN_DEFAULT_DENSE_INDEX_TYPE Index