16static size_t lmmc_det_pivot(
const lmmc_real_t* lu,
size_t n,
size_t k) {
22 for (
size_t i = k + 1; i < n; ++i) {
32static void lmmc_det_eliminate(
lmmc_real_t* lu,
size_t n,
size_t k) {
36 for (
size_t i = k + 1; i < n; ++i) {
40 for (
size_t j = k + 1; j < n; ++j) {
50 for (
size_t k = 0; k < n; ++k) {
51 size_t pivot_row = lmmc_det_pivot(lu, n, k);
57 for (
size_t j = 0; j < n; ++j) {
59 lu[k * n + j] = lu[pivot_row * n + j];
60 lu[pivot_row * n + j] = tmp;
64 lmmc_det_eliminate(lu, n, k);
70 for (
size_t i = 0; i < n; ++i) {
80static int lmmc_det_fast(
double x,
double y,
double z,
double w,
82 if (!isfinite(p) || !isfinite(q) ||
83 fabs(p) < DBL_MIN || fabs(q) < DBL_MIN) {
86 const double det = fma(x, w, -q) - fma(y, z, -q);
87 if (!isfinite(det) || fabs(det) < DBL_MIN) {
95 const double x = a->
data[0];
96 const double y = a->
data[1];
99 const double p = x * w;
100 const double q = y * z;
102 if (!isfinite(x) || !isfinite(y) || !isfinite(z) || !isfinite(w)) {
106 if (lmmc_det_fast(x, y, z, w, p, q, out_det)) {
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);
123 *out_det = scalbn(sum + residual, scale);
127 if (!lmmc_mat_descriptor_is_valid(a) || out_det == NULL) {
142 lmmc_det_two(a, out_det);
147 if (!lmmc_safe_mul_size(n, n, &n_elem) ||
148 !lmmc_safe_mul_size(n_elem,
sizeof(
lmmc_real_t), &n_bytes)) {
157 for (
size_t i = 0; i < n; ++i) {
158 for (
size_t j = 0; j < n; ++j) {
162 lmmc_det_lu(lu, n, out_det);
182 for (
size_t i = 0; i < n; ++i) {
183 for (
size_t j = 0; j < n; ++j) {
191 for (
size_t j = 0; j < n; ++j) {
202 size_t* pivots = NULL;
205 if (!lmmc_mat_descriptor_is_valid(A) ||
206 !lmmc_mat_descriptor_is_valid(A_inv)) {
231 if (pivots == NULL) {
244 status = lmmc_inverse_columns(&lu_mat, pivots, A_inv);
255 size_t begin = upper ? i + 1 : 0;
256 size_t end = upper ? T->
rows : i;
261 for (
size_t j = begin; j < end; ++j) {
276 if (diag_val == 0.0) {
289 if (!lmmc_mat_descriptor_is_valid(T) ||
290 !lmmc_vec_descriptor_is_valid(b) ||
291 !lmmc_vec_descriptor_is_valid(x)) {
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);
321 if (!lmmc_mat_descriptor_is_valid(a) || out_rank == NULL) {
418 lmmc_fill_identity_unchecked(out);
421 lmmc_status_t status = lmmc_power_multiply(out, base, temp, out);
428 lmmc_status_t status = lmmc_power_multiply(base, base, temp, base);
442 if (!lmmc_mat_descriptor_is_valid(a) ||
443 !lmmc_mat_descriptor_is_valid(out)) {
450 if (out->
rows != dim || out->
cols != dim) {
454 lmmc_fill_identity_unchecked(out);
460 if (!lmmc_safe_mul_size(dim, dim, &total)) {
463 lmmc_status_t status = lmmc_power_workspace(a, n, &base, &temp);
468 unsigned int exp = n < 0 ? (
unsigned int)(-(n + 1)) + 1u : (
unsigned int)n;
469 status = lmmc_power_accumulate(&base, &temp, exp, out);
479 size_t nn = lu->
rows;
490 for (
size_t i = 0; i < B->
rows; ++i) {
491 for (
size_t j = 0; j < nn; ++j) {
498 for (
size_t j = 0; j < nn; ++j) {
510 size_t* pivots = NULL;
514 if (!lmmc_mat_descriptor_is_valid(B) ||
515 !lmmc_mat_descriptor_is_valid(A) ||
516 !lmmc_mat_descriptor_is_valid(X)) {
531 if (X->
rows != m || X->
cols != nn) {
547 if (!lmmc_safe_mul_size(nn,
sizeof(
size_t), &pivot_bytes)) {
552 if (pivots == NULL) {
564 status = lmmc_rdiv_rows(&at_mat, pivots, B, X);
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_status_t lmmc_svd(const lmmc_mat_t *a, lmmc_svd_result_t *out_result)
计算奇异值分解:A = U * Σ * V^T.
void lmmc_svd_result_destroy(lmmc_svd_result_t *result)
释放 lmmc_svd 输出结果.
稠密矩阵直接分解接口(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_NUMERICAL_FAILURE
@ LMMC_STATUS_DIMENSION_MISMATCH
@ LMMC_STATUS_ALLOCATION_FAILED
@ LMMC_STATUS_SINGULAR_MATRIX
@ LMMC_STATUS_INVALID_ARGUMENT