Home | History | Annotate | Download | only in Tensor
      1 // This file is part of Eigen, a lightweight C++ template library
      2 // for linear algebra.
      3 //
      4 // Copyright (C) 2014 Benoit Steiner <benoit.steiner.goog (at) gmail.com>
      5 //
      6 // This Source Code Form is subject to the terms of the Mozilla
      7 // Public License v. 2.0. If a copy of the MPL was not distributed
      8 // with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
      9 
     10 #ifndef EIGEN_CXX11_TENSOR_TENSOR_FUNCTORS_H
     11 #define EIGEN_CXX11_TENSOR_TENSOR_FUNCTORS_H
     12 
     13 namespace Eigen {
     14 namespace internal {
     15 
     16 
     17 /** \internal
     18  * \brief Template functor to compute the modulo between an array and a scalar.
     19  */
     20 template <typename Scalar>
     21 struct scalar_mod_op {
     22   EIGEN_DEVICE_FUNC scalar_mod_op(const Scalar& divisor) : m_divisor(divisor) {}
     23   EIGEN_DEVICE_FUNC inline Scalar operator() (const Scalar& a) const { return a % m_divisor; }
     24   const Scalar m_divisor;
     25 };
     26 template <typename Scalar>
     27 struct functor_traits<scalar_mod_op<Scalar> >
     28 { enum { Cost = scalar_div_cost<Scalar,false>::value, PacketAccess = false }; };
     29 
     30 
     31 /** \internal
     32  * \brief Template functor to compute the modulo between 2 arrays.
     33  */
     34 template <typename Scalar>
     35 struct scalar_mod2_op {
     36   EIGEN_EMPTY_STRUCT_CTOR(scalar_mod2_op);
     37   EIGEN_DEVICE_FUNC inline Scalar operator() (const Scalar& a, const Scalar& b) const { return a % b; }
     38 };
     39 template <typename Scalar>
     40 struct functor_traits<scalar_mod2_op<Scalar> >
     41 { enum { Cost = scalar_div_cost<Scalar,false>::value, PacketAccess = false }; };
     42 
     43 template <typename Scalar>
     44 struct scalar_fmod_op {
     45   EIGEN_EMPTY_STRUCT_CTOR(scalar_fmod_op);
     46   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar
     47   operator()(const Scalar& a, const Scalar& b) const {
     48     return numext::fmod(a, b);
     49   }
     50 };
     51 template <typename Scalar>
     52 struct functor_traits<scalar_fmod_op<Scalar> > {
     53   enum { Cost = 13,  // Reciprocal throughput of FPREM on Haswell.
     54          PacketAccess = false };
     55 };
     56 
     57 
     58 /** \internal
     59   * \brief Template functor to compute the sigmoid of a scalar
     60   * \sa class CwiseUnaryOp, ArrayBase::sigmoid()
     61   */
     62 template <typename T>
     63 struct scalar_sigmoid_op {
     64   EIGEN_EMPTY_STRUCT_CTOR(scalar_sigmoid_op)
     65   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T operator()(const T& x) const {
     66     const T one = T(1);
     67     return one / (one + numext::exp(-x));
     68   }
     69 
     70   template <typename Packet> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
     71   Packet packetOp(const Packet& x) const {
     72     const Packet one = pset1<Packet>(T(1));
     73     return pdiv(one, padd(one, pexp(pnegate(x))));
     74   }
     75 };
     76 
     77 template <typename T>
     78 struct functor_traits<scalar_sigmoid_op<T> > {
     79   enum {
     80     Cost = NumTraits<T>::AddCost * 2 + NumTraits<T>::MulCost * 6,
     81     PacketAccess = packet_traits<T>::HasAdd && packet_traits<T>::HasDiv &&
     82                    packet_traits<T>::HasNegate && packet_traits<T>::HasExp
     83   };
     84 };
     85 
     86 
     87 template<typename Reducer, typename Device>
     88 struct reducer_traits {
     89   enum {
     90     Cost = 1,
     91     PacketAccess = false
     92   };
     93 };
     94 
     95 // Standard reduction functors
     96 template <typename T> struct SumReducer
     97 {
     98   static const bool PacketAccess = packet_traits<T>::HasAdd;
     99   static const bool IsStateful = false;
    100 
    101   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void reduce(const T t, T* accum) const {
    102     internal::scalar_sum_op<T> sum_op;
    103     *accum = sum_op(*accum, t);
    104   }
    105   template <typename Packet>
    106   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void reducePacket(const Packet& p, Packet* accum) const {
    107     (*accum) = padd<Packet>(*accum, p);
    108   }
    109 
    110   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T initialize() const {
    111     internal::scalar_cast_op<int, T> conv;
    112     return conv(0);
    113   }
    114   template <typename Packet>
    115   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet initializePacket() const {
    116     return pset1<Packet>(initialize());
    117   }
    118   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T finalize(const T accum) const {
    119     return accum;
    120   }
    121   template <typename Packet>
    122   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet finalizePacket(const Packet& vaccum) const {
    123     return vaccum;
    124   }
    125   template <typename Packet>
    126   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T finalizeBoth(const T saccum, const Packet& vaccum) const {
    127     internal::scalar_sum_op<T> sum_op;
    128     return sum_op(saccum, predux(vaccum));
    129   }
    130 };
    131 
    132 template <typename T, typename Device>
    133 struct reducer_traits<SumReducer<T>, Device> {
    134   enum {
    135     Cost = NumTraits<T>::AddCost,
    136     PacketAccess = PacketType<T, Device>::HasAdd
    137   };
    138 };
    139 
    140 
    141 template <typename T> struct MeanReducer
    142 {
    143   static const bool PacketAccess = packet_traits<T>::HasAdd && !NumTraits<T>::IsInteger;
    144   static const bool IsStateful = true;
    145 
    146   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    147   MeanReducer() : scalarCount_(0), packetCount_(0) { }
    148 
    149   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void reduce(const T t, T* accum) {
    150     internal::scalar_sum_op<T> sum_op;
    151     *accum = sum_op(*accum, t);
    152     scalarCount_++;
    153   }
    154   template <typename Packet>
    155   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void reducePacket(const Packet& p, Packet* accum) {
    156     (*accum) = padd<Packet>(*accum, p);
    157     packetCount_++;
    158   }
    159 
    160   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T initialize() const {
    161     internal::scalar_cast_op<int, T> conv;
    162     return conv(0);
    163   }
    164   template <typename Packet>
    165   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet initializePacket() const {
    166     return pset1<Packet>(initialize());
    167   }
    168   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T finalize(const T accum) const {
    169     return accum / scalarCount_;
    170   }
    171   template <typename Packet>
    172   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet finalizePacket(const Packet& vaccum) const {
    173     return pdiv(vaccum, pset1<Packet>(packetCount_));
    174   }
    175   template <typename Packet>
    176   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T finalizeBoth(const T saccum, const Packet& vaccum) const {
    177     internal::scalar_sum_op<T> sum_op;
    178     return sum_op(saccum, predux(vaccum)) / (scalarCount_ + packetCount_ * unpacket_traits<Packet>::size);
    179   }
    180 
    181   protected:
    182     DenseIndex scalarCount_;
    183     DenseIndex packetCount_;
    184 };
    185 
    186 template <typename T, typename Device>
    187 struct reducer_traits<MeanReducer<T>, Device> {
    188   enum {
    189     Cost = NumTraits<T>::AddCost,
    190     PacketAccess = PacketType<T, Device>::HasAdd
    191   };
    192 };
    193 
    194 
    195 template <typename T, bool IsMax = true, bool IsInteger = true>
    196 struct MinMaxBottomValue {
    197   EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE T bottom_value() {
    198     return Eigen::NumTraits<T>::lowest();
    199   }
    200 };
    201 template <typename T>
    202 struct MinMaxBottomValue<T, true, false> {
    203   EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE T bottom_value() {
    204     return -Eigen::NumTraits<T>::infinity();
    205   }
    206 };
    207 template <typename T>
    208 struct MinMaxBottomValue<T, false, true> {
    209   EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE T bottom_value() {
    210     return Eigen::NumTraits<T>::highest();
    211   }
    212 };
    213 template <typename T>
    214 struct MinMaxBottomValue<T, false, false> {
    215   EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE T bottom_value() {
    216     return Eigen::NumTraits<T>::infinity();
    217   }
    218 };
    219 
    220 
    221 template <typename T> struct MaxReducer
    222 {
    223   static const bool PacketAccess = packet_traits<T>::HasMax;
    224   static const bool IsStateful = false;
    225 
    226   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void reduce(const T t, T* accum) const {
    227     if (t > *accum) { *accum = t; }
    228   }
    229   template <typename Packet>
    230   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void reducePacket(const Packet& p, Packet* accum) const {
    231     (*accum) = pmax<Packet>(*accum, p);
    232   }
    233   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T initialize() const {
    234     return MinMaxBottomValue<T, true, Eigen::NumTraits<T>::IsInteger>::bottom_value();
    235   }
    236   template <typename Packet>
    237   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet initializePacket() const {
    238     return pset1<Packet>(initialize());
    239   }
    240   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T finalize(const T accum) const {
    241     return accum;
    242   }
    243   template <typename Packet>
    244   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet finalizePacket(const Packet& vaccum) const {
    245     return vaccum;
    246   }
    247   template <typename Packet>
    248   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T finalizeBoth(const T saccum, const Packet& vaccum) const {
    249     return numext::maxi(saccum, predux_max(vaccum));
    250   }
    251 };
    252 
    253 template <typename T, typename Device>
    254 struct reducer_traits<MaxReducer<T>, Device> {
    255   enum {
    256     Cost = NumTraits<T>::AddCost,
    257     PacketAccess = PacketType<T, Device>::HasMax
    258   };
    259 };
    260 
    261 
    262 template <typename T> struct MinReducer
    263 {
    264   static const bool PacketAccess = packet_traits<T>::HasMin;
    265   static const bool IsStateful = false;
    266 
    267   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void reduce(const T t, T* accum) const {
    268     if (t < *accum) { *accum = t; }
    269   }
    270   template <typename Packet>
    271   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void reducePacket(const Packet& p, Packet* accum) const {
    272     (*accum) = pmin<Packet>(*accum, p);
    273   }
    274   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T initialize() const {
    275     return MinMaxBottomValue<T, false, Eigen::NumTraits<T>::IsInteger>::bottom_value();
    276   }
    277   template <typename Packet>
    278   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet initializePacket() const {
    279     return pset1<Packet>(initialize());
    280   }
    281   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T finalize(const T accum) const {
    282     return accum;
    283   }
    284   template <typename Packet>
    285   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet finalizePacket(const Packet& vaccum) const {
    286     return vaccum;
    287   }
    288   template <typename Packet>
    289   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T finalizeBoth(const T saccum, const Packet& vaccum) const {
    290     return numext::mini(saccum, predux_min(vaccum));
    291   }
    292 };
    293 
    294 template <typename T, typename Device>
    295 struct reducer_traits<MinReducer<T>, Device> {
    296   enum {
    297     Cost = NumTraits<T>::AddCost,
    298     PacketAccess = PacketType<T, Device>::HasMin
    299   };
    300 };
    301 
    302 
    303 template <typename T> struct ProdReducer
    304 {
    305   static const bool PacketAccess = packet_traits<T>::HasMul;
    306   static const bool IsStateful = false;
    307 
    308   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void reduce(const T t, T* accum) const {
    309     internal::scalar_product_op<T> prod_op;
    310     (*accum) = prod_op(*accum, t);
    311   }
    312   template <typename Packet>
    313   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void reducePacket(const Packet& p, Packet* accum) const {
    314     (*accum) = pmul<Packet>(*accum, p);
    315   }
    316 
    317   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T initialize() const {
    318     internal::scalar_cast_op<int, T> conv;
    319     return conv(1);
    320   }
    321   template <typename Packet>
    322   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet initializePacket() const {
    323     return pset1<Packet>(initialize());
    324   }
    325   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T finalize(const T accum) const {
    326     return accum;
    327   }
    328   template <typename Packet>
    329   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet finalizePacket(const Packet& vaccum) const {
    330     return vaccum;
    331   }
    332   template <typename Packet>
    333   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T finalizeBoth(const T saccum, const Packet& vaccum) const {
    334     internal::scalar_product_op<T> prod_op;
    335     return prod_op(saccum, predux_mul(vaccum));
    336   }
    337 };
    338 
    339 template <typename T, typename Device>
    340 struct reducer_traits<ProdReducer<T>, Device> {
    341   enum {
    342     Cost = NumTraits<T>::MulCost,
    343     PacketAccess = PacketType<T, Device>::HasMul
    344   };
    345 };
    346 
    347 
    348 struct AndReducer
    349 {
    350   static const bool PacketAccess = false;
    351   static const bool IsStateful = false;
    352 
    353   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void reduce(bool t, bool* accum) const {
    354     *accum = *accum && t;
    355   }
    356   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool initialize() const {
    357     return true;
    358   }
    359   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool finalize(bool accum) const {
    360     return accum;
    361   }
    362 };
    363 
    364 template <typename Device>
    365 struct reducer_traits<AndReducer, Device> {
    366   enum {
    367     Cost = 1,
    368     PacketAccess = false
    369   };
    370 };
    371 
    372 
    373 struct OrReducer {
    374   static const bool PacketAccess = false;
    375   static const bool IsStateful = false;
    376 
    377   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void reduce(bool t, bool* accum) const {
    378     *accum = *accum || t;
    379   }
    380   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool initialize() const {
    381     return false;
    382   }
    383   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool finalize(bool accum) const {
    384     return accum;
    385   }
    386 };
    387 
    388 template <typename Device>
    389 struct reducer_traits<OrReducer, Device> {
    390   enum {
    391     Cost = 1,
    392     PacketAccess = false
    393   };
    394 };
    395 
    396 
    397 // Argmin/Argmax reducers
    398 template <typename T> struct ArgMaxTupleReducer
    399 {
    400   static const bool PacketAccess = false;
    401   static const bool IsStateful = false;
    402 
    403   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void reduce(const T t, T* accum) const {
    404     if (t.second > accum->second) { *accum = t; }
    405   }
    406   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T initialize() const {
    407     return T(0, NumTraits<typename T::second_type>::lowest());
    408   }
    409   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T finalize(const T& accum) const {
    410     return accum;
    411   }
    412 };
    413 
    414 template <typename T, typename Device>
    415 struct reducer_traits<ArgMaxTupleReducer<T>, Device> {
    416   enum {
    417     Cost = NumTraits<T>::AddCost,
    418     PacketAccess = false
    419   };
    420 };
    421 
    422 
    423 template <typename T> struct ArgMinTupleReducer
    424 {
    425   static const bool PacketAccess = false;
    426   static const bool IsStateful = false;
    427 
    428   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void reduce(const T& t, T* accum) const {
    429     if (t.second < accum->second) { *accum = t; }
    430   }
    431   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T initialize() const {
    432     return T(0, NumTraits<typename T::second_type>::highest());
    433   }
    434   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T finalize(const T& accum) const {
    435     return accum;
    436   }
    437 };
    438 
    439 template <typename T, typename Device>
    440 struct reducer_traits<ArgMinTupleReducer<T>, Device> {
    441   enum {
    442     Cost = NumTraits<T>::AddCost,
    443     PacketAccess = false
    444   };
    445 };
    446 
    447 
    448 template <typename T, typename Index, size_t NumDims>
    449 class GaussianGenerator {
    450  public:
    451   static const bool PacketAccess = false;
    452 
    453   EIGEN_DEVICE_FUNC GaussianGenerator(const array<T, NumDims>& means,
    454                                       const array<T, NumDims>& std_devs)
    455       : m_means(means)
    456   {
    457     for (size_t i = 0; i < NumDims; ++i) {
    458       m_two_sigmas[i] = std_devs[i] * std_devs[i] * 2;
    459     }
    460   }
    461 
    462   EIGEN_DEVICE_FUNC T operator()(const array<Index, NumDims>& coordinates) const {
    463     T tmp = T(0);
    464     for (size_t i = 0; i < NumDims; ++i) {
    465       T offset = coordinates[i] - m_means[i];
    466       tmp += offset * offset / m_two_sigmas[i];
    467     }
    468     return numext::exp(-tmp);
    469   }
    470 
    471  private:
    472   array<T, NumDims> m_means;
    473   array<T, NumDims> m_two_sigmas;
    474 };
    475 
    476 template <typename T, typename Index, size_t NumDims>
    477 struct functor_traits<GaussianGenerator<T, Index, NumDims> > {
    478   enum {
    479     Cost = NumDims * (2 * NumTraits<T>::AddCost + NumTraits<T>::MulCost +
    480                       functor_traits<scalar_quotient_op<T, T> >::Cost) +
    481            functor_traits<scalar_exp_op<T> >::Cost,
    482     PacketAccess = GaussianGenerator<T, Index, NumDims>::PacketAccess
    483   };
    484 };
    485 
    486 } // end namespace internal
    487 } // end namespace Eigen
    488 
    489 #endif // EIGEN_CXX11_TENSOR_TENSOR_FUNCTORS_H
    490