File indexing completed on 2025-01-18 09:40:05
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #ifndef BOOST_HYPERGEOMETRIC_1F1_RECURRENCE_HPP_
0012 #define BOOST_HYPERGEOMETRIC_1F1_RECURRENCE_HPP_
0013
0014 #include <boost/math/special_functions/modf.hpp>
0015 #include <boost/math/special_functions/next.hpp>
0016
0017 #include <boost/math/tools/recurrence.hpp>
0018 #include <boost/math/special_functions/detail/hypergeometric_pFq_checked_series.hpp>
0019
0020 namespace boost { namespace math { namespace detail {
0021
0022
0023 template <class T, class Policy>
0024 inline T hypergeometric_1F1_imp(const T& a, const T& b, const T& z, const Policy& pol);
0025
0026 template <class T, class Policy>
0027 inline T hypergeometric_1F1_imp(const T& a, const T& b, const T& z, const Policy& pol, long long& log_scaling);
0028
0029 template <class T>
0030 struct hypergeometric_1F1_recurrence_a_coefficients
0031 {
0032 using result_type = boost::math::tuple<T, T, T>;
0033
0034 hypergeometric_1F1_recurrence_a_coefficients(const T& a, const T& b, const T& z):
0035 a(a), b(b), z(z)
0036 {
0037 }
0038
0039 hypergeometric_1F1_recurrence_a_coefficients(const hypergeometric_1F1_recurrence_a_coefficients&) = default;
0040
0041 hypergeometric_1F1_recurrence_a_coefficients operator=(const hypergeometric_1F1_recurrence_a_coefficients&) = delete;
0042
0043 result_type operator()(std::intmax_t i) const
0044 {
0045 const T ai = a + i;
0046
0047 const T an = b - ai;
0048 const T bn = (2 * ai - b + z);
0049 const T cn = -ai;
0050
0051 return boost::math::make_tuple(an, bn, cn);
0052 }
0053
0054 private:
0055 const T a;
0056 const T b;
0057 const T z;
0058 };
0059
0060 template <class T>
0061 struct hypergeometric_1F1_recurrence_b_coefficients
0062 {
0063 using result_type = boost::math::tuple<T, T, T>;
0064
0065 hypergeometric_1F1_recurrence_b_coefficients(const T& a, const T& b, const T& z):
0066 a(a), b(b), z(z)
0067 {
0068 }
0069
0070 hypergeometric_1F1_recurrence_b_coefficients(const hypergeometric_1F1_recurrence_b_coefficients&) = default;
0071
0072 hypergeometric_1F1_recurrence_b_coefficients& operator=(const hypergeometric_1F1_recurrence_b_coefficients&) = delete;
0073
0074 result_type operator()(std::intmax_t i) const
0075 {
0076 const T bi = b + i;
0077
0078 const T an = bi * (bi - 1);
0079 const T bn = bi * (1 - bi - z);
0080 const T cn = z * (bi - a);
0081
0082 return boost::math::make_tuple(an, bn, cn);
0083 }
0084
0085 private:
0086 const T a;
0087 const T b;
0088 const T z;
0089 };
0090
0091
0092
0093 template <class T>
0094 struct hypergeometric_1F1_recurrence_small_b_coefficients
0095 {
0096 using result_type = boost::math::tuple<T, T, T>;
0097
0098 hypergeometric_1F1_recurrence_small_b_coefficients(const T& a, const T& b, const T& z, int N) :
0099 a(a), b(b), z(z), N(N)
0100 {
0101 }
0102
0103 hypergeometric_1F1_recurrence_small_b_coefficients(const hypergeometric_1F1_recurrence_small_b_coefficients&) = default;
0104
0105 hypergeometric_1F1_recurrence_small_b_coefficients operator=(const hypergeometric_1F1_recurrence_small_b_coefficients&) = delete;
0106
0107 result_type operator()(std::intmax_t i) const
0108 {
0109 const T bi = b + (i + N);
0110 const T bi_minus_1 = b + (i + N - 1);
0111
0112 const T an = bi * bi_minus_1;
0113 const T bn = bi * (-bi_minus_1 - z);
0114 const T cn = z * (bi - a);
0115
0116 return boost::math::make_tuple(an, bn, cn);
0117 }
0118
0119 private:
0120 const T a;
0121 const T b;
0122 const T z;
0123 int N;
0124 };
0125
0126 template <class T>
0127 struct hypergeometric_1F1_recurrence_a_and_b_coefficients
0128 {
0129 using result_type = boost::math::tuple<T, T, T>;
0130
0131 hypergeometric_1F1_recurrence_a_and_b_coefficients(const T& a, const T& b, const T& z, int offset = 0):
0132 a(a), b(b), z(z), offset(offset)
0133 {
0134 }
0135
0136 hypergeometric_1F1_recurrence_a_and_b_coefficients(const hypergeometric_1F1_recurrence_a_and_b_coefficients&) = default;
0137
0138 hypergeometric_1F1_recurrence_a_and_b_coefficients operator=(const hypergeometric_1F1_recurrence_a_and_b_coefficients&) = delete;
0139
0140 result_type operator()(std::intmax_t i) const
0141 {
0142 const T ai = a + (offset + i);
0143 const T bi = b + (offset + i);
0144
0145 const T an = bi * (b + (offset + i - 1));
0146 const T bn = bi * (z - (b + (offset + i - 1)));
0147 const T cn = -ai * z;
0148
0149 return boost::math::make_tuple(an, bn, cn);
0150 }
0151
0152 private:
0153 const T a;
0154 const T b;
0155 const T z;
0156 int offset;
0157 };
0158 #if 0
0159
0160
0161
0162
0163
0164
0165
0166 template <class T>
0167 struct hypergeometric_1F1_recurrence_2a_and_2b_coefficients
0168 {
0169 typedef boost::math::tuple<T, T, T> result_type;
0170
0171 hypergeometric_1F1_recurrence_2a_and_2b_coefficients(const T& a, const T& b, const T& z, int offset = 0) :
0172 a(a), b(b), z(z), offset(offset)
0173 {
0174 }
0175
0176 result_type operator()(std::intmax_t i) const
0177 {
0178 i *= 2;
0179 const T ai = a + (offset + i);
0180 const T bi = b + (offset + i);
0181
0182 const T an = -bi * (b + (offset + i - 1)) * (b + (offset + i - 2)) / (-(b + (offset + i - 2)) + z);
0183 const T bn = bi * (a + (offset + i - 1)) * z / (z - (b + (offset + i - 2)))
0184 + bi * (z - (b + (offset + i - 1)))
0185 + ai * bi * z * (b + (offset + i + 1)) / ((b + (offset + i + 1)) * (z - bi));
0186 const T cn = -ai * (a + (offset + i + 1)) * z * z / ((b + (offset + i + 1)) * (z - bi));
0187
0188 return boost::math::make_tuple(an, bn, cn);
0189 }
0190
0191 private:
0192 const T a, b, z;
0193 int offset;
0194 hypergeometric_1F1_recurrence_2a_and_2b_coefficients operator=(const hypergeometric_1F1_recurrence_2a_and_2b_coefficients&);
0195 };
0196
0197
0198
0199
0200
0201 template <class T>
0202 struct hypergeometric_1F1_recurrence_2a_coefficients
0203 {
0204 typedef boost::math::tuple<T, T, T> result_type;
0205
0206 hypergeometric_1F1_recurrence_2a_coefficients(const T& a, const T& b, const T& z, int offset = 0) :
0207 a(a), b(b), z(z), offset(offset)
0208 {
0209 }
0210
0211 result_type operator()(std::intmax_t i) const
0212 {
0213 i *= 2;
0214 const T ai = a + (offset + i);
0215
0216 const T an = -(b - ai) * (b - (a + (offset + i - 1))) / (2 * (a + (offset + i - 1)) - b + z);
0217 const T bn = (b - ai) * (a + (offset + i - 1)) / (2 * (a + (offset + i - 1)) - b + z) + (2 * ai - b + z) + ai * (b - (a + (offset + i + 1))) / (2 * (a + (offset + i + 1)) - b + z);
0218 const T cn = -ai * (a + (offset + i + 1)) / (2 * (a + (offset + i + 1)) - b + z);
0219
0220 return boost::math::make_tuple(an, bn, cn);
0221 }
0222
0223 private:
0224 const T a, b, z;
0225 int offset;
0226 hypergeometric_1F1_recurrence_2a_coefficients operator=(const hypergeometric_1F1_recurrence_2a_coefficients&);
0227 };
0228
0229
0230
0231
0232
0233 template <class T>
0234 struct hypergeometric_1F1_recurrence_2b_coefficients
0235 {
0236 typedef boost::math::tuple<T, T, T> result_type;
0237
0238 hypergeometric_1F1_recurrence_2b_coefficients(const T& a, const T& b, const T& z, int offset = 0) :
0239 a(a), b(b), z(z), offset(offset)
0240 {
0241 }
0242
0243 result_type operator()(std::intmax_t i) const
0244 {
0245 i *= 2;
0246 const T bi = b + (offset + i);
0247 const T bi_m1 = b + (offset + i - 1);
0248 const T bi_p1 = b + (offset + i + 1);
0249 const T bi_m2 = b + (offset + i - 2);
0250
0251 const T an = bi * (bi_m1) * (bi_m1) * (bi_m2) / (-bi_m1 * (-bi_m2 - z));
0252 const T bn = z * bi * bi_m1 * (bi_m1 - a) / (-bi_m1 * (-bi_m2 - z)) + bi * (-bi_m1 - z) + z * (bi - a) * bi_p1 * bi / (bi_p1 * (bi + z));
0253 const T cn = z * z * (bi - a) * (bi_p1 - a) / (bi_p1 * (bi + z));
0254
0255 return boost::math::make_tuple(an, bn, cn);
0256 }
0257
0258 private:
0259 const T a, b, z;
0260 int offset;
0261 hypergeometric_1F1_recurrence_2b_coefficients operator=(const hypergeometric_1F1_recurrence_2b_coefficients&);
0262 };
0263
0264
0265
0266
0267
0268
0269
0270 template <class T>
0271 struct hypergeometric_1F1_recurrence_a_plus_b_minus_coefficients
0272 {
0273 typedef boost::math::tuple<T, T, T> result_type;
0274
0275 hypergeometric_1F1_recurrence_a_plus_b_minus_coefficients(const T& a, const T& b, const T& z, int offset = 0) :
0276 a(a), b(b), z(z), offset(offset)
0277 {
0278 }
0279
0280 result_type operator()(std::intmax_t i) const
0281 {
0282 const T ai = a + (offset + i);
0283 const T bi = b - (offset + i);
0284
0285 const T an = -z * (bi - ai) * (ai - 1 - bi) / (bi * (ai - 1 + z));
0286 const T bn = z * ((-1 / (ai + z) - 1 / (ai + z - 1)) * (bi + z - 1) + 3) + bi - 1;
0287 const T cn = ai * (1 - bi) / (ai + z);
0288
0289 return boost::math::make_tuple(an, bn, cn);
0290 }
0291
0292 private:
0293 const T a, b, z;
0294 int offset;
0295 hypergeometric_1F1_recurrence_a_plus_b_minus_coefficients operator=(const hypergeometric_1F1_recurrence_a_plus_b_minus_coefficients&);
0296 };
0297 #endif
0298
0299 template <class T, class Policy>
0300 inline T hypergeometric_1F1_backward_recurrence_for_negative_a(const T& a, const T& b, const T& z, const Policy& pol, const char* function, long long& log_scaling)
0301 {
0302 BOOST_MATH_STD_USING
0303
0304 std::intmax_t integer_part = 0;
0305 T ak = modf(a, &integer_part);
0306
0307
0308
0309 if (0 != ak)
0310 {
0311 ak += 2;
0312 integer_part -= 2;
0313 }
0314 if (ak - 1 == b)
0315 {
0316
0317
0318
0319 ak -= 1;
0320 integer_part += 1;
0321 }
0322
0323 if (-integer_part > static_cast<std::intmax_t>(policies::get_max_series_iterations<Policy>()))
0324 return policies::raise_evaluation_error<T>(function, "1F1 arguments sit in a range with a so negative that we have no evaluation method, got a = %1%", std::numeric_limits<T>::quiet_NaN(), pol);
0325
0326 T first {};
0327 T second {};
0328 if(ak == 0)
0329 {
0330 first = 1;
0331 ak -= 1;
0332 second = 1 - z / b;
0333 if (fabs(second) < 0.5)
0334 second = (b - z) / b;
0335 }
0336 else
0337 {
0338 long long scaling1 {};
0339 long long scaling2 {};
0340 first = detail::hypergeometric_1F1_imp(ak, b, z, pol, scaling1);
0341 ak -= 1;
0342 second = detail::hypergeometric_1F1_imp(ak, b, z, pol, scaling2);
0343 if (scaling1 != scaling2)
0344 {
0345 second *= exp(T(scaling2 - scaling1));
0346 }
0347 log_scaling += scaling1;
0348 }
0349 ++integer_part;
0350
0351 detail::hypergeometric_1F1_recurrence_a_coefficients<T> s(ak, b, z);
0352
0353 return tools::apply_recurrence_relation_backward(s,
0354 static_cast<unsigned int>(std::abs(integer_part)),
0355 first,
0356 second, &log_scaling);
0357 }
0358
0359
0360 template <class T, class Policy>
0361 T hypergeometric_1F1_backwards_recursion_on_b_for_negative_a(const T& a, const T& b, const T& z, const Policy& pol, const char*, long long& log_scaling)
0362 {
0363 using std::swap;
0364 BOOST_MATH_STD_USING
0365
0366
0367
0368
0369
0370
0371
0372
0373
0374
0375
0376
0377
0378
0379
0380
0381
0382
0383
0384
0385
0386 BOOST_MATH_ASSERT(a < -1);
0387
0388 int b_shift = itrunc(z - b) + 2;
0389
0390 int a_shift = itrunc(-a);
0391 if (a + a_shift != 0)
0392 {
0393 a_shift += 2;
0394 }
0395
0396
0397
0398
0399 if (b_shift > static_cast<std::intmax_t>(boost::math::policies::get_max_series_iterations<Policy>()))
0400 return hypergeometric_1F1_checked_series_impl(a, b, z, pol, log_scaling);
0401
0402 if (a_shift > static_cast<std::intmax_t>(boost::math::policies::get_max_series_iterations<Policy>()))
0403 return hypergeometric_1F1_checked_series_impl(a, b, z, pol, log_scaling);
0404
0405 int a_b_shift = b < 0 ? itrunc(b + b_shift) : b_shift;
0406 int leading_a_shift = (std::min)(3, a_shift);
0407 if (a_b_shift > a_shift - 3)
0408 {
0409 a_b_shift = a_shift < 3 ? 0 : a_shift - 3;
0410 }
0411 else
0412 {
0413
0414
0415 leading_a_shift = a_shift - a_b_shift;
0416 }
0417 int trailing_b_shift = b_shift - a_b_shift;
0418 if (a_b_shift < 5)
0419 {
0420
0421 if (a_b_shift > 0)
0422 {
0423 leading_a_shift += a_b_shift;
0424 trailing_b_shift += a_b_shift;
0425 }
0426 a_b_shift = 0;
0427 --leading_a_shift;
0428 }
0429
0430 BOOST_MATH_ASSERT(leading_a_shift > 1);
0431 BOOST_MATH_ASSERT(a_b_shift + leading_a_shift + (a_b_shift == 0 ? 1 : 0) == a_shift);
0432 BOOST_MATH_ASSERT(a_b_shift + trailing_b_shift == b_shift);
0433
0434 if ((trailing_b_shift == 0) && (fabs(b) < 0.5) && a_b_shift)
0435 {
0436
0437 int diff = (std::min)(a_b_shift, 3);
0438 a_b_shift -= diff;
0439 leading_a_shift += diff;
0440 trailing_b_shift += diff;
0441 }
0442
0443 T first {};
0444 T second {};
0445 long long scale1 {};
0446 long long scale2 {};
0447 first = boost::math::detail::hypergeometric_1F1_imp(T(a + a_shift), T(b + b_shift), z, pol, scale1);
0448
0449
0450
0451
0452 second = boost::math::detail::hypergeometric_1F1_imp(T(a + a_shift - 1), T(b + b_shift), z, pol, scale2);
0453 if (scale1 != scale2)
0454 second *= exp(T(scale2 - scale1));
0455 log_scaling += scale1;
0456
0457
0458
0459
0460
0461
0462 second = boost::math::tools::apply_recurrence_relation_backward(
0463 hypergeometric_1F1_recurrence_a_coefficients<T>(a + a_shift - 1, b + b_shift, z),
0464 leading_a_shift, first, second, &log_scaling, &first);
0465
0466 if (a_b_shift)
0467 {
0468
0469
0470
0471
0472
0473 {
0474
0475 T la = a + a_shift - leading_a_shift - 1;
0476 T lb = b + b_shift;
0477 second = ((1 + la - lb) * second - la * first) / (1 - lb);
0478 }
0479
0480
0481
0482
0483 second = boost::math::tools::apply_recurrence_relation_backward(
0484 hypergeometric_1F1_recurrence_a_and_b_coefficients<T>(a, b + b_shift - a_b_shift, z, a_b_shift - 1),
0485 a_b_shift - 1, first, second, &log_scaling, &first);
0486
0487
0488
0489
0490 {
0491 T lb = b + trailing_b_shift + 1;
0492 first = (second * (lb - 1) - a * first) / -(1 + a - lb);
0493 }
0494 }
0495 else
0496 {
0497
0498
0499
0500
0501 T third = -(second * (1 + a - b - b_shift) - first * a) / (b + b_shift - 1);
0502 swap(first, second);
0503 swap(second, third);
0504 --trailing_b_shift;
0505 }
0506
0507
0508
0509 if (trailing_b_shift)
0510 {
0511 second = boost::math::tools::apply_recurrence_relation_backward(
0512 hypergeometric_1F1_recurrence_small_b_coefficients<T>(a, b, z, trailing_b_shift),
0513 trailing_b_shift, first, second, &log_scaling);
0514 }
0515 return second;
0516 }
0517
0518
0519
0520 } } }
0521
0522 #endif