// Copyright Nick Thompson, 2017 // Use, modification and distribution are subject to the // Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) #define BOOST_TEST_MODULE adaptive_gauss_kronrod_quadrature_test #include #include #if !defined(BOOST_NO_CXX11_DECLTYPE) && !defined(BOOST_NO_CXX11_TRAILING_RESULT_TYPES) && !defined(BOOST_NO_SFINAE_EXPR) #include #include #include #include #include #include #if !defined(TEST1) && !defined(TEST1A) && !defined(TEST2) && !defined(TEST3) # define TEST1 # define TEST1A # define TEST2 # define TEST3 #endif #ifdef _MSC_VER #pragma warning(disable:4127) // Conditional expression is constant #endif using std::expm1; using std::atan; using std::tan; using std::log; using std::log1p; using std::asinh; using std::atanh; using std::sqrt; using std::isnormal; using std::abs; using std::sinh; using std::tanh; using std::cosh; using std::pow; using std::exp; using std::sin; using std::cos; using std::string; using boost::math::quadrature::gauss_kronrod; using boost::math::constants::pi; using boost::math::constants::half_pi; using boost::math::constants::two_div_pi; using boost::math::constants::two_pi; using boost::math::constants::half; using boost::math::constants::third; using boost::math::constants::half; using boost::math::constants::third; using boost::math::constants::catalan; using boost::math::constants::ln_two; using boost::math::constants::root_two; using boost::math::constants::root_two_pi; using boost::math::constants::root_pi; using boost::multiprecision::cpp_bin_float_quad; template Real get_termination_condition() { return boost::math::tools::epsilon() * 1000; } template void test_linear() { std::cout << "Testing linear functions are integrated properly by gauss_kronrod on type " << boost::typeindex::type_id().pretty_name() << "\n"; Real tol = boost::math::tools::epsilon() * 10; Real error; auto f = [](const Real& x) { return 5*x + 7; }; Real L1; Real Q = gauss_kronrod::integrate(f, (Real) 0, (Real) 1, 15, get_termination_condition(), &error, &L1); BOOST_CHECK_CLOSE_FRACTION(Q, 9.5, tol); BOOST_CHECK_CLOSE_FRACTION(L1, 9.5, tol); BOOST_CHECK_LE(fabs(error / Q), get_termination_condition()); BOOST_CHECK_GE(fabs(error), fabs(Q - 9.5)); } template void test_quadratic() { std::cout << "Testing quadratic functions are integrated properly by gauss-kronrod on type " << boost::typeindex::type_id().pretty_name() << "\n"; Real tol = boost::math::tools::epsilon() * 10; Real error; auto f = [](const Real& x) { return 5*x*x + 7*x + 12; }; Real L1; Real Q = gauss_kronrod::integrate(f, 0, 1, 15, get_termination_condition(), &error, &L1); BOOST_CHECK_CLOSE_FRACTION(Q, (Real) 17 + half()*third(), tol); BOOST_CHECK_CLOSE_FRACTION(L1, (Real) 17 + half()*third(), tol); BOOST_CHECK_LE(fabs(error / Q), get_termination_condition()); BOOST_CHECK_GE(fabs(error), fabs(Q - ((Real)17 + half()*third()))); } // Examples taken from //http://crd-legacy.lbl.gov/~dhbailey/dhbpapers/quadrature.pdf template void test_ca() { std::cout << "Testing integration of C(a) on type " << boost::typeindex::type_id().pretty_name() << "\n"; Real tol = boost::math::tools::epsilon() * 10; Real L1; Real error; auto f1 = [](const Real& x) { return atan(x)/(x*(x*x + 1)) ; }; Real Q = gauss_kronrod::integrate(f1, 0, 1, 15, get_termination_condition(), &error, &L1); Real Q_expected = pi()*ln_two()/8 + catalan()*half(); BOOST_CHECK_CLOSE_FRACTION(Q, Q_expected, tol); BOOST_CHECK_CLOSE_FRACTION(L1, Q_expected, tol); BOOST_CHECK_LE(fabs(error / Q), get_termination_condition()); BOOST_CHECK_GE(fabs(error), fabs(Q - Q_expected)); auto f2 = [](Real x)->Real { Real t0 = x*x + 1; Real t1 = sqrt(t0); return atan(t1)/(t0*t1); }; Q = gauss_kronrod::integrate(f2, 0 , 1, 15, get_termination_condition(), &error, &L1); Q_expected = pi()/4 - pi()/root_two() + 3*atan(root_two())/root_two(); BOOST_CHECK_CLOSE_FRACTION(Q, Q_expected, tol); BOOST_CHECK_CLOSE_FRACTION(L1, Q_expected, tol); BOOST_CHECK_LE(fabs(error / Q), get_termination_condition()); BOOST_CHECK_GE(fabs(error), fabs(Q - Q_expected)); auto f5 = [](Real t)->Real { return t*t*log(t)/((t*t - 1)*(t*t*t*t + 1)); }; Q = gauss_kronrod::integrate(f5, 0, 1, 25); Q_expected = pi()*pi()*(2 - root_two())/32; BOOST_CHECK_CLOSE_FRACTION(Q, Q_expected, 100 * tol); } template void test_three_quadrature_schemes_examples() { std::cout << "Testing integral in 'A Comparison of Three High Precision Quadrature Schemes' on type " << boost::typeindex::type_id().pretty_name() << "\n"; Real tol = boost::math::tools::epsilon() * 10; Real Q; Real Q_expected; // Example 1: auto f1 = [](const Real& t) { return t*boost::math::log1p(t); }; Q = gauss_kronrod::integrate(f1, 0 , 1); Q_expected = half()*half(); BOOST_CHECK_CLOSE_FRACTION(Q, Q_expected, tol); // Example 2: auto f2 = [](const Real& t) { return t*t*atan(t); }; Q = gauss_kronrod::integrate(f2, 0, 1); Q_expected = (pi() -2 + 2*ln_two())/12; BOOST_CHECK_CLOSE_FRACTION(Q, Q_expected, 2 * tol); // Example 3: auto f3 = [](const Real& t) { return exp(t)*cos(t); }; Q = gauss_kronrod::integrate(f3, 0, half_pi()); Q_expected = boost::math::expm1(half_pi())*half(); BOOST_CHECK_CLOSE_FRACTION(Q, Q_expected, tol); // Example 4: auto f4 = [](Real x)->Real { Real t0 = sqrt(x*x + 2); return atan(t0)/(t0*(x*x+1)); }; Q = gauss_kronrod::integrate(f4, 0, 1); Q_expected = 5*pi()*pi()/96; BOOST_CHECK_CLOSE_FRACTION(Q, Q_expected, tol); } template void test_integration_over_real_line() { std::cout << "Testing integrals over entire real line in 'A Comparison of Three High Precision Quadrature Schemes' on type " << boost::typeindex::type_id().pretty_name() << "\n"; Real tol = boost::math::tools::epsilon() * 10; Real Q; Real Q_expected; Real L1; Real error; auto f1 = [](const Real& t) { return 1/(1+t*t);}; Q = gauss_kronrod::integrate(f1, -boost::math::tools::max_value(), boost::math::tools::max_value(), 15, get_termination_condition(), &error, &L1); Q_expected = pi(); BOOST_CHECK_CLOSE_FRACTION(Q, Q_expected, tol); BOOST_CHECK_CLOSE_FRACTION(L1, Q_expected, tol); BOOST_CHECK_LE(fabs(error / Q), get_termination_condition()); auto f4 = [](const Real& t) { return 1/cosh(t);}; Q = gauss_kronrod::integrate(f4, -boost::math::tools::max_value(), boost::math::tools::max_value(), 15, get_termination_condition(), &error, &L1); Q_expected = pi(); BOOST_CHECK_CLOSE_FRACTION(Q, Q_expected, tol); BOOST_CHECK_CLOSE_FRACTION(L1, Q_expected, tol); BOOST_CHECK_LE(fabs(error / Q), get_termination_condition()); } template void test_right_limit_infinite() { std::cout << "Testing right limit infinite for Gauss-Kronrod in 'A Comparison of Three High Precision Quadrature Schemes' on type " << boost::typeindex::type_id().pretty_name() << "\n"; Real tol = boost::math::tools::epsilon() * 10; Real Q; Real Q_expected; Real L1; Real error; // Example 11: auto f1 = [](const Real& t) { return 1/(1+t*t);}; Q = gauss_kronrod::integrate(f1, 0, boost::math::tools::max_value(), 15, get_termination_condition(), &error, &L1); Q_expected = half_pi(); BOOST_CHECK_CLOSE(Q, Q_expected, 100*tol); BOOST_CHECK_LE(fabs(error / Q), get_termination_condition()); auto f4 = [](const Real& t) { return 1/(1+t*t); }; Q = gauss_kronrod::integrate(f4, 1, boost::math::tools::max_value(), 15, get_termination_condition(), &error, &L1); Q_expected = pi()/4; BOOST_CHECK_CLOSE(Q, Q_expected, 100*tol); BOOST_CHECK_LE(fabs(error / Q), get_termination_condition()); } template void test_left_limit_infinite() { std::cout << "Testing left limit infinite for Gauss-Kronrod in 'A Comparison of Three High Precision Quadrature Schemes' on type " << boost::typeindex::type_id().pretty_name() << "\n"; Real tol = boost::math::tools::epsilon() * 10; Real Q; Real Q_expected; // Example 11: auto f1 = [](const Real& t) { return 1/(1+t*t);}; Q = gauss_kronrod::integrate(f1, -boost::math::tools::max_value(), 0); Q_expected = half_pi(); BOOST_CHECK_CLOSE(Q, Q_expected, 300*tol); } BOOST_AUTO_TEST_CASE(gauss_quadrature_test) { #ifdef TEST1 std::cout << "Testing with 15 point Gauss-Kronrod rule:\n"; test_linear(); test_quadratic(); test_ca(); test_three_quadrature_schemes_examples(); test_integration_over_real_line(); test_right_limit_infinite(); test_left_limit_infinite(); // test one case where we do not have pre-computed constants: std::cout << "Testing with 17 point Gauss-Kronrod rule:\n"; test_linear(); test_quadratic(); test_ca(); test_three_quadrature_schemes_examples(); test_integration_over_real_line(); test_right_limit_infinite(); test_left_limit_infinite(); #endif #ifdef TEST1A std::cout << "Testing with 21 point Gauss-Kronrod rule:\n"; test_linear(); test_quadratic(); test_ca(); test_three_quadrature_schemes_examples(); test_integration_over_real_line(); test_right_limit_infinite(); test_left_limit_infinite(); std::cout << "Testing with 31 point Gauss-Kronrod rule:\n"; test_linear(); test_quadratic(); test_ca(); test_three_quadrature_schemes_examples(); test_integration_over_real_line(); test_right_limit_infinite(); test_left_limit_infinite(); #endif #ifdef TEST2 std::cout << "Testing with 41 point Gauss-Kronrod rule:\n"; test_linear(); test_quadratic(); test_ca(); test_three_quadrature_schemes_examples(); test_integration_over_real_line(); test_right_limit_infinite(); test_left_limit_infinite(); std::cout << "Testing with 51 point Gauss-Kronrod rule:\n"; test_linear(); test_quadratic(); test_ca(); test_three_quadrature_schemes_examples(); test_integration_over_real_line(); test_right_limit_infinite(); test_left_limit_infinite(); #endif #ifdef TEST3 std::cout << "Testing with 61 point Gauss-Kronrod rule:\n"; test_linear(); test_quadratic(); test_ca(); test_three_quadrature_schemes_examples(); test_integration_over_real_line(); test_right_limit_infinite(); test_left_limit_infinite(); #endif } #else int main() { return 0; } #endif