LMMC
Lamina Mathematic core
载入中...
搜索中...
未找到
quadrature_weighted.c
浏览该文件的文档.
2
11
12#define LMMC_GH_MAX_ORDER 20
13
14static size_t lmmc_quad_tridiag_block_end(
15 const lmmc_real_t* diag, const lmmc_real_t* subdiag, size_t first, size_t n)
16{
17 size_t last = first;
18 while (last < n - 1) {
19 const lmmc_real_t dd = lmmc_abs(diag[last]) + lmmc_abs(diag[last + 1]);
20 if (lmmc_abs(subdiag[last]) + dd == dd) break;
21 ++last;
22 }
23 return last;
24}
25
26static void lmmc_quad_tridiag_sweep(
27 lmmc_real_t* diag, lmmc_real_t* subdiag, lmmc_real_t* z,
28 size_t first, size_t last)
29{
30 lmmc_real_t g = (diag[first + 1] - diag[first]) / (2.0 * subdiag[first]);
31 lmmc_real_t r = sqrt(g * g + 1.0);
32 const lmmc_real_t sign_g = g >= 0.0 ? 1.0 : -1.0;
33 lmmc_real_t s = 1.0, c = 1.0, p = 0.0;
34 g = diag[last] - diag[first] + subdiag[first] / (g + sign_g * r);
35 for (size_t i = last; i > first; --i) {
36 const lmmc_real_t fi = s * subdiag[i - 1];
37 const lmmc_real_t bi = c * subdiag[i - 1];
38 const lmmc_real_t zi = z[i];
39 if (lmmc_abs(fi) >= lmmc_abs(g)) {
40 c = g / fi;
41 r = sqrt(c * c + 1.0);
42 subdiag[i] = fi * r;
43 s = 1.0 / r;
44 c *= s;
45 } else {
46 s = fi / g;
47 r = sqrt(s * s + 1.0);
48 subdiag[i] = g * r;
49 c = 1.0 / r;
50 s *= c;
51 }
52 g = diag[i] - p;
53 r = (diag[i - 1] - g) * s + 2.0 * c * bi;
54 p = s * r;
55 diag[i] = g + p;
56 g = c * r - bi;
57 z[i] = s * z[i - 1] + c * zi;
58 z[i - 1] = c * z[i - 1] - s * zi;
59 }
60 diag[first] -= p;
61 subdiag[first] = g;
62}
63
64static lmmc_status_t tridiag_eigvals_weights(
65 lmmc_real_t* diag, lmmc_real_t* subdiag,
66 lmmc_real_t* weights, size_t n, lmmc_real_t mu0,
67 size_t iteration_limit)
68{
70 for (size_t i = 0; i < n; i++) z[i] = (i == 0) ? 1.0 : 0.0;
71
72 for (size_t l = 0; l < n; l++) {
73 size_t iterations = 0;
74 while (1) {
75 const size_t m =
76 lmmc_quad_tridiag_block_end(diag, subdiag, l, n);
77 if (m == l) break;
78 if (iterations++ >= iteration_limit) {
80 }
81 lmmc_quad_tridiag_sweep(diag, subdiag, z, l, m);
82 if (m < n - 1) subdiag[m] = 0.0;
83 }
84 }
85
86 for (size_t i = 0; i < n; i++) {
87 weights[i] = mu0 * z[i] * z[i];
88 }
89 return LMMC_STATUS_OK;
90}
91
92#ifdef LMMC_BUILD_TESTS
93lmmc_status_t lmmc_quad_gauss_hermite_with_iteration_limit_for_test(
94 lmmc_quad_func_t f, void* ud, size_t order,
95 size_t iteration_limit, lmmc_real_t* out);
96#endif
97
98static lmmc_status_t lmmc_quad_gauss_hermite_impl(
99 lmmc_quad_func_t f, void* ud, size_t order,
100 size_t iteration_limit, lmmc_real_t* out)
101{
105 lmmc_real_t sum = 0.0;
106
107 if (f == NULL || out == NULL) {
109 }
110 if (order < 1 || order > LMMC_GH_MAX_ORDER) {
111 *out = 0.0;
113 }
114
115 for (size_t i = 0; i < order; i++) {
116 diag[i] = 0.0;
117 }
118 for (size_t i = 0; i < order - 1; i++) {
119 subdiag[i] = sqrt((lmmc_real_t)(i + 1) / 2.0);
120 }
121
122 const lmmc_status_t eigensolver_status = tridiag_eigvals_weights(
123 diag, subdiag, weights, order, sqrt(LMMC_CONST_PI),
124 iteration_limit);
125 if (eigensolver_status != LMMC_STATUS_OK) {
126 return eigensolver_status;
127 }
128
129 *out = 0.0;
130 for (size_t i = 0; i < order; i++) {
131 const lmmc_real_t value = f(diag[i], ud);
132 if (!isfinite(value)) {
134 }
135 sum += weights[i] * value;
136 if (!isfinite(sum)) {
138 }
139 }
140
141 *out = sum;
142 return LMMC_STATUS_OK;
143}
144
145#ifdef LMMC_BUILD_TESTS
146lmmc_status_t lmmc_quad_gauss_hermite_with_iteration_limit_for_test(
147 lmmc_quad_func_t f, void* ud, size_t order,
148 size_t iteration_limit, lmmc_real_t* out)
149{
150 return lmmc_quad_gauss_hermite_impl(
151 f, ud, order, iteration_limit, out);
152}
153#endif
154
156 lmmc_quad_func_t f, void* ud,
157 size_t order, lmmc_real_t* out)
158{
159 return lmmc_quad_gauss_hermite_impl(f, ud, order, 100, out);
160}
161
162
171
172#define LMMC_GL_LAG_MAX_ORDER 20
173
175 lmmc_quad_func_t f, void* ud,
176 size_t order, lmmc_real_t* out)
177{
181 lmmc_real_t sum = 0.0;
182
183 if (f == NULL || out == NULL) {
185 }
186 *out = 0.0;
187 if (order < 1 || order > LMMC_GL_LAG_MAX_ORDER) {
189 }
190
191 for (size_t i = 0; i < order; i++) {
192 diag[i] = 2.0 * (lmmc_real_t)i + 1.0;
193 }
194 for (size_t i = 0; i < order - 1; i++) {
195 subdiag[i] = (lmmc_real_t)(i + 1);
196 }
197
198 const lmmc_status_t eigensolver_status = tridiag_eigvals_weights(
199 diag, subdiag, weights, order, 1.0, 100);
200 if (eigensolver_status != LMMC_STATUS_OK) {
201 return eigensolver_status;
202 }
203
204 for (size_t i = 0; i < order; i++) {
205 const lmmc_real_t value = f(diag[i], ud);
206 if (!isfinite(value)) {
208 }
209 sum += weights[i] * value;
210 if (!isfinite(sum)) {
212 }
213 }
214
215 *out = sum;
216 return LMMC_STATUS_OK;
217}
double lmmc_real_t
Public and internal LMMC real type.
#define LMMC_CONST_PI
圆周率常数 。
lmmc_real_t(*) lmmc_quad_func_t(lmmc_real_t x, void *user_data)
被积函数签名 。
lmmc_status_t lmmc_quad_gauss_hermite(lmmc_quad_func_t f, void *ud, size_t order, lmmc_real_t *out)
Gauss-Hermite 求积:权函数 ,积分域 。
lmmc_status_t lmmc_quad_gauss_laguerre(lmmc_quad_func_t f, void *ud, size_t order, lmmc_real_t *out)
Gauss-Laguerre 求积:权函数 ,积分域 。
#define LMMC_GH_MAX_ORDER
Gauss-Hermite 求积,权函数 exp(-x^2),积分域 (-inf, +inf)。
#define LMMC_GL_LAG_MAX_ORDER
Gauss-Laguerre 求积,权函数 exp(-x),积分域 [0, +inf)。
lmmc_status_t
LMMC 库统一返回的状态码.
@ LMMC_STATUS_CONVERGENCE_FAILED
@ LMMC_STATUS_OK
@ LMMC_STATUS_NUMERICAL_FAILURE
@ LMMC_STATUS_INVALID_ARGUMENT