• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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@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 {
scalar_mod_opscalar_mod_op22   EIGEN_DEVICE_FUNC scalar_mod_op(const Scalar& divisor) : m_divisor(divisor) {}
operatorscalar_mod_op23   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