LMMC
Lamina Mathematic core
载入中...
搜索中...
未找到
itersolve.c
浏览该文件的文档.
2#include "sparse_internal.h"
3
5 if (v == NULL || out_norm == NULL || v->data == NULL || v->size == 0) {
7 }
8
9
10 for (size_t i = 0; i < v->size; ++i) {
11 if (!lmmc_is_finite(&v->data[i])) {
13 }
14 }
15
16 lmmc_status_t st = lmmc_vec_norm2(v, out_norm);
17 if (st != LMMC_STATUS_OK) {
18 return st;
19 }
20
21 if (!lmmc_is_finite(&*out_norm)) {
23 }
24 return LMMC_STATUS_OK;
25}
26
28 lmmc_status_t st = lmmc_vec_dot(a, b, out_dot);
29 if (st != LMMC_STATUS_OK) {
30 return st;
31 }
32 if (!lmmc_is_finite(&*out_dot)) {
34 }
35 return LMMC_STATUS_OK;
36}
37
39 const lmmc_precond_t* precond,
40 const lmmc_vec_t* rhs,
41 lmmc_vec_t* out
42) {
43 if (precond == NULL) {
44 return lmmc_vec_copy(rhs, out);
45 }
46 return lmmc_precond_apply(precond, rhs, out);
47}
48
49void lmmc_itersolve_do_log(const lmmc_itersolve_config_t* cfg, size_t iter, lmmc_real_t residual_norm) {
50 const lmmc_diagnostic_t diagnostic = {
51 LMMC_DIAGNOSTIC_TRACE, "itersolve", "iteration", iter,
52 &residual_norm, 1
53 };
54 lmmc_diagnostic_emit(&cfg->diagnostics, &diagnostic);
55}
56
58 size_t max_iter = 0;
59
60 if (out_cfg == NULL || problem_size == 0) {
62 }
63
64 if (problem_size > ((size_t)-1) / 20) {
65 max_iter = 1000;
66 } else {
67 max_iter = problem_size * 20;
68 if (max_iter < 100) {
69 max_iter = 100;
70 }
71 }
72
73
74 LMMC_REAL_INIT(&out_cfg->abs_tol);
75 LMMC_REAL_INIT(&out_cfg->rel_tol);
77 LMMC_REAL_SET_D(&out_cfg->rel_tol, 1e-8);
78
79 out_cfg->max_iter = max_iter;
80 out_cfg->restart = (problem_size < 30) ? problem_size : 30;
81 out_cfg->diagnostics = (lmmc_diagnostic_sink_t){0};
82 out_cfg->apply_op = NULL;
83 out_cfg->op_user_data = NULL;
84 out_cfg->apply_transpose_op = NULL;
85 return LMMC_STATUS_OK;
86}
87
88static lmmc_status_t lmmc_itersolve_validate_config(const lmmc_itersolve_config_t* cfg) {
89 if (!isfinite(cfg->abs_tol) || !isfinite(cfg->rel_tol) ||
90 cfg->abs_tol < 0.0 || cfg->rel_tol < 0.0 || cfg->max_iter == 0) {
92 }
93 return LMMC_STATUS_OK;
94}
95
96static lmmc_status_t lmmc_itersolve_square_dimensions(const lmmc_sparse_mat_t* a,
97 const lmmc_vec_t* b, const lmmc_vec_t* x) {
98 if (lmmc_sparse_validate(a) != LMMC_STATUS_OK || b == NULL || x == NULL ||
99 b->data == NULL || x->data == NULL) {
101 }
102 if (a->rows == 0 || a->cols == 0 || b->size == 0 || x->size == 0) {
104 }
105 if (a->rows != a->cols || b->size != a->rows || x->size != a->cols) {
107 }
108 return LMMC_STATUS_OK;
109}
110
112 const lmmc_sparse_mat_t* a,
113 const lmmc_vec_t* b,
114 const lmmc_precond_t* precond,
115 const lmmc_itersolve_config_t* cfg,
116 lmmc_vec_t* x,
118 lmmc_itersolve_result_t* out_result
119) {
120 lmmc_status_t st = lmmc_itersolve_square_dimensions(a, b, x);
121 if (st != LMMC_STATUS_OK) {
122 return st;
123 }
124
125 if (cfg != NULL) {
126 *out_cfg = *cfg;
127 } else {
128 st = lmmc_itersolve_default_config(b->size, out_cfg);
129 if (st != LMMC_STATUS_OK) {
130 goto cleanup;
131 }
132 }
133
134 st = lmmc_itersolve_validate_config(out_cfg);
135 if (st != LMMC_STATUS_OK) {
136 return st;
137 }
138
139 if (precond != NULL && precond->size != b->size) {
141 goto cleanup;
142 }
143
144 if (out_result != NULL) {
145 out_result->converged = 0;
146 out_result->num_iter = 0;
149 LMMC_REAL_SET_D(&out_result->initial_residual_norm, 0.0);
150 LMMC_REAL_SET_D(&out_result->final_residual_norm, 0.0);
151 }
152
153cleanup:
154 return st;
155}
156
158 const size_t* sizes, size_t count, lmmc_real_t** storage) {
159 size_t total = 0;
160 for (size_t i = 0; i < count; ++i) {
161 if (!lmmc_safe_add_size(total, sizes[i], &total)) {
163 }
164 }
165 size_t bytes;
166 if (!lmmc_safe_mul_size(total, sizeof(lmmc_real_t), &bytes)) {
168 }
169 *storage = lmmc_memory_alloc(bytes);
170 if (*storage == NULL) {
172 }
173 memset(*storage, 0, bytes);
174 lmmc_real_t* next = *storage;
175 for (size_t i = 0; i < count; ++i) {
176 *vectors[i] = (lmmc_vec_t){sizes[i], next, 0};
177 next += sizes[i];
178 }
179 return LMMC_STATUS_OK;
180}
181
183 if (result != NULL) {
184 result->converged = 0;
185 result->num_iter = 0;
186 result->initial_residual_norm = 0.0;
187 result->final_residual_norm = 0.0;
188 }
189}
190
192 if (result != NULL) {
193 result->initial_residual_norm = norm;
194 result->final_residual_norm = norm;
195 }
196}
197
199 int converged, size_t iterations, lmmc_real_t norm) {
200 if (result != NULL) {
201 result->converged = converged;
202 result->num_iter = iterations;
203 if (isfinite(norm)) {
204 result->final_residual_norm = norm;
205 }
206 }
207}
208
210 const lmmc_vec_t* b, const lmmc_vec_t* x, lmmc_vec_t* ax, lmmc_vec_t* r) {
212 if (st != LMMC_STATUS_OK) {
213 return st;
214 }
215 for (size_t i = 0; i < b->size; ++i) {
216 r->data[i] = b->data[i] - ax->data[i];
217 }
218 return LMMC_STATUS_OK;
219}
220
222 const lmmc_itersolve_config_t* cfg, const lmmc_vec_t* b,
223 const lmmc_vec_t* x, lmmc_vec_t* r, lmmc_real_t* norm) {
224 for (size_t i = 0; i < x->size; ++i) {
225 if (!isfinite(x->data[i])) {
227 }
228 }
229 lmmc_status_t st = lmmc_itersolve_matvec(a, cfg, x, r);
230 if (st != LMMC_STATUS_OK) {
231 return st;
232 }
233 for (size_t i = 0; i < b->size; ++i) {
234 r->data[i] = b->data[i] - r->data[i];
235 }
236 lmmc_real_t value;
237 st = lmmc_vec_norm2_checked(r, &value);
238 if (st == LMMC_STATUS_OK) {
239 *norm = value;
240 }
241 return st;
242}
243
245 const lmmc_vec_t* b, const lmmc_vec_t* r, lmmc_real_t* norm,
246 lmmc_real_t* threshold) {
247 lmmc_real_t norm_b;
248 lmmc_status_t st = lmmc_vec_norm2_checked(b, &norm_b);
249 if (st != LMMC_STATUS_OK) {
250 return st;
251 }
252 st = lmmc_vec_norm2_checked(r, norm);
253 if (st != LMMC_STATUS_OK) {
254 return st;
255 }
256 *threshold = cfg->abs_tol + cfg->rel_tol * norm_b;
257 return isfinite(*threshold) ? LMMC_STATUS_OK : LMMC_STATUS_NUMERICAL_FAILURE;
258}
259
261 const lmmc_vec_t* b, const lmmc_itersolve_config_t* cfg,
262 const lmmc_vec_t* x, lmmc_itersolve_config_t* local) {
263 if (b == NULL || x == NULL || b->data == NULL || x->data == NULL ||
264 b->size == 0 || x->size == 0) {
266 }
267 if (a != NULL && lmmc_sparse_validate(a) != LMMC_STATUS_OK) {
269 }
270 if (cfg != NULL) {
271 *local = *cfg;
272 }
273 else {
275 if (st != LMMC_STATUS_OK) {
276 return st;
277 }
278 }
279 if ((local->apply_op != NULL) == (a != NULL)) {
281 }
282 return lmmc_itersolve_validate_config(local);
283}
284
286 const lmmc_sparse_mat_t* a,
287 const lmmc_itersolve_config_t* cfg,
288 const lmmc_vec_t* x_in,
289 lmmc_vec_t* y_out
290) {
291 if (cfg->apply_op != NULL) {
292 return cfg->apply_op(x_in, y_out, cfg->op_user_data);
293 }
294 return lmmc_sparse_mat_vec_mul(a, x_in, y_out);
295}
296
298static lmmc_status_t lmmc_matvec_transpose_csr(
299 const lmmc_sparse_mat_t* a,
300 const lmmc_vec_t* x_in,
301 lmmc_vec_t* y_out
302) {
303 size_t i, j;
304 for (i = 0; i < y_out->size; ++i) {
305 y_out->data[i] = 0.0;
306 }
307 for (i = 0; i < a->rows; ++i) {
308 size_t start = a->row_ptr[i];
309 size_t end = a->row_ptr[i + 1];
310 for (j = start; j < end; ++j) {
311 size_t col = a->col_idx[j];
312 y_out->data[col] += a->values[j] * x_in->data[i];
313 }
314 }
315 return LMMC_STATUS_OK;
316}
317
319static lmmc_status_t lmmc_matvec_transpose_csc(
320 const lmmc_sparse_mat_t* a,
321 const lmmc_vec_t* x_in,
322 lmmc_vec_t* y_out
323) {
324 size_t i, j;
325 for (j = 0; j < y_out->size; ++j) {
326 y_out->data[j] = 0.0;
327 }
329 for (j = 0; j < a->cols; ++j) {
330 size_t start = a->row_ptr[j];
331 size_t end = a->row_ptr[j + 1];
332 double acc = 0.0;
333 for (i = start; i < end; ++i) {
334 size_t row = a->col_idx[i];
335 acc += a->values[i] * x_in->data[row];
336 }
337 y_out->data[j] = acc;
338 }
339 return LMMC_STATUS_OK;
340}
341
343 const lmmc_sparse_mat_t* a,
344 const lmmc_itersolve_config_t* cfg,
345 const lmmc_vec_t* x_in,
346 lmmc_vec_t* y_out
347) {
348 if (cfg->apply_transpose_op != NULL) {
349 return cfg->apply_transpose_op(x_in, y_out, cfg->op_user_data);
350 }
351 if (lmmc_sparse_validate(a) != LMMC_STATUS_OK) {
353 }
354 if (a->format == LMMC_SPARSE_CSR) {
355 return lmmc_matvec_transpose_csr(a, x_in, y_out);
356 }
357 return lmmc_matvec_transpose_csc(a, x_in, y_out);
358}
#define LMMC_REAL_INIT(x)
初始化一个 lmmc_real_t 变量(POD 类型为空操作)。
double lmmc_real_t
Public and internal LMMC real type.
#define LMMC_REAL_SET_D(dst, dbl)
将一个 double 字面量赋值到 lmmc_real_t 。
lmmc_status_t lmmc_vec_dot(const lmmc_vec_t *a, const lmmc_vec_t *b, lmmc_real_t *out_dot)
计算两个等长向量的内积: 。
lmmc_status_t lmmc_vec_norm2(const lmmc_vec_t *x, lmmc_real_t *out_norm)
计算向量的欧几里得(L2)范数: 。 采用缩放平方和累加;最终结果超出 binary64 范围时可为无穷。
lmmc_status_t lmmc_vec_copy(const lmmc_vec_t *src, lmmc_vec_t *dst)
逐元素复制向量内容:dst = src。
lmmc_real_t * data
一维稠密向量。
void lmmc_diagnostic_emit(const lmmc_diagnostic_sink_t *sink, const lmmc_diagnostic_t *diagnostic)
通过调用方持有的接收器发送一个诊断事件;空接收器直接完成.
@ LMMC_DIAGNOSTIC_TRACE
lmmc_status_t lmmc_vec_dot_checked(const lmmc_vec_t *a, const lmmc_vec_t *b, lmmc_real_t *out_dot)
lmmc_status_t lmmc_vec_norm2_checked(const lmmc_vec_t *v, lmmc_real_t *out_norm)
lmmc_status_t lmmc_itersolve_threshold(const lmmc_itersolve_config_t *cfg, const lmmc_vec_t *b, const lmmc_vec_t *r, lmmc_real_t *norm, lmmc_real_t *threshold)
lmmc_status_t lmmc_itersolve_true_residual(const lmmc_sparse_mat_t *a, const lmmc_itersolve_config_t *cfg, const lmmc_vec_t *b, const lmmc_vec_t *x, lmmc_vec_t *r, lmmc_real_t *norm)
lmmc_status_t lmmc_apply_precond_or_identity(const lmmc_precond_t *precond, const lmmc_vec_t *rhs, lmmc_vec_t *out)
lmmc_status_t lmmc_itersolve_transpose(const lmmc_sparse_mat_t *a, const lmmc_itersolve_config_t *cfg, const lmmc_vec_t *x_in, lmmc_vec_t *y_out)
lmmc_status_t lmmc_itersolve_validate(const lmmc_sparse_mat_t *a, const lmmc_vec_t *b, const lmmc_precond_t *precond, const lmmc_itersolve_config_t *cfg, lmmc_vec_t *x, lmmc_itersolve_config_t *out_cfg, lmmc_itersolve_result_t *out_result)
lmmc_status_t lmmc_itersolve_workspace(lmmc_vec_t *const *vectors, const size_t *sizes, size_t count, lmmc_real_t **storage)
所有视图借用求解过程统一分配的存储区,最后一次日志回调后释放。
void lmmc_itersolve_finish(lmmc_itersolve_result_t *result, int converged, size_t iterations, lmmc_real_t norm)
lmmc_status_t lmmc_itersolve_residual(const lmmc_sparse_mat_t *a, const lmmc_vec_t *b, const lmmc_vec_t *x, lmmc_vec_t *ax, lmmc_vec_t *r)
void lmmc_itersolve_result_init(lmmc_itersolve_result_t *result)
lmmc_status_t lmmc_itersolve_matvec(const lmmc_sparse_mat_t *a, const lmmc_itersolve_config_t *cfg, const lmmc_vec_t *x_in, lmmc_vec_t *y_out)
通过无矩阵算子或稀疏矩阵计算 y = A*x。
void lmmc_itersolve_initial(lmmc_itersolve_result_t *result, lmmc_real_t norm)
lmmc_status_t lmmc_itersolve_dispatch_config(const lmmc_sparse_mat_t *a, const lmmc_vec_t *b, const lmmc_itersolve_config_t *cfg, const lmmc_vec_t *x, lmmc_itersolve_config_t *local)
void lmmc_itersolve_do_log(const lmmc_itersolve_config_t *cfg, size_t iter, lmmc_real_t residual_norm)
lmmc_diagnostic_sink_t diagnostics
lmmc_matvec_op_t apply_transpose_op
lmmc_status_t lmmc_itersolve_default_config(size_t problem_size, lmmc_itersolve_config_t *out_cfg)
根据问题规模生成迭代求解器默认配置。
lmmc_real_t initial_residual_norm
lmmc_matvec_op_t apply_op
迭代求解器配置。
迭代求解的结果统计。
void * lmmc_memory_alloc(size_t size)
#define LMMC_DEFAULT_ABS_TOL
库默认的绝对容差.
lmmc_status_t lmmc_precond_apply(const lmmc_precond_t *precond, const lmmc_vec_t *rhs, lmmc_vec_t *out)
应用预处理子:求解 M*out = rhs。
通用预处理子句柄。
lmmc_status_t lmmc_sparse_mat_vec_mul(const lmmc_sparse_mat_t *sparse, const lmmc_vec_t *x, lmmc_vec_t *y)
稀疏矩阵-稠密向量乘法:y = A * x。
稀疏矩阵模块内部共享辅助函数(仅源文件可见)。
@ LMMC_SPARSE_CSR
lmmc_sparse_format_t format
通用稀疏矩阵(CSR / CSC 共用同一结构)。
lmmc_status_t
LMMC 库统一返回的状态码.
@ LMMC_STATUS_OK
@ LMMC_STATUS_NUMERICAL_FAILURE
@ LMMC_STATUS_DIMENSION_MISMATCH
@ LMMC_STATUS_ALLOCATION_FAILED
@ LMMC_STATUS_INVALID_ARGUMENT