cardinal_quintic_b_spline_test.cpp 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  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 <boost/math/interpolators/cardinal_quintic_b_spline.hpp>
  11. #ifdef BOOST_HAS_FLOAT128
  12. #include <boost/multiprecision/float128.hpp>
  13. using boost::multiprecision::float128;
  14. #endif
  15. using boost::math::interpolators::cardinal_quintic_b_spline;
  16. template<class Real>
  17. void test_constant()
  18. {
  19. Real c = 7.5;
  20. Real t0 = 0;
  21. Real h = Real(1)/Real(16);
  22. size_t n = 513;
  23. std::vector<Real> v(n, c);
  24. std::pair<Real, Real> left_endpoint_derivatives{0, 0};
  25. std::pair<Real, Real> right_endpoint_derivatives{0, 0};
  26. auto qbs = cardinal_quintic_b_spline<Real>(v.data(), v.size(), t0, h, left_endpoint_derivatives, right_endpoint_derivatives);
  27. size_t i = 0;
  28. while (i < n) {
  29. Real t = t0 + i*h;
  30. CHECK_ULP_CLOSE(c, qbs(t), 3);
  31. CHECK_MOLLIFIED_CLOSE(Real(0), qbs.prime(t), 400*std::numeric_limits<Real>::epsilon());
  32. CHECK_MOLLIFIED_CLOSE(Real(0), qbs.double_prime(t), 60000*std::numeric_limits<Real>::epsilon());
  33. ++i;
  34. }
  35. i = 0;
  36. while (i < n - 1) {
  37. Real t = t0 + i*h + h/2;
  38. CHECK_ULP_CLOSE(c, qbs(t), 5);
  39. CHECK_MOLLIFIED_CLOSE(Real(0), qbs.prime(t), 600*std::numeric_limits<Real>::epsilon());
  40. CHECK_MOLLIFIED_CLOSE(Real(0), qbs.double_prime(t), 30000*std::numeric_limits<Real>::epsilon());
  41. t = t0 + i*h + h/4;
  42. CHECK_ULP_CLOSE(c, qbs(t), 4);
  43. CHECK_MOLLIFIED_CLOSE(Real(0), qbs.prime(t), 600*std::numeric_limits<Real>::epsilon());
  44. CHECK_MOLLIFIED_CLOSE(Real(0), qbs.double_prime(t), 10000*std::numeric_limits<Real>::epsilon());
  45. ++i;
  46. }
  47. }
  48. template<class Real>
  49. void test_constant_estimate_derivatives()
  50. {
  51. Real c = 7.5;
  52. Real t0 = 0;
  53. Real h = Real(1)/Real(16);
  54. size_t n = 513;
  55. std::vector<Real> v(n, c);
  56. auto qbs = cardinal_quintic_b_spline<Real>(v.data(), v.size(), t0, h);
  57. size_t i = 0;
  58. while (i < n) {
  59. Real t = t0 + i*h;
  60. CHECK_ULP_CLOSE(c, qbs(t), 3);
  61. CHECK_MOLLIFIED_CLOSE(Real(0), qbs.prime(t), 1200*std::numeric_limits<Real>::epsilon());
  62. CHECK_MOLLIFIED_CLOSE(Real(0), qbs.double_prime(t), 200000*std::numeric_limits<Real>::epsilon());
  63. ++i;
  64. }
  65. i = 0;
  66. while (i < n - 1) {
  67. Real t = t0 + i*h + h/2;
  68. CHECK_ULP_CLOSE(c, qbs(t), 8);
  69. CHECK_MOLLIFIED_CLOSE(Real(0), qbs.prime(t), 1200*std::numeric_limits<Real>::epsilon());
  70. CHECK_MOLLIFIED_CLOSE(Real(0), qbs.double_prime(t), 80000*std::numeric_limits<Real>::epsilon());
  71. t = t0 + i*h + h/4;
  72. CHECK_ULP_CLOSE(c, qbs(t), 5);
  73. CHECK_MOLLIFIED_CLOSE(Real(0), qbs.prime(t), 1200*std::numeric_limits<Real>::epsilon());
  74. CHECK_MOLLIFIED_CLOSE(Real(0), qbs.double_prime(t), 38000*std::numeric_limits<Real>::epsilon());
  75. ++i;
  76. }
  77. }
  78. template<class Real>
  79. void test_linear()
  80. {
  81. using std::abs;
  82. Real m = 8.3;
  83. Real b = 7.2;
  84. Real t0 = 0;
  85. Real h = Real(1)/Real(16);
  86. size_t n = 512;
  87. std::vector<Real> y(n);
  88. for (size_t i = 0; i < n; ++i) {
  89. Real t = i*h;
  90. y[i] = m*t + b;
  91. }
  92. std::pair<Real, Real> left_endpoint_derivatives{m, 0};
  93. std::pair<Real, Real> right_endpoint_derivatives{m, 0};
  94. auto qbs = cardinal_quintic_b_spline<Real>(y.data(), y.size(), t0, h, left_endpoint_derivatives, right_endpoint_derivatives);
  95. size_t i = 0;
  96. while (i < n) {
  97. Real t = t0 + i*h;
  98. if (!CHECK_ULP_CLOSE(m*t+b, qbs(t), 3)) {
  99. std::cerr << " Problem at t = " << t << "\n";
  100. }
  101. if(!CHECK_MOLLIFIED_CLOSE(m, qbs.prime(t), 100*abs(m*t+b)*std::numeric_limits<Real>::epsilon())) {
  102. std::cerr << " Problem at t = " << t << "\n";
  103. }
  104. if(!CHECK_MOLLIFIED_CLOSE(0, qbs.double_prime(t), 10000*abs(m*t+b)*std::numeric_limits<Real>::epsilon())) {
  105. std::cerr << " Problem at t = " << t << "\n";
  106. }
  107. ++i;
  108. }
  109. i = 0;
  110. while (i < n - 1) {
  111. Real t = t0 + i*h + h/2;
  112. if(!CHECK_ULP_CLOSE(m*t+b, qbs(t), 4)) {
  113. std::cerr << " Problem at t = " << t << "\n";
  114. }
  115. CHECK_MOLLIFIED_CLOSE(m, qbs.prime(t), 1500*std::numeric_limits<Real>::epsilon());
  116. t = t0 + i*h + h/4;
  117. if(!CHECK_ULP_CLOSE(m*t+b, qbs(t), 4)) {
  118. std::cerr << " Problem at t = " << t << "\n";
  119. }
  120. CHECK_MOLLIFIED_CLOSE(m, qbs.prime(t), 3000*std::numeric_limits<Real>::epsilon());
  121. ++i;
  122. }
  123. }
  124. template<class Real>
  125. void test_linear_estimate_derivatives()
  126. {
  127. using std::abs;
  128. Real m = 8.3;
  129. Real b = 7.2;
  130. Real t0 = 0;
  131. Real h = Real(1)/Real(16);
  132. size_t n = 512;
  133. std::vector<Real> y(n);
  134. for (size_t i = 0; i < n; ++i) {
  135. Real t = i*h;
  136. y[i] = m*t + b;
  137. }
  138. auto qbs = cardinal_quintic_b_spline<Real>(y.data(), y.size(), t0, h);
  139. size_t i = 0;
  140. while (i < n) {
  141. Real t = t0 + i*h;
  142. if (!CHECK_ULP_CLOSE(m*t+b, qbs(t), 3)) {
  143. std::cerr << " Problem at t = " << t << "\n";
  144. }
  145. if(!CHECK_MOLLIFIED_CLOSE(m, qbs.prime(t), 100*abs(m*t+b)*std::numeric_limits<Real>::epsilon())) {
  146. std::cerr << " Problem at t = " << t << "\n";
  147. }
  148. if(!CHECK_MOLLIFIED_CLOSE(0, qbs.double_prime(t), 20000*abs(m*t+b)*std::numeric_limits<Real>::epsilon())) {
  149. std::cerr << " Problem at t = " << t << "\n";
  150. }
  151. ++i;
  152. }
  153. i = 0;
  154. while (i < n - 1) {
  155. Real t = t0 + i*h + h/2;
  156. if(!CHECK_ULP_CLOSE(m*t+b, qbs(t), 5)) {
  157. std::cerr << " Problem at t = " << t << "\n";
  158. }
  159. CHECK_MOLLIFIED_CLOSE(m, qbs.prime(t), 1500*std::numeric_limits<Real>::epsilon());
  160. t = t0 + i*h + h/4;
  161. if(!CHECK_ULP_CLOSE(m*t+b, qbs(t), 4)) {
  162. std::cerr << " Problem at t = " << t << "\n";
  163. }
  164. CHECK_MOLLIFIED_CLOSE(m, qbs.prime(t), 3000*std::numeric_limits<Real>::epsilon());
  165. ++i;
  166. }
  167. }
  168. template<class Real>
  169. void test_quadratic()
  170. {
  171. Real a = Real(1)/Real(16);
  172. Real b = -3.5;
  173. Real c = -9;
  174. Real t0 = 0;
  175. Real h = Real(1)/Real(16);
  176. size_t n = 513;
  177. std::vector<Real> y(n);
  178. for (size_t i = 0; i < n; ++i) {
  179. Real t = i*h;
  180. y[i] = a*t*t + b*t + c;
  181. }
  182. Real t_max = t0 + (n-1)*h;
  183. std::pair<Real, Real> left_endpoint_derivatives{b, 2*a};
  184. std::pair<Real, Real> right_endpoint_derivatives{2*a*t_max + b, 2*a};
  185. auto qbs = cardinal_quintic_b_spline<Real>(y, t0, h, left_endpoint_derivatives, right_endpoint_derivatives);
  186. size_t i = 0;
  187. while (i < n) {
  188. Real t = t0 + i*h;
  189. CHECK_ULP_CLOSE(a*t*t + b*t + c, qbs(t), 3);
  190. ++i;
  191. }
  192. i = 0;
  193. while (i < n -1) {
  194. Real t = t0 + i*h + h/2;
  195. if(!CHECK_ULP_CLOSE(a*t*t + b*t + c, qbs(t), 5)) {
  196. std::cerr << " Problem at abscissa t = " << t << "\n";
  197. }
  198. t = t0 + i*h + h/4;
  199. if (!CHECK_ULP_CLOSE(a*t*t + b*t + c, qbs(t), 5)) {
  200. std::cerr << " Problem abscissa t = " << t << "\n";
  201. }
  202. ++i;
  203. }
  204. }
  205. template<class Real>
  206. void test_quadratic_estimate_derivatives()
  207. {
  208. Real a = Real(1)/Real(16);
  209. Real b = -3.5;
  210. Real c = -9;
  211. Real t0 = 0;
  212. Real h = Real(1)/Real(16);
  213. size_t n = 513;
  214. std::vector<Real> y(n);
  215. for (size_t i = 0; i < n; ++i) {
  216. Real t = i*h;
  217. y[i] = a*t*t + b*t + c;
  218. }
  219. auto qbs = cardinal_quintic_b_spline<Real>(y, t0, h);
  220. size_t i = 0;
  221. while (i < n) {
  222. Real t = t0 + i*h;
  223. CHECK_ULP_CLOSE(a*t*t + b*t + c, qbs(t), 3);
  224. ++i;
  225. }
  226. i = 0;
  227. while (i < n -1) {
  228. Real t = t0 + i*h + h/2;
  229. if(!CHECK_ULP_CLOSE(a*t*t + b*t + c, qbs(t), 10)) {
  230. std::cerr << " Problem at abscissa t = " << t << "\n";
  231. }
  232. t = t0 + i*h + h/4;
  233. if (!CHECK_ULP_CLOSE(a*t*t + b*t + c, qbs(t), 6)) {
  234. std::cerr << " Problem abscissa t = " << t << "\n";
  235. }
  236. ++i;
  237. }
  238. }
  239. int main()
  240. {
  241. test_constant<double>();
  242. test_constant<long double>();
  243. test_constant_estimate_derivatives<double>();
  244. test_constant_estimate_derivatives<long double>();
  245. test_linear<float>();
  246. test_linear<double>();
  247. test_linear<long double>();
  248. test_linear_estimate_derivatives<double>();
  249. test_linear_estimate_derivatives<long double>();
  250. test_quadratic<double>();
  251. test_quadratic<long double>();
  252. test_quadratic_estimate_derivatives<double>();
  253. test_quadratic_estimate_derivatives<long double>();
  254. #ifdef BOOST_HAS_FLOAT128
  255. test_constant<float128>();
  256. test_linear<float128>();
  257. test_linear_estimate_derivatives<float128>();
  258. #endif
  259. return boost::math::test::report_errors();
  260. }