如何在Python中实现基于Householder的QR分解?
我目前正在尝试对矩形矩阵实施基于Householder的QR分解,如(第3、4、5页)所述 显然,我有些伪代码弄错了,因为(1)我的结果与如何在Python中实现基于Householder的QR分解?,python,numpy,linear-algebra,numerical-methods,qr-decomposition,Python,Numpy,Linear Algebra,Numerical Methods,Qr Decomposition,我目前正在尝试对矩形矩阵实施基于Householder的QR分解,如(第3、4、5页)所述 显然,我有些伪代码弄错了,因为(1)我的结果与numpy.qr.linalg()不同,(2)我的例程生成的矩阵R不是上三角矩阵 我的代码(也可在下获得) 导入数学 导入argparse 将numpy作为np导入 从键入导入联合 def householder(alpha:float,x:np.ndarray)->联合[np.ndarray,int]: """ 计算alpha和x的Householder向量
numpy.qr.linalg()
不同,(2)我的例程生成的矩阵R
不是上三角矩阵
我的代码(也可在下获得)
导入数学
导入argparse
将numpy作为np导入
从键入导入联合
def householder(alpha:float,x:np.ndarray)->联合[np.ndarray,int]:
"""
计算alpha和x的Householder向量。
:参数alpha:
:参数x:
:返回:
"""
s=数学功率(np.linalg.norm(x,ord=2),2)
v=x
如果s==0:
tau=0
其他:
t=math.sqrt(alpha*alpha+s)
v_one=alpha-t如果alpha并[np.ndarray,np.ndarray]:
"""
对指定矩阵A应用基于Householder的QR分解。
:参数A:
:参数m:
:参数n:
:返回:
"""
H=[]
R=A
Q=A
I=np.眼(m,m)
对于范围(0,n)内的j:
#应用户主变换。
x=A[j+1:m,j]
v_户主,tau=户主(np.linalg.norm(x),x)
v=np.零((1,m))
v[0,j]=1
v[0,j+1:m]=v_户主
res=I-tau*v*np.转置(v)
R=np.matmul(res,R)
H.追加(res)
返回Q,R
m=10
n=8
A=np.rand.rand(m,n)
q、 r=np.linalg.qr(A)
Q、 R=qr_分解(A,m,n)
打印(“****”)
打印(Q)
打印(q)
打印(“----”)
印刷品(R)
印刷品(r)
因此,我不清楚如何将零引入我的R
矩阵/我的代码的哪一部分是不正确的。我很乐意接受任何指点!
非常感谢您抽出时间。您链接到的笔记中有许多问题/缺少详细信息。在咨询了其他人(包括这个非常有用的人)之后,我能够想出一个类似的工作实现 工作算法 以下是
qr\u分解的工作版本的代码:
import numpy as np
from typing import Union
def householder(x: np.ndarray) -> Union[np.ndarray, int]:
alpha = x[0]
s = np.power(np.linalg.norm(x[1:]), 2)
v = x.copy()
if s == 0:
tau = 0
else:
t = np.sqrt(alpha**2 + s)
v[0] = alpha - t if alpha <= 0 else -s / (alpha + t)
tau = 2 * v[0]**2 / (s + v[0]**2)
v /= v[0]
return v, tau
def qr_decomposition(A: np.ndarray) -> Union[np.ndarray, np.ndarray]:
m,n = A.shape
R = A.copy()
Q = np.identity(m)
for j in range(0, n):
# Apply Householder transformation.
v, tau = householder(R[j:, j])
H = np.identity(m)
H[j:, j:] -= tau * v.reshape(-1, 1) @ v
R = H @ R
Q = H @ Q
return Q[:n].T, R[:n]
m = 5
n = 4
A = np.random.rand(m, n)
q, r = np.linalg.qr(A)
Q, R = qr_decomposition(A)
with np.printoptions(linewidth=9999, precision=20, suppress=True):
print("**** Q from qr_decomposition")
print(Q)
print("**** Q from np.linalg.qr")
print(q)
print()
print("**** R from qr_decomposition")
print(R)
print("**** R from np.linalg.qr")
print(r)
此版本的qr\u分解
near精确地再现了np.linalg.qr
的输出。下文对这些差异进行了评论
输出的数值精度
np.linalg.qr
和qr_分解
的输出值匹配精度高。然而,qr_分解
用于生成R
中的零的计算组合并不能完全抵消,因此这些零实际上并不完全等于零
事实证明,np.linalg.qr
没有做任何花哨的浮点运算来确保其输出中的零是0.0
。它将强制将这些值设置为0.0
。因此,要获得相同的结果,只需将qr\u分解中的return
行更改为:
return Q[:n].T, np.triu(R[:n])
输出中的符号(+
/-
)
Q和R中的一些+/-
符号在np.linalg.qr
和qr\u分解
的输出中是不同的,但这并不是一个真正的问题,因为符号有许多有效的选择(见此)。通过使用替代算法生成v
和tau
,您可以精确匹配符号约定,即np.linalg.qr
:
def householder_vectorized(a):
"""Use this version of householder to reproduce the output of np.linalg.qr
exactly (specifically, to match the sign convention it uses)
based on https://rosettacode.org/wiki/QR_decomposition#Python
"""
v = a / (a[0] + np.copysign(np.linalg.norm(a), a[0]))
v[0] = 1
tau = 2 / (v.T @ v)
return v,tau
与np.linalg.qr的输出完全匹配
总而言之,此版本的qr\u分解
将与np.linalg.qr
的输出完全匹配:
输出:
**** Q from qr_decomposition
[[ 0.5194188817843675 -0.10699353671401633 0.4322294754656072 -0.7293293270703678 ]
[ 0.5218635773595086 0.11737804362574514 -0.5171653705211056 0.04467925806590414]
[ 0.34858177783013133 0.6023104248793858 -0.33329256746256875 -0.03450824948274838]
[ 0.03371048915852807 0.6655221685383623 0.6127023580593225 0.28795294754791 ]
[ 0.5789790833500734 -0.411189947884951 0.24337120818874305 0.618041080584351 ]]
**** Q from np.linalg.qr
[[-0.5194188817843672 0.10699353671401617 0.4322294754656068 0.7293293270703679 ]
[-0.5218635773595086 -0.11737804362574503 -0.5171653705211053 -0.044679258065904115]
[-0.3485817778301313 -0.6023104248793857 -0.33329256746256863 0.03450824948274819 ]
[-0.03371048915852807 -0.665522168538362 0.6127023580593226 -0.2879529475479097 ]
[-0.5789790833500733 0.41118994788495106 0.24337120818874317 -0.6180410805843508 ]]
**** R from qr_decomposition
[[ 0.6894219296137802 1.042676051151294 1.3418719684631446 1.2498925815126485 ]
[ 0.00000000000000000685 0.7076056836914905 0.29883043386651403 0.41955370595004277 ]
[-0.0000000000000000097 -0.00000000000000007292 0.5304551654027297 0.18966088433421135 ]
[-0.00000000000000000662 0.00000000000000008718 0.00000000000000002322 0.6156558913022807 ]]
**** R from np.linalg.qr
[[-0.6894219296137803 -1.042676051151294 -1.3418719684631442 -1.2498925815126483 ]
[ 0. -0.7076056836914905 -0.29883043386651376 -0.4195537059500425 ]
[ 0. 0. 0.53045516540273 0.18966088433421188]
[ 0. 0. 0. -0.6156558913022805 ]]
**** Q from qr_decomposition
[[-0.10345123000824041 0.6455437884382418 0.44810714367794663 -0.03963544711256745 ]
[-0.55856415402318 -0.3660716543156899 0.5953932791844518 0.43106504879433577 ]
[-0.30655198880585594 0.6606757192118904 -0.21483067305535333 0.3045011114089389 ]
[-0.48053620675695174 -0.11139783377793576 -0.6310958848894725 0.2956864520726446 ]
[-0.5936453158283703 -0.01904935140131578 -0.016510508076204543 -0.79527388379824 ]]
**** Q from np.linalg.qr
[[-0.10345123000824041 0.6455437884382426 0.44810714367794663 -0.039635447112567376]
[-0.5585641540231802 -0.3660716543156898 0.5953932791844523 0.4310650487943359 ]
[-0.30655198880585594 0.6606757192118904 -0.21483067305535375 0.30450111140893893 ]
[-0.48053620675695186 -0.1113978337779356 -0.6310958848894725 0.29568645207264455 ]
[-0.5936453158283704 -0.01904935140131564 -0.0165105080762043 -0.79527388379824 ]]
**** R from qr_decomposition
[[-1.653391466100325 -1.0838054573405895 -1.0632037969249921 -1.1825735233596888 ]
[ 0. 0.7263519982452554 0.7798481878600413 0.5496287509656425 ]
[ 0. 0. -0.26840760341581243 -0.2002757085967938 ]
[ 0. 0. 0. 0.48524469321440966]]
**** R from np.linalg.qr
[[-1.6533914661003253 -1.0838054573405895 -1.0632037969249923 -1.182573523359689 ]
[ 0. 0.7263519982452559 0.7798481878600418 0.5496287509656428]
[ 0. 0. -0.2684076034158126 -0.2002757085967939]
[ 0. 0. 0. 0.4852446932144096]]
除了尾随数字中不可避免的舍入错误外,输出现在匹配。您遇到的基本问题是链接到的注释完全是垃圾。他们对householder
算法的伪代码是不完整的,他们对实际householder矩阵H
的描述完全是混乱的。在查阅了其他资料后,我在下面的答案中找到了一个可行的版本。这太棒了,谢谢!我同意,你链接的那本书在过程上更清晰。我真的很欣赏这个深入的答案,这是一个很好的例子!您的示例中“@”的确切操作是什么?@
是
import numpy as np
from typing import Union
def qr_decomposition(A: np.ndarray) -> Union[np.ndarray, np.ndarray]:
m,n = A.shape
R = A.copy()
Q = np.identity(m)
for j in range(0, n):
# Apply Householder transformation.
v, tau = householder_vectorized(R[j:, j, np.newaxis])
H = np.identity(m)
H[j:, j:] -= tau * (v @ v.T)
R = H @ R
Q = H @ Q
return Q[:n].T, np.triu(R[:n])
m = 5
n = 4
A = np.random.rand(m, n)
q, r = np.linalg.qr(A)
Q, R = qr_decomposition(A)
with np.printoptions(linewidth=9999, precision=20, suppress=True):
print("**** Q from qr_decomposition")
print(Q)
print("**** Q from np.linalg.qr")
print(q)
print()
print("**** R from qr_decomposition")
print(R)
print("**** R from np.linalg.qr")
print(r)
**** Q from qr_decomposition
[[-0.10345123000824041 0.6455437884382418 0.44810714367794663 -0.03963544711256745 ]
[-0.55856415402318 -0.3660716543156899 0.5953932791844518 0.43106504879433577 ]
[-0.30655198880585594 0.6606757192118904 -0.21483067305535333 0.3045011114089389 ]
[-0.48053620675695174 -0.11139783377793576 -0.6310958848894725 0.2956864520726446 ]
[-0.5936453158283703 -0.01904935140131578 -0.016510508076204543 -0.79527388379824 ]]
**** Q from np.linalg.qr
[[-0.10345123000824041 0.6455437884382426 0.44810714367794663 -0.039635447112567376]
[-0.5585641540231802 -0.3660716543156898 0.5953932791844523 0.4310650487943359 ]
[-0.30655198880585594 0.6606757192118904 -0.21483067305535375 0.30450111140893893 ]
[-0.48053620675695186 -0.1113978337779356 -0.6310958848894725 0.29568645207264455 ]
[-0.5936453158283704 -0.01904935140131564 -0.0165105080762043 -0.79527388379824 ]]
**** R from qr_decomposition
[[-1.653391466100325 -1.0838054573405895 -1.0632037969249921 -1.1825735233596888 ]
[ 0. 0.7263519982452554 0.7798481878600413 0.5496287509656425 ]
[ 0. 0. -0.26840760341581243 -0.2002757085967938 ]
[ 0. 0. 0. 0.48524469321440966]]
**** R from np.linalg.qr
[[-1.6533914661003253 -1.0838054573405895 -1.0632037969249923 -1.182573523359689 ]
[ 0. 0.7263519982452559 0.7798481878600418 0.5496287509656428]
[ 0. 0. -0.2684076034158126 -0.2002757085967939]
[ 0. 0. 0. 0.4852446932144096]]