Hawaii Hybrid
Loading...
Searching...
No Matches
cspline.h
Go to the documentation of this file.
1/*
2 * artfin 14.09.25
3 *
4 * This implementation is based on:
5 * Richard L. Burden & J. Douglas Faires, Numerical Analysis, Ninth Edition
6 * Algoithm 3.5 (page 173)
7 *
8 ************************************************************************
9 * Reference Python program that uses Spline from Scipy.Interpolate
10 *
11 * import numpy as np
12 * from scipy.interpolate import CubicSpline
13 *
14 * if __name__ == "__main__":
15 * x = np.array([-1.0, -0.5, 0.0, 0.5])
16 * y = np.array([0.86199480, 0.95802009, 1.0986123, 1.2943767])
17 *
18 * cs = CubicSpline(x, y, bc_type=((1, 0.155362), (1, 0.451863)))
19 *
20 * print("Coefficients:\n", cs.c)
21 *
22 * x = -0.9
23 * print("x = {}, spline = {}".format(x, cs(x)))
24 *
25 *
26 ************************************************************************
27 * Example:
28 *
29 * #define CSPLINE_IMPLEMENTATION
30 * #include "src/cspline.h"
31 *
32 * int main()
33 * {
34 * double x[] = {-1.0, -0.5, 0.0, 0.5};
35 * double y[] = {0.86199480, 0.95802009, 1.0986123, 1.2943767};
36 * double fp0 = 0.155362;
37 * double fpn = 0.451863;
38 *
39 * CSpline *spl = cspline_init(x, y, sizeof(x)/sizeof(x[0]), fp0, fpn);
40 *
41 * printf("i a[i] \t b[i] \t c[i] \t d[i]\n");
42 * for (size_t i = 0; i < spl->N; ++i) {
43 * printf("%zu \t %.6f \t %.6f \t %.6f \t %.6f\n", i, spl->a[i], spl->b[i], spl->c[i], spl->d[i]);
44 * }
45 *
46 * double yv;
47 * double xv = -0.9;
48 * if (cspline_eval(spl, xv, &yv)) {
49 * printf("x = %.5e => y = %.10e\n", xv, yv);
50 * }
51 *
52 * cspline_free(spl);
53 * return 0;
54 * }
55 */
56
57#ifndef CSPLINE_H_
58#define CSPLINE_H_
59
60#include <assert.h>
61#include <stdbool.h>
62#include <stddef.h>
63#include <stdio.h>
64#include <string.h>
65#include <stdlib.h>
66#include <math.h>
67
68typedef struct {
69 size_t N;
70 double *x;
71 double *y;
72 double fp0;
73 double fpn;
74 double *a;
75 double *h;
76 double *alpha;
77 double *II;
78 double *mu;
79 double *z;
80 double *b;
81 double *c;
82 double *d;
83 double *mem;
84} CSpline;
85
86CSpline* cspline_init(double *x, double *y, size_t len, double fp0, double fpn);
87bool cspline_eval(CSpline *cs, double x, double *y);
89
90
91#ifdef CSPLINE_IMPLEMENTATION
92
93static const double CSPLINE_EPS = 1e-12;
94
95CSpline* cspline_init(double *x, double *y, size_t len, double fp0, double fpn)
96{
97 CSpline *cs = (CSpline*) malloc(1 * sizeof(CSpline));
98 cs->N = len - 1;
99 size_t n = cs->N;
100
101 size_t capacity = 10*(n + 1) + n;
102 double *mem = (double*) malloc(capacity * sizeof(double));
103 assert((mem != NULL) && "ASSERT: cannot allocate enough memory\n");
104 memset(mem, 0, capacity*sizeof(double));
105 cs->mem = mem;
106
107 cs->fp0 = fp0;
108 cs->fpn = fpn;
109
110 size_t offset = 0;
111 cs->x = mem + offset; offset += (n + 1);
112 cs->y = mem + offset; offset += (n + 1);
113 cs->a = mem + offset; offset += (n + 1);
114 cs->h = mem + offset; offset += n;
115 cs->alpha = mem + offset; offset += (n + 1);
116 cs->II = mem + offset; offset += (n + 1);
117 cs->mu = mem + offset; offset += (n + 1);
118 cs->z = mem + offset; offset += (n + 1);
119 cs->b = mem + offset; offset += (n + 1);
120 cs->c = mem + offset; offset += (n + 1);
121 cs->d = mem + offset; offset += (n + 1);
122
123 memcpy(cs->x, x, (n + 1)*sizeof(double));
124 memcpy(cs->y, y, (n + 1)*sizeof(double));
125 memcpy(cs->a, y, (n + 1)*sizeof(double));
126
127 for (size_t i = 0; i < n; ++i) {
128 cs->h[i] = cs->x[i + 1] - cs->x[i];
129
130 if (fabs(cs->h[i]) < CSPLINE_EPS) {
131 printf("ERROR: x-values are too close to each other: difference x[%zu] and x[%zu] is less than expected epsilon\n",
132 i, i + 1);
133 exit(1);
134 }
135
136 if (cs->h[i] < 0) {
137 printf("ERROR: x-values have to be strictly increasing. Found x[%zu] = %.5e and x[%zu] = %.5e which must be increasing\n",
138 i, cs->x[i], i + 1, cs->x[i + 1]);
139 exit(1);
140 }
141 }
142
143 cs->alpha[0] = 3.0*(cs->a[1] - cs->a[0])/cs->h[0] - 3.0*fp0;
144 cs->alpha[n] = 3.0*fpn - 3.0*(cs->a[n] - cs->a[n - 1])/cs->h[n - 1];
145
146 for (size_t i = 1; i < n; ++i) {
147 cs->alpha[i] = 3.0/cs->h[i]*(cs->a[i + 1]-cs->a[i]) - 3.0/cs->h[i - 1]*(cs->a[i]-cs->a[i - 1]);
148 }
149
150 cs->II[0] = 2.0 * cs->h[0];
151 cs->mu[0] = 0.5;
152 cs->z[0] = cs->alpha[0] / cs->II[0];
153
154 for (size_t i = 1; i < n; ++i) {
155 cs->II[i] = 2.0*(cs->x[i + 1] - cs->x[i - 1]) - cs->h[i - 1]*cs->mu[i - 1];
156 cs->mu[i] = cs->h[i] / cs->II[i];
157 cs->z[i] = (cs->alpha[i] - cs->h[i - 1]*cs->z[i - 1])/cs->II[i];
158 }
159
160 cs->II[n] = cs->h[n - 1]*(2.0 - cs->mu[n - 1]);
161 cs->z[n] = (cs->alpha[n] - cs->h[n - 1]*cs->z[n - 1]) / cs->II[n];
162
163 cs->c[n] = cs->z[n];
164
165 for (int j = (int)n - 1; j >= 0; --j) {
166 cs->c[j] = cs->z[j] - cs->mu[j] * cs->c[j + 1];
167 cs->b[j] = (cs->a[j + 1] - cs->a[j])/cs->h[j] - cs->h[j]*(cs->c[j + 1] + 2.0*cs->c[j])/3.0;
168 cs->d[j] = (cs->c[j + 1] - cs->c[j]) / 3.0 / cs->h[j];
169 }
170
171 return cs;
172}
173
174bool cspline_eval(CSpline *cs, double x, double *y)
175{
176 double xmin = cs->x[0];
177 double xmax = cs->x[cs->N];
178 if ((x < xmin) || (x > xmax)) {
179 printf("ERROR: requested x = %.5e is outside interpolation range [%.5e -- %.5e]\n",
180 x, xmin, xmax);
181 return false;
182 }
183
184 size_t j = 0;
185 while ((j <= cs->N - 1) && (x >= cs->x[j + 1])) j++;
186
187 *y = cs->a[j] + cs->b[j]*(x - cs->x[j]) + cs->c[j]*(x - cs->x[j])*(x - cs->x[j]) + cs->d[j]*(x - cs->x[j])*(x - cs->x[j])*(x - cs->x[j]);
188 return true;
189}
190
191void cspline_free(CSpline *cs)
192{
193 free(cs->mem);
194 free(cs);
195}
196
197#endif // CSPLINE_IMPLEMENTATION
198
199#endif // CSPLINE_H_
CSpline * cspline_init(double *x, double *y, size_t len, double fp0, double fpn)
void cspline_free(CSpline *cs)
bool cspline_eval(CSpline *cs, double x, double *y)
Definition cspline.h:68
double * h
Definition cspline.h:75
double * mu
Definition cspline.h:78
double * a
Definition cspline.h:74
double * c
Definition cspline.h:81
size_t N
Definition cspline.h:69
double * x
Definition cspline.h:70
double * z
Definition cspline.h:79
double fp0
Definition cspline.h:72
double * II
Definition cspline.h:77
double * d
Definition cspline.h:82
double * alpha
Definition cspline.h:76
double * b
Definition cspline.h:80
double * mem
Definition cspline.h:83
double * y
Definition cspline.h:71
double fpn
Definition cspline.h:73