LMMC
Lamina Mathematic core
载入中...
搜索中...
未找到
sparse_cholesky.c
浏览该文件的文档.
1#include <string.h>
2#include <math.h>
3#include "memory_bridge.h"
4#include "internal.h"
5#include "lmmc/sparse.h"
7
8static lmmc_status_t chol_allocate_indices(lmmc_sparse_chol_t* chol)
9{
10 size_t n = chol->n;
11 chol->perm = (size_t*)lmmc_memory_alloc_array(n, sizeof(size_t));
12 chol->perm_inv = (size_t*)lmmc_memory_alloc_array(n, sizeof(size_t));
13 chol->L_col_ptr = (size_t*)lmmc_memory_alloc_array_plus(n, 1, sizeof(size_t));
14
15if (!chol->perm || !chol->perm_inv || !chol->L_col_ptr) {
17 }
18 memset(chol->L_col_ptr, 0, (n + 1) * sizeof(size_t));
19 return LMMC_STATUS_OK;
20}
21
22static lmmc_status_t chol_allocate_factors(lmmc_sparse_chol_t* chol, size_t nnz)
23{
24 size_t n = chol->n;
25 size_t initial_capacity = (nnz > 64) ? nnz : 64;
26 if (initial_capacity < n) {
27 initial_capacity = n;
28 }
29
30 chol->L_row_idx = (size_t*)lmmc_memory_alloc_array(initial_capacity, sizeof(size_t));
31 chol->L_values = (lmmc_real_t*)lmmc_memory_alloc_array(initial_capacity, sizeof(lmmc_real_t));
32
33if (!chol->L_row_idx || !chol->L_values) {
35}
36 chol->L_capacity = initial_capacity;
37 return LMMC_STATUS_OK;
38}
40 const lmmc_sparse_mat_t* a,
41 lmmc_sparse_chol_t** out_chol)
42{
43 lmmc_sparse_chol_t* chol = NULL;
45 int csc_needs_free = 0;
46 size_t n;
47 lmmc_status_t status;
48
49 if (a == NULL || out_chol == NULL) {
51 }
52 if (a->rows == 0 || a->cols == 0) {
54 }
55 if (a->rows != a->cols) {
57 }
58
59 n = a->rows;
60
61 status = lmmc_sparse_direct_csc(a, &csc, &csc_needs_free);
62 if (status != LMMC_STATUS_OK) {
63 return status;
64 }
65
67 if (chol == NULL) {
68 if (csc_needs_free) {
70 }
72 }
73 memset(chol, 0, sizeof(lmmc_sparse_chol_t));
74 chol->n = n;
75status = chol_allocate_indices(chol);
76 if (status == LMMC_STATUS_OK) {
77 status = lmmc_sparse_residual_reorder(&csc, chol->perm);
78 }
79 if (status != LMMC_STATUS_OK) {
80 goto fail;
81 }
82 for (size_t i = 0; i < n; ++i) chol->perm_inv[chol->perm[i]] = i;
83 status = chol_allocate_factors(chol, a->nnz);
84 if (status != LMMC_STATUS_OK) {
85 goto fail;
86 }
87 chol->L_nnz = 0;
88 if (csc_needs_free) {
90 }
91 *out_chol = chol;
92 return LMMC_STATUS_OK;
93fail:
95 if (csc_needs_free) {
97 }
98 return status;
99}
100
101static void chol_scatter_column(const lmmc_sparse_mat_t* csc,
102 const lmmc_sparse_chol_t* chol, size_t j, lmmc_real_t* col_dense)
103{
104 size_t orig_col = chol->perm[j];
105 memset(col_dense, 0, chol->n * sizeof(lmmc_real_t));
106 size_t col_start = csc->row_ptr[orig_col];
107 size_t col_end = csc->row_ptr[orig_col + 1];
108 for (size_t p = col_start; p < col_end; p++) {
109 size_t orig_row = csc->col_idx[p];
110 size_t perm_row = chol->perm_inv[orig_row];
111 if (perm_row >= j) {
112 col_dense[perm_row] += csc->values[p];
113 }
114 }
115}
116
117static lmmc_real_t chol_column_entry(const lmmc_sparse_chol_t* chol,
118 size_t column, size_t row)
119{
120 for (size_t p = chol->L_col_ptr[column]; p < chol->L_col_ptr[column + 1]; ++p) {
121 size_t current = chol->L_row_idx[p];
122 if (current == row) {
123 return chol->L_values[p];
124 }
125 if (current > row) {
126 break;
127 }
128 }
129 return 0.0;
130}
131
132static void chol_update_column(const lmmc_sparse_chol_t* chol, size_t j,
133 lmmc_real_t* col_dense)
134{
136 for (size_t k = 0; k < j; k++) {
137 size_t L_start = chol->L_col_ptr[k];
138 size_t L_end = chol->L_col_ptr[k + 1];
139 lmmc_real_t Ljk = chol_column_entry(chol, k, j);
140 if (Ljk == 0.0) {
141 continue;
142 }
143
145 for (size_t p = L_start; p < L_end; p++) {
146 size_t i = chol->L_row_idx[p];
147 if (i >= j) {
148 col_dense[i] -= chol->L_values[p] * Ljk;
149 }
150 }
151 }
152}
153
154static lmmc_status_t chol_store_column(lmmc_sparse_chol_t* chol, size_t j,
155 const lmmc_real_t* col_dense)
156{
157 size_t n = chol->n;
158 lmmc_status_t status;
159 lmmc_real_t diag = col_dense[j];
160 lmmc_real_t sqrt_diag;
161
162 if (diag <= 0.0) {
164 return status;
165 }
166
167 sqrt_diag = sqrt(diag);
168
169 status = lmmc_sparse_factor_capacity(&chol->L_row_idx, &chol->L_values,
170 &chol->L_capacity, chol->L_nnz);
171 if (status != LMMC_STATUS_OK) {
172 return status;
173 }
174 chol->L_row_idx[chol->L_nnz] = j;
175 chol->L_values[chol->L_nnz] = sqrt_diag;
176 chol->L_nnz++;
177
178 for (size_t i = j + 1; i < n; i++) {
179 if (col_dense[i] != 0.0) {
180 status = lmmc_sparse_factor_capacity(&chol->L_row_idx, &chol->L_values,
181 &chol->L_capacity, chol->L_nnz);
182 if (status != LMMC_STATUS_OK) {
183 return status;
184 }
185 chol->L_row_idx[chol->L_nnz] = i;
186 chol->L_values[chol->L_nnz] = col_dense[i] / sqrt_diag;
187 chol->L_nnz++;
188 }
189 }
190 return LMMC_STATUS_OK;
191}
192
194 const lmmc_sparse_mat_t* a,
195 lmmc_sparse_chol_t* chol)
196{
198 int csc_needs_free = 0;
200 size_t n;
201 lmmc_real_t* col_dense = NULL;
202
203 if (a == NULL || chol == NULL) {
205 }
206 if (a->rows != a->cols) {
208 }
209 if (a->rows != chol->n) {
211 }
212
213 n = chol->n;
214
215 status = lmmc_sparse_direct_csc(a, &csc, &csc_needs_free);
216 if (status != LMMC_STATUS_OK) {
217 return status;
218 }
219
220 col_dense = (lmmc_real_t*)lmmc_memory_alloc_array(n, sizeof(lmmc_real_t));
221 if (col_dense == NULL) {
222 if (csc_needs_free) {
224 }
226 }
227
228 chol->L_nnz = 0;
229
231for (size_t j = 0; j < n; j++) {
232 chol->L_col_ptr[j] = chol->L_nnz;
233 chol_scatter_column(&csc, chol, j, col_dense);
234 chol_update_column(chol, j, col_dense);
235 status = chol_store_column(chol, j, col_dense);
236 if (status != LMMC_STATUS_OK) {
237 goto chol_cleanup;
238 }
239}
240 chol->L_col_ptr[n] = chol->L_nnz;
241
242chol_cleanup:
243 if (col_dense) {
244 lmmc_memory_free(col_dense);
245 }
246 if (csc_needs_free) {
248 }
249 return status;
250}
251
252static lmmc_status_t chol_forward_solve(const lmmc_sparse_chol_t* chol,
253 lmmc_real_t* work)
254{
255 size_t n = chol->n;
257 for (size_t j = 0; j < n; j++) {
258 size_t L_start = chol->L_col_ptr[j];
259 size_t L_end = chol->L_col_ptr[j + 1];
260 lmmc_real_t diag = 0.0;
261 size_t diag_idx = (size_t)-1;
262
263 for (size_t p = L_start; p < L_end; p++) {
264 if (chol->L_row_idx[p] == j) {
265 diag = chol->L_values[p];
266 diag_idx = p;
267 break;
268 }
269 }
270 if (diag == 0.0) {
272 }
273
274 work[j] = work[j] / diag;
275
276 for (size_t p = L_start; p < L_end; p++) {
277 if (p == diag_idx) {
278 continue;
279 }
280 size_t i = chol->L_row_idx[p];
281 work[i] -= chol->L_values[p] * work[j];
282 }
283 }
284 return LMMC_STATUS_OK;
285}
286
287static lmmc_status_t chol_backward_solve(const lmmc_sparse_chol_t* chol,
288 lmmc_real_t* work)
289{
290 size_t n = chol->n;
292 for (size_t jj = 0; jj < n; jj++) {
293 size_t j = n - 1 - jj;
294 size_t L_start = chol->L_col_ptr[j];
295 size_t L_end = chol->L_col_ptr[j + 1];
296 lmmc_real_t diag = 0.0;
297 size_t diag_idx = (size_t)-1;
298
299 for (size_t p = L_start; p < L_end; p++) {
300 if (chol->L_row_idx[p] == j) {
301 diag = chol->L_values[p];
302 diag_idx = p;
303 break;
304 }
305 }
306 if (diag == 0.0) {
308 }
309
310 for (size_t p = L_start; p < L_end; p++) {
311 if (p == diag_idx) {
312 continue;
313 }
314 size_t i = chol->L_row_idx[p];
315 work[j] -= chol->L_values[p] * work[i];
316 }
317 work[j] = work[j] / diag;
318 }
319 return LMMC_STATUS_OK;
320}
321
328 const lmmc_sparse_chol_t* chol,
329 const lmmc_vec_t* b,
330 lmmc_vec_t* x)
331{
332 size_t n;
333 lmmc_real_t* work = NULL;
334
335 if (chol == NULL || b == NULL || x == NULL) {
337 }
338 if (b->data == NULL || x->data == NULL) {
340 }
341
342 n = chol->n;
343 if (b->size != n || x->size != n) {
345 }
346
348 if (work == NULL) {
350 }
351
353 for (size_t i = 0; i < n; i++) {
354 work[i] = b->data[chol->perm[i]];
355 }
356
357lmmc_status_t status = chol_forward_solve(chol, work);
358if (status == LMMC_STATUS_OK) {
359 status = chol_backward_solve(chol, work);
360}
361if (status != LMMC_STATUS_OK) {
362 lmmc_memory_free(work);
363 return status;
364}
367 for (size_t k = 0; k < n; k++) {
368 x->data[chol->perm[k]] = work[k];
369 }
370
371 lmmc_memory_free(work);
372 return LMMC_STATUS_OK;
373}
374
376{
377 if (chol == NULL) {
378 return;
379 }
380 if (chol->perm) {
381 lmmc_memory_free(chol->perm);
382 }
383 if (chol->perm_inv) {
385 }
386 if (chol->L_col_ptr) {
388 }
389 if (chol->L_row_idx) {
391 }
392 if (chol->L_values) {
394 }
395 lmmc_memory_free(chol);
396}
double lmmc_real_t
Public and internal LMMC real type.
lmmc_real_t * data
一维稠密向量。
LMMC 内部使用的公共工具(仅源文件可见).
void * lmmc_memory_alloc_array(size_t count, size_t element_size)
void * lmmc_memory_alloc(size_t size)
void * lmmc_memory_alloc_array_plus(size_t count, size_t extra, size_t element_size)
void lmmc_memory_free(void *pointer)
Private recoverable allocator for persistent LMMC ownership.
lmmc_status_t lmmc_sparse_factor_capacity(size_t **idx, lmmc_real_t **vals, size_t *capacity, size_t needed)
lmmc_status_t lmmc_sparse_direct_csc(const lmmc_sparse_mat_t *a, lmmc_sparse_mat_t *csc_out, int *needs_free)
lmmc_status_t lmmc_sparse_residual_reorder(const lmmc_sparse_mat_t *csc, size_t *perm)
稀疏 Cholesky 分解上下文(不透明类型,要求 A 对称正定)。
lmmc_status_t lmmc_sparse_chol_numeric(const lmmc_sparse_mat_t *a, lmmc_sparse_chol_t *chol)
使用稠密列工作区的左看稀疏 Cholesky 数值分解。
void lmmc_sparse_chol_destroy(lmmc_sparse_chol_t *chol)
销毁稀疏 Cholesky 上下文。
lmmc_status_t lmmc_sparse_chol_solve(const lmmc_sparse_chol_t *chol, const lmmc_vec_t *b, lmmc_vec_t *x)
使用已分解的 Cholesky 因子求解 A*x = b。
lmmc_status_t lmmc_sparse_chol_symbolic(const lmmc_sparse_mat_t *a, lmmc_sparse_chol_t **out_chol)
稀疏 Cholesky 符号分析:去重简单图和贪心残余度重排序。
void lmmc_sparse_destroy(lmmc_sparse_mat_t *sparse)
销毁稀疏矩阵,释放其拥有的缓冲区并清零全部字段。
通用稀疏矩阵(CSR / CSC 共用同一结构)。
lmmc_status_t
LMMC 库统一返回的状态码.
@ LMMC_STATUS_OK
@ LMMC_STATUS_NOT_POSITIVE_DEFINITE
@ LMMC_STATUS_DIMENSION_MISMATCH
@ LMMC_STATUS_ALLOCATION_FAILED
@ LMMC_STATUS_INVALID_ARGUMENT