TensorPadding.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) 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_PADDING_H
11 #define EIGEN_CXX11_TENSOR_TENSOR_PADDING_H
12 
13 namespace Eigen {
14 
22 namespace internal {
23 template<typename PaddingDimensions, typename XprType>
24 struct traits<TensorPaddingOp<PaddingDimensions, XprType> > : public traits<XprType>
25 {
26  typedef typename XprType::Scalar Scalar;
28  typedef typename XprTraits::StorageKind StorageKind;
29  typedef typename XprTraits::Index Index;
30  typedef typename XprType::Nested Nested;
32  static const int NumDimensions = XprTraits::NumDimensions;
33  static const int Layout = XprTraits::Layout;
34 };
35 
36 template<typename PaddingDimensions, typename XprType>
37 struct eval<TensorPaddingOp<PaddingDimensions, XprType>, Eigen::Dense>
38 {
40 };
41 
42 template<typename PaddingDimensions, typename XprType>
43 struct nested<TensorPaddingOp<PaddingDimensions, XprType>, 1, typename eval<TensorPaddingOp<PaddingDimensions, XprType> >::type>
44 {
46 };
47 
48 } // end namespace internal
49 
50 
51 
52 template<typename PaddingDimensions, typename XprType>
53 class TensorPaddingOp : public TensorBase<TensorPaddingOp<PaddingDimensions, XprType>, ReadOnlyAccessors>
54 {
55  public:
58  typedef typename XprType::CoeffReturnType CoeffReturnType;
62 
63  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorPaddingOp(const XprType& expr, const PaddingDimensions& padding_dims, const Scalar padding_value)
64  : m_xpr(expr), m_padding_dims(padding_dims), m_padding_value(padding_value) {}
65 
66  EIGEN_DEVICE_FUNC
67  const PaddingDimensions& padding() const { return m_padding_dims; }
68  EIGEN_DEVICE_FUNC
69  Scalar padding_value() const { return m_padding_value; }
70 
71  EIGEN_DEVICE_FUNC
73  expression() const { return m_xpr; }
74 
75  protected:
76  typename XprType::Nested m_xpr;
77  const PaddingDimensions m_padding_dims;
78  const Scalar m_padding_value;
79 };
80 
81 
82 // Eval as rvalue
83 template<typename PaddingDimensions, typename ArgType, typename Device>
84 struct TensorEvaluator<const TensorPaddingOp<PaddingDimensions, ArgType>, Device>
85 {
87  typedef typename XprType::Index Index;
90  typedef typename XprType::Scalar Scalar;
94 
95  enum {
96  IsAligned = true,
99  CoordAccess = true,
100  RawAccess = false
101  };
102 
103  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorEvaluator(const XprType& op, const Device& device)
104  : m_impl(op.expression(), device), m_padding(op.padding()), m_paddingValue(op.padding_value())
105  {
106  // The padding op doesn't change the rank of the tensor. Directly padding a scalar would lead
107  // to a vector, which doesn't make sense. Instead one should reshape the scalar into a vector
108  // of 1 element first and then pad.
109  EIGEN_STATIC_ASSERT((NumDims > 0), YOU_MADE_A_PROGRAMMING_MISTAKE);
110 
111  // Compute dimensions
112  m_dimensions = m_impl.dimensions();
113  for (int i = 0; i < NumDims; ++i) {
114  m_dimensions[i] += m_padding[i].first + m_padding[i].second;
115  }
116  const typename TensorEvaluator<ArgType, Device>::Dimensions& input_dims = m_impl.dimensions();
117  if (static_cast<int>(Layout) == static_cast<int>(ColMajor)) {
118  m_inputStrides[0] = 1;
119  m_outputStrides[0] = 1;
120  for (int i = 1; i < NumDims; ++i) {
121  m_inputStrides[i] = m_inputStrides[i-1] * input_dims[i-1];
122  m_outputStrides[i] = m_outputStrides[i-1] * m_dimensions[i-1];
123  }
124  m_outputStrides[NumDims] = m_outputStrides[NumDims-1] * m_dimensions[NumDims-1];
125  } else {
126  m_inputStrides[NumDims - 1] = 1;
127  m_outputStrides[NumDims] = 1;
128  for (int i = NumDims - 2; i >= 0; --i) {
129  m_inputStrides[i] = m_inputStrides[i+1] * input_dims[i+1];
130  m_outputStrides[i+1] = m_outputStrides[i+2] * m_dimensions[i+1];
131  }
132  m_outputStrides[0] = m_outputStrides[1] * m_dimensions[0];
133  }
134  }
135 
136  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Dimensions& dimensions() const { return m_dimensions; }
137 
138  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool evalSubExprsIfNeeded(Scalar*) {
139  m_impl.evalSubExprsIfNeeded(NULL);
140  return true;
141  }
142  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void cleanup() {
143  m_impl.cleanup();
144  }
145 
146  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(Index index) const
147  {
148  eigen_assert(index < dimensions().TotalSize());
149  Index inputIndex = 0;
150  if (static_cast<int>(Layout) == static_cast<int>(ColMajor)) {
151  for (int i = NumDims - 1; i > 0; --i) {
152  const Index idx = index / m_outputStrides[i];
153  if (isPaddingAtIndexForDim(idx, i)) {
154  return m_paddingValue;
155  }
156  inputIndex += (idx - m_padding[i].first) * m_inputStrides[i];
157  index -= idx * m_outputStrides[i];
158  }
159  if (isPaddingAtIndexForDim(index, 0)) {
160  return m_paddingValue;
161  }
162  inputIndex += (index - m_padding[0].first);
163  } else {
164  for (int i = 0; i < NumDims - 1; ++i) {
165  const Index idx = index / m_outputStrides[i+1];
166  if (isPaddingAtIndexForDim(idx, i)) {
167  return m_paddingValue;
168  }
169  inputIndex += (idx - m_padding[i].first) * m_inputStrides[i];
170  index -= idx * m_outputStrides[i+1];
171  }
172  if (isPaddingAtIndexForDim(index, NumDims-1)) {
173  return m_paddingValue;
174  }
175  inputIndex += (index - m_padding[NumDims-1].first);
176  }
177  return m_impl.coeff(inputIndex);
178  }
179 
180  template<int LoadMode>
181  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketReturnType packet(Index index) const
182  {
183  if (static_cast<int>(Layout) == static_cast<int>(ColMajor)) {
184  return packetColMajor(index);
185  }
186  return packetRowMajor(index);
187  }
188 
189  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorOpCost costPerCoeff(bool vectorized) const {
190  TensorOpCost cost = m_impl.costPerCoeff(vectorized);
191  if (static_cast<int>(Layout) == static_cast<int>(ColMajor)) {
192  for (int i = 0; i < NumDims; ++i)
193  updateCostPerDimension(cost, i, i == 0);
194  } else {
195  for (int i = NumDims - 1; i >= 0; --i)
196  updateCostPerDimension(cost, i, i == NumDims - 1);
197  }
198  return cost;
199  }
200 
201  EIGEN_DEVICE_FUNC Scalar* data() const { return NULL; }
202 
203  private:
205  Index index, int dim_index) const {
206 #if defined(EIGEN_HAS_INDEX_LIST)
207  return (!internal::index_pair_first_statically_eq<PaddingDimensions>(dim_index, 0) &&
208  index < m_padding[dim_index].first) ||
209  (!internal::index_pair_second_statically_eq<PaddingDimensions>(dim_index, 0) &&
210  index >= m_dimensions[dim_index] - m_padding[dim_index].second);
211 #else
212  return (index < m_padding[dim_index].first) ||
213  (index >= m_dimensions[dim_index] - m_padding[dim_index].second);
214 #endif
215  }
216 
218  int dim_index) const {
219 #if defined(EIGEN_HAS_INDEX_LIST)
220  return internal::index_pair_first_statically_eq<PaddingDimensions>(dim_index, 0);
221 #else
222  EIGEN_UNUSED_VARIABLE(dim_index);
223  return false;
224 #endif
225  }
226 
228  int dim_index) const {
229 #if defined(EIGEN_HAS_INDEX_LIST)
230  return internal::index_pair_second_statically_eq<PaddingDimensions>(dim_index, 0);
231 #else
232  EIGEN_UNUSED_VARIABLE(dim_index);
233  return false;
234 #endif
235  }
236 
237 
238  void updateCostPerDimension(TensorOpCost& cost, int i, bool first) const {
239  const double in = static_cast<double>(m_impl.dimensions()[i]);
240  const double out = in + m_padding[i].first + m_padding[i].second;
241  if (out == 0)
242  return;
243  const double reduction = in / out;
244  cost *= reduction;
245  if (first) {
246  cost += TensorOpCost(0, 0, 2 * TensorOpCost::AddCost<Index>() +
247  reduction * (1 * TensorOpCost::AddCost<Index>()));
248  } else {
249  cost += TensorOpCost(0, 0, 2 * TensorOpCost::AddCost<Index>() +
250  2 * TensorOpCost::MulCost<Index>() +
251  reduction * (2 * TensorOpCost::MulCost<Index>() +
252  1 * TensorOpCost::DivCost<Index>()));
253  }
254  }
255 
256  protected:
257 
258  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketReturnType packetColMajor(Index index) const
259  {
260  EIGEN_STATIC_ASSERT((PacketSize > 1), YOU_MADE_A_PROGRAMMING_MISTAKE)
261  eigen_assert(index+PacketSize-1 < dimensions().TotalSize());
262 
263  const Index initialIndex = index;
264  Index inputIndex = 0;
265  for (int i = NumDims - 1; i > 0; --i) {
266  const Index first = index;
267  const Index last = index + PacketSize - 1;
268  const Index lastPaddedLeft = m_padding[i].first * m_outputStrides[i];
269  const Index firstPaddedRight = (m_dimensions[i] - m_padding[i].second) * m_outputStrides[i];
270  const Index lastPaddedRight = m_outputStrides[i+1];
271 
272  if (!isLeftPaddingCompileTimeZero(i) && last < lastPaddedLeft) {
273  // all the coefficient are in the padding zone.
274  return internal::pset1<PacketReturnType>(m_paddingValue);
275  }
276  else if (!isRightPaddingCompileTimeZero(i) && first >= firstPaddedRight && last < lastPaddedRight) {
277  // all the coefficient are in the padding zone.
278  return internal::pset1<PacketReturnType>(m_paddingValue);
279  }
280  else if ((isLeftPaddingCompileTimeZero(i) && isRightPaddingCompileTimeZero(i)) || (first >= lastPaddedLeft && last < firstPaddedRight)) {
281  // all the coefficient are between the 2 padding zones.
282  const Index idx = index / m_outputStrides[i];
283  inputIndex += (idx - m_padding[i].first) * m_inputStrides[i];
284  index -= idx * m_outputStrides[i];
285  }
286  else {
287  // Every other case
288  return packetWithPossibleZero(initialIndex);
289  }
290  }
291 
292  const Index last = index + PacketSize - 1;
293  const Index first = index;
294  const Index lastPaddedLeft = m_padding[0].first;
295  const Index firstPaddedRight = (m_dimensions[0] - m_padding[0].second);
296  const Index lastPaddedRight = m_outputStrides[1];
297 
298  if (!isLeftPaddingCompileTimeZero(0) && last < lastPaddedLeft) {
299  // all the coefficient are in the padding zone.
300  return internal::pset1<PacketReturnType>(m_paddingValue);
301  }
302  else if (!isRightPaddingCompileTimeZero(0) && first >= firstPaddedRight && last < lastPaddedRight) {
303  // all the coefficient are in the padding zone.
304  return internal::pset1<PacketReturnType>(m_paddingValue);
305  }
306  else if ((isLeftPaddingCompileTimeZero(0) && isRightPaddingCompileTimeZero(0)) || (first >= lastPaddedLeft && last < firstPaddedRight)) {
307  // all the coefficient are between the 2 padding zones.
308  inputIndex += (index - m_padding[0].first);
309  return m_impl.template packet<Unaligned>(inputIndex);
310  }
311  // Every other case
312  return packetWithPossibleZero(initialIndex);
313  }
314 
315  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketReturnType packetRowMajor(Index index) const
316  {
317  EIGEN_STATIC_ASSERT((PacketSize > 1), YOU_MADE_A_PROGRAMMING_MISTAKE)
318  eigen_assert(index+PacketSize-1 < dimensions().TotalSize());
319 
320  const Index initialIndex = index;
321  Index inputIndex = 0;
322 
323  for (int i = 0; i < NumDims - 1; ++i) {
324  const Index first = index;
325  const Index last = index + PacketSize - 1;
326  const Index lastPaddedLeft = m_padding[i].first * m_outputStrides[i+1];
327  const Index firstPaddedRight = (m_dimensions[i] - m_padding[i].second) * m_outputStrides[i+1];
328  const Index lastPaddedRight = m_outputStrides[i];
329 
330  if (!isLeftPaddingCompileTimeZero(i) && last < lastPaddedLeft) {
331  // all the coefficient are in the padding zone.
332  return internal::pset1<PacketReturnType>(m_paddingValue);
333  }
334  else if (!isRightPaddingCompileTimeZero(i) && first >= firstPaddedRight && last < lastPaddedRight) {
335  // all the coefficient are in the padding zone.
336  return internal::pset1<PacketReturnType>(m_paddingValue);
337  }
338  else if ((isLeftPaddingCompileTimeZero(i) && isRightPaddingCompileTimeZero(i)) || (first >= lastPaddedLeft && last < firstPaddedRight)) {
339  // all the coefficient are between the 2 padding zones.
340  const Index idx = index / m_outputStrides[i+1];
341  inputIndex += (idx - m_padding[i].first) * m_inputStrides[i];
342  index -= idx * m_outputStrides[i+1];
343  }
344  else {
345  // Every other case
346  return packetWithPossibleZero(initialIndex);
347  }
348  }
349 
350  const Index last = index + PacketSize - 1;
351  const Index first = index;
352  const Index lastPaddedLeft = m_padding[NumDims-1].first;
353  const Index firstPaddedRight = (m_dimensions[NumDims-1] - m_padding[NumDims-1].second);
354  const Index lastPaddedRight = m_outputStrides[NumDims-1];
355 
356  if (!isLeftPaddingCompileTimeZero(NumDims-1) && last < lastPaddedLeft) {
357  // all the coefficient are in the padding zone.
358  return internal::pset1<PacketReturnType>(m_paddingValue);
359  }
360  else if (!isRightPaddingCompileTimeZero(NumDims-1) && first >= firstPaddedRight && last < lastPaddedRight) {
361  // all the coefficient are in the padding zone.
362  return internal::pset1<PacketReturnType>(m_paddingValue);
363  }
364  else if ((isLeftPaddingCompileTimeZero(NumDims-1) && isRightPaddingCompileTimeZero(NumDims-1)) || (first >= lastPaddedLeft && last < firstPaddedRight)) {
365  // all the coefficient are between the 2 padding zones.
366  inputIndex += (index - m_padding[NumDims-1].first);
367  return m_impl.template packet<Unaligned>(inputIndex);
368  }
369  // Every other case
370  return packetWithPossibleZero(initialIndex);
371  }
372 
373  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketReturnType packetWithPossibleZero(Index index) const
374  {
376  for (int i = 0; i < PacketSize; ++i) {
377  values[i] = coeff(index+i);
378  }
379  PacketReturnType rslt = internal::pload<PacketReturnType>(values);
380  return rslt;
381  }
382 
383  Dimensions m_dimensions;
387  PaddingDimensions m_padding;
388 
390 };
391 
392 
393 
394 
395 } // end namespace Eigen
396 
397 #endif // EIGEN_CXX11_TENSOR_TENSOR_PADDING_H
#define EIGEN_ALWAYS_INLINE
Definition: Macros.h:507
#define EIGEN_STRONG_INLINE
Definition: Macros.h:493
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Dimensions & dimensions() const
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketReturnType packetRowMajor(Index index) const
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketReturnType packetColMajor(Index index) const
std::vector< double > values
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool evalSubExprsIfNeeded(Scalar *)
Definition: LDLT.h:16
A cost model used to limit the number of threads used for evaluating tensor expression.
#define EIGEN_STATIC_ASSERT(CONDITION, MSG)
Definition: StaticAssert.h:122
Eigen::NumTraits< Scalar >::Real RealScalar
Definition: TensorPadding.h:57
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorOpCost costPerCoeff(bool vectorized) const
EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE bool isRightPaddingCompileTimeZero(int dim_index) const
Eigen::internal::traits< TensorPaddingOp >::Scalar Scalar
Definition: TensorPadding.h:56
XprType::Nested m_xpr
Definition: TensorPadding.h:76
EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE bool isPaddingAtIndexForDim(Index index, int dim_index) const
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorPaddingOp(const XprType &expr, const PaddingDimensions &padding_dims, const Scalar padding_value)
Definition: TensorPadding.h:63
EIGEN_DEFAULT_DENSE_INDEX_TYPE Index
The Index type as used for the API.
Definition: Meta.h:33
#define eigen_assert(x)
Definition: Macros.h:577
const Scalar m_padding_value
Definition: TensorPadding.h:78
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorEvaluator(const XprType &op, const Device &device)
EIGEN_DEVICE_FUNC const internal::remove_all< typename XprType::Nested >::type & expression() const
Definition: TensorPadding.h:73
const PaddingDimensions m_padding_dims
Definition: TensorPadding.h:77
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(Index index) const
XprType::CoeffReturnType CoeffReturnType
Definition: TensorPadding.h:58
Eigen::internal::nested< TensorPaddingOp >::type Nested
Definition: TensorPadding.h:59
EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE bool isLeftPaddingCompileTimeZero(int dim_index) const
The tensor base class.
Definition: TensorBase.h:827
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketReturnType packet(Index index) const
EIGEN_DEVICE_FUNC Scalar padding_value() const
Definition: TensorPadding.h:69
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Dimensions & dimensions() const
Eigen::internal::traits< TensorPaddingOp >::StorageKind StorageKind
Definition: TensorPadding.h:60
#define EIGEN_ALIGN_MAX
Definition: Macros.h:755
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketReturnType packetWithPossibleZero(Index index) const
Eigen::internal::traits< TensorPaddingOp >::Index Index
Definition: TensorPadding.h:61
#define EIGEN_UNUSED_VARIABLE(var)
Definition: Macros.h:616
internal::packet_traits< Scalar >::type type
Definition: TensorMeta.h:51
EIGEN_DEVICE_FUNC const PaddingDimensions & padding() const
Definition: TensorPadding.h:67


hebiros
Author(s): Xavier Artache , Matthew Tesch
autogenerated on Thu Sep 3 2020 04:09:27