1. INF442 : Traitement des donn´ees massives
A4 : Alg`ebre lin´eaire distribu´ee
Frank Nielsen
X2013
6 mai 2015
2. Plan
◮ un peu de MPI
◮ produit matriciel sur la topologie du tore
◮ la g´en´ericit´e avec la biblioth`eque C++ STL
3. MPI : pas de m´emoire globale !
→ m´emoire locale pour chaque processus, ´echange de messages
Diff´erent d’un fil de calcul (fork) avec m´emoire globale partag´ee
(INF431)
i n t main ( i n t argc , char ∗∗ argv ) {
i n t rang , n , var ;
i n t ∗ ptr=&var ;
MPI Init (&argc , &argv ) ;
MPI Comm size (MPI COMM WORLD, &n ) ;
MPI Comm rank (MPI COMM WORLD, &rang ) ;
∗ ptr=rang ; ( ∗ ptr )++;
p r i n t f ( ”P%d var=%dn” , rang , var ) ;
MPI Finalize () ;}
P0 var =1
P2 var =3
P1 var =2
P3 var =4
4. #i n c l u d e <s t d i o . h>
#i n c l u d e <mpi . h>
i n t main ( i n t argc , c har∗∗ argv ) {
i n t rang , p , autre , taga =0, tagb =1; double a , b ;
MPI Status s t a t u s ; MPI Request r e q u e s t ;
MPI Init (&argc , &argv ) ; MPI Comm size (MPI COMM WORLD, &p ) ; MPI Comm rank (
MPI COMM WORLD, &rang ) ;
i f (p==2)
{
// M´emoire locale de chaque processus
a u t r e=1−rang ; // l’autre processus
a=0; b=1;
p r i n t f (” Proc . %d a u t r e=%d avant a=%f b=%f n” , rang , autre , a , b ) ;
// double swap en utilisant une op´eration de communication sans variable locale tmp !
// on utilise en fait le buffer de communication pour tmp
MPI Isend(&a , 1 , MPI DOUBLE, autre , taga , MPI COMM WORLD, &r e q u e s t ) ;
MPI Isend(&b , 1 , MPI DOUBLE, autre , tagb , MPI COMM WORLD, &r e q u e s t ) ;
p r i n t f (” Attendons avec MPI WAIT que l e s messages s o i e n t bie n p a r t i s . . . n” ) ;
MPI Wait(& re que st , &s t a t u s ) ;
// Re¸coit dans a le message avec tagb (donc la valeur de b)
MPI Recv(&a , 1 , MPI DOUBLE, autre , tagb , MPI COMM WORLD, &s t a t u s ) ;
// Re¸coit dans b le message avec taga (donc la valeur de a)
MPI Recv(&b , 1 , MPI DOUBLE, autre , taga , MPI COMM WORLD, &s t a t u s ) ;
p r i n t f (” Proc . %d apre s a=%f b=%f n” , rang , a , b ) ;
} e l s e
i f ( rang==0) p r i n t f (” Executez avec mpirun −np 2 mpiswap442 . exe ” ) ;
M P I F i n a l i z e () ;}
5. taga=0; tagb=1;
a=0;
b=1;
Isend(a,P1,taga);
Isend(b,P1,tagb);
MPI Wait;
Recv(&a,tagb);
Recv(&b,taga);
P0
taga=0; tagb=1;
a=0;
b=1;
Isend(a,P0,taga);
Isend(b,P0,tagb);
MPI Wait;
Recv(&a,tagb);
Recv(&b,taga);
P1
0, taga
1, tagb1, tagb
0, taga
m´emoire locale P0 m´emoire locale P1
[ france ~]$ mpirun -np 2 mpiswap442 .exe
Proc . 1 autre =0 avant a =0.000000 b =1.000000
Attendons avec MPI_WAIT que les messages soient bien partis ...
Proc . 0 autre =1 avant a =0.000000 b =1.000000
Attendons avec MPI_WAIT que les messages soient bien partis ...
Proc . 1 apres a =1.000000 b =0.000000
Proc . 0 apres a =1.000000 b =0.000000
6. Alg`ebre lin´eaire en parall`ele : la r´egression
Frank Nielsen 1.Les matrices en HPC-1.R´egression A6-6
7. La r´egression lin´eaire
◮ on veut pr´edire ˆy = f (x) avec f (x) = ˆβ0 + d
i=1
ˆβi xi .
◮ les observations (xi , yi ) sont dans Rd × R. Pour des classes
C0 et C1 (valeurs de y), on peut encoder y = 0 ssi. xi ∈ C0 et
y = 1 ssi. xi ∈ C1
◮ on classifie avec la r´egression en ´evaluant ˆyi = f (xi ) puis en
seuillant : xi ∈ C0 ssi. ˆyi < 1
2 et xi ∈ C1 ssi. ˆyi ≥ 1
2
◮ on peut augmenter l’espace des donn´ees en rajoutant une
coordonn´ee x0 = 1. Ainsi x ← (x, 1) et
f (x) = d
i=0
ˆβi xi = x⊤
i β (d + 1 param`etres `a ´evaluer)
◮ l’erreur que l’on veut minimiser est les moindres carr´es
( Residual Sum of Squares , RSS) :
ˆβ = min
β
n
i=1
(yi − x⊤
i β)2
Frank Nielsen 1.Les matrices en HPC-1.R´egression A6-7
8. La r´egression lin´eaire et la classification
Fronti`ere de d´ecision = hyperplan (espace affine de dimension
d − 1 dans Rd )
Frank Nielsen 1.Les matrices en HPC-1.R´egression A6-8
9. La r´egression lin´eaire ordinaire
Soit X la matrice des donn´ees de dimension n × (d + 1), y le
vecteur colonne de dimension n et β le vecteur param`etre de
dimension d + 1. On a la somme des diff´erences au carr´e :
RSS(β) =
n
i=1
(yi − x⊤
i β)2
= (y − Xβ)⊤
(y − Xβ)
En prenant le gradient ∇βRSS(β), on trouve l’´equation dite
normale ( normal equation ) :
X⊤
(y − Xβ) = 0
Pour X⊤X non-singuli`ere, on trouve ˆβ minimisant les moindres
carr´es par la matrice pseudo-inverse (Penrose-Moore) :
ˆβ = (X⊤
X)−1
X⊤
y = X†
y
Frank Nielsen 1.Les matrices en HPC-1.R´egression A6-9
10. La r´egression lin´eaire en Scilab
rand(’seed ’,getdate(’s’))
x = -30:30; a=0.8; b=5; y=a
*x+b;
// on perturbe avec un bruit
uniforme
bruit=rand(1,61,’uniform ’)
-0.5;
y = y+10*bruit;
// regression lin´eaire en scilab
[aa , bb] = reglin(x, y);
plot(x, y,’r+’ );
plot(x, a*x+b,’bo -’)
Frank Nielsen 1.Les matrices en HPC-1.R´egression A6-10
11. La r´egression lin´eaire : ordinaire ou totale
x
y
y = a × x
(x1, y1)
(x2, y2)
(x3, y3)
ordinary regression vs. total regression
Frank Nielsen 1.Les matrices en HPC-1.R´egression A6-11
12. Comparaison de la classification par r´egression ou par
k-PPV
Classifieur sur un vecteur al´eatoire = variable al´eatoire ⇒ variance
et biais
Frank Nielsen 1.Les matrices en HPC-1.R´egression A6-12
13. Comparaison de la classification par r´egression vs. k-PPV
◮ r´egression = bon pour interpoler et extrapoler mais mod`ele
rigide avec l’hypoth`ese globale d’une fonction lin´eaire f (x)
(faible complexit´e = d + 1 param`etres).
⇒ grand biais et petite variance
◮ k-PPV : mod`ele f (x) localement constant, flexible, mais
grande complexit´e = d × n “param`etres”.
⇒ petit biais mais grande variance
Frank Nielsen 1.Les matrices en HPC-1.R´egression A6-13
14. Alg`ebre lin´eaire : les briques de base
◮ des vecteurs colonnes :
v =
v1
...
vl
◮ des matrices (square, skinny, ou fat) :
M =
m1,1 ... m1,c
...
...
...
ml,1 ... ml,c
◮ plusieurs types de matrices avec leur stockage m´emoire :
matrices denses O(lc), matrices diagonales, matrices
sym´etriques, matrices triangulaires, matrices creuses O(l + c).
Alg`ebre multi-lin´eaire et tenseurs.
Frank Nielsen 1.Les matrices en HPC-1.R´egression A6-14
15. Les op´erations/primitives en alg`ebre lin´eaire
Soit l = c = d les dimensions des matrices et vecteurs.
◮ le produit scalaire v1 · v2 = v⊤
1 × v2 : O(d)
◮ le produit matrice-vecteur M × v : O(d2)
◮ le produit matrice-matrice M1 × M2 : O(d3)
◮ la factorisation (d´ecomposition) LU M = L × U (pour
r´esoudre les syst`emes lin´eaires), QR, etc.
Toutes ces primitives sont impl´ement´ees dans la biblioth`eque BLAS,
Basic Linear Algebra Subroutines en plusieurs niveaux
http://www.netlib.org/blas/
Frank Nielsen 1.Les matrices en HPC-1.R´egression A6-15
16. La multiplication matricielle : un d´efi = probl`eme ouvert !
◮ mˆeme en s´equentiel, on ne connait pas d’algorithme
optimal !
◮ borne inf´erieure : Ω(d2), nombre d’entr´ees de la matrice
carr´ee r´esultat.
◮ meilleur algorithme connu `a ce jour : O(d2.3728639) , analyse
fine de l’algorithme de Coppersmith et Winograd.
Le Gall, Fran¸cois (2014), “Powers of tensors and fast matrix
multiplication,” Proceedings of the 39th International
Symposium on Symbolic and Algebraic Computation (ISSAC
2014), arXiv:1401.7714
Frank Nielsen 1.Les matrices en HPC-1.R´egression A6-16
17. Diff´erents motifs pour le parall´elisme de donn´ees
◮ acc`es et transmissions des donn´ees M et v sur un cluster de
machines : d´epend de la topologie du r´eseau d’interconnexion
◮ dispositions bloc-colonnes et bloc-colonne cycliques
→ largeur b du bloc ´el´ementaire (chaque bloc tient dans la
m´emoire locale)
Idem si on prend les lignes (= colonnes de la matrice transpos´ee)
18. Diff´erents motifs pour le parall´elisme des donn´ees
Motif 2D bloc ligne-colonne , et 2D bloc ligne-colonne cyclique
Damier, ´echiquier
20. Produit matrice-vecteur sur l’anneau : Bloc colonne 1D
En BLAS, une op´eration de base :
y ← y + Ax
A(i) = Ai× n
p
:(i+1)× n
p
−1,·: sous-matrice bloc ligne de dimension
n × n
p
y(i) ← y(i) + A(i) × x(i) = y(i) +
j
A[i][j] × x[j]
◮ initialement, A(i), x(i) et y(i) sont stock´es sur le processus Pi
◮ faire tourner les sous-vecteurs x(i) sur la topologie de
l’anneau orient´e
23. produitMatriceVecteur (A, x , y ) {
q = Comm rank () ; // rang du processus
p = Comm size () ; // nombre de processus
r = n/p ; // taille des blocs
f o r ( step =0; step<p ; step++) {
// on envoie le bloc de x sur le prochain nœud de l’anneau
send ( x , r ) ; // communication non-bloquante
// calcul local : produit matrice-vecteur bloc
f o r ( i =0; i<r ; i++) {
f o r ( j =0; j<r ; j++) {
y [ i ] = y [ i ] + a [ i , (q−step mod p) r + j
] ∗ x [ j ] ;
}
}
// on re¸coit le bloc de x du processus pr´ec´edent de l’anneau
r e c e i v e (temp , r ) ;
x = temp ;}
}
24. Produit matriciel parall`ele
Les algorithmes parall`eles vont d´ependre :
◮ des motifs des donn´ees
◮ de la topologie du r´eseau d’interconnexion des machines
◮ des types d’op´erations de communications utilis´es
Coˆut d’une communication entre deux nœuds voisins :
Temps Message = Latence + #longeur × temps par unit´e de longeur
Temps Message = α + τl
◮ on mesure α et τ en ´equivalent FLOPS
◮ efficacit´e : temps s´equentiel/(P × temps parall`ele)
◮ speed-up optimal ⇔ efficacit´e = 1
Frank Nielsen 1.Les matrices en HPC-4.Complexit´e des communications A6-24
25. Le produit matriciel sur un cluster de machines
C = A × B
◮ les ´el´ements des matrices n × n sont initialement distribu´es
sur les P processus P1, ..., PP−1
◮ on ´echange par messages des matrices blocs (rappel MPI : pas
de m´emoire partag´ee globale)
◮ plusieurs motifs de d´ecompositions :
◮ blocs de lignes
◮ blocs de colonnes
◮ blocs de damiers
◮ les d´ecompositions sont en rapport avec les algorithmes et le
r´eseau d’interconnexion (graphe complet, anneau, tore)
26. Le tore 2D
◮ on consid´ere
√
P ∈ N le cˆot´e de la grille torique `a√
P ×
√
P = P processeurs (NB : anneau = tore 1D)
◮ chaque processeur Pi peut communiquer avec ses 4 voisins :
Nord, Sud, Est, Ouest
27. Produit matriciel C = A × B sur le tore
◮ initialement, les matrices sont stock´es par bloc avec le motif
de damier (par bloc 2D) sur le tore.
◮ le processus Pi,j pour i, j ∈ {1, ...,
√
P} est responsable du
calcul de
C(i, j) =
√
P
k=1
A(i, k) × B(k, j)
Plusieurs fa¸cons de transmettre les matrices blocs A(·, ·),
B(·, ·) et C(·, ·).
→ nous allons voir trois principaux algorithmes
29. Algorithme de Cannon : vue g´en´erale
◮ n´ecessite des op´erations de pre-skewing des matrices avant
les calculs locaux et des op´erations de post-skewing apr`es ces
calculs locaux
◮ les communications des sous-matrices A et B sont des
rotations horizontales (←) et des rotations verticales (↑).
Frank Nielsen 3.Produit matriciel-1.L’algorithme de Cannon A6-29
32. // Pr´e-traitement des matrices A et B
// Preskew ← : ´el´ements diagonaux de A align´es
verticalement sur la premi`ere colonne
PreskewHorizontal(A);
// Preskew ↑ : ´el´ements diagonaux de B align´es
horizontalement sur la premi`ere ligne
PreskewVertical(B);
// Initialise les blocs de C `a 0
C = 0;
pour k = 1 `a
√
P faire
C ← C+ProduitsLocaux(A,B);
// d´ecalage vers la gauche ←
RotationHorizontale(A);
// d´ecalage vers le haut ↑
RotationVerticale(B);
fin
// Post-traitement des matrices A et B : op´erations
inverses du pr´e-traitement
// Preskew →
PostskewHorizontal(A);
// Preskew ↓
PostskewVertical(B);
Frank Nielsen 3.Produit matriciel-1.L’algorithme de Cannon A6-32
34. Algorithme de Fox
◮ initialement, les donn´ees ne bougent pas (= pas de
pr´e-traitement)
◮ diffusions horitonzales des diagonales de A (d´ecal´ees vers la
droite)
◮ rotations verticales de B, de bas en haut
... appel´e aussi algorithme broadcast-multiply-roll
Frank Nielsen 3.Produit matriciel-2.Algorithme de Fox A6-34
37. // Initialise les blocs de C `a 0
C = 0;
pour i = 1 `a
√
P faire
// Broadcast
Diffusion de la i-i`eme diagonale de A sur les lignes de processus
du tore;
// Multiply
C ← C+ProduitsLocaux(A,B);
// Roll
// Rotation verticale : d´ecalage vers le haut ↑
RotationVerticale(B);
fin
Frank Nielsen 3.Produit matriciel-2.Algorithme de Fox A6-37
39. Produit matriciel : algorithme de Snyder
◮ initialement, on transpose B : B ← B⊤
◮ sommes globales (reduce) sur les lignes de processeurs
◮ accumulation des r´esultats sur les diagonales principales de
C (d´ecal´ees `a chaque ´etape vers la droite)
◮ rotations verticales de bas en haut
A0,0 A0,1 A0,2
A1,0 A1,1 A1,2
A2,0 A2,1 A2,2 premi`ere diagonale
deuxi`eme diagonale
troisi`eme diagonale
Frank Nielsen 3.Produit matriciel-3.Algorithme de Snyder A6-39
40. A0,0 A0,1 A0,2
A1,2A1,1A1,0
A2,0 A2,1 A2,2
B0,0 B0,1 B0,2
B1,2B1,1B1,0
B2,0 B2,1 B2,2
Initialisation
Pre-processing :
Transpose B → B⊤
´etape 1:
Calculs locaux et
accumulation sur
la premi`ere diagonale
de C
B0,0
B1,1
B2,2
B1,0 B2,0
B0,2
B0,1 B2,1
B1,2
C0,0
C1,1
C2,2
B⊤
A0,0 A0,1 A0,2
A1,2A1,1 A1,0
A2,0 A2,1A2,2
A0,0 A0,1 A0,2
A1,2A1,1 A1,0
A2,0 A2,1A2,2
B0,0
B1,1
B2,2
B1,0 B2,0
B0,2
B0,1 B2,1
B1,2
Frank Nielsen 3.Produit matriciel-3.Algorithme de Snyder A6-40
41. ´etape 1’:
Rotation verticale
de B
A0,0 A0,1 A0,2
A1,2A1,1 A1,0
A2,0 A2,1A2,2 B0,0 B1,0 B2,0
B1,1B0,1 B2,1
B2,2B0,2 B1,2
´etape 2:
Calculs locaux et
accumulation sur
la deuxi`eme diagonale
de C
´etape 2’:
Rotation verticale de B
A0,0 A0,1 A0,2
A1,2A1,1 A1,0
A2,0 A2,1A2,2 B0,0 B1,0 B2,0
B1,1B0,1 B2,1
B2,2B0,2 B1,2
C0,1
C1,2
C2,0
A0,0 A0,1 A0,2
A1,2A1,1 A1,0
A2,0 A2,1A2,2
B0,0 B1,0 B2,0
B1,1B0,1 B2,1
B2,2B0,2 B1,2 C0,2
C1,0
C2,1
´etape 3:
Calculs locaux et
accumulation sur
la troisi`eme diagonale
de C
Frank Nielsen 3.Produit matriciel-3.Algorithme de Snyder A6-41
42. // Preskewing
Transpose B;
// Phase de calcul
for k = 1 to
√
P do
// Produit scalaire ligne par ligne sur A et B
Calcule localement par bloc : C = A × B;
// On calcule les matrices blocs d´efinitives de C
pour la k-i`eme diagonale
// Somme globale ´equivaut au produit scalaire
d’une ligne de A avec une ligne de B
Somme globale de C sur les processeurs lignes pour la
k-i`eme diagonale de C;
D´ecalage vertical de B;
end
// On transpose B afin de retrouver la matrice
initiale
Transpose B;
Frank Nielsen 3.Produit matriciel-3.Algorithme de Snyder A6-42
43. En r´esum´e
Le produit matriciel sur le tore :
◮ algorithme de Cannon (pr´e-processing)
◮ algorithme de Fox (broadcast-multiply-roll)
◮ algorithme de Snyder (sommes globales)
Comparatif des trois algorithmes :
Algorithme Cannon Fox Snyder
pr´etraitement preskewing de A et B rien transposition B ← B⊤
produits matriciels en place en place sur les lignes PEs
mouvements A gauche → droite diffusion horizontale rien
mouvements B bas → haut bas → haut bas → haut
Frank Nielsen 3.Produit matriciel-3.Algorithme de Snyder A6-43
45. Les classes g´en´eriques en C++
But de la g´en´ericit´e = produire du code ind´ependant des
types (instanci´es lors de l’usage):
// returns 0 if equal, 1 if value1 is bigger, -1 otherwise
i n t compare ( const i n t &value1 , const i n t &value2 ) {
i f ( value1 < value2 ) r e t u r n −1;
i f ( value2 < value1 ) r e t u r n 1 ;
r e t u r n 0 ;
}
// returns 0 if equal, 1 if value1 is bigger, -1 otherwise
i n t compare ( const s t r i n g &value1 , const s t r i n g &
value2 ) {
i f ( value1 < value2 ) r e t u r n −1;
i f ( value2 < value1 ) r e t u r n 1 ;
r e t u r n 0;}
⇒ factorisation du code puis `a la compilation, code polymorphique
pour les divers types requis : g´en´eration des codes sp´ecifiques pour
les types demand´es.
46. #i n c l u d e <iostream >
#i n c l u d e <s t r i n g >
// returns 0 if equal, 1 if value1 is bigger, -1 otherwise
template <c l a s s T>
i n t compare ( const T &value1 , const T &value2 ) {
i f ( value1 < value2 ) r e t u r n −1;
i f ( value2 < value1 ) r e t u r n 1 ;
r e t u r n 0 ;
}
// On est gentil ici pour le compilateur :
// on indique explicitement les types demand´es
i n t main ( i n t argc , char ∗∗ argv ) {
std : : s t r i n g h (” h e l l o ” ) , w( ” world ” ) ;
std : : cout << compare<std : : s t r i n g >(h , w) << std : :
endl ;
std : : cout << compare<int >(10 , 20) << std : : endl ;
std : : cout << compare<double >(50.5 , 5 0 .6 ) << std : :
endl ;
r e t u r n 0;}
47. Inf´erence des types demand´es par le compilateur
#i n c l u d e <iostream >
#i n c l u d e <s t r i n g >
// returns 0 if equal, 1 if value1 is bigger, -1 otherwise
template <c l a s s T>
i n t compare ( const T &value1 , const T &value2 ) {
i f ( value1 < value2 ) r e t u r n −1;
i f ( value2 < value1 ) r e t u r n 1 ;
r e t u r n 0 ;
}
// Le compilateur doit trouver le type demande ici :
// inf´erence de types
i n t main ( i n t argc , char ∗∗ argv ) {
std : : s t r i n g h (” h e l l o ” ) , w( ” world ” ) ;
std : : cout << compare (h , w) << std : : endl ;
std : : cout << compare (10 , 20) << std : : endl ;
std : : cout << compare (5 0 .5 , 5 0 .6 ) << std : : endl ;
r e t u r n 0;}
48. M´ecanisme de compilation
◮ le compilateur ne g´en´ere pas de code directement lorsqu’il
rencontre une classe/fonction template parce qu’il ne connaˆıt
pas encore quelles seront les types demand´es.
◮ quand le compilateur rencontre une fonction template
utilis´ee, il sait quel type est demand´e : Il instancie alors le
template et compile le code correspondant
⇒ les classes/fonctions templates doivent donc se trouver dans le
fichier d’en-tˆete, header .h
Le m´ecanisme de template ressemble donc a une macro
expansion...
49. fichier compare.h :
#i f n d e f COMPARE H
#d e f i n e COMPARE H
template <c l a s s T> i n t comp( const T& a , const T& b )
{
i f ( a < b ) r e t u r n −1;
i f (b < a ) r e t u r n 1 ;
r e t u r n 0;}
#e n d i f // COMPARE H
fichier main.cpp :
#i n c l u d e <iostream >
#i n c l u d e ”compare . h”
using namespace std ;
i n t main ( i n t argc , char ∗∗ argv )
{ cout << comp<int >(10 , 20) ; cout << endl ;
r e t u r n 0 ; }
50. Lire un fichier dans un vector de la STL
Vous avez d´ej`a utilis´e la classe vector de la STL ! (tableaux
dynamiques)
i f s t r e a m f i n ;
f i n . open ( ” f i c h i e r . t x t ” ) ;
vector <s t r i n g > t e x t e ; s t r i n g mote ;
while ( f i n >> mot )
{ t e x t e . push back (mot ) ;}
f i n . c l o s e ( ) ;
◮ La boucle while lit jusqu’`a temps de rencontrer EOF (End
Of File)
◮ Les donn´ees sont des chaˆınes de caract`eres s´epar´ees par des
d´elimiteurs (espace, tab, retour `a la ligne, point virgule pour
les fichiers CSV, Comma-Separated Values)
51. STL : une collection de structures de donn´ees
Le concept fondamental est le containeur avec son iterator , le
tout en template !
Structure de donn´ees nom STL #include
tableau dynamique vector <vector>
liste chaˆın´ee list <list>
pile stack <stack>
file queue <queue>
arbre binaire set <set>
table de hachage map <set>
tas ordonn´e file de priorit´e <queue>
Les #include sont `a faire sans le .h
52. La STL : structures de donn´ees g´en´eriques
set <s t r i n g > mots ;
l i s t <Eleve> PromoX2013 ;
stack < vector <int > > nombres ;
`A chaque container STL, on a un it´erateur (iterator) associ´e de
type container<T>::iterator
set <s t r i n g >:: i t e r a t o r p=mots . f i n d ( ” cours ”) ;
l i s t <Eleve >:: i t e r a t o r premier=PromoX2013 . begin
() ;
stack < vector <int > >:: i t e r a t o r f i n=nombres . end
() ;
On d´eref´erence un it´erateur comme pour un pointeur : *it
53. Les containeurs stockent par valeur, pas par ref´erence
◮ quand on ins´ere un objet, le containeur va en faire une copie
◮ quand le containeur doit r´earranger les objets, il proc´ede en
faisant des copies de ceux-ci. Par exemple, si on tri, ou si on
ins´ere sur un containeur map, etc.
◮ si on veut ´eviter cela, il faudra donc faire des containeurs de
pointeurs !
C++11 a le mot clef auto pour inf´erer directemement les types et
un “foreach” (pour les curieux !) :
f o r ( vector <Printer >:: i t e r a t o r i t = vec . begin () ; i t
< vec . end () ; i t ++) { cout << ∗ i t << endl ; }
f o r ( auto i t = vec . begin () ; i t < vec . end () ; i t ++) {
cout << ∗ i t << endl ; }
std : : s t r i n g s t r ( ” Bonjour INF442” ) ; f o r ( auto c :
s t r ) { std : : cout << c << endl ; }
54. Fonctions membres communes `a la STL
Toutes les classes containeurs ont les fonctions membres :
i n t s i z e ()
i t e r a t o r begin ()
i t e r a t o r end ()
bool empty ()
Pour lister tous les ´el´ements d’un containeur, on fait :
l i s t <s t r i n g >:: i t e r a t o r i t=maListe . begin () ;
while ( i t != maListe . end () )
{ cout << ∗ i t <<endl ; i t e r ++;}
Notons que end() est un ´el´ement sentinel . On ne peut pas
d´eref´erencer end().
55. Diff´erents acc`es aux ´el´ements d’un containeur
◮ pour vector, on peut acc´eder aux ´el´ements en utilisant un
index [i] :
vector <int > vec442<double >;
vec442 [0]=280;
... mais les crochets ne peuvent pas ˆetre utilis´es pour
list<int> par exemple
◮ on peut rajouter un ´el´ement `a la fin d’une liste ou d’un
vecteur avec push back :
monVecteur . push back (2013) ;
maListe . push back (2013) ;
... mais il n’ y a pas de push_back pour les ensembles (cod´es
par des arbres binaires) :
set <int > monEnsemble ;
monEnsemble . push back (2013) ; // Erreur !!!
56. La liste (doublement chaˆın´ee)
On peut ajouter `a la tˆete ou `a la queue d’une liste en temps
constant :
maListe . push back (2013) ;
maListe . p u s h f r on t (2015) ;
On peut ins´erer ou supprimer un ´el´ement avec un it´erateur :
l i s t <s t r i n g >:: i t e r a t o r p=maListe . begin () ;
p=maListe . e r a s e ( p ) ;
p=maListe . i n s e r t (p , ”HPC” ) ;
On peut avancer ou reculer dans une liste avec les op´erateurs
unaires ++ et -- :
p++; p−−; // faire attention aux d´ebordements possibles
Seul b´emol : on ne peut pas directement acc´eder i-i`eme ´el´ement
(cela demande de parcourir la liste, pas de crochets).
57. La liste doublement chaˆın´ee en STL
Voir INF311/INF411
NULL
NULL
C++ HPC MPI
list<string>::iterator it=liste.find("HPC")
q=it-- q=it++
58. Les piles et les files
◮ Piles ( stacks ) et files ( queues ) sont des sous-classes de la
classe deque
◮ Une pile est une liste chaˆın´ee avec la propri´et´e Dernier Arriv´e
Premier Sorti, DAPS (LIFO : Last In First Out).
◮ Une file est une liste chaˆın´ee avec la propri´et´e Premier Arriv´e
Premier Sorti, PAPS (FIFO : First In First Out).
◮ On acc´ede au dernier ´el`eement au sommet de la pile ou au
premier ´el´ement d’une file avec les primitives push et pop
◮ Pour les piles, on a aussi top, et pour les files front et back
59. Les piles : illustration
stack <s t r i n g > S ;
S . push ( ”A”) ;
S . push ( ”B”) ;
S . push ( ”C”) ;
S . pop () ;
Q. pop () ;
S . push ( ”D”) ;
Q. push ( ”D”) ;
cout << S . top () ;
60. Les files : illustration
queue<s t r i n g > Q;
Q. push ( ”A”) ;
Q. push ( ”B”) ;
Q. push ( ”C”) ;
Q. pop () ;
Q. push ( ”D”) ;
cout << Q. f r o n t () << Q. back () ;
61. Les files de priorit´e
On doit d´efinir un operator < .
La plus grande valeur est sur le haut (max-heap, top).
p r i o r i t y q u e u e <int > Q;
Q. push (23) ; Q. push (12) ; Q. push (71) ; Q. push (2) ;
cout << Q. top () ;
Q. pop () ;
cout << Q. top () ;
pour la plus petite valeur (min-heap), il faut donc changer le sens
s´emantique de l’op´erateur < ...
http://en.cppreference.com/w/cpp/language/operator_comparison
62. On peut trier facilement avec une file de priorit´e...
#i n c l u d e <queue>
#i n c l u d e <iostream >
using namespace std ;
s t r u c t comparator {
bool o perato r () ( i n t i , i n t j ) { r e t u r n i < j ;}
} ;
i n t main ( i n t argc , char const ∗ argv [ ] )
{
p r i o r i t y q u e u e <int , std : : vector <int >,
comparator> minHeap ;
minHeap . push (10) ; minHeap . push (5) ;
minHeap . push (12) ; minHeap . push (3) ;
minHeap . push (3) ; minHeap . push (4) ;
while ( ! minHeap . empty () ) {
cout << minHeap . top () << ” ” ;
minHeap . pop () ;
}
r e t u r n 0;} // 12 10 5 4 3 3
63. Les ensembles : set (arbres binaires ´equilibr´es)
On doit d´efinir operator <. Toutes les valeurs sont uniques
(sinon, utiliser un multiset).
insert(value), erase(value), erase(iterator),
iterator find(value)
set <s t r i n g > s ;
s . i n s e r t ( ” Ecole ” ) ;
s . i n s e r t ( ” Polytechnique ” ) ;
s . e r a s e ( ” Ecole ” ) ;
cout << ∗( s . f i n d ( ” Polytechnique ”) ) ;
64. Le hachage (map)
◮ Diff´erence entre hachage ferm´e (tableau) et hachage ouvert
(tableau de pointeurs sur des listes).
◮ Templates pour la clef et le type de donn´ees map<K,T>.
◮ On doit d´efiniroperator < pour le type K.
map<int , s t r i n g > monHachage ;
monHachage [23121981] = ” A n n i v e r s a i r e Toto” ;
monHachage [05031953] = ” A n n i v e r s a i r e T i t i ” ;
. . .
map<s t r i n g , int > monHachageRev ;
monHachageRev [ ”Toto” ] = 23121981;
monHachageRev [ ” T i t i ” ] = 05031953;
65. Le hachage (map)
Les fonctions membres pour la classe STL map :
erase(iterator), erase(K clef), map_name(K key)
map<s t r i n g , int > M;
M[ ”A” ] = 23;
M[ ”B” ] = 12;
M[ ”C” ] = 71;
M[ ”D” ] = 5;
M. e r a s e ( ”D” ) ;
cout << M[ ”B” ] ;
66. La classe STL paire `a la rescousse
map<s t r i n g , int > maMap;
pair <s t r i n g , int > p a i r e ( ”Tutu” , 606) ;
maMap. i n s e r t ( p a i r e ) ;
. . .
// on cr´e´e un nouvel enregistrement en faisant aussi :
maMap[ ”Tata” ] = 707;
⇒ op´erateur crochet [K]
67. Les temps d’acc´es aux structures de donn´ees
Pour un containeur `a n ´el´ements :
vecteur list set map
Ins´erer/supprimer O(n) O(1) O(log n) ˜O(1)
Rechercher O(n) O(n) O(log n) ˜O(1)
Voir INF311/INF411.
68. Les it´erateurs
Chaque containeur est equipp´e d’un it´erateur :
container <T>:: i t e r a t o r i t ;
i t=C. begin () ;
◮ ++ et -- pour avancer ou reculer
◮ * pour d´eref´erencer
◮ == et =! pour les tests de comparaisons
Seulement dans la classe vector, on peut bouger de p ´el´ements
(arithm´etique) en faisant
vector <T>:: i t e r a t o r i t ;
i t=i t+p ;
i t=i t −p ;
69. Les it´erateurs : premier et dernier ´el´ements
Le dernier ´el´ement est une sentinelle :
cout << ∗( L . begin () ) ; // oui, si pas vide !
cout << ∗( L . end () ) ; // toujours non !
l i s t <s t r i n g >:: i t e r a t o r p = L . end () ;
p−−;
cout << ∗p ; // ok, si pas vide !
70. La classe STL algorithm
Proc´edures (pas des m´ethodes de classe) : find, remove, count,
shuffle, replace, sort, for each, min element,
binary search, transform, copy, swap :
i t e r = f i n d (L . begin () , L . end () , ” Cours INF442”
) ;
i n t x = count (L . begin () , L . end () , ” i n s c r i t en
INF442” ) ;
r e p l a c e (L . begin () , L . end () , ”DEP442” , ”INF442”
) ;
if : prend une fonction bool´eene utilisateur :
r e p l a c e i f (L . begin , L . end () , appartient442S , ”
Tutorat ”) ;
72. Boost
◮ un ensemble de biblioth`eques qui se comportent bien avec la
STL :
http://www.boost.org/
◮ liste des biblioth`eques de Boost :
http://www.boost.org/doc/libs/
Graph BGL generic graph components
MPI MPI interface in Boost style
Rational rational number class
Thread Portable multi-threading
uBlas linear algebra for vector/matrix
Xpressive regular expression
Install´e dans le r´epertoire /usr/local/boost-1.56.0
73. Boost : la biblioth`eque uBLAS
#i n c l u d e <boost / numeric / ublas / matrix . hpp>
#i n c l u d e <boost / numeric / ublas / i o . hpp>
using namespace std ;
using namespace boost : : numeric : : ublas ;
i n t main () {
matrix <double> m (3 , 3) ;
f o r ( unsigned i = 0; i < m. s i z e 1 () ; ++ i )
f o r ( unsigned j = 0; j < m. s i z e 2 () ;
++ j )
m ( i , j ) = i + j ∗ j ;
cout << m << endl ;
}
74. Boost : la biblioth`eque uBLAS
alias mpiboost =’/usr/local/openmpi -1.8.3/ bin
/mpic++ -I/usr/local/boost -1.56.0/ include
/ -L/usr/local/boost -1.56.0/ lib/ -
lboost_mpi -lboost_serialization ’
mpiboost matrice442.cpp -o matrice442.exe
mpirun -np 1 matrice442.exe
[3 ,3]((0 ,1 ,4) ,(1,2,5) ,(2,3,6))
http://www.boost.org/doc/libs/1_58_0/libs/numeric/ublas/doc/
75. # i n c l u d e <boost / numeric / ublas / matrix . hpp>
# i n c l u d e <boost / numeric / ublas / i o . hpp>
# i n c l u d e <boost / numeric / ublas / matrix . hpp>
using namespace boost : : numeric : : ublas ;
using namespace std ;
i n t main () {
matrix <double > myMat (3 ,3 , 2 . 5 ) ;
myMat (0 ,0)= myMat (2 ,2) =1.0;
myMat (0 ,2)= −3.6; myMat (2 ,0) =5.9;
cout << ”My Mat : ” << myMat << endl ;
cout << ”Num Rows : ” << myMat . s i z e 1 () << endl ;
cout << ”Num Cols : ” << myMat . s i z e 2 () << endl ;
cout << ”My Mat Transp : ” << t r a n s (myMat) << endl
;
cout << ”My Mat Real Part : ” << r e a l (myMat) <<
endl ;
myMat . r e s i z e (4 ,4) ;
cout << ”My Resized Mat : ” << myMat << endl ;
r e t u r n 0;}
76. matrix <double > myMat (3 ,3 , 2. 5) ;
myMat (0 ,0)= myMat (2 ,2) =1.0;
myMat (0 ,2)= −3.6; myMat (2 ,0) =5.9;
mpirun -np 1 matricefun442.exe
My Mat :[3 ,3]((1 ,2.5 , -3.6) ,(2.5 ,2.5 ,2.5)
,(5.9 ,2.5 ,1))
Num Rows :3
Num Cols :3
My Mat Transp :[3 ,3]((1,2.5 ,5.9)
,(2.5 ,2.5 ,2.5) ,( -3.6 ,2.5 ,1))
My Mat Real Part :[3 ,3]((1 ,2.5 , -3.6)
,(2.5 ,2.5 ,2.5) ,(5.9 ,2.5 ,1))
My Resized Mat :[4 ,4]((1,2.5 , -3.6 ,3.57355e
-115) ,(2.5,2.5,2.5 ,2.02567e -322)
,(5.9 ,2.5 ,1 ,0) ,(0,0,0,0))
77. R´esum´e A4
la classification par r´egression lin´eaire (et comparaison avec le
classifieur k-PPV)
le produit matrice-vecteur sur l’anneau orient´e
produits matriciels sur le tore : algorithmes de Cannon
(pre-processing), de Fox (broadcast-multiply-roll) et de Snyder
(sommes globales)
la g´en´ericit´e avec la biblioth`eque C++ STL
la biblioth`eque Boost uBLAS
Pour la prochaine fois : lire le chapitre 5 du polycopi´e