12. Sympy: un sistema de álgebra computacional¶
SymPy es un sistema de álgebra computacional (CAS) escrito en Python puro, está desarrollado con un enfoque en la extensibilidad y facilidad de uso, tanto a través de aplicaciones interactivas como programáticas. Estas características le han permitido a SymPy convertirse en una librería de cómputo simbólico muy popular en el ecosistema científico de Python.
En todo este capítulo se asumirá que se ha importado la librería SymPy, con las siguientes instrucciones:
from sympy import *
Adicionalmente dentro del entorno de Jupyter podemos ejecutar la siguiente instrucción que permite renderizar las expresiones resultantes.
init_printing()
12.1. Variables simbólicas¶
Las variables simbólicas son el alma de SymPy, todas las operaciones de álgebra simbólica se basan en estas.
A una variable simbólica se le asigna un símbolo que la representa mediante la función symbols
:
x = symbols("x")
print(type(x))
<class 'sympy.core.symbol.Symbol'>
Con la función symbols
se define una nueva variable simbólica que se guarda en x
, se verifica
que se crea un objeto de la clase Symbol
. Con la variable x
ya definida se puede comenzar
a formar expresiones algebraicas y manipular matemáticamente.
x + 2
x**2 - 2*x - 10
sqrt(x) - sin(x)
Puede definir múltiples variables separando por comas cada representación simbólica:
p,q,r = symbols("p,q,r")
p**q + r/q
Además de la forma anterior, también es posible tener variables simbólicas disponibles si se importan
del módulo abc
de SymPy:
from sympy.abc import a,b,c,d
(a + b)*(c + d)
12.2. Manipulación algebraica¶
SymPy es una poderosa herramienta de manipulación y simplificación algebraica, en lo subsiguiente se revisarán algunos casos elementales y se describirá el uso de las herramientas (funciones) que proporciona.
En primera instancia se definen algunas variables simbólicas a utilizar:
x,y,z = symbols("x,y,z")
a,b,c,d,k,m,n = symbols("a,b,c,d,k,m,n")
Para las expresiones algebraicas formadas en SymPy por default se evalúan y simplifican los términos semejantes. Vea los siguientes casos:
x**2 + 5*x**3 - 10*x**2 + 5*x - 10*(x + 1)
a*b + c*d + x/y - 7*a*b
Naturalmente para simplificaciones y operaciones un poco menos obvias, habrá que especificarle lo que se requiere.
Una de las operaciones elementales de simplificación en álgebra es la factorización, SymPy dispone de la
función factor
, la cual toma una expresión algebraica y la factoriza conforme sea posible.
Por ejemplo, suponiendo que se tiene la expresión \(ab + ac\), es sencillo identificar que se puede
factorizar como \(a(b+c)\), SymPy hace lo mismo sin sobresalto alguno.
factor(a*b + a*c)
De igual forma se sabe que una expresión de la forma \( ac + ad + bc + bd \) se puede factorizar como \( (a + b) (d + c) \).
factor( a*c + a*d + b*c + b*d )
Así, para un binomio al cuadrado se sabe que, \( (a+b)(a+b) \) es la factorización de una expresión del tipo \( a^2 + 2ab + b^2 \).
factor(a**2 + 2*a*b + b**2)
¿Se puede hacer el proceso inverso, es decir, dados dos factores obtener su expresión expandida?
Por supuesto, para ello se hace uso de la función expand
.
expand( (x-7)*(x-3) )
SymPy puede manejar cualquier cantidad de factores y devolver la expresión que resulta de realizar la multiplicación algebraica, sin estar limitada siquiera por la cantidad de variables simbólicas.
expand( (x + y)*(x - y) )
expand( (x + y)*(x+y) )
expand( (x + y)**2 )
expand( (x + y)**3 )
expand( a*(m + n)**2 )
De manera general, si requiere simplificar una expresión algebraica SymPy dispone de una función más o menos universal que funcionará en la mayoría de los casos: simplify
. Por ejemplo, suponiendo que
se tiene la siguiente expresión algebraica racional y se requiere reducir lo más posible:
Se puede notar que tanto en el numerador como en el denominador se puede factorizar \(x\), lo cual conduce a:
Con SymPy:
simplify( (x**2 - 3*x)/(x**2 + 3*x) )
Lo mismo para una expresión que involucre funciones trigonométricas, por ejemplo, cualquiera que haya cursado matemáticas del nivel secundario, al menos, sabe que \(\sin^2 x + \cos^2 x = 1 \), y también lo sabe SymPy:
simplify( sin(x)**2 + cos(x)**2 )
Pero también sabe que \( \cos x \cos y - \sin x \sin y = \cos(x+y) \).
simplify( cos(x)*cos(y) - sin(x)*sin(y) )
O bien:
simplify( (1+tan(x)**2)/(1+cot(x)**2) )
Habitualmente para la manipulación de expresiones que contienen funciones trigonométricas se suele utilizar
la función trigsimp
que en muchos casos lo que devuelva coincidirá con simplify
.
Sin embargo, si en lugar de reducir una expresión trigonométrica se requiere expandirla, como
en el caso del coseno o seno de la suma de dos ángulos, probablemente por intuición se utilizaría expand
,
pero aquí no funciona como puede verificar.
expand( sin(x + y) )
En este caso puede utilizar la función expand_trig
, la cual maneja de mejor manera las manipulaciones trigonométricas:
expand_trig( sin(x+y) )
12.3. Resolviendo ecuaciones e inecuaciones¶
SymPy dispone de la función solve
, la cual resuelve desde ecuaciones polinomiales, sistemas de ecuaciones lineales,
inecuaciones, hasta sistemas de ecuaciones no lineales. La sintaxis de solve
es polimórfica y en general depende
de lo que se requiera resolver, tendiendo siempre a que sea posible especificar el mínimo número de parámetros.
En las siguientes subsecciones se describen algunos casos, se asumirá en lo subsiguiente que además de importar SymPy se definieron las siguientes variables simbólicas:
x,y,z = symbols("x,y,z")
a,b,c = symbols("a,b,c")
12.3.1. Ecuaciones polinómicas¶
La sintaxis más elemental de solve
es pasando un sólo argumento, el cual se espera sea una expresión algebraica
y se considera que esta estará igualada a cero. Por ejemplo para resolver la ecuación lineal \( x - 3 = 0 \):
solve( x - 3 )
Para una ecuación cuadrática \( x^2 + 2x + 2 = 0 \):
solve(x**2 + 2*x + 2)
En este caso la ecuación tiene soluciones complejas, la unidad imaginaria en SymPy se especifica mediante
el símbolo I
.
Si se quisiera resolver la ecuación cuadrática en su forma general, por intuición y lo que sabemos hasta ahora, haríamos:
solve(a*x**2 + b*x + c)
Note que el problema está en que al haber más de una variable simbólica, SymPy no sabe con respecto a qué variable debe resolver y toma la primera en orden alfabético. Para especificar explícitamente respecto a qué variable resolver, se puede indicar mediante un segundo argumento:
solve(a*x**2 + b*x + c, x)
Puede verificar que devuelve, en efecto, la tan conocida fórmula general.
12.3.2. Ecuaciones trigonométricas¶
12.4. Cálculo¶
12.4.1. Límites¶
Para calcular límites matemáticos SymPy dispone de la función limit
, la cual requiere al menos tres
argumentos de entrada: la función, variable y valor al que tiende. Por ejemplo, si se quiere calcular
el siguiente límite:
Tendría que teclearse lo siguiente:
limit(sin(x)/x, x, 0)
Para calcular limites laterales debe pasarse un cuarto argumento, por ejemplo:
limit(1/(x-5), x, 5, "-")
limit(1/(x-5), x, 5, "+")
El símbolo +
denota el cálculo de un límite lateral por la derecha y el símbolo -
un límite lateral por la izquierda.
12.4.2. Derivadas¶
Las derivadas en Python se calculan utilizando la función diff
, misma que en su forma más simple espera
al menos dos argumentos: una expresión algebraica y una variable respecto a la cual derivar. Por ejemplo:
diff(exp(x)*cos(x), x)
Es posible también especificar una derivada de orden superior mediante un tercer argumento:
diff(5*x**2 + 3*x - 10, x, 2)
La instrucción anterior calcula la segunda derivada de la función \( f(x) = 5x^2 + 3x - 10 \).
12.4.3. Integrales¶
Para calcular integrales vamos a utilizar la función integrate
, la cual acepta al menos dos
argumentos: la función a integrar y la expresión respecto a la cual se integra, por ejemplo:
integrate(x**2 + 3*x - 7, x)
Esa instrucción calcula la integral:
Note que la expresión algebraica devuelta por Python no contiene la constante de integración, por default SymPy no la considera. Sí en algún caso específico necesita referir a la constante de integración puede adicionarla manualmente.
Las integrales definidas se pueden calcular si el segundo argumento se hace una tupla de la forma
(variable, a, b)
, donde a
y b
indican el límite inferior y superior a
evaluar en la integral:
Por ejemplo, para evaluar:
integrate(sin(x), (x, 0, pi))
O para:
integrate(z**2, (z,-5,5))
12.5. Vectores¶
Un vector denota una cantidad física que tiene magnitud y orientación en un determinado sistema de referencia.
En SymPy los vectores se pueden definir mediante la clase Matrix
del módulo matrices
, de tal
manera que en primera instancia haría falta importar dicho módulo, para esto hacemos:
from sympy.matrices import Matrix
Ahora vamos a definir dos vectores \(\vec{u}\) y \(\vec{v}\):
u = Matrix([2,1,-5])
v = Matrix([4,-1,3])
Una suma y resta vectorial se pueden ejecutar sin muchas complicaciones, mediante los operadores aritméticos ya conocidos.
u + v
v - u
La magnitud de un vector se puede calcular utilizando el método norm
.
u.norm()
v.norm()
Recuerde que si requiere ver las expresiones resultantes como fracciones decimales debe usar evalf
.
El producto escalar de dos vectores puede calcularlo utilizando el método dot
, por
ejemplo \( \vec{u} \cdot \vec{v} \) lo puede especificar como:
u.dot(v)
Para calcular el producto vectorial utilice el método cross
, por ejemplo
\( \vec{u} \times \vec{v} \):
u.cross(v)
Recuerde que el producto vectorial no es conmutativo, por tanto, \(\vec{v} \times \vec{u} \) resultará en un vector diferente al obtenido anteriormente, como puede verificar enseguida:
v.cross(u)
12.6. Matrices¶
Las matrices son arreglos rectangulares de números o cantidades simbólicas. En SymPy,
se definen utilizando la clase Matrix
, pasándole como argumentos una lista de
listas, donde cada sublista corresponde a una fila de la matriz.
Por ejemplo, vamos a definir las matrices \(A\), \(B\) y \(C\), dadas por:
Primero, importamos la clase Matrix
del módulo matrices
:
from sympy.matrices import Matrix
Luego escribiríamos:
A = Matrix([[20,50,100], [10,35,200], [-30,20,80]])
B = Matrix([[12,26,45],[3,-15,18],[54,20,0]])
C = Matrix([[5,9], [2,3], [-10,8]])
De manera muy sencilla podríamos realizar operaciones matriciales básicas, por ejemplo, una suma:
A + B
Naturalmente, y como es esperable, SymPy conoce y aplica las reglas de álgebra de matrices, observe:
A + C
---------------------------------------------------------------------------
ShapeError Traceback (most recent call last)
<ipython-input-57-c3cb66996588> in <module>()
----> 1 A + C
~\Anaconda3\lib\site-packages\sympy\core\decorators.py in binary_op_wrapper(self, other)
130 else:
131 return f(self)
--> 132 return func(self, other)
133 return binary_op_wrapper
134 return priority_decorator
~\Anaconda3\lib\site-packages\sympy\matrices\common.py in __add__(self, other)
1949 if self.shape != other.shape:
1950 raise ShapeError("Matrix size mismatch: %s + %s" % (
-> 1951 self.shape, other.shape))
1952
1953 # honest sympy matrices defer to their class's routine
ShapeError: Matrix size mismatch: (3, 3) + (3, 2)
SymPy es muy explícito en ese tipo de situaciones y nos imprime un mensaje de error suficientemente descriptivo. De igual forma que es válido realizar el producto \(AC\), pero no \(CA\):
A*C
C*A
---------------------------------------------------------------------------
ShapeError Traceback (most recent call last)
<ipython-input-59-cbae4c009e52> in <module>()
----> 1 C*A
~\Anaconda3\lib\site-packages\sympy\core\decorators.py in binary_op_wrapper(self, other)
130 else:
131 return f(self)
--> 132 return func(self, other)
133 return binary_op_wrapper
134 return priority_decorator
~\Anaconda3\lib\site-packages\sympy\matrices\common.py in __mul__(self, other)
2006 if self.shape[1] != other.shape[0]:
2007 raise ShapeError("Matrix size mismatch: %s * %s." % (
-> 2008 self.shape, other.shape))
2009
2010 # honest sympy matrices defer to their class's routine
ShapeError: Matrix size mismatch: (3, 2) * (3, 3).
El determinante de una matriz podemos calcularlo mediante la función det
:
det(B)
O bien, mediante el propio método det
:
B.det()
La matriz inversa podemos calcularla utilizando el método inv
:
A.inv()
A.inv()*A
La transpuesta de una matriz se puede obtener accediendo al atributo T
C.T
12.7. Ejercicios¶
Utilice Python/SymPy para resolver los siguientes ejercicios:
Resuelva las siguientes ecuaciones (para la variable \(x\)):
\( x + 3x = 10 \)
\( 2x^2 - 10x + 5 = 0 \)
\( \frac{a}{x} + bx - 8 = 0 \)
\( \cos x + \sin x = 10 \)
\( kx - 10 = x^2 \)
Calcule las siguientes derivadas:
\( \frac{d}{dx} \left( \cos x \right) \)
\( \frac{d}{dt} \left( at^2 - 2\tan t - \frac{10}{t} \right) \)
\( \frac{d}{dz} \left( z^5 - 10 e^{-z} \right) \)
Calcule las siguientes integrales indefinidas:
\( \int \cos x \, dx \)
\( \int \left( x^3 - 8x \right)\, dx \)
\( \int \left( e^{-3x} \sin x \right) \, dx \)
\( \int \left( s^2 + ks - m \right) \, ds \)
Calcule las siguientes integrales definidas:
\( \int_{a}^{b} \sin x \, dx \)
\( \int_{-10}^{5} x^2 + 10x \, dx \)
\( \int_{0}^{2} 10e^{-z} \, dz \)
Resuelva la siguiente ecuación diferencial: $\( \frac{dS}{dr} = kS \)$
Escriba una función que dados como entrada dos vectores, determine sí estos son paralelos.
Desarrolle una función llamada
calcula_fuerza_resultante
que reciba como datos de entrada un conjunto de vectores fuerza y devuelva el vector de fuerza resultante.Escriba un función llamada
calcula_momento_resultante
que reciba como datos de entrada un conjunto de vectores fuerza y un conjunto de vectores de posición del punto de aplicación de la fuerza con respecto a un cierto punto. Se deberá devolver el momento total producido por las fuerzas con respecto al punto.