introdução à linguagem de programação julia: a … · scientific computation, also known as...

21
Capítulo 4 Introdução à linguagem de programação Julia: A ambiciosa linguagem de programação que quer substituir Python, R e Matlab. João Marcello Pereira Abstract Scientific computation, also known as computational science, is the field of knowledge for the construction of mathematical models and techniques of numerical solutions using software and hardware to analyze and solve scientific problems. The Julia programming language is an opensource alternative to MATLAB®, Maple®, Fortran, R and Python, focused on teaching numerical and symbolic programming, and scientific research. Based on several other languages, Julia has JIT compilation (just in time) is designed for parallel and distributed computing, is IDE free choice, has integration with C, Fortran and Python, as well as practical package development and management by GIT. Resumo A computação científica, também conhecida como ciência computacional, é o campo do saber destinado à construção de modelos matemáticos e técnicas de soluções numéricas utilizando softwares e hardwares para analisar e resolver problemas científicos. A linguagem de programação Julia é uma alternativa opensource ao MATLAB ® , Maple ®, Fortran, R e Python, focado no ensino de programação numérica e simbólica, e pesquisa científica. Baseada em várias outras linguagens, Julia apresenta compilação JIT (just in time) é projetado para computação paralela e distribuída, é de livre escolha de IDE, possui integração com C, Fortran e Python, além de desenvolvimento de pacotes de forma prática e gerenciamento via GIT. III Escola Regional de Informática do Piauí. Livro Anais - Artigos e Minicursos, v. 1, n. 1, p. 315-335, jun, 2017. www.eripi.com.br/2017 - ISBN: 978-85-7669-395-6

Upload: hadan

Post on 25-Sep-2018

212 views

Category:

Documents


0 download

TRANSCRIPT

Capítulo

4

Introdução à linguagem de programação Julia: A ambiciosa linguagem de programação que quer substituir Python, R e Matlab.

João Marcello Pereira

Abstract

Scientific computation, also known as computational science, is the field of knowledge for the construction of mathematical models and techniques of numerical solutions using software and hardware to analyze and solve scientific problems. The Julia programming language is an opensource alternative to MATLAB®, Maple®, Fortran, R and Python, focused on teaching numerical and symbolic programming, and scientific research. Based on several other languages, Julia has JIT compilation (just in time) is designed for parallel and distributed computing, is IDE free choice, has integration with C, Fortran and Python, as well as practical package development and management by GIT.

Resumo

A computação científica, também conhecida como ciência computacional, é o campo do saber destinado à construção de modelos matemáticos e técnicas de soluções numéricas utilizando softwares e hardwares para analisar e resolver problemas científicos. A linguagem de programação Julia é uma alternativa opensource ao MATLAB®, Maple®,

Fortran, R e Python, focado no ensino de programação numérica e simbólica, e pesquisa científica. Baseada em várias outras linguagens, Julia apresenta compilação JIT (just in time) é projetado para computação paralela e distribuída, é de livre escolha de IDE, possui integração com C, Fortran e Python, além de desenvolvimento de pacotes de forma prática e gerenciamento via GIT.

III Escola Regional de Informática do Piauí. Livro Anais - Artigos e Minicursos, v. 1, n. 1, p. 315-335, jun, 2017.www.eripi.com.br/2017 - ISBN: 978-85-7669-395-6

4.1. Introdução

A análise numérica permite que inúmeros problemas matemáticos, cujas soluções algébricas são difíceis, ou até mesmo impossíveis de se encontrar, possam ser resolvidos por meio de métodos numéricos apropriados [Sperandio; Mendes; Silva, 2003]. Dessa forma, diversos softwares e linguagens de programação foram desenvolvidos com o intuito de resolver problemas numéricos, sendo aplicados, principalmente, em pesquisas e no ensino das disciplinas de cálculo e métodos numéricos. Entre esses, o MATLAB® é a mais expressiva plataforma (linguagem e ambiente de programação) de programação numérica e simbólica utilizada nas instituições de ensino e nas indústrias. Embora seja muito popular no ambiente acadêmico, o MATLAB® é uma plataforma fechada de alto custo de aquisição, além de exigir computadores acima do padrão básico do mercado brasileiro. Neste ponto, há diversas alternativas de código aberto como Python, R, Fortran. Julia surgiu nesse cenário com a proposta ousada de substituir várias linguagens voltadas para computação científica. Conforme as palavras dos criadores, Bezanson et al. (2015):

