/* * Copyright Nick Thompson, 2019 * Use, modification and distribution are subject to the * Boost Software License, Version 1.0. (See accompanying file * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) */ #include "math_unit_test.hpp" #include #include #include #ifdef BOOST_HAS_FLOAT128 #include using boost::multiprecision::float128; #endif using boost::math::interpolators::cardinal_quintic_b_spline; template void test_constant() { Real c = 7.5; Real t0 = 0; Real h = Real(1)/Real(16); size_t n = 513; std::vector v(n, c); std::pair left_endpoint_derivatives{0, 0}; std::pair right_endpoint_derivatives{0, 0}; auto qbs = cardinal_quintic_b_spline(v.data(), v.size(), t0, h, left_endpoint_derivatives, right_endpoint_derivatives); size_t i = 0; while (i < n) { Real t = t0 + i*h; CHECK_ULP_CLOSE(c, qbs(t), 3); CHECK_MOLLIFIED_CLOSE(Real(0), qbs.prime(t), 400*std::numeric_limits::epsilon()); CHECK_MOLLIFIED_CLOSE(Real(0), qbs.double_prime(t), 60000*std::numeric_limits::epsilon()); ++i; } i = 0; while (i < n - 1) { Real t = t0 + i*h + h/2; CHECK_ULP_CLOSE(c, qbs(t), 5); CHECK_MOLLIFIED_CLOSE(Real(0), qbs.prime(t), 600*std::numeric_limits::epsilon()); CHECK_MOLLIFIED_CLOSE(Real(0), qbs.double_prime(t), 30000*std::numeric_limits::epsilon()); t = t0 + i*h + h/4; CHECK_ULP_CLOSE(c, qbs(t), 4); CHECK_MOLLIFIED_CLOSE(Real(0), qbs.prime(t), 600*std::numeric_limits::epsilon()); CHECK_MOLLIFIED_CLOSE(Real(0), qbs.double_prime(t), 10000*std::numeric_limits::epsilon()); ++i; } } template void test_constant_estimate_derivatives() { Real c = 7.5; Real t0 = 0; Real h = Real(1)/Real(16); size_t n = 513; std::vector v(n, c); auto qbs = cardinal_quintic_b_spline(v.data(), v.size(), t0, h); size_t i = 0; while (i < n) { Real t = t0 + i*h; CHECK_ULP_CLOSE(c, qbs(t), 3); CHECK_MOLLIFIED_CLOSE(Real(0), qbs.prime(t), 1200*std::numeric_limits::epsilon()); CHECK_MOLLIFIED_CLOSE(Real(0), qbs.double_prime(t), 200000*std::numeric_limits::epsilon()); ++i; } i = 0; while (i < n - 1) { Real t = t0 + i*h + h/2; CHECK_ULP_CLOSE(c, qbs(t), 8); CHECK_MOLLIFIED_CLOSE(Real(0), qbs.prime(t), 1200*std::numeric_limits::epsilon()); CHECK_MOLLIFIED_CLOSE(Real(0), qbs.double_prime(t), 80000*std::numeric_limits::epsilon()); t = t0 + i*h + h/4; CHECK_ULP_CLOSE(c, qbs(t), 5); CHECK_MOLLIFIED_CLOSE(Real(0), qbs.prime(t), 1200*std::numeric_limits::epsilon()); CHECK_MOLLIFIED_CLOSE(Real(0), qbs.double_prime(t), 38000*std::numeric_limits::epsilon()); ++i; } } template void test_linear() { using std::abs; Real m = 8.3; Real b = 7.2; Real t0 = 0; Real h = Real(1)/Real(16); size_t n = 512; std::vector y(n); for (size_t i = 0; i < n; ++i) { Real t = i*h; y[i] = m*t + b; } std::pair left_endpoint_derivatives{m, 0}; std::pair right_endpoint_derivatives{m, 0}; auto qbs = cardinal_quintic_b_spline(y.data(), y.size(), t0, h, left_endpoint_derivatives, right_endpoint_derivatives); size_t i = 0; while (i < n) { Real t = t0 + i*h; if (!CHECK_ULP_CLOSE(m*t+b, qbs(t), 3)) { std::cerr << " Problem at t = " << t << "\n"; } if(!CHECK_MOLLIFIED_CLOSE(m, qbs.prime(t), 100*abs(m*t+b)*std::numeric_limits::epsilon())) { std::cerr << " Problem at t = " << t << "\n"; } if(!CHECK_MOLLIFIED_CLOSE(0, qbs.double_prime(t), 10000*abs(m*t+b)*std::numeric_limits::epsilon())) { std::cerr << " Problem at t = " << t << "\n"; } ++i; } i = 0; while (i < n - 1) { Real t = t0 + i*h + h/2; if(!CHECK_ULP_CLOSE(m*t+b, qbs(t), 4)) { std::cerr << " Problem at t = " << t << "\n"; } CHECK_MOLLIFIED_CLOSE(m, qbs.prime(t), 1500*std::numeric_limits::epsilon()); t = t0 + i*h + h/4; if(!CHECK_ULP_CLOSE(m*t+b, qbs(t), 4)) { std::cerr << " Problem at t = " << t << "\n"; } CHECK_MOLLIFIED_CLOSE(m, qbs.prime(t), 3000*std::numeric_limits::epsilon()); ++i; } } template void test_linear_estimate_derivatives() { using std::abs; Real m = 8.3; Real b = 7.2; Real t0 = 0; Real h = Real(1)/Real(16); size_t n = 512; std::vector y(n); for (size_t i = 0; i < n; ++i) { Real t = i*h; y[i] = m*t + b; } auto qbs = cardinal_quintic_b_spline(y.data(), y.size(), t0, h); size_t i = 0; while (i < n) { Real t = t0 + i*h; if (!CHECK_ULP_CLOSE(m*t+b, qbs(t), 3)) { std::cerr << " Problem at t = " << t << "\n"; } if(!CHECK_MOLLIFIED_CLOSE(m, qbs.prime(t), 100*abs(m*t+b)*std::numeric_limits::epsilon())) { std::cerr << " Problem at t = " << t << "\n"; } if(!CHECK_MOLLIFIED_CLOSE(0, qbs.double_prime(t), 20000*abs(m*t+b)*std::numeric_limits::epsilon())) { std::cerr << " Problem at t = " << t << "\n"; } ++i; } i = 0; while (i < n - 1) { Real t = t0 + i*h + h/2; if(!CHECK_ULP_CLOSE(m*t+b, qbs(t), 5)) { std::cerr << " Problem at t = " << t << "\n"; } CHECK_MOLLIFIED_CLOSE(m, qbs.prime(t), 1500*std::numeric_limits::epsilon()); t = t0 + i*h + h/4; if(!CHECK_ULP_CLOSE(m*t+b, qbs(t), 4)) { std::cerr << " Problem at t = " << t << "\n"; } CHECK_MOLLIFIED_CLOSE(m, qbs.prime(t), 3000*std::numeric_limits::epsilon()); ++i; } } template void test_quadratic() { Real a = Real(1)/Real(16); Real b = -3.5; Real c = -9; Real t0 = 0; Real h = Real(1)/Real(16); size_t n = 513; std::vector y(n); for (size_t i = 0; i < n; ++i) { Real t = i*h; y[i] = a*t*t + b*t + c; } Real t_max = t0 + (n-1)*h; std::pair left_endpoint_derivatives{b, 2*a}; std::pair right_endpoint_derivatives{2*a*t_max + b, 2*a}; auto qbs = cardinal_quintic_b_spline(y, t0, h, left_endpoint_derivatives, right_endpoint_derivatives); size_t i = 0; while (i < n) { Real t = t0 + i*h; CHECK_ULP_CLOSE(a*t*t + b*t + c, qbs(t), 3); ++i; } i = 0; while (i < n -1) { Real t = t0 + i*h + h/2; if(!CHECK_ULP_CLOSE(a*t*t + b*t + c, qbs(t), 5)) { std::cerr << " Problem at abscissa t = " << t << "\n"; } t = t0 + i*h + h/4; if (!CHECK_ULP_CLOSE(a*t*t + b*t + c, qbs(t), 5)) { std::cerr << " Problem abscissa t = " << t << "\n"; } ++i; } } template void test_quadratic_estimate_derivatives() { Real a = Real(1)/Real(16); Real b = -3.5; Real c = -9; Real t0 = 0; Real h = Real(1)/Real(16); size_t n = 513; std::vector y(n); for (size_t i = 0; i < n; ++i) { Real t = i*h; y[i] = a*t*t + b*t + c; } auto qbs = cardinal_quintic_b_spline(y, t0, h); size_t i = 0; while (i < n) { Real t = t0 + i*h; CHECK_ULP_CLOSE(a*t*t + b*t + c, qbs(t), 3); ++i; } i = 0; while (i < n -1) { Real t = t0 + i*h + h/2; if(!CHECK_ULP_CLOSE(a*t*t + b*t + c, qbs(t), 10)) { std::cerr << " Problem at abscissa t = " << t << "\n"; } t = t0 + i*h + h/4; if (!CHECK_ULP_CLOSE(a*t*t + b*t + c, qbs(t), 6)) { std::cerr << " Problem abscissa t = " << t << "\n"; } ++i; } } int main() { test_constant(); test_constant(); test_constant_estimate_derivatives(); test_constant_estimate_derivatives(); test_linear(); test_linear(); test_linear(); test_linear_estimate_derivatives(); test_linear_estimate_derivatives(); test_quadratic(); test_quadratic(); test_quadratic_estimate_derivatives(); test_quadratic_estimate_derivatives(); #ifdef BOOST_HAS_FLOAT128 test_constant(); test_linear(); test_linear_estimate_derivatives(); #endif return boost::math::test::report_errors(); }