我想找到单变量多项式的所有真正根。我可以使用Jenkins-Traub算法,但我想学习如何使用伴随矩阵来解决它。
我知道如何将多项式转换为伴随矩阵,我发现了一个执行QR分解的脚本:http://quantstart.com/articles/QR-Decomposition-with-Python-and-NumPy
这就是我迷失的地方:接下来要做什么?我想我必须计算多个分解但是当我这样做时,我总是得到相同的结果(显然)。我还读到,首先将伴随矩阵转换为Hessenberg形式可能很有用 - 但是如何?然后有“转变” - 它们是什么?
我也找到了http://www.nr.com/webnotes/nr3web17.pdf,但由于我不明白其中任何一个,我想知道是否有更简单的方法(即使速度较慢或较不稳定)。
换句话说:阅读http://en.wikipedia.org/wiki/QR_algorithm
“让A为我们想要计算特征值的实矩阵” 好吧,这是我的伴侣矩阵,对吗?
“我们计算QR分解Ak = QkRk”
从第一个链接开始Q, R = householder(A)
,对吧?
“然后我们形成Ak + 1 = RkQk” 简单,只需乘以R和Q
“在某些条件下,[2]矩阵Ak会聚到三角矩阵,A的Schur形式。三角矩阵的特征值列在对角线上,特征值问题得到解决。”<登记/> ......等等,什么?我试过了:
for i in range(100):
Q, R = householder(A)
A = mult_matrix(R, Q)
但似乎没有任何进展,我看不到任何数字,甚至接近正确的根。
拜托,有人可以向我解释一下吗?
PS:我不想盲目地使用LAPACK或类似的东西,因为我想了解它是如何工作的,至少在非常简单的条件下。
PPS:还有http://adorio-research.org/wordpress/?p=184(不确定它与第一种方法有什么不同,但是......)
答案 0 :(得分:1)
如果您的伴随矩阵是将q(x)
映射到x*q(x) mod p(x)
其中p(x)=x^(n+1)+p_n*x^n+...+p_1*x+p_0
。
显然,A具有
的形状0 0 0 ... 0 -p_0
1 0 0 ... 0 -p_1
0 1 0 ... 0 -p_2
. . . ... . . .
0 0 0 ... 1 -p_n
已经是Hessenberg形式。由于此形式在QR算法期间保留,因此您可以使用带有Givens旋转的QR分解,其中仅发生靠近对角线的旋转。
在未移位的QR算法中,您应该至少在右下角的3x3区块中观察到明显的发展。
如果你取右下2x2块的一个特征值并从每个对角元素中减去它,那么你就可以得到弗朗西斯的移位QR算法。减去的数字s是当前最小特征值的最佳估计值。请注意,很可能,您现在离开了真实域并且必须使用复杂的矩阵条目进行计算。您必须将移位保留在内存中,并在后续步骤中添加任何新移位,并将组合移位添加回找到的任何特征值。
只要任何子对角线条目实际为零,就会发生矩阵分割。如果分裂发生在最后一行,则最后一个对角线条目是移位矩阵的特征值(A-s * I)。如果分割分离最后的2x2块,则可以很容易地确定其特征值,这也是移位矩阵的特征值。
如果在其他任何地方发生分割,则QR算法将分别递归地应用于对角线块。
算法的所有变体的收敛性通过对角线下方的条目收敛到零来测量。
基本算法在那些子对角线条目中具有几何会聚,(i,i-1)处的条目的几何因子是位置i-1和i处的特征值的大小的分数。只要有大跳跃,就会快速达到零。
共轭复特征值具有相同的大小,因此算法将在对角线上产生一个2x2块,求解该块的二次特征方程,得到相应的特征值。
对于多个或聚集的特征值,将发生更大的对角线块。
附录二
这是一行
alpha = -cmp(x[0],0) * norm(x)
在户主程序中。在大多数情况下,x[0]
不会完全为0,因此会生成一个符号。但是,对于伴随矩阵,x[0]==0
按构造,因此不会产生任何符号,alpha会得到错误的值0.将其更改为更多行人
alpha = norm(x)
if x[0] < 0: alpha = -alpha
并且效果很好。
def companion_matrix(p):
n=len(p)-1
C=[[float(i+1 == j) for i in xrange(n-1)] for j in xrange(n)]
for j in range(n): C[j].append(-p[n-j]/p[0])
return C
def QR_roots(p):
n=len(p)-1
A=companion_matrix(p)
for k in range(10+n):
print "step: ",k+1," after ",(k+1)*(5+n), "iterations"
for j in range(5+n):
Q,R=householder(A)
A=mult_matrix(R,Q)
print("below diagonal")
pprint([ A[i+1][i] for i in range(n-1) ])
print("diagonal")
pprint([ A[i][i] for i in range(n) ])
print("above diagonal")
pprint([ A[i][i+1] for i in range(n-1) ])
p=[ 1, 2, 5, 3, 6, 8, 6, 4, 3, 2, 7]
QR_roots(p)
#for a case with multiple roots at 1 and 4
#p= [1,-11,43,-73,56,-16]
#QR_roots(p)