“Queremos uma linguagem de código aberto, com uma licença liberal. Queremos a velocidade de C com o dinamismo de Ruby. Queremos uma linguagem que seja homoicônica, com macros verdadeiros como Lisp, mas com notação matemática óbvia e familiar como Matlab. Queremos algo tão útil para programação geral como Python, tão fácil para estatísticas como R, como natural para processamento de strings como Perl, tão poderoso para álgebra linear como Matlab, tão bom e adaptável como programas juntos em shell. Algo simples de aprender, mas que ainda satisfaça os hackers mais sérios. Queremos que ele interativo e queremos compilado.

(Será que mencionamos que deve ser tão rápido quanto C?)”

Os esforços dos desenvolvedores em projetar uma linguagem de alto desempenho podem ser observados nos resultados de um benchmark entre várias linguagens disponível no site oficial da linguagem Julia. O benchmark consiste na execução de vários códigos em um único núcleo (execução serial) de um processador Intel® Xeon® CPU E7-8850 2.00GHz com 1TB de memória RAM DDR3 de 1067MHz e sistema operacional Linux.

Tabela 4.1. Tempo de processamento relativo ao temp o de C (Quanto menor, melhor. Performance de C = 1)

Conforme dos dados apresentados, Julia apresenta um potencial significativo, principalmente em função de uma linguagem que ainda não chegou à sua versão 1.0.

Algoritmos Fortran

(gcc 5.4.1)

Julia

(0.4.0)

Python

(3.4.3)

R

(3.2.2)

Matlab

(R2015b)

Octave

(4.0.0)

Mathematica

(10.2.0)

JavaScript

(V8 3.28.74.19)

Go

(go4.5)

LuaJIT

(gsl-shell 2.3.1)

Java

(4.8.0_45)

fibonacci 0.70 2.11 77.76 533.52 26.89 9324.35 118.53 3.36 4.86 4.71 4.21

parse_int 5.05 4.45 17.02 45.73 802.52 9584.44 15.02 6.06 4.20 5.77 3.35

quicksort 4.31 4.15 32.89 264.54 4.92 1866.01 43.23 2.70 4.29 2.03 2.60

mandel 0.81 0.79 15.32 53.16 7.58 454.81 5.13 0.66 4.11 0.67 4.35

pi_sum 4.00 4.00 24.99 9.56 4.00 299.31 4.69 4.01 4.00 4.00 4.00

rand_mat_stat 4.45 4.66 17.93 14.56 14.52 30.93 5.95 2.30 2.96 3.27 3.92

rand_mat_mul 3.48 4.02 4.14 4.57 4.12 4.12 4.30 15.07 4.42 4.16 2.36

4.2. Linguagem de programação Julia

