Métodos computacionais / 2019

Davi C. Rodrigues
Aula 2

e-mail: davi@cosmo-ufes.org
página do curso: davi.cosmo-ufes.org/metodoscomputacionais2019

Cap. 2 - A linguagem do Mathematica (ou Wolfram Language)

Acompanhando o Paul Wellin Programming with Mathematica: An Introduction  (2013)

2.1 Expressões

Tipos de expressões

Head[x]

x=5;
Head[x]

? Head

{Head[1], Head[1.], Head[ 3 + I 2], Head[45/7]}

12/7.

N[12/7]

Head[{1,2,4,5}]

x = ;

x

Head[]

phi =

Head[phi]

x

Plot[(x^2), {x,0,2}, Frame -> True, FrameLabel-> {phi, phi}]

Head[]

{CompleteGraph[10], Head[%]}

Head[CompleteGraph[25]]

AtomQ[2/a]

Head[2/a]

FullForm[2/a]

Clear[a,b]
Head[a+b]

IntegerQ[2.]

Head[2/3]

Head[x]

Átomos

FullForm[Hold@Plot[x,{x,0,1}]]

Head[Plot]

Print["x"]

Estrutura das expressões

Head[a+b+c]
FullForm[a+b+c]  
FullForm[a b c] /. Times -> Plus
a b c /. Times -> Plus

? FullForm

FullForm[{1234,345,2345,2345}]
FullForm[]

list= {1,2,3,4};
Part[list,-2]

list[[-2]]

FullForm[HoldForm[list[[-1]]]]

(2 + b  == (E^(3 y + 5)))[[1]]
(2 + b  == (E^(3 y + 5)))[[2]]
(2 + b  == (E^(3 y + 5)))[[1,1]]
(2 + b  == (E^(3 y + 5)))[[2,2,2,2]]

TreeForm[2 + b  == (E^(3 y + 5))]

Note que “2 + 3 i” é uma expressão atômica, mas “a + b” não é. Assim,

(a + b)[[2]]
(2 + I 3)[[2]]

FullForm[2 + 3 I]

Contudo, pode-se usar

Re[2 + 3 I]
Im[2 + 3 I]

NumberQ[2]
NumberQ[x]

AtomQ[2]
AtomQ[2 + 3]
AtomQ[2 x]
AtomQ[Cos[x]]

Head[True]

{(2 x)[[1]], (2 x)[[2]]}
{Cos[x][[1]], Cos[x][[0]]}

Head[Cos[x]]

Length[{1,2,3}]

m = {{1,2,3}, {4,5,6}}
m2 = {{1,2,3}, {4,5,6}} // TableForm

m

Length[m]

Length@Transpose@m

(Dimensions@m)[[1]]

m2

Delete[f[2,3],0]

Sequence[2,3]

Plot[x,{x,0,1}]

Clear[x]

y = {x, {x,0,1}}

Plot[Evaluate@Delete[y,0]]

Delete[m,0]

Delete[Delete[{a,b,c},0],0]
Delete[a,b,c,0]

Delete[Cos[x],0]

FullForm[2 Cos[x] + 3]
TreeForm[2 Cos[x] + 3]

FullForm[2 Cos[x] + 3]
(2 Cos[x] + 3)[[0]]
Head[(2 Cos[x] + 3)]
(2 Cos[x] + 3)[[1]]
(2 Cos[x] + 3)[[2]]
(2 Cos[x] + 3)[[2,1]]
(2 Cos[x] + 3)[[2,2]]
(2 Cos[x] + 3)[[2,2,1]]
(2 Cos[x] + 3)[[2,2,0]]

FullForm[2/3]

AtomQ[Rational[2,1]]

(2/3)[[1]]

{Numerator[2/3],Denominator[2/3]}

Hold[2+5]

HoldForm[2+5]

Hold[2+(2+5)2]
FullForm[HoldForm[2+(2+5)2]]
TreeForm[HoldForm[2+(2+5)2]]

