Ejercicio: 1Eva_IIT2018_T2 Distancia mínima a un punto
Literal a
Se requiere analizar la distancias entre una trayectoria y el punto = [1,1]
Al analizar las distancias de ex y el punto [1,1] se trazan lineas paralelas a los ejes desde el punto [1,1], por lo que se determina que el intervalo de x = [a,b] para distancias se encuentra en:
a > 0, a = 0.1
b < 1, b = 0.7
El ejercicio usa la fórmula de distancia entre dos puntos:
d = \sqrt{(x_2-x_1)^2+(y_2- y_1)^2}
en los cuales:
[x1,y1] = [1,1]
[x2,y2] = [x, ex]
que al sustituir en la fórmula se convierte en:
d = \sqrt{(x-1)^2+(e^x- 1)^2}
que es lo requerido en el literal a
Literal b
Para usar un método de búsqueda de raíces, se requiere encontrar el valor cuando f(x) = d’ = 0.
Un método como el de Newton Raphson requiere también f'(x) = d''
f(x) = \frac{x + (e^x - 1)e^x - 1}{\sqrt{(x - 1)^2 + (e^x - 1)^2}}
f'(x)= \frac{(e^x - 1)e^x + e^{2x} + 1 - \frac{(x + (e^x - 1)e^x - 1)^2}{(x - 1)^2 + (e^x - 1)^2}} {\sqrt{(x - 1)^2 + (e^x - 1)^2}}
expresiones obtenidas usando Sympy
f(x) :
(x + (exp(x) - 1)*exp(x) - 1)/sqrt((x - 1)**2 + (exp(x) - 1)**2)
f'(x) :
((exp(x) - 1)*exp(x) + exp(2*x) + 1 - (x + (exp(x) - 1)*exp(x) - 1)**2/((x - 1)**2 + (exp(x) - 1)**2))/sqrt((x - 1)**2 + (exp(x) - 1)**2)
f(x) :
/ x \ x
x + \e - 1/*e - 1
--------------------------
______________________
/ 2
/ 2 / x \
\/ (x - 1) + \e - 1/
f'(x) :
2
/ / x \ x \
/ x \ x 2*x \x + \e - 1/*e - 1/
\e - 1/*e + e + 1 - ----------------------
2
2 / x \
(x - 1) + \e - 1/
-----------------------------------------------
______________________
/ 2
/ 2 / x \
\/ (x - 1) + \e - 1/
lo que permite observar la raíz de f(x) en una gráfica:
con las siguientes instrucciones:
# Eva_IIT2018_T2 Distancia mínima a un punto
import numpy as np
import matplotlib.pyplot as plt
import sympy as sym
# INGRESO
x = sym.Symbol('x')
fx = sym.sqrt((x-1)**2+(sym.exp(x) -1)**2)
a = 0
b = 1
muestras = 21
# PROCEDIMIENTO
dfx = sym.diff(fx,x,1)
d2fx = sym.diff(fx,x,2)
f = sym.lambdify(x,dfx)
xi = np.linspace(a,b,muestras)
fi = f(xi)
# SALIDA
print('f(x) :')
print(dfx)
print("f'(x) :")
print(d2fx)
print()
print('f(x) :')
sym.pprint(dfx)
print("f'(x) :")
sym.pprint(d2fx)
# GRAFICA
plt.plot(xi,fi, label='f(x)')
plt.axhline(0)
plt.xlabel('x')
plt.ylabel('f(x)')
plt.legend()
plt.grid()
plt.show()
Usando el método de la bisección para el intervalo dado, se tiene:
f(x) = \frac{x + (e^x - 1)e^x - 1}{\sqrt{(x - 1)^2 + (e^x - 1)^2}}
itera = 0 , a = 0, b=1
c= \frac{0+1}{2} = 0.5
f(0) = \frac{0 + (e^0 - 1)e^0 - 1}{\sqrt{(0 - 1)^2 + (e^0 - 1)^2}} = -1
f(1) = \frac{1 + (e^1 - 1)e^1 - 1}{\sqrt{(1 - 1)^2 + (e^1 - 1)^2}} 2.7183
f(0.5) = \frac{(0.5) + (e^(0.5) - 1)e^(0.5) - 1}{\sqrt{((0.5) - 1)^2 + (e^(0.5) - 1)^2}} = 0.6954
cambio de signo a la izquierda,
a= 0, b=c=0.5
tramo = |0.5-0| = 0.5
itera = 1
c= \frac{0+0.5}{2} = 0.25
f(0.25) = \frac{(0.25) + (e^(0.25) - 1)e^(0.25) - 1}{\sqrt{((0.25) - 1)^2 + (e^(0.25) - 1)^2}} = -0.4804
cambio de signo a la derecha,
a=c= 0.25, b=0.5
itera = 2
c= \frac{0.25+0.5}{2} = 0.375
f(0.375) = \frac{(0.375) + (e^(0.375) - 1)e^(0.375) - 1}{\sqrt{((0.375) - 1)^2 + (e^(0.375) - 1)^2}} = 0.0479
cambio de signo a la izquierda,
a= 0.25, b=c=0.375
se continúan las iteraciones con el algoritmo, para encontrar la raíz en 0.364:
método de Bisección
i ['a', 'c', 'b'] ['f(a)', 'f(c)', 'f(b)']
tramo
0 [0, 0.5, 1] [-1. 0.6954 2.7183]
0.5
1 [0, 0.25, 0.5] [-1. -0.4804 0.6954]
0.25
2 [0.25, 0.375, 0.5] [-0.4804 0.0479 0.6954]
0.125
3 [0.25, 0.3125, 0.375] [-0.4804 -0.2388 0.0479]
0.0625
4 [0.3125, 0.34375, 0.375] [-0.2388 -0.1004 0.0479]
0.03125
5 [0.34375, 0.359375, 0.375] [-0.1004 -0.0274 0.0479]
0.015625
6 [0.359375, 0.3671875, 0.375] [-0.0274 0.01 0.0479]
0.0078125
7 [0.359375, 0.36328125, 0.3671875] [-0.0274 -0.0088 0.01 ]
0.00390625
8 [0.36328125, 0.365234375, 0.3671875] [-0.0088 0.0006 0.01 ]
0.001953125
9 [0.36328125, 0.3642578125, 0.365234375] [-0.0088 -0.0041 0.0006]
0.0009765625
raíz en: 0.3642578125
Al algoritmo anterior se complementa con las instrucciones de la función para la bisección.
# Eva_IIT2018_T2 Distancia mínima a un punto
import numpy as np
import matplotlib.pyplot as plt
import sympy as sym
# INGRESO
x = sym.Symbol('x')
fx = sym.sqrt((x-1)**2+(sym.exp(x) -1)**2)
a = 0
b = 1
muestras = 21
# PROCEDIMIENTO
dfx = sym.diff(fx,x,1)
d2fx = sym.diff(fx,x,2)
f = sym.lambdify(x,dfx)
xi = np.linspace(a,b,muestras)
fi = f(xi)
# SALIDA
print('f(x) :')
print(dfx)
print("f'(x) :")
print(d2fx)
print()
print('f(x) :')
sym.pprint(dfx)
print("f'(x) :")
sym.pprint(d2fx)
# GRAFICA
plt.plot(xi,fi, label='f(x)')
plt.axhline(0)
plt.xlabel('x')
plt.ylabel('f(x)')
plt.legend()
plt.grid()
plt.show()
# Algoritmo de Bisección
# [a,b] se escogen de la gráfica de la función
# error = tolera
import numpy as np
def biseccion(fx,a,b,tolera,iteramax = 20, vertabla=False, precision=4):
'''
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)
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)
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)
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
return(respuesta)
# INGRESO
tolera = 0.001
# PROCEDIMIENTO
respuesta = biseccion(f,a,b,tolera,vertabla=True)
# SALIDA
print('raíz en: ', respuesta)
Opción 2
Para encontrar el punto más cercano, se debe encontrar el mínimo de la distancia, se podría derivar la función y encontrar la raiz en cero.
Considere simplificar la función a un polinomio, donde tiene dos opciones:
b.1 Polinomio de Taylor, que también requiere derivadas (descartado)
b.2 evaluar la función en varios puntos, interpolar y obtener un polinomio.
Al reutilizar el algoritmo del tema 1 se obtiene lo planteado en b.2, usando un polinomio de grado 3, con muestras de 4 puntos equidistantes en el eje x.
polinomio
0.867192074184622*x**3 + 1.22015957396232*x**2 - 1.21861610672236*x + 1.01491694350023
derivada polinomio:
2.60157622255387*x**2 + 2.44031914792464*x - 1.21861610672236
Al aplicar un método para encontrar raíces se tiene que:
en distancia mínima en x= 0.3644244280922699
con y = 1.4396851273165785
distancia = 0.7728384816953889
Instrucciones en Python
# 1ra Evaluación II Término 2018
# Tema 2. Distancia mínima a un punto
import numpy as np
import matplotlib.pyplot as plt
import sympy as sym
# PRESENTA PROBLEMA
# INGRESO
punto = [1,1]
trayectoria = lambda x: np.exp(x)
a = 0
b = 1
muestras = 51
# PROCEDIMIENTO
xif = np.linspace(a,b,muestras)
trayecto = trayectoria(xif)
# SALIDA
plt.plot(xif,trayecto, label = 'trayectoria')
plt.plot(punto[0],punto[1],'ro')
plt.axhline(punto[0], color='grey')
plt.axvline(punto[1], color='grey')
plt.title('distancia a un punto')
plt.legend()
plt.xlabel('x')
plt.ylabel('y')
plt.show()
# ------------------------
# PARA ANALIZAR DISTANCIAS
def interpola_lagrange(xi,yi):
'''
Interpolación con método de Lagrange
resultado: polinomio en forma simbólica
'''
# PROCEDIMIENTO
n = len(xi)
x = sym.Symbol('x')
# Polinomio
polinomio = 0
for i in range(0,n,1):
# Termino de Lagrange
termino = 1
for j in range(0,n,1):
if (j!=i):
termino = termino*(x-xi[j])/(xi[i]-xi[j])
polinomio = polinomio + termino*yi[i]
# Expande el polinomio
polinomio = polinomio.expand()
return(polinomio)
def posicionfalsa(fx,a,b,tolera):
fa = fx(a)
fb = fx(b)
c = b - fb*(a-b)/(fa-fb)
tramo = abs(c-a)
while (tramo > tolera):
fc = fx(c)
cambia = np.sign(fa)*np.sign(fc)
if (cambia > 0):
tramo = abs(c-a)
a=c
fa=fc
else:
tramo = abs(c-b)
b=c
fb=fc
c = b - fb*(a-b)/(fa-fb)
print(tramo)
respuesta = c
# Valida respuesta
fa = fx(a)
fb = fx(b)
cambio = np.sign(fa)*np.sign(fb)
if (cambio>0):
respuesta = np.nan
return(respuesta)
# INGRESO
# Trayectoria y punto tomados de sección PRESENTA PROBLEMA
y = lambda x: np.sqrt((x-punto[0])**2+(trayectoria(x)-punto[1])**2)
a = 0.1
b = 0.7
muestras = 51
tolera = 0.0001
muestrap = 4 # Para el polinomio
# PROCEDIMIENTO
yif = y(xif)
xip = np.linspace(a,b,muestrap)
yip = y(xip)
x = sym.Symbol('x')
polinomio = interpola_lagrange(xip,yip)
px = sym.lambdify('x',polinomio)
pxi = px(xif)
dpx = polinomio.diff('x',1)
dpxn = sym.lambdify('x',dpx)
fxi = dpxn(xif)
raiz = posicionfalsa(dpxn,a,b,tolera)
# SALIDA
print('polinomio')
print(polinomio)
print('derivada polinomio:')
print(dpx)
print('en distancia mínima en x=',raiz)
print('con y =', trayectoria(raiz))
print('distancia = ', y(raiz))
# GRAFICA
plt.plot(xif,yif, label = 'distancia')
plt.plot(xif,pxi, label = 'p(x)')
plt.plot(xif,fxi, label = 'dpx(x)')
plt.axhline(0, color = 'grey')
plt.axvline(raiz, color = 'grey')
plt.legend()
plt.title('Distancia mínima de punto a f(x)')
plt.xlabel('x')
plt.ylabel('distancia')
plt.show()