Para finalizar el proyecto vamos a crear una calculadora de límites y derivadas, además de realizar gráficos ilustrativos de los mismos. De tal manera necesitaremos de todo lo aprendido en las primeras tres partes del proyecto. Primero hagamos un bosquejo de lo que realizaremos en código:
Así, debemos crear un menú para el usuario; en este caso será el siguiente:
y el usuario ingresará el número 1 ó 2 según sea el caso. Si el usuario ingresa el 1 arrojaremos una serie de instrucciones para que el usuario ingrese los datos correctos
Después mostraremos el resultado del límite que desea calcular el usuario y preguntaremos si desea ver un gráfico ilustrativo.
Comencemos trabajando esta primer parte y después adaptaremos el código para el caso de las derivadas.
# Calcular el límite de una función continua
# ----------------------------------------------------------------
# Saludo
print("Bienvenido a la calculadora de límites y derivadas.")
print("¿Qué desea hacer?")
print()
# mostramos el menú
print(f'''1. Calcular el límite de una función continua\n
2. Calcular la derivada de una función explícita''')
# entrada del usuario, debemos de controlar posibles errores en la información que se ingrese
accion = int(input("(1 | 2): "))
while accion != 1 and accion != 2:
print("¡Error! debe ingresar o el número 1 ó el número 2 solamente")
# volvemos a preguntar la acción que desea realizar
accion = int(input("(1 | 2): "))
print("Pasemos al siguiente paso......")
Bienvenido a la calculadora de límites y derivadas. ¿Qué desea hacer? 1. Calcular el límite de una función continua 2. Calcular la derivada de una función explícita (1 | 2): 3 ¡Error! debe ingresar o el número 1 ó el número 2 solamente (1 | 2): 1 Pasemos al siguiente paso......
sympy
para interpretar la función que el usuario ingrese, esto es, dado que la información que ingresa el usuario es de tipo string, al emplear parse_expr()
interpretaremos la cadena de texto ingresada como una función para trabajar en Python (para ello también necesitamos definir a x
como un símbolo matemático). De tal manera # realizamos las importaciones pertinentes
from sympy import *
from sympy.parsing.sympy_parser import parse_expr
# declaramos una variable que nos permita continuar con el código si todo va bien
continuar = True
# declaramos la variable x
x = symbols("x")
# mostramos un menú para pedir al usuario la función y hacía que valor tiende x (controlamos posibles errores)
try:
print("Ingresa la función que depende de x: ")
fun = input(": ")
print("hacía qué valor tiende x: ")
lim = float(input(": "))
# interpretamos la función
y = parse_expr(fun)
# mostramos el resultado
print(f'El límite de la función {y} cuando x tiende a {lim} es:')
print(limit(y,x,lim))
except:
print("Error al ingresar la información, fin del programa")
continuar = False
Ingresa la función que depende de x: : x**2 hacía qué valor tiende x: : 2 El límite de la función x**2 cuando x tiende a 2.0 es: 4.00000000000000
continuar
siga siendo verdadera, pues notemos que si hubo un error al ingresar la información la variable será falsa por lo que el programa finalizara. Después adaptaremos el código de la parte II del proyecto para la graficación. Recordemos que las líneas auxiliares son aquellas líneas que marcan el valor del límite de una función en la gráfica, por ejemplo:Ahora, recordemos para el caso en que $\lim\limits_{x}\rightarrow 2 x^{2}=4$, que para graficar dichas líneas usabamos que $0\leq u\leq 2$ y dejabamos fijo el valor del límite (4) para graficar la línea horizontalmplot.plot(u,4, marker=",", color="k")
; luego usabamos que $0\leq v\leq 4$ y dejabamos fijo el valor al cual tiende $x$ (que en dicho ejemplo era $x=2$) para graficar la línea vertical mplot.plot(2,v, marker=",", color="k")
. Pero, para generalizar dichas líneas auxiliares a cualquier función coninua y para cualquier valor al que tienda $x$ necesitamos cambiar los intervalos donde se "mueve" $u$ y $v$. Veamos los siguientes casos:
y en ambos casos utilizaremos
mplot.plot(u,y.subs(x,lim), marker=",", color="k")
donde ponemos y.subs(x,lim)
pues el valor de la ordenada $y$ será el valor obtenido de evaluar la función $y$ (previamente ingresada por el usuario) en el valor $x=lim$ (donde lim
es el valor al que tiende $x$). Además, lo anterior también funciona para el caso en que $y_{0}$ sea negativa
Por otro lado
para el caso de las líneas auxiliares verticales dejaremos fijo al valor de la $x$ cuando $x=lim$, esto es
mplot.plot(lim,v, marker=",", color="k")
y tendremos dos casos: uno cuando el valor de evaluar $x=lim$ en la función es positivo (caso 1) y el otro cuando evaluemos $x=lim$ en la función y el valor obtenido sea negativo (caso 2). Notemos que en ambos casos no importa si el valor de $lim$ es positivo o negativo ($x_{0}$ ó $x_{0}'$ respectivamente). De tal manera tenemos el código:
# importamos el módulo para crear dataframes
import pandas as pd
# importamos el módulo para graficar
import matplotlib.pyplot as mplot
#---------------------------------------------------------------------
# Preguntamos al usuario si desea ver un gráfico representativo
print("Deseas ver un gráfico representativo del cálculo anterior")
graf_1 = input("(si | no): ")
# convertimos la cadena a minúsculas (lo anterior para trabajar aún en caso que el usuario haya
# ingresado si o no con alguna mayúscula)
graf_2 = graf_1.lower()
# Luego
if graf_2 == "si":
continuar = True
elif graf_2 == "no":
print("Fin del programa")
continuar = False
else:
print("¡Error! fin del programa")
continuar = False
# continuamos con la graficación
if continuar = True:
# valores de aproximación
valores = {"x": [lim + 1 / i for i in range(-10,11) if i != 0], "f(x)": [y.subs(x,i) for i in
[lim + 1 / i for i in range(-10,11) if i != 0]]}
# creamos el dataframe
df = pd.DataFrame(valores)
# graficamos los puntos
for i in range(-10,11):
mplot.plot(df.iloc[i,0], df.iloc[i,1], marker = "o", color = "b")
# definimos el dominio de graficación
x = np.arange(-6,6, 0.01)
# graficamos la funcion
mplot.plot(x,y, color = "k")
# graficamos el punto de interés en el límite (es x=x0)
mplot.plot(lim, y.subs(x,lim), marker = "o", color = "r")
# graficamos las líneas auxiliares con los casos vistos anteriormente
# .
# .
# Aquí irá el código de los casos de las líneas auxiliares
# el cual trabajaremos abajo
# .
# .
mplot.show()
print("Fin del programa")
Implementemos el código de las líneas auxiliares:
# Construcción de las líneas auxiliares.
# Caso en la ordenada y0 es positiva
if y.subs(x,lim) > 0:
v = 0
while v <= y.subs(x,lim) and v >= 0:
mplot.plot(lim,v, marker=",", color="k")
v += 0.1
# caso en que x=x0 es positivo
if lim > 0:
u = 0
while u <= lim and u >= 0:
mplot.plot(u,y.subs(x,lim), marker=",", color="k")
u += 0.08
# caso en que x=x0 es negativo
else:
u = lim
while u <= 0 and u >= lim:
mplot.plot(u,y.subs(x,lim), marker=",", color="k")
u += 0.08
# Caso en que la ordenada y0 es negativa
else:
v = y.subs(x,lim)
while v <= 0 and v >= y.subs(x,lim):
mplot.plot(lim,v, marker=",", color="k")
v += 0.1
# caso en que x=x0 es positivo
if lim > 0:
u = 0
while u <= lim and u >= 0:
mplot.plot(u,y.subs(x,lim), marker=",", color="k")
u += 0.08
# caso en que x=x0 es negativo
else:
u = lim
while u <= 0 and u >= lim:
mplot.plot(u,y.subs(x,lim), marker=",", color="k")
u += 0.08
donde los casos principales son aquellos en que la ordenda $y_{0}$ es positiva o negativa y dentro de ellos están los casos en que $x_{0}$ es positiva o negativa. Lo anterior pues, recordemos, que no importa si el valor de $x_{0}=lim$ es positivo o negativo, la forma de construir las líneas verticales serán la misma para los casos en que $y_{0}$ sea positiva o ngeativa. Finalmente debemos especificar que, si alguna de las entradas del punto de interés
# graficamos el punto de interés en el límite (es x=x0)
mplot.plot(lim, y.subs(x,lim), marker = "o", color = "r")
es cero (es decir si lim = 0
ó y.subs(x,lim) = 0)
entonces no dibujaremos las líneas auxiliares pues tendríamos casos como
en estos casos no tiene sentido crear líneas auxiliares. Por ende utilizaremos un condicional if
para crear las líneas auxiliares en el caso en que lim != 0
ó y.subs(x,lim) != 0)
. Implementemos pues todo el código
# importamos los módulos necesarios
import pandas as pd
import matplotlib.pyplot as mplot
import numpy as np
#---------------------------------------------------------------------
# continuamos con la graficación
if continuar == True:
# Preguntamos al usuario si desea ver un gráfico representativo
print("Deseas ver un gráfico representativo del cálculo anterior")
graf_1 = input("(si | no): ")
# convertimos la cadena a minúsculas (lo anterior para trabajar aún en caso que el usuario haya
# ingresado si o no con alguna mayúscula)
graf_2 = graf_1.lower()
# Luego
if graf_2 == "si":
continuar = True
elif graf_2 == "no":
print("Fin del programa")
continuar = False
else:
print("¡Error! fin del programa")
continuar = False
# valores de aproximación
valores = {"x": [lim + 1 / i for i in range(-10,11) if i != 0], "f(x)": [y.subs(x,i) for i in
[lim + 1 / i for i in range(-10,11) if i != 0]]}
# creamos el dataframe
df = pd.DataFrame(valores)
# graficamos los puntos
for i in range(-10,11):
mplot.plot(df.iloc[i,0], df.iloc[i,1], marker = "o", color = "b")
# graficamos el punto de interés en el límite (es x=x0)
mplot.plot(lim, y.subs(x,lim), marker = "o", color = "r")
if lim != 0 or y.subs(x,lim) != 0:
# Construcción de las líneas auxiliares.
# Caso en la ordenada y0 es positiva
if y.subs(x,lim) > 0:
v = 0
while v <= y.subs(x,lim) and v >= 0:
mplot.plot(lim,v, marker=",", color="k")
v += 0.1
# caso en que x=x0 es positivo
if lim > 0:
u = 0
while u <= lim and u >= 0:
mplot.plot(u,y.subs(x,lim), marker=",", color="k")
u += 0.08
# caso en que x=x0 es negativo
else:
u = lim
while u <= 0 and u >= lim:
mplot.plot(u,y.subs(x,lim), marker=",", color="k")
u += 0.08
# Caso en que la ordenada y0 es negativa
else:
v = y.subs(x,lim)
while v <= 0 and v >= y.subs(x,lim):
mplot.plot(lim,v, marker=",", color="k")
v += 0.1
# caso en que x=x0 es positivo
if lim > 0:
u = 0
while u <= lim and u >= 0:
mplot.plot(u,y.subs(x,lim), marker=",", color="k")
u += 0.08
# caso en que x=x0 es negativo
else:
u = lim
while u <= 0 and u >= lim:
mplot.plot(u,y.subs(x,lim), marker=",", color="k")
u += 0.08
#----------------
# definimos el dominio de graficación
x = np.arange(-3,3, 0.01)
# graficamos la funcion
mplot.plot(x,eval(fun), color = "k")
mplot.grid()
mplot.show()
print("Fin del programa")
Deseas ver un gráfico representativo del cálculo anterior (si | no): si
Fin del programa
Es importante resaltar que hemos colocado
mplot.plot(x,eval(fun), color = "k")
para graficar la función pues si colocaramos como intuitivamente debería de ser
mplot.plot(x,y, color = "k")
obtendríamos un error. Lo que ocurre es que la función y
ha sido interpretada de la entrada de usuario mediante parse_expr()
lo cual nos sirve para hallar el límite de dicha expresión, pero no podemos evaluarla en un rango completo. En cambio, la función eval()
nos permite evaluar cadenas de texto y dado que fun
es la cadena de texto que ingresa el usuario, podemos efectuar esta evaluación.
Veamos un poco del funcionamiento de eval()
.
Creamos una variable inicializada x = 3
, después una cadena de texto funcion = "x ** 3"
. Mediante la función eval()
podemos efectuar el cálculo $(3)^{3}=27$:
# declaramos la variable
x = 3
# declaramos la función
funcion = "x ** 3"
print(eval(funcion))
27
Es así como eval(fun)
nos permite evaluar la función en el rango de valores dado por x
. Ahora es preciso mencionar que el código anterior sólo sirve para funciones algebraicas, sin embargo es sencillo adaptar el código para funciones logarítmicas, exponenciales y trigonométricas si la función ingresada por el usuario incluye el término np.
. Funciones racionales (como $f(x)=\frac{1}{x}$) no pueden ser trabajadas con el programa pues éstas no son continuas, de hecho, podemos adaptar el código del programa para sólo mostrar el límite que se desea calcular sin mostrar gráficos auxiliares.
Continuando, podemos agregar np.
a las funciones ingresadas por el usuario, por ejemplo
# declaramos la variable x la cual vale "pi medios" (o 90 grados)
x = np.pi / 2
# declaramos la función
funcion_2 = "np.sin(x)"
print(eval(funcion_2))
1.0
O también podemos colocar, si es el caso, el string np.
a la función que ingrese el usuario. Por ejemplo, supongamos que el usuario ingresa "log(x)"
entonces recordemos que nosotros podemos sumar cadenas de texto
x = np.e
funcion_3 = "log(x)"
# agregamos np. a la cadena de texto "log(x)" para poder interpretarlo en Python
funcion_3_2 = "np." + funcion_3
print(funcion_3_2)
print(eval(funcion_3_2))
np.log(x) 1.0
Y finalmente, para que el usuario ingrese el valor de $e$ o de $\pi$ bastara con mostrar un menú para brindar algunas aproximaciones de estos números. De tal manera, si desea ingresar el valor de $\frac{\pi}{2}$ bastará con ingresar 3.1416 / 2
y aunque el resultado que obtengamos en la evaluación sea aproximado nos dará una buena idea del valor real. Por ejemplo podemos cambiar el código anterior como
x = 2.718281828
funcion_3 = "log(x)"
# agregamos np. a la cadena de texto "log(x)" para poder interpretarlo en Python
funcion_3_2 = "np." + funcion_3
print(funcion_3_2)
print(eval(funcion_3_2))
np.log(x) 0.9999999998311266
La adaptación de lo antes mencionado a nuestro código original del programa será un ejercicio de clase. Es así como finalizamos la parte IV de este proyecto el cual es bastante útil para prácticar los conceptos que hemos estado viendo.