TensorReverse.h
00001 // This file is part of Eigen, a lightweight C++ template library
00002 // for linear algebra.
00003 //
00004 // Copyright (C) 2014 Navdeep Jaitly <ndjaitly@google.com>
00005 //                    Benoit Steiner <benoit.steiner.goog@gmail.com>
00006 //
00007 // This Source Code Form is subject to the terms of the Mozilla
00008 // Public License v. 2.0. If a copy of the MPL was not distributed
00009 // with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
00010 
00011 #ifndef EIGEN_CXX11_TENSOR_TENSOR_REVERSE_H
00012 #define EIGEN_CXX11_TENSOR_TENSOR_REVERSE_H
00013 namespace Eigen {
00014 
00021 namespace internal {
00022 template<typename ReverseDimensions, typename XprType>
00023 struct traits<TensorReverseOp<ReverseDimensions,
00024                               XprType> > : public traits<XprType>
00025 {
00026   typedef typename XprType::Scalar Scalar;
00027   typedef traits<XprType> XprTraits;
00028   typedef typename XprTraits::StorageKind StorageKind;
00029   typedef typename XprTraits::Index Index;
00030   typedef typename XprType::Nested Nested;
00031   typedef typename remove_reference<Nested>::type _Nested;
00032   static const int NumDimensions = XprTraits::NumDimensions;
00033   static const int Layout = XprTraits::Layout;
00034 };
00035 
00036 template<typename ReverseDimensions, typename XprType>
00037 struct eval<TensorReverseOp<ReverseDimensions, XprType>, Eigen::Dense>
00038 {
00039   typedef const TensorReverseOp<ReverseDimensions, XprType>& type;
00040 };
00041 
00042 template<typename ReverseDimensions, typename XprType>
00043 struct nested<TensorReverseOp<ReverseDimensions, XprType>, 1,
00044             typename eval<TensorReverseOp<ReverseDimensions, XprType> >::type>
00045 {
00046   typedef TensorReverseOp<ReverseDimensions, XprType> type;
00047 };
00048 
00049 }  // end namespace internal
00050 
00051 template<typename ReverseDimensions, typename XprType>
00052 class TensorReverseOp : public TensorBase<TensorReverseOp<ReverseDimensions,
00053                                           XprType>, WriteAccessors>
00054 {
00055   public:
00056   typedef typename Eigen::internal::traits<TensorReverseOp>::Scalar Scalar;
00057   typedef typename Eigen::NumTraits<Scalar>::Real RealScalar;
00058   typedef typename XprType::CoeffReturnType CoeffReturnType;
00059   typedef typename Eigen::internal::nested<TensorReverseOp>::type Nested;
00060   typedef typename Eigen::internal::traits<TensorReverseOp>::StorageKind
00061                                                                     StorageKind;
00062   typedef typename Eigen::internal::traits<TensorReverseOp>::Index Index;
00063 
00064   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorReverseOp(
00065       const XprType& expr, const ReverseDimensions& reverse_dims)
00066       : m_xpr(expr), m_reverse_dims(reverse_dims) { }
00067 
00068     EIGEN_DEVICE_FUNC
00069     const ReverseDimensions& reverse() const { return m_reverse_dims; }
00070 
00071     EIGEN_DEVICE_FUNC
00072     const typename internal::remove_all<typename XprType::Nested>::type&
00073     expression() const { return m_xpr; }
00074 
00075     EIGEN_DEVICE_FUNC
00076     EIGEN_STRONG_INLINE TensorReverseOp& operator = (const TensorReverseOp& other)
00077     {
00078       typedef TensorAssignOp<TensorReverseOp, const TensorReverseOp> Assign;
00079       Assign assign(*this, other);
00080       internal::TensorExecutor<const Assign, DefaultDevice>::run(assign, DefaultDevice());
00081       return *this;
00082     }
00083 
00084     template<typename OtherDerived>
00085     EIGEN_DEVICE_FUNC
00086     EIGEN_STRONG_INLINE TensorReverseOp& operator = (const OtherDerived& other)
00087     {
00088       typedef TensorAssignOp<TensorReverseOp, const OtherDerived> Assign;
00089       Assign assign(*this, other);
00090       internal::TensorExecutor<const Assign, DefaultDevice>::run(assign, DefaultDevice());
00091       return *this;
00092     }
00093 
00094   protected:
00095     typename XprType::Nested m_xpr;
00096     const ReverseDimensions m_reverse_dims;
00097 };
00098 
00099 // Eval as rvalue
00100 template<typename ReverseDimensions, typename ArgType, typename Device>
00101 struct TensorEvaluator<const TensorReverseOp<ReverseDimensions, ArgType>, Device>
00102 {
00103   typedef TensorReverseOp<ReverseDimensions, ArgType> XprType;
00104   typedef typename XprType::Index Index;
00105   static const int NumDims = internal::array_size<ReverseDimensions>::value;
00106   typedef DSizes<Index, NumDims> Dimensions;
00107   typedef typename XprType::Scalar Scalar;
00108   typedef typename XprType::CoeffReturnType CoeffReturnType;
00109   typedef typename PacketType<CoeffReturnType, Device>::type PacketReturnType;
00110   static const int PacketSize = internal::unpacket_traits<PacketReturnType>::size;
00111 
00112   enum {
00113     IsAligned = false,
00114     PacketAccess = TensorEvaluator<ArgType, Device>::PacketAccess,
00115     Layout = TensorEvaluator<ArgType, Device>::Layout,
00116     CoordAccess = false,  // to be implemented
00117     RawAccess = false
00118   };
00119 
00120   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorEvaluator(const XprType& op,
00121                                                         const Device& device)
00122       : m_impl(op.expression(), device), m_reverse(op.reverse())
00123   {
00124     // Reversing a scalar isn't supported yet. It would be a no-op anyway.
00125     EIGEN_STATIC_ASSERT((NumDims > 0), YOU_MADE_A_PROGRAMMING_MISTAKE);
00126 
00127     // Compute strides
00128     m_dimensions = m_impl.dimensions();
00129     if (static_cast<int>(Layout) == static_cast<int>(ColMajor)) {
00130       m_strides[0] = 1;
00131       for (int i = 1; i < NumDims; ++i) {
00132         m_strides[i] = m_strides[i-1] * m_dimensions[i-1];
00133       }
00134     } else {
00135       m_strides[NumDims-1] = 1;
00136       for (int i = NumDims - 2; i >= 0; --i) {
00137         m_strides[i] = m_strides[i+1] * m_dimensions[i+1];
00138       }
00139     }
00140   }
00141 
00142   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
00143   const Dimensions& dimensions() const { return m_dimensions; }
00144 
00145   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool evalSubExprsIfNeeded(Scalar*) {
00146     m_impl.evalSubExprsIfNeeded(NULL);
00147     return true;
00148   }
00149   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void cleanup() {
00150     m_impl.cleanup();
00151   }
00152 
00153   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index reverseIndex(
00154       Index index) const {
00155     eigen_assert(index < dimensions().TotalSize());
00156     Index inputIndex = 0;
00157     if (static_cast<int>(Layout) == static_cast<int>(ColMajor)) {
00158       for (int i = NumDims - 1; i > 0; --i) {
00159         Index idx = index / m_strides[i];
00160         index -= idx * m_strides[i];
00161         if (m_reverse[i]) {
00162           idx = m_dimensions[i] - idx - 1;
00163         }
00164         inputIndex += idx * m_strides[i] ;
00165       }
00166       if (m_reverse[0]) {
00167         inputIndex += (m_dimensions[0] - index - 1);
00168       } else {
00169         inputIndex += index;
00170       }
00171     } else {
00172       for (int i = 0; i < NumDims - 1; ++i) {
00173         Index idx = index / m_strides[i];
00174         index -= idx * m_strides[i];
00175         if (m_reverse[i]) {
00176           idx = m_dimensions[i] - idx - 1;
00177         }
00178         inputIndex += idx * m_strides[i] ;
00179       }
00180       if (m_reverse[NumDims-1]) {
00181         inputIndex += (m_dimensions[NumDims-1] - index - 1);
00182       } else {
00183         inputIndex += index;
00184       }
00185     }
00186     return inputIndex;
00187   }
00188 
00189   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(
00190       Index index) const  {
00191     return m_impl.coeff(reverseIndex(index));
00192   }
00193 
00194   template<int LoadMode>
00195   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
00196   PacketReturnType packet(Index index) const
00197   {
00198     EIGEN_STATIC_ASSERT((PacketSize > 1), YOU_MADE_A_PROGRAMMING_MISTAKE)
00199     eigen_assert(index+PacketSize-1 < dimensions().TotalSize());
00200 
00201     // TODO(ndjaitly): write a better packing routine that uses
00202     // local structure.
00203     EIGEN_ALIGN_MAX typename internal::remove_const<CoeffReturnType>::type
00204                                                             values[PacketSize];
00205     for (int i = 0; i < PacketSize; ++i) {
00206       values[i] = coeff(index+i);
00207     }
00208     PacketReturnType rslt = internal::pload<PacketReturnType>(values);
00209     return rslt;
00210   }
00211 
00212   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorOpCost costPerCoeff(bool vectorized) const {
00213     double compute_cost = NumDims * (2 * TensorOpCost::AddCost<Index>() +
00214                                      2 * TensorOpCost::MulCost<Index>() +
00215                                      TensorOpCost::DivCost<Index>());
00216     for (int i = 0; i < NumDims; ++i) {
00217       if (m_reverse[i]) {
00218         compute_cost += 2 * TensorOpCost::AddCost<Index>();
00219       }
00220     }
00221     return m_impl.costPerCoeff(vectorized) +
00222            TensorOpCost(0, 0, compute_cost, false /* vectorized */, PacketSize);
00223   }
00224 
00225   EIGEN_DEVICE_FUNC Scalar* data() const { return NULL; }
00226 
00227  protected:
00228   Dimensions m_dimensions;
00229   array<Index, NumDims> m_strides;
00230   TensorEvaluator<ArgType, Device> m_impl;
00231   ReverseDimensions m_reverse;
00232 };
00233 
00234 // Eval as lvalue
00235 
00236 template <typename ReverseDimensions, typename ArgType, typename Device>
00237 struct TensorEvaluator<TensorReverseOp<ReverseDimensions, ArgType>, Device>
00238     : public TensorEvaluator<const TensorReverseOp<ReverseDimensions, ArgType>,
00239                              Device> {
00240   typedef TensorEvaluator<const TensorReverseOp<ReverseDimensions, ArgType>,
00241                           Device> Base;
00242   typedef TensorReverseOp<ReverseDimensions, ArgType> XprType;
00243   typedef typename XprType::Index Index;
00244   static const int NumDims = internal::array_size<ReverseDimensions>::value;
00245   typedef DSizes<Index, NumDims> Dimensions;
00246 
00247   enum {
00248     IsAligned = false,
00249     PacketAccess = TensorEvaluator<ArgType, Device>::PacketAccess,
00250     Layout = TensorEvaluator<ArgType, Device>::Layout,
00251     CoordAccess = false,  // to be implemented
00252     RawAccess = false
00253   };
00254   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorEvaluator(const XprType& op,
00255                                                         const Device& device)
00256       : Base(op, device) {}
00257 
00258   typedef typename XprType::Scalar Scalar;
00259   typedef typename XprType::CoeffReturnType CoeffReturnType;
00260   typedef typename PacketType<CoeffReturnType, Device>::type PacketReturnType;
00261   static const int PacketSize = internal::unpacket_traits<PacketReturnType>::size;
00262 
00263   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
00264   const Dimensions& dimensions() const { return this->m_dimensions; }
00265 
00266   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& coeffRef(Index index) {
00267     return this->m_impl.coeffRef(this->reverseIndex(index));
00268   }
00269 
00270   template <int StoreMode> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
00271   void writePacket(Index index, const PacketReturnType& x) {
00272     EIGEN_STATIC_ASSERT((PacketSize > 1), YOU_MADE_A_PROGRAMMING_MISTAKE)
00273     eigen_assert(index+PacketSize-1 < dimensions().TotalSize());
00274 
00275     // This code is pilfered from TensorMorphing.h
00276     EIGEN_ALIGN_MAX CoeffReturnType values[PacketSize];
00277     internal::pstore<CoeffReturnType, PacketReturnType>(values, x);
00278     for (int i = 0; i < PacketSize; ++i) {
00279       this->coeffRef(index+i) = values[i];
00280     }
00281   }
00282 
00283 };
00284 
00285 
00286 }  // end namespace Eigen
00287 
00288 #endif // EIGEN_CXX11_TENSOR_TENSOR_REVERSE_H
 All Classes Functions Variables Typedefs Enumerator