TensorFunctors.h
00001 // This file is part of Eigen, a lightweight C++ template library
00002 // for linear algebra.
00003 //
00004 // Copyright (C) 2014 Benoit Steiner <benoit.steiner.goog@gmail.com>
00005 //
00006 // This Source Code Form is subject to the terms of the Mozilla
00007 // Public License v. 2.0. If a copy of the MPL was not distributed
00008 // with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
00009 
00010 #ifndef EIGEN_CXX11_TENSOR_TENSOR_FUNCTORS_H
00011 #define EIGEN_CXX11_TENSOR_TENSOR_FUNCTORS_H
00012 
00013 namespace Eigen {
00014 namespace internal {
00015 
00016 
00020 template <typename Scalar>
00021 struct scalar_mod_op {
00022   EIGEN_DEVICE_FUNC scalar_mod_op(const Scalar& divisor) : m_divisor(divisor) {}
00023   EIGEN_DEVICE_FUNC inline Scalar operator() (const Scalar& a) const { return a % m_divisor; }
00024   const Scalar m_divisor;
00025 };
00026 template <typename Scalar>
00027 struct functor_traits<scalar_mod_op<Scalar> >
00028 { enum { Cost = scalar_div_cost<Scalar,false>::value, PacketAccess = false }; };
00029 
00030 
00034 template <typename Scalar>
00035 struct scalar_mod2_op {
00036   EIGEN_EMPTY_STRUCT_CTOR(scalar_mod2_op);
00037   EIGEN_DEVICE_FUNC inline Scalar operator() (const Scalar& a, const Scalar& b) const { return a % b; }
00038 };
00039 template <typename Scalar>
00040 struct functor_traits<scalar_mod2_op<Scalar> >
00041 { enum { Cost = scalar_div_cost<Scalar,false>::value, PacketAccess = false }; };
00042 
00043 template <typename Scalar>
00044 struct scalar_fmod_op {
00045   EIGEN_EMPTY_STRUCT_CTOR(scalar_fmod_op);
00046   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar
00047   operator()(const Scalar& a, const Scalar& b) const {
00048     return numext::fmod(a, b);
00049   }
00050 };
00051 template <typename Scalar>
00052 struct functor_traits<scalar_fmod_op<Scalar> > {
00053   enum { Cost = 13,  // Reciprocal throughput of FPREM on Haswell.
00054          PacketAccess = false };
00055 };
00056 
00057 
00062 template <typename T>
00063 struct scalar_sigmoid_op {
00064   EIGEN_EMPTY_STRUCT_CTOR(scalar_sigmoid_op)
00065   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T operator()(const T& x) const {
00066     const T one = T(1);
00067     return one / (one + numext::exp(-x));
00068   }
00069 
00070   template <typename Packet> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
00071   Packet packetOp(const Packet& x) const {
00072     const Packet one = pset1<Packet>(T(1));
00073     return pdiv(one, padd(one, pexp(pnegate(x))));
00074   }
00075 };
00076 
00077 template <typename T>
00078 struct functor_traits<scalar_sigmoid_op<T> > {
00079   enum {
00080     Cost = NumTraits<T>::AddCost * 2 + NumTraits<T>::MulCost * 6,
00081     PacketAccess = packet_traits<T>::HasAdd && packet_traits<T>::HasDiv &&
00082                    packet_traits<T>::HasNegate && packet_traits<T>::HasExp
00083   };
00084 };
00085 
00086 
00087 template<typename Reducer, typename Device>
00088 struct reducer_traits {
00089   enum {
00090     Cost = 1,
00091     PacketAccess = false
00092   };
00093 };
00094 
00095 // Standard reduction functors
00096 template <typename T> struct SumReducer
00097 {
00098   static const bool PacketAccess = packet_traits<T>::HasAdd;
00099   static const bool IsStateful = false;
00100 
00101   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void reduce(const T t, T* accum) const {
00102     internal::scalar_sum_op<T> sum_op;
00103     *accum = sum_op(*accum, t);
00104   }
00105   template <typename Packet>
00106   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void reducePacket(const Packet& p, Packet* accum) const {
00107     (*accum) = padd<Packet>(*accum, p);
00108   }
00109 
00110   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T initialize() const {
00111     internal::scalar_cast_op<int, T> conv;
00112     return conv(0);
00113   }
00114   template <typename Packet>
00115   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet initializePacket() const {
00116     return pset1<Packet>(initialize());
00117   }
00118   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T finalize(const T accum) const {
00119     return accum;
00120   }
00121   template <typename Packet>
00122   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet finalizePacket(const Packet& vaccum) const {
00123     return vaccum;
00124   }
00125   template <typename Packet>
00126   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T finalizeBoth(const T saccum, const Packet& vaccum) const {
00127     internal::scalar_sum_op<T> sum_op;
00128     return sum_op(saccum, predux(vaccum));
00129   }
00130 };
00131 
00132 template <typename T, typename Device>
00133 struct reducer_traits<SumReducer<T>, Device> {
00134   enum {
00135     Cost = NumTraits<T>::AddCost,
00136     PacketAccess = PacketType<T, Device>::HasAdd
00137   };
00138 };
00139 
00140 
00141 template <typename T> struct MeanReducer
00142 {
00143   static const bool PacketAccess = packet_traits<T>::HasAdd && !NumTraits<T>::IsInteger;
00144   static const bool IsStateful = true;
00145 
00146   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
00147   MeanReducer() : scalarCount_(0), packetCount_(0) { }
00148 
00149   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void reduce(const T t, T* accum) {
00150     internal::scalar_sum_op<T> sum_op;
00151     *accum = sum_op(*accum, t);
00152     scalarCount_++;
00153   }
00154   template <typename Packet>
00155   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void reducePacket(const Packet& p, Packet* accum) {
00156     (*accum) = padd<Packet>(*accum, p);
00157     packetCount_++;
00158   }
00159 
00160   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T initialize() const {
00161     internal::scalar_cast_op<int, T> conv;
00162     return conv(0);
00163   }
00164   template <typename Packet>
00165   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet initializePacket() const {
00166     return pset1<Packet>(initialize());
00167   }
00168   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T finalize(const T accum) const {
00169     return accum / scalarCount_;
00170   }
00171   template <typename Packet>
00172   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet finalizePacket(const Packet& vaccum) const {
00173     return pdiv(vaccum, pset1<Packet>(packetCount_));
00174   }
00175   template <typename Packet>
00176   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T finalizeBoth(const T saccum, const Packet& vaccum) const {
00177     internal::scalar_sum_op<T> sum_op;
00178     return sum_op(saccum, predux(vaccum)) / (scalarCount_ + packetCount_ * unpacket_traits<Packet>::size);
00179   }
00180 
00181   protected:
00182     DenseIndex scalarCount_;
00183     DenseIndex packetCount_;
00184 };
00185 
00186 template <typename T, typename Device>
00187 struct reducer_traits<MeanReducer<T>, Device> {
00188   enum {
00189     Cost = NumTraits<T>::AddCost,
00190     PacketAccess = PacketType<T, Device>::HasAdd
00191   };
00192 };
00193 
00194 
00195 template <typename T, bool IsMax = true, bool IsInteger = true>
00196 struct MinMaxBottomValue {
00197   EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE T bottom_value() {
00198     return Eigen::NumTraits<T>::lowest();
00199   }
00200 };
00201 template <typename T>
00202 struct MinMaxBottomValue<T, true, false> {
00203   EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE T bottom_value() {
00204     return -Eigen::NumTraits<T>::infinity();
00205   }
00206 };
00207 template <typename T>
00208 struct MinMaxBottomValue<T, false, true> {
00209   EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE T bottom_value() {
00210     return Eigen::NumTraits<T>::highest();
00211   }
00212 };
00213 template <typename T>
00214 struct MinMaxBottomValue<T, false, false> {
00215   EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE T bottom_value() {
00216     return Eigen::NumTraits<T>::infinity();
00217   }
00218 };
00219 
00220 
00221 template <typename T> struct MaxReducer
00222 {
00223   static const bool PacketAccess = packet_traits<T>::HasMax;
00224   static const bool IsStateful = false;
00225 
00226   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void reduce(const T t, T* accum) const {
00227     if (t > *accum) { *accum = t; }
00228   }
00229   template <typename Packet>
00230   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void reducePacket(const Packet& p, Packet* accum) const {
00231     (*accum) = pmax<Packet>(*accum, p);
00232   }
00233   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T initialize() const {
00234     return MinMaxBottomValue<T, true, Eigen::NumTraits<T>::IsInteger>::bottom_value();
00235   }
00236   template <typename Packet>
00237   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet initializePacket() const {
00238     return pset1<Packet>(initialize());
00239   }
00240   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T finalize(const T accum) const {
00241     return accum;
00242   }
00243   template <typename Packet>
00244   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet finalizePacket(const Packet& vaccum) const {
00245     return vaccum;
00246   }
00247   template <typename Packet>
00248   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T finalizeBoth(const T saccum, const Packet& vaccum) const {
00249     return numext::maxi(saccum, predux_max(vaccum));
00250   }
00251 };
00252 
00253 template <typename T, typename Device>
00254 struct reducer_traits<MaxReducer<T>, Device> {
00255   enum {
00256     Cost = NumTraits<T>::AddCost,
00257     PacketAccess = PacketType<T, Device>::HasMax
00258   };
00259 };
00260 
00261 
00262 template <typename T> struct MinReducer
00263 {
00264   static const bool PacketAccess = packet_traits<T>::HasMin;
00265   static const bool IsStateful = false;
00266 
00267   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void reduce(const T t, T* accum) const {
00268     if (t < *accum) { *accum = t; }
00269   }
00270   template <typename Packet>
00271   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void reducePacket(const Packet& p, Packet* accum) const {
00272     (*accum) = pmin<Packet>(*accum, p);
00273   }
00274   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T initialize() const {
00275     return MinMaxBottomValue<T, false, Eigen::NumTraits<T>::IsInteger>::bottom_value();
00276   }
00277   template <typename Packet>
00278   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet initializePacket() const {
00279     return pset1<Packet>(initialize());
00280   }
00281   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T finalize(const T accum) const {
00282     return accum;
00283   }
00284   template <typename Packet>
00285   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet finalizePacket(const Packet& vaccum) const {
00286     return vaccum;
00287   }
00288   template <typename Packet>
00289   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T finalizeBoth(const T saccum, const Packet& vaccum) const {
00290     return numext::mini(saccum, predux_min(vaccum));
00291   }
00292 };
00293 
00294 template <typename T, typename Device>
00295 struct reducer_traits<MinReducer<T>, Device> {
00296   enum {
00297     Cost = NumTraits<T>::AddCost,
00298     PacketAccess = PacketType<T, Device>::HasMin
00299   };
00300 };
00301 
00302 
00303 template <typename T> struct ProdReducer
00304 {
00305   static const bool PacketAccess = packet_traits<T>::HasMul;
00306   static const bool IsStateful = false;
00307 
00308   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void reduce(const T t, T* accum) const {
00309     internal::scalar_product_op<T> prod_op;
00310     (*accum) = prod_op(*accum, t);
00311   }
00312   template <typename Packet>
00313   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void reducePacket(const Packet& p, Packet* accum) const {
00314     (*accum) = pmul<Packet>(*accum, p);
00315   }
00316 
00317   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T initialize() const {
00318     internal::scalar_cast_op<int, T> conv;
00319     return conv(1);
00320   }
00321   template <typename Packet>
00322   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet initializePacket() const {
00323     return pset1<Packet>(initialize());
00324   }
00325   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T finalize(const T accum) const {
00326     return accum;
00327   }
00328   template <typename Packet>
00329   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet finalizePacket(const Packet& vaccum) const {
00330     return vaccum;
00331   }
00332   template <typename Packet>
00333   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T finalizeBoth(const T saccum, const Packet& vaccum) const {
00334     internal::scalar_product_op<T> prod_op;
00335     return prod_op(saccum, predux_mul(vaccum));
00336   }
00337 };
00338 
00339 template <typename T, typename Device>
00340 struct reducer_traits<ProdReducer<T>, Device> {
00341   enum {
00342     Cost = NumTraits<T>::MulCost,
00343     PacketAccess = PacketType<T, Device>::HasMul
00344   };
00345 };
00346 
00347 
00348 struct AndReducer
00349 {
00350   static const bool PacketAccess = false;
00351   static const bool IsStateful = false;
00352 
00353   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void reduce(bool t, bool* accum) const {
00354     *accum = *accum && t;
00355   }
00356   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool initialize() const {
00357     return true;
00358   }
00359   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool finalize(bool accum) const {
00360     return accum;
00361   }
00362 };
00363 
00364 template <typename Device>
00365 struct reducer_traits<AndReducer, Device> {
00366   enum {
00367     Cost = 1,
00368     PacketAccess = false
00369   };
00370 };
00371 
00372 
00373 struct OrReducer {
00374   static const bool PacketAccess = false;
00375   static const bool IsStateful = false;
00376 
00377   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void reduce(bool t, bool* accum) const {
00378     *accum = *accum || t;
00379   }
00380   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool initialize() const {
00381     return false;
00382   }
00383   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool finalize(bool accum) const {
00384     return accum;
00385   }
00386 };
00387 
00388 template <typename Device>
00389 struct reducer_traits<OrReducer, Device> {
00390   enum {
00391     Cost = 1,
00392     PacketAccess = false
00393   };
00394 };
00395 
00396 
00397 // Argmin/Argmax reducers
00398 template <typename T> struct ArgMaxTupleReducer
00399 {
00400   static const bool PacketAccess = false;
00401   static const bool IsStateful = false;
00402 
00403   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void reduce(const T t, T* accum) const {
00404     if (t.second > accum->second) { *accum = t; }
00405   }
00406   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T initialize() const {
00407     return T(0, NumTraits<typename T::second_type>::lowest());
00408   }
00409   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T finalize(const T& accum) const {
00410     return accum;
00411   }
00412 };
00413 
00414 template <typename T, typename Device>
00415 struct reducer_traits<ArgMaxTupleReducer<T>, Device> {
00416   enum {
00417     Cost = NumTraits<T>::AddCost,
00418     PacketAccess = false
00419   };
00420 };
00421 
00422 
00423 template <typename T> struct ArgMinTupleReducer
00424 {
00425   static const bool PacketAccess = false;
00426   static const bool IsStateful = false;
00427 
00428   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void reduce(const T& t, T* accum) const {
00429     if (t.second < accum->second) { *accum = t; }
00430   }
00431   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T initialize() const {
00432     return T(0, NumTraits<typename T::second_type>::highest());
00433   }
00434   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T finalize(const T& accum) const {
00435     return accum;
00436   }
00437 };
00438 
00439 template <typename T, typename Device>
00440 struct reducer_traits<ArgMinTupleReducer<T>, Device> {
00441   enum {
00442     Cost = NumTraits<T>::AddCost,
00443     PacketAccess = false
00444   };
00445 };
00446 
00447 
00448 template <typename T, typename Index, size_t NumDims>
00449 class GaussianGenerator {
00450  public:
00451   static const bool PacketAccess = false;
00452 
00453   EIGEN_DEVICE_FUNC GaussianGenerator(const array<T, NumDims>& means,
00454                                       const array<T, NumDims>& std_devs)
00455       : m_means(means)
00456   {
00457     for (size_t i = 0; i < NumDims; ++i) {
00458       m_two_sigmas[i] = std_devs[i] * std_devs[i] * 2;
00459     }
00460   }
00461 
00462   EIGEN_DEVICE_FUNC T operator()(const array<Index, NumDims>& coordinates) const {
00463     T tmp = T(0);
00464     for (size_t i = 0; i < NumDims; ++i) {
00465       T offset = coordinates[i] - m_means[i];
00466       tmp += offset * offset / m_two_sigmas[i];
00467     }
00468     return numext::exp(-tmp);
00469   }
00470 
00471  private:
00472   array<T, NumDims> m_means;
00473   array<T, NumDims> m_two_sigmas;
00474 };
00475 
00476 template <typename T, typename Index, size_t NumDims>
00477 struct functor_traits<GaussianGenerator<T, Index, NumDims> > {
00478   enum {
00479     Cost = NumDims * (2 * NumTraits<T>::AddCost + NumTraits<T>::MulCost +
00480                       functor_traits<scalar_quotient_op<T, T> >::Cost) +
00481            functor_traits<scalar_exp_op<T> >::Cost,
00482     PacketAccess = GaussianGenerator<T, Index, NumDims>::PacketAccess
00483   };
00484 };
00485 
00486 } // end namespace internal
00487 } // end namespace Eigen
00488 
00489 #endif // EIGEN_CXX11_TENSOR_TENSOR_FUNCTORS_H
 All Classes Functions Variables Typedefs Enumerator