Está en la página 1de 10

3/6/22, 11:54 Actividad Grupal Equipo 9

ACTIVIDAD EQUIPO N 9 - PROGRAMACIÓN


CIENTÍFICA
Esta actividad consiste en escribir código, con la ayuda de algunas Bibliotecas de Python (en
nuestro caso particular: Numpy para los métodos numéricos, Sympy para cálculo simbólico,
Interpolation de Scipy para escribir nuestros polinomios de interpolación, y Matplotlib para
graficar nuestros resultados).

Cabe destacar que en este apartado explicaremos paso por paso nuestro código. Se presentará,
junto con este notebook, un documento de Word que recopilará los resultados de hacer para
cada función, tipo de nodo, y número de nodo con sus respectivas conclusiones.

Explicaremos caso por caso los siguientes pasos:

1. La función a evaluar
2. Obtención de Nodos Equiespaciados
3. Obtención de Nodos Ortogonales mediante las raices del polinomio de Chebyshev
4. Obtención de los Polinomios de Interpolación y Graficar: Lagrange, Baricéntrica, Newton y
Splines

Comencemos de una vez con:

La Función a Evaluar
Como necesitaremos importar varias bibliotecas para empezar a escribir nuestros códigos, lo
haremos en el siguiente apartado:

In [182…
import numpy as np

import scipy as scp

import sympy as syp

from scipy.interpolate import lagrange

from scipy.interpolate import barycentric_interpolate

from scipy.interpolate import UnivariateSpline

import matplotlib.pyplot as plt

from timeit import default_timer

import plotly.graph_objects as go

Ahora que tenemos nuestros paquetes cargados, vamos a escribir una función muy simple que
nos devuelva nuestro f(x) a evaluar:

In [165…
def fun(xi):

return np.sin(xi)

Dejaremos el caso para sen(x) nada mas para fines ilustrativos. Ahora, cada que necesitemos
escribir una función, simplemente tenemos que cambiar la expresión en nuestra función para
ese fin. La función nos devolverá los valores correspondientes en la función de los nodos
escogidos por cualquiera de los métodos. Tambien trabajaremos con funciones y variables
simbólicas, pero se especificará en su momento.

localhost:8888/nbconvert/html/Actividad Grupal Equipo 9.ipynb?download=false 1/10


3/6/22, 11:54 Actividad Grupal Equipo 9

Obtención de Nodos Equiespaciados


Estos son los nodos de toda la vida: escogemos un intervalo, definimos un (n) y con unas
fórmulas muy sencillas obtenemos unos puntos dentro de ese intérvalo por donde tendrá que
pasar nuestra función interpoladora. Nuestro código queda como sigue:

In [166…
def NodosEq(n,a,b):

h=(b-a)/n

xi=np.zeros(n+1)

for i in range(n+1):

xi[i]=a+i*h

return xi

Así que: si queremos, por ejemplo, 11 nodos equiespaciados desde -5 a 5 usando las fórmulas
conocidas, tendremos:

In [167…
n=11

a=-5

b=5

xi=NodosEq((n),(a),(b))

xi

array([-5. , -4.09090909, -3.18181818, -2.27272727, -1.36363636,

Out[167…
-0.45454545, 0.45454545, 1.36363636, 2.27272727, 3.18181818,

4.09090909, 5. ])
Como vemos tenemos una función que devuelve, a partir de un intervalo, el número de nodos
que le pidamos. Cabde destacar que calcularemos como se calcula en la mayoría de los libros de
texto de análisis numérico: donde se piden n nodos, pero además se agrega el nodo N0, dando
como resultado n+1 puntos que evalauar.

Obtención de Nodos Ortogonales


Para los nodos ortogonales tenemos de hecho varias herramientas. Hay una bastante útil que
incluso podría ayudarnos a ahorrar un poco de poder computacional. Dado que los nodos
ortogonales obtenidos por este método, requieren que se calcule una serie de polinomios del
grado n, esto podría llevanos unos cuantos recursos. Pero, podemos usar una fórmula mucho
más sencilla, complementada con una pequeña transformación lineal, que nos permitirá obtener
estos nodos ortogonales (Burden, Faires, 2011). Como siempre, escribiremos una función para
ello:

In [168…
def NodosOrt(a,b,n):

k= np.linspace(0,n,n+1)

f=np.cos(np.pi*(2*k+1)/(2*(n+1)))

xi=0.5*(b-a)*f+0.5*(b+a)

xi=xi[::-1]

return xi

In [169…
n=11

a=-5

b=5

xi=NodosOrt((a),(b),(n))

xi

localhost:8888/nbconvert/html/Actividad Grupal Equipo 9.ipynb?download=false 2/10


3/6/22, 11:54 Actividad Grupal Equipo 9

array([-4.95722431, -4.61939766, -3.9667667 , -3.04380715, -1.91341716,

Out[169…
-0.65263096, 0.65263096, 1.91341716, 3.04380715, 3.9667667 ,

4.61939766, 4.95722431])
Ya tenemos nuestros dos métodos de obtención de nodos. Ahora vamos por los polinomios de
interpolación:

Polinomios de Interpolación y sus Gráficas


Ahora vamos al trabajo mas duro; los polinomios de interpolación. Por ahora sabemos tenemos
algunas herramientas que harán la mayoría del trabajo pesado por nosotros: lagrange,
barycentric_interpolate y InterpolatedUnivariateSpline se harán cargo de la interpolación de
Lagrange, Baricéntrica y Splines Cúbicos por nosotros. Eso nos deja con la tarea de escribir
nuestras propias funciones para obtener la función para Diferencias de Newton.
Sin mas
dilación, empezemos.

Interpolación de Lagrange
Como dijimos, tenemos cubierto este inciso haciendo uso de las funciones que ya tenemos a
disposición en la bibliotecas que cargamos al principio.

In [170…
yi=fun(xi)

l=lagrange(xi,yi)

print ('el polinomio de lagrange es:')

print (l)

el polinomio de lagrange es:

11 10 9 8 7

-1.536e-08 x - 1.652e-20 x + 2.503e-06 x - 1.301e-18 x - 0.0001953 x

6 5 4 3 2

+ 3.751e-17 x + 0.008315 x + 3.903e-16 x - 0.1666 x + 3.227e-16 x + 1 x - 5.204e-18

La función incluso devuelve el polinomio en forma bastante simplicafada. Ahora vamos por su
gráfica.

In [172…
from numpy.polynomial.polynomial import Polynomial

Polynomial(l.coef[::-1]).coef

plt.scatter(xi, yi, label='Nodos')

xp=np.linspace(min(xi),max(xi))

plt.plot(xp, Polynomial(l.coef[::-1])(xp), label='Poli')

plt.plot(xp, np.sin(xp), label='original',linestyle='-.')

plt.plot()

plt.legend()

plt.show()

localhost:8888/nbconvert/html/Actividad Grupal Equipo 9.ipynb?download=false 3/10


3/6/22, 11:54 Actividad Grupal Equipo 9

Gracias a la ayuda de las herramientas que tenemos a mano, pudimos no solo graficar ambas
funciones, sino que incluso tenemos la posibilidad de colocar nuestros puntos para demostrar
que en efecto estamos pasando por ellos.

Interpolación Baricéntrica
Aquí tenemos también una herramienta a usar que nos viene desde interpolation de scipy.

In [173…
yi=fun(xi)

xo=np.linspace(min(xi),max(xi),100)

p=barycentric_interpolate(xi,yi,xo)

plt.scatter(xi, yi, label='Nodos')

xp=np.linspace(min(xi),max(xi))

plt.plot(xp, barycentric_interpolate(xi,yi,xp), label='Poli')

plt.plot(xp, fun(xp), label='original',linestyle='-.')

plt.legend()

plt.show()

Por desgracia, la herramienta barycentric_interpolate no arroja el polinomio ni tiene alguna


propiedad coef que llamar para poder construir el nuestro, lo que tiene sentido por el tipo de
interpolación que resulta a veces en un polinomio de tipo racional. Sin embargo, y solo para
poder tener una mejor idea de que sucede con esta interpolación, decidimos escribir nuestro
propio código para poder generar una función que nos deje ver el polinomio resultante.

In [174…
def PoliBar(xi,yi):

x=syp.symbols('x',real=True)

localhost:8888/nbconvert/html/Actividad Grupal Equipo 9.ipynb?download=false 4/10


3/6/22, 11:54 Actividad Grupal Equipo 9

p=0

q=0

n=len(xi)

w=1

for i in range(0,n):

for j in range(0,n):

if j==i:

continue

else:

w=w*1/((xi[i]-xi[j]))

p=p+((w*yi[i])/(x-xi[i]))

q=q+w/(x-xi[i])

w=1

r=p/q

r=syp.simplify(r)

return r

In [175…
r=PoliBar(xi,yi)

x=syp.symbols('x',real=True)

syp.plot((r,(x,-5,5)),(syp.sin(x),(x,-5,5)))

Out[175… 1.53568162914043 ⋅ 10
−8
x
11
+ 6.7762635780344 ⋅ 10
−21
x
10
− 2.50301596709575 ⋅ 10
−6
x
9

5 −16 4 3
− 0.00831517175348184x + 1.80411241501588 ⋅ 10 x + 0.166628107330418x + 4.44

−22 11 −20 10 −19 9


3.70576914423756 ⋅ 10 x − 1.22819777351874 ⋅ 10 x + 1.0842021724855 ⋅ 10 x

−17 5 −16 4 −16


− 8.67361737988404 ⋅ 10 x − 4.11129463806503 ⋅ 10 x + 7.64145691167784 ⋅ 10 x

Si bien que no es el polinomio más bonito, vemos que podemos obtener un polinomio
expresado como una función para este caso. Cabe notar que estamos usando la función plot del
sympy que, lamentablemente, no permite las graficas de puntos tipo scatter. Pero vemos que el
polinomio cumple con su objetivo: acomodarse a la función original, que es seno en este caso
ilustrativo.

Interpolación de Newton
Como habiamos dicho, no tenemos alguna función que venga precargada en las bibliotecas que
hemos consultado. Así que toca escribir una función propia tal como hicimos para nuestro
polinomio de la interpolación baricéntrica.

localhost:8888/nbconvert/html/Actividad Grupal Equipo 9.ipynb?download=false 5/10


3/6/22, 11:54 Actividad Grupal Equipo 9

In [176… def PoliNewton(xi,yi):

x=syp.symbols('x',real=True)

n=len(xi)

bn=np.zeros([n,n]) #para almacenar los valores de la tabla de diferencias

#asignar los valores

for i in range(0,n):

bn[i,0]=yi[i]

#inicializando variables para trabajar

i=0

j=1

p=0

vx=1

for j in range(1,n):

for i in range(0,n-j):

bn[i,j]=(bn[i+1,j-1]-bn[i,j-1])/(xi[i+j]-xi[i])

print ('la primera fila de la tabla de diferencias que corresponde a los coefici
print (bn[0])

p=bn[0,0]

for i in range(1,n):

for j in range(0,i):

vx=vx*(x-xi[j])

p=p+bn[0,i]*vx

vx=1

return p.simplify()

In [177…
p=PoliNewton(xi,yi)

syp.plot ((p,(x,-5,5)),(syp.sin(x),(x,-5,5)))

la primera fila de la tabla de diferencias que corresponde a los coeficientes b_n de


l polinomio de Newton de x^0 hasta x^(n-1) queda como sigue:

[ 9.70177254e-01 7.54889179e-02 -4.80009856e-01 8.44083995e-02

2.00976126e-02 -7.04719083e-03 5.09027372e-04 7.22160631e-05

-1.69056082e-05 9.99593014e-07 7.61271830e-08 -1.53568163e-08]

Out[177… −1.53568162914053 ⋅ 10
−8
x
11
+ 1.01908651466533 ⋅ 10
−21
x
10
+ 2.5030159670958 ⋅ 10
−6
x
9

5 −17 4 3
+ 0.00831517175348189x − 1.39319979164387 ⋅ 10 x − 0.166628107330418x + 3.4932

Otra vez hemos obtenido tanto el polinomio para ser visualizado y su respectiva gráfica que se
amolda bastante bien a la función original en el caso de seno.

Interpolación con Splines Cúbicos


localhost:8888/nbconvert/html/Actividad Grupal Equipo 9.ipynb?download=false 6/10
3/6/22, 11:54 Actividad Grupal Equipo 9

Ahora vamos al último caso de nuestras interpolaciones hechas con splines cúbicos. Como
sabemos, los splines cúbicos son funciones cúbicas a trozos. Vamos a usar el UnivariateSpline
con k=3 para poder obtener nuestra función de spline. Tenemos la desventaja que, tal y como
sucede en los casos anteriores, no tenemos la posibilidad de ver las funciones expresadas
simbólicamente directamente. Sin embargo, podemos recurrir a un par de alternativas. Sabemos
que los splines cúbicos son un poco engorrosos de calcular, y para ello podemos hacer uso
tanto de los fundamentos teóricos de los splines, como de algunos algoritmos mas
especializados. Se encontró en internet un código en base al algoritmo de Jacobi que permite
ver los coeficientes de cada uno de los trozos de gráfica. Se implementan a continuación dos
funciones:

In [178…
import pandas as pd

import numpy as np

def jacobi(A, b, x0, tol, n_iterations=300):

n = A.shape[0]

x = x0.copy()

x_prev = x0.copy()

counter = 0

x_diff = tol+1

while (x_diff > tol) and (counter < n_iterations):

for i in range(0, n):

s = 0

for j in range(0,n):

if i != j:

s += A[i,j] * x_prev[j]

x[i] = (b[i] - s) / A[i,i]

counter += 1

x_diff = (np.sum((x-x_prev)**2))**0.5

x_prev = x.copy()

return x

def cubic_spline(x, y, tol = 1e-100):

x = np.array(x)

y = np.array(y)

if np.any(np.diff(x) < 0):

idx = np.argsort(x)

x = x[idx]

y = y[idx]

size = len(x)

delta_x = np.diff(x)

delta_y = np.diff(y)

A = np.zeros(shape = (size,size))

b = np.zeros(shape=(size,1))

A[0,0] = 1

A[-1,-1] = 1

for i in range(1,size-1):

A[i, i-1] = delta_x[i-1]

A[i, i+1] = delta_x[i]

A[i,i] = 2*(delta_x[i-1]+delta_x[i])

b[i,0] = 3*(delta_y[i]/delta_x[i] - delta_y[i-1]/delta_x[i-1])

c = jacobi(A, b, np.zeros(len(A)), tol = tol, n_iterations=1000)

localhost:8888/nbconvert/html/Actividad Grupal Equipo 9.ipynb?download=false 7/10


3/6/22, 11:54 Actividad Grupal Equipo 9

d = np.zeros(shape = (size-1,1))

b = np.zeros(shape = (size-1,1))

for i in range(0,len(d)):

d[i] = (c[i+1] - c[i]) / (3*delta_x[i])

b[i] = (delta_y[i]/delta_x[i]) - (delta_x[i]/3)*(2*c[i] + c[i+1])

return b.squeeze(), c.squeeze(), d.squeeze()

In [179…
p=cubic_spline(xi, yi, tol = 1e-100)

(array([ 0.14290692, -0.05934709, -0.69040258, -0.98462057, -0.3272742 ,

Out[179…
0.77991455, 0.77991455, -0.3272742 , -0.98462057, -0.69040258,

-0.05934709]),

array([ 0. , -0.59869169, -0.36824908, 0.0494724 , 0.53204936,

0.34612392, -0.34612392, -0.53204936, -0.0494724 , 0.36824908,

0.59869169, 0. ]),

array([-0.59072871, 0.11769929, 0.15086305, 0.14230397, -0.04915595,

-0.17678389, -0.04915595, 0.14230397, 0.15086305, 0.11769929,

-0.59072871]))
La primer fila hace referencia a los coeficientes de grado 1, la segunda de grado 2 y la tercera de
grado 3

Ahora usaremos el scipy.interpolate.UnivariateSpline para graficar nuestros splines

In [180…
spline = UnivariateSpline(xi,yi,k=3,s=0.00)

xp=np.linspace(min(xi),max(xi))

plt.scatter(xi, yi, label='Nodos')

plt.plot(xp,spline(xp),color='red',linestyle='--',label='Poli')

plt.plot(xp, fun(xp), label='original',linestyle='-.')

plt.legend()

plt.show()

Cálculo del Error y Midiendo el Tiempo del Algoritmo:


Hemos finalizado todos nuestros métodos de interpolación. Sin embargo, aún no hemos
terminado del todo. Ddebemos calcular aún dos cosas más: El error de la interpolación y el
tiempo que le toma al algoritmo calcular cada caso.
Para el primero haremos uso de una tabla y
para el segundo haremos un código bastante sencillo: usaremos la biblioteca timeit y con una
operación bastante sencilla, podremos ver en pantalla el tiempo que le toma al programa
recorrer todo nuestro código.

localhost:8888/nbconvert/html/Actividad Grupal Equipo 9.ipynb?download=false 8/10


3/6/22, 11:54 Actividad Grupal Equipo 9

In [183… #para calcular nuestro tiempo de ejecución

inicio=default_timer()

fin=default_timer()

print ('El tiempo de ejecución fue de :'+str(fin-inicio))

El tiempo de ejecución fue de :5.359999886422884e-05

In [184…
a=np.linspace(min(xi),max(xi),n)

b=spline(a)

c=np.sin(a)

d=b-c

fig = go.Figure(data=[go.Table(

header=dict(values=['x','Interpolación', 'Función Original','Error']),

cells=dict(values=[a,b,c,d]))])

print ('Tabla error')

fig.show()

Tabla error

x Interpolación

-4.957224306869052 0.9701772544214131
-3.9657794454952415 0.7339959814686711
-2.974334584121431 -0.16597140028926202
-1.982889722747621 -0.9166960110967988
-0.9914448613738105 -0.8297763809729726
0 1.249000902703301e-16
0 99144486137381 0 8297763809729726

Esto es, en pocas palabras, nuestro código explicado paso por paso. Se presentarán los
resultados en un documento de Word de los siguientes casos:
Para los nodos equiespaciados

1. función trigonométrica (sin(x)), nodos equiespaciados, n=11 para Lagrange, Baricéntrica,


Newton y Splines (-5,5)
2. función trigonométrica (sin(x)), nodos equiespaciados, n=21 para Lagrange, Baricéntrica,
Newton y Splines (-5,5)

localhost:8888/nbconvert/html/Actividad Grupal Equipo 9.ipynb?download=false 9/10


3/6/22, 11:54 Actividad Grupal Equipo 9

3. función exponencial (e^(-20x^2)), nodos equiespaciados, n=11 para Lagrange, Baricéntrica,


Newton y Splines (-2,2)
4. función exponencial (e^(-20x^2)), nodos equiespaciados, n=21 para Lagrange, Baricéntrica,
Newton y Splines (-2,2)
5. función Racional (1/(1+25x^2)), nodos equiespaciados, n=11 para Lagrange, Baricéntrica,
Newton y Splines (-1.5,1.5)
6. función Racional (1/(1+25x^2)), nodos equiespaciados, n=21 para Lagrange, Baricéntrica,
Newton y Splines (-1.5,1.5)

Para los nodos Ortogonales

1. función trigonométrica (sin(x)), nodos ortogonales, n=11 para Lagrange, Baricéntrica,


Newton y Splines (-5,5)
2. función trigonométrica (sin(x)), nodos ortogonales, n=21 para Lagrange, Baricéntrica,
Newton y Splines (-5,5)
3. función exponencial (e^(-20x^2)), nodos ortogonales, n=11 para Lagrange, Baricéntrica,
Newton y Splines (-2,2)
4. función exponencial (e^(-20x^2)), nodos ortogonales, n=21 para Lagrange, Baricéntrica,
Newton y Splines (-2,2)
5. función Racional (1/(1+25x^2)), nodos ortogonales, n=11 para Lagrange, Baricéntrica,
Newton y Splines (-1.5,1.5)
6. función Racional (1/(1+25x^2)), nodos ortogonales, n=21 para Lagrange, Baricéntrica,
Newton y Splines (-1.5,1.5)

localhost:8888/nbconvert/html/Actividad Grupal Equipo 9.ipynb?download=false 10/10

También podría gustarte