Actualmente estoy haciendo esto con la biblioteca de armadillo , pero resulta ser demasiado lento. La cuestión es que necesito hacer esto por un billón de matrices y resulta que calcular los dos determinantes es el cuello de botella de mi programa. Por eso tengo dos preguntas
¿Hay algún truco que pueda usar para calcular el determinante más rápido dado que conozco su tamaño? ¿Es quizás una expansión desordenada para matrices que podría funcionar en este caso?
¿Hay alguna otra manera eficiente de probar la igualdad
Editar. Para responder los comentarios. Necesito calcular todos los gráficos G no autocomplementarios conectados de orden , de modo que y tengan el mismo número de árboles de expansión. La motivación para esto se puede encontrar en esta publicación de mathoverflow . En cuanto a la máquina, estoy ejecutando esto en una máquina de 8 núcleos 3.4GHh en paralelo.
Editar. Pude reducir el tiempo de ejecución esperado en un 50% al hacer un programa en C para calcular específicamente el determinante de una matriz de . Las sugerencias son bienvenidas.
fuente
Respuestas:
Como ya está usando C ++ y sus matrices son simétricas positivas definidas, realizaría una factorización dividida de y también de . Aquí supongo que también es positivo definido, de lo contrario, el requerirá pivote para la estabilidad numérica (también es posible que, aunque no sea positivo definido, no sea necesario pivotar, pero debe intentarlo).LDLT Q 12I−Q−J 12I−Q−J LDLT
Esto es más rápido que una factorización LU, y también más rápido que Cholesky porque se evitan las raíces cuadradas. El determinante es simplemente el producto de los elementos de la matriz diagonal . El código para realizar una factorización LDL es tan simple que puede escribirlo en menos de 50 líneas de C. La página de Wikipedia en él describe el algoritmo, y tengo un código simple para hacer Cholesky aquí . Puede simplificarlo enormemente y modificarlo para evitar la raíz cuadrada para implementar la factorizaciónD LDLT
Como también puede controlar el formato de almacenamiento, puede optimizar aún más la rutina para almacenar solo la mitad de la matriz y empaquetarla en una matriz lineal para maximizar la localidad de la memoria. También escribiría rutinas de actualización simples de productos de puntos personalizados y de rango 1, ya que los tamaños de los problemas son tan pequeños que debe dejar que el compilador incorpore las rutinas para reducir la sobrecarga de llamadas. Como se trata de un bucle de tamaño fijo, el compilador debería poder alinear y desenrollar automáticamente las cosas cuando sea apropiado.
intentar jugar trucos para aprovechar el hecho de que contiene dentro de la expresión. Es probable que para problemas de tamaño tan pequeño, estos trucos terminen siendo más lentos que simplemente realizar dos cálculos determinantes por separado. Por supuesto, la única forma de verificar estas afirmaciones es probarlo.12I−Q−J Q
fuente
Sin alguna información sobre la construcción de estas matrices simétricas reales definidas positivas, las sugerencias a realizar son necesariamente limitadas.12×12
Descargué el paquete Armadillo de Sourceforge y eché un vistazo a la documentación. Tratar de mejorar el rendimiento de cómputo separado y , donde es la matriz de rango de todos los, estableciendo por ejemplo . La documentación señala que este es el valor predeterminado para matrices de hasta , por lo que, por omisión, supongo que la opción es predeterminada para el caso .det(Q) det(12I−Q−J) J 4×4 12×12
det(Q,slow=false)
slow=true
Lo queQ 12×12 el determinante se realizará porque el cálculo se "arroja sobre una pared" a LAPACK (o ATLAS) en ese punto sin ninguna indicación de que no se requiere pivotar; ver
slow=true
presumiblemente hace es un giro parcial o total para obtener una forma escalonada de fila, desde la cual se puede encontrar fácilmente el determinante. Sin embargo, sabe de antemano que la matriz es positiva definida, por lo que pivotar es innecesario para la estabilidad (al menos presuntamente para la mayor parte de sus cálculos. No está claro si el paquete Armadillo arroja una excepción si los pivotes se vuelven demasiado pequeños, pero esto debería ser un característica de un paquete razonable de álgebra lineal numérica. EDITAR: Encontré el código Armadillo que se implementa en el archivo de encabezado , usando plantillas C ++ para una funcionalidad sustancial. La configuración no parece afectar cómodet
include\armadillo_bits\auxlib_meat.hpp
slow=false
det_lapack
y sus invocaciones en ese archivo.El otro punto sería seguir su recomendación de construir el paquete Armadillo que se vincule a los reemplazos de alta velocidad para BLAS y LAPACK, si realmente los está utilizando; ver Sec. 5 del archivo README.TXT de Armadillo para más detalles. [El uso de una versión dedicada de 64 bits de BLAS o LAPACK también se recomienda para la velocidad en las máquinas actuales de 64 bits.]
La reducción de filas a la forma escalonada es esencialmente una eliminación gaussiana y tiene una complejidad aritmética . Para ambas matrices, esto equivale al doble de ese trabajo, o . Estas operaciones pueden ser el "cuello de botella" en su procesamiento, pero hay pocas esperanzas de que sin una estructura especial en (o algunas relaciones conocidas entre los billones de casos de prueba que permiten la amortización) el trabajo podría reducirse a .23n3+O(n2) 43n3+O(n2) Q O(n2)
En comparación, la expansión por cofactores de una matriz general involucraoperaciones de multiplicación (y aproximadamente tantas sumas / restas), por lo que para la comparación ( vs. ) favorece claramente la eliminación sobre los cofactores.n×n n! n=12 12!=479001600 23n3=1152
Otro enfoque que requiere sería reducir a la forma tridiagonal con transformaciones de Householder, lo que también pone en forma tridiagonal. La computación y pueden realizarse posteriormente en operaciones . [El efecto de la actualización de rango uno en el segundo determinante puede expresarse como un factor escalar dado al resolver un sistema tridiagonal.]43n3+O(n2) Q 12I−Q det(Q) det(12I−Q−J) O(n) −J
La implementación de un cálculo tan independiente podría valer la pena como una verificación de los resultados de llamadas exitosas (o fallidas) a la
det
función de Armadillo .Caso especial: Como lo sugiere un comentario de Jernej, suponga que donde como antes es la matriz (rango 1) de todos y es un matriz diagonal no singular (positiva). De hecho, para la aplicación propuesta en la teoría de grafos, estas serían matrices enteras. Entonces una fórmula explícita para es:Q=D−J J D=diag(d1,…,dn) det(Q)
Un bosquejo de su prueba brinda la oportunidad de ilustrar una aplicabilidad más amplia, es decir, cuando tiene un determinante conocido y el sistema se resuelve rápidamente. Comience factorizando:D Dv=(1…1)T
Ahora vuelve a ser el rango 1, es decir . Tenga en cuenta que el segundo determinante es simplemente:D−1J (d−11…d−1n)T(1…1)
donde es el polinomio característico de . Como matriz de rango 1, debe tener (al menos) factores de para tener en cuenta su espacio nulo. El valor propio "faltante" es , como se puede ver en el cálculo:f(x) D−1J f(x) n−1 x ∑d−1i
Se deduce que el polinomio característico , es como se muestra arriba para , .f(x)=xn−1(x−∑d−1i) f(1) det(I−D−1J) 1−∑d−1i
También tenga en cuenta que si , entonces , una matriz diagonal cuyo determinante es simplemente el producto de sus entradas diagonales.Q=D−J 12I−Q−J=12I−D+J−J=12I−D
fuente
Si tiene una forma estructurada de enumerar los gráficos de los que desea calcular los determinantes, tal vez podría encontrar actualizaciones de bajo rango que lo transfieran de un gráfico a otro.
Si es así, podría usar el lema determinante de la matriz para calcular de manera económica el determinante del gráfico posterior que se enumerará utilizando su conocimiento del determinante del gráfico actual.
Es decir, para una matriz y los vectores : Esto puede generalizarse si U y V son matrices y es :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)
Para calcular eficientemente el inverso, puede usar la fórmula de Sherman-Morrison para obtener el inverso de la matriz posterior de la actual:(A+uvT)−1=A−1−A−1uvTA−11+vTA−1u
fuente