LMMC
Lamina Mathematic core
载入中...
搜索中...
未找到
itersolve_lsqr.c
浏览该文件的文档.
2
8
9static lmmc_status_t lmmc_lsqr_validate(const lmmc_sparse_mat_t* a,
10 const lmmc_vec_t* b, const lmmc_itersolve_config_t* cfg,
11 const lmmc_vec_t* x, lmmc_itersolve_config_t* local) {
12 lmmc_status_t st = lmmc_itersolve_dispatch_config(a, b, cfg, x, local);
13 if (st != LMMC_STATUS_OK) {
14 return st;
15 }
16 if ((a == NULL && local->apply_transpose_op == NULL) ||
17 (a != NULL && local->apply_transpose_op != NULL)) {
19 }
20 if (a != NULL && (b->size != a->rows || x->size != a->cols)) {
22 }
23 return LMMC_STATUS_OK;
24}
25
26static lmmc_status_t lmmc_lsqr_start(const lmmc_sparse_mat_t* a,
27 const lmmc_vec_t* b, const lmmc_itersolve_config_t* cfg,
28 const lmmc_vec_t* x, lmmc_lsqr_state_t* s) {
29 double norm_b;
31 if (st != LMMC_STATUS_OK) {
32 return st;
33 }
34 s->threshold = cfg->abs_tol + cfg->rel_tol * norm_b;
35 if (!isfinite(s->threshold)) {
37 }
38 st = lmmc_itersolve_true_residual(a, cfg, b, x, &s->av_tmp, &s->norm_r);
39 if (st != LMMC_STATUS_OK) {
40 return st;
41 }
42 s->beta = s->norm_r;
43 s->phi_bar = s->beta;
44 return lmmc_vec_copy(&s->av_tmp, &s->u);
45}
46
47static lmmc_status_t lmmc_lsqr_stationary(const lmmc_sparse_mat_t* a,
49 double anorm, int* converged) {
50 /* Normalize before A^T so tiny residuals cannot underflow the test. */
51 for (size_t i = 0; i < s->av_tmp.size; ++i) {
52 s->av_tmp.data[i] /= s->norm_r;
53 }
55 if (st != LMMC_STATUS_OK) {
56 return st;
57 }
58 double norm_atr;
59 st = lmmc_vec_norm2_checked(&s->tmp_vec, &norm_atr);
60 if (st != LMMC_STATUS_OK) {
61 return st;
62 }
63 if (anorm == 0.0) {
64 if (norm_atr != 0.0) {
66 }
67 *converged = 1;
68 } else {
69 double ratio = norm_atr / anorm;
70 if (!isfinite(ratio)) {
72 }
73 *converged = ratio <= cfg->rel_tol;
74 }
75 return LMMC_STATUS_OK;
76}
77
78static lmmc_status_t lmmc_lsqr_basis(const lmmc_sparse_mat_t* a,
80 for (size_t i = 0; i < s->u.size; ++i) {
81 s->u.data[i] /= s->beta;
82 }
83 lmmc_status_t st = lmmc_itersolve_transpose(a, cfg, &s->u, &s->v);
84 if (st != LMMC_STATUS_OK) {
85 return st;
86 }
87 st = lmmc_vec_norm2_checked(&s->v, &s->alpha);
88 if (st != LMMC_STATUS_OK || s->alpha == 0.0) {
89 return st;
90 }
91 for (size_t i = 0; i < s->v.size; ++i) {
92 s->v.data[i] /= s->alpha;
93 }
94 s->rho_bar = s->alpha;
95 return lmmc_vec_copy(&s->v, &s->w);
96}
97
98static lmmc_status_t lmmc_lsqr_bidiagonalize(const lmmc_sparse_mat_t* a,
100 int* basis_exhausted) {
101 const double old_alpha = s->alpha;
102 lmmc_status_t st = lmmc_itersolve_matvec(a, cfg, &s->v, &s->av_tmp);
103 if (st != LMMC_STATUS_OK) {
104 return st;
105 }
106 for (size_t i = 0; i < s->u.size; ++i) {
107 s->u.data[i] = s->av_tmp.data[i] - old_alpha * s->u.data[i];
108 }
109 st = lmmc_vec_norm2_checked(&s->u, &s->beta);
110 if (st != LMMC_STATUS_OK) {
111 return st;
112 }
113 s->anorm = hypot(hypot(s->anorm, old_alpha), s->beta);
114 if (!isfinite(s->anorm)) {
116 }
117 s->alpha = 0.0;
118 if (s->beta != 0.0) {
119 for (size_t i = 0; i < s->u.size; ++i) {
120 s->u.data[i] /= s->beta;
121 }
122 st = lmmc_itersolve_transpose(a, cfg, &s->u, &s->tmp_vec);
123 if (st != LMMC_STATUS_OK) {
124 return st;
125 }
126 for (size_t i = 0; i < s->v.size; ++i) {
127 s->v.data[i] = s->tmp_vec.data[i] - s->beta * s->v.data[i];
128 }
129 st = lmmc_vec_norm2_checked(&s->v, &s->alpha);
130 if (st != LMMC_STATUS_OK) {
131 return st;
132 }
133 if (s->alpha != 0.0) {
134 for (size_t i = 0; i < s->v.size; ++i) {
135 s->v.data[i] /= s->alpha;
136 }
137 }
138 }
139 *basis_exhausted = s->beta == 0.0 || s->alpha == 0.0;
140 return LMMC_STATUS_OK;
141}
142
143static lmmc_status_t lmmc_lsqr_rotate(lmmc_vec_t* x,
144 lmmc_lsqr_state_t* s, int* updated) {
145 *updated = 0;
146 s->rho = hypot(s->rho_bar, s->beta);
147 if (!isfinite(s->rho)) {
149 }
150 if (s->rho == 0.0) {
151 return LMMC_STATUS_OK;
152 }
153 const double cs = s->rho_bar / s->rho;
154 const double sn = s->beta / s->rho;
155 s->theta = sn * s->alpha;
156 s->rho_bar = -cs * s->alpha;
157 const double phi = cs * s->phi_bar;
158 s->phi_bar = sn * s->phi_bar;
159 const double scale = phi / s->rho;
160 if (!isfinite(cs) || !isfinite(sn) || !isfinite(s->theta) ||
161 !isfinite(s->rho_bar) || !isfinite(phi) || !isfinite(s->phi_bar) ||
162 !isfinite(scale)) {
164 }
165 for (size_t i = 0; i < x->size; ++i) {
166 x->data[i] += scale * s->w.data[i];
167 if (!isfinite(x->data[i])) {
169 }
170 }
171 *updated = 1;
172 return LMMC_STATUS_OK;
173}
174
175static lmmc_status_t lmmc_lsqr_iterate(const lmmc_sparse_mat_t* a,
176 const lmmc_vec_t* b, const lmmc_itersolve_config_t* cfg, lmmc_vec_t* x,
177 lmmc_lsqr_state_t* s, size_t* iterations, int* converged) {
178 lmmc_status_t st = lmmc_lsqr_basis(a, cfg, s);
179 if (st != LMMC_STATUS_OK) {
180 return st;
181 }
182 if (s->alpha == 0.0) {
183 return lmmc_lsqr_stationary(a, cfg, s, 0.0, converged);
184 }
185 for (size_t iter = 0; iter < cfg->max_iter; ++iter) {
186 int basis_exhausted;
187 st = lmmc_lsqr_bidiagonalize(a, cfg, s, &basis_exhausted);
188 if (st != LMMC_STATUS_OK) {
189 return st;
190 }
191 /* Even an exhausted basis still supplies its final solution update. */
192 int updated;
193 st = lmmc_lsqr_rotate(x, s, &updated);
194 if (st != LMMC_STATUS_OK) {
195 return st;
196 }
197 if (updated) {
198 *iterations = iter + 1;
199 }
200 st = lmmc_itersolve_true_residual(a, cfg, b, x, &s->av_tmp, &s->norm_r);
201 if (st != LMMC_STATUS_OK) {
202 return st;
203 }
204 if (updated) {
205 lmmc_itersolve_do_log(cfg, *iterations, s->norm_r);
206 }
207 if (s->norm_r <= s->threshold) {
208 *converged = 1;
209 } else {
210 st = lmmc_lsqr_stationary(a, cfg, s, s->anorm, converged);
211 if (st != LMMC_STATUS_OK) {
212 return st;
213 }
214 }
215 if (!updated || *converged || basis_exhausted || *iterations == cfg->max_iter) {
216 break;
217 }
218 const double scale = s->theta / s->rho;
219 if (!isfinite(scale)) {
221 }
222 for (size_t i = 0; i < s->w.size; ++i) {
223 s->w.data[i] = s->v.data[i] - scale * s->w.data[i];
224 if (!isfinite(s->w.data[i])) {
226 }
227 }
228 }
229 return LMMC_STATUS_OK;
230}
231
233 const lmmc_vec_t* b, const lmmc_itersolve_config_t* cfg,
234 lmmc_vec_t* x, lmmc_itersolve_result_t* out_result) {
236 lmmc_status_t st = lmmc_lsqr_validate(a, b, cfg, x, &local);
237 if (st != LMMC_STATUS_OK) {
238 return st;
239 }
240 lmmc_lsqr_state_t s = {.norm_r = NAN};
241 lmmc_real_t* storage = NULL;
242 size_t iterations = 0;
243 int converged = 0;
244 lmmc_itersolve_result_init(out_result);
245 lmmc_vec_t* vectors[] = {&s.u, &s.v, &s.w, &s.tmp_vec, &s.av_tmp};
246 const size_t sizes[] = {b->size, x->size, x->size, x->size, b->size};
247 st = lmmc_itersolve_workspace(vectors, sizes, 5, &storage);
248 if (st != LMMC_STATUS_OK) {
249 goto cleanup;
250 }
251 st = lmmc_lsqr_start(a, b, &local, x, &s);
252 if (st != LMMC_STATUS_OK) {
253 goto cleanup;
254 }
255 lmmc_itersolve_initial(out_result, s.norm_r);
256 lmmc_itersolve_do_log(&local, 0, s.norm_r);
257 if (s.norm_r <= s.threshold) {
258 converged = 1;
259 } else {
260 st = lmmc_lsqr_iterate(a, b, &local, x, &s, &iterations, &converged);
261 }
262cleanup:
263 lmmc_itersolve_finish(out_result, converged, iterations, s.norm_r);
264 lmmc_memory_free(storage);
265 return st;
266}
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_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_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_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_matvec_op_t apply_transpose_op
lmmc_status_t lmmc_lsqr_solve(const lmmc_sparse_mat_t *a, const lmmc_vec_t *b, const lmmc_itersolve_config_t *cfg, lmmc_vec_t *x, lmmc_itersolve_result_t *out_result)
LSQR 求解最小二乘问题 min ||Ax - b||_2 。
迭代求解器配置。
迭代求解的结果统计。
void lmmc_memory_free(void *pointer)
通用稀疏矩阵(CSR / CSC 共用同一结构)。
lmmc_status_t
LMMC 库统一返回的状态码.
@ LMMC_STATUS_OK
@ LMMC_STATUS_NUMERICAL_FAILURE
@ LMMC_STATUS_DIMENSION_MISMATCH
@ LMMC_STATUS_INVALID_ARGUMENT