// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2008-2010 Gael Guennebaud // // 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/. #ifndef EIGEN_BINARY_FUNCTORS_H #define EIGEN_BINARY_FUNCTORS_H // IWYU pragma: private #include "../InternalHeaderCheck.h" namespace Eigen { namespace internal { //---------- associative binary functors ---------- template struct binary_op_base { typedef Arg1 first_argument_type; typedef Arg2 second_argument_type; }; /** \internal * \brief Template functor to compute the sum of two scalars * * \sa class CwiseBinaryOp, MatrixBase::operator+, class VectorwiseOp, DenseBase::sum() */ template struct scalar_sum_op : binary_op_base { typedef typename ScalarBinaryOpTraits::ReturnType result_type; #ifdef EIGEN_SCALAR_BINARY_OP_PLUGIN scalar_sum_op(){EIGEN_SCALAR_BINARY_OP_PLUGIN} #endif EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type operator()(const LhsScalar& a, const RhsScalar& b) const { return a + b; } template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const { return internal::padd(a, b); } template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type predux(const Packet& a) const { return internal::predux(a); } }; template struct functor_traits> { enum { Cost = (int(NumTraits::AddCost) + int(NumTraits::AddCost)) / 2, // rough estimate! PacketAccess = is_same::value && packet_traits::HasAdd && packet_traits::HasAdd // TODO vectorize mixed sum }; }; template <> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool scalar_sum_op::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 struct scalar_product_op : binary_op_base { typedef typename ScalarBinaryOpTraits::ReturnType result_type; #ifdef EIGEN_SCALAR_BINARY_OP_PLUGIN scalar_product_op(){EIGEN_SCALAR_BINARY_OP_PLUGIN} #endif EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type operator()(const LhsScalar& a, const RhsScalar& b) const { return a * b; } template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const { return internal::pmul(a, b); } template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type predux(const Packet& a) const { return internal::predux_mul(a); } }; template struct functor_traits> { enum { Cost = (int(NumTraits::MulCost) + int(NumTraits::MulCost)) / 2, // rough estimate! PacketAccess = is_same::value && packet_traits::HasMul && packet_traits::HasMul // TODO vectorize mixed product }; }; template <> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool scalar_product_op::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 struct scalar_conj_product_op : binary_op_base { enum { Conj = NumTraits::IsComplex }; typedef typename ScalarBinaryOpTraits::ReturnType result_type; EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type operator()(const LhsScalar& a, const RhsScalar& b) const { return conj_helper().pmul(a, b); } template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const { return conj_helper().pmul(a, b); } }; template struct functor_traits> { enum { Cost = NumTraits::MulCost, PacketAccess = internal::is_same::value && packet_traits::HasMul }; }; /** \internal * \brief Template functor to compute the min of two scalars * * \sa class CwiseBinaryOp, MatrixBase::cwiseMin, class VectorwiseOp, MatrixBase::minCoeff() */ template struct scalar_min_op : binary_op_base { typedef typename ScalarBinaryOpTraits::ReturnType result_type; EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type operator()(const LhsScalar& a, const RhsScalar& b) const { return internal::pmin(a, b); } template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const { return internal::pmin(a, b); } template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type predux(const Packet& a) const { return internal::predux_min(a); } }; template struct functor_traits> { enum { Cost = (NumTraits::AddCost + NumTraits::AddCost) / 2, PacketAccess = internal::is_same::value && packet_traits::HasMin }; }; /** \internal * \brief Template functor to compute the max of two scalars * * \sa class CwiseBinaryOp, MatrixBase::cwiseMax, class VectorwiseOp, MatrixBase::maxCoeff() */ template struct scalar_max_op : binary_op_base { typedef typename ScalarBinaryOpTraits::ReturnType result_type; EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type operator()(const LhsScalar& a, const RhsScalar& b) const { return internal::pmax(a, b); } template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const { return internal::pmax(a, b); } template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type predux(const Packet& a) const { return internal::predux_max(a); } }; template struct functor_traits> { enum { Cost = (NumTraits::AddCost + NumTraits::AddCost) / 2, PacketAccess = internal::is_same::value && packet_traits::HasMax }; }; /** \internal * \brief Template functors for comparison of two scalars * \todo Implement packet-comparisons */ template struct scalar_cmp_op; template struct functor_traits> { enum { Cost = (NumTraits::AddCost + NumTraits::AddCost) / 2, PacketAccess = (UseTypedComparators || is_same::value) && is_same::value && packet_traits::HasCmp }; }; template struct scalar_cmp_op : binary_op_base { using result_type = std::conditional_t; EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type operator()(const LhsScalar& a, const RhsScalar& b) const { return a == b ? result_type(1) : result_type(0); } template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const { const Packet cst_one = pset1(result_type(1)); return pand(pcmp_eq(a, b), cst_one); } }; template struct scalar_cmp_op : binary_op_base { using result_type = std::conditional_t; EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type operator()(const LhsScalar& a, const RhsScalar& b) const { return a < b ? result_type(1) : result_type(0); } template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const { const Packet cst_one = pset1(result_type(1)); return pand(pcmp_lt(a, b), cst_one); } }; template struct scalar_cmp_op : binary_op_base { using result_type = std::conditional_t; EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type operator()(const LhsScalar& a, const RhsScalar& b) const { return a <= b ? result_type(1) : result_type(0); } template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const { const Packet cst_one = pset1(result_type(1)); return pand(cst_one, pcmp_le(a, b)); } }; template struct scalar_cmp_op : binary_op_base { using result_type = std::conditional_t; EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type operator()(const LhsScalar& a, const RhsScalar& b) const { return a > b ? result_type(1) : result_type(0); } template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const { const Packet cst_one = pset1(result_type(1)); return pand(cst_one, pcmp_lt(b, a)); } }; template struct scalar_cmp_op : binary_op_base { using result_type = std::conditional_t; EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type operator()(const LhsScalar& a, const RhsScalar& b) const { return a >= b ? result_type(1) : result_type(0); } template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const { const Packet cst_one = pset1(result_type(1)); return pand(cst_one, pcmp_le(b, a)); } }; template struct scalar_cmp_op : binary_op_base { using result_type = std::conditional_t; EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type operator()(const LhsScalar& a, const RhsScalar& b) const { return !(a <= b || b <= a) ? result_type(1) : result_type(0); } template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const { const Packet cst_one = pset1(result_type(1)); return pandnot(cst_one, por(pcmp_le(a, b), pcmp_le(b, a))); } }; template struct scalar_cmp_op : binary_op_base { using result_type = std::conditional_t; EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type operator()(const LhsScalar& a, const RhsScalar& b) const { return a != b ? result_type(1) : result_type(0); } template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const { const Packet cst_one = pset1(result_type(1)); 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 struct scalar_hypot_op : binary_op_base { EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const 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 struct functor_traits> { enum { Cost = 3 * NumTraits::AddCost + 2 * NumTraits::MulCost + 2 * scalar_div_cost::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 struct scalar_pow_op : binary_op_base { typedef typename ScalarBinaryOpTraits::ReturnType result_type; #ifdef EIGEN_SCALAR_BINARY_OP_PLUGIN scalar_pow_op() { typedef Scalar LhsScalar; typedef Exponent RhsScalar; EIGEN_SCALAR_BINARY_OP_PLUGIN } #endif EIGEN_DEVICE_FUNC inline result_type operator()(const Scalar& a, const Exponent& b) const { return numext::pow(a, b); } template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& b) const { return generic_pow(a, b); } }; template struct functor_traits> { enum { Cost = 5 * NumTraits::MulCost, PacketAccess = (!NumTraits::IsComplex && !NumTraits::IsInteger && packet_traits::HasPow) }; }; //---------- non associative binary functors ---------- /** \internal * \brief Template functor to compute the difference of two scalars * * \sa class CwiseBinaryOp, MatrixBase::operator- */ template struct scalar_difference_op : binary_op_base { typedef typename ScalarBinaryOpTraits::ReturnType result_type; #ifdef EIGEN_SCALAR_BINARY_OP_PLUGIN scalar_difference_op(){EIGEN_SCALAR_BINARY_OP_PLUGIN} #endif EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const result_type operator()(const LhsScalar& a, const RhsScalar& b) const { return a - b; } template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& b) const { return internal::psub(a, b); } }; template struct functor_traits> { enum { Cost = (int(NumTraits::AddCost) + int(NumTraits::AddCost)) / 2, PacketAccess = is_same::value && packet_traits::HasSub && packet_traits::HasSub }; }; template ::type>::IsInteger> struct maybe_raise_div_by_zero { static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void run(Packet x) { EIGEN_UNUSED_VARIABLE(x); } }; #ifndef EIGEN_GPU_COMPILE_PHASE template struct maybe_raise_div_by_zero { static EIGEN_DEVICE_FUNC 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::type zero = 0; volatile typename unpacket_traits::type val = 1; val = val / zero; } } }; #endif /** \internal * \brief Template functor to compute the quotient of two scalars * * \sa class CwiseBinaryOp, Cwise::operator/() */ template struct scalar_quotient_op : binary_op_base { typedef typename ScalarBinaryOpTraits::ReturnType result_type; #ifdef EIGEN_SCALAR_BINARY_OP_PLUGIN scalar_quotient_op(){EIGEN_SCALAR_BINARY_OP_PLUGIN} #endif EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const result_type operator()(const LhsScalar& a, const RhsScalar& b) const { return a / b; } template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& b) const { return internal::pdiv(a, b); } }; template struct functor_traits> { typedef typename scalar_quotient_op::result_type result_type; enum { PacketAccess = is_same::value && packet_traits::HasDiv && packet_traits::HasDiv, Cost = scalar_div_cost::value }; }; /** \internal * \brief Template functor to compute the and of two scalars as if they were booleans * * \sa class CwiseBinaryOp, ArrayBase::operator&& */ template 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 EIGEN_STRONG_INLINE Scalar operator()(const Scalar& a, const Scalar& b) const { return (a != Scalar(0)) && (b != Scalar(0)) ? Scalar(1) : Scalar(0); } template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const { const Packet cst_one = pset1(Scalar(1)); // 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); } }; template struct functor_traits> { enum { Cost = NumTraits::AddCost, PacketAccess = packet_traits::HasCmp }; }; /** \internal * \brief Template functor to compute the or of two scalars as if they were booleans * * \sa class CwiseBinaryOp, ArrayBase::operator|| */ template 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 EIGEN_STRONG_INLINE Scalar operator()(const Scalar& a, const Scalar& b) const { return (a != Scalar(0)) || (b != Scalar(0)) ? Scalar(1) : Scalar(0); } template EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const { const Packet cst_one = pset1(Scalar(1)); // 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 struct functor_traits> { enum { Cost = NumTraits::AddCost, PacketAccess = packet_traits::HasCmp }; }; /** \internal * \brief Template functor to compute the xor of two scalars as if they were booleans * * \sa class CwiseBinaryOp, ArrayBase::operator^ */ template 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 EIGEN_STRONG_INLINE Scalar operator()(const Scalar& a, const Scalar& b) const { return (a != Scalar(0)) != (b != Scalar(0)) ? Scalar(1) : Scalar(0); } template EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const { const Packet cst_one = pset1(Scalar(1)); // 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 struct functor_traits> { enum { Cost = NumTraits::AddCost, PacketAccess = packet_traits::HasCmp }; }; template ::IsComplex> struct bitwise_binary_impl { static constexpr size_t Size = sizeof(Scalar); using uint_t = typename numext::get_integer_by_size::unsigned_type; static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar run_and(const Scalar& a, const Scalar& b) { uint_t a_as_uint = numext::bit_cast(a); uint_t b_as_uint = numext::bit_cast(b); uint_t result = a_as_uint & b_as_uint; return numext::bit_cast(result); } static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar run_or(const Scalar& a, const Scalar& b) { uint_t a_as_uint = numext::bit_cast(a); uint_t b_as_uint = numext::bit_cast(b); uint_t result = a_as_uint | b_as_uint; return numext::bit_cast(result); } static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar run_xor(const Scalar& a, const Scalar& b) { uint_t a_as_uint = numext::bit_cast(a); uint_t b_as_uint = numext::bit_cast(b); uint_t result = a_as_uint ^ b_as_uint; return numext::bit_cast(result); } }; template struct bitwise_binary_impl { using Real = typename NumTraits::Real; static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar run_and(const Scalar& a, const Scalar& b) { Real real_result = bitwise_binary_impl::run_and(numext::real(a), numext::real(b)); Real imag_result = bitwise_binary_impl::run_and(numext::imag(a), numext::imag(b)); return Scalar(real_result, imag_result); } static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar run_or(const Scalar& a, const Scalar& b) { Real real_result = bitwise_binary_impl::run_or(numext::real(a), numext::real(b)); Real imag_result = bitwise_binary_impl::run_or(numext::imag(a), numext::imag(b)); return Scalar(real_result, imag_result); } static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar run_xor(const Scalar& a, const Scalar& b) { Real real_result = bitwise_binary_impl::run_xor(numext::real(a), numext::real(b)); Real imag_result = bitwise_binary_impl::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 struct scalar_bitwise_and_op { EIGEN_STATIC_ASSERT(!NumTraits::RequireInitialization, BITWISE OPERATIONS MAY ONLY BE PERFORMED ON PLAIN DATA TYPES) EIGEN_STATIC_ASSERT((!internal::is_same::value), DONT USE BITWISE OPS ON BOOLEAN TYPES) using result_type = Scalar; EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar operator()(const Scalar& a, const Scalar& b) const { return bitwise_binary_impl::run_and(a, b); } template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const { return pand(a, b); } }; template struct functor_traits> { enum { Cost = NumTraits::AddCost, PacketAccess = true }; }; /** \internal * \brief Template functor to compute the bitwise or of two scalars * * \sa class CwiseBinaryOp, ArrayBase::operator| */ template struct scalar_bitwise_or_op { EIGEN_STATIC_ASSERT(!NumTraits::RequireInitialization, BITWISE OPERATIONS MAY ONLY BE PERFORMED ON PLAIN DATA TYPES) EIGEN_STATIC_ASSERT((!internal::is_same::value), DONT USE BITWISE OPS ON BOOLEAN TYPES) using result_type = Scalar; EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar operator()(const Scalar& a, const Scalar& b) const { return bitwise_binary_impl::run_or(a, b); } template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const { return por(a, b); } }; template struct functor_traits> { enum { Cost = NumTraits::AddCost, PacketAccess = true }; }; /** \internal * \brief Template functor to compute the bitwise xor of two scalars * * \sa class CwiseBinaryOp, ArrayBase::operator^ */ template struct scalar_bitwise_xor_op { EIGEN_STATIC_ASSERT(!NumTraits::RequireInitialization, BITWISE OPERATIONS MAY ONLY BE PERFORMED ON PLAIN DATA TYPES) EIGEN_STATIC_ASSERT((!internal::is_same::value), DONT USE BITWISE OPS ON BOOLEAN TYPES) using result_type = Scalar; EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar operator()(const Scalar& a, const Scalar& b) const { return bitwise_binary_impl::run_xor(a, b); } template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const { return pxor(a, b); } }; template struct functor_traits> { enum { Cost = NumTraits::AddCost, PacketAccess = true }; }; /** \internal * \brief Template functor to compute the absolute difference of two scalars * * \sa class CwiseBinaryOp, MatrixBase::absolute_difference */ template struct scalar_absolute_difference_op : binary_op_base { typedef typename ScalarBinaryOpTraits::ReturnType result_type; #ifdef EIGEN_SCALAR_BINARY_OP_PLUGIN scalar_absolute_difference_op(){EIGEN_SCALAR_BINARY_OP_PLUGIN} #endif EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const result_type operator()(const LhsScalar& a, const RhsScalar& b) const { return numext::absdiff(a, b); } template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& b) const { return internal::pabsdiff(a, b); } }; template struct functor_traits> { enum { Cost = (NumTraits::AddCost + NumTraits::AddCost) / 2, PacketAccess = is_same::value && packet_traits::HasAbsDiff }; }; template struct scalar_atan2_op { using Scalar = LhsScalar; static constexpr bool Enable = is_same::value && !NumTraits::IsInteger && !NumTraits::IsComplex; EIGEN_STATIC_ASSERT(Enable, "LhsScalar and RhsScalar must be the same non-integer, non-complex type") EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar operator()(const Scalar& y, const Scalar& x) const { return numext::atan2(y, x); } template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& y, const Packet& x) const { return internal::patan2(y, x); } }; template struct functor_traits> { using Scalar = LhsScalar; enum { PacketAccess = is_same::value && packet_traits::HasATan && packet_traits::HasDiv && !NumTraits::IsInteger && !NumTraits::IsComplex, Cost = int(scalar_div_cost::value) + int(functor_traits>::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 std::binder1st/binder2nd but with the following differences: // - they are compatible with packetOp // - they are portable across C++ versions (the std::binder* are deprecated in C++11) template struct bind1st_op : BinaryOp { typedef typename BinaryOp::first_argument_type first_argument_type; typedef typename BinaryOp::second_argument_type second_argument_type; typedef typename BinaryOp::result_type result_type; EIGEN_DEVICE_FUNC explicit bind1st_op(const first_argument_type& val) : m_value(val) {} EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const result_type operator()(const second_argument_type& b) const { return BinaryOp::operator()(m_value, b); } template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Packet packetOp(const Packet& b) const { return BinaryOp::packetOp(internal::pset1(m_value), b); } first_argument_type m_value; }; template struct functor_traits> : functor_traits {}; template struct bind2nd_op : BinaryOp { typedef typename BinaryOp::first_argument_type first_argument_type; typedef typename BinaryOp::second_argument_type second_argument_type; typedef typename BinaryOp::result_type result_type; EIGEN_DEVICE_FUNC explicit bind2nd_op(const second_argument_type& val) : m_value(val) {} EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const result_type operator()(const first_argument_type& a) const { return BinaryOp::operator()(a, m_value); } template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a) const { return BinaryOp::packetOp(a, internal::pset1(m_value)); } second_argument_type m_value; }; template struct functor_traits> : functor_traits {}; } // end namespace internal } // end namespace Eigen #endif // EIGEN_BINARY_FUNCTORS_H