Saltar al contenido principal
LibreTexts Español

6.2: Autosolucionadores numéricos

  • Page ID
    125062
  • \( \newcommand{\vecs}[1]{\overset { \scriptstyle \rightharpoonup} {\mathbf{#1}} } \)

    \( \newcommand{\vecd}[1]{\overset{-\!-\!\rightharpoonup}{\vphantom{a}\smash {#1}}} \)

    \( \newcommand{\id}{\mathrm{id}}\) \( \newcommand{\Span}{\mathrm{span}}\)

    ( \newcommand{\kernel}{\mathrm{null}\,}\) \( \newcommand{\range}{\mathrm{range}\,}\)

    \( \newcommand{\RealPart}{\mathrm{Re}}\) \( \newcommand{\ImaginaryPart}{\mathrm{Im}}\)

    \( \newcommand{\Argument}{\mathrm{Arg}}\) \( \newcommand{\norm}[1]{\| #1 \|}\)

    \( \newcommand{\inner}[2]{\langle #1, #2 \rangle}\)

    \( \newcommand{\Span}{\mathrm{span}}\)

    \( \newcommand{\id}{\mathrm{id}}\)

    \( \newcommand{\Span}{\mathrm{span}}\)

    \( \newcommand{\kernel}{\mathrm{null}\,}\)

    \( \newcommand{\range}{\mathrm{range}\,}\)

    \( \newcommand{\RealPart}{\mathrm{Re}}\)

    \( \newcommand{\ImaginaryPart}{\mathrm{Im}}\)

    \( \newcommand{\Argument}{\mathrm{Arg}}\)

    \( \newcommand{\norm}[1]{\| #1 \|}\)

    \( \newcommand{\inner}[2]{\langle #1, #2 \rangle}\)

    \( \newcommand{\Span}{\mathrm{span}}\) \( \newcommand{\AA}{\unicode[.8,0]{x212B}}\)

    \( \newcommand{\vectorA}[1]{\vec{#1}}      % arrow\)

    \( \newcommand{\vectorAt}[1]{\vec{\text{#1}}}      % arrow\)

    \( \newcommand{\vectorB}[1]{\overset { \scriptstyle \rightharpoonup} {\mathbf{#1}} } \)

    \( \newcommand{\vectorC}[1]{\textbf{#1}} \)

    \( \newcommand{\vectorD}[1]{\overrightarrow{#1}} \)

    \( \newcommand{\vectorDt}[1]{\overrightarrow{\text{#1}}} \)

    \( \newcommand{\vectE}[1]{\overset{-\!-\!\rightharpoonup}{\vphantom{a}\smash{\mathbf {#1}}}} \)

    \( \newcommand{\vecs}[1]{\overset { \scriptstyle \rightharpoonup} {\mathbf{#1}} } \)

    \( \newcommand{\vecd}[1]{\overset{-\!-\!\rightharpoonup}{\vphantom{a}\smash {#1}}} \)

    Como se discutió anteriormente, la teoría de la imposibilidad de Abel nos dice que no existe una fórmula algebraica general para calcular los valores propios de una\(N\times N\) matriz, para\(N\ge 5\). En la práctica, sin embargo, existen métodos numéricos, llamados autosolvers, que pueden calcular valores propios (y vectores propios) incluso para matrices muy grandes, con cientos de hilas/columnas, o mayores. ¿Cómo podría ser esto?

    La respuesta es que los autosolucionadores numéricos son aproximados, no exactos. Pero aunque sus resultados no son exactos, son muy precisos, pueden acercarse a los valores propios exactos dentro de los límites de precisión fundamentales de la aritmética de punto flotante. Como estamos limitados por esos límites de precisión de punto flotante de todos modos, ¡eso es lo suficientemente bueno!

    6.2.1 Croquis del Método Eigensolver

    No entraremos en detalles sobre cómo funcionan los autosolucionadores numéricos, ya que eso implicaría una digresión bastante larga. Para los interesados, el siguiente trabajo brinda una buena presentación pedagógica de la asignatura:

    • Bruno Lang, Solucionadores Directos para Problemas Simétricos de Autovalor. Métodos y Algoritmos Modernos de Química Cuántica, Proceedings, Segunda Ed. (2000). Enlace de descarga en PDF

    Aquí hay un boceto muy breve del método básico. Similar a la eliminación gaussiana, el algoritmo contiene dos fases, una fase inicial relativamente costo/lenta y una segunda fase relativamente rápida. La primera fase, que se llama Reducción de Householder, aplica un conjunto cuidadosamente elegido de transformaciones de similitud a la matriz de entrada\(\mathbf{A}_0\):

    \[\mathbf{A}_0 \;\rightarrow \;\mathbf{A}_1 = \mathbf{X}_1^{-1} \mathbf{A}_0 \mathbf{X}_1 \;\rightarrow \; \mathbf{A}_2 = \mathbf{X}_2^{-1} \mathbf{A}_1 \mathbf{X}_2, \;\; \mathrm{etc.}\]

    El resultado final es una matriz\(\mathbf{A}_k\) que está en forma de Hessenberg: los elementos debajo de la primera subdiagonal son todos cero (los elementos inmediatamente debajo de la diagonal principal, es decir, a lo largo de la primera subdiagonal, pueden ser distintos de cero). Toda la fase de reducción de Householder requiere operaciones\(O(N^{3})\) aritméticas, donde\(N\) está el tamaño de la matriz.

    La segunda fase del algoritmo se llama iteración QR. Usando un tipo diferente de transformación de similitud, los elementos a lo largo de la subdiagonal de la matriz de Hessenberg se reducen en magnitud. Cuando estos elementos se vuelven insignificantes, la matriz se vuelve triangular superior; en ese caso, los valores propios son simplemente los elementos a lo largo de la diagonal.

    El proceso QR es iterativo, ya que reduce progresivamente la magnitud de los elementos de la matriz a lo largo de la subdiagonal. Formalmente, se requeriría un número infinito de iteraciones para reducir estos elementos a cero, ¡por eso no se viola el teorema de la imposibilidad de Abel! En la práctica, sin embargo, la iteración QR converge de manera extremadamente rápida, por lo que esta fase acaba tomando solo\(O(N^{2})\) tiempo.

    De ahí que el tiempo de ejecución general para encontrar los valores propios de una matriz se escala como\(O(N^{3})\). Los vectores propios también se pueden calcular como un efecto secundario del algoritmo, sin un aumento adicional en el escalado de tiempo de ejecución.

    6.2.2 Implementación de Python

    Hay cuatro autosolvers numéricos principales implementados en Scipy, que se encuentran todos en el paquete scipy.linalg:

    La razón para tener cuatro funciones separadas es la eficiencia. Los tiempos de ejecución de las cuatro funciones escalan como\(O(N^{3})\), pero para cada uno\(N\) los tiempos de ejecución reales de eigvalsh y eigvalsh serán más cortos que eig y eigh, porque solo se le pide al solucionador propio que encuentre los valores propios y no es necesario construir los vectores propios. Además, eigvalsh es más rápido que eigvals, y eigh es más rápido que eig, porque el algoritmo eigensolver puede hacer uso de ciertos atajos numéricos que son válidos solo para matrices hermitianas.

    Si pasas eigvalsh o eigh una matriz que en realidad no es hermitiana, los resultados son impredecibles; la función puede devolver un valor incorrecto sin señalar ningún error. Por lo tanto, solo debes usar estas funciones si estás seguro de que la matriz de entrada es definitivamente hermitiana (lo cual suele ser porque construiste la matriz de esa manera); si el mtrix es hermitiano, eigvalsh o eigh son ciertamente preferibles de usar, porque corren más rápido que sus Contrapartes no hermitianas.

    Aquí hay un programa corto que usa eigvals para encontrar los valores propios de una\(3\times 3\) matriz:

    from scipy import *
    import scipy.linalg as lin
    
    A = array([[1,3,1],[1, 3, 4],[2, 4, 2]])
    lambd = lin.eigvals(A)
    
    print(lambd)
    

    Ejecución de los resultados del programa:

    [ 7.45031849+0.j         -0.72515925+0.52865751j -0.72515925-0.52865751j]
    

    El valor de retorno de eigvals es una matriz 1D de números complejos, que almacena los valores propios de la entrada. La función eigvalsh se comporta de manera similar, excepto que se devuelve una matriz real (ya que las matrices hermitianas tienen valores propios reales). Nota: no podemos usar lambda como nombre de una variable, porque lambda está reservada como una palabra clave especial en Python.

    Aquí hay un ejemplo de uso de eig:

    >>> A = array([[1,3,1],[1, 3, 4],[2, 4, 2]])
    >>> lambd, Q = lin.eig(A)
    >>> lambd
    array([ 7.45031849+0.j    , -0.72515925+0.52865751j,   -0.72515925-0.52865751j])
    >>> Q
    array([[ 0.40501343+0.j        ,  0.73795979+0.j        ,  0.73795979-0.j        ],
           [ 0.65985810+0.j        , -0.51208724+0.22130102j, -0.51208724-0.22130102j],
           [ 0.63289132+0.j        ,  0.26316357-0.27377508j,  0.26316357+0.27377508j]])
    

    La función eig devuelve un par de valores; la primera es una matriz 1D de valores propios (que nombramos lambd en el ejemplo anterior), y la segunda es una matriz 2D que contiene los vectores propios correspondientes en cada columna (que nombramos Q). Por ejemplo, se puede acceder al primer vector propio con Q [:,0]. Podemos verificar que esto es de hecho un vector propio:

    >>> dot(A, Q[:,0])
    array([ 3.01747903+0.j,  4.91615298+0.j,  4.71524187+0.j])
    >>> lambd[0] * Q[:,0]
    array([ 3.01747903+0.j,  4.91615298+0.j,  4.71524187+0.j])
    

    La función eigh se comporta de manera similar, excepto que la matriz 1D de valores propios es real.

    6.2.3 Problema Generalizado de Autovalor

    A veces, también puede encontrarse con problemas generalizados de valores propios, que tienen la forma

    \[\mathbf{A}\, \vec{x} = \lambda\, \mathbf{B}\, \vec{x},\]

    para matrices cuadradas de igual tamaño conocidas\(\mathbf{A}\) y\(\mathbf{B}\). Llamamos\(\lambda\) un “autovalor generalizado”, y\(\vec{x}\) un “autovector generalizado”, para el par de matrices\((\mathbf{A},\mathbf{B})\). El problema del valor propio generalizado se reduce al problema del valor propio ordinario cuando\(\mathbf{B}\) es la matriz de identidad.

    La manera ingenua de resolver el problema del valor propio generalizado sería calcular la inversa de\(\mathbf{B}^{-1}\), y luego resolver el problema del valor propio para\(\mathbf{B}^{-1}\mathbf{A}\). Sin embargo, resulta que el problema del valor propio generalizado puede resolverse directamente con solo ligeras modificaciones al algoritmo habitual de autosolucionador numérico. De hecho, los autosolvers de Scipy descritos en la sección anterior resolverán el problema de autovalores generalizados si pasa una matriz 2D\(\mathbf{B}\) como segunda entrada (si se omite esa segunda entrada, los autosolvers resuelven el problema de autovalores ordinarios, como se describió anteriormente).

    Aquí hay un programa de ejemplo para resolver un problema de autovalor generalizado:

    from scipy import *
    import scipy.linalg as lin
    
    A = array([[1,3,1],[1, 3, 4],[2, 4, 2]])
    B = array([[0,2,1], [0, 1, 1], [2, 0, 1]])
    
    lambd, Q = lin.eig(A, B)
    
    ## Verify the solution for first generalized eigenvector:
    lhs = dot(A,Q[:,0])             # A . x
    rhs = lambd[0] * dot(B, Q[:,0]) # lambda B . x
    
    print(lhs)
    print(rhs)
    

    Ejecutando las impresiones del programa anterior:

    [-0.16078694+0.j -0.07726949+0.j  0.42268561+0.j]
    [-0.16078694+0.j -0.07726949+0.j  0.42268561+0.j]
    

    Los autosolvers hermitianos, eigh y eigvalsh, se pueden utilizar para resolver el problema del autovalor generalizado solo si tanto las matrices como\(\mathbf{A}\) las\(\mathbf{B}\) matrices son hermitianas.


    This page titled 6.2: Autosolucionadores numéricos is shared under a CC BY-SA 4.0 license and was authored, remixed, and/or curated by Y. D. Chong via source content that was edited to the style and standards of the LibreTexts platform; a detailed edit history is available upon request.