Utilizo o MATLAB há mais de 25 anos. (E antes disso, eu até usei MATRIXx, uma tentativa tardia, sem lamento, de espinafre, ou talvez um ripoff). Não é a primeira língua em que aprendi a programar, mas é aquela com a qual eu amadureci matematicamente. Conhecer MATLAB tem sido muito bom para a minha carreira.
No entanto, é impossível ignorar a ascensão do Python na computação científica. Os MathWorks devem sentir o mesmo: não só adicionaram a capacidade de chamar Python diretamente de dentro do MATLAB, mas adotaram algumas de suas características de linguagem, como a transmissão mais agressiva para operandos de operadores binários.
Chegou a um ponto em que tenho questionado meu uso contínuo do MATLAB tanto na pesquisa quanto no ensino. No entanto, tanta coisa vem facilmente para mim lá, e eu tenho investido tanto em materiais para isso, que foi difícil reunir motivação para realmente aprender algo novo.
Introduzir o livro de texto baseado no MATLAB que eu co-escrevi para matemática computacional introdutória. O livro tem mais de 40 funções e 160 exemplos computacionais, e cobre o que eu acho que é uma base completa no uso do MATLAB para computação científica numérica. Assim, em parte como auto-aperfeiçoamento, e em parte para aumentar a utilidade do livro, eu parti este ano para traduzir os códigos para Julia e Python. Esta experiência me levou a uma perspectiva particular sobre as três linguagens em relação à computação científica, que eu tento capturar abaixo.
I colocará a maior parte das vezes de lado as questões de custo e abertura. MATLAB, ao contrário de Python e Julia, não é nem livre de cerveja nem de fala. Esta é de facto uma grande distinção – para alguns, uma disposição – mas eu quero considerar os méritos técnicos. Por muitos anos, MATLAB foi muito além de qualquer produto gratuito em uma série de maneiras altamente úteis, e se você quisesse ser produtivo, então o custo seria amaldiçoado. É uma consideração separada do apelo platônico de uma língua e ecossistema.
Quando você coloca o custo de lado, um quadro útil para muitas das diferenças entre essas línguas reside em suas origens. MATLAB, o mais antigo dos esforços, priorizou a matemática, particularmente a matemática orientada numericamente. Python, que começou a sério no final dos anos 80, fez da informática o seu foco central. Júlia, que começou em 2009, se propôs a atingir um maior equilíbrio entre estes lados.
MATLAB
Originalmente, cada valor em MATLAB era um conjunto de números de pontos flutuantes de dupla precisão. Ambos os aspectos desta escolha, matrizes e ponto flutuante, foram decisões de design inspiradas.
O padrão IEEE 754 para ponto flutuante não foi adotado até 1985, e a memória foi medida em K, não G. Duplos de ponto flutuante não eram a forma mais eficiente de representar personagens ou inteiros, mas eram o que cientistas, engenheiros e, cada vez mais, matemáticos queriam usar a maior parte do tempo. Além disso, as variáveis não tinham que ser declaradas e a memória não tinha que ser explicitamente alocada. Deixar o computador lidar com essas tarefas, e tirar os tipos de dados do caminho, liberou seu cérebro para pensar nos algoritmos que operariam nos dados.
Arrays eram importantes porque os algoritmos numéricos em álgebra linear estavam vindo para o seu próprio, na forma de LINPACK e EISPACK. Mas acessá-los com o portador padrão em computação científica, FORTRAN 77, foi um processo de múltiplas etapas que envolveu a declaração de variáveis, a chamada de rotinas criptografadas, a compilação de código e, em seguida, o exame de dados e arquivos de saída. Escrever uma multiplicação matricial como A*B
e obter a resposta impressa imediatamente foi uma mudança de jogo.
MATLAB também tornou os gráficos fáceis e muito mais acessíveis. Nenhuma biblioteca específica para máquinas com chamadas de baixo nível, apenas plot(x,y)
e você viu praticamente o que qualquer outra pessoa com MATLAB iria ver. Havia mais inovações, como números complexos cozidos, matrizes esparsas, ferramentas para construir interfaces gráficas de usuário entre plataformas, e um conjunto de solvers ODE de ponta, que fizeram do MATLAB o lugar para fazer computação científica à velocidade do pensamento.
No entanto, o design ideal para computações interativas, mesmo longas, nem sempre foi propício à escrita de software bom e performante. A movimentação de dados entre muitas funções exigia malabarismos com muitas variáveis e consulta frequente de documentação sobre argumentos de entrada e saída. Uma função por arquivo em disco em um namespace plano era refrescantemente simples para um projeto pequeno, mas uma dor de cabeça para um projeto grande. Certos padrões de programação (vetorização, pré-alocação de memória) tinham que ser aplicados se você quisesse evitar gargalos de velocidade. A computação científica estava agora sendo aplicada a muito mais domínios, com vastas quantidades de diferentes tipos de dados nativos. Etc.
MathWorks respondeu continuando a inovar dentro do MATLAB: funções em linha, funções aninhadas, fechamentos de variáveis, numerosos tipos de dados, características orientadas a objetos, frameworks de teste de unidades, e assim por diante. Cada inovação foi provavelmente a solução para um problema importante. Mas o acúmulo de 40 anos dessas mudanças teve o efeito colateral de desgastar a simplicidade e a unidade de conceito. Em 2009 escrevi um livro que cobriu muito bem o que considerei essencial do MATLAB em menos de 100 páginas. Tanto quanto eu sei, todas essas coisas ainda estão disponíveis. Mas você precisa saber muito mais agora para se chamar de proficiente.
Python
Em certo sentido a história de Python parece ser quase uma imagem espelho da MATLAB. Ambos apresentavam uma linha de comando interativa (agora amplamente chamada de REPL, para “read-eval-print loop”) e liberdade de declarações e compilação de variáveis. Mas o MATLAB foi criado como um playground para analistas numéricos, enquanto o Python foi criado com hackers em mente. Cada um cresceu em direção ao outro público através de revisões e extensões.
A meu ver, Python ainda carece de apelo matemático. Você tem fealdade e pequenos aborrecimentos como **
ao invés de ^
, @
para multiplicação de matrizes (uma inovação recente!), um shape
ao invés do tamanho de uma matriz, armazenamento orientado a linhas, etc. Se você acredita que V.conj().T@D**3@V
é uma maneira elegante de escrever $V^*D^3V$, então você pode precisar consultar um médico. E há a indexação zero (em oposição aos índices que começam em 1). Eu li os argumentos, e não os acho decisivos. É claramente uma questão de preferência – o material das guerras santas online – porque você pode citar exemplos pouco convincentes para qualquer uma das convenções. O que eu acho decisivo é que temos décadas de prática matemática indexando vetores e matrizes de um, e a maioria dos pseudocódigos faz essa suposição.
Além dos pequenos aborrecimentos, eu acho o ecossistema Python+NumPy+SciPy kludgy e inconsistente. A Prova A é o fato de que apesar da linguagem ser bastante dedicada à orientação a objetos, existe uma classe matricial, e ainda assim seu uso é desencorajado e será depreciado. Talvez o MATLAB tenha simplesmente me corrompido, mas eu acho que as matrizes são um tipo de objeto importante o suficiente para manter e promover. Não é um grande ponto de venda do OOP que você pode ter *
fazer coisas diferentes para arrays e matrizes? Existem muitas outras infelicidades a este respeito. (Por que eu preciso de um comando chamado spsolve? Não posso simplesmente chamar solve
em uma matriz esparsa? E em e sobre.)
Há também lugares onde o ecossistema numérico parece um pouco fino para mim. Por exemplo, a quadratura e os solvers de ODE parecem um conjunto mínimo em 2019. AFAICT não há métodos para DAEs, DDEs, solvers simpáticos, ou solvers implícitos que permitam iterações internas de Krylov. Dê uma olhada nas referências para estas funções; elas têm em sua maioria 30 anos ou mais – ainda são boas, mas muito longe de serem completas. O pacote Matplotlib é um trabalho incrível, e por um tempo ele ficou melhor que o MATLAB, mas eu o acho bastante faltando em 3D ainda.
Alguns especialistas argumentam que existem razões profundas pelas quais o código Python luta para manter a velocidade de execução com linguagens compiladas. Eu me divirto com os resultados da busca por “python é muito lento”. Os campeões de Python fazem muitos dos mesmos argumentos/apologias que as pessoas faziam para o MATLAB na época. Isso não significa que eles estejam errados, mas há mais do que apenas um problema de percepção.
Eu acho que entendo porque Python tem sido tão excitante para muitas pessoas na computação científica. Ele tem alguma sintaxe e poder MATLAB, disponível a partir de uma REPL. Ele tem ótimas ferramentas ao seu redor e joga bem com outras linguagens e áreas da computação. Oferece isso sem custos e com muito melhor reprodutibilidade a longo prazo. Claramente, funciona bem para muitas pessoas que provavelmente vêem poucas razões para mudar.
Mas para as coisas que eu sei fazer em computação científica, Python parece muito mais uma tarefa para aprender e usar do que eu estou acostumado. Não saberemos por um tempo se ele continuará a varrer a comunidade ou se já se aproximou do seu auge. Não tenho poderes de previsão especiais, mas sou grosseiro.
Julia
Julia tem as vantagens e desvantagens de ser um retardatário. Aplaudo os criadores de Júlia por pensarem que poderiam fazer melhor:
Queremos uma linguagem que seja de código aberto, com uma licença liberal. Queremos a velocidade do C com o dinamismo do 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 utilizável para programação geral como Python, tão fácil para estatísticas como R, tão natural para processamento de strings como Perl, tão poderoso para álgebra linear como Matlab, tão bom a colar programas como a shell. Algo que é simples de aprender, mas que mantém os hackers mais sérios felizes. Nós o queremos interativo e o queremos compilado.
Em grande parte, eu acredito que eles tiveram sucesso. Tarde no caminho para a versão 1.0 eles pareceram minimizar um pouco a REPL, e houve algumas espiadas quase gratuitas longe do MATLAB. (Como é exactamente LinRange
melhor que linspace
?) Estes são quibbles, no entanto.
Esta é a primeira linguagem que usei que vai além de ASCII. Eu ainda recebo uma quantidade desarrazoada de satisfação por usar variáveis como ϕ
e operadores como ≈
. É mais do que cosmético; ser capaz de se parecer mais com as expressões matemáticas que escrevemos é uma vantagem real, embora complique um pouco o ensino e a documentação.
O trabalho em Júlia me expôs que eu peguei alguns hábitos de programação por causa das escolhas do MATLAB, não superioridade inerente. A vetorização não é natural para muitas coisas. É abrir os olhos para encontrar em Júlia que você pode vetorizar qualquer função apenas adicionando um ponto ao seu nome. Construir uma matriz através de uma compreensão faz com que os loops aninhados (ou meshgrid
truques) pareçam chicotes de buggy em comparação, e evitar uma matriz completamente através de um gerador para uma simples soma faz com que se sinta como obter algo para nada. (Estou ciente de que Python tem características de linguagem similares.)
A grande característica de envio múltiplo torna algumas coisas muito mais fáceis e claras do que a orientação a objetos. Por exemplo, suponha que você tenha aulas de Wall and Ball em uma linguagem tradicional orientada a objetos. Qual classe deve detectar uma colisão de uma bola com uma parede? Ou você precisa de uma aula de Sala para jogar como árbitro? Este tipo de perguntas pode levar-me à distracção. Com o envio múltiplo, os dados são empacotados em tipos de objetos, mas os métodos que operam sobre os dados não estão vinculados a uma classe. Então
function detect_collision(B::Ball,W::Wall)
sabe sobre os tipos mas é definido independentemente deles. É preciso um pouco de programação para eu apreciar como é interessante e potencialmente importante a noção de despacho múltiplo para estender a linguagem.
O ecossistema numérico tem evoluído rapidamente. O meu exemplo número um é DifferentialEquations.jl, escrito pelo incrível Chris Rackauckas. Se este software não ganhar o prémio Wilkinson em breve, o sistema está avariado. Basta ir ao site e preparar-se para ser convertido.
Eu ainda não vi os grandes ganhos de velocidade sobre o MATLAB que Julia promete. Em parte isso é a minha relativa inexperiência e os tipos de tarefas que faço, mas em parte também porque o MathWorks fez um trabalho incrível de optimização automática do código. Não é um aspecto da codificação que eu foco a maior parte do tempo, de qualquer forma.
Programação em Júlia levou algum tempo para me sentir confortável com (talvez eu esteja apenas ficando velho e cristalizado). Isso me faz pensar em tipos de dados mais do que eu gostaria, e há sempre a suspeita sorrateira de que eu perdi o jeito certo de fazer alguma coisa. Mas para uso diário, tenho tanta probabilidade de me virar para a Julia como o MATLAB agora.
O resultado final
MATLAB é a solução corporativa, especialmente para engenharia. É provavelmente ainda a mais fácil de aprender para tarefas numéricas básicas. Documentação meticulosa e décadas de ferramentas de aprendizagem contribuídas são definitivamente importantes.
MATLAB é o sedan BMW do mundo da computação científica. É caro, e isso é antes de você começar a falar sobre acessórios (caixas de ferramentas). Você está pagando por um desempenho e serviço sólido e suave. Também atrai uma quantidade desproporcional de ódio.
Python é uma pickup Ford. É ubíqua e amada por muitos (nos EUA). Pode fazer tudo o que você quiser, e é construída para fazer algumas coisas que outros veículos não podem. É provável que você queira pedir um emprestado de vez em quando. Mas não oferece uma grande experiência de condução pura.
Julia é um Tesla. É construído com um objectivo audacioso de mudar o futuro, e talvez o faça. Também pode vir a ser apenas uma nota de rodapé. Mas entretanto você vai chegar onde está indo com estilo, e com poder de sobra.