Etiqueta: algoritmo Python

  • 3.5 Normas de vector o matriz como distancias con Python

    [ norma 3D ] [ acople aeronave ] [ algoritmo ]

    ..


    Normas de un vector en 3D

    Referencia: Chapra 10.3.1 p298, Burden 7.1 p320, Rodríguez 4.4.1 p132

    La norma de un vector se interpreta como una distancia entre la coordenada definida por el vector [xi, yi, zi] y el origen [0,0,0]. También se puede realizar respecto a otro punto de referencia, se conoce como Norma Euclidiana o Norma p=2.

    Previamente, en búsqueda de raíces, el error de aproximación se considera como la diferencia entre dos iteraciones sucesivas:.puntos en el espacio

    error = |x_{i+1} - x_{i}|

    Si el concepto se extiende a vectores en tres dimensiones, se observa como el error entre vectores |Xi+1 - Xi| que se interpreta mejor como una distancia.

    Por ejemplo, si se usan los puntos y se visualizan en un gráfico:

        X2:  [ 2  4 -1]
       -X1: -[ 1  2  3]
    ______________________
    errado =|[ 1  2 -4]|
    

    La diferencia entre los vectores |[ 1, 2, -4]|  es más simple de observar como un número escalar. Una forma de convertir el punto a un escalar es usar la distancia al origen.

    errado = \sqrt{1^2 + 2^2 + (-4)^2} = 4.58

    error distancia 02El resultado también se interpreta como la distancia entre los puntos X1 y X2.

    De ampliar el concepto a n dimensiones se conoce como norma de un vector o matriz.

    ||x|| = \sqrt{x^2+y^2+z^2} ||x|| = \Big[ \sum_{i=0}^{n} x_i ^2 \Big] ^{1/2}

    [ norma 3D ] [ acople aeronave ] [ algoritmo ]
    ..


    2. Distancia entre dos puntos en el espacio, error y Norma

    Observe los siguientes videos, sobre acople de aeronaves.

    Acoplamiento de aviones para recarga de combustible . www.AiirSource.com. 30/diciembre/2015. llenar combustible en vuelo
    KC-135 Stratotanker in Action - Aircraft Air Refueling

    El carguero ruso Progress M-06M pasó de largo la Estación Espacial Internacional fracasado en su intento de acoplarse

    Soyuz MS-22 docking. 21 sept 2022.

    • ¿Considera importante que exista acoplamiento para iniciar la carga el combustible? o ¿para abrir la escotilla del transbordador?

    Si el error de acoplamiento entre artefactos se calcula como la Norma entre los puntos de "contacto",

    • ¿es necesario calcular la raíz cuadrada de los cuadrados de las diferencias? o,
    • ¿Solo toma en cuenta el mínimo o el máximo de las diferencias entre las coordenadas?,
    • ¿cuál de las formas tiene menos operaciones, es más rápida de realizar?

    considere sus respuestas para el siguiente concepto.

    [ norma 3D ] [ acople aeronave ] [ algoritmo ]


    3. Norma infinito

    Se determina como el valor mas grande entre los elementos del vector o matriz.

    ||x|| = max\Big[ |x_i| \Big]

    Es más sencilla de calcular que la Norma Euclidiana, Norma P=2, mostrada al principio.

    Se interpreta como si alguna de las diferencia entre las coordenadas de los puntos de acople entre aeronaves es mayor que lo tolerado, no se debe permitir abrir la válvula de combustible o la escotilla del transbordador. No es prioritario calcular la suma de los cuadrados de las diferencias para saber que no existe acople aún.

    Existen otras formas de calcular la Norma, que se presentan en la siguiente página web.

    [ norma 3D ] [ acople aeronave ] [ algoritmo ]

    ..


    4. Algoritmo con Python

    Principalmente se usa para generar las gráficas 3D, que ayudan a la interpretación del concepto con los puntos de coordenadas:

    X0 = np.array([0.0, 0, 0])
    X1 = np.array([1.0, 2, 3])
    X2 = np.array([2.0, 4,-1])
    

    Las instrucciones gráficas principales son:

    El resultado de la parte numérica se obtiene con pocas instrucciones en el bloque de procedimiento

         X2:  [ 2 4 -1]
        -X1: -[ 1 2  3]
    
    ____________________
    errado =  [ 1 2 -4]
    ||errado|| =  4.58257569495584
    Norma euclidiana :  4.58257569495584
    

    las instrucciones en Python son:

    # Norma como error
    # o distancia entre dos puntos
    # caso 3D
    import numpy as np
    
    # INGRESO
    X0 = np.array([0.0, 0, 0])
    X1 = np.array([1.0, 2, 3])
    X2 = np.array([2.0, 4,-1])
    
    # PROCEDIMIENTO
    errado = X2 - X1
    distancia = np.sqrt(np.sum(errado**2))
    # funciones numpy
    Nerrado = np.linalg.norm(errado)
    
    # SALIDA
    print('X1 = ', X1)
    print('X2 = ', X2)
    print('errado = ', errado)
    print('||errado|| = ', distancia)
    print('Norma euclidiana : ',Nerrado)
    
    
    # Grafica
    import matplotlib.pyplot as plt
    from mpl_toolkits.mplot3d import Axes3D
    figura  = plt.figure()
    grafica = figura.add_subplot(111,projection = '3d')
    
    # puntos en el espacio
    [x, y , z] = X0
    grafica.scatter(x,y,z, c = 'blue',
                    marker='o', label = 'X0')
    
    [x, y , z] = X1
    grafica.scatter(x,y,z, c = 'red',
                    marker='o', label = 'X1')
    
    [x, y , z] = X2
    grafica.scatter(x,y,z, c = 'green',
                    marker='o', label = 'X2')
    
    # líneas entre puntos
    linea = np.concatenate(([X0],[X1]),axis = 0)
    x = linea[:,0]
    y = linea[:,1]
    z = linea[:,2]
    grafica.plot(x,y,z, label = '||X1||')
    
    linea = np.concatenate(([X0],[X2]),axis = 0)
    x = linea[:,0]
    y = linea[:,1]
    z = linea[:,2]
    grafica.plot(x,y,z, label = '||X2||')
    
    linea = np.concatenate(([X1],[X2]),axis = 0)
    x = linea[:,0]
    y = linea[:,1]
    z = linea[:,2]
    grafica.plot(x,y,z, label = '||error||')
    
    grafica.set_xlabel('eje x')
    grafica.set_ylabel('eje y')
    grafica.set_zlabel('eje z')
    grafica.legend()
    
    grafica.view_init(35, 25)
    plt.show()
    

    [ norma 3D ] [ acople aeronave ] [ algoritmo ]

  • 3.4 Método de Gauss-Jordan con Python

    [ Gauss-Jordan ] [ Ejercicio ] [ Eliminación atrás ] [ Algoritmo ] [ función ]
    ..


    1. Método de Gauss-Jordan

    Referencia: Chapra 9.7 p277, Burden 9Ed Ex6.1.12 p370, Rodríguez 4.2 p106

    El método de Gauss-Jordan presenta un procedimiento alterno al de "sustitución hacia atrás" realizado para el método de Gauss. Luego de obtener la "matriz triangular superior", aplica el procedimiento de "Eliminación hacia atrás".

    \left( \begin{array}{rrr|r} a_{0,0} & a_{0,1} & a_{0,2} & b_{0} \\ 0 & a_{1,1} & a_{1,2} & b_{1} \\ 0 & 0 & a_{2,2} & b_{2} \end{array} \right)
    • Eliminación hacia atrás

    Eliminación hacia atras grafico animadoDesde la última fila,
    para i = n-1, n-2, ...
    sobre las filas k = i-1 superiores

    a_{k} = a_{k} -a_{i}\frac{a_{ki}}{a_{ii}}

    Se mantienen al inicio los procedimientos para:
    matriz aumentada,
    pivoteo parcial por filas,
    eliminación hacia adelante desarrollados anteriormente.

    [ Gauss-Jordan ] [ Ejercicio ] [ Eliminación atrás ] [ Algoritmo ] [ función ]
    ..


    2. Ejercicio

    Referencia: Rodríguez 4.0 p105,  1Eva_IT2010_T3_MN Precio artículos

    \begin{cases} 4x_1+2x_2+5x_3 = 60.70 \\ 2x_1+5x_2+8x_3 = 92.90 \\ 5x_1+4x_2+3x_3 = 56.30 \end{cases}

    Matriz Diagonal superiorSe continúa con el ejercicio desarrollado para el método de Gauss desde la "matriz triangular superior",
    luego de eliminación hacia adelante:

    [[ 5.    4.    3.   56.3 ]
     [ 0.    3.4   6.8  70.38]
     [ 0.    0.    5.   40.5 ]]

    [ Gauss-Jordan ] [ Ejercicio ] [ Eliminación atrás ] [ Algoritmo ] [ función ]
    ..


    3. Eliminación hacia atrás

    El procedimiento es semejante al realizado para "eliminación hacia adelante", con la diferencia que se inicia en la última fila hacia la primera. Para el ejercicio presentado se tiene que:

    utlfila = n-1 = 3-1 = 2
    ultcolumna = m-1 = 4-1 = 3

    iteración 1, operación fila 3 y 2

    Se aplica desde la última fila i, para las otras filas k que se encuentran hacia atrás.Eliminación hacia Atras i=2,j=1

    i = ultfila = 2
    pivote = AB[2,2] = 5
    k = i-1 # hacia atrás

    se realizan las operaciones entre las filas i y la fila j

             [0.  3.4  6.8    70.38]
    -(6.8/5)*[0.  0.   5.     40.5 ]
    _______________________________
           = [0.0 3.4  8.8e-16 15.3]
    

    para reemplazar los valores de la segunda fila en la matriz aumentada

    [[5.0    4.0    3.0      56.3]
     [0.0    3.4    8.8e-16  15.3]
     [0.0    0.0    5.0      40.5]]

    Observe que hay un valor muy pequeño del orden de 8.8x10-16, que para las otras magnitudes se puede considerar como casi cero.

    iteración 2, operación fila 3 y 1

    Se calculan los nuevos valores de índice kEliminacion hacia Atras i=2, j=0

    k = k-1 = 2-1 = 1 # hacia atrás

    se realizan las operaciones entre las filas i y la fila j

           [5.0    4.0    3.0    56.3]
    -(3/5)*[0.0    0.0    5.0    40.5]
    __________________________________
         = [5.0    4.0    0.0    32.0]

    que al actualizar la matriz aumentada se tiene:

    [[5.0    4.0    0.0      32.0]
     [0.0    3.4    8.8e-16  15.3]
     [0.0    0.0    5.0      40.5]]}
    

    Al haber terminado las filas hacia arriba, Eliminacion hacia Atras i=2,j2, pivote=1
    se puede así determinar el valor de x3 al dividir la fila 3 para el pivote

    [[5.0    4.0    0.0      32.0]
     [0.0    3.4    8.8e-16  15.3]
     [0.0    0.0    1.0       8.1]]}
    

    iteración 3, operación fila 2 y 1Eliminación hacia Atras i=1,j=0

    se actualizan los valores de los índices:

    i = i-1 = 2-1 = 1
    k = i-1 = 1-1 = 0

    se pueden realizar operaciones en una sola fila hacia atrás, por lo que el resultado hasta ahora es:

             [5.0    4.0    0.0     32.0]
    -(4/3.4)*[0.0    3.4    8.8e-16 15.3]
    __________________________________
           = [5.0    0.0   -1.04e-15 14.0]
    
    [[ 5.0    0.0   -1.04e-15  14.0]
     [ 0.0    3.4    8.8e-16   15.3]
     [ 0.0    0.0    1.0        8.1]]
    

    Eliminacion hacia Atras i=1,j=1, pivote=1

    Se obtiene el valor de x2,
    dividiendo para el valor del pivote,

    [[ 5.0    0.0   -1.04e-15  14.0]
     [ 0.0    1.0    2.6e-16    4.5]
     [ 0.0    0.0    1.0        8.1]]

    iteración 4, operación fila 1Eliminación hacia atras, pivote=1

    No hay otras filas con las que iterar,
    por lo que solo se obtiene el valor de x1 al dividir para el pivote.

    [[ 1.0    0.0   -2.08e-15  2.8]
     [ 0.0    1.0    2.6e-16   4.5]
     [ 0.0    0.0    1.0       8.1]]

    La solución del sistema de ecuaciones se presenta como una matriz identidad concatenada a un vector columna de constantes.

    solución X: 
    [2.8, 4.5, 8.1]
    X= [2.8, 4.5 , 8.1 ]

    Observación: en la matriz hay unos valores del orden de 10-16, que corresponden a errores de operaciones en computadora (truncamiento y redondeo) que pueden ser descartados por ser casi cero. Hay que establecer entonces un parámetro para controlar los casos en que la diferencia entre los ordenes de magnitud son por ejemplo menores a 15 ordenes de magnitud 10-15. e implementarlo en los algoritmos.

    [ Gauss-Jordan ] [ Ejercicio ] [ Eliminación atrás ] [ Algoritmo ] [ función ]
    ..


    4. Algoritmo en Python

    Esta sección reutiliza el algoritmo desarrollado para el Método de Gauss, por lo que los bloques de procedimiento son semejantes hasta eliminación hacia adelante. Se añade el procedimiento de eliminación hacia atrás para completar la solución al sistema de ecuaciones.

    Instrucciones en Python

    # Método de Gauss-Jordan
    # Sistemas de Ecuaciones A.X=B
    import numpy as np
    
    # INGRESO
    A = [[4,2,5],
         [2,5,8],
         [5,4,3]]
    B = [60.70, 92.90, 56.30]
    
    # PROCEDIMIENTO
    np.set_printoptions(precision=4) # 4 decimales en print
    casicero = 1e-15  # redondear a cero
    # Matrices como arreglo, numeros reales
    A = np.array(A,dtype=float)
    B = np.array(B,dtype=float)
    
    # Matriz aumentada AB
    B_columna = np.transpose([B])
    AB  = np.concatenate((A,B_columna),axis=1)
    
    # Pivoteo parcial por filas
    tamano = np.shape(AB)
    n = tamano[0]
    m = tamano[1]
    
    # Para cada fila en AB
    for i in range(0,n-1,1):
        # columna desde diagonal i en adelante
        columna = abs(AB[i:,i])
        dondemax = np.argmax(columna)
        
        if (dondemax !=0): # NO en diagonal
            # intercambia filas
            temporal = np.copy(AB[i,:])
            AB[i,:]  = AB[dondemax+i,:]
            AB[dondemax+i,:] = temporal
    print('Pivoteo parcial por filas AB: ----')
    print(AB)
    
    # Eliminación hacia adelante
    print('Eliminación hacia adelante: ------')
    for i in range(0,n-1,1): # una fila
        pivote   = AB[i,i]
        adelante = i + 1
        for k in range(adelante,n,1): # diagonal adelante
            factor  = AB[k,i]/pivote
            AB[k,:] = AB[k,:] - AB[i,:]*factor
    
            print('i:',i,'k:',k, 'factor:',factor)
        print(AB)
    
    # Eliminación hacia atras
    print('Eliminación hacia atras: ------')
    ultfila = n-1
    ultcolumna = m-1
    for i in range(ultfila,0-1,-1): # una fila
        pivote   = AB[i,i]
        print('i:',i,' pivote:',pivote)
        
        atras = i - 1
        for k in range(atras,0-1,-1): # diagonal adelante
            factor  = AB[k,i]/pivote
            AB[k,:] = AB[k,:] - AB[i,:]*factor
            for j in range(0,m,1): # casicero revisa
                if abs(AB[k,j])<casicero:
                    AB[k,j]=0
            
            print(' k:',k, 'factor:',factor)
        print(AB)
        
        AB[i,:] = AB[i,:]/AB[i,i] # diagonal a unos
        
    print('AB:')
    print(AB)
    X = np.copy(AB[:,ultcolumna])
    
    # SALIDA
    print('Método de Gauss-Jordan')
    print('solución X: ')
    print(X)
    

    El resultado del algoritmo es:

    Pivoteo parcial por filas AB: ----
    [[ 5.   4.   3.  56.3]
     [ 2.   5.   8.  92.9]
     [ 4.   2.   5.  60.7]]
    Eliminación hacia adelante: ------
    i: 0 k: 1 factor: 0.4
    i: 0 k: 2 factor: 0.8
    [[ 5.    4.    3.   56.3 ]
     [ 0.    3.4   6.8  70.38]
     [ 0.   -1.2   2.6  15.66]]
    i: 1 k: 2 factor: -0.3529411764705883
    [[ 5.    4.    3.   56.3 ]
     [ 0.    3.4   6.8  70.38]
     [ 0.    0.    5.   40.5 ]]
    Eliminación hacia atras: ------
    i: 2  pivote: 5.0
     k: 1 factor: 1.3599999999999999
     k: 0 factor: 0.6
    [[ 5.   4.   0.  32. ]
     [ 0.   3.4  0.  15.3]
     [ 0.   0.   5.  40.5]]
    i: 1  pivote: 3.4
     k: 0 factor: 1.1764705882352942
    [[ 5.   0.   0.  14. ]
     [ 0.   3.4  0.  15.3]
     [ 0.   0.   1.   8.1]]
    i: 0  pivote: 5.0
    [[ 5.   0.   0.  14. ]
     [ 0.   1.   0.   4.5]
     [ 0.   0.   1.   8.1]]
    AB:
    [[1.  0.  0.  2.8]
     [0.  1.  0.  4.5]
     [0.  0.  1.  8.1]]
    Método de Gauss-Jordan
    solución X: 
    [2.8 4.5 8.1]

    [ Gauss-Jordan ] [ Ejercicio ] [ Eliminación atrás ] [ Algoritmo ] [ función ]
    ..


    5. Algoritmo como función en Python

    El algoritmo considera que valores con magnitud menores a "casicero" se redondean a 0. Se aplica recorriendo la fila de referencia k, por cada elemento j.

    # redondeo a cero
    for j in range(0,m,1): 
        if np.abs(AB[k,j])<=casicero:
            AB[k,j]=0
    

    Adicionalmente se añade el parámetro "inversa", que se usa para encontrar A-1 como se indica en Matriz Inversa.

    Con el algoritmo se obtiene el siguiente resultado:

    Matriz aumentada
    [[ 4.   2.   5.  60.7]
     [ 2.   5.   8.  92.9]
     [ 5.   4.   3.  56.3]]
    Pivoteo parcial:
      1 intercambiar filas:  0 y 2
    [[ 5.   4.   3.  56.3]
     [ 2.   5.   8.  92.9]
     [ 4.   2.   5.  60.7]]
    Elimina hacia adelante:
     fila i: 0  pivote: 5.0
      fila k: 1  factor: 0.4
      fila k: 2  factor: 0.8
    [[ 5.    4.    3.   56.3 ]
     [ 0.    3.4   6.8  70.38]
     [ 0.   -1.2   2.6  15.66]]
     fila i: 1  pivote: 3.4
      fila k: 2  factor: -0.3529411764705883
    [[ 5.    4.    3.   56.3 ]
     [ 0.    3.4   6.8  70.38]
     [ 0.    0.    5.   40.5 ]]
     fila i: 2  pivote: 5.0
    [[ 5.    4.    3.   56.3 ]
     [ 0.    3.4   6.8  70.38]
     [ 0.    0.    5.   40.5 ]]
    Elimina hacia Atrás:
     fila i: 2  pivote: 5.0
      fila k: 1  factor: 1.3599999999999999
      fila k: 0  factor: 0.6
    [[ 5.   4.   0.  32. ]
     [ 0.   3.4  0.  15.3]
     [ 0.   0.   1.   8.1]]
     fila i: 1  pivote: 3.4
      fila k: 0  factor: 1.1764705882352942
    [[ 5.   0.   0.  14. ]
     [ 0.   1.   0.   4.5]
     [ 0.   0.   1.   8.1]]
     fila i: 0  pivote: 5.0
    [[1.  0.  0.  2.8]
     [0.  1.  0.  4.5]
     [0.  0.  1.  8.1]]
    solución X: 
    [2.8 4.5 8.1]

    Instrucciones en Python

    # Método de Gauss-Jordan
    # Sistemas de Ecuaciones A.X=B
    import numpy as np
    
    def gauss_eliminaAtras(AB, vertabla=False,
                           inversa=False,
                           casicero = 1e-15):
        ''' Gauss-Jordan elimina hacia atrás
        Requiere la matriz triangular inferior
        Tarea: Verificar que sea triangular inferior
        '''
        tamano = np.shape(AB)
        n = tamano[0]
        m = tamano[1]
        
        ultfila = n-1
        ultcolumna = m-1
        if vertabla==True:
            print('Elimina hacia Atrás:')
            
        for i in range(ultfila,0-1,-1):
            pivote = AB[i,i]
            atras = i-1  # arriba de la fila i
            if vertabla==True:
                print(' fila i:',i,' pivote:', pivote)
                
            for k in range(atras,0-1,-1):
                if np.abs(AB[k,i])>=casicero:
                    factor = AB[k,i]/pivote
                    AB[k,:] = AB[k,:] - factor*AB[i,:]
                    
                    # redondeo a cero
                    for j in range(0,m,1): 
                        if np.abs(AB[k,j])<=casicero:
                            AB[k,j]=0
                    if vertabla==True:
                        print('  fila k:',k,
                              ' factor:',factor)
                else:
                    print('  pivote:', pivote,'en fila:',i,
                          'genera division para cero')
            AB[i,:] = AB[i,:]/AB[i,i] # diagonal a unos
            
            if vertabla==True:
                print(AB)
        
        respuesta = np.copy(AB[:,ultcolumna])
        if inversa==True: # matriz inversa
            respuesta = np.copy(AB[:,n:])
        return(respuesta)
    
    def gauss_eliminaAdelante(AB,vertabla=False,
                              lu=False,casicero = 1e-15):
        ''' Gauss elimina hacia adelante
        tarea: verificar términos cero
        '''
        tamano = np.shape(AB)
        n = tamano[0]
        m = tamano[1]
        if vertabla==True:
            print('Elimina hacia adelante:')
        for i in range(0,n,1):
            pivote = AB[i,i]
            adelante = i+1
            if vertabla==True:
                print(' fila i:',i,' pivote:', pivote)
            for k in range(adelante,n,1):
                if (np.abs(pivote)>=casicero):
                    factor = AB[k,i]/pivote
                    AB[k,:] = AB[k,:] - factor*AB[i,:]
                    for j in range(0,m,1): # casicero revisa
                        if abs(AB[k,j])<casicero:
                            AB[k,j]=0
                    if vertabla==True:
                        print('  fila k:',k,
                              ' factor:',factor)
                else:
                    print('  pivote:', pivote,'en fila:',i,
                          'genera division para cero')
            if vertabla==True:
                print(AB)
        respuesta = np.copy(AB)
        if lu==True: # matriz triangular A=L.U
            U = AB[:,:n-1]
            respuesta = [AB,L,U]
        return(respuesta)
    
    def pivoteafila(A,B,vertabla=False):
        '''
        Pivotea parcial por filas
        Si hay ceros en diagonal es matriz singular,
        Tarea: Revisar si diagonal tiene ceros
        '''
        A = np.array(A,dtype=float)
        B = np.array(B,dtype=float)
        # Matriz aumentada
        nB = len(np.shape(B))
        if nB == 1:
            B = np.transpose([B])
        AB  = np.concatenate((A,B),axis=1)
        
        if vertabla==True:
            print('Matriz aumentada')
            print(AB)
            print('Pivoteo parcial:')
        
        # Pivoteo por filas AB
        tamano = np.shape(AB)
        n = tamano[0]
        m = tamano[1]
        
        # Para cada fila en AB
        pivoteado = 0
        for i in range(0,n-1,1):
            # columna desde diagonal i en adelante
            columna = np.abs(AB[i:,i])
            dondemax = np.argmax(columna)
            
            # dondemax no es en diagonal
            if (dondemax != 0):
                # intercambia filas
                temporal = np.copy(AB[i,:])
                AB[i,:] = AB[dondemax+i,:]
                AB[dondemax+i,:] = temporal
    
                pivoteado = pivoteado + 1
                if vertabla==True:
                    print(' ',pivoteado, 'intercambiar filas: ',i,'y', dondemax+i)
        if vertabla==True:
            if pivoteado==0:
                print('  Pivoteo por filas NO requerido')
            else:
                print('AB:')
                print(AB)
        return(AB)
    
    # PROGRAMA ------------------------
    # INGRESO
    A = [[4,2,5],
         [2,5,8],
         [5,4,3]]
    
    B = [60.70,92.90,56.30]
    
    # PROCEDIMIENTO
    np.set_printoptions(precision=4) # 4 decimales en print
    casicero = 1e-15  # redondear a cero
    
    AB = pivoteafila(A,B,vertabla=True)
    
    AB = gauss_eliminaAdelante(AB,vertabla=True)
    
    X = gauss_eliminaAtras(AB,vertabla=True)
    
    # SALIDA
    print('solución X: ')
    print(X)
    

    Tarea
    implementar caso cuando aparecen ceros en la diagonal para dar respuesta, convertir a funciones cada parte

    [ Gauss-Jordan ] [ Ejercicio ] [ Eliminación atrás ] [ Algoritmo ] [ función ]

  • 3.3 Método de Gauss con Python

    [ Gauss ] [ Ejercicio ] [ Eliminación adelante ] [ Sustitución atrás ]
    [ Algoritmo ] [ función ]

    ..


    1. Método de Gauss

    Referencia: Chapra 9.2 p254, Burden 6.1 p273, Rodríguez 4.3 p119

    El método de Gauss opera sobre la matriz aumentada y pivoteada por filas, añadiendo los procesos:

    \begin{cases} a_{0,0} x_0+a_{0,1}x_1+a_{0,2} x_2 = b_{0} \\ a_{1,0} x_0+a_{1,1}x_1+a_{1,2} x_2 = b_{1} \\ a_{2,0} x_0+a_{2,1}x_1+a_{2,2} x_2 = b_{2} \end{cases}

    1.1 Eliminación hacia adelante

    Eliminación hacia adelante grafico animadoDesde la primera fila i ,
    sobre las filas inferiores

    k = i+1, i+2, ...

    a_{k} = a_{k} -a_{i}\frac{a_{ki}}{a_{ii}}

    1.2 Sustitución hacia atrás

    Desde la última fila, para

    i = n-1, n-2, ...

    x_i = \Bigg( b_i-\sum_{j=i+1}^{n} a_{ij} x_{j} \Bigg) \frac{1}{a_{ii}}

    y las columnas j luego de la diagonal.

    [ Gauss ] [ Ejercicio ] [ Eliminación adelante ] [ Sustitución atrás ]
    [ Algoritmo ] [ función ]
    ..


    2. Ejercicio

    Referencia: Rodríguez 4.0 p105,  1Eva_IT2010_T3_MN Precio artículos

    Elimina Adelante 00Para el sistema de ecuaciones mostrado, desarrolle usando el método de Gauss.

    \begin{cases} 4x_1+2x_2+5x_3 = 60.70 \\ 2x_1+5x_2+8x_3 = 92.90 \\ 5x_1+4x_2+3x_3 = 56.30 \end{cases}

    Eliminación hacia adelante grafico animadoSe aplica el pivoteo parcial por filas, que tiene como resultado:

    \left( \begin{array}{rrr|r} 5 & 4 & 3 & 56.3 \\ 2 & 5 & 8 & 92.9 \\ 4 & 2 & 5 & 60.7 \end{array} \right)
    [[ 5.   4.   3.  56.3]
     [ 2.   5.   8.  92.9]
     [ 4.   2.   5.  60.7]]
    

    [ Gauss ] [ Ejercicio ] [ Eliminación adelante ] [ Sustitución atrás ]
    [ Algoritmo ] [ función ]
    ..


    3. Eliminación hacia adelante o eliminación Gaussiana

    Matriz Diagonal superiorConsiste en simplificar la matriz a una triangular superior, con ceros debajo de la diagonal, usando operaciones entre filas, para obtener:

    \left( \begin{array}{rrr|r} 5 & 4 & 3 & 56.3 \\ 0 & 3.4 & 6.8 & 70.38 \\ 0 & 0 & 5 & 40.5 \end{array} \right)
    Elimina hacia adelante
    [[ 5.    4.    3.   56.3 ]
     [ 0.    3.4   6.8  70.38]
     [ 0.    0.    5.   40.5 ]]
    

    Los índices de fila y columna en la matriz A[i,j] se usan de forma semejante a la nomenclatura de los textos de Álgebra Lineal. Progresivamente para cada fila, se toma como referencia o pivote el elemento de la diagonal (i=j).
    Luego, se realizan operaciones con las filas inferiores para convertir los elementos por debajo de la diagonal en cero.
    Las operaciones ya incluyen el vector B debido a que se trabaja sobre la matriz aumentada AB.

    AB Matriz aumentada y pivoteada por filas:
    [[ 5.   4.   3.  56.3]
     [ 2.   5.   8.  92.9]
     [ 4.   2.   5.  60.7]]
    

    iteración fila 1, operación fila 1 y 2
    Para la fila 1, con posición i=0, se usa el elemento ai,i como pivote.

    pivote = AB[i,i] = AB[0,0] = 5

    Para las filas que están después de la diagonal se referencian como k. Se obtiene el factor escalar de la operación entre filas de la fórmula.

    k = i+1 = 0+1 = 1
    factor = AB[1,0]/pivote = 2/5
    a_{k} = a_{k} -a_{i}\frac{a_{k,i}}{pivote}

    y se realiza la operación entre fila k y la fila i para actualizar la fila k,Elimina Adelante i=0, j=1

           [ 2. 5.  8.  92.9]
    -(2/5)*[ 5. 4.  3.  56.3]
    __________________________
         = [ 0. 3.4 6.8 70.38]

    con lo que la matriz aumentada AB se actualiza a:

    AB =
    [[ 5.    4.    3.   56.3 ]
     [ 0.    3.4   6.8  70.38]
     [ 4.    2.    5.   60.7 ]]

    iteración fila 1, operación fila 1 y 3
    Elimina Adelante i=0, j=2Se continúa con la siguiente fila, quedando la matriz aumentada con la columna debajo de la primera diagonal en cero:

    k = k+1 = 2
    factor = 4/5
    
            [ 4.  2.  5.   60.7] 
    - (4/5)*[ 5.  4.  3.   56.3]
    _____________________________
          = [ 0. -1.2 2.6  15.66]
    
    AB =
    [[ 5.    4.    3.   56.3 ]
     [ 0.    3.4   6.8  70.38]
     [ 0.   -1.2   2.6  15.66]]

    Como ya se terminaron las operaciones con la primera posición de la diagonal, el siguiente paso es usar la segunda posición, i =1.

    iteración fila 2
    Elimina Adelante i=1, j=2Para la fila 2, con posición i=1, se toma el elemento de la diagonal ai,i como pivote, la variable adelante indica la referencia de la tercera fila

    pivote = A[i,i] = AB[1,1] = 3.4

    Para las filas ubicadas adelante de la diagonal se referencian como k. Para aplicar la fórmula por filas, se obtiene el factor .

    k = i+1 = 1+1 = 2
    factor = AB[2,1]/pivote  = -1.2/3.4 = - 0,3529
    
                [ 0. -1.2 2.6 15.66]
    -(-1.2/3.4)*[ 0.  3.4 6.8 70.38]
    ________________________________
             =  [ 0.  0.  5.  40.5 ]
    
    AB =
    [[ 5.    4.    3.   56.3 ]
     [ 0.    3.4   6.8  70.38]
     [ 0.    0.    5.   40.5 ]]
    

    Con lo que se completa el objetivo de tener ceros debajo de la diagonal. Matriz Diagonal superior
    Observe que no es necesario realizar operaciones para la última fila, por lo que k debe llegar solamente hasta la fila penúltima.

    El resultado de la eliminación hacia adelante, a ser usado en el próximo paso es:

    \left( \begin{array}{rrr|r} 5 & 4 & 3 & 56.3 \\ 0 & 3.4 & 6.8 & 70.38 \\ 0 & 0 & 5 & 40.5 \end{array} \right)

    [ Gauss ] [ Ejercicio ] [ Eliminación adelante ] [ Sustitución atrás ]
    [ Algoritmo ] [ función ]
    ..


    4. Sustitución hacia atrás

    La fórmula se interpreta para facilitar el algoritmo.
    Desde la última fila, para i = n-1, n-2, ...
    Y las columnas j luego de la diagonal

    x_i = \Bigg( b_i-\sum_{j=i+1}^{n} a_{ij} x_{j} \Bigg) \frac{1}{a_{ii}}

    Para una fila i, el vector B[i] representa el valor de la constante en la fila i de la matriz aumentada, A[i,j] se refiere los valores de los coeficientes de la ecuación, de los que se encuentran a la derecha de la diagonal.

    Las operaciones se realizan de abajo hacia arriba desde la última fila. Para el ejercicio presentado se tiene que:

    ultfila = n-1 = 3-1 = 2
    ultcolumna = m-1 = 4-1 = 3

    la matriz a procesar es la resultante de eliminación hacia adelante:

    \left( \begin{array}{rrr|r} 5 & 4 & 3 & 56.3 \\ 0 & 3.4 & 6.8 & 70.38 \\ 0 & 0 & 5 & 40.5 \end{array} \right)
    Elimina hacia adelante
    [[ 5.    4.    3.   56.3 ]
     [ 0.    3.4   6.8  70.38]
     [ 0.    0.    5.   40.5 ]]
    

    iteración 1, fila 3, i=2
    Empieza desde la última fila de la matriz,

    [ 0. 0. 5. 40.5 ]
    0 x_1 + 0 x_2 + 5 x_3 = 40.5

    El valor de la constante es B[i] = 40.5 y no existen elementos hacia la derecha de la diagonal. No se usa la ultima columna que es de las constantes:

    5 x_3 = 40.5 x_3 = \frac{40.5}{5} = 8.1

    la respuesta se interpreta en el vector X como:

    X= [ x_1 , x_2 , x_3] = [ 0 , 0 , 8.1 ]

    iteración 2, fila 2,  i = 1
    De la penúltima fila se obtiene la ecuación para encontrar x2

    [ 0. 3.4 6.8 70.38]
    0x_1 + 3.4 x_2 +6.8 x_3 = 70.38

    se observa que B[i] = 70.38 y  a la derecha de a diagonal se tiene un solo valor de 6.8.

    3.4 x_2 = 70.38 -6.8 x_3 3.4 x_2 = 70.38 -6.8 (8.1)

    Usa el valor de x3 encontrado en la iteración anterior. Muestra la ecuación para la segunda fila.

    x_2 = \frac{70.38 -6.8 (8.1)}{3.4} = 4.5

    la respuesta se interpreta en el vector X como:

    X= [ 0 , 4.5 , 8.1 ]

    iteración 3 fila 1, i=0
    Se sigue el mismo proceso para la siguiente incógnita x1 que se interpreta como

    [ 5. 4. 3. 56.3 ]
    5x_1 + 4 x_2 + 3x_3 = 56.3 5x_1 = 56.3 - ( 4 x_2 + 3x_3) x_1 = \frac{56.3 - ( 4 (4.5) + 3(8.1))}{5} = 2.8

    Se encuentra que la solución al sistema de ecuaciones es:

    X= [ 2.8, 4.5 , 8.1 ]
    Método de Gauss
    solución X: 
    [2.8 4.5 8.1]
    

    Verificar respuesta

    Para verificar que el resultado es correcto, se usa el producto punto entre la matriz a y el vector resultado X. La operación A.X = B debe dar el vector B.

    >>> A
    array([[4., 2., 5.],
           [2., 5., 8.],
           [5., 4., 3.]])
    >>> X
    array([2.8, 4.5, 8.1])
    >>> np.dot(A,X)
    array([60.7, 92.9, 56.3])

    [ Gauss ] [ Ejercicio ] [ Eliminación adelante ] [ Sustitución atrás ]
    [ Algoritmo ] [ función ]
    ..


    5. Algoritmo con Python

    El algoritmo para el Método de Gauss, reutiliza las instrucciones para matriz aumentada y pivoteo parcial por filas.

    Recordar: Asegurar que los arreglos sean de tipo número Real (float), para que no se considere el vector como entero y realice operaciones entre enteros, generando errores por truncamiento.

    El resultado del algoritmo muestra los siguientes resultados:

    Pivoteo parcial por filas AB: ----
    [[ 5.   4.   3.  56.3]
     [ 2.   5.   8.  92.9]
     [ 4.   2.   5.  60.7]]
    Eliminación hacia adelante: ------
    i: 0 k: 1 factor: 0.4
    i: 0 k: 2 factor: 0.8
    [[ 5.    4.    3.   56.3 ]
     [ 0.    3.4   6.8  70.38]
     [ 0.   -1.2   2.6  15.66]]
    i: 1 k: 2 factor: -0.3529411764705883
    [[ 5.    4.    3.   56.3 ]
     [ 0.    3.4   6.8  70.38]
     [ 0.    0.    5.   40.5 ]]
    Método de Gauss
    solución X: 
    [2.8 4.5 8.1]

    La parte nueva a desarrollar corresponde al procedimiento de "eliminación hacia adelante" y el procedimiento de "sustitución hacia atrás".

    # Método de Gauss
    # Sistemas de Ecuaciones A.X=B
    import numpy as np
    
    # INGRESO
    # NOTA: Para AB, se ha usado pivoteo parcial por filas
    A = [[4,2,5],
         [2,5,8],
         [5,4,3]]
    B = [60.70, 92.90, 56.30]
    
    # PROCEDIMIENTO
    # Matrices como arreglo, numeros reales
    A = np.array(A,dtype=float)
    B = np.array(B,dtype=float)
    
    # Matriz aumentada AB
    B_columna = np.transpose([B])
    AB  = np.concatenate((A,B_columna),axis=1)
    
    # Pivoteo parcial por filas
    tamano = np.shape(AB)
    n = tamano[0]
    m = tamano[1]
    
    # Para cada fila en AB
    for i in range(0,n-1,1):
        # columna desde diagonal i en adelante
        columna = abs(AB[i:,i])
        dondemax = np.argmax(columna)
        
        if (dondemax !=0): # NO en diagonal
            # intercambia filas
            temporal = np.copy(AB[i,:])
            AB[i,:]  = AB[dondemax+i,:]
            AB[dondemax+i,:] = temporal
    print('Pivoteo parcial por filas AB: ----')
    print(AB)
    
    # Eliminación hacia adelante
    print('Eliminación hacia adelante: ------')
    for i in range(0,n-1,1): # una fila
        pivote   = AB[i,i]
        adelante = i + 1
        for k in range(adelante,n,1): # diagonal adelante
            factor  = AB[k,i]/pivote
            AB[k,:] = AB[k,:] - AB[i,:]*factor
    
            print('i:',i,'k:',k, 'factor:',factor)
        print(AB)
    
    # Sustitución hacia atrás
    ultfila = n-1
    ultcolumna = m-1
    X = np.zeros(n,dtype=float)
    for i in range(ultfila,0-1,-1):
        suma = AB[i,ultcolumna]
        for j in range(i+1,ultcolumna,1):
            suma = suma - AB[i,j]*X[j]
        X[i] = suma/AB[i,i]
    
    # SALIDA
    print('Método de Gauss')
    print('solución X: ')
    print(X)
    

    Tarea

    Revisar cuando la matriz pivoteada por filas tienen en la diagonal un elemento cero o muy cercano a 0, la matriz sería singular. El valor considerado como casi cero podría ser 1x10-15

    A estas alturas, por la cantidad de líneas de instrucción es recomendable reutilizar bloques de algoritmos usando funciones def-return. Por ejemplo: pivoteo por filas, eliminación hacia adelante, sustitución hacia atrás.

    [ Gauss ] [ Ejercicio ] [ Eliminación adelante ] [ Sustitución atrás ]
    [ Algoritmo ] [ función ]

    ..


    6. Algoritmo como función de Python

    Se integra la función pivoteafila(), se crean las funciones para los procedimientos gauss_eliminaAdelante()gauss_sustituyeAtras(), usando la variable vertabla para observar los resultados parciales.

    # Método de Gauss
    # Sistemas de Ecuaciones A.X=B
    import numpy as np
    
    def gauss_eliminaAdelante(AB,vertabla=False,casicero = 1e-15):
        ''' Gauss elimina hacia adelante
        tarea: verificar términos cero
        '''
        tamano = np.shape(AB)
        n = tamano[0]
        m = tamano[1]
        if vertabla==True:
            print('Elimina hacia adelante:')
        for i in range(0,n,1):
            pivote = AB[i,i]
            adelante = i+1
            if vertabla==True:
                print(' fila i:',i,' pivote:', pivote)
            for k in range(adelante,n,1):
                if (np.abs(pivote)>=casicero):
                    factor = AB[k,i]/pivote
                    AB[k,:] = AB[k,:] - factor*AB[i,:]
                    for j in range(0,m,1): # casicero revisa
                        if abs(AB[k,j])<casicero:
                            AB[k,j]=0
                    if vertabla==True:
                        print('  fila k:',k,
                              ' factor:',factor)
                else:
                    print('  pivote:', pivote,'en fila:',i,
                          'genera division para cero')
            if vertabla==True:
                print(AB)
        return(AB)
    
    def gauss_sustituyeAtras(AB,vertabla=False,casicero = 1e-15):
        ''' Gauss sustituye hacia atras
        '''
        n,m = np.shape(AB)
        # Sustitución hacia atras
        if vertabla==True:
            print('Sustitute hacia atras:')
        X = np.zeros(n,dtype=float) 
        ultfila = n-1
        ultcolumna = m-1
        for i in range(ultfila,0-1,-1):
            suma = AB[i,ultcolumna]   # B[i]
            for j in range(i+1,ultcolumna,1):
                suma = suma - AB[i,j]*X[j]
            X[i] = suma/AB[i,i]    # suma/pivote
            if vertabla==True:
                print(' fila i:',i,
                      '   X['+str(i)+']:',X[i])
        return(X)
    
    def pivoteafila(A,B,vertabla=False):
        '''
        Pivoteo parcial por filas, entrega matriz aumentada AB
        Si hay ceros en diagonal es matriz singular,
        Tarea: Revisar si diagonal tiene ceros
        '''
        A = np.array(A,dtype=float)
        B = np.array(B,dtype=float)
        # Matriz aumentada
        nB = len(np.shape(B))
        if nB == 1:
            B = np.transpose([B])
        AB  = np.concatenate((A,B),axis=1)
        
        if vertabla==True:
            print('Matriz aumentada')
            print(AB)
            print('Pivoteo parcial:')
        
        # Pivoteo por filas AB
        tamano = np.shape(AB)
        n = tamano[0]
        m = tamano[1]
        
        # Para cada fila en AB
        pivoteado = 0
        for i in range(0,n-1,1):
            # columna desde diagonal i en adelante
            columna = np.abs(AB[i:,i])
            dondemax = np.argmax(columna)
            
            # dondemax no es en diagonal
            if (dondemax != 0):
                # intercambia filas
                temporal = np.copy(AB[i,:])
                AB[i,:] = AB[dondemax+i,:]
                AB[dondemax+i,:] = temporal
    
                pivoteado = pivoteado + 1
                if vertabla==True:
                    print(' ',pivoteado,
                          'intercambiar filas: ',i,
                          'con', dondemax+i)
        if vertabla==True:
            if pivoteado==0:
                print('  Pivoteo por filas NO requerido')
            else:
                print('AB:')
                print(AB)
        return(AB)
    
    # PROGRAMA Búsqueda de solucion  --------
    # INGRESO
    A = [[4,2,5],
         [2,5,8],
         [5,4,3]]
    B = [60.70,92.90,56.30]
    
    # PROCEDIMIENTO
    AB = pivoteafila(A,B,vertabla=True)
    
    AB = gauss_eliminaAdelante(AB,vertabla=True)
    
    X = gauss_sustituyeAtras(AB,vertabla=True)
    
    # SALIDA
    print('Método de Gauss')
    print('solución X: ')
    print(X)
    

    El resultado para el ejercicio anterior es:

    Matriz aumentada
    [[ 4.   2.   5.  60.7]
     [ 2.   5.   8.  92.9]
     [ 5.   4.   3.  56.3]]
    Pivoteo parcial:
      1 intercambiar filas:  0 con 2
    [[ 5.   4.   3.  56.3]
     [ 2.   5.   8.  92.9]
     [ 4.   2.   5.  60.7]]
    Elimina hacia adelante:
     fila i: 0  pivote: 5.0
      fila k: 1  factor: 0.4
      fila k: 2  factor: 0.8
    [[ 5.    4.    3.   56.3 ]
     [ 0.    3.4   6.8  70.38]
     [ 0.   -1.2   2.6  15.66]]
     fila i: 1  pivote: 3.4
      fila k: 2  factor: -0.3529411764705883
    [[ 5.    4.    3.   56.3 ]
     [ 0.    3.4   6.8  70.38]
     [ 0.    0.    5.   40.5 ]]
     fila i: 2  pivote: 5.0
    [[ 5.    4.    3.   56.3 ]
     [ 0.    3.4   6.8  70.38]
     [ 0.    0.    5.   40.5 ]]
    Sustitute hacia atras:
     fila i: 2    X[2]: 8.100000000000003
     fila i: 1    X[1]: 4.499999999999997
     fila i: 0    X[0]: 2.8
    Método de Gauss
    solución X: 
    [2.8 4.5 8.1]
    

    [ Gauss ] [ Ejercicio ] [ Eliminación adelante ] [ Sustitución atrás ]
    [ Algoritmo ] [ función ]

  • 3.2 Pivoteo parcial por filas con Python

    [ Ejercicio ] [ Matriz Aumentada ] [ Pivoteo filas ] [ algoritmo ] [ función ]

    Referencia: Chapra 9.4.2 p268. Burden 6.2 p279. Rodríguez 4.0 p105pivoteo parcial por filas

    Los métodos de solución a sistemas de ecuaciones en los primeros pasos usan la matriz aumentada y pivoteada por filas.

    Como es un procedimiento usado en todos los métodos de la unidad, para simplificar se presenta como uno de los primeros algoritmos.diagonal dominante vs cima de montaña

    El objetivo del pivoteo es ordenar la matriz para que en lo posible sea diagonal dominante.

    |a_{i,i}| \geq \sum_{j=0 ; i\neq j}^n |a_{i,j}|

    ..


    1. Ejercicio

    Referencia: 1Eva_IIT2011_T2 Sistema de Ecuaciones, diagonal dominante

    Considere el siguiente sistema de ecuaciones AX=B dado por:

    \begin{cases} -2x+5y+9z=1\\7x+y+z=6\\-3x+7y-z=-26\end{cases}

    Realice el pivoteo parcial por filas, de tal manera que la diagonal de A sea estrictamente dominante.

    [ Ejercicio ] [ Matriz Aumentada ] [ Pivoteo filas ] [ algoritmo ] [ función ]
    ..


    2. Matriz Aumentada

    El sistema de ecuaciones se escribe en la forma algebraica como matrices y vectores de la forma Ax=B

    \begin{pmatrix} -2 & 5 & 9 \\ 7 & 1 & 1 \\-3 & 7 & -1 \end{pmatrix} \begin{pmatrix} x_0 \\ x_1 \\ x_2 \end{pmatrix} = \begin{pmatrix} 1 \\ 6 \\ -26 \end{pmatrix}

    Para el algoritmo, las ecuaciones se escriben en forma de matriz A y vector B.

    A = [[-2, 5, 9],
         [ 7, 1, 1],
         [-3, 7,-1]]
    
    B = [1,6,-26]

    Las matrices y vectores se procesan como arreglos np.array() de números reales. No se usan listas.

    A = np.array(A,dtype=float)
    B = np.array(B,dtype=float)

    El vector B para la matriz aumentada se usa en forma de columna. Se aumenta una dimensión [B] y se aplica la transpuesta.

    B_columna = np.transpose([B])
    >>> B_columna
    array([[  1],
           [  6],
           [-26]])
    

    La matriz aumentada AB se forma al concatenar por columnas la matriz A con el vector B_columna,  usando el parámetro axis=1.

    AB = np.concatenate((A,B_columna),axis=1)
    

    el resultado AB se muestra como:

    >>> AB
    array([[ -2. ,  5. ,   9. ,   1.],
           [  7. ,  1. ,   1. ,   6.],
           [ -3. ,  7. ,  -1. , -26.]])
    
    \left( \begin{array}{rrr|r} -2 & 5 & 9 & 1 \\ 7 & 1 & 1 & 6 \\ -3 & 7 & -1 & -26 \end{array} \right)

    En varios algoritmos se usa la matriz aumentada AB, para mantener el orden entre filas de A y B al aplicar cambios de fila.

    [ Ejercicio ] [ Matriz Aumentada ] [ Pivoteo filas ] [ algoritmo ] [ función ]
    ..


    3. Pivoteo parcial por filas

    pivotea filas columna 0Para el pivoteo por filas de la matriz aumentada AB, tiene como primer paso revisar la primera columna, desde la posición diagonal hacia todas las filas por debajo, usando solo la magnitud de los coeficientes |A|.

    La representación gráfica de la matriz A, permite visualizar los intercambios de fila.

    >>> AB
    array([[ -2. ,  5. ,   9. ,   1.],
           [  7. ,  1. ,   1. ,   6.],
           [ -3. ,  7. ,  -1. , -26.]])

    Las instrucciones para seleccionar la columna, usar el valor absoluto y dónde se encuentra el máximo son:

    columna = abs(AB[i:,i])
    dondemax = np.argmax(columna)

    Los valores de la columna se reducen a:

    columna = [|-2.|,   fila=0
               | 7.|,   fila=1
               |-3.|]   fila=2
    dondemax = 1

    Si la magnitud de mayor valor no está en la diagonal (dondemax≠0), se realiza el intercambio entre la fila dondemax y la fila de la diagonal i en AB.

    AB = [[  7. ,  1. ,   1. ,   6.],
          [ -2. ,  5. ,   9. ,   1.],
          [ -3. ,  7. ,  -1. , -26.]]

    En éste paso se asegura que en la casilla AB[0,0] se encuentre el mayor valor de la columna 1.

    El intercambio de filas requiere tres pasos: realizar una copia de la fila que se esta analizando en un vector temporal. Luego se copian los valores en la fila AB[dondemax+i] en la fila AB[i]. Finalmente actualizando la fila AB[dondemax+i] con los valores de temporal.

        if (dondemax !=0): # NO en diagonal
            # intercambia filas
            temporal = np.copy(AB[i,:])
            AB[i,:]  = AB[dondemax+i,:]
            AB[dondemax+i,:] = temporal

    pivoteo por filas siguiente columnaSe repite el proceso anterior para la siguiente columna (j=1), pero siempre formada desde la diagonal (i=j).

    La columna en éste paso se reduce el tamaño en una posición. Se consideran solo las magnitudes para la selección de dondemax.

    AB = [[  7. ,  1. ,   1. ,   6.],
          [ -2. ,  5. ,   9. ,   1.],
          [ -3. ,  7. ,  -1. , -26.]]

    Los valores de la columna se reducen a:

    columna = [|5|,  fila=0
               |7|]  fila=1
    dondemax = 1

    En el ejercicio se encuentra que: la magnitud de mayor valor está en la fila=1, no en la diagonal. Se realiza el intercambio entre la fila 'i' y la fila (dondemax+i) de AB.

    AB = ([[  7. ,  1. ,   1. ,   6.],
           [ -3. ,  7. ,  -1. , -26.],
           [ -2. ,  5. ,   9. ,   1.]]

    pivoteo por filas completadoSe repite el proceso para la tercera columna desde la diagonal, que resulta tener solo una casilla (columna =[9]) y no ser requiere continuar.

    En la gráfica se destaca el resultado del pivoteo por filas, acercando en lo posible a una matriz diagonal dominante.

    Pivoteo parcial por filas AB:
    [[  7. , 1. ,  1. ,   6.],
     [ -3. , 7. , -1. , -26.],
     [ -2. , 5. ,  9. ,   1.]]
    A:
    [[ 7. , 1. , 1.],
    [ -3. , 7. , -1.],
    [ -2. , 5. , 9.]]
    B:
    [6. , -26. , 1.]
    

    Tarea: Revisar cuando en una columna se tiene dos valores mayores de igual valor. Ampliar el algoritmo. Considere como ejemplo del caso planteado: 1Eva_IT2011_T2_MN Alimentos para animales

    [ Ejercicio ] [ Matriz Aumentada ] [ Pivoteo filas ] [ algoritmo ] [ función ]
    ..


    4. Algoritmo en Python

    Para realizar el algoritmo, es de recordar que para realizar operaciones en una matriz sin alterar la original, se usa una copia de la matriz (np.copy).  Con la copia de la matriz, se puede comparar y observar los cambios entre la matriz original y la copia a la que se aplicaron cambios.

    Si no es necesaria la comparación entre el antes y después, no se realiza la copia y se ahorra el espacio de memoria, detalle importante para matrices de "gran tamaño" y una computadora con "limitada" memoria.

    # Pivoteo parcial por filas
    import numpy as np
    
    # INGRESO
    A = [[-2, 5, 9],
         [ 7, 1, 1],
         [-3, 7,-1]]
    B = [1,6,-26]
    
    # PROCEDIMIENTO
    # Matrices como arreglo, numeros reales
    A = np.array(A,dtype=float)
    B = np.array(B,dtype=float)
    
    # Matriz aumentada AB
    B_columna = np.transpose([B])
    AB  = np.concatenate((A,B_columna),axis=1)
    AB0 = np.copy(AB) # copia de AB
    
    # Pivoteo parcial por filas
    tamano = np.shape(AB)
    n = tamano[0]
    m = tamano[1]
    
    # Para cada fila en AB
    for i in range(0,n-1,1):
        # columna desde diagonal i en adelante
        columna = abs(AB[i:,i])
        dondemax = np.argmax(columna)
        
        if (dondemax !=0): # NO en diagonal
            # intercambia filas
            temporal = np.copy(AB[i,:])
            AB[i,:]  = AB[dondemax+i,:]
            AB[dondemax+i,:] = temporal
    # Actualiza A y B pivoteado
    A = AB[:,:n]
    B = AB[:,n]
    
    # SALIDA
    print('Matriz aumentada:')
    print(AB0)
    print('Pivoteo parcial por filas AB:')
    print(AB)
    print('A:')
    print(A)
    print('B:')
    print(B)
    

    [ Ejercicio ] [ Matriz Aumentada ] [ Pivoteo filas ] [ algoritmo ] [ función ]
    ..


    5. Función pivoteafila(M)

    Los bloques de cada procedimiento que se repiten en otros métodos se convierten a funciones def-return, empaquetando las soluciones algorítmicas.

    # Pivoteo parcial por filas, funcion
    import numpy as np
    
    def pivoteafila(A,B,vertabla=False):
        '''
        Pivoteo parcial por filas, entrega matriz aumentada AB
        Si hay ceros en diagonal es matriz singular,
        Tarea: Revisar si diagonal tiene ceros
        '''
        A = np.array(A,dtype=float)
        B = np.array(B,dtype=float)
        # Matriz aumentada
        nB = len(np.shape(B))
        if nB == 1:
            B = np.transpose([B])
        AB  = np.concatenate((A,B),axis=1)
        
        if vertabla==True:
            print('Matriz aumentada')
            print(AB)
            print('Pivoteo parcial:')
        
        # Pivoteo por filas AB
        tamano = np.shape(AB)
        n = tamano[0]
        m = tamano[1]
        
        # Para cada fila en AB
        pivoteado = 0
        for i in range(0,n-1,1):
            # columna desde diagonal i en adelante
            columna = np.abs(AB[i:,i])
            dondemax = np.argmax(columna)
            
            # dondemax no es en diagonal
            if (dondemax != 0):
                # intercambia filas
                temporal = np.copy(AB[i,:])
                AB[i,:] = AB[dondemax+i,:]
                AB[dondemax+i,:] = temporal
    
                pivoteado = pivoteado + 1
                if vertabla==True:
                    print(' ',pivoteado,
                          'intercambiar filas: ',i,
                          'con', dondemax+i)
        if vertabla==True:
            if pivoteado==0:
                print('  Pivoteo por filas NO requerido')
            else:
                print('AB:')
                print(AB)
        return(AB)
    
    # INGRESO
    A = [[-2, 5, 9],
         [ 7, 1, 1],
         [-3, 7,-1]]
    B = [1,6,-26]
    
    # PROCEDIMIENTO
    AB = pivoteafila(A,B,vertabla=True)
    n = len(AB)
    
    # Actualiza A y B pivoteado
    A = AB[:,:n]
    B = AB[:,n]
    
    # SALIDA
    print('Pivoteo parcial por filas AB:')
    print(AB)
    print('A:')
    print(A)
    print('B:')
    print(B)
    

    El resultado del ejercicio es:

    Matriz aumentada
    [[ -2.   5.   9.   1.]
     [  7.   1.   1.   6.]
     [ -3.   7.  -1. -26.]]
    Pivoteo parcial:
      1 intercambiar filas:  0 con 1
      2 intercambiar filas:  1 con 2
    [[  7.   1.   1.   6.]
     [ -3.   7.  -1. -26.]
     [ -2.   5.   9.   1.]]
    Pivoteo parcial por filas AB:
    [[  7.   1.   1.   6.]
     [ -3.   7.  -1. -26.]
     [ -2.   5.   9.   1.]]
    A:
    [[ 7.  1.  1.]
     [-3.  7. -1.]
     [-2.  5.  9.]]
    B:
    [  6. -26.   1.]

    [ Ejercicio ] [ Matriz Aumentada ] [ Pivoteo filas ] [ algoritmo ] [ función ]


    6. Gráfica de Matriz A en 3D

    Instrucciones para la gráfica en 3D de una matriz A. Las alturas de las barras son relativas a los valores de la casilla A[i,j]

    # Matriz A como Barras3D
    import numpy as np
    import matplotlib.pyplot as plt
    
    # INGRESO
    ##A = [[-2, 5, 9],
    ##     [ 7, 1, 1],
    ##     [-3, 7,-1]]
    ##titulo = 'matriz A'
    
    ##A = [[ 7, 1, 1],
    ##     [-2, 5, 9],
    ##     [-3, 7,-1]]
    ##titulo = 'A pivotea fila0 y fila1'
    
    ##A = [[ 7, 1, 1],
    ##     [-3, 7,-1],
    ##     [-2, 5, 9]]
    ##titulo = 'A pivotea fila1 y fila2'
    
    A = [[ 7, 1, 1],
         [-3, 7,-1],
         [-2, 5, 9]]
    titulo='A: Pivoteo por Filas'
    
    # PROCEDIMIENTO
    A = np.array(A, dtype=float)
    n,m = np.shape(A)
    
    # para grafica 3D
    xi = np.arange(0,n,1)
    yj = np.arange(0,m,1)
    Xi,Yj = np.meshgrid(xi,yj)
    
    A_min = np.min([np.min(A),-3])
    A_max = np.max([np.max(A),9])
    
    # SALIDA
    # Grafica barras 3D
    fig3D = plt.figure()
    graf3D = fig3D.add_subplot(111,projection='3d')
    
    AT = np.transpose(A) # filas en x, columnas en y
    h = 0.5 # Barras ancho y profundidad
    color_A = AT.ravel()/A_max
    color_ij = plt.cm.rainbow(color_A)
    
    graf3D.bar3d(Xi.ravel(),Yj.ravel(),
                 np.zeros(n*m),h,h,
                 AT.ravel(),color=color_ij)
    
    # escala eje z
    graf3D.set_zlim(A_min,A_max)
    # etiqueta
    graf3D.set_xlabel('filas i')
    graf3D.set_ylabel('columnas j')
    graf3D.set_zlabel('A[i,j]')
    graf3D.set_title(titulo)
    # etiquetas ejes
    graf3D.xaxis.set_ticks(xi + h/2)
    graf3D.xaxis.set_ticklabels(xi)
    graf3D.yaxis.set_ticks(yj + h/2)
    graf3D.yaxis.set_ticklabels(yj)
    # Barra de color
    color_escala = plt.Normalize(A_min,A_max)
    color_barra = plt.cm.ScalarMappable(norm=color_escala,
                    cmap=plt.colormaps["rainbow"])
    fig3D.colorbar(color_barra,ax=graf3D,label="A[i,j]")
    
    graf3D.view_init(35,35)
    plt.show()
    

    [ Ejercicio ] [ Matriz Aumentada ] [ Pivoteo filas ] [ algoritmo ] [ función ]


    7. Ejercicio 2

    Referencia: Rodríguez 4.0 p105,  1Eva_IT2010_T3_MN Precio artículosvende frutas

    Ejemplo 1. Un comerciante compra tres productos A, B, C, pero en las facturas únicamente consta la cantidad comprada en Kg y el valor total de la compra.

    Se necesita determinar el precio unitario de cada producto.  Dispone de solo tres facturas con los siguientes datos:

    Ejemplo:
    Cantidad Valor ($)
    Factura X0 X1 X2 Pagado
    1 4 2 5 60.70
    2 2 5 8 92.90
    3 5 4 3 56.30

    Los precios unitarios se pueden representar por las variables x0, x1, x2 para escribir el sistema de ecuaciones que muestran las relaciones de cantidad, precio y valor pagado:

    \begin{cases} 4x_0+2x_1+5x_2 = 60.70 \\ 2x_0+5x_1+8x_2 = 92.90 \\ 5x_0+4x_1+3x_2 = 56.30 \end{cases}

    Desarrollo

    El sistema de ecuaciones se escribe en la forma algebraica como matrices y vectores de la forma Ax=B

    \begin{pmatrix} 4 & 2 & 5 \\ 2 & 5 & 8 \\5 & 4 & 3 \end{pmatrix} \begin{pmatrix} x_0 \\ x_1 \\ x_2 \end{pmatrix} = \begin{pmatrix} 60.70 \\ 92.90 \\ 56.30 \end{pmatrix}

    La matriz aumentada usando el algoritmo tiene como resultado:

    >>> AB
    array([[ 4. ,  2. ,  5. , 60.7],
           [ 2. ,  5. ,  8. , 92.9],
           [ 5. ,  4. ,  3. , 56.3]])
    

    En varios algoritmos se usa la matriz aumentada AB, para mantener el orden entre filas al aplicar cambios de fila.

    Para el pivoteo por fila de la matriz aumentada AB, tiene como primer paso revisar la primera columna desde la diagonal en adelante.

    >>> AB
    array([[ 4. ,  2. ,  5. , 60.7],
           [ 2. ,  5. ,  8. , 92.9],
           [ 5. ,  4. ,  3. , 56.3]])
    

    Los valores de la columna se reducen a:

    columna = [|4|,   fila=0
               |2|,   fila=1
               |5|]   fila=2
    dondemax = 2

    En el ejercicio se encuentra que: la magnitud de mayor valor está en la última fila, no en la diagonal. Se realiza el intercambio entre la fila 2 y la fila 0 de AB.

    AB = [[ 5. ,  4. ,  3. , 56.3],
          [ 2. ,  5. ,  8. , 92.9],
          [ 4. ,  2. ,  5. , 60.7]]

    Se repite el proceso anterior para la siguiente columna, pero siempre formada desde la diagonal.

    AB = [[ 5. ,  4. ,  3. , 56.3],
          [ 2. ,  5. ,  8. , 92.9],
          [ 4. ,  2. ,  5. , 60.7]]

    Los valores de la columna se reducen a:

    columna = [|5|,  fila=0
               |2|]  fila=1
    dondemax = 0

    Como la posición dondemax es la primera, índice 0, se determina que ya está en la diagonal de AB y no es necesario realizar el intercambio de filas.

    Se repite el proceso para la tercera columna desde la diagonal, que resulta tener solo una casilla (columna =[5]) y no ser requiere continuar.

    El resultado del pivoteo por fila se muestra a continuación:

    Pivoteo parcial por filas AB:
    [[ 5.   4.   3.  56.3]
     [ 2.   5.   8.  92.9]
     [ 4.   2.   5.  60.7]]
    A:
    [[5. 4. 3.]
     [2. 5. 8.]
     [4. 2. 5.]]
    B:
    [56.3 92.9 60.7]
    

    [ Ejercicio ] [ Matriz Aumentada ] [ Pivoteo filas ] [ algoritmo ] [ función ]

  • 3.1 Sistema de ecuaciones 3x3, planos 3D con Python

    Ejemplo: [ ejercicio ] [ analítico ] [ algoritmo ] [ Python ]

    Referencia: Chapra 9.1 p247Plano Ecuaciones 3x3 animado
    Como punto de partida para la unidad de sistema de ecuaciones, se usa un ejemplo para ilustrar la solución del sistema en gráficos para 3 ecuaciones y 3 incógnitas.

    La solución es un punto de intersección de los planos en el espacio dados por cada ecuación en el sistema.

    La intersección entre dos planos es una recta, que al añadir un plano adicional la intersección es un punto. Las coordenadas del punto es la solución buscada.

    Para representar lo indicado, se realiza el desarrollo analítico del ejercicio junto al algoritmo y las gráficas en 3D con Python y Matplotlib.

    Ejemplo: [ ejercicio ] [ analítico ] [ algoritmo ] [ Python ]
    ..


    1. Ejercicio

    Referencia: 1Eva_IIT2011_T2 Sistema de Ecuaciones, diagonal dominante

    Considere el siguiente sistema de ecuaciones AX=B dado por:

    \begin{cases} -2x+5y+9z=1\\7x+y+z=6\\-3x+7y-z=-26\end{cases}

    Se pueden representar como planos en el espacio despejando la variable z para cada ecuación, de la forma:

    \begin{cases} z=(1+ 2x - 5y)/9\\z=(6 -7x-y)/1\\z=(-26+3x-7y)/(-1)\end{cases}

    Ejemplo: [ ejercicio ] [ analítico ] [ algoritmo ] [ Python ]
    ..


    2. Desarrollo analítico. Ecuaciones como Planos en el espacio

    Para diferenciar las ecuaciones, se añade el índice por filas i a cada una:

    \begin{cases}f_0(x,y) : z=(1+ 2x - 5y)/9\\f_1(x,y) : z=(6 -7x-y)/1\\f_2(x,y) : z=(-26+3x-7y)/(-1)\end{cases}

    Si observamos la primera ecuación en una gráfica, encontramos que para realizar el plano se requiere definir los intervalos para los ejes X, Y, por ejemplo:

    -5 ≤ x ≤ 5
    -7 ≤ y ≤ 7

    Plano Ecuaciones 3x3 animado 0

    Al combinar los planos Z0 y Z1, encontramos que la solución al sistema es la recta intersección de ambos planos.

    Plano Z0 Z1

    Usando la tercera ecuación, la intersección de los planos genera un punto cuyas coordenadas corresponden a la solución del sistema.

    Plano Z0 Z1 Z2

    Recta intersección de planos Z0 y Z1

    Usando solo las dos primeras ecuaciones y considerando para el eje 'y' una constante, por ejemplo el lado izquierdo del intervalo ya.

    \begin{cases} -2x+5y_a+9z=1\\7x+y_a+z=6\end{cases}

    Se reordenan las ecuaciones y reemplazan valores:

    \begin{cases} -2x+9z=1-5y_a\\7x+z=6-y_a\end{cases} \begin{cases} -2x+9z=1-5(-7)\\7x+z=6-(-7)\end{cases}

    Al resolver las ecuaciones se encuentra un punto de la recta de intersección, del lado izquierdo del intervalo para el eje y. Se aplica el mismo proceso para el lado derecho del intervalo del eje 'y' y se tienen las coordenadas:

    array([[ 1.24615385, -7.        ,  4.27692308],
           [ 0.38461538,  7.        , -3.69230769]])

    Con las que se puede trazar la línea de intersección entre los planos Z0 y Z1

    Ejemplo: [ ejercicio ] [ analítico ] [ algoritmo ] [ Python ]
    ..


    3. Algoritmo con Python

    Para observar el sistema de ecuaciones en un gráfico de tres dimensiones, se utilizan gráficas 3D  y observar los resultados con varios puntos de vista al rotar el gráfico con el cursor.

    Para el algoritmo, las ecuaciones del sistema se escriben en forma matricial Ax=B.

    \begin{cases} -2x+5y+9z=1\\7x+y+z=6\\-3x+7y-z=-26\end{cases}

    A es una matriz de coeficientes cuadrada, el número de filas es igual al de columnas. B es un vector de constantes, con el mismo número de elementos que filas de A.

    # INGRESO Ax=B
    A = [[-2, 5, 9],
         [ 7, 1, 1],
         [-3, 7,-1]]
    
    B = [1,6,-26]

    Las ecuaciones de cada plano escriben usando los coeficientes de A y B, según lo realizado en el desarrollo analítico al despejar la variable z. Cada ecuación es una expresión de dos variables (x,y), para simplificar se usa el formato lambda x,y.

    # Ecuaciones de planos
    f0 = lambda x,y: (B[0]-A[0,0]*x-A[0,1]*y)/A[0,2]
    f1 = lambda x,y: (B[1]-A[1,0]*x-A[1,1]*y)/A[1,2]
    f2 = lambda x,y: (B[2]-A[2,0]*x-A[2,1]*y)/A[2,2]

    Ejemplo: [ ejercicio ] [ analítico ] [ algoritmo ] [ Python ]

    ..

    3.1 Intervalos, muestras para cada eje en los vectores xi, yj

    Para la gráfica 3D se requiere usar intervalos para las variables independientes x,y de forma semejante a las gráficas en 2D. En cada intervalo se realizaran muestras en varios puntos del intervalo. La combinación de muestras en cada eje, generan puntos en el plano X,Y.

    Se generan las muestras para cada eje en los vectores xi, yj

    xa = -5    # Intervalo [xa,xb] para eje x
    xb = 5
    ya = 7     # Intervalo [ya,yb] para eje y
    yb = -7
    muestras = 11
    
    xi = np.linspace(xa,xb, muestras)
    yj = np.linspace(ya,yb, muestras)
    

    el resultado de las muestras en cada eje para el ejercicio es:

    >>> xi
    array([-5., -4., -3., -2., -1.,  0.,  1.,  2.,  3.,  4.,  5.])
    >>> yj
    array([-7. , -5.6, -4.2, -2.8, -1.4,  0. ,  1.4,  2.8,  4.2,  5.6,  7. ])
    >>> 
    

    Las combinaciones entre las muestras de cada eje se realizan en las matrices Xi,Yj, (en mayúsculas).

    Xi, Yj = np.meshgrid(xi,yj)
    

    Cada matriz representa una malla de puntos en el plano, usando luego cada punto para evaluar el valor de Z. El resultado son las matrices con los puntos de evaluación en la malla. Por ejemplo el primer punto [x0,y0] = [-5,-7]:

    >>> Xi
    array([[-5., -4., -3., -2., -1.,  0.,  1.,  2.,  3.,  4.,  5.],
           [-5., -4., -3., -2., -1.,  0.,  1.,  2.,  3.,  4.,  5.],
           [-5., -4., -3., -2., -1.,  0.,  1.,  2.,  3.,  4.,  5.],
           [-5., -4., -3., -2., -1.,  0.,  1.,  2.,  3.,  4.,  5.],
           [-5., -4., -3., -2., -1.,  0.,  1.,  2.,  3.,  4.,  5.],
           [-5., -4., -3., -2., -1.,  0.,  1.,  2.,  3.,  4.,  5.],
           [-5., -4., -3., -2., -1.,  0.,  1.,  2.,  3.,  4.,  5.],
           [-5., -4., -3., -2., -1.,  0.,  1.,  2.,  3.,  4.,  5.],
           [-5., -4., -3., -2., -1.,  0.,  1.,  2.,  3.,  4.,  5.],
           [-5., -4., -3., -2., -1.,  0.,  1.,  2.,  3.,  4.,  5.],
           [-5., -4., -3., -2., -1.,  0.,  1.,  2.,  3.,  4.,  5.]])
    >>> Yj
    array([[-7. , -7. , -7. , -7. , -7. , -7. , -7. , -7. , -7. , -7. , -7. ],
           [-5.6, -5.6, -5.6, -5.6, -5.6, -5.6, -5.6, -5.6, -5.6, -5.6, -5.6],
           [-4.2, -4.2, -4.2, -4.2, -4.2, -4.2, -4.2, -4.2, -4.2, -4.2, -4.2],
           [-2.8, -2.8, -2.8, -2.8, -2.8, -2.8, -2.8, -2.8, -2.8, -2.8, -2.8],
           [-1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4],
           [ 0. ,  0. ,  0. ,  0. ,  0. ,  0. ,  0. ,  0. ,  0. ,  0. ,  0. ],
           [ 1.4,  1.4,  1.4,  1.4,  1.4,  1.4,  1.4,  1.4,  1.4,  1.4,  1.4],
           [ 2.8,  2.8,  2.8,  2.8,  2.8,  2.8,  2.8,  2.8,  2.8,  2.8,  2.8],
           [ 4.2,  4.2,  4.2,  4.2,  4.2,  4.2,  4.2,  4.2,  4.2,  4.2,  4.2],
           [ 5.6,  5.6,  5.6,  5.6,  5.6,  5.6,  5.6,  5.6,  5.6,  5.6,  5.6],
           [ 7. ,  7. ,  7. ,  7. ,  7. ,  7. ,  7. ,  7. ,  7. ,  7. ,  7. ]])
    >>> 
    

    La matriz de resultados Zi, se genera al evaluar una ecuación en cada punto (ij). Como hay una ecuación por cada fila, se usa el índice para diferenciar cada resultado Zi.

    Z0 = f0(Xi,Yj)
    Z1 = f1(Xi,Yj)
    Z2 = f2(Xi,Yj)
    

    El gráfico del plano Z0, se realiza con las matrices Xi,Yj, con la instrucción plot_wireframe(Xi,Yj,Z0) de las librerías 3D. Luego se repite el procedimiento para Z1 y Z2.

    graf3D.plot_wireframe(Xi,Yj,Z0,
                          color ='blue',
                          label='Z0')

    Si es necesario, revise la sección de Gráficas 3D para wireframe.

    Para simplicidad del algoritmo, pues la revisión del concepto es sobre intersección de planos, la solución se obtiene con la librería Numpy.

    punto = np.linalg.solve(A,B)

    Ejemplo: [ ejercicio ] [ analítico ] [ algoritmo ] [ Python ]
    ..


    4. Instrucciones con Python

    # Sistema de ecuaciones 3x3
    # Interseccion de Planos
    import numpy as np
    import matplotlib.pyplot as plt
    from mpl_toolkits.mplot3d import axes3d
    
    # INGRESO Ax=B
    A = [[-2, 5, 9],
         [ 7, 1, 1],
         [-3, 7,-1]]
    B = [1,6,-26]
    
    xa = -5     # Intervalo Xi ,[ax,bx]
    xb = 5
    ya = -7     # Intervalo Yj ,[ay,by]
    yb = 7
    muestras = 11 # en cada intervalo
    
    # PROCEDIMIENTO
    # matriz y vector como Numpy
    A = np.array(A,dtype=float)
    B = np.array(B,dtype=float)
    
    # solucion al sistema
    punto = np.linalg.solve(A,B)
    
    # Interseccion entre ecuacion Z0 y Z1
    A01  = np.copy(A[0:2,[0,2]])
    # usando ay, extremo izquierdo eje y
    B01  = B[0:2] - ya*A[0:2,1]
    x01 = np.linalg.solve(A01,B01)
    recta01 = [x01[0],ya,x01[1]]  # tabla coordenadas
    # usando by, extremo derecho eje y
    B01 = B[0:2] - yb*A[0:2,1]
    x01 = np.linalg.solve(A01,B01)
    recta01 = np.concatenate(([recta01 ],
                      [[x01[0],yb,x01[1]]]),
                      axis=0)
    
    # ecuaciones de planos
    f0 = lambda x,y: (B[0]-A[0,0]*x-A[0,1]*y)/A[0,2]
    f1 = lambda x,y: (B[1]-A[1,0]*x-A[1,1]*y)/A[1,2]
    f2 = lambda x,y: (B[2]-A[2,0]*x-A[2,1]*y)/A[2,2]
    
    # muestras
    xi = np.linspace(xa,xb, muestras)
    yj = np.linspace(ya,yb, muestras)
    Xi, Yj = np.meshgrid(xi,yj) # en plano XY
    
    # evalua planos Zi
    Z0 = f0(Xi,Yj)
    Z1 = f1(Xi,Yj)
    Z2 = f2(Xi,Yj)
    
    # SALIDA
    print('respuesta de A.X=B : ')
    print(punto)
    
    # GRAFICA 3D
    fig3D = plt.figure()
    graf3D = fig3D.add_subplot(111, projection='3d')
    
    # Planos
    graf3D.plot_wireframe(Xi,Yj,Z0,
                           color ='blue',
                           label='Z0')
    graf3D.plot_wireframe(Xi,Yj,Z1,
                           color ='orange',
                           label='Z1')
    graf3D.plot_wireframe(Xi,Yj,Z2,
                           color ='green',
                           label='Z2')
    
    # recta entre planos Z0 y Z1
    graf3D.plot(recta01[:,0],recta01[:,1], recta01[:,2],
                color='purple',
                label='recta01',linewidth=4)
    
    # Punto solucion Z0,Z1,Z2
    graf3D.plot(punto[0],punto[1],punto[2],
                'o',color='red',
                label='Punto',linewidth=6)
    
    # etiquetas y entorno gráfico
    graf3D.set_title('Sistema de ecuaciones 3x3')
    graf3D.set_xlabel('x')
    graf3D.set_ylabel('y')
    graf3D.set_zlabel('z')
    graf3D.set_xlim(xa, xb)
    graf3D.set_ylim(ya, yb)
    graf3D.legend()
    graf3D.view_init(45, 45) # elevacion, azimut
    
    ### rotacion de ejes
    ##for angulo in range(45, 360+45, 5 ):
    ##    graf3D.view_init(45, angulo)
    ##    plt.draw()
    ##    plt.pause(.1)
    
    plt.show()
    

    Ejemplo: [ ejercicio ] [ analítico ] [ algoritmo ] [ Python ]


    Referencia: Dear linear algebra students, This is what matrices (and matrix manipulation) really look like. Zach Star. 5 mar 2020.

    Ejemplo: [ ejercicio ] [ analítico ] [ algoritmo ] [ Python ]

  • 2.7 Métodos de raíces con gráficos animados en Python

    GIF animado: [ Bisección ] [ Posicion Falsa ] [ Newton-Raphson ] [ Punto Fijo ] [ Secante ]

    Solo para fines didácticos, y como complemento para los ejercicios presentados en la unidad para raíces de ecuaciones, se presentan las instrucciones para las animaciones usadas en la presentación de los conceptos y ejercicios. Los algoritmos para animación NO son necesarios para realizar los ejercicios, que requieren una parte analítica con al menos tres iteraciones en papel y lápiz. Se lo adjunta como una herramienta didáctica de asistencia para las clases.

    La gráfica (graf_ani) se crea en una ventana (fig_ani), inicializando con la linea a partir f(x) y configurando los parámetros base para el gráfico.

    Se usan procedimientos para crear unatrama() para marca de iteración y en cada cambio se limpia la trama manteniendo la base con limpiatrama().

    En caso de requerir un archivo .gif animado se proporciona un nombre de archivo. Para crear el archivo se requiere de la librería 'pillow', a ser instalado.

    otros ejemplos de animación en el curso de Fundamentos de Programación:

    Movimiento circular – Una partícula, animación con matplotlib-Python

    GIF animado: [ Bisección ] [ Posicion Falsa ] [ Newton-Raphson ] [ Punto Fijo ] [ Secante ]
    ..


    Método de la Bisección con gráfico animado en Python

    método de Biseccion animado

    # Algoritmo de Bisecci n, Tabla
    # Los valores de [a,b] son aceptables
    # y seleccionados desde la gr fica de la funci n
    # error = tolera
    
    import numpy as np
    
    def biseccion_tabla(fx,a,b,tolera,iteramax = 20,
                        vertabla=False, precision=6):
        '''Algoritmo de Bisecci n
        Los valores de [a,b] son seleccionados
        desde la gr fica de la funci n
        error = tolera
        '''
        fa = fx(a)
        fb = fx(b)
        tramo = np.abs(b-a)
        itera = 0
        cambia = np.sign(fa)*np.sign(fb)
        tabla=[]
        if cambia<0: # existe cambio de signo f(a) vs f(b)
            if vertabla==True:
                print('m todo de Bisecci n')
                print('i', ['a','c','b'],[ 'f(a)', 'f(c)','f(b)'])
                print('  ','tramo')
                np.set_printoptions(precision)
                
            while (tramo>=tolera and itera<=iteramax):
                c = (a+b)/2
                fc = fx(c)
                cambia = np.sign(fa)*np.sign(fc)
                unafila = [a,c,b,fa,fc,fb] 
                if vertabla==True:
                    print(itera,[a,c,b],np.array([fa,fc,fb]))
                if (cambia<0):
                    b = c
                    fb = fc
                else:
                    a = c
                    fa = fc
                tramo = np.abs(b-a)
                unafila.append(tramo)
                tabla.append(unafila)
                if vertabla==True:
                    print('  ',tramo)
                itera = itera + 1
            respuesta = c
            # Valida respuesta
            if (itera>=iteramax):
                respuesta = np.nan
    
        else: 
            print(' No existe cambio de signo entre f(a) y f(b)')
            print(' f(a) =',fa,',  f(b) =',fb) 
            respuesta=np.nan
        tabla = np.array(tabla,dtype=float)
        return(respuesta,tabla)
    
    # PROGRAMA #######################
    
    # INGRESO
    fx = lambda x: x**3 + 4*x**2 - 10
    
    a = 1
    b = 2
    tolera = 0.001
    
    # PROCEDIMIENTO
    [raiz,tabla] = biseccion_tabla(fx,a,b,tolera,vertabla=True)
    
    # SALIDA
    print('ra z en: ', raiz)
    
    # GRAFICA
    import matplotlib.pyplot as plt
    muestras = 21
    xi = np.linspace(a,b,muestras)
    fi = fx(xi)
    xc = tabla[:,1]
    yc = tabla[:,4]
    
    plt.plot(xi,fi, label='f(x)')
    plt.plot([a,b],[fx(a),fx(b)],'o',
             color='red',label='[[a,b],[f(a),f(b)]]')
    plt.scatter(xc,yc,color='orange', label='[c,f(c)]')
    plt.axhline(0)
    plt.xlabel('x')
    plt.ylabel('f(x)')
    plt.title('Bisecci n')
    plt.grid()
    plt.legend()
    #plt.show()
    
    # GRAFICA CON ANIMACION ------------
    import matplotlib.animation as animation
    
    xa = tabla[:,0]
    ya = tabla[:,3]
    xb = tabla[:,2]
    yb = tabla[:,5]
    xc = tabla[:,1]
    yc = tabla[:,4]
    
    # Inicializa parametros de trama/foto
    narchivo = 'Biseccion' # nombre archivo
    retardo = 700 # milisegundos entre tramas
    tramas = len(xa)
    
    # GRAFICA animada en fig_ani
    fig_ani, graf_ani = plt.subplots()
    ymax = np.max(fi)
    ymin = np.min(fi)
    deltax = np.abs(b-a)
    deltay = np.abs(ymax-ymin)
    graf_ani.set_xlim([a-0.05*deltax,b+0.05*deltax])
    graf_ani.set_ylim([ymin-0.05*deltay,ymax+0.05*deltay])
    linea0 = graf_ani.axhline(0, color='k')
    # Lineas y puntos base
    lineafx,= graf_ani.plot(xi,fi, label='f(x)')
    
    puntoa, = graf_ani.plot(xa[0], ya[0],'o',
                            color='red', label='a')
    puntob, = graf_ani.plot(xb[0], yb[0],'o',
                            color='green', label='b')
    puntoc, = graf_ani.plot(xc[0], yc[0],'o',
                            color='orange', label='c')
    lineaa, = graf_ani.plot([xa[0],xa[0]],
                            [0,ya[0]],color='red',
                            linestyle='dashed')
    lineab, = graf_ani.plot([xb[0],xb[0]],
                            [0,yb[0]],color='green',
                            linestyle='dashed')
    lineac, = graf_ani.plot([xc[0],xc[0]],
                            [0,yc[0]],
                            color='orange',
                            linestyle='dashed')
    linea_ab, = graf_ani.plot([xa[0],xb[0]],
                            [0,0],
                            color='yellow',
                            linestyle='dotted')
    # Configura gr fica
    graf_ani.set_title('Bisecci n')
    graf_ani.set_xlabel('x')
    graf_ani.set_ylabel('f(x)')
    graf_ani.legend()
    graf_ani.grid()
    
    # Cada nueva trama
    def unatrama(i,xa,ya,xb,yb,xc,yc):
        # actualiza cada punto
        puntoa.set_xdata([xa[i]]) 
        puntoa.set_ydata([ya[i]])
        puntob.set_xdata([xb[i]])
        puntob.set_ydata([yb[i]])
        puntoc.set_xdata([xc[i]])
        puntoc.set_ydata([yc[i]])
        # actualiza cada linea
        lineaa.set_ydata([ya[i], 0])
        lineaa.set_xdata([xa[i], xa[i]])
        lineab.set_ydata([yb[i], 0])
        lineab.set_xdata([xb[i], xb[i]])
        lineac.set_ydata([yc[i], 0])
        lineac.set_xdata([xc[i], xc[i]])
        linea_ab.set_ydata([0, 0])
        linea_ab.set_xdata([xa[i], xb[i]])
        return (puntoa, puntob, puntoc, lineaa, lineab, lineac,linea_ab)
    
    # Limpia trama anterior
    def limpiatrama():
        puntoa.set_ydata(np.ma.array(xa, mask=True))
        puntob.set_ydata(np.ma.array(xb, mask=True))
        puntoc.set_ydata(np.ma.array(xc, mask=True))
        lineaa.set_ydata(np.ma.array([0,0], mask=True))
        lineab.set_ydata(np.ma.array([0,0], mask=True))
        lineac.set_ydata(np.ma.array([0,0], mask=True))
        linea_ab.set_ydata(np.ma.array([0,0], mask=True))
        return (puntoa, puntob, puntoc, lineaa, lineab, lineac,linea_ab)
    
    # contador de tramas
    i = np.arange(0,tramas,1)
    ani = animation.FuncAnimation(fig_ani,unatrama,
                                  i ,
                                  fargs=(xa, ya,
                                         xb, yb,
                                         xc, yc),
                                  init_func=limpiatrama,
                                  interval=retardo,
                                  blit=True)
    # Graba Archivo GIFAnimado y video
    ani.save(narchivo+'_animado.gif', writer='pillow')
    #ani.save(narchivo+'_animado.mp4')
    plt.show()
    
    

    GIF animado: [ Bisección ] [ Posicion Falsa ] [ Newton-Raphson ] [ Punto Fijo ] [ Secante ]

    ..


    Método de la Posición Falsa con gráfico animado en Python

    Posicion Falsa animado GIF

    # Algoritmo de falsa posicion para raices
    # Los valores de [a,b] son seleccionados
    # desde la gráfica de la función
    # error = tolera
    
    import numpy as np
    
    def posicionfalsa_tabla(fx,a,b,tolera,iteramax = 20,
                            vertabla=False, precision=6):
        '''fx en forma numérica lambda
        Los valores de [a,b] son seleccionados
        desde la gráfica de la función
        error = tolera
        '''
        fa = fx(a)
        fb = fx(b)
        tramo = np.abs(b-a)
        itera = 0
        cambia = np.sign(fa)*np.sign(fb)
        tabla = []
        if cambia<0: # existe cambio de signo f(a) vs f(b)
            if vertabla==True:
                print('método de la Posición Falsa ')
                print('i', ['a','c','b'],[ 'f(a)', 'f(c)','f(b)'])
                print('  ','tramo')
                np.set_printoptions(precision)
    
            while (tramo >= tolera and itera<=iteramax):
                c = b - fb*(a-b)/(fa-fb)
                fc = fx(c)
                cambia = np.sign(fa)*np.sign(fc)
                unafila = [a,c,b,fa, fc, fb]
                if vertabla==True:
                    print(itera,np.array([a,c,b]),
                          np.array([fa,fc,fb]))
                if (cambia > 0):
                    tramo = np.abs(c-a)
                    a = c
                    fa = fc
                else:
                    tramo = np.abs(b-c)
                    b = c
                    fb = fc
                unafila.append(tramo)
                tabla.append(unafila)
                if vertabla==True:
                    print('  ',tramo)
                itera = itera + 1
            respuesta = c
            # Valida respuesta
            if (itera>=iteramax):
                respuesta = np.nan
        else: 
            print(' No existe cambio de signo entre f(a) y f(b)')
            print(' f(a) =',fa,',  f(b) =',fb) 
            respuesta=np.nan
        tabla = np.array(tabla,dtype=float)
        return(respuesta,tabla)
    
    # PROGRAMA ----------------------
    
    # INGRESO
    fx = lambda x: x**3 + 4*x**2 - 10
    
    a = 1
    b = 2
    tolera = 0.001
    
    # PROCEDIMIENTO
    [raiz,tabla] = posicionfalsa_tabla(fx,a,b,tolera,
                                       vertabla=True)
    # SALIDA
    print('raíz en: ', raiz)
    
    # GRAFICA
    import matplotlib.pyplot as plt
    muestras = 21
    xi = np.linspace(a,b,muestras)
    fi = fx(xi)
    xc = tabla[:,1]
    yc = tabla[:,4]
    
    plt.plot(xi,fi, label='f(x)')
    plt.plot([a,b],[fx(a),fx(b)],'o',
             color='red',label='[[a,b],[f(a),f(b)]]')
    plt.scatter(xc,yc,color='orange', label='[c,f(c)]')
    plt.axhline(0)
    plt.xlabel('x')
    plt.ylabel('f(x)')
    plt.title('Posición Falsa')
    plt.grid()
    plt.legend()
    #plt.show()
    
    # GRAFICA CON ANIMACION ------------
    #import matplotlib.pyplot as plt
    import matplotlib.animation as animation
    
    xa = tabla[:,0]
    ya = tabla[:,3]
    xc = tabla[:,1]
    yc = tabla[:,4]
    xb = tabla[:,2]
    yb = tabla[:,5]
    
    # Inicializa parametros de trama/foto
    narchivo = 'PosicionFalsa' # nombre archivo
    retardo = 700 # milisegundos entre tramas
    tramas = len(xa)
    
    # GRAFICA animada en fig_ani
    fig_ani, graf_ani = plt.subplots()
    graf_ani.set_xlim([a,b])
    graf_ani.set_ylim([np.min(fi),np.max(fi)])
    # Lineas y puntos base
    lineafx, = graf_ani.plot(xi,fi,label ='f(x)')
    
    puntoa, = graf_ani.plot(xa[0], ya[0],'o',
                            color='red', label='a')
    puntob, = graf_ani.plot(xb[0], yb[0],'o',
                            color='green', label='b')
    puntoc, = graf_ani.plot(xc[0], yc[0],'o',
                            color='orange', label='c')
    
    lineaab, = graf_ani.plot([xa[0],xb[0]],[ya[0],yb[0]],
                            color ='orange',
                            label='y=mx+b')
    lineac0, = graf_ani.plot([xc[0],xc[0]],[0,yc[0]],
                            color='magenta',
                            linestyle='dashed')
    
    # Configura gráfica
    linea0 = graf_ani.axhline(0, color='k')
    graf_ani.set_title('Posición Falsa')
    graf_ani.set_xlabel('x')
    graf_ani.set_ylabel('f(x)')
    graf_ani.legend()
    graf_ani.grid()
    
    # Cada nueva trama
    def unatrama(i,xa,ya,xc,yc,xb,yb):
        # actualiza cada punto, [] porque es solo un valor
        puntoa.set_xdata([xa[i]])
        puntoa.set_ydata([ya[i]])
        puntob.set_xdata([xb[i]])
        puntob.set_ydata([yb[i]])
        puntoc.set_xdata([xc[i]])
        puntoc.set_ydata([yc[i]])
        # actualiza cada linea
        lineaab.set_ydata([ya[i], yb[i]])
        lineaab.set_xdata([xa[i], xb[i]])
        lineac0.set_ydata([0, yc[i]])
        lineac0.set_xdata([xc[i], xc[i]])  
        return (puntoa, puntob, puntoc, lineaab,lineac0,)
    
    # Cada nueva trama
    def limpiatrama():
        puntoa.set_ydata(np.ma.array(xa, mask=True))
        puntob.set_ydata(np.ma.array(xb, mask=True))
        puntoc.set_ydata(np.ma.array(xc, mask=True))
        lineaab.set_ydata(np.ma.array([0,0], mask=True))
        lineac0.set_ydata(np.ma.array([0,0], mask=True))
        return (puntoa, puntob, puntoc, lineaab,lineac0,)
    
    # contador de tramas
    i = np.arange(0, tramas,1)
    ani = animation.FuncAnimation(fig_ani,unatrama,
                                  i ,
                                  fargs=(xa, ya,
                                         xc, yc,
                                         xb,yb),
                                  init_func=limpiatrama,
                                  interval=retardo,
                                  blit=True)
    # Graba Archivo GIFAnimado y video
    ani.save(narchivo+'_animado.gif', writer='pillow')
    #ani.save(narchivo+'.mp4')
    plt.show()
    

    GIF animado: [ Bisección ] [ Posicion Falsa ] [ Newton-Raphson ] [ Punto Fijo ] [ Secante ]
    ..


    Método de Newton-Raphson con gráfico animado en Python

    Newton Raphson GIF animado

    # Método de Newton-Raphson
    # Ejemplo 1 (Burden ejemplo 1 p.51/pdf.61)
    import numpy as np
    
    def newton_raphson_tabla(fx,dfx,xi, tolera, iteramax=100,
                       vertabla=False, precision=4):
        '''
        fx y dfx en forma numérica lambda
        xi es el punto inicial de búsqueda
        '''
        itera=0
        tramo = abs(2*tolera)
        tabla = []
        if vertabla==True:
            print('método de Newton-Raphson')
            print('i', ['xi','fi','dfi', 'xnuevo', 'tramo'])
            np.set_printoptions(precision)
        while (tramo>=tolera):
            fi = fx(xi)
            dfi = dfx(xi)
            xnuevo = xi - fi/dfi
            tramo = abs(xnuevo-xi)
            if vertabla==True:
                print(itera,np.array([xi,fi,dfi,xnuevo,tramo]))
    
            tabla.append([xi,fi,dfi,xnuevo,tramo])
            xi = xnuevo
            itera = itera + 1
    
        if itera>=iteramax:
            xi = np.nan
            print('itera: ',itera,
                  'No converge,se alcanzó el máximo de iteraciones')
        tabla = np.array(tabla,dtype=float)
        return(xi,tabla)
    
    # PROGRAMA ----------------------
    
    # INGRESO
    fx = lambda x: x**3 + 4*x**2 - 10
    dfx = lambda x: 3*(x**2) + 8*x
    
    a = 1
    b = 4
    x0 = 3
    tolera = 0.001
    
    # PROCEDIMIENTO
    [raiz,tabla] = newton_raphson_tabla(fx, dfx, x0,
                                 tolera, vertabla=True)
    # SALIDA
    print('raiz en :', raiz)
    
    # GRAFICA
    import matplotlib.pyplot as plt
    muestras = 21
    xi = np.linspace(a,b,muestras)
    fi = fx(xi)
    xc = tabla[:,3]
    yc = fx(xc)
    
    plt.plot(xi,fi, label='f(x)')
    plt.plot(x0,fx(x0),'o',
             color='red',label='[x0,f(x0)]')
    plt.scatter(xc,yc,color='orange', label='[c,f(c)]')
    plt.axhline(0)
    plt.xlabel('x')
    plt.ylabel('f(x)')
    plt.grid()
    plt.legend()
    #plt.show()
    
    # GRAFICA CON ANIMACION ------------
    #import matplotlib.pyplot as plt
    import matplotlib.animation as animation
    
    xa = tabla[:,0]
    ya = tabla[:,1]
    xb = tabla[:,3]
    dfi = tabla[:,2]
    # Aproximacion con tangente
    b0 = ya[0] - dfi[0]*x0
    tangentei = dfi[0]*xi + b0
    ci = -b0/dfi[0]
    
    # Inicializa parametros de trama/foto
    narchivo = 'NewtonRaphson' # nombre archivo
    retardo = 700 # milisegundos entre tramas
    tramas = len(xa)
    
    # GRAFICA animada en fig_ani
    fig_ani, graf_ani = plt.subplots()
    graf_ani.set_xlim([a,b])
    graf_ani.set_ylim([np.min(fi),np.max(fi)])
    # Lineas y puntos base
    lineafx, = graf_ani.plot(xi,fi,label ='f(x)')
    
    puntoa, = graf_ani.plot(xa[0], ya[0],'o',
                            color='red', label='x[i]')
    puntob, = graf_ani.plot(xb[0], 0,'o',
                            color='green', label='x[i+1]')
    
    lineatanx, = graf_ani.plot(xi,tangentei,
                               color='orange',label='tangente')
    lineaa, = graf_ani.plot([xa[0],xa[0]],
                            [ya[0],0], color='magenta',
                            linestyle='dashed')
    lineab, = graf_ani.plot([xb[0],xb[0]],
                             [0,fx(xb[0])], color='magenta',
                             linestyle='dashed')
    # Configura gráfica
    linea0 = graf_ani.axhline(0, color='k')
    graf_ani.set_title('Newton-Raphson')
    graf_ani.set_xlabel('x')
    graf_ani.set_ylabel('f(x)')
    graf_ani.legend()
    graf_ani.grid()
    
    # Cada nueva trama
    def unatrama(i,xa,ya,xb,dfi):
        # actualiza cada punto, [] porque es solo un valor
        puntoa.set_xdata([xa[i]]) 
        puntoa.set_ydata([ya[i]])
        puntob.set_xdata([xb[i]])
        puntob.set_ydata([0])
        # actualiza cada linea
        lineaa.set_ydata([ya[i], 0])
        lineaa.set_xdata([xa[i], xa[i]])
        lineab.set_ydata([0, fx(xb[i])])
        lineab.set_xdata([xb[i], xb[i]])
        # Aproximacion con tangente
        b0 = ya[i] - dfi[i]*xa[i]
        tangentei = dfi[i]*xi+b0
        lineatanx.set_ydata(tangentei)
        
        return (puntoa, puntob, lineaa, lineab,lineatanx,)
    
    # Limpia trama anterior
    def limpiatrama():
        puntoa.set_ydata(np.ma.array(xa, mask=True))
        puntob.set_ydata(np.ma.array(xb, mask=True))
        lineaa.set_ydata(np.ma.array([0,0], mask=True))
        lineab.set_ydata(np.ma.array([0,0], mask=True))
        lineatanx.set_ydata(np.ma.array(xi, mask=True))
        return (puntoa, puntob, lineaa, lineab,lineatanx,)
    
    # contador de tramas
    i = np.arange(0,tramas,1)
    ani = animation.FuncAnimation(fig_ani,unatrama,
                                  i ,
                                  fargs=(xa, ya,
                                         xb, dfi),
                                  init_func=limpiatrama,
                                  interval=retardo,
                                  blit=True)
    # Graba Archivo GIFAnimado y video
    ani.save(narchivo+'_animado.gif', writer='pillow')
    #ani.save(narchivo+'.mp4')
    plt.show()
    

    GIF animado: [ Bisección ] [ Posicion Falsa ] [ Newton-Raphson ] [ Punto Fijo ] [ Secante ]

    ..


    Método del Punto Fijo con gráfico animado en Python

    Punto Fijo GIF animadoInstrucciones en Python

    # Algoritmo de punto fijo, Tabla
    # Los valores de [a,b] son seleccionados
    # desde la gráfica de la función
    # error = tolera
    
    import numpy as np
    
    def puntofijo_tabla(gx,a,tolera, iteramax=20,
                        vertabla=True, precision=6):
        '''g(x) se obtiene al despejar una x de f(x)
        máximo de iteraciones predeterminado: iteramax
        si no converge hasta iteramax iteraciones
        la respuesta es NaN (Not a Number)
        '''
        itera = 0
        b = gx(a)
        tramo = abs(b-a)
        tabla = [[a,b,tramo]]
        if vertabla==True:
            print('método del Punto Fijo')
            print('i', ['xi','gi','tramo'])
            np.set_printoptions(precision)
            print(itera,np.array([a,b,tramo]))
        while(tramo>=tolera and itera<=iteramax):
            a = b
            b = gx(a)
            tramo = abs(b-a)
            itera = itera + 1
            if vertabla==True:
                print(itera,np.array([a,b,tramo]))
            tabla.append([a,b,tramo])
        respuesta = b
        # Valida respuesta
        if itera>=iteramax:
            respuesta = np.nan
            print('itera: ',itera,
                  'No converge,se alcanzó el máximo de iteraciones')
        tabla = np.array(tabla,dtype=float)
        return(respuesta,tabla)
    
    # PROGRAMA ----------------------
    
    # INGRESO
    fx = lambda x: np.exp(-x) - x
    gx = lambda x: np.exp(-x)
    
    a = 0
    b = 1
    tolera = 0.001
    
    # PROCEDIMIENTO
    [raiz,tabla] = puntofijo_tabla(gx,a,tolera, vertabla=True)
    
    # SALIDA
    print('raiz en :', raiz)
    
    # GRAFICA
    import matplotlib.pyplot as plt
    muestras = 21
    xi = np.linspace(a,b,muestras)
    fi = fx(xi)
    gi = gx(xi)
    yi = xi
    
    plt.plot(xi,fi, label='f(x)',
             linestyle='dashed')
    plt.plot(xi,gi, label='g(x)')
    plt.plot(xi,yi, label='y=x')
    
    plt.axvline(raiz, color='magenta',
                linestyle='dotted')
    plt.axhline(0)
    plt.xlabel('x')
    plt.ylabel('f(x)')
    plt.title('Punto Fijo')
    plt.grid()
    plt.legend()
    #plt.show()
    
    # GRAFICA CON ANIMACION ------------
    #import matplotlib.pyplot as plt
    import matplotlib.animation as animation
    
    xc = tabla[:,0]
    yc = tabla[:,1]
    
    # Inicializa parametros de trama/foto
    narchivo = 'PuntoFijo' # nombre archivo
    retardo = 700 # milisegundos entre tramas
    tramas = len(xc)
    
    # GRAFICA animada en fig_ani
    fig_ani, graf_ani = plt.subplots()
    dx = np.abs(b-a)
    dy = np.abs(gx(b)-gx(a))
    graf_ani.set_xlim([a-0.05*dx,b+0.05*dx])
    graf_ani.set_ylim([np.min(fi)-0.05*dy,np.max(fi)+0.05*dy])
    
    # Lineas y puntos base
    puntoa,  = graf_ani.plot(xc[0], yc[0], 'ro')
    puntob,  = graf_ani.plot(xc[0], xc[0], 'go') # y=x
    lineafx, = graf_ani.plot(xi,fi, color='blue',
                         linestyle='dashed', label='f(x)')
    lineagx, = graf_ani.plot(xi,gi, color='orange', label='g(x)')
    lineayx, = graf_ani.plot(xi,yi, color='green', label='y=x')
    linearaiz = graf_ani.axvline(raiz, color='magenta',linestyle='dotted')
    
    # Configura gráfica
    linea0 = graf_ani.axhline(0, color='k')
    graf_ani.set_title('Punto Fijo')
    graf_ani.set_xlabel('x')
    graf_ani.set_ylabel('f(x)')
    graf_ani.legend()
    graf_ani.grid()
    
    # Cada nueva trama
    def unatrama(i,xc,yc):
        # actualiza cada punto, [] porque es solo un valor
        puntoa.set_xdata([xc[i]])
        puntoa.set_ydata([yc[i]])
        puntob.set_xdata([xc[i]]) # y=x
        puntob.set_ydata([xc[i]])
        
        # actualiza cada flecha
        dx = xc[i+1]-xc[i]
        dy = yc[i]-xc[i]
        flecha01 = graf_ani.arrow(xc[i],xc[i], 0,dy,
                  length_includes_head = True,
                  head_width = 0.05*abs(dy),
                  head_length = 0.1*abs(dy))
        flecha02 = graf_ani.arrow(xc[i],yc[i], dx,0,
                  length_includes_head = True,
                  head_width = 0.05*abs(dx),
                  head_length = 0.1*abs(dx))
        return (puntoa, puntob, flecha01, flecha02)
    
    # Limpia trama anterior
    def limpiatrama():
        puntoa.set_ydata(np.ma.array([xc[0]], mask=True))
        puntob.set_ydata(np.ma.array([xc[0]], mask=True))
        return (puntoa, puntob)
    
    # contador de tramas
    i = np.arange(0, tramas-1,1)
    ani = animation.FuncAnimation(fig_ani,unatrama,
                                  i ,
                                  fargs=(xc, yc),
                                  init_func=limpiatrama,
                                  interval=retardo,
                                  blit=True)
    # Graba Archivo GIFAnimado y video
    ani.save(narchivo+'_animado.gif', writer='pillow')
    #ani.save(narchivo+'.mp4')
    plt.show()
    

    GIF animado: [ Bisección ] [ Posicion Falsa ] [ Newton-Raphson ] [ Punto Fijo ] [ Secante ]

    ..


    Método de la Secante con gráfico animado en Python

    Secante Metodo animado

    Instrucciones en Python

    # Método de la secante
    # Ejemplo 1 (Burden ejemplo 1 p.51/pdf.61)
    import numpy as np
    
    def secante_raiz_tabla(fx,a,b,tolera, iteramax=20,
                     vertabla=True, precision=6):
        '''fx en forma numérica lambda
        Los valores de [a,b] son seleccionados
        desde la gráfica de la función
        '''
        xi_1 = a
        xi = b
        itera = 0
        tramo = np.abs(xi-xi_1)
        tabla = []
        if vertabla==True:
            print('método de la Secante')
            print('i','[ x[i-1], xi, x[i+1], f[i-1], fi ]','tramo')
            np.set_printoptions(precision)
        while not(tramo<tolera or itera>iteramax):
            fi_1 = fx(xi_1)
            fi = fx(xi)
            xi1 = xi-fi*(xi_1 - xi)/(fi_1-fi)
            tramo = np.abs(xi1-xi)
            if vertabla==True:
                print(itera,np.array([xi_1,xi,xi1,fi_1,fi]),tramo)
            tabla.append([xi_1,xi,xi1,fi_1,fi])
            xi_1 = xi
            xi = xi1
            itera = itera + 1
        if itera>=iteramax:
            xi = np.nan
            print('itera: ',itera,
                  'No converge,se alcanzó el máximo de iteraciones')
        respuesta = xi
        tabla = np.array(tabla,dtype=float)
        return(respuesta,tabla)
    
    # PROGRAMA ----------------------
    
    # INGRESO
    fx = lambda x: x**3 + 4*x**2 - 10
    
    a = 1
    b = 4
    c = (a+b)/2
    tolera = 0.001
    tramos = 100
    
    # PROCEDIMIENTO
    [raiz,tabla] = secante_raiz_tabla(fx,c,b,tolera,
                                      vertabla=True)
    # SALIDA
    print('raiz en :', raiz)
    
    # GRAFICA
    import matplotlib.pyplot as plt
    muestras = 21
    xi = np.linspace(a,b,muestras)
    fi = fx(xi)
    xc = tabla[:,2]
    yc = fx(xc)
    
    plt.plot(xi,fi, label='f(x)')
    plt.plot([a,b],[fx(a),fx(b)],'o',
             color='red',label='[x0,f(x0)]')
    plt.scatter(xc,yc,color='orange', label='[c,f(c)]')
    plt.axhline(0)
    plt.xlabel('x')
    plt.ylabel('f(x)')
    plt.grid()
    plt.legend()
    #plt.show()
    
    
    # GRÁFICO CON ANIMACION ######
    import matplotlib.animation as animation
    
    xa = tabla[:,0]
    ya = tabla[:,3]
    xb = tabla[:,1]
    yb = tabla[:,4]
    xc = tabla[:,2]
    
    # Inicializa parametros de trama/foto
    narchivo = 'SecanteMetodo' # nombre archivo
    retardo = 700 # milisegundos entre tramas
    tramas = len(xa)
    
    # GRAFICA animada en fig_ani
    fig_ani, graf_ani = plt.subplots()
    graf_ani.set_xlim([a,b])
    graf_ani.set_ylim([np.min(fi),np.max(fi)])
    
    # Lineas y puntos base
    lineafx, = graf_ani.plot(xi,fi,label ='f(x)')
    
    puntoa, = graf_ani.plot(xa[0], ya[0],'o',
                            color='red', label='x[i-1]')
    puntob, = graf_ani.plot(xb[0], yb[0],'o',
                            color='green', label='x[i]')
    puntoc, = graf_ani.plot(xc[0], yc[0],'o',
                            color='orange', label='x[i+1]')
    
    lineatan1, = graf_ani.plot([xa[0],xb[0]],
                               [ya[0],yb[0]],
                               color='orange',label='secante ac')
    lineatan2, = graf_ani.plot([xc[0],xb[0]],
                               [0,yb[0]],
                               color='orange',label='secante cb')
    linea_a, = graf_ani.plot([xa[0],xa[0]],
                             [ya[0],0], color='magenta',
                             linestyle='dashed')
    linea_b, = graf_ani.plot([xb[0],xb[0]],
                             [0,yb[0]], color='magenta',
                             linestyle='dashed')
    # Configura gráfica
    linea0 = graf_ani.axhline(0, color='k')
    graf_ani.set_title('Método de la Secante')
    graf_ani.set_xlabel('x')
    graf_ani.set_ylabel('f(x)')
    graf_ani.legend()
    graf_ani.grid()
    
    # Cada nueva trama
    def unatrama(i,xa,ya,xb,yb,xc):
        # actualiza cada punto, [] porque es solo un valor
        puntoa.set_xdata([xa[i]]) 
        puntoa.set_ydata([ya[i]])
        puntob.set_xdata([xb[i]])
        puntob.set_ydata([yb[i]])
        puntoc.set_xdata([xc[i]])
        puntoc.set_ydata([0])
        # actualiza cada linea
        linea_a.set_ydata([ya[i], 0])
        linea_a.set_xdata([xa[i], xa[i]])
        linea_b.set_ydata([0, yb[i]])
        linea_b.set_xdata([xb[i], xb[i]])
        lineatan1.set_ydata([ya[i], 0])
        lineatan1.set_xdata([xa[i], xc[i]])
        lineatan2.set_ydata([0, yb[i]])
        lineatan2.set_xdata([xc[i], xb[i]])
    
        return (puntoa, puntob, puntoc,
                linea_a, linea_b,
                lineatan1, lineatan2,)
    
    # Limpia trama anterior
    def limpiatrama():
        puntoa.set_ydata(np.ma.array(xa, mask=True))
        puntob.set_ydata(np.ma.array(xb, mask=True))
        puntoc.set_ydata(np.ma.array(xc, mask=True))
        linea_a.set_ydata(np.ma.array([0,0], mask=True))
        linea_b.set_ydata(np.ma.array([0,0], mask=True))
        lineatan1.set_ydata(np.ma.array([0,0], mask=True))
        lineatan2.set_ydata(np.ma.array([0,0], mask=True))
        return (puntoa, puntob, puntoc,
                linea_a, linea_b,
                lineatan1, lineatan2,)
    
    # contador de tramas
    i = np.arange(0,tramas,1)
    ani = animation.FuncAnimation(fig_ani,unatrama,
                                  i ,
                                  fargs=(xa, ya,
                                         xb, yb,
                                         xc),
                                  init_func=limpiatrama,
                                  interval=retardo,
                                  blit=True)
    # Graba Archivo GIFAnimado y video
    ani.save(narchivo+'_animado.gif', writer='pillow')
    #ani.save(narchivo+'.mp4')
    plt.show()
    

    GIF animado: [ Bisección ] [ Posicion Falsa ] [ Newton-Raphson ] [ Punto Fijo ] [ Secante ]

  • 2.6 Sistemas de Ecuaciones no lineales - Newton-Raphson

    Referencia: Chapra 6.5 p162, Chapra Ejercicio 6.11 p166

    Con el método de Newton-Raphson para múltiples ecuaciones, determine las raíces para:

    x^2+xy =10 y + 3xy^2 = 57

    Observe que un par correcto de raíces es x=2 y y=3.
    Use como valores iniciales x=1.5, y=3.5

    Planteamiento

    Las ecuaciones se expresan de la forma f(x,y) = 0

    x^2+xy -10 = 0 y + 3xy^2 -57 = 0

    Se puede usar extensiones de los métodos abiertos para resolver ecuaciones simples, por ejemplo Newton-Raphson.

    u_{i+1} = u_i + (x_{i+1}-x_i)\frac{\partial u_i}{\partial x} + (y_{i+1}-y_i) \frac{\partial u_i}{\partial y} v_{i+1} = v_i + (x_{i+1}-x_i)\frac{\partial v_i}{\partial x} + (y_{i+1}-y_i) \frac{\partial v_i}{\partial y}

    ecuaciones que se pueden reordenar y encontrar la solución a partir de la matriz Jacobiano.

    Instrucciones en Python

    Usando un algoritmo para resolver el Jacobiano y estimar los puntos luego de cada iteración se obtienen:

    iteración:  1
    Jacobiano con puntos iniciales: 
    [ 6.5   1.5 ]
    [           ]
    [36.75  32.5]
    determinante:  156.12499999999994
    puntos xi,yi: 2.03602882305845 2.84387510008006
    error: 0.656124899919936
    iteración:  2
    Jacobiano con puntos iniciales: 
    [6.91593274619696  2.03602882305845]
    [                                  ]
    [24.2628767545662  35.7412700376474]
    determinante:  197.78430344142245
    puntos xi,yi: 1.99870060905582 3.00228856292451
    error: 0.158413462844444
    iteración:  3
    Jacobiano con puntos iniciales: 
    [6.99968978103616  1.99870060905582]
    [                                  ]
    [27.0412098452019  37.0040558756713]
    determinante:  204.96962918261596
    puntos xi,yi: 1.99999998387626 2.99999941338891
    error: 0.00228914953559523
    iteración:  4
    Jacobiano con puntos iniciales: 
    [6.99999938114143  1.99999998387626]
    [                                  ]
    [26.9999894410015  36.9999926704397]
    determinante:  204.9999473486533
    puntos xi,yi: 1.99999999999998 3.00000000000008
    error: 5.86611161867978e-7
    Resultado: 
    1.99999999999998 3.00000000000008
    

    Algoritmo presentado para dos ecuaciones y dos incógnitas, en la unidad 3 se puede ampliar la propuesta. Revisar el método de Gauss-Seidel y Jacobi.

    # Ejercicio Chapra Ej:6.11
    # Sistemas de ecuaciones no lineales
    # con método de Newton Raphson para xy
    
    import numpy as np
    import sympy as sym
    
    def matrizJacobiano(variables, funciones):
        n = len(funciones)
        m = len(variables)
        # matriz Jacobiano inicia con ceros
        Jcb = sym.zeros(n,m)
        for i in range(0,n,1):
            unafi = sym.sympify(funciones[i])
            for j in range(0,m,1):
                unavariable = variables[j]
                Jcb[i,j] = sym.diff(unafi, unavariable)
        return Jcb
    
    # PROGRAMA ----------
    # INGRESO
    x = sym.Symbol('x')
    y = sym.Symbol('y')
    
    f1 = x**2 + x*y - 10
    f2 = y + 3*x*(y**2)-57
    
    x0 = 1.5
    y0 = 3.5
    
    tolera = 0.0001
    
    # PROCEDIMIENTO
    funciones = [f1,f2]
    variables = [x,y]
    n = len(funciones)
    m = len(variables)
    
    Jxy = matrizJacobiano(variables, funciones)
    
    # valores iniciales
    xi = x0
    yi = y0
    
    # tramo inicial, mayor que tolerancia
    itera = 0
    tramo = tolera*2
    
    while (tramo>tolera):
        J = Jxy.subs([(x,xi),(y,yi)])
    
        # determinante de J
        Jn = np.array(J,dtype=float)
        determinante =  np.linalg.det(Jn)
    
        # iteraciones
        f1i = f1.subs([(x,xi),(y,yi)])
        f2i = f2.subs([(x,xi),(y,yi)])
    
        numerador1 = f1i*Jn[n-1,m-1]-f2i*Jn[0,m-1]
        xi1 = xi - numerador1/determinante
        numerador2 = f2i*Jn[0,0]-f1i*Jn[n-1,0]
        yi1 = yi -numerador2/determinante
        
        tramo = np.max(np.abs([xi1-xi,yi1-yi]))
        xi = xi1
        yi = yi1
    
        itera = itera +1
        print('iteración: ',itera)
        print('Jacobiano con puntos iniciales: ')
        sym.pprint(J)
        print('determinante: ', determinante)
        print('puntos xi,yi:',xi,yi)
        print('error:',tramo)
        
    # SALIDA
    print('Resultado: ')
    print(xi,yi)
    
  • 2.5.1 Método de la Secante - Ejemplo con Python

    [ Secante ] [ Ejercicio ] [ Analítico ] [ Algoritmo ] [ función ]
    ..


    1. Ejercicio

    Referencia: Burden 2.1 ejemplo 1 p38

    La ecuación mostrada tiene una raíz en el intervalo [1,2], ya que f(1) = -5 y f(2) = 14. Muestre los resultados parciales del algoritmo de la secante con una tolerancia de 0.0001

    f(x) = x^3 + 4x^2 -10 =0

    Secante Metodo animadoLa gráfica se realiza iniciando con los valores 2.5 y 4 para observar mejor el efecto gráfico en las iteraciones.

    [ Secante ] [ Ejercicio ] [ Analítico ] [ Algoritmo ] [función]
    ..


    2. Desarrollo Analítico

    f(x) = x^3 + 4x^2 -10 =0 x_{i+1}= x_i - f(x_i)\frac{(x_{i-1} - x_i)}{f(x_{i-1}) - f(x_i)}

    Se probará con valores iniciales dentro del tramo [1,2], tolera = 0.001

    itera = 0

    X-1 = 1,  X0 =2,

    f(1) = (1)^3 + 4(1)^2 -10 = -5 f(2) = (2)^3 + 4(2)^2 -10 =14 x_{1}= 2 - 14\frac{(1 - 2)}{(-5 - 14)} = 1.2632 errado = |1.2632 - 2| = 0.7368

    itera = 1

    X0 = 2,  X1 = 1.2632

    f(2) =14 f(1.2632) = ( 1.2632)^3 + 4( 1.2632)^2 -10 =-1.6023 x_{2}= 1.2632 - (-1.6023)\frac{(2 - 1.2632)}{(14 -(-1.6023))} =1.3388 errado = |1.3388 - 1.2632 | = 0.0756

    itera = 2

    X1 =1.2632, X2 =1.3388

    f(1.2632) = -1.6023 f(1.3388) = (1.3388)^3 + 4(1.3388)^2 -10 =-0.4304 x_{3}= 1.3388 - (-0.4304)\frac{(1.2632 - 1.3388)}{(-1.6023 -(-0.4304))} = 1.3666 errado = | 1.3388- 1.3666| =0.0277

    desarrollando una tabla con el algoritmo se tiene:

    método de la Secante
    i [ x[i-1], xi, x[i+1], f[i-1], fi ] tramo
    0 [ 1.      2.      1.2632 -5.     14.    ] 0.736842105263158
    1 [ 2.      1.2632  1.3388 14.     -1.6023] 0.0756699440909967
    2 [ 1.2632  1.3388  1.3666 -1.6023 -0.4304] 0.027788555891506528
    3 [ 1.3388  1.3666  1.3652 -0.4304  0.0229] 0.001404492087488718
    4 [ 1.3666e+00  1.3652e+00  1.3652e+00  2.2909e-02 -2.9907e-04] 1.809847900258177e-05
    raíz:  1.3652300011108591
    tramo: 1.809847900258177e-05
    itera: 5

    [ Secante ] [ Ejercicio ] [ Analítico ] [ Algoritmo ] [ función ]
    ..


    3. Algoritmo en Python

    Para identificar los puntos consecutivos con variables simples, se usa la siguiente conversión:

    xi-1 xi xi+1
    xa xb xc

    Instrucciones en Python

    # Método de secante
    import numpy as np
    
    # INGRESO
    fx = lambda x: x**3 + 4*x**2 - 10
    a = 1 # intervalo de búsqueda
    b = 2
    tolera = 0.001
    iteramax = 20
    
    # PROCEDIMIENTO
    xa = a
    xb = b
    itera = 0
    tramo = 2*tolera
    while tramo>tolera and itera<iteramax:
        fa = fx(xa)
        fb = fx(xb)
        xc = xb - fb*(xa - xb)/(fa - fb)
        tramo = abs(xc - xb)
        xa = xb
        xb = xc
        itera = itera + 1
    
    if itera>=iteramax: # revisa convergencia
        xc = np.nan
    
    # SALIDA
    print('raiz:',xc)
    print('tramo:',tramo)
    print('itera:',itera)
    

    [ Secante ] [ Ejercicio ] [ Analítico ] [ Algoritmo ] [ función ]
    ..


    4. Función en Python

    Una función resumida, se recomienda realizar la validación de cambio de signo entre [a,b]

    # Método de secante
    import numpy as np
    
    def secante_raiz(fx,a,b,tolera, iteramax=20,
                     vertabla=True, precision=6):
        '''fx en forma numérica lambda
        Los valores de [a,b] son seleccionados
        desde la gráfica de la función
        '''
        xa = a
        xb = b
        itera = 0
        tramo = np.abs(xb-xa)
        if vertabla==True:
            print('método de la Secante')
            print('i','[ x[i-1], xi, x[i+1], f[i-1], fi ]','tramo')
            np.set_printoptions(precision)
        while not(tramo<tolera or itera>iteramax):
            fa = fx(xa)
            fb = fx(xb)
            xc = xb - fb*(xa - xb)/(fa - fb)
            tramo = abs(xc - xb)
            if vertabla==True:
                print(itera,np.array([xa,xb,xc,fa,fb]),tramo)
            xa = xb
            xb = xc
            itera = itera + 1
        if itera>=iteramax:
            xc = np.nan
            print('itera: ',itera,
                  'No converge,se alcanzó el máximo de iteraciones')
        respuesta = xc
        
        return(respuesta)
    
    # INGRESO
    fx = lambda x: x**3 + 4*x**2 - 10
    a = 1
    b = 2
    tolera = 0.001
    
    # PROCEDIMIENTO
    respuesta = secante_raiz(fx,a,b,tolera,
                             vertabla=True,precision=4)
    # SALIDA
    print('raíz: ', respuesta)
    

    5. Función en librería Scipy.optimize.newton - Secante

    El método de la secante se encuentra implementado en Scipy en la forma de algoritmo de newton, que al no incluir como parámetro de la función para la derivada de f(x), usa el método de la secante:

    >>> import scipy as sp
    >>> sp.optimize.newton(fx,xa, tol=tolera)
    1.3652320383201266

    https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.newton.html


    [ Secante ] [ Ejercicio ] [ Analítico ] [ Algoritmo ] [ función ]

  • 2.4.1 Método de Newton-Raphson - Ejemplo con Python

    [ Newton-Raphson ] [ Ejercicio ] [ Analítico ] [ Algoritmo ] [gráf] [función]
    ..


    1. Ejercicio

    ReferenciaBurden 2.1 ejemplo 1 p38

    La ecuación mostrada tiene una raíz en [1,2], ya que f(1)=-5 y f(2)=14.
    Muestre los resultados parciales del algoritmo de Newton-Raphson con una tolerancia de 0.0001

    f(x) = x^3 + 4x^2 -10 =0

    Newton Raphson GIF animado
    [ Newton-Raphson ] [ Ejercicio ] [ Analítico ] [ Algoritmo ] [gráf] [función]
    ..


    2. Desarrollo Analítico

    El método requiere  obtener la derivada f'(x) de la ecuación para el factor del denominador.

    f(x) = x^3 + 4x^2 -10 f'(x) = 3x^2 + 8x x_{i+1} = x_i -\frac{f(x_i)}{f'(x_i)}

    Para el desarrollo se inicia la búsqueda desde un punto en el intervalo [1,2], por ejemplo el extremo derecho, x1=2.

    iteración 1

    f(2) = (2)^3 + 4(2)^2 -10 = 14 f'(2) = 3(2)^2 + 8(2) = 28 x_{2} = 2 -\frac{14}{28} = 1.5 tramo = |2 -1.5| = 0.5

    iteración 2

    f(1.5) = (1.5)^3 + 4(1.5)^2 -10 = 2.375 f'(1.5) = 3(1.5)^2 + 8(1.5) = 18.75 x_{3} = 1.5 -\frac{2.375}{18.75} = 1.3733 tramo = |1.5 -1.3733| = 0.1267

    iteración 3

    f(1.3733) = (1.3733)^3 + 4(1.3733)^2 -10 = 0.1337 f'(1.3733) = 3(1.3733)^2 + 8(1.3733) = 16.6442 x_{4} = 1.3733 -\frac{0.1337}{16.6442} =1.3652 tramo = |1.3733 -1.3652| = 0.0081

    La tabla resume los valores de las iteraciones

    Método de Newton-Raphson
    iteración xi xnuevo tramo
    1 2 1.5 0.5
    2 1.5 1.3733 0.1267
    3 1.3733 1.3653 0.0081
    4 ...

    Observe que el error representado por el tramo se va reduciendo entre cada iteración. Se debe repetir las iteraciones hasta que el error sea menor al valor tolerado.

    Las demás iteraciones se dejan como tarea

    [ Newton-Raphson ] [ Ejercicio ] [ Analítico ] [ Algoritmo ] [gráf] [función]
    ..


    3. Algoritmo con Python

    El método de Newton-Raphson se implementa como algoritmo básico en Python

    Se muestra el resultado del algoritmo luego de que el tramo alcance un valor menor que tolera.

    raiz en:  1.3652300139161466
    con error de:  3.200095847999407e-05
    

    A lo expuesto en el video, se añade el control de iteraciones "iteramax" por si se da el caso que el algoritmo no es convergente.

    # Método de Newton-Raphson
    import numpy as np
    
    # INGRESO
    fx  = lambda x: x**3 + 4*(x**2) - 10
    dfx = lambda x: 3*(x**2) + 8*x
    
    x0 = 2
    tolera = 0.001
    iteramax = 100
    
    # PROCEDIMIENTO
    itera = 0
    tramo = abs(2*tolera)
    xi = x0
    while (tramo>=tolera and itera<iteramax):
        fi = fx(xi)
        dfi = dfx(xi)
        xnuevo = xi - fi/dfi
        tramo = abs(xnuevo-xi)
        xi = xnuevo
        itera = itera + 1
    
    if itera>=iteramax:
        xi = np.nan
    
    # SALIDA
    print('raiz en: ', xi)
    print('con error de: ',tramo)
    

    [ Newton-Raphson ] [ Ejercicio ] [ Analítico ] [ Algoritmo ] [gráf] [función]
    ..


    4. Gráfica en Python

    La gráfica presentada para revisar f(x) se realiza con las instrucciones:

    # GRAFICA
    import matplotlib.pyplot as plt
    a = 1
    b = 2
    muestras = 21
    
    xj = np.linspace(a,b,muestras)
    fj = fx(xj)
    plt.plot(xj,fj, label='f(x)')
    plt.plot(xi,0, 'o')
    plt.axhline(0)
    plt.xlabel('x')
    plt.ylabel('f(x)')
    plt.grid()
    plt.legend()
    plt.show()
    

    [ Newton-Raphson ] [ Ejercicio ] [ Analítico ] [ Algoritmo ] [gráf] [función]
    ..


    5. Algoritmo en Python como Función

    Se convierte el algoritmo a una función, con partes para ver la tabla, y se obtienen los siguientes resultados:

    i ['xi', 'fi', 'dfi', 'xnuevo', 'tramo']
    0 [ 2.  14.  28.   1.5  0.5]
    1 [ 1.5     2.375  18.75    1.3733  0.1267]
    2 [1.3733e+00 1.3435e-01 1.6645e+01 1.3653e+00 8.0713e-03]
    3 [1.3653e+00 5.2846e-04 1.6514e+01 1.3652e+00 3.2001e-05]
    raíz en:  1.3652300139161466
    

    Instrucciones en Python

    # Ejemplo 1 (Burden ejemplo 1 p.51/pdf.61)
    
    import numpy as np
    import matplotlib.pyplot as plt
    
    def newton_raphson(fx,dfx,xi, tolera, iteramax=100,
                       vertabla=False, precision=4):
        '''fx y dfx en forma numérica lambda
        xi es el punto inicial de búsqueda
        '''
        itera=0
        tramo = abs(2*tolera)
        if vertabla==True:
            print('método de Newton-Raphson')
            print('i', ['xi','fi','dfi', 'xnuevo', 'tramo'])
            np.set_printoptions(precision)
        while (tramo>=tolera):
            fi = fx(xi)
            dfi = dfx(xi)
            xnuevo = xi - fi/dfi
            tramo = abs(xnuevo-xi)
            if vertabla==True:
                print(itera,np.array([xi,fi,dfi,xnuevo,tramo]))
            xi = xnuevo
            itera = itera + 1
    
        if itera>=iteramax:
            xi = np.nan
            print('itera: ',itera,
                  'No converge,se alcanzó el máximo de iteraciones')
    
        return(xi)
    
    # INGRESO
    fx  = lambda x: x**3 + 4*(x**2) - 10
    dfx = lambda x: 3*(x**2) + 8*x
    
    x0 = 2
    tolera = 0.001
    
    # PROCEDIMIENTO
    respuesta = newton_raphson(fx,dfx,x0, tolera, vertabla=True)
    # SALIDA
    print('raíz en: ', respuesta)
    

    La gráfica se la puede añadir usando las instrucciones dadas en el algoritmo básico realizado al inicio par ala comprensión del método.

    [ Newton-Raphson ] [ Ejercicio ] [ Analítico ] [ Algoritmo ] [gráf] [función]


    6. Función en librería scipy.optimize.newton

    El método de Newton-Raphson se encuentra implementado en la librería  Scipy, que también puede ser usado de la forma:

    >>> import scipy as sp
    >>> sp.optimize.newton(fx,x0, fprime=dfx, tol = tolera)
    1.3652300139161466
    >>> 
    

    https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.newton.html


    Tarea

    Calcule la raíz de f(x) = e-x - x, empleando como valor inicial x0 = 0

    • Revisar las modificaciones si se quiere usar la forma simbólica de la función y obtener la derivada con Sympy.

    [ Newton-Raphson ] [ Ejercicio ] [ Analítico ] [ Algoritmo ] [gráf] [función]

  • 2.3.1 Método del Punto fijo - Ejemplo con Python

    [ Punto fijo ] [ Ejercicio ] [ Analítico ] [ Algoritmo ] [ gráfica ] [ función ]
    ..


    1. Ejercicio

    Referencia: Burden 2.2 p41, Chapra 6.1 p143, Rodríguez 3.2 p44

    Encontrar la solución a la ecuación, usando el método del punto fijo, considerando tolerancia de 0.001

    f(x): e^{-x} - x = 0

    Punto Fijo 01a_GIF

    [ Punto fijo ] [ Ejercicio ] [ Analítico ] [ Algoritmo ] [ gráfica ] [ función ]

    ..


    2. Desarrollo Analítico

    Al igual que los métodos anteriores, es conveniente determinar el intervalo [a,b] donde es posible evaluar f(x). Se revisa si hay cambio de signo en el intervalo para buscar una raíz. Para el ejemplo, el rango de observación será [0,1], pues f(0)=1 es positivo y f(1)=-0.63 es negativo.Punto Fijo Balanza animado

    Para el punto fijo, se reordena la ecuación para para tener una ecuación con la variable independiente separada. Se obtiene por un lado la recta identidad y=x, por otro se tiene la función g(x).

    f(x): e^{-x} - x = 0 x = e^{-x}

    g(x) = e^{-x}punto fijo 01b

    Se buscará la intersección entre las dos expresiones .

    Se puede iniciar la búsqueda por uno de los extremos del rango [a,b].

    iteración 1

    - iniciando desde el extremo izquierdo c=a,

    c = 0

    - se determina el valor nuevo de gc=g(c) ,

    gc = g(0) = e^{-0} = 1

    - se determina la diferencia de la aproximación o error = |gc-c|

    tramo = |1-0| = 1

    - se proyecta en la recta identidad, como el nuevo punto de evaluación
    c = gc.

    - se repite el proceso para el nuevo valor de c, hasta que el error sea menor al tolerado. En caso que el proceso no converge, se utiliza un contador de iteraciones máximo, para evitar tener un lazo infinito.

    iteración 2

    c = 1 gc = g(1) = e^{-1} = 0.3678 tramo =|0.3678 - 1|= 0.6322

    iteración 3

    c = 0.3678 gc = e^{-0.3678} = 0.6922 tramo =|0.6922-0.3678|= 0.3244

    La tabla resume los valores de las iteraciones

    Método del punto fijo
    iteración c gc= g(c) |tramo|
    1 0 1.0 1
    2 1.0 0.3678 0.6322
    3 0.3678 0.6922 0.3244
    4 0.6922 ...
    5

    El proceso realizado en la tabla se muestra en la gráfica, para una función que converge.

    Cuando el método no converge

    Cuando la 'x' a separar en la expresión f(x) es otra, el resultado no siempre será convergente. Si para el ejercicio anterior se hubiese despejado la 'x' en el exponencial, la expresión g(x) se obtiene como:

    f(x): e^{-x} - x = 0 e^{-x} = x \ln\Big(e^{-x}\Big) = \ln(x) -x= \ln(x) x= -\ln(x)

    Al revisar la gráfica del algoritmo se observa que también se cumple que la raíz de f(x) coincide en el valor x con la intersección entre la identidad y g(x).

    punto fijo No Converge

    Sin embargo al realizar las iteraciones se tiene que:

    iteración 1
    c = 0.5
    gc = -ln(0.5) = 0.6931
    tramo = | 0.6931-0.5| =0.1931

    iteración 2
    c = 0.6931
    gc = -ln(0.6931) = 0.3665
    tramo = | 0.3665-0.6931| = 0.3266

    iteración 3
     c = 0.3665
    gc = -ln(0.3665) = 1.0037
    tramo = | 1.0037-0.3665| = 0.6372

    Se observa que el tramo o error aumenta en cada iteración, con lo que se concluye que de esta forma, la aplicación del método no es convergente.

    [ Punto fijo ] [ Ejercicio ] [ Analítico ] [ Algoritmo ] [ gráfica ] [ función ]
    ..


    3. Algoritmo en Python

    El algoritmo en Python del video se adjunta para seguimiento. Se requiere la función gx, el punto inicial y la tolerancia, la variable de número de iteraciones máxima, iteramax, permite controlar la convergencia de la función con el método.

    El resultado del algoritmo se presenta como:

    raíz en:  0.5669089119214953
    errado :  0.0006477254067881466
    itera  :  14

    Instrucciones en Python

    # Algoritmo de punto fijo
    # error = tolera
    import numpy as np
    
    # INGRESO
    fx = lambda x: np.exp(-x) - x
    gx = lambda x: np.exp(-x)
    
    c = 0  # valor inicial
    tolera = 0.001
    iteramax = 40
    
    # PROCEDIMIENTO
    tramo = 2*tolera # al menos una iteracion
    i = 0  # iteración inicial
    while tramo>=tolera and i<iteramax:
        gc = gx(c)
        tramo = abs(gc-c)
        c = gc
        i = i + 1
    
    if (i>=iteramax): # Valida convergencia
        c = np.nan
    
    # SALIDA
    print('raíz en: ', c)
    print('errado : ', tramo)
    print('itera  : ', i)
    

    Para obtener la gráfica básica se determinan los puntos para cada función fx y gx. Como los valores de c y gc cambiaron durante el algoritmo, para la siguiente sección es necesario volver a escribirlos u obtener una copia de los valores en otra variable para reutilizarlos en ésta sección.

    [ Punto fijo ] [ Ejercicio ] [ Analítico ] [ Algoritmo ] [ gráfica ] [ función ]
    ..


    4. Gráfica en Python

    Se añaden las siguiente instrucciones al algoritmo anterior:

    # GRAFICA
    import matplotlib.pyplot as plt
    
    a = 0  # intervalo de gráfica en [a,b]
    b = 1
    muestras = 21
    
    # calcula los puntos para fx y gx
    xi = np.linspace(a,b,muestras)
    fi = fx(xi)
    gi = gx(xi)
    yi = xi
    
    plt.plot(xi,fi, label='f(x)',
             linestyle='dashed')
    plt.plot(xi,gi, label='g(x)')
    plt.plot(xi,yi, label='y=x')
    
    plt.axvline(c, color='magenta',
                linestyle='dotted')
    plt.axhline(0)
    plt.xlabel('x')
    plt.ylabel('f(x)')
    plt.title('Punto Fijo')
    plt.grid()
    plt.legend()
    plt.show()
    

    [ Punto fijo ] [ Ejercicio ] [ Analítico ] [ Algoritmo ] [ gráfica ] [ función ]
    ..


    5. Algoritmo en Python como Función

    El resultado del algoritmo como una función y mostrando la tabla de resultados por iteraciones es:

    método del Punto Fijo
    i ['xi', 'gi', 'tramo']
    0 [0. 1. 1.]
    1 [1.       0.367879 0.632121]
    2 [0.367879 0.692201 0.324321]
    3 [0.692201 0.500474 0.191727]
    4 [0.500474 0.606244 0.10577 ]
    5 [0.606244 0.545396 0.060848]
    6 [0.545396 0.579612 0.034217]
    7 [0.579612 0.560115 0.019497]
    8 [0.560115 0.571143 0.011028]
    9 [0.571143 0.564879 0.006264]
    10 [0.564879 0.568429 0.003549]
    11 [0.568429 0.566415 0.002014]
    12 [0.566415 0.567557 0.001142]
    13 [0.567557 0.566909 0.000648]
    raíz en:  0.5669089119214953
    

    Instrucciones en Python

    # Algoritmo de punto fijo
    # error = tolera
    import numpy as np
    
    def puntofijo(gx,c,tolera,iteramax=40,vertabla=True, precision=6):
        """
        g(x) se obtiene al despejar una x de f(x)
        máximo de iteraciones predeterminado: iteramax
        si no converge hasta iteramax iteraciones
        la respuesta es NaN (Not a Number)
        """
        itera = 0 # iteración inicial
        tramo = 2*tolera # al menos una iteracion
        if vertabla==True:
            print('método del Punto Fijo')
            print('i', ['xi','gi','tramo'])
            np.set_printoptions(precision)
        while (tramo>=tolera and itera<=iteramax):
            gc = gx(c)
            tramo = abs(gc-c)
            if vertabla==True:
                print(itera,np.array([c,gc,tramo]))
            c = gc
            itera = itera + 1
        respuesta = c
        # Valida respuesta
        if itera>=iteramax:
            respuesta = np.nan
            print('itera: ',itera,
                  'No converge,se alcanzó el máximo de iteraciones')
        return(respuesta)
    
    # PROGRAMA ----------------------
    # INGRESO
    fx = lambda x: np.exp(-x) - x
    gx = lambda x: np.exp(-x)
    
    c = 0  # valor inicial
    tolera = 0.001
    iteramax = 15
    
    # PROCEDIMIENTO
    respuesta = puntofijo(gx,c,tolera,iteramax,vertabla=True)
    
    # SALIDA
    print('raíz en: ', respuesta)
    

    De añadirse la parte gráfica, el bloque requiere el intervalo de observación [a,b].

    [ Punto fijo ] [ Ejercicio ] [ Analítico ] [ Algoritmo ] [ gráfica ] [ función ]


    6. Función en librería Scipy.optimize.fixed_point

    El método del punto fijo se encuentra implementado en Scipy, que también puede ser usado de la forma:

    >>> import numpy as np
    >>> import scipy as sp
    >>> gx = lambda x: np.exp(-x)
    >>> c = 0
    >>> sp.optimize.fixed_point(gx,c,xtol=0.001,maxiter=15)
    array(0.5671432948307147)
    

    el valor predeterminado de iteraciones si no se escribe es 500 y la tolerancia predeterminada es xtol=1e-08
    https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.fixed_point.html


    Tarea

    • Revisar lo que sucede cuando el valor inicial a esta a la derecha de la raíz.
    • Validar que la función converge, revisando que |g'(x)|<1, o que la función g(x) tenga pendiente menor a pendiente de la recta identidad.

    [ Punto fijo ] [ Ejercicio ] [ Analítico ] [ Algoritmo ] [ gráfica ] [ función ]