O desenvolvimento e a execução de algoritmos de machine learning e inteligência artificial dependem fortemente de computação numérica. Mas, em muitas situações, a matemática simbólica é essencial.
SymPy é uma biblioteca de matemática simbólica do Python. Ela é de graça e leve. Seus códigos são simples, compreensíveis e facilmente integráveis em aplicações com outras bibliotecas Python. Neste post, conheceremos algumas de suas funcionalidades.
Instalação
Segundo a documentação oficial, a melhor forma de instalar o SymPy é instalando o Anaconda. O Anaconda já vem com SymPy instalado. Também é possível obter SymPy clonando seu repositório do GitHub.
git clone https://github.com/sympy/sympy.git
A instalação com pip também é possível:
python -m pip install -e .
Matemática simbólica com Python
Computação simbólica lida com a computação de objetos matemáticos através de suas representações exatas. Consequentemente, na matemática simbólica, expressões com variáveis não avaliadas são deixadas em suas formas simbólicas. Por exemplo, no código abaixo, usamos a raiz quadrada do Python para calcular a raiz de 10, o que é feito de forma aproximada.
from math import sqrt
print('resolução numérica: ', sqrt(10))
resolução numérica: 3.1622776601683795
Com SymPy, a expressão é deixada em sua forma simbólica.
import sympy as sp
print('resolução simbólica: ',sp.sqrt(10))
resolução simbólica: sqrt(10)
Se é possível simplificar o resultado, o SymPy fará isso mantendo sua solução exata, ou seja, sem aproximações.
import sympy as sp
print('resolução simbólica: ',sp.sqrt(40))
resolução simbólica: 2*sqrt(10)
Computação de expressões simbólicas com variáveis
Sistemas de computação simbólica como o SymPy são capazes de calcular expressões simbólicas com variáveis como exemplificado abaixo.
>>> from sympy import symbols, pprint
>>> x, y, z = symbols('x y z')
>>> solution = x + 2*y + z*x
>>> pprint(solution)
x⋅z + x + 2⋅y
>>> solution2 = solution * x
>>> pprint(solution2)
x⋅(x⋅z + x + 2⋅y)
Note que, no exemplo acima, embora o SymPy tenha obtido a expressão correta, ela não foi escrita na forma mais comum na qual x deveria aparecer ao quadrado. Isso ocorre porque a maioria das simplificações com SymPy não é feita de forma automática. Ou seja, as simplificações geralmente precisam ser especificadas.
>>> from sympy import expand
>>> expand(solution2)
x**2*z + x**2 + 2*x*y
Também é possível escrever expressões matemáticas simbólicas num formato mais elegante, mas ainda imperfeito na versão atual do SymPy. O comando init_printing possibilita que as expressões matemáticas simbólicas sejam escritas numa versão pretty printed, mas que ainda precisa melhorar.
>>> from sympy import *
>>> init_printing(use_unicode=True)
>>> expand((x + 2*y + z*x)*x)
2 2
x ⋅z + x + 2⋅x⋅y
Outra forma de obter o mesmo resultado é com o método pprint do SymPy como feito anteriormente.
>>> from sympy import pprint
>>> pprint(expand(solution2))
2 2
x ⋅z + x + 2⋅x⋅y
Soluções algébricas de expressões matemáticas
Exemplos como os mostrados acima têm inúmeras aplicações. No entanto, o verdadeiro poder do uso de matemática simbólica com Python é sua capacidade de fazer todos os tipos de cálculos simbolicamente.
SymPy tem dois solvers para soluções algébricas de expressões matemáticas, o solve() e o solveset(). O solve() é apropriado para obter representações simbólicas explícitas dos diferentes valores que uma variável pode assumir para satisfazer uma equação.
>>> from sympy.abc import x, y
>>> from sympy import solve
>>> solution = solve(x**2 - y, x, dict=True)
>>> pprint(solution)
[{x: -√y}, {x: √y}]
O método solve() também pode ser usado para obtenção de soluções algébricas de sistemas de equações.
>>> from sympy import solve
>>> from sympy.abc import x, y, z
>>> solution = solve([x**2 + y - 2*z, y + 4*z], x, y, dict=True)
>>> pprint(solution)
[{x: -√6⋅√z, y: -4⋅z}, {x: √6⋅√z, y: -4⋅z}]
Já o solveset() é adequado para representar soluções de forma matematicamente precisa, usando conjuntos matemáticos.
>>> from sympy import solveset
>>> solveset(x**2 - y, x)
{-√y, √y}
O método solveset() também obtém a representação de todas as soluções, inclusive se houver soluções infinitas.
>>> from sympy import pprint, sin, solveset
>>> from sympy.abc import x
>>> solution = solveset(sin(x), x)
>>> pprint(solution)
{2⋅n⋅π │ n ∊ ℤ} ∪ {2⋅n⋅π + π │ n ∊ ℤ}
Além disso, o solveset() possibilita que o usuário limite o domínio das soluções a qualquer conjunto arbitrário.
>>> from sympy import S, solveset
>>> from sympy.abc import x
>>> solveset(x**4 - 256, x, domain=S.Reals)
{-4, 4}
Integrais, derivadas e limites
Evidentemente, derivadas, integrais e limites não poderiam faltar numa biblioteca como SymPy. Abaixo exemplificamos um cálculo simbólico de uma derivada.
>>> from sympy import *
>>> solution = diff(sin(x)*exp(x), x)
>>> pprint(solution)
x x
ℯ ⋅sin(x) + ℯ ⋅cos(x)
Também é possível obter soluções de equações diferenciais com o método dsolve().
>>> from sympy import Function, dsolve, Derivative
>>> from sympy.abc import x
>>> y = Function('y')
>>> solution = dsolve(Derivative(y(x), x, x) + 9*y(x), y(x))
>>> pprint(solution)
y(x) = C₁⋅sin(3⋅x) + C₂⋅cos(3⋅x)
O cálculo simbólico de integrais com SymPy também é simples, veja um exemplo:
>>> from sympy import *
>>> solution = integrate(sin(x**2), (x, -oo, oo))
>>> pprint(solution)
√2⋅√π
─────
2
Abaixo mostramos um exemplo de cálculo de limite com x tendendo a zero.
>>> limit(sin(x)/x, x, 0)
1
Matrizes
Cálculo matricial não poderia faltar numa biblioteca como SymPy. O cálculo matricial é facilmente realizado com NumPy quando a matriz tem valores numéricos. Porém, diferentemente do NumPy, o SymPy possibilita trabalhar com matrizes simbólicas. Veja um exemplo:
>>> from sympy import init_printing
>>> init_printing(use_unicode=True)
>>> from sympy import symbols
>>> from sympy.matrices import Matrix
>>> c, d, e = symbols("c, d, e")
>>> A = Matrix([[c,d], [1, -e]])
>>> A
⎡c d ⎤
⎢ ⎥
⎣1 -e⎦
SymPy também calcula eigenvalues de matrizes como exemplificado abaixo:
>>> Matrix([[1, 2], [2, 2]]).eigenvals()
⎧3 √17 3 √17 ⎫
⎨─ - ───: 1, ─ + ───: 1⎬
⎩2 2 2 2 ⎭
Calculando a derivada da tangente hiperbólica para redes neurais
Algoritmos de inteligência artificial precisam de matemática simbólica em diversas situações. Talvez a mais popular seja para calcular as derivadas de funções de ativação durante a backpropagation de redes neurais e deep learning. Muitas bibliotecas realizam esses cálculos de forma numérica, mas o SymPy possibilita sua realização simbólica. Abaixo, mostramos o exemplo do cálculo da derivada da função de ativação tangente hiperbólica. Primeiro definimos a sua equação:
>>> from sympy import init_printing
>>> init_printing(use_unicode=True)
>>> from sympy import diff, symbols, exp
>>> x = symbols("x")
>>> sympy_tanh = (exp(x) - exp(-x)) / (exp(x) + exp(-x))
>>> sympy_tanh
x -x
ℯ - ℯ
────────
x -x
ℯ + ℯ
Depois calculamos a derivada:
>>> solution = diff(sympy_tanh, x)
>>> solution
⎛ x -x⎞ ⎛ x -x⎞
⎝- ℯ + ℯ ⎠⋅⎝ℯ - ℯ ⎠
─────────────────────── + 1
2
⎛ x -x⎞
⎝ℯ + ℯ ⎠
Conclusões
Neste post, apresentamos brevemente a biblioteca SymPy para matemática simbólica com Python. A biblioteca, embora seja relativamente nova, tem várias outras funcionalidades que não mencionamos. Portanto, para quem tem interesse na área, consulte a documentação oficial e se divirta!