Skip to content

File interpolation.hpp

File List > astrea > math > math > interpolation.hpp

Go to the documentation of this file

#pragma once

#include <array>
#include <stdexcept>
#include <vector>

namespace astrea {
namespace math {

template <typename X, typename Y>
inline Y interpolate(const std::vector<X>& x, const std::vector<Y>& y, const X& sx)
{
    if (x.size() != y.size()) { throw std::runtime_error("Input vectors must have the same size for interpolation."); }

    const X& xi = x[0];
    const X& xf = x[x.size() - 1];
    if (sx < xi || sx > xf) { throw std::runtime_error("Asked for interpolation outside of dataset bounds."); }
    if (sx == xi) { return y[0]; }
    if (sx == xf) { return y[x.size() - 1]; }

    // Find indexes
    const size_t idx = std::distance(x.begin(), std::lower_bound(x.begin(), x.end(), sx)) - 1;

    // Get nearest points
    const X& x0 = x[idx];
    const X& x1 = x[idx + 1];
    const Y& y0 = y[idx];
    const Y& y1 = y[idx + 1];

    return y0 + (sx - x0) * (y1 - y0) / (x1 - x0);
}

template <typename X, typename Y>
inline Y fast_interpolate(const std::array<X, 2>& x, const std::array<Y, 2>& y, const X& sx)
{
    const X& x0 = x[0];
    const X& x1 = x[1];
    const Y& y0 = y[0];
    const Y& y1 = y[1];

    if (sx < x0 || sx > x1) { throw std::runtime_error("Asked for interpolation outside of dataset bounds."); }
    if (sx == x0) { return y0; }
    if (sx == x1) { return y1; }

    return y0 + (sx - x0) * (y1 - y0) / (x1 - x0);
}

// TDOD: Fix UB somewhere in spline or just get rid of spline.
// std::vector<double> cubic_spline(const std::vector<double>& x, const std::vector<double>& y, const std::vector<double>& sx);

} // namespace math
} // namespace astrea