Warning, file /include/boost/math/interpolators/detail/cardinal_quadratic_b_spline_detail.hpp was not indexed
or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001
0002
0003
0004
0005
0006
0007 #ifndef BOOST_MATH_INTERPOLATORS_CARDINAL_QUADRATIC_B_SPLINE_DETAIL_HPP
0008 #define BOOST_MATH_INTERPOLATORS_CARDINAL_QUADRATIC_B_SPLINE_DETAIL_HPP
0009 #include <vector>
0010 #include <cmath>
0011 #include <stdexcept>
0012
0013 namespace boost{ namespace math{ namespace interpolators{ namespace detail{
0014
0015 template <class Real>
0016 Real b2_spline(Real x) {
0017 using std::abs;
0018 Real absx = abs(x);
0019 if (absx < 1/Real(2))
0020 {
0021 Real y = absx - 1/Real(2);
0022 Real z = absx + 1/Real(2);
0023 return (2-y*y-z*z)/2;
0024 }
0025 if (absx < Real(3)/Real(2))
0026 {
0027 Real y = absx - Real(3)/Real(2);
0028 return y*y/2;
0029 }
0030 return static_cast<Real>(0);
0031 }
0032
0033 template <class Real>
0034 Real b2_spline_prime(Real x) {
0035 if (x < 0) {
0036 return -b2_spline_prime(-x);
0037 }
0038
0039 if (x < 1/Real(2))
0040 {
0041 return -2*x;
0042 }
0043 if (x < Real(3)/Real(2))
0044 {
0045 return x - Real(3)/Real(2);
0046 }
0047 return static_cast<Real>(0);
0048 }
0049
0050
0051 template <class Real>
0052 class cardinal_quadratic_b_spline_detail
0053 {
0054 public:
0055
0056
0057
0058 cardinal_quadratic_b_spline_detail(const Real* const y,
0059 size_t n,
0060 Real t0 ,
0061 Real h ,
0062 Real left_endpoint_derivative = std::numeric_limits<Real>::quiet_NaN(),
0063 Real right_endpoint_derivative = std::numeric_limits<Real>::quiet_NaN())
0064 {
0065 if (h <= 0) {
0066 throw std::logic_error("Spacing must be > 0.");
0067 }
0068 m_inv_h = 1/h;
0069 m_t0 = t0;
0070
0071 if (n < 3) {
0072 throw std::logic_error("The interpolator requires at least 3 points.");
0073 }
0074
0075 using std::isnan;
0076 Real a;
0077 if (isnan(left_endpoint_derivative)) {
0078
0079 a = -3*y[0] + 4*y[1] - y[2];
0080 }
0081 else {
0082 a = 2*h*left_endpoint_derivative;
0083 }
0084
0085 Real b;
0086 if (isnan(right_endpoint_derivative)) {
0087 b = 3*y[n-1] - 4*y[n-2] + y[n-3];
0088 }
0089 else {
0090 b = 2*h*right_endpoint_derivative;
0091 }
0092
0093 m_alpha.resize(n + 2);
0094
0095
0096 std::vector<Real> rhs(n + 2, std::numeric_limits<Real>::quiet_NaN());
0097 std::vector<Real> super_diagonal(n + 2, std::numeric_limits<Real>::quiet_NaN());
0098
0099 rhs[0] = -a;
0100 rhs[rhs.size() - 1] = b;
0101
0102 super_diagonal[0] = 0;
0103
0104 for(size_t i = 1; i < rhs.size() - 1; ++i) {
0105 rhs[i] = 8*y[i - 1];
0106 super_diagonal[i] = 1;
0107 }
0108
0109
0110 rhs[1] = (rhs[1] - rhs[0])/6;
0111 super_diagonal[1] = Real(1)/Real(3);
0112
0113
0114
0115
0116
0117
0118 for (size_t i = 2; i < rhs.size() - 1; ++i) {
0119 Real diagonal = 6 - super_diagonal[i - 1];
0120 rhs[i] = (rhs[i] - rhs[i - 1])/diagonal;
0121 super_diagonal[i] /= diagonal;
0122 }
0123
0124
0125
0126
0127
0128 rhs[n+1] = rhs[n+1] + rhs[n-1];
0129 Real bottom_subdiagonal = super_diagonal[n-1];
0130
0131
0132
0133
0134
0135
0136 rhs[n+1] = (rhs[n+1]-bottom_subdiagonal*rhs[n])/(1-bottom_subdiagonal*super_diagonal[n]);
0137
0138 m_alpha[n+1] = rhs[n+1];
0139 for (size_t i = n; i > 0; --i) {
0140 m_alpha[i] = rhs[i] - m_alpha[i+1]*super_diagonal[i];
0141 }
0142 m_alpha[0] = m_alpha[2] + rhs[0];
0143 }
0144
0145 Real operator()(Real t) const {
0146 if (t < m_t0 || t > m_t0 + (m_alpha.size()-2)/m_inv_h) {
0147 const char* err_msg = "Tried to evaluate the cardinal quadratic b-spline outside the domain of of interpolation; extrapolation does not work.";
0148 throw std::domain_error(err_msg);
0149 }
0150
0151
0152
0153
0154 using std::floor;
0155 using std::ceil;
0156 Real x = (t-m_t0)*m_inv_h;
0157 auto j_min = static_cast<size_t>(ceil(x - Real(1)/Real(2)));
0158 auto j_max = static_cast<size_t>(ceil(x + Real(5)/Real(2)));
0159 if (j_max >= m_alpha.size()) {
0160 j_max = m_alpha.size() - 1;
0161 }
0162
0163 Real y = 0;
0164 x += 1;
0165 for (size_t j = j_min; j <= j_max; ++j) {
0166 y += m_alpha[j]*detail::b2_spline(x - j);
0167 }
0168 return y;
0169 }
0170
0171 Real prime(Real t) const {
0172 if (t < m_t0 || t > m_t0 + (m_alpha.size()-2)/m_inv_h) {
0173 const char* err_msg = "Tried to evaluate the cardinal quadratic b-spline outside the domain of of interpolation; extrapolation does not work.";
0174 throw std::domain_error(err_msg);
0175 }
0176
0177
0178
0179
0180 using std::floor;
0181 using std::ceil;
0182 Real x = (t-m_t0)*m_inv_h;
0183 auto j_min = static_cast<size_t>(ceil(x - Real(1)/Real(2)));
0184 auto j_max = static_cast<size_t>(ceil(x + Real(5)/Real(2)));
0185 if (j_max >= m_alpha.size()) {
0186 j_max = m_alpha.size() - 1;
0187 }
0188
0189 Real y = 0;
0190 x += 1;
0191 for (size_t j = j_min; j <= j_max; ++j) {
0192 y += m_alpha[j]*detail::b2_spline_prime(x - j);
0193 }
0194 return y*m_inv_h;
0195 }
0196
0197 Real t_max() const {
0198 return m_t0 + (m_alpha.size()-3)/m_inv_h;
0199 }
0200
0201 private:
0202 std::vector<Real> m_alpha;
0203 Real m_inv_h;
0204 Real m_t0;
0205 };
0206
0207 }}}}
0208 #endif