(actualizado em 18 de Setembro de 2019)
O IPython (agora integrado no projecto Jupyter) é um ambiente interactivo para a utilização livre da linguagem Python como ferramenta de cálculo e visualização, bem como para o desenvolvimento de (pequenos) programas na linguagem Python e sua prototipagem rápida. A versatilidade do ambiente IPython facilita a integração com outros ambientes e linguagens de programação.
O IPython pode ser facilmente instalado através da distribuição Anaconda disponível em www.anaconda.com/download. Basta descarregar o instalador adequado ao seu sistema operativo (Windows, OSX, Linux) para a versão corrente da linguagem Python (versão 3, que usaremos sempre ao longo deste curso) e executá-lo. Após a instalação, basta abrir o Navigator e começar a trabalhar.
No modo Jupyter Notebook, que usaremos, a interacção dá-se através de um interface muito simples suportado por um browser, que por sua vez comunica com um kernel que disponibiliza um interpretador de Python. É neste modo que trabalharemos, desde já, sendo também muito útil para a produção de conteúdos de ensino/divulgação, como este texto.
O ambiente IPython, simples e interactivo, é extremamente conveniente para a aprendizagem da programação (no caso em Python), nomeadamente a elaboração de pequenos programas e sua experimentação. Mais adiante, quando necessário, veremos como ultrapassar algumas limitações do ambiente IPython no contexto da programação em larga (maior) escala e introduziremos, nomeadamente, o ambiente Spyder também disponibilizado pela distribuição Anaconda.
O ambiente IPython surge-nos dividido em células, onde podemos escrever e avaliar expressões. Há também células de texto, como esta, onde podemos fazer anotações relevantes. O IPython providencia ainda um conjunto de extensões à linguagem Python, para interacção com o sistema operativo e com outros ambientes e linguagens, bem como mecanismos de introspecção e de controlo da computação, que iremos abordando ao longo do texto, e que se denominam de $\textrm{magics}$.
O Python disponibiliza à partida, para além de algumas funcionalidades básicas, várias operações numéricas que podemos utilizar: +
(adição), -
(subtracção), *
(multiplicação), /
(divisão), **
(exponenciação), //
(divisão inteira), %
(resto da divisão inteira). Agrupamos expressões usando parênteses, como é usual. As expressões são avaliadas premindo SHIFT+RETURN.
1+1-3
(2*3)%5
7/3
7//3
10**3
abs(-1)*max(1,2,3)+min(1,2,3)+round(2.6)
1/3+1/2
Para podermos usar este ambiente como ambiente de cálculo e visualização, rico e apelativo, necessitamos de usar extensões à linguagem básica. A linguagem Python, como muitas outras linguagens de programação modernas, dispõe de mecanismos de modularização robustos. Um dos mais importantes é a existência de bibliotecas com extensões à linguagem básica, que servem os mais diversos fins. Estas extensões estão organizadas em pacotes de módulos, de que falaremos mais adiante. Existem vários módulos que dão suporte a mecanismos de cálculo e visualização gráfica que poderão ser bastante úteis, nomeadamente: Scipy e Matplotlib, ambas incluindo Numpy, que por sua vez inclui Math, e ainda Sympy, cuja utilização ilustramos de seguida.
As extensões Numpy e Matplotlib estão incluídas na extensão Pylab, que pode ser carregada como se mostra abaixo. A instrução precedida de % é aquilo a que na terminologia do IPython se denomina $\textrm{magic}$, uma extensão à linguagem Python que facilita a interacção com o sistema. Introduziremos, quando necessário, outras magias do IPython.
Note-se que a extensão Pylab fornece um contexto essencialmente equivalente ao ambiente comercial MATLAB, profusamente utilizado em aplicações em diversas áreas da engenharia.
%pylab inline
?pylab
Avaliando a expressão acima e percorrendo a informação na janela resultante podemos identificar as funcionalidades que passamos a ter disponíveis, algumas das quais ilustraremos de seguida. Poderá ser útil averiguar também os conteúdos de Numpy e Matplotlib, bem como da extensão Math que é incluída conjuntamente.
pi
Note-se que o valor de $\pi$ é aproximado, pelo que poderá haver pequenos (?) erros de cálculo. Tipicamente, os números reais em Python são representados com 53 dígitos de precisão.
?pi
cos(2*pi)
sin(pi/6)
sin(2*pi/3)-sqrt(3)/2
log(e**5)
log2(1024)-log10(1000)
Veremos mais abaixo o que fazer caso pretendamos trabalhar com precisão arbitrária, ou mesmo com representações simbólicas, exactas mas menos eficientes.
A manipulação numérica de vectores e matrizes é disponibilizada directamente pela extensão Pylab.
array([1,2,3,4])
arange(1,5)
arange(1,10,2)
shape(array([1,2,3,4]))
shape(array([[1,2,3],[3,4,5]]))
ndim(array([[[1,1],[1,1]],[[2,2],[2,2]],[[3,3],[3,3]]]))
shape(array([[[1,1],[1,1]],[[2,2],[2,2]],[[3,3],[3,3]]]))
reshape(arange(100),(10,10))
fromfunction(lambda i, j: i + j, (3, 3))
zeros((3,3))
ones((3,4))
eye(3)
rand(3,4)
print(rand(3,4))
print(arange(1,10000))
array([1,2,3])+array([1,2,3])
2*array([1,2,3])
array([1,2,3])*array([1,2,3])
eye(3)+eye(3)
ones((3,3))*ones((3))
dot(array([1,2,3]),array([4,5,6]))
dot(ones((3,3)),ones((3,3)))
dot(ones((3,3)),eye(3))
transpose(array([[1,2],[3,4],[5,6]]))
trace(array([[2,0],[1,3]]))
det(array([[1,0],[1,0]]))
det(array([[2,3,2],[4,2,3],[9,6,7]]))
inv(array([[2,3,2],[4,2,3],[9,6,7]]))
dot(array([[2,3,2],[4,2,3],[9,6,7]]),array([[-4,-9,5],[-1,-4,2],[6,15,-8]]))
solve(array([[1,1],[1,-1]]),array([[2],[0]]))
eig(array([[2,0],[1,3]]))
O significado e importância de operações matriciais como produtos, inversas, determinantes ou valores próprios é objecto de estudo da disciplina de Álgebra Linear.
complex(1,1)
(0+1j)**2+1j
conjugate(1+1j)
real(complex(1,-1))
imag(complex(1,-1))
abs(1+1j)
A extensão Sympy suporta uma miríade de funcionalidades para cálculo simbólico.
from sympy import *
Esta extensão redefine várias das funcionalidades disponibilizadas pelas extensões anteriores, e introduz muitas outras. Discutiremos abaixo as mais relevantes. Note-se que pi é redefinida, enquanto e não. A versão simbólica do número de Napier é E.
e+E
sin(pi/6)
sin(2*pi/3)-sqrt(3)/2
É sempre possível avaliar numericamente (e aproximadamente) uma expressão simbólica. Para tal recorre-se ao método evalf. Veremos mais tarde qual o significado exacto de um método.
(pi/2).evalf()
A representação de números racionais como fracções exactas poderá ser particularmente útil.
Rational(1,2)+Rational(1,3)
(Rational(1,2)+Rational(1,3)).evalf()
A extensão Sympy permite fazer manipulação de simbólica de expressões, como é usual em álgebra. Os símbolos devem ser definidos como se mostra abaixo.
x,y = symbols("x"),symbols("y")
x+x
x*y+y*x
factor(x**2-y**2)
(x - y)*(x + y)
expand((x - y)*(x + y))
expand((1+x)**5)
factor(x**5 + 5*x**4 + 10*x**3 + 10*x**2 + 5*x + 1)
x*x**2-x**3
together(1/x+1/y)
É possível avaliar uma expressão concretizando valores para os símbolos que contém, recorrendo ao método subs.
(x+y).subs(y,x)
(x**2-y).subs([(x,5),(y,3)])
Na extensão simbólica Sympy, as matrizes são agora representadas usando Matrix.
Matrix([[1,x],[2,y]])+Matrix([[x,x],[y,x]])
São introduzidas várias funcionalidades adicionais, e algumas operações são também redefinidas. Por exemplo, * passa a ser o produto de matrizes, em vez de dot.
Matrix([[1,x],[2,y]])*Matrix([[x,x],[y,x]])
shape(Matrix([[1,x],[2,y]]))
Matrix([[1,x],[2,y]]).row(1)
Matrix([[1,x],[2,y]]).row(0)
Matrix([[1,x],[2,y]]).col(0)
Matrix([[1,x],[2,y]])**(-1)
det(Matrix([[1,x],[2,y]]))
Matrix([[1,x],[2,y]]).eigenvals()
Matrix([[1,x],[2,y]]).eigenvects()
Matrix(2,2,[1,2,3,4])
Matrix(3,2,range(6))
Matrix(3,2,lambda i,j:i+j)
diff(x**2+x+5,x)
diff(1/x**2,x)
diff(sin(x),x)
É possível também definir nomes simbólicos para funções.
f=Function("f")
diff(f(x)**2,x)
g=Function("g")
diff(f(x)+g(x),x)
diff(f(x)*g(x),x)
diff(f(g(x)),x)
integrate(x,x)
integrate(1/(1+x**2),x)
integrate(x*sin(x),x)
integrate(x,(x,0,1))
integrate(sin(x),(x,0,pi))
integrate(E**-x,(x,0,oo))
limit(sin(x)/x,x,0)
limit(atan(x),x,oo)
?limit
limit(1/x,x,0,dir="+")
limit(1/x,x,0,dir="-")
?summation
summation(x,(x,0,5))
n = Symbol("n")
summation(x,(x,0,n))
summation(1/2**n,(n,1,oo))
summation(1/factorial(x),(x,0,oo))
summation(x,(x,0,oo))
?series
series(cos(x),x, 0, 10)
series(E**x,x,0,10)
A extensão Sympy também disponibiliza a manipulação simbólica de números complexos. A constante imaginária é agora representada por $\textsf{I}$, em vez de j.
?I
I**2
(1+2*I)*(1-I)
im(1+2*I+3)
re(1+2*I+3)
a,b=Symbol("a"),Symbol("b")
conjugate(a+b*I)
solve(x**2+1,x)
?solve
solve(2*x+5-7,x)
c=Symbol("c")
solve(a*x**2+b*x+c,x)
solve(a*x**2+b*x+c,c)
solve(x**2+1,x)
solve((2*a-b,a+b-3),a,b)
solve(cos(x),x)
solve(2*x<1,x)
solve([x<3,x**2>1],x)
solve(x*cos(x)-log(x),x)
Como seria de esperar, há limites para aquilo que podemos fazer simbolicamente. Veremos mais abaixo como poderemos tentar obter soluções numéricas, aproximadas, para esta equação.
Como a computação simbólica é bastante mais pesada e nem sempre é uma opção, por vezes é mesmo necessário trabalhar numericamente. Se e quando necessário podemos controlar a precisão dos cálculos envolvidos. Uma das formas mais expeditas de o conseguir consiste na utilização do módulo Mpmat da extensão Sympy.
from mpmath import mp
mp.pi
2*mp.pi
mp.dps=100
print(mp.pi)
mp.dps=500
print(mp.pi)
O parâmetro dps
controla a precisão de trabalho, no caso 100 ou 500 casas decimais significativas. É importante distinguir precisão de exactidão (accuracy em inglês): exactidão é o inverso do erro de cálculo, que é a diferença entre o valor calculado e o valor exacto (ou o seu logaritmo, dependendo das implementações).
O controlo dos erros de cálculo é um assunto complexo, pois pequenos erros podem propagar-se por vezes de forma bastante invasiva. Vale a pena explorar as possibilidades oferecidas por esta extensão do Python, acessíveis através de completação por TAB como abaixo.
from IPython.display import Image
Image("mpmethods.png")
Vejamos, por exemplo, como podemos obter uma solução numérica para a equação não-elementar x*cos(x)-log(x)==0
.
mp.findroot(lambda x:x*cos(x)-log(x),1)
plot(1+x**2, (x, -5, 5))
plot(sin(x),(x,0,2*pi))
plot(sin(x**2),(x,0,10))
plot(x*cos(x)-log(x), (x, 10**(-3), 2))
O gráfico acima poderá ajudar-nos a confirmar a correcção da solução aproximada obtida mais acima usando findroot
para a equação correspondente a x*cos(x)-log(x)
.
Podemos também desenhar o grafico de várias funções em simultâneo.
plot((sin(x),(x,-pi,pi)),(x,(x,-2,2)))
Há várias outras primitivas gráficas disponíveis, nomeadamente para visualizar, das mais diversas formas, listas de valores.
pie([45,30,10,10,4,1])
bar(range(10),[10,-7,20,3,15,-8,5,11,0,14])
hist([5,5,1,1,1,5,2,2,3,5])
A extensão Sympy.plotting adiciona várias outras funcionalidades úteis para geração de gráficos. No caso, importaremos apenas a funcionalidade plot3d.
from sympy.plotting import plot3d
?plot3d
plot3d(x+y,(x,-1,1),(y,-1,1))
plot3d(y**2*sin(x),(x,0,2*pi),(y,0,20))
plot3d(sin(x*cos(y)),(x,0,2*pi),(y,10,20))
Há extensões que permitem visualizar informação de outros tipos. No caso abaixo, importaremos da extensão Matplotlib.pyplot apenas a funcionalidade plot, a que chamaremos dataplot para que não seja redefinida.
from matplotlib.pyplot import plot as dataplot
?dataplot
dataplot([1,2,3,4,5])
dataplot([1,-2,3,-4,5],"ro-")
dataplot([1,5,3,4,2,6],"g*--")
dataplot([1,2,3,4,5], "go-", label="line 1", linewidth=2)
dataplot([2,9,0,4], "rs", label="line 2")
axis([-2, 8, -2, 10])
legend()
Veremos mais adiante, quando necessário, como produzir conteúdos gráficos mais elaborados, nomeadamente animações.
Pelas suas características, que estudaremos, a linguagem Python vem ganhando uma crescente importância para experimentação e desenvolvimento de aplicações, nomeadamente científicas, vindo a ser adoptada por empresas e universidades, pequenas e grandes, pelo mundo fora. De referir, por serem relevantes a jusante, as seguintes ferramentas baseadas em Python:
Introdução à Programação em Mathematica (3a edição): J. Carmo, A. Sernadas, C. Sernadas, F. M. Dionísio, C. Caleiro, IST Press, 2014.
Think Python: How to think like a computer scientist: A. Downey, Green Tea Press, 2012.
Introduction to Computation and Programming Using Python (revised and expanded edition): J. V. Guttag, MIT Press, 2013.
The Art of Computer Programming: D. E. Knuth, Addison-Wesley (volumes 1--3, 4A), 1998.
Learning Python (fifth edition): M. Lutz, O'Reilly Media, 2013.
Programação em Python: Introdução à programação utilizando múltiplos paradigmas: J. P. Martins, IST Press, 2015.
Introdução à Programação em MatLab: J. Ramos, A. Sernadas e P. Mateus, DMIST, 2005.
Learning IPython for Interactive Computing and Data Visualization: C. Rossant, Packt Publishing, 2013.
Programação em Mathematica: A. Sernadas, C. Sernadas e J. Ramos, DMIST, 2003.
No sistema operativo OSX há por vezes diferenças na codificação de caracteres. Caso ocorra um erro do tipo
ValueError: unknown locale: UTF-8
é necessário editar manualmente o ficheiro .bash_profile
juntando-lhe as duas linhas seguintes:
export LC_ALL=en_US.UTF-8
export LANG=en_US.UTF-8