[PYTHON] J'ai essayé Smith en standardisant une matrice entière avec Numpy

Récemment, j'ai lu un livre intitulé "Structure et topologie des protéines (Hiraoka)" avec un ami. Dans ce livre, il y avait une méthode de décomposition d'une matrice d'entiers appelée standardisation Smith, donc je l'ai implémentée avec Numpy.

Matrice de base

Avant d'expliquer la standardisation de Smith, il est nécessaire d'expliquer la matrice de base de la matrice entière.

La matrice de base dans l'espace vectoriel est la matrice pour effectuer la transformation de base de la matrice. (Il devrait être appris au cours de la première année d'université.). Il y a les trois transformations de base suivantes de la matrice.

  1. Multipliez une ligne ou une colonne par un certain nombre (à l'exclusion de 0).
  2. Permutez deux lignes ou colonnes.
  3. Ajoutez un multiple constant d'une autre ligne ou colonne à une ligne ou colonne.

Chaque transformation peut être réalisée à partir de la gauche ou de la droite en appliquant une matrice ** régulière ** (c'est-à-dire une matrice dans laquelle une matrice inverse existe). Cette matrice régulière est appelée la matrice de base.

Ici, si les matrices de base correspondant à 1, 2 et 3 sont exprimées comme $ P_i (c), Q_ {ij}, R_ {ij} (c) $, elles sont comme suit.

P_i(c) =\begin{pmatrix}
1&&&&&&\\
&\ddots&&&&&\\
&&1&&&&\\
&&&c&&&\\
&&&&1&&\\
&&&&&\ddots&\\
&&&&&&1\\
\end{pmatrix}
Q_{ij} =\begin{pmatrix}
1&&&&&&\\
&\ddots&&&&&\\
&&0&&1&&\\
&&&\ddots&&&\\
&&1&&0&&\\
&&&&&\ddots&\\
&&&&&&1\\
\end{pmatrix}
R_{ij}(c) =\begin{pmatrix}
1&&&&&&\\
&\ddots&&&&&\\
&&1&&c&&\\
&&&\ddots&&&\\
&&&&1&&\\
&&&&&\ddots&\\
&&&&&&1\\
\end{pmatrix}

De plus, l'inverse de chaque matrice de base est 1.~ P_i(c)^{-1} = P_i(1/c) 2.~Q_{ij}^{-1} = Q_{ij} 3.~R_{ij}(c)^{-1} = R_{ij}(-c) Par conséquent, la régularité de la matrice de base est dérivée. La théorie de base de l'algèbre linéaire telle que la méthode de balayage est dérivée en utilisant cette matrice de base.

Maintenant, considérons la matrice de base pour la matrice entière.

La matrice de base $ Q_ {ij}, R_ {ij} (c) $ sur l'espace vectoriel peut être adoptée comme matrice de base pour la matrice entière car la matrice inverse est la matrice entière pour l'entier $ c $. D'autre part, $ P_i (c) $ n'a pas de matrice inverse à moins que la constante $ c $ soit 1 ou -1. Puisque $ P_i (1) $ est une matrice unitaire, $ P_i (-1) $ est une matrice de base d'une matrice entière.

Par conséquent, pour l'entier $ c $, $ P_i (-1), Q_ {ij}, R_ {ij} (c) $ sont la matrice de base de la matrice entière.

Type standard Smith

La standardisation de Smith est une méthode de diagonalisation pour les matrices entières. La matrice d'entiers arbitraires A utilise les matrices $ P et Q $

B = Q^{-1} A P = 
\left(
    \begin{array}{c|c}
     \begin{matrix}
     c_1 & &0 \\
      & \ddots &\\
     0 & & c_k
     \end{matrix}
     & 0 \\
\hline
     0 &0
\end{array}\right)

Peut être diagonalisé avec. Ici, $ P et Q $ sont les produits des matrices de base, et $ c_ {i + 1} $ peut être divisé par $ c_i $. Puisque les matrices $ P et Q $ sont les produits des matrices de base, il existe une matrice inverse de matrices entières. La forme diagonalisée par le produit de cette matrice de base est appelée la forme standard de Smith.

Exemple:

\begin{pmatrix}
1&0&0\\
7&-7&-4\\
0&2&1
\end{pmatrix}^{-1}
\begin{pmatrix}
7&3&2&1\\
7&6&7&7\\
4&8&2&0
\end{pmatrix}
\begin{pmatrix}
0&0&-6&13\\
0&0&-13&28\\
0&1&65&-138\\
1&-2&-49&101
\end{pmatrix}
=
\begin{pmatrix}
1&0&0&0\\
0&1&0&0\\
0&0&2&0
\end{pmatrix}

Le formulaire standard Smith est obtenu en répétant les quatre opérations suivantes.

  1. $ A_ {t + 1} = {\ rm moveMN} (A_t) $: (1,1) Une transformation qui déplace la plus petite valeur vers un élément.

Déplacez l'élément $ A [i, j] $ avec la plus petite valeur absolue non nulle vers le composant (1,1). En d'autres termes

    {\rm moveMN}(A_t) = 
    \begin{cases}
    Q_{i,0} A_tQ_{0,j},& A[i,j]>0\\
    Q_{i,0} A_tQ_{0,j}P_1(-1),& A[i,j]<0    
    \end{cases}

Est défini comme.

Exemple:

\begin{pmatrix}
7&9&5&8\\
5&1&0&2\\
8&1&8&5
\end{pmatrix}
\rightarrow
\begin{pmatrix}
1&5&0&2\\
9&7&5&8\\
1&8&8&5
\end{pmatrix}
  1. $ A_ {t + 1} = {\ rm rowR} (A_t) $: Conversion pour réduire la colonne la plus à gauche sauf $ A [1,1] $.

Pour tout $ i $, si $ q_i = A [i, 0] \ div A [0,0] $ (le reste est tronqué) $ {\rm rowR}(A_t) := \prod_{i>1} R_{i,0}(-q_i) A_t $ Est défini comme.

Exemple:

\begin{pmatrix}
1&5&0&2\\
9&7&5&8\\
1&8&8&5
\end{pmatrix}
\rightarrow
\begin{pmatrix}
1&5&0&2\\
0&-38&5&10\\
0&3&8&3
\end{pmatrix}
  1. $ A_ {t + 1} = {\ rm colR} (A_t) $: Transformez pour rendre la ligne du haut plus petite sauf $ A [1,1] $.

Pour tout $ i $, si $ q_i = A [0, i] \ div A [0,0] $ (le reste est tronqué) $ {\rm colR}(A_t) := \prod_{i>1} A_t R_{0,i}(-q_i) $ Est défini comme.

Exemple:

\begin{pmatrix}
1&5&0&2\\
0&-38&5&10\\
0&3&8&3
\end{pmatrix}
\rightarrow
\begin{pmatrix}
1&0&0&0\\
0&-38&5&10\\
0&3&8&3
\end{pmatrix}
  1. $ A_ {t + 1} = {\ rm remR} (A_t) $: Une conversion qui exclut les éléments qui ne sont pas divisibles par $ A [1,1] $ dans $ A [2:, 2:] $.

Soit $ A [i, j] $ un élément non divisible par $ A [1,1] $, et soit $ q = A [i, j] \ div A [1,1] $ (le reste est tronqué). Cette fois, $ {\rm remR}(A_t) := R_{0,j}(q) A_t R_{i,0}(-1) $ Est défini comme.

Exemple:

\begin{pmatrix}
2&0&0&0\\
0&2&3&4\\
0&2&2&6
\end{pmatrix}
\rightarrow
\begin{pmatrix}
2&0&-2&0\\
2&2&1&4\\
0&2&2&6
\end{pmatrix}

===

Le formulaire standard Smith peut être généré en répétant les quatre transformations ci-dessus selon l'algorithme suivant.

  1. A = moveMN(A)
  2. A = rowR(A)
  3. Si A [2:, 1]! = 0, revenez à 1.
  4. A = colR(A)
  5. Si A [1,2:]! = 0, revenez à 1.
  6. Si tous les éléments de A [2:, 2:] ne sont pas divisibles par A [1,1], alors A = remR (A) et 1. Retourner à.
  7. Réglez A = A [2:, 2:] et revenez à 1.

Ce code python est présenté ci-dessous.

Code Python

import numpy as np

#Matrice de base sur matrice entière
def Eij(i,j,n):
    E = np.eye(n)
    E[i,i] = 0
    E[j,j] = 0
    E[i,j] = 1
    E[j,i] = 1
    return E

def Ei(i,n):
    E = np.eye(n)
    E[i,i] = -1
    return E

def Ec(i,j,c,n):
    E = np.eye(n)
    E[i,j] = c
    return E    

# A[k:,k:]La plus petite valeur absolue autre que 0 ci-dessus est A[k,k]Convertir pour passer à
def moveMN(A,k):
    tmp_A = A[k:,k:]
    a = np.abs(tmp_A[tmp_A != 0]).min()
    i = np.where(np.abs(tmp_A) == a)[0][0] + k
    j = np.where(np.abs(tmp_A) == a)[1][0]+ k
    P = Eij(k,j,A.shape[1])
    invQ = Eij(i,k,A.shape[0])
    B = invQ.dot(A).dot(P)
    if B[k,k]<0:
        Pi =Ei(k,A.shape[1])
        B = B.dot(Pi)
        P = P.dot(Pi)
    return invQ.astype(int),B.astype(int),P.astype(int)

#A[k,k]Utilisant un[k+1:,k]Conversion qui s'ajuste à 0.(Si vous ne pouvez pas l'organiser, l'élément est A[k,k]Plus petite)
def rowR(A,k):
    B = A.copy()
    invQ = np.eye(A.shape[0])
    P = np.eye(A.shape[1])
    for i in range(k+1,A.shape[0]):
        q = A[i,k]//A[k,k]
        #Résidu
        r = A[i,k]%A[k,k]
        invQi = Ec(i,k,-q,A.shape[0])
        B = invQi.dot(B)
        invQ = invQi.dot(invQ)
    return invQ.astype(int),B.astype(int),P.astype(int)

#A[k,k]Utilisant un[k,k+1]Conversion qui s'ajuste à 0.(Si vous ne pouvez pas l'organiser, l'élément est A[k,k]Plus petite)
def colR(A,k):
    B = A.copy()
    invQ = np.eye(A.shape[0])
    P = np.eye(A.shape[1])
    for i in range(k+1,A.shape[1]):
        q = A[k,i]//A[k,k]
        #Résidu
        r = A[k,i]%A[k,k]
        Pi = Ec(k,i,-q,A.shape[1])
        B = B.dot(Pi)
        P = P.dot(Pi)
    return invQ.astype(int),B.astype(int),P.astype(int)

# A[k+1:,k+1:]Dans un[k,k]Élément A qui n'est pas divisible par[i,j]UNE[k,k]Conversion pour convertir en résidus de
def remR(A,k):
    invQ = np.eye(A.shape[0])
    P = np.eye(A.shape[1])
    #  Find i,j
    i = np.where(A[k+1:,k+1:]%A[k,k] !=0)[0][0] +k+1
    j = np.where(A[k+1:,k+1:]%A[k,k] !=0)[1][0] +k+1
    q = A[i,j]//A[k,k]
    r = A[i,j]%A[k,k]
    invQi = Ec(i,k,q,A.shape[0])
    Pi = Ec(k,j,-1,A.shape[1])
    B = invQi.dot(A).dot(Pi)
    P = P.dot(Pi)
    invQ = invQi.dot(invQ)
    return invQ.astype(int),B.astype(int),P.astype(int)


# Main Function
def Smith_Normalization(A):
    invQ = np.eye(A.shape[0])
    P = np.eye(A.shape[1])
    A0 = A.copy()
    # limit of optimization
    N = 1000
    for k in range(min(A0.shape)):
        # If A0[k:,k:] is zero matrix, then stop calculation
        if np.sum(np.abs(A0[k:,k:]))==0:
            break
        for i in range(N):
            if i == N-1 : 
                print("Error: Time Out")
            # minimize A[k,k]
            invQi,A1,Pi = moveMN(A0,k)
            invQ = invQi.dot(invQ)
            P = P.dot(Pi)
            # make zero row A[k+1:,k]
            invQi,A2,Pi = rowR(A1,k)
            invQ = invQi.dot(invQ)
            P = P.dot(Pi)
            # if row A2[k+1:,k] is zero vector ?
            if np.abs(A2[k+1:,k]).sum() ==0:
                # make zero col A[k,k+1:]
                invQi,A3,Pi = colR(A2,k)
                invQ = invQi.dot(invQ)
                P = P.dot(Pi)
                # if col A3[k+1:,k] is zero vector ?
                if np.abs(A3[k,k+1:]).sum() ==0:
                    # A[k,k]|A[k+1:,k+1:]?
                    if np.sum(A3[k+1:,k+1:]%A3[k,k]) == 0:                    
                        A0 = A3.copy()            
                        break;
                    else:
                        # reduce A[k+1:,k+1:]
                        invQi,A0,Pi = remR(A3,k)
                        invQ = invQi.dot(invQ)
                        P = P.dot(Pi)
                else:
                    A0 = A3.copy()            
            else:
                A0 = A2.copy()

    B = A0.copy().astype(int)
    P = P.astype(int)
    invQ = invQ.astype(int)
    return invQ,B,P



# Check result
A = np.random.randint(0,10,(4,5))
invQ,B,P = Smith_Normalization(A)
print(A)
print(invQ)
print(B)
print(P)

Résumé

--Défini la matrice de base de la matrice entière.

Il était très difficile d'écrire un résumé par rapport au code python. (J'ai cassé quelques explications polies ...)

Détails du code

https://github.com/yuji0001/2020Topology_basic

Reference

Hiroaki Hiraoka, "Structure et topologie des protéines, introduction au groupe d'homologie persistante", Kyoritsu Publishing, 2013 Author Yuji Okamoto [email protected]

Recommended Posts

J'ai essayé Smith en standardisant une matrice entière avec Numpy
J'ai essayé la décomposition matricielle non négative (NMF) avec TensorFlow
J'ai essayé de détecter un objet avec M2Det!
J'ai essayé d'envoyer un email avec SendGrid + Python
Concaténation de matrices avec Numpy
J'ai essayé d'implémenter le perceptron artificiel avec python
J'ai essayé de créer une application OCR avec PySimpleGUI
J'ai essayé de trouver la classe alternative avec tensorflow
J'ai essayé fp-growth avec python
J'ai essayé de gratter avec Python
J'ai écrit GP avec numpy
J'ai essayé Learning-to-Rank avec Elasticsearch!
Essayez l'opération matricielle avec NumPy
J'ai essayé le clustering avec PyCaret
J'ai essayé gRPC avec Python
J'ai essayé de gratter avec du python
J'ai créé une bibliothèque d'opérations matricielles à N dimensions Matft avec Swift
J'ai essayé d'envoyer un e-mail d'Amazon SES avec Python
J'ai essayé de créer un article dans Wiki.js avec SQL Alchemy
J'ai essayé de résumer des phrases avec summpy
J'ai essayé l'apprentissage automatique avec liblinear
J'ai essayé webScraping avec python.
J'ai essayé de déplacer de la nourriture avec SinGAN
J'ai envoyé un SMS avec Python
J'ai essayé d'implémenter DeepPose avec PyTorch
J'ai essayé d'envoyer du courrier depuis le serveur Sakura avec flask-mail
J'ai essayé la détection de visage avec MTCNN
J'ai essayé d'exécuter prolog avec python 3.8.2.
J'ai essayé la communication SMTP avec Python
J'ai essayé la génération de phrases avec GPT-2
J'ai essayé d'apprendre LightGBM avec Yellowbrick
J'ai essayé la reconnaissance faciale avec OpenCV
J'ai essayé de créer une fonction de similitude d'image avec Python + OpenCV
J'ai essayé de mettre en œuvre un apprentissage en profondeur qui n'est pas profond avec uniquement NumPy
J'ai créé un capteur d'ouverture / fermeture (lien Twitter) avec TWE-Lite-2525A
J'obtiens une erreur avec les pandas d'importation.
J'ai essayé l'analyse de régression multiple avec régression polypoly
J'ai essayé d'utiliser Amazon SQS avec django-celery
J'ai essayé d'implémenter Autoencoder avec TensorFlow
J'ai essayé linebot avec flacon (anaconda) + heroku
J'ai essayé de commencer avec Hy
J'ai essayé d'utiliser du sélénium avec du chrome sans tête
J'ai essayé l'analyse factorielle avec des données Titanic!
J'ai essayé d'apprendre avec le Titanic de Kaggle (kaggle②)
J'ai essayé le rendu non réaliste avec Python + opencv
J'ai essayé un langage fonctionnel avec Python
J'ai essayé la récurrence avec Python ② (séquence de nombres Fibonatch)
J'ai essayé d'implémenter DeepPose avec PyTorch PartⅡ
J'ai essayé d'implémenter CVAE avec PyTorch
J'ai essayé de jouer avec l'image avec Pillow
J'ai fait un jeu de vie avec Numpy
J'ai essayé de résoudre TSP avec QAOA
J'ai essayé la reconnaissance d'image simple avec Jupyter
J'ai essayé le réglage fin de CNN avec Resnet
J'ai essayé le traitement du langage naturel avec des transformateurs.
# J'ai essayé quelque chose comme Vlookup avec Python # 2