$darkmode
Eigen  5.0.1-dev
BinaryFunctors.h
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 // IWYU pragma: private
14 #include "../InternalHeaderCheck.h"
15 
16 namespace Eigen {
17 
18 namespace internal {
19 
20 //---------- associative binary functors ----------
21 
22 template <typename Arg1, typename Arg2>
23 struct binary_op_base {
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  typedef typename ScalarBinaryOpTraits<LhsScalar, RhsScalar, scalar_sum_op>::ReturnType result_type;
36 #ifdef EIGEN_SCALAR_BINARY_OP_PLUGIN
37  scalar_sum_op(){EIGEN_SCALAR_BINARY_OP_PLUGIN}
38 #endif
39  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type
40  operator()(const LhsScalar& a, const RhsScalar& b) const {
41  return a + b;
42  }
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  }
47  template <typename Packet>
48  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type predux(const Packet& a) const {
49  return internal::predux(a);
50  }
51 };
52 template <typename LhsScalar, typename RhsScalar>
53 struct functor_traits<scalar_sum_op<LhsScalar, RhsScalar>> {
54  enum {
55  Cost = (int(NumTraits<LhsScalar>::AddCost) + int(NumTraits<RhsScalar>::AddCost)) / 2, // rough estimate!
56  PacketAccess =
57  is_same<LhsScalar, RhsScalar>::value && packet_traits<LhsScalar>::HasAdd && packet_traits<RhsScalar>::HasAdd
58  // TODO vectorize mixed sum
59  };
60 };
61 
62 template <>
63 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool scalar_sum_op<bool, bool>::operator()(const bool& a, const bool& b) const {
64  return a || b;
65 }
66 
72 template <typename LhsScalar, typename RhsScalar>
73 struct scalar_product_op : binary_op_base<LhsScalar, RhsScalar> {
74  typedef typename ScalarBinaryOpTraits<LhsScalar, RhsScalar, scalar_product_op>::ReturnType result_type;
75 #ifdef EIGEN_SCALAR_BINARY_OP_PLUGIN
76  scalar_product_op(){EIGEN_SCALAR_BINARY_OP_PLUGIN}
77 #endif
78  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type
79  operator()(const LhsScalar& a, const RhsScalar& b) const {
80  return a * b;
81  }
82  template <typename Packet>
83  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const {
84  return internal::pmul(a, b);
85  }
86  template <typename Packet>
87  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type predux(const Packet& a) const {
88  return internal::predux_mul(a);
89  }
90 };
91 template <typename LhsScalar, typename RhsScalar>
92 struct functor_traits<scalar_product_op<LhsScalar, RhsScalar>> {
93  enum {
94  Cost = (int(NumTraits<LhsScalar>::MulCost) + int(NumTraits<RhsScalar>::MulCost)) / 2, // rough estimate!
95  PacketAccess =
96  is_same<LhsScalar, RhsScalar>::value && packet_traits<LhsScalar>::HasMul && packet_traits<RhsScalar>::HasMul
97  // TODO vectorize mixed product
98  };
99 };
100 
101 template <>
102 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool scalar_product_op<bool, bool>::operator()(const bool& a,
103  const bool& b) const {
104  return a && b;
105 }
106 
113 template <typename LhsScalar, typename RhsScalar>
114 struct scalar_conj_product_op : binary_op_base<LhsScalar, RhsScalar> {
115  enum { Conj = NumTraits<LhsScalar>::IsComplex };
116 
117  typedef typename ScalarBinaryOpTraits<LhsScalar, RhsScalar, scalar_conj_product_op>::ReturnType result_type;
118 
119  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type operator()(const LhsScalar& a, const RhsScalar& b) const {
120  return conj_helper<LhsScalar, RhsScalar, Conj, false>().pmul(a, b);
121  }
122 
123  template <typename Packet>
124  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const {
125  return conj_helper<Packet, Packet, Conj, false>().pmul(a, b);
126  }
127 };
128 template <typename LhsScalar, typename RhsScalar>
129 struct functor_traits<scalar_conj_product_op<LhsScalar, RhsScalar>> {
130  enum {
131  Cost = NumTraits<LhsScalar>::MulCost,
132  PacketAccess = internal::is_same<LhsScalar, RhsScalar>::value && packet_traits<LhsScalar>::HasMul
133  };
134 };
135 
141 template <typename LhsScalar, typename RhsScalar, int NaNPropagation>
142 struct scalar_min_op : binary_op_base<LhsScalar, RhsScalar> {
143  typedef typename ScalarBinaryOpTraits<LhsScalar, RhsScalar, scalar_min_op>::ReturnType result_type;
144  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type operator()(const LhsScalar& a, const RhsScalar& b) const {
145  return internal::pmin<NaNPropagation>(a, b);
146  }
147  template <typename Packet>
148  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const {
149  return internal::pmin<NaNPropagation>(a, b);
150  }
151  template <typename Packet>
152  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type predux(const Packet& a) const {
153  return internal::predux_min<NaNPropagation>(a);
154  }
155 };
156 
157 template <typename LhsScalar, typename RhsScalar, int NaNPropagation>
158 struct functor_traits<scalar_min_op<LhsScalar, RhsScalar, NaNPropagation>> {
159  enum {
160  Cost = (NumTraits<LhsScalar>::AddCost + NumTraits<RhsScalar>::AddCost) / 2,
161  PacketAccess = internal::is_same<LhsScalar, RhsScalar>::value && packet_traits<LhsScalar>::HasMin
162  };
163 };
164 
170 template <typename LhsScalar, typename RhsScalar, int NaNPropagation>
171 struct scalar_max_op : binary_op_base<LhsScalar, RhsScalar> {
172  typedef typename ScalarBinaryOpTraits<LhsScalar, RhsScalar, scalar_max_op>::ReturnType result_type;
173  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type operator()(const LhsScalar& a, const RhsScalar& b) const {
174  return internal::pmax<NaNPropagation>(a, b);
175  }
176  template <typename Packet>
177  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const {
178  return internal::pmax<NaNPropagation>(a, b);
179  }
180  template <typename Packet>
181  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type predux(const Packet& a) const {
182  return internal::predux_max<NaNPropagation>(a);
183  }
184 };
185 
186 template <typename LhsScalar, typename RhsScalar, int NaNPropagation>
187 struct functor_traits<scalar_max_op<LhsScalar, RhsScalar, NaNPropagation>> {
188  enum {
189  Cost = (NumTraits<LhsScalar>::AddCost + NumTraits<RhsScalar>::AddCost) / 2,
190  PacketAccess = internal::is_same<LhsScalar, RhsScalar>::value && packet_traits<LhsScalar>::HasMax
191  };
192 };
193 
198 template <typename LhsScalar, typename RhsScalar, ComparisonName cmp, 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 {
204  Cost = (NumTraits<LhsScalar>::AddCost + NumTraits<RhsScalar>::AddCost) / 2,
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 scalar_cmp_op<LhsScalar, RhsScalar, cmp_EQ, UseTypedComparators> : binary_op_base<LhsScalar, RhsScalar> {
212  using result_type = std::conditional_t<UseTypedComparators, LhsScalar, bool>;
213  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type operator()(const LhsScalar& a, const RhsScalar& b) const {
214  return a == b ? result_type(1) : result_type(0);
215  }
216  template <typename Packet>
217  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const {
218  const Packet cst_one = pset1<Packet>(result_type(1));
219  return pand(pcmp_eq(a, b), cst_one);
220  }
221 };
222 
223 template <typename LhsScalar, typename RhsScalar, bool UseTypedComparators>
224 struct scalar_cmp_op<LhsScalar, RhsScalar, cmp_LT, UseTypedComparators> : binary_op_base<LhsScalar, RhsScalar> {
225  using result_type = std::conditional_t<UseTypedComparators, LhsScalar, bool>;
226  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type operator()(const LhsScalar& a, const RhsScalar& b) const {
227  return a < b ? result_type(1) : result_type(0);
228  }
229  template <typename Packet>
230  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const {
231  const Packet cst_one = pset1<Packet>(result_type(1));
232  return pand(pcmp_lt(a, b), cst_one);
233  }
234 };
235 
236 template <typename LhsScalar, typename RhsScalar, bool UseTypedComparators>
237 struct scalar_cmp_op<LhsScalar, RhsScalar, cmp_LE, UseTypedComparators> : binary_op_base<LhsScalar, RhsScalar> {
238  using result_type = std::conditional_t<UseTypedComparators, LhsScalar, bool>;
239  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type operator()(const LhsScalar& a, const RhsScalar& b) const {
240  return a <= b ? result_type(1) : result_type(0);
241  }
242  template <typename Packet>
243  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const {
244  const Packet cst_one = pset1<Packet>(result_type(1));
245  return pand(cst_one, pcmp_le(a, b));
246  }
247 };
248 
249 template <typename LhsScalar, typename RhsScalar, bool UseTypedComparators>
250 struct scalar_cmp_op<LhsScalar, RhsScalar, cmp_GT, UseTypedComparators> : binary_op_base<LhsScalar, RhsScalar> {
251  using result_type = std::conditional_t<UseTypedComparators, LhsScalar, bool>;
252  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type operator()(const LhsScalar& a, const RhsScalar& b) const {
253  return a > b ? result_type(1) : result_type(0);
254  }
255  template <typename Packet>
256  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const {
257  const Packet cst_one = pset1<Packet>(result_type(1));
258  return pand(cst_one, pcmp_lt(b, a));
259  }
260 };
261 
262 template <typename LhsScalar, typename RhsScalar, bool UseTypedComparators>
263 struct scalar_cmp_op<LhsScalar, RhsScalar, cmp_GE, UseTypedComparators> : binary_op_base<LhsScalar, RhsScalar> {
264  using result_type = std::conditional_t<UseTypedComparators, LhsScalar, bool>;
265  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type operator()(const LhsScalar& a, const RhsScalar& b) const {
266  return a >= b ? result_type(1) : result_type(0);
267  }
268  template <typename Packet>
269  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const {
270  const Packet cst_one = pset1<Packet>(result_type(1));
271  return pand(cst_one, pcmp_le(b, a));
272  }
273 };
274 
275 template <typename LhsScalar, typename RhsScalar, bool UseTypedComparators>
276 struct scalar_cmp_op<LhsScalar, RhsScalar, cmp_UNORD, UseTypedComparators> : binary_op_base<LhsScalar, RhsScalar> {
277  using result_type = std::conditional_t<UseTypedComparators, LhsScalar, bool>;
278  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type operator()(const LhsScalar& a, const RhsScalar& b) const {
279  return !(a <= b || b <= a) ? result_type(1) : result_type(0);
280  }
281  template <typename Packet>
282  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const {
283  const Packet cst_one = pset1<Packet>(result_type(1));
284  return pandnot(cst_one, por(pcmp_le(a, b), pcmp_le(b, a)));
285  }
286 };
287 
288 template <typename LhsScalar, typename RhsScalar, bool UseTypedComparators>
289 struct scalar_cmp_op<LhsScalar, RhsScalar, cmp_NEQ, UseTypedComparators> : binary_op_base<LhsScalar, RhsScalar> {
290  using result_type = std::conditional_t<UseTypedComparators, LhsScalar, bool>;
291  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type operator()(const LhsScalar& a, const RhsScalar& b) const {
292  return a != b ? result_type(1) : result_type(0);
293  }
294  template <typename Packet>
295  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const {
296  const Packet cst_one = pset1<Packet>(result_type(1));
297  return pandnot(cst_one, pcmp_eq(a, b));
298  }
299 };
300 
306 template <typename Scalar>
307 struct scalar_hypot_op<Scalar, Scalar> : binary_op_base<Scalar, Scalar> {
308  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar operator()(const Scalar& x, const Scalar& y) const {
309  // This functor is used by hypotNorm only for which it is faster to first apply abs
310  // on all coefficients prior to reduction through hypot.
311  // This way we avoid calling abs on positive and real entries, and this also permits
312  // to seamlessly handle complexes. Otherwise we would have to handle both real and complexes
313  // through the same functor...
314  return internal::positive_real_hypot(x, y);
315  }
316 };
317 template <typename Scalar>
318 struct functor_traits<scalar_hypot_op<Scalar, Scalar>> {
319  enum {
320  Cost = 3 * NumTraits<Scalar>::AddCost + 2 * NumTraits<Scalar>::MulCost + 2 * scalar_div_cost<Scalar, false>::value,
321  PacketAccess = false
322  };
323 };
324 
329 template <typename Scalar, typename Exponent>
330 struct scalar_pow_op : binary_op_base<Scalar, Exponent> {
331  typedef typename ScalarBinaryOpTraits<Scalar, Exponent, scalar_pow_op>::ReturnType result_type;
332 #ifdef EIGEN_SCALAR_BINARY_OP_PLUGIN
333  scalar_pow_op() {
334  typedef Scalar LhsScalar;
335  typedef Exponent RhsScalar;
336  EIGEN_SCALAR_BINARY_OP_PLUGIN
337  }
338 #endif
339 
340  EIGEN_DEVICE_FUNC inline result_type operator()(const Scalar& a, const Exponent& b) const {
341  return numext::pow(a, b);
342  }
343 
344  template <typename Packet>
345  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& b) const {
346  return generic_pow(a, b);
347  }
348 };
349 
350 template <typename Scalar, typename Exponent>
351 struct functor_traits<scalar_pow_op<Scalar, Exponent>> {
352  enum {
353  Cost = 5 * NumTraits<Scalar>::MulCost,
354  PacketAccess = (!NumTraits<Scalar>::IsComplex && !NumTraits<Scalar>::IsInteger && packet_traits<Scalar>::HasPow)
355  };
356 };
357 
358 //---------- non associative binary functors ----------
359 
365 template <typename LhsScalar, typename RhsScalar>
366 struct scalar_difference_op : binary_op_base<LhsScalar, RhsScalar> {
367  typedef typename ScalarBinaryOpTraits<LhsScalar, RhsScalar, scalar_difference_op>::ReturnType result_type;
368 #ifdef EIGEN_SCALAR_BINARY_OP_PLUGIN
369  scalar_difference_op(){EIGEN_SCALAR_BINARY_OP_PLUGIN}
370 #endif
371  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const result_type
372  operator()(const LhsScalar& a, const RhsScalar& b) const {
373  return a - b;
374  }
375  template <typename Packet>
376  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& b) const {
377  return internal::psub(a, b);
378  }
379 };
380 template <typename LhsScalar, typename RhsScalar>
381 struct functor_traits<scalar_difference_op<LhsScalar, RhsScalar>> {
382  enum {
383  Cost = (int(NumTraits<LhsScalar>::AddCost) + int(NumTraits<RhsScalar>::AddCost)) / 2,
384  PacketAccess =
385  is_same<LhsScalar, RhsScalar>::value && packet_traits<LhsScalar>::HasSub && packet_traits<RhsScalar>::HasSub
386  };
387 };
388 
389 template <typename Packet, bool IsInteger = NumTraits<typename unpacket_traits<Packet>::type>::IsInteger>
390 struct maybe_raise_div_by_zero {
391  static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void run(Packet x) { EIGEN_UNUSED_VARIABLE(x); }
392 };
393 
394 #ifndef EIGEN_GPU_COMPILE_PHASE
395 template <typename Packet>
396 struct maybe_raise_div_by_zero<Packet, true> {
397  static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void run(Packet x) {
398  if (EIGEN_PREDICT_FALSE(predux_any(pcmp_eq(x, pzero(x))))) {
399  // Use volatile variables to force a division by zero, which will
400  // result in the default platform behaviour (usually SIGFPE).
401  volatile typename unpacket_traits<Packet>::type zero = 0;
402  volatile typename unpacket_traits<Packet>::type val = 1;
403  val = val / zero;
404  }
405  }
406 };
407 #endif
408 
414 template <typename LhsScalar, typename RhsScalar>
415 struct scalar_quotient_op : binary_op_base<LhsScalar, RhsScalar> {
416  typedef typename ScalarBinaryOpTraits<LhsScalar, RhsScalar, scalar_quotient_op>::ReturnType result_type;
417 #ifdef EIGEN_SCALAR_BINARY_OP_PLUGIN
418  scalar_quotient_op(){EIGEN_SCALAR_BINARY_OP_PLUGIN}
419 #endif
420  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const result_type
421  operator()(const LhsScalar& a, const RhsScalar& b) const {
422  return a / b;
423  }
424  template <typename Packet>
425  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& b) const {
426  return internal::pdiv(a, b);
427  }
428 };
429 template <typename LhsScalar, typename RhsScalar>
430 struct functor_traits<scalar_quotient_op<LhsScalar, RhsScalar>> {
431  typedef typename scalar_quotient_op<LhsScalar, RhsScalar>::result_type result_type;
432  enum {
433  PacketAccess =
434  is_same<LhsScalar, RhsScalar>::value && packet_traits<LhsScalar>::HasDiv && packet_traits<RhsScalar>::HasDiv,
435  Cost = scalar_div_cost<result_type, PacketAccess>::value
436  };
437 };
438 
444 template <typename Scalar>
445 struct scalar_boolean_and_op {
446  using result_type = Scalar;
447  // `false` any value `a` that satisfies `a == Scalar(0)`
448  // `true` is the complement of `false`
449  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar operator()(const Scalar& a, const Scalar& b) const {
450  return (a != Scalar(0)) && (b != Scalar(0)) ? Scalar(1) : Scalar(0);
451  }
452  template <typename Packet>
453  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const {
454  const Packet cst_one = pset1<Packet>(Scalar(1));
455  // and(a,b) == !or(!a,!b)
456  Packet not_a = pcmp_eq(a, pzero(a));
457  Packet not_b = pcmp_eq(b, pzero(b));
458  Packet a_nand_b = por(not_a, not_b);
459  return pandnot(cst_one, a_nand_b);
460  }
461 };
462 template <typename Scalar>
463 struct functor_traits<scalar_boolean_and_op<Scalar>> {
464  enum { Cost = NumTraits<Scalar>::AddCost, PacketAccess = packet_traits<Scalar>::HasCmp };
465 };
466 
472 template <typename Scalar>
473 struct scalar_boolean_or_op {
474  using result_type = Scalar;
475  // `false` any value `a` that satisfies `a == Scalar(0)`
476  // `true` is the complement of `false`
477  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar operator()(const Scalar& a, const Scalar& b) const {
478  return (a != Scalar(0)) || (b != Scalar(0)) ? Scalar(1) : Scalar(0);
479  }
480  template <typename Packet>
481  EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const {
482  const Packet cst_one = pset1<Packet>(Scalar(1));
483  // if or(a,b) == 0, then a == 0 and b == 0
484  // or(a,b) == !nor(a,b)
485  Packet a_nor_b = pcmp_eq(por(a, b), pzero(a));
486  return pandnot(cst_one, a_nor_b);
487  }
488 };
489 template <typename Scalar>
490 struct functor_traits<scalar_boolean_or_op<Scalar>> {
491  enum { Cost = NumTraits<Scalar>::AddCost, PacketAccess = packet_traits<Scalar>::HasCmp };
492 };
493 
499 template <typename Scalar>
500 struct scalar_boolean_xor_op {
501  using result_type = Scalar;
502  // `false` any value `a` that satisfies `a == Scalar(0)`
503  // `true` is the complement of `false`
504  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar operator()(const Scalar& a, const Scalar& b) const {
505  return (a != Scalar(0)) != (b != Scalar(0)) ? Scalar(1) : Scalar(0);
506  }
507  template <typename Packet>
508  EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const {
509  const Packet cst_one = pset1<Packet>(Scalar(1));
510  // xor(a,b) == xor(!a,!b)
511  Packet not_a = pcmp_eq(a, pzero(a));
512  Packet not_b = pcmp_eq(b, pzero(b));
513  Packet a_xor_b = pxor(not_a, not_b);
514  return pand(cst_one, a_xor_b);
515  }
516 };
517 template <typename Scalar>
518 struct functor_traits<scalar_boolean_xor_op<Scalar>> {
519  enum { Cost = NumTraits<Scalar>::AddCost, PacketAccess = packet_traits<Scalar>::HasCmp };
520 };
521 
522 template <typename Scalar, bool IsComplex = NumTraits<Scalar>::IsComplex>
523 struct bitwise_binary_impl {
524  static constexpr size_t Size = sizeof(Scalar);
525  using uint_t = typename numext::get_integer_by_size<Size>::unsigned_type;
526  static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar run_and(const Scalar& a, const Scalar& b) {
527  uint_t a_as_uint = numext::bit_cast<uint_t, Scalar>(a);
528  uint_t b_as_uint = numext::bit_cast<uint_t, Scalar>(b);
529  uint_t result = a_as_uint & b_as_uint;
530  return numext::bit_cast<Scalar, uint_t>(result);
531  }
532  static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar run_or(const Scalar& a, const Scalar& b) {
533  uint_t a_as_uint = numext::bit_cast<uint_t, Scalar>(a);
534  uint_t b_as_uint = numext::bit_cast<uint_t, Scalar>(b);
535  uint_t result = a_as_uint | b_as_uint;
536  return numext::bit_cast<Scalar, uint_t>(result);
537  }
538  static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar run_xor(const Scalar& a, const Scalar& b) {
539  uint_t a_as_uint = numext::bit_cast<uint_t, Scalar>(a);
540  uint_t b_as_uint = numext::bit_cast<uint_t, Scalar>(b);
541  uint_t result = a_as_uint ^ b_as_uint;
542  return numext::bit_cast<Scalar, uint_t>(result);
543  }
544 };
545 
546 template <typename Scalar>
547 struct bitwise_binary_impl<Scalar, true> {
548  using Real = typename NumTraits<Scalar>::Real;
549  static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar run_and(const Scalar& a, const Scalar& b) {
550  Real real_result = bitwise_binary_impl<Real>::run_and(numext::real(a), numext::real(b));
551  Real imag_result = bitwise_binary_impl<Real>::run_and(numext::imag(a), numext::imag(b));
552  return Scalar(real_result, imag_result);
553  }
554  static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar run_or(const Scalar& a, const Scalar& b) {
555  Real real_result = bitwise_binary_impl<Real>::run_or(numext::real(a), numext::real(b));
556  Real imag_result = bitwise_binary_impl<Real>::run_or(numext::imag(a), numext::imag(b));
557  return Scalar(real_result, imag_result);
558  }
559  static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar run_xor(const Scalar& a, const Scalar& b) {
560  Real real_result = bitwise_binary_impl<Real>::run_xor(numext::real(a), numext::real(b));
561  Real imag_result = bitwise_binary_impl<Real>::run_xor(numext::imag(a), numext::imag(b));
562  return Scalar(real_result, imag_result);
563  }
564 };
565 
571 template <typename Scalar>
572 struct scalar_bitwise_and_op {
573  EIGEN_STATIC_ASSERT(!NumTraits<Scalar>::RequireInitialization,
574  BITWISE OPERATIONS MAY ONLY BE PERFORMED ON PLAIN DATA TYPES)
575  EIGEN_STATIC_ASSERT((!internal::is_same<Scalar, bool>::value), DONT USE BITWISE OPS ON BOOLEAN TYPES)
576  using result_type = Scalar;
577  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar operator()(const Scalar& a, const Scalar& b) const {
578  return bitwise_binary_impl<Scalar>::run_and(a, b);
579  }
580  template <typename Packet>
581  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const {
582  return pand(a, b);
583  }
584 };
585 template <typename Scalar>
586 struct functor_traits<scalar_bitwise_and_op<Scalar>> {
587  enum { Cost = NumTraits<Scalar>::AddCost, PacketAccess = true };
588 };
589 
595 template <typename Scalar>
596 struct scalar_bitwise_or_op {
597  EIGEN_STATIC_ASSERT(!NumTraits<Scalar>::RequireInitialization,
598  BITWISE OPERATIONS MAY ONLY BE PERFORMED ON PLAIN DATA TYPES)
599  EIGEN_STATIC_ASSERT((!internal::is_same<Scalar, bool>::value), DONT USE BITWISE OPS ON BOOLEAN TYPES)
600  using result_type = Scalar;
601  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar operator()(const Scalar& a, const Scalar& b) const {
602  return bitwise_binary_impl<Scalar>::run_or(a, b);
603  }
604  template <typename Packet>
605  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const {
606  return por(a, b);
607  }
608 };
609 template <typename Scalar>
610 struct functor_traits<scalar_bitwise_or_op<Scalar>> {
611  enum { Cost = NumTraits<Scalar>::AddCost, PacketAccess = true };
612 };
613 
619 template <typename Scalar>
620 struct scalar_bitwise_xor_op {
621  EIGEN_STATIC_ASSERT(!NumTraits<Scalar>::RequireInitialization,
622  BITWISE OPERATIONS MAY ONLY BE PERFORMED ON PLAIN DATA TYPES)
623  EIGEN_STATIC_ASSERT((!internal::is_same<Scalar, bool>::value), DONT USE BITWISE OPS ON BOOLEAN TYPES)
624  using result_type = Scalar;
625  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar operator()(const Scalar& a, const Scalar& b) const {
626  return bitwise_binary_impl<Scalar>::run_xor(a, b);
627  }
628  template <typename Packet>
629  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const {
630  return pxor(a, b);
631  }
632 };
633 template <typename Scalar>
634 struct functor_traits<scalar_bitwise_xor_op<Scalar>> {
635  enum { Cost = NumTraits<Scalar>::AddCost, PacketAccess = true };
636 };
637 
643 template <typename LhsScalar, typename RhsScalar>
644 struct scalar_absolute_difference_op : binary_op_base<LhsScalar, RhsScalar> {
645  typedef typename ScalarBinaryOpTraits<LhsScalar, RhsScalar, scalar_absolute_difference_op>::ReturnType result_type;
646 #ifdef EIGEN_SCALAR_BINARY_OP_PLUGIN
647  scalar_absolute_difference_op(){EIGEN_SCALAR_BINARY_OP_PLUGIN}
648 #endif
649  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const result_type
650  operator()(const LhsScalar& a, const RhsScalar& b) const {
651  return numext::absdiff(a, b);
652  }
653  template <typename Packet>
654  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& b) const {
655  return internal::pabsdiff(a, b);
656  }
657 };
658 template <typename LhsScalar, typename RhsScalar>
659 struct functor_traits<scalar_absolute_difference_op<LhsScalar, RhsScalar>> {
660  enum {
661  Cost = (NumTraits<LhsScalar>::AddCost + NumTraits<RhsScalar>::AddCost) / 2,
662  PacketAccess = is_same<LhsScalar, RhsScalar>::value && packet_traits<LhsScalar>::HasAbsDiff
663  };
664 };
665 
666 template <typename LhsScalar, typename RhsScalar>
667 struct scalar_atan2_op {
668  using Scalar = LhsScalar;
669 
670  static constexpr bool Enable =
671  is_same<LhsScalar, RhsScalar>::value && !NumTraits<Scalar>::IsInteger && !NumTraits<Scalar>::IsComplex;
672  EIGEN_STATIC_ASSERT(Enable, "LhsScalar and RhsScalar must be the same non-integer, non-complex type")
673 
674  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar operator()(const Scalar& y, const Scalar& x) const {
675  return numext::atan2(y, x);
676  }
677  template <typename Packet>
678  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& y, const Packet& x) const {
679  return internal::patan2(y, x);
680  }
681 };
682 
683 template <typename LhsScalar, typename RhsScalar>
684 struct functor_traits<scalar_atan2_op<LhsScalar, RhsScalar>> {
685  using Scalar = LhsScalar;
686  enum {
687  PacketAccess = is_same<LhsScalar, RhsScalar>::value && packet_traits<Scalar>::HasATan &&
688  packet_traits<Scalar>::HasDiv && !NumTraits<Scalar>::IsInteger && !NumTraits<Scalar>::IsComplex,
689  Cost = int(scalar_div_cost<Scalar, PacketAccess>::value) + int(functor_traits<scalar_atan_op<Scalar>>::Cost)
690  };
691 };
692 
693 //---------- binary functors bound to a constant, thus appearing as a unary functor ----------
694 
695 // The following two classes permits to turn any binary functor into a unary one with one argument bound to a constant
696 // value. They are analogues to std::binder1st/binder2nd but with the following differences:
697 // - they are compatible with packetOp
698 // - they are portable across C++ versions (the std::binder* are deprecated in C++11)
699 template <typename BinaryOp>
700 struct bind1st_op : BinaryOp {
701  typedef typename BinaryOp::first_argument_type first_argument_type;
702  typedef typename BinaryOp::second_argument_type second_argument_type;
703  typedef typename BinaryOp::result_type result_type;
704 
705  EIGEN_DEVICE_FUNC explicit bind1st_op(const first_argument_type& val) : m_value(val) {}
706 
707  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const result_type operator()(const second_argument_type& b) const {
708  return BinaryOp::operator()(m_value, b);
709  }
710 
711  template <typename Packet>
712  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Packet packetOp(const Packet& b) const {
713  return BinaryOp::packetOp(internal::pset1<Packet>(m_value), b);
714  }
715 
716  first_argument_type m_value;
717 };
718 template <typename BinaryOp>
719 struct functor_traits<bind1st_op<BinaryOp>> : functor_traits<BinaryOp> {};
720 
721 template <typename BinaryOp>
722 struct bind2nd_op : BinaryOp {
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 bind2nd_op(const second_argument_type& val) : m_value(val) {}
728 
729  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const result_type operator()(const first_argument_type& a) const {
730  return BinaryOp::operator()(a, m_value);
731  }
732 
733  template <typename Packet>
734  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a) const {
735  return BinaryOp::packetOp(a, internal::pset1<Packet>(m_value));
736  }
737 
738  second_argument_type m_value;
739 };
740 template <typename BinaryOp>
741 struct functor_traits<bind2nd_op<BinaryOp>> : functor_traits<BinaryOp> {};
742 
743 } // end namespace internal
744 
745 } // end namespace Eigen
746 
747 #endif // EIGEN_BINARY_FUNCTORS_H
Namespace containing all symbols from the Eigen library.
Definition: B01_Experimental.dox:1