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