cardinal_b_spline_test.cpp 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. /*
  2. * Copyright Nick Thompson, 2019
  3. * Use, modification and distribution are subject to the
  4. * Boost Software License, Version 1.0. (See accompanying file
  5. * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. */
  7. #include "math_unit_test.hpp"
  8. #include <numeric>
  9. #include <utility>
  10. #include <random>
  11. #include <cmath>
  12. #include <boost/math/special_functions/cardinal_b_spline.hpp>
  13. #include <boost/math/interpolators/detail/cubic_b_spline_detail.hpp>
  14. #ifdef BOOST_HAS_FLOAT128
  15. #include <boost/multiprecision/float128.hpp>
  16. using boost::multiprecision::float128;
  17. #endif
  18. using std::abs;
  19. using boost::math::cardinal_b_spline;
  20. using boost::math::cardinal_b_spline_prime;
  21. using boost::math::forward_cardinal_b_spline;
  22. using boost::math::cardinal_b_spline_double_prime;
  23. template<class Real>
  24. void test_box()
  25. {
  26. Real t = cardinal_b_spline<0>(Real(1.1));
  27. Real expected = 0;
  28. CHECK_ULP_CLOSE(expected, t, 0);
  29. CHECK_ULP_CLOSE(expected, cardinal_b_spline_prime<0>(Real(1.1)), 0);
  30. t = cardinal_b_spline<0>(Real(-1.1));
  31. expected = 0;
  32. CHECK_ULP_CLOSE(expected, t, 0);
  33. Real h = Real(1)/Real(256);
  34. for (t = -Real(1)/Real(2)+h; t < Real(1)/Real(2); t += h)
  35. {
  36. expected = 1;
  37. CHECK_ULP_CLOSE(expected, cardinal_b_spline<0>(t), 0);
  38. expected = 0;
  39. CHECK_ULP_CLOSE(expected, cardinal_b_spline_prime<0>(Real(1.1)), 0);
  40. }
  41. for (t = h; t < 1; t += h)
  42. {
  43. expected = 1;
  44. CHECK_ULP_CLOSE(expected, forward_cardinal_b_spline<0>(t), 0);
  45. }
  46. }
  47. template<class Real>
  48. void test_hat()
  49. {
  50. Real t = cardinal_b_spline<1>(Real(2.1));
  51. Real expected = 0;
  52. CHECK_ULP_CLOSE(expected, t, 0);
  53. t = cardinal_b_spline<1>(Real(-2.1));
  54. expected = 0;
  55. CHECK_ULP_CLOSE(expected, t, 0);
  56. Real h = Real(1)/Real(256);
  57. for (t = -1; t <= 1; t += h)
  58. {
  59. expected = 1-abs(t);
  60. if(!CHECK_ULP_CLOSE(expected, cardinal_b_spline<1>(t), 0) )
  61. {
  62. std::cerr << " Problem at t = " << t << "\n";
  63. }
  64. if (t == -Real(1)) {
  65. if (!CHECK_ULP_CLOSE(Real(1)/Real(2), cardinal_b_spline_prime<1>(t), 0)) {
  66. std::cout << " Problem at t = " << t << "\n";
  67. }
  68. }
  69. else if (t == Real(1)) {
  70. CHECK_ULP_CLOSE(-Real(1)/Real(2), cardinal_b_spline_prime<1>(t), 0);
  71. }
  72. else if (t < 0) {
  73. CHECK_ULP_CLOSE(Real(1), cardinal_b_spline_prime<1>(t), 0);
  74. }
  75. else if (t == 0) {
  76. CHECK_ULP_CLOSE(Real(0), cardinal_b_spline_prime<1>(t), 0);
  77. }
  78. else if (t > 0) {
  79. CHECK_ULP_CLOSE(Real(-1), cardinal_b_spline_prime<1>(t), 0);
  80. }
  81. }
  82. for (t = 0; t < 2; t += h)
  83. {
  84. expected = 1 - abs(t-1);
  85. CHECK_ULP_CLOSE(expected, forward_cardinal_b_spline<1>(t), 0);
  86. }
  87. }
  88. template<class Real>
  89. void test_quadratic()
  90. {
  91. using std::abs;
  92. auto b2 = [](Real x) {
  93. Real absx = abs(x);
  94. if (absx >= 3/Real(2)) {
  95. return Real(0);
  96. }
  97. if (absx >= 1/Real(2)) {
  98. Real t = absx - 3/Real(2);
  99. return t*t/2;
  100. }
  101. Real t1 = absx - 1/Real(2);
  102. Real t2 = absx + 1/Real(2);
  103. return (2-t1*t1 -t2*t2)/2;
  104. };
  105. auto b2_prime = [&](Real x)->Real {
  106. Real absx = abs(x);
  107. Real signx = 1;
  108. if (x < 0) {
  109. signx = -1;
  110. }
  111. if (absx >= 3/Real(2)) {
  112. return Real(0);
  113. }
  114. if (absx >= 1/Real(2)) {
  115. return (absx - 3/Real(2))*signx;
  116. }
  117. return -2*absx*signx;
  118. };
  119. Real h = 1/Real(256);
  120. for (Real t = -5; t <= 5; t += h) {
  121. Real expected = b2(t);
  122. CHECK_ULP_CLOSE(expected, cardinal_b_spline<2>(t), 0);
  123. expected = b2_prime(t);
  124. if (!CHECK_ULP_CLOSE(expected, cardinal_b_spline_prime<2>(t), 0))
  125. {
  126. std::cerr << " Problem at t = " << t << "\n";
  127. }
  128. }
  129. }
  130. template<class Real>
  131. void test_cubic()
  132. {
  133. Real expected = Real(2)/Real(3);
  134. Real computed = cardinal_b_spline<3, Real>(0);
  135. CHECK_ULP_CLOSE(expected, computed, 0);
  136. expected = Real(1)/Real(6);
  137. computed = cardinal_b_spline<3, Real>(1);
  138. CHECK_ULP_CLOSE(expected, computed, 0);
  139. expected = Real(0);
  140. computed = cardinal_b_spline<3, Real>(2);
  141. CHECK_ULP_CLOSE(expected, computed, 0);
  142. Real h = 1/Real(256);
  143. for (Real t = -4; t <= 4; t += h) {
  144. expected = boost::math::detail::b3_spline_prime<Real>(t);
  145. computed = cardinal_b_spline_prime<3>(t);
  146. CHECK_ULP_CLOSE(expected, computed, 0);
  147. expected = boost::math::detail::b3_spline_double_prime<Real>(t);
  148. computed = cardinal_b_spline_double_prime<3>(t);
  149. if (!CHECK_ULP_CLOSE(expected, computed, 0)) {
  150. std::cerr << " Problem at t = " << t << "\n";
  151. }
  152. }
  153. }
  154. template<class Real>
  155. void test_quintic()
  156. {
  157. Real expected = Real(11)/Real(20);
  158. Real computed = cardinal_b_spline<5, Real>(0);
  159. CHECK_ULP_CLOSE(expected, computed, 0);
  160. expected = Real(13)/Real(60);
  161. computed = cardinal_b_spline<5, Real>(1);
  162. CHECK_ULP_CLOSE(expected, computed, 1);
  163. expected = Real(1)/Real(120);
  164. computed = cardinal_b_spline<5, Real>(2);
  165. CHECK_ULP_CLOSE(expected, computed, 0);
  166. expected = Real(0);
  167. computed = cardinal_b_spline<5, Real>(3);
  168. CHECK_ULP_CLOSE(expected, computed, 0);
  169. }
  170. template<unsigned n, typename Real>
  171. void test_b_spline_derivatives()
  172. {
  173. Real h = 1/Real(256);
  174. Real supp = (n+Real(1))/Real(2);
  175. for (Real t = -supp - 1; t <= supp+1; t+= h)
  176. {
  177. Real expected = cardinal_b_spline<n-1>(t+Real(1)/Real(2)) - cardinal_b_spline<n-1>(t - Real(1)/Real(2));
  178. Real computed = cardinal_b_spline_prime<n>(t);
  179. CHECK_MOLLIFIED_CLOSE(expected, computed, std::numeric_limits<Real>::epsilon());
  180. expected = cardinal_b_spline<n-2>(t+1) - 2*cardinal_b_spline<n-2>(t) + cardinal_b_spline<n-2>(t-1);
  181. computed = cardinal_b_spline_double_prime<n>(t);
  182. CHECK_MOLLIFIED_CLOSE(expected, computed, 2*std::numeric_limits<Real>::epsilon());
  183. }
  184. }
  185. template<unsigned n, typename Real>
  186. void test_partition_of_unity()
  187. {
  188. std::mt19937 gen(323723);
  189. Real supp = (n+1.0)/2.0;
  190. std::uniform_real_distribution<Real> dis(-supp, -supp+1);
  191. for(size_t i = 0; i < 500; ++i) {
  192. Real x = dis(gen);
  193. Real one = 0;
  194. while (x < supp) {
  195. one += cardinal_b_spline<n>(x);
  196. x += 1;
  197. }
  198. if(!CHECK_ULP_CLOSE(Real(1), one, n)) {
  199. std::cerr << " Partition of unity failure at n = " << n << "\n";
  200. }
  201. }
  202. }
  203. int main()
  204. {
  205. test_box<float>();
  206. test_box<double>();
  207. test_box<long double>();
  208. test_hat<float>();
  209. test_hat<double>();
  210. test_hat<long double>();
  211. test_quadratic<float>();
  212. test_quadratic<double>();
  213. test_quadratic<long double>();
  214. test_cubic<float>();
  215. test_cubic<double>();
  216. test_cubic<long double>();
  217. test_quintic<float>();
  218. test_quintic<double>();
  219. test_quintic<long double>();
  220. test_partition_of_unity<1, double>();
  221. test_partition_of_unity<2, double>();
  222. test_partition_of_unity<3, double>();
  223. test_partition_of_unity<4, double>();
  224. test_partition_of_unity<5, double>();
  225. test_partition_of_unity<6, double>();
  226. test_b_spline_derivatives<3, double>();
  227. test_b_spline_derivatives<4, double>();
  228. test_b_spline_derivatives<5, double>();
  229. test_b_spline_derivatives<6, double>();
  230. test_b_spline_derivatives<7, double>();
  231. test_b_spline_derivatives<8, double>();
  232. test_b_spline_derivatives<9, double>();
  233. test_b_spline_derivatives<3, long double>();
  234. test_b_spline_derivatives<4, long double>();
  235. test_b_spline_derivatives<5, long double>();
  236. test_b_spline_derivatives<6, long double>();
  237. test_b_spline_derivatives<7, long double>();
  238. test_b_spline_derivatives<8, long double>();
  239. test_b_spline_derivatives<9, long double>();
  240. #ifdef BOOST_HAS_FLOAT128
  241. test_box<float128>();
  242. test_hat<float128>();
  243. test_quadratic<float128>();
  244. test_cubic<float128>();
  245. test_quintic<float128>();
  246. #endif
  247. return boost::math::test::report_errors();
  248. }