123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492 |
- #ifndef BOOST_HYPERGEOMETRIC_1F1_LARGE_ABZ_HPP_
- #define BOOST_HYPERGEOMETRIC_1F1_LARGE_ABZ_HPP_
- #include <boost/math/special_functions/detail/hypergeometric_1F1_bessel.hpp>
- #include <boost/math/special_functions/detail/hypergeometric_series.hpp>
- #include <boost/math/special_functions/gamma.hpp>
- #include <boost/math/special_functions/trunc.hpp>
- namespace boost { namespace math { namespace detail {
- template <class T>
- inline bool is_negative_integer(const T& x)
- {
- using std::floor;
- return (x <= 0) && (floor(x) == x);
- }
- template <class T, class Policy>
- struct hypergeometric_1F1_igamma_series
- {
- enum{ cache_size = 64 };
- typedef T result_type;
- hypergeometric_1F1_igamma_series(const T& alpha, const T& delta, const T& x, const Policy& pol)
- : delta_poch(-delta), alpha_poch(alpha), x(x), k(0), cache_offset(0), pol(pol)
- {
- BOOST_MATH_STD_USING
- T log_term = log(x) * -alpha;
- log_scaling = lltrunc(log_term - 3 - boost::math::tools::log_min_value<T>() / 50);
- term = exp(log_term - log_scaling);
- refill_cache();
- }
- T operator()()
- {
- if (k - cache_offset >= cache_size)
- {
- cache_offset += cache_size;
- refill_cache();
- }
- T result = term * gamma_cache[k - cache_offset];
- term *= delta_poch * alpha_poch / (++k * x);
- delta_poch += 1;
- alpha_poch += 1;
- return result;
- }
- void refill_cache()
- {
- typedef typename lanczos::lanczos<T, Policy>::type lanczos_type;
- gamma_cache[cache_size - 1] = boost::math::gamma_p(alpha_poch + ((int)cache_size - 1), x, pol);
- for (int i = cache_size - 1; i > 0; --i)
- {
- gamma_cache[i - 1] = gamma_cache[i] >= 1 ? T(1) : T(gamma_cache[i] + regularised_gamma_prefix(T(alpha_poch + (i - 1)), x, pol, lanczos_type()) / (alpha_poch + (i - 1)));
- }
- }
- T delta_poch, alpha_poch, x, term;
- T gamma_cache[cache_size];
- int k;
- long long log_scaling;
- int cache_offset;
- Policy pol;
- };
- template <class T, class Policy>
- T hypergeometric_1F1_igamma(const T& a, const T& b, const T& x, const T& b_minus_a, const Policy& pol, long long& log_scaling)
- {
- BOOST_MATH_STD_USING
- if (b_minus_a == 0)
- {
-
- long long scale = lltrunc(x, pol);
- log_scaling += scale;
- return exp(x - scale);
- }
- hypergeometric_1F1_igamma_series<T, Policy> s(b_minus_a, a - 1, x, pol);
- log_scaling += s.log_scaling;
- std::uintmax_t max_iter = boost::math::policies::get_max_series_iterations<Policy>();
- T result = boost::math::tools::sum_series(s, boost::math::policies::get_epsilon<T, Policy>(), max_iter);
- boost::math::policies::check_series_iterations<T>("boost::math::tgamma<%1%>(%1%,%1%)", max_iter, pol);
- T log_prefix = x + boost::math::lgamma(b, pol) - boost::math::lgamma(a, pol);
- long long scale = lltrunc(log_prefix);
- log_scaling += scale;
- return result * exp(log_prefix - scale);
- }
- template <class T, class Policy>
- T hypergeometric_1F1_shift_on_a(T h, const T& a_local, const T& b_local, const T& x, int a_shift, const Policy& pol, long long& log_scaling)
- {
- BOOST_MATH_STD_USING
- T a = a_local + a_shift;
- if (a_shift == 0)
- return h;
- else if (a_shift > 0)
- {
-
-
-
-
-
-
-
-
-
-
- T crossover_a = (b_local - x) / 2;
- int crossover_shift = itrunc(crossover_a - a_local);
- if (crossover_shift > 1)
- {
-
-
-
-
- if (crossover_shift > a_shift)
- crossover_shift = a_shift;
- crossover_a = a_local + crossover_shift;
- boost::math::detail::hypergeometric_1F1_recurrence_b_coefficients<T> b_coef(crossover_a, b_local, x);
- std::uintmax_t max_iter = boost::math::policies::get_max_series_iterations<Policy>();
- T b_ratio = boost::math::tools::function_ratio_from_backwards_recurrence(b_coef, boost::math::policies::get_epsilon<T, Policy>(), max_iter);
- boost::math::policies::check_series_iterations<T>("boost::math::hypergeometric_1F1_large_abz<%1%>(%1%,%1%,%1%)", max_iter, pol);
-
-
-
-
-
-
- T first = 1;
- T second = ((1 + crossover_a - b_local) / crossover_a) + ((b_local - 1) / crossover_a) / b_ratio;
-
-
-
- boost::math::detail::hypergeometric_1F1_recurrence_a_coefficients<T> a_coef(crossover_a, b_local, x);
- long long backwards_scale = 0;
- T comparitor = boost::math::tools::apply_recurrence_relation_backward(a_coef, crossover_shift, second, first, &backwards_scale);
- log_scaling -= backwards_scale;
- if ((h < 1) && (tools::max_value<T>() * h > comparitor))
- {
-
- long long scale = lltrunc(log(h), pol) + 1;
- h *= exp(T(-scale));
- log_scaling += scale;
- }
- comparitor /= h;
- first /= comparitor;
- second /= comparitor;
-
-
-
- if (crossover_shift < a_shift)
- {
- boost::math::detail::hypergeometric_1F1_recurrence_a_coefficients<T> a_coef_2(crossover_a + 1, b_local, x);
- h = boost::math::tools::apply_recurrence_relation_forward(a_coef_2, a_shift - crossover_shift - 1, first, second, &log_scaling);
- }
- else
- h = first;
- }
- else
- {
-
-
-
- boost::math::detail::hypergeometric_1F1_recurrence_b_coefficients<T> b_coef(a_local, b_local, x);
- std::uintmax_t max_iter = boost::math::policies::get_max_series_iterations<Policy>();
- T b_ratio = boost::math::tools::function_ratio_from_backwards_recurrence(b_coef, boost::math::policies::get_epsilon<T, Policy>(), max_iter);
- boost::math::policies::check_series_iterations<T>("boost::math::hypergeometric_1F1_large_abz<%1%>(%1%,%1%,%1%)", max_iter, pol);
-
-
-
-
-
-
- T second = ((1 + a_local - b_local) / a_local) * h + ((b_local - 1) / a_local) * h / b_ratio;
- boost::math::detail::hypergeometric_1F1_recurrence_a_coefficients<T> a_coef(a_local + 1, b_local, x);
- h = boost::math::tools::apply_recurrence_relation_forward(a_coef, --a_shift, h, second, &log_scaling);
- }
- }
- else
- {
-
-
-
-
-
-
-
-
-
-
- BOOST_MATH_ASSERT(2 * a - b_local + x > 0);
- boost::math::detail::hypergeometric_1F1_recurrence_b_coefficients<T> b_coef(a, b_local, x);
- std::uintmax_t max_iter = boost::math::policies::get_max_series_iterations<Policy>();
- T b_ratio = boost::math::tools::function_ratio_from_backwards_recurrence(b_coef, boost::math::policies::get_epsilon<T, Policy>(), max_iter);
- boost::math::policies::check_series_iterations<T>("boost::math::hypergeometric_1F1_large_abz<%1%>(%1%,%1%,%1%)", max_iter, pol);
-
-
-
-
-
-
- T first = 1;
- T second = ((1 + a - b_local) / a) + ((b_local - 1) / a) * (1 / b_ratio);
- if (a_shift == -1)
- h = h / second;
- else
- {
- boost::math::detail::hypergeometric_1F1_recurrence_a_coefficients<T> a_coef(a + 1, b_local, x);
- T comparitor = boost::math::tools::apply_recurrence_relation_forward(a_coef, -(a_shift + 1), first, second);
- if (boost::math::tools::min_value<T>() * comparitor > h)
- {
-
- long long rescale = lltrunc(log(fabs(h)));
- T scale = exp(T(-rescale));
- h *= scale;
- log_scaling += rescale;
- }
- h = h / comparitor;
- }
- }
- return h;
- }
- template <class T, class Policy>
- T hypergeometric_1F1_shift_on_b(T h, const T& a, const T& b_local, const T& x, int b_shift, const Policy& pol, long long& log_scaling)
- {
- BOOST_MATH_STD_USING
- T b = b_local + b_shift;
- if (b_shift == 0)
- return h;
- else if (b_shift > 0)
- {
-
-
-
-
- boost::math::detail::hypergeometric_1F1_recurrence_b_coefficients<T> b_coef(a, b, x);
- std::uintmax_t max_iter = boost::math::policies::get_max_series_iterations<Policy>();
- T first = 1;
- T second = 1 / boost::math::tools::function_ratio_from_backwards_recurrence(b_coef, boost::math::policies::get_epsilon<T, Policy>(), max_iter);
- boost::math::policies::check_series_iterations<T>("boost::math::hypergeometric_1F1_large_abz<%1%>(%1%,%1%,%1%)", max_iter, pol);
- if (b_shift == 1)
- h = h / second;
- else
- {
-
-
-
- boost::math::detail::hypergeometric_1F1_recurrence_b_coefficients<T> b_coef_2(a, b - 1, x);
- long long local_scale = 0;
- T comparitor = boost::math::tools::apply_recurrence_relation_backward(b_coef_2, --b_shift, first, second, &local_scale);
- log_scaling -= local_scale;
- if (boost::math::tools::min_value<T>() * comparitor > h)
- {
-
- long long rescale = lltrunc(log(fabs(h)));
- T scale = exp(T(-rescale));
- h *= scale;
- log_scaling += rescale;
- }
- h = h / comparitor;
- }
- }
- else
- {
- T second;
- if (a == b_local)
- {
-
- second = -b_local * (1 - b_local - x) * h / (b_local * (b_local - 1));
- }
- else
- {
- BOOST_MATH_ASSERT(!is_negative_integer(b - a));
- boost::math::detail::hypergeometric_1F1_recurrence_b_coefficients<T> b_coef(a, b_local, x);
- std::uintmax_t max_iter = boost::math::policies::get_max_series_iterations<Policy>();
- second = h / boost::math::tools::function_ratio_from_backwards_recurrence(b_coef, boost::math::policies::get_epsilon<T, Policy>(), max_iter);
- boost::math::policies::check_series_iterations<T>("boost::math::hypergeometric_1F1_large_abz<%1%>(%1%,%1%,%1%)", max_iter, pol);
- }
- if (b_shift == -1)
- h = second;
- else
- {
- boost::math::detail::hypergeometric_1F1_recurrence_b_coefficients<T> b_coef_2(a, b_local - 1, x);
- h = boost::math::tools::apply_recurrence_relation_backward(b_coef_2, -(++b_shift), h, second, &log_scaling);
- }
- }
- return h;
- }
- template <class T, class Policy>
- T hypergeometric_1F1_large_igamma(const T& a, const T& b, const T& x, const T& b_minus_a, const Policy& pol, long long& log_scaling)
- {
- BOOST_MATH_STD_USING
-
-
-
-
-
- int b_shift = b * 2 < x ? 0 : itrunc(b - x / 2);
- int a_shift = a > b - b_shift ? -itrunc(b - b_shift - a - 1) : -itrunc(b - b_shift - a);
- if (a_shift < 0)
- {
-
- b_shift -= a_shift;
- a_shift = 0;
- }
- T a_local = a - a_shift;
- T b_local = b - b_shift;
- T b_minus_a_local = (a_shift == 0) && (b_shift == 0) ? b_minus_a : b_local - a_local;
- long long local_scaling = 0;
- T h = hypergeometric_1F1_igamma(a_local, b_local, x, b_minus_a_local, pol, local_scaling);
- log_scaling += local_scaling;
-
-
-
- h = hypergeometric_1F1_shift_on_a(h, a_local, b_local, x, a_shift, pol, log_scaling);
- h = hypergeometric_1F1_shift_on_b(h, a, b_local, x, b_shift, pol, log_scaling);
- return h;
- }
- template <class T, class Policy>
- T hypergeometric_1F1_large_series(const T& a, const T& b, const T& z, const Policy& pol, long long& log_scaling)
- {
- BOOST_MATH_STD_USING
-
-
-
- int a_shift(0), b_shift(0);
- if (a * z > b)
- {
- a_shift = itrunc(a) - 5;
- b_shift = b < z ? itrunc(b - z - 1) : 0;
- }
-
-
-
-
- if (a_shift < 5)
- a_shift = 0;
- T a_local = a - a_shift;
- T b_local = b - b_shift;
- T h = boost::math::detail::hypergeometric_1F1_generic_series(a_local, b_local, z, pol, log_scaling, "hypergeometric_1F1_large_series<%1%>(a,b,z)");
-
-
-
- if (a_shift && (a_local == 0))
- {
-
-
-
-
-
- long long scale = 0;
- T h2 = boost::math::detail::hypergeometric_1F1_generic_series(T(a_local + 1), b_local, z, pol, scale, "hypergeometric_1F1_large_series<%1%>(a,b,z)");
- if (scale != log_scaling)
- {
- h2 *= exp(T(scale - log_scaling));
- }
- boost::math::detail::hypergeometric_1F1_recurrence_a_coefficients<T> coef(a_local + 1, b_local, z);
- h = boost::math::tools::apply_recurrence_relation_forward(coef, a_shift - 1, h, h2, &log_scaling);
- h = hypergeometric_1F1_shift_on_b(h, a, b_local, z, b_shift, pol, log_scaling);
- }
- else
- {
- h = hypergeometric_1F1_shift_on_a(h, a_local, b_local, z, a_shift, pol, log_scaling);
- h = hypergeometric_1F1_shift_on_b(h, a, b_local, z, b_shift, pol, log_scaling);
- }
- return h;
- }
- template <class T, class Policy>
- T hypergeometric_1F1_large_13_3_6_series(const T& a, const T& b, const T& z, const Policy& pol, long long& log_scaling)
- {
- BOOST_MATH_STD_USING
-
-
-
-
- int b_shift = itrunc(b - a);
- if ((b_shift < 0) && (b - b_shift != a))
- b_shift -= 1;
- T b_local = b - b_shift;
- if ((b_local - a - 0.5 <= 0) && (b_local != a))
- {
-
- b_shift -= 1;
- b_local += 1;
- }
- T h = boost::math::detail::hypergeometric_1F1_AS_13_3_6(a, b_local, z, T(b_local - a), pol, log_scaling);
- return hypergeometric_1F1_shift_on_b(h, a, b_local, z, b_shift, pol, log_scaling);
- }
- template <class T, class Policy>
- T hypergeometric_1F1_large_abz(const T& a, const T& b, const T& z, const Policy& pol, long long& log_scaling)
- {
- BOOST_MATH_STD_USING
-
-
-
-
-
- enum method
- {
- method_series = 0,
- method_shifted_series,
- method_gamma,
- method_bessel
- };
-
-
-
- T current_cost = (sqrt(16 * z * (3 * a + z) + 9 * b * b - 24 * b * z) - 3 * b + 4 * z) / 6;
- method current_method = method_series;
-
-
-
-
-
-
-
-
- T cost = a + ((b < z) ? T(z - b) : T(0));
- if((b > 1) && (cost < current_cost) && ((b > z) || !is_negative_integer(b-a)))
- {
- current_method = method_shifted_series;
- current_cost = cost;
- }
-
-
-
-
-
-
-
- T b_shift = fabs(b * 2 < z ? T(0) : T(b - z / 2));
- T a_shift = fabs(a > b - b_shift ? T(-(b - b_shift - a - 1)) : T(-(b - b_shift - a)));
- cost = 1000 + b_shift + a_shift;
- if((b > 1) && (cost <= current_cost))
- {
- current_method = method_gamma;
- current_cost = cost;
- }
-
-
-
-
-
-
-
-
-
-
- cost = 50 + fabs(b - a);
- if((b > 1) && (cost <= current_cost) && (z < tools::log_max_value<T>()) && (z < 11356) && (b - a != 0.5f))
- {
- current_method = method_bessel;
- current_cost = cost;
- }
- switch (current_method)
- {
- case method_series:
- return detail::hypergeometric_1F1_generic_series(a, b, z, pol, log_scaling, "hypergeometric_1f1_large_abz<%1%>(a,b,z)");
- case method_shifted_series:
- return detail::hypergeometric_1F1_large_series(a, b, z, pol, log_scaling);
- case method_gamma:
- return detail::hypergeometric_1F1_large_igamma(a, b, z, T(b - a), pol, log_scaling);
- case method_bessel:
- return detail::hypergeometric_1F1_large_13_3_6_series(a, b, z, pol, log_scaling);
- }
- return 0;
- }
- } } }
- #endif
|