Quelles stratégies de programmation puis-je adopter pour modifier facilement les paramètres de l'algorithme?

17

Le développement d'algorithmes scientifiques est un processus hautement itératif impliquant souvent la modification de nombreux paramètres que je souhaiterais faire varier soit dans le cadre de ma conception expérimentale, soit dans le cadre de l'amélioration des performances de l'algorithme. Quelles stratégies puis-je adopter pour structurer ces paramètres afin de pouvoir les modifier facilement entre les itérations et d'en ajouter facilement de nouveaux?

Scottie T
la source

Réponses:

14

Il est fastidieux pour l'utilisateur de spécifier chaque aspect d'un algorithme. Si l'algorithme autorise les composants imbriqués, aucun nombre fini d'options ne serait suffisant. Par conséquent, il est essentiel que les options ne remontent pas nécessairement au niveau supérieur, comme dans le cas d'arguments explicites ou de paramètres de modèle. C'est ce qu'on appelle parfois le «problème de configuration» en génie logiciel. Je crois que PETSc dispose d'un système unique et puissant pour la gestion de la configuration. Il est similaire au modèle Service Locator dans l'essai de Martin Fowler sur l'inversion de contrôle .

Le système de configuration de PETSc fonctionne grâce à une combinaison de configurations spécifiées par l'utilisateur gérées par les objets du solveur (avec des requêtes get et set) et la base de données d'options. Tout composant de la simulation peut déclarer une option de configuration, une valeur par défaut et un emplacement pour placer le résultat. Les objets imbriqués ont des préfixes qui peuvent être composés, de sorte que chaque objet nécessitant une configuration peut être adressé indépendamment. Les options elles-mêmes peuvent être lues à partir de la ligne de commande, de l'environnement, des fichiers de configuration ou du code. Lorsqu'une option est déclarée, une chaîne d'aide et une page de manuel sont spécifiées, afin que l' -helpoption soit compréhensible et pour qu'une interface graphique correctement liée puisse être écrite.

L'utilisateur appelle une SetFromOptionsméthode pour configurer un objet lui-même en fonction des options de ligne de commande. L'appel de cette fonction est facultatif et peut ne pas être appelé si l'utilisateur (personne qui écrit du code qui appelle PETSc) expose les options via une autre interface. Nous recommandons fortement à l'utilisateur d'exposer la base de données d'options car cela donne à l'utilisateur final (personne exécutant l'application) beaucoup de pouvoir, mais ce n'est pas nécessaire.

Une configuration typique, appelée via

PetscObjectOptionsBegin(object); /* object has prefix and descriptive string */
PetscOptionsReal("-ts_atol",                                      /* options database key */
                 "Absolute tolerance for local truncation error", /* long description */
                 "TSSetTolerances",                               /* function and man page on topic */
                  ts->atol,                                       /* current/default value *?
                  &ts->atol,                                      /* place to store value */
                  &option_set);                                   /* TRUE if the option was set */
PetscOptionsList("-ts_type","Time stepping method","TSSetType",TSList,
                 defaultType,typeName,sizeof typeName,&option_set);
TSAdaptSetFromOptions(ts->adapt);                                 /* configures adaptive controller method */
/* ... many others */
/* ... the following is only called from implicit implementations */
SNESSetFromOptions(ts->snes);                                     /* configure nonlinear solver. */
PetscOptionsEnd();

Remarques:

  • PetscOptionsList()présente à l'utilisateur un choix dans une liste dynamique. Il existe une architecture de plugin que les nouvelles implémentations peuvent utiliser pour s'exposer en tant que première classe aux appelants. (Ces implémentations peuvent être placées dans des bibliothèques partagées et utilisées comme première classe sans recompiler les programmes.)
  • SNESSetFromOptions() configure récursivement les solveurs linéaires, les préconditionneurs et tous les autres composants qui nécessitent une configuration.
Jed Brown
la source
11

J'ai rencontré ce problème à plusieurs reprises lors du développement de mes propres codes de simulation à partir de zéro: quels paramètres doivent aller dans un fichier d'entrée, qui doivent être extraits de la ligne de commande, etc. Après quelques expérimentations, les éléments suivants se sont révélés efficaces. (Il n'est pas aussi avancé que PETSc.)

Au lieu d'écrire un «programme» de simulation expérimental, je suis plus enclin à écrire un package Python qui contient toutes les fonctions et classes nécessaires pour exécuter la simulation. Le fichier d'entrée traditionnel est ensuite remplacé par un petit script Python avec 5 à 10 lignes de code. Certaines lignes sont généralement liées au chargement des fichiers de données et à la spécification de la sortie. D'autres sont des instructions pour le calcul réel. De bonnes valeurs par défaut pour les arguments facultatifs dans le paquet Python permettent aux débutants d'utiliser la bibliothèque pour des simulations simples, tandis que l'utilisateur avancé a toujours accès à toutes les cloches et sifflets.

Quelques exemples:

Toon Verstraelen
la source
C'est super, mais je pense que c'est orthogonal au problème de configuration. Si vous devez spécifier un algorithme hiérarchique ou imbriqué, vous disposez d'options pour spécifier de nombreux objets internes. Le code appelant ceux-ci ne devrait même pas vraiment connaître leur existence car le nombre de niveaux et les types d'imbrication peuvent changer. C'est le problème de tous ces choix qui "bouillonnent". Avec votre code Python de haut niveau, vous pouvez rendre "facile" la spécification de ces options, mais vous devez toujours les spécifier dans le code. Je pense que ce n'est généralement pas une bonne chose.
Jed Brown
xmonad utilise cette méthode pour configurer son gestionnaire de fenêtres pour X.
rcollyer
2

Comme premier point, je ferais l'algorithme ET le logiciel le plus général possible. J'ai appris ça à la dure.

Disons que vous commencez avec un cas de test simple. Vous pouvez le faire plus rapidement. Mais ensuite, si vous avez rendu le logiciel trop spécifique (trop peu de paramètres) pour ce cas initial, vous perdrez de plus en plus de temps à l'adapter à chaque fois que vous ajouterez un nouveau degré de liberté. Ce que je fais maintenant, c'est passer plus de temps au début à rendre la chose assez générale et à augmenter la variation des paramètres à mesure que j'avance.

Cela implique plus de tests depuis le début car vous aurez plus de paramètres à partir du point de départ, mais cela signifie que vous pouvez jouer beaucoup avec l'algorithme à zéro ou à un coût très faible.

Exemple: l'algorithme consiste à calculer l'intégrale de surface du produit scalaire de deux fonctions vectorielles. Ne présumez pas dès le début la taille, la géométrie et la discrétisation de la surface si vous souhaitez à l'avenir changer cela. Faites une fonction de produit scalaire, rendez la surface aussi générale que possible, calculez l'intégrale d'une manière formelle agréable. Vous pouvez tester chaque fonction que vous créez séparément.

Au début, vous pouvez et commencer à intégrer des géométries simples et à déclarer au début certains paramètres sous forme de constantes. Au fil du temps, si vous voulez changer la géométrie, vous pouvez le faire facilement. Si vous aviez fait des hypothèses au début, vous auriez à changer le code entier à chaque fois.

jbcolmenares
la source