| // This file is part of Eigen, a lightweight C++ template library | |
| // for linear algebra. | |
| // | |
| // Copyright (C) 2008-2010 Gael Guennebaud <gael.guennebaud@inria.fr> | |
| // | |
| // This Source Code Form is subject to the terms of the Mozilla | |
| // Public License v. 2.0. If a copy of the MPL was not distributed | |
| // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. | |
| // SPDX-License-Identifier: MPL-2.0 | |
| #ifndef EIGEN_BINARY_FUNCTORS_H | |
| #define EIGEN_BINARY_FUNCTORS_H | |
| // IWYU pragma: private | |
| #include "../InternalHeaderCheck.h" | |
| namespace Eigen { | |
| namespace internal { | |
| //---------- associative binary functors ---------- | |
| template <typename Arg1, typename Arg2> | |
| struct binary_op_base { | |
| using first_argument_type = Arg1; | |
| using second_argument_type = Arg2; | |
| }; | |
| /** \internal | |
| * \brief Template functor to compute the sum of two scalars | |
| * | |
| * \sa class CwiseBinaryOp, MatrixBase::operator+, class VectorwiseOp, DenseBase::sum() | |
| */ | |
| template <typename LhsScalar, typename RhsScalar> | |
| struct scalar_sum_op : binary_op_base<LhsScalar, RhsScalar> { | |
| using result_type = typename ScalarBinaryOpTraits<LhsScalar, RhsScalar, scalar_sum_op>::ReturnType; | |
| #ifdef EIGEN_SCALAR_BINARY_OP_PLUGIN | |
| scalar_sum_op(){EIGEN_SCALAR_BINARY_OP_PLUGIN} | |
| #endif | |
| EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE result_type | |
| operator()(const LhsScalar& a, const RhsScalar& b) const { | |
| return a + b; | |
| } | |
| template <typename Packet> | |
| EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const { | |
| return internal::padd(a, b); | |
| } | |
| template <typename Packet> | |
| EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type predux(const Packet& a) const { | |
| return internal::predux(a); | |
| } | |
| }; | |
| template <typename LhsScalar, typename RhsScalar> | |
| struct functor_traits<scalar_sum_op<LhsScalar, RhsScalar>> { | |
| enum { | |
| Cost = (int(NumTraits<LhsScalar>::AddCost) + int(NumTraits<RhsScalar>::AddCost)) / 2, // rough estimate! | |
| PacketAccess = std::is_same<LhsScalar, RhsScalar>::value && packet_traits<LhsScalar>::HasAdd && | |
| packet_traits<RhsScalar>::HasAdd | |
| // TODO: vectorize mixed sum | |
| }; | |
| }; | |
| // Addition commutes for arithmetic and complex scalars. A user-defined Scalar may define a | |
| // non-commutative operator+ (e.g. concatenation), so it keeps the order-preserving default. | |
| template <typename Scalar> | |
| struct functor_is_commutative<scalar_sum_op<Scalar, Scalar>> | |
| : bool_constant<is_arithmetic<Scalar>::value || NumTraits<Scalar>::IsComplex> {}; | |
| template <> | |
| EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE bool scalar_sum_op<bool, bool>::operator()(const bool& a, | |
| const bool& b) const { | |
| return a | b; | |
| } | |
| /** \internal | |
| * \brief Template functor to compute the product of two scalars | |
| * | |
| * \sa class CwiseBinaryOp, Cwise::operator*(), class VectorwiseOp, MatrixBase::redux() | |
| */ | |
| template <typename LhsScalar, typename RhsScalar> | |
| struct scalar_product_op : binary_op_base<LhsScalar, RhsScalar> { | |
| using result_type = typename ScalarBinaryOpTraits<LhsScalar, RhsScalar, scalar_product_op>::ReturnType; | |
| #ifdef EIGEN_SCALAR_BINARY_OP_PLUGIN | |
| scalar_product_op(){EIGEN_SCALAR_BINARY_OP_PLUGIN} | |
| #endif | |
| EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE result_type | |
| operator()(const LhsScalar& a, const RhsScalar& b) const { | |
| return internal::mul(a, b); | |
| } | |
| template <typename Packet> | |
| EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const { | |
| return internal::pmul(a, b); | |
| } | |
| template <typename Packet> | |
| EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type predux(const Packet& a) const { | |
| return internal::predux_mul(a); | |
| } | |
| }; | |
| template <typename LhsScalar, typename RhsScalar> | |
| struct functor_traits<scalar_product_op<LhsScalar, RhsScalar>> { | |
| enum { | |
| Cost = (int(NumTraits<LhsScalar>::MulCost) + int(NumTraits<RhsScalar>::MulCost)) / 2, // rough estimate! | |
| PacketAccess = std::is_same<LhsScalar, RhsScalar>::value && packet_traits<LhsScalar>::HasMul && | |
| packet_traits<RhsScalar>::HasMul | |
| // TODO: vectorize mixed product | |
| }; | |
| }; | |
| // Multiplication commutes for arithmetic and complex scalars, but not for every user-defined | |
| // Scalar (e.g. quaternion-like or matrix-like types). | |
| template <typename Scalar> | |
| struct functor_is_commutative<scalar_product_op<Scalar, Scalar>> | |
| : bool_constant<is_arithmetic<Scalar>::value || NumTraits<Scalar>::IsComplex> {}; | |
| // Same as scalar_product_op, but its scalar path uses pmul instead of operator*. For complex scalars | |
| // pmul is Eigen's explicit (non-Annex-G) complex multiply, so this avoids std::complex::operator*, | |
| // which GCC lowers to the slow libgcc __mul?c3 call. The packet path (packetOp/predux) is inherited | |
| // unchanged -- it already uses pmul -- so the vectorized reduction and its precision are identical to | |
| // scalar_product_op (this only matters for the non-vectorized scalar tail). Used by the coeff-based | |
| // product's coeff(); pmul requires matching operand types, so mixed types fall back to operator* | |
| // (which is cheap for real*complex and never hits the complex*complex libcall). | |
| template <typename LhsScalar, typename RhsScalar> | |
| struct fast_mult_op : scalar_product_op<LhsScalar, RhsScalar> { | |
| using result_type = typename scalar_product_op<LhsScalar, RhsScalar>::result_type; | |
| EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type operator()(const LhsScalar& a, const RhsScalar& b) const { | |
| return mul(a, b, bool_constant<std::is_same<LhsScalar, RhsScalar>::value>()); | |
| } | |
| private: | |
| EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type mul(const LhsScalar& a, const RhsScalar& b, std::true_type) const { | |
| return pmul(a, b); | |
| } | |
| EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type mul(const LhsScalar& a, const RhsScalar& b, std::false_type) const { | |
| return a * b; | |
| } | |
| }; | |
| template <typename LhsScalar, typename RhsScalar> | |
| struct functor_traits<fast_mult_op<LhsScalar, RhsScalar>> : functor_traits<scalar_product_op<LhsScalar, RhsScalar>> {}; | |
| template <> | |
| EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE bool scalar_product_op<bool, bool>::operator()(const bool& a, | |
| const bool& b) const { | |
| return a & b; | |
| } | |
| /** \internal | |
| * \brief Template functor to compute the conjugate product of two scalars | |
| * | |
| * This is a short cut for conj(x) * y which is needed for optimization purpose; in Eigen2 support mode, this becomes x | |
| * * conj(y) | |
| */ | |
| template <typename LhsScalar, typename RhsScalar> | |
| struct scalar_conj_product_op : binary_op_base<LhsScalar, RhsScalar> { | |
| enum { Conj = NumTraits<LhsScalar>::IsComplex }; | |
| using result_type = typename ScalarBinaryOpTraits<LhsScalar, RhsScalar, scalar_conj_product_op>::ReturnType; | |
| EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE result_type operator()(const LhsScalar& a, const RhsScalar& b) const { | |
| return conj_helper<LhsScalar, RhsScalar, Conj, false>().pmul(a, b); | |
| } | |
| template <typename Packet> | |
| EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const { | |
| return conj_helper<Packet, Packet, Conj, false>().pmul(a, b); | |
| } | |
| }; | |
| template <typename LhsScalar, typename RhsScalar> | |
| struct functor_traits<scalar_conj_product_op<LhsScalar, RhsScalar>> { | |
| enum { | |
| Cost = NumTraits<LhsScalar>::MulCost, | |
| PacketAccess = std::is_same<LhsScalar, RhsScalar>::value && packet_traits<LhsScalar>::HasMul | |
| }; | |
| }; | |
| /** \internal | |
| * \brief Template functor to compute the min of two scalars | |
| * | |
| * \sa class CwiseBinaryOp, MatrixBase::cwiseMin, class VectorwiseOp, MatrixBase::minCoeff() | |
| */ | |
| template <typename LhsScalar, typename RhsScalar, int NaNPropagation> | |
| struct scalar_min_op : binary_op_base<LhsScalar, RhsScalar> { | |
| using result_type = typename ScalarBinaryOpTraits<LhsScalar, RhsScalar, scalar_min_op>::ReturnType; | |
| EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE result_type operator()(const LhsScalar& a, const RhsScalar& b) const { | |
| return internal::pmin<NaNPropagation>(a, b); | |
| } | |
| template <typename Packet> | |
| EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const { | |
| return internal::pmin<NaNPropagation>(a, b); | |
| } | |
| template <typename Packet> | |
| EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type predux(const Packet& a) const { | |
| return internal::predux_min<NaNPropagation>(a); | |
| } | |
| }; | |
| template <typename LhsScalar, typename RhsScalar, int NaNPropagation> | |
| struct functor_traits<scalar_min_op<LhsScalar, RhsScalar, NaNPropagation>> { | |
| enum { | |
| Cost = (NumTraits<LhsScalar>::AddCost + NumTraits<RhsScalar>::AddCost) / 2, | |
| PacketAccess = std::is_same<LhsScalar, RhsScalar>::value && packet_traits<LhsScalar>::HasMin | |
| }; | |
| }; | |
| // min/max commute for arithmetic scalars only: PropagateNumbers and PropagateNaN treat NaN | |
| // operands symmetrically, PropagateFast leaves NaN results unspecified, and -0.0/+0.0 ties may | |
| // already resolve either way in the packet reduction paths. A custom scalar is excluded even | |
| // though it compares with operator<, because the generic std::min/std::max keep the first | |
| // operand when values compare equivalent, and equivalent custom values may be observably | |
| // distinct (e.g. carry a payload the comparison ignores). | |
| template <typename Scalar, int NaNPropagation> | |
| struct functor_is_commutative<scalar_min_op<Scalar, Scalar, NaNPropagation>> : is_arithmetic<Scalar> {}; | |
| /** \internal | |
| * \brief Template functor to compute the max of two scalars | |
| * | |
| * \sa class CwiseBinaryOp, MatrixBase::cwiseMax, class VectorwiseOp, MatrixBase::maxCoeff() | |
| */ | |
| template <typename LhsScalar, typename RhsScalar, int NaNPropagation> | |
| struct scalar_max_op : binary_op_base<LhsScalar, RhsScalar> { | |
| using result_type = typename ScalarBinaryOpTraits<LhsScalar, RhsScalar, scalar_max_op>::ReturnType; | |
| EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE result_type operator()(const LhsScalar& a, const RhsScalar& b) const { | |
| return internal::pmax<NaNPropagation>(a, b); | |
| } | |
| template <typename Packet> | |
| EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const { | |
| return internal::pmax<NaNPropagation>(a, b); | |
| } | |
| template <typename Packet> | |
| EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type predux(const Packet& a) const { | |
| return internal::predux_max<NaNPropagation>(a); | |
| } | |
| }; | |
| template <typename LhsScalar, typename RhsScalar, int NaNPropagation> | |
| struct functor_traits<scalar_max_op<LhsScalar, RhsScalar, NaNPropagation>> { | |
| enum { | |
| Cost = (NumTraits<LhsScalar>::AddCost + NumTraits<RhsScalar>::AddCost) / 2, | |
| PacketAccess = std::is_same<LhsScalar, RhsScalar>::value && packet_traits<LhsScalar>::HasMax | |
| }; | |
| }; | |
| template <typename Scalar, int NaNPropagation> | |
| struct functor_is_commutative<scalar_max_op<Scalar, Scalar, NaNPropagation>> : is_arithmetic<Scalar> {}; | |
| /** \internal | |
| * \brief Template functors for comparison of two scalars | |
| * \todo Implement packet-comparisons | |
| */ | |
| template <typename LhsScalar, typename RhsScalar, ComparisonName cmp, bool UseTypedComparators = false> | |
| struct scalar_cmp_op; | |
| template <typename LhsScalar, typename RhsScalar, ComparisonName cmp, bool UseTypedComparators> | |
| struct functor_traits<scalar_cmp_op<LhsScalar, RhsScalar, cmp, UseTypedComparators>> { | |
| enum { | |
| Cost = (NumTraits<LhsScalar>::AddCost + NumTraits<RhsScalar>::AddCost) / 2, | |
| PacketAccess = (UseTypedComparators || std::is_same<LhsScalar, bool>::value) && | |
| std::is_same<LhsScalar, RhsScalar>::value && packet_traits<LhsScalar>::HasCmp | |
| }; | |
| }; | |
| template <typename LhsScalar, typename RhsScalar, bool UseTypedComparators> | |
| struct scalar_cmp_op<LhsScalar, RhsScalar, cmp_EQ, UseTypedComparators> : binary_op_base<LhsScalar, RhsScalar> { | |
| using result_type = std::conditional_t<UseTypedComparators, LhsScalar, bool>; | |
| EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE result_type operator()(const LhsScalar& a, const RhsScalar& b) const { | |
| return result_type(a == b); | |
| } | |
| template <typename Packet> | |
| EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const { | |
| const Packet cst_one = pset1<Packet>(result_type(true)); | |
| return pand(pcmp_eq(a, b), cst_one); | |
| } | |
| }; | |
| template <typename LhsScalar, typename RhsScalar, bool UseTypedComparators> | |
| struct scalar_cmp_op<LhsScalar, RhsScalar, cmp_LT, UseTypedComparators> : binary_op_base<LhsScalar, RhsScalar> { | |
| using result_type = std::conditional_t<UseTypedComparators, LhsScalar, bool>; | |
| EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE result_type operator()(const LhsScalar& a, const RhsScalar& b) const { | |
| return result_type(a < b); | |
| } | |
| template <typename Packet> | |
| EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const { | |
| const Packet cst_one = pset1<Packet>(result_type(true)); | |
| return pand(pcmp_lt(a, b), cst_one); | |
| } | |
| }; | |
| template <typename LhsScalar, typename RhsScalar, bool UseTypedComparators> | |
| struct scalar_cmp_op<LhsScalar, RhsScalar, cmp_LE, UseTypedComparators> : binary_op_base<LhsScalar, RhsScalar> { | |
| using result_type = std::conditional_t<UseTypedComparators, LhsScalar, bool>; | |
| EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE result_type operator()(const LhsScalar& a, const RhsScalar& b) const { | |
| return result_type(a <= b); | |
| } | |
| template <typename Packet> | |
| EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const { | |
| const Packet cst_one = pset1<Packet>(result_type(true)); | |
| return pand(cst_one, pcmp_le(a, b)); | |
| } | |
| }; | |
| template <typename LhsScalar, typename RhsScalar, bool UseTypedComparators> | |
| struct scalar_cmp_op<LhsScalar, RhsScalar, cmp_GT, UseTypedComparators> : binary_op_base<LhsScalar, RhsScalar> { | |
| using result_type = std::conditional_t<UseTypedComparators, LhsScalar, bool>; | |
| EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE result_type operator()(const LhsScalar& a, const RhsScalar& b) const { | |
| return result_type(a > b); | |
| } | |
| template <typename Packet> | |
| EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const { | |
| const Packet cst_one = pset1<Packet>(result_type(true)); | |
| return pand(cst_one, pcmp_lt(b, a)); | |
| } | |
| }; | |
| template <typename LhsScalar, typename RhsScalar, bool UseTypedComparators> | |
| struct scalar_cmp_op<LhsScalar, RhsScalar, cmp_GE, UseTypedComparators> : binary_op_base<LhsScalar, RhsScalar> { | |
| using result_type = std::conditional_t<UseTypedComparators, LhsScalar, bool>; | |
| EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE result_type operator()(const LhsScalar& a, const RhsScalar& b) const { | |
| return result_type(a >= b); | |
| } | |
| template <typename Packet> | |
| EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const { | |
| const Packet cst_one = pset1<Packet>(result_type(true)); | |
| return pand(cst_one, pcmp_le(b, a)); | |
| } | |
| }; | |
| template <typename LhsScalar, typename RhsScalar, bool UseTypedComparators> | |
| struct scalar_cmp_op<LhsScalar, RhsScalar, cmp_UNORD, UseTypedComparators> : binary_op_base<LhsScalar, RhsScalar> { | |
| using result_type = std::conditional_t<UseTypedComparators, LhsScalar, bool>; | |
| EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE result_type operator()(const LhsScalar& a, const RhsScalar& b) const { | |
| return result_type(!(a <= b || b <= a)); | |
| } | |
| template <typename Packet> | |
| EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const { | |
| const Packet cst_one = pset1<Packet>(result_type(true)); | |
| return pandnot(cst_one, por(pcmp_le(a, b), pcmp_le(b, a))); | |
| } | |
| }; | |
| template <typename LhsScalar, typename RhsScalar, bool UseTypedComparators> | |
| struct scalar_cmp_op<LhsScalar, RhsScalar, cmp_NEQ, UseTypedComparators> : binary_op_base<LhsScalar, RhsScalar> { | |
| using result_type = std::conditional_t<UseTypedComparators, LhsScalar, bool>; | |
| EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE result_type operator()(const LhsScalar& a, const RhsScalar& b) const { | |
| return result_type(a != b); | |
| } | |
| template <typename Packet> | |
| EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const { | |
| const Packet cst_one = pset1<Packet>(result_type(true)); | |
| return pandnot(cst_one, pcmp_eq(a, b)); | |
| } | |
| }; | |
| /** \internal | |
| * \brief Template functor to compute the hypot of two \b positive \b and \b real scalars | |
| * | |
| * \sa MatrixBase::stableNorm(), class Redux | |
| */ | |
| template <typename Scalar> | |
| struct scalar_hypot_op<Scalar, Scalar> : binary_op_base<Scalar, Scalar> { | |
| EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE Scalar operator()(const Scalar& x, const Scalar& y) const { | |
| // This functor is used by hypotNorm only for which it is faster to first apply abs | |
| // on all coefficients prior to reduction through hypot. | |
| // This way we avoid calling abs on positive and real entries, and this also permits | |
| // to seamlessly handle complexes. Otherwise we would have to handle both real and complexes | |
| // through the same functor... | |
| return internal::positive_real_hypot(x, y); | |
| } | |
| }; | |
| template <typename Scalar> | |
| struct functor_traits<scalar_hypot_op<Scalar, Scalar>> { | |
| enum { | |
| Cost = 3 * NumTraits<Scalar>::AddCost + 2 * NumTraits<Scalar>::MulCost + 2 * scalar_div_cost<Scalar, false>::value, | |
| PacketAccess = false | |
| }; | |
| }; | |
| /** \internal | |
| * \brief Template functor to compute the pow of two scalars | |
| * See the specification of pow in https://en.cppreference.com/w/cpp/numeric/math/pow | |
| */ | |
| template <typename Scalar, typename Exponent> | |
| struct scalar_pow_op : binary_op_base<Scalar, Exponent> { | |
| using result_type = typename ScalarBinaryOpTraits<Scalar, Exponent, scalar_pow_op>::ReturnType; | |
| #ifdef EIGEN_SCALAR_BINARY_OP_PLUGIN | |
| scalar_pow_op() { | |
| using LhsScalar = Scalar; | |
| using RhsScalar = Exponent; | |
| EIGEN_SCALAR_BINARY_OP_PLUGIN | |
| } | |
| #endif | |
| EIGEN_DEVICE_FUNC constexpr inline result_type operator()(const Scalar& a, const Exponent& b) const { | |
| return numext::pow(a, b); | |
| } | |
| template <typename Packet> | |
| EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const { | |
| return generic_pow(a, b); | |
| } | |
| }; | |
| template <typename Scalar, typename Exponent> | |
| struct functor_traits<scalar_pow_op<Scalar, Exponent>> { | |
| enum { | |
| Cost = 5 * NumTraits<Scalar>::MulCost, | |
| PacketAccess = (!NumTraits<Scalar>::IsComplex && !NumTraits<Scalar>::IsInteger && packet_traits<Scalar>::HasPow) | |
| }; | |
| }; | |
| //---------- non associative binary functors ---------- | |
| /** \internal | |
| * \brief Template functor to compute the difference of two scalars | |
| * | |
| * \sa class CwiseBinaryOp, MatrixBase::operator- | |
| */ | |
| template <typename LhsScalar, typename RhsScalar> | |
| struct scalar_difference_op : binary_op_base<LhsScalar, RhsScalar> { | |
| EIGEN_STATIC_ASSERT((!std::is_same<LhsScalar, bool>::value || !std::is_same<RhsScalar, bool>::value), | |
| BOOLEAN_SUBTRACTION_IS_NOT_SUPPORTED__CAST_TO_A_SIGNED_INTEGER_TYPE) | |
| using result_type = typename ScalarBinaryOpTraits<LhsScalar, RhsScalar, scalar_difference_op>::ReturnType; | |
| #ifdef EIGEN_SCALAR_BINARY_OP_PLUGIN | |
| scalar_difference_op(){EIGEN_SCALAR_BINARY_OP_PLUGIN} | |
| #endif | |
| EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE result_type | |
| operator()(const LhsScalar& a, const RhsScalar& b) const { | |
| return a - b; | |
| } | |
| template <typename Packet> | |
| EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const { | |
| return internal::psub(a, b); | |
| } | |
| }; | |
| template <typename LhsScalar, typename RhsScalar> | |
| struct functor_traits<scalar_difference_op<LhsScalar, RhsScalar>> { | |
| enum { | |
| Cost = (int(NumTraits<LhsScalar>::AddCost) + int(NumTraits<RhsScalar>::AddCost)) / 2, | |
| PacketAccess = std::is_same<LhsScalar, RhsScalar>::value && packet_traits<LhsScalar>::HasSub && | |
| packet_traits<RhsScalar>::HasSub | |
| }; | |
| }; | |
| template <typename Packet, bool IsInteger = NumTraits<typename unpacket_traits<Packet>::type>::IsInteger> | |
| struct maybe_raise_div_by_zero { | |
| static EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE void run(Packet x) { EIGEN_UNUSED_VARIABLE(x); } | |
| }; | |
| #ifndef EIGEN_GPU_COMPILE_PHASE | |
| template <typename Packet> | |
| struct maybe_raise_div_by_zero<Packet, true> { | |
| static EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE void run(Packet x) { | |
| if (EIGEN_PREDICT_FALSE(predux_any(pcmp_eq(x, pzero(x))))) { | |
| // Use volatile variables to force a division by zero, which will | |
| // result in the default platform behaviour (usually SIGFPE). | |
| volatile typename unpacket_traits<Packet>::type zero = 0; | |
| volatile typename unpacket_traits<Packet>::type val = 1; | |
| val = val / zero; | |
| } | |
| } | |
| }; | |
| #endif | |
| /** \internal | |
| * \brief Template functor to compute the quotient of two scalars | |
| * | |
| * \sa class CwiseBinaryOp, Cwise::operator/() | |
| */ | |
| template <typename LhsScalar, typename RhsScalar> | |
| struct scalar_quotient_op : binary_op_base<LhsScalar, RhsScalar> { | |
| using result_type = typename ScalarBinaryOpTraits<LhsScalar, RhsScalar, scalar_quotient_op>::ReturnType; | |
| #ifdef EIGEN_SCALAR_BINARY_OP_PLUGIN | |
| scalar_quotient_op(){EIGEN_SCALAR_BINARY_OP_PLUGIN} | |
| #endif | |
| EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type | |
| operator()(const LhsScalar& a, const RhsScalar& b) const { | |
| return numext::divide(a, b); | |
| } | |
| template <typename Packet> | |
| EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const { | |
| return internal::pdiv(a, b); | |
| } | |
| }; | |
| template <typename LhsScalar, typename RhsScalar> | |
| struct functor_traits<scalar_quotient_op<LhsScalar, RhsScalar>> { | |
| using result_type = typename scalar_quotient_op<LhsScalar, RhsScalar>::result_type; | |
| enum { | |
| PacketAccess = std::is_same<LhsScalar, RhsScalar>::value && packet_traits<LhsScalar>::HasDiv && | |
| packet_traits<RhsScalar>::HasDiv, | |
| Cost = scalar_div_cost<result_type, PacketAccess>::value | |
| }; | |
| }; | |
| // Packet16b is currently Eigen's only Boolean packet. Its loads contain valid bool objects, and its casts, | |
| // comparisons, and Boolean packet operations canonicalize every lane to 0 or 1. The direct bitwise fast paths below | |
| // rely on this invariant. | |
| /** \internal | |
| * \brief Template functor to compute the modulus of two integer scalars | |
| * | |
| * \sa class CwiseBinaryOp, ArrayBase::operator%() | |
| */ | |
| template <typename LhsScalar, typename RhsScalar> | |
| struct scalar_modulus_op : binary_op_base<LhsScalar, RhsScalar> { | |
| using result_type = typename ScalarBinaryOpTraits<LhsScalar, RhsScalar, scalar_modulus_op>::ReturnType; | |
| static constexpr bool Enable = std::is_same<LhsScalar, RhsScalar>::value && NumTraits<LhsScalar>::IsInteger; | |
| EIGEN_STATIC_ASSERT(Enable, "LhsScalar and RhsScalar must be the same integer type") | |
| #ifdef EIGEN_SCALAR_BINARY_OP_PLUGIN | |
| scalar_modulus_op(){EIGEN_SCALAR_BINARY_OP_PLUGIN} | |
| #endif | |
| EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE result_type | |
| operator()(const LhsScalar& a, const RhsScalar& b) const { | |
| return a % b; | |
| } | |
| }; | |
| template <typename LhsScalar, typename RhsScalar> | |
| struct functor_traits<scalar_modulus_op<LhsScalar, RhsScalar>> { | |
| using result_type = typename scalar_modulus_op<LhsScalar, RhsScalar>::result_type; | |
| static constexpr bool PacketAccess = false; | |
| static constexpr int Cost = scalar_div_cost<result_type, false>::value; | |
| }; | |
| /** \internal | |
| * \brief Template functor to compute the and of two scalars as if they were booleans | |
| * | |
| * \sa class CwiseBinaryOp, ArrayBase::operator&& | |
| */ | |
| template <typename Scalar> | |
| struct scalar_boolean_and_op { | |
| using result_type = Scalar; | |
| // `false` any value `a` that satisfies `a == Scalar(0)` | |
| // `true` is the complement of `false` | |
| EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE Scalar operator()(const Scalar& a, const Scalar& b) const { | |
| return Scalar((a != Scalar(0)) && (b != Scalar(0))); | |
| } | |
| template <typename Packet> | |
| EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const { | |
| EIGEN_IF_CONSTEXPR ((std::is_same<Scalar, bool>::value)) { | |
| return pand(a, b); | |
| } else { | |
| const Packet cst_one = pset1<Packet>(Scalar(true)); | |
| // and(a,b) == !or(!a,!b) | |
| Packet not_a = pcmp_eq(a, pzero(a)); | |
| Packet not_b = pcmp_eq(b, pzero(b)); | |
| Packet a_nand_b = por(not_a, not_b); | |
| return pandnot(cst_one, a_nand_b); | |
| } | |
| } | |
| }; | |
| // Keep bool logical functors eager so scalar evaluator loops remain branch-free. | |
| template <> | |
| EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE bool scalar_boolean_and_op<bool>::operator()(const bool& a, | |
| const bool& b) const { | |
| return a & b; | |
| } | |
| template <typename Scalar> | |
| struct functor_traits<scalar_boolean_and_op<Scalar>> { | |
| enum { Cost = NumTraits<Scalar>::AddCost, PacketAccess = packet_traits<Scalar>::HasCmp }; | |
| }; | |
| /** \internal | |
| * \brief Template functor to compute the or of two scalars as if they were booleans | |
| * | |
| * \sa class CwiseBinaryOp, ArrayBase::operator|| | |
| */ | |
| template <typename Scalar> | |
| struct scalar_boolean_or_op { | |
| using result_type = Scalar; | |
| // `false` any value `a` that satisfies `a == Scalar(0)` | |
| // `true` is the complement of `false` | |
| EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE Scalar operator()(const Scalar& a, const Scalar& b) const { | |
| return Scalar((a != Scalar(0)) || (b != Scalar(0))); | |
| } | |
| template <typename Packet> | |
| EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const { | |
| EIGEN_IF_CONSTEXPR ((std::is_same<Scalar, bool>::value)) { | |
| return por(a, b); | |
| } else { | |
| const Packet cst_one = pset1<Packet>(Scalar(true)); | |
| // if or(a,b) == 0, then a == 0 and b == 0 | |
| // or(a,b) == !nor(a,b) | |
| Packet a_nor_b = pcmp_eq(por(a, b), pzero(a)); | |
| return pandnot(cst_one, a_nor_b); | |
| } | |
| } | |
| }; | |
| template <> | |
| EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE bool scalar_boolean_or_op<bool>::operator()(const bool& a, | |
| const bool& b) const { | |
| return a | b; | |
| } | |
| template <typename Scalar> | |
| struct functor_traits<scalar_boolean_or_op<Scalar>> { | |
| enum { Cost = NumTraits<Scalar>::AddCost, PacketAccess = packet_traits<Scalar>::HasCmp }; | |
| }; | |
| /** \internal | |
| * \brief Template functor to compute the xor of two scalars as if they were booleans | |
| * | |
| * \sa class CwiseBinaryOp, ArrayBase::operator^ | |
| */ | |
| template <typename Scalar> | |
| struct scalar_boolean_xor_op { | |
| using result_type = Scalar; | |
| // `false` any value `a` that satisfies `a == Scalar(0)` | |
| // `true` is the complement of `false` | |
| EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE Scalar operator()(const Scalar& a, const Scalar& b) const { | |
| return Scalar((a != Scalar(0)) != (b != Scalar(0))); | |
| } | |
| template <typename Packet> | |
| EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const { | |
| EIGEN_IF_CONSTEXPR ((std::is_same<Scalar, bool>::value)) { | |
| return pxor(a, b); | |
| } else { | |
| const Packet cst_one = pset1<Packet>(Scalar(true)); | |
| // xor(a,b) == xor(!a,!b) | |
| Packet not_a = pcmp_eq(a, pzero(a)); | |
| Packet not_b = pcmp_eq(b, pzero(b)); | |
| Packet a_xor_b = pxor(not_a, not_b); | |
| return pand(cst_one, a_xor_b); | |
| } | |
| } | |
| }; | |
| template <typename Scalar> | |
| struct functor_traits<scalar_boolean_xor_op<Scalar>> { | |
| enum { Cost = NumTraits<Scalar>::AddCost, PacketAccess = packet_traits<Scalar>::HasCmp }; | |
| }; | |
| template <typename Scalar, bool IsComplex = NumTraits<Scalar>::IsComplex> | |
| struct bitwise_binary_impl { | |
| static constexpr size_t Size = sizeof(Scalar); | |
| using uint_t = typename numext::get_integer_by_size<Size>::unsigned_type; | |
| static EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE Scalar run_and(const Scalar& a, const Scalar& b) { | |
| uint_t a_as_uint = numext::bit_cast<uint_t, Scalar>(a); | |
| uint_t b_as_uint = numext::bit_cast<uint_t, Scalar>(b); | |
| uint_t result = a_as_uint & b_as_uint; | |
| return numext::bit_cast<Scalar, uint_t>(result); | |
| } | |
| static EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE Scalar run_or(const Scalar& a, const Scalar& b) { | |
| uint_t a_as_uint = numext::bit_cast<uint_t, Scalar>(a); | |
| uint_t b_as_uint = numext::bit_cast<uint_t, Scalar>(b); | |
| uint_t result = a_as_uint | b_as_uint; | |
| return numext::bit_cast<Scalar, uint_t>(result); | |
| } | |
| static EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE Scalar run_xor(const Scalar& a, const Scalar& b) { | |
| uint_t a_as_uint = numext::bit_cast<uint_t, Scalar>(a); | |
| uint_t b_as_uint = numext::bit_cast<uint_t, Scalar>(b); | |
| uint_t result = a_as_uint ^ b_as_uint; | |
| return numext::bit_cast<Scalar, uint_t>(result); | |
| } | |
| }; | |
| template <typename Scalar> | |
| struct bitwise_binary_impl<Scalar, true> { | |
| using Real = typename NumTraits<Scalar>::Real; | |
| static EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE Scalar run_and(const Scalar& a, const Scalar& b) { | |
| Real real_result = bitwise_binary_impl<Real>::run_and(numext::real(a), numext::real(b)); | |
| Real imag_result = bitwise_binary_impl<Real>::run_and(numext::imag(a), numext::imag(b)); | |
| return Scalar(real_result, imag_result); | |
| } | |
| static EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE Scalar run_or(const Scalar& a, const Scalar& b) { | |
| Real real_result = bitwise_binary_impl<Real>::run_or(numext::real(a), numext::real(b)); | |
| Real imag_result = bitwise_binary_impl<Real>::run_or(numext::imag(a), numext::imag(b)); | |
| return Scalar(real_result, imag_result); | |
| } | |
| static EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE Scalar run_xor(const Scalar& a, const Scalar& b) { | |
| Real real_result = bitwise_binary_impl<Real>::run_xor(numext::real(a), numext::real(b)); | |
| Real imag_result = bitwise_binary_impl<Real>::run_xor(numext::imag(a), numext::imag(b)); | |
| return Scalar(real_result, imag_result); | |
| } | |
| }; | |
| /** \internal | |
| * \brief Template functor to compute the bitwise and of two scalars | |
| * | |
| * \sa class CwiseBinaryOp, ArrayBase::operator& | |
| */ | |
| template <typename Scalar> | |
| struct scalar_bitwise_and_op { | |
| EIGEN_STATIC_ASSERT(!NumTraits<Scalar>::RequireInitialization, | |
| BITWISE OPERATIONS MAY ONLY BE PERFORMED ON PLAIN DATA TYPES) | |
| EIGEN_STATIC_ASSERT((!std::is_same<Scalar, bool>::value), DONT USE BITWISE OPS ON BOOLEAN TYPES) | |
| using result_type = Scalar; | |
| EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE Scalar operator()(const Scalar& a, const Scalar& b) const { | |
| return bitwise_binary_impl<Scalar>::run_and(a, b); | |
| } | |
| template <typename Packet> | |
| EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const { | |
| return pand(a, b); | |
| } | |
| }; | |
| template <typename Scalar> | |
| struct functor_traits<scalar_bitwise_and_op<Scalar>> { | |
| enum { Cost = NumTraits<Scalar>::AddCost, PacketAccess = true }; | |
| }; | |
| /** \internal | |
| * \brief Template functor to compute the bitwise or of two scalars | |
| * | |
| * \sa class CwiseBinaryOp, ArrayBase::operator| | |
| */ | |
| template <typename Scalar> | |
| struct scalar_bitwise_or_op { | |
| EIGEN_STATIC_ASSERT(!NumTraits<Scalar>::RequireInitialization, | |
| BITWISE OPERATIONS MAY ONLY BE PERFORMED ON PLAIN DATA TYPES) | |
| EIGEN_STATIC_ASSERT((!std::is_same<Scalar, bool>::value), DONT USE BITWISE OPS ON BOOLEAN TYPES) | |
| using result_type = Scalar; | |
| EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE Scalar operator()(const Scalar& a, const Scalar& b) const { | |
| return bitwise_binary_impl<Scalar>::run_or(a, b); | |
| } | |
| template <typename Packet> | |
| EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const { | |
| return por(a, b); | |
| } | |
| }; | |
| template <typename Scalar> | |
| struct functor_traits<scalar_bitwise_or_op<Scalar>> { | |
| enum { Cost = NumTraits<Scalar>::AddCost, PacketAccess = true }; | |
| }; | |
| /** \internal | |
| * \brief Template functor to compute the bitwise xor of two scalars | |
| * | |
| * \sa class CwiseBinaryOp, ArrayBase::operator^ | |
| */ | |
| template <typename Scalar> | |
| struct scalar_bitwise_xor_op { | |
| EIGEN_STATIC_ASSERT(!NumTraits<Scalar>::RequireInitialization, | |
| BITWISE OPERATIONS MAY ONLY BE PERFORMED ON PLAIN DATA TYPES) | |
| EIGEN_STATIC_ASSERT((!std::is_same<Scalar, bool>::value), DONT USE BITWISE OPS ON BOOLEAN TYPES) | |
| using result_type = Scalar; | |
| EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE Scalar operator()(const Scalar& a, const Scalar& b) const { | |
| return bitwise_binary_impl<Scalar>::run_xor(a, b); | |
| } | |
| template <typename Packet> | |
| EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const { | |
| return pxor(a, b); | |
| } | |
| }; | |
| template <typename Scalar> | |
| struct functor_traits<scalar_bitwise_xor_op<Scalar>> { | |
| enum { Cost = NumTraits<Scalar>::AddCost, PacketAccess = true }; | |
| }; | |
| /** \internal | |
| * \brief Template functor to compute the absolute difference of two scalars | |
| * | |
| * \sa class CwiseBinaryOp, MatrixBase::absolute_difference | |
| */ | |
| template <typename LhsScalar, typename RhsScalar> | |
| struct scalar_absolute_difference_op : binary_op_base<LhsScalar, RhsScalar> { | |
| using result_type = typename ScalarBinaryOpTraits<LhsScalar, RhsScalar, scalar_absolute_difference_op>::ReturnType; | |
| #ifdef EIGEN_SCALAR_BINARY_OP_PLUGIN | |
| scalar_absolute_difference_op(){EIGEN_SCALAR_BINARY_OP_PLUGIN} | |
| #endif | |
| EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE result_type | |
| operator()(const LhsScalar& a, const RhsScalar& b) const { | |
| return numext::absdiff(a, b); | |
| } | |
| template <typename Packet> | |
| EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const { | |
| return internal::pabsdiff(a, b); | |
| } | |
| }; | |
| template <typename LhsScalar, typename RhsScalar> | |
| struct functor_traits<scalar_absolute_difference_op<LhsScalar, RhsScalar>> { | |
| enum { | |
| Cost = (NumTraits<LhsScalar>::AddCost + NumTraits<RhsScalar>::AddCost) / 2, | |
| PacketAccess = std::is_same<LhsScalar, RhsScalar>::value && packet_traits<LhsScalar>::HasAbsDiff | |
| }; | |
| }; | |
| template <typename LhsScalar, typename RhsScalar> | |
| struct scalar_atan2_op { | |
| using Scalar = LhsScalar; | |
| static constexpr bool Enable = | |
| std::is_same<LhsScalar, RhsScalar>::value && !NumTraits<Scalar>::IsInteger && !NumTraits<Scalar>::IsComplex; | |
| EIGEN_STATIC_ASSERT(Enable, "LhsScalar and RhsScalar must be the same non-integer, non-complex type") | |
| EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE Scalar operator()(const Scalar& y, const Scalar& x) const { | |
| return numext::atan2(y, x); | |
| } | |
| template <typename Packet> | |
| EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& y, const Packet& x) const { | |
| return internal::patan2(y, x); | |
| } | |
| }; | |
| template <typename LhsScalar, typename RhsScalar> | |
| struct functor_traits<scalar_atan2_op<LhsScalar, RhsScalar>> { | |
| using Scalar = LhsScalar; | |
| enum { | |
| PacketAccess = std::is_same<LhsScalar, RhsScalar>::value && packet_traits<Scalar>::HasATan && | |
| packet_traits<Scalar>::HasDiv && !NumTraits<Scalar>::IsInteger && !NumTraits<Scalar>::IsComplex, | |
| Cost = int(scalar_div_cost<Scalar, PacketAccess>::value) + int(functor_traits<scalar_atan_op<Scalar>>::Cost) | |
| }; | |
| }; | |
| //---------- binary functors bound to a constant, thus appearing as a unary functor ---------- | |
| // The following two classes permits to turn any binary functor into a unary one with one argument bound to a constant | |
| // value. They are analogues to the removed std::binder1st/binder2nd and are also compatible with packetOp. | |
| template <typename BinaryOp> | |
| struct bind1st_op : BinaryOp { | |
| using first_argument_type = typename BinaryOp::first_argument_type; | |
| using second_argument_type = typename BinaryOp::second_argument_type; | |
| using result_type = typename BinaryOp::result_type; | |
| EIGEN_DEVICE_FUNC constexpr explicit bind1st_op(const first_argument_type& val) : m_value(val) {} | |
| EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE result_type operator()(const second_argument_type& b) const { | |
| return BinaryOp::operator()(m_value, b); | |
| } | |
| template <typename Packet> | |
| EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& b) const { | |
| return BinaryOp::packetOp(internal::pset1<Packet>(m_value), b); | |
| } | |
| first_argument_type m_value; | |
| }; | |
| template <typename BinaryOp> | |
| struct functor_traits<bind1st_op<BinaryOp>> : functor_traits<BinaryOp> {}; | |
| template <typename BinaryOp> | |
| struct bind2nd_op : BinaryOp { | |
| using first_argument_type = typename BinaryOp::first_argument_type; | |
| using second_argument_type = typename BinaryOp::second_argument_type; | |
| using result_type = typename BinaryOp::result_type; | |
| EIGEN_DEVICE_FUNC constexpr explicit bind2nd_op(const second_argument_type& val) : m_value(val) {} | |
| EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE result_type operator()(const first_argument_type& a) const { | |
| return BinaryOp::operator()(a, m_value); | |
| } | |
| template <typename Packet> | |
| EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a) const { | |
| return BinaryOp::packetOp(a, internal::pset1<Packet>(m_value)); | |
| } | |
| second_argument_type m_value; | |
| }; | |
| template <typename BinaryOp> | |
| struct functor_traits<bind2nd_op<BinaryOp>> : functor_traits<BinaryOp> {}; | |
| } // end namespace internal | |
| } // end namespace Eigen | |
| #endif // EIGEN_BINARY_FUNCTORS_H |