Introdução à Programação em Python

Notebook 01 - IPython como ambiente de computação, cálculo e visualização

Carlos Caleiro, Jaime Ramos

Dep. Matemática, IST - 2016

(actualizado em 18 de Setembro de 2019)

Introdução ao ambiente IPython

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 IPython como ferramenta de cálculo e visualização

Cálculo numérico

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.

In [1]:
1+1-3
Out[1]:
-1
In [2]:
(2*3)%5
Out[2]:
1
In [3]:
7/3
Out[3]:
2.3333333333333335
In [4]:
7//3
Out[4]:
2
In [5]:
10**3
Out[5]:
1000
In [6]:
abs(-1)*max(1,2,3)+min(1,2,3)+round(2.6)
Out[6]:
7
In [7]:
1/3+1/2
Out[7]:
0.8333333333333333

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.

In [8]:
%pylab inline
Populating the interactive namespace from numpy and matplotlib
In [9]:
?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.

In [10]:
pi
Out[10]:
3.141592653589793

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.

In [11]:
?pi
In [12]:
cos(2*pi)
Out[12]:
1.0
In [13]:
sin(pi/6)
Out[13]:
0.49999999999999994
In [14]:
sin(2*pi/3)-sqrt(3)/2
Out[14]:
2.220446049250313e-16
In [15]:
log(e**5)
Out[15]:
5.0
In [16]:
log2(1024)-log10(1000)
Out[16]:
7.0

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.

Vectores e matrizes

A manipulação numérica de vectores e matrizes é disponibilizada directamente pela extensão Pylab.

In [17]:
array([1,2,3,4])
Out[17]:
array([1, 2, 3, 4])
In [18]:
arange(1,5)
Out[18]:
array([1, 2, 3, 4])
In [19]:
arange(1,10,2)
Out[19]:
array([1, 3, 5, 7, 9])
In [20]:
shape(array([1,2,3,4]))
Out[20]:
(4,)
In [21]:
shape(array([[1,2,3],[3,4,5]]))
Out[21]:
(2, 3)
In [22]:
ndim(array([[[1,1],[1,1]],[[2,2],[2,2]],[[3,3],[3,3]]]))
Out[22]:
3
In [23]:
shape(array([[[1,1],[1,1]],[[2,2],[2,2]],[[3,3],[3,3]]]))
Out[23]:
(3, 2, 2)
In [24]:
reshape(arange(100),(10,10))
Out[24]:
array([[ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9],
       [10, 11, 12, 13, 14, 15, 16, 17, 18, 19],
       [20, 21, 22, 23, 24, 25, 26, 27, 28, 29],
       [30, 31, 32, 33, 34, 35, 36, 37, 38, 39],
       [40, 41, 42, 43, 44, 45, 46, 47, 48, 49],
       [50, 51, 52, 53, 54, 55, 56, 57, 58, 59],
       [60, 61, 62, 63, 64, 65, 66, 67, 68, 69],
       [70, 71, 72, 73, 74, 75, 76, 77, 78, 79],
       [80, 81, 82, 83, 84, 85, 86, 87, 88, 89],
       [90, 91, 92, 93, 94, 95, 96, 97, 98, 99]])
In [25]:
fromfunction(lambda i, j: i + j, (3, 3))
Out[25]:
array([[0., 1., 2.],
       [1., 2., 3.],
       [2., 3., 4.]])
In [26]:
zeros((3,3))
Out[26]:
array([[0., 0., 0.],
       [0., 0., 0.],
       [0., 0., 0.]])
In [27]:
ones((3,4))
Out[27]:
array([[1., 1., 1., 1.],
       [1., 1., 1., 1.],
       [1., 1., 1., 1.]])
In [28]:
eye(3)
Out[28]:
array([[1., 0., 0.],
       [0., 1., 0.],
       [0., 0., 1.]])
In [29]:
rand(3,4)
Out[29]:
array([[0.39936009, 0.82021467, 0.57301195, 0.40932012],
       [0.44970128, 0.87858468, 0.09337122, 0.64706307],
       [0.51126101, 0.33821554, 0.18602321, 0.14068964]])
In [30]:
print(rand(3,4))
[[0.56160006 0.11861895 0.00795708 0.7099636 ]
 [0.95610751 0.37245243 0.55466018 0.40657516]
 [0.55927415 0.79059928 0.25886881 0.22258423]]
