Expressões racionais, logaritmos e exponencias no SymPy

sympy racionais log exp

Neste artigo veremos como trabalhar com expressões racionais, exponenciais e logaritmos com a biblioteca SymPy do Python.

Importando o SymPy e criando alguns símbolos

Vamos começar importando o SymPy e criando alguns símbolos que usaremos no decorrer do artigo. Caso tenha alguma dificuldade no conceito de símbolos da biblioteca, veja o primeiro artigo da série sobre SymPy:

import sympy

# configuração para outputs melhores no artigo, pode ser ignorado
sympy.init_printing(use_latex='png', scale=1.0, order='grlex',
                    forecolor='Black', backcolor='White',)

x, y, a, b, c, d, n = sympy.symbols('x y a b c d n')

Expressões racionais

Uma função racional é qualquer função que pode ser expressa como uma razão (quociente) de polinômios:

Por padrão, o SymPy não junta ou divide expressões racionais. Por exemplo:

a/b + c/d

Caso queiramos “juntar” as frações, o que manualmente faríamos com o procedimento do mínimo múltiplo comum (MMC), usamos o método together:

sympy.together(_)

Lembrando, o underscore (_) é apenas uma forma abreviada de reutilizar um resultado de uma célula anterior.

Vejamos agora o contrário, uma situação onde temos uma expressão racional e gostaríamos de escrevê-la na forma de frações mais simples, chamadas frações parciais. Uma situação onde usualmente fazemos essa operação é na resolução de problemas de integrais de funções racionais. Neste caso, usamos o método apart:

(x**2 + x + 4)/(x + 2)
sympy.apart(_)

Exponenciais e logaritmos

Logaritmos e exponenciais aparecem nos mais diferentes contextos de problemas matemáticos. Assim, é importante saber como utililzá-los com o SymPy, especialmente as considerações implícitas que o pacote faz e que podem dar origem a resultados que nem sempre são os esperados num primeiro momento.

Começando pela forma de denotação, em boa parte das linguagens de programação e suas bibliotecas, a representação log expressa logaritmo natural que, em trabalhos escritos, costumamos escrever como ln. Em Python e no SymPy não é diferente, mas o SymPy tenta ser mais amigável e considera ln = log:

sympy.ln(x)

Veja que no resultado aparece log(x) mesmo tendo escrito ln(x) na célula. E lembre-se que esta é uma “camaradagem” do SymPy e não do Python em si. Por exemplo, não tente utilizar com a biblioteca padrão math:

import math

math.ln(10)
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
/tmp/ipykernel_16553/2001684872.py in <module>
      1 import math
      2 
----> 3 math.ln(10)

AttributeError: module 'math' has no attribute 'ln'
math.log(10)  # aqui funciona, sendo log a representação de ln. Não confundir com log10
math.log10(10)

No estudo de matemática em níveis mais básicos as seguintes identidades são ensinadas para logaritmos:

No entanto, tais identidades não são válidas se x e y forem complexos arbitrários devido ao ponto de ramificação (descontinuidade) existente no plano complexo para um logaritmo. Vamos ver como o SymPy lida com tais expressṍes:

sympy.log(x * y)
sympy.log(x**n)

Veja que o SymPy manteve a multiplicação e a exponenciação. Vamos tentar forçar a expansão com o método expand_log:

sympy.expand_log(sympy.log(x * y))
sympy.expand_log(sympy.log(x**n))

Veja que “não funcionou”. Ou melhor, funcionou, pois não especificamos condições de contorno para x, y e n. Logo, o SymPy não faz nenhuma consideração implícita e considera que, no pior casos, são complexos e a expansão não pode ser realizada.

Agora, o expand_log, assim como outros métodos do SymPy que veremos em outros artigos dessa série, fossui um parâmetro chamado force que, quando True, faz com que a expansão seja feita forçadamente:

sympy.expand_log(sympy.log(x * y), force=True)
sympy.expand_log(sympy.log(x**n), force=True)

Mas, na vida real, boas ideias não precisam ser forçadas. Ou, trazendo para um contexto mais próxima da programação, vamos nos lembrar do Zen do Python:

import this
The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!

Olhe o segundo verso: explícito é melhor que implícito. Assim, melhor do que forçar a expansão, seria deixar explícitas as condições de contorno para cada símbolo e, se tais condições forem adequadas, a expansão ocorre naturalmente.

As identidades acima são válidas desde que x e y sejam positivos e n seja um número real. Assim, vamos redefinir tais símbolos explicitando tais condições:

x, y = sympy.symbols('x y', positive=True)
n = sympy.symbols('n', real=True)

Vamos verificar se as expansões agora são possíveis:

sympy.expand_log(sympy.log(x * y))
sympy.expand_log(sympy.log(x**n))

Na minha opinião, a segunda forma é bem melhor. Sempre que se souber as condições de cada símbolo (se é sempre positiva, negativa, real…) é uma boa prática explicitar ao criar o símbolo.

Caso a operação contrária, combinação, seja desejada há o logcombine:

sympy.logcombine(sympy.log(x) + sympy.log(y))
sympy.logcombine(n * sympy.log(x))

Por fim, vamos falar do número de Euler, a base no logaritmo natural. Tal número possui diversas definições:

No SymPy é representado por E. Desta forma, exp(x) é equivalente a E**x:

sympy.E
sympy.E**x
sympy.exp(x)

Podemos obter uma aproximação numérica para E utilizando formas já vistas em outros artigos:

sympy.E.n()

Vamos verificar com E que log realmente representa logaritmo natural:

sympy.log(sympy.E**2)

Mas, e se quisermos logaritmo em alguma outra base? Basta passar a base como segundo argumento do método log:

sympy.log(10**2, 10)

Conclusão

Mais um artigo sobre SymPy. Expressões racionais, logaritmos e exponenciais aparecem diversas vezes em diversos conceitos, de forma que o visto auqi neste artigo será útil diversas vezes nos próximos artigos.

Caso queira saber quando novos artigos são disponibilizados, siga o Ciência Programada nas redes sociais. A lista completa de artigos sobre SymPy pode ser vista na tag SymPy e, caso queira ver a série na ordem, veja a lista abaixo, que será atualizada a cada novo artigo:

Até a próxima.

Compartilhe:

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *

Rolar para cima