LMMC
Lamina Mathematic core
载入中...
搜索中...
未找到
eigen_schur.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
12static void hessenberg_column(lmmc_mat_t* H, lmmc_mat_t* Q,
13 size_t k, lmmc_real_t* vbuf)
14{
15 size_t n = H->rows;
16 size_t i;
17 size_t len = n - k - 1;
18 lmmc_real_t tau, beta;
19
20 for (i = 0; i < len; i++) {
21 vbuf[i] = MAT_ELEM(H, k + 1 + i, k);
22 }
23
24 householder_make(vbuf, len, &tau, &beta);
25
26 MAT_ELEM(H, k + 1, k) = beta;
27 for (i = 1; i < len; i++) {
28 MAT_ELEM(H, k + 1 + i, k) = 0.0;
29 }
30
32 householder_apply_left(H, k + 1, len, k + 1, n, vbuf, tau);
33
35 householder_apply_right(H, 0, n, k + 1, len, vbuf, tau);
36
38 householder_apply_right(Q, 0, n, k + 1, len, vbuf, tau);
39}
40
47static lmmc_status_t hessenberg_reduce(lmmc_mat_t *H, lmmc_mat_t *Q) {
48 size_t n = H->rows;
49 size_t k, i, j;
50 lmmc_real_t *vbuf;
51
52 for (i = 0; i < n; i++) {
53 for (j = 0; j < n; j++) {
54 MAT_ELEM(Q, i, j) = (i == j) ? 1.0 : 0.0;
55 }
56 }
57
58 if (n <= 2) {
59 return LMMC_STATUS_OK;
60 }
61
63 if (!vbuf) {
65 }
66
67 for (k = 0; k < n - 2; k++) {
68 hessenberg_column(H, Q, k, vbuf);
69 }
70
71 lmmc_memory_free(vbuf);
72 return LMMC_STATUS_OK;
73}
74static lmmc_real_t schur_matrix_norm(const lmmc_mat_t* H)
75{
76 lmmc_real_t norm = 0.0;
77 for (size_t i = 0; i < H->rows; i++) {
78 for (size_t j = 0; j < H->rows; j++) {
79 norm += lmmc_abs(MAT_ELEM(H, i, j));
80 }
81 }
82 return norm;
83}
84
85static int schur_find_split(lmmc_mat_t* H, int en, lmmc_real_t norm)
86{
87 const lmmc_real_t eps = 2.2204460492503131e-16;
88 int l;
91 for (l = en; l > 0; l--) {
92 s = lmmc_abs(MAT_ELEM(H, l - 1, l - 1)) +
93 lmmc_abs(MAT_ELEM(H, l, l));
94 if (s == 0.0) {
95 s = norm;
96 }
97 if (lmmc_abs(MAT_ELEM(H, l, l - 1)) <= eps * s) {
98 MAT_ELEM(H, l, l - 1) = 0.0;
99 break;
100 }
101 }
102 return l;
103}
104
105static void francis_initial_column(const lmmc_mat_t* H, int en, int l,
106 int its, lmmc_real_t* v)
107{
108 lmmc_real_t x = MAT_ELEM(H, en, en);
109 lmmc_real_t y = MAT_ELEM(H, en - 1, en - 1);
110 lmmc_real_t w = MAT_ELEM(H, en, en - 1) * MAT_ELEM(H, en - 1, en);
111 lmmc_real_t s, t, p, q, r;
112 if (its == 10 || its == 20) {
114 t = lmmc_abs(MAT_ELEM(H, en, en - 1)) +
115 lmmc_abs(MAT_ELEM(H, en - 1, en - 2));
116 x = MAT_ELEM(H, en, en) + 1.5 * t;
117 y = x;
118 w = -0.4375 * t * t;
119 }
121 s = x + y;
122 t = x * y - w;
123
125 p = MAT_ELEM(H, l, l) * (MAT_ELEM(H, l, l) - s) +
126 MAT_ELEM(H, l, l + 1) * MAT_ELEM(H, l + 1, l) + t;
127 q = MAT_ELEM(H, l + 1, l) *
128 (MAT_ELEM(H, l, l) + MAT_ELEM(H, l + 1, l + 1) - s);
129 r = MAT_ELEM(H, l + 1, l) * MAT_ELEM(H, l + 2, l + 1);
130v[0] = p;
131 v[1] = q;
132 v[2] = r;
133}
134
135static void francis_reflector(lmmc_mat_t* H, lmmc_mat_t* Q,
136 int k, int l, int en, lmmc_real_t* v)
137{
138 int n = (int)H->rows;
139 int notlast;
140 lmmc_real_t tau, beta_val;
141 notlast = (k != en - 1);
142 size_t len = notlast ? 3 : 2;
143
144 if (k != l) {
145 v[0] = MAT_ELEM(H, k, k - 1);
146 v[1] = MAT_ELEM(H, k + 1, k - 1);
147 if (notlast) {
148 v[2] = MAT_ELEM(H, k + 2, k - 1);
149 }
150 }
151 householder_make(v, len, &tau, &beta_val);
152
153 if (k != l) {
154 MAT_ELEM(H, k, k - 1) = beta_val;
155 MAT_ELEM(H, k + 1, k - 1) = 0.0;
156 if (notlast) {
157 MAT_ELEM(H, k + 2, k - 1) = 0.0;
158 }
159 } else if (l != 0) {
161 MAT_ELEM(H, k, k - 1) = -MAT_ELEM(H, k, k - 1);
162 }
163
165 householder_apply_left(H, (size_t)k, len, (size_t)k, (size_t)n, v, tau);
166
168 {
169 size_t nr = (size_t)((int)(k + len + 1) <= en + 1 ?
170 (int)(k + len + 1) : en + 1);
171 householder_apply_right(H, 0, nr, (size_t)k, len, v, tau);
172 }
173
174 householder_apply_right(Q, 0, (size_t)n, (size_t)k, len, v, tau);
175}
176
177static void francis_step(lmmc_mat_t* H, lmmc_mat_t* Q, int en, int l, int its)
178{
179 lmmc_real_t v[3];
180 francis_initial_column(H, en, l, its, v);
181 for (int k = l; k <= en - 1; k++) {
182 francis_reflector(H, Q, k, l, en, v);
183 }
184}
201static lmmc_status_t francis_qr_iteration(lmmc_mat_t* H, lmmc_mat_t* Q, size_t nn)
202{
203 const size_t max_iter = 30 * nn;
204 size_t total_iter = 0;
205 lmmc_real_t norm = schur_matrix_norm(H);
206 if (norm == 0.0) {
207 return LMMC_STATUS_OK;
208 }
209 int en = (int)nn - 1;
210 while (en >= 2) {
211 int its = 0;
212 for (;;) {
213 int l = schur_find_split(H, en, norm);
214 if (l == en) {
215 en--;
216 break;
217 }
218 if (l == en - 1) {
219 en -= 2;
220 break;
221 }
222 if (total_iter >= max_iter) {
224 }
225 francis_step(H, Q, en, l, its);
226 its++;
227 total_iter++;
228 }
229 }
230 return LMMC_STATUS_OK;
231}
232
234{
235 lmmc_status_t status = hessenberg_reduce(h, q);
236 if (status != LMMC_STATUS_OK) {
237 return status;
238 }
239 return francis_qr_iteration(h, q, h->rows);
240}
LMMC binary real type and arithmetic spelling.
double lmmc_real_t
Public and internal LMMC real type.
行优先存储的稠密矩阵。
特征值 / 奇异值分解,伪逆与条件数接口.
lmmc_status_t lmmc_eigen_schur_reduce(lmmc_mat_t *h, lmmc_mat_t *q)
void householder_apply_left(lmmc_mat_t *M, size_t i0, size_t len, size_t j0, size_t j1, const lmmc_real_t *v, lmmc_real_t tau)
void householder_make(lmmc_real_t *x, size_t len, lmmc_real_t *tau_out, lmmc_real_t *beta_out)
void householder_apply_right(lmmc_mat_t *M, size_t i0, size_t i1, size_t j0, size_t len, const lmmc_real_t *v, lmmc_real_t tau)
特征值 / SVD 模块内部共享的缩放、Householder 与 Givens 辅助接口(仅源文件可见)。
#define MAT_ELEM(mat, i, j)
LMMC 内部使用的公共工具(仅源文件可见).
稠密矩阵直接分解接口(LU、Cholesky、QR)。
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_CONVERGENCE_FAILED
@ LMMC_STATUS_OK
@ LMMC_STATUS_ALLOCATION_FAILED