diff --git a/uppsrc/plugin/Eigen/Eigen/CMakeLists.txt b/uppsrc/plugin/Eigen/Eigen/CMakeLists.txt new file mode 100644 index 000000000..a92dd6f6c --- /dev/null +++ b/uppsrc/plugin/Eigen/Eigen/CMakeLists.txt @@ -0,0 +1,19 @@ +include(RegexUtils) +test_escape_string_as_regex() + +file(GLOB Eigen_directory_files "*") + +escape_string_as_regex(ESCAPED_CMAKE_CURRENT_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}") + +foreach(f ${Eigen_directory_files}) + if(NOT f MATCHES "\\.txt" AND NOT f MATCHES "${ESCAPED_CMAKE_CURRENT_SOURCE_DIR}/[.].+" AND NOT f MATCHES "${ESCAPED_CMAKE_CURRENT_SOURCE_DIR}/src") + list(APPEND Eigen_directory_files_to_install ${f}) + endif() +endforeach(f ${Eigen_directory_files}) + +install(FILES + ${Eigen_directory_files_to_install} + DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen COMPONENT Devel + ) + +add_subdirectory(src) diff --git a/uppsrc/plugin/Eigen/Eigen/Core b/uppsrc/plugin/Eigen/Eigen/Core index c87f99df3..509c529e1 100644 --- a/uppsrc/plugin/Eigen/Eigen/Core +++ b/uppsrc/plugin/Eigen/Eigen/Core @@ -123,7 +123,7 @@ #undef bool #undef vector #undef pixel - #elif defined __ARM_NEON__ + #elif defined __ARM_NEON #define EIGEN_VECTORIZE #define EIGEN_VECTORIZE_NEON #include diff --git a/uppsrc/plugin/Eigen/Eigen/src/CMakeLists.txt b/uppsrc/plugin/Eigen/Eigen/src/CMakeLists.txt new file mode 100644 index 000000000..c326f374d --- /dev/null +++ b/uppsrc/plugin/Eigen/Eigen/src/CMakeLists.txt @@ -0,0 +1,7 @@ +file(GLOB Eigen_src_subdirectories "*") +escape_string_as_regex(ESCAPED_CMAKE_CURRENT_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}") +foreach(f ${Eigen_src_subdirectories}) + if(NOT f MATCHES "\\.txt" AND NOT f MATCHES "${ESCAPED_CMAKE_CURRENT_SOURCE_DIR}/[.].+" ) + add_subdirectory(${f}) + endif() +endforeach() diff --git a/uppsrc/plugin/Eigen/Eigen/src/Cholesky/CMakeLists.txt b/uppsrc/plugin/Eigen/Eigen/src/Cholesky/CMakeLists.txt new file mode 100644 index 000000000..d01488b41 --- /dev/null +++ b/uppsrc/plugin/Eigen/Eigen/src/Cholesky/CMakeLists.txt @@ -0,0 +1,6 @@ +FILE(GLOB Eigen_Cholesky_SRCS "*.h") + +INSTALL(FILES + ${Eigen_Cholesky_SRCS} + DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen/src/Cholesky COMPONENT Devel + ) diff --git a/uppsrc/plugin/Eigen/Eigen/src/Cholesky/LDLT.h b/uppsrc/plugin/Eigen/Eigen/src/Cholesky/LDLT.h index 02ab93880..e01ae8233 100644 --- a/uppsrc/plugin/Eigen/Eigen/src/Cholesky/LDLT.h +++ b/uppsrc/plugin/Eigen/Eigen/src/Cholesky/LDLT.h @@ -235,6 +235,11 @@ template class LDLT } protected: + + static void check_template_parameters() + { + EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar); + } /** \internal * Used to compute and store the Cholesky decomposition A = L D L^* = U^* D U. @@ -434,6 +439,8 @@ template struct LDLT_Traits template LDLT& LDLT::compute(const MatrixType& a) { + check_template_parameters(); + eigen_assert(a.rows()==a.cols()); const Index size = a.rows(); diff --git a/uppsrc/plugin/Eigen/Eigen/src/Cholesky/LLT.h b/uppsrc/plugin/Eigen/Eigen/src/Cholesky/LLT.h index 2e6189f7d..59723a63d 100644 --- a/uppsrc/plugin/Eigen/Eigen/src/Cholesky/LLT.h +++ b/uppsrc/plugin/Eigen/Eigen/src/Cholesky/LLT.h @@ -174,6 +174,12 @@ template class LLT LLT rankUpdate(const VectorType& vec, const RealScalar& sigma = 1); protected: + + static void check_template_parameters() + { + EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar); + } + /** \internal * Used to compute and store L * The strict upper part is not used and even not initialized. @@ -384,6 +390,8 @@ template struct LLT_Traits template LLT& LLT::compute(const MatrixType& a) { + check_template_parameters(); + eigen_assert(a.rows()==a.cols()); const Index size = a.rows(); m_matrix.resize(size, size); diff --git a/uppsrc/plugin/Eigen/Eigen/src/Cholesky/LLT_MKL.h b/uppsrc/plugin/Eigen/Eigen/src/Cholesky/LLT_MKL.h index 64daa445c..66675d747 100644 --- a/uppsrc/plugin/Eigen/Eigen/src/Cholesky/LLT_MKL.h +++ b/uppsrc/plugin/Eigen/Eigen/src/Cholesky/LLT_MKL.h @@ -60,7 +60,7 @@ template<> struct mkl_llt \ lda = m.outerStride(); \ \ info = LAPACKE_##MKLPREFIX##potrf( matrix_order, uplo, size, (MKLTYPE*)a, lda ); \ - info = (info==0) ? Success : NumericalIssue; \ + info = (info==0) ? -1 : info>0 ? info-1 : size; \ return info; \ } \ }; \ diff --git a/uppsrc/plugin/Eigen/Eigen/src/CholmodSupport/CMakeLists.txt b/uppsrc/plugin/Eigen/Eigen/src/CholmodSupport/CMakeLists.txt new file mode 100644 index 000000000..814dfa613 --- /dev/null +++ b/uppsrc/plugin/Eigen/Eigen/src/CholmodSupport/CMakeLists.txt @@ -0,0 +1,6 @@ +FILE(GLOB Eigen_CholmodSupport_SRCS "*.h") + +INSTALL(FILES + ${Eigen_CholmodSupport_SRCS} + DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen/src/CholmodSupport COMPONENT Devel + ) diff --git a/uppsrc/plugin/Eigen/Eigen/src/Core/Assign.h b/uppsrc/plugin/Eigen/Eigen/src/Core/Assign.h index 1dccc2f42..bcfc261e5 100644 --- a/uppsrc/plugin/Eigen/Eigen/src/Core/Assign.h +++ b/uppsrc/plugin/Eigen/Eigen/src/Core/Assign.h @@ -439,19 +439,26 @@ struct assign_impl PacketTraits; + typedef typename Derived1::Scalar Scalar; + typedef packet_traits PacketTraits; enum { packetSize = PacketTraits::size, alignable = PacketTraits::AlignedOnScalar, - dstAlignment = alignable ? Aligned : int(assign_traits::DstIsAligned) , + dstIsAligned = assign_traits::DstIsAligned, + dstAlignment = alignable ? Aligned : int(dstIsAligned), srcAlignment = assign_traits::JointAlignment }; + const Scalar *dst_ptr = &dst.coeffRef(0,0); + if((!bool(dstIsAligned)) && (Index(dst_ptr) % sizeof(Scalar))>0) + { + // the pointer is not aligend-on scalar, so alignment is not possible + return assign_impl::run(dst, src); + } const Index packetAlignedMask = packetSize - 1; const Index innerSize = dst.innerSize(); const Index outerSize = dst.outerSize(); const Index alignedStep = alignable ? (packetSize - dst.outerStride() % packetSize) & packetAlignedMask : 0; - Index alignedStart = ((!alignable) || assign_traits::DstIsAligned) ? 0 - : internal::first_aligned(&dst.coeffRef(0,0), innerSize); + Index alignedStart = ((!alignable) || bool(dstIsAligned)) ? 0 : internal::first_aligned(dst_ptr, innerSize); for(Index outer = 0; outer < outerSize; ++outer) { diff --git a/uppsrc/plugin/Eigen/Eigen/src/Core/Block.h b/uppsrc/plugin/Eigen/Eigen/src/Core/Block.h index 87bedfa46..827894443 100644 --- a/uppsrc/plugin/Eigen/Eigen/src/Core/Block.h +++ b/uppsrc/plugin/Eigen/Eigen/src/Core/Block.h @@ -66,8 +66,9 @@ struct traits > : traits::MaxColsAtCompileTime), XprTypeIsRowMajor = (int(traits::Flags)&RowMajorBit) != 0, - IsRowMajor = (MaxRowsAtCompileTime==1&&MaxColsAtCompileTime!=1) ? 1 - : (MaxColsAtCompileTime==1&&MaxRowsAtCompileTime!=1) ? 0 + IsDense = is_same::value, + IsRowMajor = (IsDense&&MaxRowsAtCompileTime==1&&MaxColsAtCompileTime!=1) ? 1 + : (IsDense&&MaxColsAtCompileTime==1&&MaxRowsAtCompileTime!=1) ? 0 : XprTypeIsRowMajor, HasSameStorageOrderAsXprType = (IsRowMajor == XprTypeIsRowMajor), InnerSize = IsRowMajor ? int(ColsAtCompileTime) : int(RowsAtCompileTime), diff --git a/uppsrc/plugin/Eigen/Eigen/src/Core/CMakeLists.txt b/uppsrc/plugin/Eigen/Eigen/src/Core/CMakeLists.txt new file mode 100644 index 000000000..2346fc2bb --- /dev/null +++ b/uppsrc/plugin/Eigen/Eigen/src/Core/CMakeLists.txt @@ -0,0 +1,10 @@ +FILE(GLOB Eigen_Core_SRCS "*.h") + +INSTALL(FILES + ${Eigen_Core_SRCS} + DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen/src/Core COMPONENT Devel + ) + +ADD_SUBDIRECTORY(products) +ADD_SUBDIRECTORY(util) +ADD_SUBDIRECTORY(arch) diff --git a/uppsrc/plugin/Eigen/Eigen/src/Core/DenseBase.h b/uppsrc/plugin/Eigen/Eigen/src/Core/DenseBase.h index 04862f374..32f60d8dc 100644 --- a/uppsrc/plugin/Eigen/Eigen/src/Core/DenseBase.h +++ b/uppsrc/plugin/Eigen/Eigen/src/Core/DenseBase.h @@ -266,11 +266,13 @@ template class DenseBase template Derived& operator=(const ReturnByValue& func); -#ifndef EIGEN_PARSED_BY_DOXYGEN - /** Copies \a other into *this without evaluating other. \returns a reference to *this. */ + /** \internal Copies \a other into *this without evaluating other. \returns a reference to *this. */ template Derived& lazyAssign(const DenseBase& other); -#endif // not EIGEN_PARSED_BY_DOXYGEN + + /** \internal Evaluates \a other into *this. \returns a reference to *this. */ + template + Derived& lazyAssign(const ReturnByValue& other); CommaInitializer operator<< (const Scalar& s); diff --git a/uppsrc/plugin/Eigen/Eigen/src/Core/DiagonalProduct.h b/uppsrc/plugin/Eigen/Eigen/src/Core/DiagonalProduct.h index c03a0c2e1..00f8f2915 100644 --- a/uppsrc/plugin/Eigen/Eigen/src/Core/DiagonalProduct.h +++ b/uppsrc/plugin/Eigen/Eigen/src/Core/DiagonalProduct.h @@ -34,7 +34,7 @@ struct traits > _Vectorizable = bool(int(MatrixType::Flags)&PacketAccessBit) && _SameTypes && (_ScalarAccessOnDiag || (bool(int(DiagonalType::DiagonalVectorType::Flags)&PacketAccessBit))), _LinearAccessMask = (RowsAtCompileTime==1 || ColsAtCompileTime==1) ? LinearAccessBit : 0, - Flags = ((HereditaryBits|_LinearAccessMask) & (unsigned int)(MatrixType::Flags)) | (_Vectorizable ? PacketAccessBit : 0) | AlignedBit,//(int(MatrixType::Flags)&int(DiagonalType::DiagonalVectorType::Flags)&AlignedBit), + Flags = ((HereditaryBits|_LinearAccessMask|AlignedBit) & (unsigned int)(MatrixType::Flags)) | (_Vectorizable ? PacketAccessBit : 0),//(int(MatrixType::Flags)&int(DiagonalType::DiagonalVectorType::Flags)&AlignedBit), CoeffReadCost = NumTraits::MulCost + MatrixType::CoeffReadCost + DiagonalType::DiagonalVectorType::CoeffReadCost }; }; diff --git a/uppsrc/plugin/Eigen/Eigen/src/Core/Functors.h b/uppsrc/plugin/Eigen/Eigen/src/Core/Functors.h index b08b967ff..5f14c6587 100644 --- a/uppsrc/plugin/Eigen/Eigen/src/Core/Functors.h +++ b/uppsrc/plugin/Eigen/Eigen/src/Core/Functors.h @@ -259,6 +259,47 @@ template<> struct functor_traits { }; }; +/** \internal + * \brief Template functors for comparison of two scalars + * \todo Implement packet-comparisons + */ +template struct scalar_cmp_op; + +template +struct functor_traits > { + enum { + Cost = NumTraits::AddCost, + PacketAccess = false + }; +}; + +template +struct result_of(Scalar,Scalar)> { + typedef bool type; +}; + + +template struct scalar_cmp_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_cmp_op) + EIGEN_STRONG_INLINE bool operator()(const Scalar& a, const Scalar& b) const {return a==b;} +}; +template struct scalar_cmp_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_cmp_op) + EIGEN_STRONG_INLINE bool operator()(const Scalar& a, const Scalar& b) const {return a struct scalar_cmp_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_cmp_op) + EIGEN_STRONG_INLINE bool operator()(const Scalar& a, const Scalar& b) const {return a<=b;} +}; +template struct scalar_cmp_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_cmp_op) + EIGEN_STRONG_INLINE bool operator()(const Scalar& a, const Scalar& b) const {return !(a<=b || b<=a);} +}; +template struct scalar_cmp_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_cmp_op) + EIGEN_STRONG_INLINE bool operator()(const Scalar& a, const Scalar& b) const {return a!=b;} +}; + // unary functors: /** \internal diff --git a/uppsrc/plugin/Eigen/Eigen/src/Core/MapBase.h b/uppsrc/plugin/Eigen/Eigen/src/Core/MapBase.h index b145a0b3d..92e114129 100644 --- a/uppsrc/plugin/Eigen/Eigen/src/Core/MapBase.h +++ b/uppsrc/plugin/Eigen/Eigen/src/Core/MapBase.h @@ -157,7 +157,7 @@ template class MapBase internal::inner_stride_at_compile_time::ret==1), PACKET_ACCESS_REQUIRES_TO_HAVE_INNER_STRIDE_FIXED_TO_1); eigen_assert(EIGEN_IMPLIES(internal::traits::Flags&AlignedBit, (size_t(m_data) % 16) == 0) - && "data is not aligned"); + && "input pointer is not aligned on a 16 byte boundary"); } PointerType m_data; @@ -168,6 +168,7 @@ template class MapBase template class MapBase : public MapBase { + typedef MapBase ReadOnlyMapBase; public: typedef MapBase Base; @@ -230,15 +231,13 @@ template class MapBase Derived& operator=(const MapBase& other) { - Base::Base::operator=(other); + ReadOnlyMapBase::Base::operator=(other); return derived(); } - // In theory MapBase should not make a using Base::operator=, - // and thus we should directly do: using Base::Base::operator=; - // However, this would confuse recent MSVC 2013 (bug 821), and since MapBase - // has operator= to make ICC 11 happy, we can also make MSVC 2013 happy as follow: - using Base::operator=; + // In theory we could simply refer to Base:Base::operator=, but MSVC does not like Base::Base, + // see bugs 821 and 920. + using ReadOnlyMapBase::Base::operator=; }; #undef EIGEN_STATIC_ASSERT_INDEX_BASED_ACCESS diff --git a/uppsrc/plugin/Eigen/Eigen/src/Core/MatrixBase.h b/uppsrc/plugin/Eigen/Eigen/src/Core/MatrixBase.h index cc3279746..b67a7c119 100644 --- a/uppsrc/plugin/Eigen/Eigen/src/Core/MatrixBase.h +++ b/uppsrc/plugin/Eigen/Eigen/src/Core/MatrixBase.h @@ -159,13 +159,11 @@ template class MatrixBase template Derived& operator=(const ReturnByValue& other); -#ifndef EIGEN_PARSED_BY_DOXYGEN template Derived& lazyAssign(const ProductBase& other); template Derived& lazyAssign(const MatrixPowerProduct& other); -#endif // not EIGEN_PARSED_BY_DOXYGEN template Derived& operator+=(const MatrixBase& other); diff --git a/uppsrc/plugin/Eigen/Eigen/src/Core/PermutationMatrix.h b/uppsrc/plugin/Eigen/Eigen/src/Core/PermutationMatrix.h index f26f3e5cc..85ffae265 100644 --- a/uppsrc/plugin/Eigen/Eigen/src/Core/PermutationMatrix.h +++ b/uppsrc/plugin/Eigen/Eigen/src/Core/PermutationMatrix.h @@ -250,6 +250,35 @@ class PermutationBase : public EigenBase template friend inline PlainPermutationType operator*(const Transpose >& other, const PermutationBase& perm) { return PlainPermutationType(internal::PermPermProduct, other.eval(), perm); } + + /** \returns the determinant of the permutation matrix, which is either 1 or -1 depending on the parity of the permutation. + * + * This function is O(\c n) procedure allocating a buffer of \c n booleans. + */ + Index determinant() const + { + Index res = 1; + Index n = size(); + Matrix mask(n); + mask.fill(false); + Index r = 0; + while(r < n) + { + // search for the next seed + while(r=n) + break; + // we got one, let's follow it until we are back to the seed + Index k0 = r++; + mask.coeffRef(k0) = true; + for(Index k=indices().coeff(k0); k!=k0; k=indices().coeff(k)) + { + mask.coeffRef(k) = true; + res = -res; + } + } + return res; + } protected: diff --git a/uppsrc/plugin/Eigen/Eigen/src/Core/PlainObjectBase.h b/uppsrc/plugin/Eigen/Eigen/src/Core/PlainObjectBase.h index dd34b59e5..8a3e4545a 100644 --- a/uppsrc/plugin/Eigen/Eigen/src/Core/PlainObjectBase.h +++ b/uppsrc/plugin/Eigen/Eigen/src/Core/PlainObjectBase.h @@ -573,6 +573,8 @@ class PlainObjectBase : public internal::dense_xpr_base::type : (rows() == other.rows() && cols() == other.cols()))) && "Size mismatch. Automatic resizing is disabled because EIGEN_NO_AUTOMATIC_RESIZING is defined"); EIGEN_ONLY_USED_FOR_DEBUG(other); + if(this->size()==0) + resizeLike(other); #else resizeLike(other); #endif diff --git a/uppsrc/plugin/Eigen/Eigen/src/Core/Ref.h b/uppsrc/plugin/Eigen/Eigen/src/Core/Ref.h index df87b1af4..f53674cff 100644 --- a/uppsrc/plugin/Eigen/Eigen/src/Core/Ref.h +++ b/uppsrc/plugin/Eigen/Eigen/src/Core/Ref.h @@ -108,7 +108,8 @@ struct traits > OuterStrideMatch = Derived::IsVectorAtCompileTime || int(StrideType::OuterStrideAtCompileTime)==int(Dynamic) || int(StrideType::OuterStrideAtCompileTime)==int(Derived::OuterStrideAtCompileTime), AlignmentMatch = (_Options!=Aligned) || ((PlainObjectType::Flags&AlignedBit)==0) || ((traits::Flags&AlignedBit)==AlignedBit), - MatchAtCompileTime = HasDirectAccess && StorageOrderMatch && InnerStrideMatch && OuterStrideMatch && AlignmentMatch + ScalarTypeMatch = internal::is_same::value, + MatchAtCompileTime = HasDirectAccess && StorageOrderMatch && InnerStrideMatch && OuterStrideMatch && AlignmentMatch && ScalarTypeMatch }; typedef typename internal::conditional::type type; }; @@ -187,9 +188,11 @@ protected: template class Ref : public RefBase > { + private: typedef internal::traits Traits; template - inline Ref(const PlainObjectBase& expr); + inline Ref(const PlainObjectBase& expr, + typename internal::enable_if::MatchAtCompileTime),Derived>::type* = 0); public: typedef RefBase Base; @@ -198,13 +201,15 @@ template class Ref #ifndef EIGEN_PARSED_BY_DOXYGEN template - inline Ref(PlainObjectBase& expr) + inline Ref(PlainObjectBase& expr, + typename internal::enable_if::MatchAtCompileTime),Derived>::type* = 0) { EIGEN_STATIC_ASSERT(static_cast(Traits::template match::MatchAtCompileTime), STORAGE_LAYOUT_DOES_NOT_MATCH); Base::construct(expr.derived()); } template - inline Ref(const DenseBase& expr) + inline Ref(const DenseBase& expr, + typename internal::enable_if::MatchAtCompileTime),Derived>::type* = 0) #else template inline Ref(DenseBase& expr) @@ -231,7 +236,8 @@ template class Ref< EIGEN_DENSE_PUBLIC_INTERFACE(Ref) template - inline Ref(const DenseBase& expr) + inline Ref(const DenseBase& expr, + typename internal::enable_if::ScalarTypeMatch),Derived>::type* = 0) { // std::cout << match_helper::HasDirectAccess << "," << match_helper::OuterStrideMatch << "," << match_helper::InnerStrideMatch << "\n"; // std::cout << int(StrideType::OuterStrideAtCompileTime) << " - " << int(Derived::OuterStrideAtCompileTime) << "\n"; diff --git a/uppsrc/plugin/Eigen/Eigen/src/Core/ReturnByValue.h b/uppsrc/plugin/Eigen/Eigen/src/Core/ReturnByValue.h index d66c24ba0..f635598dc 100644 --- a/uppsrc/plugin/Eigen/Eigen/src/Core/ReturnByValue.h +++ b/uppsrc/plugin/Eigen/Eigen/src/Core/ReturnByValue.h @@ -72,6 +72,8 @@ template class ReturnByValue const Unusable& coeff(Index,Index) const { return *reinterpret_cast(this); } Unusable& coeffRef(Index) { return *reinterpret_cast(this); } Unusable& coeffRef(Index,Index) { return *reinterpret_cast(this); } + template Unusable& packet(Index) const; + template Unusable& packet(Index, Index) const; #endif }; @@ -83,6 +85,15 @@ Derived& DenseBase::operator=(const ReturnByValue& other) return derived(); } +template +template +Derived& DenseBase::lazyAssign(const ReturnByValue& other) +{ + other.evalTo(derived()); + return derived(); +} + + } // end namespace Eigen #endif // EIGEN_RETURNBYVALUE_H diff --git a/uppsrc/plugin/Eigen/Eigen/src/Core/arch/AltiVec/CMakeLists.txt b/uppsrc/plugin/Eigen/Eigen/src/Core/arch/AltiVec/CMakeLists.txt new file mode 100644 index 000000000..9f8d2e9c4 --- /dev/null +++ b/uppsrc/plugin/Eigen/Eigen/src/Core/arch/AltiVec/CMakeLists.txt @@ -0,0 +1,6 @@ +FILE(GLOB Eigen_Core_arch_AltiVec_SRCS "*.h") + +INSTALL(FILES + ${Eigen_Core_arch_AltiVec_SRCS} + DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen/src/Core/arch/AltiVec COMPONENT Devel +) diff --git a/uppsrc/plugin/Eigen/Eigen/src/Core/arch/CMakeLists.txt b/uppsrc/plugin/Eigen/Eigen/src/Core/arch/CMakeLists.txt new file mode 100644 index 000000000..8456dec15 --- /dev/null +++ b/uppsrc/plugin/Eigen/Eigen/src/Core/arch/CMakeLists.txt @@ -0,0 +1,4 @@ +ADD_SUBDIRECTORY(SSE) +ADD_SUBDIRECTORY(AltiVec) +ADD_SUBDIRECTORY(NEON) +ADD_SUBDIRECTORY(Default) diff --git a/uppsrc/plugin/Eigen/Eigen/src/Core/arch/Default/CMakeLists.txt b/uppsrc/plugin/Eigen/Eigen/src/Core/arch/Default/CMakeLists.txt new file mode 100644 index 000000000..339c091d1 --- /dev/null +++ b/uppsrc/plugin/Eigen/Eigen/src/Core/arch/Default/CMakeLists.txt @@ -0,0 +1,6 @@ +FILE(GLOB Eigen_Core_arch_Default_SRCS "*.h") + +INSTALL(FILES + ${Eigen_Core_arch_Default_SRCS} + DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen/src/Core/arch/Default COMPONENT Devel +) diff --git a/uppsrc/plugin/Eigen/Eigen/src/Core/arch/NEON/CMakeLists.txt b/uppsrc/plugin/Eigen/Eigen/src/Core/arch/NEON/CMakeLists.txt new file mode 100644 index 000000000..fd4d4af50 --- /dev/null +++ b/uppsrc/plugin/Eigen/Eigen/src/Core/arch/NEON/CMakeLists.txt @@ -0,0 +1,6 @@ +FILE(GLOB Eigen_Core_arch_NEON_SRCS "*.h") + +INSTALL(FILES + ${Eigen_Core_arch_NEON_SRCS} + DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen/src/Core/arch/NEON COMPONENT Devel +) diff --git a/uppsrc/plugin/Eigen/Eigen/src/Core/arch/NEON/Complex.h b/uppsrc/plugin/Eigen/Eigen/src/Core/arch/NEON/Complex.h index f183d31de..8d9255eef 100644 --- a/uppsrc/plugin/Eigen/Eigen/src/Core/arch/NEON/Complex.h +++ b/uppsrc/plugin/Eigen/Eigen/src/Core/arch/NEON/Complex.h @@ -110,7 +110,7 @@ template<> EIGEN_STRONG_INLINE Packet2cf ploaddup(const std::complex< template<> EIGEN_STRONG_INLINE void pstore >(std::complex * to, const Packet2cf& from) { EIGEN_DEBUG_ALIGNED_STORE pstore((float*)to, from.v); } template<> EIGEN_STRONG_INLINE void pstoreu >(std::complex * to, const Packet2cf& from) { EIGEN_DEBUG_UNALIGNED_STORE pstoreu((float*)to, from.v); } -template<> EIGEN_STRONG_INLINE void prefetch >(const std::complex * addr) { __pld((float *)addr); } +template<> EIGEN_STRONG_INLINE void prefetch >(const std::complex * addr) { EIGEN_ARM_PREFETCH((float *)addr); } template<> EIGEN_STRONG_INLINE std::complex pfirst(const Packet2cf& a) { diff --git a/uppsrc/plugin/Eigen/Eigen/src/Core/arch/NEON/PacketMath.h b/uppsrc/plugin/Eigen/Eigen/src/Core/arch/NEON/PacketMath.h index a4dbdc1ea..94dfab330 100644 --- a/uppsrc/plugin/Eigen/Eigen/src/Core/arch/NEON/PacketMath.h +++ b/uppsrc/plugin/Eigen/Eigen/src/Core/arch/NEON/PacketMath.h @@ -218,8 +218,8 @@ template<> EIGEN_STRONG_INLINE void pstore(int* to, const Packet4i& f template<> EIGEN_STRONG_INLINE void pstoreu(float* to, const Packet4f& from) { EIGEN_DEBUG_UNALIGNED_STORE vst1q_f32(to, from); } template<> EIGEN_STRONG_INLINE void pstoreu(int* to, const Packet4i& from) { EIGEN_DEBUG_UNALIGNED_STORE vst1q_s32(to, from); } -template<> EIGEN_STRONG_INLINE void prefetch(const float* addr) { __pld(addr); } -template<> EIGEN_STRONG_INLINE void prefetch(const int* addr) { __pld(addr); } +template<> EIGEN_STRONG_INLINE void prefetch(const float* addr) { EIGEN_ARM_PREFETCH(addr); } +template<> EIGEN_STRONG_INLINE void prefetch(const int* addr) { EIGEN_ARM_PREFETCH(addr); } // FIXME only store the 2 first elements ? template<> EIGEN_STRONG_INLINE float pfirst(const Packet4f& a) { float EIGEN_ALIGN16 x[4]; vst1q_f32(x, a); return x[0]; } diff --git a/uppsrc/plugin/Eigen/Eigen/src/Core/arch/SSE/CMakeLists.txt b/uppsrc/plugin/Eigen/Eigen/src/Core/arch/SSE/CMakeLists.txt new file mode 100644 index 000000000..46ea7cc62 --- /dev/null +++ b/uppsrc/plugin/Eigen/Eigen/src/Core/arch/SSE/CMakeLists.txt @@ -0,0 +1,6 @@ +FILE(GLOB Eigen_Core_arch_SSE_SRCS "*.h") + +INSTALL(FILES + ${Eigen_Core_arch_SSE_SRCS} + DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen/src/Core/arch/SSE COMPONENT Devel +) diff --git a/uppsrc/plugin/Eigen/Eigen/src/Core/products/CMakeLists.txt b/uppsrc/plugin/Eigen/Eigen/src/Core/products/CMakeLists.txt new file mode 100644 index 000000000..21fc94ae3 --- /dev/null +++ b/uppsrc/plugin/Eigen/Eigen/src/Core/products/CMakeLists.txt @@ -0,0 +1,6 @@ +FILE(GLOB Eigen_Core_Product_SRCS "*.h") + +INSTALL(FILES + ${Eigen_Core_Product_SRCS} + DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen/src/Core/products COMPONENT Devel + ) diff --git a/uppsrc/plugin/Eigen/Eigen/src/Core/products/CoeffBasedProduct.h b/uppsrc/plugin/Eigen/Eigen/src/Core/products/CoeffBasedProduct.h index 421f925e1..2a9d65b94 100644 --- a/uppsrc/plugin/Eigen/Eigen/src/Core/products/CoeffBasedProduct.h +++ b/uppsrc/plugin/Eigen/Eigen/src/Core/products/CoeffBasedProduct.h @@ -134,7 +134,7 @@ class CoeffBasedProduct }; typedef internal::product_coeff_impl ScalarCoeffImpl; typedef CoeffBasedProduct LazyCoeffBasedProductType; @@ -185,7 +185,7 @@ class CoeffBasedProduct { PacketScalar res; internal::product_packet_impl ::run(row, col, m_lhs, m_rhs, res); return res; @@ -243,7 +243,17 @@ struct product_coeff_impl static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, RetScalar &res) { product_coeff_impl::run(row, col, lhs, rhs, res); - res += lhs.coeff(row, UnrollingIndex) * rhs.coeff(UnrollingIndex, col); + res += lhs.coeff(row, UnrollingIndex-1) * rhs.coeff(UnrollingIndex-1, col); + } +}; + +template +struct product_coeff_impl +{ + typedef typename Lhs::Index Index; + static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, RetScalar &res) + { + res = lhs.coeff(row, 0) * rhs.coeff(0, col); } }; @@ -251,9 +261,9 @@ template struct product_coeff_impl { typedef typename Lhs::Index Index; - static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, RetScalar &res) + static EIGEN_STRONG_INLINE void run(Index /*row*/, Index /*col*/, const Lhs& /*lhs*/, const Rhs& /*rhs*/, RetScalar &res) { - res = lhs.coeff(row, 0) * rhs.coeff(0, col); + res = RetScalar(0); } }; @@ -293,6 +303,16 @@ struct product_coeff_vectorized_unroller<0, Lhs, Rhs, Packet> } }; +template +struct product_coeff_impl +{ + typedef typename Lhs::Index Index; + static EIGEN_STRONG_INLINE void run(Index /*row*/, Index /*col*/, const Lhs& /*lhs*/, const Rhs& /*rhs*/, RetScalar &res) + { + res = 0; + } +}; + template struct product_coeff_impl { @@ -302,8 +322,7 @@ struct product_coeff_impl::run(row, col, lhs, rhs, pres); - product_coeff_impl::run(row, col, lhs, rhs, res); + product_coeff_vectorized_unroller::run(row, col, lhs, rhs, pres); res = predux(pres); } }; @@ -371,7 +390,7 @@ struct product_packet_impl static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Packet &res) { product_packet_impl::run(row, col, lhs, rhs, res); - res = pmadd(pset1(lhs.coeff(row, UnrollingIndex)), rhs.template packet(UnrollingIndex, col), res); + res = pmadd(pset1(lhs.coeff(row, UnrollingIndex-1)), rhs.template packet(UnrollingIndex-1, col), res); } }; @@ -382,12 +401,12 @@ struct product_packet_impl static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Packet &res) { product_packet_impl::run(row, col, lhs, rhs, res); - res = pmadd(lhs.template packet(row, UnrollingIndex), pset1(rhs.coeff(UnrollingIndex, col)), res); + res = pmadd(lhs.template packet(row, UnrollingIndex-1), pset1(rhs.coeff(UnrollingIndex-1, col)), res); } }; template -struct product_packet_impl +struct product_packet_impl { typedef typename Lhs::Index Index; static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Packet &res) @@ -397,7 +416,7 @@ struct product_packet_impl }; template -struct product_packet_impl +struct product_packet_impl { typedef typename Lhs::Index Index; static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Packet &res) @@ -406,16 +425,35 @@ struct product_packet_impl } }; +template +struct product_packet_impl +{ + typedef typename Lhs::Index Index; + static EIGEN_STRONG_INLINE void run(Index /*row*/, Index /*col*/, const Lhs& /*lhs*/, const Rhs& /*rhs*/, Packet &res) + { + res = pset1(0); + } +}; + +template +struct product_packet_impl +{ + typedef typename Lhs::Index Index; + static EIGEN_STRONG_INLINE void run(Index /*row*/, Index /*col*/, const Lhs& /*lhs*/, const Rhs& /*rhs*/, Packet &res) + { + res = pset1(0); + } +}; + template struct product_packet_impl { typedef typename Lhs::Index Index; static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Packet& res) { - eigen_assert(lhs.cols()>0 && "you are using a non initialized matrix"); - res = pmul(pset1(lhs.coeff(row, 0)),rhs.template packet(0, col)); - for(Index i = 1; i < lhs.cols(); ++i) - res = pmadd(pset1(lhs.coeff(row, i)), rhs.template packet(i, col), res); + res = pset1(0); + for(Index i = 0; i < lhs.cols(); ++i) + res = pmadd(pset1(lhs.coeff(row, i)), rhs.template packet(i, col), res); } }; @@ -425,10 +463,9 @@ struct product_packet_impl typedef typename Lhs::Index Index; static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Packet& res) { - eigen_assert(lhs.cols()>0 && "you are using a non initialized matrix"); - res = pmul(lhs.template packet(row, 0), pset1(rhs.coeff(0, col))); - for(Index i = 1; i < lhs.cols(); ++i) - res = pmadd(lhs.template packet(row, i), pset1(rhs.coeff(i, col)), res); + res = pset1(0); + for(Index i = 0; i < lhs.cols(); ++i) + res = pmadd(lhs.template packet(row, i), pset1(rhs.coeff(i, col)), res); } }; diff --git a/uppsrc/plugin/Eigen/Eigen/src/Core/products/Parallelizer.h b/uppsrc/plugin/Eigen/Eigen/src/Core/products/Parallelizer.h index 5c3e9b7ac..6937ee332 100644 --- a/uppsrc/plugin/Eigen/Eigen/src/Core/products/Parallelizer.h +++ b/uppsrc/plugin/Eigen/Eigen/src/Core/products/Parallelizer.h @@ -125,19 +125,22 @@ void parallelize_gemm(const Functor& func, Index rows, Index cols, bool transpos if(transpose) std::swap(rows,cols); - Index blockCols = (cols / threads) & ~Index(0x3); - Index blockRows = (rows / threads) & ~Index(0x7); - GemmParallelInfo* info = new GemmParallelInfo[threads]; - #pragma omp parallel for schedule(static,1) num_threads(threads) - for(Index i=0; ix || (EIGEN_WORLD_VERSION>=x && \ (EIGEN_MAJOR_VERSION>y || (EIGEN_MAJOR_VERSION>=y && \ @@ -278,6 +278,7 @@ namespace Eigen { #error Please tell me what is the equivalent of __attribute__((aligned(n))) for your compiler #endif +#define EIGEN_ALIGN8 EIGEN_ALIGN_TO_BOUNDARY(8) #define EIGEN_ALIGN16 EIGEN_ALIGN_TO_BOUNDARY(16) #if EIGEN_ALIGN_STATICALLY @@ -313,7 +314,7 @@ namespace Eigen { // just an empty macro ! #define EIGEN_EMPTY -#if defined(_MSC_VER) && (!defined(__INTEL_COMPILER)) +#if defined(_MSC_VER) && (_MSC_VER < 1800) && (!defined(__INTEL_COMPILER)) #define EIGEN_INHERIT_ASSIGNMENT_EQUAL_OPERATOR(Derived) \ using Base::operator =; #elif defined(__clang__) // workaround clang bug (see http://forum.kde.org/viewtopic.php?f=74&t=102653) @@ -332,8 +333,11 @@ namespace Eigen { } #endif -#define EIGEN_INHERIT_ASSIGNMENT_OPERATORS(Derived) \ - EIGEN_INHERIT_ASSIGNMENT_EQUAL_OPERATOR(Derived) +/** \internal + * \brief Macro to manually inherit assignment operators. + * This is necessary, because the implicitly defined assignment operator gets deleted when a custom operator= is defined. + */ +#define EIGEN_INHERIT_ASSIGNMENT_OPERATORS(Derived) EIGEN_INHERIT_ASSIGNMENT_EQUAL_OPERATOR(Derived) /** * Just a side note. Commenting within defines works only by documenting diff --git a/uppsrc/plugin/Eigen/Eigen/src/Core/util/Memory.h b/uppsrc/plugin/Eigen/Eigen/src/Core/util/Memory.h index 07e54ef06..b9af5cf8c 100644 --- a/uppsrc/plugin/Eigen/Eigen/src/Core/util/Memory.h +++ b/uppsrc/plugin/Eigen/Eigen/src/Core/util/Memory.h @@ -466,9 +466,8 @@ template inline void conditional_aligned_delete_auto(T * template static inline Index first_aligned(const Scalar* array, Index size) { - enum { PacketSize = packet_traits::size, - PacketAlignedMask = PacketSize-1 - }; + static const Index PacketSize = packet_traits::size; + static const Index PacketAlignedMask = PacketSize-1; if(PacketSize==1) { @@ -524,7 +523,7 @@ template struct smart_copy_helper { // you can overwrite Eigen's default behavior regarding alloca by defining EIGEN_ALLOCA // to the appropriate stack allocation function #ifndef EIGEN_ALLOCA - #if (defined __linux__) + #if (defined __linux__) || (defined __APPLE__) || (defined alloca) #define EIGEN_ALLOCA alloca #elif defined(_MSC_VER) #define EIGEN_ALLOCA _alloca diff --git a/uppsrc/plugin/Eigen/Eigen/src/Eigen2Support/CMakeLists.txt b/uppsrc/plugin/Eigen/Eigen/src/Eigen2Support/CMakeLists.txt new file mode 100644 index 000000000..7ae41b3cb --- /dev/null +++ b/uppsrc/plugin/Eigen/Eigen/src/Eigen2Support/CMakeLists.txt @@ -0,0 +1,8 @@ +FILE(GLOB Eigen_Eigen2Support_SRCS "*.h") + +INSTALL(FILES + ${Eigen_Eigen2Support_SRCS} + DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen/src/Eigen2Support COMPONENT Devel + ) + +ADD_SUBDIRECTORY(Geometry) \ No newline at end of file diff --git a/uppsrc/plugin/Eigen/Eigen/src/Eigen2Support/Geometry/CMakeLists.txt b/uppsrc/plugin/Eigen/Eigen/src/Eigen2Support/Geometry/CMakeLists.txt new file mode 100644 index 000000000..c347a8f26 --- /dev/null +++ b/uppsrc/plugin/Eigen/Eigen/src/Eigen2Support/Geometry/CMakeLists.txt @@ -0,0 +1,6 @@ +FILE(GLOB Eigen_Eigen2Support_Geometry_SRCS "*.h") + +INSTALL(FILES + ${Eigen_Eigen2Support_Geometry_SRCS} + DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen/src/Eigen2Support/Geometry + ) diff --git a/uppsrc/plugin/Eigen/Eigen/src/Eigenvalues/CMakeLists.txt b/uppsrc/plugin/Eigen/Eigen/src/Eigenvalues/CMakeLists.txt new file mode 100644 index 000000000..193e02685 --- /dev/null +++ b/uppsrc/plugin/Eigen/Eigen/src/Eigenvalues/CMakeLists.txt @@ -0,0 +1,6 @@ +FILE(GLOB Eigen_EIGENVALUES_SRCS "*.h") + +INSTALL(FILES + ${Eigen_EIGENVALUES_SRCS} + DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen/src/Eigenvalues COMPONENT Devel + ) diff --git a/uppsrc/plugin/Eigen/Eigen/src/Eigenvalues/ComplexEigenSolver.h b/uppsrc/plugin/Eigen/Eigen/src/Eigenvalues/ComplexEigenSolver.h index af434bc9b..417c72944 100644 --- a/uppsrc/plugin/Eigen/Eigen/src/Eigenvalues/ComplexEigenSolver.h +++ b/uppsrc/plugin/Eigen/Eigen/src/Eigenvalues/ComplexEigenSolver.h @@ -234,6 +234,12 @@ template class ComplexEigenSolver } protected: + + static void check_template_parameters() + { + EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar); + } + EigenvectorType m_eivec; EigenvalueType m_eivalues; ComplexSchur m_schur; @@ -251,6 +257,8 @@ template ComplexEigenSolver& ComplexEigenSolver::compute(const MatrixType& matrix, bool computeEigenvectors) { + check_template_parameters(); + // this code is inspired from Jampack eigen_assert(matrix.cols() == matrix.rows()); diff --git a/uppsrc/plugin/Eigen/Eigen/src/Eigenvalues/EigenSolver.h b/uppsrc/plugin/Eigen/Eigen/src/Eigenvalues/EigenSolver.h index 6e7150685..20c59a7a2 100644 --- a/uppsrc/plugin/Eigen/Eigen/src/Eigenvalues/EigenSolver.h +++ b/uppsrc/plugin/Eigen/Eigen/src/Eigenvalues/EigenSolver.h @@ -298,6 +298,13 @@ template class EigenSolver void doComputeEigenvectors(); protected: + + static void check_template_parameters() + { + EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar); + EIGEN_STATIC_ASSERT(!NumTraits::IsComplex, NUMERIC_TYPE_MUST_BE_REAL); + } + MatrixType m_eivec; EigenvalueType m_eivalues; bool m_isInitialized; @@ -364,6 +371,8 @@ template EigenSolver& EigenSolver::compute(const MatrixType& matrix, bool computeEigenvectors) { + check_template_parameters(); + using std::sqrt; using std::abs; eigen_assert(matrix.cols() == matrix.rows()); diff --git a/uppsrc/plugin/Eigen/Eigen/src/Eigenvalues/GeneralizedEigenSolver.h b/uppsrc/plugin/Eigen/Eigen/src/Eigenvalues/GeneralizedEigenSolver.h index dc240e13e..956e80d9e 100644 --- a/uppsrc/plugin/Eigen/Eigen/src/Eigenvalues/GeneralizedEigenSolver.h +++ b/uppsrc/plugin/Eigen/Eigen/src/Eigenvalues/GeneralizedEigenSolver.h @@ -263,6 +263,13 @@ template class GeneralizedEigenSolver } protected: + + static void check_template_parameters() + { + EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar); + EIGEN_STATIC_ASSERT(!NumTraits::IsComplex, NUMERIC_TYPE_MUST_BE_REAL); + } + MatrixType m_eivec; ComplexVectorType m_alphas; VectorType m_betas; @@ -290,6 +297,8 @@ template GeneralizedEigenSolver& GeneralizedEigenSolver::compute(const MatrixType& A, const MatrixType& B, bool computeEigenvectors) { + check_template_parameters(); + using std::sqrt; using std::abs; eigen_assert(A.cols() == A.rows() && B.cols() == A.rows() && B.cols() == B.rows()); diff --git a/uppsrc/plugin/Eigen/Eigen/src/Eigenvalues/RealQZ.h b/uppsrc/plugin/Eigen/Eigen/src/Eigenvalues/RealQZ.h index 5706eeebe..aa3833eba 100644 --- a/uppsrc/plugin/Eigen/Eigen/src/Eigenvalues/RealQZ.h +++ b/uppsrc/plugin/Eigen/Eigen/src/Eigenvalues/RealQZ.h @@ -240,10 +240,10 @@ namespace Eigen { m_S.coeffRef(i,j) = Scalar(0.0); m_S.rightCols(dim-j-1).applyOnTheLeft(i-1,i,G.adjoint()); m_T.rightCols(dim-i+1).applyOnTheLeft(i-1,i,G.adjoint()); + // update Q + if (m_computeQZ) + m_Q.applyOnTheRight(i-1,i,G); } - // update Q - if (m_computeQZ) - m_Q.applyOnTheRight(i-1,i,G); // kill T(i,i-1) if(m_T.coeff(i,i-1)!=Scalar(0)) { @@ -251,10 +251,10 @@ namespace Eigen { m_T.coeffRef(i,i-1) = Scalar(0.0); m_S.applyOnTheRight(i,i-1,G); m_T.topRows(i).applyOnTheRight(i,i-1,G); + // update Z + if (m_computeQZ) + m_Z.applyOnTheLeft(i,i-1,G.adjoint()); } - // update Z - if (m_computeQZ) - m_Z.applyOnTheLeft(i,i-1,G.adjoint()); } } } @@ -313,7 +313,7 @@ namespace Eigen { using std::abs; using std::sqrt; const Index dim=m_S.cols(); - if (abs(m_S.coeff(i+1,i)==Scalar(0))) + if (abs(m_S.coeff(i+1,i))==Scalar(0)) return; Index z = findSmallDiagEntry(i,i+1); if (z==i-1) diff --git a/uppsrc/plugin/Eigen/Eigen/src/Eigenvalues/RealSchur.h b/uppsrc/plugin/Eigen/Eigen/src/Eigenvalues/RealSchur.h index 64d136341..16d387537 100644 --- a/uppsrc/plugin/Eigen/Eigen/src/Eigenvalues/RealSchur.h +++ b/uppsrc/plugin/Eigen/Eigen/src/Eigenvalues/RealSchur.h @@ -234,7 +234,7 @@ template class RealSchur typedef Matrix Vector3s; Scalar computeNormOfT(); - Index findSmallSubdiagEntry(Index iu, const Scalar& norm); + Index findSmallSubdiagEntry(Index iu); void splitOffTwoRows(Index iu, bool computeU, const Scalar& exshift); void computeShift(Index iu, Index iter, Scalar& exshift, Vector3s& shiftInfo); void initFrancisQRStep(Index il, Index iu, const Vector3s& shiftInfo, Index& im, Vector3s& firstHouseholderVector); @@ -286,7 +286,7 @@ RealSchur& RealSchur::computeFromHessenberg(const HessMa { while (iu >= 0) { - Index il = findSmallSubdiagEntry(iu, norm); + Index il = findSmallSubdiagEntry(iu); // Check for convergence if (il == iu) // One root found @@ -343,16 +343,14 @@ inline typename MatrixType::Scalar RealSchur::computeNormOfT() /** \internal Look for single small sub-diagonal element and returns its index */ template -inline typename MatrixType::Index RealSchur::findSmallSubdiagEntry(Index iu, const Scalar& norm) +inline typename MatrixType::Index RealSchur::findSmallSubdiagEntry(Index iu) { using std::abs; Index res = iu; while (res > 0) { Scalar s = abs(m_matT.coeff(res-1,res-1)) + abs(m_matT.coeff(res,res)); - if (s == 0.0) - s = norm; - if (abs(m_matT.coeff(res,res-1)) < NumTraits::epsilon() * s) + if (abs(m_matT.coeff(res,res-1)) <= NumTraits::epsilon() * s) break; res--; } @@ -457,9 +455,7 @@ inline void RealSchur::initFrancisQRStep(Index il, Index iu, const V const Scalar lhs = m_matT.coeff(im,im-1) * (abs(v.coeff(1)) + abs(v.coeff(2))); const Scalar rhs = v.coeff(0) * (abs(m_matT.coeff(im-1,im-1)) + abs(Tmm) + abs(m_matT.coeff(im+1,im+1))); if (abs(lhs) < NumTraits::epsilon() * rhs) - { break; - } } } diff --git a/uppsrc/plugin/Eigen/Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h b/uppsrc/plugin/Eigen/Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h index be89de4a9..c2e76c884 100644 --- a/uppsrc/plugin/Eigen/Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h +++ b/uppsrc/plugin/Eigen/Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h @@ -351,6 +351,11 @@ template class SelfAdjointEigenSolver #endif // EIGEN2_SUPPORT protected: + static void check_template_parameters() + { + EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar); + } + MatrixType m_eivec; RealVectorType m_eivalues; typename TridiagonalizationType::SubDiagonalType m_subdiag; @@ -384,6 +389,8 @@ template SelfAdjointEigenSolver& SelfAdjointEigenSolver ::compute(const MatrixType& matrix, int options) { + check_template_parameters(); + using std::abs; eigen_assert(matrix.cols() == matrix.rows()); eigen_assert((options&~(EigVecMask|GenEigMask))==0 @@ -490,7 +497,12 @@ template struct direct_selfadjoint_eigenvalues struct direct_selfadjoint_eigenvalues Scalar(0)) + Scalar a_over_3 = (c2*c2_over_3 - c1)*s_inv3; + if(a_over_3 Scalar(0)) + Scalar q = a_over_3*a_over_3*a_over_3 - half_b*half_b; + if(q 0, atan2 is in [0, pi] and theta is in [0, pi/3] Scalar cos_theta = cos(theta); Scalar sin_theta = sin(theta); - roots(0) = c2_over_3 + Scalar(2)*rho*cos_theta; - roots(1) = c2_over_3 - rho*(cos_theta + s_sqrt3*sin_theta); - roots(2) = c2_over_3 - rho*(cos_theta - s_sqrt3*sin_theta); - - // Sort in increasing order. - if (roots(0) >= roots(1)) - std::swap(roots(0),roots(1)); - if (roots(1) >= roots(2)) - { - std::swap(roots(1),roots(2)); - if (roots(0) >= roots(1)) - std::swap(roots(0),roots(1)); - } + // roots are already sorted, since cos is monotonically decreasing on [0, pi] + roots(0) = c2_over_3 - rho*(cos_theta + s_sqrt3*sin_theta); // == 2*rho*cos(theta+2pi/3) + roots(1) = c2_over_3 - rho*(cos_theta - s_sqrt3*sin_theta); // == 2*rho*cos(theta+ pi/3) + roots(2) = c2_over_3 + Scalar(2)*rho*cos_theta; } - + + static inline bool extract_kernel(MatrixType& mat, Ref res, Ref representative) + { + using std::abs; + Index i0; + // Find non-zero column i0 (by construction, there must exist a non zero coefficient on the diagonal): + mat.diagonal().cwiseAbs().maxCoeff(&i0); + // mat.col(i0) is a good candidate for an orthogonal vector to the current eigenvector, + // so let's save it: + representative = mat.col(i0); + Scalar n0, n1; + VectorType c0, c1; + n0 = (c0 = representative.cross(mat.col((i0+1)%3))).squaredNorm(); + n1 = (c1 = representative.cross(mat.col((i0+2)%3))).squaredNorm(); + if(n0>n1) res = c0/std::sqrt(n0); + else res = c1/std::sqrt(n1); + + return true; + } + static inline void run(SolverType& solver, const MatrixType& mat, int options) { - using std::sqrt; eigen_assert(mat.cols() == 3 && mat.cols() == mat.rows()); eigen_assert((options&~(EigVecMask|GenEigMask))==0 && (options&EigVecMask)!=EigVecMask @@ -552,116 +573,72 @@ template struct direct_selfadjoint_eigenvalues(); + scaledMat.diagonal().array() -= shift; + Scalar scale = scaledMat.cwiseAbs().maxCoeff(); + if(scale > 0) scaledMat /= scale; // TODO for scale==0 we could save the remaining operations // compute the eigenvalues computeRoots(scaledMat,eivals); - // compute the eigen vectors + // compute the eigenvectors if(computeEigenvectors) { - Scalar safeNorm2 = Eigen::NumTraits::epsilon(); if((eivals(2)-eivals(0))<=Eigen::NumTraits::epsilon()) { + // All three eigenvalues are numerically the same eivecs.setIdentity(); } else { - scaledMat = scaledMat.template selfadjointView(); MatrixType tmp; tmp = scaledMat; + // Compute the eigenvector of the most distinct eigenvalue Scalar d0 = eivals(2) - eivals(1); Scalar d1 = eivals(1) - eivals(0); - int k = d0 > d1 ? 2 : 0; - d0 = d0 > d1 ? d0 : d1; - - tmp.diagonal().array () -= eivals(k); - VectorType cross; - Scalar n; - n = (cross = tmp.row(0).cross(tmp.row(1))).squaredNorm(); - - if(n>safeNorm2) + Index k(0), l(2); + if(d0 > d1) { - eivecs.col(k) = cross / sqrt(n); + std::swap(k,l); + d0 = d1; + } + + // Compute the eigenvector of index k + { + tmp.diagonal().array () -= eivals(k); + // By construction, 'tmp' is of rank 2, and its kernel corresponds to the respective eigenvector. + extract_kernel(tmp, eivecs.col(k), eivecs.col(l)); + } + + // Compute eigenvector of index l + if(d0<=2*Eigen::NumTraits::epsilon()*d1) + { + // If d0 is too small, then the two other eigenvalues are numerically the same, + // and thus we only have to ortho-normalize the near orthogonal vector we saved above. + eivecs.col(l) -= eivecs.col(k).dot(eivecs.col(l))*eivecs.col(l); + eivecs.col(l).normalize(); } else { - n = (cross = tmp.row(0).cross(tmp.row(2))).squaredNorm(); + tmp = scaledMat; + tmp.diagonal().array () -= eivals(l); - if(n>safeNorm2) - { - eivecs.col(k) = cross / sqrt(n); - } - else - { - n = (cross = tmp.row(1).cross(tmp.row(2))).squaredNorm(); - - if(n>safeNorm2) - { - eivecs.col(k) = cross / sqrt(n); - } - else - { - // the input matrix and/or the eigenvaues probably contains some inf/NaN, - // => exit - // scale back to the original size. - eivals *= scale; - - solver.m_info = NumericalIssue; - solver.m_isInitialized = true; - solver.m_eigenvectorsOk = computeEigenvectors; - return; - } - } + VectorType dummy; + extract_kernel(tmp, eivecs.col(l), dummy); } - tmp = scaledMat; - tmp.diagonal().array() -= eivals(1); - - if(d0<=Eigen::NumTraits::epsilon()) - { - eivecs.col(1) = eivecs.col(k).unitOrthogonal(); - } - else - { - n = (cross = eivecs.col(k).cross(tmp.row(0))).squaredNorm(); - if(n>safeNorm2) - { - eivecs.col(1) = cross / sqrt(n); - } - else - { - n = (cross = eivecs.col(k).cross(tmp.row(1))).squaredNorm(); - if(n>safeNorm2) - eivecs.col(1) = cross / sqrt(n); - else - { - n = (cross = eivecs.col(k).cross(tmp.row(2))).squaredNorm(); - if(n>safeNorm2) - eivecs.col(1) = cross / sqrt(n); - else - { - // we should never reach this point, - // if so the last two eigenvalues are likely to be very close to each other - eivecs.col(1) = eivecs.col(k).unitOrthogonal(); - } - } - } - - // make sure that eivecs[1] is orthogonal to eivecs[2] - // FIXME: this step should not be needed - Scalar d = eivecs.col(1).dot(eivecs.col(k)); - eivecs.col(1) = (eivecs.col(1) - d * eivecs.col(k)).normalized(); - } - - eivecs.col(k==2 ? 0 : 2) = eivecs.col(k).cross(eivecs.col(1)).normalized(); + // Compute last eigenvector from the other two + eivecs.col(1) = eivecs.col(2).cross(eivecs.col(0)).normalized(); } } + // Rescale back to the original size. eivals *= scale; + eivals.array() += shift; solver.m_info = Success; solver.m_isInitialized = true; @@ -679,7 +656,7 @@ template struct direct_selfadjoint_eigenvalues struct direct_selfadjoint_eigenvalues struct direct_selfadjoint_eigenvaluesc2) + if((eivals(1)-eivals(0))<=abs(eivals(1))*Eigen::NumTraits::epsilon()) { - eivecs.col(1) << -scaledMat(1,0), scaledMat(0,0); - eivecs.col(1) /= sqrt(a2+b2); + eivecs.setIdentity(); } else { - eivecs.col(1) << -scaledMat(1,1), scaledMat(1,0); - eivecs.col(1) /= sqrt(c2+b2); - } + scaledMat.diagonal().array () -= eivals(1); + Scalar a2 = numext::abs2(scaledMat(0,0)); + Scalar c2 = numext::abs2(scaledMat(1,1)); + Scalar b2 = numext::abs2(scaledMat(1,0)); + if(a2>c2) + { + eivecs.col(1) << -scaledMat(1,0), scaledMat(0,0); + eivecs.col(1) /= sqrt(a2+b2); + } + else + { + eivecs.col(1) << -scaledMat(1,1), scaledMat(1,0); + eivecs.col(1) /= sqrt(c2+b2); + } - eivecs.col(0) << eivecs.col(1).unitOrthogonal(); + eivecs.col(0) << eivecs.col(1).unitOrthogonal(); + } } // Rescale back to the original size. diff --git a/uppsrc/plugin/Eigen/Eigen/src/Geometry/AlignedBox.h b/uppsrc/plugin/Eigen/Eigen/src/Geometry/AlignedBox.h index 8e186d57a..b226336de 100644 --- a/uppsrc/plugin/Eigen/Eigen/src/Geometry/AlignedBox.h +++ b/uppsrc/plugin/Eigen/Eigen/src/Geometry/AlignedBox.h @@ -19,10 +19,12 @@ namespace Eigen { * * \brief An axis aligned box * - * \param _Scalar the type of the scalar coefficients - * \param _AmbientDim the dimension of the ambient space, can be a compile time value or Dynamic. + * \tparam _Scalar the type of the scalar coefficients + * \tparam _AmbientDim the dimension of the ambient space, can be a compile time value or Dynamic. * * This class represents an axis aligned box as a pair of the minimal and maximal corners. + * \warning The result of most methods is undefined when applied to an empty box. You can check for empty boxes using isEmpty(). + * \sa alignedboxtypedefs */ template class AlignedBox @@ -40,18 +42,21 @@ EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(_Scalar,_AmbientDim) /** Define constants to name the corners of a 1D, 2D or 3D axis aligned bounding box */ enum CornerType { - /** 1D names */ + /** 1D names @{ */ Min=0, Max=1, + /** @} */ - /** Added names for 2D */ + /** Identifier for 2D corner @{ */ BottomLeft=0, BottomRight=1, TopLeft=2, TopRight=3, + /** @} */ - /** Added names for 3D */ + /** Identifier for 3D corner @{ */ BottomLeftFloor=0, BottomRightFloor=1, TopLeftFloor=2, TopRightFloor=3, BottomLeftCeil=4, BottomRightCeil=5, TopLeftCeil=6, TopRightCeil=7 + /** @} */ }; @@ -63,34 +68,33 @@ EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(_Scalar,_AmbientDim) inline explicit AlignedBox(Index _dim) : m_min(_dim), m_max(_dim) { setEmpty(); } - /** Constructs a box with extremities \a _min and \a _max. */ + /** Constructs a box with extremities \a _min and \a _max. + * \warning If either component of \a _min is larger than the same component of \a _max, the constructed box is empty. */ template inline AlignedBox(const OtherVectorType1& _min, const OtherVectorType2& _max) : m_min(_min), m_max(_max) {} /** Constructs a box containing a single point \a p. */ template - inline explicit AlignedBox(const MatrixBase& a_p) - { - typename internal::nested::type p(a_p.derived()); - m_min = p; - m_max = p; - } + inline explicit AlignedBox(const MatrixBase& p) : m_min(p), m_max(m_min) + { } ~AlignedBox() {} /** \returns the dimension in which the box holds */ inline Index dim() const { return AmbientDimAtCompileTime==Dynamic ? m_min.size() : Index(AmbientDimAtCompileTime); } - /** \deprecated use isEmpty */ + /** \deprecated use isEmpty() */ inline bool isNull() const { return isEmpty(); } - /** \deprecated use setEmpty */ + /** \deprecated use setEmpty() */ inline void setNull() { setEmpty(); } - /** \returns true if the box is empty. */ + /** \returns true if the box is empty. + * \sa setEmpty */ inline bool isEmpty() const { return (m_min.array() > m_max.array()).any(); } - /** Makes \c *this an empty box. */ + /** Makes \c *this an empty box. + * \sa isEmpty */ inline void setEmpty() { m_min.setConstant( ScalarTraits::highest() ); @@ -175,27 +179,34 @@ EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(_Scalar,_AmbientDim) /** \returns true if the point \a p is inside the box \c *this. */ template - inline bool contains(const MatrixBase& a_p) const + inline bool contains(const MatrixBase& p) const { - typename internal::nested::type p(a_p.derived()); - return (m_min.array()<=p.array()).all() && (p.array()<=m_max.array()).all(); + typename internal::nested::type p_n(p.derived()); + return (m_min.array()<=p_n.array()).all() && (p_n.array()<=m_max.array()).all(); } /** \returns true if the box \a b is entirely inside the box \c *this. */ inline bool contains(const AlignedBox& b) const { return (m_min.array()<=(b.min)().array()).all() && ((b.max)().array()<=m_max.array()).all(); } - /** Extends \c *this such that it contains the point \a p and returns a reference to \c *this. */ + /** \returns true if the box \a b is intersecting the box \c *this. + * \sa intersection, clamp */ + inline bool intersects(const AlignedBox& b) const + { return (m_min.array()<=(b.max)().array()).all() && ((b.min)().array()<=m_max.array()).all(); } + + /** Extends \c *this such that it contains the point \a p and returns a reference to \c *this. + * \sa extend(const AlignedBox&) */ template - inline AlignedBox& extend(const MatrixBase& a_p) + inline AlignedBox& extend(const MatrixBase& p) { - typename internal::nested::type p(a_p.derived()); - m_min = m_min.cwiseMin(p); - m_max = m_max.cwiseMax(p); + typename internal::nested::type p_n(p.derived()); + m_min = m_min.cwiseMin(p_n); + m_max = m_max.cwiseMax(p_n); return *this; } - /** Extends \c *this such that it contains the box \a b and returns a reference to \c *this. */ + /** Extends \c *this such that it contains the box \a b and returns a reference to \c *this. + * \sa merged, extend(const MatrixBase&) */ inline AlignedBox& extend(const AlignedBox& b) { m_min = m_min.cwiseMin(b.m_min); @@ -203,7 +214,9 @@ EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(_Scalar,_AmbientDim) return *this; } - /** Clamps \c *this by the box \a b and returns a reference to \c *this. */ + /** Clamps \c *this by the box \a b and returns a reference to \c *this. + * \note If the boxes don't intersect, the resulting box is empty. + * \sa intersection(), intersects() */ inline AlignedBox& clamp(const AlignedBox& b) { m_min = m_min.cwiseMax(b.m_min); @@ -211,11 +224,15 @@ EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(_Scalar,_AmbientDim) return *this; } - /** Returns an AlignedBox that is the intersection of \a b and \c *this */ + /** Returns an AlignedBox that is the intersection of \a b and \c *this + * \note If the boxes don't intersect, the resulting box is empty. + * \sa intersects(), clamp, contains() */ inline AlignedBox intersection(const AlignedBox& b) const {return AlignedBox(m_min.cwiseMax(b.m_min), m_max.cwiseMin(b.m_max)); } - /** Returns an AlignedBox that is the union of \a b and \c *this */ + /** Returns an AlignedBox that is the union of \a b and \c *this. + * \note Merging with an empty box may result in a box bigger than \c *this. + * \sa extend(const AlignedBox&) */ inline AlignedBox merged(const AlignedBox& b) const { return AlignedBox(m_min.cwiseMin(b.m_min), m_max.cwiseMax(b.m_max)); } @@ -231,20 +248,20 @@ EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(_Scalar,_AmbientDim) /** \returns the squared distance between the point \a p and the box \c *this, * and zero if \a p is inside the box. - * \sa exteriorDistance() + * \sa exteriorDistance(const MatrixBase&), squaredExteriorDistance(const AlignedBox&) */ template - inline Scalar squaredExteriorDistance(const MatrixBase& a_p) const; + inline Scalar squaredExteriorDistance(const MatrixBase& p) const; /** \returns the squared distance between the boxes \a b and \c *this, * and zero if the boxes intersect. - * \sa exteriorDistance() + * \sa exteriorDistance(const AlignedBox&), squaredExteriorDistance(const MatrixBase&) */ inline Scalar squaredExteriorDistance(const AlignedBox& b) const; /** \returns the distance between the point \a p and the box \c *this, * and zero if \a p is inside the box. - * \sa squaredExteriorDistance() + * \sa squaredExteriorDistance(const MatrixBase&), exteriorDistance(const AlignedBox&) */ template inline NonInteger exteriorDistance(const MatrixBase& p) const @@ -252,7 +269,7 @@ EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(_Scalar,_AmbientDim) /** \returns the distance between the boxes \a b and \c *this, * and zero if the boxes intersect. - * \sa squaredExteriorDistance() + * \sa squaredExteriorDistance(const AlignedBox&), exteriorDistance(const MatrixBase&) */ inline NonInteger exteriorDistance(const AlignedBox& b) const { using std::sqrt; return sqrt(NonInteger(squaredExteriorDistance(b))); } diff --git a/uppsrc/plugin/Eigen/Eigen/src/Geometry/CMakeLists.txt b/uppsrc/plugin/Eigen/Eigen/src/Geometry/CMakeLists.txt new file mode 100644 index 000000000..f8f728b84 --- /dev/null +++ b/uppsrc/plugin/Eigen/Eigen/src/Geometry/CMakeLists.txt @@ -0,0 +1,8 @@ +FILE(GLOB Eigen_Geometry_SRCS "*.h") + +INSTALL(FILES + ${Eigen_Geometry_SRCS} + DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen/src/Geometry COMPONENT Devel + ) + +ADD_SUBDIRECTORY(arch) diff --git a/uppsrc/plugin/Eigen/Eigen/src/Geometry/Homogeneous.h b/uppsrc/plugin/Eigen/Eigen/src/Geometry/Homogeneous.h index 00e71d190..372e422b9 100644 --- a/uppsrc/plugin/Eigen/Eigen/src/Geometry/Homogeneous.h +++ b/uppsrc/plugin/Eigen/Eigen/src/Geometry/Homogeneous.h @@ -79,7 +79,7 @@ template class Homogeneous { if( (int(Direction)==Vertical && row==m_matrix.rows()) || (int(Direction)==Horizontal && col==m_matrix.cols())) - return 1; + return Scalar(1); return m_matrix.coeff(row, col); } diff --git a/uppsrc/plugin/Eigen/Eigen/src/Geometry/Quaternion.h b/uppsrc/plugin/Eigen/Eigen/src/Geometry/Quaternion.h index f06653f1c..93056f60d 100644 --- a/uppsrc/plugin/Eigen/Eigen/src/Geometry/Quaternion.h +++ b/uppsrc/plugin/Eigen/Eigen/src/Geometry/Quaternion.h @@ -161,7 +161,7 @@ public: { return coeffs().isApprox(other.coeffs(), prec); } /** return the result vector of \a v through the rotation*/ - EIGEN_STRONG_INLINE Vector3 _transformVector(Vector3 v) const; + EIGEN_STRONG_INLINE Vector3 _transformVector(const Vector3& v) const; /** \returns \c *this with scalar type casted to \a NewScalarType * @@ -231,7 +231,7 @@ class Quaternion : public QuaternionBase > public: typedef _Scalar Scalar; - EIGEN_INHERIT_ASSIGNMENT_EQUAL_OPERATOR(Quaternion) + EIGEN_INHERIT_ASSIGNMENT_OPERATORS(Quaternion) using Base::operator*=; typedef typename internal::traits::Coefficients Coefficients; @@ -341,7 +341,7 @@ class Map, _Options > public: typedef _Scalar Scalar; typedef typename internal::traits::Coefficients Coefficients; - EIGEN_INHERIT_ASSIGNMENT_EQUAL_OPERATOR(Map) + EIGEN_INHERIT_ASSIGNMENT_OPERATORS(Map) using Base::operator*=; /** Constructs a Mapped Quaternion object from the pointer \a coeffs @@ -378,7 +378,7 @@ class Map, _Options > public: typedef _Scalar Scalar; typedef typename internal::traits::Coefficients Coefficients; - EIGEN_INHERIT_ASSIGNMENT_EQUAL_OPERATOR(Map) + EIGEN_INHERIT_ASSIGNMENT_OPERATORS(Map) using Base::operator*=; /** Constructs a Mapped Quaternion object from the pointer \a coeffs @@ -461,7 +461,7 @@ EIGEN_STRONG_INLINE Derived& QuaternionBase::operator*= (const Quaterni */ template EIGEN_STRONG_INLINE typename QuaternionBase::Vector3 -QuaternionBase::_transformVector(Vector3 v) const +QuaternionBase::_transformVector(const Vector3& v) const { // Note that this algorithm comes from the optimization by hand // of the conversion to a Matrix followed by a Matrix/Vector product. @@ -637,7 +637,7 @@ inline Quaternion::Scalar> QuaternionBasesquaredNorm(); - if (n2 > 0) + if (n2 > Scalar(0)) return Quaternion(conjugate().coeffs() / n2); else { @@ -667,12 +667,10 @@ template inline typename internal::traits::Scalar QuaternionBase::angularDistance(const QuaternionBase& other) const { - using std::acos; + using std::atan2; using std::abs; - Scalar d = abs(this->dot(other)); - if (d>=Scalar(1)) - return Scalar(0); - return Scalar(2) * acos(d); + Quaternion d = (*this) * other.conjugate(); + return Scalar(2) * atan2( d.vec().norm(), abs(d.w()) ); } @@ -712,7 +710,7 @@ QuaternionBase::slerp(const Scalar& t, const QuaternionBase(scale0 * coeffs() + scale1 * other.coeffs()); } diff --git a/uppsrc/plugin/Eigen/Eigen/src/Geometry/Rotation2D.h b/uppsrc/plugin/Eigen/Eigen/src/Geometry/Rotation2D.h index 776c36144..a2d59fce1 100644 --- a/uppsrc/plugin/Eigen/Eigen/src/Geometry/Rotation2D.h +++ b/uppsrc/plugin/Eigen/Eigen/src/Geometry/Rotation2D.h @@ -59,7 +59,7 @@ protected: public: /** Construct a 2D counter clock wise rotation from the angle \a a in radian. */ - explicit inline Rotation2D(const Scalar& a) : m_angle(a) {} + inline Rotation2D(const Scalar& a) : m_angle(a) {} /** Default constructor wihtout initialization. The represented rotation is undefined. */ Rotation2D() {} diff --git a/uppsrc/plugin/Eigen/Eigen/src/Geometry/arch/CMakeLists.txt b/uppsrc/plugin/Eigen/Eigen/src/Geometry/arch/CMakeLists.txt new file mode 100644 index 000000000..1267a79c7 --- /dev/null +++ b/uppsrc/plugin/Eigen/Eigen/src/Geometry/arch/CMakeLists.txt @@ -0,0 +1,6 @@ +FILE(GLOB Eigen_Geometry_arch_SRCS "*.h") + +INSTALL(FILES + ${Eigen_Geometry_arch_SRCS} + DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen/src/Geometry/arch COMPONENT Devel + ) diff --git a/uppsrc/plugin/Eigen/Eigen/src/Householder/CMakeLists.txt b/uppsrc/plugin/Eigen/Eigen/src/Householder/CMakeLists.txt new file mode 100644 index 000000000..ce4937db0 --- /dev/null +++ b/uppsrc/plugin/Eigen/Eigen/src/Householder/CMakeLists.txt @@ -0,0 +1,6 @@ +FILE(GLOB Eigen_Householder_SRCS "*.h") + +INSTALL(FILES + ${Eigen_Householder_SRCS} + DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen/src/Householder COMPONENT Devel + ) diff --git a/uppsrc/plugin/Eigen/Eigen/src/IterativeLinearSolvers/BiCGSTAB.h b/uppsrc/plugin/Eigen/Eigen/src/IterativeLinearSolvers/BiCGSTAB.h index dd135c21f..2625c4dc3 100644 --- a/uppsrc/plugin/Eigen/Eigen/src/IterativeLinearSolvers/BiCGSTAB.h +++ b/uppsrc/plugin/Eigen/Eigen/src/IterativeLinearSolvers/BiCGSTAB.h @@ -151,20 +151,7 @@ struct traits > * \endcode * * By default the iterations start with x=0 as an initial guess of the solution. - * One can control the start using the solveWithGuess() method. Here is a step by - * step execution example starting with a random guess and printing the evolution - * of the estimated error: - * * \code - * x = VectorXd::Random(n); - * solver.setMaxIterations(1); - * int i = 0; - * do { - * x = solver.solveWithGuess(b,x); - * std::cout << i << " : " << solver.error() << std::endl; - * ++i; - * } while (solver.info()!=Success && i<100); - * \endcode - * Note that such a step by step excution is slightly slower. + * One can control the start using the solveWithGuess() method. * * \sa class SimplicialCholesky, DiagonalPreconditioner, IdentityPreconditioner */ diff --git a/uppsrc/plugin/Eigen/Eigen/src/IterativeLinearSolvers/CMakeLists.txt b/uppsrc/plugin/Eigen/Eigen/src/IterativeLinearSolvers/CMakeLists.txt new file mode 100644 index 000000000..59ccc0072 --- /dev/null +++ b/uppsrc/plugin/Eigen/Eigen/src/IterativeLinearSolvers/CMakeLists.txt @@ -0,0 +1,6 @@ +FILE(GLOB Eigen_IterativeLinearSolvers_SRCS "*.h") + +INSTALL(FILES + ${Eigen_IterativeLinearSolvers_SRCS} + DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen/src/IterativeLinearSolvers COMPONENT Devel + ) diff --git a/uppsrc/plugin/Eigen/Eigen/src/IterativeLinearSolvers/ConjugateGradient.h b/uppsrc/plugin/Eigen/Eigen/src/IterativeLinearSolvers/ConjugateGradient.h index a74a8155e..8ba4a8dbe 100644 --- a/uppsrc/plugin/Eigen/Eigen/src/IterativeLinearSolvers/ConjugateGradient.h +++ b/uppsrc/plugin/Eigen/Eigen/src/IterativeLinearSolvers/ConjugateGradient.h @@ -112,9 +112,9 @@ struct traits > * This class allows to solve for A.x = b sparse linear problems using a conjugate gradient algorithm. * The sparse matrix A must be selfadjoint. The vectors x and b can be either dense or sparse. * - * \tparam _MatrixType the type of the sparse matrix A, can be a dense or a sparse matrix. - * \tparam _UpLo the triangular part that will be used for the computations. It can be Lower - * or Upper. Default is Lower. + * \tparam _MatrixType the type of the matrix A, can be a dense or a sparse matrix. + * \tparam _UpLo the triangular part that will be used for the computations. It can be Lower, + * Upper, or Lower|Upper in which the full matrix entries will be considered. Default is Lower. * \tparam _Preconditioner the type of the preconditioner. Default is DiagonalPreconditioner * * The maximal number of iterations and tolerance value can be controlled via the setMaxIterations() @@ -137,20 +137,7 @@ struct traits > * \endcode * * By default the iterations start with x=0 as an initial guess of the solution. - * One can control the start using the solveWithGuess() method. Here is a step by - * step execution example starting with a random guess and printing the evolution - * of the estimated error: - * * \code - * x = VectorXd::Random(n); - * cg.setMaxIterations(1); - * int i = 0; - * do { - * x = cg.solveWithGuess(b,x); - * std::cout << i << " : " << cg.error() << std::endl; - * ++i; - * } while (cg.info()!=Success && i<100); - * \endcode - * Note that such a step by step excution is slightly slower. + * One can control the start using the solveWithGuess() method. * * \sa class SimplicialCholesky, DiagonalPreconditioner, IdentityPreconditioner */ @@ -213,6 +200,10 @@ public: template void _solveWithGuess(const Rhs& b, Dest& x) const { + typedef typename internal::conditional + >::type MatrixWrapperType; m_iterations = Base::maxIterations(); m_error = Base::m_tolerance; @@ -222,8 +213,7 @@ public: m_error = Base::m_tolerance; typename Dest::ColXpr xj(x,j); - internal::conjugate_gradient(mp_matrix->template selfadjointView(), b.col(j), xj, - Base::m_preconditioner, m_iterations, m_error); + internal::conjugate_gradient(MatrixWrapperType(*mp_matrix), b.col(j), xj, Base::m_preconditioner, m_iterations, m_error); } m_isInitialized = true; @@ -234,7 +224,7 @@ public: template void _solve(const Rhs& b, Dest& x) const { - x.setOnes(); + x.setZero(); _solveWithGuess(b,x); } diff --git a/uppsrc/plugin/Eigen/Eigen/src/IterativeLinearSolvers/IncompleteLUT.h b/uppsrc/plugin/Eigen/Eigen/src/IterativeLinearSolvers/IncompleteLUT.h index b55afc136..4c169aa60 100644 --- a/uppsrc/plugin/Eigen/Eigen/src/IterativeLinearSolvers/IncompleteLUT.h +++ b/uppsrc/plugin/Eigen/Eigen/src/IterativeLinearSolvers/IncompleteLUT.h @@ -150,7 +150,6 @@ class IncompleteLUT : internal::noncopyable { analyzePattern(amat); factorize(amat); - m_isInitialized = m_factorizationIsOk; return *this; } @@ -235,6 +234,8 @@ void IncompleteLUT::analyzePattern(const _MatrixType& amat) m_Pinv = m_P.inverse(); // ... and the inverse permutation m_analysisIsOk = true; + m_factorizationIsOk = false; + m_isInitialized = false; } template @@ -442,6 +443,7 @@ void IncompleteLUT::factorize(const _MatrixType& amat) m_lu.makeCompressed(); m_factorizationIsOk = true; + m_isInitialized = m_factorizationIsOk; m_info = Success; } diff --git a/uppsrc/plugin/Eigen/Eigen/src/Jacobi/CMakeLists.txt b/uppsrc/plugin/Eigen/Eigen/src/Jacobi/CMakeLists.txt new file mode 100644 index 000000000..490dac626 --- /dev/null +++ b/uppsrc/plugin/Eigen/Eigen/src/Jacobi/CMakeLists.txt @@ -0,0 +1,6 @@ +FILE(GLOB Eigen_Jacobi_SRCS "*.h") + +INSTALL(FILES + ${Eigen_Jacobi_SRCS} + DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen/src/Jacobi COMPONENT Devel + ) diff --git a/uppsrc/plugin/Eigen/Eigen/src/LU/CMakeLists.txt b/uppsrc/plugin/Eigen/Eigen/src/LU/CMakeLists.txt new file mode 100644 index 000000000..e0d8d78c1 --- /dev/null +++ b/uppsrc/plugin/Eigen/Eigen/src/LU/CMakeLists.txt @@ -0,0 +1,8 @@ +FILE(GLOB Eigen_LU_SRCS "*.h") + +INSTALL(FILES + ${Eigen_LU_SRCS} + DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen/src/LU COMPONENT Devel + ) + +ADD_SUBDIRECTORY(arch) diff --git a/uppsrc/plugin/Eigen/Eigen/src/LU/FullPivLU.h b/uppsrc/plugin/Eigen/Eigen/src/LU/FullPivLU.h index 79ab6a8c8..26bc71447 100644 --- a/uppsrc/plugin/Eigen/Eigen/src/LU/FullPivLU.h +++ b/uppsrc/plugin/Eigen/Eigen/src/LU/FullPivLU.h @@ -374,6 +374,12 @@ template class FullPivLU inline Index cols() const { return m_lu.cols(); } protected: + + static void check_template_parameters() + { + EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar); + } + MatrixType m_lu; PermutationPType m_p; PermutationQType m_q; @@ -418,6 +424,8 @@ FullPivLU::FullPivLU(const MatrixType& matrix) template FullPivLU& FullPivLU::compute(const MatrixType& matrix) { + check_template_parameters(); + // the permutations are stored as int indices, so just to be sure: eigen_assert(matrix.rows()<=NumTraits::highest() && matrix.cols()<=NumTraits::highest()); diff --git a/uppsrc/plugin/Eigen/Eigen/src/LU/PartialPivLU.h b/uppsrc/plugin/Eigen/Eigen/src/LU/PartialPivLU.h index 740ee694c..7d1db948c 100644 --- a/uppsrc/plugin/Eigen/Eigen/src/LU/PartialPivLU.h +++ b/uppsrc/plugin/Eigen/Eigen/src/LU/PartialPivLU.h @@ -171,6 +171,12 @@ template class PartialPivLU inline Index cols() const { return m_lu.cols(); } protected: + + static void check_template_parameters() + { + EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar); + } + MatrixType m_lu; PermutationType m_p; TranspositionType m_rowsTranspositions; @@ -386,6 +392,8 @@ void partial_lu_inplace(MatrixType& lu, TranspositionType& row_transpositions, t template PartialPivLU& PartialPivLU::compute(const MatrixType& matrix) { + check_template_parameters(); + // the row permutation is stored as int indices, so just to be sure: eigen_assert(matrix.rows()::highest()); diff --git a/uppsrc/plugin/Eigen/Eigen/src/LU/arch/CMakeLists.txt b/uppsrc/plugin/Eigen/Eigen/src/LU/arch/CMakeLists.txt new file mode 100644 index 000000000..f6b7ed9ec --- /dev/null +++ b/uppsrc/plugin/Eigen/Eigen/src/LU/arch/CMakeLists.txt @@ -0,0 +1,6 @@ +FILE(GLOB Eigen_LU_arch_SRCS "*.h") + +INSTALL(FILES + ${Eigen_LU_arch_SRCS} + DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen/src/LU/arch COMPONENT Devel + ) diff --git a/uppsrc/plugin/Eigen/Eigen/src/MetisSupport/CMakeLists.txt b/uppsrc/plugin/Eigen/Eigen/src/MetisSupport/CMakeLists.txt new file mode 100644 index 000000000..2bad31416 --- /dev/null +++ b/uppsrc/plugin/Eigen/Eigen/src/MetisSupport/CMakeLists.txt @@ -0,0 +1,6 @@ +FILE(GLOB Eigen_MetisSupport_SRCS "*.h") + +INSTALL(FILES + ${Eigen_MetisSupport_SRCS} + DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen/src/MetisSupport COMPONENT Devel + ) diff --git a/uppsrc/plugin/Eigen/Eigen/src/OrderingMethods/Amd.h b/uppsrc/plugin/Eigen/Eigen/src/OrderingMethods/Amd.h index 41b4fd7e3..1c28bdf41 100644 --- a/uppsrc/plugin/Eigen/Eigen/src/OrderingMethods/Amd.h +++ b/uppsrc/plugin/Eigen/Eigen/src/OrderingMethods/Amd.h @@ -144,15 +144,23 @@ void minimum_degree_ordering(SparseMatrix& C, Permutation /* --- Initialize degree lists ------------------------------------------ */ for(i = 0; i < n; i++) { + bool has_diag = false; + for(p = Cp[i]; p dense) /* node i is dense */ + else if(d > dense || !has_diag) /* node i is dense or has no structural diagonal element */ { nv[i] = 0; /* absorb i into element n */ elen[i] = -1; /* node i is dead */ @@ -168,6 +176,10 @@ void minimum_degree_ordering(SparseMatrix& C, Permutation } } + elen[n] = -2; /* n is a dead element */ + Cp[n] = -1; /* n is a root of assembly tree */ + w[n] = 0; /* n is a dead element */ + while (nel < n) /* while (selecting pivots) do */ { /* --- Select node of minimum approximate degree -------------------- */ diff --git a/uppsrc/plugin/Eigen/Eigen/src/OrderingMethods/CMakeLists.txt b/uppsrc/plugin/Eigen/Eigen/src/OrderingMethods/CMakeLists.txt new file mode 100644 index 000000000..9f4bb2758 --- /dev/null +++ b/uppsrc/plugin/Eigen/Eigen/src/OrderingMethods/CMakeLists.txt @@ -0,0 +1,6 @@ +FILE(GLOB Eigen_OrderingMethods_SRCS "*.h") + +INSTALL(FILES + ${Eigen_OrderingMethods_SRCS} + DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen/src/OrderingMethods COMPONENT Devel + ) diff --git a/uppsrc/plugin/Eigen/Eigen/src/PaStiXSupport/CMakeLists.txt b/uppsrc/plugin/Eigen/Eigen/src/PaStiXSupport/CMakeLists.txt new file mode 100644 index 000000000..28c657e9b --- /dev/null +++ b/uppsrc/plugin/Eigen/Eigen/src/PaStiXSupport/CMakeLists.txt @@ -0,0 +1,6 @@ +FILE(GLOB Eigen_PastixSupport_SRCS "*.h") + +INSTALL(FILES + ${Eigen_PastixSupport_SRCS} + DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen/src/PaStiXSupport COMPONENT Devel + ) diff --git a/uppsrc/plugin/Eigen/Eigen/src/PardisoSupport/CMakeLists.txt b/uppsrc/plugin/Eigen/Eigen/src/PardisoSupport/CMakeLists.txt new file mode 100644 index 000000000..a097ab401 --- /dev/null +++ b/uppsrc/plugin/Eigen/Eigen/src/PardisoSupport/CMakeLists.txt @@ -0,0 +1,6 @@ +FILE(GLOB Eigen_PardisoSupport_SRCS "*.h") + +INSTALL(FILES + ${Eigen_PardisoSupport_SRCS} + DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen/src/PardisoSupport COMPONENT Devel + ) diff --git a/uppsrc/plugin/Eigen/Eigen/src/QR/CMakeLists.txt b/uppsrc/plugin/Eigen/Eigen/src/QR/CMakeLists.txt new file mode 100644 index 000000000..96f43d7f5 --- /dev/null +++ b/uppsrc/plugin/Eigen/Eigen/src/QR/CMakeLists.txt @@ -0,0 +1,6 @@ +FILE(GLOB Eigen_QR_SRCS "*.h") + +INSTALL(FILES + ${Eigen_QR_SRCS} + DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen/src/QR COMPONENT Devel + ) diff --git a/uppsrc/plugin/Eigen/Eigen/src/QR/ColPivHouseholderQR.h b/uppsrc/plugin/Eigen/Eigen/src/QR/ColPivHouseholderQR.h index 773d1df8f..567eab7cd 100644 --- a/uppsrc/plugin/Eigen/Eigen/src/QR/ColPivHouseholderQR.h +++ b/uppsrc/plugin/Eigen/Eigen/src/QR/ColPivHouseholderQR.h @@ -384,6 +384,12 @@ template class ColPivHouseholderQR } protected: + + static void check_template_parameters() + { + EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar); + } + MatrixType m_qr; HCoeffsType m_hCoeffs; PermutationType m_colsPermutation; @@ -422,6 +428,8 @@ typename MatrixType::RealScalar ColPivHouseholderQR::logAbsDetermina template ColPivHouseholderQR& ColPivHouseholderQR::compute(const MatrixType& matrix) { + check_template_parameters(); + using std::abs; Index rows = matrix.rows(); Index cols = matrix.cols(); @@ -463,20 +471,10 @@ ColPivHouseholderQR& ColPivHouseholderQR::compute(const // we store that back into our table: it can't hurt to correct our table. m_colSqNorms.coeffRef(biggest_col_index) = biggest_col_sq_norm; - // if the current biggest column is smaller than epsilon times the initial biggest column, - // terminate to avoid generating nan/inf values. - // Note that here, if we test instead for "biggest == 0", we get a failure every 1000 (or so) - // repetitions of the unit test, with the result of solve() filled with large values of the order - // of 1/(size*epsilon). - if(biggest_col_sq_norm < threshold_helper * RealScalar(rows-k)) - { + // Track the number of meaningful pivots but do not stop the decomposition to make + // sure that the initial matrix is properly reproduced. See bug 941. + if(m_nonzero_pivots==size && biggest_col_sq_norm < threshold_helper * RealScalar(rows-k)) m_nonzero_pivots = k; - m_hCoeffs.tail(size-k).setZero(); - m_qr.bottomRightCorner(rows-k,cols-k) - .template triangularView() - .setZero(); - break; - } // apply the transposition to the columns m_colsTranspositions.coeffRef(k) = biggest_col_index; @@ -505,7 +503,7 @@ ColPivHouseholderQR& ColPivHouseholderQR::compute(const } m_colsPermutation.setIdentity(PermIndexType(cols)); - for(PermIndexType k = 0; k < m_nonzero_pivots; ++k) + for(PermIndexType k = 0; k < size/*m_nonzero_pivots*/; ++k) m_colsPermutation.applyTranspositionOnTheRight(k, PermIndexType(m_colsTranspositions.coeff(k))); m_det_pq = (number_of_transpositions%2) ? -1 : 1; @@ -555,13 +553,15 @@ struct solve_retval, Rhs> } // end namespace internal -/** \returns the matrix Q as a sequence of householder transformations */ +/** \returns the matrix Q as a sequence of householder transformations. + * You can extract the meaningful part only by using: + * \code qr.householderQ().setLength(qr.nonzeroPivots()) \endcode*/ template typename ColPivHouseholderQR::HouseholderSequenceType ColPivHouseholderQR ::householderQ() const { eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized."); - return HouseholderSequenceType(m_qr, m_hCoeffs.conjugate()).setLength(m_nonzero_pivots); + return HouseholderSequenceType(m_qr, m_hCoeffs.conjugate()); } /** \return the column-pivoting Householder QR decomposition of \c *this. diff --git a/uppsrc/plugin/Eigen/Eigen/src/QR/FullPivHouseholderQR.h b/uppsrc/plugin/Eigen/Eigen/src/QR/FullPivHouseholderQR.h index 6168e7abf..0b39966e1 100644 --- a/uppsrc/plugin/Eigen/Eigen/src/QR/FullPivHouseholderQR.h +++ b/uppsrc/plugin/Eigen/Eigen/src/QR/FullPivHouseholderQR.h @@ -368,6 +368,12 @@ template class FullPivHouseholderQR RealScalar maxPivot() const { return m_maxpivot; } protected: + + static void check_template_parameters() + { + EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar); + } + MatrixType m_qr; HCoeffsType m_hCoeffs; IntDiagSizeVectorType m_rows_transpositions; @@ -407,6 +413,8 @@ typename MatrixType::RealScalar FullPivHouseholderQR::logAbsDetermin template FullPivHouseholderQR& FullPivHouseholderQR::compute(const MatrixType& matrix) { + check_template_parameters(); + using std::abs; Index rows = matrix.rows(); Index cols = matrix.cols(); diff --git a/uppsrc/plugin/Eigen/Eigen/src/QR/HouseholderQR.h b/uppsrc/plugin/Eigen/Eigen/src/QR/HouseholderQR.h index abc61bcbb..343a66499 100644 --- a/uppsrc/plugin/Eigen/Eigen/src/QR/HouseholderQR.h +++ b/uppsrc/plugin/Eigen/Eigen/src/QR/HouseholderQR.h @@ -189,6 +189,12 @@ template class HouseholderQR const HCoeffsType& hCoeffs() const { return m_hCoeffs; } protected: + + static void check_template_parameters() + { + EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar); + } + MatrixType m_qr; HCoeffsType m_hCoeffs; RowVectorType m_temp; @@ -251,56 +257,62 @@ void householder_qr_inplace_unblocked(MatrixQR& mat, HCoeffs& hCoeffs, typename } /** \internal */ -template -void householder_qr_inplace_blocked(MatrixQR& mat, HCoeffs& hCoeffs, - typename MatrixQR::Index maxBlockSize=32, - typename MatrixQR::Scalar* tempData = 0) +template +struct householder_qr_inplace_blocked { - typedef typename MatrixQR::Index Index; - typedef typename MatrixQR::Scalar Scalar; - typedef Block BlockType; - - Index rows = mat.rows(); - Index cols = mat.cols(); - Index size = (std::min)(rows, cols); - - typedef Matrix TempType; - TempType tempVector; - if(tempData==0) + // This is specialized for MKL-supported Scalar types in HouseholderQR_MKL.h + static void run(MatrixQR& mat, HCoeffs& hCoeffs, + typename MatrixQR::Index maxBlockSize=32, + typename MatrixQR::Scalar* tempData = 0) { - tempVector.resize(cols); - tempData = tempVector.data(); - } + typedef typename MatrixQR::Index Index; + typedef typename MatrixQR::Scalar Scalar; + typedef Block BlockType; - Index blockSize = (std::min)(maxBlockSize,size); + Index rows = mat.rows(); + Index cols = mat.cols(); + Index size = (std::min)(rows, cols); - Index k = 0; - for (k = 0; k < size; k += blockSize) - { - Index bs = (std::min)(size-k,blockSize); // actual size of the block - Index tcols = cols - k - bs; // trailing columns - Index brows = rows-k; // rows of the block - - // partition the matrix: - // A00 | A01 | A02 - // mat = A10 | A11 | A12 - // A20 | A21 | A22 - // and performs the qr dec of [A11^T A12^T]^T - // and update [A21^T A22^T]^T using level 3 operations. - // Finally, the algorithm continue on A22 - - BlockType A11_21 = mat.block(k,k,brows,bs); - Block hCoeffsSegment = hCoeffs.segment(k,bs); - - householder_qr_inplace_unblocked(A11_21, hCoeffsSegment, tempData); - - if(tcols) + typedef Matrix TempType; + TempType tempVector; + if(tempData==0) { - BlockType A21_22 = mat.block(k,k+bs,brows,tcols); - apply_block_householder_on_the_left(A21_22,A11_21,hCoeffsSegment.adjoint()); + tempVector.resize(cols); + tempData = tempVector.data(); + } + + Index blockSize = (std::min)(maxBlockSize,size); + + Index k = 0; + for (k = 0; k < size; k += blockSize) + { + Index bs = (std::min)(size-k,blockSize); // actual size of the block + Index tcols = cols - k - bs; // trailing columns + Index brows = rows-k; // rows of the block + + // partition the matrix: + // A00 | A01 | A02 + // mat = A10 | A11 | A12 + // A20 | A21 | A22 + // and performs the qr dec of [A11^T A12^T]^T + // and update [A21^T A22^T]^T using level 3 operations. + // Finally, the algorithm continue on A22 + + BlockType A11_21 = mat.block(k,k,brows,bs); + Block hCoeffsSegment = hCoeffs.segment(k,bs); + + householder_qr_inplace_unblocked(A11_21, hCoeffsSegment, tempData); + + if(tcols) + { + BlockType A21_22 = mat.block(k,k+bs,brows,tcols); + apply_block_householder_on_the_left(A21_22,A11_21,hCoeffsSegment.adjoint()); + } } } -} +}; template struct solve_retval, Rhs> @@ -343,6 +355,8 @@ struct solve_retval, Rhs> template HouseholderQR& HouseholderQR::compute(const MatrixType& matrix) { + check_template_parameters(); + Index rows = matrix.rows(); Index cols = matrix.cols(); Index size = (std::min)(rows,cols); @@ -352,7 +366,7 @@ HouseholderQR& HouseholderQR::compute(const MatrixType& m_temp.resize(cols); - internal::householder_qr_inplace_blocked(m_qr, m_hCoeffs, 48, m_temp.data()); + internal::householder_qr_inplace_blocked::run(m_qr, m_hCoeffs, 48, m_temp.data()); m_isInitialized = true; return *this; diff --git a/uppsrc/plugin/Eigen/Eigen/src/QR/HouseholderQR_MKL.h b/uppsrc/plugin/Eigen/Eigen/src/QR/HouseholderQR_MKL.h index 5313de604..b80f1b48d 100644 --- a/uppsrc/plugin/Eigen/Eigen/src/QR/HouseholderQR_MKL.h +++ b/uppsrc/plugin/Eigen/Eigen/src/QR/HouseholderQR_MKL.h @@ -34,28 +34,30 @@ #ifndef EIGEN_QR_MKL_H #define EIGEN_QR_MKL_H -#include "Eigen/src/Core/util/MKL_support.h" +#include "../Core/util/MKL_support.h" namespace Eigen { -namespace internal { + namespace internal { -/** \internal Specialization for the data types supported by MKL */ + /** \internal Specialization for the data types supported by MKL */ #define EIGEN_MKL_QR_NOPIV(EIGTYPE, MKLTYPE, MKLPREFIX) \ template \ -void householder_qr_inplace_blocked(MatrixQR& mat, HCoeffs& hCoeffs, \ - typename MatrixQR::Index maxBlockSize=32, \ - EIGTYPE* tempData = 0) \ +struct householder_qr_inplace_blocked \ { \ - lapack_int m = mat.rows(); \ - lapack_int n = mat.cols(); \ - lapack_int lda = mat.outerStride(); \ - lapack_int matrix_order = (MatrixQR::IsRowMajor) ? LAPACK_ROW_MAJOR : LAPACK_COL_MAJOR; \ - LAPACKE_##MKLPREFIX##geqrf( matrix_order, m, n, (MKLTYPE*)mat.data(), lda, (MKLTYPE*)hCoeffs.data()); \ - hCoeffs.adjointInPlace(); \ -\ -} + static void run(MatrixQR& mat, HCoeffs& hCoeffs, \ + typename MatrixQR::Index = 32, \ + typename MatrixQR::Scalar* = 0) \ + { \ + lapack_int m = (lapack_int) mat.rows(); \ + lapack_int n = (lapack_int) mat.cols(); \ + lapack_int lda = (lapack_int) mat.outerStride(); \ + lapack_int matrix_order = (MatrixQR::IsRowMajor) ? LAPACK_ROW_MAJOR : LAPACK_COL_MAJOR; \ + LAPACKE_##MKLPREFIX##geqrf( matrix_order, m, n, (MKLTYPE*)mat.data(), lda, (MKLTYPE*)hCoeffs.data()); \ + hCoeffs.adjointInPlace(); \ + } \ +}; EIGEN_MKL_QR_NOPIV(double, double, d) EIGEN_MKL_QR_NOPIV(float, float, s) diff --git a/uppsrc/plugin/Eigen/Eigen/src/SPQRSupport/CMakeLists.txt b/uppsrc/plugin/Eigen/Eigen/src/SPQRSupport/CMakeLists.txt new file mode 100644 index 000000000..4968beaf2 --- /dev/null +++ b/uppsrc/plugin/Eigen/Eigen/src/SPQRSupport/CMakeLists.txt @@ -0,0 +1,6 @@ +FILE(GLOB Eigen_SPQRSupport_SRCS "*.h") + +INSTALL(FILES + ${Eigen_SPQRSupport_SRCS} + DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen/src/SPQRSupport/ COMPONENT Devel + ) diff --git a/uppsrc/plugin/Eigen/Eigen/src/SPQRSupport/SuiteSparseQRSupport.h b/uppsrc/plugin/Eigen/Eigen/src/SPQRSupport/SuiteSparseQRSupport.h index a2cc2a9e2..de00877de 100644 --- a/uppsrc/plugin/Eigen/Eigen/src/SPQRSupport/SuiteSparseQRSupport.h +++ b/uppsrc/plugin/Eigen/Eigen/src/SPQRSupport/SuiteSparseQRSupport.h @@ -64,19 +64,13 @@ class SPQR typedef PermutationMatrix PermutationType; public: SPQR() - : m_isInitialized(false), - m_ordering(SPQR_ORDERING_DEFAULT), - m_allow_tol(SPQR_DEFAULT_TOL), - m_tolerance (NumTraits::epsilon()) + : m_isInitialized(false), m_ordering(SPQR_ORDERING_DEFAULT), m_allow_tol(SPQR_DEFAULT_TOL), m_tolerance (NumTraits::epsilon()), m_useDefaultThreshold(true) { cholmod_l_start(&m_cc); } - SPQR(const _MatrixType& matrix) - : m_isInitialized(false), - m_ordering(SPQR_ORDERING_DEFAULT), - m_allow_tol(SPQR_DEFAULT_TOL), - m_tolerance (NumTraits::epsilon()) + SPQR(const _MatrixType& matrix) + : m_isInitialized(false), m_ordering(SPQR_ORDERING_DEFAULT), m_allow_tol(SPQR_DEFAULT_TOL), m_tolerance (NumTraits::epsilon()), m_useDefaultThreshold(true) { cholmod_l_start(&m_cc); compute(matrix); @@ -101,10 +95,26 @@ class SPQR if(m_isInitialized) SPQR_free(); MatrixType mat(matrix); + + /* Compute the default threshold as in MatLab, see: + * Tim Davis, "Algorithm 915, SuiteSparseQR: Multifrontal Multithreaded Rank-Revealing + * Sparse QR Factorization, ACM Trans. on Math. Soft. 38(1), 2011, Page 8:3 + */ + RealScalar pivotThreshold = m_tolerance; + if(m_useDefaultThreshold) + { + using std::max; + RealScalar max2Norm = 0.0; + for (int j = 0; j < mat.cols(); j++) max2Norm = (max)(max2Norm, mat.col(j).norm()); + if(max2Norm==RealScalar(0)) + max2Norm = RealScalar(1); + pivotThreshold = 20 * (mat.rows() + mat.cols()) * max2Norm * NumTraits::epsilon(); + } + cholmod_sparse A; A = viewAsCholmod(mat); Index col = matrix.cols(); - m_rank = SuiteSparseQR(m_ordering, m_tolerance, col, &A, + m_rank = SuiteSparseQR(m_ordering, pivotThreshold, col, &A, &m_cR, &m_E, &m_H, &m_HPinv, &m_HTau, &m_cc); if (!m_cR) @@ -120,7 +130,7 @@ class SPQR /** * Get the number of rows of the input matrix and the Q matrix */ - inline Index rows() const {return m_H->nrow; } + inline Index rows() const {return m_cR->nrow; } /** * Get the number of columns of the input matrix. @@ -145,16 +155,25 @@ class SPQR { eigen_assert(m_isInitialized && " The QR factorization should be computed first, call compute()"); eigen_assert(b.cols()==1 && "This method is for vectors only"); - + //Compute Q^T * b - typename Dest::PlainObject y; + typename Dest::PlainObject y, y2; y = matrixQ().transpose() * b; - // Solves with the triangular matrix R + + // Solves with the triangular matrix R Index rk = this->rank(); - y.topRows(rk) = this->matrixR().topLeftCorner(rk, rk).template triangularView().solve(y.topRows(rk)); - y.bottomRows(cols()-rk).setZero(); + y2 = y; + y.resize((std::max)(cols(),Index(y.rows())),y.cols()); + y.topRows(rk) = this->matrixR().topLeftCorner(rk, rk).template triangularView().solve(y2.topRows(rk)); + // Apply the column permutation - dest.topRows(cols()) = colsPermutation() * y.topRows(cols()); + // colsPermutation() performs a copy of the permutation, + // so let's apply it manually: + for(Index i = 0; i < rk; ++i) dest.row(m_E[i]) = y.row(i); + for(Index i = rk; i < cols(); ++i) dest.row(m_E[i]).setZero(); + +// y.bottomRows(y.rows()-rk).setZero(); +// dest = colsPermutation() * y.topRows(cols()); m_info = Success; } @@ -197,7 +216,11 @@ class SPQR /// Set the fill-reducing ordering method to be used void setSPQROrdering(int ord) { m_ordering = ord;} /// Set the tolerance tol to treat columns with 2-norm < =tol as zero - void setPivotThreshold(const RealScalar& tol) { m_tolerance = tol; } + void setPivotThreshold(const RealScalar& tol) + { + m_useDefaultThreshold = false; + m_tolerance = tol; + } /** \returns a pointer to the SPQR workspace */ cholmod_common *cholmodCommon() const { return &m_cc; } @@ -230,6 +253,7 @@ class SPQR mutable cholmod_dense *m_HTau; // The Householder coefficients mutable Index m_rank; // The rank of the matrix mutable cholmod_common m_cc; // Workspace and parameters + bool m_useDefaultThreshold; // Use default threshold template friend struct SPQR_QProduct; }; diff --git a/uppsrc/plugin/Eigen/Eigen/src/SVD/CMakeLists.txt b/uppsrc/plugin/Eigen/Eigen/src/SVD/CMakeLists.txt new file mode 100644 index 000000000..55efc44b1 --- /dev/null +++ b/uppsrc/plugin/Eigen/Eigen/src/SVD/CMakeLists.txt @@ -0,0 +1,6 @@ +FILE(GLOB Eigen_SVD_SRCS "*.h") + +INSTALL(FILES + ${Eigen_SVD_SRCS} + DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen/src/SVD COMPONENT Devel + ) diff --git a/uppsrc/plugin/Eigen/Eigen/src/SVD/JacobiSVD.h b/uppsrc/plugin/Eigen/Eigen/src/SVD/JacobiSVD.h index c57f2974c..1b2977419 100644 --- a/uppsrc/plugin/Eigen/Eigen/src/SVD/JacobiSVD.h +++ b/uppsrc/plugin/Eigen/Eigen/src/SVD/JacobiSVD.h @@ -742,6 +742,11 @@ template class JacobiSVD private: void allocate(Index rows, Index cols, unsigned int computationOptions); + + static void check_template_parameters() + { + EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar); + } protected: MatrixUType m_matrixU; @@ -818,6 +823,8 @@ template JacobiSVD& JacobiSVD::compute(const MatrixType& matrix, unsigned int computationOptions) { + check_template_parameters(); + using std::abs; allocate(matrix.rows(), matrix.cols(), computationOptions); diff --git a/uppsrc/plugin/Eigen/Eigen/src/SparseCholesky/CMakeLists.txt b/uppsrc/plugin/Eigen/Eigen/src/SparseCholesky/CMakeLists.txt new file mode 100644 index 000000000..375a59d7a --- /dev/null +++ b/uppsrc/plugin/Eigen/Eigen/src/SparseCholesky/CMakeLists.txt @@ -0,0 +1,6 @@ +FILE(GLOB Eigen_SparseCholesky_SRCS "*.h") + +INSTALL(FILES + ${Eigen_SparseCholesky_SRCS} + DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen/src/SparseCholesky COMPONENT Devel + ) diff --git a/uppsrc/plugin/Eigen/Eigen/src/SparseCore/CMakeLists.txt b/uppsrc/plugin/Eigen/Eigen/src/SparseCore/CMakeLists.txt new file mode 100644 index 000000000..d860452a6 --- /dev/null +++ b/uppsrc/plugin/Eigen/Eigen/src/SparseCore/CMakeLists.txt @@ -0,0 +1,6 @@ +FILE(GLOB Eigen_SparseCore_SRCS "*.h") + +INSTALL(FILES + ${Eigen_SparseCore_SRCS} + DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen/src/SparseCore COMPONENT Devel + ) diff --git a/uppsrc/plugin/Eigen/Eigen/src/SparseCore/SparseBlock.h b/uppsrc/plugin/Eigen/Eigen/src/SparseCore/SparseBlock.h index 0ede034ba..0c90bafbe 100644 --- a/uppsrc/plugin/Eigen/Eigen/src/SparseCore/SparseBlock.h +++ b/uppsrc/plugin/Eigen/Eigen/src/SparseCore/SparseBlock.h @@ -57,6 +57,16 @@ public: inline BlockImpl(const XprType& xpr, int startRow, int startCol, int blockRows, int blockCols) : m_matrix(xpr), m_outerStart(IsRowMajor ? startRow : startCol), m_outerSize(IsRowMajor ? blockRows : blockCols) {} + + inline const Scalar coeff(int row, int col) const + { + return m_matrix.coeff(row + IsRowMajor ? m_outerStart : 0, col +IsRowMajor ? 0 : m_outerStart); + } + + inline const Scalar coeff(int index) const + { + return m_matrix.coeff(IsRowMajor ? m_outerStart : index, IsRowMajor ? index : m_outerStart); + } EIGEN_STRONG_INLINE Index rows() const { return IsRowMajor ? m_outerSize.value() : m_matrix.rows(); } EIGEN_STRONG_INLINE Index cols() const { return IsRowMajor ? m_matrix.cols() : m_outerSize.value(); } @@ -226,6 +236,21 @@ public: else return Map >(m_matrix.innerNonZeroPtr()+m_outerStart, m_outerSize.value()).sum(); } + + inline Scalar& coeffRef(int row, int col) + { + return m_matrix.const_cast_derived().coeffRef(row + (IsRowMajor ? m_outerStart : 0), col + (IsRowMajor ? 0 : m_outerStart)); + } + + inline const Scalar coeff(int row, int col) const + { + return m_matrix.coeff(row + (IsRowMajor ? m_outerStart : 0), col + (IsRowMajor ? 0 : m_outerStart)); + } + + inline const Scalar coeff(int index) const + { + return m_matrix.coeff(IsRowMajor ? m_outerStart : index, IsRowMajor ? index : m_outerStart); + } const Scalar& lastCoeff() const { @@ -313,6 +338,16 @@ public: else return Map >(m_matrix.innerNonZeroPtr()+m_outerStart, m_outerSize.value()).sum(); } + + inline const Scalar coeff(int row, int col) const + { + return m_matrix.coeff(row + (IsRowMajor ? m_outerStart : 0), col + (IsRowMajor ? 0 : m_outerStart)); + } + + inline const Scalar coeff(int index) const + { + return m_matrix.coeff(IsRowMajor ? m_outerStart : index, IsRowMajor ? index : m_outerStart); + } const Scalar& lastCoeff() const { @@ -355,7 +390,8 @@ const typename SparseMatrixBase::ConstInnerVectorReturnType SparseMatri * is col-major (resp. row-major). */ template -Block SparseMatrixBase::innerVectors(Index outerStart, Index outerSize) +typename SparseMatrixBase::InnerVectorsReturnType +SparseMatrixBase::innerVectors(Index outerStart, Index outerSize) { return Block(derived(), IsRowMajor ? outerStart : 0, IsRowMajor ? 0 : outerStart, @@ -367,7 +403,8 @@ Block SparseMatrixBase::innerVectors(Inde * is col-major (resp. row-major). Read-only. */ template -const Block SparseMatrixBase::innerVectors(Index outerStart, Index outerSize) const +const typename SparseMatrixBase::ConstInnerVectorsReturnType +SparseMatrixBase::innerVectors(Index outerStart, Index outerSize) const { return Block(derived(), IsRowMajor ? outerStart : 0, IsRowMajor ? 0 : outerStart, @@ -394,8 +431,8 @@ public: : m_matrix(xpr), m_startRow( (BlockRows==1) && (BlockCols==XprType::ColsAtCompileTime) ? i : 0), m_startCol( (BlockRows==XprType::RowsAtCompileTime) && (BlockCols==1) ? i : 0), - m_blockRows(xpr.rows()), - m_blockCols(xpr.cols()) + m_blockRows(BlockRows==1 ? 1 : xpr.rows()), + m_blockCols(BlockCols==1 ? 1 : xpr.cols()) {} /** Dynamic-size constructor @@ -497,3 +534,4 @@ public: } // end namespace Eigen #endif // EIGEN_SPARSE_BLOCK_H + diff --git a/uppsrc/plugin/Eigen/Eigen/src/SparseCore/SparseDenseProduct.h b/uppsrc/plugin/Eigen/Eigen/src/SparseCore/SparseDenseProduct.h index a9084192e..ccb6ae7b7 100644 --- a/uppsrc/plugin/Eigen/Eigen/src/SparseCore/SparseDenseProduct.h +++ b/uppsrc/plugin/Eigen/Eigen/src/SparseCore/SparseDenseProduct.h @@ -180,7 +180,7 @@ struct sparse_time_dense_product_impl class SparseMatrixBase : public EigenBase const ConstInnerVectorReturnType innerVector(Index outer) const; // set of inner-vectors - Block innerVectors(Index outerStart, Index outerSize); - const Block innerVectors(Index outerStart, Index outerSize) const; + typedef Block InnerVectorsReturnType; + typedef Block ConstInnerVectorsReturnType; + InnerVectorsReturnType innerVectors(Index outerStart, Index outerSize); + const ConstInnerVectorsReturnType innerVectors(Index outerStart, Index outerSize) const; /** \internal use operator= */ template diff --git a/uppsrc/plugin/Eigen/Eigen/src/SparseCore/TriangularSolver.h b/uppsrc/plugin/Eigen/Eigen/src/SparseCore/TriangularSolver.h index cb8ad82b4..ccc12af79 100644 --- a/uppsrc/plugin/Eigen/Eigen/src/SparseCore/TriangularSolver.h +++ b/uppsrc/plugin/Eigen/Eigen/src/SparseCore/TriangularSolver.h @@ -69,7 +69,7 @@ struct sparse_solve_triangular_selector for(int i=lhs.rows()-1 ; i>=0 ; --i) { Scalar tmp = other.coeff(i,col); - Scalar l_ii = 0; + Scalar l_ii(0); typename Lhs::InnerIterator it(lhs, i); while(it && it.index()cols(); ++j) + { + for (typename SCMatrix::InnerIterator it(m_Lstore, j); it; ++it) + { + if(it.index() == j) + { + if(it.value()<0) + det = -det; + else if(it.value()==0) + return 0; + break; + } + } + } + return det * m_detPermR * m_detPermC; + } + + /** \returns The determinant of the matrix. + * + * \sa absDeterminant(), logAbsDeterminant() + */ + Scalar determinant() + { + eigen_assert(m_factorizationIsOk && "The matrix should be factorized first."); + // Initialize with the determinant of the row matrix + Scalar det = Scalar(1.); + // Note that the diagonal blocks of U are stored in supernodes, + // which are available in the L part :) + for (Index j = 0; j < this->cols(); ++j) + { + for (typename SCMatrix::InnerIterator it(m_Lstore, j); it; ++it) + { + if(it.index() == j) + { + det *= it.value(); + break; + } + } + } + return det * Scalar(m_detPermR * m_detPermC); + } protected: // Functions void initperfvalues() { - m_perfv.panel_size = 1; + m_perfv.panel_size = 16; m_perfv.relax = 1; m_perfv.maxsuper = 128; m_perfv.rowblk = 16; @@ -345,8 +390,8 @@ class SparseLU : public internal::SparseLUImpl m_perfv; RealScalar m_diagpivotthresh; // Specifies the threshold used for a diagonal entry to be an acceptable pivot - Index m_nnzL, m_nnzU; // Nonzeros in L and U factors - Index m_detPermR; // Determinant of the coefficient matrix + Index m_nnzL, m_nnzU; // Nonzeros in L and U factors + Index m_detPermR, m_detPermC; // Determinants of the permutation matrices private: // Disable copy constructor SparseLU (const SparseLU& ); @@ -622,7 +667,8 @@ void SparseLU::factorize(const MatrixType& matrix) } // Update the determinant of the row permutation matrix - if (pivrow != jj) m_detPermR *= -1; + // FIXME: the following test is not correct, we should probably take iperm_c into account and pivrow is not directly the row pivot. + if (pivrow != jj) m_detPermR = -m_detPermR; // Prune columns (0:jj-1) using column jj Base::pruneL(jj, m_perm_r.indices(), pivrow, nseg, segrep, repfnz_k, xprune, m_glu); @@ -637,10 +683,13 @@ void SparseLU::factorize(const MatrixType& matrix) jcol += panel_size; // Move to the next panel } // end for -- end elimination + m_detPermR = m_perm_r.determinant(); + m_detPermC = m_perm_c.determinant(); + // Count the number of nonzeros in factors Base::countnz(n, m_nnzL, m_nnzU, m_glu); // Apply permutation to the L subscripts - Base::fixupL(n, m_perm_r.indices(), m_glu); + Base::fixupL(n, m_perm_r.indices(), m_glu); // Create supernode matrix L m_Lstore.setInfos(m, n, m_glu.lusup, m_glu.xlusup, m_glu.lsub, m_glu.xlsub, m_glu.supno, m_glu.xsup); diff --git a/uppsrc/plugin/Eigen/Eigen/src/SparseLU/SparseLU_pivotL.h b/uppsrc/plugin/Eigen/Eigen/src/SparseLU/SparseLU_pivotL.h index ddcd4ec98..457789c78 100644 --- a/uppsrc/plugin/Eigen/Eigen/src/SparseLU/SparseLU_pivotL.h +++ b/uppsrc/plugin/Eigen/Eigen/src/SparseLU/SparseLU_pivotL.h @@ -77,7 +77,8 @@ Index SparseLUImpl::pivotL(const Index jcol, const RealScalar& dia RealScalar rtemp; Index isub, icol, itemp, k; for (isub = nsupc; isub < nsupr; ++isub) { - rtemp = std::abs(lu_col_ptr[isub]); + using std::abs; + rtemp = abs(lu_col_ptr[isub]); if (rtemp > pivmax) { pivmax = rtemp; pivptr = isub; @@ -101,7 +102,8 @@ Index SparseLUImpl::pivotL(const Index jcol, const RealScalar& dia if (diag >= 0 ) { // Diagonal element exists - rtemp = std::abs(lu_col_ptr[diag]); + using std::abs; + rtemp = abs(lu_col_ptr[diag]); if (rtemp != 0.0 && rtemp >= thresh) pivptr = diag; } pivrow = lsub_ptr[pivptr]; diff --git a/uppsrc/plugin/Eigen/Eigen/src/SparseQR/CMakeLists.txt b/uppsrc/plugin/Eigen/Eigen/src/SparseQR/CMakeLists.txt new file mode 100644 index 000000000..f9ddf2bdb --- /dev/null +++ b/uppsrc/plugin/Eigen/Eigen/src/SparseQR/CMakeLists.txt @@ -0,0 +1,6 @@ +FILE(GLOB Eigen_SparseQR_SRCS "*.h") + +INSTALL(FILES + ${Eigen_SparseQR_SRCS} + DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen/src/SparseQR/ COMPONENT Devel + ) diff --git a/uppsrc/plugin/Eigen/Eigen/src/StlSupport/CMakeLists.txt b/uppsrc/plugin/Eigen/Eigen/src/StlSupport/CMakeLists.txt new file mode 100644 index 000000000..0f094f637 --- /dev/null +++ b/uppsrc/plugin/Eigen/Eigen/src/StlSupport/CMakeLists.txt @@ -0,0 +1,6 @@ +FILE(GLOB Eigen_StlSupport_SRCS "*.h") + +INSTALL(FILES + ${Eigen_StlSupport_SRCS} + DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen/src/StlSupport COMPONENT Devel + ) diff --git a/uppsrc/plugin/Eigen/Eigen/src/SuperLUSupport/CMakeLists.txt b/uppsrc/plugin/Eigen/Eigen/src/SuperLUSupport/CMakeLists.txt new file mode 100644 index 000000000..b28ebe583 --- /dev/null +++ b/uppsrc/plugin/Eigen/Eigen/src/SuperLUSupport/CMakeLists.txt @@ -0,0 +1,6 @@ +FILE(GLOB Eigen_SuperLUSupport_SRCS "*.h") + +INSTALL(FILES + ${Eigen_SuperLUSupport_SRCS} + DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen/src/SuperLUSupport COMPONENT Devel + ) diff --git a/uppsrc/plugin/Eigen/Eigen/src/UmfPackSupport/CMakeLists.txt b/uppsrc/plugin/Eigen/Eigen/src/UmfPackSupport/CMakeLists.txt new file mode 100644 index 000000000..a57de0020 --- /dev/null +++ b/uppsrc/plugin/Eigen/Eigen/src/UmfPackSupport/CMakeLists.txt @@ -0,0 +1,6 @@ +FILE(GLOB Eigen_UmfPackSupport_SRCS "*.h") + +INSTALL(FILES + ${Eigen_UmfPackSupport_SRCS} + DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen/src/UmfPackSupport COMPONENT Devel + ) diff --git a/uppsrc/plugin/Eigen/Eigen/src/misc/CMakeLists.txt b/uppsrc/plugin/Eigen/Eigen/src/misc/CMakeLists.txt new file mode 100644 index 000000000..a58ffb745 --- /dev/null +++ b/uppsrc/plugin/Eigen/Eigen/src/misc/CMakeLists.txt @@ -0,0 +1,6 @@ +FILE(GLOB Eigen_misc_SRCS "*.h") + +INSTALL(FILES + ${Eigen_misc_SRCS} + DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen/src/misc COMPONENT Devel + ) diff --git a/uppsrc/plugin/Eigen/Eigen/src/plugins/ArrayCwiseBinaryOps.h b/uppsrc/plugin/Eigen/Eigen/src/plugins/ArrayCwiseBinaryOps.h index 5c8c476ee..1951286f3 100644 --- a/uppsrc/plugin/Eigen/Eigen/src/plugins/ArrayCwiseBinaryOps.h +++ b/uppsrc/plugin/Eigen/Eigen/src/plugins/ArrayCwiseBinaryOps.h @@ -70,6 +70,43 @@ max return (max)(Derived::PlainObject::Constant(rows(), cols(), other)); } + +#define EIGEN_MAKE_CWISE_COMP_OP(OP, COMPARATOR) \ +template \ +EIGEN_STRONG_INLINE const CwiseBinaryOp, const Derived, const OtherDerived> \ +OP(const EIGEN_CURRENT_STORAGE_BASE_CLASS &other) const \ +{ \ + return CwiseBinaryOp, const Derived, const OtherDerived>(derived(), other.derived()); \ +}\ +typedef CwiseBinaryOp, const Derived, const CwiseNullaryOp, PlainObject> > Cmp ## COMPARATOR ## ReturnType; \ +typedef CwiseBinaryOp, const CwiseNullaryOp, PlainObject>, const Derived > RCmp ## COMPARATOR ## ReturnType; \ +EIGEN_STRONG_INLINE const Cmp ## COMPARATOR ## ReturnType \ +OP(const Scalar& s) const { \ + return this->OP(Derived::PlainObject::Constant(rows(), cols(), s)); \ +} \ +friend EIGEN_STRONG_INLINE const RCmp ## COMPARATOR ## ReturnType \ +OP(const Scalar& s, const Derived& d) { \ + return Derived::PlainObject::Constant(d.rows(), d.cols(), s).OP(d); \ +} + +#define EIGEN_MAKE_CWISE_COMP_R_OP(OP, R_OP, RCOMPARATOR) \ +template \ +EIGEN_STRONG_INLINE const CwiseBinaryOp, const OtherDerived, const Derived> \ +OP(const EIGEN_CURRENT_STORAGE_BASE_CLASS &other) const \ +{ \ + return CwiseBinaryOp, const OtherDerived, const Derived>(other.derived(), derived()); \ +} \ +\ +inline const RCmp ## RCOMPARATOR ## ReturnType \ +OP(const Scalar& s) const { \ + return Derived::PlainObject::Constant(rows(), cols(), s).R_OP(*this); \ +} \ +friend inline const Cmp ## RCOMPARATOR ## ReturnType \ +OP(const Scalar& s, const Derived& d) { \ + return d.R_OP(Derived::PlainObject::Constant(d.rows(), d.cols(), s)); \ +} + + /** \returns an expression of the coefficient-wise \< operator of *this and \a other * * Example: \include Cwise_less.cpp @@ -77,7 +114,7 @@ max * * \sa all(), any(), operator>(), operator<=() */ -EIGEN_MAKE_CWISE_BINARY_OP(operator<,std::less) +EIGEN_MAKE_CWISE_COMP_OP(operator<, LT) /** \returns an expression of the coefficient-wise \<= operator of *this and \a other * @@ -86,7 +123,7 @@ EIGEN_MAKE_CWISE_BINARY_OP(operator<,std::less) * * \sa all(), any(), operator>=(), operator<() */ -EIGEN_MAKE_CWISE_BINARY_OP(operator<=,std::less_equal) +EIGEN_MAKE_CWISE_COMP_OP(operator<=, LE) /** \returns an expression of the coefficient-wise \> operator of *this and \a other * @@ -95,7 +132,7 @@ EIGEN_MAKE_CWISE_BINARY_OP(operator<=,std::less_equal) * * \sa all(), any(), operator>=(), operator<() */ -EIGEN_MAKE_CWISE_BINARY_OP(operator>,std::greater) +EIGEN_MAKE_CWISE_COMP_R_OP(operator>, operator<, LT) /** \returns an expression of the coefficient-wise \>= operator of *this and \a other * @@ -104,7 +141,7 @@ EIGEN_MAKE_CWISE_BINARY_OP(operator>,std::greater) * * \sa all(), any(), operator>(), operator<=() */ -EIGEN_MAKE_CWISE_BINARY_OP(operator>=,std::greater_equal) +EIGEN_MAKE_CWISE_COMP_R_OP(operator>=, operator<=, LE) /** \returns an expression of the coefficient-wise == operator of *this and \a other * @@ -118,7 +155,7 @@ EIGEN_MAKE_CWISE_BINARY_OP(operator>=,std::greater_equal) * * \sa all(), any(), isApprox(), isMuchSmallerThan() */ -EIGEN_MAKE_CWISE_BINARY_OP(operator==,std::equal_to) +EIGEN_MAKE_CWISE_COMP_OP(operator==, EQ) /** \returns an expression of the coefficient-wise != operator of *this and \a other * @@ -132,7 +169,10 @@ EIGEN_MAKE_CWISE_BINARY_OP(operator==,std::equal_to) * * \sa all(), any(), isApprox(), isMuchSmallerThan() */ -EIGEN_MAKE_CWISE_BINARY_OP(operator!=,std::not_equal_to) +EIGEN_MAKE_CWISE_COMP_OP(operator!=, NEQ) + +#undef EIGEN_MAKE_CWISE_COMP_OP +#undef EIGEN_MAKE_CWISE_COMP_R_OP // scalar addition @@ -209,3 +249,5 @@ operator||(const EIGEN_CURRENT_STORAGE_BASE_CLASS &other) const THIS_METHOD_IS_ONLY_FOR_EXPRESSIONS_OF_BOOL); return CwiseBinaryOp(derived(),other.derived()); } + + diff --git a/uppsrc/plugin/Eigen/Eigen/src/plugins/ArrayCwiseUnaryOps.h b/uppsrc/plugin/Eigen/Eigen/src/plugins/ArrayCwiseUnaryOps.h index a59636790..1c3ed3fcd 100644 --- a/uppsrc/plugin/Eigen/Eigen/src/plugins/ArrayCwiseUnaryOps.h +++ b/uppsrc/plugin/Eigen/Eigen/src/plugins/ArrayCwiseUnaryOps.h @@ -185,19 +185,3 @@ cube() const { return derived(); } - -#define EIGEN_MAKE_SCALAR_CWISE_UNARY_OP(METHOD_NAME,FUNCTOR) \ - inline const CwiseUnaryOp >, const Derived> \ - METHOD_NAME(const Scalar& s) const { \ - return CwiseUnaryOp >, const Derived> \ - (derived(), std::bind2nd(FUNCTOR(), s)); \ - } - -EIGEN_MAKE_SCALAR_CWISE_UNARY_OP(operator==, std::equal_to) -EIGEN_MAKE_SCALAR_CWISE_UNARY_OP(operator!=, std::not_equal_to) -EIGEN_MAKE_SCALAR_CWISE_UNARY_OP(operator<, std::less) -EIGEN_MAKE_SCALAR_CWISE_UNARY_OP(operator<=, std::less_equal) -EIGEN_MAKE_SCALAR_CWISE_UNARY_OP(operator>, std::greater) -EIGEN_MAKE_SCALAR_CWISE_UNARY_OP(operator>=, std::greater_equal) - - diff --git a/uppsrc/plugin/Eigen/Eigen/src/plugins/CMakeLists.txt b/uppsrc/plugin/Eigen/Eigen/src/plugins/CMakeLists.txt new file mode 100644 index 000000000..1a1d3ffbd --- /dev/null +++ b/uppsrc/plugin/Eigen/Eigen/src/plugins/CMakeLists.txt @@ -0,0 +1,6 @@ +FILE(GLOB Eigen_plugins_SRCS "*.h") + +INSTALL(FILES + ${Eigen_plugins_SRCS} + DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen/src/plugins COMPONENT Devel + ) diff --git a/uppsrc/plugin/Eigen/Eigen/src/plugins/MatrixCwiseBinaryOps.h b/uppsrc/plugin/Eigen/Eigen/src/plugins/MatrixCwiseBinaryOps.h index 7f62149e0..c4a042b70 100644 --- a/uppsrc/plugin/Eigen/Eigen/src/plugins/MatrixCwiseBinaryOps.h +++ b/uppsrc/plugin/Eigen/Eigen/src/plugins/MatrixCwiseBinaryOps.h @@ -124,3 +124,20 @@ cwiseQuotient(const EIGEN_CURRENT_STORAGE_BASE_CLASS &other) const { return CwiseBinaryOp, const Derived, const OtherDerived>(derived(), other.derived()); } + +typedef CwiseBinaryOp, const Derived, const ConstantReturnType> CwiseScalarEqualReturnType; + +/** \returns an expression of the coefficient-wise == operator of \c *this and a scalar \a s + * + * \warning this performs an exact comparison, which is generally a bad idea with floating-point types. + * In order to check for equality between two vectors or matrices with floating-point coefficients, it is + * generally a far better idea to use a fuzzy comparison as provided by isApprox() and + * isMuchSmallerThan(). + * + * \sa cwiseEqual(const MatrixBase &) const + */ +inline const CwiseScalarEqualReturnType +cwiseEqual(const Scalar& s) const +{ + return CwiseScalarEqualReturnType(derived(), Derived::Constant(rows(), cols(), s), internal::scalar_cmp_op()); +} diff --git a/uppsrc/plugin/Eigen/Eigen/src/plugins/MatrixCwiseUnaryOps.h b/uppsrc/plugin/Eigen/Eigen/src/plugins/MatrixCwiseUnaryOps.h index 0cf0640ba..8de10935d 100644 --- a/uppsrc/plugin/Eigen/Eigen/src/plugins/MatrixCwiseUnaryOps.h +++ b/uppsrc/plugin/Eigen/Eigen/src/plugins/MatrixCwiseUnaryOps.h @@ -50,18 +50,3 @@ cwiseSqrt() const { return derived(); } inline const CwiseUnaryOp, const Derived> cwiseInverse() const { return derived(); } -/** \returns an expression of the coefficient-wise == operator of \c *this and a scalar \a s - * - * \warning this performs an exact comparison, which is generally a bad idea with floating-point types. - * In order to check for equality between two vectors or matrices with floating-point coefficients, it is - * generally a far better idea to use a fuzzy comparison as provided by isApprox() and - * isMuchSmallerThan(). - * - * \sa cwiseEqual(const MatrixBase &) const - */ -inline const CwiseUnaryOp >, const Derived> -cwiseEqual(const Scalar& s) const -{ - return CwiseUnaryOp >,const Derived> - (derived(), std::bind1st(std::equal_to(), s)); -} diff --git a/uppsrc/plugin/Eigen/srcdoc.tpp/Eigen$en-us.tpp b/uppsrc/plugin/Eigen/srcdoc.tpp/Eigen$en-us.tpp index 3e8dd04d4..2f595f107 100644 --- a/uppsrc/plugin/Eigen/srcdoc.tpp/Eigen$en-us.tpp +++ b/uppsrc/plugin/Eigen/srcdoc.tpp/Eigen$en-us.tpp @@ -17,7 +17,7 @@ vectors, numerical solvers and related algorithms.]&] [s0; [C2 -|Matrix2d res `= a`*b;-|// Just multiply them using `*]&] [s0;#2 &] [s0;#2 &] -[s0;# [2 Eigen package is a wrapper of Eigen 3.1.2 library. It includes +[s0;# [2 Eigen package is a wrapper of Eigen 3.2.5 library. It includes the library and helper functions to integrate better Eigen with U`+`+. Starting from the 3.1.1 version, it is licensed under the ][^http`:`/`/www`.mozilla`.org`/MPL`/2`.0`/^2 MPL2][2 , which diff --git a/uppsrc/plugin/Eigen/unsupported/CMakeLists.txt b/uppsrc/plugin/Eigen/unsupported/CMakeLists.txt new file mode 100644 index 000000000..4fef40a86 --- /dev/null +++ b/uppsrc/plugin/Eigen/unsupported/CMakeLists.txt @@ -0,0 +1,7 @@ +add_subdirectory(Eigen) +add_subdirectory(doc EXCLUDE_FROM_ALL) +if(EIGEN_LEAVE_TEST_IN_ALL_TARGET) + add_subdirectory(test) # can't do EXCLUDE_FROM_ALL here, breaks CTest +else() + add_subdirectory(test EXCLUDE_FROM_ALL) +endif() diff --git a/uppsrc/plugin/Eigen/unsupported/Eigen/CMakeLists.txt b/uppsrc/plugin/Eigen/unsupported/Eigen/CMakeLists.txt new file mode 100644 index 000000000..e1fbf97e2 --- /dev/null +++ b/uppsrc/plugin/Eigen/unsupported/Eigen/CMakeLists.txt @@ -0,0 +1,11 @@ +set(Eigen_HEADERS AdolcForward AlignedVector3 ArpackSupport AutoDiff BVH FFT IterativeSolvers KroneckerProduct LevenbergMarquardt + MatrixFunctions MoreVectorization MPRealSupport NonLinearOptimization NumericalDiff OpenGLSupport Polynomials + Skyline SparseExtra Splines + ) + +install(FILES + ${Eigen_HEADERS} + DESTINATION ${INCLUDE_INSTALL_DIR}/unsupported/Eigen COMPONENT Devel + ) + +add_subdirectory(src) diff --git a/uppsrc/plugin/Eigen/unsupported/Eigen/src/AutoDiff/CMakeLists.txt b/uppsrc/plugin/Eigen/unsupported/Eigen/src/AutoDiff/CMakeLists.txt new file mode 100644 index 000000000..ad91fd9c4 --- /dev/null +++ b/uppsrc/plugin/Eigen/unsupported/Eigen/src/AutoDiff/CMakeLists.txt @@ -0,0 +1,6 @@ +FILE(GLOB Eigen_AutoDiff_SRCS "*.h") + +INSTALL(FILES + ${Eigen_AutoDiff_SRCS} + DESTINATION ${INCLUDE_INSTALL_DIR}/unsupported/Eigen/src/AutoDiff COMPONENT Devel + ) diff --git a/uppsrc/plugin/Eigen/unsupported/Eigen/src/BVH/CMakeLists.txt b/uppsrc/plugin/Eigen/unsupported/Eigen/src/BVH/CMakeLists.txt new file mode 100644 index 000000000..b377d865c --- /dev/null +++ b/uppsrc/plugin/Eigen/unsupported/Eigen/src/BVH/CMakeLists.txt @@ -0,0 +1,6 @@ +FILE(GLOB Eigen_BVH_SRCS "*.h") + +INSTALL(FILES + ${Eigen_BVH_SRCS} + DESTINATION ${INCLUDE_INSTALL_DIR}/unsupported/Eigen/src/BVH COMPONENT Devel + ) diff --git a/uppsrc/plugin/Eigen/unsupported/Eigen/src/CMakeLists.txt b/uppsrc/plugin/Eigen/unsupported/Eigen/src/CMakeLists.txt new file mode 100644 index 000000000..125c43fdf --- /dev/null +++ b/uppsrc/plugin/Eigen/unsupported/Eigen/src/CMakeLists.txt @@ -0,0 +1,14 @@ +ADD_SUBDIRECTORY(AutoDiff) +ADD_SUBDIRECTORY(BVH) +ADD_SUBDIRECTORY(FFT) +ADD_SUBDIRECTORY(IterativeSolvers) +ADD_SUBDIRECTORY(KroneckerProduct) +ADD_SUBDIRECTORY(LevenbergMarquardt) +ADD_SUBDIRECTORY(MatrixFunctions) +ADD_SUBDIRECTORY(MoreVectorization) +ADD_SUBDIRECTORY(NonLinearOptimization) +ADD_SUBDIRECTORY(NumericalDiff) +ADD_SUBDIRECTORY(Polynomials) +ADD_SUBDIRECTORY(Skyline) +ADD_SUBDIRECTORY(SparseExtra) +ADD_SUBDIRECTORY(Splines) diff --git a/uppsrc/plugin/Eigen/unsupported/Eigen/src/FFT/CMakeLists.txt b/uppsrc/plugin/Eigen/unsupported/Eigen/src/FFT/CMakeLists.txt new file mode 100644 index 000000000..edcffcb18 --- /dev/null +++ b/uppsrc/plugin/Eigen/unsupported/Eigen/src/FFT/CMakeLists.txt @@ -0,0 +1,6 @@ +FILE(GLOB Eigen_FFT_SRCS "*.h") + +INSTALL(FILES + ${Eigen_FFT_SRCS} + DESTINATION ${INCLUDE_INSTALL_DIR}/unsupported/Eigen/src/FFT COMPONENT Devel + ) diff --git a/uppsrc/plugin/Eigen/unsupported/Eigen/src/IterativeSolvers/CMakeLists.txt b/uppsrc/plugin/Eigen/unsupported/Eigen/src/IterativeSolvers/CMakeLists.txt new file mode 100644 index 000000000..7986afc5e --- /dev/null +++ b/uppsrc/plugin/Eigen/unsupported/Eigen/src/IterativeSolvers/CMakeLists.txt @@ -0,0 +1,6 @@ +FILE(GLOB Eigen_IterativeSolvers_SRCS "*.h") + +INSTALL(FILES + ${Eigen_IterativeSolvers_SRCS} + DESTINATION ${INCLUDE_INSTALL_DIR}/unsupported/Eigen/src/IterativeSolvers COMPONENT Devel + ) diff --git a/uppsrc/plugin/Eigen/unsupported/Eigen/src/IterativeSolvers/GMRES.h b/uppsrc/plugin/Eigen/unsupported/Eigen/src/IterativeSolvers/GMRES.h index c8c84069e..7ba13afd2 100644 --- a/uppsrc/plugin/Eigen/unsupported/Eigen/src/IterativeSolvers/GMRES.h +++ b/uppsrc/plugin/Eigen/unsupported/Eigen/src/IterativeSolvers/GMRES.h @@ -246,20 +246,7 @@ struct traits > * \endcode * * By default the iterations start with x=0 as an initial guess of the solution. - * One can control the start using the solveWithGuess() method. Here is a step by - * step execution example starting with a random guess and printing the evolution - * of the estimated error: - * * \code - * x = VectorXd::Random(n); - * solver.setMaxIterations(1); - * int i = 0; - * do { - * x = solver.solveWithGuess(b,x); - * std::cout << i << " : " << solver.error() << std::endl; - * ++i; - * } while (solver.info()!=Success && i<100); - * \endcode - * Note that such a step by step excution is slightly slower. + * One can control the start using the solveWithGuess() method. * * \sa class SimplicialCholesky, DiagonalPreconditioner, IdentityPreconditioner */ diff --git a/uppsrc/plugin/Eigen/unsupported/Eigen/src/IterativeSolvers/MINRES.h b/uppsrc/plugin/Eigen/unsupported/Eigen/src/IterativeSolvers/MINRES.h index 0e56342a8..30f26aa50 100644 --- a/uppsrc/plugin/Eigen/unsupported/Eigen/src/IterativeSolvers/MINRES.h +++ b/uppsrc/plugin/Eigen/unsupported/Eigen/src/IterativeSolvers/MINRES.h @@ -37,22 +37,31 @@ namespace Eigen { typedef typename Dest::Scalar Scalar; typedef Matrix VectorType; + // Check for zero rhs + const RealScalar rhsNorm2(rhs.squaredNorm()); + if(rhsNorm2 == 0) + { + x.setZero(); + iters = 0; + tol_error = 0; + return; + } + // initialize const int maxIters(iters); // initialize maxIters to iters const int N(mat.cols()); // the size of the matrix - const RealScalar rhsNorm2(rhs.squaredNorm()); const RealScalar threshold2(tol_error*tol_error*rhsNorm2); // convergence threshold (compared to residualNorm2) // Initialize preconditioned Lanczos -// VectorType v_old(N); // will be initialized inside loop + VectorType v_old(N); // will be initialized inside loop VectorType v( VectorType::Zero(N) ); //initialize v VectorType v_new(rhs-mat*x); //initialize v_new RealScalar residualNorm2(v_new.squaredNorm()); -// VectorType w(N); // will be initialized inside loop + VectorType w(N); // will be initialized inside loop VectorType w_new(precond.solve(v_new)); // initialize w_new // RealScalar beta; // will be initialized inside loop RealScalar beta_new2(v_new.dot(w_new)); - eigen_assert(beta_new2 >= 0 && "PRECONDITIONER IS NOT POSITIVE DEFINITE"); + eigen_assert(beta_new2 >= 0.0 && "PRECONDITIONER IS NOT POSITIVE DEFINITE"); RealScalar beta_new(sqrt(beta_new2)); const RealScalar beta_one(beta_new); v_new /= beta_new; @@ -62,14 +71,14 @@ namespace Eigen { RealScalar c_old(1.0); RealScalar s(0.0); // the sine of the Givens rotation RealScalar s_old(0.0); // the sine of the Givens rotation -// VectorType p_oold(N); // will be initialized in loop + VectorType p_oold(N); // will be initialized in loop VectorType p_old(VectorType::Zero(N)); // initialize p_old=0 VectorType p(p_old); // initialize p=0 RealScalar eta(1.0); iters = 0; // reset iters - while ( iters < maxIters ){ - + while ( iters < maxIters ) + { // Preconditioned Lanczos /* Note that there are 4 variants on the Lanczos algorithm. These are * described in Paige, C. C. (1972). Computational variants of @@ -81,17 +90,17 @@ namespace Eigen { * A. Greenbaum, Iterative Methods for Solving Linear Systems, SIAM (1987). */ const RealScalar beta(beta_new); -// v_old = v; // update: at first time step, this makes v_old = 0 so value of beta doesn't matter - const VectorType v_old(v); // NOT SURE IF CREATING v_old EVERY ITERATION IS EFFICIENT + v_old = v; // update: at first time step, this makes v_old = 0 so value of beta doesn't matter +// const VectorType v_old(v); // NOT SURE IF CREATING v_old EVERY ITERATION IS EFFICIENT v = v_new; // update -// w = w_new; // update - const VectorType w(w_new); // NOT SURE IF CREATING w EVERY ITERATION IS EFFICIENT + w = w_new; // update +// const VectorType w(w_new); // NOT SURE IF CREATING w EVERY ITERATION IS EFFICIENT v_new.noalias() = mat*w - beta*v_old; // compute v_new const RealScalar alpha = v_new.dot(w); v_new -= alpha*v; // overwrite v_new w_new = precond.solve(v_new); // overwrite w_new beta_new2 = v_new.dot(w_new); // compute beta_new - eigen_assert(beta_new2 >= 0 && "PRECONDITIONER IS NOT POSITIVE DEFINITE"); + eigen_assert(beta_new2 >= 0.0 && "PRECONDITIONER IS NOT POSITIVE DEFINITE"); beta_new = sqrt(beta_new2); // compute beta_new v_new /= beta_new; // overwrite v_new for next iteration w_new /= beta_new; // overwrite w_new for next iteration @@ -107,21 +116,28 @@ namespace Eigen { s=beta_new/r1; // new sine // Update solution -// p_oold = p_old; - const VectorType p_oold(p_old); // NOT SURE IF CREATING p_oold EVERY ITERATION IS EFFICIENT + p_oold = p_old; +// const VectorType p_oold(p_old); // NOT SURE IF CREATING p_oold EVERY ITERATION IS EFFICIENT p_old = p; p.noalias()=(w-r2*p_old-r3*p_oold) /r1; // IS NOALIAS REQUIRED? x += beta_one*c*eta*p; + + /* Update the squared residual. Note that this is the estimated residual. + The real residual |Ax-b|^2 may be slightly larger */ residualNorm2 *= s*s; - if ( residualNorm2 < threshold2){ + if ( residualNorm2 < threshold2) + { break; } eta=-s*eta; // update eta iters++; // increment iteration number (for output purposes) } - tol_error = std::sqrt(residualNorm2 / rhsNorm2); // return error. Note that this is the estimated error. The real error |Ax-b|/|b| may be slightly larger + + /* Compute error. Note that this is the estimated error. The real + error |Ax-b|/|b| may be slightly larger */ + tol_error = std::sqrt(residualNorm2 / rhsNorm2); } } @@ -174,20 +190,7 @@ namespace Eigen { * \endcode * * By default the iterations start with x=0 as an initial guess of the solution. - * One can control the start using the solveWithGuess() method. Here is a step by - * step execution example starting with a random guess and printing the evolution - * of the estimated error: - * * \code - * x = VectorXd::Random(n); - * mr.setMaxIterations(1); - * int i = 0; - * do { - * x = mr.solveWithGuess(b,x); - * std::cout << i << " : " << mr.error() << std::endl; - * ++i; - * } while (mr.info()!=Success && i<100); - * \endcode - * Note that such a step by step excution is slightly slower. + * One can control the start using the solveWithGuess() method. * * \sa class ConjugateGradient, BiCGSTAB, SimplicialCholesky, DiagonalPreconditioner, IdentityPreconditioner */ @@ -250,6 +253,11 @@ namespace Eigen { template void _solveWithGuess(const Rhs& b, Dest& x) const { + typedef typename internal::conditional + >::type MatrixWrapperType; + m_iterations = Base::maxIterations(); m_error = Base::m_tolerance; @@ -259,7 +267,7 @@ namespace Eigen { m_error = Base::m_tolerance; typename Dest::ColXpr xj(x,j); - internal::minres(mp_matrix->template selfadjointView(), b.col(j), xj, + internal::minres(MatrixWrapperType(*mp_matrix), b.col(j), xj, Base::m_preconditioner, m_iterations, m_error); } diff --git a/uppsrc/plugin/Eigen/unsupported/Eigen/src/KroneckerProduct/CMakeLists.txt b/uppsrc/plugin/Eigen/unsupported/Eigen/src/KroneckerProduct/CMakeLists.txt new file mode 100644 index 000000000..4daefebee --- /dev/null +++ b/uppsrc/plugin/Eigen/unsupported/Eigen/src/KroneckerProduct/CMakeLists.txt @@ -0,0 +1,6 @@ +FILE(GLOB Eigen_KroneckerProduct_SRCS "*.h") + +INSTALL(FILES + ${Eigen_KroneckerProduct_SRCS} + DESTINATION ${INCLUDE_INSTALL_DIR}/unsupported/Eigen/src/KroneckerProduct COMPONENT Devel + ) diff --git a/uppsrc/plugin/Eigen/unsupported/Eigen/src/LevenbergMarquardt/CMakeLists.txt b/uppsrc/plugin/Eigen/unsupported/Eigen/src/LevenbergMarquardt/CMakeLists.txt new file mode 100644 index 000000000..d9690854d --- /dev/null +++ b/uppsrc/plugin/Eigen/unsupported/Eigen/src/LevenbergMarquardt/CMakeLists.txt @@ -0,0 +1,6 @@ +FILE(GLOB Eigen_LevenbergMarquardt_SRCS "*.h") + +INSTALL(FILES + ${Eigen_LevenbergMarquardt_SRCS} + DESTINATION ${INCLUDE_INSTALL_DIR}/unsupported/Eigen/src/LevenbergMarquardt COMPONENT Devel + ) diff --git a/uppsrc/plugin/Eigen/unsupported/Eigen/src/MatrixFunctions/CMakeLists.txt b/uppsrc/plugin/Eigen/unsupported/Eigen/src/MatrixFunctions/CMakeLists.txt new file mode 100644 index 000000000..cdde64d2c --- /dev/null +++ b/uppsrc/plugin/Eigen/unsupported/Eigen/src/MatrixFunctions/CMakeLists.txt @@ -0,0 +1,6 @@ +FILE(GLOB Eigen_MatrixFunctions_SRCS "*.h") + +INSTALL(FILES + ${Eigen_MatrixFunctions_SRCS} + DESTINATION ${INCLUDE_INSTALL_DIR}/unsupported/Eigen/src/MatrixFunctions COMPONENT Devel + ) diff --git a/uppsrc/plugin/Eigen/unsupported/Eigen/src/MoreVectorization/CMakeLists.txt b/uppsrc/plugin/Eigen/unsupported/Eigen/src/MoreVectorization/CMakeLists.txt new file mode 100644 index 000000000..1b887cc8e --- /dev/null +++ b/uppsrc/plugin/Eigen/unsupported/Eigen/src/MoreVectorization/CMakeLists.txt @@ -0,0 +1,6 @@ +FILE(GLOB Eigen_MoreVectorization_SRCS "*.h") + +INSTALL(FILES + ${Eigen_MoreVectorization_SRCS} + DESTINATION ${INCLUDE_INSTALL_DIR}/unsupported/Eigen/src/MoreVectorization COMPONENT Devel + ) diff --git a/uppsrc/plugin/Eigen/unsupported/Eigen/src/NonLinearOptimization/CMakeLists.txt b/uppsrc/plugin/Eigen/unsupported/Eigen/src/NonLinearOptimization/CMakeLists.txt new file mode 100644 index 000000000..9322ddadf --- /dev/null +++ b/uppsrc/plugin/Eigen/unsupported/Eigen/src/NonLinearOptimization/CMakeLists.txt @@ -0,0 +1,6 @@ +FILE(GLOB Eigen_NonLinearOptimization_SRCS "*.h") + +INSTALL(FILES + ${Eigen_NonLinearOptimization_SRCS} + DESTINATION ${INCLUDE_INSTALL_DIR}/unsupported/Eigen/src/NonLinearOptimization COMPONENT Devel + ) diff --git a/uppsrc/plugin/Eigen/unsupported/Eigen/src/NumericalDiff/CMakeLists.txt b/uppsrc/plugin/Eigen/unsupported/Eigen/src/NumericalDiff/CMakeLists.txt new file mode 100644 index 000000000..1199aca2f --- /dev/null +++ b/uppsrc/plugin/Eigen/unsupported/Eigen/src/NumericalDiff/CMakeLists.txt @@ -0,0 +1,6 @@ +FILE(GLOB Eigen_NumericalDiff_SRCS "*.h") + +INSTALL(FILES + ${Eigen_NumericalDiff_SRCS} + DESTINATION ${INCLUDE_INSTALL_DIR}/unsupported/Eigen/src/NumericalDiff COMPONENT Devel + ) diff --git a/uppsrc/plugin/Eigen/unsupported/Eigen/src/Polynomials/CMakeLists.txt b/uppsrc/plugin/Eigen/unsupported/Eigen/src/Polynomials/CMakeLists.txt new file mode 100644 index 000000000..51f13f3cb --- /dev/null +++ b/uppsrc/plugin/Eigen/unsupported/Eigen/src/Polynomials/CMakeLists.txt @@ -0,0 +1,6 @@ +FILE(GLOB Eigen_Polynomials_SRCS "*.h") + +INSTALL(FILES + ${Eigen_Polynomials_SRCS} + DESTINATION ${INCLUDE_INSTALL_DIR}/unsupported/Eigen/src/Polynomials COMPONENT Devel + ) diff --git a/uppsrc/plugin/Eigen/unsupported/Eigen/src/SVD/CMakeLists.txt b/uppsrc/plugin/Eigen/unsupported/Eigen/src/SVD/CMakeLists.txt new file mode 100644 index 000000000..b40baf092 --- /dev/null +++ b/uppsrc/plugin/Eigen/unsupported/Eigen/src/SVD/CMakeLists.txt @@ -0,0 +1,6 @@ +FILE(GLOB Eigen_SVD_SRCS "*.h") + +INSTALL(FILES + ${Eigen_SVD_SRCS} + DESTINATION ${INCLUDE_INSTALL_DIR}unsupported/Eigen/src/SVD COMPONENT Devel + ) diff --git a/uppsrc/plugin/Eigen/unsupported/Eigen/src/Skyline/CMakeLists.txt b/uppsrc/plugin/Eigen/unsupported/Eigen/src/Skyline/CMakeLists.txt new file mode 100644 index 000000000..3bf1b0dd4 --- /dev/null +++ b/uppsrc/plugin/Eigen/unsupported/Eigen/src/Skyline/CMakeLists.txt @@ -0,0 +1,6 @@ +FILE(GLOB Eigen_Skyline_SRCS "*.h") + +INSTALL(FILES + ${Eigen_Skyline_SRCS} + DESTINATION ${INCLUDE_INSTALL_DIR}/unsupported/Eigen/src/Skyline COMPONENT Devel + ) diff --git a/uppsrc/plugin/Eigen/unsupported/Eigen/src/SparseExtra/CMakeLists.txt b/uppsrc/plugin/Eigen/unsupported/Eigen/src/SparseExtra/CMakeLists.txt new file mode 100644 index 000000000..7ea32ca5e --- /dev/null +++ b/uppsrc/plugin/Eigen/unsupported/Eigen/src/SparseExtra/CMakeLists.txt @@ -0,0 +1,6 @@ +FILE(GLOB Eigen_SparseExtra_SRCS "*.h") + +INSTALL(FILES + ${Eigen_SparseExtra_SRCS} + DESTINATION ${INCLUDE_INSTALL_DIR}/unsupported/Eigen/src/SparseExtra COMPONENT Devel + ) diff --git a/uppsrc/plugin/Eigen/unsupported/Eigen/src/Splines/CMakeLists.txt b/uppsrc/plugin/Eigen/unsupported/Eigen/src/Splines/CMakeLists.txt new file mode 100644 index 000000000..55c6271e9 --- /dev/null +++ b/uppsrc/plugin/Eigen/unsupported/Eigen/src/Splines/CMakeLists.txt @@ -0,0 +1,6 @@ +FILE(GLOB Eigen_Splines_SRCS "*.h") + +INSTALL(FILES + ${Eigen_Splines_SRCS} + DESTINATION ${INCLUDE_INSTALL_DIR}/unsupported/Eigen/src/Splines COMPONENT Devel + ) diff --git a/uppsrc/plugin/Eigen/unsupported/bench/bench_svd.cpp b/uppsrc/plugin/Eigen/unsupported/bench/bench_svd.cpp new file mode 100644 index 000000000..01d8231ae --- /dev/null +++ b/uppsrc/plugin/Eigen/unsupported/bench/bench_svd.cpp @@ -0,0 +1,123 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2013 Gauthier Brun +// Copyright (C) 2013 Nicolas Carre +// Copyright (C) 2013 Jean Ceccato +// Copyright (C) 2013 Pierre Zoppitelli +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/ + +// Bench to compare the efficiency of SVD algorithms + +#include +#include +#include + + +using namespace Eigen; +using namespace std; + +// number of computations of each algorithm before the print of the time +#ifndef REPEAT +#define REPEAT 10 +#endif + +// number of tests of the same type +#ifndef NUMBER_SAMPLE +#define NUMBER_SAMPLE 2 +#endif + +template +void bench_svd(const MatrixType& a = MatrixType()) +{ + MatrixType m = MatrixType::Random(a.rows(), a.cols()); + BenchTimer timerJacobi; + BenchTimer timerBDC; + timerJacobi.reset(); + timerBDC.reset(); + + cout << " Only compute Singular Values" < bdc_matrix(m); + } + timerBDC.stop(); + + timerJacobi.start(); + for (int i=0; i jacobi_matrix(m); + } + timerJacobi.stop(); + + + cout << "Sample " << k << " : " << REPEAT << " computations : Jacobi : " << fixed << timerJacobi.value() << "s "; + cout << " || " << " BDC : " << timerBDC.value() << "s " <= timerJacobi.value()) + cout << "KO : BDC is " << timerJacobi.value() / timerBDC.value() << " times faster than Jacobi" < bdc_matrix(m, ComputeFullU|ComputeFullV); + } + timerBDC.stop(); + + timerJacobi.start(); + for (int i=0; i jacobi_matrix(m, ComputeFullU|ComputeFullV); + } + timerJacobi.stop(); + + + cout << "Sample " << k << " : " << REPEAT << " computations : Jacobi : " << fixed << timerJacobi.value() << "s "; + cout << " || " << " BDC : " << timerBDC.value() << "s " <= timerJacobi.value()) + cout << "KO : BDC is " << timerJacobi.value() / timerBDC.value() << " times faster than Jacobi" < >(Matrix(6, 6)); + + std::cout<<"On a (Dynamic, Dynamic) (32, 32) Matrix" < >(Matrix(32, 32)); + + //std::cout<<"On a (Dynamic, Dynamic) (128, 128) Matrix" < >(Matrix(128, 128)); + + std::cout<<"On a (Dynamic, Dynamic) (160, 160) Matrix" < >(Matrix(160, 160)); + + std::cout<< "--------------------------------------------------------------------"<< std::endl; + +} diff --git a/uppsrc/plugin/Eigen/unsupported/doc/CMakeLists.txt b/uppsrc/plugin/Eigen/unsupported/doc/CMakeLists.txt new file mode 100644 index 000000000..9e9ab9800 --- /dev/null +++ b/uppsrc/plugin/Eigen/unsupported/doc/CMakeLists.txt @@ -0,0 +1,4 @@ +set_directory_properties(PROPERTIES EXCLUDE_FROM_ALL TRUE) + +add_subdirectory(examples) +add_subdirectory(snippets) diff --git a/uppsrc/plugin/Eigen/unsupported/doc/Overview.dox b/uppsrc/plugin/Eigen/unsupported/doc/Overview.dox new file mode 100644 index 000000000..d048377df --- /dev/null +++ b/uppsrc/plugin/Eigen/unsupported/doc/Overview.dox @@ -0,0 +1,25 @@ +namespace Eigen { + +/** \mainpage Eigen's unsupported modules + +This is the API documentation for Eigen's unsupported modules. + +These modules are contributions from various users. They are provided "as is", without any support. + +Click on the \e Modules tab at the top of this page to get a list of all unsupported modules. + +Don't miss the official Eigen documentation. + +*/ + +/* + +\defgroup Unsupported_modules Unsupported modules + +The unsupported modules are contributions from various users. They are +provided "as is", without any support. Nevertheless, some of them are +subject to be included in Eigen in the future. + +*/ + +} diff --git a/uppsrc/plugin/Eigen/unsupported/doc/eigendoxy_layout.xml.in b/uppsrc/plugin/Eigen/unsupported/doc/eigendoxy_layout.xml.in new file mode 100644 index 000000000..c93621ed3 --- /dev/null +++ b/uppsrc/plugin/Eigen/unsupported/doc/eigendoxy_layout.xml.in @@ -0,0 +1,177 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/uppsrc/plugin/Eigen/unsupported/doc/examples/BVH_Example.cpp b/uppsrc/plugin/Eigen/unsupported/doc/examples/BVH_Example.cpp new file mode 100644 index 000000000..6b6fac075 --- /dev/null +++ b/uppsrc/plugin/Eigen/unsupported/doc/examples/BVH_Example.cpp @@ -0,0 +1,52 @@ +#include +#include +#include + +using namespace Eigen; +typedef AlignedBox Box2d; + +namespace Eigen { + namespace internal { + Box2d bounding_box(const Vector2d &v) { return Box2d(v, v); } //compute the bounding box of a single point + } +} + +struct PointPointMinimizer //how to compute squared distances between points and rectangles +{ + PointPointMinimizer() : calls(0) {} + typedef double Scalar; + + double minimumOnVolumeVolume(const Box2d &r1, const Box2d &r2) { ++calls; return r1.squaredExteriorDistance(r2); } + double minimumOnVolumeObject(const Box2d &r, const Vector2d &v) { ++calls; return r.squaredExteriorDistance(v); } + double minimumOnObjectVolume(const Vector2d &v, const Box2d &r) { ++calls; return r.squaredExteriorDistance(v); } + double minimumOnObjectObject(const Vector2d &v1, const Vector2d &v2) { ++calls; return (v1 - v2).squaredNorm(); } + + int calls; +}; + +int main() +{ + typedef std::vector > StdVectorOfVector2d; + StdVectorOfVector2d redPoints, bluePoints; + for(int i = 0; i < 100; ++i) { //initialize random set of red points and blue points + redPoints.push_back(Vector2d::Random()); + bluePoints.push_back(Vector2d::Random()); + } + + PointPointMinimizer minimizer; + double minDistSq = std::numeric_limits::max(); + + //brute force to find closest red-blue pair + for(int i = 0; i < (int)redPoints.size(); ++i) + for(int j = 0; j < (int)bluePoints.size(); ++j) + minDistSq = std::min(minDistSq, minimizer.minimumOnObjectObject(redPoints[i], bluePoints[j])); + std::cout << "Brute force distance = " << sqrt(minDistSq) << ", calls = " << minimizer.calls << std::endl; + + //using BVH to find closest red-blue pair + minimizer.calls = 0; + KdBVH redTree(redPoints.begin(), redPoints.end()), blueTree(bluePoints.begin(), bluePoints.end()); //construct the trees + minDistSq = BVMinimize(redTree, blueTree, minimizer); //actual BVH minimization call + std::cout << "BVH distance = " << sqrt(minDistSq) << ", calls = " << minimizer.calls << std::endl; + + return 0; +} diff --git a/uppsrc/plugin/Eigen/unsupported/doc/examples/CMakeLists.txt b/uppsrc/plugin/Eigen/unsupported/doc/examples/CMakeLists.txt new file mode 100644 index 000000000..c47646dfc --- /dev/null +++ b/uppsrc/plugin/Eigen/unsupported/doc/examples/CMakeLists.txt @@ -0,0 +1,20 @@ +FILE(GLOB examples_SRCS "*.cpp") + +ADD_CUSTOM_TARGET(unsupported_examples) + +INCLUDE_DIRECTORIES(../../../unsupported ../../../unsupported/test) + +FOREACH(example_src ${examples_SRCS}) + GET_FILENAME_COMPONENT(example ${example_src} NAME_WE) + ADD_EXECUTABLE(example_${example} ${example_src}) + if(EIGEN_STANDARD_LIBRARIES_TO_LINK_TO) + target_link_libraries(example_${example} ${EIGEN_STANDARD_LIBRARIES_TO_LINK_TO}) + endif() + ADD_CUSTOM_COMMAND( + TARGET example_${example} + POST_BUILD + COMMAND example_${example} + ARGS >${CMAKE_CURRENT_BINARY_DIR}/${example}.out + ) + ADD_DEPENDENCIES(unsupported_examples example_${example}) +ENDFOREACH(example_src) diff --git a/uppsrc/plugin/Eigen/unsupported/doc/examples/FFT.cpp b/uppsrc/plugin/Eigen/unsupported/doc/examples/FFT.cpp new file mode 100644 index 000000000..fcbf81276 --- /dev/null +++ b/uppsrc/plugin/Eigen/unsupported/doc/examples/FFT.cpp @@ -0,0 +1,118 @@ +// To use the simple FFT implementation +// g++ -o demofft -I.. -Wall -O3 FFT.cpp + +// To use the FFTW implementation +// g++ -o demofft -I.. -DUSE_FFTW -Wall -O3 FFT.cpp -lfftw3 -lfftw3f -lfftw3l + +#ifdef USE_FFTW +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +using namespace std; +using namespace Eigen; + +template +T mag2(T a) +{ + return a*a; +} +template +T mag2(std::complex a) +{ + return norm(a); +} + +template +T mag2(const std::vector & vec) +{ + T out=0; + for (size_t k=0;k +T mag2(const std::vector > & vec) +{ + T out=0; + for (size_t k=0;k +vector operator-(const vector & a,const vector & b ) +{ + vector c(a); + for (size_t k=0;k +void RandomFill(std::vector & vec) +{ + for (size_t k=0;k +void RandomFill(std::vector > & vec) +{ + for (size_t k=0;k ( T( rand() )/T(RAND_MAX) - .5, T( rand() )/T(RAND_MAX) - .5); +} + +template +void fwd_inv(size_t nfft) +{ + typedef typename NumTraits::Real Scalar; + vector timebuf(nfft); + RandomFill(timebuf); + + vector freqbuf; + static FFT fft; + fft.fwd(freqbuf,timebuf); + + vector timebuf2; + fft.inv(timebuf2,freqbuf); + + long double rmse = mag2(timebuf - timebuf2) / mag2(timebuf); + cout << "roundtrip rmse: " << rmse << endl; +} + +template +void two_demos(int nfft) +{ + cout << " scalar "; + fwd_inv >(nfft); + cout << " complex "; + fwd_inv,std::complex >(nfft); +} + +void demo_all_types(int nfft) +{ + cout << "nfft=" << nfft << endl; + cout << " float" << endl; + two_demos(nfft); + cout << " double" << endl; + two_demos(nfft); + cout << " long double" << endl; + two_demos(nfft); +} + +int main() +{ + demo_all_types( 2*3*4*5*7 ); + demo_all_types( 2*9*16*25 ); + demo_all_types( 1024 ); + return 0; +} diff --git a/uppsrc/plugin/Eigen/unsupported/doc/examples/MatrixExponential.cpp b/uppsrc/plugin/Eigen/unsupported/doc/examples/MatrixExponential.cpp new file mode 100644 index 000000000..ebd3b9675 --- /dev/null +++ b/uppsrc/plugin/Eigen/unsupported/doc/examples/MatrixExponential.cpp @@ -0,0 +1,16 @@ +#include +#include + +using namespace Eigen; + +int main() +{ + const double pi = std::acos(-1.0); + + MatrixXd A(3,3); + A << 0, -pi/4, 0, + pi/4, 0, 0, + 0, 0, 0; + std::cout << "The matrix A is:\n" << A << "\n\n"; + std::cout << "The matrix exponential of A is:\n" << A.exp() << "\n\n"; +} diff --git a/uppsrc/plugin/Eigen/unsupported/doc/examples/MatrixFunction.cpp b/uppsrc/plugin/Eigen/unsupported/doc/examples/MatrixFunction.cpp new file mode 100644 index 000000000..a4172e4ae --- /dev/null +++ b/uppsrc/plugin/Eigen/unsupported/doc/examples/MatrixFunction.cpp @@ -0,0 +1,23 @@ +#include +#include + +using namespace Eigen; + +std::complex expfn(std::complex x, int) +{ + return std::exp(x); +} + +int main() +{ + const double pi = std::acos(-1.0); + + MatrixXd A(3,3); + A << 0, -pi/4, 0, + pi/4, 0, 0, + 0, 0, 0; + + std::cout << "The matrix A is:\n" << A << "\n\n"; + std::cout << "The matrix exponential of A is:\n" + << A.matrixFunction(expfn) << "\n\n"; +} diff --git a/uppsrc/plugin/Eigen/unsupported/doc/examples/MatrixLogarithm.cpp b/uppsrc/plugin/Eigen/unsupported/doc/examples/MatrixLogarithm.cpp new file mode 100644 index 000000000..8c5d97054 --- /dev/null +++ b/uppsrc/plugin/Eigen/unsupported/doc/examples/MatrixLogarithm.cpp @@ -0,0 +1,15 @@ +#include +#include + +using namespace Eigen; + +int main() +{ + using std::sqrt; + MatrixXd A(3,3); + A << 0.5*sqrt(2), -0.5*sqrt(2), 0, + 0.5*sqrt(2), 0.5*sqrt(2), 0, + 0, 0, 1; + std::cout << "The matrix A is:\n" << A << "\n\n"; + std::cout << "The matrix logarithm of A is:\n" << A.log() << "\n"; +} diff --git a/uppsrc/plugin/Eigen/unsupported/doc/examples/MatrixPower.cpp b/uppsrc/plugin/Eigen/unsupported/doc/examples/MatrixPower.cpp new file mode 100644 index 000000000..222452476 --- /dev/null +++ b/uppsrc/plugin/Eigen/unsupported/doc/examples/MatrixPower.cpp @@ -0,0 +1,16 @@ +#include +#include + +using namespace Eigen; + +int main() +{ + const double pi = std::acos(-1.0); + Matrix3d A; + A << cos(1), -sin(1), 0, + sin(1), cos(1), 0, + 0 , 0 , 1; + std::cout << "The matrix A is:\n" << A << "\n\n" + "The matrix power A^(pi/4) is:\n" << A.pow(pi/4) << std::endl; + return 0; +} diff --git a/uppsrc/plugin/Eigen/unsupported/doc/examples/MatrixPower_optimal.cpp b/uppsrc/plugin/Eigen/unsupported/doc/examples/MatrixPower_optimal.cpp new file mode 100644 index 000000000..86470ba0a --- /dev/null +++ b/uppsrc/plugin/Eigen/unsupported/doc/examples/MatrixPower_optimal.cpp @@ -0,0 +1,17 @@ +#include +#include + +using namespace Eigen; + +int main() +{ + Matrix4cd A = Matrix4cd::Random(); + MatrixPower Apow(A); + + std::cout << "The matrix A is:\n" << A << "\n\n" + "A^3.1 is:\n" << Apow(3.1) << "\n\n" + "A^3.3 is:\n" << Apow(3.3) << "\n\n" + "A^3.7 is:\n" << Apow(3.7) << "\n\n" + "A^3.9 is:\n" << Apow(3.9) << std::endl; + return 0; +} diff --git a/uppsrc/plugin/Eigen/unsupported/doc/examples/MatrixSine.cpp b/uppsrc/plugin/Eigen/unsupported/doc/examples/MatrixSine.cpp new file mode 100644 index 000000000..9eea9a081 --- /dev/null +++ b/uppsrc/plugin/Eigen/unsupported/doc/examples/MatrixSine.cpp @@ -0,0 +1,20 @@ +#include +#include + +using namespace Eigen; + +int main() +{ + MatrixXd A = MatrixXd::Random(3,3); + std::cout << "A = \n" << A << "\n\n"; + + MatrixXd sinA = A.sin(); + std::cout << "sin(A) = \n" << sinA << "\n\n"; + + MatrixXd cosA = A.cos(); + std::cout << "cos(A) = \n" << cosA << "\n\n"; + + // The matrix functions satisfy sin^2(A) + cos^2(A) = I, + // like the scalar functions. + std::cout << "sin^2(A) + cos^2(A) = \n" << sinA*sinA + cosA*cosA << "\n\n"; +} diff --git a/uppsrc/plugin/Eigen/unsupported/doc/examples/MatrixSinh.cpp b/uppsrc/plugin/Eigen/unsupported/doc/examples/MatrixSinh.cpp new file mode 100644 index 000000000..f77186724 --- /dev/null +++ b/uppsrc/plugin/Eigen/unsupported/doc/examples/MatrixSinh.cpp @@ -0,0 +1,20 @@ +#include +#include + +using namespace Eigen; + +int main() +{ + MatrixXf A = MatrixXf::Random(3,3); + std::cout << "A = \n" << A << "\n\n"; + + MatrixXf sinhA = A.sinh(); + std::cout << "sinh(A) = \n" << sinhA << "\n\n"; + + MatrixXf coshA = A.cosh(); + std::cout << "cosh(A) = \n" << coshA << "\n\n"; + + // The matrix functions satisfy cosh^2(A) - sinh^2(A) = I, + // like the scalar functions. + std::cout << "cosh^2(A) - sinh^2(A) = \n" << coshA*coshA - sinhA*sinhA << "\n\n"; +} diff --git a/uppsrc/plugin/Eigen/unsupported/doc/examples/MatrixSquareRoot.cpp b/uppsrc/plugin/Eigen/unsupported/doc/examples/MatrixSquareRoot.cpp new file mode 100644 index 000000000..88e7557d7 --- /dev/null +++ b/uppsrc/plugin/Eigen/unsupported/doc/examples/MatrixSquareRoot.cpp @@ -0,0 +1,16 @@ +#include +#include + +using namespace Eigen; + +int main() +{ + const double pi = std::acos(-1.0); + + MatrixXd A(2,2); + A << cos(pi/3), -sin(pi/3), + sin(pi/3), cos(pi/3); + std::cout << "The matrix A is:\n" << A << "\n\n"; + std::cout << "The matrix square root of A is:\n" << A.sqrt() << "\n\n"; + std::cout << "The square of the last matrix is:\n" << A.sqrt() * A.sqrt() << "\n"; +} diff --git a/uppsrc/plugin/Eigen/unsupported/doc/examples/PolynomialSolver1.cpp b/uppsrc/plugin/Eigen/unsupported/doc/examples/PolynomialSolver1.cpp new file mode 100644 index 000000000..cd777a4e2 --- /dev/null +++ b/uppsrc/plugin/Eigen/unsupported/doc/examples/PolynomialSolver1.cpp @@ -0,0 +1,53 @@ +#include +#include +#include + +using namespace Eigen; +using namespace std; + +int main() +{ + typedef Matrix Vector5d; + + Vector5d roots = Vector5d::Random(); + cout << "Roots: " << roots.transpose() << endl; + Eigen::Matrix polynomial; + roots_to_monicPolynomial( roots, polynomial ); + + PolynomialSolver psolve( polynomial ); + cout << "Complex roots: " << psolve.roots().transpose() << endl; + + std::vector realRoots; + psolve.realRoots( realRoots ); + Map mapRR( &realRoots[0] ); + cout << "Real roots: " << mapRR.transpose() << endl; + + cout << endl; + cout << "Illustration of the convergence problem with the QR algorithm: " << endl; + cout << "---------------------------------------------------------------" << endl; + Eigen::Matrix hardCase_polynomial; + hardCase_polynomial << + -0.957, 0.9219, 0.3516, 0.9453, -0.4023, -0.5508, -0.03125; + cout << "Hard case polynomial defined by floats: " << hardCase_polynomial.transpose() << endl; + PolynomialSolver psolvef( hardCase_polynomial ); + cout << "Complex roots: " << psolvef.roots().transpose() << endl; + Eigen::Matrix evals; + for( int i=0; i<6; ++i ){ evals[i] = std::abs( poly_eval( hardCase_polynomial, psolvef.roots()[i] ) ); } + cout << "Norms of the evaluations of the polynomial at the roots: " << evals.transpose() << endl << endl; + + cout << "Using double's almost always solves the problem for small degrees: " << endl; + cout << "-------------------------------------------------------------------" << endl; + PolynomialSolver psolve6d( hardCase_polynomial.cast() ); + cout << "Complex roots: " << psolve6d.roots().transpose() << endl; + for( int i=0; i<6; ++i ) + { + std::complex castedRoot( psolve6d.roots()[i].real(), psolve6d.roots()[i].imag() ); + evals[i] = std::abs( poly_eval( hardCase_polynomial, castedRoot ) ); + } + cout << "Norms of the evaluations of the polynomial at the roots: " << evals.transpose() << endl << endl; + + cout.precision(10); + cout << "The last root in float then in double: " << psolvef.roots()[5] << "\t" << psolve6d.roots()[5] << endl; + std::complex castedRoot( psolve6d.roots()[5].real(), psolve6d.roots()[5].imag() ); + cout << "Norm of the difference: " << std::abs( psolvef.roots()[5] - castedRoot ) << endl; +} diff --git a/uppsrc/plugin/Eigen/unsupported/doc/examples/PolynomialUtils1.cpp b/uppsrc/plugin/Eigen/unsupported/doc/examples/PolynomialUtils1.cpp new file mode 100644 index 000000000..dbfe520b5 --- /dev/null +++ b/uppsrc/plugin/Eigen/unsupported/doc/examples/PolynomialUtils1.cpp @@ -0,0 +1,20 @@ +#include +#include + +using namespace Eigen; +using namespace std; + +int main() +{ + Vector4d roots = Vector4d::Random(); + cout << "Roots: " << roots.transpose() << endl; + Eigen::Matrix polynomial; + roots_to_monicPolynomial( roots, polynomial ); + cout << "Polynomial: "; + for( int i=0; i<4; ++i ){ cout << polynomial[i] << ".x^" << i << "+ "; } + cout << polynomial[4] << ".x^4" << endl; + Vector4d evaluation; + for( int i=0; i<4; ++i ){ + evaluation[i] = poly_eval( polynomial, roots[i] ); } + cout << "Evaluation of the polynomial at the roots: " << evaluation.transpose(); +} diff --git a/uppsrc/plugin/Eigen/unsupported/doc/snippets/CMakeLists.txt b/uppsrc/plugin/Eigen/unsupported/doc/snippets/CMakeLists.txt new file mode 100644 index 000000000..f0c5cc2a8 --- /dev/null +++ b/uppsrc/plugin/Eigen/unsupported/doc/snippets/CMakeLists.txt @@ -0,0 +1,26 @@ +FILE(GLOB snippets_SRCS "*.cpp") + +ADD_CUSTOM_TARGET(unsupported_snippets) + +FOREACH(snippet_src ${snippets_SRCS}) + GET_FILENAME_COMPONENT(snippet ${snippet_src} NAME_WE) + SET(compile_snippet_target compile_${snippet}) + SET(compile_snippet_src ${compile_snippet_target}.cpp) + FILE(READ ${snippet_src} snippet_source_code) + CONFIGURE_FILE(${PROJECT_SOURCE_DIR}/doc/snippets/compile_snippet.cpp.in + ${CMAKE_CURRENT_BINARY_DIR}/${compile_snippet_src}) + ADD_EXECUTABLE(${compile_snippet_target} + ${CMAKE_CURRENT_BINARY_DIR}/${compile_snippet_src}) + if(EIGEN_STANDARD_LIBRARIES_TO_LINK_TO) + target_link_libraries(${compile_snippet_target} ${EIGEN_STANDARD_LIBRARIES_TO_LINK_TO}) + endif() + ADD_CUSTOM_COMMAND( + TARGET ${compile_snippet_target} + POST_BUILD + COMMAND ${compile_snippet_target} + ARGS >${CMAKE_CURRENT_BINARY_DIR}/${snippet}.out + ) + ADD_DEPENDENCIES(unsupported_snippets ${compile_snippet_target}) + set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/${compile_snippet_src} + PROPERTIES OBJECT_DEPENDS ${snippet_src}) +ENDFOREACH(snippet_src) diff --git a/uppsrc/plugin/Eigen/unsupported/test/BVH.cpp b/uppsrc/plugin/Eigen/unsupported/test/BVH.cpp new file mode 100644 index 000000000..ff5b3299d --- /dev/null +++ b/uppsrc/plugin/Eigen/unsupported/test/BVH.cpp @@ -0,0 +1,222 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2009 Ilya Baran +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "main.h" +#include +#include +#include + +namespace Eigen { + +template AlignedBox bounding_box(const Matrix &v) { return AlignedBox(v); } + +} + + +template +struct Ball +{ +EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(double, Dim) + + typedef Matrix VectorType; + + Ball() {} + Ball(const VectorType &c, double r) : center(c), radius(r) {} + + VectorType center; + double radius; +}; +template AlignedBox bounding_box(const Ball &b) +{ return AlignedBox(b.center.array() - b.radius, b.center.array() + b.radius); } + +inline double SQR(double x) { return x * x; } + +template +struct BallPointStuff //this class provides functions to be both an intersector and a minimizer, both for a ball and a point and for two trees +{ + typedef double Scalar; + typedef Matrix VectorType; + typedef Ball BallType; + typedef AlignedBox BoxType; + + BallPointStuff() : calls(0), count(0) {} + BallPointStuff(const VectorType &inP) : p(inP), calls(0), count(0) {} + + + bool intersectVolume(const BoxType &r) { ++calls; return r.contains(p); } + bool intersectObject(const BallType &b) { + ++calls; + if((b.center - p).squaredNorm() < SQR(b.radius)) + ++count; + return false; //continue + } + + bool intersectVolumeVolume(const BoxType &r1, const BoxType &r2) { ++calls; return !(r1.intersection(r2)).isNull(); } + bool intersectVolumeObject(const BoxType &r, const BallType &b) { ++calls; return r.squaredExteriorDistance(b.center) < SQR(b.radius); } + bool intersectObjectVolume(const BallType &b, const BoxType &r) { ++calls; return r.squaredExteriorDistance(b.center) < SQR(b.radius); } + bool intersectObjectObject(const BallType &b1, const BallType &b2){ + ++calls; + if((b1.center - b2.center).norm() < b1.radius + b2.radius) + ++count; + return false; + } + bool intersectVolumeObject(const BoxType &r, const VectorType &v) { ++calls; return r.contains(v); } + bool intersectObjectObject(const BallType &b, const VectorType &v){ + ++calls; + if((b.center - v).squaredNorm() < SQR(b.radius)) + ++count; + return false; + } + + double minimumOnVolume(const BoxType &r) { ++calls; return r.squaredExteriorDistance(p); } + double minimumOnObject(const BallType &b) { ++calls; return (std::max)(0., (b.center - p).squaredNorm() - SQR(b.radius)); } + double minimumOnVolumeVolume(const BoxType &r1, const BoxType &r2) { ++calls; return r1.squaredExteriorDistance(r2); } + double minimumOnVolumeObject(const BoxType &r, const BallType &b) { ++calls; return SQR((std::max)(0., r.exteriorDistance(b.center) - b.radius)); } + double minimumOnObjectVolume(const BallType &b, const BoxType &r) { ++calls; return SQR((std::max)(0., r.exteriorDistance(b.center) - b.radius)); } + double minimumOnObjectObject(const BallType &b1, const BallType &b2){ ++calls; return SQR((std::max)(0., (b1.center - b2.center).norm() - b1.radius - b2.radius)); } + double minimumOnVolumeObject(const BoxType &r, const VectorType &v) { ++calls; return r.squaredExteriorDistance(v); } + double minimumOnObjectObject(const BallType &b, const VectorType &v){ ++calls; return SQR((std::max)(0., (b.center - v).norm() - b.radius)); } + + VectorType p; + int calls; + int count; +}; + + +template +struct TreeTest +{ + typedef Matrix VectorType; + typedef std::vector > VectorTypeList; + typedef Ball BallType; + typedef std::vector > BallTypeList; + typedef AlignedBox BoxType; + + void testIntersect1() + { + BallTypeList b; + for(int i = 0; i < 500; ++i) { + b.push_back(BallType(VectorType::Random(), 0.5 * internal::random(0., 1.))); + } + KdBVH tree(b.begin(), b.end()); + + VectorType pt = VectorType::Random(); + BallPointStuff i1(pt), i2(pt); + + for(int i = 0; i < (int)b.size(); ++i) + i1.intersectObject(b[i]); + + BVIntersect(tree, i2); + + VERIFY(i1.count == i2.count); + } + + void testMinimize1() + { + BallTypeList b; + for(int i = 0; i < 500; ++i) { + b.push_back(BallType(VectorType::Random(), 0.01 * internal::random(0., 1.))); + } + KdBVH tree(b.begin(), b.end()); + + VectorType pt = VectorType::Random(); + BallPointStuff i1(pt), i2(pt); + + double m1 = (std::numeric_limits::max)(), m2 = m1; + + for(int i = 0; i < (int)b.size(); ++i) + m1 = (std::min)(m1, i1.minimumOnObject(b[i])); + + m2 = BVMinimize(tree, i2); + + VERIFY_IS_APPROX(m1, m2); + } + + void testIntersect2() + { + BallTypeList b; + VectorTypeList v; + + for(int i = 0; i < 50; ++i) { + b.push_back(BallType(VectorType::Random(), 0.5 * internal::random(0., 1.))); + for(int j = 0; j < 3; ++j) + v.push_back(VectorType::Random()); + } + + KdBVH tree(b.begin(), b.end()); + KdBVH vTree(v.begin(), v.end()); + + BallPointStuff i1, i2; + + for(int i = 0; i < (int)b.size(); ++i) + for(int j = 0; j < (int)v.size(); ++j) + i1.intersectObjectObject(b[i], v[j]); + + BVIntersect(tree, vTree, i2); + + VERIFY(i1.count == i2.count); + } + + void testMinimize2() + { + BallTypeList b; + VectorTypeList v; + + for(int i = 0; i < 50; ++i) { + b.push_back(BallType(VectorType::Random(), 1e-7 + 1e-6 * internal::random(0., 1.))); + for(int j = 0; j < 3; ++j) + v.push_back(VectorType::Random()); + } + + KdBVH tree(b.begin(), b.end()); + KdBVH vTree(v.begin(), v.end()); + + BallPointStuff i1, i2; + + double m1 = (std::numeric_limits::max)(), m2 = m1; + + for(int i = 0; i < (int)b.size(); ++i) + for(int j = 0; j < (int)v.size(); ++j) + m1 = (std::min)(m1, i1.minimumOnObjectObject(b[i], v[j])); + + m2 = BVMinimize(tree, vTree, i2); + + VERIFY_IS_APPROX(m1, m2); + } +}; + + +void test_BVH() +{ + for(int i = 0; i < g_repeat; i++) { +#ifdef EIGEN_TEST_PART_1 + TreeTest<2> test2; + CALL_SUBTEST(test2.testIntersect1()); + CALL_SUBTEST(test2.testMinimize1()); + CALL_SUBTEST(test2.testIntersect2()); + CALL_SUBTEST(test2.testMinimize2()); +#endif + +#ifdef EIGEN_TEST_PART_2 + TreeTest<3> test3; + CALL_SUBTEST(test3.testIntersect1()); + CALL_SUBTEST(test3.testMinimize1()); + CALL_SUBTEST(test3.testIntersect2()); + CALL_SUBTEST(test3.testMinimize2()); +#endif + +#ifdef EIGEN_TEST_PART_3 + TreeTest<4> test4; + CALL_SUBTEST(test4.testIntersect1()); + CALL_SUBTEST(test4.testMinimize1()); + CALL_SUBTEST(test4.testIntersect2()); + CALL_SUBTEST(test4.testMinimize2()); +#endif + } +} diff --git a/uppsrc/plugin/Eigen/unsupported/test/CMakeLists.txt b/uppsrc/plugin/Eigen/unsupported/test/CMakeLists.txt new file mode 100644 index 000000000..2e4cfdb2e --- /dev/null +++ b/uppsrc/plugin/Eigen/unsupported/test/CMakeLists.txt @@ -0,0 +1,90 @@ + +set_property(GLOBAL PROPERTY EIGEN_CURRENT_SUBPROJECT "Unsupported") +add_custom_target(BuildUnsupported) + +include_directories(../../test ../../unsupported ../../Eigen + ${CMAKE_CURRENT_BINARY_DIR}/../../test) + +find_package(GoogleHash) +if(GOOGLEHASH_FOUND) + add_definitions("-DEIGEN_GOOGLEHASH_SUPPORT") + include_directories(${GOOGLEHASH_INCLUDES}) + ei_add_property(EIGEN_TESTED_BACKENDS "GoogleHash, ") +else(GOOGLEHASH_FOUND) + ei_add_property(EIGEN_MISSING_BACKENDS "GoogleHash, ") +endif(GOOGLEHASH_FOUND) + +find_package(Adolc) +if(ADOLC_FOUND) + include_directories(${ADOLC_INCLUDES}) + ei_add_property(EIGEN_TESTED_BACKENDS "Adolc, ") + ei_add_test(forward_adolc "" ${ADOLC_LIBRARIES}) +else(ADOLC_FOUND) + ei_add_property(EIGEN_MISSING_BACKENDS "Adolc, ") +endif(ADOLC_FOUND) + +# this test seems to never have been successful on x87, so is considered to contain a FP-related bug. +# see thread: "non-linear optimization test summary" +ei_add_test(NonLinearOptimization) + +ei_add_test(NumericalDiff) +ei_add_test(autodiff) +ei_add_test(BVH) +ei_add_test(matrix_exponential) +ei_add_test(matrix_function) +ei_add_test(matrix_power) +ei_add_test(matrix_square_root) +ei_add_test(alignedvector3) +ei_add_test(FFT) + +find_package(MPFR 2.3.0) +find_package(GMP) +if(MPFR_FOUND) + include_directories(${MPFR_INCLUDES} ./mpreal) + ei_add_property(EIGEN_TESTED_BACKENDS "MPFR C++, ") + set(EIGEN_MPFR_TEST_LIBRARIES ${MPFR_LIBRARIES} ${GMP_LIBRARIES}) + ei_add_test(mpreal_support "" "${EIGEN_MPFR_TEST_LIBRARIES}" ) +else() + ei_add_property(EIGEN_MISSING_BACKENDS "MPFR C++, ") +endif() + +ei_add_test(sparse_extra "" "") + +find_package(FFTW) +if(FFTW_FOUND) + ei_add_property(EIGEN_TESTED_BACKENDS "fftw, ") + include_directories( ${FFTW_INCLUDES} ) + if(FFTWL_LIB) + ei_add_test(FFTW "-DEIGEN_FFTW_DEFAULT -DEIGEN_HAS_FFTWL" "${FFTW_LIBRARIES}" ) + else() + ei_add_test(FFTW "-DEIGEN_FFTW_DEFAULT" "${FFTW_LIBRARIES}" ) + endif() +else() + ei_add_property(EIGEN_MISSING_BACKENDS "fftw, ") +endif() + +option(EIGEN_TEST_NO_OPENGL "Disable OpenGL support in unit tests" OFF) +if(NOT EIGEN_TEST_NO_OPENGL) + find_package(OpenGL) + find_package(GLUT) + find_package(GLEW) + if(OPENGL_FOUND AND GLUT_FOUND AND GLEW_FOUND) + include_directories(${OPENGL_INCLUDE_DIR} ${GLUT_INCLUDE_DIR} ${GLEW_INCLUDE_DIRS}) + ei_add_property(EIGEN_TESTED_BACKENDS "OpenGL, ") + set(EIGEN_GL_LIB ${GLUT_LIBRARIES} ${GLEW_LIBRARIES} ${OPENGL_LIBRARIES}) + ei_add_test(openglsupport "" "${EIGEN_GL_LIB}" ) + else() + ei_add_property(EIGEN_MISSING_BACKENDS "OpenGL, ") + endif() +else() + ei_add_property(EIGEN_MISSING_BACKENDS "OpenGL, ") +endif() + +ei_add_test(polynomialsolver) +ei_add_test(polynomialutils) +ei_add_test(kronecker_product) +ei_add_test(splines) +ei_add_test(gmres) +ei_add_test(minres) +ei_add_test(levenberg_marquardt) +ei_add_test(bdcsvd) diff --git a/uppsrc/plugin/Eigen/unsupported/test/FFT.cpp b/uppsrc/plugin/Eigen/unsupported/test/FFT.cpp new file mode 100644 index 000000000..45c87f5a7 --- /dev/null +++ b/uppsrc/plugin/Eigen/unsupported/test/FFT.cpp @@ -0,0 +1,2 @@ +#define test_FFTW test_FFT +#include "FFTW.cpp" diff --git a/uppsrc/plugin/Eigen/unsupported/test/FFTW.cpp b/uppsrc/plugin/Eigen/unsupported/test/FFTW.cpp new file mode 100644 index 000000000..d3718e2d2 --- /dev/null +++ b/uppsrc/plugin/Eigen/unsupported/test/FFTW.cpp @@ -0,0 +1,262 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2009 Mark Borgerding mark a borgerding net +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "main.h" +#include + +template +std::complex RandomCpx() { return std::complex( (T)(rand()/(T)RAND_MAX - .5), (T)(rand()/(T)RAND_MAX - .5) ); } + +using namespace std; +using namespace Eigen; + + +template < typename T> +complex promote(complex x) { return complex(x.real(),x.imag()); } + +complex promote(float x) { return complex( x); } +complex promote(double x) { return complex( x); } +complex promote(long double x) { return complex( x); } + + + template + long double fft_rmse( const VT1 & fftbuf,const VT2 & timebuf) + { + long double totalpower=0; + long double difpower=0; + long double pi = acos((long double)-1 ); + for (size_t k0=0;k0<(size_t)fftbuf.size();++k0) { + complex acc = 0; + long double phinc = -2.*k0* pi / timebuf.size(); + for (size_t k1=0;k1<(size_t)timebuf.size();++k1) { + acc += promote( timebuf[k1] ) * exp( complex(0,k1*phinc) ); + } + totalpower += numext::abs2(acc); + complex x = promote(fftbuf[k0]); + complex dif = acc - x; + difpower += numext::abs2(dif); + //cerr << k0 << "\t" << acc << "\t" << x << "\t" << sqrt(numext::abs2(dif)) << endl; + } + cerr << "rmse:" << sqrt(difpower/totalpower) << endl; + return sqrt(difpower/totalpower); + } + + template + long double dif_rmse( const VT1 buf1,const VT2 buf2) + { + long double totalpower=0; + long double difpower=0; + size_t n = (min)( buf1.size(),buf2.size() ); + for (size_t k=0;k struct VectorType; + +template struct VectorType +{ + typedef vector type; +}; + +template struct VectorType +{ + typedef Matrix type; +}; + +template +void test_scalar_generic(int nfft) +{ + typedef typename FFT::Complex Complex; + typedef typename FFT::Scalar Scalar; + typedef typename VectorType::type ScalarVector; + typedef typename VectorType::type ComplexVector; + + FFT fft; + ScalarVector tbuf(nfft); + ComplexVector freqBuf; + for (int k=0;k>1)+1) ); + VERIFY( fft_rmse(freqBuf,tbuf) < test_precision() );// gross check + + fft.ClearFlag(fft.HalfSpectrum ); + fft.fwd( freqBuf,tbuf); + VERIFY( (size_t)freqBuf.size() == (size_t)nfft); + VERIFY( fft_rmse(freqBuf,tbuf) < test_precision() );// gross check + + if (nfft&1) + return; // odd FFTs get the wrong size inverse FFT + + ScalarVector tbuf2; + fft.inv( tbuf2 , freqBuf); + VERIFY( dif_rmse(tbuf,tbuf2) < test_precision() );// gross check + + + // verify that the Unscaled flag takes effect + ScalarVector tbuf3; + fft.SetFlag(fft.Unscaled); + + fft.inv( tbuf3 , freqBuf); + + for (int k=0;k " << (tbuf3[i] - tbuf[i] ) << endl; + + VERIFY( dif_rmse(tbuf,tbuf3) < test_precision() );// gross check + + // verify that ClearFlag works + fft.ClearFlag(fft.Unscaled); + fft.inv( tbuf2 , freqBuf); + VERIFY( dif_rmse(tbuf,tbuf2) < test_precision() );// gross check +} + +template +void test_scalar(int nfft) +{ + test_scalar_generic(nfft); + //test_scalar_generic(nfft); +} + + +template +void test_complex_generic(int nfft) +{ + typedef typename FFT::Complex Complex; + typedef typename VectorType::type ComplexVector; + + FFT fft; + + ComplexVector inbuf(nfft); + ComplexVector outbuf; + ComplexVector buf3; + for (int k=0;k() );// gross check + fft.inv( buf3 , outbuf); + + VERIFY( dif_rmse(inbuf,buf3) < test_precision() );// gross check + + // verify that the Unscaled flag takes effect + ComplexVector buf4; + fft.SetFlag(fft.Unscaled); + fft.inv( buf4 , outbuf); + for (int k=0;k() );// gross check + + // verify that ClearFlag works + fft.ClearFlag(fft.Unscaled); + fft.inv( buf3 , outbuf); + VERIFY( dif_rmse(inbuf,buf3) < test_precision() );// gross check +} + +template +void test_complex(int nfft) +{ + test_complex_generic(nfft); + test_complex_generic(nfft); +} +/* +template +void test_complex2d() +{ + typedef typename Eigen::FFT::Complex Complex; + FFT fft; + Eigen::Matrix src,src2,dst,dst2; + + src = Eigen::Matrix::Random(); + //src = Eigen::Matrix::Identity(); + + for (int k=0;k tmpOut; + fft.fwd( tmpOut,src.col(k) ); + dst2.col(k) = tmpOut; + } + + for (int k=0;k tmpOut; + fft.fwd( tmpOut, dst2.row(k) ); + dst2.row(k) = tmpOut; + } + + fft.fwd2(dst.data(),src.data(),ncols,nrows); + fft.inv2(src2.data(),dst.data(),ncols,nrows); + VERIFY( (src-src2).norm() < test_precision() ); + VERIFY( (dst-dst2).norm() < test_precision() ); +} +*/ + + +void test_return_by_value(int len) +{ + VectorXf in; + VectorXf in1; + in.setRandom( len ); + VectorXcf out1,out2; + FFT fft; + + fft.SetFlag(fft.HalfSpectrum ); + + fft.fwd(out1,in); + out2 = fft.fwd(in); + VERIFY( (out1-out2).norm() < test_precision() ); + in1 = fft.inv(out1); + VERIFY( (in1-in).norm() < test_precision() ); +} + +void test_FFTW() +{ + CALL_SUBTEST( test_return_by_value(32) ); + //CALL_SUBTEST( ( test_complex2d () ) ); CALL_SUBTEST( ( test_complex2d () ) ); + //CALL_SUBTEST( ( test_complex2d () ) ); + CALL_SUBTEST( test_complex(32) ); CALL_SUBTEST( test_complex(32) ); + CALL_SUBTEST( test_complex(256) ); CALL_SUBTEST( test_complex(256) ); + CALL_SUBTEST( test_complex(3*8) ); CALL_SUBTEST( test_complex(3*8) ); + CALL_SUBTEST( test_complex(5*32) ); CALL_SUBTEST( test_complex(5*32) ); + CALL_SUBTEST( test_complex(2*3*4) ); CALL_SUBTEST( test_complex(2*3*4) ); + CALL_SUBTEST( test_complex(2*3*4*5) ); CALL_SUBTEST( test_complex(2*3*4*5) ); + CALL_SUBTEST( test_complex(2*3*4*5*7) ); CALL_SUBTEST( test_complex(2*3*4*5*7) ); + + CALL_SUBTEST( test_scalar(32) ); CALL_SUBTEST( test_scalar(32) ); + CALL_SUBTEST( test_scalar(45) ); CALL_SUBTEST( test_scalar(45) ); + CALL_SUBTEST( test_scalar(50) ); CALL_SUBTEST( test_scalar(50) ); + CALL_SUBTEST( test_scalar(256) ); CALL_SUBTEST( test_scalar(256) ); + CALL_SUBTEST( test_scalar(2*3*4*5*7) ); CALL_SUBTEST( test_scalar(2*3*4*5*7) ); + + #ifdef EIGEN_HAS_FFTWL + CALL_SUBTEST( test_complex(32) ); + CALL_SUBTEST( test_complex(256) ); + CALL_SUBTEST( test_complex(3*8) ); + CALL_SUBTEST( test_complex(5*32) ); + CALL_SUBTEST( test_complex(2*3*4) ); + CALL_SUBTEST( test_complex(2*3*4*5) ); + CALL_SUBTEST( test_complex(2*3*4*5*7) ); + + CALL_SUBTEST( test_scalar(32) ); + CALL_SUBTEST( test_scalar(45) ); + CALL_SUBTEST( test_scalar(50) ); + CALL_SUBTEST( test_scalar(256) ); + CALL_SUBTEST( test_scalar(2*3*4*5*7) ); + #endif +} diff --git a/uppsrc/plugin/Eigen/unsupported/test/NonLinearOptimization.cpp b/uppsrc/plugin/Eigen/unsupported/test/NonLinearOptimization.cpp new file mode 100644 index 000000000..d7376b0f5 --- /dev/null +++ b/uppsrc/plugin/Eigen/unsupported/test/NonLinearOptimization.cpp @@ -0,0 +1,1870 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2009 Thomas Capricelli + +#include + +#include "main.h" +#include + +// This disables some useless Warnings on MSVC. +// It is intended to be done for this test only. +#include + +using std::sqrt; + +int fcn_chkder(const VectorXd &x, VectorXd &fvec, MatrixXd &fjac, int iflag) +{ + /* subroutine fcn for chkder example. */ + + int i; + assert(15 == fvec.size()); + assert(3 == x.size()); + double tmp1, tmp2, tmp3, tmp4; + static const double y[15]={1.4e-1, 1.8e-1, 2.2e-1, 2.5e-1, 2.9e-1, 3.2e-1, 3.5e-1, + 3.9e-1, 3.7e-1, 5.8e-1, 7.3e-1, 9.6e-1, 1.34, 2.1, 4.39}; + + + if (iflag == 0) + return 0; + + if (iflag != 2) + for (i=0; i<15; i++) { + tmp1 = i+1; + tmp2 = 16-i-1; + tmp3 = tmp1; + if (i >= 8) tmp3 = tmp2; + fvec[i] = y[i] - (x[0] + tmp1/(x[1]*tmp2 + x[2]*tmp3)); + } + else { + for (i = 0; i < 15; i++) { + tmp1 = i+1; + tmp2 = 16-i-1; + + /* error introduced into next statement for illustration. */ + /* corrected statement should read tmp3 = tmp1 . */ + + tmp3 = tmp2; + if (i >= 8) tmp3 = tmp2; + tmp4 = (x[1]*tmp2 + x[2]*tmp3); tmp4=tmp4*tmp4; + fjac(i,0) = -1.; + fjac(i,1) = tmp1*tmp2/tmp4; + fjac(i,2) = tmp1*tmp3/tmp4; + } + } + return 0; +} + + +void testChkder() +{ + const int m=15, n=3; + VectorXd x(n), fvec(m), xp, fvecp(m), err; + MatrixXd fjac(m,n); + VectorXi ipvt; + + /* the following values should be suitable for */ + /* checking the jacobian matrix. */ + x << 9.2e-1, 1.3e-1, 5.4e-1; + + internal::chkder(x, fvec, fjac, xp, fvecp, 1, err); + fcn_chkder(x, fvec, fjac, 1); + fcn_chkder(x, fvec, fjac, 2); + fcn_chkder(xp, fvecp, fjac, 1); + internal::chkder(x, fvec, fjac, xp, fvecp, 2, err); + + fvecp -= fvec; + + // check those + VectorXd fvec_ref(m), fvecp_ref(m), err_ref(m); + fvec_ref << + -1.181606, -1.429655, -1.606344, + -1.745269, -1.840654, -1.921586, + -1.984141, -2.022537, -2.468977, + -2.827562, -3.473582, -4.437612, + -6.047662, -9.267761, -18.91806; + fvecp_ref << + -7.724666e-09, -3.432406e-09, -2.034843e-10, + 2.313685e-09, 4.331078e-09, 5.984096e-09, + 7.363281e-09, 8.53147e-09, 1.488591e-08, + 2.33585e-08, 3.522012e-08, 5.301255e-08, + 8.26666e-08, 1.419747e-07, 3.19899e-07; + err_ref << + 0.1141397, 0.09943516, 0.09674474, + 0.09980447, 0.1073116, 0.1220445, + 0.1526814, 1, 1, + 1, 1, 1, + 1, 1, 1; + + VERIFY_IS_APPROX(fvec, fvec_ref); + VERIFY_IS_APPROX(fvecp, fvecp_ref); + VERIFY_IS_APPROX(err, err_ref); +} + +// Generic functor +template +struct Functor +{ + typedef _Scalar Scalar; + enum { + InputsAtCompileTime = NX, + ValuesAtCompileTime = NY + }; + typedef Matrix InputType; + typedef Matrix ValueType; + typedef Matrix JacobianType; + + const int m_inputs, m_values; + + Functor() : m_inputs(InputsAtCompileTime), m_values(ValuesAtCompileTime) {} + Functor(int inputs, int values) : m_inputs(inputs), m_values(values) {} + + int inputs() const { return m_inputs; } + int values() const { return m_values; } + + // you should define that in the subclass : +// void operator() (const InputType& x, ValueType* v, JacobianType* _j=0) const; +}; + +struct lmder_functor : Functor +{ + lmder_functor(void): Functor(3,15) {} + int operator()(const VectorXd &x, VectorXd &fvec) const + { + double tmp1, tmp2, tmp3; + static const double y[15] = {1.4e-1, 1.8e-1, 2.2e-1, 2.5e-1, 2.9e-1, 3.2e-1, 3.5e-1, + 3.9e-1, 3.7e-1, 5.8e-1, 7.3e-1, 9.6e-1, 1.34, 2.1, 4.39}; + + for (int i = 0; i < values(); i++) + { + tmp1 = i+1; + tmp2 = 16 - i - 1; + tmp3 = (i>=8)? tmp2 : tmp1; + fvec[i] = y[i] - (x[0] + tmp1/(x[1]*tmp2 + x[2]*tmp3)); + } + return 0; + } + + int df(const VectorXd &x, MatrixXd &fjac) const + { + double tmp1, tmp2, tmp3, tmp4; + for (int i = 0; i < values(); i++) + { + tmp1 = i+1; + tmp2 = 16 - i - 1; + tmp3 = (i>=8)? tmp2 : tmp1; + tmp4 = (x[1]*tmp2 + x[2]*tmp3); tmp4 = tmp4*tmp4; + fjac(i,0) = -1; + fjac(i,1) = tmp1*tmp2/tmp4; + fjac(i,2) = tmp1*tmp3/tmp4; + } + return 0; + } +}; + +void testLmder1() +{ + int n=3, info; + + VectorXd x; + + /* the following starting values provide a rough fit. */ + x.setConstant(n, 1.); + + // do the computation + lmder_functor functor; + LevenbergMarquardt lm(functor); + info = lm.lmder1(x); + + // check return value + VERIFY_IS_EQUAL(info, 1); + VERIFY_IS_EQUAL(lm.nfev, 6); + VERIFY_IS_EQUAL(lm.njev, 5); + + // check norm + VERIFY_IS_APPROX(lm.fvec.blueNorm(), 0.09063596); + + // check x + VectorXd x_ref(n); + x_ref << 0.08241058, 1.133037, 2.343695; + VERIFY_IS_APPROX(x, x_ref); +} + +void testLmder() +{ + const int m=15, n=3; + int info; + double fnorm, covfac; + VectorXd x; + + /* the following starting values provide a rough fit. */ + x.setConstant(n, 1.); + + // do the computation + lmder_functor functor; + LevenbergMarquardt lm(functor); + info = lm.minimize(x); + + // check return values + VERIFY_IS_EQUAL(info, 1); + VERIFY_IS_EQUAL(lm.nfev, 6); + VERIFY_IS_EQUAL(lm.njev, 5); + + // check norm + fnorm = lm.fvec.blueNorm(); + VERIFY_IS_APPROX(fnorm, 0.09063596); + + // check x + VectorXd x_ref(n); + x_ref << 0.08241058, 1.133037, 2.343695; + VERIFY_IS_APPROX(x, x_ref); + + // check covariance + covfac = fnorm*fnorm/(m-n); + internal::covar(lm.fjac, lm.permutation.indices()); // TODO : move this as a function of lm + + MatrixXd cov_ref(n,n); + cov_ref << + 0.0001531202, 0.002869941, -0.002656662, + 0.002869941, 0.09480935, -0.09098995, + -0.002656662, -0.09098995, 0.08778727; + +// std::cout << fjac*covfac << std::endl; + + MatrixXd cov; + cov = covfac*lm.fjac.topLeftCorner(); + VERIFY_IS_APPROX( cov, cov_ref); + // TODO: why isn't this allowed ? : + // VERIFY_IS_APPROX( covfac*fjac.topLeftCorner() , cov_ref); +} + +struct hybrj_functor : Functor +{ + hybrj_functor(void) : Functor(9,9) {} + + int operator()(const VectorXd &x, VectorXd &fvec) + { + double temp, temp1, temp2; + const int n = x.size(); + assert(fvec.size()==n); + for (int k = 0; k < n; k++) + { + temp = (3. - 2.*x[k])*x[k]; + temp1 = 0.; + if (k) temp1 = x[k-1]; + temp2 = 0.; + if (k != n-1) temp2 = x[k+1]; + fvec[k] = temp - temp1 - 2.*temp2 + 1.; + } + return 0; + } + int df(const VectorXd &x, MatrixXd &fjac) + { + const int n = x.size(); + assert(fjac.rows()==n); + assert(fjac.cols()==n); + for (int k = 0; k < n; k++) + { + for (int j = 0; j < n; j++) + fjac(k,j) = 0.; + fjac(k,k) = 3.- 4.*x[k]; + if (k) fjac(k,k-1) = -1.; + if (k != n-1) fjac(k,k+1) = -2.; + } + return 0; + } +}; + + +void testHybrj1() +{ + const int n=9; + int info; + VectorXd x(n); + + /* the following starting values provide a rough fit. */ + x.setConstant(n, -1.); + + // do the computation + hybrj_functor functor; + HybridNonLinearSolver solver(functor); + info = solver.hybrj1(x); + + // check return value + VERIFY_IS_EQUAL(info, 1); + VERIFY_IS_EQUAL(solver.nfev, 11); + VERIFY_IS_EQUAL(solver.njev, 1); + + // check norm + VERIFY_IS_APPROX(solver.fvec.blueNorm(), 1.192636e-08); + + +// check x + VectorXd x_ref(n); + x_ref << + -0.5706545, -0.6816283, -0.7017325, + -0.7042129, -0.701369, -0.6918656, + -0.665792, -0.5960342, -0.4164121; + VERIFY_IS_APPROX(x, x_ref); +} + +void testHybrj() +{ + const int n=9; + int info; + VectorXd x(n); + + /* the following starting values provide a rough fit. */ + x.setConstant(n, -1.); + + + // do the computation + hybrj_functor functor; + HybridNonLinearSolver solver(functor); + solver.diag.setConstant(n, 1.); + solver.useExternalScaling = true; + info = solver.solve(x); + + // check return value + VERIFY_IS_EQUAL(info, 1); + VERIFY_IS_EQUAL(solver.nfev, 11); + VERIFY_IS_EQUAL(solver.njev, 1); + + // check norm + VERIFY_IS_APPROX(solver.fvec.blueNorm(), 1.192636e-08); + + +// check x + VectorXd x_ref(n); + x_ref << + -0.5706545, -0.6816283, -0.7017325, + -0.7042129, -0.701369, -0.6918656, + -0.665792, -0.5960342, -0.4164121; + VERIFY_IS_APPROX(x, x_ref); + +} + +struct hybrd_functor : Functor +{ + hybrd_functor(void) : Functor(9,9) {} + int operator()(const VectorXd &x, VectorXd &fvec) const + { + double temp, temp1, temp2; + const int n = x.size(); + + assert(fvec.size()==n); + for (int k=0; k < n; k++) + { + temp = (3. - 2.*x[k])*x[k]; + temp1 = 0.; + if (k) temp1 = x[k-1]; + temp2 = 0.; + if (k != n-1) temp2 = x[k+1]; + fvec[k] = temp - temp1 - 2.*temp2 + 1.; + } + return 0; + } +}; + +void testHybrd1() +{ + int n=9, info; + VectorXd x(n); + + /* the following starting values provide a rough solution. */ + x.setConstant(n, -1.); + + // do the computation + hybrd_functor functor; + HybridNonLinearSolver solver(functor); + info = solver.hybrd1(x); + + // check return value + VERIFY_IS_EQUAL(info, 1); + VERIFY_IS_EQUAL(solver.nfev, 20); + + // check norm + VERIFY_IS_APPROX(solver.fvec.blueNorm(), 1.192636e-08); + + // check x + VectorXd x_ref(n); + x_ref << -0.5706545, -0.6816283, -0.7017325, -0.7042129, -0.701369, -0.6918656, -0.665792, -0.5960342, -0.4164121; + VERIFY_IS_APPROX(x, x_ref); +} + +void testHybrd() +{ + const int n=9; + int info; + VectorXd x; + + /* the following starting values provide a rough fit. */ + x.setConstant(n, -1.); + + // do the computation + hybrd_functor functor; + HybridNonLinearSolver solver(functor); + solver.parameters.nb_of_subdiagonals = 1; + solver.parameters.nb_of_superdiagonals = 1; + solver.diag.setConstant(n, 1.); + solver.useExternalScaling = true; + info = solver.solveNumericalDiff(x); + + // check return value + VERIFY_IS_EQUAL(info, 1); + VERIFY_IS_EQUAL(solver.nfev, 14); + + // check norm + VERIFY_IS_APPROX(solver.fvec.blueNorm(), 1.192636e-08); + + // check x + VectorXd x_ref(n); + x_ref << + -0.5706545, -0.6816283, -0.7017325, + -0.7042129, -0.701369, -0.6918656, + -0.665792, -0.5960342, -0.4164121; + VERIFY_IS_APPROX(x, x_ref); +} + +struct lmstr_functor : Functor +{ + lmstr_functor(void) : Functor(3,15) {} + int operator()(const VectorXd &x, VectorXd &fvec) + { + /* subroutine fcn for lmstr1 example. */ + double tmp1, tmp2, tmp3; + static const double y[15]={1.4e-1, 1.8e-1, 2.2e-1, 2.5e-1, 2.9e-1, 3.2e-1, 3.5e-1, + 3.9e-1, 3.7e-1, 5.8e-1, 7.3e-1, 9.6e-1, 1.34, 2.1, 4.39}; + + assert(15==fvec.size()); + assert(3==x.size()); + + for (int i=0; i<15; i++) + { + tmp1 = i+1; + tmp2 = 16 - i - 1; + tmp3 = (i>=8)? tmp2 : tmp1; + fvec[i] = y[i] - (x[0] + tmp1/(x[1]*tmp2 + x[2]*tmp3)); + } + return 0; + } + int df(const VectorXd &x, VectorXd &jac_row, VectorXd::Index rownb) + { + assert(x.size()==3); + assert(jac_row.size()==x.size()); + double tmp1, tmp2, tmp3, tmp4; + + int i = rownb-2; + tmp1 = i+1; + tmp2 = 16 - i - 1; + tmp3 = (i>=8)? tmp2 : tmp1; + tmp4 = (x[1]*tmp2 + x[2]*tmp3); tmp4 = tmp4*tmp4; + jac_row[0] = -1; + jac_row[1] = tmp1*tmp2/tmp4; + jac_row[2] = tmp1*tmp3/tmp4; + return 0; + } +}; + +void testLmstr1() +{ + const int n=3; + int info; + + VectorXd x(n); + + /* the following starting values provide a rough fit. */ + x.setConstant(n, 1.); + + // do the computation + lmstr_functor functor; + LevenbergMarquardt lm(functor); + info = lm.lmstr1(x); + + // check return value + VERIFY_IS_EQUAL(info, 1); + VERIFY_IS_EQUAL(lm.nfev, 6); + VERIFY_IS_EQUAL(lm.njev, 5); + + // check norm + VERIFY_IS_APPROX(lm.fvec.blueNorm(), 0.09063596); + + // check x + VectorXd x_ref(n); + x_ref << 0.08241058, 1.133037, 2.343695 ; + VERIFY_IS_APPROX(x, x_ref); +} + +void testLmstr() +{ + const int n=3; + int info; + double fnorm; + VectorXd x(n); + + /* the following starting values provide a rough fit. */ + x.setConstant(n, 1.); + + // do the computation + lmstr_functor functor; + LevenbergMarquardt lm(functor); + info = lm.minimizeOptimumStorage(x); + + // check return values + VERIFY_IS_EQUAL(info, 1); + VERIFY_IS_EQUAL(lm.nfev, 6); + VERIFY_IS_EQUAL(lm.njev, 5); + + // check norm + fnorm = lm.fvec.blueNorm(); + VERIFY_IS_APPROX(fnorm, 0.09063596); + + // check x + VectorXd x_ref(n); + x_ref << 0.08241058, 1.133037, 2.343695; + VERIFY_IS_APPROX(x, x_ref); + +} + +struct lmdif_functor : Functor +{ + lmdif_functor(void) : Functor(3,15) {} + int operator()(const VectorXd &x, VectorXd &fvec) const + { + int i; + double tmp1,tmp2,tmp3; + static const double y[15]={1.4e-1,1.8e-1,2.2e-1,2.5e-1,2.9e-1,3.2e-1,3.5e-1,3.9e-1, + 3.7e-1,5.8e-1,7.3e-1,9.6e-1,1.34e0,2.1e0,4.39e0}; + + assert(x.size()==3); + assert(fvec.size()==15); + for (i=0; i<15; i++) + { + tmp1 = i+1; + tmp2 = 15 - i; + tmp3 = tmp1; + + if (i >= 8) tmp3 = tmp2; + fvec[i] = y[i] - (x[0] + tmp1/(x[1]*tmp2 + x[2]*tmp3)); + } + return 0; + } +}; + +void testLmdif1() +{ + const int n=3; + int info; + + VectorXd x(n), fvec(15); + + /* the following starting values provide a rough fit. */ + x.setConstant(n, 1.); + + // do the computation + lmdif_functor functor; + DenseIndex nfev; + info = LevenbergMarquardt::lmdif1(functor, x, &nfev); + + // check return value + VERIFY_IS_EQUAL(info, 1); + VERIFY_IS_EQUAL(nfev, 26); + + // check norm + functor(x, fvec); + VERIFY_IS_APPROX(fvec.blueNorm(), 0.09063596); + + // check x + VectorXd x_ref(n); + x_ref << 0.0824106, 1.1330366, 2.3436947; + VERIFY_IS_APPROX(x, x_ref); + +} + +void testLmdif() +{ + const int m=15, n=3; + int info; + double fnorm, covfac; + VectorXd x(n); + + /* the following starting values provide a rough fit. */ + x.setConstant(n, 1.); + + // do the computation + lmdif_functor functor; + NumericalDiff numDiff(functor); + LevenbergMarquardt > lm(numDiff); + info = lm.minimize(x); + + // check return values + VERIFY_IS_EQUAL(info, 1); + VERIFY_IS_EQUAL(lm.nfev, 26); + + // check norm + fnorm = lm.fvec.blueNorm(); + VERIFY_IS_APPROX(fnorm, 0.09063596); + + // check x + VectorXd x_ref(n); + x_ref << 0.08241058, 1.133037, 2.343695; + VERIFY_IS_APPROX(x, x_ref); + + // check covariance + covfac = fnorm*fnorm/(m-n); + internal::covar(lm.fjac, lm.permutation.indices()); // TODO : move this as a function of lm + + MatrixXd cov_ref(n,n); + cov_ref << + 0.0001531202, 0.002869942, -0.002656662, + 0.002869942, 0.09480937, -0.09098997, + -0.002656662, -0.09098997, 0.08778729; + +// std::cout << fjac*covfac << std::endl; + + MatrixXd cov; + cov = covfac*lm.fjac.topLeftCorner(); + VERIFY_IS_APPROX( cov, cov_ref); + // TODO: why isn't this allowed ? : + // VERIFY_IS_APPROX( covfac*fjac.topLeftCorner() , cov_ref); +} + +struct chwirut2_functor : Functor +{ + chwirut2_functor(void) : Functor(3,54) {} + static const double m_x[54]; + static const double m_y[54]; + int operator()(const VectorXd &b, VectorXd &fvec) + { + int i; + + assert(b.size()==3); + assert(fvec.size()==54); + for(i=0; i<54; i++) { + double x = m_x[i]; + fvec[i] = exp(-b[0]*x)/(b[1]+b[2]*x) - m_y[i]; + } + return 0; + } + int df(const VectorXd &b, MatrixXd &fjac) + { + assert(b.size()==3); + assert(fjac.rows()==54); + assert(fjac.cols()==3); + for(int i=0; i<54; i++) { + double x = m_x[i]; + double factor = 1./(b[1]+b[2]*x); + double e = exp(-b[0]*x); + fjac(i,0) = -x*e*factor; + fjac(i,1) = -e*factor*factor; + fjac(i,2) = -x*e*factor*factor; + } + return 0; + } +}; +const double chwirut2_functor::m_x[54] = { 0.500E0, 1.000E0, 1.750E0, 3.750E0, 5.750E0, 0.875E0, 2.250E0, 3.250E0, 5.250E0, 0.750E0, 1.750E0, 2.750E0, 4.750E0, 0.625E0, 1.250E0, 2.250E0, 4.250E0, .500E0, 3.000E0, .750E0, 3.000E0, 1.500E0, 6.000E0, 3.000E0, 6.000E0, 1.500E0, 3.000E0, .500E0, 2.000E0, 4.000E0, .750E0, 2.000E0, 5.000E0, .750E0, 2.250E0, 3.750E0, 5.750E0, 3.000E0, .750E0, 2.500E0, 4.000E0, .750E0, 2.500E0, 4.000E0, .750E0, 2.500E0, 4.000E0, .500E0, 6.000E0, 3.000E0, .500E0, 2.750E0, .500E0, 1.750E0}; +const double chwirut2_functor::m_y[54] = { 92.9000E0 ,57.1000E0 ,31.0500E0 ,11.5875E0 ,8.0250E0 ,63.6000E0 ,21.4000E0 ,14.2500E0 ,8.4750E0 ,63.8000E0 ,26.8000E0 ,16.4625E0 ,7.1250E0 ,67.3000E0 ,41.0000E0 ,21.1500E0 ,8.1750E0 ,81.5000E0 ,13.1200E0 ,59.9000E0 ,14.6200E0 ,32.9000E0 ,5.4400E0 ,12.5600E0 ,5.4400E0 ,32.0000E0 ,13.9500E0 ,75.8000E0 ,20.0000E0 ,10.4200E0 ,59.5000E0 ,21.6700E0 ,8.5500E0 ,62.0000E0 ,20.2000E0 ,7.7600E0 ,3.7500E0 ,11.8100E0 ,54.7000E0 ,23.7000E0 ,11.5500E0 ,61.3000E0 ,17.7000E0 ,8.7400E0 ,59.2000E0 ,16.3000E0 ,8.6200E0 ,81.0000E0 ,4.8700E0 ,14.6200E0 ,81.7000E0 ,17.1700E0 ,81.3000E0 ,28.9000E0 }; + +// http://www.itl.nist.gov/div898/strd/nls/data/chwirut2.shtml +void testNistChwirut2(void) +{ + const int n=3; + int info; + + VectorXd x(n); + + /* + * First try + */ + x<< 0.1, 0.01, 0.02; + // do the computation + chwirut2_functor functor; + LevenbergMarquardt lm(functor); + info = lm.minimize(x); + + // check return value + VERIFY_IS_EQUAL(info, 1); + VERIFY_IS_EQUAL(lm.nfev, 10); + VERIFY_IS_EQUAL(lm.njev, 8); + // check norm^2 + VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 5.1304802941E+02); + // check x + VERIFY_IS_APPROX(x[0], 1.6657666537E-01); + VERIFY_IS_APPROX(x[1], 5.1653291286E-03); + VERIFY_IS_APPROX(x[2], 1.2150007096E-02); + + /* + * Second try + */ + x<< 0.15, 0.008, 0.010; + // do the computation + lm.resetParameters(); + lm.parameters.ftol = 1.E6*NumTraits::epsilon(); + lm.parameters.xtol = 1.E6*NumTraits::epsilon(); + info = lm.minimize(x); + + // check return value + VERIFY_IS_EQUAL(info, 1); + VERIFY_IS_EQUAL(lm.nfev, 7); + VERIFY_IS_EQUAL(lm.njev, 6); + // check norm^2 + VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 5.1304802941E+02); + // check x + VERIFY_IS_APPROX(x[0], 1.6657666537E-01); + VERIFY_IS_APPROX(x[1], 5.1653291286E-03); + VERIFY_IS_APPROX(x[2], 1.2150007096E-02); +} + + +struct misra1a_functor : Functor +{ + misra1a_functor(void) : Functor(2,14) {} + static const double m_x[14]; + static const double m_y[14]; + int operator()(const VectorXd &b, VectorXd &fvec) + { + assert(b.size()==2); + assert(fvec.size()==14); + for(int i=0; i<14; i++) { + fvec[i] = b[0]*(1.-exp(-b[1]*m_x[i])) - m_y[i] ; + } + return 0; + } + int df(const VectorXd &b, MatrixXd &fjac) + { + assert(b.size()==2); + assert(fjac.rows()==14); + assert(fjac.cols()==2); + for(int i=0; i<14; i++) { + fjac(i,0) = (1.-exp(-b[1]*m_x[i])); + fjac(i,1) = (b[0]*m_x[i]*exp(-b[1]*m_x[i])); + } + return 0; + } +}; +const double misra1a_functor::m_x[14] = { 77.6E0, 114.9E0, 141.1E0, 190.8E0, 239.9E0, 289.0E0, 332.8E0, 378.4E0, 434.8E0, 477.3E0, 536.8E0, 593.1E0, 689.1E0, 760.0E0}; +const double misra1a_functor::m_y[14] = { 10.07E0, 14.73E0, 17.94E0, 23.93E0, 29.61E0, 35.18E0, 40.02E0, 44.82E0, 50.76E0, 55.05E0, 61.01E0, 66.40E0, 75.47E0, 81.78E0}; + +// http://www.itl.nist.gov/div898/strd/nls/data/misra1a.shtml +void testNistMisra1a(void) +{ + const int n=2; + int info; + + VectorXd x(n); + + /* + * First try + */ + x<< 500., 0.0001; + // do the computation + misra1a_functor functor; + LevenbergMarquardt lm(functor); + info = lm.minimize(x); + + // check return value + VERIFY_IS_EQUAL(info, 1); + VERIFY_IS_EQUAL(lm.nfev, 19); + VERIFY_IS_EQUAL(lm.njev, 15); + // check norm^2 + VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 1.2455138894E-01); + // check x + VERIFY_IS_APPROX(x[0], 2.3894212918E+02); + VERIFY_IS_APPROX(x[1], 5.5015643181E-04); + + /* + * Second try + */ + x<< 250., 0.0005; + // do the computation + info = lm.minimize(x); + + // check return value + VERIFY_IS_EQUAL(info, 1); + VERIFY_IS_EQUAL(lm.nfev, 5); + VERIFY_IS_EQUAL(lm.njev, 4); + // check norm^2 + VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 1.2455138894E-01); + // check x + VERIFY_IS_APPROX(x[0], 2.3894212918E+02); + VERIFY_IS_APPROX(x[1], 5.5015643181E-04); +} + +struct hahn1_functor : Functor +{ + hahn1_functor(void) : Functor(7,236) {} + static const double m_x[236]; + int operator()(const VectorXd &b, VectorXd &fvec) + { + static const double m_y[236] = { .591E0 , 1.547E0 , 2.902E0 , 2.894E0 , 4.703E0 , 6.307E0 , 7.03E0 , 7.898E0 , 9.470E0 , 9.484E0 , 10.072E0 , 10.163E0 , 11.615E0 , 12.005E0 , 12.478E0 , 12.982E0 , 12.970E0 , 13.926E0 , 14.452E0 , 14.404E0 , 15.190E0 , 15.550E0 , 15.528E0 , 15.499E0 , 16.131E0 , 16.438E0 , 16.387E0 , 16.549E0 , 16.872E0 , 16.830E0 , 16.926E0 , 16.907E0 , 16.966E0 , 17.060E0 , 17.122E0 , 17.311E0 , 17.355E0 , 17.668E0 , 17.767E0 , 17.803E0 , 17.765E0 , 17.768E0 , 17.736E0 , 17.858E0 , 17.877E0 , 17.912E0 , 18.046E0 , 18.085E0 , 18.291E0 , 18.357E0 , 18.426E0 , 18.584E0 , 18.610E0 , 18.870E0 , 18.795E0 , 19.111E0 , .367E0 , .796E0 , 0.892E0 , 1.903E0 , 2.150E0 , 3.697E0 , 5.870E0 , 6.421E0 , 7.422E0 , 9.944E0 , 11.023E0 , 11.87E0 , 12.786E0 , 14.067E0 , 13.974E0 , 14.462E0 , 14.464E0 , 15.381E0 , 15.483E0 , 15.59E0 , 16.075E0 , 16.347E0 , 16.181E0 , 16.915E0 , 17.003E0 , 16.978E0 , 17.756E0 , 17.808E0 , 17.868E0 , 18.481E0 , 18.486E0 , 19.090E0 , 16.062E0 , 16.337E0 , 16.345E0 , + 16.388E0 , 17.159E0 , 17.116E0 , 17.164E0 , 17.123E0 , 17.979E0 , 17.974E0 , 18.007E0 , 17.993E0 , 18.523E0 , 18.669E0 , 18.617E0 , 19.371E0 , 19.330E0 , 0.080E0 , 0.248E0 , 1.089E0 , 1.418E0 , 2.278E0 , 3.624E0 , 4.574E0 , 5.556E0 , 7.267E0 , 7.695E0 , 9.136E0 , 9.959E0 , 9.957E0 , 11.600E0 , 13.138E0 , 13.564E0 , 13.871E0 , 13.994E0 , 14.947E0 , 15.473E0 , 15.379E0 , 15.455E0 , 15.908E0 , 16.114E0 , 17.071E0 , 17.135E0 , 17.282E0 , 17.368E0 , 17.483E0 , 17.764E0 , 18.185E0 , 18.271E0 , 18.236E0 , 18.237E0 , 18.523E0 , 18.627E0 , 18.665E0 , 19.086E0 , 0.214E0 , 0.943E0 , 1.429E0 , 2.241E0 , 2.951E0 , 3.782E0 , 4.757E0 , 5.602E0 , 7.169E0 , 8.920E0 , 10.055E0 , 12.035E0 , 12.861E0 , 13.436E0 , 14.167E0 , 14.755E0 , 15.168E0 , 15.651E0 , 15.746E0 , 16.216E0 , 16.445E0 , 16.965E0 , 17.121E0 , 17.206E0 , 17.250E0 , 17.339E0 , 17.793E0 , 18.123E0 , 18.49E0 , 18.566E0 , 18.645E0 , 18.706E0 , 18.924E0 , 19.1E0 , 0.375E0 , 0.471E0 , 1.504E0 , 2.204E0 , 2.813E0 , 4.765E0 , 9.835E0 , 10.040E0 , 11.946E0 , 12.596E0 , +13.303E0 , 13.922E0 , 14.440E0 , 14.951E0 , 15.627E0 , 15.639E0 , 15.814E0 , 16.315E0 , 16.334E0 , 16.430E0 , 16.423E0 , 17.024E0 , 17.009E0 , 17.165E0 , 17.134E0 , 17.349E0 , 17.576E0 , 17.848E0 , 18.090E0 , 18.276E0 , 18.404E0 , 18.519E0 , 19.133E0 , 19.074E0 , 19.239E0 , 19.280E0 , 19.101E0 , 19.398E0 , 19.252E0 , 19.89E0 , 20.007E0 , 19.929E0 , 19.268E0 , 19.324E0 , 20.049E0 , 20.107E0 , 20.062E0 , 20.065E0 , 19.286E0 , 19.972E0 , 20.088E0 , 20.743E0 , 20.83E0 , 20.935E0 , 21.035E0 , 20.93E0 , 21.074E0 , 21.085E0 , 20.935E0 }; + + // int called=0; printf("call hahn1_functor with iflag=%d, called=%d\n", iflag, called); if (iflag==1) called++; + + assert(b.size()==7); + assert(fvec.size()==236); + for(int i=0; i<236; i++) { + double x=m_x[i], xx=x*x, xxx=xx*x; + fvec[i] = (b[0]+b[1]*x+b[2]*xx+b[3]*xxx) / (1.+b[4]*x+b[5]*xx+b[6]*xxx) - m_y[i]; + } + return 0; + } + + int df(const VectorXd &b, MatrixXd &fjac) + { + assert(b.size()==7); + assert(fjac.rows()==236); + assert(fjac.cols()==7); + for(int i=0; i<236; i++) { + double x=m_x[i], xx=x*x, xxx=xx*x; + double fact = 1./(1.+b[4]*x+b[5]*xx+b[6]*xxx); + fjac(i,0) = 1.*fact; + fjac(i,1) = x*fact; + fjac(i,2) = xx*fact; + fjac(i,3) = xxx*fact; + fact = - (b[0]+b[1]*x+b[2]*xx+b[3]*xxx) * fact * fact; + fjac(i,4) = x*fact; + fjac(i,5) = xx*fact; + fjac(i,6) = xxx*fact; + } + return 0; + } +}; +const double hahn1_functor::m_x[236] = { 24.41E0 , 34.82E0 , 44.09E0 , 45.07E0 , 54.98E0 , 65.51E0 , 70.53E0 , 75.70E0 , 89.57E0 , 91.14E0 , 96.40E0 , 97.19E0 , 114.26E0 , 120.25E0 , 127.08E0 , 133.55E0 , 133.61E0 , 158.67E0 , 172.74E0 , 171.31E0 , 202.14E0 , 220.55E0 , 221.05E0 , 221.39E0 , 250.99E0 , 268.99E0 , 271.80E0 , 271.97E0 , 321.31E0 , 321.69E0 , 330.14E0 , 333.03E0 , 333.47E0 , 340.77E0 , 345.65E0 , 373.11E0 , 373.79E0 , 411.82E0 , 419.51E0 , 421.59E0 , 422.02E0 , 422.47E0 , 422.61E0 , 441.75E0 , 447.41E0 , 448.7E0 , 472.89E0 , 476.69E0 , 522.47E0 , 522.62E0 , 524.43E0 , 546.75E0 , 549.53E0 , 575.29E0 , 576.00E0 , 625.55E0 , 20.15E0 , 28.78E0 , 29.57E0 , 37.41E0 , 39.12E0 , 50.24E0 , 61.38E0 , 66.25E0 , 73.42E0 , 95.52E0 , 107.32E0 , 122.04E0 , 134.03E0 , 163.19E0 , 163.48E0 , 175.70E0 , 179.86E0 , 211.27E0 , 217.78E0 , 219.14E0 , 262.52E0 , 268.01E0 , 268.62E0 , 336.25E0 , 337.23E0 , 339.33E0 , 427.38E0 , 428.58E0 , 432.68E0 , 528.99E0 , 531.08E0 , 628.34E0 , 253.24E0 , 273.13E0 , 273.66E0 , +282.10E0 , 346.62E0 , 347.19E0 , 348.78E0 , 351.18E0 , 450.10E0 , 450.35E0 , 451.92E0 , 455.56E0 , 552.22E0 , 553.56E0 , 555.74E0 , 652.59E0 , 656.20E0 , 14.13E0 , 20.41E0 , 31.30E0 , 33.84E0 , 39.70E0 , 48.83E0 , 54.50E0 , 60.41E0 , 72.77E0 , 75.25E0 , 86.84E0 , 94.88E0 , 96.40E0 , 117.37E0 , 139.08E0 , 147.73E0 , 158.63E0 , 161.84E0 , 192.11E0 , 206.76E0 , 209.07E0 , 213.32E0 , 226.44E0 , 237.12E0 , 330.90E0 , 358.72E0 , 370.77E0 , 372.72E0 , 396.24E0 , 416.59E0 , 484.02E0 , 495.47E0 , 514.78E0 , 515.65E0 , 519.47E0 , 544.47E0 , 560.11E0 , 620.77E0 , 18.97E0 , 28.93E0 , 33.91E0 , 40.03E0 , 44.66E0 , 49.87E0 , 55.16E0 , 60.90E0 , 72.08E0 , 85.15E0 , 97.06E0 , 119.63E0 , 133.27E0 , 143.84E0 , 161.91E0 , 180.67E0 , 198.44E0 , 226.86E0 , 229.65E0 , 258.27E0 , 273.77E0 , 339.15E0 , 350.13E0 , 362.75E0 , 371.03E0 , 393.32E0 , 448.53E0 , 473.78E0 , 511.12E0 , 524.70E0 , 548.75E0 , 551.64E0 , 574.02E0 , 623.86E0 , 21.46E0 , 24.33E0 , 33.43E0 , 39.22E0 , 44.18E0 , 55.02E0 , 94.33E0 , 96.44E0 , 118.82E0 , 128.48E0 , +141.94E0 , 156.92E0 , 171.65E0 , 190.00E0 , 223.26E0 , 223.88E0 , 231.50E0 , 265.05E0 , 269.44E0 , 271.78E0 , 273.46E0 , 334.61E0 , 339.79E0 , 349.52E0 , 358.18E0 , 377.98E0 , 394.77E0 , 429.66E0 , 468.22E0 , 487.27E0 , 519.54E0 , 523.03E0 , 612.99E0 , 638.59E0 , 641.36E0 , 622.05E0 , 631.50E0 , 663.97E0 , 646.9E0 , 748.29E0 , 749.21E0 , 750.14E0 , 647.04E0 , 646.89E0 , 746.9E0 , 748.43E0 , 747.35E0 , 749.27E0 , 647.61E0 , 747.78E0 , 750.51E0 , 851.37E0 , 845.97E0 , 847.54E0 , 849.93E0 , 851.61E0 , 849.75E0 , 850.98E0 , 848.23E0}; + +// http://www.itl.nist.gov/div898/strd/nls/data/hahn1.shtml +void testNistHahn1(void) +{ + const int n=7; + int info; + + VectorXd x(n); + + /* + * First try + */ + x<< 10., -1., .05, -.00001, -.05, .001, -.000001; + // do the computation + hahn1_functor functor; + LevenbergMarquardt lm(functor); + info = lm.minimize(x); + + // check return value + VERIFY_IS_EQUAL(info, 1); + VERIFY_IS_EQUAL(lm.nfev, 11); + VERIFY_IS_EQUAL(lm.njev, 10); + // check norm^2 + VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 1.5324382854E+00); + // check x + VERIFY_IS_APPROX(x[0], 1.0776351733E+00); + VERIFY_IS_APPROX(x[1],-1.2269296921E-01); + VERIFY_IS_APPROX(x[2], 4.0863750610E-03); + VERIFY_IS_APPROX(x[3],-1.426264e-06); // shoulde be : -1.4262662514E-06 + VERIFY_IS_APPROX(x[4],-5.7609940901E-03); + VERIFY_IS_APPROX(x[5], 2.4053735503E-04); + VERIFY_IS_APPROX(x[6],-1.2314450199E-07); + + /* + * Second try + */ + x<< .1, -.1, .005, -.000001, -.005, .0001, -.0000001; + // do the computation + info = lm.minimize(x); + + // check return value + VERIFY_IS_EQUAL(info, 1); + VERIFY_IS_EQUAL(lm.nfev, 11); + VERIFY_IS_EQUAL(lm.njev, 10); + // check norm^2 + VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 1.5324382854E+00); + // check x + VERIFY_IS_APPROX(x[0], 1.077640); // should be : 1.0776351733E+00 + VERIFY_IS_APPROX(x[1], -0.1226933); // should be : -1.2269296921E-01 + VERIFY_IS_APPROX(x[2], 0.004086383); // should be : 4.0863750610E-03 + VERIFY_IS_APPROX(x[3], -1.426277e-06); // shoulde be : -1.4262662514E-06 + VERIFY_IS_APPROX(x[4],-5.7609940901E-03); + VERIFY_IS_APPROX(x[5], 0.00024053772); // should be : 2.4053735503E-04 + VERIFY_IS_APPROX(x[6], -1.231450e-07); // should be : -1.2314450199E-07 + +} + +struct misra1d_functor : Functor +{ + misra1d_functor(void) : Functor(2,14) {} + static const double x[14]; + static const double y[14]; + int operator()(const VectorXd &b, VectorXd &fvec) + { + assert(b.size()==2); + assert(fvec.size()==14); + for(int i=0; i<14; i++) { + fvec[i] = b[0]*b[1]*x[i]/(1.+b[1]*x[i]) - y[i]; + } + return 0; + } + int df(const VectorXd &b, MatrixXd &fjac) + { + assert(b.size()==2); + assert(fjac.rows()==14); + assert(fjac.cols()==2); + for(int i=0; i<14; i++) { + double den = 1.+b[1]*x[i]; + fjac(i,0) = b[1]*x[i] / den; + fjac(i,1) = b[0]*x[i]*(den-b[1]*x[i])/den/den; + } + return 0; + } +}; +const double misra1d_functor::x[14] = { 77.6E0, 114.9E0, 141.1E0, 190.8E0, 239.9E0, 289.0E0, 332.8E0, 378.4E0, 434.8E0, 477.3E0, 536.8E0, 593.1E0, 689.1E0, 760.0E0}; +const double misra1d_functor::y[14] = { 10.07E0, 14.73E0, 17.94E0, 23.93E0, 29.61E0, 35.18E0, 40.02E0, 44.82E0, 50.76E0, 55.05E0, 61.01E0, 66.40E0, 75.47E0, 81.78E0}; + +// http://www.itl.nist.gov/div898/strd/nls/data/misra1d.shtml +void testNistMisra1d(void) +{ + const int n=2; + int info; + + VectorXd x(n); + + /* + * First try + */ + x<< 500., 0.0001; + // do the computation + misra1d_functor functor; + LevenbergMarquardt lm(functor); + info = lm.minimize(x); + + // check return value + VERIFY_IS_EQUAL(info, 3); + VERIFY_IS_EQUAL(lm.nfev, 9); + VERIFY_IS_EQUAL(lm.njev, 7); + // check norm^2 + VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 5.6419295283E-02); + // check x + VERIFY_IS_APPROX(x[0], 4.3736970754E+02); + VERIFY_IS_APPROX(x[1], 3.0227324449E-04); + + /* + * Second try + */ + x<< 450., 0.0003; + // do the computation + info = lm.minimize(x); + + // check return value + VERIFY_IS_EQUAL(info, 1); + VERIFY_IS_EQUAL(lm.nfev, 4); + VERIFY_IS_EQUAL(lm.njev, 3); + // check norm^2 + VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 5.6419295283E-02); + // check x + VERIFY_IS_APPROX(x[0], 4.3736970754E+02); + VERIFY_IS_APPROX(x[1], 3.0227324449E-04); +} + + +struct lanczos1_functor : Functor +{ + lanczos1_functor(void) : Functor(6,24) {} + static const double x[24]; + static const double y[24]; + int operator()(const VectorXd &b, VectorXd &fvec) + { + assert(b.size()==6); + assert(fvec.size()==24); + for(int i=0; i<24; i++) + fvec[i] = b[0]*exp(-b[1]*x[i]) + b[2]*exp(-b[3]*x[i]) + b[4]*exp(-b[5]*x[i]) - y[i]; + return 0; + } + int df(const VectorXd &b, MatrixXd &fjac) + { + assert(b.size()==6); + assert(fjac.rows()==24); + assert(fjac.cols()==6); + for(int i=0; i<24; i++) { + fjac(i,0) = exp(-b[1]*x[i]); + fjac(i,1) = -b[0]*x[i]*exp(-b[1]*x[i]); + fjac(i,2) = exp(-b[3]*x[i]); + fjac(i,3) = -b[2]*x[i]*exp(-b[3]*x[i]); + fjac(i,4) = exp(-b[5]*x[i]); + fjac(i,5) = -b[4]*x[i]*exp(-b[5]*x[i]); + } + return 0; + } +}; +const double lanczos1_functor::x[24] = { 0.000000000000E+00, 5.000000000000E-02, 1.000000000000E-01, 1.500000000000E-01, 2.000000000000E-01, 2.500000000000E-01, 3.000000000000E-01, 3.500000000000E-01, 4.000000000000E-01, 4.500000000000E-01, 5.000000000000E-01, 5.500000000000E-01, 6.000000000000E-01, 6.500000000000E-01, 7.000000000000E-01, 7.500000000000E-01, 8.000000000000E-01, 8.500000000000E-01, 9.000000000000E-01, 9.500000000000E-01, 1.000000000000E+00, 1.050000000000E+00, 1.100000000000E+00, 1.150000000000E+00 }; +const double lanczos1_functor::y[24] = { 2.513400000000E+00 ,2.044333373291E+00 ,1.668404436564E+00 ,1.366418021208E+00 ,1.123232487372E+00 ,9.268897180037E-01 ,7.679338563728E-01 ,6.388775523106E-01 ,5.337835317402E-01 ,4.479363617347E-01 ,3.775847884350E-01 ,3.197393199326E-01 ,2.720130773746E-01 ,2.324965529032E-01 ,1.996589546065E-01 ,1.722704126914E-01 ,1.493405660168E-01 ,1.300700206922E-01 ,1.138119324644E-01 ,1.000415587559E-01 ,8.833209084540E-02 ,7.833544019350E-02 ,6.976693743449E-02 ,6.239312536719E-02 }; + +// http://www.itl.nist.gov/div898/strd/nls/data/lanczos1.shtml +void testNistLanczos1(void) +{ + const int n=6; + int info; + + VectorXd x(n); + + /* + * First try + */ + x<< 1.2, 0.3, 5.6, 5.5, 6.5, 7.6; + // do the computation + lanczos1_functor functor; + LevenbergMarquardt lm(functor); + info = lm.minimize(x); + + // check return value + VERIFY_IS_EQUAL(info, 2); + VERIFY_IS_EQUAL(lm.nfev, 79); + VERIFY_IS_EQUAL(lm.njev, 72); + // check norm^2 + VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 1.430899764097e-25); // should be 1.4307867721E-25, but nist results are on 128-bit floats + // check x + VERIFY_IS_APPROX(x[0], 9.5100000027E-02); + VERIFY_IS_APPROX(x[1], 1.0000000001E+00); + VERIFY_IS_APPROX(x[2], 8.6070000013E-01); + VERIFY_IS_APPROX(x[3], 3.0000000002E+00); + VERIFY_IS_APPROX(x[4], 1.5575999998E+00); + VERIFY_IS_APPROX(x[5], 5.0000000001E+00); + + /* + * Second try + */ + x<< 0.5, 0.7, 3.6, 4.2, 4., 6.3; + // do the computation + info = lm.minimize(x); + + // check return value + VERIFY_IS_EQUAL(info, 2); + VERIFY_IS_EQUAL(lm.nfev, 9); + VERIFY_IS_EQUAL(lm.njev, 8); + // check norm^2 + VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 1.428595533845e-25); // should be 1.4307867721E-25, but nist results are on 128-bit floats + // check x + VERIFY_IS_APPROX(x[0], 9.5100000027E-02); + VERIFY_IS_APPROX(x[1], 1.0000000001E+00); + VERIFY_IS_APPROX(x[2], 8.6070000013E-01); + VERIFY_IS_APPROX(x[3], 3.0000000002E+00); + VERIFY_IS_APPROX(x[4], 1.5575999998E+00); + VERIFY_IS_APPROX(x[5], 5.0000000001E+00); + +} + +struct rat42_functor : Functor +{ + rat42_functor(void) : Functor(3,9) {} + static const double x[9]; + static const double y[9]; + int operator()(const VectorXd &b, VectorXd &fvec) + { + assert(b.size()==3); + assert(fvec.size()==9); + for(int i=0; i<9; i++) { + fvec[i] = b[0] / (1.+exp(b[1]-b[2]*x[i])) - y[i]; + } + return 0; + } + + int df(const VectorXd &b, MatrixXd &fjac) + { + assert(b.size()==3); + assert(fjac.rows()==9); + assert(fjac.cols()==3); + for(int i=0; i<9; i++) { + double e = exp(b[1]-b[2]*x[i]); + fjac(i,0) = 1./(1.+e); + fjac(i,1) = -b[0]*e/(1.+e)/(1.+e); + fjac(i,2) = +b[0]*e*x[i]/(1.+e)/(1.+e); + } + return 0; + } +}; +const double rat42_functor::x[9] = { 9.000E0, 14.000E0, 21.000E0, 28.000E0, 42.000E0, 57.000E0, 63.000E0, 70.000E0, 79.000E0 }; +const double rat42_functor::y[9] = { 8.930E0 ,10.800E0 ,18.590E0 ,22.330E0 ,39.350E0 ,56.110E0 ,61.730E0 ,64.620E0 ,67.080E0 }; + +// http://www.itl.nist.gov/div898/strd/nls/data/ratkowsky2.shtml +void testNistRat42(void) +{ + const int n=3; + int info; + + VectorXd x(n); + + /* + * First try + */ + x<< 100., 1., 0.1; + // do the computation + rat42_functor functor; + LevenbergMarquardt lm(functor); + info = lm.minimize(x); + + // check return value + VERIFY_IS_EQUAL(info, 1); + VERIFY_IS_EQUAL(lm.nfev, 10); + VERIFY_IS_EQUAL(lm.njev, 8); + // check norm^2 + VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 8.0565229338E+00); + // check x + VERIFY_IS_APPROX(x[0], 7.2462237576E+01); + VERIFY_IS_APPROX(x[1], 2.6180768402E+00); + VERIFY_IS_APPROX(x[2], 6.7359200066E-02); + + /* + * Second try + */ + x<< 75., 2.5, 0.07; + // do the computation + info = lm.minimize(x); + + // check return value + VERIFY_IS_EQUAL(info, 1); + VERIFY_IS_EQUAL(lm.nfev, 6); + VERIFY_IS_EQUAL(lm.njev, 5); + // check norm^2 + VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 8.0565229338E+00); + // check x + VERIFY_IS_APPROX(x[0], 7.2462237576E+01); + VERIFY_IS_APPROX(x[1], 2.6180768402E+00); + VERIFY_IS_APPROX(x[2], 6.7359200066E-02); +} + +struct MGH10_functor : Functor +{ + MGH10_functor(void) : Functor(3,16) {} + static const double x[16]; + static const double y[16]; + int operator()(const VectorXd &b, VectorXd &fvec) + { + assert(b.size()==3); + assert(fvec.size()==16); + for(int i=0; i<16; i++) + fvec[i] = b[0] * exp(b[1]/(x[i]+b[2])) - y[i]; + return 0; + } + int df(const VectorXd &b, MatrixXd &fjac) + { + assert(b.size()==3); + assert(fjac.rows()==16); + assert(fjac.cols()==3); + for(int i=0; i<16; i++) { + double factor = 1./(x[i]+b[2]); + double e = exp(b[1]*factor); + fjac(i,0) = e; + fjac(i,1) = b[0]*factor*e; + fjac(i,2) = -b[1]*b[0]*factor*factor*e; + } + return 0; + } +}; +const double MGH10_functor::x[16] = { 5.000000E+01, 5.500000E+01, 6.000000E+01, 6.500000E+01, 7.000000E+01, 7.500000E+01, 8.000000E+01, 8.500000E+01, 9.000000E+01, 9.500000E+01, 1.000000E+02, 1.050000E+02, 1.100000E+02, 1.150000E+02, 1.200000E+02, 1.250000E+02 }; +const double MGH10_functor::y[16] = { 3.478000E+04, 2.861000E+04, 2.365000E+04, 1.963000E+04, 1.637000E+04, 1.372000E+04, 1.154000E+04, 9.744000E+03, 8.261000E+03, 7.030000E+03, 6.005000E+03, 5.147000E+03, 4.427000E+03, 3.820000E+03, 3.307000E+03, 2.872000E+03 }; + +// http://www.itl.nist.gov/div898/strd/nls/data/mgh10.shtml +void testNistMGH10(void) +{ + const int n=3; + int info; + + VectorXd x(n); + + /* + * First try + */ + x<< 2., 400000., 25000.; + // do the computation + MGH10_functor functor; + LevenbergMarquardt lm(functor); + info = lm.minimize(x); + + // check return value + VERIFY_IS_EQUAL(info, 2); + VERIFY_IS_EQUAL(lm.nfev, 284 ); + VERIFY_IS_EQUAL(lm.njev, 249 ); + // check norm^2 + VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 8.7945855171E+01); + // check x + VERIFY_IS_APPROX(x[0], 5.6096364710E-03); + VERIFY_IS_APPROX(x[1], 6.1813463463E+03); + VERIFY_IS_APPROX(x[2], 3.4522363462E+02); + + /* + * Second try + */ + x<< 0.02, 4000., 250.; + // do the computation + info = lm.minimize(x); + + // check return value + VERIFY_IS_EQUAL(info, 3); + VERIFY_IS_EQUAL(lm.nfev, 126); + VERIFY_IS_EQUAL(lm.njev, 116); + // check norm^2 + VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 8.7945855171E+01); + // check x + VERIFY_IS_APPROX(x[0], 5.6096364710E-03); + VERIFY_IS_APPROX(x[1], 6.1813463463E+03); + VERIFY_IS_APPROX(x[2], 3.4522363462E+02); +} + + +struct BoxBOD_functor : Functor +{ + BoxBOD_functor(void) : Functor(2,6) {} + static const double x[6]; + int operator()(const VectorXd &b, VectorXd &fvec) + { + static const double y[6] = { 109., 149., 149., 191., 213., 224. }; + assert(b.size()==2); + assert(fvec.size()==6); + for(int i=0; i<6; i++) + fvec[i] = b[0]*(1.-exp(-b[1]*x[i])) - y[i]; + return 0; + } + int df(const VectorXd &b, MatrixXd &fjac) + { + assert(b.size()==2); + assert(fjac.rows()==6); + assert(fjac.cols()==2); + for(int i=0; i<6; i++) { + double e = exp(-b[1]*x[i]); + fjac(i,0) = 1.-e; + fjac(i,1) = b[0]*x[i]*e; + } + return 0; + } +}; +const double BoxBOD_functor::x[6] = { 1., 2., 3., 5., 7., 10. }; + +// http://www.itl.nist.gov/div898/strd/nls/data/boxbod.shtml +void testNistBoxBOD(void) +{ + const int n=2; + int info; + + VectorXd x(n); + + /* + * First try + */ + x<< 1., 1.; + // do the computation + BoxBOD_functor functor; + LevenbergMarquardt lm(functor); + lm.parameters.ftol = 1.E6*NumTraits::epsilon(); + lm.parameters.xtol = 1.E6*NumTraits::epsilon(); + lm.parameters.factor = 10.; + info = lm.minimize(x); + + // check return value + VERIFY_IS_EQUAL(info, 1); + VERIFY_IS_EQUAL(lm.nfev, 31); + VERIFY_IS_EQUAL(lm.njev, 25); + // check norm^2 + VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 1.1680088766E+03); + // check x + VERIFY_IS_APPROX(x[0], 2.1380940889E+02); + VERIFY_IS_APPROX(x[1], 5.4723748542E-01); + + /* + * Second try + */ + x<< 100., 0.75; + // do the computation + lm.resetParameters(); + lm.parameters.ftol = NumTraits::epsilon(); + lm.parameters.xtol = NumTraits::epsilon(); + info = lm.minimize(x); + + // check return value + VERIFY_IS_EQUAL(info, 1); + VERIFY_IS_EQUAL(lm.nfev, 15 ); + VERIFY_IS_EQUAL(lm.njev, 14 ); + // check norm^2 + VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 1.1680088766E+03); + // check x + VERIFY_IS_APPROX(x[0], 2.1380940889E+02); + VERIFY_IS_APPROX(x[1], 5.4723748542E-01); +} + +struct MGH17_functor : Functor +{ + MGH17_functor(void) : Functor(5,33) {} + static const double x[33]; + static const double y[33]; + int operator()(const VectorXd &b, VectorXd &fvec) + { + assert(b.size()==5); + assert(fvec.size()==33); + for(int i=0; i<33; i++) + fvec[i] = b[0] + b[1]*exp(-b[3]*x[i]) + b[2]*exp(-b[4]*x[i]) - y[i]; + return 0; + } + int df(const VectorXd &b, MatrixXd &fjac) + { + assert(b.size()==5); + assert(fjac.rows()==33); + assert(fjac.cols()==5); + for(int i=0; i<33; i++) { + fjac(i,0) = 1.; + fjac(i,1) = exp(-b[3]*x[i]); + fjac(i,2) = exp(-b[4]*x[i]); + fjac(i,3) = -x[i]*b[1]*exp(-b[3]*x[i]); + fjac(i,4) = -x[i]*b[2]*exp(-b[4]*x[i]); + } + return 0; + } +}; +const double MGH17_functor::x[33] = { 0.000000E+00, 1.000000E+01, 2.000000E+01, 3.000000E+01, 4.000000E+01, 5.000000E+01, 6.000000E+01, 7.000000E+01, 8.000000E+01, 9.000000E+01, 1.000000E+02, 1.100000E+02, 1.200000E+02, 1.300000E+02, 1.400000E+02, 1.500000E+02, 1.600000E+02, 1.700000E+02, 1.800000E+02, 1.900000E+02, 2.000000E+02, 2.100000E+02, 2.200000E+02, 2.300000E+02, 2.400000E+02, 2.500000E+02, 2.600000E+02, 2.700000E+02, 2.800000E+02, 2.900000E+02, 3.000000E+02, 3.100000E+02, 3.200000E+02 }; +const double MGH17_functor::y[33] = { 8.440000E-01, 9.080000E-01, 9.320000E-01, 9.360000E-01, 9.250000E-01, 9.080000E-01, 8.810000E-01, 8.500000E-01, 8.180000E-01, 7.840000E-01, 7.510000E-01, 7.180000E-01, 6.850000E-01, 6.580000E-01, 6.280000E-01, 6.030000E-01, 5.800000E-01, 5.580000E-01, 5.380000E-01, 5.220000E-01, 5.060000E-01, 4.900000E-01, 4.780000E-01, 4.670000E-01, 4.570000E-01, 4.480000E-01, 4.380000E-01, 4.310000E-01, 4.240000E-01, 4.200000E-01, 4.140000E-01, 4.110000E-01, 4.060000E-01 }; + +// http://www.itl.nist.gov/div898/strd/nls/data/mgh17.shtml +void testNistMGH17(void) +{ + const int n=5; + int info; + + VectorXd x(n); + + /* + * First try + */ + x<< 50., 150., -100., 1., 2.; + // do the computation + MGH17_functor functor; + LevenbergMarquardt lm(functor); + lm.parameters.ftol = NumTraits::epsilon(); + lm.parameters.xtol = NumTraits::epsilon(); + lm.parameters.maxfev = 1000; + info = lm.minimize(x); + + // check return value + VERIFY_IS_EQUAL(info, 2); + VERIFY_IS_EQUAL(lm.nfev, 602 ); + VERIFY_IS_EQUAL(lm.njev, 545 ); + // check norm^2 + VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 5.4648946975E-05); + // check x + VERIFY_IS_APPROX(x[0], 3.7541005211E-01); + VERIFY_IS_APPROX(x[1], 1.9358469127E+00); + VERIFY_IS_APPROX(x[2], -1.4646871366E+00); + VERIFY_IS_APPROX(x[3], 1.2867534640E-02); + VERIFY_IS_APPROX(x[4], 2.2122699662E-02); + + /* + * Second try + */ + x<< 0.5 ,1.5 ,-1 ,0.01 ,0.02; + // do the computation + lm.resetParameters(); + info = lm.minimize(x); + + // check return value + VERIFY_IS_EQUAL(info, 1); + VERIFY_IS_EQUAL(lm.nfev, 18); + VERIFY_IS_EQUAL(lm.njev, 15); + // check norm^2 + VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 5.4648946975E-05); + // check x + VERIFY_IS_APPROX(x[0], 3.7541005211E-01); + VERIFY_IS_APPROX(x[1], 1.9358469127E+00); + VERIFY_IS_APPROX(x[2], -1.4646871366E+00); + VERIFY_IS_APPROX(x[3], 1.2867534640E-02); + VERIFY_IS_APPROX(x[4], 2.2122699662E-02); +} + +struct MGH09_functor : Functor +{ + MGH09_functor(void) : Functor(4,11) {} + static const double _x[11]; + static const double y[11]; + int operator()(const VectorXd &b, VectorXd &fvec) + { + assert(b.size()==4); + assert(fvec.size()==11); + for(int i=0; i<11; i++) { + double x = _x[i], xx=x*x; + fvec[i] = b[0]*(xx+x*b[1])/(xx+x*b[2]+b[3]) - y[i]; + } + return 0; + } + int df(const VectorXd &b, MatrixXd &fjac) + { + assert(b.size()==4); + assert(fjac.rows()==11); + assert(fjac.cols()==4); + for(int i=0; i<11; i++) { + double x = _x[i], xx=x*x; + double factor = 1./(xx+x*b[2]+b[3]); + fjac(i,0) = (xx+x*b[1]) * factor; + fjac(i,1) = b[0]*x* factor; + fjac(i,2) = - b[0]*(xx+x*b[1]) * x * factor * factor; + fjac(i,3) = - b[0]*(xx+x*b[1]) * factor * factor; + } + return 0; + } +}; +const double MGH09_functor::_x[11] = { 4., 2., 1., 5.E-1 , 2.5E-01, 1.670000E-01, 1.250000E-01, 1.E-01, 8.330000E-02, 7.140000E-02, 6.250000E-02 }; +const double MGH09_functor::y[11] = { 1.957000E-01, 1.947000E-01, 1.735000E-01, 1.600000E-01, 8.440000E-02, 6.270000E-02, 4.560000E-02, 3.420000E-02, 3.230000E-02, 2.350000E-02, 2.460000E-02 }; + +// http://www.itl.nist.gov/div898/strd/nls/data/mgh09.shtml +void testNistMGH09(void) +{ + const int n=4; + int info; + + VectorXd x(n); + + /* + * First try + */ + x<< 25., 39, 41.5, 39.; + // do the computation + MGH09_functor functor; + LevenbergMarquardt lm(functor); + lm.parameters.maxfev = 1000; + info = lm.minimize(x); + + // check return value + VERIFY_IS_EQUAL(info, 1); + VERIFY_IS_EQUAL(lm.nfev, 490 ); + VERIFY_IS_EQUAL(lm.njev, 376 ); + // check norm^2 + VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 3.0750560385E-04); + // check x + VERIFY_IS_APPROX(x[0], 0.1928077089); // should be 1.9280693458E-01 + VERIFY_IS_APPROX(x[1], 0.19126423573); // should be 1.9128232873E-01 + VERIFY_IS_APPROX(x[2], 0.12305309914); // should be 1.2305650693E-01 + VERIFY_IS_APPROX(x[3], 0.13605395375); // should be 1.3606233068E-01 + + /* + * Second try + */ + x<< 0.25, 0.39, 0.415, 0.39; + // do the computation + lm.resetParameters(); + info = lm.minimize(x); + + // check return value + VERIFY_IS_EQUAL(info, 1); + VERIFY_IS_EQUAL(lm.nfev, 18); + VERIFY_IS_EQUAL(lm.njev, 16); + // check norm^2 + VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 3.0750560385E-04); + // check x + VERIFY_IS_APPROX(x[0], 0.19280781); // should be 1.9280693458E-01 + VERIFY_IS_APPROX(x[1], 0.19126265); // should be 1.9128232873E-01 + VERIFY_IS_APPROX(x[2], 0.12305280); // should be 1.2305650693E-01 + VERIFY_IS_APPROX(x[3], 0.13605322); // should be 1.3606233068E-01 +} + + + +struct Bennett5_functor : Functor +{ + Bennett5_functor(void) : Functor(3,154) {} + static const double x[154]; + static const double y[154]; + int operator()(const VectorXd &b, VectorXd &fvec) + { + assert(b.size()==3); + assert(fvec.size()==154); + for(int i=0; i<154; i++) + fvec[i] = b[0]* pow(b[1]+x[i],-1./b[2]) - y[i]; + return 0; + } + int df(const VectorXd &b, MatrixXd &fjac) + { + assert(b.size()==3); + assert(fjac.rows()==154); + assert(fjac.cols()==3); + for(int i=0; i<154; i++) { + double e = pow(b[1]+x[i],-1./b[2]); + fjac(i,0) = e; + fjac(i,1) = - b[0]*e/b[2]/(b[1]+x[i]); + fjac(i,2) = b[0]*e*log(b[1]+x[i])/b[2]/b[2]; + } + return 0; + } +}; +const double Bennett5_functor::x[154] = { 7.447168E0, 8.102586E0, 8.452547E0, 8.711278E0, 8.916774E0, 9.087155E0, 9.232590E0, 9.359535E0, 9.472166E0, 9.573384E0, 9.665293E0, 9.749461E0, 9.827092E0, 9.899128E0, 9.966321E0, 10.029280E0, 10.088510E0, 10.144430E0, 10.197380E0, 10.247670E0, 10.295560E0, 10.341250E0, 10.384950E0, 10.426820E0, 10.467000E0, 10.505640E0, 10.542830E0, 10.578690E0, 10.613310E0, 10.646780E0, 10.679150E0, 10.710520E0, 10.740920E0, 10.770440E0, 10.799100E0, 10.826970E0, 10.854080E0, 10.880470E0, 10.906190E0, 10.931260E0, 10.955720E0, 10.979590E0, 11.002910E0, 11.025700E0, 11.047980E0, 11.069770E0, 11.091100E0, 11.111980E0, 11.132440E0, 11.152480E0, 11.172130E0, 11.191410E0, 11.210310E0, 11.228870E0, 11.247090E0, 11.264980E0, 11.282560E0, 11.299840E0, 11.316820E0, 11.333520E0, 11.349940E0, 11.366100E0, 11.382000E0, 11.397660E0, 11.413070E0, 11.428240E0, 11.443200E0, 11.457930E0, 11.472440E0, 11.486750E0, 11.500860E0, 11.514770E0, 11.528490E0, 11.542020E0, 11.555380E0, 11.568550E0, +11.581560E0, 11.594420E0, 11.607121E0, 11.619640E0, 11.632000E0, 11.644210E0, 11.656280E0, 11.668200E0, 11.679980E0, 11.691620E0, 11.703130E0, 11.714510E0, 11.725760E0, 11.736880E0, 11.747890E0, 11.758780E0, 11.769550E0, 11.780200E0, 11.790730E0, 11.801160E0, 11.811480E0, 11.821700E0, 11.831810E0, 11.841820E0, 11.851730E0, 11.861550E0, 11.871270E0, 11.880890E0, 11.890420E0, 11.899870E0, 11.909220E0, 11.918490E0, 11.927680E0, 11.936780E0, 11.945790E0, 11.954730E0, 11.963590E0, 11.972370E0, 11.981070E0, 11.989700E0, 11.998260E0, 12.006740E0, 12.015150E0, 12.023490E0, 12.031760E0, 12.039970E0, 12.048100E0, 12.056170E0, 12.064180E0, 12.072120E0, 12.080010E0, 12.087820E0, 12.095580E0, 12.103280E0, 12.110920E0, 12.118500E0, 12.126030E0, 12.133500E0, 12.140910E0, 12.148270E0, 12.155570E0, 12.162830E0, 12.170030E0, 12.177170E0, 12.184270E0, 12.191320E0, 12.198320E0, 12.205270E0, 12.212170E0, 12.219030E0, 12.225840E0, 12.232600E0, 12.239320E0, 12.245990E0, 12.252620E0, 12.259200E0, 12.265750E0, 12.272240E0 }; +const double Bennett5_functor::y[154] = { -34.834702E0 ,-34.393200E0 ,-34.152901E0 ,-33.979099E0 ,-33.845901E0 ,-33.732899E0 ,-33.640301E0 ,-33.559200E0 ,-33.486801E0 ,-33.423100E0 ,-33.365101E0 ,-33.313000E0 ,-33.260899E0 ,-33.217400E0 ,-33.176899E0 ,-33.139198E0 ,-33.101601E0 ,-33.066799E0 ,-33.035000E0 ,-33.003101E0 ,-32.971298E0 ,-32.942299E0 ,-32.916302E0 ,-32.890202E0 ,-32.864101E0 ,-32.841000E0 ,-32.817799E0 ,-32.797501E0 ,-32.774300E0 ,-32.757000E0 ,-32.733799E0 ,-32.716400E0 ,-32.699100E0 ,-32.678799E0 ,-32.661400E0 ,-32.644001E0 ,-32.626701E0 ,-32.612202E0 ,-32.597698E0 ,-32.583199E0 ,-32.568699E0 ,-32.554298E0 ,-32.539799E0 ,-32.525299E0 ,-32.510799E0 ,-32.499199E0 ,-32.487598E0 ,-32.473202E0 ,-32.461601E0 ,-32.435501E0 ,-32.435501E0 ,-32.426800E0 ,-32.412300E0 ,-32.400799E0 ,-32.392101E0 ,-32.380501E0 ,-32.366001E0 ,-32.357300E0 ,-32.348598E0 ,-32.339901E0 ,-32.328400E0 ,-32.319698E0 ,-32.311001E0 ,-32.299400E0 ,-32.290699E0 ,-32.282001E0 ,-32.273300E0 ,-32.264599E0 ,-32.256001E0 ,-32.247299E0 +,-32.238602E0 ,-32.229900E0 ,-32.224098E0 ,-32.215401E0 ,-32.203800E0 ,-32.198002E0 ,-32.189400E0 ,-32.183601E0 ,-32.174900E0 ,-32.169102E0 ,-32.163300E0 ,-32.154598E0 ,-32.145901E0 ,-32.140099E0 ,-32.131401E0 ,-32.125599E0 ,-32.119801E0 ,-32.111198E0 ,-32.105400E0 ,-32.096699E0 ,-32.090900E0 ,-32.088001E0 ,-32.079300E0 ,-32.073502E0 ,-32.067699E0 ,-32.061901E0 ,-32.056099E0 ,-32.050301E0 ,-32.044498E0 ,-32.038799E0 ,-32.033001E0 ,-32.027199E0 ,-32.024300E0 ,-32.018501E0 ,-32.012699E0 ,-32.004002E0 ,-32.001099E0 ,-31.995300E0 ,-31.989500E0 ,-31.983700E0 ,-31.977900E0 ,-31.972099E0 ,-31.969299E0 ,-31.963501E0 ,-31.957701E0 ,-31.951900E0 ,-31.946100E0 ,-31.940300E0 ,-31.937401E0 ,-31.931601E0 ,-31.925800E0 ,-31.922899E0 ,-31.917101E0 ,-31.911301E0 ,-31.908400E0 ,-31.902599E0 ,-31.896900E0 ,-31.893999E0 ,-31.888201E0 ,-31.885300E0 ,-31.882401E0 ,-31.876600E0 ,-31.873699E0 ,-31.867901E0 ,-31.862101E0 ,-31.859200E0 ,-31.856300E0 ,-31.850500E0 ,-31.844700E0 ,-31.841801E0 ,-31.838900E0 ,-31.833099E0 ,-31.830200E0 , +-31.827299E0 ,-31.821600E0 ,-31.818701E0 ,-31.812901E0 ,-31.809999E0 ,-31.807100E0 ,-31.801300E0 ,-31.798401E0 ,-31.795500E0 ,-31.789700E0 ,-31.786800E0 }; + +// http://www.itl.nist.gov/div898/strd/nls/data/bennett5.shtml +void testNistBennett5(void) +{ + const int n=3; + int info; + + VectorXd x(n); + + /* + * First try + */ + x<< -2000., 50., 0.8; + // do the computation + Bennett5_functor functor; + LevenbergMarquardt lm(functor); + lm.parameters.maxfev = 1000; + info = lm.minimize(x); + + // check return value + VERIFY_IS_EQUAL(info, 1); + VERIFY_IS_EQUAL(lm.nfev, 758); + VERIFY_IS_EQUAL(lm.njev, 744); + // check norm^2 + VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 5.2404744073E-04); + // check x + VERIFY_IS_APPROX(x[0], -2.5235058043E+03); + VERIFY_IS_APPROX(x[1], 4.6736564644E+01); + VERIFY_IS_APPROX(x[2], 9.3218483193E-01); + /* + * Second try + */ + x<< -1500., 45., 0.85; + // do the computation + lm.resetParameters(); + info = lm.minimize(x); + + // check return value + VERIFY_IS_EQUAL(info, 1); + VERIFY_IS_EQUAL(lm.nfev, 203); + VERIFY_IS_EQUAL(lm.njev, 192); + // check norm^2 + VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 5.2404744073E-04); + // check x + VERIFY_IS_APPROX(x[0], -2523.3007865); // should be -2.5235058043E+03 + VERIFY_IS_APPROX(x[1], 46.735705771); // should be 4.6736564644E+01); + VERIFY_IS_APPROX(x[2], 0.93219881891); // should be 9.3218483193E-01); +} + +struct thurber_functor : Functor +{ + thurber_functor(void) : Functor(7,37) {} + static const double _x[37]; + static const double _y[37]; + int operator()(const VectorXd &b, VectorXd &fvec) + { + // int called=0; printf("call hahn1_functor with iflag=%d, called=%d\n", iflag, called); if (iflag==1) called++; + assert(b.size()==7); + assert(fvec.size()==37); + for(int i=0; i<37; i++) { + double x=_x[i], xx=x*x, xxx=xx*x; + fvec[i] = (b[0]+b[1]*x+b[2]*xx+b[3]*xxx) / (1.+b[4]*x+b[5]*xx+b[6]*xxx) - _y[i]; + } + return 0; + } + int df(const VectorXd &b, MatrixXd &fjac) + { + assert(b.size()==7); + assert(fjac.rows()==37); + assert(fjac.cols()==7); + for(int i=0; i<37; i++) { + double x=_x[i], xx=x*x, xxx=xx*x; + double fact = 1./(1.+b[4]*x+b[5]*xx+b[6]*xxx); + fjac(i,0) = 1.*fact; + fjac(i,1) = x*fact; + fjac(i,2) = xx*fact; + fjac(i,3) = xxx*fact; + fact = - (b[0]+b[1]*x+b[2]*xx+b[3]*xxx) * fact * fact; + fjac(i,4) = x*fact; + fjac(i,5) = xx*fact; + fjac(i,6) = xxx*fact; + } + return 0; + } +}; +const double thurber_functor::_x[37] = { -3.067E0, -2.981E0, -2.921E0, -2.912E0, -2.840E0, -2.797E0, -2.702E0, -2.699E0, -2.633E0, -2.481E0, -2.363E0, -2.322E0, -1.501E0, -1.460E0, -1.274E0, -1.212E0, -1.100E0, -1.046E0, -0.915E0, -0.714E0, -0.566E0, -0.545E0, -0.400E0, -0.309E0, -0.109E0, -0.103E0, 0.010E0, 0.119E0, 0.377E0, 0.790E0, 0.963E0, 1.006E0, 1.115E0, 1.572E0, 1.841E0, 2.047E0, 2.200E0 }; +const double thurber_functor::_y[37] = { 80.574E0, 84.248E0, 87.264E0, 87.195E0, 89.076E0, 89.608E0, 89.868E0, 90.101E0, 92.405E0, 95.854E0, 100.696E0, 101.060E0, 401.672E0, 390.724E0, 567.534E0, 635.316E0, 733.054E0, 759.087E0, 894.206E0, 990.785E0, 1090.109E0, 1080.914E0, 1122.643E0, 1178.351E0, 1260.531E0, 1273.514E0, 1288.339E0, 1327.543E0, 1353.863E0, 1414.509E0, 1425.208E0, 1421.384E0, 1442.962E0, 1464.350E0, 1468.705E0, 1447.894E0, 1457.628E0}; + +// http://www.itl.nist.gov/div898/strd/nls/data/thurber.shtml +void testNistThurber(void) +{ + const int n=7; + int info; + + VectorXd x(n); + + /* + * First try + */ + x<< 1000 ,1000 ,400 ,40 ,0.7,0.3,0.0 ; + // do the computation + thurber_functor functor; + LevenbergMarquardt lm(functor); + lm.parameters.ftol = 1.E4*NumTraits::epsilon(); + lm.parameters.xtol = 1.E4*NumTraits::epsilon(); + info = lm.minimize(x); + + // check return value + VERIFY_IS_EQUAL(info, 1); + VERIFY_IS_EQUAL(lm.nfev, 39); + VERIFY_IS_EQUAL(lm.njev, 36); + // check norm^2 + VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 5.6427082397E+03); + // check x + VERIFY_IS_APPROX(x[0], 1.2881396800E+03); + VERIFY_IS_APPROX(x[1], 1.4910792535E+03); + VERIFY_IS_APPROX(x[2], 5.8323836877E+02); + VERIFY_IS_APPROX(x[3], 7.5416644291E+01); + VERIFY_IS_APPROX(x[4], 9.6629502864E-01); + VERIFY_IS_APPROX(x[5], 3.9797285797E-01); + VERIFY_IS_APPROX(x[6], 4.9727297349E-02); + + /* + * Second try + */ + x<< 1300 ,1500 ,500 ,75 ,1 ,0.4 ,0.05 ; + // do the computation + lm.resetParameters(); + lm.parameters.ftol = 1.E4*NumTraits::epsilon(); + lm.parameters.xtol = 1.E4*NumTraits::epsilon(); + info = lm.minimize(x); + + // check return value + VERIFY_IS_EQUAL(info, 1); + VERIFY_IS_EQUAL(lm.nfev, 29); + VERIFY_IS_EQUAL(lm.njev, 28); + // check norm^2 + VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 5.6427082397E+03); + // check x + VERIFY_IS_APPROX(x[0], 1.2881396800E+03); + VERIFY_IS_APPROX(x[1], 1.4910792535E+03); + VERIFY_IS_APPROX(x[2], 5.8323836877E+02); + VERIFY_IS_APPROX(x[3], 7.5416644291E+01); + VERIFY_IS_APPROX(x[4], 9.6629502864E-01); + VERIFY_IS_APPROX(x[5], 3.9797285797E-01); + VERIFY_IS_APPROX(x[6], 4.9727297349E-02); +} + +struct rat43_functor : Functor +{ + rat43_functor(void) : Functor(4,15) {} + static const double x[15]; + static const double y[15]; + int operator()(const VectorXd &b, VectorXd &fvec) + { + assert(b.size()==4); + assert(fvec.size()==15); + for(int i=0; i<15; i++) + fvec[i] = b[0] * pow(1.+exp(b[1]-b[2]*x[i]),-1./b[3]) - y[i]; + return 0; + } + int df(const VectorXd &b, MatrixXd &fjac) + { + assert(b.size()==4); + assert(fjac.rows()==15); + assert(fjac.cols()==4); + for(int i=0; i<15; i++) { + double e = exp(b[1]-b[2]*x[i]); + double power = -1./b[3]; + fjac(i,0) = pow(1.+e, power); + fjac(i,1) = power*b[0]*e*pow(1.+e, power-1.); + fjac(i,2) = -power*b[0]*e*x[i]*pow(1.+e, power-1.); + fjac(i,3) = b[0]*power*power*log(1.+e)*pow(1.+e, power); + } + return 0; + } +}; +const double rat43_functor::x[15] = { 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15. }; +const double rat43_functor::y[15] = { 16.08, 33.83, 65.80, 97.20, 191.55, 326.20, 386.87, 520.53, 590.03, 651.92, 724.93, 699.56, 689.96, 637.56, 717.41 }; + +// http://www.itl.nist.gov/div898/strd/nls/data/ratkowsky3.shtml +void testNistRat43(void) +{ + const int n=4; + int info; + + VectorXd x(n); + + /* + * First try + */ + x<< 100., 10., 1., 1.; + // do the computation + rat43_functor functor; + LevenbergMarquardt lm(functor); + lm.parameters.ftol = 1.E6*NumTraits::epsilon(); + lm.parameters.xtol = 1.E6*NumTraits::epsilon(); + info = lm.minimize(x); + + // check return value + VERIFY_IS_EQUAL(info, 1); + VERIFY_IS_EQUAL(lm.nfev, 27); + VERIFY_IS_EQUAL(lm.njev, 20); + // check norm^2 + VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 8.7864049080E+03); + // check x + VERIFY_IS_APPROX(x[0], 6.9964151270E+02); + VERIFY_IS_APPROX(x[1], 5.2771253025E+00); + VERIFY_IS_APPROX(x[2], 7.5962938329E-01); + VERIFY_IS_APPROX(x[3], 1.2792483859E+00); + + /* + * Second try + */ + x<< 700., 5., 0.75, 1.3; + // do the computation + lm.resetParameters(); + lm.parameters.ftol = 1.E5*NumTraits::epsilon(); + lm.parameters.xtol = 1.E5*NumTraits::epsilon(); + info = lm.minimize(x); + + // check return value + VERIFY_IS_EQUAL(info, 1); + VERIFY_IS_EQUAL(lm.nfev, 9); + VERIFY_IS_EQUAL(lm.njev, 8); + // check norm^2 + VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 8.7864049080E+03); + // check x + VERIFY_IS_APPROX(x[0], 6.9964151270E+02); + VERIFY_IS_APPROX(x[1], 5.2771253025E+00); + VERIFY_IS_APPROX(x[2], 7.5962938329E-01); + VERIFY_IS_APPROX(x[3], 1.2792483859E+00); +} + + + +struct eckerle4_functor : Functor +{ + eckerle4_functor(void) : Functor(3,35) {} + static const double x[35]; + static const double y[35]; + int operator()(const VectorXd &b, VectorXd &fvec) + { + assert(b.size()==3); + assert(fvec.size()==35); + for(int i=0; i<35; i++) + fvec[i] = b[0]/b[1] * exp(-0.5*(x[i]-b[2])*(x[i]-b[2])/(b[1]*b[1])) - y[i]; + return 0; + } + int df(const VectorXd &b, MatrixXd &fjac) + { + assert(b.size()==3); + assert(fjac.rows()==35); + assert(fjac.cols()==3); + for(int i=0; i<35; i++) { + double b12 = b[1]*b[1]; + double e = exp(-0.5*(x[i]-b[2])*(x[i]-b[2])/b12); + fjac(i,0) = e / b[1]; + fjac(i,1) = ((x[i]-b[2])*(x[i]-b[2])/b12-1.) * b[0]*e/b12; + fjac(i,2) = (x[i]-b[2])*e*b[0]/b[1]/b12; + } + return 0; + } +}; +const double eckerle4_functor::x[35] = { 400.0, 405.0, 410.0, 415.0, 420.0, 425.0, 430.0, 435.0, 436.5, 438.0, 439.5, 441.0, 442.5, 444.0, 445.5, 447.0, 448.5, 450.0, 451.5, 453.0, 454.5, 456.0, 457.5, 459.0, 460.5, 462.0, 463.5, 465.0, 470.0, 475.0, 480.0, 485.0, 490.0, 495.0, 500.0}; +const double eckerle4_functor::y[35] = { 0.0001575, 0.0001699, 0.0002350, 0.0003102, 0.0004917, 0.0008710, 0.0017418, 0.0046400, 0.0065895, 0.0097302, 0.0149002, 0.0237310, 0.0401683, 0.0712559, 0.1264458, 0.2073413, 0.2902366, 0.3445623, 0.3698049, 0.3668534, 0.3106727, 0.2078154, 0.1164354, 0.0616764, 0.0337200, 0.0194023, 0.0117831, 0.0074357, 0.0022732, 0.0008800, 0.0004579, 0.0002345, 0.0001586, 0.0001143, 0.0000710 }; + +// http://www.itl.nist.gov/div898/strd/nls/data/eckerle4.shtml +void testNistEckerle4(void) +{ + const int n=3; + int info; + + VectorXd x(n); + + /* + * First try + */ + x<< 1., 10., 500.; + // do the computation + eckerle4_functor functor; + LevenbergMarquardt lm(functor); + info = lm.minimize(x); + + // check return value + VERIFY_IS_EQUAL(info, 1); + VERIFY_IS_EQUAL(lm.nfev, 18); + VERIFY_IS_EQUAL(lm.njev, 15); + // check norm^2 + VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 1.4635887487E-03); + // check x + VERIFY_IS_APPROX(x[0], 1.5543827178); + VERIFY_IS_APPROX(x[1], 4.0888321754); + VERIFY_IS_APPROX(x[2], 4.5154121844E+02); + + /* + * Second try + */ + x<< 1.5, 5., 450.; + // do the computation + info = lm.minimize(x); + + // check return value + VERIFY_IS_EQUAL(info, 1); + VERIFY_IS_EQUAL(lm.nfev, 7); + VERIFY_IS_EQUAL(lm.njev, 6); + // check norm^2 + VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 1.4635887487E-03); + // check x + VERIFY_IS_APPROX(x[0], 1.5543827178); + VERIFY_IS_APPROX(x[1], 4.0888321754); + VERIFY_IS_APPROX(x[2], 4.5154121844E+02); +} + +void test_NonLinearOptimization() +{ + // Tests using the examples provided by (c)minpack + CALL_SUBTEST/*_1*/(testChkder()); + CALL_SUBTEST/*_1*/(testLmder1()); + CALL_SUBTEST/*_1*/(testLmder()); + CALL_SUBTEST/*_2*/(testHybrj1()); + CALL_SUBTEST/*_2*/(testHybrj()); + CALL_SUBTEST/*_2*/(testHybrd1()); + CALL_SUBTEST/*_2*/(testHybrd()); + CALL_SUBTEST/*_3*/(testLmstr1()); + CALL_SUBTEST/*_3*/(testLmstr()); + CALL_SUBTEST/*_3*/(testLmdif1()); + CALL_SUBTEST/*_3*/(testLmdif()); + + // NIST tests, level of difficulty = "Lower" + CALL_SUBTEST/*_4*/(testNistMisra1a()); + CALL_SUBTEST/*_4*/(testNistChwirut2()); + + // NIST tests, level of difficulty = "Average" + CALL_SUBTEST/*_5*/(testNistHahn1()); + CALL_SUBTEST/*_6*/(testNistMisra1d()); +// CALL_SUBTEST/*_7*/(testNistMGH17()); +// CALL_SUBTEST/*_8*/(testNistLanczos1()); + +// // NIST tests, level of difficulty = "Higher" + CALL_SUBTEST/*_9*/(testNistRat42()); +// CALL_SUBTEST/*_10*/(testNistMGH10()); + CALL_SUBTEST/*_11*/(testNistBoxBOD()); +// CALL_SUBTEST/*_12*/(testNistMGH09()); + CALL_SUBTEST/*_13*/(testNistBennett5()); + CALL_SUBTEST/*_14*/(testNistThurber()); + CALL_SUBTEST/*_15*/(testNistRat43()); + CALL_SUBTEST/*_16*/(testNistEckerle4()); +} + +/* + * Can be useful for debugging... + printf("info, nfev : %d, %d\n", info, lm.nfev); + printf("info, nfev, njev : %d, %d, %d\n", info, solver.nfev, solver.njev); + printf("info, nfev : %d, %d\n", info, solver.nfev); + printf("x[0] : %.32g\n", x[0]); + printf("x[1] : %.32g\n", x[1]); + printf("x[2] : %.32g\n", x[2]); + printf("x[3] : %.32g\n", x[3]); + printf("fvec.blueNorm() : %.32g\n", solver.fvec.blueNorm()); + printf("fvec.blueNorm() : %.32g\n", lm.fvec.blueNorm()); + + printf("info, nfev, njev : %d, %d, %d\n", info, lm.nfev, lm.njev); + printf("fvec.squaredNorm() : %.13g\n", lm.fvec.squaredNorm()); + std::cout << x << std::endl; + std::cout.precision(9); + std::cout << x[0] << std::endl; + std::cout << x[1] << std::endl; + std::cout << x[2] << std::endl; + std::cout << x[3] << std::endl; +*/ + diff --git a/uppsrc/plugin/Eigen/unsupported/test/NumericalDiff.cpp b/uppsrc/plugin/Eigen/unsupported/test/NumericalDiff.cpp new file mode 100644 index 000000000..27d888056 --- /dev/null +++ b/uppsrc/plugin/Eigen/unsupported/test/NumericalDiff.cpp @@ -0,0 +1,114 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2009 Thomas Capricelli + +#include + +#include "main.h" +#include + +// Generic functor +template +struct Functor +{ + typedef _Scalar Scalar; + enum { + InputsAtCompileTime = NX, + ValuesAtCompileTime = NY + }; + typedef Matrix InputType; + typedef Matrix ValueType; + typedef Matrix JacobianType; + + int m_inputs, m_values; + + Functor() : m_inputs(InputsAtCompileTime), m_values(ValuesAtCompileTime) {} + Functor(int inputs, int values) : m_inputs(inputs), m_values(values) {} + + int inputs() const { return m_inputs; } + int values() const { return m_values; } + +}; + +struct my_functor : Functor +{ + my_functor(void): Functor(3,15) {} + int operator()(const VectorXd &x, VectorXd &fvec) const + { + double tmp1, tmp2, tmp3; + double y[15] = {1.4e-1, 1.8e-1, 2.2e-1, 2.5e-1, 2.9e-1, 3.2e-1, 3.5e-1, + 3.9e-1, 3.7e-1, 5.8e-1, 7.3e-1, 9.6e-1, 1.34, 2.1, 4.39}; + + for (int i = 0; i < values(); i++) + { + tmp1 = i+1; + tmp2 = 16 - i - 1; + tmp3 = (i>=8)? tmp2 : tmp1; + fvec[i] = y[i] - (x[0] + tmp1/(x[1]*tmp2 + x[2]*tmp3)); + } + return 0; + } + + int actual_df(const VectorXd &x, MatrixXd &fjac) const + { + double tmp1, tmp2, tmp3, tmp4; + for (int i = 0; i < values(); i++) + { + tmp1 = i+1; + tmp2 = 16 - i - 1; + tmp3 = (i>=8)? tmp2 : tmp1; + tmp4 = (x[1]*tmp2 + x[2]*tmp3); tmp4 = tmp4*tmp4; + fjac(i,0) = -1; + fjac(i,1) = tmp1*tmp2/tmp4; + fjac(i,2) = tmp1*tmp3/tmp4; + } + return 0; + } +}; + +void test_forward() +{ + VectorXd x(3); + MatrixXd jac(15,3); + MatrixXd actual_jac(15,3); + my_functor functor; + + x << 0.082, 1.13, 2.35; + + // real one + functor.actual_df(x, actual_jac); +// std::cout << actual_jac << std::endl << std::endl; + + // using NumericalDiff + NumericalDiff numDiff(functor); + numDiff.df(x, jac); +// std::cout << jac << std::endl; + + VERIFY_IS_APPROX(jac, actual_jac); +} + +void test_central() +{ + VectorXd x(3); + MatrixXd jac(15,3); + MatrixXd actual_jac(15,3); + my_functor functor; + + x << 0.082, 1.13, 2.35; + + // real one + functor.actual_df(x, actual_jac); + + // using NumericalDiff + NumericalDiff numDiff(functor); + numDiff.df(x, jac); + + VERIFY_IS_APPROX(jac, actual_jac); +} + +void test_NumericalDiff() +{ + CALL_SUBTEST(test_forward()); + CALL_SUBTEST(test_central()); +} diff --git a/uppsrc/plugin/Eigen/unsupported/test/alignedvector3.cpp b/uppsrc/plugin/Eigen/unsupported/test/alignedvector3.cpp new file mode 100644 index 000000000..fc2bc2135 --- /dev/null +++ b/uppsrc/plugin/Eigen/unsupported/test/alignedvector3.cpp @@ -0,0 +1,59 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2009 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "main.h" +#include + +template +void alignedvector3() +{ + Scalar s1 = internal::random(); + Scalar s2 = internal::random(); + typedef Matrix RefType; + typedef Matrix Mat33; + typedef AlignedVector3 FastType; + RefType r1(RefType::Random()), r2(RefType::Random()), r3(RefType::Random()), + r4(RefType::Random()), r5(RefType::Random()), r6(RefType::Random()); + FastType f1(r1), f2(r2), f3(r3), f4(r4), f5(r5), f6(r6); + Mat33 m1(Mat33::Random()); + + VERIFY_IS_APPROX(f1,r1); + VERIFY_IS_APPROX(f4,r4); + + VERIFY_IS_APPROX(f4+f1,r4+r1); + VERIFY_IS_APPROX(f4-f1,r4-r1); + VERIFY_IS_APPROX(f4+f1-f2,r4+r1-r2); + VERIFY_IS_APPROX(f4+=f3,r4+=r3); + VERIFY_IS_APPROX(f4-=f5,r4-=r5); + VERIFY_IS_APPROX(f4-=f5+f1,r4-=r5+r1); + VERIFY_IS_APPROX(f5+f1-s1*f2,r5+r1-s1*r2); + VERIFY_IS_APPROX(f5+f1/s2-s1*f2,r5+r1/s2-s1*r2); + + VERIFY_IS_APPROX(m1*f4,m1*r4); + VERIFY_IS_APPROX(f4.transpose()*m1,r4.transpose()*m1); + + VERIFY_IS_APPROX(f2.dot(f3),r2.dot(r3)); + VERIFY_IS_APPROX(f2.cross(f3),r2.cross(r3)); + VERIFY_IS_APPROX(f2.norm(),r2.norm()); + + VERIFY_IS_APPROX(f2.normalized(),r2.normalized()); + + VERIFY_IS_APPROX((f2+f1).normalized(),(r2+r1).normalized()); + + f2.normalize(); + r2.normalize(); + VERIFY_IS_APPROX(f2,r2); +} + +void test_alignedvector3() +{ + for(int i = 0; i < g_repeat; i++) { + CALL_SUBTEST( alignedvector3() ); + } +} diff --git a/uppsrc/plugin/Eigen/unsupported/test/autodiff.cpp b/uppsrc/plugin/Eigen/unsupported/test/autodiff.cpp new file mode 100644 index 000000000..087e7c542 --- /dev/null +++ b/uppsrc/plugin/Eigen/unsupported/test/autodiff.cpp @@ -0,0 +1,173 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2009 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "main.h" +#include + +template +EIGEN_DONT_INLINE Scalar foo(const Scalar& x, const Scalar& y) +{ + using namespace std; +// return x+std::sin(y); + EIGEN_ASM_COMMENT("mybegin"); + return static_cast(x*2 - pow(x,2) + 2*sqrt(y*y) - 4 * sin(x) + 2 * cos(y) - exp(-0.5*x*x)); + //return x+2*y*x;//x*2 -std::pow(x,2);//(2*y/x);// - y*2; + EIGEN_ASM_COMMENT("myend"); +} + +template +EIGEN_DONT_INLINE typename Vector::Scalar foo(const Vector& p) +{ + typedef typename Vector::Scalar Scalar; + return (p-Vector(Scalar(-1),Scalar(1.))).norm() + (p.array() * p.array()).sum() + p.dot(p); +} + +template +struct TestFunc1 +{ + typedef _Scalar Scalar; + enum { + InputsAtCompileTime = NX, + ValuesAtCompileTime = NY + }; + typedef Matrix InputType; + typedef Matrix ValueType; + typedef Matrix JacobianType; + + int m_inputs, m_values; + + TestFunc1() : m_inputs(InputsAtCompileTime), m_values(ValuesAtCompileTime) {} + TestFunc1(int inputs, int values) : m_inputs(inputs), m_values(values) {} + + int inputs() const { return m_inputs; } + int values() const { return m_values; } + + template + void operator() (const Matrix& x, Matrix* _v) const + { + Matrix& v = *_v; + + v[0] = 2 * x[0] * x[0] + x[0] * x[1]; + v[1] = 3 * x[1] * x[0] + 0.5 * x[1] * x[1]; + if(inputs()>2) + { + v[0] += 0.5 * x[2]; + v[1] += x[2]; + } + if(values()>2) + { + v[2] = 3 * x[1] * x[0] * x[0]; + } + if (inputs()>2 && values()>2) + v[2] *= x[2]; + } + + void operator() (const InputType& x, ValueType* v, JacobianType* _j) const + { + (*this)(x, v); + + if(_j) + { + JacobianType& j = *_j; + + j(0,0) = 4 * x[0] + x[1]; + j(1,0) = 3 * x[1]; + + j(0,1) = x[0]; + j(1,1) = 3 * x[0] + 2 * 0.5 * x[1]; + + if (inputs()>2) + { + j(0,2) = 0.5; + j(1,2) = 1; + } + if(values()>2) + { + j(2,0) = 3 * x[1] * 2 * x[0]; + j(2,1) = 3 * x[0] * x[0]; + } + if (inputs()>2 && values()>2) + { + j(2,0) *= x[2]; + j(2,1) *= x[2]; + + j(2,2) = 3 * x[1] * x[0] * x[0]; + j(2,2) = 3 * x[1] * x[0] * x[0]; + } + } + } +}; + +template void forward_jacobian(const Func& f) +{ + typename Func::InputType x = Func::InputType::Random(f.inputs()); + typename Func::ValueType y(f.values()), yref(f.values()); + typename Func::JacobianType j(f.values(),f.inputs()), jref(f.values(),f.inputs()); + + jref.setZero(); + yref.setZero(); + f(x,&yref,&jref); +// std::cerr << y.transpose() << "\n\n";; +// std::cerr << j << "\n\n";; + + j.setZero(); + y.setZero(); + AutoDiffJacobian autoj(f); + autoj(x, &y, &j); +// std::cerr << y.transpose() << "\n\n";; +// std::cerr << j << "\n\n";; + + VERIFY_IS_APPROX(y, yref); + VERIFY_IS_APPROX(j, jref); +} + + +// TODO also check actual derivatives! +void test_autodiff_scalar() +{ + Vector2f p = Vector2f::Random(); + typedef AutoDiffScalar AD; + AD ax(p.x(),Vector2f::UnitX()); + AD ay(p.y(),Vector2f::UnitY()); + AD res = foo(ax,ay); + VERIFY_IS_APPROX(res.value(), foo(p.x(),p.y())); +} + +// TODO also check actual derivatives! +void test_autodiff_vector() +{ + Vector2f p = Vector2f::Random(); + typedef AutoDiffScalar AD; + typedef Matrix VectorAD; + VectorAD ap = p.cast(); + ap.x().derivatives() = Vector2f::UnitX(); + ap.y().derivatives() = Vector2f::UnitY(); + + AD res = foo(ap); + VERIFY_IS_APPROX(res.value(), foo(p)); +} + +void test_autodiff_jacobian() +{ + CALL_SUBTEST(( forward_jacobian(TestFunc1()) )); + CALL_SUBTEST(( forward_jacobian(TestFunc1()) )); + CALL_SUBTEST(( forward_jacobian(TestFunc1()) )); + CALL_SUBTEST(( forward_jacobian(TestFunc1()) )); + CALL_SUBTEST(( forward_jacobian(TestFunc1(3,3)) )); +} + +void test_autodiff() +{ + for(int i = 0; i < g_repeat; i++) { + CALL_SUBTEST_1( test_autodiff_scalar() ); + CALL_SUBTEST_2( test_autodiff_vector() ); + CALL_SUBTEST_3( test_autodiff_jacobian() ); + } +} + diff --git a/uppsrc/plugin/Eigen/unsupported/test/bdcsvd.cpp b/uppsrc/plugin/Eigen/unsupported/test/bdcsvd.cpp new file mode 100644 index 000000000..115a649b0 --- /dev/null +++ b/uppsrc/plugin/Eigen/unsupported/test/bdcsvd.cpp @@ -0,0 +1,213 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2013 Gauthier Brun +// Copyright (C) 2013 Nicolas Carre +// Copyright (C) 2013 Jean Ceccato +// Copyright (C) 2013 Pierre Zoppitelli +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/ + +#include "svd_common.h" +#include +#include + +// check if "svd" is the good image of "m" +template +void bdcsvd_check_full(const MatrixType& m, const BDCSVD& svd) +{ + svd_check_full< MatrixType, BDCSVD< MatrixType > >(m, svd); +} + +// Compare to a reference value +template +void bdcsvd_compare_to_full(const MatrixType& m, + unsigned int computationOptions, + const BDCSVD& referenceSvd) +{ + svd_compare_to_full< MatrixType, BDCSVD< MatrixType > >(m, computationOptions, referenceSvd); +} // end bdcsvd_compare_to_full + + +template +void bdcsvd_solve(const MatrixType& m, unsigned int computationOptions) +{ + svd_solve< MatrixType, BDCSVD< MatrixType > >(m, computationOptions); +} // end template bdcsvd_solve + + +// test the computations options +template +void bdcsvd_test_all_computation_options(const MatrixType& m) +{ + BDCSVD fullSvd(m, ComputeFullU|ComputeFullV); + svd_test_computation_options_1< MatrixType, BDCSVD< MatrixType > >(m, fullSvd); + svd_test_computation_options_2< MatrixType, BDCSVD< MatrixType > >(m, fullSvd); +} // end bdcsvd_test_all_computation_options + + +// Call a test with all the computations options +template +void bdcsvd(const MatrixType& a = MatrixType(), bool pickrandom = true) +{ + MatrixType m = pickrandom ? MatrixType::Random(a.rows(), a.cols()) : a; + bdcsvd_test_all_computation_options(m); +} // end template bdcsvd + + +// verify assert +template +void bdcsvd_verify_assert(const MatrixType& m) +{ + svd_verify_assert< MatrixType, BDCSVD< MatrixType > >(m); +}// end template bdcsvd_verify_assert + + +// test weird values +template +void bdcsvd_inf_nan() +{ + svd_inf_nan< MatrixType, BDCSVD< MatrixType > >(); +}// end template bdcsvd_inf_nan + + + +void bdcsvd_preallocate() +{ + svd_preallocate< BDCSVD< MatrixXf > >(); +} // end bdcsvd_preallocate + + +// compare the Singular values returned with Jacobi and Bdc +template +void compare_bdc_jacobi(const MatrixType& a = MatrixType(), unsigned int computationOptions = 0) +{ + std::cout << "debut compare" << std::endl; + MatrixType m = MatrixType::Random(a.rows(), a.cols()); + BDCSVD bdc_svd(m); + JacobiSVD jacobi_svd(m); + VERIFY_IS_APPROX(bdc_svd.singularValues(), jacobi_svd.singularValues()); + if(computationOptions & ComputeFullU) + VERIFY_IS_APPROX(bdc_svd.matrixU(), jacobi_svd.matrixU()); + if(computationOptions & ComputeThinU) + VERIFY_IS_APPROX(bdc_svd.matrixU(), jacobi_svd.matrixU()); + if(computationOptions & ComputeFullV) + VERIFY_IS_APPROX(bdc_svd.matrixV(), jacobi_svd.matrixV()); + if(computationOptions & ComputeThinV) + VERIFY_IS_APPROX(bdc_svd.matrixV(), jacobi_svd.matrixV()); + std::cout << "fin compare" << std::endl; +} // end template compare_bdc_jacobi + + +// call the tests +void test_bdcsvd() +{ + // test of Dynamic defined Matrix (42, 42) of float + CALL_SUBTEST_11(( bdcsvd_verify_assert > + (Matrix(42,42)) )); + CALL_SUBTEST_11(( compare_bdc_jacobi > + (Matrix(42,42), 0) )); + CALL_SUBTEST_11(( bdcsvd > + (Matrix(42,42)) )); + + // test of Dynamic defined Matrix (50, 50) of double + CALL_SUBTEST_13(( bdcsvd_verify_assert > + (Matrix(50,50)) )); + CALL_SUBTEST_13(( compare_bdc_jacobi > + (Matrix(50,50), 0) )); + CALL_SUBTEST_13(( bdcsvd > + (Matrix(50, 50)) )); + + // test of Dynamic defined Matrix (22, 22) of complex double + CALL_SUBTEST_14(( bdcsvd_verify_assert,Dynamic,Dynamic> > + (Matrix,Dynamic,Dynamic>(22,22)) )); + CALL_SUBTEST_14(( compare_bdc_jacobi,Dynamic,Dynamic> > + (Matrix, Dynamic, Dynamic> (22,22), 0) )); + CALL_SUBTEST_14(( bdcsvd,Dynamic,Dynamic> > + (Matrix,Dynamic,Dynamic>(22, 22)) )); + + // test of Dynamic defined Matrix (10, 10) of int + //CALL_SUBTEST_15(( bdcsvd_verify_assert > + // (Matrix(10,10)) )); + //CALL_SUBTEST_15(( compare_bdc_jacobi > + // (Matrix(10,10), 0) )); + //CALL_SUBTEST_15(( bdcsvd > + // (Matrix(10, 10)) )); + + + // test of Dynamic defined Matrix (8, 6) of double + + CALL_SUBTEST_16(( bdcsvd_verify_assert > + (Matrix(8,6)) )); + CALL_SUBTEST_16(( compare_bdc_jacobi > + (Matrix(8, 6), 0) )); + CALL_SUBTEST_16(( bdcsvd > + (Matrix(8, 6)) )); + + + + // test of Dynamic defined Matrix (36, 12) of float + CALL_SUBTEST_17(( compare_bdc_jacobi > + (Matrix(36, 12), 0) )); + CALL_SUBTEST_17(( bdcsvd > + (Matrix(36, 12)) )); + + // test of Dynamic defined Matrix (5, 8) of double + CALL_SUBTEST_18(( compare_bdc_jacobi > + (Matrix(5, 8), 0) )); + CALL_SUBTEST_18(( bdcsvd > + (Matrix(5, 8)) )); + + + // non regression tests + CALL_SUBTEST_3(( bdcsvd_verify_assert(Matrix3f()) )); + CALL_SUBTEST_4(( bdcsvd_verify_assert(Matrix4d()) )); + CALL_SUBTEST_7(( bdcsvd_verify_assert(MatrixXf(10,12)) )); + CALL_SUBTEST_8(( bdcsvd_verify_assert(MatrixXcd(7,5)) )); + + // SUBTESTS 1 and 2 on specifics matrix + for(int i = 0; i < g_repeat; i++) { + Matrix2cd m; + m << 0, 1, + 0, 1; + CALL_SUBTEST_1(( bdcsvd(m, false) )); + m << 1, 0, + 1, 0; + CALL_SUBTEST_1(( bdcsvd(m, false) )); + + Matrix2d n; + n << 0, 0, + 0, 0; + CALL_SUBTEST_2(( bdcsvd(n, false) )); + n << 0, 0, + 0, 1; + CALL_SUBTEST_2(( bdcsvd(n, false) )); + + // Statics matrix don't work with BDSVD yet + // bdc algo on a random 3x3 float matrix + // CALL_SUBTEST_3(( bdcsvd() )); + // bdc algo on a random 4x4 double matrix + // CALL_SUBTEST_4(( bdcsvd() )); + // bdc algo on a random 3x5 float matrix + // CALL_SUBTEST_5(( bdcsvd >() )); + + int r = internal::random(1, 30), + c = internal::random(1, 30); + CALL_SUBTEST_7(( bdcsvd(MatrixXf(r,c)) )); + CALL_SUBTEST_8(( bdcsvd(MatrixXcd(r,c)) )); + (void) r; + (void) c; + + // Test on inf/nan matrix + CALL_SUBTEST_7( bdcsvd_inf_nan() ); + } + + CALL_SUBTEST_7(( bdcsvd(MatrixXf(internal::random(EIGEN_TEST_MAX_SIZE/4, EIGEN_TEST_MAX_SIZE/2), internal::random(EIGEN_TEST_MAX_SIZE/4, EIGEN_TEST_MAX_SIZE/2))) )); + CALL_SUBTEST_8(( bdcsvd(MatrixXcd(internal::random(EIGEN_TEST_MAX_SIZE/4, EIGEN_TEST_MAX_SIZE/3), internal::random(EIGEN_TEST_MAX_SIZE/4, EIGEN_TEST_MAX_SIZE/3))) )); + + // Test problem size constructors + CALL_SUBTEST_7( BDCSVD(10,10) ); + +} // end test_bdcsvd diff --git a/uppsrc/plugin/Eigen/unsupported/test/dgmres.cpp b/uppsrc/plugin/Eigen/unsupported/test/dgmres.cpp new file mode 100644 index 000000000..2b11807c8 --- /dev/null +++ b/uppsrc/plugin/Eigen/unsupported/test/dgmres.cpp @@ -0,0 +1,31 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2011 Gael Guennebaud +// Copyright (C) 2012 desire Nuentsa + +template void test_dgmres_T() +{ + DGMRES, DiagonalPreconditioner > dgmres_colmajor_diag; + DGMRES, IdentityPreconditioner > dgmres_colmajor_I; + DGMRES, IncompleteLUT > dgmres_colmajor_ilut; + //GMRES, SSORPreconditioner > dgmres_colmajor_ssor; + + CALL_SUBTEST( check_sparse_square_solving(dgmres_colmajor_diag) ); +// CALL_SUBTEST( check_sparse_square_solving(dgmres_colmajor_I) ); + CALL_SUBTEST( check_sparse_square_solving(dgmres_colmajor_ilut) ); + //CALL_SUBTEST( check_sparse_square_solving(dgmres_colmajor_ssor) ); +} + +void test_dgmres() +{ + CALL_SUBTEST_1(test_dgmres_T()); + CALL_SUBTEST_2(test_dgmres_T >()); +} diff --git a/uppsrc/plugin/Eigen/unsupported/test/forward_adolc.cpp b/uppsrc/plugin/Eigen/unsupported/test/forward_adolc.cpp new file mode 100644 index 000000000..d4baafe62 --- /dev/null +++ b/uppsrc/plugin/Eigen/unsupported/test/forward_adolc.cpp @@ -0,0 +1,143 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "main.h" +#include + +#define NUMBER_DIRECTIONS 16 +#include + +int adtl::ADOLC_numDir; + +template +EIGEN_DONT_INLINE typename Vector::Scalar foo(const Vector& p) +{ + typedef typename Vector::Scalar Scalar; + return (p-Vector(Scalar(-1),Scalar(1.))).norm() + (p.array().sqrt().abs() * p.array().sin()).sum() + p.dot(p); +} + +template +struct TestFunc1 +{ + typedef _Scalar Scalar; + enum { + InputsAtCompileTime = NX, + ValuesAtCompileTime = NY + }; + typedef Matrix InputType; + typedef Matrix ValueType; + typedef Matrix JacobianType; + + int m_inputs, m_values; + + TestFunc1() : m_inputs(InputsAtCompileTime), m_values(ValuesAtCompileTime) {} + TestFunc1(int inputs, int values) : m_inputs(inputs), m_values(values) {} + + int inputs() const { return m_inputs; } + int values() const { return m_values; } + + template + void operator() (const Matrix& x, Matrix* _v) const + { + Matrix& v = *_v; + + v[0] = 2 * x[0] * x[0] + x[0] * x[1]; + v[1] = 3 * x[1] * x[0] + 0.5 * x[1] * x[1]; + if(inputs()>2) + { + v[0] += 0.5 * x[2]; + v[1] += x[2]; + } + if(values()>2) + { + v[2] = 3 * x[1] * x[0] * x[0]; + } + if (inputs()>2 && values()>2) + v[2] *= x[2]; + } + + void operator() (const InputType& x, ValueType* v, JacobianType* _j) const + { + (*this)(x, v); + + if(_j) + { + JacobianType& j = *_j; + + j(0,0) = 4 * x[0] + x[1]; + j(1,0) = 3 * x[1]; + + j(0,1) = x[0]; + j(1,1) = 3 * x[0] + 2 * 0.5 * x[1]; + + if (inputs()>2) + { + j(0,2) = 0.5; + j(1,2) = 1; + } + if(values()>2) + { + j(2,0) = 3 * x[1] * 2 * x[0]; + j(2,1) = 3 * x[0] * x[0]; + } + if (inputs()>2 && values()>2) + { + j(2,0) *= x[2]; + j(2,1) *= x[2]; + + j(2,2) = 3 * x[1] * x[0] * x[0]; + j(2,2) = 3 * x[1] * x[0] * x[0]; + } + } + } +}; + +template void adolc_forward_jacobian(const Func& f) +{ + typename Func::InputType x = Func::InputType::Random(f.inputs()); + typename Func::ValueType y(f.values()), yref(f.values()); + typename Func::JacobianType j(f.values(),f.inputs()), jref(f.values(),f.inputs()); + + jref.setZero(); + yref.setZero(); + f(x,&yref,&jref); +// std::cerr << y.transpose() << "\n\n";; +// std::cerr << j << "\n\n";; + + j.setZero(); + y.setZero(); + AdolcForwardJacobian autoj(f); + autoj(x, &y, &j); +// std::cerr << y.transpose() << "\n\n";; +// std::cerr << j << "\n\n";; + + VERIFY_IS_APPROX(y, yref); + VERIFY_IS_APPROX(j, jref); +} + +void test_forward_adolc() +{ + adtl::ADOLC_numDir = NUMBER_DIRECTIONS; + + for(int i = 0; i < g_repeat; i++) { + CALL_SUBTEST(( adolc_forward_jacobian(TestFunc1()) )); + CALL_SUBTEST(( adolc_forward_jacobian(TestFunc1()) )); + CALL_SUBTEST(( adolc_forward_jacobian(TestFunc1()) )); + CALL_SUBTEST(( adolc_forward_jacobian(TestFunc1()) )); + CALL_SUBTEST(( adolc_forward_jacobian(TestFunc1(3,3)) )); + } + + { + // simple instanciation tests + Matrix x; + foo(x); + Matrix A(4,4);; + A.selfadjointView().eigenvalues(); + } +} diff --git a/uppsrc/plugin/Eigen/unsupported/test/gmres.cpp b/uppsrc/plugin/Eigen/unsupported/test/gmres.cpp new file mode 100644 index 000000000..f2969116b --- /dev/null +++ b/uppsrc/plugin/Eigen/unsupported/test/gmres.cpp @@ -0,0 +1,31 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2011 Gael Guennebaud +// Copyright (C) 2012 Kolja Brix +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "../../test/sparse_solver.h" +#include + +template void test_gmres_T() +{ + GMRES, DiagonalPreconditioner > gmres_colmajor_diag; + GMRES, IdentityPreconditioner > gmres_colmajor_I; + GMRES, IncompleteLUT > gmres_colmajor_ilut; + //GMRES, SSORPreconditioner > gmres_colmajor_ssor; + + CALL_SUBTEST( check_sparse_square_solving(gmres_colmajor_diag) ); +// CALL_SUBTEST( check_sparse_square_solving(gmres_colmajor_I) ); + CALL_SUBTEST( check_sparse_square_solving(gmres_colmajor_ilut) ); + //CALL_SUBTEST( check_sparse_square_solving(gmres_colmajor_ssor) ); +} + +void test_gmres() +{ + CALL_SUBTEST_1(test_gmres_T()); + CALL_SUBTEST_2(test_gmres_T >()); +} diff --git a/uppsrc/plugin/Eigen/unsupported/test/jacobisvd.cpp b/uppsrc/plugin/Eigen/unsupported/test/jacobisvd.cpp new file mode 100644 index 000000000..b4e884eee --- /dev/null +++ b/uppsrc/plugin/Eigen/unsupported/test/jacobisvd.cpp @@ -0,0 +1,198 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008 Gael Guennebaud +// Copyright (C) 2009 Benoit Jacob +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "svd_common.h" + +template +void jacobisvd_check_full(const MatrixType& m, const JacobiSVD& svd) +{ + svd_check_full >(m, svd); +} + +template +void jacobisvd_compare_to_full(const MatrixType& m, + unsigned int computationOptions, + const JacobiSVD& referenceSvd) +{ + svd_compare_to_full >(m, computationOptions, referenceSvd); +} + + +template +void jacobisvd_solve(const MatrixType& m, unsigned int computationOptions) +{ + svd_solve< MatrixType, JacobiSVD< MatrixType, QRPreconditioner > >(m, computationOptions); +} + + + +template +void jacobisvd_test_all_computation_options(const MatrixType& m) +{ + + if (QRPreconditioner == NoQRPreconditioner && m.rows() != m.cols()) + return; + + JacobiSVD< MatrixType, QRPreconditioner > fullSvd(m, ComputeFullU|ComputeFullV); + svd_test_computation_options_1< MatrixType, JacobiSVD< MatrixType, QRPreconditioner > >(m, fullSvd); + + if(QRPreconditioner == FullPivHouseholderQRPreconditioner) + return; + svd_test_computation_options_2< MatrixType, JacobiSVD< MatrixType, QRPreconditioner > >(m, fullSvd); + +} + +template +void jacobisvd(const MatrixType& a = MatrixType(), bool pickrandom = true) +{ + MatrixType m = pickrandom ? MatrixType::Random(a.rows(), a.cols()) : a; + + jacobisvd_test_all_computation_options(m); + jacobisvd_test_all_computation_options(m); + jacobisvd_test_all_computation_options(m); + jacobisvd_test_all_computation_options(m); +} + + +template +void jacobisvd_verify_assert(const MatrixType& m) +{ + + svd_verify_assert >(m); + + typedef typename MatrixType::Index Index; + Index rows = m.rows(); + Index cols = m.cols(); + + enum { + RowsAtCompileTime = MatrixType::RowsAtCompileTime, + ColsAtCompileTime = MatrixType::ColsAtCompileTime + }; + + MatrixType a = MatrixType::Zero(rows, cols); + a.setZero(); + + if (ColsAtCompileTime == Dynamic) + { + JacobiSVD svd_fullqr; + VERIFY_RAISES_ASSERT(svd_fullqr.compute(a, ComputeFullU|ComputeThinV)) + VERIFY_RAISES_ASSERT(svd_fullqr.compute(a, ComputeThinU|ComputeThinV)) + VERIFY_RAISES_ASSERT(svd_fullqr.compute(a, ComputeThinU|ComputeFullV)) + } +} + +template +void jacobisvd_method() +{ + enum { Size = MatrixType::RowsAtCompileTime }; + typedef typename MatrixType::RealScalar RealScalar; + typedef Matrix RealVecType; + MatrixType m = MatrixType::Identity(); + VERIFY_IS_APPROX(m.jacobiSvd().singularValues(), RealVecType::Ones()); + VERIFY_RAISES_ASSERT(m.jacobiSvd().matrixU()); + VERIFY_RAISES_ASSERT(m.jacobiSvd().matrixV()); + VERIFY_IS_APPROX(m.jacobiSvd(ComputeFullU|ComputeFullV).solve(m), m); +} + + + +template +void jacobisvd_inf_nan() +{ + svd_inf_nan >(); +} + + +// Regression test for bug 286: JacobiSVD loops indefinitely with some +// matrices containing denormal numbers. +void jacobisvd_bug286() +{ +#if defined __INTEL_COMPILER +// shut up warning #239: floating point underflow +#pragma warning push +#pragma warning disable 239 +#endif + Matrix2d M; + M << -7.90884e-313, -4.94e-324, + 0, 5.60844e-313; +#if defined __INTEL_COMPILER +#pragma warning pop +#endif + JacobiSVD svd; + svd.compute(M); // just check we don't loop indefinitely +} + + +void jacobisvd_preallocate() +{ + svd_preallocate< JacobiSVD >(); +} + +void test_jacobisvd() +{ + CALL_SUBTEST_11(( jacobisvd > + (Matrix(16, 6)) )); + + CALL_SUBTEST_3(( jacobisvd_verify_assert(Matrix3f()) )); + CALL_SUBTEST_4(( jacobisvd_verify_assert(Matrix4d()) )); + CALL_SUBTEST_7(( jacobisvd_verify_assert(MatrixXf(10,12)) )); + CALL_SUBTEST_8(( jacobisvd_verify_assert(MatrixXcd(7,5)) )); + + for(int i = 0; i < g_repeat; i++) { + Matrix2cd m; + m << 0, 1, + 0, 1; + CALL_SUBTEST_1(( jacobisvd(m, false) )); + m << 1, 0, + 1, 0; + CALL_SUBTEST_1(( jacobisvd(m, false) )); + + Matrix2d n; + n << 0, 0, + 0, 0; + CALL_SUBTEST_2(( jacobisvd(n, false) )); + n << 0, 0, + 0, 1; + CALL_SUBTEST_2(( jacobisvd(n, false) )); + + CALL_SUBTEST_3(( jacobisvd() )); + CALL_SUBTEST_4(( jacobisvd() )); + CALL_SUBTEST_5(( jacobisvd >() )); + CALL_SUBTEST_6(( jacobisvd >(Matrix(10,2)) )); + + int r = internal::random(1, 30), + c = internal::random(1, 30); + CALL_SUBTEST_7(( jacobisvd(MatrixXf(r,c)) )); + CALL_SUBTEST_8(( jacobisvd(MatrixXcd(r,c)) )); + (void) r; + (void) c; + + // Test on inf/nan matrix + CALL_SUBTEST_7( jacobisvd_inf_nan() ); + } + + CALL_SUBTEST_7(( jacobisvd(MatrixXf(internal::random(EIGEN_TEST_MAX_SIZE/4, EIGEN_TEST_MAX_SIZE/2), internal::random(EIGEN_TEST_MAX_SIZE/4, EIGEN_TEST_MAX_SIZE/2))) )); + CALL_SUBTEST_8(( jacobisvd(MatrixXcd(internal::random(EIGEN_TEST_MAX_SIZE/4, EIGEN_TEST_MAX_SIZE/3), internal::random(EIGEN_TEST_MAX_SIZE/4, EIGEN_TEST_MAX_SIZE/3))) )); + + + // test matrixbase method + CALL_SUBTEST_1(( jacobisvd_method() )); + CALL_SUBTEST_3(( jacobisvd_method() )); + + + // Test problem size constructors + CALL_SUBTEST_7( JacobiSVD(10,10) ); + + // Check that preallocation avoids subsequent mallocs + CALL_SUBTEST_9( jacobisvd_preallocate() ); + + // Regression check for bug 286 + CALL_SUBTEST_2( jacobisvd_bug286() ); +} diff --git a/uppsrc/plugin/Eigen/unsupported/test/kronecker_product.cpp b/uppsrc/plugin/Eigen/unsupported/test/kronecker_product.cpp new file mode 100644 index 000000000..8ddc6ec28 --- /dev/null +++ b/uppsrc/plugin/Eigen/unsupported/test/kronecker_product.cpp @@ -0,0 +1,181 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2011 Kolja Brix +// Copyright (C) 2011 Andreas Platen +// Copyright (C) 2012 Chen-Pang He +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + + +#include "sparse.h" +#include +#include + + +template +void check_dimension(const MatrixType& ab, const int rows, const int cols) +{ + VERIFY_IS_EQUAL(ab.rows(), rows); + VERIFY_IS_EQUAL(ab.cols(), cols); +} + + +template +void check_kronecker_product(const MatrixType& ab) +{ + VERIFY_IS_EQUAL(ab.rows(), 6); + VERIFY_IS_EQUAL(ab.cols(), 6); + VERIFY_IS_EQUAL(ab.nonZeros(), 36); + VERIFY_IS_APPROX(ab.coeff(0,0), -0.4017367630386106); + VERIFY_IS_APPROX(ab.coeff(0,1), 0.1056863433932735); + VERIFY_IS_APPROX(ab.coeff(0,2), -0.7255206194554212); + VERIFY_IS_APPROX(ab.coeff(0,3), 0.1908653336744706); + VERIFY_IS_APPROX(ab.coeff(0,4), 0.350864567234111); + VERIFY_IS_APPROX(ab.coeff(0,5), -0.0923032108308013); + VERIFY_IS_APPROX(ab.coeff(1,0), 0.415417514804677); + VERIFY_IS_APPROX(ab.coeff(1,1), -0.2369227701722048); + VERIFY_IS_APPROX(ab.coeff(1,2), 0.7502275131458511); + VERIFY_IS_APPROX(ab.coeff(1,3), -0.4278731019742696); + VERIFY_IS_APPROX(ab.coeff(1,4), -0.3628129162264507); + VERIFY_IS_APPROX(ab.coeff(1,5), 0.2069210808481275); + VERIFY_IS_APPROX(ab.coeff(2,0), 0.05465890160863986); + VERIFY_IS_APPROX(ab.coeff(2,1), -0.2634092511419858); + VERIFY_IS_APPROX(ab.coeff(2,2), 0.09871180285793758); + VERIFY_IS_APPROX(ab.coeff(2,3), -0.4757066334017702); + VERIFY_IS_APPROX(ab.coeff(2,4), -0.04773740823058334); + VERIFY_IS_APPROX(ab.coeff(2,5), 0.2300535609645254); + VERIFY_IS_APPROX(ab.coeff(3,0), -0.8172945853260133); + VERIFY_IS_APPROX(ab.coeff(3,1), 0.2150086428359221); + VERIFY_IS_APPROX(ab.coeff(3,2), 0.5825113847292743); + VERIFY_IS_APPROX(ab.coeff(3,3), -0.1532433770097174); + VERIFY_IS_APPROX(ab.coeff(3,4), -0.329383387282399); + VERIFY_IS_APPROX(ab.coeff(3,5), 0.08665207912033064); + VERIFY_IS_APPROX(ab.coeff(4,0), 0.8451267514863225); + VERIFY_IS_APPROX(ab.coeff(4,1), -0.481996458918977); + VERIFY_IS_APPROX(ab.coeff(4,2), -0.6023482390791535); + VERIFY_IS_APPROX(ab.coeff(4,3), 0.3435339347164565); + VERIFY_IS_APPROX(ab.coeff(4,4), 0.3406002157428891); + VERIFY_IS_APPROX(ab.coeff(4,5), -0.1942526344200915); + VERIFY_IS_APPROX(ab.coeff(5,0), 0.1111982482925399); + VERIFY_IS_APPROX(ab.coeff(5,1), -0.5358806424754169); + VERIFY_IS_APPROX(ab.coeff(5,2), -0.07925446559335647); + VERIFY_IS_APPROX(ab.coeff(5,3), 0.3819388757769038); + VERIFY_IS_APPROX(ab.coeff(5,4), 0.04481475387219876); + VERIFY_IS_APPROX(ab.coeff(5,5), -0.2159688616158057); +} + + +template +void check_sparse_kronecker_product(const MatrixType& ab) +{ + VERIFY_IS_EQUAL(ab.rows(), 12); + VERIFY_IS_EQUAL(ab.cols(), 10); + VERIFY_IS_EQUAL(ab.nonZeros(), 3*2); + VERIFY_IS_APPROX(ab.coeff(3,0), -0.04); + VERIFY_IS_APPROX(ab.coeff(5,1), 0.05); + VERIFY_IS_APPROX(ab.coeff(0,6), -0.08); + VERIFY_IS_APPROX(ab.coeff(2,7), 0.10); + VERIFY_IS_APPROX(ab.coeff(6,8), 0.12); + VERIFY_IS_APPROX(ab.coeff(8,9), -0.15); +} + + +void test_kronecker_product() +{ + // DM = dense matrix; SM = sparse matrix + + Matrix DM_a; + SparseMatrix SM_a(2,3); + SM_a.insert(0,0) = DM_a.coeffRef(0,0) = -0.4461540300782201; + SM_a.insert(0,1) = DM_a.coeffRef(0,1) = -0.8057364375283049; + SM_a.insert(0,2) = DM_a.coeffRef(0,2) = 0.3896572459516341; + SM_a.insert(1,0) = DM_a.coeffRef(1,0) = -0.9076572187376921; + SM_a.insert(1,1) = DM_a.coeffRef(1,1) = 0.6469156566545853; + SM_a.insert(1,2) = DM_a.coeffRef(1,2) = -0.3658010398782789; + + MatrixXd DM_b(3,2); + SparseMatrix SM_b(3,2); + SM_b.insert(0,0) = DM_b.coeffRef(0,0) = 0.9004440976767099; + SM_b.insert(0,1) = DM_b.coeffRef(0,1) = -0.2368830858139832; + SM_b.insert(1,0) = DM_b.coeffRef(1,0) = -0.9311078389941825; + SM_b.insert(1,1) = DM_b.coeffRef(1,1) = 0.5310335762980047; + SM_b.insert(2,0) = DM_b.coeffRef(2,0) = -0.1225112806872035; + SM_b.insert(2,1) = DM_b.coeffRef(2,1) = 0.5903998022741264; + + SparseMatrix SM_row_a(SM_a), SM_row_b(SM_b); + + // test kroneckerProduct(DM_block,DM,DM_fixedSize) + Matrix DM_fix_ab = kroneckerProduct(DM_a.topLeftCorner<2,3>(),DM_b); + + CALL_SUBTEST(check_kronecker_product(DM_fix_ab)); + + for(int i=0;i(2,5) = kroneckerProduct(DM_a,DM_b); + CALL_SUBTEST(check_kronecker_product(DM_block_ab.block<6,6>(2,5))); + + // test kroneckerProduct(DM,DM,DM) + MatrixXd DM_ab = kroneckerProduct(DM_a,DM_b); + CALL_SUBTEST(check_kronecker_product(DM_ab)); + + // test kroneckerProduct(SM,DM,SM) + SparseMatrix SM_ab = kroneckerProduct(SM_a,DM_b); + CALL_SUBTEST(check_kronecker_product(SM_ab)); + SparseMatrix SM_ab2 = kroneckerProduct(SM_a,DM_b); + CALL_SUBTEST(check_kronecker_product(SM_ab2)); + + // test kroneckerProduct(DM,SM,SM) + SM_ab.setZero(); + SM_ab.insert(0,0)=37.0; + SM_ab = kroneckerProduct(DM_a,SM_b); + CALL_SUBTEST(check_kronecker_product(SM_ab)); + SM_ab2.setZero(); + SM_ab2.insert(0,0)=37.0; + SM_ab2 = kroneckerProduct(DM_a,SM_b); + CALL_SUBTEST(check_kronecker_product(SM_ab2)); + + // test kroneckerProduct(SM,SM,SM) + SM_ab.resize(2,33); + SM_ab.insert(0,0)=37.0; + SM_ab = kroneckerProduct(SM_a,SM_b); + CALL_SUBTEST(check_kronecker_product(SM_ab)); + SM_ab2.resize(5,11); + SM_ab2.insert(0,0)=37.0; + SM_ab2 = kroneckerProduct(SM_a,SM_b); + CALL_SUBTEST(check_kronecker_product(SM_ab2)); + + // test kroneckerProduct(SM,SM,SM) with sparse pattern + SM_a.resize(4,5); + SM_b.resize(3,2); + SM_a.resizeNonZeros(0); + SM_b.resizeNonZeros(0); + SM_a.insert(1,0) = -0.1; + SM_a.insert(0,3) = -0.2; + SM_a.insert(2,4) = 0.3; + SM_a.finalize(); + + SM_b.insert(0,0) = 0.4; + SM_b.insert(2,1) = -0.5; + SM_b.finalize(); + SM_ab.resize(1,1); + SM_ab.insert(0,0)=37.0; + SM_ab = kroneckerProduct(SM_a,SM_b); + CALL_SUBTEST(check_sparse_kronecker_product(SM_ab)); + + // test dimension of result of kroneckerProduct(DM,DM,DM) + MatrixXd DM_a2(2,1); + MatrixXd DM_b2(5,4); + MatrixXd DM_ab2 = kroneckerProduct(DM_a2,DM_b2); + CALL_SUBTEST(check_dimension(DM_ab2,2*5,1*4)); + DM_a2.resize(10,9); + DM_b2.resize(4,8); + DM_ab2 = kroneckerProduct(DM_a2,DM_b2); + CALL_SUBTEST(check_dimension(DM_ab2,10*4,9*8)); +} diff --git a/uppsrc/plugin/Eigen/unsupported/test/levenberg_marquardt.cpp b/uppsrc/plugin/Eigen/unsupported/test/levenberg_marquardt.cpp new file mode 100644 index 000000000..04464727d --- /dev/null +++ b/uppsrc/plugin/Eigen/unsupported/test/levenberg_marquardt.cpp @@ -0,0 +1,1448 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2009 Thomas Capricelli +// Copyright (C) 2012 desire Nuentsa + +#include "main.h" +#include + +// This disables some useless Warnings on MSVC. +// It is intended to be done for this test only. +#include + +using std::sqrt; + +struct lmder_functor : DenseFunctor +{ + lmder_functor(void): DenseFunctor(3,15) {} + int operator()(const VectorXd &x, VectorXd &fvec) const + { + double tmp1, tmp2, tmp3; + static const double y[15] = {1.4e-1, 1.8e-1, 2.2e-1, 2.5e-1, 2.9e-1, 3.2e-1, 3.5e-1, + 3.9e-1, 3.7e-1, 5.8e-1, 7.3e-1, 9.6e-1, 1.34, 2.1, 4.39}; + + for (int i = 0; i < values(); i++) + { + tmp1 = i+1; + tmp2 = 16 - i - 1; + tmp3 = (i>=8)? tmp2 : tmp1; + fvec[i] = y[i] - (x[0] + tmp1/(x[1]*tmp2 + x[2]*tmp3)); + } + return 0; + } + + int df(const VectorXd &x, MatrixXd &fjac) const + { + double tmp1, tmp2, tmp3, tmp4; + for (int i = 0; i < values(); i++) + { + tmp1 = i+1; + tmp2 = 16 - i - 1; + tmp3 = (i>=8)? tmp2 : tmp1; + tmp4 = (x[1]*tmp2 + x[2]*tmp3); tmp4 = tmp4*tmp4; + fjac(i,0) = -1; + fjac(i,1) = tmp1*tmp2/tmp4; + fjac(i,2) = tmp1*tmp3/tmp4; + } + return 0; + } +}; + +void testLmder1() +{ + int n=3, info; + + VectorXd x; + + /* the following starting values provide a rough fit. */ + x.setConstant(n, 1.); + + // do the computation + lmder_functor functor; + LevenbergMarquardt lm(functor); + info = lm.lmder1(x); + + // check return value + VERIFY_IS_EQUAL(info, 1); + VERIFY_IS_EQUAL(lm.nfev(), 6); + VERIFY_IS_EQUAL(lm.njev(), 5); + + // check norm + VERIFY_IS_APPROX(lm.fvec().blueNorm(), 0.09063596); + + // check x + VectorXd x_ref(n); + x_ref << 0.08241058, 1.133037, 2.343695; + VERIFY_IS_APPROX(x, x_ref); +} + +void testLmder() +{ + const int m=15, n=3; + int info; + double fnorm, covfac; + VectorXd x; + + /* the following starting values provide a rough fit. */ + x.setConstant(n, 1.); + + // do the computation + lmder_functor functor; + LevenbergMarquardt lm(functor); + info = lm.minimize(x); + + // check return values + VERIFY_IS_EQUAL(info, 1); + VERIFY_IS_EQUAL(lm.nfev(), 6); + VERIFY_IS_EQUAL(lm.njev(), 5); + + // check norm + fnorm = lm.fvec().blueNorm(); + VERIFY_IS_APPROX(fnorm, 0.09063596); + + // check x + VectorXd x_ref(n); + x_ref << 0.08241058, 1.133037, 2.343695; + VERIFY_IS_APPROX(x, x_ref); + + // check covariance + covfac = fnorm*fnorm/(m-n); + internal::covar(lm.matrixR(), lm.permutation().indices()); // TODO : move this as a function of lm + + MatrixXd cov_ref(n,n); + cov_ref << + 0.0001531202, 0.002869941, -0.002656662, + 0.002869941, 0.09480935, -0.09098995, + -0.002656662, -0.09098995, 0.08778727; + +// std::cout << fjac*covfac << std::endl; + + MatrixXd cov; + cov = covfac*lm.matrixR().topLeftCorner(); + VERIFY_IS_APPROX( cov, cov_ref); + // TODO: why isn't this allowed ? : + // VERIFY_IS_APPROX( covfac*fjac.topLeftCorner() , cov_ref); +} + +struct lmdif_functor : DenseFunctor +{ + lmdif_functor(void) : DenseFunctor(3,15) {} + int operator()(const VectorXd &x, VectorXd &fvec) const + { + int i; + double tmp1,tmp2,tmp3; + static const double y[15]={1.4e-1,1.8e-1,2.2e-1,2.5e-1,2.9e-1,3.2e-1,3.5e-1,3.9e-1, + 3.7e-1,5.8e-1,7.3e-1,9.6e-1,1.34e0,2.1e0,4.39e0}; + + assert(x.size()==3); + assert(fvec.size()==15); + for (i=0; i<15; i++) + { + tmp1 = i+1; + tmp2 = 15 - i; + tmp3 = tmp1; + + if (i >= 8) tmp3 = tmp2; + fvec[i] = y[i] - (x[0] + tmp1/(x[1]*tmp2 + x[2]*tmp3)); + } + return 0; + } +}; + +void testLmdif1() +{ + const int n=3; + int info; + + VectorXd x(n), fvec(15); + + /* the following starting values provide a rough fit. */ + x.setConstant(n, 1.); + + // do the computation + lmdif_functor functor; + DenseIndex nfev; + info = LevenbergMarquardt::lmdif1(functor, x, &nfev); + + // check return value + VERIFY_IS_EQUAL(info, 1); +// VERIFY_IS_EQUAL(nfev, 26); + + // check norm + functor(x, fvec); + VERIFY_IS_APPROX(fvec.blueNorm(), 0.09063596); + + // check x + VectorXd x_ref(n); + x_ref << 0.0824106, 1.1330366, 2.3436947; + VERIFY_IS_APPROX(x, x_ref); + +} + +void testLmdif() +{ + const int m=15, n=3; + int info; + double fnorm, covfac; + VectorXd x(n); + + /* the following starting values provide a rough fit. */ + x.setConstant(n, 1.); + + // do the computation + lmdif_functor functor; + NumericalDiff numDiff(functor); + LevenbergMarquardt > lm(numDiff); + info = lm.minimize(x); + + // check return values + VERIFY_IS_EQUAL(info, 1); +// VERIFY_IS_EQUAL(lm.nfev(), 26); + + // check norm + fnorm = lm.fvec().blueNorm(); + VERIFY_IS_APPROX(fnorm, 0.09063596); + + // check x + VectorXd x_ref(n); + x_ref << 0.08241058, 1.133037, 2.343695; + VERIFY_IS_APPROX(x, x_ref); + + // check covariance + covfac = fnorm*fnorm/(m-n); + internal::covar(lm.matrixR(), lm.permutation().indices()); // TODO : move this as a function of lm + + MatrixXd cov_ref(n,n); + cov_ref << + 0.0001531202, 0.002869942, -0.002656662, + 0.002869942, 0.09480937, -0.09098997, + -0.002656662, -0.09098997, 0.08778729; + +// std::cout << fjac*covfac << std::endl; + + MatrixXd cov; + cov = covfac*lm.matrixR().topLeftCorner(); + VERIFY_IS_APPROX( cov, cov_ref); + // TODO: why isn't this allowed ? : + // VERIFY_IS_APPROX( covfac*fjac.topLeftCorner() , cov_ref); +} + +struct chwirut2_functor : DenseFunctor +{ + chwirut2_functor(void) : DenseFunctor(3,54) {} + static const double m_x[54]; + static const double m_y[54]; + int operator()(const VectorXd &b, VectorXd &fvec) + { + int i; + + assert(b.size()==3); + assert(fvec.size()==54); + for(i=0; i<54; i++) { + double x = m_x[i]; + fvec[i] = exp(-b[0]*x)/(b[1]+b[2]*x) - m_y[i]; + } + return 0; + } + int df(const VectorXd &b, MatrixXd &fjac) + { + assert(b.size()==3); + assert(fjac.rows()==54); + assert(fjac.cols()==3); + for(int i=0; i<54; i++) { + double x = m_x[i]; + double factor = 1./(b[1]+b[2]*x); + double e = exp(-b[0]*x); + fjac(i,0) = -x*e*factor; + fjac(i,1) = -e*factor*factor; + fjac(i,2) = -x*e*factor*factor; + } + return 0; + } +}; +const double chwirut2_functor::m_x[54] = { 0.500E0, 1.000E0, 1.750E0, 3.750E0, 5.750E0, 0.875E0, 2.250E0, 3.250E0, 5.250E0, 0.750E0, 1.750E0, 2.750E0, 4.750E0, 0.625E0, 1.250E0, 2.250E0, 4.250E0, .500E0, 3.000E0, .750E0, 3.000E0, 1.500E0, 6.000E0, 3.000E0, 6.000E0, 1.500E0, 3.000E0, .500E0, 2.000E0, 4.000E0, .750E0, 2.000E0, 5.000E0, .750E0, 2.250E0, 3.750E0, 5.750E0, 3.000E0, .750E0, 2.500E0, 4.000E0, .750E0, 2.500E0, 4.000E0, .750E0, 2.500E0, 4.000E0, .500E0, 6.000E0, 3.000E0, .500E0, 2.750E0, .500E0, 1.750E0}; +const double chwirut2_functor::m_y[54] = { 92.9000E0 ,57.1000E0 ,31.0500E0 ,11.5875E0 ,8.0250E0 ,63.6000E0 ,21.4000E0 ,14.2500E0 ,8.4750E0 ,63.8000E0 ,26.8000E0 ,16.4625E0 ,7.1250E0 ,67.3000E0 ,41.0000E0 ,21.1500E0 ,8.1750E0 ,81.5000E0 ,13.1200E0 ,59.9000E0 ,14.6200E0 ,32.9000E0 ,5.4400E0 ,12.5600E0 ,5.4400E0 ,32.0000E0 ,13.9500E0 ,75.8000E0 ,20.0000E0 ,10.4200E0 ,59.5000E0 ,21.6700E0 ,8.5500E0 ,62.0000E0 ,20.2000E0 ,7.7600E0 ,3.7500E0 ,11.8100E0 ,54.7000E0 ,23.7000E0 ,11.5500E0 ,61.3000E0 ,17.7000E0 ,8.7400E0 ,59.2000E0 ,16.3000E0 ,8.6200E0 ,81.0000E0 ,4.8700E0 ,14.6200E0 ,81.7000E0 ,17.1700E0 ,81.3000E0 ,28.9000E0 }; + +// http://www.itl.nist.gov/div898/strd/nls/data/chwirut2.shtml +void testNistChwirut2(void) +{ + const int n=3; + int info; + + VectorXd x(n); + + /* + * First try + */ + x<< 0.1, 0.01, 0.02; + // do the computation + chwirut2_functor functor; + LevenbergMarquardt lm(functor); + info = lm.minimize(x); + + // check return value + VERIFY_IS_EQUAL(info, 1); +// VERIFY_IS_EQUAL(lm.nfev(), 10); + VERIFY_IS_EQUAL(lm.njev(), 8); + // check norm^2 + VERIFY_IS_APPROX(lm.fvec().squaredNorm(), 5.1304802941E+02); + // check x + VERIFY_IS_APPROX(x[0], 1.6657666537E-01); + VERIFY_IS_APPROX(x[1], 5.1653291286E-03); + VERIFY_IS_APPROX(x[2], 1.2150007096E-02); + + /* + * Second try + */ + x<< 0.15, 0.008, 0.010; + // do the computation + lm.resetParameters(); + lm.setFtol(1.E6*NumTraits::epsilon()); + lm.setXtol(1.E6*NumTraits::epsilon()); + info = lm.minimize(x); + + // check return value + VERIFY_IS_EQUAL(info, 1); +// VERIFY_IS_EQUAL(lm.nfev(), 7); + VERIFY_IS_EQUAL(lm.njev(), 6); + // check norm^2 + VERIFY_IS_APPROX(lm.fvec().squaredNorm(), 5.1304802941E+02); + // check x + VERIFY_IS_APPROX(x[0], 1.6657666537E-01); + VERIFY_IS_APPROX(x[1], 5.1653291286E-03); + VERIFY_IS_APPROX(x[2], 1.2150007096E-02); +} + + +struct misra1a_functor : DenseFunctor +{ + misra1a_functor(void) : DenseFunctor(2,14) {} + static const double m_x[14]; + static const double m_y[14]; + int operator()(const VectorXd &b, VectorXd &fvec) + { + assert(b.size()==2); + assert(fvec.size()==14); + for(int i=0; i<14; i++) { + fvec[i] = b[0]*(1.-exp(-b[1]*m_x[i])) - m_y[i] ; + } + return 0; + } + int df(const VectorXd &b, MatrixXd &fjac) + { + assert(b.size()==2); + assert(fjac.rows()==14); + assert(fjac.cols()==2); + for(int i=0; i<14; i++) { + fjac(i,0) = (1.-exp(-b[1]*m_x[i])); + fjac(i,1) = (b[0]*m_x[i]*exp(-b[1]*m_x[i])); + } + return 0; + } +}; +const double misra1a_functor::m_x[14] = { 77.6E0, 114.9E0, 141.1E0, 190.8E0, 239.9E0, 289.0E0, 332.8E0, 378.4E0, 434.8E0, 477.3E0, 536.8E0, 593.1E0, 689.1E0, 760.0E0}; +const double misra1a_functor::m_y[14] = { 10.07E0, 14.73E0, 17.94E0, 23.93E0, 29.61E0, 35.18E0, 40.02E0, 44.82E0, 50.76E0, 55.05E0, 61.01E0, 66.40E0, 75.47E0, 81.78E0}; + +// http://www.itl.nist.gov/div898/strd/nls/data/misra1a.shtml +void testNistMisra1a(void) +{ + const int n=2; + int info; + + VectorXd x(n); + + /* + * First try + */ + x<< 500., 0.0001; + // do the computation + misra1a_functor functor; + LevenbergMarquardt lm(functor); + info = lm.minimize(x); + + // check return value + VERIFY_IS_EQUAL(info, 1); + VERIFY_IS_EQUAL(lm.nfev(), 19); + VERIFY_IS_EQUAL(lm.njev(), 15); + // check norm^2 + VERIFY_IS_APPROX(lm.fvec().squaredNorm(), 1.2455138894E-01); + // check x + VERIFY_IS_APPROX(x[0], 2.3894212918E+02); + VERIFY_IS_APPROX(x[1], 5.5015643181E-04); + + /* + * Second try + */ + x<< 250., 0.0005; + // do the computation + info = lm.minimize(x); + + // check return value + VERIFY_IS_EQUAL(info, 1); + VERIFY_IS_EQUAL(lm.nfev(), 5); + VERIFY_IS_EQUAL(lm.njev(), 4); + // check norm^2 + VERIFY_IS_APPROX(lm.fvec().squaredNorm(), 1.2455138894E-01); + // check x + VERIFY_IS_APPROX(x[0], 2.3894212918E+02); + VERIFY_IS_APPROX(x[1], 5.5015643181E-04); +} + +struct hahn1_functor : DenseFunctor +{ + hahn1_functor(void) : DenseFunctor(7,236) {} + static const double m_x[236]; + int operator()(const VectorXd &b, VectorXd &fvec) + { + static const double m_y[236] = { .591E0 , 1.547E0 , 2.902E0 , 2.894E0 , 4.703E0 , 6.307E0 , 7.03E0 , 7.898E0 , 9.470E0 , 9.484E0 , 10.072E0 , 10.163E0 , 11.615E0 , 12.005E0 , 12.478E0 , 12.982E0 , 12.970E0 , 13.926E0 , 14.452E0 , 14.404E0 , 15.190E0 , 15.550E0 , 15.528E0 , 15.499E0 , 16.131E0 , 16.438E0 , 16.387E0 , 16.549E0 , 16.872E0 , 16.830E0 , 16.926E0 , 16.907E0 , 16.966E0 , 17.060E0 , 17.122E0 , 17.311E0 , 17.355E0 , 17.668E0 , 17.767E0 , 17.803E0 , 17.765E0 , 17.768E0 , 17.736E0 , 17.858E0 , 17.877E0 , 17.912E0 , 18.046E0 , 18.085E0 , 18.291E0 , 18.357E0 , 18.426E0 , 18.584E0 , 18.610E0 , 18.870E0 , 18.795E0 , 19.111E0 , .367E0 , .796E0 , 0.892E0 , 1.903E0 , 2.150E0 , 3.697E0 , 5.870E0 , 6.421E0 , 7.422E0 , 9.944E0 , 11.023E0 , 11.87E0 , 12.786E0 , 14.067E0 , 13.974E0 , 14.462E0 , 14.464E0 , 15.381E0 , 15.483E0 , 15.59E0 , 16.075E0 , 16.347E0 , 16.181E0 , 16.915E0 , 17.003E0 , 16.978E0 , 17.756E0 , 17.808E0 , 17.868E0 , 18.481E0 , 18.486E0 , 19.090E0 , 16.062E0 , 16.337E0 , 16.345E0 , + 16.388E0 , 17.159E0 , 17.116E0 , 17.164E0 , 17.123E0 , 17.979E0 , 17.974E0 , 18.007E0 , 17.993E0 , 18.523E0 , 18.669E0 , 18.617E0 , 19.371E0 , 19.330E0 , 0.080E0 , 0.248E0 , 1.089E0 , 1.418E0 , 2.278E0 , 3.624E0 , 4.574E0 , 5.556E0 , 7.267E0 , 7.695E0 , 9.136E0 , 9.959E0 , 9.957E0 , 11.600E0 , 13.138E0 , 13.564E0 , 13.871E0 , 13.994E0 , 14.947E0 , 15.473E0 , 15.379E0 , 15.455E0 , 15.908E0 , 16.114E0 , 17.071E0 , 17.135E0 , 17.282E0 , 17.368E0 , 17.483E0 , 17.764E0 , 18.185E0 , 18.271E0 , 18.236E0 , 18.237E0 , 18.523E0 , 18.627E0 , 18.665E0 , 19.086E0 , 0.214E0 , 0.943E0 , 1.429E0 , 2.241E0 , 2.951E0 , 3.782E0 , 4.757E0 , 5.602E0 , 7.169E0 , 8.920E0 , 10.055E0 , 12.035E0 , 12.861E0 , 13.436E0 , 14.167E0 , 14.755E0 , 15.168E0 , 15.651E0 , 15.746E0 , 16.216E0 , 16.445E0 , 16.965E0 , 17.121E0 , 17.206E0 , 17.250E0 , 17.339E0 , 17.793E0 , 18.123E0 , 18.49E0 , 18.566E0 , 18.645E0 , 18.706E0 , 18.924E0 , 19.1E0 , 0.375E0 , 0.471E0 , 1.504E0 , 2.204E0 , 2.813E0 , 4.765E0 , 9.835E0 , 10.040E0 , 11.946E0 , +12.596E0 , +13.303E0 , 13.922E0 , 14.440E0 , 14.951E0 , 15.627E0 , 15.639E0 , 15.814E0 , 16.315E0 , 16.334E0 , 16.430E0 , 16.423E0 , 17.024E0 , 17.009E0 , 17.165E0 , 17.134E0 , 17.349E0 , 17.576E0 , 17.848E0 , 18.090E0 , 18.276E0 , 18.404E0 , 18.519E0 , 19.133E0 , 19.074E0 , 19.239E0 , 19.280E0 , 19.101E0 , 19.398E0 , 19.252E0 , 19.89E0 , 20.007E0 , 19.929E0 , 19.268E0 , 19.324E0 , 20.049E0 , 20.107E0 , 20.062E0 , 20.065E0 , 19.286E0 , 19.972E0 , 20.088E0 , 20.743E0 , 20.83E0 , 20.935E0 , 21.035E0 , 20.93E0 , 21.074E0 , 21.085E0 , 20.935E0 }; + + // int called=0; printf("call hahn1_functor with iflag=%d, called=%d\n", iflag, called); if (iflag==1) called++; + + assert(b.size()==7); + assert(fvec.size()==236); + for(int i=0; i<236; i++) { + double x=m_x[i], xx=x*x, xxx=xx*x; + fvec[i] = (b[0]+b[1]*x+b[2]*xx+b[3]*xxx) / (1.+b[4]*x+b[5]*xx+b[6]*xxx) - m_y[i]; + } + return 0; + } + + int df(const VectorXd &b, MatrixXd &fjac) + { + assert(b.size()==7); + assert(fjac.rows()==236); + assert(fjac.cols()==7); + for(int i=0; i<236; i++) { + double x=m_x[i], xx=x*x, xxx=xx*x; + double fact = 1./(1.+b[4]*x+b[5]*xx+b[6]*xxx); + fjac(i,0) = 1.*fact; + fjac(i,1) = x*fact; + fjac(i,2) = xx*fact; + fjac(i,3) = xxx*fact; + fact = - (b[0]+b[1]*x+b[2]*xx+b[3]*xxx) * fact * fact; + fjac(i,4) = x*fact; + fjac(i,5) = xx*fact; + fjac(i,6) = xxx*fact; + } + return 0; + } +}; +const double hahn1_functor::m_x[236] = { 24.41E0 , 34.82E0 , 44.09E0 , 45.07E0 , 54.98E0 , 65.51E0 , 70.53E0 , 75.70E0 , 89.57E0 , 91.14E0 , 96.40E0 , 97.19E0 , 114.26E0 , 120.25E0 , 127.08E0 , 133.55E0 , 133.61E0 , 158.67E0 , 172.74E0 , 171.31E0 , 202.14E0 , 220.55E0 , 221.05E0 , 221.39E0 , 250.99E0 , 268.99E0 , 271.80E0 , 271.97E0 , 321.31E0 , 321.69E0 , 330.14E0 , 333.03E0 , 333.47E0 , 340.77E0 , 345.65E0 , 373.11E0 , 373.79E0 , 411.82E0 , 419.51E0 , 421.59E0 , 422.02E0 , 422.47E0 , 422.61E0 , 441.75E0 , 447.41E0 , 448.7E0 , 472.89E0 , 476.69E0 , 522.47E0 , 522.62E0 , 524.43E0 , 546.75E0 , 549.53E0 , 575.29E0 , 576.00E0 , 625.55E0 , 20.15E0 , 28.78E0 , 29.57E0 , 37.41E0 , 39.12E0 , 50.24E0 , 61.38E0 , 66.25E0 , 73.42E0 , 95.52E0 , 107.32E0 , 122.04E0 , 134.03E0 , 163.19E0 , 163.48E0 , 175.70E0 , 179.86E0 , 211.27E0 , 217.78E0 , 219.14E0 , 262.52E0 , 268.01E0 , 268.62E0 , 336.25E0 , 337.23E0 , 339.33E0 , 427.38E0 , 428.58E0 , 432.68E0 , 528.99E0 , 531.08E0 , 628.34E0 , 253.24E0 , 273.13E0 , 273.66E0 , +282.10E0 , 346.62E0 , 347.19E0 , 348.78E0 , 351.18E0 , 450.10E0 , 450.35E0 , 451.92E0 , 455.56E0 , 552.22E0 , 553.56E0 , 555.74E0 , 652.59E0 , 656.20E0 , 14.13E0 , 20.41E0 , 31.30E0 , 33.84E0 , 39.70E0 , 48.83E0 , 54.50E0 , 60.41E0 , 72.77E0 , 75.25E0 , 86.84E0 , 94.88E0 , 96.40E0 , 117.37E0 , 139.08E0 , 147.73E0 , 158.63E0 , 161.84E0 , 192.11E0 , 206.76E0 , 209.07E0 , 213.32E0 , 226.44E0 , 237.12E0 , 330.90E0 , 358.72E0 , 370.77E0 , 372.72E0 , 396.24E0 , 416.59E0 , 484.02E0 , 495.47E0 , 514.78E0 , 515.65E0 , 519.47E0 , 544.47E0 , 560.11E0 , 620.77E0 , 18.97E0 , 28.93E0 , 33.91E0 , 40.03E0 , 44.66E0 , 49.87E0 , 55.16E0 , 60.90E0 , 72.08E0 , 85.15E0 , 97.06E0 , 119.63E0 , 133.27E0 , 143.84E0 , 161.91E0 , 180.67E0 , 198.44E0 , 226.86E0 , 229.65E0 , 258.27E0 , 273.77E0 , 339.15E0 , 350.13E0 , 362.75E0 , 371.03E0 , 393.32E0 , 448.53E0 , 473.78E0 , 511.12E0 , 524.70E0 , 548.75E0 , 551.64E0 , 574.02E0 , 623.86E0 , 21.46E0 , 24.33E0 , 33.43E0 , 39.22E0 , 44.18E0 , 55.02E0 , 94.33E0 , 96.44E0 , 118.82E0 , 128.48E0 , +141.94E0 , 156.92E0 , 171.65E0 , 190.00E0 , 223.26E0 , 223.88E0 , 231.50E0 , 265.05E0 , 269.44E0 , 271.78E0 , 273.46E0 , 334.61E0 , 339.79E0 , 349.52E0 , 358.18E0 , 377.98E0 , 394.77E0 , 429.66E0 , 468.22E0 , 487.27E0 , 519.54E0 , 523.03E0 , 612.99E0 , 638.59E0 , 641.36E0 , 622.05E0 , 631.50E0 , 663.97E0 , 646.9E0 , 748.29E0 , 749.21E0 , 750.14E0 , 647.04E0 , 646.89E0 , 746.9E0 , 748.43E0 , 747.35E0 , 749.27E0 , 647.61E0 , 747.78E0 , 750.51E0 , 851.37E0 , 845.97E0 , 847.54E0 , 849.93E0 , 851.61E0 , 849.75E0 , 850.98E0 , 848.23E0}; + +// http://www.itl.nist.gov/div898/strd/nls/data/hahn1.shtml +void testNistHahn1(void) +{ + const int n=7; + int info; + + VectorXd x(n); + + /* + * First try + */ + x<< 10., -1., .05, -.00001, -.05, .001, -.000001; + // do the computation + hahn1_functor functor; + LevenbergMarquardt lm(functor); + info = lm.minimize(x); + + // check return value + VERIFY_IS_EQUAL(info, 1); + VERIFY_IS_EQUAL(lm.nfev(), 11); + VERIFY_IS_EQUAL(lm.njev(), 10); + // check norm^2 + VERIFY_IS_APPROX(lm.fvec().squaredNorm(), 1.5324382854E+00); + // check x + VERIFY_IS_APPROX(x[0], 1.0776351733E+00); + VERIFY_IS_APPROX(x[1],-1.2269296921E-01); + VERIFY_IS_APPROX(x[2], 4.0863750610E-03); + VERIFY_IS_APPROX(x[3],-1.426264e-06); // shoulde be : -1.4262662514E-06 + VERIFY_IS_APPROX(x[4],-5.7609940901E-03); + VERIFY_IS_APPROX(x[5], 2.4053735503E-04); + VERIFY_IS_APPROX(x[6],-1.2314450199E-07); + + /* + * Second try + */ + x<< .1, -.1, .005, -.000001, -.005, .0001, -.0000001; + // do the computation + info = lm.minimize(x); + + // check return value + VERIFY_IS_EQUAL(info, 1); +// VERIFY_IS_EQUAL(lm.nfev(), 11); + VERIFY_IS_EQUAL(lm.njev(), 10); + // check norm^2 + VERIFY_IS_APPROX(lm.fvec().squaredNorm(), 1.5324382854E+00); + // check x + VERIFY_IS_APPROX(x[0], 1.077640); // should be : 1.0776351733E+00 + VERIFY_IS_APPROX(x[1], -0.1226933); // should be : -1.2269296921E-01 + VERIFY_IS_APPROX(x[2], 0.004086383); // should be : 4.0863750610E-03 + VERIFY_IS_APPROX(x[3], -1.426277e-06); // shoulde be : -1.4262662514E-06 + VERIFY_IS_APPROX(x[4],-5.7609940901E-03); + VERIFY_IS_APPROX(x[5], 0.00024053772); // should be : 2.4053735503E-04 + VERIFY_IS_APPROX(x[6], -1.231450e-07); // should be : -1.2314450199E-07 + +} + +struct misra1d_functor : DenseFunctor +{ + misra1d_functor(void) : DenseFunctor(2,14) {} + static const double x[14]; + static const double y[14]; + int operator()(const VectorXd &b, VectorXd &fvec) + { + assert(b.size()==2); + assert(fvec.size()==14); + for(int i=0; i<14; i++) { + fvec[i] = b[0]*b[1]*x[i]/(1.+b[1]*x[i]) - y[i]; + } + return 0; + } + int df(const VectorXd &b, MatrixXd &fjac) + { + assert(b.size()==2); + assert(fjac.rows()==14); + assert(fjac.cols()==2); + for(int i=0; i<14; i++) { + double den = 1.+b[1]*x[i]; + fjac(i,0) = b[1]*x[i] / den; + fjac(i,1) = b[0]*x[i]*(den-b[1]*x[i])/den/den; + } + return 0; + } +}; +const double misra1d_functor::x[14] = { 77.6E0, 114.9E0, 141.1E0, 190.8E0, 239.9E0, 289.0E0, 332.8E0, 378.4E0, 434.8E0, 477.3E0, 536.8E0, 593.1E0, 689.1E0, 760.0E0}; +const double misra1d_functor::y[14] = { 10.07E0, 14.73E0, 17.94E0, 23.93E0, 29.61E0, 35.18E0, 40.02E0, 44.82E0, 50.76E0, 55.05E0, 61.01E0, 66.40E0, 75.47E0, 81.78E0}; + +// http://www.itl.nist.gov/div898/strd/nls/data/misra1d.shtml +void testNistMisra1d(void) +{ + const int n=2; + int info; + + VectorXd x(n); + + /* + * First try + */ + x<< 500., 0.0001; + // do the computation + misra1d_functor functor; + LevenbergMarquardt lm(functor); + info = lm.minimize(x); + + // check return value + VERIFY_IS_EQUAL(info, 1); + VERIFY_IS_EQUAL(lm.nfev(), 9); + VERIFY_IS_EQUAL(lm.njev(), 7); + // check norm^2 + VERIFY_IS_APPROX(lm.fvec().squaredNorm(), 5.6419295283E-02); + // check x + VERIFY_IS_APPROX(x[0], 4.3736970754E+02); + VERIFY_IS_APPROX(x[1], 3.0227324449E-04); + + /* + * Second try + */ + x<< 450., 0.0003; + // do the computation + info = lm.minimize(x); + + // check return value + VERIFY_IS_EQUAL(info, 1); + VERIFY_IS_EQUAL(lm.nfev(), 4); + VERIFY_IS_EQUAL(lm.njev(), 3); + // check norm^2 + VERIFY_IS_APPROX(lm.fvec().squaredNorm(), 5.6419295283E-02); + // check x + VERIFY_IS_APPROX(x[0], 4.3736970754E+02); + VERIFY_IS_APPROX(x[1], 3.0227324449E-04); +} + + +struct lanczos1_functor : DenseFunctor +{ + lanczos1_functor(void) : DenseFunctor(6,24) {} + static const double x[24]; + static const double y[24]; + int operator()(const VectorXd &b, VectorXd &fvec) + { + assert(b.size()==6); + assert(fvec.size()==24); + for(int i=0; i<24; i++) + fvec[i] = b[0]*exp(-b[1]*x[i]) + b[2]*exp(-b[3]*x[i]) + b[4]*exp(-b[5]*x[i]) - y[i]; + return 0; + } + int df(const VectorXd &b, MatrixXd &fjac) + { + assert(b.size()==6); + assert(fjac.rows()==24); + assert(fjac.cols()==6); + for(int i=0; i<24; i++) { + fjac(i,0) = exp(-b[1]*x[i]); + fjac(i,1) = -b[0]*x[i]*exp(-b[1]*x[i]); + fjac(i,2) = exp(-b[3]*x[i]); + fjac(i,3) = -b[2]*x[i]*exp(-b[3]*x[i]); + fjac(i,4) = exp(-b[5]*x[i]); + fjac(i,5) = -b[4]*x[i]*exp(-b[5]*x[i]); + } + return 0; + } +}; +const double lanczos1_functor::x[24] = { 0.000000000000E+00, 5.000000000000E-02, 1.000000000000E-01, 1.500000000000E-01, 2.000000000000E-01, 2.500000000000E-01, 3.000000000000E-01, 3.500000000000E-01, 4.000000000000E-01, 4.500000000000E-01, 5.000000000000E-01, 5.500000000000E-01, 6.000000000000E-01, 6.500000000000E-01, 7.000000000000E-01, 7.500000000000E-01, 8.000000000000E-01, 8.500000000000E-01, 9.000000000000E-01, 9.500000000000E-01, 1.000000000000E+00, 1.050000000000E+00, 1.100000000000E+00, 1.150000000000E+00 }; +const double lanczos1_functor::y[24] = { 2.513400000000E+00 ,2.044333373291E+00 ,1.668404436564E+00 ,1.366418021208E+00 ,1.123232487372E+00 ,9.268897180037E-01 ,7.679338563728E-01 ,6.388775523106E-01 ,5.337835317402E-01 ,4.479363617347E-01 ,3.775847884350E-01 ,3.197393199326E-01 ,2.720130773746E-01 ,2.324965529032E-01 ,1.996589546065E-01 ,1.722704126914E-01 ,1.493405660168E-01 ,1.300700206922E-01 ,1.138119324644E-01 ,1.000415587559E-01 ,8.833209084540E-02 ,7.833544019350E-02 ,6.976693743449E-02 ,6.239312536719E-02 }; + +// http://www.itl.nist.gov/div898/strd/nls/data/lanczos1.shtml +void testNistLanczos1(void) +{ + const int n=6; + int info; + + VectorXd x(n); + + /* + * First try + */ + x<< 1.2, 0.3, 5.6, 5.5, 6.5, 7.6; + // do the computation + lanczos1_functor functor; + LevenbergMarquardt lm(functor); + info = lm.minimize(x); + + // check return value + VERIFY_IS_EQUAL(info, 2); + VERIFY_IS_EQUAL(lm.nfev(), 79); + VERIFY_IS_EQUAL(lm.njev(), 72); + // check norm^2 +// VERIFY_IS_APPROX(lm.fvec().squaredNorm(), 1.430899764097e-25); // should be 1.4307867721E-25, but nist results are on 128-bit floats + // check x + VERIFY_IS_APPROX(x[0], 9.5100000027E-02); + VERIFY_IS_APPROX(x[1], 1.0000000001E+00); + VERIFY_IS_APPROX(x[2], 8.6070000013E-01); + VERIFY_IS_APPROX(x[3], 3.0000000002E+00); + VERIFY_IS_APPROX(x[4], 1.5575999998E+00); + VERIFY_IS_APPROX(x[5], 5.0000000001E+00); + + /* + * Second try + */ + x<< 0.5, 0.7, 3.6, 4.2, 4., 6.3; + // do the computation + info = lm.minimize(x); + + // check return value + VERIFY_IS_EQUAL(info, 2); + VERIFY_IS_EQUAL(lm.nfev(), 9); + VERIFY_IS_EQUAL(lm.njev(), 8); + // check norm^2 +// VERIFY_IS_APPROX(lm.fvec().squaredNorm(), 1.428595533845e-25); // should be 1.4307867721E-25, but nist results are on 128-bit floats + // check x + VERIFY_IS_APPROX(x[0], 9.5100000027E-02); + VERIFY_IS_APPROX(x[1], 1.0000000001E+00); + VERIFY_IS_APPROX(x[2], 8.6070000013E-01); + VERIFY_IS_APPROX(x[3], 3.0000000002E+00); + VERIFY_IS_APPROX(x[4], 1.5575999998E+00); + VERIFY_IS_APPROX(x[5], 5.0000000001E+00); + +} + +struct rat42_functor : DenseFunctor +{ + rat42_functor(void) : DenseFunctor(3,9) {} + static const double x[9]; + static const double y[9]; + int operator()(const VectorXd &b, VectorXd &fvec) + { + assert(b.size()==3); + assert(fvec.size()==9); + for(int i=0; i<9; i++) { + fvec[i] = b[0] / (1.+exp(b[1]-b[2]*x[i])) - y[i]; + } + return 0; + } + + int df(const VectorXd &b, MatrixXd &fjac) + { + assert(b.size()==3); + assert(fjac.rows()==9); + assert(fjac.cols()==3); + for(int i=0; i<9; i++) { + double e = exp(b[1]-b[2]*x[i]); + fjac(i,0) = 1./(1.+e); + fjac(i,1) = -b[0]*e/(1.+e)/(1.+e); + fjac(i,2) = +b[0]*e*x[i]/(1.+e)/(1.+e); + } + return 0; + } +}; +const double rat42_functor::x[9] = { 9.000E0, 14.000E0, 21.000E0, 28.000E0, 42.000E0, 57.000E0, 63.000E0, 70.000E0, 79.000E0 }; +const double rat42_functor::y[9] = { 8.930E0 ,10.800E0 ,18.590E0 ,22.330E0 ,39.350E0 ,56.110E0 ,61.730E0 ,64.620E0 ,67.080E0 }; + +// http://www.itl.nist.gov/div898/strd/nls/data/ratkowsky2.shtml +void testNistRat42(void) +{ + const int n=3; + int info; + + VectorXd x(n); + + /* + * First try + */ + x<< 100., 1., 0.1; + // do the computation + rat42_functor functor; + LevenbergMarquardt lm(functor); + info = lm.minimize(x); + + // check return value + VERIFY_IS_EQUAL(info, 1); + VERIFY_IS_EQUAL(lm.nfev(), 10); + VERIFY_IS_EQUAL(lm.njev(), 8); + // check norm^2 + VERIFY_IS_APPROX(lm.fvec().squaredNorm(), 8.0565229338E+00); + // check x + VERIFY_IS_APPROX(x[0], 7.2462237576E+01); + VERIFY_IS_APPROX(x[1], 2.6180768402E+00); + VERIFY_IS_APPROX(x[2], 6.7359200066E-02); + + /* + * Second try + */ + x<< 75., 2.5, 0.07; + // do the computation + info = lm.minimize(x); + + // check return value + VERIFY_IS_EQUAL(info, 1); + VERIFY_IS_EQUAL(lm.nfev(), 6); + VERIFY_IS_EQUAL(lm.njev(), 5); + // check norm^2 + VERIFY_IS_APPROX(lm.fvec().squaredNorm(), 8.0565229338E+00); + // check x + VERIFY_IS_APPROX(x[0], 7.2462237576E+01); + VERIFY_IS_APPROX(x[1], 2.6180768402E+00); + VERIFY_IS_APPROX(x[2], 6.7359200066E-02); +} + +struct MGH10_functor : DenseFunctor +{ + MGH10_functor(void) : DenseFunctor(3,16) {} + static const double x[16]; + static const double y[16]; + int operator()(const VectorXd &b, VectorXd &fvec) + { + assert(b.size()==3); + assert(fvec.size()==16); + for(int i=0; i<16; i++) + fvec[i] = b[0] * exp(b[1]/(x[i]+b[2])) - y[i]; + return 0; + } + int df(const VectorXd &b, MatrixXd &fjac) + { + assert(b.size()==3); + assert(fjac.rows()==16); + assert(fjac.cols()==3); + for(int i=0; i<16; i++) { + double factor = 1./(x[i]+b[2]); + double e = exp(b[1]*factor); + fjac(i,0) = e; + fjac(i,1) = b[0]*factor*e; + fjac(i,2) = -b[1]*b[0]*factor*factor*e; + } + return 0; + } +}; +const double MGH10_functor::x[16] = { 5.000000E+01, 5.500000E+01, 6.000000E+01, 6.500000E+01, 7.000000E+01, 7.500000E+01, 8.000000E+01, 8.500000E+01, 9.000000E+01, 9.500000E+01, 1.000000E+02, 1.050000E+02, 1.100000E+02, 1.150000E+02, 1.200000E+02, 1.250000E+02 }; +const double MGH10_functor::y[16] = { 3.478000E+04, 2.861000E+04, 2.365000E+04, 1.963000E+04, 1.637000E+04, 1.372000E+04, 1.154000E+04, 9.744000E+03, 8.261000E+03, 7.030000E+03, 6.005000E+03, 5.147000E+03, 4.427000E+03, 3.820000E+03, 3.307000E+03, 2.872000E+03 }; + +// http://www.itl.nist.gov/div898/strd/nls/data/mgh10.shtml +void testNistMGH10(void) +{ + const int n=3; + int info; + + VectorXd x(n); + + /* + * First try + */ + x<< 2., 400000., 25000.; + // do the computation + MGH10_functor functor; + LevenbergMarquardt lm(functor); + info = lm.minimize(x); + + // check return value + VERIFY_IS_EQUAL(info, 1); + VERIFY_IS_EQUAL(lm.nfev(), 284 ); + VERIFY_IS_EQUAL(lm.njev(), 249 ); + // check norm^2 + VERIFY_IS_APPROX(lm.fvec().squaredNorm(), 8.7945855171E+01); + // check x + VERIFY_IS_APPROX(x[0], 5.6096364710E-03); + VERIFY_IS_APPROX(x[1], 6.1813463463E+03); + VERIFY_IS_APPROX(x[2], 3.4522363462E+02); + + /* + * Second try + */ + x<< 0.02, 4000., 250.; + // do the computation + info = lm.minimize(x); + + // check return value + VERIFY_IS_EQUAL(info, 1); + VERIFY_IS_EQUAL(lm.nfev(), 126); + VERIFY_IS_EQUAL(lm.njev(), 116); + // check norm^2 + VERIFY_IS_APPROX(lm.fvec().squaredNorm(), 8.7945855171E+01); + // check x + VERIFY_IS_APPROX(x[0], 5.6096364710E-03); + VERIFY_IS_APPROX(x[1], 6.1813463463E+03); + VERIFY_IS_APPROX(x[2], 3.4522363462E+02); +} + + +struct BoxBOD_functor : DenseFunctor +{ + BoxBOD_functor(void) : DenseFunctor(2,6) {} + static const double x[6]; + int operator()(const VectorXd &b, VectorXd &fvec) + { + static const double y[6] = { 109., 149., 149., 191., 213., 224. }; + assert(b.size()==2); + assert(fvec.size()==6); + for(int i=0; i<6; i++) + fvec[i] = b[0]*(1.-exp(-b[1]*x[i])) - y[i]; + return 0; + } + int df(const VectorXd &b, MatrixXd &fjac) + { + assert(b.size()==2); + assert(fjac.rows()==6); + assert(fjac.cols()==2); + for(int i=0; i<6; i++) { + double e = exp(-b[1]*x[i]); + fjac(i,0) = 1.-e; + fjac(i,1) = b[0]*x[i]*e; + } + return 0; + } +}; +const double BoxBOD_functor::x[6] = { 1., 2., 3., 5., 7., 10. }; + +// http://www.itl.nist.gov/div898/strd/nls/data/boxbod.shtml +void testNistBoxBOD(void) +{ + const int n=2; + int info; + + VectorXd x(n); + + /* + * First try + */ + x<< 1., 1.; + // do the computation + BoxBOD_functor functor; + LevenbergMarquardt lm(functor); + lm.setFtol(1.E6*NumTraits::epsilon()); + lm.setXtol(1.E6*NumTraits::epsilon()); + lm.setFactor(10); + info = lm.minimize(x); + + // check return value + VERIFY_IS_EQUAL(info, 1); + VERIFY_IS_EQUAL(lm.nfev(), 31); + VERIFY_IS_EQUAL(lm.njev(), 25); + // check norm^2 + VERIFY_IS_APPROX(lm.fvec().squaredNorm(), 1.1680088766E+03); + // check x + VERIFY_IS_APPROX(x[0], 2.1380940889E+02); + VERIFY_IS_APPROX(x[1], 5.4723748542E-01); + + /* + * Second try + */ + x<< 100., 0.75; + // do the computation + lm.resetParameters(); + lm.setFtol(NumTraits::epsilon()); + lm.setXtol( NumTraits::epsilon()); + info = lm.minimize(x); + + // check return value + VERIFY_IS_EQUAL(info, 1); + VERIFY_IS_EQUAL(lm.nfev(), 15 ); + VERIFY_IS_EQUAL(lm.njev(), 14 ); + // check norm^2 + VERIFY_IS_APPROX(lm.fvec().squaredNorm(), 1.1680088766E+03); + // check x + VERIFY_IS_APPROX(x[0], 2.1380940889E+02); + VERIFY_IS_APPROX(x[1], 5.4723748542E-01); +} + +struct MGH17_functor : DenseFunctor +{ + MGH17_functor(void) : DenseFunctor(5,33) {} + static const double x[33]; + static const double y[33]; + int operator()(const VectorXd &b, VectorXd &fvec) + { + assert(b.size()==5); + assert(fvec.size()==33); + for(int i=0; i<33; i++) + fvec[i] = b[0] + b[1]*exp(-b[3]*x[i]) + b[2]*exp(-b[4]*x[i]) - y[i]; + return 0; + } + int df(const VectorXd &b, MatrixXd &fjac) + { + assert(b.size()==5); + assert(fjac.rows()==33); + assert(fjac.cols()==5); + for(int i=0; i<33; i++) { + fjac(i,0) = 1.; + fjac(i,1) = exp(-b[3]*x[i]); + fjac(i,2) = exp(-b[4]*x[i]); + fjac(i,3) = -x[i]*b[1]*exp(-b[3]*x[i]); + fjac(i,4) = -x[i]*b[2]*exp(-b[4]*x[i]); + } + return 0; + } +}; +const double MGH17_functor::x[33] = { 0.000000E+00, 1.000000E+01, 2.000000E+01, 3.000000E+01, 4.000000E+01, 5.000000E+01, 6.000000E+01, 7.000000E+01, 8.000000E+01, 9.000000E+01, 1.000000E+02, 1.100000E+02, 1.200000E+02, 1.300000E+02, 1.400000E+02, 1.500000E+02, 1.600000E+02, 1.700000E+02, 1.800000E+02, 1.900000E+02, 2.000000E+02, 2.100000E+02, 2.200000E+02, 2.300000E+02, 2.400000E+02, 2.500000E+02, 2.600000E+02, 2.700000E+02, 2.800000E+02, 2.900000E+02, 3.000000E+02, 3.100000E+02, 3.200000E+02 }; +const double MGH17_functor::y[33] = { 8.440000E-01, 9.080000E-01, 9.320000E-01, 9.360000E-01, 9.250000E-01, 9.080000E-01, 8.810000E-01, 8.500000E-01, 8.180000E-01, 7.840000E-01, 7.510000E-01, 7.180000E-01, 6.850000E-01, 6.580000E-01, 6.280000E-01, 6.030000E-01, 5.800000E-01, 5.580000E-01, 5.380000E-01, 5.220000E-01, 5.060000E-01, 4.900000E-01, 4.780000E-01, 4.670000E-01, 4.570000E-01, 4.480000E-01, 4.380000E-01, 4.310000E-01, 4.240000E-01, 4.200000E-01, 4.140000E-01, 4.110000E-01, 4.060000E-01 }; + +// http://www.itl.nist.gov/div898/strd/nls/data/mgh17.shtml +void testNistMGH17(void) +{ + const int n=5; + int info; + + VectorXd x(n); + + /* + * First try + */ + x<< 50., 150., -100., 1., 2.; + // do the computation + MGH17_functor functor; + LevenbergMarquardt lm(functor); + lm.setFtol(NumTraits::epsilon()); + lm.setXtol(NumTraits::epsilon()); + lm.setMaxfev(1000); + info = lm.minimize(x); + + // check return value +// VERIFY_IS_EQUAL(info, 2); //FIXME Use (lm.info() == Success) +// VERIFY_IS_EQUAL(lm.nfev(), 602 ); + VERIFY_IS_EQUAL(lm.njev(), 545 ); + // check norm^2 + VERIFY_IS_APPROX(lm.fvec().squaredNorm(), 5.4648946975E-05); + // check x + VERIFY_IS_APPROX(x[0], 3.7541005211E-01); + VERIFY_IS_APPROX(x[1], 1.9358469127E+00); + VERIFY_IS_APPROX(x[2], -1.4646871366E+00); + VERIFY_IS_APPROX(x[3], 1.2867534640E-02); + VERIFY_IS_APPROX(x[4], 2.2122699662E-02); + + /* + * Second try + */ + x<< 0.5 ,1.5 ,-1 ,0.01 ,0.02; + // do the computation + lm.resetParameters(); + info = lm.minimize(x); + + // check return value + VERIFY_IS_EQUAL(info, 1); + VERIFY_IS_EQUAL(lm.nfev(), 18); + VERIFY_IS_EQUAL(lm.njev(), 15); + // check norm^2 + VERIFY_IS_APPROX(lm.fvec().squaredNorm(), 5.4648946975E-05); + // check x + VERIFY_IS_APPROX(x[0], 3.7541005211E-01); + VERIFY_IS_APPROX(x[1], 1.9358469127E+00); + VERIFY_IS_APPROX(x[2], -1.4646871366E+00); + VERIFY_IS_APPROX(x[3], 1.2867534640E-02); + VERIFY_IS_APPROX(x[4], 2.2122699662E-02); +} + +struct MGH09_functor : DenseFunctor +{ + MGH09_functor(void) : DenseFunctor(4,11) {} + static const double _x[11]; + static const double y[11]; + int operator()(const VectorXd &b, VectorXd &fvec) + { + assert(b.size()==4); + assert(fvec.size()==11); + for(int i=0; i<11; i++) { + double x = _x[i], xx=x*x; + fvec[i] = b[0]*(xx+x*b[1])/(xx+x*b[2]+b[3]) - y[i]; + } + return 0; + } + int df(const VectorXd &b, MatrixXd &fjac) + { + assert(b.size()==4); + assert(fjac.rows()==11); + assert(fjac.cols()==4); + for(int i=0; i<11; i++) { + double x = _x[i], xx=x*x; + double factor = 1./(xx+x*b[2]+b[3]); + fjac(i,0) = (xx+x*b[1]) * factor; + fjac(i,1) = b[0]*x* factor; + fjac(i,2) = - b[0]*(xx+x*b[1]) * x * factor * factor; + fjac(i,3) = - b[0]*(xx+x*b[1]) * factor * factor; + } + return 0; + } +}; +const double MGH09_functor::_x[11] = { 4., 2., 1., 5.E-1 , 2.5E-01, 1.670000E-01, 1.250000E-01, 1.E-01, 8.330000E-02, 7.140000E-02, 6.250000E-02 }; +const double MGH09_functor::y[11] = { 1.957000E-01, 1.947000E-01, 1.735000E-01, 1.600000E-01, 8.440000E-02, 6.270000E-02, 4.560000E-02, 3.420000E-02, 3.230000E-02, 2.350000E-02, 2.460000E-02 }; + +// http://www.itl.nist.gov/div898/strd/nls/data/mgh09.shtml +void testNistMGH09(void) +{ + const int n=4; + int info; + + VectorXd x(n); + + /* + * First try + */ + x<< 25., 39, 41.5, 39.; + // do the computation + MGH09_functor functor; + LevenbergMarquardt lm(functor); + lm.setMaxfev(1000); + info = lm.minimize(x); + + // check return value + VERIFY_IS_EQUAL(info, 1); + VERIFY_IS_EQUAL(lm.nfev(), 490 ); + VERIFY_IS_EQUAL(lm.njev(), 376 ); + // check norm^2 + VERIFY_IS_APPROX(lm.fvec().squaredNorm(), 3.0750560385E-04); + // check x + VERIFY_IS_APPROX(x[0], 0.1928077089); // should be 1.9280693458E-01 + VERIFY_IS_APPROX(x[1], 0.19126423573); // should be 1.9128232873E-01 + VERIFY_IS_APPROX(x[2], 0.12305309914); // should be 1.2305650693E-01 + VERIFY_IS_APPROX(x[3], 0.13605395375); // should be 1.3606233068E-01 + + /* + * Second try + */ + x<< 0.25, 0.39, 0.415, 0.39; + // do the computation + lm.resetParameters(); + info = lm.minimize(x); + + // check return value + VERIFY_IS_EQUAL(info, 1); + VERIFY_IS_EQUAL(lm.nfev(), 18); + VERIFY_IS_EQUAL(lm.njev(), 16); + // check norm^2 + VERIFY_IS_APPROX(lm.fvec().squaredNorm(), 3.0750560385E-04); + // check x + VERIFY_IS_APPROX(x[0], 0.19280781); // should be 1.9280693458E-01 + VERIFY_IS_APPROX(x[1], 0.19126265); // should be 1.9128232873E-01 + VERIFY_IS_APPROX(x[2], 0.12305280); // should be 1.2305650693E-01 + VERIFY_IS_APPROX(x[3], 0.13605322); // should be 1.3606233068E-01 +} + + + +struct Bennett5_functor : DenseFunctor +{ + Bennett5_functor(void) : DenseFunctor(3,154) {} + static const double x[154]; + static const double y[154]; + int operator()(const VectorXd &b, VectorXd &fvec) + { + assert(b.size()==3); + assert(fvec.size()==154); + for(int i=0; i<154; i++) + fvec[i] = b[0]* pow(b[1]+x[i],-1./b[2]) - y[i]; + return 0; + } + int df(const VectorXd &b, MatrixXd &fjac) + { + assert(b.size()==3); + assert(fjac.rows()==154); + assert(fjac.cols()==3); + for(int i=0; i<154; i++) { + double e = pow(b[1]+x[i],-1./b[2]); + fjac(i,0) = e; + fjac(i,1) = - b[0]*e/b[2]/(b[1]+x[i]); + fjac(i,2) = b[0]*e*log(b[1]+x[i])/b[2]/b[2]; + } + return 0; + } +}; +const double Bennett5_functor::x[154] = { 7.447168E0, 8.102586E0, 8.452547E0, 8.711278E0, 8.916774E0, 9.087155E0, 9.232590E0, 9.359535E0, 9.472166E0, 9.573384E0, 9.665293E0, 9.749461E0, 9.827092E0, 9.899128E0, 9.966321E0, 10.029280E0, 10.088510E0, 10.144430E0, 10.197380E0, 10.247670E0, 10.295560E0, 10.341250E0, 10.384950E0, 10.426820E0, 10.467000E0, 10.505640E0, 10.542830E0, 10.578690E0, 10.613310E0, 10.646780E0, 10.679150E0, 10.710520E0, 10.740920E0, 10.770440E0, 10.799100E0, 10.826970E0, 10.854080E0, 10.880470E0, 10.906190E0, 10.931260E0, 10.955720E0, 10.979590E0, 11.002910E0, 11.025700E0, 11.047980E0, 11.069770E0, 11.091100E0, 11.111980E0, 11.132440E0, 11.152480E0, 11.172130E0, 11.191410E0, 11.210310E0, 11.228870E0, 11.247090E0, 11.264980E0, 11.282560E0, 11.299840E0, 11.316820E0, 11.333520E0, 11.349940E0, 11.366100E0, 11.382000E0, 11.397660E0, 11.413070E0, 11.428240E0, 11.443200E0, 11.457930E0, 11.472440E0, 11.486750E0, 11.500860E0, 11.514770E0, 11.528490E0, 11.542020E0, 11.555380E0, 11.568550E0, +11.581560E0, 11.594420E0, 11.607121E0, 11.619640E0, 11.632000E0, 11.644210E0, 11.656280E0, 11.668200E0, 11.679980E0, 11.691620E0, 11.703130E0, 11.714510E0, 11.725760E0, 11.736880E0, 11.747890E0, 11.758780E0, 11.769550E0, 11.780200E0, 11.790730E0, 11.801160E0, 11.811480E0, 11.821700E0, 11.831810E0, 11.841820E0, 11.851730E0, 11.861550E0, 11.871270E0, 11.880890E0, 11.890420E0, 11.899870E0, 11.909220E0, 11.918490E0, 11.927680E0, 11.936780E0, 11.945790E0, 11.954730E0, 11.963590E0, 11.972370E0, 11.981070E0, 11.989700E0, 11.998260E0, 12.006740E0, 12.015150E0, 12.023490E0, 12.031760E0, 12.039970E0, 12.048100E0, 12.056170E0, 12.064180E0, 12.072120E0, 12.080010E0, 12.087820E0, 12.095580E0, 12.103280E0, 12.110920E0, 12.118500E0, 12.126030E0, 12.133500E0, 12.140910E0, 12.148270E0, 12.155570E0, 12.162830E0, 12.170030E0, 12.177170E0, 12.184270E0, 12.191320E0, 12.198320E0, 12.205270E0, 12.212170E0, 12.219030E0, 12.225840E0, 12.232600E0, 12.239320E0, 12.245990E0, 12.252620E0, 12.259200E0, 12.265750E0, 12.272240E0 }; +const double Bennett5_functor::y[154] = { -34.834702E0 ,-34.393200E0 ,-34.152901E0 ,-33.979099E0 ,-33.845901E0 ,-33.732899E0 ,-33.640301E0 ,-33.559200E0 ,-33.486801E0 ,-33.423100E0 ,-33.365101E0 ,-33.313000E0 ,-33.260899E0 ,-33.217400E0 ,-33.176899E0 ,-33.139198E0 ,-33.101601E0 ,-33.066799E0 ,-33.035000E0 ,-33.003101E0 ,-32.971298E0 ,-32.942299E0 ,-32.916302E0 ,-32.890202E0 ,-32.864101E0 ,-32.841000E0 ,-32.817799E0 ,-32.797501E0 ,-32.774300E0 ,-32.757000E0 ,-32.733799E0 ,-32.716400E0 ,-32.699100E0 ,-32.678799E0 ,-32.661400E0 ,-32.644001E0 ,-32.626701E0 ,-32.612202E0 ,-32.597698E0 ,-32.583199E0 ,-32.568699E0 ,-32.554298E0 ,-32.539799E0 ,-32.525299E0 ,-32.510799E0 ,-32.499199E0 ,-32.487598E0 ,-32.473202E0 ,-32.461601E0 ,-32.435501E0 ,-32.435501E0 ,-32.426800E0 ,-32.412300E0 ,-32.400799E0 ,-32.392101E0 ,-32.380501E0 ,-32.366001E0 ,-32.357300E0 ,-32.348598E0 ,-32.339901E0 ,-32.328400E0 ,-32.319698E0 ,-32.311001E0 ,-32.299400E0 ,-32.290699E0 ,-32.282001E0 ,-32.273300E0 ,-32.264599E0 ,-32.256001E0 ,-32.247299E0 +,-32.238602E0 ,-32.229900E0 ,-32.224098E0 ,-32.215401E0 ,-32.203800E0 ,-32.198002E0 ,-32.189400E0 ,-32.183601E0 ,-32.174900E0 ,-32.169102E0 ,-32.163300E0 ,-32.154598E0 ,-32.145901E0 ,-32.140099E0 ,-32.131401E0 ,-32.125599E0 ,-32.119801E0 ,-32.111198E0 ,-32.105400E0 ,-32.096699E0 ,-32.090900E0 ,-32.088001E0 ,-32.079300E0 ,-32.073502E0 ,-32.067699E0 ,-32.061901E0 ,-32.056099E0 ,-32.050301E0 ,-32.044498E0 ,-32.038799E0 ,-32.033001E0 ,-32.027199E0 ,-32.024300E0 ,-32.018501E0 ,-32.012699E0 ,-32.004002E0 ,-32.001099E0 ,-31.995300E0 ,-31.989500E0 ,-31.983700E0 ,-31.977900E0 ,-31.972099E0 ,-31.969299E0 ,-31.963501E0 ,-31.957701E0 ,-31.951900E0 ,-31.946100E0 ,-31.940300E0 ,-31.937401E0 ,-31.931601E0 ,-31.925800E0 ,-31.922899E0 ,-31.917101E0 ,-31.911301E0 ,-31.908400E0 ,-31.902599E0 ,-31.896900E0 ,-31.893999E0 ,-31.888201E0 ,-31.885300E0 ,-31.882401E0 ,-31.876600E0 ,-31.873699E0 ,-31.867901E0 ,-31.862101E0 ,-31.859200E0 ,-31.856300E0 ,-31.850500E0 ,-31.844700E0 ,-31.841801E0 ,-31.838900E0 ,-31.833099E0 ,-31.830200E0 , +-31.827299E0 ,-31.821600E0 ,-31.818701E0 ,-31.812901E0 ,-31.809999E0 ,-31.807100E0 ,-31.801300E0 ,-31.798401E0 ,-31.795500E0 ,-31.789700E0 ,-31.786800E0 }; + +// http://www.itl.nist.gov/div898/strd/nls/data/bennett5.shtml +void testNistBennett5(void) +{ + const int n=3; + int info; + + VectorXd x(n); + + /* + * First try + */ + x<< -2000., 50., 0.8; + // do the computation + Bennett5_functor functor; + LevenbergMarquardt lm(functor); + lm.setMaxfev(1000); + info = lm.minimize(x); + + // check return value + VERIFY_IS_EQUAL(info, 1); + VERIFY_IS_EQUAL(lm.nfev(), 758); + VERIFY_IS_EQUAL(lm.njev(), 744); + // check norm^2 + VERIFY_IS_APPROX(lm.fvec().squaredNorm(), 5.2404744073E-04); + // check x + VERIFY_IS_APPROX(x[0], -2.5235058043E+03); + VERIFY_IS_APPROX(x[1], 4.6736564644E+01); + VERIFY_IS_APPROX(x[2], 9.3218483193E-01); + /* + * Second try + */ + x<< -1500., 45., 0.85; + // do the computation + lm.resetParameters(); + info = lm.minimize(x); + + // check return value + VERIFY_IS_EQUAL(info, 1); + VERIFY_IS_EQUAL(lm.nfev(), 203); + VERIFY_IS_EQUAL(lm.njev(), 192); + // check norm^2 + VERIFY_IS_APPROX(lm.fvec().squaredNorm(), 5.2404744073E-04); + // check x + VERIFY_IS_APPROX(x[0], -2523.3007865); // should be -2.5235058043E+03 + VERIFY_IS_APPROX(x[1], 46.735705771); // should be 4.6736564644E+01); + VERIFY_IS_APPROX(x[2], 0.93219881891); // should be 9.3218483193E-01); +} + +struct thurber_functor : DenseFunctor +{ + thurber_functor(void) : DenseFunctor(7,37) {} + static const double _x[37]; + static const double _y[37]; + int operator()(const VectorXd &b, VectorXd &fvec) + { + // int called=0; printf("call hahn1_functor with iflag=%d, called=%d\n", iflag, called); if (iflag==1) called++; + assert(b.size()==7); + assert(fvec.size()==37); + for(int i=0; i<37; i++) { + double x=_x[i], xx=x*x, xxx=xx*x; + fvec[i] = (b[0]+b[1]*x+b[2]*xx+b[3]*xxx) / (1.+b[4]*x+b[5]*xx+b[6]*xxx) - _y[i]; + } + return 0; + } + int df(const VectorXd &b, MatrixXd &fjac) + { + assert(b.size()==7); + assert(fjac.rows()==37); + assert(fjac.cols()==7); + for(int i=0; i<37; i++) { + double x=_x[i], xx=x*x, xxx=xx*x; + double fact = 1./(1.+b[4]*x+b[5]*xx+b[6]*xxx); + fjac(i,0) = 1.*fact; + fjac(i,1) = x*fact; + fjac(i,2) = xx*fact; + fjac(i,3) = xxx*fact; + fact = - (b[0]+b[1]*x+b[2]*xx+b[3]*xxx) * fact * fact; + fjac(i,4) = x*fact; + fjac(i,5) = xx*fact; + fjac(i,6) = xxx*fact; + } + return 0; + } +}; +const double thurber_functor::_x[37] = { -3.067E0, -2.981E0, -2.921E0, -2.912E0, -2.840E0, -2.797E0, -2.702E0, -2.699E0, -2.633E0, -2.481E0, -2.363E0, -2.322E0, -1.501E0, -1.460E0, -1.274E0, -1.212E0, -1.100E0, -1.046E0, -0.915E0, -0.714E0, -0.566E0, -0.545E0, -0.400E0, -0.309E0, -0.109E0, -0.103E0, 0.010E0, 0.119E0, 0.377E0, 0.790E0, 0.963E0, 1.006E0, 1.115E0, 1.572E0, 1.841E0, 2.047E0, 2.200E0 }; +const double thurber_functor::_y[37] = { 80.574E0, 84.248E0, 87.264E0, 87.195E0, 89.076E0, 89.608E0, 89.868E0, 90.101E0, 92.405E0, 95.854E0, 100.696E0, 101.060E0, 401.672E0, 390.724E0, 567.534E0, 635.316E0, 733.054E0, 759.087E0, 894.206E0, 990.785E0, 1090.109E0, 1080.914E0, 1122.643E0, 1178.351E0, 1260.531E0, 1273.514E0, 1288.339E0, 1327.543E0, 1353.863E0, 1414.509E0, 1425.208E0, 1421.384E0, 1442.962E0, 1464.350E0, 1468.705E0, 1447.894E0, 1457.628E0}; + +// http://www.itl.nist.gov/div898/strd/nls/data/thurber.shtml +void testNistThurber(void) +{ + const int n=7; + int info; + + VectorXd x(n); + + /* + * First try + */ + x<< 1000 ,1000 ,400 ,40 ,0.7,0.3,0.0 ; + // do the computation + thurber_functor functor; + LevenbergMarquardt lm(functor); + lm.setFtol(1.E4*NumTraits::epsilon()); + lm.setXtol(1.E4*NumTraits::epsilon()); + info = lm.minimize(x); + + // check return value + VERIFY_IS_EQUAL(info, 1); + VERIFY_IS_EQUAL(lm.nfev(), 39); + VERIFY_IS_EQUAL(lm.njev(), 36); + // check norm^2 + VERIFY_IS_APPROX(lm.fvec().squaredNorm(), 5.6427082397E+03); + // check x + VERIFY_IS_APPROX(x[0], 1.2881396800E+03); + VERIFY_IS_APPROX(x[1], 1.4910792535E+03); + VERIFY_IS_APPROX(x[2], 5.8323836877E+02); + VERIFY_IS_APPROX(x[3], 7.5416644291E+01); + VERIFY_IS_APPROX(x[4], 9.6629502864E-01); + VERIFY_IS_APPROX(x[5], 3.9797285797E-01); + VERIFY_IS_APPROX(x[6], 4.9727297349E-02); + + /* + * Second try + */ + x<< 1300 ,1500 ,500 ,75 ,1 ,0.4 ,0.05 ; + // do the computation + lm.resetParameters(); + lm.setFtol(1.E4*NumTraits::epsilon()); + lm.setXtol(1.E4*NumTraits::epsilon()); + info = lm.minimize(x); + + // check return value + VERIFY_IS_EQUAL(info, 1); + VERIFY_IS_EQUAL(lm.nfev(), 29); + VERIFY_IS_EQUAL(lm.njev(), 28); + // check norm^2 + VERIFY_IS_APPROX(lm.fvec().squaredNorm(), 5.6427082397E+03); + // check x + VERIFY_IS_APPROX(x[0], 1.2881396800E+03); + VERIFY_IS_APPROX(x[1], 1.4910792535E+03); + VERIFY_IS_APPROX(x[2], 5.8323836877E+02); + VERIFY_IS_APPROX(x[3], 7.5416644291E+01); + VERIFY_IS_APPROX(x[4], 9.6629502864E-01); + VERIFY_IS_APPROX(x[5], 3.9797285797E-01); + VERIFY_IS_APPROX(x[6], 4.9727297349E-02); +} + +struct rat43_functor : DenseFunctor +{ + rat43_functor(void) : DenseFunctor(4,15) {} + static const double x[15]; + static const double y[15]; + int operator()(const VectorXd &b, VectorXd &fvec) + { + assert(b.size()==4); + assert(fvec.size()==15); + for(int i=0; i<15; i++) + fvec[i] = b[0] * pow(1.+exp(b[1]-b[2]*x[i]),-1./b[3]) - y[i]; + return 0; + } + int df(const VectorXd &b, MatrixXd &fjac) + { + assert(b.size()==4); + assert(fjac.rows()==15); + assert(fjac.cols()==4); + for(int i=0; i<15; i++) { + double e = exp(b[1]-b[2]*x[i]); + double power = -1./b[3]; + fjac(i,0) = pow(1.+e, power); + fjac(i,1) = power*b[0]*e*pow(1.+e, power-1.); + fjac(i,2) = -power*b[0]*e*x[i]*pow(1.+e, power-1.); + fjac(i,3) = b[0]*power*power*log(1.+e)*pow(1.+e, power); + } + return 0; + } +}; +const double rat43_functor::x[15] = { 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15. }; +const double rat43_functor::y[15] = { 16.08, 33.83, 65.80, 97.20, 191.55, 326.20, 386.87, 520.53, 590.03, 651.92, 724.93, 699.56, 689.96, 637.56, 717.41 }; + +// http://www.itl.nist.gov/div898/strd/nls/data/ratkowsky3.shtml +void testNistRat43(void) +{ + const int n=4; + int info; + + VectorXd x(n); + + /* + * First try + */ + x<< 100., 10., 1., 1.; + // do the computation + rat43_functor functor; + LevenbergMarquardt lm(functor); + lm.setFtol(1.E6*NumTraits::epsilon()); + lm.setXtol(1.E6*NumTraits::epsilon()); + info = lm.minimize(x); + + // check return value + VERIFY_IS_EQUAL(info, 1); + VERIFY_IS_EQUAL(lm.nfev(), 27); + VERIFY_IS_EQUAL(lm.njev(), 20); + // check norm^2 + VERIFY_IS_APPROX(lm.fvec().squaredNorm(), 8.7864049080E+03); + // check x + VERIFY_IS_APPROX(x[0], 6.9964151270E+02); + VERIFY_IS_APPROX(x[1], 5.2771253025E+00); + VERIFY_IS_APPROX(x[2], 7.5962938329E-01); + VERIFY_IS_APPROX(x[3], 1.2792483859E+00); + + /* + * Second try + */ + x<< 700., 5., 0.75, 1.3; + // do the computation + lm.resetParameters(); + lm.setFtol(1.E5*NumTraits::epsilon()); + lm.setXtol(1.E5*NumTraits::epsilon()); + info = lm.minimize(x); + + // check return value + VERIFY_IS_EQUAL(info, 1); + VERIFY_IS_EQUAL(lm.nfev(), 9); + VERIFY_IS_EQUAL(lm.njev(), 8); + // check norm^2 + VERIFY_IS_APPROX(lm.fvec().squaredNorm(), 8.7864049080E+03); + // check x + VERIFY_IS_APPROX(x[0], 6.9964151270E+02); + VERIFY_IS_APPROX(x[1], 5.2771253025E+00); + VERIFY_IS_APPROX(x[2], 7.5962938329E-01); + VERIFY_IS_APPROX(x[3], 1.2792483859E+00); +} + + + +struct eckerle4_functor : DenseFunctor +{ + eckerle4_functor(void) : DenseFunctor(3,35) {} + static const double x[35]; + static const double y[35]; + int operator()(const VectorXd &b, VectorXd &fvec) + { + assert(b.size()==3); + assert(fvec.size()==35); + for(int i=0; i<35; i++) + fvec[i] = b[0]/b[1] * exp(-0.5*(x[i]-b[2])*(x[i]-b[2])/(b[1]*b[1])) - y[i]; + return 0; + } + int df(const VectorXd &b, MatrixXd &fjac) + { + assert(b.size()==3); + assert(fjac.rows()==35); + assert(fjac.cols()==3); + for(int i=0; i<35; i++) { + double b12 = b[1]*b[1]; + double e = exp(-0.5*(x[i]-b[2])*(x[i]-b[2])/b12); + fjac(i,0) = e / b[1]; + fjac(i,1) = ((x[i]-b[2])*(x[i]-b[2])/b12-1.) * b[0]*e/b12; + fjac(i,2) = (x[i]-b[2])*e*b[0]/b[1]/b12; + } + return 0; + } +}; +const double eckerle4_functor::x[35] = { 400.0, 405.0, 410.0, 415.0, 420.0, 425.0, 430.0, 435.0, 436.5, 438.0, 439.5, 441.0, 442.5, 444.0, 445.5, 447.0, 448.5, 450.0, 451.5, 453.0, 454.5, 456.0, 457.5, 459.0, 460.5, 462.0, 463.5, 465.0, 470.0, 475.0, 480.0, 485.0, 490.0, 495.0, 500.0}; +const double eckerle4_functor::y[35] = { 0.0001575, 0.0001699, 0.0002350, 0.0003102, 0.0004917, 0.0008710, 0.0017418, 0.0046400, 0.0065895, 0.0097302, 0.0149002, 0.0237310, 0.0401683, 0.0712559, 0.1264458, 0.2073413, 0.2902366, 0.3445623, 0.3698049, 0.3668534, 0.3106727, 0.2078154, 0.1164354, 0.0616764, 0.0337200, 0.0194023, 0.0117831, 0.0074357, 0.0022732, 0.0008800, 0.0004579, 0.0002345, 0.0001586, 0.0001143, 0.0000710 }; + +// http://www.itl.nist.gov/div898/strd/nls/data/eckerle4.shtml +void testNistEckerle4(void) +{ + const int n=3; + int info; + + VectorXd x(n); + + /* + * First try + */ + x<< 1., 10., 500.; + // do the computation + eckerle4_functor functor; + LevenbergMarquardt lm(functor); + info = lm.minimize(x); + + // check return value + VERIFY_IS_EQUAL(info, 1); + VERIFY_IS_EQUAL(lm.nfev(), 18); + VERIFY_IS_EQUAL(lm.njev(), 15); + // check norm^2 + VERIFY_IS_APPROX(lm.fvec().squaredNorm(), 1.4635887487E-03); + // check x + VERIFY_IS_APPROX(x[0], 1.5543827178); + VERIFY_IS_APPROX(x[1], 4.0888321754); + VERIFY_IS_APPROX(x[2], 4.5154121844E+02); + + /* + * Second try + */ + x<< 1.5, 5., 450.; + // do the computation + info = lm.minimize(x); + + // check return value + VERIFY_IS_EQUAL(info, 1); + VERIFY_IS_EQUAL(lm.nfev(), 7); + VERIFY_IS_EQUAL(lm.njev(), 6); + // check norm^2 + VERIFY_IS_APPROX(lm.fvec().squaredNorm(), 1.4635887487E-03); + // check x + VERIFY_IS_APPROX(x[0], 1.5543827178); + VERIFY_IS_APPROX(x[1], 4.0888321754); + VERIFY_IS_APPROX(x[2], 4.5154121844E+02); +} + +void test_levenberg_marquardt() +{ + // Tests using the examples provided by (c)minpack + CALL_SUBTEST(testLmder1()); + CALL_SUBTEST(testLmder()); + CALL_SUBTEST(testLmdif1()); +// CALL_SUBTEST(testLmstr1()); +// CALL_SUBTEST(testLmstr()); + CALL_SUBTEST(testLmdif()); + + // NIST tests, level of difficulty = "Lower" + CALL_SUBTEST(testNistMisra1a()); + CALL_SUBTEST(testNistChwirut2()); + + // NIST tests, level of difficulty = "Average" + CALL_SUBTEST(testNistHahn1()); + CALL_SUBTEST(testNistMisra1d()); + CALL_SUBTEST(testNistMGH17()); + CALL_SUBTEST(testNistLanczos1()); + +// // NIST tests, level of difficulty = "Higher" + CALL_SUBTEST(testNistRat42()); + CALL_SUBTEST(testNistMGH10()); + CALL_SUBTEST(testNistBoxBOD()); +// CALL_SUBTEST(testNistMGH09()); + CALL_SUBTEST(testNistBennett5()); + CALL_SUBTEST(testNistThurber()); + CALL_SUBTEST(testNistRat43()); + CALL_SUBTEST(testNistEckerle4()); +} diff --git a/uppsrc/plugin/Eigen/unsupported/test/matrix_exponential.cpp b/uppsrc/plugin/Eigen/unsupported/test/matrix_exponential.cpp new file mode 100644 index 000000000..50dec083d --- /dev/null +++ b/uppsrc/plugin/Eigen/unsupported/test/matrix_exponential.cpp @@ -0,0 +1,141 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2009 Jitse Niesen +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "matrix_functions.h" + +double binom(int n, int k) +{ + double res = 1; + for (int i=0; i +T expfn(T x, int) +{ + return std::exp(x); +} + +template +void test2dRotation(double tol) +{ + Matrix A, B, C; + T angle; + + A << 0, 1, -1, 0; + for (int i=0; i<=20; i++) + { + angle = static_cast(pow(10, i / 5. - 2)); + B << std::cos(angle), std::sin(angle), -std::sin(angle), std::cos(angle); + + C = (angle*A).matrixFunction(expfn); + std::cout << "test2dRotation: i = " << i << " error funm = " << relerr(C, B); + VERIFY(C.isApprox(B, static_cast(tol))); + + C = (angle*A).exp(); + std::cout << " error expm = " << relerr(C, B) << "\n"; + VERIFY(C.isApprox(B, static_cast(tol))); + } +} + +template +void test2dHyperbolicRotation(double tol) +{ + Matrix,2,2> A, B, C; + std::complex imagUnit(0,1); + T angle, ch, sh; + + for (int i=0; i<=20; i++) + { + angle = static_cast((i-10) / 2.0); + ch = std::cosh(angle); + sh = std::sinh(angle); + A << 0, angle*imagUnit, -angle*imagUnit, 0; + B << ch, sh*imagUnit, -sh*imagUnit, ch; + + C = A.matrixFunction(expfn); + std::cout << "test2dHyperbolicRotation: i = " << i << " error funm = " << relerr(C, B); + VERIFY(C.isApprox(B, static_cast(tol))); + + C = A.exp(); + std::cout << " error expm = " << relerr(C, B) << "\n"; + VERIFY(C.isApprox(B, static_cast(tol))); + } +} + +template +void testPascal(double tol) +{ + for (int size=1; size<20; size++) + { + Matrix A(size,size), B(size,size), C(size,size); + A.setZero(); + for (int i=0; i(i+1); + B.setZero(); + for (int i=0; i(binom(i,j)); + + C = A.matrixFunction(expfn); + std::cout << "testPascal: size = " << size << " error funm = " << relerr(C, B); + VERIFY(C.isApprox(B, static_cast(tol))); + + C = A.exp(); + std::cout << " error expm = " << relerr(C, B) << "\n"; + VERIFY(C.isApprox(B, static_cast(tol))); + } +} + +template +void randomTest(const MatrixType& m, double tol) +{ + /* this test covers the following files: + Inverse.h + */ + typename MatrixType::Index rows = m.rows(); + typename MatrixType::Index cols = m.cols(); + MatrixType m1(rows, cols), m2(rows, cols), identity = MatrixType::Identity(rows, cols); + + typedef typename NumTraits::Scalar>::Real RealScalar; + + for(int i = 0; i < g_repeat; i++) { + m1 = MatrixType::Random(rows, cols); + + m2 = m1.matrixFunction(expfn) * (-m1).matrixFunction(expfn); + std::cout << "randomTest: error funm = " << relerr(identity, m2); + VERIFY(identity.isApprox(m2, static_cast(tol))); + + m2 = m1.exp() * (-m1).exp(); + std::cout << " error expm = " << relerr(identity, m2) << "\n"; + VERIFY(identity.isApprox(m2, static_cast(tol))); + } +} + +void test_matrix_exponential() +{ + CALL_SUBTEST_2(test2dRotation(1e-13)); + CALL_SUBTEST_1(test2dRotation(2e-5)); // was 1e-5, relaxed for clang 2.8 / linux / x86-64 + CALL_SUBTEST_8(test2dRotation(1e-13)); + CALL_SUBTEST_2(test2dHyperbolicRotation(1e-14)); + CALL_SUBTEST_1(test2dHyperbolicRotation(1e-5)); + CALL_SUBTEST_8(test2dHyperbolicRotation(1e-14)); + CALL_SUBTEST_6(testPascal(1e-6)); + CALL_SUBTEST_5(testPascal(1e-15)); + CALL_SUBTEST_2(randomTest(Matrix2d(), 1e-13)); + CALL_SUBTEST_7(randomTest(Matrix(), 1e-13)); + CALL_SUBTEST_3(randomTest(Matrix4cd(), 1e-13)); + CALL_SUBTEST_4(randomTest(MatrixXd(8,8), 1e-13)); + CALL_SUBTEST_1(randomTest(Matrix2f(), 1e-4)); + CALL_SUBTEST_5(randomTest(Matrix3cf(), 1e-4)); + CALL_SUBTEST_1(randomTest(Matrix4f(), 1e-4)); + CALL_SUBTEST_6(randomTest(MatrixXf(8,8), 1e-4)); + CALL_SUBTEST_9(randomTest(Matrix(7,7), 1e-13)); +} diff --git a/uppsrc/plugin/Eigen/unsupported/test/matrix_function.cpp b/uppsrc/plugin/Eigen/unsupported/test/matrix_function.cpp new file mode 100644 index 000000000..3c76cfb65 --- /dev/null +++ b/uppsrc/plugin/Eigen/unsupported/test/matrix_function.cpp @@ -0,0 +1,193 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2010 Jitse Niesen +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "main.h" +#include + +// Variant of VERIFY_IS_APPROX which uses absolute error instead of +// relative error. +#define VERIFY_IS_APPROX_ABS(a, b) VERIFY(test_isApprox_abs(a, b)) + +template +inline bool test_isApprox_abs(const Type1& a, const Type2& b) +{ + return ((a-b).array().abs() < test_precision()).all(); +} + + +// Returns a matrix with eigenvalues clustered around 0, 1 and 2. +template +MatrixType randomMatrixWithRealEivals(const typename MatrixType::Index size) +{ + typedef typename MatrixType::Index Index; + typedef typename MatrixType::Scalar Scalar; + typedef typename MatrixType::RealScalar RealScalar; + MatrixType diag = MatrixType::Zero(size, size); + for (Index i = 0; i < size; ++i) { + diag(i, i) = Scalar(RealScalar(internal::random(0,2))) + + internal::random() * Scalar(RealScalar(0.01)); + } + MatrixType A = MatrixType::Random(size, size); + HouseholderQR QRofA(A); + return QRofA.householderQ().inverse() * diag * QRofA.householderQ(); +} + +template ::Scalar>::IsComplex> +struct randomMatrixWithImagEivals +{ + // Returns a matrix with eigenvalues clustered around 0 and +/- i. + static MatrixType run(const typename MatrixType::Index size); +}; + +// Partial specialization for real matrices +template +struct randomMatrixWithImagEivals +{ + static MatrixType run(const typename MatrixType::Index size) + { + typedef typename MatrixType::Index Index; + typedef typename MatrixType::Scalar Scalar; + MatrixType diag = MatrixType::Zero(size, size); + Index i = 0; + while (i < size) { + Index randomInt = internal::random(-1, 1); + if (randomInt == 0 || i == size-1) { + diag(i, i) = internal::random() * Scalar(0.01); + ++i; + } else { + Scalar alpha = Scalar(randomInt) + internal::random() * Scalar(0.01); + diag(i, i+1) = alpha; + diag(i+1, i) = -alpha; + i += 2; + } + } + MatrixType A = MatrixType::Random(size, size); + HouseholderQR QRofA(A); + return QRofA.householderQ().inverse() * diag * QRofA.householderQ(); + } +}; + +// Partial specialization for complex matrices +template +struct randomMatrixWithImagEivals +{ + static MatrixType run(const typename MatrixType::Index size) + { + typedef typename MatrixType::Index Index; + typedef typename MatrixType::Scalar Scalar; + typedef typename MatrixType::RealScalar RealScalar; + const Scalar imagUnit(0, 1); + MatrixType diag = MatrixType::Zero(size, size); + for (Index i = 0; i < size; ++i) { + diag(i, i) = Scalar(RealScalar(internal::random(-1, 1))) * imagUnit + + internal::random() * Scalar(RealScalar(0.01)); + } + MatrixType A = MatrixType::Random(size, size); + HouseholderQR QRofA(A); + return QRofA.householderQ().inverse() * diag * QRofA.householderQ(); + } +}; + + +template +void testMatrixExponential(const MatrixType& A) +{ + typedef typename internal::traits::Scalar Scalar; + typedef typename NumTraits::Real RealScalar; + typedef std::complex ComplexScalar; + + VERIFY_IS_APPROX(A.exp(), A.matrixFunction(StdStemFunctions::exp)); +} + +template +void testMatrixLogarithm(const MatrixType& A) +{ + typedef typename internal::traits::Scalar Scalar; + typedef typename NumTraits::Real RealScalar; + + MatrixType scaledA; + RealScalar maxImagPartOfSpectrum = A.eigenvalues().imag().cwiseAbs().maxCoeff(); + if (maxImagPartOfSpectrum >= 0.9 * M_PI) + scaledA = A * 0.9 * M_PI / maxImagPartOfSpectrum; + else + scaledA = A; + + // identity X.exp().log() = X only holds if Im(lambda) < pi for all eigenvalues of X + MatrixType expA = scaledA.exp(); + MatrixType logExpA = expA.log(); + VERIFY_IS_APPROX(logExpA, scaledA); +} + +template +void testHyperbolicFunctions(const MatrixType& A) +{ + // Need to use absolute error because of possible cancellation when + // adding/subtracting expA and expmA. + VERIFY_IS_APPROX_ABS(A.sinh(), (A.exp() - (-A).exp()) / 2); + VERIFY_IS_APPROX_ABS(A.cosh(), (A.exp() + (-A).exp()) / 2); +} + +template +void testGonioFunctions(const MatrixType& A) +{ + typedef typename MatrixType::Scalar Scalar; + typedef typename NumTraits::Real RealScalar; + typedef std::complex ComplexScalar; + typedef Matrix ComplexMatrix; + + ComplexScalar imagUnit(0,1); + ComplexScalar two(2,0); + + ComplexMatrix Ac = A.template cast(); + + ComplexMatrix exp_iA = (imagUnit * Ac).exp(); + ComplexMatrix exp_miA = (-imagUnit * Ac).exp(); + + ComplexMatrix sinAc = A.sin().template cast(); + VERIFY_IS_APPROX_ABS(sinAc, (exp_iA - exp_miA) / (two*imagUnit)); + + ComplexMatrix cosAc = A.cos().template cast(); + VERIFY_IS_APPROX_ABS(cosAc, (exp_iA + exp_miA) / 2); +} + +template +void testMatrix(const MatrixType& A) +{ + testMatrixExponential(A); + testMatrixLogarithm(A); + testHyperbolicFunctions(A); + testGonioFunctions(A); +} + +template +void testMatrixType(const MatrixType& m) +{ + // Matrices with clustered eigenvalue lead to different code paths + // in MatrixFunction.h and are thus useful for testing. + typedef typename MatrixType::Index Index; + + const Index size = m.rows(); + for (int i = 0; i < g_repeat; i++) { + testMatrix(MatrixType::Random(size, size).eval()); + testMatrix(randomMatrixWithRealEivals(size)); + testMatrix(randomMatrixWithImagEivals::run(size)); + } +} + +void test_matrix_function() +{ + CALL_SUBTEST_1(testMatrixType(Matrix())); + CALL_SUBTEST_2(testMatrixType(Matrix3cf())); + CALL_SUBTEST_3(testMatrixType(MatrixXf(8,8))); + CALL_SUBTEST_4(testMatrixType(Matrix2d())); + CALL_SUBTEST_5(testMatrixType(Matrix())); + CALL_SUBTEST_6(testMatrixType(Matrix4cd())); + CALL_SUBTEST_7(testMatrixType(MatrixXd(13,13))); +} diff --git a/uppsrc/plugin/Eigen/unsupported/test/matrix_functions.h b/uppsrc/plugin/Eigen/unsupported/test/matrix_functions.h new file mode 100644 index 000000000..5817caef6 --- /dev/null +++ b/uppsrc/plugin/Eigen/unsupported/test/matrix_functions.h @@ -0,0 +1,47 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2009-2011 Jitse Niesen +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "main.h" +#include + +template ::Scalar>::IsComplex> +struct generateTestMatrix; + +// for real matrices, make sure none of the eigenvalues are negative +template +struct generateTestMatrix +{ + static void run(MatrixType& result, typename MatrixType::Index size) + { + MatrixType mat = MatrixType::Random(size, size); + EigenSolver es(mat); + typename EigenSolver::EigenvalueType eivals = es.eigenvalues(); + for (typename MatrixType::Index i = 0; i < size; ++i) { + if (eivals(i).imag() == 0 && eivals(i).real() < 0) + eivals(i) = -eivals(i); + } + result = (es.eigenvectors() * eivals.asDiagonal() * es.eigenvectors().inverse()).real(); + } +}; + +// for complex matrices, any matrix is fine +template +struct generateTestMatrix +{ + static void run(MatrixType& result, typename MatrixType::Index size) + { + result = MatrixType::Random(size, size); + } +}; + +template +double relerr(const MatrixBase& A, const MatrixBase& B) +{ + return std::sqrt((A - B).cwiseAbs2().sum() / (std::min)(A.cwiseAbs2().sum(), B.cwiseAbs2().sum())); +} diff --git a/uppsrc/plugin/Eigen/unsupported/test/matrix_power.cpp b/uppsrc/plugin/Eigen/unsupported/test/matrix_power.cpp new file mode 100644 index 000000000..b9d513b45 --- /dev/null +++ b/uppsrc/plugin/Eigen/unsupported/test/matrix_power.cpp @@ -0,0 +1,133 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2012 Chen-Pang He +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "matrix_functions.h" + +template ::IsComplex> +struct generateTriangularMatrix; + +// for real matrices, make sure none of the eigenvalues are negative +template +struct generateTriangularMatrix +{ + static void run(MatrixType& result, typename MatrixType::Index size) + { + result.resize(size, size); + result.template triangularView() = MatrixType::Random(size, size); + for (typename MatrixType::Index i = 0; i < size; ++i) + result.coeffRef(i,i) = std::abs(result.coeff(i,i)); + } +}; + +// for complex matrices, any matrix is fine +template +struct generateTriangularMatrix +{ + static void run(MatrixType& result, typename MatrixType::Index size) + { + result.resize(size, size); + result.template triangularView() = MatrixType::Random(size, size); + } +}; + +template +void test2dRotation(double tol) +{ + Matrix A, B, C; + T angle, c, s; + + A << 0, 1, -1, 0; + MatrixPower > Apow(A); + + for (int i=0; i<=20; ++i) { + angle = pow(10, (i-10) / 5.); + c = std::cos(angle); + s = std::sin(angle); + B << c, s, -s, c; + + C = Apow(std::ldexp(angle,1) / M_PI); + std::cout << "test2dRotation: i = " << i << " error powerm = " << relerr(C,B) << '\n'; + VERIFY(C.isApprox(B, static_cast(tol))); + } +} + +template +void test2dHyperbolicRotation(double tol) +{ + Matrix,2,2> A, B, C; + T angle, ch = std::cosh((T)1); + std::complex ish(0, std::sinh((T)1)); + + A << ch, ish, -ish, ch; + MatrixPower,2,2> > Apow(A); + + for (int i=0; i<=20; ++i) { + angle = std::ldexp(static_cast(i-10), -1); + ch = std::cosh(angle); + ish = std::complex(0, std::sinh(angle)); + B << ch, ish, -ish, ch; + + C = Apow(angle); + std::cout << "test2dHyperbolicRotation: i = " << i << " error powerm = " << relerr(C,B) << '\n'; + VERIFY(C.isApprox(B, static_cast(tol))); + } +} + +template +void testExponentLaws(const MatrixType& m, double tol) +{ + typedef typename MatrixType::RealScalar RealScalar; + MatrixType m1, m2, m3, m4, m5; + RealScalar x, y; + + for (int i=0; i < g_repeat; ++i) { + generateTestMatrix::run(m1, m.rows()); + MatrixPower mpow(m1); + + x = internal::random(); + y = internal::random(); + m2 = mpow(x); + m3 = mpow(y); + + m4 = mpow(x+y); + m5.noalias() = m2 * m3; + VERIFY(m4.isApprox(m5, static_cast(tol))); + + m4 = mpow(x*y); + m5 = m2.pow(y); + VERIFY(m4.isApprox(m5, static_cast(tol))); + + m4 = (std::abs(x) * m1).pow(y); + m5 = std::pow(std::abs(x), y) * m3; + VERIFY(m4.isApprox(m5, static_cast(tol))); + } +} + +typedef Matrix Matrix3dRowMajor; +typedef Matrix MatrixXe; + +void test_matrix_power() +{ + CALL_SUBTEST_2(test2dRotation(1e-13)); + CALL_SUBTEST_1(test2dRotation(2e-5)); // was 1e-5, relaxed for clang 2.8 / linux / x86-64 + CALL_SUBTEST_9(test2dRotation(1e-13)); + CALL_SUBTEST_2(test2dHyperbolicRotation(1e-14)); + CALL_SUBTEST_1(test2dHyperbolicRotation(1e-5)); + CALL_SUBTEST_9(test2dHyperbolicRotation(1e-14)); + + CALL_SUBTEST_2(testExponentLaws(Matrix2d(), 1e-13)); + CALL_SUBTEST_7(testExponentLaws(Matrix3dRowMajor(), 1e-13)); + CALL_SUBTEST_3(testExponentLaws(Matrix4cd(), 1e-13)); + CALL_SUBTEST_4(testExponentLaws(MatrixXd(8,8), 2e-12)); + CALL_SUBTEST_1(testExponentLaws(Matrix2f(), 1e-4)); + CALL_SUBTEST_5(testExponentLaws(Matrix3cf(), 1e-4)); + CALL_SUBTEST_8(testExponentLaws(Matrix4f(), 1e-4)); + CALL_SUBTEST_6(testExponentLaws(MatrixXf(2,2), 1e-3)); // see bug 614 + CALL_SUBTEST_9(testExponentLaws(MatrixXe(7,7), 1e-13)); +} diff --git a/uppsrc/plugin/Eigen/unsupported/test/matrix_square_root.cpp b/uppsrc/plugin/Eigen/unsupported/test/matrix_square_root.cpp new file mode 100644 index 000000000..ea541e1ea --- /dev/null +++ b/uppsrc/plugin/Eigen/unsupported/test/matrix_square_root.cpp @@ -0,0 +1,31 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2011 Jitse Niesen +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "matrix_functions.h" + +template +void testMatrixSqrt(const MatrixType& m) +{ + MatrixType A; + generateTestMatrix::run(A, m.rows()); + MatrixType sqrtA = A.sqrt(); + VERIFY_IS_APPROX(sqrtA * sqrtA, A); +} + +void test_matrix_square_root() +{ + for (int i = 0; i < g_repeat; i++) { + CALL_SUBTEST_1(testMatrixSqrt(Matrix3cf())); + CALL_SUBTEST_2(testMatrixSqrt(MatrixXcd(12,12))); + CALL_SUBTEST_3(testMatrixSqrt(Matrix4f())); + CALL_SUBTEST_4(testMatrixSqrt(Matrix(9, 9))); + CALL_SUBTEST_5(testMatrixSqrt(Matrix())); + CALL_SUBTEST_5(testMatrixSqrt(Matrix,1,1>())); + } +} diff --git a/uppsrc/plugin/Eigen/unsupported/test/minres.cpp b/uppsrc/plugin/Eigen/unsupported/test/minres.cpp new file mode 100644 index 000000000..509ebe09a --- /dev/null +++ b/uppsrc/plugin/Eigen/unsupported/test/minres.cpp @@ -0,0 +1,49 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2011 Gael Guennebaud +// Copyright (C) 2012 Giacomo Po +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. +#include + +#include "../../test/sparse_solver.h" +#include + +template void test_minres_T() +{ + MINRES, Lower|Upper, DiagonalPreconditioner > minres_colmajor_diag; + MINRES, Lower, IdentityPreconditioner > minres_colmajor_lower_I; + MINRES, Upper, IdentityPreconditioner > minres_colmajor_upper_I; +// MINRES, Lower, IncompleteLUT > minres_colmajor_ilut; + //minres, SSORPreconditioner > minres_colmajor_ssor; + + +// CALL_SUBTEST( check_sparse_square_solving(minres_colmajor_diag) ); + // CALL_SUBTEST( check_sparse_square_solving(minres_colmajor_ilut) ); + //CALL_SUBTEST( check_sparse_square_solving(minres_colmajor_ssor) ); + + // Diagonal preconditioner + MINRES, Lower, DiagonalPreconditioner > minres_colmajor_lower_diag; + MINRES, Upper, DiagonalPreconditioner > minres_colmajor_upper_diag; + MINRES, Upper|Lower, DiagonalPreconditioner > minres_colmajor_uplo_diag; + + // call tests for SPD matrix + CALL_SUBTEST( check_sparse_spd_solving(minres_colmajor_lower_I) ); + CALL_SUBTEST( check_sparse_spd_solving(minres_colmajor_upper_I) ); + + CALL_SUBTEST( check_sparse_spd_solving(minres_colmajor_lower_diag) ); + CALL_SUBTEST( check_sparse_spd_solving(minres_colmajor_upper_diag) ); +// CALL_SUBTEST( check_sparse_spd_solving(minres_colmajor_uplo_diag) ); + + // TO DO: symmetric semi-definite matrix + // TO DO: symmetric indefinite matrix +} + +void test_minres() +{ + CALL_SUBTEST_1(test_minres_T()); +// CALL_SUBTEST_2(test_minres_T >()); +} diff --git a/uppsrc/plugin/Eigen/unsupported/test/mpreal/mpreal.h b/uppsrc/plugin/Eigen/unsupported/test/mpreal/mpreal.h new file mode 100644 index 000000000..7d6f4e79f --- /dev/null +++ b/uppsrc/plugin/Eigen/unsupported/test/mpreal/mpreal.h @@ -0,0 +1,3074 @@ +/* + MPFR C++: Multi-precision floating point number class for C++. + Based on MPFR library: http://mpfr.org + + Project homepage: http://www.holoborodko.com/pavel/mpfr + Contact e-mail: pavel@holoborodko.com + + Copyright (c) 2008-2014 Pavel Holoborodko + + Contributors: + Dmitriy Gubanov, Konstantin Holoborodko, Brian Gladman, + Helmut Jarausch, Fokko Beekhof, Ulrich Mutze, Heinz van Saanen, + Pere Constans, Peter van Hoof, Gael Guennebaud, Tsai Chia Cheng, + Alexei Zubanov, Jauhien Piatlicki, Victor Berger, John Westwood, + Petr Aleksandrov, Orion Poplawski, Charles Karney. + + Licensing: + (A) MPFR C++ is under GNU General Public License ("GPL"). + + (B) Non-free licenses may also be purchased from the author, for users who + do not want their programs protected by the GPL. + + The non-free licenses are for users that wish to use MPFR C++ in + their products but are unwilling to release their software + under the GPL (which would require them to release source code + and allow free redistribution). + + Such users can purchase an unlimited-use license from the author. + Contact us for more details. + + GNU General Public License ("GPL") copyright permissions statement: + ************************************************************************** + This program is free software: 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 3 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef __MPREAL_H__ +#define __MPREAL_H__ + +#include +#include +#include +#include +#include +#include +#include +#include + +// Options +// FIXME HAVE_INT64_SUPPORT leads to clashes with long int and int64_t on some systems. +//#define MPREAL_HAVE_INT64_SUPPORT // Enable int64_t support if possible. Available only for MSVC 2010 & GCC. +#define MPREAL_HAVE_MSVC_DEBUGVIEW // Enable Debugger Visualizer for "Debug" builds in MSVC. +#define MPREAL_HAVE_DYNAMIC_STD_NUMERIC_LIMITS // Enable extended std::numeric_limits specialization. + // Meaning that "digits", "round_style" and similar members are defined as functions, not constants. + // See std::numeric_limits at the end of the file for more information. + +// Library version +#define MPREAL_VERSION_MAJOR 3 +#define MPREAL_VERSION_MINOR 5 +#define MPREAL_VERSION_PATCHLEVEL 9 +#define MPREAL_VERSION_STRING "3.5.9" + +// Detect compiler using signatures from http://predef.sourceforge.net/ +#if defined(__GNUC__) && defined(__INTEL_COMPILER) + #define IsInf(x) isinf(x) // Intel ICC compiler on Linux + +#elif defined(_MSC_VER) // Microsoft Visual C++ + #define IsInf(x) (!_finite(x)) + +#else + #define IsInf(x) std::isinf(x) // GNU C/C++ (and/or other compilers), just hope for C99 conformance +#endif + +// A Clang feature extension to determine compiler features. +#ifndef __has_feature + #define __has_feature(x) 0 +#endif + +// Detect support for r-value references (move semantic). Borrowed from Eigen. +#if (__has_feature(cxx_rvalue_references) || \ + defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L || \ + (defined(_MSC_VER) && _MSC_VER >= 1600)) + + #define MPREAL_HAVE_MOVE_SUPPORT + + // Use fields in mpfr_t structure to check if it was initialized / set dummy initialization + #define mpfr_is_initialized(x) (0 != (x)->_mpfr_d) + #define mpfr_set_uninitialized(x) ((x)->_mpfr_d = 0 ) +#endif + +// Detect support for explicit converters. +#if (__has_feature(cxx_explicit_conversions) || \ + defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L || \ + (defined(_MSC_VER) && _MSC_VER >= 1800)) + + #define MPREAL_HAVE_EXPLICIT_CONVERTERS +#endif + +// Detect available 64-bit capabilities +#if defined(MPREAL_HAVE_INT64_SUPPORT) + + #define MPFR_USE_INTMAX_T // Should be defined before mpfr.h + + #if defined(_MSC_VER) // MSVC + Windows + #if (_MSC_VER >= 1600) + #include // is available only in msvc2010! + + #else // MPFR relies on intmax_t which is available only in msvc2010 + #undef MPREAL_HAVE_INT64_SUPPORT // Besides, MPFR & MPIR have to be compiled with msvc2010 + #undef MPFR_USE_INTMAX_T // Since we cannot detect this, disable x64 by default + // Someone should change this manually if needed. + #endif + + #elif defined (__GNUC__) && defined(__linux__) + #if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(__ia64) || defined(__itanium__) || defined(_M_IA64) || defined (__PPC64__) + #undef MPREAL_HAVE_INT64_SUPPORT // Remove all shaman dances for x64 builds since + #undef MPFR_USE_INTMAX_T // GCC already supports x64 as of "long int" is 64-bit integer, nothing left to do + #else + #include // use int64_t, uint64_t otherwise + #endif + + #else + #include // rely on int64_t, uint64_t in all other cases, Mac OSX, etc. + #endif + +#endif + +#if defined(MPREAL_HAVE_MSVC_DEBUGVIEW) && defined(_MSC_VER) && defined(_DEBUG) + #define MPREAL_MSVC_DEBUGVIEW_CODE DebugView = toString(); + #define MPREAL_MSVC_DEBUGVIEW_DATA std::string DebugView; +#else + #define MPREAL_MSVC_DEBUGVIEW_CODE + #define MPREAL_MSVC_DEBUGVIEW_DATA +#endif + +#include + +#if (MPFR_VERSION < MPFR_VERSION_NUM(3,0,0)) + #include // Needed for random() +#endif + +// Less important options +#define MPREAL_DOUBLE_BITS_OVERFLOW -1 // Triggers overflow exception during conversion to double if mpreal + // cannot fit in MPREAL_DOUBLE_BITS_OVERFLOW bits + // = -1 disables overflow checks (default) +#if defined(__GNUC__) + #define MPREAL_PERMISSIVE_EXPR __extension__ +#else + #define MPREAL_PERMISSIVE_EXPR +#endif + +namespace mpfr { + +class mpreal { +private: + mpfr_t mp; + +public: + + // Get default rounding mode & precision + inline static mp_rnd_t get_default_rnd() { return (mp_rnd_t)(mpfr_get_default_rounding_mode()); } + inline static mp_prec_t get_default_prec() { return mpfr_get_default_prec(); } + + // Constructors && type conversions + mpreal(); + mpreal(const mpreal& u); + mpreal(const mpf_t u); + mpreal(const mpz_t u, mp_prec_t prec = mpreal::get_default_prec(), mp_rnd_t mode = mpreal::get_default_rnd()); + mpreal(const mpq_t u, mp_prec_t prec = mpreal::get_default_prec(), mp_rnd_t mode = mpreal::get_default_rnd()); + mpreal(const double u, mp_prec_t prec = mpreal::get_default_prec(), mp_rnd_t mode = mpreal::get_default_rnd()); + mpreal(const long double u, mp_prec_t prec = mpreal::get_default_prec(), mp_rnd_t mode = mpreal::get_default_rnd()); + mpreal(const unsigned long int u, mp_prec_t prec = mpreal::get_default_prec(), mp_rnd_t mode = mpreal::get_default_rnd()); + mpreal(const unsigned int u, mp_prec_t prec = mpreal::get_default_prec(), mp_rnd_t mode = mpreal::get_default_rnd()); + mpreal(const long int u, mp_prec_t prec = mpreal::get_default_prec(), mp_rnd_t mode = mpreal::get_default_rnd()); + mpreal(const int u, mp_prec_t prec = mpreal::get_default_prec(), mp_rnd_t mode = mpreal::get_default_rnd()); + + // Construct mpreal from mpfr_t structure. + // shared = true allows to avoid deep copy, so that mpreal and 'u' share the same data & pointers. + mpreal(const mpfr_t u, bool shared = false); + +#if defined (MPREAL_HAVE_INT64_SUPPORT) + mpreal(const uint64_t u, mp_prec_t prec = mpreal::get_default_prec(), mp_rnd_t mode = mpreal::get_default_rnd()); + mpreal(const int64_t u, mp_prec_t prec = mpreal::get_default_prec(), mp_rnd_t mode = mpreal::get_default_rnd()); +#endif + + mpreal(const char* s, mp_prec_t prec = mpreal::get_default_prec(), int base = 10, mp_rnd_t mode = mpreal::get_default_rnd()); + mpreal(const std::string& s, mp_prec_t prec = mpreal::get_default_prec(), int base = 10, mp_rnd_t mode = mpreal::get_default_rnd()); + + ~mpreal(); + +#ifdef MPREAL_HAVE_MOVE_SUPPORT + mpreal& operator=(mpreal&& v); + mpreal(mpreal&& u); +#endif + + // Operations + // = + // +, -, *, /, ++, --, <<, >> + // *=, +=, -=, /=, + // <, >, ==, <=, >= + + // = + mpreal& operator=(const mpreal& v); + mpreal& operator=(const mpf_t v); + mpreal& operator=(const mpz_t v); + mpreal& operator=(const mpq_t v); + mpreal& operator=(const long double v); + mpreal& operator=(const double v); + mpreal& operator=(const unsigned long int v); + mpreal& operator=(const unsigned int v); + mpreal& operator=(const long int v); + mpreal& operator=(const int v); + mpreal& operator=(const char* s); + mpreal& operator=(const std::string& s); + + // + + mpreal& operator+=(const mpreal& v); + mpreal& operator+=(const mpf_t v); + mpreal& operator+=(const mpz_t v); + mpreal& operator+=(const mpq_t v); + mpreal& operator+=(const long double u); + mpreal& operator+=(const double u); + mpreal& operator+=(const unsigned long int u); + mpreal& operator+=(const unsigned int u); + mpreal& operator+=(const long int u); + mpreal& operator+=(const int u); + +#if defined (MPREAL_HAVE_INT64_SUPPORT) + mpreal& operator+=(const int64_t u); + mpreal& operator+=(const uint64_t u); + mpreal& operator-=(const int64_t u); + mpreal& operator-=(const uint64_t u); + mpreal& operator*=(const int64_t u); + mpreal& operator*=(const uint64_t u); + mpreal& operator/=(const int64_t u); + mpreal& operator/=(const uint64_t u); +#endif + + const mpreal operator+() const; + mpreal& operator++ (); + const mpreal operator++ (int); + + // - + mpreal& operator-=(const mpreal& v); + mpreal& operator-=(const mpz_t v); + mpreal& operator-=(const mpq_t v); + mpreal& operator-=(const long double u); + mpreal& operator-=(const double u); + mpreal& operator-=(const unsigned long int u); + mpreal& operator-=(const unsigned int u); + mpreal& operator-=(const long int u); + mpreal& operator-=(const int u); + const mpreal operator-() const; + friend const mpreal operator-(const unsigned long int b, const mpreal& a); + friend const mpreal operator-(const unsigned int b, const mpreal& a); + friend const mpreal operator-(const long int b, const mpreal& a); + friend const mpreal operator-(const int b, const mpreal& a); + friend const mpreal operator-(const double b, const mpreal& a); + mpreal& operator-- (); + const mpreal operator-- (int); + + // * + mpreal& operator*=(const mpreal& v); + mpreal& operator*=(const mpz_t v); + mpreal& operator*=(const mpq_t v); + mpreal& operator*=(const long double v); + mpreal& operator*=(const double v); + mpreal& operator*=(const unsigned long int v); + mpreal& operator*=(const unsigned int v); + mpreal& operator*=(const long int v); + mpreal& operator*=(const int v); + + // / + mpreal& operator/=(const mpreal& v); + mpreal& operator/=(const mpz_t v); + mpreal& operator/=(const mpq_t v); + mpreal& operator/=(const long double v); + mpreal& operator/=(const double v); + mpreal& operator/=(const unsigned long int v); + mpreal& operator/=(const unsigned int v); + mpreal& operator/=(const long int v); + mpreal& operator/=(const int v); + friend const mpreal operator/(const unsigned long int b, const mpreal& a); + friend const mpreal operator/(const unsigned int b, const mpreal& a); + friend const mpreal operator/(const long int b, const mpreal& a); + friend const mpreal operator/(const int b, const mpreal& a); + friend const mpreal operator/(const double b, const mpreal& a); + + //<<= Fast Multiplication by 2^u + mpreal& operator<<=(const unsigned long int u); + mpreal& operator<<=(const unsigned int u); + mpreal& operator<<=(const long int u); + mpreal& operator<<=(const int u); + + //>>= Fast Division by 2^u + mpreal& operator>>=(const unsigned long int u); + mpreal& operator>>=(const unsigned int u); + mpreal& operator>>=(const long int u); + mpreal& operator>>=(const int u); + + // Boolean Operators + friend bool operator > (const mpreal& a, const mpreal& b); + friend bool operator >= (const mpreal& a, const mpreal& b); + friend bool operator < (const mpreal& a, const mpreal& b); + friend bool operator <= (const mpreal& a, const mpreal& b); + friend bool operator == (const mpreal& a, const mpreal& b); + friend bool operator != (const mpreal& a, const mpreal& b); + + // Optimized specializations for boolean operators + friend bool operator == (const mpreal& a, const unsigned long int b); + friend bool operator == (const mpreal& a, const unsigned int b); + friend bool operator == (const mpreal& a, const long int b); + friend bool operator == (const mpreal& a, const int b); + friend bool operator == (const mpreal& a, const long double b); + friend bool operator == (const mpreal& a, const double b); + + // Type Conversion operators + bool toBool (mp_rnd_t mode = GMP_RNDZ) const; + long toLong (mp_rnd_t mode = GMP_RNDZ) const; + unsigned long toULong (mp_rnd_t mode = GMP_RNDZ) const; + float toFloat (mp_rnd_t mode = GMP_RNDN) const; + double toDouble (mp_rnd_t mode = GMP_RNDN) const; + long double toLDouble (mp_rnd_t mode = GMP_RNDN) const; + +#if defined (MPREAL_HAVE_EXPLICIT_CONVERTERS) + explicit operator bool () const { return toBool(); } + explicit operator int () const { return toLong(); } + explicit operator long () const { return toLong(); } + explicit operator long long () const { return toLong(); } + explicit operator unsigned () const { return toULong(); } + explicit operator unsigned long () const { return toULong(); } + explicit operator unsigned long long () const { return toULong(); } + explicit operator float () const { return toFloat(); } + explicit operator double () const { return toDouble(); } + explicit operator long double () const { return toLDouble(); } +#endif + +#if defined (MPREAL_HAVE_INT64_SUPPORT) + int64_t toInt64 (mp_rnd_t mode = GMP_RNDZ) const; + uint64_t toUInt64 (mp_rnd_t mode = GMP_RNDZ) const; + + #if defined (MPREAL_HAVE_EXPLICIT_CONVERTERS) + explicit operator int64_t () const { return toInt64(); } + explicit operator uint64_t () const { return toUInt64(); } + #endif +#endif + + // Get raw pointers so that mpreal can be directly used in raw mpfr_* functions + ::mpfr_ptr mpfr_ptr(); + ::mpfr_srcptr mpfr_ptr() const; + ::mpfr_srcptr mpfr_srcptr() const; + + // Convert mpreal to string with n significant digits in base b + // n = -1 -> convert with the maximum available digits + std::string toString(int n = -1, int b = 10, mp_rnd_t mode = mpreal::get_default_rnd()) const; + +#if (MPFR_VERSION >= MPFR_VERSION_NUM(2,4,0)) + std::string toString(const std::string& format) const; +#endif + + std::ostream& output(std::ostream& os) const; + + // Math Functions + friend const mpreal sqr (const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal sqrt(const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal sqrt(const unsigned long int v, mp_rnd_t rnd_mode); + friend const mpreal cbrt(const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal root(const mpreal& v, unsigned long int k, mp_rnd_t rnd_mode); + friend const mpreal pow (const mpreal& a, const mpreal& b, mp_rnd_t rnd_mode); + friend const mpreal pow (const mpreal& a, const mpz_t b, mp_rnd_t rnd_mode); + friend const mpreal pow (const mpreal& a, const unsigned long int b, mp_rnd_t rnd_mode); + friend const mpreal pow (const mpreal& a, const long int b, mp_rnd_t rnd_mode); + friend const mpreal pow (const unsigned long int a, const mpreal& b, mp_rnd_t rnd_mode); + friend const mpreal pow (const unsigned long int a, const unsigned long int b, mp_rnd_t rnd_mode); + friend const mpreal fabs(const mpreal& v, mp_rnd_t rnd_mode); + + friend const mpreal abs(const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal dim(const mpreal& a, const mpreal& b, mp_rnd_t rnd_mode); + friend inline const mpreal mul_2ui(const mpreal& v, unsigned long int k, mp_rnd_t rnd_mode); + friend inline const mpreal mul_2si(const mpreal& v, long int k, mp_rnd_t rnd_mode); + friend inline const mpreal div_2ui(const mpreal& v, unsigned long int k, mp_rnd_t rnd_mode); + friend inline const mpreal div_2si(const mpreal& v, long int k, mp_rnd_t rnd_mode); + friend int cmpabs(const mpreal& a,const mpreal& b); + + friend const mpreal log (const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal log2 (const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal log10(const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal exp (const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal exp2 (const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal exp10(const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal log1p(const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal expm1(const mpreal& v, mp_rnd_t rnd_mode); + + friend const mpreal cos(const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal sin(const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal tan(const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal sec(const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal csc(const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal cot(const mpreal& v, mp_rnd_t rnd_mode); + friend int sin_cos(mpreal& s, mpreal& c, const mpreal& v, mp_rnd_t rnd_mode); + + friend const mpreal acos (const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal asin (const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal atan (const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal atan2 (const mpreal& y, const mpreal& x, mp_rnd_t rnd_mode); + friend const mpreal acot (const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal asec (const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal acsc (const mpreal& v, mp_rnd_t rnd_mode); + + friend const mpreal cosh (const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal sinh (const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal tanh (const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal sech (const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal csch (const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal coth (const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal acosh (const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal asinh (const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal atanh (const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal acoth (const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal asech (const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal acsch (const mpreal& v, mp_rnd_t rnd_mode); + + friend const mpreal hypot (const mpreal& x, const mpreal& y, mp_rnd_t rnd_mode); + + friend const mpreal fac_ui (unsigned long int v, mp_prec_t prec, mp_rnd_t rnd_mode); + friend const mpreal eint (const mpreal& v, mp_rnd_t rnd_mode); + + friend const mpreal gamma (const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal lngamma (const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal lgamma (const mpreal& v, int *signp, mp_rnd_t rnd_mode); + friend const mpreal zeta (const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal erf (const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal erfc (const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal besselj0 (const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal besselj1 (const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal besseljn (long n, const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal bessely0 (const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal bessely1 (const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal besselyn (long n, const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal fma (const mpreal& v1, const mpreal& v2, const mpreal& v3, mp_rnd_t rnd_mode); + friend const mpreal fms (const mpreal& v1, const mpreal& v2, const mpreal& v3, mp_rnd_t rnd_mode); + friend const mpreal agm (const mpreal& v1, const mpreal& v2, mp_rnd_t rnd_mode); + friend const mpreal sum (const mpreal tab[], unsigned long int n, mp_rnd_t rnd_mode); + friend int sgn(const mpreal& v); // returns -1 or +1 + +// MPFR 2.4.0 Specifics +#if (MPFR_VERSION >= MPFR_VERSION_NUM(2,4,0)) + friend int sinh_cosh (mpreal& s, mpreal& c, const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal li2 (const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal fmod (const mpreal& x, const mpreal& y, mp_rnd_t rnd_mode); + friend const mpreal rec_sqrt (const mpreal& v, mp_rnd_t rnd_mode); + + // MATLAB's semantic equivalents + friend const mpreal rem (const mpreal& x, const mpreal& y, mp_rnd_t rnd_mode); // Remainder after division + friend const mpreal mod (const mpreal& x, const mpreal& y, mp_rnd_t rnd_mode); // Modulus after division +#endif + +// MPFR 3.0.0 Specifics +#if (MPFR_VERSION >= MPFR_VERSION_NUM(3,0,0)) + friend const mpreal digamma (const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal ai (const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal urandom (gmp_randstate_t& state, mp_rnd_t rnd_mode); // use gmp_randinit_default() to init state, gmp_randclear() to clear + friend const mpreal grandom (gmp_randstate_t& state, mp_rnd_t rnd_mode); // use gmp_randinit_default() to init state, gmp_randclear() to clear + friend const mpreal grandom (unsigned int seed); +#endif + + // Uniformly distributed random number generation in [0,1] using + // Mersenne-Twister algorithm by default. + // Use parameter to setup seed, e.g.: random((unsigned)time(NULL)) + // Check urandom() for more precise control. + friend const mpreal random(unsigned int seed); + + // Exponent and mantissa manipulation + friend const mpreal frexp(const mpreal& v, mp_exp_t* exp); + friend const mpreal ldexp(const mpreal& v, mp_exp_t exp); + + // Splits mpreal value into fractional and integer parts. + // Returns fractional part and stores integer part in n. + friend const mpreal modf(const mpreal& v, mpreal& n); + + // Constants + // don't forget to call mpfr_free_cache() for every thread where you are using const-functions + friend const mpreal const_log2 (mp_prec_t prec, mp_rnd_t rnd_mode); + friend const mpreal const_pi (mp_prec_t prec, mp_rnd_t rnd_mode); + friend const mpreal const_euler (mp_prec_t prec, mp_rnd_t rnd_mode); + friend const mpreal const_catalan (mp_prec_t prec, mp_rnd_t rnd_mode); + + // returns +inf iff sign>=0 otherwise -inf + friend const mpreal const_infinity(int sign, mp_prec_t prec); + + // Output/ Input + friend std::ostream& operator<<(std::ostream& os, const mpreal& v); + friend std::istream& operator>>(std::istream& is, mpreal& v); + + // Integer Related Functions + friend const mpreal rint (const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal ceil (const mpreal& v); + friend const mpreal floor(const mpreal& v); + friend const mpreal round(const mpreal& v); + friend const mpreal trunc(const mpreal& v); + friend const mpreal rint_ceil (const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal rint_floor (const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal rint_round (const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal rint_trunc (const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal frac (const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal remainder ( const mpreal& x, const mpreal& y, mp_rnd_t rnd_mode); + friend const mpreal remquo (long* q, const mpreal& x, const mpreal& y, mp_rnd_t rnd_mode); + + // Miscellaneous Functions + friend const mpreal nexttoward (const mpreal& x, const mpreal& y); + friend const mpreal nextabove (const mpreal& x); + friend const mpreal nextbelow (const mpreal& x); + + // use gmp_randinit_default() to init state, gmp_randclear() to clear + friend const mpreal urandomb (gmp_randstate_t& state); + +// MPFR < 2.4.2 Specifics +#if (MPFR_VERSION <= MPFR_VERSION_NUM(2,4,2)) + friend const mpreal random2 (mp_size_t size, mp_exp_t exp); +#endif + + // Instance Checkers + friend bool isnan (const mpreal& v); + friend bool isinf (const mpreal& v); + friend bool isfinite (const mpreal& v); + + friend bool isnum (const mpreal& v); + friend bool iszero (const mpreal& v); + friend bool isint (const mpreal& v); + +#if (MPFR_VERSION >= MPFR_VERSION_NUM(3,0,0)) + friend bool isregular(const mpreal& v); +#endif + + // Set/Get instance properties + inline mp_prec_t get_prec() const; + inline void set_prec(mp_prec_t prec, mp_rnd_t rnd_mode = get_default_rnd()); // Change precision with rounding mode + + // Aliases for get_prec(), set_prec() - needed for compatibility with std::complex interface + inline mpreal& setPrecision(int Precision, mp_rnd_t RoundingMode = get_default_rnd()); + inline int getPrecision() const; + + // Set mpreal to +/- inf, NaN, +/-0 + mpreal& setInf (int Sign = +1); + mpreal& setNan (); + mpreal& setZero (int Sign = +1); + mpreal& setSign (int Sign, mp_rnd_t RoundingMode = get_default_rnd()); + + //Exponent + mp_exp_t get_exp(); + int set_exp(mp_exp_t e); + int check_range (int t, mp_rnd_t rnd_mode = get_default_rnd()); + int subnormalize (int t,mp_rnd_t rnd_mode = get_default_rnd()); + + // Inexact conversion from float + inline bool fits_in_bits(double x, int n); + + // Set/Get global properties + static void set_default_prec(mp_prec_t prec); + static void set_default_rnd(mp_rnd_t rnd_mode); + + static mp_exp_t get_emin (void); + static mp_exp_t get_emax (void); + static mp_exp_t get_emin_min (void); + static mp_exp_t get_emin_max (void); + static mp_exp_t get_emax_min (void); + static mp_exp_t get_emax_max (void); + static int set_emin (mp_exp_t exp); + static int set_emax (mp_exp_t exp); + + // Efficient swapping of two mpreal values - needed for std algorithms + friend void swap(mpreal& x, mpreal& y); + + friend const mpreal fmax(const mpreal& x, const mpreal& y, mp_rnd_t rnd_mode); + friend const mpreal fmin(const mpreal& x, const mpreal& y, mp_rnd_t rnd_mode); + +private: + // Human friendly Debug Preview in Visual Studio. + // Put one of these lines: + // + // mpfr::mpreal= ; Show value only + // mpfr::mpreal=, bits ; Show value & precision + // + // at the beginning of + // [Visual Studio Installation Folder]\Common7\Packages\Debugger\autoexp.dat + MPREAL_MSVC_DEBUGVIEW_DATA + + // "Smart" resources deallocation. Checks if instance initialized before deletion. + void clear(::mpfr_ptr); +}; + +////////////////////////////////////////////////////////////////////////// +// Exceptions +class conversion_overflow : public std::exception { +public: + std::string why() { return "inexact conversion from floating point"; } +}; + +////////////////////////////////////////////////////////////////////////// +// Constructors & converters +// Default constructor: creates mp number and initializes it to 0. +inline mpreal::mpreal() +{ + mpfr_init2 (mpfr_ptr(), mpreal::get_default_prec()); + mpfr_set_ui(mpfr_ptr(), 0, mpreal::get_default_rnd()); + + MPREAL_MSVC_DEBUGVIEW_CODE; +} + +inline mpreal::mpreal(const mpreal& u) +{ + mpfr_init2(mpfr_ptr(),mpfr_get_prec(u.mpfr_srcptr())); + mpfr_set (mpfr_ptr(),u.mpfr_srcptr(),mpreal::get_default_rnd()); + + MPREAL_MSVC_DEBUGVIEW_CODE; +} + +#ifdef MPREAL_HAVE_MOVE_SUPPORT +inline mpreal::mpreal(mpreal&& other) +{ + mpfr_set_uninitialized(mpfr_ptr()); // make sure "other" holds no pinter to actual data + mpfr_swap(mpfr_ptr(), other.mpfr_ptr()); + + MPREAL_MSVC_DEBUGVIEW_CODE; +} + +inline mpreal& mpreal::operator=(mpreal&& other) +{ + mpfr_swap(mpfr_ptr(), other.mpfr_ptr()); + + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} +#endif + +inline mpreal::mpreal(const mpfr_t u, bool shared) +{ + if(shared) + { + std::memcpy(mpfr_ptr(), u, sizeof(mpfr_t)); + } + else + { + mpfr_init2(mpfr_ptr(), mpfr_get_prec(u)); + mpfr_set (mpfr_ptr(), u, mpreal::get_default_rnd()); + } + + MPREAL_MSVC_DEBUGVIEW_CODE; +} + +inline mpreal::mpreal(const mpf_t u) +{ + mpfr_init2(mpfr_ptr(),(mp_prec_t) mpf_get_prec(u)); // (gmp: mp_bitcnt_t) unsigned long -> long (mpfr: mp_prec_t) + mpfr_set_f(mpfr_ptr(),u,mpreal::get_default_rnd()); + + MPREAL_MSVC_DEBUGVIEW_CODE; +} + +inline mpreal::mpreal(const mpz_t u, mp_prec_t prec, mp_rnd_t mode) +{ + mpfr_init2(mpfr_ptr(), prec); + mpfr_set_z(mpfr_ptr(), u, mode); + + MPREAL_MSVC_DEBUGVIEW_CODE; +} + +inline mpreal::mpreal(const mpq_t u, mp_prec_t prec, mp_rnd_t mode) +{ + mpfr_init2(mpfr_ptr(), prec); + mpfr_set_q(mpfr_ptr(), u, mode); + + MPREAL_MSVC_DEBUGVIEW_CODE; +} + +inline mpreal::mpreal(const double u, mp_prec_t prec, mp_rnd_t mode) +{ + mpfr_init2(mpfr_ptr(), prec); + +#if (MPREAL_DOUBLE_BITS_OVERFLOW > -1) + if(fits_in_bits(u, MPREAL_DOUBLE_BITS_OVERFLOW)) + { + mpfr_set_d(mpfr_ptr(), u, mode); + }else + throw conversion_overflow(); +#else + mpfr_set_d(mpfr_ptr(), u, mode); +#endif + + MPREAL_MSVC_DEBUGVIEW_CODE; +} + +inline mpreal::mpreal(const long double u, mp_prec_t prec, mp_rnd_t mode) +{ + mpfr_init2 (mpfr_ptr(), prec); + mpfr_set_ld(mpfr_ptr(), u, mode); + + MPREAL_MSVC_DEBUGVIEW_CODE; +} + +inline mpreal::mpreal(const unsigned long int u, mp_prec_t prec, mp_rnd_t mode) +{ + mpfr_init2 (mpfr_ptr(), prec); + mpfr_set_ui(mpfr_ptr(), u, mode); + + MPREAL_MSVC_DEBUGVIEW_CODE; +} + +inline mpreal::mpreal(const unsigned int u, mp_prec_t prec, mp_rnd_t mode) +{ + mpfr_init2 (mpfr_ptr(), prec); + mpfr_set_ui(mpfr_ptr(), u, mode); + + MPREAL_MSVC_DEBUGVIEW_CODE; +} + +inline mpreal::mpreal(const long int u, mp_prec_t prec, mp_rnd_t mode) +{ + mpfr_init2 (mpfr_ptr(), prec); + mpfr_set_si(mpfr_ptr(), u, mode); + + MPREAL_MSVC_DEBUGVIEW_CODE; +} + +inline mpreal::mpreal(const int u, mp_prec_t prec, mp_rnd_t mode) +{ + mpfr_init2 (mpfr_ptr(), prec); + mpfr_set_si(mpfr_ptr(), u, mode); + + MPREAL_MSVC_DEBUGVIEW_CODE; +} + +#if defined (MPREAL_HAVE_INT64_SUPPORT) +inline mpreal::mpreal(const uint64_t u, mp_prec_t prec, mp_rnd_t mode) +{ + mpfr_init2 (mpfr_ptr(), prec); + mpfr_set_uj(mpfr_ptr(), u, mode); + + MPREAL_MSVC_DEBUGVIEW_CODE; +} + +inline mpreal::mpreal(const int64_t u, mp_prec_t prec, mp_rnd_t mode) +{ + mpfr_init2 (mpfr_ptr(), prec); + mpfr_set_sj(mpfr_ptr(), u, mode); + + MPREAL_MSVC_DEBUGVIEW_CODE; +} +#endif + +inline mpreal::mpreal(const char* s, mp_prec_t prec, int base, mp_rnd_t mode) +{ + mpfr_init2 (mpfr_ptr(), prec); + mpfr_set_str(mpfr_ptr(), s, base, mode); + + MPREAL_MSVC_DEBUGVIEW_CODE; +} + +inline mpreal::mpreal(const std::string& s, mp_prec_t prec, int base, mp_rnd_t mode) +{ + mpfr_init2 (mpfr_ptr(), prec); + mpfr_set_str(mpfr_ptr(), s.c_str(), base, mode); + + MPREAL_MSVC_DEBUGVIEW_CODE; +} + +inline void mpreal::clear(::mpfr_ptr x) +{ +#ifdef MPREAL_HAVE_MOVE_SUPPORT + if(mpfr_is_initialized(x)) +#endif + mpfr_clear(x); +} + +inline mpreal::~mpreal() +{ + clear(mpfr_ptr()); +} + +// internal namespace needed for template magic +namespace internal{ + + // Use SFINAE to restrict arithmetic operations instantiation only for numeric types + // This is needed for smooth integration with libraries based on expression templates, like Eigen. + // TODO: Do the same for boolean operators. + template struct result_type {}; + + template <> struct result_type {typedef mpreal type;}; + template <> struct result_type {typedef mpreal type;}; + template <> struct result_type {typedef mpreal type;}; + template <> struct result_type {typedef mpreal type;}; + template <> struct result_type {typedef mpreal type;}; + template <> struct result_type {typedef mpreal type;}; + template <> struct result_type {typedef mpreal type;}; + template <> struct result_type {typedef mpreal type;}; + template <> struct result_type {typedef mpreal type;}; + +#if defined (MPREAL_HAVE_INT64_SUPPORT) + template <> struct result_type {typedef mpreal type;}; + template <> struct result_type {typedef mpreal type;}; +#endif +} + +// + Addition +template +inline const typename internal::result_type::type + operator+(const mpreal& lhs, const Rhs& rhs){ return mpreal(lhs) += rhs; } + +template +inline const typename internal::result_type::type + operator+(const Lhs& lhs, const mpreal& rhs){ return mpreal(rhs) += lhs; } + +// - Subtraction +template +inline const typename internal::result_type::type + operator-(const mpreal& lhs, const Rhs& rhs){ return mpreal(lhs) -= rhs; } + +template +inline const typename internal::result_type::type + operator-(const Lhs& lhs, const mpreal& rhs){ return mpreal(lhs) -= rhs; } + +// * Multiplication +template +inline const typename internal::result_type::type + operator*(const mpreal& lhs, const Rhs& rhs){ return mpreal(lhs) *= rhs; } + +template +inline const typename internal::result_type::type + operator*(const Lhs& lhs, const mpreal& rhs){ return mpreal(rhs) *= lhs; } + +// / Division +template +inline const typename internal::result_type::type + operator/(const mpreal& lhs, const Rhs& rhs){ return mpreal(lhs) /= rhs; } + +template +inline const typename internal::result_type::type + operator/(const Lhs& lhs, const mpreal& rhs){ return mpreal(lhs) /= rhs; } + +////////////////////////////////////////////////////////////////////////// +// sqrt +const mpreal sqrt(const unsigned int v, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); +const mpreal sqrt(const long int v, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); +const mpreal sqrt(const int v, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); +const mpreal sqrt(const long double v, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); +const mpreal sqrt(const double v, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); + +// abs +inline const mpreal abs(const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()); + +////////////////////////////////////////////////////////////////////////// +// pow +const mpreal pow(const mpreal& a, const unsigned int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); +const mpreal pow(const mpreal& a, const int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); +const mpreal pow(const mpreal& a, const long double b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); +const mpreal pow(const mpreal& a, const double b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); + +const mpreal pow(const unsigned int a, const mpreal& b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); +const mpreal pow(const long int a, const mpreal& b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); +const mpreal pow(const int a, const mpreal& b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); +const mpreal pow(const long double a, const mpreal& b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); +const mpreal pow(const double a, const mpreal& b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); + +const mpreal pow(const unsigned long int a, const unsigned int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); +const mpreal pow(const unsigned long int a, const long int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); +const mpreal pow(const unsigned long int a, const int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); +const mpreal pow(const unsigned long int a, const long double b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); +const mpreal pow(const unsigned long int a, const double b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); + +const mpreal pow(const unsigned int a, const unsigned long int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); +const mpreal pow(const unsigned int a, const unsigned int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); +const mpreal pow(const unsigned int a, const long int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); +const mpreal pow(const unsigned int a, const int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); +const mpreal pow(const unsigned int a, const long double b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); +const mpreal pow(const unsigned int a, const double b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); + +const mpreal pow(const long int a, const unsigned long int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); +const mpreal pow(const long int a, const unsigned int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); +const mpreal pow(const long int a, const long int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); +const mpreal pow(const long int a, const int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); +const mpreal pow(const long int a, const long double b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); +const mpreal pow(const long int a, const double b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); + +const mpreal pow(const int a, const unsigned long int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); +const mpreal pow(const int a, const unsigned int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); +const mpreal pow(const int a, const long int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); +const mpreal pow(const int a, const int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); +const mpreal pow(const int a, const long double b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); +const mpreal pow(const int a, const double b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); + +const mpreal pow(const long double a, const long double b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); +const mpreal pow(const long double a, const unsigned long int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); +const mpreal pow(const long double a, const unsigned int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); +const mpreal pow(const long double a, const long int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); +const mpreal pow(const long double a, const int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); + +const mpreal pow(const double a, const double b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); +const mpreal pow(const double a, const unsigned long int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); +const mpreal pow(const double a, const unsigned int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); +const mpreal pow(const double a, const long int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); +const mpreal pow(const double a, const int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); + +inline const mpreal mul_2ui(const mpreal& v, unsigned long int k, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); +inline const mpreal mul_2si(const mpreal& v, long int k, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); +inline const mpreal div_2ui(const mpreal& v, unsigned long int k, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); +inline const mpreal div_2si(const mpreal& v, long int k, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); + +////////////////////////////////////////////////////////////////////////// +// Estimate machine epsilon for the given precision +// Returns smallest eps such that 1.0 + eps != 1.0 +inline mpreal machine_epsilon(mp_prec_t prec = mpreal::get_default_prec()); + +// Returns smallest eps such that x + eps != x (relative machine epsilon) +inline mpreal machine_epsilon(const mpreal& x); + +// Gives max & min values for the required precision, +// minval is 'safe' meaning 1 / minval does not overflow +// maxval is 'safe' meaning 1 / maxval does not underflow +inline mpreal minval(mp_prec_t prec = mpreal::get_default_prec()); +inline mpreal maxval(mp_prec_t prec = mpreal::get_default_prec()); + +// 'Dirty' equality check 1: |a-b| < min{|a|,|b|} * eps +inline bool isEqualFuzzy(const mpreal& a, const mpreal& b, const mpreal& eps); + +// 'Dirty' equality check 2: |a-b| < min{|a|,|b|} * eps( min{|a|,|b|} ) +inline bool isEqualFuzzy(const mpreal& a, const mpreal& b); + +// 'Bitwise' equality check +// maxUlps - a and b can be apart by maxUlps binary numbers. +inline bool isEqualUlps(const mpreal& a, const mpreal& b, int maxUlps); + +////////////////////////////////////////////////////////////////////////// +// Convert precision in 'bits' to decimal digits and vice versa. +// bits = ceil(digits*log[2](10)) +// digits = floor(bits*log[10](2)) + +inline mp_prec_t digits2bits(int d); +inline int bits2digits(mp_prec_t b); + +////////////////////////////////////////////////////////////////////////// +// min, max +const mpreal (max)(const mpreal& x, const mpreal& y); +const mpreal (min)(const mpreal& x, const mpreal& y); + +////////////////////////////////////////////////////////////////////////// +// Implementation +////////////////////////////////////////////////////////////////////////// + +////////////////////////////////////////////////////////////////////////// +// Operators - Assignment +inline mpreal& mpreal::operator=(const mpreal& v) +{ + if (this != &v) + { + mp_prec_t tp = mpfr_get_prec( mpfr_srcptr()); + mp_prec_t vp = mpfr_get_prec(v.mpfr_srcptr()); + + if(tp != vp){ + clear(mpfr_ptr()); + mpfr_init2(mpfr_ptr(), vp); + } + + mpfr_set(mpfr_ptr(), v.mpfr_srcptr(), mpreal::get_default_rnd()); + + MPREAL_MSVC_DEBUGVIEW_CODE; + } + return *this; +} + +inline mpreal& mpreal::operator=(const mpf_t v) +{ + mpfr_set_f(mpfr_ptr(), v, mpreal::get_default_rnd()); + + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator=(const mpz_t v) +{ + mpfr_set_z(mpfr_ptr(), v, mpreal::get_default_rnd()); + + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator=(const mpq_t v) +{ + mpfr_set_q(mpfr_ptr(), v, mpreal::get_default_rnd()); + + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator=(const long double v) +{ + mpfr_set_ld(mpfr_ptr(), v, mpreal::get_default_rnd()); + + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator=(const double v) +{ +#if (MPREAL_DOUBLE_BITS_OVERFLOW > -1) + if(fits_in_bits(v, MPREAL_DOUBLE_BITS_OVERFLOW)) + { + mpfr_set_d(mpfr_ptr(),v,mpreal::get_default_rnd()); + }else + throw conversion_overflow(); +#else + mpfr_set_d(mpfr_ptr(),v,mpreal::get_default_rnd()); +#endif + + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator=(const unsigned long int v) +{ + mpfr_set_ui(mpfr_ptr(), v, mpreal::get_default_rnd()); + + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator=(const unsigned int v) +{ + mpfr_set_ui(mpfr_ptr(), v, mpreal::get_default_rnd()); + + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator=(const long int v) +{ + mpfr_set_si(mpfr_ptr(), v, mpreal::get_default_rnd()); + + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator=(const int v) +{ + mpfr_set_si(mpfr_ptr(), v, mpreal::get_default_rnd()); + + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator=(const char* s) +{ + // Use other converters for more precise control on base & precision & rounding: + // + // mpreal(const char* s, mp_prec_t prec, int base, mp_rnd_t mode) + // mpreal(const std::string& s,mp_prec_t prec, int base, mp_rnd_t mode) + // + // Here we assume base = 10 and we use precision of target variable. + + mpfr_t t; + + mpfr_init2(t, mpfr_get_prec(mpfr_srcptr())); + + if(0 == mpfr_set_str(t, s, 10, mpreal::get_default_rnd())) + { + mpfr_set(mpfr_ptr(), t, mpreal::get_default_rnd()); + MPREAL_MSVC_DEBUGVIEW_CODE; + } + + clear(t); + return *this; +} + +inline mpreal& mpreal::operator=(const std::string& s) +{ + // Use other converters for more precise control on base & precision & rounding: + // + // mpreal(const char* s, mp_prec_t prec, int base, mp_rnd_t mode) + // mpreal(const std::string& s,mp_prec_t prec, int base, mp_rnd_t mode) + // + // Here we assume base = 10 and we use precision of target variable. + + mpfr_t t; + + mpfr_init2(t, mpfr_get_prec(mpfr_srcptr())); + + if(0 == mpfr_set_str(t, s.c_str(), 10, mpreal::get_default_rnd())) + { + mpfr_set(mpfr_ptr(), t, mpreal::get_default_rnd()); + MPREAL_MSVC_DEBUGVIEW_CODE; + } + + clear(t); + return *this; +} + + +////////////////////////////////////////////////////////////////////////// +// + Addition +inline mpreal& mpreal::operator+=(const mpreal& v) +{ + mpfr_add(mpfr_ptr(), mpfr_srcptr(), v.mpfr_srcptr(), mpreal::get_default_rnd()); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator+=(const mpf_t u) +{ + *this += mpreal(u); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator+=(const mpz_t u) +{ + mpfr_add_z(mpfr_ptr(),mpfr_srcptr(),u,mpreal::get_default_rnd()); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator+=(const mpq_t u) +{ + mpfr_add_q(mpfr_ptr(),mpfr_srcptr(),u,mpreal::get_default_rnd()); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator+= (const long double u) +{ + *this += mpreal(u); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator+= (const double u) +{ +#if (MPFR_VERSION >= MPFR_VERSION_NUM(2,4,0)) + mpfr_add_d(mpfr_ptr(),mpfr_srcptr(),u,mpreal::get_default_rnd()); +#else + *this += mpreal(u); +#endif + + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator+=(const unsigned long int u) +{ + mpfr_add_ui(mpfr_ptr(),mpfr_srcptr(),u,mpreal::get_default_rnd()); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator+=(const unsigned int u) +{ + mpfr_add_ui(mpfr_ptr(),mpfr_srcptr(),u,mpreal::get_default_rnd()); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator+=(const long int u) +{ + mpfr_add_si(mpfr_ptr(),mpfr_srcptr(),u,mpreal::get_default_rnd()); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator+=(const int u) +{ + mpfr_add_si(mpfr_ptr(),mpfr_srcptr(),u,mpreal::get_default_rnd()); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +#if defined (MPREAL_HAVE_INT64_SUPPORT) +inline mpreal& mpreal::operator+=(const int64_t u){ *this += mpreal(u); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } +inline mpreal& mpreal::operator+=(const uint64_t u){ *this += mpreal(u); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } +inline mpreal& mpreal::operator-=(const int64_t u){ *this -= mpreal(u); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } +inline mpreal& mpreal::operator-=(const uint64_t u){ *this -= mpreal(u); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } +inline mpreal& mpreal::operator*=(const int64_t u){ *this *= mpreal(u); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } +inline mpreal& mpreal::operator*=(const uint64_t u){ *this *= mpreal(u); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } +inline mpreal& mpreal::operator/=(const int64_t u){ *this /= mpreal(u); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } +inline mpreal& mpreal::operator/=(const uint64_t u){ *this /= mpreal(u); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } +#endif + +inline const mpreal mpreal::operator+()const { return mpreal(*this); } + +inline const mpreal operator+(const mpreal& a, const mpreal& b) +{ + mpreal c(0, (std::max)(mpfr_get_prec(a.mpfr_ptr()), mpfr_get_prec(b.mpfr_ptr()))); + mpfr_add(c.mpfr_ptr(), a.mpfr_srcptr(), b.mpfr_srcptr(), mpreal::get_default_rnd()); + return c; +} + +inline mpreal& mpreal::operator++() +{ + return *this += 1; +} + +inline const mpreal mpreal::operator++ (int) +{ + mpreal x(*this); + *this += 1; + return x; +} + +inline mpreal& mpreal::operator--() +{ + return *this -= 1; +} + +inline const mpreal mpreal::operator-- (int) +{ + mpreal x(*this); + *this -= 1; + return x; +} + +////////////////////////////////////////////////////////////////////////// +// - Subtraction +inline mpreal& mpreal::operator-=(const mpreal& v) +{ + mpfr_sub(mpfr_ptr(),mpfr_srcptr(),v.mpfr_srcptr(),mpreal::get_default_rnd()); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator-=(const mpz_t v) +{ + mpfr_sub_z(mpfr_ptr(),mpfr_srcptr(),v,mpreal::get_default_rnd()); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator-=(const mpq_t v) +{ + mpfr_sub_q(mpfr_ptr(),mpfr_srcptr(),v,mpreal::get_default_rnd()); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator-=(const long double v) +{ + *this -= mpreal(v); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator-=(const double v) +{ +#if (MPFR_VERSION >= MPFR_VERSION_NUM(2,4,0)) + mpfr_sub_d(mpfr_ptr(),mpfr_srcptr(),v,mpreal::get_default_rnd()); +#else + *this -= mpreal(v); +#endif + + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator-=(const unsigned long int v) +{ + mpfr_sub_ui(mpfr_ptr(),mpfr_srcptr(),v,mpreal::get_default_rnd()); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator-=(const unsigned int v) +{ + mpfr_sub_ui(mpfr_ptr(),mpfr_srcptr(),v,mpreal::get_default_rnd()); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator-=(const long int v) +{ + mpfr_sub_si(mpfr_ptr(),mpfr_srcptr(),v,mpreal::get_default_rnd()); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator-=(const int v) +{ + mpfr_sub_si(mpfr_ptr(),mpfr_srcptr(),v,mpreal::get_default_rnd()); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline const mpreal mpreal::operator-()const +{ + mpreal u(*this); + mpfr_neg(u.mpfr_ptr(),u.mpfr_srcptr(),mpreal::get_default_rnd()); + return u; +} + +inline const mpreal operator-(const mpreal& a, const mpreal& b) +{ + mpreal c(0, (std::max)(mpfr_get_prec(a.mpfr_ptr()), mpfr_get_prec(b.mpfr_ptr()))); + mpfr_sub(c.mpfr_ptr(), a.mpfr_srcptr(), b.mpfr_srcptr(), mpreal::get_default_rnd()); + return c; +} + +inline const mpreal operator-(const double b, const mpreal& a) +{ +#if (MPFR_VERSION >= MPFR_VERSION_NUM(2,4,0)) + mpreal x(0, mpfr_get_prec(a.mpfr_ptr())); + mpfr_d_sub(x.mpfr_ptr(), b, a.mpfr_srcptr(), mpreal::get_default_rnd()); + return x; +#else + mpreal x(b, mpfr_get_prec(a.mpfr_ptr())); + x -= a; + return x; +#endif +} + +inline const mpreal operator-(const unsigned long int b, const mpreal& a) +{ + mpreal x(0, mpfr_get_prec(a.mpfr_ptr())); + mpfr_ui_sub(x.mpfr_ptr(), b, a.mpfr_srcptr(), mpreal::get_default_rnd()); + return x; +} + +inline const mpreal operator-(const unsigned int b, const mpreal& a) +{ + mpreal x(0, mpfr_get_prec(a.mpfr_ptr())); + mpfr_ui_sub(x.mpfr_ptr(), b, a.mpfr_srcptr(), mpreal::get_default_rnd()); + return x; +} + +inline const mpreal operator-(const long int b, const mpreal& a) +{ + mpreal x(0, mpfr_get_prec(a.mpfr_ptr())); + mpfr_si_sub(x.mpfr_ptr(), b, a.mpfr_srcptr(), mpreal::get_default_rnd()); + return x; +} + +inline const mpreal operator-(const int b, const mpreal& a) +{ + mpreal x(0, mpfr_get_prec(a.mpfr_ptr())); + mpfr_si_sub(x.mpfr_ptr(), b, a.mpfr_srcptr(), mpreal::get_default_rnd()); + return x; +} + +////////////////////////////////////////////////////////////////////////// +// * Multiplication +inline mpreal& mpreal::operator*= (const mpreal& v) +{ + mpfr_mul(mpfr_ptr(),mpfr_srcptr(),v.mpfr_srcptr(),mpreal::get_default_rnd()); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator*=(const mpz_t v) +{ + mpfr_mul_z(mpfr_ptr(),mpfr_srcptr(),v,mpreal::get_default_rnd()); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator*=(const mpq_t v) +{ + mpfr_mul_q(mpfr_ptr(),mpfr_srcptr(),v,mpreal::get_default_rnd()); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator*=(const long double v) +{ + *this *= mpreal(v); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator*=(const double v) +{ +#if (MPFR_VERSION >= MPFR_VERSION_NUM(2,4,0)) + mpfr_mul_d(mpfr_ptr(),mpfr_srcptr(),v,mpreal::get_default_rnd()); +#else + *this *= mpreal(v); +#endif + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator*=(const unsigned long int v) +{ + mpfr_mul_ui(mpfr_ptr(),mpfr_srcptr(),v,mpreal::get_default_rnd()); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator*=(const unsigned int v) +{ + mpfr_mul_ui(mpfr_ptr(),mpfr_srcptr(),v,mpreal::get_default_rnd()); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator*=(const long int v) +{ + mpfr_mul_si(mpfr_ptr(),mpfr_srcptr(),v,mpreal::get_default_rnd()); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator*=(const int v) +{ + mpfr_mul_si(mpfr_ptr(),mpfr_srcptr(),v,mpreal::get_default_rnd()); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline const mpreal operator*(const mpreal& a, const mpreal& b) +{ + mpreal c(0, (std::max)(mpfr_get_prec(a.mpfr_ptr()), mpfr_get_prec(b.mpfr_ptr()))); + mpfr_mul(c.mpfr_ptr(), a.mpfr_srcptr(), b.mpfr_srcptr(), mpreal::get_default_rnd()); + return c; +} + +////////////////////////////////////////////////////////////////////////// +// / Division +inline mpreal& mpreal::operator/=(const mpreal& v) +{ + mpfr_div(mpfr_ptr(),mpfr_srcptr(),v.mpfr_srcptr(),mpreal::get_default_rnd()); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator/=(const mpz_t v) +{ + mpfr_div_z(mpfr_ptr(),mpfr_srcptr(),v,mpreal::get_default_rnd()); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator/=(const mpq_t v) +{ + mpfr_div_q(mpfr_ptr(),mpfr_srcptr(),v,mpreal::get_default_rnd()); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator/=(const long double v) +{ + *this /= mpreal(v); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator/=(const double v) +{ +#if (MPFR_VERSION >= MPFR_VERSION_NUM(2,4,0)) + mpfr_div_d(mpfr_ptr(),mpfr_srcptr(),v,mpreal::get_default_rnd()); +#else + *this /= mpreal(v); +#endif + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator/=(const unsigned long int v) +{ + mpfr_div_ui(mpfr_ptr(),mpfr_srcptr(),v,mpreal::get_default_rnd()); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator/=(const unsigned int v) +{ + mpfr_div_ui(mpfr_ptr(),mpfr_srcptr(),v,mpreal::get_default_rnd()); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator/=(const long int v) +{ + mpfr_div_si(mpfr_ptr(),mpfr_srcptr(),v,mpreal::get_default_rnd()); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator/=(const int v) +{ + mpfr_div_si(mpfr_ptr(),mpfr_srcptr(),v,mpreal::get_default_rnd()); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline const mpreal operator/(const mpreal& a, const mpreal& b) +{ + mpreal c(0, (std::max)(mpfr_get_prec(a.mpfr_srcptr()), mpfr_get_prec(b.mpfr_srcptr()))); + mpfr_div(c.mpfr_ptr(), a.mpfr_srcptr(), b.mpfr_srcptr(), mpreal::get_default_rnd()); + return c; +} + +inline const mpreal operator/(const unsigned long int b, const mpreal& a) +{ + mpreal x(0, mpfr_get_prec(a.mpfr_srcptr())); + mpfr_ui_div(x.mpfr_ptr(), b, a.mpfr_srcptr(), mpreal::get_default_rnd()); + return x; +} + +inline const mpreal operator/(const unsigned int b, const mpreal& a) +{ + mpreal x(0, mpfr_get_prec(a.mpfr_srcptr())); + mpfr_ui_div(x.mpfr_ptr(), b, a.mpfr_srcptr(), mpreal::get_default_rnd()); + return x; +} + +inline const mpreal operator/(const long int b, const mpreal& a) +{ + mpreal x(0, mpfr_get_prec(a.mpfr_srcptr())); + mpfr_si_div(x.mpfr_ptr(), b, a.mpfr_srcptr(), mpreal::get_default_rnd()); + return x; +} + +inline const mpreal operator/(const int b, const mpreal& a) +{ + mpreal x(0, mpfr_get_prec(a.mpfr_srcptr())); + mpfr_si_div(x.mpfr_ptr(), b, a.mpfr_srcptr(), mpreal::get_default_rnd()); + return x; +} + +inline const mpreal operator/(const double b, const mpreal& a) +{ +#if (MPFR_VERSION >= MPFR_VERSION_NUM(2,4,0)) + mpreal x(0, mpfr_get_prec(a.mpfr_srcptr())); + mpfr_d_div(x.mpfr_ptr(), b, a.mpfr_srcptr(), mpreal::get_default_rnd()); + return x; +#else + mpreal x(0, mpfr_get_prec(a.mpfr_ptr())); + x /= a; + return x; +#endif +} + +////////////////////////////////////////////////////////////////////////// +// Shifts operators - Multiplication/Division by power of 2 +inline mpreal& mpreal::operator<<=(const unsigned long int u) +{ + mpfr_mul_2ui(mpfr_ptr(),mpfr_srcptr(),u,mpreal::get_default_rnd()); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator<<=(const unsigned int u) +{ + mpfr_mul_2ui(mpfr_ptr(),mpfr_srcptr(),static_cast(u),mpreal::get_default_rnd()); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator<<=(const long int u) +{ + mpfr_mul_2si(mpfr_ptr(),mpfr_srcptr(),u,mpreal::get_default_rnd()); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator<<=(const int u) +{ + mpfr_mul_2si(mpfr_ptr(),mpfr_srcptr(),static_cast(u),mpreal::get_default_rnd()); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator>>=(const unsigned long int u) +{ + mpfr_div_2ui(mpfr_ptr(),mpfr_srcptr(),u,mpreal::get_default_rnd()); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator>>=(const unsigned int u) +{ + mpfr_div_2ui(mpfr_ptr(),mpfr_srcptr(),static_cast(u),mpreal::get_default_rnd()); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator>>=(const long int u) +{ + mpfr_div_2si(mpfr_ptr(),mpfr_srcptr(),u,mpreal::get_default_rnd()); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator>>=(const int u) +{ + mpfr_div_2si(mpfr_ptr(),mpfr_srcptr(),static_cast(u),mpreal::get_default_rnd()); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline const mpreal operator<<(const mpreal& v, const unsigned long int k) +{ + return mul_2ui(v,k); +} + +inline const mpreal operator<<(const mpreal& v, const unsigned int k) +{ + return mul_2ui(v,static_cast(k)); +} + +inline const mpreal operator<<(const mpreal& v, const long int k) +{ + return mul_2si(v,k); +} + +inline const mpreal operator<<(const mpreal& v, const int k) +{ + return mul_2si(v,static_cast(k)); +} + +inline const mpreal operator>>(const mpreal& v, const unsigned long int k) +{ + return div_2ui(v,k); +} + +inline const mpreal operator>>(const mpreal& v, const long int k) +{ + return div_2si(v,k); +} + +inline const mpreal operator>>(const mpreal& v, const unsigned int k) +{ + return div_2ui(v,static_cast(k)); +} + +inline const mpreal operator>>(const mpreal& v, const int k) +{ + return div_2si(v,static_cast(k)); +} + +// mul_2ui +inline const mpreal mul_2ui(const mpreal& v, unsigned long int k, mp_rnd_t rnd_mode) +{ + mpreal x(v); + mpfr_mul_2ui(x.mpfr_ptr(),v.mpfr_srcptr(),k,rnd_mode); + return x; +} + +// mul_2si +inline const mpreal mul_2si(const mpreal& v, long int k, mp_rnd_t rnd_mode) +{ + mpreal x(v); + mpfr_mul_2si(x.mpfr_ptr(),v.mpfr_srcptr(),k,rnd_mode); + return x; +} + +inline const mpreal div_2ui(const mpreal& v, unsigned long int k, mp_rnd_t rnd_mode) +{ + mpreal x(v); + mpfr_div_2ui(x.mpfr_ptr(),v.mpfr_srcptr(),k,rnd_mode); + return x; +} + +inline const mpreal div_2si(const mpreal& v, long int k, mp_rnd_t rnd_mode) +{ + mpreal x(v); + mpfr_div_2si(x.mpfr_ptr(),v.mpfr_srcptr(),k,rnd_mode); + return x; +} + +////////////////////////////////////////////////////////////////////////// +//Boolean operators +inline bool operator > (const mpreal& a, const mpreal& b){ return (mpfr_greater_p (a.mpfr_srcptr(),b.mpfr_srcptr()) !=0 ); } +inline bool operator >= (const mpreal& a, const mpreal& b){ return (mpfr_greaterequal_p (a.mpfr_srcptr(),b.mpfr_srcptr()) !=0 ); } +inline bool operator < (const mpreal& a, const mpreal& b){ return (mpfr_less_p (a.mpfr_srcptr(),b.mpfr_srcptr()) !=0 ); } +inline bool operator <= (const mpreal& a, const mpreal& b){ return (mpfr_lessequal_p (a.mpfr_srcptr(),b.mpfr_srcptr()) !=0 ); } +inline bool operator == (const mpreal& a, const mpreal& b){ return (mpfr_equal_p (a.mpfr_srcptr(),b.mpfr_srcptr()) !=0 ); } +inline bool operator != (const mpreal& a, const mpreal& b){ return (mpfr_lessgreater_p (a.mpfr_srcptr(),b.mpfr_srcptr()) !=0 ); } + +inline bool operator == (const mpreal& a, const unsigned long int b ){ return (mpfr_cmp_ui(a.mpfr_srcptr(),b) == 0 ); } +inline bool operator == (const mpreal& a, const unsigned int b ){ return (mpfr_cmp_ui(a.mpfr_srcptr(),b) == 0 ); } +inline bool operator == (const mpreal& a, const long int b ){ return (mpfr_cmp_si(a.mpfr_srcptr(),b) == 0 ); } +inline bool operator == (const mpreal& a, const int b ){ return (mpfr_cmp_si(a.mpfr_srcptr(),b) == 0 ); } +inline bool operator == (const mpreal& a, const long double b ){ return (mpfr_cmp_ld(a.mpfr_srcptr(),b) == 0 ); } +inline bool operator == (const mpreal& a, const double b ){ return (mpfr_cmp_d (a.mpfr_srcptr(),b) == 0 ); } + + +inline bool isnan (const mpreal& op){ return (mpfr_nan_p (op.mpfr_srcptr()) != 0 ); } +inline bool isinf (const mpreal& op){ return (mpfr_inf_p (op.mpfr_srcptr()) != 0 ); } +inline bool isfinite (const mpreal& op){ return (mpfr_number_p (op.mpfr_srcptr()) != 0 ); } +inline bool iszero (const mpreal& op){ return (mpfr_zero_p (op.mpfr_srcptr()) != 0 ); } +inline bool isint (const mpreal& op){ return (mpfr_integer_p(op.mpfr_srcptr()) != 0 ); } + +#if (MPFR_VERSION >= MPFR_VERSION_NUM(3,0,0)) +inline bool isregular(const mpreal& op){ return (mpfr_regular_p(op.mpfr_srcptr()));} +#endif + +////////////////////////////////////////////////////////////////////////// +// Type Converters +inline bool mpreal::toBool (mp_rnd_t /*mode*/) const { return mpfr_zero_p (mpfr_srcptr()) == 0; } +inline long mpreal::toLong (mp_rnd_t mode) const { return mpfr_get_si (mpfr_srcptr(), mode); } +inline unsigned long mpreal::toULong (mp_rnd_t mode) const { return mpfr_get_ui (mpfr_srcptr(), mode); } +inline float mpreal::toFloat (mp_rnd_t mode) const { return mpfr_get_flt(mpfr_srcptr(), mode); } +inline double mpreal::toDouble (mp_rnd_t mode) const { return mpfr_get_d (mpfr_srcptr(), mode); } +inline long double mpreal::toLDouble(mp_rnd_t mode) const { return mpfr_get_ld (mpfr_srcptr(), mode); } + +#if defined (MPREAL_HAVE_INT64_SUPPORT) +inline int64_t mpreal::toInt64 (mp_rnd_t mode) const{ return mpfr_get_sj(mpfr_srcptr(), mode); } +inline uint64_t mpreal::toUInt64(mp_rnd_t mode) const{ return mpfr_get_uj(mpfr_srcptr(), mode); } +#endif + +inline ::mpfr_ptr mpreal::mpfr_ptr() { return mp; } +inline ::mpfr_srcptr mpreal::mpfr_ptr() const { return mp; } +inline ::mpfr_srcptr mpreal::mpfr_srcptr() const { return mp; } + +template +inline std::string toString(T t, std::ios_base & (*f)(std::ios_base&)) +{ + std::ostringstream oss; + oss << f << t; + return oss.str(); +} + +#if (MPFR_VERSION >= MPFR_VERSION_NUM(2,4,0)) + +inline std::string mpreal::toString(const std::string& format) const +{ + char *s = NULL; + std::string out; + + if( !format.empty() ) + { + if(!(mpfr_asprintf(&s, format.c_str(), mpfr_srcptr()) < 0)) + { + out = std::string(s); + + mpfr_free_str(s); + } + } + + return out; +} + +#endif + +inline std::string mpreal::toString(int n, int b, mp_rnd_t mode) const +{ + // TODO: Add extended format specification (f, e, rounding mode) as it done in output operator + (void)b; + (void)mode; + +#if (MPFR_VERSION >= MPFR_VERSION_NUM(2,4,0)) + + std::ostringstream format; + + int digits = (n >= 0) ? n : bits2digits(mpfr_get_prec(mpfr_srcptr())); + + format << "%." << digits << "RNg"; + + return toString(format.str()); + +#else + + char *s, *ns = NULL; + size_t slen, nslen; + mp_exp_t exp; + std::string out; + + if(mpfr_inf_p(mp)) + { + if(mpfr_sgn(mp)>0) return "+Inf"; + else return "-Inf"; + } + + if(mpfr_zero_p(mp)) return "0"; + if(mpfr_nan_p(mp)) return "NaN"; + + s = mpfr_get_str(NULL, &exp, b, 0, mp, mode); + ns = mpfr_get_str(NULL, &exp, b, (std::max)(0,n), mp, mode); + + if(s!=NULL && ns!=NULL) + { + slen = strlen(s); + nslen = strlen(ns); + if(nslen<=slen) + { + mpfr_free_str(s); + s = ns; + slen = nslen; + } + else { + mpfr_free_str(ns); + } + + // Make human eye-friendly formatting if possible + if (exp>0 && static_cast(exp)s+exp) ptr--; + + if(ptr==s+exp) out = std::string(s,exp+1); + else out = std::string(s,exp+1)+'.'+std::string(s+exp+1,ptr-(s+exp+1)+1); + + //out = string(s,exp+1)+'.'+string(s+exp+1); + } + else + { + // Remove zeros starting from right end + char* ptr = s+slen-1; + while (*ptr=='0' && ptr>s+exp-1) ptr--; + + if(ptr==s+exp-1) out = std::string(s,exp); + else out = std::string(s,exp)+'.'+std::string(s+exp,ptr-(s+exp)+1); + + //out = string(s,exp)+'.'+string(s+exp); + } + + }else{ // exp<0 || exp>slen + if(s[0]=='-') + { + // Remove zeros starting from right end + char* ptr = s+slen-1; + while (*ptr=='0' && ptr>s+1) ptr--; + + if(ptr==s+1) out = std::string(s,2); + else out = std::string(s,2)+'.'+std::string(s+2,ptr-(s+2)+1); + + //out = string(s,2)+'.'+string(s+2); + } + else + { + // Remove zeros starting from right end + char* ptr = s+slen-1; + while (*ptr=='0' && ptr>s) ptr--; + + if(ptr==s) out = std::string(s,1); + else out = std::string(s,1)+'.'+std::string(s+1,ptr-(s+1)+1); + + //out = string(s,1)+'.'+string(s+1); + } + + // Make final string + if(--exp) + { + if(exp>0) out += "e+"+mpfr::toString(exp,std::dec); + else out += "e"+mpfr::toString(exp,std::dec); + } + } + + mpfr_free_str(s); + return out; + }else{ + return "conversion error!"; + } +#endif +} + + +////////////////////////////////////////////////////////////////////////// +// I/O +inline std::ostream& mpreal::output(std::ostream& os) const +{ + std::ostringstream format; + const std::ios::fmtflags flags = os.flags(); + + format << ((flags & std::ios::showpos) ? "%+" : "%"); + if (os.precision() >= 0) + format << '.' << os.precision() << "R*" + << ((flags & std::ios::floatfield) == std::ios::fixed ? 'f' : + (flags & std::ios::floatfield) == std::ios::scientific ? 'e' : + 'g'); + else + format << "R*e"; + + char *s = NULL; + if(!(mpfr_asprintf(&s, format.str().c_str(), + mpfr::mpreal::get_default_rnd(), + mpfr_srcptr()) + < 0)) + { + os << std::string(s); + mpfr_free_str(s); + } + return os; +} + +inline std::ostream& operator<<(std::ostream& os, const mpreal& v) +{ + return v.output(os); +} + +inline std::istream& operator>>(std::istream &is, mpreal& v) +{ + // TODO: use cout::hexfloat and other flags to setup base + std::string tmp; + is >> tmp; + mpfr_set_str(v.mpfr_ptr(), tmp.c_str(), 10, mpreal::get_default_rnd()); + return is; +} + +////////////////////////////////////////////////////////////////////////// +// Bits - decimal digits relation +// bits = ceil(digits*log[2](10)) +// digits = floor(bits*log[10](2)) + +inline mp_prec_t digits2bits(int d) +{ + const double LOG2_10 = 3.3219280948873624; + + return mp_prec_t(std::ceil( d * LOG2_10 )); +} + +inline int bits2digits(mp_prec_t b) +{ + const double LOG10_2 = 0.30102999566398119; + + return int(std::floor( b * LOG10_2 )); +} + +////////////////////////////////////////////////////////////////////////// +// Set/Get number properties +inline int sgn(const mpreal& op) +{ + int r = mpfr_signbit(op.mpfr_srcptr()); + return (r > 0? -1 : 1); +} + +inline mpreal& mpreal::setSign(int sign, mp_rnd_t RoundingMode) +{ + mpfr_setsign(mpfr_ptr(), mpfr_srcptr(), (sign < 0 ? 1 : 0), RoundingMode); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline int mpreal::getPrecision() const +{ + return int(mpfr_get_prec(mpfr_srcptr())); +} + +inline mpreal& mpreal::setPrecision(int Precision, mp_rnd_t RoundingMode) +{ + mpfr_prec_round(mpfr_ptr(), Precision, RoundingMode); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::setInf(int sign) +{ + mpfr_set_inf(mpfr_ptr(), sign); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::setNan() +{ + mpfr_set_nan(mpfr_ptr()); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::setZero(int sign) +{ + +#if (MPFR_VERSION >= MPFR_VERSION_NUM(3,0,0)) + mpfr_set_zero(mpfr_ptr(), sign); +#else + mpfr_set_si(mpfr_ptr(), 0, (mpfr_get_default_rounding_mode)()); + setSign(sign); +#endif + + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mp_prec_t mpreal::get_prec() const +{ + return mpfr_get_prec(mpfr_srcptr()); +} + +inline void mpreal::set_prec(mp_prec_t prec, mp_rnd_t rnd_mode) +{ + mpfr_prec_round(mpfr_ptr(),prec,rnd_mode); + MPREAL_MSVC_DEBUGVIEW_CODE; +} + +inline mp_exp_t mpreal::get_exp () +{ + return mpfr_get_exp(mpfr_srcptr()); +} + +inline int mpreal::set_exp (mp_exp_t e) +{ + int x = mpfr_set_exp(mpfr_ptr(), e); + MPREAL_MSVC_DEBUGVIEW_CODE; + return x; +} + +inline const mpreal frexp(const mpreal& v, mp_exp_t* exp) +{ + mpreal x(v); + *exp = x.get_exp(); + x.set_exp(0); + return x; +} + +inline const mpreal ldexp(const mpreal& v, mp_exp_t exp) +{ + mpreal x(v); + + // rounding is not important since we just increasing the exponent + mpfr_mul_2si(x.mpfr_ptr(), x.mpfr_srcptr(), exp, mpreal::get_default_rnd()); + return x; +} + +inline mpreal machine_epsilon(mp_prec_t prec) +{ + /* the smallest eps such that 1 + eps != 1 */ + return machine_epsilon(mpreal(1, prec)); +} + +inline mpreal machine_epsilon(const mpreal& x) +{ + /* the smallest eps such that x + eps != x */ + if( x < 0) + { + return nextabove(-x) + x; + }else{ + return nextabove( x) - x; + } +} + +// minval is 'safe' meaning 1 / minval does not overflow +inline mpreal minval(mp_prec_t prec) +{ + /* min = 1/2 * 2^emin = 2^(emin - 1) */ + return mpreal(1, prec) << mpreal::get_emin()-1; +} + +// maxval is 'safe' meaning 1 / maxval does not underflow +inline mpreal maxval(mp_prec_t prec) +{ + /* max = (1 - eps) * 2^emax, eps is machine epsilon */ + return (mpreal(1, prec) - machine_epsilon(prec)) << mpreal::get_emax(); +} + +inline bool isEqualUlps(const mpreal& a, const mpreal& b, int maxUlps) +{ + return abs(a - b) <= machine_epsilon((max)(abs(a), abs(b))) * maxUlps; +} + +inline bool isEqualFuzzy(const mpreal& a, const mpreal& b, const mpreal& eps) +{ + return abs(a - b) <= eps; +} + +inline bool isEqualFuzzy(const mpreal& a, const mpreal& b) +{ + return isEqualFuzzy(a, b, machine_epsilon((max)(1, (min)(abs(a), abs(b))))); +} + +inline const mpreal modf(const mpreal& v, mpreal& n) +{ + mpreal f(v); + + // rounding is not important since we are using the same number + mpfr_frac (f.mpfr_ptr(),f.mpfr_srcptr(),mpreal::get_default_rnd()); + mpfr_trunc(n.mpfr_ptr(),v.mpfr_srcptr()); + return f; +} + +inline int mpreal::check_range (int t, mp_rnd_t rnd_mode) +{ + return mpfr_check_range(mpfr_ptr(),t,rnd_mode); +} + +inline int mpreal::subnormalize (int t,mp_rnd_t rnd_mode) +{ + int r = mpfr_subnormalize(mpfr_ptr(),t,rnd_mode); + MPREAL_MSVC_DEBUGVIEW_CODE; + return r; +} + +inline mp_exp_t mpreal::get_emin (void) +{ + return mpfr_get_emin(); +} + +inline int mpreal::set_emin (mp_exp_t exp) +{ + return mpfr_set_emin(exp); +} + +inline mp_exp_t mpreal::get_emax (void) +{ + return mpfr_get_emax(); +} + +inline int mpreal::set_emax (mp_exp_t exp) +{ + return mpfr_set_emax(exp); +} + +inline mp_exp_t mpreal::get_emin_min (void) +{ + return mpfr_get_emin_min(); +} + +inline mp_exp_t mpreal::get_emin_max (void) +{ + return mpfr_get_emin_max(); +} + +inline mp_exp_t mpreal::get_emax_min (void) +{ + return mpfr_get_emax_min(); +} + +inline mp_exp_t mpreal::get_emax_max (void) +{ + return mpfr_get_emax_max(); +} + +////////////////////////////////////////////////////////////////////////// +// Mathematical Functions +////////////////////////////////////////////////////////////////////////// +#define MPREAL_UNARY_MATH_FUNCTION_BODY(f) \ + mpreal y(0, mpfr_get_prec(x.mpfr_srcptr())); \ + mpfr_##f(y.mpfr_ptr(), x.mpfr_srcptr(), r); \ + return y; + +inline const mpreal sqr (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) +{ MPREAL_UNARY_MATH_FUNCTION_BODY(sqr ); } + +inline const mpreal sqrt (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) +{ MPREAL_UNARY_MATH_FUNCTION_BODY(sqrt); } + +inline const mpreal sqrt(const unsigned long int x, mp_rnd_t r) +{ + mpreal y; + mpfr_sqrt_ui(y.mpfr_ptr(), x, r); + return y; +} + +inline const mpreal sqrt(const unsigned int v, mp_rnd_t rnd_mode) +{ + return sqrt(static_cast(v),rnd_mode); +} + +inline const mpreal sqrt(const long int v, mp_rnd_t rnd_mode) +{ + if (v>=0) return sqrt(static_cast(v),rnd_mode); + else return mpreal().setNan(); // NaN +} + +inline const mpreal sqrt(const int v, mp_rnd_t rnd_mode) +{ + if (v>=0) return sqrt(static_cast(v),rnd_mode); + else return mpreal().setNan(); // NaN +} + +inline const mpreal root(const mpreal& x, unsigned long int k, mp_rnd_t r = mpreal::get_default_rnd()) +{ + mpreal y(0, mpfr_get_prec(x.mpfr_srcptr())); + mpfr_root(y.mpfr_ptr(), x.mpfr_srcptr(), k, r); + return y; +} + +inline const mpreal dim(const mpreal& a, const mpreal& b, mp_rnd_t r = mpreal::get_default_rnd()) +{ + mpreal y(0, mpfr_get_prec(a.mpfr_srcptr())); + mpfr_dim(y.mpfr_ptr(), a.mpfr_srcptr(), b.mpfr_srcptr(), r); + return y; +} + +inline int cmpabs(const mpreal& a,const mpreal& b) +{ + return mpfr_cmpabs(a.mpfr_ptr(), b.mpfr_srcptr()); +} + +inline int sin_cos(mpreal& s, mpreal& c, const mpreal& v, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) +{ + return mpfr_sin_cos(s.mpfr_ptr(), c.mpfr_ptr(), v.mpfr_srcptr(), rnd_mode); +} + +inline const mpreal sqrt (const long double v, mp_rnd_t rnd_mode) { return sqrt(mpreal(v),rnd_mode); } +inline const mpreal sqrt (const double v, mp_rnd_t rnd_mode) { return sqrt(mpreal(v),rnd_mode); } + +inline const mpreal cbrt (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(cbrt ); } +inline const mpreal fabs (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(abs ); } +inline const mpreal abs (const mpreal& x, mp_rnd_t r) { MPREAL_UNARY_MATH_FUNCTION_BODY(abs ); } +inline const mpreal log (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(log ); } +inline const mpreal log2 (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(log2 ); } +inline const mpreal log10 (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(log10); } +inline const mpreal exp (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(exp ); } +inline const mpreal exp2 (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(exp2 ); } +inline const mpreal exp10 (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(exp10); } +inline const mpreal cos (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(cos ); } +inline const mpreal sin (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(sin ); } +inline const mpreal tan (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(tan ); } +inline const mpreal sec (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(sec ); } +inline const mpreal csc (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(csc ); } +inline const mpreal cot (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(cot ); } +inline const mpreal acos (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(acos ); } +inline const mpreal asin (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(asin ); } +inline const mpreal atan (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(atan ); } + +inline const mpreal acot (const mpreal& v, mp_rnd_t r = mpreal::get_default_rnd()) { return atan (1/v, r); } +inline const mpreal asec (const mpreal& v, mp_rnd_t r = mpreal::get_default_rnd()) { return acos (1/v, r); } +inline const mpreal acsc (const mpreal& v, mp_rnd_t r = mpreal::get_default_rnd()) { return asin (1/v, r); } +inline const mpreal acoth (const mpreal& v, mp_rnd_t r = mpreal::get_default_rnd()) { return atanh(1/v, r); } +inline const mpreal asech (const mpreal& v, mp_rnd_t r = mpreal::get_default_rnd()) { return acosh(1/v, r); } +inline const mpreal acsch (const mpreal& v, mp_rnd_t r = mpreal::get_default_rnd()) { return asinh(1/v, r); } + +inline const mpreal cosh (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(cosh ); } +inline const mpreal sinh (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(sinh ); } +inline const mpreal tanh (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(tanh ); } +inline const mpreal sech (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(sech ); } +inline const mpreal csch (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(csch ); } +inline const mpreal coth (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(coth ); } +inline const mpreal acosh (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(acosh); } +inline const mpreal asinh (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(asinh); } +inline const mpreal atanh (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(atanh); } + +inline const mpreal log1p (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(log1p ); } +inline const mpreal expm1 (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(expm1 ); } +inline const mpreal eint (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(eint ); } +inline const mpreal gamma (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(gamma ); } +inline const mpreal lngamma (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(lngamma); } +inline const mpreal zeta (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(zeta ); } +inline const mpreal erf (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(erf ); } +inline const mpreal erfc (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(erfc ); } +inline const mpreal besselj0(const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(j0 ); } +inline const mpreal besselj1(const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(j1 ); } +inline const mpreal bessely0(const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(y0 ); } +inline const mpreal bessely1(const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(y1 ); } + +inline const mpreal atan2 (const mpreal& y, const mpreal& x, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) +{ + mpreal a(0,(std::max)(y.getPrecision(), x.getPrecision())); + mpfr_atan2(a.mpfr_ptr(), y.mpfr_srcptr(), x.mpfr_srcptr(), rnd_mode); + return a; +} + +inline const mpreal hypot (const mpreal& x, const mpreal& y, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) +{ + mpreal a(0,(std::max)(y.getPrecision(), x.getPrecision())); + mpfr_hypot(a.mpfr_ptr(), x.mpfr_srcptr(), y.mpfr_srcptr(), rnd_mode); + return a; +} + +inline const mpreal remainder (const mpreal& x, const mpreal& y, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) +{ + mpreal a(0,(std::max)(y.getPrecision(), x.getPrecision())); + mpfr_remainder(a.mpfr_ptr(), x.mpfr_srcptr(), y.mpfr_srcptr(), rnd_mode); + return a; +} + +inline const mpreal remquo (long* q, const mpreal& x, const mpreal& y, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) +{ + mpreal a(0,(std::max)(y.getPrecision(), x.getPrecision())); + mpfr_remquo(a.mpfr_ptr(),q, x.mpfr_srcptr(), y.mpfr_srcptr(), rnd_mode); + return a; +} + +inline const mpreal fac_ui (unsigned long int v, mp_prec_t prec = mpreal::get_default_prec(), + mp_rnd_t rnd_mode = mpreal::get_default_rnd()) +{ + mpreal x(0, prec); + mpfr_fac_ui(x.mpfr_ptr(),v,rnd_mode); + return x; +} + + +inline const mpreal lgamma (const mpreal& v, int *signp = 0, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) +{ + mpreal x(v); + int tsignp; + + if(signp) mpfr_lgamma(x.mpfr_ptr(), signp,v.mpfr_srcptr(),rnd_mode); + else mpfr_lgamma(x.mpfr_ptr(),&tsignp,v.mpfr_srcptr(),rnd_mode); + + return x; +} + + +inline const mpreal besseljn (long n, const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) +{ + mpreal y(0, x.getPrecision()); + mpfr_jn(y.mpfr_ptr(), n, x.mpfr_srcptr(), r); + return y; +} + +inline const mpreal besselyn (long n, const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) +{ + mpreal y(0, x.getPrecision()); + mpfr_yn(y.mpfr_ptr(), n, x.mpfr_srcptr(), r); + return y; +} + +inline const mpreal fma (const mpreal& v1, const mpreal& v2, const mpreal& v3, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) +{ + mpreal a; + mp_prec_t p1, p2, p3; + + p1 = v1.get_prec(); + p2 = v2.get_prec(); + p3 = v3.get_prec(); + + a.set_prec(p3>p2?(p3>p1?p3:p1):(p2>p1?p2:p1)); + + mpfr_fma(a.mp,v1.mp,v2.mp,v3.mp,rnd_mode); + return a; +} + +inline const mpreal fms (const mpreal& v1, const mpreal& v2, const mpreal& v3, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) +{ + mpreal a; + mp_prec_t p1, p2, p3; + + p1 = v1.get_prec(); + p2 = v2.get_prec(); + p3 = v3.get_prec(); + + a.set_prec(p3>p2?(p3>p1?p3:p1):(p2>p1?p2:p1)); + + mpfr_fms(a.mp,v1.mp,v2.mp,v3.mp,rnd_mode); + return a; +} + +inline const mpreal agm (const mpreal& v1, const mpreal& v2, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) +{ + mpreal a; + mp_prec_t p1, p2; + + p1 = v1.get_prec(); + p2 = v2.get_prec(); + + a.set_prec(p1>p2?p1:p2); + + mpfr_agm(a.mp, v1.mp, v2.mp, rnd_mode); + + return a; +} + +inline const mpreal sum (const mpreal tab[], unsigned long int n, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) +{ + mpreal x; + mpfr_ptr* t; + unsigned long int i; + + t = new mpfr_ptr[n]; + for (i=0;i= MPFR_VERSION_NUM(2,4,0)) + +inline int sinh_cosh(mpreal& s, mpreal& c, const mpreal& v, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) +{ + return mpfr_sinh_cosh(s.mp,c.mp,v.mp,rnd_mode); +} + +inline const mpreal li2 (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) +{ + MPREAL_UNARY_MATH_FUNCTION_BODY(li2); +} + +inline const mpreal rem (const mpreal& x, const mpreal& y, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) +{ + /* R = rem(X,Y) if Y != 0, returns X - n * Y where n = trunc(X/Y). */ + return fmod(x, y, rnd_mode); +} + +inline const mpreal mod (const mpreal& x, const mpreal& y, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) +{ + (void)rnd_mode; + + /* + + m = mod(x,y) if y != 0, returns x - n*y where n = floor(x/y) + + The following are true by convention: + - mod(x,0) is x + - mod(x,x) is 0 + - mod(x,y) for x != y and y != 0 has the same sign as y. + + */ + + if(iszero(y)) return x; + if(x == y) return 0; + + mpreal m = x - floor(x / y) * y; + + m.setSign(sgn(y)); // make sure result has the same sign as Y + + return m; +} + +inline const mpreal fmod (const mpreal& x, const mpreal& y, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) +{ + mpreal a; + mp_prec_t yp, xp; + + yp = y.get_prec(); + xp = x.get_prec(); + + a.set_prec(yp>xp?yp:xp); + + mpfr_fmod(a.mp, x.mp, y.mp, rnd_mode); + + return a; +} + +inline const mpreal rec_sqrt(const mpreal& v, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) +{ + mpreal x(v); + mpfr_rec_sqrt(x.mp,v.mp,rnd_mode); + return x; +} +#endif // MPFR 2.4.0 Specifics + +////////////////////////////////////////////////////////////////////////// +// MPFR 3.0.0 Specifics +#if (MPFR_VERSION >= MPFR_VERSION_NUM(3,0,0)) +inline const mpreal digamma (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(digamma); } +inline const mpreal ai (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(ai); } +#endif // MPFR 3.0.0 Specifics + +////////////////////////////////////////////////////////////////////////// +// Constants +inline const mpreal const_log2 (mp_prec_t p = mpreal::get_default_prec(), mp_rnd_t r = mpreal::get_default_rnd()) +{ + mpreal x(0, p); + mpfr_const_log2(x.mpfr_ptr(), r); + return x; +} + +inline const mpreal const_pi (mp_prec_t p = mpreal::get_default_prec(), mp_rnd_t r = mpreal::get_default_rnd()) +{ + mpreal x(0, p); + mpfr_const_pi(x.mpfr_ptr(), r); + return x; +} + +inline const mpreal const_euler (mp_prec_t p = mpreal::get_default_prec(), mp_rnd_t r = mpreal::get_default_rnd()) +{ + mpreal x(0, p); + mpfr_const_euler(x.mpfr_ptr(), r); + return x; +} + +inline const mpreal const_catalan (mp_prec_t p = mpreal::get_default_prec(), mp_rnd_t r = mpreal::get_default_rnd()) +{ + mpreal x(0, p); + mpfr_const_catalan(x.mpfr_ptr(), r); + return x; +} + +inline const mpreal const_infinity (int sign = 1, mp_prec_t p = mpreal::get_default_prec()) +{ + mpreal x(0, p); + mpfr_set_inf(x.mpfr_ptr(), sign); + return x; +} + +////////////////////////////////////////////////////////////////////////// +// Integer Related Functions +inline const mpreal ceil(const mpreal& v) +{ + mpreal x(v); + mpfr_ceil(x.mp,v.mp); + return x; +} + +inline const mpreal floor(const mpreal& v) +{ + mpreal x(v); + mpfr_floor(x.mp,v.mp); + return x; +} + +inline const mpreal round(const mpreal& v) +{ + mpreal x(v); + mpfr_round(x.mp,v.mp); + return x; +} + +inline const mpreal trunc(const mpreal& v) +{ + mpreal x(v); + mpfr_trunc(x.mp,v.mp); + return x; +} + +inline const mpreal rint (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(rint ); } +inline const mpreal rint_ceil (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(rint_ceil ); } +inline const mpreal rint_floor (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(rint_floor); } +inline const mpreal rint_round (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(rint_round); } +inline const mpreal rint_trunc (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(rint_trunc); } +inline const mpreal frac (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(frac ); } + +////////////////////////////////////////////////////////////////////////// +// Miscellaneous Functions +inline void swap (mpreal& a, mpreal& b) { mpfr_swap(a.mp,b.mp); } +inline const mpreal (max)(const mpreal& x, const mpreal& y){ return (x>y?x:y); } +inline const mpreal (min)(const mpreal& x, const mpreal& y){ return (x= MPFR_VERSION_NUM(3,1,0)) +// use gmp_randinit_default() to init state, gmp_randclear() to clear +inline const mpreal urandom (gmp_randstate_t& state, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) +{ + mpreal x; + mpfr_urandom(x.mp,state,rnd_mode); + return x; +} + +inline const mpreal grandom (gmp_randstate_t& state, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) +{ + mpreal x; + mpfr_grandom(x.mp, NULL, state, rnd_mode); + return x; +} + +#endif + +#if (MPFR_VERSION <= MPFR_VERSION_NUM(2,4,2)) +inline const mpreal random2 (mp_size_t size, mp_exp_t exp) +{ + mpreal x; + mpfr_random2(x.mp,size,exp); + return x; +} +#endif + +// Uniformly distributed random number generation +// a = random(seed); <- initialization & first random number generation +// a = random(); <- next random numbers generation +// seed != 0 +inline const mpreal random(unsigned int seed = 0) +{ + +#if (MPFR_VERSION >= MPFR_VERSION_NUM(3,0,0)) + static gmp_randstate_t state; + static bool isFirstTime = true; + + if(isFirstTime) + { + gmp_randinit_default(state); + gmp_randseed_ui(state,0); + isFirstTime = false; + } + + if(seed != 0) gmp_randseed_ui(state,seed); + + return mpfr::urandom(state); +#else + if(seed != 0) std::srand(seed); + return mpfr::mpreal(std::rand()/(double)RAND_MAX); +#endif + +} + +#if (MPFR_VERSION >= MPFR_VERSION_NUM(3,0,0)) +inline const mpreal grandom(unsigned int seed = 0) +{ + static gmp_randstate_t state; + static bool isFirstTime = true; + + if(isFirstTime) + { + gmp_randinit_default(state); + gmp_randseed_ui(state,0); + isFirstTime = false; + } + + if(seed != 0) gmp_randseed_ui(state,seed); + + return mpfr::grandom(state); +} +#endif + +////////////////////////////////////////////////////////////////////////// +// Set/Get global properties +inline void mpreal::set_default_prec(mp_prec_t prec) +{ + mpfr_set_default_prec(prec); +} + +inline void mpreal::set_default_rnd(mp_rnd_t rnd_mode) +{ + mpfr_set_default_rounding_mode(rnd_mode); +} + +inline bool mpreal::fits_in_bits(double x, int n) +{ + int i; + double t; + return IsInf(x) || (std::modf ( std::ldexp ( std::frexp ( x, &i ), n ), &t ) == 0.0); +} + +inline const mpreal pow(const mpreal& a, const mpreal& b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) +{ + mpreal x(a); + mpfr_pow(x.mp,x.mp,b.mp,rnd_mode); + return x; +} + +inline const mpreal pow(const mpreal& a, const mpz_t b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) +{ + mpreal x(a); + mpfr_pow_z(x.mp,x.mp,b,rnd_mode); + return x; +} + +inline const mpreal pow(const mpreal& a, const unsigned long int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) +{ + mpreal x(a); + mpfr_pow_ui(x.mp,x.mp,b,rnd_mode); + return x; +} + +inline const mpreal pow(const mpreal& a, const unsigned int b, mp_rnd_t rnd_mode) +{ + return pow(a,static_cast(b),rnd_mode); +} + +inline const mpreal pow(const mpreal& a, const long int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) +{ + mpreal x(a); + mpfr_pow_si(x.mp,x.mp,b,rnd_mode); + return x; +} + +inline const mpreal pow(const mpreal& a, const int b, mp_rnd_t rnd_mode) +{ + return pow(a,static_cast(b),rnd_mode); +} + +inline const mpreal pow(const mpreal& a, const long double b, mp_rnd_t rnd_mode) +{ + return pow(a,mpreal(b),rnd_mode); +} + +inline const mpreal pow(const mpreal& a, const double b, mp_rnd_t rnd_mode) +{ + return pow(a,mpreal(b),rnd_mode); +} + +inline const mpreal pow(const unsigned long int a, const mpreal& b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) +{ + mpreal x(a); + mpfr_ui_pow(x.mp,a,b.mp,rnd_mode); + return x; +} + +inline const mpreal pow(const unsigned int a, const mpreal& b, mp_rnd_t rnd_mode) +{ + return pow(static_cast(a),b,rnd_mode); +} + +inline const mpreal pow(const long int a, const mpreal& b, mp_rnd_t rnd_mode) +{ + if (a>=0) return pow(static_cast(a),b,rnd_mode); + else return pow(mpreal(a),b,rnd_mode); +} + +inline const mpreal pow(const int a, const mpreal& b, mp_rnd_t rnd_mode) +{ + if (a>=0) return pow(static_cast(a),b,rnd_mode); + else return pow(mpreal(a),b,rnd_mode); +} + +inline const mpreal pow(const long double a, const mpreal& b, mp_rnd_t rnd_mode) +{ + return pow(mpreal(a),b,rnd_mode); +} + +inline const mpreal pow(const double a, const mpreal& b, mp_rnd_t rnd_mode) +{ + return pow(mpreal(a),b,rnd_mode); +} + +// pow unsigned long int +inline const mpreal pow(const unsigned long int a, const unsigned long int b, mp_rnd_t rnd_mode) +{ + mpreal x(a); + mpfr_ui_pow_ui(x.mp,a,b,rnd_mode); + return x; +} + +inline const mpreal pow(const unsigned long int a, const unsigned int b, mp_rnd_t rnd_mode) +{ + return pow(a,static_cast(b),rnd_mode); //mpfr_ui_pow_ui +} + +inline const mpreal pow(const unsigned long int a, const long int b, mp_rnd_t rnd_mode) +{ + if(b>0) return pow(a,static_cast(b),rnd_mode); //mpfr_ui_pow_ui + else return pow(a,mpreal(b),rnd_mode); //mpfr_ui_pow +} + +inline const mpreal pow(const unsigned long int a, const int b, mp_rnd_t rnd_mode) +{ + if(b>0) return pow(a,static_cast(b),rnd_mode); //mpfr_ui_pow_ui + else return pow(a,mpreal(b),rnd_mode); //mpfr_ui_pow +} + +inline const mpreal pow(const unsigned long int a, const long double b, mp_rnd_t rnd_mode) +{ + return pow(a,mpreal(b),rnd_mode); //mpfr_ui_pow +} + +inline const mpreal pow(const unsigned long int a, const double b, mp_rnd_t rnd_mode) +{ + return pow(a,mpreal(b),rnd_mode); //mpfr_ui_pow +} + +// pow unsigned int +inline const mpreal pow(const unsigned int a, const unsigned long int b, mp_rnd_t rnd_mode) +{ + return pow(static_cast(a),b,rnd_mode); //mpfr_ui_pow_ui +} + +inline const mpreal pow(const unsigned int a, const unsigned int b, mp_rnd_t rnd_mode) +{ + return pow(static_cast(a),static_cast(b),rnd_mode); //mpfr_ui_pow_ui +} + +inline const mpreal pow(const unsigned int a, const long int b, mp_rnd_t rnd_mode) +{ + if(b>0) return pow(static_cast(a),static_cast(b),rnd_mode); //mpfr_ui_pow_ui + else return pow(static_cast(a),mpreal(b),rnd_mode); //mpfr_ui_pow +} + +inline const mpreal pow(const unsigned int a, const int b, mp_rnd_t rnd_mode) +{ + if(b>0) return pow(static_cast(a),static_cast(b),rnd_mode); //mpfr_ui_pow_ui + else return pow(static_cast(a),mpreal(b),rnd_mode); //mpfr_ui_pow +} + +inline const mpreal pow(const unsigned int a, const long double b, mp_rnd_t rnd_mode) +{ + return pow(static_cast(a),mpreal(b),rnd_mode); //mpfr_ui_pow +} + +inline const mpreal pow(const unsigned int a, const double b, mp_rnd_t rnd_mode) +{ + return pow(static_cast(a),mpreal(b),rnd_mode); //mpfr_ui_pow +} + +// pow long int +inline const mpreal pow(const long int a, const unsigned long int b, mp_rnd_t rnd_mode) +{ + if (a>0) return pow(static_cast(a),b,rnd_mode); //mpfr_ui_pow_ui + else return pow(mpreal(a),b,rnd_mode); //mpfr_pow_ui +} + +inline const mpreal pow(const long int a, const unsigned int b, mp_rnd_t rnd_mode) +{ + if (a>0) return pow(static_cast(a),static_cast(b),rnd_mode); //mpfr_ui_pow_ui + else return pow(mpreal(a),static_cast(b),rnd_mode); //mpfr_pow_ui +} + +inline const mpreal pow(const long int a, const long int b, mp_rnd_t rnd_mode) +{ + if (a>0) + { + if(b>0) return pow(static_cast(a),static_cast(b),rnd_mode); //mpfr_ui_pow_ui + else return pow(static_cast(a),mpreal(b),rnd_mode); //mpfr_ui_pow + }else{ + return pow(mpreal(a),b,rnd_mode); // mpfr_pow_si + } +} + +inline const mpreal pow(const long int a, const int b, mp_rnd_t rnd_mode) +{ + if (a>0) + { + if(b>0) return pow(static_cast(a),static_cast(b),rnd_mode); //mpfr_ui_pow_ui + else return pow(static_cast(a),mpreal(b),rnd_mode); //mpfr_ui_pow + }else{ + return pow(mpreal(a),static_cast(b),rnd_mode); // mpfr_pow_si + } +} + +inline const mpreal pow(const long int a, const long double b, mp_rnd_t rnd_mode) +{ + if (a>=0) return pow(static_cast(a),mpreal(b),rnd_mode); //mpfr_ui_pow + else return pow(mpreal(a),mpreal(b),rnd_mode); //mpfr_pow +} + +inline const mpreal pow(const long int a, const double b, mp_rnd_t rnd_mode) +{ + if (a>=0) return pow(static_cast(a),mpreal(b),rnd_mode); //mpfr_ui_pow + else return pow(mpreal(a),mpreal(b),rnd_mode); //mpfr_pow +} + +// pow int +inline const mpreal pow(const int a, const unsigned long int b, mp_rnd_t rnd_mode) +{ + if (a>0) return pow(static_cast(a),b,rnd_mode); //mpfr_ui_pow_ui + else return pow(mpreal(a),b,rnd_mode); //mpfr_pow_ui +} + +inline const mpreal pow(const int a, const unsigned int b, mp_rnd_t rnd_mode) +{ + if (a>0) return pow(static_cast(a),static_cast(b),rnd_mode); //mpfr_ui_pow_ui + else return pow(mpreal(a),static_cast(b),rnd_mode); //mpfr_pow_ui +} + +inline const mpreal pow(const int a, const long int b, mp_rnd_t rnd_mode) +{ + if (a>0) + { + if(b>0) return pow(static_cast(a),static_cast(b),rnd_mode); //mpfr_ui_pow_ui + else return pow(static_cast(a),mpreal(b),rnd_mode); //mpfr_ui_pow + }else{ + return pow(mpreal(a),b,rnd_mode); // mpfr_pow_si + } +} + +inline const mpreal pow(const int a, const int b, mp_rnd_t rnd_mode) +{ + if (a>0) + { + if(b>0) return pow(static_cast(a),static_cast(b),rnd_mode); //mpfr_ui_pow_ui + else return pow(static_cast(a),mpreal(b),rnd_mode); //mpfr_ui_pow + }else{ + return pow(mpreal(a),static_cast(b),rnd_mode); // mpfr_pow_si + } +} + +inline const mpreal pow(const int a, const long double b, mp_rnd_t rnd_mode) +{ + if (a>=0) return pow(static_cast(a),mpreal(b),rnd_mode); //mpfr_ui_pow + else return pow(mpreal(a),mpreal(b),rnd_mode); //mpfr_pow +} + +inline const mpreal pow(const int a, const double b, mp_rnd_t rnd_mode) +{ + if (a>=0) return pow(static_cast(a),mpreal(b),rnd_mode); //mpfr_ui_pow + else return pow(mpreal(a),mpreal(b),rnd_mode); //mpfr_pow +} + +// pow long double +inline const mpreal pow(const long double a, const long double b, mp_rnd_t rnd_mode) +{ + return pow(mpreal(a),mpreal(b),rnd_mode); +} + +inline const mpreal pow(const long double a, const unsigned long int b, mp_rnd_t rnd_mode) +{ + return pow(mpreal(a),b,rnd_mode); //mpfr_pow_ui +} + +inline const mpreal pow(const long double a, const unsigned int b, mp_rnd_t rnd_mode) +{ + return pow(mpreal(a),static_cast(b),rnd_mode); //mpfr_pow_ui +} + +inline const mpreal pow(const long double a, const long int b, mp_rnd_t rnd_mode) +{ + return pow(mpreal(a),b,rnd_mode); // mpfr_pow_si +} + +inline const mpreal pow(const long double a, const int b, mp_rnd_t rnd_mode) +{ + return pow(mpreal(a),static_cast(b),rnd_mode); // mpfr_pow_si +} + +inline const mpreal pow(const double a, const double b, mp_rnd_t rnd_mode) +{ + return pow(mpreal(a),mpreal(b),rnd_mode); +} + +inline const mpreal pow(const double a, const unsigned long int b, mp_rnd_t rnd_mode) +{ + return pow(mpreal(a),b,rnd_mode); // mpfr_pow_ui +} + +inline const mpreal pow(const double a, const unsigned int b, mp_rnd_t rnd_mode) +{ + return pow(mpreal(a),static_cast(b),rnd_mode); // mpfr_pow_ui +} + +inline const mpreal pow(const double a, const long int b, mp_rnd_t rnd_mode) +{ + return pow(mpreal(a),b,rnd_mode); // mpfr_pow_si +} + +inline const mpreal pow(const double a, const int b, mp_rnd_t rnd_mode) +{ + return pow(mpreal(a),static_cast(b),rnd_mode); // mpfr_pow_si +} +} // End of mpfr namespace + +// Explicit specialization of std::swap for mpreal numbers +// Thus standard algorithms will use efficient version of swap (due to Koenig lookup) +// Non-throwing swap C++ idiom: http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Non-throwing_swap +namespace std +{ + // we are allowed to extend namespace std with specializations only + template <> + inline void swap(mpfr::mpreal& x, mpfr::mpreal& y) + { + return mpfr::swap(x, y); + } + + template<> + class numeric_limits + { + public: + static const bool is_specialized = true; + static const bool is_signed = true; + static const bool is_integer = false; + static const bool is_exact = false; + static const int radix = 2; + + static const bool has_infinity = true; + static const bool has_quiet_NaN = true; + static const bool has_signaling_NaN = true; + + static const bool is_iec559 = true; // = IEEE 754 + static const bool is_bounded = true; + static const bool is_modulo = false; + static const bool traps = true; + static const bool tinyness_before = true; + + static const float_denorm_style has_denorm = denorm_absent; + + inline static mpfr::mpreal (min) (mp_prec_t precision = mpfr::mpreal::get_default_prec()) { return mpfr::minval(precision); } + inline static mpfr::mpreal (max) (mp_prec_t precision = mpfr::mpreal::get_default_prec()) { return mpfr::maxval(precision); } + inline static mpfr::mpreal lowest (mp_prec_t precision = mpfr::mpreal::get_default_prec()) { return -mpfr::maxval(precision); } + + // Returns smallest eps such that 1 + eps != 1 (classic machine epsilon) + inline static mpfr::mpreal epsilon(mp_prec_t precision = mpfr::mpreal::get_default_prec()) { return mpfr::machine_epsilon(precision); } + + // Returns smallest eps such that x + eps != x (relative machine epsilon) + inline static mpfr::mpreal epsilon(const mpfr::mpreal& x) { return mpfr::machine_epsilon(x); } + + inline static mpfr::mpreal round_error(mp_prec_t precision = mpfr::mpreal::get_default_prec()) + { + mp_rnd_t r = mpfr::mpreal::get_default_rnd(); + + if(r == GMP_RNDN) return mpfr::mpreal(0.5, precision); + else return mpfr::mpreal(1.0, precision); + } + + inline static const mpfr::mpreal infinity() { return mpfr::const_infinity(); } + inline static const mpfr::mpreal quiet_NaN() { return mpfr::mpreal().setNan(); } + inline static const mpfr::mpreal signaling_NaN() { return mpfr::mpreal().setNan(); } + inline static const mpfr::mpreal denorm_min() { return (min)(); } + + // Please note, exponent range is not fixed in MPFR + static const int min_exponent = MPFR_EMIN_DEFAULT; + static const int max_exponent = MPFR_EMAX_DEFAULT; + MPREAL_PERMISSIVE_EXPR static const int min_exponent10 = (int) (MPFR_EMIN_DEFAULT * 0.3010299956639811); + MPREAL_PERMISSIVE_EXPR static const int max_exponent10 = (int) (MPFR_EMAX_DEFAULT * 0.3010299956639811); + +#ifdef MPREAL_HAVE_DYNAMIC_STD_NUMERIC_LIMITS + + // Following members should be constant according to standard, but they can be variable in MPFR + // So we define them as functions here. + // + // This is preferable way for std::numeric_limits specialization. + // But it is incompatible with standard std::numeric_limits and might not work with other libraries, e.g. boost. + // See below for compatible implementation. + inline static float_round_style round_style() + { + mp_rnd_t r = mpfr::mpreal::get_default_rnd(); + + switch (r) + { + case GMP_RNDN: return round_to_nearest; + case GMP_RNDZ: return round_toward_zero; + case GMP_RNDU: return round_toward_infinity; + case GMP_RNDD: return round_toward_neg_infinity; + default: return round_indeterminate; + } + } + + inline static int digits() { return int(mpfr::mpreal::get_default_prec()); } + inline static int digits(const mpfr::mpreal& x) { return x.getPrecision(); } + + inline static int digits10(mp_prec_t precision = mpfr::mpreal::get_default_prec()) + { + return mpfr::bits2digits(precision); + } + + inline static int digits10(const mpfr::mpreal& x) + { + return mpfr::bits2digits(x.getPrecision()); + } + + inline static int max_digits10(mp_prec_t precision = mpfr::mpreal::get_default_prec()) + { + return digits10(precision); + } +#else + // Digits and round_style are NOT constants when it comes to mpreal. + // If possible, please use functions digits() and round_style() defined above. + // + // These (default) values are preserved for compatibility with existing libraries, e.g. boost. + // Change them accordingly to your application. + // + // For example, if you use 256 bits of precision uniformly in your program, then: + // digits = 256 + // digits10 = 77 + // max_digits10 = 78 + // + // Approximate formula for decimal digits is: digits10 = floor(log10(2) * digits). See bits2digits() for more details. + + static const std::float_round_style round_style = round_to_nearest; + static const int digits = 53; + static const int digits10 = 15; + static const int max_digits10 = 16; +#endif + }; + +} + +#endif /* __MPREAL_H__ */ diff --git a/uppsrc/plugin/Eigen/unsupported/test/mpreal_support.cpp b/uppsrc/plugin/Eigen/unsupported/test/mpreal_support.cpp new file mode 100644 index 000000000..bc00382be --- /dev/null +++ b/uppsrc/plugin/Eigen/unsupported/test/mpreal_support.cpp @@ -0,0 +1,57 @@ +#include "main.h" +#include +#include +#include +#include + +using namespace mpfr; +using namespace Eigen; + +void test_mpreal_support() +{ + // set precision to 256 bits (double has only 53 bits) + mpreal::set_default_prec(256); + typedef Matrix MatrixXmp; + + std::cerr << "epsilon = " << NumTraits::epsilon() << "\n"; + std::cerr << "dummy_precision = " << NumTraits::dummy_precision() << "\n"; + std::cerr << "highest = " << NumTraits::highest() << "\n"; + std::cerr << "lowest = " << NumTraits::lowest() << "\n"; + + for(int i = 0; i < g_repeat; i++) { + int s = Eigen::internal::random(1,100); + MatrixXmp A = MatrixXmp::Random(s,s); + MatrixXmp B = MatrixXmp::Random(s,s); + MatrixXmp S = A.adjoint() * A; + MatrixXmp X; + + // Basic stuffs + VERIFY_IS_APPROX(A.real(), A); + VERIFY(Eigen::internal::isApprox(A.array().abs2().sum(), A.squaredNorm())); + VERIFY_IS_APPROX(A.array().exp(), exp(A.array())); + VERIFY_IS_APPROX(A.array().abs2().sqrt(), A.array().abs()); + VERIFY_IS_APPROX(A.array().sin(), sin(A.array())); + VERIFY_IS_APPROX(A.array().cos(), cos(A.array())); + + + // Cholesky + X = S.selfadjointView().llt().solve(B); + VERIFY_IS_APPROX((S.selfadjointView()*X).eval(),B); + + // partial LU + X = A.lu().solve(B); + VERIFY_IS_APPROX((A*X).eval(),B); + + // symmetric eigenvalues + SelfAdjointEigenSolver eig(S); + VERIFY_IS_EQUAL(eig.info(), Success); + VERIFY( (S.selfadjointView() * eig.eigenvectors()).isApprox(eig.eigenvectors() * eig.eigenvalues().asDiagonal(), NumTraits::dummy_precision()*1e3) ); + } + + { + MatrixXmp A(8,3); A.setRandom(); + // test output (interesting things happen in this code) + std::stringstream stream; + stream << A; + } +} diff --git a/uppsrc/plugin/Eigen/unsupported/test/openglsupport.cpp b/uppsrc/plugin/Eigen/unsupported/test/openglsupport.cpp new file mode 100644 index 000000000..706a816f7 --- /dev/null +++ b/uppsrc/plugin/Eigen/unsupported/test/openglsupport.cpp @@ -0,0 +1,337 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2010 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include +#include +#include +#include +#include +using namespace Eigen; + + + + +#define VERIFY_MATRIX(CODE,REF) { \ + glLoadIdentity(); \ + CODE; \ + Matrix m; m.setZero(); \ + glGet(GL_MODELVIEW_MATRIX, m); \ + if(!(REF).cast().isApprox(m)) { \ + std::cerr << "Expected:\n" << ((REF).cast()) << "\n" << "got\n" << m << "\n\n"; \ + } \ + VERIFY_IS_APPROX((REF).cast(), m); \ + } + +#define VERIFY_UNIFORM(SUFFIX,NAME,TYPE) { \ + TYPE value; value.setRandom(); \ + TYPE data; \ + int loc = glGetUniformLocation(prg_id, #NAME); \ + VERIFY((loc!=-1) && "uniform not found"); \ + glUniform(loc,value); \ + EIGEN_CAT(glGetUniform,SUFFIX)(prg_id,loc,data.data()); \ + if(!value.isApprox(data)) { \ + std::cerr << "Expected:\n" << value << "\n" << "got\n" << data << "\n\n"; \ + } \ + VERIFY_IS_APPROX(value, data); \ + } + +#define VERIFY_UNIFORMi(NAME,TYPE) { \ + TYPE value = TYPE::Random().eval().cast().cast(); \ + TYPE data; \ + int loc = glGetUniformLocation(prg_id, #NAME); \ + VERIFY((loc!=-1) && "uniform not found"); \ + glUniform(loc,value); \ + glGetUniformiv(prg_id,loc,(GLint*)data.data()); \ + if(!value.isApprox(data)) { \ + std::cerr << "Expected:\n" << value << "\n" << "got\n" << data << "\n\n"; \ + } \ + VERIFY_IS_APPROX(value, data); \ + } + +void printInfoLog(GLuint objectID) +{ + int infologLength, charsWritten; + GLchar *infoLog; + glGetProgramiv(objectID,GL_INFO_LOG_LENGTH, &infologLength); + if(infologLength > 0) + { + infoLog = new GLchar[infologLength]; + glGetProgramInfoLog(objectID, infologLength, &charsWritten, infoLog); + if (charsWritten>0) + std::cerr << "Shader info : \n" << infoLog << std::endl; + delete[] infoLog; + } +} + +GLint createShader(const char* vtx, const char* frg) +{ + GLint prg_id = glCreateProgram(); + GLint vtx_id = glCreateShader(GL_VERTEX_SHADER); + GLint frg_id = glCreateShader(GL_FRAGMENT_SHADER); + GLint ok; + + glShaderSource(vtx_id, 1, &vtx, 0); + glCompileShader(vtx_id); + glGetShaderiv(vtx_id,GL_COMPILE_STATUS,&ok); + if(!ok) + { + std::cerr << "vtx compilation failed\n"; + } + + glShaderSource(frg_id, 1, &frg, 0); + glCompileShader(frg_id); + glGetShaderiv(frg_id,GL_COMPILE_STATUS,&ok); + if(!ok) + { + std::cerr << "frg compilation failed\n"; + } + + glAttachShader(prg_id, vtx_id); + glAttachShader(prg_id, frg_id); + glLinkProgram(prg_id); + glGetProgramiv(prg_id,GL_LINK_STATUS,&ok); + if(!ok) + { + std::cerr << "linking failed\n"; + } + printInfoLog(prg_id); + + glUseProgram(prg_id); + return prg_id; +} + +void test_openglsupport() +{ + int argc = 0; + glutInit(&argc, 0); + glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); + glutInitWindowPosition (0,0); + glutInitWindowSize(10, 10); + + if(glutCreateWindow("Eigen") <= 0) + { + std::cerr << "Error: Unable to create GLUT Window.\n"; + exit(1); + } + + glewExperimental = GL_TRUE; + if(glewInit() != GLEW_OK) + { + std::cerr << "Warning: Failed to initialize GLEW\n"; + } + + Vector3f v3f; + Matrix3f rot; + glBegin(GL_POINTS); + + glVertex(v3f); + glVertex(2*v3f+v3f); + glVertex(rot*v3f); + + glEnd(); + + // 4x4 matrices + Matrix4f mf44; mf44.setRandom(); + VERIFY_MATRIX(glLoadMatrix(mf44), mf44); + VERIFY_MATRIX(glMultMatrix(mf44), mf44); + Matrix4d md44; md44.setRandom(); + VERIFY_MATRIX(glLoadMatrix(md44), md44); + VERIFY_MATRIX(glMultMatrix(md44), md44); + + // Quaternion + Quaterniond qd(AngleAxisd(internal::random(), Vector3d::Random())); + VERIFY_MATRIX(glRotate(qd), Projective3d(qd).matrix()); + + Quaternionf qf(AngleAxisf(internal::random(), Vector3f::Random())); + VERIFY_MATRIX(glRotate(qf), Projective3f(qf).matrix()); + + // 3D Transform + Transform acf3; acf3.matrix().setRandom(); + VERIFY_MATRIX(glLoadMatrix(acf3), Projective3f(acf3).matrix()); + VERIFY_MATRIX(glMultMatrix(acf3), Projective3f(acf3).matrix()); + + Transform af3(acf3); + VERIFY_MATRIX(glLoadMatrix(af3), Projective3f(af3).matrix()); + VERIFY_MATRIX(glMultMatrix(af3), Projective3f(af3).matrix()); + + Transform pf3; pf3.matrix().setRandom(); + VERIFY_MATRIX(glLoadMatrix(pf3), Projective3f(pf3).matrix()); + VERIFY_MATRIX(glMultMatrix(pf3), Projective3f(pf3).matrix()); + + Transform acd3; acd3.matrix().setRandom(); + VERIFY_MATRIX(glLoadMatrix(acd3), Projective3d(acd3).matrix()); + VERIFY_MATRIX(glMultMatrix(acd3), Projective3d(acd3).matrix()); + + Transform ad3(acd3); + VERIFY_MATRIX(glLoadMatrix(ad3), Projective3d(ad3).matrix()); + VERIFY_MATRIX(glMultMatrix(ad3), Projective3d(ad3).matrix()); + + Transform pd3; pd3.matrix().setRandom(); + VERIFY_MATRIX(glLoadMatrix(pd3), Projective3d(pd3).matrix()); + VERIFY_MATRIX(glMultMatrix(pd3), Projective3d(pd3).matrix()); + + // translations (2D and 3D) + { + Vector2f vf2; vf2.setRandom(); Vector3f vf23; vf23 << vf2, 0; + VERIFY_MATRIX(glTranslate(vf2), Projective3f(Translation3f(vf23)).matrix()); + Vector2d vd2; vd2.setRandom(); Vector3d vd23; vd23 << vd2, 0; + VERIFY_MATRIX(glTranslate(vd2), Projective3d(Translation3d(vd23)).matrix()); + + Vector3f vf3; vf3.setRandom(); + VERIFY_MATRIX(glTranslate(vf3), Projective3f(Translation3f(vf3)).matrix()); + Vector3d vd3; vd3.setRandom(); + VERIFY_MATRIX(glTranslate(vd3), Projective3d(Translation3d(vd3)).matrix()); + + Translation tf3; tf3.vector().setRandom(); + VERIFY_MATRIX(glTranslate(tf3), Projective3f(tf3).matrix()); + + Translation td3; td3.vector().setRandom(); + VERIFY_MATRIX(glTranslate(td3), Projective3d(td3).matrix()); + } + + // scaling (2D and 3D) + { + Vector2f vf2; vf2.setRandom(); Vector3f vf23; vf23 << vf2, 1; + VERIFY_MATRIX(glScale(vf2), Projective3f(Scaling(vf23)).matrix()); + Vector2d vd2; vd2.setRandom(); Vector3d vd23; vd23 << vd2, 1; + VERIFY_MATRIX(glScale(vd2), Projective3d(Scaling(vd23)).matrix()); + + Vector3f vf3; vf3.setRandom(); + VERIFY_MATRIX(glScale(vf3), Projective3f(Scaling(vf3)).matrix()); + Vector3d vd3; vd3.setRandom(); + VERIFY_MATRIX(glScale(vd3), Projective3d(Scaling(vd3)).matrix()); + + UniformScaling usf(internal::random()); + VERIFY_MATRIX(glScale(usf), Projective3f(usf).matrix()); + + UniformScaling usd(internal::random()); + VERIFY_MATRIX(glScale(usd), Projective3d(usd).matrix()); + } + + // uniform + { + const char* vtx = "void main(void) { gl_Position = gl_Vertex; }\n"; + + if(GLEW_VERSION_2_0) + { + #ifdef GL_VERSION_2_0 + const char* frg = "" + "uniform vec2 v2f;\n" + "uniform vec3 v3f;\n" + "uniform vec4 v4f;\n" + "uniform ivec2 v2i;\n" + "uniform ivec3 v3i;\n" + "uniform ivec4 v4i;\n" + "uniform mat2 m2f;\n" + "uniform mat3 m3f;\n" + "uniform mat4 m4f;\n" + "void main(void) { gl_FragColor = vec4(v2f[0]+v3f[0]+v4f[0])+vec4(v2i[0]+v3i[0]+v4i[0])+vec4(m2f[0][0]+m3f[0][0]+m4f[0][0]); }\n"; + + GLint prg_id = createShader(vtx,frg); + + VERIFY_UNIFORM(fv,v2f, Vector2f); + VERIFY_UNIFORM(fv,v3f, Vector3f); + VERIFY_UNIFORM(fv,v4f, Vector4f); + VERIFY_UNIFORMi(v2i, Vector2i); + VERIFY_UNIFORMi(v3i, Vector3i); + VERIFY_UNIFORMi(v4i, Vector4i); + VERIFY_UNIFORM(fv,m2f, Matrix2f); + VERIFY_UNIFORM(fv,m3f, Matrix3f); + VERIFY_UNIFORM(fv,m4f, Matrix4f); + #endif + } + else + std::cerr << "Warning: opengl 2.0 was not tested\n"; + + if(GLEW_VERSION_2_1) + { + #ifdef GL_VERSION_2_1 + const char* frg = "#version 120\n" + "uniform mat2x3 m23f;\n" + "uniform mat3x2 m32f;\n" + "uniform mat2x4 m24f;\n" + "uniform mat4x2 m42f;\n" + "uniform mat3x4 m34f;\n" + "uniform mat4x3 m43f;\n" + "void main(void) { gl_FragColor = vec4(m23f[0][0]+m32f[0][0]+m24f[0][0]+m42f[0][0]+m34f[0][0]+m43f[0][0]); }\n"; + + GLint prg_id = createShader(vtx,frg); + + typedef Matrix Matrix23f; + typedef Matrix Matrix32f; + typedef Matrix Matrix24f; + typedef Matrix Matrix42f; + typedef Matrix Matrix34f; + typedef Matrix Matrix43f; + + VERIFY_UNIFORM(fv,m23f, Matrix23f); + VERIFY_UNIFORM(fv,m32f, Matrix32f); + VERIFY_UNIFORM(fv,m24f, Matrix24f); + VERIFY_UNIFORM(fv,m42f, Matrix42f); + VERIFY_UNIFORM(fv,m34f, Matrix34f); + VERIFY_UNIFORM(fv,m43f, Matrix43f); + #endif + } + else + std::cerr << "Warning: opengl 2.1 was not tested\n"; + + if(GLEW_VERSION_3_0) + { + #ifdef GL_VERSION_3_0 + const char* frg = "#version 150\n" + "uniform uvec2 v2ui;\n" + "uniform uvec3 v3ui;\n" + "uniform uvec4 v4ui;\n" + "out vec4 data;\n" + "void main(void) { data = vec4(v2ui[0]+v3ui[0]+v4ui[0]); }\n"; + + GLint prg_id = createShader(vtx,frg); + + typedef Matrix Vector2ui; + typedef Matrix Vector3ui; + typedef Matrix Vector4ui; + + VERIFY_UNIFORMi(v2ui, Vector2ui); + VERIFY_UNIFORMi(v3ui, Vector3ui); + VERIFY_UNIFORMi(v4ui, Vector4ui); + #endif + } + else + std::cerr << "Warning: opengl 3.0 was not tested\n"; + + #ifdef GLEW_ARB_gpu_shader_fp64 + if(GLEW_ARB_gpu_shader_fp64) + { + #ifdef GL_ARB_gpu_shader_fp64 + const char* frg = "#version 150\n" + "uniform dvec2 v2d;\n" + "uniform dvec3 v3d;\n" + "uniform dvec4 v4d;\n" + "out vec4 data;\n" + "void main(void) { data = vec4(v2d[0]+v3d[0]+v4d[0]); }\n"; + + GLint prg_id = createShader(vtx,frg); + + typedef Vector2d Vector2d; + typedef Vector3d Vector3d; + typedef Vector4d Vector4d; + + VERIFY_UNIFORM(dv,v2d, Vector2d); + VERIFY_UNIFORM(dv,v3d, Vector3d); + VERIFY_UNIFORM(dv,v4d, Vector4d); + #endif + } + else + std::cerr << "Warning: GLEW_ARB_gpu_shader_fp64 was not tested\n"; + #else + std::cerr << "Warning: GLEW_ARB_gpu_shader_fp64 was not tested\n"; + #endif + } + +} diff --git a/uppsrc/plugin/Eigen/unsupported/test/polynomialsolver.cpp b/uppsrc/plugin/Eigen/unsupported/test/polynomialsolver.cpp new file mode 100644 index 000000000..de79f1538 --- /dev/null +++ b/uppsrc/plugin/Eigen/unsupported/test/polynomialsolver.cpp @@ -0,0 +1,213 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2010 Manuel Yguel +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "main.h" +#include +#include +#include + +using namespace std; + +namespace Eigen { +namespace internal { +template +struct increment_if_fixed_size +{ + enum { + ret = (Size == Dynamic) ? Dynamic : Size+1 + }; +}; +} +} + + +template +bool aux_evalSolver( const POLYNOMIAL& pols, SOLVER& psolve ) +{ + typedef typename POLYNOMIAL::Index Index; + typedef typename POLYNOMIAL::Scalar Scalar; + + typedef typename SOLVER::RootsType RootsType; + typedef Matrix EvalRootsType; + + const Index deg = pols.size()-1; + + psolve.compute( pols ); + const RootsType& roots( psolve.roots() ); + EvalRootsType evr( deg ); + for( int i=0; i() ); + if( !evalToZero ) + { + cerr << "WRONG root: " << endl; + cerr << "Polynomial: " << pols.transpose() << endl; + cerr << "Roots found: " << roots.transpose() << endl; + cerr << "Abs value of the polynomial at the roots: " << evr.transpose() << endl; + cerr << endl; + } + + std::vector rootModuli( roots.size() ); + Map< EvalRootsType > aux( &rootModuli[0], roots.size() ); + aux = roots.array().abs(); + std::sort( rootModuli.begin(), rootModuli.end() ); + bool distinctModuli=true; + for( size_t i=1; i +void evalSolver( const POLYNOMIAL& pols ) +{ + typedef typename POLYNOMIAL::Scalar Scalar; + + typedef PolynomialSolver PolynomialSolverType; + + PolynomialSolverType psolve; + aux_evalSolver( pols, psolve ); +} + + + + +template< int Deg, typename POLYNOMIAL, typename ROOTS, typename REAL_ROOTS > +void evalSolverSugarFunction( const POLYNOMIAL& pols, const ROOTS& roots, const REAL_ROOTS& real_roots ) +{ + using std::sqrt; + typedef typename POLYNOMIAL::Scalar Scalar; + + typedef PolynomialSolver PolynomialSolverType; + + PolynomialSolverType psolve; + if( aux_evalSolver( pols, psolve ) ) + { + //It is supposed that + // 1) the roots found are correct + // 2) the roots have distinct moduli + + typedef typename REAL_ROOTS::Scalar Real; + + //Test realRoots + std::vector< Real > calc_realRoots; + psolve.realRoots( calc_realRoots ); + VERIFY( calc_realRoots.size() == (size_t)real_roots.size() ); + + const Scalar psPrec = sqrt( test_precision() ); + + for( size_t i=0; i 0 ) ); + if( hasRealRoot ){ + VERIFY( internal::isApprox( real_roots.array().abs().maxCoeff(), abs(r), psPrec ) ); } + + //Test absSmallestRealRoot + r = psolve.absSmallestRealRoot( hasRealRoot ); + VERIFY( hasRealRoot == (real_roots.size() > 0 ) ); + if( hasRealRoot ){ + VERIFY( internal::isApprox( real_roots.array().abs().minCoeff(), abs( r ), psPrec ) ); } + + //Test greatestRealRoot + r = psolve.greatestRealRoot( hasRealRoot ); + VERIFY( hasRealRoot == (real_roots.size() > 0 ) ); + if( hasRealRoot ){ + VERIFY( internal::isApprox( real_roots.array().maxCoeff(), r, psPrec ) ); } + + //Test smallestRealRoot + r = psolve.smallestRealRoot( hasRealRoot ); + VERIFY( hasRealRoot == (real_roots.size() > 0 ) ); + if( hasRealRoot ){ + VERIFY( internal::isApprox( real_roots.array().minCoeff(), r, psPrec ) ); } + } +} + + +template +void polynomialsolver(int deg) +{ + typedef internal::increment_if_fixed_size<_Deg> Dim; + typedef Matrix<_Scalar,Dim::ret,1> PolynomialType; + typedef Matrix<_Scalar,_Deg,1> EvalRootsType; + + cout << "Standard cases" << endl; + PolynomialType pols = PolynomialType::Random(deg+1); + evalSolver<_Deg,PolynomialType>( pols ); + + cout << "Hard cases" << endl; + _Scalar multipleRoot = internal::random<_Scalar>(); + EvalRootsType allRoots = EvalRootsType::Constant(deg,multipleRoot); + roots_to_monicPolynomial( allRoots, pols ); + evalSolver<_Deg,PolynomialType>( pols ); + + cout << "Test sugar" << endl; + EvalRootsType realRoots = EvalRootsType::Random(deg); + roots_to_monicPolynomial( realRoots, pols ); + evalSolverSugarFunction<_Deg>( + pols, + realRoots.template cast < + std::complex< + typename NumTraits<_Scalar>::Real + > + >(), + realRoots ); +} + +void test_polynomialsolver() +{ + for(int i = 0; i < g_repeat; i++) + { + CALL_SUBTEST_1( (polynomialsolver(1)) ); + CALL_SUBTEST_2( (polynomialsolver(2)) ); + CALL_SUBTEST_3( (polynomialsolver(3)) ); + CALL_SUBTEST_4( (polynomialsolver(4)) ); + CALL_SUBTEST_5( (polynomialsolver(5)) ); + CALL_SUBTEST_6( (polynomialsolver(6)) ); + CALL_SUBTEST_7( (polynomialsolver(7)) ); + CALL_SUBTEST_8( (polynomialsolver(8)) ); + + CALL_SUBTEST_9( (polynomialsolver( + internal::random(9,13) + )) ); + CALL_SUBTEST_10((polynomialsolver( + internal::random(9,13) + )) ); + } +} diff --git a/uppsrc/plugin/Eigen/unsupported/test/polynomialutils.cpp b/uppsrc/plugin/Eigen/unsupported/test/polynomialutils.cpp new file mode 100644 index 000000000..5fc968402 --- /dev/null +++ b/uppsrc/plugin/Eigen/unsupported/test/polynomialutils.cpp @@ -0,0 +1,113 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2010 Manuel Yguel +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "main.h" +#include +#include + +using namespace std; + +namespace Eigen { +namespace internal { +template +struct increment_if_fixed_size +{ + enum { + ret = (Size == Dynamic) ? Dynamic : Size+1 + }; +}; +} +} + +template +void realRoots_to_monicPolynomial_test(int deg) +{ + typedef internal::increment_if_fixed_size<_Deg> Dim; + typedef Matrix<_Scalar,Dim::ret,1> PolynomialType; + typedef Matrix<_Scalar,_Deg,1> EvalRootsType; + + PolynomialType pols(deg+1); + EvalRootsType roots = EvalRootsType::Random(deg); + roots_to_monicPolynomial( roots, pols ); + + EvalRootsType evr( deg ); + for( int i=0; i() ); + if( !evalToZero ){ + cerr << evr.transpose() << endl; } + VERIFY( evalToZero ); +} + +template void realRoots_to_monicPolynomial_scalar() +{ + CALL_SUBTEST_2( (realRoots_to_monicPolynomial_test<_Scalar,2>(2)) ); + CALL_SUBTEST_3( (realRoots_to_monicPolynomial_test<_Scalar,3>(3)) ); + CALL_SUBTEST_4( (realRoots_to_monicPolynomial_test<_Scalar,4>(4)) ); + CALL_SUBTEST_5( (realRoots_to_monicPolynomial_test<_Scalar,5>(5)) ); + CALL_SUBTEST_6( (realRoots_to_monicPolynomial_test<_Scalar,6>(6)) ); + CALL_SUBTEST_7( (realRoots_to_monicPolynomial_test<_Scalar,7>(7)) ); + CALL_SUBTEST_8( (realRoots_to_monicPolynomial_test<_Scalar,17>(17)) ); + + CALL_SUBTEST_9( (realRoots_to_monicPolynomial_test<_Scalar,Dynamic>( + internal::random(18,26) )) ); +} + + + + +template +void CauchyBounds(int deg) +{ + typedef internal::increment_if_fixed_size<_Deg> Dim; + typedef Matrix<_Scalar,Dim::ret,1> PolynomialType; + typedef Matrix<_Scalar,_Deg,1> EvalRootsType; + + PolynomialType pols(deg+1); + EvalRootsType roots = EvalRootsType::Random(deg); + roots_to_monicPolynomial( roots, pols ); + _Scalar M = cauchy_max_bound( pols ); + _Scalar m = cauchy_min_bound( pols ); + _Scalar Max = roots.array().abs().maxCoeff(); + _Scalar min = roots.array().abs().minCoeff(); + bool eval = (M >= Max) && (m <= min); + if( !eval ) + { + cerr << "Roots: " << roots << endl; + cerr << "Bounds: (" << m << ", " << M << ")" << endl; + cerr << "Min,Max: (" << min << ", " << Max << ")" << endl; + } + VERIFY( eval ); +} + +template void CauchyBounds_scalar() +{ + CALL_SUBTEST_2( (CauchyBounds<_Scalar,2>(2)) ); + CALL_SUBTEST_3( (CauchyBounds<_Scalar,3>(3)) ); + CALL_SUBTEST_4( (CauchyBounds<_Scalar,4>(4)) ); + CALL_SUBTEST_5( (CauchyBounds<_Scalar,5>(5)) ); + CALL_SUBTEST_6( (CauchyBounds<_Scalar,6>(6)) ); + CALL_SUBTEST_7( (CauchyBounds<_Scalar,7>(7)) ); + CALL_SUBTEST_8( (CauchyBounds<_Scalar,17>(17)) ); + + CALL_SUBTEST_9( (CauchyBounds<_Scalar,Dynamic>( + internal::random(18,26) )) ); +} + +void test_polynomialutils() +{ + for(int i = 0; i < g_repeat; i++) + { + realRoots_to_monicPolynomial_scalar(); + realRoots_to_monicPolynomial_scalar(); + CauchyBounds_scalar(); + CauchyBounds_scalar(); + } +} diff --git a/uppsrc/plugin/Eigen/unsupported/test/sparse_extra.cpp b/uppsrc/plugin/Eigen/unsupported/test/sparse_extra.cpp new file mode 100644 index 000000000..1ee791b0f --- /dev/null +++ b/uppsrc/plugin/Eigen/unsupported/test/sparse_extra.cpp @@ -0,0 +1,148 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008-2010 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + + +// import basic and product tests for deprectaed DynamicSparseMatrix +#define EIGEN_NO_DEPRECATED_WARNING +#include "sparse_basic.cpp" +#include "sparse_product.cpp" +#include + +template +bool test_random_setter(SparseMatrix& sm, const DenseType& ref, const std::vector& nonzeroCoords) +{ + { + sm.setZero(); + SetterType w(sm); + std::vector remaining = nonzeroCoords; + while(!remaining.empty()) + { + int i = internal::random(0,static_cast(remaining.size())-1); + w(remaining[i].x(),remaining[i].y()) = ref.coeff(remaining[i].x(),remaining[i].y()); + remaining[i] = remaining.back(); + remaining.pop_back(); + } + } + return sm.isApprox(ref); +} + +template +bool test_random_setter(DynamicSparseMatrix& sm, const DenseType& ref, const std::vector& nonzeroCoords) +{ + sm.setZero(); + std::vector remaining = nonzeroCoords; + while(!remaining.empty()) + { + int i = internal::random(0,static_cast(remaining.size())-1); + sm.coeffRef(remaining[i].x(),remaining[i].y()) = ref.coeff(remaining[i].x(),remaining[i].y()); + remaining[i] = remaining.back(); + remaining.pop_back(); + } + return sm.isApprox(ref); +} + +template void sparse_extra(const SparseMatrixType& ref) +{ + typedef typename SparseMatrixType::Index Index; + const Index rows = ref.rows(); + const Index cols = ref.cols(); + typedef typename SparseMatrixType::Scalar Scalar; + enum { Flags = SparseMatrixType::Flags }; + + double density = (std::max)(8./(rows*cols), 0.01); + typedef Matrix DenseMatrix; + typedef Matrix DenseVector; + Scalar eps = 1e-6; + + SparseMatrixType m(rows, cols); + DenseMatrix refMat = DenseMatrix::Zero(rows, cols); + DenseVector vec1 = DenseVector::Random(rows); + + std::vector zeroCoords; + std::vector nonzeroCoords; + initSparse(density, refMat, m, 0, &zeroCoords, &nonzeroCoords); + + if (zeroCoords.size()==0 || nonzeroCoords.size()==0) + return; + + // test coeff and coeffRef + for (int i=0; i<(int)zeroCoords.size(); ++i) + { + VERIFY_IS_MUCH_SMALLER_THAN( m.coeff(zeroCoords[i].x(),zeroCoords[i].y()), eps ); + if(internal::is_same >::value) + VERIFY_RAISES_ASSERT( m.coeffRef(zeroCoords[0].x(),zeroCoords[0].y()) = 5 ); + } + VERIFY_IS_APPROX(m, refMat); + + m.coeffRef(nonzeroCoords[0].x(), nonzeroCoords[0].y()) = Scalar(5); + refMat.coeffRef(nonzeroCoords[0].x(), nonzeroCoords[0].y()) = Scalar(5); + + VERIFY_IS_APPROX(m, refMat); + + // random setter +// { +// m.setZero(); +// VERIFY_IS_NOT_APPROX(m, refMat); +// SparseSetter w(m); +// std::vector remaining = nonzeroCoords; +// while(!remaining.empty()) +// { +// int i = internal::random(0,remaining.size()-1); +// w->coeffRef(remaining[i].x(),remaining[i].y()) = refMat.coeff(remaining[i].x(),remaining[i].y()); +// remaining[i] = remaining.back(); +// remaining.pop_back(); +// } +// } +// VERIFY_IS_APPROX(m, refMat); + + VERIFY(( test_random_setter >(m,refMat,nonzeroCoords) )); + #ifdef EIGEN_UNORDERED_MAP_SUPPORT + VERIFY(( test_random_setter >(m,refMat,nonzeroCoords) )); + #endif + #ifdef _DENSE_HASH_MAP_H_ + VERIFY(( test_random_setter >(m,refMat,nonzeroCoords) )); + #endif + #ifdef _SPARSE_HASH_MAP_H_ + VERIFY(( test_random_setter >(m,refMat,nonzeroCoords) )); + #endif + + + // test RandomSetter + /*{ + SparseMatrixType m1(rows,cols), m2(rows,cols); + DenseMatrix refM1 = DenseMatrix::Zero(rows, rows); + initSparse(density, refM1, m1); + { + Eigen::RandomSetter setter(m2); + for (int j=0; j(1,50); + CALL_SUBTEST_1( sparse_extra(SparseMatrix(8, 8)) ); + CALL_SUBTEST_2( sparse_extra(SparseMatrix >(s, s)) ); + CALL_SUBTEST_1( sparse_extra(SparseMatrix(s, s)) ); + + CALL_SUBTEST_3( sparse_extra(DynamicSparseMatrix(s, s)) ); +// CALL_SUBTEST_3(( sparse_basic(DynamicSparseMatrix(s, s)) )); +// CALL_SUBTEST_3(( sparse_basic(DynamicSparseMatrix(s, s)) )); + + CALL_SUBTEST_3( (sparse_product >()) ); + CALL_SUBTEST_3( (sparse_product >()) ); + } +} diff --git a/uppsrc/plugin/Eigen/unsupported/test/splines.cpp b/uppsrc/plugin/Eigen/unsupported/test/splines.cpp new file mode 100644 index 000000000..a7eb3e0c4 --- /dev/null +++ b/uppsrc/plugin/Eigen/unsupported/test/splines.cpp @@ -0,0 +1,244 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2010-2011 Hauke Heibel +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "main.h" + +#include + +namespace Eigen { + +// lets do some explicit instantiations and thus +// force the compilation of all spline functions... +template class Spline; +template class Spline; + +template class Spline; +template class Spline; +template class Spline; +template class Spline; + +template class Spline; +template class Spline; + +template class Spline; +template class Spline; +template class Spline; +template class Spline; + +} + +Spline closed_spline2d() +{ + RowVectorXd knots(12); + knots << 0, + 0, + 0, + 0, + 0.867193179093898, + 1.660330955342408, + 2.605084834823134, + 3.484154586374428, + 4.252699478956276, + 4.252699478956276, + 4.252699478956276, + 4.252699478956276; + + MatrixXd ctrls(8,2); + ctrls << -0.370967741935484, 0.236842105263158, + -0.231401860693277, 0.442245185027632, + 0.344361228532831, 0.773369994120753, + 0.828990216203802, 0.106550882647595, + 0.407270163678382, -1.043452922172848, + -0.488467813584053, -0.390098582530090, + -0.494657189446427, 0.054804824897884, + -0.370967741935484, 0.236842105263158; + ctrls.transposeInPlace(); + + return Spline(knots, ctrls); +} + +/* create a reference spline */ +Spline spline3d() +{ + RowVectorXd knots(11); + knots << 0, + 0, + 0, + 0.118997681558377, + 0.162611735194631, + 0.498364051982143, + 0.655098003973841, + 0.679702676853675, + 1.000000000000000, + 1.000000000000000, + 1.000000000000000; + + MatrixXd ctrls(8,3); + ctrls << 0.959743958516081, 0.340385726666133, 0.585267750979777, + 0.223811939491137, 0.751267059305653, 0.255095115459269, + 0.505957051665142, 0.699076722656686, 0.890903252535799, + 0.959291425205444, 0.547215529963803, 0.138624442828679, + 0.149294005559057, 0.257508254123736, 0.840717255983663, + 0.254282178971531, 0.814284826068816, 0.243524968724989, + 0.929263623187228, 0.349983765984809, 0.196595250431208, + 0.251083857976031, 0.616044676146639, 0.473288848902729; + ctrls.transposeInPlace(); + + return Spline(knots, ctrls); +} + +/* compares evaluations against known results */ +void eval_spline3d() +{ + Spline3d spline = spline3d(); + + RowVectorXd u(10); + u << 0.351659507062997, + 0.830828627896291, + 0.585264091152724, + 0.549723608291140, + 0.917193663829810, + 0.285839018820374, + 0.757200229110721, + 0.753729094278495, + 0.380445846975357, + 0.567821640725221; + + MatrixXd pts(10,3); + pts << 0.707620811535916, 0.510258911240815, 0.417485437023409, + 0.603422256426978, 0.529498282727551, 0.270351549348981, + 0.228364197569334, 0.423745615677815, 0.637687289287490, + 0.275556796335168, 0.350856706427970, 0.684295784598905, + 0.514519311047655, 0.525077224890754, 0.351628308305896, + 0.724152914315666, 0.574461155457304, 0.469860285484058, + 0.529365063753288, 0.613328702656816, 0.237837040141739, + 0.522469395136878, 0.619099658652895, 0.237139665242069, + 0.677357023849552, 0.480655768435853, 0.422227610314397, + 0.247046593173758, 0.380604672404750, 0.670065791405019; + pts.transposeInPlace(); + + for (int i=0; i::Interpolate(points,3); + + for (Eigen::DenseIndex i=0; i::Interpolate(points,3,chord_lengths); + + for (Eigen::DenseIndex i=0; i +// Copyright (C) 2009 Benoit Jacob +// +// Copyright (C) 2013 Gauthier Brun +// Copyright (C) 2013 Nicolas Carre +// Copyright (C) 2013 Jean Ceccato +// Copyright (C) 2013 Pierre Zoppitelli +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +// discard stack allocation as that too bypasses malloc +#define EIGEN_STACK_ALLOCATION_LIMIT 0 +#define EIGEN_RUNTIME_NO_MALLOC + +#include "main.h" +#include +#include + + +// check if "svd" is the good image of "m" +template +void svd_check_full(const MatrixType& m, const SVD& svd) +{ + typedef typename MatrixType::Index Index; + Index rows = m.rows(); + Index cols = m.cols(); + enum { + RowsAtCompileTime = MatrixType::RowsAtCompileTime, + ColsAtCompileTime = MatrixType::ColsAtCompileTime + }; + + typedef typename MatrixType::Scalar Scalar; + typedef Matrix MatrixUType; + typedef Matrix MatrixVType; + + + MatrixType sigma = MatrixType::Zero(rows, cols); + sigma.diagonal() = svd.singularValues().template cast(); + MatrixUType u = svd.matrixU(); + MatrixVType v = svd.matrixV(); + VERIFY_IS_APPROX(m, u * sigma * v.adjoint()); + VERIFY_IS_UNITARY(u); + VERIFY_IS_UNITARY(v); +} // end svd_check_full + + + +// Compare to a reference value +template +void svd_compare_to_full(const MatrixType& m, + unsigned int computationOptions, + const SVD& referenceSvd) +{ + typedef typename MatrixType::Index Index; + Index rows = m.rows(); + Index cols = m.cols(); + Index diagSize = (std::min)(rows, cols); + + SVD svd(m, computationOptions); + + VERIFY_IS_APPROX(svd.singularValues(), referenceSvd.singularValues()); + if(computationOptions & ComputeFullU) + VERIFY_IS_APPROX(svd.matrixU(), referenceSvd.matrixU()); + if(computationOptions & ComputeThinU) + VERIFY_IS_APPROX(svd.matrixU(), referenceSvd.matrixU().leftCols(diagSize)); + if(computationOptions & ComputeFullV) + VERIFY_IS_APPROX(svd.matrixV(), referenceSvd.matrixV()); + if(computationOptions & ComputeThinV) + VERIFY_IS_APPROX(svd.matrixV(), referenceSvd.matrixV().leftCols(diagSize)); +} // end svd_compare_to_full + + + +template +void svd_solve(const MatrixType& m, unsigned int computationOptions) +{ + typedef typename MatrixType::Scalar Scalar; + typedef typename MatrixType::Index Index; + Index rows = m.rows(); + Index cols = m.cols(); + + enum { + RowsAtCompileTime = MatrixType::RowsAtCompileTime, + ColsAtCompileTime = MatrixType::ColsAtCompileTime + }; + + typedef Matrix RhsType; + typedef Matrix SolutionType; + + RhsType rhs = RhsType::Random(rows, internal::random(1, cols)); + SVD svd(m, computationOptions); + SolutionType x = svd.solve(rhs); + // evaluate normal equation which works also for least-squares solutions + VERIFY_IS_APPROX(m.adjoint()*m*x,m.adjoint()*rhs); +} // end svd_solve + + +// test computations options +// 2 functions because Jacobisvd can return before the second function +template +void svd_test_computation_options_1(const MatrixType& m, const SVD& fullSvd) +{ + svd_check_full< MatrixType, SVD >(m, fullSvd); + svd_solve< MatrixType, SVD >(m, ComputeFullU | ComputeFullV); +} + + +template +void svd_test_computation_options_2(const MatrixType& m, const SVD& fullSvd) +{ + svd_compare_to_full< MatrixType, SVD >(m, ComputeFullU, fullSvd); + svd_compare_to_full< MatrixType, SVD >(m, ComputeFullV, fullSvd); + svd_compare_to_full< MatrixType, SVD >(m, 0, fullSvd); + + if (MatrixType::ColsAtCompileTime == Dynamic) { + // thin U/V are only available with dynamic number of columns + + svd_compare_to_full< MatrixType, SVD >(m, ComputeFullU|ComputeThinV, fullSvd); + svd_compare_to_full< MatrixType, SVD >(m, ComputeThinV, fullSvd); + svd_compare_to_full< MatrixType, SVD >(m, ComputeThinU|ComputeFullV, fullSvd); + svd_compare_to_full< MatrixType, SVD >(m, ComputeThinU , fullSvd); + svd_compare_to_full< MatrixType, SVD >(m, ComputeThinU|ComputeThinV, fullSvd); + svd_solve(m, ComputeFullU | ComputeThinV); + svd_solve(m, ComputeThinU | ComputeFullV); + svd_solve(m, ComputeThinU | ComputeThinV); + + typedef typename MatrixType::Index Index; + Index diagSize = (std::min)(m.rows(), m.cols()); + SVD svd(m, ComputeThinU | ComputeThinV); + VERIFY_IS_APPROX(m, svd.matrixU().leftCols(diagSize) * svd.singularValues().asDiagonal() * svd.matrixV().leftCols(diagSize).adjoint()); + } +} + +template +void svd_verify_assert(const MatrixType& m) +{ + typedef typename MatrixType::Scalar Scalar; + typedef typename MatrixType::Index Index; + Index rows = m.rows(); + Index cols = m.cols(); + + enum { + RowsAtCompileTime = MatrixType::RowsAtCompileTime, + ColsAtCompileTime = MatrixType::ColsAtCompileTime + }; + + typedef Matrix RhsType; + RhsType rhs(rows); + SVD svd; + VERIFY_RAISES_ASSERT(svd.matrixU()) + VERIFY_RAISES_ASSERT(svd.singularValues()) + VERIFY_RAISES_ASSERT(svd.matrixV()) + VERIFY_RAISES_ASSERT(svd.solve(rhs)) + MatrixType a = MatrixType::Zero(rows, cols); + a.setZero(); + svd.compute(a, 0); + VERIFY_RAISES_ASSERT(svd.matrixU()) + VERIFY_RAISES_ASSERT(svd.matrixV()) + svd.singularValues(); + VERIFY_RAISES_ASSERT(svd.solve(rhs)) + + if (ColsAtCompileTime == Dynamic) + { + svd.compute(a, ComputeThinU); + svd.matrixU(); + VERIFY_RAISES_ASSERT(svd.matrixV()) + VERIFY_RAISES_ASSERT(svd.solve(rhs)) + svd.compute(a, ComputeThinV); + svd.matrixV(); + VERIFY_RAISES_ASSERT(svd.matrixU()) + VERIFY_RAISES_ASSERT(svd.solve(rhs)) + } + else + { + VERIFY_RAISES_ASSERT(svd.compute(a, ComputeThinU)) + VERIFY_RAISES_ASSERT(svd.compute(a, ComputeThinV)) + } +} + +// work around stupid msvc error when constructing at compile time an expression that involves +// a division by zero, even if the numeric type has floating point +template +EIGEN_DONT_INLINE Scalar zero() { return Scalar(0); } + +// workaround aggressive optimization in ICC +template EIGEN_DONT_INLINE T sub(T a, T b) { return a - b; } + + +template +void svd_inf_nan() +{ + // all this function does is verify we don't iterate infinitely on nan/inf values + + SVD svd; + typedef typename MatrixType::Scalar Scalar; + Scalar some_inf = Scalar(1) / zero(); + VERIFY(sub(some_inf, some_inf) != sub(some_inf, some_inf)); + svd.compute(MatrixType::Constant(10,10,some_inf), ComputeFullU | ComputeFullV); + + Scalar some_nan = zero () / zero (); + VERIFY(some_nan != some_nan); + svd.compute(MatrixType::Constant(10,10,some_nan), ComputeFullU | ComputeFullV); + + MatrixType m = MatrixType::Zero(10,10); + m(internal::random(0,9), internal::random(0,9)) = some_inf; + svd.compute(m, ComputeFullU | ComputeFullV); + + m = MatrixType::Zero(10,10); + m(internal::random(0,9), internal::random(0,9)) = some_nan; + svd.compute(m, ComputeFullU | ComputeFullV); +} + + +template +void svd_preallocate() +{ + Vector3f v(3.f, 2.f, 1.f); + MatrixXf m = v.asDiagonal(); + + internal::set_is_malloc_allowed(false); + VERIFY_RAISES_ASSERT(VectorXf v(10);) + SVD svd; + internal::set_is_malloc_allowed(true); + svd.compute(m); + VERIFY_IS_APPROX(svd.singularValues(), v); + + SVD svd2(3,3); + internal::set_is_malloc_allowed(false); + svd2.compute(m); + internal::set_is_malloc_allowed(true); + VERIFY_IS_APPROX(svd2.singularValues(), v); + VERIFY_RAISES_ASSERT(svd2.matrixU()); + VERIFY_RAISES_ASSERT(svd2.matrixV()); + svd2.compute(m, ComputeFullU | ComputeFullV); + VERIFY_IS_APPROX(svd2.matrixU(), Matrix3f::Identity()); + VERIFY_IS_APPROX(svd2.matrixV(), Matrix3f::Identity()); + internal::set_is_malloc_allowed(false); + svd2.compute(m); + internal::set_is_malloc_allowed(true); + + SVD svd3(3,3,ComputeFullU|ComputeFullV); + internal::set_is_malloc_allowed(false); + svd2.compute(m); + internal::set_is_malloc_allowed(true); + VERIFY_IS_APPROX(svd2.singularValues(), v); + VERIFY_IS_APPROX(svd2.matrixU(), Matrix3f::Identity()); + VERIFY_IS_APPROX(svd2.matrixV(), Matrix3f::Identity()); + internal::set_is_malloc_allowed(false); + svd2.compute(m, ComputeFullU|ComputeFullV); + internal::set_is_malloc_allowed(true); +} + + + + +