Complejidad de la inversión de la matriz en numpy

11

Estoy resolviendo ecuaciones diferenciales que requieren invertir matrices cuadradas densas. Esta inversión matricial consume la mayor parte de mi tiempo de cálculo, por lo que me preguntaba si estoy usando el algoritmo más rápido disponible.

Mi elección actual es numpy.linalg.inv . De mis números veo que se escala como donde n es el número de filas, por lo que el método parece ser la eliminación gaussiana.O(n3)

Según Wikipedia , hay algoritmos más rápidos disponibles. ¿Alguien sabe si hay una biblioteca que implemente estos?

Me pregunto, ¿por qué no es molesto usar estos algoritmos más rápidos?

físicaGuy
fuente
Necesitas realizar tus matrices antes. Mira a Scipy. Escaso por su ayuda. Contiene muchas herramientas que necesitas.
Tobal
@Tobal no estoy seguro de seguir ... ¿cómo "realizarías" una matriz? y exactamente cómo scipy.sparseayudaría?
GoHokies
@GoHokies scipy es un complemento de numpy. Las matrices densas / dispersas deben implementarse mucho antes de realizar algunos cálculos, esto mejora sus cálculos. Lea este documento docs.scipy.org/doc/scipy/reference/sparse.html que explica mejor que yo con mi mal inglés.
Tobal
@Tobal La pregunta se refiere específicamente a matrices densas , así que no veo cómo scipy.sparsees relevante aquí.
Christian Clason
2
@Tobal - Creo que todavía no entiendo. ¿Qué quiere decir exactamente con "preformar sus matrices" y "las matrices deben implementarse mucho antes de hacer algunos cálculos"? Con respecto a su último comentario, seguramente estará de acuerdo en que las técnicas que pueden usarse para matrices dispersas y densas son muy diferentes.
Wolfgang Bangerth

Respuestas:

20

(Esto se está haciendo demasiado largo para comentarios ...)

Asumiré que realmente necesitas calcular un inverso en tu algoritmo. 1 Primero, es importante tener en cuenta que estos algoritmos alternativos en realidad no se afirman que sean más rápidos , solo que tienen una mejor complejidad asintótica (lo que significa que el número requerido de operaciones elementales crece más lentamente). De hecho, en la práctica, estos son en realidad (mucho) más lentos que el enfoque estándar (para un dado ), por las siguientes razones:n

  1. La notación oculta una constante frente a la potencia de , que puede ser astronómicamente grande, tan grande que puede ser mucho más pequeña que para cualquier que puede ser manejado por cualquier computadora en el futuro previsible. (Este es el caso del algoritmo Coppersmith – Winograd, por ejemplo).OnC1n3C2n2.xn

  2. La complejidad supone que cada operación (aritmética) lleva el mismo tiempo, pero esto está lejos de ser cierto en la práctica real: multiplicar un grupo de números con el mismo número es mucho más rápido que multiplicar la misma cantidad de números diferentes . Esto se debe al hecho de que el cuello de botella principal en la informática actual es llevar los datos a la memoria caché, no las operaciones aritméticas reales sobre esos datos. Por lo tanto, un algoritmo que se puede reorganizar para tener la primera situación (llamado reconocimiento de caché ) será mucho más rápido que uno donde esto no sea posible. (Este es el caso del algoritmo de Strassen, por ejemplo).

Además, la estabilidad numérica es al menos tan importante como el rendimiento; y aquí, nuevamente, el enfoque estándar generalmente gana.

Por esta razón, las bibliotecas estándar de alto rendimiento (BLAS / LAPACK, que Numpy llama cuando le pide que calcule un inverso) generalmente solo implementan este enfoque. Por supuesto, hay implementaciones de Numpy de, por ejemplo, el algoritmo de Strassen, pero un algoritmo ajustado a mano en el nivel de ensamblaje superará a un algoritmo escrito en un lenguaje de alto nivel para cualquier tamaño de matriz razonable.O(n3)O(n2.x)


1 Pero me equivocaría si no señalara que esto rara vez es realmente necesario: cada vez que necesite calcular un producto , debería resolver el sistema lineal (p. Ej., usando ) y use lugar: esto es mucho más estable y se puede hacer (dependiendo de la estructura de la matriz ) mucho más rápido. Si necesita usar varias veces, puede calcular previamente una factorización de (que generalmente es la parte más costosa de la solución) y reutilizarla más tarde.A1bAx=bnumpy.linalg.solvexAA1A

Christian Clason
fuente
Gran respuesta, gracias señor, en particular por señalar al diablo en los detalles (constantes en notación O grande) que hace una gran diferencia entre la velocidad teórica y la velocidad práctica.
Gaborous
Creo que la parte de "lo inverso rara vez es necesario" debería enfatizarse más. Si el propósito es resolver un sistema de ecuaciones diferenciales, no parece probable que se necesite un inverso completo.
Jared Goguen
@o_o Bueno, ese fue mi primer comentario original (que eliminé después de consolidarlos en una sola respuesta). Pero pensé que, en beneficio del sitio (y de los lectores posteriores), una respuesta debería responder a la pregunta real en la pregunta (que es razonable y sobre el tema), incluso si hay un problema XY detrás. Además, no quería sonar demasiado amonestador ...
Christian Clason
1
Como escribí, en casi todos los casos puede reescribir su algoritmo para reemplazar las operaciones que involucran el inverso con la resolución del sistema lineal correspondiente (o en este caso, la secuencia de sistemas lineales); si está interesado, puede hacer una pregunta por separado sobre eso ("¿puedo evitar invertir matrices en este algoritmo?"). Y sí, dado que el número de matrices no depende de , la complejidad sigue siendo la misma (solo obtienes una constante más grande, por un factor de cuatro en tu caso). n
Christian Clason
1
@Heisenberg: depende de la estructura de - LU, Cholesky o incluso de los trabajos de descomposición QR. El punto (que se hace en cualquier texto sobre álgebra lineal numérica) es que aplicar la descomposición es barato en comparación con calcularlo, por lo que debe hacer esto último solo una vez y luego aplicarlo muchas veces. A
Christian Clason
4

Probablemente debería tener en cuenta que, enterrado en el interior del código fuente numpy (consulte https://github.com/numpy/numpy/blob/master/numpy/linalg/umath_linalg.c.src ) la rutina inv intenta llamar a la función dgetrf del paquete LAPACK de su sistema, que luego realiza una descomposición LU de su matriz original. Esto es moralmente equivalente a la eliminación gaussiana, pero puede ajustarse a una complejidad ligeramente inferior mediante el uso de algoritmos de multiplicación de matriz más rápidos en un BLAS de alto rendimiento.

Si sigue esta ruta, se le debe advertir que obligar a toda la cadena de bibliotecas a usar la nueva biblioteca en lugar del sistema que viene con su distribución es bastante complejo. Una alternativa en los sistemas informáticos modernos es buscar métodos paralelos utilizando paquetes como scaLAPACK o (en el mundo de Python) petsc4py. Sin embargo, estos suelen ser más felices de ser utilizados como solucionadores iterativos para sistemas de álgebra lineal que los aplicados a métodos directos y PETSc en objetivos particulares sistemas dispersos más que sistemas densos.

origimbo
fuente