Commit dec10b52 by d_a_heitbrink

grabbed latest spline libs from BOOST, these are only in dev branch as of 4.1.2020

parent 27c3e34d
/*
* Copyright Nick Thompson, 2017
* Use, modification and distribution are subject to the
* Boost Software License, Version 1.0. (See accompanying file
* LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*
* Given N samples (t_i, y_i) which are irregularly spaced, this routine constructs an
* interpolant s which is constructed in O(N) time, occupies O(N) space, and can be evaluated in O(N) time.
* The interpolation is stable, unless one point is incredibly close to another, and the next point is incredibly far.
* The measure of this stability is the "local mesh ratio", which can be queried from the routine.
* Pictorially, the following t_i spacing is bad (has a high local mesh ratio)
* || | | | |
* and this t_i spacing is good (has a low local mesh ratio)
* | | | | | | | | | |
*
*
* If f is C^{d+2}, then the interpolant is O(h^(d+1)) accurate, where d is the interpolation order.
* A disadvantage of this interpolant is that it does not reproduce rational functions; for example, 1/(1+x^2) is not interpolated exactly.
*
* References:
* Floater, Michael S., and Kai Hormann. "Barycentric rational interpolation with no poles and high rates of approximation." Numerische Mathematik 107.2 (2007): 315-331.
* Press, William H., et al. "Numerical recipes third edition: the art of scientific computing." Cambridge University Press 32 (2007): 10013-2473.
*/
#ifndef BOOST_MATH_INTERPOLATORS_BARYCENTRIC_RATIONAL_HPP
#define BOOST_MATH_INTERPOLATORS_BARYCENTRIC_RATIONAL_HPP
#include <memory>
#include <boost/math/interpolators/detail/barycentric_rational_detail.hpp>
namespace boost{ namespace math{
template<class Real>
class barycentric_rational
{
public:
barycentric_rational(const Real* const x, const Real* const y, size_t n, size_t approximation_order = 3);
barycentric_rational(std::vector<Real>&& x, std::vector<Real>&& y, size_t approximation_order = 3);
template <class InputIterator1, class InputIterator2>
barycentric_rational(InputIterator1 start_x, InputIterator1 end_x, InputIterator2 start_y, size_t approximation_order = 3, typename boost::disable_if_c<boost::is_integral<InputIterator2>::value>::type* = 0);
Real operator()(Real x) const;
Real prime(Real x) const;
std::vector<Real>&& return_x()
{
return m_imp->return_x();
}
std::vector<Real>&& return_y()
{
return m_imp->return_y();
}
private:
std::shared_ptr<detail::barycentric_rational_imp<Real>> m_imp;
};
template <class Real>
barycentric_rational<Real>::barycentric_rational(const Real* const x, const Real* const y, size_t n, size_t approximation_order):
m_imp(std::make_shared<detail::barycentric_rational_imp<Real>>(x, x + n, y, approximation_order))
{
return;
}
template <class Real>
barycentric_rational<Real>::barycentric_rational(std::vector<Real>&& x, std::vector<Real>&& y, size_t approximation_order):
m_imp(std::make_shared<detail::barycentric_rational_imp<Real>>(std::move(x), std::move(y), approximation_order))
{
return;
}
template <class Real>
template <class InputIterator1, class InputIterator2>
barycentric_rational<Real>::barycentric_rational(InputIterator1 start_x, InputIterator1 end_x, InputIterator2 start_y, size_t approximation_order, typename boost::disable_if_c<boost::is_integral<InputIterator2>::value>::type*)
: m_imp(std::make_shared<detail::barycentric_rational_imp<Real>>(start_x, end_x, start_y, approximation_order))
{
}
template<class Real>
Real barycentric_rational<Real>::operator()(Real x) const
{
return m_imp->operator()(x);
}
template<class Real>
Real barycentric_rational<Real>::prime(Real x) const
{
return m_imp->prime(x);
}
}}
#endif
/*
* Copyright Nick Thompson, 2017
* Use, modification and distribution are subject to the
* Boost Software License, Version 1.0. (See accompanying file
* LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*
* Given N samples (t_i, y_i) which are irregularly spaced, this routine constructs an
* interpolant s which is constructed in O(N) time, occupies O(N) space, and can be evaluated in O(N) time.
* The interpolation is stable, unless one point is incredibly close to another, and the next point is incredibly far.
* The measure of this stability is the "local mesh ratio", which can be queried from the routine.
* Pictorially, the following t_i spacing is bad (has a high local mesh ratio)
* || | | | |
* and this t_i spacing is good (has a low local mesh ratio)
* | | | | | | | | | |
*
*
* If f is C^{d+2}, then the interpolant is O(h^(d+1)) accurate, where d is the interpolation order.
* A disadvantage of this interpolant is that it does not reproduce rational functions; for example, 1/(1+x^2) is not interpolated exactly.
*
* References:
* Floater, Michael S., and Kai Hormann. "Barycentric rational interpolation with no poles and high rates of approximation."
* Numerische Mathematik 107.2 (2007): 315-331.
* Press, William H., et al. "Numerical recipes third edition: the art of scientific computing." Cambridge University Press 32 (2007): 10013-2473.
*/
#ifndef BOOST_MATH_INTERPOLATORS_BARYCENTRIC_RATIONAL_HPP
#define BOOST_MATH_INTERPOLATORS_BARYCENTRIC_RATIONAL_HPP
#include <memory>
#include <boost/math/interpolators/detail/barycentric_rational_detail.hpp>
namespace boost{ namespace math{
template<class Real>
class barycentric_rational
{
public:
barycentric_rational(const Real* const x, const Real* const y, size_t n, size_t approximation_order = 3);
barycentric_rational(std::vector<Real>&& x, std::vector<Real>&& y, size_t approximation_order = 3);
template <class InputIterator1, class InputIterator2>
barycentric_rational(InputIterator1 start_x, InputIterator1 end_x, InputIterator2 start_y, size_t approximation_order = 3, typename boost::disable_if_c<boost::is_integral<InputIterator2>::value>::type* = 0);
Real operator()(Real x) const;
Real prime(Real x) const;
std::vector<Real>&& return_x()
{
return m_imp->return_x();
}
std::vector<Real>&& return_y()
{
return m_imp->return_y();
}
private:
std::shared_ptr<detail::barycentric_rational_imp<Real>> m_imp;
};
template <class Real>
barycentric_rational<Real>::barycentric_rational(const Real* const x, const Real* const y, size_t n, size_t approximation_order):
m_imp(std::make_shared<detail::barycentric_rational_imp<Real>>(x, x + n, y, approximation_order))
{
return;
}
template <class Real>
barycentric_rational<Real>::barycentric_rational(std::vector<Real>&& x, std::vector<Real>&& y, size_t approximation_order):
m_imp(std::make_shared<detail::barycentric_rational_imp<Real>>(std::move(x), std::move(y), approximation_order))
{
return;
}
template <class Real>
template <class InputIterator1, class InputIterator2>
barycentric_rational<Real>::barycentric_rational(InputIterator1 start_x, InputIterator1 end_x, InputIterator2 start_y, size_t approximation_order, typename boost::disable_if_c<boost::is_integral<InputIterator2>::value>::type*)
: m_imp(std::make_shared<detail::barycentric_rational_imp<Real>>(start_x, end_x, start_y, approximation_order))
{
}
template<class Real>
Real barycentric_rational<Real>::operator()(Real x) const
{
return m_imp->operator()(x);
}
template<class Real>
Real barycentric_rational<Real>::prime(Real x) const
{
return m_imp->prime(x);
}
}}
#endif
// Copyright Nick Thompson, 2017
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)
// This implements the compactly supported cubic b spline algorithm described in
// Kress, Rainer. "Numerical analysis, volume 181 of Graduate Texts in Mathematics." (1998).
// Splines of compact support are faster to evaluate and are better conditioned than classical cubic splines.
// Let f be the function we are trying to interpolate, and s be the interpolating spline.
// The routine constructs the interpolant in O(N) time, and evaluating s at a point takes constant time.
// The order of accuracy depends on the regularity of the f, however, assuming f is
// four-times continuously differentiable, the error is of O(h^4).
// In addition, we can differentiate the spline and obtain a good interpolant for f'.
// The main restriction of this method is that the samples of f must be evenly spaced.
// Look for barycentric rational interpolation for non-evenly sampled data.
// Properties:
// - s(x_j) = f(x_j)
// - All cubic polynomials interpolated exactly
#ifndef BOOST_MATH_INTERPOLATORS_CARDINAL_CUBIC_B_SPLINE_HPP
#define BOOST_MATH_INTERPOLATORS_CARDINAL_CUBIC_B_SPLINE_HPP
#include <boost/math/interpolators/detail/cardinal_cubic_b_spline_detail.hpp>
namespace boost{ namespace math{ namespace interpolators {
template <class Real>
class cardinal_cubic_b_spline
{
public:
// If you don't know the value of the derivative at the endpoints, leave them as nans and the routine will estimate them.
// f[0] = f(a), f[length -1] = b, step_size = (b - a)/(length -1).
template <class BidiIterator>
cardinal_cubic_b_spline(const BidiIterator f, BidiIterator end_p, Real left_endpoint, Real step_size,
Real left_endpoint_derivative = std::numeric_limits<Real>::quiet_NaN(),
Real right_endpoint_derivative = std::numeric_limits<Real>::quiet_NaN());
cardinal_cubic_b_spline(const Real* const f, size_t length, Real left_endpoint, Real step_size,
Real left_endpoint_derivative = std::numeric_limits<Real>::quiet_NaN(),
Real right_endpoint_derivative = std::numeric_limits<Real>::quiet_NaN());
cardinal_cubic_b_spline() = default;
Real operator()(Real x) const;
Real prime(Real x) const;
Real double_prime(Real x) const;
private:
std::shared_ptr<detail::cardinal_cubic_b_spline_imp<Real>> m_imp;
};
template<class Real>
cardinal_cubic_b_spline<Real>::cardinal_cubic_b_spline(const Real* const f, size_t length, Real left_endpoint, Real step_size,
Real left_endpoint_derivative, Real right_endpoint_derivative) : m_imp(std::make_shared<detail::cardinal_cubic_b_spline_imp<Real>>(f, f + length, left_endpoint, step_size, left_endpoint_derivative, right_endpoint_derivative))
{
}
template <class Real>
template <class BidiIterator>
cardinal_cubic_b_spline<Real>::cardinal_cubic_b_spline(BidiIterator f, BidiIterator end_p, Real left_endpoint, Real step_size,
Real left_endpoint_derivative, Real right_endpoint_derivative) : m_imp(std::make_shared<detail::cardinal_cubic_b_spline_imp<Real>>(f, end_p, left_endpoint, step_size, left_endpoint_derivative, right_endpoint_derivative))
{
}
template<class Real>
Real cardinal_cubic_b_spline<Real>::operator()(Real x) const
{
return m_imp->operator()(x);
}
template<class Real>
Real cardinal_cubic_b_spline<Real>::prime(Real x) const
{
return m_imp->prime(x);
}
template<class Real>
Real cardinal_cubic_b_spline<Real>::double_prime(Real x) const
{
return m_imp->double_prime(x);
}
}}}
#endif
// Copyright Nick Thompson, 2019
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_MATH_INTERPOLATORS_CARDINAL_QUADRATIC_B_SPLINE_HPP
#define BOOST_MATH_INTERPOLATORS_CARDINAL_QUADRATIC_B_SPLINE_HPP
#include <memory>
#include <boost/math/interpolators/detail/cardinal_quadratic_b_spline_detail.hpp>
namespace boost{ namespace math{ namespace interpolators {
template <class Real>
class cardinal_quadratic_b_spline
{
public:
// If you don't know the value of the derivative at the endpoints, leave them as nans and the routine will estimate them.
// y[0] = y(a), y[n - 1] = y(b), step_size = (b - a)/(n -1).
cardinal_quadratic_b_spline(const Real* const y,
size_t n,
Real t0 /* initial time, left endpoint */,
Real h /*spacing, stepsize*/,
Real left_endpoint_derivative = std::numeric_limits<Real>::quiet_NaN(),
Real right_endpoint_derivative = std::numeric_limits<Real>::quiet_NaN())
: impl_(std::make_shared<detail::cardinal_quadratic_b_spline_detail<Real>>(y, n, t0, h, left_endpoint_derivative, right_endpoint_derivative))
{}
// Oh the bizarre error messages if we template this on a RandomAccessContainer:
cardinal_quadratic_b_spline(std::vector<Real> const & y,
Real t0 /* initial time, left endpoint */,
Real h /*spacing, stepsize*/,
Real left_endpoint_derivative = std::numeric_limits<Real>::quiet_NaN(),
Real right_endpoint_derivative = std::numeric_limits<Real>::quiet_NaN())
: impl_(std::make_shared<detail::cardinal_quadratic_b_spline_detail<Real>>(y.data(), y.size(), t0, h, left_endpoint_derivative, right_endpoint_derivative))
{}
Real operator()(Real t) const {
return impl_->operator()(t);
}
Real prime(Real t) const {
return impl_->prime(t);
}
Real t_max() const {
return impl_->t_max();
}
private:
std::shared_ptr<detail::cardinal_quadratic_b_spline_detail<Real>> impl_;
};
}}}
#endif
// Copyright Nick Thompson, 2019
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_MATH_INTERPOLATORS_CARDINAL_QUINTIC_B_SPLINE_HPP
#define BOOST_MATH_INTERPOLATORS_CARDINAL_QUINTIC_B_SPLINE_HPP
#include <memory>
#include <limits>
#include <boost/math/interpolators/detail/cardinal_quintic_b_spline_detail.hpp>
namespace boost{ namespace math{ namespace interpolators {
template <class Real>
class cardinal_quintic_b_spline
{
public:
// If you don't know the value of the derivative at the endpoints, leave them as nans and the routine will estimate them.
// y[0] = y(a), y[n - 1] = y(b), step_size = (b - a)/(n -1).
cardinal_quintic_b_spline(const Real* const y,
size_t n,
Real t0 /* initial time, left endpoint */,
Real h /*spacing, stepsize*/,
std::pair<Real, Real> left_endpoint_derivatives = {std::numeric_limits<Real>::quiet_NaN(), std::numeric_limits<Real>::quiet_NaN()},
std::pair<Real, Real> right_endpoint_derivatives = {std::numeric_limits<Real>::quiet_NaN(), std::numeric_limits<Real>::quiet_NaN()})
: impl_(std::make_shared<detail::cardinal_quintic_b_spline_detail<Real>>(y, n, t0, h, left_endpoint_derivatives, right_endpoint_derivatives))
{}
// Oh the bizarre error messages if we template this on a RandomAccessContainer:
cardinal_quintic_b_spline(std::vector<Real> const & y,
Real t0 /* initial time, left endpoint */,
Real h /*spacing, stepsize*/,
std::pair<Real, Real> left_endpoint_derivatives = {std::numeric_limits<Real>::quiet_NaN(), std::numeric_limits<Real>::quiet_NaN()},
std::pair<Real, Real> right_endpoint_derivatives = {std::numeric_limits<Real>::quiet_NaN(), std::numeric_limits<Real>::quiet_NaN()})
: impl_(std::make_shared<detail::cardinal_quintic_b_spline_detail<Real>>(y.data(), y.size(), t0, h, left_endpoint_derivatives, right_endpoint_derivatives))
{}
Real operator()(Real t) const {
return impl_->operator()(t);
}
Real prime(Real t) const {
return impl_->prime(t);
}
Real double_prime(Real t) const {
return impl_->double_prime(t);
}
Real t_max() const {
return impl_->t_max();
}
private:
std::shared_ptr<detail::cardinal_quintic_b_spline_detail<Real>> impl_;
};
}}}
#endif
// (C) Copyright Nick Thompson 2019.
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_MATH_INTERPOLATORS_CARDINAL_TRIGONOMETRIC_HPP
#define BOOST_MATH_INTERPOLATORS_CARDINAL_TRIGONOMETRIC_HPP
#include <memory>
#include <boost/math/interpolators/detail/cardinal_trigonometric_detail.hpp>
namespace boost { namespace math { namespace interpolators {
template<class RandomAccessContainer>
class cardinal_trigonometric
{
public:
using Real = typename RandomAccessContainer::value_type;
cardinal_trigonometric(RandomAccessContainer const & v, Real t0, Real h)
{
m_impl = std::make_shared<interpolators::detail::cardinal_trigonometric_detail<Real>>(v.data(), v.size(), t0, h);
}
Real operator()(Real t) const
{
return m_impl->operator()(t);
}
Real prime(Real t) const
{
return m_impl->prime(t);
}
Real double_prime(Real t) const
{
return m_impl->double_prime(t);
}
Real period() const
{
return m_impl->period();
}
Real integrate() const
{
return m_impl->integrate();
}
Real squared_l2() const
{
return m_impl->squared_l2();
}
private:
std::shared_ptr<interpolators::detail::cardinal_trigonometric_detail<Real>> m_impl;
};
}}}
#endif
// Copyright Nick Thompson, 2017
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)
// This implements the compactly supported cubic b spline algorithm described in
// Kress, Rainer. "Numerical analysis, volume 181 of Graduate Texts in Mathematics." (1998).
// Splines of compact support are faster to evaluate and are better conditioned than classical cubic splines.
// Let f be the function we are trying to interpolate, and s be the interpolating spline.
// The routine constructs the interpolant in O(N) time, and evaluating s at a point takes constant time.
// The order of accuracy depends on the regularity of the f, however, assuming f is
// four-times continuously differentiable, the error is of O(h^4).
// In addition, we can differentiate the spline and obtain a good interpolant for f'.
// The main restriction of this method is that the samples of f must be evenly spaced.
// Look for barycentric rational interpolation for non-evenly sampled data.
// Properties:
// - s(x_j) = f(x_j)
// - All cubic polynomials interpolated exactly
#ifndef BOOST_MATH_INTERPOLATORS_CUBIC_B_SPLINE_HPP
#define BOOST_MATH_INTERPOLATORS_CUBIC_B_SPLINE_HPP
#include <boost/math/interpolators/detail/cubic_b_spline_detail.hpp>
namespace boost{ namespace math{
template <class Real>
class cubic_b_spline
{
public:
// If you don't know the value of the derivative at the endpoints, leave them as nans and the routine will estimate them.
// f[0] = f(a), f[length -1] = b, step_size = (b - a)/(length -1).
template <class BidiIterator>
cubic_b_spline(const BidiIterator f, BidiIterator end_p, Real left_endpoint, Real step_size,
Real left_endpoint_derivative = std::numeric_limits<Real>::quiet_NaN(),
Real right_endpoint_derivative = std::numeric_limits<Real>::quiet_NaN());
cubic_b_spline(const Real* const f, size_t length, Real left_endpoint, Real step_size,
Real left_endpoint_derivative = std::numeric_limits<Real>::quiet_NaN(),
Real right_endpoint_derivative = std::numeric_limits<Real>::quiet_NaN());
cubic_b_spline() = default;
Real operator()(Real x) const;
Real prime(Real x) const;
private:
std::shared_ptr<detail::cubic_b_spline_imp<Real>> m_imp;
};
template<class Real>
cubic_b_spline<Real>::cubic_b_spline(const Real* const f, size_t length, Real left_endpoint, Real step_size,
Real left_endpoint_derivative, Real right_endpoint_derivative) : m_imp(std::make_shared<detail::cubic_b_spline_imp<Real>>(f, f + length, left_endpoint, step_size, left_endpoint_derivative, right_endpoint_derivative))
{
}
template <class Real>
template <class BidiIterator>
cubic_b_spline<Real>::cubic_b_spline(BidiIterator f, BidiIterator end_p, Real left_endpoint, Real step_size,
Real left_endpoint_derivative, Real right_endpoint_derivative) : m_imp(std::make_shared<detail::cubic_b_spline_imp<Real>>(f, end_p, left_endpoint, step_size, left_endpoint_derivative, right_endpoint_derivative))
{
}
template<class Real>
Real cubic_b_spline<Real>::operator()(Real x) const
{
return m_imp->operator()(x);
}
template<class Real>
Real cubic_b_spline<Real>::prime(Real x) const
{
return m_imp->prime(x);
}
}}
#endif
// Copyright Nick Thompson, 2017
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)
// This implements the compactly supported cubic b spline algorithm described in
// Kress, Rainer. "Numerical analysis, volume 181 of Graduate Texts in Mathematics." (1998).
// Splines of compact support are faster to evaluate and are better conditioned than classical cubic splines.
// Let f be the function we are trying to interpolate, and s be the interpolating spline.
// The routine constructs the interpolant in O(N) time, and evaluating s at a point takes constant time.
// The order of accuracy depends on the regularity of the f, however, assuming f is
// four-times continuously differentiable, the error is of O(h^4).
// In addition, we can differentiate the spline and obtain a good interpolant for f'.
// The main restriction of this method is that the samples of f must be evenly spaced.
// Look for barycentric rational interpolation for non-evenly sampled data.
// Properties:
// - s(x_j) = f(x_j)
// - All cubic polynomials interpolated exactly
#ifndef BOOST_MATH_INTERPOLATORS_CUBIC_B_SPLINE_HPP
#define BOOST_MATH_INTERPOLATORS_CUBIC_B_SPLINE_HPP
#include <boost/math/interpolators/detail/cubic_b_spline_detail.hpp>
#include <boost/config/header_deprecated.hpp>
BOOST_HEADER_DEPRECATED("<boost/math/interpolators/cardinal_cubic_b_spline.hpp>");
namespace boost{ namespace math{
template <class Real>
class cubic_b_spline
{
public:
// If you don't know the value of the derivative at the endpoints, leave them as nans and the routine will estimate them.
// f[0] = f(a), f[length -1] = b, step_size = (b - a)/(length -1).
template <class BidiIterator>
cubic_b_spline(const BidiIterator f, BidiIterator end_p, Real left_endpoint, Real step_size,
Real left_endpoint_derivative = std::numeric_limits<Real>::quiet_NaN(),
Real right_endpoint_derivative = std::numeric_limits<Real>::quiet_NaN());
cubic_b_spline(const Real* const f, size_t length, Real left_endpoint, Real step_size,
Real left_endpoint_derivative = std::numeric_limits<Real>::quiet_NaN(),
Real right_endpoint_derivative = std::numeric_limits<Real>::quiet_NaN());
cubic_b_spline() = default;
Real operator()(Real x) const;
Real prime(Real x) const;
Real double_prime(Real x) const;
private:
std::shared_ptr<detail::cubic_b_spline_imp<Real>> m_imp;
};
template<class Real>
cubic_b_spline<Real>::cubic_b_spline(const Real* const f, size_t length, Real left_endpoint, Real step_size,
Real left_endpoint_derivative, Real right_endpoint_derivative) : m_imp(std::make_shared<detail::cubic_b_spline_imp<Real>>(f, f + length, left_endpoint, step_size, left_endpoint_derivative, right_endpoint_derivative))
{
}
template <class Real>
template <class BidiIterator>
cubic_b_spline<Real>::cubic_b_spline(BidiIterator f, BidiIterator end_p, Real left_endpoint, Real step_size,
Real left_endpoint_derivative, Real right_endpoint_derivative) : m_imp(std::make_shared<detail::cubic_b_spline_imp<Real>>(f, end_p, left_endpoint, step_size, left_endpoint_derivative, right_endpoint_derivative))
{
}
template<class Real>
Real cubic_b_spline<Real>::operator()(Real x) const
{
return m_imp->operator()(x);
}
template<class Real>
Real cubic_b_spline<Real>::prime(Real x) const
{
return m_imp->prime(x);
}
template<class Real>
Real cubic_b_spline<Real>::double_prime(Real x) const
{
return m_imp->double_prime(x);
}
}}
#endif
// Copyright Nick Thompson, 2020
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_MATH_INTERPOLATORS_CUBIC_HERMITE_HPP
#define BOOST_MATH_INTERPOLATORS_CUBIC_HERMITE_HPP
#include <memory>
#include <boost/math/interpolators/detail/cubic_hermite_detail.hpp>
namespace boost::math::interpolators {
template<class RandomAccessContainer>
class cubic_hermite {
public:
using Real = typename RandomAccessContainer::value_type;
cubic_hermite(RandomAccessContainer && x, RandomAccessContainer && y, RandomAccessContainer && dydx)
: impl_(std::make_shared<detail::cubic_hermite_detail<RandomAccessContainer>>(std::move(x), std::move(y), std::move(dydx)))
{}
inline Real operator()(Real x) const {
return impl_->operator()(x);
}
inline Real prime(Real x) const {
return impl_->prime(x);
}
friend std::ostream& operator<<(std::ostream & os, const cubic_hermite & m)
{
os << *m.impl_;
return os;
}
void push_back(Real x, Real y, Real dydx)
{
impl_->push_back(x, y, dydx);
}
int64_t bytes() const
{
return impl_->bytes() + sizeof(impl_);
}
std::pair<Real, Real> domain() const
{
return impl_->domain();
}
private:
std::shared_ptr<detail::cubic_hermite_detail<RandomAccessContainer>> impl_;
};
template<class RandomAccessContainer>
class cardinal_cubic_hermite {
public:
using Real = typename RandomAccessContainer::value_type;
cardinal_cubic_hermite(RandomAccessContainer && y, RandomAccessContainer && dydx, Real x0, Real dx)
: impl_(std::make_shared<detail::cardinal_cubic_hermite_detail<RandomAccessContainer>>(std::move(y), std::move(dydx), x0, dx))
{}
inline Real operator()(Real x) const
{
return impl_->operator()(x);
}
inline Real prime(Real x) const
{
return impl_->prime(x);
}
friend std::ostream& operator<<(std::ostream & os, const cardinal_cubic_hermite & m)
{
os << *m.impl_;
return os;
}
int64_t bytes() const
{
return impl_->bytes() + sizeof(impl_);
}
std::pair<Real, Real> domain() const
{
return impl_->domain();
}
private:
std::shared_ptr<detail::cardinal_cubic_hermite_detail<RandomAccessContainer>> impl_;
};
template<class RandomAccessContainer>
class cardinal_cubic_hermite_aos {
public:
using Point = typename RandomAccessContainer::value_type;
using Real = typename Point::value_type;
cardinal_cubic_hermite_aos(RandomAccessContainer && data, Real x0, Real dx)
: impl_(std::make_shared<detail::cardinal_cubic_hermite_detail_aos<RandomAccessContainer>>(std::move(data), x0, dx))
{}
inline Real operator()(Real x) const
{
return impl_->operator()(x);
}
inline Real prime(Real x) const
{
return impl_->prime(x);
}
friend std::ostream& operator<<(std::ostream & os, const cardinal_cubic_hermite_aos & m)
{
os << *m.impl_;
return os;
}
int64_t bytes() const
{
return impl_->bytes() + sizeof(impl_);
}
std::pair<Real, Real> domain() const
{
return impl_->domain();
}
private:
std::shared_ptr<detail::cardinal_cubic_hermite_detail_aos<RandomAccessContainer>> impl_;
};
}
#endif
\ No newline at end of file
// Copyright Nick Thompson, 2019
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_MATH_INTERPOLATORS_CARDINAL_QUADRATIC_B_SPLINE_DETAIL_HPP
#define BOOST_MATH_INTERPOLATORS_CARDINAL_QUADRATIC_B_SPLINE_DETAIL_HPP
#include <vector>
#include <cmath>
#include <stdexcept>
namespace boost{ namespace math{ namespace interpolators{ namespace detail{
template <class Real>
Real b2_spline(Real x) {
using std::abs;
Real absx = abs(x);
if (absx < 1/Real(2))
{
Real y = absx - 1/Real(2);
Real z = absx + 1/Real(2);
return (2-y*y-z*z)/2;
}
if (absx < Real(3)/Real(2))
{
Real y = absx - Real(3)/Real(2);
return y*y/2;
}
return (Real) 0;
}
template <class Real>
Real b2_spline_prime(Real x) {
if (x < 0) {
return -b2_spline_prime(-x);
}
if (x < 1/Real(2))
{
return -2*x;
}
if (x < Real(3)/Real(2))
{
return x - Real(3)/Real(2);
}
return (Real) 0;
}
template <class Real>
class cardinal_quadratic_b_spline_detail
{
public:
// If you don't know the value of the derivative at the endpoints, leave them as nans and the routine will estimate them.
// y[0] = y(a), y[n -1] = y(b), step_size = (b - a)/(n -1).
cardinal_quadratic_b_spline_detail(const Real* const y,
size_t n,
Real t0 /* initial time, left endpoint */,
Real h /*spacing, stepsize*/,
Real left_endpoint_derivative = std::numeric_limits<Real>::quiet_NaN(),
Real right_endpoint_derivative = std::numeric_limits<Real>::quiet_NaN())
{
if (h <= 0) {
throw std::logic_error("Spacing must be > 0.");
}
m_inv_h = 1/h;
m_t0 = t0;
if (n < 3) {
throw std::logic_error("The interpolator requires at least 3 points.");
}
using std::isnan;
Real a;
if (isnan(left_endpoint_derivative)) {
// http://web.media.mit.edu/~crtaylor/calculator.html
a = -3*y[0] + 4*y[1] - y[2];
}
else {
a = 2*h*left_endpoint_derivative;
}
Real b;
if (isnan(right_endpoint_derivative)) {
b = 3*y[n-1] - 4*y[n-2] + y[n-3];
}
else {
b = 2*h*right_endpoint_derivative;
}
m_alpha.resize(n + 2);
// Begin row reduction:
std::vector<Real> rhs(n + 2, std::numeric_limits<Real>::quiet_NaN());
std::vector<Real> super_diagonal(n + 2, std::numeric_limits<Real>::quiet_NaN());
rhs[0] = -a;
rhs[rhs.size() - 1] = b;
super_diagonal[0] = 0;
for(size_t i = 1; i < rhs.size() - 1; ++i) {
rhs[i] = 8*y[i - 1];
super_diagonal[i] = 1;
}
// Patch up 5-diagonal problem:
rhs[1] = (rhs[1] - rhs[0])/6;
super_diagonal[1] = Real(1)/Real(3);
// First two rows are now:
// 1 0 -1 | -2hy0'
// 0 1 1/3| (8y0+2hy0')/6
// Start traditional tridiagonal row reduction:
for (size_t i = 2; i < rhs.size() - 1; ++i) {
Real diagonal = 6 - super_diagonal[i - 1];
rhs[i] = (rhs[i] - rhs[i - 1])/diagonal;
super_diagonal[i] /= diagonal;
}
// 1 sd[n-1] 0 | rhs[n-1]
// 0 1 sd[n] | rhs[n]
// -1 0 1 | rhs[n+1]
rhs[n+1] = rhs[n+1] + rhs[n-1];
Real bottom_subdiagonal = super_diagonal[n-1];
// We're here:
// 1 sd[n-1] 0 | rhs[n-1]
// 0 1 sd[n] | rhs[n]
// 0 bs 1 | rhs[n+1]
rhs[n+1] = (rhs[n+1]-bottom_subdiagonal*rhs[n])/(1-bottom_subdiagonal*super_diagonal[n]);
m_alpha[n+1] = rhs[n+1];
for (size_t i = n; i > 0; --i) {
m_alpha[i] = rhs[i] - m_alpha[i+1]*super_diagonal[i];
}
m_alpha[0] = m_alpha[2] + rhs[0];
}
Real operator()(Real t) const {
if (t < m_t0 || t > m_t0 + (m_alpha.size()-2)/m_inv_h) {
const char* err_msg = "Tried to evaluate the cardinal quadratic b-spline outside the domain of of interpolation; extrapolation does not work.";
throw std::domain_error(err_msg);
}
// Let k, gamma be defined via t = t0 + kh + gamma * h.
// Now find all j: |k-j+1+gamma|< 3/2, or, in other words
// j_min = ceil((t-t0)/h - 1/2)
// j_max = floor(t-t0)/h + 5/2)
using std::floor;
using std::ceil;
Real x = (t-m_t0)*m_inv_h;
size_t j_min = ceil(x - Real(1)/Real(2));
size_t j_max = ceil(x + Real(5)/Real(2));
if (j_max >= m_alpha.size()) {
j_max = m_alpha.size() - 1;
}
Real y = 0;
x += 1;
for (size_t j = j_min; j <= j_max; ++j) {
y += m_alpha[j]*detail::b2_spline(x - j);
}
return y;
}
Real prime(Real t) const {
if (t < m_t0 || t > m_t0 + (m_alpha.size()-2)/m_inv_h) {
const char* err_msg = "Tried to evaluate the cardinal quadratic b-spline outside the domain of of interpolation; extrapolation does not work.";
throw std::domain_error(err_msg);
}
// Let k, gamma be defined via t = t0 + kh + gamma * h.
// Now find all j: |k-j+1+gamma|< 3/2, or, in other words
// j_min = ceil((t-t0)/h - 1/2)
// j_max = floor(t-t0)/h + 5/2)
using std::floor;
using std::ceil;
Real x = (t-m_t0)*m_inv_h;
size_t j_min = ceil(x - Real(1)/Real(2));
size_t j_max = ceil(x + Real(5)/Real(2));
if (j_max >= m_alpha.size()) {
j_max = m_alpha.size() - 1;
}
Real y = 0;
x += 1;
for (size_t j = j_min; j <= j_max; ++j) {
y += m_alpha[j]*detail::b2_spline_prime(x - j);
}
return y*m_inv_h;
}
Real t_max() const {
return m_t0 + (m_alpha.size()-3)/m_inv_h;
}
private:
std::vector<Real> m_alpha;
Real m_inv_h;
Real m_t0;
};
}}}}
#endif
/*
* Copyright Nick Thompson, 2019
* Use, modification and distribution are subject to the
* Boost Software License, Version 1.0. (See accompanying file
* LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
#ifndef BOOST_MATH_INTERPOLATORS_VECTOR_BARYCENTRIC_RATIONAL_DETAIL_HPP
#define BOOST_MATH_INTERPOLATORS_VECTOR_BARYCENTRIC_RATIONAL_DETAIL_HPP
#include <vector>
#include <utility> // for std::move
#include <limits>
#include <boost/assert.hpp>
namespace boost{ namespace math{ namespace detail{
template <class TimeContainer, class SpaceContainer>
class vector_barycentric_rational_imp
{
public:
using Real = typename TimeContainer::value_type;
using Point = typename SpaceContainer::value_type;
vector_barycentric_rational_imp(TimeContainer&& t, SpaceContainer&& y, size_t approximation_order);
void operator()(Point& p, Real t) const;
void eval_with_prime(Point& x, Point& dxdt, Real t) const;
// The barycentric weights are only interesting to the unit tests:
Real weight(size_t i) const { return w_[i]; }
private:
void calculate_weights(size_t approximation_order);
TimeContainer t_;
SpaceContainer y_;
TimeContainer w_;
};
template <class TimeContainer, class SpaceContainer>
vector_barycentric_rational_imp<TimeContainer, SpaceContainer>::vector_barycentric_rational_imp(TimeContainer&& t, SpaceContainer&& y, size_t approximation_order)
{
using std::numeric_limits;
t_ = std::move(t);
y_ = std::move(y);
BOOST_ASSERT_MSG(t_.size() == y_.size(), "There must be the same number of time points as space points.");
BOOST_ASSERT_MSG(approximation_order < y_.size(), "Approximation order must be < data length.");
for (size_t i = 1; i < t_.size(); ++i)
{
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].");
}
calculate_weights(approximation_order);
}
template<class TimeContainer, class SpaceContainer>
void vector_barycentric_rational_imp<TimeContainer, SpaceContainer>::calculate_weights(size_t approximation_order)
{
using Real = typename TimeContainer::value_type;
using std::abs;
int64_t n = t_.size();
w_.resize(n, Real(0));
for(int64_t k = 0; k < n; ++k)
{
int64_t i_min = (std::max)(k - (int64_t) approximation_order, (int64_t) 0);
int64_t i_max = k;
if (k >= n - (std::ptrdiff_t)approximation_order)
{
i_max = n - approximation_order - 1;
}
for(int64_t i = i_min; i <= i_max; ++i)
{
Real inv_product = 1;
int64_t j_max = (std::min)(static_cast<int64_t>(i + approximation_order), static_cast<int64_t>(n - 1));
for(int64_t j = i; j <= j_max; ++j)
{
if (j == k)
{
continue;
}
Real diff = t_[k] - t_[j];
inv_product *= diff;
}
if (i % 2 == 0)
{
w_[k] += 1/inv_product;
}
else
{
w_[k] -= 1/inv_product;
}
}
}
}
template<class TimeContainer, class SpaceContainer>
void vector_barycentric_rational_imp<TimeContainer, SpaceContainer>::operator()(typename SpaceContainer::value_type& p, typename TimeContainer::value_type t) const
{
using Real = typename TimeContainer::value_type;
for (auto & x : p)
{
x = Real(0);
}
Real denominator = 0;
for(size_t i = 0; i < t_.size(); ++i)
{
// See associated commentary in the scalar version of this function.
if (t == t_[i])
{
p = y_[i];
return;
}
Real x = w_[i]/(t - t_[i]);
for (decltype(p.size()) j = 0; j < p.size(); ++j)
{
p[j] += x*y_[i][j];
}
denominator += x;
}
for (decltype(p.size()) j = 0; j < p.size(); ++j)
{
p[j] /= denominator;
}
return;
}
template<class TimeContainer, class SpaceContainer>
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
{
using Point = typename SpaceContainer::value_type;
using Real = typename TimeContainer::value_type;
this->operator()(x, t);
Point numerator;
for (decltype(x.size()) i = 0; i < x.size(); ++i)
{
numerator[i] = 0;
}
Real denominator = 0;
for(decltype(t_.size()) i = 0; i < t_.size(); ++i)
{
if (t == t_[i])
{
Point sum;
for (decltype(x.size()) i = 0; i < x.size(); ++i)
{
sum[i] = 0;
}
for (decltype(t_.size()) j = 0; j < t_.size(); ++j)
{
if (j == i)
{
continue;
}
for (decltype(sum.size()) k = 0; k < sum.size(); ++k)
{
sum[k] += w_[j]*(y_[i][k] - y_[j][k])/(t_[i] - t_[j]);
}
}
for (decltype(sum.size()) k = 0; k < sum.size(); ++k)
{
dxdt[k] = -sum[k]/w_[i];
}
return;
}
Real tw = w_[i]/(t - t_[i]);
Point diff;
for (decltype(diff.size()) j = 0; j < diff.size(); ++j)
{
diff[j] = (x[j] - y_[i][j])/(t-t_[i]);
}
for (decltype(diff.size()) j = 0; j < diff.size(); ++j)
{
numerator[j] += tw*diff[j];
}
denominator += tw;
}
for (decltype(dxdt.size()) j = 0; j < dxdt.size(); ++j)
{
dxdt[j] = numerator[j]/denominator;
}
return;
}
}}}
#endif
// Copyright Nick Thompson, 2019
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_MATH_INTERPOLATORS_WHITAKKER_SHANNON_DETAIL_HPP
#define BOOST_MATH_INTERPOLATORS_WHITAKKER_SHANNON_DETAIL_HPP
#include <boost/assert.hpp>
#include <boost/math/constants/constants.hpp>
#include <boost/math/special_functions/sin_pi.hpp>
#include <boost/math/special_functions/cos_pi.hpp>
namespace boost { namespace math { namespace interpolators { namespace detail {
template<class RandomAccessContainer>
class whittaker_shannon_detail {
public:
using Real = typename RandomAccessContainer::value_type;
whittaker_shannon_detail(RandomAccessContainer&& y, Real const & t0, Real const & h) : m_y{std::move(y)}, m_t0{t0}, m_h{h}
{
for (size_t i = 1; i < m_y.size(); i += 2)
{
m_y[i] = -m_y[i];
}
}
inline Real operator()(Real t) const {
using boost::math::constants::pi;
using std::isfinite;
using std::floor;
Real y = 0;
Real x = (t - m_t0)/m_h;
Real z = x;
auto it = m_y.begin();
// For some reason, neither clang nor g++ will cache the address of m_y.end() in a register.
// Hence make a copy of it:
auto end = m_y.end();
while(it != end)
{
y += *it++/z;
z -= 1;
}
if (!isfinite(y))
{
BOOST_ASSERT_MSG(floor(x) == ceil(x), "Floor and ceiling should be equal.\n");
size_t i = static_cast<size_t>(floor(x));
if (i & 1)
{
return -m_y[i];
}
return m_y[i];
}
return y*boost::math::sin_pi(x)/pi<Real>();
}
Real prime(Real t) const {
using boost::math::constants::pi;
using std::isfinite;
using std::floor;
Real x = (t - m_t0)/m_h;
if (ceil(x) == x) {
Real s = 0;
long j = static_cast<long>(x);
long n = m_y.size();
for (long i = 0; i < n; ++i)
{
if (j - i != 0)
{
s += m_y[i]/(j-i);
}
// else derivative of sinc at zero is zero.
}
if (j & 1) {
s /= -m_h;
} else {
s /= m_h;
}
return s;
}
Real z = x;
auto it = m_y.begin();
Real cospix = boost::math::cos_pi(x);
Real sinpix_div_pi = boost::math::sin_pi(x)/pi<Real>();
Real s = 0;
auto end = m_y.end();
while(it != end)
{
s += (*it++)*(z*cospix - sinpix_div_pi)/(z*z);
z -= 1;
}
return s/m_h;
}
Real operator[](size_t i) const {
if (i & 1)
{
return -m_y[i];
}
return m_y[i];
}
RandomAccessContainer&& return_data() {
for (size_t i = 1; i < m_y.size(); i += 2)
{
m_y[i] = -m_y[i];
}
return std::move(m_y);
}
private:
RandomAccessContainer m_y;
Real m_t0;
Real m_h;
};
}}}}
#endif
// Copyright Nick Thompson, 2020
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)
// See: https://blogs.mathworks.com/cleve/2019/04/29/makima-piecewise-cubic-interpolation/
// And: https://doi.org/10.1145/321607.321609
#ifndef BOOST_MATH_INTERPOLATORS_MAKIMA_HPP
#define BOOST_MATH_INTERPOLATORS_MAKIMA_HPP
#include <memory>
#include <cmath>
#include <boost/math/interpolators/detail/cubic_hermite_detail.hpp>
namespace boost::math::interpolators {
template<class RandomAccessContainer>
class makima {
public:
using Real = typename RandomAccessContainer::value_type;
makima(RandomAccessContainer && x, RandomAccessContainer && y,
Real left_endpoint_derivative = std::numeric_limits<Real>::quiet_NaN(),
Real right_endpoint_derivative = std::numeric_limits<Real>::quiet_NaN())
{
using std::isnan;
using std::abs;
if (x.size() < 4)
{
throw std::domain_error("Must be at least four data points.");
}
RandomAccessContainer s(x.size(), std::numeric_limits<Real>::quiet_NaN());
Real m2 = (y[3]-y[2])/(x[3]-x[2]);
Real m1 = (y[2]-y[1])/(x[2]-x[1]);
Real m0 = (y[1]-y[0])/(x[1]-x[0]);
// Quadratic extrapolation: m_{-1} = 2m_0 - m_1:
Real mm1 = 2*m0 - m1;
// Quadratic extrapolation: m_{-2} = 2*m_{-1}-m_0:
Real mm2 = 2*mm1 - m0;
Real w1 = abs(m1-m0) + abs(m1+m0)/2;
Real w2 = abs(mm1-mm2) + abs(mm1+mm2)/2;
if (isnan(left_endpoint_derivative))
{
s[0] = (w1*mm1 + w2*m0)/(w1+w2);
if (isnan(s[0]))
{
s[0] = 0;
}
}
else
{
s[0] = left_endpoint_derivative;
}
w1 = abs(m2-m1) + abs(m2+m1)/2;
w2 = abs(m0-mm1) + abs(m0+mm1)/2;
s[1] = (w1*m0 + w2*m1)/(w1+w2);
if (isnan(s[1])) {
s[1] = 0;
}
for (decltype(s.size()) i = 2; i < s.size()-2; ++i) {
Real mim2 = (y[i-1]-y[i-2])/(x[i-1]-x[i-2]);
Real mim1 = (y[i ]-y[i-1])/(x[i ]-x[i-1]);
Real mi = (y[i+1]-y[i ])/(x[i+1]-x[i ]);
Real mip1 = (y[i+2]-y[i+1])/(x[i+2]-x[i+1]);
w1 = abs(mip1-mi) + abs(mip1+mi)/2;
w2 = abs(mim1-mim2) + abs(mim1+mim2)/2;
s[i] = (w1*mim1 + w2*mi)/(w1+w2);
if (isnan(s[i])) {
s[i] = 0;
}
}
// Quadratic extrapolation at the other end:
decltype(s.size()) n = s.size();
Real mnm4 = (y[n-3]-y[n-4])/(x[n-3]-x[n-4]);
Real mnm3 = (y[n-2]-y[n-3])/(x[n-2]-x[n-3]);
Real mnm2 = (y[n-1]-y[n-2])/(x[n-1]-x[n-2]);
Real mnm1 = 2*mnm2 - mnm3;
Real mn = 2*mnm1 - mnm2;
w1 = abs(mnm1 - mnm2) + abs(mnm1+mnm2)/2;
w2 = abs(mnm3 - mnm4) + abs(mnm3+mnm4)/2;
s[n-2] = (w1*mnm3 + w2*mnm2)/(w1 + w2);
if (isnan(s[n-2])) {
s[n-2] = 0;
}
w1 = abs(mn - mnm1) + abs(mn+mnm1)/2;
w2 = abs(mnm2 - mnm3) + abs(mnm2+mnm3)/2;
if (isnan(right_endpoint_derivative))
{
s[n-1] = (w1*mnm2 + w2*mnm1)/(w1+w2);
if (isnan(s[n-1])) {
s[n-1] = 0;
}
}
else
{
s[n-1] = right_endpoint_derivative;
}
impl_ = std::make_shared<detail::cubic_hermite_detail<RandomAccessContainer>>(std::move(x), std::move(y), std::move(s));
}
Real operator()(Real x) const {
return impl_->operator()(x);
}
Real prime(Real x) const {
return impl_->prime(x);
}
friend std::ostream& operator<<(std::ostream & os, const makima & m)
{
os << *m.impl_;
return os;
}
void push_back(Real x, Real y) {
using std::abs;
using std::isnan;
if (x <= impl_->x_.back()) {
throw std::domain_error("Calling push_back must preserve the monotonicity of the x's");
}
impl_->x_.push_back(x);
impl_->y_.push_back(y);
impl_->dydx_.push_back(std::numeric_limits<Real>::quiet_NaN());
// dydx_[n-2] was computed by extrapolation. Now dydx_[n-2] -> dydx_[n-3], and it can be computed by the same formula.
decltype(impl_->size()) n = impl_->size();
auto i = n - 3;
Real mim2 = (impl_->y_[i-1]-impl_->y_[i-2])/(impl_->x_[i-1]-impl_->x_[i-2]);
Real mim1 = (impl_->y_[i ]-impl_->y_[i-1])/(impl_->x_[i ]-impl_->x_[i-1]);
Real mi = (impl_->y_[i+1]-impl_->y_[i ])/(impl_->x_[i+1]-impl_->x_[i ]);
Real mip1 = (impl_->y_[i+2]-impl_->y_[i+1])/(impl_->x_[i+2]-impl_->x_[i+1]);
Real w1 = abs(mip1-mi) + abs(mip1+mi)/2;
Real w2 = abs(mim1-mim2) + abs(mim1+mim2)/2;
impl_->dydx_[i] = (w1*mim1 + w2*mi)/(w1+w2);
if (isnan(impl_->dydx_[i])) {
impl_->dydx_[i] = 0;
}
Real mnm4 = (impl_->y_[n-3]-impl_->y_[n-4])/(impl_->x_[n-3]-impl_->x_[n-4]);
Real mnm3 = (impl_->y_[n-2]-impl_->y_[n-3])/(impl_->x_[n-2]-impl_->x_[n-3]);
Real mnm2 = (impl_->y_[n-1]-impl_->y_[n-2])/(impl_->x_[n-1]-impl_->x_[n-2]);
Real mnm1 = 2*mnm2 - mnm3;
Real mn = 2*mnm1 - mnm2;
w1 = abs(mnm1 - mnm2) + abs(mnm1+mnm2)/2;
w2 = abs(mnm3 - mnm4) + abs(mnm3+mnm4)/2;
impl_->dydx_[n-2] = (w1*mnm3 + w2*mnm2)/(w1 + w2);
if (isnan(impl_->dydx_[n-2])) {
impl_->dydx_[n-2] = 0;
}
w1 = abs(mn - mnm1) + abs(mn+mnm1)/2;
w2 = abs(mnm2 - mnm3) + abs(mnm2+mnm3)/2;
impl_->dydx_[n-1] = (w1*mnm2 + w2*mnm1)/(w1+w2);
if (isnan(impl_->dydx_[n-1])) {
impl_->dydx_[n-1] = 0;
}
}
private:
std::shared_ptr<detail::cubic_hermite_detail<RandomAccessContainer>> impl_;
};
}
#endif
\ No newline at end of file
// Copyright Nick Thompson, 2020
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_MATH_INTERPOLATORS_PCHIP_HPP
#define BOOST_MATH_INTERPOLATORS_PCHIP_HPP
#include <memory>
#include <boost/math/interpolators/detail/cubic_hermite_detail.hpp>
namespace boost::math::interpolators {
template<class RandomAccessContainer>
class pchip {
public:
using Real = typename RandomAccessContainer::value_type;
pchip(RandomAccessContainer && x, RandomAccessContainer && y,
Real left_endpoint_derivative = std::numeric_limits<Real>::quiet_NaN(),
Real right_endpoint_derivative = std::numeric_limits<Real>::quiet_NaN())
{
if (x.size() < 4)
{
throw std::domain_error("Must be at least four data points.");
}
RandomAccessContainer s(x.size(), std::numeric_limits<Real>::quiet_NaN());
if (isnan(left_endpoint_derivative))
{
// O(h) finite difference derivative:
// This, I believe, is the only derivative guaranteed to be monotonic:
s[0] = (y[1]-y[0])/(x[1]-x[0]);
}
else
{
s[0] = left_endpoint_derivative;
}
for (decltype(s.size()) k = 1; k < s.size()-1; ++k) {
Real hkm1 = x[k] - x[k-1];
Real dkm1 = (y[k] - y[k-1])/hkm1;
Real hk = x[k+1] - x[k];
Real dk = (y[k+1] - y[k])/hk;
Real w1 = 2*hk + hkm1;
Real w2 = hk + 2*hkm1;
if ( (dk > 0 && dkm1 < 0) || (dk < 0 && dkm1 > 0) || dk == 0 || dkm1 == 0)
{
s[k] = 0;
}
else
{
s[k] = (w1+w2)/(w1/dkm1 + w2/dk);
}
}
// Quadratic extrapolation at the other end:
auto n = s.size();
if (isnan(right_endpoint_derivative))
{
s[n-1] = (y[n-1]-y[n-2])/(x[n-1] - x[n-2]);
}
else
{
s[n-1] = right_endpoint_derivative;
}
impl_ = std::make_shared<detail::cubic_hermite_detail<RandomAccessContainer>>(std::move(x), std::move(y), std::move(s));
}
Real operator()(Real x) const {
return impl_->operator()(x);
}
Real prime(Real x) const {
return impl_->prime(x);
}
friend std::ostream& operator<<(std::ostream & os, const pchip & m)
{
os << *m.impl_;
return os;
}
void push_back(Real x, Real y) {
using std::abs;
using std::isnan;
if (x <= impl_->x_.back()) {
throw std::domain_error("Calling push_back must preserve the monotonicity of the x's");
}
impl_->x_.push_back(x);
impl_->y_.push_back(y);
impl_->dydx_.push_back(std::numeric_limits<Real>::quiet_NaN());
auto n = impl_->size();
impl_->dydx_[n-1] = (impl_->y_[n-1]-impl_->y_[n-2])/(impl_->x_[n-1] - impl_->x_[n-2]);
// Now fix s_[n-2]:
auto k = n-2;
Real hkm1 = impl_->x_[k] - impl_->x_[k-1];
Real dkm1 = (impl_->y_[k] - impl_->y_[k-1])/hkm1;
Real hk = impl_->x_[k+1] - impl_->x_[k];
Real dk = (impl_->y_[k+1] - impl_->y_[k])/hk;
Real w1 = 2*hk + hkm1;
Real w2 = hk + 2*hkm1;
if ( (dk > 0 && dkm1 < 0) || (dk < 0 && dkm1 > 0) || dk == 0 || dkm1 == 0)
{
impl_->dydx_[k] = 0;
}
else
{
impl_->dydx_[k] = (w1+w2)/(w1/dkm1 + w2/dk);
}
}
private:
std::shared_ptr<detail::cubic_hermite_detail<RandomAccessContainer>> impl_;
};
}
#endif
\ No newline at end of file
/*
* Copyright Nick Thompson, 2020
* Use, modification and distribution are subject to the
* Boost Software License, Version 1.0. (See accompanying file
* LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
#ifndef BOOST_MATH_INTERPOLATORS_QUINTIC_HERMITE_HPP
#define BOOST_MATH_INTERPOLATORS_QUINTIC_HERMITE_HPP
#include <algorithm>
#include <stdexcept>
#include <memory>
#include <boost/math/interpolators/detail/quintic_hermite_detail.hpp>
namespace boost::math::interpolators {
template<class RandomAccessContainer>
class quintic_hermite {
public:
using Real = typename RandomAccessContainer::value_type;
quintic_hermite(RandomAccessContainer && x, RandomAccessContainer && y, RandomAccessContainer && dydx, RandomAccessContainer && d2ydx2)
: impl_(std::make_shared<detail::quintic_hermite_detail<RandomAccessContainer>>(std::move(x), std::move(y), std::move(dydx), std::move(d2ydx2)))
{}
Real operator()(Real x) const
{
return impl_->operator()(x);
}
Real prime(Real x) const
{
return impl_->prime(x);
}
Real double_prime(Real x) const
{
return impl_->double_prime(x);
}
friend std::ostream& operator<<(std::ostream & os, const quintic_hermite & m)
{
os << *m.impl_;
return os;
}
void push_back(Real x, Real y, Real dydx, Real d2ydx2)
{
impl_->push_back(x, y, dydx, d2ydx2);
}
int64_t bytes() const
{
return impl_->bytes() + sizeof(impl_);
}
std::pair<Real, Real> domain() const
{
return impl_->domain();
}
private:
std::shared_ptr<detail::quintic_hermite_detail<RandomAccessContainer>> impl_;
};
template<class RandomAccessContainer>
class cardinal_quintic_hermite {
public:
using Real = typename RandomAccessContainer::value_type;
cardinal_quintic_hermite(RandomAccessContainer && y, RandomAccessContainer && dydx, RandomAccessContainer && d2ydx2, Real x0, Real dx)
: impl_(std::make_shared<detail::cardinal_quintic_hermite_detail<RandomAccessContainer>>(std::move(y), std::move(dydx), std::move(d2ydx2), x0, dx))
{}
inline Real operator()(Real x) const {
return impl_->operator()(x);
}
inline Real prime(Real x) const {
return impl_->prime(x);
}
inline Real double_prime(Real x) const
{
return impl_->double_prime(x);
}
int64_t bytes() const
{
return impl_->bytes() + sizeof(impl_);
}
std::pair<Real, Real> domain() const
{
return impl_->domain();
}
private:
std::shared_ptr<detail::cardinal_quintic_hermite_detail<RandomAccessContainer>> impl_;
};
template<class RandomAccessContainer>
class cardinal_quintic_hermite_aos {
public:
using Point = typename RandomAccessContainer::value_type;
using Real = typename Point::value_type;
cardinal_quintic_hermite_aos(RandomAccessContainer && data, Real x0, Real dx)
: impl_(std::make_shared<detail::cardinal_quintic_hermite_detail_aos<RandomAccessContainer>>(std::move(data), x0, dx))
{}
inline Real operator()(Real x) const
{
return impl_->operator()(x);
}
inline Real prime(Real x) const
{
return impl_->prime(x);
}
inline Real double_prime(Real x) const
{
return impl_->double_prime(x);
}
int64_t bytes() const
{
return impl_->bytes() + sizeof(impl_);
}
std::pair<Real, Real> domain() const
{
return impl_->domain();
}
private:
std::shared_ptr<detail::cardinal_quintic_hermite_detail_aos<RandomAccessContainer>> impl_;
};
}
#endif
/*
* Copyright Nick Thompson, 2020
* Use, modification and distribution are subject to the
* Boost Software License, Version 1.0. (See accompanying file
* LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
#ifndef BOOST_MATH_INTERPOLATORS_SEPTIC_HERMITE_HPP
#define BOOST_MATH_INTERPOLATORS_SEPTIC_HERMITE_HPP
#include <algorithm>
#include <stdexcept>
#include <memory>
#include <boost/math/interpolators/detail/septic_hermite_detail.hpp>
namespace boost::math::interpolators {
template<class RandomAccessContainer>
class septic_hermite
{
public:
using Real = typename RandomAccessContainer::value_type;
septic_hermite(RandomAccessContainer && x, RandomAccessContainer && y, RandomAccessContainer && dydx,
RandomAccessContainer && d2ydx2, RandomAccessContainer && d3ydx3)
: impl_(std::make_shared<detail::septic_hermite_detail<RandomAccessContainer>>(std::move(x),
std::move(y), std::move(dydx), std::move(d2ydx2), std::move(d3ydx3)))
{}
inline Real operator()(Real x) const
{
return impl_->operator()(x);
}
inline Real prime(Real x) const
{
return impl_->prime(x);
}
inline Real double_prime(Real x) const
{
return impl_->double_prime(x);
}
friend std::ostream& operator<<(std::ostream & os, const septic_hermite & m)
{
os << *m.impl_;
return os;
}
int64_t bytes() const
{
return impl_->bytes() + sizeof(impl_);
}
std::pair<Real, Real> domain() const
{
return impl_->domain();
}
private:
std::shared_ptr<detail::septic_hermite_detail<RandomAccessContainer>> impl_;
};
template<class RandomAccessContainer>
class cardinal_septic_hermite
{
public:
using Real = typename RandomAccessContainer::value_type;
cardinal_septic_hermite(RandomAccessContainer && y, RandomAccessContainer && dydx,
RandomAccessContainer && d2ydx2, RandomAccessContainer && d3ydx3, Real x0, Real dx)
: impl_(std::make_shared<detail::cardinal_septic_hermite_detail<RandomAccessContainer>>(
std::move(y), std::move(dydx), std::move(d2ydx2), std::move(d3ydx3), x0, dx))
{}
inline Real operator()(Real x) const
{
return impl_->operator()(x);
}
inline Real prime(Real x) const
{
return impl_->prime(x);
}
inline Real double_prime(Real x) const
{
return impl_->double_prime(x);
}
int64_t bytes() const
{
return impl_->bytes() + sizeof(impl_);
}
std::pair<Real, Real> domain() const
{
return impl_->domain();
}
private:
std::shared_ptr<detail::cardinal_septic_hermite_detail<RandomAccessContainer>> impl_;
};
template<class RandomAccessContainer>
class cardinal_septic_hermite_aos {
public:
using Point = typename RandomAccessContainer::value_type;
using Real = typename Point::value_type;
cardinal_septic_hermite_aos(RandomAccessContainer && data, Real x0, Real dx)
: impl_(std::make_shared<detail::cardinal_septic_hermite_detail_aos<RandomAccessContainer>>(std::move(data), x0, dx))
{}
inline Real operator()(Real x) const
{
return impl_->operator()(x);
}
inline Real prime(Real x) const
{
return impl_->prime(x);
}
inline Real double_prime(Real x) const
{
return impl_->double_prime(x);
}
int64_t bytes() const
{
return impl_.size() + sizeof(impl_);
}
std::pair<Real, Real> domain() const
{
return impl_->domain();
}
private:
std::shared_ptr<detail::cardinal_septic_hermite_detail_aos<RandomAccessContainer>> impl_;
};
}
#endif
\ No newline at end of file
/*
* Copyright Nick Thompson, 2019
* Use, modification and distribution are subject to the
* Boost Software License, Version 1.0. (See accompanying file
* LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*
* Exactly the same as barycentric_rational.hpp, but delivers values in $\mathbb{R}^n$.
* In some sense this is trivial, since each component of the vector is computed in exactly the same
* as would be computed by barycentric_rational.hpp. But this is a bit more efficient and convenient.
*/
#ifndef BOOST_MATH_INTERPOLATORS_VECTOR_BARYCENTRIC_RATIONAL_HPP
#define BOOST_MATH_INTERPOLATORS_VECTOR_BARYCENTRIC_RATIONAL_HPP
#include <memory>
#include <boost/math/interpolators/detail/vector_barycentric_rational_detail.hpp>
namespace boost{ namespace math{
template<class TimeContainer, class SpaceContainer>
class vector_barycentric_rational
{
public:
using Real = typename TimeContainer::value_type;
using Point = typename SpaceContainer::value_type;
vector_barycentric_rational(TimeContainer&& times, SpaceContainer&& points, size_t approximation_order = 3);
void operator()(Point& x, Real t) const;
// I have validated using google benchmark that returning a value is no more expensive populating it,
// at least for Eigen vectors with known size at compile-time.
// This is kinda a weird thing to discover since it goes against the advice of basically every high-performance computing book.
Point operator()(Real t) const {
Point p;
this->operator()(p, t);
return p;
}
void prime(Point& dxdt, Real t) const {
Point x;
m_imp->eval_with_prime(x, dxdt, t);
}
Point prime(Real t) const {
Point p;
this->prime(p, t);
return p;
}
void eval_with_prime(Point& x, Point& dxdt, Real t) const {
m_imp->eval_with_prime(x, dxdt, t);
return;
}
std::pair<Point, Point> eval_with_prime(Real t) const {
Point x;
Point dxdt;
m_imp->eval_with_prime(x, dxdt, t);
return {x, dxdt};
}
private:
std::shared_ptr<detail::vector_barycentric_rational_imp<TimeContainer, SpaceContainer>> m_imp;
};
template <class TimeContainer, class SpaceContainer>
vector_barycentric_rational<TimeContainer, SpaceContainer>::vector_barycentric_rational(TimeContainer&& times, SpaceContainer&& points, size_t approximation_order):
m_imp(std::make_shared<detail::vector_barycentric_rational_imp<TimeContainer, SpaceContainer>>(std::move(times), std::move(points), approximation_order))
{
return;
}
template <class TimeContainer, class SpaceContainer>
void vector_barycentric_rational<TimeContainer, SpaceContainer>::operator()(typename SpaceContainer::value_type& p, typename TimeContainer::value_type t) const
{
m_imp->operator()(p, t);
return;
}
}}
#endif
// Copyright Nick Thompson, 2019
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_MATH_INTERPOLATORS_WHITAKKER_SHANNON_HPP
#define BOOST_MATH_INTERPOLATORS_WHITAKKER_SHANNON_HPP
#include <memory>
#include <boost/math/interpolators/detail/whittaker_shannon_detail.hpp>
namespace boost { namespace math { namespace interpolators {
template<class RandomAccessContainer>
class whittaker_shannon {
public:
using Real = typename RandomAccessContainer::value_type;
whittaker_shannon(RandomAccessContainer&& y, Real const & t0, Real const & h)
: m_impl(std::make_shared<detail::whittaker_shannon_detail<RandomAccessContainer>>(std::move(y), t0, h))
{}
inline Real operator()(Real t) const
{
return m_impl->operator()(t);
}
inline Real prime(Real t) const
{
return m_impl->prime(t);
}
inline Real operator[](size_t i) const
{
return m_impl->operator[](i);
}
RandomAccessContainer&& return_data()
{
return m_impl->return_data();
}
private:
std::shared_ptr<detail::whittaker_shannon_detail<RandomAccessContainer>> m_impl;
};
}}}
#endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment