TensorGenerator.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) 2015 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_GENERATOR_H
11 #define EIGEN_CXX11_TENSOR_TENSOR_GENERATOR_H
12 
13 #include "./InternalHeaderCheck.h"
14 
15 namespace Eigen {
16 
24 namespace internal {
25 template<typename Generator, typename XprType>
26 struct traits<TensorGeneratorOp<Generator, XprType> > : public traits<XprType>
27 {
28  typedef typename XprType::Scalar Scalar;
29  typedef traits<XprType> XprTraits;
30  typedef typename XprTraits::StorageKind StorageKind;
31  typedef typename XprTraits::Index Index;
32  typedef typename XprType::Nested Nested;
33  typedef std::remove_reference_t<Nested> Nested_;
34  static constexpr int NumDimensions = XprTraits::NumDimensions;
35  static constexpr int Layout = XprTraits::Layout;
36  typedef typename XprTraits::PointerType PointerType;
37 };
38 
39 template<typename Generator, typename XprType>
40 struct eval<TensorGeneratorOp<Generator, XprType>, Eigen::Dense>
41 {
42  typedef const TensorGeneratorOp<Generator, XprType>& type;
43 };
44 
45 template<typename Generator, typename XprType>
46 struct nested<TensorGeneratorOp<Generator, XprType>, 1, typename eval<TensorGeneratorOp<Generator, XprType> >::type>
47 {
48  typedef TensorGeneratorOp<Generator, XprType> type;
49 };
50 
51 } // end namespace internal
52 
53 
54 
55 template<typename Generator, typename XprType>
56 class TensorGeneratorOp : public TensorBase<TensorGeneratorOp<Generator, XprType>, ReadOnlyAccessors>
57 {
58  public:
59  typedef typename Eigen::internal::traits<TensorGeneratorOp>::Scalar Scalar;
61  typedef typename XprType::CoeffReturnType CoeffReturnType;
62  typedef typename Eigen::internal::nested<TensorGeneratorOp>::type Nested;
63  typedef typename Eigen::internal::traits<TensorGeneratorOp>::StorageKind StorageKind;
64  typedef typename Eigen::internal::traits<TensorGeneratorOp>::Index Index;
65 
66  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorGeneratorOp(const XprType& expr, const Generator& generator)
67  : m_xpr(expr), m_generator(generator) {}
68 
70  const Generator& generator() const { return m_generator; }
71 
74  expression() const { return m_xpr; }
75 
76  protected:
77  typename XprType::Nested m_xpr;
78  const Generator m_generator;
79 };
80 
81 
82 // Eval as rvalue
83 template<typename Generator, typename ArgType, typename Device>
84 struct TensorEvaluator<const TensorGeneratorOp<Generator, ArgType>, Device>
85 {
87  typedef typename XprType::Index Index;
89  static constexpr int NumDims = internal::array_size<Dimensions>::value;
90  typedef typename XprType::Scalar Scalar;
96  enum {
97  IsAligned = false,
99  BlockAccess = true,
100  PreferBlockAccess = true,
101  CoordAccess = false, // to be implemented
102  RawAccess = false
103  };
104 
105  typedef internal::TensorIntDivisor<Index> IndexDivisor;
106 
107  //===- Tensor block evaluation strategy (see TensorBlock.h) -------------===//
108  typedef internal::TensorBlockDescriptor<NumDims, Index> TensorBlockDesc;
109  typedef internal::TensorBlockScratchAllocator<Device> TensorBlockScratch;
110 
111  typedef typename internal::TensorMaterializedBlock<CoeffReturnType, NumDims,
112  Layout, Index>
114  //===--------------------------------------------------------------------===//
115 
116  EIGEN_STRONG_INLINE TensorEvaluator(const XprType& op, const Device& device)
117  : m_device(device), m_generator(op.generator())
118  {
119  TensorEvaluator<ArgType, Device> argImpl(op.expression(), device);
120  m_dimensions = argImpl.dimensions();
121 
122  if (static_cast<int>(Layout) == static_cast<int>(ColMajor)) {
123  m_strides[0] = 1;
125  for (int i = 1; i < NumDims; ++i) {
126  m_strides[i] = m_strides[i - 1] * m_dimensions[i - 1];
127  if (m_strides[i] != 0) m_fast_strides[i] = IndexDivisor(m_strides[i]);
128  }
129  } else {
130  m_strides[NumDims - 1] = 1;
132  for (int i = NumDims - 2; i >= 0; --i) {
133  m_strides[i] = m_strides[i + 1] * m_dimensions[i + 1];
134  if (m_strides[i] != 0) m_fast_strides[i] = IndexDivisor(m_strides[i]);
135  }
136  }
137  }
138 
139  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Dimensions& dimensions() const { return m_dimensions; }
140 
141  EIGEN_STRONG_INLINE bool evalSubExprsIfNeeded(EvaluatorPointerType /*data*/) {
142  return true;
143  }
144  EIGEN_STRONG_INLINE void cleanup() {
145  }
146 
147  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(Index index) const
148  {
149  array<Index, NumDims> coords;
150  extract_coordinates(index, coords);
151  return m_generator(coords);
152  }
153 
154  template<int LoadMode>
155  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketReturnType packet(Index index) const
156  {
157  const int packetSize = PacketType<CoeffReturnType, Device>::size;
158  eigen_assert(index+packetSize-1 < dimensions().TotalSize());
159 
160  EIGEN_ALIGN_MAX std::remove_const_t<CoeffReturnType> values[packetSize];
161  for (int i = 0; i < packetSize; ++i) {
162  values[i] = coeff(index+i);
163  }
164  PacketReturnType rslt = internal::pload<PacketReturnType>(values);
165  return rslt;
166  }
167 
168  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
169  internal::TensorBlockResourceRequirements getResourceRequirements() const {
170  const size_t target_size = m_device.firstLevelCacheSize();
171  // TODO(ezhulenev): Generator should have a cost.
172  return internal::TensorBlockResourceRequirements::skewed<Scalar>(
173  target_size);
174  }
175 
176  struct BlockIteratorState {
181  };
182 
183  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorBlock
185  bool /*root_of_expr_ast*/ = false) const {
186  static const bool is_col_major =
187  static_cast<int>(Layout) == static_cast<int>(ColMajor);
188 
189  // Compute spatial coordinates for the first block element.
190  array<Index, NumDims> coords;
191  extract_coordinates(desc.offset(), coords);
192  array<Index, NumDims> initial_coords = coords;
193 
194  // Offset in the output block buffer.
195  Index offset = 0;
196 
197  // Initialize output block iterator state. Dimension in this array are
198  // always in inner_most -> outer_most order (col major layout).
200  for (int i = 0; i < NumDims; ++i) {
201  const int dim = is_col_major ? i : NumDims - 1 - i;
202  it[i].size = desc.dimension(dim);
203  it[i].stride = i == 0 ? 1 : (it[i - 1].size * it[i - 1].stride);
204  it[i].span = it[i].stride * (it[i].size - 1);
205  it[i].count = 0;
206  }
207  eigen_assert(it[0].stride == 1);
208 
209  // Prepare storage for the materialized generator result.
210  const typename TensorBlock::Storage block_storage =
211  TensorBlock::prepareStorage(desc, scratch);
212 
213  CoeffReturnType* block_buffer = block_storage.data();
214 
215  static const int packet_size = PacketType<CoeffReturnType, Device>::size;
216 
217  static const int inner_dim = is_col_major ? 0 : NumDims - 1;
218  const Index inner_dim_size = it[0].size;
219  const Index inner_dim_vectorized = inner_dim_size - packet_size;
220 
221  while (it[NumDims - 1].count < it[NumDims - 1].size) {
222  Index i = 0;
223  // Generate data for the vectorized part of the inner-most dimension.
224  for (; i <= inner_dim_vectorized; i += packet_size) {
225  for (Index j = 0; j < packet_size; ++j) {
226  array<Index, NumDims> j_coords = coords; // Break loop dependence.
227  j_coords[inner_dim] += j;
228  *(block_buffer + offset + i + j) = m_generator(j_coords);
229  }
230  coords[inner_dim] += packet_size;
231  }
232  // Finalize non-vectorized part of the inner-most dimension.
233  for (; i < inner_dim_size; ++i) {
234  *(block_buffer + offset + i) = m_generator(coords);
235  coords[inner_dim]++;
236  }
237  coords[inner_dim] = initial_coords[inner_dim];
238 
239  // For the 1d tensor we need to generate only one inner-most dimension.
240  if (NumDims == 1) break;
241 
242  // Update offset.
243  for (i = 1; i < NumDims; ++i) {
244  if (++it[i].count < it[i].size) {
245  offset += it[i].stride;
246  coords[is_col_major ? i : NumDims - 1 - i]++;
247  break;
248  }
249  if (i != NumDims - 1) it[i].count = 0;
250  coords[is_col_major ? i : NumDims - 1 - i] =
251  initial_coords[is_col_major ? i : NumDims - 1 - i];
252  offset -= it[i].span;
253  }
254  }
255 
256  return block_storage.AsTensorMaterializedBlock();
257  }
258 
259  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorOpCost
260  costPerCoeff(bool) const {
261  // TODO(rmlarsen): This is just a placeholder. Define interface to make
262  // generators return their cost.
263  return TensorOpCost(0, 0, TensorOpCost::AddCost<Scalar>() +
264  TensorOpCost::MulCost<Scalar>());
265  }
266 
267  EIGEN_DEVICE_FUNC EvaluatorPointerType data() const { return NULL; }
268 
269  protected:
270  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
271  void extract_coordinates(Index index, array<Index, NumDims>& coords) const {
272  if (static_cast<int>(Layout) == static_cast<int>(ColMajor)) {
273  for (int i = NumDims - 1; i > 0; --i) {
274  const Index idx = index / m_fast_strides[i];
275  index -= idx * m_strides[i];
276  coords[i] = idx;
277  }
278  coords[0] = index;
279  } else {
280  for (int i = 0; i < NumDims - 1; ++i) {
281  const Index idx = index / m_fast_strides[i];
282  index -= idx * m_strides[i];
283  coords[i] = idx;
284  }
285  coords[NumDims-1] = index;
286  }
287  }
288 
293  Generator m_generator;
294 };
295 
296 } // end namespace Eigen
297 
298 #endif // EIGEN_CXX11_TENSOR_TENSOR_GENERATOR_H
int i
#define EIGEN_ALIGN_MAX
#define EIGEN_UNROLL_LOOP
#define EIGEN_DEVICE_FUNC
#define eigen_assert(x)
#define EIGEN_DEVICE_REF
Definition: TensorMacros.h:36
The tensor base class.
Tensor generator class.
Eigen::internal::traits< TensorGeneratorOp >::StorageKind StorageKind
Eigen::internal::traits< TensorGeneratorOp >::Scalar Scalar
TensorGeneratorOp(const XprType &expr, const Generator &generator)
Eigen::internal::nested< TensorGeneratorOp >::type Nested
Eigen::NumTraits< Scalar >::Real RealScalar
XprType::CoeffReturnType CoeffReturnType
Eigen::internal::traits< TensorGeneratorOp >::Index Index
const Generator m_generator
const Generator & generator() const
const internal::remove_all_t< typename XprType::Nested > & expression() const
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
SparseMat::Index size
internal::TensorBlockResourceRequirements getResourceRequirements() const
TensorBlock block(TensorBlockDesc &desc, TensorBlockScratch &scratch, bool=false) const
internal::TensorMaterializedBlock< CoeffReturnType, NumDims, Layout, Index > TensorBlock
void extract_coordinates(Index index, array< Index, NumDims > &coords) const
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
Derived::Scalar CoeffReturnType
std::ptrdiff_t j