Estruturas de dados para código de volume finito: matrizes versus classes
11
Eu tenho que escrever um código de volume finito para Magnetohydrodynamics (MHD). Escrevi código numérico antes, mas não nessa escala. Eu só queria perguntar qual seria uma boa escolha, usando uma estrutura de dados (abordagem orientada a objetos) com classes ou apenas usando várias matrizes para propriedades diferentes, em termos de velocidade, escalabilidade etc. Eu pretendo escrever o código em python e use fortran para parte numericamente intensiva.
Resposta simples: no python moderno, todo tipo de dados é uma classe; portanto, formalmente, não há diferença entre as duas soluções que você propôs. (Lembre-se de usar classes de novo estilo: classes clássicas são obsoletas! Consulte http://docs.python.org/2/reference/datamodel.html#new-style-and-classic-classes )
Agora, a pergunta deve ser: como organizo uma estrutura de dados eficiente em python? Não há dúvida de que a própria idéia de organizar as células como uma matriz de class Cellinstâncias é muito ineficiente. Você terminará com uma bagunça de ponteiros e dados não contíguos organizados como uma lista vinculada complicada. Obviamente, você tem a capacidade de inserir facilmente novas células na sua lista: mas você precisa desse recurso? Pelo contrário, você terá armazenamento de dados não contíguo e precisará acessar todas as células por diferentes níveis de indireção.
Se você organizar seus dados como dados, numpy.ndarrayentão os dados são contíguos à memória, e o acesso a células diferentes é simplesmente feito através do seu bloco de memória: economia de espaço (sem perda de memória para ponteiros) e rápido .
Conforme apontado por Ethan, os conceitos de OO devem ser usados, mas em nível superior, uma vez que uma estrutura de dados de baixo nível eficiente seja implementada, geralmente através de numpy.ndarray's.
Programação OO significa vincular dados aos métodos que operam nos próprios dados em um nível mais alto de abstração. (Um exemplo: eu implementei um código FEM no qual a matriz de rigidez foi definida como uma classe com um método para fatoração esparsa super nodal de cholesky. A primeira implementação foi dentro do núcleo: quando uma implementação fora do núcleo era necessária foi obtido por herança e por ajustes mínimos no armazenamento de dados subjacentes. Quase 100% do código cholesky super nodal foi reutilizado.)
Um último comentário, mas crucial: um procedimento numérico eficiente é o resultado de um mapeamento inteligente de um algoritmo e uma estrutura de dados para sua arquitetura de computação de destino. Se você começar com a estrutura de dados incorreta, não há como recuperar a eficiência, sem uma reescrita completa.
@ EthanCoon Obrigado pelo seu comentário à outra resposta, que me levou a escrever a minha.
Stefano M
10
Eu estava pensando nisso há alguns dias (também em Python). Pessoalmente, não acho que a programação orientada a objetos seja sempre uma boa opção para programação numérica. Você pode se distrair com o design das classes em vez de apenas resolver as equações. Eu prefiro ficar com funções simples, e com numpy você pode ter suas equações vetorizadas, de modo que o número de linhas que você precisa é muito pequeno. Numpy é muito rápido porque os cálculos reais são feitos com um back-end C (ou FORTRAN?).
O que eu recomendaria que você fizesse,
Escreva um script Python que resolva a versão mais simples possível do seu problema usando uma abordagem funcional com numpy. Por exemplo, tenha tudo na unidade arbitrária e tente apenas 1D (ou 2D). É perfeitamente bom nesta fase se o código estiver confuso. O importante é que você esteja avançando com seu projeto.
Depois de ter algo que funciona. Identifique onde o código é detalhado e refrator. Nesta fase, você pode brincar com idéias diferentes sobre como simplificar seu código. Talvez introduza funções nas quais você percebe que está se repetindo. Você pode comparar com a versão original para saber que não está apresentando erros.
Decida se a abordagem orientada a objetos reduzirá ainda mais a complexidade do código.
A principal mensagem é não começar a escrever aulas até que você já tenha resolvido o problema da maneira mais simples possível. Somente com a experiência de solucionar um problema, você saberá como definir sua interface orientada a objetos. Se você fizer isso antes, é provável que apenas atrapalhe.
Discordo totalmente da afirmação de que OO não é um bom ajuste para programação numérica, mas onde é um bom ajuste está em um nível muito mais alto. OO é muito útil para coisas como modelos de física, malhas, solucionadores, etc., mas quase sempre é inadequado no nível das células.
aí
No post, eu queria alertar sobre as possíveis quedas da "objetificação prematura" do código numérico, principalmente quando alguém está começando. Não sou contra o uso de objetos, veja meu terceiro ponto: se os objetos podem reduzir a complexidade, são uma boa idéia. Concordo que os exemplos que você cita são bons usos, mas chegar a esse ponto requer experiência.
Eu estava pensando nisso há alguns dias (também em Python). Pessoalmente, não acho que a programação orientada a objetos seja sempre uma boa opção para programação numérica. Você pode se distrair com o design das classes em vez de apenas resolver as equações. Eu prefiro ficar com funções simples, e com numpy você pode ter suas equações vetorizadas, de modo que o número de linhas que você precisa é muito pequeno. Numpy é muito rápido porque os cálculos reais são feitos com um back-end C (ou FORTRAN?).
O que eu recomendaria que você fizesse,
A principal mensagem é não começar a escrever aulas até que você já tenha resolvido o problema da maneira mais simples possível. Somente com a experiência de solucionar um problema, você saberá como definir sua interface orientada a objetos. Se você fizer isso antes, é provável que apenas atrapalhe.
fonte