TensorTrace.h
Go to the documentation of this file.
1 // This file is part of Eigen, a lightweight C++ template library
2 // for linear algebra.
3 //
4 // Copyright (C) 2017 Gagan Goel <gagan.nith@gmail.com>
5 // Copyright (C) 2017 Benoit Steiner <benoit.steiner.goog@gmail.com>
6 //
7 // This Source Code Form is subject to the terms of the Mozilla
8 // Public License v. 2.0. If a copy of the MPL was not distributed
9 // with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 
11 #ifndef EIGEN_CXX11_TENSOR_TENSOR_TRACE_H
12 #define EIGEN_CXX11_TENSOR_TENSOR_TRACE_H
13 
14 #include "./InternalHeaderCheck.h"
15 
16 namespace Eigen {
17 
26 namespace internal {
27 template<typename Dims, typename XprType>
28 struct traits<TensorTraceOp<Dims, XprType> > : public traits<XprType>
29 {
30  typedef typename XprType::Scalar Scalar;
31  typedef traits<XprType> XprTraits;
32  typedef typename XprTraits::StorageKind StorageKind;
33  typedef typename XprTraits::Index Index;
34  typedef typename XprType::Nested Nested;
35  typedef std::remove_reference_t<Nested> Nested_;
36  static constexpr int NumDimensions = XprTraits::NumDimensions - array_size<Dims>::value;
37  static constexpr int Layout = XprTraits::Layout;
38 };
39 
40 template<typename Dims, typename XprType>
41 struct eval<TensorTraceOp<Dims, XprType>, Eigen::Dense>
42 {
43  typedef const TensorTraceOp<Dims, XprType>& type;
44 };
45 
46 template<typename Dims, typename XprType>
47 struct nested<TensorTraceOp<Dims, XprType>, 1, typename eval<TensorTraceOp<Dims, XprType> >::type>
48 {
49  typedef TensorTraceOp<Dims, XprType> type;
50 };
51 
52 } // end namespace internal
53 
54 
55 template<typename Dims, typename XprType>
56 class TensorTraceOp : public TensorBase<TensorTraceOp<Dims, XprType> >
57 {
58  public:
59  typedef typename Eigen::internal::traits<TensorTraceOp>::Scalar Scalar;
61  typedef typename XprType::CoeffReturnType CoeffReturnType;
62  typedef typename Eigen::internal::nested<TensorTraceOp>::type Nested;
63  typedef typename Eigen::internal::traits<TensorTraceOp>::StorageKind StorageKind;
64  typedef typename Eigen::internal::traits<TensorTraceOp>::Index Index;
65 
66  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorTraceOp(const XprType& expr, const Dims& dims)
67  : m_xpr(expr), m_dims(dims) {
68  }
69 
70  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
71  const Dims& dims() const { return m_dims; }
72 
73  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
75 
76  protected:
77  typename XprType::Nested m_xpr;
78  const Dims m_dims;
79 };
80 
81 
82 // Eval as rvalue
83 template<typename Dims, typename ArgType, typename Device>
84 struct TensorEvaluator<const TensorTraceOp<Dims, ArgType>, Device>
85 {
87  static constexpr int NumInputDims = internal::array_size<typename TensorEvaluator<ArgType, Device>::Dimensions>::value;
88  static constexpr int NumReducedDims = internal::array_size<Dims>::value;
89  static constexpr int NumOutputDims = NumInputDims - NumReducedDims;
90  typedef typename XprType::Index Index;
92  typedef typename XprType::Scalar Scalar;
95  static constexpr int PacketSize = internal::unpacket_traits<PacketReturnType>::size;
98 
100  enum {
101  IsAligned = false,
103  BlockAccess = false,
105  CoordAccess = false,
106  RawAccess = false
107  };
108 
109  //===- Tensor block evaluation strategy (see TensorBlock.h) -------------===//
110  typedef internal::TensorBlockNotImplemented TensorBlock;
111  //===--------------------------------------------------------------------===//
112 
113  EIGEN_STRONG_INLINE TensorEvaluator(const XprType& op, const Device& device)
114  : m_impl(op.expression(), device), m_traceDim(1), m_device(device)
115  {
116 
117  EIGEN_STATIC_ASSERT((NumOutputDims >= 0), YOU_MADE_A_PROGRAMMING_MISTAKE);
118  EIGEN_STATIC_ASSERT((NumReducedDims >= 2) || ((NumReducedDims == 0) && (NumInputDims == 0)), YOU_MADE_A_PROGRAMMING_MISTAKE);
119 
120  for (int i = 0; i < NumInputDims; ++i) {
121  m_reduced[i] = false;
122  }
123 
124  const Dims& op_dims = op.dims();
125  for (int i = 0; i < NumReducedDims; ++i) {
126  eigen_assert(op_dims[i] >= 0);
127  eigen_assert(op_dims[i] < NumInputDims);
128  m_reduced[op_dims[i]] = true;
129  }
130 
131  // All the dimensions should be distinct to compute the trace
132  int num_distinct_reduce_dims = 0;
133  for (int i = 0; i < NumInputDims; ++i) {
134  if (m_reduced[i]) {
135  ++num_distinct_reduce_dims;
136  }
137  }
138 
139  EIGEN_ONLY_USED_FOR_DEBUG(num_distinct_reduce_dims);
140  eigen_assert(num_distinct_reduce_dims == NumReducedDims);
141 
142  // Compute the dimensions of the result.
143  const typename TensorEvaluator<ArgType, Device>::Dimensions& input_dims = m_impl.dimensions();
144 
145  int output_index = 0;
146  int reduced_index = 0;
147  for (int i = 0; i < NumInputDims; ++i) {
148  if (m_reduced[i]) {
149  m_reducedDims[reduced_index] = input_dims[i];
150  if (reduced_index > 0) {
151  // All the trace dimensions must have the same size
152  eigen_assert(m_reducedDims[0] == m_reducedDims[reduced_index]);
153  }
154  ++reduced_index;
155  }
156  else {
157  m_dimensions[output_index] = input_dims[i];
158  ++output_index;
159  }
160  }
161 
162  if (NumReducedDims != 0) {
163  m_traceDim = m_reducedDims[0];
164  }
165 
166  // Compute the output strides
167  if (NumOutputDims > 0) {
168  if (static_cast<int>(Layout) == static_cast<int>(ColMajor)) {
169  m_outputStrides[0] = 1;
170  for (int i = 1; i < NumOutputDims; ++i) {
171  m_outputStrides[i] = m_outputStrides[i - 1] * m_dimensions[i - 1];
172  }
173  }
174  else {
175  m_outputStrides.back() = 1;
176  for (int i = NumOutputDims - 2; i >= 0; --i) {
177  m_outputStrides[i] = m_outputStrides[i + 1] * m_dimensions[i + 1];
178  }
179  }
180  }
181 
182  // Compute the input strides
183  if (NumInputDims > 0) {
184  array<Index, NumInputDims> input_strides;
185  if (static_cast<int>(Layout) == static_cast<int>(ColMajor)) {
186  input_strides[0] = 1;
187  for (int i = 1; i < NumInputDims; ++i) {
188  input_strides[i] = input_strides[i - 1] * input_dims[i - 1];
189  }
190  }
191  else {
192  input_strides.back() = 1;
193  for (int i = NumInputDims - 2; i >= 0; --i) {
194  input_strides[i] = input_strides[i + 1] * input_dims[i + 1];
195  }
196  }
197 
198  output_index = 0;
199  reduced_index = 0;
200  for (int i = 0; i < NumInputDims; ++i) {
201  if(m_reduced[i]) {
202  m_reducedStrides[reduced_index] = input_strides[i];
203  ++reduced_index;
204  }
205  else {
206  m_preservedStrides[output_index] = input_strides[i];
207  ++output_index;
208  }
209  }
210  }
211  }
212 
213  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Dimensions& dimensions() const {
214  return m_dimensions;
215  }
216 
217  EIGEN_STRONG_INLINE bool evalSubExprsIfNeeded(EvaluatorPointerType /*data*/) {
218  m_impl.evalSubExprsIfNeeded(NULL);
219  return true;
220  }
221 
222  EIGEN_STRONG_INLINE void cleanup() {
223  m_impl.cleanup();
224  }
225 
226  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(Index index) const
227  {
228  // Initialize the result
229  CoeffReturnType result = internal::cast<int, CoeffReturnType>(0);
230  Index index_stride = 0;
231  for (int i = 0; i < NumReducedDims; ++i) {
232  index_stride += m_reducedStrides[i];
233  }
234 
235  // If trace is requested along all dimensions, starting index would be 0
236  Index cur_index = 0;
237  if (NumOutputDims != 0)
238  cur_index = firstInput(index);
239  for (Index i = 0; i < m_traceDim; ++i) {
240  result += m_impl.coeff(cur_index);
241  cur_index += index_stride;
242  }
243 
244  return result;
245  }
246 
247  template<int LoadMode>
248  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketReturnType packet(Index index) const {
249  eigen_assert(index + PacketSize - 1 < dimensions().TotalSize());
250 
251  EIGEN_ALIGN_MAX std::remove_const_t<CoeffReturnType> values[PacketSize];
252  for (int i = 0; i < PacketSize; ++i) {
253  values[i] = coeff(index + i);
254  }
255  PacketReturnType result = internal::ploadt<PacketReturnType, LoadMode>(values);
256  return result;
257  }
258 
259  protected:
260  // Given the output index, finds the first index in the input tensor used to compute the trace
261  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index firstInput(Index index) const {
262  Index startInput = 0;
263  if (static_cast<int>(Layout) == static_cast<int>(ColMajor)) {
264  for (int i = NumOutputDims - 1; i > 0; --i) {
265  const Index idx = index / m_outputStrides[i];
266  startInput += idx * m_preservedStrides[i];
267  index -= idx * m_outputStrides[i];
268  }
269  startInput += index * m_preservedStrides[0];
270  }
271  else {
272  for (int i = 0; i < NumOutputDims - 1; ++i) {
273  const Index idx = index / m_outputStrides[i];
274  startInput += idx * m_preservedStrides[i];
275  index -= idx * m_outputStrides[i];
276  }
277  startInput += index * m_preservedStrides[NumOutputDims - 1];
278  }
279  return startInput;
280  }
281 
284  // Initialize the size of the trace dimension
292 };
293 
294 
295 } // End namespace Eigen
296 
297 #endif // EIGEN_CXX11_TENSOR_TENSOR_TRACE_H
int i
#define EIGEN_ALIGN_MAX
#define EIGEN_DEVICE_FUNC
#define EIGEN_ONLY_USED_FOR_DEBUG(x)
#define eigen_assert(x)
#define EIGEN_STATIC_ASSERT(X, MSG)
#define EIGEN_DEVICE_REF
Definition: TensorMacros.h:36
The tensor base class.
Eigen::internal::nested< TensorTraceOp >::type Nested
Definition: TensorTrace.h:62
TensorTraceOp(const XprType &expr, const Dims &dims)
Definition: TensorTrace.h:66
XprType::Nested m_xpr
Definition: TensorTrace.h:77
const Dims & dims() const
Definition: TensorTrace.h:71
XprType::CoeffReturnType CoeffReturnType
Definition: TensorTrace.h:61
const internal::remove_all_t< typename XprType::Nested > & expression() const
Definition: TensorTrace.h:74
Eigen::internal::traits< TensorTraceOp >::StorageKind StorageKind
Definition: TensorTrace.h:63
Eigen::internal::traits< TensorTraceOp >::Scalar Scalar
Definition: TensorTrace.h:59
Eigen::NumTraits< Scalar >::Real RealScalar
Definition: TensorTrace.h:60
Eigen::internal::traits< TensorTraceOp >::Index Index
Definition: TensorTrace.h:64
typename remove_all< T >::type remove_all_t
: TensorContractionSycl.h, provides various tensor contraction kernel for SYCL backend
std::array< T, N > array
EIGEN_DEFAULT_DENSE_INDEX_TYPE Index
internal::packet_traits< Scalar >::type type
Definition: TensorMeta.h:55
PacketType< CoeffReturnType, Device >::type PacketReturnType
Definition: TensorTrace.h:94
A cost model used to limit the number of threads used for evaluating tensor expression.
const Dimensions & dimensions() const
static constexpr int Layout
const Device EIGEN_DEVICE_REF m_device
CoeffReturnType coeff(Index index) const
static constexpr int PacketSize