File indexing completed on 2025-01-18 09:40:15
0001
0002
0003
0004
0005
0006
0007
0008 #ifndef BOOST_MATH_HYPERGEOMETRIC_PFQ_HPP
0009 #define BOOST_MATH_HYPERGEOMETRIC_PFQ_HPP
0010
0011 #include <boost/math/special_functions/detail/hypergeometric_pFq_checked_series.hpp>
0012 #include <boost/math/tools/throw_exception.hpp>
0013 #include <chrono>
0014 #include <initializer_list>
0015
0016 namespace boost {
0017 namespace math {
0018
0019 namespace detail {
0020
0021 struct pFq_termination_exception : public std::runtime_error
0022 {
0023 pFq_termination_exception(const char* p) : std::runtime_error(p) {}
0024 };
0025
0026 struct timed_iteration_terminator
0027 {
0028 timed_iteration_terminator(std::uintmax_t i, double t) : max_iter(i), max_time(t), start_time(std::chrono::system_clock::now()) {}
0029
0030 bool operator()(std::uintmax_t iter)const
0031 {
0032 if (iter > max_iter)
0033 BOOST_MATH_THROW_EXCEPTION(boost::math::detail::pFq_termination_exception("pFq exceeded maximum permitted iterations."));
0034 if (std::chrono::duration<double>(std::chrono::system_clock::now() - start_time).count() > max_time)
0035 BOOST_MATH_THROW_EXCEPTION(boost::math::detail::pFq_termination_exception("pFq exceeded maximum permitted evaluation time."));
0036 return false;
0037 }
0038
0039 std::uintmax_t max_iter;
0040 double max_time;
0041 std::chrono::system_clock::time_point start_time;
0042 };
0043
0044 }
0045
0046 template <class Seq, class Real, class Policy>
0047 inline typename tools::promote_args<Real, typename Seq::value_type>::type hypergeometric_pFq(const Seq& aj, const Seq& bj, const Real& z, Real* p_abs_error, const Policy& pol)
0048 {
0049 typedef typename tools::promote_args<Real, typename Seq::value_type>::type result_type;
0050 typedef typename policies::evaluation<result_type, Policy>::type value_type;
0051 typedef typename policies::normalise<
0052 Policy,
0053 policies::promote_float<false>,
0054 policies::promote_double<false>,
0055 policies::discrete_quantile<>,
0056 policies::assert_undefined<> >::type forwarding_policy;
0057
0058 BOOST_MATH_STD_USING
0059
0060 long long scale = 0;
0061 std::pair<value_type, value_type> r = boost::math::detail::hypergeometric_pFq_checked_series_impl(aj, bj, value_type(z), pol, boost::math::detail::iteration_terminator(boost::math::policies::get_max_series_iterations<forwarding_policy>()), scale);
0062 r.first *= exp(Real(scale));
0063 r.second *= exp(Real(scale));
0064 if (p_abs_error)
0065 *p_abs_error = static_cast<Real>(r.second) * boost::math::tools::epsilon<Real>();
0066 return policies::checked_narrowing_cast<result_type, Policy>(r.first, "boost::math::hypergeometric_pFq<%1%>(%1%,%1%,%1%)");
0067 }
0068
0069 template <class Seq, class Real>
0070 inline typename tools::promote_args<Real, typename Seq::value_type>::type hypergeometric_pFq(const Seq& aj, const Seq& bj, const Real& z, Real* p_abs_error = 0)
0071 {
0072 return hypergeometric_pFq(aj, bj, z, p_abs_error, boost::math::policies::policy<>());
0073 }
0074
0075 template <class R, class Real, class Policy>
0076 inline typename tools::promote_args<Real, R>::type hypergeometric_pFq(const std::initializer_list<R>& aj, const std::initializer_list<R>& bj, const Real& z, Real* p_abs_error, const Policy& pol)
0077 {
0078 return hypergeometric_pFq<std::initializer_list<R>, Real, Policy>(aj, bj, z, p_abs_error, pol);
0079 }
0080
0081 template <class R, class Real>
0082 inline typename tools::promote_args<Real, R>::type hypergeometric_pFq(const std::initializer_list<R>& aj, const std::initializer_list<R>& bj, const Real& z, Real* p_abs_error = nullptr)
0083 {
0084 return hypergeometric_pFq<std::initializer_list<R>, Real>(aj, bj, z, p_abs_error);
0085 }
0086
0087 #ifndef BOOST_NO_EXCEPTIONS
0088 template <class T>
0089 struct scoped_precision
0090 {
0091 scoped_precision(unsigned p)
0092 {
0093 old_p = T::default_precision();
0094 T::default_precision(p);
0095 }
0096 ~scoped_precision()
0097 {
0098 T::default_precision(old_p);
0099 }
0100 unsigned old_p;
0101 };
0102
0103 template <class Seq, class Real, class Policy>
0104 Real hypergeometric_pFq_precision(const Seq& aj, const Seq& bj, Real z, unsigned digits10, double timeout, const Policy& pol)
0105 {
0106 unsigned current_precision = digits10 + 5;
0107
0108 for (auto ai = aj.begin(); ai != aj.end(); ++ai)
0109 {
0110 current_precision = (std::max)(current_precision, ai->precision());
0111 }
0112 for (auto bi = bj.begin(); bi != bj.end(); ++bi)
0113 {
0114 current_precision = (std::max)(current_precision, bi->precision());
0115 }
0116 current_precision = (std::max)(current_precision, z.precision());
0117
0118 Real r, norm;
0119 std::vector<Real> aa(aj), bb(bj);
0120 do
0121 {
0122 scoped_precision<Real> p(current_precision);
0123 for (auto ai = aa.begin(); ai != aa.end(); ++ai)
0124 ai->precision(current_precision);
0125 for (auto bi = bb.begin(); bi != bb.end(); ++bi)
0126 bi->precision(current_precision);
0127 z.precision(current_precision);
0128 try
0129 {
0130 long long scale = 0;
0131 std::pair<Real, Real> rp = boost::math::detail::hypergeometric_pFq_checked_series_impl(aa, bb, z, pol, boost::math::detail::timed_iteration_terminator(boost::math::policies::get_max_series_iterations<Policy>(), timeout), scale);
0132 rp.first *= exp(Real(scale));
0133 rp.second *= exp(Real(scale));
0134
0135 r = rp.first;
0136 norm = rp.second;
0137
0138 unsigned cancellation;
0139 try {
0140 cancellation = itrunc(log10(abs(norm / r)));
0141 }
0142 catch (const boost::math::rounding_error&)
0143 {
0144
0145 cancellation = UINT_MAX;
0146 }
0147 if (cancellation >= current_precision - 1)
0148 {
0149 current_precision *= 2;
0150 continue;
0151 }
0152 unsigned precision_obtained = current_precision - 1 - cancellation;
0153 if (precision_obtained < digits10)
0154 {
0155 current_precision += digits10 - precision_obtained + 5;
0156 }
0157 else
0158 break;
0159 }
0160 catch (const boost::math::evaluation_error&)
0161 {
0162 current_precision *= 2;
0163 }
0164 catch (const detail::pFq_termination_exception& e)
0165 {
0166
0167
0168
0169 throw boost::math::evaluation_error(e.what());
0170 }
0171 } while (true);
0172
0173 return r;
0174 }
0175 template <class Seq, class Real>
0176 Real hypergeometric_pFq_precision(const Seq& aj, const Seq& bj, const Real& z, unsigned digits10, double timeout = 0.5)
0177 {
0178 return hypergeometric_pFq_precision(aj, bj, z, digits10, timeout, boost::math::policies::policy<>());
0179 }
0180
0181 template <class Real, class Policy>
0182 Real hypergeometric_pFq_precision(const std::initializer_list<Real>& aj, const std::initializer_list<Real>& bj, const Real& z, unsigned digits10, double timeout, const Policy& pol)
0183 {
0184 return hypergeometric_pFq_precision< std::initializer_list<Real>, Real>(aj, bj, z, digits10, timeout, pol);
0185 }
0186 template <class Real>
0187 Real hypergeometric_pFq_precision(const std::initializer_list<Real>& aj, const std::initializer_list<Real>& bj, const Real& z, unsigned digits10, double timeout = 0.5)
0188 {
0189 return hypergeometric_pFq_precision< std::initializer_list<Real>, Real>(aj, bj, z, digits10, timeout, boost::math::policies::policy<>());
0190 }
0191 #endif
0192 }
0193 }
0194
0195 #endif