Métodos computacionais / 2019

Davi C. Rodrigues
Aula 7

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

Item 0: lembre dos novos exercícios.
Item 1: revisão dos exercícios enviados para nota.
Item 2: Exportação de dados para Python ou Fortran
Continuação do Paul Welling

Sugestão

- Desenvolva um código para calcular derivadas funcionais (pode usar em parte um pacote que o mathematica já possui, mas que não é muito completo). Em particular, o código deve conseguir calcular expressões do tipo
 
 ∫B(x)((δ (∂_x)A(x))/(δ A(y))) dx = - (∂_y)B(y)

Cap.5:  Programação funcional

Introdução

É um dos principais paradigmas de programação, sendo uma variação da forma declarativa.

Há várias visões diferentes sobre as relações entre os pardigmas de programação

Fonte: https://blog.k2datascience.com

Comentários gerais. 

Sugere-se que talvez seja mais natural para quem aborda programação com uma visão matemática-científica

Comentar sobre o Lisp

Exemplo de forma imperativa de código para inverter colunas.

lis = {{α,1}, {β,2}, {γ,3}};
temp = Table[0,{Length@lis}];
Do[temp[[i]] = {lis[[i,2]],lis[[i,1]]}, {i,1,Length@lis}];
temp

Exemplos de forma funcional...

lis[[All,{2,1}]]

Reverse /@ lis

Equivalentemente,

Map[Reverse, lis]

Fala-se menos de como o computador realiza passo a passo.
Note ainda a ausência de “efeito colateral” / “side effects”. 
No exemplo acima, o “temp” muda o contexto.
Note que isso sempre pode ser evitado definindo módulos / blocos adequadamente, mas há uma diferança de ênfase com respeito aos efeitos colaterais entre os paradigmas imperativos contra os declarativos.

Na forma imperativa

temp

5.2 Funções para manipular expressões

Três dos principais exemplos são Map, Apply e Thread

Map

Map[Head, {3, 22/7, π, a, 3.14159, Range[10], Plot[x,{x,1,10}]}]

Head /@ {3, 22/7, π, a, 3.14159, Range[10], Plot[x,{x,1,10}]}

Apply

Apply[h, g[a,b,c]]
h@@g[a,b,c]

Apply, como também vimos, substitui a Cabeça/Head.

O mesmo resultado pode ser atingido com ReplaceAll, porém de forma menos econômica,

g[a,b,c] /. g-> h

Apply[h, g[a[d[z]],b[e],c],0]
Apply[h, g[a[d[z]],b[e],c],1]
Apply[h, g[a[d[z]],b[e],c],2]

Apply[h, g[a[d[z]],b[e],c],{0}]
Apply[h, g[a[d[z]],b[e],c],{1}]
Apply[h, g[a[d[z]],b[e],c],{2}]

Uma forma simples de gerar uma sequência a partir de uma lista é

Sequence@@{a,b,c}

Um exemplo que pode parecer complicado num primeiro momento...

Sequence@@{{i,3},{j,4}}

f[x_] = 2;
f[List[1,2]]

