以递归方式计算矩阵(nxn)的行列式

时间:2013-05-12 17:24:10

标签: python recursion

我将编写一些代码来计算方阵(nxn)的行列式,使用拉普拉斯算法(意义递归算法)编写为Wikipedia's Laplace Expansion

我已经上课Matrix,其中包括 init setitem getitem repr 以及计算行列式所需的所有东西(包括minor(i,j))。

所以我尝试了以下代码:

def determinant(self,i=0)  # i can be any of the matrix's rows
    assert isinstance(self,Matrix)
    n,m = self.dim()    # Q.dim() returns the size of the matrix Q
    assert n == m
    if (n,m) == (1,1):
        return self[0,0]
    det = 0
    for j in range(n):
        det += ((-1)**(i+j))*(self[i,j])*((self.minor(i,j)).determinant())
    return det

正如预期的那样,在每次递归调用中,self都会变成一个合适的小调。但是当从递归调用返回时,它不会改变回原始矩阵。 这会导致for循环出现问题(当函数到达(n,m)==(1,1)时,会返回矩阵的这一个值,但在for循环中,self仍然是1x1矩阵 - 为什么?)

5 个答案:

答案 0 :(得分:1)

你确定你的minor会返回一个新对象而不是对原始矩阵对象的引用吗?我使用了您的确切行列式方法并为您的类实现了minor方法,它对我来说很好。

下面是矩阵类的快速/脏实现,因为我没有实现。为简洁起见,我选择仅为方形矩阵实现它,在这种情况下,当我们处理决定因素时,这并不重要。注意与你的方法相同的det方法,以及minor方法(其余方法是为了方便实现和测试):

class matrix:
    def __init__(self, n):
        self.data = [0.0 for i in range(n*n)]
        self.dim = n
    @classmethod
    def rand(self, n):
        import random
        a = matrix(n)
        for i in range(n):
            for j in range(n):
                a[i,j] = random.random()
        return a
    @classmethod
    def eye(self, n):
        a = matrix(n)
        for i in range(n):
            a[i,i] = 1.0
        return a        
    def __repr__(self):
        n = self.dim
        for i in range(n):
            print str(self.data[i*n: i*n+n])
        return ''    
    def __getitem__(self,(i,j)):
        assert i < self.dim and j < self.dim
        return self.data[self.dim*i + j]
    def __setitem__(self, (i, j), val):
        assert i < self.dim and j < self.dim
        self.data[self.dim*i + j] = float(val)
    #
    def minor(self, i,j):
        n = self.dim
        assert i < n and j < n
        a = matrix(self.dim-1)
        for k in range(n):
            for l in range(n):
                if k == i or l == j: continue
                if k < i:
                    K = k
                else:
                    K = k-1
                if l < j:
                    L = l
                else:
                    L = l-1
                a[K,L] = self[k,l]
        return a
    def det(self, i=0):
        n = self.dim    
        if n == 1:
            return self[0,0]
        d = 0
        for j in range(n):
            d += ((-1)**(i+j))*(self[i,j])*((self.minor(i,j)).det())
        return d
    def __mul__(self, v):
        n = self.dim
        a = matrix(n)
        for i in range(n):
            for j in range(n):
                a[i,j] = v * self[i,j]
        return a
    __rmul__ = __mul__

现在进行测试

import numpy as np
a = matrix(3)
# same matrix from the Wikipedia page
a[0,0] = 1
a[0,1] = 2
a[0,2] = 3
a[1,0] = 4
a[1,1] = 5
a[1,2] = 6
a[2,0] = 7
a[2,1] = 8
a[2,2] = 9
a.det()   # returns 0.0
# trying with numpy the same matrix
A = np.array(a.data).reshape([3,3])
print np.linalg.det(A)  # returns -9.51619735393e-16

numpy情况下的残差是因为它通过(高斯)消除方法而不是拉普拉斯展开计算行列式。您还可以比较随机矩阵的结果,看看您的行列式函数和numpy之间的差异是否超出float精度:

import numpy as np
a = 10*matrix.rand(4)
A = np.array( a.data ).reshape([4,4])
print (np.linalg.det(A) - a.det())/a.det() # varies between zero and 1e-14

答案 1 :(得分:0)

这是python 3中的函数。

注意:我使用一维列表来容纳矩阵,而size数组是方形数组中的行数或列数。它使用递归算法来查找行列式。

function Loop(){
    var AllGroup=["GroupA1","GroupB1"]
    var GroupA1=["A1","A2"]
    var GroupB1=["B1","B2"]
    var Group=""

for(var i = 0; i < AllGroup.length; i++){
    Group=AllGroup[i]

    var SubGroup=""
    for(var x = 0; x < Group.length; x++){
        SubGroup=Group[x]
        alert(SubGroup);
    }
}
}

答案 2 :(得分:0)

使用Sarrus规则(非递归方法) 以下链接上的示例使用Javascript,但可以轻松地用python编写 https://github.com/apanasara/Faster_nxn_Determinant

答案 3 :(得分:0)

import numpy as np

def smaller_matrix(original_matrix,row, column):
    for ii in range(len(original_matrix)):
        new_matrix=np.delete(original_matrix,ii,0)
        new_matrix=np.delete(new_matrix,column,1)
        return new_matrix


def determinant(matrix):
    """Returns a determinant of a matrix by recursive method."""
    (r,c) = matrix.shape 
    if r != c:
        print("Error!Not a square matrix!")
        return None
    elif r==2:
        simple_determinant = matrix[0][0]*matrix[1][1]-matrix[0][1]*matrix[1][0]
        return simple_determinant
    else: 
        answer=0
        for j in range(r):
            cofactor = (-1)**(0+j) * matrix[0][j] * determinant(smaller_matrix(matrix, 0, j))
            answer+= cofactor
        return answer



#test the function
#Only works for numpy.array input
np.random.seed(1)
matrix=np.random.rand(5,5)

determinant(matrix)

答案 4 :(得分:-2)

我发布此代码是因为我无法在互联网上使用它,如何仅使用标准库来解决n * n行列式。 目的是与那些觉得有用的人分享。 我开始计算与a(0,i)相关的子矩阵Ai。 我使用递归行列式来缩短它。

Dim x   As Variant

Debug.Print IsEmpty(x)  ' True
Debug.Print IsNull(x)   ' False
Debug.Print x = ""      ' True
Debug.Print Nz(x) = ""  ' True

x = Null
Debug.Print IsEmpty(x)  ' False
Debug.Print IsNull(x)   ' True
Debug.Print x = ""      ' Null
Debug.Print Nz(x) = ""  ' True

x = ""
Debug.Print IsEmpty(x)  ' False
Debug.Print IsNull(x)   ' False
Debug.Print x = ""      ' True
Debug.Print Nz(x) = ""  ' True

抱歉没人在评论之前:) 如果您需要任何进一步的解释,请不要犹豫。