LMMC
Lamina Mathematic core
载入中...
搜索中...
未找到
eigen_inverse_iteration.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
19
20static void inverse_workspace_destroy(lmmc_eigen_inverse_workspace_t* work)
21{
23 lmmc_vec_destroy(&work->rhs);
24 if (work->pivots) {
26 }
28 memset(work, 0, sizeof(*work));
29}
30
31static lmmc_status_t inverse_workspace_resize(lmmc_eigen_inverse_workspace_t* work, size_t n)
32{
33 if (work->shifted.rows == n) {
34 return LMMC_STATUS_OK;
35 }
36 inverse_workspace_destroy(work);
37 lmmc_status_t status = lmmc_mat_create(n, n, &work->shifted);
38 if (status != LMMC_STATUS_OK) {
39 return status;
40 }
41 work->pivots = (size_t*)lmmc_memory_alloc_array(n, sizeof(size_t));
42 if (!work->pivots) {
44 }
45 status = lmmc_vec_create(n, &work->rhs);
46 if (status != LMMC_STATUS_OK) {
47 return status;
48 }
49 return lmmc_vec_create(n, &work->solution);
50}
51
52static lmmc_real_t inverse_matrix_norm(const lmmc_mat_t* A)
53{
54 lmmc_real_t norm_A = 0.0;
55 for (size_t i = 0; i < A->rows; i++) {
56 for (size_t j = 0; j < A->rows; j++) {
57 norm_A += MAT_ELEM(A, i, j) * MAT_ELEM(A, i, j);
58 }
59 }
60 norm_A = sqrt(norm_A);
61 if (norm_A < 1.0) {
62 norm_A = 1.0;
63 }
64 return norm_A;
65}
66
67static void fill_real_shift(const lmmc_mat_t* A, lmmc_real_t shift, lmmc_mat_t* shifted)
68{
69 for (size_t i = 0; i < A->rows; i++) {
70 for (size_t j = 0; j < A->rows; j++) {
71 MAT_ELEM(shifted, i, j) = MAT_ELEM(A, i, j) - ((i == j) ? shift : 0.0);
72 }
73 }
74}
75
76static lmmc_status_t factor_real_shift(const lmmc_mat_t* A, lmmc_real_t mu,
78{
79 const lmmc_real_t eps = 2.2204460492503131e-16;
80 lmmc_real_t norm_A = inverse_matrix_norm(A);
81 lmmc_real_t perturb = eps * norm_A * (lmmc_real_t)A->rows;
82 fill_real_shift(A, mu + perturb, &work->shifted);
83 lmmc_status_t status = lmmc_lu_decompose_inplace(&work->shifted, work->pivots, NULL);
84 if (status == LMMC_STATUS_SINGULAR_MATRIX) {
85 perturb = sqrt(eps) * norm_A;
86 fill_real_shift(A, mu + perturb, &work->shifted);
87 status = lmmc_lu_decompose_inplace(&work->shifted, work->pivots, NULL);
88 }
89 return status;
90}
91
92static void fill_complex_shift(const lmmc_mat_t* A, lmmc_real_t alpha_p,
93 lmmc_real_t beta, lmmc_mat_t* big)
94{
95 size_t n = A->rows;
96 size_t n2 = 2 * n;
97 size_t i, j;
98 for (i = 0; i < n2; i++) {
99 for (j = 0; j < n2; j++) {
100 MAT_ELEM(big, i, j) = 0.0;
101 }
102 }
103
105 for (i = 0; i < n; i++) {
106 for (j = 0; j < n; j++) {
107 MAT_ELEM(big, i, j) = MAT_ELEM(A, i, j) - ((i == j) ? alpha_p : 0.0);
108 }
109 }
110
112 for (i = 0; i < n; i++) {
113 MAT_ELEM(big, i, n + i) = beta;
114 }
115
117 for (i = 0; i < n; i++) {
118 MAT_ELEM(big, n + i, i) = -beta;
119 }
120
122 for (i = 0; i < n; i++) {
123 for (j = 0; j < n; j++) {
124 MAT_ELEM(big, n + i, n + j) = MAT_ELEM(A, i, j) - ((i == j) ? alpha_p : 0.0);
125 }
126 }
127}
128
129static void retry_complex_shift(const lmmc_mat_t* A, lmmc_real_t alpha_p,
130 lmmc_real_t beta, lmmc_mat_t* big)
131{
132 size_t n = A->rows;
133 size_t i, j;
134 for (i = 0; i < n; i++) {
135 for (j = 0; j < n; j++) {
136 lmmc_real_t aij = MAT_ELEM(A, i, j) - ((i == j) ? alpha_p : 0.0);
137 MAT_ELEM(big, i, j) = aij;
138 MAT_ELEM(big, n + i, n + j) = aij;
139 }
140 }
141 for (i = 0; i < n; i++) {
142 MAT_ELEM(big, i, n + i) = beta;
143 MAT_ELEM(big, n + i, i) = -beta;
144 }
145}
146
147static lmmc_status_t factor_complex_shift(const lmmc_mat_t* A, lmmc_real_t alpha,
149{
150 const lmmc_real_t eps = 2.2204460492503131e-16;
151 lmmc_real_t norm_A = inverse_matrix_norm(A);
152 lmmc_real_t perturb = eps * norm_A * (lmmc_real_t)A->rows;
153 fill_complex_shift(A, alpha + perturb, beta, &work->shifted);
154 lmmc_status_t status = lmmc_lu_decompose_inplace(&work->shifted, work->pivots, NULL);
155 if (status == LMMC_STATUS_SINGULAR_MATRIX) {
156 retry_complex_shift(A, alpha + sqrt(eps) * norm_A, beta, &work->shifted);
157 status = lmmc_lu_decompose_inplace(&work->shifted, work->pivots, NULL);
158 }
159 return status;
160}
161
162static lmmc_real_t inverse_vector_norm(const lmmc_vec_t* vector)
163{
164 lmmc_real_t nrm = 0.0;
165 for (size_t i = 0; i < vector->size; i++) nrm += vector->data[i] * vector->data[i];
166 return sqrt(nrm);
167}
168
169static void inverse_start_vector(size_t n, lmmc_eigen_inverse_workspace_t* work)
170{
171 for (size_t i = 0; i < n; i++) {
172 work->rhs.data[i] = ((i % 2 == 0) ? 1.0 : -1.0) / (lmmc_real_t)(i + 1);
173 }
174 if (work->rhs.size != n) {
175 for (size_t i = 0; i < n; i++) {
176 work->rhs.data[n + i] = 1.0 / (lmmc_real_t)(n + i + 1);
177 }
178 }
179 lmmc_real_t nrm = inverse_vector_norm(&work->rhs);
180 if (nrm > 0.0) {
181 for (size_t i = 0; i < work->rhs.size; i++) work->rhs.data[i] /= nrm;
182 }
183}
184
185static lmmc_status_t inverse_iterate(lmmc_eigen_inverse_workspace_t* work)
186{
187 const size_t max_iter = 20;
188 for (size_t iter = 0; iter < max_iter; iter++) {
189 lmmc_status_t status = lmmc_lu_solve(&work->shifted, work->pivots,
190 &work->rhs, &work->solution);
191 if (status != LMMC_STATUS_OK) {
192 return status;
193 }
194 lmmc_real_t nrm = inverse_vector_norm(&work->solution);
195 if (nrm == 0.0) {
196 nrm = 1.0;
197 }
198 for (size_t i = 0; i < work->solution.size; i++) work->solution.data[i] /= nrm;
199 for (size_t i = 0; i < work->solution.size; i++) {
200 work->rhs.data[i] = work->solution.data[i];
201 }
202 }
203 return LMMC_STATUS_OK;
204}
205
206static void store_real_vector(lmmc_eigen_gen_full_result_t* result, size_t column,
208{
209 for (size_t j = 0; j < result->real_parts.size; j++) {
210 MAT_ELEM(&result->vectors_real, j, column) = work->solution.data[j];
211 MAT_ELEM(&result->vectors_imag, j, column) = 0.0;
212 }
213}
214
215static void store_complex_vectors(lmmc_eigen_gen_full_result_t* result, size_t column,
217{
218 size_t n = result->real_parts.size;
219 for (size_t j = 0; j < n; j++) {
220 MAT_ELEM(&result->vectors_real, j, column) = work->solution.data[j];
221 MAT_ELEM(&result->vectors_imag, j, column) = work->solution.data[n + j];
222 MAT_ELEM(&result->vectors_real, j, column + 1) = work->solution.data[j];
223 MAT_ELEM(&result->vectors_imag, j, column + 1) = -work->solution.data[n + j];
224 }
225}
226
229{
230 size_t n = a->rows;
233 for (size_t i = 0; i < n;) {
234 int is_real = result->imag_parts.data[i] == 0.0;
235 status = inverse_workspace_resize(&work, is_real ? n : 2 * n);
236 if (status != LMMC_STATUS_OK) {
237 break;
238 }
239 if (is_real) {
240 status = factor_real_shift(a, result->real_parts.data[i], &work);
241 } else {
242 status = factor_complex_shift(a, result->real_parts.data[i],
243 result->imag_parts.data[i], &work);
244 }
245 if (status != LMMC_STATUS_OK) {
246 break;
247 }
248 inverse_start_vector(n, &work);
249 status = inverse_iterate(&work);
250 if (status != LMMC_STATUS_OK) {
251 break;
252 }
253 if (is_real) {
254 store_real_vector(result, i, &work);
255 ++i;
256 } else {
257 store_complex_vectors(result, i, &work);
258 i += 2;
259 }
260 }
261 inverse_workspace_destroy(&work);
262 return status;
263}
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
行优先存储的稠密矩阵。
一维稠密向量。
特征值 / 奇异值分解,伪逆与条件数接口.
一般实矩阵完整特征分解结果(特征值 + 特征向量).
定义 eigen.h:42
lmmc_status_t lmmc_eigen_inverse_vectors(const lmmc_mat_t *a, lmmc_eigen_gen_full_result_t *result)
特征值 / SVD 模块内部共享的缩放、Householder 与 Givens 辅助接口(仅源文件可见)。
#define MAT_ELEM(mat, i, j)
特征向量计算阶段独占的工作区,各移位复用同一缓冲区。
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_free(void *pointer)
Private recoverable allocator for persistent LMMC ownership.
lmmc_status_t
LMMC 库统一返回的状态码.
@ LMMC_STATUS_OK
@ LMMC_STATUS_ALLOCATION_FAILED
@ LMMC_STATUS_SINGULAR_MATRIX