_ SymPy es una biblioteca de Python para matemática simbólica. Apunta a convertirse en un sistema de algebra computacional (CAS) con todas sus prestaciones manteniendo el código tan simple como sea posible para manterlo comprensible y fácilmente extensible. SymPy está escrito totalmente en Python y no requiere bibliotecas adicionales. Este proyecto comenzó en 2005, fue lanzado al público en 2007 y a él han contribuido durante estos años cientos de personas.
_ Otros CAS conocidos son Mathematica y Maple, sin embargo ambos son software privativo y de pago. Aquí puedes encontrar una comparativa de SymPy con Maple. _
Hoy veremos cómo:
Sin embargo, SymPy no acaba aquí ni mucho menos...
from IPython.display import HTML
HTML('<iframe src="http://docs.sympy.org/latest/index.html" width="700" height="400"></iframe>')
HTML('<iframe src="http://www.sympygamma.com/input/?i=integrate%281+%2F+%281+%2B+x^2%29%29" width="700" height="400"></iframe>')
Lo primero, como siempre, es importar aquello que vayamos a necesitar:
# Importación
from sympy import init_session
init_session(use_latex=True)
IPython console for SymPy 0.7.5 (Python 3.4.2-64-bit) (ground types: python) These commands were executed: >>> from __future__ import division >>> from sympy import * >>> x, y, z, t = symbols('x y z t') >>> k, m, n = symbols('k m n', integer=True) >>> f, g, h = symbols('f g h', cls=Function) Documentation can be found at http://www.sympy.org
WARNING: Hook shutdown_hook is deprecated. Use the atexit module instead.
Lo primero que vemos es que el comando init_session
ha llevado a cabo algunas acciones por nostros:
use_latex=True
obtenemos la salida en $\LaTeX$.# Intentamos usar un símbolo que no hemos creado
a = 2 * b
--------------------------------------------------------------------------- NameError Traceback (most recent call last) <ipython-input-5-9024d2cb83d8> in <module>() 1 # Intentamos usar un símbolo que no hemos creado ----> 2 a = 2 * b NameError: name 'b' is not defined
Como en b
no había sido creada, Python no sabe qué es b
.
Esto mismo nos ocurre con los símbolos de SymPy. Antes de usar una variable, debo decir que es un símbolo y asignárselo:
# Creamos el símbolo a
a = symbols('a')
a
# Número pi
(a + pi) ** 2
# Unidad imaginaria
a + 2 * I
# Número e
E
# Vemos qué tipo de variable es a
type(a)
sympy.core.symbol.Symbol
Ahora ya podría crear b = 2 * a
:
b = 2 * a
b
type(b)
sympy.core.mul.Mul
¿Qué está ocurriendo? Python detecta que a es una variable de tipo Symbol
y al multiplicarla por 2
devuelve una variable de Sympy.
Como Python permite que el tipo de una variable cambie, si ahora le asigno a a
un valor float deja de ser un símbolo.
a = 2.26492
a
type(a)
float
Las conclusiones son:
Las variables de tipo Symbol
actúan como contenedores en los que no sabemos qué hay (un real, un complejo, una lista...). Hay que tener en cuenta que: una cosa es el nombre de la variable y otra el símbolo con el que se representa.
#creación de símbolos
coef_traccion = symbols('c_T')
coef_traccion
Incluso puedo hacer cosas raras como:
# Diferencia entre variable y símbolo
a = symbols('b')
a
Además, se pueden crear varos símbolos a la vez:
x, y, z, t = symbols('x y z t')
y símbolos griegos:
w = symbols('omega')
W = symbols('Omega')
w, W
Fuente: Documentación oficial de SymPy
Por defecto, SymPy entiende que los símbolos son números complejos. Esto puede producir resultados inesperados ante determinadas operaciones como, por ejemplo, lo logaritmos. Podemos indicar que la variable es real, entera... en el momento de la creación:
# Creamos símbolos reales
x, y, z, t = symbols('x y z t', real=True)
# Podemos ver las asunciones de un símbolo
x.assumptions0
{'complex': True, 'real': True, 'hermitian': True, 'imaginary': False, 'commutative': True}
Comencemos por crear una expresión como: $\cos(x)^2+\sin(x)^2$
expr = cos(x)**2 + sin(x)**2
expr
simplify()
¶Podemos pedirle que simplifique la expresión anterior:
simplify(expr)
En este caso parece estar claro lo que quiere decir más simple, pero como en cualquier CAS el comando simplify
puede no devolvernos la expresión que nosotros queremos. Cuando esto ocurra necesitaremos usar otras instrucciones.
.subs()
¶En algunas ocasiones necesitaremos sustituir una variable por otra, por otra expresión o por un valor.
expr
# Sustituimos x por y ** 2
expr.subs(x, y**2)
# ¡Pero la expresión no cambia!
expr
# Para que cambie
expr = expr.subs(x, y**2)
expr
Cambia el sin(x)
por exp(x)
expr.subs(sin(x), exp(x))
Particulariza la expresión $sin(x) + 3 x $ en $x = \pi$
(sin(x) + 3 * x).subs(x, pi)
Aunque si lo que queremos es obtener el valor numérico lo mejor es .evalf()
(sin(x) + 3 * x).subs(x, pi).evalf(25)
#ver pi con 25 decimales
pi.evalf(25)
#el mismo resultado se obtiene ocn la función N()
N(pi,25)
SymPy ofrece numerosas funciones para simplificar y manipular expresiones. Entre otras, destacan:
expand()
factor()
collect()
apart()
cancel()
Puedes consultar en la documentación de SymPy lo que hace cada una y algunos ejemplos. Existen también funciones específicas de simplificación para funciones trigonométricas, potencias y logaritmos. Abre esta documentación si lo necesitas.
Pasaremos rápidamente por esta parte, para hacer cosas "más interesantes". Te proponemos algunos ejemplos para que te familiarices con el manejor de expresiones:
Crea las expresiones de la izquierda y averigua qué función te hace obtener la de la derecha:
expresión 1 | expresión 2 |
---|---|
$\left(x^{3} + 3 y + 2\right)^{2}$ | $x^{6} + 6 x^{3} y + 4 x^{3} + 9 y^{2} + 12 y + 4$ |
$\frac{\left(3 x^{2} - 2 x + 1\right)}{\left(x - 1\right)^{2}} $ | $3 + \frac{4}{x - 1} + \frac{2}{\left(x - 1\right)^{2}}$ |
$x^{3} + 9 x^{2} + 27 x + 27$ | $\left(x + 3\right)^{3}$ |
$\sin(x+2y)$ | $\left(2 \cos^{2}{\left (y \right )} - 1\right) \sin{\left (x \right )} + 2 \sin{\left (y \right )} \cos{\left (x \right )} \cos{\left (y \right )}$ |
#1
expr1 = (x ** 3 + 3 * y + 2) ** 2
expr1
expr1_exp = expr1.expand()
expr1_exp
#2
expr2 = (3 * x ** 2 - 2 * x + 1) / (x - 1) ** 2
expr2
expr2.apart()
#3
expr3 = x ** 3 + 9 * x ** 2 + 27 * x + 27
expr3
expr3.factor()
#4
expr4 = sin(x + 2 * y)
expr4
expand(expr4)
expand_trig(expr4)
expand(expr4, trig=True)
Puedes derivar una expresion usando el método .diff()
y la función dif()
#creamos una expresión
expr = cos(x)
#obtenemos la derivada primera con funcion
diff(expr, x)
#utilizando método
expr.diff(x)
¿derivada tercera?
expr.diff(x, x, x)
expr.diff(x, 3)
¿varias variables?
expr_xy = y ** 3 * sin(x) ** 2 + x ** 2 * cos(y)
expr_xy
diff(expr_xy, x, 2, y, 2)
Queremos que la deje indicada, usamos Derivative()
Derivative(expr_xy, x, 2, y)
¿Será capaz SymPy de aplicar la regla de la cadena?
# Creamos una función F
F = Function('F')
F(x)
# Creamos una función G
G = Function('G')
G(x)
# Derivamos la función compuesta F(G(x))
F(G(x)).diff(x)
En un caso en el que conocemos las funciones:
# definimos una f
f = 2 * y * exp(x)
f
# definimos una g(f)
g = f **2 * cos(x) + f
g
#la derivamos
diff(g,x)
Si te digo que se integra usando el método .integrate()
o la función integrate()
. ¿Te atreves a integrar estas casi inmediatas...?:
int1 = cos(x) ** 2
integrate(int1)
int2 = 1 / sin(x)
integrate(int2)
x, a = symbols('x a', real=True)
int3 = 1 / (x**2 + a**2)**2
integrate(int3, x)
Calculemos este límite sacado del libro Cálculo: definiciones, teoremas y resultados, de Juan de Burgos:
$$\lim_{x \to 0} \left(\frac{x}{\tan{\left (x \right )}}\right)^{\frac{1}{x^{2}}}$$Primero creamos la expresión:
x = symbols('x', real=True)
expr = (x / tan(x)) ** (1 / x**2)
expr
Obtenemos el límite con la función limit()
y si queremos dejarlo indicado, podemos usar Limit()
:
limit(expr, x, 0)
Los desarrollos en serie se pueden llevar a cabo con el método .series()
o la función series()
#creamos la expresión
expr = exp(x)
expr
#la desarrollamos en serie
series(expr)
Se puede especificar el número de términos pasándole un argumento n=...
. El número que le pasemos será el primer término que desprecie.
# Indicando el número de términos
series(expr, n=10)
Si nos molesta el $\mathcal{O}(x^{10})$ lo podemos quitar con removeO()
:
series(expr, n=10).removeO()
series(sin(x), n=8, x0=pi/3).removeO().subs(x, x-pi/3)
Como se ha mencionado anteriormente las ecuaciones no se pueden crear con el =
#creamos la ecuación
ecuacion = Eq(x ** 2 - x, 3)
ecuacion
# También la podemos crear como
Eq(x ** 2 - x -3)
#la resolvemos
solve(ecuacion)
Pero la gracia es resolver con símbolos, ¿no? $$a e^{\frac{x}{t}} = C$$
# Creamos los símbolos y la ecuación
a, x, t, C = symbols('a, x, t, C', real=True)
ecuacion = Eq(a * exp(x/t), C)
ecuacion
# La resolvemos
solve(ecuacion ,x)
Si consultamos la ayuda, vemos que las posibilidades y el número de parámetros son muchos, no vamos a entrar ahora en ellos, pero ¿se ve la potencia?
Tratemos de resolver, por ejemplo:
$$y{\left (x \right )} + \frac{d}{d x} y{\left (x \right )} + \frac{d^{2}}{d x^{2}} y{\left (x \right )} = \cos{\left (x \right )}$$x = symbols('x')
f = Function('y')
ecuacion_dif = Eq(y(x).diff(x,2) + y(x).diff(x) + y(x), cos(x))
ecuacion_dif
#resolvemos
dsolve(ecuacion_dif, f(x))
#creamos una matriz llena de símbolos
a, b, c, d = symbols('a b c d')
A = Matrix([
[a, b],
[c, d]
])
A
#sacamos autovalores
A.eigenvals()
#inversa
A.inv()
#elevamos al cuadrado la matriz
A ** 2
_ Esto ha sido un rápido recorrido por algunas de las posibilidades que ofrece SymPy . El cálculo simbólico es un terreno díficil y este joven paquete avanza a pasos agigantados gracias a un grupo de desarrolladores siempre dispuestos a mejorar y escuchar sugerencias. Sus posibilidades no acaban aquí. En la siguiente clase presentaremos el paquete mechanics
, pero además cuenta con herramientas para geometría, mecánica cuántica, teoría de números, combinatoria... Puedes echar un ojo aquí. _
Las siguientes celdas contienen configuración del Notebook
Para visualizar y utlizar los enlaces a Twitter el notebook debe ejecutarse como seguro
File > Trusted Notebook
%%html
<a href="https://twitter.com/Pybonacci" class="twitter-follow-button" data-show-count="false">Follow @Pybonacci</a>
<script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0],p=/^http:/.test(d.location)?'http':'https';if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src=p+'://platform.twitter.com/widgets.js';fjs.parentNode.insertBefore(js,fjs);}}(document, 'script', 'twitter-wjs');</script>
# Esta celda da el estilo al notebook
from IPython.core.display import HTML
css_file = '../styles/aeropython.css'
HTML(open(css_file, "r").read())