1 // Copyright Nick Thompson, 2017
2 // Use, modification and distribution are subject to the
3 // Boost Software License, Version 1.0.
4 // (See accompanying file LICENSE_1_0.txt
5 // or copy at http://www.boost.org/LICENSE_1_0.txt)
7 #define BOOST_TEST_MODULE barycentric_rational
10 #include <boost/random/uniform_real_distribution.hpp>
11 #include <boost/type_index.hpp>
12 #include <boost/test/included/unit_test.hpp>
13 #include <boost/test/floating_point_comparison.hpp>
14 #include <boost/math/interpolators/barycentric_rational.hpp>
15 #include <boost/multiprecision/cpp_bin_float.hpp>
17 #ifdef BOOST_HAS_FLOAT128
18 #include <boost/multiprecision/float128.hpp>
21 using boost::multiprecision::cpp_bin_float_50
;
24 void test_interpolation_condition()
26 std::cout
<< "Testing interpolation condition for barycentric interpolation on type " << boost::typeindex::type_id
<Real
>().pretty_name() << "\n";
28 boost::random::uniform_real_distribution
<Real
> dis(0.1f
, 1);
29 std::vector
<Real
> x(500);
30 std::vector
<Real
> y(500);
33 for (size_t i
= 1; i
< x
.size(); ++i
)
35 x
[i
] = x
[i
-1] + dis(gen
);
39 boost::math::barycentric_rational
<Real
> interpolator(x
.data(), y
.data(), y
.size());
41 for (size_t i
= 0; i
< x
.size(); ++i
)
43 auto z
= interpolator(x
[i
]);
44 BOOST_CHECK_CLOSE(z
, y
[i
], 100*std::numeric_limits
<Real
>::epsilon());
49 void test_interpolation_condition_high_order()
51 std::cout
<< "Testing interpolation condition in high order for barycentric interpolation on type " << boost::typeindex::type_id
<Real
>().pretty_name() << "\n";
53 boost::random::uniform_real_distribution
<Real
> dis(0.1f
, 1);
54 std::vector
<Real
> x(500);
55 std::vector
<Real
> y(500);
58 for (size_t i
= 1; i
< x
.size(); ++i
)
60 x
[i
] = x
[i
-1] + dis(gen
);
64 // Order 5 approximation:
65 boost::math::barycentric_rational
<Real
> interpolator(x
.data(), y
.data(), y
.size(), 5);
67 for (size_t i
= 0; i
< x
.size(); ++i
)
69 auto z
= interpolator(x
[i
]);
70 BOOST_CHECK_CLOSE(z
, y
[i
], 100*std::numeric_limits
<Real
>::epsilon());
78 std::cout
<< "Testing that constants are interpolated correctly using barycentric interpolation on type " << boost::typeindex::type_id
<Real
>().pretty_name() << "\n";
81 boost::random::uniform_real_distribution
<Real
> dis(0.1f
, 1);
82 std::vector
<Real
> x(500);
83 std::vector
<Real
> y(500);
87 for (size_t i
= 1; i
< x
.size(); ++i
)
89 x
[i
] = x
[i
-1] + dis(gen
);
93 boost::math::barycentric_rational
<Real
> interpolator(x
.data(), y
.data(), y
.size());
95 for (size_t i
= 0; i
< x
.size(); ++i
)
97 // Don't evaluate the constant at x[i]; that's already tested in the interpolation condition test.
98 auto z
= interpolator(x
[i
] + dis(gen
));
99 BOOST_CHECK_CLOSE(z
, constant
, 100*sqrt(std::numeric_limits
<Real
>::epsilon()));
104 void test_constant_high_order()
106 std::cout
<< "Testing that constants are interpolated correctly in high order using barycentric interpolation on type " << boost::typeindex::type_id
<Real
>().pretty_name() << "\n";
109 boost::random::uniform_real_distribution
<Real
> dis(0.1f
, 1);
110 std::vector
<Real
> x(500);
111 std::vector
<Real
> y(500);
115 for (size_t i
= 1; i
< x
.size(); ++i
)
117 x
[i
] = x
[i
-1] + dis(gen
);
121 // Set interpolation order to 7:
122 boost::math::barycentric_rational
<Real
> interpolator(x
.data(), y
.data(), y
.size(), 7);
124 for (size_t i
= 0; i
< x
.size(); ++i
)
126 auto z
= interpolator(x
[i
] + dis(gen
));
127 BOOST_CHECK_CLOSE(z
, constant
, 1000*sqrt(std::numeric_limits
<Real
>::epsilon()));
135 std::cout
<< "Testing interpolation of Runge's 1/(1+25x^2) function using barycentric interpolation on type " << boost::typeindex::type_id
<Real
>().pretty_name() << "\n";
138 boost::random::uniform_real_distribution
<Real
> dis(0.005f
, 0.01f
);
139 std::vector
<Real
> x(500);
140 std::vector
<Real
> y(500);
142 y
[0] = 1/(1+25*x
[0]*x
[0]);
143 for (size_t i
= 1; i
< x
.size(); ++i
)
145 x
[i
] = x
[i
-1] + dis(gen
);
146 y
[i
] = 1/(1+25*x
[i
]*x
[i
]);
149 boost::math::barycentric_rational
<Real
> interpolator(x
.data(), y
.data(), y
.size(), 5);
151 for (size_t i
= 0; i
< x
.size(); ++i
)
153 auto t
= x
[i
] + dis(gen
);
154 auto z
= interpolator(t
);
155 BOOST_CHECK_CLOSE(z
, 1/(1+25*t
*t
), 0.03);
162 std::cout
<< "Testing weights are calculated correctly using barycentric interpolation on type " << boost::typeindex::type_id
<Real
>().pretty_name() << "\n";
165 boost::random::uniform_real_distribution
<Real
> dis(0.005, 0.01);
166 std::vector
<Real
> x(500);
167 std::vector
<Real
> y(500);
169 y
[0] = 1/(1+25*x
[0]*x
[0]);
170 for (size_t i
= 1; i
< x
.size(); ++i
)
172 x
[i
] = x
[i
-1] + dis(gen
);
173 y
[i
] = 1/(1+25*x
[i
]*x
[i
]);
176 boost::math::detail::barycentric_rational_imp
<Real
> interpolator(x
.data(), x
.data() + x
.size(), y
.data(), 0);
178 for (size_t i
= 0; i
< x
.size(); ++i
)
180 auto w
= interpolator
.weight(i
);
183 BOOST_CHECK_CLOSE(w
, 1, 0.00001);
187 BOOST_CHECK_CLOSE(w
, -1, 0.00001);
192 interpolator
= boost::math::detail::barycentric_rational_imp
<Real
>(x
.data(), x
.data() + x
.size(), y
.data(), 1);
194 for (size_t i
= 1; i
< x
.size() -1; ++i
)
196 auto w
= interpolator
.weight(i
);
197 auto w_expect
= 1/(x
[i
] - x
[i
- 1]) + 1/(x
[i
+1] - x
[i
]);
200 BOOST_CHECK_CLOSE(w
, -w_expect
, 0.00001);
204 BOOST_CHECK_CLOSE(w
, w_expect
, 0.00001);
211 BOOST_AUTO_TEST_CASE(barycentric_rational
)
213 test_weights
<double>();
214 test_constant
<float>();
215 test_constant
<double>();
216 test_constant
<long double>();
217 test_constant
<cpp_bin_float_50
>();
219 test_constant_high_order
<float>();
220 test_constant_high_order
<double>();
221 test_constant_high_order
<long double>();
222 test_constant_high_order
<cpp_bin_float_50
>();
224 test_interpolation_condition
<float>();
225 test_interpolation_condition
<double>();
226 test_interpolation_condition
<long double>();
227 test_interpolation_condition
<cpp_bin_float_50
>();
229 test_interpolation_condition_high_order
<float>();
230 test_interpolation_condition_high_order
<double>();
231 test_interpolation_condition_high_order
<long double>();
232 test_interpolation_condition_high_order
<cpp_bin_float_50
>();
235 test_runge
<double>();
236 test_runge
<long double>();
237 test_runge
<cpp_bin_float_50
>();
239 #ifdef BOOST_HAS_FLOAT128
240 test_interpolation_condition
<boost::multiprecision::float128
>();
241 test_constant
<boost::multiprecision::float128
>();
242 test_constant_high_order
<boost::multiprecision::float128
>();
243 test_interpolation_condition_high_order
<boost::multiprecision::float128
>();
244 test_runge
<boost::multiprecision::float128
>();