web-dev-qa-db-fra.com

python fonction intégrée pour faire la réduction de la matrice

python a-t-il une fonction intégrée qui convertit une matrice en forme d'échelon de ligne (également connue sous le nom de triangulaire supérieur)?

23
user968102

Si vous pouvez utiliser sympy , Matrix.rref() peut le faire:

In [8]: sympy.Matrix(np.random.random((4,4))).rref()
Out[8]: 
([1, 1.42711055402454e-17, 0, -1.38777878078145e-17]
[0,                  1.0, 0,  2.22044604925031e-16]
[0, -2.3388341405089e-16, 1, -2.22044604925031e-16]
[0, 3.65674099486992e-17, 0,                   1.0],
 [0, 1, 2, 3])
28
NPE

voir http://mail.scipy.org/pipermail/numpy-discussion/2008-November/038705.html

Fondamentalement: ne le faites pas.

L'algorithme rref produit trop d'imprécision lorsqu'il est implémenté sur un ordinateur. Vous voulez donc soit résoudre le problème d'une autre manière, soit utiliser des symboles comme l'a suggéré @aix.

4
Winston Ewert

Oui. Dans scipy.linalg, lu fait LU décomposition qui vous donnera essentiellement la forme de l'échelon de ligne.

Il existe d'autres factorisations telles que qr, rq, svd, et plus encore, si cela vous intéresse.

Documentation.

4
Steve Tjoa

Je suis d'accord avec un commentaire @Mile à la réponse @WinstonEwert Il n'y a aucune raison pour qu'un ordinateur ne puisse pas effectuer RREF avec précision donnée .

La réalisation de RREF ne devrait pas être très compliquée, et matlab a en quelque sorte réussi à avoir cette fonction, donc numpy devrait avoir aussi.

J'ai fait une réalisation très simple et directe, ce qui est très inefficace. Mais pour les matrices simples, cela fonctionne plutôt bien:

def rref(mat,precision=0,GJ=False):
    m,n = mat.shape
    p,t = precision, 1e-1**precision
    A = around(mat.astype(float).copy(),decimals=p )
    if GJ:
        A = hstack((A,identity(n)))
    pcol = -1 #pivot colum
    for i in xrange(m):
        pcol += 1
        if pcol >= n : break
        #pivot index
        pid = argmax( abs(A[i:,pcol]) )
        #Row exchange
        A[i,:],A[pid+i,:] = A[pid+i,:].copy(),A[i,:].copy()
        #pivot with given precision
        while pcol < n and abs(A[i,pcol]) < t:
            #pivot index
            pid = argmax( abs(A[i:,pcol]) )
            #Row exchange
            A[i,:],A[pid+i,:] = A[pid+i,:].copy(),A[i,:].copy()
            pcol += 1
        if pcol >= n : break
        pivot = float(A[i,pcol])
        for j in xrange(m):
            if j == i: continue
            mul = float(A[j,pcol])/pivot
            A[j,:] = around(A[j,:] - A[i,:]*mul,decimals=p)
        A[i,:] /= pivot
        A[i,:] = around(A[i,:],decimals=p)

    if GJ:
        return A[:,:n].copy(),A[:,n:].copy()
    else:
        return A   

Voici quelques tests simples

print "/*--------------------------------------/"
print "/             Simple TEST               /"
print "/--------------------------------------*/"
A = array([[1,2,3],[4,5,6],[-7,8,9]])
print "A:\n",R
R = rref(A,precision=6)
print "R:\n",R
print
print "With GJ "
R,E =   rref(A,precision=6,GJ=True)
print "R:\n",R
print "E:\n",E
print "AdotE:\n",around( dot(A,E),decimals=0)

/*--------------------------------------/
/             Simple TEST               /
/--------------------------------------*/
A:
[[ 1.  0.  1.]
 [-0.  1.  1.]
 [ 0.  0.  0.]
 [ 0.  0.  0.]]
R:
[[ 1.  0.  0.]
 [ 0.  1.  0.]
 [ 0.  0.  1.]]

With GJ 
R:
[[ 1.  0.  0.]
 [ 0.  1.  0.]
 [ 0.  0.  1.]]
E:
[[-0.071428  0.142857 -0.071429]
 [-1.857142  0.714285  0.142857]
 [ 1.595237 -0.523809 -0.071428]]
AdotE:
[[ 1.  0.  0.]
 [ 0.  1.  0.]
 [-0.  0.  1.]]

print "/*--------------------------------------/"
print "/        Not Invertable TEST            /"
print "/--------------------------------------*/"
A = array([
    [2,2,4, 4],
    [3,1,6, 2],
    [5,3,10,6]])
print "A:\n",A
R = rref(A,precision=2)
print "R:\n",R
print
print "A^{T}:\n",A.T
R = rref(A.T,precision=10)
print "R:\n",R
/*--------------------------------------/
/        Not Invertable TEST            /
/--------------------------------------*/
A:
[[ 2  2  4  4]
 [ 3  1  6  2]
 [ 5  3 10  6]]
R:
[[ 1.  0.  2.  0.]
 [-0.  1. -0.  2.]
 [ 0.  0.  0.  0.]]

A^{T}:
[[ 2  3  5]
 [ 2  1  3]
 [ 4  6 10]
 [ 4  2  6]]
R:
[[ 1.  0.  1.]
 [-0.  1.  1.]
 [ 0.  0.  0.]
 [ 0.  0.  0.]]
3
rth

Vous pouvez le définir vous-même:

def rref(matrix):
    A = np.array(matrix, dtype=np.float64)

    i = 0 # row
    j = 0 # column
    while True:
        # find next nonzero column
        while all(A.T[j] == 0.0):
            j += 1
            # if reached the end, break
            if j == len(A[0]) - 1 : break
        # if a_ij == 0 find first row i_>=i with a 
        # nonzero entry in column j and swap rows i and i_
        if A[i][j] == 0:
            i_ = i
            while A[i_][j] == 0:
                i_ += 1
                # if reached the end, break
                if i_ == len(A) - 1 : break
            A[[i, i_]] = A[[i_, i]]
        # divide ith row a_ij to make it a_ij == 1
        A[i] = A[i] / A[i][j]
        # eliminate all other entries in the jth column by subtracting
        # multiples of of the ith row from the others
        for i_ in range(len(A)):
            if i_ != i:
                A[i_] = A[i_] - A[i] * A[i_][j] / A[i][j]
        # if reached the end, break
        if (i == len(A) - 1) or (j == len(A[0]) - 1): break
        # otherwise, we continue
        i += 1
        j += 1

    return A
0
Peter Francis