In [31]:
print(arange(1,10000))
[   1    2    3 ... 9997 9998 9999]
In [32]:
array([1,2,3])+array([1,2,3])
Out[32]:
array([2, 4, 6])
In [33]:
2*array([1,2,3])
Out[33]:
array([2, 4, 6])
In [34]:
array([1,2,3])*array([1,2,3])
Out[34]:
array([1, 4, 9])
In [35]:
eye(3)+eye(3)
Out[35]:
array([[2., 0., 0.],
       [0., 2., 0.],
       [0., 0., 2.]])
In [36]:
ones((3,3))*ones((3))
Out[36]:
array([[1., 1., 1.],
       [1., 1., 1.],
       [1., 1., 1.]])
In [37]:
dot(array([1,2,3]),array([4,5,6]))
Out[37]:
32
In [38]:
dot(ones((3,3)),ones((3,3)))
Out[38]:
array([[3., 3., 3.],
       [3., 3., 3.],
       [3., 3., 3.]])
In [39]:
dot(ones((3,3)),eye(3))
Out[39]:
array([[1., 1., 1.],
       [1., 1., 1.],
       [1., 1., 1.]])
In [40]:
transpose(array([[1,2],[3,4],[5,6]]))
Out[40]:
array([[1, 3, 5],
       [2, 4, 6]])
In [41]:
trace(array([[2,0],[1,3]]))
Out[41]:
5
In [42]:
det(array([[1,0],[1,0]]))
Out[42]:
0.0
In [43]:
det(array([[2,3,2],[4,2,3],[9,6,7]]))
Out[43]:
1.0000000000000067
In [44]:
inv(array([[2,3,2],[4,2,3],[9,6,7]]))
Out[44]:
array([[-4., -9.,  5.],
       [-1., -4.,  2.],
       [ 6., 15., -8.]])
In [45]:
dot(array([[2,3,2],[4,2,3],[9,6,7]]),array([[-4,-9,5],[-1,-4,2],[6,15,-8]]))
Out[45]:
array([[1, 0, 0],
       [0, 1, 0],
       [0, 0, 1]])
In [46]:
solve(array([[1,1],[1,-1]]),array([[2],[0]]))
Out[46]:
array([[1.],
       [1.]])
In [47]:
eig(array([[2,0],[1,3]]))
Out[47]:
(array([3., 2.]), array([[ 0.        ,  0.70710678],
        [ 1.        , -0.70710678]]))

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.

Números complexos

In [48]:
complex(1,1)
Out[48]:
(1+1j)
In [49]:
(0+1j)**2+1j
Out[49]:
(-1+1j)
In [50]:
conjugate(1+1j)
Out[50]:
(1-1j)
In [51]:
real(complex(1,-1))
Out[51]:
1.0
In [52]:
imag(complex(1,-1))
Out[52]:
-1.0
In [53]:
abs(1+1j)
Out[53]:
1.4142135623730951

Cálculo simbólico

A extensão Sympy suporta uma miríade de funcionalidades para cálculo simbólico.

In [54]:
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.

In [55]:
e+E
Out[55]:
$\displaystyle 2.71828182845905 + e$
In [56]:
sin(pi/6)
Out[56]:
$\displaystyle \frac{1}{2}$
In [57]:
sin(2*pi/3)-sqrt(3)/2
Out[57]:
$\displaystyle 0$

É 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.

In [58]:
(pi/2).evalf()
Out[58]:
$\displaystyle 1.5707963267949$

A representação de números racionais como fracções exactas poderá ser particularmente útil.

In [59]:
Rational(1,2)+Rational(1,3)
Out[59]:
$\displaystyle \frac{5}{6}$
In [60]:
(Rational(1,2)+Rational(1,3)).evalf()
Out[60]:
$\displaystyle 0.833333333333333$

Manipulação simbólica de expressões

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.

