LMMC
Lamina Mathematic core
载入中...
搜索中...
未找到
eigen_general.c
浏览该文件的文档.
1#include <math.h>
2#include <string.h>
3#include "memory_bridge.h"
4#include "internal.h"
5#include "eigen_internal.h"
6#include "lmmc/config.h"
7#include "lmmc/dense.h"
8#include "lmmc/eigen.h"
11
13{
14 for (size_t i = 0; i < a->rows; ++i) {
15 for (size_t j = 0; j < a->cols; ++j) {
16 MAT_ELEM(result, i, j) = MAT_ELEM(a, i, j) / scale;
17 }
18 }
19}
20
22 lmmc_real_t scale)
23{
24 for (size_t i = 0; i < real->size; ++i) {
25 real->data[i] *= scale;
26 imag->data[i] *= scale;
27 if (!isfinite(real->data[i]) || !isfinite(imag->data[i])) {
29 }
30 }
31 return LMMC_STATUS_OK;
32}
34 lmmc_real_t a00, lmmc_real_t a01,
35 lmmc_real_t a10, lmmc_real_t a11,
36 lmmc_real_t *real0, lmmc_real_t *imag0,
37 lmmc_real_t *real1, lmmc_real_t *imag1)
38{
39 const lmmc_real_t trace = a00 + a11;
40 const lmmc_real_t determinant = a00 * a11 - a01 * a10;
41 const lmmc_real_t discriminant =
42 fma(trace, trace, -4.0 * determinant);
43 if (discriminant >= 0.0) {
44 const lmmc_real_t root = sqrt(discriminant);
45 const lmmc_real_t q =
46 0.5 * (trace + copysign(root, trace));
47 *real0 = q;
48 *real1 = q == 0.0 ? 0.0 : determinant / q;
49 *imag0 = 0.0;
50 *imag1 = 0.0;
51 } else {
52 const lmmc_real_t imaginary = sqrt(-discriminant) * 0.5;
53 *real0 = trace * 0.5;
54 *real1 = trace * 0.5;
55 *imag0 = imaginary;
56 *imag1 = -imaginary;
57 }
58}
59
65static void extract_eigenvalues_from_schur(const lmmc_mat_t *H, size_t n,
66 lmmc_real_t *re, lmmc_real_t *im) {
67 size_t i = 0;
68 while (i < n) {
69 if (i + 1 == n || MAT_ELEM(H, i + 1, i) == 0.0) {
71 re[i] = MAT_ELEM(H, i, i);
72 im[i] = 0.0;
73 i++;
74 } else {
76 lmmc_real_t a11 = MAT_ELEM(H, i, i);
77 lmmc_real_t a12 = MAT_ELEM(H, i, i + 1);
78 lmmc_real_t a21 = MAT_ELEM(H, i + 1, i);
79 lmmc_real_t a22 = MAT_ELEM(H, i + 1, i + 1);
81 a11, a12, a21, a22,
82 &re[i], &im[i], &re[i + 1], &im[i + 1]);
83 i += 2;
84 }
85 }
86}
87static void eigenvalues_small(const lmmc_mat_t* a, lmmc_real_t matrix_scale,
88 lmmc_eigen_gen_result_t* out_result)
89{
90 if (a->rows == 1) {
91 out_result->real_parts.data[0] = MAT_ELEM(a, 0, 0);
92 out_result->imag_parts.data[0] = 0.0;
93 return;
94 }
95 lmmc_real_t a00 = MAT_ELEM(a, 0, 0) / matrix_scale;
96 lmmc_real_t a01 = MAT_ELEM(a, 0, 1) / matrix_scale;
97 lmmc_real_t a10 = MAT_ELEM(a, 1, 0) / matrix_scale;
98 lmmc_real_t a11 = MAT_ELEM(a, 1, 1) / matrix_scale;
100 a00, a01, a10, a11,
101 &out_result->real_parts.data[0],
102 &out_result->imag_parts.data[0],
103 &out_result->real_parts.data[1],
104 &out_result->imag_parts.data[1]);
105 out_result->real_parts.data[0] *= matrix_scale;
106 out_result->imag_parts.data[0] *= matrix_scale;
107 out_result->real_parts.data[1] *= matrix_scale;
108 out_result->imag_parts.data[1] *= matrix_scale;
109}
110
111static lmmc_status_t eigenvalues_large(const lmmc_mat_t* a, lmmc_real_t matrix_scale,
112 lmmc_eigen_gen_result_t* out_result)
113{
114 size_t n = a->rows;
115 lmmc_mat_t H, Q_mat;
116 lmmc_status_t status = lmmc_mat_create(n, n, &H);
117 if (status != LMMC_STATUS_OK) {
118 return status;
119 }
120 status = lmmc_mat_create(n, n, &Q_mat);
121 if (status != LMMC_STATUS_OK) {
123 return status;
124 }
125 lmmc_eigen_copy_scaled(a, matrix_scale, &H);
126 status = lmmc_eigen_schur_reduce(&H, &Q_mat);
127 if (status == LMMC_STATUS_OK) {
128 extract_eigenvalues_from_schur(&H, n,
129 out_result->real_parts.data, out_result->imag_parts.data);
130 status = lmmc_eigen_restore_scale(&out_result->real_parts,
131 &out_result->imag_parts, matrix_scale);
132 }
134 lmmc_mat_destroy(&Q_mat);
135 return status;
136}
137
139 lmmc_eigen_gen_result_t* out_result)
140{
141 lmmc_real_t matrix_scale;
142 if (!lmmc_mat_descriptor_is_valid(a) || !out_result) {
144 }
145 if (a->rows != a->cols) {
147 }
148 lmmc_status_t status = lmmc_eigen_matrix_scale(a, &matrix_scale);
149 if (status != LMMC_STATUS_OK) {
150 return status;
151 }
152 size_t n = a->rows;
153 status = lmmc_vec_create(n, &out_result->real_parts);
154 if (status != LMMC_STATUS_OK) {
155 return status;
156 }
157 status = lmmc_vec_create(n, &out_result->imag_parts);
158 if (status != LMMC_STATUS_OK) {
159 lmmc_vec_destroy(&out_result->real_parts);
160 return status;
161 }
162if (n <= 2) {
163 eigenvalues_small(a, matrix_scale, out_result);
164 return LMMC_STATUS_OK;
165 }
166 status = eigenvalues_large(a, matrix_scale, out_result);
167 if (status != LMMC_STATUS_OK) {
169 }
170 return status;
171}
173{
174 if (!result) {
175 return;
176 }
179}
LMMC binary real type and arithmetic spelling.
double lmmc_real_t
Public and internal LMMC real type.
lmmc_status_t lmmc_mat_create(size_t rows, size_t cols, lmmc_mat_t *out_mat)
创建 rows x cols 的零矩阵。
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_status_t lmmc_eigen_general(const lmmc_mat_t *a, lmmc_eigen_gen_result_t *out_result)
计算一般实矩阵的特征值(不输出特征向量).
void lmmc_eigen_gen_result_destroy(lmmc_eigen_gen_result_t *result)
释放 lmmc_eigen_general 输出结果.
一般实矩阵特征分解结果(仅特征值,使用实部 / 虚部分别存储).
定义 eigen.h:28
void lmmc_eigen_values_2x2(lmmc_real_t a00, lmmc_real_t a01, lmmc_real_t a10, lmmc_real_t a11, lmmc_real_t *real0, lmmc_real_t *imag0, lmmc_real_t *real1, lmmc_real_t *imag1)
lmmc_status_t lmmc_eigen_restore_scale(lmmc_vec_t *real, lmmc_vec_t *imag, lmmc_real_t scale)
void lmmc_eigen_copy_scaled(const lmmc_mat_t *a, lmmc_real_t scale, lmmc_mat_t *result)
lmmc_status_t lmmc_eigen_schur_reduce(lmmc_mat_t *h, lmmc_mat_t *q)
lmmc_status_t lmmc_eigen_matrix_scale(const lmmc_mat_t *a, lmmc_real_t *scale)
特征值 / SVD 模块内部共享的缩放、Householder 与 Givens 辅助接口(仅源文件可见)。
#define MAT_ELEM(mat, i, j)
LMMC 内部使用的公共工具(仅源文件可见).
稠密矩阵直接分解接口(LU、Cholesky、QR)。
Private recoverable allocator for persistent LMMC ownership.
lmmc_status_t
LMMC 库统一返回的状态码.
@ LMMC_STATUS_OK
@ LMMC_STATUS_NUMERICAL_FAILURE
@ LMMC_STATUS_INVALID_ARGUMENT