Eigen  3.4.90 (git rev 5a9f66fb35d03a4da9ef8976e67a61b30aa16dcf)
 
Loading...
Searching...
No Matches
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 <[email protected]>
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
16namespace Eigen {
17
18namespace internal {
19
20//---------- associative binary functors ----------
21
22template <typename Arg1, typename Arg2>
23struct binary_op_base {
24 typedef Arg1 first_argument_type;
25 typedef Arg2 second_argument_type;
26};
27
33template <typename LhsScalar, typename RhsScalar>
34struct 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};
52template <typename LhsScalar, typename RhsScalar>
53struct 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
62template <>
63EIGEN_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
72template <typename LhsScalar, typename RhsScalar>
73struct 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};
91template <typename LhsScalar, typename RhsScalar>
92struct 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
101template <>
102EIGEN_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
113template <typename LhsScalar, typename RhsScalar>
114struct 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};
128template <typename LhsScalar, typename RhsScalar>
129struct 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
141template <typename LhsScalar, typename RhsScalar, int NaNPropagation>
142struct 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
157template <typename LhsScalar, typename RhsScalar, int NaNPropagation>
158struct 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
170template <typename LhsScalar, typename RhsScalar, int NaNPropagation>
171struct 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
186template <typename LhsScalar, typename RhsScalar, int NaNPropagation>
187struct 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
198template <typename LhsScalar, typename RhsScalar, ComparisonName cmp, bool UseTypedComparators = false>
199struct scalar_cmp_op;
200
201template <typename LhsScalar, typename RhsScalar, ComparisonName cmp, bool UseTypedComparators>
202struct 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
210template <typename LhsScalar, typename RhsScalar, bool UseTypedComparators>
211struct 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
218template <typename LhsScalar, typename RhsScalar, bool UseTypedComparators>
219using cmp_return_t = typename typed_cmp_helper<LhsScalar, RhsScalar, UseTypedComparators>::type;
220
221template <typename LhsScalar, typename RhsScalar, bool UseTypedComparators>
222struct scalar_cmp_op<LhsScalar, RhsScalar, cmp_EQ, UseTypedComparators> : binary_op_base<LhsScalar, RhsScalar> {
223 using result_type = cmp_return_t<LhsScalar, RhsScalar, UseTypedComparators>;
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
234template <typename LhsScalar, typename RhsScalar, bool UseTypedComparators>
235struct 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
247template <typename LhsScalar, typename RhsScalar, bool UseTypedComparators>
248struct 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
260template <typename LhsScalar, typename RhsScalar, bool UseTypedComparators>
261struct 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
273template <typename LhsScalar, typename RhsScalar, bool UseTypedComparators>
274struct 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
286template <typename LhsScalar, typename RhsScalar, bool UseTypedComparators>
287struct 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
299template <typename LhsScalar, typename RhsScalar, bool UseTypedComparators>
300struct 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
317template <typename Scalar>
318struct scalar_hypot_op<Scalar, Scalar> : binary_op_base<Scalar, Scalar> {
319 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar operator()(const Scalar& x, const Scalar& y) const {
320 // This functor is used by hypotNorm only for which it is faster to first apply abs
321 // on all coefficients prior to reduction through hypot.
322 // This way we avoid calling abs on positive and real entries, and this also permits
323 // to seamlessly handle complexes. Otherwise we would have to handle both real and complexes
324 // through the same functor...
325 return internal::positive_real_hypot(x, y);
326 }
327};
328template <typename Scalar>
329struct functor_traits<scalar_hypot_op<Scalar, Scalar>> {
330 enum {
331 Cost = 3 * NumTraits<Scalar>::AddCost + 2 * NumTraits<Scalar>::MulCost + 2 * scalar_div_cost<Scalar, false>::value,
332 PacketAccess = false
333 };
334};
335
340template <typename Scalar, typename Exponent>
341struct scalar_pow_op : binary_op_base<Scalar, Exponent> {
342 typedef typename ScalarBinaryOpTraits<Scalar, Exponent, scalar_pow_op>::ReturnType result_type;
343#ifdef EIGEN_SCALAR_BINARY_OP_PLUGIN
344 scalar_pow_op() {
345 typedef Scalar LhsScalar;
346 typedef Exponent RhsScalar;
347 EIGEN_SCALAR_BINARY_OP_PLUGIN
348 }
349#endif
350
351 EIGEN_DEVICE_FUNC inline result_type operator()(const Scalar& a, const Exponent& b) const {
352 return numext::pow(a, b);
353 }
354
355 template <typename Packet>
356 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& b) const {
357 return generic_pow(a, b);
358 }
359};
360
361template <typename Scalar, typename Exponent>
362struct functor_traits<scalar_pow_op<Scalar, Exponent>> {
363 enum {
364 Cost = 5 * NumTraits<Scalar>::MulCost,
365 PacketAccess = (!NumTraits<Scalar>::IsComplex && !NumTraits<Scalar>::IsInteger && packet_traits<Scalar>::HasExp &&
366 packet_traits<Scalar>::HasLog && packet_traits<Scalar>::HasRound && packet_traits<Scalar>::HasCmp &&
367 // Temporarily disable packet access for half/bfloat16 until
368 // accuracy is improved.
369 !is_same<Scalar, half>::value && !is_same<Scalar, bfloat16>::value)
370 };
371};
372
373//---------- non associative binary functors ----------
374
380template <typename LhsScalar, typename RhsScalar>
381struct scalar_difference_op : binary_op_base<LhsScalar, RhsScalar> {
382 typedef typename ScalarBinaryOpTraits<LhsScalar, RhsScalar, scalar_difference_op>::ReturnType result_type;
383#ifdef EIGEN_SCALAR_BINARY_OP_PLUGIN
384 scalar_difference_op(){EIGEN_SCALAR_BINARY_OP_PLUGIN}
385#endif
386 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const result_type
387 operator()(const LhsScalar& a, const RhsScalar& b) const {
388 return a - b;
389 }
390 template <typename Packet>
391 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& b) const {
392 return internal::psub(a, b);
393 }
394};
395template <typename LhsScalar, typename RhsScalar>
396struct functor_traits<scalar_difference_op<LhsScalar, RhsScalar>> {
397 enum {
398 Cost = (int(NumTraits<LhsScalar>::AddCost) + int(NumTraits<RhsScalar>::AddCost)) / 2,
399 PacketAccess =
400 is_same<LhsScalar, RhsScalar>::value && packet_traits<LhsScalar>::HasSub && packet_traits<RhsScalar>::HasSub
401 };
402};
403
404template <typename Packet, bool IsInteger = NumTraits<typename unpacket_traits<Packet>::type>::IsInteger>
405struct maybe_raise_div_by_zero {
406 static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void run(Packet x) { EIGEN_UNUSED_VARIABLE(x); }
407};
408
409#ifndef EIGEN_GPU_COMPILE_PHASE
410template <typename Packet>
411struct maybe_raise_div_by_zero<Packet, true> {
412 static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void run(Packet x) {
413 if (EIGEN_PREDICT_FALSE(predux_any(pcmp_eq(x, pzero(x))))) {
414 // Use volatile variables to force a division by zero, which will
415 // result in the default platform behaviour (usually SIGFPE).
416 volatile typename unpacket_traits<Packet>::type zero = 0;
417 volatile typename unpacket_traits<Packet>::type val = 1;
418 val = val / zero;
419 }
420 }
421};
422#endif
423
429template <typename LhsScalar, typename RhsScalar>
430struct scalar_quotient_op : binary_op_base<LhsScalar, RhsScalar> {
431 typedef typename ScalarBinaryOpTraits<LhsScalar, RhsScalar, scalar_quotient_op>::ReturnType result_type;
432#ifdef EIGEN_SCALAR_BINARY_OP_PLUGIN
433 scalar_quotient_op(){EIGEN_SCALAR_BINARY_OP_PLUGIN}
434#endif
435 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const result_type
436 operator()(const LhsScalar& a, const RhsScalar& b) const {
437 return a / b;
438 }
439 template <typename Packet>
440 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& b) const {
441 maybe_raise_div_by_zero<Packet>::run(b);
442 return internal::pdiv(a, b);
443 }
444};
445template <typename LhsScalar, typename RhsScalar>
446struct functor_traits<scalar_quotient_op<LhsScalar, RhsScalar>> {
447 typedef typename scalar_quotient_op<LhsScalar, RhsScalar>::result_type result_type;
448 enum {
449 PacketAccess =
450 is_same<LhsScalar, RhsScalar>::value && packet_traits<LhsScalar>::HasDiv && packet_traits<RhsScalar>::HasDiv,
451 Cost = scalar_div_cost<result_type, PacketAccess>::value
452 };
453};
454
460template <typename Scalar>
461struct scalar_boolean_and_op {
462 using result_type = Scalar;
463 // `false` any value `a` that satisfies `a == Scalar(0)`
464 // `true` is the complement of `false`
465 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar operator()(const Scalar& a, const Scalar& b) const {
466 return (a != Scalar(0)) && (b != Scalar(0)) ? Scalar(1) : Scalar(0);
467 }
468 template <typename Packet>
469 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const {
470 const Packet cst_one = pset1<Packet>(Scalar(1));
471 // and(a,b) == !or(!a,!b)
472 Packet not_a = pcmp_eq(a, pzero(a));
473 Packet not_b = pcmp_eq(b, pzero(b));
474 Packet a_nand_b = por(not_a, not_b);
475 return pandnot(cst_one, a_nand_b);
476 }
477};
478template <typename Scalar>
479struct functor_traits<scalar_boolean_and_op<Scalar>> {
480 enum { Cost = NumTraits<Scalar>::AddCost, PacketAccess = packet_traits<Scalar>::HasCmp };
481};
482
488template <typename Scalar>
489struct scalar_boolean_or_op {
490 using result_type = Scalar;
491 // `false` any value `a` that satisfies `a == Scalar(0)`
492 // `true` is the complement of `false`
493 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar operator()(const Scalar& a, const Scalar& b) const {
494 return (a != Scalar(0)) || (b != Scalar(0)) ? Scalar(1) : Scalar(0);
495 }
496 template <typename Packet>
497 EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const {
498 const Packet cst_one = pset1<Packet>(Scalar(1));
499 // if or(a,b) == 0, then a == 0 and b == 0
500 // or(a,b) == !nor(a,b)
501 Packet a_nor_b = pcmp_eq(por(a, b), pzero(a));
502 return pandnot(cst_one, a_nor_b);
503 }
504};
505template <typename Scalar>
506struct functor_traits<scalar_boolean_or_op<Scalar>> {
507 enum { Cost = NumTraits<Scalar>::AddCost, PacketAccess = packet_traits<Scalar>::HasCmp };
508};
509
515template <typename Scalar>
516struct scalar_boolean_xor_op {
517 using result_type = Scalar;
518 // `false` any value `a` that satisfies `a == Scalar(0)`
519 // `true` is the complement of `false`
520 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar operator()(const Scalar& a, const Scalar& b) const {
521 return (a != Scalar(0)) != (b != Scalar(0)) ? Scalar(1) : Scalar(0);
522 }
523 template <typename Packet>
524 EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const {
525 const Packet cst_one = pset1<Packet>(Scalar(1));
526 // xor(a,b) == xor(!a,!b)
527 Packet not_a = pcmp_eq(a, pzero(a));
528 Packet not_b = pcmp_eq(b, pzero(b));
529 Packet a_xor_b = pxor(not_a, not_b);
530 return pand(cst_one, a_xor_b);
531 }
532};
533template <typename Scalar>
534struct functor_traits<scalar_boolean_xor_op<Scalar>> {
535 enum { Cost = NumTraits<Scalar>::AddCost, PacketAccess = packet_traits<Scalar>::HasCmp };
536};
537
538template <typename Scalar, bool IsComplex = NumTraits<Scalar>::IsComplex>
539struct bitwise_binary_impl {
540 static constexpr size_t Size = sizeof(Scalar);
541 using uint_t = typename numext::get_integer_by_size<Size>::unsigned_type;
542 static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar run_and(const Scalar& a, const Scalar& b) {
543 uint_t a_as_uint = numext::bit_cast<uint_t, Scalar>(a);
544 uint_t b_as_uint = numext::bit_cast<uint_t, Scalar>(b);
545 uint_t result = a_as_uint & b_as_uint;
546 return numext::bit_cast<Scalar, uint_t>(result);
547 }
548 static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar run_or(const Scalar& a, const Scalar& b) {
549 uint_t a_as_uint = numext::bit_cast<uint_t, Scalar>(a);
550 uint_t b_as_uint = numext::bit_cast<uint_t, Scalar>(b);
551 uint_t result = a_as_uint | b_as_uint;
552 return numext::bit_cast<Scalar, uint_t>(result);
553 }
554 static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar run_xor(const Scalar& a, const Scalar& b) {
555 uint_t a_as_uint = numext::bit_cast<uint_t, Scalar>(a);
556 uint_t b_as_uint = numext::bit_cast<uint_t, Scalar>(b);
557 uint_t result = a_as_uint ^ b_as_uint;
558 return numext::bit_cast<Scalar, uint_t>(result);
559 }
560};
561
562template <typename Scalar>
563struct bitwise_binary_impl<Scalar, true> {
564 using Real = typename NumTraits<Scalar>::Real;
565 static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar run_and(const Scalar& a, const Scalar& b) {
566 Real real_result = bitwise_binary_impl<Real>::run_and(numext::real(a), numext::real(b));
567 Real imag_result = bitwise_binary_impl<Real>::run_and(numext::imag(a), numext::imag(b));
568 return Scalar(real_result, imag_result);
569 }
570 static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar run_or(const Scalar& a, const Scalar& b) {
571 Real real_result = bitwise_binary_impl<Real>::run_or(numext::real(a), numext::real(b));
572 Real imag_result = bitwise_binary_impl<Real>::run_or(numext::imag(a), numext::imag(b));
573 return Scalar(real_result, imag_result);
574 }
575 static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar run_xor(const Scalar& a, const Scalar& b) {
576 Real real_result = bitwise_binary_impl<Real>::run_xor(numext::real(a), numext::real(b));
577 Real imag_result = bitwise_binary_impl<Real>::run_xor(numext::imag(a), numext::imag(b));
578 return Scalar(real_result, imag_result);
579 }
580};
581
587template <typename Scalar>
588struct scalar_bitwise_and_op {
589 EIGEN_STATIC_ASSERT(!NumTraits<Scalar>::RequireInitialization,
590 BITWISE OPERATIONS MAY ONLY BE PERFORMED ON PLAIN DATA TYPES)
591 EIGEN_STATIC_ASSERT((!internal::is_same<Scalar, bool>::value), DONT USE BITWISE OPS ON BOOLEAN TYPES)
592 using result_type = Scalar;
593 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar operator()(const Scalar& a, const Scalar& b) const {
594 return bitwise_binary_impl<Scalar>::run_and(a, b);
595 }
596 template <typename Packet>
597 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const {
598 return pand(a, b);
599 }
600};
601template <typename Scalar>
602struct functor_traits<scalar_bitwise_and_op<Scalar>> {
603 enum { Cost = NumTraits<Scalar>::AddCost, PacketAccess = true };
604};
605
611template <typename Scalar>
612struct scalar_bitwise_or_op {
613 EIGEN_STATIC_ASSERT(!NumTraits<Scalar>::RequireInitialization,
614 BITWISE OPERATIONS MAY ONLY BE PERFORMED ON PLAIN DATA TYPES)
615 EIGEN_STATIC_ASSERT((!internal::is_same<Scalar, bool>::value), DONT USE BITWISE OPS ON BOOLEAN TYPES)
616 using result_type = Scalar;
617 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar operator()(const Scalar& a, const Scalar& b) const {
618 return bitwise_binary_impl<Scalar>::run_or(a, b);
619 }
620 template <typename Packet>
621 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const {
622 return por(a, b);
623 }
624};
625template <typename Scalar>
626struct functor_traits<scalar_bitwise_or_op<Scalar>> {
627 enum { Cost = NumTraits<Scalar>::AddCost, PacketAccess = true };
628};
629
635template <typename Scalar>
636struct scalar_bitwise_xor_op {
637 EIGEN_STATIC_ASSERT(!NumTraits<Scalar>::RequireInitialization,
638 BITWISE OPERATIONS MAY ONLY BE PERFORMED ON PLAIN DATA TYPES)
639 EIGEN_STATIC_ASSERT((!internal::is_same<Scalar, bool>::value), DONT USE BITWISE OPS ON BOOLEAN TYPES)
640 using result_type = Scalar;
641 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar operator()(const Scalar& a, const Scalar& b) const {
642 return bitwise_binary_impl<Scalar>::run_xor(a, b);
643 }
644 template <typename Packet>
645 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const {
646 return pxor(a, b);
647 }
648};
649template <typename Scalar>
650struct functor_traits<scalar_bitwise_xor_op<Scalar>> {
651 enum { Cost = NumTraits<Scalar>::AddCost, PacketAccess = true };
652};
653
659template <typename LhsScalar, typename RhsScalar>
660struct scalar_absolute_difference_op : binary_op_base<LhsScalar, RhsScalar> {
661 typedef typename ScalarBinaryOpTraits<LhsScalar, RhsScalar, scalar_absolute_difference_op>::ReturnType result_type;
662#ifdef EIGEN_SCALAR_BINARY_OP_PLUGIN
663 scalar_absolute_difference_op(){EIGEN_SCALAR_BINARY_OP_PLUGIN}
664#endif
665 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const result_type
666 operator()(const LhsScalar& a, const RhsScalar& b) const {
667 return numext::absdiff(a, b);
668 }
669 template <typename Packet>
670 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& b) const {
671 return internal::pabsdiff(a, b);
672 }
673};
674template <typename LhsScalar, typename RhsScalar>
675struct functor_traits<scalar_absolute_difference_op<LhsScalar, RhsScalar>> {
676 enum {
677 Cost = (NumTraits<LhsScalar>::AddCost + NumTraits<RhsScalar>::AddCost) / 2,
678 PacketAccess = is_same<LhsScalar, RhsScalar>::value && packet_traits<LhsScalar>::HasAbsDiff
679 };
680};
681
682template <typename LhsScalar, typename RhsScalar>
683struct scalar_atan2_op {
684 using Scalar = LhsScalar;
685
686 static constexpr bool Enable =
687 is_same<LhsScalar, RhsScalar>::value && !NumTraits<Scalar>::IsInteger && !NumTraits<Scalar>::IsComplex;
688 EIGEN_STATIC_ASSERT(Enable, "LhsScalar and RhsScalar must be the same non-integer, non-complex type")
689
690 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar operator()(const Scalar& y, const Scalar& x) const {
691 return numext::atan2(y, x);
692 }
693 template <typename Packet>
694 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& y, const Packet& x) const {
695 return internal::patan2(y, x);
696 }
697};
698
699template <typename LhsScalar, typename RhsScalar>
700struct functor_traits<scalar_atan2_op<LhsScalar, RhsScalar>> {
701 using Scalar = LhsScalar;
702 enum {
703 PacketAccess = is_same<LhsScalar, RhsScalar>::value && packet_traits<Scalar>::HasATan &&
704 packet_traits<Scalar>::HasDiv && !NumTraits<Scalar>::IsInteger && !NumTraits<Scalar>::IsComplex,
705 Cost = int(scalar_div_cost<Scalar, PacketAccess>::value) + int(functor_traits<scalar_atan_op<Scalar>>::Cost)
706 };
707};
708
709//---------- binary functors bound to a constant, thus appearing as a unary functor ----------
710
711// The following two classes permits to turn any binary functor into a unary one with one argument bound to a constant
712// value. They are analogues to std::binder1st/binder2nd but with the following differences:
713// - they are compatible with packetOp
714// - they are portable across C++ versions (the std::binder* are deprecated in C++11)
715template <typename BinaryOp>
716struct bind1st_op : BinaryOp {
717 typedef typename BinaryOp::first_argument_type first_argument_type;
718 typedef typename BinaryOp::second_argument_type second_argument_type;
719 typedef typename BinaryOp::result_type result_type;
720
721 EIGEN_DEVICE_FUNC explicit bind1st_op(const first_argument_type& val) : m_value(val) {}
722
723 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const result_type operator()(const second_argument_type& b) const {
724 return BinaryOp::operator()(m_value, b);
725 }
726
727 template <typename Packet>
728 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Packet packetOp(const Packet& b) const {
729 return BinaryOp::packetOp(internal::pset1<Packet>(m_value), b);
730 }
731
732 first_argument_type m_value;
733};
734template <typename BinaryOp>
735struct functor_traits<bind1st_op<BinaryOp>> : functor_traits<BinaryOp> {};
736
737template <typename BinaryOp>
738struct bind2nd_op : BinaryOp {
739 typedef typename BinaryOp::first_argument_type first_argument_type;
740 typedef typename BinaryOp::second_argument_type second_argument_type;
741 typedef typename BinaryOp::result_type result_type;
742
743 EIGEN_DEVICE_FUNC explicit bind2nd_op(const second_argument_type& val) : m_value(val) {}
744
745 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const result_type operator()(const first_argument_type& a) const {
746 return BinaryOp::operator()(a, m_value);
747 }
748
749 template <typename Packet>
750 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a) const {
751 return BinaryOp::packetOp(a, internal::pset1<Packet>(m_value));
752 }
753
754 second_argument_type m_value;
755};
756template <typename BinaryOp>
757struct functor_traits<bind2nd_op<BinaryOp>> : functor_traits<BinaryOp> {};
758
759} // end namespace internal
760
761} // end namespace Eigen
762
763#endif // EIGEN_BINARY_FUNCTORS_H
Namespace containing all symbols from the Eigen library.
Definition Core:137