In [61]:
x,y = symbols("x"),symbols("y")
In [62]:
x+x
Out[62]:
$\displaystyle 2 x$
In [63]:
x*y+y*x
Out[63]:
$\displaystyle 2 x y$
In [64]:
factor(x**2-y**2)
Out[64]:
$\displaystyle \left(x - y\right) \left(x + y\right)$
In [65]:
(x - y)*(x + y)
Out[65]:
$\displaystyle \left(x - y\right) \left(x + y\right)$
In [66]:
expand((x - y)*(x + y))
Out[66]:
$\displaystyle x^{2} - y^{2}$
In [67]:
expand((1+x)**5)
Out[67]:
$\displaystyle x^{5} + 5 x^{4} + 10 x^{3} + 10 x^{2} + 5 x + 1$
In [68]:
factor(x**5 + 5*x**4 + 10*x**3 + 10*x**2 + 5*x + 1)
Out[68]:
$\displaystyle \left(x + 1\right)^{5}$
In [69]:
x*x**2-x**3
Out[69]:
$\displaystyle 0$
In [70]:
together(1/x+1/y)
Out[70]:
$\displaystyle \frac{x + y}{x y}$

É possível avaliar uma expressão concretizando valores para os símbolos que contém, recorrendo ao método subs.

In [71]:
(x+y).subs(y,x)
Out[71]:
$\displaystyle 2 x$
In [72]:
(x**2-y).subs([(x,5),(y,3)])
Out[72]:
$\displaystyle 22$

Matrizes revisitadas

Na extensão simbólica Sympy, as matrizes são agora representadas usando Matrix.

In [73]:
Matrix([[1,x],[2,y]])+Matrix([[x,x],[y,x]])
Out[73]:
$\displaystyle \left[\begin{matrix}x + 1 & 2 x\\y + 2 & x + y\end{matrix}\right]$

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.

In [74]:
Matrix([[1,x],[2,y]])*Matrix([[x,x],[y,x]])
Out[74]:
$\displaystyle \left[\begin{matrix}x y + x & x^{2} + x\\2 x + y^{2} & x y + 2 x\end{matrix}\right]$
In [75]:
shape(Matrix([[1,x],[2,y]]))
Out[75]:
(2, 2)
In [76]:
Matrix([[1,x],[2,y]]).row(1)
Out[76]:
$\displaystyle \left[\begin{matrix}2 & y\end{matrix}\right]$
In [77]:
Matrix([[1,x],[2,y]]).row(0)
Out[77]:
$\displaystyle \left[\begin{matrix}1 & x\end{matrix}\right]$
In [78]:
Matrix([[1,x],[2,y]]).col(0)
Out[78]:
$\displaystyle \left[\begin{matrix}1\\2\end{matrix}\right]$
In [79]:
Matrix([[1,x],[2,y]])**(-1)
Out[79]:
$\displaystyle \left[\begin{matrix}\frac{y}{- 2 x + y} & - \frac{x}{- 2 x + y}\\- \frac{2}{- 2 x + y} & \frac{1}{- 2 x + y}\end{matrix}\right]$
In [80]:
det(Matrix([[1,x],[2,y]]))
Out[80]:
$\displaystyle - 2 x + y$
In [81]:
Matrix([[1,x],[2,y]]).eigenvals()
Out[81]:
{y/2 - sqrt(8*x + y**2 - 2*y + 1)/2 + 1/2: 1,
 y/2 + sqrt(8*x + y**2 - 2*y + 1)/2 + 1/2: 1}
In [82]:
Matrix([[1,x],[2,y]]).eigenvects()
Out[82]:
[(y/2 - sqrt(8*x + y**2 - 2*y + 1)/2 + 1/2, 1, [Matrix([
   [-y/4 - sqrt(8*x + y**2 - 2*y + 1)/4 + 1/4],
   [                                        1]])]),
 (y/2 + sqrt(8*x + y**2 - 2*y + 1)/2 + 1/2, 1, [Matrix([
   [-y/4 + sqrt(8*x + y**2 - 2*y + 1)/4 + 1/4],
   [                                        1]])])]
In [83]:
Matrix(2,2,[1,2,3,4])
Out[83]:
$\displaystyle \left[\begin{matrix}1 & 2\\3 & 4\end{matrix}\right]$
In [84]:
Matrix(3,2,range(6))
Out[84]:
$\displaystyle \left[\begin{matrix}0 & 1\\2 & 3\\4 & 5\end{matrix}\right]$
In [85]:
Matrix(3,2,lambda i,j:i+j)
Out[85]:
$\displaystyle \left[\begin{matrix}0 & 1\\1 & 2\\2 & 3\end{matrix}\right]$

Derivação, primitivação e integração

