Je me retrouve souvent à écrire du code très similaire pour les versions à une, deux et trois dimensions d'une opération / algorithme donné. La maintenance de toutes ces versions peut devenir fastidieuse. La génération de code simple fonctionne assez bien, mais il semble que l'on pense qu'il doit y avoir un meilleur moyen.
Existe-t-il un moyen relativement simple d'écrire une opération une fois et de la généraliser à des dimensions supérieures ou inférieures?
Un exemple concret est: supposons que j'ai besoin de calculer le gradient d'un champ de vitesse dans l'espace spectral. En trois dimensions, les boucles Fortran ressembleraient à quelque chose comme:
do k = 1, n
do j = 1, n
do i = 1, n
phi(i,j,k) = ddx(i)*u(i,j,k) + ddx(j)*v(i,j,k) + ddx(k)*w(i,j,k)
end do
end do
end do
où le ddx
tableau est correctement défini. (On pourrait également le faire avec des multiplications matricielles.) Le code d'un flux bidimensionnel est presque exactement le même, sauf: la troisième dimension est supprimée des boucles, des index et du nombre de composants. Y a-t-il une meilleure façon d'exprimer cela?
Un autre exemple est: supposons que j'ai des vitesses de fluide définies point par point sur une grille tridimensionnelle. Pour interpoler la vitesse à un emplacement arbitraire (c'est-à-dire ne correspondant pas aux points de la grille), on peut utiliser successivement l'algorithme Neville unidimensionnel sur les trois dimensions (c'est-à-dire la réduction dimensionnelle). Existe-t-il un moyen facile de faire une réduction dimensionnelle étant donné l'implémentation unidimensionnelle d'un algorithme simple?
la source
La question souligne que la plupart des langages de programmation "simples" (C, Fortran, au moins) ne vous permettent pas de le faire proprement. Une contrainte supplémentaire est que vous souhaitez une commodité de notation et de bonnes performances.
Par conséquent, au lieu d' écrire un code spécifique à une dimension, envisagez d'écrire un code qui génère un code spécifique à une dimension. Ce générateur est indépendant des dimensions, même si le code de calcul ne l'est pas. En d'autres termes, vous ajoutez une couche de raisonnement entre votre notation et le code exprimant le calcul. Les modèles C ++ reviennent à la même chose: à l'envers, ils sont intégrés directement dans le langage. Inconvénient, ils sont un peu lourds à écrire. Cela réduit la question de savoir comment réaliser pratiquement le générateur de code.
OpenCL vous permet de générer du code au moment de l'exécution assez proprement. Il permet également une séparation très nette entre «programme de contrôle externe» et «boucles / noyaux internes». Le programme externe de génération est beaucoup moins contraint aux performances, et pourrait donc aussi bien être écrit dans un langage confortable, comme Python. C'est mon espoir pour la façon dont PyOpenCL sera utilisé - désolé pour la fiche sans vergogne renouvelée.
la source
Cela peut être accompli dans n'importe quelle langue avec le prototype mental approximatif suivant:
De là, il s'agit de lutter contre la syntaxe de votre certain langage pour garder votre code conforme nd.
Après avoir écrit un solveur de dynamique des fluides à n dimensions , j'ai trouvé qu'il était utile d'avoir un langage qui supporte le décompactage d'un objet de type liste comme arguments d'une fonction. Soit a = (1,2,3) f (a *) -> f (1,2,3). De plus, des itérateurs avancés (tels que ndenumerate dans numpy) font du code un ordre de grandeur plus propre.
la source
la source
Les réponses claires si vous voulez garder la vitesse de Fortran sont d'utiliser un langage qui a une bonne génération de code comme Julia ou C ++. Les modèles C ++ ont déjà été mentionnés, je vais donc mentionner les outils de Julia ici. Les fonctions générées par Julia vous permettent d'utiliser sa métaprogrammation pour créer des fonctions à la demande via des informations de type. Donc, essentiellement, ce que vous pouvez faire ici, c'est faire
puis vous utilisez le
N
pour créer par programme le code que vous souhaitez exécuter étant donné qu'il estN
dimensionnel. Ensuite, la bibliothèque cartésienne de Julia ou des packages comme les expressions Einsum.jl peuvent être facilement construits pour laN
fonction dimensionnelle.Ce qui est bien avec Julia ici, c'est que cette fonction est compilée statiquement et optimisée pour chaque nouveau tableau dimensionnel que vous utilisez, donc elle ne compilera pas plus que ce dont vous avez besoin, mais elle vous donnera la vitesse C / Fortran. En fin de compte, cela est similaire à l'utilisation de modèles C ++, mais c'est un langage de niveau supérieur avec beaucoup d'outils pour le rendre plus facile (assez facile que ce serait un joli problème de devoirs pour un étudiant de premier cycle).
Un autre langage qui est bon pour cela est un Lisp comme Common Lisp. Il est facile à utiliser car comme Julia, il vous donne l'AST compilé avec beaucoup d'outils d'introspection intégrés, mais contrairement à Julia, il ne le compilera pas automatiquement (dans la plupart des distributions).
la source
Je suis dans le même bateau (Fortran). Une fois que j'ai mes éléments 1D, 2D, 3D et 4D (je fais de la géométrie projective), je crée les mêmes opérateurs pour chaque type, puis j'écris ma logique avec des équations de haut niveau qui rendent clair ce qui se passe. Ce n'est pas aussi lent qu'on pourrait le penser d'avoir des boucles distinctes pour chaque opération et beaucoup de copie de mémoire. Je laisse le compilateur / processeur faire les optimisations.
Par exemple
À utiliser dans des équations comme
où
e
etr
etg
peut avoir toute dimensionnalité qui a un sens mathématique.la source