2017-09-18 3 views
2

J'ai utilisé sympy pour travailler avec des systèmes d'équations différentielles. J'écris les équations symboliquement, utilisez autowrap pour les compiler par cython, puis passez la fonction résultante au solveur ODE scipy. L'un des principaux avantages de cela est que je peux résoudre symboliquement le jacobien en utilisant la fonction sympy jacobian, la compiler, et aussi le solveur ODE.sympy compilation de fonctions avec de grandes matrices

Cela a fonctionné très bien pour les systèmes d'environ 30 variables. Récemment, j'ai essayé de le faire avec 150 variables, et ce qui s'est passé, c'est que j'ai manqué de mémoire lors de la compilation de la fonction jacobienne. C'est sur Windows avec anaconda et les outils Microsoft Visual C++ 14 pour Python. Fondamentalement lors de la compilation de la jacobienne, qui est maintenant un vecteur de 22000 éléments, l'utilisation de la mémoire pendant l'étape de liaison est passé à environ 7 Go (sur mon ordinateur portable 8 Go) avant de s'écrouler finalement.

Est-ce que quelqu'un a des suggestions avant d'aller sur une machine avec plus de mémoire? Les autres systèmes d'exploitation ou autres compilateurs C sont-ils susceptibles d'améliorer la situation?

Je sais que beaucoup de gens font ce genre de travail, donc s'il y a une réponse, ce sera bénéfique pour une bonne partie de la communauté.

Edit: réponse à certains commentaires de Jonathan:

Oui, je suis pleinement conscient que ce problème est un N^2. Le jacobien est une matrice de toutes les dérivées partielles, donc il aura la taille N^2. Il n'y a pas de véritable moyen de contourner cette échelle. Cependant, un tableau de 22000 éléments n'est pas au niveau qui créerait un problème de mémoire pendant l'exécution - j'ai seulement le problème lors de la compilation.

Fondamentalement, il existe trois niveaux auxquels nous pouvons nous attaquer. 1) résoudre le problème ODE sans le jacobien, ou en quelque sorte séparer le jacobien pour ne pas avoir une matrice de 150x150. Cela irait à la racine même, mais il limite certainement ce que je peux faire, et je ne suis pas encore convaincu qu'il est impossible de compiler la fonction jacobienne

2) changer quelque chose sur la façon dont sympy génère automatiquement le code C, pour diviser en plusieurs morceaux, utilisez plus de fonctions pour les expressions intermédiaires, pour rendre le fichier .c plus petit. Les personnes ayant plus d'expérience de sympie peuvent avoir des idées à ce sujet. 3) changer quelque chose sur la façon dont le C est compilé, de sorte que moins de mémoire est nécessaire.

Je pensais qu'en postant une question distincte plus orientée autour de # 3 (literal referencing of large array -- compiler out of memory), j'obtiendrais une réponse différente de l'auditoire. C'est en fait exactement ce qui est arrivé. Peut-être la réponse à # 3 est "vous ne pouvez pas" mais c'est aussi une information utile.

+0

Je dois appuyer cette question, car je suis lié par la même limitation; Cependant, pour moi, je reçois le message "erreur fatale C1002: le compilateur est hors de l'espace de tas dans le passage 2", plutôt qu'un crash direct. Les tentatives rapides sur ubuntu + gcc-compiler sur la machine d'un collègue n'ont malheureusement pas résolu le problème. Si rien d'autre ne l'aide, on peut contourner ce problème en utilisant 'autowrap' sur quelques sous-matrices du jacobien, et définir une fonction en python pour reconstituer les parties. C'est bien sûr une solution de rechange et loin d'être idéale. – DavidP

+0

Oui, désolé j'ai utilisé "accident" un peu vaguement. Je reçois la même erreur ou une erreur similaire. –

+0

Notez la question suivante [référencement littéral de grand tableau - compilateur out of memory] (https://stackoverflow.com/questions/46380587). C'est actuellement fermé en tant que doublon de ceci. Veuillez signaler que ce commentaire n'est plus nécessaire si le statut du doublon est modifié. –

Répondre

0

Suite à un grand nombre des exemples postés à http://www.sympy.org/scipy-2017-codegen-tutorial/ j'ai été en mesure de compiler ceci. Les choses-clés étaient 1) au lieu d'utiliser autowrap, écrivez le code C directement avec plus de contrôle sur celui-ci. Entre autres choses, cela permet de passer la liste d'arguments en tant que vecteur au lieu de l'étendre. Cela a pris quelques efforts pour travailler (en installant les drapeaux du compilateur à travers distutils, etc, etc) mais à la fin cela a bien fonctionné. Avoir le repo du cours lié ci-dessus comme un exemple a beaucoup aidé.2) en utilisant une élimination par sous-expression commune (sympy.cse) pour réduire considérablement la taille des expressions pour les éléments jacobiens. Par lui-même n'a pas fait beaucoup pour aider dans ce cas (bien que j'ai pu l'utiliser pour améliorer considérablement les performances des modèles plus petits). Le code était encore de 200 Mo au lieu des 300 Mo d'origine. Mais en le combinant avec (2) (cse), j'ai réussi à le réduire à un maigre 1,7 Mo (malgré 14000 variables temporaires). Le cse prend environ 20-30 minutes sur mon ordinateur portable. Après cela, il compile rapidement.