TensorReverse.h
1 // This file is part of Eigen, a lightweight C++ template library
2 // for linear algebra.
3 //
4 // Copyright (C) 2014 Navdeep Jaitly <ndjaitly@google.com>
5 // 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_REVERSE_H
12 #define EIGEN_CXX11_TENSOR_TENSOR_REVERSE_H
13 namespace Eigen {
14 
21 namespace internal {
22 template<typename ReverseDimensions, typename XprType>
23 struct traits<TensorReverseOp<ReverseDimensions,
24  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 ReverseDimensions, typename XprType>
38 struct eval<TensorReverseOp<ReverseDimensions, XprType>, Eigen::Dense>
39 {
40  typedef const TensorReverseOp<ReverseDimensions, XprType>& type;
41 };
42 
43 template<typename ReverseDimensions, typename XprType>
44 struct nested<TensorReverseOp<ReverseDimensions, XprType>, 1,
45  typename eval<TensorReverseOp<ReverseDimensions, XprType> >::type>
46 {
47  typedef TensorReverseOp<ReverseDimensions, XprType> type;
48 };
49 
50 } // end namespace internal
51 
52 template<typename ReverseDimensions, typename XprType>
53 class TensorReverseOp : public TensorBase<TensorReverseOp<ReverseDimensions,
54  XprType>, WriteAccessors>
55 {
56  public:
57  typedef typename Eigen::internal::traits<TensorReverseOp>::Scalar Scalar;
58  typedef typename Eigen::internal::traits<TensorReverseOp>::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<TensorReverseOp>::type Nested;
63  typedef typename Eigen::internal::traits<TensorReverseOp>::StorageKind
64  StorageKind;
65  typedef typename Eigen::internal::traits<TensorReverseOp>::Index Index;
66 
67  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorReverseOp(
68  const XprType& expr, const ReverseDimensions& reverse_dims)
69  : m_xpr(expr), m_reverse_dims(reverse_dims) { }
70 
71  EIGEN_DEVICE_FUNC
72  const ReverseDimensions& reverse() const { return m_reverse_dims; }
73 
74  EIGEN_DEVICE_FUNC
75  const typename internal::remove_all<typename XprType::Nested>::type&
76  expression() const { return m_xpr; }
77 
78  EIGEN_DEVICE_FUNC
79  EIGEN_STRONG_INLINE TensorReverseOp& operator = (const TensorReverseOp& other)
80  {
81  typedef TensorAssignOp<TensorReverseOp, const TensorReverseOp> Assign;
82  Assign assign(*this, other);
83  internal::TensorExecutor<const Assign, DefaultDevice>::run(assign, DefaultDevice());
84  return *this;
85  }
86 
87  template<typename OtherDerived>
88  EIGEN_DEVICE_FUNC
89  EIGEN_STRONG_INLINE TensorReverseOp& operator = (const OtherDerived& other)
90  {
91  typedef TensorAssignOp<TensorReverseOp, const OtherDerived> Assign;
92  Assign assign(*this, other);
93  internal::TensorExecutor<const Assign, DefaultDevice>::run(assign, DefaultDevice());
94  return *this;
95  }
96 
97  protected:
98  typename XprType::Nested m_xpr;
99  const ReverseDimensions m_reverse_dims;
100 };
101 
102 // Eval as rvalue
103 template<typename ReverseDimensions, typename ArgType, typename Device>
104 struct TensorEvaluator<const TensorReverseOp<ReverseDimensions, ArgType>, Device>
105 {
106  typedef TensorReverseOp<ReverseDimensions, ArgType> XprType;
107  typedef typename XprType::Index Index;
108  static const int NumDims = internal::array_size<ReverseDimensions>::value;
109  typedef DSizes<Index, NumDims> Dimensions;
110 
111  enum {
112  IsAligned = false,
113  PacketAccess = TensorEvaluator<ArgType, Device>::PacketAccess,
114  Layout = TensorEvaluator<ArgType, Device>::Layout,
115  CoordAccess = false, // to be implemented
116  };
117 
118  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorEvaluator(const XprType& op,
119  const Device& device)
120  : m_impl(op.expression(), device), m_reverse(op.reverse())
121  {
122  // Reversing a scalar isn't supported yet. It would be a no-op anyway.
123  EIGEN_STATIC_ASSERT(NumDims > 0, YOU_MADE_A_PROGRAMMING_MISTAKE);
124 
125  // Compute strides
126  m_dimensions = m_impl.dimensions();
127  if (static_cast<int>(Layout) == static_cast<int>(ColMajor)) {
128  m_strides[0] = 1;
129  for (int i = 1; i < NumDims; ++i) {
130  m_strides[i] = m_strides[i-1] * m_dimensions[i-1];
131  }
132  } else {
133  m_strides[NumDims-1] = 1;
134  for (int i = NumDims - 2; i >= 0; --i) {
135  m_strides[i] = m_strides[i+1] * m_dimensions[i+1];
136  }
137  }
138  }
139 
140  typedef typename XprType::Scalar Scalar;
141  typedef typename XprType::CoeffReturnType CoeffReturnType;
142  typedef typename XprType::PacketReturnType PacketReturnType;
143 
144  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
145  const Dimensions& dimensions() const { return m_dimensions; }
146 
147  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool evalSubExprsIfNeeded(Scalar*) {
148  m_impl.evalSubExprsIfNeeded(NULL);
149  return true;
150  }
151  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void cleanup() {
152  m_impl.cleanup();
153  }
154 
155  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index reverseIndex(
156  Index index) const {
157  eigen_assert(index < dimensions().TotalSize());
158  Index inputIndex = 0;
159  if (static_cast<int>(Layout) == static_cast<int>(ColMajor)) {
160  for (int i = NumDims - 1; i > 0; --i) {
161  Index idx = index / m_strides[i];
162  index -= idx * m_strides[i];
163  if (m_reverse[i]) {
164  idx = m_dimensions[i] - idx - 1;
165  }
166  inputIndex += idx * m_strides[i] ;
167  }
168  if (m_reverse[0]) {
169  inputIndex += (m_dimensions[0] - index - 1);
170  } else {
171  inputIndex += index;
172  }
173  } else {
174  for (int i = 0; i < NumDims - 1; ++i) {
175  Index idx = index / m_strides[i];
176  index -= idx * m_strides[i];
177  if (m_reverse[i]) {
178  idx = m_dimensions[i] - idx - 1;
179  }
180  inputIndex += idx * m_strides[i] ;
181  }
182  if (m_reverse[NumDims-1]) {
183  inputIndex += (m_dimensions[NumDims-1] - index - 1);
184  } else {
185  inputIndex += index;
186  }
187  }
188  return inputIndex;
189  }
190 
191  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(
192  Index index) const {
193  return m_impl.coeff(reverseIndex(index));
194  }
195 
196  template<int LoadMode>
197  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
198  PacketReturnType packet(Index index) const
199  {
200  const int packetSize = internal::unpacket_traits<PacketReturnType>::size;
201  EIGEN_STATIC_ASSERT(packetSize > 1, YOU_MADE_A_PROGRAMMING_MISTAKE)
202  eigen_assert(index+packetSize-1 < dimensions().TotalSize());
203 
204  // TODO(ndjaitly): write a better packing routine that uses
205  // local structure.
206  EIGEN_ALIGN_MAX typename internal::remove_const<CoeffReturnType>::type
207  values[packetSize];
208  for (int i = 0; i < packetSize; ++i) {
209  values[i] = coeff(index+i);
210  }
211  PacketReturnType rslt = internal::pload<PacketReturnType>(values);
212  return rslt;
213  }
214 
215  EIGEN_DEVICE_FUNC Scalar* data() const { return NULL; }
216 
217  protected:
218  Dimensions m_dimensions;
219  array<Index, NumDims> m_strides;
220  TensorEvaluator<ArgType, Device> m_impl;
221  ReverseDimensions m_reverse;
222 };
223 
224 // Eval as lvalue
225 
226 template <typename ReverseDimensions, typename ArgType, typename Device>
227 struct TensorEvaluator<TensorReverseOp<ReverseDimensions, ArgType>, Device>
228  : public TensorEvaluator<const TensorReverseOp<ReverseDimensions, ArgType>,
229  Device> {
230  typedef TensorEvaluator<const TensorReverseOp<ReverseDimensions, ArgType>,
231  Device> Base;
232  typedef TensorReverseOp<ReverseDimensions, ArgType> XprType;
233  typedef typename XprType::Index Index;
234  static const int NumDims = internal::array_size<ReverseDimensions>::value;
235  typedef DSizes<Index, NumDims> Dimensions;
236 
237  enum {
238  IsAligned = false,
239  PacketAccess = TensorEvaluator<ArgType, Device>::PacketAccess,
240  Layout = TensorEvaluator<ArgType, Device>::Layout,
241  CoordAccess = false, // to be implemented
242  };
243  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorEvaluator(const XprType& op,
244  const Device& device)
245  : Base(op, device) {}
246 
247  typedef typename XprType::Scalar Scalar;
248  typedef typename XprType::CoeffReturnType CoeffReturnType;
249  typedef typename XprType::PacketReturnType PacketReturnType;
250 
251  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
252  const Dimensions& dimensions() const { return this->m_dimensions; }
253 
254  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& coeffRef(Index index) {
255  return this->m_impl.coeffRef(this->reverseIndex(index));
256  }
257 
258  template <int StoreMode> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
259  void writePacket(Index index, const PacketReturnType& x) {
260  const int packetSize = internal::unpacket_traits<PacketReturnType>::size;
261  EIGEN_STATIC_ASSERT(packetSize > 1, YOU_MADE_A_PROGRAMMING_MISTAKE)
262  eigen_assert(index+packetSize-1 < dimensions().TotalSize());
263 
264  // This code is pilfered from TensorMorphing.h
265  EIGEN_ALIGN_MAX CoeffReturnType values[packetSize];
266  internal::pstore<CoeffReturnType, PacketReturnType>(values, x);
267  for (int i = 0; i < packetSize; ++i) {
268  this->coeffRef(index+i) = values[i];
269  }
270  }
271 
272 };
273 
274 
275 } // end namespace Eigen
276 
277 #endif // EIGEN_CXX11_TENSOR_TENSOR_REVERSE_H
Namespace containing all symbols from the Eigen library.
Definition: CXX11Meta.h:13