$darkmode
Eigen  5.0.1-dev
UnaryFunctors.h
1 // This file is part of Eigen, a lightweight C++ template library
2 // for linear algebra.
3 //
4 // Copyright (C) 2008-2016 Gael Guennebaud <gael.guennebaud@inria.fr>
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_UNARY_FUNCTORS_H
11 #define EIGEN_UNARY_FUNCTORS_H
12 
13 // IWYU pragma: private
14 #include "../InternalHeaderCheck.h"
15 
16 namespace Eigen {
17 
18 namespace internal {
19 
25 template <typename Scalar>
26 struct scalar_opposite_op {
27  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar operator()(const Scalar& a) const { return numext::negate(a); }
28  template <typename Packet>
29  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a) const {
30  return internal::pnegate(a);
31  }
32 };
33 template <typename Scalar>
34 struct functor_traits<scalar_opposite_op<Scalar>> {
35  enum { Cost = NumTraits<Scalar>::AddCost, PacketAccess = packet_traits<Scalar>::HasNegate };
36 };
37 
43 template <typename Scalar>
44 struct scalar_abs_op {
45  typedef typename NumTraits<Scalar>::Real result_type;
46  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const result_type operator()(const Scalar& a) const { return numext::abs(a); }
47  template <typename Packet>
48  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a) const {
49  return internal::pabs(a);
50  }
51 };
52 template <typename Scalar>
53 struct functor_traits<scalar_abs_op<Scalar>> {
54  enum { Cost = NumTraits<Scalar>::AddCost, PacketAccess = packet_traits<Scalar>::HasAbs };
55 };
56 
62 template <typename Scalar>
63 struct scalar_score_coeff_op : scalar_abs_op<Scalar> {
64  typedef void Score_is_abs;
65 };
66 template <typename Scalar>
67 struct functor_traits<scalar_score_coeff_op<Scalar>> : functor_traits<scalar_abs_op<Scalar>> {};
68 
69 /* Avoid recomputing abs when we know the score and they are the same. Not a true Eigen functor. */
70 template <typename Scalar, typename = void>
71 struct abs_knowing_score {
72  typedef typename NumTraits<Scalar>::Real result_type;
73  template <typename Score>
74  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const result_type operator()(const Scalar& a, const Score&) const {
75  return numext::abs(a);
76  }
77 };
78 template <typename Scalar>
79 struct abs_knowing_score<Scalar, typename scalar_score_coeff_op<Scalar>::Score_is_abs> {
80  typedef typename NumTraits<Scalar>::Real result_type;
81  template <typename Scal>
82  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const result_type operator()(const Scal&, const result_type& a) const {
83  return a;
84  }
85 };
86 
92 template <typename Scalar>
93 struct scalar_abs2_op {
94  typedef typename NumTraits<Scalar>::Real result_type;
95  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const result_type operator()(const Scalar& a) const { return numext::abs2(a); }
96  template <typename Packet>
97  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a) const {
98  return internal::pmul(a, a);
99  }
100 };
101 template <typename Scalar>
102 struct functor_traits<scalar_abs2_op<Scalar>> {
103  enum { Cost = NumTraits<Scalar>::MulCost, PacketAccess = packet_traits<Scalar>::HasAbs2 };
104 };
105 
106 template <typename Scalar, bool IsComplex = NumTraits<Scalar>::IsComplex>
107 struct squared_norm_functor {
108  typedef Scalar result_type;
109  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar operator()(const Scalar& a) const {
110  return Scalar(numext::real(a) * numext::real(a), numext::imag(a) * numext::imag(a));
111  }
112  template <typename Packet>
113  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a) const {
114  return Packet(pmul(a.v, a.v));
115  }
116 };
117 template <typename Scalar>
118 struct squared_norm_functor<Scalar, false> : scalar_abs2_op<Scalar> {};
119 
120 template <typename Scalar>
121 struct functor_traits<squared_norm_functor<Scalar>> {
122  using Real = typename NumTraits<Scalar>::Real;
123  enum { Cost = NumTraits<Real>::MulCost, PacketAccess = packet_traits<Real>::HasMul };
124 };
125 
131 template <typename Scalar>
132 struct scalar_conjugate_op {
133  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar operator()(const Scalar& a) const { return numext::conj(a); }
134  template <typename Packet>
135  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a) const {
136  return internal::pconj(a);
137  }
138 };
139 template <typename Scalar>
140 struct functor_traits<scalar_conjugate_op<Scalar>> {
141  enum {
142  Cost = 0,
143  // Yes the cost is zero even for complexes because in most cases for which
144  // the cost is used, conjugation turns to be a no-op. Some examples:
145  // cost(a*conj(b)) == cost(a*b)
146  // cost(a+conj(b)) == cost(a+b)
147  // <etc.
148  // If we don't set it to zero, then:
149  // A.conjugate().lazyProduct(B.conjugate())
150  // will bake its operands. We definitely don't want that!
151  PacketAccess = packet_traits<Scalar>::HasConj
152  };
153 };
154 
160 template <typename Scalar>
161 struct scalar_arg_op {
162  typedef typename NumTraits<Scalar>::Real result_type;
163  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const result_type operator()(const Scalar& a) const { return numext::arg(a); }
164  template <typename Packet>
165  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a) const {
166  return internal::parg(a);
167  }
168 };
169 template <typename Scalar>
170 struct functor_traits<scalar_arg_op<Scalar>> {
171  enum {
172  Cost = NumTraits<Scalar>::IsComplex ? 5 * NumTraits<Scalar>::MulCost : NumTraits<Scalar>::AddCost,
173  PacketAccess = packet_traits<Scalar>::HasArg
174  };
175 };
176 
182 template <typename Scalar>
183 struct scalar_carg_op {
184  using result_type = Scalar;
185  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar operator()(const Scalar& a) const {
186  return Scalar(numext::arg(a));
187  }
188  template <typename Packet>
189  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a) const {
190  return pcarg(a);
191  }
192 };
193 template <typename Scalar>
194 struct functor_traits<scalar_carg_op<Scalar>> {
195  using RealScalar = typename NumTraits<Scalar>::Real;
196  enum { Cost = functor_traits<scalar_atan2_op<RealScalar>>::Cost, PacketAccess = packet_traits<RealScalar>::HasATan };
197 };
198 
204 template <typename Scalar, typename NewType>
205 struct scalar_cast_op {
206  typedef NewType result_type;
207  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const NewType operator()(const Scalar& a) const {
208  return cast<Scalar, NewType>(a);
209  }
210 };
211 
212 template <typename Scalar, typename NewType>
213 struct functor_traits<scalar_cast_op<Scalar, NewType>> {
214  enum { Cost = is_same<Scalar, NewType>::value ? 0 : NumTraits<NewType>::AddCost, PacketAccess = false };
215 };
216 
223 template <typename SrcType, typename DstType>
224 struct core_cast_op : scalar_cast_op<SrcType, DstType> {};
225 
226 template <typename SrcType, typename DstType>
227 struct functor_traits<core_cast_op<SrcType, DstType>> {
228  using CastingTraits = type_casting_traits<SrcType, DstType>;
229  enum {
230  Cost = is_same<SrcType, DstType>::value ? 0 : NumTraits<DstType>::AddCost,
231  PacketAccess = CastingTraits::VectorizedCast && (CastingTraits::SrcCoeffRatio <= 8)
232  };
233 };
234 
240 template <typename Scalar, int N>
241 struct scalar_shift_right_op {
242  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar operator()(const Scalar& a) const {
243  return numext::arithmetic_shift_right(a);
244  }
245  template <typename Packet>
246  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a) const {
247  return internal::parithmetic_shift_right<N>(a);
248  }
249 };
250 template <typename Scalar, int N>
251 struct functor_traits<scalar_shift_right_op<Scalar, N>> {
252  enum { Cost = NumTraits<Scalar>::AddCost, PacketAccess = packet_traits<Scalar>::HasShift };
253 };
254 
260 template <typename Scalar, int N>
261 struct scalar_shift_left_op {
262  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar operator()(const Scalar& a) const {
263  return numext::logical_shift_left(a);
264  }
265  template <typename Packet>
266  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a) const {
267  return internal::plogical_shift_left<N>(a);
268  }
269 };
270 template <typename Scalar, int N>
271 struct functor_traits<scalar_shift_left_op<Scalar, N>> {
272  enum { Cost = NumTraits<Scalar>::AddCost, PacketAccess = packet_traits<Scalar>::HasShift };
273 };
274 
280 template <typename Scalar>
281 struct scalar_real_op {
282  typedef typename NumTraits<Scalar>::Real result_type;
283  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type operator()(const Scalar& a) const { return numext::real(a); }
284 };
285 template <typename Scalar>
286 struct functor_traits<scalar_real_op<Scalar>> {
287  enum { Cost = 0, PacketAccess = false };
288 };
289 
295 template <typename Scalar>
296 struct scalar_imag_op {
297  typedef typename NumTraits<Scalar>::Real result_type;
298  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type operator()(const Scalar& a) const { return numext::imag(a); }
299 };
300 template <typename Scalar>
301 struct functor_traits<scalar_imag_op<Scalar>> {
302  enum { Cost = 0, PacketAccess = false };
303 };
304 
310 template <typename Scalar>
311 struct scalar_real_ref_op {
312  typedef typename NumTraits<Scalar>::Real result_type;
313  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const result_type& operator()(const Scalar& a) const {
314  return numext::real_ref(a);
315  }
316  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type& operator()(Scalar& a) const { return numext::real_ref(a); }
317 };
318 template <typename Scalar>
319 struct functor_traits<scalar_real_ref_op<Scalar>> {
320  enum { Cost = 0, PacketAccess = false };
321 };
322 
328 template <typename Scalar>
329 struct scalar_imag_ref_op {
330  typedef typename NumTraits<Scalar>::Real result_type;
331  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type& operator()(Scalar& a) const { return numext::imag_ref(a); }
332  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const result_type& operator()(const Scalar& a) const {
333  return numext::imag_ref(a);
334  }
335 };
336 template <typename Scalar>
337 struct functor_traits<scalar_imag_ref_op<Scalar>> {
338  enum { Cost = 0, PacketAccess = false };
339 };
340 
347 template <typename Scalar>
348 struct scalar_exp_op {
349  EIGEN_DEVICE_FUNC inline const Scalar operator()(const Scalar& a) const { return internal::pexp(a); }
350  template <typename Packet>
351  EIGEN_DEVICE_FUNC inline Packet packetOp(const Packet& a) const {
352  return internal::pexp(a);
353  }
354 };
355 template <typename Scalar>
356 struct functor_traits<scalar_exp_op<Scalar>> {
357  enum {
358  PacketAccess = packet_traits<Scalar>::HasExp,
359  // The following numbers are based on the AVX implementation.
360 #ifdef EIGEN_VECTORIZE_FMA
361  // Haswell can issue 2 add/mul/madd per cycle.
362  Cost = (sizeof(Scalar) == 4
363  // float: 8 pmadd, 4 pmul, 2 padd/psub, 6 other
364  ? (8 * NumTraits<Scalar>::AddCost + 6 * NumTraits<Scalar>::MulCost)
365  // double: 7 pmadd, 5 pmul, 3 padd/psub, 1 div, 13 other
366  : (14 * NumTraits<Scalar>::AddCost + 6 * NumTraits<Scalar>::MulCost +
367  scalar_div_cost<Scalar, packet_traits<Scalar>::HasDiv>::value))
368 #else
369  Cost = (sizeof(Scalar) == 4
370  // float: 7 pmadd, 6 pmul, 4 padd/psub, 10 other
371  ? (21 * NumTraits<Scalar>::AddCost + 13 * NumTraits<Scalar>::MulCost)
372  // double: 7 pmadd, 5 pmul, 3 padd/psub, 1 div, 13 other
373  : (23 * NumTraits<Scalar>::AddCost + 12 * NumTraits<Scalar>::MulCost +
374  scalar_div_cost<Scalar, packet_traits<Scalar>::HasDiv>::value))
375 #endif
376  };
377 };
378 
379 template <typename Scalar>
380 struct scalar_exp2_op {
381  EIGEN_DEVICE_FUNC inline const Scalar operator()(const Scalar& a) const { return internal::pexp2(a); }
382  template <typename Packet>
383  EIGEN_DEVICE_FUNC inline Packet packetOp(const Packet& a) const {
384  return internal::pexp2(a);
385  }
386 };
387 template <typename Scalar>
388 struct functor_traits<scalar_exp2_op<Scalar>> {
389  enum {
390  PacketAccess = packet_traits<Scalar>::HasExp,
391  Cost = functor_traits<scalar_exp_op<Scalar>>::Cost // TODO measure cost of exp2
392  };
393 };
394 
401 template <typename Scalar>
402 struct scalar_expm1_op {
403  EIGEN_DEVICE_FUNC inline const Scalar operator()(const Scalar& a) const { return numext::expm1(a); }
404  template <typename Packet>
405  EIGEN_DEVICE_FUNC inline Packet packetOp(const Packet& a) const {
406  return internal::pexpm1(a);
407  }
408 };
409 template <typename Scalar>
410 struct functor_traits<scalar_expm1_op<Scalar>> {
411  enum {
412  PacketAccess = packet_traits<Scalar>::HasExpm1,
413  Cost = functor_traits<scalar_exp_op<Scalar>>::Cost // TODO measure cost of expm1
414  };
415 };
416 
423 template <typename Scalar>
424 struct scalar_log_op {
425  EIGEN_DEVICE_FUNC inline const Scalar operator()(const Scalar& a) const { return numext::log(a); }
426  template <typename Packet>
427  EIGEN_DEVICE_FUNC inline Packet packetOp(const Packet& a) const {
428  return internal::plog(a);
429  }
430 };
431 template <typename Scalar>
432 struct functor_traits<scalar_log_op<Scalar>> {
433  enum {
434  PacketAccess = packet_traits<Scalar>::HasLog,
435  Cost = (PacketAccess
436  // The following numbers are based on the AVX implementation.
437 #ifdef EIGEN_VECTORIZE_FMA
438  // 8 pmadd, 6 pmul, 8 padd/psub, 16 other, can issue 2 add/mul/madd per cycle.
439  ? (20 * NumTraits<Scalar>::AddCost + 7 * NumTraits<Scalar>::MulCost)
440 #else
441  // 8 pmadd, 6 pmul, 8 padd/psub, 20 other
442  ? (36 * NumTraits<Scalar>::AddCost + 14 * NumTraits<Scalar>::MulCost)
443 #endif
444  // Measured cost of std::log.
445  : sizeof(Scalar) == 4 ? 40 : 85)
446  };
447 };
448 
455 template <typename Scalar>
456 struct scalar_log1p_op {
457  EIGEN_DEVICE_FUNC inline const Scalar operator()(const Scalar& a) const { return numext::log1p(a); }
458  template <typename Packet>
459  EIGEN_DEVICE_FUNC inline Packet packetOp(const Packet& a) const {
460  return internal::plog1p(a);
461  }
462 };
463 template <typename Scalar>
464 struct functor_traits<scalar_log1p_op<Scalar>> {
465  enum {
466  PacketAccess = packet_traits<Scalar>::HasLog1p,
467  Cost = functor_traits<scalar_log_op<Scalar>>::Cost // TODO measure cost of log1p
468  };
469 };
470 
477 template <typename Scalar>
478 struct scalar_log10_op {
479  EIGEN_DEVICE_FUNC inline const Scalar operator()(const Scalar& a) const { EIGEN_USING_STD(log10) return log10(a); }
480  template <typename Packet>
481  EIGEN_DEVICE_FUNC inline Packet packetOp(const Packet& a) const {
482  return internal::plog10(a);
483  }
484 };
485 template <typename Scalar>
486 struct functor_traits<scalar_log10_op<Scalar>> {
487  enum { Cost = 5 * NumTraits<Scalar>::MulCost, PacketAccess = packet_traits<Scalar>::HasLog10 };
488 };
489 
496 template <typename Scalar>
497 struct scalar_log2_op {
498  using RealScalar = typename NumTraits<Scalar>::Real;
499  EIGEN_DEVICE_FUNC inline const Scalar operator()(const Scalar& a) const {
500  return Scalar(RealScalar(EIGEN_LOG2E)) * numext::log(a);
501  }
502  template <typename Packet>
503  EIGEN_DEVICE_FUNC inline Packet packetOp(const Packet& a) const {
504  return internal::plog2(a);
505  }
506 };
507 template <typename Scalar>
508 struct functor_traits<scalar_log2_op<Scalar>> {
509  enum { Cost = 5 * NumTraits<Scalar>::MulCost, PacketAccess = packet_traits<Scalar>::HasLog };
510 };
511 
516 template <typename Scalar>
517 struct scalar_sqrt_op {
518  EIGEN_DEVICE_FUNC inline const Scalar operator()(const Scalar& a) const { return numext::sqrt(a); }
519  template <typename Packet>
520  EIGEN_DEVICE_FUNC inline Packet packetOp(const Packet& a) const {
521  return internal::psqrt(a);
522  }
523 };
524 template <typename Scalar>
525 struct functor_traits<scalar_sqrt_op<Scalar>> {
526  enum {
527 #if EIGEN_FAST_MATH
528  // The following numbers are based on the AVX implementation.
529  Cost = (sizeof(Scalar) == 8 ? 28
530  // 4 pmul, 1 pmadd, 3 other
531  : (3 * NumTraits<Scalar>::AddCost + 5 * NumTraits<Scalar>::MulCost)),
532 #else
533  // The following numbers are based on min VSQRT throughput on Haswell.
534  Cost = (sizeof(Scalar) == 8 ? 28 : 14),
535 #endif
536  PacketAccess = packet_traits<Scalar>::HasSqrt
537  };
538 };
539 
540 // Boolean specialization to eliminate -Wimplicit-conversion-floating-point-to-bool warnings.
541 template <>
542 struct scalar_sqrt_op<bool> {
543  EIGEN_DEPRECATED EIGEN_DEVICE_FUNC inline bool operator()(const bool& a) const { return a; }
544  template <typename Packet>
545  EIGEN_DEPRECATED EIGEN_DEVICE_FUNC inline Packet packetOp(const Packet& a) const {
546  return a;
547  }
548 };
549 template <>
550 struct functor_traits<scalar_sqrt_op<bool>> {
551  enum { Cost = 1, PacketAccess = packet_traits<bool>::Vectorizable };
552 };
553 
558 template <typename Scalar>
559 struct scalar_cbrt_op {
560  EIGEN_DEVICE_FUNC inline const Scalar operator()(const Scalar& a) const { return numext::cbrt(a); }
561  template <typename Packet>
562  EIGEN_DEVICE_FUNC inline Packet packetOp(const Packet& a) const {
563  return internal::pcbrt(a);
564  }
565 };
566 
567 template <typename Scalar>
568 struct functor_traits<scalar_cbrt_op<Scalar>> {
569  enum { Cost = 20 * NumTraits<Scalar>::MulCost, PacketAccess = packet_traits<Scalar>::HasCbrt };
570 };
571 
576 template <typename Scalar>
577 struct scalar_rsqrt_op {
578  EIGEN_DEVICE_FUNC inline const Scalar operator()(const Scalar& a) const { return numext::rsqrt(a); }
579  template <typename Packet>
580  EIGEN_DEVICE_FUNC inline Packet packetOp(const Packet& a) const {
581  return internal::prsqrt(a);
582  }
583 };
584 
585 template <typename Scalar>
586 struct functor_traits<scalar_rsqrt_op<Scalar>> {
587  enum { Cost = 5 * NumTraits<Scalar>::MulCost, PacketAccess = packet_traits<Scalar>::HasRsqrt };
588 };
589 
594 template <typename Scalar>
595 struct scalar_cos_op {
596  EIGEN_DEVICE_FUNC inline Scalar operator()(const Scalar& a) const { return numext::cos(a); }
597  template <typename Packet>
598  EIGEN_DEVICE_FUNC inline Packet packetOp(const Packet& a) const {
599  return internal::pcos(a);
600  }
601 };
602 template <typename Scalar>
603 struct functor_traits<scalar_cos_op<Scalar>> {
604  enum { Cost = 5 * NumTraits<Scalar>::MulCost, PacketAccess = packet_traits<Scalar>::HasCos };
605 };
606 
611 template <typename Scalar>
612 struct scalar_sin_op {
613  EIGEN_DEVICE_FUNC inline const Scalar operator()(const Scalar& a) const { return numext::sin(a); }
614  template <typename Packet>
615  EIGEN_DEVICE_FUNC inline Packet packetOp(const Packet& a) const {
616  return internal::psin(a);
617  }
618 };
619 template <typename Scalar>
620 struct functor_traits<scalar_sin_op<Scalar>> {
621  enum { Cost = 5 * NumTraits<Scalar>::MulCost, PacketAccess = packet_traits<Scalar>::HasSin };
622 };
623 
628 template <typename Scalar>
629 struct scalar_tan_op {
630  EIGEN_DEVICE_FUNC inline const Scalar operator()(const Scalar& a) const { return numext::tan(a); }
631  template <typename Packet>
632  EIGEN_DEVICE_FUNC inline Packet packetOp(const Packet& a) const {
633  return internal::ptan(a);
634  }
635 };
636 template <typename Scalar>
637 struct functor_traits<scalar_tan_op<Scalar>> {
638  enum { Cost = 5 * NumTraits<Scalar>::MulCost, PacketAccess = packet_traits<Scalar>::HasTan };
639 };
640 
645 template <typename Scalar>
646 struct scalar_acos_op {
647  EIGEN_DEVICE_FUNC inline const Scalar operator()(const Scalar& a) const { return numext::acos(a); }
648  template <typename Packet>
649  EIGEN_DEVICE_FUNC inline Packet packetOp(const Packet& a) const {
650  return internal::pacos(a);
651  }
652 };
653 template <typename Scalar>
654 struct functor_traits<scalar_acos_op<Scalar>> {
655  enum { Cost = 5 * NumTraits<Scalar>::MulCost, PacketAccess = packet_traits<Scalar>::HasACos };
656 };
657 
662 template <typename Scalar>
663 struct scalar_asin_op {
664  EIGEN_DEVICE_FUNC inline const Scalar operator()(const Scalar& a) const { return numext::asin(a); }
665  template <typename Packet>
666  EIGEN_DEVICE_FUNC inline Packet packetOp(const Packet& a) const {
667  return internal::pasin(a);
668  }
669 };
670 template <typename Scalar>
671 struct functor_traits<scalar_asin_op<Scalar>> {
672  enum { Cost = 5 * NumTraits<Scalar>::MulCost, PacketAccess = packet_traits<Scalar>::HasASin };
673 };
674 
679 template <typename Scalar>
680 struct scalar_atan_op {
681  EIGEN_DEVICE_FUNC inline const Scalar operator()(const Scalar& a) const { return numext::atan(a); }
682  template <typename Packet>
683  EIGEN_DEVICE_FUNC inline Packet packetOp(const Packet& a) const {
684  return internal::patan(a);
685  }
686 };
687 template <typename Scalar>
688 struct functor_traits<scalar_atan_op<Scalar>> {
689  enum { Cost = 5 * NumTraits<Scalar>::MulCost, PacketAccess = packet_traits<Scalar>::HasATan };
690 };
691 
696 template <typename Scalar>
697 struct scalar_tanh_op {
698  EIGEN_DEVICE_FUNC inline const Scalar operator()(const Scalar& a) const { return numext::tanh(a); }
699  template <typename Packet>
700  EIGEN_DEVICE_FUNC inline Packet packetOp(const Packet& x) const {
701  return ptanh(x);
702  }
703 };
704 
705 template <typename Scalar>
706 struct functor_traits<scalar_tanh_op<Scalar>> {
707  enum {
708  PacketAccess = packet_traits<Scalar>::HasTanh,
709  Cost = ((EIGEN_FAST_MATH && is_same<Scalar, float>::value)
710 // The following numbers are based on the AVX implementation,
711 #ifdef EIGEN_VECTORIZE_FMA
712  // Haswell can issue 2 add/mul/madd per cycle.
713  // 9 pmadd, 2 pmul, 1 div, 2 other
714  ? (2 * NumTraits<Scalar>::AddCost + 6 * NumTraits<Scalar>::MulCost +
715  scalar_div_cost<Scalar, packet_traits<Scalar>::HasDiv>::value)
716 #else
717  ? (11 * NumTraits<Scalar>::AddCost + 11 * NumTraits<Scalar>::MulCost +
718  scalar_div_cost<Scalar, packet_traits<Scalar>::HasDiv>::value)
719 #endif
720  // This number assumes a naive implementation of tanh
721  : (6 * NumTraits<Scalar>::AddCost + 3 * NumTraits<Scalar>::MulCost +
722  2 * scalar_div_cost<Scalar, packet_traits<Scalar>::HasDiv>::value +
723  functor_traits<scalar_exp_op<Scalar>>::Cost))
724  };
725 };
726 
731 template <typename Scalar>
732 struct scalar_atanh_op {
733  EIGEN_DEVICE_FUNC inline const Scalar operator()(const Scalar& a) const { return numext::atanh(a); }
734  template <typename Packet>
735  EIGEN_DEVICE_FUNC inline Packet packetOp(const Packet& x) const {
736  return patanh(x);
737  }
738 };
739 
740 template <typename Scalar>
741 struct functor_traits<scalar_atanh_op<Scalar>> {
742  enum { Cost = 5 * NumTraits<Scalar>::MulCost, PacketAccess = packet_traits<Scalar>::HasATanh };
743 };
744 
749 template <typename Scalar>
750 struct scalar_sinh_op {
751  EIGEN_DEVICE_FUNC inline const Scalar operator()(const Scalar& a) const { return numext::sinh(a); }
752  template <typename Packet>
753  EIGEN_DEVICE_FUNC inline Packet packetOp(const Packet& a) const {
754  return internal::psinh(a);
755  }
756 };
757 template <typename Scalar>
758 struct functor_traits<scalar_sinh_op<Scalar>> {
759  enum { Cost = 5 * NumTraits<Scalar>::MulCost, PacketAccess = packet_traits<Scalar>::HasSinh };
760 };
761 
766 template <typename Scalar>
767 struct scalar_asinh_op {
768  EIGEN_DEVICE_FUNC inline const Scalar operator()(const Scalar& a) const { return numext::asinh(a); }
769 };
770 
771 template <typename Scalar>
772 struct functor_traits<scalar_asinh_op<Scalar>> {
773  enum { Cost = 5 * NumTraits<Scalar>::MulCost, PacketAccess = false };
774 };
775 
780 template <typename Scalar>
781 struct scalar_cosh_op {
782  EIGEN_DEVICE_FUNC inline const Scalar operator()(const Scalar& a) const { return numext::cosh(a); }
783  template <typename Packet>
784  EIGEN_DEVICE_FUNC inline Packet packetOp(const Packet& a) const {
785  return internal::pcosh(a);
786  }
787 };
788 template <typename Scalar>
789 struct functor_traits<scalar_cosh_op<Scalar>> {
790  enum { Cost = 5 * NumTraits<Scalar>::MulCost, PacketAccess = packet_traits<Scalar>::HasCosh };
791 };
792 
797 template <typename Scalar>
798 struct scalar_acosh_op {
799  EIGEN_DEVICE_FUNC inline const Scalar operator()(const Scalar& a) const { return numext::acosh(a); }
800 };
801 
802 template <typename Scalar>
803 struct functor_traits<scalar_acosh_op<Scalar>> {
804  enum { Cost = 5 * NumTraits<Scalar>::MulCost, PacketAccess = false };
805 };
806 
811 template <typename Scalar>
812 struct scalar_inverse_op {
813  EIGEN_DEVICE_FUNC inline Scalar operator()(const Scalar& a) const { return Scalar(1) / a; }
814  template <typename Packet>
815  EIGEN_DEVICE_FUNC inline const Packet packetOp(const Packet& a) const {
816  return internal::preciprocal(a);
817  }
818 };
819 template <typename Scalar>
820 struct functor_traits<scalar_inverse_op<Scalar>> {
821  enum {
822  PacketAccess = packet_traits<Scalar>::HasDiv,
823  // If packet_traits<Scalar>::HasReciprocal then the Estimated cost is that
824  // of computing an approximation plus a single Newton-Raphson step, which
825  // consists of 1 pmul + 1 pmadd.
826  Cost = (packet_traits<Scalar>::HasReciprocal ? 4 * NumTraits<Scalar>::MulCost
827  : scalar_div_cost<Scalar, PacketAccess>::value)
828  };
829 };
830 
835 template <typename Scalar>
836 struct scalar_square_op {
837  EIGEN_DEVICE_FUNC inline Scalar operator()(const Scalar& a) const { return a * a; }
838  template <typename Packet>
839  EIGEN_DEVICE_FUNC inline const Packet packetOp(const Packet& a) const {
840  return internal::pmul(a, a);
841  }
842 };
843 template <typename Scalar>
844 struct functor_traits<scalar_square_op<Scalar>> {
845  enum { Cost = NumTraits<Scalar>::MulCost, PacketAccess = packet_traits<Scalar>::HasMul };
846 };
847 
848 // Boolean specialization to avoid -Wint-in-bool-context warnings on GCC.
849 template <>
850 struct scalar_square_op<bool> {
851  EIGEN_DEPRECATED EIGEN_DEVICE_FUNC inline bool operator()(const bool& a) const { return a; }
852  template <typename Packet>
853  EIGEN_DEPRECATED EIGEN_DEVICE_FUNC inline const Packet packetOp(const Packet& a) const {
854  return a;
855  }
856 };
857 template <>
858 struct functor_traits<scalar_square_op<bool>> {
859  enum { Cost = 0, PacketAccess = packet_traits<bool>::Vectorizable };
860 };
861 
866 template <typename Scalar>
867 struct scalar_cube_op {
868  EIGEN_DEVICE_FUNC inline Scalar operator()(const Scalar& a) const { return a * a * a; }
869  template <typename Packet>
870  EIGEN_DEVICE_FUNC inline const Packet packetOp(const Packet& a) const {
871  return internal::pmul(a, pmul(a, a));
872  }
873 };
874 template <typename Scalar>
875 struct functor_traits<scalar_cube_op<Scalar>> {
876  enum { Cost = 2 * NumTraits<Scalar>::MulCost, PacketAccess = packet_traits<Scalar>::HasMul };
877 };
878 
879 // Boolean specialization to avoid -Wint-in-bool-context warnings on GCC.
880 template <>
881 struct scalar_cube_op<bool> {
882  EIGEN_DEPRECATED EIGEN_DEVICE_FUNC inline bool operator()(const bool& a) const { return a; }
883  template <typename Packet>
884  EIGEN_DEPRECATED EIGEN_DEVICE_FUNC inline const Packet packetOp(const Packet& a) const {
885  return a;
886  }
887 };
888 template <>
889 struct functor_traits<scalar_cube_op<bool>> {
890  enum { Cost = 0, PacketAccess = packet_traits<bool>::Vectorizable };
891 };
892 
897 template <typename Scalar>
898 struct scalar_round_op {
899  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar operator()(const Scalar& a) const { return numext::round(a); }
900  template <typename Packet>
901  EIGEN_DEVICE_FUNC inline Packet packetOp(const Packet& a) const {
902  return internal::pround(a);
903  }
904 };
905 template <typename Scalar>
906 struct functor_traits<scalar_round_op<Scalar>> {
907  enum {
908  Cost = NumTraits<Scalar>::MulCost,
909  PacketAccess = packet_traits<Scalar>::HasRound || NumTraits<Scalar>::IsInteger
910  };
911 };
912 
917 template <typename Scalar>
918 struct scalar_floor_op {
919  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar operator()(const Scalar& a) const { return numext::floor(a); }
920  template <typename Packet>
921  EIGEN_DEVICE_FUNC inline Packet packetOp(const Packet& a) const {
922  return internal::pfloor(a);
923  }
924 };
925 template <typename Scalar>
926 struct functor_traits<scalar_floor_op<Scalar>> {
927  enum {
928  Cost = NumTraits<Scalar>::MulCost,
929  PacketAccess = packet_traits<Scalar>::HasRound || NumTraits<Scalar>::IsInteger
930  };
931 };
932 
937 template <typename Scalar>
938 struct scalar_rint_op {
939  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar operator()(const Scalar& a) const { return numext::rint(a); }
940  template <typename Packet>
941  EIGEN_DEVICE_FUNC inline Packet packetOp(const Packet& a) const {
942  return internal::print(a);
943  }
944 };
945 template <typename Scalar>
946 struct functor_traits<scalar_rint_op<Scalar>> {
947  enum {
948  Cost = NumTraits<Scalar>::MulCost,
949  PacketAccess = packet_traits<Scalar>::HasRound || NumTraits<Scalar>::IsInteger
950  };
951 };
952 
957 template <typename Scalar>
958 struct scalar_ceil_op {
959  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar operator()(const Scalar& a) const { return numext::ceil(a); }
960  template <typename Packet>
961  EIGEN_DEVICE_FUNC inline Packet packetOp(const Packet& a) const {
962  return internal::pceil(a);
963  }
964 };
965 template <typename Scalar>
966 struct functor_traits<scalar_ceil_op<Scalar>> {
967  enum {
968  Cost = NumTraits<Scalar>::MulCost,
969  PacketAccess = packet_traits<Scalar>::HasRound || NumTraits<Scalar>::IsInteger
970  };
971 };
972 
977 template <typename Scalar>
978 struct scalar_trunc_op {
979  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar operator()(const Scalar& a) const { return numext::trunc(a); }
980  template <typename Packet>
981  EIGEN_DEVICE_FUNC inline Packet packetOp(const Packet& a) const {
982  return internal::ptrunc(a);
983  }
984 };
985 template <typename Scalar>
986 struct functor_traits<scalar_trunc_op<Scalar>> {
987  enum {
988  Cost = NumTraits<Scalar>::MulCost,
989  PacketAccess = packet_traits<Scalar>::HasRound || NumTraits<Scalar>::IsInteger
990  };
991 };
992 
997 template <typename Scalar, bool UseTypedPredicate = false>
998 struct scalar_isnan_op {
999  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool operator()(const Scalar& a) const {
1000 #if defined(SYCL_DEVICE_ONLY)
1001  return numext::isnan(a);
1002 #else
1003  return numext::isnan EIGEN_NOT_A_MACRO(a);
1004 #endif
1005  }
1006 };
1007 
1008 template <typename Scalar>
1009 struct scalar_isnan_op<Scalar, true> {
1010  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar operator()(const Scalar& a) const {
1011 #if defined(SYCL_DEVICE_ONLY)
1012  return (numext::isnan(a) ? ptrue(a) : pzero(a));
1013 #else
1014  return (numext::isnan EIGEN_NOT_A_MACRO(a) ? ptrue(a) : pzero(a));
1015 #endif
1016  }
1017  template <typename Packet>
1018  EIGEN_DEVICE_FUNC inline Packet packetOp(const Packet& a) const {
1019  return pisnan(a);
1020  }
1021 };
1022 
1023 template <typename Scalar, bool UseTypedPredicate>
1024 struct functor_traits<scalar_isnan_op<Scalar, UseTypedPredicate>> {
1025  enum { Cost = NumTraits<Scalar>::MulCost, PacketAccess = packet_traits<Scalar>::HasCmp && UseTypedPredicate };
1026 };
1027 
1032 template <typename Scalar, bool UseTypedPredicate = false>
1033 struct scalar_isinf_op {
1034  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool operator()(const Scalar& a) const {
1035 #if defined(SYCL_DEVICE_ONLY)
1036  return numext::isinf(a);
1037 #else
1038  return (numext::isinf)(a);
1039 #endif
1040  }
1041 };
1042 
1043 template <typename Scalar>
1044 struct scalar_isinf_op<Scalar, true> {
1045  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar operator()(const Scalar& a) const {
1046 #if defined(SYCL_DEVICE_ONLY)
1047  return (numext::isinf(a) ? ptrue(a) : pzero(a));
1048 #else
1049  return (numext::isinf EIGEN_NOT_A_MACRO(a) ? ptrue(a) : pzero(a));
1050 #endif
1051  }
1052  template <typename Packet>
1053  EIGEN_DEVICE_FUNC inline Packet packetOp(const Packet& a) const {
1054  return pisinf(a);
1055  }
1056 };
1057 template <typename Scalar, bool UseTypedPredicate>
1058 struct functor_traits<scalar_isinf_op<Scalar, UseTypedPredicate>> {
1059  enum { Cost = NumTraits<Scalar>::MulCost, PacketAccess = packet_traits<Scalar>::HasCmp && UseTypedPredicate };
1060 };
1061 
1066 template <typename Scalar, bool UseTypedPredicate = false>
1067 struct scalar_isfinite_op {
1068  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool operator()(const Scalar& a) const {
1069 #if defined(SYCL_DEVICE_ONLY)
1070  return numext::isfinite(a);
1071 #else
1072  return (numext::isfinite)(a);
1073 #endif
1074  }
1075 };
1076 
1077 template <typename Scalar>
1078 struct scalar_isfinite_op<Scalar, true> {
1079  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar operator()(const Scalar& a) const {
1080 #if defined(SYCL_DEVICE_ONLY)
1081  return (numext::isfinite(a) ? ptrue(a) : pzero(a));
1082 #else
1083  return (numext::isfinite EIGEN_NOT_A_MACRO(a) ? ptrue(a) : pzero(a));
1084 #endif
1085  }
1086  template <typename Packet>
1087  EIGEN_DEVICE_FUNC inline Packet packetOp(const Packet& a) const {
1088  constexpr Scalar inf = NumTraits<Scalar>::infinity();
1089  return pcmp_lt(pabs(a), pset1<Packet>(inf));
1090  }
1091 };
1092 template <typename Scalar, bool UseTypedPredicate>
1093 struct functor_traits<scalar_isfinite_op<Scalar, UseTypedPredicate>> {
1094  enum { Cost = NumTraits<Scalar>::MulCost, PacketAccess = packet_traits<Scalar>::HasCmp && UseTypedPredicate };
1095 };
1096 
1102 template <typename Scalar>
1103 struct scalar_boolean_not_op {
1104  using result_type = Scalar;
1105  // `false` any value `a` that satisfies `a == Scalar(0)`
1106  // `true` is the complement of `false`
1107  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar operator()(const Scalar& a) const {
1108  return a == Scalar(0) ? Scalar(1) : Scalar(0);
1109  }
1110  template <typename Packet>
1111  EIGEN_STRONG_INLINE Packet packetOp(const Packet& a) const {
1112  const Packet cst_one = pset1<Packet>(Scalar(1));
1113  Packet not_a = pcmp_eq(a, pzero(a));
1114  return pand(not_a, cst_one);
1115  }
1116 };
1117 template <typename Scalar>
1118 struct functor_traits<scalar_boolean_not_op<Scalar>> {
1119  enum { Cost = NumTraits<Scalar>::AddCost, PacketAccess = packet_traits<Scalar>::HasCmp };
1120 };
1121 
1122 template <typename Scalar, bool IsComplex = NumTraits<Scalar>::IsComplex>
1123 struct bitwise_unary_impl {
1124  static constexpr size_t Size = sizeof(Scalar);
1125  using uint_t = typename numext::get_integer_by_size<Size>::unsigned_type;
1126  static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar run_not(const Scalar& a) {
1127  uint_t a_as_uint = numext::bit_cast<uint_t, Scalar>(a);
1128  uint_t result = ~a_as_uint;
1129  return numext::bit_cast<Scalar, uint_t>(result);
1130  }
1131 };
1132 
1133 template <typename Scalar>
1134 struct bitwise_unary_impl<Scalar, true> {
1135  using Real = typename NumTraits<Scalar>::Real;
1136  static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar run_not(const Scalar& a) {
1137  Real real_result = bitwise_unary_impl<Real>::run_not(numext::real(a));
1138  Real imag_result = bitwise_unary_impl<Real>::run_not(numext::imag(a));
1139  return Scalar(real_result, imag_result);
1140  }
1141 };
1142 
1148 template <typename Scalar>
1149 struct scalar_bitwise_not_op {
1150  EIGEN_STATIC_ASSERT(!NumTraits<Scalar>::RequireInitialization,
1151  BITWISE OPERATIONS MAY ONLY BE PERFORMED ON PLAIN DATA TYPES)
1152  EIGEN_STATIC_ASSERT((!internal::is_same<Scalar, bool>::value), DONT USE BITWISE OPS ON BOOLEAN TYPES)
1153  using result_type = Scalar;
1154  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar operator()(const Scalar& a) const {
1155  return bitwise_unary_impl<Scalar>::run_not(a);
1156  }
1157  template <typename Packet>
1158  EIGEN_STRONG_INLINE Packet packetOp(const Packet& a) const {
1159  return pandnot(ptrue(a), a);
1160  }
1161 };
1162 template <typename Scalar>
1163 struct functor_traits<scalar_bitwise_not_op<Scalar>> {
1164  enum { Cost = NumTraits<Scalar>::AddCost, PacketAccess = true };
1165 };
1166 
1171 template <typename Scalar>
1172 struct scalar_sign_op {
1173  EIGEN_DEVICE_FUNC inline const Scalar operator()(const Scalar& a) const { return numext::sign(a); }
1174 
1175  template <typename Packet>
1176  EIGEN_DEVICE_FUNC inline Packet packetOp(const Packet& a) const {
1177  return internal::psign(a);
1178  }
1179 };
1180 
1181 template <typename Scalar>
1182 struct functor_traits<scalar_sign_op<Scalar>> {
1183  enum {
1184  Cost = NumTraits<Scalar>::IsComplex ? (8 * NumTraits<Scalar>::MulCost) // roughly
1185  : (3 * NumTraits<Scalar>::AddCost),
1186  PacketAccess = packet_traits<Scalar>::HasSign && packet_traits<Scalar>::Vectorizable
1187  };
1188 };
1189 
1190 // Real-valued implementation.
1191 template <typename T, typename EnableIf = void>
1192 struct scalar_logistic_op_impl {
1193  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T operator()(const T& x) const { return packetOp(x); }
1194 
1195  template <typename Packet>
1196  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& x) const {
1197  const Packet one = pset1<Packet>(T(1));
1198  const Packet inf = pset1<Packet>(NumTraits<T>::infinity());
1199  const Packet e = pexp(x);
1200  const Packet inf_mask = pcmp_eq(e, inf);
1201  return pselect(inf_mask, one, pdiv(e, padd(one, e)));
1202  }
1203 };
1204 
1205 // Complex-valud implementation.
1206 template <typename T>
1207 struct scalar_logistic_op_impl<T, std::enable_if_t<NumTraits<T>::IsComplex>> {
1208  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T operator()(const T& x) const {
1209  const T e = numext::exp(x);
1210  return (numext::isinf)(numext::real(e)) ? T(1) : e / (e + T(1));
1211  }
1212 };
1213 
1218 template <typename T>
1219 struct scalar_logistic_op : scalar_logistic_op_impl<T> {};
1220 
1221 // TODO(rmlarsen): Enable the following on host when integer_packet is defined
1222 // for the relevant packet types.
1223 #ifndef EIGEN_GPUCC
1224 
1240 template <>
1241 struct scalar_logistic_op<float> {
1242  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE float operator()(const float& x) const {
1243  // Truncate at the first point where the interpolant is exactly one.
1244  const float cst_exp_hi = 16.6355324f;
1245  const float e = numext::exp(numext::mini(x, cst_exp_hi));
1246  return e / (1.0f + e);
1247  }
1248 
1249  template <typename Packet>
1250  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& _x) const {
1251  const Packet cst_zero = pset1<Packet>(0.0f);
1252  const Packet cst_one = pset1<Packet>(1.0f);
1253  const Packet cst_half = pset1<Packet>(0.5f);
1254  // Truncate at the first point where the interpolant is exactly one.
1255  const Packet cst_exp_hi = pset1<Packet>(16.6355324f);
1256  const Packet cst_exp_lo = pset1<Packet>(-104.f);
1257 
1258  // Clamp x to the non-trivial range where S(x). Outside this
1259  // interval the correctly rounded value of S(x) is either zero
1260  // or one.
1261  Packet zero_mask = pcmp_lt(_x, cst_exp_lo);
1262  Packet x = pmin(_x, cst_exp_hi);
1263 
1264  // 1. Multiplicative range reduction:
1265  // Reduce the range of x by a factor of 2. This avoids having
1266  // to compute exp(x) accurately where the result is a denormalized
1267  // value.
1268  x = pmul(x, cst_half);
1269 
1270  // 2. Subtractive range reduction:
1271  // Express exp(x) as exp(m*ln(2) + r) = 2^m*exp(r), start by extracting
1272  // m = floor(x/ln(2) + 0.5), such that x = m*ln(2) + r.
1273  const Packet cst_cephes_LOG2EF = pset1<Packet>(1.44269504088896341f);
1274  Packet m = pfloor(pmadd(x, cst_cephes_LOG2EF, cst_half));
1275  // Get r = x - m*ln(2). We use a trick from Cephes where the term
1276  // m*ln(2) is subtracted out in two parts, m*C1+m*C2 = m*ln(2),
1277  // to avoid accumulating truncation errors.
1278  const Packet cst_cephes_exp_C1 = pset1<Packet>(-0.693359375f);
1279  const Packet cst_cephes_exp_C2 = pset1<Packet>(2.12194440e-4f);
1280  Packet r = pmadd(m, cst_cephes_exp_C1, x);
1281  r = pmadd(m, cst_cephes_exp_C2, r);
1282 
1283  // 3. Compute an approximation to exp(r) using a degree 5 minimax polynomial.
1284  // We compute even and odd terms separately to increase instruction level
1285  // parallelism.
1286  Packet r2 = pmul(r, r);
1287  const Packet cst_p2 = pset1<Packet>(0.49999141693115234375f);
1288  const Packet cst_p3 = pset1<Packet>(0.16666877269744873046875f);
1289  const Packet cst_p4 = pset1<Packet>(4.1898667812347412109375e-2f);
1290  const Packet cst_p5 = pset1<Packet>(8.33471305668354034423828125e-3f);
1291 
1292  const Packet p_even = pmadd(r2, cst_p4, cst_p2);
1293  const Packet p_odd = pmadd(r2, cst_p5, cst_p3);
1294  const Packet p_low = padd(r, cst_one);
1295  Packet p = pmadd(r, p_odd, p_even);
1296  p = pmadd(r2, p, p_low);
1297 
1298  // 4. Undo subtractive range reduction exp(m*ln(2) + r) = 2^m * exp(r).
1299  Packet e = pldexp_fast(p, m);
1300 
1301  // 5. Undo multiplicative range reduction by using exp(r) = exp(r/2)^2.
1302  e = pmul(e, e);
1303 
1304  // Return exp(x) / (1 + exp(x))
1305  return pselect(zero_mask, cst_zero, pdiv(e, padd(cst_one, e)));
1306  }
1307 };
1308 #endif // #ifndef EIGEN_GPU_COMPILE_PHASE
1309 
1310 template <typename T>
1311 struct functor_traits<scalar_logistic_op<T>> {
1312  enum {
1313  // The cost estimate for float here here is for the common(?) case where
1314  // all arguments are greater than -9.
1315  Cost = scalar_div_cost<T, packet_traits<T>::HasDiv>::value +
1316  (internal::is_same<T, float>::value ? NumTraits<T>::AddCost * 15 + NumTraits<T>::MulCost * 11
1317  : NumTraits<T>::AddCost * 2 + functor_traits<scalar_exp_op<T>>::Cost),
1318  PacketAccess = !NumTraits<T>::IsComplex && packet_traits<T>::HasAdd && packet_traits<T>::HasDiv &&
1319  (internal::is_same<T, float>::value
1320  ? packet_traits<T>::HasMul && packet_traits<T>::HasMax && packet_traits<T>::HasMin
1321  : packet_traits<T>::HasNegate && packet_traits<T>::HasExp)
1322  };
1323 };
1324 
1325 template <typename Scalar, typename ExponentScalar, bool IsBaseInteger = NumTraits<Scalar>::IsInteger,
1326  bool IsExponentInteger = NumTraits<ExponentScalar>::IsInteger,
1327  bool IsBaseComplex = NumTraits<Scalar>::IsComplex,
1328  bool IsExponentComplex = NumTraits<ExponentScalar>::IsComplex>
1329 struct scalar_unary_pow_op {
1330  typedef typename internal::promote_scalar_arg<
1331  Scalar, ExponentScalar,
1332  internal::has_ReturnType<ScalarBinaryOpTraits<Scalar, ExponentScalar, scalar_unary_pow_op>>::value>::type
1333  PromotedExponent;
1334  typedef typename ScalarBinaryOpTraits<Scalar, PromotedExponent, scalar_unary_pow_op>::ReturnType result_type;
1335  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE scalar_unary_pow_op(const ExponentScalar& exponent) : m_exponent(exponent) {}
1336  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type operator()(const Scalar& a) const {
1337  EIGEN_USING_STD(pow);
1338  return static_cast<result_type>(pow(a, m_exponent));
1339  }
1340 
1341  private:
1342  const ExponentScalar m_exponent;
1343  scalar_unary_pow_op() {}
1344 };
1345 
1346 template <typename T>
1347 constexpr int exponent_digits() {
1348  return CHAR_BIT * sizeof(T) - NumTraits<T>::digits() - NumTraits<T>::IsSigned;
1349 }
1350 
1351 template <typename From, typename To>
1352 struct is_floating_exactly_representable {
1353  // TODO(rmlarsen): Add radix to NumTraits and enable this check.
1354  // (NumTraits<To>::radix == NumTraits<From>::radix) &&
1355  static constexpr bool value =
1356  (exponent_digits<To>() >= exponent_digits<From>() && NumTraits<To>::digits() >= NumTraits<From>::digits());
1357 };
1358 
1359 // Specialization for real, non-integer types, non-complex types.
1360 template <typename Scalar, typename ExponentScalar>
1361 struct scalar_unary_pow_op<Scalar, ExponentScalar, false, false, false, false> {
1362  template <bool IsExactlyRepresentable = is_floating_exactly_representable<ExponentScalar, Scalar>::value>
1363  std::enable_if_t<IsExactlyRepresentable, void> check_is_representable() const {}
1364 
1365  // Issue a deprecation warning if we do a narrowing conversion on the exponent.
1366  template <bool IsExactlyRepresentable = is_floating_exactly_representable<ExponentScalar, Scalar>::value>
1367  EIGEN_DEPRECATED std::enable_if_t<!IsExactlyRepresentable, void> check_is_representable() const {}
1368 
1369  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE scalar_unary_pow_op(const ExponentScalar& exponent)
1370  : m_exponent(static_cast<Scalar>(exponent)) {
1371  check_is_representable();
1372  }
1373 
1374  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar operator()(const Scalar& a) const {
1375  EIGEN_USING_STD(pow);
1376  return static_cast<Scalar>(pow(a, m_exponent));
1377  }
1378  template <typename Packet>
1379  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a) const {
1380  return unary_pow_impl<Packet, Scalar>::run(a, m_exponent);
1381  }
1382 
1383  private:
1384  const Scalar m_exponent;
1385  scalar_unary_pow_op() {}
1386 };
1387 
1388 template <typename Scalar, typename ExponentScalar, bool BaseIsInteger>
1389 struct scalar_unary_pow_op<Scalar, ExponentScalar, BaseIsInteger, true, false, false> {
1390  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE scalar_unary_pow_op(const ExponentScalar& exponent) : m_exponent(exponent) {}
1391  // TODO: error handling logic for complex^real_integer
1392  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar operator()(const Scalar& a) const {
1393  return unary_pow_impl<Scalar, ExponentScalar>::run(a, m_exponent);
1394  }
1395  template <typename Packet>
1396  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a) const {
1397  return unary_pow_impl<Packet, ExponentScalar>::run(a, m_exponent);
1398  }
1399 
1400  private:
1401  const ExponentScalar m_exponent;
1402  scalar_unary_pow_op() {}
1403 };
1404 
1405 template <typename Scalar, typename ExponentScalar>
1406 struct functor_traits<scalar_unary_pow_op<Scalar, ExponentScalar>> {
1407  enum {
1408  GenPacketAccess = functor_traits<scalar_pow_op<Scalar, ExponentScalar>>::PacketAccess,
1409  IntPacketAccess = !NumTraits<Scalar>::IsComplex && packet_traits<Scalar>::HasMul &&
1410  (packet_traits<Scalar>::HasDiv || NumTraits<Scalar>::IsInteger) && packet_traits<Scalar>::HasCmp,
1411  PacketAccess = NumTraits<ExponentScalar>::IsInteger ? IntPacketAccess : (IntPacketAccess && GenPacketAccess),
1412  Cost = functor_traits<scalar_pow_op<Scalar, ExponentScalar>>::Cost
1413  };
1414 };
1415 
1416 } // end namespace internal
1417 
1418 } // end namespace Eigen
1419 
1420 #endif // EIGEN_FUNCTORS_H
Namespace containing all symbols from the Eigen library.
Definition: B01_Experimental.dox:1
Definition: BFloat16.h:231
const Eigen::CwiseUnaryOp< Eigen::internal::scalar_log10_op< typename Derived::Scalar >, const Derived > log10(const Eigen::ArrayBase< Derived > &x)