adaptive_gauss_kronrod_quadrature_test.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. // Copyright Nick Thompson, 2017
  2. // Use, modification and distribution are subject to the
  3. // Boost Software License, Version 1.0.
  4. // (See accompanying file LICENSE_1_0.txt
  5. // or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. #define BOOST_TEST_MODULE adaptive_gauss_kronrod_quadrature_test
  7. #include <boost/config.hpp>
  8. #include <boost/detail/workaround.hpp>
  9. #if !defined(BOOST_NO_CXX11_DECLTYPE) && !defined(BOOST_NO_CXX11_TRAILING_RESULT_TYPES) && !defined(BOOST_NO_SFINAE_EXPR)
  10. #include <boost/math/concepts/real_concept.hpp>
  11. #include <boost/test/included/unit_test.hpp>
  12. #include <boost/test/tools/floating_point_comparison.hpp>
  13. #include <boost/math/quadrature/gauss_kronrod.hpp>
  14. #include <boost/math/special_functions/sinc.hpp>
  15. #include <boost/multiprecision/cpp_bin_float.hpp>
  16. #if !defined(TEST1) && !defined(TEST1A) && !defined(TEST2) && !defined(TEST3)
  17. # define TEST1
  18. # define TEST1A
  19. # define TEST2
  20. # define TEST3
  21. #endif
  22. #ifdef _MSC_VER
  23. #pragma warning(disable:4127) // Conditional expression is constant
  24. #endif
  25. using std::expm1;
  26. using std::atan;
  27. using std::tan;
  28. using std::log;
  29. using std::log1p;
  30. using std::asinh;
  31. using std::atanh;
  32. using std::sqrt;
  33. using std::isnormal;
  34. using std::abs;
  35. using std::sinh;
  36. using std::tanh;
  37. using std::cosh;
  38. using std::pow;
  39. using std::exp;
  40. using std::sin;
  41. using std::cos;
  42. using std::string;
  43. using boost::math::quadrature::gauss_kronrod;
  44. using boost::math::constants::pi;
  45. using boost::math::constants::half_pi;
  46. using boost::math::constants::two_div_pi;
  47. using boost::math::constants::two_pi;
  48. using boost::math::constants::half;
  49. using boost::math::constants::third;
  50. using boost::math::constants::half;
  51. using boost::math::constants::third;
  52. using boost::math::constants::catalan;
  53. using boost::math::constants::ln_two;
  54. using boost::math::constants::root_two;
  55. using boost::math::constants::root_two_pi;
  56. using boost::math::constants::root_pi;
  57. using boost::multiprecision::cpp_bin_float_quad;
  58. template <class Real>
  59. Real get_termination_condition()
  60. {
  61. return boost::math::tools::epsilon<Real>() * 1000;
  62. }
  63. template<class Real, unsigned Points>
  64. void test_linear()
  65. {
  66. std::cout << "Testing linear functions are integrated properly by gauss_kronrod on type " << boost::typeindex::type_id<Real>().pretty_name() << "\n";
  67. Real tol = boost::math::tools::epsilon<Real>() * 10;
  68. Real error;
  69. auto f = [](const Real& x)
  70. {
  71. return 5*x + 7;
  72. };
  73. Real L1;
  74. Real Q = gauss_kronrod<Real, Points>::integrate(f, (Real) 0, (Real) 1, 15, get_termination_condition<Real>(), &error, &L1);
  75. BOOST_CHECK_CLOSE_FRACTION(Q, 9.5, tol);
  76. BOOST_CHECK_CLOSE_FRACTION(L1, 9.5, tol);
  77. BOOST_CHECK_LE(fabs(error / Q), get_termination_condition<Real>());
  78. BOOST_CHECK_GE(fabs(error), fabs(Q - 9.5));
  79. }
  80. template<class Real, unsigned Points>
  81. void test_quadratic()
  82. {
  83. std::cout << "Testing quadratic functions are integrated properly by gauss-kronrod on type " << boost::typeindex::type_id<Real>().pretty_name() << "\n";
  84. Real tol = boost::math::tools::epsilon<Real>() * 10;
  85. Real error;
  86. auto f = [](const Real& x) { return 5*x*x + 7*x + 12; };
  87. Real L1;
  88. Real Q = gauss_kronrod<Real, Points>::integrate(f, 0, 1, 15, get_termination_condition<Real>(), &error, &L1);
  89. BOOST_CHECK_CLOSE_FRACTION(Q, (Real) 17 + half<Real>()*third<Real>(), tol);
  90. BOOST_CHECK_CLOSE_FRACTION(L1, (Real) 17 + half<Real>()*third<Real>(), tol);
  91. BOOST_CHECK_LE(fabs(error / Q), get_termination_condition<Real>());
  92. BOOST_CHECK_GE(fabs(error), fabs(Q - ((Real)17 + half<Real>()*third<Real>())));
  93. }
  94. // Examples taken from
  95. //http://crd-legacy.lbl.gov/~dhbailey/dhbpapers/quadrature.pdf
  96. template<class Real, unsigned Points>
  97. void test_ca()
  98. {
  99. std::cout << "Testing integration of C(a) on type " << boost::typeindex::type_id<Real>().pretty_name() << "\n";
  100. Real tol = boost::math::tools::epsilon<Real>() * 10;
  101. Real L1;
  102. Real error;
  103. auto f1 = [](const Real& x) { return atan(x)/(x*(x*x + 1)) ; };
  104. Real Q = gauss_kronrod<Real, Points>::integrate(f1, 0, 1, 15, get_termination_condition<Real>(), &error, &L1);
  105. Real Q_expected = pi<Real>()*ln_two<Real>()/8 + catalan<Real>()*half<Real>();
  106. BOOST_CHECK_CLOSE_FRACTION(Q, Q_expected, tol);
  107. BOOST_CHECK_CLOSE_FRACTION(L1, Q_expected, tol);
  108. BOOST_CHECK_LE(fabs(error / Q), get_termination_condition<Real>());
  109. BOOST_CHECK_GE(fabs(error), fabs(Q - Q_expected));
  110. auto f2 = [](Real x)->Real { Real t0 = x*x + 1; Real t1 = sqrt(t0); return atan(t1)/(t0*t1); };
  111. Q = gauss_kronrod<Real, Points>::integrate(f2, 0 , 1, 15, get_termination_condition<Real>(), &error, &L1);
  112. Q_expected = pi<Real>()/4 - pi<Real>()/root_two<Real>() + 3*atan(root_two<Real>())/root_two<Real>();
  113. BOOST_CHECK_CLOSE_FRACTION(Q, Q_expected, tol);
  114. BOOST_CHECK_CLOSE_FRACTION(L1, Q_expected, tol);
  115. BOOST_CHECK_LE(fabs(error / Q), get_termination_condition<Real>());
  116. BOOST_CHECK_GE(fabs(error), fabs(Q - Q_expected));
  117. auto f5 = [](Real t)->Real { return t*t*log(t)/((t*t - 1)*(t*t*t*t + 1)); };
  118. Q = gauss_kronrod<Real, Points>::integrate(f5, 0, 1, 25);
  119. Q_expected = pi<Real>()*pi<Real>()*(2 - root_two<Real>())/32;
  120. BOOST_CHECK_CLOSE_FRACTION(Q, Q_expected, 100 * tol);
  121. }
  122. template<class Real, unsigned Points>
  123. void test_three_quadrature_schemes_examples()
  124. {
  125. std::cout << "Testing integral in 'A Comparison of Three High Precision Quadrature Schemes' on type " << boost::typeindex::type_id<Real>().pretty_name() << "\n";
  126. Real tol = boost::math::tools::epsilon<Real>() * 10;
  127. Real Q;
  128. Real Q_expected;
  129. // Example 1:
  130. auto f1 = [](const Real& t) { return t*boost::math::log1p(t); };
  131. Q = gauss_kronrod<Real, Points>::integrate(f1, 0 , 1);
  132. Q_expected = half<Real>()*half<Real>();
  133. BOOST_CHECK_CLOSE_FRACTION(Q, Q_expected, tol);
  134. // Example 2:
  135. auto f2 = [](const Real& t) { return t*t*atan(t); };
  136. Q = gauss_kronrod<Real, Points>::integrate(f2, 0, 1);
  137. Q_expected = (pi<Real>() -2 + 2*ln_two<Real>())/12;
  138. BOOST_CHECK_CLOSE_FRACTION(Q, Q_expected, 2 * tol);
  139. // Example 3:
  140. auto f3 = [](const Real& t) { return exp(t)*cos(t); };
  141. Q = gauss_kronrod<Real, Points>::integrate(f3, 0, half_pi<Real>());
  142. Q_expected = boost::math::expm1(half_pi<Real>())*half<Real>();
  143. BOOST_CHECK_CLOSE_FRACTION(Q, Q_expected, tol);
  144. // Example 4:
  145. auto f4 = [](Real x)->Real { Real t0 = sqrt(x*x + 2); return atan(t0)/(t0*(x*x+1)); };
  146. Q = gauss_kronrod<Real, Points>::integrate(f4, 0, 1);
  147. Q_expected = 5*pi<Real>()*pi<Real>()/96;
  148. BOOST_CHECK_CLOSE_FRACTION(Q, Q_expected, tol);
  149. }
  150. template<class Real, unsigned Points>
  151. void test_integration_over_real_line()
  152. {
  153. std::cout << "Testing integrals over entire real line in 'A Comparison of Three High Precision Quadrature Schemes' on type " << boost::typeindex::type_id<Real>().pretty_name() << "\n";
  154. Real tol = boost::math::tools::epsilon<Real>() * 10;
  155. Real Q;
  156. Real Q_expected;
  157. Real L1;
  158. Real error;
  159. auto f1 = [](const Real& t) { return 1/(1+t*t);};
  160. Q = gauss_kronrod<Real, Points>::integrate(f1, -boost::math::tools::max_value<Real>(), boost::math::tools::max_value<Real>(), 15, get_termination_condition<Real>(), &error, &L1);
  161. Q_expected = pi<Real>();
  162. BOOST_CHECK_CLOSE_FRACTION(Q, Q_expected, tol);
  163. BOOST_CHECK_CLOSE_FRACTION(L1, Q_expected, tol);
  164. BOOST_CHECK_LE(fabs(error / Q), get_termination_condition<Real>());
  165. auto f4 = [](const Real& t) { return 1/cosh(t);};
  166. Q = gauss_kronrod<Real, Points>::integrate(f4, -boost::math::tools::max_value<Real>(), boost::math::tools::max_value<Real>(), 15, get_termination_condition<Real>(), &error, &L1);
  167. Q_expected = pi<Real>();
  168. BOOST_CHECK_CLOSE_FRACTION(Q, Q_expected, tol);
  169. BOOST_CHECK_CLOSE_FRACTION(L1, Q_expected, tol);
  170. BOOST_CHECK_LE(fabs(error / Q), get_termination_condition<Real>());
  171. }
  172. template<class Real, unsigned Points>
  173. void test_right_limit_infinite()
  174. {
  175. std::cout << "Testing right limit infinite for Gauss-Kronrod in 'A Comparison of Three High Precision Quadrature Schemes' on type " << boost::typeindex::type_id<Real>().pretty_name() << "\n";
  176. Real tol = boost::math::tools::epsilon<Real>() * 10;
  177. Real Q;
  178. Real Q_expected;
  179. Real L1;
  180. Real error;
  181. // Example 11:
  182. auto f1 = [](const Real& t) { return 1/(1+t*t);};
  183. Q = gauss_kronrod<Real, Points>::integrate(f1, 0, boost::math::tools::max_value<Real>(), 15, get_termination_condition<Real>(), &error, &L1);
  184. Q_expected = half_pi<Real>();
  185. BOOST_CHECK_CLOSE(Q, Q_expected, 100*tol);
  186. BOOST_CHECK_LE(fabs(error / Q), get_termination_condition<Real>());
  187. auto f4 = [](const Real& t) { return 1/(1+t*t); };
  188. Q = gauss_kronrod<Real, Points>::integrate(f4, 1, boost::math::tools::max_value<Real>(), 15, get_termination_condition<Real>(), &error, &L1);
  189. Q_expected = pi<Real>()/4;
  190. BOOST_CHECK_CLOSE(Q, Q_expected, 100*tol);
  191. BOOST_CHECK_LE(fabs(error / Q), get_termination_condition<Real>());
  192. }
  193. template<class Real, unsigned Points>
  194. void test_left_limit_infinite()
  195. {
  196. std::cout << "Testing left limit infinite for Gauss-Kronrod in 'A Comparison of Three High Precision Quadrature Schemes' on type " << boost::typeindex::type_id<Real>().pretty_name() << "\n";
  197. Real tol = boost::math::tools::epsilon<Real>() * 10;
  198. Real Q;
  199. Real Q_expected;
  200. // Example 11:
  201. auto f1 = [](const Real& t) { return 1/(1+t*t);};
  202. Q = gauss_kronrod<Real, Points>::integrate(f1, -boost::math::tools::max_value<Real>(), 0);
  203. Q_expected = half_pi<Real>();
  204. BOOST_CHECK_CLOSE(Q, Q_expected, 300*tol);
  205. }
  206. BOOST_AUTO_TEST_CASE(gauss_quadrature_test)
  207. {
  208. #ifdef TEST1
  209. std::cout << "Testing with 15 point Gauss-Kronrod rule:\n";
  210. test_linear<double, 15>();
  211. test_quadratic<double, 15>();
  212. test_ca<double, 15>();
  213. test_three_quadrature_schemes_examples<double, 15>();
  214. test_integration_over_real_line<double, 15>();
  215. test_right_limit_infinite<double, 15>();
  216. test_left_limit_infinite<double, 15>();
  217. // test one case where we do not have pre-computed constants:
  218. std::cout << "Testing with 17 point Gauss-Kronrod rule:\n";
  219. test_linear<double, 17>();
  220. test_quadratic<double, 17>();
  221. test_ca<double, 17>();
  222. test_three_quadrature_schemes_examples<double, 17>();
  223. test_integration_over_real_line<double, 17>();
  224. test_right_limit_infinite<double, 17>();
  225. test_left_limit_infinite<double, 17>();
  226. #endif
  227. #ifdef TEST1A
  228. std::cout << "Testing with 21 point Gauss-Kronrod rule:\n";
  229. test_linear<cpp_bin_float_quad, 21>();
  230. test_quadratic<cpp_bin_float_quad, 21>();
  231. test_ca<cpp_bin_float_quad, 21>();
  232. test_three_quadrature_schemes_examples<cpp_bin_float_quad, 21>();
  233. test_integration_over_real_line<cpp_bin_float_quad, 21>();
  234. test_right_limit_infinite<cpp_bin_float_quad, 21>();
  235. test_left_limit_infinite<cpp_bin_float_quad, 21>();
  236. std::cout << "Testing with 31 point Gauss-Kronrod rule:\n";
  237. test_linear<cpp_bin_float_quad, 31>();
  238. test_quadratic<cpp_bin_float_quad, 31>();
  239. test_ca<cpp_bin_float_quad, 31>();
  240. test_three_quadrature_schemes_examples<cpp_bin_float_quad, 31>();
  241. test_integration_over_real_line<cpp_bin_float_quad, 31>();
  242. test_right_limit_infinite<cpp_bin_float_quad, 31>();
  243. test_left_limit_infinite<cpp_bin_float_quad, 31>();
  244. #endif
  245. #ifdef TEST2
  246. std::cout << "Testing with 41 point Gauss-Kronrod rule:\n";
  247. test_linear<cpp_bin_float_quad, 41>();
  248. test_quadratic<cpp_bin_float_quad, 41>();
  249. test_ca<cpp_bin_float_quad, 41>();
  250. test_three_quadrature_schemes_examples<cpp_bin_float_quad, 41>();
  251. test_integration_over_real_line<cpp_bin_float_quad, 41>();
  252. test_right_limit_infinite<cpp_bin_float_quad, 41>();
  253. test_left_limit_infinite<cpp_bin_float_quad, 41>();
  254. std::cout << "Testing with 51 point Gauss-Kronrod rule:\n";
  255. test_linear<cpp_bin_float_quad, 51>();
  256. test_quadratic<cpp_bin_float_quad, 51>();
  257. test_ca<cpp_bin_float_quad, 51>();
  258. test_three_quadrature_schemes_examples<cpp_bin_float_quad, 51>();
  259. test_integration_over_real_line<cpp_bin_float_quad, 51>();
  260. test_right_limit_infinite<cpp_bin_float_quad, 51>();
  261. test_left_limit_infinite<cpp_bin_float_quad, 51>();
  262. #endif
  263. #ifdef TEST3
  264. std::cout << "Testing with 61 point Gauss-Kronrod rule:\n";
  265. test_linear<cpp_bin_float_quad, 61>();
  266. test_quadratic<cpp_bin_float_quad, 61>();
  267. test_ca<cpp_bin_float_quad, 61>();
  268. test_three_quadrature_schemes_examples<cpp_bin_float_quad, 61>();
  269. test_integration_over_real_line<cpp_bin_float_quad, 61>();
  270. test_right_limit_infinite<cpp_bin_float_quad, 61>();
  271. test_left_limit_infinite<cpp_bin_float_quad, 61>();
  272. #endif
  273. }
  274. #else
  275. int main() { return 0; }
  276. #endif