La fonction det_recursive fonctionne pour une matrice carrée de n'importe quelle taille. Cependant, comme il utilise la méthode naïve récursive pour étendre la formule de Laplace, il est très lent pour les matrices de grande taille.
Une autre technique consiste à transformer la matrice en une forme triangulaire supérieure en utilisant la technique d'élimination de gauss. Alors le déterminant de la matrice est simplement le produit des éléments diagonaux de la forme transformée triangulaire de la matrice originale.
Fondamentalement, numpy est le plus rapide, mais en interne, il utilise une sorte de méthode de transformation de matrice linéaire similaire à ce que fait l'élimination de gauss. Cependant, je ne suis pas sûr de ce que c'est exactement!
In[1]
import numpy as np
In[2]
mat = np.random.rand(9,9)
print("numpy asnwer = ", np.linalg.det(mat))
Out[2]
numpy asnwer = 0.016770106020608373
In[3]
def det_recursive(A):
if A.shape[0] != A.shape[1]:
raise ValueError('matrix {} is not Square'.format(A))
sol = 0
if A.shape != (1,1):
for i in range(A.shape[0]):
sol = sol + (-1)**i * A[i, 0] * det_recursive(np.delete(np.delete(A, 0, axis= 1), i, axis= 0))
return sol
else:
return A[0,0]
In[4]
print("recursive asnwer = ", det_recursive(mat))
Out[4]
recursive asnwer = 0.016770106020608397
In[5]
def det_gauss_elimination(a,tol=1.0e-9):
"""
calculate determinant using gauss-elimination method
"""
a = np.copy(a)
assert(a.shape[0] == a.shape[1])
n = a.shape[0]
# Set up scale factors
s = np.zeros(n)
mult = 0
for i in range(n):
s[i] = max(np.abs(a[i,:])) # find the max of each row
for k in range(0, n-1): #pivot row
# Row interchange, if needed
p = np.argmax(np.abs(a[k:n,k])/s[k:n]) + k
if abs(a[p,k]) < tol:
raise Exception("Matrix is singular")
if p != k:
a[[k,p],:] = a[[p, k],:]
s[k],s[p] = s[p],s[k]
mult = mult + 1
# convert a to upper triangular matrix
for i in range(k+1,n):
if a[i,k] != 0.0: # skip if a(i,k) is already zero
lam = a [i,k]/a[k,k]
a[i,k:n] = a[i,k:n] - lam*a[k,k:n]
deter = np.prod(np.diag(a))* (-1)**mult
return deter
In[6]
print("gauss elimination asnwer = ", det_gauss_elimination(mat))
Out[6]
gauss elimination asnwer = 0.016770106020608383
In[7]
print("numpy time")
%timeit -n3 -r3 np.linalg.det(mat)
print("\nrecursion time")
%timeit -n3 -r3 det_recursive(mat)
print("\ngauss_elimination time")
%timeit -n3 -r3 det_gauss_elimination(mat)
Out[7]
numpy time
40.8 µs ± 17.2 µs per loop (mean ± std. dev. of 3 runs, 3 loops each)
recursion time
10.1 s ± 128 ms per loop (mean ± std. dev. of 3 runs, 3 loops each)
gauss_elimination time
472 µs ± 106 µs per loop (mean ± std. dev. of 3 runs, 3 loops each)
Avez-vous vraiment besoin de coder votre propre routine? Il existe de nombreux modules disponibles qui le feront pour vous. Découvrez numpy, par exemple. (les pages web de documentation de numpy semblent être hors ligne pour le moment - peut-être en raison de la tempête de neige en Amérique de l'Est?) –
limitation pour utiliser certaines de ces fonctions de construction, vous devez en construire une –
Étant donné que vous devez coder votre propre routine, faites vous devez utiliser la méthode des mineurs? C'est * très * inefficace même pour des tailles modérées de N, de l'ordre de N factoriel. Pourriez-vous utiliser l'élimination gaussienne, par exemple? Je l'ai utilisé pour mon tout premier programme d'ordinateur exécuté - écrit à la main sur des cartes pour un mainframe fonctionnant BASIC, il y a plusieurs années. –