Table[i^j,##]& @@ffff[{i,3},{j,4}]

Table[i^j,{i,3},{j,4}]

h@@@{{a1,a2,a3},{b1,b2,b3},c}

Apply[h,{{a1,a2,a3},{b1,b2,b3},c},1]

Thread & MapThread

Thread[g[{a,b,c},{x,y,z}, {h,j,k}]]

Thread[g[{a,b,c},{x,y,z}]]

MapThread[g,{{a,b,c},{x,y,z}}]

Equivalentemente, com maior verborragia...

Transpose@{{a,b,c},{x,y,z}}

g@@@({{a,b,c},{x,y,z}}\[Transpose])

{a,b,c} =={e,f,g}
FullForm@%

Thread[Equal[{a,b,c} ,{e,f,g}]]

Outros menos frequentes: Outer & Inner

?Outer

? Inner

Outer[f,{a1,a2,a3}, {b1,b2,b3}]

Outer[Times,{a1,a2,a3}, {b1,b2}] // TableForm

Inner[f,{a1,a2,a3}, {b1,b2,b3},g]

Inner[Times,{a1,a2,a3}, {b1,b2,b3},Plus]

{a1,a2,a3}. {b1,b2,b3}

fibonacci[n_] :=

f[0] = 0;
f[1]=1;
f[n_]:= f[n-1] + f[n-2]/; n≥ 2

f[7]

Nest[# +1 & ,1,5]

fib[0]=0;
fib[1] = 1;
fib[n_] :=

Cle

Fibonacci[4]

Fibonacci[6]

5.3 Iterating functions

Nest[g,a,4]

g[a_] := a-1

factor[n_] :=Times@@NestList[g,n,n-1]

factor[3]

Fold[f,x,{a,b,c}]

Construções com escopo local

Definindo uma função como uma sequência de outras funções.

É imediato definir uma função que é uma composição de outras, por exemplo

Clear[f]
f[θ_] = Abs[Cos[(θ^2)]];
TreeForm[f[θ]]

Eventualmente é conveninte que uma única função seja associada a várlias linhas de comando. Há várias forma de fazer isso, por exemplo

int[x_?NumberQ] := NIntegrate[((BesselJ[1,a])/(Sqrt[Abs[1 - a]]))((BesselJ[0,(Sqrt[a])])^3)(a^5), {a,0, x}, MaxRecursion->50, PrecisionGoal -> 5, WorkingPrecision -> 40, AccuracyGoal -> ∞] ; (*Coloquei uma função oscilatória qualquer isso não representa nada fisicamente que eu saiba...*)

int[g]

int[1] // AbsoluteTiming

Sin[1.] // AbsoluteTiming

Como encontrar uma estimativa  do tempo médio de cada uma dessas integrais no intervalo de (10^(-5)) até (10^5)?

AbsoluteTiming[int[10]]

Attributes[Power]

(10^(Sort[RandomReal[{-5,5}, 20]]))

(tempSol = AbsoluteTiming[int[#]]& /@ (10^(Sort[RandomReal[{-5,5}, 20]]))) // AbsoluteTiming



Mean[tempSol[[All,1]]]
Median[tempSol[[All,1]]]

{ListPlot[tempSol[[All,1]], PlotRange-> All], ListLogPlot[tempSol[[All,2]], PlotRange -> All]}

Off[NIntegrate::slwcon]

AbsoluteTiming[data1 = Table[{x,int[x]},{x,0.1,5,1/30}]; ]

AbsoluteTiming[data2 = {#,int[#]} & /@ (10^(RandomReal[{-5,5}, 50])); ]

data = Sort[Join[data1,data2]];

ListLogPlot[data]
ListLogPlot[data, PlotRange -> All]

data[[1]]
Dimensions[data]

intI = Interpolation[data, InterpolationOrder ->3]

ListPlot[data, PlotRange -> {{0,5}, Automatic}]

Plot[intI[x], {x,-0.1,5}, PlotPoints -> 10000, MaxRecursion->15]

intI[-0.2]

intI = Interpolation[data, Method -> "Spline"]

intI[-100000]

Show[{ListLogLogPlot[data, PlotRange -> {{0.1,0.5}, Automatic}], LogLogPlot[intI[x], {x,0,5}, PlotStyle->Red]}]

Plot[intI''[x], {x,0,5}, PlotStyle->Red]

Export["datatest.csv", data]

Dimensions@data

DumpSave["datatest.mx",data];

int[1] // AbsoluteTiming
intI[1] // AbsoluteTiming

Plot[1 - int[x]/intI[x], {x,0.1,5}, PlotPoints -> 10, MaxRecursion->4, PlotRange -> All]

Show[LogPlot[intI[x],{x,0,5}, PlotRange-> All], ListLogPlot[data]]

f[x_] := 
(Print[x]; 
Plot[a,{a,0,x}])

f[2]

Imagine agora que queremos uma função que faça todos esses procedimentos de uma vez, tendo como resultado a função interpolada e podendo ou não exportar a tabela de dados.

Exercício: Definia a função  interpol[integral, lista de pontos, método de interpolação, export?]

Table[i,{i,{1,5,78,3}}]

interpol[integral_, lista_, metodo_, export_] := (
data = Table[{x,integral[x]}, {x, lista}];
If[export == 1, Export["datatest.csv", data]];
integralI = Interpolation[data, Method -> metodo]
)

interpol

interpol[int, Table[i,{i,0,5,1/20}], Spline, 1]

integralI[4]

Plot[integralI[x],{x,0,5}]

Aparte sobre interpolação

Show[Plot[intI[x],{x,0.1,5}, PlotStyle->Red], ListPlot[data]]

Show[Plot[intI[x],{x,1,2} , PlotStyle->Red], ListPlot[data]]

Plot[1 - ((intI[x])/(int[x])), {x,0.1,5}, PlotPoints -> 20, MaxRecursion->2, PlotRange -> #] & /@ {Automatic, All}

Plot[1 - ((intI[x])/(int[x])), {x,10,100}, PlotPoints -> 20, MaxRecursion->2]

Plot[1 - ((intI[x])/(int[x])), {x,4.5,5.5}, PlotPoints -> 20, MaxRecursion->2]

Plot[intI'''[x],{x,1,2} , PlotStyle->Red, PlotRange -> All]

intI2 = Interpolation[data, InterpolationOrder->20]

Plot[intI2[x],{x,0.1,5}]

Show[Plot[{intI[x], intI2[x]},{x,1,5} , PlotStyle->Red], ListPlot[data]]

Plot[1 - ((intI[x])/(intI2[x])), {x,0.2,5}, PlotRange -> #, ImageSize-> Medium] & /@ {Automatic, All}