84 votes

Matrice symétrique "intelligente" Numpy

Existe-t-il une matrice symétrique intelligente et compacte dans numpy qui remplit automatiquement (et de manière transparente) la position à [j][i] lorsque [i][j] est écrit ?

import numpy
a = numpy.symmetric((3, 3))
a[0][1] = 1
a[1][0] == a[0][1]
# True
print(a)
# [[0 1 0], [1 0 0], [0 0 0]]

assert numpy.all(a == a.T) # pour toute matrice symétrique

Un Hermitien automatique serait également agréable, bien que je n'en aurai pas besoin au moment de l'écriture.

1 votes

Vous pouvez envisager de marquer la réponse comme acceptée, si elle résout votre problème. :)

2 votes

J'ai voulu attendre une meilleure (c'est-à-dire intégrée et efficace en mémoire) réponse à venir. Il n'y a rien de mal avec votre réponse, bien sûr, donc je l'accepterai de toute façon.

0 votes

Je pense qu'à ce jour, vous ne pouvez que sous-classer (non merci) ou envelopper numpy, par exemple en enveloppant numpy en modifiant la façon dont vous remplissez la matrice via vos propres fonctions setter, afin d'obtenir une interface qui y ressemble. Je pense que vous pouvez également ajouter des tableaux masqués pour éviter les calculs en double en aval, tant que les tableaux masqués prennent en charge suffisamment de vos scénarios de manipulation de matrice. Rien n'est intégré ni d'une manière génériquement robuste.

0voto

Charles F Points 349

Il est trivial de remplir de manière pythonique [i][j] si [j][i] est rempli. La question du stockage est un peu plus intéressante. On peut augmenter la classe de tableau numpy avec un attribut packed qui est utile à la fois pour économiser le stockage et pour lire ultérieurement les données.

class Sym(np.ndarray):

    # classe wrapper pour le tableau numpy pour les matrices symétriques. Le nouvel attribut peut emballer la matrice pour optimiser le stockage.
    # Utilisation :
    # Si vous avez une matrice symétrique A comme un tableau numpy de forme (n,n), Sym(A).packed est un tableau numpy de forme (n(n+1)/2,) 
    # qui est une version compressée de A. Pour le convertir à nouveau, il suffit d'emballer la liste à plat dans Sym(). Notez que Sym(Sym(A).packed)

    def __new__(cls, input_array):
        obj = np.asarray(input_array).view(cls)

        if len(obj.shape) == 1:
            l = obj.copy()
            p = obj.copy()
            m = int((np.sqrt(8 * len(obj) + 1) - 1) / 2)
            sqrt_m = np.sqrt(m)

            if np.isclose(sqrt_m, np.round(sqrt_m)):
                A = np.zeros((m, m))
                for i in range(m):
                    A[i, i:] = l[:(m-i)]
                    A[i:, i] = l[:(m-i)]
                    l = l[(m-i):]
                obj = np.asarray(A).view(cls)
                obj.packed = p

            else:
                raise ValueError('La longueur d'entrée unidimensionnelle doit être un nombre triangulaire.')

        elif len(obj.shape) == 2:
            if obj.shape[0] != obj.shape[1]:
                raise ValueError('L'entrée bidimensionnelle doit être une matrice carrée.')
            packed_out = []
            for i in range(obj.shape[0]):
                packed_out.append(obj[i, i:])
            obj.packed = np.concatenate(packed_out)

        else:
            raise ValueError('Le tableau d'entrée doit être en 1 ou 2 dimensions.')

        retourner obj

    def __array_finalize__(self, obj):
        if obj is None: return
        self.packed = getattr(obj, 'packed', None)

```

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X