LMMC
Lamina Mathematic core
载入中...
搜索中...
未找到
dense_solvers.c
浏览该文件的文档.
1
5
6#include <float.h>
7#include <math.h>
8#include <string.h>
9#include "memory_bridge.h"
10#include "internal.h"
11#include "lmmc/config.h"
12#include "lmmc/dense.h"
13#include "lmmc/linear_algebra.h"
14#include "lmmc/eigen.h"
15
16static size_t lmmc_det_pivot(const lmmc_real_t* lu, size_t n, size_t k) {
17 size_t pivot_row = k;
18 lmmc_real_t abs_val;
19 lmmc_real_t max_val;
20 lmmc_real_t zero = 0.0;
21 LMMC_REAL_ABS(&max_val, &lu[k * n + k]);
22 for (size_t i = k + 1; i < n; ++i) {
23 LMMC_REAL_ABS(&abs_val, &lu[i * n + k]);
24 if (LMMC_REAL_CMP(&abs_val, &max_val) > 0) {
25 LMMC_REAL_SET(&max_val, &abs_val);
26 pivot_row = i;
27 }
28 }
29 return LMMC_REAL_CMP(&max_val, &zero) == 0 ? n : pivot_row;
30}
31
32static void lmmc_det_eliminate(lmmc_real_t* lu, size_t n, size_t k) {
33 lmmc_real_t factor;
34 lmmc_real_t tmp_mul;
35 lmmc_real_t tmp_sub;
36 for (size_t i = k + 1; i < n; ++i) {
37 LMMC_REAL_DIV(&factor, &lu[i * n + k], &lu[k * n + k]);
38 LMMC_REAL_SET(&lu[i * n + k], &factor);
39
40 for (size_t j = k + 1; j < n; ++j) {
41 LMMC_REAL_MUL(&tmp_mul, &factor, &lu[k * n + j]);
42 LMMC_REAL_SUB(&tmp_sub, &lu[i * n + j], &tmp_mul);
43 LMMC_REAL_SET(&lu[i * n + j], &tmp_sub);
44 }
45 }
46}
47
48static void lmmc_det_lu(lmmc_real_t* lu, size_t n, lmmc_real_t* out_det) {
49 int sign = 1;
50 for (size_t k = 0; k < n; ++k) {
51 size_t pivot_row = lmmc_det_pivot(lu, n, k);
52 if (pivot_row == n) {
53 LMMC_REAL_SET_D(out_det, 0.0);
54 return;
55 }
56 if (pivot_row != k) {
57 for (size_t j = 0; j < n; ++j) {
58 lmmc_real_t tmp = lu[k * n + j];
59 lu[k * n + j] = lu[pivot_row * n + j];
60 lu[pivot_row * n + j] = tmp;
61 }
62 sign = -sign;
63 }
64 lmmc_det_eliminate(lu, n, k);
65 }
66 lmmc_real_t det; LMMC_REAL_INIT(&det);
67 LMMC_REAL_SET_D(&det, (double)sign);
68
69 lmmc_real_t tmp_prod; LMMC_REAL_INIT(&tmp_prod);
70 for (size_t i = 0; i < n; ++i) {
71 LMMC_REAL_MUL(&tmp_prod, &det, &lu[i * n + i]);
72 LMMC_REAL_SET(&det, &tmp_prod);
73 }
74 LMMC_REAL_SET(out_det, &det);
75
76 LMMC_REAL_CLEAR(&det);
77 LMMC_REAL_CLEAR(&tmp_prod);
78}
79
80static int lmmc_det_fast(double x, double y, double z, double w,
81 double p, double q, lmmc_real_t* out_det) {
82 if (!isfinite(p) || !isfinite(q) ||
83 fabs(p) < DBL_MIN || fabs(q) < DBL_MIN) {
84 return 0;
85 }
86 const double det = fma(x, w, -q) - fma(y, z, -q);
87 if (!isfinite(det) || fabs(det) < DBL_MIN) {
88 return 0;
89 }
90 *out_det = det;
91 return 1;
92}
93
94static void lmmc_det_two(const lmmc_mat_t* a, lmmc_real_t* out_det) {
95 const double x = a->data[0];
96 const double y = a->data[1];
97 const double z = a->data[a->stride];
98 const double w = a->data[a->stride + 1];
99 const double p = x * w;
100 const double q = y * z;
101
102 if (!isfinite(x) || !isfinite(y) || !isfinite(z) || !isfinite(w)) {
103 *out_det = p - q;
104 return;
105 }
106 if (lmmc_det_fast(x, y, z, w, p, q, out_det)) {
107 return;
108 }
109 int ex, ey, ez, ew;
110 const double mx = frexp(x, &ex);
111 const double my = frexp(y, &ey);
112 const double mz = frexp(z, &ez);
113 const double mw = frexp(w, &ew);
114 const double mp = mx * mw;
115 const double mq = my * mz;
116 const int ep = ex + ew;
117 const int eq = ey + ez;
118 const int scale = mp == 0.0 ? eq : mq == 0.0 ? ep : ep > eq ? ep : eq;
119 const double sum = scalbn(mp, ep - scale) - scalbn(mq, eq - scale);
120 const double residual = scalbn(fma(mx, mw, -mp), ep - scale) -
121 scalbn(fma(my, mz, -mq), eq - scale);
122 /* Align before subtraction so overflowing products can cancel. */
123 *out_det = scalbn(sum + residual, scale);
124}
125
127 if (!lmmc_mat_descriptor_is_valid(a) || out_det == NULL) {
129 }
130 if (a->rows != a->cols) {
132 }
133
134 size_t n = a->rows;
135
136
137 if (n == 1) {
138 LMMC_REAL_SET(out_det, &a->data[0]);
139 return LMMC_STATUS_OK;
140 }
141 if (n == 2) {
142 lmmc_det_two(a, out_det);
143 return LMMC_STATUS_OK;
144 }
145 size_t n_elem;
146 size_t n_bytes;
147 if (!lmmc_safe_mul_size(n, n, &n_elem) ||
148 !lmmc_safe_mul_size(n_elem, sizeof(lmmc_real_t), &n_bytes)) {
150 }
152 if (lu == NULL) {
154 }
155
156
157 for (size_t i = 0; i < n; ++i) {
158 for (size_t j = 0; j < n; ++j) {
159 lu[i * n + j] = a->data[i * a->stride + j];
160 }
161 }
162 lmmc_det_lu(lu, n, out_det);
164 return LMMC_STATUS_OK;
165}
166
167static lmmc_status_t lmmc_inverse_columns(const lmmc_mat_t* lu,
168 const size_t* pivots, lmmc_mat_t* inverse) {
169 size_t n = lu->rows;
170 lmmc_vec_t ei;
171 lmmc_vec_t col;
172 lmmc_status_t status = lmmc_vec_create(n, &ei);
173 if (status != LMMC_STATUS_OK) {
174 return status;
175 }
176 status = lmmc_vec_create(n, &col);
177 if (status != LMMC_STATUS_OK) {
178 lmmc_vec_destroy(&ei);
179 return status;
180 }
182 for (size_t i = 0; i < n; ++i) {
183 for (size_t j = 0; j < n; ++j) {
184 LMMC_REAL_SET_D(&ei.data[j], 0.0);
185 }
186 LMMC_REAL_SET_D(&ei.data[i], 1.0);
187 status = lmmc_lu_solve(lu, pivots, &ei, &col);
188 if (status != LMMC_STATUS_OK) {
189 break;
190 }
191 for (size_t j = 0; j < n; ++j) {
192 LMMC_REAL_SET(&inverse->data[j * inverse->stride + i], &col.data[j]);
193 }
194 }
195 lmmc_vec_destroy(&col);
196 lmmc_vec_destroy(&ei);
197 return status;
198}
199
201 lmmc_mat_t lu_mat;
202 size_t* pivots = NULL;
203 size_t n;
204 lmmc_status_t status;
205 if (!lmmc_mat_descriptor_is_valid(A) ||
206 !lmmc_mat_descriptor_is_valid(A_inv)) {
208 }
209 if (A->rows != A->cols) {
211 }
212 if (A_inv->rows != A->rows || A_inv->cols != A->cols) {
214 }
215
216 n = A->rows;
217
218 /* Copy A into workspace for LU decomposition */
219 status = lmmc_mat_create(n, n, &lu_mat);
220 if (status != LMMC_STATUS_OK) {
221 return status;
222 }
223 status = lmmc_mat_copy(A, &lu_mat);
224 if (status != LMMC_STATUS_OK) {
225 lmmc_mat_destroy(&lu_mat);
226 return status;
227 }
228
229 /* Allocate pivot array */
230 pivots = (size_t*)lmmc_memory_alloc_array(n, sizeof(size_t));
231 if (pivots == NULL) {
232 lmmc_mat_destroy(&lu_mat);
234 }
235
236 /* LU decompose with partial pivoting */
237 status = lmmc_lu_decompose_inplace(&lu_mat, pivots, NULL);
238 if (status != LMMC_STATUS_OK) {
239 /* Singular or other failure — leave A_inv unmodified */
240 lmmc_memory_free(pivots);
241 lmmc_mat_destroy(&lu_mat);
242 return status;
243 }
244 status = lmmc_inverse_columns(&lu_mat, pivots, A_inv);
245 lmmc_memory_free(pivots);
246 lmmc_mat_destroy(&lu_mat);
247 return status;
248}
249
250static lmmc_status_t lmmc_triangular_row(const lmmc_mat_t* T,
251 int upper, int diag_unit, const lmmc_vec_t* b, lmmc_vec_t* x, size_t i) {
252 lmmc_real_t sum;
253 lmmc_real_t tmp;
254 lmmc_real_t diag_val;
255 size_t begin = upper ? i + 1 : 0;
256 size_t end = upper ? T->rows : i;
257 LMMC_REAL_SET(&sum, &b->data[i]);
258 if (!LMMC_REAL_IS_FINITE(&sum)) {
260 }
261 for (size_t j = begin; j < end; ++j) {
262 LMMC_REAL_MUL(&tmp, &T->data[i * T->stride + j], &x->data[j]);
263 LMMC_REAL_SUB(&sum, &sum, &tmp);
264 if (!LMMC_REAL_IS_FINITE(&tmp) || !LMMC_REAL_IS_FINITE(&sum)) {
266 }
267 }
268 if (diag_unit) {
269 LMMC_REAL_SET(&x->data[i], &sum);
270 return LMMC_STATUS_OK;
271 }
272 LMMC_REAL_SET(&diag_val, &T->data[i * T->stride + i]);
273 if (!LMMC_REAL_IS_FINITE(&diag_val)) {
275 }
276 if (diag_val == 0.0) {
278 }
279 LMMC_REAL_DIV(&x->data[i], &sum, &diag_val);
280 if (!LMMC_REAL_IS_FINITE(&x->data[i])) {
282 }
283 return LMMC_STATUS_OK;
284}
285
286lmmc_status_t lmmc_solve_triangular(const lmmc_mat_t* T, int upper, int diag_unit,
287 const lmmc_vec_t* b, lmmc_vec_t* x) {
288
289 if (!lmmc_mat_descriptor_is_valid(T) ||
290 !lmmc_vec_descriptor_is_valid(b) ||
291 !lmmc_vec_descriptor_is_valid(x)) {
293 }
294 if (T->rows != T->cols) {
296 }
297 if (b->size != T->rows || x->size != T->rows) {
299 }
300 for (size_t step = 0; step < T->rows; ++step) {
301 size_t i = upper ? T->rows - 1 - step : step;
302 lmmc_status_t status = lmmc_triangular_row(T, upper, diag_unit, b, x, i);
303 if (status != LMMC_STATUS_OK) {
304 return status;
305 }
306 }
307 return LMMC_STATUS_OK;
308}
309
310lmmc_status_t lmmc_mat_rank(const lmmc_mat_t* a, lmmc_real_t tol, size_t* out_rank)
311{
313 lmmc_status_t status;
314 size_t i, count;
315 size_t max_dim;
316 lmmc_real_t effective_tol;
317 lmmc_real_t eps_val;
318 lmmc_real_t dim_val;
319 lmmc_real_t tmp;
320
321 if (!lmmc_mat_descriptor_is_valid(a) || out_rank == NULL) {
323 }
324
325 /* Compute SVD */
326 status = lmmc_svd(a, &svd);
327 if (status != LMMC_STATUS_OK) {
328 return status;
329 }
330
331 /* Determine effective tolerance */
332 LMMC_REAL_INIT(&effective_tol);
333 if (tol <= 0.0) {
334 /* Default: max(rows, cols) * LMMC_REAL_EPSILON * sigma[0] */
335 max_dim = (a->rows > a->cols) ? a->rows : a->cols;
336
337 LMMC_REAL_INIT(&eps_val);
339
340 LMMC_REAL_INIT(&dim_val);
341 LMMC_REAL_SET_D(&dim_val, (double)max_dim);
342
343 LMMC_REAL_INIT(&tmp);
344 LMMC_REAL_MUL(&tmp, &dim_val, &eps_val);
345 LMMC_REAL_MUL(&effective_tol, &tmp, &svd.sigma.data[0]);
346
347 LMMC_REAL_CLEAR(&eps_val);
348 LMMC_REAL_CLEAR(&dim_val);
349 LMMC_REAL_CLEAR(&tmp);
350 } else {
351 LMMC_REAL_SET_D(&effective_tol, tol);
352 }
353
354 /* Count singular values > tol */
355 count = 0;
356 for (i = 0; i < svd.sigma.size; ++i) {
357 if (LMMC_REAL_CMP(&svd.sigma.data[i], &effective_tol) > 0) {
358 count++;
359 }
360 }
361
362 *out_rank = count;
363
364 LMMC_REAL_CLEAR(&effective_tol);
366 return LMMC_STATUS_OK;
367}
368
369
370static lmmc_status_t lmmc_power_workspace(const lmmc_mat_t* a, int n,
371 lmmc_mat_t* base, lmmc_mat_t* temp) {
372 lmmc_mat_t inverse = {0};
373 const lmmc_mat_t* source = a;
374 lmmc_status_t status;
375 if (n < 0) {
376 status = lmmc_mat_create(a->rows, a->cols, &inverse);
377 if (status != LMMC_STATUS_OK) {
378 return status;
379 }
380 status = lmmc_mat_inv(a, &inverse);
381 if (status != LMMC_STATUS_OK) {
382 lmmc_mat_destroy(&inverse);
383 return status;
384 }
385 source = &inverse;
386 }
387 status = lmmc_mat_create(a->rows, a->cols, base);
388 if (status == LMMC_STATUS_OK) {
389 status = lmmc_mat_create(a->rows, a->cols, temp);
390 if (status != LMMC_STATUS_OK) {
391 lmmc_mat_destroy(base);
392 }
393 }
394 if (status == LMMC_STATUS_OK) {
395 status = lmmc_mat_copy(source, base);
396 if (status != LMMC_STATUS_OK) {
397 lmmc_mat_destroy(temp);
398 lmmc_mat_destroy(base);
399 }
400 }
401 if (n < 0) {
402 lmmc_mat_destroy(&inverse);
403 }
404 return status;
405}
406
407static lmmc_status_t lmmc_power_multiply(const lmmc_mat_t* left,
408 const lmmc_mat_t* right, lmmc_mat_t* temp, lmmc_mat_t* out) {
409 lmmc_status_t status = lmmc_mat_mul(left, right, temp);
410 if (status != LMMC_STATUS_OK) {
411 return status;
412 }
413 return lmmc_mat_copy(temp, out);
414}
415
416static lmmc_status_t lmmc_power_accumulate(lmmc_mat_t* base,
417 lmmc_mat_t* temp, unsigned int exp, lmmc_mat_t* out) {
418 lmmc_fill_identity_unchecked(out);
419 while (exp > 0) {
420 if (exp & 1u) {
421 lmmc_status_t status = lmmc_power_multiply(out, base, temp, out);
422 if (status != LMMC_STATUS_OK) {
423 return status;
424 }
425 }
426 exp >>= 1u;
427 if (exp > 0) {
428 lmmc_status_t status = lmmc_power_multiply(base, base, temp, base);
429 if (status != LMMC_STATUS_OK) {
430 return status;
431 }
432 }
433 }
434 return LMMC_STATUS_OK;
435}
436
438 lmmc_mat_t base;
439 lmmc_mat_t temp;
440 size_t dim;
441 size_t total;
442 if (!lmmc_mat_descriptor_is_valid(a) ||
443 !lmmc_mat_descriptor_is_valid(out)) {
445 }
446 if (a->rows != a->cols) {
448 }
449 dim = a->rows;
450 if (out->rows != dim || out->cols != dim) {
452 }
453 if (n == 0) {
454 lmmc_fill_identity_unchecked(out);
455 return LMMC_STATUS_OK;
456 }
457 if (n == 1) {
458 return lmmc_mat_copy(a, out);
459 }
460 if (!lmmc_safe_mul_size(dim, dim, &total)) {
462 }
463 lmmc_status_t status = lmmc_power_workspace(a, n, &base, &temp);
464 if (status != LMMC_STATUS_OK) {
465 return status;
466 }
468 unsigned int exp = n < 0 ? (unsigned int)(-(n + 1)) + 1u : (unsigned int)n;
469 status = lmmc_power_accumulate(&base, &temp, exp, out);
470 lmmc_mat_destroy(&temp);
471 lmmc_mat_destroy(&base);
472 return status;
473}
474
475static lmmc_status_t lmmc_rdiv_rows(const lmmc_mat_t* lu,
476 const size_t* pivots, const lmmc_mat_t* B, lmmc_mat_t* X) {
477 lmmc_vec_t rhs_vec;
478 lmmc_vec_t sol_vec;
479 size_t nn = lu->rows;
480 lmmc_status_t status = lmmc_vec_create(nn, &rhs_vec);
481 if (status != LMMC_STATUS_OK) {
482 return status;
483 }
484 status = lmmc_vec_create(nn, &sol_vec);
485 if (status != LMMC_STATUS_OK) {
486 lmmc_vec_destroy(&rhs_vec);
487 return status;
488 }
490 for (size_t i = 0; i < B->rows; ++i) {
491 for (size_t j = 0; j < nn; ++j) {
492 LMMC_REAL_SET(&rhs_vec.data[j], &B->data[i * B->stride + j]);
493 }
494 status = lmmc_lu_solve(lu, pivots, &rhs_vec, &sol_vec);
495 if (status != LMMC_STATUS_OK) {
496 break;
497 }
498 for (size_t j = 0; j < nn; ++j) {
499 LMMC_REAL_SET(&X->data[i * X->stride + j], &sol_vec.data[j]);
500 }
501 }
502 lmmc_vec_destroy(&sol_vec);
503 lmmc_vec_destroy(&rhs_vec);
504 return status;
505}
506
508{
509 lmmc_mat_t at_mat;
510 size_t* pivots = NULL;
511 lmmc_status_t status;
512 size_t nn, m;
513 size_t pivot_bytes;
514 if (!lmmc_mat_descriptor_is_valid(B) ||
515 !lmmc_mat_descriptor_is_valid(A) ||
516 !lmmc_mat_descriptor_is_valid(X)) {
518 }
519 /* A must be square */
520 if (A->rows != A->cols) {
522 }
523 nn = A->rows;
524 m = B->rows;
525
526 /* B must have nn columns */
527 if (B->cols != nn) {
529 }
530 /* X must be m × nn */
531 if (X->rows != m || X->cols != nn) {
533 }
534
535 /* Compute A^T into at_mat */
536 status = lmmc_mat_create(nn, nn, &at_mat);
537 if (status != LMMC_STATUS_OK) {
538 return status;
539 }
540 status = lmmc_mat_transpose_to(A, &at_mat);
541 if (status != LMMC_STATUS_OK) {
542 lmmc_mat_destroy(&at_mat);
543 return status;
544 }
545
546 /* Allocate pivot array */
547 if (!lmmc_safe_mul_size(nn, sizeof(size_t), &pivot_bytes)) {
548 lmmc_mat_destroy(&at_mat);
550 }
551 pivots = (size_t*)lmmc_memory_alloc(pivot_bytes);
552 if (pivots == NULL) {
553 lmmc_mat_destroy(&at_mat);
555 }
556
557 /* LU decompose A^T in-place */
558 status = lmmc_lu_decompose_inplace(&at_mat, pivots, NULL);
559 if (status != LMMC_STATUS_OK) {
560 lmmc_memory_free(pivots);
561 lmmc_mat_destroy(&at_mat);
562 return status;
563 }
564 status = lmmc_rdiv_rows(&at_mat, pivots, B, X);
565 lmmc_memory_free(pivots);
566 lmmc_mat_destroy(&at_mat);
567 return status;
568}
LMMC binary real type and arithmetic spelling.
#define LMMC_REAL_CLEAR(x)
释放一个 lmmc_real_t 变量(POD 类型为空操作)。
#define LMMC_REAL_INIT(x)
初始化一个 lmmc_real_t 变量(POD 类型为空操作)。
#define LMMC_REAL_DIV(res, a, b)
计算 *res = *a / *b 。
#define LMMC_REAL_SUB(res, a, b)
计算 *res = *a - *b 。
double lmmc_real_t
Public and internal LMMC real type.
#define LMMC_REAL_SET(dst, src)
将一个 lmmc_real_t 赋值到另一个:*dst = *src 。
#define LMMC_REAL_MUL(res, a, b)
计算 *res = *a * *b 。
#define LMMC_REAL_EPSILON
既有算法的经验近似阈值,非机器 epsilon。
#define LMMC_REAL_ABS(res, a)
计算绝对值,*res = |*a| 。
#define LMMC_REAL_CMP(a, b)
比较 *a 与 *b ,返回 -1/0/1 。
#define LMMC_REAL_SET_D(dst, dbl)
将一个 double 字面量赋值到 lmmc_real_t 。
#define LMMC_REAL_IS_FINITE(x)
判断 *x 是否为有限数。
lmmc_status_t lmmc_mat_mul(const lmmc_mat_t *a, const lmmc_mat_t *b, lmmc_mat_t *c)
计算矩阵乘积:c = a * b。
lmmc_status_t lmmc_mat_pow(const lmmc_mat_t *a, int n, lmmc_mat_t *out)
计算方阵整数幂 。
lmmc_status_t lmmc_mat_rdiv(const lmmc_mat_t *B, const lmmc_mat_t *A, lmmc_mat_t *X)
计算矩阵右除 。
lmmc_status_t lmmc_mat_det(const lmmc_mat_t *a, lmmc_real_t *out_det)
通过 LU 分解计算方阵行列式。
lmmc_status_t lmmc_mat_rank(const lmmc_mat_t *a, lmmc_real_t tol, size_t *out_rank)
通过 SVD 计算矩阵的数值秩。
lmmc_status_t lmmc_solve_triangular(const lmmc_mat_t *T, int upper, int diag_unit, const lmmc_vec_t *b, lmmc_vec_t *x)
求解三角系统 。
lmmc_status_t lmmc_mat_inv(const lmmc_mat_t *A, lmmc_mat_t *A_inv)
计算方阵的逆矩阵。
lmmc_status_t lmmc_mat_copy(const lmmc_mat_t *src, lmmc_mat_t *dst)
逐元素复制矩阵内容:dst = src。
lmmc_status_t lmmc_mat_create(size_t rows, size_t cols, lmmc_mat_t *out_mat)
创建 rows x cols 的零矩阵。
lmmc_status_t lmmc_mat_transpose_to(const lmmc_mat_t *src, lmmc_mat_t *dst)
计算矩阵转置:dst = src^T。
lmmc_status_t lmmc_vec_create(size_t size, lmmc_vec_t *out_vec)
创建长度为 size 的零向量。
void lmmc_mat_destroy(lmmc_mat_t *mat)
销毁矩阵,释放其拥有的缓冲区并清零结构体字段。
void lmmc_vec_destroy(lmmc_vec_t *vec)
销毁向量,释放其拥有的缓冲区并清零字段。
lmmc_real_t * data
lmmc_real_t * data
行优先存储的稠密矩阵。
一维稠密向量。
特征值 / 奇异值分解,伪逆与条件数接口.
lmmc_status_t lmmc_svd(const lmmc_mat_t *a, lmmc_svd_result_t *out_result)
计算奇异值分解:A = U * Σ * V^T.
lmmc_vec_t sigma
定义 eigen.h:54
void lmmc_svd_result_destroy(lmmc_svd_result_t *result)
释放 lmmc_svd 输出结果.
奇异值分解结果: .
定义 eigen.h:52
LMMC 内部使用的公共工具(仅源文件可见).
稠密矩阵直接分解接口(LU、Cholesky、QR)。
lmmc_status_t lmmc_lu_solve(const lmmc_mat_t *lu, const size_t *pivots, const lmmc_vec_t *b, lmmc_vec_t *x)
利用 LU 分解结果求解线性系统 A*x = b。
lmmc_status_t lmmc_lu_decompose_inplace(lmmc_mat_t *a, size_t *pivots, size_t *out_swap_count)
就地 LU 分解(带部分主元选取):P*A = L*U。
void * lmmc_memory_alloc_array(size_t count, size_t element_size)
void * lmmc_memory_alloc(size_t size)
void lmmc_memory_free(void *pointer)
Private recoverable allocator for persistent LMMC ownership.
lmmc_status_t
LMMC 库统一返回的状态码.
@ LMMC_STATUS_OK
@ LMMC_STATUS_NUMERICAL_FAILURE
@ LMMC_STATUS_DIMENSION_MISMATCH
@ LMMC_STATUS_ALLOCATION_FAILED
@ LMMC_STATUS_SINGULAR_MATRIX
@ LMMC_STATUS_INVALID_ARGUMENT