On me donne une matrice symétrique, inversible, définie positive et dense. Je dois tester si où J est la matrice des uns.J
Je fais actuellement cela avec la bibliothèque de tatou mais cela s'avère trop lent. Le fait est que je dois le faire pour un billion de matrices et il s'avère que le calcul des deux déterminants est le goulot d'étranglement de mon programme. J'ai donc deux questions
Y a-t-il une astuce que je pourrais utiliser pour calculer le déterminant plus rapidement étant donné que je connaissais sa taille? Une extension désordonnée pour les matrices pourrait-elle fonctionner dans ce cas?
Existe-t-il un autre moyen efficace de tester l'égalité
Éditer. Pour répondre aux commentaires. J'ai besoin de calculer tous les graphes connectés non auto-complémentaires d'ordre telle sorte que et aient le même nombre d'arbres couvrant. La motivation pour cela peut être trouvée dans ce post de mathoverflow . En ce qui concerne la machine, je l'exécute en parallèle sur une machine à 8 cœurs 3,4 GHz.
Éditer. J'ai pu réduire le temps d'exécution prévu de 50% en créant un programme C pour calculer spécifiquement le déterminant d'une matrice . Les suggestions sont toujours les bienvenues.
la source
Réponses:
Puisque vous utilisez déjà C ++ et que vos matrices sont définies positives symétriques, j'effectuerais une factorisation pivotée de et également de . Ici, je suppose que est également défini positif, sinon le nécessitera un pivotement pour la stabilité numérique (il est également possible que même s'il n'est pas défini positif, le pivotement ne soit pas nécessaire, mais vous devez l'essayer). Q 12 I - Q - J 12 I - Q - J L D L TLDLT Q 12I−Q−J 12I−Q−J LDLT
C'est plus rapide qu'une factorisation LU, et aussi plus rapide que Cholesky car les racines carrées sont évitées. Le déterminant est simplement le produit des éléments de la matrice diagonale . Le code pour effectuer une factorisation LDL est si simple que vous pouvez l'écrire en moins de 50 lignes de C. La page Wikipedia à ce sujet décrit l'algorithme, et j'ai un code simple pour faire Cholesky ici . Vous pouvez grandement simplifier cela et le modifier pour éviter que la racine carrée implémente la factorisationL D L TD LDLT
Étant donné que vous pouvez également contrôler le format de stockage, vous pouvez optimiser davantage la routine pour stocker uniquement la moitié de la matrice et l'emballer dans un tableau linéaire pour maximiser la localité de la mémoire. J'écrirais également de simples routines de mise à jour personnalisées de produits scalaires et de rang 1, car les tailles de problème sont si petites que vous devriez laisser le compilateur aligner les routines pour réduire la surcharge des appels. Puisqu'il s'agit d'une boucle de taille fixe, le compilateur devrait être en mesure d'inclure et de dérouler automatiquement les choses le cas échéant.
J'éviterais d'essayer de jouer des tours pour profiter du fait que contient à l'intérieur de l'expression. Il est probable que pour de si petites tailles de problème, ces astuces finissent par être plus lentes que de simplement effectuer deux calculs déterminants distincts. Bien sûr, la seule façon de vérifier ces affirmations est de l'essayer.Q12I−Q−J Q
la source
Sans quelques informations sur la construction de ces matrices symétriques réelles définies positives , les suggestions à faire sont nécessairement assez limitées.12×12
J'ai téléchargé le paquet Armadillo de Sourceforge et j'ai jeté un œil à la documentation. Essayez d'améliorer les performances du calcul séparé de et , où est la matrice de rang 1 de toutes les unités, en définissant par exemple . La documentation note que c'est la valeur par défaut pour les matrices jusqu'à la taille , donc par omission je suppose que l' option est une valeur par défaut pour le cas .det(Q) J 4 × 4 12 × 12det(12I−Q−J) J 4×4 12×12
det(Q,slow=false)
slow=true
Ce qui estQ 12×12 le déterminant sera fait parce que le calcul est "jeté sur un mur" vers LAPACK (ou ATLAS) à ce point sans indication que le pivotement n'est pas requis; voir
slow=true
vraisemblablement fait est un pivot partiel ou total pour obtenir une forme d'échelon de ligne, à partir de laquelle le déterminant est facilement trouvé. Cependant, vous savez à l'avance que la matrice est définie positive, donc le pivotement n'est pas nécessaire pour la stabilité (au moins présumément pour la majeure partie de vos calculs. Il n'est pas clair si le paquet Armadillo lève une exception si les pivots deviennent trop petits, mais cela devrait être un fonctionnalité d'un package d'algèbre linéaire numérique raisonnable. EDIT: J'ai trouvé le code Armadillo qui implémente dans le fichier d'en-tête , en utilisant des modèles C ++ pour des fonctionnalités substantielles. Le paramètre ne semble pas affecter la façon dont un12 × 12det
include\armadillo_bits\auxlib_meat.hpp
slow=false
det_lapack
et ses invocations dans ce fichier.L'autre point serait de suivre leur recommandation de construire le paquet Armadillo lié aux remplacements à haute vitesse pour BLAS et LAPACK, si vous les utilisez effectivement; voir Sec. 5 du fichier README.TXT d'Armadillo pour plus de détails. [L'utilisation d'une version 64 bits dédiée de BLAS ou LAPACK est également recommandée pour la vitesse sur les machines 64 bits actuelles.]
La réduction des lignes en échelon est essentiellement une élimination gaussienne et a une complexité arithmétique . Pour les deux matrices, cela équivaut alors au double de ce travail, ou . Ces opérations peuvent bien être le "goulot d'étranglement" dans votre traitement, mais il y a peu d'espoir que sans structure spéciale dans (ou certaines relations connues parmi les milliards de cas de test permettant l'amortissement), le travail pourrait être réduit à .423n3+O(n2) QO(n2)43n3+O(n2) Q O(n2)
A titre de comparaison, l'expansion par les cofacteurs d'une matrice générale impliqueles opérations de multiplication (et à peu près autant d'additions / soustractions), donc pour la comparaison ( vs ) favorise clairement l'élimination par rapport aux cofacteurs.n ! n = 12 12 ! = 479001600 2n×n n! n=12 12!=479001600 23n3=1152
Une autre approche nécessitant un travail consisterait à réduire en forme tridiagonale avec des transformations de Householder, ce qui met également en forme tridiagonale. Les calculs et peuvent ensuite être effectués dans des opérations . [L'effet de la mise à jour de rang un dans le deuxième déterminant peut être exprimé comme un facteur scalaire donné en résolvant un système tridiagonal.]Q12I-Qdet(Q)det(12I-Q-J)O(n)-J43n3+O(n2) Q 12I−Q det(Q) det(12I−Q−J) O(n) −J
La mise en œuvre d'un tel calcul indépendant pourrait être utile pour vérifier les résultats des appels réussis (ou échoués) à la
det
fonction d'Armadillo .Cas spécial: comme suggéré par un commentaire de Jernej, supposons que où comme avant est la matrice (rang 1) de tous les uns et est un matrice diagonale non singulière (positive). En effet, pour l'application proposée en théorie des graphes, il s'agirait de matrices entières. Alors une formule explicite pour est:J D = diag ( d 1 , … , d n ) det ( Q )Q=D−J J D=diag(d1,…,dn) det(Q)
Une esquisse de sa preuve donne l'occasion d'illustrer une applicabilité plus large, c'est-à-dire chaque fois que a un déterminant connu et que le système est rapidement résolu. Commencez par prendre en compte:D v = ( 1 … 1 ) TD Dv=(1…1)T
Maintenant est à nouveau rang 1, à savoir . Notez que le deuxième déterminant est simplement:( d - 1 1 … d - 1 n ) T ( 1 … 1 )D−1J (d−11…d−1n)T(1…1)
où est le polynôme caractéristique de . En tant que matrice de rang 1, doit avoir (au moins) facteurs de pour tenir compte de son espace nul. La valeur propre "manquante" est , comme le montre le calcul:D - 1 J f ( x ) n - 1 x ∑ d - 1 if(x) D−1J f(x) n−1 x ∑d−1i
Il s'ensuit que le polynôme caractéristique , et est comme indiqué ci-dessus pour , .f ( 1 ) det ( I - D - 1 J ) 1 - ∑ d - 1 if(x)=xn−1(x−∑d−1i) f(1) det(I−D−1J) 1−∑d−1i
Notez également que si , alors , une matrice diagonale dont le déterminant est simplement le produit de ses entrées diagonales.12 I - Q - J = 12 I - D + J - J = 12 I - DQ=D−J 12I−Q−J=12I−D+J−J=12I−D
la source
Si vous avez une façon structurée d'énumérer les graphiques dont vous souhaitez calculer les déterminants, vous pourriez peut-être trouver des mises à jour de bas rang qui vous transfèrent d'un graphique à un autre.
Si tel est le cas, vous pouvez alors utiliser le lemme déterminant de matrice pour calculer à moindre coût le déterminant du graphique suivant à énumérer en utilisant votre connaissance du déterminant du graphique actuel.
Autrement dit, pour une matrice et des vecteurs : Ceci peut être généralisé si U et V sont matrices et est :A u,v det(A+uvT)=(1+vTA−1u)det(A) n×m A n×n det(A+UVT)=det(Im+VTA−1U)det(A)
Pour calculer efficacement l'inverse, vous pouvez utiliser la formule de Sherman-Morrison pour obtenir l'inverse de la matrice suivante à partir de la matrice actuelle:(A+uvT)−1=A−1−A−1uvTA−11+vTA−1u
la source