Quando devo usar modelos de expressão C ++ na ciência da computação e quando * não * devo usá-los?


24

Suponha que eu esteja trabalhando em um código científico em C ++. Em uma discussão recente com um colega, foi argumentado que os modelos de expressão poderiam ser uma coisa muito ruim, potencialmente tornando o software compilável apenas em determinadas versões do gcc. Supostamente, esse problema afetou alguns códigos científicos, como aludido nas legendas dessa paródia de Downfall . (Estes são os únicos exemplos que conheço, daí o link.)

No entanto, outras pessoas argumentaram que os modelos de expressão são úteis porque podem gerar ganhos de desempenho, como neste artigo no SIAM Journal of Scientific Computing , evitando o armazenamento de resultados intermediários em variáveis ​​temporárias.

Não sei muito sobre metaprogramação de modelos em C ++, mas sei que é uma abordagem usada na diferenciação automática e na aritmética de intervalos. Foi assim que entrei em uma discussão sobre modelos de expressão. Dadas as vantagens em potencial no desempenho e as desvantagens em manutenção (se essa é a palavra certa), quando devo usar os modelos de expressão C ++ na ciência da computação e quando devo evitá-los?


Ah, o vídeo é muito engraçado. Eu não sabia que existia. Quem fez isso, sabia?
Wolfgang Bangerth

Nenhuma idéia; algumas pessoas do PETSc me enviaram links em um ponto. Eu acho que um desenvolvedor FEniCS conseguiu.
precisa

O link do vídeo está quebrado e estou morrendo de curiosidade. Novo link?
Praxeolitic

Oh Drat, deixa pra lá, vejo que o YouTube chegou para os nossos vídeos de Hitler.
Praxeolitic

Respostas:


17

Meu problema com os modelos de expressão é que eles são uma abstração muito vazada. Você gasta muito trabalho escrevendo código muito complicado para executar uma tarefa simples com uma sintaxe melhor. Porém, se você deseja alterar o algoritmo, precisa mexer no código sujo e, se usar tipos ou sintaxe, recebe mensagens de erro completamente ininteligíveis. Se o seu aplicativo é mapeado perfeitamente para uma biblioteca baseada em modelos de expressão, pode valer a pena considerar, mas se você não tiver certeza, eu recomendaria apenas escrever o código normal. Claro, o código de alto nível é menos bonito, mas você pode fazer o que precisa ser feito. Como benefício, o tempo de compilação e os tamanhos binários diminuirão muito e você não precisará lidar com uma enorme variação no desempenho devido à escolha do compilador e do sinalizador de compilação.


Sim, eu vi algumas das longas mensagens de erro em primeira mão quando tive que portar o código do gcc 2.95 para o gcc 4.x, e o compilador estava lançando todos os tipos de erros sobre modelos. Um colega de laboratório meu está desenvolvendo uma biblioteca de modelos para aritmética de intervalo em C ++ (adicionando novos recursos que não estão no Boost :: Interval para realizar mais pesquisas) e não quero ver o código se tornar um pesadelo compilar.
precisa

12

Outros comentaram sobre a dificuldade de escrever programas de ET, bem como a complexidade de entender as mensagens de erro. Deixe-me comentar sobre a questão dos compiladores: É verdade que, um tempo atrás, um dos grandes problemas foi encontrar um compilador compatível o suficiente com o padrão C ++ para fazer tudo funcionar e funcionar de maneira portável. Como conseqüência, encontramos muitos bugs - eu tenho 2-300 relatórios de bugs em meu nome, distribuídos por gcc, Intel icc, IBM xlC e pgicc de Portland. Consequentemente, o script de configuração deal.II é um repositório de um grande número de testes de erros do compilador, principalmente na área de modelos, declarações de amigos, espaços para nome, etc.

Mas acontece que os fabricantes do compilador realmente se uniram: hoje, o gcc e o icc passam em todos os nossos testes e é fácil escrever um código portátil entre os dois. Eu diria que a IGP não está muito atrasada, mas tem uma série de peculiaridades que parecem não desaparecer ao longo dos anos. O xlC, por outro lado, é uma história totalmente diferente - eles corrigem um bug a cada 6 meses, mas, apesar de apresentarem relatórios de bug durante anos, o progresso é extremamente lento e o xlC nunca conseguiu compilar o acordo.

O que tudo isso significa é o seguinte: se você se mantém com os dois grandes compiladores, pode esperar que eles funcionem hoje. Como a maioria dos computadores e sistemas operacionais hoje em dia normalmente possui pelo menos um deles, isso é suficiente. A única plataforma onde as coisas são mais difíceis é o BlueGene, onde o compilador do sistema geralmente é o xlC, com todos os seus bugs.


Por curiosidade, você já tentou compilar com os novos compiladores xlc no / Q?
Aron Ahmadia 29/09/12

Não. Admito que desisti de xlC.
Wolfgang Bangerth

5

Eu experimentei um pouco com ETs há muito tempo, quando, como você mencionou, os compiladores ainda estavam lutando com eles. Eu usei a biblioteca blitz para álgebra linear em algum código meu. O problema foi obter o bom compilador e, como eu não sou um programador C ++ perfeito, interpretar as mensagens de erro do compilador. O último era simplesmente incontrolável. O compilador geraria, em média, cerca de 1000 linhas de mensagens de erro. De maneira alguma eu fui capaz de encontrar rapidamente meu erro de programação.

Você pode encontrar mais informações na página da on- line (existem os procedimentos de duas oficinas de ET).

Mas eu ficaria longe deles ....


