diff options
-rw-r--r-- | Eigen/src/Core/Assign_MKL.h | 26 | ||||
-rw-r--r-- | Eigen/src/Core/GenericPacketMath.h | 45 | ||||
-rw-r--r-- | Eigen/src/Core/GlobalFunctions.h | 19 | ||||
-rw-r--r-- | Eigen/src/Core/MathFunctions.h | 174 | ||||
-rw-r--r-- | Eigen/src/Core/functors/UnaryFunctors.h | 222 | ||||
-rw-r--r-- | Eigen/src/Core/util/Macros.h | 10 | ||||
-rw-r--r-- | Eigen/src/plugins/ArrayCwiseUnaryOps.h | 206 | ||||
-rw-r--r-- | doc/snippets/Cwise_arg.cpp | 3 | ||||
-rw-r--r-- | doc/snippets/Cwise_boolean_not.cpp | 5 | ||||
-rw-r--r-- | doc/snippets/Cwise_ceil.cpp | 3 | ||||
-rw-r--r-- | doc/snippets/Cwise_cosh.cpp | 2 | ||||
-rw-r--r-- | doc/snippets/Cwise_floor.cpp | 3 | ||||
-rw-r--r-- | doc/snippets/Cwise_isFinite.cpp | 5 | ||||
-rw-r--r-- | doc/snippets/Cwise_isInf.cpp | 5 | ||||
-rw-r--r-- | doc/snippets/Cwise_isNaN.cpp | 5 | ||||
-rw-r--r-- | doc/snippets/Cwise_log10.cpp | 2 | ||||
-rw-r--r-- | doc/snippets/Cwise_round.cpp | 3 | ||||
-rw-r--r-- | doc/snippets/Cwise_sinh.cpp | 2 | ||||
-rw-r--r-- | doc/snippets/Cwise_tanh.cpp | 2 | ||||
-rw-r--r-- | test/array.cpp | 123 | ||||
-rw-r--r-- | test/main.h | 7 | ||||
-rw-r--r-- | test/packetmath.cpp | 10 | ||||
-rw-r--r-- | test/stable_norm.cpp | 40 |
23 files changed, 845 insertions, 77 deletions
diff --git a/Eigen/src/Core/Assign_MKL.h b/Eigen/src/Core/Assign_MKL.h index a7b9e9293..d4ef1d3a4 100644 --- a/Eigen/src/Core/Assign_MKL.h +++ b/Eigen/src/Core/Assign_MKL.h @@ -196,18 +196,26 @@ EIGEN_MKL_VML_SPECIALIZE_ASSIGN(SliceVectorizedTraversal,NoUnrolling) EIGEN_MKL_VML_DECLARE_UNARY_CALLS_COMPLEX_LA(EIGENOP, VMLOP) -EIGEN_MKL_VML_DECLARE_UNARY_CALLS_LA(sin, Sin) -EIGEN_MKL_VML_DECLARE_UNARY_CALLS_LA(asin, Asin) -EIGEN_MKL_VML_DECLARE_UNARY_CALLS_LA(cos, Cos) -EIGEN_MKL_VML_DECLARE_UNARY_CALLS_LA(acos, Acos) -EIGEN_MKL_VML_DECLARE_UNARY_CALLS_LA(tan, Tan) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS_LA(sin, Sin) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS_LA(asin, Asin) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS_LA(sinh, Sinh) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS_LA(cos, Cos) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS_LA(acos, Acos) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS_LA(cosh, Cosh) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS_LA(tan, Tan) EIGEN_MKL_VML_DECLARE_UNARY_CALLS_LA(atan, Atan) -//EIGEN_MKL_VML_DECLARE_UNARY_CALLS(abs, Abs) -EIGEN_MKL_VML_DECLARE_UNARY_CALLS_LA(exp, Exp) -EIGEN_MKL_VML_DECLARE_UNARY_CALLS_LA(log, Ln) -EIGEN_MKL_VML_DECLARE_UNARY_CALLS_LA(sqrt, Sqrt) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS_LA(tanh, Tanh) +//EIGEN_MKL_VML_DECLARE_UNARY_CALLS(abs, Abs) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS_LA(exp, Exp) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS_LA(log, Ln) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS_LA(log10, Log10) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS(sqrt, Sqrt) EIGEN_MKL_VML_DECLARE_UNARY_CALLS_REAL(square, Sqr) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS_COMPLEX(arg, Arg) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS_REAL(round, Round) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS_REAL(floor, Floor) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS_REAL(ceil, Ceil) // The vm*powx functions are not avaibale in the windows version of MKL. #ifndef _WIN32 diff --git a/Eigen/src/Core/GenericPacketMath.h b/Eigen/src/Core/GenericPacketMath.h index 77941c059..8a7a0eddc 100644 --- a/Eigen/src/Core/GenericPacketMath.h +++ b/Eigen/src/Core/GenericPacketMath.h @@ -49,6 +49,7 @@ struct default_packet_traits HasMul = 1, HasNegate = 1, HasAbs = 1, + HasArg = 0, HasAbs2 = 1, HasMin = 1, HasMax = 1, @@ -61,6 +62,7 @@ struct default_packet_traits HasRsqrt = 0, HasExp = 0, HasLog = 0, + HasLog10 = 0, HasPow = 0, HasSin = 0, @@ -68,7 +70,14 @@ struct default_packet_traits HasTan = 0, HasASin = 0, HasACos = 0, - HasATan = 0 + HasATan = 0, + HasSinh = 0, + HasCosh = 0, + HasTanh = 0, + + HasRound = 0, + HasFloor = 0, + HasCeil = 0 }; }; @@ -163,6 +172,10 @@ pmax(const Packet& a, template<typename Packet> EIGEN_DEVICE_FUNC inline Packet pabs(const Packet& a) { using std::abs; return abs(a); } +/** \internal \returns the phase angle of \a a */ +template<typename Packet> EIGEN_DEVICE_FUNC inline Packet +parg(const Packet& a) { using numext::arg; return arg(a); } + /** \internal \returns the bitwise and of \a a and \a b */ template<typename Packet> EIGEN_DEVICE_FUNC inline Packet pand(const Packet& a, const Packet& b) { return a & b; } @@ -359,10 +372,22 @@ Packet pasin(const Packet& a) { using std::asin; return asin(a); } template<typename Packet> EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS Packet pacos(const Packet& a) { using std::acos; return acos(a); } -/** \internal \returns the atan of \a a (coeff-wise) */ +/** \internal \returns the arc tangent of \a a (coeff-wise) */ template<typename Packet> EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS Packet patan(const Packet& a) { using std::atan; return atan(a); } +/** \internal \returns the hyperbolic sine of \a a (coeff-wise) */ +template<typename Packet> EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS +Packet psinh(const Packet& a) { using std::sinh; return sinh(a); } + +/** \internal \returns the hyperbolic cosine of \a a (coeff-wise) */ +template<typename Packet> EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS +Packet pcosh(const Packet& a) { using std::cosh; return cosh(a); } + +/** \internal \returns the hyperbolic tan of \a a (coeff-wise) */ +template<typename Packet> EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS +Packet ptanh(const Packet& a) { using std::tanh; return tanh(a); } + /** \internal \returns the exp of \a a (coeff-wise) */ template<typename Packet> EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS Packet pexp(const Packet& a) { using std::exp; return exp(a); } @@ -371,6 +396,10 @@ Packet pexp(const Packet& a) { using std::exp; return exp(a); } template<typename Packet> EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS Packet plog(const Packet& a) { using std::log; return log(a); } +/** \internal \returns the log10 of \a a (coeff-wise) */ +template<typename Packet> EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS +Packet plog10(const Packet& a) { using std::log10; return log10(a); } + /** \internal \returns the square-root of \a a (coeff-wise) */ template<typename Packet> EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS Packet psqrt(const Packet& a) { using std::sqrt; return sqrt(a); } @@ -381,6 +410,18 @@ Packet prsqrt(const Packet& a) { return pdiv(pset1<Packet>(1), psqrt(a)); } +/** \internal \returns the rounded value of \a a (coeff-wise) */ +template<typename Packet> EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS +Packet pround(const Packet& a) { using numext::round; return round(a); } + +/** \internal \returns the floor of \a a (coeff-wise) */ +template<typename Packet> EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS +Packet pfloor(const Packet& a) { using numext::floor; return floor(a); } + +/** \internal \returns the ceil of \a a (coeff-wise) */ +template<typename Packet> EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS +Packet pceil(const Packet& a) { using numext::ceil; return ceil(a); } + /*************************************************************************** * The following functions might not have to be overwritten for vectorized types ***************************************************************************/ diff --git a/Eigen/src/Core/GlobalFunctions.h b/Eigen/src/Core/GlobalFunctions.h index ee67b7d3c..1924c8e5f 100644 --- a/Eigen/src/Core/GlobalFunctions.h +++ b/Eigen/src/Core/GlobalFunctions.h @@ -40,16 +40,31 @@ namespace Eigen EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(real,scalar_real_op) EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(imag,scalar_imag_op) EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(conj,scalar_conjugate_op) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(inverse,scalar_inverse_op) EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(sin,scalar_sin_op) EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(cos,scalar_cos_op) - EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(asin,scalar_asin_op) - EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(acos,scalar_acos_op) EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(tan,scalar_tan_op) EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(atan,scalar_atan_op) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(asin,scalar_asin_op) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(acos,scalar_acos_op) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(sinh,scalar_sinh_op) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(cosh,scalar_cosh_op) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(tanh,scalar_tanh_op) EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(exp,scalar_exp_op) EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(log,scalar_log_op) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(log10,scalar_log10_op) EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(abs,scalar_abs_op) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(abs2,scalar_abs2_op) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(arg,scalar_arg_op) EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(sqrt,scalar_sqrt_op) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(square,scalar_square_op) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(cube,scalar_cube_op) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(round,scalar_round_op) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(floor,scalar_floor_op) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(ceil,scalar_ceil_op) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(isNaN,scalar_isNaN_op) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(isInf,scalar_isInf_op) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(isFinite,scalar_isFinite_op) template<typename Derived> inline const Eigen::CwiseUnaryOp<Eigen::internal::scalar_pow_op<typename Derived::Scalar>, const Derived> diff --git a/Eigen/src/Core/MathFunctions.h b/Eigen/src/Core/MathFunctions.h index 3c240c272..1ce935909 100644 --- a/Eigen/src/Core/MathFunctions.h +++ b/Eigen/src/Core/MathFunctions.h @@ -361,7 +361,94 @@ inline NewType cast(const OldType& x) } /**************************************************************************** -* Implementation of logp1 * +* Implementation of round * +****************************************************************************/ +// In C++11 we can specialize round_impl for real Scalars +// Let's be conservative and enable the default C++11 implementation only if we are sure it exists +#if (__cplusplus >= 201103L) && (EIGEN_COMP_GNUC_STRICT || EIGEN_COMP_CLANG || EIGEN_COMP_MSVC || EIGEN_COMP_ICC) \ + && (EIGEN_ARCH_i386_OR_x86_64) && (EIGEN_OS_GNULINUX || EIGEN_OS_WIN_STRICT || EIGEN_OS_MAC) + template<typename Scalar> + struct round_impl { + static inline Scalar run(const Scalar& x) + { + EIGEN_STATIC_ASSERT((!NumTraits<Scalar>::IsComplex), NUMERIC_TYPE_MUST_BE_REAL) + using std::round; + return round(x); + } + }; +// No C++11, use our own implementation +#else + template<typename Scalar> + struct round_impl + { + static inline Scalar run(const Scalar& x) + { + EIGEN_STATIC_ASSERT((!NumTraits<Scalar>::IsComplex), NUMERIC_TYPE_MUST_BE_REAL) + using std::floor; + using std::ceil; + return (x > 0.0) ? floor(x + 0.5) : ceil(x - 0.5); + } + }; +#endif + +template<typename Scalar> +struct round_retval +{ + typedef Scalar type; +}; + +/**************************************************************************** +* Implementation of arg * +****************************************************************************/ +// In C++11 we can specialize arg_impl for all Scalars +// Let's be conservative and enable the default C++11 implementation only if we are sure it exists +#if (__cplusplus >= 201103L) && (EIGEN_COMP_GNUC_STRICT || EIGEN_COMP_CLANG || EIGEN_COMP_MSVC || EIGEN_COMP_ICC) \ + && (EIGEN_ARCH_i386_OR_x86_64) && (EIGEN_OS_GNULINUX || EIGEN_OS_WIN_STRICT || EIGEN_OS_MAC) + template<typename Scalar> + struct arg_impl { + static inline Scalar run(const Scalar& x) + { + using std::arg; + return arg(x); + } + }; + +// No C++11, use our own implementation for real Scalars +#else + template<typename Scalar, bool IsComplex = NumTraits<Scalar>::IsComplex> + struct arg_default_impl + { + typedef typename NumTraits<Scalar>::Real RealScalar; + EIGEN_DEVICE_FUNC + static inline RealScalar run(const Scalar& x) + { + const double pi = std::acos(-1.0); + return (x < 0.0) ? pi : 0.0; } + }; + + template<typename Scalar> + struct arg_default_impl<Scalar,true> + { + typedef typename NumTraits<Scalar>::Real RealScalar; + EIGEN_DEVICE_FUNC + static inline RealScalar run(const Scalar& x) + { + using std::arg; + return arg(x); + } + }; + + template<typename Scalar> struct arg_impl : arg_default_impl<Scalar> {}; +#endif + +template<typename Scalar> +struct arg_retval +{ + typedef typename NumTraits<Scalar>::Real type; +}; + +/**************************************************************************** +* Implementation of log1p * ****************************************************************************/ template<typename Scalar, bool isComplex = NumTraits<Scalar>::IsComplex > struct log1p_impl @@ -588,7 +675,7 @@ inline EIGEN_MATHFUNC_RETVAL(random, Scalar) random() } // end namespace internal /**************************************************************************** -* Generic math function * +* Generic math functions * ****************************************************************************/ namespace numext { @@ -639,6 +726,13 @@ inline EIGEN_MATHFUNC_RETVAL(imag, Scalar) imag(const Scalar& x) template<typename Scalar> EIGEN_DEVICE_FUNC +inline EIGEN_MATHFUNC_RETVAL(arg, Scalar) arg(const Scalar& x) +{ + return EIGEN_MATHFUNC_IMPL(arg, Scalar)::run(x); +} + +template<typename Scalar> +EIGEN_DEVICE_FUNC inline typename internal::add_const_on_value_type< EIGEN_MATHFUNC_RETVAL(imag_ref, Scalar) >::type imag_ref(const Scalar& x) { return internal::imag_ref_impl<Scalar>::run(x); @@ -693,13 +787,16 @@ inline EIGEN_MATHFUNC_RETVAL(pow, Scalar) pow(const Scalar& x, const Scalar& y) return EIGEN_MATHFUNC_IMPL(pow, Scalar)::run(x, y); } -// std::isfinite is non standard, so let's define our own version, -// even though it is not very efficient. template<typename T> EIGEN_DEVICE_FUNC bool (isfinite)(const T& x) { - return x<NumTraits<T>::highest() && x>NumTraits<T>::lowest(); + #ifdef EIGEN_HAS_C99_MATH + using std::isfinite; + return isfinite(x); + #else + return x<NumTraits<T>::highest() && x>NumTraits<T>::lowest(); + #endif } template<typename T> @@ -711,6 +808,73 @@ bool (isfinite)(const std::complex<T>& x) return isfinite(real(x)) && isfinite(imag(x)); } +template<typename T> +EIGEN_DEVICE_FUNC +bool (isNaN)(const T& x) +{ + #ifdef EIGEN_HAS_C99_MATH + using std::isnan; + return isnan(x); + #else + return x != x; + #endif +} + +template<typename T> +EIGEN_DEVICE_FUNC +bool (isNaN)(const std::complex<T>& x) +{ + using std::real; + using std::imag; + using std::isnan; + return isnan(real(x)) || isnan(imag(x)); +} + +template<typename T> +EIGEN_DEVICE_FUNC +bool (isInf)(const T& x) +{ + #ifdef EIGEN_HAS_C99_MATH + using std::isinf; + return isinf(x); + #else + return x>NumTraits<T>::highest() || x<NumTraits<T>::lowest(); + #endif +} + +template<typename T> +EIGEN_DEVICE_FUNC +bool (isInf)(const std::complex<T>& x) +{ + using std::real; + using std::imag; + using std::isinf; + return isinf(real(x)) || isinf(imag(x)); +} + +template<typename Scalar> +EIGEN_DEVICE_FUNC +inline EIGEN_MATHFUNC_RETVAL(round, Scalar) round(const Scalar& x) +{ + return EIGEN_MATHFUNC_IMPL(round, Scalar)::run(x); +} + +template<typename T> +EIGEN_DEVICE_FUNC +T (floor)(const T& x) +{ + using std::floor; + return floor(x); +} + +template<typename T> +EIGEN_DEVICE_FUNC +T (ceil)(const T& x) +{ + using std::ceil; + return ceil(x); +} + // Log base 2 for 32 bits positive integers. // Conveniently returns 0 for x==0. inline int log2(int x) diff --git a/Eigen/src/Core/functors/UnaryFunctors.h b/Eigen/src/Core/functors/UnaryFunctors.h index 4e03761ea..a6fa5ee31 100644 --- a/Eigen/src/Core/functors/UnaryFunctors.h +++ b/Eigen/src/Core/functors/UnaryFunctors.h @@ -123,6 +123,27 @@ struct functor_traits<scalar_conjugate_op<Scalar> > }; /** \internal + * \brief Template functor to compute the phase angle of a complex + * + * \sa class CwiseUnaryOp, Cwise::arg + */ +template<typename Scalar> struct scalar_arg_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_arg_op) + typedef typename NumTraits<Scalar>::Real result_type; + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const result_type operator() (const Scalar& a) const { using numext::arg; return arg(a); } + template<typename Packet> + EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a) const + { return internal::parg(a); } +}; +template<typename Scalar> +struct functor_traits<scalar_arg_op<Scalar> > +{ + enum { + Cost = NumTraits<Scalar>::IsComplex ? 5 * NumTraits<Scalar>::MulCost : NumTraits<Scalar>::AddCost, + PacketAccess = packet_traits<Scalar>::HasArg + }; +}; +/** \internal * \brief Template functor to cast a scalar to another type * * \sa class CwiseUnaryOp, MatrixBase::cast() @@ -233,6 +254,21 @@ template<typename Scalar> struct functor_traits<scalar_log_op<Scalar> > { enum { Cost = 5 * NumTraits<Scalar>::MulCost, PacketAccess = packet_traits<Scalar>::HasLog }; }; +/** \internal + * + * \brief Template functor to compute the base-10 logarithm of a scalar + * + * \sa class CwiseUnaryOp, Cwise::log10() + */ +template<typename Scalar> struct scalar_log10_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_log10_op) + EIGEN_DEVICE_FUNC inline const Scalar operator() (const Scalar& a) const { using std::log10; return log10(a); } + typedef typename packet_traits<Scalar>::type Packet; + inline Packet packetOp(const Packet& a) const { return internal::plog10(a); } +}; +template<typename Scalar> +struct functor_traits<scalar_log10_op<Scalar> > +{ enum { Cost = 5 * NumTraits<Scalar>::MulCost, PacketAccess = packet_traits<Scalar>::HasLog10 }; }; /** \internal * \brief Template functor to compute the square root of a scalar @@ -367,7 +403,6 @@ struct functor_traits<scalar_asin_op<Scalar> > }; }; - /** \internal * \brief Template functor to compute the atan of a scalar * \sa class CwiseUnaryOp, ArrayBase::atan() @@ -388,6 +423,63 @@ struct functor_traits<scalar_atan_op<Scalar> > }; /** \internal + * \brief Template functor to compute the tanh of a scalar + * \sa class CwiseUnaryOp, ArrayBase::tanh() + */ +template<typename Scalar> struct scalar_tanh_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_tanh_op) + inline const Scalar operator() (const Scalar& a) const { using std::tanh; return tanh(a); } + typedef typename packet_traits<Scalar>::type Packet; + inline Packet packetOp(const Packet& a) const { return internal::ptanh(a); } +}; +template<typename Scalar> +struct functor_traits<scalar_tanh_op<Scalar> > +{ + enum { + Cost = 5 * NumTraits<Scalar>::MulCost, + PacketAccess = packet_traits<Scalar>::HasTanh + }; +}; + +/** \internal + * \brief Template functor to compute the sinh of a scalar + * \sa class CwiseUnaryOp, ArrayBase::sinh() + */ +template<typename Scalar> struct scalar_sinh_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_sinh_op) + inline const Scalar operator() (const Scalar& a) const { using std::sinh; return sinh(a); } + typedef typename packet_traits<Scalar>::type Packet; + inline Packet packetOp(const Packet& a) const { return internal::psinh(a); } +}; +template<typename Scalar> +struct functor_traits<scalar_sinh_op<Scalar> > +{ + enum { + Cost = 5 * NumTraits<Scalar>::MulCost, + PacketAccess = packet_traits<Scalar>::HasSinh + }; +}; + +/** \internal + * \brief Template functor to compute the cosh of a scalar + * \sa class CwiseUnaryOp, ArrayBase::cosh() + */ +template<typename Scalar> struct scalar_cosh_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_cosh_op) + inline const Scalar operator() (const Scalar& a) const { using std::cosh; return cosh(a); } + typedef typename packet_traits<Scalar>::type Packet; + inline Packet packetOp(const Packet& a) const { return internal::pcosh(a); } +}; +template<typename Scalar> +struct functor_traits<scalar_cosh_op<Scalar> > +{ + enum { + Cost = 5 * NumTraits<Scalar>::MulCost, + PacketAccess = packet_traits<Scalar>::HasCosh + }; +}; + +/** \internal * \brief Template functor to compute the inverse of a scalar * \sa class CwiseUnaryOp, Cwise::inverse() */ @@ -435,6 +527,134 @@ template<typename Scalar> struct functor_traits<scalar_cube_op<Scalar> > { enum { Cost = 2*NumTraits<Scalar>::MulCost, PacketAccess = packet_traits<Scalar>::HasMul }; }; +/** \internal + * \brief Template functor to compute the rounded value of a scalar + * \sa class CwiseUnaryOp, ArrayBase::round() + */ +template<typename Scalar> struct scalar_round_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_round_op) + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar operator() (const Scalar& a) const { using numext::round; return round(a); } + typedef typename packet_traits<Scalar>::type Packet; + inline Packet packetOp(const Packet& a) const { return internal::pround(a); } +}; +template<typename Scalar> +struct functor_traits<scalar_round_op<Scalar> > +{ + enum { + Cost = NumTraits<Scalar>::MulCost, + PacketAccess = packet_traits<Scalar>::HasRound + }; +}; + +/** \internal + * \brief Template functor to compute the floor of a scalar + * \sa class CwiseUnaryOp, ArrayBase::floor() + */ +template<typename Scalar> struct scalar_floor_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_floor_op) + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar operator() (const Scalar& a) const { return numext::floor(a); } + typedef typename packet_traits<Scalar>::type Packet; + inline Packet packetOp(const Packet& a) const { return internal::pfloor(a); } +}; +template<typename Scalar> +struct functor_traits<scalar_floor_op<Scalar> > +{ + enum { + Cost = NumTraits<Scalar>::MulCost, + PacketAccess = packet_traits<Scalar>::HasFloor + }; +}; + +/** \internal + * \brief Template functor to compute the ceil of a scalar + * \sa class CwiseUnaryOp, ArrayBase::ceil() + */ +template<typename Scalar> struct scalar_ceil_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_ceil_op) + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar operator() (const Scalar& a) const { return numext::ceil(a); } + typedef typename packet_traits<Scalar>::type Packet; + inline Packet packetOp(const Packet& a) const { return internal::pceil(a); } +}; +template<typename Scalar> +struct functor_traits<scalar_ceil_op<Scalar> > +{ + enum { + Cost = NumTraits<Scalar>::MulCost, + PacketAccess = packet_traits<Scalar>::HasCeil + }; +}; + +/** \internal + * \brief Template functor to compute whether a scalar is NaN + * \sa class CwiseUnaryOp, ArrayBase::isNaN() + */ +template<typename Scalar> struct scalar_isNaN_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_isNaN_op) + typedef bool result_type; + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type operator() (const Scalar& a) const { return numext::isNaN(a); } +}; +template<typename Scalar> +struct functor_traits<scalar_isNaN_op<Scalar> > +{ + enum { + Cost = NumTraits<Scalar>::MulCost, + PacketAccess = false + }; +}; + +/** \internal + * \brief Template functor to compute the isInf of a scalar + * \sa class CwiseUnaryOp, ArrayBase::isInf() + */ +template<typename Scalar> struct scalar_isInf_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_isInf_op) + typedef bool result_type; + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type operator() (const Scalar& a) const { return numext::isInf(a); } +}; +template<typename Scalar> +struct functor_traits<scalar_isInf_op<Scalar> > +{ + enum { + Cost = NumTraits<Scalar>::MulCost, + PacketAccess = false + }; +}; + +/** \internal + * \brief Template functor to compute the isFinite of a scalar + * \sa class CwiseUnaryOp, ArrayBase::isFinite() + */ +template<typename Scalar> struct scalar_isFinite_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_isFinite_op) + typedef bool result_type; + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type operator() (const Scalar& a) const { return numext::isfinite(a); } +}; +template<typename Scalar> +struct functor_traits<scalar_isFinite_op<Scalar> > +{ + enum { + Cost = NumTraits<Scalar>::MulCost, + PacketAccess = false + }; +}; + +/** \internal + * \brief Template functor to compute the logical not of a boolean + * + * \sa class CwiseUnaryOp, ArrayBase::operator! + */ +template<typename Scalar> struct scalar_boolean_not_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_boolean_not_op) + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool operator() (const bool& a) const { return !a; } +}; +template<typename Scalar> +struct functor_traits<scalar_boolean_not_op<Scalar> > { + enum { + Cost = NumTraits<bool>::AddCost, + PacketAccess = false + }; +}; + } // end namespace internal diff --git a/Eigen/src/Core/util/Macros.h b/Eigen/src/Core/util/Macros.h index e9754607b..4eeb8211c 100644 --- a/Eigen/src/Core/util/Macros.h +++ b/Eigen/src/Core/util/Macros.h @@ -415,6 +415,16 @@ #define EIGEN_HAS_CONSTEXPR 1 #endif +// Does the compiler support C99 math? +#if (__cplusplus >= 201103L) && (EIGEN_COMP_GNUC_STRICT || EIGEN_COMP_CLANG || EIGEN_COMP_MSVC || EIGEN_COMP_ICC) \ + && (EIGEN_ARCH_i386_OR_x86_64) && (EIGEN_OS_GNULINUX || EIGEN_OS_WIN_STRICT || EIGEN_OS_MAC) || \ + (EIGEN_COMP_GNUC_STRICT || \ + (EIGEN_COMP_ICC && EIGEN_COMP_GNUC) || \ + (EIGEN_COMP_CLANG) || \ + (EIGEN_COMP_MSVC >= 1800)) +#define EIGEN_HAS_C99_MATH 1 +#endif + /** Allows to disable some optimizations which might affect the accuracy of the result. * Such optimization are enabled by default, and set EIGEN_FAST_MATH to 0 to disable them. * They currently include: diff --git a/Eigen/src/plugins/ArrayCwiseUnaryOps.h b/Eigen/src/plugins/ArrayCwiseUnaryOps.h index 3d4693fd1..c9f7c8f6e 100644 --- a/Eigen/src/plugins/ArrayCwiseUnaryOps.h +++ b/Eigen/src/plugins/ArrayCwiseUnaryOps.h @@ -1,21 +1,33 @@ typedef CwiseUnaryOp<internal::scalar_abs_op<Scalar>, const Derived> AbsReturnType; +typedef CwiseUnaryOp<internal::scalar_arg_op<Scalar>, const Derived> ArgReturnType; typedef CwiseUnaryOp<internal::scalar_abs2_op<Scalar>, const Derived> Abs2ReturnType; typedef CwiseUnaryOp<internal::scalar_sqrt_op<Scalar>, const Derived> SqrtReturnType; typedef CwiseUnaryOp<internal::scalar_inverse_op<Scalar>, const Derived> InverseReturnType; +typedef CwiseUnaryOp<internal::scalar_boolean_not_op<Scalar>, const Derived> BooleanNotReturnType; typedef CwiseUnaryOp<internal::scalar_exp_op<Scalar>, const Derived> ExpReturnType; typedef CwiseUnaryOp<internal::scalar_log_op<Scalar>, const Derived> LogReturnType; +typedef CwiseUnaryOp<internal::scalar_log10_op<Scalar>, const Derived> Log10ReturnType; typedef CwiseUnaryOp<internal::scalar_cos_op<Scalar>, const Derived> CosReturnType; typedef CwiseUnaryOp<internal::scalar_sin_op<Scalar>, const Derived> SinReturnType; +typedef CwiseUnaryOp<internal::scalar_tan_op<Scalar>, const Derived> TanReturnType; typedef CwiseUnaryOp<internal::scalar_acos_op<Scalar>, const Derived> AcosReturnType; typedef CwiseUnaryOp<internal::scalar_asin_op<Scalar>, const Derived> AsinReturnType; -typedef CwiseUnaryOp<internal::scalar_tan_op<Scalar>, const Derived> TanReturnType; typedef CwiseUnaryOp<internal::scalar_atan_op<Scalar>, const Derived> AtanReturnType; +typedef CwiseUnaryOp<internal::scalar_tanh_op<Scalar>, const Derived> TanhReturnType; +typedef CwiseUnaryOp<internal::scalar_sinh_op<Scalar>, const Derived> SinhReturnType; +typedef CwiseUnaryOp<internal::scalar_cosh_op<Scalar>, const Derived> CoshReturnType; typedef CwiseUnaryOp<internal::scalar_pow_op<Scalar>, const Derived> PowReturnType; typedef CwiseUnaryOp<internal::scalar_square_op<Scalar>, const Derived> SquareReturnType; typedef CwiseUnaryOp<internal::scalar_cube_op<Scalar>, const Derived> CubeReturnType; +typedef CwiseUnaryOp<internal::scalar_round_op<Scalar>, const Derived> RoundReturnType; +typedef CwiseUnaryOp<internal::scalar_floor_op<Scalar>, const Derived> FloorReturnType; +typedef CwiseUnaryOp<internal::scalar_ceil_op<Scalar>, const Derived> CeilReturnType; +typedef CwiseUnaryOp<internal::scalar_isNaN_op<Scalar>, const Derived> IsNaNReturnType; +typedef CwiseUnaryOp<internal::scalar_isInf_op<Scalar>, const Derived> IsInfReturnType; +typedef CwiseUnaryOp<internal::scalar_isFinite_op<Scalar>, const Derived> IsFiniteReturnType; /** \returns an expression of the coefficient-wise absolute value of \c *this * @@ -31,6 +43,20 @@ abs() const return AbsReturnType(derived()); } +/** \returns an expression of the coefficient-wise phase angle of \c *this + * + * Example: \include Cwise_arg.cpp + * Output: \verbinclude Cwise_arg.out + * + * \sa abs() + */ +EIGEN_DEVICE_FUNC +EIGEN_STRONG_INLINE const ArgReturnType +arg() const +{ + return ArgReturnType(derived()); +} + /** \returns an expression of the coefficient-wise squared absolute value of \c *this * * Example: \include Cwise_abs2.cpp @@ -79,6 +105,22 @@ log() const return LogReturnType(derived()); } +/** \returns an expression of the coefficient-wise base-10 logarithm of *this. + * + * This function computes the coefficient-wise base-10 logarithm. + * + * Example: \include Cwise_log10.cpp + * Output: \verbinclude Cwise_log10.out + * + * \sa log() + */ +EIGEN_DEVICE_FUNC +inline const Log10ReturnType +log10() const +{ + return Log10ReturnType(derived()); +} + /** \returns an expression of the coefficient-wise square root of *this. * * This function computes the coefficient-wise square root. The function MatrixBase::sqrt() in the @@ -131,6 +173,33 @@ sin() const return SinReturnType(derived()); } +/** \returns an expression of the coefficient-wise tan of *this. + * + * Example: \include Cwise_tan.cpp + * Output: \verbinclude Cwise_tan.out + * + * \sa cos(), sin() + */ +EIGEN_DEVICE_FUNC +inline const TanReturnType +tan() const +{ + return TanReturnType(derived()); +} + +/** \returns an expression of the coefficient-wise arc tan of *this. + * + * Example: \include Cwise_atan.cpp + * Output: \verbinclude Cwise_atan.out + * + * \sa tan(), asin(), acos() + */ +inline const AtanReturnType +atan() const +{ + return AtanReturnType(derived()); +} + /** \returns an expression of the coefficient-wise arc cosine of *this. * * Example: \include Cwise_acos.cpp @@ -159,31 +228,43 @@ asin() const return AsinReturnType(derived()); } -/** \returns an expression of the coefficient-wise tan of *this. +/** \returns an expression of the coefficient-wise hyperbolic tan of *this. * - * Example: \include Cwise_tan.cpp - * Output: \verbinclude Cwise_tan.out + * Example: \include Cwise_tanh.cpp + * Output: \verbinclude Cwise_tanh.out * - * \sa cos(), sin() + * \sa tan(), sinh(), cosh() */ -EIGEN_DEVICE_FUNC -inline const TanReturnType -tan() const +inline const TanhReturnType +tanh() const { - return TanReturnType(derived()); + return TanhReturnType(derived()); } -/** \returns an expression of the coefficient-wise arc tan of *this. +/** \returns an expression of the coefficient-wise hyperbolic sin of *this. * - * Example: \include Cwise_atan.cpp - * Output: \verbinclude Cwise_atan.out + * Example: \include Cwise_sinh.cpp + * Output: \verbinclude Cwise_sinh.out * - * \sa cos(), sin(), tan() + * \sa sin(), tanh(), cosh() */ -inline const AtanReturnType -atan() const +inline const SinhReturnType +sinh() const { - return AtanReturnType(derived()); + return SinhReturnType(derived()); +} + +/** \returns an expression of the coefficient-wise hyperbolic cos of *this. + * + * Example: \include Cwise_cosh.cpp + * Output: \verbinclude Cwise_cosh.out + * + * \sa tan(), sinh(), cosh() + */ +inline const CoshReturnType +cosh() const +{ + return CoshReturnType(derived()); } /** \returns an expression of the coefficient-wise power of *this to the given exponent. @@ -246,5 +327,98 @@ cube() const return CubeReturnType(derived()); } +/** \returns an expression of the coefficient-wise round of *this. + * + * Example: \include Cwise_round.cpp + * Output: \verbinclude Cwise_round.out + * + * \sa ceil(), floor() + */ +inline const RoundReturnType +round() const +{ + return RoundReturnType(derived()); +} + +/** \returns an expression of the coefficient-wise floor of *this. + * + * Example: \include Cwise_floor.cpp + * Output: \verbinclude Cwise_floor.out + * + * \sa ceil(), round() + */ +inline const FloorReturnType +floor() const +{ + return FloorReturnType(derived()); +} + +/** \returns an expression of the coefficient-wise ceil of *this. + * + * Example: \include Cwise_ceil.cpp + * Output: \verbinclude Cwise_ceil.out + * + * \sa floor(), round() + */ +inline const CeilReturnType +ceil() const +{ + return CeilReturnType(derived()); +} + +/** \returns an expression of the coefficient-wise isNaN of *this. + * + * Example: \include Cwise_isNaN.cpp + * Output: \verbinclude Cwise_isNaN.out + * + * \sa isFinite(), isInf() + */ +inline const IsNaNReturnType +isNaN() const +{ + return IsNaNReturnType(derived()); +} + +/** \returns an expression of the coefficient-wise isInf of *this. + * + * Example: \include Cwise_isInf.cpp + * Output: \verbinclude Cwise_isInf.out + * + * \sa isNaN(), isFinite() + */ +inline const IsInfReturnType +isInf() const +{ + return IsInfReturnType(derived()); +} +/** \returns an expression of the coefficient-wise isFinite of *this. + * + * Example: \include Cwise_isFinite.cpp + * Output: \verbinclude Cwise_isFinite.out + * + * \sa isNaN(), isInf() + */ +inline const IsFiniteReturnType +isFinite() const +{ + return IsFiniteReturnType(derived()); +} +/** \returns an expression of the coefficient-wise ! operator of *this + * + * \warning this operator is for expression of bool only. + * + * Example: \include Cwise_boolean_not.cpp + * Output: \verbinclude Cwise_boolean_not.out + * + * \sa operator!=() + */ +EIGEN_DEVICE_FUNC +inline const BooleanNotReturnType +operator!() const +{ + EIGEN_STATIC_ASSERT((internal::is_same<bool,Scalar>::value), + THIS_METHOD_IS_ONLY_FOR_EXPRESSIONS_OF_BOOL); + return BooleanNotReturnType(derived()); +} diff --git a/doc/snippets/Cwise_arg.cpp b/doc/snippets/Cwise_arg.cpp new file mode 100644 index 000000000..3f45133b6 --- /dev/null +++ b/doc/snippets/Cwise_arg.cpp @@ -0,0 +1,3 @@ +ArrayXcf v = ArrayXcf::Random(3); +cout << v << endl << endl; +cout << arg(v) << endl; diff --git a/doc/snippets/Cwise_boolean_not.cpp b/doc/snippets/Cwise_boolean_not.cpp new file mode 100644 index 000000000..8b8e6fc95 --- /dev/null +++ b/doc/snippets/Cwise_boolean_not.cpp @@ -0,0 +1,5 @@ +Array3d v(1,2,3); +v(1) *= 0.0/0.0; +v(2) /= 0.0; +cout << v << endl << endl; +cout << !isFinite(v) << endl; diff --git a/doc/snippets/Cwise_ceil.cpp b/doc/snippets/Cwise_ceil.cpp new file mode 100644 index 000000000..76cf661f4 --- /dev/null +++ b/doc/snippets/Cwise_ceil.cpp @@ -0,0 +1,3 @@ +ArrayXd v = ArrayXd::LinSpaced(7,-2,2); +cout << v << endl << endl; +cout << ceil(v) << endl; diff --git a/doc/snippets/Cwise_cosh.cpp b/doc/snippets/Cwise_cosh.cpp new file mode 100644 index 000000000..80ee75da5 --- /dev/null +++ b/doc/snippets/Cwise_cosh.cpp @@ -0,0 +1,2 @@ +ArrayXd v = ArrayXd::LinSpaced(5,0,1); +cout << cosh(v) << endl; diff --git a/doc/snippets/Cwise_floor.cpp b/doc/snippets/Cwise_floor.cpp new file mode 100644 index 000000000..73756b41c --- /dev/null +++ b/doc/snippets/Cwise_floor.cpp @@ -0,0 +1,3 @@ +ArrayXd v = ArrayXd::LinSpaced(7,-2,2); +cout << v << endl << endl; +cout << floor(v) << endl; diff --git a/doc/snippets/Cwise_isFinite.cpp b/doc/snippets/Cwise_isFinite.cpp new file mode 100644 index 000000000..7e59456bf --- /dev/null +++ b/doc/snippets/Cwise_isFinite.cpp @@ -0,0 +1,5 @@ +Array3d v(1,2,3); +v(1) *= 0.0/0.0; +v(2) /= 0.0; +cout << v << endl << endl; +cout << isFinite(v) << endl; diff --git a/doc/snippets/Cwise_isInf.cpp b/doc/snippets/Cwise_isInf.cpp new file mode 100644 index 000000000..beb6746d0 --- /dev/null +++ b/doc/snippets/Cwise_isInf.cpp @@ -0,0 +1,5 @@ +Array3d v(1,2,3); +v(1) *= 0.0/0.0; +v(2) /= 0.0; +cout << v << endl << endl; +cout << isInf(v) << endl; diff --git a/doc/snippets/Cwise_isNaN.cpp b/doc/snippets/Cwise_isNaN.cpp new file mode 100644 index 000000000..cc1e7fe6a --- /dev/null +++ b/doc/snippets/Cwise_isNaN.cpp @@ -0,0 +1,5 @@ +Array3d v(1,2,3); +v(1) *= 0.0/0.0; +v(2) /= 0.0; +cout << v << endl << endl; +cout << isNaN(v) << endl; diff --git a/doc/snippets/Cwise_log10.cpp b/doc/snippets/Cwise_log10.cpp new file mode 100644 index 000000000..b7ae4a834 --- /dev/null +++ b/doc/snippets/Cwise_log10.cpp @@ -0,0 +1,2 @@ +Array4d v(-1,0,1,2); +cout << log10(v) << endl; diff --git a/doc/snippets/Cwise_round.cpp b/doc/snippets/Cwise_round.cpp new file mode 100644 index 000000000..e5c88230b --- /dev/null +++ b/doc/snippets/Cwise_round.cpp @@ -0,0 +1,3 @@ +ArrayXd v = ArrayXd::LinSpaced(7,-2,2); +cout << v << endl << endl; +cout << round(v) << endl; diff --git a/doc/snippets/Cwise_sinh.cpp b/doc/snippets/Cwise_sinh.cpp new file mode 100644 index 000000000..fac9b19a8 --- /dev/null +++ b/doc/snippets/Cwise_sinh.cpp @@ -0,0 +1,2 @@ +ArrayXd v = ArrayXd::LinSpaced(5,0,1); +cout << sinh(v) << endl; diff --git a/doc/snippets/Cwise_tanh.cpp b/doc/snippets/Cwise_tanh.cpp new file mode 100644 index 000000000..30cd0450d --- /dev/null +++ b/doc/snippets/Cwise_tanh.cpp @@ -0,0 +1,2 @@ +ArrayXd v = ArrayXd::LinSpaced(5,0,1); +cout << tanh(v) << endl; diff --git a/test/array.cpp b/test/array.cpp index 1443f9f88..90c75e9f0 100644 --- a/test/array.cpp +++ b/test/array.cpp @@ -201,18 +201,54 @@ template<typename ArrayType> void array_real(const ArrayType& m) Scalar s1 = internal::random<Scalar>(); - // these tests are mostly to check possible compilation issues. + // these tests are mostly to check possible compilation issues with free-functions. VERIFY_IS_APPROX(m1.sin(), sin(m1)); VERIFY_IS_APPROX(m1.cos(), cos(m1)); + VERIFY_IS_APPROX(m1.tan(), tan(m1)); VERIFY_IS_APPROX(m1.asin(), asin(m1)); VERIFY_IS_APPROX(m1.acos(), acos(m1)); - VERIFY_IS_APPROX(m1.tan(), tan(m1)); VERIFY_IS_APPROX(m1.atan(), atan(m1)); - + VERIFY_IS_APPROX(m1.sinh(), sinh(m1)); + VERIFY_IS_APPROX(m1.cosh(), cosh(m1)); + VERIFY_IS_APPROX(m1.tanh(), tanh(m1)); + VERIFY_IS_APPROX(m1.arg(), arg(m1)); + VERIFY_IS_APPROX(m1.round(), round(m1)); + VERIFY_IS_APPROX(m1.floor(), floor(m1)); + VERIFY_IS_APPROX(m1.ceil(), ceil(m1)); + VERIFY((m1.isNaN() == isNaN(m1)).all()); + VERIFY((m1.isInf() == isInf(m1)).all()); + VERIFY((m1.isFinite() == isFinite(m1)).all()); + VERIFY_IS_APPROX(m1.inverse(), inverse(m1)); + VERIFY_IS_APPROX(m1.abs(), abs(m1)); + VERIFY_IS_APPROX(m1.abs2(), abs2(m1)); + VERIFY_IS_APPROX(m1.square(), square(m1)); + VERIFY_IS_APPROX(m1.cube(), cube(m1)); VERIFY_IS_APPROX(cos(m1+RealScalar(3)*m2), cos((m1+RealScalar(3)*m2).eval())); - VERIFY_IS_APPROX(m1.abs().sqrt(), sqrt(abs(m1))); - VERIFY_IS_APPROX(m1.abs(), sqrt(numext::abs2(m1))); + + // avoid NaNs with abs() so verification doesn't fail + m3 = m1.abs(); + VERIFY_IS_APPROX(m3.sqrt(), sqrt(abs(m1))); + VERIFY_IS_APPROX(m3.log(), log(m3)); + VERIFY_IS_APPROX(m3.log10(), log10(m3)); + + + VERIFY((!(m1>m2) == (m1<=m2)).all()); + + VERIFY_IS_APPROX(sin(m1.asin()), m1); + VERIFY_IS_APPROX(cos(m1.acos()), m1); + VERIFY_IS_APPROX(tan(m1.atan()), m1); + VERIFY_IS_APPROX(sinh(m1), 0.5*(exp(m1)-exp(-m1))); + VERIFY_IS_APPROX(cosh(m1), 0.5*(exp(m1)+exp(-m1))); + VERIFY_IS_APPROX(tanh(m1), (0.5*(exp(m1)-exp(-m1)))/(0.5*(exp(m1)+exp(-m1)))); + VERIFY_IS_APPROX(arg(m1), ((ArrayType)(m1<0))*std::acos(-1.0)); + VERIFY((round(m1) <= ceil(m1) && round(m1) >= floor(m1)).all()); + VERIFY(isNaN(m1*0.0/0.0).all()); + VERIFY(isInf(m1/0.0).all()); + VERIFY((isFinite(m1) && !isFinite(m1*0.0/0.0) && !isFinite(m1/0.0)).all()); + VERIFY_IS_APPROX(inverse(inverse(m1)),m1); + VERIFY((abs(m1) == m1 || abs(m1) == -m1).all()); + VERIFY_IS_APPROX(m3, sqrt(abs2(m1))); VERIFY_IS_APPROX(numext::abs2(numext::real(m1)) + numext::abs2(numext::imag(m1)), numext::abs2(m1)); VERIFY_IS_APPROX(numext::abs2(real(m1)) + numext::abs2(imag(m1)), numext::abs2(m1)); @@ -221,7 +257,7 @@ template<typename ArrayType> void array_real(const ArrayType& m) // shift argument of logarithm so that it is not zero Scalar smallNumber = NumTraits<Scalar>::dummy_precision(); - VERIFY_IS_APPROX((m1.abs() + smallNumber).log() , log(abs(m1) + smallNumber)); + VERIFY_IS_APPROX((m3 + smallNumber).log() , log(abs(m1) + smallNumber)); VERIFY_IS_APPROX(m1.exp() * m2.exp(), exp(m1+m2)); VERIFY_IS_APPROX(m1.exp(), exp(m1)); @@ -229,13 +265,15 @@ template<typename ArrayType> void array_real(const ArrayType& m) VERIFY_IS_APPROX(m1.pow(2), m1.square()); VERIFY_IS_APPROX(pow(m1,2), m1.square()); + VERIFY_IS_APPROX(m1.pow(3), m1.cube()); + VERIFY_IS_APPROX(pow(m1,3), m1.cube()); ArrayType exponents = ArrayType::Constant(rows, cols, RealScalar(2)); VERIFY_IS_APPROX(Eigen::pow(m1,exponents), m1.square()); - m3 = m1.abs(); VERIFY_IS_APPROX(m3.pow(RealScalar(0.5)), m3.sqrt()); VERIFY_IS_APPROX(pow(m3,RealScalar(0.5)), m3.sqrt()); + VERIFY_IS_APPROX(log10(m3), log(m3)/log(10)); // scalar by array division const RealScalar tiny = sqrt(std::numeric_limits<RealScalar>::epsilon()); @@ -246,14 +284,16 @@ template<typename ArrayType> void array_real(const ArrayType& m) // check inplace transpose m3 = m1; m3.transposeInPlace(); - VERIFY_IS_APPROX(m3,m1.transpose()); + VERIFY_IS_APPROX(m3, m1.transpose()); m3.transposeInPlace(); - VERIFY_IS_APPROX(m3,m1); + VERIFY_IS_APPROX(m3, m1); } template<typename ArrayType> void array_complex(const ArrayType& m) { typedef typename ArrayType::Index Index; + typedef typename ArrayType::Scalar Scalar; + typedef typename NumTraits<Scalar>::Real RealScalar; Index rows = m.rows(); Index cols = m.cols(); @@ -261,12 +301,73 @@ template<typename ArrayType> void array_complex(const ArrayType& m) ArrayType m1 = ArrayType::Random(rows, cols), m2(rows, cols); + Array<RealScalar, -1, -1> m3(rows, cols); + + Scalar s1 = internal::random<Scalar>(); + for (Index i = 0; i < m.rows(); ++i) for (Index j = 0; j < m.cols(); ++j) m2(i,j) = sqrt(m1(i,j)); - VERIFY_IS_APPROX(m1.sqrt(), m2); - VERIFY_IS_APPROX(m1.sqrt(), Eigen::sqrt(m1)); + // these tests are mostly to check possible compilation issues with free-functions. + VERIFY_IS_APPROX(m1.sin(), sin(m1)); + VERIFY_IS_APPROX(m1.cos(), cos(m1)); + VERIFY_IS_APPROX(m1.tan(), tan(m1)); + VERIFY_IS_APPROX(m1.sinh(), sinh(m1)); + VERIFY_IS_APPROX(m1.cosh(), cosh(m1)); + VERIFY_IS_APPROX(m1.tanh(), tanh(m1)); + VERIFY_IS_APPROX(m1.arg(), arg(m1)); + VERIFY((m1.isNaN() == isNaN(m1)).all()); + VERIFY((m1.isInf() == isInf(m1)).all()); + VERIFY((m1.isFinite() == isFinite(m1)).all()); + VERIFY_IS_APPROX(m1.inverse(), inverse(m1)); + VERIFY_IS_APPROX(m1.log(), log(m1)); + VERIFY_IS_APPROX(m1.log10(), log10(m1)); + VERIFY_IS_APPROX(m1.abs(), abs(m1)); + VERIFY_IS_APPROX(m1.abs2(), abs2(m1)); + VERIFY_IS_APPROX(m1.sqrt(), sqrt(m1)); + VERIFY_IS_APPROX(m1.square(), square(m1)); + VERIFY_IS_APPROX(m1.cube(), cube(m1)); + VERIFY_IS_APPROX(cos(m1+RealScalar(3)*m2), cos((m1+RealScalar(3)*m2).eval())); + + + VERIFY_IS_APPROX(m1.exp() * m2.exp(), exp(m1+m2)); + VERIFY_IS_APPROX(m1.exp(), exp(m1)); + VERIFY_IS_APPROX(m1.exp() / m2.exp(),(m1-m2).exp()); + + VERIFY_IS_APPROX(sinh(m1), 0.5*(exp(m1)-exp(-m1))); + VERIFY_IS_APPROX(cosh(m1), 0.5*(exp(m1)+exp(-m1))); + VERIFY_IS_APPROX(tanh(m1), (0.5*(exp(m1)-exp(-m1)))/(0.5*(exp(m1)+exp(-m1)))); + + for (Index i = 0; i < m.rows(); ++i) + for (Index j = 0; j < m.cols(); ++j) + m3(i,j) = std::atan2(imag(m1(i,j)), real(m1(i,j))); + VERIFY_IS_APPROX(arg(m1), m3); + + std::complex<RealScalar> zero(0.0,0.0); + VERIFY(isNaN(m1*zero/zero).all()); + VERIFY(isInf(m1/zero).all()); + VERIFY((isFinite(m1) && !isFinite(m1*zero/zero) && !isFinite(m1/zero)).all()); + + VERIFY_IS_APPROX(inverse(inverse(m1)),m1); + VERIFY_IS_APPROX(conj(m1.conjugate()), m1); + VERIFY_IS_APPROX(abs(m1), sqrt(square(real(m1))+square(imag(m1)))); + VERIFY_IS_APPROX(abs(m1), sqrt(abs2(m1))); + VERIFY_IS_APPROX(log10(m1), log(m1)/log(10)); + + // scalar by array division + const RealScalar tiny = sqrt(std::numeric_limits<RealScalar>::epsilon()); + s1 += Scalar(tiny); + m1 += ArrayType::Constant(rows,cols,Scalar(tiny)); + VERIFY_IS_APPROX(s1/m1, s1 * m1.inverse()); + + // check inplace transpose + m2 = m1; + m2.transposeInPlace(); + VERIFY_IS_APPROX(m2, m1.transpose()); + m2.transposeInPlace(); + VERIFY_IS_APPROX(m2, m1); + } template<typename ArrayType> void min_max(const ArrayType& m) diff --git a/test/main.h b/test/main.h index 3591b57a1..d336d4d9b 100644 --- a/test/main.h +++ b/test/main.h @@ -448,12 +448,7 @@ template<typename T> bool isNotNaN(const T& x) return x==x; } -template<typename T> bool isNaN(const T& x) -{ - return x!=x; -} - -template<typename T> bool isInf(const T& x) +template<typename T> bool isPlusInf(const T& x) { return x > NumTraits<T>::highest(); } diff --git a/test/packetmath.cpp b/test/packetmath.cpp index 49f601907..e3a754627 100644 --- a/test/packetmath.cpp +++ b/test/packetmath.cpp @@ -317,7 +317,7 @@ template<typename Scalar> void packetmath_real() data1[0] = std::numeric_limits<Scalar>::quiet_NaN(); packet_helper<internal::packet_traits<Scalar>::HasExp,Packet> h; h.store(data2, internal::pexp(h.load(data1))); - VERIFY(isNaN(data2[0])); + VERIFY(numext::isNaN(data2[0])); } for (int i=0; i<size; ++i) @@ -333,14 +333,14 @@ template<typename Scalar> void packetmath_real() data1[0] = std::numeric_limits<Scalar>::quiet_NaN(); packet_helper<internal::packet_traits<Scalar>::HasLog,Packet> h; h.store(data2, internal::plog(h.load(data1))); - VERIFY(isNaN(data2[0])); + VERIFY(numext::isNaN(data2[0])); data1[0] = -1.0f; h.store(data2, internal::plog(h.load(data1))); - VERIFY(isNaN(data2[0])); + VERIFY(numext::isNaN(data2[0])); #if !EIGEN_FAST_MATH h.store(data2, internal::psqrt(h.load(data1))); - VERIFY(isNaN(data2[0])); - VERIFY(isNaN(data2[1])); + VERIFY(numext::isNaN(data2[0])); + VERIFY(numext::isNaN(data2[1])); #endif } } diff --git a/test/stable_norm.cpp b/test/stable_norm.cpp index 650f62a8a..0674006de 100644 --- a/test/stable_norm.cpp +++ b/test/stable_norm.cpp @@ -111,33 +111,33 @@ template<typename MatrixType> void stable_norm(const MatrixType& m) { v = vrand; v(i,j) = std::numeric_limits<RealScalar>::quiet_NaN(); - VERIFY(!isFinite(v.squaredNorm())); VERIFY(isNaN(v.squaredNorm())); - VERIFY(!isFinite(v.norm())); VERIFY(isNaN(v.norm())); - VERIFY(!isFinite(v.stableNorm())); VERIFY(isNaN(v.stableNorm())); - VERIFY(!isFinite(v.blueNorm())); VERIFY(isNaN(v.blueNorm())); - VERIFY(!isFinite(v.hypotNorm())); VERIFY(isNaN(v.hypotNorm())); + VERIFY(!isFinite(v.squaredNorm())); VERIFY(numext::isNaN(v.squaredNorm())); + VERIFY(!isFinite(v.norm())); VERIFY(numext::isNaN(v.norm())); + VERIFY(!isFinite(v.stableNorm())); VERIFY(numext::isNaN(v.stableNorm())); + VERIFY(!isFinite(v.blueNorm())); VERIFY(numext::isNaN(v.blueNorm())); + VERIFY(!isFinite(v.hypotNorm())); VERIFY(numext::isNaN(v.hypotNorm())); } // +inf { v = vrand; v(i,j) = std::numeric_limits<RealScalar>::infinity(); - VERIFY(!isFinite(v.squaredNorm())); VERIFY(isInf(v.squaredNorm())); - VERIFY(!isFinite(v.norm())); VERIFY(isInf(v.norm())); - VERIFY(!isFinite(v.stableNorm())); VERIFY(isInf(v.stableNorm())); - VERIFY(!isFinite(v.blueNorm())); VERIFY(isInf(v.blueNorm())); - VERIFY(!isFinite(v.hypotNorm())); VERIFY(isInf(v.hypotNorm())); + VERIFY(!isFinite(v.squaredNorm())); VERIFY(isPlusInf(v.squaredNorm())); + VERIFY(!isFinite(v.norm())); VERIFY(isPlusInf(v.norm())); + VERIFY(!isFinite(v.stableNorm())); VERIFY(isPlusInf(v.stableNorm())); + VERIFY(!isFinite(v.blueNorm())); VERIFY(isPlusInf(v.blueNorm())); + VERIFY(!isFinite(v.hypotNorm())); VERIFY(isPlusInf(v.hypotNorm())); } // -inf { v = vrand; v(i,j) = -std::numeric_limits<RealScalar>::infinity(); - VERIFY(!isFinite(v.squaredNorm())); VERIFY(isInf(v.squaredNorm())); - VERIFY(!isFinite(v.norm())); VERIFY(isInf(v.norm())); - VERIFY(!isFinite(v.stableNorm())); VERIFY(isInf(v.stableNorm())); - VERIFY(!isFinite(v.blueNorm())); VERIFY(isInf(v.blueNorm())); - VERIFY(!isFinite(v.hypotNorm())); VERIFY(isInf(v.hypotNorm())); + VERIFY(!isFinite(v.squaredNorm())); VERIFY(isPlusInf(v.squaredNorm())); + VERIFY(!isFinite(v.norm())); VERIFY(isPlusInf(v.norm())); + VERIFY(!isFinite(v.stableNorm())); VERIFY(isPlusInf(v.stableNorm())); + VERIFY(!isFinite(v.blueNorm())); VERIFY(isPlusInf(v.blueNorm())); + VERIFY(!isFinite(v.hypotNorm())); VERIFY(isPlusInf(v.hypotNorm())); } // mix @@ -147,11 +147,11 @@ template<typename MatrixType> void stable_norm(const MatrixType& m) v = vrand; v(i,j) = -std::numeric_limits<RealScalar>::infinity(); v(i2,j2) = std::numeric_limits<RealScalar>::quiet_NaN(); - VERIFY(!isFinite(v.squaredNorm())); VERIFY(isNaN(v.squaredNorm())); - VERIFY(!isFinite(v.norm())); VERIFY(isNaN(v.norm())); - VERIFY(!isFinite(v.stableNorm())); VERIFY(isNaN(v.stableNorm())); - VERIFY(!isFinite(v.blueNorm())); VERIFY(isNaN(v.blueNorm())); - VERIFY(!isFinite(v.hypotNorm())); VERIFY(isNaN(v.hypotNorm())); + VERIFY(!isFinite(v.squaredNorm())); VERIFY(numext::isNaN(v.squaredNorm())); + VERIFY(!isFinite(v.norm())); VERIFY(numext::isNaN(v.norm())); + VERIFY(!isFinite(v.stableNorm())); VERIFY(numext::isNaN(v.stableNorm())); + VERIFY(!isFinite(v.blueNorm())); VERIFY(numext::isNaN(v.blueNorm())); + VERIFY(!isFinite(v.hypotNorm())); VERIFY(numext::isNaN(v.hypotNorm())); } } |