recurrence.hpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. // (C) Copyright Anton Bikineev 2014
  2. // Use, modification and distribution are subject to the
  3. // Boost Software License, Version 1.0. (See accompanying file
  4. // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  5. #ifndef BOOST_MATH_TOOLS_RECURRENCE_HPP_
  6. #define BOOST_MATH_TOOLS_RECURRENCE_HPP_
  7. #include <boost/math/tools/config.hpp>
  8. #include <boost/math/tools/precision.hpp>
  9. #include <boost/math/tools/tuple.hpp>
  10. #include <boost/math/tools/fraction.hpp>
  11. #include <boost/math/tools/cxx03_warn.hpp>
  12. namespace boost {
  13. namespace math {
  14. namespace tools {
  15. namespace detail{
  16. //
  17. // Function ratios directly from recurrence relations:
  18. // H. Shintan, Note on Miller's recurrence algorithm, J. Sci. Hiroshima Univ. Ser. A-I
  19. // Math., 29 (1965), pp. 121 - 133.
  20. // and:
  21. // COMPUTATIONAL ASPECTS OF THREE-TERM RECURRENCE RELATIONS
  22. // WALTER GAUTSCHI
  23. // SIAM REVIEW Vol. 9, No. 1, January, 1967
  24. //
  25. template <class Recurrence>
  26. struct function_ratio_from_backwards_recurrence_fraction
  27. {
  28. typedef typename boost::remove_reference<decltype(boost::math::get<0>(std::declval<Recurrence&>()(0)))>::type value_type;
  29. typedef std::pair<value_type, value_type> result_type;
  30. function_ratio_from_backwards_recurrence_fraction(const Recurrence& r) : r(r), k(0) {}
  31. result_type operator()()
  32. {
  33. value_type a, b, c;
  34. boost::math::tie(a, b, c) = r(k);
  35. ++k;
  36. // an and bn defined as per Gauchi 1.16, not the same
  37. // as the usual continued fraction a' and b's.
  38. value_type bn = a / c;
  39. value_type an = b / c;
  40. return result_type(-bn, an);
  41. }
  42. private:
  43. function_ratio_from_backwards_recurrence_fraction operator=(const function_ratio_from_backwards_recurrence_fraction&);
  44. Recurrence r;
  45. int k;
  46. };
  47. template <class R, class T>
  48. struct recurrence_reverser
  49. {
  50. recurrence_reverser(const R& r) : r(r) {}
  51. boost::math::tuple<T, T, T> operator()(int i)
  52. {
  53. using std::swap;
  54. boost::math::tuple<T, T, T> t = r(-i);
  55. swap(boost::math::get<0>(t), boost::math::get<2>(t));
  56. return t;
  57. }
  58. R r;
  59. };
  60. template <class Recurrence>
  61. struct recurrence_offsetter
  62. {
  63. typedef decltype(std::declval<Recurrence&>()(0)) result_type;
  64. recurrence_offsetter(Recurrence const& rr, int offset) : r(rr), k(offset) {}
  65. result_type operator()(int i)
  66. {
  67. return r(i + k);
  68. }
  69. private:
  70. Recurrence r;
  71. int k;
  72. };
  73. } // namespace detail
  74. //
  75. // Given a stable backwards recurrence relation:
  76. // a f_n-1 + b f_n + c f_n+1 = 0
  77. // returns the ratio f_n / f_n-1
  78. //
  79. // Recurrence: a functor that returns a tuple of the factors (a,b,c).
  80. // factor: Convergence criteria, should be no less than machine epsilon.
  81. // max_iter: Maximum iterations to use solving the continued fraction.
  82. //
  83. template <class Recurrence, class T>
  84. T function_ratio_from_backwards_recurrence(const Recurrence& r, const T& factor, boost::uintmax_t& max_iter)
  85. {
  86. detail::function_ratio_from_backwards_recurrence_fraction<Recurrence> f(r);
  87. return boost::math::tools::continued_fraction_a(f, factor, max_iter);
  88. }
  89. //
  90. // Given a stable forwards recurrence relation:
  91. // a f_n-1 + b f_n + c f_n+1 = 0
  92. // returns the ratio f_n / f_n+1
  93. //
  94. // Note that in most situations where this would be used, we're relying on
  95. // pseudo-convergence, as in most cases f_n will not be minimal as N -> -INF
  96. // as long as we reach convergence on the continued-fraction before f_n
  97. // switches behaviour, we should be fine.
  98. //
  99. // Recurrence: a functor that returns a tuple of the factors (a,b,c).
  100. // factor: Convergence criteria, should be no less than machine epsilon.
  101. // max_iter: Maximum iterations to use solving the continued fraction.
  102. //
  103. template <class Recurrence, class T>
  104. T function_ratio_from_forwards_recurrence(const Recurrence& r, const T& factor, boost::uintmax_t& max_iter)
  105. {
  106. boost::math::tools::detail::function_ratio_from_backwards_recurrence_fraction<boost::math::tools::detail::recurrence_reverser<Recurrence, T> > f(r);
  107. return boost::math::tools::continued_fraction_a(f, factor, max_iter);
  108. }
  109. // solves usual recurrence relation for homogeneous
  110. // difference equation in stable forward direction
  111. // a(n)w(n-1) + b(n)w(n) + c(n)w(n+1) = 0
  112. //
  113. // Params:
  114. // get_coefs: functor returning a tuple, where
  115. // get<0>() is a(n); get<1>() is b(n); get<2>() is c(n);
  116. // last_index: index N to be found;
  117. // first: w(-1);
  118. // second: w(0);
  119. //
  120. template <class NextCoefs, class T>
  121. inline T apply_recurrence_relation_forward(const NextCoefs& get_coefs, unsigned number_of_steps, T first, T second, long long* log_scaling = 0, T* previous = 0)
  122. {
  123. BOOST_MATH_STD_USING
  124. using boost::math::tuple;
  125. using boost::math::get;
  126. T third;
  127. T a, b, c;
  128. for (unsigned k = 0; k < number_of_steps; ++k)
  129. {
  130. tie(a, b, c) = get_coefs(k);
  131. if ((log_scaling) &&
  132. ((fabs(tools::max_value<T>() * (c / (a * 2048))) < fabs(first))
  133. || (fabs(tools::max_value<T>() * (c / (b * 2048))) < fabs(second))
  134. || (fabs(tools::min_value<T>() * (c * 2048 / a)) > fabs(first))
  135. || (fabs(tools::min_value<T>() * (c * 2048 / b)) > fabs(second))
  136. ))
  137. {
  138. // Rescale everything:
  139. long long log_scale = lltrunc(log(fabs(second)));
  140. T scale = exp(T(-log_scale));
  141. second *= scale;
  142. first *= scale;
  143. *log_scaling += log_scale;
  144. }
  145. // scale each part separately to avoid spurious overflow:
  146. third = (a / -c) * first + (b / -c) * second;
  147. BOOST_ASSERT((boost::math::isfinite)(third));
  148. swap(first, second);
  149. swap(second, third);
  150. }
  151. if (previous)
  152. *previous = first;
  153. return second;
  154. }
  155. // solves usual recurrence relation for homogeneous
  156. // difference equation in stable backward direction
  157. // a(n)w(n-1) + b(n)w(n) + c(n)w(n+1) = 0
  158. //
  159. // Params:
  160. // get_coefs: functor returning a tuple, where
  161. // get<0>() is a(n); get<1>() is b(n); get<2>() is c(n);
  162. // number_of_steps: index N to be found;
  163. // first: w(1);
  164. // second: w(0);
  165. //
  166. template <class T, class NextCoefs>
  167. inline T apply_recurrence_relation_backward(const NextCoefs& get_coefs, unsigned number_of_steps, T first, T second, long long* log_scaling = 0, T* previous = 0)
  168. {
  169. BOOST_MATH_STD_USING
  170. using boost::math::tuple;
  171. using boost::math::get;
  172. T next;
  173. T a, b, c;
  174. for (unsigned k = 0; k < number_of_steps; ++k)
  175. {
  176. tie(a, b, c) = get_coefs(-static_cast<int>(k));
  177. if ((log_scaling) &&
  178. ( (fabs(tools::max_value<T>() * (a / b) / 2048) < fabs(second))
  179. || (fabs(tools::max_value<T>() * (a / c) / 2048) < fabs(first))
  180. || (fabs(tools::min_value<T>() * (a / b) * 2048) > fabs(second))
  181. || (fabs(tools::min_value<T>() * (a / c) * 2048) > fabs(first))
  182. ))
  183. {
  184. // Rescale everything:
  185. int log_scale = itrunc(log(fabs(second)));
  186. T scale = exp(T(-log_scale));
  187. second *= scale;
  188. first *= scale;
  189. *log_scaling += log_scale;
  190. }
  191. // scale each part separately to avoid spurious overflow:
  192. next = (b / -a) * second + (c / -a) * first;
  193. BOOST_ASSERT((boost::math::isfinite)(next));
  194. swap(first, second);
  195. swap(second, next);
  196. }
  197. if (previous)
  198. *previous = first;
  199. return second;
  200. }
  201. template <class Recurrence>
  202. struct forward_recurrence_iterator
  203. {
  204. typedef typename boost::remove_reference<decltype(std::get<0>(std::declval<Recurrence&>()(0)))>::type value_type;
  205. forward_recurrence_iterator(const Recurrence& r, value_type f_n_minus_1, value_type f_n)
  206. : f_n_minus_1(f_n_minus_1), f_n(f_n), coef(r), k(0) {}
  207. forward_recurrence_iterator(const Recurrence& r, value_type f_n)
  208. : f_n(f_n), coef(r), k(0)
  209. {
  210. boost::uintmax_t max_iter = boost::math::policies::get_max_series_iterations<boost::math::policies::policy<> >();
  211. f_n_minus_1 = f_n * boost::math::tools::function_ratio_from_forwards_recurrence(detail::recurrence_offsetter<Recurrence>(r, -1), value_type(boost::math::tools::epsilon<value_type>() * 2), max_iter);
  212. boost::math::policies::check_series_iterations<value_type>("forward_recurrence_iterator<>::forward_recurrence_iterator", max_iter, boost::math::policies::policy<>());
  213. }
  214. forward_recurrence_iterator& operator++()
  215. {
  216. using std::swap;
  217. value_type a, b, c;
  218. boost::math::tie(a, b, c) = coef(k);
  219. value_type f_n_plus_1 = a * f_n_minus_1 / -c + b * f_n / -c;
  220. swap(f_n_minus_1, f_n);
  221. swap(f_n, f_n_plus_1);
  222. ++k;
  223. return *this;
  224. }
  225. forward_recurrence_iterator operator++(int)
  226. {
  227. forward_recurrence_iterator t(*this);
  228. ++(*this);
  229. return t;
  230. }
  231. value_type operator*() { return f_n; }
  232. value_type f_n_minus_1, f_n;
  233. Recurrence coef;
  234. int k;
  235. };
  236. template <class Recurrence>
  237. struct backward_recurrence_iterator
  238. {
  239. typedef typename boost::remove_reference<decltype(std::get<0>(std::declval<Recurrence&>()(0)))>::type value_type;
  240. backward_recurrence_iterator(const Recurrence& r, value_type f_n_plus_1, value_type f_n)
  241. : f_n_plus_1(f_n_plus_1), f_n(f_n), coef(r), k(0) {}
  242. backward_recurrence_iterator(const Recurrence& r, value_type f_n)
  243. : f_n(f_n), coef(r), k(0)
  244. {
  245. boost::uintmax_t max_iter = boost::math::policies::get_max_series_iterations<boost::math::policies::policy<> >();
  246. f_n_plus_1 = f_n * boost::math::tools::function_ratio_from_backwards_recurrence(detail::recurrence_offsetter<Recurrence>(r, 1), value_type(boost::math::tools::epsilon<value_type>() * 2), max_iter);
  247. boost::math::policies::check_series_iterations<value_type>("backward_recurrence_iterator<>::backward_recurrence_iterator", max_iter, boost::math::policies::policy<>());
  248. }
  249. backward_recurrence_iterator& operator++()
  250. {
  251. using std::swap;
  252. value_type a, b, c;
  253. boost::math::tie(a, b, c) = coef(k);
  254. value_type f_n_minus_1 = c * f_n_plus_1 / -a + b * f_n / -a;
  255. swap(f_n_plus_1, f_n);
  256. swap(f_n, f_n_minus_1);
  257. --k;
  258. return *this;
  259. }
  260. backward_recurrence_iterator operator++(int)
  261. {
  262. backward_recurrence_iterator t(*this);
  263. ++(*this);
  264. return t;
  265. }
  266. value_type operator*() { return f_n; }
  267. value_type f_n_plus_1, f_n;
  268. Recurrence coef;
  269. int k;
  270. };
  271. }
  272. }
  273. } // namespaces
  274. #endif // BOOST_MATH_TOOLS_RECURRENCE_HPP_