diff options
author | Stanislaw Halik <sthalik@misaki.pl> | 2016-09-18 12:42:15 +0200 |
---|---|---|
committer | Stanislaw Halik <sthalik@misaki.pl> | 2016-11-02 15:12:04 +0100 |
commit | 44861dcbfeee041223c4aac1ee075e92fa4daa01 (patch) | |
tree | 6dfdfd9637846a7aedd71ace97d7d2ad366496d7 /eigen/unsupported/test | |
parent | f3fe458b9e0a29a99a39d47d9a76dc18964b6fec (diff) |
update
Diffstat (limited to 'eigen/unsupported/test')
29 files changed, 10089 insertions, 0 deletions
diff --git a/eigen/unsupported/test/BVH.cpp b/eigen/unsupported/test/BVH.cpp new file mode 100644 index 0000000..ff5b329 --- /dev/null +++ b/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 <ibaran@mit.edu> +// +// 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 <Eigen/StdVector> +#include <Eigen/Geometry> +#include <unsupported/Eigen/BVH> + +namespace Eigen { + +template<typename Scalar, int Dim> AlignedBox<Scalar, Dim> bounding_box(const Matrix<Scalar, Dim, 1> &v) { return AlignedBox<Scalar, Dim>(v); } + +} + + +template<int Dim> +struct Ball +{ +EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(double, Dim) + + typedef Matrix<double, Dim, 1> VectorType; + + Ball() {} + Ball(const VectorType &c, double r) : center(c), radius(r) {} + + VectorType center; + double radius; +}; +template<int Dim> AlignedBox<double, Dim> bounding_box(const Ball<Dim> &b) +{ return AlignedBox<double, Dim>(b.center.array() - b.radius, b.center.array() + b.radius); } + +inline double SQR(double x) { return x * x; } + +template<int Dim> +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<double, Dim, 1> VectorType; + typedef Ball<Dim> BallType; + typedef AlignedBox<double, Dim> 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<int Dim> +struct TreeTest +{ + typedef Matrix<double, Dim, 1> VectorType; + typedef std::vector<VectorType, aligned_allocator<VectorType> > VectorTypeList; + typedef Ball<Dim> BallType; + typedef std::vector<BallType, aligned_allocator<BallType> > BallTypeList; + typedef AlignedBox<double, Dim> 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<double, Dim, BallType> tree(b.begin(), b.end()); + + VectorType pt = VectorType::Random(); + BallPointStuff<Dim> 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<double, Dim, BallType> tree(b.begin(), b.end()); + + VectorType pt = VectorType::Random(); + BallPointStuff<Dim> i1(pt), i2(pt); + + double m1 = (std::numeric_limits<double>::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<double, Dim, BallType> tree(b.begin(), b.end()); + KdBVH<double, Dim, VectorType> vTree(v.begin(), v.end()); + + BallPointStuff<Dim> 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<double, Dim, BallType> tree(b.begin(), b.end()); + KdBVH<double, Dim, VectorType> vTree(v.begin(), v.end()); + + BallPointStuff<Dim> i1, i2; + + double m1 = (std::numeric_limits<double>::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/eigen/unsupported/test/CMakeLists.txt b/eigen/unsupported/test/CMakeLists.txt new file mode 100644 index 0000000..2e4cfdb --- /dev/null +++ b/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/eigen/unsupported/test/FFT.cpp b/eigen/unsupported/test/FFT.cpp new file mode 100644 index 0000000..45c87f5 --- /dev/null +++ b/eigen/unsupported/test/FFT.cpp @@ -0,0 +1,2 @@ +#define test_FFTW test_FFT +#include "FFTW.cpp" diff --git a/eigen/unsupported/test/FFTW.cpp b/eigen/unsupported/test/FFTW.cpp new file mode 100644 index 0000000..d3718e2 --- /dev/null +++ b/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 <unsupported/Eigen/FFT> + +template <typename T> +std::complex<T> RandomCpx() { return std::complex<T>( (T)(rand()/(T)RAND_MAX - .5), (T)(rand()/(T)RAND_MAX - .5) ); } + +using namespace std; +using namespace Eigen; + + +template < typename T> +complex<long double> promote(complex<T> x) { return complex<long double>(x.real(),x.imag()); } + +complex<long double> promote(float x) { return complex<long double>( x); } +complex<long double> promote(double x) { return complex<long double>( x); } +complex<long double> promote(long double x) { return complex<long double>( x); } + + + template <typename VT1,typename VT2> + 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<long double> 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<long double>(0,k1*phinc) ); + } + totalpower += numext::abs2(acc); + complex<long double> x = promote(fftbuf[k0]); + complex<long double> 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 <typename VT1,typename VT2> + 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<n;++k) { + totalpower += (numext::abs2( buf1[k] ) + numext::abs2(buf2[k]) )/2.; + difpower += numext::abs2(buf1[k] - buf2[k]); + } + return sqrt(difpower/totalpower); + } + +enum { StdVectorContainer, EigenVectorContainer }; + +template<int Container, typename Scalar> struct VectorType; + +template<typename Scalar> struct VectorType<StdVectorContainer,Scalar> +{ + typedef vector<Scalar> type; +}; + +template<typename Scalar> struct VectorType<EigenVectorContainer,Scalar> +{ + typedef Matrix<Scalar,Dynamic,1> type; +}; + +template <int Container, typename T> +void test_scalar_generic(int nfft) +{ + typedef typename FFT<T>::Complex Complex; + typedef typename FFT<T>::Scalar Scalar; + typedef typename VectorType<Container,Scalar>::type ScalarVector; + typedef typename VectorType<Container,Complex>::type ComplexVector; + + FFT<T> fft; + ScalarVector tbuf(nfft); + ComplexVector freqBuf; + for (int k=0;k<nfft;++k) + tbuf[k]= (T)( rand()/(double)RAND_MAX - .5); + + // make sure it DOESN'T give the right full spectrum answer + // if we've asked for half-spectrum + fft.SetFlag(fft.HalfSpectrum ); + fft.fwd( freqBuf,tbuf); + VERIFY((size_t)freqBuf.size() == (size_t)( (nfft>>1)+1) ); + VERIFY( fft_rmse(freqBuf,tbuf) < test_precision<T>() );// 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<T>() );// 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<T>() );// gross check + + + // verify that the Unscaled flag takes effect + ScalarVector tbuf3; + fft.SetFlag(fft.Unscaled); + + fft.inv( tbuf3 , freqBuf); + + for (int k=0;k<nfft;++k) + tbuf3[k] *= T(1./nfft); + + + //for (size_t i=0;i<(size_t) tbuf.size();++i) + // cout << "freqBuf=" << freqBuf[i] << " in2=" << tbuf3[i] << " - in=" << tbuf[i] << " => " << (tbuf3[i] - tbuf[i] ) << endl; + + VERIFY( dif_rmse(tbuf,tbuf3) < test_precision<T>() );// gross check + + // verify that ClearFlag works + fft.ClearFlag(fft.Unscaled); + fft.inv( tbuf2 , freqBuf); + VERIFY( dif_rmse(tbuf,tbuf2) < test_precision<T>() );// gross check +} + +template <typename T> +void test_scalar(int nfft) +{ + test_scalar_generic<StdVectorContainer,T>(nfft); + //test_scalar_generic<EigenVectorContainer,T>(nfft); +} + + +template <int Container, typename T> +void test_complex_generic(int nfft) +{ + typedef typename FFT<T>::Complex Complex; + typedef typename VectorType<Container,Complex>::type ComplexVector; + + FFT<T> fft; + + ComplexVector inbuf(nfft); + ComplexVector outbuf; + ComplexVector buf3; + for (int k=0;k<nfft;++k) + inbuf[k]= Complex( (T)(rand()/(double)RAND_MAX - .5), (T)(rand()/(double)RAND_MAX - .5) ); + fft.fwd( outbuf , inbuf); + + VERIFY( fft_rmse(outbuf,inbuf) < test_precision<T>() );// gross check + fft.inv( buf3 , outbuf); + + VERIFY( dif_rmse(inbuf,buf3) < test_precision<T>() );// gross check + + // verify that the Unscaled flag takes effect + ComplexVector buf4; + fft.SetFlag(fft.Unscaled); + fft.inv( buf4 , outbuf); + for (int k=0;k<nfft;++k) + buf4[k] *= T(1./nfft); + VERIFY( dif_rmse(inbuf,buf4) < test_precision<T>() );// gross check + + // verify that ClearFlag works + fft.ClearFlag(fft.Unscaled); + fft.inv( buf3 , outbuf); + VERIFY( dif_rmse(inbuf,buf3) < test_precision<T>() );// gross check +} + +template <typename T> +void test_complex(int nfft) +{ + test_complex_generic<StdVectorContainer,T>(nfft); + test_complex_generic<EigenVectorContainer,T>(nfft); +} +/* +template <typename T,int nrows,int ncols> +void test_complex2d() +{ + typedef typename Eigen::FFT<T>::Complex Complex; + FFT<T> fft; + Eigen::Matrix<Complex,nrows,ncols> src,src2,dst,dst2; + + src = Eigen::Matrix<Complex,nrows,ncols>::Random(); + //src = Eigen::Matrix<Complex,nrows,ncols>::Identity(); + + for (int k=0;k<ncols;k++) { + Eigen::Matrix<Complex,nrows,1> tmpOut; + fft.fwd( tmpOut,src.col(k) ); + dst2.col(k) = tmpOut; + } + + for (int k=0;k<nrows;k++) { + Eigen::Matrix<Complex,1,ncols> 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<T>() ); + VERIFY( (dst-dst2).norm() < test_precision<T>() ); +} +*/ + + +void test_return_by_value(int len) +{ + VectorXf in; + VectorXf in1; + in.setRandom( len ); + VectorXcf out1,out2; + FFT<float> fft; + + fft.SetFlag(fft.HalfSpectrum ); + + fft.fwd(out1,in); + out2 = fft.fwd(in); + VERIFY( (out1-out2).norm() < test_precision<float>() ); + in1 = fft.inv(out1); + VERIFY( (in1-in).norm() < test_precision<float>() ); +} + +void test_FFTW() +{ + CALL_SUBTEST( test_return_by_value(32) ); + //CALL_SUBTEST( ( test_complex2d<float,4,8> () ) ); CALL_SUBTEST( ( test_complex2d<double,4,8> () ) ); + //CALL_SUBTEST( ( test_complex2d<long double,4,8> () ) ); + CALL_SUBTEST( test_complex<float>(32) ); CALL_SUBTEST( test_complex<double>(32) ); + CALL_SUBTEST( test_complex<float>(256) ); CALL_SUBTEST( test_complex<double>(256) ); + CALL_SUBTEST( test_complex<float>(3*8) ); CALL_SUBTEST( test_complex<double>(3*8) ); + CALL_SUBTEST( test_complex<float>(5*32) ); CALL_SUBTEST( test_complex<double>(5*32) ); + CALL_SUBTEST( test_complex<float>(2*3*4) ); CALL_SUBTEST( test_complex<double>(2*3*4) ); + CALL_SUBTEST( test_complex<float>(2*3*4*5) ); CALL_SUBTEST( test_complex<double>(2*3*4*5) ); + CALL_SUBTEST( test_complex<float>(2*3*4*5*7) ); CALL_SUBTEST( test_complex<double>(2*3*4*5*7) ); + + CALL_SUBTEST( test_scalar<float>(32) ); CALL_SUBTEST( test_scalar<double>(32) ); + CALL_SUBTEST( test_scalar<float>(45) ); CALL_SUBTEST( test_scalar<double>(45) ); + CALL_SUBTEST( test_scalar<float>(50) ); CALL_SUBTEST( test_scalar<double>(50) ); + CALL_SUBTEST( test_scalar<float>(256) ); CALL_SUBTEST( test_scalar<double>(256) ); + CALL_SUBTEST( test_scalar<float>(2*3*4*5*7) ); CALL_SUBTEST( test_scalar<double>(2*3*4*5*7) ); + + #ifdef EIGEN_HAS_FFTWL + CALL_SUBTEST( test_complex<long double>(32) ); + CALL_SUBTEST( test_complex<long double>(256) ); + CALL_SUBTEST( test_complex<long double>(3*8) ); + CALL_SUBTEST( test_complex<long double>(5*32) ); + CALL_SUBTEST( test_complex<long double>(2*3*4) ); + CALL_SUBTEST( test_complex<long double>(2*3*4*5) ); + CALL_SUBTEST( test_complex<long double>(2*3*4*5*7) ); + + CALL_SUBTEST( test_scalar<long double>(32) ); + CALL_SUBTEST( test_scalar<long double>(45) ); + CALL_SUBTEST( test_scalar<long double>(50) ); + CALL_SUBTEST( test_scalar<long double>(256) ); + CALL_SUBTEST( test_scalar<long double>(2*3*4*5*7) ); + #endif +} diff --git a/eigen/unsupported/test/NonLinearOptimization.cpp b/eigen/unsupported/test/NonLinearOptimization.cpp new file mode 100644 index 0000000..d7376b0 --- /dev/null +++ b/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 <orzel@freehackers.org> + +#include <stdio.h> + +#include "main.h" +#include <unsupported/Eigen/NonLinearOptimization> + +// This disables some useless Warnings on MSVC. +// It is intended to be done for this test only. +#include <Eigen/src/Core/util/DisableStupidWarnings.h> + +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<typename _Scalar, int NX=Dynamic, int NY=Dynamic> +struct Functor +{ + typedef _Scalar Scalar; + enum { + InputsAtCompileTime = NX, + ValuesAtCompileTime = NY + }; + typedef Matrix<Scalar,InputsAtCompileTime,1> InputType; + typedef Matrix<Scalar,ValuesAtCompileTime,1> ValueType; + typedef Matrix<Scalar,ValuesAtCompileTime,InputsAtCompileTime> 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<double> +{ + lmder_functor(void): Functor<double>(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<lmder_functor> 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<lmder_functor> 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<n,n>(); + VERIFY_IS_APPROX( cov, cov_ref); + // TODO: why isn't this allowed ? : + // VERIFY_IS_APPROX( covfac*fjac.topLeftCorner<n,n>() , cov_ref); +} + +struct hybrj_functor : Functor<double> +{ + hybrj_functor(void) : Functor<double>(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<hybrj_functor> 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<hybrj_functor> 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<double> +{ + hybrd_functor(void) : Functor<double>(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<hybrd_functor> 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<hybrd_functor> 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<double> +{ + lmstr_functor(void) : Functor<double>(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<lmstr_functor> 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<lmstr_functor> 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<double> +{ + lmdif_functor(void) : Functor<double>(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<lmdif_functor>::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<lmdif_functor> numDiff(functor); + LevenbergMarquardt<NumericalDiff<lmdif_functor> > 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<n,n>(); + VERIFY_IS_APPROX( cov, cov_ref); + // TODO: why isn't this allowed ? : + // VERIFY_IS_APPROX( covfac*fjac.topLeftCorner<n,n>() , cov_ref); +} + +struct chwirut2_functor : Functor<double> +{ + chwirut2_functor(void) : Functor<double>(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<chwirut2_functor> 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<double>::epsilon(); + lm.parameters.xtol = 1.E6*NumTraits<double>::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<double> +{ + misra1a_functor(void) : Functor<double>(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<misra1a_functor> 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<double> +{ + hahn1_functor(void) : Functor<double>(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<hahn1_functor> 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<double> +{ + misra1d_functor(void) : Functor<double>(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<misra1d_functor> 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<double> +{ + lanczos1_functor(void) : Functor<double>(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<lanczos1_functor> 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<double> +{ + rat42_functor(void) : Functor<double>(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<rat42_functor> 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<double> +{ + MGH10_functor(void) : Functor<double>(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<MGH10_functor> 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<double> +{ + BoxBOD_functor(void) : Functor<double>(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<BoxBOD_functor> lm(functor); + lm.parameters.ftol = 1.E6*NumTraits<double>::epsilon(); + lm.parameters.xtol = 1.E6*NumTraits<double>::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<double>::epsilon(); + lm.parameters.xtol = NumTraits<double>::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<double> +{ + MGH17_functor(void) : Functor<double>(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<MGH17_functor> lm(functor); + lm.parameters.ftol = NumTraits<double>::epsilon(); + lm.parameters.xtol = NumTraits<double>::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<double> +{ + MGH09_functor(void) : Functor<double>(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<MGH09_functor> 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<double> +{ + Bennett5_functor(void) : Functor<double>(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<Bennett5_functor> 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<double> +{ + thurber_functor(void) : Functor<double>(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<thurber_functor> lm(functor); + lm.parameters.ftol = 1.E4*NumTraits<double>::epsilon(); + lm.parameters.xtol = 1.E4*NumTraits<double>::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<double>::epsilon(); + lm.parameters.xtol = 1.E4*NumTraits<double>::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<double> +{ + rat43_functor(void) : Functor<double>(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<rat43_functor> lm(functor); + lm.parameters.ftol = 1.E6*NumTraits<double>::epsilon(); + lm.parameters.xtol = 1.E6*NumTraits<double>::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<double>::epsilon(); + lm.parameters.xtol = 1.E5*NumTraits<double>::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<double> +{ + eckerle4_functor(void) : Functor<double>(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<eckerle4_functor> 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/eigen/unsupported/test/NumericalDiff.cpp b/eigen/unsupported/test/NumericalDiff.cpp new file mode 100644 index 0000000..27d8880 --- /dev/null +++ b/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 <orzel@freehackers.org> + +#include <stdio.h> + +#include "main.h" +#include <unsupported/Eigen/NumericalDiff> + +// Generic functor +template<typename _Scalar, int NX=Dynamic, int NY=Dynamic> +struct Functor +{ + typedef _Scalar Scalar; + enum { + InputsAtCompileTime = NX, + ValuesAtCompileTime = NY + }; + typedef Matrix<Scalar,InputsAtCompileTime,1> InputType; + typedef Matrix<Scalar,ValuesAtCompileTime,1> ValueType; + typedef Matrix<Scalar,ValuesAtCompileTime,InputsAtCompileTime> 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<double> +{ + my_functor(void): Functor<double>(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<my_functor> 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<my_functor,Central> 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/eigen/unsupported/test/alignedvector3.cpp b/eigen/unsupported/test/alignedvector3.cpp new file mode 100644 index 0000000..fc2bc21 --- /dev/null +++ b/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 <g.gael@free.fr> +// +// 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 <unsupported/Eigen/AlignedVector3> + +template<typename Scalar> +void alignedvector3() +{ + Scalar s1 = internal::random<Scalar>(); + Scalar s2 = internal::random<Scalar>(); + typedef Matrix<Scalar,3,1> RefType; + typedef Matrix<Scalar,3,3> Mat33; + typedef AlignedVector3<Scalar> 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<float>() ); + } +} diff --git a/eigen/unsupported/test/autodiff.cpp b/eigen/unsupported/test/autodiff.cpp new file mode 100644 index 0000000..7c112a1 --- /dev/null +++ b/eigen/unsupported/test/autodiff.cpp @@ -0,0 +1,184 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2009 Gael Guennebaud <g.gael@free.fr> +// +// 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 <unsupported/Eigen/AutoDiff> + +template<typename Scalar> +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<Scalar>(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<typename Vector> +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<typename _Scalar, int NX=Dynamic, int NY=Dynamic> +struct TestFunc1 +{ + typedef _Scalar Scalar; + enum { + InputsAtCompileTime = NX, + ValuesAtCompileTime = NY + }; + typedef Matrix<Scalar,InputsAtCompileTime,1> InputType; + typedef Matrix<Scalar,ValuesAtCompileTime,1> ValueType; + typedef Matrix<Scalar,ValuesAtCompileTime,InputsAtCompileTime> 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<typename T> + void operator() (const Matrix<T,InputsAtCompileTime,1>& x, Matrix<T,ValuesAtCompileTime,1>* _v) const + { + Matrix<T,ValuesAtCompileTime,1>& 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<typename Func> 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<Func> 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<Vector2f> AD; + AD ax(p.x(),Vector2f::UnitX()); + AD ay(p.y(),Vector2f::UnitY()); + AD res = foo<AD>(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<Vector2f> AD; + typedef Matrix<AD,2,1> VectorAD; + VectorAD ap = p.cast<AD>(); + ap.x().derivatives() = Vector2f::UnitX(); + ap.y().derivatives() = Vector2f::UnitY(); + + AD res = foo<VectorAD>(ap); + VERIFY_IS_APPROX(res.value(), foo(p)); +} + +void test_autodiff_jacobian() +{ + CALL_SUBTEST(( forward_jacobian(TestFunc1<double,2,2>()) )); + CALL_SUBTEST(( forward_jacobian(TestFunc1<double,2,3>()) )); + CALL_SUBTEST(( forward_jacobian(TestFunc1<double,3,2>()) )); + CALL_SUBTEST(( forward_jacobian(TestFunc1<double,3,3>()) )); + CALL_SUBTEST(( forward_jacobian(TestFunc1<double>(3,3)) )); +} + +double bug_1222() { + typedef Eigen::AutoDiffScalar<Eigen::Vector3d> AD; + const double _cv1_3 = 1.0; + const AD chi_3 = 1.0; + // this line did not work, because operator+ returns ADS<DerType&>, which then cannot be converted to ADS<DerType> + const AD denom = chi_3 + _cv1_3; + return denom.value(); +} + +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() ); + } + + bug_1222(); +} + diff --git a/eigen/unsupported/test/bdcsvd.cpp b/eigen/unsupported/test/bdcsvd.cpp new file mode 100644 index 0000000..115a649 --- /dev/null +++ b/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 <brun.gauthier@gmail.com> +// Copyright (C) 2013 Nicolas Carre <nicolas.carre@ensimag.fr> +// Copyright (C) 2013 Jean Ceccato <jean.ceccato@ensimag.fr> +// Copyright (C) 2013 Pierre Zoppitelli <pierre.zoppitelli@ensimag.fr> +// +// 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 <iostream> +#include <Eigen/LU> + +// check if "svd" is the good image of "m" +template<typename MatrixType> +void bdcsvd_check_full(const MatrixType& m, const BDCSVD<MatrixType>& svd) +{ + svd_check_full< MatrixType, BDCSVD< MatrixType > >(m, svd); +} + +// Compare to a reference value +template<typename MatrixType> +void bdcsvd_compare_to_full(const MatrixType& m, + unsigned int computationOptions, + const BDCSVD<MatrixType>& referenceSvd) +{ + svd_compare_to_full< MatrixType, BDCSVD< MatrixType > >(m, computationOptions, referenceSvd); +} // end bdcsvd_compare_to_full + + +template<typename MatrixType> +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<typename MatrixType> +void bdcsvd_test_all_computation_options(const MatrixType& m) +{ + BDCSVD<MatrixType> 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<typename MatrixType> +void bdcsvd(const MatrixType& a = MatrixType(), bool pickrandom = true) +{ + MatrixType m = pickrandom ? MatrixType::Random(a.rows(), a.cols()) : a; + bdcsvd_test_all_computation_options<MatrixType>(m); +} // end template bdcsvd + + +// verify assert +template<typename MatrixType> +void bdcsvd_verify_assert(const MatrixType& m) +{ + svd_verify_assert< MatrixType, BDCSVD< MatrixType > >(m); +}// end template bdcsvd_verify_assert + + +// test weird values +template<typename MatrixType> +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<typename MatrixType> +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<MatrixType> bdc_svd(m); + JacobiSVD<MatrixType> 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<float,Dynamic,Dynamic> > + (Matrix<float,Dynamic,Dynamic>(42,42)) )); + CALL_SUBTEST_11(( compare_bdc_jacobi<Matrix<float,Dynamic,Dynamic> > + (Matrix<float,Dynamic,Dynamic>(42,42), 0) )); + CALL_SUBTEST_11(( bdcsvd<Matrix<float,Dynamic,Dynamic> > + (Matrix<float,Dynamic,Dynamic>(42,42)) )); + + // test of Dynamic defined Matrix (50, 50) of double + CALL_SUBTEST_13(( bdcsvd_verify_assert<Matrix<double,Dynamic,Dynamic> > + (Matrix<double,Dynamic,Dynamic>(50,50)) )); + CALL_SUBTEST_13(( compare_bdc_jacobi<Matrix<double,Dynamic,Dynamic> > + (Matrix<double,Dynamic,Dynamic>(50,50), 0) )); + CALL_SUBTEST_13(( bdcsvd<Matrix<double,Dynamic,Dynamic> > + (Matrix<double,Dynamic,Dynamic>(50, 50)) )); + + // test of Dynamic defined Matrix (22, 22) of complex double + CALL_SUBTEST_14(( bdcsvd_verify_assert<Matrix<std::complex<double>,Dynamic,Dynamic> > + (Matrix<std::complex<double>,Dynamic,Dynamic>(22,22)) )); + CALL_SUBTEST_14(( compare_bdc_jacobi<Matrix<std::complex<double>,Dynamic,Dynamic> > + (Matrix<std::complex<double>, Dynamic, Dynamic> (22,22), 0) )); + CALL_SUBTEST_14(( bdcsvd<Matrix<std::complex<double>,Dynamic,Dynamic> > + (Matrix<std::complex<double>,Dynamic,Dynamic>(22, 22)) )); + + // test of Dynamic defined Matrix (10, 10) of int + //CALL_SUBTEST_15(( bdcsvd_verify_assert<Matrix<int,Dynamic,Dynamic> > + // (Matrix<int,Dynamic,Dynamic>(10,10)) )); + //CALL_SUBTEST_15(( compare_bdc_jacobi<Matrix<int,Dynamic,Dynamic> > + // (Matrix<int,Dynamic,Dynamic>(10,10), 0) )); + //CALL_SUBTEST_15(( bdcsvd<Matrix<int,Dynamic,Dynamic> > + // (Matrix<int,Dynamic,Dynamic>(10, 10)) )); + + + // test of Dynamic defined Matrix (8, 6) of double + + CALL_SUBTEST_16(( bdcsvd_verify_assert<Matrix<double,Dynamic,Dynamic> > + (Matrix<double,Dynamic,Dynamic>(8,6)) )); + CALL_SUBTEST_16(( compare_bdc_jacobi<Matrix<double,Dynamic,Dynamic> > + (Matrix<double,Dynamic,Dynamic>(8, 6), 0) )); + CALL_SUBTEST_16(( bdcsvd<Matrix<double,Dynamic,Dynamic> > + (Matrix<double,Dynamic,Dynamic>(8, 6)) )); + + + + // test of Dynamic defined Matrix (36, 12) of float + CALL_SUBTEST_17(( compare_bdc_jacobi<Matrix<float,Dynamic,Dynamic> > + (Matrix<float,Dynamic,Dynamic>(36, 12), 0) )); + CALL_SUBTEST_17(( bdcsvd<Matrix<float,Dynamic,Dynamic> > + (Matrix<float,Dynamic,Dynamic>(36, 12)) )); + + // test of Dynamic defined Matrix (5, 8) of double + CALL_SUBTEST_18(( compare_bdc_jacobi<Matrix<double,Dynamic,Dynamic> > + (Matrix<double,Dynamic,Dynamic>(5, 8), 0) )); + CALL_SUBTEST_18(( bdcsvd<Matrix<double,Dynamic,Dynamic> > + (Matrix<double,Dynamic,Dynamic>(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<Matrix3f>() )); + // bdc algo on a random 4x4 double matrix + // CALL_SUBTEST_4(( bdcsvd<Matrix4d>() )); + // bdc algo on a random 3x5 float matrix + // CALL_SUBTEST_5(( bdcsvd<Matrix<float,3,5> >() )); + + int r = internal::random<int>(1, 30), + c = internal::random<int>(1, 30); + CALL_SUBTEST_7(( bdcsvd<MatrixXf>(MatrixXf(r,c)) )); + CALL_SUBTEST_8(( bdcsvd<MatrixXcd>(MatrixXcd(r,c)) )); + (void) r; + (void) c; + + // Test on inf/nan matrix + CALL_SUBTEST_7( bdcsvd_inf_nan<MatrixXf>() ); + } + + CALL_SUBTEST_7(( bdcsvd<MatrixXf>(MatrixXf(internal::random<int>(EIGEN_TEST_MAX_SIZE/4, EIGEN_TEST_MAX_SIZE/2), internal::random<int>(EIGEN_TEST_MAX_SIZE/4, EIGEN_TEST_MAX_SIZE/2))) )); + CALL_SUBTEST_8(( bdcsvd<MatrixXcd>(MatrixXcd(internal::random<int>(EIGEN_TEST_MAX_SIZE/4, EIGEN_TEST_MAX_SIZE/3), internal::random<int>(EIGEN_TEST_MAX_SIZE/4, EIGEN_TEST_MAX_SIZE/3))) )); + + // Test problem size constructors + CALL_SUBTEST_7( BDCSVD<MatrixXf>(10,10) ); + +} // end test_bdcsvd diff --git a/eigen/unsupported/test/dgmres.cpp b/eigen/unsupported/test/dgmres.cpp new file mode 100644 index 0000000..2b11807 --- /dev/null +++ b/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 <g.gael@free.fr> +// Copyright (C) 2012 desire Nuentsa <desire.nuentsa_wakam@inria.fr +// +// 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 <Eigen/src/IterativeSolvers/DGMRES.h> + +template<typename T> void test_dgmres_T() +{ + DGMRES<SparseMatrix<T>, DiagonalPreconditioner<T> > dgmres_colmajor_diag; + DGMRES<SparseMatrix<T>, IdentityPreconditioner > dgmres_colmajor_I; + DGMRES<SparseMatrix<T>, IncompleteLUT<T> > dgmres_colmajor_ilut; + //GMRES<SparseMatrix<T>, SSORPreconditioner<T> > 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<double>()); + CALL_SUBTEST_2(test_dgmres_T<std::complex<double> >()); +} diff --git a/eigen/unsupported/test/forward_adolc.cpp b/eigen/unsupported/test/forward_adolc.cpp new file mode 100644 index 0000000..d4baafe --- /dev/null +++ b/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 <g.gael@free.fr> +// +// 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 <Eigen/Dense> + +#define NUMBER_DIRECTIONS 16 +#include <unsupported/Eigen/AdolcForward> + +int adtl::ADOLC_numDir; + +template<typename Vector> +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<typename _Scalar, int NX=Dynamic, int NY=Dynamic> +struct TestFunc1 +{ + typedef _Scalar Scalar; + enum { + InputsAtCompileTime = NX, + ValuesAtCompileTime = NY + }; + typedef Matrix<Scalar,InputsAtCompileTime,1> InputType; + typedef Matrix<Scalar,ValuesAtCompileTime,1> ValueType; + typedef Matrix<Scalar,ValuesAtCompileTime,InputsAtCompileTime> 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<typename T> + void operator() (const Matrix<T,InputsAtCompileTime,1>& x, Matrix<T,ValuesAtCompileTime,1>* _v) const + { + Matrix<T,ValuesAtCompileTime,1>& 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<typename Func> 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<Func> 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<double,2,2>()) )); + CALL_SUBTEST(( adolc_forward_jacobian(TestFunc1<double,2,3>()) )); + CALL_SUBTEST(( adolc_forward_jacobian(TestFunc1<double,3,2>()) )); + CALL_SUBTEST(( adolc_forward_jacobian(TestFunc1<double,3,3>()) )); + CALL_SUBTEST(( adolc_forward_jacobian(TestFunc1<double>(3,3)) )); + } + + { + // simple instanciation tests + Matrix<adtl::adouble,2,1> x; + foo(x); + Matrix<adtl::adouble,Dynamic,Dynamic> A(4,4);; + A.selfadjointView<Lower>().eigenvalues(); + } +} diff --git a/eigen/unsupported/test/gmres.cpp b/eigen/unsupported/test/gmres.cpp new file mode 100644 index 0000000..f296911 --- /dev/null +++ b/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 <g.gael@free.fr> +// Copyright (C) 2012 Kolja Brix <brix@igpm.rwth-aaachen.de> +// +// 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 <Eigen/IterativeSolvers> + +template<typename T> void test_gmres_T() +{ + GMRES<SparseMatrix<T>, DiagonalPreconditioner<T> > gmres_colmajor_diag; + GMRES<SparseMatrix<T>, IdentityPreconditioner > gmres_colmajor_I; + GMRES<SparseMatrix<T>, IncompleteLUT<T> > gmres_colmajor_ilut; + //GMRES<SparseMatrix<T>, SSORPreconditioner<T> > 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<double>()); + CALL_SUBTEST_2(test_gmres_T<std::complex<double> >()); +} diff --git a/eigen/unsupported/test/jacobisvd.cpp b/eigen/unsupported/test/jacobisvd.cpp new file mode 100644 index 0000000..b4e884e --- /dev/null +++ b/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 <gael.guennebaud@inria.fr> +// Copyright (C) 2009 Benoit Jacob <jacob.benoit.1@gmail.com> +// +// 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<typename MatrixType, int QRPreconditioner> +void jacobisvd_check_full(const MatrixType& m, const JacobiSVD<MatrixType, QRPreconditioner>& svd) +{ + svd_check_full<MatrixType, JacobiSVD<MatrixType, QRPreconditioner > >(m, svd); +} + +template<typename MatrixType, int QRPreconditioner> +void jacobisvd_compare_to_full(const MatrixType& m, + unsigned int computationOptions, + const JacobiSVD<MatrixType, QRPreconditioner>& referenceSvd) +{ + svd_compare_to_full<MatrixType, JacobiSVD<MatrixType, QRPreconditioner> >(m, computationOptions, referenceSvd); +} + + +template<typename MatrixType, int QRPreconditioner> +void jacobisvd_solve(const MatrixType& m, unsigned int computationOptions) +{ + svd_solve< MatrixType, JacobiSVD< MatrixType, QRPreconditioner > >(m, computationOptions); +} + + + +template<typename MatrixType, int QRPreconditioner> +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<typename MatrixType> +void jacobisvd(const MatrixType& a = MatrixType(), bool pickrandom = true) +{ + MatrixType m = pickrandom ? MatrixType::Random(a.rows(), a.cols()) : a; + + jacobisvd_test_all_computation_options<MatrixType, FullPivHouseholderQRPreconditioner>(m); + jacobisvd_test_all_computation_options<MatrixType, ColPivHouseholderQRPreconditioner>(m); + jacobisvd_test_all_computation_options<MatrixType, HouseholderQRPreconditioner>(m); + jacobisvd_test_all_computation_options<MatrixType, NoQRPreconditioner>(m); +} + + +template<typename MatrixType> +void jacobisvd_verify_assert(const MatrixType& m) +{ + + svd_verify_assert<MatrixType, JacobiSVD< MatrixType > >(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<MatrixType, FullPivHouseholderQRPreconditioner> 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<typename MatrixType> +void jacobisvd_method() +{ + enum { Size = MatrixType::RowsAtCompileTime }; + typedef typename MatrixType::RealScalar RealScalar; + typedef Matrix<RealScalar, Size, 1> 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<typename MatrixType> +void jacobisvd_inf_nan() +{ + svd_inf_nan<MatrixType, JacobiSVD< MatrixType > >(); +} + + +// 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<Matrix2d> svd; + svd.compute(M); // just check we don't loop indefinitely +} + + +void jacobisvd_preallocate() +{ + svd_preallocate< JacobiSVD <MatrixXf> >(); +} + +void test_jacobisvd() +{ + CALL_SUBTEST_11(( jacobisvd<Matrix<double,Dynamic,Dynamic> > + (Matrix<double,Dynamic,Dynamic>(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<Matrix3f>() )); + CALL_SUBTEST_4(( jacobisvd<Matrix4d>() )); + CALL_SUBTEST_5(( jacobisvd<Matrix<float,3,5> >() )); + CALL_SUBTEST_6(( jacobisvd<Matrix<double,Dynamic,2> >(Matrix<double,Dynamic,2>(10,2)) )); + + int r = internal::random<int>(1, 30), + c = internal::random<int>(1, 30); + CALL_SUBTEST_7(( jacobisvd<MatrixXf>(MatrixXf(r,c)) )); + CALL_SUBTEST_8(( jacobisvd<MatrixXcd>(MatrixXcd(r,c)) )); + (void) r; + (void) c; + + // Test on inf/nan matrix + CALL_SUBTEST_7( jacobisvd_inf_nan<MatrixXf>() ); + } + + CALL_SUBTEST_7(( jacobisvd<MatrixXf>(MatrixXf(internal::random<int>(EIGEN_TEST_MAX_SIZE/4, EIGEN_TEST_MAX_SIZE/2), internal::random<int>(EIGEN_TEST_MAX_SIZE/4, EIGEN_TEST_MAX_SIZE/2))) )); + CALL_SUBTEST_8(( jacobisvd<MatrixXcd>(MatrixXcd(internal::random<int>(EIGEN_TEST_MAX_SIZE/4, EIGEN_TEST_MAX_SIZE/3), internal::random<int>(EIGEN_TEST_MAX_SIZE/4, EIGEN_TEST_MAX_SIZE/3))) )); + + + // test matrixbase method + CALL_SUBTEST_1(( jacobisvd_method<Matrix2cd>() )); + CALL_SUBTEST_3(( jacobisvd_method<Matrix3f>() )); + + + // Test problem size constructors + CALL_SUBTEST_7( JacobiSVD<MatrixXf>(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/eigen/unsupported/test/kronecker_product.cpp b/eigen/unsupported/test/kronecker_product.cpp new file mode 100644 index 0000000..8ddc6ec --- /dev/null +++ b/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 <brix@igpm.rwth-aachen.de> +// Copyright (C) 2011 Andreas Platen <andiplaten@gmx.de> +// Copyright (C) 2012 Chen-Pang He <jdh8@ms63.hinet.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 "sparse.h" +#include <Eigen/SparseExtra> +#include <Eigen/KroneckerProduct> + + +template<typename MatrixType> +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<typename MatrixType> +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<typename MatrixType> +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<double, 2, 3> DM_a; + SparseMatrix<double> 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<double> 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<double,RowMajor> SM_row_a(SM_a), SM_row_b(SM_b); + + // test kroneckerProduct(DM_block,DM,DM_fixedSize) + Matrix<double, 6, 6> DM_fix_ab = kroneckerProduct(DM_a.topLeftCorner<2,3>(),DM_b); + + CALL_SUBTEST(check_kronecker_product(DM_fix_ab)); + + for(int i=0;i<DM_fix_ab.rows();++i) + for(int j=0;j<DM_fix_ab.cols();++j) + VERIFY_IS_APPROX(kroneckerProduct(DM_a,DM_b).coeff(i,j), DM_fix_ab(i,j)); + + // test kroneckerProduct(DM,DM,DM_block) + MatrixXd DM_block_ab(10,15); + DM_block_ab.block<6,6>(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<double> SM_ab = kroneckerProduct(SM_a,DM_b); + CALL_SUBTEST(check_kronecker_product(SM_ab)); + SparseMatrix<double,RowMajor> 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/eigen/unsupported/test/levenberg_marquardt.cpp b/eigen/unsupported/test/levenberg_marquardt.cpp new file mode 100644 index 0000000..0446472 --- /dev/null +++ b/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 <orzel@freehackers.org> +// Copyright (C) 2012 desire Nuentsa <desire.nuentsa_wakam@inria.fr +// +// 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 <stdio.h> + +#include "main.h" +#include <unsupported/Eigen/LevenbergMarquardt> + +// This disables some useless Warnings on MSVC. +// It is intended to be done for this test only. +#include <Eigen/src/Core/util/DisableStupidWarnings.h> + +using std::sqrt; + +struct lmder_functor : DenseFunctor<double> +{ + lmder_functor(void): DenseFunctor<double>(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<lmder_functor> 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<lmder_functor> 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<n,n>(); + VERIFY_IS_APPROX( cov, cov_ref); + // TODO: why isn't this allowed ? : + // VERIFY_IS_APPROX( covfac*fjac.topLeftCorner<n,n>() , cov_ref); +} + +struct lmdif_functor : DenseFunctor<double> +{ + lmdif_functor(void) : DenseFunctor<double>(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<lmdif_functor>::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<lmdif_functor> numDiff(functor); + LevenbergMarquardt<NumericalDiff<lmdif_functor> > 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<n,n>(); + VERIFY_IS_APPROX( cov, cov_ref); + // TODO: why isn't this allowed ? : + // VERIFY_IS_APPROX( covfac*fjac.topLeftCorner<n,n>() , cov_ref); +} + +struct chwirut2_functor : DenseFunctor<double> +{ + chwirut2_functor(void) : DenseFunctor<double>(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<chwirut2_functor> 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<double>::epsilon()); + lm.setXtol(1.E6*NumTraits<double>::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<double> +{ + misra1a_functor(void) : DenseFunctor<double>(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<misra1a_functor> 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<double> +{ + hahn1_functor(void) : DenseFunctor<double>(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<hahn1_functor> 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<double> +{ + misra1d_functor(void) : DenseFunctor<double>(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<misra1d_functor> 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<double> +{ + lanczos1_functor(void) : DenseFunctor<double>(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<lanczos1_functor> 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<double> +{ + rat42_functor(void) : DenseFunctor<double>(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<rat42_functor> 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<double> +{ + MGH10_functor(void) : DenseFunctor<double>(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<MGH10_functor> 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<double> +{ + BoxBOD_functor(void) : DenseFunctor<double>(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<BoxBOD_functor> lm(functor); + lm.setFtol(1.E6*NumTraits<double>::epsilon()); + lm.setXtol(1.E6*NumTraits<double>::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<double>::epsilon()); + lm.setXtol( NumTraits<double>::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<double> +{ + MGH17_functor(void) : DenseFunctor<double>(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<MGH17_functor> lm(functor); + lm.setFtol(NumTraits<double>::epsilon()); + lm.setXtol(NumTraits<double>::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<double> +{ + MGH09_functor(void) : DenseFunctor<double>(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<MGH09_functor> 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<double> +{ + Bennett5_functor(void) : DenseFunctor<double>(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<Bennett5_functor> 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<double> +{ + thurber_functor(void) : DenseFunctor<double>(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<thurber_functor> lm(functor); + lm.setFtol(1.E4*NumTraits<double>::epsilon()); + lm.setXtol(1.E4*NumTraits<double>::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<double>::epsilon()); + lm.setXtol(1.E4*NumTraits<double>::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<double> +{ + rat43_functor(void) : DenseFunctor<double>(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<rat43_functor> lm(functor); + lm.setFtol(1.E6*NumTraits<double>::epsilon()); + lm.setXtol(1.E6*NumTraits<double>::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<double>::epsilon()); + lm.setXtol(1.E5*NumTraits<double>::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<double> +{ + eckerle4_functor(void) : DenseFunctor<double>(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<eckerle4_functor> 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/eigen/unsupported/test/matrix_exponential.cpp b/eigen/unsupported/test/matrix_exponential.cpp new file mode 100644 index 0000000..50dec08 --- /dev/null +++ b/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 <jitse@maths.leeds.ac.uk> +// +// 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<k; i++) + res = res * (n-k+i+1) / (i+1); + return res; +} + +template <typename T> +T expfn(T x, int) +{ + return std::exp(x); +} + +template <typename T> +void test2dRotation(double tol) +{ + Matrix<T,2,2> A, B, C; + T angle; + + A << 0, 1, -1, 0; + for (int i=0; i<=20; i++) + { + angle = static_cast<T>(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<T>(tol))); + + C = (angle*A).exp(); + std::cout << " error expm = " << relerr(C, B) << "\n"; + VERIFY(C.isApprox(B, static_cast<T>(tol))); + } +} + +template <typename T> +void test2dHyperbolicRotation(double tol) +{ + Matrix<std::complex<T>,2,2> A, B, C; + std::complex<T> imagUnit(0,1); + T angle, ch, sh; + + for (int i=0; i<=20; i++) + { + angle = static_cast<T>((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<T>(tol))); + + C = A.exp(); + std::cout << " error expm = " << relerr(C, B) << "\n"; + VERIFY(C.isApprox(B, static_cast<T>(tol))); + } +} + +template <typename T> +void testPascal(double tol) +{ + for (int size=1; size<20; size++) + { + Matrix<T,Dynamic,Dynamic> A(size,size), B(size,size), C(size,size); + A.setZero(); + for (int i=0; i<size-1; i++) + A(i+1,i) = static_cast<T>(i+1); + B.setZero(); + for (int i=0; i<size; i++) + for (int j=0; j<=i; j++) + B(i,j) = static_cast<T>(binom(i,j)); + + C = A.matrixFunction(expfn); + std::cout << "testPascal: size = " << size << " error funm = " << relerr(C, B); + VERIFY(C.isApprox(B, static_cast<T>(tol))); + + C = A.exp(); + std::cout << " error expm = " << relerr(C, B) << "\n"; + VERIFY(C.isApprox(B, static_cast<T>(tol))); + } +} + +template<typename MatrixType> +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<typename internal::traits<MatrixType>::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<RealScalar>(tol))); + + m2 = m1.exp() * (-m1).exp(); + std::cout << " error expm = " << relerr(identity, m2) << "\n"; + VERIFY(identity.isApprox(m2, static_cast<RealScalar>(tol))); + } +} + +void test_matrix_exponential() +{ + CALL_SUBTEST_2(test2dRotation<double>(1e-13)); + CALL_SUBTEST_1(test2dRotation<float>(2e-5)); // was 1e-5, relaxed for clang 2.8 / linux / x86-64 + CALL_SUBTEST_8(test2dRotation<long double>(1e-13)); + CALL_SUBTEST_2(test2dHyperbolicRotation<double>(1e-14)); + CALL_SUBTEST_1(test2dHyperbolicRotation<float>(1e-5)); + CALL_SUBTEST_8(test2dHyperbolicRotation<long double>(1e-14)); + CALL_SUBTEST_6(testPascal<float>(1e-6)); + CALL_SUBTEST_5(testPascal<double>(1e-15)); + CALL_SUBTEST_2(randomTest(Matrix2d(), 1e-13)); + CALL_SUBTEST_7(randomTest(Matrix<double,3,3,RowMajor>(), 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<long double,Dynamic,Dynamic>(7,7), 1e-13)); +} diff --git a/eigen/unsupported/test/matrix_function.cpp b/eigen/unsupported/test/matrix_function.cpp new file mode 100644 index 0000000..3c76cfb --- /dev/null +++ b/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 <jitse@maths.leeds.ac.uk> +// +// 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 <unsupported/Eigen/MatrixFunctions> + +// 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<typename Type1, typename Type2> +inline bool test_isApprox_abs(const Type1& a, const Type2& b) +{ + return ((a-b).array().abs() < test_precision<typename Type1::RealScalar>()).all(); +} + + +// Returns a matrix with eigenvalues clustered around 0, 1 and 2. +template<typename MatrixType> +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<int>(0,2))) + + internal::random<Scalar>() * Scalar(RealScalar(0.01)); + } + MatrixType A = MatrixType::Random(size, size); + HouseholderQR<MatrixType> QRofA(A); + return QRofA.householderQ().inverse() * diag * QRofA.householderQ(); +} + +template <typename MatrixType, int IsComplex = NumTraits<typename internal::traits<MatrixType>::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<typename MatrixType> +struct randomMatrixWithImagEivals<MatrixType, 0> +{ + 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<Index>(-1, 1); + if (randomInt == 0 || i == size-1) { + diag(i, i) = internal::random<Scalar>() * Scalar(0.01); + ++i; + } else { + Scalar alpha = Scalar(randomInt) + internal::random<Scalar>() * Scalar(0.01); + diag(i, i+1) = alpha; + diag(i+1, i) = -alpha; + i += 2; + } + } + MatrixType A = MatrixType::Random(size, size); + HouseholderQR<MatrixType> QRofA(A); + return QRofA.householderQ().inverse() * diag * QRofA.householderQ(); + } +}; + +// Partial specialization for complex matrices +template<typename MatrixType> +struct randomMatrixWithImagEivals<MatrixType, 1> +{ + 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<Index>(-1, 1))) * imagUnit + + internal::random<Scalar>() * Scalar(RealScalar(0.01)); + } + MatrixType A = MatrixType::Random(size, size); + HouseholderQR<MatrixType> QRofA(A); + return QRofA.householderQ().inverse() * diag * QRofA.householderQ(); + } +}; + + +template<typename MatrixType> +void testMatrixExponential(const MatrixType& A) +{ + typedef typename internal::traits<MatrixType>::Scalar Scalar; + typedef typename NumTraits<Scalar>::Real RealScalar; + typedef std::complex<RealScalar> ComplexScalar; + + VERIFY_IS_APPROX(A.exp(), A.matrixFunction(StdStemFunctions<ComplexScalar>::exp)); +} + +template<typename MatrixType> +void testMatrixLogarithm(const MatrixType& A) +{ + typedef typename internal::traits<MatrixType>::Scalar Scalar; + typedef typename NumTraits<Scalar>::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<typename MatrixType> +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<typename MatrixType> +void testGonioFunctions(const MatrixType& A) +{ + typedef typename MatrixType::Scalar Scalar; + typedef typename NumTraits<Scalar>::Real RealScalar; + typedef std::complex<RealScalar> ComplexScalar; + typedef Matrix<ComplexScalar, MatrixType::RowsAtCompileTime, + MatrixType::ColsAtCompileTime, MatrixType::Options> ComplexMatrix; + + ComplexScalar imagUnit(0,1); + ComplexScalar two(2,0); + + ComplexMatrix Ac = A.template cast<ComplexScalar>(); + + ComplexMatrix exp_iA = (imagUnit * Ac).exp(); + ComplexMatrix exp_miA = (-imagUnit * Ac).exp(); + + ComplexMatrix sinAc = A.sin().template cast<ComplexScalar>(); + VERIFY_IS_APPROX_ABS(sinAc, (exp_iA - exp_miA) / (two*imagUnit)); + + ComplexMatrix cosAc = A.cos().template cast<ComplexScalar>(); + VERIFY_IS_APPROX_ABS(cosAc, (exp_iA + exp_miA) / 2); +} + +template<typename MatrixType> +void testMatrix(const MatrixType& A) +{ + testMatrixExponential(A); + testMatrixLogarithm(A); + testHyperbolicFunctions(A); + testGonioFunctions(A); +} + +template<typename MatrixType> +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<MatrixType>(size)); + testMatrix(randomMatrixWithImagEivals<MatrixType>::run(size)); + } +} + +void test_matrix_function() +{ + CALL_SUBTEST_1(testMatrixType(Matrix<float,1,1>())); + CALL_SUBTEST_2(testMatrixType(Matrix3cf())); + CALL_SUBTEST_3(testMatrixType(MatrixXf(8,8))); + CALL_SUBTEST_4(testMatrixType(Matrix2d())); + CALL_SUBTEST_5(testMatrixType(Matrix<double,5,5,RowMajor>())); + CALL_SUBTEST_6(testMatrixType(Matrix4cd())); + CALL_SUBTEST_7(testMatrixType(MatrixXd(13,13))); +} diff --git a/eigen/unsupported/test/matrix_functions.h b/eigen/unsupported/test/matrix_functions.h new file mode 100644 index 0000000..5817cae --- /dev/null +++ b/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 <jitse@maths.leeds.ac.uk> +// +// 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 <unsupported/Eigen/MatrixFunctions> + +template <typename MatrixType, int IsComplex = NumTraits<typename internal::traits<MatrixType>::Scalar>::IsComplex> +struct generateTestMatrix; + +// for real matrices, make sure none of the eigenvalues are negative +template <typename MatrixType> +struct generateTestMatrix<MatrixType,0> +{ + static void run(MatrixType& result, typename MatrixType::Index size) + { + MatrixType mat = MatrixType::Random(size, size); + EigenSolver<MatrixType> es(mat); + typename EigenSolver<MatrixType>::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 <typename MatrixType> +struct generateTestMatrix<MatrixType,1> +{ + static void run(MatrixType& result, typename MatrixType::Index size) + { + result = MatrixType::Random(size, size); + } +}; + +template <typename Derived, typename OtherDerived> +double relerr(const MatrixBase<Derived>& A, const MatrixBase<OtherDerived>& B) +{ + return std::sqrt((A - B).cwiseAbs2().sum() / (std::min)(A.cwiseAbs2().sum(), B.cwiseAbs2().sum())); +} diff --git a/eigen/unsupported/test/matrix_power.cpp b/eigen/unsupported/test/matrix_power.cpp new file mode 100644 index 0000000..b9d513b --- /dev/null +++ b/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 <jdh8@ms63.hinet.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 "matrix_functions.h" + +template <typename MatrixType, int IsComplex = NumTraits<typename MatrixType::Scalar>::IsComplex> +struct generateTriangularMatrix; + +// for real matrices, make sure none of the eigenvalues are negative +template <typename MatrixType> +struct generateTriangularMatrix<MatrixType,0> +{ + static void run(MatrixType& result, typename MatrixType::Index size) + { + result.resize(size, size); + result.template triangularView<Upper>() = 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 <typename MatrixType> +struct generateTriangularMatrix<MatrixType,1> +{ + static void run(MatrixType& result, typename MatrixType::Index size) + { + result.resize(size, size); + result.template triangularView<Upper>() = MatrixType::Random(size, size); + } +}; + +template<typename T> +void test2dRotation(double tol) +{ + Matrix<T,2,2> A, B, C; + T angle, c, s; + + A << 0, 1, -1, 0; + MatrixPower<Matrix<T,2,2> > 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<T>(tol))); + } +} + +template<typename T> +void test2dHyperbolicRotation(double tol) +{ + Matrix<std::complex<T>,2,2> A, B, C; + T angle, ch = std::cosh((T)1); + std::complex<T> ish(0, std::sinh((T)1)); + + A << ch, ish, -ish, ch; + MatrixPower<Matrix<std::complex<T>,2,2> > Apow(A); + + for (int i=0; i<=20; ++i) { + angle = std::ldexp(static_cast<T>(i-10), -1); + ch = std::cosh(angle); + ish = std::complex<T>(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<T>(tol))); + } +} + +template<typename MatrixType> +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<MatrixType>::run(m1, m.rows()); + MatrixPower<MatrixType> mpow(m1); + + x = internal::random<RealScalar>(); + y = internal::random<RealScalar>(); + m2 = mpow(x); + m3 = mpow(y); + + m4 = mpow(x+y); + m5.noalias() = m2 * m3; + VERIFY(m4.isApprox(m5, static_cast<RealScalar>(tol))); + + m4 = mpow(x*y); + m5 = m2.pow(y); + VERIFY(m4.isApprox(m5, static_cast<RealScalar>(tol))); + + m4 = (std::abs(x) * m1).pow(y); + m5 = std::pow(std::abs(x), y) * m3; + VERIFY(m4.isApprox(m5, static_cast<RealScalar>(tol))); + } +} + +typedef Matrix<double,3,3,RowMajor> Matrix3dRowMajor; +typedef Matrix<long double,Dynamic,Dynamic> MatrixXe; + +void test_matrix_power() +{ + CALL_SUBTEST_2(test2dRotation<double>(1e-13)); + CALL_SUBTEST_1(test2dRotation<float>(2e-5)); // was 1e-5, relaxed for clang 2.8 / linux / x86-64 + CALL_SUBTEST_9(test2dRotation<long double>(1e-13)); + CALL_SUBTEST_2(test2dHyperbolicRotation<double>(1e-14)); + CALL_SUBTEST_1(test2dHyperbolicRotation<float>(1e-5)); + CALL_SUBTEST_9(test2dHyperbolicRotation<long double>(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/eigen/unsupported/test/matrix_square_root.cpp b/eigen/unsupported/test/matrix_square_root.cpp new file mode 100644 index 0000000..ea541e1 --- /dev/null +++ b/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 <jitse@maths.leeds.ac.uk> +// +// 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<typename MatrixType> +void testMatrixSqrt(const MatrixType& m) +{ + MatrixType A; + generateTestMatrix<MatrixType>::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<double,Dynamic,Dynamic,RowMajor>(9, 9))); + CALL_SUBTEST_5(testMatrixSqrt(Matrix<float,1,1>())); + CALL_SUBTEST_5(testMatrixSqrt(Matrix<std::complex<float>,1,1>())); + } +} diff --git a/eigen/unsupported/test/minres.cpp b/eigen/unsupported/test/minres.cpp new file mode 100644 index 0000000..509ebe0 --- /dev/null +++ b/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 <g.gael@free.fr> +// Copyright (C) 2012 Giacomo Po <gpo@ucla.edu> +// +// 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 <cmath> + +#include "../../test/sparse_solver.h" +#include <Eigen/IterativeSolvers> + +template<typename T> void test_minres_T() +{ + MINRES<SparseMatrix<T>, Lower|Upper, DiagonalPreconditioner<T> > minres_colmajor_diag; + MINRES<SparseMatrix<T>, Lower, IdentityPreconditioner > minres_colmajor_lower_I; + MINRES<SparseMatrix<T>, Upper, IdentityPreconditioner > minres_colmajor_upper_I; +// MINRES<SparseMatrix<T>, Lower, IncompleteLUT<T> > minres_colmajor_ilut; + //minres<SparseMatrix<T>, SSORPreconditioner<T> > 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<SparseMatrix<T>, Lower, DiagonalPreconditioner<T> > minres_colmajor_lower_diag; + MINRES<SparseMatrix<T>, Upper, DiagonalPreconditioner<T> > minres_colmajor_upper_diag; + MINRES<SparseMatrix<T>, Upper|Lower, DiagonalPreconditioner<T> > 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<double>()); +// CALL_SUBTEST_2(test_minres_T<std::complex<double> >()); +} diff --git a/eigen/unsupported/test/mpreal/mpreal.h b/eigen/unsupported/test/mpreal/mpreal.h new file mode 100644 index 0000000..f83e52d --- /dev/null +++ b/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 <http://www.gnu.org/licenses/>. +*/ + +#ifndef __MPREAL_H__ +#define __MPREAL_H__ + +#include <string> +#include <iostream> +#include <sstream> +#include <stdexcept> +#include <cfloat> +#include <cmath> +#include <cstring> +#include <limits> + +// 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<mpfr::mpreal> specialization. + // Meaning that "digits", "round_style" and similar members are defined as functions, not constants. + // See std::numeric_limits<mpfr::mpreal> 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 <stdint.h> // <stdint.h> 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 <stdint.h> // use int64_t, uint64_t otherwise + #endif + + #else + #include <stdint.h> // 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 <mpfr.h> + +#if (MPFR_VERSION < MPFR_VERSION_NUM(3,0,0)) + #include <cstdlib> // 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<mpreal> 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=<DebugView> ; Show value only + // mpfr::mpreal=<DebugView>, <mp[0]._mpfr_prec,u>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 <typename ArgumentType> struct result_type {}; + + template <> struct result_type<mpreal> {typedef mpreal type;}; + template <> struct result_type<mpz_t> {typedef mpreal type;}; + template <> struct result_type<mpq_t> {typedef mpreal type;}; + template <> struct result_type<long double> {typedef mpreal type;}; + template <> struct result_type<double> {typedef mpreal type;}; + template <> struct result_type<unsigned long int> {typedef mpreal type;}; + template <> struct result_type<unsigned int> {typedef mpreal type;}; + template <> struct result_type<long int> {typedef mpreal type;}; + template <> struct result_type<int> {typedef mpreal type;}; + +#if defined (MPREAL_HAVE_INT64_SUPPORT) + template <> struct result_type<int64_t > {typedef mpreal type;}; + template <> struct result_type<uint64_t > {typedef mpreal type;}; +#endif +} + +// + Addition +template <typename Rhs> +inline const typename internal::result_type<Rhs>::type + operator+(const mpreal& lhs, const Rhs& rhs){ return mpreal(lhs) += rhs; } + +template <typename Lhs> +inline const typename internal::result_type<Lhs>::type + operator+(const Lhs& lhs, const mpreal& rhs){ return mpreal(rhs) += lhs; } + +// - Subtraction +template <typename Rhs> +inline const typename internal::result_type<Rhs>::type + operator-(const mpreal& lhs, const Rhs& rhs){ return mpreal(lhs) -= rhs; } + +template <typename Lhs> +inline const typename internal::result_type<Lhs>::type + operator-(const Lhs& lhs, const mpreal& rhs){ return mpreal(lhs) -= rhs; } + +// * Multiplication +template <typename Rhs> +inline const typename internal::result_type<Rhs>::type + operator*(const mpreal& lhs, const Rhs& rhs){ return mpreal(lhs) *= rhs; } + +template <typename Lhs> +inline const typename internal::result_type<Lhs>::type + operator*(const Lhs& lhs, const mpreal& rhs){ return mpreal(rhs) *= lhs; } + +// / Division +template <typename Rhs> +inline const typename internal::result_type<Rhs>::type + operator/(const mpreal& lhs, const Rhs& rhs){ return mpreal(lhs) /= rhs; } + +template <typename Lhs> +inline const typename internal::result_type<Lhs>::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<unsigned long int>(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<long int>(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<unsigned long int>(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<long int>(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<unsigned long int>(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<long int>(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<unsigned long int>(k)); +} + +inline const mpreal operator>>(const mpreal& v, const int k) +{ + return div_2si(v,static_cast<long int>(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 <class T> +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<size_t>(exp)<slen) + { + if(s[0]=='-') + { + // Remove zeros starting from right end + char* ptr = s+slen-1; + while (*ptr=='0' && ptr>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<mp_exp_t>(exp,std::dec); + else out += "e"+mpfr::toString<mp_exp_t>(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<unsigned long int>(v),rnd_mode); +} + +inline const mpreal sqrt(const long int v, mp_rnd_t rnd_mode) +{ + if (v>=0) return sqrt(static_cast<unsigned long int>(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<unsigned long int>(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<n;i++) t[i] = (mpfr_ptr)tab[i].mp; + mpfr_sum(x.mp,t,n,rnd_mode); + delete[] t; + return x; +} + +////////////////////////////////////////////////////////////////////////// +// MPFR 2.4.0 Specifics +#if (MPFR_VERSION >= 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<y?x:y); } + +inline const mpreal fmax(const mpreal& x, const mpreal& y, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) +{ + mpreal a; + mpfr_max(a.mp,x.mp,y.mp,rnd_mode); + return a; +} + +inline const mpreal fmin(const mpreal& x, const mpreal& y, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) +{ + mpreal a; + mpfr_min(a.mp,x.mp,y.mp,rnd_mode); + return a; +} + +inline const mpreal nexttoward (const mpreal& x, const mpreal& y) +{ + mpreal a(x); + mpfr_nexttoward(a.mp,y.mp); + return a; +} + +inline const mpreal nextabove (const mpreal& x) +{ + mpreal a(x); + mpfr_nextabove(a.mp); + return a; +} + +inline const mpreal nextbelow (const mpreal& x) +{ + mpreal a(x); + mpfr_nextbelow(a.mp); + return a; +} + +inline const mpreal urandomb (gmp_randstate_t& state) +{ + mpreal x; + mpfr_urandomb(x.mp,state); + return x; +} + +#if (MPFR_VERSION >= 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<unsigned long int>(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<long int>(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<unsigned long int>(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<unsigned long int>(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<unsigned long int>(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<unsigned long int>(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<unsigned long int>(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<unsigned long int>(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<unsigned long int>(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<unsigned long int>(a),static_cast<unsigned long int>(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<unsigned long int>(a),static_cast<unsigned long int>(b),rnd_mode); //mpfr_ui_pow_ui + else return pow(static_cast<unsigned long int>(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<unsigned long int>(a),static_cast<unsigned long int>(b),rnd_mode); //mpfr_ui_pow_ui + else return pow(static_cast<unsigned long int>(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<unsigned long int>(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<unsigned long int>(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<unsigned long int>(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<unsigned long int>(a),static_cast<unsigned long int>(b),rnd_mode); //mpfr_ui_pow_ui + else return pow(mpreal(a),static_cast<unsigned long int>(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<unsigned long int>(a),static_cast<unsigned long int>(b),rnd_mode); //mpfr_ui_pow_ui + else return pow(static_cast<unsigned long int>(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<unsigned long int>(a),static_cast<unsigned long int>(b),rnd_mode); //mpfr_ui_pow_ui + else return pow(static_cast<unsigned long int>(a),mpreal(b),rnd_mode); //mpfr_ui_pow + }else{ + return pow(mpreal(a),static_cast<long int>(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<unsigned long int>(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<unsigned long int>(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<unsigned long int>(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<unsigned long int>(a),static_cast<unsigned long int>(b),rnd_mode); //mpfr_ui_pow_ui + else return pow(mpreal(a),static_cast<unsigned long int>(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<unsigned long int>(a),static_cast<unsigned long int>(b),rnd_mode); //mpfr_ui_pow_ui + else return pow(static_cast<unsigned long int>(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<unsigned long int>(a),static_cast<unsigned long int>(b),rnd_mode); //mpfr_ui_pow_ui + else return pow(static_cast<unsigned long int>(a),mpreal(b),rnd_mode); //mpfr_ui_pow + }else{ + return pow(mpreal(a),static_cast<long int>(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<unsigned long int>(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<unsigned long int>(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<unsigned long int>(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<long int>(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<unsigned long int>(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<long int>(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<mpfr::mpreal> + { + 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<mpfr::mpreal> 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/eigen/unsupported/test/mpreal_support.cpp b/eigen/unsupported/test/mpreal_support.cpp new file mode 100644 index 0000000..bc00382 --- /dev/null +++ b/eigen/unsupported/test/mpreal_support.cpp @@ -0,0 +1,57 @@ +#include "main.h" +#include <Eigen/MPRealSupport> +#include <Eigen/LU> +#include <Eigen/Eigenvalues> +#include <sstream> + +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<mpreal,Eigen::Dynamic,Eigen::Dynamic> MatrixXmp; + + std::cerr << "epsilon = " << NumTraits<mpreal>::epsilon() << "\n"; + std::cerr << "dummy_precision = " << NumTraits<mpreal>::dummy_precision() << "\n"; + std::cerr << "highest = " << NumTraits<mpreal>::highest() << "\n"; + std::cerr << "lowest = " << NumTraits<mpreal>::lowest() << "\n"; + + for(int i = 0; i < g_repeat; i++) { + int s = Eigen::internal::random<int>(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<Lower>().llt().solve(B); + VERIFY_IS_APPROX((S.selfadjointView<Lower>()*X).eval(),B); + + // partial LU + X = A.lu().solve(B); + VERIFY_IS_APPROX((A*X).eval(),B); + + // symmetric eigenvalues + SelfAdjointEigenSolver<MatrixXmp> eig(S); + VERIFY_IS_EQUAL(eig.info(), Success); + VERIFY( (S.selfadjointView<Lower>() * eig.eigenvectors()).isApprox(eig.eigenvectors() * eig.eigenvalues().asDiagonal(), NumTraits<mpreal>::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/eigen/unsupported/test/openglsupport.cpp b/eigen/unsupported/test/openglsupport.cpp new file mode 100644 index 0000000..706a816 --- /dev/null +++ b/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 <gael.guennebaud@inria.fr> +// +// 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 <iostream> +#include <GL/glew.h> +#include <Eigen/OpenGLSupport> +#include <GL/glut.h> +using namespace Eigen; + + + + +#define VERIFY_MATRIX(CODE,REF) { \ + glLoadIdentity(); \ + CODE; \ + Matrix<float,4,4,ColMajor> m; m.setZero(); \ + glGet(GL_MODELVIEW_MATRIX, m); \ + if(!(REF).cast<float>().isApprox(m)) { \ + std::cerr << "Expected:\n" << ((REF).cast<float>()) << "\n" << "got\n" << m << "\n\n"; \ + } \ + VERIFY_IS_APPROX((REF).cast<float>(), 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<float>().cast<TYPE::Scalar>(); \ + 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<double>(), Vector3d::Random())); + VERIFY_MATRIX(glRotate(qd), Projective3d(qd).matrix()); + + Quaternionf qf(AngleAxisf(internal::random<double>(), Vector3f::Random())); + VERIFY_MATRIX(glRotate(qf), Projective3f(qf).matrix()); + + // 3D Transform + Transform<float,3,AffineCompact> acf3; acf3.matrix().setRandom(); + VERIFY_MATRIX(glLoadMatrix(acf3), Projective3f(acf3).matrix()); + VERIFY_MATRIX(glMultMatrix(acf3), Projective3f(acf3).matrix()); + + Transform<float,3,Affine> af3(acf3); + VERIFY_MATRIX(glLoadMatrix(af3), Projective3f(af3).matrix()); + VERIFY_MATRIX(glMultMatrix(af3), Projective3f(af3).matrix()); + + Transform<float,3,Projective> pf3; pf3.matrix().setRandom(); + VERIFY_MATRIX(glLoadMatrix(pf3), Projective3f(pf3).matrix()); + VERIFY_MATRIX(glMultMatrix(pf3), Projective3f(pf3).matrix()); + + Transform<double,3,AffineCompact> acd3; acd3.matrix().setRandom(); + VERIFY_MATRIX(glLoadMatrix(acd3), Projective3d(acd3).matrix()); + VERIFY_MATRIX(glMultMatrix(acd3), Projective3d(acd3).matrix()); + + Transform<double,3,Affine> ad3(acd3); + VERIFY_MATRIX(glLoadMatrix(ad3), Projective3d(ad3).matrix()); + VERIFY_MATRIX(glMultMatrix(ad3), Projective3d(ad3).matrix()); + + Transform<double,3,Projective> 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<float,3> tf3; tf3.vector().setRandom(); + VERIFY_MATRIX(glTranslate(tf3), Projective3f(tf3).matrix()); + + Translation<double,3> 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<float> usf(internal::random<float>()); + VERIFY_MATRIX(glScale(usf), Projective3f(usf).matrix()); + + UniformScaling<double> usd(internal::random<double>()); + 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<float,2,3> Matrix23f; + typedef Matrix<float,3,2> Matrix32f; + typedef Matrix<float,2,4> Matrix24f; + typedef Matrix<float,4,2> Matrix42f; + typedef Matrix<float,3,4> Matrix34f; + typedef Matrix<float,4,3> 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<unsigned int,2,1> Vector2ui; + typedef Matrix<unsigned int,3,1> Vector3ui; + typedef Matrix<unsigned int,4,1> 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/eigen/unsupported/test/polynomialsolver.cpp b/eigen/unsupported/test/polynomialsolver.cpp new file mode 100644 index 0000000..de79f15 --- /dev/null +++ b/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 <manuel.yguel@gmail.com> +// +// 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 <unsupported/Eigen/Polynomials> +#include <iostream> +#include <algorithm> + +using namespace std; + +namespace Eigen { +namespace internal { +template<int Size> +struct increment_if_fixed_size +{ + enum { + ret = (Size == Dynamic) ? Dynamic : Size+1 + }; +}; +} +} + + +template<int Deg, typename POLYNOMIAL, typename SOLVER> +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<Scalar,Deg,1> EvalRootsType; + + const Index deg = pols.size()-1; + + psolve.compute( pols ); + const RootsType& roots( psolve.roots() ); + EvalRootsType evr( deg ); + for( int i=0; i<roots.size(); ++i ){ + evr[i] = std::abs( poly_eval( pols, roots[i] ) ); } + + bool evalToZero = evr.isZero( test_precision<Scalar>() ); + 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<Scalar> 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<rootModuli.size() && distinctModuli; ++i ) + { + if( internal::isApprox( rootModuli[i], rootModuli[i-1] ) ){ + distinctModuli = false; } + } + VERIFY( evalToZero || !distinctModuli ); + + return distinctModuli; +} + + + + + + + +template<int Deg, typename POLYNOMIAL> +void evalSolver( const POLYNOMIAL& pols ) +{ + typedef typename POLYNOMIAL::Scalar Scalar; + + typedef PolynomialSolver<Scalar, Deg > PolynomialSolverType; + + PolynomialSolverType psolve; + aux_evalSolver<Deg, POLYNOMIAL, PolynomialSolverType>( 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<Scalar, Deg > PolynomialSolverType; + + PolynomialSolverType psolve; + if( aux_evalSolver<Deg, POLYNOMIAL, PolynomialSolverType>( 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<Scalar>() ); + + for( size_t i=0; i<calc_realRoots.size(); ++i ) + { + bool found = false; + for( size_t j=0; j<calc_realRoots.size()&& !found; ++j ) + { + if( internal::isApprox( calc_realRoots[i], real_roots[j] ), psPrec ){ + found = true; } + } + VERIFY( found ); + } + + //Test greatestRoot + VERIFY( internal::isApprox( roots.array().abs().maxCoeff(), + abs( psolve.greatestRoot() ), psPrec ) ); + + //Test smallestRoot + VERIFY( internal::isApprox( roots.array().abs().minCoeff(), + abs( psolve.smallestRoot() ), psPrec ) ); + + bool hasRealRoot; + //Test absGreatestRealRoot + Real r = psolve.absGreatestRealRoot( hasRealRoot ); + VERIFY( hasRealRoot == (real_roots.size() > 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<typename _Scalar, int _Deg> +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<float,1>(1)) ); + CALL_SUBTEST_2( (polynomialsolver<double,2>(2)) ); + CALL_SUBTEST_3( (polynomialsolver<double,3>(3)) ); + CALL_SUBTEST_4( (polynomialsolver<float,4>(4)) ); + CALL_SUBTEST_5( (polynomialsolver<double,5>(5)) ); + CALL_SUBTEST_6( (polynomialsolver<float,6>(6)) ); + CALL_SUBTEST_7( (polynomialsolver<float,7>(7)) ); + CALL_SUBTEST_8( (polynomialsolver<double,8>(8)) ); + + CALL_SUBTEST_9( (polynomialsolver<float,Dynamic>( + internal::random<int>(9,13) + )) ); + CALL_SUBTEST_10((polynomialsolver<double,Dynamic>( + internal::random<int>(9,13) + )) ); + } +} diff --git a/eigen/unsupported/test/polynomialutils.cpp b/eigen/unsupported/test/polynomialutils.cpp new file mode 100644 index 0000000..5fc9684 --- /dev/null +++ b/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 <manuel.yguel@gmail.com> +// +// 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 <unsupported/Eigen/Polynomials> +#include <iostream> + +using namespace std; + +namespace Eigen { +namespace internal { +template<int Size> +struct increment_if_fixed_size +{ + enum { + ret = (Size == Dynamic) ? Dynamic : Size+1 + }; +}; +} +} + +template<typename _Scalar, int _Deg> +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<roots.size(); ++i ){ + evr[i] = std::abs( poly_eval( pols, roots[i] ) ); } + + bool evalToZero = evr.isZero( test_precision<_Scalar>() ); + if( !evalToZero ){ + cerr << evr.transpose() << endl; } + VERIFY( evalToZero ); +} + +template<typename _Scalar> 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<int>(18,26) )) ); +} + + + + +template<typename _Scalar, int _Deg> +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<typename _Scalar> 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<int>(18,26) )) ); +} + +void test_polynomialutils() +{ + for(int i = 0; i < g_repeat; i++) + { + realRoots_to_monicPolynomial_scalar<double>(); + realRoots_to_monicPolynomial_scalar<float>(); + CauchyBounds_scalar<double>(); + CauchyBounds_scalar<float>(); + } +} diff --git a/eigen/unsupported/test/sparse_extra.cpp b/eigen/unsupported/test/sparse_extra.cpp new file mode 100644 index 0000000..1ee791b --- /dev/null +++ b/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 <g.gael@free.fr> +// +// 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 <Eigen/SparseExtra> + +template<typename SetterType,typename DenseType, typename Scalar, int Options> +bool test_random_setter(SparseMatrix<Scalar,Options>& sm, const DenseType& ref, const std::vector<Vector2i>& nonzeroCoords) +{ + { + sm.setZero(); + SetterType w(sm); + std::vector<Vector2i> remaining = nonzeroCoords; + while(!remaining.empty()) + { + int i = internal::random<int>(0,static_cast<int>(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<typename SetterType,typename DenseType, typename T> +bool test_random_setter(DynamicSparseMatrix<T>& sm, const DenseType& ref, const std::vector<Vector2i>& nonzeroCoords) +{ + sm.setZero(); + std::vector<Vector2i> remaining = nonzeroCoords; + while(!remaining.empty()) + { + int i = internal::random<int>(0,static_cast<int>(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<typename SparseMatrixType> 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<Scalar,Dynamic,Dynamic> DenseMatrix; + typedef Matrix<Scalar,Dynamic,1> DenseVector; + Scalar eps = 1e-6; + + SparseMatrixType m(rows, cols); + DenseMatrix refMat = DenseMatrix::Zero(rows, cols); + DenseVector vec1 = DenseVector::Random(rows); + + std::vector<Vector2i> zeroCoords; + std::vector<Vector2i> nonzeroCoords; + initSparse<Scalar>(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<SparseMatrixType,SparseMatrix<Scalar,Flags> >::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<SparseMatrixType, RandomAccessPattern> w(m); +// std::vector<Vector2i> remaining = nonzeroCoords; +// while(!remaining.empty()) +// { +// int i = internal::random<int>(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<RandomSetter<SparseMatrixType, StdMapTraits> >(m,refMat,nonzeroCoords) )); + #ifdef EIGEN_UNORDERED_MAP_SUPPORT + VERIFY(( test_random_setter<RandomSetter<SparseMatrixType, StdUnorderedMapTraits> >(m,refMat,nonzeroCoords) )); + #endif + #ifdef _DENSE_HASH_MAP_H_ + VERIFY(( test_random_setter<RandomSetter<SparseMatrixType, GoogleDenseHashMapTraits> >(m,refMat,nonzeroCoords) )); + #endif + #ifdef _SPARSE_HASH_MAP_H_ + VERIFY(( test_random_setter<RandomSetter<SparseMatrixType, GoogleSparseHashMapTraits> >(m,refMat,nonzeroCoords) )); + #endif + + + // test RandomSetter + /*{ + SparseMatrixType m1(rows,cols), m2(rows,cols); + DenseMatrix refM1 = DenseMatrix::Zero(rows, rows); + initSparse<Scalar>(density, refM1, m1); + { + Eigen::RandomSetter<SparseMatrixType > setter(m2); + for (int j=0; j<m1.outerSize(); ++j) + for (typename SparseMatrixType::InnerIterator i(m1,j); i; ++i) + setter(i.index(), j) = i.value(); + } + VERIFY_IS_APPROX(m1, m2); + }*/ + + +} + +void test_sparse_extra() +{ + for(int i = 0; i < g_repeat; i++) { + int s = Eigen::internal::random<int>(1,50); + CALL_SUBTEST_1( sparse_extra(SparseMatrix<double>(8, 8)) ); + CALL_SUBTEST_2( sparse_extra(SparseMatrix<std::complex<double> >(s, s)) ); + CALL_SUBTEST_1( sparse_extra(SparseMatrix<double>(s, s)) ); + + CALL_SUBTEST_3( sparse_extra(DynamicSparseMatrix<double>(s, s)) ); +// CALL_SUBTEST_3(( sparse_basic(DynamicSparseMatrix<double>(s, s)) )); +// CALL_SUBTEST_3(( sparse_basic(DynamicSparseMatrix<double,ColMajor,long int>(s, s)) )); + + CALL_SUBTEST_3( (sparse_product<DynamicSparseMatrix<float, ColMajor> >()) ); + CALL_SUBTEST_3( (sparse_product<DynamicSparseMatrix<float, RowMajor> >()) ); + } +} diff --git a/eigen/unsupported/test/splines.cpp b/eigen/unsupported/test/splines.cpp new file mode 100644 index 0000000..a7eb3e0 --- /dev/null +++ b/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 <heibel@gmail.com> +// +// 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 <unsupported/Eigen/Splines> + +namespace Eigen { + +// lets do some explicit instantiations and thus +// force the compilation of all spline functions... +template class Spline<double, 2, Dynamic>; +template class Spline<double, 3, Dynamic>; + +template class Spline<double, 2, 2>; +template class Spline<double, 2, 3>; +template class Spline<double, 2, 4>; +template class Spline<double, 2, 5>; + +template class Spline<float, 2, Dynamic>; +template class Spline<float, 3, Dynamic>; + +template class Spline<float, 3, 2>; +template class Spline<float, 3, 3>; +template class Spline<float, 3, 4>; +template class Spline<float, 3, 5>; + +} + +Spline<double, 2, Dynamic> 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<double, 2, Dynamic>(knots, ctrls); +} + +/* create a reference spline */ +Spline<double, 3, Dynamic> 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<double, 3, Dynamic>(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<u.size(); ++i) + { + Vector3d pt = spline(u(i)); + VERIFY( (pt - pts.col(i)).norm() < 1e-14 ); + } +} + +/* compares evaluations on corner cases */ +void eval_spline3d_onbrks() +{ + Spline3d spline = spline3d(); + + RowVectorXd u = spline.knots(); + + MatrixXd pts(11,3); + pts << 0.959743958516081, 0.340385726666133, 0.585267750979777, + 0.959743958516081, 0.340385726666133, 0.585267750979777, + 0.959743958516081, 0.340385726666133, 0.585267750979777, + 0.430282980289940, 0.713074680056118, 0.720373307943349, + 0.558074875553060, 0.681617921034459, 0.804417124839942, + 0.407076008291750, 0.349707710518163, 0.617275937419545, + 0.240037008286602, 0.738739390398014, 0.324554153129411, + 0.302434111480572, 0.781162443963899, 0.240177089094644, + 0.251083857976031, 0.616044676146639, 0.473288848902729, + 0.251083857976031, 0.616044676146639, 0.473288848902729, + 0.251083857976031, 0.616044676146639, 0.473288848902729; + pts.transposeInPlace(); + + for (int i=0; i<u.size(); ++i) + { + Vector3d pt = spline(u(i)); + VERIFY( (pt - pts.col(i)).norm() < 1e-14 ); + } +} + +void eval_closed_spline2d() +{ + Spline2d spline = closed_spline2d(); + + RowVectorXd u(12); + u << 0, + 0.332457030395796, + 0.356467130532952, + 0.453562180176215, + 0.648017921874804, + 0.973770235555003, + 1.882577647219307, + 2.289408593930498, + 3.511951429883045, + 3.884149321369450, + 4.236261590369414, + 4.252699478956276; + + MatrixXd pts(12,2); + pts << -0.370967741935484, 0.236842105263158, + -0.152576775123250, 0.448975001279334, + -0.133417538277668, 0.461615613865667, + -0.053199060826740, 0.507630360006299, + 0.114249591147281, 0.570414135097409, + 0.377810316891987, 0.560497102875315, + 0.665052120135908, -0.157557441109611, + 0.516006487053228, -0.559763292174825, + -0.379486035348887, -0.331959640488223, + -0.462034726249078, -0.039105670080824, + -0.378730600917982, 0.225127015099919, + -0.370967741935484, 0.236842105263158; + pts.transposeInPlace(); + + for (int i=0; i<u.size(); ++i) + { + Vector2d pt = spline(u(i)); + VERIFY( (pt - pts.col(i)).norm() < 1e-14 ); + } +} + +void check_global_interpolation2d() +{ + typedef Spline2d::PointType PointType; + typedef Spline2d::KnotVectorType KnotVectorType; + typedef Spline2d::ControlPointVectorType ControlPointVectorType; + + ControlPointVectorType points = ControlPointVectorType::Random(2,100); + + KnotVectorType chord_lengths; // knot parameters + Eigen::ChordLengths(points, chord_lengths); + + // interpolation without knot parameters + { + const Spline2d spline = SplineFitting<Spline2d>::Interpolate(points,3); + + for (Eigen::DenseIndex i=0; i<points.cols(); ++i) + { + PointType pt = spline( chord_lengths(i) ); + PointType ref = points.col(i); + VERIFY( (pt - ref).matrix().norm() < 1e-14 ); + } + } + + // interpolation with given knot parameters + { + const Spline2d spline = SplineFitting<Spline2d>::Interpolate(points,3,chord_lengths); + + for (Eigen::DenseIndex i=0; i<points.cols(); ++i) + { + PointType pt = spline( chord_lengths(i) ); + PointType ref = points.col(i); + VERIFY( (pt - ref).matrix().norm() < 1e-14 ); + } + } +} + + +void test_splines() +{ + CALL_SUBTEST( eval_spline3d() ); + CALL_SUBTEST( eval_spline3d_onbrks() ); + CALL_SUBTEST( eval_closed_spline2d() ); + CALL_SUBTEST( check_global_interpolation2d() ); +} diff --git a/eigen/unsupported/test/svd_common.h b/eigen/unsupported/test/svd_common.h new file mode 100644 index 0000000..b40c23a --- /dev/null +++ b/eigen/unsupported/test/svd_common.h @@ -0,0 +1,261 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr> +// Copyright (C) 2009 Benoit Jacob <jacob.benoit.1@gmail.com> +// +// Copyright (C) 2013 Gauthier Brun <brun.gauthier@gmail.com> +// Copyright (C) 2013 Nicolas Carre <nicolas.carre@ensimag.fr> +// Copyright (C) 2013 Jean Ceccato <jean.ceccato@ensimag.fr> +// Copyright (C) 2013 Pierre Zoppitelli <pierre.zoppitelli@ensimag.fr> +// +// 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 <unsupported/Eigen/SVD> +#include <Eigen/LU> + + +// check if "svd" is the good image of "m" +template<typename MatrixType, typename SVD> +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<Scalar, RowsAtCompileTime, RowsAtCompileTime> MatrixUType; + typedef Matrix<Scalar, ColsAtCompileTime, ColsAtCompileTime> MatrixVType; + + + MatrixType sigma = MatrixType::Zero(rows, cols); + sigma.diagonal() = svd.singularValues().template cast<Scalar>(); + 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<typename MatrixType, typename SVD> +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<typename MatrixType, typename SVD> +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<Scalar, RowsAtCompileTime, Dynamic> RhsType; + typedef Matrix<Scalar, ColsAtCompileTime, Dynamic> SolutionType; + + RhsType rhs = RhsType::Random(rows, internal::random<Index>(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<typename MatrixType, typename SVD> +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<typename MatrixType, typename SVD> +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<MatrixType, SVD>(m, ComputeFullU | ComputeThinV); + svd_solve<MatrixType, SVD>(m, ComputeThinU | ComputeFullV); + svd_solve<MatrixType, SVD>(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<typename MatrixType, typename SVD> +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<Scalar, RowsAtCompileTime, 1> 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<typename Scalar> +EIGEN_DONT_INLINE Scalar zero() { return Scalar(0); } + +// workaround aggressive optimization in ICC +template<typename T> EIGEN_DONT_INLINE T sub(T a, T b) { return a - b; } + + +template<typename MatrixType, typename SVD> +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<Scalar>(); + 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<Scalar> () / zero<Scalar> (); + VERIFY(some_nan != some_nan); + svd.compute(MatrixType::Constant(10,10,some_nan), ComputeFullU | ComputeFullV); + + MatrixType m = MatrixType::Zero(10,10); + m(internal::random<int>(0,9), internal::random<int>(0,9)) = some_inf; + svd.compute(m, ComputeFullU | ComputeFullV); + + m = MatrixType::Zero(10,10); + m(internal::random<int>(0,9), internal::random<int>(0,9)) = some_nan; + svd.compute(m, ComputeFullU | ComputeFullV); +} + + +template<typename SVD> +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); +} + + + + + |