10#ifndef EIGEN_CXX11_TENSOR_TENSOR_CONTRACTION_MAPPER_H
11#define EIGEN_CXX11_TENSOR_TENSOR_CONTRACTION_MAPPER_H
14#include "./InternalHeaderCheck.h"
20enum { Rhs = 0, Lhs = 1 };
27template <
typename Tensor,
bool HasRawAccess,
template <
class>
class MakePointer_ = MakePointer>
30template <
typename Scalar,
typename Index,
int side,
typename Tensor,
typename nocontract_t,
typename contract_t,
31 int packet_size,
bool inner_dim_contiguous,
bool inner_dim_reordered,
int Alignment,
32 template <
class>
class MakePointer_ = MakePointer>
33class BaseTensorContractionMapper;
35template <
typename Tensor,
bool HasRawAccess,
template <
class>
class MakePointer_>
37 enum { DirectOffsets =
false };
39 EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE CoeffLoader(
const Tensor& tensor) : m_tensor(tensor) {}
41 EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE
void offsetBuffer(
typename Tensor::Index) {
42 eigen_assert(
false &&
"unsupported");
45 EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE
const typename MakePointer_<const typename Tensor::Scalar>::Type data()
const {
46 eigen_assert(
false &&
"unsupported");
50 EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE
typename Tensor::Scalar coeff(
typename Tensor::Index index)
const {
51 return m_tensor.coeff(index);
54 template <
int LoadMode>
55 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
typename Tensor::PacketReturnType packet(
typename Tensor::Index index)
const {
56 return m_tensor.template packet<LoadMode>(index);
63template <
typename Tensor,
template <
class>
class MakePointer_>
65 enum { DirectOffsets =
true };
67 EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE CoeffLoader(
const Tensor& tensor) : m_data(tensor.data()) {}
69 EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE
void offsetBuffer(
typename Tensor::Index offset) { m_data += offset; }
71 EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE
const typename MakePointer_<const typename Tensor::Scalar>::Type data()
const {
75 EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE
typename Tensor::Scalar coeff(
typename Tensor::Index index)
const {
76 return loadConstant(m_data + index);
79 template <
int LoadMode>
80 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
typename Tensor::PacketReturnType packet(
typename Tensor::Index index)
const {
81 return internal::ploadt_ro<typename Tensor::PacketReturnType, LoadMode>(m_data + index);
85 typedef typename Tensor::Scalar Scalar;
87 typename MakePointer_<const Scalar>::Type m_data;
90template <
typename Scalar,
typename Index,
int side,
typename Tensor,
typename nocontract_t,
typename contract_t,
91 int packet_size,
bool inner_dim_contiguous,
int Alignment,
template <
class>
class MakePointer_ = MakePointer>
92class SimpleTensorContractionMapper {
94 EIGEN_DEVICE_FUNC SimpleTensorContractionMapper(
const Tensor& tensor,
const nocontract_t& nocontract_strides,
95 const nocontract_t& ij_strides,
const contract_t& contract_strides,
96 const contract_t& k_strides)
98 m_nocontract_strides(nocontract_strides),
99 m_ij_strides(ij_strides),
100 m_contract_strides(contract_strides),
101 m_k_strides(k_strides) {}
103 enum { DirectOffsets = CoeffLoader<Tensor, Tensor::RawAccess, MakePointer_>::DirectOffsets };
105 EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE
void offsetBuffer(
typename Tensor::Index offset) {
106 m_tensor.offsetBuffer(offset);
109 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
void prefetch(
Index ) {}
111 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar operator()(
Index row)
const {
113 return operator()(row, 0);
116 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar operator()(
Index row,
Index col)
const {
117 return m_tensor.coeff(computeIndex(row, col));
120#ifdef EIGEN_MULTIDIMENSIONAL_SUBSCRIPT
121 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar operator[](
Index row,
Index col)
const {
return operator()(row, col); }
124 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
Index computeIndex(
Index row,
Index col)
const {
125 const bool left = (side == Lhs);
126 EIGEN_UNUSED_VARIABLE(left);
127 Index nocontract_val = left ? row : col;
130 for (
int i =
static_cast<int>(array_size<nocontract_t>::value) - 1; i > 0; i--) {
131 const Index idx = nocontract_val / m_ij_strides[i];
132 linidx += idx * m_nocontract_strides[i];
133 nocontract_val -= idx * m_ij_strides[i];
135 if (array_size<typename Tensor::Dimensions>::value > array_size<contract_t>::value) {
136 if (side == Lhs && inner_dim_contiguous) {
137 eigen_assert(m_nocontract_strides[0] == 1);
138 linidx += nocontract_val;
140 linidx += nocontract_val * m_nocontract_strides[0];
144 Index contract_val = left ? col : row;
145 if (array_size<contract_t>::value > 0) {
147 for (
int i =
static_cast<int>(array_size<contract_t>::value) - 1; i > 0; i--) {
148 const Index idx = contract_val / m_k_strides[i];
149 linidx += idx * m_contract_strides[i];
150 contract_val -= idx * m_k_strides[i];
153 if (side == Rhs && inner_dim_contiguous) {
154 eigen_assert(m_contract_strides[0] == 1);
155 linidx += contract_val;
157 linidx += contract_val * m_contract_strides[0];
164 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE IndexPair<Index> computeIndexPair(
Index row,
Index col,
165 const Index distance)
const {
166 const bool left = (side == Lhs);
167 EIGEN_UNUSED_VARIABLE(left);
168 Index nocontract_val[2] = {left ? row : col, left ? row + distance : col};
169 Index linidx[2] = {0, 0};
170 if (array_size<typename Tensor::Dimensions>::value > array_size<contract_t>::value) {
172 for (
int i =
static_cast<int>(array_size<nocontract_t>::value) - 1; i > 0; i--) {
173 const Index idx0 = nocontract_val[0] / m_ij_strides[i];
174 const Index idx1 = nocontract_val[1] / m_ij_strides[i];
175 linidx[0] += idx0 * m_nocontract_strides[i];
176 linidx[1] += idx1 * m_nocontract_strides[i];
177 nocontract_val[0] -= idx0 * m_ij_strides[i];
178 nocontract_val[1] -= idx1 * m_ij_strides[i];
180 if (side == Lhs && inner_dim_contiguous) {
181 eigen_assert(m_nocontract_strides[0] == 1);
182 linidx[0] += nocontract_val[0];
183 linidx[1] += nocontract_val[1];
185 linidx[0] += nocontract_val[0] * m_nocontract_strides[0];
186 linidx[1] += nocontract_val[1] * m_nocontract_strides[0];
190 Index contract_val[2] = {left ? col : row, left ? col : row + distance};
191 if (array_size<contract_t>::value > 0) {
193 for (
int i =
static_cast<int>(array_size<contract_t>::value) - 1; i > 0; i--) {
194 const Index idx0 = contract_val[0] / m_k_strides[i];
195 const Index idx1 = contract_val[1] / m_k_strides[i];
196 linidx[0] += idx0 * m_contract_strides[i];
197 linidx[1] += idx1 * m_contract_strides[i];
198 contract_val[0] -= idx0 * m_k_strides[i];
199 contract_val[1] -= idx1 * m_k_strides[i];
202 if (side == Rhs && inner_dim_contiguous) {
203 eigen_assert(m_contract_strides[0] == 1);
204 linidx[0] += contract_val[0];
205 linidx[1] += contract_val[1];
207 linidx[0] += contract_val[0] * m_contract_strides[0];
208 linidx[1] += contract_val[1] * m_contract_strides[0];
211 return IndexPair<Index>(linidx[0], linidx[1]);
214 EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE
Index firstAligned(
Index size)
const {
218 return (Alignment ==
Aligned) && (side == Lhs) && inner_dim_contiguous ? 0 : size;
220 EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE
Index stride()
const {
221 return ((side == Lhs) && inner_dim_contiguous && array_size<contract_t>::value > 0) ? m_contract_strides[0] : 1;
224 const CoeffLoader<Tensor, Tensor::RawAccess, MakePointer_>& tensor()
const {
return m_tensor; }
226 const nocontract_t& nocontract_strides()
const {
return m_nocontract_strides; }
227 const nocontract_t& ij_strides()
const {
return m_ij_strides; }
228 const contract_t& contract_strides()
const {
return m_contract_strides; }
229 const contract_t& k_strides()
const {
return m_k_strides; }
232 CoeffLoader<Tensor, Tensor::RawAccess, MakePointer_> m_tensor;
233 const nocontract_t m_nocontract_strides;
234 const nocontract_t m_ij_strides;
235 const contract_t m_contract_strides;
236 const contract_t m_k_strides;
239template <
typename Scalar,
typename Index,
int side,
typename Tensor,
typename nocontract_t,
typename contract_t,
240 int packet_size,
bool inner_dim_contiguous,
bool inner_dim_reordered,
int Alignment,
241 template <
class>
class MakePointer_>
242class BaseTensorContractionMapper
243 :
public SimpleTensorContractionMapper<Scalar, Index, side, Tensor, nocontract_t, contract_t, packet_size,
244 inner_dim_contiguous, Alignment, MakePointer_> {
246 typedef SimpleTensorContractionMapper<Scalar,
Index, side, Tensor, nocontract_t, contract_t, packet_size,
247 inner_dim_contiguous, Alignment, MakePointer_>
250 EIGEN_DEVICE_FUNC BaseTensorContractionMapper(
const Tensor& tensor,
const nocontract_t& nocontract_strides,
251 const nocontract_t& ij_strides,
const contract_t& contract_strides,
252 const contract_t& k_strides)
253 : ParentMapper(tensor, nocontract_strides, ij_strides, contract_strides, k_strides) {}
255 template <
typename PacketT,
int AlignmentType>
256 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
257 std::enable_if_t<internal::unpacket_traits<PacketT>::size == packet_size, PacketT>
263 EIGEN_STATIC_ASSERT(packet_size % 2 == 0, YOU_MADE_A_PROGRAMMING_MISTAKE);
265 if (Tensor::PacketAccess && inner_dim_contiguous && !inner_dim_reordered) {
266 const Index index = this->computeIndex(i, j);
267 eigen_assert(this->computeIndex(i + packet_size - 1, j) == index + packet_size - 1);
268 return this->m_tensor.template packet<AlignmentType>(index);
271 const IndexPair<Index> indexPair = this->computeIndexPair(i, j, packet_size - 1);
272 const Index first = indexPair.first;
273 const Index lastIdx = indexPair.second;
279 if (Tensor::PacketAccess && (side == Lhs || internal::array_size<contract_t>::value <= 1 || !inner_dim_reordered) &&
280 (lastIdx - first) == (packet_size - 1)) {
281 return this->m_tensor.template packet<AlignmentType>(first);
284 EIGEN_ALIGN_MAX Scalar data[packet_size];
286 data[0] = this->m_tensor.coeff(first);
288 for (
Index k = 1; k < packet_size - 1; k += 2) {
289 const IndexPair<Index> internal_pair = this->computeIndexPair(i + k, j, 1);
290 data[k] = this->m_tensor.coeff(internal_pair.first);
291 data[k + 1] = this->m_tensor.coeff(internal_pair.second);
293 data[packet_size - 1] = this->m_tensor.coeff(lastIdx);
295 return pload<PacketT>(data);
298 template <
typename PacketT,
int AlignmentType>
299 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
300 std::enable_if_t<internal::unpacket_traits<PacketT>::size != packet_size, PacketT>
302 const Index requested_packet_size = internal::unpacket_traits<PacketT>::size;
303 EIGEN_ALIGN_MAX Scalar data[requested_packet_size];
305 const IndexPair<Index> indexPair = this->computeIndexPair(i, j, requested_packet_size - 1);
306 const Index first = indexPair.first;
307 const Index lastIdx = indexPair.second;
309 data[0] = this->m_tensor.coeff(first);
310 for (
Index k = 1; k < requested_packet_size - 1; k += 2) {
311 const IndexPair<Index> internal_pair = this->computeIndexPair(i + k, j, 1);
312 data[k] = this->m_tensor.coeff(internal_pair.first);
313 data[k + 1] = this->m_tensor.coeff(internal_pair.second);
315 data[requested_packet_size - 1] = this->m_tensor.coeff(lastIdx);
317 return pload<PacketT>(data);
320 template <
typename PacketT,
int AlignmentType>
321 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketT loadPacket(
Index i,
Index j)
const {
322 return this->load<PacketT, AlignmentType>(i, j);
326template <
typename Scalar,
typename Index,
int side,
typename Tensor,
typename nocontract_t,
typename contract_t,
327 bool inner_dim_contiguous,
bool inner_dim_reordered,
int Alignment,
template <
class>
class MakePointer_>
328class BaseTensorContractionMapper<Scalar,
Index, side, Tensor, nocontract_t, contract_t, 1, inner_dim_contiguous,
329 inner_dim_reordered, Alignment, MakePointer_>
330 :
public SimpleTensorContractionMapper<Scalar, Index, side, Tensor, nocontract_t, contract_t, 1,
331 inner_dim_contiguous, Alignment, MakePointer_> {
333 typedef SimpleTensorContractionMapper<Scalar,
Index, side, Tensor, nocontract_t, contract_t, 1, inner_dim_contiguous,
334 Alignment, MakePointer_>
337 EIGEN_DEVICE_FUNC BaseTensorContractionMapper(
const Tensor& tensor,
const nocontract_t& nocontract_strides,
338 const nocontract_t& ij_strides,
const contract_t& contract_strides,
339 const contract_t& k_strides)
340 : ParentMapper(tensor, nocontract_strides, ij_strides, contract_strides, k_strides) {}
342 template <
typename PacketT,
int>
343 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketT loadPacket(
Index i,
Index j)
const {
344 EIGEN_ALIGN_MAX Scalar data[1];
345 data[0] = this->m_tensor.coeff(this->computeIndex(i, j));
346 return pload<PacketT>(data);
348 template <
typename PacketT,
int>
349 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketT load(
Index i,
Index j)
const {
350 EIGEN_ALIGN_MAX Scalar data[1];
351 data[0] = this->m_tensor.coeff(this->computeIndex(i, j));
352 return pload<PacketT>(data);
356template <
typename Scalar,
typename Index,
int side,
typename Tensor,
typename nocontract_t,
typename contract_t,
357 int packet_size,
bool inner_dim_contiguous,
bool inner_dim_reordered,
int Alignment,
358 template <
class>
class MakePointer_ = MakePointer>
359class TensorContractionSubMapper {
361 typedef BaseTensorContractionMapper<Scalar,
Index, side, Tensor, nocontract_t, contract_t, packet_size,
362 inner_dim_contiguous, inner_dim_reordered, Alignment, MakePointer_>
364 typedef TensorContractionSubMapper<Scalar,
Index, side, Tensor, nocontract_t, contract_t, packet_size,
365 inner_dim_contiguous, inner_dim_reordered, Alignment, MakePointer_>
367 typedef Self LinearMapper;
368 typedef Self SubMapper;
374 ParentMapper::DirectOffsets && (side == Lhs) && inner_dim_contiguous && (array_size<contract_t>::value > 0)
377 EIGEN_DEVICE_FUNC TensorContractionSubMapper(
const ParentMapper& base_mapper,
Index vert_offset,
Index horiz_offset)
378 : m_base_mapper(base_mapper), m_vert_offset(vert_offset), m_horiz_offset(horiz_offset) {
381 if (UseDirectOffsets) {
382 Index stride = m_base_mapper.stride();
383 m_base_mapper.offsetBuffer(vert_offset + horiz_offset * stride);
387 EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE Scalar operator()(
Index i)
const {
388 if (UseDirectOffsets) {
389 return m_base_mapper(i, 0);
391 return m_base_mapper(i + m_vert_offset, m_horiz_offset);
393 EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE Scalar operator()(
Index i,
Index j)
const {
394 if (UseDirectOffsets) {
395 return m_base_mapper(i, j);
397 return m_base_mapper(i + m_vert_offset, j + m_horiz_offset);
400 template <
typename PacketT>
401 EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE PacketT loadPacket(
Index i)
const {
402 if (UseDirectOffsets) {
403 return m_base_mapper.template loadPacket<PacketT, Alignment>(i, 0);
405 return m_base_mapper.template loadPacket<PacketT, Alignment>(i + m_vert_offset, m_horiz_offset);
408 template <
typename PacketT>
409 EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE PacketT loadPacket(
Index i,
Index j)
const {
410 if (UseDirectOffsets) {
411 return m_base_mapper.template loadPacket<PacketT, Alignment>(i, j);
413 return m_base_mapper.template loadPacket<PacketT, Alignment>(i + m_vert_offset, j + m_horiz_offset);
416 template <
typename PacketT>
417 EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE PacketT loadPacketPartial(
Index i,
Index j,
Index,
Index = 0)
const {
418 if (UseDirectOffsets) {
419 return m_base_mapper.template loadPacket<PacketT, Alignment>(i, j);
421 return m_base_mapper.template loadPacket<PacketT, Alignment>(i + m_vert_offset, j + m_horiz_offset);
424 template <
typename PacketT,
int AlignmentType>
425 EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE PacketT loadPacket(
Index i,
Index j)
const {
426 if (UseDirectOffsets) {
427 return m_base_mapper.template load<PacketT, AlignmentType>(i, j);
429 return m_base_mapper.template loadPacket<PacketT, AlignmentType>(i + m_vert_offset, j + m_horiz_offset);
432 template <
typename PacketT>
433 EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE
void storePacket(
Index i,
const PacketT& p)
const {
434 if (UseDirectOffsets) {
435 m_base_mapper.storePacket(i, 0, p);
437 m_base_mapper.storePacket(i + m_vert_offset, m_horiz_offset, p);
440 EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE LinearMapper getLinearMapper(
Index i,
Index j)
const {
441 if (UseDirectOffsets) {
442 return LinearMapper(m_base_mapper, i, j);
444 return LinearMapper(m_base_mapper, i + m_vert_offset, j + m_horiz_offset);
447 EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE SubMapper getSubMapper(
Index i,
Index j)
const {
448 if (UseDirectOffsets) {
449 return SubMapper(m_base_mapper, i, j);
451 return SubMapper(m_base_mapper, i + m_vert_offset, j + m_horiz_offset);
454 EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE
const Index stride()
const {
return m_base_mapper.stride(); }
456 template <
typename PacketT,
int AlignmentType>
457 EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE PacketT load(
Index i)
const {
458 EIGEN_STATIC_ASSERT((internal::is_same<PacketT, PacketT>::value), YOU_MADE_A_PROGRAMMING_MISTAKE);
460 if (UseDirectOffsets) {
461 return m_base_mapper.template loadPacket<PacketT, ActualAlignment>(i, 0);
463 return m_base_mapper.template loadPacket<PacketT, ActualAlignment>(i + m_vert_offset, m_horiz_offset);
466 template <
typename PacketT>
467 EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE
bool aligned(
Index)
const {
471 const ParentMapper& base_mapper()
const {
return m_base_mapper; }
472 Index vert_offset()
const {
return m_vert_offset; }
473 Index horiz_offset()
const {
return m_horiz_offset; }
476 ParentMapper m_base_mapper;
477 const Index m_vert_offset;
478 const Index m_horiz_offset;
481template <
typename Scalar_,
typename Index,
int side,
typename Tensor,
typename nocontract_t,
typename contract_t,
482 int packet_size,
bool inner_dim_contiguous,
bool inner_dim_reordered,
int Alignment,
483 template <
class>
class MakePointer_ = MakePointer>
484class TensorContractionInputMapper
485 :
public BaseTensorContractionMapper<Scalar_, Index, side, Tensor, nocontract_t, contract_t, packet_size,
486 inner_dim_contiguous, inner_dim_reordered, Alignment, MakePointer_> {
488 typedef Scalar_ Scalar;
489 typedef BaseTensorContractionMapper<Scalar,
Index, side, Tensor, nocontract_t, contract_t, packet_size,
490 inner_dim_contiguous, inner_dim_reordered, Alignment, MakePointer_>
492 typedef TensorContractionSubMapper<Scalar,
Index, side, Tensor, nocontract_t, contract_t, packet_size,
493 inner_dim_contiguous, inner_dim_reordered, Alignment, MakePointer_>
495 typedef SubMapper VectorMapper;
496 typedef SubMapper LinearMapper;
498 EIGEN_DEVICE_FUNC TensorContractionInputMapper(
const Tensor& tensor,
const nocontract_t& nocontract_strides,
499 const nocontract_t& ij_strides,
const contract_t& contract_strides,
500 const contract_t& k_strides)
501 : Base(tensor, nocontract_strides, ij_strides, contract_strides, k_strides) {}
503 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE SubMapper getSubMapper(
Index i,
Index j)
const {
504 return SubMapper(*
this, i, j);
507 EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE LinearMapper getLinearMapper(
Index i,
Index j)
const {
508 return LinearMapper(*
this, i, j);
511 EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE VectorMapper getVectorMapper(
Index i,
Index j)
const {
512 return VectorMapper(*
this, i, j);
515 EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE
const CoeffLoader<Tensor, Tensor::RawAccess, MakePointer_>& get_tensor()
const {
516 return Base::m_tensor;
521struct TensorContractionInputMapperTrait;
523template <
typename Scalar_,
typename Index_,
int side_,
typename Tensor_,
typename nocontract_t_,
typename contract_t_,
524 int packet_size_,
bool inner_dim_contiguous_,
bool inner_dim_reordered_,
int Alignment_,
525 template <
class>
class MakePointer_>
526struct TensorContractionInputMapperTrait<
527 TensorContractionInputMapper<Scalar_, Index_, side_, Tensor_, nocontract_t_, contract_t_, packet_size_,
528 inner_dim_contiguous_, inner_dim_reordered_, Alignment_, MakePointer_> > {
529 typedef Tensor_ XprType;
530 static const bool inner_dim_contiguous = inner_dim_contiguous_;
531 static const bool inner_dim_reordered = inner_dim_reordered_;
The tensor class.
Definition Tensor.h:68
Namespace containing all symbols from the Eigen library.
EIGEN_DEFAULT_DENSE_INDEX_TYPE Index
Definition TensorContractionMapper.h:36