Você está na página 1de 21

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

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.
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 tempo de C (Quanto menor, melhor.
Performance de C = 1)

Algoritmos Fortran Julia Python R Matlab Octave Mathematica JavaScript Go LuaJIT Java
(gcc (0.4.0) (3.4.3) (3.2.2) (R2015b) (4.0.0) (10.2.0) (V8 (go4.5) (gsl- (4.8.0_45
5.4.1) 3.28.74.19) shell )
2.3.1)

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

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