[ Dif_Finitas ] [ Dif_Finitas avanzadas ] [ Dif_Divididas_Newton ]
Solo para fines didácticos, y como complemento para los ejercicios presentados en la unidad para Interpolación polinómica, 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.
En los algoritmos, se convierten las partes en funciones, que se usan para generar los polinomios para cada grado y se incorporan en un gráfico animado con los resultados presentados.
Para la gráfica animada se añaden las instrucciones siguientes:
Se determina el intervalo para el eje x usando los valores mínimos y máximos del vector xi. Se toma como muestras para el polinomio las suficientes para una línea suave, que pueden ser mayores a 21 y se crean los valores para el polinomio en p_xi.
Para cada polinomio se guarda en una tabla los valores px(p_xi)del polinomio evaluado el vector p_xi
La gráfica (graf_ani) se crea en una ventana (fig_ani), inicializando con los puntos [xi,fi] en color rojo, y configurando los parámetros base para el gráfico.
Se usan procedimientos para crear unatrama() para cada polinomio 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'.
otros ejemplos de animación en el curso de Fundamentos de Programación:
Movimiento circular – Una partícula, animación con matplotlib-Python
Interpolación por Diferencias Finitas Avanzadas
En la función para interpolación se añade la verificación de tamaños de paso equidistantes o iguales. En el caso de no tener tamaños de paso equidistantes
tabla de diferencias finitas
['i', 'xi', 'fi', 'd1f', 'd2f']
[[0. 0.1 1.45 0.15 0. ]
[1. 0.2 1.6 0. 0. ]]
dfinita: [0.15 0. ]
1.45 +
+( 0.15 / 0.1 )* ( x - 0.1 )
polinomio simplificado
1.5*x + 1.3
tabla de diferencias finitas
['i', 'xi', 'fi', 'd1f', 'd2f', 'd3f']
[[ 0. 0.1 1.45 0.15 -0.05 0. ]
[ 1. 0.2 1.6 0.1 0. 0. ]
[ 2. 0.3 1.7 0. 0. 0. ]]
dfinita: [ 0.15 -0.05 0. ]
1.45 +
+( 0.15 / 0.1 )* ( x - 0.1 )
+( -0.05 / 0.02 )* (x - 0.2)*(x - 0.1)
polinomio simplificado
-2.5*x**2 + 2.25*x + 1.25
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. ]]
dfinita: [ 0.15 -0.05 0.25 0. ]
1.45 +
+( 0.15 / 0.1 )* ( x - 0.1 )
+( -0.05 / 0.02 )* (x - 0.2)*(x - 0.1)
+( 0.25 / 0.006 )* (x - 0.3)*(x - 0.2)*(x - 0.1)
polinomio simplificado
41.66667*x**3 - 27.500002*x**2 + 6.8333337*x + 0.99999998
Polinomios con Diferencias Finitas Avanzadas
px_0 =
1.45
px_1 =
1.5*x + 1.3
px_2 =
2
- 2.5*x + 2.25*x + 1.25
px_3 =
3 2
41.66667*x - 27.500002*x + 6.8333337*x + 0.99999998
El resumen de las instrucciones se presentan a continuación.
# Interpolación -Diferencias finitas avanzadas # Tarea: Verificar tamaño de vectores, # verificar puntos equidistantes en x import numpy as np import math import sympy as sym def dif_finitas(xi,fi, precision=5, vertabla=False): '''Genera la tabla de diferencias finitas resultado en: tabla,titulo Tarea: verificar tamaño de vectores ''' xi = np.array(xi,dtype=float) fi = np.array(fi,dtype=float) # Tabla de Diferencias Finitas titulo = ['i','xi','fi'] n = len(xi) ki = np.arange(0,n,1) tabla = np.concatenate(([ki],[xi],[fi]),axis=0) tabla = np.transpose(tabla) # diferencias finitas vacia dfinita = np.zeros(shape=(n,n),dtype=float) tabla = np.concatenate((tabla,dfinita), axis=1) # Calcula tabla, inicia en columna 3 [n,m] = np.shape(tabla) diagonal = n-1 j = 3 while (j < m): # Añade título para cada columna titulo.append('d'+str(j-2)+'f') # cada fila de columna i = 0 while (i < diagonal): tabla[i,j] = tabla[i+1,j-1]-tabla[i,j-1] i = i+1 diagonal = diagonal - 1 j = j+1 if vertabla==True: np.set_printoptions(precision) print('tabla de diferencias finitas') print(titulo) print(tabla) return(tabla, titulo) def pasosEquidistantes(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. ''' xi = np.array(xi,dtype=float) n = len(xi) # revisa tamaños de paso equidistantes h_iguales = True if n>3: dx = np.zeros(n,dtype=float) for i in range(0,n-1,1): # calcula hi como dx dx[i] = xi[i+1]-xi[i] for i in range(0,n-2,1): # revisa diferencias dx[i] = dx[i+1]-dx[i] if dx[i]<=casicero: # redondea cero dx[i]=0 if abs(dx[i])>0: h_iguales=False print('tamaños de paso diferentes en i:',i+1,',',i+2) dx[n-2]=0 return(h_iguales) def interpola_dfinitasAvz(xi,fi, vertabla=False, precision=5, casicero = 1e-15): '''Interpolación de diferencias finitas resultado: polinomio en forma simbólica, redondear a cero si es menor que casicero ''' xi = np.array(xi,dtype=float) fi = np.array(fi,dtype=float) n = len(xi) # revisa tamaños de paso equidistantes h_iguales = pasosEquidistantes(xi, casicero) if vertabla==True: np.set_printoptions(precision) # POLINOMIO con diferencias Finitas avanzadas x = sym.Symbol('x') polisimple = sym.S.NaN # expresión del polinomio con Sympy if h_iguales==True: tabla,titulo = dif_finitas(xi,fi,vertabla) h = xi[1] - xi[0] dfinita = tabla[0,3:] if vertabla==True: print('dfinita: ',dfinita) print(fi[0],'+') n = len(dfinita) polinomio = fi[0] for j in range(1,n,1): denominador = math.factorial(j)*(h**j) factor = np.around(dfinita[j-1]/denominador,precision) termino = 1 for k in range(0,j,1): termino = termino*(x-xi[k]) if vertabla==True: txt1='';txt2='' if n<=2 or j<=1: txt1 = '('; txt2 = ')' print('+(',np.around(dfinita[j-1],precision), '/',np.around(denominador,precision), ')*',txt1,termino,txt2) polinomio = polinomio + termino*factor # simplifica multiplicando entre (x-xi) polisimple = polinomio.expand() if vertabla==True: print('polinomio simplificado') print(polisimple) return(polisimple) # INGRESO , Datos de prueba xi = [0.10, 0.2, 0.3, 0.4] fi = [1.45, 1.6, 1.7, 2.0] # PROCEDIMIENTO # tabla polinomios n = len(xi) px_tabla = [fi[0]] for grado in range(1,n,1): polinomio = interpola_dfinitasAvz(xi[:grado+1],fi[:grado+1], vertabla=True, precision=4) print('',) px_tabla.append(polinomio) # SALIDA print('Polinomios con Diferencias Finitas Avanzadas') for grado in range(0,n,1): print('px_'+str(grado)+' =') #, px_tabla[grado]) sym.pprint(px_tabla[grado]) print()
Parte adicional para la gráfica con GIF animado
# GRAFICA CON ANIMACION polinomios -------- import matplotlib.pyplot as plt import matplotlib.animation as animation unmetodo = 'Diferencias Finitas Avanzadas' narchivo = 'DifFinitasAvz' # nombre archivo muestras = 51 # de cada p(X) # Puntos para la gráfica a = np.min(xi) b = np.max(xi) p_xi = np.linspace(a,b,muestras) # lineas por grado de polinomio x = sym.Symbol('x') px_lineas = np.zeros(shape=(n,muestras), dtype=float) for grado in range(0,n,1): polinomio = px_tabla[grado] px = sym.utilities.lambdify(x,polinomio,'numpy') px_lineas[grado] = px(p_xi) # Parametros de trama/foto retardo = 800 # milisegundos entre tramas tramas = len(px_lineas) ymax = np.max(fi) ymin = np.min(fi) deltax = 0.1*np.abs(b-a) deltay = 0.1*np.abs(ymax-ymin) # GRAFICA animada en fig_ani fig_ani, graf_ani = plt.subplots() # Función Base fx_linea, = graf_ani.plot(xi,fi,'o',color='red') # Polinomios de px_tabla grado = 0 px_unalinea, = graf_ani.plot(p_xi, px_lineas[0], label='grado: 0') # Configura gráfica graf_ani.set_xlim([a-deltax,b+deltax]) graf_ani.set_ylim([ymin-deltay,ymax+deltay]) graf_ani.axhline(0, color='k') # Linea horizontal en cero graf_ani.set_title('Polinomio - '+unmetodo) graf_ani.set_xlabel('x') graf_ani.set_ylabel('p(x)') graf_ani.grid() # Cuadros de texto en gráfico txt_x = (b+a)/2 txt_y = ymax txt_poli = graf_ani.text(txt_x, txt_y,'p(x):', horizontalalignment='center') txt_grado = graf_ani.text(txt_x, txt_y-deltay,'grado:', horizontalalignment='center') # Nueva Trama def unatrama(i,p_xi,pxi): # actualiza cada linea px_unalinea.set_xdata(p_xi) px_unalinea.set_ydata(pxi[i]) unpolinomio = px_tabla[i] if unpolinomio == sym.S.NaN: unpolinomio = 'h pasos no equidistantes' etiquetap = 'p'+str(i)+'(x) = '+str(unpolinomio) px_unalinea.set_label(etiquetap) # actualiza texto txt_poli.set_text(etiquetap) txt_grado.set_text('Grado: '+str(i)) # color de la línea if (i<=9): lineacolor = 'C'+str(i) else: numerocolor = i%10 lineacolor = 'C'+str(numerocolor) px_unalinea.set_color(lineacolor) return (px_unalinea, txt_poli, txt_grado) # Limpia Trama anterior def limpiatrama(): px_unalinea.set_ydata(np.ma.array(p_xi, mask=True)) px_unalinea.set_label('') txt_poli.set_text('') txt_grado.set_text('') return (px_unalinea,txt_poli, txt_grado) # Trama contador i = np.arange(0,tramas,1) ani = animation.FuncAnimation(fig_ani, unatrama, i , fargs = (p_xi,px_lineas), init_func = limpiatrama, interval = retardo, blit=True) # Graba Archivo GIFAnimado y video ani.save(narchivo+'_GIFanimado.gif', writer='pillow') # ani.save(narchivo+'_video.mp4') plt.draw() plt.show()
[ Dif_Finitas ] [ Dif_Finitas avanzadas ] [ Dif_Divididas_Newton ]
Interpolación por Diferencias Divididas de Newton
tabla de diferencias divididas
['i', 'xi', 'fi', 'F[1]', 'F[2]']
[[0. 0.1 1.45 1.5 0. ]
[1. 0.2 1.6 0. 0. ]]
difDividida: [1.5 0. ]
1.45 +
+( 1.5 )*( x - 0.1 )
polinomio simplificado
1.5*x + 1.3
tabla de diferencias divididas
['i', 'xi', 'fi', 'F[1]', 'F[2]', 'F[3]']
[[ 0. 0.1 1.45 1.5 -2.5 0. ]
[ 1. 0.2 1.6 1. 0. 0. ]
[ 2. 0.3 1.7 0. 0. 0. ]]
difDividida: [ 1.5 -2.5 0. ]
1.45 +
+( 1.5 )*( x - 0.1 )
+( -2.5 )* (x - 0.2)*(x - 0.1)
polinomio simplificado
-2.5*x**2 + 2.25*x + 1.25
tabla de diferencias divididas
['i', 'xi', 'fi', 'F[1]', 'F[2]', 'F[3]', 'F[4]']
[[ 0.00000e+00 1.00000e-01 1.45000e+00 1.50000e+00 -2.50000e+00
5.00000e+00 0.00000e+00]
[ 1.00000e+00 2.00000e-01 1.60000e+00 1.00000e+00 3.33067e-15
0.00000e+00 0.00000e+00]
[ 2.00000e+00 3.00000e-01 1.70000e+00 1.00000e+00 0.00000e+00
0.00000e+00 0.00000e+00]
[ 3.00000e+00 6.00000e-01 2.00000e+00 0.00000e+00 0.00000e+00
0.00000e+00 0.00000e+00]]
difDividida: [ 1.5 -2.5 5. 0. ]
1.45 +
+( 1.5 )*( x - 0.1 )
+( -2.5 )* (x - 0.2)*(x - 0.1)
+( 5.0 )* (x - 0.3)*(x - 0.2)*(x - 0.1)
polinomio simplificado
5.0*x**3 - 5.5*x**2 + 2.8*x + 1.22
Polinomios con Diferencias Divididas Newton
px_0 =
1.45
px_1 =
1.5*x + 1.3
px_2 =
2
- 2.5*x + 2.25*x + 1.25
px_3 =
3 2
5.0*x - 5.5*x + 2.8*x + 1.22
>>>
Instrucciones en Python
# Interpolación -Diferencias Divididas de Newton # Tarea: Verificar tamaño de vectores, import numpy as np import sympy as sym def dif_divididas(xi,fi, vertabla=False, precision=5, casicero = 1e-15): '''Genera la tabla de diferencias divididas resultado en: tabla, titulo Tarea: verificar tamaño de vectores ''' xi = np.array(xi,dtype=float) fi = np.array(fi,dtype=float) # Tabla de Diferencias Divididas titulo = ['i','xi','fi'] n = len(xi) ki = np.arange(0,n,1) tabla = np.concatenate(([ki],[xi],[fi]),axis=0) tabla = np.transpose(tabla) # diferencias divididas vacia dfinita = np.zeros(shape=(n,n),dtype=float) tabla = np.concatenate((tabla,dfinita), axis=1) # Calcula tabla, inicia en columna 3 [n,m] = np.shape(tabla) diagonal = n-1 j = 3 while (j < m): # Añade título para cada columna titulo.append('F['+str(j-2)+']') # cada fila de columna i = 0 paso = j-2 # inicia en 1 while (i < diagonal): denominador = (xi[i+paso]-xi[i]) numerador = tabla[i+1,j-1]-tabla[i,j-1] tabla[i,j] = numerador/denominador if np.abs(tabla[i,j])<= casicero: tabla[i,j] = 0 i = i+1 diagonal = diagonal - 1 j = j+1 if vertabla==True: np.set_printoptions(precision) print('tabla de diferencias divididas') print(titulo) print(tabla) return(tabla, titulo) def interpola_difDividida(xi,fi, vertabla=False, precision=5, casicero = 1e-15): '''Interpolación de diferencias finitas resultado: polinomio en forma simbólica, redondear a cero si es menor que casicero ''' xi = np.array(xi,dtype=float) fi = np.array(fi,dtype=float) # Tabla de Diferencias Divididas tabla,titulo = dif_divididas(xi,fi,vertabla, precision,casicero) dDividida = tabla[0,3:] n = len(dDividida) x = sym.Symbol('x') polinomio = fi[0] if vertabla==True: print('difDividida: ',dDividida) print(fi[0],'+') for j in range(1,n,1): factor = np.around(dDividida[j-1],precision) termino = 1 for k in range(0,j,1): termino = termino*(x-xi[k]) if vertabla==True: txt1='';txt2='' if n<=2 or j<=1: txt1 = '('; txt2 = ')' print('+(',factor,')*'+txt1,termino,txt2) polinomio = polinomio + termino*factor # simplifica multiplicando entre (x-xi) polisimple = polinomio.expand() if vertabla==True: print('polinomio simplificado') print(polisimple) return(polisimple) # INGRESO , Datos de prueba xi = [0.10, 0.2, 0.3, 0.6] fi = [1.45, 1.6, 1.7, 2.0] # PROCEDIMIENTO # tabla polinomios n = len(xi) px_tabla = [fi[0]] for grado in range(1,n,1): polinomio = interpola_difDividida(xi[:grado+1],fi[:grado+1], vertabla=True) print('',) px_tabla.append(polinomio) # SALIDA print('Polinomios con Diferencias Divididas Newton') for grado in range(0,n,1): print('px_'+str(grado)+' =') #, px_tabla[grado]) sym.pprint(px_tabla[grado]) print()
Para la gráfica animada se usa el mismo bloque de instrucciones del método de Diferencias Finitas avanzadas, solo requiere cambiar el nombre del método y el nombre para el archivo GIF animado.
Interpolación por el Método de Lagrange
Interpola con Lagrange 1.45 * (x - 0.4)*(x - 0.3)*(x - 0.2) / (-0.2 + 0.1)*(-0.3 + 0.1)*(-0.4 + 0.1) + 1.6 * (x - 0.4)*(x - 0.3)*(x - 0.1) / (-0.1 + 0.2)*(-0.3 + 0.2)*(-0.4 + 0.2) + 1.7 * (x - 0.4)*(x - 0.2)*(x - 0.1) / (-0.1 + 0.3)*(-0.2 + 0.3)*(-0.4 + 0.3) + 2.0 * (x - 0.3)*(x - 0.2)*(x - 0.1) / (-0.1 + 0.4)*(-0.2 + 0.4)*(-0.3 + 0.4) polinomio simplificado 41.666667*x**3 - 27.5*x**2 + 6.833333*x + 1.0 Interpolación con Lagrange 41.666667*x**3 - 27.5*x**2 + 6.833333*x + 1.0 >>>
Instrucciones en Python
# Interpolación - Lagrange # Tarea: Verificar tamaño de vectores, import numpy as np import sympy as sym def interpola_Lagrange(xi,fi,vertabla=False, precision=6, casicero = 1e-15): ''' Interpolación con método de Lagrange resultado: polinomio en forma simbólica ''' xi = np.array(xi,dtype=float) fi = np.array(fi,dtype=float) n = len(xi) x = sym.Symbol('x') # Polinomio con Lagrange if vertabla==True: print('Interpola con Lagrange') polinomio = sym.S.Zero for i in range(0,n,1): # Termino de Lagrange termino = 1 numerador = 1 denominador = 1 for j in range(0,n,1): if (j!=i): numerador = numerador*(x-xi[j]) denominador = denominador*(sym.UnevaluatedExpr(xi[i])-xi[j]) if vertabla==True: txt0='' ; txt1='('; txt2=')' if i>0: txt0='+' if n>2: txt1=''; txt2='' print(txt0,fi[i],'*'+txt1,numerador,txt2+'/'+ txt1, denominador,txt2) #factor = np.around(fi[i]/float(denominador.doit()),precision) polinomio = polinomio + (fi[i]/denominador.doit())*numerador # Expande el polinomio polisimple = polinomio.expand() polisimple = redondea_coef(polisimple, precision) if vertabla==True: print('polinomio simplificado') print(polisimple) return(polisimple) def redondea_coef(ecuacion, precision=6,casicero = 1e-15): ''' redondea coeficientes de términos suma de una ecuacion ''' tipo = type(ecuacion) tipo_eq = False if tipo == sym.core.relational.Equality: RHS = ecuacion.rhs ecuacion = ecuacion.lhs tipo = type(ecuacion) tipo_eq = True if tipo == sym.core.add.Add: # términos suma de ecuacion term_sum = sym.Add.make_args(ecuacion) ecuacion = sym.S.Zero for term_k in term_sum: # factor multiplicativo de termino suma term_mul = sym.Mul.make_args(term_k) producto = sym.S.One for factor in term_mul: if not(factor.has(sym.Symbol)): factor = np.around(float(factor),precision) if (abs(factor)%1)<casicero: # si es entero factor = int(factor) producto = producto*factor ecuacion = ecuacion + producto if tipo == sym.core.mul.Mul: # termino único, busca factores term_mul = sym.Mul.make_args(ecuacion) producto = sym.S.One for factor in term_mul: if not(factor.has(sym.Symbol)): factor = np.around(float(factor),precision) print(factor) if (abs(factor)%1)<casicero: # si es entero factor = int(factor) producto = producto*factor ecuacion = producto if tipo == float: # si es entero if (abs(ecuacion)%1)<casicero: ecuacion = int(ecuacion) if tipo_eq: ecuacion = sym.Eq(ecuacion,RHS) return(ecuacion) # INGRESO , Datos de prueba xi = [0.10, 0.2, 0.3, 0.4] fi = [1.45, 1.6, 1.7, 2.0] # PROCEDIMIENTO # tabla polinomios polisimple = interpola_Lagrange(xi,fi, vertabla=True) # SALIDA print('Interpolación con Lagrange') print(polisimple)
Para la gráfica animada se usa el mismo bloque de instrucciones del método de Diferencias Finitas avanzadas, solo requiere cambiar el nombre del método y el nombre para el archivo GIF animado.