In [86]:
diff(x**2+x+5,x)
Out[86]:
$\displaystyle 2 x + 1$
In [87]:
diff(1/x**2,x)
Out[87]:
$\displaystyle - \frac{2}{x^{3}}$
In [88]:
diff(sin(x),x)
Out[88]:
$\displaystyle \cos{\left(x \right)}$

É possível também definir nomes simbólicos para funções.

In [89]:
f=Function("f")
In [90]:
diff(f(x)**2,x)
Out[90]:
$\displaystyle 2 f{\left(x \right)} \frac{d}{d x} f{\left(x \right)}$
In [91]:
g=Function("g")
In [92]:
diff(f(x)+g(x),x)
Out[92]:
$\displaystyle \frac{d}{d x} f{\left(x \right)} + \frac{d}{d x} g{\left(x \right)}$
In [93]:
diff(f(x)*g(x),x)
Out[93]:
$\displaystyle f{\left(x \right)} \frac{d}{d x} g{\left(x \right)} + g{\left(x \right)} \frac{d}{d x} f{\left(x \right)}$
In [94]:
diff(f(g(x)),x)
Out[94]:
$\displaystyle \frac{d}{d g{\left(x \right)}} f{\left(g{\left(x \right)} \right)} \frac{d}{d x} g{\left(x \right)}$
In [95]:
integrate(x,x)
Out[95]:
$\displaystyle \frac{x^{2}}{2}$
In [96]:
integrate(1/(1+x**2),x)
Out[96]:
$\displaystyle \operatorname{atan}{\left(x \right)}$
In [97]:
integrate(x*sin(x),x)
Out[97]:
$\displaystyle - x \cos{\left(x \right)} + \sin{\left(x \right)}$
In [98]:
integrate(x,(x,0,1))
Out[98]:
$\displaystyle \frac{1}{2}$
In [99]:
integrate(sin(x),(x,0,pi))
Out[99]:
$\displaystyle 2$
In [100]:
integrate(E**-x,(x,0,oo))
Out[100]:
$\displaystyle 1$

Limites

In [101]:
limit(sin(x)/x,x,0)
Out[101]:
$\displaystyle 1$
In [102]:
limit(atan(x),x,oo)
Out[102]:
$\displaystyle \frac{\pi}{2}$
In [103]:
?limit
In [104]:
limit(1/x,x,0,dir="+")
Out[104]:
$\displaystyle \infty$
In [105]:
limit(1/x,x,0,dir="-")
Out[105]:
$\displaystyle -\infty$

Somatórios e séries

In [106]:
?summation
In [107]:
summation(x,(x,0,5))
Out[107]:
$\displaystyle 15$
In [108]:
n = Symbol("n")
In [109]:
summation(x,(x,0,n))
Out[109]:
$\displaystyle \frac{n^{2}}{2} + \frac{n}{2}$
In [110]:
summation(1/2**n,(n,1,oo))
Out[110]:
$\displaystyle 1$
In [111]:
summation(1/factorial(x),(x,0,oo))
Out[111]:
$\displaystyle e$
In [112]:
summation(x,(x,0,oo))
Out[112]:
$\displaystyle \infty$
In [113]:
?series
In [114]:
series(cos(x),x, 0, 10)
Out[114]:
$\displaystyle 1 - \frac{x^{2}}{2} + \frac{x^{4}}{24} - \frac{x^{6}}{720} + \frac{x^{8}}{40320} + O\left(x^{10}\right)$
In [115]:
series(E**x,x,0,10)
Out[115]:
$\displaystyle 1 + x + \frac{x^{2}}{2} + \frac{x^{3}}{6} + \frac{x^{4}}{24} + \frac{x^{5}}{120} + \frac{x^{6}}{720} + \frac{x^{7}}{5040} + \frac{x^{8}}{40320} + \frac{x^{9}}{362880} + O\left(x^{10}\right)$

Números complexos revisitados

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.

In [116]:
?I
In [117]:
I**2
Out[117]:
$\displaystyle -1$
In [118]:
(1+2*I)*(1-I)
Out[118]:
$\displaystyle \left(1 - i\right) \left(1 + 2 i\right)$
In [119]:
im(1+2*I+3)
Out[119]:
$\displaystyle 2$
In [120]:
re(1+2*I+3)
Out[120]:
$\displaystyle 4$
In [121]:
a,b=Symbol("a"),Symbol("b")
In [122]:
conjugate(a+b*I)
Out[122]:
$\displaystyle \overline{a} - i \overline{b}$
In [123]:
solve(x**2+1,x)
Out[123]:
[-I, I]

