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 15 /** \class TensorReverse 16 * \ingroup CXX11_Tensor_Module 17 * 18 * \brief Tensor reverse elements class. 19 * 20 */ 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 XprTraits::StorageKind StorageKind; 29 typedef typename XprTraits::Index Index; 30 typedef typename XprType::Nested Nested; 31 typedef typename remove_reference<Nested>::type _Nested; 32 static const int NumDimensions = XprTraits::NumDimensions; 33 static const int Layout = XprTraits::Layout; 34 }; 35 36 template<typename ReverseDimensions, typename XprType> 37 struct eval<TensorReverseOp<ReverseDimensions, XprType>, Eigen::Dense> 38 { 39 typedef const TensorReverseOp<ReverseDimensions, XprType>& type; 40 }; 41 42 template<typename ReverseDimensions, typename XprType> 43 struct nested<TensorReverseOp<ReverseDimensions, XprType>, 1, 44 typename eval<TensorReverseOp<ReverseDimensions, XprType> >::type> 45 { 46 typedef TensorReverseOp<ReverseDimensions, XprType> type; 47 }; 48 49 } // end namespace internal 50 51 template<typename ReverseDimensions, typename XprType> 52 class TensorReverseOp : public TensorBase<TensorReverseOp<ReverseDimensions, 53 XprType>, WriteAccessors> 54 { 55 public: 56 typedef typename Eigen::internal::traits<TensorReverseOp>::Scalar Scalar; 57 typedef typename Eigen::NumTraits<Scalar>::Real RealScalar; 58 typedef typename XprType::CoeffReturnType CoeffReturnType; 59 typedef typename Eigen::internal::nested<TensorReverseOp>::type Nested; 60 typedef typename Eigen::internal::traits<TensorReverseOp>::StorageKind 61 StorageKind; 62 typedef typename Eigen::internal::traits<TensorReverseOp>::Index Index; 63 64 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorReverseOp( 65 const XprType& expr, const ReverseDimensions& reverse_dims) 66 : m_xpr(expr), m_reverse_dims(reverse_dims) { } 67 68 EIGEN_DEVICE_FUNC 69 const ReverseDimensions& reverse() const { return m_reverse_dims; } 70 71 EIGEN_DEVICE_FUNC 72 const typename internal::remove_all<typename XprType::Nested>::type& 73 expression() const { return m_xpr; } 74 75 EIGEN_DEVICE_FUNC 76 EIGEN_STRONG_INLINE TensorReverseOp& operator = (const TensorReverseOp& other) 77 { 78 typedef TensorAssignOp<TensorReverseOp, const TensorReverseOp> Assign; 79 Assign assign(*this, other); 80 internal::TensorExecutor<const Assign, DefaultDevice>::run(assign, DefaultDevice()); 81 return *this; 82 } 83 84 template<typename OtherDerived> 85 EIGEN_DEVICE_FUNC 86 EIGEN_STRONG_INLINE TensorReverseOp& operator = (const OtherDerived& other) 87 { 88 typedef TensorAssignOp<TensorReverseOp, const OtherDerived> Assign; 89 Assign assign(*this, other); 90 internal::TensorExecutor<const Assign, DefaultDevice>::run(assign, DefaultDevice()); 91 return *this; 92 } 93 94 protected: 95 typename XprType::Nested m_xpr; 96 const ReverseDimensions m_reverse_dims; 97 }; 98 99 // Eval as rvalue 100 template<typename ReverseDimensions, typename ArgType, typename Device> 101 struct TensorEvaluator<const TensorReverseOp<ReverseDimensions, ArgType>, Device> 102 { 103 typedef TensorReverseOp<ReverseDimensions, ArgType> XprType; 104 typedef typename XprType::Index Index; 105 static const int NumDims = internal::array_size<ReverseDimensions>::value; 106 typedef DSizes<Index, NumDims> Dimensions; 107 typedef typename XprType::Scalar Scalar; 108 typedef typename XprType::CoeffReturnType CoeffReturnType; 109 typedef typename PacketType<CoeffReturnType, Device>::type PacketReturnType; 110 static const int PacketSize = internal::unpacket_traits<PacketReturnType>::size; 111 112 enum { 113 IsAligned = false, 114 PacketAccess = TensorEvaluator<ArgType, Device>::PacketAccess, 115 Layout = TensorEvaluator<ArgType, Device>::Layout, 116 CoordAccess = false, // to be implemented 117 RawAccess = false 118 }; 119 120 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorEvaluator(const XprType& op, 121 const Device& device) 122 : m_impl(op.expression(), device), m_reverse(op.reverse()) 123 { 124 // Reversing a scalar isn't supported yet. It would be a no-op anyway. 125 EIGEN_STATIC_ASSERT((NumDims > 0), YOU_MADE_A_PROGRAMMING_MISTAKE); 126 127 // Compute strides 128 m_dimensions = m_impl.dimensions(); 129 if (static_cast<int>(Layout) == static_cast<int>(ColMajor)) { 130 m_strides[0] = 1; 131 for (int i = 1; i < NumDims; ++i) { 132 m_strides[i] = m_strides[i-1] * m_dimensions[i-1]; 133 } 134 } else { 135 m_strides[NumDims-1] = 1; 136 for (int i = NumDims - 2; i >= 0; --i) { 137 m_strides[i] = m_strides[i+1] * m_dimensions[i+1]; 138 } 139 } 140 } 141 142 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE 143 const Dimensions& dimensions() const { return m_dimensions; } 144 145 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool evalSubExprsIfNeeded(Scalar*) { 146 m_impl.evalSubExprsIfNeeded(NULL); 147 return true; 148 } 149 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void cleanup() { 150 m_impl.cleanup(); 151 } 152 153 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index reverseIndex( 154 Index index) const { 155 eigen_assert(index < dimensions().TotalSize()); 156 Index inputIndex = 0; 157 if (static_cast<int>(Layout) == static_cast<int>(ColMajor)) { 158 for (int i = NumDims - 1; i > 0; --i) { 159 Index idx = index / m_strides[i]; 160 index -= idx * m_strides[i]; 161 if (m_reverse[i]) { 162 idx = m_dimensions[i] - idx - 1; 163 } 164 inputIndex += idx * m_strides[i] ; 165 } 166 if (m_reverse[0]) { 167 inputIndex += (m_dimensions[0] - index - 1); 168 } else { 169 inputIndex += index; 170 } 171 } else { 172 for (int i = 0; i < NumDims - 1; ++i) { 173 Index idx = index / m_strides[i]; 174 index -= idx * m_strides[i]; 175 if (m_reverse[i]) { 176 idx = m_dimensions[i] - idx - 1; 177 } 178 inputIndex += idx * m_strides[i] ; 179 } 180 if (m_reverse[NumDims-1]) { 181 inputIndex += (m_dimensions[NumDims-1] - index - 1); 182 } else { 183 inputIndex += index; 184 } 185 } 186 return inputIndex; 187 } 188 189 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff( 190 Index index) const { 191 return m_impl.coeff(reverseIndex(index)); 192 } 193 194 template<int LoadMode> 195 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE 196 PacketReturnType packet(Index index) const 197 { 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 EIGEN_STRONG_INLINE TensorOpCost costPerCoeff(bool vectorized) const { 213 double compute_cost = NumDims * (2 * TensorOpCost::AddCost<Index>() + 214 2 * TensorOpCost::MulCost<Index>() + 215 TensorOpCost::DivCost<Index>()); 216 for (int i = 0; i < NumDims; ++i) { 217 if (m_reverse[i]) { 218 compute_cost += 2 * TensorOpCost::AddCost<Index>(); 219 } 220 } 221 return m_impl.costPerCoeff(vectorized) + 222 TensorOpCost(0, 0, compute_cost, false /* vectorized */, PacketSize); 223 } 224 225 EIGEN_DEVICE_FUNC Scalar* data() const { return NULL; } 226 227 protected: 228 Dimensions m_dimensions; 229 array<Index, NumDims> m_strides; 230 TensorEvaluator<ArgType, Device> m_impl; 231 ReverseDimensions m_reverse; 232 }; 233 234 // Eval as lvalue 235 236 template <typename ReverseDimensions, typename ArgType, typename Device> 237 struct TensorEvaluator<TensorReverseOp<ReverseDimensions, ArgType>, Device> 238 : public TensorEvaluator<const TensorReverseOp<ReverseDimensions, ArgType>, 239 Device> { 240 typedef TensorEvaluator<const TensorReverseOp<ReverseDimensions, ArgType>, 241 Device> Base; 242 typedef TensorReverseOp<ReverseDimensions, ArgType> XprType; 243 typedef typename XprType::Index Index; 244 static const int NumDims = internal::array_size<ReverseDimensions>::value; 245 typedef DSizes<Index, NumDims> Dimensions; 246 247 enum { 248 IsAligned = false, 249 PacketAccess = TensorEvaluator<ArgType, Device>::PacketAccess, 250 Layout = TensorEvaluator<ArgType, Device>::Layout, 251 CoordAccess = false, // to be implemented 252 RawAccess = false 253 }; 254 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorEvaluator(const XprType& op, 255 const Device& device) 256 : Base(op, device) {} 257 258 typedef typename XprType::Scalar Scalar; 259 typedef typename XprType::CoeffReturnType CoeffReturnType; 260 typedef typename PacketType<CoeffReturnType, Device>::type PacketReturnType; 261 static const int PacketSize = internal::unpacket_traits<PacketReturnType>::size; 262 263 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE 264 const Dimensions& dimensions() const { return this->m_dimensions; } 265 266 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& coeffRef(Index index) { 267 return this->m_impl.coeffRef(this->reverseIndex(index)); 268 } 269 270 template <int StoreMode> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE 271 void writePacket(Index index, const PacketReturnType& x) { 272 EIGEN_STATIC_ASSERT((PacketSize > 1), YOU_MADE_A_PROGRAMMING_MISTAKE) 273 eigen_assert(index+PacketSize-1 < dimensions().TotalSize()); 274 275 // This code is pilfered from TensorMorphing.h 276 EIGEN_ALIGN_MAX CoeffReturnType values[PacketSize]; 277 internal::pstore<CoeffReturnType, PacketReturnType>(values, x); 278 for (int i = 0; i < PacketSize; ++i) { 279 this->coeffRef(index+i) = values[i]; 280 } 281 } 282 283 }; 284 285 286 } // end namespace Eigen 287 288 #endif // EIGEN_CXX11_TENSOR_TENSOR_REVERSE_H 289