Julia é uma linguagem de programação compilada (JIT – Just In Time) open source de alto nível, projetada com foco na computação científica e numérica de alto desempenho [Bezanson et al. 2015]. É relativamente jovem, posto que teve início no MIT em agosto de 2009 e, em fevereiro de 2012, tornou-se open source. É fruto do trabalho de quatro pesquisadores: Stefan Karpinski, Jeff Bezanson, Alan Edelman e Viral Shah [Bezanson et al. 2015]. A linguagem Julia foi pensada como uma linguagem para computação científica suficientemente rápida, tal como as linguagens C e Fortran, mas igualmente fácil de aprender como o MATLAB® e o Mathematica®, com o objetivo de facilitar a modelagem computacional. É escrito em C, C++ e Scheme, e a biblioteca padrão é escrita utilizando a própria linguagem. Possui forte inspiração em MATLAB®, Lisp, C, Fortran, Mathematica®, Python, Perl, R, Ruby, Lua, além de compartilhar muitas características de Dylan e Fortress. A versão estável atual de Julia é v0.5.2 lançada em 10 de maio de 2017. O site oficial (http://julialang.org), lista abaixo como os recursos principais da linguagem:

• Sintaxe intuitiva e semelhante ao MATLAB®

• Despacho múltiplo: permite definir diferentes comportamentos para uma mesma função a partir de diferentes combinações dos tipos de seus argumentos;

• Sistema de tipos dinâmico: tipos para documentação, otimização e despacho;

• Bom desempenho, aproximando-se de linguagens compiladas estaticamente como C;

• Gerenciador de pacotes embutido;

• Macros similares a Lisp e outras funcionalidades de metaprogramação;

• Chamadas para funções de bibliotecas Python por meio do pacote PyCall.jl;

• Chamadas para funções de bibliotecas C diretamente sem necessidade de wrappers ou APIs especiais;

• Projetado para paralelismo e computação distribuída;

• Tipos definidos pelo usuário são tão rápidos e compactos quanto os tipos nativos da linguagem;

• Geração automática de código especializado e eficiente para diferentes tipos de argumentos;

• Conversões e promoções elegantes e extensíveis para tipos numéricos e demais tipos;

• Suporte eficiente para Unicode;

• Licença MIT.

A compilação just-in-time (JIT) baseado em LLVM de Julia, combinado com seu design, permite que a linguagem se equipare à performance da linguagem C em vários cenários. Neste ponto, a compilação Just-in-Time é descrito por Sengupta (2015) como:

A compilação Just-in-Time é uma técnica na qual o código escrito em uma linguagem de alto nível é convertido em código de máquina para execução na CPU em tempo de execução. Isso contrasta com as linguagens interpretadas, que executam o código diretamente em tempo de execução. Isso geralmente tem uma sobrecarga significativamente maior.

O processo de compilação na linguagem Julia é descrito por Balbaert (2015) da seguinte forma:

Na primeira vez em que é executada uma função na linguagem Julia, ela é analisada e os tipos são inferidos. Em seguida, o código LLVM é gerado pelo compilador JIT, que é otimizado e compilado para código nativo. Na segunda vez em que é executada novamente a mesma função Julia, o código nativo, já gerado, é chamado. Esta é a razão pela qual, na segunda vez em que é chamada uma função com argumentos de um tipo específico, o tempo de execução é bem menor que na primeira vez.

Feito as considerações iniciais sobre a linguagem, os tópicos seguintes são referentes aos comandos básicos, interface, instalação, tipos de dados, cotrole de fluxo, escopo, gerenciamento de pacotes, matemática simbólica, gráficos e dataframes.

4.3. Começando com o Julia

A maneira mais fácil de "testar" a linguagem de programação Julia é através do JuliaBox (juliabox.com). JuliaBox é um ambiente de programação com interface web Jupyter hospedado na nuvem do Google para codificação em linguagem Julia sem a necessidade de instalar qualquer software na máquina local. O Jupyter é uma aplicação web derivado do IPython que é um interpretador de comandos interativo para várias linguagens de programação. A interface Jupyter oferece type introspection, rich media, sintax shell, suporte para mais de 40 linguagens de programação, incluindo as mais populares em computação científica como Python, R, Julia e Scala. Além disto, permite realizar o download do código em outros formatos (.pdf, .md, .rst, .html e .tex), gerar apresentação de slides, permite escrita de texto científicos em latex e markdown, importação/exportação de projetos para o github e muitas outras funcionalidades. JuliaBox disponibiliza algumas recursos interessantes para cada usuário:

• Permite executar um terminal bash Linux que pode ser usado para executar o Julia REPL;

• Transferência de arquivos para o contêiner de uma sessão;

• Sincronização de arquivos com o Google Drive e Github;

• Extensível com plugins;

• 500 MB de espaço em disco;

• 6 GB de memória RAM;

• 4 CPUs (16 cores) Xeon(R) CPU 2.60GHz;

• Ubuntu 14.04.5 LTS;

• Interface web Jupyter;

• E muito mais.

O JuliaBox não é um ambiente ideal para simulações e benchmark, a proposta é dos desenvolvedores é fornecer um ambiente de codificação prática e portável. São

permitas apenas 3h de uso contínuo, após isto, ocorrerá lougout e um novo login será necessário.

Figura 4.1. Interface inicial do JuliaBox.

Figure 4.2. Pastas e arquivos no formato “ipynb”.

Figura 4.3. Interface Jupyter do JuliaBox

Outra forma de utilizar Julia é instalando na máquina local de acordo com o sistema operacional:

• Windows

Baixe o executável de acordo do com a arquitetura do computador no endereço https://julialang.org/downloads/ e execute o processo de instalação clicando no executável e seguindo as informações do instalador.

• Linux

Ubuntu e derivados (Mint/Kubuntu)

#ferramentas de compilação

:~$ sudo apt-get update

:~$ sudo apt-get install build-essential

#Instalação Julia

:~$ sudo add-apt-repository ppa:staticfloat/juliareleases

:~$ sudo add-apt-repository ppa:staticfloat/julia-deps

:~$ sudo apt-get update && sudo apt-get install julia

Artch e derivados (Manjaro/Artegos)

#ferramentas de compilação

:~$ sudo pacman -Sy base-devel && sudo pacman -Syu

#Instalação Julia

:~$ sudo pacman –S Julia

RedHat e derivados (Fedora/Scientific/CentOS)

#ferramentas de compilação

:~$ sudo dnf groupinstall "Development Tools and Libraries" ou "Ferramentas de Desenvolvimento C e Bibliotecas"

#Instalação Julia

:~$ sudo dnf copr enable nalimilan/julia

:~$ sudo yum install julia

Binários

Basta baixar os binários do site (https://julialang.org/downloads/), extrair para um diretório e executar o binário “Julia” dentro da pasta “bin” na forma:

:~$ ./Julia

4.4. Comandos Básicos

Os comandos em Julia apresentam sintaxe muito semelhante à sintaxe dos comandos em MATLAB ®. Vejamos alguns pontos interessantes:

• Ponto e vírgula ao final do comando oculta o resultado;

• Comentários são na forma de #;

• O ponto antes de um operador matemático indica operação elemento-elemento em um array (ex: ./, .^);

• 4.0 (float) e 1 (inteiro) são diferentes;

• Informação do tipo: variable::Bool significa que a variável é do tipo booleano;

• Todos os pacotes são escritos usando a primeira letra maiúscula entre aspas duplas;

• Julia é Case-Sensitive F e f são diferentes;

• Funções e comandos de controle de fluxo (if, for, while...) necessita de "end" para terminar o bloco;

• Macros são iniciados por "@";

• O comando de ajuda é ? comando/função;

Alguns comandos básicos:

4.5. Tipos Básicos

Em Julia existem basicamente dois tipos: tipos abstratos e tipos concretos. Um tipo abstrato é caracterizado por não ser instanciado, servindo apenas para a construção de outros tipos. Já os tipos concretos podem ser instanciados, mas não podem ter subtipos. A árvore de tipo (Figura 4.4) em Julia possui mais de 500 tipos! Apesar de enorme é útil, pois permite a construção de código generalizado, em vez de restringi-lo a um único tipo.

Figura 4.4. Interface Jupyter do JuliaBox [Larsson, 2017]

Exemplo de algumas estruturas com tipos básicos:

4.6. Gerenciamento de pacotes

A Julia tem um gerenciador de pacotes embutido escrito na própria linguagem assim como também grande parte da sua biblioteca padrão. Os pacotes adicionais (registrados ou mantido por usuários) são disponibilizados no GitHub (github.com) e a lista oficial (1385 pacotes registrados) está disponível em http://pkg.julialang.org.

Os pacotes desenvolvidos para a linguagem Julia estão sempre sendo atualizados, logo, é importante atualizar a base de pacotes instalados. O processo de instalação (do repositório oficial) e remoção de pacotes utiliza somente dois comandos: Pkg.add(“NomePacote”) e Pkg.rm(“NomePacote”).

4.7. Controle de fluxo

Nas linguagens de programação, uma estrutura de controle (ou fluxo de controle) possui relação com a ordem em que estruturas lógicas são executadas ou avaliadas em um código computacional. Em Julia, assim com outras linguagens, temos as estruturas condicionais e estruturas de repetição.

• Estrutura Condicional

A avaliação condicional na linguagem Julia permite que partes de código sejam avaliados ou não dependendo do valor de uma expressão booleana. Dessa forma uma estrutura condicional é útil para implementar situações no qual requer a execução de ações alternativas que dependem de certas condições quando avaliadas. Código:

Não existe implementada uma estrutura “Case” em Julia, a saída é utilizar o pacote Match.jl como alternativa.

• Estruturas de Repetição

Estruturas de repetição, que permitem executar mais de uma vez um mesmo trecho de código. Julia possui as seguintes estruturas de repetição: loop while, for e do.

4.8. Funções

Na linguagem Julia, uma função é um objeto que mapeia uma tupla de valores de argumentos de entrada e produz um ou vários valores de retorno. De acordo com o manual oficial (versão 0.5), as funções de Julia não são funções matemáticas puras, no sentido de que as funções podem alterar e ser afetadas pelo estado global do programa. No entanto podemos utilizar (principalmente a forma reduzida da função genérica) as funções em Julia de forma bem próximas do conceito matemático de acordo com as duas formas: função genérica e função anônima. Cada uma possui vantagens e desvantagens quanto ao desempenho e sintaxe. Em geral a mais utilizada é a função genérica. Qualquer função pode ser aplicada elemento-elemento a qualquer array (ou outra coleção) com a sintaxe função.(Array).

O multiple dispatch ou Despacho múltiplo é uma das características mais importantes de Julia e um grande diferencial em relação a outras linguagens para computação científica. As funções em Julia podem ter vários métodos definidos e o comportamento da execução depende dos argumentos que são passados. Quando uma função é chamada, Julia fará uma pesquisa na sua vtable (tabela de métodos virtual) em tempo de execução para descobrir qual método correto deve ser chamado com base nos tipos de todos os seus argumentos; Este é o mecanismo de Julia de despacho múltiplo, que nem Python, nem C++ ou Fortran implementam [Balbaert, 2015].

• Função Genérica

As funções genéricas possuem este nome porque estão prontas para trabalhar com diferentes tipos de dados. A construção de funções é feita na forma de blocos ou reduzida (estrutura semelhante a uma definição matemática).

Para realizar o cálculo com arrays, basta usar o “.” entre o nome da função e array:

As funções podem ser escritas em um arquivo “.jl” e importadas para o ambiente de programação. No exemplo abaixo, a função fibonacci recursiva foi salva no arquivo “ fiboR.jl” e importada pelo comando include(). Outra possibilidade é gravar várias funções em um único arquivo e importa-las com o mesmo comando.

Exemplo de Despacho múltiplo

• Função Anônima

Funções anônimas não têm um nome para serem invocadas diretamente, mas são muito usadas como parâmetros para outras funções, ou são atribuídas a uma variável, que acaba funcionando como um nome [Balduino, 2012]. Um exemplo clássico de uso de uma função anônima ocorre combinado com a função map(), no qual esta aplica cada valor de um array a uma função anônima e retorna um novo array contendo os valores resultantes. Outra aplicação é quando uma função precisa ser redefinida várias vezes. Ao definir uma função anônima em Julia, devemos observar que o resultado é uma função genérica, mas com um nome gerado pelo compilador na forma (::#a)(generic function with b method). Os caracteres #a representam o número gerado pelo compilador baseado em numeração consecutiva e b o número de métodos.

Para realizar o cálculo com arrays, basta usar o “.” entre a função e array:

4.9. Escopo

O escopo de uma variável é a região dentro do código no qual uma variável está visível. O objetivo do escopo de variáveis em linguagens de programação é bem claro: evitar conflitos de nomeação de variáveis. Na linguagem Julia existem dois tipos principais de escopos denominados escopo global e escopo local (Soft ou Hard), sendo que este último pode ser aninhado.

• Global

Em Julia as variáveis globais que são acessíveis de qualquer lugar do programa e uma variável global declarada como const pode alterar seu valor (um aviso é informado na tela) conforme a conveniência. Código:

• Soft Local

Um escopo local geralmente herda todas as variáveis de seu escopo principal, tanto para leitura e escrita. Em um escopo soft local, todas as variáveis são herdadas de seu escopo principal, a menos que uma variável seja especificamente marcada com a palavra chave local.

• Hard Local

Escopo hard local é determinado principalmente por funções (em todas as suas formas) e macro. Em um escopo hard local, todas as variáveis são herdadas de seu escopo principal.

4.10. Matemática simbólica

A abordagem simbólica é de domínio dos sistemas de álgebra computacional (CAS), trabalhado através de programas muito abrangentes como o Mathematica®, o Maple® e o Maxima. Julia usa o pacote SymPy do Python via pacote Pycall.jl para realizar cálculos de matemática simbólica. Dessa forma, é possível integrar e diferenciar funções simbolicamente, resolver grande parte das EDOs lineares de segunda ordem, realizar simplificação de expressões, além de muitas outras manipulações simbólicas.

4.11. Gráficos

É possível utilizar diversos pacotes gráficos com Julia. Alguns pacotes disponíveis no repositório oficial: PyPlot.jl, PlotlyJS.jl, GR.jl e GadFly.jl. PyPlot.jl permite plotar diferentes tipos de gráficos 2D e 3D. Utiliza o pacote

PyCall.jl para chamar o matplotlib do Python diretamente do código em Julia. Uma das

vantagens do pacote PyPlot.jl é a quantidade de opções de gráficos e configuração de

visualização.

GR.jl é um pacote que fornece uma interface de Julia para GR no qual oferece

aos desenvolvedores uma compacta e consistente biblioteca gráfica 2D e 3D para seus

programas baseado em OpenGL.

GadFly.jl é um pacote para plotar e visualizar somente gráficos 2D totalmente

escrito em Julia. Baseia-se em grande parte nos trabalhos de Hadley Wickhams e Leland

Wilkinson. Foi criado por Daniel C. Jones e atualmente é mantida pela comunidade.

GadFly.jl gera gráficos muito bonitos e apresenta várias opções de visualização,

incluindo uma prática barra de zoom.

PlotlyJS.jl é uma interface para a biblioteca desenvolvida em javascript Plotly.js

que permite criar gráficos interativos de alta qualidade visual.

Plots.jl é um conjunto de ferramentas para construção e visualização de gráficos

2D e 3D. Diferente dos outros pacotes gráficos, Plots cria uma interface para um

backends gráfico, ou seja, para um pacote (PyPlot, GR, PlotlyJS e outros) responsável

por gerar o gráfico. Uma grande vantagem do pacote Plots.jl é que um mesmo conjunto

de comandos pode ser utilizado para vários backends, eliminando assim a necessidade e

aprender vários comandos diferentes para cada pacote gráfico.

4.12. DataFrames

Data frames são objetos usados para guardar dados na forma de tabelas. Um data frame possui colunas nomeadas, sendo que todas as colunas possuem a mesma quantidade de linhas. É uma ótima forma de visualizar informações, pois além de manter uma boa formatação dos dados, ainda permite que sejam gravados em arquivos do tipo CSV ou XLS, que podem ser abertos e manipulados em softwares de planilha como o excel (Microsoft®) ou calc (LibreOffice). DataFrames.jl é um dos pacotes disponíveis para trabalhar com dados tabulares na linguagem Julia.

Referências

Balbaert, Ivo et al (2015). “Getting Started With Julia Programming”. Birmingham, Packt Publishing.,p.30-35

Baldoino, Plínio. (2012)“Dominando JavaScript com jQuery”, São Paulo, Casa do Código., p.31-32

Larsson, Olle et al (2017). “A brief overview of Julia the programming language”. https://www8.cs.umu.se/kurser/5DV086/VT17/. Maio.

Sengupta, Avik (2016).“Julia High Performanc”. Birmingham, Packt Publishing., p.1-5.

Sherrington, Malcolm (2015). “Mastering Julia”. Birmingham, Packt Publishing., p.120-122

Sperandio, D.; Mendes, J. T; Silva, L. H (2003). “Cálculo numérico – Características matemáticas e computacionais dos métodos numéricos”. São Paulo, Pearson., p.15