Warning, file /include/boost/math/interpolators/detail/cardinal_cubic_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_CUBIC_B_SPLINE_DETAIL_HPP
0008 #define BOOST_MATH_INTERPOLATORS_CARDINAL_CUBIC_B_SPLINE_DETAIL_HPP
0009
0010 #include <limits>
0011 #include <cmath>
0012 #include <vector>
0013 #include <memory>
0014 #include <boost/math/constants/constants.hpp>
0015 #include <boost/math/special_functions/fpclassify.hpp>
0016 #include <boost/math/special_functions/trunc.hpp>
0017
0018 namespace boost{ namespace math{ namespace interpolators{ namespace detail{
0019
0020
0021 template <class Real>
0022 class cardinal_cubic_b_spline_imp
0023 {
0024 public:
0025
0026
0027 template <class BidiIterator>
0028 cardinal_cubic_b_spline_imp(BidiIterator f, BidiIterator end_p, Real left_endpoint, Real step_size,
0029 Real left_endpoint_derivative = std::numeric_limits<Real>::quiet_NaN(),
0030 Real right_endpoint_derivative = std::numeric_limits<Real>::quiet_NaN());
0031
0032 Real operator()(Real x) const;
0033
0034 Real prime(Real x) const;
0035
0036 Real double_prime(Real x) const;
0037
0038 private:
0039 std::vector<Real> m_beta;
0040 Real m_h_inv;
0041 Real m_a;
0042 Real m_avg;
0043 };
0044
0045
0046
0047 template <class Real>
0048 Real b3_spline(Real x)
0049 {
0050 using std::abs;
0051 Real absx = abs(x);
0052 if (absx < 1)
0053 {
0054 Real y = 2 - absx;
0055 Real z = 1 - absx;
0056 return boost::math::constants::sixth<Real>()*(y*y*y - 4*z*z*z);
0057 }
0058 if (absx < 2)
0059 {
0060 Real y = 2 - absx;
0061 return boost::math::constants::sixth<Real>()*y*y*y;
0062 }
0063 return static_cast<Real>(0);
0064 }
0065
0066 template<class Real>
0067 Real b3_spline_prime(Real x)
0068 {
0069 if (x < 0)
0070 {
0071 return -b3_spline_prime(-x);
0072 }
0073
0074 if (x < 1)
0075 {
0076 return x*(3*boost::math::constants::half<Real>()*x - 2);
0077 }
0078 if (x < 2)
0079 {
0080 return -boost::math::constants::half<Real>()*(2 - x)*(2 - x);
0081 }
0082 return static_cast<Real>(0);
0083 }
0084
0085 template<class Real>
0086 Real b3_spline_double_prime(Real x)
0087 {
0088 if (x < 0)
0089 {
0090 return b3_spline_double_prime(-x);
0091 }
0092
0093 if (x < 1)
0094 {
0095 return 3*x - 2;
0096 }
0097 if (x < 2)
0098 {
0099 return (2 - x);
0100 }
0101 return static_cast<Real>(0);
0102 }
0103
0104
0105 template <class Real>
0106 template <class BidiIterator>
0107 cardinal_cubic_b_spline_imp<Real>::cardinal_cubic_b_spline_imp(BidiIterator f, BidiIterator end_p, Real left_endpoint, Real step_size,
0108 Real left_endpoint_derivative, Real right_endpoint_derivative) : m_a(left_endpoint), m_avg(0)
0109 {
0110 using boost::math::constants::third;
0111
0112 std::size_t length = end_p - f;
0113
0114 if (length < 5)
0115 {
0116 if (boost::math::isnan(left_endpoint_derivative) || boost::math::isnan(right_endpoint_derivative))
0117 {
0118 throw std::logic_error("Interpolation using a cubic b spline with derivatives estimated at the endpoints requires at least 5 points.\n");
0119 }
0120 if (length < 3)
0121 {
0122 throw std::logic_error("Interpolation using a cubic b spline requires at least 3 points.\n");
0123 }
0124 }
0125
0126 if (boost::math::isnan(left_endpoint))
0127 {
0128 throw std::logic_error("Left endpoint is NAN; this is disallowed.\n");
0129 }
0130 if (left_endpoint + length*step_size >= (std::numeric_limits<Real>::max)())
0131 {
0132 throw std::logic_error("Right endpoint overflows the maximum representable number of the specified precision.\n");
0133 }
0134 if (step_size <= 0)
0135 {
0136 throw std::logic_error("The step size must be strictly > 0.\n");
0137 }
0138
0139
0140 m_h_inv = 1/step_size;
0141
0142
0143 Real a1 = left_endpoint_derivative;
0144
0145
0146
0147
0148 if (boost::math::isnan(a1))
0149 {
0150
0151
0152
0153 Real t0 = 4*(f[1] + third<Real>()*f[3]);
0154 Real t1 = -(25*third<Real>()*f[0] + f[4])/4 - 3*f[2];
0155 a1 = m_h_inv*(t0 + t1);
0156 }
0157
0158 Real b1 = right_endpoint_derivative;
0159 if (boost::math::isnan(b1))
0160 {
0161 size_t n = length - 1;
0162 Real t0 = -4*(f[n - 1] + third<Real>()*f[n - 3]);
0163 Real t1 = (25*third<Real>()*f[n] + f[n - 4])/4 + 3*f[n - 2];
0164
0165 b1 = m_h_inv*(t0 + t1);
0166 }
0167
0168
0169
0170 m_beta.resize(length + 2, std::numeric_limits<Real>::quiet_NaN());
0171
0172
0173
0174
0175
0176
0177
0178 Real t = 1;
0179 for (size_t i = 0; i < length; ++i)
0180 {
0181 if (boost::math::isnan(f[i]))
0182 {
0183 std::string err = "This function you are trying to interpolate is a nan at index " + std::to_string(i) + "\n";
0184 throw std::logic_error(err);
0185 }
0186 m_avg += (f[i] - m_avg) / t;
0187 t += 1;
0188 }
0189
0190
0191
0192
0193
0194
0195
0196
0197
0198
0199
0200
0201
0202
0203
0204 std::vector<Real> rhs(length + 2, std::numeric_limits<Real>::quiet_NaN());
0205 std::vector<Real> super_diagonal(length + 2, std::numeric_limits<Real>::quiet_NaN());
0206
0207 rhs[0] = -2*step_size*a1;
0208 rhs[rhs.size() - 1] = -2*step_size*b1;
0209
0210 super_diagonal[0] = 0;
0211
0212 for(size_t i = 1; i < rhs.size() - 1; ++i)
0213 {
0214 rhs[i] = 6*(f[i - 1] - m_avg);
0215 super_diagonal[i] = 1;
0216 }
0217
0218
0219
0220
0221
0222
0223
0224
0225
0226
0227
0228 super_diagonal[1] = static_cast<Real>(0.5);
0229 rhs[1] = (rhs[1] - rhs[0])/4;
0230
0231
0232 for (size_t i = 2; i < rhs.size() - 1; ++i)
0233 {
0234 Real diagonal = 4 - super_diagonal[i - 1];
0235 rhs[i] = (rhs[i] - rhs[i - 1])/diagonal;
0236 super_diagonal[i] /= diagonal;
0237 }
0238
0239
0240
0241
0242
0243 Real final_subdiag = -super_diagonal[rhs.size() - 3];
0244 rhs[rhs.size() - 1] = (rhs[rhs.size() - 1] - rhs[rhs.size() - 3])/final_subdiag;
0245 Real final_diag = -1/final_subdiag;
0246
0247
0248
0249
0250
0251 final_diag = final_diag - super_diagonal[rhs.size() - 2];
0252 rhs[rhs.size() - 1] = rhs[rhs.size() - 1] - rhs[rhs.size() - 2];
0253
0254
0255
0256 m_beta[rhs.size() - 1] = rhs[rhs.size() - 1]/final_diag;
0257 for(size_t i = rhs.size() - 2; i > 0; --i)
0258 {
0259 m_beta[i] = rhs[i] - super_diagonal[i]*m_beta[i + 1];
0260 }
0261 m_beta[0] = m_beta[2] + rhs[0];
0262 }
0263
0264 template<class Real>
0265 Real cardinal_cubic_b_spline_imp<Real>::operator()(Real x) const
0266 {
0267
0268
0269 Real z = m_avg;
0270 Real t = m_h_inv*(x - m_a) + 1;
0271
0272 using std::max;
0273 using std::min;
0274 using std::ceil;
0275 using std::floor;
0276
0277 size_t k_min = static_cast<size_t>((max)(static_cast<long>(0), boost::math::ltrunc(ceil(t - 2))));
0278 size_t k_max = static_cast<size_t>((max)((min)(static_cast<long>(m_beta.size() - 1), boost::math::ltrunc(floor(t + 2))), 0l));
0279
0280 for (size_t k = k_min; k <= k_max; ++k)
0281 {
0282 z += m_beta[k]*b3_spline(t - k);
0283 }
0284
0285 return z;
0286 }
0287
0288 template<class Real>
0289 Real cardinal_cubic_b_spline_imp<Real>::prime(Real x) const
0290 {
0291 Real z = 0;
0292 Real t = m_h_inv*(x - m_a) + 1;
0293
0294 using std::max;
0295 using std::min;
0296 using std::ceil;
0297 using std::floor;
0298
0299 size_t k_min = static_cast<size_t>((max)(static_cast<long>(0), boost::math::ltrunc(ceil(t - 2))));
0300 size_t k_max = static_cast<size_t>((min)(static_cast<long>(m_beta.size() - 1), boost::math::ltrunc(floor(t + 2))));
0301
0302 for (size_t k = k_min; k <= k_max; ++k)
0303 {
0304 z += m_beta[k]*b3_spline_prime(t - k);
0305 }
0306 return z*m_h_inv;
0307 }
0308
0309 template<class Real>
0310 Real cardinal_cubic_b_spline_imp<Real>::double_prime(Real x) const
0311 {
0312 Real z = 0;
0313 Real t = m_h_inv*(x - m_a) + 1;
0314
0315 using std::max;
0316 using std::min;
0317 using std::ceil;
0318 using std::floor;
0319
0320 size_t k_min = static_cast<size_t>((max)(static_cast<long>(0), boost::math::ltrunc(ceil(t - 2))));
0321 size_t k_max = static_cast<size_t>((min)(static_cast<long>(m_beta.size() - 1), boost::math::ltrunc(floor(t + 2))));
0322
0323 for (size_t k = k_min; k <= k_max; ++k)
0324 {
0325 z += m_beta[k]*b3_spline_double_prime(t - k);
0326 }
0327 return z*m_h_inv*m_h_inv;
0328 }
0329
0330 }}}}
0331 #endif