Resolução de equações e inequações

In [124]:
?solve
In [125]:
solve(2*x+5-7,x)
Out[125]:
[1]
In [126]:
c=Symbol("c")
In [127]:
solve(a*x**2+b*x+c,x)
Out[127]:
[(-b + sqrt(-4*a*c + b**2))/(2*a), -(b + sqrt(-4*a*c + b**2))/(2*a)]
In [128]:
solve(a*x**2+b*x+c,c)
Out[128]:
[-x*(a*x + b)]
In [129]:
solve(x**2+1,x)
Out[129]:
[-I, I]
In [130]:
solve((2*a-b,a+b-3),a,b)
Out[130]:
{a: 1, b: 2}
In [131]:
solve(cos(x),x)
Out[131]:
[pi/2, 3*pi/2]
In [132]:
solve(2*x<1,x)
Out[132]:
$\displaystyle -\infty < x \wedge x < \frac{1}{2}$
In [133]:
solve([x<3,x**2>1],x)
Out[133]:
$\displaystyle \left(-\infty < x \wedge x < -1\right) \vee \left(1 < x \wedge x < 3\right)$
In [134]:
solve(x*cos(x)-log(x),x)
---------------------------------------------------------------------------
NotImplementedError                       Traceback (most recent call last)
<ipython-input-134-b15b3c16e1e1> in <module>
----> 1 solve(x*cos(x)-log(x),x)

//anaconda3/lib/python3.7/site-packages/sympy/solvers/solvers.py in solve(f, *symbols, **flags)
   1169     ###########################################################################
   1170     if bare_f:
-> 1171         solution = _solve(f[0], *symbols, **flags)
   1172     else:
   1173         solution = _solve_system(f, symbols, **flags)

//anaconda3/lib/python3.7/site-packages/sympy/solvers/solvers.py in _solve(f, *symbols, **flags)
   1740 
   1741     if result is False:
-> 1742         raise NotImplementedError('\n'.join([msg, not_impl_msg % f]))
   1743 
   1744     if flags.get('simplify', True):

