1 // (C) Copyright John Maddock 2018.
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
6 #define BOOST_TEST_MODULE test_recurrences
7
8 #include <boost/config.hpp>
9
10 #ifndef BOOST_NO_CXX11_HDR_TUPLE
11 #include <boost/multiprecision/cpp_bin_float.hpp>
12 #include <boost/math/tools/recurrence.hpp>
13 #include <boost/math/special_functions/bessel.hpp>
14 #include <boost/test/included/unit_test.hpp>
15 #include <boost/test/floating_point_comparison.hpp>
16 //#include <boost/test/tools/floating_point_comparison.hpp>
17 #include <boost/math/concepts/real_concept.hpp>
18
19 #ifdef BOOST_MSVC
20 #pragma warning(disable:4127)
21 #endif
22
23 template <class T>
24 struct bessel_jy_recurrence
25 {
bessel_jy_recurrencebessel_jy_recurrence26 bessel_jy_recurrence(T v, T z) : v(v), z(z) {}
operator ()bessel_jy_recurrence27 boost::math::tuple<T, T, T> operator()(int k)const
28 {
29 return boost::math::tuple<T, T, T>(T(1), -2 * (v + k) / z, T(1));
30 }
31
32 T v, z;
33 };
34
35 template <class T>
36 struct bessel_ik_recurrence
37 {
bessel_ik_recurrencebessel_ik_recurrence38 bessel_ik_recurrence(T v, T z) : v(v), z(z) {}
operator ()bessel_ik_recurrence39 boost::math::tuple<T, T, T> operator()(int k)const
40 {
41 return boost::math::tuple<T, T, T>(T(1), -2 * (v + k) / z, T(-1));
42 }
43
44 T v, z;
45 };
46
47
48 template <class T>
test_spots(T,const char * name)49 void test_spots(T, const char* name)
50 {
51 std::cout << "Running tests for type " << name << std::endl;
52 T tol = boost::math::tools::epsilon<T>() * 5;
53 if ((std::numeric_limits<T>::digits > 53) || (std::numeric_limits<T>::digits == 0))
54 tol *= 5;
55 //
56 // Test forward recurrence on Y_v(x):
57 //
58 {
59 T v = 22.25;
60 T x = 4.125;
61 bessel_jy_recurrence<T> coef(v, x);
62 T prev;
63 T first = boost::math::cyl_neumann(v - 1, x);
64 T second = boost::math::cyl_neumann(v, x);
65 T sixth = boost::math::tools::apply_recurrence_relation_forward(coef, 6, first, second, (int*)0, &prev);
66 T expected1 = boost::math::cyl_neumann(v + 6, x);
67 T expected2 = boost::math::cyl_neumann(v + 5, x);
68 BOOST_CHECK_CLOSE_FRACTION(sixth, expected1, tol);
69 BOOST_CHECK_CLOSE_FRACTION(prev, expected2, tol);
70
71 boost::math::tools::forward_recurrence_iterator< bessel_jy_recurrence<T> > it(coef, first, second);
72 for (unsigned i = 0; i < 15; ++i)
73 {
74 expected1 = boost::math::cyl_neumann(v + i, x);
75 T found = *it;
76 BOOST_CHECK_CLOSE_FRACTION(found, expected1, tol);
77 ++it;
78 }
79
80 if (std::numeric_limits<T>::max_exponent > 300)
81 {
82 //
83 // This calculates the ratio Y_v(x)/Y_v+1(x) from the recurrence relations
84 // which are only transiently stable since Y_v is not minimal as v->-INF
85 // but only as v->0. We have to be sure that v is sufficiently large that
86 // convergence is complete before we reach the origin.
87 //
88 v = 102.75;
89 boost::uintmax_t max_iter = 200;
90 T ratio = boost::math::tools::function_ratio_from_forwards_recurrence(bessel_jy_recurrence<T>(v, x), boost::math::tools::epsilon<T>(), max_iter);
91 first = boost::math::cyl_neumann(v, x);
92 second = boost::math::cyl_neumann(v + 1, x);
93 BOOST_CHECK_CLOSE_FRACTION(ratio, first / second, tol);
94
95 boost::math::tools::forward_recurrence_iterator< bessel_jy_recurrence<T> > it2(bessel_jy_recurrence<T>(v, x), boost::math::cyl_neumann(v, x));
96 for (unsigned i = 0; i < 15; ++i)
97 {
98 expected1 = boost::math::cyl_neumann(v + i, x);
99 T found = *it2;
100 BOOST_CHECK_CLOSE_FRACTION(found, expected1, tol);
101 ++it2;
102 }
103 }
104
105 }
106 //
107 // Test backward recurrence on J_v(x):
108 //
109 {
110 if ((std::numeric_limits<T>::digits > 53) || !std::numeric_limits<T>::is_specialized)
111 tol *= 5;
112
113 T v = 22.25;
114 T x = 4.125;
115 bessel_jy_recurrence<T> coef(v, x);
116 T prev;
117 T first = boost::math::cyl_bessel_j(v + 1, x);
118 T second = boost::math::cyl_bessel_j(v, x);
119 T sixth = boost::math::tools::apply_recurrence_relation_backward(coef, 6, first, second, (int*)0, &prev);
120 T expected1 = boost::math::cyl_bessel_j(v - 6, x);
121 T expected2 = boost::math::cyl_bessel_j(v - 5, x);
122 BOOST_CHECK_CLOSE_FRACTION(sixth, expected1, tol);
123 BOOST_CHECK_CLOSE_FRACTION(prev, expected2, tol);
124
125 boost::math::tools::backward_recurrence_iterator< bessel_jy_recurrence<T> > it(coef, first, second);
126 for (unsigned i = 0; i < 15; ++i)
127 {
128 expected1 = boost::math::cyl_bessel_j(v - i, x);
129 T found = *it;
130 BOOST_CHECK_CLOSE_FRACTION(found, expected1, tol);
131 ++it;
132 }
133
134 boost::uintmax_t max_iter = 200;
135 T ratio = boost::math::tools::function_ratio_from_backwards_recurrence(bessel_jy_recurrence<T>(v, x), boost::math::tools::epsilon<T>(), max_iter);
136 first = boost::math::cyl_bessel_j(v, x);
137 second = boost::math::cyl_bessel_j(v - 1, x);
138 BOOST_CHECK_CLOSE_FRACTION(ratio, first / second, tol);
139
140 boost::math::tools::backward_recurrence_iterator< bessel_jy_recurrence<T> > it2(bessel_jy_recurrence<T>(v, x), boost::math::cyl_bessel_j(v, x));
141 //boost::math::tools::backward_recurrence_iterator< bessel_jy_recurrence<T> > it3(bessel_jy_recurrence<T>(v, x), boost::math::cyl_neumann(v+1, x), boost::math::cyl_neumann(v, x));
142 for (unsigned i = 0; i < 15; ++i)
143 {
144 expected1 = boost::math::cyl_bessel_j(v - i, x);
145 T found = *it2;
146 BOOST_CHECK_CLOSE_FRACTION(found, expected1, tol);
147 ++it2;
148 }
149
150 }
151 }
152
153
BOOST_AUTO_TEST_CASE(test_main)154 BOOST_AUTO_TEST_CASE( test_main )
155 {
156 BOOST_MATH_CONTROL_FP;
157 #if !defined(TEST) || TEST == 1
158 test_spots(0.0F, "float");
159 test_spots(0.0, "double");
160 #ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
161 test_spots(0.0L, "long double");
162 #ifndef BOOST_MATH_NO_REAL_CONCEPT_TESTS
163 test_spots(boost::math::concepts::real_concept(0.1), "real_concept");
164 #endif
165 #endif
166 #endif
167 #if !defined(TEST) || TEST == 2 || TEST == 3
168 test_spots(boost::multiprecision::cpp_bin_float_quad(), "cpp_bin_float_quad");
169 #endif
170 }
171
172 #else
173
main()174 int main() { return 0; }
175
176 #endif
177