diff options
author | 2010-05-02 21:51:27 +0100 | |
---|---|---|
committer | 2010-05-02 21:51:27 +0100 | |
commit | 38021b08c1278d0740fd3e678d17e7539c9f1c93 (patch) | |
tree | b60d77a287228ca2b450ebd42ad4410302c9dd37 /Eigen | |
parent | afed0ef90d8f6c6c62dc5b1173bbbc63bee3c5c1 (diff) | |
parent | 8f249e8b5459ed79914db7847cebd3a40458bd8b (diff) |
Merge.
Diffstat (limited to 'Eigen')
-rw-r--r-- | Eigen/Dense | 2 | ||||
-rw-r--r-- | Eigen/LeastSquares | 28 | ||||
-rw-r--r-- | Eigen/src/Array/ArrayBase.h | 2 | ||||
-rw-r--r-- | Eigen/src/Array/GlobalFunctions.h | 53 | ||||
-rw-r--r-- | Eigen/src/CMakeLists.txt | 1 | ||||
-rw-r--r-- | Eigen/src/Core/Dot.h | 2 | ||||
-rw-r--r-- | Eigen/src/Core/Functors.h | 16 | ||||
-rw-r--r-- | Eigen/src/Core/Fuzzy.h | 2 | ||||
-rw-r--r-- | Eigen/src/Core/IO.h | 24 | ||||
-rw-r--r-- | Eigen/src/Core/MathFunctions.h | 1027 | ||||
-rw-r--r-- | Eigen/src/Core/NumTraits.h | 176 | ||||
-rw-r--r-- | Eigen/src/Core/SelfCwiseBinaryOp.h | 6 | ||||
-rw-r--r-- | Eigen/src/Core/util/StaticAssert.h | 5 | ||||
-rw-r--r-- | Eigen/src/Geometry/AlignedBox.h | 15 | ||||
-rw-r--r-- | Eigen/src/LU/Inverse.h | 4 | ||||
-rw-r--r-- | Eigen/src/LeastSquares/CMakeLists.txt | 6 | ||||
-rw-r--r-- | Eigen/src/LeastSquares/LeastSquares.h | 181 |
17 files changed, 930 insertions, 620 deletions
diff --git a/Eigen/Dense b/Eigen/Dense index 6177b67ac..9ab39b653 100644 --- a/Eigen/Dense +++ b/Eigen/Dense @@ -4,4 +4,4 @@ #include "QR" #include "SVD" #include "Geometry" -#include "LeastSquares" +#include "Eigenvalues"
\ No newline at end of file diff --git a/Eigen/LeastSquares b/Eigen/LeastSquares deleted file mode 100644 index 61b83bbc8..000000000 --- a/Eigen/LeastSquares +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef EIGEN_REGRESSION_MODULE_H -#define EIGEN_REGRESSION_MODULE_H - -#include "Core" - -#include "src/Core/util/DisableMSVCWarnings.h" - -#include "Eigenvalues" -#include "Geometry" - -namespace Eigen { - -/** \defgroup LeastSquares_Module LeastSquares module - * This module provides linear regression and related features. - * - * \code - * #include <Eigen/LeastSquares> - * \endcode - */ - -#include "src/LeastSquares/LeastSquares.h" - -} // namespace Eigen - -#include "src/Core/util/EnableMSVCWarnings.h" - -#endif // EIGEN_REGRESSION_MODULE_H -/* vim: set filetype=cpp et sw=2 ts=2 ai: */ diff --git a/Eigen/src/Array/ArrayBase.h b/Eigen/src/Array/ArrayBase.h index c507b7694..b835a57ad 100644 --- a/Eigen/src/Array/ArrayBase.h +++ b/Eigen/src/Array/ArrayBase.h @@ -54,6 +54,8 @@ template<typename Derived> class ArrayBase #ifndef EIGEN_PARSED_BY_DOXYGEN /** The base class for a given storage type. */ typedef ArrayBase StorageBaseType; + + typedef ArrayBase Eigen_BaseClassForSpecializationOfGlobalMathFuncImpl; using ei_special_scalar_op_base<Derived,typename ei_traits<Derived>::Scalar, typename NumTraits<typename ei_traits<Derived>::Scalar>::Real>::operator*; diff --git a/Eigen/src/Array/GlobalFunctions.h b/Eigen/src/Array/GlobalFunctions.h index 33f00c2ba..9aa022547 100644 --- a/Eigen/src/Array/GlobalFunctions.h +++ b/Eigen/src/Array/GlobalFunctions.h @@ -2,6 +2,7 @@ // for linear algebra. // // Copyright (C) 2010 Gael Guennebaud <g.gael@free.fr> +// Copyright (C) 2010 Benoit Jacob <jacob.benoit.1@gmail.com> // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -25,31 +26,55 @@ #ifndef EIGEN_GLOBAL_FUNCTIONS_H #define EIGEN_GLOBAL_FUNCTIONS_H -#define EIGEN_ARRAY_DECLARARE_GLOBAL_UNARY(NAME,FUNCTOR) \ +#define EIGEN_ARRAY_DECLARE_GLOBAL_STD_UNARY(NAME,FUNCTOR) \ template<typename Derived> \ inline const Eigen::CwiseUnaryOp<Eigen::FUNCTOR<typename Derived::Scalar>, Derived> \ NAME(const Eigen::ArrayBase<Derived>& x) { \ return x.derived(); \ } - + +#define EIGEN_ARRAY_DECLARE_GLOBAL_EIGEN_UNARY(NAME,FUNCTOR) \ + \ + template<typename Derived> \ + struct NAME##_retval<ArrayBase<Derived> > \ + { \ + typedef const Eigen::CwiseUnaryOp<Eigen::FUNCTOR<typename Derived::Scalar>, Derived> type; \ + }; \ + template<typename Derived> \ + struct NAME##_impl<ArrayBase<Derived> > \ + { \ + static inline typename NAME##_retval<ArrayBase<Derived> >::type run(const Eigen::ArrayBase<Derived>& x) \ + { \ + return x.derived(); \ + } \ + }; + + namespace std { - EIGEN_ARRAY_DECLARARE_GLOBAL_UNARY(sin,ei_scalar_sin_op) - EIGEN_ARRAY_DECLARARE_GLOBAL_UNARY(cos,ei_scalar_cos_op) - EIGEN_ARRAY_DECLARARE_GLOBAL_UNARY(exp,ei_scalar_exp_op) - EIGEN_ARRAY_DECLARARE_GLOBAL_UNARY(log,ei_scalar_log_op) - EIGEN_ARRAY_DECLARARE_GLOBAL_UNARY(abs,ei_scalar_abs_op) - EIGEN_ARRAY_DECLARARE_GLOBAL_UNARY(sqrt,ei_scalar_sqrt_op) + EIGEN_ARRAY_DECLARE_GLOBAL_STD_UNARY(real,ei_scalar_real_op) + EIGEN_ARRAY_DECLARE_GLOBAL_STD_UNARY(imag,ei_scalar_imag_op) + EIGEN_ARRAY_DECLARE_GLOBAL_STD_UNARY(sin,ei_scalar_sin_op) + EIGEN_ARRAY_DECLARE_GLOBAL_STD_UNARY(cos,ei_scalar_cos_op) + EIGEN_ARRAY_DECLARE_GLOBAL_STD_UNARY(exp,ei_scalar_exp_op) + EIGEN_ARRAY_DECLARE_GLOBAL_STD_UNARY(log,ei_scalar_log_op) + EIGEN_ARRAY_DECLARE_GLOBAL_STD_UNARY(abs,ei_scalar_abs_op) + EIGEN_ARRAY_DECLARE_GLOBAL_STD_UNARY(sqrt,ei_scalar_sqrt_op) } namespace Eigen { - EIGEN_ARRAY_DECLARARE_GLOBAL_UNARY(ei_sin,ei_scalar_sin_op) - EIGEN_ARRAY_DECLARARE_GLOBAL_UNARY(ei_cos,ei_scalar_cos_op) - EIGEN_ARRAY_DECLARARE_GLOBAL_UNARY(ei_exp,ei_scalar_exp_op) - EIGEN_ARRAY_DECLARARE_GLOBAL_UNARY(ei_log,ei_scalar_log_op) - EIGEN_ARRAY_DECLARARE_GLOBAL_UNARY(ei_abs,ei_scalar_abs_op) - EIGEN_ARRAY_DECLARARE_GLOBAL_UNARY(ei_sqrt,ei_scalar_sqrt_op) + EIGEN_ARRAY_DECLARE_GLOBAL_EIGEN_UNARY(ei_real,ei_scalar_real_op) + EIGEN_ARRAY_DECLARE_GLOBAL_EIGEN_UNARY(ei_imag,ei_scalar_imag_op) + EIGEN_ARRAY_DECLARE_GLOBAL_EIGEN_UNARY(ei_sin,ei_scalar_sin_op) + EIGEN_ARRAY_DECLARE_GLOBAL_EIGEN_UNARY(ei_cos,ei_scalar_cos_op) + EIGEN_ARRAY_DECLARE_GLOBAL_EIGEN_UNARY(ei_exp,ei_scalar_exp_op) + EIGEN_ARRAY_DECLARE_GLOBAL_EIGEN_UNARY(ei_log,ei_scalar_log_op) + EIGEN_ARRAY_DECLARE_GLOBAL_EIGEN_UNARY(ei_abs,ei_scalar_abs_op) + EIGEN_ARRAY_DECLARE_GLOBAL_EIGEN_UNARY(ei_abs2,ei_scalar_abs2_op) + EIGEN_ARRAY_DECLARE_GLOBAL_EIGEN_UNARY(ei_sqrt,ei_scalar_sqrt_op) } +// TODO: cleanly disable those functions that are not suppored on Array (ei_real_ref, ei_random, ei_isApprox...) + #endif // EIGEN_GLOBAL_FUNCTIONS_H diff --git a/Eigen/src/CMakeLists.txt b/Eigen/src/CMakeLists.txt index 0d3604f06..9009291d9 100644 --- a/Eigen/src/CMakeLists.txt +++ b/Eigen/src/CMakeLists.txt @@ -5,7 +5,6 @@ ADD_SUBDIRECTORY(SVD) ADD_SUBDIRECTORY(Cholesky) ADD_SUBDIRECTORY(Array) ADD_SUBDIRECTORY(Geometry) -ADD_SUBDIRECTORY(LeastSquares) ADD_SUBDIRECTORY(Sparse) ADD_SUBDIRECTORY(Jacobi) ADD_SUBDIRECTORY(Householder) diff --git a/Eigen/src/Core/Dot.h b/Eigen/src/Core/Dot.h index fbdc67bd3..4bd81872d 100644 --- a/Eigen/src/Core/Dot.h +++ b/Eigen/src/Core/Dot.h @@ -161,7 +161,7 @@ bool MatrixBase<Derived>::isUnitary(RealScalar prec) const typename Derived::Nested nested(derived()); for(int i = 0; i < cols(); ++i) { - if(!ei_isApprox(nested.col(i).squaredNorm(), static_cast<Scalar>(1), prec)) + if(!ei_isApprox(nested.col(i).squaredNorm(), static_cast<RealScalar>(1), prec)) return false; for(int j = 0; j < i; ++j) if(!ei_isMuchSmallerThan(nested.col(i).dot(nested.col(j)), static_cast<Scalar>(1), prec)) diff --git a/Eigen/src/Core/Functors.h b/Eigen/src/Core/Functors.h index d02633cb8..bdceb9bb5 100644 --- a/Eigen/src/Core/Functors.h +++ b/Eigen/src/Core/Functors.h @@ -180,7 +180,7 @@ struct ei_functor_traits<ei_scalar_quotient_op<Scalar> > { Cost = 2 * NumTraits<Scalar>::MulCost, PacketAccess = ei_packet_traits<Scalar>::size>1 #if (defined EIGEN_VECTORIZE) - && NumTraits<Scalar>::HasFloatingPoint + && !NumTraits<Scalar>::IsInteger #endif }; }; @@ -384,7 +384,7 @@ template<typename Scalar1,typename Scalar2> struct ei_functor_traits<ei_scalar_multiple2_op<Scalar1,Scalar2> > { enum { Cost = NumTraits<Scalar1>::MulCost, PacketAccess = false }; }; -template<typename Scalar, bool HasFloatingPoint> +template<typename Scalar, bool IsInteger> struct ei_scalar_quotient1_impl { typedef typename ei_packet_traits<Scalar>::type PacketScalar; // FIXME default copy constructors seems bugged with std::complex<> @@ -396,11 +396,11 @@ struct ei_scalar_quotient1_impl { const Scalar m_other; }; template<typename Scalar> -struct ei_functor_traits<ei_scalar_quotient1_impl<Scalar,true> > +struct ei_functor_traits<ei_scalar_quotient1_impl<Scalar,false> > { enum { Cost = NumTraits<Scalar>::MulCost, PacketAccess = ei_packet_traits<Scalar>::size>1 }; }; template<typename Scalar> -struct ei_scalar_quotient1_impl<Scalar,false> { +struct ei_scalar_quotient1_impl<Scalar,true> { // FIXME default copy constructors seems bugged with std::complex<> EIGEN_STRONG_INLINE ei_scalar_quotient1_impl(const ei_scalar_quotient1_impl& other) : m_other(other.m_other) { } EIGEN_STRONG_INLINE ei_scalar_quotient1_impl(const Scalar& other) : m_other(other) {} @@ -408,7 +408,7 @@ struct ei_scalar_quotient1_impl<Scalar,false> { typename ei_makeconst<typename NumTraits<Scalar>::Nested>::type m_other; }; template<typename Scalar> -struct ei_functor_traits<ei_scalar_quotient1_impl<Scalar,false> > +struct ei_functor_traits<ei_scalar_quotient1_impl<Scalar,true> > { enum { Cost = 2 * NumTraits<Scalar>::MulCost, PacketAccess = false }; }; /** \internal @@ -420,13 +420,13 @@ struct ei_functor_traits<ei_scalar_quotient1_impl<Scalar,false> > * \sa class CwiseUnaryOp, MatrixBase::operator/ */ template<typename Scalar> -struct ei_scalar_quotient1_op : ei_scalar_quotient1_impl<Scalar, NumTraits<Scalar>::HasFloatingPoint > { +struct ei_scalar_quotient1_op : ei_scalar_quotient1_impl<Scalar, NumTraits<Scalar>::IsInteger > { EIGEN_STRONG_INLINE ei_scalar_quotient1_op(const Scalar& other) - : ei_scalar_quotient1_impl<Scalar, NumTraits<Scalar>::HasFloatingPoint >(other) {} + : ei_scalar_quotient1_impl<Scalar, NumTraits<Scalar>::IsInteger >(other) {} }; template<typename Scalar> struct ei_functor_traits<ei_scalar_quotient1_op<Scalar> > -: ei_functor_traits<ei_scalar_quotient1_impl<Scalar, NumTraits<Scalar>::HasFloatingPoint> > +: ei_functor_traits<ei_scalar_quotient1_impl<Scalar, NumTraits<Scalar>::IsInteger> > {}; // nullary functors diff --git a/Eigen/src/Core/Fuzzy.h b/Eigen/src/Core/Fuzzy.h index dfa042377..432da4288 100644 --- a/Eigen/src/Core/Fuzzy.h +++ b/Eigen/src/Core/Fuzzy.h @@ -26,6 +26,8 @@ #ifndef EIGEN_FUZZY_H #define EIGEN_FUZZY_H +// TODO support small integer types properly i.e. do exact compare on coeffs --- taking a HS norm is guaranteed to cause integer overflow. + #ifndef EIGEN_LEGACY_COMPARES /** \returns \c true if \c *this is approximately equal to \a other, within the precision diff --git a/Eigen/src/Core/IO.h b/Eigen/src/Core/IO.h index c98742246..3da92d21a 100644 --- a/Eigen/src/Core/IO.h +++ b/Eigen/src/Core/IO.h @@ -126,8 +126,8 @@ DenseBase<Derived>::format(const IOFormat& fmt) const return WithFormat<Derived>(derived(), fmt); } -template<typename Scalar> -struct ei_significant_decimals_impl +template<typename Scalar, bool IsInteger> +struct ei_significant_decimals_default_impl { typedef typename NumTraits<Scalar>::Real RealScalar; static inline int run() @@ -136,6 +136,20 @@ struct ei_significant_decimals_impl } }; +template<typename Scalar> +struct ei_significant_decimals_default_impl<Scalar, true> +{ + static inline int run() + { + return 0; + } +}; + +template<typename Scalar> +struct ei_significant_decimals_impl + : ei_significant_decimals_default_impl<Scalar, NumTraits<Scalar>::IsInteger> +{}; + /** \internal * print the matrix \a _m to the output stream \a s using the output format \a fmt */ template<typename Derived> @@ -153,13 +167,13 @@ std::ostream & ei_print_matrix(std::ostream & s, const Derived& _m, const IOForm } else if(fmt.precision == FullPrecision) { - if (NumTraits<Scalar>::HasFloatingPoint) + if (NumTraits<Scalar>::IsInteger) { - explicit_precision = ei_significant_decimals_impl<Scalar>::run(); + explicit_precision = 0; } else { - explicit_precision = 0; + explicit_precision = ei_significant_decimals_impl<Scalar>::run(); } } else diff --git a/Eigen/src/Core/MathFunctions.h b/Eigen/src/Core/MathFunctions.h index 4a21ec975..c24665a4b 100644 --- a/Eigen/src/Core/MathFunctions.h +++ b/Eigen/src/Core/MathFunctions.h @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2006-2009 Benoit Jacob <jacob.benoit.1@gmail.com> +// Copyright (C) 2006-2010 Benoit Jacob <jacob.benoit.1@gmail.com> // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -25,330 +25,845 @@ #ifndef EIGEN_MATHFUNCTIONS_H #define EIGEN_MATHFUNCTIONS_H -template<typename T> inline T ei_random(T a, T b); -template<typename T> inline T ei_random(); -template<typename T> inline T ei_random_amplitude() +/** \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<T>::type is a typedef for it. + * - otherwise, ei_global_math_functions_filtering_base<T>::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<Derived>. + * So we must make sure to use ei_sin_impl<ArrayBase<Derived> > and not ei_sin_impl<Derived>, 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<typename T, typename dummy = void> +struct ei_global_math_functions_filtering_base { - if(NumTraits<T>::HasFloatingPoint) return static_cast<T>(1); - else return static_cast<T>(10); -} + typedef T type; +}; -template<typename T> inline typename NumTraits<T>::Real ei_hypot(T x, T y) +template<typename T> struct ei_always_void { typedef void type; }; + +template<typename T> +struct ei_global_math_functions_filtering_base + <T, + typename ei_always_void<typename T::Eigen_BaseClassForSpecializationOfGlobalMathFuncImpl>::type + > { - typedef typename NumTraits<T>::Real RealScalar; - RealScalar _x = ei_abs(x); - RealScalar _y = ei_abs(y); - T p = std::max(_x, _y); - T q = std::min(_x, _y); - T qp = q/p; - return p * ei_sqrt(T(1) + qp*qp); -} + typedef typename T::Eigen_BaseClassForSpecializationOfGlobalMathFuncImpl type; +}; + +#define EIGEN_MATHFUNC_IMPL(func, scalar) ei_##func##_impl<typename ei_global_math_functions_filtering_base<scalar>::type> +#define EIGEN_MATHFUNC_RETVAL(func, scalar) typename ei_##func##_retval<typename ei_global_math_functions_filtering_base<scalar>::type>::type + -// the point of wrapping these casts in this helper template struct is to allow users to specialize it to custom types -// that may not have the needed conversion operators (especially as c++98 doesn't have explicit conversion operators). +/**************************************************************************** +* Implementation of ei_real * +****************************************************************************/ -template<typename OldType, typename NewType> struct ei_cast_impl +template<typename Scalar> +struct ei_real_impl { - static inline NewType run(const OldType& x) + typedef typename NumTraits<Scalar>::Real RealScalar; + static inline RealScalar run(const Scalar& x) { - return static_cast<NewType>(x); - } + return x; + }; }; -template<typename OldType, typename NewType> inline NewType ei_cast(const OldType& x) +template<typename RealScalar> +struct ei_real_impl<std::complex<RealScalar> > { - return ei_cast_impl<OldType, NewType>::run(x); -} + static inline RealScalar run(const std::complex<RealScalar>& x) + { + return std::real(x); + }; +}; +template<typename Scalar> +struct ei_real_retval +{ + typedef typename NumTraits<Scalar>::Real type; +}; -/************** -*** int *** -**************/ - -inline int ei_real(int x) { return x; } -inline int& ei_real_ref(int& x) { return x; } -inline int ei_imag(int) { return 0; } -inline int ei_conj(int x) { return x; } -inline int ei_abs(int x) { return std::abs(x); } -inline int ei_abs2(int x) { return x*x; } -inline int ei_sqrt(int) { ei_assert(false); return 0; } -inline int ei_exp(int) { ei_assert(false); return 0; } -inline int ei_log(int) { ei_assert(false); return 0; } -inline int ei_sin(int) { ei_assert(false); return 0; } -inline int ei_cos(int) { ei_assert(false); return 0; } -inline int ei_atan2(int, int) { ei_assert(false); return 0; } -inline int ei_pow(int x, int y) -{ - int res = 1; - if(y < 0) return 0; - if(y & 1) res *= x; - y >>= 1; - while(y) - { - x *= x; - if(y&1) res *= x; - y >>= 1; - } - return res; +template<typename Scalar> +inline EIGEN_MATHFUNC_RETVAL(real, Scalar) ei_real(const Scalar& x) +{ + return EIGEN_MATHFUNC_IMPL(real, Scalar)::run(x); } -template<> inline int ei_random(int a, int b) +/**************************************************************************** +* Implementation of ei_imag * +****************************************************************************/ + +template<typename Scalar> +struct ei_imag_impl { - // We can't just do rand()%n as only the high-order bits are really random - return a + static_cast<int>((b-a+1) * (std::rand() / (RAND_MAX + 1.0))); -} -template<> inline int ei_random() + typedef typename NumTraits<Scalar>::Real RealScalar; + static inline RealScalar run(const Scalar&) + { + return RealScalar(0); + }; +}; + +template<typename RealScalar> +struct ei_imag_impl<std::complex<RealScalar> > { - return ei_random<int>(-ei_random_amplitude<int>(), ei_random_amplitude<int>()); -} -inline bool ei_isMuchSmallerThan(int a, int, int = NumTraits<int>::dummy_precision()) + static inline RealScalar run(const std::complex<RealScalar>& x) + { + return std::imag(x); + }; +}; + +template<typename Scalar> +struct ei_imag_retval { - return a == 0; -} -inline bool ei_isApprox(int a, int b, int = NumTraits<int>::dummy_precision()) + typedef typename NumTraits<Scalar>::Real type; +}; + +template<typename Scalar> +inline EIGEN_MATHFUNC_RETVAL(imag, Scalar) ei_imag(const Scalar& x) { - return a == b; + return EIGEN_MATHFUNC_IMPL(imag, Scalar)::run(x); } -inline bool ei_isApproxOrLessThan(int a, int b, int = NumTraits<int>::dummy_precision()) + +/**************************************************************************** +* Implementation of ei_real_ref * +****************************************************************************/ + +template<typename Scalar> +struct ei_real_ref_impl { - return a <= b; -} + typedef typename NumTraits<Scalar>::Real RealScalar; + static inline RealScalar& run(Scalar& x) + { + return reinterpret_cast<RealScalar*>(&x)[0]; + }; + static inline const RealScalar& run(const Scalar& x) + { + return reinterpret_cast<const RealScalar*>(&x)[0]; + }; +}; -/************** -*** float *** -**************/ - -inline float ei_real(float x) { return x; } -inline float& ei_real_ref(float& x) { return x; } -inline float ei_imag(float) { return 0.f; } -inline float ei_conj(float x) { return x; } -inline float ei_abs(float x) { return std::abs(x); } -inline float ei_abs2(float x) { return x*x; } -inline float ei_norm1(float x) { return ei_abs(x); } -inline float ei_sqrt(float x) { return std::sqrt(x); } -inline float ei_exp(float x) { return std::exp(x); } -inline float ei_log(float x) { return std::log(x); } -inline float ei_sin(float x) { return std::sin(x); } -inline float ei_cos(float x) { return std::cos(x); } -inline float ei_atan2(float y, float x) { return std::atan2(y,x); } -inline float ei_pow(float x, float y) { return std::pow(x, y); } - -template<> inline float ei_random(float a, float b) -{ -#ifdef EIGEN_NICE_RANDOM - int i; - do { i = ei_random<int>(256*int(a),256*int(b)); - } while(i==0); - return float(i)/256.f; -#else - return a + (b-a) * float(std::rand()) / float(RAND_MAX); -#endif -} -template<> inline float ei_random() +template<typename Scalar> +struct ei_real_ref_retval { - return ei_random<float>(-ei_random_amplitude<float>(), ei_random_amplitude<float>()); -} -inline bool ei_isMuchSmallerThan(float a, float b, float prec = NumTraits<float>::dummy_precision()) + typedef typename NumTraits<Scalar>::Real & type; +}; + +template<typename Scalar> +inline typename ei_makeconst< EIGEN_MATHFUNC_RETVAL(real_ref, Scalar) >::type ei_real_ref(const Scalar& x) { - return ei_abs(a) <= ei_abs(b) * prec; + return ei_real_ref_impl<Scalar>::run(x); } -inline bool ei_isApprox(float a, float b, float prec = NumTraits<float>::dummy_precision()) + +template<typename Scalar> +inline EIGEN_MATHFUNC_RETVAL(real_ref, Scalar) ei_real_ref(Scalar& x) { - return ei_abs(a - b) <= std::min(ei_abs(a), ei_abs(b)) * prec; + return EIGEN_MATHFUNC_IMPL(real_ref, Scalar)::run(x); } -inline bool ei_isApproxOrLessThan(float a, float b, float prec = NumTraits<float>::dummy_precision()) + +/**************************************************************************** +* Implementation of ei_imag_ref * +****************************************************************************/ + +template<typename Scalar, bool IsComplex> +struct ei_imag_ref_default_impl { - return a <= b || ei_isApprox(a, b, prec); -} + typedef typename NumTraits<Scalar>::Real RealScalar; + static inline RealScalar& run(Scalar& x) + { + return reinterpret_cast<RealScalar*>(&x)[1]; + } + static inline const RealScalar& run(const Scalar& x) + { + return reinterpret_cast<RealScalar*>(&x)[1]; + } +}; -/************** -*** double *** -**************/ - -inline double ei_real(double x) { return x; } -inline double& ei_real_ref(double& x) { return x; } -inline double ei_imag(double) { return 0.; } -inline double ei_conj(double x) { return x; } -inline double ei_abs(double x) { return std::abs(x); } -inline double ei_abs2(double x) { return x*x; } -inline double ei_norm1(double x) { return ei_abs(x); } -inline double ei_sqrt(double x) { return std::sqrt(x); } -inline double ei_exp(double x) { return std::exp(x); } -inline double ei_log(double x) { return std::log(x); } -inline double ei_sin(double x) { return std::sin(x); } -inline double ei_cos(double x) { return std::cos(x); } -inline double ei_atan2(double y, double x) { return std::atan2(y,x); } -inline double ei_pow(double x, double y) { return std::pow(x, y); } - -template<> inline double ei_random(double a, double b) -{ -#ifdef EIGEN_NICE_RANDOM - int i; - do { i= ei_random<int>(256*int(a),256*int(b)); - } while(i==0); - return i/256.; -#else - return a + (b-a) * std::rand() / RAND_MAX; -#endif -} -template<> inline double ei_random() +template<typename Scalar> +struct ei_imag_ref_default_impl<Scalar, false> { - return ei_random<double>(-ei_random_amplitude<double>(), ei_random_amplitude<double>()); + static inline Scalar run(Scalar&) + { + return Scalar(0); + } + static inline const Scalar run(const Scalar&) + { + return Scalar(0); + } +}; + +template<typename Scalar> +struct ei_imag_ref_impl : ei_imag_ref_default_impl<Scalar, NumTraits<Scalar>::IsComplex> {}; + +template<typename Scalar> +struct ei_imag_ref_retval +{ + typedef typename NumTraits<Scalar>::Real & type; +}; + +template<typename Scalar> +inline typename ei_makeconst< EIGEN_MATHFUNC_RETVAL(imag_ref, Scalar) >::type ei_imag_ref(const Scalar& x) +{ + return ei_imag_ref_impl<Scalar>::run(x); } -inline bool ei_isMuchSmallerThan(double a, double b, double prec = NumTraits<double>::dummy_precision()) + +template<typename Scalar> +inline EIGEN_MATHFUNC_RETVAL(imag_ref, Scalar) ei_imag_ref(Scalar& x) { - return ei_abs(a) <= ei_abs(b) * prec; + return EIGEN_MATHFUNC_IMPL(imag_ref, Scalar)::run(x); } -inline bool ei_isApprox(double a, double b, double prec = NumTraits<double>::dummy_precision()) + +/**************************************************************************** +* Implementation of ei_conj * +****************************************************************************/ + +template<typename Scalar> +struct ei_conj_impl +{ + static inline Scalar run(const Scalar& x) + { + return x; + }; +}; + +template<typename RealScalar> +struct ei_conj_impl<std::complex<RealScalar> > +{ + static inline std::complex<RealScalar> run(const std::complex<RealScalar>& x) + { + return std::conj(x); + }; +}; + +template<typename Scalar> +struct ei_conj_retval { - return ei_abs(a - b) <= std::min(ei_abs(a), ei_abs(b)) * prec; + typedef Scalar type; +}; + +template<typename Scalar> +inline EIGEN_MATHFUNC_RETVAL(conj, Scalar) ei_conj(const Scalar& x) +{ + return EIGEN_MATHFUNC_IMPL(conj, Scalar)::run(x); } -inline bool ei_isApproxOrLessThan(double a, double b, double prec = NumTraits<double>::dummy_precision()) + +/**************************************************************************** +* Implementation of ei_abs * +****************************************************************************/ + +template<typename Scalar> +struct ei_abs_impl { - return a <= b || ei_isApprox(a, b, prec); + typedef typename NumTraits<Scalar>::Real RealScalar; + static inline RealScalar run(const Scalar& x) + { + return std::abs(x); + }; +}; + +template<typename Scalar> +struct ei_abs_retval +{ + typedef typename NumTraits<Scalar>::Real type; +}; + +template<typename Scalar> +inline EIGEN_MATHFUNC_RETVAL(abs, Scalar) ei_abs(const Scalar& x) +{ + return EIGEN_MATHFUNC_IMPL(abs, Scalar)::run(x); } -/********************* -*** complex<float> *** -*********************/ - -inline float ei_real(const std::complex<float>& x) { return std::real(x); } -inline float ei_imag(const std::complex<float>& x) { return std::imag(x); } -inline float& ei_real_ref(std::complex<float>& x) { return reinterpret_cast<float*>(&x)[0]; } -inline float& ei_imag_ref(std::complex<float>& x) { return reinterpret_cast<float*>(&x)[1]; } -inline std::complex<float> ei_conj(const std::complex<float>& x) { return std::conj(x); } -inline float ei_abs(const std::complex<float>& x) { return std::abs(x); } -inline float ei_abs2(const std::complex<float>& x) { return std::norm(x); } -inline float ei_norm1(const std::complex<float> &x) { return(ei_abs(x.real()) + ei_abs(x.imag())); } -inline std::complex<float> ei_sqrt(std::complex<float>x) { return std::sqrt(x); } -inline std::complex<float> ei_exp(std::complex<float> x) { return std::exp(x); } -inline std::complex<float> ei_sin(std::complex<float> x) { return std::sin(x); } -inline std::complex<float> ei_cos(std::complex<float> x) { return std::cos(x); } -inline std::complex<float> ei_atan2(std::complex<float>, std::complex<float> ) { ei_assert(false); return 0.f; } - -template<> inline std::complex<float> ei_random() -{ - return std::complex<float>(ei_random<float>(), ei_random<float>()); +/**************************************************************************** +* Implementation of ei_abs2 * +****************************************************************************/ + +template<typename Scalar> +struct ei_abs2_impl +{ + typedef typename NumTraits<Scalar>::Real RealScalar; + static inline RealScalar run(const Scalar& x) + { + return x*x; + }; +}; + +template<typename RealScalar> +struct ei_abs2_impl<std::complex<RealScalar> > +{ + static inline RealScalar run(const std::complex<RealScalar>& x) + { + return std::norm(x); + }; +}; + +template<typename Scalar> +struct ei_abs2_retval +{ + typedef typename NumTraits<Scalar>::Real type; +}; + +template<typename Scalar> +inline EIGEN_MATHFUNC_RETVAL(abs2, Scalar) ei_abs2(const Scalar& x) +{ + return EIGEN_MATHFUNC_IMPL(abs2, Scalar)::run(x); } -inline bool ei_isMuchSmallerThan(const std::complex<float>& a, const std::complex<float>& b, float prec = NumTraits<float>::dummy_precision()) + +/**************************************************************************** +* Implementation of ei_norm1 * +****************************************************************************/ + +template<typename Scalar, bool IsComplex> +struct ei_norm1_default_impl +{ + typedef typename NumTraits<Scalar>::Real RealScalar; + static inline RealScalar run(const Scalar& x) + { + return ei_abs(ei_real(x)) + ei_abs(ei_imag(x)); + }; +}; + +template<typename Scalar> +struct ei_norm1_default_impl<Scalar, false> +{ + static inline Scalar run(const Scalar& x) + { + return ei_abs(x); + }; +}; + +template<typename Scalar> +struct ei_norm1_impl : ei_norm1_default_impl<Scalar, NumTraits<Scalar>::IsComplex> {}; + +template<typename Scalar> +struct ei_norm1_retval +{ + typedef typename NumTraits<Scalar>::Real type; +}; + +template<typename Scalar> +inline EIGEN_MATHFUNC_RETVAL(norm1, Scalar) ei_norm1(const Scalar& x) { - return ei_abs2(a) <= ei_abs2(b) * prec * prec; + return EIGEN_MATHFUNC_IMPL(norm1, Scalar)::run(x); } -inline bool ei_isMuchSmallerThan(const std::complex<float>& a, float b, float prec = NumTraits<float>::dummy_precision()) + +/**************************************************************************** +* Implementation of ei_hypot * +****************************************************************************/ + +template<typename Scalar> +struct ei_hypot_impl +{ + typedef typename NumTraits<Scalar>::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<typename Scalar> +struct ei_hypot_retval { - return ei_abs2(a) <= ei_abs2(b) * prec * prec; + typedef typename NumTraits<Scalar>::Real type; +}; + +template<typename Scalar> +inline EIGEN_MATHFUNC_RETVAL(hypot, Scalar) ei_hypot(const Scalar& x, const Scalar& y) +{ + return EIGEN_MATHFUNC_IMPL(hypot, Scalar)::run(x, y); } -inline bool ei_isApprox(const std::complex<float>& a, const std::complex<float>& b, float prec = NumTraits<float>::dummy_precision()) + +/**************************************************************************** +* Implementation of ei_cast * +****************************************************************************/ + +template<typename OldType, typename NewType> +struct ei_cast_impl { - return ei_isApprox(ei_real(a), ei_real(b), prec) - && ei_isApprox(ei_imag(a), ei_imag(b), prec); + static inline NewType run(const OldType& x) + { + return static_cast<NewType>(x); + } +}; + +// here, for once, we're plainly returning NewType: we don't want ei_cast to do weird things. + +template<typename OldType, typename NewType> +inline NewType ei_cast(const OldType& x) +{ + return ei_cast_impl<OldType, NewType>::run(x); } -// ei_isApproxOrLessThan wouldn't make sense for complex numbers - -/********************** -*** complex<double> *** -**********************/ - -inline double ei_real(const std::complex<double>& x) { return std::real(x); } -inline double ei_imag(const std::complex<double>& x) { return std::imag(x); } -inline double& ei_real_ref(std::complex<double>& x) { return reinterpret_cast<double*>(&x)[0]; } -inline double& ei_imag_ref(std::complex<double>& x) { return reinterpret_cast<double*>(&x)[1]; } -inline std::complex<double> ei_conj(const std::complex<double>& x) { return std::conj(x); } -inline double ei_abs(const std::complex<double>& x) { return std::abs(x); } -inline double ei_abs2(const std::complex<double>& x) { return std::norm(x); } -inline double ei_norm1(const std::complex<double> &x) { return(ei_abs(x.real()) + ei_abs(x.imag())); } -inline std::complex<double> ei_sqrt(std::complex<double>x) { return std::sqrt(x); } -inline std::complex<double> ei_exp(std::complex<double> x) { return std::exp(x); } -inline std::complex<double> ei_sin(std::complex<double> x) { return std::sin(x); } -inline std::complex<double> ei_cos(std::complex<double> x) { return std::cos(x); } -inline std::complex<double> ei_atan2(std::complex<double>, std::complex<double>) { ei_assert(false); return 0.; } - -template<> inline std::complex<double> ei_random() -{ - return std::complex<double>(ei_random<double>(), ei_random<double>()); + +/**************************************************************************** +* Implementation of ei_sqrt * +****************************************************************************/ + +template<typename Scalar, bool IsInteger> +struct ei_sqrt_default_impl +{ + static inline Scalar run(const Scalar& x) + { + return std::sqrt(x); + }; +}; + +template<typename Scalar> +struct ei_sqrt_default_impl<Scalar, true> +{ + static inline Scalar run(const Scalar&) + { + EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar) + return Scalar(0); + }; +}; + +template<typename Scalar> +struct ei_sqrt_impl : ei_sqrt_default_impl<Scalar, NumTraits<Scalar>::IsInteger> {}; + +template<typename Scalar> +struct ei_sqrt_retval +{ + typedef Scalar type; +}; + +template<typename Scalar> +inline EIGEN_MATHFUNC_RETVAL(sqrt, Scalar) ei_sqrt(const Scalar& x) +{ + return EIGEN_MATHFUNC_IMPL(sqrt, Scalar)::run(x); } -inline bool ei_isMuchSmallerThan(const std::complex<double>& a, const std::complex<double>& b, double prec = NumTraits<double>::dummy_precision()) + +/**************************************************************************** +* Implementation of ei_exp * +****************************************************************************/ + +template<typename Scalar, bool IsInteger> +struct ei_exp_default_impl +{ + static inline Scalar run(const Scalar& x) + { + return std::exp(x); + }; +}; + +template<typename Scalar> +struct ei_exp_default_impl<Scalar, true> { - return ei_abs2(a) <= ei_abs2(b) * prec * prec; + static inline Scalar run(const Scalar&) + { + EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar) + return Scalar(0); + }; +}; + +template<typename Scalar> +struct ei_exp_impl : ei_exp_default_impl<Scalar, NumTraits<Scalar>::IsInteger> {}; + +template<typename Scalar> +struct ei_exp_retval +{ + typedef Scalar type; +}; + +template<typename Scalar> +inline EIGEN_MATHFUNC_RETVAL(exp, Scalar) ei_exp(const Scalar& x) +{ + return EIGEN_MATHFUNC_IMPL(exp, Scalar)::run(x); } -inline bool ei_isMuchSmallerThan(const std::complex<double>& a, double b, double prec = NumTraits<double>::dummy_precision()) + +/**************************************************************************** +* Implementation of ei_cos * +****************************************************************************/ + +template<typename Scalar, bool IsInteger> +struct ei_cos_default_impl { - return ei_abs2(a) <= ei_abs2(b) * prec * prec; + static inline Scalar run(const Scalar& x) + { + return std::cos(x); + }; +}; + +template<typename Scalar> +struct ei_cos_default_impl<Scalar, true> +{ + static inline Scalar run(const Scalar&) + { + EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar) + return Scalar(0); + }; +}; + +template<typename Scalar> +struct ei_cos_impl : ei_cos_default_impl<Scalar, NumTraits<Scalar>::IsInteger> {}; + +template<typename Scalar> +struct ei_cos_retval +{ + typedef Scalar type; +}; + +template<typename Scalar> +inline EIGEN_MATHFUNC_RETVAL(cos, Scalar) ei_cos(const Scalar& x) +{ + return EIGEN_MATHFUNC_IMPL(cos, Scalar)::run(x); } -inline bool ei_isApprox(const std::complex<double>& a, const std::complex<double>& b, double prec = NumTraits<double>::dummy_precision()) + +/**************************************************************************** +* Implementation of ei_sin * +****************************************************************************/ + +template<typename Scalar, bool IsInteger> +struct ei_sin_default_impl +{ + static inline Scalar run(const Scalar& x) + { + return std::sin(x); + }; +}; + +template<typename Scalar> +struct ei_sin_default_impl<Scalar, true> +{ + static inline Scalar run(const Scalar&) + { + EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar) + return Scalar(0); + }; +}; + +template<typename Scalar> +struct ei_sin_impl : ei_sin_default_impl<Scalar, NumTraits<Scalar>::IsInteger> {}; + +template<typename Scalar> +struct ei_sin_retval +{ + typedef Scalar type; +}; + +template<typename Scalar> +inline EIGEN_MATHFUNC_RETVAL(sin, Scalar) ei_sin(const Scalar& x) { - return ei_isApprox(ei_real(a), ei_real(b), prec) - && ei_isApprox(ei_imag(a), ei_imag(b), prec); + return EIGEN_MATHFUNC_IMPL(sin, Scalar)::run(x); } -// ei_isApproxOrLessThan wouldn't make sense for complex numbers - - -/****************** -*** long double *** -******************/ - -inline long double ei_real(long double x) { return x; } -inline long double& ei_real_ref(long double& x) { return x; } -inline long double ei_imag(long double) { return 0.; } -inline long double ei_conj(long double x) { return x; } -inline long double ei_abs(long double x) { return std::abs(x); } -inline long double ei_abs2(long double x) { return x*x; } -inline long double ei_sqrt(long double x) { return std::sqrt(x); } -inline long double ei_exp(long double x) { return std::exp(x); } -inline long double ei_log(long double x) { return std::log(x); } -inline long double ei_sin(long double x) { return std::sin(x); } -inline long double ei_cos(long double x) { return std::cos(x); } -inline long double ei_atan2(long double y, long double x) { return std::atan2(y,x); } -inline long double ei_pow(long double x, long double y) { return std::pow(x, y); } - -template<> inline long double ei_random(long double a, long double b) -{ - return ei_random<double>(static_cast<double>(a),static_cast<double>(b)); + +/**************************************************************************** +* Implementation of ei_log * +****************************************************************************/ + +template<typename Scalar, bool IsInteger> +struct ei_log_default_impl +{ + static inline Scalar run(const Scalar& x) + { + return std::log(x); + }; +}; + +template<typename Scalar> +struct ei_log_default_impl<Scalar, true> +{ + static inline Scalar run(const Scalar&) + { + EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar) + return Scalar(0); + }; +}; + +template<typename Scalar> +struct ei_log_impl : ei_log_default_impl<Scalar, NumTraits<Scalar>::IsInteger> {}; + +template<typename Scalar> +struct ei_log_retval +{ + typedef Scalar type; +}; + +template<typename Scalar> +inline EIGEN_MATHFUNC_RETVAL(log, Scalar) ei_log(const Scalar& x) +{ + return EIGEN_MATHFUNC_IMPL(log, Scalar)::run(x); } -template<> inline long double ei_random() + +/**************************************************************************** +* Implementation of ei_atan2 * +****************************************************************************/ + +template<typename Scalar, bool IsInteger> +struct ei_atan2_default_impl +{ + typedef Scalar retval; + static inline Scalar run(const Scalar& x, const Scalar& y) + { + return std::atan2(x, y); + }; +}; + +template<typename Scalar> +struct ei_atan2_default_impl<Scalar, true> +{ + static inline Scalar run(const Scalar&, const Scalar&) + { + EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar) + return Scalar(0); + }; +}; + +template<typename Scalar> +struct ei_atan2_impl : ei_atan2_default_impl<Scalar, NumTraits<Scalar>::IsInteger> {}; + +template<typename Scalar> +struct ei_atan2_retval { - return ei_random<double>(-ei_random_amplitude<double>(), ei_random_amplitude<double>()); + typedef Scalar type; +}; + +template<typename Scalar> +inline EIGEN_MATHFUNC_RETVAL(atan2, Scalar) ei_atan2(const Scalar& x, const Scalar& y) +{ + return EIGEN_MATHFUNC_IMPL(atan2, Scalar)::run(x, y); } -inline bool ei_isMuchSmallerThan(long double a, long double b, long double prec = NumTraits<long double>::dummy_precision()) + +/**************************************************************************** +* Implementation of ei_pow * +****************************************************************************/ + +template<typename Scalar, bool IsInteger> +struct ei_pow_default_impl { - return ei_abs(a) <= ei_abs(b) * prec; + typedef Scalar retval; + static inline Scalar run(const Scalar& x, const Scalar& y) + { + return std::pow(x, y); + }; +}; + +template<typename Scalar> +struct ei_pow_default_impl<Scalar, true> +{ + static inline Scalar run(Scalar x, Scalar y) + { + int res = 1; + if(NumTraits<Scalar>::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<typename Scalar> +struct ei_pow_impl : ei_pow_default_impl<Scalar, NumTraits<Scalar>::IsInteger> {}; + +template<typename Scalar> +struct ei_pow_retval +{ + typedef Scalar type; +}; + +template<typename Scalar> +inline EIGEN_MATHFUNC_RETVAL(pow, Scalar) ei_pow(const Scalar& x, const Scalar& y) +{ + return EIGEN_MATHFUNC_IMPL(pow, Scalar)::run(x, y); } -inline bool ei_isApprox(long double a, long double b, long double prec = NumTraits<long double>::dummy_precision()) + +/**************************************************************************** +* Implementation of ei_random * +****************************************************************************/ + +template<typename Scalar, + bool IsComplex, + bool IsInteger> +struct ei_random_default_impl {}; + +template<typename Scalar> +struct ei_random_impl : ei_random_default_impl<Scalar, NumTraits<Scalar>::IsComplex, NumTraits<Scalar>::IsInteger> {}; + +template<typename Scalar> +struct ei_random_retval { - return ei_abs(a - b) <= std::min(ei_abs(a), ei_abs(b)) * prec; + typedef Scalar type; +}; + +template<typename Scalar> inline EIGEN_MATHFUNC_RETVAL(random, Scalar) ei_random(const Scalar& x, const Scalar& y); +template<typename Scalar> inline EIGEN_MATHFUNC_RETVAL(random, Scalar) ei_random(); + +template<typename Scalar> +struct ei_random_default_impl<Scalar, false, false> +{ + 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<Scalar>::IsSigned ? -1 : 0), Scalar(1)); + }; +}; + +template<typename Scalar> +struct ei_random_default_impl<Scalar, false, true> +{ + static inline Scalar run(const Scalar& x, const Scalar& y) + { + return x + Scalar((y-x+1) * (std::rand() / (RAND_MAX + typename NumTraits<Scalar>::NonInteger(1)))); + }; + static inline Scalar run() + { + return run(Scalar(NumTraits<Scalar>::IsSigned ? -10 : 0), Scalar(10)); + }; +}; + +template<typename Scalar> +struct ei_random_default_impl<Scalar, true, false> +{ + 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<Scalar>::Real RealScalar; + return Scalar(ei_random<RealScalar>(), ei_random<RealScalar>()); + }; +}; + +template<typename Scalar> +inline EIGEN_MATHFUNC_RETVAL(random, Scalar) ei_random(const Scalar& x, const Scalar& y) +{ + return EIGEN_MATHFUNC_IMPL(random, Scalar)::run(x, y); } -inline bool ei_isApproxOrLessThan(long double a, long double b, long double prec = NumTraits<long double>::dummy_precision()) + +template<typename Scalar> +inline EIGEN_MATHFUNC_RETVAL(random, Scalar) ei_random() { - return a <= b || ei_isApprox(a, b, prec); + return EIGEN_MATHFUNC_IMPL(random, Scalar)::run(); } -/************** -*** bool *** -**************/ +/**************************************************************************** +* Implementation of fuzzy comparisons * +****************************************************************************/ -inline bool ei_real(bool x) { return x; } -inline bool& ei_real_ref(bool& x) { return x; } -inline bool ei_imag(bool) { return 0; } -inline bool ei_conj(bool x) { return x; } -inline bool ei_abs(bool x) { return x; } -inline bool ei_abs2(bool x) { return x; } -inline bool ei_sqrt(bool x) { return x; } +template<typename Scalar, + bool IsComplex, + bool IsInteger> +struct ei_scalar_fuzzy_default_impl {}; -template<> inline bool ei_random() +template<typename Scalar> +struct ei_scalar_fuzzy_default_impl<Scalar, false, false> { - return (ei_random<int>(0,1) == 1); -} -inline bool ei_isMuchSmallerThan(bool a, bool, bool = NumTraits<bool>::dummy_precision()) + typedef typename NumTraits<Scalar>::Real RealScalar; + template<typename OtherScalar> + 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<typename Scalar> +struct ei_scalar_fuzzy_default_impl<Scalar, false, true> +{ + typedef typename NumTraits<Scalar>::Real RealScalar; + template<typename OtherScalar> + 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<typename Scalar> +struct ei_scalar_fuzzy_default_impl<Scalar, true, false> +{ + typedef typename NumTraits<Scalar>::Real RealScalar; + template<typename OtherScalar> + 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<typename Scalar> +struct ei_scalar_fuzzy_impl : ei_scalar_fuzzy_default_impl<Scalar, NumTraits<Scalar>::IsComplex, NumTraits<Scalar>::IsInteger> {}; + +template<typename Scalar, typename OtherScalar> +inline bool ei_isMuchSmallerThan(const Scalar& x, const OtherScalar& y, + typename NumTraits<Scalar>::Real precision = NumTraits<Scalar>::dummy_precision()) { - return !a; + return ei_scalar_fuzzy_impl<Scalar>::template isMuchSmallerThan<OtherScalar>(x, y, precision); } -inline bool ei_isApprox(bool a, bool b, bool = NumTraits<bool>::dummy_precision()) + +template<typename Scalar> +inline bool ei_isApprox(const Scalar& x, const Scalar& y, + typename NumTraits<Scalar>::Real precision = NumTraits<Scalar>::dummy_precision()) { - return a == b; + return ei_scalar_fuzzy_impl<Scalar>::isApprox(x, y, precision); } -inline bool ei_isApproxOrLessThan(bool a, bool b, bool = NumTraits<bool>::dummy_precision()) + +template<typename Scalar> +inline bool ei_isApproxOrLessThan(const Scalar& x, const Scalar& y, + typename NumTraits<Scalar>::Real precision = NumTraits<Scalar>::dummy_precision()) { - return int(a) <= int(b); + return ei_scalar_fuzzy_impl<Scalar>::isApproxOrLessThan(x, y, precision); } +/****************************************** +*** The special case of the bool type *** +******************************************/ + +template<> struct ei_random_impl<bool> +{ + static inline bool run() + { + return bool(ei_random<int>(0,1)); + }; +}; + +template<> struct ei_scalar_fuzzy_impl<bool> +{ + static inline bool isApprox(bool x, bool y, bool) + { + return x == y; + }; +}; + #endif // EIGEN_MATHFUNCTIONS_H diff --git a/Eigen/src/Core/NumTraits.h b/Eigen/src/Core/NumTraits.h index 37787b569..76bf8a58f 100644 --- a/Eigen/src/Core/NumTraits.h +++ b/Eigen/src/Core/NumTraits.h @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com> +// Copyright (C) 2006-2010 Benoit Jacob <jacob.benoit.1@gmail.com> // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -27,157 +27,121 @@ /** \class NumTraits * - * \brief Holds some data about the various numeric (i.e. scalar) types allowed by Eigen. + * \brief Holds information about the various numeric (i.e. scalar) types allowed by Eigen. * - * \param T the numeric type about which this class provides data. Recall that Eigen allows - * only the following types for \a T: \c int, \c float, \c double, - * \c std::complex<float>, \c std::complex<double>, and \c long \c double (especially - * useful to enforce x87 arithmetics when SSE is the default). + * \param T the numeric type at hand * - * The provided data consists of everything that is supported by std::numeric_limits, plus: + * 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<U> then \a Real * is a typedef to \a U. - * \li A typedef \a FloatingPoint, giving the "floating-point type" of \a T. If \a T is - * \c int, then \a FloatingPoint is a typedef to \c double. Otherwise, \a FloatingPoint - * is a typedef to \a T. + * \li A typedef \a 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 ei_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 \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 * type, and to 0 otherwise. - * \li An enum \a HasFloatingPoint. It is equal to \c 0 if \a T is \c int, - * and to \c 1 otherwise. + * \li An enum value \a IsInteger. It is equal to \c 1 if \a T is an integer type such as \c int, + * and to \c 0 otherwise. + * \li Enum values ReadCost, AddCost and MulCost representing a rough estimate of the number of CPU cycles needed + * to by move / add / mul instructions respectively, assuming the data is already stored in CPU registers. + * Stay vague here. No need to do architecture-specific stuff. + * \li An enum value \a IsSigned. It is equal to \c 1 if \a T is a signed type and to 0 if \a T is unsigned. * \li An epsilon() function which, unlike std::numeric_limits::epsilon(), returns a \a Real instead of a \a T. - * \li A dummy_precision() function returning a weak epsilon value. It is mainly used by the fuzzy comparison operators. - * \li Two highest() and lowest() functions returning the highest and lowest possible values respectively. + * \li A dummy_precision() function returning a weak epsilon value. It is mainly used as a default + * value by the fuzzy comparison operators. + * \li highest() and lowest() functions returning the highest and lowest possible values respectively. */ -template<typename T> struct NumTraits; - -template<typename T> struct ei_default_float_numtraits - : std::numeric_limits<T> -{ - inline static T highest() { return std::numeric_limits<T>::max(); } - inline static T lowest() { return -std::numeric_limits<T>::max(); } -}; - -template<typename T> struct ei_default_integral_numtraits - : std::numeric_limits<T> -{ - inline static T dummy_precision() { return T(0); } - inline static T highest() { return std::numeric_limits<T>::max(); } - inline static T lowest() { return std::numeric_limits<T>::min(); } -}; -template<> struct NumTraits<int> - : ei_default_integral_numtraits<int> +template<typename T> struct GenericNumTraits { - typedef int Real; - typedef double FloatingPoint; - typedef int Nested; enum { + IsInteger = std::numeric_limits<T>::is_integer, + IsSigned = std::numeric_limits<T>::is_signed, IsComplex = 0, - HasFloatingPoint = 0, ReadCost = 1, AddCost = 1, MulCost = 1 }; + + typedef T Real; + typedef typename ei_meta_if< + IsInteger, + typename ei_meta_if<sizeof(T)<=2, float, double>::ret, + T + >::ret NonInteger; + typedef T Nested; + + inline static Real epsilon() { return std::numeric_limits<T>::epsilon(); } + inline static Real dummy_precision() + { + // make sure to override this for floating-point types + return Real(0); + } + inline static T highest() { return std::numeric_limits<T>::max(); } + inline static T lowest() { return std::numeric_limits<T>::min(); } }; +template<typename T> struct NumTraits : GenericNumTraits<T> +{}; + template<> struct NumTraits<float> - : ei_default_float_numtraits<float> + : GenericNumTraits<float> { - typedef float Real; - typedef float FloatingPoint; - typedef float Nested; - enum { - IsComplex = 0, - HasFloatingPoint = 1, - ReadCost = 1, - AddCost = 1, - MulCost = 1 - }; - inline static float dummy_precision() { return 1e-5f; } }; -template<> struct NumTraits<double> - : ei_default_float_numtraits<double> +template<> struct NumTraits<double> : GenericNumTraits<double> { - typedef double Real; - typedef double FloatingPoint; - typedef double Nested; - enum { - IsComplex = 0, - HasFloatingPoint = 1, - ReadCost = 1, - AddCost = 1, - MulCost = 1 - }; - inline static double dummy_precision() { return 1e-12; } }; +template<> struct NumTraits<long double> + : GenericNumTraits<long double> +{ + static inline long double dummy_precision() { return 1e-15l; } +}; + template<typename _Real> struct NumTraits<std::complex<_Real> > - : ei_default_float_numtraits<std::complex<_Real> > + : GenericNumTraits<std::complex<_Real> > { typedef _Real Real; - typedef std::complex<_Real> FloatingPoint; - typedef std::complex<_Real> Nested; enum { IsComplex = 1, - HasFloatingPoint = NumTraits<Real>::HasFloatingPoint, ReadCost = 2, AddCost = 2 * NumTraits<Real>::AddCost, MulCost = 4 * NumTraits<Real>::MulCost + 2 * NumTraits<Real>::AddCost }; - inline static Real epsilon() { return std::numeric_limits<Real>::epsilon(); } + inline static Real epsilon() { return NumTraits<Real>::epsilon(); } inline static Real dummy_precision() { return NumTraits<Real>::dummy_precision(); } }; -template<> struct NumTraits<long long int> - : ei_default_integral_numtraits<long long int> +template<typename Scalar, int Rows, int Cols, int Options, int MaxRows, int MaxCols> +struct NumTraits<Array<Scalar, Rows, Cols, Options, MaxRows, MaxCols> > { - typedef long long int Real; - typedef long double FloatingPoint; - typedef long long int Nested; + typedef Array<Scalar, Rows, Cols, Options, MaxRows, MaxCols> ArrayType; + typedef typename NumTraits<Scalar>::Real RealScalar; + typedef Array<RealScalar, Rows, Cols, Options, MaxRows, MaxCols> Real; + typedef typename NumTraits<Scalar>::NonInteger NonIntegerScalar; + typedef Array<NonIntegerScalar, Rows, Cols, Options, MaxRows, MaxCols> NonInteger; + typedef ArrayType & Nested; + enum { - IsComplex = 0, - HasFloatingPoint = 0, - ReadCost = 1, - AddCost = 1, - MulCost = 1 + IsComplex = NumTraits<Scalar>::IsComplex, + IsInteger = NumTraits<Scalar>::IsInteger, + IsSigned = NumTraits<Scalar>::IsSigned, + ReadCost = ArrayType::SizeAtCompileTime==Dynamic ? Dynamic : ArrayType::SizeAtCompileTime * NumTraits<Scalar>::ReadCost, + AddCost = ArrayType::SizeAtCompileTime==Dynamic ? Dynamic : ArrayType::SizeAtCompileTime * NumTraits<Scalar>::AddCost, + MulCost = ArrayType::SizeAtCompileTime==Dynamic ? Dynamic : ArrayType::SizeAtCompileTime * NumTraits<Scalar>::MulCost }; }; -template<> struct NumTraits<long double> - : ei_default_float_numtraits<long double> -{ - typedef long double Real; - typedef long double FloatingPoint; - typedef long double Nested; - enum { - IsComplex = 0, - HasFloatingPoint = 1, - ReadCost = 1, - AddCost = 1, - MulCost = 1 - }; - - static inline long double dummy_precision() { return NumTraits<double>::dummy_precision(); } -}; -template<> struct NumTraits<bool> - : ei_default_integral_numtraits<bool> -{ - typedef bool Real; - typedef float FloatingPoint; - typedef bool Nested; - enum { - IsComplex = 0, - HasFloatingPoint = 0, - ReadCost = 1, - AddCost = 1, - MulCost = 1 - }; -}; #endif // EIGEN_NUMTRAITS_H diff --git a/Eigen/src/Core/SelfCwiseBinaryOp.h b/Eigen/src/Core/SelfCwiseBinaryOp.h index 31d7edc31..f8f8a9f86 100644 --- a/Eigen/src/Core/SelfCwiseBinaryOp.h +++ b/Eigen/src/Core/SelfCwiseBinaryOp.h @@ -133,9 +133,11 @@ inline Derived& DenseBase<Derived>::operator*=(const Scalar& other) template<typename Derived> inline Derived& DenseBase<Derived>::operator/=(const Scalar& other) { - SelfCwiseBinaryOp<typename ei_meta_if<NumTraits<Scalar>::HasFloatingPoint,ei_scalar_product_op<Scalar>,ei_scalar_quotient_op<Scalar> >::ret, Derived> tmp(derived()); + SelfCwiseBinaryOp<typename ei_meta_if<NumTraits<Scalar>::IsInteger, + ei_scalar_quotient_op<Scalar>, + ei_scalar_product_op<Scalar> >::ret, Derived> tmp(derived()); typedef typename Derived::PlainObject PlainObject; - tmp = PlainObject::Constant(rows(),cols(), NumTraits<Scalar>::HasFloatingPoint ? Scalar(1)/other : other); + tmp = PlainObject::Constant(rows(),cols(), NumTraits<Scalar>::IsInteger ? other : Scalar(1)/other); return derived(); } diff --git a/Eigen/src/Core/util/StaticAssert.h b/Eigen/src/Core/util/StaticAssert.h index 31f7d0038..cf0db2901 100644 --- a/Eigen/src/Core/util/StaticAssert.h +++ b/Eigen/src/Core/util/StaticAssert.h @@ -65,7 +65,7 @@ YOU_CALLED_A_FIXED_SIZE_METHOD_ON_A_DYNAMIC_SIZE_MATRIX_OR_VECTOR, YOU_CALLED_A_DYNAMIC_SIZE_METHOD_ON_A_FIXED_SIZE_MATRIX_OR_VECTOR, UNALIGNED_LOAD_AND_STORE_OPERATIONS_UNIMPLEMENTED_ON_ALTIVEC, - NUMERIC_TYPE_MUST_BE_FLOATING_POINT, + THIS_FUNCTION_IS_NOT_FOR_INTEGER_NUMERIC_TYPES, NUMERIC_TYPE_MUST_BE_REAL, COEFFICIENT_WRITE_ACCESS_TO_SELFADJOINT_NOT_SUPPORTED, WRITING_TO_TRIANGULAR_PART_WITH_UNIT_DIAGONAL_IS_NOT_SUPPORTED, @@ -158,6 +158,9 @@ ) \ ) +#define EIGEN_STATIC_ASSERT_NON_INTEGER(TYPE) \ + EIGEN_STATIC_ASSERT(!NumTraits<TYPE>::IsInteger, THIS_FUNCTION_IS_NOT_FOR_INTEGER_NUMERIC_TYPES) + // static assertion failing if it is guaranteed at compile-time that the two matrix expression types have different sizes #define EIGEN_STATIC_ASSERT_SAME_MATRIX_SIZE(TYPE0,TYPE1) \ EIGEN_STATIC_ASSERT( \ diff --git a/Eigen/src/Geometry/AlignedBox.h b/Eigen/src/Geometry/AlignedBox.h index b5b40a82d..f3bee6f7d 100644 --- a/Eigen/src/Geometry/AlignedBox.h +++ b/Eigen/src/Geometry/AlignedBox.h @@ -46,7 +46,7 @@ EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(_Scalar,_AmbientDim) typedef _Scalar Scalar; typedef NumTraits<Scalar> ScalarTraits; typedef typename ScalarTraits::Real RealScalar; - typedef typename ScalarTraits::FloatingPoint FloatingPoint; + typedef typename ScalarTraits::NonInteger NonInteger; typedef Matrix<Scalar,AmbientDimAtCompileTime,1> VectorType; /** Define constants to name the corners of a 1D, 2D or 3D axis aligned bounding box */ @@ -174,11 +174,10 @@ EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(_Scalar,_AmbientDim) VectorType r; for(int d=0; d<dim(); ++d) { - if(ScalarTraits::HasFloatingPoint) + if(!ScalarTraits::IsInteger) { r[d] = m_min[d] + (m_max[d]-m_min[d]) - * (ei_random<Scalar>() + ei_random_amplitude<Scalar>()) - / (Scalar(2)*ei_random_amplitude<Scalar>() ); + * ei_random<Scalar>(Scalar(0), Scalar(1)); } else r[d] = ei_random(m_min[d], m_max[d]); @@ -260,15 +259,15 @@ EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(_Scalar,_AmbientDim) * \sa squaredExteriorDistance() */ template<typename Derived> - inline FloatingPoint exteriorDistance(const MatrixBase<Derived>& p) const - { return ei_sqrt(FloatingPoint(squaredExteriorDistance(p))); } + inline NonInteger exteriorDistance(const MatrixBase<Derived>& p) const + { return ei_sqrt(NonInteger(squaredExteriorDistance(p))); } /** \returns the distance between the boxes \a b and \c *this, * and zero if the boxes intersect. * \sa squaredExteriorDistance() */ - inline FloatingPoint exteriorDistance(const AlignedBox& b) const - { return ei_sqrt(FloatingPoint(squaredExteriorDistance(b))); } + inline NonInteger exteriorDistance(const AlignedBox& b) const + { return ei_sqrt(NonInteger(squaredExteriorDistance(b))); } /** \returns \c *this with scalar type casted to \a NewScalarType * diff --git a/Eigen/src/LU/Inverse.h b/Eigen/src/LU/Inverse.h index 8e9012048..9e0c46094 100644 --- a/Eigen/src/LU/Inverse.h +++ b/Eigen/src/LU/Inverse.h @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2008-2009 Benoit Jacob <jacob.benoit.1@gmail.com> +// Copyright (C) 2008-2010 Benoit Jacob <jacob.benoit.1@gmail.com> // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -325,7 +325,7 @@ struct ei_inverse_impl : public ReturnByValue<ei_inverse_impl<MatrixType> > template<typename Derived> inline const ei_inverse_impl<Derived> MatrixBase<Derived>::inverse() const { - EIGEN_STATIC_ASSERT(NumTraits<Scalar>::HasFloatingPoint,NUMERIC_TYPE_MUST_BE_FLOATING_POINT) + EIGEN_STATIC_ASSERT(!NumTraits<Scalar>::IsInteger,THIS_FUNCTION_IS_NOT_FOR_INTEGER_NUMERIC_TYPES) ei_assert(rows() == cols()); return ei_inverse_impl<Derived>(derived()); } diff --git a/Eigen/src/LeastSquares/CMakeLists.txt b/Eigen/src/LeastSquares/CMakeLists.txt deleted file mode 100644 index 89ccca542..000000000 --- a/Eigen/src/LeastSquares/CMakeLists.txt +++ /dev/null @@ -1,6 +0,0 @@ -FILE(GLOB Eigen_LeastSquares_SRCS "*.h") - -INSTALL(FILES - ${Eigen_LeastSquares_SRCS} - DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen/src/LeastSquares COMPONENT Devel - ) diff --git a/Eigen/src/LeastSquares/LeastSquares.h b/Eigen/src/LeastSquares/LeastSquares.h deleted file mode 100644 index e0e9af1bc..000000000 --- a/Eigen/src/LeastSquares/LeastSquares.h +++ /dev/null @@ -1,181 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2006-2009 Benoit Jacob <jacob.benoit.1@gmail.com> -// -// 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 <http://www.gnu.org/licenses/>. - -#ifndef EIGEN_LEASTSQUARES_H -#define EIGEN_LEASTSQUARES_H - -/** \ingroup LeastSquares_Module - * - * \leastsquares_module - * - * For a set of points, this function tries to express - * one of the coords as a linear (affine) function of the other coords. - * - * This is best explained by an example. This function works in full - * generality, for points in a space of arbitrary dimension, and also over - * the complex numbers, but for this example we will work in dimension 3 - * over the real numbers (doubles). - * - * So let us work with the following set of 5 points given by their - * \f$(x,y,z)\f$ coordinates: - * @code - Vector3d points[5]; - points[0] = Vector3d( 3.02, 6.89, -4.32 ); - points[1] = Vector3d( 2.01, 5.39, -3.79 ); - points[2] = Vector3d( 2.41, 6.01, -4.01 ); - points[3] = Vector3d( 2.09, 5.55, -3.86 ); - points[4] = Vector3d( 2.58, 6.32, -4.10 ); - * @endcode - * Suppose that we want to express the second coordinate (\f$y\f$) as a linear - * expression in \f$x\f$ and \f$z\f$, that is, - * \f[ y=ax+bz+c \f] - * for some constants \f$a,b,c\f$. Thus, we want to find the best possible - * constants \f$a,b,c\f$ so that the plane of equation \f$y=ax+bz+c\f$ fits - * best the five above points. To do that, call this function as follows: - * @code - Vector3d coeffs; // will store the coefficients a, b, c - linearRegression( - 5, - &points, - &coeffs, - 1 // the coord to express as a function of - // the other ones. 0 means x, 1 means y, 2 means z. - ); - * @endcode - * Now the vector \a coeffs is approximately - * \f$( 0.495 , -1.927 , -2.906 )\f$. - * Thus, we get \f$a=0.495, b = -1.927, c = -2.906\f$. Let us check for - * instance how near points[0] is from the plane of equation \f$y=ax+bz+c\f$. - * Looking at the coords of points[0], we see that: - * \f[ax+bz+c = 0.495 * 3.02 + (-1.927) * (-4.32) + (-2.906) = 6.91.\f] - * On the other hand, we have \f$y=6.89\f$. We see that the values - * \f$6.91\f$ and \f$6.89\f$ - * are near, so points[0] is very near the plane of equation \f$y=ax+bz+c\f$. - * - * Let's now describe precisely the parameters: - * @param numPoints the number of points - * @param points the array of pointers to the points on which to perform the linear regression - * @param result pointer to the vector in which to store the result. - This vector must be of the same type and size as the - data points. The meaning of its coords is as follows. - For brevity, let \f$n=Size\f$, - \f$r_i=result[i]\f$, - and \f$f=funcOfOthers\f$. Denote by - \f$x_0,\ldots,x_{n-1}\f$ - the n coordinates in the n-dimensional space. - Then the resulting equation is: - \f[ x_f = r_0 x_0 + \cdots + r_{f-1}x_{f-1} - + r_{f+1}x_{f+1} + \cdots + r_{n-1}x_{n-1} + r_n. \f] - * @param funcOfOthers Determines which coord to express as a function of the - others. Coords are numbered starting from 0, so that a - value of 0 means \f$x\f$, 1 means \f$y\f$, - 2 means \f$z\f$, ... - * - * \sa fitHyperplane() - */ -template<typename VectorType> -void linearRegression(int numPoints, - VectorType **points, - VectorType *result, - int funcOfOthers ) -{ - typedef typename VectorType::Scalar Scalar; - typedef Hyperplane<Scalar, VectorType::SizeAtCompileTime> HyperplaneType; - const int size = points[0]->size(); - result->resize(size); - HyperplaneType h(size); - fitHyperplane(numPoints, points, &h); - for(int i = 0; i < funcOfOthers; i++) - result->coeffRef(i) = - h.coeffs()[i] / h.coeffs()[funcOfOthers]; - for(int i = funcOfOthers; i < size; i++) - result->coeffRef(i) = - h.coeffs()[i+1] / h.coeffs()[funcOfOthers]; -} - -/** \ingroup LeastSquares_Module - * - * \leastsquares_module - * - * This function is quite similar to linearRegression(), so we refer to the - * documentation of this function and only list here the differences. - * - * The main difference from linearRegression() is that this function doesn't - * take a \a funcOfOthers argument. Instead, it finds a general equation - * of the form - * \f[ r_0 x_0 + \cdots + r_{n-1}x_{n-1} + r_n = 0, \f] - * where \f$n=Size\f$, \f$r_i=retCoefficients[i]\f$, and we denote by - * \f$x_0,\ldots,x_{n-1}\f$ the n coordinates in the n-dimensional space. - * - * Thus, the vector \a retCoefficients has size \f$n+1\f$, which is another - * difference from linearRegression(). - * - * In practice, this function performs an hyper-plane fit in a total least square sense - * via the following steps: - * 1 - center the data to the mean - * 2 - compute the covariance matrix - * 3 - pick the eigenvector corresponding to the smallest eigenvalue of the covariance matrix - * The ratio of the smallest eigenvalue and the second one gives us a hint about the relevance - * of the solution. This value is optionally returned in \a soundness. - * - * \sa linearRegression() - */ -template<typename VectorType, typename HyperplaneType> -void fitHyperplane(int numPoints, - VectorType **points, - HyperplaneType *result, - typename NumTraits<typename VectorType::Scalar>::Real* soundness = 0) -{ - typedef typename VectorType::Scalar Scalar; - typedef Matrix<Scalar,VectorType::SizeAtCompileTime,VectorType::SizeAtCompileTime> CovMatrixType; - EIGEN_STATIC_ASSERT_VECTOR_ONLY(VectorType) - ei_assert(numPoints >= 1); - int size = points[0]->size(); - ei_assert(size+1 == result->coeffs().size()); - - // compute the mean of the data - VectorType mean = VectorType::Zero(size); - for(int i = 0; i < numPoints; ++i) - mean += *(points[i]); - mean /= numPoints; - - // compute the covariance matrix - CovMatrixType covMat = CovMatrixType::Zero(size, size); - for(int i = 0; i < numPoints; ++i) - { - VectorType diff = (*(points[i]) - mean).conjugate(); - covMat += diff * diff.adjoint(); - } - - // now we just have to pick the eigen vector with smallest eigen value - SelfAdjointEigenSolver<CovMatrixType> eig(covMat); - result->normal() = eig.eigenvectors().col(0); - if (soundness) - *soundness = eig.eigenvalues().coeff(0)/eig.eigenvalues().coeff(1); - - // let's compute the constant coefficient such that the - // plane pass trough the mean point: - result->offset() = - (result->normal().cwiseProduct(mean)).sum(); -} - - -#endif // EIGEN_LEASTSQUARES_H |