NotImplementedError: multiple generators [x, cos(x), log(x)]
No algorithms are implemented to solve equation x*cos(x) - log(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.

Controlo da precisão em cálculos numéricos

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.

In [135]:
from mpmath import mp
In [136]:
mp.pi
Out[136]:
<pi: 3.14159~>
In [137]:
2*mp.pi
Out[137]:
mpf('6.2831853071795862')
In [138]:
mp.dps=100
print(mp.pi)
3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117068
In [139]:
mp.dps=500
print(mp.pi)
3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461284756482337867831652712019091456485669234603486104543266482133936072602491412737245870066063155881748815209209628292540917153643678925903600113305305488204665213841469519415116094330572703657595919530921861173819326117931051185480744623799627495673518857527248912279381830119491

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.

In [140]:
from IPython.display import Image
Image("mpmethods.png")
Out[140]:

Vejamos, por exemplo, como podemos obter uma solução numérica para a equação não-elementar x*cos(x)-log(x)==0.

In [141]:
mp.findroot(lambda x:x*cos(x)-log(x),1)
Out[141]:
mpf('1.3475798620233314552584182846207099276785226493535943506247392495225400905747579535928171658973488501381979031022252595554334302549182120963308798835760977059101353945868549451306814806749129977743512134206063929219345634123973737353947064792088527199092170903201049973375557998272607370418169628132094987634979460243980085010298890576971089442021776418437159996892451074988723179348906177897307264688001413012219897929773833092694387173064924984532873704752431660596342428427369357144625822520869874838')

Geração de gráficos

In [142]:
plot(1+x**2, (x, -5, 5))
Out[142]:
<sympy.plotting.plot.Plot at 0x1189c7a58>
In [143]:
plot(sin(x),(x,0,2*pi))
Out[143]:
<sympy.plotting.plot.Plot at 0x118c51710>
In [144]:
plot(sin(x**2),(x,0,10))
Out[144]:
<sympy.plotting.plot.Plot at 0x118d59a58>
In [145]:
plot(x*cos(x)-log(x), (x, 10**(-3), 2))
Out[145]:
<sympy.plotting.plot.Plot at 0x118f2ec88>

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.

In [146]:
plot((sin(x),(x,-pi,pi)),(x,(x,-2,2)))
Out[146]:
<sympy.plotting.plot.Plot at 0x118e4c5f8>

Há várias outras primitivas gráficas disponíveis, nomeadamente para visualizar, das mais diversas formas, listas de valores.

In [147]:
pie([45,30,10,10,4,1])
Out[147]:
([<matplotlib.patches.Wedge at 0x119141e80>,
  <matplotlib.patches.Wedge at 0x11914c390>,
  <matplotlib.patches.Wedge at 0x11914c828>,
  <matplotlib.patches.Wedge at 0x11914ccc0>,
  <matplotlib.patches.Wedge at 0x119159198>,
  <matplotlib.patches.Wedge at 0x119159630>],
 [Text(0.17207795223283862, 1.086457168210212, ''),
  Text(-0.8899187180267096, -0.6465637441936393, ''),
  Text(0.33991869870988073, -1.0461621663333946, ''),
  Text(0.8899187028927927, -0.64656376502369, ''),
  Text(1.0805159790822678, -0.2061194288462117, ''),
  Text(1.0994572168309389, -0.03455182134657518, '')])
In [148]:
bar(range(10),[10,-7,20,3,15,-8,5,11,0,14])
Out[148]:
<BarContainer object of 10 artists>
In [149]:
hist([5,5,1,1,1,5,2,2,3,5])
Out[149]:
(array([3., 0., 2., 0., 0., 1., 0., 0., 0., 4.]),
 array([1. , 1.4, 1.8, 2.2, 2.6, 3. , 3.4, 3.8, 4.2, 4.6, 5. ]),
 <a list of 10 Patch objects>)

A extensão Sympy.plotting adiciona várias outras funcionalidades úteis para geração de gráficos. No caso, importaremos apenas a funcionalidade plot3d.

In [150]:
from sympy.plotting import plot3d
In [151]:
?plot3d
In [152]:
plot3d(x+y,(x,-1,1),(y,-1,1))
Out[152]:
<sympy.plotting.plot.Plot at 0x1192e7518>
In [153]:
plot3d(y**2*sin(x),(x,0,2*pi),(y,0,20))
Out[153]:
<sympy.plotting.plot.Plot at 0x1192e7cc0>
In [154]:
plot3d(sin(x*cos(y)),(x,0,2*pi),(y,10,20))
Out[154]:
<sympy.plotting.plot.Plot at 0x107db93c8>

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.

In [155]:
from matplotlib.pyplot import plot as dataplot 
In [156]:
?dataplot
In [157]:
dataplot([1,2,3,4,5])
Out[157]:
[<matplotlib.lines.Line2D at 0x119c78860>]
In [158]:
dataplot([1,-2,3,-4,5],"ro-")
Out[158]:
[<matplotlib.lines.Line2D at 0x119ea0b38>]
In [159]:
dataplot([1,5,3,4,2,6],"g*--")
Out[159]:
[<matplotlib.lines.Line2D at 0x119f5b780>]
In [160]:
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()
Out[160]:
<matplotlib.legend.Legend at 0x11a240588>

Veremos mais adiante, quando necessário, como produzir conteúdos gráficos mais elaborados, nomeadamente animações.

Outros ambientes de computação baseados em Python

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:

  • SageMath (também integrado no projecto Jupyter) é um ambiente livre que integra ferramentas computacionais para matemática, à semelhança de sistemas proprietários como o Mathematica
  • PyMOL é uma ferramenta de modelação e visualização biomolecular de crescente importância para engenheiros nas áreas da biotecnologia

Sumário

  • O IPython é um ambiente de programação interactivo muito simples, apropriado à experimentação rápida de programas em Python, e portanto adequado à sua aprendizagem
  • Munido das extensões adequadas o ambiente IPython pode ser utilizado como poderosa ferramenta de cálculo numérico e simbólico, e de visualização gráfica, extremamente útil em aplicações científicas, matemática e engenharia
  • A extensão Pylab fornece um ambiente de computação essencialmente equivalente ao popular sistema proprietário MATLAB

Bibliografia

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.

Nota

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