File indexing completed on 2026-08-28 08:52:57
0001
0002
0003
0004
0005
0006
0007
0008 #ifndef BOOST_MATH_INTERPOLATORS_VECTOR_BARYCENTRIC_RATIONAL_DETAIL_HPP
0009 #define BOOST_MATH_INTERPOLATORS_VECTOR_BARYCENTRIC_RATIONAL_DETAIL_HPP
0010
0011 #include <cstdint>
0012 #include <cmath>
0013 #include <vector>
0014 #include <utility> // for std::move
0015 #include <limits>
0016 #include <algorithm>
0017 #include <boost/math/tools/assert.hpp>
0018
0019 namespace boost{ namespace math{ namespace interpolators{ namespace detail{
0020
0021 template <class TimeContainer, class SpaceContainer>
0022 class vector_barycentric_rational_imp
0023 {
0024 public:
0025 using Real = typename TimeContainer::value_type;
0026 using Point = typename SpaceContainer::value_type;
0027
0028 vector_barycentric_rational_imp(TimeContainer&& t, SpaceContainer&& y, size_t approximation_order);
0029
0030 void operator()(Point& p, Real t) const;
0031
0032 void eval_with_prime(Point& x, Point& dxdt, Real t) const;
0033
0034
0035 Real weight(size_t i) const { return w_[i]; }
0036
0037 private:
0038
0039 void calculate_weights(size_t approximation_order);
0040
0041 TimeContainer t_;
0042 SpaceContainer y_;
0043 TimeContainer w_;
0044 };
0045
0046 template <class TimeContainer, class SpaceContainer>
0047 vector_barycentric_rational_imp<TimeContainer, SpaceContainer>::vector_barycentric_rational_imp(TimeContainer&& t, SpaceContainer&& y, size_t approximation_order)
0048 {
0049 using std::numeric_limits;
0050 t_ = std::move(t);
0051 y_ = std::move(y);
0052
0053 BOOST_MATH_ASSERT_MSG(t_.size() == y_.size(), "There must be the same number of time points as space points.");
0054 BOOST_MATH_ASSERT_MSG(approximation_order < y_.size(), "Approximation order must be < data length.");
0055 for (size_t i = 1; i < t_.size(); ++i)
0056 {
0057 BOOST_MATH_ASSERT_MSG(t_[i] - t_[i-1] > (numeric_limits<typename TimeContainer::value_type>::min)(), "The abscissas must be listed in strictly increasing order t[0] < t[1] < ... < t[n-1].");
0058 }
0059 calculate_weights(approximation_order);
0060 }
0061
0062
0063 template<class TimeContainer, class SpaceContainer>
0064 void vector_barycentric_rational_imp<TimeContainer, SpaceContainer>::calculate_weights(size_t approximation_order)
0065 {
0066 using Real = typename TimeContainer::value_type;
0067 using std::abs;
0068 std::int64_t n = t_.size();
0069 w_.resize(n, Real(0));
0070 for(std::int64_t k = 0; k < n; ++k)
0071 {
0072 std::int64_t i_min = (std::max)(k - static_cast<std::int64_t>(approximation_order), static_cast<std::int64_t>(0));
0073 std::int64_t i_max = k;
0074 if (k >= n - (std::ptrdiff_t)approximation_order)
0075 {
0076 i_max = n - approximation_order - 1;
0077 }
0078
0079 for(std::int64_t i = i_min; i <= i_max; ++i)
0080 {
0081 Real inv_product = 1;
0082 std::int64_t j_max = (std::min)(static_cast<std::int64_t>(i + approximation_order), static_cast<std::int64_t>(n - 1));
0083 for(std::int64_t j = i; j <= j_max; ++j)
0084 {
0085 if (j == k)
0086 {
0087 continue;
0088 }
0089 Real diff = t_[k] - t_[j];
0090 inv_product *= diff;
0091 }
0092 if (i % 2 == 0)
0093 {
0094 w_[k] += 1/inv_product;
0095 }
0096 else
0097 {
0098 w_[k] -= 1/inv_product;
0099 }
0100 }
0101 }
0102 }
0103
0104
0105 template<class TimeContainer, class SpaceContainer>
0106 void vector_barycentric_rational_imp<TimeContainer, SpaceContainer>::operator()(typename SpaceContainer::value_type& p, typename TimeContainer::value_type t) const
0107 {
0108 using Real = typename TimeContainer::value_type;
0109 for (auto & x : p)
0110 {
0111 x = Real(0);
0112 }
0113 Real denominator = 0;
0114 for(size_t i = 0; i < t_.size(); ++i)
0115 {
0116
0117 if (t == t_[i])
0118 {
0119 p = y_[i];
0120 return;
0121 }
0122 Real x = w_[i]/(t - t_[i]);
0123 for (decltype(p.size()) j = 0; j < p.size(); ++j)
0124 {
0125 p[j] += x*y_[i][j];
0126 }
0127 denominator += x;
0128 }
0129 for (decltype(p.size()) j = 0; j < p.size(); ++j)
0130 {
0131 p[j] /= denominator;
0132 }
0133 return;
0134 }
0135
0136 template<class TimeContainer, class SpaceContainer>
0137 void vector_barycentric_rational_imp<TimeContainer, SpaceContainer>::eval_with_prime(typename SpaceContainer::value_type& x, typename SpaceContainer::value_type& dxdt, typename TimeContainer::value_type t) const
0138 {
0139 using Point = typename SpaceContainer::value_type;
0140 using Real = typename TimeContainer::value_type;
0141 this->operator()(x, t);
0142 Point numerator;
0143 for (decltype(x.size()) i = 0; i < x.size(); ++i)
0144 {
0145 numerator[i] = 0;
0146 }
0147 Real denominator = 0;
0148 for(decltype(t_.size()) i = 0; i < t_.size(); ++i)
0149 {
0150 if (t == t_[i])
0151 {
0152 Point sum;
0153 for (decltype(x.size()) i = 0; i < x.size(); ++i)
0154 {
0155 sum[i] = 0;
0156 }
0157
0158 for (decltype(t_.size()) j = 0; j < t_.size(); ++j)
0159 {
0160 if (j == i)
0161 {
0162 continue;
0163 }
0164 for (decltype(sum.size()) k = 0; k < sum.size(); ++k)
0165 {
0166 sum[k] += w_[j]*(y_[i][k] - y_[j][k])/(t_[i] - t_[j]);
0167 }
0168 }
0169 for (decltype(sum.size()) k = 0; k < sum.size(); ++k)
0170 {
0171 dxdt[k] = -sum[k]/w_[i];
0172 }
0173 return;
0174 }
0175 Real tw = w_[i]/(t - t_[i]);
0176 Point diff;
0177 for (decltype(diff.size()) j = 0; j < diff.size(); ++j)
0178 {
0179 diff[j] = (x[j] - y_[i][j])/(t-t_[i]);
0180 }
0181 for (decltype(diff.size()) j = 0; j < diff.size(); ++j)
0182 {
0183 numerator[j] += tw*diff[j];
0184 }
0185 denominator += tw;
0186 }
0187
0188 for (decltype(dxdt.size()) j = 0; j < dxdt.size(); ++j)
0189 {
0190 dxdt[j] = numerator[j]/denominator;
0191 }
0192 return;
0193 }
0194
0195 }}}}
0196 #endif