TensorPadding.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_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;
27  typedef traits<XprType> XprTraits;
28  typedef typename packet_traits<Scalar>::type Packet;
29  typedef typename XprTraits::StorageKind StorageKind;
30  typedef typename XprTraits::Index Index;
31  typedef typename XprType::Nested Nested;
32  typedef typename remove_reference<Nested>::type _Nested;
33  static const int NumDimensions = XprTraits::NumDimensions;
34  static const int Layout = XprTraits::Layout;
35 };
36 
37 template<typename PaddingDimensions, typename XprType>
38 struct eval<TensorPaddingOp<PaddingDimensions, XprType>, Eigen::Dense>
39 {
40  typedef const TensorPaddingOp<PaddingDimensions, XprType>& type;
41 };
42 
43 template<typename PaddingDimensions, typename XprType>
44 struct nested<TensorPaddingOp<PaddingDimensions, XprType>, 1, typename eval<TensorPaddingOp<PaddingDimensions, XprType> >::type>
45 {
46  typedef TensorPaddingOp<PaddingDimensions, XprType> type;
47 };
48 
49 } // end namespace internal
50 
51 
52 
53 template<typename PaddingDimensions, typename XprType>
54 class TensorPaddingOp : public TensorBase<TensorPaddingOp<PaddingDimensions, XprType>, ReadOnlyAccessors>
55 {
56  public:
57  typedef typename Eigen::internal::traits<TensorPaddingOp>::Scalar Scalar;
58  typedef typename Eigen::internal::traits<TensorPaddingOp>::Packet Packet;
59  typedef typename Eigen::NumTraits<Scalar>::Real RealScalar;
60  typedef typename XprType::CoeffReturnType CoeffReturnType;
61  typedef typename XprType::PacketReturnType PacketReturnType;
62  typedef typename Eigen::internal::nested<TensorPaddingOp>::type Nested;
63  typedef typename Eigen::internal::traits<TensorPaddingOp>::StorageKind StorageKind;
64  typedef typename Eigen::internal::traits<TensorPaddingOp>::Index Index;
65 
66  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorPaddingOp(const XprType& expr, const PaddingDimensions& padding_dims)
67  : m_xpr(expr), m_padding_dims(padding_dims) {}
68 
69  EIGEN_DEVICE_FUNC
70  const PaddingDimensions& padding() const { return m_padding_dims; }
71 
72  EIGEN_DEVICE_FUNC
73  const typename internal::remove_all<typename XprType::Nested>::type&
74  expression() const { return m_xpr; }
75 
76  protected:
77  typename XprType::Nested m_xpr;
78  const PaddingDimensions m_padding_dims;
79 };
80 
81 
82 // Eval as rvalue
83 template<typename PaddingDimensions, typename ArgType, typename Device>
84 struct TensorEvaluator<const TensorPaddingOp<PaddingDimensions, ArgType>, Device>
85 {
86  typedef TensorPaddingOp<PaddingDimensions, ArgType> XprType;
87  typedef typename XprType::Index Index;
88  static const int NumDims = internal::array_size<PaddingDimensions>::value;
89  typedef DSizes<Index, NumDims> Dimensions;
90 
91  enum {
92  IsAligned = false,
93  PacketAccess = TensorEvaluator<ArgType, Device>::PacketAccess,
94  Layout = TensorEvaluator<ArgType, Device>::Layout,
95  CoordAccess = true,
96  };
97 
98  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorEvaluator(const XprType& op, const Device& device)
99  : m_impl(op.expression(), device), m_padding(op.padding())
100  {
101  // The padding op doesn't change the rank of the tensor. Directly padding a scalar would lead
102  // to a vector, which doesn't make sense. Instead one should reshape the scalar into a vector
103  // of 1 element first and then pad.
104  EIGEN_STATIC_ASSERT(NumDims > 0, YOU_MADE_A_PROGRAMMING_MISTAKE);
105 
106  // Compute dimensions
107  m_dimensions = m_impl.dimensions();
108  for (int i = 0; i < NumDims; ++i) {
109  m_dimensions[i] += m_padding[i].first + m_padding[i].second;
110  }
111  const typename TensorEvaluator<ArgType, Device>::Dimensions& input_dims = m_impl.dimensions();
112  if (static_cast<int>(Layout) == static_cast<int>(ColMajor)) {
113  m_inputStrides[0] = 1;
114  m_outputStrides[0] = 1;
115  for (int i = 1; i < NumDims; ++i) {
116  m_inputStrides[i] = m_inputStrides[i-1] * input_dims[i-1];
117  m_outputStrides[i] = m_outputStrides[i-1] * m_dimensions[i-1];
118  }
119  m_outputStrides[NumDims] = m_outputStrides[NumDims-1] * m_dimensions[NumDims-1];
120  } else {
121  m_inputStrides[NumDims - 1] = 1;
122  m_outputStrides[NumDims] = 1;
123  for (int i = NumDims - 2; i >= 0; --i) {
124  m_inputStrides[i] = m_inputStrides[i+1] * input_dims[i+1];
125  m_outputStrides[i+1] = m_outputStrides[i+2] * m_dimensions[i+1];
126  }
127  m_outputStrides[0] = m_outputStrides[1] * m_dimensions[0];
128  }
129  }
130 
131  typedef typename XprType::Scalar Scalar;
132  typedef typename XprType::CoeffReturnType CoeffReturnType;
133  typedef typename XprType::PacketReturnType PacketReturnType;
134 
135  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Dimensions& dimensions() const { return m_dimensions; }
136 
137  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool evalSubExprsIfNeeded(Scalar*) {
138  m_impl.evalSubExprsIfNeeded(NULL);
139  return true;
140  }
141  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void cleanup() {
142  m_impl.cleanup();
143  }
144 
145  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(Index index) const
146  {
147  eigen_assert(index < dimensions().TotalSize());
148  Index inputIndex = 0;
149  if (static_cast<int>(Layout) == static_cast<int>(ColMajor)) {
150  for (int i = NumDims - 1; i > 0; --i) {
151  const Index idx = index / m_outputStrides[i];
152  if (idx < m_padding[i].first || idx >= m_dimensions[i] - m_padding[i].second) {
153  return Scalar(0);
154  }
155  inputIndex += (idx - m_padding[i].first) * m_inputStrides[i];
156  index -= idx * m_outputStrides[i];
157  }
158  if (index < m_padding[0].first || index >= m_dimensions[0] - m_padding[0].second) {
159  return Scalar(0);
160  }
161  inputIndex += (index - m_padding[0].first);
162  } else {
163  for (int i = 0; i < NumDims - 1; ++i) {
164  const Index idx = index / m_outputStrides[i+1];
165  if (idx < m_padding[i].first || idx >= m_dimensions[i] - m_padding[i].second) {
166  return Scalar(0);
167  }
168  inputIndex += (idx - m_padding[i].first) * m_inputStrides[i];
169  index -= idx * m_outputStrides[i+1];
170  }
171  if (index < m_padding[NumDims-1].first ||
172  index >= m_dimensions[NumDims-1] - m_padding[NumDims-1].second) {
173  return Scalar(0);
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 CoeffReturnType coeff(const array<Index, NumDims>& coords) const
190  {
191  Index inputIndex;
192  if (static_cast<int>(Layout) == static_cast<int>(ColMajor)) {
193  {
194  const Index idx = coords[0];
195  if (idx < m_padding[0].first || idx >= m_dimensions[0] - m_padding[0].second) {
196  return Scalar(0);
197  }
198  inputIndex = idx - m_padding[0].first;
199  }
200  for (int i = 1; i < NumDims; ++i) {
201  const Index idx = coords[i];
202  if (idx < m_padding[i].first || idx >= m_dimensions[i] - m_padding[i].second) {
203  return Scalar(0);
204  }
205  inputIndex += (idx - m_padding[i].first) * m_inputStrides[i];
206  }
207  } else {
208  {
209  const Index idx = coords[NumDims-1];
210  if (idx < m_padding[NumDims-1].first || idx >= m_dimensions[NumDims-1] - m_padding[NumDims-1].second) {
211  return Scalar(0);
212  }
213  inputIndex = idx - m_padding[NumDims-1].first;
214  }
215  for (int i = NumDims - 2; i >= 0; --i) {
216  const Index idx = coords[i];
217  if (idx < m_padding[i].first || idx >= m_dimensions[i] - m_padding[i].second) {
218  return Scalar(0);
219  }
220  inputIndex += (idx - m_padding[i].first) * m_inputStrides[i];
221  }
222  }
223  return m_impl.coeff(inputIndex);
224  }
225 
226  EIGEN_DEVICE_FUNC Scalar* data() const { return NULL; }
227 
228  protected:
229 
230  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketReturnType packetColMajor(Index index) const
231  {
232  const int packetSize = internal::unpacket_traits<PacketReturnType>::size;
233  EIGEN_STATIC_ASSERT(packetSize > 1, YOU_MADE_A_PROGRAMMING_MISTAKE)
234  eigen_assert(index+packetSize-1 < dimensions().TotalSize());
235 
236  const Index initialIndex = index;
237  Index inputIndex = 0;
238  for (int i = NumDims - 1; i > 0; --i) {
239  const Index first = index;
240  const Index last = index + packetSize - 1;
241  const Index lastPaddedLeft = m_padding[i].first * m_outputStrides[i];
242  const Index firstPaddedRight = (m_dimensions[i] - m_padding[i].second) * m_outputStrides[i];
243  const Index lastPaddedRight = m_outputStrides[i+1];
244 
245  if (last < lastPaddedLeft) {
246  // all the coefficient are in the padding zone.
247  return internal::pset1<PacketReturnType>(Scalar(0));
248  }
249  else if (first >= firstPaddedRight && last < lastPaddedRight) {
250  // all the coefficient are in the padding zone.
251  return internal::pset1<PacketReturnType>(Scalar(0));
252  }
253  else if (first >= lastPaddedLeft && last < firstPaddedRight) {
254  // all the coefficient are between the 2 padding zones.
255  const Index idx = index / m_outputStrides[i];
256  inputIndex += (idx - m_padding[i].first) * m_inputStrides[i];
257  index -= idx * m_outputStrides[i];
258  }
259  else {
260  // Every other case
261  return packetWithPossibleZero(initialIndex);
262  }
263  }
264 
265  const Index last = index + packetSize - 1;
266  const Index first = index;
267  const Index lastPaddedLeft = m_padding[0].first;
268  const Index firstPaddedRight = (m_dimensions[0] - m_padding[0].second);
269  const Index lastPaddedRight = m_outputStrides[1];
270 
271  if (last < lastPaddedLeft) {
272  // all the coefficient are in the padding zone.
273  return internal::pset1<PacketReturnType>(Scalar(0));
274  }
275  else if (first >= firstPaddedRight && last < lastPaddedRight) {
276  // all the coefficient are in the padding zone.
277  return internal::pset1<PacketReturnType>(Scalar(0));
278  }
279  else if (first >= lastPaddedLeft && last < firstPaddedRight) {
280  // all the coefficient are between the 2 padding zones.
281  inputIndex += (index - m_padding[0].first);
282  return m_impl.template packet<Unaligned>(inputIndex);
283  }
284  // Every other case
285  return packetWithPossibleZero(initialIndex);
286  }
287 
288  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketReturnType packetRowMajor(Index index) const
289  {
290  const int packetSize = internal::unpacket_traits<PacketReturnType>::size;
291  EIGEN_STATIC_ASSERT(packetSize > 1, YOU_MADE_A_PROGRAMMING_MISTAKE)
292  eigen_assert(index+packetSize-1 < dimensions().TotalSize());
293 
294  const Index initialIndex = index;
295  Index inputIndex = 0;
296 
297  for (int i = 0; i < NumDims - 1; ++i) {
298  const Index first = index;
299  const Index last = index + packetSize - 1;
300  const Index lastPaddedLeft = m_padding[i].first * m_outputStrides[i+1];
301  const Index firstPaddedRight = (m_dimensions[i] - m_padding[i].second) * m_outputStrides[i+1];
302  const Index lastPaddedRight = m_outputStrides[i];
303 
304  if (last < lastPaddedLeft) {
305  // all the coefficient are in the padding zone.
306  return internal::pset1<PacketReturnType>(Scalar(0));
307  }
308  else if (first >= firstPaddedRight && last < lastPaddedRight) {
309  // all the coefficient are in the padding zone.
310  return internal::pset1<PacketReturnType>(Scalar(0));
311  }
312  else if (first >= lastPaddedLeft && last < firstPaddedRight) {
313  // all the coefficient are between the 2 padding zones.
314  const Index idx = index / m_outputStrides[i+1];
315  inputIndex += (idx - m_padding[i].first) * m_inputStrides[i];
316  index -= idx * m_outputStrides[i+1];
317  }
318  else {
319  // Every other case
320  return packetWithPossibleZero(initialIndex);
321  }
322  }
323 
324  const Index last = index + packetSize - 1;
325  const Index first = index;
326  const Index lastPaddedLeft = m_padding[NumDims-1].first;
327  const Index firstPaddedRight = (m_dimensions[NumDims-1] - m_padding[NumDims-1].second);
328  const Index lastPaddedRight = m_outputStrides[NumDims-1];
329 
330  if (last < lastPaddedLeft) {
331  // all the coefficient are in the padding zone.
332  return internal::pset1<PacketReturnType>(Scalar(0));
333  }
334  else if (first >= firstPaddedRight && last < lastPaddedRight) {
335  // all the coefficient are in the padding zone.
336  return internal::pset1<PacketReturnType>(Scalar(0));
337  }
338  else if (first >= lastPaddedLeft && last < firstPaddedRight) {
339  // all the coefficient are between the 2 padding zones.
340  inputIndex += (index - m_padding[NumDims-1].first);
341  return m_impl.template packet<Unaligned>(inputIndex);
342  }
343  // Every other case
344  return packetWithPossibleZero(initialIndex);
345  }
346 
347  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketReturnType packetWithPossibleZero(Index index) const
348  {
349  const int packetSize = internal::unpacket_traits<PacketReturnType>::size;
350  EIGEN_ALIGN_MAX typename internal::remove_const<CoeffReturnType>::type values[packetSize];
351  for (int i = 0; i < packetSize; ++i) {
352  values[i] = coeff(index+i);
353  }
354  PacketReturnType rslt = internal::pload<PacketReturnType>(values);
355  return rslt;
356  }
357 
358  Dimensions m_dimensions;
359  array<Index, NumDims+1> m_outputStrides;
360  array<Index, NumDims> m_inputStrides;
361  TensorEvaluator<ArgType, Device> m_impl;
362  PaddingDimensions m_padding;
363 };
364 
365 
366 
367 
368 } // end namespace Eigen
369 
370 #endif // EIGEN_CXX11_TENSOR_TENSOR_PADDING_H
Namespace containing all symbols from the Eigen library.
Definition: CXX11Meta.h:13