Categoría: Unidad 4 Interpolación polinómica

  • 4.2.1 Interpolación por Diferencias finitas avanzadas (h) con Python

    Dif_Finitas avanzadas ] [ Ejercicio ] [ Analítico ] [ Algoritmo ] [ gráfica ]
    [ función ]
    ..


    1. Interpolación por Diferencias finitas avanzadas

    Referencia: Rodríguez 6.6.4 p221, Burden 9Ed p129

    Se usa en interpolación cuando los puntos en el "eje x" se encuentran igualmente espaciados, la diferencia entre puntos consecutivos xi es una constante denominada h.

    h = xi+1 - xi

    diferencias finitas Avanzadas GIF animado
    Una relación entre derivadas y diferencias finitas se establece mediante: f^{(n)}(z) = \frac{\Delta ^{n} f_{0}}{h^{n}} para algún z en el intervalo [x0,xn].

    \frac{\Delta ^{n} f_{0}}{h^{n}} es una aproximación para la n-ésima derivada f(n)

    El polinomio de interpolación se puede construir por medio de diferencias finitas avanzadas con las siguiente fórmula:

    p_n (x) = f_0 + \frac{\Delta f_0}{h} (x - x_0) + + \frac{\Delta^2 f_0}{2!h^2} (x - x_0)(x - x_1) + + \frac{\Delta^3 f_0}{3!h^3} (x - x_0)(x - x_1)(x - x_2) + \text{...} + \frac{\Delta^n f_0}{n!h^n} (x - x_0)(x - x_1) \text{...} (x - x_{n-1})

    Observe que en la medida que se toman más puntos de muestra, el grado del polinomio puede ser mayor.

    polinomio de diferencias finitas avanzadas

    Dif_Finitas avanzadas ] [ Ejercicio ] [ Analítico ] [ Algoritmo ] [ gráfica ]
    [ función ]
    ..


    2. Ejercicio

    Se toman los datos del ejercicio de diferencias finitas , observando que se requiere que el tamaño de paso h  sea constante entre los puntos consecutivos xi.

    xi = [0.1, 0.2, 0.3, 0.4]
    fi = [1.45, 1.6, 1.7, 2.0]
    xi 0.1 0.2 0.3 0.4
    fi 1.45 1.6 1.7 2.0

    Para éste ejercicio se comprueba que h = 0.1

    Dif_Finitas avanzadas ] [ Ejercicio ] [ Analítico ] [ Algoritmo ] [ gráfica ]
    [ función ]
    ..


    3. Desarrollo Analítico

    Se inicia el cálculo de la distancia entre puntos xi, comprobando que debe ser constante h, además que los valores xi deben encontrarse ordenados de forma ascendente:

    h = xi[1] - xi[0] = 0.2-0.1 = 0.1
    h = xi[2] - xi[1] = 0.3-0.2 = 0.1
    h = xi[3] - xi[2] = 0.4-0.3 = 0.1

    Se usan los resultados previos del ejercicio con diferencias finitas:

    Tabla Diferencia Finita: 
    [['i', 'xi', 'fi', 'd1f', 'd2f', 'd3f', 'd4f']]
    [[ 0.    0.1   1.45  0.15 -0.05  0.25  0.  ]
     [ 1.    0.2   1.6   0.1   0.2   0.    0.  ]
     [ 2.    0.3   1.7   0.3   0.    0.    0.  ]
     [ 3.    0.4   2.    0.    0.    0.    0.  ]]
    

    Como los tamaños de paso en xi son constantes, h=0.1, es posible usar el método. Para la construcción del polinomio, se usan los valores de diferencias finitas de la primera fila desde la columna 3 en adelante.

    dfinita = tabla[0,3:] = [0.15, -0.05, 0.25, 0.]

    Se empieza con el valor del primer punto de la función f(0.1), j=0.

    p3(x) = f0 = 1.45

    para añadirle el término j=1, más el factor por calcular:

    factor = \frac{\Delta^1 f_0}{1!h^1} = \frac{0.15}{1!(0.1)} = 1.5

    completando el término como:

    término = factor(x-x_0) = 1.5(x-0.1) p_3(x) = 1.45 + 1.5(x-0.1)

    Para el segundo término j=2, se repite el proceso:

    factor = \frac{\Delta^2 f_0}{2!h^2} = \frac{-0.05}{2!(0.1)^2} = -2.5 término = factor(x-x_0) = -2.5(x-0.1)(x-0.2) p_3(x)= 1.45 + 1.5(x-0.1) +(-2.5)(x-0.1)(x-0.2)

    Finalmente, añadiendo el término j=3 cuyo cálculo es semejante a los anteriores, se deja como tarea.

    El resultado del método es:

    p_3(x)= 1.45 + 1.5(x-0.1) -2.5(x-0.1)(x-0.2) + + 41.667(x - 0.3)(x - 0.2)(x - 0.1)

    Se puede seguir simplificando la respuesta, por ejemplo usando solo el término de grado con 1.5(x-0.1) se tiene que:

    p_3(x) = 1.3 + 1.5x -2.5(x-0.1)(x-0.2)+ + 41.667(x - 0.3)(x - 0.2)(x - 0.1)

    Seguir simplificando la expresión en papel, se deja como tarea.

    La gráfica del polinomio obtenido comprueba que pasa por cada uno de los puntos dados para el ejercicio.

    interpolación polinómica

    Dif_Finitas avanzadas ] [ Ejercicio ] [ Analítico ] [ Algoritmo ] [ gráfica ]
    [ función ]
    ..


    4. Algoritmo en Python

    El polinomio se construye usando el ejercicio de diferencias finitas.

    Para construir la expresión del polinomio añadiendo los términos de la fórmula, se define la variable simbólica x con Sympy.

    Para simplificar el polinomio resultante con las expresiones de multiplicación, se utiliza la instrucción sym.expand().

    En caso de requerir evaluar la fórmula con un vector de datos se la convierte a la forma lambda para evaluación numérica.

    Se añaden las instrucciones para realizar la gráfica en el intervalo [a,b] dado por los valores xi, definiendo el número de muestras = 21 que son suficientes para que la gráfica se observe sin distorsión.

    Se añade un bloque para la revisión que los puntos xi sean equidistantes y se encuentren en orden.

    # Diferencias finitas Avanzadas - Interpolación
    # Tarea: Verificar tamaño de vectores
    import numpy as np
    import math
    import sympy as sym
    
    # INGRESO
    xi = [0.1, 0.2, 0.3, 0.4]
    fi = [1.45, 1.6, 1.7, 2.0]
    
    # PROCEDIMIENTO
    casicero = 1e-15
    # Vectores como arreglo, numeros reales
    xi = np.array(xi,dtype=float)
    fi = np.array(fi,dtype=float)
    n = len(xi)
    
    msj = [] # mensajes de error
    
    # xi revisar orden ascendente
    tramos  = np.diff(xi,1)  # diferencias en xi
    donde = -1  # suponer ordenados
    i = 0
    while i<(n-1) and donde<0:
        if tramos[i]<0:
            donde = i+1
            msj.append(['sin orden en',donde])
        i = i+1
    
    # xi tramos desiguales o no equidistantes
    if (n-1)>=2: # len(tramos)>=2
        dtramos = np.diff(tramos,1) # cero o menores a casicero
        errado  = np.max(np.abs(dtramos)) # |error| mayor
        donde = -1 # suponer equidistantes
        if errado>=casicero:  # no equidistantes
            donde = np.argmax(np.abs(dtramos))+1
            msj.append(['no equidistantes',donde])
    
    
    # Tabla de Diferencias Finitas
    tabla_etiq = ['i','xi','fi']
    ki = np.arange(0,n,1) # filas
    tabla = np.concatenate(([ki],[xi],[fi]),axis=0)
    tabla = np.transpose(tabla)
    dfinita = np.zeros(shape=(n,n),dtype=float)
    tabla = np.concatenate((tabla,dfinita), axis=1)
    n,m = np.shape(tabla)
    # Calular tabla de Diferencias Finitas
    diagonal = n-1 # derecha a izquierda
    j = 3  # inicia en columna 3
    while (j < m): # columna
        tabla_etiq.append('d'+str(j-2)+'f')
        i = 0 # fila
        while (i < diagonal): # antes de diagonal
            tabla[i,j] = tabla[i+1,j-1]-tabla[i,j-1]
    
            if abs(tabla[i,j])<casicero: # casicero revisa
                    tabla[i,j]=0
            i = i + 1
        diagonal = diagonal - 1
        j = j + 1
    
    dfinita = tabla[0,3:] # diferencias finitas
    h = xi[1] - xi[0]     # suponer tramos equidistantes
    
    # polinomio con diferencias Finitas Avanzadas
    x = sym.Symbol('x')
    polinomio = fi[0] +0*x # en Sympy
    for i in range(1,n,1):
        denominador = math.factorial(i)*(h**i)
        factor = dfinita[i-1]/denominador
        termino = 1
        for j in range(0,i,1):
            termino = termino*(x-xi[j])
        polinomio = polinomio + termino*factor
    
    polisimple = polinomio.expand() # simplifica los (x-xi)
    px = sym.lambdify(x,polisimple) # evaluación numérica
    
    # SALIDA
    if len(msj)>0: # mensajes de error
        print('Revisar tramos, d1x:',tramos)
        for unmsj in msj:
            print('Tramos',unmsj[0],
                  'desde i:',unmsj[1])
    else:
        print('Tramo h:',h)
    print('Tabla Diferencia Finita')
    print([tabla_etiq])
    print(tabla)
    print('dfinita: ')
    print(dfinita)
    print('polinomio: ')
    print(polinomio)
    print('polinomio simplificado: ' )
    print(polisimple)
    

    teniendo como resultado:

    Tramo h: 0.1
    Tabla Diferencia Finita
    [['i', 'xi', 'fi', 'd1f', 'd2f', 'd3f', 'd4f']]
    [[ 0.    0.1   1.45  0.15 -0.05  0.25  0.  ]
     [ 1.    0.2   1.6   0.1   0.2   0.    0.  ]
     [ 2.    0.3   1.7   0.3   0.    0.    0.  ]
     [ 3.    0.4   2.    0.    0.    0.    0.  ]]
    dfinita: 
    [ 0.15 -0.05  0.25  0.  ]
    polinomio: 
    1.5*x + 41.6666666666667*(x - 0.3)*(x - 0.2)*(x - 0.1) - 2.50000000000001*(x - 0.2)*(x - 0.1) + 1.3
    polinomio simplificado: 
    41.6666666666667*x**3 - 27.5*x**2 + 6.83333333333335*x + 0.999999999999999
    

    el polinomio de puede evaluar como px(valor) una vez que se convierte a la forma lambda para usar con Numpy:

    >>> px(0.1)
    1.4500000000000004
    >>> px(0.2)
    1.6000000000000025
    >>> px0.3)
    1.7000000000000042
    >>> 
    

    Dif_Finitas avanzadas ] [ Ejercicio ] [ Analítico ] [ Algoritmo ] [ gráfica ]
    [ función ]
    ..


    5. Gráfica de polinomio de interpolación

    Las instrucciones son semejantes a las presentadas en polinomio de interpolación. Se añade instrucciones para el caso en que los puntos no sean equidistantes en el eje de las x.

    Como el bloque de gráfica se usa en otros métodos de la unidad, se incorpora la verificación de lista de errores 'msj' usando el bloque 'try-except'.

    # GRAFICA --------------
    import matplotlib.pyplot as plt
    
    titulo = 'Interpolación: Diferencias Finitas Avanzadas'
    muestras = 21  # resolución gráfica
    
    a = np.min(xi) # intervalo [a,b]
    b = np.max(xi)
    xk = np.linspace(a,b,muestras)
    yk = px(xk)
    
    plt.plot(xi,fi,'o', label='[xi,fi]')
    plt.plot(xk,yk, label='p(x)')
    
    try: # existen mensajes de error
        msj_existe = len(msj)
    except NameError:
        msj = []
        
    if len(msj)>0: # tramos con error
        untipo = msj[0][0]
        donde = msj[0][1] # indice error
        plt.plot(xi[donde:donde+2],fi[donde:donde+2],
                 'ro',label=untipo)
        plt.plot(xi[donde:donde+2],fi[donde:donde+2],
                 'r--')
        
    plt.xlabel('xi')
    plt.ylabel('fi')
    plt.legend()
    plt.title(titulo)
    plt.show()

    diferencias finitas avanzadas 01

    Tarea: se recomienda realizar las gráficas comparativas entre métodos, debe mostrar la diferencia con los métodos que requieren el tamaño de paso equidistante h, y los que no lo requieren. Permite detectar errores de selección de método para interpolación.

    Dif_Finitas avanzadas ] [ Ejercicio ] [ Analítico ] [ Algoritmo ] [ gráfica ]
    [ función ]
    ..


    6. Algoritmo como función

    Se reordena el algoritmo para usar funciones, la gráfica es la misma que para el algoritmo sin funciones anterior

    El bloque de salida es semejante al resultado anterior. Las funciones pueden ser reutilizadas de ser necesarias en el siguiente método de interpolación.

    Tabla de Diferencias finitas
    [['i', 'xi', 'fi', 'd1f', 'd2f', 'd3f', 'd4f']]
    [[ 0.    0.1   1.45  0.15 -0.05  0.25  0.  ]
     [ 1.    0.2   1.6   0.1   0.2   0.    0.  ]
     [ 2.    0.3   1.7   0.3   0.    0.    0.  ]
     [ 3.    0.4   2.    0.    0.    0.    0.  ]]
    xi_ascendente: True
    tramos xi Equidistantes: True
    Tramo h: 0.1
    polinomio: 
    1.30000000000000 +
    1.5*x +
    -2.50000000000001*(x - 0.2)*(x - 0.1) +
    41.6666666666667*(x - 0.3)*(x - 0.2)*(x - 0.1)
    
    polinomio simplificado: 
    41.6666666666667*x**3 - 27.5*x**2 + 6.83333333333335*x + 0.999999999999999
    

    Instrucciones en Python

    # Diferencias finitas Avanzadas - Interpolación
    # funciones dif_finitas
    # Tarea: Verificar tamaño de vectores
    import numpy as np
    import math
    import sympy as sym
    
    def revisa_orden(xi,orden='up'):
        ''' Revisa orden en vector xi.
          orden='up': orden ascendente
          orden='down' : orden descendente
        resultado:
          True:  xi ordenado,
          False: xi desordenado y dónde.
        '''
        # Vectores como arreglo, numeros reales
        xi = np.array(xi,dtype=float)
        n = len(xi)
        
        msj = [] # mensajes de error
        # xi revisar orden ascendente o descendente
        tramos  = np.diff(xi,1)  # diferencias en xi
        ordenado = True  # suponer ordenados
        k = 1 # 1: ascendente
        if orden=='down':
            k = -1 # -1: descendente
        donde = -1
        i = 0
        while i<(n-1) and donde<0:
            if k*tramos[i]<0:
                ordenado = False
                donde = i+1
                msj.append(['sin orden',donde])
            i = i+1
        return([ordenado,msj])
    
    def tramos_equidistantes(xi, casicero = 1e-15):
        ''' Revisa tamaños de paso h en vector xi.
        True:  h son equidistantes,
        False: h tiene tamaño de paso diferentes y dónde.
        '''
        # Vectores como arreglo, numeros reales
        xi = np.array(xi,dtype=float)
        n = len(xi)
        msj = [] # mensajes de error
        
        # revisa tamaños de paso desiguales o no equidistantes
        h_iguales = True
        if (n-1)>=2: # al menos dos tramos
            dtramos = np.diff(xi,2) # cero o menores a casicero
            errado  = np.max(np.abs(dtramos)) # |error| mayor
            if errado>=casicero:  # no equidistantes
                h_iguales=False
                donde = np.argmax(np.abs(dtramos))+1
                msj.append(['no equidistantes',donde])
    
        return([h_iguales,msj])
    
    def diferencias_tabla(xi,fi,tipo='finitas', vertabla=False,
                    casicero = 1e-15, precision=4):
        '''Genera la tabla de diferencias finitas o divididas
          tipo = 'finitas, tipo = 'divididas'
        resultado en: tabla, titulo
        Tarea: verificar tamaño de vectores
        '''
        # revisa tipo de tabla
        tipolist = ['finitas','divididas']
        if not(tipo in tipolist):
            print('error de tipo, seleccione:',tipolist)
            return()
        
        prefijo = ['d','f']
        if tipo=='divididas':
            prefijo = ['F[',']']
        
        # Matrices como arreglo, numeros reales
        xi = np.array(xi,dtype=float)
        fi = np.array(fi,dtype=float)
        n = len(xi)
    
        # Tabla de Diferencias Finitas/Divididas
        tabla_etiq = ['i','xi','fi']
        ki = np.arange(0,n,1) # filas
        tabla = np.concatenate(([ki],[xi],[fi]),axis=0)
        tabla = np.transpose(tabla)
        dfinita = np.zeros(shape=(n,n),dtype=float)
        tabla = np.concatenate((tabla,dfinita), axis=1)
        n,m = np.shape(tabla)
        # Calular tabla de Diferencias Finitas/Divididas
        diagonal = n-1 # derecha a izquierda
        j = 3  # inicia en columna 3
        while (j < m): # columna
            tabla_etiq.append(prefijo[0]+str(j-2)+prefijo[1])
            # paso = j-2 # inicia en 1
            i = 0 # fila
            while (i < diagonal): # antes de diagonal
                tabla[i,j] = tabla[i+1,j-1]-tabla[i,j-1]
    
                if tipo=='divididas':
                    # denominador = xi[i+paso]-xi[i]
                    denominador = xi[i+j-2]-xi[i]
                    tabla[i,j] = tabla[i,j]/denominador
                    
                if abs(tabla[i,j])<casicero: # casicero revisa
                        tabla[i,j]=0
                i = i + 1
            diagonal = diagonal - 1
            j = j + 1
                
        if vertabla==True:
            np.set_printoptions(precision)
            print('Tabla de Diferencias',tipo)
            print([tabla_etiq])
            print(tabla)
        return([tabla, tabla_etiq])
    
    # PROGRAMA ---------------------
    
    # INGRESO
    xi = [0.1, 0.2, 0.3, 0.4]
    fi = [1.45, 1.6, 1.7, 2.0]
    
    tipo_tabla = 'finitas'
    
    # PROCEDIMIENTO
    casicero = 1e-12
    # Vectores como arreglo, numeros reales
    xi = np.array(xi,dtype=float)
    fi = np.array(fi,dtype=float)
    n = len(xi)
    
    xi_ascendente,msj = revisa_orden(xi)
    h_iguales,msj_h = tramos_equidistantes(xi, casicero = casicero)
    if len(msj_h)>0:
        msj.extend(msj_h)   
    tabla,titulo = diferencias_tabla(xi,fi,tipo=tipo_tabla,
                                     vertabla=True, casicero = casicero)
    
    dfinita = tabla[0,3:] # diferencias finitas
    h = xi[1] - xi[0]     # suponer tramos equidistantes
    
    # polinomio con diferencias Finitas Avanzadas/ divididas
    x = sym.Symbol('x')
    polinomio = fi[0] +0*x # sym.S.Zero en Sympy
    for i in range(1,n,1):
        factor = dfinita[i-1] # diferencias divididas
        if tipo_tabla=='finitas': # diferencias Finitas Avanzadas
            denominador = math.factorial(i)*(h**i)
            factor = factor/denominador
        termino = 1
        for j in range(0,i,1):
            termino = termino*(x-xi[j])
        polinomio = polinomio + termino*factor
    
    polisimple = polinomio.expand() # simplifica los (x-xi)
    px = sym.lambdify(x,polisimple) # evaluacion numerica
    
    # SALIDA
    print('xi_ascendente:',xi_ascendente)
    print('tramos xi Equidistantes:',h_iguales)
    if len(msj)>0: # mensajes de error
        print('Revisar tramos, d1x:',np.diff(xi,1))
        for unmsj in msj:
            print('Tramos',unmsj[0],
                  'desde i:',unmsj[1])
    else:
        print('Tramo h:',h)
    
    print('d'+tipo_tabla+': ')
    print(dfinita)
    print('polinomio: ')
    #print(polinomio)
    terminos = sym.Add.make_args(polinomio)
    n_term = len(terminos)
    for i in range(0,n_term,1):
        if i<(n_term-1):
            print(terminos[i],'+')
        else:
            print(terminos[i])
    print()
    print('polinomio simplificado: ' )
    print(polisimple)
    

    La gráfica se genera con el mismo bloque de instrucciones de la sección gráfica.

    Dif_Finitas avanzadas ] [ Ejercicio ] [ Analítico ] [ Algoritmo ] [ gráfica ]
    [ función ]

  • 4.2 Diferencias finitas, tabla con Python

    [ Dif_Finitas ] [ ejercicio ] [ analítico ] [ algoritmo ] [ gráfica ] [ función ]
    ..


    1. Diferencias finitas

    Referencia: Rodríguez 6.5 p211, Chapra 18.1.3 p509

    Establece relaciones simples entre los puntos dados que describen la función f(x). Las tabla de diferencias finitas es un elemento base para varios métodos de interpolación, por lo que se trata como un tema inicial.

    diferencias finitas 01 animado
    [ Dif_Finitas ] [ ejercicio [ algoritmo ] [ gráfica ] [ función ]
    ..


    2. Ejercicio

    Los datos provienen del ejercicio para el polinomio de interpolación con Vandermonde. Se modifica el primer par ordenado a [0.1, 1.45].

    xi = [0.1, 0.2, 0.3, 0.4] 
    fi = [1.45, 1.6, 1.7, 2.0]
    xi 0.1 0.2 0.3 0.4
    fi 1.45 1.6 1.7 2.0

    [ Dif_Finitas ] [ ejercicio ] [ analítico ] [ algoritmo ] [ gráfica ] [ función ]
    ..


    3. Desarrollo analítico

    La tabla de diferencias finitas se construye tomando los datos y sus índices como parte de las primeras columnas.

    i xi fi Δ1fi Δ2fi Δ3fi Δ4fi
    0 0.1 1.45 0.15 -0.05 0.25 0.
    1 0.2 1.6 0.1 0.2 0. 0.
    2 0.3 1.7 0.3 0. 0. 0.
    3 0.4 2.0 0. 0. 0. 0.

    Cada casilla de diferencia finita Δjfi se obtiene restando los dos valores consecutivos de la columna anterior. Por ejemplo, para la primera columna:

    \Delta ^1 f_0 = 1.6-1.45 = 0.15 \Delta ^1 f_1 = 1.7-1.6 = 0.1 \Delta ^1 f_2 = 2.0-1.7 = 0.3

    y la siguiente Δ1f3 no es posible calcular.

    Siguiendo el mismo procedimiento se calculan los valores de la siguiente columna Δ2fi como las diferencias de la columna anterior.

    \Delta ^2 f_0 = 0.1-0.15 = -0.05 \Delta ^2 f_1 = 0.3-0.1 = 0.2

    finalmente Δ3fi

    \Delta ^3 f_0 = 0.2-(-0.05) = 0.25

    Si la función f(x) de donde provienen los datos es un polinomio de grado n, entonces la n-ésima diferencia finita será una constante, y las siguientes diferencias se anularán.

    [ Dif_Finitas ] [ ejercicio ] [ analítico ] [ algoritmo ] [ gráfica ] [ función ]
    ..


    4. Algoritmo en Python

    Para crear la tabla de diferencias finitas, las primeras columnas requieren concatenar los valores de los índices ixi y fi.

    xi = [0.10, 0.2, 0.3, 0.4]
    fi = [1.45, 1.6, 1.7, 2.0]

    Los índices i se crean en un vector ki, pues la variable i es usada como fila en matrices, por lo que evitamos confundirlas al usar la variable.

    A la matriz con las tres columnas descritas, se le añade a la derecha una matriz de nxn para calcular las diferencias.

    Se calculan las diferencias para cada columna, realizando la operación entre los valores de cada fila. Considere que no se realizan cálculos desde la diagonal hacia abajo en la tabla, los valores quedan como cero.

    Al final se muestra el título y el resultado de la tabla.

    # Diferencias finitas: [tabla_etiq,tabla]
    # Tarea: verificar tamaño de vectores
    import numpy as np
    
    # INGRESO, Datos de prueba
    xi = [0.10, 0.2, 0.3, 0.4]
    fi = [1.45, 1.6, 1.7, 2.0]
    
    # PROCEDIMIENTO
    casicero = 1e-15  # redondear a cero
    # Matrices como arreglo, numeros reales
    xi = np.array(xi,dtype=float)
    fi = np.array(fi,dtype=float)
    n = len(xi)
    
    # Tabla de Diferencias Finitas
    tabla_etiq = ['i','xi','fi']
    ki = np.arange(0,n,1) # filas
    tabla = np.concatenate(([ki],[xi],[fi]),axis=0)
    tabla = np.transpose(tabla)
    dfinita = np.zeros(shape=(n,n),dtype=float)
    tabla = np.concatenate((tabla,dfinita), axis=1)
    n,m = np.shape(tabla)
    # Calular tabla de Diferencias Finitas
    diagonal = n-1 # derecha a izquierda
    j = 3  # inicia en columna 3
    while (j < m): # columna
        tabla_etiq.append('d'+str(j-2)+'f') 
        i = 0 # fila
        while (i < diagonal): # antes de diagonal
            tabla[i,j] = tabla[i+1,j-1]-tabla[i,j-1]
            
            if abs(tabla[i,j])<casicero: # casicero revisa
                    tabla[i,j]=0
            i = i + 1
        diagonal = diagonal - 1
        j = j + 1
    
    # SALIDA
    print('Tabla Diferencia Finita: ')
    print([tabla_etiq])
    print(tabla)

    el resultado de aplicar el algoritmo es:

    Tabla Diferencia Finita: 
    [['i', 'xi', 'fi', 'd1f', 'd2f', 'd3f', 'd4f']]
    [[ 0.    0.1   1.45  0.15 -0.05  0.25  0.  ]
     [ 1.    0.2   1.6   0.1   0.2   0.    0.  ]
     [ 2.    0.3   1.7   0.3   0.    0.    0.  ]
     [ 3.    0.4   2.    0.    0.    0.    0.  ]]
    >>> 
    

    [ Dif_Finitas ] [ ejercicio ] [ analítico ] [ algoritmo ] [ gráfica ] [ función ]
    ..


    5. Gráfica de puntos con líneas horizontales

    Para tener una referencia visual sobre las primeras diferencias finitas, en una gráfica se trazan las líneas horizontales que pasan por cada punto. Para las segundas diferencias se debe incluir en la gráfica las primeras diferencias finitas vs xi repitiendo el proceso. Las líneas de distancia se añadieron con un editor de imágenes.

    diferencias finitas 01 graf

    Las instrucciones adicionales al algoritmo anterior para añadir la gráfica son:

    # Gráfica --------------
    import matplotlib.pyplot as plt
    
    titulo = 'Diferencia Finita'
    
    for i in range(0,n,1):
        plt.axhline(fi[i],ls='--', color='yellow')
        if i<(n-1):
            plt.annotate("", xytext=(xi[i+1], fi[i]),
                         xy=(xi[i+1], fi[i+1]),
                         arrowprops=dict(arrowstyle="<->"),
                         color='magenta')
            plt.annotate("Δ1f["+str(i)+"]",
                         xy=(xi[i+1], fi[i+1]),
                         xytext=(xi[i+1],(fi[i]+fi[i+1])/2))
                         
    plt.plot(xi,fi,'o', label = 'Puntos')
    plt.legend()
    plt.xlabel('xi')
    plt.ylabel('fi')
    plt.title(titulo)
    plt.show()
    

    [ Dif_Finitas ] [ ejercicio ] [ analítico ] [ algoritmo ] [ gráfica ] [ función ]
    ..


    6. Diferencias finitas como función en Numpy.diff

    np.diff(vector,orden)calcula la diferencia de elementos consecutivos a lo largo de un eje específico de una matriz. Incluye un parámetro de orden para la n-esima diferencia finita. Ejemplo:

    >>> import numpy as np
    >>> xi = [0.10, 0.2, 0.3, 0.4]
    >>> fi = [1.45, 1.6, 1.7, 2.0]
    >>> d1f = np.diff(fi,1)
    >>> d1f
    array([0.15, 0.1 , 0.3 ])
    >>> d2f = np.diff(fi,2)
    >>> d2f
    array([-0.05,  0.2 ])
    >>> d1x = np.diff(xi,1)
    >>> d1x
    array([0.1, 0.1, 0.1])
    >>> d2x = np.diff(xi,n=2)
    >>> d2x
    array([-2.77555756e-17,  5.55111512e-17])

    Δ2xi es un valor casicero que se debe incluir en el algoritmo para redondear a cero cuando sea por ejemplo 10-15. Asunto que ya fue incluido desde Método de Gauss en la unidad de sistemas de ecuaciones

    Referenciahttps://numpy.org/doc/stable/reference/generated/numpy.diff.html

    [ Dif_Finitas ] [ ejercicio ] [ analítico ] [ algoritmo ] [ gráfica ] [ función ]

  • 4.1 Polinomio de interpolación con Vandermonde en Python

    Interpolación: [ Ejercicio ] [ Analítico ] [ Algoritmo ] [ gráfica ] [ Función ]
    ..


    1. Ejercicio

    Referencia: Rodríguez 6.1 p191, Chapra 18.3 p520

    Unir n puntos en el plano usando un polinomios de interpolación se puede realizar con un polinomio de grado (n-1).

    interpolación polinómica, matriz de Vandermonde

    xi 0 0.2 0.3 0.4
    fi 1 1.6 1.7 2.0

    Por ejemplo, dados los 4 puntos en la tabla [xi,fi] se requiere generar un polinomio de grado 3 de la forma:

    p(x) = a_0 x^3 + a_1 x^2 + a_2 x^1 + a_3

    Interpolación: [ Ejercicio ] [ Analítico ] [ Algoritmo ] [ gráfica ] [ Función ]
    ..


    2. Desarrollo Analítico

    Es posible generar un sistema de ecuaciones para p(x) haciendo que pase por cada uno de los puntos o coordenadas.
    Por ejemplo si se toma el primer punto con xi=0 y fi=1 se establece la ecuación:

    p(0) = 1 a_0 (0)^3 + a_1 (0)^2 + a_2 (0)^1 + a_3 = 1 p(0.2) = 1.6 a_0 (0.2)^3 + a_1 (0.2)^2 + a_2 (0.2)^1 + a_3 = 1.6

    Note que ahora las incógnitas son los coeficientes ai. Luego se continúa con los otros puntos seleccionados hasta completar las ecuaciones necesarias para el grado del polinomio seleccionado.

    a_0 (0.0)^3 + a_1 (0.0)^2 + a_2 (0.0)^1 + a_3 = 1.0 a_0 (0.2)^3 + a_1 (0.2)^2 + a_2 (0.2)^1 + a_3 = 1.6 a_0 (0.3)^3 + a_1 (0.3)^2 + a_2 (0.3)^1 + a_3 = 1.7 a_0 (0.4)^3 + a_1 (0.4)^2 + a_2 (0.4)^1 + a_3 = 2.0

    El sistema obtenido se resuelve con alguno de los métodos conocidos para la Solución a sistemas de ecuaciones, que requieren escribir las ecuaciones en la forma de matriz A y vector B, desarrollar la matriz aumentada, pivotear por filas, etc.

    \begin{pmatrix} 0.0^3 & 0.0^2 & 0.0^1 & 1 \\ 0.2^3 & 0.2^2 & 0.2^1 & 1 \\ 0.3^3 & 0.3^2 & 0.3^1 & 1 \\ 0.4^3 & 0.4^2 & 0.4^1 & 1 \end{pmatrix} . \begin{pmatrix} a_0 \\ a_1 \\ a_2 \\ a_3 \end{pmatrix} = \begin{pmatrix} 1.0 \\ 1.6 \\ 1.7 \\ 2.0 \end{pmatrix}

    La matriz A también se conoce como Matriz Vandermonde D, que se construye observando que los coeficientes se elevan al exponente referenciado al índice columna pero de derecha a izquierda. La última columna tiene valores 1 por tener como coeficiente el valor de xi0.

    Para enfocarnos en la interpolación, en la solución se propone usar un algoritmo o función en Python, obteniendo el siguiente resultado:

    los coeficientes del polinomio: 
    [ 41.66666667 -27.5          6.83333333   1.        ]

    a partir del cual que se construye el polinomio con los valores obtenidos.

    Polinomio de interpolación p(x): 
    41.66666666667*x**3 - 27.5*x**2 + 6.83333333333*x + 1.0
    

    que re-escrito es,

    p(x) = 41.6666 x^3 - 27.5 x^2 + 6.8333 x + 1

    Se realiza  la gráfica de p(x) dentro del intervalo de los datos del ejercicio y se obtiene la línea contínua que pasa por cada uno de los puntos.

    interpola polinomio 02

    Interpolación: [ Ejercicio ] [ Analítico ] [ Algoritmo ] [ gráfica ] [ Función ]
    ..


    3. Algoritmo en Python

    Para desarrollar el ejercicio, se realiza un bloque para construir la matriz A y vector B, usando los vectores que representan los puntos de muestra de la función o experimento.

    xi = [0,0.2,0.3,0.4]
    fi = [1,1.6,1.7,2.0]

    Observe que en éste caso los datos se dan en forma de lista y se deben convertir hacia arreglos.

    La matriz A o Matriz Vandermonde D, se construye observando que los coeficientes del vector xi se elevan al exponente referenciado al índice columna pero de derecha a izquierda.

    Construir el polinomio consiste en resolver el sistema de ecuaciones indicado en la sección anterior. Para simplificar la solución del sistema, se usa Numpy, que entrega el vector solución que representan los coeficientes del polinomio de interpolación.

    Para construir la expresión del polinomio, se usa la forma simbólica con Sympy, de forma semejante a la usada para construir el polinomio de Taylor.
    Para mostrar el polinomio de una manera más fácil de interpretar se usa la instrucción sym.pprint(), usada al final del algoritmo.

    # El polinomio de interpolación y Vandermonde
    import numpy as np
    import sympy as sym
    
    # INGRESO
    xi = [0,0.2,0.3,0.4]
    fi = [1,1.6,1.7,2.0]
    
    # PROCEDIMIENTO
    # Matrices como arreglo, numeros reales
    xi = np.array(xi,dtype=float)
    fi = np.array(fi,dtype=float)
    n = len(xi)
    # Matriz Vandermonde D
    D = np.zeros(shape=(n,n),dtype=float)
    for i in range(0,n,1):
        for j in range(0,n,1):
            potencia = (n-1)-j # Derecha a izquierda
            D[i,j] = xi[i]**potencia
    
    # Resuelve sistema de ecuaciones A.X=B
    coeficiente = np.linalg.solve(D,fi)
    
    # Polinomio en forma simbólica
    x = sym.Symbol('x')
    polinomio = 0*x   # sym.S.Zero
    for i in range(0,n,1):
        potencia = (n-1)-i   # Derecha a izquierda
        termino = coeficiente[i]*(x**potencia)
        polinomio = polinomio + termino
    
    # polinomio para evaluación numérica
    px = sym.lambdify(x,polinomio)
    
    # SALIDA
    print('Matriz Vandermonde: ')
    print(D)
    print('los coeficientes del polinomio: ')
    print(coeficiente)
    print('Polinomio de interpolación: ')
    print(polinomio)
    print('\n formato pprint')
    sym.pprint(polinomio)
    

    con lo que se obtiene el siguiente resultado:

    Matriz Vandermonde: 
    [[0.    0.    0.    1.   ]
     [0.008 0.04  0.2   1.   ]
     [0.027 0.09  0.3   1.   ]
     [0.064 0.16  0.4   1.   ]]
    los coeficientes del polinomio: 
    [ 41.66666667 -27.5 6.83333333 1. ]
    Polinomio de interpolación: 
    41.66666666667*x**3 - 27.5*x**2 + 6.83333333333*x + 1.0
    
    formato pprint
                      3         2                           
    41.66666666667*x  - 27.5*x  + 6.83333333333*x + 1.0
    

    Interpolación: [ Ejercicio ] [ Analítico ] [ Algoritmo ] [ gráfica ] [ Función ]
    ..


    4. Gráfica del polinomio

    Para facilitar la evaluación numérica del polinomio, se convierte el polinomio a la forma Lambda px. La gráfica se realiza con un número de muestras suficientes para suavizar la curva dentro del intervalo [a,b], por ejemplo 21, con lo que se comprueba que la curva pase por todos los puntos de la tabla xi,fi dados en el ejercicio.

    Instrucciones adicionales al algoritmo para la gráfica:

    # GRAFICA
    import matplotlib.pyplot as plt
    
    muestras = 21  # muestras = tramos+1
    
    a = np.min(xi) # intervalo [a,b]
    b = np.max(xi)
    xk = np.linspace(a,b,muestras)
    yk = px(xk)
    
    # Usando evaluación simbólica
    ##yk = np.zeros(muestras,dtype=float)
    ##for k in range(0,muestras,1):
    ##    yin[k] = polinomio.subs(x,xk[k])
    
    plt.plot(xi,fi,'o', label='[xi,fi]')
    plt.plot(xk,yk, label='p(x)')
    plt.xlabel('xi')
    plt.ylabel('fi')
    plt.legend()
    plt.title(polinomio)
    plt.show()
    

    Interpolación: [ Ejercicio ] [ Analítico ] [ Algoritmo ] [ gráfica ] [ Función ]
    ..


    5. Vandermonde como función en Numpy.vander

    La matriz de Vandermonde se puede crear con Numpy usando la instrucción np.vander(xi,len(xi)).

    >>> import numpy as np
    >>> xi = [0. , 0.2, 0.3, 0.4]
    >>> fi = [1. , 1.6, 1.7, 2. ]
    >>> D = np.vander(xi,len(xi))
    >>> D
    array([[0.   , 0.   , 0.   , 1.   ],
           [0.008, 0.04 , 0.2  , 1.   ],
           [0.027, 0.09 , 0.3  , 1.   ],
           [0.064, 0.16 , 0.4  , 1.   ]])
    >>> coeficiente = np.linalg.solve(D,fi)
    >>> coeficiente
    array([ 41.66667, -27.5    ,   6.83333,   1.     ])

    Interpolación: [ Ejercicio ] [ Analítico ] [ Algoritmo ] [ gráfica ] [ Función ]