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.
Puede hacer cosas como:
Sin embargo, SymPy no acaba aquí ni mucho menos...
In [2]:
import sympy as sym
%matplotlib inline
Para que los resultados sean formateados en $\LaTeX$ podemos usar:
In [3]:
sym.init_printing(use_latex=True)
In [4]:
x = sym.Symbol('x')
In [5]:
(sym.pi + x)**2
Out[5]:
In [6]:
# forma alternativa de definir (varios) símbolos
a, b, c = sym.symbols("a, b, c")
In [7]:
type(a)
Out[7]:
Podemos agregar algunas propiedades a los símbolos cuando son creados:
In [8]:
x = sym.Symbol('x', real=True)
In [9]:
x.is_imaginary
Out[9]:
In [10]:
x = sym.Symbol('x', positive=True)
In [11]:
x > 0
Out[11]:
In [12]:
1+1*sym.I
Out[12]:
In [13]:
sym.I**2
Out[13]:
In [14]:
(x * sym.I + 1)**2
Out[14]:
In [15]:
r1 = sym.Rational(4,5)
r2 = sym.Rational(5,4)
In [16]:
r1
Out[16]:
In [17]:
r1+r2
Out[17]:
In [18]:
r1/r2
Out[18]:
SymPy usa una librería para trabajar con números con precisión arbitraria, y tiene expresiones SymPy predefinidas para varias constantes matemáticas, tales como: pi
, e
y oo
para el infinito.
Para evaluar numéricamente una expresión podemos usar la función evalf
(o bien N
). Ésta usa un argumento n
que especifíca el número de cifras significativas.
In [19]:
sym.pi.evalf(n=50)
Out[19]:
In [20]:
y = (x + sym.pi)**2
In [21]:
sym.N(y, 5) # equivalente a evalf
Out[21]:
Cuando evaluamos numéricamente expresiones a menudo deseamos substituir un símbolo por un valor numérico. En SymPy hacemos esto usando la función subs
:
In [22]:
y.subs(x, 1.5)
Out[22]:
In [23]:
sym.N(y.subs(x, 1.5))
Out[23]:
La función subs
también puede ser usada para substituir símbolos y expresiones:
In [24]:
y.subs(x, a+sym.pi)
Out[24]:
También podemos combinar la evaluación numérica de expresiones con arreglos NumPy:
In [25]:
import numpy as np
In [26]:
x_vec = np.arange(0, 10, 0.1)
In [27]:
y_vec = np.array([sym.N(((x + sym.pi)**2).subs(x, xx)) for xx in x_vec])
In [28]:
import matplotlib.pyplot as plt
plt.plot(x_vec, y_vec);
Sin embargo, este tipo de evaluación numérica puede ser muy lenta, y existe una forma mucho más eficiente de realizar la misma tarea: Usar la función lambdify
para "mapear" una expresión de Sympy a una función que es mucho más eficiente para la evaluación numérica:
In [29]:
f = sym.lambdify([x], (x + sym.pi)**2, 'numpy') # el primer argumento es una lista de variables de las que la función f dependerá: en este caso sólo x -> f(x)
In [30]:
type(f)
Out[30]:
In [31]:
y_vec = f(x_vec) # ahora podemos pasar directamente un arreglo Numpy. Así f(x) es evaluado más eficientemente
La mayor eficiencia de usar funciones "lambdificadas" en lugar de usar evalación numérica directa puede ser significativa, a menudo de varios órdenes de magnitud. Aún en este sencillo ejemplo obtenemos un aumento de velocidad importante:
In [32]:
%%timeit
y_vec = np.array([sym.N(((x + sym.pi)**2).subs(x, xx)) for xx in x_vec])
In [33]:
%%timeit
y_vec = f(x_vec)
Uno de los usos principales de un sistema de cálculo simbólico es que realiza manipulaciones algebráicas de expresiones. Por ejemplo, si queremos expandir un producto, factorizar una expresión, o simplificar un resultado. En esta sección presentamos las funciones para realizar estas operaciones básicas en SymPy.
In [34]:
(x+1)*(x+2)*(x+3)
Out[34]:
In [35]:
sym.expand((x+1)*(x+2)*(x+3))
Out[35]:
La función expand
acepta varias argumentos clave con los que se puede indicar qué tipo de expansión deseamos realizar. Por ejemplo, para expandir expresiones trigonométricas, usamos el argumento clave trig=True
:
In [36]:
sym.sin(a+b)
Out[36]:
In [37]:
sym.expand(sym.sin(a+b), trig=True)
Out[37]:
Ver help(expand)
para una descripción detallada de los distintos tipos de expansiones que la función expand
puede realizar.
También podemos factorizar expresiones, usando la función factor
de SymPy:
In [38]:
sym.factor(x**3 + 6 * x**2 + 11*x + 6)
Out[38]:
In [39]:
# simplify expande un producto
sym.simplify((x+1)*(x+2)*(x+3))
Out[39]:
In [40]:
# simplify usa identidades trigonometricas
sym.simplify(sym.sin(a)**2 + sym.cos(a)**2)
Out[40]:
In [41]:
sym.simplify(sym.cos(x)/sym.sin(x))
Out[41]:
In [42]:
f1 = 1/((a+1)*(a+2))
In [43]:
f1
Out[43]:
In [44]:
sym.apart(f1)
Out[44]:
In [45]:
f2 = 1/(a+2) + 1/(a+3)
In [46]:
f2
Out[46]:
In [47]:
sym.together(f2)
Out[47]:
Podemos usar también Simplify
:
In [48]:
sym.simplify(f2)
Out[48]:
In [49]:
y
Out[49]:
In [50]:
sym.diff(y**2, x)
Out[50]:
Para calcular derivadas de orden superior podemos usar:
In [51]:
sym.diff(y**2, x, x)
Out[51]:
o bien
In [52]:
sym.diff(y**2, x, 2) # hace lo mismo
Out[52]:
Calculando la derivada de una función de varias variables:
In [53]:
x, y, z = sym.symbols("x,y,z")
In [54]:
f = sym.sin(x*y) + sym.cos(y*z)
$\frac{d^3f}{dxdy^2}$
In [55]:
sym.diff(f, x, 1, y, 2)
Out[55]:
In [56]:
f
Out[56]:
In [57]:
sym.integrate(f, x)
Out[57]:
Si le damos los límites de integración calculamos la integral definida
In [58]:
sym.integrate(f, (x, -1, 1))
Out[58]:
Tambien podemos calcular integrales impropias
In [59]:
from sympy import oo
# oo es el infinito
In [60]:
sym.integrate(sym.exp(-x**2), (x, -oo, oo))
Out[60]:
In [61]:
n = sym.Symbol("n")
In [62]:
sym.Sum(1/n**2, (n, 1, 10))
Out[62]:
In [63]:
sym.Sum(1/n**2, (n,1, 10)).evalf()
Out[63]:
In [64]:
sym.Sum(1/n**2, (n, 1, oo)).evalf()
Out[64]:
Lo mismo con productos
In [65]:
sym.Product(n, (n, 1, 10)) # 10!
Out[65]:
In [66]:
sym.limit(sym.sin(x)/x, x, 0)
Out[66]:
Se puede usar el límite para verificar una derivada
In [67]:
f
Out[67]:
In [68]:
sym.diff(f, x)
Out[68]:
La derivada por definicion es $$\frac{d}{{dx}}f\left( x \right) = \mathop {\lim }\limits_{h \to 0} \frac{{f\left( {x + h } \right) - f\left( x \right)}}{h }$$
In [69]:
h = sym.Symbol("h")
In [70]:
sym.limit((f.subs(x, x+h) - f)/h, h, 0)
Out[70]:
OK!
Podemos calcular los limites laterales usando el argumento dir
:
In [71]:
sym.limit(1/x, x, 0, dir="+")
Out[71]:
In [72]:
sym.limit(1/x, x, 0, dir="-")
Out[72]:
In [73]:
sym.series(sym.exp(x), x)
Out[73]:
Por defecto, se calcula la expansión alrededor de $x=0$ (serie de Taylor), pero podemos expandir la serie al rededor de otro punto
In [74]:
sym.series(sym.exp(x), x, 1)
Out[74]:
Tambien podemos especificar el orden
In [75]:
sym.series(sym.exp(x), x, 1, 10)
Out[75]:
La expansion en serie incluye la aproximación de orden. Lo cual es útil para trabajar con series de diferente orden
In [76]:
s1 = sym.cos(x).series(x, 0, 5)
s1
Out[76]:
In [77]:
s2 = sym.sin(x).series(x, 0, 2)
s2
Out[77]:
In [78]:
sym.expand(s1 * s2)
Out[78]:
Si queremos eliminar la aproximación de orden usamos el método removeO
In [79]:
sym.expand(s1.removeO() * s2.removeO())
Out[79]:
Pero hay que tener en cuenta que esta no es la expansión correcta de $\cos(x)\sin(x)$ al $5$to orden:
In [80]:
(sym.cos(x)*sym.sin(x)).series(x, 0, 6)
Out[80]:
In [81]:
m11, m12, m21, m22 = sym.symbols("m11, m12, m21, m22")
b1, b2 = sym.symbols("b1, b2")
In [82]:
A = sym.Matrix([[m11, m12],[m21, m22]])
A
Out[82]:
In [83]:
b = sym.Matrix([[b1], [b2]])
b
Out[83]:
Con la clase Matrix
podemos realizar las operaciones matriciales típicas
In [84]:
A**2
Out[84]:
In [85]:
A * b
Out[85]:
Y tambien determinantes e inversas:
In [86]:
A.det()
Out[86]:
In [87]:
A.inv()
Out[87]:
In [88]:
sym.solve(x**2 - 1, x)
Out[88]:
In [89]:
sym.solve(x**4 - x**2 - 1, x)
Out[89]:
Sistemas de ecuaciones
In [90]:
sym.solve([x + y - 1, x - y - 1], [x,y])
Out[90]:
La ecuacion puede estar en términos de otras variables simbólicas
In [91]:
sym.solve([x + y - a, x - y - c], [x,y])
Out[91]:
In [92]:
# Esta celda da el estilo al notebook
from IPython.core.display import HTML
css_file = './css/aeropython.css'
HTML(open(css_file, "r").read())
Out[92]:
In [ ]: