LMMC
Lamina Mathematic core
载入中...
搜索中...
未找到
itersolve_minres.c
浏览该文件的文档.
2#include "precond_internal.h"
3
11
12static lmmc_status_t lmmc_minres_validate(const lmmc_sparse_mat_t* a,
13 const lmmc_vec_t* b, const lmmc_precond_t* precond,
14 const lmmc_itersolve_config_t* cfg, const lmmc_vec_t* x,
16 lmmc_status_t st = lmmc_itersolve_dispatch_config(a, b, cfg, x, local);
17 if (st != LMMC_STATUS_OK) {
18 return st;
19 }
20 if (a != NULL) {
21 if (a->rows != a->cols || b->size != a->rows || x->size != a->cols) {
23 }
24 } else if (b->size != x->size) {
26 }
27 return lmmc_precond_validate_spd(precond, b->size);
28}
29
30static lmmc_status_t lmmc_minres_beta(const lmmc_vec_t* r,
31 const lmmc_vec_t* y, double* beta) {
32 int nonzero = 0;
33 for (size_t i = 0; i < r->size; ++i) {
34 if (!isfinite(r->data[i]) || !isfinite(y->data[i])) {
36 }
37 nonzero |= r->data[i] != 0.0;
38 }
39 double dot;
40 lmmc_status_t st = lmmc_vec_dot_checked(r, y, &dot);
41 if (st != LMMC_STATUS_OK) {
42 return st;
43 }
44 if (dot < 0.0) {
46 }
47 if (dot == 0.0 && nonzero) {
49 }
50 *beta = sqrt(dot);
51 return LMMC_STATUS_OK;
52}
53
54static lmmc_status_t lmmc_minres_start(const lmmc_sparse_mat_t* a,
55 const lmmc_vec_t* b, const lmmc_itersolve_config_t* cfg,
56 const lmmc_vec_t* x, lmmc_minres_state_t* s) {
57 double norm_b;
59 if (st != LMMC_STATUS_OK) {
60 return st;
61 }
62 s->threshold = cfg->abs_tol + cfg->rel_tol * norm_b;
63 if (!isfinite(s->threshold)) {
65 }
66 st = lmmc_itersolve_true_residual(a, cfg, b, x, &s->true_r, &s->norm_r);
67 if (st != LMMC_STATUS_OK) {
68 return st;
69 }
70 return lmmc_vec_copy(&s->true_r, &s->r_curr);
71}
72
73static lmmc_status_t lmmc_minres_lanczos(const lmmc_sparse_mat_t* a,
74 const lmmc_precond_t* precond, const lmmc_itersolve_config_t* cfg,
76 for (size_t i = 0; i < s->v.size; ++i) {
77 s->v.data[i] = s->y.data[i] / s->beta;
78 if (!isfinite(s->v.data[i])) {
80 }
81 }
82 lmmc_status_t st = lmmc_itersolve_matvec(a, cfg, &s->v, &s->lanczos_tmp);
83 if (st != LMMC_STATUS_OK) {
84 return st;
85 }
86 if (s->old_beta != 0.0) {
87 const double scale = s->beta / s->old_beta;
88 if (!isfinite(scale)) {
90 }
91 for (size_t i = 0; i < s->v.size; ++i) {
92 s->lanczos_tmp.data[i] -= scale * s->r_prev.data[i];
93 }
94 }
95 for (size_t i = 0; i < s->v.size; ++i) {
96 if (!isfinite(s->lanczos_tmp.data[i])) {
98 }
99 }
100 st = lmmc_vec_dot_checked(&s->v, &s->lanczos_tmp, &s->alpha);
101 if (st != LMMC_STATUS_OK) {
102 return st;
103 }
104 const double scale = s->alpha / s->beta;
105 if (!isfinite(scale)) {
107 }
108 for (size_t i = 0; i < s->v.size; ++i) {
109 s->lanczos_tmp.data[i] -= scale * s->r_curr.data[i];
110 if (!isfinite(s->lanczos_tmp.data[i])) {
112 }
113 }
114 lmmc_vec_t tmp = s->r_prev;
115 s->r_prev = s->r_curr;
116 s->r_curr = s->lanczos_tmp;
117 s->lanczos_tmp = tmp;
118 st = lmmc_apply_precond_or_identity(precond, &s->r_curr, &s->y);
119 if (st != LMMC_STATUS_OK) {
120 return st;
121 }
122 return lmmc_minres_beta(&s->r_curr, &s->y, &s->beta_next);
123}
124
125static lmmc_status_t lmmc_minres_rotate(lmmc_vec_t* x,
126 lmmc_minres_state_t* s, int* updated) {
127 const double oldeps = s->epsln;
128 const double delta = s->cs * s->dbar + s->sn * s->alpha;
129 const double gbar = s->sn * s->dbar - s->cs * s->alpha;
130 s->epsln = s->sn * s->beta_next;
131 s->dbar = -s->cs * s->beta_next;
132 const double gamma = hypot(gbar, s->beta_next);
133 if (!isfinite(delta) || !isfinite(gbar) || !isfinite(s->epsln) ||
134 !isfinite(s->dbar) || !isfinite(gamma)) {
136 }
137 *updated = 0;
138 if (gamma == 0.0) {
139 return LMMC_STATUS_OK;
140 }
141 s->cs = gbar / gamma;
142 s->sn = s->beta_next / gamma;
143 const double phi = s->cs * s->phibar;
144 s->phibar = s->sn * s->phibar;
145 if (!isfinite(s->cs) || !isfinite(s->sn) || !isfinite(phi) || !isfinite(s->phibar)) {
147 }
148 for (size_t i = 0; i < x->size; ++i) {
149 s->w_next.data[i] = (s->v.data[i] - oldeps * s->w_prev2.data[i] -
150 delta * s->w_prev.data[i]) / gamma;
151 if (!isfinite(s->w_next.data[i])) {
153 }
154 }
155 for (size_t i = 0; i < x->size; ++i) {
156 x->data[i] += phi * s->w_next.data[i];
157 if (!isfinite(x->data[i])) {
159 }
160 }
161 lmmc_vec_t tmp = s->w_prev2;
162 s->w_prev2 = s->w_prev;
163 s->w_prev = s->w_next;
164 s->w_next = tmp;
165 *updated = 1;
166 return LMMC_STATUS_OK;
167}
168
169static lmmc_status_t lmmc_minres_iterate(const lmmc_sparse_mat_t* a,
170 const lmmc_vec_t* b, const lmmc_precond_t* precond,
171 const lmmc_itersolve_config_t* cfg, lmmc_vec_t* x,
172 lmmc_minres_state_t* s, size_t* iterations, int* converged) {
174 if (st != LMMC_STATUS_OK) {
175 return st;
176 }
177 st = lmmc_minres_beta(&s->r_curr, &s->y, &s->beta);
178 if (st != LMMC_STATUS_OK) {
179 return st;
180 }
181 s->cs = -1.0;
182 s->phibar = s->beta;
183 for (size_t iter = 0; iter < cfg->max_iter; ++iter) {
184 st = lmmc_minres_lanczos(a, precond, cfg, s);
185 if (st != LMMC_STATUS_OK) {
186 return st;
187 }
188 int updated;
189 st = lmmc_minres_rotate(x, s, &updated);
190 if (st != LMMC_STATUS_OK) {
191 return st;
192 }
193 if (!updated) {
194 break;
195 }
196 *iterations = iter + 1;
197 st = lmmc_itersolve_true_residual(a, cfg, b, x, &s->true_r, &s->norm_r);
198 if (st != LMMC_STATUS_OK) {
199 return st;
200 }
201 lmmc_itersolve_do_log(cfg, *iterations, s->norm_r);
202 if (s->norm_r <= s->threshold) {
203 *converged = 1;
204 break;
205 }
206 if (s->beta_next == 0.0) {
207 break;
208 }
209 s->old_beta = s->beta;
210 s->beta = s->beta_next;
211 }
212 return LMMC_STATUS_OK;
213}
214
216 const lmmc_vec_t* b, const lmmc_precond_t* precond,
217 const lmmc_itersolve_config_t* cfg, lmmc_vec_t* x,
218 lmmc_itersolve_result_t* out_result) {
220 lmmc_status_t st = lmmc_minres_validate(a, b, precond, cfg, x, &local);
221 if (st != LMMC_STATUS_OK) {
222 return st;
223 }
224 lmmc_minres_state_t s = {.norm_r = NAN};
225 lmmc_real_t* storage = NULL;
226 size_t iterations = 0;
227 int converged = 0;
228 lmmc_itersolve_result_init(out_result);
229 lmmc_vec_t* vectors[] = {&s.r_prev, &s.r_curr, &s.y, &s.v, &s.lanczos_tmp,
230 &s.w_prev2, &s.w_prev, &s.w_next, &s.true_r};
231 const size_t n = b->size;
232 const size_t sizes[] = {n, n, n, n, n, n, n, n, n};
233 st = lmmc_itersolve_workspace(vectors, sizes, 9, &storage);
234 if (st != LMMC_STATUS_OK) {
235 goto cleanup;
236 }
237 st = lmmc_minres_start(a, b, &local, x, &s);
238 if (st != LMMC_STATUS_OK) {
239 goto cleanup;
240 }
241 lmmc_itersolve_initial(out_result, s.norm_r);
242 lmmc_itersolve_do_log(&local, 0, s.norm_r);
243 if (s.norm_r <= s.threshold) {
244 converged = 1;
245 } else {
246 st = lmmc_minres_iterate(a, b, precond, &local, x, &s, &iterations, &converged);
247 }
248cleanup:
249 lmmc_itersolve_finish(out_result, converged, iterations, s.norm_r);
250 lmmc_memory_free(storage);
251 return st;
252}
double lmmc_real_t
Public and internal LMMC real type.
lmmc_status_t lmmc_vec_copy(const lmmc_vec_t *src, lmmc_vec_t *dst)
逐元素复制向量内容:dst = src。
lmmc_real_t * data
一维稠密向量。
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_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_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)
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_status_t lmmc_minres_solve(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_result_t *out_result)
MINRES 求解对称(可能不定)稀疏系统 A x = b 。
迭代求解器配置。
迭代求解的结果统计。
void lmmc_memory_free(void *pointer)
lmmc_status_t lmmc_precond_validate_spd(const lmmc_precond_t *precond, size_t size)
通用预处理子句柄。
通用稀疏矩阵(CSR / CSC 共用同一结构)。
lmmc_status_t
LMMC 库统一返回的状态码.
@ LMMC_STATUS_OK
@ LMMC_STATUS_NUMERICAL_FAILURE
@ LMMC_STATUS_NOT_POSITIVE_DEFINITE
@ LMMC_STATUS_DIMENSION_MISMATCH