As mensagens de erro do compilador são de fato uma das minhas preocupações. Com alguns dos códigos C ++ modelados que eu compilar para criar bibliotecas para meus projetos, o compilador pode gerar centenas de linhas de mensagens de aviso. No entanto, não é meu código, não o entendo e, de um modo geral, funciona, então deixo-o em paz. Mensagens de erro enigmáticas e longas não são um bom presságio para depuração.
precisa

4

O problema já começa com o termo 'modelos de expressão (ET)'. Não sei se existe uma definição precisa para isso. Mas em seu uso comum, de alguma forma, combina 'como você codifica expressões de álgebra linear' e 'como ele é computado'. Por exemplo:

Você codifica a operação vetorial

v = 2*x + 3*y + 4*z;                    // (1)

E é calculado por um loop

for (int i=0; i<n; ++i)                 // (2)
    v(i) = 2*x(i) + 3*y(i) + 4*z(i);

Na minha opinião, são duas coisas diferentes e precisam ser dissociadas: (1) é uma interface e (2) uma implementação possível. Quero dizer, isso é uma prática comum em programação. Certamente (2) pode ser uma boa implementação padrão, mas em geral eu quero poder utilizar uma implementação especializada e dedicada. Por exemplo, eu quero que uma função como

myGreatVecSum(alpha, x, beta, y, gamma, z, result);    // (3)

ser chamado quando estou codificando (1). Talvez (3) apenas use internamente um loop como em (2). Mas, dependendo do tamanho do vetor, outras implementações podem ser mais eficientes. De qualquer forma, algum especialista em alto desempenho pode implementar e ajustar (3) o máximo possível. Portanto, se (1) não pode ser mapeado para uma chamada de (3), evito o açúcar sintático de (1) e chamo diretamente (3) imediatamente.

O que eu descrevo não é novidade. Pelo contrário, é a ideia por trás do BLAS / LPACK:

  • Todas as operações críticas de desempenho no LAPACK são feitas chamando as funções BLAS.
  • O BLAS apenas define uma interface para as expressões de álgebra linear que são comumente necessárias.
  • Para o BLAS, existem diferentes implementações otimizadas.

Se o escopo do BLAS não for suficiente (por exemplo, ele não fornece uma função como (3)), pode-se estender o escopo do BLAS. Portanto, este dinossauro dos anos 60 e 70 percebe, com sua ferramenta da idade da pedra, uma separação limpa e ortogonal da interface e implementação. É engraçado que (a maioria) das bibliotecas numéricas C ++ não atinjam esse nível de qualidade de software. Embora a própria linguagem de programação seja muito mais sofisticada. Portanto, não é de surpreender que o BLAS / LAPACK ainda esteja vivo e se desenvolva ativamente.

Então, na minha opinião, os ETs não são maus por si só. Mas como eles são comumente usados ​​em bibliotecas numéricas C ++ ganharam uma reputação muito ruim nos círculos científicos da computação.


Michael, acho que você está perdendo um dos pontos dos modelos de expressão. Seu exemplo de código (1) não é realmente mapeado para nenhuma chamada BLAS otimizada. De fato, mesmo quando existe uma rotina BLAS, a sobrecarga de uma chamada de função BLAS a torna bastante terrível para vetores e matrizes pequenos. Bibliotecas sofisticadas de modelos de expressão como Blaze e Eigen podem usar avaliação de expressão adiada para evitar o uso de temporários, mas estou convencido de que quase nada além de uma linguagem específica de domínio será capaz de superar a álgebra linear rolada à mão.
Aron Ahmadia 29/09/12

Não, acho que você está perdendo o objetivo. É preciso distinguir entre (a) BLAS como uma especificação de algum frequentemente necessária Álgebra Linear operação (b) uma implementação de Blas como ATLAS, GotoBLAS, etc. BTW que como ele funciona em Flens: Por padrão uma expressão como (1) o faria ser avaliado chamando axpy do BLAS três vezes. Mas sem modificar (1) eu também poderia avaliá-lo como em (2). Portanto, o que acontece logicamente é o seguinte: se uma operação como em (1) é importante, o conjunto de operações BLAS especificadas (a) pode ser estendido.
Michael Lehn

Portanto, o ponto principal é: Notações como 'v = x + y + z' e como finalmente são finalmente calculadas devem ser separadas. Eigen, MTL, BLITZ, blaze-lib falham completamente a esse respeito.
Michael Lehn

1
Certo, mas o número de operações de álgebra linear frequentemente necessárias é combinatório. Se você usar uma linguagem como C ++, poderá implementar conforme necessário, usando modelos de expressão (esta é a abordagem Eigen / Blaze) combinando sub-blocos e algoritmos de forma inteligente usando avaliação adiada ou implementando uma grande quantidade biblioteca de todas as rotinas possíveis. Eu não defendo nenhuma dessas abordagens, pois trabalhos recentes em Numba e Cython mostram que podemos obter um desempenho semelhante ou melhor trabalhando em linguagens de script de alto nível como Python.
Aron Ahmadia 29/09/12

Mas, novamente, o que eu reclamo é o fato de que bibliotecas tão sofisticadas (no sentido de complicadas mas inflexíveis) como Eigen combinam fortemente a notação e o mecanismo de avaliação e até acham que é uma coisa boa. Se eu usar uma ferramenta como o Matlab, só quero codificar as coisas e confiar que o Matlab está fazendo o melhor possível. Se eu usar uma linguagem como C ++, quero estar no controle. Portanto, avalie se existe um mecanismo de avaliação padrão, mas deve ser possível alterá-lo. Caso contrário, eu volto e chamo diretamente as funções em C ++.
Michael Lehn
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.