LMMC
Lamina Mathematic core
载入中...
搜索中...
未找到
interp_spline.c
浏览该文件的文档.
1#include "memory_bridge.h"
3
4#include <math.h>
5#include <string.h>
6
13
15{
16 if (!spline) {
17 return;
18 }
19 lmmc_memory_free(spline->xs);
20 lmmc_memory_free(spline->ys);
21 lmmc_memory_free(spline->coeffs);
22 lmmc_memory_free(spline);
23}
24
26 const lmmc_interp_cspline_t* spline,
27 lmmc_real_t query_x, lmmc_real_t* out_y)
28{
29 size_t seg;
30 lmmc_real_t dx, a, b, c, d, result;
31 if (!spline || !out_y || !isfinite(query_x)) {
33 }
34 if (query_x < spline->xs[0] || query_x > spline->xs[spline->n - 1]) {
36 }
37 if (query_x == spline->xs[spline->n - 1]) {
38 *out_y = spline->ys[spline->n - 1];
39 return LMMC_STATUS_OK;
40 }
41 seg = interp_find_interval(spline->xs, spline->n, query_x);
42 dx = query_x - spline->xs[seg];
43 a = spline->coeffs[4 * seg + 0];
44 b = spline->coeffs[4 * seg + 1];
45 c = spline->coeffs[4 * seg + 2];
46 d = spline->coeffs[4 * seg + 3];
47 result = a + dx * (b + dx * (c + dx * d));
48 if (!isfinite(result)) {
50 }
51 *out_y = result;
52 return LMMC_STATUS_OK;
53}
54
59static void cspline_compute_coeffs(lmmc_interp_cspline_t* spline,
60 const lmmc_real_t* h,
61 const lmmc_real_t* M)
62{
63 size_t i, nm1 = spline->n - 1;
64 for (i = 0; i < nm1; i++) {
65 lmmc_real_t ai = spline->ys[i];
66 lmmc_real_t ci = M[i] / 2.0;
67 lmmc_real_t di = (M[i + 1] - M[i]) / (6.0 * h[i]);
68 lmmc_real_t bi = (spline->ys[i + 1] - spline->ys[i]) / h[i]
69 - h[i] * (2.0 * M[i] + M[i + 1]) / 6.0;
70 spline->coeffs[4 * i + 0] = ai;
71 spline->coeffs[4 * i + 1] = bi;
72 spline->coeffs[4 * i + 2] = ci;
73 spline->coeffs[4 * i + 3] = di;
74 }
75}
76
77static int interp_spline_check_boundary(const lmmc_real_t* ys, size_t n,
79 lmmc_real_t left, lmmc_real_t right)
80{
81 if (bc < LMMC_SPLINE_NATURAL || bc > LMMC_SPLINE_PERIODIC) {
82 return 0;
83 }
84 if (bc == LMMC_SPLINE_CLAMPED) {
85 return isfinite(left) && isfinite(right);
86 }
87 if (bc == LMMC_SPLINE_PERIODIC && fabs(ys[0] - ys[n - 1]) > 1e-12) {
88 return 0;
89 }
90 return 1;
91}
92
93static lmmc_interp_cspline_t* interp_spline_allocate(
94 const lmmc_real_t* xs, const lmmc_real_t* ys, size_t n)
95{
96 lmmc_interp_cspline_t* spline = lmmc_memory_alloc(sizeof(*spline));
97 if (!spline) {
98 return NULL;
99 }
100 spline->n = n;
101 spline->xs = lmmc_memory_alloc_array(n, sizeof(lmmc_real_t));
102 spline->ys = lmmc_memory_alloc_array(n, sizeof(lmmc_real_t));
103 spline->coeffs = lmmc_memory_alloc_array_2d(n - 1, 4, sizeof(lmmc_real_t));
104 if (!spline->xs || !spline->ys || !spline->coeffs) {
106 return NULL;
107 }
108 memcpy(spline->xs, xs, n * sizeof(lmmc_real_t));
109 memcpy(spline->ys, ys, n * sizeof(lmmc_real_t));
110 return spline;
111}
112
113static int interp_spline_workspace_init(interp_spline_workspace_t* w,
114 const lmmc_interp_cspline_t* spline,
116{
117 size_t i, n = spline->n;
118 size_t arrays = bc == LMMC_SPLINE_PERIODIC ? 8 : 6;
119 lmmc_real_t* storage = lmmc_memory_alloc_array_2d(n, arrays, sizeof(lmmc_real_t));
120 if (!storage) {
121 return 0;
122 }
123 w->n = n;
124 w->ys = spline->ys;
125 w->h = storage;
126 w->moments = storage + n;
127 w->sub = storage + 2 * n;
128 w->dia = storage + 3 * n;
129 w->sup = storage + 4 * n;
130 w->rhs = storage + 5 * n;
131 w->auxiliary = NULL;
132 w->diagonal_copy = NULL;
133 if (bc == LMMC_SPLINE_PERIODIC) {
134 w->auxiliary = storage + 6 * n;
135 w->diagonal_copy = storage + 7 * n;
136 }
137 for (i = 0; i < n - 1; ++i) w->h[i] = spline->xs[i + 1] - spline->xs[i];
138 return 1;
139}
140
142 const lmmc_real_t* xs, const lmmc_real_t* ys, size_t n,
143 lmmc_spline_bc_t bc, lmmc_real_t deriv_left, lmmc_real_t deriv_right,
144 lmmc_interp_cspline_t** out_spline)
145{
146 lmmc_interp_cspline_t* spline;
148 if (!out_spline) {
150 }
151 *out_spline = NULL;
152 if (!interp_check_samples(xs, ys, n, 3)) {
154 }
155 if (!interp_spline_check_boundary(ys, n, bc, deriv_left, deriv_right)) {
157 }
158 spline = interp_spline_allocate(xs, ys, n);
159 if (!spline) {
161 }
162 if (!interp_spline_workspace_init(&work, spline, bc)) {
165 }
166 switch (bc) {
169 break;
172 break;
173 default:
174 interp_spline_standard(&work, bc, deriv_left, deriv_right);
175 break;
176 }
177 cspline_compute_coeffs(spline, work.h, work.moments);
178 lmmc_memory_free(work.h);
179 if (!interp_check_finite_values(spline->coeffs, (n - 1) * 4)) {
182 }
183 *out_spline = spline;
184 return LMMC_STATUS_OK;
185}
186
188 const lmmc_real_t* xs, const lmmc_real_t* ys, size_t n,
189 lmmc_interp_cspline_t** out_spline)
190{
191 return lmmc_interp_cspline_create_ex(xs, ys, n, LMMC_SPLINE_NATURAL, 0.0, 0.0, out_spline);
192}
double lmmc_real_t
Public and internal LMMC real type.
lmmc_status_t lmmc_interp_cspline_eval(const lmmc_interp_cspline_t *spline, lmmc_real_t query_x, lmmc_real_t *out_y)
在样条上求值.
lmmc_status_t lmmc_interp_cspline_create(const lmmc_real_t *xs, const lmmc_real_t *ys, size_t n, lmmc_interp_cspline_t **out_spline)
由节点构造自然三次样条.
lmmc_spline_bc_t
样条边界条件类型.
@ LMMC_SPLINE_NOT_A_KNOT
@ LMMC_SPLINE_CLAMPED
@ LMMC_SPLINE_NATURAL
@ LMMC_SPLINE_PERIODIC
lmmc_status_t lmmc_interp_cspline_create_ex(const lmmc_real_t *xs, const lmmc_real_t *ys, size_t n, lmmc_spline_bc_t bc, lmmc_real_t deriv_left, lmmc_real_t deriv_right, lmmc_interp_cspline_t **out_spline)
由节点构造带指定边界条件的三次样条.
void lmmc_interp_cspline_destroy(lmmc_interp_cspline_t *spline)
销毁三次样条上下文,释放内部分配的所有内存.
void interp_spline_standard(interp_spline_workspace_t *work, lmmc_spline_bc_t bc, lmmc_real_t deriv_left, lmmc_real_t deriv_right)
size_t interp_find_interval(const lmmc_real_t *xs, size_t n, lmmc_real_t query_x)
定义 interp.c:6
int interp_check_finite_values(const lmmc_real_t *values, size_t n)
int interp_check_samples(const lmmc_real_t *xs, const lmmc_real_t *ys, size_t n, size_t minimum)
void interp_spline_periodic(interp_spline_workspace_t *work)
void interp_spline_not_a_knot(interp_spline_workspace_t *work)
三次样条插值上下文(不透明类型,自然边界条件).
void * lmmc_memory_alloc_array(size_t count, size_t element_size)
void * lmmc_memory_alloc(size_t size)
void * lmmc_memory_alloc_array_2d(size_t rows, size_t cols, size_t element_size)
void lmmc_memory_free(void *pointer)
Private recoverable allocator for persistent LMMC ownership.
lmmc_status_t
LMMC 库统一返回的状态码.
@ LMMC_STATUS_OK
@ LMMC_STATUS_NUMERICAL_FAILURE
@ LMMC_STATUS_ALLOCATION_FAILED
@ LMMC_STATUS_INVALID_ARGUMENT
@ LMMC_STATUS_OUT_OF_RANGE