recurrence.hpp 13 KB

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