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  // Compute strides
123  m_dimensions = m_impl.dimensions();
124  if (static_cast<int>(Layout) == static_cast<int>(ColMajor)) {
125  m_strides[0] = 1;
126  for (int i = 1; i < NumDims; ++i) {
127  m_strides[i] = m_strides[i-1] * m_dimensions[i-1];
128  }
129  } else {
130  m_strides[NumDims-1] = 1;
131  for (int i = NumDims - 2; i >= 0; --i) {
132  m_strides[i] = m_strides[i+1] * m_dimensions[i+1];
133  }
134  }
135  }
136 
137  typedef typename XprType::Scalar Scalar;
138  typedef typename XprType::CoeffReturnType CoeffReturnType;
139  typedef typename XprType::PacketReturnType PacketReturnType;
140 
141  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
142  const Dimensions& dimensions() const { return m_dimensions; }
143 
144  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool evalSubExprsIfNeeded(Scalar*) {
145  m_impl.evalSubExprsIfNeeded(NULL);
146  return true;
147  }
148  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void cleanup() {
149  m_impl.cleanup();
150  }
151 
152  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index reverseIndex(
153  Index index) const {
154  eigen_assert(index < dimensions().TotalSize());
155  Index inputIndex = 0;
156  if (static_cast<int>(Layout) == static_cast<int>(ColMajor)) {
157  for (int i = NumDims - 1; i > 0; --i) {
158  Index idx = index / m_strides[i];
159  index -= idx * m_strides[i];
160  if (m_reverse[i]) {
161  idx = m_dimensions[i] - idx - 1;
162  }
163  inputIndex += idx * m_strides[i] ;
164  }
165  if (m_reverse[0]) {
166  inputIndex += (m_dimensions[0] - index - 1);
167  } else {
168  inputIndex += index;
169  }
170  } else {
171  for (int i = 0; i < NumDims - 1; ++i) {
172  Index idx = index / m_strides[i];
173  index -= idx * m_strides[i];
174  if (m_reverse[i]) {
175  idx = m_dimensions[i] - idx - 1;
176  }
177  inputIndex += idx * m_strides[i] ;
178  }
179  if (m_reverse[NumDims-1]) {
180  inputIndex += (m_dimensions[NumDims-1] - index - 1);
181  } else {
182  inputIndex += index;
183  }
184  }
185  return inputIndex;
186  }
187 
188  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(
189  Index index) const {
190  return m_impl.coeff(reverseIndex(index));
191  }
192 
193  template<int LoadMode>
194  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
195  PacketReturnType packet(Index index) const
196  {
197  const int packetSize = internal::unpacket_traits<PacketReturnType>::size;
198  EIGEN_STATIC_ASSERT(packetSize > 1, YOU_MADE_A_PROGRAMMING_MISTAKE)
199  eigen_assert(index+packetSize-1 < dimensions().TotalSize());
200 
201  // TODO(ndjaitly): write a better packing routine that uses
202  // local structure.
203  EIGEN_ALIGN_MAX typename internal::remove_const<CoeffReturnType>::type
204  values[packetSize];
205  for (int i = 0; i < packetSize; ++i) {
206  values[i] = coeff(index+i);
207  }
208  PacketReturnType rslt = internal::pload<PacketReturnType>(values);
209  return rslt;
210  }
211 
212  EIGEN_DEVICE_FUNC Scalar* data() const { return NULL; }
213 
214  protected:
215  Dimensions m_dimensions;
216  array<Index, NumDims> m_strides;
217  TensorEvaluator<ArgType, Device> m_impl;
218  ReverseDimensions m_reverse;
219 };
220 
221 // Eval as lvalue
222 
223 template <typename ReverseDimensions, typename ArgType, typename Device>
224 struct TensorEvaluator<TensorReverseOp<ReverseDimensions, ArgType>, Device>
225  : public TensorEvaluator<const TensorReverseOp<ReverseDimensions, ArgType>,
226  Device> {
227  typedef TensorEvaluator<const TensorReverseOp<ReverseDimensions, ArgType>,
228  Device> Base;
229  typedef TensorReverseOp<ReverseDimensions, ArgType> XprType;
230  typedef typename XprType::Index Index;
231  static const int NumDims = internal::array_size<ReverseDimensions>::value;
232  typedef DSizes<Index, NumDims> Dimensions;
233 
234  enum {
235  IsAligned = false,
236  PacketAccess = TensorEvaluator<ArgType, Device>::PacketAccess,
237  Layout = TensorEvaluator<ArgType, Device>::Layout,
238  CoordAccess = false, // to be implemented
239  };
240  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorEvaluator(const XprType& op,
241  const Device& device)
242  : Base(op, device) {}
243 
244  typedef typename XprType::Scalar Scalar;
245  typedef typename XprType::CoeffReturnType CoeffReturnType;
246  typedef typename XprType::PacketReturnType PacketReturnType;
247 
248  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
249  const Dimensions& dimensions() const { return this->m_dimensions; }
250 
251  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& coeffRef(Index index) {
252  return this->m_impl.coeffRef(this->reverseIndex(index));
253  }
254 
255  template <int StoreMode> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
256  void writePacket(Index index, const PacketReturnType& x) {
257  const int packetSize = internal::unpacket_traits<PacketReturnType>::size;
258  EIGEN_STATIC_ASSERT(packetSize > 1, YOU_MADE_A_PROGRAMMING_MISTAKE)
259  eigen_assert(index+packetSize-1 < dimensions().TotalSize());
260 
261  // This code is pilfered from TensorMorphing.h
262  EIGEN_ALIGN_MAX CoeffReturnType values[packetSize];
263  internal::pstore<CoeffReturnType, PacketReturnType>(values, x);
264  for (int i = 0; i < packetSize; ++i) {
265  this->coeffRef(index+i) = values[i];
266  }
267  }
268 
269 };
270 
271 
272 } // end namespace Eigen
273 
274 #endif // EIGEN_CXX11_TENSOR_TENSOR_REVERSE_H
Namespace containing all symbols from the Eigen library.
Definition: CXX11Meta.h:13