LMMC
Lamina Mathematic core
载入中...
搜索中...
未找到
quadrature_adaptive.c
浏览该文件的文档.
2#include "memory_bridge.h"
3
12
17
29
30static int lmmc_quad_sum_add(lmmc_quad_sum_t* acc, lmmc_real_t value)
31{
32 const lmmc_real_t sum = acc->sum + value;
33 lmmc_real_t residual;
34 if (!isfinite(sum)) {
35 return 0;
36 }
37 if (fabs(acc->sum) >= fabs(value)) {
38 residual = (acc->sum - sum) + value;
39 } else {
40 residual = (value - sum) + acc->sum;
41 }
42 acc->correction += residual;
43 acc->sum = sum;
44 return isfinite(acc->correction);
45}
46
47static int lmmc_quad_sample(
49{
50 if (!isfinite(x) || work->num_evals == SIZE_MAX) {
51 return 0;
52 }
53 *value = work->func(x, work->user_data);
54 ++work->num_evals;
55 return isfinite(*value);
56}
57
58static lmmc_real_t lmmc_quad_simpson_panel(
59 const lmmc_quad_leaf_t* leaf, size_t first, size_t step)
60{
61 lmmc_real_t center, half_length;
63 leaf->x[first], leaf->x[first + 2 * step], &center, &half_length);
64 return (half_length / 3.0) *
65 (leaf->f[first] + 4.0 * leaf->f[first + step] +
66 leaf->f[first + 2 * step]);
67}
68
69static int lmmc_quad_leaf_estimate(lmmc_quad_leaf_t* leaf)
70{
71 const lmmc_real_t whole = lmmc_quad_simpson_panel(leaf, 0, 2);
72 const lmmc_real_t left = lmmc_quad_simpson_panel(leaf, 0, 1);
73 const lmmc_real_t right = lmmc_quad_simpson_panel(leaf, 2, 1);
74 const lmmc_real_t combined = left + right;
75 const lmmc_real_t delta = combined - whole;
76 leaf->value = combined + delta / 15.0;
77 leaf->error = fabs(delta) / 15.0;
78 return isfinite(whole) && isfinite(left) && isfinite(right) &&
79 isfinite(combined) && isfinite(leaf->value) && isfinite(leaf->error);
80}
81
82static int lmmc_quad_leaf_midpoints(lmmc_quad_leaf_t* leaf)
83{
84 leaf->x[1] = lmmc_quad_midpoint(leaf->x[0], leaf->x[2]);
85 leaf->x[3] = lmmc_quad_midpoint(leaf->x[2], leaf->x[4]);
86 return leaf->x[0] < leaf->x[1] && leaf->x[1] < leaf->x[2] &&
87 leaf->x[2] < leaf->x[3] && leaf->x[3] < leaf->x[4];
88}
89
90static int lmmc_quad_leaf_finish(
92{
93 if (!lmmc_quad_sample(work, leaf->x[1], &leaf->f[1])) {
94 return 0;
95 }
96 if (!lmmc_quad_sample(work, leaf->x[3], &leaf->f[3])) {
97 return 0;
98 }
99 return lmmc_quad_leaf_estimate(leaf);
100}
101
102static int lmmc_quad_leaf_initial(
105{
106 leaf->depth = 0;
107 leaf->x[0] = a;
108 leaf->x[2] = lmmc_quad_midpoint(a, b);
109 leaf->x[4] = b;
110 if (!lmmc_quad_leaf_midpoints(leaf)) {
111 return 0;
112 }
113 if (!lmmc_quad_sample(work, a, &leaf->f[0])) {
114 return 0;
115 }
116 if (!lmmc_quad_sample(work, b, &leaf->f[4])) {
117 return 0;
118 }
119 if (!lmmc_quad_sample(work, leaf->x[2], &leaf->f[2])) {
120 return 0;
121 }
122 return lmmc_quad_leaf_finish(work, leaf);
123}
124
125static int lmmc_quad_leaf_can_split(
126 const lmmc_quad_leaf_t* leaf, size_t max_depth)
127{
128 if (leaf->depth >= max_depth) {
129 return 0;
130 }
132 for (size_t i = 0; i < 4; ++i) {
133 const lmmc_real_t mid = lmmc_quad_midpoint(leaf->x[i], leaf->x[i + 1]);
134 if (mid <= leaf->x[i] || mid >= leaf->x[i + 1]) {
135 return 0;
136 }
137 }
138 return 1;
139}
140
141static int lmmc_quad_leaf_child(
142 lmmc_quad_workspace_t* work, const lmmc_quad_leaf_t* parent,
143 size_t first, lmmc_quad_leaf_t* child)
144{
145 child->depth = parent->depth + 1;
146 for (size_t i = 0; i < 3; ++i) {
147 child->x[2 * i] = parent->x[first + i];
148 child->f[2 * i] = parent->f[first + i];
149 }
150 if (!lmmc_quad_leaf_midpoints(child)) {
151 return 0;
152 }
153 return lmmc_quad_leaf_finish(work, child);
154}
155
156static int lmmc_quad_leaf_precedes(
157 const lmmc_quad_leaf_t* left, const lmmc_quad_leaf_t* right)
158{
159 if (left->error != right->error) {
160 return left->error > right->error;
161 }
162 return left->x[0] < right->x[0];
163}
164
165static int lmmc_quad_heap_reserve(lmmc_quad_workspace_t* work, size_t extra)
166{
167 size_t needed, capacity, bytes;
168 lmmc_quad_leaf_t* heap;
169 if (!lmmc_safe_add_size(work->size, extra, &needed)) {
170 return 0;
171 }
172 if (needed <= work->capacity) {
173 return 1;
174 }
175 capacity = work->capacity == 0 ? 16 : work->capacity;
176 while (capacity < needed) {
177 if (capacity > SIZE_MAX / 2) {
178 capacity = needed;
179 break;
180 }
181 capacity *= 2;
182 }
183 if (!lmmc_safe_mul_size(capacity, sizeof(*heap), &bytes)) {
184 return 0;
185 }
186 heap = (lmmc_quad_leaf_t*)lmmc_memory_realloc(work->heap, bytes);
187 if (heap == NULL) {
188 return 0;
189 }
190 work->heap = heap;
191 work->capacity = capacity;
192 return 1;
193}
194
195static void lmmc_quad_heap_push(
196 lmmc_quad_workspace_t* work, const lmmc_quad_leaf_t* leaf)
197{
198 size_t pos = work->size++;
199 while (pos != 0) {
200 const size_t parent = (pos - 1) / 2;
201 if (!lmmc_quad_leaf_precedes(leaf, &work->heap[parent])) break;
202 work->heap[pos] = work->heap[parent];
203 pos = parent;
204 }
205 work->heap[pos] = *leaf;
206}
207
208static lmmc_quad_leaf_t lmmc_quad_heap_pop(lmmc_quad_workspace_t* work)
209{
210 const lmmc_quad_leaf_t result = work->heap[0];
211 const lmmc_quad_leaf_t last = work->heap[--work->size];
212 size_t pos = 0;
214 while (pos < work->size / 2) {
215 size_t child = 2 * pos + 1;
216 if (child + 1 < work->size &&
217 lmmc_quad_leaf_precedes(&work->heap[child + 1], &work->heap[child])) {
218 ++child;
219 }
220 if (!lmmc_quad_leaf_precedes(&work->heap[child], &last)) break;
221 work->heap[pos] = work->heap[child];
222 pos = child;
223 }
224 if (work->size != 0) work->heap[pos] = last;
225 return result;
226}
227
228static int lmmc_quad_totals_add(
229 lmmc_quad_workspace_t* work, const lmmc_quad_leaf_t* leaf,
230 lmmc_real_t sign)
231{
232 return lmmc_quad_sum_add(&work->value, sign * leaf->value) &&
233 lmmc_quad_sum_add(&work->error, sign * leaf->error);
234}
235
236static lmmc_status_t lmmc_quad_refine(lmmc_quad_workspace_t* work)
237{
238 lmmc_quad_leaf_t parent = lmmc_quad_heap_pop(work);
239 lmmc_quad_leaf_t left, right;
240 int split_left, split_right;
241 if (work->num_evals > SIZE_MAX - 4) {
243 }
244 if (!lmmc_quad_leaf_child(work, &parent, 0, &left) ||
245 !lmmc_quad_leaf_child(work, &parent, 2, &right)) {
247 }
248 split_left = lmmc_quad_leaf_can_split(&left, work->max_depth);
249 split_right = lmmc_quad_leaf_can_split(&right, work->max_depth);
250 if (!lmmc_quad_heap_reserve(work, (size_t)split_left + (size_t)split_right)) {
252 }
253 if (!lmmc_quad_totals_add(work, &parent, -1.0) ||
254 !lmmc_quad_totals_add(work, &left, 1.0) ||
255 !lmmc_quad_totals_add(work, &right, 1.0)) {
257 }
259 if (split_left) {
260 lmmc_quad_heap_push(work, &left);
261 }
262 if (split_right) {
263 lmmc_quad_heap_push(work, &right);
264 }
265 return LMMC_STATUS_OK;
266}
267
268static lmmc_status_t lmmc_quad_global_integral(
269 lmmc_quad_workspace_t* work, const lmmc_quad_leaf_t* root,
270 lmmc_real_t abs_tol, lmmc_real_t rel_tol,
271 lmmc_quad_result_t* result)
272{
273 for (;;) {
274 lmmc_real_t tolerance;
275 lmmc_status_t status;
276 result->value = work->value.sum + work->value.correction;
277 result->error = work->error.sum + work->error.correction;
278 result->num_evals = work->num_evals;
279 tolerance = lmmc_max(abs_tol, rel_tol * fabs(result->value));
280 if (!isfinite(result->value) || !isfinite(result->error) ||
281 result->error < 0.0 || !isfinite(tolerance)) {
283 }
284 if (result->error <= tolerance) {
285 return LMMC_STATUS_OK;
286 }
287 if (root != NULL) {
288 if (lmmc_quad_leaf_can_split(root, work->max_depth)) {
289 if (!lmmc_quad_heap_reserve(work, 1)) {
291 }
292 lmmc_quad_heap_push(work, root);
293 }
294 root = NULL;
295 }
296 if (work->size == 0) {
298 }
299 status = lmmc_quad_refine(work);
300 if (status != LMMC_STATUS_OK) {
301 return status;
302 }
303 }
304}
305
306static int lmmc_quad_adaptive_arguments(
307 lmmc_real_t a, lmmc_real_t b, lmmc_real_t abs_tol, lmmc_real_t rel_tol)
308{
309 if (!isfinite(a) || !isfinite(b) || a >= b) {
310 return 0;
311 }
312 if (!isfinite(abs_tol) || !isfinite(rel_tol)) {
313 return 0;
314 }
315 return abs_tol >= 0.0 && rel_tol >= 0.0;
316}
317
319 lmmc_quad_func_t func, void* user_data,
321 lmmc_real_t abs_tol, lmmc_real_t rel_tol,
322 size_t max_depth, lmmc_quad_result_t* out_result)
323{
324 lmmc_quad_workspace_t work = {0};
325 lmmc_quad_leaf_t root;
326 lmmc_quad_result_t result;
327 lmmc_status_t status;
328 if (func == NULL || out_result == NULL ||
329 !lmmc_quad_adaptive_arguments(a, b, abs_tol, rel_tol)) {
331 }
332 work.func = func;
333 work.user_data = user_data;
334 work.max_depth = max_depth;
335 if (!lmmc_quad_leaf_initial(&work, &root, a, b) ||
336 !lmmc_quad_totals_add(&work, &root, 1.0)) {
338 }
339 status = lmmc_quad_global_integral(&work, &root, abs_tol, rel_tol, &result);
341 if (status == LMMC_STATUS_OK || status == LMMC_STATUS_WARNING_MAX_DEPTH) {
342 *out_result = result;
343 }
344 return status;
345}
double lmmc_real_t
Public and internal LMMC real type.
void * lmmc_memory_realloc(void *pointer, size_t size)
void lmmc_memory_free(void *pointer)
Private recoverable allocator for persistent LMMC ownership.
lmmc_real_t(*) lmmc_quad_func_t(lmmc_real_t x, void *user_data)
被积函数签名 。
lmmc_status_t lmmc_quad_adaptive(lmmc_quad_func_t func, void *user_data, lmmc_real_t a, lmmc_real_t b, lmmc_real_t abs_tol, lmmc_real_t rel_tol, size_t max_depth, lmmc_quad_result_t *out_result)
自适应 Simpson 积分,使用最大误差堆控制全局误差。
自适应积分输出结果。
叶节点保存五个采样值,每个子节点复用其中三个。
void lmmc_quad_center_half_length(lmmc_real_t a, lmmc_real_t b, lmmc_real_t *center, lmmc_real_t *half_length)
lmmc_real_t lmmc_quad_midpoint(lmmc_real_t a, lmmc_real_t b)
lmmc_status_t
LMMC 库统一返回的状态码.
@ LMMC_STATUS_OK
@ LMMC_STATUS_NUMERICAL_FAILURE
@ LMMC_STATUS_ALLOCATION_FAILED
@ LMMC_STATUS_INVALID_ARGUMENT
@ LMMC_STATUS_WARNING_MAX_DEPTH