2017-02-06 1 views
3

Disons que je définis une grande matrice quadratique (par exemple 150x150). Une fois c'est un tableau numpy (matrice A), une fois c'est un tableau scipy sparse (matrice B).Pourquoi la fonction d'inversion de matrice dans numpy et scipy renvoie des résultats différents avec de grandes matrices quadratiques?

import numpy as np 
import scipy as sp 

from scipy.sparse.linalg import spsolve 

size = 150 
A = np.zeros((size, size)) 
length = 1000 
# Set some random numbers at random places 
A[np.random.randint(0, size, (2, length)).tolist()] = \ 
    np.random.randint(0, size, (length,)) 
B = sp.sparse.csc_matrix(A) 

Maintenant, je calcule l'inverse des deux matrices. Pour la matrice B J'utilise les deux méthodes pour calculer l'inverse (sp.sparse.linalg.inv et spsolve).

epsilon = 10.**-8 # Is needed to prevent singularity of each matrix 

inv_A = np.linalg.pinv(A+np.eye(size)*epsilon) 
inv_B = sp.sparse.linalg.inv(B+sp.sparse.identity(size)*epsilon) 
inv_B2 = spsolve(B+sp.sparse.identity(size)*epsilon, sp.sparse.identity(size)) 

Pour vérifier si les deux inverses de A et B sont égaux, je vais résumer les différences au carré.

# Is not equal zero, question: Why? 
# Sometimes very small (~+-10**-27), sometimes very big (~+-10**5) 
print("np.sum((inv_A - inv_B)**2): {}".format(np.sum((inv_A - inv_B)**2))) 
# Should be zero 
print("np.sum((inv_B - inv_B2)**2): {}".format(np.sum((inv_B - inv_B2)**2))) 

Le problème est le suivant: Si j'utilise de petites matrices, par ex. 10x10, l'erreur entre des fonctions inverses numpy as scipy est très faible (environ ~ + -10 ** - 32). Mais j'ai besoin de la version clairsemée pour les grandes matrices (par exemple 500x500). Est-ce que je fais ici quelque chose de mal, ou est-il possible de calculer le bon inverse d'une matrice clairsemée en python?

+1

Quelle est la taille de l'erreur relative? –

+0

Voulez-vous dire l'erreur relative possible pour mon problème ou l'erreur relative entre les deux matrices? – PiMathCLanguage

+0

Je veux dire l'erreur que vous avez calculée divisée par la longueur euclidienne au carré de l'un des deux inverses que vous comparez. –

Répondre

2

La réponse à votre question principale est: En raison de votre malheureux choix de matrices d'exemple. Laissez-moi élaborer.

La précision de la machine est limitée, donc l'arithmétique en virgule flottante sera rarement précise à 100%. Juste essayer

>>> np.linspace(0, 0.9, 10)[1:] == np.linspace(0.1, 1, 10)[:-1] 
array([ True, True, True, True, True, False, True, True, True], dtype=bool) 

Normalement, c'est pas de problème, car les erreurs sont trop petites pour remarquer.

Cependant, pour de nombreux calculs, certaines entrées sont difficiles à manipuler et peuvent dépasser un algorithme numérique. Cela s'applique certainement à l'inversion de matrice, et vous avez eu la malchance de choisir des intrants aussi difficiles.

Vous pouvez réellement vérifier si une matrice peut être 'mal conditionnée' en regardant ses valeurs singulières, voir par exemple here. Voici les chiffres de l'état de la matrice pour plusieurs matrices générées par votre script (size=200, une matrice bien comportés a une valeur beaucoup plus proche de 1)

971899214237.0 
5.0134186641e+12 
36848.0807109 
958492416768.0 
1.66615247737e+16 
1.42435766189e+12 
1954.62614384 
2.35259324603e+12 
5.58292606978e+12 

Passage à des matrices bien comportés vos résultats devraient améliorer de manière drastique.