Hold[2/3]
FullForm[HoldForm[2/3]]
TreeForm[HoldForm[2 + 3 I]]
TreeForm[2 + 3 I]

Rational[2,3]

TreeForm

FullForm[2+(2+5)2]

Ordem de execução das expressões

FullForm[x-> t]

ReleaseHold[Hold[2+3] /. 3-> 6]

f[2,3,4]

Ver também “The Standard Evaluation Procedure” (tutorial do mathematica).

Em geral, o Mathematica segue a seguinte ordem:

1. Computa a “cabeça”/”Head” da expressão
2. Calcula cada elemento associado ao Head (exceto se houver algum atributo associado a Hold, HoldFirst por exemplo)
3. Aplica transformações  Orderless, Listable e Flat
4. Aplicação das definições e regras (toda definição é uma regra para o Mathematica)
5. A expressão obtida é computada, ou seja, volta-se ao item 1. O loop termina quando o resultado de uma iteração for igual ao da iteração anterior.

Clear[a]
f[x_] = 5 x;
FullForm[f[2a x+a^2+1]]
TreeForm[f[2a x+a^2+1]]
TracePrint[f[2a x+a^2+1]]

a=7;
f[x_] = 5 x;
f[2a x+a^2+1] 
TracePrint[f[2a x+a^2+1]]

i=1; c= 0;
If[i > 4 && c=0, Print[i], Print["nao"]]

c

c==0

If[True, oi]

FullForm[Hold[i > 4 || c==0]]

Sequência de estrutura lógica

a=2;
b=3;
c=0;

a== 2 && b== 3 && c==0

FullForm[Hold[a== 2 && b== 3 && c==0]]
TracePrint[a== 2 && b== 3 && c==0]

b=1;
a== 2 && b== 3 && c==0
FullForm[Hold[a== 2 && b== 3 && c==0]]
TracePrint[a== 2 && b== 3 && c==0]

Clear@c
if = If[c==1, oi, tchau];

if

c=1

if

c==1

Head[234+24234]

Cos[0]

Clear[x,y]
Cos[Integrate[x,{x,0,2}]]

2+2 /. 2-> 5

2 + x /. 2->5

FullForm[Hold[2+2 /. 2-> 5]]

Precedence[Hold]
Precedence[Plus]
Precedence[ReplaceAll]

ReleaseHold[HoldForm[2+2]/. 2-> 5]

a=2; b= 4

Definições

Simples, já vimos vários desses itens... Mais detalhes no livro.

Segue lembrete da diferença entre Set e SetDelayed, definição de função e definição de variável com índice.

Clear[a,b,c]

a:= 3;
b := a+1;

a

b

a=5

b

OwnValues[b]

Atributos

f[x_] := 8 x

g[{a,b,c}]

SetAttributes[g, Listable]

g[{a,b,c}]

Attributes[Times]

Attributes[f]

Attributes[E]

Já vimos um pouco sobre o tema, aqui seguem mais exemplos.

printAtt[x_] := Print[x , " -> ", Attributes[x]];

printAtt[List]
printAtt[Set]
printAtt[SetDelayed]
printAtt[Table]
printAtt[Plot]
printAtt[Plus]
printAtt[Times]
printAtt[Log]
printAtt[printAtt]

Brincando com outra forma de fazer o mesmo e estendendo as funções...

Map[printAtt, {List, Set, SetDelayed, Table,Plot, Plus,Times,Log, printAtt, Map, E, π}] ;

Exceto pela função que inventamos, todas as demais possuem o atributo Protected.

Protected

?Protected

π = 2

Unprotect[π]

Pi = 2

Pi

E

EE

π

π

Unprotect[π]

π = 2

2 / π

π = Set

π[a,5]

a

Exit[]

A função Plus possui o atributo Flat.

Flat

Attributes[Plus]

? Flat

Plus[a,b]

