web-dev-qa-db-fra.com

Découvrez si la matrice est définie positive avec numpy

J'ai besoin de savoir si la matrice est définie positive . Ma matrice est une matrice numpy. Je m'attendais à trouver une méthode connexe dans la bibliothèque numpy, mais sans succès. J'apprécie toute aide.

46
Zygimantas Gatelis

Vous pouvez également vérifier si toutes les valeurs propres de la matrice sont positives, si c'est le cas, la matrice est définie positive:

import numpy as np

def is_pos_def(x):
    return np.all(np.linalg.eigvals(x) > 0)
52
Akavall

Vous pouvez essayer de calculer la décomposition de Cholesky ( numpy.linalg.cholesky ). Cela augmentera LinAlgError si la matrice n'est pas définie positive.

45
NPE

Il semble y avoir une petite confusion dans toutes les réponses ci-dessus (au moins concernant la question).

Pour les matrices réelles, les tests pour les valeurs propres positives et les termes positifs dans np.linalg.cholesky ne s'appliquent que si la matrice est symétrique. Il faut donc d'abord tester si la matrice est symétrique puis appliquer l'une de ces méthodes (valeurs propres positives ou décomposition de Cholesky).

Par exemple:

import numpy as np

#A nonsymmetric matrix
A = np.array([[9,7],[6,14]])

#check that all eigenvalues are positive:
np.all(np.linalg.eigvals(A) > 0)

#take a 'Cholesky' decomposition:
chol_A = np.linalg.cholesky(A)

La matrice A n'est pas symétrique, mais les valeurs propres sont positives et Numpy renvoie une décomposition de Cholesky incorrecte. Vous pouvez vérifier que:

chol_A.dot(chol_A.T)

est différent de A.

Vous pouvez également vérifier que toutes les fonctions python ci-dessus testeraient positivement la "définition positive". Cela pourrait potentiellement être un problème grave si vous essayez d'utiliser la décomposition Cholesky pour calculer l'inverse, puisque:

>np.linalg.inv(A)
array([[ 0.16666667, -0.08333333],
   [-0.07142857,  0.10714286]])

>np.linalg.inv(chol_A.T).dot(np.linalg.inv(chol_A))
array([[ 0.15555556, -0.06666667],
   [-0.06666667,  0.1       ]])

sont différents.

En résumé, je suggère d'ajouter une ligne à l'une des fonctions ci-dessus pour vérifier si la matrice est symétrique, par exemple:

def is_pos_def(A):
    if np.array_equal(A, A.T):
        try:
            np.linalg.cholesky(A)
            return True
        except np.linalg.LinAlgError:
            return False
    else:
        return False

Vous pouvez remplacer np.array_equal (A, A.T) dans la fonction ci-dessus pour np.allclose (A, A.T) pour éviter les différences dues aux erreurs en virgule flottante.

11
Daniel Garza

Pour illustrer la réponse de @ NPE avec du code prêt à l'emploi:

import numpy as np

def is_pd(K):
    try:
        np.linalg.cholesky(K)
        return 1 
    except np.linalg.linalg.LinAlgError as err:
        if 'Matrix is not positive definite' in err.message:
            return 0
        else:
            raise 
4
MarcoMag

Je ne sais pas pourquoi la solution de NPE est si sous-estimée. C'est la meilleure façon de procéder. J'ai trouvé sur Wkipedia que la complexité est cubique.

De plus, il est dit qu'elle est plus stable numériquement que la décomposition de Lu. Et la décomposition de Lu est plus stable que la méthode de recherche de toutes les valeurs propres.

Et, c'est une solution très élégante, car c'est un fait:

Une matrice a une décomposition de Cholesky si et seulement si elle est positive symétrique.

Alors pourquoi ne pas utiliser les mathématiques? Peut-être que certaines personnes ont peur de l'augmentation de l'exception, mais c'est aussi un fait, il est très utile de programmer avec des exceptions.

4
InfiniteLooper

Pour une matrice réelle $ A $, nous avons $ x ^ TAx =\frac {1} {2} (x ^ T (A + A ^ T) x) $, et $ A + A ^ T $ est une matrice réelle symétrique . Donc $ A $ est positif défini si $ A + A ^ T $ est positif défini, si toutes les valeurs propres de $ A + A ^ T $ sont positives.

import numpy as np

def is_pos_def(A):
    M = np.matrix(A)
    return np.all(np.linalg.eigvals(M+M.transpose()) > 0)
0
Martin Wang