加速用于计算矩阵辅助因子的python代码

时间:2011-06-29 21:45:36

标签: python matrix performance numpy linear-algebra

作为复杂任务的一部分,我需要计算matrix cofactors。我使用这个nice code for computing matrix minors以一种简单的方式做到了这一点。这是我的代码:

def matrix_cofactor(matrix):
    C = np.zeros(matrix.shape)
    nrows, ncols = C.shape
    for row in xrange(nrows):
        for col in xrange(ncols):
            minor = matrix[np.array(range(row)+range(row+1,nrows))[:,np.newaxis],
                           np.array(range(col)+range(col+1,ncols))]
            C[row, col] = (-1)**(row+col) * np.linalg.det(minor)
    return C

事实证明,这个矩阵辅助因子代码是瓶颈,我想优化上面的代码片段。有关如何做到这一点的任何想法?

4 个答案:

答案 0 :(得分:13)

如果你的矩阵是可逆的,那么辅助因子与逆矩阵相关:

def matrix_cofactor(matrix):
    return np.linalg.inv(matrix).T * np.linalg.det(matrix)

这提供了大的加速(对于50x50矩阵,大约为1000x)。主要原因是基本原因:这是一个O(n^3)算法,而基于minor-det的算法是O(n^5)

这可能意味着对于不可逆矩阵,有一些聪明的方法来计算辅助因子(即,不使用上面使用的数学公式,但是使用其他一些等价的定义)。


如果你坚持使用基于det的方法,你可以做的是:

大部分时间似乎花在det内。 (查看line_profiler以便自己找到它。)你可以尝试通过将Numpy与英特尔MKL联系起来加速这部分,但除此之外,没有太多可以做的。

您可以像这样加速代码的其他部分:

minor = np.zeros([nrows-1, ncols-1])
for row in xrange(nrows):
    for col in xrange(ncols):
        minor[:row,:col] = matrix[:row,:col]
        minor[row:,:col] = matrix[row+1:,:col]
        minor[:row,col:] = matrix[:row,col+1:]
        minor[row:,col:] = matrix[row+1:,col+1:]
        ...

根据矩阵的大小,总运行时间增加10-50%。原始代码具有Python range和列表操作,这比直接切片索引慢。您也可以尝试更聪明,只复制实际更改的次要部分 - 但是,在上述更改之后,接近100%的时间花在numpy.linalg.det内,以便优化其他部分没有多大意义。

答案 1 :(得分:2)

np.array(range(row)+range(row+1,nrows))[:,np.newaxis]的计算并不依赖于col,因此您可以将其移到内部循环之外并缓存该值。根据您拥有的列数,这可能会进行一些小优化。

答案 2 :(得分:0)

from sympy import *
A = Matrix([[1,2,0],[0,3,0],[0,7,1]])
A.adjugate().T

输出(即辅因子矩阵)为:

Matrix([
[ 3, 0,  0],
[-2, 1, -7],
[ 0, 0,  3]])

答案 3 :(得分:0)

我建议不要使用反函数和行列式,而是建议使用SVD

def cofactors(A):
    U,sigma,Vt = np.linalg.svd(A)
    N = len(sigma)
    g = np.tile(sigma,N)
    g[::(N+1)] = 1
    G = np.diag(-(-1)**N*np.product(np.reshape(g,(N,N)),1)) 
    return U @ G @ Vt