用伴随矩阵寻根

时间:2013-11-17 16:59:38

标签: algorithm matrix polynomial-math qr-decomposition

我想找到单变量多项式的所有真正根。我可以使用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(不确定它与第一种方法有什么不同,但是......)

1 个答案:

答案 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,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)