QR法求解特征值特征向量

一 QR原理

理论依据:任意一个非奇异矩阵(满秩的方阵)A都可以分解为一个正交矩阵Q和一个上三角矩阵R的乘积,且当R对角元符号确定时,分解是唯一的。QR分解是一种迭代方法,迭代格式如下: 在这里插入图片描述
当Ak基本收敛到为上三角矩阵时,迭代完成,此时主对角元素就是特征值。

特别地:当A是对称阵的时候,Ak是对角阵Λ,Q=Qk-1Qk-2…Q1就是其正交特征向量矩,有QTAQ=Ak=Λ,即A正交对角化与Ak。

如何理解?我们看下图公式:
在这里插入图片描述

所以,QR迭代过程从数学的角度来想其实就是不断正交化的过程。

二 QR算法步骤

1.Householder变换进行QR分解

反射矩阵:任取单位向量w,反射矩阵H=E-2WWT ,显然HHT =E,H是正交阵

定理:任取两个模长相等的的向量x,y,一定存在一个反射矩阵H,使得Hx=y,
此时w=(x-y)/(|x-y|)(向量的差除以向量差的模)

应用:现在我们取矩阵的一列为x,m=|x|,y=m*[1,0,0,…0]T 根据上面的定理求出H,使得Hx=y,是不是通过正交变化就把那一列化成了[m,0,0,0]T ,这样就达到了将下三角元素全化为0的效果。看下图,举个例子来说明QR分解过程:
在这里插入图片描述
看懂上述过程就知道,Householder变换是利用了反射定理,经过n-1轮正交变换,将下三角元素全部化为0,从而得到上三角矩阵R,将所有H矩阵左乘运算再转置得到正交矩阵Q,即A=QR

我们看看QR分解的代码:

#QR分解
def qrSplit(A):
    n=A.shape[0]#A的维度
    Q=[[]]
    R=A
    for i in range(0,n-1):
        B=R
        if i!=0:
            #删除一行一列,得n-1阶子阵
            B=B[i:,i:]
        #取第一列向量
        x=B[:,0]
        #向量摸长
        m=np.linalg.norm(x)
        #生成一个模长为m,其余项为0的向量y
        y=[0 for j in range(0,n-i)]
        y[0]=m
        #计算householde
  • 30
    点赞
  • 188
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
QR 分解可以用来求解矩阵的特征值特征向量。下面是一个简单的 C 语言程序,用来实现 QR 分解并求解矩阵的特征值特征向量: ```c #include <stdio.h> #include <math.h> #define N 3 // 矩阵维数 void print_matrix(double A[N][N]) { // 打印矩阵 for (int i = 0; i < N; i++) { for (int j = 0; j < N; j++) { printf("%.2f\t", A[i][j]); } printf("\n"); } } double dot_product(double u[N], double v[N]) { // 向量点积 double result = 0.0; for (int i = 0; i < N; i++) { result += u[i] * v[i]; } return result; } void copy_matrix(double src[N][N], double dst[N][N]) { // 复制矩阵 for (int i = 0; i < N; i++) { for (int j = 0; j < N; j++) { dst[i][j] = src[i][j]; } } } void qr_decomposition(double A[N][N], double Q[N][N], double R[N][N]) { // QR 分解 double v[N][N], u[N][N]; copy_matrix(A, R); for (int k = 0; k < N - 1; k++) { double norm = 0.0; for (int i = k; i < N; i++) { norm += R[i][k] * R[i][k]; } norm = sqrt(norm); double s = R[k][k] > 0 ? -1.0 : 1.0; v[k][k] = R[k][k] - s * norm; for (int i = k + 1; i < N; i++) { v[i][k] = R[i][k]; } double beta = -s * norm; for (int j = k + 1; j < N; j++) { double dot = dot_product(&v[k][0], &v[j][0]); for (int i = k; i < N; i++) { R[i][j] -= (2.0 * dot / beta) * v[i][k]; } } } for (int i = 0; i < N; i++) { for (int j = 0; j < N; j++) { Q[i][j] = i == j ? 1.0 : 0.0; } } for (int k = N - 2; k >= 0; k--) { for (int j = k + 1; j < N; j++) { double dot = dot_product(&v[k][0], &Q[0][j]); for (int i = 0; i < N; i++) { Q[i][j] -= (2.0 * dot / v[k][k]) * v[i][k]; } } } } void eigen(double A[N][N], double lambda[N], double V[N][N]) { // 求解特征值特征向量 double Q[N][N], R[N][N]; qr_decomposition(A, Q, R); double B[N][N]; copy_matrix(A, B); for (int i = 0; i < N; i++) { lambda[i] = B[i][i]; } for (int i = 0; i < N; i++) { for (int j = 0; j < N; j++) { V[j][i] = Q[j][i]; } } for (int i = 0; i < N; i++) { for (int j = 0; j < N; j++) { V[i][j] /= V[N - 1][j]; } } } int main() { double A[N][N] = {{1, 2, 3}, {2, 4, 5}, {3, 5, 6}}; double lambda[N], V[N][N]; eigen(A, lambda, V); printf("eigenvalues:\n"); for (int i = 0; i < N; i++) { printf("%.2f\n", lambda[i]); } printf("eigenvectors:\n"); print_matrix(V); return 0; } ``` 程序中的 `qr_decomposition` 函数用来实现 QR 分解,`eigen` 函数用来求解特征值特征向量。这个程序可以处理 3x3 的矩阵,如果要处理更大的矩阵,只需要修改宏定义中的 `N` 即可。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值