Sync public subset from Flux (private)
This commit is contained in:
0
include/numerics/interpolation1d/.gitkeep
Normal file
0
include/numerics/interpolation1d/.gitkeep
Normal file
@@ -0,0 +1,88 @@
|
||||
#pragma once
|
||||
|
||||
#include "./numerics/interpolation1d/interpolation1d_base.h"
|
||||
|
||||
#include "./utils/vector.h"
|
||||
#include "./numerics/min.h"
|
||||
#include "./numerics/max.h"
|
||||
|
||||
|
||||
namespace numerics{
|
||||
|
||||
template <typename T>
|
||||
struct interp_barycentric : Base_interp<T> {
|
||||
using Base = Base_interp<T>;
|
||||
|
||||
// bring base data members into scope (or use this->xx / this->yy below)
|
||||
using Base::xx;
|
||||
using Base::yy;
|
||||
using Base::n;
|
||||
|
||||
utils::Vector<T> w;
|
||||
int64_t d;
|
||||
|
||||
interp_barycentric(const utils::Vector<T> &xv, const utils::Vector<T> &yv, uint64_t dd)
|
||||
: Base_interp<T>(xv, &yv[0], xv.size()), w(n,T{0}), d(dd) {
|
||||
// Constructor arguments are x and y vectors of length n, and order d of desired approximation.
|
||||
if (n <= d){
|
||||
throw std::invalid_argument("d too large for number of points in interp_barycentric");
|
||||
}
|
||||
for (int64_t k = 0; k < n; ++k){
|
||||
int64_t imin = numerics::max(k-d, static_cast<int64_t>(0));
|
||||
int64_t imax;
|
||||
if (k >= n - d) {
|
||||
imax = n - d - 1;
|
||||
} else {
|
||||
imax = k;
|
||||
}
|
||||
T temp;
|
||||
if ( (imin & 1) != 0 ) { // odd?
|
||||
temp = T{-1};
|
||||
} else { // even
|
||||
temp = T{1};
|
||||
}
|
||||
T sum = T{0};
|
||||
|
||||
for (int64_t i = imin; i <= imax; ++i){
|
||||
int64_t jmax = numerics::min(i+d, n-1);
|
||||
T term = T{1};
|
||||
for (int64_t j = i; j <= jmax; ++j){
|
||||
if (j == k){
|
||||
continue;
|
||||
}
|
||||
term *= (xx[k] - xx[j]);
|
||||
}
|
||||
term = temp/term;
|
||||
temp = -temp;
|
||||
sum += term;
|
||||
}
|
||||
w[k] = sum;
|
||||
}
|
||||
}
|
||||
|
||||
T rawinterp(int64_t jl, T x) override{
|
||||
|
||||
T num{T{0}}, den{T{0}};
|
||||
|
||||
for (int64_t i = 0; i < n; ++i){
|
||||
T h = x - xx[i];
|
||||
if (h == T{0}){
|
||||
return yy[i];
|
||||
}else{
|
||||
T temp = w[i]/h;
|
||||
num += temp*yy[i];
|
||||
den += temp;
|
||||
}
|
||||
}
|
||||
return num/den;
|
||||
}
|
||||
|
||||
|
||||
T interp(T x) {
|
||||
return rawinterp(1, x);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
} // namespace numerics
|
||||
|
||||
151
include/numerics/interpolation1d/interpolation1d_base.h
Normal file
151
include/numerics/interpolation1d/interpolation1d_base.h
Normal file
@@ -0,0 +1,151 @@
|
||||
#pragma once
|
||||
|
||||
#include "./numerics/min.h"
|
||||
#include "./numerics/max.h"
|
||||
#include "./numerics/abs.h"
|
||||
|
||||
#include "./utils/vector.h"
|
||||
|
||||
|
||||
namespace numerics{
|
||||
|
||||
template <typename T>
|
||||
struct Base_interp{
|
||||
|
||||
int64_t n, mm;
|
||||
int64_t jsav, dj;
|
||||
bool cor;
|
||||
const T *xx, *yy;
|
||||
|
||||
|
||||
Base_interp(const utils::Vector<T>& x, const T *y, uint64_t m)
|
||||
:n(x.size()), mm(m), jsav(0), cor(false), xx(&x[0]), yy(y){
|
||||
//dj = numerics::min(static_cast<int64_t>(1), static_cast<int64_t>(std::pow(static_cast<T>(n), 0.25))); // from NR
|
||||
dj = numerics::max(static_cast<int64_t>(1), static_cast<int64_t>(std::pow(static_cast<T>(n), 0.25))); // from chatbot
|
||||
|
||||
if (mm < 2 || n < mm) throw std::invalid_argument("Base_interp: invalid mm or n");
|
||||
if (!xx || !yy) throw std::invalid_argument("Base_interp: null data pointers");
|
||||
if (n < 2) throw std::invalid_argument("Base_interp: need at least 2 points");
|
||||
|
||||
bool asc = false;
|
||||
if (xx[0] < xx[1]){
|
||||
asc = true;
|
||||
}
|
||||
for (int64_t i = 1; i < n; ++i){
|
||||
if (!(xx[i] > xx[i-1]) && asc) {
|
||||
throw std::invalid_argument("x must be strictly increasing");
|
||||
} else if (!(xx[i] < xx[i-1]) && !asc){
|
||||
throw std::invalid_argument("x must be strictly decreasing");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
T interp(T x){
|
||||
int64_t jlo;
|
||||
if (cor){
|
||||
jlo = hunt(x);
|
||||
}
|
||||
else{
|
||||
jlo = locate(x);
|
||||
}
|
||||
return rawinterp(jlo,x);
|
||||
}
|
||||
|
||||
// Derived classes provide this as the actual interpolation method.
|
||||
T virtual rawinterp(int64_t jlo, T x) = 0;
|
||||
|
||||
|
||||
int64_t locate(const T x){
|
||||
int64_t ju, jl;
|
||||
int64_t jm;
|
||||
|
||||
if (n < 2 || mm < 2 || mm > n){
|
||||
throw std::runtime_error("Interpolate: locate size error");
|
||||
}
|
||||
|
||||
bool ascnd = (xx[n-1] >= xx[0]); // True if ascending order of table, false otherwise.
|
||||
jl = 0; // Initialize lower
|
||||
ju = n-1; // and upper limits.
|
||||
while (ju - jl > 1) { // If we are not yet done,
|
||||
jm = (ju+jl) >> 1; // compute a midpoint,
|
||||
if ((x >= xx[jm]) == ascnd){
|
||||
jl=jm; // and replace either the lower limit
|
||||
}else{
|
||||
ju=jm; // or the upper limit, as appropriate.
|
||||
}
|
||||
} // Repeat until the test condition is satisfied.
|
||||
|
||||
if (std::abs(jl - jsav) > dj){ // Decide whether to use hunt or locate next time.
|
||||
cor = false;
|
||||
}else{
|
||||
cor = true;
|
||||
}
|
||||
jsav = jl;
|
||||
return numerics::max(static_cast<int64_t>(0), numerics::min(n-mm, jl-((mm-2)>>1)));
|
||||
}
|
||||
|
||||
int64_t hunt(const T x){
|
||||
int64_t jl=jsav, jm, ju, inc=1;
|
||||
|
||||
if (n < 2 || mm < 2 || mm > n){
|
||||
throw std::runtime_error("Interpolate: hunt size error");
|
||||
}
|
||||
bool ascnd=(xx[n-1] >= xx[0]); // True if ascending order of table, false otherwise.
|
||||
if (jl < 0 || jl > n-1) { // Input guess not useful. Go immediately to bisection.
|
||||
jl=0;
|
||||
ju=n-1;
|
||||
}else{
|
||||
if ((x >= xx[jl]) == ascnd){ // Hunt up:
|
||||
for (;;){
|
||||
ju = jl + inc;
|
||||
if (ju >= n-1){
|
||||
ju = n-1;
|
||||
break; // Off end of table.
|
||||
}else if((x < xx[ju]) == ascnd){
|
||||
break; // Found bracket.
|
||||
}else{ // Not done, so double the increment and try again.
|
||||
jl = ju;
|
||||
inc += inc;
|
||||
}
|
||||
}
|
||||
}else{ // Hunt down:
|
||||
ju = jl;
|
||||
for (;;){
|
||||
jl = jl - inc;
|
||||
if (jl <= 0){ //Off end of table.
|
||||
jl = 0;
|
||||
break;
|
||||
}else if((x >= xx[jl]) == ascnd){
|
||||
break; // Found bracket.
|
||||
}
|
||||
else{ // Not done, so double the increment and try again.
|
||||
ju = jl;
|
||||
inc += inc;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
while(ju-jl > 1){ // Hunt is done, so begin the final bisection phase:
|
||||
jm = (ju+jl) >> 1;
|
||||
if ((x >= xx[jm]) == ascnd){
|
||||
jl =jm;
|
||||
}else{
|
||||
ju=jm;
|
||||
}
|
||||
}
|
||||
if (numerics::abs(jl-jsav) > dj){
|
||||
cor = false;
|
||||
}else{
|
||||
cor = true;
|
||||
}
|
||||
jsav = jl;
|
||||
return numerics::max(static_cast<int64_t>(0), numerics::min(n-mm, jl-((mm-2)>>1)));
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
} // namespace numerics
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
#pragma once
|
||||
|
||||
#include "./numerics/interpolation1d/interpolation1d_base.h"
|
||||
|
||||
//#include "./numerics/abs.h"
|
||||
#include "./utils/vector.h"
|
||||
|
||||
|
||||
namespace numerics{
|
||||
|
||||
template <typename T>
|
||||
struct interp_cubic_spline : Base_interp<T> {
|
||||
using Base = Base_interp<T>;
|
||||
// bring base data members into scope (or use this->xx / this->yy below)
|
||||
using Base::xx;
|
||||
using Base::yy;
|
||||
//using Base::mm;
|
||||
|
||||
utils::Vector<T> y2;
|
||||
|
||||
|
||||
interp_cubic_spline(utils::Vector<T> &xv, utils::Vector<T> &yv, T yp1=T{1.e99}, T ypn=T{1.e99})
|
||||
: Base_interp<T>(xv, &yv[0], 2), y2(xv.size(),T{0}) {
|
||||
sety2(&xv[0], &yv[0], yp1, ypn);
|
||||
}
|
||||
|
||||
interp_cubic_spline(utils::Vector<T> &xv, const T *yv, T yp1=T{1.e99}, T ypn=T{1.e99})
|
||||
: Base_interp<T>(xv, yv, 2), y2(xv.size(),T{0}) {
|
||||
sety2(&xv[0], yv, yp1, ypn);
|
||||
}
|
||||
|
||||
|
||||
void sety2(const T *xv, const T *yv, T yp1, T ypn){
|
||||
|
||||
T p, qn, sig, un;
|
||||
uint64_t n = y2.size();
|
||||
utils::Vector<T> u(n-1, T{0});
|
||||
|
||||
if (yp1 > static_cast<T>(0.99e99)){ // The lower boundary condition is set either to be “natural”
|
||||
y2[0] = u[0] = T{0};
|
||||
}else{ // or else to have a specified first derivative.
|
||||
y2[0] = T{-0.5};
|
||||
u[0] = (3.0/(xv[1]-xv[0]))*(((yv[1]-yv[0])/(xv[1]-xv[0]))-yp1);
|
||||
}
|
||||
for (uint64_t i = 1; i < n-1; ++i){ // This is the decomposition loop of the tridiagonal algorithm
|
||||
sig = (xv[i]-xv[i-1])/(xv[i+1]-xv[i-1]);
|
||||
p = sig*y2[i-1]+T{2};
|
||||
y2[i] = (sig - T{1})/p; // y2 and u are used for temporary storage of the decomposed factors.
|
||||
u[i]=((yv[i+1]-yv[i])/(xv[i+1]-xv[i])) - ((yv[i]-yv[i-1])/(xv[i]-xv[i-1]));
|
||||
u[i]=((T{6}*u[i]/(xv[i+1]-xv[i-1])) - sig*u[i-1])/p;
|
||||
}
|
||||
if (ypn > static_cast<T>(0.99e99)){ // The upper boundary condition is set either to be “natural”
|
||||
qn = un = T{0};
|
||||
}else{ // or else to have a specified first derivative.
|
||||
qn = T{0.5};
|
||||
un = (T{3}/(xv[n-1]-xv[n-2]))*(ypn-((yv[n-1]-yv[n-2])/(xv[n-1]-xv[n-2])));
|
||||
}
|
||||
y2[n-1] = (un-(qn*u[n-2]))/((qn*y2[n-2])+T{1});
|
||||
for (int64_t k = n-2; k >= 0; --k){
|
||||
y2[k] = y2[k] * y2[k+1]+u[k];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
T rawinterp(int64_t jl, T x) override{
|
||||
|
||||
int64_t klo=jl, khi=jl+1;
|
||||
T y, h, b, a;
|
||||
|
||||
h = xx[khi] - xx[klo];
|
||||
if (h == T{0}){ // The xa’s must be distinct.
|
||||
throw std::invalid_argument("interp_cubic_spline: Bad input to routine splint");
|
||||
}
|
||||
|
||||
a = (xx[khi] - x)/h; // Cubic spline polynomial is now evaluated.
|
||||
b = (x - xx[klo])/h;
|
||||
y = a*yy[klo] + b*yy[khi] + ( ((a*a*a) - a)*y2[klo] + ((b*b*b) - b)*y2[khi] ) * (h*h) / T{6};
|
||||
|
||||
|
||||
return y;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
} // namespace numerics
|
||||
|
||||
29
include/numerics/interpolation1d/interpolation1d_linear.h
Normal file
29
include/numerics/interpolation1d/interpolation1d_linear.h
Normal file
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#include "./numerics/interpolation1d/interpolation1d_base.h"
|
||||
|
||||
|
||||
namespace numerics{
|
||||
|
||||
template <typename T>
|
||||
struct interp_linear : Base_interp<T> {
|
||||
using Base = Base_interp<T>;
|
||||
// bring base data members into scope (or use this->xx / this->yy below)
|
||||
using Base::xx;
|
||||
using Base::yy;
|
||||
|
||||
|
||||
interp_linear(const utils::Vector<T> &xv, const utils::Vector<T> &yv): Base_interp<T>(xv, &yv[0], 2){}
|
||||
|
||||
T rawinterp(int64_t j, T x) override{
|
||||
if (xx[j]==xx[j+1]){
|
||||
return yy[j]; // Table is defective, but we can recover.
|
||||
}else {
|
||||
return (yy[j] + ((x-xx[j])/(xx[j+1]-xx[j]))*(yy[j+1]-yy[j]));
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
} // namespace numerics
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
#pragma once
|
||||
|
||||
#include "./numerics/interpolation1d/interpolation1d_base.h"
|
||||
|
||||
#include "./numerics/abs.h"
|
||||
#include "./utils/vector.h"
|
||||
|
||||
|
||||
namespace numerics{
|
||||
|
||||
template <typename T>
|
||||
struct interp_polynomial : Base_interp<T> {
|
||||
using Base = Base_interp<T>;
|
||||
// bring base data members into scope (or use this->xx / this->yy below)
|
||||
using Base::xx;
|
||||
using Base::yy;
|
||||
using Base::mm;
|
||||
|
||||
T dy;
|
||||
|
||||
|
||||
interp_polynomial(const utils::Vector<T> &xv, const utils::Vector<T> &yv, uint64_t m)
|
||||
: Base_interp<T>(xv, &yv[0], m), dy(T{0}){}
|
||||
|
||||
T rawinterp(int64_t jl, T x) override{
|
||||
|
||||
int64_t ns=0;
|
||||
T y, den, dif, dift, ho, hp, w;
|
||||
const T *xa = &xx[jl], *ya = &yy[jl];
|
||||
utils::Vector<T> c(mm,0), d(mm,0);
|
||||
dif = numerics::abs(x-xa[0]);
|
||||
|
||||
for (int64_t i = 0; i < mm; ++i){ // Here we find the index ns of the closest table entry,
|
||||
dift = numerics::abs(x-xa[i]);
|
||||
if (dift < dif){
|
||||
ns = i;
|
||||
dif=dift;
|
||||
}
|
||||
c[i]=ya[i]; // and initialize the tableau of c’s and d’s.
|
||||
d[i]=ya[i];
|
||||
}
|
||||
y = ya[ns]; // This is the initial approximation to y.
|
||||
ns -= 1;
|
||||
|
||||
for (int64_t m = 1; m < mm; ++m){ // For each column of the tableau,
|
||||
for (int64_t i = 0; i < mm-m; ++i){ // we loop over the current c’s and d’s and update them.
|
||||
ho = xa[i]-x;
|
||||
hp = xa[i+m]-x;
|
||||
w = c[i+1]-d[i];
|
||||
den = ho-hp;
|
||||
if (den == T{0.0}){
|
||||
throw std::invalid_argument("interp_polynomial error"); // This error can occur only if two input xa’s are (to within roundoff identical.
|
||||
}
|
||||
den = w/den; // Here the c’s and d’s are updated.
|
||||
d[i] = hp*den;
|
||||
c[i] = ho*den;
|
||||
}
|
||||
bool take_left = 2 * (ns + 1) < (mm - m);
|
||||
|
||||
if (take_left) {
|
||||
dy = c[ns + 1];
|
||||
y += dy;
|
||||
} else {
|
||||
dy = d[ns];
|
||||
y += dy;
|
||||
ns -= 1;
|
||||
}
|
||||
}
|
||||
return y;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
} // namespace numerics
|
||||
|
||||
79
include/numerics/interpolation1d/interpolation1d_rational.h
Normal file
79
include/numerics/interpolation1d/interpolation1d_rational.h
Normal file
@@ -0,0 +1,79 @@
|
||||
#pragma once
|
||||
|
||||
#include "./numerics/interpolation1d/interpolation1d_base.h"
|
||||
|
||||
#include "./utils/vector.h"
|
||||
#include "./numerics/abs.h"
|
||||
|
||||
namespace numerics{
|
||||
|
||||
template <typename T>
|
||||
struct interp_rational : Base_interp<T> {
|
||||
using Base = Base_interp<T>;
|
||||
|
||||
// bring base data members into scope (or use this->xx / this->yy below)
|
||||
using Base::xx;
|
||||
using Base::yy;
|
||||
using Base::mm;
|
||||
|
||||
T dy;
|
||||
|
||||
|
||||
|
||||
interp_rational(const utils::Vector<T> &xv, const utils::Vector<T> &yv, uint64_t m)
|
||||
: Base_interp<T>(xv, &yv[0], m), dy(T{0}){}
|
||||
|
||||
T rawinterp(int64_t jl, T x) override{
|
||||
|
||||
const T TINY = T{1.0e-99};
|
||||
int64_t ns=0;
|
||||
T y, w, t, hh, h, dd;
|
||||
const T *xa = &xx[jl], *ya = &yy[jl];
|
||||
utils::Vector<T> c(mm, T{0}), d(mm, T{0});
|
||||
|
||||
hh = numerics::abs(x - xa[0]);
|
||||
|
||||
for (int64_t i = 0; i < mm; ++i){
|
||||
h = numerics::abs(x-xa[i]);
|
||||
if (h == T{0}){
|
||||
dy = T{0};
|
||||
return ya[i];
|
||||
}else if (h < hh){
|
||||
ns = i;
|
||||
hh = h;
|
||||
}
|
||||
c[i] = ya[i];
|
||||
d[i] = ya[i] + TINY; // The TINY part is needed to prevent a rare zero-over-zero condition.
|
||||
}
|
||||
y = ya[ns];
|
||||
ns -= 1;
|
||||
for (int64_t m = 1; m < mm; ++m){
|
||||
for (int64_t i = 0; i < mm-m; ++i){
|
||||
w = c[i+1] - d[i];
|
||||
h = xa[i+m] - x; // h will never be zero, since this was tested in the initializing loop.
|
||||
t = (xa[i] - x)*d[i]/h;
|
||||
dd = t - c[i+1];
|
||||
if (dd == T{0}){ // This error condition indicates that the interpolating function has a pole at the requested value of x.
|
||||
throw std::invalid_argument("Error in routine interp_rational"); //
|
||||
}
|
||||
dd = w/dd;
|
||||
d[i] = c[i+1]*dd;
|
||||
c[i] = t*dd;
|
||||
}
|
||||
const bool take_left = (2 * (ns + 1) < (mm - m));
|
||||
|
||||
if (take_left) {
|
||||
dy = c[ns + 1];
|
||||
} else {
|
||||
dy = d[ns];
|
||||
ns -= 1;
|
||||
}
|
||||
y += dy;
|
||||
}
|
||||
return y;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
} // namespace numerics
|
||||
|
||||
Reference in New Issue
Block a user