LMMC
Lamina Mathematic core
载入中...
搜索中...
未找到
eigen_svd_iteration.c
浏览该文件的文档.
1
4#include <math.h>
5#include "internal.h"
7#include "eigen_internal.h"
9
10static lmmc_real_t trailing_shift(const lmmc_real_t *d,
11 const lmmc_real_t *e, size_t lo, size_t hi)
12{
13 lmmc_real_t emm = (hi >= lo + 2) ? e[hi - 2] : 0.0;
14 lmmc_real_t tnm = d[hi - 1] * d[hi - 1] + emm * emm;
15 lmmc_real_t tnn = d[hi] * d[hi] + e[hi - 1] * e[hi - 1];
16 lmmc_real_t tmn = d[hi - 1] * e[hi - 1];
17 lmmc_real_t bb = (tnm - tnn) * 0.5;
18 lmmc_real_t cc = tmn * tmn;
19 if (bb == 0.0 && cc == 0.0) {
20 return tnn;
21 }
22 lmmc_real_t disc = sqrt(bb * bb + cc);
23 lmmc_real_t denom = (bb >= 0.0) ? (bb + disc) : (bb - disc);
24 return tnn - cc / denom;
25}
26
27static void bidiag_qr_step(lmmc_real_t *d, lmmc_real_t *e,
28 size_t lo, size_t hi, lmmc_mat_t *u, lmmc_mat_t *v)
29{
30 lmmc_real_t f = d[lo] * d[lo] - trailing_shift(d, e, lo, hi);
31 lmmc_real_t g = d[lo] * e[lo];
32 for (size_t i = lo; i < hi; ++i) {
33 lmmc_real_t c, s, r;
34 givens_compute(f, g, &c, &s, &r);
35 if (i > lo) {
36 e[i - 1] = r;
37 }
38 f = c * d[i] + s * e[i];
39 e[i] = c * e[i] - s * d[i];
40 g = s * d[i + 1];
41 d[i + 1] = c * d[i + 1];
42 givens_right(v, v->rows, i, i + 1, c, s);
43
44 givens_compute(f, g, &c, &s, &r);
45 d[i] = r;
46 f = c * e[i] + s * d[i + 1];
47 d[i + 1] = c * d[i + 1] - s * e[i];
48 if (i + 1 < hi) {
49 g = s * e[i + 1];
50 e[i + 1] = c * e[i + 1];
51 }
52 givens_right(u, u->rows, i, i + 1, c, s);
53 }
54 e[hi - 1] = f;
55}
56
57static int deflate_edge(const lmmc_real_t *d, lmmc_real_t *e, size_t index)
58{
59 lmmc_real_t threshold = LMMC_REAL_EPSILON *
60 (lmmc_abs(d[index - 1]) + lmmc_abs(d[index]));
61 if (lmmc_abs(e[index - 1]) <= threshold) {
62 e[index - 1] = 0.0;
63 return 1;
64 }
65 return 0;
66}
67
68static void cancel_zero_diagonal(lmmc_real_t *d, lmmc_real_t *e,
69 size_t k, size_t hi, lmmc_mat_t *u)
70{
71 lmmc_real_t f = e[k];
72 e[k] = 0.0;
73 for (size_t i = k + 1; i <= hi; ++i) {
74 lmmc_real_t c, s, r;
75 givens_compute(d[i], f, &c, &s, &r);
76 d[i] = r;
77 if (i < hi) {
78 f = -s * e[i];
79 e[i] = c * e[i];
80 }
81 givens_right(u, u->rows, k, i, c, s);
82 }
83}
84
85static int cancel_block_zero(lmmc_real_t *d, lmmc_real_t *e,
86 size_t lo, size_t hi, lmmc_mat_t *u)
87{
88 for (size_t k = lo; k < hi; ++k) {
89 if (d[k] == 0.0) {
90 cancel_zero_diagonal(d, e, k, hi, u);
91 return 1;
92 }
93 }
94 return 0;
95}
96
98 size_t n, lmmc_mat_t *u, lmmc_mat_t *v)
99{
100 const size_t max_iter_total = 30 * n + 30;
101 size_t iter = 0;
102 size_t hi = n - 1;
103 while (hi > 0) {
104 while (hi > 0 && deflate_edge(d, e, hi)) {
105 --hi;
106 }
107 if (hi == 0) {
108 break;
109 }
110 size_t lo = hi;
111 while (lo > 0 && !deflate_edge(d, e, lo)) {
112 --lo;
113 }
114 if (cancel_block_zero(d, e, lo, hi, u)) {
115 continue;
116 }
117 if (iter++ > max_iter_total) {
119 }
120 bidiag_qr_step(d, e, lo, hi, u, v);
121 }
122 return LMMC_STATUS_OK;
123}
double lmmc_real_t
Public and internal LMMC real type.
#define LMMC_REAL_EPSILON
既有算法的经验近似阈值,非机器 epsilon。
行优先存储的稠密矩阵。
void givens_right(lmmc_mat_t *M, size_t rows, size_t p, size_t q, lmmc_real_t c, lmmc_real_t s)
void givens_compute(lmmc_real_t a, lmmc_real_t b, lmmc_real_t *c, lmmc_real_t *s, lmmc_real_t *r)
特征值 / SVD 模块内部共享的缩放、Householder 与 Givens 辅助接口(仅源文件可见)。
lmmc_status_t lmmc_svd_diagonalize(lmmc_real_t *d, lmmc_real_t *e, size_t n, lmmc_mat_t *u, lmmc_mat_t *v)
LMMC 内部使用的公共工具(仅源文件可见).
稠密矩阵直接分解接口(LU、Cholesky、QR)。
lmmc_status_t
LMMC 库统一返回的状态码.
@ LMMC_STATUS_CONVERGENCE_FAILED
@ LMMC_STATUS_OK