Plus[a,Plus[b,Plus[c,d]]]
Plus[a,Plus[b,Plus[c,d]]] == Plus[a,b,c,d]

Flatten@{{a}, {a,b,f}, {d, {ff, f}}}

Logo o atributo Flat é responsável pela associatividade da adição.

SetAttributes[f, Flat]

f[x]

?f

f[x, f[u,v]]

OneIdentity

?OneIdentity

Plus[Plus[a,b]]

Plus[Plus[a,b],0]

OneIdentity pode ser interpretada como uma notação simplificada para somar zero. Em essência fornece uma notacação que eventualmente pode ser conveniente.

Orderless

Está associada à comutatividade da adição

Plus[a,b] == Plus[b,a]

SetAttributes[aux,Orderless]

aux[x,y]

Attributes[aux]

aux[x,y] == aux[y,x]

aux[y,x]

Devido a Plus ser Orderless, o Mathematica usa, ao mostrar o resultado do Plus, uma certa ordem arbitrária, porém consistente, a saber,

(x^3)+(x^5)+(x^4)+(x^2)+1+x

c+b+a+z

f[x_ + y_] := (x^2) + (y^2)

f[a+b]

f[2 + 3]

SetAttributes[f, HoldAll]

f[2 + 3]

Attributes[Plot]

Clear[x]
Plot[Evaluate@D[(x^2),x],{x,0,1}]

Map[f, {a,b,c}]

f /@ {a,b,c}

Sobre função pura.

f[x_] := 2 x + 9

g = 2 ((#)^2) + 5 # &;
h = 2 ((#1)^2) + 5 #2 &;

h[1,2]

Head[h]

list = Table[2i+j, {i,10}, {j,5}];
TableForm@list

Select[Flatten@list, EvenQ]

Range[Length[list]]

Select[#, EvenQ] & /@ list

Abaixo temos uma aplicação de função pura como argumento de Select.

Select[Flatten@list, # > 20 &]

A estrutura abaixo com dois “#” funciona, mas a leitura (por um humano) é um pouco confusa, pois o significado depende de qual dos dois “#” o Mathematica substitui os valores primeiro.

Select[#, # > 20 &] & /@ list

FullForm@Hold[Select[#, # > 20 &] & /@ list]

Uma forma de tornar a leitura mais clara (que pode ser especialmente útil em programas mais complexos), é definir uma função pura com antecedência.

f= # > 20 &;

f[2]
f[30]

Select[#, f]& /@ list

Outra forma é usando o Hold, assim exigindo que primeiro o Map (/@) seja executado e depois a função Select.

aux = Hold[Select[#, # > 20 &]] & /@ list

Agora que o Map foi executado, o Hold é liberado.

ReleaseHold[aux]

Enfatizo que para esse caso em particular, nem a definição da função f e nem o uso de Hold é essencial, dado que o Mathematica já interpreta o uso de # na ordem que desejamos (a outra ordem simplesmente não faz sentido). Essas formas com f e com Hold podem ser essenciais em outros problemas mais complexos, além de serem recomendadas para facilitar a leitura. 
É sempre bom lembrar que um bom código deve tanto realizar as operações desejadas quando deve ser claro, de forma possibilitar a fácil leitura e edição.

Segue um exemplo em que a ordem de execução dos slots (#) não é a primeira vista evidente

#^2&/@#^2&/@Range[10]

Outra ordem pode ser forçada usando parênteses

#^2&/@(#^2&/@Range[10])

Note que a primeira execução, embora esteja correta “gramaticalmente” , ou seja, sem erro de sintaxe, não faz nenhum sentido de ser escrito, pois o mesmo resultado é obtido por

#^2&/@#^2&/@ #^2&/@#^2&/@ #^2&/@#^2&/@Range[10]

#^2&/@Range[10]

Ou simplesmente

Range[10]^2

A segunda opção poderia também ser obtida por meio de

(Range[10]^2)^2

Range[10]^4