hypergeometric_1F1_recurrence.hpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // Copyright 2014 Anton Bikineev
  3. // Copyright 2014 Christopher Kormanyos
  4. // Copyright 2014 John Maddock
  5. // Copyright 2014 Paul Bristow
  6. // Distributed under the Boost
  7. // Software License, Version 1.0. (See accompanying file
  8. // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  9. #ifndef BOOST_HYPERGEOMETRIC_1F1_RECURRENCE_HPP_
  10. #define BOOST_HYPERGEOMETRIC_1F1_RECURRENCE_HPP_
  11. #include <boost/math/special_functions/modf.hpp>
  12. #include <boost/math/special_functions/next.hpp>
  13. #include <boost/math/tools/recurrence.hpp>
  14. #include <boost/math/special_functions/detail/hypergeometric_pFq_checked_series.hpp>
  15. namespace boost { namespace math { namespace detail {
  16. // forward declaration for initial values
  17. template <class T, class Policy>
  18. inline T hypergeometric_1F1_imp(const T& a, const T& b, const T& z, const Policy& pol);
  19. template <class T, class Policy>
  20. inline T hypergeometric_1F1_imp(const T& a, const T& b, const T& z, const Policy& pol, long long& log_scaling);
  21. template <class T>
  22. struct hypergeometric_1F1_recurrence_a_coefficients
  23. {
  24. using result_type = boost::math::tuple<T, T, T>;
  25. hypergeometric_1F1_recurrence_a_coefficients(const T& a, const T& b, const T& z):
  26. a(a), b(b), z(z)
  27. {
  28. }
  29. hypergeometric_1F1_recurrence_a_coefficients(const hypergeometric_1F1_recurrence_a_coefficients&) = default;
  30. hypergeometric_1F1_recurrence_a_coefficients operator=(const hypergeometric_1F1_recurrence_a_coefficients&) = delete;
  31. result_type operator()(std::intmax_t i) const
  32. {
  33. const T ai = a + i;
  34. const T an = b - ai;
  35. const T bn = (2 * ai - b + z);
  36. const T cn = -ai;
  37. return boost::math::make_tuple(an, bn, cn);
  38. }
  39. private:
  40. const T a;
  41. const T b;
  42. const T z;
  43. };
  44. template <class T>
  45. struct hypergeometric_1F1_recurrence_b_coefficients
  46. {
  47. using result_type = boost::math::tuple<T, T, T>;
  48. hypergeometric_1F1_recurrence_b_coefficients(const T& a, const T& b, const T& z):
  49. a(a), b(b), z(z)
  50. {
  51. }
  52. hypergeometric_1F1_recurrence_b_coefficients(const hypergeometric_1F1_recurrence_b_coefficients&) = default;
  53. hypergeometric_1F1_recurrence_b_coefficients& operator=(const hypergeometric_1F1_recurrence_b_coefficients&) = delete;
  54. result_type operator()(std::intmax_t i) const
  55. {
  56. const T bi = b + i;
  57. const T an = bi * (bi - 1);
  58. const T bn = bi * (1 - bi - z);
  59. const T cn = z * (bi - a);
  60. return boost::math::make_tuple(an, bn, cn);
  61. }
  62. private:
  63. const T a;
  64. const T b;
  65. const T z;
  66. };
  67. //
  68. // for use when we're recursing to a small b:
  69. //
  70. template <class T>
  71. struct hypergeometric_1F1_recurrence_small_b_coefficients
  72. {
  73. using result_type = boost::math::tuple<T, T, T>;
  74. hypergeometric_1F1_recurrence_small_b_coefficients(const T& a, const T& b, const T& z, int N) :
  75. a(a), b(b), z(z), N(N)
  76. {
  77. }
  78. hypergeometric_1F1_recurrence_small_b_coefficients(const hypergeometric_1F1_recurrence_small_b_coefficients&) = default;
  79. hypergeometric_1F1_recurrence_small_b_coefficients operator=(const hypergeometric_1F1_recurrence_small_b_coefficients&) = delete;
  80. result_type operator()(std::intmax_t i) const
  81. {
  82. const T bi = b + (i + N);
  83. const T bi_minus_1 = b + (i + N - 1);
  84. const T an = bi * bi_minus_1;
  85. const T bn = bi * (-bi_minus_1 - z);
  86. const T cn = z * (bi - a);
  87. return boost::math::make_tuple(an, bn, cn);
  88. }
  89. private:
  90. const T a;
  91. const T b;
  92. const T z;
  93. int N;
  94. };
  95. template <class T>
  96. struct hypergeometric_1F1_recurrence_a_and_b_coefficients
  97. {
  98. using result_type = boost::math::tuple<T, T, T>;
  99. hypergeometric_1F1_recurrence_a_and_b_coefficients(const T& a, const T& b, const T& z, int offset = 0):
  100. a(a), b(b), z(z), offset(offset)
  101. {
  102. }
  103. hypergeometric_1F1_recurrence_a_and_b_coefficients(const hypergeometric_1F1_recurrence_a_and_b_coefficients&) = default;
  104. hypergeometric_1F1_recurrence_a_and_b_coefficients operator=(const hypergeometric_1F1_recurrence_a_and_b_coefficients&) = delete;
  105. result_type operator()(std::intmax_t i) const
  106. {
  107. const T ai = a + (offset + i);
  108. const T bi = b + (offset + i);
  109. const T an = bi * (b + (offset + i - 1));
  110. const T bn = bi * (z - (b + (offset + i - 1)));
  111. const T cn = -ai * z;
  112. return boost::math::make_tuple(an, bn, cn);
  113. }
  114. private:
  115. const T a;
  116. const T b;
  117. const T z;
  118. int offset;
  119. };
  120. #if 0
  121. //
  122. // These next few recurrence relations are archived for future reference, some of them are novel, though all
  123. // are trivially derived from the existing well known relations:
  124. //
  125. // Recurrence relation for double-stepping on both a and b:
  126. // - b(b-1)(b-2) / (2-b+z) M(a-2,b-2,z) + [b(a-1)z / (2-b+z) + b(1-b+z) + abz(b+1) /(b+1)(z-b)] M(a,b,z) - a(a+1)z^2 / (b+1)(z-b) M(a+2,b+2,z)
  127. //
  128. template <class T>
  129. struct hypergeometric_1F1_recurrence_2a_and_2b_coefficients
  130. {
  131. typedef boost::math::tuple<T, T, T> result_type;
  132. hypergeometric_1F1_recurrence_2a_and_2b_coefficients(const T& a, const T& b, const T& z, int offset = 0) :
  133. a(a), b(b), z(z), offset(offset)
  134. {
  135. }
  136. result_type operator()(std::intmax_t i) const
  137. {
  138. i *= 2;
  139. const T ai = a + (offset + i);
  140. const T bi = b + (offset + i);
  141. const T an = -bi * (b + (offset + i - 1)) * (b + (offset + i - 2)) / (-(b + (offset + i - 2)) + z);
  142. const T bn = bi * (a + (offset + i - 1)) * z / (z - (b + (offset + i - 2)))
  143. + bi * (z - (b + (offset + i - 1)))
  144. + ai * bi * z * (b + (offset + i + 1)) / ((b + (offset + i + 1)) * (z - bi));
  145. const T cn = -ai * (a + (offset + i + 1)) * z * z / ((b + (offset + i + 1)) * (z - bi));
  146. return boost::math::make_tuple(an, bn, cn);
  147. }
  148. private:
  149. const T a, b, z;
  150. int offset;
  151. hypergeometric_1F1_recurrence_2a_and_2b_coefficients operator=(const hypergeometric_1F1_recurrence_2a_and_2b_coefficients&);
  152. };
  153. //
  154. // Recurrence relation for double-stepping on a:
  155. // -(b-a)(1 + b - a)/(2a-2-b+z)M(a-2,b,z) + [(b-a)(a-1)/(2a-2-b+z) + (2a-b+z) + a(b-a-1)/(2a+2-b+z)]M(a,b,z) -a(a+1)/(2a+2-b+z)M(a+2,b,z)
  156. //
  157. template <class T>
  158. struct hypergeometric_1F1_recurrence_2a_coefficients
  159. {
  160. typedef boost::math::tuple<T, T, T> result_type;
  161. hypergeometric_1F1_recurrence_2a_coefficients(const T& a, const T& b, const T& z, int offset = 0) :
  162. a(a), b(b), z(z), offset(offset)
  163. {
  164. }
  165. result_type operator()(std::intmax_t i) const
  166. {
  167. i *= 2;
  168. const T ai = a + (offset + i);
  169. // -(b-a)(1 + b - a)/(2a-2-b+z)
  170. const T an = -(b - ai) * (b - (a + (offset + i - 1))) / (2 * (a + (offset + i - 1)) - b + z);
  171. 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);
  172. const T cn = -ai * (a + (offset + i + 1)) / (2 * (a + (offset + i + 1)) - b + z);
  173. return boost::math::make_tuple(an, bn, cn);
  174. }
  175. private:
  176. const T a, b, z;
  177. int offset;
  178. hypergeometric_1F1_recurrence_2a_coefficients operator=(const hypergeometric_1F1_recurrence_2a_coefficients&);
  179. };
  180. //
  181. // Recurrence relation for double-stepping on b:
  182. // b(b-1)^2(b-2)/((1-b)(2-b-z)) M(a,b-2,z) + [zb(b-1)(b-1-a)/((1-b)(2-b-z)) + b(1-b-z) + z(b-a)(b+1)b/((b+1)(b+z)) ] M(a,b,z) + z^2(b-a)(b+1-a)/((b+1)(b+z)) M(a,b+2,z)
  183. //
  184. template <class T>
  185. struct hypergeometric_1F1_recurrence_2b_coefficients
  186. {
  187. typedef boost::math::tuple<T, T, T> result_type;
  188. hypergeometric_1F1_recurrence_2b_coefficients(const T& a, const T& b, const T& z, int offset = 0) :
  189. a(a), b(b), z(z), offset(offset)
  190. {
  191. }
  192. result_type operator()(std::intmax_t i) const
  193. {
  194. i *= 2;
  195. const T bi = b + (offset + i);
  196. const T bi_m1 = b + (offset + i - 1);
  197. const T bi_p1 = b + (offset + i + 1);
  198. const T bi_m2 = b + (offset + i - 2);
  199. const T an = bi * (bi_m1) * (bi_m1) * (bi_m2) / (-bi_m1 * (-bi_m2 - z));
  200. 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));
  201. const T cn = z * z * (bi - a) * (bi_p1 - a) / (bi_p1 * (bi + z));
  202. return boost::math::make_tuple(an, bn, cn);
  203. }
  204. private:
  205. const T a, b, z;
  206. int offset;
  207. hypergeometric_1F1_recurrence_2b_coefficients operator=(const hypergeometric_1F1_recurrence_2b_coefficients&);
  208. };
  209. //
  210. // Recurrence relation for a+ b-:
  211. // -z(b-a)(a-1-b)/(b(a-1+z)) M(a-1,b+1,z) + [(b-a)(a-1)b/(b(a-1+z)) + (2a-b+z) + a(b-a-1)/(a+z)] M(a,b,z) + a(1-b)/(a+z) M(a+1,b-1,z)
  212. //
  213. // This is potentially the most useful of these novel recurrences.
  214. // - - + - +
  215. template <class T>
  216. struct hypergeometric_1F1_recurrence_a_plus_b_minus_coefficients
  217. {
  218. typedef boost::math::tuple<T, T, T> result_type;
  219. hypergeometric_1F1_recurrence_a_plus_b_minus_coefficients(const T& a, const T& b, const T& z, int offset = 0) :
  220. a(a), b(b), z(z), offset(offset)
  221. {
  222. }
  223. result_type operator()(std::intmax_t i) const
  224. {
  225. const T ai = a + (offset + i);
  226. const T bi = b - (offset + i);
  227. const T an = -z * (bi - ai) * (ai - 1 - bi) / (bi * (ai - 1 + z));
  228. const T bn = z * ((-1 / (ai + z) - 1 / (ai + z - 1)) * (bi + z - 1) + 3) + bi - 1;
  229. const T cn = ai * (1 - bi) / (ai + z);
  230. return boost::math::make_tuple(an, bn, cn);
  231. }
  232. private:
  233. const T a, b, z;
  234. int offset;
  235. hypergeometric_1F1_recurrence_a_plus_b_minus_coefficients operator=(const hypergeometric_1F1_recurrence_a_plus_b_minus_coefficients&);
  236. };
  237. #endif
  238. template <class T, class Policy>
  239. 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)
  240. {
  241. BOOST_MATH_STD_USING // modf, frexp, fabs, pow
  242. std::intmax_t integer_part = 0;
  243. T ak = modf(a, &integer_part);
  244. //
  245. // We need ak-1 positive to avoid infinite recursion below:
  246. //
  247. if (0 != ak)
  248. {
  249. ak += 2;
  250. integer_part -= 2;
  251. }
  252. if (ak - 1 == b)
  253. {
  254. // When ak - 1 == b are recursion coefficients disappear to zero and
  255. // we end up with a NaN result. Reduce the recursion steps by 1 to
  256. // avoid this. We rely on |b| small and therefore no infinite recursion.
  257. ak -= 1;
  258. integer_part += 1;
  259. }
  260. if (-integer_part > static_cast<std::intmax_t>(policies::get_max_series_iterations<Policy>()))
  261. 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);
  262. T first {};
  263. T second {};
  264. if(ak == 0)
  265. {
  266. first = 1;
  267. ak -= 1;
  268. second = 1 - z / b;
  269. if (fabs(second) < 0.5)
  270. second = (b - z) / b; // cancellation avoidance
  271. }
  272. else
  273. {
  274. long long scaling1 {};
  275. long long scaling2 {};
  276. first = detail::hypergeometric_1F1_imp(ak, b, z, pol, scaling1);
  277. ak -= 1;
  278. second = detail::hypergeometric_1F1_imp(ak, b, z, pol, scaling2);
  279. if (scaling1 != scaling2)
  280. {
  281. second *= exp(T(scaling2 - scaling1));
  282. }
  283. log_scaling += scaling1;
  284. }
  285. ++integer_part;
  286. detail::hypergeometric_1F1_recurrence_a_coefficients<T> s(ak, b, z);
  287. return tools::apply_recurrence_relation_backward(s,
  288. static_cast<unsigned int>(std::abs(integer_part)),
  289. first,
  290. second, &log_scaling);
  291. }
  292. template <class T, class Policy>
  293. 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)
  294. {
  295. using std::swap;
  296. BOOST_MATH_STD_USING // modf, frexp, fabs, pow
  297. //
  298. // We compute
  299. //
  300. // M[a + a_shift, b + b_shift; z]
  301. //
  302. // and recurse backwards on a and b down to
  303. //
  304. // M[a, b, z]
  305. //
  306. // With a + a_shift > 1 and b + b_shift > z
  307. //
  308. // There are 3 distinct regions to ensure stability during the recursions:
  309. //
  310. // a > 0 : stable for backwards on a
  311. // a < 0, b > 0 : stable for backwards on a and b
  312. // a < 0, b < 0 : stable for backwards on b (as long as |b| is small).
  313. //
  314. // We could simplify things by ignoring the middle region, but it's more efficient
  315. // to recurse on a and b together when we can.
  316. //
  317. BOOST_MATH_ASSERT(a < -1); // Not tested nor taken for -1 < a < 0
  318. int b_shift = itrunc(z - b) + 2;
  319. int a_shift = itrunc(-a);
  320. if (a + a_shift != 0)
  321. {
  322. a_shift += 2;
  323. }
  324. //
  325. // If the shifts are so large that we would throw an evaluation_error, try the series instead,
  326. // even though this will almost certainly throw as well:
  327. //
  328. if (b_shift > static_cast<std::intmax_t>(boost::math::policies::get_max_series_iterations<Policy>()))
  329. return hypergeometric_1F1_checked_series_impl(a, b, z, pol, log_scaling);
  330. if (a_shift > static_cast<std::intmax_t>(boost::math::policies::get_max_series_iterations<Policy>()))
  331. return hypergeometric_1F1_checked_series_impl(a, b, z, pol, log_scaling);
  332. int a_b_shift = b < 0 ? itrunc(b + b_shift) : b_shift; // The max we can shift on a and b together
  333. int leading_a_shift = (std::min)(3, a_shift); // Just enough to make a negative
  334. if (a_b_shift > a_shift - 3)
  335. {
  336. a_b_shift = a_shift < 3 ? 0 : a_shift - 3;
  337. }
  338. else
  339. {
  340. // Need to ensure that leading_a_shift is large enough that a will reach it's target
  341. // after the first 2 phases (-,0) and (-,-) are over:
  342. leading_a_shift = a_shift - a_b_shift;
  343. }
  344. int trailing_b_shift = b_shift - a_b_shift;
  345. if (a_b_shift < 5)
  346. {
  347. // Might as well do things in two steps rather than 3:
  348. if (a_b_shift > 0)
  349. {
  350. leading_a_shift += a_b_shift;
  351. trailing_b_shift += a_b_shift;
  352. }
  353. a_b_shift = 0;
  354. --leading_a_shift;
  355. }
  356. BOOST_MATH_ASSERT(leading_a_shift > 1);
  357. BOOST_MATH_ASSERT(a_b_shift + leading_a_shift + (a_b_shift == 0 ? 1 : 0) == a_shift);
  358. BOOST_MATH_ASSERT(a_b_shift + trailing_b_shift == b_shift);
  359. if ((trailing_b_shift == 0) && (fabs(b) < 0.5) && a_b_shift)
  360. {
  361. // Better to have the final recursion on b alone, otherwise we lose precision when b is very small:
  362. int diff = (std::min)(a_b_shift, 3);
  363. a_b_shift -= diff;
  364. leading_a_shift += diff;
  365. trailing_b_shift += diff;
  366. }
  367. T first {};
  368. T second {};
  369. long long scale1 {};
  370. long long scale2 {};
  371. first = boost::math::detail::hypergeometric_1F1_imp(T(a + a_shift), T(b + b_shift), z, pol, scale1);
  372. //
  373. // It would be good to compute "second" from first and the ratio - unfortunately we are right on the cusp
  374. // recursion on a switching from stable backwards to stable forwards behaviour and so this is not possible here.
  375. //
  376. second = boost::math::detail::hypergeometric_1F1_imp(T(a + a_shift - 1), T(b + b_shift), z, pol, scale2);
  377. if (scale1 != scale2)
  378. second *= exp(T(scale2 - scale1));
  379. log_scaling += scale1;
  380. //
  381. // Now we have [a + a_shift, b + b_shift, z] and [a + a_shift - 1, b + b_shift, z]
  382. // and want to recurse until [a + a_shift - leading_a_shift, b + b_shift, z] and [a + a_shift - leadng_a_shift - 1, b + b_shift, z]
  383. // which is leading_a_shift -1 steps.
  384. //
  385. second = boost::math::tools::apply_recurrence_relation_backward(
  386. hypergeometric_1F1_recurrence_a_coefficients<T>(a + a_shift - 1, b + b_shift, z),
  387. leading_a_shift, first, second, &log_scaling, &first);
  388. if (a_b_shift)
  389. {
  390. //
  391. // Now we need to switch to an a+b shift so that we have:
  392. // [a + a_shift - leading_a_shift, b + b_shift, z] and [a + a_shift - leadng_a_shift - 1, b + b_shift - 1, z]
  393. // A&S 13.4.3 gives us what we need:
  394. //
  395. {
  396. // local a's and b's:
  397. T la = a + a_shift - leading_a_shift - 1;
  398. T lb = b + b_shift;
  399. second = ((1 + la - lb) * second - la * first) / (1 - lb);
  400. }
  401. //
  402. // Now apply a_b_shift - 1 recursions to get down to
  403. // [a + 1, b + trailing_b_shift + 1, z] and [a, b + trailing_b_shift, z]
  404. //
  405. second = boost::math::tools::apply_recurrence_relation_backward(
  406. hypergeometric_1F1_recurrence_a_and_b_coefficients<T>(a, b + b_shift - a_b_shift, z, a_b_shift - 1),
  407. a_b_shift - 1, first, second, &log_scaling, &first);
  408. //
  409. // Now we need to switch to a b shift, a different application of A&S 13.4.3
  410. // will get us there, we leave "second" where it is, and move "first" sideways:
  411. //
  412. {
  413. T lb = b + trailing_b_shift + 1;
  414. first = (second * (lb - 1) - a * first) / -(1 + a - lb);
  415. }
  416. }
  417. else
  418. {
  419. //
  420. // We have M[a+1, b+b_shift, z] and M[a, b+b_shift, z] and need M[a, b+b_shift-1, z] for
  421. // recursion on b: A&S 13.4.3 gives us what we need.
  422. //
  423. T third = -(second * (1 + a - b - b_shift) - first * a) / (b + b_shift - 1);
  424. swap(first, second);
  425. swap(second, third);
  426. --trailing_b_shift;
  427. }
  428. //
  429. // Finish off by applying trailing_b_shift recursions:
  430. //
  431. if (trailing_b_shift)
  432. {
  433. second = boost::math::tools::apply_recurrence_relation_backward(
  434. hypergeometric_1F1_recurrence_small_b_coefficients<T>(a, b, z, trailing_b_shift),
  435. trailing_b_shift, first, second, &log_scaling);
  436. }
  437. return second;
  438. }
  439. } } } // namespaces
  440. #endif // BOOST_HYPERGEOMETRIC_1F1_RECURRENCE_HPP_