Muitos algoritmos numéricos (integração, diferenciação, interpolação, funções especiais etc.) estão disponíveis em bibliotecas de computação científica, como GSL . Mas muitas vezes vejo código com implementações "roladas manualmente" dessas funções. Para pequenos programas que não são necessariamente destinados à distribuição pública, é prática comum entre os cientistas da computação implementar apenas algoritmos numéricos (com o que quero dizer copiar ou transcrever de um site, Receitas Numéricas ou similares) quando você precisar deles? Nesse caso, existe um motivo específico para evitar a vinculação a algo como GSL, ou é apenas mais "tradição" do que qualquer outra coisa?
Eu pergunto porque sou um grande fã da reutilização de código , o que sugere que eu deveria tentar usar implementações existentes sempre que possível. Mas estou curioso para saber se existem razões para que esse princípio seja menos valioso na computação científica do que na programação geral.
Esqueci de mencionar: estou perguntando especificamente sobre C e C ++, em oposição a linguagens como Python, onde há um benefício claro (velocidade de execução) em usar uma biblioteca.
Respostas:
Eu costumava implementar tudo sozinho, mas ultimamente comecei a usar muito mais as bibliotecas. Eu acho que existem várias vantagens muito importantes no uso de uma biblioteca, além da questão de saber se você deve escrever uma rotina ou não. Se você usa uma biblioteca, obtém
No último ponto acima, estou pensando em grandes bibliotecas como Trilinos ou PETSc . Eu posso reforçar isso com alguns exemplos pessoais concretos no desenvolvimento do PyClaw . Embora tivesse sido fácil paralelizar o Clawpack com as chamadas MPI, optamos por usar o PETSc. Isso nos permitiu limitar o código paralelo no pacote a menos de 300 linhas de Python, mas, melhor ainda, ao colocar nossos dados no formato do PETSc, obtivemos acesso imediato aos solucionadores implícitos do PETSc, permitindo o trabalho atual em um solucionador implícito no PyClaw. Como segundo exemplo, o PyClaw inicialmente incluiu a reconstrução WENO de quinta ordem com código de mão, mas finalmente decidimos confiar no PyWENOpacote para isso. Foi um grande ganho, pois o PyWENO pode gerar automaticamente rotinas WENO de qualquer ordem em vários idiomas.
Por fim, se você usar bibliotecas, poderá contribuir de volta desenvolvendo melhorias ou localizando bugs, o que beneficiará muitas outras pessoas, enquanto a depuração ou aprimoramento do seu próprio código apenas o beneficia.
fonte
Existe uma sobrecarga substancial do programador envolvida na vinculação a uma função de biblioteca, especialmente se essa biblioteca for nova para o programador. Geralmente, é mais simples reescrever algoritmos simples do que descobrir as especificidades de uma biblioteca específica. À medida que os algoritmos se tornam mais complexos, esse comportamento muda.
O Python se destacou em reduzir essa sobrecarga com ferramentas como pip / easy_install e uma interface uniforme de estrutura de dados (ou seja, toda biblioteca parece pegar e produzir uma matriz numpy).
fonte
Um dos projetos nos quais estou envolvido agora é escrever um pacote flexível de simulação e análise para uma classe de detectores de física de partículas. Um dos objetivos deste projeto é fornecer a base de código a ser usada nessas coisas nas próximas décadas.
Neste ponto, já temos duas dúzias de dependências, tornando o processo de construção um pesadelo que gerou um projeto separado gerenciado fora do centro de computação Fermilab, apenas para fornecer uma cadeia de ferramentas confiável.
Agora imagine que você encontra a necessidade de alguma ferramenta que não esteja nessa cadeia de ferramentas (aconteceu comigo no mês passado). Você tem três escolhas
É muito fácil escolher (1). Talvez seja fácil demais.
fonte
Eu acho que é bastante comum, com alguns algoritmos com maior probabilidade de serem reimplementados do que outros.
Há uma troca complicada entre quão irritante é instalar uma biblioteca, quão difícil é implementar o algoritmo você mesmo, quão difícil é otimizá-lo e quão bem a biblioteca se adapta às suas necessidades. Além disso, às vezes o uso de uma biblioteca é apenas um exagero: usei o algoritmo de bissecção lenta em um dos meus programas porque o chamei apenas algumas vezes e não queria adicionar uma biblioteca apenas para isso.
É fácil escrever uma versão bem otimizada? Se for, pode ser melhor fazê-lo. Você conseguirá exatamente o que precisa e não dependerá do trabalho de ninguém. Mas é claro que você realmente precisa saber o que está fazendo: mesmo algoritmos simples podem ser difíceis de implementar.
Eu ficaria curioso para ver um estudo sobre isso, mas, da minha perspectiva tendenciosa, os cientistas costumam usar bibliotecas para álgebra linear e geradores de números aleatórios, com a maior parte do código restante sendo caseiro.
fonte
Eu acho que implementar um algoritmo em vez de usar uma biblioteca pode às vezes dar uma melhor compreensão e controle do modelo. Quando estou codificando algum programa para cálculos científicos, é importante entender o que estou fazendo. A implementação de algoritmos importantes me ajuda a obter um melhor conhecimento do problema e a obter um melhor controle dele.
Por outro lado, às vezes não é uma tarefa trivial selecionar uma biblioteca necessária para obter uma solução; portanto, é melhor procurar algoritmos já implementados quando você tiver certeza do que está tentando alcançar e por que deseja.
Se os algoritmos forem complexos, codificá-los manualmente oferece a oportunidade de melhorar o desempenho / qualidade da solução usando recursos específicos da tarefa. E, às vezes, é necessário alterar um pouco o algoritmo, o que é mais fácil se você souber o código que escreveu e poderá editá-lo da maneira que desejar.
fonte
Uma resposta é que existem tantas variações leves no código numérico que é realmente difícil encapsular isso em uma biblioteca. Considere isso em comparação com o software da Web, que geralmente é fácil de instalar e possui um conjunto claro de entradas e saídas. Eu acho que mais comum são as pessoas pegando uma estrutura, ou uma grande biblioteca que funciona como uma estrutura (Trilinos / PETSc), e usando esse ecossistema para obter os benefícios do uso de códigos comunitários.
fonte
Antes de decidir se deve ou não usar bibliotecas, acho que você também gostaria de descobrir o quanto o uso de uma biblioteca ajudará seu código. Se você estiver usando uma biblioteca bem otimizada para um kernel computacional chave, provavelmente é muito mais eficiente do que tentar escrever o seu próprio.
No entanto, se você estiver escrevendo uma rotina especializada que será chamada apenas uma vez durante a execução de um programa, pode não valer a pena adaptar seu código para se adequar à estrutura exigida por uma biblioteca.
(Outra coisa a se pensar: quanta reestruturação você precisará fazer para tirar proveito da biblioteca? A menos que as horas de trabalho que você gaste para corrigir o código sejam compensadas pelos ganhos correspondentes em eficiência ou precisão numérica, talvez não vale a pena a longo prazo. Idealmente, porém, isso é algo que você planeja ao projetar inicialmente estruturas e algoritmos de dados, para que o "fluxo" da biblioteca seja levado em consideração desde o início.)
fonte
Meus 2 centavos.
Eu acho que é mais fácil escrever geralmente sobre isso, ao invés de apenas sobre C / C ++. Primeiro, bibliotecas em linguagens como Python não são necessariamente usadas para obter um benefício de velocidade, mesmo que isso seja uma consequência. Acho que o @David cobriu muito bem os motivos.
Levando isso de cima, a implementação da linguagem, em certa medida, determina a quais bibliotecas você tem acesso. Linguagens comumente usadas na ciência computacional incluem C, C ++, Python, Perl, Java, Fortran e R. Exemplos menos comuns podem ser Ocaml e Common Lisp. Agora, como a maioria dessas linguagens é escrita em C, elas possuem uma interface de função estrangeira natural para C. No entanto, não é tão fácil chamar, por exemplo, uma biblioteca Perl do Python ou vice-versa. Portanto, na prática, as pessoas tendem a
Use uma biblioteca escrita em sua linguagem de implementação, geralmente algo que faça parte das bibliotecas padrão ou esteja amplamente disponível ou
Chame uma biblioteca C / C ++ através dos idiomas FFI. Isso pressupõe que um wrapper ainda não exista, pois, se existir, não será facilmente distinguível de (1).
(2) geralmente é mais difícil, porque você precisa envolver a função C / C ++. Além disso, você deve agrupar a biblioteca ou adicionar uma dependência extra. Por esse motivo, é mais provável que as pessoas usem as bibliotecas de idiomas internas, em vez de usar GSL, por exemplo, que está em C.
Para rotinas muito genéricas, por exemplo, gerar amostras aleatórias a partir de distribuições ou rotinas numéricas básicas como quadratura de integrais, é fácil e comum reutilizar alguma biblioteca. À medida que a funcionalidade que estamos tentando implementar se torna mais complexa, torna-se exponencialmente mais improvável que se encontre a função exata que se deseja em outra biblioteca e, mesmo que se faça, pode-se gastar muito tempo pesquisando e finalmente adaptando a função como necessário (o estilo / design do código pode ser um problema, por exemplo). E, como discutido acima, é possível acessar apenas um subconjunto das bibliotecas existentes. Por outro lado, implementar um algoritmo sozinho, se ele for complexo e não o foco principal, pode ser assustador e, é claro, é preciso lidar com esses problemas de velocidade incômodos.
Portanto, isso se torna um problema de otimização na análise de custo / benefício. Minha experiência é que, mesmo para técnicas comparativamente padrão como o MCMC, eu geralmente acabo escrevendo meu próprio código, porque ele se encaixa melhor na maneira como estou projetando o software geral.
Obviamente, mesmo que você não use o código, é possível aprender com o código de outras pessoas. Mas não sei quantas vezes os cientistas se preocupam em fazer isso. Minha impressão é que ler o código de outras pessoas para aprender é mais uma coisa de engenheiro de software.
fonte
Pensando no meu curso de mecânica do segundo ano, me ocorre que parte da razão pela qual eu implementei minhas próprias versões de algoritmos conhecidos é que fui ensinado a fazê-lo dessa maneira. Não consigo pensar em um único exemplo em que me ensinaram como fazer interface e vincular uma biblioteca na minha graduação em física. Tenho uma boa lembrança de ver pela primeira vez uma lista de coordenadas de uma bola de golfe girando, tendo calculado a solução das equações de Newton acopladas no FORTRAN. Há uma certa emoção e satisfação (até orgulho) que advém do cálculo das coisas do zero.
fonte
Eu acho que se deve usar bibliotecas testadas, tanto quanto possível. A maioria das pessoas não é especialista em computação numérica e provavelmente não será capaz de implementar uma solução tão correta e cuidadosamente quanto o que está disponível em bibliotecas bem testadas. Dito isto, no entanto, às vezes é o caso de não haver bibliotecas disponíveis que implementem a combinação de recursos necessários em um determinado aplicativo. Eu já vi isso acontecer na área técnica em que trabalho; os códigos existentes não resolveram todos os casos e alguém acabou implementando um solucionador do zero.
fonte
O problema fundamental está geralmente na interface entre o aplicativo e a biblioteca. Um programador de aplicativos tem conhecimento sobre o problema que geralmente é perdido ao passar o problema (por exemplo, como uma matriz) para uma biblioteca. Esse conhecimento é tal que explorá-lo mais do que compensa os benefícios do uso da biblioteca altamente otimizada. Como resultado, o programador de aplicativos "rola" sua própria implementação que explora o conhecimento.
Assim, uma biblioteca realmente boa precisa que esse conhecimento seja passado do aplicativo para a biblioteca, para que a biblioteca também possa tirar proveito dela.
fonte
Além de tudo o que já foi dito acima, repetirei minha resposta da pergunta "Fortran vs C ++": O ativo mais valioso que um programador possui é seu tempo. Sim, dependências externas geralmente são estranhas. Mas gastar tempo para reimplementar, depurar e testar algoritmos que outros já implementaram é quase sempre estúpido, e o resultado raramente será tão bom quanto o código que foi escrito por especialistas em um tópico específico. Reutilize o que os outros fizeram!
fonte
O grupo com o qual trabalho utiliza bibliotecas o máximo possível. Sou um dos poucos programadores, e o resto das pessoas começou a programar no trabalho. Eles sabem o suficiente de suas próprias limitações para saber onde não devem se interessar. IMSL é a biblioteca preferida. Coisas como a GSL seriam proibidas devido a restrições de licenciamento, mesmo que essa seja uma agência federal e que entregemos nosso software de qualquer maneira.
fonte
"A reutilização é principalmente um fenômeno social. Eu posso usar o software de outra pessoa, desde que
"- Stroustrup, The C ++ Programming Language 2 ed. (1991) p. 383.
fonte
Várias boas razões foram apresentadas por outras pessoas para usar bibliotecas e também para rolar suas próprias rotinas.
Às vezes, você pode acelerar os cálculos para um aplicativo específico porque sabe com antecedência que nunca precisará da ampla gama de valores que a rotina da biblioteca cobre ou da precisão que essas rotinas fornecem.
Obviamente, depende muito do aplicativo específico e de quantas vezes a rotina da biblioteca será chamada. Por que você chamaria uma rotina de biblioteca de funções de Bessel bilhões de vezes se você só precisa de alguns números significativos para um pequeno intervalo de x, e alguma técnica mais simples será suficiente para suas necessidades?
fonte
É pouco a acrescentar, temos que reutilizar o código, trata-se de sustentabilidade e contribuição do código para a sociedade, mas isso é tudo acima.
A razão pela qual não reutilizamos o código é que, se você está iniciando o programador, é difícil entender o código de outras pessoas. É particularmente difícil com o C ++ avançado, e você também pode fazer alguns truques em C puro.
Muitas vezes, no início, entendemos o método, mas não como ele é implementado na biblioteca, ou simplesmente como usar a biblioteca com sua interface genérica, controle de erros e convenções, muitas vezes documentadas para programadores experientes, se é que existem. Isso dá a ilusão de que é melhor implementar um método padrão, como a fatoração da LU sozinho. Além disso, novos programadores subestimam o valor do teste de código, validação e portabilidade para diferentes sistemas operacionais. Portanto, no final, a razão é a preguiça, escrever código próprio parece ser uma solução mais rápida e fácil.
A realidade é que podemos aprender mais usando e lendo código do que programando você mesmo do zero.
A preguiça me leva a maior parte do tempo, acho que também a maioria das pessoas. Pelo mesmo motivo, alguns escrevem código do zero e outros usam bibliotecas existentes.
fonte
Os algoritmos de bibliotecas fornecem, em contraste com as próprias implementações:
Ainda considero bom ao inserir um novo campo implementar uma versão de um algoritmo bem compreensível por conta própria. Eu levo muito tempo no total. Comprei e li livros, chamado Press et al. Eu sempre leio muita teoria antes e durante essas implementações. E depois de entender os conceitos gerais de um campo e experimentar as armadilhas na prática para mim, é hora de pular para as implementações de bibliotecas melhores em todos os aspectos. Eu acho que você se tornará um usuário melhor da biblioteca se você escrever um algoritmo "olá mundo" no campo de bibliotecas por conta própria.
Se você trabalha em uma equipe maior, pode não ser sua escolha se a sua equipe usa uma biblioteca específica ou não. A equipe principal pode tomar a decisão. E pode haver uma pessoa responsável pela ligação da biblioteca em seu projeto com seus próprios planejamentos de tempo. Reescrevendo um algoritmo que você pode fazer com seu próprio planejamento de tempo, sem depender da decisão de outras pessoas.
Se você está sozinho e gosta de distribuir, existe outro problema. Considero, assim como muitos outros códigos fonte, o recurso mais útil. Muitos de todos os informáticos podem concordar aqui. Em um campo aplicado fora da informática, pode ser necessário fornecer um executável pré-compilado no Windows. No Linux, você pode configurar as coisas de forma relativamente fácil por conta própria, no caso de bibliotecas de uso de código aberto.
Reescrever um algoritmo por conta própria oferece liberdade de permissão. Seu projeto pode não suportar a licença GPL da GSL, por exemplo.
A isenção pode ser a única restrição que é independente do ponto de vista dos pesquisadores.
fonte