Rng
-
Upload
issam-dakhlaoui -
Category
Documents
-
view
8 -
download
0
description
Transcript of Rng
Génération de nombres aléatoires uniformes et non uniformes en contexte
distribué.
Hamid BADI
10 Janvier 2008
Table des matières 1 Généralités sur la génération de nombres aléatoires...................................................................4
1.1 Générateurs de nombres pseudoaléatoires ............................................................................41.2 Les types de PRGN existants .................................................................................................41.3 Notion de germe......................................................................................................................61.4 Les générateurs quasialéatoires.............................................................................................6
2 Caractéristiques des PRNG.........................................................................................................72.1 Uniformité...............................................................................................................................72.2 Périodicité...............................................................................................................................72.3 Répétabilité.............................................................................................................................82.4 Efficacité................................................................................................................................82.5 Indépendance..........................................................................................................................9
3 Les PRNG en contexte distribué...............................................................................................103.1 MPI et contexte distribué......................................................................................................103.2 Complexité de génération pseudoaléatoire en contexte distribué........................................143.3 Solutions envisageables........................................................................................................17
3.3.1 Utilisation d'un modèle maître / esclave.........................................................................173.3.2 Méthode de Nonoverlapping blocks...............................................................................173.3.3 Méthode du leapfrogging « saut de grenouille »............................................................193.3.4 Utilisation de plusieurs générateurs...............................................................................21
4 Les outils existants....................................................................................................................224.1 SPRNG.................................................................................................................................22
4.1.1 Présentation.....................................................................................................................224.1.2 Utilisation.......................................................................................................................224.1.3 Exemple d'utilisation......................................................................................................264.1.4 Limites............................................................................................................................28
4.2 GNU Scientific Library GSL.............................................................................................294.2.1 Présentation....................................................................................................................29
Références :.......................................................................................................................................30
1 Généralités sur la génération de nombres aléatoiresLa génération de nombres aléatoires par des calculateurs, qui de par leur conception sont
déterministes, fait l'objet depuis des décennies de nombreux projets de recherche en informatique. La complexité réside dans le fait que tout programme informatique détermine à partir d'une liste de valeurs en entrée, un ensemble de valeurs en sortie identique à chaque exécution, si les valeurs d'entrées sont inchangées entre deux exécutions. Il est de ce fait impossible de générer une suite de nombres purement aléatoires avec des machines déterministes telles que les ordinateurs.
1.1 - Générateurs de nombres pseudo-aléatoires
Il est important d'introduire ici la notion de générateur de nombres pseudoaléatoires. Ils sont aussi appelé PRNG (désignant Pseudo Random Number Generator). Le principe de ces générateurs consiste à créer à partir d'un germe initial, un nombre dit pseudoaléatoire, qui ne présente aucun lien logique ou arithmétique apparent avec le germe. Ce nombre généré est ensuite utilisé pour créer un second nombre pseudoaléatoire. On peut ainsi récursivement générer une suite de nombres qui n'ont, d'apparence, aucun lien logique dans leur séquence, mais qui sont en fait tous obtenus par une formule déterministe.
1.2 - Les types de PRGN existants
Le premier d'entre eux fut développé par John Von Neumann en 1940. Il repose sur le principe de l'élévation au carré de nombres codés sur k digits afin de générer une suite pseudo aléatoire. Une fois le nombre élevé au carré, on conserve les k digits situés entre les digits 3k/2 et k/2. Ces k digits constituent alors un nombre aléatoire et sont à nouveau utilisés pour recommencer l'opération.
1234 ² = 01522756 xx5227xx
nombre aléatoire tiré : 5227
Sur cet exemple on ne génère que des nombres de 4 digits. Il en faut en réalité beaucoup plus pour générer une suite de qualité. Nous reviendrons plus tard sur les critères de qualité d'un PRNG.
Suite à l'algorithme de Von Neumann de nombreuses autres méthodes de génération de nombres pseudoaléatoires ont vu le jour.
Une des méthodes les plus employées utilise la congruence linéaire. Ces LCG (Linear Congruential Generator) utilisent la formule suivante pour générer une suite de nombres pseudoaléatoires.
La qualité du générateur sera en partie déterminée par le choix des paramètres a, b et m.
On peut citer les méthodes de registres à décalage bouclés (SRG, pour ShiftRegister Generator), qui utilisent l'opération binaire XOR sur la séquence de bit du précédent nombre pseudoaléatoire
1 Généralités sur la génération de nombres aléatoires 4
afin d’en générer un nouveau.
1 Généralités sur la génération de nombres aléatoires 5
1.3 - Notion de germe
On appel « germe » d'un PRNG le nombre qui permet de l'initialiser. Il s'agit d'une valeur numérique donné par l'utilisateur sur laquelle est effectuée l'opération arithmétique définie dans l'implémentation du générateur. Ce résultat sera un nombre pseudoaléatoire. Une seule valeur d'entrée est nécessaire à l'initialisation car les nombres pseudoaléatoires suivant seront calculés récursivement à partir des précédents.
On peut voir ainsi qu'à une valeur donnée pour le germe d'un PRNG, correspond une et une seule séquence de nombres pseudoaléatoire. Les conséquences de cette caractéristique seront détaillées par la suite.
1.4 - Les générateurs quasi-aléatoires
Il s'agit de générateurs également utilisés dans le cadre de simulation stochastique, en particulier dans le domaine des finances. La grande différence avec les générateurs pseudoaléatoires vient du fait que la séquence générée est entièrement déterministe et ne présente aucun caractère aléatoire. On peut donc se demander d'où vient se nom de générateur quasialéatoire, en anglais Quasi Random Number Generator (QRNG).
Ce nom vient du fait que la séquence peut générer un QRNG correspond à un échantillon d'une distribution de loi de probabilité, alors qu'un PRNG simule une distribution de loi de probabilité [GENTLE 03]. Le but d'un QRNG est d'effectuer des tirages qui remplissent le plus uniformément possible un espace d'une dimension donnée.
Une implémentation de tels générateurs repose sur l'utilisation de fractals. Les fractals effectuent des opérations sur un élément afin de le diviser en plusieurs éléments de structures identiques. Par exemple, prenons le segment [01] et effectuons l'opération de le diviser en 2. On obtient alors 2 sous ensembles [00,5] et ]0,51]. Si l'on répète l'opération sur ces 2 sousensembles on obtient alors 4 sous intervalles.
Ainsi de suite on peut obtenir une suite de points à scission d'un sous ensemble en 2. Cela permet d'obtenir une suite de points formant une distribution uniforme mais non aléatoire.
1 Généralités sur la génération de nombres aléatoires 6
2 Caractéristiques des PRNGLa qualité des générateurs pseudoaléatoires dépend essentiellement de la faculté qu'à cette
formule arithmétique à produire une séquence de nombre vérifiant les principes fondamentaux suivants :
2.1 - Uniformité
En probabilité on définit qu'une variable aléatoire X suit une loi uniforme sur un intervalle [a b] si elle est absolument continue et que sa densité est définie par :
f x =1
b−asi x ∈ [a−b ]
0 sinon
La moyenne étant égale à (b + a) / 2 et l'écarttype à (b + a)² / 12
On dit que le principe d'uniformité d'un générateur pseudoaléatoire est respecté si les valeurs tirées par ce générateur suivent rigoureusement cette loi uniforme. En d'autres termes, chaque nombre généré par le PRNG doit avoir la même probabilité d'être tiré et ce en tout point de l'intervalle de tirage.
Cette propriété est essentielle car elle constitue la base de tout tirage aléatoire. Toutes les autres lois de probabilité classiques telle que la loi normale ou la loi exponentielle dérivent de la loi uniforme. Ainsi si le générateur est biaisé, tout algorithme qui simulerait une loi de probabilité plus complexe serait également biaisé et fournirait par conséquent des résultats peu fiables.
2.2 - Périodicité
On définit par périodicité le nombre de tirages pseudoaléatoires que peut effectuer un PNRG avant de retirer un résultat déjà sorti. Mathématiquement, la probabilité qu'une variable aléatoire réelle soit égale à une constante est nulle. Il est donc en théorie impossible qu'un tel événement se produise et la période serait donc infinie. Cependant, il est important de rappeler que même si de nombreux générateurs sont utilisés pour la génération de nombres réels, ils ne peuvent effectuer que des tirages discrets et en nombre fini d'éléments du fait du codage binaire des nombres réels. De ce fait la période ne peut excéder le nombre de réels codables par le générateur.
La période est importante car elle indique le nombre d'éléments différents que peux sortir le générateur. Une période trop courte se révélera problématique dans des applications où de nombreux tirages sont nécessaires, telle que des simulations de MonteCarlo. En effet, rappelons qu'un PRNG utilise les précédents nombres tirés pour générer le suivant. De ce fait si un nombre a déjà été tiré par un PRNG, tous les suivants auront également été tirés. Il est donc totalement inutile de tirer plus de nombres que la période du générateur. Sinon cela conduirait à effectuer plusieurs fois exactement les mêmes tests, ce qui engendrerait un allongement du temps d'exécution sans pour autant améliorer la qualité des résultats.
2 Caractéristiques des PRNG 7
2.3 - Répétabilité
On appel répétabilité la faculté que possède un générateur à fournir facilement deux séquences pseudoaléatoires strictement identiques.
On pourrait penser qu'une telle propriété soit néfaste pour des applications informatiques. En effet, si le but de la génération de nombres aléatoires est d'obtenir des nombres imprédictibles, le fait de générer deux séquences identiques de suite semble en contradiction avec ce principe.
En réalité, cela s'avère très utile dans certaines applications. D'ailleurs c'est en partie pour cet avantage que les PRNG sont préférés aux générateurs de nombres purement aléatoires pour des simulations de MonteCarlo. En effet, le débogage d'algorithmes qui utilise cette technique s'en trouve facilité si les résultats restent constants d'une exécution à l'autre. Cela permet d'évaluer et d'améliorer les performances de l'algorithme sans se demander si les variations dans les résultats proviennent des modifications apportées, ou si elles ne sont que le résultat d'une séquence stochastique plus ou moins favorable.
On peut considérer que la répétabilité est respectée si, à partir d'un même germe, on peut obtenir deux séquences de nombres pseudoaléatoires rigoureusement identiques entre deux exécutions utilisant le même générateur. On note ici l'importance du germe qui permet à lui seul de garder la trace de la séquence aléatoire complète.
2.4 - Efficacité
Les générateurs pseudoaléatoires étant souvent utilisés pour des simulations stochastiques nécessitant parfois plusieurs centaines de milliers de tirages, il semble évident que la fonction chargée d'effectuer un tirage soit le plus efficace possible. Pour être efficace, le temps entre l'appel à la fonction chargée de renvoyer un nombre aléatoire et la réception de la valeur par le programme doit être extrêmement court.
C'est aussi pour cette efficacité plus importante que les PRNG sont préférés au générateurs purement aléatoires.
2 Caractéristiques des PRNG 8
2.5 - Indépendance
On dit qu'un PRNG respete le critère d'indépendance si il génère des séquences pseudoaléatoires non corrélées. Le niveau de corrélation entre deux séquences est difficile à déterminer. Il faut pour cela effectuer de nombreux tests sur les générateurs tels que DieHard [MARSAGLIA 96] ou le Test U01 [L'ECUYER 07]. On peut voir sur les images suivante un exemple de générateurs corrélés et noncorrélés.
Ce test empirique de L'Ecuyer consiste a effectuer un tirage de 1000 paires de nombres pseudoaléatoires. Chaque paire donnant les coordonées d'un point à placer dans un repère de 0 à 0,001 en absice et 0 et 1 en ordonnée.
Cela permet de distinguer ou non manière empirique des structures redondantes qui sont les signes de générateurs corrélés. Ainsi, on peut voir une net corrélation sur le générateur rand() à gauche, alors que le générateur MLCG laisse apparaître une disposition de points d'apparence plus aléatoire.
2 Caractéristiques des PRNG 9
Générateur standard du langage C rand() Générateur MLCG de Pierre L'Ecuyer
3 Les PRNG en contexte distribué
3.1 - MPI et contexte distribué
On parle de contexte distribué dès lors qu'un algorithme utilise un système informatique disposant de plusieurs processeurs ayant chacun leur propre espace mémoire. De telles machines sont utilisées afin de paralléliser les programmes et ainsi accélérer leur exécution. Au lancement du programme, les segments de codes nécessaires à l'exécution sont dupliqués pour chaque processeur actif. Ce qui donne naissance à plusieurs processus qui exécuteront les même instructions.
Par exemple, un algorithme qui nécessite d'exécuter un très grand nombre de fois les mêmes instructions mais sur des données différentes, peut voir son temps d'exécution considérablement réduit si ces calculs sont effectués en même temps par plusieurs processeurs. Ainsi au lieu d'un seul processeur qui exécute les N instructions nécessaires, on a M processeurs qui effectuent N/M instructions. On notera toutefois que cette méthode ne divise pas le temps d'exécution par le nombre de processeurs utilisés en raison des temps de communications entre les processeurs.
En effet, en contexte distribué chaque processeur dispose de son propre espace et de ce fait il est impératif de faire parvenir à chaque processeur les données nécessaires au calcul. De plus, une fois les calculs effectués il faut rassembler les résultats vers un seul processeur.
La communication entre processeur peut s'effectuer grâce à la Message Passing Interface (MPI). MPI est une librairie développée sous plusieurs langages, notamment C, Fortran et C++, qui met à la disposition des développeurs un certains nombres de fonctions permettant la communication en contexte distribué. Le principe de base de fonctionnement de MPI repose sur l'envoi de message entre les différents processus. On distingue plusieurs catégories de fonctions, ici décrite avec une implémentation en C.
Les fonctions de contrôle d'environnement :MPI_Init(argc,argv)
Il s'agit de la fonction d'initialisation paramétrée avec les arguments de la ligne de commande. argv contient notamment le nombre de processus créés.
MPI_Comm_rank(world,rank)MPI_Comm_size(world,size)
C'est 2 fonctions permettent respectivement d'obtenir le numéro du processus qui est exécuté ainsi que le nombre total de processus en activité. Il est en effet important de connaître l'identifiant du processus tournant car chaque processeur possède la même séquence d'instructions, or ils n'effectuent pas systématiquement les même actions. Le paramètre rank permet donc de tester les processus les uns des autres, le premier processus ayant l'identifiant 0. Le paramètre world, également présent dans plusieurs autres fonctions, référence toujours le communicateur utilisé. Il prend souvent la valeur désignant le communicateur par défaut désigné par la constancte MPI_COMM_WORLD.
3 Les PRNG en contexte distribué 10
MPI_Wait(request,status)
Cette fonction permet de bloquer l'exécution d'un processus tant qu'il ne reçoit pas la requête désigné pas le paramètre request. Le paramètre status pointe sur une structure qui enregistre des informations comme par exemple des erreurs. Comme pour le paramètre world décrit précédement, status est utilisé dans plusieurs fonction MPI et possède dans chaque cas les même propriétés.MPI_Finalize()
Cette fonction permet de clôturer proprement le programme qui utilise MPI.
3 Les PRNG en contexte distribué 11
Les fonctions de communication point à point :MPI_Send(buffer, size, type, dest, tag, world)MPI_Recv(buffer, size, type, src , tag, world, status)
La fonction MPI_Send permet d'envoyer un buffer de données depuis le processeurs qui effectue l'appel vers le processeur référencé par le paramètre dest. Il est nécessaire d'indiquer dans le paramètre size le nombre d'éléments contenu dans le buffer d'envoi ainsi que le type de données envoyé grâce au paramètre type. Enfin le paramètre world référence le contexte d'exécution et tag donne un identifiant au message envoyé.
La fonction MPI_Recv lors qu'elle est appelée ce mets en attente d'un buffer de données provenant du processus src et ayant pour identifiant tag. A la réception, les size éléments de type type seront enregistrés dans le buffer référencé par buffer. MPI_Isend(buffer, size, type, dest, tag, world, request)MPI_Irecv(buffer, size, type, src , tag, world, request)
Les fonctions MPI_Isend() et MPI_Irecv() ont des fonctionnalité analogue aux 2 fonctions précédentes. Elle se distingue toute fois par leur caractère non bloquant. Cela signifie que l'exécution séquentielle de l'algorithme ne s'arrête pas à l'appel de ces fonctions. Dans le cas d'un envoi, MPI_Isend() ne fait que préparer l'envoi et ne l'effectuera qu'une fois qu'il recevra la requête référencée par req. MPI_Irecv() quand à elle n'attend pas la réception totale ou partielle du buffer pour continuer l'exécution. Le développeur doit alors s'assurer de la réception du message grâce à la fonction wait() décrite précédemment.
Les fonctions de communications collectives :MPI_Bcast(buffer, size, type,root,world)
Cette fonction est similaire à MPI_Send() à la différence que l'information envoyé n'est pas destinée à un seul processus ciblé mais du processus root à l'ensemble des autres. Buffer sert à la fois de buffer d'envoi pour root et de réception pour les autres.
MPI_Scatter(send_buffer,send_size,send_type recv_buffer,recv_size,recv_type,root, world)
A l'appel de cette fonction le processus root envoi send_size élément de type send_type contenu dans le send_buffer. Chaque processus recevra ensuite, recv_size élément de type recv_type dans le buffer recv_buffer. Plus simplement, la fonction permet d'envoyé un buffer contenant beaucoup d'élément en le scindant de manière à ce que chaque processus reçoivent une partie du buffer.
MPI_Reduce(send_buffer,recv_buffer,size,type,op,root,world)
Cette fonction permet de rassembler des données calculer par plusieurs processeur. Chaque processeur envoie par le buffer send_buffer,size éléments de type type. Chacun de ces éléments étant rassemblé par le processus root dans le recv_buffer en utilisant l'opération op (addition, produit, maximum ...).
Compilation est exécution :
3 Les PRNG en contexte distribué 12
Avant de pouvoir être exécuter, il est necessaire de compiler le code source grâce aux compilateurs mpicc pour un code en C et mpiCC pour un code en C++. Le programme compilé doit ensuite être exécuté grace à la commande suivante :mpirun np X nom_de_l'executable
L'option np permet d'indiquer le nombre de processus à créer, la variable x représente ce nombre de processus.
3 Les PRNG en contexte distribué 13
3.2 - Complexité de génération pseudo-aléatoire en contexte distribué
L'intérêt de pouvoir générer des nombres pseudoaléatoires en contexte distribué est directement l'intérêt même de la programmation distribué, à savoir accroître les performances d'un algorithme. Si il était impossible d'utiliser des nombres pseudoaléatoires satisfaisant en contexte distribué, cela constituerait un frein à l'avancer technologique apporté grâce aux simulations stochastiques. Le temps d'exécutions de telles simulations pouvant parfois être excessivement long sur une machine monoprocesseur.
Bien qu'il soit possible de générer des nombres pseudoaléatoires en contexte distribué, cela n'est pas sans contraintes en raison du principe de fonctionnement d'un PRNG. On a vu précédemment qu'un générateur aléatoire devait être initialisé avec un germe afin qu'il génère une suite pseudoaléatoire. Cette initialisation constitue en contexte distribuée un problème majeur. Étudions les conséquences que cela entraîne dans un exemple.
Le programme C suivant utilise la bibliothèque MPI afin de générer 3 nombres pseudoaléatoires pour chaque processeurs distincts, ici 4 processeur sont utilisés. Le générateur utilisé est rand(), le générateur par défaut sous UNIX. Chaque processus effectue dans un premier temps l'initialisation de l'environnement MPI et initialise le générateur avec la constante SEED. Il affiche ensuite 3 entiers tirés avec le générateur rand().
1 > #include <stdlib.h>2 > #include <stdio.h>3 > #include <mpi.h>4 >5 > #define SEED 1483793 /* germe initiale */6 >7 > int main (int argc, char ** argv)8 > {9 > int rank,10> size;11>12> /* initialisation du contexte MPI*/13> MPI_Init(&argc,&argv);14> MPI_Comm_rank( MPI_COMM_WORLD, &rank );15> MPI_Comm_size( MPI_COMM_WORLD, &size );16>17> /*Initialisation du generateur unix standard rand */18> srand( SEED );19> 20> /*affichage de trois nombres pseudo-aléatoires par processus*/21> printf( "\n------- Processus %d -------\n", rank );22> printf( "nombre 1 %d :\n",rand() );23> printf( "nombre 2 %d :\n",rand() );24> printf( "nombre 3 %d :\n",rand() );25>26> MPI_Finalize();27> return 0;
3 Les PRNG en contexte distribué 14
28> }
3 Les PRNG en contexte distribué 15
On obtient en sortie de l'exécution les résultats suivant :------- Processus 0 -------
nombre 1 : 1682786746
nombre 2 : 727574205
nombre 3 : 1824008005
------- Processus 3 -------
nombre 1 : 1682786746
nombre 2 : 727574205
nombre 3 : 1824008005
------- Processus 1 -------
nombre 1 : 1682786746
nombre 2 : 727574205
nombre 3 : 1824008005
------- Processus 2 -------
nombre 1 : 1682786746
nombre 2 : 727574205nombre 3 : 1824008005
On distingue immédiatement que les 4 séquences sont identiques. Ces résultats étaient prévisibles. En effet, on peut voir ligne 18 que l'on initialise le générateur rand() avec la constante SEED définie ligne 5. Cette initialisation est faite dans chacun des processus, donc chaque processus va créer une séquence pseudoaléatoire à partir du même germe et par conséquent générer la même séquence.
Une solution trivial serait d'avoir un germe différent par processus. Cette méthode générerait bien une séquence différente par processeur. La question qui se pose alors est : quels germes utiliser ?
Comme pour l'exemple, il est possible de définir autant de constantes différentes qu'il y a de processus créés. Cependant, un choix arbitraire des germes peut conduire à des résultats très insatisfaisant [GENTLE 03]. Il est en effet impossible de savoir dans quelles mesures seront corrélées les séquences. Certes, il se pourra dans certains cas qu'elles soient très indépendantes ou au contraire extrêmement corrélées. Il se peut même que les séquences se chevauchent dans le cas où un processus génère un nombre déjà tiré par un autre processus. On se retrouverait alors avec 2 séquences identiques ce qui nuirait à la qualité des résultats.
Bien que l'une des principales applications des PRNG soient de simuler des phénomènes nstochastiques, il est nécessaire que les développeurs du modèle de simulation soient certains de la fiabilité du simulateur. En effet, les aléas des résultats fournis à l'issu de la simulation doivent être conditionnés exclusivement par les lois de probabilités définies par les paramètres du modèles. La qualité de la séquence générée à chaque répétition de la simulation doit être garantie. Dans le cas contraire il devient difficile de statuer entre : les résultats sontils le fruit d'un scénario probable ou ontils étaient engendrés par un comportement "exceptionnel" du PRNG. La réalisation d'une simulation de qualité nécessite donc un générateur fiable à chaque exécution.
3 Les PRNG en contexte distribué 16
3.3 - Solutions envisageables
3.3.1 Utilisation d'un modèle maître / esclaveUne solution viable serait de séparer la génération de nombres pseudoaléatoires des calculs
qui utiliserons ces nombres. Dans ce contexte un processus qu'on peut appeler "maître", n'effectue que de la génération de nombres pseudoaléatoire, tandis que les multiples processus "travailleurs" effectuent les calculs appropriés. Il est alors nécessaire d'utiliser les fonctions de communication intégrées dans MPI afin que le maître puisse envoyer des nombres aux travailleurs et que les travailleurs effectuent des requête au maître lorsqu'ils ont besoin d'une nouvelle séquence stochastique.
Avec cette technique il n'y a pas de problèmes de corrélation, car la génération de nombre pseudoaléatoire se fait comme dans tout programme séquentiel standard (programme n'utilisant qu'un seul processeur). L'inconvénient vient du fait que le programme est ralentit par le seul processeur qui génère les nombres alors que plusieurs effectuent les calculs et attendent de recevoir de nouvelles données. Le gain en temps d'exécution entre le programme séquentiel et le parallèle s'en trouve donc réduit.
3.3.2 Méthode de Nonoverlapping blocksLa première que décrivent décrivent Cristopher A. Stoner et Paul Coddington [STONER 94]
consiste à calculer à l'avance un germe pour chaque séquence distincte à générer. Ce mécanisme est nommé sous le terme lookahead. Reprenons la formule arithmétique standard des générateurs congruentiels :
Si l'on fixe b à 0 on peut aboutir à la formule suivante :
x : représente la suite aléatoiren : désigne le nombre d'itération du générateurk : désigne le nombre de valeurs "passées" grâce au lookaheada,m : paramètres du générateur congruentiel
Grâce à cette propriété il est possible de connaître à l'avance par un calcul simple la valeur que générera le PRNG dans k itérations. Il est ainsi possible de calculer des germes différent pour chaque processus et avec lesquels nous seront sur qu'il n'y aura pas de chevauchement. D'où le nom de Nonoverlapping Blocks donné par James E. Gentle [GENTLE 03].
Le principe consiste à envoyer à chaque processus un germe différent mais qui font tous partie de la même séquence aléatoire mais à des indices différents. Il est possible d'adapter la formule afin d'intégrer le nombre de tirage à effectuer par processeur ainsi que le numéro du
3 Les PRNG en contexte distribué 17
processus dans le calcul de chaque germe.
i : numéro du processusxi : désigne le germe du ieme processusx0 : désigne le germe initiale donné par l'utilisateurk : désigne le nombre de valeurs "passées" grâce au lookaheada,m : paramètres du générateur congruentielA noter que le calcul de aki+1 peut se révéler coûteux en raison de la gestion des
dépassements de capacités.
Au début de l'éxécution, on calcule pour chaque processus i, de 0 à p1 (p désignant le nombre de processus), un germe correspondant au (n*i)eme nombre aléatoire de la séquence. Ces germes sont ensuite distribué à chaque procesus qui pourront alors générer des nombres aléatoires de façon "classique".
3 Les PRNG en contexte distribué 18
3.3.3 Méthode du leapfrogging « saut de grenouille »Cette méthode utilise comme la précédente un mécanisme de prévision des nombres
aléatoires qui seront tirés dans k itérations. La différence se tient dans le fait, qu'au lieu de calculer un germe situé trés loin en avant de la séquence une seule fois pour chaque processus, on le calcule à chaque itérations pour chaque processus mais en recherchant beaucoup moins loin. La formule suivante permet de calculer le prochain nombre aléatoire tiré pour chaque processus i :
x : représente la séquence aléatoiren : nombre d'itération du générateur par processus p : nombre total de processusi : numéro de processusk : nombre d'éléments "sautés" dans la séquence
Pour être efficace k doit être supérieur ou égale au nombre de processus p. Dans le cas contraire les processus dont l'identifiant i serait supérieur ou égale à k généreraient les mêmes valeurs que les processus d'identifiant i – k.
A chaque itération, tous les processus de 0 à p calculent le pième nombre aléatoire suivant à partir de sa propre position. Chaque processus génère ainsi des nombres pseudoaléatoire d'une même séquence.
L'un des inconvénient des générateurs linéaires qui utilisent ces 2 méthodes est qu'ils possèdent une faible période ce qui peut être préjudiciable dans des applications parallèles où le nombre de tirages peut être extrêmement grand. Afin d'augmenter la périodicité, on utilise généralement une méthode de brassage de plusieurs générateurs.
De plus, on peut assister à une forte corrélation entre les diverses soussuites générées par les méthodes du leapfrogging et du nonoaverlapping blocks. Une combinaison des 2 méthodes peut
3 Les PRNG en contexte distribué 19
contribuer à diminuer ces corrélations,
3 Les PRNG en contexte distribué 20
3.3.4 Utilisation de plusieurs générateursUne autre technique pour générer des séquences stochastiques indépendantes dans un
contexte distribué est d'utiliser un générateur diffèrent par séquence. Les générateurs étant différent les séquences produites seront donc forcément différentes et vraisemblablement non corrélées [GENTLE 03]. De plus il n'y a pas de possibilité de chevauchement car même si deux générateurs produisent le même nombre pseudoaléatoire, ils ne généreront pas le même chiffre à l'état n+1.
Afin d'obtenir un générateur différent par processeur, il est possible d'utiliser un générateur congruentiel mais dont les paramètres sont spécifiques à chaque processus. Ainsi la constante multiplicative de ces générateurs peut être généré par un autre générateur pseudoaléatoire.
Il est également possible d'utiliser des générateurs de type complètement différents pour chaque processeur, cependant il se pose un problème de "scalabilité" (par extension de l'anglais scalablity pour extensibilité). En effet, un PRNG fonctionnant en contexte distribué doit pouvoir le faire sur un nombre variables de processus et par conséquent il faut assurer de pouvoir affecter un générateur différent par processus.
3 Les PRNG en contexte distribué 21
4 Les outils existants
4.1 - SPRNG
4.1.1 PrésentationDéveloppé par des équipes de l'université de l'état de Floride (The Department Of Computer
Science and the School Of Computational Science at Florida State University), SPRNG est l'acronyme de Scalable Parallel Random Number Generator [MASCAGNI 00]. Il s'agit d'une librairie permettant la génération de séquences aléatoires distinctes et non corrélées dans des contextes distribués pour chaque processus. Cette librairie est disponible en 2 versions. La version 2.0 écrite pour les langage Fortran et C et la version 4.0 qui est développée pour le C++ et toujours le Fortran. La dernière version date à ce jour du 7 juin 2007.
SPRNG implémente 6 générateurs différents et utilise la bibliothèque MPI afin d'effectuer les échanges d'informations entre les processus nécessaires au fonctionnement du générateur. A l'initialisation du générateur un germe est calculé pour chaque processus grâce à la méthode du nonoverlapping blocks à partir du paramètre passé à la fonction d'initialisation. Après cette phase d'initialisation chacun de ces générateurs peuvent être utilisés aussi simplement que n'importe qu'elle autre générateur utilisé dans un algorithme séquentiel. Chaque générateur effectue des tirages selon une loi uniforme entre 0 et 1, et renvoie donc des réels double précision entre 0 et 1.
4.1.2 UtilisationSPRNG fournit 2 interfaces distincte référencé par l'interface simple et l'interface par défaut
(default). L'interface simple est utilisée si il n'est pas nécessaire de distinguer plusieurs séquences stochastique sur un même processeur. Si on utilise cette interface, à l'initialisation une seule séquence sera généré sur chaque processeur, chaque séquence étant distincte de celle des autres processus. L'interface default permet d'utiliser plusieurs séquences distinctes sur chaque processeur. Chacune des séquences étant référencée par un identifiant.
Les descriptions suivantes utilisent la version 4.0 de SPRNG avec un code en C++.
Interface Simple:
Inclusions :
L'utilisation de SPRNG nécessite l'inclusion des fichiers d'entête sprng_.h. Il doit de plus définir les 2 macros SIMPLE_SPRNG et USE_MPI.#define SIMPLE_SPRNG /* 2 macros à définir pour utiliser */#define USE_MPI /* l'interface simple */ /* /!\ à définir avant l'inclusion qui suit */#include "sprng.h" /* fichier d'entête de SPRNG */
4 Les outils existants 22
4 Les outils existants 23
Initialisation :
Elle se fait par le simple appel à la fonction init_sprng() :int *init_sprng(int seed, int param, int rng_type = 0)
seed : représente le germe initialparam : sert à paramétrer certains générateur tel que le générateur congruentiel linéaire. Se
paramètre peut prendre la valeur de la constante SPRGN_DEFAULT.rng_type: représente le type de générateur à utiliser parmi lesquels :
0 : Combined Multiple Recursive Generator
1 : 48 Bit Linear Congruential Generator with Prime Addend
2 : 64 Bit Linear Congruential Generator with Prime Addend
3 : Modified Lagged Fibonacci Generator
4 : Multiplicative Lagged Fibonacci Generator
5 : Prime Modulus Linear Congruential Generator
Si le paramètre n'est pas précisé, le Combined Mulitple Recursive Generator est utilisé
Utilisation :
Une fois initialisé, chaque processus peut faire appel aux fonctions sprng() et isprng() pour obtenir respectivement un nombre pseudoaléatoire flottant compris entre 0 et 1 ou un entier compris entre 0 et 231.double sprng()int isprng()
Interface par défaut :
Inclusions :
Il faut inclure le fichier des fichiers d'entête sprng_cpp.h.
#include "sprng_cpp.h" /* fichier d'entête de SPRNG */
Initialisation :
Dans l'interface default, il faut déclarer un pointeur d'objet de classe Sprng et utilisé la fonction SelectType() afin de choisir le type de générateur à utiliser. Cette fonction prend argument un entier désignant les même générateurs que dans l'interface simple. L'appel aux méthodes de cette objet remplace les appels de fonctions de l'interface simple.
Sprng *stream; /*déclaration d'un pointeur sur un objet Sprng*/stream = SelectType(gtype); /*selection du type de générateur */stream>init_sprng(streamNum, nbStream, seed, param)
streamNum : désigne le numéro de stream, il a généralement la valeur du numéro de processusnbStream : nombre total de séquences à générer
4 Les outils existants 24
seed et param sont identiques à la version simple.
Utilisation :
L'utilisation est identique à l'interface simple à la différence qu'il faut faire appel aux méthode d'un objet Sprng et non à une simple fonction.double Sprng::sprng()int Sprng::isprng()
4 Les outils existants 25
4.1.3 Exemple d'utilisationL'exemple suivant est inspiré du site de référence de SPRNG http://sprng.cs.fsu.edu. Ce
programme utilise l'interface default de la version 4.0 de SPRNG et la version C de la bibliothèque MPI.
#include <stdio.h>#include <mpi.h> /* fichier d'entete MPI */#include "sprng.h" /* fichier d'entete de SPRNG */
#define SEED 985456376 /* germe unique utilise pour generer les *//* distinctes sur chaque processus */
int main(int argc, char *argv[]){ /*Variables et objets de manipulation de SPRNG*/
int streamnum, /* identifiant de sequence stochastique */ nstreams; /* nombre de sequences a generer */
int *stream; /* pointeur vers un objet de type Sprng */ /* cette objet est utilise pour tous les */ /* appels aux methode de SPRNG */
int gtype = 0; /* utilisation du Combined Multiple */ /* Recursive Generator */
/*Variables de manipulation de MPI*/
int myid, /* identifiant du processus en cours */ nprocs; /* nombre total de processus */
/*autres variables*/
int i; /* indice de boucle */ double rn; /* enregistre un nombre pseudoaleatoire */
/*Configuration d'MPI*/
MPI_Init(&argc, &argv); /* initialisation de MPI */ MPI_Comm_rank(MPI_COMM_WORLD, &myid); /* enregistrement du numero de */ /* processus */ MPI_Comm_size(MPI_COMM_WORLD, &nprocs); /* enregistrement du nombre de */ /* processus */
/*Initialisation*/
streamnum = myid; /*l'identifiant de sequence est egale au numero de*/ nstreams = nprocs; /*et on veut autant de sequences que de processus */
/* instanciation d'un generateur SPRNG de type gtype */
/* initialisation de la sequence stochastique avec les parametres de */
4 Les outils existants 26
/* generateur standards (SPRGN_DEFAULT) */ stream = init_sprng(0,streamnum,nstreams,SEED,SPRNG_DEFAULT);
/*Affichage des resultats*/
/* affichage des proprietes de la sequence */ printf("\n\nProcessus %d, informations sur la sequence :\n", myid,print_sprng(stream));
/* generation et affichage de trois nombres pseudoaleatoires */ for (i=0;i<3;i++) { rn = sprng(stream); printf("Processus %d, nombre pseudoaleatoire %d: %.14f\n", myid, i+1, rn); }
/*Sortie de programme*/
free_sprng(stream); /* liberation de l'objet Sprng */ MPI_Finalize(); /* cloture d'MPI */
return 0;}
Aprés compilation, la commande suivante permet d'executer le programme exemple en parallèle sur 4 processeurs differents :mpirun np 4 exemple
Additive Lagged Fibonacci Generator
seed = 985456376, stream_number = 2 parameter = 0
Processus 2, informations sur la sequence :
Processus 2, nombre pseudoaleatoire 1: 0.81418942802375
Processus 2, nombre pseudoaleatoire 2: 0.11452920359573
Processus 2, nombre pseudoaleatoire 3: 0.85094477780857
Additive Lagged Fibonacci Generator
seed = 985456376, stream_number = 3 parameter = 0
4 Les outils existants 27
Processus 3, informations sur la sequence :
Processus 3, nombre pseudoaleatoire 1: 0.67243778038410
Processus 3, nombre pseudoaleatoire 2: 0.54868241275882
Processus 3, nombre pseudoaleatoire 3: 0.54435642037535
Additive Lagged Fibonacci Generator
seed = 985456376, stream_number = 1 parameter = 0
Processus 1, informations sur la sequence :
Processus 1, nombre pseudoaleatoire 1: 0.44147640787630
Processus 1, nombre pseudoaleatoire 2: 0.43404284173811
Processus 1, nombre pseudoaleatoire 3: 0.84724763334503
Additive Lagged Fibonacci Generator
seed = 985456376, stream_number = 0 parameter = 0
Processus 0, informations sur la sequence :
Processus 0, nombre pseudoaleatoire 1: 0.50427166200642
Processus 0, nombre pseudoaleatoire 2: 0.55843670419893
Processus 0, nombre pseudoaleatoire 3: 0.00084777812323
Nous pouvons remarquer que l'on obtient 4 séquences differentes alors qu'un seul germe a été utilisé.
4.1.4 LimitesSPRNG est une librairie efficace, capable de générer en contexte distribué, des séquences de
nombres pseudoaléatoires de qualités et utilisables pour des applications scientiques. Cependant, elle est limité par le fait qu'elle ne génère des nombres pseudoaléatoires suivant exclusivement la
4 Les outils existants 28
loi uniforme entre 0 et 1. Or la plupart des applications utilisant SPRNG font appel à d'autre lois de probabilité telle que la loi normale ou exponentielle. Le développeur est alors contraint de réécrire les fonctions permettant de simuler ces lois en faisant appel à des transformations qui utilise les nombres pseudoaléatoires suivant la loi uniforme entre 0 et 1 fournient par SPRNG.
4.2 - GNU Scientific Library - GSL
4.2.1 PrésentationComme son nom l'indique, GSL [GALASSI 06] est une libraire participant au projet GNU
fournissant des outils destinées aux applications scientifiques. Elle est distribuée sous la licence GNU – GPL (GNU – General Public Licence) la version actuelle est la 1.10 publiée le 15 septembre 2007.
La librairie est destinée aux developpeurs C et C++ et propose prés de 1000 fonctions utilisable dans des domaines tels que l'algèbre linéaire, le calcul vectoriel et matriciel, le calcul differentiel, en statistiques ect ... Une des fonctionalité les plus utiles dans notre cas concerne les fonctions simulant des distributions aléatoires et la génération de nombres pseudoaléatoire.
En effet, GSL fournit l'implementation de fonctions pouvant simuler la plupart des lois de probabilités standards. Elle utilise des algorithmes qui utilisent la loi uniforme [01] afin de générer un nombre pseudoaléatoire suivant une loi spécifique. Les nombres pseudoaléatoires suivant cette loi uniforme sont générés par l'un des PRNG fournit par GSL. Lesquels n'étant pas prévus pour être utilisés en contexte distribué.
4 Les outils existants 29
Références :[GENTLE 03] :
Ramdom number generation and MonteCarlo methods / James E. Gentle 2nd édition 2003Springer – Statistic and Computing – ISBN : 0287001786
[STONER 94]:
Random Number Generation on Parallel Computer System, proposal for 1994 NPAC REU Project Christophe A. Stoner, Paul Coddington
[MARSAGLIA 96] :
DIEHARD : A Battery of Tests of Randomness, Marsaglia G. 1996http ://stat.fsu.edu/pub/~diehard
[L'ECUYER 07] :
TestU01: A C Library for Empirical Testing of Random Number GeneratorsP. L'Ecuyer et R. Simard, ACM Transactions on Mathematical Software, 33, 4, Article 22, August 2007.
[GALASSI 06] :
GNU Scientific Library Reference Manual Revised Second Edition,M. Galassi et al, ISBN 0954161734
[MASCAGNI 00]
M. Mascagni and A. Srinivasan (2000), "Algorithm 806: SPRNG: A Scalable Library for Pseudorandom Number Generation," ACM Transactions on Mathematical Software, 26: 436461
Références : 30