recurrence.hpp 13 KB

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