From 66e99ab6a1444d8e3d47211e4540837e6b982a3a Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 6 Jun 2016 15:11:41 +0200 Subject: Relax mixing-type constraints for binary coefficient-wise operators: - Replace internal::scalar_product_traits by Eigen::ScalarBinaryOpTraits - Remove the "functor_is_product_like" helper (was pretty ugly) - Currently, OP is not used, but it is available to the user for fine grained tuning - Currently, only the following operators have been generalized: *,/,+,-,=,*=,/=,+=,-= - TODO: generalize all other binray operators (comparisons,pow,etc.) - TODO: handle "scalar op array" operators (currently only * is handled) - TODO: move the handling of the "void" scalar type to ScalarBinaryOpTraits --- test/mixingtypes.cpp | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) (limited to 'test/mixingtypes.cpp') diff --git a/test/mixingtypes.cpp b/test/mixingtypes.cpp index dbcf468ea..66d9b777a 100644 --- a/test/mixingtypes.cpp +++ b/test/mixingtypes.cpp @@ -42,6 +42,7 @@ template void mixingtypes(int size = SizeAtCompileType) Mat_f mf = Mat_f::Random(size,size); Mat_d md = mf.template cast(); + //Mat_d rd = md; Mat_cf mcf = Mat_cf::Random(size,size); Mat_cd mcd = mcf.template cast >(); Mat_cd rcd = mcd; @@ -56,16 +57,12 @@ template void mixingtypes(int size = SizeAtCompileType) mf+mf; - VERIFY_RAISES_ASSERT(mf+md); -#if !EIGEN_HAS_STD_RESULT_OF - // this one does not even compile with C++11 - VERIFY_RAISES_ASSERT(mf+mcf); -#endif + +// VERIFY_RAISES_ASSERT(mf+md); // does not even compile #ifdef EIGEN_DONT_VECTORIZE VERIFY_RAISES_ASSERT(vf=vd); VERIFY_RAISES_ASSERT(vf+=vd); - VERIFY_RAISES_ASSERT(mcd=md); #endif // check scalar products @@ -186,16 +183,35 @@ template void mixingtypes(int size = SizeAtCompileType) Mat_cd((scd * md.template cast().eval() * mcd).template triangularView())); - VERIFY_IS_APPROX( md.array() * mcd.array(), md.template cast().eval().array() * mcd.array() ); - VERIFY_IS_APPROX( mcd.array() * md.array(), mcd.array() * md.template cast().eval().array() ); + + VERIFY_IS_APPROX( md.array() * mcd.array(), md.template cast().eval().array() * mcd.array() ); + VERIFY_IS_APPROX( mcd.array() * md.array(), mcd.array() * md.template cast().eval().array() ); + + VERIFY_IS_APPROX( md.array() + mcd.array(), md.template cast().eval().array() + mcd.array() ); + VERIFY_IS_APPROX( mcd.array() + md.array(), mcd.array() + md.template cast().eval().array() ); + + VERIFY_IS_APPROX( md.array() - mcd.array(), md.template cast().eval().array() - mcd.array() ); + VERIFY_IS_APPROX( mcd.array() - md.array(), mcd.array() - md.template cast().eval().array() ); // VERIFY_IS_APPROX( md.array() / mcd.array(), md.template cast().eval().array() / mcd.array() ); VERIFY_IS_APPROX( mcd.array() / md.array(), mcd.array() / md.template cast().eval().array() ); + rcd = mcd; + VERIFY_IS_APPROX( rcd = md, md.template cast().eval() ); + rcd = mcd; + VERIFY_IS_APPROX( rcd += md, mcd + md.template cast().eval() ); + rcd = mcd; + VERIFY_IS_APPROX( rcd -= md, mcd - md.template cast().eval() ); rcd = mcd; VERIFY_IS_APPROX( rcd.array() *= md.array(), mcd.array() * md.template cast().eval().array() ); rcd = mcd; VERIFY_IS_APPROX( rcd.array() /= md.array(), mcd.array() / md.template cast().eval().array() ); + + rcd = mcd; + VERIFY_IS_APPROX( rcd += md + mcd*md, mcd + (md.template cast().eval()) + mcd*(md.template cast().eval())); + + rcd = mcd; + VERIFY_IS_APPROX( rcd += mcd + md*md, mcd + mcd + ((md*md).template cast().eval()) ); } void test_mixingtypes() -- cgit v1.2.3 From 3d71d3918e750be81739f24cdc0687648fb7f5c5 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 6 Jun 2016 23:10:55 +0200 Subject: Disable shortcuts for res ?= prod when the scalar types do not match exactly. --- Eigen/src/Core/ProductEvaluators.h | 15 +++++++++------ test/mixingtypes.cpp | 13 +++++++++++-- 2 files changed, 20 insertions(+), 8 deletions(-) (limited to 'test/mixingtypes.cpp') diff --git a/Eigen/src/Core/ProductEvaluators.h b/Eigen/src/Core/ProductEvaluators.h index 7f041e5dd..71ae6e54c 100644 --- a/Eigen/src/Core/ProductEvaluators.h +++ b/Eigen/src/Core/ProductEvaluators.h @@ -122,14 +122,17 @@ protected: PlainObject m_result; }; +// The following three shortcuts are enabled only if the scalar types match excatly. +// TODO: we could enable them for different scalar types when the product is not vectorized. + // Dense = Product template< typename DstXprType, typename Lhs, typename Rhs, int Options, typename Scalar> -struct Assignment, internal::assign_op::Scalar>, Dense2Dense, +struct Assignment, internal::assign_op, Dense2Dense, typename enable_if<(Options==DefaultProduct || Options==AliasFreeProduct),Scalar>::type> { typedef Product SrcXprType; static EIGEN_STRONG_INLINE - void run(DstXprType &dst, const SrcXprType &src, const internal::assign_op &) + void run(DstXprType &dst, const SrcXprType &src, const internal::assign_op &) { // FIXME shall we handle nested_eval here? generic_product_impl::evalTo(dst, src.lhs(), src.rhs()); @@ -138,12 +141,12 @@ struct Assignment, internal::assign_op -struct Assignment, internal::add_assign_op::Scalar>, Dense2Dense, +struct Assignment, internal::add_assign_op, Dense2Dense, typename enable_if<(Options==DefaultProduct || Options==AliasFreeProduct),Scalar>::type> { typedef Product SrcXprType; static EIGEN_STRONG_INLINE - void run(DstXprType &dst, const SrcXprType &src, const internal::add_assign_op &) + void run(DstXprType &dst, const SrcXprType &src, const internal::add_assign_op &) { // FIXME shall we handle nested_eval here? generic_product_impl::addTo(dst, src.lhs(), src.rhs()); @@ -152,12 +155,12 @@ struct Assignment, internal::add_assign_op< // Dense -= Product template< typename DstXprType, typename Lhs, typename Rhs, int Options, typename Scalar> -struct Assignment, internal::sub_assign_op::Scalar>, Dense2Dense, +struct Assignment, internal::sub_assign_op, Dense2Dense, typename enable_if<(Options==DefaultProduct || Options==AliasFreeProduct),Scalar>::type> { typedef Product SrcXprType; static EIGEN_STRONG_INLINE - void run(DstXprType &dst, const SrcXprType &src, const internal::sub_assign_op &) + void run(DstXprType &dst, const SrcXprType &src, const internal::sub_assign_op &) { // FIXME shall we handle nested_eval here? generic_product_impl::subTo(dst, src.lhs(), src.rhs()); diff --git a/test/mixingtypes.cpp b/test/mixingtypes.cpp index 66d9b777a..2af188b25 100644 --- a/test/mixingtypes.cpp +++ b/test/mixingtypes.cpp @@ -208,10 +208,19 @@ template void mixingtypes(int size = SizeAtCompileType) VERIFY_IS_APPROX( rcd.array() /= md.array(), mcd.array() / md.template cast().eval().array() ); rcd = mcd; - VERIFY_IS_APPROX( rcd += md + mcd*md, mcd + (md.template cast().eval()) + mcd*(md.template cast().eval())); + VERIFY_IS_APPROX( rcd.noalias() += md + mcd*md, mcd + (md.template cast().eval()) + mcd*(md.template cast().eval())); + VERIFY_IS_APPROX( rcd.noalias() = md*md, ((md*md).eval().template cast()) ); rcd = mcd; - VERIFY_IS_APPROX( rcd += mcd + md*md, mcd + mcd + ((md*md).template cast().eval()) ); + VERIFY_IS_APPROX( rcd.noalias() += md*md, mcd + ((md*md).eval().template cast()) ); + rcd = mcd; + VERIFY_IS_APPROX( rcd.noalias() -= md*md, mcd - ((md*md).eval().template cast()) ); + + VERIFY_IS_APPROX( rcd.noalias() = mcd + md*md, mcd + ((md*md).eval().template cast()) ); + rcd = mcd; + VERIFY_IS_APPROX( rcd.noalias() += mcd + md*md, mcd + mcd + ((md*md).eval().template cast()) ); + rcd = mcd; + VERIFY_IS_APPROX( rcd.noalias() -= mcd + md*md, - ((md*md).eval().template cast()) ); } void test_mixingtypes() -- cgit v1.2.3 From 5de8d7036b8b48bc4986d96f677c77eb466ce02b Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Fri, 10 Jun 2016 15:58:22 +0200 Subject: Add real.pow(complex), complex.pow(real) unit tests. --- test/mixingtypes.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'test/mixingtypes.cpp') diff --git a/test/mixingtypes.cpp b/test/mixingtypes.cpp index 2af188b25..d719a3c53 100644 --- a/test/mixingtypes.cpp +++ b/test/mixingtypes.cpp @@ -196,6 +196,9 @@ template void mixingtypes(int size = SizeAtCompileType) // VERIFY_IS_APPROX( md.array() / mcd.array(), md.template cast().eval().array() / mcd.array() ); VERIFY_IS_APPROX( mcd.array() / md.array(), mcd.array() / md.template cast().eval().array() ); + VERIFY_IS_APPROX( md.array().pow(mcd.array()), md.template cast().eval().array().pow(mcd.array()) ); + VERIFY_IS_APPROX( mcd.array().pow(md.array()), mcd.array().pow(md.template cast().eval().array()) ); + rcd = mcd; VERIFY_IS_APPROX( rcd = md, md.template cast().eval() ); rcd = mcd; -- cgit v1.2.3 From 2ca2ffb65e10af6310382bd6efb294efb4f74588 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 13 Jun 2016 16:15:32 +0200 Subject: check for mixing types in "array / scalar" expressions --- test/mixingtypes.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'test/mixingtypes.cpp') diff --git a/test/mixingtypes.cpp b/test/mixingtypes.cpp index d719a3c53..dee4f35df 100644 --- a/test/mixingtypes.cpp +++ b/test/mixingtypes.cpp @@ -67,9 +67,13 @@ template void mixingtypes(int size = SizeAtCompileType) // check scalar products VERIFY_IS_APPROX(vcf * sf , vcf * complex(sf)); - VERIFY_IS_APPROX(sd * vcd, complex(sd) * vcd); + VERIFY_IS_APPROX(sd * vcd , complex(sd) * vcd); VERIFY_IS_APPROX(vf * scf , vf.template cast >() * scf); - VERIFY_IS_APPROX(scd * vd, scd * vd.template cast >()); + VERIFY_IS_APPROX(scd * vd , scd * vd.template cast >()); + + // check scalar quotients + VERIFY_IS_APPROX(vcf / sf , vcf / complex(sf)); + VERIFY_IS_APPROX(vf / scf , vf.template cast >() / scf); // check dot product vf.dot(vf); -- cgit v1.2.3 From a8c08e8b8e8bdd486a5a27b9f1e92c48ef4361cd Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 14 Jun 2016 12:06:10 +0200 Subject: Implement expr+scalar, scalar+expr, expr-scalar, and scalar-expr as binary expressions, and generalize supported scalar types. The following functors are now deprecated: scalar_add_op, scalar_sub_op, and scalar_rsub_op. --- Eigen/src/Core/functors/BinaryFunctors.h | 31 +++++++---------- Eigen/src/Core/util/ForwardDeclarations.h | 1 - Eigen/src/plugins/ArrayCwiseBinaryOps.h | 57 ++++++++++++++++--------------- test/linearstructure.cpp | 16 +++++++++ test/mixingtypes.cpp | 12 +++++++ 5 files changed, 70 insertions(+), 47 deletions(-) (limited to 'test/mixingtypes.cpp') diff --git a/Eigen/src/Core/functors/BinaryFunctors.h b/Eigen/src/Core/functors/BinaryFunctors.h index 77e9e6e93..fd7b5f8b4 100644 --- a/Eigen/src/Core/functors/BinaryFunctors.h +++ b/Eigen/src/Core/functors/BinaryFunctors.h @@ -32,7 +32,13 @@ template struct scalar_sum_op : binary_op_base { typedef typename ScalarBinaryOpTraits::ReturnType result_type; +#ifndef EIGEN_SCALAR_BINARY_OP_PLUGIN EIGEN_EMPTY_STRUCT_CTOR(scalar_sum_op) +#else + scalar_sum_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 @@ -315,7 +321,13 @@ template struct scalar_difference_op : binary_op_base { typedef typename ScalarBinaryOpTraits::ReturnType result_type; +#ifndef EIGEN_SCALAR_BINARY_OP_PLUGIN EIGEN_EMPTY_STRUCT_CTOR(scalar_difference_op) +#else + 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 @@ -584,7 +596,7 @@ struct functor_traits > /** \internal * \brief Template functor to subtract a fixed scalar to another one - * \sa class CwiseUnaryOp, Array::operator-, struct scalar_add_op, struct scalar_rsub_op + * \sa class CwiseUnaryOp, Array::operator-, struct scalar_add_op */ template struct scalar_sub_op { @@ -600,23 +612,6 @@ template struct functor_traits > { enum { Cost = NumTraits::AddCost, PacketAccess = packet_traits::HasAdd }; }; -/** \internal - * \brief Template functor to subtract a scalar to fixed another one - * \sa class CwiseUnaryOp, Array::operator-, struct scalar_add_op, struct scalar_sub_op - */ -template -struct scalar_rsub_op { - EIGEN_DEVICE_FUNC inline scalar_rsub_op(const scalar_rsub_op& other) : m_other(other.m_other) { } - EIGEN_DEVICE_FUNC inline scalar_rsub_op(const Scalar& other) : m_other(other) { } - EIGEN_DEVICE_FUNC inline Scalar operator() (const Scalar& a) const { return m_other - a; } - template - EIGEN_DEVICE_FUNC inline const Packet packetOp(const Packet& a) const - { return internal::psub(pset1(m_other), a); } - const Scalar m_other; -}; -template -struct functor_traits > -{ enum { Cost = NumTraits::AddCost, PacketAccess = packet_traits::HasAdd }; }; /** \internal * \brief Template functor to raise a scalar to a power diff --git a/Eigen/src/Core/util/ForwardDeclarations.h b/Eigen/src/Core/util/ForwardDeclarations.h index 8334446d6..c1295dc5f 100644 --- a/Eigen/src/Core/util/ForwardDeclarations.h +++ b/Eigen/src/Core/util/ForwardDeclarations.h @@ -202,7 +202,6 @@ template struct scalar_square_op; template struct scalar_cube_op; template struct scalar_cast_op; template struct scalar_random_op; -template struct scalar_add_op; template struct scalar_constant_op; template struct scalar_identity_op; template struct scalar_sign_op; diff --git a/Eigen/src/plugins/ArrayCwiseBinaryOps.h b/Eigen/src/plugins/ArrayCwiseBinaryOps.h index 351762e82..8bf4e9b18 100644 --- a/Eigen/src/plugins/ArrayCwiseBinaryOps.h +++ b/Eigen/src/plugins/ArrayCwiseBinaryOps.h @@ -192,48 +192,49 @@ EIGEN_MAKE_CWISE_COMP_OP(operator!=, NEQ) #undef EIGEN_MAKE_CWISE_COMP_R_OP // scalar addition - +#ifndef EIGEN_PARSED_BY_DOXYGEN +EIGEN_MAKE_SCALAR_BINARY_OP(operator+,sum); +#else /** \returns an expression of \c *this with each coeff incremented by the constant \a scalar + * + * \tparam T is the scalar type of \a scalar. It must be compatible with the scalar type of the given expression. * * Example: \include Cwise_plus.cpp * Output: \verbinclude Cwise_plus.out * * \sa operator+=(), operator-() */ -EIGEN_DEVICE_FUNC -inline const CwiseUnaryOp, const Derived> -operator+(const Scalar& scalar) const -{ - return CwiseUnaryOp, const Derived>(derived(), internal::scalar_add_op(scalar)); -} - -EIGEN_DEVICE_FUNC -friend inline const CwiseUnaryOp, const Derived> -operator+(const Scalar& scalar,const EIGEN_CURRENT_STORAGE_BASE_CLASS& other) -{ - return other + scalar; -} +template +const CwiseBinaryOp,Derived,Constant > operator+(const T& scalar) const; +/** \returns an expression of \a expr with each coeff incremented by the constant \a scalar + * + * \tparam T is the scalar type of \a scalar. It must be compatible with the scalar type of the given expression. + */ +template friend +const CwiseBinaryOp,Constant,Derived> operator+(const T& scalar, const StorageBaseType& expr); +#endif +#ifndef EIGEN_PARSED_BY_DOXYGEN +EIGEN_MAKE_SCALAR_BINARY_OP(operator-,difference); +#else /** \returns an expression of \c *this with each coeff decremented by the constant \a scalar + * + * \tparam T is the scalar type of \a scalar. It must be compatible with the scalar type of the given expression. * * Example: \include Cwise_minus.cpp * Output: \verbinclude Cwise_minus.out * - * \sa operator+(), operator-=() + * \sa operator+=(), operator-() */ -EIGEN_DEVICE_FUNC -inline const CwiseUnaryOp, const Derived> -operator-(const Scalar& scalar) const -{ - return CwiseUnaryOp, const Derived>(derived(), internal::scalar_sub_op(scalar));; -} - -EIGEN_DEVICE_FUNC -friend inline const CwiseUnaryOp, const Derived> -operator-(const Scalar& scalar,const EIGEN_CURRENT_STORAGE_BASE_CLASS& other) -{ - return CwiseUnaryOp, const Derived>(other.derived(), internal::scalar_rsub_op(scalar));; -} +template +const CwiseBinaryOp,Derived,Constant > operator-(const T& scalar) const; +/** \returns an expression of the constant matrix of value \a scalar decremented by the coefficients of \a expr + * + * \tparam T is the scalar type of \a scalar. It must be compatible with the scalar type of the given expression. + */ +template friend +const CwiseBinaryOp,Constant,Derived> operator-(const T& scalar, const StorageBaseType& expr); +#endif /** \returns an expression of the coefficient-wise && operator of *this and \a other * diff --git a/test/linearstructure.cpp b/test/linearstructure.cpp index 7eef976d2..17474af10 100644 --- a/test/linearstructure.cpp +++ b/test/linearstructure.cpp @@ -93,6 +93,22 @@ template void real_complex(DenseIndex rows = MatrixType::Ro g_called = false; VERIFY_IS_APPROX(m1/s, m1/Scalar(s)); VERIFY(g_called && "matrix / real not properly optimized"); + + g_called = false; + VERIFY_IS_APPROX(s+m1.array(), Scalar(s)+m1.array()); + VERIFY(g_called && "real + matrix not properly optimized"); + + g_called = false; + VERIFY_IS_APPROX(m1.array()+s, m1.array()+Scalar(s)); + VERIFY(g_called && "matrix + real not properly optimized"); + + g_called = false; + VERIFY_IS_APPROX(s-m1.array(), Scalar(s)-m1.array()); + VERIFY(g_called && "real - matrix not properly optimized"); + + g_called = false; + VERIFY_IS_APPROX(m1.array()-s, m1.array()-Scalar(s)); + VERIFY(g_called && "matrix - real not properly optimized"); } void test_linearstructure() diff --git a/test/mixingtypes.cpp b/test/mixingtypes.cpp index dee4f35df..cf2207114 100644 --- a/test/mixingtypes.cpp +++ b/test/mixingtypes.cpp @@ -75,6 +75,18 @@ template void mixingtypes(int size = SizeAtCompileType) VERIFY_IS_APPROX(vcf / sf , vcf / complex(sf)); VERIFY_IS_APPROX(vf / scf , vf.template cast >() / scf); + // check scalar increment + VERIFY_IS_APPROX(vcf.array() + sf , vcf.array() + complex(sf)); + VERIFY_IS_APPROX(sd + vcd.array(), complex(sd) + vcd.array()); + VERIFY_IS_APPROX(vf.array() + scf, vf.template cast >().array() + scf); + VERIFY_IS_APPROX(scd + vd.array() , scd + vd.template cast >().array()); + + // check scalar subtractions + VERIFY_IS_APPROX(vcf.array() - sf , vcf.array() - complex(sf)); + VERIFY_IS_APPROX(sd - vcd.array(), complex(sd) - vcd.array()); + VERIFY_IS_APPROX(vf.array() - scf, vf.template cast >().array() - scf); + VERIFY_IS_APPROX(scd - vd.array() , scd - vd.template cast >().array()); + // check dot product vf.dot(vf); #if 0 // we get other compilation errors here than just static asserts -- cgit v1.2.3 From 396d9cfb6eaa62ecafc6f2d02851f0d2f8d6b4ef Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 14 Jun 2016 14:10:07 +0200 Subject: Generalize expr.pow(scalar), pow(expr,scalar) and pow(scalar,expr). Internal: scalar_pow_op (unary) is removed, and scalar_binary_pow_op is renamed scalar_pow_op. --- Eigen/src/Core/GlobalFunctions.h | 58 +++++++++++++++++++++++++------ Eigen/src/Core/MathFunctions.h | 2 +- Eigen/src/Core/functors/BinaryFunctors.h | 39 ++++++++------------- Eigen/src/Core/util/ForwardDeclarations.h | 3 +- Eigen/src/plugins/ArrayCwiseBinaryOps.h | 21 ++++++++++- Eigen/src/plugins/ArrayCwiseUnaryOps.h | 19 ---------- test/mixingtypes.cpp | 47 +++++++++++++++++-------- 7 files changed, 117 insertions(+), 72 deletions(-) (limited to 'test/mixingtypes.cpp') diff --git a/Eigen/src/Core/GlobalFunctions.h b/Eigen/src/Core/GlobalFunctions.h index e489cefec..60e2ccfed 100644 --- a/Eigen/src/Core/GlobalFunctions.h +++ b/Eigen/src/Core/GlobalFunctions.h @@ -89,14 +89,32 @@ namespace Eigen EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(sign,scalar_sign_op,sign (or 0),\sa ArrayBase::sign) /** \returns an expression of the coefficient-wise power of \a x to the given constant \a exponent. + * + * \tparam ScalarExponent is the scalar type of \a exponent. It must be compatible with the scalar type of the given expression (\c Derived::Scalar). * * \sa ArrayBase::pow() + * + * \relates ArrayBase */ +#ifdef EIGEN_PARSED_BY_DOXYGEN + template + inline const CwiseBinaryOp,Derived,Constant > + pow(const Eigen::ArrayBase& x, const ScalarExponent& exponent); +#else + template + inline typename internal::enable_if< !(internal::is_same::value) + && ScalarBinaryOpTraits::Defined, + const EIGEN_EXPR_BINARYOP_SCALAR_RETURN_TYPE(Derived,ScalarExponent,pow) >::type + pow(const Eigen::ArrayBase& x, const ScalarExponent& exponent) { + return x.derived().pow(exponent); + } + template - inline const Eigen::CwiseUnaryOp, const Derived> + inline const EIGEN_EXPR_BINARYOP_SCALAR_RETURN_TYPE(Derived,typename Derived::Scalar,pow) pow(const Eigen::ArrayBase& x, const typename Derived::Scalar& exponent) { return x.derived().pow(exponent); } +#endif /** \returns an expression of the coefficient-wise power of \a x to the given array of \a exponents. * @@ -106,12 +124,14 @@ namespace Eigen * Output: \verbinclude Cwise_array_power_array.out * * \sa ArrayBase::pow() + * + * \relates ArrayBase */ template - inline const Eigen::CwiseBinaryOp, const Derived, const ExponentDerived> + inline const Eigen::CwiseBinaryOp, const Derived, const ExponentDerived> pow(const Eigen::ArrayBase& x, const Eigen::ArrayBase& exponents) { - return Eigen::CwiseBinaryOp, const Derived, const ExponentDerived>( + return Eigen::CwiseBinaryOp, const Derived, const ExponentDerived>( x.derived(), exponents.derived() ); @@ -120,23 +140,39 @@ namespace Eigen /** \returns an expression of the coefficient-wise power of the scalar \a x to the given array of \a exponents. * * This function computes the coefficient-wise power between a scalar and an array of exponents. - * Beaware that the scalar type of the input scalar \a x and the exponents \a exponents must be the same. + * + * \tparam Scalar is the scalar type of \a x. It must be compatible with the scalar type of the given array expression (\c Derived::Scalar). * * Example: \include Cwise_scalar_power_array.cpp * Output: \verbinclude Cwise_scalar_power_array.out * * \sa ArrayBase::pow() + * + * \relates ArrayBase */ +#ifdef EIGEN_PARSED_BY_DOXYGEN + template + inline const CwiseBinaryOp,Constant,Derived> + pow(const Scalar& x,const Eigen::ArrayBase& x); +#else + template + inline typename internal::enable_if< !(internal::is_same::value) + && ScalarBinaryOpTraits::Defined, + const EIGEN_SCALAR_BINARYOP_EXPR_RETURN_TYPE(Scalar,Derived,pow) >::type + pow(const Scalar& x, const Eigen::ArrayBase& exponents) + { + return EIGEN_SCALAR_BINARYOP_EXPR_RETURN_TYPE(Scalar,Derived,pow)( + typename internal::plain_constant_type::type(exponents.rows(), exponents.cols(), x), exponents.derived() ); + } + template - inline const Eigen::CwiseBinaryOp, const typename Derived::ConstantReturnType, const Derived> - pow(const typename Derived::Scalar& x, const Eigen::ArrayBase& exponents) + inline const EIGEN_SCALAR_BINARYOP_EXPR_RETURN_TYPE(typename Derived::Scalar,Derived,pow) + pow(const typename Derived::Scalar& x, const Eigen::ArrayBase& exponents) { - typename Derived::ConstantReturnType constant_x(exponents.rows(), exponents.cols(), x); - return Eigen::CwiseBinaryOp, const typename Derived::ConstantReturnType, const Derived>( - constant_x, - exponents.derived() - ); + return EIGEN_SCALAR_BINARYOP_EXPR_RETURN_TYPE(typename Derived::Scalar,Derived,pow)( + typename internal::plain_constant_type::type(exponents.rows(), exponents.cols(), x), exponents.derived() ); } +#endif /** * \brief Component-wise division of a scalar by array elements. diff --git a/Eigen/src/Core/MathFunctions.h b/Eigen/src/Core/MathFunctions.h index 2a05ae12d..b683effab 100644 --- a/Eigen/src/Core/MathFunctions.h +++ b/Eigen/src/Core/MathFunctions.h @@ -498,7 +498,7 @@ template: struct pow_impl { //typedef Scalar retval; - typedef typename ScalarBinaryOpTraits >::ReturnType result_type; + typedef typename ScalarBinaryOpTraits >::ReturnType result_type; static EIGEN_DEVICE_FUNC inline result_type run(const ScalarX& x, const ScalarY& y) { EIGEN_USING_STD_MATH(pow); diff --git a/Eigen/src/Core/functors/BinaryFunctors.h b/Eigen/src/Core/functors/BinaryFunctors.h index fd7b5f8b4..9e40303be 100644 --- a/Eigen/src/Core/functors/BinaryFunctors.h +++ b/Eigen/src/Core/functors/BinaryFunctors.h @@ -295,16 +295,24 @@ struct functor_traits > { /** \internal * \brief Template functor to compute the pow of two scalars */ -template -struct scalar_binary_pow_op : binary_op_base +template +struct scalar_pow_op : binary_op_base { - typedef typename ScalarBinaryOpTraits::ReturnType result_type; - EIGEN_EMPTY_STRUCT_CTOR(scalar_binary_pow_op) + typedef typename ScalarBinaryOpTraits::ReturnType result_type; +#ifndef EIGEN_SCALAR_BINARY_OP_PLUGIN + EIGEN_EMPTY_STRUCT_CTOR(scalar_pow_op) +#else + 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 OtherScalar& b) const { return numext::pow(a, b); } + inline result_type operator() (const Scalar& a, const Exponent& b) const { return numext::pow(a, b); } }; -template -struct functor_traits > { +template +struct functor_traits > { enum { Cost = 5 * NumTraits::MulCost, PacketAccess = false }; }; @@ -613,23 +621,6 @@ struct functor_traits > { enum { Cost = NumTraits::AddCost, PacketAccess = packet_traits::HasAdd }; }; -/** \internal - * \brief Template functor to raise a scalar to a power - * \sa class CwiseUnaryOp, Cwise::pow - */ -template -struct scalar_pow_op { - // FIXME default copy constructors seems bugged with std::complex<> - EIGEN_DEVICE_FUNC inline scalar_pow_op(const scalar_pow_op& other) : m_exponent(other.m_exponent) { } - EIGEN_DEVICE_FUNC inline scalar_pow_op(const Scalar& exponent) : m_exponent(exponent) {} - EIGEN_DEVICE_FUNC - inline Scalar operator() (const Scalar& a) const { return numext::pow(a, m_exponent); } - const Scalar m_exponent; -}; -template -struct functor_traits > -{ enum { Cost = 5 * NumTraits::MulCost, PacketAccess = false }; }; - /** \internal * \brief Template functor to compute the quotient between a scalar and array entries. * \sa class CwiseUnaryOp, Cwise::inverse() diff --git a/Eigen/src/Core/util/ForwardDeclarations.h b/Eigen/src/Core/util/ForwardDeclarations.h index c1295dc5f..830f20f90 100644 --- a/Eigen/src/Core/util/ForwardDeclarations.h +++ b/Eigen/src/Core/util/ForwardDeclarations.h @@ -196,7 +196,6 @@ template struct scalar_sin_op; template struct scalar_acos_op; template struct scalar_asin_op; template struct scalar_tan_op; -template struct scalar_pow_op; template struct scalar_inverse_op; template struct scalar_square_op; template struct scalar_cube_op; @@ -209,10 +208,10 @@ template struct scalar_igamma_op; template struct scalar_igammac_op; template struct scalar_betainc_op; +template struct scalar_pow_op; template struct scalar_hypot_op; template struct scalar_product_op; template struct scalar_quotient_op; -template struct scalar_binary_pow_op; } // end namespace internal diff --git a/Eigen/src/plugins/ArrayCwiseBinaryOps.h b/Eigen/src/plugins/ArrayCwiseBinaryOps.h index 8bf4e9b18..1e20e35d7 100644 --- a/Eigen/src/plugins/ArrayCwiseBinaryOps.h +++ b/Eigen/src/plugins/ArrayCwiseBinaryOps.h @@ -82,7 +82,26 @@ max * Example: \include Cwise_array_power_array.cpp * Output: \verbinclude Cwise_array_power_array.out */ -EIGEN_MAKE_CWISE_BINARY_OP(pow,binary_pow) +EIGEN_MAKE_CWISE_BINARY_OP(pow,pow) + +#ifndef EIGEN_PARSED_BY_DOXYGEN +EIGEN_MAKE_SCALAR_BINARY_OP_ONTHERIGHT(pow,pow); +#else +/** \returns an expression of the coefficients of \c *this rasied to the constant power \a exponent + * + * \tparam T is the scalar type of \a exponent. It must be compatible with the scalar type of the given expression. + * + * This function computes the coefficient-wise power. The function MatrixBase::pow() in the + * unsupported module MatrixFunctions computes the matrix power. + * + * Example: \include Cwise_pow.cpp + * Output: \verbinclude Cwise_pow.out + * + * \sa ArrayBase::pow(ArrayBase), square(), cube(), exp(), log() + */ +template +const CwiseBinaryOp,Derived,Constant > pow(const T& exponent) const; +#endif // TODO code generating macros could be moved to Macros.h and could include generation of documentation diff --git a/Eigen/src/plugins/ArrayCwiseUnaryOps.h b/Eigen/src/plugins/ArrayCwiseUnaryOps.h index 775fa6ee0..4a6361d8a 100644 --- a/Eigen/src/plugins/ArrayCwiseUnaryOps.h +++ b/Eigen/src/plugins/ArrayCwiseUnaryOps.h @@ -26,7 +26,6 @@ typedef CwiseUnaryOp, const Derived> LgammaRe typedef CwiseUnaryOp, const Derived> DigammaReturnType; typedef CwiseUnaryOp, const Derived> ErfReturnType; typedef CwiseUnaryOp, const Derived> ErfcReturnType; -typedef CwiseUnaryOp, const Derived> PowReturnType; typedef CwiseUnaryOp, const Derived> SquareReturnType; typedef CwiseUnaryOp, const Derived> CubeReturnType; typedef CwiseUnaryOp, const Derived> RoundReturnType; @@ -388,24 +387,6 @@ erfc() const return ErfcReturnType(derived()); } -/** \returns an expression of the coefficient-wise power of *this to the given exponent. - * - * This function computes the coefficient-wise power. The function MatrixBase::pow() in the - * unsupported module MatrixFunctions computes the matrix power. - * - * Example: \include Cwise_pow.cpp - * Output: \verbinclude Cwise_pow.out - * - * \sa exp(), log() - */ -EIGEN_DEVICE_FUNC -inline const PowReturnType -pow(const Scalar& exponent) const -{ - return PowReturnType(derived(), internal::scalar_pow_op(exponent)); -} - - /** \returns an expression of the coefficient-wise inverse of *this. * * Example: \include Cwise_inverse.cpp diff --git a/test/mixingtypes.cpp b/test/mixingtypes.cpp index cf2207114..b38271a17 100644 --- a/test/mixingtypes.cpp +++ b/test/mixingtypes.cpp @@ -23,10 +23,18 @@ #endif +static bool g_called; +#define EIGEN_SCALAR_BINARY_OP_PLUGIN { g_called |= (!internal::is_same::value); } + #include "main.h" using namespace std; +#define VERIFY_MIX_SCALAR(XPR,REF) \ + g_called = false; \ + VERIFY_IS_APPROX(XPR,REF); \ + VERIFY( g_called && #XPR" not properly optimized"); + template void mixingtypes(int size = SizeAtCompileType) { typedef std::complex CF; @@ -66,26 +74,34 @@ template void mixingtypes(int size = SizeAtCompileType) #endif // check scalar products - VERIFY_IS_APPROX(vcf * sf , vcf * complex(sf)); - VERIFY_IS_APPROX(sd * vcd , complex(sd) * vcd); - VERIFY_IS_APPROX(vf * scf , vf.template cast >() * scf); - VERIFY_IS_APPROX(scd * vd , scd * vd.template cast >()); + VERIFY_MIX_SCALAR(vcf * sf , vcf * complex(sf)); + VERIFY_MIX_SCALAR(sd * vcd , complex(sd) * vcd); + VERIFY_MIX_SCALAR(vf * scf , vf.template cast >() * scf); + VERIFY_MIX_SCALAR(scd * vd , scd * vd.template cast >()); // check scalar quotients - VERIFY_IS_APPROX(vcf / sf , vcf / complex(sf)); - VERIFY_IS_APPROX(vf / scf , vf.template cast >() / scf); + VERIFY_MIX_SCALAR(vcf / sf , vcf / complex(sf)); + VERIFY_MIX_SCALAR(vf / scf , vf.template cast >() / scf); // check scalar increment - VERIFY_IS_APPROX(vcf.array() + sf , vcf.array() + complex(sf)); - VERIFY_IS_APPROX(sd + vcd.array(), complex(sd) + vcd.array()); - VERIFY_IS_APPROX(vf.array() + scf, vf.template cast >().array() + scf); - VERIFY_IS_APPROX(scd + vd.array() , scd + vd.template cast >().array()); + VERIFY_MIX_SCALAR(vcf.array() + sf , vcf.array() + complex(sf)); + VERIFY_MIX_SCALAR(sd + vcd.array(), complex(sd) + vcd.array()); + VERIFY_MIX_SCALAR(vf.array() + scf, vf.template cast >().array() + scf); + VERIFY_MIX_SCALAR(scd + vd.array() , scd + vd.template cast >().array()); // check scalar subtractions - VERIFY_IS_APPROX(vcf.array() - sf , vcf.array() - complex(sf)); - VERIFY_IS_APPROX(sd - vcd.array(), complex(sd) - vcd.array()); - VERIFY_IS_APPROX(vf.array() - scf, vf.template cast >().array() - scf); - VERIFY_IS_APPROX(scd - vd.array() , scd - vd.template cast >().array()); + VERIFY_MIX_SCALAR(vcf.array() - sf , vcf.array() - complex(sf)); + VERIFY_MIX_SCALAR(sd - vcd.array(), complex(sd) - vcd.array()); + VERIFY_MIX_SCALAR(vf.array() - scf, vf.template cast >().array() - scf); + VERIFY_MIX_SCALAR(scd - vd.array() , scd - vd.template cast >().array()); + + // check scalar powers + VERIFY_MIX_SCALAR( pow(vcf.array(), sf), pow(vcf.array(), complex(sf)) ); + VERIFY_MIX_SCALAR( vcf.array().pow(sf) , pow(vcf.array(), complex(sf)) ); + VERIFY_MIX_SCALAR( pow(sd, vcd.array()), pow(complex(sd), vcd.array()) ); + VERIFY_MIX_SCALAR( pow(vf.array(), scf), pow(vf.template cast >().array(), scf) ); + VERIFY_MIX_SCALAR( vf.array().pow(scf) , pow(vf.template cast >().array(), scf) ); + VERIFY_MIX_SCALAR( pow(scd, vd.array()), pow(scd, vd.template cast >().array()) ); // check dot product vf.dot(vf); @@ -215,6 +231,9 @@ template void mixingtypes(int size = SizeAtCompileType) VERIFY_IS_APPROX( md.array().pow(mcd.array()), md.template cast().eval().array().pow(mcd.array()) ); VERIFY_IS_APPROX( mcd.array().pow(md.array()), mcd.array().pow(md.template cast().eval().array()) ); + VERIFY_IS_APPROX( pow(md.array(),mcd.array()), md.template cast().eval().array().pow(mcd.array()) ); + VERIFY_IS_APPROX( pow(mcd.array(),md.array()), mcd.array().pow(md.template cast().eval().array()) ); + rcd = mcd; VERIFY_IS_APPROX( rcd = md, md.template cast().eval() ); rcd = mcd; -- cgit v1.2.3 From 70dad84b737374e97319733ebff6f36e86ac384d Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 14 Jun 2016 15:26:37 +0200 Subject: Generalize expr/expr and scalar/expr wrt scalar types. --- Eigen/src/Core/GlobalFunctions.h | 34 +++++++++++++++++++++++++-------- Eigen/src/plugins/ArrayCwiseBinaryOps.h | 4 ++-- test/mixingtypes.cpp | 4 +++- 3 files changed, 31 insertions(+), 11 deletions(-) (limited to 'test/mixingtypes.cpp') diff --git a/Eigen/src/Core/GlobalFunctions.h b/Eigen/src/Core/GlobalFunctions.h index 60e2ccfed..5ffa6c694 100644 --- a/Eigen/src/Core/GlobalFunctions.h +++ b/Eigen/src/Core/GlobalFunctions.h @@ -175,17 +175,35 @@ namespace Eigen #endif /** - * \brief Component-wise division of a scalar by array elements. + * \brief Component-wise division of the scalar \a s by array elements of \a a. + * + * \tparam Scalar is the scalar type of \a x. It must be compatible with the scalar type of the given array expression (\c Derived::Scalar). + * + * \relates ArrayBase **/ - template - inline const Eigen::CwiseUnaryOp, const Derived> - operator/(const typename Derived::Scalar& s, const Eigen::ArrayBase& a) +#ifdef EIGEN_PARSED_BY_DOXYGEN + template + inline const CwiseBinaryOp,Constant,Derived> + operator/(const Scalar& s,const Eigen::ArrayBase& a); +#else + template + inline typename internal::enable_if< !(internal::is_same::value) + && ScalarBinaryOpTraits::Defined, + const EIGEN_SCALAR_BINARYOP_EXPR_RETURN_TYPE(Scalar,Derived,quotient) >::type + operator/(const Scalar& s, const Eigen::ArrayBase& a) { - return Eigen::CwiseUnaryOp, const Derived>( - a.derived(), - Eigen::internal::scalar_inverse_mult_op(s) - ); + return EIGEN_SCALAR_BINARYOP_EXPR_RETURN_TYPE(Scalar,Derived,quotient)( + typename internal::plain_constant_type::type(a.rows(), a.cols(), s), a.derived() ); + } + + template + inline const EIGEN_SCALAR_BINARYOP_EXPR_RETURN_TYPE(typename Derived::Scalar,Derived,quotient) + operator/(const typename Derived::Scalar& s, const Eigen::ArrayBase& a) + { + return EIGEN_SCALAR_BINARYOP_EXPR_RETURN_TYPE(typename Derived::Scalar,Derived,quotient)( + typename internal::plain_constant_type::type(a.rows(), a.cols(), s), a.derived() ); } +#endif /** \cpp11 \returns an expression of the coefficient-wise igamma(\a a, \a x) to the given arrays. * diff --git a/Eigen/src/plugins/ArrayCwiseBinaryOps.h b/Eigen/src/plugins/ArrayCwiseBinaryOps.h index 1e20e35d7..0c1429c75 100644 --- a/Eigen/src/plugins/ArrayCwiseBinaryOps.h +++ b/Eigen/src/plugins/ArrayCwiseBinaryOps.h @@ -17,10 +17,10 @@ operator*(const EIGEN_CURRENT_STORAGE_BASE_CLASS &other) const */ template EIGEN_DEVICE_FUNC -EIGEN_STRONG_INLINE const CwiseBinaryOp, const Derived, const OtherDerived> +EIGEN_STRONG_INLINE const CwiseBinaryOp, const Derived, const OtherDerived> operator/(const EIGEN_CURRENT_STORAGE_BASE_CLASS &other) const { - return CwiseBinaryOp, const Derived, const OtherDerived>(derived(), other.derived()); + return CwiseBinaryOp, const Derived, const OtherDerived>(derived(), other.derived()); } /** \returns an expression of the coefficient-wise min of \c *this and \a other diff --git a/test/mixingtypes.cpp b/test/mixingtypes.cpp index b38271a17..fe8c16470 100644 --- a/test/mixingtypes.cpp +++ b/test/mixingtypes.cpp @@ -82,6 +82,8 @@ template void mixingtypes(int size = SizeAtCompileType) // check scalar quotients VERIFY_MIX_SCALAR(vcf / sf , vcf / complex(sf)); VERIFY_MIX_SCALAR(vf / scf , vf.template cast >() / scf); + VERIFY_MIX_SCALAR(vf.array() / scf, vf.template cast >().array() / scf); + VERIFY_MIX_SCALAR(scd / vd.array() , scd / vd.template cast >().array()); // check scalar increment VERIFY_MIX_SCALAR(vcf.array() + sf , vcf.array() + complex(sf)); @@ -225,7 +227,7 @@ template void mixingtypes(int size = SizeAtCompileType) VERIFY_IS_APPROX( md.array() - mcd.array(), md.template cast().eval().array() - mcd.array() ); VERIFY_IS_APPROX( mcd.array() - md.array(), mcd.array() - md.template cast().eval().array() ); -// VERIFY_IS_APPROX( md.array() / mcd.array(), md.template cast().eval().array() / mcd.array() ); + VERIFY_IS_APPROX( md.array() / mcd.array(), md.template cast().eval().array() / mcd.array() ); VERIFY_IS_APPROX( mcd.array() / md.array(), mcd.array() / md.template cast().eval().array() ); VERIFY_IS_APPROX( md.array().pow(mcd.array()), md.template cast().eval().array().pow(mcd.array()) ); -- cgit v1.2.3 From 76faf4a9657efeed089aeedc98a769410c32d3d7 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Thu, 23 Jun 2016 14:27:20 +0200 Subject: Introduce a NumTraits::Literal type to be used for literals, and improve mixing type support in operations between arrays and scalars: - 2 * ArrayXcf is now optimized in the sense that the integer 2 is properly promoted to a float instead of a complex (fix a regression) - 2.1 * ArrayXi is now forbiden (previously, 2.1 was converted to 2) - This mechanism should be applicable to any custom scalar type, assuming NumTraits::Literal is properly defined (it defaults to T) --- Eigen/src/Core/NumTraits.h | 11 ++++++++--- Eigen/src/Core/util/Macros.h | 30 ++++++++---------------------- Eigen/src/Core/util/XprHelper.h | 28 ++++++++++++++++++++++++++++ test/mixingtypes.cpp | 5 +++++ test/nesting_ops.cpp | 4 ++-- 5 files changed, 51 insertions(+), 27 deletions(-) (limited to 'test/mixingtypes.cpp') diff --git a/Eigen/src/Core/NumTraits.h b/Eigen/src/Core/NumTraits.h index e065fa714..03f64a8e9 100644 --- a/Eigen/src/Core/NumTraits.h +++ b/Eigen/src/Core/NumTraits.h @@ -22,14 +22,16 @@ namespace Eigen { * This class stores enums, typedefs and static methods giving information about a numeric type. * * The provided data consists of: - * \li A typedef \a Real, giving the "real part" type of \a T. If \a T is already real, - * then \a Real is just a typedef to \a T. If \a T is \c std::complex then \a Real + * \li A typedef \c Real, giving the "real part" type of \a T. If \a T is already real, + * then \c Real is just a typedef to \a T. If \a T is \c std::complex then \c Real * is a typedef to \a U. - * \li A typedef \a NonInteger, giving the type that should be used for operations producing non-integral values, + * \li A typedef \c NonInteger, giving the type that should be used for operations producing non-integral values, * such as quotients, square roots, etc. If \a T is a floating-point type, then this typedef just gives * \a T again. Note however that many Eigen functions such as internal::sqrt simply refuse to * take integers. Outside of a few cases, Eigen doesn't do automatic type promotion. Thus, this typedef is * only intended as a helper for code that needs to explicitly promote types. + * \li A typedef \c Literal giving the type to use for numeric literals such as "2" or "0.5". For instance, for \c std::complex, Literal is defined as \c U. + * Of course, this type must be fully compatible with \a T. In doubt, just use \a T here. * \li A typedef \a Nested giving the type to use to nest a value inside of the expression tree. If you don't know what * this means, just use \a T here. * \li An enum value \a IsComplex. It is equal to 1 if \a T is a \c std::complex @@ -84,6 +86,7 @@ template struct GenericNumTraits T >::type NonInteger; typedef T Nested; + typedef T Literal; EIGEN_DEVICE_FUNC static inline Real epsilon() @@ -145,6 +148,7 @@ template struct NumTraits > : GenericNumTraits > { typedef _Real Real; + typedef typename NumTraits<_Real>::Literal Literal; enum { IsComplex = 1, RequireInitialization = NumTraits<_Real>::RequireInitialization, @@ -168,6 +172,7 @@ struct NumTraits > typedef typename NumTraits::NonInteger NonIntegerScalar; typedef Array NonInteger; typedef ArrayType & Nested; + typedef typename NumTraits::Literal Literal; enum { IsComplex = NumTraits::IsComplex, diff --git a/Eigen/src/Core/util/Macros.h b/Eigen/src/Core/util/Macros.h index 87cc44657..6de21d2bb 100644 --- a/Eigen/src/Core/util/Macros.h +++ b/Eigen/src/Core/util/Macros.h @@ -906,35 +906,21 @@ namespace Eigen { const typename internal::plain_constant_type::type, const EXPR> #define EIGEN_MAKE_SCALAR_BINARY_OP_ONTHERIGHT(METHOD,OPNAME) \ - EIGEN_DEVICE_FUNC inline \ - const EIGEN_EXPR_BINARYOP_SCALAR_RETURN_TYPE(Derived,Scalar,OPNAME) \ - (METHOD)(const Scalar& scalar) const { \ - return EIGEN_EXPR_BINARYOP_SCALAR_RETURN_TYPE(Derived,Scalar,OPNAME)(derived(), \ - typename internal::plain_constant_type::type(derived().rows(), derived().cols(), scalar)); \ - } \ - \ template EIGEN_DEVICE_FUNC inline \ - typename internal::enable_if >::Defined, \ - const EIGEN_EXPR_BINARYOP_SCALAR_RETURN_TYPE(Derived,T,OPNAME) >::type \ + const EIGEN_EXPR_BINARYOP_SCALAR_RETURN_TYPE(Derived,typename internal::promote_scalar_arg >::Defined>::type,OPNAME) \ (METHOD)(const T& scalar) const { \ - return EIGEN_EXPR_BINARYOP_SCALAR_RETURN_TYPE(Derived,T,OPNAME)(derived(), \ - typename internal::plain_constant_type::type(derived().rows(), derived().cols(), scalar)); \ + typedef typename internal::promote_scalar_arg >::Defined>::type PromotedT; \ + return EIGEN_EXPR_BINARYOP_SCALAR_RETURN_TYPE(Derived,PromotedT,OPNAME)(derived(), \ + typename internal::plain_constant_type::type(derived().rows(), derived().cols(), internal::scalar_constant_op(scalar))); \ } #define EIGEN_MAKE_SCALAR_BINARY_OP_ONTHELEFT(METHOD,OPNAME) \ - EIGEN_DEVICE_FUNC inline friend \ - const EIGEN_SCALAR_BINARYOP_EXPR_RETURN_TYPE(Scalar,Derived,OPNAME) \ - (METHOD)(const Scalar& scalar, const StorageBaseType& matrix) { \ - return EIGEN_SCALAR_BINARYOP_EXPR_RETURN_TYPE(Scalar,Derived,OPNAME)( \ - typename internal::plain_constant_type::type(matrix.derived().rows(), matrix.derived().cols(), scalar), matrix.derived()); \ - } \ - \ template EIGEN_DEVICE_FUNC inline friend \ - typename internal::enable_if >::Defined, \ - const EIGEN_SCALAR_BINARYOP_EXPR_RETURN_TYPE(T,Derived,OPNAME) >::type \ + const EIGEN_SCALAR_BINARYOP_EXPR_RETURN_TYPE(typename internal::promote_scalar_arg >::Defined>::type,Derived,OPNAME) \ (METHOD)(const T& scalar, const StorageBaseType& matrix) { \ - return EIGEN_SCALAR_BINARYOP_EXPR_RETURN_TYPE(T,Derived,OPNAME)( \ - typename internal::plain_constant_type::type(matrix.derived().rows(), matrix.derived().cols(), scalar), matrix.derived()); \ + typedef typename internal::promote_scalar_arg >::Defined>::type PromotedT; \ + return EIGEN_SCALAR_BINARYOP_EXPR_RETURN_TYPE(PromotedT,Derived,OPNAME)( \ + typename internal::plain_constant_type::type(matrix.derived().rows(), matrix.derived().cols(), internal::scalar_constant_op(scalar)), matrix.derived()); \ } #define EIGEN_MAKE_SCALAR_BINARY_OP(METHOD,OPNAME) \ diff --git a/Eigen/src/Core/util/XprHelper.h b/Eigen/src/Core/util/XprHelper.h index c41c408b0..b372ac1ad 100644 --- a/Eigen/src/Core/util/XprHelper.h +++ b/Eigen/src/Core/util/XprHelper.h @@ -45,6 +45,34 @@ inline IndexDest convert_index(const IndexSrc& idx) { } +// promote_scalar_arg is an helper used in operation between an expression and a scalar, like: +// expression * scalar +// Its role is to determine how the type T of the scalar operand should be promoted given the scalar type ExprScalar of the given expression. +// The IsSupported template parameter must be provided by the caller as: ScalarBinaryOpTraits::Defined using the proper order for ExprScalar and T. +// Then the logic is as follows: +// - if the operation is natively supported as defined by IsSupported, then the scalar type is not promoted, and T is returned. +// - otherwise, NumTraits::Literal is returned if T is implicitly convertible to NumTraits::Literal AND that this does not imply a float to integer conversion. +// - In all other cases, the promoted type is not defined, and the respective operation is thus invalid and not available (SFINAE). +template::Literal>::value, + bool IsSafe = NumTraits::IsInteger || !NumTraits::Literal>::IsInteger> +struct promote_scalar_arg +{ +}; + +template +struct promote_scalar_arg +{ + typedef T type; +}; + +template +struct promote_scalar_arg +{ + typedef typename NumTraits::Literal type; +}; + //classes inheriting no_assignment_operator don't generate a default operator=. class no_assignment_operator { diff --git a/test/mixingtypes.cpp b/test/mixingtypes.cpp index fe8c16470..57ef85c32 100644 --- a/test/mixingtypes.cpp +++ b/test/mixingtypes.cpp @@ -79,6 +79,11 @@ template void mixingtypes(int size = SizeAtCompileType) VERIFY_MIX_SCALAR(vf * scf , vf.template cast >() * scf); VERIFY_MIX_SCALAR(scd * vd , scd * vd.template cast >()); + VERIFY_MIX_SCALAR(vcf * 2 , vcf * complex(2)); + VERIFY_MIX_SCALAR(vcf * 2.1 , vcf * complex(2.1)); + VERIFY_MIX_SCALAR(2 * vcf, vcf * complex(2)); + VERIFY_MIX_SCALAR(2.1 * vcf , vcf * complex(2.1)); + // check scalar quotients VERIFY_MIX_SCALAR(vcf / sf , vcf / complex(sf)); VERIFY_MIX_SCALAR(vf / scf , vf.template cast >() / scf); diff --git a/test/nesting_ops.cpp b/test/nesting_ops.cpp index 2f5025305..a419b0e44 100644 --- a/test/nesting_ops.cpp +++ b/test/nesting_ops.cpp @@ -75,8 +75,8 @@ template void run_nesting_ops_2(const MatrixType& _m) } else { - VERIFY( verify_eval_type<1>(2*m1, 2*m1) ); - VERIFY( verify_eval_type<2>(2*m1, m1) ); + VERIFY( verify_eval_type<2>(2*m1, 2*m1) ); + VERIFY( verify_eval_type<3>(2*m1, m1) ); } VERIFY( verify_eval_type<2>(m1+m1, m1+m1) ); VERIFY( verify_eval_type<3>(m1+m1, m1) ); -- cgit v1.2.3