condition_number_test.cpp 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. // (C) Copyright Nick Thompson, 2019
  2. // Use, modification and distribution are subject to the
  3. // Boost Software License, Version 1.0. (See accompanying file
  4. // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  5. #define BOOST_TEST_MODULE condition_number_test
  6. #include <cmath>
  7. #include <limits>
  8. #include <iostream>
  9. #include <boost/math/constants/constants.hpp>
  10. #include <boost/math/special_functions/lambert_w.hpp>
  11. #include <boost/test/included/unit_test.hpp>
  12. #include <boost/multiprecision/cpp_bin_float.hpp>
  13. #include <boost/math/tools/condition_numbers.hpp>
  14. using std::abs;
  15. using boost::math::constants::half;
  16. using boost::math::constants::ln_two;
  17. using boost::multiprecision::cpp_bin_float_50;
  18. using boost::math::tools::summation_condition_number;
  19. using boost::math::tools::evaluation_condition_number;
  20. template<class Real>
  21. void test_summation_condition_number()
  22. {
  23. Real tol = 1000*std::numeric_limits<float>::epsilon();
  24. auto cond = summation_condition_number<Real>();
  25. // I've checked that the condition number increases with max_n,
  26. // and that the computed sum gets more accurate with increasing max_n.
  27. // But the CI system would die with more terms.
  28. Real max_n = 10000;
  29. for (Real n = 1; n < max_n; n += 2)
  30. {
  31. cond += 1/n;
  32. cond -= 1/(n+1);
  33. }
  34. BOOST_CHECK_CLOSE_FRACTION(cond.sum(), ln_two<Real>(), tol);
  35. BOOST_TEST(cond() > 14);
  36. }
  37. template<class Real>
  38. void test_exponential_sum()
  39. {
  40. using std::exp;
  41. using std::abs;
  42. Real eps = std::numeric_limits<float>::epsilon();
  43. for (Real x = -20; x <= -1; x += 0.5)
  44. {
  45. auto cond = summation_condition_number<Real>(1);
  46. size_t n = 1;
  47. Real term = x;
  48. while(n++ < 1000)
  49. {
  50. cond += term;
  51. term *= (x/n);
  52. }
  53. BOOST_CHECK_CLOSE_FRACTION(exp(x), cond.sum(), eps*cond());
  54. BOOST_CHECK_CLOSE_FRACTION(exp(2*abs(x)), cond(), eps*cond());
  55. }
  56. }
  57. template<class Real>
  58. void test_evaluation_condition_number()
  59. {
  60. using std::abs;
  61. using std::log;
  62. using std::sqrt;
  63. using std::exp;
  64. using std::sin;
  65. using std::tan;
  66. Real tol = sqrt(std::numeric_limits<Real>::epsilon());
  67. auto f1 = [](auto x) { return log(x); };
  68. for (Real x = 1.125; x < 8; x += 0.125)
  69. {
  70. Real cond = evaluation_condition_number(f1, x);
  71. BOOST_CHECK_CLOSE_FRACTION(cond, 1/log(x), tol);
  72. }
  73. auto f2 = [](auto x) { return exp(x); };
  74. for (Real x = 1.125; x < 8; x += 0.125)
  75. {
  76. Real cond = evaluation_condition_number(f2, x);
  77. BOOST_CHECK_CLOSE_FRACTION(cond, x, tol);
  78. }
  79. auto f3 = [](auto x) { return sin(x); };
  80. for (Real x = 1.125; x < 8; x += 0.125)
  81. {
  82. Real cond = evaluation_condition_number(f3, x);
  83. BOOST_CHECK_CLOSE_FRACTION(cond, abs(x/tan(x)), tol);
  84. }
  85. // Test a function which right differentiable:
  86. using boost::math::constants::e;
  87. auto f4 = [](Real x) { return boost::math::lambert_w0(x); };
  88. Real cond = evaluation_condition_number(f4, -1/e<Real>());
  89. if (std::is_same_v<Real, float>)
  90. {
  91. BOOST_CHECK_GE(cond, 30);
  92. }
  93. else
  94. {
  95. BOOST_CHECK_GE(cond, 4900);
  96. }
  97. }
  98. BOOST_AUTO_TEST_CASE(numerical_differentiation_test)
  99. {
  100. test_summation_condition_number<float>();
  101. test_summation_condition_number<cpp_bin_float_50>();
  102. test_evaluation_condition_number<float>();
  103. test_evaluation_condition_number<double>();
  104. test_evaluation_condition_number<long double>();
  105. test_evaluation_condition_number<cpp_bin_float_50>();
  106. test_exponential_sum<double>();
  107. }