BinaryFunctors.h
Go to the documentation of this file.
1 // This file is part of Eigen, a lightweight C++ template library
2 // for linear algebra.
3 //
4 // Copyright (C) 2008-2010 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_BINARY_FUNCTORS_H
11 #define EIGEN_BINARY_FUNCTORS_H
12 
13 #include "../InternalHeaderCheck.h"
14 
15 namespace Eigen {
16 
17 namespace internal {
18 
19 //---------- associative binary functors ----------
20 
21 template<typename Arg1, typename Arg2>
22 struct binary_op_base
23 {
24  typedef Arg1 first_argument_type;
25  typedef Arg2 second_argument_type;
26 };
27 
33 template<typename LhsScalar,typename RhsScalar>
34 struct scalar_sum_op : binary_op_base<LhsScalar,RhsScalar>
35 {
36  typedef typename ScalarBinaryOpTraits<LhsScalar,RhsScalar,scalar_sum_op>::ReturnType result_type;
37 #ifdef EIGEN_SCALAR_BINARY_OP_PLUGIN
38  scalar_sum_op() {
39  EIGEN_SCALAR_BINARY_OP_PLUGIN
40  }
41 #endif
42  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type operator() (const LhsScalar& a, const RhsScalar& b) const { return a + b; }
43  template<typename Packet>
44  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const
45  { return internal::padd(a,b); }
46  template<typename Packet>
47  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type predux(const Packet& a) const
48  { return internal::predux(a); }
49 };
50 template<typename LhsScalar,typename RhsScalar>
51 struct functor_traits<scalar_sum_op<LhsScalar,RhsScalar> > {
52  enum {
53  Cost = (int(NumTraits<LhsScalar>::AddCost) + int(NumTraits<RhsScalar>::AddCost)) / 2, // rough estimate!
54  PacketAccess = is_same<LhsScalar,RhsScalar>::value && packet_traits<LhsScalar>::HasAdd && packet_traits<RhsScalar>::HasAdd
55  // TODO vectorize mixed sum
56  };
57 };
58 
59 
60 template<>
61 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool scalar_sum_op<bool,bool>::operator() (const bool& a, const bool& b) const { return a || b; }
62 
63 
69 template<typename LhsScalar,typename RhsScalar>
70 struct scalar_product_op : binary_op_base<LhsScalar,RhsScalar>
71 {
72  typedef typename ScalarBinaryOpTraits<LhsScalar,RhsScalar,scalar_product_op>::ReturnType result_type;
73 #ifdef EIGEN_SCALAR_BINARY_OP_PLUGIN
74  scalar_product_op() {
75  EIGEN_SCALAR_BINARY_OP_PLUGIN
76  }
77 #endif
78  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type operator() (const LhsScalar& a, const RhsScalar& b) const { return a * b; }
79  template<typename Packet>
80  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const
81  { return internal::pmul(a,b); }
82  template<typename Packet>
83  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type predux(const Packet& a) const
84  { return internal::predux_mul(a); }
85 };
86 template<typename LhsScalar,typename RhsScalar>
87 struct functor_traits<scalar_product_op<LhsScalar,RhsScalar> > {
88  enum {
89  Cost = (int(NumTraits<LhsScalar>::MulCost) + int(NumTraits<RhsScalar>::MulCost))/2, // rough estimate!
90  PacketAccess = is_same<LhsScalar,RhsScalar>::value && packet_traits<LhsScalar>::HasMul && packet_traits<RhsScalar>::HasMul
91  // TODO vectorize mixed product
92  };
93 };
94 
95 template<>
96 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool scalar_product_op<bool,bool>::operator() (const bool& a, const bool& b) const { return a && b; }
97 
98 
104 template<typename LhsScalar,typename RhsScalar>
105 struct scalar_conj_product_op : binary_op_base<LhsScalar,RhsScalar>
106 {
107 
108  enum {
110  };
111 
112  typedef typename ScalarBinaryOpTraits<LhsScalar,RhsScalar,scalar_conj_product_op>::ReturnType result_type;
113 
114  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type operator() (const LhsScalar& a, const RhsScalar& b) const
115  { return conj_helper<LhsScalar,RhsScalar,Conj,false>().pmul(a,b); }
116 
117  template<typename Packet>
118  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const
119  { return conj_helper<Packet,Packet,Conj,false>().pmul(a,b); }
120 };
121 template<typename LhsScalar,typename RhsScalar>
122 struct functor_traits<scalar_conj_product_op<LhsScalar,RhsScalar> > {
123  enum {
125  PacketAccess = internal::is_same<LhsScalar, RhsScalar>::value && packet_traits<LhsScalar>::HasMul
126  };
127 };
128 
134 template<typename LhsScalar,typename RhsScalar, int NaNPropagation>
135 struct scalar_min_op : binary_op_base<LhsScalar,RhsScalar>
136 {
137  typedef typename ScalarBinaryOpTraits<LhsScalar,RhsScalar,scalar_min_op>::ReturnType result_type;
138  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type operator() (const LhsScalar& a, const RhsScalar& b) const {
139  return internal::pmin<NaNPropagation>(a, b);
140  }
141  template<typename Packet>
142  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const
143  {
144  return internal::pmin<NaNPropagation>(a,b);
145  }
146  template<typename Packet>
147  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type predux(const Packet& a) const
148  {
149  return internal::predux_min<NaNPropagation>(a);
150  }
151 };
152 
153 template<typename LhsScalar,typename RhsScalar, int NaNPropagation>
154 struct functor_traits<scalar_min_op<LhsScalar,RhsScalar, NaNPropagation> > {
155  enum {
157  PacketAccess = internal::is_same<LhsScalar, RhsScalar>::value && packet_traits<LhsScalar>::HasMin
158  };
159 };
160 
166 template<typename LhsScalar,typename RhsScalar, int NaNPropagation>
167 struct scalar_max_op : binary_op_base<LhsScalar,RhsScalar>
168 {
169  typedef typename ScalarBinaryOpTraits<LhsScalar,RhsScalar,scalar_max_op>::ReturnType result_type;
170  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type operator() (const LhsScalar& a, const RhsScalar& b) const {
171  return internal::pmax<NaNPropagation>(a,b);
172  }
173  template<typename Packet>
174  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const
175  {
176  return internal::pmax<NaNPropagation>(a,b);
177  }
178  template<typename Packet>
179  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type predux(const Packet& a) const
180  {
181  return internal::predux_max<NaNPropagation>(a);
182  }
183 };
184 
185 template<typename LhsScalar,typename RhsScalar, int NaNPropagation>
186 struct functor_traits<scalar_max_op<LhsScalar,RhsScalar, NaNPropagation> > {
187  enum {
189  PacketAccess = internal::is_same<LhsScalar, RhsScalar>::value && packet_traits<LhsScalar>::HasMax
190  };
191 };
192 
197 template <typename LhsScalar, typename RhsScalar, ComparisonName cmp,
198  bool UseTypedComparators = false>
199 struct scalar_cmp_op;
200 
201 template <typename LhsScalar, typename RhsScalar, ComparisonName cmp, bool UseTypedComparators>
202 struct functor_traits<scalar_cmp_op<LhsScalar, RhsScalar, cmp, UseTypedComparators>> {
203  enum {
205  PacketAccess = (UseTypedComparators || is_same<LhsScalar, bool>::value) && is_same<LhsScalar, RhsScalar>::value &&
206  packet_traits<LhsScalar>::HasCmp
207  };
208 };
209 
210 template <typename LhsScalar, typename RhsScalar, bool UseTypedComparators>
211 struct typed_cmp_helper {
212  static constexpr bool SameType = is_same<LhsScalar, RhsScalar>::value;
213  static constexpr bool IsNumeric = is_arithmetic<typename NumTraits<LhsScalar>::Real>::value;
214  static constexpr bool UseTyped = UseTypedComparators && SameType && IsNumeric;
215  using type = typename conditional<UseTyped, LhsScalar, bool>::type;
216 };
217 
218 template <typename LhsScalar, typename RhsScalar, bool UseTypedComparators>
219 using cmp_return_t = typename typed_cmp_helper<LhsScalar, RhsScalar, UseTypedComparators>::type;
220 
221 template <typename LhsScalar, typename RhsScalar, bool UseTypedComparators>
222 struct scalar_cmp_op<LhsScalar, RhsScalar, cmp_EQ, UseTypedComparators> : binary_op_base<LhsScalar, RhsScalar> {
224  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type operator()(const LhsScalar& a, const RhsScalar& b) const {
225  return a == b ? result_type(1) : result_type(0);
226  }
227  template <typename Packet>
228  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const {
229  const Packet cst_one = pset1<Packet>(result_type(1));
230  return pand(pcmp_eq(a, b), cst_one);
231  }
232 };
233 
234 template <typename LhsScalar, typename RhsScalar, bool UseTypedComparators>
235 struct scalar_cmp_op<LhsScalar, RhsScalar, cmp_LT, UseTypedComparators> : binary_op_base<LhsScalar, RhsScalar> {
236  using result_type = cmp_return_t<LhsScalar, RhsScalar, UseTypedComparators>;
237  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type operator()(const LhsScalar& a, const RhsScalar& b) const {
238  return a < b ? result_type(1) : result_type(0);
239  }
240  template <typename Packet>
241  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const {
242  const Packet cst_one = pset1<Packet>(result_type(1));
243  return pand(pcmp_lt(a, b), cst_one);
244  }
245 };
246 
247 template <typename LhsScalar, typename RhsScalar, bool UseTypedComparators>
248 struct scalar_cmp_op<LhsScalar, RhsScalar, cmp_LE, UseTypedComparators> : binary_op_base<LhsScalar, RhsScalar> {
249  using result_type = cmp_return_t<LhsScalar, RhsScalar, UseTypedComparators>;
250  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type operator()(const LhsScalar& a, const RhsScalar& b) const {
251  return a <= b ? result_type(1) : result_type(0);
252  }
253  template <typename Packet>
254  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const {
255  const Packet cst_one = pset1<Packet>(result_type(1));
256  return pand(cst_one, pcmp_le(a, b));
257  }
258 };
259 
260 template <typename LhsScalar, typename RhsScalar, bool UseTypedComparators>
261 struct scalar_cmp_op<LhsScalar, RhsScalar, cmp_GT, UseTypedComparators> : binary_op_base<LhsScalar, RhsScalar> {
262  using result_type = cmp_return_t<LhsScalar, RhsScalar, UseTypedComparators>;
263  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type operator()(const LhsScalar& a, const RhsScalar& b) const {
264  return a > b ? result_type(1) : result_type(0);
265  }
266  template <typename Packet>
267  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const {
268  const Packet cst_one = pset1<Packet>(result_type(1));
269  return pand(cst_one, pcmp_lt(b, a));
270  }
271 };
272 
273 template <typename LhsScalar, typename RhsScalar, bool UseTypedComparators>
274 struct scalar_cmp_op<LhsScalar, RhsScalar, cmp_GE, UseTypedComparators> : binary_op_base<LhsScalar, RhsScalar> {
275  using result_type = cmp_return_t<LhsScalar, RhsScalar, UseTypedComparators>;
276  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type operator()(const LhsScalar& a, const RhsScalar& b) const {
277  return a >= b ? result_type(1) : result_type(0);
278  }
279  template <typename Packet>
280  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const {
281  const Packet cst_one = pset1<Packet>(result_type(1));
282  return pand(cst_one, pcmp_le(b, a));
283  }
284 };
285 
286 template <typename LhsScalar, typename RhsScalar, bool UseTypedComparators>
287 struct scalar_cmp_op<LhsScalar, RhsScalar, cmp_UNORD, UseTypedComparators> : binary_op_base<LhsScalar, RhsScalar> {
288  using result_type = cmp_return_t<LhsScalar, RhsScalar, UseTypedComparators>;
289  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type operator()(const LhsScalar& a, const RhsScalar& b) const {
290  return !(a <= b || b <= a) ? result_type(1) : result_type(0);
291  }
292  template <typename Packet>
293  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const {
294  const Packet cst_one = pset1<Packet>(result_type(1));
295  return pandnot(cst_one, por(pcmp_le(a, b), pcmp_le(b, a)));
296  }
297 };
298 
299 template <typename LhsScalar, typename RhsScalar, bool UseTypedComparators>
300 struct scalar_cmp_op<LhsScalar, RhsScalar, cmp_NEQ, UseTypedComparators> : binary_op_base<LhsScalar, RhsScalar> {
301  using result_type = cmp_return_t<LhsScalar, RhsScalar, UseTypedComparators>;
302  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type operator()(const LhsScalar& a, const RhsScalar& b) const {
303  return a != b ? result_type(1) : result_type(0);
304  }
305  template <typename Packet>
306  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const {
307  const Packet cst_one = pset1<Packet>(result_type(1));
308  return pandnot(cst_one, pcmp_eq(a, b));
309  }
310 };
311 
317 template<typename Scalar>
318 struct scalar_hypot_op<Scalar,Scalar> : binary_op_base<Scalar,Scalar>
319 {
320  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar operator() (const Scalar &x, const Scalar &y) const
321  {
322  // This functor is used by hypotNorm only for which it is faster to first apply abs
323  // on all coefficients prior to reduction through hypot.
324  // This way we avoid calling abs on positive and real entries, and this also permits
325  // to seamlessly handle complexes. Otherwise we would have to handle both real and complexes
326  // through the same functor...
328  }
329 };
330 template<typename Scalar>
331 struct functor_traits<scalar_hypot_op<Scalar,Scalar> > {
332  enum
333  {
334  Cost = 3 * NumTraits<Scalar>::AddCost +
336  2 * scalar_div_cost<Scalar,false>::value,
337  PacketAccess = false
338  };
339 };
340 
345 template<typename Scalar, typename Exponent>
346 struct scalar_pow_op : binary_op_base<Scalar,Exponent>
347 {
348  typedef typename ScalarBinaryOpTraits<Scalar,Exponent,scalar_pow_op>::ReturnType result_type;
349 #ifdef EIGEN_SCALAR_BINARY_OP_PLUGIN
350  scalar_pow_op() {
351  typedef Scalar LhsScalar;
352  typedef Exponent RhsScalar;
353  EIGEN_SCALAR_BINARY_OP_PLUGIN
354  }
355 #endif
356 
358  inline result_type operator() (const Scalar& a, const Exponent& b) const { return numext::pow(a, b); }
359 
360  template<typename Packet>
361  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& b) const
362  {
363  return generic_pow(a,b);
364  }
365 };
366 
367 template<typename Scalar, typename Exponent>
368 struct functor_traits<scalar_pow_op<Scalar,Exponent> > {
369  enum {
370  Cost = 5 * NumTraits<Scalar>::MulCost,
372  packet_traits<Scalar>::HasExp && packet_traits<Scalar>::HasLog &&
373  packet_traits<Scalar>::HasRound && packet_traits<Scalar>::HasCmp &&
374  // Temporarily disable packet access for half/bfloat16 until
375  // accuracy is improved.
376  !is_same<Scalar, half>::value && !is_same<Scalar, bfloat16>::value
377  )
378  };
379 };
380 
381 //---------- non associative binary functors ----------
382 
388 template<typename LhsScalar,typename RhsScalar>
389 struct scalar_difference_op : binary_op_base<LhsScalar,RhsScalar>
390 {
391  typedef typename ScalarBinaryOpTraits<LhsScalar,RhsScalar,scalar_difference_op>::ReturnType result_type;
392 #ifdef EIGEN_SCALAR_BINARY_OP_PLUGIN
393  scalar_difference_op() {
394  EIGEN_SCALAR_BINARY_OP_PLUGIN
395  }
396 #endif
397  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const result_type operator() (const LhsScalar& a, const RhsScalar& b) const { return a - b; }
398  template<typename Packet>
399  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& b) const
400  { return internal::psub(a,b); }
401 };
402 template<typename LhsScalar,typename RhsScalar>
403 struct functor_traits<scalar_difference_op<LhsScalar,RhsScalar> > {
404  enum {
406  PacketAccess = is_same<LhsScalar,RhsScalar>::value && packet_traits<LhsScalar>::HasSub && packet_traits<RhsScalar>::HasSub
407  };
408 };
409 
410 template <typename Packet, bool IsInteger = NumTraits<typename unpacket_traits<Packet>::type>::IsInteger>
411 struct maybe_raise_div_by_zero {
412  static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void run(Packet x) {
414  }
415 };
416 
417 #ifndef EIGEN_GPU_COMPILE_PHASE
418 template <typename Packet>
419 struct maybe_raise_div_by_zero<Packet, true> {
420  static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void run(Packet x) {
422  // Use volatile variables to force a division by zero, which will
423  // result in the default platform behaviour (usually SIGFPE).
424  volatile typename unpacket_traits<Packet>::type zero = 0;
425  volatile typename unpacket_traits<Packet>::type val = 1;
426  val = val / zero;
427  }
428  }
429 };
430 #endif
431 
437 template<typename LhsScalar,typename RhsScalar>
438 struct scalar_quotient_op : binary_op_base<LhsScalar,RhsScalar>
439 {
440  typedef typename ScalarBinaryOpTraits<LhsScalar,RhsScalar,scalar_quotient_op>::ReturnType result_type;
441 #ifdef EIGEN_SCALAR_BINARY_OP_PLUGIN
442  scalar_quotient_op() {
443  EIGEN_SCALAR_BINARY_OP_PLUGIN
444  }
445 #endif
446  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const result_type operator() (const LhsScalar& a, const RhsScalar& b) const { return a / b; }
447  template<typename Packet>
448  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& b) const {
449  maybe_raise_div_by_zero<Packet>::run(b);
450  return internal::pdiv(a,b);
451  }
452 };
453 template<typename LhsScalar,typename RhsScalar>
454 struct functor_traits<scalar_quotient_op<LhsScalar,RhsScalar> > {
455  typedef typename scalar_quotient_op<LhsScalar,RhsScalar>::result_type result_type;
456  enum {
457  PacketAccess = is_same<LhsScalar,RhsScalar>::value && packet_traits<LhsScalar>::HasDiv && packet_traits<RhsScalar>::HasDiv,
458  Cost = scalar_div_cost<result_type,PacketAccess>::value
459  };
460 };
461 
467 template <typename Scalar>
468 struct scalar_boolean_and_op {
469  using result_type = Scalar;
470  // `false` any value `a` that satisfies `a == Scalar(0)`
471  // `true` is the complement of `false`
472  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar operator()(const Scalar& a, const Scalar& b) const {
473  return (a != Scalar(0)) && (b != Scalar(0)) ? Scalar(1) : Scalar(0);
474  }
475  template <typename Packet>
476  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const {
477  const Packet cst_one = pset1<Packet>(Scalar(1));
478  // and(a,b) == !or(!a,!b)
479  Packet not_a = pcmp_eq(a, pzero(a));
480  Packet not_b = pcmp_eq(b, pzero(b));
481  Packet a_nand_b = por(not_a, not_b);
482  return pandnot(cst_one, a_nand_b);
483  }
484 };
485 template <typename Scalar>
486 struct functor_traits<scalar_boolean_and_op<Scalar>> {
487  enum { Cost = NumTraits<Scalar>::AddCost, PacketAccess = packet_traits<Scalar>::HasCmp };
488 };
489 
495 template <typename Scalar>
496 struct scalar_boolean_or_op {
497  using result_type = Scalar;
498  // `false` any value `a` that satisfies `a == Scalar(0)`
499  // `true` is the complement of `false`
500  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar operator()(const Scalar& a, const Scalar& b) const {
501  return (a != Scalar(0)) || (b != Scalar(0)) ? Scalar(1) : Scalar(0);
502  }
503  template <typename Packet>
504  EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const {
505  const Packet cst_one = pset1<Packet>(Scalar(1));
506  // if or(a,b) == 0, then a == 0 and b == 0
507  // or(a,b) == !nor(a,b)
508  Packet a_nor_b = pcmp_eq(por(a, b), pzero(a));
509  return pandnot(cst_one, a_nor_b);
510  }
511 };
512 template <typename Scalar>
513 struct functor_traits<scalar_boolean_or_op<Scalar>> {
514  enum { Cost = NumTraits<Scalar>::AddCost, PacketAccess = packet_traits<Scalar>::HasCmp };
515 };
516 
522 template <typename Scalar>
523 struct scalar_boolean_xor_op {
524  using result_type = Scalar;
525  // `false` any value `a` that satisfies `a == Scalar(0)`
526  // `true` is the complement of `false`
527  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar operator()(const Scalar& a, const Scalar& b) const {
528  return (a != Scalar(0)) != (b != Scalar(0)) ? Scalar(1) : Scalar(0);
529  }
530  template <typename Packet>
531  EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const {
532  const Packet cst_one = pset1<Packet>(Scalar(1));
533  // xor(a,b) == xor(!a,!b)
534  Packet not_a = pcmp_eq(a, pzero(a));
535  Packet not_b = pcmp_eq(b, pzero(b));
536  Packet a_xor_b = pxor(not_a, not_b);
537  return pand(cst_one, a_xor_b);
538  }
539 };
540 template <typename Scalar>
541 struct functor_traits<scalar_boolean_xor_op<Scalar>> {
542  enum { Cost = NumTraits<Scalar>::AddCost, PacketAccess = packet_traits<Scalar>::HasCmp };
543 };
544 
545 template <typename Scalar, bool IsComplex = NumTraits<Scalar>::IsComplex>
546 struct bitwise_binary_impl {
547  static constexpr size_t Size = sizeof(Scalar);
548  using uint_t = typename numext::get_integer_by_size<Size>::unsigned_type;
549  static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar run_and(const Scalar& a, const Scalar& b) {
550  uint_t a_as_uint = numext::bit_cast<uint_t, Scalar>(a);
551  uint_t b_as_uint = numext::bit_cast<uint_t, Scalar>(b);
552  uint_t result = a_as_uint & b_as_uint;
553  return numext::bit_cast<Scalar, uint_t>(result);
554  }
555  static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar run_or(const Scalar& a, const Scalar& b) {
556  uint_t a_as_uint = numext::bit_cast<uint_t, Scalar>(a);
557  uint_t b_as_uint = numext::bit_cast<uint_t, Scalar>(b);
558  uint_t result = a_as_uint | b_as_uint;
559  return numext::bit_cast<Scalar, uint_t>(result);
560  }
561  static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar run_xor(const Scalar& a, const Scalar& b) {
562  uint_t a_as_uint = numext::bit_cast<uint_t, Scalar>(a);
563  uint_t b_as_uint = numext::bit_cast<uint_t, Scalar>(b);
564  uint_t result = a_as_uint ^ b_as_uint;
565  return numext::bit_cast<Scalar, uint_t>(result);
566  }
567 };
568 
569 template <typename Scalar>
570 struct bitwise_binary_impl<Scalar, true> {
571  using Real = typename NumTraits<Scalar>::Real;
572  static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar run_and(const Scalar& a, const Scalar& b) {
573  Real real_result = bitwise_binary_impl<Real>::run_and(numext::real(a), numext::real(b));
574  Real imag_result = bitwise_binary_impl<Real>::run_and(numext::imag(a), numext::imag(b));
575  return Scalar(real_result, imag_result);
576  }
577  static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar run_or(const Scalar& a, const Scalar& b) {
578  Real real_result = bitwise_binary_impl<Real>::run_or(numext::real(a), numext::real(b));
579  Real imag_result = bitwise_binary_impl<Real>::run_or(numext::imag(a), numext::imag(b));
580  return Scalar(real_result, imag_result);
581  }
582  static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar run_xor(const Scalar& a, const Scalar& b) {
583  Real real_result = bitwise_binary_impl<Real>::run_xor(numext::real(a), numext::real(b));
584  Real imag_result = bitwise_binary_impl<Real>::run_xor(numext::imag(a), numext::imag(b));
585  return Scalar(real_result, imag_result);
586  }
587 };
588 
594 template <typename Scalar>
595 struct scalar_bitwise_and_op {
597  BITWISE OPERATIONS MAY ONLY BE PERFORMED ON PLAIN DATA TYPES)
598  EIGEN_STATIC_ASSERT((!internal::is_same<Scalar, bool>::value), DONT USE BITWISE OPS ON BOOLEAN TYPES)
599  using result_type = Scalar;
600  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar operator()(const Scalar& a, const Scalar& b) const {
601  return bitwise_binary_impl<Scalar>::run_and(a, b);
602  }
603  template <typename Packet>
604  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const {
605  return pand(a, b);
606  }
607 };
608 template <typename Scalar>
609 struct functor_traits<scalar_bitwise_and_op<Scalar>> {
610  enum { Cost = NumTraits<Scalar>::AddCost, PacketAccess = true };
611 };
612 
618 template <typename Scalar>
619 struct scalar_bitwise_or_op {
621  BITWISE OPERATIONS MAY ONLY BE PERFORMED ON PLAIN DATA TYPES)
622  EIGEN_STATIC_ASSERT((!internal::is_same<Scalar, bool>::value), DONT USE BITWISE OPS ON BOOLEAN TYPES)
623  using result_type = Scalar;
624  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar operator()(const Scalar& a, const Scalar& b) const {
625  return bitwise_binary_impl<Scalar>::run_or(a, b);
626  }
627  template <typename Packet>
628  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const {
629  return por(a, b);
630  }
631 };
632 template <typename Scalar>
633 struct functor_traits<scalar_bitwise_or_op<Scalar>> {
634  enum { Cost = NumTraits<Scalar>::AddCost, PacketAccess = true };
635 };
636 
642 template <typename Scalar>
643 struct scalar_bitwise_xor_op {
645  BITWISE OPERATIONS MAY ONLY BE PERFORMED ON PLAIN DATA TYPES)
646  EIGEN_STATIC_ASSERT((!internal::is_same<Scalar, bool>::value), DONT USE BITWISE OPS ON BOOLEAN TYPES)
647  using result_type = Scalar;
648  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar operator()(const Scalar& a, const Scalar& b) const {
649  return bitwise_binary_impl<Scalar>::run_xor(a, b);
650  }
651  template <typename Packet>
652  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const {
653  return pxor(a, b);
654  }
655 };
656 template <typename Scalar>
657 struct functor_traits<scalar_bitwise_xor_op<Scalar>> {
658  enum { Cost = NumTraits<Scalar>::AddCost, PacketAccess = true };
659 };
660 
666 template<typename LhsScalar,typename RhsScalar>
667 struct scalar_absolute_difference_op : binary_op_base<LhsScalar,RhsScalar>
668 {
669  typedef typename ScalarBinaryOpTraits<LhsScalar,RhsScalar,scalar_absolute_difference_op>::ReturnType result_type;
670 #ifdef EIGEN_SCALAR_BINARY_OP_PLUGIN
671  scalar_absolute_difference_op() {
672  EIGEN_SCALAR_BINARY_OP_PLUGIN
673  }
674 #endif
675  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const result_type operator() (const LhsScalar& a, const RhsScalar& b) const
676  { return numext::absdiff(a,b); }
677  template<typename Packet>
678  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& b) const
679  { return internal::pabsdiff(a,b); }
680 };
681 template<typename LhsScalar,typename RhsScalar>
682 struct functor_traits<scalar_absolute_difference_op<LhsScalar,RhsScalar> > {
683  enum {
685  PacketAccess = is_same<LhsScalar,RhsScalar>::value && packet_traits<LhsScalar>::HasAbsDiff
686  };
687 };
688 
689 
690 template <typename LhsScalar, typename RhsScalar>
691 struct scalar_atan2_op {
692  using Scalar = LhsScalar;
693 
694  static constexpr bool Enable = is_same<LhsScalar, RhsScalar>::value && !NumTraits<Scalar>::IsInteger && !NumTraits<Scalar>::IsComplex;
695  EIGEN_STATIC_ASSERT(Enable, "LhsScalar and RhsScalar must be the same non-integer, non-complex type")
696 
697  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar operator()(const Scalar& y, const Scalar& x) const {
698  return numext::atan2(y, x);
699  }
700  template <typename Packet>
701  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& y, const Packet& x) const {
702  return internal::patan2(y, x);
703  }
704 };
705 
706 template<typename LhsScalar,typename RhsScalar>
707  struct functor_traits<scalar_atan2_op<LhsScalar, RhsScalar>> {
708  using Scalar = LhsScalar;
709  enum {
710  PacketAccess = is_same<LhsScalar,RhsScalar>::value && packet_traits<Scalar>::HasATan && packet_traits<Scalar>::HasDiv && !NumTraits<Scalar>::IsInteger && !NumTraits<Scalar>::IsComplex,
711  Cost = int(scalar_div_cost<Scalar, PacketAccess>::value) + int(functor_traits<scalar_atan_op<Scalar>>::Cost)
712  };
713 };
714 
715 //---------- binary functors bound to a constant, thus appearing as a unary functor ----------
716 
717 // The following two classes permits to turn any binary functor into a unary one with one argument bound to a constant value.
718 // They are analogues to std::binder1st/binder2nd but with the following differences:
719 // - they are compatible with packetOp
720 // - they are portable across C++ versions (the std::binder* are deprecated in C++11)
721 template<typename BinaryOp> struct bind1st_op : BinaryOp {
722 
723  typedef typename BinaryOp::first_argument_type first_argument_type;
724  typedef typename BinaryOp::second_argument_type second_argument_type;
725  typedef typename BinaryOp::result_type result_type;
726 
727  EIGEN_DEVICE_FUNC explicit bind1st_op(const first_argument_type &val) : m_value(val) {}
728 
729  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const result_type operator() (const second_argument_type& b) const { return BinaryOp::operator()(m_value,b); }
730 
731  template<typename Packet>
732  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Packet packetOp(const Packet& b) const
733  { return BinaryOp::packetOp(internal::pset1<Packet>(m_value), b); }
734 
735  first_argument_type m_value;
736 };
737 template<typename BinaryOp> struct functor_traits<bind1st_op<BinaryOp> > : functor_traits<BinaryOp> {};
738 
739 
740 template<typename BinaryOp> struct bind2nd_op : BinaryOp {
741 
742  typedef typename BinaryOp::first_argument_type first_argument_type;
743  typedef typename BinaryOp::second_argument_type second_argument_type;
744  typedef typename BinaryOp::result_type result_type;
745 
746  EIGEN_DEVICE_FUNC explicit bind2nd_op(const second_argument_type &val) : m_value(val) {}
747 
748  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const result_type operator() (const first_argument_type& a) const { return BinaryOp::operator()(a,m_value); }
749 
750  template<typename Packet>
751  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a) const
752  { return BinaryOp::packetOp(a,internal::pset1<Packet>(m_value)); }
753 
754  second_argument_type m_value;
755 };
756 template<typename BinaryOp> struct functor_traits<bind2nd_op<BinaryOp> > : functor_traits<BinaryOp> {};
757 
758 
759 } // end namespace internal
760 
761 } // end namespace Eigen
762 
763 #endif // EIGEN_BINARY_FUNCTORS_H
Array< int, 3, 1 > b
const ImagReturnType imag() const
RealReturnType real() const
IndexedView_or_Block operator()(const RowIndices &rowIndices, const ColIndices &colIndices)
#define EIGEN_PREDICT_FALSE(x)
Definition: Macros.h:1177
#define EIGEN_UNUSED_VARIABLE(var)
Definition: Macros.h:957
#define EIGEN_DEVICE_FUNC
Definition: Macros.h:883
#define EIGEN_STATIC_ASSERT(X, MSG)
Definition: StaticAssert.h:26
Packet padd(const Packet &a, const Packet &b)
Packet8f pzero(const Packet8f &)
unpacket_traits< Packet >::type predux(const Packet &a)
const Scalar & y
Packet8h pandnot(const Packet8h &a, const Packet8h &b)
EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS Packet generic_pow(const Packet &x, const Packet &y)
EIGEN_ALWAYS_INLINE Packet patan2(const Packet &y, const Packet &x)
Packet2cf pcmp_eq(const Packet2cf &a, const Packet2cf &b)
Packet pmul(const Packet &a, const Packet &b)
Packet psub(const Packet &a, const Packet &b)
unpacket_traits< Packet >::type predux_mul(const Packet &a)
Packet8h pand(const Packet8h &a, const Packet8h &b)
Packet pabsdiff(const Packet &a, const Packet &b)
Packet8h pxor(const Packet8h &a, const Packet8h &b)
Packet pdiv(const Packet &a, const Packet &b)
Packet8h por(const Packet8h &a, const Packet8h &b)
Packet4i pcmp_lt(const Packet4i &a, const Packet4i &b)
RealScalar positive_real_hypot(const RealScalar &x, const RealScalar &y)
bool predux_any(const Packet4f &x)
Packet4f pcmp_le(const Packet4f &a, const Packet4f &b)
typename typed_cmp_helper< LhsScalar, RhsScalar, UseTypedComparators >::type cmp_return_t
EIGEN_ALWAYS_INLINE T absdiff(const T &x, const T &y)
internal::pow_impl< ScalarX, ScalarY >::result_type pow(const ScalarX &x, const ScalarY &y)
EIGEN_ALWAYS_INLINE T atan2(const T &y, const T &x)
: InteropHeaders
Definition: Core:139