// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2006-2010 Benoit Jacob // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 3 of the License, or (at your option) any later version. // // Alternatively, you can redistribute it and/or // modify it under the terms of the GNU General Public License as // published by the Free Software Foundation; either version 2 of // the License, or (at your option) any later version. // // Eigen is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS // FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the // GNU General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License and a copy of the GNU General Public License along with // Eigen. If not, see . #ifndef EIGEN_MATHFUNCTIONS_H #define EIGEN_MATHFUNCTIONS_H /** \internal \struct ei_global_math_functions_filtering_base * * What it does: * Defines a typedef 'type' as follows: * - if type T has a member typedef Eigen_BaseClassForSpecializationOfGlobalMathFuncImpl, then * ei_global_math_functions_filtering_base::type is a typedef for it. * - otherwise, ei_global_math_functions_filtering_base::type is a typedef for T. * * How it's used: * To allow to defined the global math functions (like ei_sin...) in certain cases, like the Array expressions. * When you do ei_sin(array1+array2), the object array1+array2 has a complicated expression type, all what you want to know * is that it inherits ArrayBase. So we implement a partial specialization of ei_sin_impl for ArrayBase. * So we must make sure to use ei_sin_impl > and not ei_sin_impl, otherwise our partial specialization * won't be used. How does ei_sin know that? That's exactly what ei_global_math_functions_filtering_base tells it. * * How it's implemented: * SFINAE in the style of enable_if. Highly susceptible of breaking compilers. With GCC, it sure does work, but if you replace * the typename dummy by an integer template parameter, it doesn't work anymore! */ template struct ei_global_math_functions_filtering_base { typedef T type; }; template struct ei_always_void { typedef void type; }; template struct ei_global_math_functions_filtering_base ::type > { typedef typename T::Eigen_BaseClassForSpecializationOfGlobalMathFuncImpl type; }; #define EIGEN_MATHFUNC_IMPL(func, scalar) ei_##func##_impl::type> #define EIGEN_MATHFUNC_RETVAL(func, scalar) typename ei_##func##_retval::type>::type /**************************************************************************** * Implementation of ei_real * ****************************************************************************/ template struct ei_real_impl { typedef typename NumTraits::Real RealScalar; static inline RealScalar run(const Scalar& x) { return x; }; }; template struct ei_real_impl > { static inline RealScalar run(const std::complex& x) { return std::real(x); }; }; template struct ei_real_retval { typedef typename NumTraits::Real type; }; template inline EIGEN_MATHFUNC_RETVAL(real, Scalar) ei_real(const Scalar& x) { return EIGEN_MATHFUNC_IMPL(real, Scalar)::run(x); } /**************************************************************************** * Implementation of ei_imag * ****************************************************************************/ template struct ei_imag_impl { typedef typename NumTraits::Real RealScalar; static inline RealScalar run(const Scalar&) { return RealScalar(0); }; }; template struct ei_imag_impl > { static inline RealScalar run(const std::complex& x) { return std::imag(x); }; }; template struct ei_imag_retval { typedef typename NumTraits::Real type; }; template inline EIGEN_MATHFUNC_RETVAL(imag, Scalar) ei_imag(const Scalar& x) { return EIGEN_MATHFUNC_IMPL(imag, Scalar)::run(x); } /**************************************************************************** * Implementation of ei_real_ref * ****************************************************************************/ template struct ei_real_ref_impl { typedef typename NumTraits::Real RealScalar; static inline RealScalar& run(Scalar& x) { return reinterpret_cast(&x)[0]; }; static inline const RealScalar& run(const Scalar& x) { return reinterpret_cast(&x)[0]; }; }; template struct ei_real_ref_retval { typedef typename NumTraits::Real & type; }; template inline const EIGEN_MATHFUNC_RETVAL(real_ref, Scalar) ei_real_ref(const Scalar& x) { return ei_real_ref_impl::run(x); } template inline EIGEN_MATHFUNC_RETVAL(real_ref, Scalar) ei_real_ref(Scalar& x) { return EIGEN_MATHFUNC_IMPL(real_ref, Scalar)::run(x); } /**************************************************************************** * Implementation of ei_imag_ref * ****************************************************************************/ template struct ei_imag_ref_default_impl { typedef typename NumTraits::Real RealScalar; static inline RealScalar& run(Scalar& x) { return reinterpret_cast(&x)[1]; } static inline const RealScalar& run(const Scalar& x) { return reinterpret_cast(&x)[1]; } }; template struct ei_imag_ref_default_impl { static inline Scalar run(Scalar&) { return Scalar(0); } static inline const Scalar run(const Scalar&) { return Scalar(0); } }; template struct ei_imag_ref_impl : ei_imag_ref_default_impl::IsComplex> {}; template struct ei_imag_ref_retval { typedef typename NumTraits::Real & type; }; template inline const EIGEN_MATHFUNC_RETVAL(imag_ref, Scalar) ei_imag_ref(const Scalar& x) { return ei_imag_ref_impl::run(x); } template inline EIGEN_MATHFUNC_RETVAL(imag_ref, Scalar) ei_imag_ref(Scalar& x) { return EIGEN_MATHFUNC_IMPL(imag_ref, Scalar)::run(x); } /**************************************************************************** * Implementation of ei_conj * ****************************************************************************/ template struct ei_conj_impl { static inline Scalar run(const Scalar& x) { return x; }; }; template struct ei_conj_impl > { static inline std::complex run(const std::complex& x) { return std::conj(x); }; }; template struct ei_conj_retval { typedef Scalar type; }; template inline EIGEN_MATHFUNC_RETVAL(conj, Scalar) ei_conj(const Scalar& x) { return EIGEN_MATHFUNC_IMPL(conj, Scalar)::run(x); } /**************************************************************************** * Implementation of ei_abs * ****************************************************************************/ template struct ei_abs_impl { typedef typename NumTraits::Real RealScalar; static inline RealScalar run(const Scalar& x) { return std::abs(x); }; }; template struct ei_abs_retval { typedef typename NumTraits::Real type; }; template inline EIGEN_MATHFUNC_RETVAL(abs, Scalar) ei_abs(const Scalar& x) { return EIGEN_MATHFUNC_IMPL(abs, Scalar)::run(x); } /**************************************************************************** * Implementation of ei_abs2 * ****************************************************************************/ template struct ei_abs2_impl { typedef typename NumTraits::Real RealScalar; static inline RealScalar run(const Scalar& x) { return x*x; }; }; template struct ei_abs2_impl > { static inline RealScalar run(const std::complex& x) { return std::norm(x); }; }; template struct ei_abs2_retval { typedef typename NumTraits::Real type; }; template inline EIGEN_MATHFUNC_RETVAL(abs2, Scalar) ei_abs2(const Scalar& x) { return EIGEN_MATHFUNC_IMPL(abs2, Scalar)::run(x); } /**************************************************************************** * Implementation of ei_norm1 * ****************************************************************************/ template struct ei_norm1_default_impl { typedef typename NumTraits::Real RealScalar; static inline RealScalar run(const Scalar& x) { return ei_abs(ei_real(x)) + ei_abs(ei_imag(x)); }; }; template struct ei_norm1_default_impl { static inline Scalar run(const Scalar& x) { return ei_abs(x); }; }; template struct ei_norm1_impl : ei_norm1_default_impl::IsComplex> {}; template struct ei_norm1_retval { typedef typename NumTraits::Real type; }; template inline EIGEN_MATHFUNC_RETVAL(norm1, Scalar) ei_norm1(const Scalar& x) { return EIGEN_MATHFUNC_IMPL(norm1, Scalar)::run(x); } /**************************************************************************** * Implementation of ei_hypot * ****************************************************************************/ template struct ei_hypot_impl { typedef typename NumTraits::Real RealScalar; static inline RealScalar run(const Scalar& x, const Scalar& y) { RealScalar _x = ei_abs(x); RealScalar _y = ei_abs(y); RealScalar p = std::max(_x, _y); RealScalar q = std::min(_x, _y); RealScalar qp = q/p; return p * ei_sqrt(RealScalar(1) + qp*qp); }; }; template struct ei_hypot_retval { typedef typename NumTraits::Real type; }; template inline EIGEN_MATHFUNC_RETVAL(hypot, Scalar) ei_hypot(const Scalar& x, const Scalar& y) { return EIGEN_MATHFUNC_IMPL(hypot, Scalar)::run(x, y); } /**************************************************************************** * Implementation of ei_cast * ****************************************************************************/ template struct ei_cast_impl { static inline NewType run(const OldType& x) { return static_cast(x); } }; // here, for once, we're plainly returning NewType: we don't want ei_cast to do weird things. template inline NewType ei_cast(const OldType& x) { return ei_cast_impl::run(x); } /**************************************************************************** * Implementation of ei_sqrt * ****************************************************************************/ template struct ei_sqrt_default_impl { static inline Scalar run(const Scalar& x) { return std::sqrt(x); }; }; template struct ei_sqrt_default_impl { static inline Scalar run(const Scalar&) { EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar) return Scalar(0); }; }; template struct ei_sqrt_impl : ei_sqrt_default_impl::IsInteger> {}; template struct ei_sqrt_retval { typedef Scalar type; }; template inline EIGEN_MATHFUNC_RETVAL(sqrt, Scalar) ei_sqrt(const Scalar& x) { return EIGEN_MATHFUNC_IMPL(sqrt, Scalar)::run(x); } /**************************************************************************** * Implementation of ei_exp * ****************************************************************************/ template struct ei_exp_default_impl { static inline Scalar run(const Scalar& x) { return std::exp(x); }; }; template struct ei_exp_default_impl { static inline Scalar run(const Scalar&) { EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar) return Scalar(0); }; }; template struct ei_exp_impl : ei_exp_default_impl::IsInteger> {}; template struct ei_exp_retval { typedef Scalar type; }; template inline EIGEN_MATHFUNC_RETVAL(exp, Scalar) ei_exp(const Scalar& x) { return EIGEN_MATHFUNC_IMPL(exp, Scalar)::run(x); } /**************************************************************************** * Implementation of ei_cos * ****************************************************************************/ template struct ei_cos_default_impl { static inline Scalar run(const Scalar& x) { return std::cos(x); }; }; template struct ei_cos_default_impl { static inline Scalar run(const Scalar&) { EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar) return Scalar(0); }; }; template struct ei_cos_impl : ei_cos_default_impl::IsInteger> {}; template struct ei_cos_retval { typedef Scalar type; }; template inline EIGEN_MATHFUNC_RETVAL(cos, Scalar) ei_cos(const Scalar& x) { return EIGEN_MATHFUNC_IMPL(cos, Scalar)::run(x); } /**************************************************************************** * Implementation of ei_sin * ****************************************************************************/ template struct ei_sin_default_impl { static inline Scalar run(const Scalar& x) { return std::sin(x); }; }; template struct ei_sin_default_impl { static inline Scalar run(const Scalar&) { EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar) return Scalar(0); }; }; template struct ei_sin_impl : ei_sin_default_impl::IsInteger> {}; template struct ei_sin_retval { typedef Scalar type; }; template inline EIGEN_MATHFUNC_RETVAL(sin, Scalar) ei_sin(const Scalar& x) { return EIGEN_MATHFUNC_IMPL(sin, Scalar)::run(x); } /**************************************************************************** * Implementation of ei_log * ****************************************************************************/ template struct ei_log_default_impl { static inline Scalar run(const Scalar& x) { return std::log(x); }; }; template struct ei_log_default_impl { static inline Scalar run(const Scalar&) { EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar) return Scalar(0); }; }; template struct ei_log_impl : ei_log_default_impl::IsInteger> {}; template struct ei_log_retval { typedef Scalar type; }; template inline EIGEN_MATHFUNC_RETVAL(log, Scalar) ei_log(const Scalar& x) { return EIGEN_MATHFUNC_IMPL(log, Scalar)::run(x); } /**************************************************************************** * Implementation of ei_atan2 * ****************************************************************************/ template struct ei_atan2_default_impl { typedef Scalar retval; static inline Scalar run(const Scalar& x, const Scalar& y) { return std::atan2(x, y); }; }; template struct ei_atan2_default_impl { static inline Scalar run(const Scalar&, const Scalar&) { EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar) return Scalar(0); }; }; template struct ei_atan2_impl : ei_atan2_default_impl::IsInteger> {}; template struct ei_atan2_retval { typedef Scalar type; }; template inline EIGEN_MATHFUNC_RETVAL(atan2, Scalar) ei_atan2(const Scalar& x, const Scalar& y) { return EIGEN_MATHFUNC_IMPL(atan2, Scalar)::run(x, y); } /**************************************************************************** * Implementation of ei_pow * ****************************************************************************/ template struct ei_pow_default_impl { typedef Scalar retval; static inline Scalar run(const Scalar& x, const Scalar& y) { return std::pow(x, y); }; }; template struct ei_pow_default_impl { static inline Scalar run(Scalar x, Scalar y) { int res = 1; if(NumTraits::IsSigned) ei_assert(y >= 0); if(y & 1) res *= x; y >>= 1; while(y) { x *= x; if(y&1) res *= x; y >>= 1; } return res; }; }; template struct ei_pow_impl : ei_pow_default_impl::IsInteger> {}; template struct ei_pow_retval { typedef Scalar type; }; template inline EIGEN_MATHFUNC_RETVAL(pow, Scalar) ei_pow(const Scalar& x, const Scalar& y) { return EIGEN_MATHFUNC_IMPL(pow, Scalar)::run(x, y); } /**************************************************************************** * Implementation of ei_random * ****************************************************************************/ template struct ei_random_default_impl {}; template struct ei_random_impl : ei_random_default_impl::IsComplex, NumTraits::IsInteger> {}; template struct ei_random_retval { typedef Scalar type; }; template inline EIGEN_MATHFUNC_RETVAL(random, Scalar) ei_random(const Scalar& x, const Scalar& y); template inline EIGEN_MATHFUNC_RETVAL(random, Scalar) ei_random(); template struct ei_random_default_impl { static inline Scalar run(const Scalar& x, const Scalar& y) { return x + (y-x) * Scalar(std::rand()) / float(RAND_MAX); }; static inline Scalar run() { return run(Scalar(NumTraits::IsSigned ? -1 : 0), Scalar(1)); }; }; template struct ei_random_default_impl { static inline Scalar run(const Scalar& x, const Scalar& y) { return x + Scalar((y-x+1) * (std::rand() / (RAND_MAX + typename NumTraits::NonInteger(1)))); }; static inline Scalar run() { return run(Scalar(NumTraits::IsSigned ? -10 : 0), Scalar(10)); }; }; template struct ei_random_default_impl { static inline Scalar run(const Scalar& x, const Scalar& y) { return Scalar(ei_random(ei_real(x), ei_real(y)), ei_random(ei_imag(x), ei_imag(y))); }; static inline Scalar run() { typedef typename NumTraits::Real RealScalar; return Scalar(ei_random(), ei_random()); }; }; template inline EIGEN_MATHFUNC_RETVAL(random, Scalar) ei_random(const Scalar& x, const Scalar& y) { return EIGEN_MATHFUNC_IMPL(random, Scalar)::run(x, y); } template inline EIGEN_MATHFUNC_RETVAL(random, Scalar) ei_random() { return EIGEN_MATHFUNC_IMPL(random, Scalar)::run(); } /**************************************************************************** * Implementation of fuzzy comparisons * ****************************************************************************/ template struct ei_scalar_fuzzy_default_impl {}; template struct ei_scalar_fuzzy_default_impl { typedef typename NumTraits::Real RealScalar; template static inline bool isMuchSmallerThan(const Scalar& x, const OtherScalar& y, const RealScalar& prec) { return ei_abs(x) <= ei_abs(y) * prec; } static inline bool isApprox(const Scalar& x, const Scalar& y, const RealScalar& prec) { return ei_abs(x - y) <= std::min(ei_abs(x), ei_abs(y)) * prec; } static inline bool isApproxOrLessThan(const Scalar& x, const Scalar& y, const RealScalar& prec) { return x <= y || isApprox(x, y, prec); } }; template struct ei_scalar_fuzzy_default_impl { typedef typename NumTraits::Real RealScalar; template static inline bool isMuchSmallerThan(const Scalar& x, const Scalar&, const RealScalar&) { return x == Scalar(0); } static inline bool isApprox(const Scalar& x, const Scalar& y, const RealScalar&) { return x == y; } static inline bool isApproxOrLessThan(const Scalar& x, const Scalar& y, const RealScalar&) { return x <= y; } }; template struct ei_scalar_fuzzy_default_impl { typedef typename NumTraits::Real RealScalar; template static inline bool isMuchSmallerThan(const Scalar& x, const OtherScalar& y, const RealScalar& prec) { return ei_abs2(x) <= ei_abs2(y) * prec * prec; } static inline bool isApprox(const Scalar& x, const Scalar& y, const RealScalar& prec) { return ei_abs2(x - y) <= std::min(ei_abs2(x), ei_abs2(y)) * prec * prec; } }; template struct ei_scalar_fuzzy_impl : ei_scalar_fuzzy_default_impl::IsComplex, NumTraits::IsInteger> {}; template inline bool ei_isMuchSmallerThan(const Scalar& x, const OtherScalar& y, typename NumTraits::Real precision = NumTraits::dummy_precision()) { return ei_scalar_fuzzy_impl::template isMuchSmallerThan(x, y, precision); } template inline bool ei_isApprox(const Scalar& x, const Scalar& y, typename NumTraits::Real precision = NumTraits::dummy_precision()) { return ei_scalar_fuzzy_impl::isApprox(x, y, precision); } template inline bool ei_isApproxOrLessThan(const Scalar& x, const Scalar& y, typename NumTraits::Real precision = NumTraits::dummy_precision()) { return ei_scalar_fuzzy_impl::isApproxOrLessThan(x, y, precision); } /****************************************** *** The special case of the bool type *** ******************************************/ template<> struct ei_random_impl { static inline bool run() { return bool(ei_random(0,1)); }; }; template<> struct ei_scalar_fuzzy_impl { static inline bool isApprox(bool x, bool y, bool) { return x == y; }; }; #endif // EIGEN_MATHFUNCTIONS_H