// Copyright Matthew Pulver 2018 - 2019. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // https://www.boost.org/LICENSE_1_0.txt) #include "test_autodiff.hpp" BOOST_AUTO_TEST_SUITE(test_autodiff_4) BOOST_AUTO_TEST_CASE_TEMPLATE(lround_llround_lltrunc_truncl, T, all_float_types) { using boost::math::llround; using boost::math::lltrunc; using boost::math::lround; using boost::multiprecision::llround; using boost::multiprecision::lltrunc; using boost::multiprecision::lround; using detail::llround; using detail::lltrunc; using detail::lround; using detail::truncl; using std::truncl; constexpr std::size_t m = 3; const auto &cx = static_cast(3.25); auto x = make_fvar(cx); auto yl = lround(x); BOOST_CHECK_EQUAL(yl, lround(cx)); auto yll = llround(x); BOOST_CHECK_EQUAL(yll, llround(cx)); BOOST_CHECK_EQUAL(lltrunc(cx), lltrunc(x)); #ifndef BOOST_NO_CXX17_IF_CONSTEXPR if constexpr (!bmp::is_number::value && !bmp::is_number_expression::value) { BOOST_CHECK_EQUAL(truncl(x), truncl(cx)); } #endif } BOOST_AUTO_TEST_CASE_TEMPLATE(equality, T, all_float_types) { BOOST_MATH_STD_USING using boost::math::epsilon_difference; using boost::math::fpclassify; using boost::math::ulp; using std::fpclassify; constexpr std::size_t m = 3; // check zeros { auto x = make_fvar(0.0); auto y = T(-0.0); BOOST_CHECK_EQUAL(x.derivative(0u), y); } } #if defined(BOOST_AUTODIFF_TESTING_INCLUDE_MULTIPRECISION) BOOST_AUTO_TEST_CASE_TEMPLATE(multiprecision, T, multiprecision_float_types) { using boost::multiprecision::fabs; using detail::fabs; using std::fabs; const T eps = 3000 * std::numeric_limits::epsilon(); constexpr std::size_t Nw = 3; constexpr std::size_t Nx = 2; constexpr std::size_t Ny = 4; constexpr std::size_t Nz = 3; const auto w = make_fvar(11); const auto x = make_fvar(12); const auto y = make_fvar(13); const auto z = make_fvar(14); const auto v = mixed_partials_f(w, x, y, z); // auto = autodiff_fvar // Calculated from Mathematica symbolic differentiation. const T answer = boost::lexical_cast( "1976.3196007477977177798818752904187209081211892187" "5499076582535951111845769110560421820940516423255314"); // BOOST_CHECK_CLOSE(v.derivative(Nw,Nx,Ny,Nz), answer, eps); // Doesn't work // for cpp_dec_float const T relative_error = static_cast(fabs(v.derivative(Nw, Nx, Ny, Nz) / answer - 1)); BOOST_CHECK_LT(relative_error, eps); } #endif BOOST_AUTO_TEST_CASE_TEMPLATE(airy_hpp, T, all_float_types) { using boost::multiprecision::min; using std::min; using test_constants = test_constants_t; static constexpr auto m = test_constants::order; test_detail::RandomSample x_sampler(-100, 100); for (auto i : boost::irange(test_constants::n_samples)) { const auto &x = x_sampler.next(); { auto autodiff_v = boost::math::airy_ai(make_fvar(x)); auto anchor_v = boost::math::airy_ai(x); BOOST_CHECK_CLOSE(autodiff_v.derivative(0u), anchor_v, 1e4 * test_constants::pct_epsilon()); } { auto autodiff_v = boost::math::airy_ai_prime(make_fvar(x)); auto anchor_v = boost::math::airy_ai_prime(x); BOOST_CHECK_CLOSE(autodiff_v.derivative(0u), anchor_v, 1e4 * test_constants::pct_epsilon()); } { auto x_ = (min)(x, T(26)); auto autodiff_v = boost::math::airy_bi(make_fvar(x_)); auto anchor_v = boost::math::airy_bi(x_); BOOST_CHECK_CLOSE(autodiff_v.derivative(0u), anchor_v, 1e4 * test_constants::pct_epsilon()); } { auto x_ = ((min))(x, T(26)); auto autodiff_v = boost::math::airy_bi_prime(make_fvar(x_)); auto anchor_v = boost::math::airy_bi_prime(x_); BOOST_CHECK_CLOSE(autodiff_v.derivative(0u), anchor_v, 1e4 * test_constants::pct_epsilon()); } if (i > 0) { { auto autodiff_v = boost::math::airy_ai_zero>(i); auto anchor_v = boost::math::airy_ai_zero(i); BOOST_CHECK_CLOSE(autodiff_v.derivative(0u), anchor_v, 1e4 * test_constants::pct_epsilon()); } { auto autodiff_v = boost::math::airy_bi_zero>(i); auto anchor_v = boost::math::airy_bi_zero(i); BOOST_CHECK_CLOSE(autodiff_v.derivative(0u), anchor_v, 1e4 * test_constants::pct_epsilon()); } } } } BOOST_AUTO_TEST_CASE_TEMPLATE(acosh_hpp, T, all_float_types) { using boost::math::acosh; using test_constants = test_constants_t; static constexpr auto m = test_constants::order; test_detail::RandomSample x_sampler{1, 100}; for (auto i : boost::irange(test_constants::n_samples)) { std::ignore = i; auto x = x_sampler.next(); auto autodiff_v = acosh(make_fvar(x)); auto anchor_v = acosh(x); BOOST_CHECK_CLOSE(autodiff_v.derivative(0u), anchor_v, 1e3 * test_constants::pct_epsilon()); } } BOOST_AUTO_TEST_CASE_TEMPLATE(asinh_hpp, T, all_float_types) { using boost::math::asinh; using test_constants = test_constants_t; static constexpr auto m = test_constants::order; test_detail::RandomSample x_sampler{-100, 100}; for (auto i : boost::irange(test_constants::n_samples)) { std::ignore = i; auto x = x_sampler.next(); auto autodiff_v = asinh(make_fvar(x)); auto anchor_v = asinh(x); BOOST_CHECK_CLOSE(autodiff_v.derivative(0u), anchor_v, 1e3 * test_constants::pct_epsilon()); } } BOOST_AUTO_TEST_CASE_TEMPLATE(atanh_hpp, T, all_float_types) { using boost::math::nextafter; using std::nextafter; using boost::math::atanh; using test_constants = test_constants_t; static constexpr auto m = test_constants::order; test_detail::RandomSample x_sampler{-1, 1}; for (auto i : boost::irange(test_constants::n_samples)) { std::ignore = i; auto x = nextafter(x_sampler.next(), T(0)); auto autodiff_v = atanh(make_fvar(x)); auto anchor_v = atanh(x); BOOST_CHECK_CLOSE(autodiff_v.derivative(0u), anchor_v, 1e3 * test_constants::pct_epsilon()); } } BOOST_AUTO_TEST_CASE_TEMPLATE(atan_hpp, T, all_float_types) { using boost::math::float_prior; using boost::math::fpclassify; using boost::math::signbit; using boost::math::differentiation::detail::atan; using boost::multiprecision::atan; using boost::multiprecision::fabs; using boost::multiprecision::fpclassify; using boost::multiprecision::signbit; using detail::fabs; using std::atan; using std::fabs; using test_constants = test_constants_t; static constexpr auto m = test_constants::order; test_detail::RandomSample x_sampler{-1, 1}; for (auto i : boost::irange(test_constants::n_samples)) { std::ignore = i; auto x = T(1); while (fpclassify(T(fabs(x) - 1)) == FP_ZERO) { x = x_sampler.next(); } auto autodiff_v = atan(make_fvar(x)); auto anchor_v = atan(x); BOOST_CHECK_CLOSE(autodiff_v.derivative(0u), anchor_v, 1e3 * test_constants::pct_epsilon()); } } BOOST_AUTO_TEST_CASE_TEMPLATE(bernoulli_hpp, T, all_float_types) { using boost::multiprecision::min; using std::min; using test_constants = test_constants_t; static constexpr auto m = test_constants::order; for (auto i : boost::irange(test_constants::n_samples)) { { auto autodiff_v = boost::math::bernoulli_b2n>(i); auto anchor_v = boost::math::bernoulli_b2n(i); BOOST_CHECK_CLOSE(autodiff_v.derivative(0u), anchor_v, 50 * test_constants::pct_epsilon()); } { auto i_ = (min)(19, i); auto autodiff_v = boost::math::tangent_t2n>(i_); auto anchor_v = boost::math::tangent_t2n(i_); BOOST_CHECK_CLOSE(autodiff_v.derivative(0u), anchor_v, 50 * test_constants::pct_epsilon()); } } } // TODO(kbhat): Something in here is very slow with boost::multiprecision BOOST_AUTO_TEST_CASE_TEMPLATE(bessel_hpp, T, bin_float_types) { using boost::math::fpclassify; using boost::math::nextafter; using boost::math::signbit; using boost::math::tools::max; using boost::multiprecision::fabs; using boost::multiprecision::fpclassify; using boost::multiprecision::signbit; using detail::fabs; using std::fabs; using std::max; using std::nextafter; using test_constants = test_constants_t; static constexpr auto m = test_constants::order; test_detail::RandomSample v_sampler{-20, 20}; test_detail::RandomSample x_sampler{ -boost::math::tools::log_max_value() + 1, boost::math::tools::log_max_value() - 1}; for (auto i : boost::irange(test_constants::n_samples)) { auto v = v_sampler.next(); auto x = x_sampler.next(); v = ((fpclassify(v) == FP_ZERO) ? 1 : -1) * (max)(v, (nextafter)(T(0), ((std::numeric_limits::max))())); if (signbit(x)) { v = static_cast(boost::math::itrunc(v)); } try { auto autodiff_v = boost::math::cyl_bessel_i(make_fvar(v), make_fvar(x)); auto anchor_v = boost::math::cyl_bessel_i(v, x); BOOST_WARN_CLOSE(autodiff_v.derivative(0u), anchor_v, 1e4 * test_constants::pct_epsilon()); } catch (const std::overflow_error &) { BOOST_CHECK_THROW( boost::math::cyl_bessel_i(make_fvar(v), make_fvar(x)), boost::wrapexcept); BOOST_CHECK_THROW(boost::math::cyl_bessel_i(v, x), boost::wrapexcept); } catch (...) { std::cout << "Inputs: v: " << v << " x: " << x << std::endl; std::rethrow_exception(std::current_exception()); } { auto x_j = fabs(x) + 1; try { auto autodiff_v = boost::math::cyl_bessel_j(make_fvar(v), make_fvar(x_j)); auto anchor_v = boost::math::cyl_bessel_j(v, x_j); BOOST_WARN_CLOSE(autodiff_v.derivative(0u), anchor_v, 1e4 * test_constants::pct_epsilon()); } catch (const std::overflow_error &) { BOOST_CHECK_THROW( boost::math::cyl_bessel_j(make_fvar(v), make_fvar(x_j)), boost::wrapexcept); BOOST_CHECK_THROW(boost::math::cyl_bessel_j(v, x_j), boost::wrapexcept); } catch (...) { std::cout << "Inputs: v: " << v << " x: " << x_j << std::endl; std::rethrow_exception(std::current_exception()); } } try { auto autodiff_v = boost::math::cyl_bessel_j_zero(make_fvar(v), i + 1); auto anchor_v = boost::math::cyl_bessel_j_zero(v, i + 1); BOOST_WARN_CLOSE(autodiff_v.derivative(0u), anchor_v, 1e4 * test_constants::pct_epsilon()); } catch (const std::overflow_error &) { BOOST_CHECK_THROW( boost::math::cyl_bessel_j_zero(make_fvar(v), i + 1), boost::wrapexcept); BOOST_CHECK_THROW(boost::math::cyl_bessel_j_zero(v, i + 1), boost::wrapexcept); } catch (...) { std::cout << "Inputs: v: " << v << " i: " << (i + 1) << std::endl; std::rethrow_exception(std::current_exception()); } { auto x_k = fabs(x) + 1; try { auto autodiff_v = boost::math::cyl_bessel_k(make_fvar(v), make_fvar(x_k)); auto anchor_v = boost::math::cyl_bessel_k(v, x_k); BOOST_WARN_CLOSE(autodiff_v.derivative(0u), anchor_v, 1e4 * test_constants::pct_epsilon()); } catch (const std::overflow_error &) { BOOST_CHECK_THROW( boost::math::cyl_bessel_k(make_fvar(v), make_fvar(x_k)), boost::wrapexcept); BOOST_CHECK_THROW(boost::math::cyl_bessel_k(v, x_k), boost::wrapexcept); } catch (...) { std::cout << "Inputs: v: " << v << " x: " << x_k << std::endl; std::rethrow_exception(std::current_exception()); } } { auto x_neumann = fabs(x) + 1; try { auto autodiff_v = boost::math::cyl_neumann(make_fvar(v), make_fvar(x_neumann)); auto anchor_v = boost::math::cyl_neumann(v, x_neumann); BOOST_WARN_CLOSE(autodiff_v.derivative(0u), anchor_v, 1e4 * test_constants::pct_epsilon()); } catch (const std::overflow_error &) { BOOST_CHECK_THROW(boost::math::cyl_neumann(make_fvar(v), make_fvar(x_neumann)), boost::wrapexcept); BOOST_CHECK_THROW(boost::math::cyl_neumann(v, x_neumann), boost::wrapexcept); } catch (...) { std::cout << "Inputs: v: " << v << " x: " << x_neumann << std::endl; std::rethrow_exception(std::current_exception()); } } { try { auto autodiff_v = boost::math::cyl_neumann_zero(make_fvar(v), i + 1); auto anchor_v = boost::math::cyl_neumann_zero(v, i + 1); BOOST_WARN_CLOSE(autodiff_v.derivative(0u), anchor_v, 1e4 * test_constants::pct_epsilon()); } catch (std::overflow_error &) { BOOST_CHECK_THROW( boost::math::cyl_neumann_zero((make_fvar)(v), i + 1), boost::wrapexcept); BOOST_CHECK_THROW(boost::math::cyl_neumann_zero(v, i + 1), boost::wrapexcept); } catch (...) { std::cout << "Inputs: v: " << v << " i: " << (i + 1) << std::endl; std::rethrow_exception(std::current_exception()); } } { auto i_ = static_cast(i); try { auto autodiff_v = boost::math::sph_bessel>( i_, make_fvar(fabs(v))); auto anchor_v = boost::math::sph_bessel(i_, fabs(v)); BOOST_WARN_CLOSE(autodiff_v.derivative(0u), anchor_v, 1e4 * test_constants::pct_epsilon()); } catch (const std::overflow_error &) { BOOST_CHECK_THROW( (boost::math::sph_bessel< autodiff_fvar>)(i_, (make_fvar)(fabs(v))), boost::wrapexcept); BOOST_CHECK_THROW(boost::math::sph_bessel(i_, fabs(v)), boost::wrapexcept); } catch (...) { std::cout << "Inputs: i: " << i_ << " v: " << (fabs(v)) << std::endl; std::rethrow_exception(std::current_exception()); } { auto v_ = (max)(T(fabs(v)), nextafter(T(fabs(v)), 2 * (std::numeric_limits::min)())); try { auto autodiff_v = boost::math::sph_neumann>( i_, make_fvar(v_)); auto anchor_v = boost::math::sph_neumann(i_, v_); BOOST_WARN_CLOSE(autodiff_v.derivative(0u), anchor_v, 1e4 * test_constants::pct_epsilon()); } catch (const std::overflow_error &) { BOOST_CHECK_THROW(((boost::math::sph_neumann>( i_, make_fvar(v_)))), boost::wrapexcept); BOOST_CHECK_THROW(((boost::math::sph_neumann(i_, v_))), boost::wrapexcept); } catch (...) { std::cout << "Inputs: i: " << i_ << " v: " << v_ << std::endl; std::rethrow_exception(std::current_exception()); } } try { auto autodiff_v = boost::math::cyl_bessel_i_prime(make_fvar(v), make_fvar(x)); auto anchor_v = boost::math::cyl_bessel_i_prime(v, x); BOOST_WARN_CLOSE(autodiff_v.derivative(0u), anchor_v, 1e4 * test_constants::pct_epsilon()); } catch (const std::overflow_error &) { BOOST_CHECK_THROW(boost::math::cyl_bessel_i_prime((make_fvar)(v), (make_fvar)(x)), boost::wrapexcept); BOOST_CHECK_THROW(boost::math::cyl_bessel_i_prime(v, x), boost::wrapexcept); } catch (...) { std::cout << "Inputs: v: " << v << " x: " << x << std::endl; std::rethrow_exception(std::current_exception()); } { auto x_j = fabs(x) + 1; try { auto autodiff_v = boost::math::cyl_bessel_j_prime( make_fvar(v), make_fvar(x_j)); auto anchor_v = boost::math::cyl_bessel_j_prime(v, x_j); BOOST_WARN_CLOSE(autodiff_v.derivative(0u), anchor_v, 1e4 * test_constants::pct_epsilon()); } catch (const std::overflow_error &) { BOOST_CHECK_THROW(boost::math::cyl_bessel_j_prime( (make_fvar)(v), (make_fvar)(x_j)), boost::wrapexcept); BOOST_CHECK_THROW(boost::math::cyl_bessel_j_prime(v, x_j), boost::wrapexcept); } catch (...) { std::cout << "Inputs: v: " << v << " x_k: " << x_j << std::endl; std::rethrow_exception(std::current_exception()); } } { auto x_k = fabs(x) + 1; try { auto autodiff_v = boost::math::cyl_bessel_k_prime( make_fvar(v), make_fvar(x_k)); auto anchor_v = boost::math::cyl_bessel_k_prime(v, x_k); BOOST_WARN_CLOSE(autodiff_v.derivative(0u), anchor_v, 1e4 * test_constants::pct_epsilon()); } catch (const std::overflow_error &) { BOOST_CHECK_THROW(boost::math::cyl_bessel_k_prime( (make_fvar)(v), (make_fvar)(x_k)), boost::wrapexcept); BOOST_CHECK_THROW(boost::math::cyl_bessel_k_prime(v, x_k), boost::wrapexcept); } catch (...) { std::cout << "Inputs: v: " << v << " x: " << x_k << std::endl; std::rethrow_exception(std::current_exception()); } } { auto x_neumann = fabs(x) + 1; try { auto autodiff_v = boost::math::cyl_neumann_prime( make_fvar(v), make_fvar(x_neumann)); auto anchor_v = boost::math::cyl_neumann_prime(v, x_neumann); BOOST_WARN_CLOSE(autodiff_v.derivative(0u), anchor_v, 1e4 * test_constants::pct_epsilon()); } catch (const std::overflow_error &) { BOOST_CHECK_THROW( boost::math::cyl_neumann_prime((make_fvar)(v), (make_fvar)(x_neumann)), boost::wrapexcept); BOOST_CHECK_THROW(boost::math::cyl_neumann_prime(v, x_neumann), boost::wrapexcept); } catch (...) { std::cout << "Inputs: v: " << v << " x: " << x_neumann << std::endl; std::rethrow_exception(std::current_exception()); } } try { auto autodiff_v = boost::math::sph_bessel_prime>( i_, make_fvar(fabs(v) + 1)); auto anchor_v = boost::math::sph_bessel_prime(i_, fabs(v) + 1); BOOST_WARN_CLOSE(autodiff_v.derivative(0u), anchor_v, 1e4 * test_constants::pct_epsilon()); } catch (const std::overflow_error &) { BOOST_CHECK_THROW( (boost::math::sph_neumann< autodiff_fvar>)(i_, (make_fvar)(fabs(v) + 1)), boost::wrapexcept); BOOST_CHECK_THROW((boost::math::sph_neumann)(i_, fabs(v) + 1), boost::wrapexcept); } catch (...) { std::cout << "Inputs: i: " << i_ << " v: " << (fabs(v) + 1) << std::endl; std::rethrow_exception(std::current_exception()); } try { auto autodiff_v = boost::math::sph_neumann_prime>( i_, make_fvar(fabs(v) + 1)); auto anchor_v = boost::math::sph_neumann_prime(i_, fabs(v) + 1); BOOST_WARN_CLOSE(autodiff_v.derivative(0u), anchor_v, 1e4 * test_constants::pct_epsilon()); } catch (const std::overflow_error &) { BOOST_CHECK_THROW( (boost::math::sph_neumann_prime< autodiff_fvar>)(i_, (make_fvar)(fabs(v) + 1)), boost::wrapexcept); BOOST_CHECK_THROW((boost::math::sph_neumann_prime)(i_, fabs(v) + 1), boost::wrapexcept); } catch (...) { std::cout << "Inputs: i: " << i << " v: " << (fabs(v) + 1) << std::endl; std::rethrow_exception(std::current_exception()); } } } } BOOST_AUTO_TEST_SUITE_END()