vector_barycentric_rational_detail.hpp 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. /*
  2. * Copyright Nick Thompson, 2019
  3. * Use, modification and distribution are subject to the
  4. * Boost Software License, Version 1.0. (See accompanying file
  5. * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. */
  7. #ifndef BOOST_MATH_INTERPOLATORS_VECTOR_BARYCENTRIC_RATIONAL_DETAIL_HPP
  8. #define BOOST_MATH_INTERPOLATORS_VECTOR_BARYCENTRIC_RATIONAL_DETAIL_HPP
  9. #include <vector>
  10. #include <utility> // for std::move
  11. #include <boost/assert.hpp>
  12. namespace boost{ namespace math{ namespace detail{
  13. template <class TimeContainer, class SpaceContainer>
  14. class vector_barycentric_rational_imp
  15. {
  16. public:
  17. using Real = typename TimeContainer::value_type;
  18. using Point = typename SpaceContainer::value_type;
  19. vector_barycentric_rational_imp(TimeContainer&& t, SpaceContainer&& y, size_t approximation_order);
  20. void operator()(Point& p, Real t) const;
  21. void eval_with_prime(Point& x, Point& dxdt, Real t) const;
  22. // The barycentric weights are only interesting to the unit tests:
  23. Real weight(size_t i) const { return w_[i]; }
  24. private:
  25. void calculate_weights(size_t approximation_order);
  26. TimeContainer t_;
  27. SpaceContainer y_;
  28. TimeContainer w_;
  29. };
  30. template <class TimeContainer, class SpaceContainer>
  31. vector_barycentric_rational_imp<TimeContainer, SpaceContainer>::vector_barycentric_rational_imp(TimeContainer&& t, SpaceContainer&& y, size_t approximation_order)
  32. {
  33. using std::numeric_limits;
  34. t_ = std::move(t);
  35. y_ = std::move(y);
  36. BOOST_ASSERT_MSG(t_.size() == y_.size(), "There must be the same number of time points as space points.");
  37. BOOST_ASSERT_MSG(approximation_order < y_.size(), "Approximation order must be < data length.");
  38. for (size_t i = 1; i < t_.size(); ++i)
  39. {
  40. BOOST_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].");
  41. }
  42. calculate_weights(approximation_order);
  43. }
  44. template<class TimeContainer, class SpaceContainer>
  45. void vector_barycentric_rational_imp<TimeContainer, SpaceContainer>::calculate_weights(size_t approximation_order)
  46. {
  47. using Real = typename TimeContainer::value_type;
  48. using std::abs;
  49. int64_t n = t_.size();
  50. w_.resize(n, Real(0));
  51. for(int64_t k = 0; k < n; ++k)
  52. {
  53. int64_t i_min = (std::max)(k - (int64_t) approximation_order, (int64_t) 0);
  54. int64_t i_max = k;
  55. if (k >= n - (std::ptrdiff_t)approximation_order)
  56. {
  57. i_max = n - approximation_order - 1;
  58. }
  59. for(int64_t i = i_min; i <= i_max; ++i)
  60. {
  61. Real inv_product = 1;
  62. int64_t j_max = (std::min)(static_cast<int64_t>(i + approximation_order), static_cast<int64_t>(n - 1));
  63. for(int64_t j = i; j <= j_max; ++j)
  64. {
  65. if (j == k)
  66. {
  67. continue;
  68. }
  69. Real diff = t_[k] - t_[j];
  70. inv_product *= diff;
  71. }
  72. if (i % 2 == 0)
  73. {
  74. w_[k] += 1/inv_product;
  75. }
  76. else
  77. {
  78. w_[k] -= 1/inv_product;
  79. }
  80. }
  81. }
  82. }
  83. template<class TimeContainer, class SpaceContainer>
  84. void vector_barycentric_rational_imp<TimeContainer, SpaceContainer>::operator()(typename SpaceContainer::value_type& p, typename TimeContainer::value_type t) const
  85. {
  86. using Real = typename TimeContainer::value_type;
  87. for (auto & x : p)
  88. {
  89. x = Real(0);
  90. }
  91. Real denominator = 0;
  92. for(size_t i = 0; i < t_.size(); ++i)
  93. {
  94. // See associated commentary in the scalar version of this function.
  95. if (t == t_[i])
  96. {
  97. p = y_[i];
  98. return;
  99. }
  100. Real x = w_[i]/(t - t_[i]);
  101. for (decltype(p.size()) j = 0; j < p.size(); ++j)
  102. {
  103. p[j] += x*y_[i][j];
  104. }
  105. denominator += x;
  106. }
  107. for (decltype(p.size()) j = 0; j < p.size(); ++j)
  108. {
  109. p[j] /= denominator;
  110. }
  111. return;
  112. }
  113. template<class TimeContainer, class SpaceContainer>
  114. 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
  115. {
  116. using Point = typename SpaceContainer::value_type;
  117. using Real = typename TimeContainer::value_type;
  118. this->operator()(x, t);
  119. Point numerator;
  120. for (decltype(x.size()) i = 0; i < x.size(); ++i)
  121. {
  122. numerator[i] = 0;
  123. }
  124. Real denominator = 0;
  125. for(decltype(t_.size()) i = 0; i < t_.size(); ++i)
  126. {
  127. if (t == t_[i])
  128. {
  129. Point sum;
  130. for (decltype(x.size()) i = 0; i < x.size(); ++i)
  131. {
  132. sum[i] = 0;
  133. }
  134. for (decltype(t_.size()) j = 0; j < t_.size(); ++j)
  135. {
  136. if (j == i)
  137. {
  138. continue;
  139. }
  140. for (decltype(sum.size()) k = 0; k < sum.size(); ++k)
  141. {
  142. sum[k] += w_[j]*(y_[i][k] - y_[j][k])/(t_[i] - t_[j]);
  143. }
  144. }
  145. for (decltype(sum.size()) k = 0; k < sum.size(); ++k)
  146. {
  147. dxdt[k] = -sum[k]/w_[i];
  148. }
  149. return;
  150. }
  151. Real tw = w_[i]/(t - t_[i]);
  152. Point diff;
  153. for (decltype(diff.size()) j = 0; j < diff.size(); ++j)
  154. {
  155. diff[j] = (x[j] - y_[i][j])/(t-t_[i]);
  156. }
  157. for (decltype(diff.size()) j = 0; j < diff.size(); ++j)
  158. {
  159. numerator[j] += tw*diff[j];
  160. }
  161. denominator += tw;
  162. }
  163. for (decltype(dxdt.size()) j = 0; j < dxdt.size(); ++j)
  164. {
  165. dxdt[j] = numerator[j]/denominator;
  166. }
  167. return;
  168. }
  169. }}}
  170. #endif