1 // (C) Copyright Nick Thompson 2019.
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)
6 #ifndef BOOST_MATH_SPECIAL_CARDINAL_B_SPLINE_HPP
7 #define BOOST_MATH_SPECIAL_CARDINAL_B_SPLINE_HPP
12 #include <type_traits>
14 namespace boost { namespace math {
19 inline Real B1(Real x)
33 template<unsigned n, typename Real>
34 Real cardinal_b_spline(Real x) {
35 static_assert(!std::is_integral<Real>::value, "Does not work with integral types.");
38 // All B-splines are even functions:
39 return cardinal_b_spline<n, Real>(-x);
44 if (x < Real(1)/Real(2)) {
47 else if (x == Real(1)/Real(2)) {
48 return Real(1)/Real(2);
60 Real supp_max = (n+1)/Real(2);
66 // Fill v with values of B1:
67 // At most two of these terms are nonzero, and at least 1.
68 // There is only one non-zero term when n is odd and x = 0.
69 std::array<Real, n> v;
70 Real z = x + 1 - supp_max;
71 for (unsigned i = 0; i < n; ++i)
77 Real smx = supp_max - x;
78 for (unsigned j = 2; j <= n; ++j)
80 Real a = (j + 1 - smx);
82 for(unsigned k = 0; k <= n - j; ++k)
84 v[k] = (a*v[k+1] + b*v[k])/Real(j);
94 template<unsigned n, typename Real>
95 Real cardinal_b_spline_prime(Real x)
97 static_assert(!std::is_integral<Real>::value, "Cardinal B-splines do not work with integer types.");
101 // All B-splines are even functions, so derivatives are odd:
102 return -cardinal_b_spline_prime<n, Real>(-x);
108 // Kinda crazy but you get what you ask for!
109 if (x == Real(1)/Real(2))
111 return std::numeric_limits<Real>::infinity();
127 return -Real(1)/Real(2);
133 Real supp_max = (n+1)/Real(2);
139 // Now we want to evaluate B_{n}(x), but stop at the second to last step and collect B_{n-1}(x+1/2) and B_{n-1}(x-1/2):
140 std::array<Real, n> v;
141 Real z = x + 1 - supp_max;
142 for (unsigned i = 0; i < n; ++i)
144 v[i] = detail::B1(z);
148 Real smx = supp_max - x;
149 for (unsigned j = 2; j <= n - 1; ++j)
151 Real a = (j + 1 - smx);
153 for(unsigned k = 0; k <= n - j; ++k)
155 v[k] = (a*v[k+1] + b*v[k])/Real(j);
165 template<unsigned n, typename Real>
166 Real cardinal_b_spline_double_prime(Real x)
168 static_assert(!std::is_integral<Real>::value, "Cardinal B-splines do not work with integer types.");
169 static_assert(n >= 3, "n>=3 for second derivatives of cardinal B-splines is required.");
173 // All B-splines are even functions, so second derivatives are even:
174 return cardinal_b_spline_double_prime<n, Real>(-x);
178 Real supp_max = (n+1)/Real(2);
184 // Now we want to evaluate B_{n}(x), but stop at the second to last step and collect B_{n-1}(x+1/2) and B_{n-1}(x-1/2):
185 std::array<Real, n> v;
186 Real z = x + 1 - supp_max;
187 for (unsigned i = 0; i < n; ++i)
189 v[i] = detail::B1(z);
193 Real smx = supp_max - x;
194 for (unsigned j = 2; j <= n - 2; ++j)
196 Real a = (j + 1 - smx);
198 for(unsigned k = 0; k <= n - j; ++k)
200 v[k] = (a*v[k+1] + b*v[k])/Real(j);
206 return v[2] - 2*v[1] + v[0];
210 template<unsigned n, class Real>
211 Real forward_cardinal_b_spline(Real x)
213 static_assert(!std::is_integral<Real>::value, "Cardinal B-splines do not work with integral types.");
214 return cardinal_b_spline<n>(x - (n+1)/Real(2));